am7xxx: use a saner approach when setting the USB configuration
[libam7xxx.git] / src / am7xxx.c
index 3334615..321a193 100644 (file)
@@ -708,6 +708,7 @@ static int open_device(am7xxx_context *ctx,
                       am7xxx_device **dev)
 {
        int ret;
+       int current_configuration;
 
        *dev = find_device(ctx, device_index);
        if (*dev == NULL) {
@@ -732,13 +733,17 @@ static int open_device(am7xxx_context *ctx,
         * to close it again before bailing out.
         */
 
-       ret = libusb_set_configuration((*dev)->usb_device,
-                                      (*dev)->desc->configuration);
-       if (ret < 0) {
-               debug(ctx, "libusb_set_configuration failed\n");
-               debug(ctx, "Cannot set configuration %hhu\n",
-                     (*dev)->desc->configuration);
-               goto out_libusb_close;
+       current_configuration = -1;
+       libusb_get_configuration((*dev)->usb_device, &current_configuration);
+       if (current_configuration != (*dev)->desc->configuration) {
+               ret = libusb_set_configuration((*dev)->usb_device,
+                                              (*dev)->desc->configuration);
+               if (ret < 0) {
+                       debug(ctx, "libusb_set_configuration failed\n");
+                       debug(ctx, "Cannot set configuration %hhu\n",
+                             (*dev)->desc->configuration);
+                       goto out_libusb_close;
+               }
        }
 
        ret = libusb_claim_interface((*dev)->usb_device,
@@ -747,12 +752,27 @@ static int open_device(am7xxx_context *ctx,
                debug(ctx, "libusb_claim_interface failed\n");
                debug(ctx, "Cannot claim interface %hhu\n",
                      (*dev)->desc->interface_number);
-out_libusb_close:
-               libusb_close((*dev)->usb_device);
-               (*dev)->usb_device = NULL;
+               goto out_libusb_close;
+       }
+
+       /* Checking that the configuration has not changed, as suggested in
+        * http://libusb.sourceforge.net/api-1.0/caveats.html
+        */
+       current_configuration = -1;
+       libusb_get_configuration((*dev)->usb_device, &current_configuration);
+       if (current_configuration != (*dev)->desc->configuration) {
+               debug(ctx, "libusb configuration changed\n");
+               debug(ctx, "Cannot claim interface %hhu\n",
+                     (*dev)->desc->interface_number);
+               goto out_libusb_close;
        }
 out:
        return ret;
+
+out_libusb_close:
+       libusb_close((*dev)->usb_device);
+       (*dev)->usb_device = NULL;
+       return ret;
 }
 
 typedef enum {
@@ -764,13 +784,14 @@ typedef enum {
  * This is where the central logic of multi-device support is.
  *
  * When 'op' == SCAN_OP_BUILD_DEVLIST the parameters 'open_device_index' and
- * 'dev' are ignored; the function returns 0 on success and a negative value
+ * 'dev' are ignored; the function returns 0 on success or a negative value
  * on error.
  *
  * When 'op' == SCAN_OP_OPEN_DEVICE the function opens the supported USB
  * device with index 'open_device_index' and returns the correspondent
- * am7xxx_device in the 'dev' parameter; the function returns 0 on success,
- * 1 if the device was already open and a negative value on error.
+ * am7xxx_device in the 'dev' parameter; the function returns the value from
+ * open_device(), which is 0 on success, 1 if the device was already open or
+ * a negative value on error.
  *
  * NOTES:
  * if scan_devices() fails when called with 'op' == SCAN_OP_BUILD_DEVLIST,