X-Git-Url: http://developer.intra2net.com/git/?p=libftdi;a=blobdiff_plain;f=src%2Fftdi.c;h=0c8d54000a66cd19e8588f2916a341daebdf52f1;hp=17790465323447721a12e00e2da3ff9a0ac57b87;hb=9956d4289d04f1c67a8738a7b8b32e1345ab0968;hpb=c8f69686112ba325b7e8c14e73e6afeff74c593f diff --git a/src/ftdi.c b/src/ftdi.c index 1779046..0c8d540 100644 --- a/src/ftdi.c +++ b/src/ftdi.c @@ -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; } } @@ -962,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; @@ -1007,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 @@ -1019,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 down to maximum supported divisor value (for AM) - try_divisor = 0x1FFF8; - } - } - else + // Round up to supported fraction (AM only) + try_divisor += am_adjust_up[try_divisor & 7]; + if (try_divisor > 0x1FFF8) { - 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) @@ -1063,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 + } + else if (*encoded_divisor == 0x4001) + { + *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; // 3000000 baud + *encoded_divisor = 0; + best_baud = clk/clk_div; } - else if (encoded_divisor == 0x4001) + else if (baudrate >= clk/(clk_div + clk_div/2)) { - encoded_divisor = 1; // 2000000 baud (BM only) + *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 || ftdi->type == TYPE_232H ) + 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; @@ -1089,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 @@ -2177,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 @@ -2186,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) @@ -2201,8 +2299,11 @@ 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; @@ -2237,6 +2338,25 @@ int ftdi_eeprom_initdefaults(struct ftdi_context *ftdi, char * manufacturer, 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); @@ -2269,6 +2389,7 @@ int ftdi_eeprom_initdefaults(struct ftdi_context *ftdi, char * manufacturer, } eeprom->size = -1; } + eeprom->initialized_for_connected_device = 1; return 0; } /*FTD2XX doesn't check for values not fitting in the ACBUS Signal oprtions*/ @@ -2552,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; @@ -2867,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 @@ -3755,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) { @@ -3764,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 */