1 // Copyright (C) 2018-2019 Intel Corporation
2 // SPDX-License-Identifier: Apache-2.0
5 #pragma comment(lib, "winusb.lib")
6 #pragma comment(lib, "setupapi.lib")
7 //#define _CRT_SECURE_NO_WARNINGS
17 #include "usb_winusb.h"
22 #define USB_DEV_NONE NULL
23 #define USB_HAN_NONE NULL
25 #define USB_ERR_NONE 0
26 #define USB_ERR_TIMEOUT -1
27 #define USB_ERR_FAILED -2
28 #define USB_ERR_INVALID -3
40 WINUSB_INTERFACE_HANDLE winUsbHan;
41 struct ep_info eps[2];
44 extern const char * usb_get_pid_name(int);
46 #if defined(_MSC_VER) && _MSC_VER < 1900
47 #define snprintf _snprintf
50 // Myriad 2: {19E08104-0543-40A5-B107-87EF463DCEF1}
51 DEFINE_GUID(GUID_DEVINTERFACE_Myriad2, 0x19e08104, 0x0543, 0x40a5,
52 0xb1, 0x07, 0x87, 0xef, 0x46, 0x3d, 0xce, 0xf1);
54 // Myriad X: {504E1220-E189-413A-BDEC-ECFFAF3A3731}
55 DEFINE_GUID(GUID_DEVINTERFACE_MyriadX, 0x504e1220, 0xe189, 0x413a,
56 0xbd, 0xec, 0xec, 0xff, 0xaf, 0x3a, 0x37, 0x31);
58 static FILE *msgfile = NULL;
59 static int verbose = 0, ignore_errors = 0;
60 static DWORD last_bulk_errcode = 0;
61 static char *errmsg_buff = NULL;
62 static size_t errmsg_buff_len = 0;
64 static const char *format_win32_msg(DWORD errId) {
65 while(!FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS,
66 NULL, errId, 0, errmsg_buff, (DWORD)errmsg_buff_len, NULL)) {
67 if(GetLastError() != ERROR_INSUFFICIENT_BUFFER) {
69 snprintf(errmsg_buff, errmsg_buff_len, "Win32 Error 0x%08lx (Unable to retrieve error message)", errId);
72 size_t nlen = errmsg_buff_len + (errmsg_buff_len / 2);
75 char *nbuff = realloc(errmsg_buff, nlen);
79 errmsg_buff_len = nlen;
84 static void wperror(const char *errmsg) {
85 DWORD errId = GetLastError();
86 fprintf(stderr, "%s: System err %d\n", errmsg, errId);
89 static void wstrerror(char *buff, const char *errmsg) {
90 DWORD errId = GetLastError();
91 snprintf(buff,strlen(buff), "%s: %s\n", errmsg, format_win32_msg(errId));
93 const char* libusb_strerror(int x)
95 return format_win32_msg(x);
99 if(errmsg_buff == NULL) {
100 errmsg_buff_len = 64;
101 errmsg_buff = malloc(errmsg_buff_len);
102 if(errmsg_buff == NULL) {
110 void usb_shutdown(void) {
111 if(errmsg_buff != NULL) {
117 int usb_can_find_by_guid(void) {
121 static usb_dev retreive_dev_path(HDEVINFO devInfo, SP_DEVICE_INTERFACE_DATA *ifaceData) {
123 PSP_DEVICE_INTERFACE_DETAIL_DATA detData;
126 if(!SetupDiGetDeviceInterfaceDetail(devInfo, ifaceData, NULL, 0, &reqLen, NULL)) {
127 if(GetLastError() != ERROR_INSUFFICIENT_BUFFER) {
128 wperror("SetupDiEnumDeviceInterfaces");
129 SetupDiDestroyDeviceInfoList(devInfo);
133 detData = (PSP_DEVICE_INTERFACE_DETAIL_DATA)_alloca(reqLen);
134 detData->cbSize = sizeof(*detData);
136 if(!SetupDiGetDeviceInterfaceDetail(devInfo, ifaceData, detData, len, &reqLen, NULL)) {
137 wperror("SetupDiGetDeviceInterfaceDetail");
138 SetupDiDestroyDeviceInfoList(devInfo);
141 res = _strdup(detData->DevicePath);
145 SetupDiDestroyDeviceInfoList(devInfo);
149 static const char *gen_addr(HDEVINFO devInfo, SP_DEVINFO_DATA *devInfoData, uint16_t pid) {
150 static char buff[16];
152 unsigned int port, hub;
153 if (!SetupDiGetDeviceRegistryProperty(devInfo, devInfoData, SPDRP_LOCATION_INFORMATION, NULL, li_buff, sizeof(li_buff), NULL))
157 if(sscanf(li_buff, "Port_#%u.Hub_#%u", &port, &hub) != 2)
160 //matching it to libusboutput
161 const char* dev_name = usb_get_pid_name(pid);
165 snprintf(buff, sizeof(buff), "%u.%u-%s", hub, port, dev_name);
166 buff[sizeof(buff) - 1] = '\0';
171 extern DEFAULT_OPENPID;
173 static int compareDeviceByHubAndPort(const void *l, const void *r) {
174 int lHub = 0, lPort = 0;
175 int rHub = 0, rPort = 0;
177 if (sscanf(((const char *)l + 4), "%d.%d", &lHub, &lPort) == EOF) {
178 perror("Can not parse hub and port of the devices");
180 if (sscanf(((const char *)r + 4), "%d.%d", &rHub, &rPort) == EOF) {
181 perror("Can not parse hub and port of the devices");
188 return rPort - lPort;
191 int usb_list_devices(uint16_t vid, uint16_t pid, uint8_t dev_des[][2 + 2 + 4 * 7 + 7]) {
194 SP_DEVINFO_DATA devInfoData;
197 devInfoData.cbSize = sizeof(devInfoData);
199 devInfo = SetupDiGetClassDevs(&GUID_DEVINTERFACE_USB_DEVICE, NULL, NULL, DIGCF_PRESENT | DIGCF_DEVICEINTERFACE);
200 if(devInfo == INVALID_HANDLE_VALUE) {
201 wperror("SetupDiGetClassDevs");
205 for (i=0; SetupDiEnumDeviceInfo(devInfo, i, &devInfoData); i++) {
206 if (!SetupDiGetDeviceRegistryProperty(devInfo, &devInfoData, SPDRP_HARDWAREID, NULL, hwid_buff, sizeof(hwid_buff), NULL)) {
210 if(sscanf(hwid_buff, "USB\\VID_%hx&PID_%hx", (int16_t *)&fvid, (int16_t *)&fpid) != 2) {
214 dev_des[i][0] = ((fvid & 0xFF00)>>8);
215 dev_des[i][1] = ((fvid & 0x00FF) >> 0);
216 dev_des[i][2] = ((fpid & 0xFF00) >> 8);
217 dev_des[i][3] = ((fpid & 0x00FF) >> 0);
218 sprintf((char *)&dev_des[i][4], "%s", gen_addr(devInfo, &devInfoData, fpid));
220 SetupDiDestroyDeviceInfoList(devInfo);
222 qsort(dev_des, i, sizeof(dev_des[0]), compareDeviceByHubAndPort);
227 void * enumerate_usb_device(uint16_t vid, uint16_t pid, const char *addr, int loud) {
229 SP_DEVICE_INTERFACE_DATA ifaceData;
231 SP_DEVINFO_DATA devInfoData;
233 int found, found_ind = -1;
236 devInfoData.cbSize = sizeof(devInfoData);
238 devInfo = SetupDiGetClassDevs(&GUID_DEVINTERFACE_USB_DEVICE, NULL, NULL, DIGCF_PRESENT | DIGCF_DEVICEINTERFACE);
239 if(devInfo == INVALID_HANDLE_VALUE) {
240 wperror("SetupDiGetClassDevs");
244 for(i=0; SetupDiEnumDeviceInfo(devInfo, i, &devInfoData); i++) {
245 if(!SetupDiGetDeviceRegistryProperty(devInfo, &devInfoData, SPDRP_HARDWAREID, NULL, hwid_buff, sizeof(hwid_buff), NULL))
248 if(sscanf(hwid_buff, "USB\\VID_%hx&PID_%hx", (int16_t*)&fvid, (int16_t*)&fpid) != 2)
251 fprintf(msgfile, "Vendor/Product ID: %04x:%04x\n", fvid, fpid);
252 if((fvid == vid) && (fpid == pid)) {
253 caddr = gen_addr(devInfo, &devInfoData, fpid);
254 if((addr == NULL) || !strcmp(caddr, addr)) {
256 fprintf(msgfile, "Found device with VID/PID %04x:%04x , address %s\n", vid, pid, caddr);
261 if(!(verbose && loud))
267 SetupDiDestroyDeviceInfoList(devInfo);
270 if(verbose && loud) {
271 if(!SetupDiEnumDeviceInfo(devInfo, found_ind, &devInfoData)) {
272 wperror("SetupDiEnumDeviceInfo");
273 SetupDiDestroyDeviceInfoList(devInfo);
277 ifaceData.cbSize = sizeof(ifaceData);
278 if(!SetupDiEnumDeviceInterfaces(devInfo, &devInfoData, &GUID_DEVINTERFACE_USB_DEVICE, 0, &ifaceData)) {
279 if(GetLastError() != ERROR_NO_MORE_ITEMS) {
280 wperror("SetupDiEnumDeviceInterfaces");
282 SetupDiDestroyDeviceInfoList(devInfo);
285 return retreive_dev_path(devInfo, &ifaceData);
288 usb_dev findDeviceByGUID(GUID guid, int loud)
291 SP_DEVICE_INTERFACE_DATA ifaceData;
293 devInfo = SetupDiGetClassDevs(&guid, NULL, NULL, DIGCF_PRESENT | DIGCF_DEVICEINTERFACE);
294 if (devInfo == INVALID_HANDLE_VALUE) {
295 wperror("SetupDiGetClassDevs");
298 ifaceData.cbSize = sizeof(ifaceData);
299 if (!SetupDiEnumDeviceInterfaces(devInfo, NULL, &guid, 0, &ifaceData)) {
300 if (GetLastError() != ERROR_NO_MORE_ITEMS) {
301 wperror("SetupDiEnumDeviceInterfaces");
303 SetupDiDestroyDeviceInfoList(devInfo);
306 return retreive_dev_path(devInfo, &ifaceData);
309 void * usb_find_device_by_guid(int loud) {
310 void *dev = USB_DEV_NONE;
312 dev = findDeviceByGUID(GUID_DEVINTERFACE_Myriad2, loud);
313 if (dev == USB_DEV_NONE)
316 dev = findDeviceByGUID(GUID_DEVINTERFACE_MyriadX, loud);
321 int usb_check_connected(usb_dev dev) {
323 if(dev == USB_DEV_NONE)
325 han = CreateFile(dev, 0, FILE_SHARE_WRITE | FILE_SHARE_READ,
326 NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL | FILE_FLAG_OVERLAPPED, NULL);
327 if(han == INVALID_HANDLE_VALUE)
333 void * usb_open_device(usb_dev dev, uint8_t *ep, uint8_t intfaceno, char *err_string_buff) {
334 HANDLE devHan = INVALID_HANDLE_VALUE;
335 WINUSB_INTERFACE_HANDLE winUsbHan = INVALID_HANDLE_VALUE;
336 USB_INTERFACE_DESCRIPTOR ifaceDesc;
337 WINUSB_PIPE_INFORMATION pipeInfo;
341 if(dev == USB_DEV_NONE)
344 devHan = CreateFile(dev, GENERIC_WRITE | GENERIC_READ, FILE_SHARE_WRITE | FILE_SHARE_READ,
345 NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL | FILE_FLAG_OVERLAPPED, NULL);
346 if(devHan == INVALID_HANDLE_VALUE) {
347 if(err_string_buff != NULL)
348 wstrerror(err_string_buff, "CreateFile");
352 if(!WinUsb_Initialize(devHan, &winUsbHan)) {
353 if (err_string_buff != NULL)
354 wstrerror(err_string_buff, "WinUsb_Initialize");
358 if(!WinUsb_QueryInterfaceSettings(winUsbHan, 0, &ifaceDesc)) {
359 if (err_string_buff != NULL)
360 wstrerror(err_string_buff, "WinUsb_QueryInterfaceSettings");
364 han = calloc(1, sizeof(*han));
366 strcpy(err_string_buff, _strerror("malloc"));
369 han->devHan = devHan;
370 han->winUsbHan = winUsbHan;
372 for(i=0; i<ifaceDesc.bNumEndpoints; i++) {
373 if(!WinUsb_QueryPipe(winUsbHan, 0, i, &pipeInfo)) {
374 if (err_string_buff != NULL)
375 wstrerror(err_string_buff, "WinUsb_QueryPipe");
380 fprintf(msgfile, "Found EP 0x%02x : max packet size is %u bytes\n",
381 pipeInfo.PipeId, pipeInfo.MaximumPacketSize);
383 if(pipeInfo.PipeType != UsbdPipeTypeBulk)
385 int ind = USB_ENDPOINT_DIRECTION_IN(pipeInfo.PipeId) ? USB_DIR_IN : USB_DIR_OUT;
386 han->eps[ind].ep = pipeInfo.PipeId;
387 han->eps[ind].sz = pipeInfo.MaximumPacketSize;
388 han->eps[ind].last_timeout = 0;
391 *ep = han->eps[USB_DIR_OUT].ep;
393 if(err_string_buff && (han->eps[USB_DIR_IN].ep == 0)) {
394 sprintf(err_string_buff, "Unable to find BULK IN endpoint\n");
397 if(err_string_buff && (han->eps[USB_DIR_OUT].ep == 0)) {
398 sprintf(err_string_buff, "Unable to find BULK OUT endpoint\n");
401 if(err_string_buff && (han->eps[USB_DIR_IN].sz == 0)) {
402 sprintf(err_string_buff, "Unable to find BULK IN endpoint size\n");
405 if(err_string_buff && (han->eps[USB_DIR_OUT].sz == 0)) {
406 sprintf(err_string_buff, "Unable to find BULK OUT endpoint size\n");
411 usb_close_device(han);
415 uint8_t usb_get_bulk_endpoint(usb_hwnd han, int dir) {
416 if((han == NULL) || ((dir != USB_DIR_OUT) && (dir != USB_DIR_IN)))
418 return han->eps[dir].ep;
421 size_t usb_get_endpoint_size(usb_hwnd han, uint8_t ep) {
424 if(han->eps[USB_DIR_OUT].ep == ep)
425 return han->eps[USB_DIR_OUT].sz;
426 if(han->eps[USB_DIR_IN].ep == ep)
427 return han->eps[USB_DIR_IN].sz;
431 int usb_bulk_write(usb_hwnd han, uint8_t ep, const void *buffer, size_t sz, uint32_t *wrote_bytes, int timeout_ms) {
433 if(wrote_bytes != NULL)
436 return USB_ERR_INVALID;
438 if(timeout_ms != han->eps[USB_DIR_OUT].last_timeout) {
439 han->eps[USB_DIR_OUT].last_timeout = timeout_ms;
440 if(!WinUsb_SetPipePolicy(han->winUsbHan, ep, PIPE_TRANSFER_TIMEOUT,
441 sizeof(ULONG), &han->eps[USB_DIR_OUT].last_timeout)) {
442 last_bulk_errcode = GetLastError();
443 wperror("WinUsb_SetPipePolicy");
444 return USB_ERR_FAILED;
447 if(!WinUsb_WritePipe(han->winUsbHan, ep, (PUCHAR)buffer, (ULONG)sz, &wb, NULL)) {
448 last_bulk_errcode = GetLastError();
449 if(last_bulk_errcode == ERROR_SEM_TIMEOUT)
450 return USB_ERR_TIMEOUT;
451 wperror("WinUsb_WritePipe");
452 printf("\nWinUsb_WritePipe failed with error:=%d\n", GetLastError());
453 return USB_ERR_FAILED;
455 last_bulk_errcode = 0;
456 if(wrote_bytes != NULL)
461 int usb_bulk_read(usb_hwnd han, uint8_t ep, void *buffer, size_t sz, uint32_t *read_bytes, int timeout_ms) {
463 if(read_bytes != NULL)
466 return USB_ERR_INVALID;
468 if(timeout_ms != han->eps[USB_DIR_IN].last_timeout) {
469 han->eps[USB_DIR_IN].last_timeout = timeout_ms;
470 if(!WinUsb_SetPipePolicy(han->winUsbHan, ep, PIPE_TRANSFER_TIMEOUT,
471 sizeof(ULONG), &han->eps[USB_DIR_IN].last_timeout)) {
472 last_bulk_errcode = GetLastError();
473 wperror("WinUsb_SetPipePolicy");
474 return USB_ERR_FAILED;
479 if(!WinUsb_ReadPipe(han->winUsbHan, ep, buffer, (ULONG)sz, &rb, NULL)) {
480 last_bulk_errcode = GetLastError();
481 if(last_bulk_errcode == ERROR_SEM_TIMEOUT)
482 return USB_ERR_TIMEOUT;
483 wperror("WinUsb_ReadPipe");
484 return USB_ERR_FAILED;
486 last_bulk_errcode = 0;
487 if(read_bytes != NULL)
492 void usb_free_device(usb_dev dev) {
497 void usb_close_device(usb_hwnd han) {
500 WinUsb_Free(han->winUsbHan);
501 CloseHandle(han->devHan);
505 const char *usb_last_bulk_errmsg(void) {
506 return format_win32_msg(last_bulk_errcode);
509 void usb_set_msgfile(FILE *file) {
513 void usb_set_verbose(int value) {
517 void usb_set_ignoreerrors(int value) {
518 ignore_errors = value;