packages feed

hidapi 0.1.2 → 0.1.3

raw patch · 8 files changed

+2865/−1732 lines, 8 files

Files

System/HIDAPI.hsc view
@@ -1,6 +1,6 @@ {-# LANGUAGE ForeignFunctionInterface, DeriveDataTypeable, DeriveGeneric #-} -#include "hidapi/hidapi.h"+#include "hidapi.h"  module System.HIDAPI   ( System.HIDAPI.init, exit, withHIDAPI
cbits/hidapi/hidapi.h view
@@ -293,22 +293,26 @@  		/** @brief Get a feature report from a HID device. -			Make sure to set the first byte of @p data[] to the Report-			ID of the report to be read.  Make sure to allow space for-			this extra byte in @p data[].+			Set the first byte of @p data[] to the Report ID of the+			report to be read.  Make sure to allow space for this+			extra byte in @p data[]. Upon return, the first byte will+			still contain the Report ID, and the report data will+			start in data[1].  			@ingroup API 			@param device A device handle returned from hid_open(). 			@param data A buffer to put the read data into, including 				the Report ID. Set the first byte of @p data[] to the-				Report ID of the report to be read.+				Report ID of the report to be read, or set it to zero+				if your device does not use numbered reports. 			@param length The number of bytes to read, including an 				extra byte for the report ID. The buffer can be longer 				than the actual report.  			@returns-				This function returns the number of bytes read and-				-1 on error.+				This function returns the number of bytes read plus+				one for the report ID (which is still in the first+				byte), or -1 on error. 		*/ 		int HID_API_EXPORT HID_API_CALL hid_get_feature_report(hid_device *device, unsigned char *data, size_t length); 
+ cbits/hidapi/linux/hid.c view
@@ -0,0 +1,795 @@+/*******************************************************+ HIDAPI - Multi-Platform library for+ communication with HID devices.++ Alan Ott+ Signal 11 Software++ 8/22/2009+ Linux Version - 6/2/2009++ Copyright 2009, All Rights Reserved.++ At the discretion of the user of this library,+ this software may be licensed under the terms of the+ GNU General Public License v3, a BSD-Style license, or the+ original HIDAPI license as outlined in the LICENSE.txt,+ LICENSE-gpl3.txt, LICENSE-bsd.txt, and LICENSE-orig.txt+ files located at the root of the source distribution.+ These files may also be found in the public source+ code repository located at:+        http://github.com/signal11/hidapi .+********************************************************/++/* C */+#include <stdio.h>+#include <string.h>+#include <stdlib.h>+#include <locale.h>+#include <errno.h>++/* Unix */+#include <unistd.h>+#include <sys/types.h>+#include <sys/stat.h>+#include <sys/ioctl.h>+#include <sys/utsname.h>+#include <fcntl.h>+#include <poll.h>++/* Linux */+#include <linux/hidraw.h>+#include <linux/version.h>+#include <linux/input.h>+#include <libudev.h>++#include "hidapi.h"++/* Definitions from linux/hidraw.h. Since these are new, some distros+   may not have header files which contain them. */+#ifndef HIDIOCSFEATURE+#define HIDIOCSFEATURE(len)    _IOC(_IOC_WRITE|_IOC_READ, 'H', 0x06, len)+#endif+#ifndef HIDIOCGFEATURE+#define HIDIOCGFEATURE(len)    _IOC(_IOC_WRITE|_IOC_READ, 'H', 0x07, len)+#endif+++/* USB HID device property names */+const char *device_string_names[] = {+	"manufacturer",+	"product",+	"serial",+};++/* Symbolic names for the properties above */+enum device_string_id {+	DEVICE_STRING_MANUFACTURER,+	DEVICE_STRING_PRODUCT,+	DEVICE_STRING_SERIAL,++	DEVICE_STRING_COUNT,+};++struct hid_device_ {+	int device_handle;+	int blocking;+	int uses_numbered_reports;+};+++static __u32 kernel_version = 0;++static __u32 detect_kernel_version(void)+{+	struct utsname name;+	int major, minor, release;+	int ret;++	uname(&name);+	ret = sscanf(name.release, "%d.%d.%d", &major, &minor, &release);+	if (ret == 3) {+		return KERNEL_VERSION(major, minor, release);+	}++	ret = sscanf(name.release, "%d.%d", &major, &minor);+	if (ret == 2) {+		return KERNEL_VERSION(major, minor, 0);+	}++	printf("Couldn't determine kernel version from version string \"%s\"\n", name.release);+	return 0;+}++static hid_device *new_hid_device(void)+{+	hid_device *dev = calloc(1, sizeof(hid_device));+	dev->device_handle = -1;+	dev->blocking = 1;+	dev->uses_numbered_reports = 0;++	return dev;+}+++/* The caller must free the returned string with free(). */+static wchar_t *utf8_to_wchar_t(const char *utf8)+{+	wchar_t *ret = NULL;++	if (utf8) {+		size_t wlen = mbstowcs(NULL, utf8, 0);+		if ((size_t) -1 == wlen) {+			return wcsdup(L"");+		}+		ret = calloc(wlen+1, sizeof(wchar_t));+		mbstowcs(ret, utf8, wlen+1);+		ret[wlen] = 0x0000;+	}++	return ret;+}++/* Get an attribute value from a udev_device and return it as a whar_t+   string. The returned string must be freed with free() when done.*/+static wchar_t *copy_udev_string(struct udev_device *dev, const char *udev_name)+{+	return utf8_to_wchar_t(udev_device_get_sysattr_value(dev, udev_name));+}++/* uses_numbered_reports() returns 1 if report_descriptor describes a device+   which contains numbered reports. */+static int uses_numbered_reports(__u8 *report_descriptor, __u32 size) {+	unsigned int i = 0;+	int size_code;+	int data_len, key_size;++	while (i < size) {+		int key = report_descriptor[i];++		/* Check for the Report ID key */+		if (key == 0x85/*Report ID*/) {+			/* This device has a Report ID, which means it uses+			   numbered reports. */+			return 1;+		}++		//printf("key: %02hhx\n", key);++		if ((key & 0xf0) == 0xf0) {+			/* This is a Long Item. The next byte contains the+			   length of the data section (value) for this key.+			   See the HID specification, version 1.11, section+			   6.2.2.3, titled "Long Items." */+			if (i+1 < size)+				data_len = report_descriptor[i+1];+			else+				data_len = 0; /* malformed report */+			key_size = 3;+		}+		else {+			/* This is a Short Item. The bottom two bits of the+			   key contain the size code for the data section+			   (value) for this key.  Refer to the HID+			   specification, version 1.11, section 6.2.2.2,+			   titled "Short Items." */+			size_code = key & 0x3;+			switch (size_code) {+			case 0:+			case 1:+			case 2:+				data_len = size_code;+				break;+			case 3:+				data_len = 4;+				break;+			default:+				/* Can't ever happen since size_code is & 0x3 */+				data_len = 0;+				break;+			};+			key_size = 1;+		}++		/* Skip over this key and it's associated data */+		i += data_len + key_size;+	}++	/* Didn't find a Report ID key. Device doesn't use numbered reports. */+	return 0;+}++/*+ * The caller is responsible for free()ing the (newly-allocated) character+ * strings pointed to by serial_number_utf8 and product_name_utf8 after use.+ */+static int+parse_uevent_info(const char *uevent, int *bus_type,+	unsigned short *vendor_id, unsigned short *product_id,+	char **serial_number_utf8, char **product_name_utf8)+{+	char *tmp = strdup(uevent);+	char *saveptr = NULL;+	char *line;+	char *key;+	char *value;++	int found_id = 0;+	int found_serial = 0;+	int found_name = 0;++	line = strtok_r(tmp, "\n", &saveptr);+	while (line != NULL) {+		/* line: "KEY=value" */+		key = line;+		value = strchr(line, '=');+		if (!value) {+			goto next_line;+		}+		*value = '\0';+		value++;++		if (strcmp(key, "HID_ID") == 0) {+			/**+			 *        type vendor   product+			 * HID_ID=0003:000005AC:00008242+			 **/+			int ret = sscanf(value, "%x:%hx:%hx", bus_type, vendor_id, product_id);+			if (ret == 3) {+				found_id = 1;+			}+		} else if (strcmp(key, "HID_NAME") == 0) {+			/* The caller has to free the product name */+			*product_name_utf8 = strdup(value);+			found_name = 1;+		} else if (strcmp(key, "HID_UNIQ") == 0) {+			/* The caller has to free the serial number */+			*serial_number_utf8 = strdup(value);+			found_serial = 1;+		}++next_line:+		line = strtok_r(NULL, "\n", &saveptr);+	}++	free(tmp);+	return (found_id && found_name && found_serial);+}+++static int get_device_string(hid_device *dev, enum device_string_id key, wchar_t *string, size_t maxlen)+{+	struct udev *udev;+	struct udev_device *udev_dev, *parent, *hid_dev;+	struct stat s;+	int ret = -1;+        char *serial_number_utf8 = NULL;+        char *product_name_utf8 = NULL;++	/* Create the udev object */+	udev = udev_new();+	if (!udev) {+		printf("Can't create udev\n");+		return -1;+	}++	/* Get the dev_t (major/minor numbers) from the file handle. */+	fstat(dev->device_handle, &s);+	/* Open a udev device from the dev_t. 'c' means character device. */+	udev_dev = udev_device_new_from_devnum(udev, 'c', s.st_rdev);+	if (udev_dev) {+		hid_dev = udev_device_get_parent_with_subsystem_devtype(+			udev_dev,+			"hid",+			NULL);+		if (hid_dev) {+			unsigned short dev_vid;+			unsigned short dev_pid;+			int bus_type;+			size_t retm;++			ret = parse_uevent_info(+			           udev_device_get_sysattr_value(hid_dev, "uevent"),+			           &bus_type,+			           &dev_vid,+			           &dev_pid,+			           &serial_number_utf8,+			           &product_name_utf8);++			if (bus_type == BUS_BLUETOOTH) {+				switch (key) {+					case DEVICE_STRING_MANUFACTURER:+						wcsncpy(string, L"", maxlen);+						ret = 0;+						break;+					case DEVICE_STRING_PRODUCT:+						retm = mbstowcs(string, product_name_utf8, maxlen);+						ret = (retm == (size_t)-1)? -1: 0;+						break;+					case DEVICE_STRING_SERIAL:+						retm = mbstowcs(string, serial_number_utf8, maxlen);+						ret = (retm == (size_t)-1)? -1: 0;+						break;+					case DEVICE_STRING_COUNT:+					default:+						ret = -1;+						break;+				}+			}+			else {+				/* This is a USB device. Find its parent USB Device node. */+				parent = udev_device_get_parent_with_subsystem_devtype(+					   udev_dev,+					   "usb",+					   "usb_device");+				if (parent) {+					const char *str;+					const char *key_str = NULL;++					if (key >= 0 && key < DEVICE_STRING_COUNT) {+						key_str = device_string_names[key];+					} else {+						ret = -1;+						goto end;+					}++					str = udev_device_get_sysattr_value(parent, key_str);+					if (str) {+						/* Convert the string from UTF-8 to wchar_t */+						retm = mbstowcs(string, str, maxlen);+						ret = (retm == (size_t)-1)? -1: 0;+						goto end;+					}+				}+			}+		}+	}++end:+        free(serial_number_utf8);+        free(product_name_utf8);++	udev_device_unref(udev_dev);+	/* parent and hid_dev don't need to be (and can't be) unref'd.+	   I'm not sure why, but they'll throw double-free() errors. */+	udev_unref(udev);++	return ret;+}++int HID_API_EXPORT hid_init(void)+{+	const char *locale;++	/* Set the locale if it's not set. */+	locale = setlocale(LC_CTYPE, NULL);+	if (!locale)+		setlocale(LC_CTYPE, "");++	kernel_version = detect_kernel_version();++	return 0;+}++int HID_API_EXPORT hid_exit(void)+{+	/* Nothing to do for this in the Linux/hidraw implementation. */+	return 0;+}+++struct hid_device_info  HID_API_EXPORT *hid_enumerate(unsigned short vendor_id, unsigned short product_id)+{+	struct udev *udev;+	struct udev_enumerate *enumerate;+	struct udev_list_entry *devices, *dev_list_entry;++	struct hid_device_info *root = NULL; /* return object */+	struct hid_device_info *cur_dev = NULL;+	struct hid_device_info *prev_dev = NULL; /* previous device */++	hid_init();++	/* Create the udev object */+	udev = udev_new();+	if (!udev) {+		printf("Can't create udev\n");+		return NULL;+	}++	/* Create a list of the devices in the 'hidraw' subsystem. */+	enumerate = udev_enumerate_new(udev);+	udev_enumerate_add_match_subsystem(enumerate, "hidraw");+	udev_enumerate_scan_devices(enumerate);+	devices = udev_enumerate_get_list_entry(enumerate);+	/* For each item, see if it matches the vid/pid, and if so+	   create a udev_device record for it */+	udev_list_entry_foreach(dev_list_entry, devices) {+		const char *sysfs_path;+		const char *dev_path;+		const char *str;+		struct udev_device *raw_dev; /* The device's hidraw udev node. */+		struct udev_device *hid_dev; /* The device's HID udev node. */+		struct udev_device *usb_dev; /* The device's USB udev node. */+		struct udev_device *intf_dev; /* The device's interface (in the USB sense). */+		unsigned short dev_vid;+		unsigned short dev_pid;+		char *serial_number_utf8 = NULL;+		char *product_name_utf8 = NULL;+		int bus_type;+		int result;++		/* Get the filename of the /sys entry for the device+		   and create a udev_device object (dev) representing it */+		sysfs_path = udev_list_entry_get_name(dev_list_entry);+		raw_dev = udev_device_new_from_syspath(udev, sysfs_path);+		dev_path = udev_device_get_devnode(raw_dev);++		hid_dev = udev_device_get_parent_with_subsystem_devtype(+			raw_dev,+			"hid",+			NULL);++		if (!hid_dev) {+			/* Unable to find parent hid device. */+			goto next;+		}++		result = parse_uevent_info(+			udev_device_get_sysattr_value(hid_dev, "uevent"),+			&bus_type,+			&dev_vid,+			&dev_pid,+			&serial_number_utf8,+			&product_name_utf8);++		if (!result) {+			/* parse_uevent_info() failed for at least one field. */+			goto next;+		}++		if (bus_type != BUS_USB && bus_type != BUS_BLUETOOTH) {+			/* We only know how to handle USB and BT devices. */+			goto next;+		}++		/* Check the VID/PID against the arguments */+		if ((vendor_id == 0x0 || vendor_id == dev_vid) &&+		    (product_id == 0x0 || product_id == dev_pid)) {+			struct hid_device_info *tmp;++			/* VID/PID match. Create the record. */+			tmp = malloc(sizeof(struct hid_device_info));+			if (cur_dev) {+				cur_dev->next = tmp;+			}+			else {+				root = tmp;+			}+			prev_dev = cur_dev;+			cur_dev = tmp;++			/* Fill out the record */+			cur_dev->next = NULL;+			cur_dev->path = dev_path? strdup(dev_path): NULL;++			/* VID/PID */+			cur_dev->vendor_id = dev_vid;+			cur_dev->product_id = dev_pid;++			/* Serial Number */+			cur_dev->serial_number = utf8_to_wchar_t(serial_number_utf8);++			/* Release Number */+			cur_dev->release_number = 0x0;++			/* Interface Number */+			cur_dev->interface_number = -1;++			switch (bus_type) {+				case BUS_USB:+					/* The device pointed to by raw_dev contains information about+					   the hidraw device. In order to get information about the+					   USB device, get the parent device with the+					   subsystem/devtype pair of "usb"/"usb_device". This will+					   be several levels up the tree, but the function will find+					   it. */+					usb_dev = udev_device_get_parent_with_subsystem_devtype(+							raw_dev,+							"usb",+							"usb_device");++					if (!usb_dev) {+						/* Free this device */+						free(cur_dev->serial_number);+						free(cur_dev->path);+						free(cur_dev);++						/* Take it off the device list. */+						if (prev_dev) {+							prev_dev->next = NULL;+							cur_dev = prev_dev;+						}+						else {+							cur_dev = root = NULL;+						}++						goto next;+					}++					/* Manufacturer and Product strings */+					cur_dev->manufacturer_string = copy_udev_string(usb_dev, device_string_names[DEVICE_STRING_MANUFACTURER]);+					cur_dev->product_string = copy_udev_string(usb_dev, device_string_names[DEVICE_STRING_PRODUCT]);++					/* Release Number */+					str = udev_device_get_sysattr_value(usb_dev, "bcdDevice");+					cur_dev->release_number = (str)? strtol(str, NULL, 16): 0x0;++					/* Get a handle to the interface's udev node. */+					intf_dev = udev_device_get_parent_with_subsystem_devtype(+							raw_dev,+							"usb",+							"usb_interface");+					if (intf_dev) {+						str = udev_device_get_sysattr_value(intf_dev, "bInterfaceNumber");+						cur_dev->interface_number = (str)? strtol(str, NULL, 16): -1;+					}++					break;++				case BUS_BLUETOOTH:+					/* Manufacturer and Product strings */+					cur_dev->manufacturer_string = wcsdup(L"");+					cur_dev->product_string = utf8_to_wchar_t(product_name_utf8);++					break;++				default:+					/* Unknown device type - this should never happen, as we+					 * check for USB and Bluetooth devices above */+					break;+			}+		}++	next:+		free(serial_number_utf8);+		free(product_name_utf8);+		udev_device_unref(raw_dev);+		/* hid_dev, usb_dev and intf_dev don't need to be (and can't be)+		   unref()d.  It will cause a double-free() error.  I'm not+		   sure why.  */+	}+	/* Free the enumerator and udev objects. */+	udev_enumerate_unref(enumerate);+	udev_unref(udev);++	return root;+}++void  HID_API_EXPORT hid_free_enumeration(struct hid_device_info *devs)+{+	struct hid_device_info *d = devs;+	while (d) {+		struct hid_device_info *next = d->next;+		free(d->path);+		free(d->serial_number);+		free(d->manufacturer_string);+		free(d->product_string);+		free(d);+		d = next;+	}+}++hid_device * hid_open(unsigned short vendor_id, unsigned short product_id, const wchar_t *serial_number)+{+	struct hid_device_info *devs, *cur_dev;+	const char *path_to_open = NULL;+	hid_device *handle = NULL;++	devs = hid_enumerate(vendor_id, product_id);+	cur_dev = devs;+	while (cur_dev) {+		if (cur_dev->vendor_id == vendor_id &&+		    cur_dev->product_id == product_id) {+			if (serial_number) {+				if (wcscmp(serial_number, cur_dev->serial_number) == 0) {+					path_to_open = cur_dev->path;+					break;+				}+			}+			else {+				path_to_open = cur_dev->path;+				break;+			}+		}+		cur_dev = cur_dev->next;+	}++	if (path_to_open) {+		/* Open the device */+		handle = hid_open_path(path_to_open);+	}++	hid_free_enumeration(devs);++	return handle;+}++hid_device * HID_API_EXPORT hid_open_path(const char *path)+{+	hid_device *dev = NULL;++	hid_init();++	dev = new_hid_device();++	/* OPEN HERE */+	dev->device_handle = open(path, O_RDWR);++	/* If we have a good handle, return it. */+	if (dev->device_handle > 0) {++		/* Get the report descriptor */+		int res, desc_size = 0;+		struct hidraw_report_descriptor rpt_desc;++		memset(&rpt_desc, 0x0, sizeof(rpt_desc));++		/* Get Report Descriptor Size */+		res = ioctl(dev->device_handle, HIDIOCGRDESCSIZE, &desc_size);+		if (res < 0)+			perror("HIDIOCGRDESCSIZE");+++		/* Get Report Descriptor */+		rpt_desc.size = desc_size;+		res = ioctl(dev->device_handle, HIDIOCGRDESC, &rpt_desc);+		if (res < 0) {+			perror("HIDIOCGRDESC");+		} else {+			/* Determine if this device uses numbered reports. */+			dev->uses_numbered_reports =+				uses_numbered_reports(rpt_desc.value,+				                      rpt_desc.size);+		}++		return dev;+	}+	else {+		/* Unable to open any devices. */+		free(dev);+		return NULL;+	}+}+++int HID_API_EXPORT hid_write(hid_device *dev, const unsigned char *data, size_t length)+{+	int bytes_written;++	bytes_written = write(dev->device_handle, data, length);++	return bytes_written;+}+++int HID_API_EXPORT hid_read_timeout(hid_device *dev, unsigned char *data, size_t length, int milliseconds)+{+	int bytes_read;++	if (milliseconds >= 0) {+		/* Milliseconds is either 0 (non-blocking) or > 0 (contains+		   a valid timeout). In both cases we want to call poll()+		   and wait for data to arrive.  Don't rely on non-blocking+		   operation (O_NONBLOCK) since some kernels don't seem to+		   properly report device disconnection through read() when+		   in non-blocking mode.  */+		int ret;+		struct pollfd fds;++		fds.fd = dev->device_handle;+		fds.events = POLLIN;+		fds.revents = 0;+		ret = poll(&fds, 1, milliseconds);+		if (ret == -1 || ret == 0) {+			/* Error or timeout */+			return ret;+		}+		else {+			/* Check for errors on the file descriptor. This will+			   indicate a device disconnection. */+			if (fds.revents & (POLLERR | POLLHUP | POLLNVAL))+				return -1;+		}+	}++	bytes_read = read(dev->device_handle, data, length);+	if (bytes_read < 0 && (errno == EAGAIN || errno == EINPROGRESS))+		bytes_read = 0;++	if (bytes_read >= 0 &&+	    kernel_version != 0 &&+	    kernel_version < KERNEL_VERSION(2,6,34) &&+	    dev->uses_numbered_reports) {+		/* Work around a kernel bug. Chop off the first byte. */+		memmove(data, data+1, bytes_read);+		bytes_read--;+	}++	return bytes_read;+}++int HID_API_EXPORT hid_read(hid_device *dev, unsigned char *data, size_t length)+{+	return hid_read_timeout(dev, data, length, (dev->blocking)? -1: 0);+}++int HID_API_EXPORT hid_set_nonblocking(hid_device *dev, int nonblock)+{+	/* Do all non-blocking in userspace using poll(), since it looks+	   like there's a bug in the kernel in some versions where+	   read() will not return -1 on disconnection of the USB device */++	dev->blocking = !nonblock;+	return 0; /* Success */+}+++int HID_API_EXPORT hid_send_feature_report(hid_device *dev, const unsigned char *data, size_t length)+{+	int res;++	res = ioctl(dev->device_handle, HIDIOCSFEATURE(length), data);+	if (res < 0)+		perror("ioctl (SFEATURE)");++	return res;+}++int HID_API_EXPORT hid_get_feature_report(hid_device *dev, unsigned char *data, size_t length)+{+	int res;++	res = ioctl(dev->device_handle, HIDIOCGFEATURE(length), data);+	if (res < 0)+		perror("ioctl (GFEATURE)");+++	return res;+}+++void HID_API_EXPORT hid_close(hid_device *dev)+{+	if (!dev)+		return;+	close(dev->device_handle);+	free(dev);+}+++int HID_API_EXPORT_CALL hid_get_manufacturer_string(hid_device *dev, wchar_t *string, size_t maxlen)+{+	return get_device_string(dev, DEVICE_STRING_MANUFACTURER, string, maxlen);+}++int HID_API_EXPORT_CALL hid_get_product_string(hid_device *dev, wchar_t *string, size_t maxlen)+{+	return get_device_string(dev, DEVICE_STRING_PRODUCT, string, maxlen);+}++int HID_API_EXPORT_CALL hid_get_serial_number_string(hid_device *dev, wchar_t *string, size_t maxlen)+{+	return get_device_string(dev, DEVICE_STRING_SERIAL, string, maxlen);+}++int HID_API_EXPORT_CALL hid_get_indexed_string(hid_device *dev, int string_index, wchar_t *string, size_t maxlen)+{+	return -1;+}+++HID_API_EXPORT const wchar_t * HID_API_CALL  hid_error(hid_device *dev)+{+	return NULL;+}
+ cbits/hidapi/mac/hid.c view
@@ -0,0 +1,1112 @@+/*******************************************************+ HIDAPI - Multi-Platform library for+ communication with HID devices.++ Alan Ott+ Signal 11 Software++ 2010-07-03++ Copyright 2010, All Rights Reserved.++ At the discretion of the user of this library,+ this software may be licensed under the terms of the+ GNU General Public License v3, a BSD-Style license, or the+ original HIDAPI license as outlined in the LICENSE.txt,+ LICENSE-gpl3.txt, LICENSE-bsd.txt, and LICENSE-orig.txt+ files located at the root of the source distribution.+ These files may also be found in the public source+ code repository located at:+        http://github.com/signal11/hidapi .+********************************************************/++/* See Apple Technical Note TN2187 for details on IOHidManager. */++#include <IOKit/hid/IOHIDManager.h>+#include <IOKit/hid/IOHIDKeys.h>+#include <CoreFoundation/CoreFoundation.h>+#include <wchar.h>+#include <locale.h>+#include <pthread.h>+#include <sys/time.h>+#include <unistd.h>++#include "hidapi.h"++/* Barrier implementation because Mac OSX doesn't have pthread_barrier.+   It also doesn't have clock_gettime(). So much for POSIX and SUSv2.+   This implementation came from Brent Priddy and was posted on+   StackOverflow. It is used with his permission. */+typedef int pthread_barrierattr_t;+typedef struct pthread_barrier {+    pthread_mutex_t mutex;+    pthread_cond_t cond;+    int count;+    int trip_count;+} pthread_barrier_t;++static int pthread_barrier_init(pthread_barrier_t *barrier, const pthread_barrierattr_t *attr, unsigned int count)+{+	if(count == 0) {+		errno = EINVAL;+		return -1;+	}++	if(pthread_mutex_init(&barrier->mutex, 0) < 0) {+		return -1;+	}+	if(pthread_cond_init(&barrier->cond, 0) < 0) {+		pthread_mutex_destroy(&barrier->mutex);+		return -1;+	}+	barrier->trip_count = count;+	barrier->count = 0;++	return 0;+}++static int pthread_barrier_destroy(pthread_barrier_t *barrier)+{+	pthread_cond_destroy(&barrier->cond);+	pthread_mutex_destroy(&barrier->mutex);+	return 0;+}++static int pthread_barrier_wait(pthread_barrier_t *barrier)+{+	pthread_mutex_lock(&barrier->mutex);+	++(barrier->count);+	if(barrier->count >= barrier->trip_count)+	{+		barrier->count = 0;+		pthread_cond_broadcast(&barrier->cond);+		pthread_mutex_unlock(&barrier->mutex);+		return 1;+	}+	else+	{+		pthread_cond_wait(&barrier->cond, &(barrier->mutex));+		pthread_mutex_unlock(&barrier->mutex);+		return 0;+	}+}++static int return_data(hid_device *dev, unsigned char *data, size_t length);++/* Linked List of input reports received from the device. */+struct input_report {+	uint8_t *data;+	size_t len;+	struct input_report *next;+};++struct hid_device_ {+	IOHIDDeviceRef device_handle;+	int blocking;+	int uses_numbered_reports;+	int disconnected;+	CFStringRef run_loop_mode;+	CFRunLoopRef run_loop;+	CFRunLoopSourceRef source;+	uint8_t *input_report_buf;+	CFIndex max_input_report_len;+	struct input_report *input_reports;++	pthread_t thread;+	pthread_mutex_t mutex; /* Protects input_reports */+	pthread_cond_t condition;+	pthread_barrier_t barrier; /* Ensures correct startup sequence */+	pthread_barrier_t shutdown_barrier; /* Ensures correct shutdown sequence */+	int shutdown_thread;+};++static hid_device *new_hid_device(void)+{+	hid_device *dev = calloc(1, sizeof(hid_device));+	dev->device_handle = NULL;+	dev->blocking = 1;+	dev->uses_numbered_reports = 0;+	dev->disconnected = 0;+	dev->run_loop_mode = NULL;+	dev->run_loop = NULL;+	dev->source = NULL;+	dev->input_report_buf = NULL;+	dev->input_reports = NULL;+	dev->shutdown_thread = 0;++	/* Thread objects */+	pthread_mutex_init(&dev->mutex, NULL);+	pthread_cond_init(&dev->condition, NULL);+	pthread_barrier_init(&dev->barrier, NULL, 2);+	pthread_barrier_init(&dev->shutdown_barrier, NULL, 2);++	return dev;+}++static void free_hid_device(hid_device *dev)+{+	if (!dev)+		return;++	/* Delete any input reports still left over. */+	struct input_report *rpt = dev->input_reports;+	while (rpt) {+		struct input_report *next = rpt->next;+		free(rpt->data);+		free(rpt);+		rpt = next;+	}++	/* Free the string and the report buffer. The check for NULL+	   is necessary here as CFRelease() doesn't handle NULL like+	   free() and others do. */+	if (dev->run_loop_mode)+		CFRelease(dev->run_loop_mode);+	if (dev->source)+		CFRelease(dev->source);+	free(dev->input_report_buf);++	/* Clean up the thread objects */+	pthread_barrier_destroy(&dev->shutdown_barrier);+	pthread_barrier_destroy(&dev->barrier);+	pthread_cond_destroy(&dev->condition);+	pthread_mutex_destroy(&dev->mutex);++	/* Free the structure itself. */+	free(dev);+}++static	IOHIDManagerRef hid_mgr = 0x0;+++#if 0+static void register_error(hid_device *device, const char *op)+{++}+#endif+++static int32_t get_int_property(IOHIDDeviceRef device, CFStringRef key)+{+	CFTypeRef ref;+	int32_t value;++	ref = IOHIDDeviceGetProperty(device, key);+	if (ref) {+		if (CFGetTypeID(ref) == CFNumberGetTypeID()) {+			CFNumberGetValue((CFNumberRef) ref, kCFNumberSInt32Type, &value);+			return value;+		}+	}+	return 0;+}++static unsigned short get_vendor_id(IOHIDDeviceRef device)+{+	return get_int_property(device, CFSTR(kIOHIDVendorIDKey));+}++static unsigned short get_product_id(IOHIDDeviceRef device)+{+	return get_int_property(device, CFSTR(kIOHIDProductIDKey));+}++static int32_t get_location_id(IOHIDDeviceRef device)+{+	return get_int_property(device, CFSTR(kIOHIDLocationIDKey));+}++static int32_t get_max_report_length(IOHIDDeviceRef device)+{+	return get_int_property(device, CFSTR(kIOHIDMaxInputReportSizeKey));+}++static int get_string_property(IOHIDDeviceRef device, CFStringRef prop, wchar_t *buf, size_t len)+{+	CFStringRef str;++	if (!len)+		return 0;++	str = IOHIDDeviceGetProperty(device, prop);++	buf[0] = 0;++	if (str) {+		CFIndex str_len = CFStringGetLength(str);+		CFRange range;+		CFIndex used_buf_len;+		CFIndex chars_copied;++		len --;++		range.location = 0;+		range.length = ((size_t)str_len > len)? len: (size_t)str_len;+		chars_copied = CFStringGetBytes(str,+			range,+			kCFStringEncodingUTF32LE,+			(char)'?',+			FALSE,+			(UInt8*)buf,+			len * sizeof(wchar_t),+			&used_buf_len);++		if (chars_copied == len)+			buf[len] = 0; /* len is decremented above */+		else+			buf[chars_copied] = 0;++		return 0;+	}+	else+		return -1;++}++static int get_string_property_utf8(IOHIDDeviceRef device, CFStringRef prop, char *buf, size_t len)+{+	CFStringRef str;+	if (!len)+		return 0;++	str = IOHIDDeviceGetProperty(device, prop);++	buf[0] = 0;++	if (str) {+		len--;++		CFIndex str_len = CFStringGetLength(str);+		CFRange range;+		range.location = 0;+		range.length = str_len;+		CFIndex used_buf_len;+		CFIndex chars_copied;+		chars_copied = CFStringGetBytes(str,+			range,+			kCFStringEncodingUTF8,+			(char)'?',+			FALSE,+			(UInt8*)buf,+			len,+			&used_buf_len);++		if (used_buf_len == len)+			buf[len] = 0; /* len is decremented above */+		else+			buf[used_buf_len] = 0;++		return used_buf_len;+	}+	else+		return 0;+}+++static int get_serial_number(IOHIDDeviceRef device, wchar_t *buf, size_t len)+{+	return get_string_property(device, CFSTR(kIOHIDSerialNumberKey), buf, len);+}++static int get_manufacturer_string(IOHIDDeviceRef device, wchar_t *buf, size_t len)+{+	return get_string_property(device, CFSTR(kIOHIDManufacturerKey), buf, len);+}++static int get_product_string(IOHIDDeviceRef device, wchar_t *buf, size_t len)+{+	return get_string_property(device, CFSTR(kIOHIDProductKey), buf, len);+}+++/* Implementation of wcsdup() for Mac. */+static wchar_t *dup_wcs(const wchar_t *s)+{+	size_t len = wcslen(s);+	wchar_t *ret = malloc((len+1)*sizeof(wchar_t));+	wcscpy(ret, s);++	return ret;+}+++static int make_path(IOHIDDeviceRef device, char *buf, size_t len)+{+	int res;+	unsigned short vid, pid;+	char transport[32];+	int32_t location;++	buf[0] = '\0';++	res = get_string_property_utf8(+		device, CFSTR(kIOHIDTransportKey),+		transport, sizeof(transport));++	if (!res)+		return -1;++	location = get_location_id(device);+	vid = get_vendor_id(device);+	pid = get_product_id(device);++	res = snprintf(buf, len, "%s_%04hx_%04hx_%x",+                       transport, vid, pid, location);+++	buf[len-1] = '\0';+	return res+1;+}++/* Initialize the IOHIDManager. Return 0 for success and -1 for failure. */+static int init_hid_manager(void)+{+	/* Initialize all the HID Manager Objects */+	hid_mgr = IOHIDManagerCreate(kCFAllocatorDefault, kIOHIDOptionsTypeNone);+	if (hid_mgr) {+		IOHIDManagerSetDeviceMatching(hid_mgr, NULL);+		IOHIDManagerScheduleWithRunLoop(hid_mgr, CFRunLoopGetCurrent(), kCFRunLoopDefaultMode);+		return 0;+	}++	return -1;+}++/* Initialize the IOHIDManager if necessary. This is the public function, and+   it is safe to call this function repeatedly. Return 0 for success and -1+   for failure. */+int HID_API_EXPORT hid_init(void)+{+	if (!hid_mgr) {+		return init_hid_manager();+	}++	/* Already initialized. */+	return 0;+}++int HID_API_EXPORT hid_exit(void)+{+	if (hid_mgr) {+		/* Close the HID manager. */+		IOHIDManagerClose(hid_mgr, kIOHIDOptionsTypeNone);+		CFRelease(hid_mgr);+		hid_mgr = NULL;+	}++	return 0;+}++static void process_pending_events(void) {+	SInt32 res;+	do {+		res = CFRunLoopRunInMode(kCFRunLoopDefaultMode, 0.001, FALSE);+	} while(res != kCFRunLoopRunFinished && res != kCFRunLoopRunTimedOut);+}++struct hid_device_info  HID_API_EXPORT *hid_enumerate(unsigned short vendor_id, unsigned short product_id)+{+	struct hid_device_info *root = NULL; /* return object */+	struct hid_device_info *cur_dev = NULL;+	CFIndex num_devices;+	int i;++	/* Set up the HID Manager if it hasn't been done */+	if (hid_init() < 0)+		return NULL;++	/* give the IOHIDManager a chance to update itself */+	process_pending_events();++	/* Get a list of the Devices */+	IOHIDManagerSetDeviceMatching(hid_mgr, NULL);+	CFSetRef device_set = IOHIDManagerCopyDevices(hid_mgr);++	/* Convert the list into a C array so we can iterate easily. */+	num_devices = CFSetGetCount(device_set);+	IOHIDDeviceRef *device_array = calloc(num_devices, sizeof(IOHIDDeviceRef));+	CFSetGetValues(device_set, (const void **) device_array);++	/* Iterate over each device, making an entry for it. */+	for (i = 0; i < num_devices; i++) {+		unsigned short dev_vid;+		unsigned short dev_pid;+		#define BUF_LEN 256+		wchar_t buf[BUF_LEN];+		char cbuf[BUF_LEN];++		IOHIDDeviceRef dev = device_array[i];++        if (!dev) {+            continue;+        }+		dev_vid = get_vendor_id(dev);+		dev_pid = get_product_id(dev);++		/* Check the VID/PID against the arguments */+		if ((vendor_id == 0x0 || vendor_id == dev_vid) &&+		    (product_id == 0x0 || product_id == dev_pid)) {+			struct hid_device_info *tmp;+			size_t len;++			/* VID/PID match. Create the record. */+			tmp = malloc(sizeof(struct hid_device_info));+			if (cur_dev) {+				cur_dev->next = tmp;+			}+			else {+				root = tmp;+			}+			cur_dev = tmp;++			/* Get the Usage Page and Usage for this device. */+			cur_dev->usage_page = get_int_property(dev, CFSTR(kIOHIDPrimaryUsagePageKey));+			cur_dev->usage = get_int_property(dev, CFSTR(kIOHIDPrimaryUsageKey));++			/* Fill out the record */+			cur_dev->next = NULL;+			len = make_path(dev, cbuf, sizeof(cbuf));+			cur_dev->path = strdup(cbuf);++			/* Serial Number */+			get_serial_number(dev, buf, BUF_LEN);+			cur_dev->serial_number = dup_wcs(buf);++			/* Manufacturer and Product strings */+			get_manufacturer_string(dev, buf, BUF_LEN);+			cur_dev->manufacturer_string = dup_wcs(buf);+			get_product_string(dev, buf, BUF_LEN);+			cur_dev->product_string = dup_wcs(buf);++			/* VID/PID */+			cur_dev->vendor_id = dev_vid;+			cur_dev->product_id = dev_pid;++			/* Release Number */+			cur_dev->release_number = get_int_property(dev, CFSTR(kIOHIDVersionNumberKey));++			/* Interface Number (Unsupported on Mac)*/+			cur_dev->interface_number = -1;+		}+	}++	free(device_array);+	CFRelease(device_set);++	return root;+}++void  HID_API_EXPORT hid_free_enumeration(struct hid_device_info *devs)+{+	/* This function is identical to the Linux version. Platform independent. */+	struct hid_device_info *d = devs;+	while (d) {+		struct hid_device_info *next = d->next;+		free(d->path);+		free(d->serial_number);+		free(d->manufacturer_string);+		free(d->product_string);+		free(d);+		d = next;+	}+}++hid_device * HID_API_EXPORT hid_open(unsigned short vendor_id, unsigned short product_id, const wchar_t *serial_number)+{+	/* This function is identical to the Linux version. Platform independent. */+	struct hid_device_info *devs, *cur_dev;+	const char *path_to_open = NULL;+	hid_device * handle = NULL;++	devs = hid_enumerate(vendor_id, product_id);+	cur_dev = devs;+	while (cur_dev) {+		if (cur_dev->vendor_id == vendor_id &&+		    cur_dev->product_id == product_id) {+			if (serial_number) {+				if (wcscmp(serial_number, cur_dev->serial_number) == 0) {+					path_to_open = cur_dev->path;+					break;+				}+			}+			else {+				path_to_open = cur_dev->path;+				break;+			}+		}+		cur_dev = cur_dev->next;+	}++	if (path_to_open) {+		/* Open the device */+		handle = hid_open_path(path_to_open);+	}++	hid_free_enumeration(devs);++	return handle;+}++static void hid_device_removal_callback(void *context, IOReturn result,+                                        void *sender)+{+	/* Stop the Run Loop for this device. */+	hid_device *d = context;++	d->disconnected = 1;+	CFRunLoopStop(d->run_loop);+}++/* The Run Loop calls this function for each input report received.+   This function puts the data into a linked list to be picked up by+   hid_read(). */+static void hid_report_callback(void *context, IOReturn result, void *sender,+                         IOHIDReportType report_type, uint32_t report_id,+                         uint8_t *report, CFIndex report_length)+{+	struct input_report *rpt;+	hid_device *dev = context;++	/* Make a new Input Report object */+	rpt = calloc(1, sizeof(struct input_report));+	rpt->data = calloc(1, report_length);+	memcpy(rpt->data, report, report_length);+	rpt->len = report_length;+	rpt->next = NULL;++	/* Lock this section */+	pthread_mutex_lock(&dev->mutex);++	/* Attach the new report object to the end of the list. */+	if (dev->input_reports == NULL) {+		/* The list is empty. Put it at the root. */+		dev->input_reports = rpt;+	}+	else {+		/* Find the end of the list and attach. */+		struct input_report *cur = dev->input_reports;+		int num_queued = 0;+		while (cur->next != NULL) {+			cur = cur->next;+			num_queued++;+		}+		cur->next = rpt;++		/* Pop one off if we've reached 30 in the queue. This+		   way we don't grow forever if the user never reads+		   anything from the device. */+		if (num_queued > 30) {+			return_data(dev, NULL, 0);+		}+	}++	/* Signal a waiting thread that there is data. */+	pthread_cond_signal(&dev->condition);++	/* Unlock */+	pthread_mutex_unlock(&dev->mutex);++}++/* This gets called when the read_thred's run loop gets signaled by+   hid_close(), and serves to stop the read_thread's run loop. */+static void perform_signal_callback(void *context)+{+	hid_device *dev = context;+	CFRunLoopStop(dev->run_loop); /*TODO: CFRunLoopGetCurrent()*/+}++static void *read_thread(void *param)+{+	hid_device *dev = param;+	SInt32 code;++	/* Move the device's run loop to this thread. */+	IOHIDDeviceScheduleWithRunLoop(dev->device_handle, CFRunLoopGetCurrent(), dev->run_loop_mode);++	/* Create the RunLoopSource which is used to signal the+	   event loop to stop when hid_close() is called. */+	CFRunLoopSourceContext ctx;+	memset(&ctx, 0, sizeof(ctx));+	ctx.version = 0;+	ctx.info = dev;+	ctx.perform = &perform_signal_callback;+	dev->source = CFRunLoopSourceCreate(kCFAllocatorDefault, 0/*order*/, &ctx);+	CFRunLoopAddSource(CFRunLoopGetCurrent(), dev->source, dev->run_loop_mode);++	/* Store off the Run Loop so it can be stopped from hid_close()+	   and on device disconnection. */+	dev->run_loop = CFRunLoopGetCurrent();++	/* Notify the main thread that the read thread is up and running. */+	pthread_barrier_wait(&dev->barrier);++	/* Run the Event Loop. CFRunLoopRunInMode() will dispatch HID input+	   reports into the hid_report_callback(). */+	while (!dev->shutdown_thread && !dev->disconnected) {+		code = CFRunLoopRunInMode(dev->run_loop_mode, 1000/*sec*/, FALSE);+		/* Return if the device has been disconnected */+		if (code == kCFRunLoopRunFinished) {+			dev->disconnected = 1;+			break;+		}+++		/* Break if The Run Loop returns Finished or Stopped. */+		if (code != kCFRunLoopRunTimedOut &&+		    code != kCFRunLoopRunHandledSource) {+			/* There was some kind of error. Setting+			   shutdown seems to make sense, but+			   there may be something else more appropriate */+			dev->shutdown_thread = 1;+			break;+		}+	}++	/* Now that the read thread is stopping, Wake any threads which are+	   waiting on data (in hid_read_timeout()). Do this under a mutex to+	   make sure that a thread which is about to go to sleep waiting on+	   the condition acutally will go to sleep before the condition is+	   signaled. */+	pthread_mutex_lock(&dev->mutex);+	pthread_cond_broadcast(&dev->condition);+	pthread_mutex_unlock(&dev->mutex);++	/* Wait here until hid_close() is called and makes it past+	   the call to CFRunLoopWakeUp(). This thread still needs to+	   be valid when that function is called on the other thread. */+	pthread_barrier_wait(&dev->shutdown_barrier);++	return NULL;+}++hid_device * HID_API_EXPORT hid_open_path(const char *path)+{+	int i;+	hid_device *dev = NULL;+	CFIndex num_devices;++	dev = new_hid_device();++	/* Set up the HID Manager if it hasn't been done */+	if (hid_init() < 0)+		return NULL;++	/* give the IOHIDManager a chance to update itself */+	process_pending_events();++	CFSetRef device_set = IOHIDManagerCopyDevices(hid_mgr);++	num_devices = CFSetGetCount(device_set);+	IOHIDDeviceRef *device_array = calloc(num_devices, sizeof(IOHIDDeviceRef));+	CFSetGetValues(device_set, (const void **) device_array);+	for (i = 0; i < num_devices; i++) {+		char cbuf[BUF_LEN];+		size_t len;+		IOHIDDeviceRef os_dev = device_array[i];++		len = make_path(os_dev, cbuf, sizeof(cbuf));+		if (!strcmp(cbuf, path)) {+			/* Matched Paths. Open this Device. */+			IOReturn ret = IOHIDDeviceOpen(os_dev, kIOHIDOptionsTypeSeizeDevice);+			if (ret == kIOReturnSuccess) {+				char str[32];++				free(device_array);+				CFRetain(os_dev);+				CFRelease(device_set);+				dev->device_handle = os_dev;++				/* Create the buffers for receiving data */+				dev->max_input_report_len = (CFIndex) get_max_report_length(os_dev);+				dev->input_report_buf = calloc(dev->max_input_report_len, sizeof(uint8_t));++				/* Create the Run Loop Mode for this device.+				   printing the reference seems to work. */+				sprintf(str, "HIDAPI_%p", os_dev);+				dev->run_loop_mode =+					CFStringCreateWithCString(NULL, str, kCFStringEncodingASCII);++				/* Attach the device to a Run Loop */+				IOHIDDeviceRegisterInputReportCallback(+					os_dev, dev->input_report_buf, dev->max_input_report_len,+					&hid_report_callback, dev);+				IOHIDDeviceRegisterRemovalCallback(dev->device_handle, hid_device_removal_callback, dev);++				/* Start the read thread */+				pthread_create(&dev->thread, NULL, read_thread, dev);++				/* Wait here for the read thread to be initialized. */+				pthread_barrier_wait(&dev->barrier);++				return dev;+			}+			else {+				goto return_error;+			}+		}+	}++return_error:+	free(device_array);+	CFRelease(device_set);+	free_hid_device(dev);+	return NULL;+}++static int set_report(hid_device *dev, IOHIDReportType type, const unsigned char *data, size_t length)+{+	const unsigned char *data_to_send;+	size_t length_to_send;+	IOReturn res;++	/* Return if the device has been disconnected. */+	if (dev->disconnected)+		return -1;++	if (data[0] == 0x0) {+		/* Not using numbered Reports.+		   Don't send the report number. */+		data_to_send = data+1;+		length_to_send = length-1;+	}+	else {+		/* Using numbered Reports.+		   Send the Report Number */+		data_to_send = data;+		length_to_send = length;+	}++	if (!dev->disconnected) {+		res = IOHIDDeviceSetReport(dev->device_handle,+					   type,+					   data[0], /* Report ID*/+					   data_to_send, length_to_send);++		if (res == kIOReturnSuccess) {+			return length;+		}+		else+			return -1;+	}++	return -1;+}++int HID_API_EXPORT hid_write(hid_device *dev, const unsigned char *data, size_t length)+{+	return set_report(dev, kIOHIDReportTypeOutput, data, length);+}++/* Helper function, so that this isn't duplicated in hid_read(). */+static int return_data(hid_device *dev, unsigned char *data, size_t length)+{+	/* Copy the data out of the linked list item (rpt) into the+	   return buffer (data), and delete the liked list item. */+	struct input_report *rpt = dev->input_reports;+	size_t len = (length < rpt->len)? length: rpt->len;+	memcpy(data, rpt->data, len);+	dev->input_reports = rpt->next;+	free(rpt->data);+	free(rpt);+	return len;+}++static int cond_wait(const hid_device *dev, pthread_cond_t *cond, pthread_mutex_t *mutex)+{+	while (!dev->input_reports) {+		int res = pthread_cond_wait(cond, mutex);+		if (res != 0)+			return res;++		/* A res of 0 means we may have been signaled or it may+		   be a spurious wakeup. Check to see that there's acutally+		   data in the queue before returning, and if not, go back+		   to sleep. See the pthread_cond_timedwait() man page for+		   details. */++		if (dev->shutdown_thread || dev->disconnected)+			return -1;+	}++	return 0;+}++static int cond_timedwait(const hid_device *dev, pthread_cond_t *cond, pthread_mutex_t *mutex, const struct timespec *abstime)+{+	while (!dev->input_reports) {+		int res = pthread_cond_timedwait(cond, mutex, abstime);+		if (res != 0)+			return res;++		/* A res of 0 means we may have been signaled or it may+		   be a spurious wakeup. Check to see that there's acutally+		   data in the queue before returning, and if not, go back+		   to sleep. See the pthread_cond_timedwait() man page for+		   details. */++		if (dev->shutdown_thread || dev->disconnected)+			return -1;+	}++	return 0;++}++int HID_API_EXPORT hid_read_timeout(hid_device *dev, unsigned char *data, size_t length, int milliseconds)+{+	int bytes_read = -1;++	/* Lock the access to the report list. */+	pthread_mutex_lock(&dev->mutex);++	/* There's an input report queued up. Return it. */+	if (dev->input_reports) {+		/* Return the first one */+		bytes_read = return_data(dev, data, length);+		goto ret;+	}++	/* Return if the device has been disconnected. */+	if (dev->disconnected) {+		bytes_read = -1;+		goto ret;+	}++	if (dev->shutdown_thread) {+		/* This means the device has been closed (or there+		   has been an error. An error code of -1 should+		   be returned. */+		bytes_read = -1;+		goto ret;+	}++	/* There is no data. Go to sleep and wait for data. */++	if (milliseconds == -1) {+		/* Blocking */+		int res;+		res = cond_wait(dev, &dev->condition, &dev->mutex);+		if (res == 0)+			bytes_read = return_data(dev, data, length);+		else {+			/* There was an error, or a device disconnection. */+			bytes_read = -1;+		}+	}+	else if (milliseconds > 0) {+		/* Non-blocking, but called with timeout. */+		int res;+		struct timespec ts;+		struct timeval tv;+		gettimeofday(&tv, NULL);+		TIMEVAL_TO_TIMESPEC(&tv, &ts);+		ts.tv_sec += milliseconds / 1000;+		ts.tv_nsec += (milliseconds % 1000) * 1000000;+		if (ts.tv_nsec >= 1000000000L) {+			ts.tv_sec++;+			ts.tv_nsec -= 1000000000L;+		}++		res = cond_timedwait(dev, &dev->condition, &dev->mutex, &ts);+		if (res == 0)+			bytes_read = return_data(dev, data, length);+		else if (res == ETIMEDOUT)+			bytes_read = 0;+		else+			bytes_read = -1;+	}+	else {+		/* Purely non-blocking */+		bytes_read = 0;+	}++ret:+	/* Unlock */+	pthread_mutex_unlock(&dev->mutex);+	return bytes_read;+}++int HID_API_EXPORT hid_read(hid_device *dev, unsigned char *data, size_t length)+{+	return hid_read_timeout(dev, data, length, (dev->blocking)? -1: 0);+}++int HID_API_EXPORT hid_set_nonblocking(hid_device *dev, int nonblock)+{+	/* All Nonblocking operation is handled by the library. */+	dev->blocking = !nonblock;++	return 0;+}++int HID_API_EXPORT hid_send_feature_report(hid_device *dev, const unsigned char *data, size_t length)+{+	return set_report(dev, kIOHIDReportTypeFeature, data, length);+}++int HID_API_EXPORT hid_get_feature_report(hid_device *dev, unsigned char *data, size_t length)+{+	CFIndex len = length;+	IOReturn res;++	/* Return if the device has been unplugged. */+	if (dev->disconnected)+		return -1;++	res = IOHIDDeviceGetReport(dev->device_handle,+	                           kIOHIDReportTypeFeature,+	                           data[0], /* Report ID */+	                           data, &len);+	if (res == kIOReturnSuccess)+		return len;+	else+		return -1;+}+++void HID_API_EXPORT hid_close(hid_device *dev)+{+	if (!dev)+		return;++	/* Disconnect the report callback before close. */+	if (!dev->disconnected) {+		IOHIDDeviceRegisterInputReportCallback(+			dev->device_handle, dev->input_report_buf, dev->max_input_report_len,+			NULL, dev);+		IOHIDDeviceRegisterRemovalCallback(dev->device_handle, NULL, dev);+		IOHIDDeviceUnscheduleFromRunLoop(dev->device_handle, dev->run_loop, dev->run_loop_mode);+		IOHIDDeviceScheduleWithRunLoop(dev->device_handle, CFRunLoopGetMain(), kCFRunLoopDefaultMode);+	}++	/* Cause read_thread() to stop. */+	dev->shutdown_thread = 1;++	/* Wake up the run thread's event loop so that the thread can exit. */+	CFRunLoopSourceSignal(dev->source);+	CFRunLoopWakeUp(dev->run_loop);++	/* Notify the read thread that it can shut down now. */+	pthread_barrier_wait(&dev->shutdown_barrier);++	/* Wait for read_thread() to end. */+	pthread_join(dev->thread, NULL);++	/* Close the OS handle to the device, but only if it's not+	   been unplugged. If it's been unplugged, then calling+	   IOHIDDeviceClose() will crash. */+	if (!dev->disconnected) {+		IOHIDDeviceClose(dev->device_handle, kIOHIDOptionsTypeSeizeDevice);+	}++	/* Clear out the queue of received reports. */+	pthread_mutex_lock(&dev->mutex);+	while (dev->input_reports) {+		return_data(dev, NULL, 0);+	}+	pthread_mutex_unlock(&dev->mutex);+	CFRelease(dev->device_handle);++	free_hid_device(dev);+}++int HID_API_EXPORT_CALL hid_get_manufacturer_string(hid_device *dev, wchar_t *string, size_t maxlen)+{+	return get_manufacturer_string(dev->device_handle, string, maxlen);+}++int HID_API_EXPORT_CALL hid_get_product_string(hid_device *dev, wchar_t *string, size_t maxlen)+{+	return get_product_string(dev->device_handle, string, maxlen);+}++int HID_API_EXPORT_CALL hid_get_serial_number_string(hid_device *dev, wchar_t *string, size_t maxlen)+{+	return get_serial_number(dev->device_handle, string, maxlen);+}++int HID_API_EXPORT_CALL hid_get_indexed_string(hid_device *dev, int string_index, wchar_t *string, size_t maxlen)+{+	/* TODO: */++	return 0;+}+++HID_API_EXPORT const wchar_t * HID_API_CALL  hid_error(hid_device *dev)+{+	/* TODO: */++	return NULL;+}++++++++#if 0+static int32_t get_usage(IOHIDDeviceRef device)+{+	int32_t res;+	res = get_int_property(device, CFSTR(kIOHIDDeviceUsageKey));+	if (!res)+		res = get_int_property(device, CFSTR(kIOHIDPrimaryUsageKey));+	return res;+}++static int32_t get_usage_page(IOHIDDeviceRef device)+{+	int32_t res;+	res = get_int_property(device, CFSTR(kIOHIDDeviceUsagePageKey));+	if (!res)+		res = get_int_property(device, CFSTR(kIOHIDPrimaryUsagePageKey));+	return res;+}++static int get_transport(IOHIDDeviceRef device, wchar_t *buf, size_t len)+{+	return get_string_property(device, CFSTR(kIOHIDTransportKey), buf, len);+}+++int main(void)+{+	IOHIDManagerRef mgr;+	int i;++	mgr = IOHIDManagerCreate(kCFAllocatorDefault, kIOHIDOptionsTypeNone);+	IOHIDManagerSetDeviceMatching(mgr, NULL);+	IOHIDManagerOpen(mgr, kIOHIDOptionsTypeNone);++	CFSetRef device_set = IOHIDManagerCopyDevices(mgr);++	CFIndex num_devices = CFSetGetCount(device_set);+	IOHIDDeviceRef *device_array = calloc(num_devices, sizeof(IOHIDDeviceRef));+	CFSetGetValues(device_set, (const void **) device_array);++	for (i = 0; i < num_devices; i++) {+		IOHIDDeviceRef dev = device_array[i];+		printf("Device: %p\n", dev);+		printf("  %04hx %04hx\n", get_vendor_id(dev), get_product_id(dev));++		wchar_t serial[256], buf[256];+		char cbuf[256];+		get_serial_number(dev, serial, 256);+++		printf("  Serial: %ls\n", serial);+		printf("  Loc: %ld\n", get_location_id(dev));+		get_transport(dev, buf, 256);+		printf("  Trans: %ls\n", buf);+		make_path(dev, cbuf, 256);+		printf("  Path: %s\n", cbuf);++	}++	return 0;+}+#endif
+ cbits/hidapi/windows/hid.c view
@@ -0,0 +1,939 @@+/*******************************************************+ HIDAPI - Multi-Platform library for+ communication with HID devices.++ Alan Ott+ Signal 11 Software++ 8/22/2009++ Copyright 2009, All Rights Reserved.+ + At the discretion of the user of this library,+ this software may be licensed under the terms of the+ GNU General Public License v3, a BSD-Style license, or the+ original HIDAPI license as outlined in the LICENSE.txt,+ LICENSE-gpl3.txt, LICENSE-bsd.txt, and LICENSE-orig.txt+ files located at the root of the source distribution.+ These files may also be found in the public source+ code repository located at:+        http://github.com/signal11/hidapi .+********************************************************/++#include <windows.h>++#ifndef _NTDEF_+typedef LONG NTSTATUS;+#endif++#ifdef __MINGW32__+#include <ntdef.h>+#include <winbase.h>+#endif++#ifdef __CYGWIN__+#include <ntdef.h>+#define _wcsdup wcsdup+#endif++/*#define HIDAPI_USE_DDK*/++#ifdef __cplusplus+extern "C" {+#endif+	#include <setupapi.h>+	#include <winioctl.h>+	#ifdef HIDAPI_USE_DDK+		#include <hidsdi.h>+	#endif++	/* Copied from inc/ddk/hidclass.h, part of the Windows DDK. */+	#define HID_OUT_CTL_CODE(id)  \+		CTL_CODE(FILE_DEVICE_KEYBOARD, (id), METHOD_OUT_DIRECT, FILE_ANY_ACCESS)+	#define IOCTL_HID_GET_FEATURE                   HID_OUT_CTL_CODE(100)++#ifdef __cplusplus+} /* extern "C" */+#endif++#include <stdio.h>+#include <stdlib.h>+++#include "hidapi.h"++#ifdef _MSC_VER+	/* Thanks Microsoft, but I know how to use strncpy(). */+	#pragma warning(disable:4996)+#endif++#ifdef __cplusplus+extern "C" {+#endif++#ifndef HIDAPI_USE_DDK+	/* Since we're not building with the DDK, and the HID header+	   files aren't part of the SDK, we have to define all this+	   stuff here. In lookup_functions(), the function pointers+	   defined below are set. */+	typedef struct _HIDD_ATTRIBUTES{+		ULONG Size;+		USHORT VendorID;+		USHORT ProductID;+		USHORT VersionNumber;+	} HIDD_ATTRIBUTES, *PHIDD_ATTRIBUTES;++	typedef USHORT USAGE;+	typedef struct _HIDP_CAPS {+		USAGE Usage;+		USAGE UsagePage;+		USHORT InputReportByteLength;+		USHORT OutputReportByteLength;+		USHORT FeatureReportByteLength;+		USHORT Reserved[17];+		USHORT fields_not_used_by_hidapi[10];+	} HIDP_CAPS, *PHIDP_CAPS;+	typedef void* PHIDP_PREPARSED_DATA;+	#define HIDP_STATUS_SUCCESS 0x110000++	typedef BOOLEAN (__stdcall *HidD_GetAttributes_)(HANDLE device, PHIDD_ATTRIBUTES attrib);+	typedef BOOLEAN (__stdcall *HidD_GetSerialNumberString_)(HANDLE device, PVOID buffer, ULONG buffer_len);+	typedef BOOLEAN (__stdcall *HidD_GetManufacturerString_)(HANDLE handle, PVOID buffer, ULONG buffer_len);+	typedef BOOLEAN (__stdcall *HidD_GetProductString_)(HANDLE handle, PVOID buffer, ULONG buffer_len);+	typedef BOOLEAN (__stdcall *HidD_SetFeature_)(HANDLE handle, PVOID data, ULONG length);+	typedef BOOLEAN (__stdcall *HidD_GetFeature_)(HANDLE handle, PVOID data, ULONG length);+	typedef BOOLEAN (__stdcall *HidD_GetIndexedString_)(HANDLE handle, ULONG string_index, PVOID buffer, ULONG buffer_len);+	typedef BOOLEAN (__stdcall *HidD_GetPreparsedData_)(HANDLE handle, PHIDP_PREPARSED_DATA *preparsed_data);+	typedef BOOLEAN (__stdcall *HidD_FreePreparsedData_)(PHIDP_PREPARSED_DATA preparsed_data);+	typedef NTSTATUS (__stdcall *HidP_GetCaps_)(PHIDP_PREPARSED_DATA preparsed_data, HIDP_CAPS *caps);+	typedef BOOLEAN (__stdcall *HidD_SetNumInputBuffers_)(HANDLE handle, ULONG number_buffers);++	static HidD_GetAttributes_ HidD_GetAttributes;+	static HidD_GetSerialNumberString_ HidD_GetSerialNumberString;+	static HidD_GetManufacturerString_ HidD_GetManufacturerString;+	static HidD_GetProductString_ HidD_GetProductString;+	static HidD_SetFeature_ HidD_SetFeature;+	static HidD_GetFeature_ HidD_GetFeature;+	static HidD_GetIndexedString_ HidD_GetIndexedString;+	static HidD_GetPreparsedData_ HidD_GetPreparsedData;+	static HidD_FreePreparsedData_ HidD_FreePreparsedData;+	static HidP_GetCaps_ HidP_GetCaps;+	static HidD_SetNumInputBuffers_ HidD_SetNumInputBuffers;++	static HMODULE lib_handle = NULL;+	static BOOLEAN initialized = FALSE;+#endif /* HIDAPI_USE_DDK */++struct hid_device_ {+		HANDLE device_handle;+		BOOL blocking;+		USHORT output_report_length;+		size_t input_report_length;+		void *last_error_str;+		DWORD last_error_num;+		BOOL read_pending;+		char *read_buf;+		OVERLAPPED ol;+};++static hid_device *new_hid_device()+{+	hid_device *dev = (hid_device*) calloc(1, sizeof(hid_device));+	dev->device_handle = INVALID_HANDLE_VALUE;+	dev->blocking = TRUE;+	dev->output_report_length = 0;+	dev->input_report_length = 0;+	dev->last_error_str = NULL;+	dev->last_error_num = 0;+	dev->read_pending = FALSE;+	dev->read_buf = NULL;+	memset(&dev->ol, 0, sizeof(dev->ol));+	dev->ol.hEvent = CreateEvent(NULL, FALSE, FALSE /*inital state f=nonsignaled*/, NULL);++	return dev;+}++static void free_hid_device(hid_device *dev)+{+	CloseHandle(dev->ol.hEvent);+	CloseHandle(dev->device_handle);+	LocalFree(dev->last_error_str);+	free(dev->read_buf);+	free(dev);+}++static void register_error(hid_device *device, const char *op)+{+	WCHAR *ptr, *msg;++	FormatMessageW(FORMAT_MESSAGE_ALLOCATE_BUFFER |+		FORMAT_MESSAGE_FROM_SYSTEM |+		FORMAT_MESSAGE_IGNORE_INSERTS,+		NULL,+		GetLastError(),+		MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),+		(LPVOID)&msg, 0/*sz*/,+		NULL);+	+	/* Get rid of the CR and LF that FormatMessage() sticks at the+	   end of the message. Thanks Microsoft! */+	ptr = msg;+	while (*ptr) {+		if (*ptr == '\r') {+			*ptr = 0x0000;+			break;+		}+		ptr++;+	}++	/* Store the message off in the Device entry so that+	   the hid_error() function can pick it up. */+	LocalFree(device->last_error_str);+	device->last_error_str = msg;+}++#ifndef HIDAPI_USE_DDK+static int lookup_functions()+{+	lib_handle = LoadLibraryA("hid.dll");+	if (lib_handle) {+#define RESOLVE(x) x = (x##_)GetProcAddress(lib_handle, #x); if (!x) return -1;+		RESOLVE(HidD_GetAttributes);+		RESOLVE(HidD_GetSerialNumberString);+		RESOLVE(HidD_GetManufacturerString);+		RESOLVE(HidD_GetProductString);+		RESOLVE(HidD_SetFeature);+		RESOLVE(HidD_GetFeature);+		RESOLVE(HidD_GetIndexedString);+		RESOLVE(HidD_GetPreparsedData);+		RESOLVE(HidD_FreePreparsedData);+		RESOLVE(HidP_GetCaps);+		RESOLVE(HidD_SetNumInputBuffers);+#undef RESOLVE+	}+	else+		return -1;++	return 0;+}+#endif++static HANDLE open_device(const char *path, BOOL enumerate)+{+	HANDLE handle;+	DWORD desired_access = (enumerate)? 0: (GENERIC_WRITE | GENERIC_READ);+	DWORD share_mode = (enumerate)?+	                      FILE_SHARE_READ|FILE_SHARE_WRITE:+	                      FILE_SHARE_READ;++	handle = CreateFileA(path,+		desired_access,+		share_mode,+		NULL,+		OPEN_EXISTING,+		FILE_FLAG_OVERLAPPED,/*FILE_ATTRIBUTE_NORMAL,*/+		0);++	return handle;+}++int HID_API_EXPORT hid_init(void)+{+#ifndef HIDAPI_USE_DDK+	if (!initialized) {+		if (lookup_functions() < 0) {+			hid_exit();+			return -1;+		}+		initialized = TRUE;+	}+#endif+	return 0;+}++int HID_API_EXPORT hid_exit(void)+{+#ifndef HIDAPI_USE_DDK+	if (lib_handle)+		FreeLibrary(lib_handle);+	lib_handle = NULL;+	initialized = FALSE;+#endif+	return 0;+}++struct hid_device_info HID_API_EXPORT * HID_API_CALL hid_enumerate(unsigned short vendor_id, unsigned short product_id)+{+	BOOL res;+	struct hid_device_info *root = NULL; /* return object */+	struct hid_device_info *cur_dev = NULL;++	/* Windows objects for interacting with the driver. */+	GUID InterfaceClassGuid = {0x4d1e55b2, 0xf16f, 0x11cf, {0x88, 0xcb, 0x00, 0x11, 0x11, 0x00, 0x00, 0x30} };+	SP_DEVINFO_DATA devinfo_data;+	SP_DEVICE_INTERFACE_DATA device_interface_data;+	SP_DEVICE_INTERFACE_DETAIL_DATA_A *device_interface_detail_data = NULL;+	HDEVINFO device_info_set = INVALID_HANDLE_VALUE;+	int device_index = 0;+	int i;++	if (hid_init() < 0)+		return NULL;++	/* Initialize the Windows objects. */+	memset(&devinfo_data, 0x0, sizeof(devinfo_data));+	devinfo_data.cbSize = sizeof(SP_DEVINFO_DATA);+	device_interface_data.cbSize = sizeof(SP_DEVICE_INTERFACE_DATA);++	/* Get information for all the devices belonging to the HID class. */+	device_info_set = SetupDiGetClassDevsA(&InterfaceClassGuid, NULL, NULL, DIGCF_PRESENT | DIGCF_DEVICEINTERFACE);+	+	/* Iterate over each device in the HID class, looking for the right one. */+	+	for (;;) {+		HANDLE write_handle = INVALID_HANDLE_VALUE;+		DWORD required_size = 0;+		HIDD_ATTRIBUTES attrib;++		res = SetupDiEnumDeviceInterfaces(device_info_set,+			NULL,+			&InterfaceClassGuid,+			device_index,+			&device_interface_data);+		+		if (!res) {+			/* A return of FALSE from this function means that+			   there are no more devices. */+			break;+		}++		/* Call with 0-sized detail size, and let the function+		   tell us how long the detail struct needs to be. The+		   size is put in &required_size. */+		res = SetupDiGetDeviceInterfaceDetailA(device_info_set,+			&device_interface_data,+			NULL,+			0,+			&required_size,+			NULL);++		/* Allocate a long enough structure for device_interface_detail_data. */+		device_interface_detail_data = (SP_DEVICE_INTERFACE_DETAIL_DATA_A*) malloc(required_size);+		device_interface_detail_data->cbSize = sizeof(SP_DEVICE_INTERFACE_DETAIL_DATA_A);++		/* Get the detailed data for this device. The detail data gives us+		   the device path for this device, which is then passed into+		   CreateFile() to get a handle to the device. */+		res = SetupDiGetDeviceInterfaceDetailA(device_info_set,+			&device_interface_data,+			device_interface_detail_data,+			required_size,+			NULL,+			NULL);++		if (!res) {+			/* register_error(dev, "Unable to call SetupDiGetDeviceInterfaceDetail");+			   Continue to the next device. */+			goto cont;+		}++		/* Make sure this device is of Setup Class "HIDClass" and has a+		   driver bound to it. */+		for (i = 0; ; i++) {+			char driver_name[256];++			/* Populate devinfo_data. This function will return failure+			   when there are no more interfaces left. */+			res = SetupDiEnumDeviceInfo(device_info_set, i, &devinfo_data);+			if (!res)+				goto cont;++			res = SetupDiGetDeviceRegistryPropertyA(device_info_set, &devinfo_data,+			               SPDRP_CLASS, NULL, (PBYTE)driver_name, sizeof(driver_name), NULL);+			if (!res)+				goto cont;++			if (strcmp(driver_name, "HIDClass") == 0) {+				/* See if there's a driver bound. */+				res = SetupDiGetDeviceRegistryPropertyA(device_info_set, &devinfo_data,+				           SPDRP_DRIVER, NULL, (PBYTE)driver_name, sizeof(driver_name), NULL);+				if (res)+					break;+			}+		}++		//wprintf(L"HandleName: %s\n", device_interface_detail_data->DevicePath);++		/* Open a handle to the device */+		write_handle = open_device(device_interface_detail_data->DevicePath, TRUE);++		/* Check validity of write_handle. */+		if (write_handle == INVALID_HANDLE_VALUE) {+			/* Unable to open the device. */+			//register_error(dev, "CreateFile");+			goto cont_close;+		}		+++		/* Get the Vendor ID and Product ID for this device. */+		attrib.Size = sizeof(HIDD_ATTRIBUTES);+		HidD_GetAttributes(write_handle, &attrib);+		//wprintf(L"Product/Vendor: %x %x\n", attrib.ProductID, attrib.VendorID);++		/* Check the VID/PID to see if we should add this+		   device to the enumeration list. */+		if ((vendor_id == 0x0 || attrib.VendorID == vendor_id) &&+		    (product_id == 0x0 || attrib.ProductID == product_id)) {++			#define WSTR_LEN 512+			const char *str;+			struct hid_device_info *tmp;+			PHIDP_PREPARSED_DATA pp_data = NULL;+			HIDP_CAPS caps;+			BOOLEAN res;+			NTSTATUS nt_res;+			wchar_t wstr[WSTR_LEN]; /* TODO: Determine Size */+			size_t len;++			/* VID/PID match. Create the record. */+			tmp = (struct hid_device_info*) calloc(1, sizeof(struct hid_device_info));+			if (cur_dev) {+				cur_dev->next = tmp;+			}+			else {+				root = tmp;+			}+			cur_dev = tmp;++			/* Get the Usage Page and Usage for this device. */+			res = HidD_GetPreparsedData(write_handle, &pp_data);+			if (res) {+				nt_res = HidP_GetCaps(pp_data, &caps);+				if (nt_res == HIDP_STATUS_SUCCESS) {+					cur_dev->usage_page = caps.UsagePage;+					cur_dev->usage = caps.Usage;+				}++				HidD_FreePreparsedData(pp_data);+			}+			+			/* Fill out the record */+			cur_dev->next = NULL;+			str = device_interface_detail_data->DevicePath;+			if (str) {+				len = strlen(str);+				cur_dev->path = (char*) calloc(len+1, sizeof(char));+				strncpy(cur_dev->path, str, len+1);+				cur_dev->path[len] = '\0';+			}+			else+				cur_dev->path = NULL;++			/* Serial Number */+			res = HidD_GetSerialNumberString(write_handle, wstr, sizeof(wstr));+			wstr[WSTR_LEN-1] = 0x0000;+			if (res) {+				cur_dev->serial_number = _wcsdup(wstr);+			}++			/* Manufacturer String */+			res = HidD_GetManufacturerString(write_handle, wstr, sizeof(wstr));+			wstr[WSTR_LEN-1] = 0x0000;+			if (res) {+				cur_dev->manufacturer_string = _wcsdup(wstr);+			}++			/* Product String */+			res = HidD_GetProductString(write_handle, wstr, sizeof(wstr));+			wstr[WSTR_LEN-1] = 0x0000;+			if (res) {+				cur_dev->product_string = _wcsdup(wstr);+			}++			/* VID/PID */+			cur_dev->vendor_id = attrib.VendorID;+			cur_dev->product_id = attrib.ProductID;++			/* Release Number */+			cur_dev->release_number = attrib.VersionNumber;++			/* Interface Number. It can sometimes be parsed out of the path+			   on Windows if a device has multiple interfaces. See+			   http://msdn.microsoft.com/en-us/windows/hardware/gg487473 or+			   search for "Hardware IDs for HID Devices" at MSDN. If it's not+			   in the path, it's set to -1. */+			cur_dev->interface_number = -1;+			if (cur_dev->path) {+				char *interface_component = strstr(cur_dev->path, "&mi_");+				if (interface_component) {+					char *hex_str = interface_component + 4;+					char *endptr = NULL;+					cur_dev->interface_number = strtol(hex_str, &endptr, 16);+					if (endptr == hex_str) {+						/* The parsing failed. Set interface_number to -1. */+						cur_dev->interface_number = -1;+					}+				}+			}+		}++cont_close:+		CloseHandle(write_handle);+cont:+		/* We no longer need the detail data. It can be freed */+		free(device_interface_detail_data);++		device_index++;++	}++	/* Close the device information handle. */+	SetupDiDestroyDeviceInfoList(device_info_set);++	return root;++}++void  HID_API_EXPORT HID_API_CALL hid_free_enumeration(struct hid_device_info *devs)+{+	/* TODO: Merge this with the Linux version. This function is platform-independent. */+	struct hid_device_info *d = devs;+	while (d) {+		struct hid_device_info *next = d->next;+		free(d->path);+		free(d->serial_number);+		free(d->manufacturer_string);+		free(d->product_string);+		free(d);+		d = next;+	}+}+++HID_API_EXPORT hid_device * HID_API_CALL hid_open(unsigned short vendor_id, unsigned short product_id, const wchar_t *serial_number)+{+	/* TODO: Merge this functions with the Linux version. This function should be platform independent. */+	struct hid_device_info *devs, *cur_dev;+	const char *path_to_open = NULL;+	hid_device *handle = NULL;+	+	devs = hid_enumerate(vendor_id, product_id);+	cur_dev = devs;+	while (cur_dev) {+		if (cur_dev->vendor_id == vendor_id &&+		    cur_dev->product_id == product_id) {+			if (serial_number) {+				if (wcscmp(serial_number, cur_dev->serial_number) == 0) {+					path_to_open = cur_dev->path;+					break;+				}+			}+			else {+				path_to_open = cur_dev->path;+				break;+			}+		}+		cur_dev = cur_dev->next;+	}++	if (path_to_open) {+		/* Open the device */+		handle = hid_open_path(path_to_open);+	}++	hid_free_enumeration(devs);+	+	return handle;+}++HID_API_EXPORT hid_device * HID_API_CALL hid_open_path(const char *path)+{+	hid_device *dev;+	HIDP_CAPS caps;+	PHIDP_PREPARSED_DATA pp_data = NULL;+	BOOLEAN res;+	NTSTATUS nt_res;++	if (hid_init() < 0) {+		return NULL;+	}++	dev = new_hid_device();++	/* Open a handle to the device */+	dev->device_handle = open_device(path, FALSE);++	/* Check validity of write_handle. */+	if (dev->device_handle == INVALID_HANDLE_VALUE) {+		/* Unable to open the device. */+		register_error(dev, "CreateFile");+		goto err;+	}++	/* Set the Input Report buffer size to 64 reports. */+	res = HidD_SetNumInputBuffers(dev->device_handle, 64);+	if (!res) {+		register_error(dev, "HidD_SetNumInputBuffers");+		goto err;+	}++	/* Get the Input Report length for the device. */+	res = HidD_GetPreparsedData(dev->device_handle, &pp_data);+	if (!res) {+		register_error(dev, "HidD_GetPreparsedData");+		goto err;+	}+	nt_res = HidP_GetCaps(pp_data, &caps);+	if (nt_res != HIDP_STATUS_SUCCESS) {+		register_error(dev, "HidP_GetCaps");	+		goto err_pp_data;+	}+	dev->output_report_length = caps.OutputReportByteLength;+	dev->input_report_length = caps.InputReportByteLength;+	HidD_FreePreparsedData(pp_data);++	dev->read_buf = (char*) malloc(dev->input_report_length);++	return dev;++err_pp_data:+		HidD_FreePreparsedData(pp_data);+err:	+		free_hid_device(dev);+		return NULL;+}++int HID_API_EXPORT HID_API_CALL hid_write(hid_device *dev, const unsigned char *data, size_t length)+{+	DWORD bytes_written;+	BOOL res;++	OVERLAPPED ol;+	unsigned char *buf;+	memset(&ol, 0, sizeof(ol));++	/* Make sure the right number of bytes are passed to WriteFile. Windows+	   expects the number of bytes which are in the _longest_ report (plus+	   one for the report number) bytes even if the data is a report+	   which is shorter than that. Windows gives us this value in+	   caps.OutputReportByteLength. If a user passes in fewer bytes than this,+	   create a temporary buffer which is the proper size. */+	if (length >= dev->output_report_length) {+		/* The user passed the right number of bytes. Use the buffer as-is. */+		buf = (unsigned char *) data;+	} else {+		/* Create a temporary buffer and copy the user's data+		   into it, padding the rest with zeros. */+		buf = (unsigned char *) malloc(dev->output_report_length);+		memcpy(buf, data, length);+		memset(buf + length, 0, dev->output_report_length - length);+		length = dev->output_report_length;+	}++	res = WriteFile(dev->device_handle, buf, length, NULL, &ol);+	+	if (!res) {+		if (GetLastError() != ERROR_IO_PENDING) {+			/* WriteFile() failed. Return error. */+			register_error(dev, "WriteFile");+			bytes_written = -1;+			goto end_of_function;+		}+	}++	/* Wait here until the write is done. This makes+	   hid_write() synchronous. */+	res = GetOverlappedResult(dev->device_handle, &ol, &bytes_written, TRUE/*wait*/);+	if (!res) {+		/* The Write operation failed. */+		register_error(dev, "WriteFile");+		bytes_written = -1;+		goto end_of_function;+	}++end_of_function:+	if (buf != data)+		free(buf);++	return bytes_written;+}+++int HID_API_EXPORT HID_API_CALL hid_read_timeout(hid_device *dev, unsigned char *data, size_t length, int milliseconds)+{+	DWORD bytes_read = 0;+	size_t copy_len = 0;+	BOOL res;++	/* Copy the handle for convenience. */+	HANDLE ev = dev->ol.hEvent;++	if (!dev->read_pending) {+		/* Start an Overlapped I/O read. */+		dev->read_pending = TRUE;+		memset(dev->read_buf, 0, dev->input_report_length);+		ResetEvent(ev);+		res = ReadFile(dev->device_handle, dev->read_buf, dev->input_report_length, &bytes_read, &dev->ol);+		+		if (!res) {+			if (GetLastError() != ERROR_IO_PENDING) {+				/* ReadFile() has failed.+				   Clean up and return error. */+				CancelIo(dev->device_handle);+				dev->read_pending = FALSE;+				goto end_of_function;+			}+		}+	}++	if (milliseconds >= 0) {+		/* See if there is any data yet. */+		res = WaitForSingleObject(ev, milliseconds);+		if (res != WAIT_OBJECT_0) {+			/* There was no data this time. Return zero bytes available,+			   but leave the Overlapped I/O running. */+			return 0;+		}+	}++	/* Either WaitForSingleObject() told us that ReadFile has completed, or+	   we are in non-blocking mode. Get the number of bytes read. The actual+	   data has been copied to the data[] array which was passed to ReadFile(). */+	res = GetOverlappedResult(dev->device_handle, &dev->ol, &bytes_read, TRUE/*wait*/);+	+	/* Set pending back to false, even if GetOverlappedResult() returned error. */+	dev->read_pending = FALSE;++	if (res && bytes_read > 0) {+		if (dev->read_buf[0] == 0x0) {+			/* If report numbers aren't being used, but Windows sticks a report+			   number (0x0) on the beginning of the report anyway. To make this+			   work like the other platforms, and to make it work more like the+			   HID spec, we'll skip over this byte. */+			bytes_read--;+			copy_len = length > bytes_read ? bytes_read : length;+			memcpy(data, dev->read_buf+1, copy_len);+		}+		else {+			/* Copy the whole buffer, report number and all. */+			copy_len = length > bytes_read ? bytes_read : length;+			memcpy(data, dev->read_buf, copy_len);+		}+	}+	+end_of_function:+	if (!res) {+		register_error(dev, "GetOverlappedResult");+		return -1;+	}+	+	return copy_len;+}++int HID_API_EXPORT HID_API_CALL hid_read(hid_device *dev, unsigned char *data, size_t length)+{+	return hid_read_timeout(dev, data, length, (dev->blocking)? -1: 0);+}++int HID_API_EXPORT HID_API_CALL hid_set_nonblocking(hid_device *dev, int nonblock)+{+	dev->blocking = !nonblock;+	return 0; /* Success */+}++int HID_API_EXPORT HID_API_CALL hid_send_feature_report(hid_device *dev, const unsigned char *data, size_t length)+{+	BOOL res = HidD_SetFeature(dev->device_handle, (PVOID)data, length);+	if (!res) {+		register_error(dev, "HidD_SetFeature");+		return -1;+	}++	return length;+}+++int HID_API_EXPORT HID_API_CALL hid_get_feature_report(hid_device *dev, unsigned char *data, size_t length)+{+	BOOL res;+#if 0+	res = HidD_GetFeature(dev->device_handle, data, length);+	if (!res) {+		register_error(dev, "HidD_GetFeature");+		return -1;+	}+	return 0; /* HidD_GetFeature() doesn't give us an actual length, unfortunately */+#else+	DWORD bytes_returned;++	OVERLAPPED ol;+	memset(&ol, 0, sizeof(ol));++	res = DeviceIoControl(dev->device_handle,+		IOCTL_HID_GET_FEATURE,+		data, length,+		data, length,+		&bytes_returned, &ol);++	if (!res) {+		if (GetLastError() != ERROR_IO_PENDING) {+			/* DeviceIoControl() failed. Return error. */+			register_error(dev, "Send Feature Report DeviceIoControl");+			return -1;+		}+	}++	/* Wait here until the write is done. This makes+	   hid_get_feature_report() synchronous. */+	res = GetOverlappedResult(dev->device_handle, &ol, &bytes_returned, TRUE/*wait*/);+	if (!res) {+		/* The operation failed. */+		register_error(dev, "Send Feature Report GetOverLappedResult");+		return -1;+	}++	/* bytes_returned does not include the first byte which contains the+	   report ID. The data buffer actually contains one more byte than+	   bytes_returned. */+	bytes_returned++;++	return bytes_returned;+#endif+}++void HID_API_EXPORT HID_API_CALL hid_close(hid_device *dev)+{+	if (!dev)+		return;+	CancelIo(dev->device_handle);+	free_hid_device(dev);+}++int HID_API_EXPORT_CALL HID_API_CALL hid_get_manufacturer_string(hid_device *dev, wchar_t *string, size_t maxlen)+{+	BOOL res;++	res = HidD_GetManufacturerString(dev->device_handle, string, sizeof(wchar_t) * maxlen);+	if (!res) {+		register_error(dev, "HidD_GetManufacturerString");+		return -1;+	}++	return 0;+}++int HID_API_EXPORT_CALL HID_API_CALL hid_get_product_string(hid_device *dev, wchar_t *string, size_t maxlen)+{+	BOOL res;++	res = HidD_GetProductString(dev->device_handle, string, sizeof(wchar_t) * maxlen);+	if (!res) {+		register_error(dev, "HidD_GetProductString");+		return -1;+	}++	return 0;+}++int HID_API_EXPORT_CALL HID_API_CALL hid_get_serial_number_string(hid_device *dev, wchar_t *string, size_t maxlen)+{+	BOOL res;++	res = HidD_GetSerialNumberString(dev->device_handle, string, sizeof(wchar_t) * maxlen);+	if (!res) {+		register_error(dev, "HidD_GetSerialNumberString");+		return -1;+	}++	return 0;+}++int HID_API_EXPORT_CALL HID_API_CALL hid_get_indexed_string(hid_device *dev, int string_index, wchar_t *string, size_t maxlen)+{+	BOOL res;++	res = HidD_GetIndexedString(dev->device_handle, string_index, string, sizeof(wchar_t) * maxlen);+	if (!res) {+		register_error(dev, "HidD_GetIndexedString");+		return -1;+	}++	return 0;+}+++HID_API_EXPORT const wchar_t * HID_API_CALL  hid_error(hid_device *dev)+{+	return (wchar_t*)dev->last_error_str;+}+++/*#define PICPGM*/+/*#define S11*/+#define P32+#ifdef S11 +  unsigned short VendorID = 0xa0a0;+	unsigned short ProductID = 0x0001;+#endif++#ifdef P32+  unsigned short VendorID = 0x04d8;+	unsigned short ProductID = 0x3f;+#endif+++#ifdef PICPGM+  unsigned short VendorID = 0x04d8;+  unsigned short ProductID = 0x0033;+#endif+++#if 0+int __cdecl main(int argc, char* argv[])+{+	int res;+	unsigned char buf[65];++	UNREFERENCED_PARAMETER(argc);+	UNREFERENCED_PARAMETER(argv);++	/* Set up the command buffer. */+	memset(buf,0x00,sizeof(buf));+	buf[0] = 0;+	buf[1] = 0x81;+	++	/* Open the device. */+	int handle = open(VendorID, ProductID, L"12345");+	if (handle < 0)+		printf("unable to open device\n");+++	/* Toggle LED (cmd 0x80) */+	buf[1] = 0x80;+	res = write(handle, buf, 65);+	if (res < 0)+		printf("Unable to write()\n");++	/* Request state (cmd 0x81) */+	buf[1] = 0x81;+	write(handle, buf, 65);+	if (res < 0)+		printf("Unable to write() (2)\n");++	/* Read requested state */+	read(handle, buf, 65);+	if (res < 0)+		printf("Unable to read()\n");++	/* Print out the returned buffer. */+	for (int i = 0; i < 4; i++)+		printf("buf[%d]: %d\n", i, buf[i]);++	return 0;+}+#endif++#ifdef __cplusplus+} /* extern "C" */+#endif
− cbits/linux/hid.c
@@ -1,795 +0,0 @@-/*******************************************************- HIDAPI - Multi-Platform library for- communication with HID devices.-- Alan Ott- Signal 11 Software-- 8/22/2009- Linux Version - 6/2/2009-- Copyright 2009, All Rights Reserved.-- At the discretion of the user of this library,- this software may be licensed under the terms of the- GNU General Public License v3, a BSD-Style license, or the- original HIDAPI license as outlined in the LICENSE.txt,- LICENSE-gpl3.txt, LICENSE-bsd.txt, and LICENSE-orig.txt- files located at the root of the source distribution.- These files may also be found in the public source- code repository located at:-        http://github.com/signal11/hidapi .-********************************************************/--/* C */-#include <stdio.h>-#include <string.h>-#include <stdlib.h>-#include <locale.h>-#include <errno.h>--/* Unix */-#include <unistd.h>-#include <sys/types.h>-#include <sys/stat.h>-#include <sys/ioctl.h>-#include <sys/utsname.h>-#include <fcntl.h>-#include <poll.h>--/* Linux */-#include <linux/hidraw.h>-#include <linux/version.h>-#include <linux/input.h>-#include <libudev.h>--#include "hidapi.h"--/* Definitions from linux/hidraw.h. Since these are new, some distros-   may not have header files which contain them. */-#ifndef HIDIOCSFEATURE-#define HIDIOCSFEATURE(len)    _IOC(_IOC_WRITE|_IOC_READ, 'H', 0x06, len)-#endif-#ifndef HIDIOCGFEATURE-#define HIDIOCGFEATURE(len)    _IOC(_IOC_WRITE|_IOC_READ, 'H', 0x07, len)-#endif---/* USB HID device property names */-const char *device_string_names[] = {-	"manufacturer",-	"product",-	"serial",-};--/* Symbolic names for the properties above */-enum device_string_id {-	DEVICE_STRING_MANUFACTURER,-	DEVICE_STRING_PRODUCT,-	DEVICE_STRING_SERIAL,--	DEVICE_STRING_COUNT,-};--struct hid_device_ {-	int device_handle;-	int blocking;-	int uses_numbered_reports;-};---static __u32 kernel_version = 0;--static __u32 detect_kernel_version(void)-{-	struct utsname name;-	int major, minor, release;-	int ret;--	uname(&name);-	ret = sscanf(name.release, "%d.%d.%d", &major, &minor, &release);-	if (ret == 3) {-		return KERNEL_VERSION(major, minor, release);-	}--	ret = sscanf(name.release, "%d.%d", &major, &minor);-	if (ret == 2) {-		return KERNEL_VERSION(major, minor, 0);-	}--	printf("Couldn't determine kernel version from version string \"%s\"\n", name.release);-	return 0;-}--static hid_device *new_hid_device(void)-{-	hid_device *dev = calloc(1, sizeof(hid_device));-	dev->device_handle = -1;-	dev->blocking = 1;-	dev->uses_numbered_reports = 0;--	return dev;-}---/* The caller must free the returned string with free(). */-static wchar_t *utf8_to_wchar_t(const char *utf8)-{-	wchar_t *ret = NULL;--	if (utf8) {-		size_t wlen = mbstowcs(NULL, utf8, 0);-		if ((size_t) -1 == wlen) {-			return wcsdup(L"");-		}-		ret = calloc(wlen+1, sizeof(wchar_t));-		mbstowcs(ret, utf8, wlen+1);-		ret[wlen] = 0x0000;-	}--	return ret;-}--/* Get an attribute value from a udev_device and return it as a whar_t-   string. The returned string must be freed with free() when done.*/-static wchar_t *copy_udev_string(struct udev_device *dev, const char *udev_name)-{-	return utf8_to_wchar_t(udev_device_get_sysattr_value(dev, udev_name));-}--/* uses_numbered_reports() returns 1 if report_descriptor describes a device-   which contains numbered reports. */-static int uses_numbered_reports(__u8 *report_descriptor, __u32 size) {-	unsigned int i = 0;-	int size_code;-	int data_len, key_size;--	while (i < size) {-		int key = report_descriptor[i];--		/* Check for the Report ID key */-		if (key == 0x85/*Report ID*/) {-			/* This device has a Report ID, which means it uses-			   numbered reports. */-			return 1;-		}--		//printf("key: %02hhx\n", key);--		if ((key & 0xf0) == 0xf0) {-			/* This is a Long Item. The next byte contains the-			   length of the data section (value) for this key.-			   See the HID specification, version 1.11, section-			   6.2.2.3, titled "Long Items." */-			if (i+1 < size)-				data_len = report_descriptor[i+1];-			else-				data_len = 0; /* malformed report */-			key_size = 3;-		}-		else {-			/* This is a Short Item. The bottom two bits of the-			   key contain the size code for the data section-			   (value) for this key.  Refer to the HID-			   specification, version 1.11, section 6.2.2.2,-			   titled "Short Items." */-			size_code = key & 0x3;-			switch (size_code) {-			case 0:-			case 1:-			case 2:-				data_len = size_code;-				break;-			case 3:-				data_len = 4;-				break;-			default:-				/* Can't ever happen since size_code is & 0x3 */-				data_len = 0;-				break;-			};-			key_size = 1;-		}--		/* Skip over this key and it's associated data */-		i += data_len + key_size;-	}--	/* Didn't find a Report ID key. Device doesn't use numbered reports. */-	return 0;-}--/*- * The caller is responsible for free()ing the (newly-allocated) character- * strings pointed to by serial_number_utf8 and product_name_utf8 after use.- */-static int-parse_uevent_info(const char *uevent, int *bus_type,-	unsigned short *vendor_id, unsigned short *product_id,-	char **serial_number_utf8, char **product_name_utf8)-{-	char *tmp = strdup(uevent);-	char *saveptr = NULL;-	char *line;-	char *key;-	char *value;--	int found_id = 0;-	int found_serial = 0;-	int found_name = 0;--	line = strtok_r(tmp, "\n", &saveptr);-	while (line != NULL) {-		/* line: "KEY=value" */-		key = line;-		value = strchr(line, '=');-		if (!value) {-			goto next_line;-		}-		*value = '\0';-		value++;--		if (strcmp(key, "HID_ID") == 0) {-			/**-			 *        type vendor   product-			 * HID_ID=0003:000005AC:00008242-			 **/-			int ret = sscanf(value, "%x:%hx:%hx", bus_type, vendor_id, product_id);-			if (ret == 3) {-				found_id = 1;-			}-		} else if (strcmp(key, "HID_NAME") == 0) {-			/* The caller has to free the product name */-			*product_name_utf8 = strdup(value);-			found_name = 1;-		} else if (strcmp(key, "HID_UNIQ") == 0) {-			/* The caller has to free the serial number */-			*serial_number_utf8 = strdup(value);-			found_serial = 1;-		}--next_line:-		line = strtok_r(NULL, "\n", &saveptr);-	}--	free(tmp);-	return (found_id && found_name && found_serial);-}---static int get_device_string(hid_device *dev, enum device_string_id key, wchar_t *string, size_t maxlen)-{-	struct udev *udev;-	struct udev_device *udev_dev, *parent, *hid_dev;-	struct stat s;-	int ret = -1;-        char *serial_number_utf8 = NULL;-        char *product_name_utf8 = NULL;--	/* Create the udev object */-	udev = udev_new();-	if (!udev) {-		printf("Can't create udev\n");-		return -1;-	}--	/* Get the dev_t (major/minor numbers) from the file handle. */-	fstat(dev->device_handle, &s);-	/* Open a udev device from the dev_t. 'c' means character device. */-	udev_dev = udev_device_new_from_devnum(udev, 'c', s.st_rdev);-	if (udev_dev) {-		hid_dev = udev_device_get_parent_with_subsystem_devtype(-			udev_dev,-			"hid",-			NULL);-		if (hid_dev) {-			unsigned short dev_vid;-			unsigned short dev_pid;-			int bus_type;-			size_t retm;--			ret = parse_uevent_info(-			           udev_device_get_sysattr_value(hid_dev, "uevent"),-			           &bus_type,-			           &dev_vid,-			           &dev_pid,-			           &serial_number_utf8,-			           &product_name_utf8);--			if (bus_type == BUS_BLUETOOTH) {-				switch (key) {-					case DEVICE_STRING_MANUFACTURER:-						wcsncpy(string, L"", maxlen);-						ret = 0;-						break;-					case DEVICE_STRING_PRODUCT:-						retm = mbstowcs(string, product_name_utf8, maxlen);-						ret = (retm == (size_t)-1)? -1: 0;-						break;-					case DEVICE_STRING_SERIAL:-						retm = mbstowcs(string, serial_number_utf8, maxlen);-						ret = (retm == (size_t)-1)? -1: 0;-						break;-					case DEVICE_STRING_COUNT:-					default:-						ret = -1;-						break;-				}-			}-			else {-				/* This is a USB device. Find its parent USB Device node. */-				parent = udev_device_get_parent_with_subsystem_devtype(-					   udev_dev,-					   "usb",-					   "usb_device");-				if (parent) {-					const char *str;-					const char *key_str = NULL;--					if (key >= 0 && key < DEVICE_STRING_COUNT) {-						key_str = device_string_names[key];-					} else {-						ret = -1;-						goto end;-					}--					str = udev_device_get_sysattr_value(parent, key_str);-					if (str) {-						/* Convert the string from UTF-8 to wchar_t */-						retm = mbstowcs(string, str, maxlen);-						ret = (retm == (size_t)-1)? -1: 0;-						goto end;-					}-				}-			}-		}-	}--end:-        free(serial_number_utf8);-        free(product_name_utf8);--	udev_device_unref(udev_dev);-	/* parent and hid_dev don't need to be (and can't be) unref'd.-	   I'm not sure why, but they'll throw double-free() errors. */-	udev_unref(udev);--	return ret;-}--int HID_API_EXPORT hid_init(void)-{-	const char *locale;--	/* Set the locale if it's not set. */-	locale = setlocale(LC_CTYPE, NULL);-	if (!locale)-		setlocale(LC_CTYPE, "");--	kernel_version = detect_kernel_version();--	return 0;-}--int HID_API_EXPORT hid_exit(void)-{-	/* Nothing to do for this in the Linux/hidraw implementation. */-	return 0;-}---struct hid_device_info  HID_API_EXPORT *hid_enumerate(unsigned short vendor_id, unsigned short product_id)-{-	struct udev *udev;-	struct udev_enumerate *enumerate;-	struct udev_list_entry *devices, *dev_list_entry;--	struct hid_device_info *root = NULL; /* return object */-	struct hid_device_info *cur_dev = NULL;-	struct hid_device_info *prev_dev = NULL; /* previous device */--	hid_init();--	/* Create the udev object */-	udev = udev_new();-	if (!udev) {-		printf("Can't create udev\n");-		return NULL;-	}--	/* Create a list of the devices in the 'hidraw' subsystem. */-	enumerate = udev_enumerate_new(udev);-	udev_enumerate_add_match_subsystem(enumerate, "hidraw");-	udev_enumerate_scan_devices(enumerate);-	devices = udev_enumerate_get_list_entry(enumerate);-	/* For each item, see if it matches the vid/pid, and if so-	   create a udev_device record for it */-	udev_list_entry_foreach(dev_list_entry, devices) {-		const char *sysfs_path;-		const char *dev_path;-		const char *str;-		struct udev_device *raw_dev; /* The device's hidraw udev node. */-		struct udev_device *hid_dev; /* The device's HID udev node. */-		struct udev_device *usb_dev; /* The device's USB udev node. */-		struct udev_device *intf_dev; /* The device's interface (in the USB sense). */-		unsigned short dev_vid;-		unsigned short dev_pid;-		char *serial_number_utf8 = NULL;-		char *product_name_utf8 = NULL;-		int bus_type;-		int result;--		/* Get the filename of the /sys entry for the device-		   and create a udev_device object (dev) representing it */-		sysfs_path = udev_list_entry_get_name(dev_list_entry);-		raw_dev = udev_device_new_from_syspath(udev, sysfs_path);-		dev_path = udev_device_get_devnode(raw_dev);--		hid_dev = udev_device_get_parent_with_subsystem_devtype(-			raw_dev,-			"hid",-			NULL);--		if (!hid_dev) {-			/* Unable to find parent hid device. */-			goto next;-		}--		result = parse_uevent_info(-			udev_device_get_sysattr_value(hid_dev, "uevent"),-			&bus_type,-			&dev_vid,-			&dev_pid,-			&serial_number_utf8,-			&product_name_utf8);--		if (!result) {-			/* parse_uevent_info() failed for at least one field. */-			goto next;-		}--		if (bus_type != BUS_USB && bus_type != BUS_BLUETOOTH) {-			/* We only know how to handle USB and BT devices. */-			goto next;-		}--		/* Check the VID/PID against the arguments */-		if ((vendor_id == 0x0 || vendor_id == dev_vid) &&-		    (product_id == 0x0 || product_id == dev_pid)) {-			struct hid_device_info *tmp;--			/* VID/PID match. Create the record. */-			tmp = malloc(sizeof(struct hid_device_info));-			if (cur_dev) {-				cur_dev->next = tmp;-			}-			else {-				root = tmp;-			}-			prev_dev = cur_dev;-			cur_dev = tmp;--			/* Fill out the record */-			cur_dev->next = NULL;-			cur_dev->path = dev_path? strdup(dev_path): NULL;--			/* VID/PID */-			cur_dev->vendor_id = dev_vid;-			cur_dev->product_id = dev_pid;--			/* Serial Number */-			cur_dev->serial_number = utf8_to_wchar_t(serial_number_utf8);--			/* Release Number */-			cur_dev->release_number = 0x0;--			/* Interface Number */-			cur_dev->interface_number = -1;--			switch (bus_type) {-				case BUS_USB:-					/* The device pointed to by raw_dev contains information about-					   the hidraw device. In order to get information about the-					   USB device, get the parent device with the-					   subsystem/devtype pair of "usb"/"usb_device". This will-					   be several levels up the tree, but the function will find-					   it. */-					usb_dev = udev_device_get_parent_with_subsystem_devtype(-							raw_dev,-							"usb",-							"usb_device");--					if (!usb_dev) {-						/* Free this device */-						free(cur_dev->serial_number);-						free(cur_dev->path);-						free(cur_dev);--						/* Take it off the device list. */-						if (prev_dev) {-							prev_dev->next = NULL;-							cur_dev = prev_dev;-						}-						else {-							cur_dev = root = NULL;-						}--						goto next;-					}--					/* Manufacturer and Product strings */-					cur_dev->manufacturer_string = copy_udev_string(usb_dev, device_string_names[DEVICE_STRING_MANUFACTURER]);-					cur_dev->product_string = copy_udev_string(usb_dev, device_string_names[DEVICE_STRING_PRODUCT]);--					/* Release Number */-					str = udev_device_get_sysattr_value(usb_dev, "bcdDevice");-					cur_dev->release_number = (str)? strtol(str, NULL, 16): 0x0;--					/* Get a handle to the interface's udev node. */-					intf_dev = udev_device_get_parent_with_subsystem_devtype(-							raw_dev,-							"usb",-							"usb_interface");-					if (intf_dev) {-						str = udev_device_get_sysattr_value(intf_dev, "bInterfaceNumber");-						cur_dev->interface_number = (str)? strtol(str, NULL, 16): -1;-					}--					break;--				case BUS_BLUETOOTH:-					/* Manufacturer and Product strings */-					cur_dev->manufacturer_string = wcsdup(L"");-					cur_dev->product_string = utf8_to_wchar_t(product_name_utf8);--					break;--				default:-					/* Unknown device type - this should never happen, as we-					 * check for USB and Bluetooth devices above */-					break;-			}-		}--	next:-		free(serial_number_utf8);-		free(product_name_utf8);-		udev_device_unref(raw_dev);-		/* hid_dev, usb_dev and intf_dev don't need to be (and can't be)-		   unref()d.  It will cause a double-free() error.  I'm not-		   sure why.  */-	}-	/* Free the enumerator and udev objects. */-	udev_enumerate_unref(enumerate);-	udev_unref(udev);--	return root;-}--void  HID_API_EXPORT hid_free_enumeration(struct hid_device_info *devs)-{-	struct hid_device_info *d = devs;-	while (d) {-		struct hid_device_info *next = d->next;-		free(d->path);-		free(d->serial_number);-		free(d->manufacturer_string);-		free(d->product_string);-		free(d);-		d = next;-	}-}--hid_device * hid_open(unsigned short vendor_id, unsigned short product_id, const wchar_t *serial_number)-{-	struct hid_device_info *devs, *cur_dev;-	const char *path_to_open = NULL;-	hid_device *handle = NULL;--	devs = hid_enumerate(vendor_id, product_id);-	cur_dev = devs;-	while (cur_dev) {-		if (cur_dev->vendor_id == vendor_id &&-		    cur_dev->product_id == product_id) {-			if (serial_number) {-				if (wcscmp(serial_number, cur_dev->serial_number) == 0) {-					path_to_open = cur_dev->path;-					break;-				}-			}-			else {-				path_to_open = cur_dev->path;-				break;-			}-		}-		cur_dev = cur_dev->next;-	}--	if (path_to_open) {-		/* Open the device */-		handle = hid_open_path(path_to_open);-	}--	hid_free_enumeration(devs);--	return handle;-}--hid_device * HID_API_EXPORT hid_open_path(const char *path)-{-	hid_device *dev = NULL;--	hid_init();--	dev = new_hid_device();--	/* OPEN HERE */-	dev->device_handle = open(path, O_RDWR);--	/* If we have a good handle, return it. */-	if (dev->device_handle > 0) {--		/* Get the report descriptor */-		int res, desc_size = 0;-		struct hidraw_report_descriptor rpt_desc;--		memset(&rpt_desc, 0x0, sizeof(rpt_desc));--		/* Get Report Descriptor Size */-		res = ioctl(dev->device_handle, HIDIOCGRDESCSIZE, &desc_size);-		if (res < 0)-			perror("HIDIOCGRDESCSIZE");---		/* Get Report Descriptor */-		rpt_desc.size = desc_size;-		res = ioctl(dev->device_handle, HIDIOCGRDESC, &rpt_desc);-		if (res < 0) {-			perror("HIDIOCGRDESC");-		} else {-			/* Determine if this device uses numbered reports. */-			dev->uses_numbered_reports =-				uses_numbered_reports(rpt_desc.value,-				                      rpt_desc.size);-		}--		return dev;-	}-	else {-		/* Unable to open any devices. */-		free(dev);-		return NULL;-	}-}---int HID_API_EXPORT hid_write(hid_device *dev, const unsigned char *data, size_t length)-{-	int bytes_written;--	bytes_written = write(dev->device_handle, data, length);--	return bytes_written;-}---int HID_API_EXPORT hid_read_timeout(hid_device *dev, unsigned char *data, size_t length, int milliseconds)-{-	int bytes_read;--	if (milliseconds >= 0) {-		/* Milliseconds is either 0 (non-blocking) or > 0 (contains-		   a valid timeout). In both cases we want to call poll()-		   and wait for data to arrive.  Don't rely on non-blocking-		   operation (O_NONBLOCK) since some kernels don't seem to-		   properly report device disconnection through read() when-		   in non-blocking mode.  */-		int ret;-		struct pollfd fds;--		fds.fd = dev->device_handle;-		fds.events = POLLIN;-		fds.revents = 0;-		ret = poll(&fds, 1, milliseconds);-		if (ret == -1 || ret == 0) {-			/* Error or timeout */-			return ret;-		}-		else {-			/* Check for errors on the file descriptor. This will-			   indicate a device disconnection. */-			if (fds.revents & (POLLERR | POLLHUP | POLLNVAL))-				return -1;-		}-	}--	bytes_read = read(dev->device_handle, data, length);-	if (bytes_read < 0 && (errno == EAGAIN || errno == EINPROGRESS))-		bytes_read = 0;--	if (bytes_read >= 0 &&-	    kernel_version != 0 &&-	    kernel_version < KERNEL_VERSION(2,6,34) &&-	    dev->uses_numbered_reports) {-		/* Work around a kernel bug. Chop off the first byte. */-		memmove(data, data+1, bytes_read);-		bytes_read--;-	}--	return bytes_read;-}--int HID_API_EXPORT hid_read(hid_device *dev, unsigned char *data, size_t length)-{-	return hid_read_timeout(dev, data, length, (dev->blocking)? -1: 0);-}--int HID_API_EXPORT hid_set_nonblocking(hid_device *dev, int nonblock)-{-	/* Do all non-blocking in userspace using poll(), since it looks-	   like there's a bug in the kernel in some versions where-	   read() will not return -1 on disconnection of the USB device */--	dev->blocking = !nonblock;-	return 0; /* Success */-}---int HID_API_EXPORT hid_send_feature_report(hid_device *dev, const unsigned char *data, size_t length)-{-	int res;--	res = ioctl(dev->device_handle, HIDIOCSFEATURE(length), data);-	if (res < 0)-		perror("ioctl (SFEATURE)");--	return res;-}--int HID_API_EXPORT hid_get_feature_report(hid_device *dev, unsigned char *data, size_t length)-{-	int res;--	res = ioctl(dev->device_handle, HIDIOCGFEATURE(length), data);-	if (res < 0)-		perror("ioctl (GFEATURE)");---	return res;-}---void HID_API_EXPORT hid_close(hid_device *dev)-{-	if (!dev)-		return;-	close(dev->device_handle);-	free(dev);-}---int HID_API_EXPORT_CALL hid_get_manufacturer_string(hid_device *dev, wchar_t *string, size_t maxlen)-{-	return get_device_string(dev, DEVICE_STRING_MANUFACTURER, string, maxlen);-}--int HID_API_EXPORT_CALL hid_get_product_string(hid_device *dev, wchar_t *string, size_t maxlen)-{-	return get_device_string(dev, DEVICE_STRING_PRODUCT, string, maxlen);-}--int HID_API_EXPORT_CALL hid_get_serial_number_string(hid_device *dev, wchar_t *string, size_t maxlen)-{-	return get_device_string(dev, DEVICE_STRING_SERIAL, string, maxlen);-}--int HID_API_EXPORT_CALL hid_get_indexed_string(hid_device *dev, int string_index, wchar_t *string, size_t maxlen)-{-	return -1;-}---HID_API_EXPORT const wchar_t * HID_API_CALL  hid_error(hid_device *dev)-{-	return NULL;-}
− cbits/windows/hid.c
@@ -1,923 +0,0 @@-/*******************************************************- HIDAPI - Multi-Platform library for- communication with HID devices.-- Alan Ott- Signal 11 Software-- 8/22/2009-- Copyright 2009, All Rights Reserved.- - At the discretion of the user of this library,- this software may be licensed under the terms of the- GNU General Public License v3, a BSD-Style license, or the- original HIDAPI license as outlined in the LICENSE.txt,- LICENSE-gpl3.txt, LICENSE-bsd.txt, and LICENSE-orig.txt- files located at the root of the source distribution.- These files may also be found in the public source- code repository located at:-        http://github.com/signal11/hidapi .-********************************************************/--#include <windows.h>--#ifndef _NTDEF_-typedef LONG NTSTATUS;-#endif--#ifdef __MINGW32__-#include <ntdef.h>-#include <winbase.h>-#endif--#ifdef __CYGWIN__-#include <ntdef.h>-#define _wcsdup wcsdup-#endif--/*#define HIDAPI_USE_DDK*/--#ifdef __cplusplus-extern "C" {-#endif-	#include <setupapi.h>-	#include <winioctl.h>-	#ifdef HIDAPI_USE_DDK-		#include <hidsdi.h>-	#endif--	/* Copied from inc/ddk/hidclass.h, part of the Windows DDK. */-	#define HID_OUT_CTL_CODE(id)  \-		CTL_CODE(FILE_DEVICE_KEYBOARD, (id), METHOD_OUT_DIRECT, FILE_ANY_ACCESS)-	#define IOCTL_HID_GET_FEATURE                   HID_OUT_CTL_CODE(100)--#ifdef __cplusplus-} /* extern "C" */-#endif--#include <stdio.h>-#include <stdlib.h>---#include "hidapi.h"--#ifdef _MSC_VER-	/* Thanks Microsoft, but I know how to use strncpy(). */-	#pragma warning(disable:4996)-#endif--#ifdef __cplusplus-extern "C" {-#endif--#ifndef HIDAPI_USE_DDK-	/* Since we're not building with the DDK, and the HID header-	   files aren't part of the SDK, we have to define all this-	   stuff here. In lookup_functions(), the function pointers-	   defined below are set. */-	typedef struct _HIDD_ATTRIBUTES{-		ULONG Size;-		USHORT VendorID;-		USHORT ProductID;-		USHORT VersionNumber;-	} HIDD_ATTRIBUTES, *PHIDD_ATTRIBUTES;--	typedef USHORT USAGE;-	typedef struct _HIDP_CAPS {-		USAGE Usage;-		USAGE UsagePage;-		USHORT InputReportByteLength;-		USHORT OutputReportByteLength;-		USHORT FeatureReportByteLength;-		USHORT Reserved[17];-		USHORT fields_not_used_by_hidapi[10];-	} HIDP_CAPS, *PHIDP_CAPS;-	typedef void* PHIDP_PREPARSED_DATA;-	#define HIDP_STATUS_SUCCESS 0x110000--	typedef BOOLEAN (__stdcall *HidD_GetAttributes_)(HANDLE device, PHIDD_ATTRIBUTES attrib);-	typedef BOOLEAN (__stdcall *HidD_GetSerialNumberString_)(HANDLE device, PVOID buffer, ULONG buffer_len);-	typedef BOOLEAN (__stdcall *HidD_GetManufacturerString_)(HANDLE handle, PVOID buffer, ULONG buffer_len);-	typedef BOOLEAN (__stdcall *HidD_GetProductString_)(HANDLE handle, PVOID buffer, ULONG buffer_len);-	typedef BOOLEAN (__stdcall *HidD_SetFeature_)(HANDLE handle, PVOID data, ULONG length);-	typedef BOOLEAN (__stdcall *HidD_GetFeature_)(HANDLE handle, PVOID data, ULONG length);-	typedef BOOLEAN (__stdcall *HidD_GetIndexedString_)(HANDLE handle, ULONG string_index, PVOID buffer, ULONG buffer_len);-	typedef BOOLEAN (__stdcall *HidD_GetPreparsedData_)(HANDLE handle, PHIDP_PREPARSED_DATA *preparsed_data);-	typedef BOOLEAN (__stdcall *HidD_FreePreparsedData_)(PHIDP_PREPARSED_DATA preparsed_data);-	typedef NTSTATUS (__stdcall *HidP_GetCaps_)(PHIDP_PREPARSED_DATA preparsed_data, HIDP_CAPS *caps);--	static HidD_GetAttributes_ HidD_GetAttributes;-	static HidD_GetSerialNumberString_ HidD_GetSerialNumberString;-	static HidD_GetManufacturerString_ HidD_GetManufacturerString;-	static HidD_GetProductString_ HidD_GetProductString;-	static HidD_SetFeature_ HidD_SetFeature;-	static HidD_GetFeature_ HidD_GetFeature;-	static HidD_GetIndexedString_ HidD_GetIndexedString;-	static HidD_GetPreparsedData_ HidD_GetPreparsedData;-	static HidD_FreePreparsedData_ HidD_FreePreparsedData;-	static HidP_GetCaps_ HidP_GetCaps;--	static HMODULE lib_handle = NULL;-	static BOOLEAN initialized = FALSE;-#endif /* HIDAPI_USE_DDK */--struct hid_device_ {-		HANDLE device_handle;-		BOOL blocking;-		USHORT output_report_length;-		size_t input_report_length;-		void *last_error_str;-		DWORD last_error_num;-		BOOL read_pending;-		char *read_buf;-		OVERLAPPED ol;-};--static hid_device *new_hid_device()-{-	hid_device *dev = (hid_device*) calloc(1, sizeof(hid_device));-	dev->device_handle = INVALID_HANDLE_VALUE;-	dev->blocking = TRUE;-	dev->output_report_length = 0;-	dev->input_report_length = 0;-	dev->last_error_str = NULL;-	dev->last_error_num = 0;-	dev->read_pending = FALSE;-	dev->read_buf = NULL;-	memset(&dev->ol, 0, sizeof(dev->ol));-	dev->ol.hEvent = CreateEvent(NULL, FALSE, FALSE /*inital state f=nonsignaled*/, NULL);--	return dev;-}--static void free_hid_device(hid_device *dev)-{-	CloseHandle(dev->ol.hEvent);-	CloseHandle(dev->device_handle);-	LocalFree(dev->last_error_str);-	free(dev->read_buf);-	free(dev);-}--static void register_error(hid_device *device, const char *op)-{-	WCHAR *ptr, *msg;--	FormatMessageW(FORMAT_MESSAGE_ALLOCATE_BUFFER |-		FORMAT_MESSAGE_FROM_SYSTEM |-		FORMAT_MESSAGE_IGNORE_INSERTS,-		NULL,-		GetLastError(),-		MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),-		(LPVOID)&msg, 0/*sz*/,-		NULL);-	-	/* Get rid of the CR and LF that FormatMessage() sticks at the-	   end of the message. Thanks Microsoft! */-	ptr = msg;-	while (*ptr) {-		if (*ptr == '\r') {-			*ptr = 0x0000;-			break;-		}-		ptr++;-	}--	/* Store the message off in the Device entry so that-	   the hid_error() function can pick it up. */-	LocalFree(device->last_error_str);-	device->last_error_str = msg;-}--#ifndef HIDAPI_USE_DDK-static int lookup_functions()-{-	lib_handle = LoadLibraryA("hid.dll");-	if (lib_handle) {-#define RESOLVE(x) x = (x##_)GetProcAddress(lib_handle, #x); if (!x) return -1;-		RESOLVE(HidD_GetAttributes);-		RESOLVE(HidD_GetSerialNumberString);-		RESOLVE(HidD_GetManufacturerString);-		RESOLVE(HidD_GetProductString);-		RESOLVE(HidD_SetFeature);-		RESOLVE(HidD_GetFeature);-		RESOLVE(HidD_GetIndexedString);-		RESOLVE(HidD_GetPreparsedData);-		RESOLVE(HidD_FreePreparsedData);-		RESOLVE(HidP_GetCaps);-#undef RESOLVE-	}-	else-		return -1;--	return 0;-}-#endif--static HANDLE open_device(const char *path, BOOL enumerate)-{-	HANDLE handle;-	DWORD desired_access = (enumerate)? 0: (GENERIC_WRITE | GENERIC_READ);-	DWORD share_mode = (enumerate)?-	                      FILE_SHARE_READ|FILE_SHARE_WRITE:-	                      FILE_SHARE_READ;--	handle = CreateFileA(path,-		desired_access,-		share_mode,-		NULL,-		OPEN_EXISTING,-		FILE_FLAG_OVERLAPPED,/*FILE_ATTRIBUTE_NORMAL,*/-		0);--	return handle;-}--int HID_API_EXPORT hid_init(void)-{-#ifndef HIDAPI_USE_DDK-	if (!initialized) {-		if (lookup_functions() < 0) {-			hid_exit();-			return -1;-		}-		initialized = TRUE;-	}-#endif-	return 0;-}--int HID_API_EXPORT hid_exit(void)-{-#ifndef HIDAPI_USE_DDK-	if (lib_handle)-		FreeLibrary(lib_handle);-	lib_handle = NULL;-	initialized = FALSE;-#endif-	return 0;-}--struct hid_device_info HID_API_EXPORT * HID_API_CALL hid_enumerate(unsigned short vendor_id, unsigned short product_id)-{-	BOOL res;-	struct hid_device_info *root = NULL; /* return object */-	struct hid_device_info *cur_dev = NULL;--	/* Windows objects for interacting with the driver. */-	GUID InterfaceClassGuid = {0x4d1e55b2, 0xf16f, 0x11cf, {0x88, 0xcb, 0x00, 0x11, 0x11, 0x00, 0x00, 0x30} };-	SP_DEVINFO_DATA devinfo_data;-	SP_DEVICE_INTERFACE_DATA device_interface_data;-	SP_DEVICE_INTERFACE_DETAIL_DATA_A *device_interface_detail_data = NULL;-	HDEVINFO device_info_set = INVALID_HANDLE_VALUE;-	int device_index = 0;-	int i;--	if (hid_init() < 0)-		return NULL;--	/* Initialize the Windows objects. */-	memset(&devinfo_data, 0x0, sizeof(devinfo_data));-	devinfo_data.cbSize = sizeof(SP_DEVINFO_DATA);-	device_interface_data.cbSize = sizeof(SP_DEVICE_INTERFACE_DATA);--	/* Get information for all the devices belonging to the HID class. */-	device_info_set = SetupDiGetClassDevsA(&InterfaceClassGuid, NULL, NULL, DIGCF_PRESENT | DIGCF_DEVICEINTERFACE);-	-	/* Iterate over each device in the HID class, looking for the right one. */-	-	for (;;) {-		HANDLE write_handle = INVALID_HANDLE_VALUE;-		DWORD required_size = 0;-		HIDD_ATTRIBUTES attrib;--		res = SetupDiEnumDeviceInterfaces(device_info_set,-			NULL,-			&InterfaceClassGuid,-			device_index,-			&device_interface_data);-		-		if (!res) {-			/* A return of FALSE from this function means that-			   there are no more devices. */-			break;-		}--		/* Call with 0-sized detail size, and let the function-		   tell us how long the detail struct needs to be. The-		   size is put in &required_size. */-		res = SetupDiGetDeviceInterfaceDetailA(device_info_set,-			&device_interface_data,-			NULL,-			0,-			&required_size,-			NULL);--		/* Allocate a long enough structure for device_interface_detail_data. */-		device_interface_detail_data = (SP_DEVICE_INTERFACE_DETAIL_DATA_A*) malloc(required_size);-		device_interface_detail_data->cbSize = sizeof(SP_DEVICE_INTERFACE_DETAIL_DATA_A);--		/* Get the detailed data for this device. The detail data gives us-		   the device path for this device, which is then passed into-		   CreateFile() to get a handle to the device. */-		res = SetupDiGetDeviceInterfaceDetailA(device_info_set,-			&device_interface_data,-			device_interface_detail_data,-			required_size,-			NULL,-			NULL);--		if (!res) {-			/* register_error(dev, "Unable to call SetupDiGetDeviceInterfaceDetail");-			   Continue to the next device. */-			goto cont;-		}--		/* Make sure this device is of Setup Class "HIDClass" and has a-		   driver bound to it. */-		for (i = 0; ; i++) {-			char driver_name[256];--			/* Populate devinfo_data. This function will return failure-			   when there are no more interfaces left. */-			res = SetupDiEnumDeviceInfo(device_info_set, i, &devinfo_data);-			if (!res)-				goto cont;--			res = SetupDiGetDeviceRegistryPropertyA(device_info_set, &devinfo_data,-			               SPDRP_CLASS, NULL, (PBYTE)driver_name, sizeof(driver_name), NULL);-			if (!res)-				goto cont;--			if (strcmp(driver_name, "HIDClass") == 0) {-				/* See if there's a driver bound. */-				res = SetupDiGetDeviceRegistryPropertyA(device_info_set, &devinfo_data,-				           SPDRP_DRIVER, NULL, (PBYTE)driver_name, sizeof(driver_name), NULL);-				if (res)-					break;-			}-		}--		//wprintf(L"HandleName: %s\n", device_interface_detail_data->DevicePath);--		/* Open a handle to the device */-		write_handle = open_device(device_interface_detail_data->DevicePath, TRUE);--		/* Check validity of write_handle. */-		if (write_handle == INVALID_HANDLE_VALUE) {-			/* Unable to open the device. */-			//register_error(dev, "CreateFile");-			goto cont_close;-		}		---		/* Get the Vendor ID and Product ID for this device. */-		attrib.Size = sizeof(HIDD_ATTRIBUTES);-		HidD_GetAttributes(write_handle, &attrib);-		//wprintf(L"Product/Vendor: %x %x\n", attrib.ProductID, attrib.VendorID);--		/* Check the VID/PID to see if we should add this-		   device to the enumeration list. */-		if ((vendor_id == 0x0 || attrib.VendorID == vendor_id) &&-		    (product_id == 0x0 || attrib.ProductID == product_id)) {--			#define WSTR_LEN 512-			const char *str;-			struct hid_device_info *tmp;-			PHIDP_PREPARSED_DATA pp_data = NULL;-			HIDP_CAPS caps;-			BOOLEAN res;-			NTSTATUS nt_res;-			wchar_t wstr[WSTR_LEN]; /* TODO: Determine Size */-			size_t len;--			/* VID/PID match. Create the record. */-			tmp = (struct hid_device_info*) calloc(1, sizeof(struct hid_device_info));-			if (cur_dev) {-				cur_dev->next = tmp;-			}-			else {-				root = tmp;-			}-			cur_dev = tmp;--			/* Get the Usage Page and Usage for this device. */-			res = HidD_GetPreparsedData(write_handle, &pp_data);-			if (res) {-				nt_res = HidP_GetCaps(pp_data, &caps);-				if (nt_res == HIDP_STATUS_SUCCESS) {-					cur_dev->usage_page = caps.UsagePage;-					cur_dev->usage = caps.Usage;-				}--				HidD_FreePreparsedData(pp_data);-			}-			-			/* Fill out the record */-			cur_dev->next = NULL;-			str = device_interface_detail_data->DevicePath;-			if (str) {-				len = strlen(str);-				cur_dev->path = (char*) calloc(len+1, sizeof(char));-				strncpy(cur_dev->path, str, len+1);-				cur_dev->path[len] = '\0';-			}-			else-				cur_dev->path = NULL;--			/* Serial Number */-			res = HidD_GetSerialNumberString(write_handle, wstr, sizeof(wstr));-			wstr[WSTR_LEN-1] = 0x0000;-			if (res) {-				cur_dev->serial_number = _wcsdup(wstr);-			}--			/* Manufacturer String */-			res = HidD_GetManufacturerString(write_handle, wstr, sizeof(wstr));-			wstr[WSTR_LEN-1] = 0x0000;-			if (res) {-				cur_dev->manufacturer_string = _wcsdup(wstr);-			}--			/* Product String */-			res = HidD_GetProductString(write_handle, wstr, sizeof(wstr));-			wstr[WSTR_LEN-1] = 0x0000;-			if (res) {-				cur_dev->product_string = _wcsdup(wstr);-			}--			/* VID/PID */-			cur_dev->vendor_id = attrib.VendorID;-			cur_dev->product_id = attrib.ProductID;--			/* Release Number */-			cur_dev->release_number = attrib.VersionNumber;--			/* Interface Number. It can sometimes be parsed out of the path-			   on Windows if a device has multiple interfaces. See-			   http://msdn.microsoft.com/en-us/windows/hardware/gg487473 or-			   search for "Hardware IDs for HID Devices" at MSDN. If it's not-			   in the path, it's set to -1. */-			cur_dev->interface_number = -1;-			if (cur_dev->path) {-				char *interface_component = strstr(cur_dev->path, "&mi_");-				if (interface_component) {-					char *hex_str = interface_component + 4;-					char *endptr = NULL;-					cur_dev->interface_number = strtol(hex_str, &endptr, 16);-					if (endptr == hex_str) {-						/* The parsing failed. Set interface_number to -1. */-						cur_dev->interface_number = -1;-					}-				}-			}-		}--cont_close:-		CloseHandle(write_handle);-cont:-		/* We no longer need the detail data. It can be freed */-		free(device_interface_detail_data);--		device_index++;--	}--	/* Close the device information handle. */-	SetupDiDestroyDeviceInfoList(device_info_set);--	return root;--}--void  HID_API_EXPORT HID_API_CALL hid_free_enumeration(struct hid_device_info *devs)-{-	/* TODO: Merge this with the Linux version. This function is platform-independent. */-	struct hid_device_info *d = devs;-	while (d) {-		struct hid_device_info *next = d->next;-		free(d->path);-		free(d->serial_number);-		free(d->manufacturer_string);-		free(d->product_string);-		free(d);-		d = next;-	}-}---HID_API_EXPORT hid_device * HID_API_CALL hid_open(unsigned short vendor_id, unsigned short product_id, const wchar_t *serial_number)-{-	/* TODO: Merge this functions with the Linux version. This function should be platform independent. */-	struct hid_device_info *devs, *cur_dev;-	const char *path_to_open = NULL;-	hid_device *handle = NULL;-	-	devs = hid_enumerate(vendor_id, product_id);-	cur_dev = devs;-	while (cur_dev) {-		if (cur_dev->vendor_id == vendor_id &&-		    cur_dev->product_id == product_id) {-			if (serial_number) {-				if (wcscmp(serial_number, cur_dev->serial_number) == 0) {-					path_to_open = cur_dev->path;-					break;-				}-			}-			else {-				path_to_open = cur_dev->path;-				break;-			}-		}-		cur_dev = cur_dev->next;-	}--	if (path_to_open) {-		/* Open the device */-		handle = hid_open_path(path_to_open);-	}--	hid_free_enumeration(devs);-	-	return handle;-}--HID_API_EXPORT hid_device * HID_API_CALL hid_open_path(const char *path)-{-	hid_device *dev;-	HIDP_CAPS caps;-	PHIDP_PREPARSED_DATA pp_data = NULL;-	BOOLEAN res;-	NTSTATUS nt_res;--	if (hid_init() < 0) {-		return NULL;-	}--	dev = new_hid_device();--	/* Open a handle to the device */-	dev->device_handle = open_device(path, FALSE);--	/* Check validity of write_handle. */-	if (dev->device_handle == INVALID_HANDLE_VALUE) {-		/* Unable to open the device. */-		register_error(dev, "CreateFile");-		goto err;-	}--	/* Get the Input Report length for the device. */-	res = HidD_GetPreparsedData(dev->device_handle, &pp_data);-	if (!res) {-		register_error(dev, "HidD_GetPreparsedData");-		goto err;-	}-	nt_res = HidP_GetCaps(pp_data, &caps);-	if (nt_res != HIDP_STATUS_SUCCESS) {-		register_error(dev, "HidP_GetCaps");	-		goto err_pp_data;-	}-	dev->output_report_length = caps.OutputReportByteLength;-	dev->input_report_length = caps.InputReportByteLength;-	HidD_FreePreparsedData(pp_data);--	dev->read_buf = (char*) malloc(dev->input_report_length);--	return dev;--err_pp_data:-		HidD_FreePreparsedData(pp_data);-err:	-		free_hid_device(dev);-		return NULL;-}--int HID_API_EXPORT HID_API_CALL hid_write(hid_device *dev, const unsigned char *data, size_t length)-{-	DWORD bytes_written;-	BOOL res;--	OVERLAPPED ol;-	unsigned char *buf;-	memset(&ol, 0, sizeof(ol));--	/* Make sure the right number of bytes are passed to WriteFile. Windows-	   expects the number of bytes which are in the _longest_ report (plus-	   one for the report number) bytes even if the data is a report-	   which is shorter than that. Windows gives us this value in-	   caps.OutputReportByteLength. If a user passes in fewer bytes than this,-	   create a temporary buffer which is the proper size. */-	if (length >= dev->output_report_length) {-		/* The user passed the right number of bytes. Use the buffer as-is. */-		buf = (unsigned char *) data;-	} else {-		/* Create a temporary buffer and copy the user's data-		   into it, padding the rest with zeros. */-		buf = (unsigned char *) malloc(dev->output_report_length);-		memcpy(buf, data, length);-		memset(buf + length, 0, dev->output_report_length - length);-		length = dev->output_report_length;-	}--	res = WriteFile(dev->device_handle, buf, length, NULL, &ol);-	-	if (!res) {-		if (GetLastError() != ERROR_IO_PENDING) {-			/* WriteFile() failed. Return error. */-			register_error(dev, "WriteFile");-			bytes_written = -1;-			goto end_of_function;-		}-	}--	/* Wait here until the write is done. This makes-	   hid_write() synchronous. */-	res = GetOverlappedResult(dev->device_handle, &ol, &bytes_written, TRUE/*wait*/);-	if (!res) {-		/* The Write operation failed. */-		register_error(dev, "WriteFile");-		bytes_written = -1;-		goto end_of_function;-	}--end_of_function:-	if (buf != data)-		free(buf);--	return bytes_written;-}---int HID_API_EXPORT HID_API_CALL hid_read_timeout(hid_device *dev, unsigned char *data, size_t length, int milliseconds)-{-	DWORD bytes_read = 0;-	BOOL res;--	/* Copy the handle for convenience. */-	HANDLE ev = dev->ol.hEvent;--	if (!dev->read_pending) {-		/* Start an Overlapped I/O read. */-		dev->read_pending = TRUE;-		memset(dev->read_buf, 0, dev->input_report_length);-		ResetEvent(ev);-		res = ReadFile(dev->device_handle, dev->read_buf, dev->input_report_length, &bytes_read, &dev->ol);-		-		if (!res) {-			if (GetLastError() != ERROR_IO_PENDING) {-				/* ReadFile() has failed.-				   Clean up and return error. */-				CancelIo(dev->device_handle);-				dev->read_pending = FALSE;-				goto end_of_function;-			}-		}-	}--	if (milliseconds >= 0) {-		/* See if there is any data yet. */-		res = WaitForSingleObject(ev, milliseconds);-		if (res != WAIT_OBJECT_0) {-			/* There was no data this time. Return zero bytes available,-			   but leave the Overlapped I/O running. */-			return 0;-		}-	}--	/* Either WaitForSingleObject() told us that ReadFile has completed, or-	   we are in non-blocking mode. Get the number of bytes read. The actual-	   data has been copied to the data[] array which was passed to ReadFile(). */-	res = GetOverlappedResult(dev->device_handle, &dev->ol, &bytes_read, TRUE/*wait*/);-	-	/* Set pending back to false, even if GetOverlappedResult() returned error. */-	dev->read_pending = FALSE;--	if (res && bytes_read > 0) {-		if (dev->read_buf[0] == 0x0) {-			/* If report numbers aren't being used, but Windows sticks a report-			   number (0x0) on the beginning of the report anyway. To make this-			   work like the other platforms, and to make it work more like the-			   HID spec, we'll skip over this byte. */-			size_t copy_len;-			bytes_read--;-			copy_len = length > bytes_read ? bytes_read : length;-			memcpy(data, dev->read_buf+1, copy_len);-		}-		else {-			/* Copy the whole buffer, report number and all. */-			size_t copy_len = length > bytes_read ? bytes_read : length;-			memcpy(data, dev->read_buf, copy_len);-		}-	}-	-end_of_function:-	if (!res) {-		register_error(dev, "GetOverlappedResult");-		return -1;-	}-	-	return bytes_read;-}--int HID_API_EXPORT HID_API_CALL hid_read(hid_device *dev, unsigned char *data, size_t length)-{-	return hid_read_timeout(dev, data, length, (dev->blocking)? -1: 0);-}--int HID_API_EXPORT HID_API_CALL hid_set_nonblocking(hid_device *dev, int nonblock)-{-	dev->blocking = !nonblock;-	return 0; /* Success */-}--int HID_API_EXPORT HID_API_CALL hid_send_feature_report(hid_device *dev, const unsigned char *data, size_t length)-{-	BOOL res = HidD_SetFeature(dev->device_handle, (PVOID)data, length);-	if (!res) {-		register_error(dev, "HidD_SetFeature");-		return -1;-	}--	return length;-}---int HID_API_EXPORT HID_API_CALL hid_get_feature_report(hid_device *dev, unsigned char *data, size_t length)-{-	BOOL res;-#if 0-	res = HidD_GetFeature(dev->device_handle, data, length);-	if (!res) {-		register_error(dev, "HidD_GetFeature");-		return -1;-	}-	return 0; /* HidD_GetFeature() doesn't give us an actual length, unfortunately */-#else-	DWORD bytes_returned;--	OVERLAPPED ol;-	memset(&ol, 0, sizeof(ol));--	res = DeviceIoControl(dev->device_handle,-		IOCTL_HID_GET_FEATURE,-		data, length,-		data, length,-		&bytes_returned, &ol);--	if (!res) {-		if (GetLastError() != ERROR_IO_PENDING) {-			/* DeviceIoControl() failed. Return error. */-			register_error(dev, "Send Feature Report DeviceIoControl");-			return -1;-		}-	}--	/* Wait here until the write is done. This makes-	   hid_get_feature_report() synchronous. */-	res = GetOverlappedResult(dev->device_handle, &ol, &bytes_returned, TRUE/*wait*/);-	if (!res) {-		/* The operation failed. */-		register_error(dev, "Send Feature Report GetOverLappedResult");-		return -1;-	}-	return bytes_returned;-#endif-}--void HID_API_EXPORT HID_API_CALL hid_close(hid_device *dev)-{-	if (!dev)-		return;-	CancelIo(dev->device_handle);-	free_hid_device(dev);-}--int HID_API_EXPORT_CALL HID_API_CALL hid_get_manufacturer_string(hid_device *dev, wchar_t *string, size_t maxlen)-{-	BOOL res;--	res = HidD_GetManufacturerString(dev->device_handle, string, sizeof(wchar_t) * maxlen);-	if (!res) {-		register_error(dev, "HidD_GetManufacturerString");-		return -1;-	}--	return 0;-}--int HID_API_EXPORT_CALL HID_API_CALL hid_get_product_string(hid_device *dev, wchar_t *string, size_t maxlen)-{-	BOOL res;--	res = HidD_GetProductString(dev->device_handle, string, sizeof(wchar_t) * maxlen);-	if (!res) {-		register_error(dev, "HidD_GetProductString");-		return -1;-	}--	return 0;-}--int HID_API_EXPORT_CALL HID_API_CALL hid_get_serial_number_string(hid_device *dev, wchar_t *string, size_t maxlen)-{-	BOOL res;--	res = HidD_GetSerialNumberString(dev->device_handle, string, sizeof(wchar_t) * maxlen);-	if (!res) {-		register_error(dev, "HidD_GetSerialNumberString");-		return -1;-	}--	return 0;-}--int HID_API_EXPORT_CALL HID_API_CALL hid_get_indexed_string(hid_device *dev, int string_index, wchar_t *string, size_t maxlen)-{-	BOOL res;--	res = HidD_GetIndexedString(dev->device_handle, string_index, string, sizeof(wchar_t) * maxlen);-	if (!res) {-		register_error(dev, "HidD_GetIndexedString");-		return -1;-	}--	return 0;-}---HID_API_EXPORT const wchar_t * HID_API_CALL  hid_error(hid_device *dev)-{-	return (wchar_t*)dev->last_error_str;-}---/*#define PICPGM*/-/*#define S11*/-#define P32-#ifdef S11 -  unsigned short VendorID = 0xa0a0;-	unsigned short ProductID = 0x0001;-#endif--#ifdef P32-  unsigned short VendorID = 0x04d8;-	unsigned short ProductID = 0x3f;-#endif---#ifdef PICPGM-  unsigned short VendorID = 0x04d8;-  unsigned short ProductID = 0x0033;-#endif---#if 0-int __cdecl main(int argc, char* argv[])-{-	int res;-	unsigned char buf[65];--	UNREFERENCED_PARAMETER(argc);-	UNREFERENCED_PARAMETER(argv);--	/* Set up the command buffer. */-	memset(buf,0x00,sizeof(buf));-	buf[0] = 0;-	buf[1] = 0x81;-	--	/* Open the device. */-	int handle = open(VendorID, ProductID, L"12345");-	if (handle < 0)-		printf("unable to open device\n");---	/* Toggle LED (cmd 0x80) */-	buf[1] = 0x80;-	res = write(handle, buf, 65);-	if (res < 0)-		printf("Unable to write()\n");--	/* Request state (cmd 0x81) */-	buf[1] = 0x81;-	write(handle, buf, 65);-	if (res < 0)-		printf("Unable to write() (2)\n");--	/* Read requested state */-	read(handle, buf, 65);-	if (res < 0)-		printf("Unable to read()\n");--	/* Print out the returned buffer. */-	for (int i = 0; i < 4; i++)-		printf("buf[%d]: %d\n", i, buf[i]);--	return 0;-}-#endif--#ifdef __cplusplus-} /* extern "C" */-#endif
hidapi.cabal view
@@ -1,5 +1,5 @@ name:              hidapi-version:           0.1.2+version:           0.1.3 build-type:        Simple cabal-version:     >= 1.6 category:          Hardware@@ -14,8 +14,6 @@  extra-source-files:   cbits/hidapi/hidapi.h-  cbits/linux/hid.c-  cbits/windows/hid.c  source-repository head   type:      git@@ -34,8 +32,11 @@   includes:      hidapi.h    if os(windows)-    c-sources:       cbits/windows/hid.c-    extra-libraries: hid setupapi+    c-sources: cbits/hidapi/windows/hid.c+    extra-libraries: setupapi   else-    c-sources:       cbits/linux/hid.c-    extra-libraries: udev+    if os(darwin)+      c-sources: cbits/hidapi/mac/hid.c+    else+      c-sources: cbits/hidapi/linux/hid.c+      extra-libraries: udev