aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--rmidevice/hiddevice.cpp113
-rw-r--r--rmidevice/hiddevice.h2
2 files changed, 72 insertions, 43 deletions
diff --git a/rmidevice/hiddevice.cpp b/rmidevice/hiddevice.cpp
index 7ebf5fd..7fc03c5 100644
--- a/rmidevice/hiddevice.cpp
+++ b/rmidevice/hiddevice.cpp
@@ -31,6 +31,7 @@
#include <linux/hidraw.h>
#include <signal.h>
#include <stdlib.h>
+#include <sys/inotify.h>
#include "hiddevice.h"
@@ -567,12 +568,24 @@ void HIDDevice::RebindDriver()
std::string bindFile;
std::string unbindFile;
std::string hidrawFile;
- struct stat stat_buf;
+ int notifyFd;
+ int wd;
int rc;
- int i;
Close();
+ notifyFd = inotify_init();
+ if (notifyFd < 0) {
+ fprintf(stderr, "Failed to initialize inotify\n");
+ return;
+ }
+
+ wd = inotify_add_watch(notifyFd, "/dev", IN_CREATE);
+ if (wd < 0) {
+ fprintf(stderr, "Failed to add watcher for /dev\n");
+ return;
+ }
+
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);
@@ -599,29 +612,12 @@ void HIDDevice::RebindDriver()
return;
}
- // The hid device id has changed since this is now a new hid device. Now 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;
- }
-
- for (i = 0; i < 200; i++) {
- rc = stat(hidrawFile.c_str(), &stat_buf);
- if (!rc)
- break;
- Sleep(5);
+ if (WaitForHidRawDevice(notifyFd, hidDeviceName, hidrawFile)) {
+ rc = Open(hidrawFile.c_str());
+ if (rc)
+ fprintf(stderr, "Failed to open device (%s) during rebind: %d: errno: %s (%d)\n",
+ hidrawFile.c_str(), rc, strerror(errno), errno);
}
-
- rc = Open(hidrawFile.c_str());
- if (rc)
- fprintf(stderr, "Failed to open device (%s) during rebind: %d: errno: %s (%d)\n",
- hidrawFile.c_str(), rc, strerror(errno), errno);
}
bool HIDDevice::FindTransportDevice(int bus, std::string & hidDeviceName,
@@ -710,27 +706,60 @@ bool HIDDevice::LookupHidDeviceName(int bus, int vendorId, int productId, std::s
return ret;
}
-bool HIDDevice::FindHidRawFile(std::string & deviceName, std::string & hidrawFile)
+bool HIDDevice::WaitForHidRawDevice(int notifyFd, std::string & deviceName,
+ std::string & hidrawFile)
{
- bool ret = false;
- char hidrawDir[PATH_MAX];
- struct dirent * devDirEntry;
- DIR * devDir;
+ struct timeval timeout;
+ fd_set fds;
+ int rc;
+ size_t sz;
+ char link[PATH_MAX];
+
+ for (;;) {
+ FD_ZERO(&fds);
+ FD_SET(notifyFd, &fds);
- snprintf(hidrawDir, PATH_MAX, "/sys/bus/hid/devices/%s/hidraw", deviceName.c_str());
+ timeout.tv_sec = 1;
+ timeout.tv_usec = 0;
- devDir = opendir(hidrawDir);
- if (!devDir)
- return false;
+ rc = select(notifyFd + 1, &fds, NULL, NULL, &timeout);
+ if (rc < 0) {
+ if (errno == -EINTR)
+ continue;
- while ((devDirEntry = readdir(devDir)) != NULL) {
- if (!strncmp(devDirEntry->d_name, "hidraw", 6)) {
- hidrawFile = std::string("/dev/") + devDirEntry->d_name;
- ret = true;
- break;
+ return false;
}
- }
- closedir(devDir);
- return ret;
-}
+ if (rc == 0) {
+ return false;
+ }
+
+ if (FD_ISSET(notifyFd, &fds)) {
+ struct inotify_event * event;
+ const int buf_len = sizeof(struct inotify_event) + NAME_MAX + 1;
+ char buf[buf_len];
+
+ rc = read(notifyFd, buf, buf_len);
+ if (rc < 0) {
+ continue;
+ }
+
+ event = (struct inotify_event *)buf;
+
+ if (!strncmp(event->name, "hidraw", 6)) {
+ std::string classPath = std::string("/sys/class/hidraw/")
+ + event->name + "/device";
+ sz = readlink(classPath.c_str(), link, PATH_MAX);
+ link[sz] = 0;
+
+ // The buffer looks something like ../../../0018:06CB:76AD.0014
+ // Add 9 to strip off ../../../ and ignore the id on the end which
+ // changes per instance.
+ if (!strncmp(deviceName.c_str(), link + 9, 14)) {
+ hidrawFile = std::string("/dev/") + event->name;
+ return true;
+ }
+ }
+ }
+ }
+} \ No newline at end of file
diff --git a/rmidevice/hiddevice.h b/rmidevice/hiddevice.h
index 05a11fa..42e8c28 100644
--- a/rmidevice/hiddevice.h
+++ b/rmidevice/hiddevice.h
@@ -81,7 +81,7 @@ private:
static bool LookupHidDeviceName(int bus, int vendorId, int productId, std::string &deviceName);
static bool FindTransportDevice(int bus, std::string & hidDeviceName,
std::string & transportDeviceName, std::string & driverPath);
- static bool FindHidRawFile(std::string & hidDeviceName, std::string & hidrawFile);
+ static bool WaitForHidRawDevice(int notifyFd, std::string & deviceName, std::string & hidraw);
};
#endif /* _HIDDEVICE_H_ */