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 https://github.com/libusb/hidapi .
21 ********************************************************/
22
23 #if defined(_MSC_VER) && !defined(_CRT_SECURE_NO_WARNINGS)
24 // Do not warn about mbsrtowcs and wcsncpy usage.
25 // https://docs.microsoft.com/cpp/c-runtime-library/security-features-in-the-crt
26 #define _CRT_SECURE_NO_WARNINGS
27 #endif
28
29 #include <windows.h>
30
31 #ifndef _NTDEF_
32 typedef LONG NTSTATUS;
33 #endif
34
35 #ifdef __MINGW32__
36 #include <ntdef.h>
37 #include <winbase.h>
38 #endif
39
40 #ifdef __CYGWIN__
41 #include <ntdef.h>
42 #define _wcsdup wcsdup
43 #endif
44
45 /* The maximum number of characters that can be passed into the
46 HidD_Get*String() functions without it failing.*/
47 #define MAX_STRING_WCHARS 0xFFF
48
49 /*#define HIDAPI_USE_DDK*/
50
51 #ifdef __cplusplus
52 extern "C" {
53 #endif
54 #include <setupapi.h>
55 #include <winioctl.h>
56 #ifdef HIDAPI_USE_DDK
57 #include <hidsdi.h>
58 #endif
59
60 /* Copied from inc/ddk/hidclass.h, part of the Windows DDK. */
61 #define HID_OUT_CTL_CODE(id) \
62 CTL_CODE(FILE_DEVICE_KEYBOARD, (id), METHOD_OUT_DIRECT, FILE_ANY_ACCESS)
63 #define IOCTL_HID_GET_FEATURE HID_OUT_CTL_CODE(100)
64 #define IOCTL_HID_GET_INPUT_REPORT HID_OUT_CTL_CODE(104)
65
66 #ifdef __cplusplus
67 } /* extern "C" */
68 #endif
69
70 #include <stdio.h>
71 #include <stdlib.h>
72 #include <string.h>
73 #include <wctype.h>
74
75 #include "hidapi.h"
76
77 #undef MIN
78 #define MIN(x,y) ((x) < (y)? (x): (y))
79
80 #ifdef __cplusplus
81 extern "C" {
82 #endif
83
84 static struct hid_api_version api_version = {
85 .major = HID_API_VERSION_MAJOR,
86 .minor = HID_API_VERSION_MINOR,
87 .patch = HID_API_VERSION_PATCH
88 };
89
90 #ifndef HIDAPI_USE_DDK
91 /* Since we're not building with the DDK, and the HID header
92 files aren't part of the SDK, we have to define all this
93 stuff here. In lookup_functions(), the function pointers
94 defined below are set. */
95 typedef struct _HIDD_ATTRIBUTES{
96 ULONG Size;
97 USHORT VendorID;
98 USHORT ProductID;
99 USHORT VersionNumber;
100 } HIDD_ATTRIBUTES, *PHIDD_ATTRIBUTES;
101
102 typedef USHORT USAGE;
103 typedef struct _HIDP_CAPS {
104 USAGE Usage;
105 USAGE UsagePage;
106 USHORT InputReportByteLength;
107 USHORT OutputReportByteLength;
108 USHORT FeatureReportByteLength;
109 USHORT Reserved[17];
110 USHORT fields_not_used_by_hidapi[10];
111 } HIDP_CAPS, *PHIDP_CAPS;
112 typedef void* PHIDP_PREPARSED_DATA;
113 #define HIDP_STATUS_SUCCESS 0x110000
114
115 typedef void (__stdcall *HidD_GetHidGuid_)(LPGUID hid_guid);
116 typedef BOOLEAN (__stdcall *HidD_GetAttributes_)(HANDLE device, PHIDD_ATTRIBUTES attrib);
117 typedef BOOLEAN (__stdcall *HidD_GetSerialNumberString_)(HANDLE device, PVOID buffer, ULONG buffer_len);
118 typedef BOOLEAN (__stdcall *HidD_GetManufacturerString_)(HANDLE handle, PVOID buffer, ULONG buffer_len);
119 typedef BOOLEAN (__stdcall *HidD_GetProductString_)(HANDLE handle, PVOID buffer, ULONG buffer_len);
120 typedef BOOLEAN (__stdcall *HidD_SetFeature_)(HANDLE handle, PVOID data, ULONG length);
121 typedef BOOLEAN (__stdcall *HidD_GetFeature_)(HANDLE handle, PVOID data, ULONG length);
122 typedef BOOLEAN (__stdcall *HidD_GetInputReport_)(HANDLE handle, PVOID data, ULONG length);
123 typedef BOOLEAN (__stdcall *HidD_GetIndexedString_)(HANDLE handle, ULONG string_index, PVOID buffer, ULONG buffer_len);
124 typedef BOOLEAN (__stdcall *HidD_GetPreparsedData_)(HANDLE handle, PHIDP_PREPARSED_DATA *preparsed_data);
125 typedef BOOLEAN (__stdcall *HidD_FreePreparsedData_)(PHIDP_PREPARSED_DATA preparsed_data);
126 typedef NTSTATUS (__stdcall *HidP_GetCaps_)(PHIDP_PREPARSED_DATA preparsed_data, HIDP_CAPS *caps);
127 typedef BOOLEAN (__stdcall *HidD_SetNumInputBuffers_)(HANDLE handle, ULONG number_buffers);
128
129 static HidD_GetHidGuid_ HidD_GetHidGuid;
130 static HidD_GetAttributes_ HidD_GetAttributes;
131 static HidD_GetSerialNumberString_ HidD_GetSerialNumberString;
132 static HidD_GetManufacturerString_ HidD_GetManufacturerString;
133 static HidD_GetProductString_ HidD_GetProductString;
134 static HidD_SetFeature_ HidD_SetFeature;
135 static HidD_GetFeature_ HidD_GetFeature;
136 static HidD_GetInputReport_ HidD_GetInputReport;
137 static HidD_GetIndexedString_ HidD_GetIndexedString;
138 static HidD_GetPreparsedData_ HidD_GetPreparsedData;
139 static HidD_FreePreparsedData_ HidD_FreePreparsedData;
140 static HidP_GetCaps_ HidP_GetCaps;
141 static HidD_SetNumInputBuffers_ HidD_SetNumInputBuffers;
142
143 static HMODULE lib_handle = NULL;
144 static BOOLEAN initialized = FALSE;
145
146 typedef DWORD RETURN_TYPE;
147 typedef RETURN_TYPE CONFIGRET;
148 typedef DWORD DEVNODE, DEVINST;
149 typedef DEVNODE* PDEVNODE, * PDEVINST;
150 typedef WCHAR* DEVNODEID_W, * DEVINSTID_W;
151
152 #define CR_SUCCESS (0x00000000)
153 #define CR_BUFFER_SMALL (0x0000001A)
154
155 #define CM_LOCATE_DEVNODE_NORMAL 0x00000000
156
157 #define DEVPROP_TYPEMOD_LIST 0x00002000
158
159 #define DEVPROP_TYPE_STRING 0x00000012
160 #define DEVPROP_TYPE_STRING_LIST (DEVPROP_TYPE_STRING|DEVPROP_TYPEMOD_LIST)
161
162 typedef CONFIGRET(__stdcall* CM_Locate_DevNodeW_)(PDEVINST pdnDevInst, DEVINSTID_W pDeviceID, ULONG ulFlags);
163 typedef CONFIGRET(__stdcall* CM_Get_Parent_)(PDEVINST pdnDevInst, DEVINST dnDevInst, ULONG ulFlags);
164 typedef CONFIGRET(__stdcall* CM_Get_DevNode_PropertyW_)(DEVINST dnDevInst, CONST DEVPROPKEY* PropertyKey, DEVPROPTYPE* PropertyType, PBYTE PropertyBuffer, PULONG PropertyBufferSize, ULONG ulFlags);
165 typedef CONFIGRET(__stdcall* CM_Get_Device_Interface_PropertyW_)(LPCWSTR pszDeviceInterface, CONST DEVPROPKEY* PropertyKey, DEVPROPTYPE* PropertyType, PBYTE PropertyBuffer, PULONG PropertyBufferSize, ULONG ulFlags);
166
167 static CM_Locate_DevNodeW_ CM_Locate_DevNodeW = NULL;
168 static CM_Get_Parent_ CM_Get_Parent = NULL;
169 static CM_Get_DevNode_PropertyW_ CM_Get_DevNode_PropertyW = NULL;
170 static CM_Get_Device_Interface_PropertyW_ CM_Get_Device_Interface_PropertyW = NULL;
171
172 static HMODULE cfgmgr32_lib_handle = NULL;
173 #endif /* HIDAPI_USE_DDK */
174
175 struct hid_device_ {
176 HANDLE device_handle;
177 BOOL blocking;
178 USHORT output_report_length;
179 unsigned char *write_buf;
180 size_t input_report_length;
181 USHORT feature_report_length;
182 unsigned char *feature_buf;
183 void *last_error_str;
184 DWORD last_error_num;
185 BOOL read_pending;
186 char *read_buf;
187 OVERLAPPED ol;
188 OVERLAPPED write_ol;
189 struct hid_device_info* device_info;
190 };
191
new_hid_device()192 static hid_device *new_hid_device()
193 {
194 hid_device *dev = (hid_device*) calloc(1, sizeof(hid_device));
195 dev->device_handle = INVALID_HANDLE_VALUE;
196 dev->blocking = TRUE;
197 dev->output_report_length = 0;
198 dev->write_buf = NULL;
199 dev->input_report_length = 0;
200 dev->feature_report_length = 0;
201 dev->feature_buf = NULL;
202 dev->last_error_str = NULL;
203 dev->last_error_num = 0;
204 dev->read_pending = FALSE;
205 dev->read_buf = NULL;
206 memset(&dev->ol, 0, sizeof(dev->ol));
207 dev->ol.hEvent = CreateEvent(NULL, FALSE, FALSE /*initial state f=nonsignaled*/, NULL);
208 memset(&dev->write_ol, 0, sizeof(dev->write_ol));
209 dev->write_ol.hEvent = CreateEvent(NULL, FALSE, FALSE /*inital state f=nonsignaled*/, NULL);
210 dev->device_info = NULL;
211
212 return dev;
213 }
214
free_hid_device(hid_device * dev)215 static void free_hid_device(hid_device *dev)
216 {
217 CloseHandle(dev->ol.hEvent);
218 CloseHandle(dev->write_ol.hEvent);
219 CloseHandle(dev->device_handle);
220 LocalFree(dev->last_error_str);
221 free(dev->write_buf);
222 free(dev->feature_buf);
223 free(dev->read_buf);
224 free(dev->device_info);
225 free(dev);
226 }
227
register_error(hid_device * dev,const char * op)228 static void register_error(hid_device *dev, const char *op)
229 {
230 WCHAR *ptr, *msg;
231 (void)op; // unreferenced param
232 FormatMessageW(FORMAT_MESSAGE_ALLOCATE_BUFFER |
233 FORMAT_MESSAGE_FROM_SYSTEM |
234 FORMAT_MESSAGE_IGNORE_INSERTS,
235 NULL,
236 GetLastError(),
237 MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
238 (LPWSTR)&msg, 0/*sz*/,
239 NULL);
240
241 /* Get rid of the CR and LF that FormatMessage() sticks at the
242 end of the message. Thanks Microsoft! */
243 ptr = msg;
244 while (*ptr) {
245 if (*ptr == L'\r') {
246 *ptr = L'\0';
247 break;
248 }
249 ptr++;
250 }
251
252 /* Store the message off in the Device entry so that
253 the hid_error() function can pick it up. */
254 LocalFree(dev->last_error_str);
255 dev->last_error_str = msg;
256 }
257
258 #ifndef HIDAPI_USE_DDK
lookup_functions()259 static int lookup_functions()
260 {
261 lib_handle = LoadLibraryA("hid.dll");
262 if (lib_handle) {
263 #if defined(__GNUC__)
264 # pragma GCC diagnostic push
265 # pragma GCC diagnostic ignored "-Wcast-function-type"
266 #endif
267 #define RESOLVE(x) x = (x##_)GetProcAddress(lib_handle, #x); if (!x) return -1;
268 RESOLVE(HidD_GetHidGuid);
269 RESOLVE(HidD_GetAttributes);
270 RESOLVE(HidD_GetSerialNumberString);
271 RESOLVE(HidD_GetManufacturerString);
272 RESOLVE(HidD_GetProductString);
273 RESOLVE(HidD_SetFeature);
274 RESOLVE(HidD_GetFeature);
275 RESOLVE(HidD_GetInputReport);
276 RESOLVE(HidD_GetIndexedString);
277 RESOLVE(HidD_GetPreparsedData);
278 RESOLVE(HidD_FreePreparsedData);
279 RESOLVE(HidP_GetCaps);
280 RESOLVE(HidD_SetNumInputBuffers);
281 #undef RESOLVE
282 #if defined(__GNUC__)
283 # pragma GCC diagnostic pop
284 #endif
285 }
286 else
287 return -1;
288
289 cfgmgr32_lib_handle = LoadLibraryA("cfgmgr32.dll");
290 if (cfgmgr32_lib_handle) {
291 #if defined(__GNUC__)
292 # pragma GCC diagnostic push
293 # pragma GCC diagnostic ignored "-Wcast-function-type"
294 #endif
295 #define RESOLVE(x) x = (x##_)GetProcAddress(cfgmgr32_lib_handle, #x);
296 RESOLVE(CM_Locate_DevNodeW);
297 RESOLVE(CM_Get_Parent);
298 RESOLVE(CM_Get_DevNode_PropertyW);
299 RESOLVE(CM_Get_Device_Interface_PropertyW);
300 #undef RESOLVE
301 #if defined(__GNUC__)
302 # pragma GCC diagnostic pop
303 #endif
304 }
305 else {
306 CM_Locate_DevNodeW = NULL;
307 CM_Get_Parent = NULL;
308 CM_Get_DevNode_PropertyW = NULL;
309 CM_Get_Device_Interface_PropertyW = NULL;
310 }
311
312 return 0;
313 }
314 #endif
315
open_device(const char * path,BOOL open_rw)316 static HANDLE open_device(const char *path, BOOL open_rw)
317 {
318 HANDLE handle;
319 DWORD desired_access = (open_rw)? (GENERIC_WRITE | GENERIC_READ): 0;
320 DWORD share_mode = FILE_SHARE_READ|FILE_SHARE_WRITE;
321
322 handle = CreateFileA(path,
323 desired_access,
324 share_mode,
325 NULL,
326 OPEN_EXISTING,
327 FILE_FLAG_OVERLAPPED,/*FILE_ATTRIBUTE_NORMAL,*/
328 0);
329
330 return handle;
331 }
332
hid_version()333 HID_API_EXPORT const struct hid_api_version* HID_API_CALL hid_version()
334 {
335 return &api_version;
336 }
337
hid_version_str()338 HID_API_EXPORT const char* HID_API_CALL hid_version_str()
339 {
340 return HID_API_VERSION_STR;
341 }
342
hid_init(void)343 int HID_API_EXPORT hid_init(void)
344 {
345 #ifndef HIDAPI_USE_DDK
346 if (!initialized) {
347 if (lookup_functions() < 0) {
348 hid_exit();
349 return -1;
350 }
351 initialized = TRUE;
352 }
353 #endif
354 return 0;
355 }
356
hid_exit(void)357 int HID_API_EXPORT hid_exit(void)
358 {
359 #ifndef HIDAPI_USE_DDK
360 if (lib_handle)
361 FreeLibrary(lib_handle);
362 lib_handle = NULL;
363 if (cfgmgr32_lib_handle)
364 FreeLibrary(cfgmgr32_lib_handle);
365 cfgmgr32_lib_handle = NULL;
366 initialized = FALSE;
367 #endif
368 return 0;
369 }
370
hid_internal_get_ble_info(struct hid_device_info * dev,DEVINST dev_node)371 static void hid_internal_get_ble_info(struct hid_device_info* dev, DEVINST dev_node)
372 {
373 ULONG len;
374 CONFIGRET cr;
375 DEVPROPTYPE property_type;
376
377 static DEVPROPKEY DEVPKEY_NAME = { { 0xb725f130, 0x47ef, 0x101a, 0xa5, 0xf1, 0x02, 0x60, 0x8c, 0x9e, 0xeb, 0xac }, 10 }; // DEVPROP_TYPE_STRING
378 static DEVPROPKEY PKEY_DeviceInterface_Bluetooth_DeviceAddress = { { 0x2BD67D8B, 0x8BEB, 0x48D5, 0x87, 0xE0, 0x6C, 0xDA, 0x34, 0x28, 0x04, 0x0A }, 1 }; // DEVPROP_TYPE_STRING
379 static DEVPROPKEY PKEY_DeviceInterface_Bluetooth_Manufacturer = { { 0x2BD67D8B, 0x8BEB, 0x48D5, 0x87, 0xE0, 0x6C, 0xDA, 0x34, 0x28, 0x04, 0x0A }, 4 }; // DEVPROP_TYPE_STRING
380
381 /* Manufacturer String */
382 len = 0;
383 cr = CM_Get_DevNode_PropertyW(dev_node, &PKEY_DeviceInterface_Bluetooth_Manufacturer, &property_type, NULL, &len, 0);
384 if (cr == CR_BUFFER_SMALL && property_type == DEVPROP_TYPE_STRING) {
385 free(dev->manufacturer_string);
386 dev->manufacturer_string = (wchar_t*)calloc(len, sizeof(BYTE));
387 CM_Get_DevNode_PropertyW(dev_node, &PKEY_DeviceInterface_Bluetooth_Manufacturer, &property_type, (PBYTE)dev->manufacturer_string, &len, 0);
388 }
389
390 /* Serial Number String (MAC Address) */
391 len = 0;
392 cr = CM_Get_DevNode_PropertyW(dev_node, &PKEY_DeviceInterface_Bluetooth_DeviceAddress, &property_type, NULL, &len, 0);
393 if (cr == CR_BUFFER_SMALL && property_type == DEVPROP_TYPE_STRING) {
394 free(dev->serial_number);
395 dev->serial_number = (wchar_t*)calloc(len, sizeof(BYTE));
396 CM_Get_DevNode_PropertyW(dev_node, &PKEY_DeviceInterface_Bluetooth_DeviceAddress, &property_type, (PBYTE)dev->serial_number, &len, 0);
397 }
398
399 /* Get devnode grandparent to reach out Bluetooth LE device node */
400 cr = CM_Get_Parent(&dev_node, dev_node, 0);
401 if (cr != CR_SUCCESS)
402 return;
403
404 /* Product String */
405 len = 0;
406 cr = CM_Get_DevNode_PropertyW(dev_node, &DEVPKEY_NAME, &property_type, NULL, &len, 0);
407 if (cr == CR_BUFFER_SMALL && property_type == DEVPROP_TYPE_STRING) {
408 free(dev->product_string);
409 dev->product_string = (wchar_t*)calloc(len, sizeof(BYTE));
410 CM_Get_DevNode_PropertyW(dev_node, &DEVPKEY_NAME, &property_type, (PBYTE)dev->product_string, &len, 0);
411 }
412 }
413
hid_internal_get_info(struct hid_device_info * dev)414 static void hid_internal_get_info(struct hid_device_info* dev)
415 {
416 const char *tmp = NULL;
417 wchar_t *interface_path = NULL, *device_id = NULL, *compatible_ids = NULL;
418 mbstate_t state;
419 ULONG len;
420 CONFIGRET cr;
421 DEVPROPTYPE property_type;
422 DEVINST dev_node;
423
424 static DEVPROPKEY DEVPKEY_Device_InstanceId = { { 0x78c34fc8, 0x104a, 0x4aca, 0x9e, 0xa4, 0x52, 0x4d, 0x52, 0x99, 0x6e, 0x57 }, 256 }; // DEVPROP_TYPE_STRING
425 static DEVPROPKEY DEVPKEY_Device_CompatibleIds = { { 0xa45c254e, 0xdf1c, 0x4efd, 0x80, 0x20, 0x67, 0xd1, 0x46, 0xa8, 0x50, 0xe0}, 4 }; // DEVPROP_TYPE_STRING_LIST
426
427 if (!CM_Get_Device_Interface_PropertyW ||
428 !CM_Locate_DevNodeW ||
429 !CM_Get_Parent ||
430 !CM_Get_DevNode_PropertyW)
431 goto end;
432
433 tmp = dev->path;
434
435 len = (ULONG)strlen(tmp);
436 interface_path = (wchar_t*)calloc(len + 1, sizeof(wchar_t));
437 memset(&state, 0, sizeof(state));
438
439 if (mbsrtowcs(interface_path, &tmp, len, &state) == (size_t)-1)
440 goto end;
441
442 /* Get the device id from interface path */
443 len = 0;
444 cr = CM_Get_Device_Interface_PropertyW(interface_path, &DEVPKEY_Device_InstanceId, &property_type, NULL, &len, 0);
445 if (cr == CR_BUFFER_SMALL && property_type == DEVPROP_TYPE_STRING) {
446 device_id = (wchar_t*)calloc(len, sizeof(BYTE));
447 cr = CM_Get_Device_Interface_PropertyW(interface_path, &DEVPKEY_Device_InstanceId, &property_type, (PBYTE)device_id, &len, 0);
448 }
449 if (cr != CR_SUCCESS)
450 goto end;
451
452 /* Open devnode from device id */
453 cr = CM_Locate_DevNodeW(&dev_node, (DEVINSTID_W)device_id, CM_LOCATE_DEVNODE_NORMAL);
454 if (cr != CR_SUCCESS)
455 goto end;
456
457 /* Get devnode parent */
458 cr = CM_Get_Parent(&dev_node, dev_node, 0);
459 if (cr != CR_SUCCESS)
460 goto end;
461
462 /* Get the compatible ids from parent devnode */
463 len = 0;
464 cr = CM_Get_DevNode_PropertyW(dev_node, &DEVPKEY_Device_CompatibleIds, &property_type, NULL, &len, 0);
465 if (cr == CR_BUFFER_SMALL && property_type == DEVPROP_TYPE_STRING_LIST) {
466 compatible_ids = (wchar_t*)calloc(len, sizeof(BYTE));
467 cr = CM_Get_DevNode_PropertyW(dev_node, &DEVPKEY_Device_CompatibleIds, &property_type, (PBYTE)compatible_ids, &len, 0);
468 }
469 if (cr != CR_SUCCESS)
470 goto end;
471
472 /* Now we can parse parent's compatible IDs to find out the device bus type */
473 for (wchar_t* compatible_id = compatible_ids; *compatible_id; compatible_id += wcslen(compatible_id) + 1) {
474 /* Normalize to upper case */
475 for (wchar_t* p = compatible_id; *p; ++p) *p = towupper(*p);
476
477 /* Bluetooth LE devices */
478 if (wcsstr(compatible_id, L"BTHLEDEVICE") != NULL) {
479 /* HidD_GetProductString/HidD_GetManufacturerString/HidD_GetSerialNumberString is not working for BLE HID devices
480 Request this info via dev node properties instead.
481 https://docs.microsoft.com/answers/questions/401236/hidd-getproductstring-with-ble-hid-device.html */
482 hid_internal_get_ble_info(dev, dev_node);
483 break;
484 }
485 }
486 end:
487 free(interface_path);
488 free(device_id);
489 free(compatible_ids);
490 }
491
hid_get_device_info(const char * path,HANDLE handle)492 static struct hid_device_info *hid_get_device_info(const char *path, HANDLE handle)
493 {
494 struct hid_device_info *dev = NULL; /* return object */
495
496 BOOL res;
497 HIDD_ATTRIBUTES attrib;
498 PHIDP_PREPARSED_DATA pp_data = NULL;
499 HIDP_CAPS caps;
500
501 #define WSTR_LEN 512
502 wchar_t wstr[WSTR_LEN]; /* TODO: Determine Size */
503
504 /* Create the record. */
505 dev = (struct hid_device_info*)calloc(1, sizeof(struct hid_device_info));
506
507 /* Fill out the record */
508 dev->next = NULL;
509
510 if (path) {
511 size_t len = strlen(path);
512 dev->path = (char*)calloc(len + 1, sizeof(char));
513 memcpy(dev->path, path, len + 1);
514 }
515 else
516 dev->path = NULL;
517
518 attrib.Size = sizeof(HIDD_ATTRIBUTES);
519 res = HidD_GetAttributes(handle, &attrib);
520 if (res) {
521 /* VID/PID */
522 dev->vendor_id = attrib.VendorID;
523 dev->product_id = attrib.ProductID;
524
525 /* Release Number */
526 dev->release_number = attrib.VersionNumber;
527 }
528
529 /* Get the Usage Page and Usage for this device. */
530 res = HidD_GetPreparsedData(handle, &pp_data);
531 if (res) {
532 NTSTATUS nt_res = HidP_GetCaps(pp_data, &caps);
533 if (nt_res == HIDP_STATUS_SUCCESS) {
534 dev->usage_page = caps.UsagePage;
535 dev->usage = caps.Usage;
536 }
537
538 HidD_FreePreparsedData(pp_data);
539 }
540
541 /* Serial Number */
542 wstr[0] = L'\0';
543 res = HidD_GetSerialNumberString(handle, wstr, sizeof(wstr));
544 wstr[WSTR_LEN - 1] = L'\0';
545 dev->serial_number = _wcsdup(wstr);
546
547 /* Manufacturer String */
548 wstr[0] = L'\0';
549 res = HidD_GetManufacturerString(handle, wstr, sizeof(wstr));
550 wstr[WSTR_LEN - 1] = L'\0';
551 dev->manufacturer_string = _wcsdup(wstr);
552
553 /* Product String */
554 wstr[0] = L'\0';
555 res = HidD_GetProductString(handle, wstr, sizeof(wstr));
556 wstr[WSTR_LEN - 1] = L'\0';
557 dev->product_string = _wcsdup(wstr);
558
559 /* Interface Number. It can sometimes be parsed out of the path
560 on Windows if a device has multiple interfaces. See
561 https://docs.microsoft.com/windows-hardware/drivers/hid/hidclass-hardware-ids-for-top-level-collections
562 or search for "HIDClass Hardware IDs for Top-Level Collections" at Microsoft Docs. If it's not
563 in the path, it's set to -1. */
564 dev->interface_number = -1;
565 if (dev->path) {
566 char* interface_component = strstr(dev->path, "&mi_");
567 if (interface_component) {
568 char* hex_str = interface_component + 4;
569 char* endptr = NULL;
570 dev->interface_number = strtol(hex_str, &endptr, 16);
571 if (endptr == hex_str) {
572 /* The parsing failed. Set interface_number to -1. */
573 dev->interface_number = -1;
574 }
575 }
576 }
577
578 hid_internal_get_info(dev);
579
580 return dev;
581 }
582
hid_enumerate(unsigned short vendor_id,unsigned short product_id)583 struct hid_device_info HID_API_EXPORT * HID_API_CALL hid_enumerate(unsigned short vendor_id, unsigned short product_id)
584 {
585 BOOL res;
586 struct hid_device_info *root = NULL; /* return object */
587 struct hid_device_info *cur_dev = NULL;
588 GUID interface_class_guid;
589
590 /* Windows objects for interacting with the driver. */
591 SP_DEVINFO_DATA devinfo_data;
592 SP_DEVICE_INTERFACE_DATA device_interface_data;
593 SP_DEVICE_INTERFACE_DETAIL_DATA_A *device_interface_detail_data = NULL;
594 HDEVINFO device_info_set = INVALID_HANDLE_VALUE;
595 char driver_name[256];
596 int device_index = 0;
597
598 if (hid_init() < 0)
599 return NULL;
600
601 /* Retrieve HID Interface Class GUID
602 https://docs.microsoft.com/windows-hardware/drivers/install/guid-devinterface-hid */
603 HidD_GetHidGuid(&interface_class_guid);
604
605 /* Initialize the Windows objects. */
606 memset(&devinfo_data, 0x0, sizeof(devinfo_data));
607 devinfo_data.cbSize = sizeof(SP_DEVINFO_DATA);
608 device_interface_data.cbSize = sizeof(SP_DEVICE_INTERFACE_DATA);
609
610 /* Get information for all the devices belonging to the HID class. */
611 device_info_set = SetupDiGetClassDevsA(&interface_class_guid, NULL, NULL, DIGCF_PRESENT | DIGCF_DEVICEINTERFACE);
612
613 /* Iterate over each device in the HID class, looking for the right one. */
614
615 for (;;) {
616 HANDLE read_handle = INVALID_HANDLE_VALUE;
617 DWORD required_size = 0;
618 HIDD_ATTRIBUTES attrib;
619
620 res = SetupDiEnumDeviceInterfaces(device_info_set,
621 NULL,
622 &interface_class_guid,
623 device_index,
624 &device_interface_data);
625
626 if (!res) {
627 /* A return of FALSE from this function means that
628 there are no more devices. */
629 break;
630 }
631
632 /* Call with 0-sized detail size, and let the function
633 tell us how long the detail struct needs to be. The
634 size is put in &required_size. */
635 res = SetupDiGetDeviceInterfaceDetailA(device_info_set,
636 &device_interface_data,
637 NULL,
638 0,
639 &required_size,
640 NULL);
641
642 /* Allocate a long enough structure for device_interface_detail_data. */
643 device_interface_detail_data = (SP_DEVICE_INTERFACE_DETAIL_DATA_A*) malloc(required_size);
644 device_interface_detail_data->cbSize = sizeof(SP_DEVICE_INTERFACE_DETAIL_DATA_A);
645
646 /* Get the detailed data for this device. The detail data gives us
647 the device path for this device, which is then passed into
648 CreateFile() to get a handle to the device. */
649 res = SetupDiGetDeviceInterfaceDetailA(device_info_set,
650 &device_interface_data,
651 device_interface_detail_data,
652 required_size,
653 NULL,
654 NULL);
655
656 if (!res) {
657 /* register_error(dev, "Unable to call SetupDiGetDeviceInterfaceDetail");
658 Continue to the next device. */
659 goto cont;
660 }
661
662 /* Populate devinfo_data. This function will return failure
663 when the device with such index doesn't exist. We've already checked it does. */
664 res = SetupDiEnumDeviceInfo(device_info_set, device_index, &devinfo_data);
665 if (!res)
666 goto cont;
667
668
669 /* Make sure this device has a driver bound to it. */
670 res = SetupDiGetDeviceRegistryPropertyA(device_info_set, &devinfo_data,
671 SPDRP_DRIVER, NULL, (PBYTE)driver_name, sizeof(driver_name), NULL);
672 if (!res)
673 goto cont;
674
675 //wprintf(L"HandleName: %s\n", device_interface_detail_data->DevicePath);
676
677 /* Open read-only handle to the device */
678 read_handle = open_device(device_interface_detail_data->DevicePath, FALSE);
679
680 /* Check validity of read_handle. */
681 if (read_handle == INVALID_HANDLE_VALUE) {
682 /* Unable to open the device. */
683 //register_error(dev, "CreateFile");
684 goto cont;
685 }
686
687 /* Get the Vendor ID and Product ID for this device. */
688 attrib.Size = sizeof(HIDD_ATTRIBUTES);
689 HidD_GetAttributes(read_handle, &attrib);
690 //wprintf(L"Product/Vendor: %x %x\n", attrib.ProductID, attrib.VendorID);
691
692 /* Check the VID/PID to see if we should add this
693 device to the enumeration list. */
694 if ((vendor_id == 0x0 || attrib.VendorID == vendor_id) &&
695 (product_id == 0x0 || attrib.ProductID == product_id)) {
696
697 /* VID/PID match. Create the record. */
698 struct hid_device_info *tmp = hid_get_device_info(device_interface_detail_data->DevicePath, read_handle);
699
700 if (tmp == NULL) {
701 goto cont_close;
702 }
703
704 if (cur_dev) {
705 cur_dev->next = tmp;
706 }
707 else {
708 root = tmp;
709 }
710 cur_dev = tmp;
711 }
712
713 cont_close:
714 CloseHandle(read_handle);
715 cont:
716 /* We no longer need the detail data. It can be freed */
717 free(device_interface_detail_data);
718
719 device_index++;
720
721 }
722
723 /* Close the device information handle. */
724 SetupDiDestroyDeviceInfoList(device_info_set);
725
726 return root;
727 }
728
hid_free_enumeration(struct hid_device_info * devs)729 void HID_API_EXPORT HID_API_CALL hid_free_enumeration(struct hid_device_info *devs)
730 {
731 /* TODO: Merge this with the Linux version. This function is platform-independent. */
732 struct hid_device_info *d = devs;
733 while (d) {
734 struct hid_device_info *next = d->next;
735 free(d->path);
736 free(d->serial_number);
737 free(d->manufacturer_string);
738 free(d->product_string);
739 free(d);
740 d = next;
741 }
742 }
743
744
hid_open(unsigned short vendor_id,unsigned short product_id,const wchar_t * serial_number)745 HID_API_EXPORT hid_device * HID_API_CALL hid_open(unsigned short vendor_id, unsigned short product_id, const wchar_t *serial_number)
746 {
747 /* TODO: Merge this functions with the Linux version. This function should be platform independent. */
748 struct hid_device_info *devs, *cur_dev;
749 const char *path_to_open = NULL;
750 hid_device *handle = NULL;
751
752 devs = hid_enumerate(vendor_id, product_id);
753 cur_dev = devs;
754 while (cur_dev) {
755 if (cur_dev->vendor_id == vendor_id &&
756 cur_dev->product_id == product_id) {
757 if (serial_number) {
758 if (cur_dev->serial_number && wcscmp(serial_number, cur_dev->serial_number) == 0) {
759 path_to_open = cur_dev->path;
760 break;
761 }
762 }
763 else {
764 path_to_open = cur_dev->path;
765 break;
766 }
767 }
768 cur_dev = cur_dev->next;
769 }
770
771 if (path_to_open) {
772 /* Open the device */
773 handle = hid_open_path(path_to_open);
774 }
775
776 hid_free_enumeration(devs);
777
778 return handle;
779 }
780
hid_open_path(const char * path)781 HID_API_EXPORT hid_device * HID_API_CALL hid_open_path(const char *path)
782 {
783 hid_device *dev;
784 HIDP_CAPS caps;
785 PHIDP_PREPARSED_DATA pp_data = NULL;
786 BOOLEAN res;
787 NTSTATUS nt_res;
788
789 if (hid_init() < 0) {
790 return NULL;
791 }
792
793 dev = new_hid_device();
794
795 /* Open a handle to the device */
796 dev->device_handle = open_device(path, TRUE);
797
798 /* Check validity of write_handle. */
799 if (dev->device_handle == INVALID_HANDLE_VALUE) {
800 /* System devices, such as keyboards and mice, cannot be opened in
801 read-write mode, because the system takes exclusive control over
802 them. This is to prevent keyloggers. However, feature reports
803 can still be sent and received. Retry opening the device, but
804 without read/write access. */
805 dev->device_handle = open_device(path, FALSE);
806
807 /* Check the validity of the limited device_handle. */
808 if (dev->device_handle == INVALID_HANDLE_VALUE) {
809 /* Unable to open the device, even without read-write mode. */
810 register_error(dev, "CreateFile");
811 goto err;
812 }
813 }
814
815 /* Set the Input Report buffer size to 64 reports. */
816 res = HidD_SetNumInputBuffers(dev->device_handle, 64);
817 if (!res) {
818 register_error(dev, "HidD_SetNumInputBuffers");
819 goto err;
820 }
821
822 /* Get the Input Report length for the device. */
823 res = HidD_GetPreparsedData(dev->device_handle, &pp_data);
824 if (!res) {
825 register_error(dev, "HidD_GetPreparsedData");
826 goto err;
827 }
828 nt_res = HidP_GetCaps(pp_data, &caps);
829 if (nt_res != HIDP_STATUS_SUCCESS) {
830 register_error(dev, "HidP_GetCaps");
831 goto err_pp_data;
832 }
833 dev->output_report_length = caps.OutputReportByteLength;
834 dev->input_report_length = caps.InputReportByteLength;
835 dev->feature_report_length = caps.FeatureReportByteLength;
836 HidD_FreePreparsedData(pp_data);
837
838 dev->read_buf = (char*) malloc(dev->input_report_length);
839
840 dev->device_info = hid_get_device_info(path, dev->device_handle);
841
842 return dev;
843
844 err_pp_data:
845 HidD_FreePreparsedData(pp_data);
846 err:
847 free_hid_device(dev);
848 return NULL;
849 }
850
hid_write(hid_device * dev,const unsigned char * data,size_t length)851 int HID_API_EXPORT HID_API_CALL hid_write(hid_device *dev, const unsigned char *data, size_t length)
852 {
853 DWORD bytes_written = 0;
854 int function_result = -1;
855 BOOL res;
856 BOOL overlapped = FALSE;
857
858 unsigned char *buf;
859
860 if (!data || (length==0)) {
861 register_error(dev, "Zero length buffer");
862 return function_result;
863 }
864
865 /* Make sure the right number of bytes are passed to WriteFile. Windows
866 expects the number of bytes which are in the _longest_ report (plus
867 one for the report number) bytes even if the data is a report
868 which is shorter than that. Windows gives us this value in
869 caps.OutputReportByteLength. If a user passes in fewer bytes than this,
870 use cached temporary buffer which is the proper size. */
871 if (length >= dev->output_report_length) {
872 /* The user passed the right number of bytes. Use the buffer as-is. */
873 buf = (unsigned char *) data;
874 } else {
875 if (dev->write_buf == NULL)
876 dev->write_buf = (unsigned char *) malloc(dev->output_report_length);
877 buf = dev->write_buf;
878 memcpy(buf, data, length);
879 memset(buf + length, 0, dev->output_report_length - length);
880 length = dev->output_report_length;
881 }
882
883 res = WriteFile(dev->device_handle, buf, (DWORD) length, NULL, &dev->write_ol);
884
885 if (!res) {
886 if (GetLastError() != ERROR_IO_PENDING) {
887 /* WriteFile() failed. Return error. */
888 register_error(dev, "WriteFile");
889 goto end_of_function;
890 }
891 overlapped = TRUE;
892 }
893
894 if (overlapped) {
895 /* Wait for the transaction to complete. This makes
896 hid_write() synchronous. */
897 res = WaitForSingleObject(dev->write_ol.hEvent, 1000);
898 if (res != WAIT_OBJECT_0) {
899 /* There was a Timeout. */
900 register_error(dev, "WriteFile/WaitForSingleObject Timeout");
901 goto end_of_function;
902 }
903
904 /* Get the result. */
905 res = GetOverlappedResult(dev->device_handle, &dev->write_ol, &bytes_written, FALSE/*wait*/);
906 if (res) {
907 function_result = bytes_written;
908 }
909 else {
910 /* The Write operation failed. */
911 register_error(dev, "WriteFile");
912 goto end_of_function;
913 }
914 }
915
916 end_of_function:
917 return function_result;
918 }
919
920
hid_read_timeout(hid_device * dev,unsigned char * data,size_t length,int milliseconds)921 int HID_API_EXPORT HID_API_CALL hid_read_timeout(hid_device *dev, unsigned char *data, size_t length, int milliseconds)
922 {
923 DWORD bytes_read = 0;
924 size_t copy_len = 0;
925 BOOL res = FALSE;
926 BOOL overlapped = FALSE;
927
928 /* Copy the handle for convenience. */
929 HANDLE ev = dev->ol.hEvent;
930
931 if (!dev->read_pending) {
932 /* Start an Overlapped I/O read. */
933 dev->read_pending = TRUE;
934 memset(dev->read_buf, 0, dev->input_report_length);
935 ResetEvent(ev);
936 res = ReadFile(dev->device_handle, dev->read_buf, (DWORD) dev->input_report_length, &bytes_read, &dev->ol);
937
938 if (!res) {
939 if (GetLastError() != ERROR_IO_PENDING) {
940 /* ReadFile() has failed.
941 Clean up and return error. */
942 CancelIo(dev->device_handle);
943 dev->read_pending = FALSE;
944 goto end_of_function;
945 }
946 overlapped = TRUE;
947 }
948 }
949 else {
950 overlapped = TRUE;
951 }
952
953 if (overlapped) {
954 if (milliseconds >= 0) {
955 /* See if there is any data yet. */
956 res = WaitForSingleObject(ev, milliseconds);
957 if (res != WAIT_OBJECT_0) {
958 /* There was no data this time. Return zero bytes available,
959 but leave the Overlapped I/O running. */
960 return 0;
961 }
962 }
963
964 /* Either WaitForSingleObject() told us that ReadFile has completed, or
965 we are in non-blocking mode. Get the number of bytes read. The actual
966 data has been copied to the data[] array which was passed to ReadFile(). */
967 res = GetOverlappedResult(dev->device_handle, &dev->ol, &bytes_read, TRUE/*wait*/);
968 }
969 /* Set pending back to false, even if GetOverlappedResult() returned error. */
970 dev->read_pending = FALSE;
971
972 if (res && bytes_read > 0) {
973 if (dev->read_buf[0] == 0x0) {
974 /* If report numbers aren't being used, but Windows sticks a report
975 number (0x0) on the beginning of the report anyway. To make this
976 work like the other platforms, and to make it work more like the
977 HID spec, we'll skip over this byte. */
978 bytes_read--;
979 copy_len = length > bytes_read ? bytes_read : length;
980 memcpy(data, dev->read_buf+1, copy_len);
981 }
982 else {
983 /* Copy the whole buffer, report number and all. */
984 copy_len = length > bytes_read ? bytes_read : length;
985 memcpy(data, dev->read_buf, copy_len);
986 }
987 }
988
989 end_of_function:
990 if (!res) {
991 register_error(dev, "GetOverlappedResult");
992 return -1;
993 }
994
995 return (int) copy_len;
996 }
997
hid_read(hid_device * dev,unsigned char * data,size_t length)998 int HID_API_EXPORT HID_API_CALL hid_read(hid_device *dev, unsigned char *data, size_t length)
999 {
1000 return hid_read_timeout(dev, data, length, (dev->blocking)? -1: 0);
1001 }
1002
hid_set_nonblocking(hid_device * dev,int nonblock)1003 int HID_API_EXPORT HID_API_CALL hid_set_nonblocking(hid_device *dev, int nonblock)
1004 {
1005 dev->blocking = !nonblock;
1006 return 0; /* Success */
1007 }
1008
hid_send_feature_report(hid_device * dev,const unsigned char * data,size_t length)1009 int HID_API_EXPORT HID_API_CALL hid_send_feature_report(hid_device *dev, const unsigned char *data, size_t length)
1010 {
1011 BOOL res = FALSE;
1012 unsigned char *buf;
1013 size_t length_to_send;
1014
1015 /* Windows expects at least caps.FeatureReportByteLength bytes passed
1016 to HidD_SetFeature(), even if the report is shorter. Any less sent and
1017 the function fails with error ERROR_INVALID_PARAMETER set. Any more
1018 and HidD_SetFeature() silently truncates the data sent in the report
1019 to caps.FeatureReportByteLength. */
1020 if (length >= dev->feature_report_length) {
1021 buf = (unsigned char *) data;
1022 length_to_send = length;
1023 } else {
1024 if (dev->feature_buf == NULL)
1025 dev->feature_buf = (unsigned char *) malloc(dev->feature_report_length);
1026 buf = dev->feature_buf;
1027 memcpy(buf, data, length);
1028 memset(buf + length, 0, dev->feature_report_length - length);
1029 length_to_send = dev->feature_report_length;
1030 }
1031
1032 res = HidD_SetFeature(dev->device_handle, (PVOID)buf, (DWORD) length_to_send);
1033
1034 if (!res) {
1035 register_error(dev, "HidD_SetFeature");
1036 return -1;
1037 }
1038
1039 return (int) length;
1040 }
1041
hid_get_report(hid_device * dev,DWORD report_type,unsigned char * data,size_t length)1042 static int hid_get_report(hid_device *dev, DWORD report_type, unsigned char *data, size_t length)
1043 {
1044 BOOL res;
1045 DWORD bytes_returned = 0;
1046
1047 OVERLAPPED ol;
1048 memset(&ol, 0, sizeof(ol));
1049
1050 res = DeviceIoControl(dev->device_handle,
1051 report_type,
1052 data, (DWORD) length,
1053 data, (DWORD) length,
1054 &bytes_returned, &ol);
1055
1056 if (!res) {
1057 if (GetLastError() != ERROR_IO_PENDING) {
1058 /* DeviceIoControl() failed. Return error. */
1059 register_error(dev, "Get Input/Feature Report DeviceIoControl");
1060 return -1;
1061 }
1062 }
1063
1064 /* Wait here until the write is done. This makes
1065 hid_get_feature_report() synchronous. */
1066 res = GetOverlappedResult(dev->device_handle, &ol, &bytes_returned, TRUE/*wait*/);
1067 if (!res) {
1068 /* The operation failed. */
1069 register_error(dev, "Get Input/Feature Report GetOverLappedResult");
1070 return -1;
1071 }
1072
1073 /* When numbered reports aren't used,
1074 bytes_returned seem to include only what is actually received from the device
1075 (not including the first byte with 0, as an indication "no numbered reports"). */
1076 if (data[0] == 0x0) {
1077 bytes_returned++;
1078 }
1079
1080 return bytes_returned;
1081 }
1082
hid_get_feature_report(hid_device * dev,unsigned char * data,size_t length)1083 int HID_API_EXPORT HID_API_CALL hid_get_feature_report(hid_device *dev, unsigned char *data, size_t length)
1084 {
1085 /* We could use HidD_GetFeature() instead, but it doesn't give us an actual length, unfortunately */
1086 return hid_get_report(dev, IOCTL_HID_GET_FEATURE, data, length);
1087 }
1088
hid_get_input_report(hid_device * dev,unsigned char * data,size_t length)1089 int HID_API_EXPORT HID_API_CALL hid_get_input_report(hid_device *dev, unsigned char *data, size_t length)
1090 {
1091 /* We could use HidD_GetInputReport() instead, but it doesn't give us an actual length, unfortunately */
1092 return hid_get_report(dev, IOCTL_HID_GET_INPUT_REPORT, data, length);
1093 }
1094
hid_close(hid_device * dev)1095 void HID_API_EXPORT HID_API_CALL hid_close(hid_device *dev)
1096 {
1097 if (!dev)
1098 return;
1099 CancelIo(dev->device_handle);
1100 free_hid_device(dev);
1101 }
1102
hid_get_manufacturer_string(hid_device * dev,wchar_t * string,size_t maxlen)1103 int HID_API_EXPORT_CALL HID_API_CALL hid_get_manufacturer_string(hid_device *dev, wchar_t *string, size_t maxlen)
1104 {
1105 if (!dev->device_info || !string || !maxlen)
1106 return -1;
1107
1108 wcsncpy(string, dev->device_info->manufacturer_string, maxlen);
1109 string[maxlen] = L'\0';
1110
1111 return 0;
1112 }
1113
hid_get_product_string(hid_device * dev,wchar_t * string,size_t maxlen)1114 int HID_API_EXPORT_CALL HID_API_CALL hid_get_product_string(hid_device *dev, wchar_t *string, size_t maxlen)
1115 {
1116 if (!dev->device_info || !string || !maxlen)
1117 return -1;
1118
1119 wcsncpy(string, dev->device_info->product_string, maxlen);
1120 string[maxlen] = L'\0';
1121
1122 return 0;
1123 }
1124
hid_get_serial_number_string(hid_device * dev,wchar_t * string,size_t maxlen)1125 int HID_API_EXPORT_CALL HID_API_CALL hid_get_serial_number_string(hid_device *dev, wchar_t *string, size_t maxlen)
1126 {
1127 if (!dev->device_info || !string || !maxlen)
1128 return -1;
1129
1130 wcsncpy(string, dev->device_info->serial_number, maxlen);
1131 string[maxlen] = L'\0';
1132
1133 return 0;
1134 }
1135
hid_get_indexed_string(hid_device * dev,int string_index,wchar_t * string,size_t maxlen)1136 int HID_API_EXPORT_CALL HID_API_CALL hid_get_indexed_string(hid_device *dev, int string_index, wchar_t *string, size_t maxlen)
1137 {
1138 BOOL res;
1139
1140 res = HidD_GetIndexedString(dev->device_handle, string_index, string, sizeof(wchar_t) * (DWORD) MIN(maxlen, MAX_STRING_WCHARS));
1141 if (!res) {
1142 register_error(dev, "HidD_GetIndexedString");
1143 return -1;
1144 }
1145
1146 return 0;
1147 }
1148
1149
hid_error(hid_device * dev)1150 HID_API_EXPORT const wchar_t * HID_API_CALL hid_error(hid_device *dev)
1151 {
1152 if (dev) {
1153 if (dev->last_error_str == NULL)
1154 return L"Success";
1155 return (wchar_t*)dev->last_error_str;
1156 }
1157
1158 // Global error messages are not (yet) implemented on Windows.
1159 return L"hid_error for global errors is not implemented yet";
1160 }
1161
1162
1163 /*#define PICPGM*/
1164 /*#define S11*/
1165 #define P32
1166 #ifdef S11
1167 unsigned short VendorID = 0xa0a0;
1168 unsigned short ProductID = 0x0001;
1169 #endif
1170
1171 #ifdef P32
1172 unsigned short VendorID = 0x04d8;
1173 unsigned short ProductID = 0x3f;
1174 #endif
1175
1176
1177 #ifdef PICPGM
1178 unsigned short VendorID = 0x04d8;
1179 unsigned short ProductID = 0x0033;
1180 #endif
1181
1182
1183 #if 0
1184 int __cdecl main(int argc, char* argv[])
1185 {
1186 int res;
1187 unsigned char buf[65];
1188
1189 UNREFERENCED_PARAMETER(argc);
1190 UNREFERENCED_PARAMETER(argv);
1191
1192 /* Set up the command buffer. */
1193 memset(buf,0x00,sizeof(buf));
1194 buf[0] = 0;
1195 buf[1] = 0x81;
1196
1197
1198 /* Open the device. */
1199 int handle = open(VendorID, ProductID, L"12345");
1200 if (handle < 0)
1201 printf("unable to open device\n");
1202
1203
1204 /* Toggle LED (cmd 0x80) */
1205 buf[1] = 0x80;
1206 res = write(handle, buf, 65);
1207 if (res < 0)
1208 printf("Unable to write()\n");
1209
1210 /* Request state (cmd 0x81) */
1211 buf[1] = 0x81;
1212 write(handle, buf, 65);
1213 if (res < 0)
1214 printf("Unable to write() (2)\n");
1215
1216 /* Read requested state */
1217 read(handle, buf, 65);
1218 if (res < 0)
1219 printf("Unable to read()\n");
1220
1221 /* Print out the returned buffer. */
1222 for (int i = 0; i < 4; i++)
1223 printf("buf[%d]: %d\n", i, buf[i]);
1224
1225 return 0;
1226 }
1227 #endif
1228
1229 #ifdef __cplusplus
1230 } /* extern "C" */
1231 #endif
1232