/* * read/verify/erase/write eeprom * only binary data files (raw data) supported * * based on * LIBFTDI EEPROM access example * * This program is distributed under the GPL, version 2 */ #include #include #include #include #include #include #include #include #include #define CMD_NONE 0 #define CMD_READ 1 #define CMD_WRITE 2 #define CMD_VERIFY 3 #define CMD_ERASE 4 #define CMD_LIST 5 #define CMD_UNDEF 99 #define MAX_EEPROM_SIZE 256 int erase_eeprom(struct ftdi_context *ftdi) { int f; int value; f = ftdi_erase_eeprom(ftdi); /* needed to determine EEPROM chip type */ if (f < 0) { fprintf(stderr, "Erase failed: %s", ftdi_get_error_string(ftdi)); return -2; } if (ftdi_get_eeprom_value(ftdi, CHIP_TYPE, & value) <0) { fprintf(stderr, "ftdi_get_eeprom_value: %d (%s)\n", f, ftdi_get_error_string(ftdi)); } if (value == -1) fprintf(stderr, "No EEPROM\n"); else if (value == 0) fprintf(stderr, "Internal EEPROM\n"); else fprintf(stderr, "Found 93x%02x\n", value); return value; } int verify_eeprom(struct ftdi_context *ftdi, unsigned char *data, int size) { int ret; int eepromSize; int i; unsigned char *eepromData; ret = ftdi_read_eeprom(ftdi); if (ret < 0) { fprintf(stderr, "Unable to read eeprom: (%s)\n", ftdi_get_error_string(ftdi)); return -1; } ret = ftdi_get_eeprom_value(ftdi, CHIP_SIZE, &eepromSize); if (ret < 0 || eepromSize != size) { fprintf(stderr, "verify failed; size mismatch\n"); return -1; } eepromData = malloc(eepromSize); if (eepromData == 0) { fprintf(stderr, "can't allocate buffer\n"); return -1; } ftdi_get_eeprom_buf(ftdi, eepromData, eepromSize); for (i = 0; i < size; i++) { if (eepromData[i] != data[i]) { fprintf(stderr, "verify failed; first data mismatch at %d\n", i); return -1; } } return 0; } int read_eeprom(struct ftdi_context *ftdi, char *filename) { int ret; int eepromSize; int fh; unsigned char *eepromData; ret = ftdi_read_eeprom(ftdi); if (ret < 0) { fprintf(stderr, "Unable to read eeprom: (%s)\n", ftdi_get_error_string(ftdi)); return -1; } ret = ftdi_get_eeprom_value(ftdi, CHIP_SIZE, &eepromSize); if (ret < 0 || eepromSize == 0 || eepromSize > MAX_EEPROM_SIZE) { fprintf(stderr, "eeprom read failed\n"); return -1; } eepromData = malloc(eepromSize); if (eepromData == 0) { fprintf(stderr, "can't allocate buffer\n"); return -1; } ftdi_get_eeprom_buf(ftdi, eepromData, eepromSize); fh = creat(filename, 0666); if (fh < 0) { fprintf(stderr, "can't open file %s to write\n", filename); return -1; } ret = write(fh, eepromData, eepromSize); if (ret != eepromSize) { fprintf(stderr, "error while writing data to file %s\n", filename); close(fh); return -1; } close(fh); return 0; } int write_eeprom(struct ftdi_context *ftdi, unsigned char *data, int size) { erase_eeprom(ftdi); ftdi_eeprom_initdefaults(ftdi, "", "", ""); ftdi_eeprom_build(ftdi); ftdi_set_eeprom_buf(ftdi, data, size); if (ftdi_write_eeprom(ftdi) < 0) { fprintf(stderr, "Failed to write eeprom :%s \n", ftdi_get_error_string(ftdi)); return -1; } return 0; } int main(int argc, char **argv) { struct ftdi_context *ftdi; struct ftdi_device_list *devlist, *curdev; int res, i; int vid = 0; int pid = 0; int index = -1; int all = 0; int do_reset = 0; int cmd = CMD_NONE; int retval = 0; char *filename = 0; unsigned char fileData[MAX_EEPROM_SIZE]; int fileDataSize = 0; if ((ftdi = ftdi_new()) == 0) { fprintf(stderr, "Failed to allocate ftdi structure :%s \n", ftdi_get_error_string(ftdi)); return EXIT_FAILURE; } while ((i = getopt(argc, argv, "ewrvlaRP:V:I:")) != -1) { switch (i) { case 'e': if (cmd != CMD_NONE) cmd = CMD_UNDEF; else cmd = CMD_ERASE; break; case 'v': if (cmd != CMD_NONE) cmd = CMD_UNDEF; else cmd = CMD_VERIFY; break; case 'r': if (cmd != CMD_NONE) cmd = CMD_UNDEF; else cmd = CMD_READ; break; case 'w': if (cmd != CMD_NONE) cmd = CMD_UNDEF; else cmd = CMD_WRITE; break; case 'l': if (cmd != CMD_NONE) cmd = CMD_UNDEF; else cmd = CMD_LIST; break; case 'R': do_reset = 1; break; case 'V': vid = strtoul(optarg, NULL, 0); break; case 'P': pid = strtoul(optarg, NULL, 0); break; case 'I': index = strtoul(optarg, NULL, 0); break; case 'a': all = 1; break; default: fprintf(stderr, "usage: %s [options] [filename]\n", *argv); fprintf(stderr, "\t-w write\n"); fprintf(stderr, "\t-e erase\n"); fprintf(stderr, "\t-r read\n"); fprintf(stderr, "\t-v verify\n"); fprintf(stderr, "\t-R reset\n"); fprintf(stderr, "\t-l list ftdi devices\n"); fprintf(stderr, "\t-P Search for device with PID == number\n"); fprintf(stderr, "\t-V Search for device with VID == number\n"); fprintf(stderr, "\t-I Use device with index == number\n"); fprintf(stderr, "\t-a Use all connected devices (only useable with cmd -e, -w, -v\n"); retval = -1; goto do_deinit; } } if (cmd == CMD_NONE || cmd == CMD_UNDEF) { fprintf(stderr, "One and only one command (-v, -e, -r, -w, -l) must be supplied.\n"); retval = EXIT_FAILURE; goto do_deinit; } if (cmd == CMD_READ || cmd == CMD_WRITE || cmd == CMD_VERIFY) { if (optind >= argc) { fprintf(stderr, "Missing filename.\n"); retval = EXIT_FAILURE; goto do_deinit; } filename = argv[optind]; if (cmd == CMD_WRITE || cmd == CMD_VERIFY) { int fh; fh = open(filename, O_RDONLY); if (fh < 0) { fprintf(stderr, "can't open file %s to read\n", filename); retval = EXIT_FAILURE; goto do_deinit; } fileDataSize = read(fh, fileData, sizeof(fileData)); if (fileDataSize <= 0) { fprintf(stderr, "error while reading data from file %s\n", filename); close(fh); retval = EXIT_FAILURE; goto do_deinit; } close(fh); } } if ((res = ftdi_usb_find_all(ftdi, &devlist, vid, pid)) < 0) { fprintf(stderr, "No FTDI found\n"); retval = EXIT_FAILURE; goto do_deinit; } else if (res >= 1) { int f; i = 0; if (res > 1 && cmd != CMD_LIST) { if (!all && index < 0 && cmd != CMD_READ) { fprintf(stderr, "Found %d devices and neither -a nor -I given!\n", res); retval = EXIT_FAILURE; goto do_deinit; } if (index < 0 && cmd == CMD_READ) { fprintf(stderr, "Found %d devices and -I not given!\n", res); retval = EXIT_FAILURE; goto do_deinit; } } else if (index < 0) index = 0; for (curdev = devlist; curdev != NULL; i++) { if (cmd == CMD_LIST) { char manufacturer[128], description[128]; int ret; printf("Checking device: %d ", i); if ((ret = ftdi_usb_get_strings(ftdi, curdev->dev, manufacturer, 128, description, 128, NULL, 0)) < 0) { fprintf(stderr, "ftdi_usb_get_strings failed: %d (%s)\n", ret, ftdi_get_error_string(ftdi)); retval = EXIT_FAILURE; goto do_deinit; } printf("Manufacturer/Description: %s / %s\n", manufacturer, description); } else if (all || i == index) { f = ftdi_usb_open_dev(ftdi, curdev->dev); if (f<0) { fprintf(stderr, "Unable to open device %d: (%s)\n", i, ftdi_get_error_string(ftdi)); } fprintf(stderr, "Using device %d: ", i); if (cmd == CMD_ERASE) { int ret; fprintf(stderr, "erasing eeprom\n"); ret = erase_eeprom(ftdi); if (ret < 0) retval = ret; else fprintf(stderr, "erase OK\n"); do_reset = 1; } if (cmd == CMD_VERIFY) { int ret; fprintf(stderr, "verifying eeprom ... "); ret = verify_eeprom(ftdi, fileData, fileDataSize); if (ret < 0) { retval = ret; } else fprintf(stderr, "verify OK\n"); } if (cmd == CMD_READ) { int ret; fprintf(stderr, "reading eeprom ... "); ret = read_eeprom(ftdi, filename); if (ret < 0) { retval = ret; } else { fprintf(stderr, " OK\n"); } } if (cmd == CMD_WRITE) { int ret; fprintf(stderr, "checking eeprom ... "); ret = verify_eeprom(ftdi, fileData, fileDataSize); if (ret < 0) { fprintf(stderr, " writing ... "); ret = write_eeprom(ftdi, fileData, fileDataSize); if (ret < 0) retval = ret; else { fprintf(stderr, "OK, verifying ... "); ret = verify_eeprom(ftdi, fileData, fileDataSize); if (ret < 0) retval = ret; else { fprintf(stderr, "OK\n"); } } do_reset = 1; } else { fprintf(stderr, "verify OK, no need to write\n"); } } libusb_device *usb_dev = libusb_get_device(ftdi->usb_dev); ftdi_usb_close(ftdi); if (cmd != CMD_LIST) { int ret; libusb_device_handle *dev_handle; ret = libusb_open(usb_dev, &dev_handle); if (ret != 0) { fprintf(stderr, " failed: libusb error code %d \n", ret); } else { fprintf(stderr, "reattaching serial driver ... "); ret = libusb_attach_kernel_driver(dev_handle, 0); if (ret != 0) { retval = EXIT_FAILURE; fprintf(stderr, " failed: libusb error code %d \n", ret); } else { fprintf(stderr, " OK\n"); } if (do_reset) { int ret; fprintf(stderr, "resetting device ... "); ret = libusb_reset_device(dev_handle); if (ret != 0) { retval = EXIT_FAILURE; fprintf(stderr, " failed\n"); } else { fprintf(stderr, " OK\n"); } } libusb_close(dev_handle); } } } curdev = curdev->next; } } else { fprintf(stderr, "No devices found\n"); } ftdi_list_free(&devlist); do_deinit: ftdi_free(ftdi); return retval; }