summaryrefslogtreecommitdiff
path: root/xpp/utils/fpga_load.c
diff options
context:
space:
mode:
authortzafrir <tzafrir@5390a7c7-147a-4af0-8ec9-7488f05a26cb>2006-05-08 07:51:38 +0000
committertzafrir <tzafrir@5390a7c7-147a-4af0-8ec9-7488f05a26cb>2006-05-08 07:51:38 +0000
commitd89a13a276d0bc8faaba42aabc8e53e8de071b87 (patch)
treeb52e544cb4575706ca17b40840081545f20ec255 /xpp/utils/fpga_load.c
parent2dd60aaf18e98b0e9d3c06bd9dce5f1128fa55ad (diff)
xpp driver release 1.1.0 (second part of commit from r1021)
* Please avoid setting the keyword Id on the firmware files (*.hex) to preserve the original versioning comment. git-svn-id: http://svn.digium.com/svn/zaptel/trunk@1023 5390a7c7-147a-4af0-8ec9-7488f05a26cb
Diffstat (limited to 'xpp/utils/fpga_load.c')
-rw-r--r--xpp/utils/fpga_load.c710
1 files changed, 710 insertions, 0 deletions
diff --git a/xpp/utils/fpga_load.c b/xpp/utils/fpga_load.c
new file mode 100644
index 0000000..cf20226
--- /dev/null
+++ b/xpp/utils/fpga_load.c
@@ -0,0 +1,710 @@
+#include <stdio.h>
+#include <assert.h>
+#include <string.h>
+#include <stdint.h>
+#include <errno.h>
+#include <sys/types.h>
+#include <sys/param.h>
+#include <usb.h>
+#include "hexfile.h"
+
+#define XORCOM_INTERNAL
+
+static const char rcsid[] = "$Id$";
+
+#define ERR(fmt, arg...) fprintf(stderr, "%s: ERROR: " fmt, progname, ## arg)
+#define INFO(fmt, arg...) fprintf(stderr, "%s: " fmt, progname, ## arg)
+
+static int verbose = LOG_WARNING;
+static char *progname;
+
+#define MAX_HEX_LINES 2000
+#define PACKET_SIZE 512
+#define EEPROM_SIZE 16
+#define SERIAL_SIZE 8
+
+enum fpga_load_packet_types {
+ STATUS_REPLY = 0x01,
+ DATA_PACKET = 0x01,
+#ifdef XORCOM_INTERNAL
+ EEPROM_SET = 0x04,
+#endif
+ EEPROM_GET = 0x08,
+ RENUMERATE = 0x10,
+ BAD_COMMAND = 0xAA
+};
+
+struct myeeprom {
+ uint8_t source;
+ uint16_t vendor;
+ uint16_t product;
+ uint8_t release_major;
+ uint8_t release_minor;
+ uint8_t reserved;
+ uint8_t serial[SERIAL_SIZE];
+} PACKED;
+
+struct fpga_packet_header {
+ struct {
+ uint8_t op;
+ } PACKED header;
+ union {
+ struct {
+ uint16_t seq;
+ uint8_t status;
+ } PACKED status_reply;
+ struct {
+ uint16_t seq;
+ uint8_t reserved;
+ uint8_t data[ZERO_SIZE];
+ } PACKED data_packet;
+ struct {
+ struct myeeprom data;
+ } PACKED eeprom_set;
+ struct {
+ struct myeeprom data;
+ } PACKED eeprom_get;
+ } d;
+} PACKED;
+
+enum fpga_load_status {
+ FW_FAIL_RESET = 1,
+ FW_FAIL_TRANS = 2,
+ FW_TRANS_OK = 4,
+ FW_CONFIG_DONE = 8
+};
+
+int my_usb_device(struct usb_device *dev, usb_dev_handle *handle);
+
+const char *load_status2str(enum fpga_load_status s)
+{
+ switch(s) {
+ case FW_FAIL_RESET: return "FW_FAIL_RESET";
+ case FW_FAIL_TRANS: return "FW_FAIL_TRANS";
+ case FW_TRANS_OK: return "FW_TRANS_OK";
+ case FW_CONFIG_DONE: return "FW_CONFIG_DONE";
+ default: return "UNKNOWN";
+ }
+}
+
+int path_of_dev(char buf[], unsigned int buflen, struct usb_device *dev)
+{
+ return snprintf(buf, buflen, "/proc/bus/usb/%s/%s", dev->bus->dirname, dev->filename);
+}
+
+struct usb_device *dev_of_path(const char *path)
+{
+ struct usb_bus *bus;
+ struct usb_device *dev;
+ char dirname[PATH_MAX];
+ char filename[PATH_MAX];
+ const char prefix[] = "/proc/bus/usb/";
+ const int prefix_len = strlen(prefix);
+ const char *p;
+ int bnum;
+ int dnum;
+ int ret;
+
+ assert(path != NULL);
+ if(strncmp(prefix, path, prefix_len) != 0) {
+ ERR("wrong path: '%s'\n", path);
+ return NULL;
+ }
+ p = path + prefix_len;
+ ret = sscanf(p, "%d/%d", &bnum, &dnum);
+ if(ret != 2) {
+ ERR("wrong path tail: '%s'\n", p);
+ return NULL;
+ }
+ sprintf(dirname, "%03d", bnum);
+ sprintf(filename, "%03d", dnum);
+ for (bus = usb_busses; bus; bus = bus->next) {
+ if(strcmp(bus->dirname, dirname) != 0)
+ continue;
+ for (dev = bus->devices; dev; dev = dev->next) {
+ if(strcmp(dev->filename, filename) == 0)
+ return dev;
+ }
+ }
+ ERR("no usb device match '%s'\n", path);
+ return NULL;
+}
+
+int get_usb_string(char *buf, unsigned int len, uint16_t item, usb_dev_handle *handle)
+{
+ char tmp[BUFSIZ];
+ int ret;
+
+ if (!item)
+ return 0;
+ ret = usb_get_string_simple(handle, item, tmp, BUFSIZ);
+ if (ret <= 0)
+ return ret;
+ return snprintf(buf, len, "%s", tmp);
+}
+
+/* My device parameters */
+#define MY_INTERFACE 0
+#define MY_CONFIG 1
+#define MY_ENDPOINTS 4
+
+#define MY_EP_OUT 0x04
+#define MY_EP_IN 0x88
+
+#define TIMEOUT 5000
+
+static const int my_endpoints[MY_ENDPOINTS] = {
+ 0x02,
+ 0x04,
+ 0x86,
+ 0x88
+};
+
+void usb_cleanup(usb_dev_handle *handle)
+{
+ if(usb_release_interface(handle, MY_INTERFACE) != 0) {
+ ERR("Releasing interface: usb: %s\n", usb_strerror());
+ }
+ if(usb_close(handle) != 0) {
+ ERR("Closing device: usb: %s\n", usb_strerror());
+ }
+}
+
+void print_bcd_ver(const struct myeeprom *eeprom)
+{
+ /* In this case, print only the version. Also note that this
+ * is an output, and sent to stdout
+ */
+ printf("%d.%03d\n", eeprom->release_major, eeprom->release_minor);
+ return;
+}
+
+void dump_eeprom(const struct myeeprom *eeprom)
+{
+ const uint8_t *data = eeprom->serial;
+
+ INFO("Source: 0x%02X\n", eeprom->source);
+ INFO("Vendor: 0x%04X\n", eeprom->vendor);
+ INFO("Product: 0x%04X\n", eeprom->product);
+ INFO("Release: %d.%03d\n", eeprom->release_major, eeprom->release_minor);
+ INFO("Data: 0x[%02X,%02X,%02X,%02X,%02X,%02X,%02X,%02X]\n",
+ data[0], data[1], data[2], data[3],
+ data[4], data[5], data[6], data[7]);
+}
+
+void dump_packet(const char *buf, int len)
+{
+ int i;
+
+ for(i = 0; i < len; i++)
+ INFO("dump: %2d> 0x%02X\n", i, (uint8_t)buf[i]);
+}
+
+#ifdef XORCOM_INTERNAL
+int eeprom_set(struct usb_dev_handle *handle, const struct myeeprom *eeprom)
+{
+ int ret;
+ int len;
+ char buf[PACKET_SIZE];
+ struct fpga_packet_header *phead = (struct fpga_packet_header *)buf;
+
+ if(verbose >= LOG_INFO)
+ INFO("%s Start...\n", __FUNCTION__);
+ assert(handle != NULL);
+ phead->header.op = EEPROM_SET;
+ memcpy(&phead->d.eeprom_set.data, eeprom, EEPROM_SIZE);
+ len = sizeof(phead->d.eeprom_set) + sizeof(phead->header.op);
+ if(verbose >= LOG_INFO) {
+ INFO("%s write %d bytes\n", __FUNCTION__, len);
+ dump_packet((char *)phead, len);
+ }
+ ret = usb_bulk_write(handle, MY_EP_OUT, (char *)phead, len, TIMEOUT);
+ if(ret < 0) {
+ ERR("usb: bulk_write failed (%d)\n", ret);
+ return ret;
+ } else if(ret != len) {
+ ERR("usb: bulk_write short write (%d)\n", ret);
+ return -EFAULT;
+ }
+ ret = usb_bulk_read(handle, MY_EP_IN, buf, sizeof(buf), TIMEOUT);
+ if(ret < 0) {
+ ERR("usb: bulk_read failed (%d)\n", ret);
+ return ret;
+ } else if(ret == 0)
+ return 0;
+ phead = (struct fpga_packet_header *)buf;
+ if(phead->header.op == BAD_COMMAND) {
+ ERR("BAD_COMMAND\n");
+ return -EINVAL;
+ } else if(phead->header.op != EEPROM_SET) {
+ ERR("Got unexpected reply op=%d\n", phead->header.op);
+ return -EINVAL;
+ }
+ if(verbose >= LOG_INFO) {
+ INFO("%s read %d bytes\n", __FUNCTION__, ret);
+ dump_packet(buf, ret);
+ }
+ return 0;
+}
+#endif
+
+int eeprom_get(struct usb_dev_handle *handle, struct myeeprom *eeprom)
+{
+ int ret;
+ int len;
+ char buf[PACKET_SIZE];
+ struct fpga_packet_header *phead = (struct fpga_packet_header *)buf;
+
+ assert(handle != NULL);
+ if(verbose >= LOG_INFO)
+ INFO("%s Start...\n", __FUNCTION__);
+ phead->header.op = EEPROM_GET;
+ len = sizeof(phead->header.op); /* warning: sending small packet */
+ if(verbose >= LOG_INFO) {
+ INFO("%s write %d bytes\n", __FUNCTION__, len);
+ dump_packet(buf, len);
+ }
+ ret = usb_bulk_write(handle, MY_EP_OUT, (char *)phead, len, TIMEOUT);
+ if(ret < 0) {
+ ERR("usb: bulk_write failed (%d)\n", ret);
+ return ret;
+ } else if(ret != len) {
+ ERR("usb: bulk_write short write (%d)\n", ret);
+ return -EFAULT;
+ }
+ ret = usb_bulk_read(handle, MY_EP_IN, buf, sizeof(buf), TIMEOUT);
+ if(ret < 0) {
+ ERR("usb: bulk_read failed (%d)\n", ret);
+ return ret;
+ } else if(ret == 0)
+ return 0;
+ phead = (struct fpga_packet_header *)buf;
+ if(phead->header.op == BAD_COMMAND) {
+ ERR("BAD_COMMAND\n");
+ return -EINVAL;
+ } else if(phead->header.op != EEPROM_GET) {
+ ERR("Got unexpected reply op=%d\n", phead->header.op);
+ return -EINVAL;
+ }
+ if(verbose >= LOG_INFO) {
+ INFO("%s read %d bytes\n", __FUNCTION__, ret);
+ dump_packet(buf, ret);
+ }
+ memcpy(eeprom, &phead->d.eeprom_get.data, EEPROM_SIZE);
+ return 0;
+}
+
+int send_hexline(struct usb_dev_handle *handle, struct hexline *hexline, int seq)
+{
+ int ret;
+ int len;
+ uint8_t *data;
+ char buf[PACKET_SIZE];
+ struct fpga_packet_header *phead = (struct fpga_packet_header *)buf;
+ enum fpga_load_status status;
+
+ assert(handle != NULL);
+ assert(hexline != NULL);
+ len = hexline->d.content.header.ll; /* don't send checksum */
+ data = hexline->d.content.tt_data.data;
+ if(hexline->d.content.header.tt != TT_DATA) {
+ ERR("Bad record %d type = %d\n", seq, hexline->d.content.header.tt);
+ return -EINVAL;
+ }
+ phead->header.op = DATA_PACKET;
+ phead->d.data_packet.seq = seq;
+ phead->d.data_packet.reserved = 0x00;
+ memcpy(phead->d.data_packet.data, data, len);
+ len += sizeof(phead);
+ if(verbose >= LOG_INFO)
+ INFO("%04d+\r", seq);
+ ret = usb_bulk_write(handle, MY_EP_OUT, (char *)phead, len, TIMEOUT);
+ if(ret < 0) {
+ ERR("usb: bulk_write failed (%d)\n", ret);
+ return ret;
+ } else if(ret != len) {
+ ERR("usb: bulk_write short write (%d)\n", ret);
+ return -EFAULT;
+ }
+ ret = usb_bulk_read(handle, MY_EP_IN, buf, sizeof(buf), TIMEOUT);
+ if(ret < 0) {
+ ERR("usb: bulk_read failed (%d)\n", ret);
+ return ret;
+ } else if(ret == 0)
+ return 0;
+ if(verbose >= LOG_INFO)
+ INFO("%04d-\r", seq);
+ phead = (struct fpga_packet_header *)buf;
+ if(phead->header.op != STATUS_REPLY) {
+ ERR("Got unexpected reply op=%d\n", phead->header.op);
+ return -EINVAL;
+ }
+ status = (enum fpga_load_status)phead->d.status_reply.status;
+ switch(status) {
+ case FW_TRANS_OK:
+ case FW_CONFIG_DONE:
+ break;
+ case FW_FAIL_RESET:
+ case FW_FAIL_TRANS:
+ ERR("status reply %s (%d)\n", load_status2str(status), status);
+ if(verbose >= LOG_INFO)
+ dump_packet(buf, ret);
+ return -EPROTO;
+ default:
+ ERR("Unknown status reply %d\n", status);
+ if(verbose >= LOG_INFO)
+ dump_packet(buf, ret);
+ return -EPROTO;
+ }
+ return 0;
+}
+
+int my_usb_device(struct usb_device *dev, usb_dev_handle *handle)
+{
+ struct usb_device_descriptor *dev_desc;
+ struct usb_config_descriptor *config_desc;
+ struct usb_interface *interface;
+ struct usb_interface_descriptor *iface_desc;
+ struct usb_endpoint_descriptor *endpoint;
+ char iManufacturer[BUFSIZ];
+ char iProduct[BUFSIZ];
+ int ret;
+ int i;
+
+ assert(dev != NULL);
+ dev_desc = &dev->descriptor;
+ config_desc = dev->config;
+ interface = config_desc->interface;
+ iface_desc = interface->altsetting;
+ if(verbose >= LOG_INFO)
+ INFO("Vendor:Product=%04X:%04X Class=%d (endpoints=%d)\n",
+ dev_desc->idVendor, dev_desc->idProduct, dev_desc->bDeviceClass, iface_desc->bNumEndpoints);
+ if(iface_desc->bInterfaceClass != 0xFF) {
+ ERR("Wrong Interface class %d\n", iface_desc->bInterfaceClass);
+ return -EINVAL;
+ }
+ if(iface_desc->bInterfaceNumber != MY_INTERFACE) {
+ ERR("Wrong Interface number %d\n", iface_desc->bInterfaceNumber);
+ return -EINVAL;
+ }
+ if(iface_desc->bNumEndpoints != MY_ENDPOINTS) {
+ ERR("Wrong number of endpoints: %d\n", iface_desc->bNumEndpoints);
+ return -EINVAL;
+ }
+ endpoint = iface_desc->endpoint;
+ for(i = 0; i < iface_desc->bNumEndpoints; i++, endpoint++) {
+ if(endpoint->bEndpointAddress != my_endpoints[i]) {
+ ERR("Wrong endpoint %d: address = 0x%X\n", i, endpoint->bEndpointAddress);
+ return -EINVAL;
+ }
+ if(endpoint->bEndpointAddress == MY_EP_OUT || endpoint->bEndpointAddress == MY_EP_IN) {
+ if(endpoint->wMaxPacketSize > PACKET_SIZE) {
+ ERR("Endpoint #%d wMaxPacketSize too large (%d)\n", i, endpoint->wMaxPacketSize);
+ return -EINVAL;
+ }
+ }
+ }
+ if(usb_reset(handle) != 0) {
+ ERR("Reseting device: usb: %s\n", usb_strerror());
+ }
+ if(usb_set_configuration(handle, MY_CONFIG) != 0) {
+ ERR("usb: %s\n", usb_strerror());
+ return -EINVAL;
+ }
+ if(usb_claim_interface(handle, MY_INTERFACE) != 0) {
+ ERR("usb: %s\n", usb_strerror());
+ return -EINVAL;
+ }
+ if(usb_resetep(handle, MY_EP_OUT) != 0) {
+ ERR("usb: %s\n", usb_strerror());
+ return -EINVAL;
+ }
+ if(usb_resetep(handle, MY_EP_IN) != 0) {
+ ERR("usb: %s\n", usb_strerror());
+ return -EINVAL;
+ }
+ ret = get_usb_string(iManufacturer, BUFSIZ, dev_desc->iManufacturer, handle);
+ ret = get_usb_string(iProduct, BUFSIZ, dev_desc->iProduct, handle);
+ if(verbose >= LOG_INFO)
+ INFO("iManufacturer=%s iProduct=%s\n", iManufacturer, iProduct);
+ return 0;
+}
+
+int renumerate_device(struct usb_dev_handle *handle)
+{
+ char buf[PACKET_SIZE];
+ struct fpga_packet_header *phead = (struct fpga_packet_header *)buf;
+ int ret;
+
+ assert(handle != NULL);
+ if(verbose >= LOG_INFO)
+ INFO("Renumerating\n");
+ phead->header.op = RENUMERATE;
+ ret = usb_bulk_write(handle, MY_EP_OUT, (char *)phead, 1, TIMEOUT);
+ if(ret < 0) {
+ ERR("usb: bulk_write failed (%d)\n", ret);
+ return ret;
+ } else if(ret != 1) {
+ ERR("usb: bulk_write short write (%d)\n", ret);
+ return -EFAULT;
+ }
+ return 0;
+}
+
+int fpga_load(struct usb_dev_handle *handle, const struct hexdata *hexdata)
+{
+ unsigned int i;
+ int ret;
+ int finished = 0;
+
+ assert(handle != NULL);
+ if(verbose >= LOG_INFO)
+ INFO("Start...\n");
+ for(i = 0; i < hexdata->maxlines; i++) {
+ struct hexline *hexline = hexdata->lines[i];
+
+ if(!hexline)
+ break;
+ if(finished) {
+ ERR("Extra data after End Of Data Record (line %d)\n", i);
+ return 0;
+ }
+ if(hexline->d.content.header.tt == TT_EOF) {
+ INFO("End of data\n");
+ finished = 1;
+ continue;
+ }
+ if((ret = send_hexline(handle, hexline, i)) != 0) {
+ perror("Failed sending hexline");
+ return 0;
+ }
+ }
+ if(verbose >= LOG_INFO)
+ INFO("Finished...\n");
+ return 1;
+}
+
+#include <getopt.h>
+
+void usage()
+{
+ fprintf(stderr, "Usage: %s -D /proc/bus/usb/<bus>/<dev> [options...]\n", progname);
+ fprintf(stderr, "\tOptions:\n");
+ fprintf(stderr, "\t\t[-b <binfile>] # output to <binfile>\n");
+ fprintf(stderr, "\t\t[-d] # Get device version from eeprom\n");
+ fprintf(stderr, "\t\t[-I <hexfile>] # Input from <hexfile>\n");
+ fprintf(stderr, "\t\t[-g] # Get eeprom from device\n");
+ fprintf(stderr, "\t\t[-V vendorid] # Set Vendor id on device\n");
+ fprintf(stderr, "\t\t[-P productid] # Set Product id on device\n");
+ fprintf(stderr, "\t\t[-R release] # Set Release. 2 dot separated decimals\n");
+ fprintf(stderr, "\t\t[-S serial] # Set Serial. 8 comma separated numbers\n");
+ exit(1);
+}
+
+static void parse_report_func(int level, const char *msg, ...)
+{
+ va_list ap;
+
+ va_start(ap, msg);
+ if(level <= verbose)
+ vfprintf(stderr, msg, ap);
+ va_end(ap);
+}
+
+
+int main(int argc, char *argv[])
+{
+ struct usb_device *dev;
+ usb_dev_handle *handle;
+ const char *devpath = NULL;
+ const char *binfile = NULL;
+ const char *hexfile = NULL;
+ struct hexdata *hexdata = NULL;
+ struct myeeprom eeprom_buf;
+ int opt_read_eeprom = 0;
+ int opt_print_bcdver_only = 0;
+#ifdef XORCOM_INTERNAL
+ int opt_write_eeprom = 0;
+ char *vendor = NULL;
+ char *product = NULL;
+ char *release = NULL;
+ char *serial = NULL;
+ uint8_t serial_buf[SERIAL_SIZE];
+ const char options[] = "b:dD:ghI:vV:P:R:S:";
+#else
+ const char options[] = "b:dD:ghI:v";
+#endif
+ int ret = 0;
+
+ progname = argv[0];
+ assert(sizeof(struct fpga_packet_header) <= PACKET_SIZE);
+ assert(sizeof(struct myeeprom) == EEPROM_SIZE);
+ while (1) {
+ int c;
+
+ c = getopt (argc, argv, options);
+ if (c == -1)
+ break;
+
+ switch (c) {
+ case 'D':
+ devpath = optarg;
+ break;
+ case 'b':
+ binfile = optarg;
+ break;
+ case 'd':
+ opt_print_bcdver_only = 1;
+ opt_read_eeprom = 1;
+ break;
+ case 'g':
+ opt_read_eeprom = 1;
+ break;
+ case 'I':
+ hexfile = optarg;
+ break;
+#ifdef XORCOM_INTERNAL
+ case 'V':
+ vendor = optarg;
+ break;
+ case 'P':
+ product = optarg;
+ break;
+ case 'R':
+ release = optarg;
+ break;
+ case 'S':
+ serial = optarg;
+ {
+ int i;
+ char *p;
+ unsigned long val;
+
+ p = strtok(serial, ",");
+ for(i = 0; i < SERIAL_SIZE && p; i++) {
+ val = strtoul(p, NULL, 0);
+ if(val > 0xFF) {
+ ERR("Value #%d for -S option is too large (%lu)\n", i+1, val);
+ usage();
+ }
+ serial_buf[i] = val;
+ p = strtok(NULL, ",");
+ }
+ if(i < SERIAL_SIZE) {
+ ERR("got only %d values for -S option. Need %d\n", i, SERIAL_SIZE);
+ usage();
+ }
+ }
+
+ break;
+#endif
+ case 'v':
+ verbose++;
+ break;
+ case 'h':
+ default:
+ ERR("Unknown option '%c'\n", c);
+ usage();
+ }
+ }
+
+ if (optind != argc) {
+ usage();
+ }
+ if(hexfile) {
+ parse_hexfile_set_reporting(parse_report_func);
+ hexdata = parse_hexfile(hexfile, MAX_HEX_LINES);
+ if(!hexdata) {
+ ERR("Bailing out\n");
+ exit(1);
+ }
+ if(binfile) {
+ dump_binary(hexdata, binfile);
+ return 0;
+ }
+ }
+ if(!devpath) {
+ ERR("Missing device path\n");
+ usage();
+ }
+ if(verbose)
+ INFO("Startup %s\n", devpath);
+
+ usb_init();
+ usb_find_busses();
+ usb_find_devices();
+ dev = dev_of_path(devpath);
+ if(!dev) {
+ ERR("Bailing out\n");
+ exit(1);
+ }
+ handle = usb_open(dev);
+ if(!handle) {
+ ERR("Failed to open usb device '%s/%s': %s\n", dev->bus->dirname, dev->filename, usb_strerror());
+ return -ENODEV;
+ }
+ if(my_usb_device(dev, handle)) {
+ ERR("Foreign usb device '%s/%s'\n", dev->bus->dirname, dev->filename);
+ ret = -ENODEV;
+ goto dev_err;
+ }
+ if(hexdata) {
+ if(!fpga_load(handle, hexdata)) {
+ ERR("FPGA loading failed\n");
+ ret = -ENODEV;
+ goto dev_err;
+ }
+ ret = renumerate_device(handle);
+ if(ret < 0) {
+ ERR("Renumeration failed: errno=%d\n", ret);
+ goto dev_err;
+ }
+ }
+#ifdef XORCOM_INTERNAL
+ if(vendor || product || release || serial)
+ opt_read_eeprom = opt_write_eeprom = 1;
+#endif
+ if(opt_read_eeprom) {
+ ret = eeprom_get(handle, &eeprom_buf);
+ if(ret < 0) {
+ ERR("Failed reading eeprom: %d\n", ret);
+ goto dev_err;
+ }
+ if (opt_print_bcdver_only)
+ print_bcd_ver(&eeprom_buf);
+ else
+ dump_eeprom(&eeprom_buf);
+ }
+#ifdef XORCOM_INTERNAL
+ if(opt_write_eeprom) {
+ // FF: address source is from device. C0: from eeprom
+ eeprom_buf.source = 0xC0;
+ if(vendor)
+ eeprom_buf.vendor = strtoul(vendor, NULL, 0);
+ if(product)
+ eeprom_buf.product = strtoul(product, NULL, 0);
+ if(release) {
+ int release_major = 0;
+ int release_minor = 0;
+
+ sscanf(release, "%d.%d", &release_major, &release_minor);
+ eeprom_buf.release_major = release_major;
+ eeprom_buf.release_minor = release_minor;
+ }
+ if(serial) {
+ memcpy(eeprom_buf.serial, serial_buf, SERIAL_SIZE);
+ }
+ dump_eeprom(&eeprom_buf);
+ ret = eeprom_set(handle, &eeprom_buf);
+ if(ret < 0) {
+ ERR("Failed writing eeprom: %d\n", ret);
+ goto dev_err;
+ }
+ }
+#endif
+ if(verbose)
+ INFO("Exiting\n");
+dev_err:
+ usb_cleanup(handle);
+ return ret;
+}