X-Git-Url: http://developer.intra2net.com/git/?p=libftdi;a=blobdiff_plain;f=src%2Fftdi.c;h=07687e81d7f6bb7f8256b72323fe2d328ab9f3ad;hp=66c159e08bbd3b5fcb4f3456a8b6cbb0ea5852c7;hb=a7c32c59a04044e70612b3ea598ab51b2cff3174;hpb=f15786e4a4fdb935f639e16ab69d717f3d29bd2b diff --git a/src/ftdi.c b/src/ftdi.c index 66c159e..07687e8 100644 --- a/src/ftdi.c +++ b/src/ftdi.c @@ -34,7 +34,9 @@ #include #include +#include "ftdi_i.h" #include "ftdi.h" +#include "ftdi_version_i.h" #define ftdi_error_return(code, str) do { \ ftdi->error_str = str; \ @@ -147,12 +149,23 @@ struct ftdi_context *ftdi_new(void) \retval 0: all fine \retval -1: unknown interface \retval -2: USB device unavailable + \retval -3: Device already open, interface can't be set in that state */ int ftdi_set_interface(struct ftdi_context *ftdi, enum ftdi_interface interface) { if (ftdi == NULL) ftdi_error_return(-2, "USB device unavailable"); + if (ftdi->usb_dev != NULL) + { + int check_interface = interface; + if (check_interface == INTERFACE_ANY) + check_interface = INTERFACE_A; + + if (ftdi->index != check_interface) + ftdi_error_return(-3, "Interface can not be changed on an already open device"); + } + switch (interface) { case INTERFACE_ANY: @@ -257,6 +270,23 @@ void ftdi_set_usbdev (struct ftdi_context *ftdi, libusb_device_handle *usb) ftdi->usb_dev = usb; } +/** + * @brief Get libftdi library version + * + * @return ftdi_version_info Library version information + **/ +struct ftdi_version_info ftdi_get_library_version() +{ + struct ftdi_version_info ver; + + ver.major = FTDI_MAJOR_VERSION; + ver.minor = FTDI_MINOR_VERSION; + ver.micro = FTDI_MICRO_VERSION; + ver.version_str = FTDI_VERSION_STRING; + ver.snapshot_str = FTDI_SNAPSHOT_VERSION; + + return ver; +} /** Finds all ftdi devices with given VID:PID on the usb bus. Creates a new @@ -1069,6 +1099,18 @@ static int ftdi_to_clkbits_AM(int baudrate, unsigned long *encoded_divisor) clk/2 -> 2 From /2, 0.125 steps may be taken. The fractional part has frac_code encoding + + value[13:0] of value is the divisor + index[9] mean 12 MHz Base(120 MHz/10) rate versus 3 MHz (48 MHz/16) else + + H Type have all features above with + {index[8],value[15:14]} is the encoded subdivisor + + FT232R, FT2232 and FT232BM have no option for 12 MHz and with + {index[0],value[15:14]} is the encoded subdivisor + + AM Type chips have only four fractional subdivisors at value[15:14] + for subdivisors 0, 0.5, 0.25, 0.125 */ static int ftdi_to_clkbits(int baudrate, unsigned int clk, int clk_div, unsigned long *encoded_divisor) { @@ -1100,7 +1142,11 @@ static int ftdi_to_clkbits(int baudrate, unsigned int clk, int clk_div, unsigned best_divisor = divisor/2; if(best_divisor > 0x20000) best_divisor = 0x1ffff; - best_baud = clk*8/clk_div/best_divisor; + best_baud = clk*16/clk_div/best_divisor; + if (best_baud & 1) /* Decide if to round up or down*/ + best_baud = best_baud /2 +1; + else + best_baud = best_baud /2; *encoded_divisor = (best_divisor >> 3) | (frac_code[best_divisor & 0x7] << 14); } return best_baud; @@ -1149,7 +1195,7 @@ static int ftdi_convert_baudrate(int baudrate, struct ftdi_context *ftdi, } // Split into "value" and "index" values *value = (unsigned short)(encoded_divisor & 0xFFFF); - if (ftdi->type == TYPE_2232C || ftdi->type == TYPE_2232H || + if (ftdi->type == TYPE_2232H || ftdi->type == TYPE_4232H || ftdi->type == TYPE_232H ) { *index = (unsigned short)(encoded_divisor >> 8); @@ -1867,21 +1913,19 @@ int ftdi_read_data_get_chunksize(struct ftdi_context *ftdi, unsigned int *chunks return 0; } - /** - Enable bitbang mode. - - \deprecated use \ref ftdi_set_bitmode with mode BITMODE_BITBANG instead + Enable/disable bitbang modes. \param ftdi pointer to ftdi_context \param bitmask Bitmask to configure lines. HIGH/ON value configures a line as output. + \param mode Bitbang mode: use the values defined in \ref ftdi_mpsse_mode \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) +int ftdi_set_bitmode(struct ftdi_context *ftdi, unsigned char bitmask, unsigned char mode) { unsigned short usb_val; @@ -1889,15 +1933,12 @@ int ftdi_enable_bitbang(struct ftdi_context *ftdi, unsigned char bitmask) 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); - - 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) - ftdi_error_return(-1, "unable to enter bitbang mode. Perhaps not a BM type chip?"); + 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) + ftdi_error_return(-1, "unable to configure bitbang mode. Perhaps not a BM/2232C type chip?"); - ftdi->bitbang_enabled = 1; + ftdi->bitbang_mode = mode; + ftdi->bitbang_enabled = (mode == BITMODE_RESET) ? 0 : 1; return 0; } @@ -1922,34 +1963,6 @@ int ftdi_disable_bitbang(struct ftdi_context *ftdi) return 0; } -/** - Enable/disable bitbang modes. - - \param ftdi pointer to ftdi_context - \param bitmask Bitmask to configure lines. - HIGH/ON value configures a line as output. - \param mode Bitbang mode: use the values defined in \ref ftdi_mpsse_mode - - \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) - ftdi_error_return(-1, "unable to configure bitbang mode. Perhaps not a 2232C type chip?"); - - ftdi->bitbang_mode = mode; - ftdi->bitbang_enabled = (mode == BITMODE_RESET) ? 0 : 1; - return 0; -} /** Directly read pin state, circumventing the read buffer. Useful for bitbang mode. @@ -2356,7 +2369,6 @@ int ftdi_eeprom_initdefaults(struct ftdi_context *ftdi, char * manufacturer, strcpy(eeprom->serial, serial); } - if (ftdi->type == TYPE_R) { eeprom->max_power = 90; @@ -2565,7 +2577,7 @@ int ftdi_eeprom_build(struct ftdi_context *ftdi) output[0x08] = j; // Addr 09: Max power consumption: max power = value * 2 mA - output[0x09] = eeprom->max_power>>1; + output[0x09] = eeprom->max_power / MAX_POWER_MILLIAMP_PER_UNIT; if (ftdi->type != TYPE_AM) { @@ -2827,8 +2839,83 @@ int ftdi_eeprom_build(struct ftdi_context *ftdi) break; case TYPE_4232H: + if (eeprom->channel_a_driver == DRIVER_VCP) + output[0x00] |= DRIVER_VCP; + else + output[0x00] &= ~DRIVER_VCP; + if (eeprom->channel_b_driver == DRIVER_VCP) + output[0x01] |= DRIVER_VCP; + else + output[0x01] &= ~DRIVER_VCP; + if (eeprom->channel_c_driver == DRIVER_VCP) + output[0x00] |= (DRIVER_VCP << 4); + else + output[0x00] &= ~(DRIVER_VCP << 4); + if (eeprom->channel_d_driver == DRIVER_VCP) + output[0x01] |= (DRIVER_VCP << 4); + else + output[0x01] &= ~(DRIVER_VCP << 4); + + if (eeprom->suspend_pull_downs == 1) + output[0x0a] |= 0x4; + else + output[0x0a] &= ~0x4; + + if (eeprom->channel_a_rs485enable) + output[0x0b] |= CHANNEL_IS_RS485 << 0; + else + output[0x0b] &= ~(CHANNEL_IS_RS485 << 0); + if (eeprom->channel_b_rs485enable) + output[0x0b] |= CHANNEL_IS_RS485 << 1; + else + output[0x0b] &= ~(CHANNEL_IS_RS485 << 1); + if (eeprom->channel_c_rs485enable) + output[0x0b] |= CHANNEL_IS_RS485 << 2; + else + output[0x0b] &= ~(CHANNEL_IS_RS485 << 2); + if (eeprom->channel_d_rs485enable) + output[0x0b] |= CHANNEL_IS_RS485 << 3; + else + output[0x0b] &= ~(CHANNEL_IS_RS485 << 3); + + if (eeprom->group0_drive > DRIVE_16MA) + output[0x0c] |= DRIVE_16MA; + else + output[0x0c] |= eeprom->group0_drive; + if (eeprom->group0_schmitt == IS_SCHMITT) + output[0x0c] |= IS_SCHMITT; + if (eeprom->group0_slew == SLOW_SLEW) + output[0x0c] |= SLOW_SLEW; + + if (eeprom->group1_drive > DRIVE_16MA) + output[0x0c] |= DRIVE_16MA<<4; + else + output[0x0c] |= eeprom->group1_drive<<4; + if (eeprom->group1_schmitt == IS_SCHMITT) + output[0x0c] |= IS_SCHMITT<<4; + if (eeprom->group1_slew == SLOW_SLEW) + output[0x0c] |= SLOW_SLEW<<4; + + if (eeprom->group2_drive > DRIVE_16MA) + output[0x0d] |= DRIVE_16MA; + else + output[0x0d] |= eeprom->group2_drive; + if (eeprom->group2_schmitt == IS_SCHMITT) + output[0x0d] |= IS_SCHMITT; + if (eeprom->group2_slew == SLOW_SLEW) + output[0x0d] |= SLOW_SLEW; + + if (eeprom->group3_drive > DRIVE_16MA) + output[0x0d] |= DRIVE_16MA<<4; + else + output[0x0d] |= eeprom->group3_drive<<4; + if (eeprom->group3_schmitt == IS_SCHMITT) + output[0x0d] |= IS_SCHMITT<<4; + if (eeprom->group3_slew == SLOW_SLEW) + output[0x0d] |= SLOW_SLEW<<4; + output[0x18] = eeprom->chip; - fprintf(stderr,"FIXME: Build FT4232H specific EEPROM settings\n"); + break; case TYPE_232H: output[0x00] = type2bit(eeprom->channel_a_type, TYPE_232H); @@ -2961,7 +3048,7 @@ int ftdi_eeprom_decode(struct ftdi_context *ftdi, int verbose) eeprom->remote_wakeup = buf[0x08] & 0x20; // Addr 09: Max power consumption: max power = value * 2 mA - eeprom->max_power = buf[0x09]; + eeprom->max_power = MAX_POWER_MILLIAMP_PER_UNIT * buf[0x09]; // Addr 0A: Chip configuration // Bit 7: 0 - reserved @@ -3084,7 +3171,7 @@ int ftdi_eeprom_decode(struct ftdi_context *ftdi, int verbose) else if (ftdi->type == TYPE_R) { /* TYPE_R flags D2XX, not VCP as all others*/ - eeprom->channel_a_driver = (~buf[0x00]) & DRIVER_VCP; + eeprom->channel_a_driver = ~buf[0x00] & DRIVER_VCP; eeprom->high_current = buf[0x00] & HIGH_CURRENT_DRIVE_R; if ( (buf[0x01]&0x40) != 0x40) fprintf(stderr, @@ -3106,15 +3193,26 @@ int ftdi_eeprom_decode(struct ftdi_context *ftdi, int verbose) eeprom->cbus_function[3] = (buf[0x15] >> 4) & 0x0f; eeprom->cbus_function[4] = buf[0x16] & 0x0f; } - else if ((ftdi->type == TYPE_2232H) ||(ftdi->type == TYPE_4232H)) + else if ((ftdi->type == TYPE_2232H) || (ftdi->type == TYPE_4232H)) { - eeprom->channel_a_type = bit2type(buf[0x00] & 0x7); eeprom->channel_a_driver = buf[0x00] & DRIVER_VCP; - eeprom->channel_b_type = bit2type(buf[0x01] & 0x7); eeprom->channel_b_driver = buf[0x01] & DRIVER_VCP; if (ftdi->type == TYPE_2232H) + { + eeprom->channel_a_type = bit2type(buf[0x00] & 0x7); + eeprom->channel_b_type = bit2type(buf[0x01] & 0x7); eeprom->suspend_dbus7 = buf[0x01] & SUSPEND_DBUS7_BIT; + } + else + { + eeprom->channel_c_driver = (buf[0x00] >> 4) & DRIVER_VCP; + eeprom->channel_d_driver = (buf[0x01] >> 4) & DRIVER_VCP; + eeprom->channel_a_rs485enable = buf[0x0b] & (CHANNEL_IS_RS485 << 0); + eeprom->channel_b_rs485enable = buf[0x0b] & (CHANNEL_IS_RS485 << 1); + eeprom->channel_c_rs485enable = buf[0x0b] & (CHANNEL_IS_RS485 << 2); + eeprom->channel_d_rs485enable = buf[0x0b] & (CHANNEL_IS_RS485 << 3); + } eeprom->chip = buf[0x18]; eeprom->group0_drive = buf[0x0c] & DRIVE_16MA; @@ -3166,7 +3264,7 @@ int ftdi_eeprom_decode(struct ftdi_context *ftdi, int verbose) if (eeprom->self_powered) fprintf(stdout, "Self-Powered%s", (eeprom->remote_wakeup)?", USB Remote Wake Up\n":"\n"); else - fprintf(stdout, "Bus Powered: %3d mA%s", eeprom->max_power * 2, + fprintf(stdout, "Bus Powered: %3d mA%s", eeprom->max_power, (eeprom->remote_wakeup)?" USB Remote Wake Up\n":"\n"); if (eeprom->manufacturer) fprintf(stdout, "Manufacturer: %s\n",eeprom->manufacturer); @@ -3256,7 +3354,6 @@ int ftdi_eeprom_decode(struct ftdi_context *ftdi, int verbose) fprintf(stdout,"C%d Function: %s\n", i, cbush_mux[eeprom->cbus_function[i]]); } - } if (ftdi->type == TYPE_R) @@ -3362,6 +3459,24 @@ int ftdi_get_eeprom_value(struct ftdi_context *ftdi, enum ftdi_eeprom_value valu case CHANNEL_B_DRIVER: *value = ftdi->eeprom->channel_b_driver; break; + case CHANNEL_C_DRIVER: + *value = ftdi->eeprom->channel_c_driver; + break; + case CHANNEL_D_DRIVER: + *value = ftdi->eeprom->channel_d_driver; + break; + case CHANNEL_A_RS485: + *value = ftdi->eeprom->channel_a_rs485enable; + break; + case CHANNEL_B_RS485: + *value = ftdi->eeprom->channel_b_rs485enable; + break; + case CHANNEL_C_RS485: + *value = ftdi->eeprom->channel_c_rs485enable; + break; + case CHANNEL_D_RS485: + *value = ftdi->eeprom->channel_d_rs485enable; + break; case CBUS_FUNCTION_0: *value = ftdi->eeprom->cbus_function[0]; break; @@ -3531,6 +3646,24 @@ int ftdi_set_eeprom_value(struct ftdi_context *ftdi, enum ftdi_eeprom_value valu case CHANNEL_B_DRIVER: ftdi->eeprom->channel_b_driver = value; break; + case CHANNEL_C_DRIVER: + ftdi->eeprom->channel_c_driver = value; + break; + case CHANNEL_D_DRIVER: + ftdi->eeprom->channel_d_driver = value; + break; + case CHANNEL_A_RS485: + ftdi->eeprom->channel_a_rs485enable = value; + break; + case CHANNEL_B_RS485: + ftdi->eeprom->channel_b_rs485enable = value; + break; + case CHANNEL_C_RS485: + ftdi->eeprom->channel_c_rs485enable = value; + break; + case CHANNEL_D_RS485: + ftdi->eeprom->channel_d_rs485enable = value; + break; case CBUS_FUNCTION_0: ftdi->eeprom->cbus_function[0] = value; break;