X-Git-Url: http://developer.intra2net.com/git/?p=libftdi;a=blobdiff_plain;f=src%2Fftdi.c;h=c19810b417f4fa214f8cb8b242468d069954470c;hp=db66b8718fc0283a1b1aedbe76121040333277d9;hb=HEAD;hpb=cb9b8a53f1536640fe4d8dfccf79268fbbd49180 diff --git a/src/ftdi.c b/src/ftdi.c index db66b87..534e3dd 100644 --- a/src/ftdi.c +++ b/src/ftdi.c @@ -83,7 +83,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 -2: couldn't allocate struct buffer \retval -3: libusb_init() failed \remark This should be called before all functions @@ -112,7 +112,7 @@ int ftdi_init(struct ftdi_context *ftdi) 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->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) @@ -298,7 +298,7 @@ struct ftdi_version_info ftdi_get_library_version(void) /** 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 + use. With VID:PID 0:0, search for the default devices (0x403:0x6001, 0x403:0x6010, 0x403:0x6011, 0x403:0x6014, 0x403:0x6015) \param ftdi pointer to ftdi_context @@ -485,27 +485,39 @@ int ftdi_usb_get_strings2(struct ftdi_context *ftdi, struct libusb_device *dev, if (libusb_get_device_descriptor(dev, &desc) < 0) ftdi_error_return(-11, "libusb_get_device_descriptor() failed"); - if (manufacturer != NULL) + if (manufacturer != NULL && mnf_len > 0) { - if (libusb_get_string_descriptor_ascii(ftdi->usb_dev, desc.iManufacturer, (unsigned char *)manufacturer, mnf_len) < 0) + if (desc.iManufacturer == 0) + { + manufacturer[0] = '\0'; + } + else if (libusb_get_string_descriptor_ascii(ftdi->usb_dev, desc.iManufacturer, (unsigned char *)manufacturer, mnf_len) < 0) { ftdi_usb_close_internal (ftdi); ftdi_error_return(-7, "libusb_get_string_descriptor_ascii() failed"); } } - if (description != NULL) + if (description != NULL && desc_len > 0) { - if (libusb_get_string_descriptor_ascii(ftdi->usb_dev, desc.iProduct, (unsigned char *)description, desc_len) < 0) + if (desc.iProduct == 0) + { + description[0] = '\0'; + } + else if (libusb_get_string_descriptor_ascii(ftdi->usb_dev, desc.iProduct, (unsigned char *)description, desc_len) < 0) { ftdi_usb_close_internal (ftdi); ftdi_error_return(-8, "libusb_get_string_descriptor_ascii() failed"); } } - if (serial != NULL) + if (serial != NULL && serial_len > 0) { - if (libusb_get_string_descriptor_ascii(ftdi->usb_dev, desc.iSerialNumber, (unsigned char *)serial, serial_len) < 0) + if (desc.iSerialNumber == 0) + { + serial[0] = '\0'; + } + else if (libusb_get_string_descriptor_ascii(ftdi->usb_dev, desc.iSerialNumber, (unsigned char *)serial, serial_len) < 0) { ftdi_usb_close_internal (ftdi); ftdi_error_return(-9, "libusb_get_string_descriptor_ascii() failed"); @@ -627,7 +639,7 @@ int ftdi_usb_open_dev(struct ftdi_context *ftdi, libusb_device *dev) ftdi_error_return(-12, "libusb_get_configuration () failed"); // set configuration (needed especially for windows) // tolerate EBUSY: one device with one configuration, but two interfaces - // and libftdi sessions to both interfaces (e.g. FT2232) + // and libftdi sessions to both interfaces (e.g. FT2232) if (desc.bNumConfigurations > 0 && cfg != cfg0) { if (libusb_set_configuration(ftdi->usb_dev, cfg0) < 0) @@ -1304,7 +1316,7 @@ static int ftdi_to_clkbits_AM(int baudrate, unsigned long *encoded_divisor) return best_baud; } -/* ftdi_to_clkbits Convert a requested baudrate for a given system clock and predivisor +/* 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 @@ -2206,6 +2218,24 @@ int ftdi_set_bitmode(struct ftdi_context *ftdi, unsigned char bitmask, unsigned } /** + Set module detach mode. + + \param ftdi pointer to ftdi_context + \param mode detach mode to use. + + \retval 0: all fine + \retval -1: can't enable bitbang mode +*/ +int ftdi_set_module_detach_mode(struct ftdi_context *ftdi, enum ftdi_module_detach_mode mode) +{ + if (ftdi == NULL) + ftdi_error_return(-1, "FTDI context invalid"); + + ftdi->module_detach_mode = mode; + return 0; +} + +/** Disable bitbang mode. \param ftdi pointer to ftdi_context @@ -2576,8 +2606,8 @@ int ftdi_set_error_char(struct ftdi_context *ftdi, \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) +int ftdi_eeprom_initdefaults(struct ftdi_context *ftdi, const char * manufacturer, + const char * product, const char * serial) { struct ftdi_eeprom *eeprom; @@ -2594,7 +2624,7 @@ int ftdi_eeprom_initdefaults(struct ftdi_context *ftdi, char * manufacturer, ftdi_error_return(-3, "No connected device or device not yet opened"); eeprom->vendor_id = 0x0403; - eeprom->use_serial = 1; + eeprom->use_serial = (serial != NULL); if ((ftdi->type == TYPE_AM) || (ftdi->type == TYPE_BM) || (ftdi->type == TYPE_R)) eeprom->product_id = 0x6001; @@ -3037,7 +3067,7 @@ 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) + // 0xa0 (TYPE_232H, TYPE_230X) i = 0; switch (ftdi->type) { @@ -3060,7 +3090,7 @@ int ftdi_eeprom_build(struct ftdi_context *ftdi) i = 0xa0; break; } - /* Wrap around 0x80 for 128 byte EEPROMS (Internale and 93x46) */ + /* Wrap around 0x80 for 128 byte EEPROMS (Internal and 93x46) */ eeprom_size_mask = eeprom->size -1; free_end = i & eeprom_size_mask; @@ -3089,19 +3119,23 @@ int ftdi_eeprom_build(struct ftdi_context *ftdi) } output[0x11] = product_size*2 + 2; - // Addr 12: Offset of the serial string + 0x80, calculated later - // Addr 13: Length of serial string - output[0x12] = i | 0x80; // calculate offset - output[i & eeprom_size_mask] = serial_size*2 + 2, i++; - output[i & eeprom_size_mask] = 0x03, i++; - for (j = 0; j < serial_size; j++) - { - output[i & eeprom_size_mask] = eeprom->serial[j], i++; - output[i & eeprom_size_mask] = 0x00, i++; + if (eeprom->use_serial) { + // Addr 12: Offset of the serial string + 0x80, calculated later + // Addr 13: Length of serial string + output[0x12] = i | 0x80; // calculate offset + output[i & eeprom_size_mask] = serial_size*2 + 2, i++; + output[i & eeprom_size_mask] = 0x03, i++; + for (j = 0; j < serial_size; j++) + { + output[i & eeprom_size_mask] = eeprom->serial[j], i++; + output[i & eeprom_size_mask] = 0x00, i++; + } + output[0x13] = serial_size*2 + 2; } // Legacy port name and PnP fields for FT2232 and newer chips - if (ftdi->type > TYPE_BM) + // It doesn't appear when written with FT_Prog for FT4232H chip. + if (ftdi->type > TYPE_BM && ftdi->type != TYPE_4232H) { output[i & eeprom_size_mask] = 0x02; /* as seen when written with FTD2XX */ i++; @@ -3109,10 +3143,10 @@ int ftdi_eeprom_build(struct ftdi_context *ftdi) i++; output[i & eeprom_size_mask] = eeprom->is_not_pnp; /* as seen when written with FTD2XX */ i++; + output[i & eeprom_size_mask] = 0x00; + i++; } - output[0x13] = serial_size*2 + 2; - if (ftdi->type > TYPE_AM) /* use_serial not used in AM devices */ { if (eeprom->use_serial) @@ -3122,7 +3156,7 @@ int ftdi_eeprom_build(struct ftdi_context *ftdi) } /* Bytes and Bits specific to (some) types - Write linear, as this allows easier fixing*/ + Write linear, as this allows easier fixing */ switch (ftdi->type) { case TYPE_AM: @@ -3194,7 +3228,7 @@ int ftdi_eeprom_build(struct ftdi_context *ftdi) if (eeprom->external_oscillator) output[0x00] |= 0x02; - output[0x01] = 0x40; /* Hard coded Endpoint Size*/ + output[0x01] = 0x40; /* Hard coded Endpoint Size */ if (eeprom->suspend_pull_downs) output[0x0A] |= 0x4; @@ -3426,7 +3460,7 @@ int ftdi_eeprom_build(struct ftdi_context *ftdi) case TYPE_230X: output[0x00] = 0x80; /* Actually, leave the default value */ /*FIXME: Make DBUS & CBUS Control configurable*/ - output[0x0c] = 0; /* DBUS drive 4mA, CBUS drive 4 mA like factory default */ + output[0x0c] = 0; /* DBUS drive 4mA, CBUS drive 4mA like factory default */ for (j = 0; j <= 6; j++) { output[0x1a + j] = eeprom->cbus_function[j]; @@ -3489,6 +3523,8 @@ int ftdi_eeprom_build(struct ftdi_context *ftdi) i = 0x50; } value = data; + output[i * 2] = data; + output[(i * 2) + 1] = data >> 8; } else { value = output[i*2]; @@ -3862,11 +3898,18 @@ int ftdi_eeprom_decode(struct ftdi_context *ftdi, int verbose) (eeprom->data_order)?"LSB":"MSB", (eeprom->flow_control)?"":"No "); } - if ((ftdi->type == TYPE_2232H) || (ftdi->type == TYPE_4232H)) + if ((ftdi->type == TYPE_2232H) || (ftdi->type == TYPE_4232H) || (ftdi->type == TYPE_2232C)) fprintf(stdout,"Channel B has Mode %s%s%s\n", channel_mode[eeprom->channel_b_type], (eeprom->channel_b_driver)?" VCP":"", (eeprom->high_current_b)?" High Current IO":""); + if (ftdi->type == TYPE_4232H) + { + fprintf(stdout,"Channel C has Mode UART%s\n", + (eeprom->channel_c_driver)?" VCP":""); + fprintf(stdout,"Channel D has Mode UART%s\n", + (eeprom->channel_d_driver)?" VCP":""); + } if (((ftdi->type == TYPE_BM) || (ftdi->type == TYPE_2232C)) && eeprom->use_usb_version) fprintf(stdout,"Use explicit USB Version %04x\n",eeprom->usb_version); @@ -4158,6 +4201,9 @@ int ftdi_get_eeprom_value(struct ftdi_context *ftdi, enum ftdi_eeprom_value valu case EXTERNAL_OSCILLATOR: *value = ftdi->eeprom->external_oscillator; break; + case USER_DATA_ADDR: + *value = ftdi->eeprom->user_data_addr; + break; default: ftdi_error_return(-1, "Request for unknown EEPROM value"); }