aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAndrew Duggan <aduggan@synaptics.com>2014-07-31 11:22:01 -0700
committerAndrew Duggan <aduggan@synaptics.com>2014-07-31 11:22:01 -0700
commit64f3a0c0192fb883513d949114cb2f8147a0af83 (patch)
tree7cc568205ed4e1e588dea46c7b812cf738b01e7b
parent18cc3b3343a6518f22de111134900b1e535aeea4 (diff)
downloadplatform_external_rmi4utils-64f3a0c0192fb883513d949114cb2f8147a0af83.tar.gz
platform_external_rmi4utils-64f3a0c0192fb883513d949114cb2f8147a0af83.tar.bz2
platform_external_rmi4utils-64f3a0c0192fb883513d949114cb2f8147a0af83.zip
Unbind and rebind the driver to the device after firmware update so that the driver reinitializes
based on the updated values and ensure the device is powered on.
-rw-r--r--rmi4update/main.cpp123
-rw-r--r--rmi4update/updateutil.cpp14
-rw-r--r--rmi4update/updateutil.h1
3 files changed, 135 insertions, 3 deletions
diff --git a/rmi4update/main.cpp b/rmi4update/main.cpp
index b2b5fcb..a807f43 100644
--- a/rmi4update/main.cpp
+++ b/rmi4update/main.cpp
@@ -20,7 +20,11 @@
#include <errno.h>
#include <getopt.h>
#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
#include <dirent.h>
+#include <unistd.h>
+#include <time.h>
#include "hiddevice.h"
#include "rmi4update.h"
@@ -52,6 +56,116 @@ int UpdateDevice(FirmwareImage & image, bool force, const char * deviceFile)
return rc;
}
+int WriteDeviceNameToFile(const char * file, const char * str)
+{
+ int fd;
+ ssize_t size;
+
+ fd = open(file, O_WRONLY);
+ if (fd < 0)
+ return UPDATE_FAIL;
+
+ for (;;) {
+ size = write(fd, str, 19);
+ if (size < 0) {
+ if (errno == EINTR)
+ continue;
+
+ return UPDATE_FAIL;
+ }
+ break;
+ }
+
+ close(fd);
+
+ return UPDATE_SUCCESS;
+}
+
+/*
+ * We need to rebind the driver to the device after firmware update for two reasons
+ * a) The parameters of the device may have changed in the new firmware so the
+ * driver should redo the initialization to read the new values.
+ * b) Kernel commit 0f5a24c6 will now power down the device once we close the
+ * file descriptor for the hidraw device file. Reloading the driver powers the
+ * device back on.
+ */
+void RebindDriver(const char * hidraw)
+{
+ int rc;
+ ssize_t size;
+ char bindFile[PATH_MAX];
+ char unbindFile[PATH_MAX];
+ char deviceLink[PATH_MAX];
+ char driverName[PATH_MAX];
+ char driverLink[PATH_MAX];
+ char linkBuf[PATH_MAX];
+ char hidDeviceString[20];
+ int i;
+
+ snprintf(unbindFile, PATH_MAX, "/sys/class/hidraw/%s/device/driver/unbind", hidraw);
+ snprintf(deviceLink, PATH_MAX, "/sys/class/hidraw/%s/device", hidraw);
+
+ size = readlink(deviceLink, linkBuf, PATH_MAX);
+ if (size < 0) {
+ fprintf(stderr, "Failed to find the HID string for this device: %s\n",
+ hidraw);
+ return;
+ }
+ linkBuf[size] = 0;
+
+ strncpy(hidDeviceString, StripPath(linkBuf, size), 20);
+
+ snprintf(driverLink, PATH_MAX, "/sys/class/hidraw/%s/device/driver", hidraw);
+
+ size = readlink(driverLink, linkBuf, PATH_MAX);
+ if (size < 0) {
+ fprintf(stderr, "Failed to find the HID string for this device: %s\n",
+ hidraw);
+ return;
+ }
+ linkBuf[size] = 0;
+
+ strncpy(driverName, StripPath(linkBuf, size), PATH_MAX);
+
+ snprintf(bindFile, PATH_MAX, "/sys/bus/hid/drivers/%s/bind", driverName);
+
+ rc = WriteDeviceNameToFile(unbindFile, hidDeviceString);
+ if (rc != UPDATE_SUCCESS) {
+ fprintf(stderr, "Failed to unbind HID device %s: %s\n",
+ hidDeviceString, strerror(errno));
+ return;
+ }
+
+ for (i = 0;; ++i) {
+ struct timespec req;
+ struct timespec rem;
+
+ rc = WriteDeviceNameToFile(bindFile, hidDeviceString);
+ if (rc == UPDATE_SUCCESS)
+ return;
+
+ if (i <= 4)
+ break;
+
+ /* device might not be ready yet to bind to */
+ req.tv_sec = 0;
+ req.tv_nsec = 100 * 1000 * 1000; /* 100 ms */
+ for (;;) {
+ rc = nanosleep(&req, &rem);
+ if (rc < 0) {
+ if (errno == EINTR) {
+ req = rem;
+ continue;
+ }
+ }
+ break;
+ }
+ }
+
+ fprintf(stderr, "Failed to bind HID device %s: %s\n",
+ hidDeviceString, strerror(errno));
+}
+
int main(int argc, char **argv)
{
int rc;
@@ -103,7 +217,8 @@ int main(int argc, char **argv)
if (deviceName) {
return UpdateDevice(image, force, deviceName);
} else {
- char buf[PATH_MAX];
+ char rawDevice[PATH_MAX];
+ char deviceFile[PATH_MAX];
bool found = false;
devDir = opendir("/dev");
@@ -112,12 +227,14 @@ int main(int argc, char **argv)
while ((devDirEntry = readdir(devDir)) != NULL) {
if (strstr(devDirEntry->d_name, "hidraw")) {
- snprintf(buf, PATH_MAX, "/dev/%s", devDirEntry->d_name);
- rc = UpdateDevice(image, force, buf);
+ strncpy(rawDevice, devDirEntry->d_name, PATH_MAX);
+ snprintf(deviceFile, PATH_MAX, "/dev/%s", devDirEntry->d_name);
+ rc = UpdateDevice(image, force, deviceFile);
if (rc != 0) {
continue;
} else {
found = true;
+ RebindDriver(rawDevice);
break;
}
}
diff --git a/rmi4update/updateutil.cpp b/rmi4update/updateutil.cpp
index 7950e4c..5b27e71 100644
--- a/rmi4update/updateutil.cpp
+++ b/rmi4update/updateutil.cpp
@@ -15,6 +15,8 @@
* limitations under the License.
*/
+#include <sys/types.h>
+
#include "updateutil.h"
const char *update_error_str[] = {
@@ -68,4 +70,16 @@ unsigned short extract_short(const unsigned char *data)
{
return (unsigned long)data [0]
+ (unsigned long)data [1] * 0x100;
+}
+
+const char * StripPath(char * path, ssize_t size)
+{
+ int i;
+ char * str;
+
+ for (i = size - 1, str = &path[size - 1]; i > 0; --i, --str)
+ if (path[i - 1] == '/')
+ break;
+
+ return str;
} \ No newline at end of file
diff --git a/rmi4update/updateutil.h b/rmi4update/updateutil.h
index 92c934d..70fc8a0 100644
--- a/rmi4update/updateutil.h
+++ b/rmi4update/updateutil.h
@@ -56,5 +56,6 @@ const char * update_err_to_string(int err);
unsigned long extract_long(const unsigned char *data);
unsigned short extract_short(const unsigned char *data);
+const char * StripPath(char * path, ssize_t size);
#endif // _UPDATEUTIL_H_ \ No newline at end of file