Decode/encode use_usb_version on BM and 2232C
[libftdi] / src / ftdi.c
index 2d10e72..5800f26 100644 (file)
@@ -2307,8 +2307,26 @@ int ftdi_eeprom_build(struct ftdi_context *ftdi)
     if (eeprom->serial != NULL)
         serial_size = strlen(eeprom->serial);
 
-    // eeprom size exceeded?
-    user_area_size = (48 - (manufacturer_size + product_size + serial_size)) * 2;
+    // eeprom size check
+    switch (ftdi->type)
+    {
+        case TYPE_AM:
+        case TYPE_BM:
+            user_area_size = 96;    // base size for strings (total of 48 characters)
+            break;
+        case TYPE_2232C:
+           user_area_size = 90;     // two extra config bytes and 4 bytes PnP stuff
+           break;
+        case TYPE_R:
+           user_area_size = 88;     // four extra config bytes + 4 bytes PnP stuff
+           break;
+        case TYPE_2232H:            // six extra config bytes + 4 bytes PnP stuff
+        case TYPE_4232H:
+           user_area_size = 86;
+           break;
+    }
+    user_area_size  -= (manufacturer_size + product_size + serial_size) * 2;
+
     if (user_area_size < 0)
         ftdi_error_return(-1,"eeprom size exceeded");
 
@@ -2327,7 +2345,8 @@ int ftdi_eeprom_build(struct ftdi_context *ftdi)
 
     // Addr 06: Device release number (0400h for BM features)
     output[0x06] = 0x00;
