X-Git-Url: http://developer.intra2net.com/git/?p=libftdi;a=blobdiff_plain;f=src%2Fftdi.c;h=297fa28a908b05bd91fb4965ff73a11accccbc9e;hp=ac0a65127aef1a84e806f4150836286a757d6916;hb=38801bf8af278a43149862ab7a07128f8c4d5aab;hpb=ca41c8ee8dcc93a431fbc0b6746b5ea246d511f9 diff --git a/src/ftdi.c b/src/ftdi.c index ac0a651..297fa28 100644 --- a/src/ftdi.c +++ b/src/ftdi.c @@ -2195,17 +2195,6 @@ void ftdi_eeprom_initdefaults(struct ftdi_context *ftdi) eeprom->product_id = 0x6001; else eeprom->product_id = 0x6010; - switch (ftdi->type) - { - case TYPE_2232C: - eeprom->release = 0x500; - break; - case TYPE_2232H: - eeprom->release = 0x200; - break; - default: - eeprom->release = 0; - } if (ftdi->type == TYPE_AM) eeprom->usb_version = 0x0101; else @@ -2268,7 +2257,7 @@ void ftdi_eeprom_free(struct ftdi_context *ftdi) */ int ftdi_eeprom_build(struct ftdi_context *ftdi, unsigned char *output) { - unsigned char i, j; + unsigned char i, j, k; unsigned short checksum, value; unsigned char manufacturer_size = 0, product_size = 0, serial_size = 0; int size_check; @@ -2284,6 +2273,11 @@ int ftdi_eeprom_build(struct ftdi_context *ftdi, unsigned char *output) if(eeprom->chip == -1) ftdi_error_return(-5,"No connected EEPROM or EEPROM Type unknown"); + if ((eeprom->chip == 0x56) || (eeprom->chip == 0x66)) + eeprom->size = 0x100; + else + eeprom->size = 0x80; + if (eeprom->manufacturer != NULL) manufacturer_size = strlen(eeprom->manufacturer); if (eeprom->product != NULL) @@ -2320,12 +2314,8 @@ int ftdi_eeprom_build(struct ftdi_context *ftdi, unsigned char *output) // empty eeprom memset (output, 0, eeprom->size); - // Addr 00: High current IO - output[0x00] = eeprom->high_current_a ? HIGH_CURRENT_DRIVE : 0; - // Addr 01: IN endpoint size (for R type devices, different for FT2232) - if (ftdi->type == TYPE_R) { - output[0x01] = 0x40; - } + // Bytes and Bits set for all Types + // Addr 02: Vendor ID output[0x02] = eeprom->vendor_id; output[0x03] = eeprom->vendor_id >> 8; @@ -2336,7 +2326,7 @@ int ftdi_eeprom_build(struct ftdi_context *ftdi, unsigned char *output) // Addr 06: Device release number (0400h for BM features) output[0x06] = 0x00; - switch (eeprom->release) { + switch (ftdi->type) { case TYPE_AM: output[0x07] = 0x02; break; @@ -2349,6 +2339,12 @@ int ftdi_eeprom_build(struct ftdi_context *ftdi, unsigned char *output) case TYPE_R: output[0x07] = 0x06; break; + case TYPE_2232H: + output[0x07] = 0x07; + break; + case TYPE_4232H: + output[0x07] = 0x08; + break; default: output[0x07] = 0x00; } @@ -2368,96 +2364,243 @@ int ftdi_eeprom_build(struct ftdi_context *ftdi, unsigned char *output) // Addr 09: Max power consumption: max power = value * 2 mA output[0x09] = eeprom->max_power; - // Addr 0A: Chip configuration - // Bit 7: 0 - reserved - // Bit 6: 0 - reserved - // Bit 5: 0 - reserved - // Bit 4: 1 - Change USB version - // not seen on FT2232C) - // Bit 3: 1 - Use the serial number string - // Bit 2: 1 - Enable suspend pull downs for lower power - // Bit 1: 1 - Out EndPoint is Isochronous - // Bit 0: 1 - In EndPoint is Isochronous - // - j = 0; - if (eeprom->in_is_isochronous == 1) - j = j | 1; - if (eeprom->out_is_isochronous == 1) - j = j | 2; - if (eeprom->suspend_pull_downs == 1) - j = j | 4; - if (eeprom->use_serial == 1) - j = j | 8; - output[0x0A] = j; - - // Addr 0B: Invert data lines - output[0x0B] = eeprom->invert & 0xff; - - // Addr 0C: USB version low byte - // Addr 0D: USB version high byte - output[0x0C] = eeprom->usb_version; - output[0x0D] = eeprom->usb_version >> 8; + if(ftdi->type != TYPE_AM) + { + // Addr 0A: Chip configuration + // Bit 7: 0 - reserved + // Bit 6: 0 - reserved + // Bit 5: 0 - reserved + // Bit 4: 1 - Change USB version + // Bit 3: 1 - Use the serial number string + // Bit 2: 1 - Enable suspend pull downs for lower power + // Bit 1: 1 - Out EndPoint is Isochronous + // Bit 0: 1 - In EndPoint is Isochronous + // + j = 0; + if (eeprom->in_is_isochronous == 1) + j = j | 1; + if (eeprom->out_is_isochronous == 1) + j = j | 2; + output[0x0A] = j; + } + // Dynamic content + // Strings start at 0x94 (TYPE_AM, TYPE_BM) + // 0x96 (TYPE_2232C), 0x98 (TYPE_R) and 0x9a (TYPE_x232H) + i = 0; + switch(ftdi->type) + { + case TYPE_2232H: + case TYPE_4232H: + i += 2; + case TYPE_R: + i += 2; + case TYPE_2232C: + i += 2; + case TYPE_AM: + case TYPE_BM: + i += 0x94; + } + /* Wrap around 0x80 for 128 byte EEPROMS (Internale and 93x46) */ + k = eeprom->size -1; // Addr 0E: Offset of the manufacturer string + 0x80, calculated later // Addr 0F: Length of manufacturer string + // Output manufacturer + output[0x0E] = i; // calculate offset + output[i++ & k] = manufacturer_size*2 + 2; + output[i++ & k] = 0x03; // type: string + for (j = 0; j < manufacturer_size; j++) + { + output[i & k] = eeprom->manufacturer[j], i++; + output[i & k] = 0x00, i++; + } output[0x0F] = manufacturer_size*2 + 2; // Addr 10: Offset of the product string + 0x80, calculated later // Addr 11: Length of product string + output[0x10] = i | 0x80; // calculate offset + output[i & k] = product_size*2 + 2, i++; + output[i & k] = 0x03, i++; + for (j = 0; j < product_size; j++) + { + output[i & k] = eeprom->product[j], i++; + output[i & k] = 0x00, i++; + } 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 & k] = serial_size*2 + 2, i++; + output[i & k] = 0x03, i++; + for (j = 0; j < serial_size; j++) + { + output[i & k] = eeprom->serial[j], i++; + output[i & k] = 0x00, i++; + } output[0x13] = serial_size*2 + 2; - // Addr 14: CBUS function: CBUS0, CBUS1 - // Addr 15: CBUS function: CBUS2, CBUS3 - // Addr 16: CBUS function: CBUS5 - output[0x14] = eeprom->cbus_function[0] | (eeprom->cbus_function[1] << 4); - output[0x15] = eeprom->cbus_function[2] | (eeprom->cbus_function[3] << 4); - output[0x16] = eeprom->cbus_function[4]; - // Addr 17: Unknown + /* Fixme: ftd2xx seems to append 0x02, 0x03 and 0x01 for PnP = 0 or 0x00 else */ + // calculate checksum - // Dynamic content - // In images produced by FTDI's FT_Prog for FT232R strings start at 0x18 - // Space till 0x18 should be considered as reserved. - if (ftdi->type >= TYPE_R) { - i = 0x18; - } else { - i = 0x14; - } - if (eeprom->size >= 256) i = 0x80; + /* Bytes and Bits specific to (some) types + Write linear, as this allows easier fixing*/ + switch(ftdi->type) + { + case TYPE_AM: + break; + 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: + output[0x00] = (eeprom->channel_a_type); + if ( eeprom->channel_a_driver == DRIVER_VCP) + output[0x00] |= DRIVER_VCP; + else + output[0x00] &= ~DRIVER_VCP; + + if ( eeprom->high_current_a == HIGH_CURRENT_DRIVE) + output[0x00] |= HIGH_CURRENT_DRIVE; + else + output[0x00] &= ~HIGH_CURRENT_DRIVE; - // Output manufacturer - output[0x0E] = i | 0x80; // calculate offset - output[i++] = manufacturer_size*2 + 2; - output[i++] = 0x03; // type: string - for (j = 0; j < manufacturer_size; j++) - { - output[i] = eeprom->manufacturer[j], i++; - output[i] = 0x00, i++; - } + output[0x01] = (eeprom->channel_b_type); + if ( eeprom->channel_b_driver == DRIVER_VCP) + output[0x01] |= DRIVER_VCP; + else + output[0x01] &= ~DRIVER_VCP; + + if ( eeprom->high_current_b == HIGH_CURRENT_DRIVE) + output[0x01] |= HIGH_CURRENT_DRIVE; + else + output[0x01] &= ~HIGH_CURRENT_DRIVE; - // Output product name - output[0x10] = i | 0x80; // calculate offset - output[i] = product_size*2 + 2, i++; - output[i] = 0x03, i++; - for (j = 0; j < product_size; j++) - { - output[i] = eeprom->product[j], i++; - output[i] = 0x00, i++; - } + if (eeprom->in_is_isochronous == 1) + output[0x0A] |= 0x1; + else + output[0x0A] &= ~0x1; + if (eeprom->out_is_isochronous == 1) + output[0x0A] |= 0x2; + else + output[0x0A] &= ~0x2; + if (eeprom->suspend_pull_downs == 1) + 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; + break; + case TYPE_R: + if(eeprom->high_current == HIGH_CURRENT_DRIVE_R) + output[0x00] |= HIGH_CURRENT_DRIVE_R; + output[0x01] = 0x40; /* Hard coded Endpoint Size*/ + + if (eeprom->suspend_pull_downs == 1) + 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; + + if(eeprom->cbus_function[0] > CBUS_BB) + output[0x14] = CBUS_BB; + else + output[0x14] = eeprom->cbus_function[0]; + + if(eeprom->cbus_function[1] > CBUS_BB) + output[0x14] |= CBUS_BB<<4; + else + output[0x14] |= eeprom->cbus_function[1]; + + if(eeprom->cbus_function[2] > CBUS_BB) + output[0x15] |= CBUS_BB<<4; + else + output[0x15] |= eeprom->cbus_function[2]; + + if(eeprom->cbus_function[3] > CBUS_BB) + output[0x15] |= CBUS_BB<<4; + else + output[0x15] |= eeprom->cbus_function[3]; + + if(eeprom->cbus_function[5] > CBUS_BB) + output[0x16] = CBUS_BB; + else + output[0x16] = eeprom->cbus_function[0]; + break; + case TYPE_2232H: + output[0x00] = (eeprom->channel_a_type); + if ( eeprom->channel_a_driver == DRIVER_VCP) + output[0x00] |= DRIVER_VCP; + else + output[0x00] &= ~DRIVER_VCP; + + output[0x01] = (eeprom->channel_b_type); + if ( eeprom->channel_b_driver == DRIVER_VCP) + output[0x01] |= DRIVER_VCP; + else + output[0x01] &= ~DRIVER_VCP; + if(eeprom->suspend_dbus7 == SUSPEND_DBUS7) + output[0x01] |= SUSPEND_DBUS7; + else + output[0x01] &= ~SUSPEND_DBUS7; + + 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[0x0c] |= DRIVE_16MA<<4; + else + output[0x0c] |= eeprom->group1_drive<<4; + if (eeprom->group1_schmitt == IS_SCHMITT) + output[0x0c] |= IS_SCHMITT<<4; + if (eeprom->group1_slew == SLOW_SLEW) + output[0x0c] |= SLOW_SLEW<<4; + + if(eeprom->group2_drive > DRIVE_16MA) + output[0x0d] |= DRIVE_16MA; + else + output[0x0d] |= eeprom->group2_drive; + if (eeprom->group2_schmitt == IS_SCHMITT) + output[0x0d] |= IS_SCHMITT; + if (eeprom->group2_slew == SLOW_SLEW) + output[0x0d] |= SLOW_SLEW; + + if(eeprom->group3_drive > DRIVE_16MA) + output[0x0d] |= DRIVE_16MA<<4; + else + output[0x0d] |= eeprom->group3_drive<<4; + if (eeprom->group3_schmitt == IS_SCHMITT) + output[0x0d] |= IS_SCHMITT<<4; + if (eeprom->group3_slew == SLOW_SLEW) + output[0x0d] |= SLOW_SLEW<<4; - // Output serial - output[0x12] = i | 0x80; // calculate offset - output[i] = serial_size*2 + 2, i++; - output[i] = 0x03, i++; - for (j = 0; j < serial_size; j++) - { - output[i] = eeprom->serial[j], i++; - output[i] = 0x00, i++; + output[0x18] = eeprom->chip; + + break; } // calculate checksum @@ -2498,6 +2641,7 @@ int ftdi_eeprom_decode(struct ftdi_context *ftdi, unsigned char *buf, int size, unsigned char manufacturer_size = 0, product_size = 0, serial_size = 0; int eeprom_size; struct ftdi_eeprom *eeprom; + int release; if (ftdi == NULL) ftdi_error_return(-1,"No context"); @@ -2509,33 +2653,13 @@ int ftdi_eeprom_decode(struct ftdi_context *ftdi, unsigned char *buf, int size, eeprom_size = 0x80; eeprom = ftdi->eeprom; - // Addr 00: Channel A setting - - eeprom->channel_a_type = buf[0x00] & 0x7; - eeprom->high_current = buf[0x00] & HIGH_CURRENT_DRIVE_R; - eeprom->channel_a_driver = buf[0x00] & DRIVER_D2XX; - eeprom->high_current_a = buf[0x00] & HIGH_CURRENT_DRIVE; - - // Addr 01: Channel B setting - - eeprom->channel_b_type = buf[0x01] & 0x7; - eeprom->channel_b_driver = buf[0x01] & DRIVER_D2XX; - eeprom->high_current_b = buf[0x01] & HIGH_CURRENT_DRIVE; - - eeprom->suspend_dbus7 = buf[0x01] & SUSPEND_DBUS7; - - if((ftdi->type == TYPE_R) && ((buf[0x01]&0x40) != 0x40)) - fprintf(stderr, - "TYPE_R EEPROM byte[0x01] Bit 6 unexpected Endpoint size. If this happened with the\n" - " EEPROM programmed by FTDI tools, please report to libftdi@developer.intra2net.com\n"); - // Addr 02: Vendor ID eeprom->vendor_id = buf[0x02] + (buf[0x03] << 8); // Addr 04: Product ID eeprom->product_id = buf[0x04] + (buf[0x05] << 8); - eeprom->release = buf[0x06] + (buf[0x07]<<8); + release = buf[0x06] + (buf[0x07]<<8); // Addr 08: Config descriptor // Bit 7: always 1 @@ -2650,16 +2774,33 @@ int ftdi_eeprom_decode(struct ftdi_context *ftdi, unsigned char *buf, int size, ftdi_error_return(-1,"EEPROM checksum error"); } - else if ((ftdi->type == TYPE_AM) || (ftdi->type == TYPE_BM)) + eeprom->channel_a_type = 0; + if ((ftdi->type == TYPE_AM) || (ftdi->type == TYPE_BM)) { eeprom->chip = -1; } else if(ftdi->type == TYPE_2232C) { + eeprom->channel_a_type = 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; + eeprom->channel_b_driver = buf[0x01] & DRIVER_VCP; + eeprom->high_current_b = buf[0x01] & HIGH_CURRENT_DRIVE; eeprom->chip = buf[0x14]; } else if(ftdi->type == TYPE_R) { + /* TYPE_R flags D2XX, not VCP as all others*/ + eeprom->channel_a_driver = (~buf[0x00]) & DRIVER_VCP; + eeprom->high_current = buf[0x00] & HIGH_CURRENT_DRIVE_R; + if( (buf[0x01]&0x40) != 0x40) + fprintf(stderr, + "TYPE_R EEPROM byte[0x01] Bit 6 unexpected Endpoint size." + " If this happened with the\n" + " EEPROM programmed by FTDI tools, please report " + "to libftdi@developer.intra2net.com\n"); + eeprom->chip = buf[0x16]; // Addr 0B: Invert data lines // Works only on FT232R, not FT245R, but no way to distinguish @@ -2675,6 +2816,14 @@ 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_driver = buf[0x00] & DRIVER_VCP; + eeprom->channel_b_type = buf[0x01] & 0x7; + eeprom->channel_b_driver = buf[0x01] & DRIVER_VCP; + + if(ftdi->type == TYPE_2232H) + eeprom->suspend_dbus7 = buf[0x01] & SUSPEND_DBUS7; + eeprom->chip = buf[0x18]; eeprom->group0_drive = buf[0x0c] & DRIVE_16MA; eeprom->group0_schmitt = buf[0x0c] & IS_SCHMITT; @@ -2695,7 +2844,7 @@ int ftdi_eeprom_decode(struct ftdi_context *ftdi, unsigned char *buf, int size, char *channel_mode[] = {"UART","245","CPU", "unknown", "OPTO"}; fprintf(stdout, "VID: 0x%04x\n",eeprom->vendor_id); fprintf(stdout, "PID: 0x%04x\n",eeprom->product_id); - fprintf(stdout, "Release: 0x%04x\n",eeprom->release); + fprintf(stdout, "Release: 0x%04x\n",release); if(eeprom->self_powered) fprintf(stdout, "Self-Powered%s", (eeprom->remote_wakeup)?", USB Remote Wake Up\n":"\n"); @@ -2722,13 +2871,13 @@ int ftdi_eeprom_decode(struct ftdi_context *ftdi, unsigned char *buf, int size, if (ftdi->type >= TYPE_2232C) fprintf(stdout,"Channel A has Mode %s%s%s\n", channel_mode[eeprom->channel_a_type], - (eeprom->channel_a_driver)?" D2XX":"", - (eeprom->high_current_a)?" High Currenr IO":""); - if (ftdi->type >= TYPE_2232C) + (eeprom->channel_a_driver)?" VCP":"", + (eeprom->high_current_a)?" High Current IO":""); + if ((ftdi->type >= TYPE_2232C) && (ftdi->type != TYPE_R)) fprintf(stdout,"Channel B has Mode %s%s%s\n", channel_mode[eeprom->channel_b_type], - (eeprom->channel_b_driver)?" D2XX":"", - (eeprom->high_current_b)?" High Currenr IO":""); + (eeprom->channel_b_driver)?" VCP":"", + (eeprom->high_current_b)?" High Current IO":""); if ((ftdi->type == TYPE_2232H) || (ftdi->type == TYPE_4232H)) { fprintf(stdout,"%s has %d mA drive%s%s\n",