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) |
| 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"); |
| 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); |
| 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]; |
| 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; |
| 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 */ |
| 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)); |
| 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); |
| 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) |
| 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[]) |
| 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 |