EEPROM[02] is VID, so high_current must be defined somewhere else
[libftdi] / src / ftdi.c
index 8bddd42..6d0163f 100644 (file)
@@ -78,6 +78,7 @@ static void ftdi_usb_close_internal (struct ftdi_context *ftdi)
 */
 int ftdi_init(struct ftdi_context *ftdi)
 {
+    ftdi->usb_ctx = NULL;
     ftdi->usb_dev = NULL;
     ftdi->usb_read_timeout = 5000;
     ftdi->usb_write_timeout = 5000;
@@ -100,7 +101,7 @@ int ftdi_init(struct ftdi_context *ftdi)
 
     ftdi->error_str = NULL;
 
-    ftdi->eeprom_size = FTDI_DEFAULT_EEPROM_SIZE;
+    ftdi->eeprom = NULL;
 
     /* All fine. Now allocate the readbuffer */
     return ftdi_read_data_set_chunksize(ftdi, 4096);
@@ -191,7 +192,7 @@ void ftdi_deinit(struct ftdi_context *ftdi)
         free(ftdi->readbuffer);
         ftdi->readbuffer = NULL;
     }
-    libusb_exit(NULL);
+    libusb_exit(ftdi->usb_ctx);
 }
 
 /**
@@ -243,10 +244,10 @@ int ftdi_usb_find_all(struct ftdi_context *ftdi, struct ftdi_device_list **devli
     int count = 0;
     int i = 0;
 
-    if (libusb_init(NULL) < 0)
+    if (libusb_init(&ftdi->usb_ctx) < 0)
         ftdi_error_return(-4, "libusb_init() failed");
 
-    if (libusb_get_device_list(NULL, &devs) < 0)
+    if (libusb_get_device_list(ftdi->usb_ctx, &devs) < 0)
         ftdi_error_return(-5, "libusb_get_device_list() failed");
 
     curdev = devlist;
@@ -490,7 +491,7 @@ int ftdi_usb_open_dev(struct ftdi_context *ftdi, libusb_device *dev)
             }
             else
             {
-                ftdi_error_return(-3, "unable to set usb configuration. Make sure the default FTDI kernel side driver is unloaded.");
+                ftdi_error_return(-3, "unable to set usb configuration. Make sure the default FTDI driver is not in use");
             }
         }
     }
@@ -504,7 +505,7 @@ int ftdi_usb_open_dev(struct ftdi_context *ftdi, libusb_device *dev)
         }
         else
         {
-            ftdi_error_return(-5, "unable to claim usb device. Make sure the default FTDI kernel side driver is unloaded.");
+            ftdi_error_return(-5, "unable to claim usb device. Make sure the default FTDI driver is not in use");
         }
     }
 
@@ -629,13 +630,13 @@ int ftdi_usb_open_desc_index(struct ftdi_context *ftdi, int vendor, int product,
     char string[256];
     int i = 0;
 
-    if (libusb_init(NULL) < 0)
+    if (libusb_init(&ftdi->usb_ctx) < 0)
         ftdi_error_return(-11, "libusb_init() failed");
 
     if (ftdi == NULL)
         ftdi_error_return(-11, "ftdi context invalid");
 
-    if (libusb_get_device_list(NULL, &devs) < 0)
+    if (libusb_get_device_list(ftdi->usb_ctx, &devs) < 0)
         ftdi_error_return(-12, "libusb_get_device_list() failed");
 
     while ((dev = devs[i++]) != NULL)
@@ -738,10 +739,10 @@ int ftdi_usb_open_string(struct ftdi_context *ftdi, const char* description)
        unsigned int bus_number, device_address;
        int i = 0;
 
-        if (libusb_init (NULL) < 0)
+        if (libusb_init (&ftdi->usb_ctx) < 0)
            ftdi_error_return(-1, "libusb_init() failed");
 
-       if (libusb_get_device_list(NULL, &devs) < 0)
+       if (libusb_get_device_list(ftdi->usb_ctx, &devs) < 0)
            ftdi_error_return(-2, "libusb_get_device_list() failed");
 
         /* XXX: This doesn't handle symlinks/odd paths/etc... */
@@ -1235,10 +1236,6 @@ int ftdi_write_data(struct ftdi_context *ftdi, unsigned char *buf, int size)
     return offset;
 }
 
