add commandline utility
[usb-relay-hid.git] / commandline / hiddata.c
1 /* Name: hiddata.c
2 * Author: Christian Starkjohann
3 * Creation Date: 2008-04-11
4 * Tabsize: 4
5 * Copyright: (c) 2008 by OBJECTIVE DEVELOPMENT Software GmbH
6 * License: GNU GPL v2 (see License.txt), GNU GPL v3 or proprietary (CommercialLicense.txt)
7 */
8
9 #include <stdio.h>
10 #include "hiddata.h"
11
12 #if 0 //ifdef DEBUG
13 #define DEBUG_PRINT(arg) printf arg
14 #else
15 #define DEBUG_PRINT(arg)
16 #endif
17
18 /* ######################################################################## */
19 #if defined(_WIN32) /* ##################################################### */
20 /* ######################################################################## */
21
22 #include "targetver.h"
23 #include <windows.h>
24 #include <setupapi.h>
25 #include <hidsdi.h>
26 #include <hidpi.h>
27
28 #ifdef _MSC_VER
29 #pragma comment(lib, "setupapi")
30 #pragma comment(lib, "hid")
31 #endif /*_MSC_VER*/
32
33
34 /* ------------------------------------------------------------------------ */
35
36 static void convertUniToAscii(char *buffer)
37 {
38 unsigned short *uni = (void *)buffer;
39 char *ascii = buffer;
40
41 while(*uni != 0){
42 if(*uni >= 256){
43 *ascii++ = '?';
44 }else{
45 *ascii++ = (char)(*uni++);
46 }
47 }
48 *ascii++ = 0;
49 }
50
51 int usbhidOpenDevice(usbDevice_t **device, int vendor, char *vendorName, int product, char *productName, int usesReportIDs)
52 {
53 GUID hidGuid; /* GUID for HID driver */
54 HDEVINFO deviceInfoList;
55 SP_DEVICE_INTERFACE_DATA deviceInfo;
56 SP_DEVICE_INTERFACE_DETAIL_DATA *deviceDetails = NULL;
57 DWORD size;
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;
62
63 HidD_GetHidGuid(&hidGuid);
64 deviceInfoList = SetupDiGetClassDevs(&hidGuid, NULL, NULL, DIGCF_PRESENT | DIGCF_INTERFACEDEVICE);
65 deviceInfo.cbSize = sizeof(deviceInfo);
66 for(i=0;;i++){
67 if(handle != INVALID_HANDLE_VALUE){
68 CloseHandle(handle);
69 handle = INVALID_HANDLE_VALUE;
70 }
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)
76 free(deviceDetails);
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));
82 #if 0
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.
86 */
87 handle = CreateFile(deviceDetails->DevicePath, ACCESS_TYPE_NONE, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, openFlag, NULL);
88 #endif
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 */
94 continue;
95 }
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){
103 char buffer[512];
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;
108 continue;
109 }
110 convertUniToAscii(buffer);
111 DEBUG_PRINT(("vendorName = \"%s\"\n", buffer));
112 if(strcmp(vendorName, buffer) != 0)
113 continue;
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;
118 continue;
119 }
120 convertUniToAscii(buffer);
121 DEBUG_PRINT(("productName = \"%s\"\n", buffer));
122 if(strcmp(productName, buffer) != 0)
123 continue;
124 }
125 break; /* we have found the device we are looking for! */
126 }
127 SetupDiDestroyDeviceInfoList(deviceInfoList);
128 if(deviceDetails != NULL)
129 free(deviceDetails);
130 if(handle != INVALID_HANDLE_VALUE){
131 *device = (usbDevice_t *)handle;
132 errorCode = 0;
133 }
134 return errorCode;
135 }
136
137 /* ------------------------------------------------------------------------ */
138
139 void usbhidCloseDevice(usbDevice_t *device)
140 {
141 CloseHandle((HANDLE)device);
142 }
143
144 /* ------------------------------------------------------------------------ */
145
146 int usbhidSetReport(usbDevice_t *device, char *buffer, int len)
147 {
148 BOOLEAN rval;
149
150 rval = HidD_SetFeature((HANDLE)device, buffer, len);
151 return rval == 0 ? USBOPEN_ERR_IO : 0;
152 }
153
154 /* ------------------------------------------------------------------------ */
155
156 int usbhidGetReport(usbDevice_t *device, int reportNumber, char *buffer, int *len)
157 {
158 BOOLEAN rval = 0;
159
160 buffer[0] = reportNumber;
161 rval = HidD_GetFeature((HANDLE)device, buffer, *len);
162 return rval == 0 ? USBOPEN_ERR_IO : 0;
163 }
164
165 /* ------------------------------------------------------------------------ */
166
167 /* ######################################################################## */
168 #else /* defined WIN32 #################################################### */
169 /* ######################################################################## */
170
171 #include <string.h>
172 #include <usb.h>
173
174 #define usbDevice usb_dev_handle /* use libusb's device structure */
175
176 /* ------------------------------------------------------------------------- */
177
178 #define USBRQ_HID_GET_REPORT 0x01
179 #define USBRQ_HID_SET_REPORT 0x09
180
181 #define USB_HID_REPORT_TYPE_FEATURE 3
182
183
184 static int usesReportIDs;
185
186 /* ------------------------------------------------------------------------- */
187
188 static int usbhidGetStringAscii(usb_dev_handle *dev, int index, char *buf, int buflen)
189 {
190 char buffer[256];
191 int rval, i;
192
193 if((rval = usb_get_string_simple(dev, index, buf, buflen)) >= 0) /* use libusb version if it works */
194 return rval;
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)
196 return rval;
197 if(buffer[1] != USB_DT_STRING){
198 *buf = 0;
199 return 0;
200 }
201 if((unsigned char)buffer[0] < rval)
202 rval = (unsigned char)buffer[0];
203 rval /= 2;
204 /* lossy conversion to ISO Latin1: */
205 for(i=1;i<rval;i++){
206 if(i > buflen) /* destination buffer overflow */
207 break;
208 buf[i-1] = buffer[2 * i];
209 if(buffer[2 * i + 1] != 0) /* outside of ISO Latin1 range */
210 buf[i-1] = '?';
211 }
212 buf[i-1] = 0;
213 return i-1;
214 }
215
216 int usbhidOpenDevice(usbDevice_t **device, int vendor, char *vendorName, int product, char *productName, int _usesReportIDs)
217 {
218 struct usb_bus *bus;
219 struct usb_device *dev;
220 usb_dev_handle *handle = NULL;
221 int errorCode = USBOPEN_ERR_NOTFOUND;
222 static int didUsbInit = 0;
223
224 if(!didUsbInit){
225 usb_init();
226 didUsbInit = 1;
227 }
228 usb_find_busses();
229 usb_find_devices();
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){
233 char string[256];
234 int len;
235 handle = usb_open(dev); /* we need to open the device in order to query strings */
236 if(!handle){
237 errorCode = USBOPEN_ERR_ACCESS;
238 fprintf(stderr, "Warning: cannot open USB device: %s\n", usb_strerror());
239 continue;
240 }
241 if(vendorName == NULL && productName == NULL){ /* name does not matter */
242 break;
243 }
244 /* now check whether the names match: */
245 len = usbhidGetStringAscii(handle, dev->descriptor.iManufacturer, string, sizeof(string));
246 if(len < 0){
247 errorCode = USBOPEN_ERR_IO;
248 fprintf(stderr, "Warning: cannot query manufacturer for device: %s\n", usb_strerror());
249 }else{
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));
254 if(len < 0){
255 errorCode = USBOPEN_ERR_IO;
256 fprintf(stderr, "Warning: cannot query product for device: %s\n", usb_strerror());
257 }else{
258 errorCode = USBOPEN_ERR_NOTFOUND;
259 /* fprintf(stderr, "seen product ->%s<-\n", string); */
260 if(strcmp(string, productName) == 0)
261 break;
262 }
263 }
264 }
265 usb_close(handle);
266 handle = NULL;
267 }
268 }
269 if(handle)
270 break;
271 }
272 if(handle != NULL){
273 errorCode = 0;
274 *device = (void *)handle;
275 usesReportIDs = _usesReportIDs;
276 }
277 return errorCode;
278 }
279
280 /* ------------------------------------------------------------------------- */
281
282 void usbhidCloseDevice(usbDevice_t *device)
283 {
284 if(device != NULL)
285 usb_close((void *)device);
286 }
287
288 /* ------------------------------------------------------------------------- */
289
290 int usbhidSetReport(usbDevice_t *device, char *buffer, int len)
291 {
292 int bytesSent, reportId = buffer[0];
293
294 if(!usesReportIDs){
295 buffer++; /* skip dummy report ID */
296 len--;
297 }
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){
300 if(bytesSent < 0)
301 fprintf(stderr, "Error sending message: %s\n", usb_strerror());
302 return USBOPEN_ERR_IO;
303 }
304 return 0;
305 }
306
307 /* ------------------------------------------------------------------------- */
308
309 int usbhidGetReport(usbDevice_t *device, int reportNumber, char *buffer, int *len)
310 {
311 int bytesReceived, maxLen = *len;
312
313 if(!usesReportIDs){
314 buffer++; /* make room for dummy report ID */
315 maxLen--;
316 }
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;
321 }
322 *len = bytesReceived;
323 if(!usesReportIDs){
324 buffer[-1] = reportNumber; /* add dummy report ID */
325 (*len)++;
326 }
327 return 0;
328 }
329
330 /* ######################################################################## */
331 #endif /* defined WIN32 ################################################### */
332 /* ######################################################################## */