1*a248dafdSChristopher Ferris /*
2*a248dafdSChristopher Ferris * Copyright (C) 2014 Andrew Duggan
3*a248dafdSChristopher Ferris * Copyright (C) 2014 Synaptics Inc
4*a248dafdSChristopher Ferris *
5*a248dafdSChristopher Ferris * Licensed under the Apache License, Version 2.0 (the "License");
6*a248dafdSChristopher Ferris * you may not use this file except in compliance with the License.
7*a248dafdSChristopher Ferris * You may obtain a copy of the License at
8*a248dafdSChristopher Ferris *
9*a248dafdSChristopher Ferris * http://www.apache.org/licenses/LICENSE-2.0
10*a248dafdSChristopher Ferris *
11*a248dafdSChristopher Ferris * Unless required by applicable law or agreed to in writing, software
12*a248dafdSChristopher Ferris * distributed under the License is distributed on an "AS IS" BASIS,
13*a248dafdSChristopher Ferris * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14*a248dafdSChristopher Ferris * See the License for the specific language governing permissions and
15*a248dafdSChristopher Ferris * limitations under the License.
16*a248dafdSChristopher Ferris */
17*a248dafdSChristopher Ferris
18*a248dafdSChristopher Ferris #include <stdio.h>
19*a248dafdSChristopher Ferris #include <sys/types.h>
20*a248dafdSChristopher Ferris #include <sys/stat.h>
21*a248dafdSChristopher Ferris #include <fcntl.h>
22*a248dafdSChristopher Ferris #include <dirent.h>
23*a248dafdSChristopher Ferris #include <errno.h>
24*a248dafdSChristopher Ferris #include <string.h>
25*a248dafdSChristopher Ferris #include <unistd.h>
26*a248dafdSChristopher Ferris #include <sys/ioctl.h>
27*a248dafdSChristopher Ferris #include <sys/select.h>
28*a248dafdSChristopher Ferris
29*a248dafdSChristopher Ferris #include <linux/types.h>
30*a248dafdSChristopher Ferris #include <linux/input.h>
31*a248dafdSChristopher Ferris #include <linux/hidraw.h>
32*a248dafdSChristopher Ferris #include <signal.h>
33*a248dafdSChristopher Ferris #include <stdlib.h>
34*a248dafdSChristopher Ferris #include <sys/inotify.h>
35*a248dafdSChristopher Ferris
36*a248dafdSChristopher Ferris #include "hiddevice.h"
37*a248dafdSChristopher Ferris
38*a248dafdSChristopher Ferris #define RMI_WRITE_REPORT_ID 0x9 // Output Report
39*a248dafdSChristopher Ferris #define RMI_READ_ADDR_REPORT_ID 0xa // Output Report
40*a248dafdSChristopher Ferris #define RMI_READ_DATA_REPORT_ID 0xb // Input Report
41*a248dafdSChristopher Ferris #define RMI_ATTN_REPORT_ID 0xc // Input Report
42*a248dafdSChristopher Ferris #define RMI_SET_RMI_MODE_REPORT_ID 0xf // Feature Report
43*a248dafdSChristopher Ferris #define RMI_SET_LID_MODE_REPORT_ID 0xe // Feature Report
44*a248dafdSChristopher Ferris
45*a248dafdSChristopher Ferris
46*a248dafdSChristopher Ferris // Make sure that none of the enums/macros conflict with possible
47*a248dafdSChristopher Ferris // kernel definition/names.
48*a248dafdSChristopher Ferris enum hid_rmi4_report_type {
49*a248dafdSChristopher Ferris HID_RMI4_REPORT_UNKNOWN = 0,
50*a248dafdSChristopher Ferris HID_RMI4_REPORT_INPUT = 1,
51*a248dafdSChristopher Ferris HID_RMI4_REPORT_OUTPUT = 2,
52*a248dafdSChristopher Ferris HID_RMI4_REPORT_FEATURE = 3,
53*a248dafdSChristopher Ferris };
54*a248dafdSChristopher Ferris
55*a248dafdSChristopher Ferris #define HID_RMI4_REPORT_TYPE_INPUT 0x81
56*a248dafdSChristopher Ferris #define HID_RMI4_REPORT_TYPE_OUTPUT 0x91
57*a248dafdSChristopher Ferris #define HID_RMI4_REPORT_TYPE_FEATURE 0xb1
58*a248dafdSChristopher Ferris
59*a248dafdSChristopher Ferris #define HID_RMI4_REPORT_ID 0
60*a248dafdSChristopher Ferris #define HID_RMI4_READ_INPUT_COUNT 1
61*a248dafdSChristopher Ferris #define HID_RMI4_READ_INPUT_DATA 2
62*a248dafdSChristopher Ferris #define HID_RMI4_READ_OUTPUT_ADDR 2
63*a248dafdSChristopher Ferris #define HID_RMI4_READ_OUTPUT_COUNT 4
64*a248dafdSChristopher Ferris #define HID_RMI4_WRITE_OUTPUT_COUNT 1
65*a248dafdSChristopher Ferris #define HID_RMI4_WRITE_OUTPUT_ADDR 2
66*a248dafdSChristopher Ferris #define HID_RMI4_WRITE_OUTPUT_DATA 4
67*a248dafdSChristopher Ferris #define HID_RMI4_FEATURE_MODE 1
68*a248dafdSChristopher Ferris #define HID_RMI4_ATTN_INTERUPT_SOURCES 1
69*a248dafdSChristopher Ferris #define HID_RMI4_ATTN_DATA 2
70*a248dafdSChristopher Ferris
71*a248dafdSChristopher Ferris #define SYNAPTICS_VENDOR_ID 0x06cb
72*a248dafdSChristopher Ferris
Open(const char * filename)73*a248dafdSChristopher Ferris int HIDDevice::Open(const char * filename)
74*a248dafdSChristopher Ferris {
75*a248dafdSChristopher Ferris int rc;
76*a248dafdSChristopher Ferris int desc_size;
77*a248dafdSChristopher Ferris std::string hidDeviceName;
78*a248dafdSChristopher Ferris std::string hidDriverName;
79*a248dafdSChristopher Ferris
80*a248dafdSChristopher Ferris if (!filename)
81*a248dafdSChristopher Ferris return -EINVAL;
82*a248dafdSChristopher Ferris
83*a248dafdSChristopher Ferris m_fd = open(filename, O_RDWR);
84*a248dafdSChristopher Ferris if (m_fd < 0)
85*a248dafdSChristopher Ferris return -1;
86*a248dafdSChristopher Ferris
87*a248dafdSChristopher Ferris memset(&m_rptDesc, 0, sizeof(m_rptDesc));
88*a248dafdSChristopher Ferris memset(&m_info, 0, sizeof(m_info));
89*a248dafdSChristopher Ferris
90*a248dafdSChristopher Ferris rc = ioctl(m_fd, HIDIOCGRDESCSIZE, &desc_size);
91*a248dafdSChristopher Ferris if (rc < 0)
92*a248dafdSChristopher Ferris goto error;
93*a248dafdSChristopher Ferris
94*a248dafdSChristopher Ferris m_rptDesc.size = desc_size;
95*a248dafdSChristopher Ferris rc = ioctl(m_fd, HIDIOCGRDESC, &m_rptDesc);
96*a248dafdSChristopher Ferris if (rc < 0)
97*a248dafdSChristopher Ferris goto error;
98*a248dafdSChristopher Ferris
99*a248dafdSChristopher Ferris rc = ioctl(m_fd, HIDIOCGRAWINFO, &m_info);
100*a248dafdSChristopher Ferris if (rc < 0)
101*a248dafdSChristopher Ferris goto error;
102*a248dafdSChristopher Ferris
103*a248dafdSChristopher Ferris if (m_info.vendor != SYNAPTICS_VENDOR_ID) {
104*a248dafdSChristopher Ferris errno = -ENODEV;
105*a248dafdSChristopher Ferris rc = -1;
106*a248dafdSChristopher Ferris goto error;
107*a248dafdSChristopher Ferris }
108*a248dafdSChristopher Ferris
109*a248dafdSChristopher Ferris ParseReportDescriptor();
110*a248dafdSChristopher Ferris
111*a248dafdSChristopher Ferris m_inputReport = new unsigned char[m_inputReportSize]();
112*a248dafdSChristopher Ferris if (!m_inputReport) {
113*a248dafdSChristopher Ferris errno = -ENOMEM;
114*a248dafdSChristopher Ferris rc = -1;
115*a248dafdSChristopher Ferris goto error;
116*a248dafdSChristopher Ferris }
117*a248dafdSChristopher Ferris
118*a248dafdSChristopher Ferris m_outputReport = new unsigned char[m_outputReportSize]();
119*a248dafdSChristopher Ferris if (!m_outputReport) {
120*a248dafdSChristopher Ferris errno = -ENOMEM;
121*a248dafdSChristopher Ferris rc = -1;
122*a248dafdSChristopher Ferris goto error;
123*a248dafdSChristopher Ferris }
124*a248dafdSChristopher Ferris
125*a248dafdSChristopher Ferris m_readData = new unsigned char[m_inputReportSize]();
126*a248dafdSChristopher Ferris if (!m_readData) {
127*a248dafdSChristopher Ferris errno = -ENOMEM;
128*a248dafdSChristopher Ferris rc = -1;
129*a248dafdSChristopher Ferris goto error;
130*a248dafdSChristopher Ferris }
131*a248dafdSChristopher Ferris
132*a248dafdSChristopher Ferris m_attnData = new unsigned char[m_inputReportSize]();
133*a248dafdSChristopher Ferris if (!m_attnData) {
134*a248dafdSChristopher Ferris errno = -ENOMEM;
135*a248dafdSChristopher Ferris rc = -1;
136*a248dafdSChristopher Ferris goto error;
137*a248dafdSChristopher Ferris }
138*a248dafdSChristopher Ferris
139*a248dafdSChristopher Ferris m_deviceOpen = true;
140*a248dafdSChristopher Ferris
141*a248dafdSChristopher Ferris // Determine which mode the device is currently running in based on the current HID driver
142*a248dafdSChristopher Ferris // hid-rmi indicated RMI Mode 1 all others would be Mode 0
143*a248dafdSChristopher Ferris if (LookupHidDeviceName(m_info.bustype, m_info.vendor, m_info.product, hidDeviceName)) {
144*a248dafdSChristopher Ferris if (LookupHidDriverName(hidDeviceName, hidDriverName)) {
145*a248dafdSChristopher Ferris if (hidDriverName == "hid-rmi")
146*a248dafdSChristopher Ferris m_initialMode = HID_RMI4_MODE_ATTN_REPORTS;
147*a248dafdSChristopher Ferris }
148*a248dafdSChristopher Ferris }
149*a248dafdSChristopher Ferris
150*a248dafdSChristopher Ferris if (m_initialMode != m_mode) {
151*a248dafdSChristopher Ferris rc = SetMode(m_mode);
152*a248dafdSChristopher Ferris if (rc) {
153*a248dafdSChristopher Ferris rc = -1;
154*a248dafdSChristopher Ferris goto error;
155*a248dafdSChristopher Ferris }
156*a248dafdSChristopher Ferris }
157*a248dafdSChristopher Ferris
158*a248dafdSChristopher Ferris return 0;
159*a248dafdSChristopher Ferris
160*a248dafdSChristopher Ferris error:
161*a248dafdSChristopher Ferris Close();
162*a248dafdSChristopher Ferris return rc;
163*a248dafdSChristopher Ferris }
164*a248dafdSChristopher Ferris
ParseReportDescriptor()165*a248dafdSChristopher Ferris void HIDDevice::ParseReportDescriptor()
166*a248dafdSChristopher Ferris {
167*a248dafdSChristopher Ferris bool isVendorSpecific = false;
168*a248dafdSChristopher Ferris bool isReport = false;
169*a248dafdSChristopher Ferris int totalReportSize = 0;
170*a248dafdSChristopher Ferris int reportSize = 0;
171*a248dafdSChristopher Ferris int reportCount = 0;
172*a248dafdSChristopher Ferris enum hid_rmi4_report_type hidReportType = HID_RMI4_REPORT_UNKNOWN;
173*a248dafdSChristopher Ferris bool inCollection = false;
174*a248dafdSChristopher Ferris
175*a248dafdSChristopher Ferris for (unsigned int i = 0; i < m_rptDesc.size; ++i) {
176*a248dafdSChristopher Ferris if (m_rptDesc.value[i] == 0xc0) {
177*a248dafdSChristopher Ferris inCollection = false;
178*a248dafdSChristopher Ferris isVendorSpecific = false;
179*a248dafdSChristopher Ferris isReport = false;
180*a248dafdSChristopher Ferris continue;
181*a248dafdSChristopher Ferris }
182*a248dafdSChristopher Ferris
183*a248dafdSChristopher Ferris if (isVendorSpecific) {
184*a248dafdSChristopher Ferris if (m_rptDesc.value[i] == 0x85) {
185*a248dafdSChristopher Ferris if (isReport) {
186*a248dafdSChristopher Ferris // finish up data on the previous report
187*a248dafdSChristopher Ferris totalReportSize = (reportSize * reportCount) >> 3;
188*a248dafdSChristopher Ferris
189*a248dafdSChristopher Ferris switch (hidReportType) {
190*a248dafdSChristopher Ferris case HID_RMI4_REPORT_INPUT:
191*a248dafdSChristopher Ferris m_inputReportSize = totalReportSize + 1;
192*a248dafdSChristopher Ferris break;
193*a248dafdSChristopher Ferris case HID_RMI4_REPORT_OUTPUT:
194*a248dafdSChristopher Ferris m_outputReportSize = totalReportSize + 1;
195*a248dafdSChristopher Ferris break;
196*a248dafdSChristopher Ferris case HID_RMI4_REPORT_FEATURE:
197*a248dafdSChristopher Ferris m_featureReportSize = totalReportSize + 1;
198*a248dafdSChristopher Ferris break;
199*a248dafdSChristopher Ferris case HID_RMI4_REPORT_UNKNOWN:
200*a248dafdSChristopher Ferris default:
201*a248dafdSChristopher Ferris break;
202*a248dafdSChristopher Ferris }
203*a248dafdSChristopher Ferris }
204*a248dafdSChristopher Ferris
205*a248dafdSChristopher Ferris // reset values for the new report
206*a248dafdSChristopher Ferris totalReportSize = 0;
207*a248dafdSChristopher Ferris reportSize = 0;
208*a248dafdSChristopher Ferris reportCount = 0;
209*a248dafdSChristopher Ferris hidReportType = HID_RMI4_REPORT_UNKNOWN;
210*a248dafdSChristopher Ferris
211*a248dafdSChristopher Ferris isReport = true;
212*a248dafdSChristopher Ferris }
213*a248dafdSChristopher Ferris
214*a248dafdSChristopher Ferris if (isReport) {
215*a248dafdSChristopher Ferris if (m_rptDesc.value[i] == 0x75) {
216*a248dafdSChristopher Ferris if (i + 1 >= m_rptDesc.size)
217*a248dafdSChristopher Ferris return;
218*a248dafdSChristopher Ferris reportSize = m_rptDesc.value[++i];
219*a248dafdSChristopher Ferris continue;
220*a248dafdSChristopher Ferris }
221*a248dafdSChristopher Ferris
222*a248dafdSChristopher Ferris if (m_rptDesc.value[i] == 0x95) {
223*a248dafdSChristopher Ferris if (i + 1 >= m_rptDesc.size)
224*a248dafdSChristopher Ferris return;
225*a248dafdSChristopher Ferris reportCount = m_rptDesc.value[++i];
226*a248dafdSChristopher Ferris continue;
227*a248dafdSChristopher Ferris }
228*a248dafdSChristopher Ferris
229*a248dafdSChristopher Ferris if (m_rptDesc.value[i] == RMI_SET_LID_MODE_REPORT_ID) {
230*a248dafdSChristopher Ferris hasVendorDefineLIDMode = true;
231*a248dafdSChristopher Ferris }
232*a248dafdSChristopher Ferris
233*a248dafdSChristopher Ferris if (m_rptDesc.value[i] == HID_RMI4_REPORT_TYPE_INPUT)
234*a248dafdSChristopher Ferris hidReportType = HID_RMI4_REPORT_INPUT;
235*a248dafdSChristopher Ferris
236*a248dafdSChristopher Ferris if (m_rptDesc.value[i] == HID_RMI4_REPORT_TYPE_OUTPUT)
237*a248dafdSChristopher Ferris hidReportType = HID_RMI4_REPORT_OUTPUT;
238*a248dafdSChristopher Ferris
239*a248dafdSChristopher Ferris if (m_rptDesc.value[i] == HID_RMI4_REPORT_TYPE_FEATURE) {
240*a248dafdSChristopher Ferris hidReportType = HID_RMI4_REPORT_FEATURE;
241*a248dafdSChristopher Ferris }
242*a248dafdSChristopher Ferris }
243*a248dafdSChristopher Ferris }
244*a248dafdSChristopher Ferris
245*a248dafdSChristopher Ferris if (!inCollection) {
246*a248dafdSChristopher Ferris switch (m_rptDesc.value[i]) {
247*a248dafdSChristopher Ferris case 0x00:
248*a248dafdSChristopher Ferris case 0x01:
249*a248dafdSChristopher Ferris case 0x02:
250*a248dafdSChristopher Ferris case 0x03:
251*a248dafdSChristopher Ferris case 0x04:
252*a248dafdSChristopher Ferris inCollection = true;
253*a248dafdSChristopher Ferris break;
254*a248dafdSChristopher Ferris case 0x05:
255*a248dafdSChristopher Ferris inCollection = true;
256*a248dafdSChristopher Ferris
257*a248dafdSChristopher Ferris if (i + 3 >= m_rptDesc.size)
258*a248dafdSChristopher Ferris break;
259*a248dafdSChristopher Ferris
260*a248dafdSChristopher Ferris // touchscreens with active pen have a Generic Mouse collection
261*a248dafdSChristopher Ferris // so stop searching if we have already found the touchscreen digitizer
262*a248dafdSChristopher Ferris // usage.
263*a248dafdSChristopher Ferris if (m_deviceType == RMI_DEVICE_TYPE_TOUCHSCREEN)
264*a248dafdSChristopher Ferris break;
265*a248dafdSChristopher Ferris
266*a248dafdSChristopher Ferris if (m_rptDesc.value[i + 1] == 0x01) {
267*a248dafdSChristopher Ferris if (m_rptDesc.value[i + 2] == 0x09 && m_rptDesc.value[i + 3] == 0x02)
268*a248dafdSChristopher Ferris m_deviceType = RMI_DEVICE_TYPE_TOUCHPAD;
269*a248dafdSChristopher Ferris } else if (m_rptDesc.value[i + 1] == 0x0d) {
270*a248dafdSChristopher Ferris if (m_rptDesc.value[i + 2] == 0x09 && m_rptDesc.value[i + 3] == 0x04)
271*a248dafdSChristopher Ferris m_deviceType = RMI_DEVICE_TYPE_TOUCHSCREEN;
272*a248dafdSChristopher Ferris // for Precision Touch Pad
273*a248dafdSChristopher Ferris else if (m_rptDesc.value[i + 2] == 0x09 && m_rptDesc.value[i + 3] == 0x05)
274*a248dafdSChristopher Ferris m_deviceType = RMI_DEVICE_TYPE_TOUCHPAD;
275*a248dafdSChristopher Ferris }
276*a248dafdSChristopher Ferris i += 3;
277*a248dafdSChristopher Ferris break;
278*a248dafdSChristopher Ferris case 0x06:
279*a248dafdSChristopher Ferris inCollection = true;
280*a248dafdSChristopher Ferris if (i + 2 >= m_rptDesc.size)
281*a248dafdSChristopher Ferris break;
282*a248dafdSChristopher Ferris
283*a248dafdSChristopher Ferris if (m_rptDesc.value[i + 1] == 0x00 && m_rptDesc.value[i + 2] == 0xFF)
284*a248dafdSChristopher Ferris isVendorSpecific = true;
285*a248dafdSChristopher Ferris i += 2;
286*a248dafdSChristopher Ferris break;
287*a248dafdSChristopher Ferris default:
288*a248dafdSChristopher Ferris break;
289*a248dafdSChristopher Ferris
290*a248dafdSChristopher Ferris }
291*a248dafdSChristopher Ferris }
292*a248dafdSChristopher Ferris }
293*a248dafdSChristopher Ferris }
294*a248dafdSChristopher Ferris
Read(unsigned short addr,unsigned char * buf,unsigned short len)295*a248dafdSChristopher Ferris int HIDDevice::Read(unsigned short addr, unsigned char *buf, unsigned short len)
296*a248dafdSChristopher Ferris {
297*a248dafdSChristopher Ferris ssize_t count;
298*a248dafdSChristopher Ferris size_t bytesReadPerRequest;
299*a248dafdSChristopher Ferris size_t bytesInDataReport;
300*a248dafdSChristopher Ferris size_t totalBytesRead;
301*a248dafdSChristopher Ferris size_t bytesPerRequest;
302*a248dafdSChristopher Ferris size_t bytesWritten;
303*a248dafdSChristopher Ferris size_t bytesToRequest;
304*a248dafdSChristopher Ferris int reportId;
305*a248dafdSChristopher Ferris int rc;
306*a248dafdSChristopher Ferris struct timeval tv;
307*a248dafdSChristopher Ferris int resendCount = 0;
308*a248dafdSChristopher Ferris
309*a248dafdSChristopher Ferris tv.tv_sec = 10 / 1000;
310*a248dafdSChristopher Ferris tv.tv_usec = (10 % 1000) * 1000;
311*a248dafdSChristopher Ferris
312*a248dafdSChristopher Ferris if (!m_deviceOpen)
313*a248dafdSChristopher Ferris return -1;
314*a248dafdSChristopher Ferris
315*a248dafdSChristopher Ferris if (m_hasDebug) {
316*a248dafdSChristopher Ferris fprintf(stdout, "R %02x : ", addr);
317*a248dafdSChristopher Ferris }
318*a248dafdSChristopher Ferris
319*a248dafdSChristopher Ferris if (m_bytesPerReadRequest)
320*a248dafdSChristopher Ferris bytesPerRequest = m_bytesPerReadRequest;
321*a248dafdSChristopher Ferris else
322*a248dafdSChristopher Ferris bytesPerRequest = len;
323*a248dafdSChristopher Ferris
324*a248dafdSChristopher Ferris for (totalBytesRead = 0; totalBytesRead < len; totalBytesRead += bytesReadPerRequest) {
325*a248dafdSChristopher Ferris Resend:
326*a248dafdSChristopher Ferris if (GetDeviceType() == RMI_DEVICE_TYPE_TOUCHPAD) {
327*a248dafdSChristopher Ferris if (resendCount == 3) {
328*a248dafdSChristopher Ferris fprintf(stderr, "resend count exceed, return as failure\n");
329*a248dafdSChristopher Ferris return -1;
330*a248dafdSChristopher Ferris }
331*a248dafdSChristopher Ferris }
332*a248dafdSChristopher Ferris count = 0;
333*a248dafdSChristopher Ferris if ((len - totalBytesRead) < bytesPerRequest)
334*a248dafdSChristopher Ferris bytesToRequest = len % bytesPerRequest;
335*a248dafdSChristopher Ferris else
336*a248dafdSChristopher Ferris bytesToRequest = bytesPerRequest;
337*a248dafdSChristopher Ferris
338*a248dafdSChristopher Ferris if (m_outputReportSize < HID_RMI4_READ_OUTPUT_COUNT + 2) {
339*a248dafdSChristopher Ferris return -1;
340*a248dafdSChristopher Ferris }
341*a248dafdSChristopher Ferris m_outputReport[HID_RMI4_REPORT_ID] = RMI_READ_ADDR_REPORT_ID;
342*a248dafdSChristopher Ferris m_outputReport[1] = 0; /* old 1 byte read count */
343*a248dafdSChristopher Ferris m_outputReport[HID_RMI4_READ_OUTPUT_ADDR] = addr & 0xFF;
344*a248dafdSChristopher Ferris m_outputReport[HID_RMI4_READ_OUTPUT_ADDR + 1] = (addr >> 8) & 0xFF;
345*a248dafdSChristopher Ferris m_outputReport[HID_RMI4_READ_OUTPUT_COUNT] = bytesToRequest & 0xFF;
346*a248dafdSChristopher Ferris m_outputReport[HID_RMI4_READ_OUTPUT_COUNT + 1] = (bytesToRequest >> 8) & 0xFF;
347*a248dafdSChristopher Ferris
348*a248dafdSChristopher Ferris m_dataBytesRead = 0;
349*a248dafdSChristopher Ferris
350*a248dafdSChristopher Ferris for (bytesWritten = 0; bytesWritten < m_outputReportSize; bytesWritten += count) {
351*a248dafdSChristopher Ferris m_bCancel = false;
352*a248dafdSChristopher Ferris count = write(m_fd, m_outputReport + bytesWritten,
353*a248dafdSChristopher Ferris m_outputReportSize - bytesWritten);
354*a248dafdSChristopher Ferris if (count < 0) {
355*a248dafdSChristopher Ferris if (errno == EINTR && m_deviceOpen && !m_bCancel)
356*a248dafdSChristopher Ferris continue;
357*a248dafdSChristopher Ferris else
358*a248dafdSChristopher Ferris return count;
359*a248dafdSChristopher Ferris }
360*a248dafdSChristopher Ferris break;
361*a248dafdSChristopher Ferris }
362*a248dafdSChristopher Ferris
363*a248dafdSChristopher Ferris bytesReadPerRequest = 0;
364*a248dafdSChristopher Ferris while (bytesReadPerRequest < bytesToRequest) {
365*a248dafdSChristopher Ferris if (GetDeviceType() == RMI_DEVICE_TYPE_TOUCHPAD) {
366*a248dafdSChristopher Ferris // Add timeout 10 ms for select() called in GetReport().
367*a248dafdSChristopher Ferris rc = GetReport(&reportId, &tv);
368*a248dafdSChristopher Ferris } else {
369*a248dafdSChristopher Ferris // Touch Screen
370*a248dafdSChristopher Ferris rc = GetReport(&reportId);
371*a248dafdSChristopher Ferris }
372*a248dafdSChristopher Ferris if (rc > 0 && reportId == RMI_READ_DATA_REPORT_ID) {
373*a248dafdSChristopher Ferris if (static_cast<ssize_t>(m_inputReportSize) <
374*a248dafdSChristopher Ferris std::max(HID_RMI4_READ_INPUT_COUNT,
375*a248dafdSChristopher Ferris HID_RMI4_READ_INPUT_DATA)){
376*a248dafdSChristopher Ferris return -1;
377*a248dafdSChristopher Ferris }
378*a248dafdSChristopher Ferris bytesInDataReport = m_readData[HID_RMI4_READ_INPUT_COUNT];
379*a248dafdSChristopher Ferris if (bytesInDataReport > bytesToRequest
380*a248dafdSChristopher Ferris || bytesReadPerRequest + bytesInDataReport > len){
381*a248dafdSChristopher Ferris return -1;
382*a248dafdSChristopher Ferris }
383*a248dafdSChristopher Ferris memcpy(buf + bytesReadPerRequest, &m_readData[HID_RMI4_READ_INPUT_DATA],
384*a248dafdSChristopher Ferris bytesInDataReport);
385*a248dafdSChristopher Ferris bytesReadPerRequest += bytesInDataReport;
386*a248dafdSChristopher Ferris m_dataBytesRead = 0;
387*a248dafdSChristopher Ferris if (GetDeviceType() == RMI_DEVICE_TYPE_TOUCHPAD) {
388*a248dafdSChristopher Ferris // Resend sheme is supported on TP only.
389*a248dafdSChristopher Ferris resendCount = 0;
390*a248dafdSChristopher Ferris }
391*a248dafdSChristopher Ferris } else if (GetDeviceType() == RMI_DEVICE_TYPE_TOUCHPAD) {
392*a248dafdSChristopher Ferris fprintf(stderr, "Some error with GetReport : rc(%d), reportID(0x%x)\n", rc, reportId);
393*a248dafdSChristopher Ferris resendCount += 1;
394*a248dafdSChristopher Ferris goto Resend;
395*a248dafdSChristopher Ferris }
396*a248dafdSChristopher Ferris }
397*a248dafdSChristopher Ferris addr += bytesPerRequest;
398*a248dafdSChristopher Ferris }
399*a248dafdSChristopher Ferris if (m_hasDebug) {
400*a248dafdSChristopher Ferris for (int i=0 ; i<len ; i++) {
401*a248dafdSChristopher Ferris fprintf(stdout, "%02x ", buf[i]);
402*a248dafdSChristopher Ferris }
403*a248dafdSChristopher Ferris fprintf(stdout, "\n");
404*a248dafdSChristopher Ferris }
405*a248dafdSChristopher Ferris
406*a248dafdSChristopher Ferris return totalBytesRead;
407*a248dafdSChristopher Ferris }
408*a248dafdSChristopher Ferris
Write(unsigned short addr,const unsigned char * buf,unsigned short len)409*a248dafdSChristopher Ferris int HIDDevice::Write(unsigned short addr, const unsigned char *buf, unsigned short len)
410*a248dafdSChristopher Ferris {
411*a248dafdSChristopher Ferris ssize_t count;
412*a248dafdSChristopher Ferris
413*a248dafdSChristopher Ferris if (!m_deviceOpen)
414*a248dafdSChristopher Ferris return -1;
415*a248dafdSChristopher Ferris
416*a248dafdSChristopher Ferris if (static_cast<ssize_t>(m_outputReportSize) <
417*a248dafdSChristopher Ferris HID_RMI4_WRITE_OUTPUT_DATA + len)
418*a248dafdSChristopher Ferris return -1;
419*a248dafdSChristopher Ferris m_outputReport[HID_RMI4_REPORT_ID] = RMI_WRITE_REPORT_ID;
420*a248dafdSChristopher Ferris m_outputReport[HID_RMI4_WRITE_OUTPUT_COUNT] = len;
421*a248dafdSChristopher Ferris m_outputReport[HID_RMI4_WRITE_OUTPUT_ADDR] = addr & 0xFF;
422*a248dafdSChristopher Ferris m_outputReport[HID_RMI4_WRITE_OUTPUT_ADDR + 1] = (addr >> 8) & 0xFF;
423*a248dafdSChristopher Ferris memcpy(&m_outputReport[HID_RMI4_WRITE_OUTPUT_DATA], buf, len);
424*a248dafdSChristopher Ferris
425*a248dafdSChristopher Ferris if (m_hasDebug) {
426*a248dafdSChristopher Ferris fprintf(stdout, "W %02x : ", addr);
427*a248dafdSChristopher Ferris for (int i=0 ; i<len ; i++) {
428*a248dafdSChristopher Ferris fprintf(stdout, "%02x ", buf[i]);
429*a248dafdSChristopher Ferris }
430*a248dafdSChristopher Ferris fprintf(stdout, "\n");
431*a248dafdSChristopher Ferris }
432*a248dafdSChristopher Ferris
433*a248dafdSChristopher Ferris for (;;) {
434*a248dafdSChristopher Ferris m_bCancel = false;
435*a248dafdSChristopher Ferris count = write(m_fd, m_outputReport, m_outputReportSize);
436*a248dafdSChristopher Ferris if (count < 0) {
437*a248dafdSChristopher Ferris if (errno == EINTR && m_deviceOpen && !m_bCancel)
438*a248dafdSChristopher Ferris continue;
439*a248dafdSChristopher Ferris else
440*a248dafdSChristopher Ferris return count;
441*a248dafdSChristopher Ferris }
442*a248dafdSChristopher Ferris return len;
443*a248dafdSChristopher Ferris }
444*a248dafdSChristopher Ferris }
445*a248dafdSChristopher Ferris
SetMode(int mode)446*a248dafdSChristopher Ferris int HIDDevice::SetMode(int mode)
447*a248dafdSChristopher Ferris {
448*a248dafdSChristopher Ferris int rc;
449*a248dafdSChristopher Ferris char buf[2];
450*a248dafdSChristopher Ferris
451*a248dafdSChristopher Ferris if (!m_deviceOpen)
452*a248dafdSChristopher Ferris return -1;
453*a248dafdSChristopher Ferris
454*a248dafdSChristopher Ferris buf[0] = RMI_SET_RMI_MODE_REPORT_ID;
455*a248dafdSChristopher Ferris buf[1] = mode;
456*a248dafdSChristopher Ferris rc = ioctl(m_fd, HIDIOCSFEATURE(2), buf);
457*a248dafdSChristopher Ferris if (rc < 0) {
458*a248dafdSChristopher Ferris perror("HIDIOCSFEATURE");
459*a248dafdSChristopher Ferris return rc;
460*a248dafdSChristopher Ferris }
461*a248dafdSChristopher Ferris
462*a248dafdSChristopher Ferris return 0;
463*a248dafdSChristopher Ferris }
464*a248dafdSChristopher Ferris
ToggleInterruptMask(bool enable)465*a248dafdSChristopher Ferris int HIDDevice::ToggleInterruptMask(bool enable)
466*a248dafdSChristopher Ferris {
467*a248dafdSChristopher Ferris int rc;
468*a248dafdSChristopher Ferris char buf[2];
469*a248dafdSChristopher Ferris
470*a248dafdSChristopher Ferris if (GetDeviceType() != RMI_DEVICE_TYPE_TOUCHPAD) {
471*a248dafdSChristopher Ferris fprintf(stdout, "Not TP, skip toggle interrupts mask\n");
472*a248dafdSChristopher Ferris return 0;
473*a248dafdSChristopher Ferris }
474*a248dafdSChristopher Ferris
475*a248dafdSChristopher Ferris // We can have information to see whether it exists this feature report currentlt.
476*a248dafdSChristopher Ferris // However, it might have no action even we set this feature with specific value.
477*a248dafdSChristopher Ferris // Need FW team's help to query more information about the existence of functions.
478*a248dafdSChristopher Ferris if (!hasVendorDefineLIDMode) {
479*a248dafdSChristopher Ferris if (m_hasDebug) {
480*a248dafdSChristopher Ferris fprintf(stdout, "no LID mode feature, return\n");
481*a248dafdSChristopher Ferris }
482*a248dafdSChristopher Ferris return 0;
483*a248dafdSChristopher Ferris }
484*a248dafdSChristopher Ferris
485*a248dafdSChristopher Ferris if (!m_deviceOpen)
486*a248dafdSChristopher Ferris return -1;
487*a248dafdSChristopher Ferris
488*a248dafdSChristopher Ferris buf[0] = RMI_SET_LID_MODE_REPORT_ID;
489*a248dafdSChristopher Ferris if (enable) {
490*a248dafdSChristopher Ferris buf[1] = 0;
491*a248dafdSChristopher Ferris } else {
492*a248dafdSChristopher Ferris buf[1] = 8;
493*a248dafdSChristopher Ferris }
494*a248dafdSChristopher Ferris rc = ioctl(m_fd, HIDIOCSFEATURE(2), buf);
495*a248dafdSChristopher Ferris if (rc < 0) {
496*a248dafdSChristopher Ferris perror("HIDIOCSFEATURE");
497*a248dafdSChristopher Ferris return rc;
498*a248dafdSChristopher Ferris }
499*a248dafdSChristopher Ferris Sleep(10);
500*a248dafdSChristopher Ferris return 0;
501*a248dafdSChristopher Ferris }
502*a248dafdSChristopher Ferris
Close()503*a248dafdSChristopher Ferris void HIDDevice::Close()
504*a248dafdSChristopher Ferris {
505*a248dafdSChristopher Ferris RMIDevice::Close();
506*a248dafdSChristopher Ferris
507*a248dafdSChristopher Ferris if (!m_deviceOpen)
508*a248dafdSChristopher Ferris return;
509*a248dafdSChristopher Ferris
510*a248dafdSChristopher Ferris if (m_initialMode != m_mode)
511*a248dafdSChristopher Ferris SetMode(m_initialMode);
512*a248dafdSChristopher Ferris
513*a248dafdSChristopher Ferris m_deviceOpen = false;
514*a248dafdSChristopher Ferris close(m_fd);
515*a248dafdSChristopher Ferris m_fd = -1;
516*a248dafdSChristopher Ferris
517*a248dafdSChristopher Ferris delete[] m_inputReport;
518*a248dafdSChristopher Ferris m_inputReport = NULL;
519*a248dafdSChristopher Ferris delete[] m_outputReport;
520*a248dafdSChristopher Ferris m_outputReport = NULL;
521*a248dafdSChristopher Ferris delete[] m_readData;
522*a248dafdSChristopher Ferris m_readData = NULL;
523*a248dafdSChristopher Ferris delete[] m_attnData;
524*a248dafdSChristopher Ferris m_attnData = NULL;
525*a248dafdSChristopher Ferris }
526*a248dafdSChristopher Ferris
WaitForAttention(struct timeval * timeout,unsigned int source_mask)527*a248dafdSChristopher Ferris int HIDDevice::WaitForAttention(struct timeval * timeout, unsigned int source_mask)
528*a248dafdSChristopher Ferris {
529*a248dafdSChristopher Ferris return GetAttentionReport(timeout, source_mask, NULL, NULL);
530*a248dafdSChristopher Ferris }
531*a248dafdSChristopher Ferris
GetAttentionReport(struct timeval * timeout,unsigned int source_mask,unsigned char * buf,unsigned int * len)532*a248dafdSChristopher Ferris int HIDDevice::GetAttentionReport(struct timeval * timeout, unsigned int source_mask,
533*a248dafdSChristopher Ferris unsigned char *buf, unsigned int *len)
534*a248dafdSChristopher Ferris {
535*a248dafdSChristopher Ferris int rc = 0;
536*a248dafdSChristopher Ferris int reportId;
537*a248dafdSChristopher Ferris
538*a248dafdSChristopher Ferris // Assume the Linux implementation of select with timeout set to the
539*a248dafdSChristopher Ferris // time remaining.
540*a248dafdSChristopher Ferris while (!timeout || (timeout->tv_sec != 0 || timeout->tv_usec != 0)) {
541*a248dafdSChristopher Ferris rc = GetReport(&reportId, timeout);
542*a248dafdSChristopher Ferris if (rc > 0) {
543*a248dafdSChristopher Ferris if (reportId == RMI_ATTN_REPORT_ID) {
544*a248dafdSChristopher Ferris // If a valid buffer is passed in then copy the data from
545*a248dafdSChristopher Ferris // the attention report into it. If the buffer is
546*a248dafdSChristopher Ferris // too small simply set *len to 0 to indicate nothing
547*a248dafdSChristopher Ferris // was copied. Some callers won't care about the contents
548*a248dafdSChristopher Ferris // of the report so failing to copy the data should not return
549*a248dafdSChristopher Ferris // an error.
550*a248dafdSChristopher Ferris if (buf && len) {
551*a248dafdSChristopher Ferris if (*len >= m_inputReportSize) {
552*a248dafdSChristopher Ferris *len = m_inputReportSize;
553*a248dafdSChristopher Ferris memcpy(buf, m_attnData, *len);
554*a248dafdSChristopher Ferris } else {
555*a248dafdSChristopher Ferris *len = 0;
556*a248dafdSChristopher Ferris }
557*a248dafdSChristopher Ferris }
558*a248dafdSChristopher Ferris
559*a248dafdSChristopher Ferris if (m_inputReportSize < HID_RMI4_ATTN_INTERUPT_SOURCES + 1)
560*a248dafdSChristopher Ferris return -1;
561*a248dafdSChristopher Ferris
562*a248dafdSChristopher Ferris if (source_mask & m_attnData[HID_RMI4_ATTN_INTERUPT_SOURCES])
563*a248dafdSChristopher Ferris return rc;
564*a248dafdSChristopher Ferris }
565*a248dafdSChristopher Ferris } else {
566*a248dafdSChristopher Ferris return rc;
567*a248dafdSChristopher Ferris }
568*a248dafdSChristopher Ferris }
569*a248dafdSChristopher Ferris
570*a248dafdSChristopher Ferris return rc;
571*a248dafdSChristopher Ferris }
572*a248dafdSChristopher Ferris
GetReport(int * reportId,struct timeval * timeout)573*a248dafdSChristopher Ferris int HIDDevice::GetReport(int *reportId, struct timeval * timeout)
574*a248dafdSChristopher Ferris {
575*a248dafdSChristopher Ferris ssize_t count = 0;
576*a248dafdSChristopher Ferris fd_set fds;
577*a248dafdSChristopher Ferris int rc;
578*a248dafdSChristopher Ferris
579*a248dafdSChristopher Ferris if (!m_deviceOpen)
580*a248dafdSChristopher Ferris return -1;
581*a248dafdSChristopher Ferris
582*a248dafdSChristopher Ferris if (m_inputReportSize < HID_RMI4_REPORT_ID + 1)
583*a248dafdSChristopher Ferris return -1;
584*a248dafdSChristopher Ferris
585*a248dafdSChristopher Ferris for (;;) {
586*a248dafdSChristopher Ferris FD_ZERO(&fds);
587*a248dafdSChristopher Ferris FD_SET(m_fd, &fds);
588*a248dafdSChristopher Ferris
589*a248dafdSChristopher Ferris rc = select(m_fd + 1, &fds, NULL, NULL, timeout);
590*a248dafdSChristopher Ferris if (rc == 0) {
591*a248dafdSChristopher Ferris return -ETIMEDOUT;
592*a248dafdSChristopher Ferris } else if (rc < 0) {
593*a248dafdSChristopher Ferris if (errno == EINTR && m_deviceOpen && !m_bCancel)
594*a248dafdSChristopher Ferris continue;
595*a248dafdSChristopher Ferris else
596*a248dafdSChristopher Ferris return rc;
597*a248dafdSChristopher Ferris } else if (rc > 0 && FD_ISSET(m_fd, &fds)) {
598*a248dafdSChristopher Ferris size_t offset = 0;
599*a248dafdSChristopher Ferris for (;;) {
600*a248dafdSChristopher Ferris m_bCancel = false;
601*a248dafdSChristopher Ferris count = read(m_fd, m_inputReport + offset, m_inputReportSize - offset);
602*a248dafdSChristopher Ferris if (count < 0) {
603*a248dafdSChristopher Ferris if (errno == EINTR && m_deviceOpen && !m_bCancel)
604*a248dafdSChristopher Ferris continue;
605*a248dafdSChristopher Ferris else
606*a248dafdSChristopher Ferris return count;
607*a248dafdSChristopher Ferris }
608*a248dafdSChristopher Ferris offset += count;
609*a248dafdSChristopher Ferris if (offset == m_inputReportSize)
610*a248dafdSChristopher Ferris break;
611*a248dafdSChristopher Ferris }
612*a248dafdSChristopher Ferris count = offset;
613*a248dafdSChristopher Ferris }
614*a248dafdSChristopher Ferris break;
615*a248dafdSChristopher Ferris }
616*a248dafdSChristopher Ferris
617*a248dafdSChristopher Ferris if (reportId)
618*a248dafdSChristopher Ferris *reportId = m_inputReport[HID_RMI4_REPORT_ID];
619*a248dafdSChristopher Ferris
620*a248dafdSChristopher Ferris if (m_inputReport[HID_RMI4_REPORT_ID] == RMI_ATTN_REPORT_ID) {
621*a248dafdSChristopher Ferris if (static_cast<ssize_t>(m_inputReportSize) < count)
622*a248dafdSChristopher Ferris return -1;
623*a248dafdSChristopher Ferris memcpy(m_attnData, m_inputReport, count);
624*a248dafdSChristopher Ferris } else if (m_inputReport[HID_RMI4_REPORT_ID] == RMI_READ_DATA_REPORT_ID) {
625*a248dafdSChristopher Ferris if (static_cast<ssize_t>(m_inputReportSize) < count)
626*a248dafdSChristopher Ferris return -1;
627*a248dafdSChristopher Ferris memcpy(m_readData, m_inputReport, count);
628*a248dafdSChristopher Ferris m_dataBytesRead = count;
629*a248dafdSChristopher Ferris }
630*a248dafdSChristopher Ferris return 1;
631*a248dafdSChristopher Ferris }
632*a248dafdSChristopher Ferris
PrintReport(const unsigned char * report)633*a248dafdSChristopher Ferris void HIDDevice::PrintReport(const unsigned char *report)
634*a248dafdSChristopher Ferris {
635*a248dafdSChristopher Ferris int i;
636*a248dafdSChristopher Ferris int len = 0;
637*a248dafdSChristopher Ferris const unsigned char * data;
638*a248dafdSChristopher Ferris int addr = 0;
639*a248dafdSChristopher Ferris
640*a248dafdSChristopher Ferris switch (report[HID_RMI4_REPORT_ID]) {
641*a248dafdSChristopher Ferris case RMI_WRITE_REPORT_ID:
642*a248dafdSChristopher Ferris len = report[HID_RMI4_WRITE_OUTPUT_COUNT];
643*a248dafdSChristopher Ferris data = &report[HID_RMI4_WRITE_OUTPUT_DATA];
644*a248dafdSChristopher Ferris addr = (report[HID_RMI4_WRITE_OUTPUT_ADDR] & 0xFF)
645*a248dafdSChristopher Ferris | ((report[HID_RMI4_WRITE_OUTPUT_ADDR + 1] & 0xFF) << 8);
646*a248dafdSChristopher Ferris fprintf(stdout, "Write Report:\n");
647*a248dafdSChristopher Ferris fprintf(stdout, "Address = 0x%02X\n", addr);
648*a248dafdSChristopher Ferris fprintf(stdout, "Length = 0x%02X\n", len);
649*a248dafdSChristopher Ferris break;
650*a248dafdSChristopher Ferris case RMI_READ_ADDR_REPORT_ID:
651*a248dafdSChristopher Ferris addr = (report[HID_RMI4_READ_OUTPUT_ADDR] & 0xFF)
652*a248dafdSChristopher Ferris | ((report[HID_RMI4_READ_OUTPUT_ADDR + 1] & 0xFF) << 8);
653*a248dafdSChristopher Ferris len = (report[HID_RMI4_READ_OUTPUT_COUNT] & 0xFF)
654*a248dafdSChristopher Ferris | ((report[HID_RMI4_READ_OUTPUT_COUNT + 1] & 0xFF) << 8);
655*a248dafdSChristopher Ferris fprintf(stdout, "Read Request (Output Report):\n");
656*a248dafdSChristopher Ferris fprintf(stdout, "Address = 0x%02X\n", addr);
657*a248dafdSChristopher Ferris fprintf(stdout, "Length = 0x%02X\n", len);
658*a248dafdSChristopher Ferris return;
659*a248dafdSChristopher Ferris break;
660*a248dafdSChristopher Ferris case RMI_READ_DATA_REPORT_ID:
661*a248dafdSChristopher Ferris len = report[HID_RMI4_READ_INPUT_COUNT];
662*a248dafdSChristopher Ferris data = &report[HID_RMI4_READ_INPUT_DATA];
663*a248dafdSChristopher Ferris fprintf(stdout, "Read Data Report:\n");
664*a248dafdSChristopher Ferris fprintf(stdout, "Length = 0x%02X\n", len);
665*a248dafdSChristopher Ferris break;
666*a248dafdSChristopher Ferris case RMI_ATTN_REPORT_ID:
667*a248dafdSChristopher Ferris fprintf(stdout, "Attention Report:\n");
668*a248dafdSChristopher Ferris len = 28;
669*a248dafdSChristopher Ferris data = &report[HID_RMI4_ATTN_DATA];
670*a248dafdSChristopher Ferris fprintf(stdout, "Interrupt Sources: 0x%02X\n",
671*a248dafdSChristopher Ferris report[HID_RMI4_ATTN_INTERUPT_SOURCES]);
672*a248dafdSChristopher Ferris break;
673*a248dafdSChristopher Ferris default:
674*a248dafdSChristopher Ferris fprintf(stderr, "Unknown Report: ID 0x%02x\n", report[HID_RMI4_REPORT_ID]);
675*a248dafdSChristopher Ferris return;
676*a248dafdSChristopher Ferris }
677*a248dafdSChristopher Ferris
678*a248dafdSChristopher Ferris fprintf(stdout, "Data:\n");
679*a248dafdSChristopher Ferris for (i = 0; i < len; ++i) {
680*a248dafdSChristopher Ferris fprintf(stdout, "0x%02X ", data[i]);
681*a248dafdSChristopher Ferris if (i % 8 == 7) {
682*a248dafdSChristopher Ferris fprintf(stdout, "\n");
683*a248dafdSChristopher Ferris }
684*a248dafdSChristopher Ferris }
685*a248dafdSChristopher Ferris fprintf(stdout, "\n\n");
686*a248dafdSChristopher Ferris }
687*a248dafdSChristopher Ferris
688*a248dafdSChristopher Ferris // Print protocol specific device information
PrintDeviceInfo()689*a248dafdSChristopher Ferris void HIDDevice::PrintDeviceInfo()
690*a248dafdSChristopher Ferris {
691*a248dafdSChristopher Ferris enum RMIDeviceType deviceType = GetDeviceType();
692*a248dafdSChristopher Ferris
693*a248dafdSChristopher Ferris fprintf(stdout, "HID device info:\nBus: %s Vendor: 0x%04x Product: 0x%04x\n",
694*a248dafdSChristopher Ferris m_info.bustype == BUS_I2C ? "I2C" : "USB", m_info.vendor, m_info.product);
695*a248dafdSChristopher Ferris fprintf(stdout, "Report sizes: input: %ld output: %ld\n", (unsigned long)m_inputReportSize,
696*a248dafdSChristopher Ferris (unsigned long)m_outputReportSize);
697*a248dafdSChristopher Ferris if (deviceType)
698*a248dafdSChristopher Ferris fprintf(stdout, "device type: %s\n", deviceType == RMI_DEVICE_TYPE_TOUCHSCREEN ?
699*a248dafdSChristopher Ferris "touchscreen" : "touchpad");
700*a248dafdSChristopher Ferris }
701*a248dafdSChristopher Ferris
WriteDeviceNameToFile(const char * file,const char * str)702*a248dafdSChristopher Ferris bool WriteDeviceNameToFile(const char * file, const char * str)
703*a248dafdSChristopher Ferris {
704*a248dafdSChristopher Ferris int fd;
705*a248dafdSChristopher Ferris ssize_t size;
706*a248dafdSChristopher Ferris
707*a248dafdSChristopher Ferris fd = open(file, O_WRONLY);
708*a248dafdSChristopher Ferris if (fd < 0)
709*a248dafdSChristopher Ferris return false;
710*a248dafdSChristopher Ferris
711*a248dafdSChristopher Ferris for (;;) {
712*a248dafdSChristopher Ferris size = write(fd, str, strlen(str));
713*a248dafdSChristopher Ferris if (size < 0) {
714*a248dafdSChristopher Ferris if (errno == EINTR)
715*a248dafdSChristopher Ferris continue;
716*a248dafdSChristopher Ferris
717*a248dafdSChristopher Ferris return false;
718*a248dafdSChristopher Ferris }
719*a248dafdSChristopher Ferris break;
720*a248dafdSChristopher Ferris }
721*a248dafdSChristopher Ferris
722*a248dafdSChristopher Ferris return close(fd) == 0 && size == static_cast<ssize_t>(strlen(str));
723*a248dafdSChristopher Ferris }
724*a248dafdSChristopher Ferris static const char * const absval[6] = { "Value", "Min ", "Max ", "Fuzz ", "Flat ", "Resolution "};
725*a248dafdSChristopher Ferris #define KEY_MAX 0x2ff
726*a248dafdSChristopher Ferris #define EV_MAX 0x1f
727*a248dafdSChristopher Ferris #define BITS_PER_LONG (sizeof(long) * 8)
728*a248dafdSChristopher Ferris #define NBITS(x) ((((x)-1)/BITS_PER_LONG)+1)
729*a248dafdSChristopher Ferris #define OFF(x) ((x)%BITS_PER_LONG)
730*a248dafdSChristopher Ferris #define BIT(x) (1UL<<OFF(x))
731*a248dafdSChristopher Ferris #define LONG(x) ((x)/BITS_PER_LONG)
732*a248dafdSChristopher Ferris #define test_bit(bit, array) ((array[LONG(bit)] >> OFF(bit)) & 1)
733*a248dafdSChristopher Ferris #define DEV_INPUT_EVENT "/dev/input"
734*a248dafdSChristopher Ferris #define EVENT_DEV_NAME "event"
735*a248dafdSChristopher Ferris /**
736*a248dafdSChristopher Ferris * Filter for the AutoDevProbe scandir on /dev/input.
737*a248dafdSChristopher Ferris *
738*a248dafdSChristopher Ferris * @param dir The current directory entry provided by scandir.
739*a248dafdSChristopher Ferris *
740*a248dafdSChristopher Ferris * @return Non-zero if the given directory entry starts with "event", or zero
741*a248dafdSChristopher Ferris * otherwise.
742*a248dafdSChristopher Ferris */
is_event_device(const struct dirent * dir)743*a248dafdSChristopher Ferris static int is_event_device(const struct dirent *dir) {
744*a248dafdSChristopher Ferris return strncmp(EVENT_DEV_NAME, dir->d_name, 5) == 0;
745*a248dafdSChristopher Ferris }
746*a248dafdSChristopher Ferris
CheckABSEvent()747*a248dafdSChristopher Ferris bool HIDDevice::CheckABSEvent()
748*a248dafdSChristopher Ferris {
749*a248dafdSChristopher Ferris int fd=-1;
750*a248dafdSChristopher Ferris unsigned int type;
751*a248dafdSChristopher Ferris int abs[6] = {0};
752*a248dafdSChristopher Ferris struct dirent **namelist;
753*a248dafdSChristopher Ferris int i, ndev;
754*a248dafdSChristopher Ferris
755*a248dafdSChristopher Ferris char input_event_name[PATH_MAX];
756*a248dafdSChristopher Ferris unsigned long bit[EV_MAX][NBITS(KEY_MAX)];
757*a248dafdSChristopher Ferris
758*a248dafdSChristopher Ferris
759*a248dafdSChristopher Ferris #ifdef __BIONIC__
760*a248dafdSChristopher Ferris // Android's libc doesn't have the GNU versionsort extension.
761*a248dafdSChristopher Ferris ndev = scandir(DEV_INPUT_EVENT, &namelist, is_event_device, alphasort);
762*a248dafdSChristopher Ferris #else
763*a248dafdSChristopher Ferris ndev = scandir(DEV_INPUT_EVENT, &namelist, is_event_device, versionsort);
764*a248dafdSChristopher Ferris #endif
765*a248dafdSChristopher Ferris if (ndev <= 0)
766*a248dafdSChristopher Ferris return false;
767*a248dafdSChristopher Ferris for (i = 0; i < ndev; i++)
768*a248dafdSChristopher Ferris {
769*a248dafdSChristopher Ferris char fname[64];
770*a248dafdSChristopher Ferris int fd = -1;
771*a248dafdSChristopher Ferris char name[256] = "???";
772*a248dafdSChristopher Ferris
773*a248dafdSChristopher Ferris snprintf(fname, sizeof(fname),
774*a248dafdSChristopher Ferris "%s/%s", DEV_INPUT_EVENT, namelist[i]->d_name);
775*a248dafdSChristopher Ferris fd = open(fname, O_RDONLY);
776*a248dafdSChristopher Ferris if (fd < 0)
777*a248dafdSChristopher Ferris continue;
778*a248dafdSChristopher Ferris ioctl(fd, EVIOCGNAME(sizeof(name)), name);
779*a248dafdSChristopher Ferris //fprintf(stderr, "%s: %s\n", fname, name);
780*a248dafdSChristopher Ferris close(fd);
781*a248dafdSChristopher Ferris
782*a248dafdSChristopher Ferris if(strstr(name, m_transportDeviceName.c_str()+4))
783*a248dafdSChristopher Ferris {
784*a248dafdSChristopher Ferris snprintf(input_event_name, sizeof(fname), "%s", fname);
785*a248dafdSChristopher Ferris }
786*a248dafdSChristopher Ferris free(namelist[i]);
787*a248dafdSChristopher Ferris }
788*a248dafdSChristopher Ferris
789*a248dafdSChristopher Ferris if ((fd = open(input_event_name, O_RDONLY)) < 0) {
790*a248dafdSChristopher Ferris if (errno == EACCES && getuid() != 0)
791*a248dafdSChristopher Ferris fprintf(stderr, "No access right \n");
792*a248dafdSChristopher Ferris }
793*a248dafdSChristopher Ferris memset(bit, 0, sizeof(bit));
794*a248dafdSChristopher Ferris ioctl(fd, EVIOCGBIT(0, EV_MAX), bit[0]);
795*a248dafdSChristopher Ferris for (type = 0; type < EV_MAX; type++) {
796*a248dafdSChristopher Ferris if (test_bit(type, bit[0]) && type == EV_ABS) {
797*a248dafdSChristopher Ferris ioctl(fd, EVIOCGBIT(type, KEY_MAX), bit[type]);
798*a248dafdSChristopher Ferris if (test_bit(ABS_X, bit[type])) {
799*a248dafdSChristopher Ferris ioctl(fd, EVIOCGABS(ABS_X), abs);
800*a248dafdSChristopher Ferris if(abs[2] == 0) //maximum
801*a248dafdSChristopher Ferris {
802*a248dafdSChristopher Ferris Sleep(1000);
803*a248dafdSChristopher Ferris return false;
804*a248dafdSChristopher Ferris }
805*a248dafdSChristopher Ferris }
806*a248dafdSChristopher Ferris }
807*a248dafdSChristopher Ferris }
808*a248dafdSChristopher Ferris return true;
809*a248dafdSChristopher Ferris }
RebindDriver()810*a248dafdSChristopher Ferris void HIDDevice::RebindDriver()
811*a248dafdSChristopher Ferris {
812*a248dafdSChristopher Ferris int bus = m_info.bustype;
813*a248dafdSChristopher Ferris int vendor = m_info.vendor;
814*a248dafdSChristopher Ferris int product = m_info.product;
815*a248dafdSChristopher Ferris std::string hidDeviceName;
816*a248dafdSChristopher Ferris std::string bindFile;
817*a248dafdSChristopher Ferris std::string unbindFile;
818*a248dafdSChristopher Ferris std::string hidrawFile;
819*a248dafdSChristopher Ferris int notifyFd;
820*a248dafdSChristopher Ferris int wd;
821*a248dafdSChristopher Ferris int rc;
822*a248dafdSChristopher Ferris Close();
823*a248dafdSChristopher Ferris
824*a248dafdSChristopher Ferris notifyFd = inotify_init();
825*a248dafdSChristopher Ferris if (notifyFd < 0) {
826*a248dafdSChristopher Ferris fprintf(stderr, "Failed to initialize inotify\n");
827*a248dafdSChristopher Ferris return;
828*a248dafdSChristopher Ferris }
829*a248dafdSChristopher Ferris
830*a248dafdSChristopher Ferris wd = inotify_add_watch(notifyFd, "/dev", IN_CREATE);
831*a248dafdSChristopher Ferris if (wd < 0) {
832*a248dafdSChristopher Ferris fprintf(stderr, "Failed to add watcher for /dev\n");
833*a248dafdSChristopher Ferris return;
834*a248dafdSChristopher Ferris }
835*a248dafdSChristopher Ferris
836*a248dafdSChristopher Ferris if (m_transportDeviceName == "") {
837*a248dafdSChristopher Ferris if (!LookupHidDeviceName(bus, vendor, product, hidDeviceName)) {
838*a248dafdSChristopher Ferris fprintf(stderr, "Failed to find HID device name for the specified device: bus (0x%x) vendor: (0x%x) product: (0x%x)\n",
839*a248dafdSChristopher Ferris bus, vendor, product);
840*a248dafdSChristopher Ferris return;
841*a248dafdSChristopher Ferris }
842*a248dafdSChristopher Ferris
843*a248dafdSChristopher Ferris if (!FindTransportDevice(bus, hidDeviceName, m_transportDeviceName, m_driverPath)) {
844*a248dafdSChristopher Ferris fprintf(stderr, "Failed to find the transport device / driver for %s\n", hidDeviceName.c_str());
845*a248dafdSChristopher Ferris return;
846*a248dafdSChristopher Ferris }
847*a248dafdSChristopher Ferris
848*a248dafdSChristopher Ferris }
849*a248dafdSChristopher Ferris
850*a248dafdSChristopher Ferris bindFile = m_driverPath + "bind";
851*a248dafdSChristopher Ferris unbindFile = m_driverPath + "unbind";
852*a248dafdSChristopher Ferris
853*a248dafdSChristopher Ferris Sleep(500);
854*a248dafdSChristopher Ferris if (!WriteDeviceNameToFile(unbindFile.c_str(), m_transportDeviceName.c_str())) {
855*a248dafdSChristopher Ferris fprintf(stderr, "Failed to unbind HID device %s: %s\n",
856*a248dafdSChristopher Ferris m_transportDeviceName.c_str(), strerror(errno));
857*a248dafdSChristopher Ferris return;
858*a248dafdSChristopher Ferris }
859*a248dafdSChristopher Ferris Sleep(500);
860*a248dafdSChristopher Ferris if (!WriteDeviceNameToFile(bindFile.c_str(), m_transportDeviceName.c_str())) {
861*a248dafdSChristopher Ferris fprintf(stderr, "Failed to bind HID device %s: %s\n",
862*a248dafdSChristopher Ferris m_transportDeviceName.c_str(), strerror(errno));
863*a248dafdSChristopher Ferris return;
864*a248dafdSChristopher Ferris }
865*a248dafdSChristopher Ferris
866*a248dafdSChristopher Ferris if (WaitForHidRawDevice(notifyFd, hidrawFile)) {
867*a248dafdSChristopher Ferris rc = Open(hidrawFile.c_str());
868*a248dafdSChristopher Ferris if (rc)
869*a248dafdSChristopher Ferris fprintf(stderr, "Failed to open device (%s) during rebind: %d: errno: %s (%d)\n",
870*a248dafdSChristopher Ferris hidrawFile.c_str(), rc, strerror(errno), errno);
871*a248dafdSChristopher Ferris }
872*a248dafdSChristopher Ferris }
873*a248dafdSChristopher Ferris
FindTransportDevice(uint32_t bus,std::string & hidDeviceName,std::string & transportDeviceName,std::string & driverPath)874*a248dafdSChristopher Ferris bool HIDDevice::FindTransportDevice(uint32_t bus, std::string & hidDeviceName,
875*a248dafdSChristopher Ferris std::string & transportDeviceName, std::string & driverPath)
876*a248dafdSChristopher Ferris {
877*a248dafdSChristopher Ferris std::string devicePrefix = "/sys/bus/";
878*a248dafdSChristopher Ferris std::string devicePath;
879*a248dafdSChristopher Ferris struct dirent * devicesDirEntry;
880*a248dafdSChristopher Ferris DIR * devicesDir;
881*a248dafdSChristopher Ferris struct dirent * devDirEntry;
882*a248dafdSChristopher Ferris DIR * devDir;
883*a248dafdSChristopher Ferris bool deviceFound = false;
884*a248dafdSChristopher Ferris ssize_t sz;
885*a248dafdSChristopher Ferris
886*a248dafdSChristopher Ferris if (bus == BUS_I2C) {
887*a248dafdSChristopher Ferris devicePrefix += "i2c/";
888*a248dafdSChristopher Ferris // The i2c driver module installed on system is vary (i2c_hid, i2c_hid_acpi, i2c_hid_of),
889*a248dafdSChristopher Ferris // so we will assign driver path until we get device name later.
890*a248dafdSChristopher Ferris } else {
891*a248dafdSChristopher Ferris devicePrefix += "usb/";
892*a248dafdSChristopher Ferris driverPath = devicePrefix + "drivers/usbhid/";
893*a248dafdSChristopher Ferris }
894*a248dafdSChristopher Ferris devicePath = devicePrefix + "devices/";
895*a248dafdSChristopher Ferris
896*a248dafdSChristopher Ferris devicesDir = opendir(devicePath.c_str());
897*a248dafdSChristopher Ferris if (!devicesDir)
898*a248dafdSChristopher Ferris return false;
899*a248dafdSChristopher Ferris
900*a248dafdSChristopher Ferris while((devicesDirEntry = readdir(devicesDir)) != NULL) {
901*a248dafdSChristopher Ferris if (devicesDirEntry->d_type != DT_LNK)
902*a248dafdSChristopher Ferris continue;
903*a248dafdSChristopher Ferris
904*a248dafdSChristopher Ferris char buf[PATH_MAX];
905*a248dafdSChristopher Ferris
906*a248dafdSChristopher Ferris sz = readlinkat(dirfd(devicesDir), devicesDirEntry->d_name, buf, PATH_MAX);
907*a248dafdSChristopher Ferris if (sz < 0)
908*a248dafdSChristopher Ferris continue;
909*a248dafdSChristopher Ferris
910*a248dafdSChristopher Ferris buf[sz] = 0;
911*a248dafdSChristopher Ferris
912*a248dafdSChristopher Ferris std::string fullLinkPath = devicePath + buf;
913*a248dafdSChristopher Ferris devDir = opendir(fullLinkPath.c_str());
914*a248dafdSChristopher Ferris if (!devDir) {
915*a248dafdSChristopher Ferris fprintf(stdout, "opendir failed\n");
916*a248dafdSChristopher Ferris continue;
917*a248dafdSChristopher Ferris }
918*a248dafdSChristopher Ferris
919*a248dafdSChristopher Ferris while ((devDirEntry = readdir(devDir)) != NULL) {
920*a248dafdSChristopher Ferris if (!strcmp(devDirEntry->d_name, hidDeviceName.c_str())) {
921*a248dafdSChristopher Ferris transportDeviceName = devicesDirEntry->d_name;
922*a248dafdSChristopher Ferris deviceFound = true;
923*a248dafdSChristopher Ferris break;
924*a248dafdSChristopher Ferris }
925*a248dafdSChristopher Ferris }
926*a248dafdSChristopher Ferris closedir(devDir);
927*a248dafdSChristopher Ferris
928*a248dafdSChristopher Ferris if (deviceFound) {
929*a248dafdSChristopher Ferris if (bus == BUS_I2C) {
930*a248dafdSChristopher Ferris std::fstream ueventfile;
931*a248dafdSChristopher Ferris std::string ueventfilepath = fullLinkPath + "/uevent";
932*a248dafdSChristopher Ferris std::string uevent;
933*a248dafdSChristopher Ferris std::string modulename;
934*a248dafdSChristopher Ferris ueventfile.open(ueventfilepath.c_str(), std::ios::in);
935*a248dafdSChristopher Ferris if(ueventfile.is_open()) {
936*a248dafdSChristopher Ferris getline(ueventfile, uevent);
937*a248dafdSChristopher Ferris modulename = uevent.substr(uevent.find("=") + 1, std::string::npos);
938*a248dafdSChristopher Ferris driverPath = devicePrefix + "drivers/";
939*a248dafdSChristopher Ferris driverPath += modulename;
940*a248dafdSChristopher Ferris driverPath += "/";
941*a248dafdSChristopher Ferris }
942*a248dafdSChristopher Ferris ueventfile.close();
943*a248dafdSChristopher Ferris }
944*a248dafdSChristopher Ferris break;
945*a248dafdSChristopher Ferris }
946*a248dafdSChristopher Ferris
947*a248dafdSChristopher Ferris }
948*a248dafdSChristopher Ferris closedir(devicesDir);
949*a248dafdSChristopher Ferris
950*a248dafdSChristopher Ferris return deviceFound;
951*a248dafdSChristopher Ferris }
952*a248dafdSChristopher Ferris
LookupHidDeviceName(uint32_t bus,int16_t vendorId,int16_t productId,std::string & deviceName)953*a248dafdSChristopher Ferris bool HIDDevice::LookupHidDeviceName(uint32_t bus, int16_t vendorId, int16_t productId, std::string & deviceName)
954*a248dafdSChristopher Ferris {
955*a248dafdSChristopher Ferris bool ret = false;
956*a248dafdSChristopher Ferris struct dirent * devDirEntry;
957*a248dafdSChristopher Ferris DIR * devDir;
958*a248dafdSChristopher Ferris char devicePrefix[15];
959*a248dafdSChristopher Ferris
960*a248dafdSChristopher Ferris snprintf(devicePrefix, 15, "%04X:%04X:%04X", bus, (vendorId & 0xFFFF), (productId & 0xFFFF));
961*a248dafdSChristopher Ferris
962*a248dafdSChristopher Ferris devDir = opendir("/sys/bus/hid/devices");
963*a248dafdSChristopher Ferris if (!devDir)
964*a248dafdSChristopher Ferris return false;
965*a248dafdSChristopher Ferris
966*a248dafdSChristopher Ferris while ((devDirEntry = readdir(devDir)) != NULL) {
967*a248dafdSChristopher Ferris if (!strncmp(devDirEntry->d_name, devicePrefix, 14)) {
968*a248dafdSChristopher Ferris deviceName = devDirEntry->d_name;
969*a248dafdSChristopher Ferris ret = true;
970*a248dafdSChristopher Ferris break;
971*a248dafdSChristopher Ferris }
972*a248dafdSChristopher Ferris }
973*a248dafdSChristopher Ferris closedir(devDir);
974*a248dafdSChristopher Ferris
975*a248dafdSChristopher Ferris return ret;
976*a248dafdSChristopher Ferris }
977*a248dafdSChristopher Ferris
LookupHidDriverName(std::string & deviceName,std::string & driverName)978*a248dafdSChristopher Ferris bool HIDDevice::LookupHidDriverName(std::string &deviceName, std::string &driverName)
979*a248dafdSChristopher Ferris {
980*a248dafdSChristopher Ferris bool ret = false;
981*a248dafdSChristopher Ferris ssize_t sz;
982*a248dafdSChristopher Ferris char link[PATH_MAX];
983*a248dafdSChristopher Ferris std::string driverLink = "/sys/bus/hid/devices/" + deviceName + "/driver";
984*a248dafdSChristopher Ferris
985*a248dafdSChristopher Ferris sz = readlink(driverLink.c_str(), link, PATH_MAX);
986*a248dafdSChristopher Ferris if (sz == -1)
987*a248dafdSChristopher Ferris return ret;
988*a248dafdSChristopher Ferris
989*a248dafdSChristopher Ferris link[sz] = 0;
990*a248dafdSChristopher Ferris
991*a248dafdSChristopher Ferris driverName = std::string(StripPath(link, PATH_MAX));
992*a248dafdSChristopher Ferris
993*a248dafdSChristopher Ferris return true;
994*a248dafdSChristopher Ferris }
995*a248dafdSChristopher Ferris
WaitForHidRawDevice(int notifyFd,std::string & hidrawFile)996*a248dafdSChristopher Ferris bool HIDDevice::WaitForHidRawDevice(int notifyFd, std::string & hidrawFile)
997*a248dafdSChristopher Ferris {
998*a248dafdSChristopher Ferris struct timeval timeout;
999*a248dafdSChristopher Ferris fd_set fds;
1000*a248dafdSChristopher Ferris int rc;
1001*a248dafdSChristopher Ferris ssize_t eventBytesRead;
1002*a248dafdSChristopher Ferris int eventBytesAvailable;
1003*a248dafdSChristopher Ferris size_t sz;
1004*a248dafdSChristopher Ferris char link[PATH_MAX];
1005*a248dafdSChristopher Ferris std::string transportDeviceName;
1006*a248dafdSChristopher Ferris std::string driverPath;
1007*a248dafdSChristopher Ferris std::string hidDeviceName;
1008*a248dafdSChristopher Ferris int offset = 0;
1009*a248dafdSChristopher Ferris
1010*a248dafdSChristopher Ferris for (;;) {
1011*a248dafdSChristopher Ferris FD_ZERO(&fds);
1012*a248dafdSChristopher Ferris FD_SET(notifyFd, &fds);
1013*a248dafdSChristopher Ferris
1014*a248dafdSChristopher Ferris timeout.tv_sec = 20;
1015*a248dafdSChristopher Ferris timeout.tv_usec = 0;
1016*a248dafdSChristopher Ferris
1017*a248dafdSChristopher Ferris rc = select(notifyFd + 1, &fds, NULL, NULL, &timeout);
1018*a248dafdSChristopher Ferris if (rc < 0) {
1019*a248dafdSChristopher Ferris if (errno == -EINTR)
1020*a248dafdSChristopher Ferris continue;
1021*a248dafdSChristopher Ferris
1022*a248dafdSChristopher Ferris return false;
1023*a248dafdSChristopher Ferris }
1024*a248dafdSChristopher Ferris
1025*a248dafdSChristopher Ferris if (rc == 0) {
1026*a248dafdSChristopher Ferris return false;
1027*a248dafdSChristopher Ferris }
1028*a248dafdSChristopher Ferris
1029*a248dafdSChristopher Ferris if (FD_ISSET(notifyFd, &fds)) {
1030*a248dafdSChristopher Ferris struct inotify_event * event;
1031*a248dafdSChristopher Ferris
1032*a248dafdSChristopher Ferris rc = ioctl(notifyFd, FIONREAD, &eventBytesAvailable);
1033*a248dafdSChristopher Ferris if (rc < 0) {
1034*a248dafdSChristopher Ferris continue;
1035*a248dafdSChristopher Ferris }
1036*a248dafdSChristopher Ferris
1037*a248dafdSChristopher Ferris char buf[eventBytesAvailable];
1038*a248dafdSChristopher Ferris
1039*a248dafdSChristopher Ferris eventBytesRead = read(notifyFd, buf, eventBytesAvailable);
1040*a248dafdSChristopher Ferris if (eventBytesRead < 0) {
1041*a248dafdSChristopher Ferris continue;
1042*a248dafdSChristopher Ferris }
1043*a248dafdSChristopher Ferris
1044*a248dafdSChristopher Ferris while (offset < eventBytesRead) {
1045*a248dafdSChristopher Ferris event = (struct inotify_event *)&buf[offset];
1046*a248dafdSChristopher Ferris
1047*a248dafdSChristopher Ferris if (!strncmp(event->name, "hidraw", 6)) {
1048*a248dafdSChristopher Ferris std::string classPath = std::string("/sys/class/hidraw/")
1049*a248dafdSChristopher Ferris + event->name + "/device";
1050*a248dafdSChristopher Ferris sz = readlink(classPath.c_str(), link, PATH_MAX);
1051*a248dafdSChristopher Ferris link[sz] = 0;
1052*a248dafdSChristopher Ferris
1053*a248dafdSChristopher Ferris hidDeviceName = std::string(link).substr(9, 19);
1054*a248dafdSChristopher Ferris
1055*a248dafdSChristopher Ferris if (!FindTransportDevice(m_info.bustype, hidDeviceName, transportDeviceName, driverPath)) {
1056*a248dafdSChristopher Ferris fprintf(stderr, "Failed to find the transport device / driver for %s\n", hidDeviceName.c_str());
1057*a248dafdSChristopher Ferris continue;
1058*a248dafdSChristopher Ferris }
1059*a248dafdSChristopher Ferris
1060*a248dafdSChristopher Ferris if (transportDeviceName == m_transportDeviceName) {
1061*a248dafdSChristopher Ferris hidrawFile = std::string("/dev/") + event->name;
1062*a248dafdSChristopher Ferris return true;
1063*a248dafdSChristopher Ferris }
1064*a248dafdSChristopher Ferris }
1065*a248dafdSChristopher Ferris
1066*a248dafdSChristopher Ferris offset += sizeof(struct inotify_event) + event->len;
1067*a248dafdSChristopher Ferris }
1068*a248dafdSChristopher Ferris }
1069*a248dafdSChristopher Ferris }
1070*a248dafdSChristopher Ferris }
1071*a248dafdSChristopher Ferris
FindDevice(enum RMIDeviceType type)1072*a248dafdSChristopher Ferris bool HIDDevice::FindDevice(enum RMIDeviceType type)
1073*a248dafdSChristopher Ferris {
1074*a248dafdSChristopher Ferris DIR * devDir;
1075*a248dafdSChristopher Ferris struct dirent * devDirEntry;
1076*a248dafdSChristopher Ferris char deviceFile[PATH_MAX];
1077*a248dafdSChristopher Ferris bool found = false;
1078*a248dafdSChristopher Ferris int rc;
1079*a248dafdSChristopher Ferris devDir = opendir("/dev");
1080*a248dafdSChristopher Ferris if (!devDir)
1081*a248dafdSChristopher Ferris return -1;
1082*a248dafdSChristopher Ferris
1083*a248dafdSChristopher Ferris while ((devDirEntry = readdir(devDir)) != NULL) {
1084*a248dafdSChristopher Ferris if (strstr(devDirEntry->d_name, "hidraw")) {
1085*a248dafdSChristopher Ferris snprintf(deviceFile, PATH_MAX, "/dev/%s", devDirEntry->d_name);
1086*a248dafdSChristopher Ferris fprintf(stdout, "Got device : /dev/%s\n", devDirEntry->d_name);
1087*a248dafdSChristopher Ferris rc = Open(deviceFile);
1088*a248dafdSChristopher Ferris if (rc != 0) {
1089*a248dafdSChristopher Ferris continue;
1090*a248dafdSChristopher Ferris } else if (type != RMI_DEVICE_TYPE_ANY && GetDeviceType() != type) {
1091*a248dafdSChristopher Ferris Close();
1092*a248dafdSChristopher Ferris continue;
1093*a248dafdSChristopher Ferris } else {
1094*a248dafdSChristopher Ferris found = true;
1095*a248dafdSChristopher Ferris break;
1096*a248dafdSChristopher Ferris }
1097*a248dafdSChristopher Ferris }
1098*a248dafdSChristopher Ferris }
1099*a248dafdSChristopher Ferris closedir(devDir);
1100*a248dafdSChristopher Ferris
1101*a248dafdSChristopher Ferris return found;
1102*a248dafdSChristopher Ferris }
1103