Last active
September 3, 2016 00:34
-
-
Save drojf/0e670fb7e9e37a4e9b1c2dda73dd0661 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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 (;;) { | |
printf("Iterating over device [%d]\n", device_index); | |
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. */ | |
puts("Finished, no more devices\n"); | |
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. */ | |
printf("Unable to call SetupDiGetDeviceInterfaceDetail"); | |
goto cont; | |
} | |
printf("device interface detail: %s\n", device_interface_detail_data->DevicePath); | |
/* Make sure this device is of Setup Class "HIDClass" and has a | |
driver bound to it. */ | |
#define ENABLE_HIDCLASS_CHECK 1 | |
#define ENABLE_FOR_LOOP 1 | |
#if ENABLE_FOR_LOOP | |
for (i = 0; ; i++) { | |
#else | |
i = device_index; | |
#endif | |
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) | |
{ | |
printf("failure on SetupDiEnumDeviceInfo()!\n"); | |
goto cont; | |
} | |
printf("Getting driver of i: [%d] Instance: [%d] guid: [%d]", i, devinfo_data.DevInst, devinfo_data.ClassGuid); | |
res = SetupDiGetDeviceRegistryPropertyA(device_info_set, &devinfo_data, | |
SPDRP_CLASS, NULL, (PBYTE)driver_name, sizeof(driver_name), NULL); | |
if (!res) | |
{ | |
printf("failure on SetupDiGetDeviceRegistryPropertyA()!\n"); | |
goto cont; | |
} | |
printf(" Driver: %s\n", driver_name); | |
#if ENABLE_HIDCLASS_CHECK | |
#if ENABLE_FOR_LOOP | |
if (strcmp(driver_name, "HIDClass") == 0) { | |
res = SetupDiGetDeviceRegistryPropertyA(device_info_set, &devinfo_data, | |
SPDRP_DRIVER, NULL, (PBYTE)driver_name, sizeof(driver_name), NULL); | |
if (res) | |
break; | |
} | |
#else | |
if (strcmp(driver_name, "HIDClass") != 0) { | |
goto cont; | |
} | |
#endif | |
#endif | |
#if ENABLE_FOR_LOOP | |
} | |
#endif | |
//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; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment