X-Git-Url: http://developer.intra2net.com/git/?p=libftdi;a=blobdiff_plain;f=src%2Fftdi.c;h=0c8d54000a66cd19e8588f2916a341daebdf52f1;hp=fc561b5a6cd4c4363de0f2a5c4954d2df90ff2dd;hb=9956d4289d04f1c67a8738a7b8b32e1345ab0968;hpb=213fb57e9e2ce7e047d753bea68369d524760c0c diff --git a/src/ftdi.c b/src/ftdi.c index fc561b5..0c8d540 100644 --- a/src/ftdi.c +++ b/src/ftdi.c @@ -2,7 +2,7 @@ ftdi.c - description ------------------- begin : Fri Apr 4 2003 - copyright : (C) 2003-2010 by Intra2net AG + copyright : (C) 2003-2011 by Intra2net AG and the libftdi developers email : opensource@intra2net.com ***************************************************************************/ @@ -63,6 +63,8 @@ static void ftdi_usb_close_internal (struct ftdi_context *ftdi) { libusb_close (ftdi->usb_dev); ftdi->usb_dev = NULL; + if(ftdi->eeprom) + ftdi->eeprom->initialized_for_connected_device = 0; } } @@ -74,6 +76,7 @@ static void ftdi_usb_close_internal (struct ftdi_context *ftdi) \retval 0: all fine \retval -1: couldn't allocate read buffer \retval -2: couldn't allocate struct buffer + \retval -3: libusb_init() failed \remark This should be called before all functions */ @@ -94,12 +97,15 @@ int ftdi_init(struct ftdi_context *ftdi) ftdi->readbuffer_remaining = 0; ftdi->writebuffer_chunksize = 4096; ftdi->max_packet_size = 0; + ftdi->error_str = NULL; + ftdi->module_detach_mode = AUTO_DETACH_SIO_MODULE; + + if (libusb_init(&ftdi->usb_ctx) < 0) + ftdi_error_return(-3, "libusb_init() failed"); ftdi_set_interface(ftdi, INTERFACE_ANY); ftdi->bitbang_mode = 1; /* when bitbang is enabled this holds the number of the mode */ - ftdi->error_str = NULL; - if (eeprom == 0) ftdi_error_return(-2, "Can't malloc struct ftdi_eeprom"); memset(eeprom, 0, sizeof(struct ftdi_eeprom)); @@ -218,7 +224,12 @@ void ftdi_deinit(struct ftdi_context *ftdi) free(ftdi->eeprom); ftdi->eeprom = NULL; } - libusb_exit(ftdi->usb_ctx); + + if (ftdi->usb_ctx) + { + libusb_exit(ftdi->usb_ctx); + ftdi->usb_ctx = NULL; + } } /** @@ -248,8 +259,10 @@ void ftdi_set_usbdev (struct ftdi_context *ftdi, libusb_device_handle *usb) /** - Finds all ftdi devices on the usb bus. Creates a new ftdi_device_list which - needs to be deallocated by ftdi_list_free() after use. + 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) \param ftdi pointer to ftdi_context \param devlist Pointer where to store list of found devices @@ -258,7 +271,6 @@ void ftdi_set_usbdev (struct ftdi_context *ftdi, libusb_device_handle *usb) \retval >0: number of devices found \retval -3: out of memory - \retval -4: libusb_init() failed \retval -5: libusb_get_device_list() failed \retval -6: libusb_get_device_descriptor() failed */ @@ -270,9 +282,6 @@ int ftdi_usb_find_all(struct ftdi_context *ftdi, struct ftdi_device_list **devli int count = 0; int i = 0; - if (libusb_init(&ftdi->usb_ctx) < 0) - ftdi_error_return(-4, "libusb_init() failed"); - if (libusb_get_device_list(ftdi->usb_ctx, &devs) < 0) ftdi_error_return(-5, "libusb_get_device_list() failed"); @@ -284,22 +293,26 @@ int ftdi_usb_find_all(struct ftdi_context *ftdi, struct ftdi_device_list **devli struct libusb_device_descriptor desc; if (libusb_get_device_descriptor(dev, &desc) < 0) - ftdi_error_return(-6, "libusb_get_device_descriptor() failed"); + ftdi_error_return_free_device_list(-6, "libusb_get_device_descriptor() failed", devs); - if (desc.idVendor == vendor && desc.idProduct == product) + if (((vendor != 0 && product != 0) && + desc.idVendor == vendor && desc.idProduct == product) || + ((vendor == 0 && product == 0) && + (desc.idVendor == 0x403) && (desc.idProduct == 0x6001 || desc.idProduct == 0x6010 + || desc.idProduct == 0x6011 || desc.idProduct == 0x6014))) { *curdev = (struct ftdi_device_list*)malloc(sizeof(struct ftdi_device_list)); if (!*curdev) - ftdi_error_return(-3, "out of memory"); + ftdi_error_return_free_device_list(-3, "out of memory", devs); (*curdev)->next = NULL; (*curdev)->dev = dev; - + libusb_ref_device(dev); curdev = &(*curdev)->next; count++; } } - + libusb_free_device_list(devs,1); return count; } @@ -315,6 +328,7 @@ void ftdi_list_free(struct ftdi_device_list **devlist) for (curdev = *devlist; curdev != NULL;) { next = curdev->next; + libusb_unref_device(curdev->dev); free(curdev); curdev = next; } @@ -423,7 +437,7 @@ static unsigned int _ftdi_determine_max_packet_size(struct ftdi_context *ftdi, l // 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. - if (ftdi->type == TYPE_2232H || ftdi->type == TYPE_4232H) + if (ftdi->type == TYPE_2232H || ftdi->type == TYPE_4232H || ftdi->type == TYPE_232H ) packet_size = 512; else packet_size = 64; @@ -469,7 +483,7 @@ static unsigned int _ftdi_determine_max_packet_size(struct ftdi_context *ftdi, l \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 + \retval -11: libusb_detach_kernel_driver() failed \retval -12: libusb_get_configuration() failed */ int ftdi_usb_open_dev(struct ftdi_context *ftdi, libusb_device *dev) @@ -498,8 +512,11 @@ int ftdi_usb_open_dev(struct ftdi_context *ftdi, libusb_device *dev) // 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. - if (libusb_detach_kernel_driver(ftdi->usb_dev, ftdi->interface) !=0) - detach_errno = errno; + if (ftdi->module_detach_mode == AUTO_DETACH_SIO_MODULE) + { + 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"); @@ -556,6 +573,8 @@ int ftdi_usb_open_dev(struct ftdi_context *ftdi, libusb_device *dev) ftdi->type = TYPE_2232H; else if (desc.bcdDevice == 0x800) ftdi->type = TYPE_4232H; + else if (desc.bcdDevice == 0x900) + ftdi->type = TYPE_232H; // Determine maximum packet size ftdi->max_packet_size = _ftdi_determine_max_packet_size(ftdi, dev); @@ -601,7 +620,6 @@ int ftdi_usb_open(struct ftdi_context *ftdi, int vendor, int product) \retval -7: set baudrate failed \retval -8: get product description failed \retval -9: get serial number failed - \retval -11: libusb_init() failed \retval -12: libusb_get_device_list() failed \retval -13: libusb_get_device_descriptor() failed */ @@ -643,9 +661,6 @@ int ftdi_usb_open_desc_index(struct ftdi_context *ftdi, int vendor, int product, char string[256]; int i = 0; - if (libusb_init(&ftdi->usb_ctx) < 0) - ftdi_error_return(-11, "libusb_init() failed"); - if (ftdi == NULL) ftdi_error_return(-11, "ftdi context invalid"); @@ -669,12 +684,12 @@ int ftdi_usb_open_desc_index(struct ftdi_context *ftdi, int vendor, int product, { if (libusb_get_string_descriptor_ascii(ftdi->usb_dev, desc.iProduct, (unsigned char *)string, sizeof(string)) < 0) { - libusb_close (ftdi->usb_dev); + ftdi_usb_close_internal (ftdi); ftdi_error_return_free_device_list(-8, "unable to fetch product description", devs); } if (strncmp(string, description, sizeof(string)) != 0) { - libusb_close (ftdi->usb_dev); + ftdi_usb_close_internal (ftdi); continue; } } @@ -724,7 +739,6 @@ int ftdi_usb_open_desc_index(struct ftdi_context *ftdi, int vendor, int product, \note The description format may be extended in later versions. \retval 0: all fine - \retval -1: libusb_init() failed \retval -2: libusb_get_device_list() failed \retval -3: usb device not found \retval -4: unable to open device @@ -752,9 +766,6 @@ int ftdi_usb_open_string(struct ftdi_context *ftdi, const char* description) unsigned int bus_number, device_address; int i = 0; - if (libusb_init (&ftdi->usb_ctx) < 0) - ftdi_error_return(-1, "libusb_init() failed"); - if (libusb_get_device_list(ftdi->usb_ctx, &devs) < 0) ftdi_error_return(-2, "libusb_get_device_list() failed"); @@ -953,34 +964,30 @@ int ftdi_usb_close(struct ftdi_context *ftdi) return rtn; } -/** - ftdi_convert_baudrate returns nearest supported baud rate to that requested. +/* ftdi_to_clkbits_AM For the AM device, convert a requested baudrate + to encoded divisor and the achievable baudrate Function is only used internally \internal + + See AN120 + clk/1 -> 0 + clk/1.5 -> 1 + clk/2 -> 2 + From /2, 0.125/ 0.25 and 0.5 steps may be taken + The fractional part has frac_code encoding */ -static int ftdi_convert_baudrate(int baudrate, struct ftdi_context *ftdi, - unsigned short *value, unsigned short *index) +static int ftdi_to_clkbits_AM(int baudrate, unsigned long *encoded_divisor) + { + static const char frac_code[8] = {0, 3, 2, 4, 1, 5, 6, 7}; static const char am_adjust_up[8] = {0, 0, 0, 1, 0, 3, 2, 1}; static const char am_adjust_dn[8] = {0, 0, 0, 1, 0, 1, 2, 3}; - static const char frac_code[8] = {0, 3, 2, 4, 1, 5, 6, 7}; int divisor, best_divisor, best_baud, best_baud_diff; - unsigned long encoded_divisor; - int i; - - if (baudrate <= 0) - { - // Return error - return -1; - } - divisor = 24000000 / baudrate; + int i; - if (ftdi->type == TYPE_AM) - { - // Round down to supported fraction (AM only) - divisor -= am_adjust_dn[divisor & 7]; - } + // Round down to supported fraction (AM only) + divisor -= am_adjust_dn[divisor & 7]; // Try this divisor and the one above it (because division rounds down) best_divisor = 0; @@ -998,11 +1005,6 @@ static int ftdi_convert_baudrate(int baudrate, struct ftdi_context *ftdi, // Round up to minimum supported divisor try_divisor = 8; } - else if (ftdi->type != TYPE_AM && try_divisor < 12) - { - // BM doesn't support divisors 9 through 11 inclusive - try_divisor = 12; - } else if (divisor < 16) { // AM doesn't support divisors 9 through 15 inclusive @@ -1010,23 +1012,12 @@ static int ftdi_convert_baudrate(int baudrate, struct ftdi_context *ftdi, } else { - if (ftdi->type == TYPE_AM) + // Round up to supported fraction (AM only) + try_divisor += am_adjust_up[try_divisor & 7]; + if (try_divisor > 0x1FFF8) { - // Round up to supported fraction (AM only) - try_divisor += am_adjust_up[try_divisor & 7]; - if (try_divisor > 0x1FFF8) - { - // Round down to maximum supported divisor value (for AM) - try_divisor = 0x1FFF8; - } - } - else - { - if (try_divisor > 0x1FFFF) - { - // Round down to maximum supported divisor value (for BM) - try_divisor = 0x1FFFF; - } + // Round down to maximum supported divisor value (for AM) + try_divisor = 0x1FFF8; } } // Get estimated baud rate (to nearest integer) @@ -1054,19 +1045,124 @@ static int ftdi_convert_baudrate(int baudrate, struct ftdi_context *ftdi, } } // Encode the best divisor value - encoded_divisor = (best_divisor >> 3) | (frac_code[best_divisor & 7] << 14); + *encoded_divisor = (best_divisor >> 3) | (frac_code[best_divisor & 7] << 14); // Deal with special cases for encoded value - if (encoded_divisor == 1) + if (*encoded_divisor == 1) { - encoded_divisor = 0; // 3000000 baud + *encoded_divisor = 0; // 3000000 baud } - else if (encoded_divisor == 0x4001) + else if (*encoded_divisor == 0x4001) { - encoded_divisor = 1; // 2000000 baud (BM only) + *encoded_divisor = 1; // 2000000 baud (BM only) + } + return best_baud; +} + +/* ftdi_to_clkbits Convert a requested baudrate for a given system clock and predivisor + to encoded divisor and the achievable baudrate + Function is only used internally + \internal + + See AN120 + clk/1 -> 0 + clk/1.5 -> 1 + 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) +{ + static const char frac_code[8] = {0, 3, 2, 4, 1, 5, 6, 7}; + int best_baud = 0; + int divisor, best_divisor; + if (baudrate >= clk/clk_div) + { + *encoded_divisor = 0; + best_baud = clk/clk_div; + } + else if (baudrate >= clk/(clk_div + clk_div/2)) + { + *encoded_divisor = 1; + best_baud = clk/(clk_div + clk_div/2); + } + else if (baudrate >= clk/(2*clk_div)) + { + *encoded_divisor = 2; + best_baud = clk/(2*clk_div); + } + else + { + /* We divide by 16 to have 3 fractional bits and one bit for rounding */ + divisor = clk*16/clk_div / baudrate; + if (divisor & 1) /* Decide if to round up or down*/ + best_divisor = divisor /2 +1; + else + best_divisor = divisor/2; + if(best_divisor > 0x20000) + best_divisor = 0x1ffff; + best_baud = clk*8/clk_div/best_divisor; + *encoded_divisor = (best_divisor >> 3) | (frac_code[best_divisor & 0x7] << 14); + } + return best_baud; +} +/** + ftdi_convert_baudrate returns nearest supported baud rate to that requested. + Function is only used internally + \internal +*/ +static int ftdi_convert_baudrate(int baudrate, struct ftdi_context *ftdi, + unsigned short *value, unsigned short *index) +{ + int best_baud; + unsigned long encoded_divisor; + + if (baudrate <= 0) + { + // Return error + return -1; + } + +#define H_CLK 120000000 +#define C_CLK 48000000 + if ((ftdi->type == TYPE_2232H) || (ftdi->type == TYPE_4232H) || (ftdi->type == TYPE_232H )) + { + if(baudrate*10 > H_CLK /0x3fff) + { + /* On H Devices, use 12 000 000 Baudrate when possible + We have a 14 bit divisor, a 1 bit divisor switch (10 or 16) + three fractional bits and a 120 MHz clock + Assume AN_120 "Sub-integer divisors between 0 and 2 are not allowed" holds for + DIV/10 CLK too, so /1, /1.5 and /2 can be handled the same*/ + best_baud = ftdi_to_clkbits(baudrate, H_CLK, 10, &encoded_divisor); + encoded_divisor |= 0x20000; /* switch on CLK/10*/ + } + 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 )) + { + best_baud = ftdi_to_clkbits(baudrate, C_CLK, 16, &encoded_divisor); + } + else + { + best_baud = ftdi_to_clkbits_AM(baudrate, &encoded_divisor); } // Split into "value" and "index" values *value = (unsigned short)(encoded_divisor & 0xFFFF); - if (ftdi->type == TYPE_2232C || ftdi->type == TYPE_2232H || ftdi->type == TYPE_4232H) + if (ftdi->type == TYPE_2232C || ftdi->type == TYPE_2232H || + ftdi->type == TYPE_4232H || ftdi->type == TYPE_232H ) { *index = (unsigned short)(encoded_divisor >> 8); *index &= 0xFF00; @@ -1080,6 +1176,16 @@ static int ftdi_convert_baudrate(int baudrate, struct ftdi_context *ftdi, } /** + * @brief Wrapper function to export ftdi_convert_baudrate() to the unit test + * Do not use, it's only for the unit test framework + **/ +int convert_baudrate_UT_export(int baudrate, struct ftdi_context *ftdi, + unsigned short *value, unsigned short *index) +{ + return ftdi_convert_baudrate(baudrate, ftdi, value, index); +} + +/** Sets the chip baud rate \param ftdi pointer to ftdi_context @@ -1984,7 +2090,7 @@ int ftdi_poll_modem_status(struct ftdi_context *ftdi, unsigned short *status) 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"); - *status = (usb_val[1] << 8) | usb_val[0]; + *status = (usb_val[1] << 8) | (usb_val[0] & 0xFF); return 0; } @@ -2168,7 +2274,7 @@ int ftdi_set_error_char(struct ftdi_context *ftdi, } /** - Init eeprom with default values. + Init eeprom with default values for the connected device \param ftdi pointer to ftdi_context \param manufacturer String to use as Manufacturer \param product String to use as Product description @@ -2177,6 +2283,7 @@ int ftdi_set_error_char(struct ftdi_context *ftdi, \retval 0: all fine \retval -1: No struct ftdi_context \retval -2: No struct ftdi_eeprom + \retval -3: No connected device or device not yet opened */ int ftdi_eeprom_initdefaults(struct ftdi_context *ftdi, char * manufacturer, char * product, char * serial) @@ -2192,11 +2299,18 @@ int ftdi_eeprom_initdefaults(struct ftdi_context *ftdi, char * manufacturer, eeprom = ftdi->eeprom; memset(eeprom, 0, sizeof(struct ftdi_eeprom)); + if (ftdi->usb_dev == NULL) + ftdi_error_return(-3, "No connected device or device not yet opened"); + eeprom->vendor_id = 0x0403; - eeprom->use_serial = USE_SERIAL_NUM; + eeprom->use_serial = 1; if ((ftdi->type == TYPE_AM) || (ftdi->type == TYPE_BM) || (ftdi->type == TYPE_R)) eeprom->product_id = 0x6001; + else if (ftdi->type == TYPE_4232H) + eeprom->product_id = 0x6011; + else if (ftdi->type == TYPE_232H) + eeprom->product_id = 0x6014; else eeprom->product_id = 0x6010; if (ftdi->type == TYPE_AM) @@ -2218,11 +2332,31 @@ int ftdi_eeprom_initdefaults(struct ftdi_context *ftdi, char * manufacturer, if (eeprom->product) free (eeprom->product); eeprom->product = NULL; + if(product) { eeprom->product = malloc(strlen(product)+1); if (eeprom->product) strcpy(eeprom->product, product); } + else + { + const char* default_product; + switch(ftdi->type) + { + case TYPE_AM: default_product = "AM"; break; + case TYPE_BM: default_product = "BM"; break; + case TYPE_2232C: default_product = "Dual RS232"; break; + case TYPE_R: default_product = "FT232R USB UART"; break; + case TYPE_2232H: default_product = "Dual RS232-HS"; break; + case TYPE_4232H: default_product = "FT4232H"; break; + case TYPE_232H: default_product = "Single-RS232-HS"; break; + default: + ftdi_error_return(-3, "Unknown chip type"); + } + eeprom->product = malloc(strlen(default_product) +1); + if (eeprom->product) + strcpy(eeprom->product, default_product); + } if (eeprom->serial) free (eeprom->serial); @@ -2246,9 +2380,72 @@ int ftdi_eeprom_initdefaults(struct ftdi_context *ftdi, char * manufacturer, eeprom->cbus_function[4] = CBUS_SLEEP; } else + { + if(ftdi->type == TYPE_232H) + { + int i; + for (i=0; i<10; i++) + eeprom->cbus_function[i] = CBUSH_TRISTATE; + } eeprom->size = -1; + } + eeprom->initialized_for_connected_device = 1; return 0; } +/*FTD2XX doesn't check for values not fitting in the ACBUS Signal oprtions*/ +void set_ft232h_cbus(struct ftdi_eeprom *eeprom, unsigned char * output) +{ + int i; + for(i=0; i<5;i++) + { + int mode_low, mode_high; + if (eeprom->cbus_function[2*i]> CBUSH_CLK7_5) + mode_low = CBUSH_TRISTATE; + else + mode_low = eeprom->cbus_function[2*i]; + if (eeprom->cbus_function[2*i+1]> CBUSH_CLK7_5) + mode_high = CBUSH_TRISTATE; + else + mode_high = eeprom->cbus_function[2*i]; + + output[0x18+i] = mode_high <<4 | mode_low; + } +} +/* Return the bits for the encoded EEPROM Structure of a requested Mode + * + */ +static unsigned char type2bit(unsigned char type, enum ftdi_chip_type chip) +{ + switch (chip) + { + case TYPE_2232H: + case TYPE_2232C: + { + switch (type) + { + case CHANNEL_IS_UART: return 0; + case CHANNEL_IS_FIFO: return 0x01; + case CHANNEL_IS_OPTO: return 0x02; + case CHANNEL_IS_CPU : return 0x04; + default: return 0; + } + } + case TYPE_232H: + { + switch (type) + { + case CHANNEL_IS_UART : return 0; + case CHANNEL_IS_FIFO : return 0x01; + case CHANNEL_IS_OPTO : return 0x02; + case CHANNEL_IS_CPU : return 0x04; + case CHANNEL_IS_FT1284 : return 0x08; + default: return 0; + } + } + default: return 0; + } + return 0; +} /** Build binary buffer from ftdi_eeprom structure. @@ -2313,6 +2510,9 @@ int ftdi_eeprom_build(struct ftdi_context *ftdi) case TYPE_4232H: user_area_size = 86; break; + case TYPE_232H: + user_area_size = 80; + break; default: user_area_size = 0; break; @@ -2357,6 +2557,9 @@ int ftdi_eeprom_build(struct ftdi_context *ftdi) case TYPE_4232H: output[0x07] = 0x08; break; + case TYPE_232H: + output[0x07] = 0x09; + break; default: output[0x07] = 0x00; } @@ -2399,9 +2602,12 @@ int ftdi_eeprom_build(struct ftdi_context *ftdi) // Dynamic content // Strings start at 0x94 (TYPE_AM, TYPE_BM) // 0x96 (TYPE_2232C), 0x98 (TYPE_R) and 0x9a (TYPE_x232H) + // 0xa0 (TYPE_232H) i = 0; switch (ftdi->type) { + case TYPE_232H: + i += 2; case TYPE_2232H: case TYPE_4232H: i += 2; @@ -2467,7 +2673,7 @@ int ftdi_eeprom_build(struct ftdi_context *ftdi) if (ftdi->type > TYPE_AM) /* use_serial not used in AM devices */ { - if (eeprom->use_serial == USE_SERIAL_NUM ) + if (eeprom->use_serial) output[0x0A] |= USE_SERIAL_NUM; else output[0x0A] &= ~USE_SERIAL_NUM; @@ -2490,7 +2696,7 @@ int ftdi_eeprom_build(struct ftdi_context *ftdi) break; case TYPE_2232C: - output[0x00] = (eeprom->channel_a_type); + output[0x00] = type2bit(eeprom->channel_a_type, TYPE_2232C); if ( eeprom->channel_a_driver == DRIVER_VCP) output[0x00] |= DRIVER_VCP; else @@ -2501,7 +2707,7 @@ int ftdi_eeprom_build(struct ftdi_context *ftdi) else output[0x00] &= ~HIGH_CURRENT_DRIVE; - output[0x01] = (eeprom->channel_b_type); + output[0x01] = type2bit(eeprom->channel_b_type, TYPE_2232C); if ( eeprom->channel_b_driver == DRIVER_VCP) output[0x01] |= DRIVER_VCP; else @@ -2572,13 +2778,13 @@ int ftdi_eeprom_build(struct ftdi_context *ftdi) output[0x16] = eeprom->cbus_function[4]; break; case TYPE_2232H: - output[0x00] = (eeprom->channel_a_type); + output[0x00] = type2bit(eeprom->channel_a_type, TYPE_2232H); if ( eeprom->channel_a_driver == DRIVER_VCP) output[0x00] |= DRIVER_VCP; else output[0x00] &= ~DRIVER_VCP; - output[0x01] = (eeprom->channel_b_type); + output[0x01] = type2bit(eeprom->channel_b_type, TYPE_2232H); if ( eeprom->channel_b_driver == DRIVER_VCP) output[0x01] |= DRIVER_VCP; else @@ -2633,7 +2839,55 @@ int ftdi_eeprom_build(struct ftdi_context *ftdi) break; case TYPE_4232H: + 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); + if ( eeprom->channel_a_driver == DRIVER_VCP) + output[0x00] |= DRIVER_VCPH; + else + output[0x00] &= ~DRIVER_VCPH; + if (eeprom->powersave) + output[0x01] |= POWER_SAVE_DISABLE_H; + else + output[0x01] &= ~POWER_SAVE_DISABLE_H; + if (eeprom->clock_polarity) + output[0x01] |= FT1284_CLK_IDLE_STATE; + else + output[0x01] &= ~FT1284_CLK_IDLE_STATE; + if (eeprom->data_order) + output[0x01] |= FT1284_DATA_LSB; + else + output[0x01] &= ~FT1284_DATA_LSB; + if (eeprom->flow_control) + output[0x01] |= FT1284_FLOW_CONTROL; + else + output[0x01] &= ~FT1284_FLOW_CONTROL; + 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[0x0d] |= DRIVE_16MA; + else + output[0x0d] |= eeprom->group1_drive; + if (eeprom->group1_schmitt == IS_SCHMITT) + output[0x0d] |= IS_SCHMITT; + if (eeprom->group1_slew == SLOW_SLEW) + output[0x0d] |= SLOW_SLEW; + + set_ft232h_cbus(eeprom, output); + + output[0x1e] = eeprom->chip; + fprintf(stderr,"FIXME: Build FT232H specific EEPROM settings\n"); + break; + } // calculate checksum @@ -2653,7 +2907,26 @@ int ftdi_eeprom_build(struct ftdi_context *ftdi) return user_area_size; } - +/* Decode the encoded EEPROM field for the FTDI Mode into a value for the abstracted + * EEPROM structure + * + * FTD2XX doesn't allow to set multiple bits in the interface mode bitfield, and so do we + */ +static unsigned char bit2type(unsigned char bits) +{ + switch (bits) + { + case 0: return CHANNEL_IS_UART; + case 1: return CHANNEL_IS_FIFO; + case 2: return CHANNEL_IS_OPTO; + case 4: return CHANNEL_IS_CPU; + case 8: return CHANNEL_IS_FT1284; + default: + fprintf(stderr," Unexpected value %d for Hardware Interface type\n", + bits); + } + return 0; +} /** Decode binary EEPROM image into an ftdi_eeprom structure. @@ -2715,7 +2988,7 @@ int ftdi_eeprom_decode(struct ftdi_context *ftdi, int verbose) eeprom->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; + eeprom->use_serial = (buf[0x0A] & USE_SERIAL_NUM)?1:0; eeprom->use_usb_version = buf[0x0A] & USE_USB_VERSION_BIT; // Addr 0C: USB version low byte when 0x0A @@ -2812,7 +3085,7 @@ int ftdi_eeprom_decode(struct ftdi_context *ftdi, int verbose) } else if (ftdi->type == TYPE_2232C) { - eeprom->channel_a_type = buf[0x00] & 0x7; + eeprom->channel_a_type = bit2type(buf[0x00] & 0x7); eeprom->channel_a_driver = buf[0x00] & DRIVER_VCP; eeprom->high_current_a = buf[0x00] & HIGH_CURRENT_DRIVE; eeprom->channel_b_type = buf[0x01] & 0x7; @@ -2847,9 +3120,9 @@ int ftdi_eeprom_decode(struct ftdi_context *ftdi, int verbose) } else if ((ftdi->type == TYPE_2232H) ||(ftdi->type == TYPE_4232H)) { - eeprom->channel_a_type = buf[0x00] & 0x7; + eeprom->channel_a_type = bit2type(buf[0x00] & 0x7); eeprom->channel_a_driver = buf[0x00] & DRIVER_VCP; - eeprom->channel_b_type = buf[0x01] & 0x7; + eeprom->channel_b_type = bit2type(buf[0x01] & 0x7); eeprom->channel_b_driver = buf[0x01] & DRIVER_VCP; if (ftdi->type == TYPE_2232H) @@ -2869,10 +3142,35 @@ int ftdi_eeprom_decode(struct ftdi_context *ftdi, int verbose) eeprom->group3_schmitt = (buf[0x0d] >> 4) & IS_SCHMITT; eeprom->group3_slew = (buf[0x0d] >> 4) & SLOW_SLEW; } + 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; + eeprom->data_order = buf[0x01] & FT1284_DATA_LSB; + eeprom->flow_control = buf[0x01] & FT1284_FLOW_CONTROL; + eeprom->powersave = buf[0x01] & POWER_SAVE_DISABLE_H; + eeprom->group0_drive = buf[0x0c] & DRIVE_16MA; + eeprom->group0_schmitt = buf[0x0c] & IS_SCHMITT; + eeprom->group0_slew = buf[0x0c] & SLOW_SLEW; + eeprom->group1_drive = buf[0x0d] & DRIVE_16MA; + eeprom->group1_schmitt = buf[0x0d] & IS_SCHMITT; + eeprom->group1_slew = buf[0x0d] & SLOW_SLEW; + + for(i=0; i<5; i++) + { + eeprom->cbus_function[2*i ] = buf[0x18+i] & 0x0f; + eeprom->cbus_function[2*i+1] = (buf[0x18+i] >> 4) & 0x0f; + } + eeprom->chip = buf[0x1e]; + /*FIXME: Decipher more values*/ + } if (verbose) { - char *channel_mode[] = {"UART","245","CPU", "unknown", "OPTO"}; + 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",release); @@ -2897,6 +3195,11 @@ int ftdi_eeprom_decode(struct ftdi_context *ftdi, int verbose) fprintf(stdout, "Suspend on DBUS7\n"); if (eeprom->suspend_pull_downs) fprintf(stdout, "Pull IO pins low during suspend\n"); + if(eeprom->powersave) + { + if(ftdi->type >= TYPE_232H) + fprintf(stdout,"Enter low power state on ACBUS7\n"); + } if (eeprom->remote_wakeup) fprintf(stdout, "Enable Remote Wake Up\n"); fprintf(stdout, "PNP: %d\n",(eeprom->is_not_pnp)?0:1); @@ -2905,7 +3208,14 @@ int ftdi_eeprom_decode(struct ftdi_context *ftdi, int verbose) channel_mode[eeprom->channel_a_type], (eeprom->channel_a_driver)?" VCP":"", (eeprom->high_current_a)?" High Current IO":""); - if ((ftdi->type >= TYPE_2232C) && (ftdi->type != TYPE_R)) + if (ftdi->type >= TYPE_232H) + { + fprintf(stdout,"FT1284 Mode Clock is idle %s, %s first, %sFlow Control\n", + (eeprom->clock_polarity)?"HIGH":"LOW", + (eeprom->data_order)?"LSB":"MSB", + (eeprom->flow_control)?"":"No "); + } + if ((ftdi->type >= TYPE_2232C) && (ftdi->type != TYPE_R) && (ftdi->type != TYPE_232H)) fprintf(stdout,"Channel B has Mode %s%s%s\n", channel_mode[eeprom->channel_b_type], (eeprom->channel_b_driver)?" VCP":"", @@ -2937,6 +3247,30 @@ int ftdi_eeprom_decode(struct ftdi_context *ftdi, int verbose) (eeprom->group3_schmitt)?" Schmitt Input":"", (eeprom->group3_slew)?" Slow Slew":""); } + else if (ftdi->type == TYPE_232H) + { + int i; + char *cbush_mux[] = {"TRISTATE","RXLED","TXLED", "TXRXLED","PWREN", + "SLEEP","DRIVE_0","DRIVE_1","IOMODE","TXDEN", + "CLK30","CLK15","CLK7_5" + }; + fprintf(stdout,"ACBUS has %d mA drive%s%s\n", + (eeprom->group0_drive+1) *4, + (eeprom->group0_schmitt)?" Schmitt Input":"", + (eeprom->group0_slew)?" Slow Slew":""); + fprintf(stdout,"ADBUS has %d mA drive%s%s\n", + (eeprom->group1_drive+1) *4, + (eeprom->group1_schmitt)?" Schmitt Input":"", + (eeprom->group1_slew)?" Slow Slew":""); + for (i=0; i<10; i++) + { + if (eeprom->cbus_function[i]<= CBUSH_CLK7_5 ) + fprintf(stdout,"C%d Function: %s\n", i, + cbush_mux[eeprom->cbus_function[i]]); + } + + } + if (ftdi->type == TYPE_R) { char *cbus_mux[] = {"TXDEN","PWREN","RXLED", "TXLED","TX+RXLED", @@ -2961,13 +3295,13 @@ int ftdi_eeprom_decode(struct ftdi_context *ftdi, int verbose) cbus_mux[eeprom->cbus_function[i]]); else { - /* FIXME for Uwe: This results in an access above array bounds. - Also I couldn't find documentation about this mode. - fprintf(stdout,"C%d BB Function: %s\n", i, - cbus_BB[i]); - */ - fprintf(stdout, "Unknown CBUS mode. Might be special mode?\n"); - (void)cbus_BB; + if (i < 4) + /* Running MPROG show that C0..3 have fixed function Synchronous + Bit Bang mode */ + fprintf(stdout,"C%d BB Function: %s\n", i, + cbus_BB[i]); + else + fprintf(stdout, "Unknown CBUS mode. Might be special mode?\n"); } } } @@ -3010,6 +3344,9 @@ int ftdi_get_eeprom_value(struct ftdi_context *ftdi, enum ftdi_eeprom_value valu case IN_IS_ISOCHRONOUS: *value = ftdi->eeprom->in_is_isochronous; break; + case OUT_IS_ISOCHRONOUS: + *value = ftdi->eeprom->out_is_isochronous; + break; case SUSPEND_PULL_DOWNS: *value = ftdi->eeprom->suspend_pull_downs; break; @@ -3019,6 +3356,9 @@ int ftdi_get_eeprom_value(struct ftdi_context *ftdi, enum ftdi_eeprom_value valu case USB_VERSION: *value = ftdi->eeprom->usb_version; break; + case USE_USB_VERSION: + *value = ftdi->eeprom->use_usb_version; + break; case MAX_POWER: *value = ftdi->eeprom->max_power; break; @@ -3049,6 +3389,21 @@ int ftdi_get_eeprom_value(struct ftdi_context *ftdi, enum ftdi_eeprom_value valu case CBUS_FUNCTION_4: *value = ftdi->eeprom->cbus_function[4]; break; + case CBUS_FUNCTION_5: + *value = ftdi->eeprom->cbus_function[5]; + break; + case CBUS_FUNCTION_6: + *value = ftdi->eeprom->cbus_function[6]; + break; + case CBUS_FUNCTION_7: + *value = ftdi->eeprom->cbus_function[7]; + break; + case CBUS_FUNCTION_8: + *value = ftdi->eeprom->cbus_function[8]; + break; + case CBUS_FUNCTION_9: + *value = ftdi->eeprom->cbus_function[8]; + break; case HIGH_CURRENT: *value = ftdi->eeprom->high_current; break; @@ -3097,7 +3452,19 @@ int ftdi_get_eeprom_value(struct ftdi_context *ftdi, enum ftdi_eeprom_value valu case GROUP3_SLEW: *value = ftdi->eeprom->group3_slew; break; - case CHIP_TYPE: + case POWER_SAVE: + *value = ftdi->eeprom->powersave; + break; + case CLOCK_POLARITY: + *value = ftdi->eeprom->clock_polarity; + break; + case DATA_ORDER: + *value = ftdi->eeprom->data_order; + break; + case FLOW_CONTROL: + *value = ftdi->eeprom->flow_control; + break; + case CHIP_TYPE: *value = ftdi->eeprom->chip; break; case CHIP_SIZE: @@ -3114,7 +3481,7 @@ int ftdi_get_eeprom_value(struct ftdi_context *ftdi, enum ftdi_eeprom_value valu No parameter checking is performed \param ftdi pointer to ftdi_context - \param value_name Enum of the value to query + \param value_name Enum of the value to set \param value to set \retval 0: all fine @@ -3146,6 +3513,9 @@ int ftdi_set_eeprom_value(struct ftdi_context *ftdi, enum ftdi_eeprom_value valu case IN_IS_ISOCHRONOUS: ftdi->eeprom->in_is_isochronous = value; break; + case OUT_IS_ISOCHRONOUS: + ftdi->eeprom->out_is_isochronous = value; + break; case SUSPEND_PULL_DOWNS: ftdi->eeprom->suspend_pull_downs = value; break; @@ -3155,6 +3525,9 @@ int ftdi_set_eeprom_value(struct ftdi_context *ftdi, enum ftdi_eeprom_value valu case USB_VERSION: ftdi->eeprom->usb_version = value; break; + case USE_USB_VERSION: + ftdi->eeprom->use_usb_version = value; + break; case MAX_POWER: ftdi->eeprom->max_power = value; break; @@ -3185,6 +3558,21 @@ int ftdi_set_eeprom_value(struct ftdi_context *ftdi, enum ftdi_eeprom_value valu case CBUS_FUNCTION_4: ftdi->eeprom->cbus_function[4] = value; break; + case CBUS_FUNCTION_5: + ftdi->eeprom->cbus_function[5] = value; + break; + case CBUS_FUNCTION_6: + ftdi->eeprom->cbus_function[6] = value; + break; + case CBUS_FUNCTION_7: + ftdi->eeprom->cbus_function[7] = value; + break; + case CBUS_FUNCTION_8: + ftdi->eeprom->cbus_function[8] = value; + break; + case CBUS_FUNCTION_9: + ftdi->eeprom->cbus_function[9] = value; + break; case HIGH_CURRENT: ftdi->eeprom->high_current = value; break; @@ -3236,6 +3624,18 @@ int ftdi_set_eeprom_value(struct ftdi_context *ftdi, enum ftdi_eeprom_value valu case CHIP_TYPE: ftdi->eeprom->chip = value; break; + case POWER_SAVE: + ftdi->eeprom->powersave = value; + break; + case CLOCK_POLARITY: + ftdi->eeprom->clock_polarity = value; + break; + case DATA_ORDER: + ftdi->eeprom->data_order = value; + break; + case FLOW_CONTROL: + ftdi->eeprom->flow_control = value; + break; case CHIP_SIZE: ftdi_error_return(-2, "EEPROM Value can't be changed"); default : @@ -3252,12 +3652,45 @@ int ftdi_set_eeprom_value(struct ftdi_context *ftdi, enum ftdi_eeprom_value valu \retval 0: All fine \retval -1: struct ftdi_contxt or ftdi_eeprom missing + \retval -2: Not enough room to store eeprom */ int ftdi_get_eeprom_buf(struct ftdi_context *ftdi, unsigned char * buf, int size) { if (!ftdi || !(ftdi->eeprom)) ftdi_error_return(-1, "No appropriate structure"); + + if (!buf || size < ftdi->eeprom->size) + ftdi_error_return(-1, "Not enough room to store eeprom"); + + // Only copy up to FTDI_MAX_EEPROM_SIZE bytes + if (size > FTDI_MAX_EEPROM_SIZE) + size = FTDI_MAX_EEPROM_SIZE; + memcpy(buf, ftdi->eeprom->buf, size); + + return 0; +} + +/** Set the EEPROM content from the user-supplied prefilled buffer + + \param ftdi pointer to ftdi_context + \param buf buffer to read EEPROM content + \param size Size of buffer + + \retval 0: All fine + \retval -1: struct ftdi_contxt or ftdi_eeprom of buf missing +*/ +int ftdi_set_eeprom_buf(struct ftdi_context *ftdi, const unsigned char * buf, int size) +{ + if (!ftdi || !(ftdi->eeprom) || !buf) + ftdi_error_return(-1, "No appropriate structure"); + + // Only copy up to FTDI_MAX_EEPROM_SIZE bytes + if (size > FTDI_MAX_EEPROM_SIZE) + size = FTDI_MAX_EEPROM_SIZE; + + memcpy(ftdi->eeprom->buf, buf, size); + return 0; } @@ -3412,6 +3845,9 @@ int ftdi_write_eeprom_location(struct ftdi_context *ftdi, int eeprom_addr, case TYPE_4232H: chip_type_location = 0x18; break; + case TYPE_232H: + chip_type_location = 0x1e; + break; default: ftdi_error_return(-4, "Device can't access unprotected area"); } @@ -3440,6 +3876,7 @@ int ftdi_write_eeprom_location(struct ftdi_context *ftdi, int eeprom_addr, \retval 0: all fine \retval -1: read failed \retval -2: USB device unavailable + \retval -3: EEPROM not initialized for the connected device; */ int ftdi_write_eeprom(struct ftdi_context *ftdi) { @@ -3449,6 +3886,10 @@ int ftdi_write_eeprom(struct ftdi_context *ftdi) if (ftdi == NULL || ftdi->usb_dev == NULL) ftdi_error_return(-2, "USB device unavailable"); + + if(ftdi->eeprom->initialized_for_connected_device == 0) + ftdi_error_return(-3, "EEPROM not initialized for the connected device"); + eeprom = ftdi->eeprom->buf; /* These commands were traced while running MProg */