Fixed bug in hiddata.*
[usb-relay-hid.git] / commandline / hiddata_mswin.c
CommitLineData
fe63975d 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")
56c8dcf9 33#if _MSC_VER < 1900 /* before VS2015 */
fe63975d 34#define snprintf _snprintf
56c8dcf9 35#endif /* VS2015 */
fe63975d 36#else /* GCC, Mingw... */
37#endif /*_MSC_VER*/
38
39/*
40 * Convert UTF-16 null term. string to single byte (ASCII or ISO Latin)
41 * change all weird characters to "?"
42 */
43static void usbstring_to_ascii(unsigned short *wp, char *cp, int size)
44{
45 unsigned short *wpend = wp + (size/sizeof(unsigned short));
46 for( ; wp < wpend; )
47 {
48 unsigned short h = *wp++;
49 *cp++ = (h < 0xFF) ? (char)h : '?';
50 if (h == 0)
51 break;
52 }
53}
54
55/*
56 * Read HID string for vendor and device, return as ASCII (or ISO Latin...)
57 */
58int usbhidGetVendorString(USBDEVHANDLE usbh, char *buffer, int len)
59{
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;
65 }
66 usbstring_to_ascii((UINT16*)buffer, buffer, len);
67 return 0;
68}
69
70int usbhidGetProductString(USBDEVHANDLE usbh, char *buffer, int len)
71{
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;
77 }
78 usbstring_to_ascii((UINT16*)buffer, buffer, len);
79 return 0;
80}
81
82/*
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.
89 */
90int usbhidEnumDevices(int vendor, int product,
91 void *context,
92 int (*usbhidEnumFunc)(USBDEVHANDLE usbh, void *ctx))
93{
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;
98 DWORD size;
99 int i, openFlag = 0; /* may be FILE_FLAG_OVERLAPPED */
100 int errorCode = USBHID_ERR_NOTFOUND;
101 HANDLE handle = INVALID_HANDLE_VALUE;
102 HIDD_ATTRIBUTES deviceAttributes;
103
104 HidD_GetHidGuid(&hidGuid);
105 deviceInfoList = SetupDiGetClassDevsW(&hidGuid, NULL, NULL, DIGCF_PRESENT | DIGCF_INTERFACEDEVICE);
106 if (!deviceInfoList || deviceInfoList == INVALID_HANDLE_VALUE)
107 {
108 return USBHID_ERR_NOTFOUND;
109 }
110
111 deviceInfo.cbSize = sizeof(deviceInfo);
112 for (i=0; ; i++) {
113 if(handle != INVALID_HANDLE_VALUE){
114 CloseHandle(handle);
115 handle = INVALID_HANDLE_VALUE;
116 }
117 if( !SetupDiEnumDeviceInterfaces(deviceInfoList, 0, &hidGuid, i, &deviceInfo) )
118 break; /* no more entries */
119 /* first do a dummy call just to determine the actual size required */
120 SetupDiGetDeviceInterfaceDetailW(deviceInfoList, &deviceInfo, NULL, 0, &size, NULL);
121 if(deviceDetails != NULL)
122 free(deviceDetails);
123 deviceDetails = malloc(size);
124 deviceDetails->cbSize = sizeof(*deviceDetails);
125 /* this call is for real: */
126 SetupDiGetDeviceInterfaceDetailW(deviceInfoList, &deviceInfo, deviceDetails, size, &size, NULL);
127 DEBUG_PRINT(("checking HID path \"%s\"\n", deviceDetails->DevicePath));
128
129 handle = CreateFileW(deviceDetails->DevicePath,
130 GENERIC_READ|GENERIC_WRITE, FILE_SHARE_READ|FILE_SHARE_WRITE, NULL, OPEN_EXISTING, openFlag, NULL);
131 if(handle == INVALID_HANDLE_VALUE){
132 DEBUG_PRINT(("open USB device failed: gle=%d\n", (int)GetLastError()));
133 /* errorCode = USBOPEN_ERR_ACCESS; opening will always fail for mouse -- ignore */
134 continue;
135 }
136 deviceAttributes.Size = sizeof(deviceAttributes);
137 HidD_GetAttributes(handle, &deviceAttributes);
138 DEBUG_PRINT(("device attributes: vid=%d pid=%d ver=%4.4X\n", deviceAttributes.VendorID, deviceAttributes.ProductID, deviceAttributes.VersionNumber));
139 if(deviceAttributes.VendorID != vendor || deviceAttributes.ProductID != product)
140 continue; /* skip this device */
141
142 errorCode = 0;
143 if ( 0 == usbhidEnumFunc((USBDEVHANDLE)handle, context) )
144 {
145 break; /* stop enumeration */
146 }
147
148 /* Now the handle is owned by the callback */
149 handle = INVALID_HANDLE_VALUE;
150 }
151
152 SetupDiDestroyDeviceInfoList(deviceInfoList);
153 if(deviceDetails != NULL)
154 free(deviceDetails);
155
156 return errorCode;
157}
158
159
160void usbhidCloseDevice(USBDEVHANDLE usbh)
161{
162 CloseHandle((HANDLE)usbh);
163}
164
165
166int usbhidSetReport(USBDEVHANDLE usbh, char *buffer, int len)
167{
168 BOOLEAN rval;
169 rval = HidD_SetFeature((HANDLE)usbh, buffer, len);
170 return rval == 0 ? USBHID_ERR_IO_HID : 0;
171}
172
173
174int usbhidGetReport(USBDEVHANDLE usbh, int reportNumber, char *buffer, int *len)
175{
176 BOOLEAN rval = 0;
56c8dcf9 177 buffer[0] = (char)reportNumber;
fe63975d 178 rval = HidD_GetFeature((HANDLE)usbh, buffer, *len);
179 return rval == 0 ? USBHID_ERR_IO_HID : 0;
180}
181
182
183int usbhidStrerror_r( int err, char *buf, int len)
184{
185 const char *s;
186 switch (err) {
187 case USBHID_ERR_ACCESS: s = "Access to device denied";
56c8dcf9 188 break;
fe63975d 189 case USBHID_ERR_NOTFOUND: s = "The specified device was not found";
56c8dcf9 190 break;
fe63975d 191 case USBHID_ERR_IO: s = "Communication error with device";
56c8dcf9 192 break;
fe63975d 193 case USBHID_ERR_IO_HID: s = "HID I/O error with device";
56c8dcf9 194 break;
fe63975d 195 default:
196 s = "";
197 }
56c8dcf9 198
fe63975d 199 return snprintf(buf, len, "%s", s);
200}