X-Git-Url: http://developer.intra2net.com/git/?p=libftdi;a=blobdiff_plain;f=src%2Fftdi.c;h=9495fb5945097e655e2f7383a8d01b3d6c039cff;hp=529b99ea47f84a3922ff50804c4fcc4ca2cf21c8;hb=ae3d154b7641b120f537c6d86871371c9d75c9e9;hpb=15079e78d3cbca7e33bd7f421c00ada20599e495 diff --git a/src/ftdi.c b/src/ftdi.c index 529b99e..9495fb5 100644 --- a/src/ftdi.c +++ b/src/ftdi.c @@ -2,8 +2,9 @@ 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 + SPDX-License-Identifier: LGPL-2.1-only ***************************************************************************/ /*************************************************************************** @@ -18,7 +19,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 @@ -35,6 +36,8 @@ #include #include "ftdi_i.h" +/* Prevent deprecated messages when building library */ +#define _FTDI_DISABLE_DEPRECATED #include "ftdi.h" #include "ftdi_version_i.h" @@ -87,7 +90,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 +114,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)); @@ -469,11 +473,12 @@ int ftdi_usb_get_strings2(struct ftdi_context *ftdi, struct libusb_device *dev, char *serial, int serial_len) { struct libusb_device_descriptor desc; + char need_open; if ((ftdi==NULL) || (dev==NULL)) return -1; - char need_open = (ftdi->usb_dev == NULL); + need_open = (ftdi->usb_dev == NULL); if (need_open && libusb_open(dev, &ftdi->usb_dev) < 0) ftdi_error_return(-4, "libusb_open() failed"); @@ -612,6 +617,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"); @@ -749,6 +759,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) @@ -823,6 +834,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. @@ -960,6 +1019,7 @@ int ftdi_usb_reset(struct ftdi_context *ftdi) /** Clears the read buffer on the chip and the internal read buffer. + This is the correct behavior for an RX flush. \param ftdi pointer to ftdi_context @@ -967,6 +1027,36 @@ int ftdi_usb_reset(struct ftdi_context *ftdi) \retval -1: read buffer purge failed \retval -2: USB device unavailable */ +int ftdi_tciflush(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_TCIFLUSH, + ftdi->index, NULL, 0, ftdi->usb_write_timeout) < 0) + ftdi_error_return(-1, "FTDI purge of RX buffer failed"); + + // Invalidate data in the readbuffer + ftdi->readbuffer_offset = 0; + ftdi->readbuffer_remaining = 0; + + return 0; +} + + +/** + Clears the write buffer on the chip and the internal read buffer. + This is incorrect behavior for an RX flush. + + \param ftdi pointer to ftdi_context + + \retval 0: all fine + \retval -1: write buffer purge failed + \retval -2: USB device unavailable + + \deprecated Use \ref ftdi_tciflush(struct ftdi_context *ftdi) +*/ int ftdi_usb_purge_rx_buffer(struct ftdi_context *ftdi) { if (ftdi == NULL || ftdi->usb_dev == NULL) @@ -986,6 +1076,7 @@ int ftdi_usb_purge_rx_buffer(struct ftdi_context *ftdi) /** Clears the write buffer on the chip. + This is correct behavior for a TX flush. \param ftdi pointer to ftdi_context @@ -993,6 +1084,32 @@ int ftdi_usb_purge_rx_buffer(struct ftdi_context *ftdi) \retval -1: write buffer purge failed \retval -2: USB device unavailable */ +int ftdi_tcoflush(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_TCOFLUSH, + ftdi->index, NULL, 0, ftdi->usb_write_timeout) < 0) + ftdi_error_return(-1, "FTDI purge of TX buffer failed"); + + return 0; +} + + +/** + Clears the read buffer on the chip. + This is incorrect behavior for a TX flush. + + \param ftdi pointer to ftdi_context + + \retval 0: all fine + \retval -1: read buffer purge failed + \retval -2: USB device unavailable + + \deprecated Use \ref ftdi_tcoflush(struct ftdi_context *ftdi) +*/ int ftdi_usb_purge_tx_buffer(struct ftdi_context *ftdi) { if (ftdi == NULL || ftdi->usb_dev == NULL) @@ -1007,7 +1124,37 @@ int ftdi_usb_purge_tx_buffer(struct ftdi_context *ftdi) } /** + Clears the RX and TX FIFOs on the chip and the internal read buffer. + This is correct behavior for both RX and TX flush. + + \param ftdi pointer to ftdi_context + + \retval 0: all fine + \retval -1: read buffer purge failed + \retval -2: write buffer purge failed + \retval -3: USB device unavailable +*/ +int ftdi_tcioflush(struct ftdi_context *ftdi) +{ + int result; + + if (ftdi == NULL || ftdi->usb_dev == NULL) + ftdi_error_return(-3, "USB device unavailable"); + + result = ftdi_tcoflush(ftdi); + if (result < 0) + return -1; + + result = ftdi_tciflush(ftdi); + if (result < 0) + return -2; + + return 0; +} + +/** Clears the buffers on the chip and the internal read buffer. + While coded incorrectly, the result is satisfactory. \param ftdi pointer to ftdi_context @@ -1015,6 +1162,8 @@ int ftdi_usb_purge_tx_buffer(struct ftdi_context *ftdi) \retval -1: read buffer purge failed \retval -2: write buffer purge failed \retval -3: USB device unavailable + + \deprecated Use \ref ftdi_tcioflush(struct ftdi_context *ftdi) */ int ftdi_usb_purge_buffers(struct ftdi_context *ftdi) { @@ -1252,7 +1401,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); } @@ -1858,13 +2007,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)"); @@ -2212,9 +2362,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 @@ -2234,6 +2386,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 @@ -2441,7 +2618,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); } @@ -2451,7 +2628,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); } @@ -2471,7 +2648,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); } @@ -2481,7 +2658,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); } @@ -2547,8 +2724,8 @@ int ftdi_eeprom_initdefaults(struct ftdi_context *ftdi, char * manufacturer, return 0; } -int ftdi_eeprom_set_strings(struct ftdi_context *ftdi, char * manufacturer, - char * product, char * serial) +int ftdi_eeprom_set_strings(struct ftdi_context *ftdi, const char * manufacturer, + const char * product, const char * serial) { struct ftdi_eeprom *eeprom; @@ -2567,7 +2744,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); } @@ -2576,7 +2753,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); } @@ -2585,7 +2762,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); @@ -2595,6 +2772,61 @@ 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; + + 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) @@ -2646,6 +2878,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; } @@ -2938,6 +3179,7 @@ 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) @@ -3170,7 +3412,6 @@ 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++) @@ -3270,7 +3511,7 @@ static unsigned char bit2type(unsigned char bits) */ static void print_inverted_bits(int invert) { - char *r_bits[] = {"TXD","RXD","RTS","CTS","DTR","DSR","DCD","RI"}; + const char *r_bits[] = {"TXD","RXD","RTS","CTS","DTR","DSR","DCD","RI"}; int i; fprintf(stdout,"Inverted bits:"); @@ -3358,7 +3599,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 @@ -3379,7 +3620,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 @@ -3400,7 +3641,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 @@ -3556,7 +3797,7 @@ int ftdi_eeprom_decode(struct ftdi_context *ftdi, int verbose) 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); @@ -3637,7 +3878,7 @@ int ftdi_eeprom_decode(struct ftdi_context *ftdi, int verbose) } else if (ftdi->type == TYPE_232H) { - char *cbush_mux[] = {"TRISTATE","TXLED","RXLED", "TXRXLED","PWREN", + const char *cbush_mux[] = {"TRISTATE","TXLED","RXLED", "TXRXLED","PWREN", "SLEEP","DRIVE_0","DRIVE_1","IOMODE","TXDEN", "CLK30","CLK15","CLK7_5" }; @@ -3658,7 +3899,7 @@ int ftdi_eeprom_decode(struct ftdi_context *ftdi, int verbose) } else if (ftdi->type == TYPE_230X) { - char *cbusx_mux[] = {"TRISTATE","TXLED","RXLED", "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#", @@ -3684,11 +3925,11 @@ int ftdi_eeprom_decode(struct ftdi_context *ftdi, int verbose) 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) print_inverted_bits(eeprom->invert); @@ -4185,12 +4426,16 @@ int ftdi_set_eeprom_user_data(struct ftdi_context *ftdi, const char * buf, int s */ 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; } @@ -4473,7 +4718,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 "";