2 * Author: Christian Starkjohann
3 * Creation Date: 2008-04-11
5 * Copyright: (c) 2008 by OBJECTIVE DEVELOPMENT Software GmbH
6 * License: GNU GPL v2 (see License.txt), GNU GPL v3 or proprietary (CommercialLicense.txt)
14 #define DEBUG_PRINT(arg) printf arg
16 #define DEBUG_PRINT(arg)
19 #define A_MAX_USB_STRING_LEN 126
22 /* ######################################################################## */
24 /* ######################################################################## */
26 #include "targetver.h"
33 #pragma comment(lib, "setupapi")
34 #pragma comment(lib, "hid")
38 * Convert UTF-16 null term. string to single byte (ASCII or ISO Latin)
39 * change all weird characters to "?"
41 static void usbstring_to_ascii(unsigned short *wp
, char *cp
, int size
)
43 unsigned short *wpend
= wp
+ (size
/sizeof(unsigned short));
46 unsigned short h
= *wp
++;
47 *cp
++ = (h
< 0xFF) ? (char)h
: '?';
54 * Read HID string for vendor and device, return as ASCII (or ISO Latin...)
56 int usbhidGetVendorString(USBDEVHANDLE usbh
, char *buffer
, int len
)
58 /* HidD_GetManufacturerString returns zero terminated UTF-16 string */
59 /* Error if buffer is too short */
60 if ( !HidD_GetManufacturerString((HANDLE
)usbh
, (void*)buffer
, len
) ) {
61 DEBUG_PRINT(("error obtaining vendor name\n"));
62 return USBOPEN_ERR_IO
;
64 usbstring_to_ascii((UINT16
*)buffer
, buffer
, len
);
68 int usbhidGetProductString(USBDEVHANDLE usbh
, char *buffer
, int len
)
70 /* HidD_GetProductString returns zero terminated UTF-16 string */
71 /* Error if buffer is too short */
72 if (!HidD_GetProductString((HANDLE
)usbh
, (void*)buffer
, len
) ) {
73 DEBUG_PRINT(("error obtaining product name\n"));
74 return USBOPEN_ERR_IO
;
76 usbstring_to_ascii((UINT16
*)buffer
, buffer
, len
);
81 * Enumerate HID USB devices.
82 * In Windows this will find also non-USB devices, but assume that
83 * filtering by PID & VID is enough.
84 * Some HID devices (mice, kbd) are locked by Windows and cannot be opened.
85 * If we cannot open a device for R&W, we skip it without error.
86 * Assume our devices are not of types reserved by Windows.
88 int usbhidEnumDevices(int vendor
, int product
,
90 int (*usbhidEnumFunc
)(USBDEVHANDLE usbh
, void *ctx
))
92 GUID hidGuid
; /* GUID for HID class */
93 HDEVINFO deviceInfoList
;
94 SP_DEVICE_INTERFACE_DATA deviceInfo
;
95 SP_DEVICE_INTERFACE_DETAIL_DATA_W
*deviceDetails
= NULL
;
97 int i
, openFlag
= 0; /* may be FILE_FLAG_OVERLAPPED */
98 int errorCode
= USBOPEN_ERR_NOTFOUND
;
99 HANDLE handle
= INVALID_HANDLE_VALUE
;
100 HIDD_ATTRIBUTES deviceAttributes
;
102 HidD_GetHidGuid(&hidGuid
);
103 deviceInfoList
= SetupDiGetClassDevsW(&hidGuid
, NULL
, NULL
, DIGCF_PRESENT
| DIGCF_INTERFACEDEVICE
);
104 if (!deviceInfoList
|| deviceInfoList
== INVALID_HANDLE_VALUE
)
106 return USBOPEN_ERR_NOTFOUND
;
109 deviceInfo
.cbSize
= sizeof(deviceInfo
);
111 if(handle
!= INVALID_HANDLE_VALUE
){
113 handle
= INVALID_HANDLE_VALUE
;
115 if( !SetupDiEnumDeviceInterfaces(deviceInfoList
, 0, &hidGuid
, i
, &deviceInfo
) )
116 break; /* no more entries */
117 /* first do a dummy call just to determine the actual size required */
118 SetupDiGetDeviceInterfaceDetailW(deviceInfoList
, &deviceInfo
, NULL
, 0, &size
, NULL
);
119 if(deviceDetails
!= NULL
)
121 deviceDetails
= malloc(size
);
122 deviceDetails
->cbSize
= sizeof(*deviceDetails
);
123 /* this call is for real: */
124 SetupDiGetDeviceInterfaceDetailW(deviceInfoList
, &deviceInfo
, deviceDetails
, size
, &size
, NULL
);
125 DEBUG_PRINT(("checking HID path \"%s\"\n", deviceDetails
->DevicePath
));
127 handle
= CreateFileW(deviceDetails
->DevicePath
,
128 GENERIC_READ
|GENERIC_WRITE
, FILE_SHARE_READ
|FILE_SHARE_WRITE
, NULL
, OPEN_EXISTING
, openFlag
, NULL
);
129 if(handle
== INVALID_HANDLE_VALUE
){
130 DEBUG_PRINT(("open USB device failed: gle=%d\n", (int)GetLastError()));
131 /* errorCode = USBOPEN_ERR_ACCESS; opening will always fail for mouse -- ignore */
134 deviceAttributes
.Size
= sizeof(deviceAttributes
);
135 HidD_GetAttributes(handle
, &deviceAttributes
);
136 DEBUG_PRINT(("device attributes: vid=%d pid=%d ver=%4.4X\n", deviceAttributes
.VendorID
, deviceAttributes
.ProductID
, deviceAttributes
.VersionNumber
));
137 if(deviceAttributes
.VendorID
!= vendor
|| deviceAttributes
.ProductID
!= product
)
138 continue; /* skip this device */
141 if ( 0 == usbhidEnumFunc((USBDEVHANDLE
)handle
, context
) )
143 break; /* stop enumeration */
146 /* Now the handle is owned by the callback */
147 handle
= INVALID_HANDLE_VALUE
;
150 SetupDiDestroyDeviceInfoList(deviceInfoList
);
151 if(deviceDetails
!= NULL
)
159 void usbhidCloseDevice(USBDEVHANDLE usbh
)
161 CloseHandle((HANDLE
)usbh
);
166 int usbhidSetReport(USBDEVHANDLE usbh
, char *buffer
, int len
)
169 rval
= HidD_SetFeature((HANDLE
)usbh
, buffer
, len
);
170 return rval
== 0 ? USBOPEN_ERR_IO
: 0;
174 int usbhidGetReport(USBDEVHANDLE usbh
, int reportNumber
, char *buffer
, int *len
)
177 buffer
[0] = reportNumber
;
178 rval
= HidD_GetFeature((HANDLE
)usbh
, buffer
, *len
);
179 return rval
== 0 ? USBOPEN_ERR_IO
: 0;
184 /* ######################################################################## */
185 #else /* defined WIN32 #################################################### */
186 /* ######################################################################## */
190 #define usbDevice usb_dev_handle /* use libusb's device structure */
192 /* ------------------------------------------------------------------------- */
194 #define USBRQ_HID_GET_REPORT 0x01
195 #define USBRQ_HID_SET_REPORT 0x09
197 #define USB_HID_REPORT_TYPE_FEATURE 3
200 static int usesReportIDs
= 0; /* 1 => 1st byte of get/set report buffer is report ID */
202 /* ------------------------------------------------------------------------- */
204 static int usbhidGetStringAscii(usb_dev_handle
*dev
, int index
, char *buf
, int buflen
)
209 if((rval
= usb_get_string_simple(dev
, index
, buf
, buflen
)) >= 0) /* use libusb version if it works */
211 if((rval
= usb_control_msg(dev
, USB_ENDPOINT_IN
, USB_REQ_GET_DESCRIPTOR
, (USB_DT_STRING
<< 8) + index
, 0x0409, buffer
, sizeof(buffer
), 5000)) < 0)
213 if(buffer
[1] != USB_DT_STRING
){
217 if((unsigned char)buffer
[0] < rval
)
218 rval
= (unsigned char)buffer
[0];
220 /* lossy conversion to ISO Latin1: */
222 if(i
> buflen
) /* destination buffer overflow */
224 buf
[i
-1] = buffer
[2 * i
];
225 if(buffer
[2 * i
+ 1] != 0) /* outside of ISO Latin1 range */
232 int usbhidOpenDevice(usbDevice_t
**device
, int vendor
, char *vendorName
, int product
, char *productName
, int _usesReportIDs
)
235 struct usb_device
*dev
;
236 usb_dev_handle
*handle
= NULL
;
237 int errorCode
= USBOPEN_ERR_NOTFOUND
;
238 static int didUsbInit
= 0;
246 for(bus
=usb_get_busses(); bus
; bus
=bus
->next
){
247 for(dev
=bus
->devices
; dev
; dev
=dev
->next
){
248 if(dev
->descriptor
.idVendor
== vendor
&& dev
->descriptor
.idProduct
== product
){
251 handle
= usb_open(dev
); /* we need to open the device in order to query strings */
253 errorCode
= USBOPEN_ERR_ACCESS
;
254 fprintf(stderr
, "Warning: cannot open USB device: %s\n", usb_strerror());
257 if(vendorName
== NULL
&& productName
== NULL
){ /* name does not matter */
260 /* now check whether the names match: */
261 len
= usbhidGetStringAscii(handle
, dev
->descriptor
.iManufacturer
, string
, sizeof(string
));
263 errorCode
= USBOPEN_ERR_IO
;
264 fprintf(stderr
, "Warning: cannot query manufacturer for device: %s\n", usb_strerror());
266 errorCode
= USBOPEN_ERR_NOTFOUND
;
267 /* fprintf(stderr, "seen device from vendor ->%s<-\n", string); */
268 if(strcmp(string
, vendorName
) == 0){
269 len
= usbhidGetStringAscii(handle
, dev
->descriptor
.iProduct
, string
, sizeof(string
));
271 errorCode
= USBOPEN_ERR_IO
;
272 fprintf(stderr
, "Warning: cannot query product for device: %s\n", usb_strerror());
274 errorCode
= USBOPEN_ERR_NOTFOUND
;
275 /* fprintf(stderr, "seen product ->%s<-\n", string); */
276 if(strcmp(string
, productName
) == 0)
290 *device
= (void *)handle
;
291 usesReportIDs
= _usesReportIDs
;
296 /* ------------------------------------------------------------------------- */
298 void usbhidCloseDevice(usbDevice_t
*device
)
301 usb_close((void *)device
);
304 /* ------------------------------------------------------------------------- */
306 int usbhidSetReport(usbDevice_t
*device
, char *buffer
, int len
)
308 int bytesSent
, reportId
= buffer
[0];
311 buffer
++; /* skip dummy report ID */
314 bytesSent
= usb_control_msg((void *)device
, USB_TYPE_CLASS
| USB_RECIP_DEVICE
| USB_ENDPOINT_OUT
, USBRQ_HID_SET_REPORT
, USB_HID_REPORT_TYPE_FEATURE
<< 8 | (reportId
& 0xff), 0, buffer
, len
, 5000);
315 if(bytesSent
!= len
){
317 fprintf(stderr
, "Error sending message: %s\n", usb_strerror());
318 return USBOPEN_ERR_IO
;
323 /* ------------------------------------------------------------------------- */
325 int usbhidGetReport(usbDevice_t
*device
, int reportNumber
, char *buffer
, int *len
)
327 int bytesReceived
, maxLen
= *len
;
330 buffer
++; /* make room for dummy report ID */
333 bytesReceived
= usb_control_msg((void *)device
, USB_TYPE_CLASS
| USB_RECIP_DEVICE
| USB_ENDPOINT_IN
, USBRQ_HID_GET_REPORT
, USB_HID_REPORT_TYPE_FEATURE
<< 8 | reportNumber
, 0, buffer
, maxLen
, 5000);
334 if(bytesReceived
< 0){
335 fprintf(stderr
, "Error sending message: %s\n", usb_strerror());
336 return USBOPEN_ERR_IO
;
338 *len
= bytesReceived
;
340 buffer
[-1] = reportNumber
; /* add dummy report ID */
346 /* ######################################################################## */
348 /* ######################################################################## */