diff options
-rw-r--r-- | rmi4update/main.cpp | 116 | ||||
-rw-r--r-- | rmi4update/rmi4update.cpp | 2 | ||||
-rw-r--r-- | rmidevice/hiddevice.cpp | 191 | ||||
-rw-r--r-- | rmidevice/hiddevice.h | 8 | ||||
-rw-r--r-- | rmidevice/rmidevice.h | 1 |
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; } |