From ee3b7b218248c8853860572dab5f4771b60a2804 Mon Sep 17 00:00:00 2001 From: scuti Date: Tue, 28 Sep 2021 20:34:21 -0700 Subject: [PATCH] scuti/hotplug (#11) Added hotplugging support. --- hanvon-libusb.c | 130 ++++++++++++++++++++++++++++++------------------ 1 file changed, 82 insertions(+), 48 deletions(-) diff --git a/hanvon-libusb.c b/hanvon-libusb.c index 8c00497..405615f 100644 --- a/hanvon-libusb.c +++ b/hanvon-libusb.c @@ -447,48 +447,78 @@ int init_ctrl(struct libusb_device * const d, return is_ok; } -int handle_device_lusb(libusb_device *d) { - libusb_device_handle *h; - int status = libusb_open(d, &h); - if (status < 0 || h == NULL) { - printf("Error opening device, %i.\n", status); - return 0; +// GLOBAL: for main and hotplug_callback +static int HOT_COUNT = 0; +static struct libusb_transfer *TX = NULL; +void loop() { + int status = 0; + int LAST_HOT_COUNT = 0; + while (1) { + if (TX != NULL && TX->dev_handle != 0) { + status = libusb_submit_transfer(TX); + } + if (status < 0 && LAST_HOT_COUNT != HOT_COUNT) { + printf("\nwarning: usb transfer status = %i\n", status); + //continue; + } + LAST_HOT_COUNT = HOT_COUNT; + libusb_handle_events_completed(NULL, NULL); } - struct libevdev *evdev = NULL; - struct libevdev_uinput *uidev = NULL; - printf("handle_device: %x\n", uidev); - if (init_ctrl(d, &evdev, &uidev) < 0) { - return 0; - } - if (evdev == NULL || uidev == NULL) { - printf("Error initializing controls, %x, %x.\n", evdev, uidev); - return 0; - } - struct libusb_transfer *tx; - const int ENDPOINT_ADDR = 0x81; // bEndpointAddress from lsusb -v - //AM_PACKET_LEN = 10; // wMaxPacketSize from lsusb -v - unsigned char buffer[AM_PACKET_LEN]; +} - // Allocate memory for transfer, configure, then submit - tx = libusb_alloc_transfer(0); - libusb_fill_interrupt_transfer( - tx, - h, +// TODO: make scuti explain why this is called twice +int hotplug_callback(struct libusb_context *ctx, struct libusb_device *dev, + libusb_hotplug_event event, void *user_data) { + + static libusb_device_handle *dev_handle; + static struct libevdev_uinput *uidev = NULL; + static struct libevdev *evdev = NULL; + struct libusb_device_descriptor desc; + int rc; + libusb_get_device_descriptor(dev, &desc); + if (LIBUSB_HOTPLUG_EVENT_DEVICE_ARRIVED == event) { + // check if the device supported + libusb_device *devs[1] = {dev}; + int index = find_device(devs, 1); + if (index < 0) { + printf("INFO: Detected Hanvon device, but it is not supported.\n"); + } else { + // libusb functions that accept libusb_device = SAFE + // submit asynchronous transfers = SAFE + // other functions that accept device handle = NOT SAFE + libusb_open(dev, &dev_handle); + if (init_ctrl(dev, &evdev, &uidev) < 0) { + printf("Error: Could not initialize controls.\n"); + exit(EXIT_FAILURE); + + } + const int ENDPOINT_ADDR = 0x81; // bEndpointAddress from lsusb -v + //AM_PACKET_LEN = 10; // wMaxPacketSize from lsusb -v + unsigned char buffer[AM_PACKET_LEN]; + TX = libusb_alloc_transfer(0); + libusb_fill_interrupt_transfer( + TX, + dev_handle, ENDPOINT_ADDR, buffer, AM_PACKET_LEN, callback_default, uidev, // extra data to send in tx - 130); // timeout in milliseconds - do { - status = libusb_submit_transfer(tx); - if (status < 0 ) { - printf("warning: usb transfer status = %i\n", status); - //continue; + 130 // timeout in milliseconds + ); + } + } else if (LIBUSB_HOTPLUG_EVENT_DEVICE_LEFT) { + if (dev_handle) { + libusb_close(dev_handle); + dev_handle = NULL; + libevdev_uinput_destroy(uidev); + libusb_free_transfer(TX); + TX = NULL; + } + } else { + printf ("INFO: Device left, but handle did not exist.\n"); } - libusb_handle_events(NULL); - } while (1); - libevdev_uinput_destroy(uidev); + HOT_COUNT++; return 0; } @@ -496,25 +526,29 @@ int main() { #define UNREF_DEVICE 1 #define KEEP_DEVICE_REF 0 - libusb_device ** devs; int r = libusb_init(NULL); if (r < 0) { return r; } - int count = libusb_get_device_list(NULL, &devs); - if (count < 0) { + libusb_hotplug_callback_handle callback_handle; + int rc; + rc = libusb_hotplug_register_callback( + NULL, + LIBUSB_HOTPLUG_EVENT_DEVICE_ARRIVED | + LIBUSB_HOTPLUG_EVENT_DEVICE_LEFT, + 0, + VENDOR_ID_HANVON, // VENDOR + LIBUSB_HOTPLUG_MATCH_ANY, // PRODUCT + LIBUSB_HOTPLUG_MATCH_ANY, // DEV CLASS + hotplug_callback, + NULL, + &callback_handle + ); + if (rc != LIBUSB_SUCCESS) { + printf("Error creating a hotplug callback\n"); libusb_exit(NULL); - return count; + return EXIT_FAILURE; } - int index = find_device(devs, count); - if (index < 0) { - printf("Device not plugged in\n"); - libusb_exit(NULL); - return 0; - } - libusb_device *device = devs[index]; - libusb_free_device_list (devs, UNREF_DEVICE); - int s = handle_device_lusb(device); - libusb_exit(NULL); + loop(); return 0; }