X-Git-Url: http://developer.intra2net.com/git/?p=libftdi;a=blobdiff_plain;f=src%2Fftdi.c;h=52266d0313010a609ae426e3c616e9bc91f39fee;hp=add6dc283499b2326acfa7c257aa54029f687650;hb=5bf1c1e3ff1616fda20c26cc3e3df7b807744c99;hpb=bc3841238bac9cb6955848fd661bbf19a5ed42c6 diff --git a/src/ftdi.c b/src/ftdi.c index add6dc2..52266d0 100644 --- a/src/ftdi.c +++ b/src/ftdi.c @@ -2,7 +2,7 @@ ftdi.c - description ------------------- begin : Fri Apr 4 2003 - copyright : (C) 2003-2014 by Intra2net AG and the libftdi developers + copyright : (C) 2003-2017 by Intra2net AG and the libftdi developers email : opensource@intra2net.com ***************************************************************************/ @@ -18,7 +18,7 @@ \mainpage libftdi API documentation Library to talk to FTDI chips. You find the latest versions of libftdi at - http://www.intra2net.com/en/developer/libftdi/ + https://www.intra2net.com/en/developer/libftdi/ The library is easy to use. Have a look at this short example: \include simple.c @@ -87,7 +87,7 @@ static void ftdi_usb_close_internal (struct ftdi_context *ftdi) */ int ftdi_init(struct ftdi_context *ftdi) { - struct ftdi_eeprom* eeprom = (struct ftdi_eeprom *)malloc(sizeof(struct ftdi_eeprom)); + struct ftdi_eeprom* eeprom; ftdi->usb_ctx = NULL; ftdi->usb_dev = NULL; ftdi->usb_read_timeout = 5000; @@ -111,6 +111,7 @@ int ftdi_init(struct ftdi_context *ftdi) ftdi_set_interface(ftdi, INTERFACE_ANY); ftdi->bitbang_mode = 1; /* when bitbang is enabled this holds the number of the mode */ + eeprom = (struct ftdi_eeprom *)malloc(sizeof(struct ftdi_eeprom)); if (eeprom == 0) ftdi_error_return(-2, "Can't malloc struct ftdi_eeprom"); memset(eeprom, 0, sizeof(struct ftdi_eeprom)); @@ -295,7 +296,7 @@ struct ftdi_version_info ftdi_get_library_version(void) Finds all ftdi devices with given VID:PID on the usb bus. Creates a new ftdi_device_list which needs to be deallocated by ftdi_list_free() after use. With VID:PID 0:0, search for the default devices - (0x403:0x6001, 0x403:0x6010, 0x403:0x6011, 0x403:0x6014) + (0x403:0x6001, 0x403:0x6010, 0x403:0x6011, 0x403:0x6014, 0x403:0x6015) \param ftdi pointer to ftdi_context \param devlist Pointer where to store list of found devices @@ -328,11 +329,12 @@ int ftdi_usb_find_all(struct ftdi_context *ftdi, struct ftdi_device_list **devli if (libusb_get_device_descriptor(dev, &desc) < 0) ftdi_error_return_free_device_list(-6, "libusb_get_device_descriptor() failed", devs); - if (((vendor != 0 && product != 0) && + if (((vendor || product) && desc.idVendor == vendor && desc.idProduct == product) || - ((vendor == 0 && product == 0) && + (!(vendor || product) && (desc.idVendor == 0x403) && (desc.idProduct == 0x6001 || desc.idProduct == 0x6010 - || desc.idProduct == 0x6011 || desc.idProduct == 0x6014))) + || desc.idProduct == 0x6011 || desc.idProduct == 0x6014 + || desc.idProduct == 0x6015))) { *curdev = (struct ftdi_device_list*)malloc(sizeof(struct ftdi_device_list)); if (!*curdev) @@ -405,16 +407,77 @@ void ftdi_list_free2(struct ftdi_device_list *devlist) \retval -9: get serial number failed \retval -11: libusb_get_device_descriptor() failed */ -int ftdi_usb_get_strings(struct ftdi_context * ftdi, struct libusb_device * dev, - char * manufacturer, int mnf_len, char * description, int desc_len, char * serial, int serial_len) +int ftdi_usb_get_strings(struct ftdi_context *ftdi, + struct libusb_device *dev, + char *manufacturer, int mnf_len, + char *description, int desc_len, + char *serial, int serial_len) { - struct libusb_device_descriptor desc; + int ret; if ((ftdi==NULL) || (dev==NULL)) return -1; if (ftdi->usb_dev == NULL && libusb_open(dev, &ftdi->usb_dev) < 0) - ftdi_error_return(-4, "libusb_open() failed"); + ftdi_error_return(-4, "libusb_open() failed"); + + // ftdi->usb_dev will not be NULL when entering ftdi_usb_get_strings2(), so + // it won't be closed either. This allows us to close it whether we actually + // called libusb_open() up above or not. This matches the expected behavior + // (and note) for ftdi_usb_get_strings(). + ret = ftdi_usb_get_strings2(ftdi, dev, + manufacturer, mnf_len, + description, desc_len, + serial, serial_len); + + // only close it if it was successful, as all other return codes close + // before returning already. + if (ret == 0) + ftdi_usb_close_internal(ftdi); + + return ret; +} + +/** + Return device ID strings from the usb device. + + The parameters manufacturer, description and serial may be NULL + or pointer to buffers to store the fetched strings. + + \note The old function ftdi_usb_get_strings() always closes the device. + This version only closes the device if it was opened by it. + + \param ftdi pointer to ftdi_context + \param dev libusb usb_dev to use + \param manufacturer Store manufacturer string here if not NULL + \param mnf_len Buffer size of manufacturer string + \param description Store product description string here if not NULL + \param desc_len Buffer size of product description string + \param serial Store serial string here if not NULL + \param serial_len Buffer size of serial string + + \retval 0: all fine + \retval -1: wrong arguments + \retval -4: unable to open device + \retval -7: get product manufacturer failed + \retval -8: get product description failed + \retval -9: get serial number failed + \retval -11: libusb_get_device_descriptor() failed +*/ +int ftdi_usb_get_strings2(struct ftdi_context *ftdi, struct libusb_device *dev, + char *manufacturer, int mnf_len, + char *description, int desc_len, + char *serial, int serial_len) +{ + struct libusb_device_descriptor desc; + char need_open; + + if ((ftdi==NULL) || (dev==NULL)) + return -1; + + need_open = (ftdi->usb_dev == NULL); + if (need_open && libusb_open(dev, &ftdi->usb_dev) < 0) + ftdi_error_return(-4, "libusb_open() failed"); if (libusb_get_device_descriptor(dev, &desc) < 0) ftdi_error_return(-11, "libusb_get_device_descriptor() failed"); @@ -446,7 +509,8 @@ int ftdi_usb_get_strings(struct ftdi_context * ftdi, struct libusb_device * dev, } } - ftdi_usb_close_internal (ftdi); + if (need_open) + ftdi_usb_close_internal (ftdi); return 0; } @@ -550,6 +614,11 @@ int ftdi_usb_open_dev(struct ftdi_context *ftdi, libusb_device *dev) if (libusb_detach_kernel_driver(ftdi->usb_dev, ftdi->interface) !=0) detach_errno = errno; } + else if (ftdi->module_detach_mode == AUTO_DETACH_REATACH_SIO_MODULE) + { + if (libusb_set_auto_detach_kernel_driver(ftdi->usb_dev, 1) != LIBUSB_SUCCESS) + detach_errno = errno; + } if (libusb_get_configuration (ftdi->usb_dev, &cfg) < 0) ftdi_error_return(-12, "libusb_get_configuration () failed"); @@ -687,6 +756,7 @@ int ftdi_usb_open_desc(struct ftdi_context *ftdi, int vendor, int product, \retval -9: get serial number failed \retval -10: unable to close device \retval -11: ftdi context invalid + \retval -12: libusb_get_device_list() failed */ int ftdi_usb_open_desc_index(struct ftdi_context *ftdi, int vendor, int product, const char* description, const char* serial, unsigned int index) @@ -761,6 +831,54 @@ int ftdi_usb_open_desc_index(struct ftdi_context *ftdi, int vendor, int product, } /** + Opens the device at a given USB bus and device address. + + \param ftdi pointer to ftdi_context + \param bus Bus number + \param addr Device address + + \retval 0: all fine + \retval -1: usb_find_busses() failed + \retval -2: usb_find_devices() failed + \retval -3: usb device not found + \retval -4: unable to open device + \retval -5: unable to claim device + \retval -6: reset failed + \retval -7: set baudrate failed + \retval -8: get product description failed + \retval -9: get serial number failed + \retval -10: unable to close device + \retval -11: ftdi context invalid + \retval -12: libusb_get_device_list() failed +*/ +int ftdi_usb_open_bus_addr(struct ftdi_context *ftdi, uint8_t bus, uint8_t addr) +{ + libusb_device *dev; + libusb_device **devs; + int i = 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) + { + if (libusb_get_bus_number(dev) == bus && libusb_get_device_address(dev) == addr) + { + int res; + res = ftdi_usb_open_dev(ftdi, dev); + libusb_free_device_list(devs,1); + return res; + } + } + + // device not found + ftdi_error_return_free_device_list(-3, "device not found", devs); +} + +/** Opens the ftdi-device described by a description-string. Intended to be used for parsing a device-description given as commandline argument. @@ -1190,7 +1308,7 @@ static int ftdi_convert_baudrate(int baudrate, struct ftdi_context *ftdi, else best_baud = ftdi_to_clkbits(baudrate, C_CLK, 16, &encoded_divisor); } - else if ((ftdi->type == TYPE_BM) || (ftdi->type == TYPE_2232C) || (ftdi->type == TYPE_R )) + else if ((ftdi->type == TYPE_BM) || (ftdi->type == TYPE_2232C) || (ftdi->type == TYPE_R) || (ftdi->type == TYPE_230X)) { best_baud = ftdi_to_clkbits(baudrate, C_CLK, 16, &encoded_divisor); } @@ -1469,9 +1587,15 @@ static void LIBUSB_CALL ftdi_read_data_cb(struct libusb_transfer *transfer) } } } - ret = libusb_submit_transfer (transfer); - if (ret < 0) - tc->completed = 1; + + if (transfer->status == LIBUSB_TRANSFER_CANCELLED) + tc->completed = LIBUSB_TRANSFER_CANCELLED; + else + { + ret = libusb_submit_transfer (transfer); + if (ret < 0) + tc->completed = 1; + } } @@ -1496,9 +1620,15 @@ static void LIBUSB_CALL ftdi_write_data_cb(struct libusb_transfer *transfer) transfer->length = write_size; transfer->buffer = tc->buf + tc->offset; - ret = libusb_submit_transfer (transfer); - if (ret < 0) - tc->completed = 1; + + if (transfer->status == LIBUSB_TRANSFER_CANCELLED) + tc->completed = LIBUSB_TRANSFER_CANCELLED; + else + { + ret = libusb_submit_transfer (transfer); + if (ret < 0) + tc->completed = 1; + } } } @@ -1661,17 +1791,19 @@ struct ftdi_transfer_control *ftdi_read_data_submit(struct ftdi_context *ftdi, u int ftdi_transfer_data_done(struct ftdi_transfer_control *tc) { int ret; - + struct timeval to = { 0, 0 }; while (!tc->completed) { - ret = libusb_handle_events(tc->ftdi->usb_ctx); + ret = libusb_handle_events_timeout_completed(tc->ftdi->usb_ctx, + &to, &tc->completed); if (ret < 0) { if (ret == LIBUSB_ERROR_INTERRUPTED) continue; libusb_cancel_transfer(tc->transfer); while (!tc->completed) - if (libusb_handle_events(tc->ftdi->usb_ctx) < 0) + if (libusb_handle_events_timeout_completed(tc->ftdi->usb_ctx, + &to, &tc->completed) < 0) break; libusb_free_transfer(tc->transfer); free (tc); @@ -1695,6 +1827,39 @@ int ftdi_transfer_data_done(struct ftdi_transfer_control *tc) } /** + Cancel transfer and wait for completion. + + Use libusb 1.0 asynchronous API. + + \param tc pointer to ftdi_transfer_control + \param to pointer to timeout value or NULL for infinite +*/ + +void ftdi_transfer_data_cancel(struct ftdi_transfer_control *tc, + struct timeval * to) +{ + struct timeval tv = { 0, 0 }; + + if (!tc->completed && tc->transfer != NULL) + { + if (to == NULL) + to = &tv; + + libusb_cancel_transfer(tc->transfer); + while (!tc->completed) + { + if (libusb_handle_events_timeout_completed(tc->ftdi->usb_ctx, to, &tc->completed) < 0) + break; + } + } + + if (tc->transfer) + libusb_free_transfer(tc->transfer); + + free (tc); +} + +/** Configure write buffer chunk size. Default is 4096. @@ -1749,13 +1914,14 @@ 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, i, num_of_chunks, chunk_remains; - int packet_size = ftdi->max_packet_size; + int 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) + packet_size = ftdi->max_packet_size; if (packet_size == 0) ftdi_error_return(-1, "max_packet_size is bogus (zero)"); @@ -2103,9 +2269,11 @@ int ftdi_poll_modem_status(struct ftdi_context *ftdi, unsigned short *status) /** Set flowcontrol for ftdi chip + Note: Do not use this function to enable XON/XOFF mode, use ftdi_setflowctrl_xonxoff() instead. + \param ftdi pointer to ftdi_context \param flowctrl flow control to use. should be - SIO_DISABLE_FLOW_CTRL, SIO_RTS_CTS_HS, SIO_DTR_DSR_HS or SIO_XON_XOFF_HS + SIO_DISABLE_FLOW_CTRL, SIO_RTS_CTS_HS, SIO_DTR_DSR_HS \retval 0: all fine \retval -1: set flow control failed @@ -2125,6 +2293,31 @@ int ftdi_setflowctrl(struct ftdi_context *ftdi, int flowctrl) } /** + Set XON/XOFF flowcontrol for ftdi chip + + \param ftdi pointer to ftdi_context + \param xon character code used to resume transmission + \param xoff character code used to pause transmission + + \retval 0: all fine + \retval -1: set flow control failed + \retval -2: USB device unavailable +*/ +int ftdi_setflowctrl_xonxoff(struct ftdi_context *ftdi, unsigned char xon, unsigned char xoff) +{ + if (ftdi == NULL || ftdi->usb_dev == NULL) + ftdi_error_return(-2, "USB device unavailable"); + + uint16_t xonxoff = xon | (xoff << 8); + if (libusb_control_transfer(ftdi->usb_dev, FTDI_DEVICE_OUT_REQTYPE, + SIO_SET_FLOW_CTRL_REQUEST, xonxoff, (SIO_XON_XOFF_HS | ftdi->index), + NULL, 0, ftdi->usb_write_timeout) < 0) + ftdi_error_return(-1, "set flow control failed"); + + return 0; +} + +/** Set dtr line \param ftdi pointer to ftdi_context @@ -2332,7 +2525,7 @@ int ftdi_eeprom_initdefaults(struct ftdi_context *ftdi, char * manufacturer, eeprom->manufacturer = NULL; if (manufacturer) { - eeprom->manufacturer = malloc(strlen(manufacturer)+1); + eeprom->manufacturer = (char *)malloc(strlen(manufacturer)+1); if (eeprom->manufacturer) strcpy(eeprom->manufacturer, manufacturer); } @@ -2342,7 +2535,7 @@ int ftdi_eeprom_initdefaults(struct ftdi_context *ftdi, char * manufacturer, eeprom->product = NULL; if(product) { - eeprom->product = malloc(strlen(product)+1); + eeprom->product = (char *)malloc(strlen(product)+1); if (eeprom->product) strcpy(eeprom->product, product); } @@ -2362,7 +2555,7 @@ int ftdi_eeprom_initdefaults(struct ftdi_context *ftdi, char * manufacturer, default: ftdi_error_return(-3, "Unknown chip type"); } - eeprom->product = malloc(strlen(default_product) +1); + eeprom->product = (char *)malloc(strlen(default_product) +1); if (eeprom->product) strcpy(eeprom->product, default_product); } @@ -2372,7 +2565,7 @@ int ftdi_eeprom_initdefaults(struct ftdi_context *ftdi, char * manufacturer, eeprom->serial = NULL; if (serial) { - eeprom->serial = malloc(strlen(serial)+1); + eeprom->serial = (char *)malloc(strlen(serial)+1); if (eeprom->serial) strcpy(eeprom->serial, serial); } @@ -2391,10 +2584,10 @@ int ftdi_eeprom_initdefaults(struct ftdi_context *ftdi, char * manufacturer, { eeprom->max_power = 90; eeprom->size = 0x100; - eeprom->cbus_function[0] = CBUSH_TXDEN; - eeprom->cbus_function[1] = CBUSH_RXLED; - eeprom->cbus_function[2] = CBUSH_TXLED; - eeprom->cbus_function[3] = CBUSH_SLEEP; + eeprom->cbus_function[0] = CBUSX_TXDEN; + eeprom->cbus_function[1] = CBUSX_RXLED; + eeprom->cbus_function[2] = CBUSX_TXLED; + eeprom->cbus_function[3] = CBUSX_SLEEP; } else { @@ -2458,7 +2651,7 @@ int ftdi_eeprom_set_strings(struct ftdi_context *ftdi, char * manufacturer, { if (eeprom->manufacturer) free (eeprom->manufacturer); - eeprom->manufacturer = malloc(strlen(manufacturer)+1); + eeprom->manufacturer = (char *)malloc(strlen(manufacturer)+1); if (eeprom->manufacturer) strcpy(eeprom->manufacturer, manufacturer); } @@ -2467,7 +2660,7 @@ int ftdi_eeprom_set_strings(struct ftdi_context *ftdi, char * manufacturer, { if (eeprom->product) free (eeprom->product); - eeprom->product = malloc(strlen(product)+1); + eeprom->product = (char *)malloc(strlen(product)+1); if (eeprom->product) strcpy(eeprom->product, product); } @@ -2476,7 +2669,7 @@ int ftdi_eeprom_set_strings(struct ftdi_context *ftdi, char * manufacturer, { if (eeprom->serial) free (eeprom->serial); - eeprom->serial = malloc(strlen(serial)+1); + eeprom->serial = (char *)malloc(strlen(serial)+1); if (eeprom->serial) { strcpy(eeprom->serial, serial); @@ -2486,8 +2679,63 @@ int ftdi_eeprom_set_strings(struct ftdi_context *ftdi, char * manufacturer, return 0; } +/** + Return device ID strings from the eeprom. Device needs to be connected. + + The parameters manufacturer, description and serial may be NULL + or pointer to buffers to store the fetched strings. + + \param ftdi pointer to ftdi_context + \param manufacturer Store manufacturer string here if not NULL + \param mnf_len Buffer size of manufacturer string + \param product Store product description string here if not NULL + \param prod_len Buffer size of product description string + \param serial Store serial string here if not NULL + \param serial_len Buffer size of serial string + + \retval 0: all fine + \retval -1: ftdi context invalid + \retval -2: ftdi eeprom buffer invalid +*/ +int ftdi_eeprom_get_strings(struct ftdi_context *ftdi, + char *manufacturer, int mnf_len, + char *product, int prod_len, + char *serial, int serial_len) +{ + struct ftdi_eeprom *eeprom; + + if (ftdi == NULL) + ftdi_error_return(-1, "No struct ftdi_context"); + if (ftdi->eeprom == NULL) + ftdi_error_return(-2, "No struct ftdi_eeprom"); + + eeprom = ftdi->eeprom; -/*FTD2XX doesn't check for values not fitting in the ACBUS Signal oprtions*/ + if (manufacturer) + { + strncpy(manufacturer, eeprom->manufacturer, mnf_len); + if (mnf_len > 0) + manufacturer[mnf_len - 1] = '\0'; + } + + if (product) + { + strncpy(product, eeprom->product, prod_len); + if (prod_len > 0) + product[prod_len - 1] = '\0'; + } + + if (serial) + { + strncpy(serial, eeprom->serial, serial_len); + if (serial_len > 0) + serial[serial_len - 1] = '\0'; + } + + return 0; +} + +/*FTD2XX doesn't check for values not fitting in the ACBUS Signal options*/ void set_ft232h_cbus(struct ftdi_eeprom *eeprom, unsigned char * output) { int i; @@ -2537,6 +2785,15 @@ static unsigned char type2bit(unsigned char type, enum ftdi_chip_type chip) default: return 0; } } + case TYPE_R: + { + switch (type) + { + case CHANNEL_IS_UART : return 0; + case CHANNEL_IS_FIFO : return 0x01; + default: return 0; + } + } case TYPE_230X: /* FT230X is only UART */ default: return 0; } @@ -2562,7 +2819,7 @@ int ftdi_eeprom_build(struct ftdi_context *ftdi) unsigned char i, j, eeprom_size_mask; unsigned short checksum, value; unsigned char manufacturer_size = 0, product_size = 0, serial_size = 0; - int user_area_size; + int user_area_size, free_start, free_end; struct ftdi_eeprom *eeprom; unsigned char * output; @@ -2597,12 +2854,12 @@ int ftdi_eeprom_build(struct ftdi_context *ftdi) { case TYPE_AM: case TYPE_BM: + case TYPE_R: user_area_size = 96; // base size for strings (total of 48 characters) break; case TYPE_2232C: user_area_size = 90; // two extra config bytes and 4 bytes PnP stuff break; - case TYPE_R: case TYPE_230X: user_area_size = 88; // four extra config bytes + 4 bytes PnP stuff break; @@ -2709,6 +2966,7 @@ int ftdi_eeprom_build(struct ftdi_context *ftdi) } /* Wrap around 0x80 for 128 byte EEPROMS (Internale and 93x46) */ eeprom_size_mask = eeprom->size -1; + free_end = i & eeprom_size_mask; // Addr 0E: Offset of the manufacturer string + 0x80, calculated later // Addr 0F: Length of manufacturer string @@ -2776,7 +3034,7 @@ int ftdi_eeprom_build(struct ftdi_context *ftdi) case TYPE_BM: output[0x0C] = eeprom->usb_version & 0xff; output[0x0D] = (eeprom->usb_version>>8) & 0xff; - if (eeprom->use_usb_version == USE_USB_VERSION_BIT) + if (eeprom->use_usb_version) output[0x0A] |= USE_USB_VERSION_BIT; else output[0x0A] &= ~USE_USB_VERSION_BIT; @@ -2818,7 +3076,7 @@ int ftdi_eeprom_build(struct ftdi_context *ftdi) output[0x0A] |= 0x4; else output[0x0A] &= ~0x4; - if (eeprom->use_usb_version == USE_USB_VERSION_BIT) + if (eeprom->use_usb_version) output[0x0A] |= USE_USB_VERSION_BIT; else output[0x0A] &= ~USE_USB_VERSION_BIT; @@ -2828,8 +3086,11 @@ int ftdi_eeprom_build(struct ftdi_context *ftdi) output[0x14] = eeprom->chip; break; case TYPE_R: + output[0x00] = type2bit(eeprom->channel_a_type, TYPE_R); if (eeprom->high_current == HIGH_CURRENT_DRIVE_R) output[0x00] |= HIGH_CURRENT_DRIVE_R; + if (eeprom->external_oscillator) + output[0x00] |= 0x02; output[0x01] = 0x40; /* Hard coded Endpoint Size*/ if (eeprom->suspend_pull_downs) @@ -2840,22 +3101,22 @@ int ftdi_eeprom_build(struct ftdi_context *ftdi) output[0x0C] = eeprom->usb_version & 0xff; output[0x0D] = (eeprom->usb_version>>8) & 0xff; - if (eeprom->cbus_function[0] > CBUS_BB) + if (eeprom->cbus_function[0] > CBUS_BB_RD) output[0x14] = CBUS_TXLED; else output[0x14] = eeprom->cbus_function[0]; - if (eeprom->cbus_function[1] > CBUS_BB) + if (eeprom->cbus_function[1] > CBUS_BB_RD) output[0x14] |= CBUS_RXLED<<4; else output[0x14] |= eeprom->cbus_function[1]<<4; - if (eeprom->cbus_function[2] > CBUS_BB) + if (eeprom->cbus_function[2] > CBUS_BB_RD) output[0x15] = CBUS_TXDEN; else output[0x15] = eeprom->cbus_function[2]; - if (eeprom->cbus_function[3] > CBUS_BB) + if (eeprom->cbus_function[3] > CBUS_BB_RD) output[0x15] |= CBUS_PWREN<<4; else output[0x15] |= eeprom->cbus_function[3]<<4; @@ -3058,16 +3319,48 @@ int ftdi_eeprom_build(struct ftdi_context *ftdi) break; case TYPE_230X: output[0x00] = 0x80; /* Actually, leave the default value */ - output[0x0a] = 0x08; /* Enable USB Serial Number */ /*FIXME: Make DBUS & CBUS Control configurable*/ output[0x0c] = 0; /* DBUS drive 4mA, CBUS drive 4 mA like factory default */ for (j = 0; j <= 6; j++) { output[0x1a + j] = eeprom->cbus_function[j]; } + output[0x0b] = eeprom->invert; break; } + /* First address without use */ + free_start = 0; + switch (ftdi->type) + { + case TYPE_230X: + free_start += 2; + case TYPE_232H: + free_start += 6; + case TYPE_2232H: + case TYPE_4232H: + free_start += 2; + case TYPE_R: + free_start += 2; + case TYPE_2232C: + free_start++; + case TYPE_AM: + case TYPE_BM: + free_start += 0x14; + } + + /* Arbitrary user data */ + if (eeprom->user_data && eeprom->user_data_size >= 0) + { + if (eeprom->user_data_addr < free_start) + fprintf(stderr,"Warning, user data starts inside the generated data!\n"); + if (eeprom->user_data_addr + eeprom->user_data_size >= free_end) + fprintf(stderr,"Warning, user data overlaps the strings area!\n"); + if (eeprom->user_data_addr + eeprom->user_data_size > eeprom->size) + ftdi_error_return(-1,"eeprom size exceeded"); + memcpy(output + eeprom->user_data_addr, eeprom->user_data, eeprom->user_data_size); + } + // calculate checksum checksum = 0xAAAA; @@ -3120,6 +3413,21 @@ static unsigned char bit2type(unsigned char bits) } return 0; } +/* Decode 230X / 232R type chips invert bits + * Prints directly to stdout. +*/ +static void print_inverted_bits(int invert) +{ + const char *r_bits[] = {"TXD","RXD","RTS","CTS","DTR","DSR","DCD","RI"}; + int i; + + fprintf(stdout,"Inverted bits:"); + for (i=0; i<8; i++) + if ((invert & (1<in_is_isochronous = buf[0x0A]&0x01; eeprom->out_is_isochronous = buf[0x0A]&0x02; eeprom->suspend_pull_downs = buf[0x0A]&0x04; - eeprom->use_serial = (buf[0x0A] & USE_SERIAL_NUM)?1:0; - eeprom->use_usb_version = buf[0x0A] & USE_USB_VERSION_BIT; + eeprom->use_serial = !!(buf[0x0A] & USE_SERIAL_NUM); + eeprom->use_usb_version = !!(buf[0x0A] & USE_USB_VERSION_BIT); // Addr 0C: USB version low byte when 0x0A // Addr 0D: USB version high byte when 0x0A @@ -3198,7 +3506,7 @@ int ftdi_eeprom_decode(struct ftdi_context *ftdi, int verbose) free(eeprom->manufacturer); if (manufacturer_size > 0) { - eeprom->manufacturer = malloc(manufacturer_size); + eeprom->manufacturer = (char *)malloc(manufacturer_size); if (eeprom->manufacturer) { // Decode manufacturer @@ -3219,7 +3527,7 @@ int ftdi_eeprom_decode(struct ftdi_context *ftdi, int verbose) product_size = buf[0x11]/2; if (product_size > 0) { - eeprom->product = malloc(product_size); + eeprom->product = (char *)malloc(product_size); if (eeprom->product) { // Decode product name @@ -3240,7 +3548,7 @@ int ftdi_eeprom_decode(struct ftdi_context *ftdi, int verbose) serial_size = buf[0x13]/2; if (serial_size > 0) { - eeprom->serial = malloc(serial_size); + eeprom->serial = (char *)malloc(serial_size); if (eeprom->serial) { // Decode serial @@ -3299,6 +3607,7 @@ int ftdi_eeprom_decode(struct ftdi_context *ftdi, int verbose) /* TYPE_R flags D2XX, not VCP as all others*/ eeprom->channel_a_driver = ~buf[0x00] & DRIVER_VCP; eeprom->high_current = buf[0x00] & HIGH_CURRENT_DRIVE_R; + eeprom->external_oscillator = buf[0x00] & 0x02; if ( (buf[0x01]&0x40) != 0x40) fprintf(stderr, "TYPE_R EEPROM byte[0x01] Bit 6 unexpected Endpoint size." @@ -3356,8 +3665,6 @@ int ftdi_eeprom_decode(struct ftdi_context *ftdi, int verbose) } else if (ftdi->type == TYPE_232H) { - int i; - eeprom->channel_a_type = buf[0x00] & 0xf; eeprom->channel_a_driver = (buf[0x00] & DRIVER_VCPH)?DRIVER_VCP:0; eeprom->clock_polarity = buf[0x01] & FT1284_CLK_IDLE_STATE; @@ -3391,11 +3698,13 @@ int ftdi_eeprom_decode(struct ftdi_context *ftdi, int verbose) eeprom->group1_drive = (buf[0x0c] >> 4) & 0x03; eeprom->group1_schmitt = (buf[0x0c] >> 4) & IS_SCHMITT; eeprom->group1_slew = (buf[0x0c] >> 4) & SLOW_SLEW; + + eeprom->invert = buf[0xb]; } if (verbose) { - char *channel_mode[] = {"UART", "FIFO", "CPU", "OPTO", "FT1284"}; + const char *channel_mode[] = {"UART", "FIFO", "CPU", "OPTO", "FT1284"}; fprintf(stdout, "VID: 0x%04x\n",eeprom->vendor_id); fprintf(stdout, "PID: 0x%04x\n",eeprom->product_id); fprintf(stdout, "Release: 0x%04x\n",eeprom->release_number); @@ -3412,8 +3721,10 @@ int ftdi_eeprom_decode(struct ftdi_context *ftdi, int verbose) if (eeprom->serial) fprintf(stdout, "Serial: %s\n",eeprom->serial); fprintf(stdout, "Checksum : %04x\n", checksum); - if (ftdi->type == TYPE_R) + if (ftdi->type == TYPE_R) { fprintf(stdout, "Internal EEPROM\n"); + fprintf(stdout,"Oscillator: %s\n", eeprom->external_oscillator?"External":"Internal"); + } else if (eeprom->chip >= 0x46) fprintf(stdout, "Attached EEPROM: 93x%02x\n", eeprom->chip); if (eeprom->suspend_dbus7) @@ -3446,7 +3757,7 @@ int ftdi_eeprom_decode(struct ftdi_context *ftdi, int verbose) (eeprom->channel_b_driver)?" VCP":"", (eeprom->high_current_b)?" High Current IO":""); if (((ftdi->type == TYPE_BM) || (ftdi->type == TYPE_2232C)) && - eeprom->use_usb_version == USE_USB_VERSION_BIT) + eeprom->use_usb_version) fprintf(stdout,"Use explicit USB Version %04x\n",eeprom->usb_version); if ((ftdi->type == TYPE_2232H) || (ftdi->type == TYPE_4232H)) @@ -3474,8 +3785,7 @@ int ftdi_eeprom_decode(struct ftdi_context *ftdi, int verbose) } else if (ftdi->type == TYPE_232H) { - int i; - char *cbush_mux[] = {"TRISTATE","RXLED","TXLED", "TXRXLED","PWREN", + const char *cbush_mux[] = {"TRISTATE","TXLED","RXLED", "TXRXLED","PWREN", "SLEEP","DRIVE_0","DRIVE_1","IOMODE","TXDEN", "CLK30","CLK15","CLK7_5" }; @@ -3496,8 +3806,7 @@ int ftdi_eeprom_decode(struct ftdi_context *ftdi, int verbose) } else if (ftdi->type == TYPE_230X) { - int i; - char *cbush_mux[] = {"TRISTATE","RXLED","TXLED", "TXRXLED","PWREN", + const char *cbusx_mux[] = {"TRISTATE","TXLED","RXLED", "TXRXLED","PWREN", "SLEEP","DRIVE_0","DRIVE_1","IOMODE","TXDEN", "CLK24","CLK12","CLK6","BAT_DETECT","BAT_DETECT#", "I2C_TXE#", "I2C_RXF#", "VBUS_SENSE", "BB_WR#", @@ -3513,31 +3822,28 @@ int ftdi_eeprom_decode(struct ftdi_context *ftdi, int verbose) (eeprom->group1_slew)?" Slow Slew":""); for (i=0; i<4; i++) { - if (eeprom->cbus_function[i]<= CBUSH_AWAKE) - fprintf(stdout,"CBUS%d Function: %s\n", i, cbush_mux[eeprom->cbus_function[i]]); + if (eeprom->cbus_function[i]<= CBUSX_AWAKE) + fprintf(stdout,"CBUS%d Function: %s\n", i, cbusx_mux[eeprom->cbus_function[i]]); } + + if (eeprom->invert) + print_inverted_bits(eeprom->invert); } if (ftdi->type == TYPE_R) { - char *cbus_mux[] = {"TXDEN","PWREN","RXLED", "TXLED","TX+RXLED", + const char *cbus_mux[] = {"TXDEN","PWREN","RXLED", "TXLED","TX+RXLED", "SLEEP","CLK48","CLK24","CLK12","CLK6", "IOMODE","BB_WR","BB_RD" }; - char *cbus_BB[] = {"RXF","TXE","RD", "WR"}; + const char *cbus_BB[] = {"RXF","TXE","RD", "WR"}; if (eeprom->invert) - { - char *r_bits[] = {"TXD","RXD","RTS", "CTS","DTR","DSR","DCD","RI"}; - fprintf(stdout,"Inverted bits:"); - for (i=0; i<8; i++) - if ((eeprom->invert & (1<invert); + for (i=0; i<5; i++) { - if (eeprom->cbus_function[i]cbus_function[i]<=CBUS_BB_RD) fprintf(stdout,"C%d Function: %s\n", i, cbus_mux[eeprom->cbus_function[i]]); else @@ -3670,7 +3976,7 @@ int ftdi_get_eeprom_value(struct ftdi_context *ftdi, enum ftdi_eeprom_value valu *value = ftdi->eeprom->cbus_function[8]; break; case CBUS_FUNCTION_9: - *value = ftdi->eeprom->cbus_function[8]; + *value = ftdi->eeprom->cbus_function[9]; break; case HIGH_CURRENT: *value = ftdi->eeprom->high_current; @@ -3738,6 +4044,9 @@ int ftdi_get_eeprom_value(struct ftdi_context *ftdi, enum ftdi_eeprom_value valu case CHIP_SIZE: *value = ftdi->eeprom->size; break; + case EXTERNAL_OSCILLATOR: + *value = ftdi->eeprom->external_oscillator; + break; default: ftdi_error_return(-1, "Request for unknown EEPROM value"); } @@ -3927,6 +4236,14 @@ int ftdi_set_eeprom_value(struct ftdi_context *ftdi, enum ftdi_eeprom_value valu break; case CHIP_SIZE: ftdi_error_return(-2, "EEPROM Value can't be changed"); + break; + case EXTERNAL_OSCILLATOR: + ftdi->eeprom->external_oscillator = value; + break; + case USER_DATA_ADDR: + ftdi->eeprom->user_data_addr = value; + break; + default : ftdi_error_return(-1, "Request to unknown EEPROM value"); } @@ -3968,7 +4285,7 @@ int ftdi_get_eeprom_buf(struct ftdi_context *ftdi, unsigned char * buf, int size \param size Size of buffer \retval 0: All fine - \retval -1: struct ftdi_contxt or ftdi_eeprom of buf missing + \retval -1: struct ftdi_context or ftdi_eeprom or buf missing */ int ftdi_set_eeprom_buf(struct ftdi_context *ftdi, const unsigned char * buf, int size) { @@ -3984,6 +4301,25 @@ int ftdi_set_eeprom_buf(struct ftdi_context *ftdi, const unsigned char * buf, in return 0; } +/** Set the EEPROM user data content from the user-supplied prefilled buffer + + \param ftdi pointer to ftdi_context + \param buf buffer to read EEPROM user data content + \param size Size of buffer + + \retval 0: All fine + \retval -1: struct ftdi_context or ftdi_eeprom or buf missing +*/ +int ftdi_set_eeprom_user_data(struct ftdi_context *ftdi, const char * buf, int size) +{ + if (!ftdi || !(ftdi->eeprom) || !buf) + ftdi_error_return(-1, "No appropriate structure"); + + ftdi->eeprom->user_data_size = size; + ftdi->eeprom->user_data = buf; + return 0; +} + /** Read eeprom location @@ -3997,12 +4333,16 @@ int ftdi_set_eeprom_buf(struct ftdi_context *ftdi, const unsigned char * buf, in */ int ftdi_read_eeprom_location (struct ftdi_context *ftdi, int eeprom_addr, unsigned short *eeprom_val) { + unsigned char buf[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) + if (libusb_control_transfer(ftdi->usb_dev, FTDI_DEVICE_IN_REQTYPE, SIO_READ_EEPROM_REQUEST, 0, eeprom_addr, buf, 2, ftdi->usb_read_timeout) != 2) ftdi_error_return(-1, "reading eeprom failed"); + *eeprom_val = (0xff & buf[0]) | (buf[1] << 8); + return 0; } @@ -4285,7 +4625,7 @@ int ftdi_erase_eeprom(struct ftdi_context *ftdi) \retval Pointer to error string */ -char *ftdi_get_error_string (struct ftdi_context *ftdi) +const char *ftdi_get_error_string (struct ftdi_context *ftdi) { if (ftdi == NULL) return "";