ftdi_usb_find_all: Only search for default devices if both VID AND PID are 0
[libftdi] / src / ftdi.c
index 7aa0417..852b3ff 100644 (file)
@@ -257,8 +257,10 @@ void ftdi_set_usbdev (struct ftdi_context *ftdi, libusb_device_handle *usb)
 
 
 /**
-    Finds all ftdi devices on the usb bus. Creates a new ftdi_device_list which
-    needs to be deallocated by ftdi_list_free() after use.
+    Finds all ftdi devices with given VID:PID on the usb bus. Creates a new
+    ftdi_device_list which needs to be deallocated by ftdi_list_free() after
+    use.  With VID:PID 0:0, search for the default devices
+    (0x403:0x6001, 0x403:0x6010, 0x403:0x6011, 0x403:0x6014) 
 
     \param ftdi pointer to ftdi_context
     \param devlist Pointer where to store list of found devices
@@ -291,7 +293,11 @@ int ftdi_usb_find_all(struct ftdi_context *ftdi, struct ftdi_device_list **devli
         if (libusb_get_device_descriptor(dev, &desc) < 0)
             ftdi_error_return_free_device_list(-6, "libusb_get_device_descriptor() failed", devs);
 
-        if (desc.idVendor == vendor && desc.idProduct == product)
+        if (((vendor != 0 && product != 0) && 
+             desc.idVendor == vendor && desc.idProduct == product) ||
+            ((vendor == 0 && product == 0) && 
+             (desc.idVendor == 0x403) && (desc.idProduct == 0x6001 || desc.idProduct == 0x6010
+                                          || desc.idProduct == 0x6011 || desc.idProduct == 0x6014)))
         {
             *curdev = (struct ftdi_device_list*)malloc(sizeof(struct ftdi_device_list));
             if (!*curdev)
@@ -299,7 +305,7 @@ int ftdi_usb_find_all(struct ftdi_context *ftdi, struct ftdi_device_list **devli
 
             (*curdev)->next = NULL;
             (*curdev)->dev = dev;
-
+            libusb_ref_device(dev);
             curdev = &(*curdev)->next;
             count++;
         }
@@ -320,6 +326,7 @@ void ftdi_list_free(struct ftdi_device_list **devlist)
     for (curdev = *devlist; curdev != NULL;)
     {
         next = curdev->next;
+        libusb_unref_device(curdev->dev);
         free(curdev);
         curdev = next;
     }
@@ -611,7 +618,6 @@ int ftdi_usb_open(struct ftdi_context *ftdi, int vendor, int product)
     \retval -7: set baudrate failed
     \retval -8: get product description failed
     \retval -9: get serial number failed
-    \retval -11: libusb_init() failed
     \retval -12: libusb_get_device_list() failed
     \retval -13: libusb_get_device_descriptor() failed
 */
