123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416 |
- /*
- * Windows backend common header for libusb 1.0
- *
- * This file brings together header code common between
- * the desktop Windows backends.
- * Copyright © 2012-2013 RealVNC Ltd.
- * Copyright © 2009-2012 Pete Batard <pete@akeo.ie>
- * Copyright © 2014-2020 Chris Dickens <christopher.a.dickens@gmail.com>
- * With contributions from Michael Plante, Orin Eman et al.
- * Parts of this code adapted from libusb-win32-v1 by Stephan Meyer
- * Major code testing contribution by Xiaofan Chen
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
- */
- #ifndef LIBUSB_WINDOWS_COMMON_H
- #define LIBUSB_WINDOWS_COMMON_H
- #include <stdbool.h>
- /*
- * Workaround for the mess that exists with the DWORD and ULONG types.
- * Visual Studio unconditionally defines these types as 'unsigned long'
- * and a long is always 32-bits, even on 64-bit builds. GCC on the other
- * hand varies the width of a long, matching it to the build. To make
- * matters worse, the platform headers for these GCC builds define a
- * DWORD/ULONG to be 'unsigned long' on 32-bit builds and 'unsigned int'
- * on 64-bit builds. This creates a great deal of warnings for compilers
- * that support printf format checking since it will never actually be
- * an unsigned long.
- */
- #if defined(_MSC_VER)
- #define ULONG_CAST(x) (x)
- #else
- #define ULONG_CAST(x) ((unsigned long)(x))
- #endif
- #if defined(__CYGWIN__)
- #define _stricmp strcasecmp
- #define _strdup strdup
- // _beginthreadex is MSVCRT => unavailable for cygwin. Fallback to using CreateThread
- #define _beginthreadex(a, b, c, d, e, f) CreateThread(a, b, (LPTHREAD_START_ROUTINE)c, d, e, (LPDWORD)f)
- #else
- #include <process.h>
- #endif
- #define safe_free(p) do {if (p != NULL) {free((void *)p); p = NULL;}} while (0)
- /*
- * API macros - leveraged from libusb-win32 1.x
- */
- #define DLL_STRINGIFY(s) #s
- /*
- * Macros for handling DLL themselves
- */
- #define DLL_HANDLE_NAME(name) __dll_##name##_handle
- #define DLL_DECLARE_HANDLE(name) \
- static HMODULE DLL_HANDLE_NAME(name)
- #define DLL_GET_HANDLE(ctx, name) \
- do { \
- DLL_HANDLE_NAME(name) = load_system_library(ctx, \
- DLL_STRINGIFY(name)); \
- if (!DLL_HANDLE_NAME(name)) \
- return false; \
- } while (0)
- #define DLL_FREE_HANDLE(name) \
- do { \
- if (DLL_HANDLE_NAME(name)) { \
- FreeLibrary(DLL_HANDLE_NAME(name)); \
- DLL_HANDLE_NAME(name) = NULL; \
- } \
- } while (0)
- /*
- * Macros for handling functions within a DLL
- */
- #define DLL_FUNC_NAME(name) __dll_##name##_func_t
- #define DLL_DECLARE_FUNC_PREFIXNAME(api, ret, prefixname, name, args) \
- typedef ret (api * DLL_FUNC_NAME(name))args; \
- static DLL_FUNC_NAME(name) prefixname
- #define DLL_DECLARE_FUNC(api, ret, name, args) \
- DLL_DECLARE_FUNC_PREFIXNAME(api, ret, name, name, args)
- #define DLL_DECLARE_FUNC_PREFIXED(api, ret, prefix, name, args) \
- DLL_DECLARE_FUNC_PREFIXNAME(api, ret, prefix##name, name, args)
- #define DLL_LOAD_FUNC_PREFIXNAME(dll, prefixname, name, ret_on_failure) \
- do { \
- HMODULE h = DLL_HANDLE_NAME(dll); \
- prefixname = (DLL_FUNC_NAME(name))GetProcAddress(h, \
- DLL_STRINGIFY(name)); \
- if (prefixname) \
- break; \
- prefixname = (DLL_FUNC_NAME(name))GetProcAddress(h, \
- DLL_STRINGIFY(name) DLL_STRINGIFY(A)); \
- if (prefixname) \
- break; \
- prefixname = (DLL_FUNC_NAME(name))GetProcAddress(h, \
- DLL_STRINGIFY(name) DLL_STRINGIFY(W)); \
- if (prefixname) \
- break; \
- if (ret_on_failure) \
- return false; \
- } while (0)
- #define DLL_LOAD_FUNC(dll, name, ret_on_failure) \
- DLL_LOAD_FUNC_PREFIXNAME(dll, name, name, ret_on_failure)
- #define DLL_LOAD_FUNC_PREFIXED(dll, prefix, name, ret_on_failure) \
- DLL_LOAD_FUNC_PREFIXNAME(dll, prefix##name, name, ret_on_failure)
- // https://msdn.microsoft.com/en-us/library/windows/hardware/ff539136(v=vs.85).aspx
- #if !defined(USBD_SUCCESS)
- typedef LONG USBD_STATUS;
- #define USBD_SUCCESS(Status) ((USBD_STATUS)(Status) >= 0)
- #define USBD_STATUS_ENDPOINT_HALTED ((USBD_STATUS)0xC0000030L)
- #define USBD_STATUS_TIMEOUT ((USBD_STATUS)0xC0006000L)
- #define USBD_STATUS_DEVICE_GONE ((USBD_STATUS)0xC0007000L)
- #define USBD_STATUS_CANCELED ((USBD_STATUS)0xC0010000L)
- #endif
- // error code added with Windows SDK 10.0.18362
- #ifndef ERROR_NO_SUCH_DEVICE
- #define ERROR_NO_SUCH_DEVICE 433L
- #endif
- /* Windows versions */
- enum windows_version {
- WINDOWS_UNDEFINED,
- WINDOWS_2000,
- WINDOWS_XP,
- WINDOWS_2003, // Also XP x64
- WINDOWS_VISTA,
- WINDOWS_7,
- WINDOWS_8,
- WINDOWS_8_1,
- WINDOWS_10,
- WINDOWS_11,
- WINDOWS_12_OR_LATER
- };
- extern enum windows_version windows_version;
- #include <pshpack1.h>
- typedef struct USB_DEVICE_DESCRIPTOR {
- UCHAR bLength;
- UCHAR bDescriptorType;
- USHORT bcdUSB;
- UCHAR bDeviceClass;
- UCHAR bDeviceSubClass;
- UCHAR bDeviceProtocol;
- UCHAR bMaxPacketSize0;
- USHORT idVendor;
- USHORT idProduct;
- USHORT bcdDevice;
- UCHAR iManufacturer;
- UCHAR iProduct;
- UCHAR iSerialNumber;
- UCHAR bNumConfigurations;
- } USB_DEVICE_DESCRIPTOR, *PUSB_DEVICE_DESCRIPTOR;
- typedef struct USB_CONFIGURATION_DESCRIPTOR {
- UCHAR bLength;
- UCHAR bDescriptorType;
- USHORT wTotalLength;
- UCHAR bNumInterfaces;
- UCHAR bConfigurationValue;
- UCHAR iConfiguration;
- UCHAR bmAttributes;
- UCHAR MaxPower;
- } USB_CONFIGURATION_DESCRIPTOR, *PUSB_CONFIGURATION_DESCRIPTOR;
- #include <poppack.h>
- #define MAX_DEVICE_ID_LEN 200
- typedef struct USB_DK_DEVICE_ID {
- WCHAR DeviceID[MAX_DEVICE_ID_LEN];
- WCHAR InstanceID[MAX_DEVICE_ID_LEN];
- } USB_DK_DEVICE_ID, *PUSB_DK_DEVICE_ID;
- typedef struct USB_DK_DEVICE_INFO {
- USB_DK_DEVICE_ID ID;
- ULONG64 FilterID;
- ULONG64 Port;
- ULONG64 Speed;
- USB_DEVICE_DESCRIPTOR DeviceDescriptor;
- } USB_DK_DEVICE_INFO, *PUSB_DK_DEVICE_INFO;
- typedef struct USB_DK_ISO_TRANSFER_RESULT {
- ULONG64 ActualLength;
- ULONG64 TransferResult;
- } USB_DK_ISO_TRANSFER_RESULT, *PUSB_DK_ISO_TRANSFER_RESULT;
- typedef struct USB_DK_GEN_TRANSFER_RESULT {
- ULONG64 BytesTransferred;
- ULONG64 UsbdStatus; // USBD_STATUS code
- } USB_DK_GEN_TRANSFER_RESULT, *PUSB_DK_GEN_TRANSFER_RESULT;
- typedef struct USB_DK_TRANSFER_RESULT {
- USB_DK_GEN_TRANSFER_RESULT GenResult;
- PVOID64 IsochronousResultsArray; // array of USB_DK_ISO_TRANSFER_RESULT
- } USB_DK_TRANSFER_RESULT, *PUSB_DK_TRANSFER_RESULT;
- typedef struct USB_DK_TRANSFER_REQUEST {
- ULONG64 EndpointAddress;
- PVOID64 Buffer;
- ULONG64 BufferLength;
- ULONG64 TransferType;
- ULONG64 IsochronousPacketsArraySize;
- PVOID64 IsochronousPacketsArray;
- USB_DK_TRANSFER_RESULT Result;
- } USB_DK_TRANSFER_REQUEST, *PUSB_DK_TRANSFER_REQUEST;
- struct usbdk_device_priv {
- USB_DK_DEVICE_ID ID;
- PUSB_CONFIGURATION_DESCRIPTOR *config_descriptors;
- HANDLE redirector_handle;
- HANDLE system_handle;
- uint8_t active_configuration;
- };
- struct winusb_device_priv {
- bool initialized;
- bool root_hub;
- uint8_t active_config;
- uint8_t depth; // distance to HCD
- const struct windows_usb_api_backend *apib;
- char *dev_id;
- char *path; // device interface path
- int sub_api; // for WinUSB-like APIs
- struct {
- char *path; // each interface needs a device interface path,
- const struct windows_usb_api_backend *apib; // an API backend (multiple drivers support),
- int sub_api;
- int8_t nb_endpoints; // and a set of endpoint addresses (USB_MAXENDPOINTS)
- uint8_t *endpoint;
- int current_altsetting;
- bool restricted_functionality; // indicates if the interface functionality is restricted
- // by Windows (eg. HID keyboards or mice cannot do R/W)
- } usb_interface[USB_MAXINTERFACES];
- struct hid_device_priv *hid;
- PUSB_CONFIGURATION_DESCRIPTOR *config_descriptor; // list of pointers to the cached config descriptors
- GUID class_guid; // checked for change during re-enumeration
- };
- struct usbdk_device_handle_priv {
- // Not currently used
- char dummy;
- };
-
- enum WINUSB_ZLP {
- WINUSB_ZLP_UNSET = 0,
- WINUSB_ZLP_OFF = 1,
- WINUSB_ZLP_ON = 2
- };
- struct winusb_device_handle_priv {
- int active_interface;
- struct {
- HANDLE dev_handle; // WinUSB needs an extra handle for the file
- HANDLE api_handle; // used by the API to communicate with the device
- uint8_t zlp[USB_MAXENDPOINTS]; // Current per-endpoint SHORT_PACKET_TERMINATE status (enum WINUSB_ZLP)
- } interface_handle[USB_MAXINTERFACES];
- int autoclaim_count[USB_MAXINTERFACES]; // For auto-release
- };
- struct usbdk_transfer_priv {
- USB_DK_TRANSFER_REQUEST request;
- PULONG64 IsochronousPacketsArray;
- PUSB_DK_ISO_TRANSFER_RESULT IsochronousResultsArray;
- };
- struct winusb_transfer_priv {
- uint8_t interface_number;
- uint8_t *hid_buffer; // 1 byte extended data buffer, required for HID
- uint8_t *hid_dest; // transfer buffer destination, required for HID
- size_t hid_expected_size;
- // For isochronous transfers with LibUSBk driver:
- void *iso_context;
- // For isochronous transfers with Microsoft WinUSB driver:
- void *isoch_buffer_handle; // The isoch_buffer_handle to free at the end of the transfer
- BOOL iso_break_stream; // Whether the isoch. stream was to be continued in the last call of libusb_submit_transfer.
- // As we this structure is zeroed out upon initialization, we need to use inverse logic here.
- libusb_transfer_cb_fn iso_user_callback; // Original transfer callback of the user. Might be used for isochronous transfers.
- };
- struct windows_backend {
- int (*init)(struct libusb_context *ctx);
- void (*exit)(struct libusb_context *ctx);
- int (*get_device_list)(struct libusb_context *ctx,
- struct discovered_devs **discdevs);
- int (*open)(struct libusb_device_handle *dev_handle);
- void (*close)(struct libusb_device_handle *dev_handle);
- int (*get_active_config_descriptor)(struct libusb_device *device,
- void *buffer, size_t len);
- int (*get_config_descriptor)(struct libusb_device *device,
- uint8_t config_index, void *buffer, size_t len);
- int (*get_config_descriptor_by_value)(struct libusb_device *device,
- uint8_t bConfigurationValue, void **buffer);
- int (*get_configuration)(struct libusb_device_handle *dev_handle, uint8_t *config);
- int (*set_configuration)(struct libusb_device_handle *dev_handle, uint8_t config);
- int (*claim_interface)(struct libusb_device_handle *dev_handle, uint8_t interface_number);
- int (*release_interface)(struct libusb_device_handle *dev_handle, uint8_t interface_number);
- int (*set_interface_altsetting)(struct libusb_device_handle *dev_handle,
- uint8_t interface_number, uint8_t altsetting);
- int (*clear_halt)(struct libusb_device_handle *dev_handle,
- unsigned char endpoint);
- int (*reset_device)(struct libusb_device_handle *dev_handle);
- void (*destroy_device)(struct libusb_device *dev);
- int (*submit_transfer)(struct usbi_transfer *itransfer);
- int (*cancel_transfer)(struct usbi_transfer *itransfer);
- void (*clear_transfer_priv)(struct usbi_transfer *itransfer);
- enum libusb_transfer_status (*copy_transfer_data)(struct usbi_transfer *itransfer, DWORD length);
- };
- struct windows_context_priv {
- const struct windows_backend *backend;
- HANDLE completion_port;
- HANDLE completion_port_thread;
- };
- union windows_device_priv {
- struct usbdk_device_priv usbdk_priv;
- struct winusb_device_priv winusb_priv;
- };
- struct windows_device_handle_priv {
- struct list_head active_transfers;
- union {
- struct usbdk_device_handle_priv usbdk_priv;
- struct winusb_device_handle_priv winusb_priv;
- };
- };
- struct windows_transfer_priv {
- OVERLAPPED overlapped;
- HANDLE handle;
- struct list_head list;
- union {
- struct usbdk_transfer_priv usbdk_priv;
- struct winusb_transfer_priv winusb_priv;
- };
- };
- static inline struct usbdk_device_handle_priv *get_usbdk_device_handle_priv(struct libusb_device_handle *dev_handle)
- {
- struct windows_device_handle_priv *handle_priv = usbi_get_device_handle_priv(dev_handle);
- return &handle_priv->usbdk_priv;
- }
- static inline struct winusb_device_handle_priv *get_winusb_device_handle_priv(struct libusb_device_handle *dev_handle)
- {
- struct windows_device_handle_priv *handle_priv = usbi_get_device_handle_priv(dev_handle);
- return &handle_priv->winusb_priv;
- }
- static inline OVERLAPPED *get_transfer_priv_overlapped(struct usbi_transfer *itransfer)
- {
- struct windows_transfer_priv *transfer_priv = usbi_get_transfer_priv(itransfer);
- return &transfer_priv->overlapped;
- }
- static inline void set_transfer_priv_handle(struct usbi_transfer *itransfer, HANDLE handle)
- {
- struct windows_transfer_priv *transfer_priv = usbi_get_transfer_priv(itransfer);
- transfer_priv->handle = handle;
- }
- static inline struct usbdk_transfer_priv *get_usbdk_transfer_priv(struct usbi_transfer *itransfer)
- {
- struct windows_transfer_priv *transfer_priv = usbi_get_transfer_priv(itransfer);
- return &transfer_priv->usbdk_priv;
- }
- static inline struct winusb_transfer_priv *get_winusb_transfer_priv(struct usbi_transfer *itransfer)
- {
- struct windows_transfer_priv *transfer_priv = usbi_get_transfer_priv(itransfer);
- return &transfer_priv->winusb_priv;
- }
- extern const struct windows_backend usbdk_backend;
- extern const struct windows_backend winusb_backend;
- HMODULE load_system_library(struct libusb_context *ctx, const char *name);
- unsigned long htab_hash(const char *str);
- enum libusb_transfer_status usbd_status_to_libusb_transfer_status(USBD_STATUS status);
- void windows_force_sync_completion(struct usbi_transfer *itransfer, ULONG size);
- #if defined(ENABLE_LOGGING)
- const char *windows_error_str(DWORD error_code);
- #endif
- #endif
|