libftdi: (tomj) Improved error handling (Evgeny Sinelnikov)
[libftdi] / ftdi / ftdi.c
index 22039b9..6f4c39b 100644 (file)
@@ -44,8 +44,11 @@ int ftdi_init(struct ftdi_context *ftdi) {
 
     ftdi->error_str = NULL;
 
-    // all fine. Now allocate the readbuffer
-    return ftdi_read_data_set_chunksize(ftdi, 4096);
+    /* All fine. Now allocate the readbuffer
+       Note: A readbuffer size above 64 bytes results in buggy input.
+             This seems to be a hardware limitation as noted
+            in the ftdi_sio driver */
+    return ftdi_read_data_set_chunksize(ftdi, 64);
 }
 
 
@@ -104,6 +107,16 @@ int ftdi_usb_open(struct ftdi_context *ftdi, int vendor, int product) {
                     if (ftdi_set_baudrate (ftdi, 9600) != 0)
                         return -7;
 
+                   // Try to guess chip type
+                   // Bug in the BM type chips: bcdDevice is 0x200 for serial == 0
+                   if (dev->descriptor.bcdDevice == 0x400 || (dev->descriptor.bcdDevice == 0x200
+                            && dev->descriptor.iSerialNumber == 0))
+                       ftdi->type = TYPE_BM;
+                   else if (dev->descriptor.bcdDevice == 0x200)
+                       ftdi->type = TYPE_AM;
+                   else if (dev->descriptor.bcdDevice == 0x500)
+                       ftdi->type = TYPE_2232C;
+
                     return 0;
                 } else {
                     ftdi->error_str = "usb_open() failed";
@@ -171,7 +184,7 @@ int ftdi_usb_close(struct ftdi_context *ftdi) {
     ftdi_convert_baudrate returns nearest supported baud rate to that requested.
     Function is only used internally
 */
-static int ftdi_convert_baudrate(int baudrate, int is_amchip,
+static int ftdi_convert_baudrate(int baudrate, struct ftdi_context *ftdi,
                                  unsigned short *value, unsigned short *index) {
     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};
@@ -187,7 +200,7 @@ static int ftdi_convert_baudrate(int baudrate, int is_amchip,
 
     divisor = 24000000 / baudrate;
 
-    if (is_amchip) {
+    if (ftdi->type == TYPE_AM) {
         // Round down to supported fraction (AM only)
         divisor -= am_adjust_dn[divisor & 7];
     }
@@ -205,14 +218,14 @@ static int ftdi_convert_baudrate(int baudrate, int is_amchip,
         if (try_divisor < 8) {
             // Round up to minimum supported divisor
             try_divisor = 8;
-        } else if (!is_amchip && try_divisor < 12) {
+        } 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
             try_divisor = 16;
         } else {
-            if (is_amchip) {
+            if (ftdi->type == TYPE_AM) {
                 // Round up to supported fraction (AM only)
                 try_divisor += am_adjust_up[try_divisor & 7];
                 if (try_divisor > 0x1FFF8) {
@@ -255,7 +268,14 @@ static int ftdi_convert_baudrate(int baudrate, int is_amchip,
     }
     // Split into "value" and "index" values
     *value = (unsigned short)(encoded_divisor & 0xFFFF);
-    *index = (unsigned short)(encoded_divisor >> 16);
+    if(ftdi->type == TYPE_2232C) {
+        *index = (unsigned short)(encoded_divisor >> 8);
+        *index &= 0xFF00;
+        *index |= ftdi->interface;
+    }
+    else
+        *index = (unsigned short)(encoded_divisor >> 16);
+    
     // Return the nearest baud rate
     return best_baud;
 }
@@ -274,7 +294,7 @@ int ftdi_set_baudrate(struct ftdi_context *ftdi, int baudrate) {
         baudrate = baudrate*4;
     }
 
-    actual_baudrate = convert_baudrate(baudrate, ftdi->type == TYPE_AM ? 1 : 0, &value, &index);
+    actual_baudrate = ftdi_convert_baudrate(baudrate, ftdi, &value, &index);
     if (actual_baudrate <= 0) {
         ftdi->error_str = "Silly baudrate <= 0.";
         return -1;
@@ -310,9 +330,12 @@ int ftdi_write_data(struct ftdi_context *ftdi, unsigned char *buf, int size) {
             write_size = size-offset;
 
         ret = usb_bulk_write(ftdi->usb_dev, ftdi->in_ep, buf+offset, write_size, ftdi->usb_write_timeout);
-        if (ret == -1) {
-            ftdi->error_str = "bulk write failed";
-            return -1;
+        if (ret < 0) {
+            if (ret == -1)
+                ftdi->error_str = "bulk write failed";
+            else
+                ftdi->error_str = "usb failed";
+            return ret;
         }
         total_written += ret;
 
@@ -364,9 +387,12 @@ int ftdi_read_data(struct ftdi_context *ftdi, unsigned char *buf, int size) {
         /* returns how much received */
         ret = usb_bulk_read (ftdi->usb_dev, ftdi->out_ep, ftdi->readbuffer, ftdi->readbuffer_chunksize, ftdi->usb_read_timeout);
 
-        if (ret == -1) {
-            ftdi->error_str = "bulk read failed";
-            return -1;
+        if (ret < 0) {
+            if (ret == -1)
+                ftdi->error_str = "bulk read failed";
+            else
+                ftdi->error_str = "usb failed";
+            return ret;
         }
 
         if (ret > 2) {
@@ -405,16 +431,17 @@ int ftdi_read_data(struct ftdi_context *ftdi, unsigned char *buf, int size) {
         }
     }
     // never reached
-    return -2;
+    return -127;
 }
 
 
 int ftdi_read_data_set_chunksize(struct ftdi_context *ftdi, unsigned int chunksize) {
+    unsigned char *new_buf;
+
     // Invalidate all remaining data
     ftdi->readbuffer_offset = 0;
     ftdi->readbuffer_remaining = 0;
 
-    unsigned char *new_buf;
     if ((new_buf = (unsigned char *)realloc(ftdi->readbuffer, chunksize)) == NULL) {
         ftdi->error_str = "out of memory for readbuffer";
         return -1;
@@ -427,7 +454,7 @@ int ftdi_read_data_set_chunksize(struct ftdi_context *ftdi, unsigned int chunksi
 }
 
 
-int ftdi_readt_data_get_chunksize(struct ftdi_context *ftdi, unsigned int *chunksize) {
+int ftdi_read_data_get_chunksize(struct ftdi_context *ftdi, unsigned int *chunksize) {
     *chunksize = ftdi->readbuffer_chunksize;
     return 0;
 }
@@ -503,8 +530,8 @@ int ftdi_get_latency_timer(struct ftdi_context *ftdi, unsigned char *latency) {
 
 
 void ftdi_eeprom_initdefaults(struct ftdi_eeprom *eeprom) {
-    eeprom->vendor_id = 0403;
-    eeprom->product_id = 6001;
+    eeprom->vendor_id = 0x0403;
+    eeprom->product_id = 0x6001;
 
     eeprom->self_powered = 1;
     eeprom->remote_wakeup = 1;
@@ -516,7 +543,7 @@ void ftdi_eeprom_initdefaults(struct ftdi_eeprom *eeprom) {
 
     eeprom->use_serial = 0;
     eeprom->change_usb_version = 0;
-    eeprom->usb_version = 200;
+    eeprom->usb_version = 0x0200;
     eeprom->max_power = 0;
 
     eeprom->manufacturer = NULL;