Merge doc changes from github
[usb-relay-hid.git] / commandline / hiddata_mswin.c
1 /* hiddata_mswin.c
2 * Win32 variant
3 */
4
5 /* Inspired by hiddata.c|h by Christian Starkjohann
6 * Copyright: (c) 2008 by OBJECTIVE DEVELOPMENT Software GmbH
7 */
8
9 #if !defined(_WIN32)
10 #error
11 #endif
12
13 #include "hiddata.h"
14 #include <stdio.h>
15 #include <string.h>
16 #include <errno.h>
17
18 #if 0 //ifdef DEBUG
19 #define DEBUG_PRINT(arg) printf arg
20 #else
21 #define DEBUG_PRINT(arg)
22 #endif
23
24 #include "targetver.h"
25 #include <windows.h>
26 #include <setupapi.h>
27 #include <hidsdi.h>
28 #include <hidpi.h>
29
30 #ifdef _MSC_VER
31 #pragma comment(lib, "setupapi")
32 #pragma comment(lib, "hid")
33 #define snprintf _snprintf
34 #else /* GCC, Mingw... */
35 #endif /*_MSC_VER*/
36
37 /*
38 * Convert UTF-16 null term. string to single byte (ASCII or ISO Latin)
39 * change all weird characters to "?"
40 */
41 static void usbstring_to_ascii(unsigned short *wp, char *cp, int size)
42 {
43 unsigned short *wpend = wp + (size/sizeof(unsigned short));
44 for( ; wp < wpend; )
45 {
46 unsigned short h = *wp++;
47 *cp++ = (h < 0xFF) ? (char)h : '?';
48 if (h == 0)
49 break;
50 }
51 }
52
53 /*
54 * Read HID string for vendor and device, return as ASCII (or ISO Latin...)
55 */
56 int usbhidGetVendorString(USBDEVHANDLE usbh, char *buffer, int len)
57 {
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 USBHID_ERR_IO_HID;
63 }
64 usbstring_to_ascii((UINT16*)buffer, buffer, len);
65 return 0;
66 }
67
68 int usbhidGetProductString(USBDEVHANDLE usbh, char *buffer, int len)
69 {
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 USBHID_ERR_IO_HID;
75 }
76 usbstring_to_ascii((UINT16*)buffer, buffer, len);
77 return 0;
78 }
79
80 /*
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.
87 */
88 int usbhidEnumDevices(int vendor, int product,
89 void *context,
90 int (*usbhidEnumFunc)(USBDEVHANDLE usbh, void *ctx))
91 {
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;
96 DWORD size;
97 int i, openFlag = 0; /* may be FILE_FLAG_OVERLAPPED */
98 int errorCode = USBHID_ERR_NOTFOUND;
99 HANDLE handle = INVALID_HANDLE_VALUE;
100 HIDD_ATTRIBUTES deviceAttributes;
101
102 HidD_GetHidGuid(&hidGuid);
103 deviceInfoList = SetupDiGetClassDevsW(&hidGuid, NULL, NULL, DIGCF_PRESENT | DIGCF_INTERFACEDEVICE);
104 if (!deviceInfoList || deviceInfoList == INVALID_HANDLE_VALUE)
105 {
106 return USBHID_ERR_NOTFOUND;
107 }
108
109 deviceInfo.cbSize = sizeof(deviceInfo);
110 for (i=0; ; i++) {
111 if(handle != INVALID_HANDLE_VALUE){
112 CloseHandle(handle);
113 handle = INVALID_HANDLE_VALUE;
114 }
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)
120 free(deviceDetails);
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));
126
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 */
132 continue;
133 }
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 */
139
140 errorCode = 0;
141 if ( 0 == usbhidEnumFunc((USBDEVHANDLE)handle, context) )
142 {
143 break; /* stop enumeration */
144 }
145
146 /* Now the handle is owned by the callback */
147 handle = INVALID_HANDLE_VALUE;
148 }
149
150 SetupDiDestroyDeviceInfoList(deviceInfoList);
151 if(deviceDetails != NULL)
152 free(deviceDetails);
153
154 return errorCode;
155 }
156
157
158 void usbhidCloseDevice(USBDEVHANDLE usbh)
159 {
160 CloseHandle((HANDLE)usbh);
161 }
162
163
164 int usbhidSetReport(USBDEVHANDLE usbh, char *buffer, int len)
165 {
166 BOOLEAN rval;
167 rval = HidD_SetFeature((HANDLE)usbh, buffer, len);
168 return rval == 0 ? USBHID_ERR_IO_HID : 0;
169 }
170
171
172 int usbhidGetReport(USBDEVHANDLE usbh, int reportNumber, char *buffer, int *len)
173 {
174 BOOLEAN rval = 0;
175 buffer[0] = reportNumber;
176 rval = HidD_GetFeature((HANDLE)usbh, buffer, *len);
177 return rval == 0 ? USBHID_ERR_IO_HID : 0;
178 }
179
180
181 int usbhidStrerror_r( int err, char *buf, int len)
182 {
183 const char *s;
184 switch (err) {
185 case USBHID_ERR_ACCESS: s = "Access to device denied";
186 case USBHID_ERR_NOTFOUND: s = "The specified device was not found";
187 case USBHID_ERR_IO: s = "Communication error with device";
188 case USBHID_ERR_IO_HID: s = "HID I/O error with device";
189 default:
190 s = "";
191 }
192
193 return snprintf(buf, len, "%s", s);
194 }