diff --git a/libusbx52/usb_x52_stub.c b/libusbx52/usb_x52_stub.c index 91d54d6..fa11adb 100644 --- a/libusbx52/usb_x52_stub.c +++ b/libusbx52/usb_x52_stub.c @@ -277,3 +277,25 @@ int libusb_control_transfer(libusb_device_handle *dev_handle, return 0; } + +int libusb_kernel_driver_active(libusb_device_handle *hdl, int interface_number) +{ + return (hdl->dev->ref_count > 0); +} + +/* Indicate that the stub library can support hotplug, even though it doesn't */ +int libusb_has_capability(uint32_t capability) +{ + return capability == LIBUSB_CAP_HAS_HOTPLUG; +} + +/* Dummy function to simulate registering callbacks */ +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 *callback_handle) +{ + return LIBUSB_SUCCESS; +} diff --git a/libx52/Makefile.am b/libx52/Makefile.am index f1209c9..22a3927 100644 --- a/libx52/Makefile.am +++ b/libx52/Makefile.am @@ -12,7 +12,7 @@ lib_LTLIBRARIES += libx52.la # See: https://www.gnu.org/software/libtool/manual/html_node/Updating-version-info.html libx52_v_CUR=6 libx52_v_AGE=4 -libx52_v_REV=0 +libx52_v_REV=1 libx52_la_SOURCES = \ libx52/x52_control.c \ libx52/x52_core.c \ diff --git a/libx52/x52_common.h b/libx52/x52_common.h index c3e8533..b40f449 100644 --- a/libx52/x52_common.h +++ b/libx52/x52_common.h @@ -51,6 +51,9 @@ struct libx52_device { int timezone[X52_MFD_CLOCKS]; libx52_clock_format time_format[X52_MFD_CLOCKS]; + + libusb_hotplug_callback_handle hotplug_handle; + int handle_registered; }; /** Flag bits */ diff --git a/libx52/x52_core.c b/libx52/x52_core.c index 809b356..d1ea6d5 100644 --- a/libx52/x52_core.c +++ b/libx52/x52_core.c @@ -42,9 +42,52 @@ static int libx52_device_is_x52pro(uint16_t idProduct) return (idProduct == X52_PROD_X52PRO); } +static int _x52_hotplug_callback(libusb_context *ctx, + libusb_device *device, + libusb_hotplug_event event, void *user_data) +{ + libx52_device *dev = user_data; + + if (dev == NULL) { + return 0; + } + + /* Double check that the context matches the libx52 structure */ + if (dev->ctx != ctx) { + return 0; + } + + if (event == LIBUSB_HOTPLUG_EVENT_DEVICE_LEFT) { + /* + * Return 1 if we successfully disconnected. This will automatically + * deregister the callback. + */ + return (libx52_disconnect(dev) == LIBX52_SUCCESS); + } + + return 0; +} + bool libx52_is_connected(libx52_device *dev) { - return (dev && dev->hdl); + int rc; + + if (!dev) { + return false; + } + + + if (dev->hdl) { + if (dev->handle_registered) { + return true; + } + + /* Check if interface 0 has a kernel driver attached */ + rc = libusb_kernel_driver_active(dev->hdl, 0); + return (rc == 1); + } + + return false; } int libx52_disconnect(libx52_device *dev) @@ -57,6 +100,7 @@ int libx52_disconnect(libx52_device *dev) libusb_close(dev->hdl); dev->hdl = NULL; dev->flags = 0; + dev->handle_registered = 0; } return LIBX52_SUCCESS; @@ -112,6 +156,23 @@ int libx52_connect(libx52_device *dev) return LIBX52_ERROR_NO_DEVICE; } + + /* Setup hotplug callback when this device is disconnected */ + if (libusb_has_capability(LIBUSB_CAP_HAS_HOTPLUG)) { + /* + * Mark if the hotplug callback registered successfully. If it did + * not register, we can use the kernel driver API to determine if + * the device is still connected. + */ + dev->handle_registered = (LIBUSB_SUCCESS == + libusb_hotplug_register_callback(dev->ctx, + LIBUSB_HOTPLUG_EVENT_DEVICE_LEFT, 0, + desc.idVendor, desc.idProduct, + LIBUSB_HOTPLUG_MATCH_ANY, + _x52_hotplug_callback, dev, + &(dev->hotplug_handle))); + } + return LIBX52_SUCCESS; }