Linux version with old libusb done
[usb-relay-hid.git] / commandline / hiddata.c
1 /* Name: hiddata.c
2 * Author: Christian Starkjohann
3 * Creation Date: 2008-04-11
4 * Tabsize: 4
5 * Copyright: (c) 2008 by OBJECTIVE DEVELOPMENT Software GmbH
6 * License: GNU GPL v2 (see License.txt), GNU GPL v3 or proprietary (CommercialLicense.txt)
7 */
8
9 #include "hiddata.h"
10 #include <stdio.h>
11 #include <string.h>
12 #include <errno.h>
13
14 #if 0 //ifdef DEBUG
15 #define DEBUG_PRINT(arg) printf arg
16 #else
17 #define DEBUG_PRINT(arg)
18 #endif
19
20 #define A_MAX_USB_STRING_LEN 126
21
22
23 /* ######################################################################## */
24 #if defined(_WIN32)
25 /* ######################################################################## */
26
27 #include "targetver.h"
28 #include <windows.h>
29 #include <setupapi.h>
30 #include <hidsdi.h>
31 #include <hidpi.h>
32
33 #ifdef _MSC_VER
34 #pragma comment(lib, "setupapi")
35 #pragma comment(lib, "hid")
36 #endif /*_MSC_VER*/
37
38 /*
39 * Convert UTF-16 null term. string to single byte (ASCII or ISO Latin)
40 * change all weird characters to "?"
41 */
42 static void usbstring_to_ascii(unsigned short *wp, char *cp, int size)
43 {
44 unsigned short *wpend = wp + (size/sizeof(unsigned short));
45 for( ; wp < wpend; )
46 {
47 unsigned short h = *wp++;
48 *cp++ = (h < 0xFF) ? (char)h : '?';
49 if (h == 0)
50 break;
51 }
52 }
53
54 /*
55 * Read HID string for vendor and device, return as ASCII (or ISO Latin...)
56 */
57 int usbhidGetVendorString(USBDEVHANDLE usbh, char *buffer, int len)
58 {
59 /* HidD_GetManufacturerString returns zero terminated UTF-16 string */
60 /* Error if buffer is too short */
61 if ( !HidD_GetManufacturerString((HANDLE)usbh, (void*)buffer, len ) ) {
62 DEBUG_PRINT(("error obtaining vendor name\n"));
63 return USBOPEN_ERR_IO;
64 }
65 usbstring_to_ascii((UINT16*)buffer, buffer, len);
66 return 0;
67 }
68
69 int usbhidGetProductString(USBDEVHANDLE usbh, char *buffer, int len)
70 {
71 /* HidD_GetProductString returns zero terminated UTF-16 string */
72 /* Error if buffer is too short */
73 if (!HidD_GetProductString((HANDLE)usbh, (void*)buffer, len ) ) {
74 DEBUG_PRINT(("error obtaining product name\n"));
75 return USBOPEN_ERR_IO;
76 }
77 usbstring_to_ascii((UINT16*)buffer, buffer, len);
78 return 0;
79 }
80
81 /*
82 * Enumerate HID USB devices.
83 * In Windows this will find also non-USB devices, but assume that
84 * filtering by PID & VID is enough.
85 * Some HID devices (mice, kbd) are locked by Windows and cannot be opened.
86 * If we cannot open a device for R&W, we skip it without error.
87 * Assume our devices are not of types reserved by Windows.
88 */
89 int usbhidEnumDevices(int vendor, int product,
90 void *context,
91 int (*usbhidEnumFunc)(USBDEVHANDLE usbh, void *ctx))
92 {
93 GUID hidGuid; /* GUID for HID class */
94 HDEVINFO deviceInfoList;
95 SP_DEVICE_INTERFACE_DATA deviceInfo;
96 SP_DEVICE_INTERFACE_DETAIL_DATA_W *deviceDetails = NULL;
97 DWORD size;
98 int i, openFlag = 0; /* may be FILE_FLAG_OVERLAPPED */
99 int errorCode = USBOPEN_ERR_NOTFOUND;
100 HANDLE handle = INVALID_HANDLE_VALUE;
101 HIDD_ATTRIBUTES deviceAttributes;
102
103 HidD_GetHidGuid(&hidGuid);
104 deviceInfoList = SetupDiGetClassDevsW(&hidGuid, NULL, NULL, DIGCF_PRESENT | DIGCF_INTERFACEDEVICE);
105 if (!deviceInfoList || deviceInfoList == INVALID_HANDLE_VALUE)
106 {
107 return USBOPEN_ERR_NOTFOUND;
108 }
109
110 deviceInfo.cbSize = sizeof(deviceInfo);
111 for (i=0; ; i++) {
112 if(handle != INVALID_HANDLE_VALUE){
113 CloseHandle(handle);
114 handle = INVALID_HANDLE_VALUE;
115 }
116 if( !SetupDiEnumDeviceInterfaces(deviceInfoList, 0, &hidGuid, i, &deviceInfo) )
117 break; /* no more entries */
118 /* first do a dummy call just to determine the actual size required */
119 SetupDiGetDeviceInterfaceDetailW(deviceInfoList, &deviceInfo, NULL, 0, &size, NULL);
120 if(deviceDetails != NULL)
121 free(deviceDetails);
122 deviceDetails = malloc(size);
123 deviceDetails->cbSize = sizeof(*deviceDetails);
124 /* this call is for real: */
125 SetupDiGetDeviceInterfaceDetailW(deviceInfoList, &deviceInfo, deviceDetails, size, &size, NULL);
126 DEBUG_PRINT(("checking HID path \"%s\"\n", deviceDetails->DevicePath));
127
128 handle = CreateFileW(deviceDetails->DevicePath,
129 GENERIC_READ|GENERIC_WRITE, FILE_SHARE_READ|FILE_SHARE_WRITE, NULL, OPEN_EXISTING, openFlag, NULL);
130 if(handle == INVALID_HANDLE_VALUE){
131 DEBUG_PRINT(("open USB device failed: gle=%d\n", (int)GetLastError()));
132 /* errorCode = USBOPEN_ERR_ACCESS; opening will always fail for mouse -- ignore */
133 continue;
134 }
135 deviceAttributes.Size = sizeof(deviceAttributes);
136 HidD_GetAttributes(handle, &deviceAttributes);
137 DEBUG_PRINT(("device attributes: vid=%d pid=%d ver=%4.4X\n", deviceAttributes.VendorID, deviceAttributes.ProductID, deviceAttributes.VersionNumber));
138 if(deviceAttributes.VendorID != vendor || deviceAttributes.ProductID != product)
139 continue; /* skip this device */
140
141 errorCode = 0;
142 if ( 0 == usbhidEnumFunc((USBDEVHANDLE)handle, context) )
143 {
144 break; /* stop enumeration */
145 }
146
147 /* Now the handle is owned by the callback */
148 handle = INVALID_HANDLE_VALUE;
149 }
150
151 SetupDiDestroyDeviceInfoList(deviceInfoList);
152 if(deviceDetails != NULL)
153 free(deviceDetails);
154
155 return errorCode;
156 }
157
158
159 void usbhidCloseDevice(USBDEVHANDLE usbh)
160 {
161 CloseHandle((HANDLE)usbh);
162 }
163
164
165 int usbhidSetReport(USBDEVHANDLE usbh, char *buffer, int len)
166 {
167 BOOLEAN rval;
168 rval = HidD_SetFeature((HANDLE)usbh, buffer, len);
169 return rval == 0 ? USBOPEN_ERR_IO : 0;
170 }
171
172
173 int usbhidGetReport(USBDEVHANDLE usbh, int reportNumber, char *buffer, int *len)
174 {
175 BOOLEAN rval = 0;
176 buffer[0] = reportNumber;
177 rval = HidD_GetFeature((HANDLE)usbh, buffer, *len);
178 return rval == 0 ? USBOPEN_ERR_IO : 0;
179 }
180
181
182
183 /* ######################################################################## */
184 #else /* defined WIN32 #################################################### */
185 /* ######################################################################## */
186
187 // Using the old simple version of libusb (before 1.0)
188 #include <usb.h>
189
190 // USBDEVHANDLE is same as struct usb_device *
191 // Open handles are stored in struct usb_device (HACK! revise for new libusb)
192
193 static inline struct usb_device * usbDevStruct(USBDEVHANDLE usbh) {
194 return (struct usb_device *)usbh;
195 }
196
197 static inline usb_dev_handle * usbDevHandle(USBDEVHANDLE usbh) {
198 return (usb_dev_handle *)(usbDevStruct(usbh)->children);
199 }
200
201 // TO DO: for devices that prepend report ID, implement this somehow
202 static inline int usesReportIDs(USBDEVHANDLE usbh) {
203 /* return 1 if 1st byte of get/set report buffer is report ID */
204 return 0;
205 }
206
207 /* ------------------------------------------------------------------------- */
208
209 #define USBRQ_HID_GET_REPORT 0x01
210 #define USBRQ_HID_SET_REPORT 0x09
211
212 #define USB_HID_REPORT_TYPE_FEATURE 3
213
214 #define A_REPORT_REQUEST_TIMEOUT 5000 /* in milliseconds */
215
216 /* ------------------------------------------------------------------------- */
217
218 int usbhidEnumDevices(int vendor, int product,
219 void *context,
220 int (*usbhidEnumFunc)(USBDEVHANDLE usbh, void *ctx))
221
222 {
223 struct usb_bus *bus;
224 struct usb_device *dev;
225 usb_dev_handle *handle = NULL;
226 int errorCode = USBOPEN_ERR_NOTFOUND;
227 static int didUsbInit = 0;
228
229 if(!didUsbInit){
230 usb_init();
231 didUsbInit = 1;
232 }
233 usb_find_busses();
234 usb_find_devices();
235 for (bus=usb_get_busses(); bus; bus=bus->next) {
236 for (dev=bus->devices; dev; dev=dev->next) {
237 if (dev->descriptor.idVendor == vendor && dev->descriptor.idProduct == product) {
238 handle = usb_open(dev); /* we need to open the device in order to query strings */
239 if ( !handle ) {
240 errorCode = USBOPEN_ERR_ACCESS;
241 fprintf(stderr, "Warning: cannot open USB device: %s\n", usb_strerror());
242 continue;
243 }
244
245 errorCode = 0;
246
247 // printf("Probing: [%s] nc=%u %p\n", dev->filename, dev->num_children, dev->children);
248 // Assume our devices are leaf, so we can use dev->children to store the handle
249 if ( dev->children ) {
250 fprintf(stderr, "ERROR: assertion failed for usb dev %p\n", dev);
251 usb_close(handle);
252 handle = NULL;
253 continue;
254 }
255
256 dev->children = (void*)handle;
257 if ( 0 == usbhidEnumFunc((void*)dev, context) )
258 {
259 break; /* stop enumeration */
260 }
261
262 /* Now the handle is owned by the callback */
263 handle = 0;
264 }
265 }
266 }
267
268 return errorCode;
269 }
270
271 /* ------------------------------------------------------------------------- */
272
273 void usbhidCloseDevice(USBDEVHANDLE usbh)
274 {
275 if (usbh != NULL) {
276 usb_close(usbDevHandle(usbh));
277 usbDevStruct(usbh)->children = NULL;
278 }
279 }
280
281 /* ------------------------------------------------------------------------- */
282
283 static int usbhidGetStringAscii(struct usb_dev_handle *dev, int index, char *buf, int buflen)
284 {
285 int rval;
286 if((rval = usb_get_string_simple(dev, index, buf, buflen)) >= 0) /* use libusb version if it works */
287 return rval;
288 if (errno == EPERM)
289 fprintf(stderr, "usbhid: Access denied to USB device. Run as root or adjust device permissions.\n");
290 else
291 fprintf(stderr, "usbhid: %s error %s\n", __FUNCTION__, usb_strerror());
292 return -1;
293 }
294
295 int usbhidGetVendorString(USBDEVHANDLE usbh, char *buffer, int len)
296 {
297 int len2 = usbhidGetStringAscii(usbDevHandle(usbh), usbDevStruct(usbh)->descriptor.iManufacturer, buffer, len);
298 if (len2 < 0) {
299 fprintf(stderr, "Warning: cannot query vendor for device\n");
300 return USBOPEN_ERR_IO;
301 }
302 return 0;
303 }
304
305 int usbhidGetProductString(USBDEVHANDLE usbh, char *buffer, int len)
306 {
307 int len2 = usbhidGetStringAscii(usbDevHandle(usbh), usbDevStruct(usbh)->descriptor.iProduct, buffer, len);
308 if (len2 < 0) {
309 fprintf(stderr, "Warning: cannot query product for device\n");
310 return USBOPEN_ERR_IO;
311 }
312 return 0;
313 }
314
315
316
317
318 int usbhidSetReport(USBDEVHANDLE usbh, char *buffer, int len)
319 {
320 int bytesSent, reportId = buffer[0];
321
322 if ( !usesReportIDs(usbh) ) {
323 buffer++; /* skip dummy report ID */
324 len--;
325 }
326 bytesSent = usb_control_msg(usbDevHandle(usbh),
327 USB_TYPE_CLASS | USB_RECIP_DEVICE | USB_ENDPOINT_OUT, USBRQ_HID_SET_REPORT, USB_HID_REPORT_TYPE_FEATURE << 8 | (reportId & 0xff),
328 0, buffer, len, A_REPORT_REQUEST_TIMEOUT);
329 if (bytesSent != len) {
330 if (bytesSent < 0)
331 fprintf(stderr, "Error sending message: %s\n", usb_strerror());
332 return USBOPEN_ERR_IO;
333 }
334 return 0;
335 }
336
337 /* ------------------------------------------------------------------------- */
338
339 int usbhidGetReport(USBDEVHANDLE usbh, int reportNumber, char *buffer, int *len)
340 {
341 int bytesReceived, maxLen = *len;
342
343 if (!usesReportIDs(usbh)) {
344 buffer++; /* make room for dummy report ID */
345 maxLen--;
346 }
347 bytesReceived = usb_control_msg(usbDevHandle(usbh),
348 USB_TYPE_CLASS | USB_RECIP_DEVICE | USB_ENDPOINT_IN, USBRQ_HID_GET_REPORT, USB_HID_REPORT_TYPE_FEATURE << 8 | reportNumber,
349 0, buffer, maxLen, A_REPORT_REQUEST_TIMEOUT);
350 if(bytesReceived < 0){
351 fprintf(stderr, "Error sending message: %s\n", usb_strerror());
352 return USBOPEN_ERR_IO;
353 }
354 *len = bytesReceived;
355 if (!usesReportIDs(usbh)) {
356 buffer[-1] = reportNumber; /* add dummy report ID */
357 (*len)++;
358 }
359 return 0;
360 }
361
362
363 void usbhidSetUsesReportId(USBDEVHANDLE usbh)
364 {
365 //TODO Implement if some devices prepend report IDs
366 }
367
368 /* ######################################################################## */
369 #endif /* WIN32 */
370 /* ######################################################################## */