X-Git-Url: http://developer.intra2net.com/git/?p=libftdi;a=blobdiff_plain;f=src%2Fftdi.c;h=ed2bbe05d9667a9d597b677e695d41bc5bb57b62;hp=4cc55e4d9857b35ed0a9b6d868299dbf03eaed9c;hb=837a71d6c580972b9638588a50cec5fbb035add6;hpb=b95e46548cdf96ef21b3de2a1b3d55ceeca12075 diff --git a/src/ftdi.c b/src/ftdi.c index 4cc55e4..ed2bbe0 100644 --- a/src/ftdi.c +++ b/src/ftdi.c @@ -74,6 +74,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 +95,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 +222,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; + } } /** @@ -258,7 +267,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 +278,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,13 +289,13 @@ 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) { *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; @@ -299,7 +304,7 @@ int ftdi_usb_find_all(struct ftdi_context *ftdi, struct ftdi_device_list **devli count++; } } - + libusb_free_device_list(devs,1); return count; } @@ -423,7 +428,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 +474,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 +503,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 +564,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); @@ -643,12 +653,12 @@ 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"); + if (libusb_init(&ftdi->usb_ctx) < 0) + ftdi_error_return(-11, "libusb_init() failed"); + if (libusb_get_device_list(ftdi->usb_ctx, &devs) < 0) ftdi_error_return(-12, "libusb_get_device_list() failed"); @@ -669,12 +679,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; } } @@ -1984,7 +1994,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; } @@ -2197,6 +2207,10 @@ int ftdi_eeprom_initdefaults(struct ftdi_context *ftdi, char * manufacturer, 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,6 +2232,7 @@ 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) @@ -2357,6 +2372,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 +2417,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; @@ -2633,7 +2654,42 @@ 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] = (eeprom->channel_a_type); + 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->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; + + output[0x1e] = eeprom->chip; + fprintf(stderr,"FIXME: Build FT232H specific EEPROM settings\n"); + break; + } // calculate checksum @@ -2869,10 +2925,25 @@ 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) + { + eeprom->channel_a_type = buf[0x00] & 0xf; + eeprom->channel_a_driver = (buf[0x00] & DRIVER_VCPH)?DRIVER_VCP:0; + 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; + + eeprom->chip = buf[0x1e]; + /*FIXME: Decipher more values*/ + } if (verbose) { - char *channel_mode[] = {"UART","245","CPU", "unknown", "OPTO"}; + char *channel_mode[] = {"UART","245","CPU", "unknown", "OPTO", "unknown1","unknown2","unknown3","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 +2968,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 +2981,7 @@ 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_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 +3013,18 @@ 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) + { + 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":""); + } + if (ftdi->type == TYPE_R) { char *cbus_mux[] = {"TXDEN","PWREN","RXLED", "TXLED","TX+RXLED", @@ -2961,13 +3049,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"); } } } @@ -3097,6 +3185,9 @@ int ftdi_get_eeprom_value(struct ftdi_context *ftdi, enum ftdi_eeprom_value valu case GROUP3_SLEW: *value = ftdi->eeprom->group3_slew; break; + case POWER_SAVE: + *value = ftdi->eeprom->powersave; + break; case CHIP_TYPE: *value = ftdi->eeprom->chip; break; @@ -3236,6 +3327,9 @@ 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 CHIP_SIZE: ftdi_error_return(-2, "EEPROM Value can't be changed"); default : @@ -3252,12 +3346,16 @@ 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; @@ -3418,6 +3516,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"); }