Enumerate all handled EEPROM values Provide ftdi_get|set_eeprom_value to access these...
[libftdi] / src / ftdi.c
index 654a8ac..26fd27d 100644 (file)
@@ -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
@@ -2650,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;
 }
 
 /**
@@ -2695,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];
@@ -2706,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
@@ -2717,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 
@@ -2858,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;
@@ -2915,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",
@@ -2970,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