EEPROM max_power build/decode inconsistency
[libftdi] / src / ftdi.c
index 9691b8f..07687e8 100644 (file)
@@ -34,7 +34,9 @@
 #include <stdio.h>
 #include <stdlib.h>
 
+#include "ftdi_i.h"
 #include "ftdi.h"
+#include "ftdi_version_i.h"
 
 #define ftdi_error_return(code, str) do {  \
         ftdi->error_str = str;             \
@@ -147,12 +149,23 @@ struct ftdi_context *ftdi_new(void)
     \retval  0: all fine
     \retval -1: unknown interface
     \retval -2: USB device unavailable
+    \retval -3: Device already open, interface can't be set in that state
 */
 int ftdi_set_interface(struct ftdi_context *ftdi, enum ftdi_interface interface)
 {
     if (ftdi == NULL)
         ftdi_error_return(-2, "USB device unavailable");
 
+    if (ftdi->usb_dev != NULL)
+    {
+        int check_interface = interface;
+        if (check_interface == INTERFACE_ANY)
+            check_interface = INTERFACE_A;
+
+        if (ftdi->index != check_interface)
+            ftdi_error_return(-3, "Interface can not be changed on an already open device");
+    }
+
     switch (interface)
     {
         case INTERFACE_ANY:
@@ -257,6 +270,23 @@ void ftdi_set_usbdev (struct ftdi_context *ftdi, libusb_device_handle *usb)
     ftdi->usb_dev = usb;
 }
 
+/**
+ * @brief Get libftdi library version
+ *
+ * @return ftdi_version_info Library version information
+ **/
+struct ftdi_version_info ftdi_get_library_version()
+{
+    struct ftdi_version_info ver;
+
+    ver.major = FTDI_MAJOR_VERSION;
+    ver.minor = FTDI_MINOR_VERSION;
+    ver.micro = FTDI_MICRO_VERSION;
+    ver.version_str = FTDI_VERSION_STRING;
+    ver.snapshot_str = FTDI_SNAPSHOT_VERSION;
+
+    return ver;
+}
 
 /**
     Finds all ftdi devices with given VID:PID on the usb bus. Creates a new
@@ -964,34 +994,30 @@ int ftdi_usb_close(struct ftdi_context *ftdi)
     return rtn;
 }
 
-/**
-    ftdi_convert_baudrate returns nearest supported baud rate to that requested.
+/*  ftdi_to_clkbits_AM For the AM device, convert a requested baudrate 
+                    to encoded divisor and the achievable baudrate
     Function is only used internally
     \internal
+
+    See AN120
+   clk/1   -> 0
+   clk/1.5 -> 1
+   clk/2   -> 2
+   From /2, 0.125/ 0.25 and 0.5 steps may be taken
+   The fractional part has frac_code encoding
 */
-static int ftdi_convert_baudrate(int baudrate, struct ftdi_context *ftdi,
-                                 unsigned short *value, unsigned short *index)
+static int ftdi_to_clkbits_AM(int baudrate, unsigned long *encoded_divisor)
+
 {
+    static const char frac_code[8] = {0, 3, 2, 4, 1, 5, 6, 7};
     static const char am_adjust_up[8] = {0, 0, 0, 1, 0, 3, 2, 1};
     static const char am_adjust_dn[8] = {0, 0, 0, 1, 0, 1, 2, 3};
-    static const char frac_code[8] = {0, 3, 2, 4, 1, 5, 6, 7};
     int divisor, best_divisor, best_baud, best_baud_diff;
-    unsigned long encoded_divisor;
-    int i;
-
-    if (baudrate <= 0)
-    {
-        // Return error
-        return -1;
-    }
-
     divisor = 24000000 / baudrate;
+    int i;
 
-    if (ftdi->type == TYPE_AM)
-    {
-        // Round down to supported fraction (AM only)
-        divisor -= am_adjust_dn[divisor & 7];
-    }
+    // Round down to supported fraction (AM only)
+    divisor -= am_adjust_dn[divisor & 7];
 
     // Try this divisor and the one above it (because division rounds down)
     best_divisor = 0;
@@ -1009,11 +1035,6 @@ static int ftdi_convert_baudrate(int baudrate, struct ftdi_context *ftdi,
             // Round up to minimum supported divisor
             try_divisor = 8;
         }
-        else if (ftdi->type != TYPE_AM && try_divisor < 12)
-        {
-            // BM doesn't support divisors 9 through 11 inclusive
-            try_divisor = 12;
-        }
         else if (divisor < 16)
         {
             // AM doesn't support divisors 9 through 15 inclusive
@@ -1021,23 +1042,12 @@ static int ftdi_convert_baudrate(int baudrate, struct ftdi_context *ftdi,
         }
         else
         {
-            if (ftdi->type == TYPE_AM)
+            // Round up to supported fraction (AM only)
+            try_divisor += am_adjust_up[try_divisor & 7];
+            if (try_divisor > 0x1FFF8)
             {
-                // Round up to supported fraction (AM only)
-                try_divisor += am_adjust_up[try_divisor & 7];
-                if (try_divisor > 0x1FFF8)
-                {
-                    // Round down to maximum supported divisor value (for AM)
-                    try_divisor = 0x1FFF8;
-                }
-            }
-            else
-            {
-                if (try_divisor > 0x1FFFF)
-                {
-                    // Round down to maximum supported divisor value (for BM)
-                    try_divisor = 0x1FFFF;
-                }
+                // Round down to maximum supported divisor value (for AM)
+                try_divisor = 0x1FFF8;
             }
         }
         // Get estimated baud rate (to nearest integer)
@@ -1065,19 +1075,128 @@ static int ftdi_convert_baudrate(int baudrate, struct ftdi_context *ftdi,
         }
     }
     // Encode the best divisor value
-    encoded_divisor = (best_divisor >> 3) | (frac_code[best_divisor & 7] << 14);
+    *encoded_divisor = (best_divisor >> 3) | (frac_code[best_divisor & 7] << 14);
     // Deal with special cases for encoded value
-    if (encoded_divisor == 1)
+    if (*encoded_divisor == 1)
     {
-        encoded_divisor = 0;    // 3000000 baud
+        *encoded_divisor = 0;    // 3000000 baud
     }
-    else if (encoded_divisor == 0x4001)
+    else if (*encoded_divisor == 0x4001)
     {
-        encoded_divisor = 1;    // 2000000 baud (BM only)
+        *encoded_divisor = 1;    // 2000000 baud (BM only)
+    }
+    return best_baud;
+}
+
+/*  ftdi_to_clkbits Convert a requested baudrate for a given system clock  and predivisor
+                    to encoded divisor and the achievable baudrate
+    Function is only used internally
+    \internal
+
+    See AN120
+   clk/1   -> 0
+   clk/1.5 -> 1
+   clk/2   -> 2
+   From /2, 0.125 steps may be taken.
+   The fractional part has frac_code encoding
+
+   value[13:0] of value is the divisor
+   index[9] mean 12 MHz Base(120 MHz/10) rate versus 3 MHz (48 MHz/16) else
+
+   H Type have all features above with
+   {index[8],value[15:14]} is the encoded subdivisor
+
+   FT232R, FT2232 and FT232BM have no option for 12 MHz and with 
+   {index[0],value[15:14]} is the encoded subdivisor
+
+   AM Type chips have only four fractional subdivisors at value[15:14]
+   for subdivisors 0, 0.5, 0.25, 0.125
+*/
+static int ftdi_to_clkbits(int baudrate, unsigned int clk, int clk_div, unsigned long *encoded_divisor)
+{
+    static const char frac_code[8] = {0, 3, 2, 4, 1, 5, 6, 7};
+    int best_baud = 0;
+    int divisor, best_divisor;
+    if (baudrate >=  clk/clk_div)
+    {
+        *encoded_divisor = 0;
+        best_baud = clk/clk_div;
+    }
+    else if (baudrate >=  clk/(clk_div + clk_div/2))
+    {
+        *encoded_divisor = 1;
+        best_baud = clk/(clk_div + clk_div/2);
+    }
+    else if (baudrate >=  clk/(2*clk_div))
+    {
+        *encoded_divisor = 2;
+        best_baud = clk/(2*clk_div);
+    }
+    else
+    {
+        /* We divide by 16 to have 3 fractional bits and one bit for rounding */
+        divisor = clk*16/clk_div / baudrate;
+        if (divisor & 1) /* Decide if to round up or down*/
+            best_divisor = divisor /2 +1;
+        else
+            best_divisor = divisor/2;
+        if(best_divisor > 0x20000)
+            best_divisor = 0x1ffff;
+        best_baud = clk*16/clk_div/best_divisor;
+        if (best_baud & 1) /* Decide if to round up or down*/
+            best_baud = best_baud /2 +1;
+        else
+            best_baud = best_baud /2;
+        *encoded_divisor = (best_divisor >> 3) | (frac_code[best_divisor & 0x7] << 14);
+    }
+    return best_baud;
+} 
+/**
+    ftdi_convert_baudrate returns nearest supported baud rate to that requested.
+    Function is only used internally
+    \internal
+*/
+static int ftdi_convert_baudrate(int baudrate, struct ftdi_context *ftdi,
+                                 unsigned short *value, unsigned short *index)
+{
+    int best_baud;
+    unsigned long encoded_divisor;
+
+    if (baudrate <= 0)
+    {
+        // Return error
+        return -1;
+    }
+
+#define H_CLK 120000000
+#define C_CLK  48000000
+    if ((ftdi->type == TYPE_2232H) || (ftdi->type == TYPE_4232H) || (ftdi->type == TYPE_232H ))
+    {
+        if(baudrate*10 > H_CLK /0x3fff)
+        {
+            /* On H Devices, use 12 000 000 Baudrate when possible
+               We have a 14 bit divisor, a 1 bit divisor switch (10 or 16) 
+               three fractional bits and a 120 MHz clock
+               Assume AN_120 "Sub-integer divisors between 0 and 2 are not allowed" holds for
+               DIV/10 CLK too, so /1, /1.5 and /2 can be handled the same*/
+            best_baud = ftdi_to_clkbits(baudrate, H_CLK, 10, &encoded_divisor);
+            encoded_divisor |= 0x20000; /* switch on CLK/10*/
+        }
+        else
+            best_baud = ftdi_to_clkbits(baudrate, C_CLK, 16, &encoded_divisor);
+    }
+    else if ((ftdi->type == TYPE_BM) || (ftdi->type == TYPE_2232C) || (ftdi->type == TYPE_R ))
+    {
+        best_baud = ftdi_to_clkbits(baudrate, C_CLK, 16, &encoded_divisor);
+    }
+    else
+    {
+        best_baud = ftdi_to_clkbits_AM(baudrate, &encoded_divisor);
     }
     // 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 || ftdi->type == TYPE_232H )
+    if (ftdi->type == TYPE_2232H || 
+        ftdi->type == TYPE_4232H || ftdi->type == TYPE_232H )
     {
         *index = (unsigned short)(encoded_divisor >> 8);
         *index &= 0xFF00;
@@ -1794,21 +1913,19 @@ int ftdi_read_data_get_chunksize(struct ftdi_context *ftdi, unsigned int *chunks
     return 0;
 }
 
-
 /**
-    Enable bitbang mode.
-
-    \deprecated use \ref ftdi_set_bitmode with mode BITMODE_BITBANG instead
+    Enable/disable bitbang modes.
 
     \param ftdi pointer to ftdi_context
     \param bitmask Bitmask to configure lines.
            HIGH/ON value configures a line as output.
+    \param mode Bitbang mode: use the values defined in \ref ftdi_mpsse_mode
 
     \retval  0: all fine
     \retval -1: can't enable bitbang mode
     \retval -2: USB device unavailable
 */
-int ftdi_enable_bitbang(struct ftdi_context *ftdi, unsigned char bitmask)
+int ftdi_set_bitmode(struct ftdi_context *ftdi, unsigned char bitmask, unsigned char mode)
 {
     unsigned short usb_val;
 
@@ -1816,15 +1933,12 @@ int ftdi_enable_bitbang(struct ftdi_context *ftdi, unsigned char bitmask)
         ftdi_error_return(-2, "USB device unavailable");
 
     usb_val = bitmask; // low byte: bitmask
-    /* FT2232C: Set bitbang_mode to 2 to enable SPI */
-    usb_val |= (ftdi->bitbang_mode << 8);
-
-    if (libusb_control_transfer(ftdi->usb_dev, FTDI_DEVICE_OUT_REQTYPE,
-                                SIO_SET_BITMODE_REQUEST, usb_val, ftdi->index,
-                                NULL, 0, ftdi->usb_write_timeout) < 0)
-        ftdi_error_return(-1, "unable to enter bitbang mode. Perhaps not a BM type chip?");
+    usb_val |= (mode << 8);
+    if (libusb_control_transfer(ftdi->usb_dev, FTDI_DEVICE_OUT_REQTYPE, SIO_SET_BITMODE_REQUEST, usb_val, ftdi->index, NULL, 0, ftdi->usb_write_timeout) < 0)
+        ftdi_error_return(-1, "unable to configure bitbang mode. Perhaps not a BM/2232C type chip?");
 
-    ftdi->bitbang_enabled = 1;
+    ftdi->bitbang_mode = mode;
+    ftdi->bitbang_enabled = (mode == BITMODE_RESET) ? 0 : 1;
     return 0;
 }
 
@@ -1849,34 +1963,6 @@ int ftdi_disable_bitbang(struct ftdi_context *ftdi)
     return 0;
 }
 
-/**
-    Enable/disable bitbang modes.
-
-    \param ftdi pointer to ftdi_context
-    \param bitmask Bitmask to configure lines.
-           HIGH/ON value configures a line as output.
-    \param mode Bitbang mode: use the values defined in \ref ftdi_mpsse_mode
-
-    \retval  0: all fine
-    \retval -1: can't enable bitbang mode
-    \retval -2: USB device unavailable
-*/
-int ftdi_set_bitmode(struct ftdi_context *ftdi, unsigned char bitmask, unsigned char mode)
-{
-    unsigned short usb_val;
-
-    if (ftdi == NULL || ftdi->usb_dev == NULL)
-        ftdi_error_return(-2, "USB device unavailable");
-
-    usb_val = bitmask; // low byte: bitmask
-    usb_val |= (mode << 8);
-    if (libusb_control_transfer(ftdi->usb_dev, FTDI_DEVICE_OUT_REQTYPE, SIO_SET_BITMODE_REQUEST, usb_val, ftdi->index, NULL, 0, ftdi->usb_write_timeout) < 0)
-        ftdi_error_return(-1, "unable to configure bitbang mode. Perhaps not a 2232C type chip?");
-
-    ftdi->bitbang_mode = mode;
-    ftdi->bitbang_enabled = (mode == BITMODE_RESET) ? 0 : 1;
-    return 0;
-}
 
 /**
     Directly read pin state, circumventing the read buffer. Useful for bitbang mode.
@@ -2218,7 +2304,7 @@ int ftdi_eeprom_initdefaults(struct ftdi_context *ftdi, char * manufacturer,
         ftdi_error_return(-3, "No connected device or device not yet opened");
 
     eeprom->vendor_id = 0x0403;
-    eeprom->use_serial = USE_SERIAL_NUM;
+    eeprom->use_serial = 1;
     if ((ftdi->type == TYPE_AM) || (ftdi->type == TYPE_BM) ||
             (ftdi->type == TYPE_R))
         eeprom->product_id = 0x6001;
@@ -2253,6 +2339,25 @@ int ftdi_eeprom_initdefaults(struct ftdi_context *ftdi, char * manufacturer,
         if (eeprom->product)
             strcpy(eeprom->product, product);
     }
+    else
+    {
+        const char* default_product;
+        switch(ftdi->type)
+        {
+        case TYPE_AM:    default_product = "AM"; break;
+        case TYPE_BM:    default_product = "BM"; break;
+        case TYPE_2232C: default_product = "Dual RS232"; break;
+        case TYPE_R:     default_product = "FT232R USB UART"; break;
+        case TYPE_2232H: default_product = "Dual RS232-HS"; break;
+        case TYPE_4232H: default_product = "FT4232H"; break;
+        case TYPE_232H:  default_product = "Single-RS232-HS"; break;
+        default:
+        ftdi_error_return(-3, "Unknown chip type");
+        }
+        eeprom->product = malloc(strlen(default_product) +1);
+        if (eeprom->product)
+            strcpy(eeprom->product, default_product);
+    }
 
     if (eeprom->serial)
         free (eeprom->serial);
@@ -2264,7 +2369,6 @@ int ftdi_eeprom_initdefaults(struct ftdi_context *ftdi, char * manufacturer,
             strcpy(eeprom->serial, serial);
     }
 
-
     if (ftdi->type == TYPE_R)
     {
         eeprom->max_power = 90;
@@ -2473,7 +2577,7 @@ int ftdi_eeprom_build(struct ftdi_context *ftdi)
     output[0x08] = j;
 
     // Addr 09: Max power consumption: max power = value * 2 mA
-    output[0x09] = eeprom->max_power>>1;
+    output[0x09] = eeprom->max_power / MAX_POWER_MILLIAMP_PER_UNIT;
 
     if (ftdi->type != TYPE_AM)
     {
@@ -2569,7 +2673,7 @@ int ftdi_eeprom_build(struct ftdi_context *ftdi)
 
     if (ftdi->type > TYPE_AM) /* use_serial not used in AM devices */
     {
-        if (eeprom->use_serial == USE_SERIAL_NUM )
+        if (eeprom->use_serial)
             output[0x0A] |= USE_SERIAL_NUM;
         else
             output[0x0A] &= ~USE_SERIAL_NUM;
@@ -2735,8 +2839,83 @@ int ftdi_eeprom_build(struct ftdi_context *ftdi)
 
             break;
         case TYPE_4232H:
+            if (eeprom->channel_a_driver == DRIVER_VCP)
+                output[0x00] |= DRIVER_VCP;
+            else
+                output[0x00] &= ~DRIVER_VCP;
+            if (eeprom->channel_b_driver == DRIVER_VCP)
+                output[0x01] |= DRIVER_VCP;
+            else
+                output[0x01] &= ~DRIVER_VCP;
+            if (eeprom->channel_c_driver == DRIVER_VCP)
+                output[0x00] |= (DRIVER_VCP << 4);
+            else
+                output[0x00] &= ~(DRIVER_VCP << 4);
+            if (eeprom->channel_d_driver == DRIVER_VCP)
+                output[0x01] |= (DRIVER_VCP << 4);
+            else
+                output[0x01] &= ~(DRIVER_VCP << 4);
+
+            if (eeprom->suspend_pull_downs == 1)
+                output[0x0a] |= 0x4;
+            else
+                output[0x0a] &= ~0x4;
+
+            if (eeprom->channel_a_rs485enable)
+                output[0x0b] |= CHANNEL_IS_RS485 << 0;
+            else
+                output[0x0b] &= ~(CHANNEL_IS_RS485 << 0);
+            if (eeprom->channel_b_rs485enable)
+                output[0x0b] |= CHANNEL_IS_RS485 << 1;
+            else
+                output[0x0b] &= ~(CHANNEL_IS_RS485 << 1);
+            if (eeprom->channel_c_rs485enable)
+                output[0x0b] |= CHANNEL_IS_RS485 << 2;
+            else
+                output[0x0b] &= ~(CHANNEL_IS_RS485 << 2);
+            if (eeprom->channel_d_rs485enable)
+                output[0x0b] |= CHANNEL_IS_RS485 << 3;
+            else
+                output[0x0b] &= ~(CHANNEL_IS_RS485 << 3);
+
+            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[0x18] = eeprom->chip;
-            fprintf(stderr,"FIXME: Build FT4232H specific EEPROM settings\n");
+
             break;
         case TYPE_232H:
             output[0x00] = type2bit(eeprom->channel_a_type, TYPE_232H);
@@ -2869,7 +3048,7 @@ int ftdi_eeprom_decode(struct ftdi_context *ftdi, int verbose)
     eeprom->remote_wakeup = buf[0x08] & 0x20;
 
     // Addr 09: Max power consumption: max power = value * 2 mA
-    eeprom->max_power = buf[0x09];
+    eeprom->max_power = MAX_POWER_MILLIAMP_PER_UNIT * buf[0x09];
 
     // Addr 0A: Chip configuration
     // Bit 7: 0 - reserved
@@ -2884,7 +3063,7 @@ int ftdi_eeprom_decode(struct ftdi_context *ftdi, int verbose)
     eeprom->in_is_isochronous  = buf[0x0A]&0x01;
     eeprom->out_is_isochronous = buf[0x0A]&0x02;
     eeprom->suspend_pull_downs = buf[0x0A]&0x04;
-    eeprom->use_serial         = buf[0x0A] & USE_SERIAL_NUM;
+    eeprom->use_serial         = (buf[0x0A] & USE_SERIAL_NUM)?1:0;
     eeprom->use_usb_version    = buf[0x0A] & USE_USB_VERSION_BIT;
 
     // Addr 0C: USB version low byte when 0x0A
@@ -2992,7 +3171,7 @@ int ftdi_eeprom_decode(struct ftdi_context *ftdi, int verbose)
     else if (ftdi->type == TYPE_R)
     {
         /* TYPE_R flags D2XX, not VCP as all others*/
-        eeprom->channel_a_driver = (~buf[0x00]) & DRIVER_VCP;
+        eeprom->channel_a_driver = ~buf[0x00] & DRIVER_VCP;
         eeprom->high_current     = buf[0x00] & HIGH_CURRENT_DRIVE_R;
         if ( (buf[0x01]&0x40) != 0x40)
             fprintf(stderr,
@@ -3014,15 +3193,26 @@ int ftdi_eeprom_decode(struct ftdi_context *ftdi, int verbose)
         eeprom->cbus_function[3] = (buf[0x15] >> 4) & 0x0f;
         eeprom->cbus_function[4] = buf[0x16] & 0x0f;
     }
-    else if ((ftdi->type == TYPE_2232H) ||(ftdi->type == TYPE_4232H))
+    else if ((ftdi->type == TYPE_2232H) || (ftdi->type == TYPE_4232H))
     {
-        eeprom->channel_a_type   = bit2type(buf[0x00] & 0x7);
         eeprom->channel_a_driver = buf[0x00] & DRIVER_VCP;
-        eeprom->channel_b_type   = bit2type(buf[0x01] & 0x7);
         eeprom->channel_b_driver = buf[0x01] & DRIVER_VCP;
 
         if (ftdi->type == TYPE_2232H)
+        {
+            eeprom->channel_a_type   = bit2type(buf[0x00] & 0x7);
+            eeprom->channel_b_type   = bit2type(buf[0x01] & 0x7);
             eeprom->suspend_dbus7    = buf[0x01] & SUSPEND_DBUS7_BIT;
+        }
+        else
+        {
+            eeprom->channel_c_driver = (buf[0x00] >> 4) & DRIVER_VCP;
+            eeprom->channel_d_driver = (buf[0x01] >> 4) & DRIVER_VCP;
+            eeprom->channel_a_rs485enable = buf[0x0b] & (CHANNEL_IS_RS485 << 0);
+            eeprom->channel_b_rs485enable = buf[0x0b] & (CHANNEL_IS_RS485 << 1);
+            eeprom->channel_c_rs485enable = buf[0x0b] & (CHANNEL_IS_RS485 << 2);
+            eeprom->channel_d_rs485enable = buf[0x0b] & (CHANNEL_IS_RS485 << 3);
+        }
 
         eeprom->chip = buf[0x18];
         eeprom->group0_drive   =  buf[0x0c]       & DRIVE_16MA;
@@ -3074,7 +3264,7 @@ int ftdi_eeprom_decode(struct ftdi_context *ftdi, int verbose)
         if (eeprom->self_powered)
             fprintf(stdout, "Self-Powered%s", (eeprom->remote_wakeup)?", USB Remote Wake Up\n":"\n");
         else
-            fprintf(stdout, "Bus Powered: %3d mA%s", eeprom->max_power * 2,
+            fprintf(stdout, "Bus Powered: %3d mA%s", eeprom->max_power,
                     (eeprom->remote_wakeup)?" USB Remote Wake Up\n":"\n");
         if (eeprom->manufacturer)
             fprintf(stdout, "Manufacturer: %s\n",eeprom->manufacturer);
@@ -3164,7 +3354,6 @@ int ftdi_eeprom_decode(struct ftdi_context *ftdi, int verbose)
                     fprintf(stdout,"C%d Function: %s\n", i,
                             cbush_mux[eeprom->cbus_function[i]]);
             }
-
         }
 
         if (ftdi->type == TYPE_R)
@@ -3270,6 +3459,24 @@ int ftdi_get_eeprom_value(struct ftdi_context *ftdi, enum ftdi_eeprom_value valu
         case CHANNEL_B_DRIVER:
             *value = ftdi->eeprom->channel_b_driver;
             break;
+        case CHANNEL_C_DRIVER:
+            *value = ftdi->eeprom->channel_c_driver;
+            break;
+        case CHANNEL_D_DRIVER:
+            *value = ftdi->eeprom->channel_d_driver;
+            break;
+        case CHANNEL_A_RS485:
+            *value = ftdi->eeprom->channel_a_rs485enable;
+            break;
+        case CHANNEL_B_RS485:
+            *value = ftdi->eeprom->channel_b_rs485enable;
+            break;
+        case CHANNEL_C_RS485:
+            *value = ftdi->eeprom->channel_c_rs485enable;
+            break;
+        case CHANNEL_D_RS485:
+            *value = ftdi->eeprom->channel_d_rs485enable;
+            break;
         case CBUS_FUNCTION_0:
             *value = ftdi->eeprom->cbus_function[0];
             break;
@@ -3439,6 +3646,24 @@ int ftdi_set_eeprom_value(struct ftdi_context *ftdi, enum ftdi_eeprom_value valu
         case CHANNEL_B_DRIVER:
             ftdi->eeprom->channel_b_driver = value;
             break;
+        case CHANNEL_C_DRIVER:
+            ftdi->eeprom->channel_c_driver = value;
+            break;
+        case CHANNEL_D_DRIVER:
+            ftdi->eeprom->channel_d_driver = value;
+            break;
+        case CHANNEL_A_RS485:
+            ftdi->eeprom->channel_a_rs485enable = value;
+            break;
+        case CHANNEL_B_RS485:
+            ftdi->eeprom->channel_b_rs485enable = value;
+            break;
+        case CHANNEL_C_RS485:
+            ftdi->eeprom->channel_c_rs485enable = value;
+            break;
+        case CHANNEL_D_RS485:
+            ftdi->eeprom->channel_d_rs485enable = value;
+            break;
         case CBUS_FUNCTION_0:
             ftdi->eeprom->cbus_function[0] = value;
             break;