-#ifdef _WIN32
-
-/* USB path is a string of at most 8 decimal numbers < 128 separated by dots */
-#define MAX_USB_PATH (8*3 + 7*1 + 1)
-
-static char *wc_to_utf8(PWCHAR wc_buffer, ULONG size)
-{
- WCHAR wc_str[size/sizeof(WCHAR)+1];
- char *utf8_str;
-
- /* zero terminate the wide char string */
- memcpy(wc_str, wc_buffer, size);
- wc_str[sizeof(wc_str)-1] = 0;
-
- /* compute the size of the utf8 converted string */
- if (!(size = WideCharToMultiByte(CP_ACP, WC_NO_BEST_FIT_CHARS, wc_str, -1,
- NULL, 0, NULL, NULL)))
- return NULL;
-
- /* allocate utf8 output buffer */
- if (!(utf8_str = malloc(size)))
- return NULL;
-
- /* actually converted to utf8 */
- if (!WideCharToMultiByte(CP_ACP, WC_NO_BEST_FIT_CHARS, wc_str, -1,
- utf8_str, size, NULL, NULL)) {
- free(utf8_str);
- return NULL;
- }
-
- return utf8_str;
-}
-
-static char *get_root_hub_name(HANDLE host_controller)
-{
- USB_ROOT_HUB_NAME root_hub_name;
- PUSB_ROOT_HUB_NAME root_hub_name_wc;
- char *root_hub_name_utf8;
- ULONG size = 0;
-
- /* compute the size of the root hub name string */
- if (!DeviceIoControl(host_controller, IOCTL_USB_GET_ROOT_HUB_NAME, 0, 0,
- &root_hub_name, sizeof(root_hub_name), &size, NULL))
- return NULL;
-
- /* allocate wide char root hub name string */
- size = root_hub_name.ActualLength;
- if (!(root_hub_name_wc = malloc(size)))
- return NULL;
-
- /* actually get the root hub name string */
- if (!DeviceIoControl(host_controller, IOCTL_USB_GET_ROOT_HUB_NAME,
- NULL, 0, root_hub_name_wc, size, &size, NULL)) {
- free(root_hub_name_wc);
- return NULL;
- }
-
- /* convert the root hub name string to utf8 */
- root_hub_name_utf8 = wc_to_utf8(root_hub_name_wc->RootHubName, size);
- free(root_hub_name_wc);
- return root_hub_name_utf8;
-}
-
-static char *get_external_hub_name(HANDLE hub, ULONG connection_index)
-{
- USB_NODE_CONNECTION_NAME ext_hub_name;
- PUSB_NODE_CONNECTION_NAME ext_hub_name_wc;
- char *ext_hub_name_utf8;
- ULONG size;
-
- /* compute the size of the external hub name string */
- ext_hub_name.ConnectionIndex = connection_index;
- if (!DeviceIoControl(hub, IOCTL_USB_GET_NODE_CONNECTION_NAME,
- &ext_hub_name, sizeof(ext_hub_name),
- &ext_hub_name, sizeof(ext_hub_name), &size, NULL))
- return NULL;
-
- /* allocate wide char external hub name string */
- size = ext_hub_name.ActualLength;
- if (size <= sizeof(ext_hub_name)
- || !(ext_hub_name_wc = malloc(size)))
- return NULL;
-
- /* get the name of the external hub attached to the specified port */
- ext_hub_name_wc->ConnectionIndex = connection_index;
- if (!DeviceIoControl(hub, IOCTL_USB_GET_NODE_CONNECTION_NAME,
- ext_hub_name_wc, size,
- ext_hub_name_wc, size, &size, NULL)) {
- free(ext_hub_name_wc);
- return NULL;
- }
-
- /* convert the external hub name string to utf8 */
- ext_hub_name_utf8 = wc_to_utf8(ext_hub_name_wc->NodeName, size);
- free(ext_hub_name_wc);
- return ext_hub_name_utf8;
-}
-
-static char *get_string_descriptor(HANDLE hub_device, ULONG connection_index,
- UCHAR descriptor_index)
-{
- char desc_req_buf[sizeof(USB_DESCRIPTOR_REQUEST) +
- MAXIMUM_USB_STRING_LENGTH] = { 0 };
- PUSB_DESCRIPTOR_REQUEST desc_req = (void *) desc_req_buf;
- PUSB_STRING_DESCRIPTOR desc = (void *) (desc_req + 1);
- ULONG size = sizeof(desc_req_buf);
-
- desc_req->ConnectionIndex = connection_index;
- desc_req->SetupPacket.wValue = (USB_STRING_DESCRIPTOR_TYPE << 8)
- | descriptor_index;
- desc_req->SetupPacket.wIndex = 0;
- desc_req->SetupPacket.wLength = size - sizeof(*desc_req);
-
- if (!DeviceIoControl(hub_device,
- IOCTL_USB_GET_DESCRIPTOR_FROM_NODE_CONNECTION,
- desc_req, size, desc_req, size, &size, NULL)
- || size < 2
- || desc->bDescriptorType != USB_STRING_DESCRIPTOR_TYPE
- || desc->bLength != size - sizeof(*desc_req)
- || desc->bLength % 2)
- return NULL;
-
- return wc_to_utf8(desc->bString, desc->bLength);
-}
-
-static void enumerate_hub(struct sp_port *port, char *hub_name,
- char *parent_path);
-
-static void enumerate_hub_ports(struct sp_port *port, HANDLE hub_device,
- ULONG nb_ports, char *parent_path)
-{
- char path[MAX_USB_PATH];
- ULONG index = 0;
-
- for (index = 1; index <= nb_ports; index++) {
- PUSB_NODE_CONNECTION_INFORMATION_EX connection_info_ex;
- ULONG size = sizeof(*connection_info_ex) + 30*sizeof(USB_PIPE_INFO);
-
- if (!(connection_info_ex = malloc(size)))
- break;
-
- connection_info_ex->ConnectionIndex = index;
- if (!DeviceIoControl(hub_device,
- IOCTL_USB_GET_NODE_CONNECTION_INFORMATION_EX,
- connection_info_ex, size,
- connection_info_ex, size, &size, NULL)) {
- /* try to get CONNECTION_INFORMATION if CONNECTION_INFORMATION_EX
- did not work */
- PUSB_NODE_CONNECTION_INFORMATION connection_info;
-
- size = sizeof(*connection_info) + 30*sizeof(USB_PIPE_INFO);
- if (!(connection_info = malloc(size))) {
- free(connection_info_ex);
- continue;
- }
- connection_info->ConnectionIndex = index;
- if (!DeviceIoControl(hub_device,
- IOCTL_USB_GET_NODE_CONNECTION_INFORMATION,
- connection_info, size,
- connection_info, size, &size, NULL)) {
- free(connection_info);
- free(connection_info_ex);
- continue;
- }
-
- connection_info_ex->ConnectionIndex = connection_info->ConnectionIndex;
- connection_info_ex->DeviceDescriptor = connection_info->DeviceDescriptor;
- connection_info_ex->DeviceIsHub = connection_info->DeviceIsHub;
- connection_info_ex->DeviceAddress = connection_info->DeviceAddress;
- free(connection_info);
- }
-
- if (connection_info_ex->DeviceIsHub) {
- /* recursively enumerate external hub */
- PCHAR ext_hub_name;
- if ((ext_hub_name = get_external_hub_name(hub_device, index))) {
- snprintf(path, sizeof(path), "%s%d.",
- parent_path, connection_info_ex->ConnectionIndex);
- enumerate_hub(port, ext_hub_name, path);
- }
- free(connection_info_ex);
- } else {
- snprintf(path, sizeof(path), "%s%d",
- parent_path, connection_info_ex->ConnectionIndex);
-
- /* check if this device is the one we search for */
- if (strcmp(path, port->usb_path)) {
- free(connection_info_ex);
- continue;
- }
-
- /* finally grab detailed informations regarding the device */
- port->usb_address = connection_info_ex->DeviceAddress + 1;
- port->usb_vid = connection_info_ex->DeviceDescriptor.idVendor;
- port->usb_pid = connection_info_ex->DeviceDescriptor.idProduct;
-
- if (connection_info_ex->DeviceDescriptor.iManufacturer)
- port->usb_manufacturer = get_string_descriptor(hub_device,index,
- connection_info_ex->DeviceDescriptor.iManufacturer);
- if (connection_info_ex->DeviceDescriptor.iProduct)
- port->usb_product = get_string_descriptor(hub_device, index,
- connection_info_ex->DeviceDescriptor.iProduct);
- if (connection_info_ex->DeviceDescriptor.iSerialNumber)
- port->usb_serial = get_string_descriptor(hub_device, index,
- connection_info_ex->DeviceDescriptor.iSerialNumber);
-
- free(connection_info_ex);
- break;
- }
- }
-}
-
-static void enumerate_hub(struct sp_port *port, char *hub_name,
- char *parent_path)
-{
- USB_NODE_INFORMATION hub_info;
- HANDLE hub_device;
- ULONG size = sizeof(hub_info);
- char *device_name;
-
- /* open the hub with its full name */
- if (!(device_name = malloc(strlen("\\\\.\\") + strlen(hub_name) + 1)))
- return;
- strcpy(device_name, "\\\\.\\");
- strcat(device_name, hub_name);
- hub_device = CreateFile(device_name, GENERIC_WRITE, FILE_SHARE_WRITE,
- NULL, OPEN_EXISTING, 0, NULL);
- free(device_name);
- if (hub_device == INVALID_HANDLE_VALUE)
- return;
-
- /* get the number of ports of the hub */
- if (DeviceIoControl(hub_device, IOCTL_USB_GET_NODE_INFORMATION,
- &hub_info, size, &hub_info, size, &size, NULL))
- /* enumarate the ports of the hub */
- enumerate_hub_ports(port, hub_device,
- hub_info.u.HubInformation.HubDescriptor.bNumberOfPorts, parent_path);
-
- CloseHandle(hub_device);
-}
-
-static void enumerate_host_controller(struct sp_port *port,
- HANDLE host_controller_device)
-{
- char *root_hub_name;
-
- if ((root_hub_name = get_root_hub_name(host_controller_device))) {
- enumerate_hub(port, root_hub_name, "");
- free(root_hub_name);
- }
-}
-
-static void get_usb_details(struct sp_port *port, DEVINST dev_inst_match)
-{
- HDEVINFO device_info;
- SP_DEVINFO_DATA device_info_data;
- ULONG i, size = 0;
-
- device_info = SetupDiGetClassDevs(&GUID_CLASS_USB_HOST_CONTROLLER,NULL,NULL,
- DIGCF_PRESENT | DIGCF_DEVICEINTERFACE);
- device_info_data.cbSize = sizeof(device_info_data);
-
- for (i=0; SetupDiEnumDeviceInfo(device_info, i, &device_info_data); i++) {
- SP_DEVICE_INTERFACE_DATA device_interface_data;
- PSP_DEVICE_INTERFACE_DETAIL_DATA device_detail_data;
- DEVINST dev_inst = dev_inst_match;
- HANDLE host_controller_device;
-
- device_interface_data.cbSize = sizeof(device_interface_data);
- if (!SetupDiEnumDeviceInterfaces(device_info, 0,
- &GUID_CLASS_USB_HOST_CONTROLLER,
- i, &device_interface_data))
- continue;
-
- if (!SetupDiGetDeviceInterfaceDetail(device_info,&device_interface_data,
- NULL, 0, &size, NULL)
- && GetLastError() != ERROR_INSUFFICIENT_BUFFER)
- continue;
-
- if (!(device_detail_data = malloc(size)))
- continue;
- device_detail_data->cbSize = sizeof(*device_detail_data);
- if (!SetupDiGetDeviceInterfaceDetail(device_info,&device_interface_data,
- device_detail_data, size, &size,
- NULL)) {
- free(device_detail_data);
- continue;
- }
-
- while (CM_Get_Parent(&dev_inst, dev_inst, 0) == CR_SUCCESS
- && dev_inst != device_info_data.DevInst) { }
- if (dev_inst != device_info_data.DevInst) {
- free(device_detail_data);
- continue;
- }
-
- port->usb_bus = i + 1;
-
- host_controller_device = CreateFile(device_detail_data->DevicePath,
- GENERIC_WRITE, FILE_SHARE_WRITE,
- NULL, OPEN_EXISTING, 0, NULL);
- if (host_controller_device != INVALID_HANDLE_VALUE) {
- enumerate_host_controller(port, host_controller_device);
- CloseHandle(host_controller_device);
- }
- free(device_detail_data);
- }
-
- SetupDiDestroyDeviceInfoList(device_info);
- return;
-}
-
-#endif /* _WIN32 */
-
-static enum sp_return sp_get_port_details(struct sp_port *port)
-{
- /* Description limited to 127 char,
- anything longer would not be user friendly anyway */
- char description[128];