Skip to content

Commit

Permalink
windows: hotplug implementation
Browse files Browse the repository at this point in the history
Implemented as is a three steps process:
1. We create a monitor on GUID_DEVINTERFACE_USB_DEVICE via a hidden window.
2. Upon notification of an event, we run the current windows backend to get
   the list of devices. This updates the hotplug status of each device to one
   of three values {UNCHANGED, ARRIVED, LEFT}.
3. According to the value, we generate events to libusb client via hotplug
   callbacks.
  • Loading branch information
sonatique committed Jun 3, 2024
1 parent 4cebd8a commit 2454f1a
Show file tree
Hide file tree
Showing 11 changed files with 401 additions and 43 deletions.
1 change: 1 addition & 0 deletions libusb/Makefile.am
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ OS_OPENBSD_SRC = os/openbsd_usb.c
OS_SUNOS_SRC = os/sunos_usb.h os/sunos_usb.c
OS_WINDOWS_SRC = libusb-1.0.def libusb-1.0.rc \
os/windows_common.h os/windows_common.c \
os/windows_hotplug.h os/windows_hotplug.c \
os/windows_usbdk.h os/windows_usbdk.c \
os/windows_winusb.h os/windows_winusb.c

Expand Down
22 changes: 15 additions & 7 deletions libusb/core.c
Original file line number Diff line number Diff line change
Expand Up @@ -728,20 +728,24 @@ struct libusb_device *usbi_alloc_device(struct libusb_context *ctx,
return dev;
}

void usbi_connect_device(struct libusb_device *dev)
void usbi_attach_device(struct libusb_device *dev)
{
struct libusb_context *ctx = DEVICE_CTX(dev);

usbi_atomic_store(&dev->attached, 1);

usbi_mutex_lock(&dev->ctx->usb_devs_lock);
list_add(&dev->list, &dev->ctx->usb_devs);
usbi_mutex_unlock(&dev->ctx->usb_devs_lock);
usbi_mutex_lock(&ctx->usb_devs_lock);
list_add(&dev->list, &ctx->usb_devs);
usbi_mutex_unlock(&ctx->usb_devs_lock);
}

usbi_hotplug_notification(ctx, dev, LIBUSB_HOTPLUG_EVENT_DEVICE_ARRIVED);
void usbi_connect_device(struct libusb_device *dev)
{
usbi_attach_device(dev);
usbi_hotplug_notification(DEVICE_CTX(dev), dev, LIBUSB_HOTPLUG_EVENT_DEVICE_ARRIVED);
}

void usbi_disconnect_device(struct libusb_device *dev)
void usbi_detach_device(struct libusb_device *dev)
{
struct libusb_context *ctx = DEVICE_CTX(dev);

Expand All @@ -750,8 +754,12 @@ void usbi_disconnect_device(struct libusb_device *dev)
usbi_mutex_lock(&ctx->usb_devs_lock);
list_del(&dev->list);
usbi_mutex_unlock(&ctx->usb_devs_lock);
}

usbi_hotplug_notification(ctx, dev, LIBUSB_HOTPLUG_EVENT_DEVICE_LEFT);
void usbi_disconnect_device(struct libusb_device *dev)
{
usbi_detach_device(dev);
usbi_hotplug_notification(DEVICE_CTX(dev), dev, LIBUSB_HOTPLUG_EVENT_DEVICE_LEFT);
}

