You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 

726 lines
20 KiB

  1. /* Raw HID I/O Routines
  2. * Copyright 2008, PJRC.COM, LLC
  3. * paul@pjrc.com
  4. *
  5. * You may redistribute this program and/or modify it under the terms
  6. * of the GNU General Public License as published by the Free Software
  7. * Foundation, either version 3 of the License, or (at your option)
  8. * any later version.
  9. *
  10. * This program is distributed in the hope that it will be useful,
  11. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  12. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  13. * GNU General Public License for more details.
  14. *
  15. * You should have received a copy of the GNU General Public License
  16. * along with this program. If not, see http://www.gnu.org/licenses/
  17. */
  18. // This code will someday be turned into "librawhid", an easy-to-use
  19. // and truly cross platform library for accessing HID reports. But
  20. // there are many complexities not properly handled by this simple
  21. // code that would be expected from a high quality library. In
  22. // particular, how report IDs are handled is not uniform on the 3
  23. // platforms. The mac code uses a single buffer which assumes no
  24. // other functions can cause the "run loop" to process HID callbacks.
  25. // The linux version doesn't extract usage and usage page from the
  26. // report descriptor and just hardcodes a signature for the Teensy
  27. // USB debug example. Lacking from all platforms are functions to
  28. // manage multiple devices and robust detection of device removal
  29. // and attachment. There are probably lots of other issues... this
  30. // code has really only been used in 2 projects. If you use it,
  31. // please report bugs to paul@pjrc.com
  32. #include <stdio.h>
  33. #include <stdlib.h>
  34. #include <stdint.h>
  35. #include <string.h>
  36. #include "rawhid.h"
  37. #ifdef OPERATING_SYSTEM
  38. #undef OPERATING_SYSTEM
  39. #endif
  40. /*************************************************************************/
  41. /** **/
  42. /** Linux **/
  43. /** **/
  44. /*************************************************************************/
  45. #if defined(LINUX) || defined(__LINUX__) || #system(linux)
  46. #define OPERATING_SYSTEM linux
  47. #include <fcntl.h>
  48. #include <errno.h>
  49. #include <unistd.h>
  50. #include <sys/types.h>
  51. #include <sys/stat.h>
  52. #include <sys/ioctl.h>
  53. #include <linux/hidraw.h>
  54. struct rawhid_struct {
  55. int fd;
  56. int name;
  57. int isok;
  58. };
  59. rawhid_t * rawhid_open_only1(int vid, int pid, int usage_page, int usage)
  60. {
  61. struct rawhid_struct *hid;
  62. struct stat devstat;
  63. struct hidraw_devinfo info;
  64. struct hidraw_report_descriptor *desc;
  65. char buf[512];
  66. // TODO; inputs are ignored and hardcoded into this signature....
  67. const unsigned char signature[]={0x06,0x31,0xFF,0x09,0x74};
  68. int r, i, fd=-1, len, found=0;
  69. //printf("Searching for device using hidraw....\n");
  70. for (i=0; i<HIDRAW_MAX_DEVICES; i++) {
  71. if (fd > 0) close(fd);
  72. snprintf(buf, sizeof(buf), "/dev/hidraw%d", i);
  73. r = stat(buf, &devstat);
  74. if (r < 0) continue;
  75. //printf("device: %s\n", buf);
  76. fd = open(buf, O_RDWR);
  77. if (fd < 0) continue;
  78. //printf(" opened\n");
  79. r = ioctl(fd, HIDIOCGRAWINFO, &info);
  80. if (r < 0) continue;
  81. //printf(" vid=%04X, pid=%04X\n", info.vendor & 0xFFFF, info.product & 0xFFFF);
  82. if ((info.vendor & 0xFFFF) != vid
  83. || (info.product & 0xFFFF) != pid) continue;
  84. r = ioctl(fd, HIDIOCGRDESCSIZE, &len);
  85. if (r < 0 || len < 1) continue;
  86. //printf(" len=%u\n", len);
  87. desc = (struct hidraw_report_descriptor *)buf;
  88. if (len > sizeof(buf)-sizeof(int)) len = sizeof(buf)-sizeof(int);
  89. desc->size = len;
  90. r = ioctl(fd, HIDIOCGRDESC, desc);
  91. if (r < 0) continue;
  92. //printf(" desc ok\n");
  93. if (len >= sizeof(signature)/* &&
  94. memcmp(desc->value, signature, sizeof(signature)) == 0*/) {
  95. //printf(" Match\n");
  96. found = 1;
  97. break;
  98. } else {
  99. //printf(" no match\n");
  100. }
  101. }
  102. if (!found) {
  103. if (fd > 0) close(fd);
  104. return NULL;
  105. }
  106. hid = (struct rawhid_struct *)malloc(sizeof(struct rawhid_struct));
  107. if (!hid) {
  108. close(fd);
  109. return NULL;
  110. }
  111. hid->fd = fd;
  112. return hid;
  113. }
  114. int rawhid_status(rawhid_t *hid)
  115. {
  116. // TODO: how to check if device is still online?
  117. return -1;
  118. }
  119. int rawhid_read(rawhid_t *h, void *buf, int bufsize, int timeout_ms)
  120. {
  121. struct rawhid_struct *hid;
  122. int num;
  123. hid = (struct rawhid_struct *)h;
  124. if (!hid || hid->fd < 0) return -1;
  125. while (1) {
  126. num = read(hid->fd, buf, bufsize);
  127. if (num < 0) {
  128. if (errno == EINTR || errno == EAGAIN) continue;
  129. if (errno == EIO) {
  130. return -1;
  131. printf("I/O Error\n");
  132. }
  133. printf("read error, r=%d, errno=%d\n", num, errno);
  134. return -1;
  135. }
  136. //printf("read %d bytes\n", num);
  137. return num;
  138. }
  139. }
  140. void rawhid_close(rawhid_t *h)
  141. {
  142. struct rawhid_struct *hid;
  143. hid = (struct rawhid_struct *)h;
  144. if (!hid || hid->fd < 0) return;
  145. close(hid->fd);
  146. hid->fd = -1;
  147. }
  148. #if 0
  149. struct rawhid_list_struct {
  150. int count;
  151. struct rawhid_list_entry {
  152. int name;
  153. int desc_length;
  154. const char *desc;
  155. } dev[HIDRAW_MAX_DEVICES];
  156. };
  157. rawhid_list_t * rawhid_list_open(int vid, int pid, int usage_page, int usage)
  158. {
  159. struct rawhid_list_struct *list;
  160. struct stat devstat;
  161. struct hidraw_devinfo info;
  162. struct hidraw_report_descriptor *desc;
  163. char buf[512], *p;
  164. const unsigned char signature[]={0x06,0x31,0xFF,0x09,0x74};
  165. int r, i, fd=-1, len;
  166. list = (struct rawhid_list_struct *)malloc(sizeof(struct rawhid_list_struct));
  167. if (!list) return NULL;
  168. list->count = 0;
  169. printf("Searching for device using hidraw....\n");
  170. for (i=0; i<HIDRAW_MAX_DEVICES; i++) {
  171. if (fd > 0) close(fd);
  172. snprintf(buf, sizeof(buf), "/dev/hidraw%d", i);
  173. r = stat(buf, &devstat);
  174. if (r < 0) continue;
  175. printf("device: %s\n", buf);
  176. fd = open(buf, O_RDWR);
  177. if (fd < 0) continue;
  178. printf(" opened\n");
  179. r = ioctl(fd, HIDIOCGRAWINFO, &info);
  180. if (r < 0) continue;
  181. printf(" vid=%04X, pid=%04X\n", info.vendor & 0xFFFF, info.product & 0xFFFF);
  182. r = ioctl(fd, HIDIOCGRDESCSIZE, &len);
  183. if (r < 0 || len < 1) continue;
  184. printf(" len=%u\n", len);
  185. desc = (struct hidraw_report_descriptor *)buf;
  186. if (len > sizeof(buf)-sizeof(int)) len = sizeof(buf)-sizeof(int);
  187. desc->size = len;
  188. r = ioctl(fd, HIDIOCGRDESC, desc);
  189. if (r < 0) continue;
  190. if (len < sizeof(signature)) continue;
  191. // TODO: actual report parsing would be nice!
  192. if (memcmp(desc->value, signature, sizeof(signature)) != 0) continue;
  193. p = (char *)malloc(len);
  194. if (!p) continue;
  195. printf(" Match\n");
  196. memcpy(p, desc->value, len);
  197. list->dev[list->count].desc = p;
  198. list->dev[list->count].desc_length = len;
  199. list->dev[list->count].name = i;
  200. list->count++;
  201. }
  202. if (fd > 0) close(fd);
  203. return list;
  204. }
  205. int rawhid_list_count(rawhid_list_t *list)
  206. {
  207. if (!list) return 0;
  208. return ((struct rawhid_list_struct *)list)->count;
  209. }
  210. void rawhid_list_close(rawhid_list_t *list)
  211. {
  212. if (list) free(list);
  213. }
  214. #endif
  215. #endif // linux
  216. /*************************************************************************/
  217. /** **/
  218. /** Mac OS X 10.5 **/
  219. /** **/
  220. /*************************************************************************/
  221. #if (defined(DARWIN) || defined(__DARWIN__)) && !defined(OPERATING_SYSTEM)
  222. #define OPERATING_SYSTEM darwin
  223. #include <IOKit/IOKitLib.h>
  224. #include <IOKit/hid/IOHIDLib.h>
  225. #include <IOKit/hid/IOHIDDevice.h>
  226. #include <unistd.h>
  227. // http://developer.apple.com/technotes/tn2007/tn2187.html
  228. struct rawhid_struct {
  229. IOHIDDeviceRef ref;
  230. int disconnected;
  231. uint8_t *buffer;
  232. int buffer_used;
  233. int buffer_report_id;
  234. };
  235. static void unplug_callback(void *hid, IOReturn ret, void *ref)
  236. {
  237. // This callback can only be called when the "run loop" (managed by macos)
  238. // is run. If the GUI is running it when idle, this will get called
  239. // automatically. If not, the run loop needs to be run explicitly
  240. // before checking the result of this function.
  241. //printf("HID/macos: unplugged callback!\n");
  242. ((struct rawhid_struct *)hid)->disconnected = 1;
  243. }
  244. static void input_callback(void *context, IOReturn result, void *sender,
  245. IOHIDReportType type, uint32_t reportID, uint8_t *report,
  246. CFIndex reportLength)
  247. {
  248. struct rawhid_struct *hid;
  249. //printf("input callback\n");
  250. if (!context) return;
  251. hid = (struct rawhid_struct *)context;
  252. hid->buffer_used = reportLength;
  253. hid->buffer_report_id = reportID;
  254. //printf("id = %d, reportLength = %d\n", reportID, (int)reportLength);
  255. //if (hid->ref == sender) printf("ref matches :-)\n");
  256. //if (report == hid->buffer) printf("buffer matches :)\n");
  257. }
  258. rawhid_t * rawhid_open_only1(int vid, int pid, int usage_page, int usage)
  259. {
  260. IOHIDManagerRef hid_manager;
  261. CFMutableDictionaryRef dict;
  262. IOReturn ret;
  263. CFSetRef device_set;
  264. IOHIDDeviceRef device_list[256];
  265. uint8_t *buf;
  266. struct rawhid_struct *hid;
  267. int num_devices;
  268. // get access to the HID Manager
  269. hid_manager = IOHIDManagerCreate(kCFAllocatorDefault, kIOHIDOptionsTypeNone);
  270. if (hid_manager == NULL || CFGetTypeID(hid_manager) != IOHIDManagerGetTypeID()) {
  271. printf("HID/macos: unable to access HID manager");
  272. return NULL;
  273. }
  274. // configure it to look for our type of device
  275. dict = IOServiceMatching(kIOHIDDeviceKey);
  276. if (dict == NULL) {
  277. printf("HID/macos: unable to create iokit dictionary");
  278. return NULL;
  279. }
  280. if (vid > 0) {
  281. CFDictionarySetValue(dict, CFSTR(kIOHIDVendorIDKey),
  282. CFNumberCreate(kCFAllocatorDefault, kCFNumberIntType, &vid));
  283. }
  284. if (pid > 0) {
  285. CFDictionarySetValue(dict, CFSTR(kIOHIDProductIDKey),
  286. CFNumberCreate(kCFAllocatorDefault, kCFNumberIntType, &pid));
  287. }
  288. if (usage_page > 0) {
  289. CFDictionarySetValue(dict, CFSTR(kIOHIDPrimaryUsagePageKey),
  290. CFNumberCreate(kCFAllocatorDefault, kCFNumberIntType, &usage_page));
  291. }
  292. if (usage > 0) {
  293. CFDictionarySetValue(dict, CFSTR(kIOHIDPrimaryUsageKey),
  294. CFNumberCreate(kCFAllocatorDefault, kCFNumberIntType, &usage));
  295. }
  296. IOHIDManagerSetDeviceMatching(hid_manager, dict);
  297. // now open the HID manager
  298. ret = IOHIDManagerOpen(hid_manager, kIOHIDOptionsTypeNone);
  299. if (ret != kIOReturnSuccess) {
  300. printf("HID/macos: Unable to open HID manager (IOHIDManagerOpen failed)");
  301. return NULL;
  302. }
  303. // get a list of devices that match our requirements
  304. device_set = IOHIDManagerCopyDevices(hid_manager);
  305. if (device_set == NULL) {
  306. //printf("HID/macos: no devices found\n");
  307. return NULL;
  308. }
  309. num_devices = (int)CFSetGetCount(device_set);
  310. //printf("number of devices found = %d\n", num_devices);
  311. if (num_devices < 1) {
  312. CFRelease(device_set);
  313. printf("HID/macos: no devices found, even though HID manager returned a set\n");
  314. return NULL;
  315. }
  316. if (num_devices > 256) {
  317. CFRelease(device_set);
  318. printf("HID/macos: too many devices, we get confused if more than 256!\n");
  319. return NULL;
  320. }
  321. CFSetGetValues(device_set, (const void **)&device_list);
  322. CFRelease(device_set);
  323. // open the first device in the list
  324. ret = IOHIDDeviceOpen(device_list[0], kIOHIDOptionsTypeNone);
  325. if (ret != kIOReturnSuccess) {
  326. printf("HID/macos: error opening device\n");
  327. return NULL;
  328. }
  329. // return this device
  330. hid = (struct rawhid_struct *)malloc(sizeof(struct rawhid_struct));
  331. buf = (uint8_t *)malloc(0x1000);
  332. if (hid == NULL || buf == NULL) {
  333. IOHIDDeviceRegisterRemovalCallback(device_list[0], NULL, NULL);
  334. IOHIDDeviceClose(device_list[0], kIOHIDOptionsTypeNone);
  335. printf("HID/macos: Unable to allocate memory\n");
  336. return NULL;
  337. }
  338. hid->ref = device_list[0];
  339. hid->disconnected = 0;
  340. hid->buffer = buf;
  341. hid->buffer_used = 0;
  342. // register a callback to receive input
  343. IOHIDDeviceRegisterInputReportCallback(hid->ref, hid->buffer, 0x1000,
  344. input_callback, hid);
  345. // register a callback to find out when it's unplugged
  346. IOHIDDeviceScheduleWithRunLoop(hid->ref, CFRunLoopGetCurrent(), kCFRunLoopDefaultMode);
  347. IOHIDDeviceRegisterRemovalCallback(hid->ref, unplug_callback, hid);
  348. return hid;
  349. }
  350. int rawhid_status(rawhid_t *hid)
  351. {
  352. if (!hid) return -1;
  353. // if a GUI is causing the run loop run, this will likely mess it up. Just
  354. // comment it out and if the callback still gets called without this, then
  355. // there's no need to run the run loop here!
  356. while (CFRunLoopRunInMode(kCFRunLoopDefaultMode, 0, true) == kCFRunLoopRunHandledSource) ;
  357. if (((struct rawhid_struct *)hid)->disconnected) {
  358. //printf("HID/macos: status: disconnected\n");
  359. return -1;
  360. }
  361. //printf("HID/macos: status: ok\n");
  362. return 0;
  363. }
  364. void rawhid_close(rawhid_t *hid)
  365. {
  366. IOHIDDeviceRef ref;
  367. if (!hid) return;
  368. ref = ((struct rawhid_struct *)hid)->ref;
  369. IOHIDDeviceRegisterRemovalCallback(ref, NULL, NULL);
  370. IOHIDDeviceClose(ref, kIOHIDOptionsTypeNone);
  371. free(hid);
  372. }
  373. int rawhid_read(rawhid_t *h, void *buf, int bufsize, int timeout_ms)
  374. {
  375. struct rawhid_struct *hid;
  376. int r, len;
  377. //printf("begin read\n");
  378. hid = (struct rawhid_struct *)h;
  379. if (!hid || hid->disconnected) return -1;
  380. while (CFRunLoopRunInMode(kCFRunLoopDefaultMode, 0, true) == kCFRunLoopRunHandledSource) {
  381. if (hid->buffer_used) {
  382. len = hid->buffer_used;
  383. if (len > bufsize) len = bufsize;
  384. memcpy(buf, hid->buffer, len);
  385. hid->buffer_used = 0;
  386. return len;
  387. }
  388. if (hid->disconnected) {
  389. return -1;
  390. }
  391. }
  392. r = CFRunLoopRunInMode(kCFRunLoopDefaultMode, (double)timeout_ms / 1000.0, true);
  393. if (r == kCFRunLoopRunTimedOut) {
  394. //printf("read timeout\n");
  395. return 0;
  396. }
  397. if (hid->buffer_used) {
  398. len = hid->buffer_used;
  399. if (len > bufsize) len = bufsize;
  400. memcpy(buf, hid->buffer, len);
  401. hid->buffer_used = 0;
  402. return len;
  403. }
  404. if (hid->disconnected) return -1;
  405. return 0;
  406. //num = bufsize;
  407. //ret = IOHIDDeviceGetReport(ref, kIOHIDReportTypeInput, 0, buf, &num);
  408. //if (!ret) return -1;
  409. //return num;
  410. }
  411. int rawhid_write(rawhid_t *hid, const void *buf, int len, int timeout_ms)
  412. {
  413. IOReturn ret;
  414. if (((struct rawhid_struct *)hid)->disconnected) return -1;
  415. ret = IOHIDDeviceSetReport(((struct rawhid_struct *)hid)->ref,
  416. kIOHIDReportTypeOutput, 0, buf, len);
  417. if (ret != kIOReturnSuccess) return -1;
  418. return 0;
  419. }
  420. #endif // Darwin - Mac OS X
  421. /*************************************************************************/
  422. /** **/
  423. /** Windows 2000/XP/Vista **/
  424. /** **/
  425. /*************************************************************************/
  426. #if (defined(WIN32) || defined(WINDOWS) || defined(__WINDOWS__)) && !defined(OPERATING_SYSTEM)
  427. #define OPERATING_SYSTEM windows
  428. #include <windows.h>
  429. #include <setupapi.h>
  430. #include <ddk/hidsdi.h>
  431. #include <ddk/hidclass.h>
  432. // http://msdn.microsoft.com/en-us/library/ms790932.aspx
  433. struct rawhid_struct {
  434. HANDLE handle;
  435. };
  436. rawhid_t * rawhid_open_only1(int vid, int pid, int usage_page, int usage)
  437. {
  438. GUID guid;
  439. HDEVINFO info;
  440. DWORD index=0, required_size;
  441. SP_DEVICE_INTERFACE_DATA iface;
  442. SP_DEVICE_INTERFACE_DETAIL_DATA *details;
  443. HIDD_ATTRIBUTES attrib;
  444. PHIDP_PREPARSED_DATA hid_data;
  445. HIDP_CAPS capabilities;
  446. struct rawhid_struct *hid;
  447. HANDLE h;
  448. BOOL ret;
  449. HidD_GetHidGuid(&guid);
  450. info = SetupDiGetClassDevs(&guid, NULL, NULL,
  451. DIGCF_PRESENT | DIGCF_DEVICEINTERFACE);
  452. if (info == INVALID_HANDLE_VALUE) {
  453. printf("HID/win32: SetupDiGetClassDevs failed");
  454. return NULL;
  455. }
  456. for (index=0; ;index++) {
  457. iface.cbSize = sizeof(SP_DEVICE_INTERFACE_DATA);
  458. ret = SetupDiEnumDeviceInterfaces(info, NULL, &guid, index, &iface);
  459. if (!ret) {
  460. // end of list
  461. SetupDiDestroyDeviceInfoList(info);
  462. return NULL;
  463. }
  464. SetupDiGetInterfaceDeviceDetail(info, &iface, NULL, 0, &required_size, NULL);
  465. details = (SP_DEVICE_INTERFACE_DETAIL_DATA *)malloc(required_size);
  466. if (details == NULL) continue;
  467. memset(details, 0, required_size);
  468. details->cbSize = sizeof(SP_DEVICE_INTERFACE_DETAIL_DATA);
  469. ret = SetupDiGetDeviceInterfaceDetail(info, &iface, details,
  470. required_size, NULL, NULL);
  471. if (!ret) {
  472. free(details);
  473. continue;
  474. }
  475. h = CreateFile(details->DevicePath, GENERIC_READ|GENERIC_WRITE,
  476. FILE_SHARE_READ|FILE_SHARE_WRITE, NULL, OPEN_EXISTING,
  477. FILE_FLAG_OVERLAPPED, NULL);
  478. free(details);
  479. if (h == INVALID_HANDLE_VALUE) continue;
  480. attrib.Size = sizeof(HIDD_ATTRIBUTES);
  481. ret = HidD_GetAttributes(h, &attrib);
  482. if (!ret) {
  483. CloseHandle(h);
  484. continue;
  485. }
  486. //printf("HID/win32: USB Device:\n");
  487. //printf("HID/win32: vid = 0x%04X\n", (int)(attrib.VendorID));
  488. //printf("HID/win32: pid = 0x%04X\n", (int)(attrib.ProductID));
  489. if (vid > 0 && vid != (int)(attrib.VendorID)) {
  490. CloseHandle(h);
  491. continue;
  492. }
  493. if (pid > 0 && pid != (int)(attrib.ProductID)) {
  494. CloseHandle(h);
  495. continue;
  496. }
  497. if (!HidD_GetPreparsedData(h, &hid_data)) {
  498. printf("HID/win32: HidD_GetPreparsedData failed\n");
  499. CloseHandle(h);
  500. continue;
  501. }
  502. if (!HidP_GetCaps(hid_data, &capabilities)) {
  503. printf("HID/win32: HidP_GetCaps failed\n");
  504. HidD_FreePreparsedData(hid_data);
  505. CloseHandle(h);
  506. continue;
  507. }
  508. printf("HID/win32: usage_page = 0x%04X\n", (int)(capabilities.UsagePage));
  509. printf("HID/win32: usage = 0x%04X\n", (int)(capabilities.Usage));
  510. if (usage_page > 0 && usage_page != (int)(capabilities.UsagePage)) {
  511. HidD_FreePreparsedData(hid_data);
  512. CloseHandle(h);
  513. continue;
  514. }
  515. if (usage > 0 && usage != (int)(capabilities.Usage)) {
  516. HidD_FreePreparsedData(hid_data);
  517. CloseHandle(h);
  518. continue;
  519. }
  520. HidD_FreePreparsedData(hid_data);
  521. hid = (struct rawhid_struct *)malloc(sizeof(struct rawhid_struct));
  522. if (!hid) {
  523. CloseHandle(h);
  524. printf("HID/win32: Unable to get %d bytes", sizeof(struct rawhid_struct));
  525. continue;
  526. }
  527. hid->handle = h;
  528. return hid;
  529. }
  530. }
  531. int rawhid_status(rawhid_t *hid)
  532. {
  533. PHIDP_PREPARSED_DATA hid_data;
  534. if (!hid) return -1;
  535. if (!HidD_GetPreparsedData(((struct rawhid_struct *)hid)->handle, &hid_data)) {
  536. printf("HID/win32: HidD_GetPreparsedData failed, device assumed disconnected\n");
  537. return -1;
  538. }
  539. printf("HID/win32: HidD_GetPreparsedData ok, device still online :-)\n");
  540. HidD_FreePreparsedData(hid_data);
  541. return 0;
  542. }
  543. void rawhid_close(rawhid_t *hid)
  544. {
  545. if (!hid) return;
  546. CloseHandle(((struct rawhid_struct *)hid)->handle);
  547. free(hid);
  548. }
  549. int rawhid_read(rawhid_t *h, void *buf, int bufsize, int timeout_ms)
  550. {
  551. DWORD num=0, result;
  552. BOOL ret;
  553. OVERLAPPED ov;
  554. struct rawhid_struct *hid;
  555. int r;
  556. hid = (struct rawhid_struct *)h;
  557. if (!hid) return -1;
  558. memset(&ov, 0, sizeof(OVERLAPPED));
  559. ov.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
  560. if (ov.hEvent == NULL) return -1;
  561. ret = ReadFile(hid->handle, buf, bufsize, &num, &ov);
  562. if (ret) {
  563. //printf("HID/win32: read success (immediate)\n");
  564. r = num;
  565. } else {
  566. if (GetLastError() == ERROR_IO_PENDING) {
  567. result = WaitForSingleObject(ov.hEvent, timeout_ms);
  568. if (result == WAIT_OBJECT_0) {
  569. if (GetOverlappedResult(hid->handle, &ov, &num, FALSE)) {
  570. //printf("HID/win32: read success (delayed)\n");
  571. r = num;
  572. } else {
  573. //printf("HID/win32: read failure (delayed)\n");
  574. r = -1;
  575. }
  576. } else {
  577. //printf("HID/win32: read timeout, %lx\n", result);
  578. CancelIo(hid->handle);
  579. r = 0;
  580. }
  581. } else {
  582. //printf("HID/win32: read error (immediate)\n");
  583. r = -1;
  584. }
  585. }
  586. CloseHandle(ov.hEvent);
  587. return r;
  588. }
  589. int rawhid_write(rawhid_t *h, const void *buf, int len, int timeout_ms)
  590. {
  591. DWORD num=0;
  592. BOOL ret;
  593. OVERLAPPED ov;
  594. struct rawhid_struct *hid;
  595. int r;
  596. hid = (struct rawhid_struct *)h;
  597. if (!hid) return -1;
  598. memset(&ov, 0, sizeof(OVERLAPPED));
  599. ov.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
  600. if (ov.hEvent == NULL) return -1;
  601. // first byte is report ID, must be zero if report IDs not used
  602. ret = WriteFile(hid->handle, buf, len, &num, &ov);
  603. if (ret) {
  604. if (num == len) {
  605. //printf("HID/win32: write success (immediate)\n");
  606. r = 0;
  607. } else {
  608. //printf("HID/win32: partial write (immediate)\n");
  609. r = -1;
  610. }
  611. } else {
  612. if (GetLastError() == ERROR_IO_PENDING) {
  613. if (GetOverlappedResult(hid->handle, &ov, &num, TRUE)) {
  614. if (num == len) {
  615. //printf("HID/win32: write success (delayed)\n");
  616. r = 0;
  617. } else {
  618. //printf("HID/win32: partial write (delayed)\n");
  619. r = -1;
  620. }
  621. } else {
  622. //printf("HID/win32: write error (delayed)\n");
  623. r = -1;
  624. }
  625. } else {
  626. //printf("HID/win32: write error (immediate)\n");
  627. r = -1;
  628. }
  629. }
  630. CloseHandle(ov.hEvent);
  631. return r;
  632. }
  633. #endif // windows
  634. #ifndef OPERATING_SYSTEM
  635. #error Unknown operating system
  636. #endif