From 3d7c48a6e5c5c532cdd66b3ba5a8c5911bcf2383 Mon Sep 17 00:00:00 2001 From: ZoRo Date: Sat, 19 Feb 2022 12:47:26 +0000 Subject: Initial --- src/os/windows_common.h | 415 ++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 415 insertions(+) create mode 100644 src/os/windows_common.h (limited to 'src/os/windows_common.h') diff --git a/src/os/windows_common.h b/src/os/windows_common.h new file mode 100644 index 0000000..792a31e --- /dev/null +++ b/src/os/windows_common.h @@ -0,0 +1,415 @@ +/* + * 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 + * Copyright © 2014-2020 Chris Dickens + * 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 + +/* + * 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 +#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_OR_LATER +}; + +extern enum windows_version windows_version; + +#include + +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 + +#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 -- cgit v1.2.3