OLD | NEW |
---|---|
(Empty) | |
1 /******************************************************* | |
2 HIDAPI - Multi-Platform library for | |
3 communication with HID devices. | |
4 | |
5 Alan Ott | |
6 Signal 11 Software | |
7 | |
8 8/22/2009 | |
9 | |
10 Copyright 2009, All Rights Reserved. | |
11 | |
12 At the discretion of the user of this library, | |
13 this software may be licensed under the terms of the | |
14 GNU General Public License v3, a BSD-Style license, or the | |
15 original HIDAPI license as outlined in the LICENSE.txt, | |
16 LICENSE-gpl3.txt, LICENSE-bsd.txt, and LICENSE-orig.txt | |
17 files located at the root of the source distribution. | |
18 These files may also be found in the public source | |
19 code repository located at: | |
20 http://github.com/signal11/hidapi . | |
21 ********************************************************/ | |
22 | |
23 #include <windows.h> | |
24 | |
25 #ifndef _NTDEF_ | |
26 typedef LONG NTSTATUS; | |
27 #endif | |
28 | |
29 #ifdef __MINGW32__ | |
30 #include <ntdef.h> | |
31 #include <winbase.h> | |
32 #endif | |
33 | |
34 #ifdef __CYGWIN__ | |
35 #include <ntdef.h> | |
36 #define _wcsdup wcsdup | |
37 #endif | |
38 | |
39 /*#define HIDAPI_USE_DDK*/ | |
40 | |
41 #ifdef __cplusplus | |
42 extern "C" { | |
43 #endif | |
44 #include <setupapi.h> | |
45 #include <winioctl.h> | |
46 #ifdef HIDAPI_USE_DDK | |
47 #include <hidsdi.h> | |
48 #endif | |
49 | |
50 /* Copied from inc/ddk/hidclass.h, part of the Windows DDK. */ | |
51 #define HID_OUT_CTL_CODE(id) \ | |
52 CTL_CODE(FILE_DEVICE_KEYBOARD, (id), METHOD_OUT_DIRECT, FILE_ANY _ACCESS) | |
53 #define IOCTL_HID_GET_FEATURE HID_OUT_CTL_CODE(100) | |
54 | |
55 #ifdef __cplusplus | |
56 } /* extern "C" */ | |
57 #endif | |
58 | |
59 #include <stdio.h> | |
60 #include <stdlib.h> | |
61 | |
62 | |
63 #include "hidapi.h" | |
64 | |
65 #ifdef _MSC_VER | |
66 /* Thanks Microsoft, but I know how to use strncpy(). */ | |
67 #pragma warning(disable:4996) | |
Will Harris
2014/01/14 23:40:01
prefer to disable in the gyp file rather than inli
| |
68 #endif | |
69 | |
70 #ifdef __cplusplus | |
71 extern "C" { | |
72 #endif | |
73 | |
74 #ifndef HIDAPI_USE_DDK | |
75 /* Since we're not building with the DDK, and the HID header | |
76 files aren't part of the SDK, we have to define all this | |
77 stuff here. In lookup_functions(), the function pointers | |
78 defined below are set. */ | |
79 typedef struct _HIDD_ATTRIBUTES{ | |
80 ULONG Size; | |
81 USHORT VendorID; | |
82 USHORT ProductID; | |
83 USHORT VersionNumber; | |
84 } HIDD_ATTRIBUTES, *PHIDD_ATTRIBUTES; | |
85 | |
86 typedef USHORT USAGE; | |
87 typedef struct _HIDP_CAPS { | |
88 USAGE Usage; | |
89 USAGE UsagePage; | |
90 USHORT InputReportByteLength; | |
91 USHORT OutputReportByteLength; | |
92 USHORT FeatureReportByteLength; | |
93 USHORT Reserved[17]; | |
94 USHORT fields_not_used_by_hidapi[10]; | |
95 } HIDP_CAPS, *PHIDP_CAPS; | |
96 typedef void* PHIDP_PREPARSED_DATA; | |
97 #define HIDP_STATUS_SUCCESS 0x110000 | |
98 | |
99 typedef BOOLEAN (__stdcall *HidD_GetAttributes_)(HANDLE device, PHIDD_AT TRIBUTES attrib); | |
100 typedef BOOLEAN (__stdcall *HidD_GetSerialNumberString_)(HANDLE device, PVOID buffer, ULONG buffer_len); | |
101 typedef BOOLEAN (__stdcall *HidD_GetManufacturerString_)(HANDLE handle, PVOID buffer, ULONG buffer_len); | |
102 typedef BOOLEAN (__stdcall *HidD_GetProductString_)(HANDLE handle, PVOID buffer, ULONG buffer_len); | |
103 typedef BOOLEAN (__stdcall *HidD_SetFeature_)(HANDLE handle, PVOID data, ULONG length); | |
104 typedef BOOLEAN (__stdcall *HidD_GetFeature_)(HANDLE handle, PVOID data, ULONG length); | |
105 typedef BOOLEAN (__stdcall *HidD_GetIndexedString_)(HANDLE handle, ULONG string_index, PVOID buffer, ULONG buffer_len); | |
106 typedef BOOLEAN (__stdcall *HidD_GetPreparsedData_)(HANDLE handle, PHIDP _PREPARSED_DATA *preparsed_data); | |
107 typedef BOOLEAN (__stdcall *HidD_FreePreparsedData_)(PHIDP_PREPARSED_DAT A preparsed_data); | |
108 typedef NTSTATUS (__stdcall *HidP_GetCaps_)(PHIDP_PREPARSED_DATA prepars ed_data, HIDP_CAPS *caps); | |
109 | |
110 static HidD_GetAttributes_ HidD_GetAttributes; | |
111 static HidD_GetSerialNumberString_ HidD_GetSerialNumberString; | |
112 static HidD_GetManufacturerString_ HidD_GetManufacturerString; | |
113 static HidD_GetProductString_ HidD_GetProductString; | |
114 static HidD_SetFeature_ HidD_SetFeature; | |
115 static HidD_GetFeature_ HidD_GetFeature; | |
116 static HidD_GetIndexedString_ HidD_GetIndexedString; | |
117 static HidD_GetPreparsedData_ HidD_GetPreparsedData; | |
118 static HidD_FreePreparsedData_ HidD_FreePreparsedData; | |
119 static HidP_GetCaps_ HidP_GetCaps; | |
120 | |
121 static HMODULE lib_handle = NULL; | |
122 static BOOLEAN initialized = FALSE; | |
123 #endif /* HIDAPI_USE_DDK */ | |
124 | |
125 struct hid_device_ { | |
126 HANDLE device_handle; | |
127 BOOL blocking; | |
128 USHORT output_report_length; | |
129 size_t input_report_length; | |
130 void *last_error_str; | |
131 DWORD last_error_num; | |
132 BOOL read_pending; | |
133 char *read_buf; | |
134 OVERLAPPED ol; | |
135 }; | |
136 | |
137 static hid_device *new_hid_device() | |
138 { | |
139 hid_device *dev = (hid_device*) calloc(1, sizeof(hid_device)); | |
140 dev->device_handle = INVALID_HANDLE_VALUE; | |
141 dev->blocking = TRUE; | |
142 dev->output_report_length = 0; | |
143 dev->input_report_length = 0; | |
144 dev->last_error_str = NULL; | |
145 dev->last_error_num = 0; | |
146 dev->read_pending = FALSE; | |
147 dev->read_buf = NULL; | |
148 memset(&dev->ol, 0, sizeof(dev->ol)); | |
149 dev->ol.hEvent = CreateEvent(NULL, FALSE, FALSE /*inital state f=nonsign aled*/, NULL); | |
150 | |
151 return dev; | |
152 } | |
153 | |
154 static void free_hid_device(hid_device *dev) | |
155 { | |
156 CloseHandle(dev->ol.hEvent); | |
157 CloseHandle(dev->device_handle); | |
158 LocalFree(dev->last_error_str); | |
159 free(dev->read_buf); | |
160 free(dev); | |
161 } | |
162 | |
163 static void register_error(hid_device *device, const char *op) | |
164 { | |
165 WCHAR *ptr, *msg; | |
166 | |
167 FormatMessageW(FORMAT_MESSAGE_ALLOCATE_BUFFER | | |
168 FORMAT_MESSAGE_FROM_SYSTEM | | |
169 FORMAT_MESSAGE_IGNORE_INSERTS, | |
170 NULL, | |
171 GetLastError(), | |
172 MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), | |
173 (LPVOID)&msg, 0/*sz*/, | |
174 NULL); | |
175 | |
176 /* Get rid of the CR and LF that FormatMessage() sticks at the | |
177 end of the message. Thanks Microsoft! */ | |
178 ptr = msg; | |
179 while (*ptr) { | |
180 if (*ptr == '\r') { | |
181 *ptr = 0x0000; | |
182 break; | |
183 } | |
184 ptr++; | |
185 } | |
186 | |
187 /* Store the message off in the Device entry so that | |
188 the hid_error() function can pick it up. */ | |
189 LocalFree(device->last_error_str); | |
190 device->last_error_str = msg; | |
191 } | |
192 | |
193 #ifndef HIDAPI_USE_DDK | |
194 static int lookup_functions() | |
195 { | |
196 lib_handle = LoadLibraryA("hid.dll"); | |
Will Harris
2014/01/14 23:40:01
where will this code be called from? Prefer not t
| |
197 if (lib_handle) { | |
198 #define RESOLVE(x) x = (x##_)GetProcAddress(lib_handle, #x); if (!x) return -1; | |
199 RESOLVE(HidD_GetAttributes); | |
200 RESOLVE(HidD_GetSerialNumberString); | |
201 RESOLVE(HidD_GetManufacturerString); | |
202 RESOLVE(HidD_GetProductString); | |
203 RESOLVE(HidD_SetFeature); | |
204 RESOLVE(HidD_GetFeature); | |
205 RESOLVE(HidD_GetIndexedString); | |
206 RESOLVE(HidD_GetPreparsedData); | |
207 RESOLVE(HidD_FreePreparsedData); | |
208 RESOLVE(HidP_GetCaps); | |
209 #undef RESOLVE | |
210 } | |
211 else | |
212 return -1; | |
213 | |
214 return 0; | |
215 } | |
216 #endif | |
217 | |
218 static HANDLE open_device(const char *path, BOOL enumerate) | |
219 { | |
220 HANDLE handle; | |
221 DWORD desired_access = (enumerate)? 0: (GENERIC_WRITE | GENERIC_READ); | |
222 DWORD share_mode = (enumerate)? | |
223 FILE_SHARE_READ|FILE_SHARE_WRITE: | |
224 FILE_SHARE_READ; | |
225 | |
226 handle = CreateFileA(path, | |
227 desired_access, | |
228 share_mode, | |
229 NULL, | |
230 OPEN_EXISTING, | |
231 FILE_FLAG_OVERLAPPED,/*FILE_ATTRIBUTE_NORMAL,*/ | |
232 0); | |
233 | |
234 return handle; | |
235 } | |
236 | |
237 int HID_API_EXPORT hid_init(void) | |
238 { | |
239 #ifndef HIDAPI_USE_DDK | |
240 if (!initialized) { | |
241 if (lookup_functions() < 0) { | |
242 hid_exit(); | |
243 return -1; | |
244 } | |
245 initialized = TRUE; | |
246 } | |
247 #endif | |
248 return 0; | |
249 } | |
250 | |
251 int HID_API_EXPORT hid_exit(void) | |
252 { | |
253 #ifndef HIDAPI_USE_DDK | |
254 if (lib_handle) | |
255 FreeLibrary(lib_handle); | |
256 lib_handle = NULL; | |
257 initialized = FALSE; | |
258 #endif | |
259 return 0; | |
260 } | |
261 | |
262 struct hid_device_info HID_API_EXPORT * HID_API_CALL hid_enumerate(unsigned shor t vendor_id, unsigned short product_id) | |
263 { | |
264 BOOL res; | |
265 struct hid_device_info *root = NULL; /* return object */ | |
266 struct hid_device_info *cur_dev = NULL; | |
267 | |
268 /* Windows objects for interacting with the driver. */ | |
269 GUID InterfaceClassGuid = {0x4d1e55b2, 0xf16f, 0x11cf, {0x88, 0xcb, 0x00 , 0x11, 0x11, 0x00, 0x00, 0x30} }; | |
270 SP_DEVINFO_DATA devinfo_data; | |
271 SP_DEVICE_INTERFACE_DATA device_interface_data; | |
272 SP_DEVICE_INTERFACE_DETAIL_DATA_A *device_interface_detail_data = NULL; | |
273 HDEVINFO device_info_set = INVALID_HANDLE_VALUE; | |
274 int device_index = 0; | |
275 int i; | |
276 | |
277 if (hid_init() < 0) | |
278 return NULL; | |
279 | |
280 /* Initialize the Windows objects. */ | |
281 memset(&devinfo_data, 0x0, sizeof(devinfo_data)); | |
282 devinfo_data.cbSize = sizeof(SP_DEVINFO_DATA); | |
283 device_interface_data.cbSize = sizeof(SP_DEVICE_INTERFACE_DATA); | |
284 | |
285 /* Get information for all the devices belonging to the HID class. */ | |
286 device_info_set = SetupDiGetClassDevsA(&InterfaceClassGuid, NULL, NULL, DIGCF_PRESENT | DIGCF_DEVICEINTERFACE); | |
287 | |
288 /* Iterate over each device in the HID class, looking for the right one. */ | |
289 | |
290 for (;;) { | |
291 HANDLE write_handle = INVALID_HANDLE_VALUE; | |
292 DWORD required_size = 0; | |
293 HIDD_ATTRIBUTES attrib; | |
294 | |
295 res = SetupDiEnumDeviceInterfaces(device_info_set, | |
296 NULL, | |
297 &InterfaceClassGuid, | |
298 device_index, | |
299 &device_interface_data); | |
300 | |
301 if (!res) { | |
302 /* A return of FALSE from this function means that | |
303 there are no more devices. */ | |
304 break; | |
305 } | |
306 | |
307 /* Call with 0-sized detail size, and let the function | |
308 tell us how long the detail struct needs to be. The | |
309 size is put in &required_size. */ | |
310 res = SetupDiGetDeviceInterfaceDetailA(device_info_set, | |
311 &device_interface_data, | |
312 NULL, | |
313 0, | |
314 &required_size, | |
315 NULL); | |
316 | |
317 /* Allocate a long enough structure for device_interface_detail_ data. */ | |
318 device_interface_detail_data = (SP_DEVICE_INTERFACE_DETAIL_DATA_ A*) malloc(required_size); | |
Will Harris
2014/01/14 23:40:01
check return value of malloc
| |
319 device_interface_detail_data->cbSize = sizeof(SP_DEVICE_INTERFAC E_DETAIL_DATA_A); | |
320 | |
321 /* Get the detailed data for this device. The detail data gives us | |
322 the device path for this device, which is then passed into | |
323 CreateFile() to get a handle to the device. */ | |
324 res = SetupDiGetDeviceInterfaceDetailA(device_info_set, | |
325 &device_interface_data, | |
326 device_interface_detail_data, | |
327 required_size, | |
328 NULL, | |
329 NULL); | |
330 | |
331 if (!res) { | |
332 /* register_error(dev, "Unable to call SetupDiGetDeviceI nterfaceDetail"); | |
333 Continue to the next device. */ | |
334 goto cont; | |
335 } | |
336 | |
337 /* Make sure this device is of Setup Class "HIDClass" and has a | |
338 driver bound to it. */ | |
339 for (i = 0; ; i++) { | |
340 char driver_name[256]; | |
Will Harris
2014/01/14 23:40:01
where is 256 from?
| |
341 | |
342 /* Populate devinfo_data. This function will return fail ure | |
343 when there are no more interfaces left. */ | |
344 res = SetupDiEnumDeviceInfo(device_info_set, i, &devinfo _data); | |
345 if (!res) | |
346 goto cont; | |
347 | |
348 res = SetupDiGetDeviceRegistryPropertyA(device_info_set, &devinfo_data, | |
349 SPDRP_CLASS, NULL, (PBYTE)driver_name, si zeof(driver_name), NULL); | |
350 if (!res) | |
351 goto cont; | |
352 | |
353 if (strcmp(driver_name, "HIDClass") == 0) { | |
354 /* See if there's a driver bound. */ | |
355 res = SetupDiGetDeviceRegistryPropertyA(device_i nfo_set, &devinfo_data, | |
356 SPDRP_DRIVER, NULL, (PBYTE)driver_nam e, sizeof(driver_name), NULL); | |
357 if (res) | |
358 break; | |
359 } | |
360 } | |
361 | |
362 //wprintf(L"HandleName: %s\n", device_interface_detail_data->Dev icePath); | |
363 | |
364 /* Open a handle to the device */ | |
365 write_handle = open_device(device_interface_detail_data->DeviceP ath, TRUE); | |
366 | |
367 /* Check validity of write_handle. */ | |
368 if (write_handle == INVALID_HANDLE_VALUE) { | |
369 /* Unable to open the device. */ | |
370 //register_error(dev, "CreateFile"); | |
371 goto cont_close; | |
Will Harris
2014/01/14 23:40:01
CloseHandle() on invalid handle later on
| |
372 } | |
373 | |
374 | |
375 /* Get the Vendor ID and Product ID for this device. */ | |
376 attrib.Size = sizeof(HIDD_ATTRIBUTES); | |
377 HidD_GetAttributes(write_handle, &attrib); | |
378 //wprintf(L"Product/Vendor: %x %x\n", attrib.ProductID, attrib.V endorID); | |
379 | |
380 /* Check the VID/PID to see if we should add this | |
381 device to the enumeration list. */ | |
382 if ((vendor_id == 0x0 || attrib.VendorID == vendor_id) && | |
383 (product_id == 0x0 || attrib.ProductID == product_id)) { | |
384 | |
385 #define WSTR_LEN 512 | |
386 const char *str; | |
387 struct hid_device_info *tmp; | |
388 PHIDP_PREPARSED_DATA pp_data = NULL; | |
389 HIDP_CAPS caps; | |
390 BOOLEAN res; | |
391 NTSTATUS nt_res; | |
392 wchar_t wstr[WSTR_LEN]; /* TODO: Determine Size */ | |
Will Harris
2014/01/14 23:40:01
seems like a rather scary TODO
| |
393 size_t len; | |
394 | |
395 /* VID/PID match. Create the record. */ | |
396 tmp = (struct hid_device_info*) calloc(1, sizeof(struct hid_device_info)); | |
397 if (cur_dev) { | |
398 cur_dev->next = tmp; | |
399 } | |
400 else { | |
401 root = tmp; | |
402 } | |
403 cur_dev = tmp; | |
404 | |
405 /* Get the Usage Page and Usage for this device. */ | |
406 res = HidD_GetPreparsedData(write_handle, &pp_data); | |
407 if (res) { | |
408 nt_res = HidP_GetCaps(pp_data, &caps); | |
409 if (nt_res == HIDP_STATUS_SUCCESS) { | |
410 cur_dev->usage_page = caps.UsagePage; | |
411 cur_dev->usage = caps.Usage; | |
412 } | |
413 | |
414 HidD_FreePreparsedData(pp_data); | |
415 } | |
416 | |
417 /* Fill out the record */ | |
418 cur_dev->next = NULL; | |
419 str = device_interface_detail_data->DevicePath; | |
420 if (str) { | |
421 len = strlen(str); | |
422 cur_dev->path = (char*) calloc(len+1, sizeof(cha r)); | |
423 strncpy(cur_dev->path, str, len+1); | |
424 cur_dev->path[len] = '\0'; | |
425 } | |
426 else | |
427 cur_dev->path = NULL; | |
428 | |
429 /* Serial Number */ | |
430 res = HidD_GetSerialNumberString(write_handle, wstr, siz eof(wstr)); | |
Will Harris
2014/01/14 23:40:01
these functions all take number of bytes but sizeo
| |
431 wstr[WSTR_LEN-1] = 0x0000; | |
432 if (res) { | |
433 cur_dev->serial_number = _wcsdup(wstr); | |
434 } | |
435 | |
436 /* Manufacturer String */ | |
437 res = HidD_GetManufacturerString(write_handle, wstr, siz eof(wstr)); | |
438 wstr[WSTR_LEN-1] = 0x0000; | |
439 if (res) { | |
440 cur_dev->manufacturer_string = _wcsdup(wstr); | |
441 } | |
442 | |
443 /* Product String */ | |
444 res = HidD_GetProductString(write_handle, wstr, sizeof(w str)); | |
445 wstr[WSTR_LEN-1] = 0x0000; | |
446 if (res) { | |
447 cur_dev->product_string = _wcsdup(wstr); | |
448 } | |
449 | |
450 /* VID/PID */ | |
451 cur_dev->vendor_id = attrib.VendorID; | |
452 cur_dev->product_id = attrib.ProductID; | |
453 | |
454 /* Release Number */ | |
455 cur_dev->release_number = attrib.VersionNumber; | |
456 | |
457 /* Interface Number. It can sometimes be parsed out of t he path | |
458 on Windows if a device has multiple interfaces. See | |
459 http://msdn.microsoft.com/en-us/windows/hardware/gg48 7473 or | |
460 search for "Hardware IDs for HID Devices" at MSDN. If it's not | |
461 in the path, it's set to -1. */ | |
462 cur_dev->interface_number = -1; | |
463 if (cur_dev->path) { | |
464 char *interface_component = strstr(cur_dev->path , "&mi_"); | |
465 if (interface_component) { | |
466 char *hex_str = interface_component + 4; | |
467 char *endptr = NULL; | |
468 cur_dev->interface_number = strtol(hex_s tr, &endptr, 16); | |
469 if (endptr == hex_str) { | |
470 /* The parsing failed. Set inter face_number to -1. */ | |
471 cur_dev->interface_number = -1; | |
472 } | |
473 } | |
474 } | |
475 } | |
476 | |
477 cont_close: | |
478 CloseHandle(write_handle); | |
479 cont: | |
480 /* We no longer need the detail data. It can be freed */ | |
481 free(device_interface_detail_data); | |
482 | |
483 device_index++; | |
484 | |
485 } | |
486 | |
487 /* Close the device information handle. */ | |
488 SetupDiDestroyDeviceInfoList(device_info_set); | |
489 | |
490 return root; | |
491 | |
492 } | |
493 | |
494 void HID_API_EXPORT HID_API_CALL hid_free_enumeration(struct hid_device_info *d evs) | |
495 { | |
496 /* TODO: Merge this with the Linux version. This function is platform-in dependent. */ | |
497 struct hid_device_info *d = devs; | |
498 while (d) { | |
499 struct hid_device_info *next = d->next; | |
500 free(d->path); | |
501 free(d->serial_number); | |
502 free(d->manufacturer_string); | |
503 free(d->product_string); | |
504 free(d); | |
505 d = next; | |
506 } | |
507 } | |
508 | |
509 | |
510 HID_API_EXPORT hid_device * HID_API_CALL hid_open(unsigned short vendor_id, unsi gned short product_id, const wchar_t *serial_number) | |
511 { | |
512 /* TODO: Merge this functions with the Linux version. This function shou ld be platform independent. */ | |
513 struct hid_device_info *devs, *cur_dev; | |
514 const char *path_to_open = NULL; | |
515 hid_device *handle = NULL; | |
516 | |
517 devs = hid_enumerate(vendor_id, product_id); | |
518 cur_dev = devs; | |
519 while (cur_dev) { | |
520 if (cur_dev->vendor_id == vendor_id && | |
521 cur_dev->product_id == product_id) { | |
522 if (serial_number) { | |
523 if (wcscmp(serial_number, cur_dev->serial_number ) == 0) { | |
524 path_to_open = cur_dev->path; | |
525 break; | |
526 } | |
527 } | |
528 else { | |
529 path_to_open = cur_dev->path; | |
530 break; | |
531 } | |
532 } | |
533 cur_dev = cur_dev->next; | |
534 } | |
535 | |
536 if (path_to_open) { | |
537 /* Open the device */ | |
538 handle = hid_open_path(path_to_open); | |
539 } | |
540 | |
541 hid_free_enumeration(devs); | |
542 | |
543 return handle; | |
544 } | |
545 | |
546 HID_API_EXPORT hid_device * HID_API_CALL hid_open_path(const char *path) | |
547 { | |
548 hid_device *dev; | |
549 HIDP_CAPS caps; | |
550 PHIDP_PREPARSED_DATA pp_data = NULL; | |
551 BOOLEAN res; | |
552 NTSTATUS nt_res; | |
553 | |
554 if (hid_init() < 0) { | |
555 return NULL; | |
556 } | |
557 | |
558 dev = new_hid_device(); | |
559 | |
560 /* Open a handle to the device */ | |
561 dev->device_handle = open_device(path, FALSE); | |
562 | |
563 /* Check validity of write_handle. */ | |
564 if (dev->device_handle == INVALID_HANDLE_VALUE) { | |
565 /* Unable to open the device. */ | |
566 register_error(dev, "CreateFile"); | |
567 goto err; | |
568 } | |
569 | |
570 /* Get the Input Report length for the device. */ | |
571 res = HidD_GetPreparsedData(dev->device_handle, &pp_data); | |
572 if (!res) { | |
573 register_error(dev, "HidD_GetPreparsedData"); | |
574 goto err; | |
575 } | |
576 nt_res = HidP_GetCaps(pp_data, &caps); | |
577 if (nt_res != HIDP_STATUS_SUCCESS) { | |
578 register_error(dev, "HidP_GetCaps"); | |
579 goto err_pp_data; | |
580 } | |
581 dev->output_report_length = caps.OutputReportByteLength; | |
582 dev->input_report_length = caps.InputReportByteLength; | |
583 HidD_FreePreparsedData(pp_data); | |
584 | |
585 dev->read_buf = (char*) malloc(dev->input_report_length); | |
Will Harris
2014/01/14 23:40:01
check return value
| |
586 | |
587 return dev; | |
588 | |
589 err_pp_data: | |
590 HidD_FreePreparsedData(pp_data); | |
591 err: | |
592 free_hid_device(dev); | |
593 return NULL; | |
594 } | |
595 | |
596 int HID_API_EXPORT HID_API_CALL hid_write(hid_device *dev, const unsigned char * data, size_t length) | |
597 { | |
598 DWORD bytes_written; | |
599 BOOL res; | |
600 | |
601 OVERLAPPED ol; | |
602 unsigned char *buf; | |
603 memset(&ol, 0, sizeof(ol)); | |
604 | |
605 /* Make sure the right number of bytes are passed to WriteFile. Windows | |
606 expects the number of bytes which are in the _longest_ report (plus | |
607 one for the report number) bytes even if the data is a report | |
608 which is shorter than that. Windows gives us this value in | |
609 caps.OutputReportByteLength. If a user passes in fewer bytes than thi s, | |
610 create a temporary buffer which is the proper size. */ | |
611 if (length >= dev->output_report_length) { | |
612 /* The user passed the right number of bytes. Use the buffer as- is. */ | |
613 buf = (unsigned char *) data; | |
614 } else { | |
615 /* Create a temporary buffer and copy the user's data | |
616 into it, padding the rest with zeros. */ | |
617 buf = (unsigned char *) malloc(dev->output_report_length); | |
618 memcpy(buf, data, length); | |
619 memset(buf + length, 0, dev->output_report_length - length); | |
620 length = dev->output_report_length; | |
621 } | |
622 | |
623 res = WriteFile(dev->device_handle, buf, length, NULL, &ol); | |
624 | |
625 if (!res) { | |
626 if (GetLastError() != ERROR_IO_PENDING) { | |
627 /* WriteFile() failed. Return error. */ | |
628 register_error(dev, "WriteFile"); | |
629 bytes_written = -1; | |
630 goto end_of_function; | |
631 } | |
632 } | |
633 | |
634 /* Wait here until the write is done. This makes | |
635 hid_write() synchronous. */ | |
636 res = GetOverlappedResult(dev->device_handle, &ol, &bytes_written, TRUE/ *wait*/); | |
637 if (!res) { | |
638 /* The Write operation failed. */ | |
639 register_error(dev, "WriteFile"); | |
640 bytes_written = -1; | |
641 goto end_of_function; | |
642 } | |
643 | |
644 end_of_function: | |
645 if (buf != data) | |
646 free(buf); | |
647 | |
648 return bytes_written; | |
649 } | |
650 | |
651 | |
652 int HID_API_EXPORT HID_API_CALL hid_read_timeout(hid_device *dev, unsigned char *data, size_t length, int milliseconds) | |
653 { | |
654 DWORD bytes_read = 0; | |
655 BOOL res; | |
656 | |
657 /* Copy the handle for convenience. */ | |
658 HANDLE ev = dev->ol.hEvent; | |
659 | |
660 if (!dev->read_pending) { | |
661 /* Start an Overlapped I/O read. */ | |
662 dev->read_pending = TRUE; | |
663 memset(dev->read_buf, 0, dev->input_report_length); | |
664 ResetEvent(ev); | |
665 res = ReadFile(dev->device_handle, dev->read_buf, dev->input_rep ort_length, &bytes_read, &dev->ol); | |
666 | |
667 if (!res) { | |
668 if (GetLastError() != ERROR_IO_PENDING) { | |
669 /* ReadFile() has failed. | |
670 Clean up and return error. */ | |
671 CancelIo(dev->device_handle); | |
672 dev->read_pending = FALSE; | |
673 goto end_of_function; | |
674 } | |
675 } | |
676 } | |
677 | |
678 if (milliseconds >= 0) { | |
679 /* See if there is any data yet. */ | |
680 res = WaitForSingleObject(ev, milliseconds); | |
681 if (res != WAIT_OBJECT_0) { | |
682 /* There was no data this time. Return zero bytes availa ble, | |
683 but leave the Overlapped I/O running. */ | |
684 return 0; | |
685 } | |
686 } | |
687 | |
688 /* Either WaitForSingleObject() told us that ReadFile has completed, or | |
689 we are in non-blocking mode. Get the number of bytes read. The actual | |
690 data has been copied to the data[] array which was passed to ReadFile (). */ | |
691 res = GetOverlappedResult(dev->device_handle, &dev->ol, &bytes_read, TRU E/*wait*/); | |
692 | |
693 /* Set pending back to false, even if GetOverlappedResult() returned err or. */ | |
694 dev->read_pending = FALSE; | |
695 | |
696 if (res && bytes_read > 0) { | |
697 if (dev->read_buf[0] == 0x0) { | |
698 /* If report numbers aren't being used, but Windows stic ks a report | |
699 number (0x0) on the beginning of the report anyway. T o make this | |
700 work like the other platforms, and to make it work mo re like the | |
701 HID spec, we'll skip over this byte. */ | |
702 size_t copy_len; | |
703 bytes_read--; | |
704 copy_len = length > bytes_read ? bytes_read : length; | |
705 memcpy(data, dev->read_buf+1, copy_len); | |
706 } | |
707 else { | |
708 /* Copy the whole buffer, report number and all. */ | |
709 size_t copy_len = length > bytes_read ? bytes_read : len gth; | |
710 memcpy(data, dev->read_buf, copy_len); | |
711 } | |
712 } | |
713 | |
714 end_of_function: | |
715 if (!res) { | |
716 register_error(dev, "GetOverlappedResult"); | |
717 return -1; | |
718 } | |
719 | |
720 return bytes_read; | |
721 } | |
722 | |
723 int HID_API_EXPORT HID_API_CALL hid_read(hid_device *dev, unsigned char *data, s ize_t length) | |
Will Harris
2014/01/14 23:40:01
your calls from Chromeland are using the blocking
| |
724 { | |
725 return hid_read_timeout(dev, data, length, (dev->blocking)? -1: 0); | |
726 } | |
727 | |
728 int HID_API_EXPORT HID_API_CALL hid_set_nonblocking(hid_device *dev, int nonbloc k) | |
729 { | |
730 dev->blocking = !nonblock; | |
731 return 0; /* Success */ | |
732 } | |
733 | |
734 int HID_API_EXPORT HID_API_CALL hid_send_feature_report(hid_device *dev, const u nsigned char *data, size_t length) | |
735 { | |
736 BOOL res = HidD_SetFeature(dev->device_handle, (PVOID)data, length); | |
737 if (!res) { | |
738 register_error(dev, "HidD_SetFeature"); | |
739 return -1; | |
740 } | |
741 | |
742 return length; | |
743 } | |
744 | |
745 | |
746 int HID_API_EXPORT HID_API_CALL hid_get_feature_report(hid_device *dev, unsigned char *data, size_t length) | |
747 { | |
748 BOOL res; | |
749 #if 0 | |
750 res = HidD_GetFeature(dev->device_handle, data, length); | |
751 if (!res) { | |
752 register_error(dev, "HidD_GetFeature"); | |
753 return -1; | |
754 } | |
755 return 0; /* HidD_GetFeature() doesn't give us an actual length, unfortu nately */ | |
756 #else | |
757 DWORD bytes_returned; | |
758 | |
759 OVERLAPPED ol; | |
760 memset(&ol, 0, sizeof(ol)); | |
761 | |
762 res = DeviceIoControl(dev->device_handle, | |
763 IOCTL_HID_GET_FEATURE, | |
764 data, length, | |
765 data, length, | |
766 &bytes_returned, &ol); | |
767 | |
768 if (!res) { | |
769 if (GetLastError() != ERROR_IO_PENDING) { | |
770 /* DeviceIoControl() failed. Return error. */ | |
771 register_error(dev, "Send Feature Report DeviceIoControl "); | |
772 return -1; | |
773 } | |
774 } | |
775 | |
776 /* Wait here until the write is done. This makes | |
777 hid_get_feature_report() synchronous. */ | |
778 res = GetOverlappedResult(dev->device_handle, &ol, &bytes_returned, TRUE /*wait*/); | |
779 if (!res) { | |
780 /* The operation failed. */ | |
781 register_error(dev, "Send Feature Report GetOverLappedResult"); | |
782 return -1; | |
783 } | |
784 return bytes_returned; | |
785 #endif | |
786 } | |
787 | |
788 void HID_API_EXPORT HID_API_CALL hid_close(hid_device *dev) | |
789 { | |
790 if (!dev) | |
791 return; | |
792 CancelIo(dev->device_handle); | |
793 free_hid_device(dev); | |
794 } | |
795 | |
796 int HID_API_EXPORT_CALL HID_API_CALL hid_get_manufacturer_string(hid_device *dev , wchar_t *string, size_t maxlen) | |
797 { | |
798 BOOL res; | |
799 | |
800 res = HidD_GetManufacturerString(dev->device_handle, string, sizeof(wcha r_t) * maxlen); | |
801 if (!res) { | |
802 register_error(dev, "HidD_GetManufacturerString"); | |
803 return -1; | |
804 } | |
805 | |
806 return 0; | |
807 } | |
808 | |
809 int HID_API_EXPORT_CALL HID_API_CALL hid_get_product_string(hid_device *dev, wch ar_t *string, size_t maxlen) | |
810 { | |
811 BOOL res; | |
812 | |
813 res = HidD_GetProductString(dev->device_handle, string, sizeof(wchar_t) * maxlen); | |
814 if (!res) { | |
815 register_error(dev, "HidD_GetProductString"); | |
816 return -1; | |
817 } | |
818 | |
819 return 0; | |
820 } | |
821 | |
822 int HID_API_EXPORT_CALL HID_API_CALL hid_get_serial_number_string(hid_device *de v, wchar_t *string, size_t maxlen) | |
823 { | |
824 BOOL res; | |
825 | |
826 res = HidD_GetSerialNumberString(dev->device_handle, string, sizeof(wcha r_t) * maxlen); | |
827 if (!res) { | |
828 register_error(dev, "HidD_GetSerialNumberString"); | |
829 return -1; | |
830 } | |
831 | |
832 return 0; | |
833 } | |
834 | |
835 int HID_API_EXPORT_CALL HID_API_CALL hid_get_indexed_string(hid_device *dev, int string_index, wchar_t *string, size_t maxlen) | |
836 { | |
837 BOOL res; | |
838 | |
839 res = HidD_GetIndexedString(dev->device_handle, string_index, string, si zeof(wchar_t) * maxlen); | |
840 if (!res) { | |
841 register_error(dev, "HidD_GetIndexedString"); | |
842 return -1; | |
843 } | |
844 | |
845 return 0; | |
846 } | |
847 | |
848 | |
849 HID_API_EXPORT const wchar_t * HID_API_CALL hid_error(hid_device *dev) | |
850 { | |
851 return (wchar_t*)dev->last_error_str; | |
852 } | |
853 | |
854 | |
855 /*#define PICPGM*/ | |
856 /*#define S11*/ | |
857 #define P32 | |
858 #ifdef S11 | |
859 unsigned short VendorID = 0xa0a0; | |
860 unsigned short ProductID = 0x0001; | |
861 #endif | |
862 | |
863 #ifdef P32 | |
864 unsigned short VendorID = 0x04d8; | |
865 unsigned short ProductID = 0x3f; | |
866 #endif | |
867 | |
868 | |
869 #ifdef PICPGM | |
870 unsigned short VendorID = 0x04d8; | |
871 unsigned short ProductID = 0x0033; | |
872 #endif | |
873 | |
874 | |
875 #if 0 | |
876 int __cdecl main(int argc, char* argv[]) | |
Will Harris
2014/01/14 23:40:01
can this test code be removed and/or replaced with
| |
877 { | |
878 int res; | |
879 unsigned char buf[65]; | |
880 | |
881 UNREFERENCED_PARAMETER(argc); | |
882 UNREFERENCED_PARAMETER(argv); | |
883 | |
884 /* Set up the command buffer. */ | |
885 memset(buf,0x00,sizeof(buf)); | |
886 buf[0] = 0; | |
887 buf[1] = 0x81; | |
888 | |
889 | |
890 /* Open the device. */ | |
891 int handle = open(VendorID, ProductID, L"12345"); | |
892 if (handle < 0) | |
893 printf("unable to open device\n"); | |
894 | |
895 | |
896 /* Toggle LED (cmd 0x80) */ | |
897 buf[1] = 0x80; | |
898 res = write(handle, buf, 65); | |
899 if (res < 0) | |
900 printf("Unable to write()\n"); | |
901 | |
902 /* Request state (cmd 0x81) */ | |
903 buf[1] = 0x81; | |
904 write(handle, buf, 65); | |
905 if (res < 0) | |
906 printf("Unable to write() (2)\n"); | |
907 | |
908 /* Read requested state */ | |
909 read(handle, buf, 65); | |
910 if (res < 0) | |
911 printf("Unable to read()\n"); | |
912 | |
913 /* Print out the returned buffer. */ | |
914 for (int i = 0; i < 4; i++) | |
915 printf("buf[%d]: %d\n", i, buf[i]); | |
916 | |
917 return 0; | |
918 } | |
919 #endif | |
920 | |
921 #ifdef __cplusplus | |
922 } /* extern "C" */ | |
923 #endif | |
OLD | NEW |