-#ifdef LIBFTDI_LINUX_ASYNC_MODE
-#ifdef USB_CLASS_PTP
-#error LIBFTDI_LINUX_ASYNC_MODE is not compatible with libusb-compat-0.1!
-#endif
 static void ftdi_read_data_cb(struct libusb_transfer *transfer)
 {
     struct ftdi_transfer_control *tc = (struct ftdi_transfer_control *) transfer->user_data;
@@ -1325,9 +1322,9 @@ static void ftdi_write_data_cb(struct libusb_transfer *transfer)
 {
     struct ftdi_transfer_control *tc = (struct ftdi_transfer_control *) transfer->user_data;
     struct ftdi_context *ftdi = tc->ftdi;
-
-    tc->offset = transfer->actual_length;
-
+    
+    tc->offset += transfer->actual_length;
+    
     if (tc->offset == tc->size)
     {
         tc->completed = 1;
@@ -1353,8 +1350,7 @@ static void ftdi_write_data_cb(struct libusb_transfer *transfer)
     Writes data to the chip. Does not wait for completion of the transfer
     nor does it make sure that the transfer was successful.
 
-    Use libusb 1.0 Asynchronous API.
-    Only available if compiled with --with-async-mode.
+    Use libusb 1.0 asynchronous API.
 
     \param ftdi pointer to ftdi_context
     \param buf Buffer with the data
@@ -1392,7 +1388,9 @@ struct ftdi_transfer_control *ftdi_write_data_submit(struct ftdi_context *ftdi,
     else
       write_size = ftdi->writebuffer_chunksize;
 
-    libusb_fill_bulk_transfer(transfer, ftdi->usb_dev, ftdi->in_ep, buf, write_size, ftdi_write_data_cb, tc, ftdi->usb_write_timeout);
+    libusb_fill_bulk_transfer(transfer, ftdi->usb_dev, ftdi->in_ep, buf,
+                              write_size, ftdi_write_data_cb, tc,
+                              ftdi->usb_write_timeout);
     transfer->type = LIBUSB_TRANSFER_TYPE_BULK;
 
     ret = libusb_submit_transfer(transfer);
@@ -1412,8 +1410,7 @@ struct ftdi_transfer_control *ftdi_write_data_submit(struct ftdi_context *ftdi,
     Reads data from the chip. Does not wait for completion of the transfer
     nor does it make sure that the transfer was successful.
 
-    Use libusb 1.0 Asynchronous API.
-    Only available if compiled with --with-async-mode.
+    Use libusb 1.0 asynchronous API.
 
     \param ftdi pointer to ftdi_context
     \param buf Buffer with the data
@@ -1494,8 +1491,7 @@ struct ftdi_transfer_control *ftdi_read_data_submit(struct ftdi_context *ftdi, u
 /**
     Wait for completion of the transfer.
 
-    Use libusb 1.0 Asynchronous API.
-    Only available if compiled with --with-async-mode.
+    Use libusb 1.0 asynchronous API.
 
     \param tc pointer to ftdi_transfer_control
 
@@ -1509,34 +1505,36 @@ int ftdi_transfer_data_done(struct ftdi_transfer_control *tc)
 
     while (!tc->completed)
     {
-        ret = libusb_handle_events(NULL);
+        ret = libusb_handle_events(tc->ftdi->usb_ctx);
         if (ret < 0)
         {
             if (ret == LIBUSB_ERROR_INTERRUPTED)
                 continue;
             libusb_cancel_transfer(tc->transfer);
             while (!tc->completed)
-                if (libusb_handle_events(NULL) < 0)
+                if (libusb_handle_events(tc->ftdi->usb_ctx) < 0)
                     break;
             libusb_free_transfer(tc->transfer);
             free (tc);
-            tc = NULL;
             return ret;
         }
     }
 
-    if (tc->transfer->status == LIBUSB_TRANSFER_COMPLETED)
-        ret = tc->offset;
-    else
-        ret = -1;
-
-    libusb_free_transfer(tc->transfer);
+    ret = tc->offset;
+    /**
+     * tc->transfer could be NULL if "(size <= ftdi->readbuffer_remaining)"
+     * at ftdi_read_data_submit(). Therefore, we need to check it here.
+     **/
+    if (tc->transfer)
+    {
+        if (tc->transfer->status != LIBUSB_TRANSFER_COMPLETED)
+            ret = -1;
+        libusb_free_transfer(tc->transfer);
+    }
     free(tc);
     return ret;
 }
 
-#endif // LIBFTDI_LINUX_ASYNC_MODE
-
 /**
     Configure write buffer chunk size.
     Default is 4096.
@@ -2167,8 +2165,8 @@ void ftdi_eeprom_setsize(struct ftdi_context *ftdi, struct ftdi_eeprom *eeprom,
     if (ftdi == NULL)
         return;
 
-    ftdi->eeprom_size=size;
-    eeprom->size=size;
+    ftdi->eeprom = eeprom;
+    ftdi->eeprom->size=size;
 }
 
 /**
@@ -2176,17 +2174,25 @@ void ftdi_eeprom_setsize(struct ftdi_context *ftdi, struct ftdi_eeprom *eeprom,
 
     \param eeprom Pointer to ftdi_eeprom
 */
-void ftdi_eeprom_initdefaults(struct ftdi_eeprom *eeprom)
+void ftdi_eeprom_initdefaults(struct ftdi_context *ftdi)
 {
-    if (eeprom == NULL)
+    int i;
+    struct ftdi_eeprom *eeprom;
+
+    if (ftdi == NULL)
         return;
 
+    if (ftdi->eeprom == NULL)
+        return;
+
+    eeprom = ftdi->eeprom;
+
     eeprom->vendor_id = 0x0403;
     eeprom->product_id = 0x6001;
 
     eeprom->self_powered = 1;
     eeprom->remote_wakeup = 1;
-    eeprom->BM_type_chip = 1;
+    eeprom->chip_type = TYPE_BM;
 
     eeprom->in_is_isochronous = 0;
     eeprom->out_is_isochronous = 0;
@@ -2200,30 +2206,74 @@ void ftdi_eeprom_initdefaults(struct ftdi_eeprom *eeprom)
     eeprom->manufacturer = NULL;
     eeprom->product = NULL;
     eeprom->serial = NULL;
+    for (i=0; i < 5; i++)
+    {
+        eeprom->cbus_function[i] = 0;
+    }
+    eeprom->high_current = 0;
+    eeprom->invert = 0;
 
-    eeprom->size = FTDI_DEFAULT_EEPROM_SIZE;
+    eeprom->size = FTDI_MAX_EEPROM_SIZE;
+}
+
+/**
+    Frees allocated memory in eeprom.
+
+    \param eeprom Pointer to ftdi_eeprom
+*/
+void ftdi_eeprom_free(struct ftdi_context *ftdi)
+{
+    if (!ftdi)
+        return;
+    if (ftdi->eeprom)
+    {
+        struct ftdi_eeprom *eeprom = ftdi->eeprom;
+
+        if (eeprom->manufacturer != 0) {
+            free(eeprom->manufacturer);
+            eeprom->manufacturer = 0;
+        }
+        if (eeprom->product != 0) {
+            free(eeprom->product);
+            eeprom->product = 0;
+        }
+        if (eeprom->serial != 0) {
+            free(eeprom->serial);
+            eeprom->serial = 0;
+        }
+    }
 }
 
 /**
     Build binary output from ftdi_eeprom structure.
     Output is suitable for ftdi_write_eeprom().
 
+    \note This function doesn't handle FT2232x devices. Only FT232x.
     \param eeprom Pointer to ftdi_eeprom
     \param output Buffer of 128 bytes to store eeprom image to
 
-    \retval >0: used eeprom size
+    \retval >0: free eeprom size
     \retval -1: eeprom size (128 bytes) exceeded by custom strings
     \retval -2: Invalid eeprom pointer
+    \retval -3: Invalid cbus function setting
+    \retval -4: Chip doesn't support invert
+    \retval -5: Chip doesn't support high current drive
 */
-int ftdi_eeprom_build(struct ftdi_eeprom *eeprom, unsigned char *output)
+int ftdi_eeprom_build(struct ftdi_context *ftdi, unsigned char *output)
 {
     unsigned char i, j;
     unsigned short checksum, value;
     unsigned char manufacturer_size = 0, product_size = 0, serial_size = 0;
     int size_check;
+    const int cbus_max[5] = {13, 13, 13, 13, 9};
+    struct ftdi_eeprom *eeprom;
 
-    if (eeprom == NULL)
-        return -2;
+    if (ftdi == NULL)
+        ftdi_error_return(-2,"No context");
+    if (ftdi->eeprom == NULL)
+        ftdi_error_return(-2,"No eeprom structure");
+
+    eeprom= ftdi->eeprom;
 
     if (eeprom->manufacturer != NULL)
         manufacturer_size = strlen(eeprom->manufacturer);
@@ -2232,6 +2282,18 @@ int ftdi_eeprom_build(struct ftdi_eeprom *eeprom, unsigned char *output)
     if (eeprom->serial != NULL)
         serial_size = strlen(eeprom->serial);
 
+    // highest allowed cbus value
+    for (i = 0; i < 5; i++)
+    {
+        if ((eeprom->cbus_function[i] > cbus_max[i]) ||
+            (eeprom->cbus_function[i] && eeprom->chip_type != TYPE_R)) return -3;
+    }
+    if (eeprom->chip_type != TYPE_R)
+    {
+        if (eeprom->invert) return -4;
+        if (eeprom->high_current) return -5;
+    }
+
     size_check = eeprom->size;
     size_check -= 28; // 28 are always in use (fixed)
 
@@ -2239,7 +2301,7 @@ int ftdi_eeprom_build(struct ftdi_eeprom *eeprom, unsigned char *output)
     // it seems that the FTDI chip will not read these strings from the lower half
     // Each string starts with two bytes; offset and type (0x03 for string)
     // the checksum needs two bytes, so without the string data that 8 bytes from the top half
-    if (eeprom->size>=256)size_check = 120;
+    if (eeprom->size>=256) size_check = 120;
     size_check -= manufacturer_size*2;
     size_check -= product_size*2;
     size_check -= serial_size*2;
@@ -2251,7 +2313,12 @@ int ftdi_eeprom_build(struct ftdi_eeprom *eeprom, unsigned char *output)
     // empty eeprom
     memset (output, 0, eeprom->size);
 
-    // Addr 00: Stay 00 00
+    // Addr 00: High current IO
+    output[0x00] = eeprom->high_current ? HIGH_CURRENT_DRIVE : 0;
+    // Addr 01: IN endpoint size (for R type devices, different for FT2232)
+    if (eeprom->chip_type == TYPE_R) {
+        output[0x01] = 0x40;
+    }
     // Addr 02: Vendor ID
     output[0x02] = eeprom->vendor_id;
     output[0x03] = eeprom->vendor_id >> 8;
@@ -2262,11 +2329,22 @@ int ftdi_eeprom_build(struct ftdi_eeprom *eeprom, unsigned char *output)
 
     // Addr 06: Device release number (0400h for BM features)
     output[0x06] = 0x00;
-
-    if (eeprom->BM_type_chip == 1)
-        output[0x07] = 0x04;
-    else
-        output[0x07] = 0x02;
+    switch (eeprom->chip_type) {
+        case TYPE_AM:
+            output[0x07] = 0x02;
+            break;
+        case TYPE_BM:
+            output[0x07] = 0x04;
+            break;
+        case TYPE_2232C:
+            output[0x07] = 0x05;
+            break;
+        case TYPE_R:
+            output[0x07] = 0x06;
+            break;
+        default:
+            output[0x07] = 0x00;
+    }
 
     // Addr 08: Config descriptor
     // Bit 7: always 1
@@ -2306,8 +2384,8 @@ int ftdi_eeprom_build(struct ftdi_eeprom *eeprom, unsigned char *output)
         j = j | 16;
     output[0x0A] = j;
 
-    // Addr 0B: reserved
-    output[0x0B] = 0x00;
+    // Addr 0B: Invert data lines
+    output[0x0B] = eeprom->invert & 0xff;
 
     // Addr 0C: USB version low byte when 0x0A bit 4 is set
     // Addr 0D: USB version high byte when 0x0A bit 4 is set
@@ -2330,9 +2408,23 @@ int ftdi_eeprom_build(struct ftdi_eeprom *eeprom, unsigned char *output)
     // Addr 13: Length of serial string
     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
+
     // Dynamic content
-    i=0x14;
-    if (eeprom->size>=256) i = 0x80;
+    // In images produced by FTDI's FT_Prog for FT232R strings start at 0x18
+    // Space till 0x18 should be considered as reserved.
+    if (eeprom->chip_type >= TYPE_R) {
+        i = 0x18;
+    } else {
+        i = 0x14;
+    }
+    if (eeprom->size >= 256) i = 0x80;
 
 
     // Output manufacturer
@@ -2396,37 +2488,23 @@ int ftdi_eeprom_build(struct ftdi_eeprom *eeprom, unsigned char *output)
    FIXME: How to pass size? How to handle size field in ftdi_eeprom?
    FIXME: Strings are malloc'ed here and should be freed somewhere
 */
-int ftdi_eeprom_decode(struct ftdi_eeprom *eeprom, unsigned char *buf, int size)
+int ftdi_eeprom_decode(struct ftdi_context *ftdi, unsigned char *buf, int size)
 {
     unsigned char i, j;
     unsigned short checksum, eeprom_checksum, value;
     unsigned char manufacturer_size = 0, product_size = 0, serial_size = 0;
-    int eeprom_size = 128;
-
-    if (eeprom == NULL)
-        return -1;
-#if 0
-    size_check = eeprom->size;
-    size_check -= 28; // 28 are always in use (fixed)
-
-    // Top half of a 256byte eeprom is used just for strings and checksum
-    // it seems that the FTDI chip will not read these strings from the lower half
-    // Each string starts with two bytes; offset and type (0x03 for string)
-    // the checksum needs two bytes, so without the string data that 8 bytes from the top half
-    if (eeprom->size>=256)size_check = 120;
-    size_check -= manufacturer_size*2;
-    size_check -= product_size*2;
-    size_check -= serial_size*2;
+    int eeprom_size;
+    struct ftdi_eeprom *eeprom;
 
-    // eeprom size exceeded?
-    if (size_check < 0)
-        return (-1);
-#endif
-
-    // empty eeprom struct
-    memset(eeprom, 0, sizeof(struct ftdi_eeprom));
-
-    // Addr 00: Stay 00 00
+    if (ftdi == NULL)
+        ftdi_error_return(-1,"No context");
+    if (ftdi->eeprom == NULL)
+        ftdi_error_return(-1,"No eeprom");
+    eeprom_size = ftdi->eeprom->size;
+    if(ftdi->type == TYPE_R)
+        eeprom_size = 0x80;
+    eeprom = ftdi->eeprom;
 
     // Addr 02: Vendor ID
     eeprom->vendor_id = buf[0x02] + (buf[0x03] << 8);
@@ -2437,14 +2515,17 @@ int ftdi_eeprom_decode(struct ftdi_eeprom *eeprom, unsigned char *buf, int size)
     value = buf[0x06] + (buf[0x07]<<8);
     switch (value)
     {
+        case 0x0600:
+            eeprom->chip_type = TYPE_R;
+            break;
         case 0x0400:
-            eeprom->BM_type_chip = 1;
+            eeprom->chip_type = TYPE_BM;
             break;
         case 0x0200:
-            eeprom->BM_type_chip = 0;
+            eeprom->chip_type = TYPE_AM;
             break;
         default: // Unknown device
-            eeprom->BM_type_chip = 0;
+            eeprom->chip_type = 0;
             break;
     }
 
@@ -2477,7 +2558,8 @@ int ftdi_eeprom_decode(struct ftdi_eeprom *eeprom, unsigned char *buf, int size)
     if (j&0x08) eeprom->use_serial = 1;
     if (j&0x10) eeprom->change_usb_version = 1;
 
-    // Addr 0B: reserved
+    // Addr 0B: Invert data lines
+    eeprom->invert = buf[0x0B];
 
     // Addr 0C: USB version low byte when 0x0A bit 4 is set
     // Addr 0D: USB version high byte when 0x0A bit 4 is set
@@ -2489,44 +2571,72 @@ int ftdi_eeprom_decode(struct ftdi_eeprom *eeprom, unsigned char *buf, int size)
     // Addr 0E: Offset of the manufacturer string + 0x80, calculated later
     // Addr 0F: Length of manufacturer string
     manufacturer_size = buf[0x0F]/2;
-    if (manufacturer_size > 0) eeprom->manufacturer = malloc(manufacturer_size);
+    if (manufacturer_size > 0) 
+    {
+        eeprom->manufacturer = malloc(manufacturer_size);
+        if (eeprom->manufacturer)
+        {
+            // Decode manufacturer
+            i = buf[0x0E]; // offset
+            for (j=0;j<manufacturer_size-1;j++)
+            {
+                eeprom->manufacturer[j] = buf[2*j+i+2];
+            }
+            eeprom->manufacturer[j] = '\0';
+        }
+    }
     else eeprom->manufacturer = NULL;
 
     // Addr 10: Offset of the product string + 0x80, calculated later
     // Addr 11: Length of product string
     product_size = buf[0x11]/2;
-    if (product_size > 0) eeprom->product = malloc(product_size);
+    if (product_size > 0)
+    {
+        eeprom->product = malloc(product_size);
+        if(eeprom->product)
+        {
+            // Decode product name
+            i = buf[0x10]; // offset
+            for (j=0;j<product_size-1;j++)
+            {
+                eeprom->product[j] = buf[2*j+i+2];
+            }
+            eeprom->product[j] = '\0';
+        }
+    }
     else eeprom->product = NULL;
 
     // Addr 12: Offset of the serial string + 0x80, calculated later
     // Addr 13: Length of serial string
     serial_size = buf[0x13]/2;
-    if (serial_size > 0) eeprom->serial = malloc(serial_size);
-    else eeprom->serial = NULL;
-
-    // Decode manufacturer
-    i = buf[0x0E] & 0x7f; // offset
-    for (j=0;j<manufacturer_size-1;j++)
+    if (serial_size > 0)
     {
-        eeprom->manufacturer[j] = buf[2*j+i+2];
-    }
-    eeprom->manufacturer[j] = '\0';
-
-    // Decode product name
-    i = buf[0x10] & 0x7f; // offset
-    for (j=0;j<product_size-1;j++)
-    {
-        eeprom->product[j] = buf[2*j+i+2];
+        eeprom->serial = malloc(serial_size);
+        if(eeprom->serial)
+        {
+            // Decode serial
+            i = buf[0x12]; // offset
+            for (j=0;j<serial_size-1;j++)
+            {
+                eeprom->serial[j] = buf[2*j+i+2];
+            }
+            eeprom->serial[j] = '\0';
+        }
     }
-    eeprom->product[j] = '\0';
+    else eeprom->serial = NULL;
 
-    // Decode serial
-    i = buf[0x12] & 0x7f; // offset
-    for (j=0;j<serial_size-1;j++)
-    {
-        eeprom->serial[j] = buf[2*j+i+2];
+    // Addr 14: CBUS function: CBUS0, CBUS1
+    // Addr 15: CBUS function: CBUS2, CBUS3
+    // Addr 16: CBUS function: CBUS5
+    if (eeprom->chip_type == TYPE_R) {
+        eeprom->cbus_function[0] = buf[0x14] & 0x0f;
+        eeprom->cbus_function[1] = (buf[0x14] >> 4) & 0x0f;
+        eeprom->cbus_function[2] = buf[0x15] & 0x0f;
+        eeprom->cbus_function[3] = (buf[0x15] >> 4) & 0x0f;
+        eeprom->cbus_function[4] = buf[0x16] & 0x0f;
+    } else {
+        for (j=0; j<5; j++) eeprom->cbus_function[j] = 0;
     }
-    eeprom->serial[j] = '\0';
 
     // verify checksum
     checksum = 0xAAAA;
@@ -2545,7 +2655,7 @@ int ftdi_eeprom_decode(struct ftdi_eeprom *eeprom, unsigned char *buf, int size)
     if (eeprom_checksum != checksum)
     {
         fprintf(stderr, "Checksum Error: %04x %04x\n", checksum, eeprom_checksum);
-        return -1;
+        ftdi_error_return(-1,"EEPROM checksum error");
     }
 
     return 0;
@@ -2567,7 +2677,7 @@ int ftdi_read_eeprom_location (struct ftdi_context *ftdi, int eeprom_addr, unsig
     if (ftdi == NULL || ftdi->usb_dev == NULL)
         ftdi_error_return(-2, "USB device unavailable");
 
-    if (libusb_control_transfer(ftdi->usb_dev, FTDI_DEVICE_IN_REQTYPE, SIO_READ_EEPROM_REQUEST, 0, eeprom_addr, (char *)eeprom_val, 2, ftdi->usb_read_timeout) != 2)
+    if (libusb_control_transfer(ftdi->usb_dev, FTDI_DEVICE_IN_REQTYPE, SIO_READ_EEPROM_REQUEST, 0, eeprom_addr, (unsigned char *)eeprom_val, 2, ftdi->usb_read_timeout) != 2)
         ftdi_error_return(-1, "reading eeprom failed");
 
     return 0;
@@ -2590,12 +2700,24 @@ int ftdi_read_eeprom(struct ftdi_context *ftdi, unsigned char *eeprom)
     if (ftdi == NULL || ftdi->usb_dev == NULL)
         ftdi_error_return(-2, "USB device unavailable");
 
-    for (i = 0; i < ftdi->eeprom_size/2; i++)
+    for (i = 0; i < FTDI_MAX_EEPROM_SIZE/2; i++)
     {
         if (libusb_control_transfer(ftdi->usb_dev, FTDI_DEVICE_IN_REQTYPE, SIO_READ_EEPROM_REQUEST, 0, i, eeprom+(i*2), 2, ftdi->usb_read_timeout) != 2)
             ftdi_error_return(-1, "reading eeprom failed");
     }
 
+    if (ftdi->type == TYPE_R)
+        ftdi->eeprom->size = 0xa0;
+    /*    Guesses size of eeprom by comparing halves 
+          - will not work with blank eeprom */
+    else if (strrchr((const char *)eeprom, 0xff) == ((const char *)eeprom +FTDI_MAX_EEPROM_SIZE -1))
+        ftdi->eeprom->size = -1;
+    else if(memcmp(eeprom,&eeprom[0x80],0x80) == 0)
+        ftdi->eeprom->size = 0x80;
+    else if(memcmp(eeprom,&eeprom[0x40],0x40) == 0)
+        ftdi->eeprom->size = 0x40;
+    else
+        ftdi->eeprom->size = 0x100;
     return 0;
 }
 
@@ -2651,43 +2773,6 @@ int ftdi_read_chipid(struct ftdi_context *ftdi, unsigned int *chipid)
 }
 
 /**
-    Guesses size of eeprom by reading eeprom and comparing halves - will not work with blank eeprom
-    Call this function then do a write then call again to see if size changes, if so write again.
-
-    \param ftdi pointer to ftdi_context
-    \param eeprom Pointer to store eeprom into
-    \param maxsize the size of the buffer to read into
-
-    \retval -1: eeprom read failed
-    \retval -2: USB device unavailable
-    \retval >=0: size of eeprom
-*/
-int ftdi_read_eeprom_getsize(struct ftdi_context *ftdi, unsigned char *eeprom, int maxsize)
-{
-    int i=0,j,minsize=32;
-    int size=minsize;
-
-    if (ftdi == NULL || ftdi->usb_dev == NULL)
-        ftdi_error_return(-2, "USB device unavailable");
-
-    do
-    {
-        for (j = 0; i < maxsize/2 && j<size; j++)
-        {
-            if (libusb_control_transfer(ftdi->usb_dev, FTDI_DEVICE_IN_REQTYPE,
-                                        SIO_READ_EEPROM_REQUEST, 0, i,
-                                        eeprom+(i*2), 2, ftdi->usb_read_timeout) != 2)
-                ftdi_error_return(-1, "eeprom read failed");
-            i++;
-        }
-        size*=2;
-    }
-    while (size<=maxsize && memcmp(eeprom,&eeprom[size/2],size/2)!=0);
-
-    return size/2;
-}
-
-/**
     Write eeprom location
 
     \param ftdi pointer to ftdi_context
@@ -2737,7 +2822,7 @@ int ftdi_write_eeprom(struct ftdi_context *ftdi, unsigned char *eeprom)
     if ((ret = ftdi_set_latency_timer(ftdi, 0x77)) != 0)
         return ret;
 
-    for (i = 0; i < ftdi->eeprom_size/2; i++)
+    for (i = 0; i < ftdi->eeprom->size/2; i++)
     {
         usb_val = eeprom[i*2];
         usb_val += eeprom[(i*2)+1] << 8;