From cc8d6e9344343986d21783ed9c7126343e7cc592 Mon Sep 17 00:00:00 2001 From: nirenjan Date: Fri, 22 May 2020 00:42:01 -0700 Subject: [PATCH] Revert hotplug support in libx52 This removes the earlier work done in libx52 to support USB hotplug. This wasn't adequately tested, and the reason to have hotplug support was to address perceived deficiencies in the standard API. However, on recent reflection and experimentation, it seems to be easier to support adding methods to connect to an X52/X52Pro joystick dynamically after initializing the library. This approach also lends itself to adding checks when sending control packets to close the device handle when it detects device disconnection. Also, one could add a disconnect method to disconnect from any connected joysticks. Finally, this commit reverts a series of commits that chronicled my journey into implementing hotplug support and simulating it in libusbx52. By coalescing the revert into a single commit, it makes it easier to revert the revert in the future, if necessary. --- ChangeLog.md | 1 - docs/design/hotplug.md | 63 --------- lib/libusbx52/Makefile.am | 2 +- lib/libusbx52/libusbx52.h | 30 +--- lib/libusbx52/usb_x52_hotplug.c | 124 ---------------- lib/libusbx52/usb_x52_stub.c | 43 ++++-- lib/libusbx52/usb_x52_vector.c | 83 ----------- lib/libx52/Makefile.am | 2 +- lib/libx52/libx52.h | 129 +---------------- lib/libx52/x52_core.c | 244 +------------------------------- lib/libx52/x52_hotplug.h | 40 ------ 11 files changed, 45 insertions(+), 716 deletions(-) delete mode 100644 docs/design/hotplug.md delete mode 100644 lib/libusbx52/usb_x52_hotplug.c delete mode 100644 lib/libusbx52/usb_x52_vector.c delete mode 100644 lib/libx52/x52_hotplug.h diff --git a/ChangeLog.md b/ChangeLog.md index 414e68e..36a51ac 100644 --- a/ChangeLog.md +++ b/ChangeLog.md @@ -6,7 +6,6 @@ The format is based upon [Keep a Changelog]. ## [Unreleased] ### Added -- USB Hotplug support to libx52 and libusbx52 - Internationalization for the following: * libx52 * x52test diff --git a/docs/design/hotplug.md b/docs/design/hotplug.md deleted file mode 100644 index 2e79949..0000000 --- a/docs/design/hotplug.md +++ /dev/null @@ -1,63 +0,0 @@ -libx52 Hotplug Support -====================== - -This document describes a design for USB hotplug support in libx52. The idea is -to have a daemon process running at all times, which will update the hardware -when the X52/X52Pro is plugged in. - -# Assumptions - -The core assumption is that a maximum of 1 device is present at any time. There -is no goal to support more than 1 X52/X52Pro at the same time. - -# LibUSB Hotplug Support - -libusb-1.0 version 1.0.16 and newer support hotplug notifications when a device -is inserted or removed. These call a registered callback function which can read -the device descriptor, and take action accordingly. - -# libx52 Hotplug design - -The hotplug mechanism consists of the following functions: - -``` -int libx52_hotplug_init(libx52_hotplug_service **svc); -void libx52_hotplug_exit(libx52_hotplug_service *svc); - -int libx52_hotplug_register_callback(libx52_hotplug_service *svc, - libx52_hotplug_fn *callback_fn, - void *user_data, - libx52_hotplug_callback_handle **cb_handle); - -int libx52_hotplug_deregister_callback(libx52_hotplug_callback_handle *cb_handle); - -typedef void (*libx52_hotplug_fn)(bool inserted, void *user_data, libx52_device *dev); -``` - -The init function will take care of initializing libx52, so the user should -not call `libx52_init`. The exit function will also take care of deinitializing -libx52, so the user should not call `libx52_exit`. - -The user may register any number of callbacks, and they are called in an -undefined order on device insertion and removal. Each register callback also -returns a callback handle in an output parameter. This callback handle can be -used to deregister the callback in the future, if necessary. - -`libx52_hotplug_exit` will take care of deregistering all registered callbacks, -and will deinitialize libx52. - -# Interaction with libusbx52 - -As of this writing, libusbx52 reads from a regular file, however, in order to -support hotplug, the read should read from a fifo. Under Linux, a program can -open a fifo for reading and writing, and this should allow the program to write -a small amount of data into the fifo and exit, and the program using libusbx52 -can read from that file. - -In this case, the data format should change to include an additional character -prior to the idVendor and idProduct fields. This additional character will -indicate whether the device is being inserted or removed. - -libusbx52 must now spawn a separate thread to deal with the fifo. This thread -will read from the fifo, and callback the registered handler when an event -occurs. diff --git a/lib/libusbx52/Makefile.am b/lib/libusbx52/Makefile.am index 9b828b2..bb850ce 100644 --- a/lib/libusbx52/Makefile.am +++ b/lib/libusbx52/Makefile.am @@ -14,7 +14,7 @@ CC = $(PTHREAD_CC) # libusb stub library for use by test programs check_LTLIBRARIES = libusbx52.la -libusbx52_la_SOURCES = usb_x52_stub.c usb_x52_hotplug.c usb_x52_vector.c +libusbx52_la_SOURCES = usb_x52_stub.c libusbx52_la_CFLAGS = @LIBUSB_CFLAGS@ libusbx52_la_LDFLAGS = -rpath /nowhere -module diff --git a/lib/libusbx52/libusbx52.h b/lib/libusbx52/libusbx52.h index 78ce355..e7d7ca1 100644 --- a/lib/libusbx52/libusbx52.h +++ b/lib/libusbx52/libusbx52.h @@ -7,7 +7,7 @@ */ #include -#include +// #include #include struct libusb_device { @@ -23,17 +23,6 @@ struct libusb_context { int debug_level; int num_devices; struct libusb_device *devices; - - // Hotplug support - int hotplug_vid; - int hotplug_pid; - libusb_hotplug_event events; - libusb_hotplug_callback_fn callback; - void * cb_user_data; - - // Hotplug threading - volatile int stop_thread; - pthread_t hotplug_pthread; }; struct libusb_device_handle { @@ -76,20 +65,3 @@ struct libusb_device_handle { */ #define DEFAULT_OUTPUT_DATA_FILE "/tmp/libusbx52_output_data" -/** - * @brief Device update FIFO environment variable - * - * This is used by the test driver to update the simulated USB device list - */ -#define INPUT_DEVICE_FIFO_ENV "LIBUSBX52_DEVICE_FIFO" - -/** - * @brief Default file location of the device update FIFO - * - * This FIFO is read by a thread in libusbx52 and used to simulate the hotplug - * functionality of libusb. - */ -#define DEFAULT_INPUT_DEVICE_FIFO_FILE "/tmp/libusbx52_device_fifo" - -libusb_device* vector_push(libusb_context *ctx, int vid, int pid); -libusb_device* vector_pop(libusb_context *ctx, int vid, int pid); diff --git a/lib/libusbx52/usb_x52_hotplug.c b/lib/libusbx52/usb_x52_hotplug.c deleted file mode 100644 index f1b6a0d..0000000 --- a/lib/libusbx52/usb_x52_hotplug.c +++ /dev/null @@ -1,124 +0,0 @@ -/* - * LibUSB stub driver for hotplug APIs - * - * Copyright (C) 2020 Nirenjan Krishnan (nirenjan@nirenjan.org) - * - * SPDX-License-Identifier: GPL-2.0-only WITH Classpath-exception-2.0 - */ - -#include -#include -#include -#include -#include -#include - -#include -#include "libusbx52.h" - -#define CB_HANDLE_MAGIC 0xca11bacc - -static void *service_hotplug_events(void *args) -{ - libusb_context *ctx = args; - int parsed; - int vid; - int pid; - char action; - char *dev_fifo_file; - FILE *fifo; - libusb_device *dev; - - // Get the filename of the FIFO - dev_fifo_file = getenv(INPUT_DEVICE_FIFO_ENV); - if (dev_fifo_file == NULL || dev_fifo_file[0] == '\0') { - dev_fifo_file = DEFAULT_INPUT_DEVICE_FIFO_FILE; - } - - // Remove the FIFO if it exists - unlink(dev_fifo_file); - - // Create the FIFO - mkfifo(dev_fifo_file, 0777); - - fifo = fopen(dev_fifo_file, "r"); - if (fifo == NULL) { - return NULL; - } - - while (!ctx->stop_thread) { - parsed = fscanf(fifo, "%c %x %x", &action, &vid, &pid); - if (parsed == 3) { - switch (action) { - case '+': - dev = vector_push(ctx, vid, pid); - if ((ctx->events & LIBUSB_HOTPLUG_EVENT_DEVICE_ARRIVED) && - (ctx->hotplug_vid == LIBUSB_HOTPLUG_MATCH_ANY || ctx->hotplug_vid == vid) && - (ctx->hotplug_pid == LIBUSB_HOTPLUG_MATCH_ANY || ctx->hotplug_pid == pid)) { - (ctx->callback)(ctx, dev, - LIBUSB_HOTPLUG_EVENT_DEVICE_ARRIVED, - ctx->cb_user_data); - } - break; - - case '-': - dev = vector_pop(ctx, vid, pid); - if ((ctx->events & LIBUSB_HOTPLUG_EVENT_DEVICE_LEFT) && - (ctx->hotplug_vid == LIBUSB_HOTPLUG_MATCH_ANY || ctx->hotplug_vid == vid) && - (ctx->hotplug_pid == LIBUSB_HOTPLUG_MATCH_ANY || ctx->hotplug_pid == pid)) { - (ctx->callback)(ctx, dev, - LIBUSB_HOTPLUG_EVENT_DEVICE_LEFT, - ctx->cb_user_data); - } - break; - - case 'x': - /* Terminate the loop */ - ctx->stop_thread = 1; - break; - - } - } - } - - // Close the FIFO - fclose(fifo); - return NULL; -} - -int libusb_hotplug_register_callback(libusb_context *ctx, - libusb_hotplug_event events, - libusb_hotplug_flag flags, - int vendor_id, - int product_id, - int dev_class, - libusb_hotplug_callback_fn cb_fn, - void *user_data, - libusb_hotplug_callback_handle *cb_handle) -{ - // Save the events, flags, etc in the context. - ctx->hotplug_vid = vendor_id; - ctx->hotplug_pid = product_id; - ctx->events = events; - - ctx->callback = cb_fn; - ctx->cb_user_data = user_data; - - // Spawn the thread - pthread_create(&(ctx->hotplug_pthread), NULL, service_hotplug_events, ctx); - - // Since the stub library only accepts a single callback function, - // we will return a static value that will be used to check when - // deregistering. Only if the value matches will we terminate the thread. - *cb_handle = CB_HANDLE_MAGIC; - return LIBUSB_SUCCESS; -} - -void libusb_hotplug_deregister_callback(libusb_context *ctx, - libusb_hotplug_callback_handle cb_handle) -{ - if (cb_handle == CB_HANDLE_MAGIC) { - ctx->stop_thread = 1; - pthread_join(ctx->hotplug_pthread, NULL); - } -} diff --git a/lib/libusbx52/usb_x52_stub.c b/lib/libusbx52/usb_x52_stub.c index 5eb0dcd..9209539 100644 --- a/lib/libusbx52/usb_x52_stub.c +++ b/lib/libusbx52/usb_x52_stub.c @@ -51,6 +51,7 @@ int libusb_init(libusb_context **ctx) } /* Determine the number of devices in the file */ + dev_count = 0; do { parsed = fscanf(dev_list, "%x %x", &vid, &pid); /* @@ -60,12 +61,41 @@ int libusb_init(libusb_context **ctx) if (parsed < 2) { break; } - - if (vector_push(tmp_ctx, vid, pid) == NULL) { - goto init_err_recovery; - } + dev_count++; } while (!feof(dev_list)); + /* Make sure we have at least 1 device */ + if (dev_count == 0) { + rc = LIBUSB_ERROR_NOT_FOUND; + goto init_err_recovery; + } + + /* We now have the number of devices, allocate memory for them */ + tmp_ctx->devices = calloc(dev_count, sizeof(*(tmp_ctx->devices))); + if (tmp_ctx->devices == NULL) { + rc = LIBUSB_ERROR_NO_MEM; + goto init_err_recovery; + } + tmp_ctx->num_devices = dev_count; + + /* Rewind and read the file again, but now put them into the device list */ + rewind(dev_list); + + for (i = 0; i < dev_count && !feof(dev_list); i++) { + /* Set the base fields */ + tmp_ctx->devices[i].context = tmp_ctx; + tmp_ctx->devices[i].index = i; + + parsed = fscanf(dev_list, "%x %x", &vid, &pid); + if (parsed < 2) { + /* Parse error, skip this device */ + continue; + } + /* Set the VID & PID */ + tmp_ctx->devices[i].desc.idVendor = vid; + tmp_ctx->devices[i].desc.idProduct = pid; + } + /* Done, close the file and return */ fclose(dev_list); @@ -73,11 +103,6 @@ int libusb_init(libusb_context **ctx) return LIBUSB_SUCCESS; init_err_recovery: - /* Free the device list, if it is available */ - if (tmp_ctx->devices != NULL) { - free(tmp_ctx->devices); - } - /* Close the device list file if it is open */ if (dev_list) { fclose(dev_list); diff --git a/lib/libusbx52/usb_x52_vector.c b/lib/libusbx52/usb_x52_vector.c deleted file mode 100644 index 6082917..0000000 --- a/lib/libusbx52/usb_x52_vector.c +++ /dev/null @@ -1,83 +0,0 @@ -/* - * LibUSB stub - device list - * - * Copyright (C) 2020 Nirenjan Krishnan (nirenjan@nirenjan.org) - * - * SPDX-License-Identifier: GPL-2.0-only WITH Classpath-exception-2.0 - */ - -#include -#include -#include -#include -#include "libusbx52.h" - -static pthread_mutex_t vector_mutex = PTHREAD_MUTEX_INITIALIZER; - -libusb_device * vector_push(libusb_context *ctx, int vid, int pid) -{ - int i; - int num_devices; - libusb_device *devlist; - - pthread_mutex_lock(&vector_mutex); - - // Make sure that we have an empty slot, if not, we need to reallocate the - // device list - for (i = 0; i < ctx->num_devices; i++) { - if (ctx->devices[i].context == NULL) { - break; - } - } - - if (i == ctx->num_devices) { - // No empty slots, we will need to reallocate the device list - num_devices = ctx->num_devices + 1; - devlist = calloc(num_devices, sizeof(*devlist)); - if (devlist == NULL) { - pthread_mutex_unlock(&vector_mutex); - return NULL; - } - memcpy(devlist, ctx->devices, ctx->num_devices * sizeof(*devlist)); - ctx->num_devices = num_devices; - - free(ctx->devices); - ctx->devices = devlist; - } - - ctx->devices[i].context = ctx; - ctx->devices[i].index = i; - ctx->devices[i].desc.idVendor = vid; - ctx->devices[i].desc.idProduct = pid; - - pthread_mutex_unlock(&vector_mutex); - return &(ctx->devices[i]); -} - -libusb_device * vector_pop(libusb_context *ctx, int vid, int pid) -{ - int i; - libusb_device *dev; - - // Search through the device list for a matching VID/PID pair - // If found, then delete it from the list - - pthread_mutex_lock(&vector_mutex); - - for (i = 0; i < ctx->num_devices; i++) { - dev = &(ctx->devices[i]); - if (dev->desc.idVendor == vid && dev->desc.idProduct == pid) { - break; - } - } - - if (i < ctx->num_devices) { - memset(dev, 0, sizeof(*dev)); - } else { - dev = NULL; - } - - pthread_mutex_unlock(&vector_mutex); - - return dev; -} diff --git a/lib/libx52/Makefile.am b/lib/libx52/Makefile.am index b11b8cd..0f38cad 100644 --- a/lib/libx52/Makefile.am +++ b/lib/libx52/Makefile.am @@ -24,4 +24,4 @@ x52include_HEADERS = libx52.h pkgconfig_DATA = libx52.pc # Extra files that need to be in the distribution -EXTRA_DIST = libx52.h x52_commands.h x52_common.h x52_hotplug.h README.md +EXTRA_DIST = libx52.h x52_commands.h x52_common.h README.md diff --git a/lib/libx52/libx52.h b/lib/libx52/libx52.h index e0783b2..234605c 100644 --- a/lib/libx52/libx52.h +++ b/lib/libx52/libx52.h @@ -6,22 +6,11 @@ * SPDX-License-Identifier: GPL-2.0-only WITH Classpath-exception-2.0 */ -/** - * @file libx52.h - * @brief Headers for the Saitek X52 MFD & LED driver library - * - * This file contains the type and function prototypes for the Saitek X52 - * driver library. These are only needed to control the MFD and LEDs, and - * don't impact the joystick (HID) functionality. - * - * @author Nirenjan Krishnan (nirenjan@nirenjan.org) - */ #ifndef LIBX52_H #define LIBX52_H #include #include -#include #ifdef __cplusplus extern "C" { @@ -39,38 +28,6 @@ struct libx52_device; */ typedef struct libx52_device libx52_device; -/** - * @addtogroup libx52hotplug - * @{ - */ - -/** - * @brief Opaque structure used by libx52 hotplug API - */ -struct libx52_hotplug_callback_handle; - -/** - * @brief Opaque structure used by libx52 hotplug API - */ -typedef struct libx52_hotplug_callback_handle libx52_hotplug_callback_handle; - -/** - * @brief Opaque structure used by libx52 hotplug API - */ -struct libx52_hotplug_service; - -/** - * @brief Opaque structure used by libx52 hotplug API - */ -typedef struct libx52_hotplug_service libx52_hotplug_service; - -/** - * @brief Callback function for hotplug events - */ -typedef void (*libx52_hotplug_fn)(bool inserted, void *user_data, libx52_device *dev); - -/** @} */ - /** * @brief List of supported clocks on the MFD * @ingroup libx52clock @@ -252,7 +209,7 @@ typedef enum { * structures to access the joystick, and returns a \ref libx52_device pointer. * All calls to libx52 use the returned pointer to control the device. * - * If no joystick is found `libx52_init()` returns \ref LIBX52_ERROR_NO_DEVICE. + * If no joystick is found `libx52_init()` returns _NULL_. * * @par Limitations * This function does not support hotplugging. The joystick must be plugged in @@ -276,90 +233,10 @@ int libx52_init(libx52_device ** dev); */ void libx52_exit(libx52_device *dev); -/** - * @brief Initialize the X52 library hotplug service - * - * This function initializes the libx52 library hotplug service, which will - * monitor the bus for insertion and removal of any X52/X52Pro joystick, and - * will trigger registered callbacks on such events. - * - * @see libx52_hotplug_register_callback - * @see libx52_hotplug_deregister_callback - * - * @param[out] svc Pointer to a \ref libx52_hotplug_service * - * - * @returns \ref libx52_error_code indicating status - */ -int libx52_hotplug_init(libx52_hotplug_service **svc); - -/** - * @brief Exit the library and free up any resources used - * - * This function releases any resources allocated by \ref libx52_hotplug_init - * and terminates the library. Using the freed device now is invalid and can - * cause errors. - * - * @param[in] svc Pointer to the hotplug service - * @returns None - */ -void libx52_hotplug_exit(libx52_hotplug_service *svc); - /** @} */ /** - * @defgroup libx52hotplug Hotplug Callbacks - * @{ - */ - -/** - * @brief Register a callback function - * - * This function registers a callback function that is triggered when a - * supported joystick is inserted or removed. - * - * @param[in] svc Pointer to the hotplug service - * @param[in] callback_fn Pointer to callback function - * @param[in] user_data Any user data that needs to be passed to the - * callback function - * @param[out] cb_handle Pointer to a \ref libx52_hotplug_callback_handle * - * This will be used by the application to deregister - * the callback if necessary. This may be NULL, in - * which case, the callback handle is not saved. - * - * @returns \ref libx52_error_code indicating status - * - * @par Example - * @code - * libx52_hotplug_service *svc; - * libx52_hotplug_callback_handle *hdl; - * ... - * rc = libx52_hotplug_register_callback(svc, hotplug_cb, context, &hdl); - * if (rc != LIBX52_SUCCESS) { - * return rc; - * } - * @endcode - */ -int libx52_hotplug_register_callback(libx52_hotplug_service *svc, - libx52_hotplug_fn callback_fn, - void *user_data, - libx52_hotplug_callback_handle **cb_handle); - -/** - * @brief Deregister a callback function - * - * This function deregisters a previously registered callback function when - * a supported joystick is inserted or removed. - * - * @param[in] hdl Pointer to the hotplug callback handle - * - * @returns \ref libx52_error_code indicating status - */ -int libx52_hotplug_deregister_callback(libx52_hotplug_callback_handle *hdl); - -/** @} */ - -/** - * @defgroup libx52mfdled MFD & LED control + * @defgroup mfdled MFD & LED control * @{ */ @@ -633,8 +510,6 @@ int libx52_vendor_command(libx52_device *x52, uint16_t index, uint16_t value); */ const char * libx52_strerror(libx52_error_code error); -/** @} */ - #ifdef __cplusplus } #endif diff --git a/lib/libx52/x52_core.c b/lib/libx52/x52_core.c index 85b1eca..85114cd 100644 --- a/lib/libx52/x52_core.c +++ b/lib/libx52/x52_core.c @@ -15,7 +15,6 @@ #include "libx52.h" #include "x52_commands.h" #include "x52_common.h" -#include "x52_hotplug.h" #include "gettext.h" #define VENDOR_SAITEK 0x06a3 @@ -38,12 +37,10 @@ static int libx52_check_product(uint16_t idVendor, uint16_t idProduct) return 0; } -/* Set flags according to the device model */ -static void libx52_set_dev_flags(libx52_device *dev, uint16_t idProduct) +/* Check if the attached device is an X52 Pro */ +static int libx52_device_is_x52pro(uint16_t idProduct) { - if (idProduct == X52_PROD_X52PRO) { - set_bit(&(dev->flags), X52_FLAG_IS_PRO); - } + return (idProduct == X52_PROD_X52PRO); } int libx52_init(libx52_device **dev) @@ -97,7 +94,9 @@ int libx52_init(libx52_device **dev) x52_dev->hdl = hdl; - libx52_set_dev_flags(x52_dev, desc.idProduct); + if (libx52_device_is_x52pro(desc.idProduct)) { + set_bit(&(x52_dev->flags), X52_FLAG_IS_PRO); + } break; } } @@ -129,234 +128,3 @@ void libx52_exit(libx52_device *dev) free(dev); } -static int _hotplug_handler( - libusb_context *ctx, - libusb_device *dev, - libusb_hotplug_event event, - void *user_data -) { - libx52_hotplug_service *svc = user_data; - libx52_hotplug_callback_handle *cb; - struct libusb_device_descriptor desc; - size_t i; - int rc; - - rc = libusb_get_device_descriptor(dev, &desc); - if (rc != LIBUSB_SUCCESS) { - return rc; - } - - if (libx52_check_product(desc.idVendor, desc.idProduct)) { - return LIBX52_ERROR_NOT_SUPPORTED; - } - - if (event == LIBUSB_HOTPLUG_EVENT_DEVICE_ARRIVED) { - rc = libusb_open(dev, &(svc->dev->hdl)); - if (rc != LIBUSB_SUCCESS) { - return libx52internal_translate_libusb_error(rc); - } - - libx52_set_dev_flags(svc->dev, desc.idProduct); - } else if (event == LIBUSB_HOTPLUG_EVENT_DEVICE_LEFT) { - if (svc->dev->hdl != NULL) { - libusb_close(svc->dev->hdl); - svc->dev->hdl = NULL; - } - } else { - return LIBX52_ERROR_INVALID_PARAM; - } - - /* Iterate through registered callbacks */ - for (i = 0; i < svc->num_callbacks; i++) { - cb = svc->callbacks[i]; - if (cb->callback != NULL) { - (cb->callback)(event == LIBUSB_HOTPLUG_EVENT_DEVICE_ARRIVED, - cb->user_data, svc->dev); - } - } - - return 0; -} - -int libx52_hotplug_init(libx52_hotplug_service **service) -{ - libx52_hotplug_service *svc; - int rc = LIBX52_SUCCESS; - - /* Make sure that we have a valid return pointer */ - if (service == NULL) { - return LIBX52_ERROR_INVALID_PARAM; - } - - /* Allocate memory for the library's data structures */ - svc = calloc(1, sizeof(*svc)); - if (svc == NULL) { - rc = LIBX52_ERROR_OUT_OF_MEMORY; - goto err_recovery; - } - - /* Allocate initial buffer for callbacks list */ - svc->callbacks = calloc(DEFAULT_NUM_CALLBACKS, sizeof(*(svc->callbacks))); - if (svc->callbacks == NULL) { - rc = LIBX52_ERROR_OUT_OF_MEMORY; - goto err_recovery; - } - svc->num_callbacks = DEFAULT_NUM_CALLBACKS; - - svc->dev = calloc(1, sizeof(*(svc->dev))); - if (svc->dev == NULL) { - rc = LIBX52_ERROR_OUT_OF_MEMORY; - goto err_recovery; - } - - /* Initialize libusb */ - rc = libusb_init(&(svc->dev->ctx)); - if (rc != LIBUSB_SUCCESS) { - rc = LIBX52_ERROR_INIT_FAILURE; - goto err_recovery; - } - #if defined(LIBUSB_API_VERSION) && (LIBUSB_API_VERSION >= 0x01000106) - /* - * Use the libusb_set_option flag instead of libusb_set_debug. This - * was introduced in libusb 1.0.22 - */ - libusb_set_option(svc->dev->ctx, LIBUSB_OPTION_LOG_LEVEL, - LIBUSB_LOG_LEVEL_WARNING); - #else - libusb_set_debug(svc->dev->ctx, LIBUSB_LOG_LEVEL_WARNING); - #endif - - /* Register with the libusb hotplug API */ - rc = libusb_hotplug_register_callback(svc->dev->ctx, - LIBUSB_HOTPLUG_EVENT_DEVICE_ARRIVED | LIBUSB_HOTPLUG_EVENT_DEVICE_LEFT, - LIBUSB_HOTPLUG_ENUMERATE, VENDOR_SAITEK, - LIBUSB_HOTPLUG_MATCH_ANY, LIBUSB_HOTPLUG_MATCH_ANY, - _hotplug_handler, svc, &(svc->cb_handle)); - if (rc != LIBUSB_SUCCESS) { - rc = LIBX52_ERROR_INIT_FAILURE; - libusb_exit(svc->dev->ctx); - goto err_recovery; - } - - *service = svc; - return rc; - -err_recovery: - if (svc->dev != NULL) { - free(svc->dev); - } - - if (svc->callbacks != NULL) { - free(svc->callbacks); - } - - free(svc); - return rc; -} - -void libx52_hotplug_exit(libx52_hotplug_service *svc) { - if (svc == NULL || svc->dev == NULL || svc->callbacks == NULL) { - return; - } - - /* Deregister the callback handle */ - libusb_hotplug_deregister_callback(svc->dev->ctx, svc->cb_handle); - - /* Clean up registered callback handlers */ - for (size_t i = 0; i < svc->num_callbacks; i++) { - free(svc->callbacks[i]); - } - free(svc->callbacks); - - if (svc->dev->hdl != NULL) { - libusb_close(svc->dev->hdl); - } - - libusb_exit(svc->dev->ctx); - - /* Clear the device area and free it */ - memset(svc->dev, 0, sizeof(*svc->dev)); - free(svc->dev); - - /* Clear the service pointer before freeing it */ - memset(svc, 0, sizeof(*svc)); - free(svc); -} - -int libx52_hotplug_register_callback(libx52_hotplug_service *svc, - libx52_hotplug_fn callback_fn, - void *user_data, - libx52_hotplug_callback_handle **cb_handle) -{ - libx52_hotplug_callback_handle *hdl; - libx52_hotplug_callback_handle **callbacks; - size_t i; - - if (svc == NULL || callback_fn == NULL) { - return LIBX52_ERROR_INVALID_PARAM; - } - - /* Find an empty slot */ - for (i = 0; i < svc->num_callbacks; i++) { - if (svc->callbacks[i] == NULL) { - break; - } - } - if (i == svc->num_callbacks) { - /* Existing callbacks array is full, create a new one */ - callbacks = calloc(svc->num_callbacks + DEFAULT_NUM_CALLBACKS, sizeof(*callbacks)); - if (callbacks == NULL) { - return LIBX52_ERROR_OUT_OF_MEMORY; - } - - /* Copy the callbacks array to the new one */ - for (i = 0; i < svc->num_callbacks; i++) { - callbacks[i] = svc->callbacks[i]; - } - - /* Free the old array, and adjust the link to the new larger array */ - svc->num_callbacks += DEFAULT_NUM_CALLBACKS; - free(svc->callbacks); - svc->callbacks = callbacks; - } - - hdl = calloc(1, sizeof(*hdl)); - if (hdl == NULL) { - return LIBX52_ERROR_OUT_OF_MEMORY; - } - - hdl->svc = svc; - hdl->id = i; - hdl->callback = callback_fn; - hdl->user_data = user_data; - - /* Insert the node into the callbacks list */ - svc->callbacks[i] = hdl; - - if (cb_handle != NULL) { - *cb_handle = hdl; - } - - return LIBX52_SUCCESS; -} - -int libx52_hotplug_deregister_callback(libx52_hotplug_callback_handle *hdl) -{ - libx52_hotplug_service *svc; - - if (hdl == NULL || hdl->svc == NULL) { - return LIBX52_ERROR_INVALID_PARAM; - } - - svc = hdl->svc; - - if (hdl->id >= svc->num_callbacks) { - return LIBX52_ERROR_INVALID_PARAM; - } - - /* Free the handle */ - svc->callbacks[hdl->id] = NULL; - free(hdl); - - return LIBX52_SUCCESS; -} diff --git a/lib/libx52/x52_hotplug.h b/lib/libx52/x52_hotplug.h deleted file mode 100644 index 2e99135..0000000 --- a/lib/libx52/x52_hotplug.h +++ /dev/null @@ -1,40 +0,0 @@ -/* - * Saitex X52 Pro MFD & LED driver - * - * Copyright (C) 2012-2020 Nirenjan Krishnan (nirenjan@nirenjan.org) - * - * SPDX-License-Identifier: GPL-2.0-only WITH Classpath-exception-2.0 - */ - -#ifndef X52_HOTPLUG_H -#define X52_HOTPLUG_H - -#include -#include -#include "libx52.h" - -/* - * Structure for callback handle. This is a node in a doubly linked list, - * which is iterated over by the libusb callback handler. - */ -struct libx52_hotplug_callback_handle { - libx52_hotplug_service *svc; - - libx52_hotplug_fn callback; - void *user_data; - - size_t id; -}; - -struct libx52_hotplug_service { - libx52_device *dev; - - libusb_hotplug_callback_handle cb_handle; - - libx52_hotplug_callback_handle **callbacks; - size_t num_callbacks; -}; - -#define DEFAULT_NUM_CALLBACKS 8 - -#endif /* !defined X52_HOTPLUG_H */