xref: /aosp_15_r20/external/rmi4utils/rmidevice/hiddevice.cpp (revision a248dafd7653b99fc45f9d29e5f139b04f2f28bc)
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