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 */