1 /*
2 * Windows backend common header for libusb 1.0
3 *
4 * This file brings together header code common between
5 * the desktop Windows backends.
6 * Copyright © 2012-2013 RealVNC Ltd.
7 * Copyright © 2009-2012 Pete Batard <pete@akeo.ie>
8 * Copyright © 2014-2020 Chris Dickens <christopher.a.dickens@gmail.com>
9 * With contributions from Michael Plante, Orin Eman et al.
10 * Parts of this code adapted from libusb-win32-v1 by Stephan Meyer
11 * Major code testing contribution by Xiaofan Chen
12 *
13 * This library is free software; you can redistribute it and/or
14 * modify it under the terms of the GNU Lesser General Public
15 * License as published by the Free Software Foundation; either
16 * version 2.1 of the License, or (at your option) any later version.
17 *
18 * This library is distributed in the hope that it will be useful,
19 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
21 * Lesser General Public License for more details.
22 *
23 * You should have received a copy of the GNU Lesser General Public
24 * License along with this library; if not, write to the Free Software
25 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
26 */
27
28 #ifndef LIBUSB_WINDOWS_COMMON_H
29 #define LIBUSB_WINDOWS_COMMON_H
30
31 #include <stdbool.h>
32
33 /*
34 * Workaround for the mess that exists with the DWORD and ULONG types.
35 * Visual Studio unconditionally defines these types as 'unsigned long'
36 * and a long is always 32-bits, even on 64-bit builds. GCC on the other
37 * hand varies the width of a long, matching it to the build. To make
38 * matters worse, the platform headers for these GCC builds define a
39 * DWORD/ULONG to be 'unsigned long' on 32-bit builds and 'unsigned int'
40 * on 64-bit builds. This creates a great deal of warnings for compilers
41 * that support printf format checking since it will never actually be
42 * an unsigned long.
43 */
44 #if defined(_MSC_VER)
45 #define ULONG_CAST(x) (x)
46 #else
47 #define ULONG_CAST(x) ((unsigned long)(x))
48 #endif
49
50 #if defined(__CYGWIN__)
51 #define _stricmp strcasecmp
52 #define _strdup strdup
53 // _beginthreadex is MSVCRT => unavailable for cygwin. Fallback to using CreateThread
54 #define _beginthreadex(a, b, c, d, e, f) CreateThread(a, b, (LPTHREAD_START_ROUTINE)c, d, e, (LPDWORD)f)
55 #else
56 #include <process.h>
57 #endif
58
59 #define safe_free(p) do {if (p != NULL) {free((void *)p); p = NULL;}} while (0)
60
61 /*
62 * API macros - leveraged from libusb-win32 1.x
63 */
64 #define DLL_STRINGIFY(s) #s
65
66 /*
67 * Macros for handling DLL themselves
68 */
69 #define DLL_HANDLE_NAME(name) __dll_##name##_handle
70
71 #define DLL_DECLARE_HANDLE(name) \
72 static HMODULE DLL_HANDLE_NAME(name)
73
74 #define DLL_GET_HANDLE(ctx, name) \
75 do { \
76 DLL_HANDLE_NAME(name) = load_system_library(ctx, \
77 DLL_STRINGIFY(name)); \
78 if (!DLL_HANDLE_NAME(name)) \
79 return false; \
80 } while (0)
81
82 #define DLL_FREE_HANDLE(name) \
83 do { \
84 if (DLL_HANDLE_NAME(name)) { \
85 FreeLibrary(DLL_HANDLE_NAME(name)); \
86 DLL_HANDLE_NAME(name) = NULL; \
87 } \
88 } while (0)
89
90 /*
91 * Macros for handling functions within a DLL
92 */
93 #define DLL_FUNC_NAME(name) __dll_##name##_func_t
94
95 #define DLL_DECLARE_FUNC_PREFIXNAME(api, ret, prefixname, name, args) \
96 typedef ret (api * DLL_FUNC_NAME(name))args; \
97 static DLL_FUNC_NAME(name) prefixname
98
99 #define DLL_DECLARE_FUNC(api, ret, name, args) \
100 DLL_DECLARE_FUNC_PREFIXNAME(api, ret, name, name, args)
101 #define DLL_DECLARE_FUNC_PREFIXED(api, ret, prefix, name, args) \
102 DLL_DECLARE_FUNC_PREFIXNAME(api, ret, prefix##name, name, args)
103
104 #define DLL_LOAD_FUNC_PREFIXNAME(dll, prefixname, name, ret_on_failure) \
105 do { \
106 HMODULE h = DLL_HANDLE_NAME(dll); \
107 prefixname = (DLL_FUNC_NAME(name))GetProcAddress(h, \
108 DLL_STRINGIFY(name)); \
109 if (prefixname) \
110 break; \
111 prefixname = (DLL_FUNC_NAME(name))GetProcAddress(h, \
112 DLL_STRINGIFY(name) DLL_STRINGIFY(A)); \
113 if (prefixname) \
114 break; \
115 prefixname = (DLL_FUNC_NAME(name))GetProcAddress(h, \
116 DLL_STRINGIFY(name) DLL_STRINGIFY(W)); \
117 if (prefixname) \
118 break; \
119 if (ret_on_failure) \
120 return false; \
121 } while (0)
122
123 #define DLL_LOAD_FUNC(dll, name, ret_on_failure) \
124 DLL_LOAD_FUNC_PREFIXNAME(dll, name, name, ret_on_failure)
125 #define DLL_LOAD_FUNC_PREFIXED(dll, prefix, name, ret_on_failure) \
126 DLL_LOAD_FUNC_PREFIXNAME(dll, prefix##name, name, ret_on_failure)
127
128 // https://msdn.microsoft.com/en-us/library/windows/hardware/ff539136(v=vs.85).aspx
129 #if !defined(USBD_SUCCESS)
130 typedef LONG USBD_STATUS;
131
132 #define USBD_SUCCESS(Status) ((USBD_STATUS)(Status) >= 0)
133
134 #define USBD_STATUS_ENDPOINT_HALTED ((USBD_STATUS)0xC0000030L)
135 #define USBD_STATUS_TIMEOUT ((USBD_STATUS)0xC0006000L)
136 #define USBD_STATUS_DEVICE_GONE ((USBD_STATUS)0xC0007000L)
137 #define USBD_STATUS_CANCELED ((USBD_STATUS)0xC0010000L)
138 #endif
139
140 // error code added with Windows SDK 10.0.18362
141 #ifndef ERROR_NO_SUCH_DEVICE
142 #define ERROR_NO_SUCH_DEVICE 433L
143 #endif
144
145 /* Windows versions */
146 enum windows_version {
147 WINDOWS_UNDEFINED,
148 WINDOWS_2000,
149 WINDOWS_XP,
150 WINDOWS_2003, // Also XP x64
151 WINDOWS_VISTA,
152 WINDOWS_7,
153 WINDOWS_8,
154 WINDOWS_8_1,
155 WINDOWS_10,
156 WINDOWS_11,
157 WINDOWS_12_OR_LATER
158 };
159
160 extern enum windows_version windows_version;
161
162 #include <pshpack1.h>
163
164 typedef struct USB_DEVICE_DESCRIPTOR {
165 UCHAR bLength;
166 UCHAR bDescriptorType;
167 USHORT bcdUSB;
168 UCHAR bDeviceClass;
169 UCHAR bDeviceSubClass;
170 UCHAR bDeviceProtocol;
171 UCHAR bMaxPacketSize0;
172 USHORT idVendor;
173 USHORT idProduct;
174 USHORT bcdDevice;
175 UCHAR iManufacturer;
176 UCHAR iProduct;
177 UCHAR iSerialNumber;
178 UCHAR bNumConfigurations;
179 } USB_DEVICE_DESCRIPTOR, *PUSB_DEVICE_DESCRIPTOR;
180
181 typedef struct USB_CONFIGURATION_DESCRIPTOR {
182 UCHAR bLength;
183 UCHAR bDescriptorType;
184 USHORT wTotalLength;
185 UCHAR bNumInterfaces;
186 UCHAR bConfigurationValue;
187 UCHAR iConfiguration;
188 UCHAR bmAttributes;
189 UCHAR MaxPower;
190 } USB_CONFIGURATION_DESCRIPTOR, *PUSB_CONFIGURATION_DESCRIPTOR;
191
192 #include <poppack.h>
193
194 #define MAX_DEVICE_ID_LEN 200
195
196 typedef struct USB_DK_DEVICE_ID {
197 WCHAR DeviceID[MAX_DEVICE_ID_LEN];
198 WCHAR InstanceID[MAX_DEVICE_ID_LEN];
199 } USB_DK_DEVICE_ID, *PUSB_DK_DEVICE_ID;
200
201 typedef struct USB_DK_DEVICE_INFO {
202 USB_DK_DEVICE_ID ID;
203 ULONG64 FilterID;
204 ULONG64 Port;
205 ULONG64 Speed;
206 USB_DEVICE_DESCRIPTOR DeviceDescriptor;
207 } USB_DK_DEVICE_INFO, *PUSB_DK_DEVICE_INFO;
208
209 typedef struct USB_DK_ISO_TRANSFER_RESULT {
210 ULONG64 ActualLength;
211 ULONG64 TransferResult;
212 } USB_DK_ISO_TRANSFER_RESULT, *PUSB_DK_ISO_TRANSFER_RESULT;
213
214 typedef struct USB_DK_GEN_TRANSFER_RESULT {
215 ULONG64 BytesTransferred;
216 ULONG64 UsbdStatus; // USBD_STATUS code
217 } USB_DK_GEN_TRANSFER_RESULT, *PUSB_DK_GEN_TRANSFER_RESULT;
218
219 typedef struct USB_DK_TRANSFER_RESULT {
220 USB_DK_GEN_TRANSFER_RESULT GenResult;
221 PVOID64 IsochronousResultsArray; // array of USB_DK_ISO_TRANSFER_RESULT
222 } USB_DK_TRANSFER_RESULT, *PUSB_DK_TRANSFER_RESULT;
223
224 typedef struct USB_DK_TRANSFER_REQUEST {
225 ULONG64 EndpointAddress;
226 PVOID64 Buffer;
227 ULONG64 BufferLength;
228 ULONG64 TransferType;
229 ULONG64 IsochronousPacketsArraySize;
230 PVOID64 IsochronousPacketsArray;
231 USB_DK_TRANSFER_RESULT Result;
232 } USB_DK_TRANSFER_REQUEST, *PUSB_DK_TRANSFER_REQUEST;
233
234 struct usbdk_device_priv {
235 USB_DK_DEVICE_ID ID;
236 PUSB_CONFIGURATION_DESCRIPTOR *config_descriptors;
237 HANDLE redirector_handle;
238 HANDLE system_handle;
239 uint8_t active_configuration;
240 };
241
242 struct winusb_device_priv {
243 bool initialized;
244 bool root_hub;
245 uint8_t active_config;
246 uint8_t depth; // distance to HCD
247 const struct windows_usb_api_backend *apib;
248 char *dev_id;
249 char *path; // device interface path
250 int sub_api; // for WinUSB-like APIs
251 struct {
252 char *path; // each interface needs a device interface path,
253 const struct windows_usb_api_backend *apib; // an API backend (multiple drivers support),
254 int sub_api;
255 int8_t nb_endpoints; // and a set of endpoint addresses (USB_MAXENDPOINTS)
256 uint8_t *endpoint;
257 int current_altsetting;
258 bool restricted_functionality; // indicates if the interface functionality is restricted
259 // by Windows (eg. HID keyboards or mice cannot do R/W)
260 } usb_interface[USB_MAXINTERFACES];
261 struct hid_device_priv *hid;
262 PUSB_CONFIGURATION_DESCRIPTOR *config_descriptor; // list of pointers to the cached config descriptors
263 GUID class_guid; // checked for change during re-enumeration
264 };
265
266 struct usbdk_device_handle_priv {
267 // Not currently used
268 char dummy;
269 };
270
271 enum WINUSB_ZLP {
272 WINUSB_ZLP_UNSET = 0,
273 WINUSB_ZLP_OFF = 1,
274 WINUSB_ZLP_ON = 2
275 };
276
277 struct winusb_device_handle_priv {
278 int active_interface;
279 struct {
280 HANDLE dev_handle; // WinUSB needs an extra handle for the file
281 HANDLE api_handle; // used by the API to communicate with the device
282 uint8_t zlp[USB_MAXENDPOINTS]; // Current per-endpoint SHORT_PACKET_TERMINATE status (enum WINUSB_ZLP)
283 } interface_handle[USB_MAXINTERFACES];
284 int autoclaim_count[USB_MAXINTERFACES]; // For auto-release
285 };
286
287 struct usbdk_transfer_priv {
288 USB_DK_TRANSFER_REQUEST request;
289 PULONG64 IsochronousPacketsArray;
290 PUSB_DK_ISO_TRANSFER_RESULT IsochronousResultsArray;
291 };
292
293 struct winusb_transfer_priv {
294 uint8_t interface_number;
295
296 uint8_t *hid_buffer; // 1 byte extended data buffer, required for HID
297 uint8_t *hid_dest; // transfer buffer destination, required for HID
298 size_t hid_expected_size;
299
300 // For isochronous transfers with LibUSBk driver:
301 void *iso_context;
302
303 // For isochronous transfers with Microsoft WinUSB driver:
304 void *isoch_buffer_handle; // The isoch_buffer_handle to free at the end of the transfer
305 BOOL iso_break_stream; // Whether the isoch. stream was to be continued in the last call of libusb_submit_transfer.
306 // As we this structure is zeroed out upon initialization, we need to use inverse logic here.
307 libusb_transfer_cb_fn iso_user_callback; // Original transfer callback of the user. Might be used for isochronous transfers.
308 };
309
310 struct windows_backend {
311 int (*init)(struct libusb_context *ctx);
312 void (*exit)(struct libusb_context *ctx);
313 int (*get_device_list)(struct libusb_context *ctx,
314 struct discovered_devs **discdevs);
315 int (*open)(struct libusb_device_handle *dev_handle);
316 void (*close)(struct libusb_device_handle *dev_handle);
317 int (*get_active_config_descriptor)(struct libusb_device *device,
318 void *buffer, size_t len);
319 int (*get_config_descriptor)(struct libusb_device *device,
320 uint8_t config_index, void *buffer, size_t len);
321 int (*get_config_descriptor_by_value)(struct libusb_device *device,
322 uint8_t bConfigurationValue, void **buffer);
323 int (*get_configuration)(struct libusb_device_handle *dev_handle, uint8_t *config);
324 int (*set_configuration)(struct libusb_device_handle *dev_handle, uint8_t config);
325 int (*claim_interface)(struct libusb_device_handle *dev_handle, uint8_t interface_number);
326 int (*release_interface)(struct libusb_device_handle *dev_handle, uint8_t interface_number);
327 int (*set_interface_altsetting)(struct libusb_device_handle *dev_handle,
328 uint8_t interface_number, uint8_t altsetting);
329 int (*clear_halt)(struct libusb_device_handle *dev_handle,
330 unsigned char endpoint);
331 int (*reset_device)(struct libusb_device_handle *dev_handle);
332 void (*destroy_device)(struct libusb_device *dev);
333 int (*submit_transfer)(struct usbi_transfer *itransfer);
334 int (*cancel_transfer)(struct usbi_transfer *itransfer);
335 void (*clear_transfer_priv)(struct usbi_transfer *itransfer);
336 enum libusb_transfer_status (*copy_transfer_data)(struct usbi_transfer *itransfer, DWORD length);
337 };
338
339 struct windows_context_priv {
340 const struct windows_backend *backend;
341 HANDLE completion_port;
342 HANDLE completion_port_thread;
343 };
344
345 union windows_device_priv {
346 struct usbdk_device_priv usbdk_priv;
347 struct winusb_device_priv winusb_priv;
348 };
349
350 struct windows_device_handle_priv {
351 struct list_head active_transfers;
352 union {
353 struct usbdk_device_handle_priv usbdk_priv;
354 struct winusb_device_handle_priv winusb_priv;
355 };
356 };
357
358 struct windows_transfer_priv {
359 OVERLAPPED overlapped;
360 HANDLE handle;
361 struct list_head list;
362 union {
363 struct usbdk_transfer_priv usbdk_priv;
364 struct winusb_transfer_priv winusb_priv;
365 };
366 };
367
get_usbdk_device_handle_priv(struct libusb_device_handle * dev_handle)368 static inline struct usbdk_device_handle_priv *get_usbdk_device_handle_priv(struct libusb_device_handle *dev_handle)
369 {
370 struct windows_device_handle_priv *handle_priv = usbi_get_device_handle_priv(dev_handle);
371 return &handle_priv->usbdk_priv;
372 }
373
get_winusb_device_handle_priv(struct libusb_device_handle * dev_handle)374 static inline struct winusb_device_handle_priv *get_winusb_device_handle_priv(struct libusb_device_handle *dev_handle)
375 {
376 struct windows_device_handle_priv *handle_priv = usbi_get_device_handle_priv(dev_handle);
377 return &handle_priv->winusb_priv;
378 }
379
get_transfer_priv_overlapped(struct usbi_transfer * itransfer)380 static inline OVERLAPPED *get_transfer_priv_overlapped(struct usbi_transfer *itransfer)
381 {
382 struct windows_transfer_priv *transfer_priv = usbi_get_transfer_priv(itransfer);
383 return &transfer_priv->overlapped;
384 }
385
set_transfer_priv_handle(struct usbi_transfer * itransfer,HANDLE handle)386 static inline void set_transfer_priv_handle(struct usbi_transfer *itransfer, HANDLE handle)
387 {
388 struct windows_transfer_priv *transfer_priv = usbi_get_transfer_priv(itransfer);
389 transfer_priv->handle = handle;
390 }
391
get_usbdk_transfer_priv(struct usbi_transfer * itransfer)392 static inline struct usbdk_transfer_priv *get_usbdk_transfer_priv(struct usbi_transfer *itransfer)
393 {
394 struct windows_transfer_priv *transfer_priv = usbi_get_transfer_priv(itransfer);
395 return &transfer_priv->usbdk_priv;
396 }
397
get_winusb_transfer_priv(struct usbi_transfer * itransfer)398 static inline struct winusb_transfer_priv *get_winusb_transfer_priv(struct usbi_transfer *itransfer)
399 {
400 struct windows_transfer_priv *transfer_priv = usbi_get_transfer_priv(itransfer);
401 return &transfer_priv->winusb_priv;
402 }
403
404 extern const struct windows_backend usbdk_backend;
405 extern const struct windows_backend winusb_backend;
406
407 HMODULE load_system_library(struct libusb_context *ctx, const char *name);
408 unsigned long htab_hash(const char *str);
409 enum libusb_transfer_status usbd_status_to_libusb_transfer_status(USBD_STATUS status);
410 void windows_force_sync_completion(struct usbi_transfer *itransfer, ULONG size);
411
412 #if defined(ENABLE_LOGGING)
413 const char *windows_error_str(DWORD error_code);
414 #endif
415
416 #endif
417