From: Salvador Eduardo Tropea Date: Fri, 20 Nov 2015 22:26:03 +0000 (+0100) Subject: eeprom handling: Add support for arbitrary user data X-Git-Tag: v1.3rc1~12 X-Git-Url: http://developer.intra2net.com/git/?p=libftdi;a=commitdiff_plain;h=6e962b9a0991bf28571c7a143a532d83237c05af eeprom handling: Add support for arbitrary user data Add two new configuration options: - user_data_addr: An integer indicating the offset where we want to put the user provided data. - user_data_file: A string indicating the filename that contains the binary data to be added. I've extended the libftdi API to store the above mentioned data inside the eeprom struct. Also extended ftdi_eeprom_build to include this data. --- diff --git a/ftdi_eeprom/main.c b/ftdi_eeprom/main.c index 32d7119..7c6920b 100644 --- a/ftdi_eeprom/main.c +++ b/ftdi_eeprom/main.c @@ -36,6 +36,7 @@ #include #include #include +#include #include #include @@ -254,6 +255,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; @@ -269,6 +272,8 @@ int main(int argc, char *argv[]) } 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; @@ -517,6 +522,51 @@ 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; + struct stat st; + + 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; + } + + if (stat(user_data_file, &st)) + { + printf ("Can't stat user data file %s.\n", user_data_file); + exit (-1); + } + if (st.st_size > max_eeprom_size) + printf("Warning: %s is too big, only reading %d bytes\n", + user_data_file, max_eeprom_size); + /* 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_data(ftdi, user_data_buffer, data_size); + } + + if (command == COMMAND_ERASE) { printf("FTDI erase eeprom: %d\n", ftdi_erase_eeprom(ftdi)); @@ -527,7 +577,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) @@ -591,6 +641,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..aa4b4ec 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; @@ -2598,14 +2598,12 @@ int ftdi_eeprom_build(struct ftdi_context *ftdi) { case TYPE_AM: case TYPE_BM: + case TYPE_R: user_area_size = 96; // base size for strings (total of 48 characters) break; case TYPE_2232C: user_area_size = 90; // two extra config bytes and 4 bytes PnP stuff break; - case TYPE_R: - user_area_size = 96; - break; case TYPE_230X: user_area_size = 88; // four extra config bytes + 4 bytes PnP stuff break; @@ -2712,6 +2710,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 @@ -3074,6 +3073,38 @@ int ftdi_eeprom_build(struct ftdi_context *ftdi) break; } + /* First address without use */ + free_start = 0; + switch (ftdi->type) + { + case TYPE_230X: + free_start += 2; + case TYPE_232H: + free_start += 6; + case TYPE_2232H: + case TYPE_4232H: + free_start += 2; + case TYPE_R: + free_start += 2; + case TYPE_2232C: + free_start++; + case TYPE_AM: + case TYPE_BM: + free_start += 0x14; + } + + /* 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); + } + // calculate checksum checksum = 0xAAAA; @@ -3953,6 +3984,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 +4029,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 +4045,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_data(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..9a6ec79 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_data(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;