Hi Thomas:
El 02/11/15 a las 19:01, Thomas Jarosch escibió:
Hi SET,
Am 22.10.2015 um 21:11 schrieb Salvador Eduardo Tropea:
Hi!
I'm trying to include some data inside the EEPROM generated by ftdi_eeprom tool.
I modified the ftdi_eeprom tool and libftdi to:
1) Support a "--build-eeprom" command line option that just generates the
EEPROM image (only flashed if --flash-eeprom is provided)
2) Support two 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.
3) Extended libftdi API to store the above mentioned data inside the eeprom
struct.
4) Extended ftdi_eeprom_build to include this data.
I'm attaching the output of "git diff".
Is this patch acceptable?
Regards, SET
PS: I fixed a couple of computations that assumed the EEPROM size is 128.
thanks for your patch! It looks quite good and
just needs a few minor tweaks:
- ftdi_eeprom: Warn the user if the supplied user data
is too big for the storage area. Right now we silently truncate it.
Ok, I added a warning about it.
- Do we need to hardcode the hex offsets in "free_start"?
Could we also do "free_start += 1;" and so on?
Hmmm ... not sure. I just added this value after the last index used for
each part.
Now I moved it to a switch/case adjusting for each part.
- Hardcoding of 128 byte limit again in this line:
if (eeprom->size>128) user_area_size+=eeprom->size-128;
?
Would be good to add a comment here that explains why
it's there.
I think it was wrong. I eliminated it.
- Why not ftdi_error_return() in dangerous cases like this:
fprintf(stderr,"Warning, user data overlaps the strings area!\n");
?
Because the user could be doing it on purpose ;-)
Suppose the user knows that ftdi_eeprom lacks some obscure feature and
wants to overwrite an address that is supposed to be properly filled by
ftdi_eeprom.
- ftdi_set_eeprom_user_buf() -> rename to "ftdi_set_eeprom_user_data()"
Ok!
I'm attaching a patch with the above changes.
Regards, SET
--
Ing. Salvador Eduardo Tropea http://utic.inti.gob.ar/
INTI - Micro y Nanoelectrónica (CMNB) http://www.inti.gob.ar/
Unidad Técnica Sistemas Inteligentes Av. General Paz 5445
Tel: (+54 11) 4724 6300 ext. 6919 San Martín - B1650KNA
FAX: (+54 11) 4754 5194 Buenos Aires * Argentina
--
libftdi - see http://www.intra2net.com/en/developer/libftdi for details.
To unsubscribe send a mail to [email protected]
diff --git a/ftdi_eeprom/main.c b/ftdi_eeprom/main.c
index 455f156..f8a6a63 100644
--- a/ftdi_eeprom/main.c
+++ b/ftdi_eeprom/main.c
@@ -36,6 +36,7 @@
#include <stdio.h>
#include <string.h>
#include <errno.h>
+#include <sys/stat.h>
#include <confuse.h>
#include <libusb.h>
@@ -185,6 +186,7 @@ static void usage(const char *program)
fprintf(stderr, " i:<vendor>:<product>:<index>\n");
fprintf(stderr, " s:<vendor>:<product>:<serial>\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 +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;
@@ -263,10 +267,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 +314,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 +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));
@@ -521,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)
@@ -585,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..08da074 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;