diff options
Diffstat (limited to 'rmidevice')
-rw-r--r-- | rmidevice/Android.bp | 6 | ||||
-rw-r--r-- | rmidevice/Makefile | 2 | ||||
-rwxr-xr-x[-rw-r--r--] | rmidevice/hiddevice.cpp | 446 | ||||
-rwxr-xr-x[-rw-r--r--] | rmidevice/hiddevice.h | 36 | ||||
-rw-r--r-- | rmidevice/rmidevice.cpp | 66 | ||||
-rw-r--r-- | rmidevice/rmidevice.h | 24 | ||||
-rw-r--r-- | rmidevice/util.cpp | 70 |
7 files changed, 503 insertions, 147 deletions
diff --git a/rmidevice/Android.bp b/rmidevice/Android.bp index 6d67f4c..9b6ec71 100644 --- a/rmidevice/Android.bp +++ b/rmidevice/Android.bp @@ -10,14 +10,16 @@ package { cc_library_static { name: "rmidevice", srcs: [ - "rmifunction.cpp", - "rmidevice.cpp", "hiddevice.cpp", + "rmidevice.cpp", + "rmifunction.cpp", + "util.cpp", ], cflags: [ "-Wall", "-Werror", "-Wno-unused-parameter", + "-Wno-unused-variable", ], export_include_dirs: ["."], } diff --git a/rmidevice/Makefile b/rmidevice/Makefile index 35aec55..d9f32cc 100644 --- a/rmidevice/Makefile +++ b/rmidevice/Makefile @@ -3,7 +3,7 @@ AR ?= ar RANLIB ?= ranlib CPPFLAGS += -I../include -I./include CXXFLAGS += -fPIC -Wall -RMIDEVICESRC = rmifunction.cpp rmidevice.cpp hiddevice.cpp +RMIDEVICESRC = rmifunction.cpp rmidevice.cpp hiddevice.cpp util.cpp RMIDEVICEOBJ = $(RMIDEVICESRC:.cpp=.o) LIBNAME = librmidevice.so STATIC_LIBNAME = librmidevice.a diff --git a/rmidevice/hiddevice.cpp b/rmidevice/hiddevice.cpp index 7ebf5fd..709559d 100644..100755 --- 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" @@ -40,12 +41,6 @@ #define RMI_ATTN_REPORT_ID 0xc // Input Report #define RMI_SET_RMI_MODE_REPORT_ID 0xf // Feature Report -enum rmi_hid_mode_type { - HID_RMI4_MODE_MOUSE = 0, - HID_RMI4_MODE_ATTN_REPORTS = 1, - HID_RMI4_MODE_NO_PACKED_ATTN_REPORTS = 2, -}; - enum hid_report_type { HID_REPORT_TYPE_UNKNOWN = 0x0, HID_REPORT_TYPE_INPUT = 0x81, @@ -71,6 +66,8 @@ int HIDDevice::Open(const char * filename) { int rc; int desc_size; + std::string hidDeviceName; + std::string hidDriverName; if (!filename) return -EINVAL; @@ -84,58 +81,80 @@ int HIDDevice::Open(const char * filename) rc = ioctl(m_fd, HIDIOCGRDESCSIZE, &desc_size); if (rc < 0) - return rc; + goto error; m_rptDesc.size = desc_size; rc = ioctl(m_fd, HIDIOCGRDESC, &m_rptDesc); if (rc < 0) - return rc; + goto error; rc = ioctl(m_fd, HIDIOCGRAWINFO, &m_info); if (rc < 0) - return rc; + goto error; if (m_info.vendor != SYNAPTICS_VENDOR_ID) { errno = -ENODEV; - return -1; + rc = -1; + goto error; } - ParseReportSizes(); + ParseReportDescriptor(); m_inputReport = new unsigned char[m_inputReportSize](); if (!m_inputReport) { errno = -ENOMEM; - return -1; + rc = -1; + goto error; } m_outputReport = new unsigned char[m_outputReportSize](); if (!m_outputReport) { errno = -ENOMEM; - return -1; + rc = -1; + goto error; } m_readData = new unsigned char[m_inputReportSize](); if (!m_readData) { errno = -ENOMEM; - return -1; + rc = -1; + goto error; } m_attnData = new unsigned char[m_inputReportSize](); if (!m_attnData) { errno = -ENOMEM; - return -1; + rc = -1; + goto error; } m_deviceOpen = true; - rc = SetMode(HID_RMI4_MODE_ATTN_REPORTS); - if (rc) - return -1; + // Determine which mode the device is currently running in based on the current HID driver + // hid-rmi indicated RMI Mode 1 all others would be Mode 0 + if (LookupHidDeviceName(m_info.bustype, m_info.vendor, m_info.product, hidDeviceName)) { + if (LookupHidDriverName(hidDeviceName, hidDriverName)) { + if (hidDriverName == "hid-rmi") + m_initialMode = HID_RMI4_MODE_ATTN_REPORTS; + } + } + + if (m_initialMode != m_mode) { + rc = SetMode(m_mode); + if (rc) { + rc = -1; + goto error; + } + } return 0; + +error: + Close(); + return rc; } -void HIDDevice::ParseReportSizes() +void HIDDevice::ParseReportDescriptor() { bool isVendorSpecific = false; bool isReport = false; @@ -143,10 +162,18 @@ void HIDDevice::ParseReportSizes() int reportSize = 0; int reportCount = 0; enum hid_report_type hidReportType = HID_REPORT_TYPE_UNKNOWN; + bool inCollection = false; for (unsigned int i = 0; i < m_rptDesc.size; ++i) { + if (m_rptDesc.value[i] == 0xc0) { + inCollection = false; + isVendorSpecific = false; + isReport = false; + continue; + } + if (isVendorSpecific) { - if (m_rptDesc.value[i] == 0x85 || m_rptDesc.value[i] == 0xc0) { + if (m_rptDesc.value[i] == 0x85) { if (isReport) { // finish up data on the previous report totalReportSize = (reportSize * reportCount) >> 3; @@ -173,13 +200,7 @@ void HIDDevice::ParseReportSizes() reportCount = 0; hidReportType = HID_REPORT_TYPE_UNKNOWN; - if (m_rptDesc.value[i] == 0x85) - isReport = true; - else - isReport = false; - - if (m_rptDesc.value[i] == 0xc0) - isVendorSpecific = false; + isReport = true; } if (isReport) { @@ -209,12 +230,52 @@ void HIDDevice::ParseReportSizes() } } - if (i + 2 >= m_rptDesc.size) - return; - if (m_rptDesc.value[i] == 0x06 && m_rptDesc.value[i + 1] == 0x00 - && m_rptDesc.value[i + 2] == 0xFF) { - isVendorSpecific = true; - i += 2; + if (!inCollection) { + switch (m_rptDesc.value[i]) { + case 0x00: + case 0x01: + case 0x02: + case 0x03: + case 0x04: + inCollection = true; + break; + case 0x05: + inCollection = true; + + if (i + 3 >= m_rptDesc.size) + break; + + // touchscreens with active pen have a Generic Mouse collection + // so stop searching if we have already found the touchscreen digitizer + // usage. + if (m_deviceType == RMI_DEVICE_TYPE_TOUCHSCREEN) + break; + + if (m_rptDesc.value[i + 1] == 0x01) { + if (m_rptDesc.value[i + 2] == 0x09 && m_rptDesc.value[i + 3] == 0x02) + m_deviceType = RMI_DEVICE_TYPE_TOUCHPAD; + } else if (m_rptDesc.value[i + 1] == 0x0d) { + if (m_rptDesc.value[i + 2] == 0x09 && m_rptDesc.value[i + 3] == 0x04) + m_deviceType = RMI_DEVICE_TYPE_TOUCHSCREEN; + // for Precision Touch Pad + else if (m_rptDesc.value[i + 2] == 0x09 && m_rptDesc.value[i + 3] == 0x05) + m_deviceType = RMI_DEVICE_TYPE_TOUCHPAD; + } + i += 3; + break; + case 0x06: + inCollection = true; + if (i + 2 >= m_rptDesc.size) + break; + + if (m_rptDesc.value[i + 1] == 0x00 && m_rptDesc.value[i + 2] == 0xFF) + isVendorSpecific = true; + i += 2; + break; + default: + break; + + } } } } @@ -277,12 +338,14 @@ int HIDDevice::Read(unsigned short addr, unsigned char *buf, unsigned short len) if (rc > 0 && reportId == RMI_READ_DATA_REPORT_ID) { if (static_cast<ssize_t>(m_inputReportSize) < std::max(HID_RMI4_READ_INPUT_COUNT, - HID_RMI4_READ_INPUT_DATA)) + HID_RMI4_READ_INPUT_DATA)){ return -1; + } bytesInDataReport = m_readData[HID_RMI4_READ_INPUT_COUNT]; if (bytesInDataReport > bytesToRequest - || bytesReadPerRequest + bytesInDataReport > len) + || bytesReadPerRequest + bytesInDataReport > len){ return -1; + } memcpy(buf + bytesReadPerRequest, &m_readData[HID_RMI4_READ_INPUT_DATA], bytesInDataReport); bytesReadPerRequest += bytesInDataReport; @@ -345,10 +408,14 @@ int HIDDevice::SetMode(int mode) void HIDDevice::Close() { + RMIDevice::Close(); + if (!m_deviceOpen) return; - SetMode(HID_RMI4_MODE_MOUSE); + if (m_initialMode != m_mode) + SetMode(m_initialMode); + m_deviceOpen = false; close(m_fd); m_fd = -1; @@ -527,10 +594,15 @@ void HIDDevice::PrintReport(const unsigned char *report) // Print protocol specific device information void HIDDevice::PrintDeviceInfo() { + enum RMIDeviceType deviceType = GetDeviceType(); + fprintf(stdout, "HID device info:\nBus: %s Vendor: 0x%04x Product: 0x%04x\n", m_info.bustype == BUS_I2C ? "I2C" : "USB", m_info.vendor, m_info.product); fprintf(stdout, "Report sizes: input: %ld output: %ld\n", (unsigned long)m_inputReportSize, (unsigned long)m_outputReportSize); + if (deviceType) + fprintf(stdout, "device type: %s\n", deviceType == RMI_DEVICE_TYPE_TOUCHSCREEN ? + "touchscreen" : "touchpad"); } bool WriteDeviceNameToFile(const char * file, const char * str) @@ -555,76 +627,159 @@ bool WriteDeviceNameToFile(const char * file, const char * str) return close(fd) == 0 && size == static_cast<ssize_t>(strlen(str)); } +static const char * const absval[6] = { "Value", "Min ", "Max ", "Fuzz ", "Flat ", "Resolution "}; +#define KEY_MAX 0x2ff +#define EV_MAX 0x1f +#define BITS_PER_LONG (sizeof(long) * 8) +#define NBITS(x) ((((x)-1)/BITS_PER_LONG)+1) +#define OFF(x) ((x)%BITS_PER_LONG) +#define BIT(x) (1UL<<OFF(x)) +#define LONG(x) ((x)/BITS_PER_LONG) +#define test_bit(bit, array) ((array[LONG(bit)] >> OFF(bit)) & 1) +#define DEV_INPUT_EVENT "/dev/input" +#define EVENT_DEV_NAME "event" +/** + * Filter for the AutoDevProbe scandir on /dev/input. + * + * @param dir The current directory entry provided by scandir. + * + * @return Non-zero if the given directory entry starts with "event", or zero + * otherwise. + */ +static int is_event_device(const struct dirent *dir) { + return strncmp(EVENT_DEV_NAME, dir->d_name, 5) == 0; +} + +bool HIDDevice::CheckABSEvent() +{ + int fd=-1; + unsigned int type; + int abs[6] = {0}; + int k; + struct dirent **namelist; + int i, ndev, devnum, match; + char *filename; + int max_device = 0; + char input_event_name[PATH_MAX]; + unsigned long bit[EV_MAX][NBITS(KEY_MAX)]; + + +#ifdef __BIONIC__ + // Android's libc doesn't have the GNU versionsort extension. + ndev = scandir(DEV_INPUT_EVENT, &namelist, is_event_device, alphasort); +#else + ndev = scandir(DEV_INPUT_EVENT, &namelist, is_event_device, versionsort); +#endif + if (ndev <= 0) + return false; + for (i = 0; i < ndev; i++) + { + char fname[64]; + int fd = -1; + char name[256] = "???"; + + snprintf(fname, sizeof(fname), + "%s/%s", DEV_INPUT_EVENT, namelist[i]->d_name); + fd = open(fname, O_RDONLY); + if (fd < 0) + continue; + ioctl(fd, EVIOCGNAME(sizeof(name)), name); + //fprintf(stderr, "%s: %s\n", fname, name); + close(fd); + if(strstr(name, m_transportDeviceName.c_str()+4)) + { + snprintf(input_event_name, sizeof(fname), "%s", fname); + } + free(namelist[i]); + } + + if ((fd = open(input_event_name, O_RDONLY)) < 0) { + if (errno == EACCES && getuid() != 0) + fprintf(stderr, "No access right \n"); + } + memset(bit, 0, sizeof(bit)); + ioctl(fd, EVIOCGBIT(0, EV_MAX), bit[0]); + for (type = 0; type < EV_MAX; type++) { + if (test_bit(type, bit[0]) && type == EV_ABS) { + ioctl(fd, EVIOCGBIT(type, KEY_MAX), bit[type]); + if (test_bit(ABS_X, bit[type])) { + ioctl(fd, EVIOCGABS(ABS_X), abs); + if(abs[2] == 0) //maximum + { + Sleep(1000); + return false; + } + } + } + } + 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; - struct stat stat_buf; + int notifyFd; + int wd; int rc; - int i; - 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); + notifyFd = inotify_init(); + if (notifyFd < 0) { + fprintf(stderr, "Failed to initialize inotify\n"); return; } - if (!FindTransportDevice(bus, hidDeviceName, transportDeviceName, driverPath)) { - fprintf(stderr, "Failed to find the transport device / driver for %s\n", hidDeviceName.c_str()); + wd = inotify_add_watch(notifyFd, "/dev", IN_CREATE); + if (wd < 0) { + fprintf(stderr, "Failed to add watcher for /dev\n"); return; } - bindFile = driverPath + "bind"; - unbindFile = driverPath + "unbind"; + if (m_transportDeviceName == "") { + 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 (!WriteDeviceNameToFile(unbindFile.c_str(), transportDeviceName.c_str())) { - fprintf(stderr, "Failed to unbind HID device %s: %s\n", - transportDeviceName.c_str(), strerror(errno)); - return; - } + if (!FindTransportDevice(bus, hidDeviceName, m_transportDeviceName, m_driverPath)) { + fprintf(stderr, "Failed to find the transport device / driver for %s\n", hidDeviceName.c_str()); + 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; } + + bindFile = m_driverPath + "bind"; + unbindFile = m_driverPath + "unbind"; - // 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); + Sleep(500); + if (!WriteDeviceNameToFile(unbindFile.c_str(), m_transportDeviceName.c_str())) { + fprintf(stderr, "Failed to unbind HID device %s: %s\n", + m_transportDeviceName.c_str(), strerror(errno)); return; } - - if (!FindHidRawFile(hidDeviceName, hidrawFile)) { - fprintf(stderr, "Failed to find the hidraw device file for %s\n", hidDeviceName.c_str()); + Sleep(500); + if (!WriteDeviceNameToFile(bindFile.c_str(), m_transportDeviceName.c_str())) { + fprintf(stderr, "Failed to bind HID device %s: %s\n", + m_transportDeviceName.c_str(), strerror(errno)); return; } - for (i = 0; i < 200; i++) { - rc = stat(hidrawFile.c_str(), &stat_buf); - if (!rc) - break; - Sleep(5); + if (WaitForHidRawDevice(notifyFd, 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, +bool HIDDevice::FindTransportDevice(uint32_t bus, std::string & hidDeviceName, std::string & transportDeviceName, std::string & driverPath) { std::string devicePrefix = "/sys/bus/"; @@ -638,7 +793,15 @@ bool HIDDevice::FindTransportDevice(int bus, std::string & hidDeviceName, if (bus == BUS_I2C) { devicePrefix += "i2c/"; - driverPath = devicePrefix + "drivers/i2c_hid/"; + // From new patch released on 2020/11, i2c_hid would be renamed as i2c_hid_acpi, + // and also need backward compatible. + std::string driverPathTemp = devicePrefix + "drivers/i2c_hid/"; + DIR *driverPathtest = opendir(driverPathTemp.c_str()); + if(!driverPathtest) { + driverPath = devicePrefix + "drivers/i2c_hid_acpi/"; + } else { + driverPath = devicePrefix + "drivers/i2c_hid/"; + } } else { devicePrefix += "usb/"; driverPath = devicePrefix + "drivers/usbhid/"; @@ -685,14 +848,14 @@ bool HIDDevice::FindTransportDevice(int bus, std::string & hidDeviceName, return deviceFound; } -bool HIDDevice::LookupHidDeviceName(int bus, int vendorId, int productId, std::string & deviceName) +bool HIDDevice::LookupHidDeviceName(uint32_t bus, int16_t vendorId, int16_t productId, std::string & deviceName) { bool ret = false; struct dirent * devDirEntry; DIR * devDir; char devicePrefix[15]; - snprintf(devicePrefix, 15, "%04X:%04X:%04X", bus, vendorId, productId); + snprintf(devicePrefix, 15, "%04X:%04X:%04X", bus, (vendorId & 0xFFFF), (productId & 0xFFFF)); devDir = opendir("/sys/bus/hid/devices"); if (!devDir) @@ -710,27 +873,128 @@ bool HIDDevice::LookupHidDeviceName(int bus, int vendorId, int productId, std::s return ret; } -bool HIDDevice::FindHidRawFile(std::string & deviceName, std::string & hidrawFile) +bool HIDDevice::LookupHidDriverName(std::string &deviceName, std::string &driverName) { bool ret = false; - char hidrawDir[PATH_MAX]; - struct dirent * devDirEntry; - DIR * devDir; + ssize_t sz; + char link[PATH_MAX]; + std::string driverLink = "/sys/bus/hid/devices/" + deviceName + "/driver"; + + sz = readlink(driverLink.c_str(), link, PATH_MAX); + if (sz == -1) + return ret; - snprintf(hidrawDir, PATH_MAX, "/sys/bus/hid/devices/%s/hidraw", deviceName.c_str()); + link[sz] = 0; - devDir = opendir(hidrawDir); + driverName = std::string(StripPath(link, PATH_MAX)); + + return true; +} + +bool HIDDevice::WaitForHidRawDevice(int notifyFd, std::string & hidrawFile) +{ + struct timeval timeout; + fd_set fds; + int rc; + ssize_t eventBytesRead; + int eventBytesAvailable; + size_t sz; + char link[PATH_MAX]; + std::string transportDeviceName; + std::string driverPath; + std::string hidDeviceName; + int offset = 0; + + for (;;) { + FD_ZERO(&fds); + FD_SET(notifyFd, &fds); + + timeout.tv_sec = 20; + timeout.tv_usec = 0; + + rc = select(notifyFd + 1, &fds, NULL, NULL, &timeout); + if (rc < 0) { + if (errno == -EINTR) + continue; + + return false; + } + + if (rc == 0) { + return false; + } + + if (FD_ISSET(notifyFd, &fds)) { + struct inotify_event * event; + + rc = ioctl(notifyFd, FIONREAD, &eventBytesAvailable); + if (rc < 0) { + continue; + } + + char buf[eventBytesAvailable]; + + eventBytesRead = read(notifyFd, buf, eventBytesAvailable); + if (eventBytesRead < 0) { + continue; + } + + while (offset < eventBytesRead) { + event = (struct inotify_event *)&buf[offset]; + + 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; + + hidDeviceName = std::string(link).substr(9, 19); + + if (!FindTransportDevice(m_info.bustype, hidDeviceName, transportDeviceName, driverPath)) { + fprintf(stderr, "Failed to find the transport device / driver for %s\n", hidDeviceName.c_str()); + continue; + } + + if (transportDeviceName == m_transportDeviceName) { + hidrawFile = std::string("/dev/") + event->name; + return true; + } + } + + offset += sizeof(struct inotify_event) + event->len; + } + } + } +} + +bool HIDDevice::FindDevice(enum RMIDeviceType type) +{ + DIR * devDir; + struct dirent * devDirEntry; + char deviceFile[PATH_MAX]; + bool found = false; + int rc; + devDir = opendir("/dev"); if (!devDir) - return false; + return -1; while ((devDirEntry = readdir(devDir)) != NULL) { - if (!strncmp(devDirEntry->d_name, "hidraw", 6)) { - hidrawFile = std::string("/dev/") + devDirEntry->d_name; - ret = true; - break; + if (strstr(devDirEntry->d_name, "hidraw")) { + snprintf(deviceFile, PATH_MAX, "/dev/%s", devDirEntry->d_name); + fprintf(stdout, "Got device : /dev/%s\n", devDirEntry->d_name); + rc = Open(deviceFile); + if (rc != 0) { + continue; + } else if (type != RMI_DEVICE_TYPE_ANY && GetDeviceType() != type) { + Close(); + continue; + } else { + found = true; + break; + } } } closedir(devDir); - - return ret; + + return found; } diff --git a/rmidevice/hiddevice.h b/rmidevice/hiddevice.h index 05a11fa..b947f62 100644..100755 --- a/rmidevice/hiddevice.h +++ b/rmidevice/hiddevice.h @@ -20,8 +20,15 @@ #include <linux/hidraw.h> #include <string> +#include <stdint.h> #include "rmidevice.h" +enum rmi_hid_mode_type { + HID_RMI4_MODE_MOUSE = 0, + HID_RMI4_MODE_ATTN_REPORTS = 1, + HID_RMI4_MODE_NO_PACKED_ATTN_REPORTS = 2, +}; + class HIDDevice : public RMIDevice { public: @@ -30,7 +37,11 @@ public: m_inputReportSize(0), m_outputReportSize(0), m_featureReportSize(0), - m_deviceOpen(false) + m_deviceOpen(false), + m_mode(HID_RMI4_MODE_ATTN_REPORTS), + m_initialMode(HID_RMI4_MODE_MOUSE), + m_transportDeviceName(""), + m_driverPath("") {} virtual int Open(const char * filename); virtual int Read(unsigned short addr, unsigned char *buf, @@ -48,6 +59,9 @@ public: virtual void PrintDeviceInfo(); + virtual bool FindDevice(enum RMIDeviceType type = RMI_DEVICE_TYPE_ANY); + virtual bool CheckABSEvent(); + private: int m_fd; @@ -67,21 +81,23 @@ private: bool m_deviceOpen; - enum mode_type { - HID_RMI4_MODE_MOUSE = 0, - HID_RMI4_MODE_ATTN_REPORTS = 1, - HID_RMI4_MODE_NO_PACKED_ATTN_REPORTS = 2, - }; + rmi_hid_mode_type m_mode; + rmi_hid_mode_type m_initialMode; + + std::string m_transportDeviceName; + std::string m_driverPath; int GetReport(int *reportId, struct timeval * timeout = NULL); void PrintReport(const unsigned char *report); - void ParseReportSizes(); + void ParseReportDescriptor(); + + bool WaitForHidRawDevice(int notifyFd, std::string & hidraw); // static HID utility functions - static bool LookupHidDeviceName(int bus, int vendorId, int productId, std::string &deviceName); - static bool FindTransportDevice(int bus, std::string & hidDeviceName, + static bool LookupHidDeviceName(uint32_t bus, int16_t vendorId, int16_t productId, std::string &deviceName); + static bool LookupHidDriverName(std::string &deviceName, std::string &driverName); + static bool FindTransportDevice(uint32_t 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.cpp b/rmidevice/rmidevice.cpp index 71bafa0..15335f9 100644 --- a/rmidevice/rmidevice.cpp +++ b/rmidevice/rmidevice.cpp @@ -50,6 +50,7 @@ #define RMI_DEVICE_F01_QRY43_01_BUILD_ID (1 << 1) #define PACKAGE_ID_BYTES 4 +#define CONFIG_ID_BYTES 4 #define BUILD_ID_BYTES 3 #define RMI_F01_CMD_DEVICE_RESET 1 @@ -75,10 +76,13 @@ int RMIDevice::QueryBasicProperties() { int rc; unsigned char basicQuery[RMI_DEVICE_F01_BASIC_QUERY_LEN]; + unsigned char configid[CONFIG_ID_BYTES]; unsigned short queryAddr; + unsigned short controlAddr; unsigned char infoBuf[4]; unsigned short prodInfoAddr; RMIFunction f01; + RMIFunction f34; SetRMIPage(0x00); @@ -187,9 +191,30 @@ int RMIDevice::QueryBasicProperties() } } } + + if (GetFunction(f34, 0x34)) { + controlAddr = f34.GetControlBase(); + rc = Read(controlAddr, configid, CONFIG_ID_BYTES); + if (rc < 0 || rc < CONFIG_ID_BYTES) { + fprintf(stderr, "Failed to read the config id: %s\n", strerror(errno)); + return rc; + } + m_configID = (configid[0] << 24 | configid[1] << 16 + | configid[2] << 8 | configid[3]) & 0xFFFFFFFF; + } + return 0; } +void RMIDevice::Close() +{ + m_functionList.clear(); + m_bCancel = false; + m_bytesPerReadRequest = 0; + m_page = -1; + m_deviceType = RMI_DEVICE_TYPE_ANY; +} + void RMIDevice::PrintProperties() { fprintf(stdout, "manufacturerID:\t\t%d\n", m_manufacturerID); @@ -320,43 +345,4 @@ bool RMIDevice::InBootloader() return !!(status & 0x40); } return true; -} - -long long diff_time(struct timespec *start, struct timespec *end) -{ - long long diff; - diff = (end->tv_sec - start->tv_sec) * 1000 * 1000; - diff += (end->tv_nsec - start->tv_nsec) / 1000; - return diff; -} - -int Sleep(int ms) -{ - struct timespec ts; - struct timespec rem; - - ts.tv_sec = ms / 1000; - ts.tv_nsec = (ms % 1000) * 1000 * 1000; - for (;;) { - if (nanosleep(&ts, &rem) == 0) { - break; - } else { - if (errno == EINTR) { - ts = rem; - continue; - } - return -1; - } - } - return 0; -} - -void print_buffer(const unsigned char *buf, unsigned int len) -{ - for (unsigned int i = 0; i < len; ++i) { - fprintf(stdout, "0x%02X ", buf[i]); - if (i % 8 == 7) - fprintf(stdout, "\n"); - } - fprintf(stdout, "\n"); -} +}
\ No newline at end of file diff --git a/rmidevice/rmidevice.h b/rmidevice/rmidevice.h index 48de72b..9bfe849 100644 --- a/rmidevice/rmidevice.h +++ b/rmidevice/rmidevice.h @@ -27,10 +27,17 @@ #define RMI_INTERUPT_SOURCES_ALL_MASK 0xFFFFFFFF +enum RMIDeviceType { + RMI_DEVICE_TYPE_ANY = 0, + RMI_DEVICE_TYPE_TOUCHPAD, + RMI_DEVICE_TYPE_TOUCHSCREEN, +}; + class RMIDevice { public: - RMIDevice() : m_functionList(), m_sensorID(0), m_bCancel(false), m_bytesPerReadRequest(0), m_page(-1) + RMIDevice() : m_functionList(), m_sensorID(0), m_bCancel(false), m_bytesPerReadRequest(0), m_page(-1), + m_deviceType(RMI_DEVICE_TYPE_ANY) {} virtual ~RMIDevice() {} virtual int Open(const char * filename) = 0; @@ -44,11 +51,13 @@ public: virtual int GetAttentionReport(struct timeval * timeout, unsigned int source_mask, unsigned char *buf, unsigned int *len) { return -1; /* Unsupported */ } - virtual void Close() = 0; + virtual void Close(); virtual void Cancel() { m_bCancel = true; } virtual void RebindDriver() = 0; + virtual bool CheckABSEvent() = 0; unsigned long GetFirmwareID() { return m_buildID; } + unsigned long GetConfigID() { return m_configID; } int GetFirmwareVersionMajor() { return m_firmwareVersionMajor; } int GetFirmwareVersionMinor() { return m_firmwareVersionMinor; } virtual int QueryBasicProperties(); @@ -69,6 +78,9 @@ public: unsigned int GetNumInterruptRegs() { return m_numInterruptRegs; } + virtual bool FindDevice(enum RMIDeviceType type = RMI_DEVICE_TYPE_ANY) = 0; + enum RMIDeviceType GetDeviceType() { return m_deviceType; } + protected: std::vector<RMIFunction> m_functionList; unsigned char m_manufacturerID; @@ -82,6 +94,7 @@ protected: unsigned short m_packageID; unsigned short m_packageRev; unsigned long m_buildID; + unsigned long m_configID; unsigned char m_sensorID; unsigned long m_boardID; @@ -101,10 +114,15 @@ protected: int m_page; unsigned int m_numInterruptRegs; - }; + + enum RMIDeviceType m_deviceType; +}; /* Utility Functions */ long long diff_time(struct timespec *start, struct timespec *end); int Sleep(int ms); void print_buffer(const unsigned char *buf, unsigned int len); +unsigned long extract_long(const unsigned char *data); +unsigned short extract_short(const unsigned char *data); +const char * StripPath(const char * path, ssize_t size); #endif /* _RMIDEVICE_H_ */ diff --git a/rmidevice/util.cpp b/rmidevice/util.cpp new file mode 100644 index 0000000..64b1c1c --- /dev/null +++ b/rmidevice/util.cpp @@ -0,0 +1,70 @@ +#include <stdio.h> +#include <sys/types.h> +#include <errno.h> +#include <time.h> + +long long diff_time(struct timespec *start, struct timespec *end) +{ + long long diff; + diff = (end->tv_sec - start->tv_sec) * 1000 * 1000; + diff += (end->tv_nsec - start->tv_nsec) / 1000; + return diff; +} + +int Sleep(int ms) +{ + struct timespec ts; + struct timespec rem; + + ts.tv_sec = ms / 1000; + ts.tv_nsec = (ms % 1000) * 1000 * 1000; + for (;;) { + if (nanosleep(&ts, &rem) == 0) { + break; + } else { + if (errno == EINTR) { + ts = rem; + continue; + } + return -1; + } + } + return 0; +} + +void print_buffer(const unsigned char *buf, unsigned int len) +{ + for (unsigned int i = 0; i < len; ++i) { + fprintf(stdout, "0x%02X ", buf[i]); + if (i % 8 == 7) + fprintf(stdout, "\n"); + } + fprintf(stdout, "\n"); +} + + +const char * StripPath(const char * path, ssize_t size) +{ + int i; + const char * str; + + for (i = size - 1, str = &path[size - 1]; i > 0; --i, --str) + if (path[i - 1] == '/') + break; + + return str; +} + +unsigned long extract_long(const unsigned char *data) +{ + return (unsigned long)data [0] + + (unsigned long)data [1] * 0x100 + + (unsigned long)data [2] * 0x10000 + + (unsigned long)data [3] * 0x1000000; +} + +unsigned short extract_short(const unsigned char *data) +{ + return (unsigned long)data [0] + + (unsigned long)data [1] * 0x100; +}
\ No newline at end of file |