1 /* 2 * Copyright (C) 2014 Andrew Duggan 3 * Copyright (C) 2014 Synaptics Inc 4 * 5 * Licensed under the Apache License, Version 2.0 (the "License"); 6 * you may not use this file except in compliance with the License. 7 * You may obtain a copy of the License at 8 * 9 * http://www.apache.org/licenses/LICENSE-2.0 10 * 11 * Unless required by applicable law or agreed to in writing, software 12 * distributed under the License is distributed on an "AS IS" BASIS, 13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 * See the License for the specific language governing permissions and 15 * limitations under the License. 16 */ 17 18 #include <stdio.h> 19 #include <sys/types.h> 20 #include <sys/stat.h> 21 #include <fcntl.h> 22 #include <dirent.h> 23 #include <errno.h> 24 #include <string.h> 25 #include <unistd.h> 26 #include <sys/ioctl.h> 27 #include <sys/select.h> 28 29 #include <linux/types.h> 30 #include <linux/input.h> 31 #include <linux/hidraw.h> 32 #include <signal.h> 33 #include <stdlib.h> 34 35 #include "hiddevice.h" 36 37 #define RMI_WRITE_REPORT_ID 0x9 // Output Report 38 #define RMI_READ_ADDR_REPORT_ID 0xa // Output Report 39 #define RMI_READ_DATA_REPORT_ID 0xb // Input Report 40 #define RMI_ATTN_REPORT_ID 0xc // Input Report 41 #define RMI_SET_RMI_MODE_REPORT_ID 0xf // Feature Report 42 43 enum rmi_hid_mode_type { 44 HID_RMI4_MODE_MOUSE = 0, 45 HID_RMI4_MODE_ATTN_REPORTS = 1, 46 HID_RMI4_MODE_NO_PACKED_ATTN_REPORTS = 2, 47 }; 48 49 enum hid_report_type { 50 HID_REPORT_TYPE_UNKNOWN = 0x0, 51 HID_REPORT_TYPE_INPUT = 0x81, 52 HID_REPORT_TYPE_OUTPUT = 0x91, 53 HID_REPORT_TYPE_FEATURE = 0xb1, 54 }; 55 56 #define HID_RMI4_REPORT_ID 0 57 #define HID_RMI4_READ_INPUT_COUNT 1 58 #define HID_RMI4_READ_INPUT_DATA 2 59 #define HID_RMI4_READ_OUTPUT_ADDR 2 60 #define HID_RMI4_READ_OUTPUT_COUNT 4 61 #define HID_RMI4_WRITE_OUTPUT_COUNT 1 62 #define HID_RMI4_WRITE_OUTPUT_ADDR 2 63 #define HID_RMI4_WRITE_OUTPUT_DATA 4 64 #define HID_RMI4_FEATURE_MODE 1 65 #define HID_RMI4_ATTN_INTERUPT_SOURCES 1 66 #define HID_RMI4_ATTN_DATA 2 67 68 #define SYNAPTICS_VENDOR_ID 0x06cb 69 70 int HIDDevice::Open(const char * filename) 71 { 72 int rc; 73 int desc_size; 74 75 if (!filename) 76 return -EINVAL; 77 78 m_fd = open(filename, O_RDWR); 79 if (m_fd < 0) 80 return -1; 81 82 memset(&m_rptDesc, 0, sizeof(m_rptDesc)); 83 memset(&m_info, 0, sizeof(m_info)); 84 85 rc = ioctl(m_fd, HIDIOCGRDESCSIZE, &desc_size); 86 if (rc < 0) 87 return rc; 88 89 m_rptDesc.size = desc_size; 90 rc = ioctl(m_fd, HIDIOCGRDESC, &m_rptDesc); 91 if (rc < 0) 92 return rc; 93 94 rc = ioctl(m_fd, HIDIOCGRAWINFO, &m_info); 95 if (rc < 0) 96 return rc; 97 98 if (m_info.vendor != SYNAPTICS_VENDOR_ID) { 99 errno = -ENODEV; 100 return -1; 101 } 102 103 ParseReportSizes(); 104 105 m_inputReport = new unsigned char[m_inputReportSize](); 106 if (!m_inputReport) { 107 errno = -ENOMEM; 108 return -1; 109 } 110 111 m_outputReport = new unsigned char[m_outputReportSize](); 112 if (!m_outputReport) { 113 errno = -ENOMEM; 114 return -1; 115 } 116 117 m_readData = new unsigned char[m_inputReportSize](); 118 if (!m_readData) { 119 errno = -ENOMEM; 120 return -1; 121 } 122 123 m_attnData = new unsigned char[m_inputReportSize](); 124 if (!m_attnData) { 125 errno = -ENOMEM; 126 return -1; 127 } 128 129 m_deviceOpen = true; 130 131 rc = SetMode(HID_RMI4_MODE_ATTN_REPORTS); 132 if (rc) 133 return -1; 134 135 return 0; 136 } 137 138 void HIDDevice::ParseReportSizes() 139 { 140 bool isVendorSpecific = false; 141 bool isReport = false; 142 int totalReportSize = 0; 143 int reportSize = 0; 144 int reportCount = 0; 145 enum hid_report_type hidReportType = HID_REPORT_TYPE_UNKNOWN; 146 147 for (unsigned int i = 0; i < m_rptDesc.size; ++i) { 148 if (isVendorSpecific) { 149 if (m_rptDesc.value[i] == 0x85 || m_rptDesc.value[i] == 0xc0) { 150 if (isReport) { 151 // finish up data on the previous report 152 totalReportSize = (reportSize * reportCount) >> 3; 153 154 switch (hidReportType) { 155 case HID_REPORT_TYPE_INPUT: 156 m_inputReportSize = totalReportSize + 1; 157 break; 158 case HID_REPORT_TYPE_OUTPUT: 159 m_outputReportSize = totalReportSize + 1; 160 break; 161 case HID_REPORT_TYPE_FEATURE: 162 m_featureReportSize = totalReportSize + 1; 163 break; 164 case HID_REPORT_TYPE_UNKNOWN: 165 default: 166 break; 167 } 168 } 169 170 // reset values for the new report 171 totalReportSize = 0; 172 reportSize = 0; 173 reportCount = 0; 174 hidReportType = HID_REPORT_TYPE_UNKNOWN; 175 176 if (m_rptDesc.value[i] == 0x85) 177 isReport = true; 178 else 179 isReport = false; 180 181 if (m_rptDesc.value[i] == 0xc0) 182 isVendorSpecific = false; 183 } 184 185 if (isReport) { 186 if (m_rptDesc.value[i] == 0x75) { 187 if (i + 1 >= m_rptDesc.size) 188 return; 189 reportSize = m_rptDesc.value[++i]; 190 continue; 191 } 192 193 if (m_rptDesc.value[i] == 0x95) { 194 if (i + 1 >= m_rptDesc.size) 195 return; 196 reportCount = m_rptDesc.value[++i]; 197 continue; 198 } 199 200 if (m_rptDesc.value[i] == HID_REPORT_TYPE_INPUT) 201 hidReportType = HID_REPORT_TYPE_INPUT; 202 203 if (m_rptDesc.value[i] == HID_REPORT_TYPE_OUTPUT) 204 hidReportType = HID_REPORT_TYPE_OUTPUT; 205 206 if (m_rptDesc.value[i] == HID_REPORT_TYPE_FEATURE) { 207 hidReportType = HID_REPORT_TYPE_FEATURE; 208 } 209 } 210 } 211 212 if (i + 2 >= m_rptDesc.size) 213 return; 214 if (m_rptDesc.value[i] == 0x06 && m_rptDesc.value[i + 1] == 0x00 215 && m_rptDesc.value[i + 2] == 0xFF) { 216 isVendorSpecific = true; 217 i += 2; 218 } 219 } 220 } 221 222 int HIDDevice::Read(unsigned short addr, unsigned char *buf, unsigned short len) 223 { 224 ssize_t count; 225 size_t bytesReadPerRequest; 226 size_t bytesInDataReport; 227 size_t totalBytesRead; 228 size_t bytesPerRequest; 229 size_t bytesWritten; 230 size_t bytesToRequest; 231 int reportId; 232 int rc; 233 234 if (!m_deviceOpen) 235 return -1; 236 237 if (m_bytesPerReadRequest) 238 bytesPerRequest = m_bytesPerReadRequest; 239 else 240 bytesPerRequest = len; 241 242 for (totalBytesRead = 0; totalBytesRead < len; totalBytesRead += bytesReadPerRequest) { 243 count = 0; 244 if ((len - totalBytesRead) < bytesPerRequest) 245 bytesToRequest = len % bytesPerRequest; 246 else 247 bytesToRequest = bytesPerRequest; 248 249 if (m_outputReportSize < HID_RMI4_READ_OUTPUT_COUNT + 2) { 250 return -1; 251 } 252 m_outputReport[HID_RMI4_REPORT_ID] = RMI_READ_ADDR_REPORT_ID; 253 m_outputReport[1] = 0; /* old 1 byte read count */ 254 m_outputReport[HID_RMI4_READ_OUTPUT_ADDR] = addr & 0xFF; 255 m_outputReport[HID_RMI4_READ_OUTPUT_ADDR + 1] = (addr >> 8) & 0xFF; 256 m_outputReport[HID_RMI4_READ_OUTPUT_COUNT] = bytesToRequest & 0xFF; 257 m_outputReport[HID_RMI4_READ_OUTPUT_COUNT + 1] = (bytesToRequest >> 8) & 0xFF; 258 259 m_dataBytesRead = 0; 260 261 for (bytesWritten = 0; bytesWritten < m_outputReportSize; bytesWritten += count) { 262 m_bCancel = false; 263 count = write(m_fd, m_outputReport + bytesWritten, 264 m_outputReportSize - bytesWritten); 265 if (count < 0) { 266 if (errno == EINTR && m_deviceOpen && !m_bCancel) 267 continue; 268 else 269 return count; 270 } 271 break; 272 } 273 274 bytesReadPerRequest = 0; 275 while (bytesReadPerRequest < bytesToRequest) { 276 rc = GetReport(&reportId); 277 if (rc > 0 && reportId == RMI_READ_DATA_REPORT_ID) { 278 if (static_cast<ssize_t>(m_inputReportSize) < 279 std::max(HID_RMI4_READ_INPUT_COUNT, 280 HID_RMI4_READ_INPUT_DATA)) 281 return -1; 282 bytesInDataReport = m_readData[HID_RMI4_READ_INPUT_COUNT]; 283 if (bytesInDataReport > bytesToRequest 284 || bytesReadPerRequest + bytesInDataReport > len) 285 return -1; 286 memcpy(buf + bytesReadPerRequest, &m_readData[HID_RMI4_READ_INPUT_DATA], 287 bytesInDataReport); 288 bytesReadPerRequest += bytesInDataReport; 289 m_dataBytesRead = 0; 290 } 291 } 292 addr += bytesPerRequest; 293 } 294 295 return totalBytesRead; 296 } 297 298 int HIDDevice::Write(unsigned short addr, const unsigned char *buf, unsigned short len) 299 { 300 ssize_t count; 301 302 if (!m_deviceOpen) 303 return -1; 304 305 if (static_cast<ssize_t>(m_outputReportSize) < 306 HID_RMI4_WRITE_OUTPUT_DATA + len) 307 return -1; 308 m_outputReport[HID_RMI4_REPORT_ID] = RMI_WRITE_REPORT_ID; 309 m_outputReport[HID_RMI4_WRITE_OUTPUT_COUNT] = len; 310 m_outputReport[HID_RMI4_WRITE_OUTPUT_ADDR] = addr & 0xFF; 311 m_outputReport[HID_RMI4_WRITE_OUTPUT_ADDR + 1] = (addr >> 8) & 0xFF; 312 memcpy(&m_outputReport[HID_RMI4_WRITE_OUTPUT_DATA], buf, len); 313 314 for (;;) { 315 m_bCancel = false; 316 count = write(m_fd, m_outputReport, m_outputReportSize); 317 if (count < 0) { 318 if (errno == EINTR && m_deviceOpen && !m_bCancel) 319 continue; 320 else 321 return count; 322 } 323 return len; 324 } 325 } 326 327 int HIDDevice::SetMode(int mode) 328 { 329 int rc; 330 char buf[2]; 331 332 if (!m_deviceOpen) 333 return -1; 334 335 buf[0] = 0xF; 336 buf[1] = mode; 337 rc = ioctl(m_fd, HIDIOCSFEATURE(2), buf); 338 if (rc < 0) { 339 perror("HIDIOCSFEATURE"); 340 return rc; 341 } 342 343 return 0; 344 } 345 346 void HIDDevice::Close() 347 { 348 if (!m_deviceOpen) 349 return; 350 351 SetMode(HID_RMI4_MODE_MOUSE); 352 m_deviceOpen = false; 353 close(m_fd); 354 m_fd = -1; 355 356 delete[] m_inputReport; 357 m_inputReport = NULL; 358 delete[] m_outputReport; 359 m_outputReport = NULL; 360 delete[] m_readData; 361 m_readData = NULL; 362 delete[] m_attnData; 363 m_attnData = NULL; 364 } 365 366 int HIDDevice::WaitForAttention(struct timeval * timeout, unsigned int source_mask) 367 { 368 return GetAttentionReport(timeout, source_mask, NULL, NULL); 369 } 370 371 int HIDDevice::GetAttentionReport(struct timeval * timeout, unsigned int source_mask, 372 unsigned char *buf, unsigned int *len) 373 { 374 int rc = 0; 375 int reportId; 376 377 // Assume the Linux implementation of select with timeout set to the 378 // time remaining. 379 while (!timeout || (timeout->tv_sec != 0 || timeout->tv_usec != 0)) { 380 rc = GetReport(&reportId, timeout); 381 if (rc > 0) { 382 if (reportId == RMI_ATTN_REPORT_ID) { 383 // If a valid buffer is passed in then copy the data from 384 // the attention report into it. If the buffer is 385 // too small simply set *len to 0 to indicate nothing 386 // was copied. Some callers won't care about the contents 387 // of the report so failing to copy the data should not return 388 // an error. 389 if (buf && len) { 390 if (*len >= m_inputReportSize) { 391 *len = m_inputReportSize; 392 memcpy(buf, m_attnData, *len); 393 } else { 394 *len = 0; 395 } 396 } 397 398 if (m_inputReportSize < HID_RMI4_ATTN_INTERUPT_SOURCES + 1) 399 return -1; 400 401 if (source_mask & m_attnData[HID_RMI4_ATTN_INTERUPT_SOURCES]) 402 return rc; 403 } 404 } else { 405 return rc; 406 } 407 } 408 409 return rc; 410 } 411 412 int HIDDevice::GetReport(int *reportId, struct timeval * timeout) 413 { 414 ssize_t count = 0; 415 fd_set fds; 416 int rc; 417 418 if (!m_deviceOpen) 419 return -1; 420 421 if (m_inputReportSize < HID_RMI4_REPORT_ID + 1) 422 return -1; 423 424 for (;;) { 425 FD_ZERO(&fds); 426 FD_SET(m_fd, &fds); 427 428 rc = select(m_fd + 1, &fds, NULL, NULL, timeout); 429 if (rc == 0) { 430 return -ETIMEDOUT; 431 } else if (rc < 0) { 432 if (errno == EINTR && m_deviceOpen && !m_bCancel) 433 continue; 434 else 435 return rc; 436 } else if (rc > 0 && FD_ISSET(m_fd, &fds)) { 437 size_t offset = 0; 438 for (;;) { 439 m_bCancel = false; 440 count = read(m_fd, m_inputReport + offset, m_inputReportSize - offset); 441 if (count < 0) { 442 if (errno == EINTR && m_deviceOpen && !m_bCancel) 443 continue; 444 else 445 return count; 446 } 447 offset += count; 448 if (offset == m_inputReportSize) 449 break; 450 } 451 count = offset; 452 } 453 break; 454 } 455 456 if (reportId) 457 *reportId = m_inputReport[HID_RMI4_REPORT_ID]; 458 459 if (m_inputReport[HID_RMI4_REPORT_ID] == RMI_ATTN_REPORT_ID) { 460 if (static_cast<ssize_t>(m_inputReportSize) < count) 461 return -1; 462 memcpy(m_attnData, m_inputReport, count); 463 } else if (m_inputReport[HID_RMI4_REPORT_ID] == RMI_READ_DATA_REPORT_ID) { 464 if (static_cast<ssize_t>(m_inputReportSize) < count) 465 return -1; 466 memcpy(m_readData, m_inputReport, count); 467 m_dataBytesRead = count; 468 } 469 return 1; 470 } 471 472 void HIDDevice::PrintReport(const unsigned char *report) 473 { 474 int i; 475 int len = 0; 476 const unsigned char * data; 477 int addr = 0; 478 479 switch (report[HID_RMI4_REPORT_ID]) { 480 case RMI_WRITE_REPORT_ID: 481 len = report[HID_RMI4_WRITE_OUTPUT_COUNT]; 482 data = &report[HID_RMI4_WRITE_OUTPUT_DATA]; 483 addr = (report[HID_RMI4_WRITE_OUTPUT_ADDR] & 0xFF) 484 | ((report[HID_RMI4_WRITE_OUTPUT_ADDR + 1] & 0xFF) << 8); 485 fprintf(stdout, "Write Report:\n"); 486 fprintf(stdout, "Address = 0x%02X\n", addr); 487 fprintf(stdout, "Length = 0x%02X\n", len); 488 break; 489 case RMI_READ_ADDR_REPORT_ID: 490 addr = (report[HID_RMI4_READ_OUTPUT_ADDR] & 0xFF) 491 | ((report[HID_RMI4_READ_OUTPUT_ADDR + 1] & 0xFF) << 8); 492 len = (report[HID_RMI4_READ_OUTPUT_COUNT] & 0xFF) 493 | ((report[HID_RMI4_READ_OUTPUT_COUNT + 1] & 0xFF) << 8); 494 fprintf(stdout, "Read Request (Output Report):\n"); 495 fprintf(stdout, "Address = 0x%02X\n", addr); 496 fprintf(stdout, "Length = 0x%02X\n", len); 497 return; 498 break; 499 case RMI_READ_DATA_REPORT_ID: 500 len = report[HID_RMI4_READ_INPUT_COUNT]; 501 data = &report[HID_RMI4_READ_INPUT_DATA]; 502 fprintf(stdout, "Read Data Report:\n"); 503 fprintf(stdout, "Length = 0x%02X\n", len); 504 break; 505 case RMI_ATTN_REPORT_ID: 506 fprintf(stdout, "Attention Report:\n"); 507 len = 28; 508 data = &report[HID_RMI4_ATTN_DATA]; 509 fprintf(stdout, "Interrupt Sources: 0x%02X\n", 510 report[HID_RMI4_ATTN_INTERUPT_SOURCES]); 511 break; 512 default: 513 fprintf(stderr, "Unknown Report: ID 0x%02x\n", report[HID_RMI4_REPORT_ID]); 514 return; 515 } 516 517 fprintf(stdout, "Data:\n"); 518 for (i = 0; i < len; ++i) { 519 fprintf(stdout, "0x%02X ", data[i]); 520 if (i % 8 == 7) { 521 fprintf(stdout, "\n"); 522 } 523 } 524 fprintf(stdout, "\n\n"); 525 } 526 527 // Print protocol specific device information 528 void HIDDevice::PrintDeviceInfo() 529 { 530 fprintf(stdout, "HID device info:\nBus: %s Vendor: 0x%04x Product: 0x%04x\n", 531 m_info.bustype == BUS_I2C ? "I2C" : "USB", m_info.vendor, m_info.product); 532 fprintf(stdout, "Report sizes: input: %ld output: %ld\n", (unsigned long)m_inputReportSize, 533 (unsigned long)m_outputReportSize); 534 } 535 536 bool WriteDeviceNameToFile(const char * file, const char * str) 537 { 538 int fd; 539 ssize_t size; 540 541 fd = open(file, O_WRONLY); 542 if (fd < 0) 543 return false; 544 545 for (;;) { 546 size = write(fd, str, strlen(str)); 547 if (size < 0) { 548 if (errno == EINTR) 549 continue; 550 551 return false; 552 } 553 break; 554 } 555 556 return close(fd) == 0 && size == static_cast<ssize_t>(strlen(str)); 557 } 558 559 void HIDDevice::RebindDriver() 560 { 561 int bus = m_info.bustype; 562 int vendor = m_info.vendor; 563 int product = m_info.product; 564 std::string hidDeviceName; 565 std::string transportDeviceName; 566 std::string driverPath; 567 std::string bindFile; 568 std::string unbindFile; 569 std::string hidrawFile; 570 struct stat stat_buf; 571 int rc; 572 int i; 573 574 Close(); 575 576 if (!LookupHidDeviceName(bus, vendor, product, hidDeviceName)) { 577 fprintf(stderr, "Failed to find HID device name for the specified device: bus (0x%x) vendor: (0x%x) product: (0x%x)\n", 578 bus, vendor, product); 579 return; 580 } 581 582 if (!FindTransportDevice(bus, hidDeviceName, transportDeviceName, driverPath)) { 583 fprintf(stderr, "Failed to find the transport device / driver for %s\n", hidDeviceName.c_str()); 584 return; 585 } 586 587 bindFile = driverPath + "bind"; 588 unbindFile = driverPath + "unbind"; 589 590 if (!WriteDeviceNameToFile(unbindFile.c_str(), transportDeviceName.c_str())) { 591 fprintf(stderr, "Failed to unbind HID device %s: %s\n", 592 transportDeviceName.c_str(), strerror(errno)); 593 return; 594 } 595 596 if (!WriteDeviceNameToFile(bindFile.c_str(), transportDeviceName.c_str())) { 597 fprintf(stderr, "Failed to bind HID device %s: %s\n", 598 transportDeviceName.c_str(), strerror(errno)); 599 return; 600 } 601 602 // The hid device id has changed since this is now a new hid device. Now we have to look up the new name. 603 if (!LookupHidDeviceName(bus, vendor, product, hidDeviceName)) { 604 fprintf(stderr, "Failed to find HID device name for the specified device: bus (0x%x) vendor: (0x%x) product: (0x%x)\n", 605 bus, vendor, product); 606 return; 607 } 608 609 if (!FindHidRawFile(hidDeviceName, hidrawFile)) { 610 fprintf(stderr, "Failed to find the hidraw device file for %s\n", hidDeviceName.c_str()); 611 return; 612 } 613 614 for (i = 0; i < 200; i++) { 615 rc = stat(hidrawFile.c_str(), &stat_buf); 616 if (!rc) 617 break; 618 Sleep(5); 619 } 620 621 rc = Open(hidrawFile.c_str()); 622 if (rc) 623 fprintf(stderr, "Failed to open device (%s) during rebind: %d: errno: %s (%d)\n", 624 hidrawFile.c_str(), rc, strerror(errno), errno); 625 } 626 627 bool HIDDevice::FindTransportDevice(int bus, std::string & hidDeviceName, 628 std::string & transportDeviceName, std::string & driverPath) 629 { 630 std::string devicePrefix = "/sys/bus/"; 631 std::string devicePath; 632 struct dirent * devicesDirEntry; 633 DIR * devicesDir; 634 struct dirent * devDirEntry; 635 DIR * devDir; 636 bool deviceFound = false; 637 ssize_t sz; 638 639 if (bus == BUS_I2C) { 640 devicePrefix += "i2c/"; 641 driverPath = devicePrefix + "drivers/i2c_hid/"; 642 } else { 643 devicePrefix += "usb/"; 644 driverPath = devicePrefix + "drivers/usbhid/"; 645 } 646 devicePath = devicePrefix + "devices/"; 647 648 devicesDir = opendir(devicePath.c_str()); 649 if (!devicesDir) 650 return false; 651 652 while((devicesDirEntry = readdir(devicesDir)) != NULL) { 653 if (devicesDirEntry->d_type != DT_LNK) 654 continue; 655 656 char buf[PATH_MAX]; 657 658 sz = readlinkat(dirfd(devicesDir), devicesDirEntry->d_name, buf, PATH_MAX); 659 if (sz < 0) 660 continue; 661 662 buf[sz] = 0; 663 664 std::string fullLinkPath = devicePath + buf; 665 devDir = opendir(fullLinkPath.c_str()); 666 if (!devDir) { 667 fprintf(stdout, "opendir failed\n"); 668 continue; 669 } 670 671 while ((devDirEntry = readdir(devDir)) != NULL) { 672 if (!strcmp(devDirEntry->d_name, hidDeviceName.c_str())) { 673 transportDeviceName = devicesDirEntry->d_name; 674 deviceFound = true; 675 break; 676 } 677 } 678 closedir(devDir); 679 680 if (deviceFound) 681 break; 682 } 683 closedir(devicesDir); 684 685 return deviceFound; 686 } 687 688 bool HIDDevice::LookupHidDeviceName(int bus, int vendorId, int productId, std::string & deviceName) 689 { 690 bool ret = false; 691 struct dirent * devDirEntry; 692 DIR * devDir; 693 char devicePrefix[15]; 694 695 snprintf(devicePrefix, 15, "%04X:%04X:%04X", bus, vendorId, productId); 696 697 devDir = opendir("/sys/bus/hid/devices"); 698 if (!devDir) 699 return false; 700 701 while ((devDirEntry = readdir(devDir)) != NULL) { 702 if (!strncmp(devDirEntry->d_name, devicePrefix, 14)) { 703 deviceName = devDirEntry->d_name; 704 ret = true; 705 break; 706 } 707 } 708 closedir(devDir); 709 710 return ret; 711 } 712 713 bool HIDDevice::FindHidRawFile(std::string & deviceName, std::string & hidrawFile) 714 { 715 bool ret = false; 716 char hidrawDir[PATH_MAX]; 717 struct dirent * devDirEntry; 718 DIR * devDir; 719 720 snprintf(hidrawDir, PATH_MAX, "/sys/bus/hid/devices/%s/hidraw", deviceName.c_str()); 721 722 devDir = opendir(hidrawDir); 723 if (!devDir) 724 return false; 725 726 while ((devDirEntry = readdir(devDir)) != NULL) { 727 if (!strncmp(devDirEntry->d_name, "hidraw", 6)) { 728 hidrawFile = std::string("/dev/") + devDirEntry->d_name; 729 ret = true; 730 break; 731 } 732 } 733 closedir(devDir); 734 735 return ret; 736 } 737