diff --git a/ftdi_eeprom/main.c b/ftdi_eeprom/main.c index 455f156..9608c67 100644 --- a/ftdi_eeprom/main.c +++ b/ftdi_eeprom/main.c @@ -185,6 +185,7 @@ static void usage(const char *program) fprintf(stderr, " i:::\n"); fprintf(stderr, " s:::\n"); fprintf(stderr, "--read-eeprom Read eeprom and write to -filename- from config-file\n"); + fprintf(stderr, "--build-eeprom Build eeprom image\n"); fprintf(stderr, "--erase-eeprom Erase eeprom\n"); fprintf(stderr, "--flash-eeprom Flash eeprom\n"); } @@ -253,6 +254,8 @@ int main(int argc, char *argv[]) CFG_BOOL("chc_rs485", cfg_false, 0), CFG_BOOL("chd_rs485", cfg_false, 0), CFG_FUNC("include", &cfg_include), + CFG_INT("user_data_addr", 0x18, 0), + CFG_STR("user_data_file", "", 0), CFG_END() }; cfg_t *cfg; @@ -263,10 +266,13 @@ int main(int argc, char *argv[]) enum { COMMAND_READ = 1, COMMAND_ERASE, - COMMAND_FLASH + COMMAND_FLASH, + COMMAND_BUILD } command = 0; const char *cfg_filename = NULL; const char *device_description = NULL; + const char *user_data_file = NULL; + char *user_data_buffer = NULL; const int max_eeprom_size = 256; int my_eeprom_size = 0; @@ -307,6 +313,10 @@ int main(int argc, char *argv[]) { command = COMMAND_FLASH; } + else if (!strcmp(argv[i], "--build-eeprom")) + { + command = COMMAND_BUILD; + } else { usage(argv[0]); @@ -511,6 +521,42 @@ int main(int argc, char *argv[]) eeprom_set_value(ftdi, CHANNEL_C_RS485, cfg_getbool(cfg, "chc_rs485")); eeprom_set_value(ftdi, CHANNEL_D_RS485, cfg_getbool(cfg, "chd_rs485")); + /* Arbitrary user data */ + eeprom_set_value(ftdi, USER_DATA_ADDR, cfg_getint(cfg, "user_data_addr")); + user_data_file = cfg_getstr(cfg, "user_data_file"); + if (user_data_file && strlen(user_data_file) > 0) + { + int data_size; + + printf("User data file: %s\n", user_data_file); + /* Allocate a buffer for the user data */ + user_data_buffer = (char *)malloc(max_eeprom_size); + if (user_data_buffer == NULL) + { + fprintf(stderr, "Malloc failed, aborting\n"); + goto cleanup; + } + + /* Read the user data file, no more than max_eeprom_size bytes */ + FILE *fp = fopen(user_data_file, "rb"); + if (fp == NULL) + { + printf ("Can't open user data file %s.\n", user_data_file); + exit (-1); + } + data_size = fread(user_data_buffer, 1, max_eeprom_size, fp); + fclose(fp); + if (data_size < 1) + { + printf ("Can't read user data file %s.\n", user_data_file); + exit (-1); + } + printf("User data size: %d\n", data_size); + + ftdi_set_eeprom_user_buf(ftdi, user_data_buffer, data_size); + } + + if (command == COMMAND_ERASE) { printf("FTDI erase eeprom: %d\n", ftdi_erase_eeprom(ftdi)); @@ -521,7 +567,7 @@ int main(int argc, char *argv[]) if (size_check == -1) { - printf ("Sorry, the eeprom can only contain 128 bytes.\n"); + printf ("Sorry, the eeprom can only contain %d bytes.\n", my_eeprom_size); goto cleanup; } else if (size_check < 0) @@ -558,6 +604,7 @@ int main(int argc, char *argv[]) ftdi_set_eeprom_buf(ftdi, eeprom_buf, my_eeprom_size); } } + printf ("FTDI write eeprom: %d\n", ftdi_write_eeprom(ftdi)); libusb_reset_device(ftdi->usb_dev); } @@ -585,6 +632,8 @@ int main(int argc, char *argv[]) cleanup: if (eeprom_buf) free(eeprom_buf); + if (user_data_buffer) + free(user_data_buffer); if (command > 0) { printf("FTDI close: %d\n", ftdi_usb_close(ftdi)); diff --git a/src/ftdi.c b/src/ftdi.c index 1b29468..fbb8b7d 100644 --- a/src/ftdi.c +++ b/src/ftdi.c @@ -2563,7 +2563,7 @@ int ftdi_eeprom_build(struct ftdi_context *ftdi) unsigned char i, j, eeprom_size_mask; unsigned short checksum, value; unsigned char manufacturer_size = 0, product_size = 0, serial_size = 0; - int user_area_size; + int user_area_size, free_start, free_end; struct ftdi_eeprom *eeprom; unsigned char * output; @@ -2620,6 +2620,7 @@ int ftdi_eeprom_build(struct ftdi_context *ftdi) user_area_size = 0; break; } + if (eeprom->size>128) user_area_size+=eeprom->size-128; user_area_size -= (manufacturer_size + product_size + serial_size) * 2; if (user_area_size < 0) @@ -2712,6 +2713,7 @@ int ftdi_eeprom_build(struct ftdi_context *ftdi) } /* Wrap around 0x80 for 128 byte EEPROMS (Internale and 93x46) */ eeprom_size_mask = eeprom->size -1; + free_end = i & eeprom_size_mask; // Addr 0E: Offset of the manufacturer string + 0x80, calculated later // Addr 0F: Length of manufacturer string @@ -2761,6 +2763,7 @@ int ftdi_eeprom_build(struct ftdi_context *ftdi) } output[0x13] = serial_size*2 + 2; + free_start = 0x14; if (ftdi->type > TYPE_AM) /* use_serial not used in AM devices */ { @@ -2829,6 +2832,7 @@ int ftdi_eeprom_build(struct ftdi_context *ftdi) output[0x0C] = eeprom->usb_version & 0xff; output[0x0D] = (eeprom->usb_version>>8) & 0xff; output[0x14] = eeprom->chip; + free_start = 0x15; break; case TYPE_R: if (eeprom->high_current == HIGH_CURRENT_DRIVE_R) @@ -2869,6 +2873,7 @@ int ftdi_eeprom_build(struct ftdi_context *ftdi) output[0x16] = CBUS_SLEEP; else output[0x16] = eeprom->cbus_function[4]; + free_start = 0x17; break; case TYPE_2232H: output[0x00] = type2bit(eeprom->channel_a_type, TYPE_2232H); @@ -2929,7 +2934,7 @@ int ftdi_eeprom_build(struct ftdi_context *ftdi) output[0x0d] |= SLOW_SLEW<<4; output[0x18] = eeprom->chip; - + free_start = 0x19; break; case TYPE_4232H: if (eeprom->channel_a_driver == DRIVER_VCP) @@ -3008,7 +3013,7 @@ int ftdi_eeprom_build(struct ftdi_context *ftdi) output[0x0d] |= SLOW_SLEW<<4; output[0x18] = eeprom->chip; - + free_start = 0x19; break; case TYPE_232H: output[0x00] = type2bit(eeprom->channel_a_type, TYPE_232H); @@ -3059,6 +3064,7 @@ int ftdi_eeprom_build(struct ftdi_context *ftdi) set_ft232h_cbus(eeprom, output); output[0x1e] = eeprom->chip; + free_start = 0x1F; fprintf(stderr,"FIXME: Build FT232H specific EEPROM settings\n"); break; case TYPE_230X: @@ -3071,9 +3077,23 @@ int ftdi_eeprom_build(struct ftdi_context *ftdi) output[0x1a + j] = eeprom->cbus_function[j]; } output[0x0b] = eeprom->invert; + free_start = 0x21; break; } + /* Arbitrary user data */ + if (eeprom->user_data && (eeprom->user_data_size >= 0)) + { + if (eeprom->user_data_addr < free_start) + fprintf(stderr,"Warning, user data starts inside the generated data!\n"); + if (eeprom->user_data_addr + eeprom->user_data_size >= free_end) + fprintf(stderr,"Warning, user data overlaps the strings area!\n"); + if (eeprom->user_data_addr + eeprom->user_data_size > eeprom->size) + ftdi_error_return(-1,"eeprom size exceeded"); + memcpy(output + eeprom->user_data_addr, eeprom->user_data, eeprom->user_data_size); + user_area_size -= eeprom->user_data_size; + } + // calculate checksum checksum = 0xAAAA; @@ -3953,6 +3973,9 @@ int ftdi_set_eeprom_value(struct ftdi_context *ftdi, enum ftdi_eeprom_value valu case EXTERNAL_OSCILLATOR: ftdi->eeprom->external_oscillator = value; break; + case USER_DATA_ADDR: + ftdi->eeprom->user_data_addr = value; + break; default : ftdi_error_return(-1, "Request to unknown EEPROM value"); @@ -3995,7 +4018,7 @@ int ftdi_get_eeprom_buf(struct ftdi_context *ftdi, unsigned char * buf, int size \param size Size of buffer \retval 0: All fine - \retval -1: struct ftdi_contxt or ftdi_eeprom of buf missing + \retval -1: struct ftdi_context or ftdi_eeprom or buf missing */ int ftdi_set_eeprom_buf(struct ftdi_context *ftdi, const unsigned char * buf, int size) { @@ -4011,6 +4034,25 @@ int ftdi_set_eeprom_buf(struct ftdi_context *ftdi, const unsigned char * buf, in return 0; } +/** Set the EEPROM user data content from the user-supplied prefilled buffer + + \param ftdi pointer to ftdi_context + \param buf buffer to read EEPROM user data content + \param size Size of buffer + + \retval 0: All fine + \retval -1: struct ftdi_context or ftdi_eeprom or buf missing +*/ +int ftdi_set_eeprom_user_buf(struct ftdi_context *ftdi, const char * buf, int size) +{ + if (!ftdi || !(ftdi->eeprom) || !buf) + ftdi_error_return(-1, "No appropriate structure"); + + ftdi->eeprom->user_data_size = size; + ftdi->eeprom->user_data = buf; + return 0; +} + /** Read eeprom location diff --git a/src/ftdi.h b/src/ftdi.h index 5aaeb6c..96cc7bb 100644 --- a/src/ftdi.h +++ b/src/ftdi.h @@ -333,6 +333,7 @@ enum ftdi_eeprom_value CHANNEL_D_RS485 = 54, RELEASE_NUMBER = 55, EXTERNAL_OSCILLATOR= 56, + USER_DATA_ADDR = 57, }; /** @@ -552,6 +553,8 @@ extern "C" int ftdi_get_eeprom_buf(struct ftdi_context *ftdi, unsigned char * buf, int size); int ftdi_set_eeprom_buf(struct ftdi_context *ftdi, const unsigned char * buf, int size); + int ftdi_set_eeprom_user_buf(struct ftdi_context *ftdi, const char * buf, int size); + int ftdi_read_eeprom(struct ftdi_context *ftdi); int ftdi_read_chipid(struct ftdi_context *ftdi, unsigned int *chipid); int ftdi_write_eeprom(struct ftdi_context *ftdi); diff --git a/src/ftdi_i.h b/src/ftdi_i.h index 060a877..cf2ac78 100644 --- a/src/ftdi_i.h +++ b/src/ftdi_i.h @@ -125,6 +125,11 @@ struct ftdi_eeprom int data_order; int flow_control; + /** user data **/ + int user_data_addr; + int user_data_size; + const char *user_data; + /** eeprom size in bytes. This doesn't get stored in the eeprom but is the only way to pass it to ftdi_eeprom_build. */ int size;