Fix claiming interface with force option
authorKrzysztof Opasiak <k.opasiak@samsung.com>
Mon, 29 Jun 2015 17:34:29 +0000 (19:34 +0200)
committerStanislaw Wadas <s.wadas@samsung.com>
Wed, 2 Dec 2015 12:45:16 +0000 (13:45 +0100)
We cannot use this auto function because it afects all
interfaces of given device. Instead of let's handle this
by ourselves.

Change-Id: I6114ffe4114dc7338d146f9e17aa8259ccfa67fa
Signed-off-by: Krzysztof Opasiak <k.opasiak@samsung.com>
src/libhusb.c

index 415f8b15c532a94eba1bbb7b8e536c9790d3adc9..ef6344ee908fed144a5eb107a83f15e379ecff9b 100644 (file)
@@ -27,6 +27,8 @@
 #include "uref.h"
 #include "common.h"
 
+#define MAX_NMB_OF_CONFIGS 255
+
 struct libhusb_context {
        libusb_context *lusb_ctx;
 };
@@ -43,6 +45,8 @@ static inline struct libhusb_device *to_libhusb_device(struct uref *_uref)
 
 struct libhusb_device_handle {
        struct libusb_device_handle *lusb_dev_handle;
+       /* TODO: replace with bit fields */
+       unsigned char driver_detached[MAX_NMB_OF_CONFIGS];
 };
 
 /* TODO add error translation */
@@ -243,31 +247,79 @@ int libhusb_set_config(libhusb_device_handle *handle, int configuration)
        return ret;
 }
 
-int libhusb_claim_interface(libhusb_device_handle *handle, int interface_number, int force)
+int libhusb_claim_interface(libhusb_device_handle *handle, int interface_number,
+                           int force)
 {
-       int ret;
+       int ret = -1;
+       int driver_detached = 0;
 
        assert(handle);
 
-       if (force) {
-               ret = libusb_set_auto_detach_kernel_driver(handle->lusb_dev_handle, 1);
-               if (ret == LIBUSB_ERROR_NOT_SUPPORTED)
-                       return -1;
+       if (interface_number < 0 || interface_number > MAX_NMB_OF_CONFIGS)
+               goto out;
+
+       if (!force)
+               goto claim_interface;
+       /*
+        * If force param has been set let's check if kernel driver is active
+        * and detach it if necessary
+        */
+       ret = libusb_kernel_driver_active(handle->lusb_dev_handle,
+                                         interface_number);
+       if (ret < 0) {
+               goto out;
+       } else if (ret == 1) {
+               ret = libusb_detach_kernel_driver(handle->lusb_dev_handle,
+                                                 interface_number);
+               if (ret < 0)
+                       goto out;
+
+               driver_detached = 1;
        }
 
+claim_interface:
        ret = libusb_claim_interface(handle->lusb_dev_handle, interface_number);
+       if (ret < 0)
+               goto claim_failed;
+
+       handle->driver_detached[interface_number] = 1;
+
+       return 0;
 
+claim_failed:
+       if (driver_detached)
+               libusb_attach_kernel_driver(handle->lusb_dev_handle,
+                                           interface_number);
+out:
+       /* Add proper error handling */
        return ret;
 }
 
 int libhusb_release_interface(libhusb_device_handle *handle, int interface_number)
 {
-       int ret;
+       int ret = -1;
 
        assert(handle);
 
-       ret = libusb_release_interface(handle->lusb_dev_handle, interface_number);
+       if (interface_number < 0 || interface_number > MAX_NMB_OF_CONFIGS)
+               goto out;
+
+       ret = libusb_release_interface(handle->lusb_dev_handle,
+                                      interface_number);
+       if (ret != 0)
+               goto out;
+
+       if (handle->driver_detached[interface_number]) {
+               /*
+                * yeah we should check error code but there is no good method
+                * of handling it so for now lets just silently ignore it
+                */
+               libusb_attach_kernel_driver(handle->lusb_dev_handle,
+                                           interface_number);
+               handle->driver_detached[interface_number] = 0;
+       }
 
+out:
        return ret;
 }