X-Git-Url: http://developer.intra2net.com/git/?p=libftdi;a=blobdiff_plain;f=src%2Fftdi.c;h=9495fb5945097e655e2f7383a8d01b3d6c039cff;hp=3bfd72ffbd82bfe9161e62c3e2480eb3d63d37b9;hb=ae3d154b7641b120f537c6d86871371c9d75c9e9;hpb=c45d26308211c383903cb06f15ba7575d807fe06 diff --git a/src/ftdi.c b/src/ftdi.c index 3bfd72f..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)); @@ -613,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"); @@ -750,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) @@ -824,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. @@ -961,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 @@ -968,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) @@ -987,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 @@ -994,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) @@ -1008,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 @@ -1016,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) { @@ -1253,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); } @@ -1859,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)"); @@ -2213,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 @@ -2235,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 @@ -2548,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; @@ -2596,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) @@ -3181,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++)