Enumerate all handled EEPROM values Provide ftdi_get|set_eeprom_value to access these...
[libftdi] / src / ftdi.c
index c9492f5..26fd27d 100644 (file)
@@ -105,7 +105,7 @@ int ftdi_init(struct ftdi_context *ftdi)
 
     if (eeprom == 0)
         ftdi_error_return(-2, "Can't malloc struct ftdi_eeprom");
-    memset(eeprom, 0, sizeof(struct ftdi_eeprom);
+    memset(eeprom, 0, sizeof(struct ftdi_eeprom));
     ftdi->eeprom = eeprom;
 
     /* All fine. Now allocate the readbuffer */
@@ -2184,7 +2184,7 @@ int ftdi_set_error_char(struct ftdi_context *ftdi,
     \param manufacturer String to use as Manufacturer
     \param product String to use as Product description
     \param serial String to use as Serial number description
-    
+
     \retval  0: all fine
     \retval -1: No struct ftdi_context
     \retval -2: No struct ftdi_eeprom
@@ -2196,7 +2196,6 @@ int ftdi_eeprom_initdefaults(struct ftdi_context *ftdi, char * manufacturer,
 
     if (ftdi == NULL)
         ftdi_error_return(-1, "No struct ftdi_context");
-        
 
     if (ftdi->eeprom == NULL)
         ftdi_error_return(-2,"No struct ftdi_eeprom"); 
@@ -2268,7 +2267,7 @@ int ftdi_eeprom_initdefaults(struct ftdi_context *ftdi, char * manufacturer,
 
     \param ftdi pointer to ftdi_context
 
-    \retval >0: free eeprom size
+    \retval >=0: size of eeprom user area in bytes
     \retval -1: eeprom size (128 bytes) exceeded by custom strings
     \retval -2: Invalid eeprom pointer
     \retval -3: Invalid cbus function setting
@@ -2278,10 +2277,10 @@ int ftdi_eeprom_initdefaults(struct ftdi_context *ftdi, char * manufacturer,
 */
 int ftdi_eeprom_build(struct ftdi_context *ftdi)
 {
-    unsigned char i, j, k;
+    unsigned char i, j, eeprom_size_mask;
     unsigned short checksum, value;
     unsigned char manufacturer_size = 0, product_size = 0, serial_size = 0;
-    int size_check;
+    int user_area_size;
     struct ftdi_eeprom *eeprom;
     unsigned char * output;
 
@@ -2294,7 +2293,7 @@ int ftdi_eeprom_build(struct ftdi_context *ftdi)
     output = eeprom->buf;
 
     if(eeprom->chip == -1)
-        ftdi_error_return(-5,"No connected EEPROM or EEPROM Type unknown");
+        ftdi_error_return(-5,"No connected EEPROM or EEPROM type unknown");
 
     if ((eeprom->chip == 0x56) || (eeprom->chip == 0x66))
         eeprom->size = 0x100;
@@ -2308,31 +2307,28 @@ int ftdi_eeprom_build(struct ftdi_context *ftdi)
     if (eeprom->serial != NULL)
         serial_size = strlen(eeprom->serial);
 
-    size_check = 0x80;
-    switch(ftdi->type)
+    // eeprom size check
+    switch (ftdi->type)
     {
-    case TYPE_2232H:
-    case TYPE_4232H:
-        size_check -= 4;
-    case TYPE_R:
-        size_check -= 4;
-    case TYPE_2232C:
-        size_check -= 4;
-    case TYPE_AM:
-    case TYPE_BM:
-        size_check -= 0x14*2;
+        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;
 
-    size_check -= manufacturer_size*2;
-    size_check -= product_size*2;
-    size_check -= serial_size*2;
-
-    /* Space for the string type and pointer bytes */
-    size_check -= -9;
-
-    // eeprom size exceeded?
-    if (size_check < 0)
-        return (-1);
+    if (user_area_size < 0)
+        ftdi_error_return(-1,"eeprom size exceeded");
 
     // empty eeprom
     memset (ftdi->eeprom->buf, 0, FTDI_MAX_EEPROM_SIZE);
@@ -2349,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;
@@ -2376,7 +2373,7 @@ int ftdi_eeprom_build(struct ftdi_context *ftdi)
     // Bit 7: always 1
     // Bit 6: 1 if this device is self powered, 0 if bus powered
     // Bit 5: 1 if this device uses remote wakeup
-    // Bit 4: 1 if this device is battery powered
+    // Bit 4-0: reserved - 0
     j = 0x80;
     if (eeprom->self_powered == 1)
         j |= 0x40;
@@ -2425,61 +2422,64 @@ int ftdi_eeprom_build(struct ftdi_context *ftdi)
         i += 0x94;
     }
     /* Wrap around 0x80 for 128 byte EEPROMS (Internale and 93x46) */
-    k = eeprom->size -1;
+    eeprom_size_mask = 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
+    output[i & eeprom_size_mask] = manufacturer_size*2 + 2, i++;
+    output[i & eeprom_size_mask] = 0x03, i++; // type: string
     for (j = 0; j < manufacturer_size; j++)
     {
-        output[i & k] = eeprom->manufacturer[j], i++;
-        output[i & k] = 0x00, i++;
+        output[i & eeprom_size_mask] = eeprom->manufacturer[j], i++;
+        output[i & eeprom_size_mask] = 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++;
+    output[i & eeprom_size_mask] = product_size*2 + 2, i++;
+    output[i & eeprom_size_mask] = 0x03, i++;
     for (j = 0; j < product_size; j++)
     {
-        output[i & k] = eeprom->product[j], i++;
-        output[i & k] = 0x00, i++;
+        output[i & eeprom_size_mask] = eeprom->product[j], i++;
+        output[i & eeprom_size_mask] = 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++;
+    output[i & eeprom_size_mask] = serial_size*2 + 2, i++;
+    output[i & eeprom_size_mask] = 0x03, i++;
     for (j = 0; j < serial_size; j++)
     {
-        output[i & k] = eeprom->serial[j], i++;
-        output[i & k] = 0x00, i++;
+        output[i & eeprom_size_mask] = eeprom->serial[j], i++;
+        output[i & eeprom_size_mask] = 0x00, 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[i & k] = 0x02; /* as seen when written with FTD2XX */
-    i++;
-    output[i & k] = 0x03; /* as seen when written with FTD2XX */
-    i++;
-    output[i & k] = 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*/
@@ -2490,7 +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;
-        output[0x14] = eeprom->chip;
+        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:
 
@@ -2499,7 +2503,7 @@ int ftdi_eeprom_build(struct ftdi_context *ftdi)
             output[0x00] |= DRIVER_VCP;
         else
             output[0x00] &= ~DRIVER_VCP;
-            
+
         if ( eeprom->high_current_a == HIGH_CURRENT_DRIVE)
             output[0x00] |= HIGH_CURRENT_DRIVE;
         else
@@ -2510,7 +2514,7 @@ int ftdi_eeprom_build(struct ftdi_context *ftdi)
             output[0x01] |= DRIVER_VCP;
         else
             output[0x01] &= ~DRIVER_VCP;
-            
+
         if ( eeprom->high_current_b == HIGH_CURRENT_DRIVE)
             output[0x01] |= HIGH_CURRENT_DRIVE;
         else
@@ -2528,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;
@@ -2536,7 +2545,7 @@ int ftdi_eeprom_build(struct ftdi_context *ftdi)
         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
@@ -2544,27 +2553,27 @@ int ftdi_eeprom_build(struct ftdi_context *ftdi)
         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_TXLED;
         else
             output[0x14] = eeprom->cbus_function[0];
-        
+
         if(eeprom->cbus_function[1] > CBUS_BB)
             output[0x14] |= CBUS_RXLED<<4;
         else
             output[0x14] |= eeprom->cbus_function[1]<<4;
-        
+
         if(eeprom->cbus_function[2] > CBUS_BB)
             output[0x15] = CBUS_TXDEN;
         else
             output[0x15] = eeprom->cbus_function[2];
-        
+
         if(eeprom->cbus_function[3] > CBUS_BB)
             output[0x15] |= CBUS_PWREN<<4;
         else
             output[0x15] |= eeprom->cbus_function[3]<<4;
-        
+
         if(eeprom->cbus_function[4] > CBUS_CLK6)
             output[0x16] = CBUS_SLEEP;
         else
@@ -2576,17 +2585,17 @@ int ftdi_eeprom_build(struct ftdi_context *ftdi)
             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;
+        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;
         else
@@ -2609,7 +2618,7 @@ int ftdi_eeprom_build(struct ftdi_context *ftdi)
             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
@@ -2631,6 +2640,8 @@ int ftdi_eeprom_build(struct ftdi_context *ftdi)
         output[0x18] = eeprom->chip;
 
         break;
+    case TYPE_4232H:
+        fprintf(stderr,"FIXME: Build FT4232H specific EEPROM settings\n");
     }
 
     // calculate checksum
@@ -2648,7 +2659,7 @@ int ftdi_eeprom_build(struct ftdi_context *ftdi)
     output[eeprom->size-2] = checksum;
     output[eeprom->size-1] = checksum >> 8;
 
-    return size_check;
+    return user_area_size;
 }
 
 /**
@@ -2693,9 +2704,8 @@ int ftdi_eeprom_decode(struct ftdi_context *ftdi, int verbose)
     // Bit 7: always 1
     // Bit 6: 1 if this device is self powered, 0 if bus powered
     // Bit 5: 1 if this device uses remote wakeup
-    // Bit 4: 1 if this device is battery powered
     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];
@@ -2704,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
@@ -2715,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 
@@ -2856,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;
@@ -2913,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",
@@ -2968,6 +2977,292 @@ int ftdi_eeprom_decode(struct ftdi_context *ftdi, int verbose)
 }
 
 /**
+   Get a value from the decoded EEPROM structure
+
+   \\param ftdi pointer to ftdi_context
+   \\param value_name Enum of the value to query
+   \\param Pointer to store read value
+
+   \\retval 0: all fine
+   \\retval -1: Value doesn't exist
+*/
+int ftdi_get_eeprom_value(struct ftdi_context *ftdi, enum ftdi_eeprom_value value_name, int* value)
+{
+    switch (value_name)
+    {
+    case VENDOR_ID:
+       *value = ftdi->eeprom->vendor_id;
+       break;
+    case PRODUCT_ID:
+       *value = ftdi->eeprom->product_id;
+       break;
+    case SELF_POWERED:
+       *value = ftdi->eeprom->self_powered;
+       break;
+    case REMOTE_WAKEUP:
+       *value = ftdi->eeprom->remote_wakeup;
+       break;
+    case IS_NOT_PNP:
+       *value = ftdi->eeprom->is_not_pnp;
+       break;
+    case SUSPEND_DBUS7:
+       *value = ftdi->eeprom->suspend_dbus7;
+       break;
+    case IN_IS_ISOCHRONOUS:
+       *value = ftdi->eeprom->in_is_isochronous;
+       break;
+    case SUSPEND_PULL_DOWNS:
+       *value = ftdi->eeprom->suspend_pull_downs;
+       break;
+    case USE_SERIAL:
+       *value = ftdi->eeprom->use_serial;
+       break;
+    case USB_VERSION:
+       *value = ftdi->eeprom->usb_version;
+       break;
+    case MAX_POWER:
+       *value = ftdi->eeprom->max_power;
+       break;
+    case CHANNEL_A_TYPE:
+       *value = ftdi->eeprom->channel_a_type;
+       break;
+    case CHANNEL_B_TYPE:
+       *value = ftdi->eeprom->channel_b_type;
+       break;
+    case CHANNEL_A_DRIVER:
+       *value = ftdi->eeprom->channel_a_driver;
+       break;
+    case CHANNEL_B_DRIVER:
+       *value = ftdi->eeprom->channel_b_driver;
+       break;
+    case CBUS_FUNCTION_0:
+       *value = ftdi->eeprom->cbus_function[0];
+       break;
+    case CBUS_FUNCTION_1:
+       *value = ftdi->eeprom->cbus_function[1];
+       break;
+    case CBUS_FUNCTION_2:
+       *value = ftdi->eeprom->cbus_function[2];
+       break;
+    case CBUS_FUNCTION_3:
+       *value = ftdi->eeprom->cbus_function[3];
+       break;
+    case CBUS_FUNCTION_4:
+       *value = ftdi->eeprom->cbus_function[4];
+       break;
+    case HIGH_CURRENT:
+       *value = ftdi->eeprom->high_current;
+       break;
+    case HIGH_CURRENT_A:
+       *value = ftdi->eeprom->high_current_a;
+       break;
+    case HIGH_CURRENT_B:
+       *value = ftdi->eeprom->high_current_b;
+       break;
+    case INVERT:
+       *value = ftdi->eeprom->invert;
+       break;
+    case GROUP0_DRIVE:
+       *value = ftdi->eeprom->group0_drive;
+       break;
+    case GROUP0_SCHMITT:
+       *value = ftdi->eeprom->group0_schmitt;
+       break;
+    case GROUP0_SLEW:
+       *value = ftdi->eeprom->group0_slew;
+       break;
+    case GROUP1_DRIVE:
+       *value = ftdi->eeprom->group1_drive;
+       break;
+    case GROUP1_SCHMITT:
+       *value = ftdi->eeprom->group1_schmitt;
+       break;
+    case GROUP1_SLEW:
+       *value = ftdi->eeprom->group1_slew;
+       break;
+    case GROUP2_DRIVE:
+       *value = ftdi->eeprom->group2_drive;
+       break;
+    case GROUP2_SCHMITT:
+       *value = ftdi->eeprom->group2_schmitt;
+       break;
+    case GROUP2_SLEW:
+       *value = ftdi->eeprom->group2_slew;
+       break;
+    case GROUP3_DRIVE:
+       *value = ftdi->eeprom->group3_drive;
+       break;
+    case GROUP3_SCHMITT:
+       *value = ftdi->eeprom->group3_schmitt;
+       break;
+    case GROUP3_SLEW:
+       *value = ftdi->eeprom->group3_slew;
+       break;
+    case CHIP_TYPE:
+       *value = ftdi->eeprom->chip;
+       break;
+    case CHIP_SIZE:
+       *value = ftdi->eeprom->size;
+       break;
+    default:
+        ftdi_error_return(-1, "Request for unknown EEPROM value");
+    }
+    return 0;
+}
+
+/**
+   Set a value in the decoded EEPROM Structure
+   No parameter checking is performed
+
+   \\param ftdi pointer to ftdi_context
+   \\param value_name Enum of the value to query
+   \\param Value to set
+
+   \\retval 0: all fine
+   \\retval -1: Value doesn't exist
+   \\retval -2: Value not user settable
+*/
+int ftdi_set_eeprom_value(struct ftdi_context *ftdi, enum ftdi_eeprom_value value_name, int value)
+{
+    switch (value_name)
+    {
+    case VENDOR_ID:
+       ftdi->eeprom->vendor_id = value;
+       break;
+    case PRODUCT_ID:
+       ftdi->eeprom->product_id = value;
+       break;
+    case SELF_POWERED:
+       ftdi->eeprom->self_powered = value;
+       break;
+    case REMOTE_WAKEUP:
+       ftdi->eeprom->remote_wakeup = value;
+       break;
+    case IS_NOT_PNP:
+       ftdi->eeprom->is_not_pnp = value;
+       break;
+    case SUSPEND_DBUS7:
+       ftdi->eeprom->suspend_dbus7 = value;
+       break;
+    case IN_IS_ISOCHRONOUS:
+       ftdi->eeprom->in_is_isochronous = value;
+       break;
+    case SUSPEND_PULL_DOWNS:
+       ftdi->eeprom->suspend_pull_downs = value;
+       break;
+    case USE_SERIAL:
+       ftdi->eeprom->use_serial = value;
+       break;
+    case USB_VERSION:
+       ftdi->eeprom->usb_version = value;
+       break;
+    case MAX_POWER:
+       ftdi->eeprom->max_power = value;
+       break;
+    case CHANNEL_A_TYPE:
+       ftdi->eeprom->channel_a_type = value;
+       break;
+    case CHANNEL_B_TYPE:
+       ftdi->eeprom->channel_b_type = value;
+       break;
+    case CHANNEL_A_DRIVER:
+       ftdi->eeprom->channel_a_driver = value;
+       break;
+    case CHANNEL_B_DRIVER:
+       ftdi->eeprom->channel_b_driver = value;
+       break;
+    case CBUS_FUNCTION_0:
+       ftdi->eeprom->cbus_function[0] = value;
+       break;
+    case CBUS_FUNCTION_1:
+       ftdi->eeprom->cbus_function[1] = value;
+       break;
+    case CBUS_FUNCTION_2:
+       ftdi->eeprom->cbus_function[2] = value;
+       break;
+    case CBUS_FUNCTION_3:
+       ftdi->eeprom->cbus_function[3] = value;
+       break;
+    case CBUS_FUNCTION_4:
+       ftdi->eeprom->cbus_function[4] = value;
+       break;
+    case HIGH_CURRENT:
+       ftdi->eeprom->high_current = value;
+       break;
+    case HIGH_CURRENT_A:
+       ftdi->eeprom->high_current_a = value;
+       break;
+    case HIGH_CURRENT_B:
+       ftdi->eeprom->high_current_b = value;
+       break;
+    case INVERT:
+       ftdi->eeprom->invert = value;
+       break;
+    case GROUP0_DRIVE:
+       ftdi->eeprom->group0_drive = value;
+       break;
+    case GROUP0_SCHMITT:
+       ftdi->eeprom->group0_schmitt = value;
+       break;
+    case GROUP0_SLEW:
+       ftdi->eeprom->group0_slew = value;
+       break;
+    case GROUP1_DRIVE:
+       ftdi->eeprom->group1_drive = value;
+       break;
+    case GROUP1_SCHMITT:
+       ftdi->eeprom->group1_schmitt = value;
+       break;
+    case GROUP1_SLEW:
+       ftdi->eeprom->group1_slew = value;
+       break;
+    case GROUP2_DRIVE:
+       ftdi->eeprom->group2_drive = value;
+       break;
+    case GROUP2_SCHMITT:
+       ftdi->eeprom->group2_schmitt = value;
+       break;
+    case GROUP2_SLEW:
+       ftdi->eeprom->group2_slew = value;
+       break;
+    case GROUP3_DRIVE:
+       ftdi->eeprom->group3_drive = value;
+       break;
+    case GROUP3_SCHMITT:
+       ftdi->eeprom->group3_schmitt = value;
+       break;
+    case GROUP3_SLEW:
+       ftdi->eeprom->group3_slew = value;
+       break;
+    case CHIP_TYPE:
+       ftdi->eeprom->chip = value;
+       break;
+    case CHIP_SIZE: 
+       ftdi_error_return(-2, "EEPROM Value can't be changed");
+    default : 
+        ftdi_error_return(-1, "Request to unknown EEPROM value");
+    }
+    return 0;
+}
+
+/** Get the read-only buffer to the binary EEPROM content
+
+    \param ftdi pointer to ftdi_context
+    \param ftdi buffer to receive EEPROM content
+    \param size Size of receiving buffer
+
+    \retval 0: All fine
+    \retval -1: struct ftdi_contxt or ftdi_eeprom missing
+*/
+int ftdi_get_eeprom_buf(struct ftdi_context *ftdi, unsigned char * buf, int size) 
+    {
+       if (!ftdi || !(ftdi->eeprom))
+           ftdi_error_return(-1, "No appropriate structure");
+       memcpy(buf, ftdi->eeprom->buf, size);
+       return 0;
+    }
+
+/**
     Read eeprom location
 
     \param ftdi pointer to ftdi_context
@@ -3214,7 +3509,9 @@ int ftdi_erase_eeprom(struct ftdi_context *ftdi)
        Chip is 93x46 if magic is read at word position 0x00, as wraparound happens around 0x40
        Chip is 93x56 if magic is read at word position 0x40, as wraparound happens around 0x80
        Chip is 93x66 if magic is only read at word position 0xc0*/
-    if( ftdi_write_eeprom_location(ftdi, 0xc0, MAGIC))
+    if (libusb_control_transfer(ftdi->usb_dev, FTDI_DEVICE_OUT_REQTYPE,
+                                    SIO_WRITE_EEPROM_REQUEST, MAGIC, 0xc0,
+                                    NULL, 0, ftdi->usb_write_timeout) != 0)
         ftdi_error_return(-3, "Writing magic failed");
     if (ftdi_read_eeprom_location( ftdi, 0x00, &eeprom_value)) 
         ftdi_error_return(-4, "Reading failed failed");