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)
13 #define DEBUG_PRINT(arg) printf arg
15 #define DEBUG_PRINT(arg)
18 /* ######################################################################## */
19 #if defined(_WIN32) /* ##################################################### */
20 /* ######################################################################## */
22 #include "targetver.h"
29 #pragma comment(lib, "setupapi")
30 #pragma comment(lib, "hid")
34 /* ------------------------------------------------------------------------ */
36 static void convertUniToAscii(char *buffer
)
38 unsigned short *uni
= (void *)buffer
;
45 *ascii
++ = (char)(*uni
++);
51 int usbhidOpenDevice(usbDevice_t
**device
, int vendor
, char *vendorName
, int product
, char *productName
, int usesReportIDs
)
53 GUID hidGuid
; /* GUID for HID driver */
54 HDEVINFO deviceInfoList
;
55 SP_DEVICE_INTERFACE_DATA deviceInfo
;
56 SP_DEVICE_INTERFACE_DETAIL_DATA
*deviceDetails
= NULL
;
58 int i
, openFlag
= 0; /* may be FILE_FLAG_OVERLAPPED */
59 int errorCode
= USBOPEN_ERR_NOTFOUND
;
60 HANDLE handle
= INVALID_HANDLE_VALUE
;
61 HIDD_ATTRIBUTES deviceAttributes
;
63 HidD_GetHidGuid(&hidGuid
);
64 deviceInfoList
= SetupDiGetClassDevs(&hidGuid
, NULL
, NULL
, DIGCF_PRESENT
| DIGCF_INTERFACEDEVICE
);
65 deviceInfo
.cbSize
= sizeof(deviceInfo
);
67 if(handle
!= INVALID_HANDLE_VALUE
){
69 handle
= INVALID_HANDLE_VALUE
;
71 if(!SetupDiEnumDeviceInterfaces(deviceInfoList
, 0, &hidGuid
, i
, &deviceInfo
))
72 break; /* no more entries */
73 /* first do a dummy call just to determine the actual size required */
74 SetupDiGetDeviceInterfaceDetail(deviceInfoList
, &deviceInfo
, NULL
, 0, &size
, NULL
);
75 if(deviceDetails
!= NULL
)
77 deviceDetails
= malloc(size
);
78 deviceDetails
->cbSize
= sizeof(*deviceDetails
);
79 /* this call is for real: */
80 SetupDiGetDeviceInterfaceDetail(deviceInfoList
, &deviceInfo
, deviceDetails
, size
, &size
, NULL
);
81 DEBUG_PRINT(("checking HID path \"%s\"\n", deviceDetails
->DevicePath
));
83 /* If we want to access a mouse or keyboard, we can only use feature
84 * requests as the device is locked by Windows. It must be opened
85 * with ACCESS_TYPE_NONE.
87 handle
= CreateFile(deviceDetails
->DevicePath
, ACCESS_TYPE_NONE
, FILE_SHARE_READ
| FILE_SHARE_WRITE
, NULL
, OPEN_EXISTING
, openFlag
, NULL
);
89 /* attempt opening for R/W -- we don't care about devices which can't be accessed */
90 handle
= CreateFile(deviceDetails
->DevicePath
, GENERIC_READ
|GENERIC_WRITE
, FILE_SHARE_READ
|FILE_SHARE_WRITE
, NULL
, OPEN_EXISTING
, openFlag
, NULL
);
91 if(handle
== INVALID_HANDLE_VALUE
){
92 DEBUG_PRINT(("opening failed: %d\n", (int)GetLastError()));
93 /* errorCode = USBOPEN_ERR_ACCESS; opening will always fail for mouse -- ignore */
96 deviceAttributes
.Size
= sizeof(deviceAttributes
);
97 HidD_GetAttributes(handle
, &deviceAttributes
);
98 DEBUG_PRINT(("device attributes: vid=%d pid=%d\n", deviceAttributes
.VendorID
, deviceAttributes
.ProductID
));
99 if(deviceAttributes
.VendorID
!= vendor
|| deviceAttributes
.ProductID
!= product
)
100 continue; /* ignore this device */
101 errorCode
= USBOPEN_ERR_NOTFOUND
;
102 if(vendorName
!= NULL
&& productName
!= NULL
){
104 memset(buffer
, 0xFF, sizeof(buffer
));
105 if(!HidD_GetManufacturerString(handle
, buffer
, sizeof(buffer
))){
106 DEBUG_PRINT(("error obtaining vendor name\n"));
107 errorCode
= USBOPEN_ERR_IO
;
110 convertUniToAscii(buffer
);
111 DEBUG_PRINT(("vendorName = \"%s\"\n", buffer
));
112 if(strcmp(vendorName
, buffer
) != 0)
114 memset(buffer
, 0xFF, sizeof(buffer
));
115 if(!HidD_GetProductString(handle
, buffer
, sizeof(buffer
))){
116 DEBUG_PRINT(("error obtaining product name\n"));
117 errorCode
= USBOPEN_ERR_IO
;
120 convertUniToAscii(buffer
);
121 DEBUG_PRINT(("productName = \"%s\"\n", buffer
));
122 if(strcmp(productName
, buffer
) != 0)
125 break; /* we have found the device we are looking for! */
127 SetupDiDestroyDeviceInfoList(deviceInfoList
);
128 if(deviceDetails
!= NULL
)
130 if(handle
!= INVALID_HANDLE_VALUE
){
131 *device
= (usbDevice_t
*)handle
;
137 /* ------------------------------------------------------------------------ */
139 void usbhidCloseDevice(usbDevice_t
*device
)
141 CloseHandle((HANDLE
)device
);
144 /* ------------------------------------------------------------------------ */
146 int usbhidSetReport(usbDevice_t
*device
, char *buffer
, int len
)
150 rval
= HidD_SetFeature((HANDLE
)device
, buffer
, len
);
151 return rval
== 0 ? USBOPEN_ERR_IO
: 0;
154 /* ------------------------------------------------------------------------ */
156 int usbhidGetReport(usbDevice_t
*device
, int reportNumber
, char *buffer
, int *len
)
160 buffer
[0] = reportNumber
;
161 rval
= HidD_GetFeature((HANDLE
)device
, buffer
, *len
);
162 return rval
== 0 ? USBOPEN_ERR_IO
: 0;
165 /* ------------------------------------------------------------------------ */
167 /* ######################################################################## */
168 #else /* defined WIN32 #################################################### */
169 /* ######################################################################## */
174 #define usbDevice usb_dev_handle /* use libusb's device structure */
176 /* ------------------------------------------------------------------------- */
178 #define USBRQ_HID_GET_REPORT 0x01
179 #define USBRQ_HID_SET_REPORT 0x09
181 #define USB_HID_REPORT_TYPE_FEATURE 3
184 static int usesReportIDs
;
186 /* ------------------------------------------------------------------------- */
188 static int usbhidGetStringAscii(usb_dev_handle
*dev
, int index
, char *buf
, int buflen
)
193 if((rval
= usb_get_string_simple(dev
, index
, buf
, buflen
)) >= 0) /* use libusb version if it works */
195 if((rval
= usb_control_msg(dev
, USB_ENDPOINT_IN
, USB_REQ_GET_DESCRIPTOR
, (USB_DT_STRING
<< 8) + index
, 0x0409, buffer
, sizeof(buffer
), 5000)) < 0)
197 if(buffer
[1] != USB_DT_STRING
){
201 if((unsigned char)buffer
[0] < rval
)
202 rval
= (unsigned char)buffer
[0];
204 /* lossy conversion to ISO Latin1: */
206 if(i
> buflen
) /* destination buffer overflow */
208 buf
[i
-1] = buffer
[2 * i
];
209 if(buffer
[2 * i
+ 1] != 0) /* outside of ISO Latin1 range */
216 int usbhidOpenDevice(usbDevice_t
**device
, int vendor
, char *vendorName
, int product
, char *productName
, int _usesReportIDs
)
219 struct usb_device
*dev
;
220 usb_dev_handle
*handle
= NULL
;
221 int errorCode
= USBOPEN_ERR_NOTFOUND
;
222 static int didUsbInit
= 0;
230 for(bus
=usb_get_busses(); bus
; bus
=bus
->next
){
231 for(dev
=bus
->devices
; dev
; dev
=dev
->next
){
232 if(dev
->descriptor
.idVendor
== vendor
&& dev
->descriptor
.idProduct
== product
){
235 handle
= usb_open(dev
); /* we need to open the device in order to query strings */
237 errorCode
= USBOPEN_ERR_ACCESS
;
238 fprintf(stderr
, "Warning: cannot open USB device: %s\n", usb_strerror());
241 if(vendorName
== NULL
&& productName
== NULL
){ /* name does not matter */
244 /* now check whether the names match: */
245 len
= usbhidGetStringAscii(handle
, dev
->descriptor
.iManufacturer
, string
, sizeof(string
));
247 errorCode
= USBOPEN_ERR_IO
;
248 fprintf(stderr
, "Warning: cannot query manufacturer for device: %s\n", usb_strerror());
250 errorCode
= USBOPEN_ERR_NOTFOUND
;
251 /* fprintf(stderr, "seen device from vendor ->%s<-\n", string); */
252 if(strcmp(string
, vendorName
) == 0){
253 len
= usbhidGetStringAscii(handle
, dev
->descriptor
.iProduct
, string
, sizeof(string
));
255 errorCode
= USBOPEN_ERR_IO
;
256 fprintf(stderr
, "Warning: cannot query product for device: %s\n", usb_strerror());
258 errorCode
= USBOPEN_ERR_NOTFOUND
;
259 /* fprintf(stderr, "seen product ->%s<-\n", string); */
260 if(strcmp(string
, productName
) == 0)
274 *device
= (void *)handle
;
275 usesReportIDs
= _usesReportIDs
;
280 /* ------------------------------------------------------------------------- */
282 void usbhidCloseDevice(usbDevice_t
*device
)
285 usb_close((void *)device
);
288 /* ------------------------------------------------------------------------- */
290 int usbhidSetReport(usbDevice_t
*device
, char *buffer
, int len
)
292 int bytesSent
, reportId
= buffer
[0];
295 buffer
++; /* skip dummy report ID */
298 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);
299 if(bytesSent
!= len
){
301 fprintf(stderr
, "Error sending message: %s\n", usb_strerror());
302 return USBOPEN_ERR_IO
;
307 /* ------------------------------------------------------------------------- */
309 int usbhidGetReport(usbDevice_t
*device
, int reportNumber
, char *buffer
, int *len
)
311 int bytesReceived
, maxLen
= *len
;
314 buffer
++; /* make room for dummy report ID */
317 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);
318 if(bytesReceived
< 0){
319 fprintf(stderr
, "Error sending message: %s\n", usb_strerror());
320 return USBOPEN_ERR_IO
;
322 *len
= bytesReceived
;
324 buffer
[-1] = reportNumber
; /* add dummy report ID */
330 /* ######################################################################## */
331 #endif /* defined WIN32 ################################################### */
332 /* ######################################################################## */