X-Git-Url: http://developer.intra2net.com/git/?p=libftdi;a=blobdiff_plain;f=src%2Fftdi.c;h=6d0163f20968c7ffa4f1091454ebb56f266b018f;hp=cb065c59d06e7b7396522e901f710a4b881f929e;hb=efc843050e8d0eaef34cef36db7c4acfec7830ff;hpb=b113915025b9bdcb85112897727953f55818e90f diff --git a/src/ftdi.c b/src/ftdi.c index cb065c5..6d0163f 100644 --- a/src/ftdi.c +++ b/src/ftdi.c @@ -2,7 +2,7 @@ ftdi.c - description ------------------- begin : Fri Apr 4 2003 - copyright : (C) 2003-2008 by Intra2net AG + copyright : (C) 2003-2010 by Intra2net AG email : opensource@intra2net.com ***************************************************************************/ @@ -41,6 +41,12 @@ return code; \ } while(0); +#define ftdi_error_return_free_device_list(code, str, devs) do { \ + libusb_free_device_list(devs,1); \ + ftdi->error_str = str; \ + return code; \ + } while(0); + /** Internal function to close usb device pointer. @@ -53,7 +59,7 @@ */ static void ftdi_usb_close_internal (struct ftdi_context *ftdi) { - if (ftdi->usb_dev) + if (ftdi && ftdi->usb_dev) { libusb_close (ftdi->usb_dev); ftdi->usb_dev = NULL; @@ -72,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; @@ -94,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); @@ -131,9 +138,13 @@ struct ftdi_context *ftdi_new(void) \retval 0: all fine \retval -1: unknown interface + \retval -2: USB device unavailable */ int ftdi_set_interface(struct ftdi_context *ftdi, enum ftdi_interface interface) { + if (ftdi == NULL) + ftdi_error_return(-2, "USB device unavailable"); + switch (interface) { case INTERFACE_ANY: @@ -171,6 +182,9 @@ int ftdi_set_interface(struct ftdi_context *ftdi, enum ftdi_interface interface) */ void ftdi_deinit(struct ftdi_context *ftdi) { + if (ftdi == NULL) + return; + ftdi_usb_close_internal (ftdi); if (ftdi->readbuffer != NULL) @@ -178,6 +192,7 @@ void ftdi_deinit(struct ftdi_context *ftdi) free(ftdi->readbuffer); ftdi->readbuffer = NULL; } + libusb_exit(ftdi->usb_ctx); } /** @@ -199,6 +214,9 @@ void ftdi_free(struct ftdi_context *ftdi) */ void ftdi_set_usbdev (struct ftdi_context *ftdi, libusb_device_handle *usb) { + if (ftdi == NULL) + return; + ftdi->usb_dev = usb; } @@ -226,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; @@ -372,6 +390,10 @@ static unsigned int _ftdi_determine_max_packet_size(struct ftdi_context *ftdi, l struct libusb_config_descriptor *config0; unsigned int packet_size; + // Sanity check + if (ftdi == NULL || dev == NULL) + return 64; + // 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. @@ -418,6 +440,7 @@ static unsigned int _ftdi_determine_max_packet_size(struct ftdi_context *ftdi, l \retval -5: unable to claim device \retval -6: reset failed \retval -7: set baudrate failed + \retval -8: ftdi context invalid \retval -9: libusb_get_device_descriptor() failed \retval -10: libusb_get_config_descriptor() failed \retval -11: libusb_etach_kernel_driver() failed @@ -427,7 +450,10 @@ int ftdi_usb_open_dev(struct ftdi_context *ftdi, libusb_device *dev) { struct libusb_device_descriptor desc; struct libusb_config_descriptor *config0; - int cfg, cfg0; + int cfg, cfg0, detach_errno = 0; + + if (ftdi == NULL) + ftdi_error_return(-8, "ftdi context invalid"); if (libusb_open(dev, &ftdi->usb_dev) < 0) ftdi_error_return(-4, "libusb_open() failed"); @@ -440,22 +466,17 @@ int ftdi_usb_open_dev(struct ftdi_context *ftdi, libusb_device *dev) cfg0 = config0->bConfigurationValue; libusb_free_config_descriptor (config0); -#ifdef LIBUSB_HAS_GET_DRIVER_NP // Try to detach ftdi_sio kernel module. - // Returns ENODATA if driver is not loaded. // // The return code is kept in a separate variable and only parsed // if usb_set_configuration() or usb_claim_interface() fails as the // detach operation might be denied and everything still works fine. // Likely scenario is a static ftdi_sio kernel module. - ret = libusb_detach_kernel_driver(ftdi->usb_dev, ftdi->interface); - if (ret < 0 && ret != LIBUSB_ERROR_NOT_FOUND) - ftdi_error_return(-11, "libusb_detach_kernel_driver () failed"); -#endif + if (libusb_detach_kernel_driver(ftdi->usb_dev, ftdi->interface) !=0) + detach_errno = errno; if (libusb_get_configuration (ftdi->usb_dev, &cfg) < 0) ftdi_error_return(-12, "libusb_get_configuration () failed"); - // 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) @@ -464,14 +485,28 @@ int ftdi_usb_open_dev(struct ftdi_context *ftdi, libusb_device *dev) if (libusb_set_configuration(ftdi->usb_dev, cfg0) < 0) { ftdi_usb_close_internal (ftdi); - ftdi_error_return(-3, "unable to set usb configuration. Make sure ftdi_sio is unloaded!"); + if(detach_errno == EPERM) + { + ftdi_error_return(-8, "inappropriate permissions on device!"); + } + else + { + ftdi_error_return(-3, "unable to set usb configuration. Make sure the default FTDI driver is not in use"); + } } } if (libusb_claim_interface(ftdi->usb_dev, ftdi->interface) < 0) { ftdi_usb_close_internal (ftdi); - ftdi_error_return(-5, "unable to claim usb device. Make sure ftdi_sio is unloaded!"); + if(detach_errno == EPERM) + { + ftdi_error_return(-8, "inappropriate permissions on device!"); + } + else + { + ftdi_error_return(-5, "unable to claim usb device. Make sure the default FTDI driver is not in use"); + } } if (ftdi_usb_reset (ftdi) != 0) @@ -585,6 +620,7 @@ int ftdi_usb_open_desc(struct ftdi_context *ftdi, int vendor, int product, \retval -8: get product description failed \retval -9: get serial number failed \retval -10: unable to close device + \retval -11: ftdi context invalid */ int ftdi_usb_open_desc_index(struct ftdi_context *ftdi, int vendor, int product, const char* description, const char* serial, unsigned int index) @@ -594,30 +630,34 @@ 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 (libusb_get_device_list(NULL, &devs) < 0) + if (ftdi == NULL) + ftdi_error_return(-11, "ftdi context invalid"); + + if (libusb_get_device_list(ftdi->usb_ctx, &devs) < 0) ftdi_error_return(-12, "libusb_get_device_list() failed"); while ((dev = devs[i++]) != NULL) { struct libusb_device_descriptor desc; + int res; if (libusb_get_device_descriptor(dev, &desc) < 0) - ftdi_error_return(-13, "libusb_get_device_descriptor() failed"); + ftdi_error_return_free_device_list(-13, "libusb_get_device_descriptor() failed", devs); if (desc.idVendor == vendor && desc.idProduct == product) { if (libusb_open(dev, &ftdi->usb_dev) < 0) - ftdi_error_return(-4, "usb_open() failed"); + ftdi_error_return_free_device_list(-4, "usb_open() failed", devs); if (description != NULL) { if (libusb_get_string_descriptor_ascii(ftdi->usb_dev, desc.iProduct, (unsigned char *)string, sizeof(string)) < 0) { libusb_close (ftdi->usb_dev); - ftdi_error_return(-8, "unable to fetch product description"); + ftdi_error_return_free_device_list(-8, "unable to fetch product description", devs); } if (strncmp(string, description, sizeof(string)) != 0) { @@ -630,7 +670,7 @@ int ftdi_usb_open_desc_index(struct ftdi_context *ftdi, int vendor, int product, if (libusb_get_string_descriptor_ascii(ftdi->usb_dev, desc.iSerialNumber, (unsigned char *)string, sizeof(string)) < 0) { ftdi_usb_close_internal (ftdi); - ftdi_error_return(-9, "unable to fetch serial number"); + ftdi_error_return_free_device_list(-9, "unable to fetch serial number", devs); } if (strncmp(string, serial, sizeof(string)) != 0) { @@ -647,12 +687,14 @@ int ftdi_usb_open_desc_index(struct ftdi_context *ftdi, int vendor, int product, continue; } - return ftdi_usb_open_dev(ftdi, dev); + res = ftdi_usb_open_dev(ftdi, dev); + libusb_free_device_list(devs,1); + return res; } } // device not found - ftdi_error_return(-3, "device not found"); + ftdi_error_return_free_device_list(-3, "device not found", devs); } /** @@ -680,9 +722,13 @@ int ftdi_usb_open_desc_index(struct ftdi_context *ftdi, int vendor, int product, \retval -9: get serial number failed \retval -10: unable to close device \retval -11: illegal description format + \retval -12: ftdi context invalid */ int ftdi_usb_open_string(struct ftdi_context *ftdi, const char* description) { + if (ftdi == NULL) + ftdi_error_return(-12, "ftdi context invalid"); + if (description[0] == 0 || description[1] != ':') ftdi_error_return(-11, "illegal description format"); @@ -693,25 +739,30 @@ 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... */ if (sscanf (description + 2, "%u/%u", &bus_number, &device_address) != 2) - ftdi_error_return(-11, "illegal description format"); + ftdi_error_return_free_device_list(-11, "illegal description format", devs); while ((dev = devs[i++]) != NULL) { + int ret; if (bus_number == libusb_get_bus_number (dev) && device_address == libusb_get_device_address (dev)) - return ftdi_usb_open_dev(ftdi, dev); + { + ret = ftdi_usb_open_dev(ftdi, dev); + libusb_free_device_list(devs,1); + return ret; + } } // device not found - ftdi_error_return(-3, "device not found"); + ftdi_error_return_free_device_list(-3, "device not found", devs); } else if (description[0] == 'i' || description[0] == 's') { @@ -767,9 +818,13 @@ int ftdi_usb_open_string(struct ftdi_context *ftdi, const char* description) \retval 0: all fine \retval -1: FTDI reset failed + \retval -2: USB device unavailable */ int ftdi_usb_reset(struct ftdi_context *ftdi) { + if (ftdi == NULL || ftdi->usb_dev == NULL) + ftdi_error_return(-2, "USB device unavailable"); + if (libusb_control_transfer(ftdi->usb_dev, FTDI_DEVICE_OUT_REQTYPE, SIO_RESET_REQUEST, SIO_RESET_SIO, ftdi->index, NULL, 0, ftdi->usb_write_timeout) < 0) @@ -789,9 +844,13 @@ int ftdi_usb_reset(struct ftdi_context *ftdi) \retval 0: all fine \retval -1: read buffer purge failed + \retval -2: USB device unavailable */ int ftdi_usb_purge_rx_buffer(struct ftdi_context *ftdi) { + if (ftdi == NULL || ftdi->usb_dev == NULL) + ftdi_error_return(-2, "USB device unavailable"); + if (libusb_control_transfer(ftdi->usb_dev, FTDI_DEVICE_OUT_REQTYPE, SIO_RESET_REQUEST, SIO_RESET_PURGE_RX, ftdi->index, NULL, 0, ftdi->usb_write_timeout) < 0) @@ -811,9 +870,13 @@ int ftdi_usb_purge_rx_buffer(struct ftdi_context *ftdi) \retval 0: all fine \retval -1: write buffer purge failed + \retval -2: USB device unavailable */ int ftdi_usb_purge_tx_buffer(struct ftdi_context *ftdi) { + if (ftdi == NULL || ftdi->usb_dev == NULL) + ftdi_error_return(-2, "USB device unavailable"); + if (libusb_control_transfer(ftdi->usb_dev, FTDI_DEVICE_OUT_REQTYPE, SIO_RESET_REQUEST, SIO_RESET_PURGE_TX, ftdi->index, NULL, 0, ftdi->usb_write_timeout) < 0) @@ -830,11 +893,15 @@ int ftdi_usb_purge_tx_buffer(struct ftdi_context *ftdi) \retval 0: all fine \retval -1: read buffer purge failed \retval -2: write buffer purge failed + \retval -3: USB device unavailable */ int ftdi_usb_purge_buffers(struct ftdi_context *ftdi) { int result; + if (ftdi == NULL || ftdi->usb_dev == NULL) + ftdi_error_return(-3, "USB device unavailable"); + result = ftdi_usb_purge_rx_buffer(ftdi); if (result < 0) return -1; @@ -855,11 +922,15 @@ int ftdi_usb_purge_buffers(struct ftdi_context *ftdi) \retval 0: all fine \retval -1: usb_release failed + \retval -3: ftdi context invalid */ int ftdi_usb_close(struct ftdi_context *ftdi) { int rtn = 0; + if (ftdi == NULL) + ftdi_error_return(-3, "ftdi context invalid"); + if (ftdi->usb_dev != NULL) if (libusb_release_interface(ftdi->usb_dev, ftdi->interface) < 0) rtn = -1; @@ -1004,12 +1075,16 @@ static int ftdi_convert_baudrate(int baudrate, struct ftdi_context *ftdi, \retval 0: all fine \retval -1: invalid baudrate \retval -2: setting baudrate failed + \retval -3: USB device unavailable */ int ftdi_set_baudrate(struct ftdi_context *ftdi, int baudrate) { unsigned short value, index; int actual_baudrate; + if (ftdi == NULL || ftdi->usb_dev == NULL) + ftdi_error_return(-3, "USB device unavailable"); + if (ftdi->bitbang_enabled) { baudrate = baudrate*4; @@ -1065,6 +1140,7 @@ int ftdi_set_line_property(struct ftdi_context *ftdi, enum ftdi_bits_type bits, \retval 0: all fine \retval -1: Setting line property failed + \retval -2: USB device unavailable */ int ftdi_set_line_property2(struct ftdi_context *ftdi, enum ftdi_bits_type bits, enum ftdi_stopbits_type sbit, enum ftdi_parity_type parity, @@ -1072,6 +1148,9 @@ int ftdi_set_line_property2(struct ftdi_context *ftdi, enum ftdi_bits_type bits, { unsigned short value = bits; + if (ftdi == NULL || ftdi->usb_dev == NULL) + ftdi_error_return(-2, "USB device unavailable"); + switch (parity) { case NONE: @@ -1129,6 +1208,7 @@ int ftdi_set_line_property2(struct ftdi_context *ftdi, enum ftdi_bits_type bits, \param buf Buffer with the data \param size Size of the buffer + \retval -666: USB device unavailable \retval <0: error code from usb_bulk_write() \retval >0: number of bytes written */ @@ -1137,6 +1217,9 @@ int ftdi_write_data(struct ftdi_context *ftdi, unsigned char *buf, int size) int offset = 0; int actual_length; + if (ftdi == NULL || ftdi->usb_dev == NULL) + ftdi_error_return(-666, "USB device unavailable"); + while (offset < size) { int write_size = ftdi->writebuffer_chunksize; @@ -1153,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; @@ -1243,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; @@ -1271,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 @@ -1288,6 +1366,12 @@ struct ftdi_transfer_control *ftdi_write_data_submit(struct ftdi_context *ftdi, struct libusb_transfer *transfer = libusb_alloc_transfer(0); int write_size, ret; + if (ftdi == NULL || ftdi->usb_dev == NULL) + { + libusb_free_transfer(transfer); + return NULL; + } + tc = (struct ftdi_transfer_control *) malloc (sizeof (*tc)); if (!tc || !transfer) @@ -1304,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); @@ -1324,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 @@ -1341,6 +1426,9 @@ struct ftdi_transfer_control *ftdi_read_data_submit(struct ftdi_context *ftdi, u struct libusb_transfer *transfer; int ret; + if (ftdi == NULL || ftdi->usb_dev == NULL) + return NULL; + tc = (struct ftdi_transfer_control *) malloc (sizeof (*tc)); if (!tc) return NULL; @@ -1403,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 @@ -1418,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. @@ -1454,9 +1543,13 @@ int ftdi_transfer_data_done(struct ftdi_transfer_control *tc) \param chunksize Chunk size \retval 0: all fine + \retval -1: ftdi context invalid */ int ftdi_write_data_set_chunksize(struct ftdi_context *ftdi, unsigned int chunksize) { + if (ftdi == NULL) + ftdi_error_return(-1, "ftdi context invalid"); + ftdi->writebuffer_chunksize = chunksize; return 0; } @@ -1468,9 +1561,13 @@ int ftdi_write_data_set_chunksize(struct ftdi_context *ftdi, unsigned int chunks \param chunksize Pointer to store chunk size in \retval 0: all fine + \retval -1: ftdi context invalid */ int ftdi_write_data_get_chunksize(struct ftdi_context *ftdi, unsigned int *chunksize) { + if (ftdi == NULL) + ftdi_error_return(-1, "ftdi context invalid"); + *chunksize = ftdi->writebuffer_chunksize; return 0; } @@ -1484,6 +1581,7 @@ int ftdi_write_data_get_chunksize(struct ftdi_context *ftdi, unsigned int *chunk \param buf Buffer to store data in \param size Size of the buffer + \retval -666: USB device unavailable \retval <0: error code from libusb_bulk_transfer() \retval 0: no data was available \retval >0: number of bytes read @@ -1495,6 +1593,9 @@ int ftdi_read_data(struct ftdi_context *ftdi, unsigned char *buf, int size) int packet_size = ftdi->max_packet_size; int actual_length = 1; + if (ftdi == NULL || ftdi->usb_dev == NULL) + ftdi_error_return(-666, "USB device unavailable"); + // Packet size sanity check (avoid division by zero) if (packet_size == 0) ftdi_error_return(-1, "max_packet_size is bogus (zero)"); @@ -1609,11 +1710,15 @@ int ftdi_read_data(struct ftdi_context *ftdi, unsigned char *buf, int size) \param chunksize Chunk size \retval 0: all fine + \retval -1: ftdi context invalid */ int ftdi_read_data_set_chunksize(struct ftdi_context *ftdi, unsigned int chunksize) { unsigned char *new_buf; + if (ftdi == NULL) + ftdi_error_return(-1, "ftdi context invalid"); + // Invalidate all remaining data ftdi->readbuffer_offset = 0; ftdi->readbuffer_remaining = 0; @@ -1642,9 +1747,13 @@ int ftdi_read_data_set_chunksize(struct ftdi_context *ftdi, unsigned int chunksi \param chunksize Pointer to store chunk size in \retval 0: all fine + \retval -1: FTDI context invalid */ int ftdi_read_data_get_chunksize(struct ftdi_context *ftdi, unsigned int *chunksize) { + if (ftdi == NULL) + ftdi_error_return(-1, "FTDI context invalid"); + *chunksize = ftdi->readbuffer_chunksize; return 0; } @@ -1661,11 +1770,15 @@ int ftdi_read_data_get_chunksize(struct ftdi_context *ftdi, unsigned int *chunks \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) { unsigned short usb_val; + if (ftdi == NULL || ftdi->usb_dev == NULL) + 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); @@ -1686,9 +1799,13 @@ int ftdi_enable_bitbang(struct ftdi_context *ftdi, unsigned char bitmask) \retval 0: all fine \retval -1: can't disable bitbang mode + \retval -2: USB device unavailable */ int ftdi_disable_bitbang(struct ftdi_context *ftdi) { + if (ftdi == NULL || ftdi->usb_dev == NULL) + ftdi_error_return(-2, "USB device unavailable"); + if (libusb_control_transfer(ftdi->usb_dev, FTDI_DEVICE_OUT_REQTYPE, SIO_SET_BITMODE_REQUEST, 0, ftdi->index, NULL, 0, ftdi->usb_write_timeout) < 0) ftdi_error_return(-1, "unable to leave bitbang mode. Perhaps not a BM type chip?"); @@ -1706,11 +1823,15 @@ int ftdi_disable_bitbang(struct ftdi_context *ftdi) \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) @@ -1729,9 +1850,13 @@ int ftdi_set_bitmode(struct ftdi_context *ftdi, unsigned char bitmask, unsigned \retval 0: all fine \retval -1: read pins failed + \retval -2: USB device unavailable */ int ftdi_read_pins(struct ftdi_context *ftdi, unsigned char *pins) { + 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_PINS_REQUEST, 0, ftdi->index, (unsigned char *)pins, 1, ftdi->usb_read_timeout) != 1) ftdi_error_return(-1, "read pins failed"); @@ -1751,6 +1876,7 @@ int ftdi_read_pins(struct ftdi_context *ftdi, unsigned char *pins) \retval 0: all fine \retval -1: latency out of range \retval -2: unable to set latency timer + \retval -3: USB device unavailable */ int ftdi_set_latency_timer(struct ftdi_context *ftdi, unsigned char latency) { @@ -1759,6 +1885,9 @@ int ftdi_set_latency_timer(struct ftdi_context *ftdi, unsigned char latency) if (latency < 1) ftdi_error_return(-1, "latency out of range. Only valid for 1-255"); + if (ftdi == NULL || ftdi->usb_dev == NULL) + ftdi_error_return(-3, "USB device unavailable"); + usb_val = latency; if (libusb_control_transfer(ftdi->usb_dev, FTDI_DEVICE_OUT_REQTYPE, SIO_SET_LATENCY_TIMER_REQUEST, usb_val, ftdi->index, NULL, 0, ftdi->usb_write_timeout) < 0) ftdi_error_return(-2, "unable to set latency timer"); @@ -1774,10 +1903,15 @@ int ftdi_set_latency_timer(struct ftdi_context *ftdi, unsigned char latency) \retval 0: all fine \retval -1: unable to get latency timer + \retval -2: USB device unavailable */ int ftdi_get_latency_timer(struct ftdi_context *ftdi, unsigned char *latency) { unsigned short usb_val; + + 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_GET_LATENCY_TIMER_REQUEST, 0, ftdi->index, (unsigned char *)&usb_val, 1, ftdi->usb_read_timeout) != 1) ftdi_error_return(-1, "reading latency timer failed"); @@ -1823,11 +1957,15 @@ int ftdi_get_latency_timer(struct ftdi_context *ftdi, unsigned char *latency) \retval 0: all fine \retval -1: unable to retrieve status information + \retval -2: USB device unavailable */ int ftdi_poll_modem_status(struct ftdi_context *ftdi, unsigned short *status) { char usb_val[2]; + 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_POLL_MODEM_STATUS_REQUEST, 0, ftdi->index, (unsigned char *)usb_val, 2, ftdi->usb_read_timeout) != 2) ftdi_error_return(-1, "getting modem status failed"); @@ -1845,9 +1983,13 @@ int ftdi_poll_modem_status(struct ftdi_context *ftdi, unsigned short *status) \retval 0: all fine \retval -1: set flow control failed + \retval -2: USB device unavailable */ int ftdi_setflowctrl(struct ftdi_context *ftdi, int flowctrl) { + if (ftdi == NULL || ftdi->usb_dev == NULL) + ftdi_error_return(-2, "USB device unavailable"); + if (libusb_control_transfer(ftdi->usb_dev, FTDI_DEVICE_OUT_REQTYPE, SIO_SET_FLOW_CTRL_REQUEST, 0, (flowctrl | ftdi->index), NULL, 0, ftdi->usb_write_timeout) < 0) @@ -1864,11 +2006,15 @@ int ftdi_setflowctrl(struct ftdi_context *ftdi, int flowctrl) \retval 0: all fine \retval -1: set dtr failed + \retval -2: USB device unavailable */ int ftdi_setdtr(struct ftdi_context *ftdi, int state) { unsigned short usb_val; + if (ftdi == NULL || ftdi->usb_dev == NULL) + ftdi_error_return(-2, "USB device unavailable"); + if (state) usb_val = SIO_SET_DTR_HIGH; else @@ -1889,12 +2035,16 @@ int ftdi_setdtr(struct ftdi_context *ftdi, int state) \param state state to set line to (1 or 0) \retval 0: all fine - \retval -1 set rts failed + \retval -1: set rts failed + \retval -2: USB device unavailable */ int ftdi_setrts(struct ftdi_context *ftdi, int state) { unsigned short usb_val; + if (ftdi == NULL || ftdi->usb_dev == NULL) + ftdi_error_return(-2, "USB device unavailable"); + if (state) usb_val = SIO_SET_RTS_HIGH; else @@ -1909,19 +2059,23 @@ int ftdi_setrts(struct ftdi_context *ftdi, int state) } /** - Set dtr and rts line in one pass + Set dtr and rts line in one pass - \param ftdi pointer to ftdi_context - \param dtr DTR state to set line to (1 or 0) - \param rts RTS state to set line to (1 or 0) + \param ftdi pointer to ftdi_context + \param dtr DTR state to set line to (1 or 0) + \param rts RTS state to set line to (1 or 0) - \retval 0: all fine - \retval -1 set dtr/rts failed + \retval 0: all fine + \retval -1: set dtr/rts failed + \retval -2: USB device unavailable */ int ftdi_setdtr_rts(struct ftdi_context *ftdi, int dtr, int rts) { unsigned short usb_val; + if (ftdi == NULL || ftdi->usb_dev == NULL) + ftdi_error_return(-2, "USB device unavailable"); + if (dtr) usb_val = SIO_SET_DTR_HIGH; else @@ -1949,12 +2103,16 @@ int ftdi_setdtr_rts(struct ftdi_context *ftdi, int dtr, int rts) \retval 0: all fine \retval -1: unable to set event character + \retval -2: USB device unavailable */ int ftdi_set_event_char(struct ftdi_context *ftdi, unsigned char eventch, unsigned char enable) { unsigned short usb_val; + if (ftdi == NULL || ftdi->usb_dev == NULL) + ftdi_error_return(-2, "USB device unavailable"); + usb_val = eventch; if (enable) usb_val |= 1 << 8; @@ -1974,12 +2132,16 @@ int ftdi_set_event_char(struct ftdi_context *ftdi, \retval 0: all fine \retval -1: unable to set error character + \retval -2: USB device unavailable */ int ftdi_set_error_char(struct ftdi_context *ftdi, unsigned char errorch, unsigned char enable) { unsigned short usb_val; + if (ftdi == NULL || ftdi->usb_dev == NULL) + ftdi_error_return(-2, "USB device unavailable"); + usb_val = errorch; if (enable) usb_val |= 1 << 8; @@ -2000,8 +2162,11 @@ int ftdi_set_error_char(struct ftdi_context *ftdi, */ void ftdi_eeprom_setsize(struct ftdi_context *ftdi, struct ftdi_eeprom *eeprom, int size) { - ftdi->eeprom_size=size; - eeprom->size=size; + if (ftdi == NULL) + return; + + ftdi->eeprom = eeprom; + ftdi->eeprom->size=size; } /** @@ -2009,14 +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) { + 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; @@ -2030,26 +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; } /** - Build binary output from ftdi_eeprom structure. - Output is suitable for ftdi_write_eeprom(). + Frees allocated memory in eeprom. - \param eeprom Pointer to ftdi_eeprom - \param output Buffer of 128 bytes to store eeprom image to + \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; - \retval >0: used eeprom size - \retval -1: eeprom size (128 bytes) exceeded by custom strings + 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: 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 (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); @@ -2058,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) @@ -2065,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; @@ -2077,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; @@ -2088,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 @@ -2132,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 @@ -2156,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 @@ -2222,34 +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 0 - size_check = eeprom->size; - size_check -= 28; // 28 are always in use (fixed) + int eeprom_size; + struct ftdi_eeprom *eeprom; - // 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; - - // 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); @@ -2260,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; } @@ -2300,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 @@ -2312,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;jmanufacturer[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;jproduct[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;jmanufacturer[j] = buf[2*j+i+2]; - } - eeprom->manufacturer[j] = '\0'; - - // Decode product name - i = buf[0x10] & 0x7f; // offset - for (j=0;j 0) { - 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;jserial[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;jserial[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; @@ -2368,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; @@ -2383,10 +2670,14 @@ int ftdi_eeprom_decode(struct ftdi_eeprom *eeprom, unsigned char *buf, int size) \retval 0: all fine \retval -1: read failed + \retval -2: USB device unavailable */ int ftdi_read_eeprom_location (struct ftdi_context *ftdi, int eeprom_addr, unsigned short *eeprom_val) { - 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 (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, (unsigned char *)eeprom_val, 2, ftdi->usb_read_timeout) != 2) ftdi_error_return(-1, "reading eeprom failed"); return 0; @@ -2400,17 +2691,33 @@ int ftdi_read_eeprom_location (struct ftdi_context *ftdi, int eeprom_addr, unsig \retval 0: all fine \retval -1: read failed + \retval -2: USB device unavailable */ int ftdi_read_eeprom(struct ftdi_context *ftdi, unsigned char *eeprom) { int i; - for (i = 0; i < ftdi->eeprom_size/2; i++) + if (ftdi == NULL || ftdi->usb_dev == NULL) + ftdi_error_return(-2, "USB device unavailable"); + + 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; } @@ -2439,11 +2746,15 @@ static unsigned char ftdi_read_chipid_shift(unsigned char value) \retval 0: all fine \retval -1: read failed + \retval -2: USB device unavailable */ int ftdi_read_chipid(struct ftdi_context *ftdi, unsigned int *chipid) { unsigned int a = 0, b = 0; + 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, 0x43, (unsigned char *)&a, 2, ftdi->usb_read_timeout) == 2) { a = a << 8 | a >> 8; @@ -2462,38 +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 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; - - do - { - for (j = 0; i < maxsize/2 && jusb_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"); - 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 @@ -2502,9 +2781,13 @@ int ftdi_read_eeprom_getsize(struct ftdi_context *ftdi, unsigned char *eeprom, i \retval 0: all fine \retval -1: read failed + \retval -2: USB device unavailable */ int ftdi_write_eeprom_location(struct ftdi_context *ftdi, int eeprom_addr, unsigned short eeprom_val) { + if (ftdi == NULL || ftdi->usb_dev == NULL) + ftdi_error_return(-2, "USB device unavailable"); + if (libusb_control_transfer(ftdi->usb_dev, FTDI_DEVICE_OUT_REQTYPE, SIO_WRITE_EEPROM_REQUEST, eeprom_val, eeprom_addr, NULL, 0, ftdi->usb_write_timeout) != 0) @@ -2521,12 +2804,16 @@ int ftdi_write_eeprom_location(struct ftdi_context *ftdi, int eeprom_addr, unsig \retval 0: all fine \retval -1: read failed + \retval -2: USB device unavailable */ int ftdi_write_eeprom(struct ftdi_context *ftdi, unsigned char *eeprom) { unsigned short usb_val, status; int i, ret; + if (ftdi == NULL || ftdi->usb_dev == NULL) + ftdi_error_return(-2, "USB device unavailable"); + /* These commands were traced while running MProg */ if ((ret = ftdi_usb_reset(ftdi)) != 0) return ret; @@ -2535,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; @@ -2557,9 +2844,13 @@ int ftdi_write_eeprom(struct ftdi_context *ftdi, unsigned char *eeprom) \retval 0: all fine \retval -1: erase failed + \retval -2: USB device unavailable */ int ftdi_erase_eeprom(struct ftdi_context *ftdi) { + if (ftdi == NULL || ftdi->usb_dev == NULL) + ftdi_error_return(-2, "USB device unavailable"); + if (libusb_control_transfer(ftdi->usb_dev, FTDI_DEVICE_OUT_REQTYPE, SIO_ERASE_EEPROM_REQUEST, 0, 0, NULL, 0, ftdi->usb_write_timeout) < 0) ftdi_error_return(-1, "unable to erase eeprom"); @@ -2575,6 +2866,9 @@ int ftdi_erase_eeprom(struct ftdi_context *ftdi) */ char *ftdi_get_error_string (struct ftdi_context *ftdi) { + if (ftdi == NULL) + return ""; + return ftdi->error_str; }