FT232H has even more config bytes and less user_area
[libftdi] / src / ftdi.c
index 7aa0417..142d37f 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");
 
@@ -1076,7 +1075,7 @@ static int ftdi_convert_baudrate(int baudrate, struct ftdi_context *ftdi,
     }
     // Split into "value" and "index" values
     *value = (unsigned short)(encoded_divisor & 0xFFFF);
-    if (ftdi->type == TYPE_2232C || ftdi->type == TYPE_2232H || ftdi->type == TYPE_4232H)
+    if (ftdi->type == TYPE_2232C || ftdi->type == TYPE_2232H || ftdi->type == TYPE_4232H || ftdi->type == TYPE_232H )
     {
         *index = (unsigned short)(encoded_divisor >> 8);
         *index &= 0xFF00;
@@ -2354,6 +2353,9 @@ int ftdi_eeprom_build(struct ftdi_context *ftdi)
         case TYPE_4232H:
             user_area_size = 86;
             break;
+        case TYPE_232H:
+            user_area_size = 80;
+            break;
         default:
             user_area_size = 0;
             break;
@@ -2537,7 +2539,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 +2550,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 +2621,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 +2686,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 +2750,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 +2925,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 +2960,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 +3010,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);
@@ -3166,6 +3184,9 @@ int ftdi_get_eeprom_value(struct ftdi_context *ftdi, enum ftdi_eeprom_value valu
         case IN_IS_ISOCHRONOUS:
             *value = ftdi->eeprom->in_is_isochronous;
             break;
+        case OUT_IS_ISOCHRONOUS:
+            *value = ftdi->eeprom->out_is_isochronous;
+            break;
         case SUSPEND_PULL_DOWNS:
             *value = ftdi->eeprom->suspend_pull_downs;
             break;
@@ -3175,6 +3196,9 @@ int ftdi_get_eeprom_value(struct ftdi_context *ftdi, enum ftdi_eeprom_value valu
         case USB_VERSION:
             *value = ftdi->eeprom->usb_version;
             break;
+        case USE_USB_VERSION:
+            *value = ftdi->eeprom->use_usb_version;
+            break;
         case MAX_POWER:
             *value = ftdi->eeprom->max_power;
             break;
@@ -3329,6 +3353,9 @@ int ftdi_set_eeprom_value(struct ftdi_context *ftdi, enum ftdi_eeprom_value valu
         case IN_IS_ISOCHRONOUS:
             ftdi->eeprom->in_is_isochronous = value;
             break;
+        case OUT_IS_ISOCHRONOUS:
+            ftdi->eeprom->out_is_isochronous = value;
+            break;
         case SUSPEND_PULL_DOWNS:
             ftdi->eeprom->suspend_pull_downs = value;
             break;
@@ -3338,6 +3365,9 @@ int ftdi_set_eeprom_value(struct ftdi_context *ftdi, enum ftdi_eeprom_value valu
         case USB_VERSION:
             ftdi->eeprom->usb_version = value;
             break;
+        case USE_USB_VERSION:
+            ftdi->eeprom->use_usb_version = value;
+            break;
         case MAX_POWER:
             ftdi->eeprom->max_power = value;
             break;
@@ -3481,6 +3511,29 @@ int ftdi_get_eeprom_buf(struct ftdi_context *ftdi, unsigned char * buf, int size
     return 0;
 }
 
+/** Set the EEPROM content from the user-supplied prefilled buffer
+
+    \param ftdi pointer to ftdi_context
+    \param buf buffer to read EEPROM content
+    \param size Size of buffer
+
+    \retval 0: All fine
+    \retval -1: struct ftdi_contxt or ftdi_eeprom of buf missing
+*/
+int ftdi_set_eeprom_buf(struct ftdi_context *ftdi, const unsigned char * buf, int size)
+{
+    if (!ftdi || !(ftdi->eeprom) || !buf)
+        ftdi_error_return(-1, "No appropriate structure");
+
+    // Only copy up to FTDI_MAX_EEPROM_SIZE bytes
+    if (size > FTDI_MAX_EEPROM_SIZE)
+        size = FTDI_MAX_EEPROM_SIZE;
+
+    memcpy(ftdi->eeprom->buf, buf, size);
+
+    return 0;
+}
+
 /**
     Read eeprom location