@@ -656,9 +662,6 @@ int ftdi_usb_open_desc_index(struct ftdi_context *ftdi, int vendor, int product,
     if (ftdi == NULL)
         ftdi_error_return(-11, "ftdi context invalid");
 
-    if (libusb_init(&ftdi->usb_ctx) < 0)
-        ftdi_error_return(-11, "libusb_init() failed");
-
     if (libusb_get_device_list(ftdi->usb_ctx, &devs) < 0)
         ftdi_error_return(-12, "libusb_get_device_list() failed");
 
@@ -734,7 +737,6 @@ int ftdi_usb_open_desc_index(struct ftdi_context *ftdi, int vendor, int product,
     \note The description format may be extended in later versions.
 
     \retval  0: all fine
-    \retval -1: libusb_init() failed
     \retval -2: libusb_get_device_list() failed
     \retval -3: usb device not found
     \retval -4: unable to open device
@@ -762,9 +764,6 @@ int ftdi_usb_open_string(struct ftdi_context *ftdi, const char* description)
         unsigned int bus_number, device_address;
         int i = 0;
 
-        if (libusb_init (&ftdi->usb_ctx) < 0)
-            ftdi_error_return(-1, "libusb_init() failed");
-
         if (libusb_get_device_list(ftdi->usb_ctx, &devs) < 0)
             ftdi_error_return(-2, "libusb_get_device_list() failed");
 
@@ -2537,7 +2536,7 @@ int ftdi_eeprom_build(struct ftdi_context *ftdi)
             break;
         case TYPE_2232C:
 
-            output[0x00] = (eeprom->channel_a_type);
+            output[0x00] = (eeprom->channel_a_type)?((1<<(eeprom->channel_a_type)) & 0x7):0;
             if ( eeprom->channel_a_driver == DRIVER_VCP)
                 output[0x00] |= DRIVER_VCP;
             else
@@ -2548,7 +2547,7 @@ int ftdi_eeprom_build(struct ftdi_context *ftdi)
             else
                 output[0x00] &= ~HIGH_CURRENT_DRIVE;
 
-            output[0x01] = (eeprom->channel_b_type);
+            output[0x01] = (eeprom->channel_b_type)?((1<<(eeprom->channel_b_type)) & 0x7):0;
             if ( eeprom->channel_b_driver == DRIVER_VCP)
                 output[0x01] |= DRIVER_VCP;
             else
@@ -2619,13 +2618,13 @@ int ftdi_eeprom_build(struct ftdi_context *ftdi)
                 output[0x16] = eeprom->cbus_function[4];
             break;
         case TYPE_2232H:
-            output[0x00] = (eeprom->channel_a_type);
+            output[0x00] = (eeprom->channel_a_type)?((1<<(eeprom->channel_a_type)) & 0x7):0;
             if ( eeprom->channel_a_driver == DRIVER_VCP)
                 output[0x00] |= DRIVER_VCP;
             else
                 output[0x00] &= ~DRIVER_VCP;
 
-            output[0x01] = (eeprom->channel_b_type);
+            output[0x01] = (eeprom->channel_b_type)?((1<<(eeprom->channel_b_type)) & 0x7):0;
             if ( eeprom->channel_b_driver == DRIVER_VCP)
                 output[0x01] |= DRIVER_VCP;
             else
@@ -2684,7 +2683,7 @@ int ftdi_eeprom_build(struct ftdi_context *ftdi)
             fprintf(stderr,"FIXME: Build FT4232H specific EEPROM settings\n");
             break;
         case TYPE_232H:
-            output[0x00] = (eeprom->channel_a_type);
+            output[0x00] = (eeprom->channel_a_type)?((1<<(eeprom->channel_a_type)) & 0xf):0;
             if ( eeprom->channel_a_driver == DRIVER_VCP)
                 output[0x00] |= DRIVER_VCPH;
             else
@@ -2748,6 +2747,22 @@ int ftdi_eeprom_build(struct ftdi_context *ftdi)
 
     return user_area_size;
 }
+/* FTD2XX doesn't allow to set multiple bits in the interface mode bitfield*/
+unsigned char bit2type(unsigned char bits)
+{
+    switch (bits)
+    {
+    case 0: return 0;
+    case 1: return 1;
+    case 2: return 2;
+    case 4: return 3;
+    case 8: return 4;
+    default:
+        fprintf(stderr," Unexpected value %d for Hardware Interface type\n",
+                bits);
+    }
+    return 0;
+}
 
 /**
    Decode binary EEPROM image into an ftdi_eeprom structure.
@@ -2907,7 +2922,7 @@ int ftdi_eeprom_decode(struct ftdi_context *ftdi, int verbose)
     }
     else if (ftdi->type == TYPE_2232C)
     {
-        eeprom->channel_a_type   = buf[0x00] & 0x7;
+        eeprom->channel_a_type   = bit2type(buf[0x00] & 0x7);
         eeprom->channel_a_driver = buf[0x00] & DRIVER_VCP;
         eeprom->high_current_a   = buf[0x00] & HIGH_CURRENT_DRIVE;
         eeprom->channel_b_type   = buf[0x01] & 0x7;
@@ -2942,7 +2957,7 @@ int ftdi_eeprom_decode(struct ftdi_context *ftdi, int verbose)
     }
     else if ((ftdi->type == TYPE_2232H) ||(ftdi->type == TYPE_4232H))
     {
-        eeprom->channel_a_type   = buf[0x00] & 0x7;
+        eeprom->channel_a_type   = bit2type(buf[0x00] & 0x7);
         eeprom->channel_a_driver = buf[0x00] & DRIVER_VCP;
         eeprom->channel_b_type   = buf[0x01] & 0x7;
         eeprom->channel_b_driver = buf[0x01] & DRIVER_VCP;
@@ -2992,7 +3007,7 @@ int ftdi_eeprom_decode(struct ftdi_context *ftdi, int verbose)
 
     if (verbose)
     {
-        char *channel_mode[] = {"UART","245","CPU", "unknown", "OPTO", "unknown1","unknown2","unknown3","FT1284"};
+        char *channel_mode[] = {"UART","245","CPU", "OPTO", "FT1284"};
         fprintf(stdout, "VID:     0x%04x\n",eeprom->vendor_id);
         fprintf(stdout, "PID:     0x%04x\n",eeprom->product_id);
         fprintf(stdout, "Release: 0x%04x\n",release);