-    switch (ftdi->type) {
+    switch (ftdi->type)
+    {
         case TYPE_AM:
             output[0x07] = 0x02;
             break;
@@ -2440,24 +2459,27 @@ int ftdi_eeprom_build(struct ftdi_context *ftdi)
         output[i & eeprom_size_mask] = eeprom->serial[j], i++;
         output[i & eeprom_size_mask] = 0x00, i++;
     }
-    output[i & eeprom_size_mask] = 0x02; /* as seen when written with FTD2XX */
-    i++;
-    output[i & eeprom_size_mask] = 0x03; /* as seen when written with FTD2XX */
-    i++;
-    output[i & eeprom_size_mask] = eeprom->is_not_pnp; /* as seen when written with FTD2XX */
-    i++;
+
+    // Legacy port name and PnP fields for FT2232 and newer chips
+    if (ftdi->type > TYPE_BM)
+    {
+        output[i & eeprom_size_mask] = 0x02; /* as seen when written with FTD2XX */
+        i++;
+        output[i & eeprom_size_mask] = 0x03; /* as seen when written with FTD2XX */
+        i++;
+        output[i & eeprom_size_mask] = eeprom->is_not_pnp; /* as seen when written with FTD2XX */
+        i++;
+    }
 
     output[0x13] = serial_size*2 + 2;
 
-    if(ftdi->type > TYPE_AM) /*use_serial not used in AM devices*/
+    if(ftdi->type > TYPE_AM) /* use_serial not used in AM devices */
     {
         if (eeprom->use_serial == USE_SERIAL_NUM )
             output[0x0A] |= USE_SERIAL_NUM;
         else
             output[0x0A] &= ~USE_SERIAL_NUM;
     }
-    /* Fixme: ftd2xx seems to append 0x02, 0x03 and 0x01 for PnP = 0 or 0x00 else */
-    // calculate checksum
 
     /* Bytes and Bits specific to (some) types
        Write linear, as this allows easier fixing*/
@@ -2468,6 +2490,11 @@ int ftdi_eeprom_build(struct ftdi_context *ftdi)
     case TYPE_BM:
         output[0x0C] = eeprom->usb_version & 0xff;
         output[0x0D] = (eeprom->usb_version>>8) & 0xff;
+        if (eeprom->use_usb_version == USE_USB_VERSION_BIT)
+            output[0x0A] |= USE_USB_VERSION_BIT;
+        else
+            output[0x0A] &= ~USE_USB_VERSION_BIT;
+
         break;
     case TYPE_2232C:
 
@@ -2505,6 +2532,11 @@ int ftdi_eeprom_build(struct ftdi_context *ftdi)
             output[0x0A] |= 0x4;
         else
             output[0x0A] &= ~0x4;
+        if (eeprom->use_usb_version == USE_USB_VERSION_BIT)
+            output[0x0A] |= USE_USB_VERSION_BIT;
+        else
+            output[0x0A] &= ~USE_USB_VERSION_BIT;
+
         output[0x0C] = eeprom->usb_version & 0xff;
         output[0x0D] = (eeprom->usb_version>>8) & 0xff;
         output[0x14] = eeprom->chip;
@@ -2559,10 +2591,10 @@ int ftdi_eeprom_build(struct ftdi_context *ftdi)
             output[0x01] |= DRIVER_VCP;
         else
             output[0x01] &= ~DRIVER_VCP;
-        if(eeprom->suspend_dbus7 == SUSPEND_DBUS7)
-            output[0x01] |= SUSPEND_DBUS7;
+        if(eeprom->suspend_dbus7 == SUSPEND_DBUS7_BIT)
+            output[0x01] |= SUSPEND_DBUS7_BIT;
         else
-            output[0x01] &= ~SUSPEND_DBUS7;
+            output[0x01] &= ~SUSPEND_DBUS7_BIT;
 
         if (eeprom->suspend_pull_downs == 1)
             output[0x0A] |= 0x4;
@@ -2673,7 +2705,7 @@ int ftdi_eeprom_decode(struct ftdi_context *ftdi, int verbose)
     // Bit 6: 1 if this device is self powered, 0 if bus powered
     // Bit 5: 1 if this device uses remote wakeup
     eeprom->self_powered = buf[0x08] & 0x40;
-    eeprom->remote_wakeup = buf[0x08] & 0x20;;
+    eeprom->remote_wakeup = buf[0x08] & 0x20;
 
     // Addr 09: Max power consumption: max power = value * 2 mA
     eeprom->max_power = buf[0x09];
@@ -2682,8 +2714,7 @@ int ftdi_eeprom_decode(struct ftdi_context *ftdi, int verbose)
     // Bit 7: 0 - reserved
     // Bit 6: 0 - reserved
     // Bit 5: 0 - reserved
-    // Bit 4: 1 - Change USB version
-    //            Not seen on FT2232(D)
+    // Bit 4: 1 - Change USB version on BM and 2232C
     // Bit 3: 1 - Use the serial number string
     // Bit 2: 1 - Enable suspend pull downs for lower power
     // Bit 1: 1 - Out EndPoint is Isochronous
@@ -2693,11 +2724,7 @@ int ftdi_eeprom_decode(struct ftdi_context *ftdi, int verbose)
     eeprom->out_is_isochronous = buf[0x0A]&0x02;
     eeprom->suspend_pull_downs = buf[0x0A]&0x04;
     eeprom->use_serial         = buf[0x0A] & USE_SERIAL_NUM;
-    if(buf[0x0A]&0x10)
-        fprintf(stderr,
-                "EEPROM byte[0x0a] Bit 4 unexpected set. If this happened with the EEPROM\n"
-                "programmed by FTDI tools, please report to libftdi@developer.intra2net.com\n");
-
+    eeprom->use_usb_version    = buf[0x0A] & USE_USB_VERSION_BIT;
 
     // Addr 0C: USB version low byte when 0x0A
     // Addr 0D: USB version high byte when 0x0A 
@@ -2834,7 +2861,7 @@ int ftdi_eeprom_decode(struct ftdi_context *ftdi, int verbose)
         eeprom->channel_b_driver = buf[0x01] & DRIVER_VCP;
 
         if(ftdi->type == TYPE_2232H)
-            eeprom->suspend_dbus7    = buf[0x01] & SUSPEND_DBUS7;
+            eeprom->suspend_dbus7    = buf[0x01] & SUSPEND_DBUS7_BIT;
 
         eeprom->chip = buf[0x18];
         eeprom->group0_drive   =  buf[0x0c]       & DRIVE_16MA;
@@ -2891,6 +2918,10 @@ int ftdi_eeprom_decode(struct ftdi_context *ftdi, int verbose)
                     channel_mode[eeprom->channel_b_type],
                     (eeprom->channel_b_driver)?" VCP":"",
                     (eeprom->high_current_b)?" High Current IO":"");
+        if (((ftdi->type == TYPE_BM) || (ftdi->type == TYPE_2232C)) &&
+            eeprom->use_usb_version == USE_USB_VERSION_BIT)
+            fprintf(stdout,"Use explicit USB Version %04x\n",eeprom->usb_version);
+
         if ((ftdi->type == TYPE_2232H) || (ftdi->type == TYPE_4232H)) 
         {
             fprintf(stdout,"%s has %d mA drive%s%s\n",