X-Git-Url: http://developer.intra2net.com/git/?p=libftdi;a=blobdiff_plain;f=src%2Fftdi.c;h=c9492f56124a78ad0a7bdb24df9269bfbdb959e5;hp=67fd25940e61d39a3a088a4c66e3349b41d07e9f;hb=d45d6648ad017652e18aefc65c1300c5392b2f8e;hpb=13f00d3cd7a7cef13df7b1ecc0b0f0c678456cca diff --git a/src/ftdi.c b/src/ftdi.c index 67fd259..c9492f5 100644 --- a/src/ftdi.c +++ b/src/ftdi.c @@ -73,11 +73,13 @@ 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 \remark This should be called before all functions */ int ftdi_init(struct ftdi_context *ftdi) { + struct ftdi_eeprom* eeprom = (struct ftdi_eeprom *)malloc(sizeof(struct ftdi_eeprom)); ftdi->usb_ctx = NULL; ftdi->usb_dev = NULL; ftdi->usb_read_timeout = 5000; @@ -101,7 +103,10 @@ int ftdi_init(struct ftdi_context *ftdi) ftdi->error_str = NULL; - ftdi->eeprom = NULL; + if (eeprom == 0) + ftdi_error_return(-2, "Can't malloc struct ftdi_eeprom"); + memset(eeprom, 0, sizeof(struct ftdi_eeprom); + ftdi->eeprom = eeprom; /* All fine. Now allocate the readbuffer */ return ftdi_read_data_set_chunksize(ftdi, 4096); @@ -192,6 +197,27 @@ void ftdi_deinit(struct ftdi_context *ftdi) free(ftdi->readbuffer); ftdi->readbuffer = NULL; } + + if (ftdi->eeprom != NULL) + { + if (ftdi->eeprom->manufacturer != 0) + { + free(ftdi->eeprom->manufacturer); + ftdi->eeprom->manufacturer = 0; + } + if (ftdi->eeprom->product != 0) + { + free(ftdi->eeprom->product); + ftdi->eeprom->product = 0; + } + if (ftdi->eeprom->serial != 0) + { + free(ftdi->eeprom->serial); + ftdi->eeprom->serial = 0; + } + free(ftdi->eeprom); + ftdi->eeprom = NULL; + } libusb_exit(ftdi->usb_ctx); } @@ -2153,37 +2179,27 @@ int ftdi_set_error_char(struct ftdi_context *ftdi, } /** - Set the eeprom size - - \param ftdi pointer to ftdi_context - \param eeprom Pointer to ftdi_eeprom - \param size - -*/ -void ftdi_eeprom_setsize(struct ftdi_context *ftdi, struct ftdi_eeprom *eeprom, int size) -{ - if (ftdi == NULL) - return; - - ftdi->eeprom = eeprom; - ftdi->eeprom->size=size; -} - -/** Init eeprom with default values. - - \param eeprom Pointer to ftdi_eeprom + \param ftdi pointer to ftdi_context + \param manufacturer String to use as Manufacturer + \param product String to use as Product description + \param serial String to use as Serial number description + + \retval 0: all fine + \retval -1: No struct ftdi_context + \retval -2: No struct ftdi_eeprom */ -void ftdi_eeprom_initdefaults(struct ftdi_context *ftdi) +int ftdi_eeprom_initdefaults(struct ftdi_context *ftdi, char * manufacturer, + char * product, char * serial) { - int i; struct ftdi_eeprom *eeprom; if (ftdi == NULL) - return; + ftdi_error_return(-1, "No struct ftdi_context"); + if (ftdi->eeprom == NULL) - return; + ftdi_error_return(-2,"No struct ftdi_eeprom"); eeprom = ftdi->eeprom; memset(eeprom, 0, sizeof(struct ftdi_eeprom)); @@ -2199,15 +2215,41 @@ void ftdi_eeprom_initdefaults(struct ftdi_context *ftdi) eeprom->usb_version = 0x0101; else eeprom->usb_version = 0x0200; - eeprom->max_power = 50; + eeprom->max_power = 100; + if (eeprom->manufacturer) + free (eeprom->manufacturer); eeprom->manufacturer = NULL; + if (manufacturer) + { + eeprom->manufacturer = malloc(strlen(manufacturer)+1); + if (eeprom->manufacturer) + strcpy(eeprom->manufacturer, manufacturer); + } + + if (eeprom->product) + free (eeprom->product); eeprom->product = NULL; + { + eeprom->product = malloc(strlen(product)+1); + if (eeprom->product) + strcpy(eeprom->product, product); + } + + if (eeprom->serial) + free (eeprom->serial); eeprom->serial = NULL; + if (serial) + { + eeprom->serial = malloc(strlen(serial)+1); + if (eeprom->serial) + strcpy(eeprom->serial, serial); + } + if(ftdi->type == TYPE_R) { - eeprom->max_power = 45; + eeprom->max_power = 90; eeprom->size = 0x80; eeprom->cbus_function[0] = CBUS_TXLED; eeprom->cbus_function[1] = CBUS_RXLED; @@ -2217,43 +2259,14 @@ void ftdi_eeprom_initdefaults(struct ftdi_context *ftdi) } else eeprom->size = -1; + return 0; } /** - Frees allocated memory in eeprom. - - \param eeprom Pointer to ftdi_eeprom -*/ -void ftdi_eeprom_free(struct ftdi_context *ftdi) -{ - if (!ftdi) - return; - if (ftdi->eeprom) - { - struct ftdi_eeprom *eeprom = ftdi->eeprom; - - if (eeprom->manufacturer != 0) { - free(eeprom->manufacturer); - eeprom->manufacturer = 0; - } - if (eeprom->product != 0) { - free(eeprom->product); - eeprom->product = 0; - } - if (eeprom->serial != 0) { - free(eeprom->serial); - eeprom->serial = 0; - } - } -} - -/** - Build binary output from ftdi_eeprom structure. + Build binary buffer from ftdi_eeprom structure. Output is suitable for ftdi_write_eeprom(). - \note This function doesn't handle FT2232x devices. Only FT232x. - \param eeprom Pointer to ftdi_eeprom - \param output Buffer of 128 bytes to store eeprom image to + \param ftdi pointer to ftdi_context \retval >0: free eeprom size \retval -1: eeprom size (128 bytes) exceeded by custom strings @@ -2263,13 +2276,14 @@ void ftdi_eeprom_free(struct ftdi_context *ftdi) \retval -5: Chip doesn't support high current drive \retval -6: No connected EEPROM or EEPROM Type unknown */ -int ftdi_eeprom_build(struct ftdi_context *ftdi, unsigned char *output) +int ftdi_eeprom_build(struct ftdi_context *ftdi) { unsigned char i, j, k; unsigned short checksum, value; unsigned char manufacturer_size = 0, product_size = 0, serial_size = 0; int size_check; struct ftdi_eeprom *eeprom; + unsigned char * output; if (ftdi == NULL) ftdi_error_return(-2,"No context"); @@ -2277,6 +2291,7 @@ int ftdi_eeprom_build(struct ftdi_context *ftdi, unsigned char *output) ftdi_error_return(-2,"No eeprom structure"); eeprom= ftdi->eeprom; + output = eeprom->buf; if(eeprom->chip == -1) ftdi_error_return(-5,"No connected EEPROM or EEPROM Type unknown"); @@ -2313,14 +2328,14 @@ int ftdi_eeprom_build(struct ftdi_context *ftdi, unsigned char *output) size_check -= serial_size*2; /* Space for the string type and pointer bytes */ - size_check -= -6; + size_check -= -9; // eeprom size exceeded? if (size_check < 0) return (-1); // empty eeprom - memset (output, 0, eeprom->size); + memset (ftdi->eeprom->buf, 0, FTDI_MAX_EEPROM_SIZE); // Bytes and Bits set for all Types @@ -2370,7 +2385,7 @@ int ftdi_eeprom_build(struct ftdi_context *ftdi, unsigned char *output) output[0x08] = j; // Addr 09: Max power consumption: max power = value * 2 mA - output[0x09] = eeprom->max_power; + output[0x09] = eeprom->max_power>>1; if(ftdi->type != TYPE_AM) { @@ -2447,8 +2462,22 @@ int ftdi_eeprom_build(struct ftdi_context *ftdi, unsigned char *output) output[i & k] = eeprom->serial[j], i++; output[i & k] = 0x00, i++; } + output[i & k] = 0x02; /* as seen when written with FTD2XX */ + i++; + output[i & k] = 0x03; /* as seen when written with FTD2XX */ + i++; + output[i & k] = eeprom->is_not_pnp; /* as seen when written with FTD2XX */ + i++; + output[0x13] = serial_size*2 + 2; + if(ftdi->type > TYPE_AM) /*use_serial not used in AM devices*/ + { + if (eeprom->use_serial == USE_SERIAL_NUM ) + output[0x0A] |= USE_SERIAL_NUM; + else + output[0x0A] &= ~USE_SERIAL_NUM; + } /* Fixme: ftd2xx seems to append 0x02, 0x03 and 0x01 for PnP = 0 or 0x00 else */ // calculate checksum @@ -2461,10 +2490,6 @@ int ftdi_eeprom_build(struct ftdi_context *ftdi, unsigned char *output) case TYPE_BM: output[0x0C] = eeprom->usb_version & 0xff; output[0x0D] = (eeprom->usb_version>>8) & 0xff; - if (eeprom->use_serial == 1) - output[0x0A] |= 0x8; - else - output[0x0A] &= ~0x8; output[0x14] = eeprom->chip; break; case TYPE_2232C: @@ -2503,10 +2528,6 @@ int ftdi_eeprom_build(struct ftdi_context *ftdi, unsigned char *output) output[0x0A] |= 0x4; else output[0x0A] &= ~0x4; - if (eeprom->use_serial == USE_SERIAL_NUM ) - output[0x0A] |= USE_SERIAL_NUM; - else - output[0x0A] &= ~0x8; output[0x0C] = eeprom->usb_version & 0xff; output[0x0D] = (eeprom->usb_version>>8) & 0xff; output[0x14] = eeprom->chip; @@ -2520,10 +2541,6 @@ int ftdi_eeprom_build(struct ftdi_context *ftdi, unsigned char *output) output[0x0A] |= 0x4; else output[0x0A] &= ~0x4; - if (eeprom->use_serial == USE_SERIAL_NUM) - output[0x0A] |= USE_SERIAL_NUM; - else - output[0x0A] &= ~0x8; output[0x0B] = eeprom->invert; output[0x0C] = eeprom->usb_version & 0xff; output[0x0D] = (eeprom->usb_version>>8) & 0xff; @@ -2570,6 +2587,11 @@ int ftdi_eeprom_build(struct ftdi_context *ftdi, unsigned char *output) else output[0x01] &= ~SUSPEND_DBUS7; + if (eeprom->suspend_pull_downs == 1) + output[0x0A] |= 0x4; + else + output[0x0A] &= ~0x4; + if(eeprom->group0_drive > DRIVE_16MA) output[0x0c] |= DRIVE_16MA; else @@ -2632,23 +2654,23 @@ int ftdi_eeprom_build(struct ftdi_context *ftdi, unsigned char *output) /** Decode binary EEPROM image into an ftdi_eeprom structure. - \param eeprom Pointer to ftdi_eeprom which will be filled in. - \param buf Buffer of \a size bytes of raw eeprom data - \param size size size of eeprom data in bytes - + \param ftdi pointer to ftdi_context + \param verbose Decode EEPROM on stdout + \retval 0: all fine \retval -1: something went wrong FIXME: How to pass size? How to handle size field in ftdi_eeprom? FIXME: Strings are malloc'ed here and should be freed somewhere */ -int ftdi_eeprom_decode(struct ftdi_context *ftdi, unsigned char *buf, int size, int verbose) +int ftdi_eeprom_decode(struct ftdi_context *ftdi, int verbose) { unsigned char i, j; unsigned short checksum, eeprom_checksum, value; unsigned char manufacturer_size = 0, product_size = 0, serial_size = 0; int eeprom_size; struct ftdi_eeprom *eeprom; + unsigned char *buf = ftdi->eeprom->buf; int release; if (ftdi == NULL) @@ -2656,10 +2678,8 @@ int ftdi_eeprom_decode(struct ftdi_context *ftdi, unsigned char *buf, int size, if (ftdi->eeprom == NULL) ftdi_error_return(-1,"No eeprom structure"); - eeprom_size = ftdi->eeprom->size; - if(ftdi->type == TYPE_R) - eeprom_size = 0x80; eeprom = ftdi->eeprom; + eeprom_size = eeprom->size; // Addr 02: Vendor ID eeprom->vendor_id = buf[0x02] + (buf[0x03] << 8); @@ -2708,6 +2728,8 @@ int ftdi_eeprom_decode(struct ftdi_context *ftdi, unsigned char *buf, int size, // Addr 0E: Offset of the manufacturer string + 0x80, calculated later // Addr 0F: Length of manufacturer string manufacturer_size = buf[0x0F]/2; + if(eeprom->manufacturer) + free(eeprom->manufacturer); if (manufacturer_size > 0) { eeprom->manufacturer = malloc(manufacturer_size); @@ -2726,6 +2748,8 @@ int ftdi_eeprom_decode(struct ftdi_context *ftdi, unsigned char *buf, int size, // Addr 10: Offset of the product string + 0x80, calculated later // Addr 11: Length of product string + if(eeprom->product) + free(eeprom->product); product_size = buf[0x11]/2; if (product_size > 0) { @@ -2745,6 +2769,8 @@ int ftdi_eeprom_decode(struct ftdi_context *ftdi, unsigned char *buf, int size, // Addr 12: Offset of the serial string + 0x80, calculated later // Addr 13: Length of serial string + if(eeprom->serial) + free(eeprom->serial); serial_size = buf[0x13]/2; if (serial_size > 0) { @@ -2824,7 +2850,7 @@ int ftdi_eeprom_decode(struct ftdi_context *ftdi, unsigned char *buf, int size, } else if ((ftdi->type == TYPE_2232H) ||(ftdi->type == TYPE_4232H)) { - eeprom->high_current = buf[0x00] & HIGH_CURRENT_DRIVE_R; + eeprom->channel_a_type = buf[0x00] & 0x7; eeprom->channel_a_driver = buf[0x00] & DRIVER_VCP; eeprom->channel_b_type = buf[0x01] & 0x7; eeprom->channel_b_driver = buf[0x01] & DRIVER_VCP; @@ -2876,6 +2902,7 @@ int ftdi_eeprom_decode(struct ftdi_context *ftdi, unsigned char *buf, int size, fprintf(stdout, "Pull IO pins low during suspend\n"); if(eeprom->remote_wakeup) fprintf(stdout, "Enable Remote Wake Up\n"); + fprintf(stdout, "PNP: %d\n",(eeprom->is_not_pnp)?0:1); if (ftdi->type >= TYPE_2232C) fprintf(stdout,"Channel A has Mode %s%s%s\n", channel_mode[eeprom->channel_a_type], @@ -2966,34 +2993,37 @@ int ftdi_read_eeprom_location (struct ftdi_context *ftdi, int eeprom_addr, unsig Read eeprom \param ftdi pointer to ftdi_context - \param eeprom Pointer to store eeprom into \retval 0: all fine \retval -1: read failed \retval -2: USB device unavailable */ -int ftdi_read_eeprom(struct ftdi_context *ftdi, unsigned char *eeprom) +int ftdi_read_eeprom(struct ftdi_context *ftdi) { int i; + unsigned char *buf; if (ftdi == NULL || ftdi->usb_dev == NULL) ftdi_error_return(-2, "USB device unavailable"); + buf = ftdi->eeprom->buf; for (i = 0; i < FTDI_MAX_EEPROM_SIZE/2; i++) { - if (libusb_control_transfer(ftdi->usb_dev, FTDI_DEVICE_IN_REQTYPE, SIO_READ_EEPROM_REQUEST, 0, i, eeprom+(i*2), 2, ftdi->usb_read_timeout) != 2) + if (libusb_control_transfer( + ftdi->usb_dev, FTDI_DEVICE_IN_REQTYPE,SIO_READ_EEPROM_REQUEST, 0, i, + buf+(i*2), 2, ftdi->usb_read_timeout) != 2) ftdi_error_return(-1, "reading eeprom failed"); } if (ftdi->type == TYPE_R) - ftdi->eeprom->size = 0xa0; + ftdi->eeprom->size = 0x80; /* Guesses size of eeprom by comparing halves - will not work with blank eeprom */ - else if (strrchr((const char *)eeprom, 0xff) == ((const char *)eeprom +FTDI_MAX_EEPROM_SIZE -1)) + else if (strrchr((const char *)buf, 0xff) == ((const char *)buf +FTDI_MAX_EEPROM_SIZE -1)) ftdi->eeprom->size = -1; - else if(memcmp(eeprom,&eeprom[0x80],0x80) == 0) + else if(memcmp(buf,&buf[0x80],0x80) == 0) ftdi->eeprom->size = 0x80; - else if(memcmp(eeprom,&eeprom[0x40],0x40) == 0) + else if(memcmp(buf,&buf[0x40],0x40) == 0) ftdi->eeprom->size = 0x40; else ftdi->eeprom->size = 0x100; @@ -3059,14 +3089,47 @@ int ftdi_read_chipid(struct ftdi_context *ftdi, unsigned int *chipid) \param eeprom_val Value to be written \retval 0: all fine - \retval -1: read failed + \retval -1: write failed \retval -2: USB device unavailable + \retval -3: Invalid access to checksum protected area below 0x80 + \retval -4: Device can't access unprotected area + \retval -5: Reading chip type failed */ -int ftdi_write_eeprom_location(struct ftdi_context *ftdi, int eeprom_addr, unsigned short eeprom_val) +int ftdi_write_eeprom_location(struct ftdi_context *ftdi, int eeprom_addr, + unsigned short eeprom_val) { + int chip_type_location; + unsigned short chip_type; + if (ftdi == NULL || ftdi->usb_dev == NULL) ftdi_error_return(-2, "USB device unavailable"); + if(eeprom_addr <0x80) + ftdi_error_return(-2, "Invalid access to checksum protected area below 0x80"); + + + switch (ftdi->type) + { + case TYPE_BM: + case TYPE_2232C: + chip_type_location = 0x14; + break; + case TYPE_2232H: + case TYPE_4232H: + chip_type_location = 0x18; + break; + default: + ftdi_error_return(-4, "Device can't access unprotected area"); + } + + if (ftdi_read_eeprom_location( ftdi, chip_type_location>>1, &chip_type)) + ftdi_error_return(-5, "Reading failed failed"); + fprintf(stderr," loc 0x%04x val 0x%04x\n", chip_type_location,chip_type); + if((chip_type & 0xff) != 0x66) + { + ftdi_error_return(-6, "EEPROM is not of 93x66"); + } + if (libusb_control_transfer(ftdi->usb_dev, FTDI_DEVICE_OUT_REQTYPE, SIO_WRITE_EEPROM_REQUEST, eeprom_val, eeprom_addr, NULL, 0, ftdi->usb_write_timeout) != 0) @@ -3079,19 +3142,20 @@ int ftdi_write_eeprom_location(struct ftdi_context *ftdi, int eeprom_addr, unsig Write eeprom \param ftdi pointer to ftdi_context - \param eeprom Pointer to read eeprom from - + \retval 0: all fine \retval -1: read failed \retval -2: USB device unavailable */ -int ftdi_write_eeprom(struct ftdi_context *ftdi, unsigned char *eeprom) +int ftdi_write_eeprom(struct ftdi_context *ftdi) { unsigned short usb_val, status; int i, ret; + unsigned char *eeprom; if (ftdi == NULL || ftdi->usb_dev == NULL) ftdi_error_return(-2, "USB device unavailable"); + eeprom = ftdi->eeprom->buf; /* These commands were traced while running MProg */ if ((ret = ftdi_usb_reset(ftdi)) != 0)