summaryrefslogtreecommitdiff
path: root/src/os/windows_common.h
diff options
context:
space:
mode:
authorZoRo <dos21h@gmail.com>2022-02-19 12:47:26 +0000
committerZoRo <dos21h@gmail.com>2022-02-19 12:47:26 +0000
commit3d7c48a6e5c5c532cdd66b3ba5a8c5911bcf2383 (patch)
treeb60e21b31eb84cbcbfa97bc10a3cdf1180ce82da /src/os/windows_common.h
downloadlibrusb-3d7c48a6e5c5c532cdd66b3ba5a8c5911bcf2383.tar.gz
librusb-3d7c48a6e5c5c532cdd66b3ba5a8c5911bcf2383.zip
Initial
Diffstat (limited to 'src/os/windows_common.h')
-rw-r--r--src/os/windows_common.h415
1 files changed, 415 insertions, 0 deletions
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 <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_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