Always enable async mode using libusb 1.x
[libftdi] / src / ftdi.c
index 5c25abd..b22a55b 100644 (file)
         return code;                       \
    } while(0);
 
+#define ftdi_error_return_free_device_list(code, str, devs) do {    \
+        libusb_free_device_list(devs,1);   \
+        ftdi->error_str = str;             \
+        return code;                       \
+   } while(0);
+
 
 /**
     Internal function to close usb device pointer.
@@ -72,6 +78,7 @@ static void ftdi_usb_close_internal (struct ftdi_context *ftdi)
 */
 int ftdi_init(struct ftdi_context *ftdi)
 {
+    ftdi->usb_ctx = NULL;
     ftdi->usb_dev = NULL;
     ftdi->usb_read_timeout = 5000;
     ftdi->usb_write_timeout = 5000;
@@ -185,6 +192,7 @@ void ftdi_deinit(struct ftdi_context *ftdi)
         free(ftdi->readbuffer);
         ftdi->readbuffer = NULL;
     }
+    libusb_exit(ftdi->usb_ctx);
 }
 
 /**
@@ -236,10 +244,10 @@ int ftdi_usb_find_all(struct ftdi_context *ftdi, struct ftdi_device_list **devli
     int count = 0;
     int i = 0;
 
-    if (libusb_init(NULL) < 0)
+    if (libusb_init(&ftdi->usb_ctx) < 0)
         ftdi_error_return(-4, "libusb_init() failed");
 
-    if (libusb_get_device_list(NULL, &devs) < 0)
+    if (libusb_get_device_list(ftdi->usb_ctx, &devs) < 0)
         ftdi_error_return(-5, "libusb_get_device_list() failed");
 
     curdev = devlist;
@@ -442,7 +450,7 @@ int ftdi_usb_open_dev(struct ftdi_context *ftdi, libusb_device *dev)
 {
     struct libusb_device_descriptor desc;
     struct libusb_config_descriptor *config0;
-    int cfg, cfg0;
+    int cfg, cfg0, detach_errno = 0;
 
     if (ftdi == NULL)
         ftdi_error_return(-8, "ftdi context invalid");
@@ -458,22 +466,17 @@ int ftdi_usb_open_dev(struct ftdi_context *ftdi, libusb_device *dev)
     cfg0 = config0->bConfigurationValue;
     libusb_free_config_descriptor (config0);
 
-#ifdef LIBUSB_HAS_GET_DRIVER_NP
     // Try to detach ftdi_sio kernel module.
-    // Returns ENODATA if driver is not loaded.
     //
     // The return code is kept in a separate variable and only parsed
     // if usb_set_configuration() or usb_claim_interface() fails as the
     // detach operation might be denied and everything still works fine.
     // Likely scenario is a static ftdi_sio kernel module.
-    ret = libusb_detach_kernel_driver(ftdi->usb_dev, ftdi->interface);
-    if (ret < 0 && ret != LIBUSB_ERROR_NOT_FOUND)
-        ftdi_error_return(-11, "libusb_detach_kernel_driver () failed");
-#endif
+    if (libusb_detach_kernel_driver(ftdi->usb_dev, ftdi->interface) !=0)
+        detach_errno = errno;
 
     if (libusb_get_configuration (ftdi->usb_dev, &cfg) < 0)
         ftdi_error_return(-12, "libusb_get_configuration () failed");
-
     // set configuration (needed especially for windows)
     // tolerate EBUSY: one device with one configuration, but two interfaces
     //    and libftdi sessions to both interfaces (e.g. FT2232)
@@ -482,14 +485,28 @@ int ftdi_usb_open_dev(struct ftdi_context *ftdi, libusb_device *dev)
         if (libusb_set_configuration(ftdi->usb_dev, cfg0) < 0)
         {
             ftdi_usb_close_internal (ftdi);
-            ftdi_error_return(-3, "unable to set usb configuration. Make sure ftdi_sio is unloaded!");
+            if(detach_errno == EPERM)
+            {
+                ftdi_error_return(-8, "inappropriate permissions on device!");
+            }
+            else
+            {
+                ftdi_error_return(-3, "unable to set usb configuration. Make sure the default FTDI driver is not in use");
+            }
         }
     }
 
     if (libusb_claim_interface(ftdi->usb_dev, ftdi->interface) < 0)
     {
         ftdi_usb_close_internal (ftdi);
-        ftdi_error_return(-5, "unable to claim usb device. Make sure ftdi_sio is unloaded!");
+        if(detach_errno == EPERM)
+        {
+            ftdi_error_return(-8, "inappropriate permissions on device!");
+        }
+        else
+        {
+            ftdi_error_return(-5, "unable to claim usb device. Make sure the default FTDI driver is not in use");
+        }
     }
 
     if (ftdi_usb_reset (ftdi) != 0)
@@ -613,33 +630,34 @@ int ftdi_usb_open_desc_index(struct ftdi_context *ftdi, int vendor, int product,
     char string[256];
     int i = 0;
 
-    if (libusb_init(NULL) < 0)
+    if (libusb_init(&ftdi->usb_ctx) < 0)
         ftdi_error_return(-11, "libusb_init() failed");
 
-    if (libusb_get_device_list(NULL, &devs) < 0)
-        ftdi_error_return(-12, "libusb_get_device_list() failed");
-
     if (ftdi == NULL)
         ftdi_error_return(-11, "ftdi context invalid");
 
+    if (libusb_get_device_list(ftdi->usb_ctx, &devs) < 0)
+        ftdi_error_return(-12, "libusb_get_device_list() failed");
+
     while ((dev = devs[i++]) != NULL)
     {
         struct libusb_device_descriptor desc;
+        int res;
 
         if (libusb_get_device_descriptor(dev, &desc) < 0)
-            ftdi_error_return(-13, "libusb_get_device_descriptor() failed");
+            ftdi_error_return_free_device_list(-13, "libusb_get_device_descriptor() failed", devs);
 
         if (desc.idVendor == vendor && desc.idProduct == product)
         {
             if (libusb_open(dev, &ftdi->usb_dev) < 0)
-                ftdi_error_return(-4, "usb_open() failed");
+                ftdi_error_return_free_device_list(-4, "usb_open() failed", devs);
 
             if (description != NULL)
             {
                 if (libusb_get_string_descriptor_ascii(ftdi->usb_dev, desc.iProduct, (unsigned char *)string, sizeof(string)) < 0)
                 {
                     libusb_close (ftdi->usb_dev);
-                    ftdi_error_return(-8, "unable to fetch product description");
+                    ftdi_error_return_free_device_list(-8, "unable to fetch product description", devs);
                 }
                 if (strncmp(string, description, sizeof(string)) != 0)
                 {
@@ -652,7 +670,7 @@ int ftdi_usb_open_desc_index(struct ftdi_context *ftdi, int vendor, int product,
                 if (libusb_get_string_descriptor_ascii(ftdi->usb_dev, desc.iSerialNumber, (unsigned char *)string, sizeof(string)) < 0)
                 {
                     ftdi_usb_close_internal (ftdi);
-                    ftdi_error_return(-9, "unable to fetch serial number");
+                    ftdi_error_return_free_device_list(-9, "unable to fetch serial number", devs);
                 }
                 if (strncmp(string, serial, sizeof(string)) != 0)
                 {
@@ -669,12 +687,14 @@ int ftdi_usb_open_desc_index(struct ftdi_context *ftdi, int vendor, int product,
                     continue;
                 }
 
-            return ftdi_usb_open_dev(ftdi, dev);
+            res = ftdi_usb_open_dev(ftdi, dev);
+            libusb_free_device_list(devs,1);
+            return res;
         }
     }
 
     // device not found
-    ftdi_error_return(-3, "device not found");
+    ftdi_error_return_free_device_list(-3, "device not found", devs);
 }
 
 /**
@@ -719,25 +739,30 @@ int ftdi_usb_open_string(struct ftdi_context *ftdi, const char* description)
        unsigned int bus_number, device_address;
        int i = 0;
 
-        if (libusb_init (NULL) < 0)
+        if (libusb_init (&ftdi->usb_ctx) < 0)
            ftdi_error_return(-1, "libusb_init() failed");
 
-       if (libusb_get_device_list(NULL, &devs) < 0)
+       if (libusb_get_device_list(ftdi->usb_ctx, &devs) < 0)
            ftdi_error_return(-2, "libusb_get_device_list() failed");
 
         /* XXX: This doesn't handle symlinks/odd paths/etc... */
         if (sscanf (description + 2, "%u/%u", &bus_number, &device_address) != 2)
