diff options
Diffstat (limited to 'fpga/xilinx/programmer/dependencies/libxsvf/xsvftool-xpcu.src/fx2usb-interface.c')
| -rw-r--r-- | fpga/xilinx/programmer/dependencies/libxsvf/xsvftool-xpcu.src/fx2usb-interface.c | 212 |
1 files changed, 212 insertions, 0 deletions
diff --git a/fpga/xilinx/programmer/dependencies/libxsvf/xsvftool-xpcu.src/fx2usb-interface.c b/fpga/xilinx/programmer/dependencies/libxsvf/xsvftool-xpcu.src/fx2usb-interface.c new file mode 100644 index 0000000..f7523e1 --- /dev/null +++ b/fpga/xilinx/programmer/dependencies/libxsvf/xsvftool-xpcu.src/fx2usb-interface.c @@ -0,0 +1,212 @@ +/* + * xsvftool-xpcu - An (X)SVF player for the Xilinx Platform Cable USB + * + * Copyright (C) 2011 RIEGL Research ForschungsGmbH + * Copyright (C) 2011 Clifford Wolf <clifford@clifford.at> + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + */ + +#include <stdio.h> +#include <errno.h> +#include <string.h> +#include "fx2usb-interface.h" + +usb_dev_handle *fx2usb_open(int vendor_id, int device_id, char *dev) +{ + struct usb_bus *b; + struct usb_device *d; + char *dd = NULL; + int devlen; + + if (dev) { + devlen = strlen(dev); + dd = devlen > 8 ? &dev[devlen-8] : "|xxx|xxx"; + } + + for (b = usb_get_busses(); b; b = b->next) { + for (d = b->devices; d; d = d->next) { + if (dd) { + if (dd[0] == '/' && !strncmp(dd+1, b->dirname, 3) && + dd[4] == '/' && !strncmp(dd+5, d->filename, 3)) + return usb_open(d); + } else + if (vendor_id || device_id) { + if ((d->descriptor.idVendor == vendor_id) && (d->descriptor.idProduct == device_id)) + return usb_open(d); + } else { + // The Xilinx Platform Cable USB Vendor/Device IDs + if ((d->descriptor.idVendor == 0x03FD) && (d->descriptor.idProduct == 0x0009)) + return usb_open(d); + if ((d->descriptor.idVendor == 0x03FD) && (d->descriptor.idProduct == 0x000D)) + return usb_open(d); + if ((d->descriptor.idVendor == 0x03FD) && (d->descriptor.idProduct == 0x000F)) + return usb_open(d); + // The plain CY7C68013 dev kit Vendor/Device IDs + if ((d->descriptor.idVendor == 0x04b4) && (d->descriptor.idProduct == 0x8613)) + return usb_open(d); + } + } + } + + return NULL; +} + +static int fx2usb_fwload_ctrl_msg(usb_dev_handle *dh, int addr, const void *data, int len) +{ + int ret = usb_control_msg(dh, 0x40, 0xA0, addr, 0, (char*)data, len, 1000); + if (ret != len) + fprintf(stderr, "fx2usb_fwload_ctrl_msg: usb_control_msg for addr=0x%04X, len=%d returned %d: %s\n", addr, len, ret, ret >= 0 ? "NO ERROR" : usb_strerror()); + return ret == len ? 0 : -1; +} + +int fx2usb_upload_ihex(usb_dev_handle *dh, FILE *fp) +{ + uint8_t on = 1, off = 0; + + // assert reset + if (fx2usb_fwload_ctrl_msg(dh, 0xE600, &on, 1) < 0) { + fprintf(stderr, "fx2usb_upload_ihex: can't assert reset!\n"); + return -1; + } + + // parse and upload ihex file + char line[1024]; + int linecount = 0; + while (fgets(line, sizeof(line), fp) != NULL) + { + linecount++; + + if (line[0] != ':') + continue; + + uint8_t cksum = 0; + uint8_t ldata[512]; + int lsize = 0; + + while (sscanf(line+1+lsize*2, "%2hhx", &ldata[lsize]) == 1) { + cksum += ldata[lsize]; + lsize++; + } + + if (lsize < 5) { + fprintf(stderr, "fx2usb_upload_ihex: ihex line %d: record is to short!\n", linecount); + return -1; + } + + if (ldata[0] != lsize-5) { + fprintf(stderr, "fx2usb_upload_ihex: ihex line %d: size does not match record length!\n", linecount); + return -1; + } + + cksum -= ldata[lsize-1]; + cksum = ~cksum + 1; + + if (cksum != ldata[lsize-1]) { + fprintf(stderr, "fx2usb_upload_ihex: ihex line %d: cksum error!\n", linecount); + return -1; + } + + if (fx2usb_fwload_ctrl_msg(dh, (ldata[1] << 8) | ldata[2], &ldata[4], ldata[0]) < 0) { + fprintf(stderr, "fx2usb_upload_ihex: ihex line %d: error in fx2usb communication!\n", linecount); + return -1; + } + } + + // release reset + if (fx2usb_fwload_ctrl_msg(dh, 0xE600, &off, 1) < 0) { + fprintf(stderr, "fx2usb_upload_ihex: can't release reset!\n"); + return -1; + } + + return 0; +} + +int fx2usb_claim(usb_dev_handle *dh) +{ +#ifdef LIBUSB_HAS_DETACH_KERNEL_DRIVER_NP + usb_detach_kernel_driver_np(dh, 0); +#endif + if (usb_claim_interface(dh, 0) < 0) { + fprintf(stderr, "fx2usb_claim: claiming interface 0 failed: %s!\n", usb_strerror()); + return -1; + } + if (usb_set_altinterface(dh, 1) < 0) { + usb_release_interface(dh, 0); + fprintf(stderr, "fx2usb_claim: setting alternate interface 1 failed: %s!\n", usb_strerror()); + return -1; + } + return 0; +} + +void fx2usb_release(usb_dev_handle *dh) +{ + usb_release_interface(dh, 0); +} + +void fx2usb_flush(usb_dev_handle *dh) +{ + while (1) + { + unsigned char readbuf[2] = { 0, 0 }; + int ret = usb_bulk_read(dh, 1, (char*)readbuf, 2, 10); + if (ret <= 0) + return; + fprintf(stderr, "Unexpected data word from device: 0x%02x 0x%02x (%d)\n", readbuf[0], readbuf[1], ret); + } +} + +int fx2usb_send_chunk(usb_dev_handle *dh, int ep, const void *data, int len) +{ + int ret; +#if 0 + if (ep == 2) { + int i; + fprintf(stderr, "<ep2:%4d bytes> ...", len); + for (i = len-16; i < len; i++) { + if (i < 0) + continue; + fprintf(stderr, " %02x", ((unsigned char*)data)[i]); + } + fprintf(stderr, "\n"); + } +#endif +retry_write: + ret = usb_bulk_write(dh, ep, data, len, 1000); + if (ret == -ETIMEDOUT) { + fprintf(stderr, "fx2usb_recv_chunk: usb write timeout -> retry\n"); + fx2usb_flush(dh); + goto retry_write; + } + if (ret != len) + fprintf(stderr, "fx2usb_send_chunk: write of %d bytes to ep %d returned %d: %s\n", len, ep, ret, ret >= 0 ? "NO ERROR" : usb_strerror()); + return ret == len ? 0 : -1; +} + +int fx2usb_recv_chunk(usb_dev_handle *dh, int ep, void *data, int len, int *ret_len) +{ + int ret; +retry_read: + ret = usb_bulk_read(dh, ep, data, len, 1000); + if (ret == -ETIMEDOUT) { + fprintf(stderr, "fx2usb_recv_chunk: usb read timeout -> retry\n"); + goto retry_read; + } + if (ret > 0 && ret_len != NULL) + len = *ret_len = ret; + if (ret != len) + fprintf(stderr, "fx2usb_recv_chunk: read of %d bytes from ep %d returned %d: %s\n", len, ep, ret, ret >= 0 ? "NO ERROR" : usb_strerror()); + return ret == len ? 0 : -1; +} + |
