aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-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; }