aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAndrew Duggan <aduggan@synaptics.com>2015-05-06 17:45:48 -0700
committerAndrew Duggan <aduggan@synaptics.com>2015-05-06 17:50:14 -0700
commitbef9c2dd3bfbe71b75f59c0dba08402414e008a2 (patch)
tree1211eb6e9d01ca93abd7af06a4ae72af2b7f148e
parentbc1e37b101aa71b785e0c78abb1c2ee546506b60 (diff)
downloadrmi4utils-bef9c2dd3bfbe71b75f59c0dba08402414e008a2.tar.gz
Allow rebinding of the transport device to force a reload of the HID descriptors
In some cases during firmware update the size of the input reports can change this commit allows for the unbinding and rebinding of the transport HID device to force a reload of the HID descriptors so that the new size if read by the HID transport drivers.
-rw-r--r--rmi4update/main.cpp116
-rw-r--r--rmi4update/rmi4update.cpp2
-rw-r--r--rmidevice/hiddevice.cpp191
-rw-r--r--rmidevice/hiddevice.h8
-rw-r--r--rmidevice/rmidevice.h1
5 files changed, 202 insertions, 116 deletions
diff --git a/rmi4update/main.cpp b/rmi4update/main.cpp
index 2f86068..96b1965 100644
--- a/rmi4update/main.cpp
+++ b/rmi4update/main.cpp
@@ -71,113 +71,6 @@ int UpdateDevice(FirmwareImage & image, bool force, bool performLockdown, const
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 because the
- * parameters of the device may have changed in the new firmware and the
- * driver should redo the initialization ensure it is using the new values.
- */
-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 GetFirmwareProps(const char * deviceFile, std::string &props)
{
HIDDevice rmidevice;
@@ -282,17 +175,10 @@ int main(int argc, char **argv)
}
if (deviceName) {
- char * rawDevice;
rc = UpdateDevice(image, force, performLockdown, deviceName);
- if (rc)
- return rc;
- rawDevice = strcasestr(deviceName, "hidraw");
- if (rawDevice)
- RebindDriver(rawDevice);
return rc;
} else {
- char rawDevice[PATH_MAX];
char deviceFile[PATH_MAX];
bool found = false;
@@ -302,6 +188,7 @@ int main(int argc, char **argv)
while ((devDirEntry = readdir(devDir)) != NULL) {
if (strstr(devDirEntry->d_name, "hidraw")) {
+ char rawDevice[PATH_MAX];
strncpy(rawDevice, devDirEntry->d_name, PATH_MAX);
snprintf(deviceFile, PATH_MAX, "/dev/%s", devDirEntry->d_name);
rc = UpdateDevice(image, force, performLockdown, deviceFile);
@@ -309,7 +196,6 @@ int main(int argc, char **argv)
continue;
} else {
found = true;
- RebindDriver(rawDevice);
break;
}
}
diff --git a/rmi4update/rmi4update.cpp b/rmi4update/rmi4update.cpp
index 2888e24..7217701 100644
--- a/rmi4update/rmi4update.cpp
+++ b/rmi4update/rmi4update.cpp
@@ -499,4 +499,4 @@ int RMI4Update::WaitForIdle(int timeout_ms)
fprintf(stderr, "Idle: %d\n", !m_f34Command && !m_f34Status);
return UPDATE_FAIL_NOT_IN_IDLE_STATE;
-}
+} \ No newline at end of file
diff --git a/rmidevice/hiddevice.cpp b/rmidevice/hiddevice.cpp
index f756660..54d5465 100644
--- a/rmidevice/hiddevice.cpp
+++ b/rmidevice/hiddevice.cpp
@@ -19,6 +19,7 @@
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
+#include <dirent.h>
#include <errno.h>
#include <string.h>
#include <unistd.h>
@@ -485,3 +486,193 @@ void HIDDevice::PrintReport(const unsigned char *report)
}
fprintf(stdout, "\n\n");
}
+
+bool WriteDeviceNameToFile(const char * file, const char * str)
+{
+ int fd;
+ ssize_t size;
+
+ fd = open(file, O_WRONLY);
+ if (fd < 0)
+ return false;
+
+ for (;;) {
+ size = write(fd, str, 19);
+ if (size < 0) {
+ if (errno == EINTR)
+ continue;
+
+ return false;
+ }
+ break;
+ }
+ close(fd);
+
+ return true;
+}
+
+void HIDDevice::RebindDriver()
+{
+ int bus = m_info.bustype;
+ int vendor = m_info.vendor;
+ int product = m_info.product;
+ std::string hidDeviceName;
+ std::string transportDeviceName;
+ std::string driverPath;
+ std::string bindFile;
+ std::string unbindFile;
+ std::string hidrawFile;
+
+ Close();
+
+ if (!LookupHidDeviceName(bus, vendor, product, hidDeviceName)) {
+ fprintf(stderr, "Failed to find HID device name for the specified device: bus (0x%x) vendor: (0x%x) product: (0x%x)\n",
+ bus, vendor, product);
+ return;
+ }
+
+ if (!FindTransportDriver(bus, hidDeviceName, transportDeviceName, driverPath)) {
+ fprintf(stderr, "Failed to find the transport device / driver for %s\n", hidDeviceName.c_str());
+ return;
+ }
+
+ bindFile = driverPath + "bind";
+ unbindFile = driverPath + "unbind";
+
+ if (!WriteDeviceNameToFile(unbindFile.c_str(), transportDeviceName.c_str())) {
+ fprintf(stderr, "Failed to unbind HID device %s: %s\n",
+ transportDeviceName.c_str(), strerror(errno));
+ return;
+ }
+
+ if (!WriteDeviceNameToFile(bindFile.c_str(), transportDeviceName.c_str())) {
+ fprintf(stderr, "Failed to bind HID device %s: %s\n",
+ transportDeviceName.c_str(), strerror(errno));
+ return;
+ }
+
+ // The hid device id has changed this is now a new hid device so we have to look up the new name
+ if (!LookupHidDeviceName(bus, vendor, product, hidDeviceName)) {
+ fprintf(stderr, "Failed to find HID device name for the specified device: bus (0x%x) vendor: (0x%x) product: (0x%x)\n",
+ bus, vendor, product);
+ return;
+ }
+
+ if (!FindHidRawFile(hidDeviceName, hidrawFile)) {
+ fprintf(stderr, "Failed to find the hidraw device file for %s\n", hidDeviceName.c_str());
+ return;
+ }
+
+ Open(hidrawFile.c_str());
+}
+
+bool HIDDevice::FindTransportDriver(int bus, std::string & hidDeviceName,
+ std::string & transportDeviceName, std::string & driverPath)
+{
+ std::string devicePrefix = "/sys/bus/";
+ std::string devicePath;
+ struct dirent * devicesDirEntry;
+ DIR * devicesDir;
+ struct dirent * devDirEntry;
+ DIR * devDir;
+ bool deviceFound = false;
+ ssize_t sz;
+
+ if (bus == BUS_I2C) {
+ devicePrefix += "i2c/";
+ driverPath = devicePrefix + "drivers/i2c_hid/";
+ } else {
+ devicePrefix += "usb/";
+ driverPath = devicePrefix + "drivers/usbhid/";
+ }
+ devicePath = devicePrefix + "devices/";
+
+ devicesDir = opendir(devicePath.c_str());
+ if (!devicesDir)
+ return false;
+
+ while((devicesDirEntry = readdir(devicesDir)) != NULL) {
+ if (devicesDirEntry->d_type != DT_LNK)
+ continue;
+
+ char buf[PATH_MAX];
+
+ sz = readlinkat(dirfd(devicesDir), devicesDirEntry->d_name, buf, PATH_MAX);
+ if (sz < 0)
+ continue;
+
+ buf[sz] = 0;
+
+ std::string fullLinkPath = devicePath + buf;
+ devDir = opendir(fullLinkPath.c_str());
+ if (!devDir) {
+ fprintf(stdout, "opendir failed\n");
+ continue;
+ }
+
+ while ((devDirEntry = readdir(devDir)) != NULL) {
+ if (!strcmp(devDirEntry->d_name, hidDeviceName.c_str())) {
+ transportDeviceName = devicesDirEntry->d_name;
+ deviceFound = true;
+ break;
+ }
+ }
+ closedir(devDir);
+
+ if (deviceFound)
+ break;
+ }
+ closedir(devicesDir);
+
+ return deviceFound;
+}
+
+bool HIDDevice::LookupHidDeviceName(int bus, int vendorId, int productId, std::string & deviceName)
+{
+ bool ret = false;
+ struct dirent * devDirEntry;
+ DIR * devDir;
+ char devicePrefix[15];
+
+ snprintf(devicePrefix, 15, "%04X:%04X:%04X", bus, vendorId, productId);
+
+ devDir = opendir("/sys/bus/hid/devices");
+ if (!devDir)
+ return false;
+
+ while ((devDirEntry = readdir(devDir)) != NULL) {
+ if (!strncmp(devDirEntry->d_name, devicePrefix, 14)) {
+ deviceName = devDirEntry->d_name;
+ ret = true;
+ break;
+ }
+ }
+ closedir(devDir);
+
+ return ret;
+}
+
+bool HIDDevice::FindHidRawFile(std::string & deviceName, std::string & hidrawFile)
+{
+ bool ret = false;
+ char hidrawDir[PATH_MAX];
+ struct dirent * devDirEntry;
+ DIR * devDir;
+
+ snprintf(hidrawDir, PATH_MAX, "/sys/bus/hid/devices/%s/hidraw", deviceName.c_str());
+
+ devDir = opendir(hidrawDir);
+ if (!devDir)
+ return false;
+
+ while ((devDirEntry = readdir(devDir)) != NULL) {
+ if (!strncmp(devDirEntry->d_name, "hidraw", 6)) {
+ hidrawFile = std::string("/dev/") + devDirEntry->d_name;
+ ret = true;
+ break;
+ }
+ }
+ closedir(devDir);
+
+ return ret;
+} \ No newline at end of file
diff --git a/rmidevice/hiddevice.h b/rmidevice/hiddevice.h
index ba2d942..ac7439d 100644
--- a/rmidevice/hiddevice.h
+++ b/rmidevice/hiddevice.h
@@ -19,6 +19,7 @@
#define _HIDDEVICE_H_
#include <linux/hidraw.h>
+#include <string>
#include "rmidevice.h"
class HIDDevice : public RMIDevice
@@ -38,6 +39,7 @@ public:
virtual int GetAttentionReport(struct timeval * timeout, unsigned int source_mask,
unsigned char *buf, unsigned int *len);
virtual void Close();
+ virtual void RebindDriver();
~HIDDevice() { Close(); }
private:
@@ -68,6 +70,12 @@ private:
int GetReport(int *reportId, struct timeval * timeout = NULL);
void PrintReport(const unsigned char *report);
void ParseReportSizes();
+
+ // static HID utility functions
+ static bool LookupHidDeviceName(int bus, int vendorId, int productId, std::string &deviceName);
+ static bool FindTransportDriver(int bus, std::string & hidDeviceName,
+ std::string & transportDeviceName, std::string & driverPath);
+ static bool FindHidRawFile(std::string & hidDeviceName, std::string & hidrawFile);
};
#endif /* _HIDDEVICE_H_ */
diff --git a/rmidevice/rmidevice.h b/rmidevice/rmidevice.h
index c6d83e5..d213168 100644
--- a/rmidevice/rmidevice.h
+++ b/rmidevice/rmidevice.h
@@ -45,6 +45,7 @@ public:
{ return -1; /* Unsupported */ }
virtual void Close() = 0;
virtual void Cancel() { m_bCancel = true; }
+ virtual void RebindDriver() = 0;
unsigned long GetFirmwareID() { return m_buildID; }
int GetFirmwareVersionMajor() { return m_firmwareVersionMajor; }