5 /* Inspired by hiddata.c|h by Christian Starkjohann
6 * Copyright: (c) 2008 by OBJECTIVE DEVELOPMENT Software GmbH
19 #define DEBUG_PRINT(arg) printf arg
21 #define DEBUG_PRINT(arg)
24 #include "targetver.h"
31 #pragma comment(lib, "setupapi")
32 #pragma comment(lib, "hid")
33 #if _MSC_VER < 1900 /* before VS2015 */
34 #define snprintf _snprintf
36 #else /* GCC, Mingw... */
40 * Convert UTF-16 null term. string to single byte (ASCII or ISO Latin)
41 * change all weird characters to "?"
43 static void usbstring_to_ascii(unsigned short *wp
, char *cp
, int size
)
45 unsigned short *wpend
= wp
+ (size
/sizeof(unsigned short));
48 unsigned short h
= *wp
++;
49 *cp
++ = (h
< 0xFF) ? (char)h
: '?';
56 * Read HID string for vendor and device, return as ASCII (or ISO Latin...)
58 int usbhidGetVendorString(USBDEVHANDLE usbh
, char *buffer
, int len
)
60 /* HidD_GetManufacturerString returns zero terminated UTF-16 string */
61 /* Error if buffer is too short */
62 if ( !HidD_GetManufacturerString((HANDLE
)usbh
, (void*)buffer
, len
) ) {
63 DEBUG_PRINT(("error obtaining vendor name\n"));
64 return USBHID_ERR_IO_HID
;
66 usbstring_to_ascii((UINT16
*)buffer
, buffer
, len
);
70 int usbhidGetProductString(USBDEVHANDLE usbh
, char *buffer
, int len
)
72 /* HidD_GetProductString returns zero terminated UTF-16 string */
73 /* Error if buffer is too short */
74 if (!HidD_GetProductString((HANDLE
)usbh
, (void*)buffer
, len
) ) {
75 DEBUG_PRINT(("error obtaining product name\n"));
76 return USBHID_ERR_IO_HID
;
78 usbstring_to_ascii((UINT16
*)buffer
, buffer
, len
);
83 * Enumerate HID USB devices.
84 * In Windows this will find also non-USB devices, but assume that
85 * filtering by PID & VID is enough.
86 * Some HID devices (mice, kbd) are locked by Windows and cannot be opened.
87 * If we cannot open a device for R&W, we skip it without error.
88 * Assume our devices are not of types reserved by Windows.
90 int usbhidEnumDevices(int vendor
, int product
,
92 int (*usbhidEnumFunc
)(USBDEVHANDLE usbh
, void *ctx
))
94 GUID hidGuid
; /* GUID for HID class */
95 HDEVINFO deviceInfoList
;
96 SP_DEVICE_INTERFACE_DATA deviceInfo
;
97 SP_DEVICE_INTERFACE_DETAIL_DATA_W
*deviceDetails
= NULL
;
101 int errorCode
= USBHID_ERR_NOTFOUND
;
102 HANDLE handle
= INVALID_HANDLE_VALUE
;
103 HIDD_ATTRIBUTES deviceAttributes
;
106 HidD_GetHidGuid(&hidGuid
);
107 deviceInfoList
= SetupDiGetClassDevsW(&hidGuid
, NULL
, NULL
, DIGCF_PRESENT
| DIGCF_INTERFACEDEVICE
);
108 if (!deviceInfoList
|| deviceInfoList
== INVALID_HANDLE_VALUE
)
110 return USBHID_ERR_NOTFOUND
;
113 deviceInfo
.cbSize
= sizeof(deviceInfo
);
115 if (handle
!= INVALID_HANDLE_VALUE
) {
117 handle
= INVALID_HANDLE_VALUE
;
119 if ( !SetupDiEnumDeviceInterfaces(deviceInfoList
, 0, &hidGuid
, i
, &deviceInfo
) )
120 break; /* no more entries */
121 /* First do a dummy call just to determine the actual size required */
123 SetupDiGetDeviceInterfaceDetailW(deviceInfoList
, &deviceInfo
, NULL
, 0, &size
, NULL
);
126 if (deviceDetails
!= NULL
)
128 deviceDetails
= malloc(size
);
129 if ( !deviceDetails
) {
130 DEBUG_PRINT(("ALLOC ERROR!\n"));
133 deviceDetails
->cbSize
= sizeof(*deviceDetails
);
135 b
= SetupDiGetDeviceInterfaceDetailW(deviceInfoList
, &deviceInfo
, deviceDetails
, size
, &size
, NULL
);
138 DEBUG_PRINT(("checking HID path \"%s\"\n", deviceDetails
->DevicePath
));
140 handle
= CreateFileW(deviceDetails
->DevicePath
,
141 GENERIC_READ
|GENERIC_WRITE
, FILE_SHARE_READ
|FILE_SHARE_WRITE
, NULL
, OPEN_EXISTING
, openFlags
, NULL
);
142 if (handle
== INVALID_HANDLE_VALUE
){
143 DEBUG_PRINT(("open USB device failed: gle=%d\n", (int)GetLastError()));
144 /* Opening devices owned by OS or other apps will fail ; just ignore these. */
147 deviceAttributes
.Size
= sizeof(deviceAttributes
);
148 HidD_GetAttributes(handle
, &deviceAttributes
);
149 DEBUG_PRINT(("device attributes: vid=%d pid=%d ver=%4.4X\n", deviceAttributes
.VendorID
, deviceAttributes
.ProductID
, deviceAttributes
.VersionNumber
));
150 if (deviceAttributes
.VendorID
!= vendor
|| deviceAttributes
.ProductID
!= product
)
151 continue; /* skip this device */
154 if ( 0 == usbhidEnumFunc((USBDEVHANDLE
)handle
, context
) )
156 break; /* stop enumeration */
159 /* Now the handle is owned by the callback It may close it before return or later. */
160 handle
= INVALID_HANDLE_VALUE
;
163 SetupDiDestroyDeviceInfoList(deviceInfoList
);
164 if (deviceDetails
!= NULL
)
171 void usbhidCloseDevice(USBDEVHANDLE usbh
)
173 CloseHandle((HANDLE
)usbh
);
177 int usbhidSetReport(USBDEVHANDLE usbh
, char *buffer
, int len
)
180 rval
= HidD_SetFeature((HANDLE
)usbh
, buffer
, len
);
181 return rval
== 0 ? USBHID_ERR_IO_HID
: 0;
185 int usbhidGetReport(USBDEVHANDLE usbh
, int reportNumber
, char *buffer
, int *len
)
188 buffer
[0] = (char)reportNumber
;
189 rval
= HidD_GetFeature((HANDLE
)usbh
, buffer
, *len
);
190 return rval
== 0 ? USBHID_ERR_IO_HID
: 0;
194 int usbhidStrerror_r( int err
, char *buf
, int len
)
198 case USBHID_ERR_ACCESS
: s
= "Access to device denied";
200 case USBHID_ERR_NOTFOUND
: s
= "The specified device was not found";
202 case USBHID_ERR_IO
: s
= "Communication error with device";
204 case USBHID_ERR_IO_HID
: s
= "HID I/O error with device";
210 return snprintf(buf
, len
, "%s", s
);