Don't install baud_test program
[libftdi] / src / ftdi.c
index c62ede7..a87d653 100644 (file)
         return code;                       \
    } while(0);
 
+/**
+    Internal function to close usb device pointer.
+    Sets ftdi->usb_dev to NULL.
+    \internal
+
+    \param ftdi pointer to ftdi_context
+
+    \retval  zero if all is fine, otherwise error code from usb_close()
+*/
+static int ftdi_usb_close_internal (struct ftdi_context *ftdi)
+{
+    int ret = 0;
+
+    if (ftdi->usb_dev)
+    {
+       ret = usb_close (ftdi->usb_dev);
+       ftdi->usb_dev = NULL;
+    }
+
+    return ret;
+}
 
 /**
     Initializes a ftdi_context.
@@ -77,6 +98,7 @@ int ftdi_init(struct ftdi_context *ftdi)
     ftdi->readbuffer_offset = 0;
     ftdi->readbuffer_remaining = 0;
     ftdi->writebuffer_chunksize = 4096;
+    ftdi->max_packet_size = 0;
 
     ftdi->interface = 0;
     ftdi->index = 0;
@@ -110,7 +132,7 @@ int ftdi_init(struct ftdi_context *ftdi)
 
     \return a pointer to a new ftdi_context, or NULL on failure
 */
-struct ftdi_context *ftdi_new()
+struct ftdi_context *ftdi_new(void)
 {
     struct ftdi_context * ftdi = (struct ftdi_context *)malloc(sizeof(struct ftdi_context));
 
@@ -132,7 +154,7 @@ struct ftdi_context *ftdi_new()
     Open selected channels on a chip, otherwise use first channel.
 
     \param ftdi pointer to ftdi_context
-    \param interface Interface to use for FT2232C chips.
+    \param interface Interface to use for FT2232C/2232H/4232H chips.
 
     \retval  0: all fine
     \retval -1: unknown interface
@@ -151,6 +173,18 @@ int ftdi_set_interface(struct ftdi_context *ftdi, enum ftdi_interface interface)
             ftdi->in_ep     = 0x04;
             ftdi->out_ep    = 0x83;
             break;
+        case INTERFACE_C:
+            ftdi->interface = 2;
+            ftdi->index     = INTERFACE_C;
+            ftdi->in_ep     = 0x06;
+            ftdi->out_ep    = 0x85;
+            break;
+        case INTERFACE_D:
+            ftdi->interface = 3;
+            ftdi->index     = INTERFACE_D;
+            ftdi->in_ep     = 0x08;
+            ftdi->out_ep    = 0x87;
+            break;
         default:
             ftdi_error_return(-1, "Unknown interface");
     }
