X-Git-Url: http://developer.intra2net.com/git/?p=libftdi;a=blobdiff_plain;f=src%2Fftdi.c;h=a87d6537a1f700162360c78d631bb3ee50121270;hp=d2c4a1163008fe27cb46129a527d2c2aa705b7a2;hb=0c93de8177ee7310292ac7eab4c2e3ff993b4f2f;hpb=ef6f483889aa3d719a676f7f32303c4232941e57 diff --git a/src/ftdi.c b/src/ftdi.c index d2c4a11..a87d653 100644 --- a/src/ftdi.c +++ b/src/ftdi.c @@ -98,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; @@ -385,6 +386,45 @@ int ftdi_usb_get_strings(struct ftdi_context * ftdi, struct usb_device * dev, } /** + * 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 @@ -400,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"); @@ -419,18 +460,25 @@ int ftdi_usb_open_dev(struct ftdi_context *ftdi, struct usb_device *dev) // 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) { - ftdi_usb_close_internal (ftdi); - 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 @@ -483,6 +531,9 @@ int ftdi_usb_open_dev(struct ftdi_context *ftdi, struct usb_device *dev) 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); @@ -822,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; @@ -1258,13 +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; + int packet_size = ftdi->max_packet_size; - // New hi-speed devices from FTDI use a packet size of 512 bytes - if (ftdi->type == TYPE_2232H || ftdi->type == TYPE_4232H) - packet_size = 512; - else - packet_size = 64; + // 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)