Release values in EEPROM structure are not user changable. Remove it from the ftdi_ee...
[libftdi] / src / ftdi.c
index 7ae48cb..297fa28 100644 (file)
@@ -2257,7 +2257,7 @@ void ftdi_eeprom_free(struct ftdi_context *ftdi)
 */
 int ftdi_eeprom_build(struct ftdi_context *ftdi, unsigned char *output)
 {
-    unsigned char i, j;
+    unsigned char i, j, k;
     unsigned short checksum, value;
     unsigned char manufacturer_size = 0, product_size = 0, serial_size = 0;
     int size_check;
@@ -2273,6 +2273,11 @@ int ftdi_eeprom_build(struct ftdi_context *ftdi, unsigned char *output)
     if(eeprom->chip == -1)
         ftdi_error_return(-5,"No connected EEPROM or EEPROM Type unknown");
 
+    if ((eeprom->chip == 0x56) || (eeprom->chip == 0x66))
+        eeprom->size = 0x100;
+    else
+        eeprom->size = 0x80;
+
     if (eeprom->manufacturer != NULL)
         manufacturer_size = strlen(eeprom->manufacturer);
     if (eeprom->product != NULL)
@@ -2309,12 +2314,8 @@ int ftdi_eeprom_build(struct ftdi_context *ftdi, unsigned char *output)
     // empty eeprom
     memset (output, 0, eeprom->size);
 
-    // Addr 00: High current IO
-    output[0x00] = eeprom->high_current_a ? HIGH_CURRENT_DRIVE : 0;
-    // Addr 01: IN endpoint size (for R type devices, different for FT2232)
-    if (ftdi->type == TYPE_R) {
-        output[0x01] = 0x40;
-    }
+    // Bytes and Bits set for all Types
+
     // Addr 02: Vendor ID
     output[0x02] = eeprom->vendor_id;
     output[0x03] = eeprom->vendor_id >> 8;
@@ -2363,96 +2364,243 @@ int ftdi_eeprom_build(struct ftdi_context *ftdi, unsigned char *output)
     // Addr 09: Max power consumption: max power = value * 2 mA
     output[0x09] = eeprom->max_power;
 
-    // Addr 0A: Chip configuration
-    // Bit 7: 0 - reserved
-    // Bit 6: 0 - reserved
-    // Bit 5: 0 - reserved
-    // Bit 4: 1 - Change USB version 
-    //            not seen on FT2232C)
-    // 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
-    // Bit 0: 1 - In EndPoint is Isochronous
-    //
-    j = 0;
-    if (eeprom->in_is_isochronous == 1)
-        j = j | 1;
-    if (eeprom->out_is_isochronous == 1)
-        j = j | 2;
-    if (eeprom->suspend_pull_downs == 1)
-        j = j | 4;
-    if (eeprom->use_serial == 1)
-        j = j | 8;
-    output[0x0A] = j;
-
-    // Addr 0B: Invert data lines
-    output[0x0B] = eeprom->invert & 0xff;
-
-    // Addr 0C: USB version low byte
-    // Addr 0D: USB version high byte
-    output[0x0C] = eeprom->usb_version;
-    output[0x0D] = eeprom->usb_version >> 8;
+    if(ftdi->type != TYPE_AM)
+    {
+        // Addr 0A: Chip configuration
+        // Bit 7: 0 - reserved
+        // Bit 6: 0 - reserved
+        // Bit 5: 0 - reserved
+        // Bit 4: 1 - Change USB version 
+        // 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
+        // Bit 0: 1 - In EndPoint is Isochronous
+        //
+        j = 0;
+        if (eeprom->in_is_isochronous == 1)
+            j = j | 1;
+        if (eeprom->out_is_isochronous == 1)
+            j = j | 2;
+        output[0x0A] = j;
+    }
 
+    // Dynamic content
+    // Strings start at 0x94 (TYPE_AM, TYPE_BM)
+    // 0x96 (TYPE_2232C), 0x98 (TYPE_R) and 0x9a (TYPE_x232H)
+    i = 0;
+    switch(ftdi->type)
+    {
+    case TYPE_2232H:
+    case TYPE_4232H:
+        i += 2;
+    case TYPE_R:
+        i += 2;
+    case TYPE_2232C:
+        i += 2;
+    case TYPE_AM:
+    case TYPE_BM:
+        i += 0x94;
+    }
+    /* Wrap around 0x80 for 128 byte EEPROMS (Internale and 93x46) */
+    k = eeprom->size -1;
 
     // Addr 0E: Offset of the manufacturer string + 0x80, calculated later
     // Addr 0F: Length of manufacturer string
+    // Output manufacturer
+    output[0x0E] = i;  // calculate offset
+    output[i++ & k] = manufacturer_size*2 + 2;
+    output[i++ & k] = 0x03; // type: string
+    for (j = 0; j < manufacturer_size; j++)
+    {
+        output[i & k] = eeprom->manufacturer[j], i++;
+        output[i & k] = 0x00, i++;
+    }
     output[0x0F] = manufacturer_size*2 + 2;
 
     // Addr 10: Offset of the product string + 0x80, calculated later
     // Addr 11: Length of product string
+    output[0x10] = i | 0x80;  // calculate offset
+    output[i & k] = product_size*2 + 2, i++;
+    output[i & k] = 0x03, i++;
+    for (j = 0; j < product_size; j++)
+    {
+        output[i & k] = eeprom->product[j], i++;
+        output[i & k] = 0x00, i++;
+    }
     output[0x11] = product_size*2 + 2;
-
+    
     // Addr 12: Offset of the serial string + 0x80, calculated later
     // Addr 13: Length of serial string
+    output[0x12] = i | 0x80; // calculate offset
+    output[i & k] = serial_size*2 + 2, i++;
+    output[i & k] = 0x03, i++;
+    for (j = 0; j < serial_size; j++)
+    {
+        output[i & k] = eeprom->serial[j], i++;
+        output[i & k] = 0x00, i++;
+    }
     output[0x13] = serial_size*2 + 2;
 
-    // Addr 14: CBUS function: CBUS0, CBUS1
-    // Addr 15: CBUS function: CBUS2, CBUS3
-    // Addr 16: CBUS function: CBUS5
-    output[0x14] = eeprom->cbus_function[0] | (eeprom->cbus_function[1] << 4);
-    output[0x15] = eeprom->cbus_function[2] | (eeprom->cbus_function[3] << 4);
-    output[0x16] = eeprom->cbus_function[4];
-    // Addr 17: Unknown
+    /* Fixme: ftd2xx seems to append 0x02, 0x03 and 0x01 for PnP = 0 or 0x00 else */
+    // calculate checksum
 
-    // Dynamic content
-    // In images produced by FTDI's FT_Prog for FT232R strings start at 0x18
-    // Space till 0x18 should be considered as reserved.
-    if (ftdi->type >= TYPE_R) {
-        i = 0x18;
-    } else {
-        i = 0x14;
-    }
-    if (eeprom->size >= 256) i = 0x80;
+    /* Bytes and Bits specific to (some) types
+       Write linear, as this allows easier fixing*/
+    switch(ftdi->type)
+    {
+    case TYPE_AM:
+        break;
+    case TYPE_BM:
+        output[0x0C] = eeprom->usb_version & 0xff;
+        output[0x0D] = (eeprom->usb_version>>8) & 0xff;
+        if (eeprom->use_serial == 1)
+            output[0x0A] |= 0x8;
+        else
+            output[0x0A] &= ~0x8;
+        output[0x14] = eeprom->chip;
+        break;
+    case TYPE_2232C:
 
+        output[0x00] = (eeprom->channel_a_type);
+        if ( eeprom->channel_a_driver == DRIVER_VCP)
+            output[0x00] |= DRIVER_VCP;
+        else
+            output[0x00] &= ~DRIVER_VCP;
+            
+        if ( eeprom->high_current_a == HIGH_CURRENT_DRIVE)
+            output[0x00] |= HIGH_CURRENT_DRIVE;
+        else
+            output[0x00] &= ~HIGH_CURRENT_DRIVE;
 
-    // Output manufacturer
-    output[0x0E] = i | 0x80;  // calculate offset
-    output[i++] = manufacturer_size*2 + 2;
-    output[i++] = 0x03; // type: string
-    for (j = 0; j < manufacturer_size; j++)
-    {
-        output[i] = eeprom->manufacturer[j], i++;
-        output[i] = 0x00, i++;
-    }
+        output[0x01] = (eeprom->channel_b_type);
+        if ( eeprom->channel_b_driver == DRIVER_VCP)
+            output[0x01] |= DRIVER_VCP;
+        else
+            output[0x01] &= ~DRIVER_VCP;
+            
+        if ( eeprom->high_current_b == HIGH_CURRENT_DRIVE)
+            output[0x01] |= HIGH_CURRENT_DRIVE;
+        else
+            output[0x01] &= ~HIGH_CURRENT_DRIVE;
 
-    // Output product name
-    output[0x10] = i | 0x80;  // calculate offset
-    output[i] = product_size*2 + 2, i++;
-    output[i] = 0x03, i++;
-    for (j = 0; j < product_size; j++)
-    {
-        output[i] = eeprom->product[j], i++;
-        output[i] = 0x00, i++;
-    }
+        if (eeprom->in_is_isochronous == 1)
+            output[0x0A] |= 0x1;
+        else
+            output[0x0A] &= ~0x1;
+        if (eeprom->out_is_isochronous == 1)
+            output[0x0A] |= 0x2;
+        else
+            output[0x0A] &= ~0x2;
+        if (eeprom->suspend_pull_downs == 1)
+            output[0x0A] |= 0x4;
+        else
+            output[0x0A] &= ~0x4;
+        if (eeprom->use_serial == USE_SERIAL_NUM )
+            output[0x0A] |= USE_SERIAL_NUM;
+        else
+            output[0x0A] &= ~0x8;
+        output[0x0C] = eeprom->usb_version & 0xff;
+        output[0x0D] = (eeprom->usb_version>>8) & 0xff;
+        output[0x14] = eeprom->chip;
+        break;
+    case TYPE_R:
+        if(eeprom->high_current == HIGH_CURRENT_DRIVE_R)
+            output[0x00] |= HIGH_CURRENT_DRIVE_R;
+        output[0x01] = 0x40; /* Hard coded Endpoint Size*/
+        
+        if (eeprom->suspend_pull_downs == 1)
+            output[0x0A] |= 0x4;
+        else
+            output[0x0A] &= ~0x4;
+        if (eeprom->use_serial == USE_SERIAL_NUM)
+            output[0x0A] |= USE_SERIAL_NUM;
+        else
+            output[0x0A] &= ~0x8;
+        output[0x0B] = eeprom->invert;
+        output[0x0C] = eeprom->usb_version & 0xff;
+        output[0x0D] = (eeprom->usb_version>>8) & 0xff;
+        
+        if(eeprom->cbus_function[0] > CBUS_BB)
+            output[0x14] = CBUS_BB;
+        else
+            output[0x14] = eeprom->cbus_function[0];
+        
+        if(eeprom->cbus_function[1] > CBUS_BB)
+            output[0x14] |= CBUS_BB<<4;
+        else
+            output[0x14] |= eeprom->cbus_function[1];
+        
+        if(eeprom->cbus_function[2] > CBUS_BB)
+            output[0x15] |= CBUS_BB<<4;
+        else
+            output[0x15] |= eeprom->cbus_function[2];
+        
+        if(eeprom->cbus_function[3] > CBUS_BB)
+            output[0x15] |= CBUS_BB<<4;
+        else
+            output[0x15] |= eeprom->cbus_function[3];
+        
+        if(eeprom->cbus_function[5] > CBUS_BB)
+            output[0x16] = CBUS_BB;
+        else
+            output[0x16] = eeprom->cbus_function[0];
+        break;
+    case TYPE_2232H:
+        output[0x00] = (eeprom->channel_a_type);
+        if ( eeprom->channel_a_driver == DRIVER_VCP)
+            output[0x00] |= DRIVER_VCP;
+        else
+            output[0x00] &= ~DRIVER_VCP;
+        
+        output[0x01] = (eeprom->channel_b_type);
+        if ( eeprom->channel_b_driver == DRIVER_VCP)
+            output[0x01] |= DRIVER_VCP;
+        else
+            output[0x01] &= ~DRIVER_VCP;
+        if(eeprom->suspend_dbus7 == SUSPEND_DBUS7)
+            output[0x01] |= SUSPEND_DBUS7;
+        else
+            output[0x01] &= ~SUSPEND_DBUS7;
+        
+        if(eeprom->group0_drive > DRIVE_16MA)
+            output[0x0c] |= DRIVE_16MA;
+        else
+            output[0x0c] |= eeprom->group0_drive;
+        if (eeprom->group0_schmitt == IS_SCHMITT)
+            output[0x0c] |= IS_SCHMITT;
+        if (eeprom->group0_slew == SLOW_SLEW)
+            output[0x0c] |= SLOW_SLEW;
+
+        if(eeprom->group1_drive > DRIVE_16MA)
+            output[0x0c] |= DRIVE_16MA<<4;
+        else
+            output[0x0c] |= eeprom->group1_drive<<4;
+        if (eeprom->group1_schmitt == IS_SCHMITT)
+            output[0x0c] |= IS_SCHMITT<<4;
+        if (eeprom->group1_slew == SLOW_SLEW)
+            output[0x0c] |= SLOW_SLEW<<4;
+        
+        if(eeprom->group2_drive > DRIVE_16MA)
+            output[0x0d] |= DRIVE_16MA;
+        else
+            output[0x0d] |= eeprom->group2_drive;
+        if (eeprom->group2_schmitt == IS_SCHMITT)
+            output[0x0d] |= IS_SCHMITT;
+        if (eeprom->group2_slew == SLOW_SLEW)
+            output[0x0d] |= SLOW_SLEW;
+
+        if(eeprom->group3_drive > DRIVE_16MA)
+            output[0x0d] |= DRIVE_16MA<<4;
+        else
+            output[0x0d] |= eeprom->group3_drive<<4;
+        if (eeprom->group3_schmitt == IS_SCHMITT)
+            output[0x0d] |= IS_SCHMITT<<4;
+        if (eeprom->group3_slew == SLOW_SLEW)
+            output[0x0d] |= SLOW_SLEW<<4;
 
-    // Output serial
-    output[0x12] = i | 0x80; // calculate offset
-    output[i] = serial_size*2 + 2, i++;
-    output[i] = 0x03, i++;
-    for (j = 0; j < serial_size; j++)
-    {
-        output[i] = eeprom->serial[j], i++;
-        output[i] = 0x00, i++;
+        output[0x18] = eeprom->chip;
+
+        break;
     }
 
     // calculate checksum
@@ -2493,6 +2641,7 @@ int ftdi_eeprom_decode(struct ftdi_context *ftdi, unsigned char *buf, int size,
     unsigned char manufacturer_size = 0, product_size = 0, serial_size = 0;
     int eeprom_size;
     struct ftdi_eeprom *eeprom;
+    int release;
 
     if (ftdi == NULL)
         ftdi_error_return(-1,"No context");
@@ -2510,7 +2659,7 @@ int ftdi_eeprom_decode(struct ftdi_context *ftdi, unsigned char *buf, int size,
     // Addr 04: Product ID
     eeprom->product_id = buf[0x04] + (buf[0x05] << 8);
 
-    eeprom->release = buf[0x06] + (buf[0x07]<<8);
+    release = buf[0x06] + (buf[0x07]<<8);
 
     // Addr 08: Config descriptor
     // Bit 7: always 1
@@ -2695,7 +2844,7 @@ int ftdi_eeprom_decode(struct ftdi_context *ftdi, unsigned char *buf, int size,
         char *channel_mode[] = {"UART","245","CPU", "unknown", "OPTO"};
         fprintf(stdout, "VID:     0x%04x\n",eeprom->vendor_id);
         fprintf(stdout, "PID:     0x%04x\n",eeprom->product_id);
-        fprintf(stdout, "Release: 0x%04x\n",eeprom->release);
+        fprintf(stdout, "Release: 0x%04x\n",release);
 
         if(eeprom->self_powered)
             fprintf(stdout, "Self-Powered%s", (eeprom->remote_wakeup)?", USB Remote Wake Up\n":"\n");