/* Perform some final sanity checks on a newly discovered device. If this
Expand Down
3 changes: 3 additions & 0 deletions libusb/libusbi.h
Original file line number Diff line number Diff line change
Expand Up @@ -821,6 +821,9 @@ int usbi_handle_transfer_completion(struct usbi_transfer *itransfer,
int usbi_handle_transfer_cancellation(struct usbi_transfer *itransfer);
void usbi_signal_transfer_completion(struct usbi_transfer *itransfer);

void usbi_attach_device(struct libusb_device *dev);
void usbi_detach_device(struct libusb_device *dev);

void usbi_connect_device(struct libusb_device *dev);
void usbi_disconnect_device(struct libusb_device *dev);

Expand Down
20 changes: 13 additions & 7 deletions libusb/os/windows_common.c
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@

#include "libusbi.h"
#include "windows_common.h"
#include "windows_hotplug.h"

#define EPOCH_TIME UINT64_C(116444736000000000) // 1970.01.01 00:00:000 in MS Filetime

Expand Down Expand Up @@ -565,6 +566,16 @@ static int windows_init(struct libusb_context *ctx)

r = LIBUSB_SUCCESS;

if (init_count == 1) {
r = windows_start_event_monitor(); // Start up hotplug event handler
if (r != LIBUSB_SUCCESS) {
usbi_err(ctx, "error starting hotplug event monitor");
goto init_exit;
}
}

windows_initial_scan_devices(ctx);

init_exit: // Holds semaphore here
if ((init_count == 1) && (r != LIBUSB_SUCCESS)) { // First init failed?
if (usbdk_available) {
Expand Down Expand Up @@ -596,6 +607,7 @@ static void windows_exit(struct libusb_context *ctx)

// Only works if exits and inits are balanced exactly
if (--init_count == 0) { // Last exit
windows_stop_event_monitor();
if (usbdk_available) {
usbdk_backend.exit(ctx);
usbdk_available = false;
Expand Down Expand Up @@ -624,12 +636,6 @@ static int windows_set_option(struct libusb_context *ctx, enum libusb_option opt
return LIBUSB_ERROR_NOT_SUPPORTED;
}

static int windows_get_device_list(struct libusb_context *ctx, struct discovered_devs **discdevs)
{
struct windows_context_priv *priv = usbi_get_context_priv(ctx);
return priv->backend->get_device_list(ctx, discdevs);
}

static int windows_open(struct libusb_device_handle *dev_handle)
{
struct windows_context_priv *priv = usbi_get_context_priv(HANDLE_CTX(dev_handle));
Expand Down Expand Up @@ -888,7 +894,7 @@ const struct usbi_os_backend usbi_backend = {
windows_init,
windows_exit,
windows_set_option,
windows_get_device_list,
NULL, /* get_device_list */
NULL, /* hotplug_poll */
NULL, /* wrap_sys_device */
windows_open,
Expand Down
21 changes: 19 additions & 2 deletions libusb/os/windows_common.h
Original file line number Diff line number Diff line change
Expand Up @@ -232,12 +232,29 @@ typedef struct USB_DK_TRANSFER_REQUEST {
USB_DK_TRANSFER_RESULT Result;
} USB_DK_TRANSFER_REQUEST, *PUSB_DK_TRANSFER_REQUEST;

/* track devices that are removed, kept unchanged, added when updating device list
* using system enumeration in response to low-level hotplug events */
enum hotplug_status {
/* device is still in system enumeration as it was in previous enumeration.
* There is no need to take any action */
UNCHANGED,

/* device is newly added to the list, meaning it just appeared in system enumeration.
* A hotplug "device arrived" event shall be triggered */
ARRIVED,

/* device is no longer present in system enumeration.
* A hotplug "device left" event shall be triggered and the device removed from the list */
LEFT
};

struct usbdk_device_priv {
USB_DK_DEVICE_ID ID;
PUSB_CONFIGURATION_DESCRIPTOR *config_descriptors;
HANDLE redirector_handle;
HANDLE system_handle;
uint8_t active_configuration;
enum hotplug_status hotplug_status; /* updated while getting current device list */
};

struct winusb_device_priv {
Expand Down Expand Up @@ -269,6 +286,7 @@ struct winusb_device_priv {
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
enum hotplug_status hotplug_status; /* updated while getting current device list */
};

struct usbdk_device_handle_priv {
Expand Down Expand Up @@ -318,8 +336,7 @@ struct winusb_transfer_priv {
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 (*get_device_list)(struct libusb_context *ctx); // Refresh ctx device list with devices currently connected to the system and update the `hotplug_status` field of all enumerated devices.
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,
Expand Down
Loading

0 comments on commit 2454f1a

Please sign in to comment.