-           ftdi_error_return(-11, "illegal description format");
+           ftdi_error_return_free_device_list(-11, "illegal description format", devs);
 
        while ((dev = devs[i++]) != NULL)
         {
+            int ret;
            if (bus_number == libusb_get_bus_number (dev)
                && device_address == libusb_get_device_address (dev))
-                return ftdi_usb_open_dev(ftdi, dev);
+            {
+                ret = ftdi_usb_open_dev(ftdi, dev);
+                libusb_free_device_list(devs,1);
+                return ret;
+            }
         }
 
         // device not found
-        ftdi_error_return(-3, "device not found");
+        ftdi_error_return_free_device_list(-3, "device not found", devs);
     }
     else if (description[0] == 'i' || description[0] == 's')
     {
@@ -1211,10 +1236,6 @@ int ftdi_write_data(struct ftdi_context *ftdi, unsigned char *buf, int size)
     return offset;
 }
 
-#ifdef LIBFTDI_LINUX_ASYNC_MODE
-#ifdef USB_CLASS_PTP
-#error LIBFTDI_LINUX_ASYNC_MODE is not compatible with libusb-compat-0.1!
-#endif
 static void ftdi_read_data_cb(struct libusb_transfer *transfer)
 {
     struct ftdi_transfer_control *tc = (struct ftdi_transfer_control *) transfer->user_data;
@@ -1329,8 +1350,7 @@ static void ftdi_write_data_cb(struct libusb_transfer *transfer)
     Writes data to the chip. Does not wait for completion of the transfer
     nor does it make sure that the transfer was successful.
 
-    Use libusb 1.0 Asynchronous API.
-    Only available if compiled with --with-async-mode.
+    Use libusb 1.0 asynchronous API.
 
     \param ftdi pointer to ftdi_context
     \param buf Buffer with the data
@@ -1388,8 +1408,7 @@ struct ftdi_transfer_control *ftdi_write_data_submit(struct ftdi_context *ftdi,
     Reads data from the chip. Does not wait for completion of the transfer
     nor does it make sure that the transfer was successful.
 
-    Use libusb 1.0 Asynchronous API.
-    Only available if compiled with --with-async-mode.
+    Use libusb 1.0 asynchronous API.
 
     \param ftdi pointer to ftdi_context
     \param buf Buffer with the data
@@ -1470,8 +1489,7 @@ struct ftdi_transfer_control *ftdi_read_data_submit(struct ftdi_context *ftdi, u
 /**
     Wait for completion of the transfer.
 
-    Use libusb 1.0 Asynchronous API.
-    Only available if compiled with --with-async-mode.
+    Use libusb 1.0 asynchronous API.
 
     \param tc pointer to ftdi_transfer_control
 
@@ -1485,14 +1503,14 @@ int ftdi_transfer_data_done(struct ftdi_transfer_control *tc)
 
     while (!tc->completed)
     {
-        ret = libusb_handle_events(NULL);
+        ret = libusb_handle_events(tc->ftdi->usb_ctx);
         if (ret < 0)
         {
             if (ret == LIBUSB_ERROR_INTERRUPTED)
                 continue;
             libusb_cancel_transfer(tc->transfer);
             while (!tc->completed)
-                if (libusb_handle_events(NULL) < 0)
+                if (libusb_handle_events(tc->ftdi->usb_ctx) < 0)
                     break;
             libusb_free_transfer(tc->transfer);
             free (tc);
@@ -1511,8 +1529,6 @@ int ftdi_transfer_data_done(struct ftdi_transfer_control *tc)
     return ret;
 }
 
-#endif // LIBFTDI_LINUX_ASYNC_MODE
-
 /**
     Configure write buffer chunk size.
     Default is 4096.
@@ -2181,6 +2197,27 @@ void ftdi_eeprom_initdefaults(struct ftdi_eeprom *eeprom)
 }
 
 /**
+    Frees allocated memory in eeprom.
+
+    \param eeprom Pointer to ftdi_eeprom
+*/
+void ftdi_eeprom_free(struct ftdi_eeprom *eeprom)
+{
+    if (eeprom->manufacturer != 0) {
+        free(eeprom->manufacturer);
+        eeprom->manufacturer = 0;
+    }
+    if (eeprom->product != 0) {
+        free(eeprom->product);
+        eeprom->product = 0;
+    }
+    if (eeprom->serial != 0) {
+        free(eeprom->serial);
+        eeprom->serial = 0;
+    }
+}
+
+/**
     Build binary output from ftdi_eeprom structure.
     Output is suitable for ftdi_write_eeprom().