Chromium Code Reviews| 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 |