exynos9610: Usb: HAL: Update wahoo HAL
authorBadhri Jagan Sridharan <Badhri@google.com>
Tue, 13 Jun 2017 17:52:16 +0000 (10:52 -0700)
committerJan Altensen <info@stricted.net>
Sun, 1 Nov 2020 02:06:27 +0000 (03:06 +0100)
This CL rebases wahoo HAL based on the kernel change to update
sysfs interface.

https://partner-android-review.googlesource.com/#/c/836088/

Bug: 62272992
Test: Verify USB dialog on wahoo
Change-Id: I8bc8f494176c7648abeb9783fbd18dc837793bda

hidl/usb/Usb.cpp
hidl/usb/Usb.h
hidl/usb/android.hardware.usb@1.1-service.wahoo.rc

index 0d472bd44e674646dd51cf03def92cbd4483adf5..601c70b509a83d006c3bb0cd4076c76adcc2afd0 100644 (file)
 
 #include <android-base/logging.h>
 #include <assert.h>
+#include <chrono>
 #include <dirent.h>
 #include <pthread.h>
+#include <regex>
 #include <stdio.h>
 #include <sys/types.h>
+#include <thread>
 #include <unistd.h>
 #include <unordered_map>
 
@@ -41,7 +44,7 @@ namespace implementation {
 // Set by the signal handler to destroy the thread
 volatile bool destroyThread;
 
-int32_t readFile(std::string filename, std::string *contents) {
+int32_t readFile(const std::string &filename, std::string *contents) {
   FILE *fp;
   ssize_t read = 0;
   char *line = NULL;
@@ -64,17 +67,19 @@ int32_t readFile(std::string filename, std::string *contents) {
   return -1;
 }
 
-std::string appendRoleNodeHelper(const std::string portName,
+std::string appendRoleNodeHelper(const std::string &portName,
                                  PortRoleType type) {
   std::string node("/sys/class/typec/" + portName);
 
   switch (type) {
     case PortRoleType::DATA_ROLE:
-      return node + "/current_data_role";
+      return node + "/data_role";
     case PortRoleType::POWER_ROLE:
-      return node + "/current_power_role";
+      return node + "/power_role";
+    case PortRoleType::MODE:
+      return node + "/port_type";
     default:
-      return node + "/mode";
+      return "";
   }
 }
 
@@ -89,8 +94,8 @@ std::string convertRoletoString(PortRole role) {
     if (role.role == static_cast<uint32_t>(PortDataRole::DEVICE))
       return "device";
   } else if (role.type == PortRoleType::MODE) {
-    if (role.role == static_cast<uint32_t>(PortMode_1_1::UFP)) return "ufp";
-    if (role.role == static_cast<uint32_t>(PortMode_1_1::DFP)) return "dfp";
+    if (role.role == static_cast<uint32_t>(PortMode_1_1::UFP)) return "sink";
+    if (role.role == static_cast<uint32_t>(PortMode_1_1::DFP)) return "source";
   }
   return "none";
 }
@@ -106,60 +111,141 @@ void extractRole(std::string *roleName) {
   }
 }
 
+void switchToDrp(const std::string &portName) {
+  std::string filename =
+      appendRoleNodeHelper(std::string(portName.c_str()), PortRoleType::MODE);
+  FILE *fp;
+
+  if (filename != "") {
+    fp = fopen(filename.c_str(), "w");
+    if (fp != NULL) {
+      int ret = fputs("dual", fp);
+      fclose(fp);
+      if (ret == EOF)
+        ALOGE("Fatal: Error while switching back to drp");
+    } else {
+      ALOGE("Fatal: Cannot open file to switch back to drp");
+    }
+  } else {
+    ALOGE("Fatal: invalid node type");
+  }
+}
+
+bool switchMode(const hidl_string &portName,
+                             const PortRole &newRole, struct Usb *usb) {
+  std::string filename =
+       appendRoleNodeHelper(std::string(portName.c_str()), newRole.type);
+  std::string written;
+  FILE *fp;
+  bool roleSwitch = false;
+
+  if (filename == "") {
+    ALOGE("Fatal: invalid node type");
+    return false;
+  }
+
+  fp = fopen(filename.c_str(), "w");
+  if (fp != NULL) {
+    // Hold the lock here to prevent loosing connected signals
+    // as once the file is written the partner added signal
+    // can arrive anytime.
+    pthread_mutex_lock(&usb->mPartnerLock);
+    usb->mPartnerUp = false;
+    int ret = fputs(convertRoletoString(newRole).c_str(), fp);
+    fclose(fp);
+
+    if (ret != EOF) {
+      struct timespec   to;
+      struct timeval    tp;
+
+wait_again:
+      gettimeofday(&tp, NULL);
+      to.tv_sec = tp.tv_sec + PORT_TYPE_TIMEOUT;
+      to.tv_nsec = tp.tv_usec * 1000;;
+
+      int err = pthread_cond_timedwait(&usb->mPartnerCV, &usb->mPartnerLock, &to);
+      // There are no uevent signals which implies role swap timed out.
+      if (err == ETIMEDOUT) {
+        ALOGI("uevents wait timedout");
+      // Sanity check.
+      } else if (!usb->mPartnerUp) {
+        goto wait_again;
+      // Role switch succeeded since usb->mPartnerUp is true.
+      } else {
+        roleSwitch = true;
+      }
+    } else {
+      ALOGI("Role switch failed while wrting to file");
+    }
+    pthread_mutex_unlock(&usb->mPartnerLock);
+  }
+
+  if (!roleSwitch)
+    switchToDrp(std::string(portName.c_str()));
+
+  return roleSwitch;
+}
+
+
+
 Return<void> Usb::switchRole(const hidl_string &portName,
                              const PortRole &newRole) {
   std::string filename =
       appendRoleNodeHelper(std::string(portName.c_str()), newRole.type);
   std::string written;
   FILE *fp;
+  bool roleSwitch = false;
+
+  if (filename == "") {
+    ALOGE("Fatal: invalid node type");
+    return Void();
+  }
+
+  pthread_mutex_lock(&mRoleSwitchLock);
 
   ALOGI("filename write: %s role:%s", filename.c_str(),
         convertRoletoString(newRole).c_str());
 
-  fp = fopen(filename.c_str(), "w");
-  if (fp != NULL) {
-    int ret = fputs(convertRoletoString(newRole).c_str(), fp);
-    fclose(fp);
-    if ((ret != EOF) && !readFile(filename, &written)) {
-      extractRole(&written);
-      ALOGI("written: %s", written.c_str());
-      if (written == convertRoletoString(newRole)) {
-        pthread_mutex_lock(&mLock);
-        if (mCallback != NULL) {
-          Return<void> ret = mCallback->notifyRoleSwitchStatus(
-              portName, newRole, Status::SUCCESS);
-          if (!ret.isOk())
-            ALOGE("RoleSwitch transaction error %s", ret.description().c_str());
+  if (newRole.type == PortRoleType::MODE) {
+      roleSwitch = switchMode(portName, newRole, this);
+  } else {
+    fp = fopen(filename.c_str(), "w");
+    if (fp != NULL) {
+      int ret = fputs(convertRoletoString(newRole).c_str(), fp);
+      fclose(fp);
+      if ((ret != EOF) && !readFile(filename, &written)) {
+        extractRole(&written);
+        ALOGI("written: %s", written.c_str());
+        if (written == convertRoletoString(newRole)) {
+          roleSwitch = true;
         } else {
-          ALOGE("Not notifying the userspace. Callback is not set");
+          ALOGE("Role switch failed");
         }
-        pthread_mutex_unlock(&mLock);
-        return Void();
       } else {
-        ALOGE("Role switch failed");
+        ALOGE("failed to update the new role");
       }
     } else {
-      ALOGE("failed to update the new role");
+      ALOGE("fopen failed");
     }
-  } else {
-    ALOGE("fopen failed");
   }
 
   pthread_mutex_lock(&mLock);
-  if (mCallback != NULL) {
+  if (mCallback_1_0 != NULL) {
     Return<void> ret =
-        mCallback->notifyRoleSwitchStatus(portName, newRole, Status::ERROR);
+        mCallback_1_0->notifyRoleSwitchStatus(portName, newRole,
+        roleSwitch ? Status::SUCCESS : Status::ERROR);
     if (!ret.isOk())
       ALOGE("RoleSwitchStatus error %s", ret.description().c_str());
   } else {
     ALOGE("Not notifying the userspace. Callback is not set");
   }
   pthread_mutex_unlock(&mLock);
+  pthread_mutex_unlock(&mRoleSwitchLock);
 
   return Void();
 }
 
-Status getAccessoryConnected(std::string portName, std::string *accessory) {
+Status getAccessoryConnected(const std::string &portName, std::string *accessory) {
   std::string filename =
     "/sys/class/typec/" + portName + "-partner/accessory_mode";
 
@@ -172,7 +258,7 @@ Status getAccessoryConnected(std::string portName, std::string *accessory) {
   return Status::SUCCESS;
 }
 
-Status getCurrentRoleHelper(std::string portName, bool connected,
+Status getCurrentRoleHelper(const std::string &portName, bool connected,
                             PortRoleType type, uint32_t *currentRole) {
   std::string filename;
   std::string roleName;
@@ -181,13 +267,13 @@ Status getCurrentRoleHelper(std::string portName, bool connected,
   // Mode
 
   if (type == PortRoleType::POWER_ROLE) {
-    filename = "/sys/class/typec/" + portName + "/current_power_role";
+    filename = "/sys/class/typec/" + portName + "/power_role";
     *currentRole = static_cast<uint32_t>(PortPowerRole::NONE);
   } else if (type == PortRoleType::DATA_ROLE) {
-    filename = "/sys/class/typec/" + portName + "/current_data_role";
+    filename = "/sys/class/typec/" + portName + "/data_role";
     *currentRole = static_cast<uint32_t>(PortDataRole::NONE);
   } else if (type == PortRoleType::MODE) {
-    filename = "/sys/class/typec/" + portName + "/current_data_role";
+    filename = "/sys/class/typec/" + portName + "/data_role";
     *currentRole = static_cast<uint32_t>(PortMode_1_1::NONE);
   } else {
     return Status::ERROR;
@@ -199,10 +285,10 @@ Status getCurrentRoleHelper(std::string portName, bool connected,
     if (getAccessoryConnected(portName, &accessory) != Status::SUCCESS) {
       return Status::ERROR;
     }
-    if (accessory == "Audio Adapter Accessory Mode") {
+    if (accessory == "analog_audio") {
       *currentRole = static_cast<uint32_t>(PortMode_1_1::AUDIO_ACCESSORY);
       return Status::SUCCESS;
-    } else if (accessory == "Debug Accessory Mode") {
+    } else if (accessory == "debug") {
       *currentRole = static_cast<uint32_t>(PortMode_1_1::DEBUG_ACCESSORY);
       return Status::SUCCESS;
     }
@@ -270,13 +356,13 @@ Status getTypeCPortNamesHelper(std::unordered_map<std::string, bool> *names) {
   return Status::ERROR;
 }
 
-bool canSwitchRoleHelper(const std::string portName, PortRoleType /*type*/) {
+bool canSwitchRoleHelper(const std::string &portName, PortRoleType /*type*/) {
   std::string filename =
       "/sys/class/typec/" + portName + "-partner/supports_usb_power_delivery";
   std::string supportsPD;
 
   if (!readFile(filename, &supportsPD)) {
-    if (supportsPD == "1") {
+    if (supportsPD == "yes") {
       return true;
     }
   }
@@ -284,7 +370,13 @@ bool canSwitchRoleHelper(const std::string portName, PortRoleType /*type*/) {
   return false;
 }
 
-Status getPortStatus_1_1Helper(hidl_vec<PortStatus_1_1> *currentPortStatus_1_1) {
+/*
+ * Reuse the same method for both V1_0 and V1_1 callback objects.
+ * The caller of this method would reconstruct the V1_0::PortStatus
+ * object if required.
+ */
+Status getPortStatusHelper(hidl_vec<PortStatus_1_1> *currentPortStatus_1_1,
+    bool V1_0) {
   std::unordered_map<std::string, bool> names;
   Status result = getTypeCPortNamesHelper(&names);
   int i = -1;
@@ -320,12 +412,14 @@ Status getPortStatus_1_1Helper(hidl_vec<PortStatus_1_1> *currentPortStatus_1_1)
                                &currentRole) == Status::SUCCESS) {
         (*currentPortStatus_1_1)[i].currentMode =
             static_cast<PortMode_1_1>(currentRole);
+        (*currentPortStatus_1_1)[i].status.currentMode =
+            static_cast<V1_0::PortMode>(currentRole);
       } else {
         ALOGE("Error while retreiving current data role");
         goto done;
       }
 
-      (*currentPortStatus_1_1)[i].status.canChangeMode = false;
+      (*currentPortStatus_1_1)[i].status.canChangeMode = true;
       (*currentPortStatus_1_1)[i].status.canChangeDataRole =
           port.second ? canSwitchRoleHelper(port.first, PortRoleType::DATA_ROLE)
                       : false;
@@ -334,15 +428,18 @@ Status getPortStatus_1_1Helper(hidl_vec<PortStatus_1_1> *currentPortStatus_1_1)
               ? canSwitchRoleHelper(port.first, PortRoleType::POWER_ROLE)
               : false;
 
-      ALOGI("connected:%d canChangeMode: %d canChagedata: %d canChangePower:%d",
+      ALOGI("connected:%d canChangeMode:%d canChagedata:%d canChangePower:%d",
             port.second, (*currentPortStatus_1_1)[i].status.canChangeMode,
             (*currentPortStatus_1_1)[i].status.canChangeDataRole,
             (*currentPortStatus_1_1)[i].status.canChangePowerRole);
 
-      (*currentPortStatus_1_1)[i].supportedModes = PortMode_1_1::UFP | PortMode_1_1::DFP;
-
-      (*currentPortStatus_1_1)[i].status.supportedModes = V1_0::PortMode::NONE;
-      (*currentPortStatus_1_1)[i].status.currentMode = V1_0::PortMode::NONE;
+      if (V1_0) {
+        (*currentPortStatus_1_1)[i].status.supportedModes = V1_0::PortMode::DFP;
+      } else {
+        (*currentPortStatus_1_1)[i].supportedModes = PortMode_1_1::UFP | PortMode_1_1::DFP;
+        (*currentPortStatus_1_1)[i].status.supportedModes = V1_0::PortMode::NONE;
+        (*currentPortStatus_1_1)[i].status.currentMode = V1_0::PortMode::NONE;
+      }
     }
     return Status::SUCCESS;
   }
@@ -352,14 +449,28 @@ done:
 
 Return<void> Usb::queryPortStatus() {
   hidl_vec<PortStatus_1_1> currentPortStatus_1_1;
+  hidl_vec<V1_0::PortStatus> currentPortStatus;
   Status status;
-
-  status = getPortStatus_1_1Helper(&currentPortStatus_1_1);
+  sp<IUsbCallback> callback_V1_1 = IUsbCallback::castFrom(mCallback_1_0);
 
   pthread_mutex_lock(&mLock);
-  if (mCallback != NULL) {
-    Return<void> ret =
-        mCallback->notifyPortStatusChange_1_1(currentPortStatus_1_1, status);
+  if (mCallback_1_0 != NULL) {
+    if (callback_V1_1 != NULL) {
+      status = getPortStatusHelper(&currentPortStatus_1_1, false);
+    } else {
+      status = getPortStatusHelper(&currentPortStatus_1_1, true);
+      currentPortStatus.resize(currentPortStatus_1_1.size());
+      for (unsigned long i = 0; i < currentPortStatus_1_1.size(); i++)
+        currentPortStatus[i] = currentPortStatus_1_1[i].status;
+    }
+
+    Return<void> ret;
+
+    if (callback_V1_1 != NULL)
+      ret = callback_V1_1->notifyPortStatusChange_1_1(currentPortStatus_1_1, status);
+    else
+      ret = mCallback_1_0->notifyPortStatusChange(currentPortStatus, status);
+
     if (!ret.isOk())
       ALOGE("queryPortStatus_1_1 error %s", ret.description().c_str());
   } else {
@@ -369,6 +480,7 @@ Return<void> Usb::queryPortStatus() {
 
   return Void();
 }
+
 struct data {
   int uevent_fd;
   android::hardware::usb::V1_1::implementation::Usb *usb;
@@ -389,19 +501,62 @@ static void uevent_event(uint32_t /*epevents*/, struct data *payload) {
   cp = msg;
 
   while (*cp) {
-    if (!strncmp(cp, "DEVTYPE=typec_", strlen("DEVTYPE=typec_"))) {
+    if (std::regex_match(cp, std::regex("(add)(.*)(-partner)"))) {
+       ALOGI("partner added");
+       pthread_mutex_lock(&payload->usb->mPartnerLock);
+       payload->usb->mPartnerUp = true;
+       pthread_cond_signal(&payload->usb->mPartnerCV);
+       pthread_mutex_unlock(&payload->usb->mPartnerLock);
+    } else if (!strncmp(cp, "DEVTYPE=typec_", strlen("DEVTYPE=typec_"))) {
+      hidl_vec<PortStatus_1_1> currentPortStatus_1_1;
       ALOGI("uevent received %s", cp);
       pthread_mutex_lock(&payload->usb->mLock);
-      if (payload->usb->mCallback != NULL) {
-        hidl_vec<PortStatus_1_1> currentPortStatus_1_1;
-        Status status = getPortStatus_1_1Helper(&currentPortStatus_1_1);
-        Return<void> ret = payload->usb->mCallback->notifyPortStatusChange_1_1(
-            currentPortStatus_1_1, status);
+      if (payload->usb->mCallback_1_0 != NULL) {
+        sp<IUsbCallback> callback_V1_1 = IUsbCallback::castFrom(payload->usb->mCallback_1_0);
+        Return<void> ret;
+
+        // V1_1 callback
+        if (callback_V1_1 != NULL) {
+          Status status = getPortStatusHelper(&currentPortStatus_1_1, false);
+          ret = callback_V1_1->notifyPortStatusChange_1_1(
+              currentPortStatus_1_1, status);
+        } else { // V1_0 callback
+          Status status = getPortStatusHelper(&currentPortStatus_1_1, true);
+
+          /*
+           * Copying the result from getPortStatusHelper
+           * into V1_0::PortStatus to pass back through
+           * the V1_0 callback object.
+           */
+          hidl_vec<V1_0::PortStatus> currentPortStatus;
+          currentPortStatus.resize(currentPortStatus_1_1.size());
+          for (unsigned long i = 0; i < currentPortStatus_1_1.size(); i++)
+            currentPortStatus[i] = currentPortStatus_1_1[i].status;
+
+          ret = payload->usb->mCallback_1_0->notifyPortStatusChange(
+              currentPortStatus, status);
+        }
         if (!ret.isOk()) ALOGE("error %s", ret.description().c_str());
       } else {
         ALOGI("Notifying userspace skipped. Callback is NULL");
       }
       pthread_mutex_unlock(&payload->usb->mLock);
+
+      //Role switch is not in progress and port is in disconnected state
+      if (!pthread_mutex_trylock(&payload->usb->mRoleSwitchLock)) {
+        for (unsigned long i = 0; i < currentPortStatus_1_1.size(); i++) {
+          DIR *dp = opendir(std::string("/sys/class/typec/"
+              + std::string(currentPortStatus_1_1[i].status.portName.c_str())
+              + "-partner").c_str());
+          if (dp == NULL) {
+              //PortRole role = {.role = static_cast<uint32_t>(PortMode::UFP)};
+              switchToDrp(currentPortStatus_1_1[i].status.portName);
+          } else {
+              closedir(dp);
+          }
+        }
+        pthread_mutex_unlock(&payload->usb->mRoleSwitchLock);
+      }
       break;
     }
     /* advance to after the next \0 */
@@ -478,12 +633,13 @@ void sighandler(int sig) {
   signal(SIGUSR1, sighandler);
 }
 
-Return<void> Usb::setCallback(const sp<::android::hardware::usb::V1_0::IUsbCallback> &callback) {
+Return<void> Usb::setCallback(const sp<V1_0::IUsbCallback> &callback) {
 
   sp<IUsbCallback> callback_V1_1 = IUsbCallback::castFrom(callback);
 
   if (callback != NULL)
-    CHECK(callback_V1_1 != NULL);
+      if (callback_V1_1 == NULL)
+          ALOGI("Registering 1.0 callback");
 
   pthread_mutex_lock(&mLock);
   /*
@@ -493,18 +649,22 @@ Return<void> Usb::setCallback(const sp<::android::hardware::usb::V1_0::IUsbCallb
    * worker thread running, so updating the callback object would
    * be suffice.
    */
-  if ((mCallback == NULL && callback == NULL) ||
-      (mCallback != NULL && callback != NULL)) {
-    mCallback = callback_V1_1;
+  if ((mCallback_1_0 == NULL && callback == NULL) ||
+      (mCallback_1_0 != NULL && callback != NULL)) {
+    /*
+     * Always store as V1_0 callback object. Type cast to V1_1
+     * when the callback is actually invoked.
+     */
+    mCallback_1_0 = callback;
     pthread_mutex_unlock(&mLock);
     return Void();
   }
 
-  mCallback = callback_V1_1;
+  mCallback_1_0 = callback;
   ALOGI("registering callback");
 
   // Kill the worker thread if the new callback is NULL.
-  if (mCallback == NULL) {
+  if (mCallback_1_0 == NULL) {
     pthread_mutex_unlock(&mLock);
     if (!pthread_kill(mPoll, SIGUSR1)) {
       pthread_join(mPoll, NULL);
@@ -522,7 +682,7 @@ Return<void> Usb::setCallback(const sp<::android::hardware::usb::V1_0::IUsbCallb
    */
   if (pthread_create(&mPoll, NULL, work, this)) {
     ALOGE("pthread creation failed %d", errno);
-    mCallback = NULL;
+    mCallback_1_0 = NULL;
   }
 
   pthread_mutex_unlock(&mLock);
index 11c18ae1e3dcfb06fe4fd83d8430b15df3cedabf..bfa63aecef85a1c0ea4941b539b08062a204bc47 100644 (file)
@@ -8,6 +8,11 @@
 #include <utils/Log.h>
 
 #define UEVENT_MSG_LEN 2048
+// The type-c stack waits for 4.5 - 5.5 secs before declaring a port non-pd.
+// The -partner directory would not be created until this is done.
+// Having a margin of ~3 secs for the directory and other related bookeeping
+// structures created and uvent fired.
+#define PORT_TYPE_TIMEOUT 8
 
 namespace android {
 namespace hardware {
@@ -36,12 +41,21 @@ using ::android::sp;
 
 struct Usb : public IUsb {
     Return<void> switchRole(const hidl_string& portName, const PortRole& role) override;
-    Return<void> setCallback(const sp<::android::hardware::usb::V1_0::IUsbCallback>& callback) override;
+    Return<void> setCallback(const sp<V1_0::IUsbCallback>& callback) override;
     Return<void> queryPortStatus() override;
 
 
-    sp<IUsbCallback> mCallback;
+    sp<V1_0::IUsbCallback> mCallback_1_0;
+    // Protects mCallback variable
     pthread_mutex_t mLock = PTHREAD_MUTEX_INITIALIZER;
+    // Protects roleSwitch operation
+    pthread_mutex_t mRoleSwitchLock = PTHREAD_MUTEX_INITIALIZER;
+    // Threads waiting for the partner to come back wait here
+    pthread_cond_t mPartnerCV = PTHREAD_COND_INITIALIZER;
+    // lock protecting mPartnerCV
+    pthread_mutex_t mPartnerLock = PTHREAD_MUTEX_INITIALIZER;
+    // Variable to signal partner coming back online after type switch
+    bool mPartnerUp;
 
     private:
         pthread_t mPoll;
index e51a8709dd11d054034c0c3fe387c5ee992b5996..bc1101d1b7d9b3479dd178999c6c32ab815163cc 100644 (file)
@@ -4,7 +4,9 @@ service usb-hal-1-1 /vendor/bin/hw/android.hardware.usb@1.1-service.wahoo
     group system
 
 on boot
-    chown root system /sys/class/typec/usbc0/current_power_role
-    chown root system /sys/class/typec/usbc0/current_data_role
-    chmod 664 /sys/class/typec/usbc0/current_power_role
-    chmod 664 /sys/class/typec/usbc0/current_data_role
+    chown root system /sys/class/typec/port0/power_role
+    chown root system /sys/class/typec/port0/data_role
+    chown root system /sys/class/typec/port0/port_type
+    chmod 664 /sys/class/typec/port0/power_role
+    chmod 664 /sys/class/typec/port0/data_role
+    chmod 664 /sys/class/typec/port0/port_type