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
Open(const char * filename)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
ParseReportSizes()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
Read(unsigned short addr,unsigned char * buf,unsigned short len)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
Write(unsigned short addr,const unsigned char * buf,unsigned short len)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
SetMode(int mode)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
Close()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
WaitForAttention(struct timeval * timeout,unsigned int source_mask)366 int HIDDevice::WaitForAttention(struct timeval * timeout, unsigned int source_mask)
367 {
368 return GetAttentionReport(timeout, source_mask, NULL, NULL);
369 }
370
GetAttentionReport(struct timeval * timeout,unsigned int source_mask,unsigned char * buf,unsigned int * len)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
GetReport(int * reportId,struct timeval * timeout)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
PrintReport(const unsigned char * report)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
PrintDeviceInfo()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
WriteDeviceNameToFile(const char * file,const char * str)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
RebindDriver()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
FindTransportDevice(int bus,std::string & hidDeviceName,std::string & transportDeviceName,std::string & driverPath)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
LookupHidDeviceName(int bus,int vendorId,int productId,std::string & deviceName)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
FindHidRawFile(std::string & deviceName,std::string & hidrawFile)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