@@ -164,6 +198,8 @@ int ftdi_set_interface(struct ftdi_context *ftdi, enum ftdi_interface interface)
 */
 void ftdi_deinit(struct ftdi_context *ftdi)
 {
+    ftdi_usb_close_internal (ftdi);
+
     if (ftdi->async_usb_buffer != NULL)
     {
         free(ftdi->async_usb_buffer);
@@ -320,7 +356,7 @@ int ftdi_usb_get_strings(struct ftdi_context * ftdi, struct usb_device * dev,
     {
         if (usb_get_string_simple(ftdi->usb_dev, dev->descriptor.iManufacturer, manufacturer, mnf_len) <= 0)
         {
-            usb_close (ftdi->usb_dev);
+            ftdi_usb_close_internal (ftdi);
             ftdi_error_return(-7, usb_strerror());
         }
     }
@@ -329,7 +365,7 @@ int ftdi_usb_get_strings(struct ftdi_context * ftdi, struct usb_device * dev,
     {
         if (usb_get_string_simple(ftdi->usb_dev, dev->descriptor.iProduct, description, desc_len) <= 0)
         {
-            usb_close (ftdi->usb_dev);
+            ftdi_usb_close_internal (ftdi);
             ftdi_error_return(-8, usb_strerror());
         }
     }
@@ -338,18 +374,57 @@ int ftdi_usb_get_strings(struct ftdi_context * ftdi, struct usb_device * dev,
     {
         if (usb_get_string_simple(ftdi->usb_dev, dev->descriptor.iSerialNumber, serial, serial_len) <= 0)
         {
-            usb_close (ftdi->usb_dev);
+            ftdi_usb_close_internal (ftdi);
             ftdi_error_return(-9, usb_strerror());
         }
     }
 
-    if (usb_close (ftdi->usb_dev) != 0)
+    if (ftdi_usb_close_internal (ftdi) != 0)
         ftdi_error_return(-10, usb_strerror());
 
     return 0;
 }
 
 /**
+ * Internal function to determine the maximum packet size.
+ * \param ftdi pointer to ftdi_context
+ * \param dev libusb usb_dev to use
+ * \retval Maximum packet size for this device
+ */
+static unsigned int _ftdi_determine_max_packet_size(struct ftdi_context *ftdi, struct usb_device *dev)
+{
+    unsigned int packet_size;
+
+    // Determine maximum packet size. Init with default value.
+    // New hi-speed devices from FTDI use a packet size of 512 bytes
+    // but could be connected to a normal speed USB hub -> 64 bytes packet size.
+    if (ftdi->type == TYPE_2232H || ftdi->type == TYPE_4232H)
+        packet_size = 512;
+    else
+        packet_size = 64;
+
+    if (dev->descriptor.bNumConfigurations > 0 && dev->config)
+    {
+        struct usb_config_descriptor config = dev->config[0];
+
+        if (ftdi->interface < config.bNumInterfaces)
+        {
+            struct usb_interface interface = config.interface[ftdi->interface];
+            if (interface.num_altsetting > 0)
+            {
+                struct usb_interface_descriptor descriptor = interface.altsetting[0];
+                if (descriptor.bNumEndpoints > 0)
+                {
+                    packet_size = descriptor.endpoint[0].wMaxPacketSize;
+                }
+            }
+        }
+    }
+
+    return packet_size;
+}
+
+/**
     Opens a ftdi device given by a usb_device.
 
     \param ftdi pointer to ftdi_context
@@ -365,6 +440,7 @@ int ftdi_usb_get_strings(struct ftdi_context * ftdi, struct usb_device * dev,
 int ftdi_usb_open_dev(struct ftdi_context *ftdi, struct usb_device *dev)
 {
     int detach_errno = 0;
+    int config_val = 1;
     if (!(ftdi->usb_dev = usb_open(dev)))
         ftdi_error_return(-4, "usb_open() failed");
 
@@ -380,27 +456,36 @@ int ftdi_usb_open_dev(struct ftdi_context *ftdi, struct usb_device *dev)
         detach_errno = errno;
 #endif
 
+#ifdef __WIN32__
     // set configuration (needed especially for windows)
     // tolerate EBUSY: one device with one configuration, but two interfaces
     //    and libftdi sessions to both interfaces (e.g. FT2232)
-    if (dev->descriptor.bNumConfigurations > 0 &&
-            usb_set_configuration(ftdi->usb_dev, dev->config[0].bConfigurationValue) &&
-            errno != EBUSY)
+
+    if (dev->descriptor.bNumConfigurations > 0)
     {
-        usb_close (ftdi->usb_dev);
-        if (detach_errno == EPERM)
-        {
-            ftdi_error_return(-8, "inappropriate permissions on device!");
-        }
-        else
+        // libusb-win32 on Windows 64 can return a null pointer for a valid device
+        if (dev->config)
+            config_val = dev->config[0].bConfigurationValue;
+
+        if (usb_set_configuration(ftdi->usb_dev, config_val) &&
+            errno != EBUSY)
         {
-            ftdi_error_return(-3, "unable to set usb configuration. Make sure ftdi_sio is unloaded!");
+            ftdi_usb_close_internal (ftdi);
+            if (detach_errno == EPERM)
+            {
+                ftdi_error_return(-8, "inappropriate permissions on device!");
+            }
+            else
+            {
+                ftdi_error_return(-3, "unable to set usb configuration. Make sure ftdi_sio is unloaded!");
+            }
         }
     }
+#endif
 
     if (usb_claim_interface(ftdi->usb_dev, ftdi->interface) != 0)
     {
-        usb_close (ftdi->usb_dev);
+        ftdi_usb_close_internal (ftdi);
         if (detach_errno == EPERM)
         {
             ftdi_error_return(-8, "inappropriate permissions on device!");
@@ -413,16 +498,10 @@ int ftdi_usb_open_dev(struct ftdi_context *ftdi, struct usb_device *dev)
 
     if (ftdi_usb_reset (ftdi) != 0)
     {
-        usb_close (ftdi->usb_dev);
+        ftdi_usb_close_internal (ftdi);
         ftdi_error_return(-6, "ftdi_usb_reset failed");
     }
 
-    if (ftdi_set_baudrate (ftdi, 9600) != 0)
-    {
-        usb_close (ftdi->usb_dev);
-        ftdi_error_return(-7, "set baudrate failed");
-    }
-
     // 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
@@ -431,13 +510,35 @@ int ftdi_usb_open_dev(struct ftdi_context *ftdi, struct usb_device *dev)
     else if (dev->descriptor.bcdDevice == 0x200)
         ftdi->type = TYPE_AM;
     else if (dev->descriptor.bcdDevice == 0x500)
-    {
         ftdi->type = TYPE_2232C;
-        if (!ftdi->index)
-            ftdi->index = INTERFACE_A;
-    }
     else if (dev->descriptor.bcdDevice == 0x600)
         ftdi->type = TYPE_R;
+    else if (dev->descriptor.bcdDevice == 0x700)
+        ftdi->type = TYPE_2232H;
+    else if (dev->descriptor.bcdDevice == 0x800)
+        ftdi->type = TYPE_4232H;
+
+    // Set default interface on dual/quad type chips
+    switch(ftdi->type)
+    {
+        case TYPE_2232C:
+        case TYPE_2232H:
+        case TYPE_4232H:
+            if (!ftdi->index)
+                ftdi->index = INTERFACE_A;
+            break;
+        default:
+            break;
+    }
+
+    // Determine maximum packet size
+    ftdi->max_packet_size = _ftdi_determine_max_packet_size(ftdi, dev);
+
+    if (ftdi_set_baudrate (ftdi, 9600) != 0)
+    {
+        ftdi_usb_close_internal (ftdi);
+        ftdi_error_return(-7, "set baudrate failed");
+    }
 
     ftdi_error_return(0, "all fine");
 }
@@ -506,12 +607,12 @@ int ftdi_usb_open_desc(struct ftdi_context *ftdi, int vendor, int product,
                 {
                     if (usb_get_string_simple(ftdi->usb_dev, dev->descriptor.iProduct, string, sizeof(string)) <= 0)
                     {
-                        usb_close (ftdi->usb_dev);
+                        ftdi_usb_close_internal (ftdi);
                         ftdi_error_return(-8, "unable to fetch product description");
                     }
                     if (strncmp(string, description, sizeof(string)) != 0)
                     {
-                        if (usb_close (ftdi->usb_dev) != 0)
+                        if (ftdi_usb_close_internal (ftdi) != 0)
                             ftdi_error_return(-10, "unable to close device");
                         continue;
                     }
@@ -520,18 +621,18 @@ int ftdi_usb_open_desc(struct ftdi_context *ftdi, int vendor, int product,
                 {
                     if (usb_get_string_simple(ftdi->usb_dev, dev->descriptor.iSerialNumber, string, sizeof(string)) <= 0)
                     {
-                        usb_close (ftdi->usb_dev);
+                        ftdi_usb_close_internal (ftdi);
                         ftdi_error_return(-9, "unable to fetch serial number");
                     }
                     if (strncmp(string, serial, sizeof(string)) != 0)
                     {
-                        if (usb_close (ftdi->usb_dev) != 0)
+                        if (ftdi_usb_close_internal (ftdi) != 0)
                             ftdi_error_return(-10, "unable to close device");
                         continue;
                     }
                 }
 
-                if (usb_close (ftdi->usb_dev) != 0)
+                if (ftdi_usb_close_internal (ftdi) != 0)
                     ftdi_error_return(-10, "unable to close device");
 
                 return ftdi_usb_open_dev(ftdi, dev);
@@ -629,6 +730,8 @@ int ftdi_usb_purge_buffers(struct ftdi_context *ftdi)
     return 0;
 }
 
+
+
 /**
     Closes the ftdi device. Call ftdi_deinit() if you're cleaning up.
 
@@ -647,10 +750,11 @@ int ftdi_usb_close(struct ftdi_context *ftdi)
     ftdi_async_complete(ftdi,1);
 #endif
 
-    if (usb_release_interface(ftdi->usb_dev, ftdi->interface) != 0)
-        rtn = -1;
+    if (ftdi->usb_dev != NULL)
+        if (usb_release_interface(ftdi->usb_dev, ftdi->interface) != 0)
+            rtn = -1;
 
-    if (usb_close (ftdi->usb_dev) != 0)
+    if (ftdi_usb_close_internal (ftdi) != 0)
         rtn = -2;
 
     return rtn;
@@ -769,7 +873,7 @@ static int ftdi_convert_baudrate(int baudrate, struct ftdi_context *ftdi,
     }
     // Split into "value" and "index" values
     *value = (unsigned short)(encoded_divisor & 0xFFFF);
-    if (ftdi->type == TYPE_2232C)
+    if (ftdi->type == TYPE_2232C || ftdi->type == TYPE_2232H || ftdi->type == TYPE_4232H)
     {
         *index = (unsigned short)(encoded_divisor >> 8);
         *index &= 0xFF00;
@@ -944,6 +1048,9 @@ int ftdi_write_data(struct ftdi_context *ftdi, unsigned char *buf, int size)
 }
 
 #ifdef LIBFTDI_LINUX_ASYNC_MODE
+#ifdef USB_CLASS_PTP
+#error LIBFTDI_LINUX_ASYNC_MODE is not compatible with libusb-compat-0.1!
+#endif
 /* this is strongly dependent on libusb using the same struct layout. If libusb
    changes in some later version this may break horribly (this is for libusb 0.1.12) */
 struct usb_dev_handle
@@ -1202,6 +1309,11 @@ int ftdi_write_data_get_chunksize(struct ftdi_context *ftdi, unsigned int *chunk
 int ftdi_read_data(struct ftdi_context *ftdi, unsigned char *buf, int size)
 {
     int offset = 0, ret = 1, i, num_of_chunks, chunk_remains;
+    int packet_size = ftdi->max_packet_size;
+
+    // Packet size sanity check (avoid division by zero)
+    if (packet_size == 0)
+        ftdi_error_return(-1, "max_packet_size is bogus (zero)");
 
     // everything we want is still in the readbuffer?
     if (size <= ftdi->readbuffer_remaining)
@@ -1238,23 +1350,23 @@ int ftdi_read_data(struct ftdi_context *ftdi, unsigned char *buf, int size)
         {
             // skip FTDI status bytes.
             // Maybe stored in the future to enable modem use
-            num_of_chunks = ret / 64;
-            chunk_remains = ret % 64;
+            num_of_chunks = ret / packet_size;
+            chunk_remains = ret % packet_size;
             //printf("ret = %X, num_of_chunks = %X, chunk_remains = %X, readbuffer_offset = %X\n", ret, num_of_chunks, chunk_remains, ftdi->readbuffer_offset);
 
             ftdi->readbuffer_offset += 2;
             ret -= 2;
 
-            if (ret > 62)
+            if (ret > packet_size - 2)
             {
                 for (i = 1; i < num_of_chunks; i++)
-                    memmove (ftdi->readbuffer+ftdi->readbuffer_offset+62*i,
-                             ftdi->readbuffer+ftdi->readbuffer_offset+64*i,
-                             62);
+                    memmove (ftdi->readbuffer+ftdi->readbuffer_offset+(packet_size - 2)*i,
+                             ftdi->readbuffer+ftdi->readbuffer_offset+packet_size*i,
+                             packet_size - 2);
                 if (chunk_remains > 2)
                 {
-                    memmove (ftdi->readbuffer+ftdi->readbuffer_offset+62*i,
-                             ftdi->readbuffer+ftdi->readbuffer_offset+64*i,
+                    memmove (ftdi->readbuffer+ftdi->readbuffer_offset+(packet_size - 2)*i,
+                             ftdi->readbuffer+ftdi->readbuffer_offset+packet_size*i,
                              chunk_remains-2);
                     ret -= 2*num_of_chunks;
                 }
@@ -1909,7 +2021,7 @@ int ftdi_eeprom_build(struct ftdi_eeprom *eeprom, unsigned char *output)
    Decode binary EEPROM image into an ftdi_eeprom structure.
 
    \param eeprom Pointer to ftdi_eeprom which will be filled in.
-   \param output Buffer of \a size bytes of raw eeprom data
+   \param buf Buffer of \a size bytes of raw eeprom data
    \param size size size of eeprom data in bytes
 
    \retval 0: all fine
@@ -2072,6 +2184,24 @@ int ftdi_eeprom_decode(struct ftdi_eeprom *eeprom, unsigned char *buf, int size)
 }
 
 /**
+    Read eeprom location
+
+    \param ftdi pointer to ftdi_context
+    \param eeprom_addr Address of eeprom location to be read
+    \param eeprom_val Pointer to store read eeprom location
+
+    \retval  0: all fine
+    \retval -1: read failed
+*/
+int ftdi_read_eeprom_location (struct ftdi_context *ftdi, int eeprom_addr, unsigned short *eeprom_val)
+{
+    if (usb_control_msg(ftdi->usb_dev, FTDI_DEVICE_IN_REQTYPE, SIO_READ_EEPROM_REQUEST, 0, eeprom_addr, (char *)eeprom_val, 2, ftdi->usb_read_timeout) != 2)
+        ftdi_error_return(-1, "reading eeprom failed");
+
+    return 0;
+}
+
+/**
     Read eeprom
 
     \param ftdi pointer to ftdi_context
@@ -2173,6 +2303,26 @@ int ftdi_read_eeprom_getsize(struct ftdi_context *ftdi, unsigned char *eeprom, i
 }
 
 /**
+    Write eeprom location
+
+    \param ftdi pointer to ftdi_context
+    \param eeprom_addr Address of eeprom location to be written
+    \param eeprom_val Value to be written
+
+    \retval  0: all fine
+    \retval -1: read failed
+*/
+int ftdi_write_eeprom_location(struct ftdi_context *ftdi, int eeprom_addr, unsigned short eeprom_val)
+{
+    if (usb_control_msg(ftdi->usb_dev, FTDI_DEVICE_OUT_REQTYPE,
+                                    SIO_WRITE_EEPROM_REQUEST, eeprom_val, eeprom_addr,
+                                    NULL, 0, ftdi->usb_write_timeout) != 0)
+        ftdi_error_return(-1, "unable to write eeprom");
+
+    return 0;
+}
+
+/**
     Write eeprom
 
     \param ftdi pointer to ftdi_context