diff options
author | Tzafrir Cohen <tzafrir.cohen@xorcom.com> | 2008-06-17 17:49:05 +0000 |
---|---|---|
committer | Tzafrir Cohen <tzafrir.cohen@xorcom.com> | 2008-06-17 17:49:05 +0000 |
commit | 53894e5aa1e733a0321a69bd1b12bd794586b4ab (patch) | |
tree | 3e0d4543ad58256dd39cae60ba6de5d7a91f46a6 /xpp/fpga_load.c | |
parent | 91d0a6d645e95755c4ae0f0a13919eeb213f6606 (diff) |
Move the xpp utilities to the tools side.
git-svn-id: http://svn.asterisk.org/svn/dahdi/tools/trunk@4374 a0bf4364-ded3-4de4-8d8a-66a801d63aff
Diffstat (limited to 'xpp/fpga_load.c')
-rw-r--r-- | xpp/fpga_load.c | 1007 |
1 files changed, 1007 insertions, 0 deletions
diff --git a/xpp/fpga_load.c b/xpp/fpga_load.c new file mode 100644 index 0000000..7102501 --- /dev/null +++ b/xpp/fpga_load.c @@ -0,0 +1,1007 @@ +#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" + +static const char rcsid[] = "$Id$"; + +#define ERR(fmt, arg...) do { \ + if(verbose >= LOG_ERR) \ + fprintf(stderr, "%s: ERROR (%d): " fmt, \ + progname, __LINE__, ## arg); \ + } while(0); +#define INFO(fmt, arg...) do { \ + if(verbose >= LOG_INFO) \ + fprintf(stderr, "%s: " fmt, \ + progname, ## arg); \ + } while(0); +#define DBG(fmt, arg...) do { \ + if(verbose >= LOG_DEBUG) \ + fprintf(stderr, "%s: DBG: " fmt, \ + progname, ## arg); \ + } while(0); + +static int verbose = LOG_WARNING; +static char *progname; +static int disconnected = 0; + +#define MAX_HEX_LINES 10000 +#define PACKET_SIZE 512 +#define EEPROM_SIZE 16 +#define LABEL_SIZE 8 +#define TIMEOUT 5000 + + +/* My device parameters */ +#define MY_EP_OUT 0x04 +#define MY_EP_IN 0x88 + +#define FPGA_EP_OUT 0x02 +#define FPGA_EP_IN 0x86 + +/* USB firmware types */ +#define USB_11xx 0 +#define USB_FIRMWARE_II 1 + +#define TYPE_ENTRY(t,ni,n,ne,out,in,...) \ + [t] = { \ + .type_code = (t), \ + .num_interfaces = (ni), \ + .my_interface_num = (n), \ + .num_endpoints = (ne), \ + .my_ep_in = (in), \ + .my_ep_out = (out), \ + .name = #t, \ + .endpoints = { __VA_ARGS__ }, \ + } + +static const struct astribank_type { + int type_code; + int num_interfaces; + int my_interface_num; + int num_endpoints; + int my_ep_out; + int my_ep_in; + char *name; + int endpoints[4]; /* for matching */ +} astribank_types[] = { + TYPE_ENTRY(USB_11xx, 1, 0, 4, MY_EP_OUT, MY_EP_IN, + FPGA_EP_OUT, + MY_EP_OUT, + FPGA_EP_IN, + MY_EP_IN), + TYPE_ENTRY(USB_FIRMWARE_II, 2, 1, 2, MY_EP_OUT, MY_EP_IN, + MY_EP_OUT, + MY_EP_IN), +}; +#undef TYPE_ENTRY + +enum fpga_load_packet_types { + PT_STATUS_REPLY = 0x01, + PT_DATA_PACKET = 0x01, +#ifdef XORCOM_INTERNAL + PT_EEPROM_SET = 0x04, +#endif + PT_EEPROM_GET = 0x08, + PT_RENUMERATE = 0x10, + PT_RESET = 0x20, + PT_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 label[LABEL_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 +}; + +struct my_usb_device { + struct usb_device *dev; + usb_dev_handle *handle; + int my_interface_num; + int my_ep_out; + int my_ep_in; + char iManufacturer[BUFSIZ]; + char iProduct[BUFSIZ]; + char iSerialNumber[BUFSIZ]; + char iInterface[BUFSIZ]; + int is_usb2; + struct myeeprom eeprom; + const struct astribank_type *abtype; +}; + +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"; + } +} + +/* return 1 if: + * - str has a number + * - It is larger than 0 + * - It equals num + */ +int num_matches(int num, const char* str) { + int str_val = atoi(str); + if (str_val <= 0) + return 0; + return (str_val == num); +} + +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 *p; + int bnum; + int dnum; + int ret; + + assert(path != NULL); + if(access(path, F_OK) < 0) { + perror(path); + return NULL; + } + /* Find last '/' */ + if((p = memrchr(path, '/', strlen(path))) == NULL) { + ERR("Missing a '/' in %s\n", path); + return NULL; + } + /* Get the device number */ + ret = sscanf(p + 1, "%d", &dnum); + if(ret != 1) { + ERR("Path tail is not a device number: '%s'\n", p); + return NULL; + } + /* Search for a '/' before that */ + p = memrchr(path, '/', p - path); + if(p == NULL) + p = path; /* Relative path */ + else + p++; /* skip '/' */ + /* Get the bus number */ + ret = sscanf(p, "%d", &bnum); + if(ret != 1) { + ERR("Path tail is not a bus number: '%s'\n", p); + return NULL; + } + sprintf(dirname, "%03d", bnum); + sprintf(filename, "%03d", dnum); + for (bus = usb_busses; bus; bus = bus->next) { + if (! num_matches(bnum, bus->dirname)) + //if(strcmp(bus->dirname, dirname) != 0) + continue; + for (dev = bus->devices; dev; dev = dev->next) { + //if(strcmp(dev->filename, filename) == 0) + if (num_matches(dnum, dev->filename)) + 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); +} + +void my_usb_device_cleanup(struct my_usb_device *mydev) +{ + assert(mydev != NULL); + if(!mydev->handle) { + return; /* Nothing to do */ + } + if(!disconnected) { + if(usb_release_interface(mydev->handle, mydev->abtype->my_interface_num) != 0) { + ERR("Releasing interface: usb: %s\n", usb_strerror()); + } + } + if(usb_close(mydev->handle) != 0) { + ERR("Closing device: usb: %s\n", usb_strerror()); + } + disconnected = 1; + mydev->handle = NULL; +} + +static void show_device_info(const struct my_usb_device *mydev) +{ + const struct myeeprom *eeprom; + uint8_t data[LABEL_SIZE + 1]; + + assert(mydev != NULL); + eeprom = &mydev->eeprom; + memset(data, 0, LABEL_SIZE + 1); + memcpy(data, eeprom->label, LABEL_SIZE); + printf("USB Firmware Type: [%s]\n", mydev->abtype->name); + printf("USB iManufacturer: [%s]\n", mydev->iManufacturer); + printf("USB iProduct: [%s]\n", mydev->iProduct); + printf("USB iSerialNumber: [%s]\n", mydev->iSerialNumber); + printf("EEPROM Source: 0x%02X\n", eeprom->source); + printf("EEPROM Vendor: 0x%04X\n", eeprom->vendor); + printf("EEPROM Product: 0x%04X\n", eeprom->product); + printf("EEPROM Release: %d.%03d\n", eeprom->release_major, eeprom->release_minor); + printf("EEPROM Label: HEX(%02X,%02X,%02X,%02X,%02X,%02X,%02X,%02X) [%s]\n", + data[0], data[1], data[2], data[3], + data[4], data[5], data[6], data[7], data); +} + +void dump_packet(const char *msg, const char *buf, int len) +{ + int i; + + for(i = 0; i < len; i++) + INFO("%s: %2d> 0x%02X\n", msg, i, (uint8_t)buf[i]); +} + +int send_usb(const char *msg, struct my_usb_device *mydev, struct fpga_packet_header *phead, int len, int timeout) +{ + char *p = (char *)phead; + int ret; + + if(verbose >= LOG_DEBUG) + dump_packet(msg, p, len); + if(mydev->my_ep_out & USB_ENDPOINT_IN) { + ERR("send_usb called with an input endpoint 0x%x\n", mydev->my_ep_out); + return -EINVAL; + } + ret = usb_bulk_write(mydev->handle, mydev->my_ep_out, p, len, timeout); + if(ret < 0) { + /* + * If the device was gone, it may be the + * result of renumeration. Ignore it. + */ + if(ret != -ENODEV) { + ERR("bulk_write to endpoint 0x%x failed: %s\n", mydev->my_ep_out, usb_strerror()); + dump_packet("send_usb[ERR]", p, len); + } else { + disconnected = 1; + my_usb_device_cleanup(mydev); + } + return ret; + } else if(ret != len) { + ERR("bulk_write to endpoint 0x%x short write: %s\n", mydev->my_ep_out, usb_strerror()); + dump_packet("send_usb[ERR]", p, len); + return -EFAULT; + } + return ret; +} + +int recv_usb(const char *msg, struct my_usb_device *mydev, char *buf, size_t len, int timeout) +{ + int ret; + + if(mydev->my_ep_in & USB_ENDPOINT_OUT) { + ERR("recv_usb called with an output endpoint 0x%x\n", mydev->my_ep_in); + return -EINVAL; + } + ret = usb_bulk_read(mydev->handle, mydev->my_ep_in, buf, len, timeout); + if(ret < 0) { + ERR("bulk_read from endpoint 0x%x failed: %s\n", mydev->my_ep_in, usb_strerror()); + return ret; + } + if(verbose >= LOG_DEBUG) + dump_packet(msg, buf, ret); + return ret; +} + +#ifdef XORCOM_INTERNAL +int eeprom_set(struct my_usb_device *mydev, const struct myeeprom *eeprom) +{ + int ret; + int len; + char buf[PACKET_SIZE]; + struct fpga_packet_header *phead = (struct fpga_packet_header *)buf; + + DBG("%s Start...\n", __FUNCTION__); + assert(mydev != NULL); + phead->header.op = PT_EEPROM_SET; + memcpy(&phead->d.eeprom_set.data, eeprom, EEPROM_SIZE); + len = sizeof(phead->d.eeprom_set) + sizeof(phead->header.op); + ret = send_usb("eeprom_set[W]", mydev, phead, len, TIMEOUT); + if(ret < 0) + return ret; + ret = recv_usb("eeprom_set[R]", mydev, buf, sizeof(buf), TIMEOUT); + if(ret <= 0) + return ret; + phead = (struct fpga_packet_header *)buf; + if(phead->header.op == PT_BAD_COMMAND) { + ERR("Firmware rejected PT_EEPROM_SET command\n"); + return -EINVAL; + } else if(phead->header.op != PT_EEPROM_SET) { + ERR("Got unexpected reply op=%d\n", phead->header.op); + return -EINVAL; + } + return 0; +} +#endif + +int eeprom_get(struct my_usb_device *mydev) +{ + int ret; + int len; + char buf[PACKET_SIZE]; + struct fpga_packet_header *phead = (struct fpga_packet_header *)buf; + struct myeeprom *eeprom; + + assert(mydev != NULL); + eeprom = &mydev->eeprom; + DBG("%s Start...\n", __FUNCTION__); + phead->header.op = PT_EEPROM_GET; + len = sizeof(phead->header.op); /* warning: sending small packet */ + ret = send_usb("eeprom_get[W]", mydev, phead, len, TIMEOUT); + if(ret < 0) + return ret; + ret = recv_usb("eeprom_get[R]", mydev, buf, sizeof(buf), TIMEOUT); + if(ret <= 0) + return ret; + phead = (struct fpga_packet_header *)buf; + if(phead->header.op == PT_BAD_COMMAND) { + ERR("PT_BAD_COMMAND\n"); + return -EINVAL; + } else if(phead->header.op != PT_EEPROM_GET) { + ERR("Got unexpected reply op=%d\n", phead->header.op); + return -EINVAL; + } + memcpy(eeprom, &phead->d.eeprom_get.data, EEPROM_SIZE); + return 0; +} + +int send_hexline(struct my_usb_device *mydev, 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(mydev != NULL); + assert(hexline != NULL); + if(hexline->d.content.header.tt != TT_DATA) { + DBG("Non data record %d type = %d\n", seq, hexline->d.content.header.tt); + return 0; + } + len = hexline->d.content.header.ll; /* don't send checksum */ + data = hexline->d.content.tt_data.data; + phead->header.op = PT_DATA_PACKET; + phead->d.data_packet.seq = seq; + phead->d.data_packet.reserved = 0x00; + memcpy(phead->d.data_packet.data, data, len); + len += sizeof(hexline->d.content.header); + DBG("%04d+\r", seq); + ret = send_usb("hexline[W]", mydev, phead, len, TIMEOUT); + if(ret < 0) + return ret; + ret = recv_usb("hexline[R]", mydev, buf, sizeof(buf), TIMEOUT); + if(ret <= 0) + return ret; + DBG("%04d-\r", seq); + phead = (struct fpga_packet_header *)buf; + if(phead->header.op != PT_STATUS_REPLY) { + ERR("Got unexpected reply op=%d\n", phead->header.op); + dump_packet("hexline[ERR]", buf, ret); + 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); + dump_packet("hexline[ERR]", buf, ret); + return -EPROTO; + default: + ERR("Unknown status reply %d\n", status); + dump_packet("hexline[ERR]", buf, ret); + return -EPROTO; + } + return 0; +} + +//. returns > 0 - ok, the number of lines sent +//. returns < 0 - error number +int send_splited_hexline(struct my_usb_device *mydev, struct hexline *hexline, int seq, uint8_t maxwidth) +{ + struct hexline *extraline; + int linessent = 0; + int allocsize; + int extra_offset = 0; + unsigned int this_line = 0; + uint8_t bytesleft = 0; + + assert(mydev != NULL); + if(!hexline) { + ERR("Bad record %d type = %d\n", seq, hexline->d.content.header.tt); + return -EINVAL; + } + bytesleft = hexline->d.content.header.ll; + // split the line into several lines + while (bytesleft > 0) { + int status; + this_line = (bytesleft >= maxwidth) ? maxwidth : bytesleft; + allocsize = sizeof(struct hexline) + this_line + 1; + // generate the new line + if((extraline = (struct hexline *)malloc(allocsize)) == NULL) { + ERR("Not enough memory for spliting the lines\n" ); + return -EINVAL; + } + memset(extraline, 0, allocsize); + extraline->d.content.header.ll = this_line; + extraline->d.content.header.offset = hexline->d.content.header.offset + extra_offset; + extraline->d.content.header.tt = hexline->d.content.header.tt; + memcpy( extraline->d.content.tt_data.data, hexline->d.content.tt_data.data+extra_offset, this_line); + status = send_hexline(mydev, extraline, seq+linessent ); + // cleanups + free(extraline); + extra_offset += this_line; + bytesleft -= this_line; + if (status) + return status; + linessent++; + } + return linessent; +} + +int match_usb_device_identity(const struct usb_config_descriptor *config_desc, + const struct astribank_type *ab) +{ + struct usb_interface *interface; + struct usb_interface_descriptor *iface_desc; + + if(config_desc->bNumInterfaces <= ab->my_interface_num) + return 0; + interface = &config_desc->interface[ab->my_interface_num]; + iface_desc = interface->altsetting; + + return iface_desc->bInterfaceClass == 0xFF && + iface_desc->bInterfaceNumber == ab->my_interface_num && + iface_desc->bNumEndpoints == ab->num_endpoints; +} + +const struct astribank_type *my_usb_device_identify(const char devpath[], struct my_usb_device *mydev) +{ + struct usb_device_descriptor *dev_desc; + struct usb_config_descriptor *config_desc; + int i; + + assert(mydev != NULL); + usb_init(); + usb_find_busses(); + usb_find_devices(); + mydev->dev = dev_of_path(devpath); + if(!mydev->dev) { + ERR("Bailing out\n"); + return 0; + } + dev_desc = &mydev->dev->descriptor; + config_desc = mydev->dev->config; + for(i = 0; i < sizeof(astribank_types)/sizeof(astribank_types[0]); i++) { + if(match_usb_device_identity(config_desc, &astribank_types[i])) { + DBG("Identified[%d]: interfaces=%d endpoints=%d: \"%s\"\n", + i, + astribank_types[i].num_interfaces, + astribank_types[i].num_endpoints, + astribank_types[i].name); + return &astribank_types[i]; + } + } + return NULL; +} + +int my_usb_device_init(const char devpath[], struct my_usb_device *mydev, const struct astribank_type *abtype) +{ + 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; + int ret; + int i; + + assert(mydev != NULL); + usb_init(); + usb_find_busses(); + usb_find_devices(); + mydev->dev = dev_of_path(devpath); + if(!mydev->dev) { + ERR("Bailing out\n"); + return 0; + } + mydev->handle = usb_open(mydev->dev); + if(!mydev->handle) { + ERR("Failed to open usb device '%s/%s': %s\n", mydev->dev->bus->dirname, mydev->dev->filename, usb_strerror()); + return 0; + } + if(usb_claim_interface(mydev->handle, abtype->my_interface_num) != 0) { + ERR("usb_claim_interface: %s\n", usb_strerror()); + return 0; + } + dev_desc = &mydev->dev->descriptor; + config_desc = mydev->dev->config; + if (!config_desc) { + ERR("usb interface without a configuration\n"); + return 0; + } + interface = &config_desc->interface[abtype->my_interface_num]; + iface_desc = interface->altsetting; + endpoint = iface_desc->endpoint; + mydev->is_usb2 = (endpoint->wMaxPacketSize == 512); + for(i = 0; i < iface_desc->bNumEndpoints; i++, endpoint++) { + if(endpoint->bEndpointAddress != abtype->endpoints[i]) { + ERR("Wrong endpoint 0x%X (at index %d)\n", endpoint->bEndpointAddress, i); + return 0; + } + 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 0; + } + } + } + mydev->abtype = abtype; + mydev->my_ep_in = abtype->my_ep_in; + mydev->my_ep_out = abtype->my_ep_out; + ret = get_usb_string(mydev->iManufacturer, BUFSIZ, dev_desc->iManufacturer, mydev->handle); + ret = get_usb_string(mydev->iProduct, BUFSIZ, dev_desc->iProduct, mydev->handle); + ret = get_usb_string(mydev->iSerialNumber, BUFSIZ, dev_desc->iSerialNumber, mydev->handle); + ret = get_usb_string(mydev->iInterface, BUFSIZ, iface_desc->iInterface, mydev->handle); + INFO("ID=%04X:%04X Manufacturer=[%s] Product=[%s] SerialNumber=[%s] Interface=[%s]\n", + dev_desc->idVendor, + dev_desc->idProduct, + mydev->iManufacturer, + mydev->iProduct, + mydev->iSerialNumber, + mydev->iInterface); + if(usb_clear_halt(mydev->handle, mydev->my_ep_out) != 0) { + ERR("Clearing output endpoint: %s\n", usb_strerror()); + return 0; + } + if(usb_clear_halt(mydev->handle, mydev->my_ep_in) != 0) { + ERR("Clearing input endpoint: %s\n", usb_strerror()); + return 0; + } + return 1; +} + +int renumerate_device(struct my_usb_device *mydev, enum fpga_load_packet_types pt) +{ + char buf[PACKET_SIZE]; + struct fpga_packet_header *phead = (struct fpga_packet_header *)buf; + int ret; + + assert(mydev != NULL); + DBG("Renumerating with 0x%X\n", pt); + phead->header.op = pt; + ret = send_usb("renumerate[W]", mydev, phead, 1, TIMEOUT); + if(ret < 0 && ret != -ENODEV) + return ret; +#if 0 + /* + * FIXME: we count on our USB firmware to reset the device... should we? + */ + ret = usb_reset(mydev->handle); + if(ret < 0) { + ERR("usb_reset: %s\n", usb_strerror()); + return -ENODEV; + } +#endif + return 0; +} + +/* + * Returns: true on success, false on failure + */ +int fpga_load(struct my_usb_device *mydev, const struct hexdata *hexdata) +{ + unsigned int i; + unsigned int j = 0; + int ret; + int finished = 0; + const char *v = hexdata->version_info; + + v = (v[0]) ? v : "Unknown"; + assert(mydev != NULL); + INFO("FPGA_LOAD (version %s)\n", v); + /* + * i - is the line number + * j - is the sequence number, on USB 2, i=j, but on + * USB 1 send_splited_hexline may increase the sequence + * number, as it needs + */ + 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) { + DBG("End of data\n"); + finished = 1; + continue; + } + if(mydev->is_usb2) { + if((ret = send_hexline(mydev, hexline, i)) != 0) { + perror("Failed sending hexline"); + return 0; + } + } else { + if((ret = send_splited_hexline(mydev, hexline, j, 60)) < 0) { + perror("Failed sending hexline (splitting did not help)"); + return 0; + } + j += ret; + } + } + DBG("Finished...\n"); + return 1; +} + +#include <getopt.h> + +void usage() +{ + fprintf(stderr, "Usage: %s -D {/proc/bus/usb|/dev/bus/usb}/<bus>/<dev> [options...]\n", progname); + fprintf(stderr, "\tOptions:\n"); + fprintf(stderr, "\t\t[-r] # Reset the device\n"); + fprintf(stderr, "\t\t[-b <binfile>] # Output to <binfile>\n"); + fprintf(stderr, "\t\t[-I <hexfile>] # Input from <hexfile>\n"); + fprintf(stderr, "\t\t[-H <hexfile>] # Output to <hexfile> ('-' is stdout)\n"); + fprintf(stderr, "\t\t[-i] # Show hexfile information\n"); + fprintf(stderr, "\t\t[-g] # Get eeprom from device\n"); + fprintf(stderr, "\t\t[-v] # Increase verbosity\n"); +#ifdef XORCOM_INTERNAL + fprintf(stderr, "\t\t[-C srC byte] # Set Address sourCe (default: C0)\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[-L label] # Set label.\n"); +#endif + 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); +} + +#ifdef XORCOM_INTERNAL +static void eeprom_fill(struct myeeprom *myeeprom, + const char vendor[], + const char product[], + const char release[], + const char label[], + const char source[]) +{ + // FF: address source is from device. C0: from eeprom + if (source) + myeeprom->source = strtoul(source, NULL, 0); + else + myeeprom->source = 0xC0; + if(vendor) + myeeprom->vendor = strtoul(vendor, NULL, 0); + if(product) + myeeprom->product = strtoul(product, NULL, 0); + if(release) { + int release_major = 0; + int release_minor = 0; + + sscanf(release, "%d.%d", &release_major, &release_minor); + myeeprom->release_major = release_major; + myeeprom->release_minor = release_minor; + } + if(label) { + /* padding */ + memset(myeeprom->label, 0, LABEL_SIZE); + memcpy(myeeprom->label, label, strlen(label)); + } +} +#endif + +int main(int argc, char *argv[]) +{ + const struct astribank_type *abtype; + struct my_usb_device mydev; + const char *devpath = NULL; + const char *binfile = NULL; + const char *inhexfile = NULL; + const char *outhexfile = NULL; + struct hexdata *hexdata = NULL; + int opt_reset = 0; + int opt_info = 0; + int opt_read_eeprom = 0; + int opt_output_width = 0; + int output_is_set = 0; +#ifdef XORCOM_INTERNAL + int opt_write_eeprom = 0; + char *vendor = NULL; + char *source = NULL; + char *product = NULL; + char *release = NULL; + char *label = NULL; + const char options[] = "rib:D:ghH:I:vw:C:V:P:R:S:"; +#else + const char options[] = "rib:D:ghH:I:vw:"; +#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; + if(output_is_set++) { + ERR("Cannot set -D. Another output option is already selected\n"); + return 1; + } + break; + case 'r': + opt_reset = 1; + break; + case 'i': + opt_info = 1; + break; + case 'b': + binfile = optarg; + if(output_is_set++) { + ERR("Cannot set -b. Another output option is already selected\n"); + return 1; + } + break; + case 'g': + opt_read_eeprom = 1; + break; + case 'H': + outhexfile = optarg; + if(output_is_set++) { + ERR("Cannot set -H. Another output option is already selected\n"); + return 1; + } + break; + case 'I': + inhexfile = optarg; + break; +#ifdef XORCOM_INTERNAL + case 'V': + vendor = optarg; + break; + case 'C': + source = optarg; + break; + case 'P': + product = optarg; + break; + case 'R': + release = optarg; + break; + case 'S': + label = optarg; + { + const char GOOD_CHARS[] = + "abcdefghijklmnopqrstuvwxyz" + "ABCDEFGHIJKLMNOPQRSTUVWXYZ" + "0123456789" + "-_."; + int len = strlen(label); + int goodlen = strspn(label, GOOD_CHARS); + + if(len > LABEL_SIZE) { + ERR("Label too long (%d > %d)\n", len, LABEL_SIZE); + usage(); + } + if(goodlen != len) { + ERR("Bad character in label number (pos=%d)\n", goodlen); + usage(); + } + } + break; +#endif + case 'w': + opt_output_width = strtoul(optarg, NULL, 0); + break; + case 'v': + verbose++; + break; + case 'h': + default: + ERR("Unknown option '%c'\n", c); + usage(); + } + } + + if (optind != argc) { + usage(); + } + if(inhexfile) { +#ifdef XORCOM_INTERNAL + if(vendor || product || release || label || source ) { + ERR("The -I option is exclusive of -[VPRSC]\n"); + return 1; + } +#endif + parse_hexfile_set_reporting(parse_report_func); + hexdata = parse_hexfile(inhexfile, MAX_HEX_LINES); + if(!hexdata) { + ERR("Bailing out\n"); + exit(1); + } + if(opt_info) { + printf("%s: Version=%s Checksum=%d\n", + inhexfile, hexdata->version_info, + bsd_checksum(hexdata)); + } + if(binfile) { + dump_binary(hexdata, binfile); + return 0; + } + if(outhexfile) { + if(opt_output_width) + dump_hexfile2(hexdata, outhexfile, opt_output_width); + else + dump_hexfile(hexdata, outhexfile); + return 0; + } + } +#ifdef XORCOM_INTERNAL + else if(vendor || product || release || label || source ) { + if(outhexfile) { + FILE *fp; + + if(strcmp(outhexfile, "-") == 0) + fp = stdout; + else if((fp = fopen(outhexfile, "w")) == NULL) { + perror(outhexfile); + return 1; + } + memset(&mydev.eeprom, 0, sizeof(struct myeeprom)); + eeprom_fill(&mydev.eeprom, vendor, product, release, label, source); + gen_hexline((uint8_t *)&mydev.eeprom, 0, sizeof(mydev.eeprom), fp); + gen_hexline(NULL, 0, 0, fp); /* EOF */ + return 0; + } + } +#endif + if(!devpath) { + ERR("Missing device path\n"); + usage(); + } + DBG("Startup %s\n", devpath); + if((abtype = my_usb_device_identify(devpath, &mydev)) == NULL) { + ERR("Bad device. Does not match our types.\n"); + usage(); + } + INFO("FIRMWARE: %s (type=%d)\n", abtype->name, abtype->type_code); + if(!my_usb_device_init(devpath, &mydev, abtype)) { + ERR("Failed to initialize USB device '%s'\n", devpath); + ret = -ENODEV; + goto dev_err; + } + ret = eeprom_get(&mydev); + if(ret < 0) { + ERR("Failed reading eeprom\n"); + goto dev_err; + } +#ifdef XORCOM_INTERNAL + if(vendor || product || release || label || source ) { + eeprom_fill(&mydev.eeprom, vendor, product, release, label, source); + opt_write_eeprom = 1; + opt_read_eeprom = 1; + } +#endif + if(opt_read_eeprom) { + show_device_info(&mydev); + } + if(hexdata) { + if (!mydev.is_usb2) + INFO("Warning: working on a low end USB1 backend\n"); + if(!fpga_load(&mydev, hexdata)) { + ERR("FPGA loading failed\n"); + ret = -ENODEV; + goto dev_err; + } + ret = renumerate_device(&mydev, PT_RENUMERATE); + if(ret < 0) { + ERR("Renumeration failed: errno=%d\n", ret); + goto dev_err; + } + } +#ifdef XORCOM_INTERNAL + else if(opt_write_eeprom) { + if(abtype->type_code == USB_FIRMWARE_II) { + ERR("No EEPROM burning command in %s. Use fxload for that\n", + abtype->name); + goto dev_err; + } + ret = eeprom_set(&mydev, &mydev.eeprom); + if(ret < 0) { + ERR("Failed writing eeprom: %s\n", strerror(-ret)); + goto dev_err; + } + printf("------- RESULTS -------\n"); + show_device_info(&mydev); + } +#endif + if(opt_reset) { + DBG("Reseting to default\n"); + ret = renumerate_device(&mydev, PT_RESET); + if(ret < 0) { + ERR("Renumeration to default failed: errno=%d\n", ret); + goto dev_err; + } + } + DBG("Exiting\n"); +dev_err: + my_usb_device_cleanup(&mydev); + return ret; +} |