From 1c1fe1fd94fe1f43762aabda9e44da2359a3bdec Mon Sep 17 00:00:00 2001 From: Oron Peled Date: Thu, 10 Mar 2011 18:48:11 +0000 Subject: [PATCH] xpp: use 'xtalk' for the USB access code * Move most of the USB access code from xpp/ to xpp/xtalk/ . * astribank_tool and such tools can now use a shorter -D mmm/nnn rather than a full path. Signed-off-by: Oron Peled Acked-by: Tzafrir Cohen git-svn-id: http://svn.astersk.org/svn/dahdi/tools/trunk@9825 17933a7a-c749-41c5-a318-cba88f637d49 --- xpp/Makefile | 17 +- xpp/astribank_allow.8 | 10 +- xpp/astribank_allow.c | 6 +- xpp/astribank_hexload.8 | 10 +- xpp/astribank_hexload.c | 55 +- xpp/astribank_tool.8 | 10 +- xpp/astribank_tool.c | 10 +- xpp/astribank_usb.c | 415 ++---------- xpp/astribank_usb.h | 10 +- xpp/mpp.h | 211 +----- xpp/mpp_funcs.c | 1109 -------------------------------- xpp/mpptalk.c | 915 ++++++++++++++++++++++++++ xpp/{mpp_funcs.h => mpptalk.h} | 22 +- xpp/mpptalk_defs.h | 111 ++++ xpp/pic_loader.c | 49 +- xpp/xpp_fxloader | 18 +- xpp/{ => xtalk}/debug.c | 31 +- xpp/{ => xtalk}/debug.h | 5 +- xpp/xtalk/xlist.c | 93 +++ xpp/xtalk/xlist.h | 29 + xpp/xtalk/xtalk.c | 497 ++++++++++++++ xpp/xtalk/xtalk.h | 172 +++++ xpp/xtalk/xtalk_defs.h | 40 ++ xpp/xtalk/xusb.c | 726 +++++++++++++++++++++ xpp/xtalk/xusb.h | 98 +++ 25 files changed, 2940 insertions(+), 1729 deletions(-) delete mode 100644 xpp/mpp_funcs.c create mode 100644 xpp/mpptalk.c rename xpp/{mpp_funcs.h => mpptalk.h} (85%) create mode 100644 xpp/mpptalk_defs.h rename xpp/{ => xtalk}/debug.c (65%) rename xpp/{ => xtalk}/debug.h (86%) create mode 100644 xpp/xtalk/xlist.c create mode 100644 xpp/xtalk/xlist.h create mode 100644 xpp/xtalk/xtalk.c create mode 100644 xpp/xtalk/xtalk.h create mode 100644 xpp/xtalk/xtalk_defs.h create mode 100644 xpp/xtalk/xusb.c create mode 100644 xpp/xtalk/xusb.h diff --git a/xpp/Makefile b/xpp/Makefile index 38b5956..e4f460f 100644 --- a/xpp/Makefile +++ b/xpp/Makefile @@ -54,9 +54,12 @@ PERL_SCRIPTS = \ PERL_MANS = $(PERL_SCRIPTS:%=%.8) -ABHEXLOAD_OBJS = astribank_hexload.o hexfile.o pic_loader.o astribank_usb.o mpp_funcs.o debug.o -ABTOOL_OBJS = astribank_tool.o astribank_usb.o mpp_funcs.o debug.o -ABALLOW_OBJS = astribank_allow.o astribank_usb.o mpp_funcs.o debug.o +XTALK_OBJS = xtalk/xtalk.o xtalk/xusb.o xtalk/xlist.o xtalk/debug.o +ASTRIBANK_OBJS = astribank_usb.o mpptalk.o $(XTALK_OBJS) + +ABHEXLOAD_OBJS = astribank_hexload.o hexfile.o pic_loader.o $(ASTRIBANK_OBJS) $(OCT_OBJS) +ABTOOL_OBJS = astribank_tool.o $(ASTRIBANK_OBJS) +ABALLOW_OBJS = astribank_allow.o $(ASTRIBANK_OBJS) TARGETS = .perlcheck astribank_is_starting PROG_INSTALL = astribank_is_starting @@ -102,6 +105,8 @@ ifneq (,$(PERLLIBDIR)) done endif +CFLAGS += -I. -Ixtalk + fpga_load: fpga_load.o hexfile.o fpga_load: LIBS+=$(EXTRA_LIBS) $(USB_LIB) @@ -130,11 +135,11 @@ test_parse: LIBS+=$(EXTRA_LIBS) $(USB_LIB) touch $@ clean: - $(RM) .depend *.o $(TARGETS) + $(RM) .depend *.o xtalk/*.o $(TARGETS) .PHONY: depend depend: .depend -.depend: *.c *.h - @$(CC) -MM *.c > $@ || rm -f $@ +.depend: *.c *.h xtalk/*.c xtalk/*.h + @$(CC) $(CFLAGS) -MM *.c xtalk/*.c > $@ || rm -f $@ include .depend diff --git a/xpp/astribank_allow.8 b/xpp/astribank_allow.8 index 0fd48cc..6675432 100644 --- a/xpp/astribank_allow.8 +++ b/xpp/astribank_allow.8 @@ -30,11 +30,11 @@ information used by Xorcom to generate/modify licensed capabilities. .B \-D .I device-path .RS -Required. The device to read from/write to. On modern UDEV-based system -this is usually /dev/bus/usb/\fIbus_num\fR/\fIdevice_num\fR, -where \fIbus_num\fR and \fIdevice_num\fR are the first two numbers in the -output of lsusb(8). -On older systems that use usbfs, it is usually +Required. The device to read from/write to. This is +\fIbus_num\fR/\fIdevice_num\fR, where \fIbus_num\fR and \fIdevice_num\fR +are the first two numbers in the output of lsusb(8) or dahdi_hardware(8). +On older versions of this toolyou needed a complete path to the device, +which would be /dev/bus/usb/\fIbus_num\fR/\fIdevice_num\fR, or /proc/bus/usb/\fIbus_num\fR/\fIdevice_num\fR. .RE diff --git a/xpp/astribank_allow.c b/xpp/astribank_allow.c index b87f6fa..b1e8c52 100644 --- a/xpp/astribank_allow.c +++ b/xpp/astribank_allow.c @@ -32,8 +32,8 @@ #include #include #include "mpp.h" -#include "mpp_funcs.h" -#include "debug.h" +#include "mpptalk.h" +#include static const char rcsid[] = "$Id$"; @@ -327,7 +327,7 @@ int main(int argc, char *argv[]) usage(); } DBG("Startup %s\n", devpath); - if((astribank = mpp_init(devpath)) == NULL) { + if((astribank = mpp_init(devpath, 1)) == NULL) { ERR("Failed initializing MPP\n"); return 1; } diff --git a/xpp/astribank_hexload.8 b/xpp/astribank_hexload.8 index 6808927..08054f6 100644 --- a/xpp/astribank_hexload.8 +++ b/xpp/astribank_hexload.8 @@ -20,11 +20,11 @@ firmware. It is normally run by the script xpp_fxloader. .B \-D .I device-path .RS -Required. The device to read from/write to. On modern UDEV-based system -this is usually /dev/bus/usb/\fIbus_num\fR/\fIdevice_num\fR, -where \fIbus_num\fR and \fIdevice_num\fR are the first two numbers in the -output of lsusb(8). -On older systems that use usbfs, it is usually +Required. The device to read from/write to. This is +\fIbus_num\fR/\fIdevice_num\fR, where \fIbus_num\fR and \fIdevice_num\fR +are the first two numbers in the output of lsusb(8) or dahdi_hardware(8). +On older versions of this toolyou needed a complete path to the device, +which would be /dev/bus/usb/\fIbus_num\fR/\fIdevice_num\fR, or /proc/bus/usb/\fIbus_num\fR/\fIdevice_num\fR. .RE diff --git a/xpp/astribank_hexload.c b/xpp/astribank_hexload.c index b268e5d..8362ba2 100644 --- a/xpp/astribank_hexload.c +++ b/xpp/astribank_hexload.c @@ -27,9 +27,9 @@ #include #include #include -#include "debug.h" +#include #include "hexfile.h" -#include "mpp_funcs.h" +#include "mpptalk.h" #include "pic_loader.h" #include "astribank_usb.h" @@ -80,12 +80,16 @@ static int load_hexfile(struct astribank_device *astribank, const char *hexfile, int ret; int i; char star[] = "+\\+|+/+-"; + const char *devstr; if((hexdata = parse_hexfile(hexfile, MAX_HEX_LINES)) == NULL) { perror(hexfile); return -errno; } - INFO("Loading hexfile to %s: %s (version %s)\n", + devstr = xusb_devpath(astribank->xusb); + INFO("%s [%s]: Loading %s Firmware: %s (version %s)\n", + devstr, + xusb_serial(astribank->xusb), dev_dest2str(dest), hexdata->fname, hexdata->version_info); #if 0 @@ -96,7 +100,7 @@ static int load_hexfile(struct astribank_device *astribank, const char *hexfile, } #endif if((ret = mpp_send_start(astribank, dest, hexdata->version_info)) < 0) { - ERR("Failed hexfile send start: %d\n", ret); + ERR("%s: Failed hexfile send start: %d\n", devstr, ret); return ret; } for(i = 0; i < hexdata->maxlines; i++) { @@ -109,7 +113,7 @@ static int load_hexfile(struct astribank_device *astribank, const char *hexfile, fflush(stdout); } if(finished) { - ERR("Extra data after End Of Data Record (line %d)\n", i); + ERR("%s: Extra data after End Of Data Record (line %d)\n", devstr, i); return 0; } if(hexline->d.content.header.tt == TT_EOF) { @@ -118,7 +122,7 @@ static int load_hexfile(struct astribank_device *astribank, const char *hexfile, continue; } if((ret = handle_hexline(astribank, hexline)) < 0) { - ERR("Failed hexfile sending in lineno %d (ret=%d)\n", i, ret);; + ERR("%s: Failed hexfile sending in lineno %d (ret=%d)\n", devstr, i, ret);; return ret; } } @@ -127,7 +131,7 @@ static int load_hexfile(struct astribank_device *astribank, const char *hexfile, fflush(stdout); } if((ret = mpp_send_end(astribank)) < 0) { - ERR("Failed hexfile send end: %d\n", ret); + ERR("%s: Failed hexfile send end: %d\n", devstr, ret); return ret; } #if 0 @@ -208,21 +212,38 @@ int main(int argc, char *argv[]) ERR("Missing device path.\n"); usage(); } - if((astribank = astribank_open(devpath, iface_num)) == NULL) { - ERR("Opening astribank failed\n"); - return 1; - } - show_astribank_info(astribank); if(opt_dest) { - if(load_hexfile(astribank, argv[optind], dest) < 0) { - ERR("Loading firmware to %s failed\n", dev_dest2str(dest)); + /* + * MPP Interface + */ + struct astribank_device *astribank; + + if((astribank = mpp_init(devpath, iface_num)) == NULL) { + ERR("%s: Opening astribank failed\n", devpath); return 1; } - } else if(opt_pic) { - if((ret = load_pic(astribank, argc - optind, argv + optind)) < 0) { - ERR("Loading PIC's failed\n"); + //show_astribank_info(astribank); + if(load_hexfile(astribank, argv[optind], dest) < 0) { + ERR("%s: Loading firmware to %s failed\n", devpath, dev_dest2str(dest)); return 1; } + astribank_close(astribank, 0); + } else if(opt_pic) { + /* + * XPP Interface + */ + struct astribank_device *astribank; + + if((astribank = astribank_open(devpath, iface_num)) == NULL) { + ERR("%s: Opening astribank failed\n", devpath); + return 1; + } + if (opt_pic) { + if ((ret = load_pic(astribank, argc - optind, argv + optind)) < 0) { + ERR("%s: Loading PIC's failed\n", devpath); + return 1; + } + } } astribank_close(astribank, 0); return 0; diff --git a/xpp/astribank_tool.8 b/xpp/astribank_tool.8 index d685470..184b331 100644 --- a/xpp/astribank_tool.8 +++ b/xpp/astribank_tool.8 @@ -17,11 +17,11 @@ to the \-D command line option). .B \-D .I device-path .RS -Required. The device to read from/write to. On modern UDEV-based system -this is usually /dev/bus/usb/\fIbus_num\fR/\fIdevice_num\fR, -where \fIbus_num\fR and \fIdevice_num\fR are the first two numbers in the -output of lsusb(8). -On older systems that use usbfs, it is usually +Required. The device to read from/write to. This is +\fIbus_num\fR/\fIdevice_num\fR, where \fIbus_num\fR and \fIdevice_num\fR +are the first two numbers in the output of lsusb(8) or dahdi_hardware(8). +On older versions of this toolyou needed a complete path to the device, +which would be /dev/bus/usb/\fIbus_num\fR/\fIdevice_num\fR, or /proc/bus/usb/\fIbus_num\fR/\fIdevice_num\fR. .RE diff --git a/xpp/astribank_tool.c b/xpp/astribank_tool.c index 59ae94c..5cf0dc3 100644 --- a/xpp/astribank_tool.c +++ b/xpp/astribank_tool.c @@ -28,8 +28,10 @@ #include #include #include -#include "mpp_funcs.h" -#include "debug.h" +#include "astribank_usb.h" +#include "mpptalk.h" +#include +#include #define DBG_MASK 0x80 /* if enabled, adds support for resetting pre-MPP USB firmware - if we @@ -132,7 +134,7 @@ int old_reset(const char* devpath) DBG("Failed re-opening astribank device for old_reset\n"); return -ENODEV; } - ret = send_usb(astribank, buf, 1, 5000); + ret = xusb_send(astribank->xusb, buf, 1, 5000); /* If we just had a reenumeration, we may get -ENODEV */ if(ret < 0 && ret != -ENODEV) @@ -205,7 +207,7 @@ int main(int argc, char *argv[]) usage(); } DBG("Startup %s\n", devpath); - if((astribank = mpp_init(devpath)) == NULL) { + if((astribank = mpp_init(devpath, 1)) == NULL) { ERR("Failed initializing MPP\n"); #ifdef SUPPORT_OLD_RESET DBG("opt_reset = %s\n", opt_reset); diff --git a/xpp/astribank_usb.c b/xpp/astribank_usb.c index dce3d47..13af7cd 100644 --- a/xpp/astribank_usb.c +++ b/xpp/astribank_usb.c @@ -30,39 +30,44 @@ #include #include #include +#include #include "astribank_usb.h" -#include "debug.h" +#include static const char rcsid[] = "$Id$"; #define DBG_MASK 0x01 #define TIMEOUT 500 -#define TYPE_ENTRY(t,ni,n,ne,out,in,...) \ - [t] = { \ - .type_code = (t), \ +#define TYPE_ENTRY(t,p,ni,n,ne,out,in,...) \ + { \ + .my_vendor_id = 0xe4e4, \ + .my_product_id = (p), \ + .name = #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 interface_type interface_types[] = { - TYPE_ENTRY(USB_11xx, 1, 0, 4, MP_EP_OUT, MP_EP_IN, - XPP_EP_OUT, - MP_EP_OUT, - XPP_EP_IN, - MP_EP_IN), - TYPE_ENTRY(USB_FIRMWARE_II, 2, 1, 2, MP_EP_OUT, MP_EP_IN, - MP_EP_OUT, - MP_EP_IN), - TYPE_ENTRY(USB_PIC, 2, 0, 2, XPP_EP_OUT, XPP_EP_IN, - XPP_EP_OUT, - XPP_EP_IN), - +#define ARRAY_SIZE(x) (sizeof(x)/sizeof(x[0])) + +static const struct xusb_spec astribank_specs[] = { + /* OLD Firmwares */ + TYPE_ENTRY("USB-OLDFXS", 0x1131, 2, 1, 2, MP_EP_OUT, MP_EP_IN), + TYPE_ENTRY("FPGA-OLDFXS", 0x1132, 2, 1, 2, MP_EP_OUT, MP_EP_IN), + TYPE_ENTRY("USB-BRI", 0x1141, 2, 1, 2, MP_EP_OUT, MP_EP_IN), + TYPE_ENTRY("FPGA-BRI", 0x1142, 2, 1, 2, MP_EP_OUT, MP_EP_IN), + TYPE_ENTRY("USB-OLD", 0x1151, 2, 1, 2, MP_EP_OUT, MP_EP_IN), + TYPE_ENTRY("FPGA-OLD", 0x1152, 2, 1, 2, MP_EP_OUT, MP_EP_IN), + + TYPE_ENTRY("USB-MULTI", 0x1161, 2, 1, 2, MP_EP_OUT, MP_EP_IN), + TYPE_ENTRY("FPGA-MULTI", 0x1162, 2, 1, 2, MP_EP_OUT, MP_EP_IN), +}; + +static const struct xusb_spec astribank_pic_specs[] = { + TYPE_ENTRY("USB_PIC", 0x1161, 2, 0, 2, XPP_EP_OUT, XPP_EP_IN), }; #undef TYPE_ENTRY @@ -71,262 +76,41 @@ static const struct interface_type interface_types[] = { /* * USB handling */ - -/* return 1 if: - * - str has a number - * - It is larger than 0 - * - It equals num - */ -static 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(struct astribank_device *astribank, uint8_t item, char *buf, unsigned int len) -{ - char tmp[BUFSIZ]; - int ret; - - assert(astribank->handle); - if (!item) - return 0; - ret = usb_get_string_simple(astribank->handle, item, tmp, BUFSIZ); - if (ret <= 0) - return ret; - return snprintf(buf, len, "%s", tmp); -} - -static int match_interface(const struct astribank_device *astribank, - const struct interface_type *itype) -{ - struct usb_interface *interface; - struct usb_interface_descriptor *iface_desc; - struct usb_config_descriptor *config_desc; - int i = itype - interface_types; - int inum; - int num_altsetting; - - DBG("Checking[%d]: interfaces=%d interface num=%d endpoints=%d: \"%s\"\n", - i, - itype->num_interfaces, - itype->my_interface_num, - itype->num_endpoints, - itype->name); - config_desc = astribank->dev->config; - if (!config_desc) { - ERR("No configuration descriptor: strange USB1 controller?\n"); - return 0; - } - if(config_desc->bNumInterfaces <= itype->my_interface_num) { - DBG("Too little interfaces: have %d need %d\n", - config_desc->bNumInterfaces, itype->my_interface_num + 1); - return 0; - } - if(astribank->my_interface_num != itype->my_interface_num) { - DBG("Wrong match -- not my interface num (wanted %d)\n", astribank->my_interface_num); - return 0; - } - inum = itype->my_interface_num; - interface = &config_desc->interface[inum]; - assert(interface != NULL); - iface_desc = interface->altsetting; - num_altsetting = interface->num_altsetting; - assert(num_altsetting != 0); - assert(iface_desc != NULL); - if(iface_desc->bInterfaceClass != 0xFF) { - DBG("Bad interface class 0x%X\n", iface_desc->bInterfaceClass); - return 0; - } - if(iface_desc->bInterfaceNumber != itype->my_interface_num) { - DBG("Bad interface number %d\n", iface_desc->bInterfaceNumber); - return 0; - } - if(iface_desc->bNumEndpoints != itype->num_endpoints) { - DBG("Different number of endpoints %d\n", iface_desc->bNumEndpoints); - return 0; - } - return 1; -} - -static int astribank_init(struct astribank_device *astribank) -{ - 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; - const struct interface_type *fwtype; - int i; - - assert(astribank); - astribank->handle = usb_open(astribank->dev); - if(!astribank->handle) { - ERR("Failed to open usb device '%s/%s': %s\n", - astribank->dev->bus->dirname, astribank->dev->filename, usb_strerror()); - return 0; - } - fwtype = astribank->fwtype; - if(usb_claim_interface(astribank->handle, fwtype->my_interface_num) != 0) { - ERR("usb_claim_interface: %s\n", usb_strerror()); - return 0; - } - dev_desc = &astribank->dev->descriptor; - config_desc = astribank->dev->config; - if (!config_desc) { - ERR("usb interface without a configuration\n"); - return 0; - } - DBG("Got config_desc. Looking for interface %d\n", fwtype->my_interface_num); - interface = &config_desc->interface[fwtype->my_interface_num]; - iface_desc = interface->altsetting; - endpoint = iface_desc->endpoint; - astribank->is_usb2 = (endpoint->wMaxPacketSize == 512); - for(i = 0; i < iface_desc->bNumEndpoints; i++, endpoint++) { - DBG("Validating endpoint @ %d (interface %d)\n", i, fwtype->my_interface_num); - if(endpoint->bEndpointAddress != fwtype->endpoints[i]) { - ERR("Wrong endpoint 0x%X != 0x%X (at index %d)\n", - endpoint->bEndpointAddress, - fwtype->endpoints[i], - i); - return 0; - } - if(endpoint->bEndpointAddress == MP_EP_OUT || endpoint->bEndpointAddress == MP_EP_IN) { - if(endpoint->wMaxPacketSize > PACKET_SIZE) { - ERR("Endpoint #%d wMaxPacketSize too large (%d)\n", i, endpoint->wMaxPacketSize); - return 0; - } - } - } - astribank->my_ep_in = fwtype->my_ep_in; - astribank->my_ep_out = fwtype->my_ep_out; - if(get_usb_string(astribank, dev_desc->iManufacturer, astribank->iManufacturer, BUFSIZ) < 0) - return 0; - if(get_usb_string(astribank, dev_desc->iProduct, astribank->iProduct, BUFSIZ) < 0) - return 0; - if(get_usb_string(astribank, dev_desc->iSerialNumber, astribank->iSerialNumber, BUFSIZ) < 0) - return 0; - if(get_usb_string(astribank, iface_desc->iInterface, astribank->iInterface, BUFSIZ) < 0) - return 0; - DBG("ID=%04X:%04X Manufacturer=[%s] Product=[%s] SerialNumber=[%s] Interface=[%s]\n", - dev_desc->idVendor, - dev_desc->idProduct, - astribank->iManufacturer, - astribank->iProduct, - astribank->iSerialNumber, - astribank->iInterface); - if(usb_clear_halt(astribank->handle, astribank->my_ep_out) != 0) { - ERR("Clearing output endpoint: %s\n", usb_strerror()); - return 0; - } - if(usb_clear_halt(astribank->handle, astribank->my_ep_in) != 0) { - ERR("Clearing input endpoint: %s\n", usb_strerror()); - return 0; - } - if((i = flush_read(astribank)) < 0) { - ERR("flush_read failed: %d\n", i); - return 0; - } - return 1; -} - struct astribank_device *astribank_open(const char devpath[], int iface_num) { - struct astribank_device *astribank; - int i; + struct astribank_device *astribank = NULL; + struct xusb *xusb; DBG("devpath='%s' iface_num=%d\n", devpath, iface_num); - if((astribank = malloc(sizeof(*astribank))) == NULL) { - ERR("Out of memory"); - return NULL; + if((astribank = malloc(sizeof(struct astribank_device))) == NULL) { + ERR("Out of memory\n"); + goto fail; } memset(astribank, 0, sizeof(*astribank)); + if (iface_num) { + xusb = xusb_find_bypath(astribank_specs, ARRAY_SIZE(astribank_specs), devpath); + } else { + xusb = xusb_find_bypath(astribank_pic_specs, ARRAY_SIZE(astribank_pic_specs), devpath); + } + if (!xusb) { + ERR("%s: No device found\n", __func__); + goto fail; + } + astribank->xusb = xusb; + astribank->is_usb2 = (xusb_packet_size(xusb) == 512); astribank->my_interface_num = iface_num; - usb_init(); - usb_find_busses(); - usb_find_devices(); - astribank->dev = dev_of_path(devpath); - if(!astribank->dev) { - ERR("Bailing out\n"); + if (xusb_claim_interface(astribank->xusb) < 0) { + ERR("xusb_claim_interface failed\n"); goto fail; } - DBG("Scan interface types (astribank has %d interfaces)\n", astribank->dev->config->bNumInterfaces); - for(i = 0; i < sizeof(interface_types)/sizeof(interface_types[0]); i++) { - if(match_interface(astribank, &interface_types[i])) { - DBG("Identified[%d]: interfaces=%d endpoints=%d: \"%s\"\n", - i, - interface_types[i].num_interfaces, - interface_types[i].num_endpoints, - interface_types[i].name); - astribank->fwtype = &interface_types[i]; - goto found; - } - } - ERR("Didn't find suitable device\n"); -fail: - free(astribank); - return NULL; -found: - if(!astribank_init(astribank)) - goto fail; astribank->tx_sequenceno = 1; return astribank; +fail: + if (astribank) { + free(astribank); + astribank = NULL; + } + return NULL; } /* @@ -334,100 +118,36 @@ found: */ void show_astribank_info(const struct astribank_device *astribank) { - struct usb_device_descriptor *dev_desc; - struct usb_device *dev; + struct xusb *xusb; assert(astribank != NULL); - dev = astribank->dev; - dev_desc = &dev->descriptor; + xusb = astribank->xusb; + assert(xusb != NULL); if(verbose <= LOG_INFO) { - INFO("usb:%s/%s: ID=%04X:%04X [%s / %s / %s]\n", - dev->bus->dirname, - dev->filename, - dev_desc->idVendor, - dev_desc->idProduct, - astribank->iManufacturer, - astribank->iProduct, - astribank->iSerialNumber); + xusb_showinfo(xusb); } else { - printf("USB Bus/Device: [%s/%s]\n", dev->bus->dirname, dev->filename); - printf("USB Firmware Type: [%s]\n", astribank->fwtype->name); - printf("USB iManufacturer: [%s]\n", astribank->iManufacturer); - printf("USB iProduct: [%s]\n", astribank->iProduct); - printf("USB iSerialNumber: [%s]\n", astribank->iSerialNumber); + const struct xusb_spec *spec; + + spec = xusb_spec(xusb); + printf("USB Bus/Device: [%s]\n", xusb_devpath(xusb)); + printf("USB Firmware Type: [%s]\n", spec->name); + printf("USB iSerialNumber: [%s]\n", xusb_serial(xusb)); + printf("USB iManufacturer: [%s]\n", xusb_manufacturer(xusb)); + printf("USB iProduct: [%s]\n", xusb_product(xusb)); } } void astribank_close(struct astribank_device *astribank, int disconnected) { assert(astribank != NULL); - if(!astribank->handle) - return; /* Nothing to do */ - if(!disconnected) { - if(usb_release_interface(astribank->handle, astribank->fwtype->my_interface_num) != 0) { - ERR("Releasing interface: usb: %s\n", usb_strerror()); - } - } - if(usb_close(astribank->handle) != 0) { - ERR("Closing device: usb: %s\n", usb_strerror()); + if (astribank->xusb) { + xusb_close(astribank->xusb); + astribank->xusb = NULL; } astribank->tx_sequenceno = 0; - astribank->handle = NULL; -} - -int send_usb(struct astribank_device *astribank, char *buf, int len, int timeout) -{ - int ret; - - dump_packet(LOG_DEBUG, __FUNCTION__, buf, len); - if(astribank->my_ep_out & USB_ENDPOINT_IN) { - ERR("send_usb called with an input endpoint 0x%x\n", astribank->my_ep_out); - return -EINVAL; - } - ret = usb_bulk_write(astribank->handle, astribank->my_ep_out, buf, 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: (%d) %s\n", - astribank->my_ep_out, ret, usb_strerror()); - dump_packet(LOG_ERR, "send_usb[ERR]", buf, len); - exit(2); - } else { - DBG("bulk_write to endpoint 0x%x got ENODEV\n", astribank->my_ep_out); - astribank_close(astribank, 1); - } - return ret; - } else if(ret != len) { - ERR("bulk_write to endpoint 0x%x short write: (%d) %s\n", - astribank->my_ep_out, ret, usb_strerror()); - dump_packet(LOG_ERR, "send_usb[ERR]", buf, len); - return -EFAULT; - } - return ret; -} - -int recv_usb(struct astribank_device *astribank, char *buf, size_t len, int timeout) -{ - int ret; - - if(astribank->my_ep_in & USB_ENDPOINT_OUT) { - ERR("recv_usb called with an output endpoint 0x%x\n", astribank->my_ep_in); - return -EINVAL; - } - ret = usb_bulk_read(astribank->handle, astribank->my_ep_in, buf, len, timeout); - if(ret < 0) { - DBG("bulk_read from endpoint 0x%x failed: (%d) %s\n", - astribank->my_ep_in, ret, usb_strerror()); - memset(buf, 0, len); - return ret; - } - dump_packet(LOG_DEBUG, __FUNCTION__, buf, ret); - return ret; } +#if 0 int flush_read(struct astribank_device *astribank) { char tmpbuf[BUFSIZ]; @@ -441,10 +161,11 @@ int flush_read(struct astribank_device *astribank) return ret; } else if(ret > 0) { DBG("Got %d bytes:\n", ret); - dump_packet(LOG_DEBUG, __FUNCTION__, tmpbuf, ret); + dump_packet(LOG_DEBUG, DBG_MASK, __FUNCTION__, tmpbuf, ret); } return 0; } +#endif int release_isvalid(uint16_t release) @@ -541,12 +262,10 @@ int eeprom_fill(struct eeprom_table *eprm, int astribank_has_twinstar(struct astribank_device *astribank) { - struct usb_device_descriptor *dev_desc; uint16_t product_series; assert(astribank != NULL); - dev_desc = &astribank->dev->descriptor; - product_series = dev_desc->idProduct; + product_series = xusb_product_id(astribank->xusb); product_series &= 0xFFF0; if(product_series == 0x1160) /* New boards */ return 1; diff --git a/xpp/astribank_usb.h b/xpp/astribank_usb.h index b3b4d79..b65c1db 100644 --- a/xpp/astribank_usb.h +++ b/xpp/astribank_usb.h @@ -23,7 +23,8 @@ */ #include -#include +#include +#include #include "mpp.h" /* @@ -63,14 +64,12 @@ enum eeprom_burn_state { }; struct astribank_device { - struct usb_device *dev; + struct xusb *xusb; + struct xtalk_device *xtalk_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; enum eeprom_type eeprom_type; @@ -79,7 +78,6 @@ struct astribank_device { uint8_t mpp_proto_version; struct eeprom_table *eeprom; struct firmware_versions fw_versions; - const struct interface_type *fwtype; uint16_t tx_sequenceno; }; diff --git a/xpp/mpp.h b/xpp/mpp.h index 45654b7..23a0ce9 100644 --- a/xpp/mpp.h +++ b/xpp/mpp.h @@ -26,6 +26,10 @@ * MPP - Managment Processor Protocol definitions */ +#include +#include +#include + #ifdef __GNUC__ #define PACKED __attribute__((packed)) #else @@ -63,7 +67,8 @@ struct capabilities { uint8_t ports_bri; uint8_t ports_pri; uint8_t extra_features; /* BIT(0) - TwinStar */ - uint8_t reserved[3]; + uint8_t ports_echo; + uint8_t reserved[2]; uint32_t timestamp; } PACKED; @@ -81,53 +86,6 @@ struct extrainfo { char text[24]; } PACKED; -enum mpp_command_ops { - /* MSB of op signifies a reply from device */ - MPP_ACK = 0x80, - - MPP_PROTO_QUERY = 0x01, - MPP_PROTO_REPLY = 0x81, - - MPP_RENUM = 0x0B, /* Trigger USB renumeration */ - - MPP_EEPROM_SET = 0x0D, - - MPP_CAPS_GET = 0x0E, - MPP_CAPS_GET_REPLY = 0x8E, - MPP_CAPS_SET = 0x0F, /* Set AB capabilities */ - - MPP_DEV_SEND_START = 0x05, - MPP_DEV_SEND_SEG = 0x07, - MPP_DEV_SEND_END = 0x09, - - MPP_STATUS_GET = 0x11, /* Get Astribank Status */ - MPP_STATUS_GET_REPLY = 0x91, - MPP_STATUS_GET_REPLY_V13 = 0x91, /* backward compat */ - - MPP_EXTRAINFO_GET = 0x13, /* Get extra vendor information */ - MPP_EXTRAINFO_GET_REPLY = 0x93, - MPP_EXTRAINFO_SET = 0x15, /* Set extra vendor information */ - - MPP_EEPROM_BLK_RD = 0x27, - MPP_EEPROM_BLK_RD_REPLY = 0xA7, - - MPP_SER_SEND = 0x37, - MPP_SER_RECV = 0xB7, - - MPP_RESET = 0x45, /* Reset both FPGA and USB firmwares */ - MPP_HALF_RESET = 0x47, /* Reset only FPGA firmware */ - - /* Twinstar */ - MPP_TWS_WD_MODE_SET = 0x31, /* Set watchdog off/on guard */ - MPP_TWS_WD_MODE_GET = 0x32, /* Current watchdog mode */ - MPP_TWS_WD_MODE_GET_REPLY = 0xB2, /* Current watchdog mode */ - MPP_TWS_PORT_SET = 0x34, /* USB-[0/1] */ - MPP_TWS_PORT_GET = 0x35, /* USB-[0/1] */ - MPP_TWS_PORT_GET_REPLY = 0xB5, /* USB-[0/1] */ - MPP_TWS_PWR_GET = 0x36, /* Power: bits -> USB ports */ - MPP_TWS_PWR_GET_REPLY = 0xB6, /* Power: bits -> USB ports */ -}; - struct mpp_header { uint16_t len; uint16_t seq; @@ -141,33 +99,10 @@ enum mpp_ser_op { /* Individual commands structure */ -#define CMD_DEF(name, ...) struct d_ ## name { __VA_ARGS__ } PACKED d_ ## name - -CMD_DEF(ACK, - uint8_t stat; - ); - -CMD_DEF(PROTO_QUERY, - uint8_t proto_version; - uint8_t reserved; - ); - -CMD_DEF(PROTO_REPLY, - uint8_t proto_version; - uint8_t reserved; - ); - -CMD_DEF(STATUS_GET); - -CMD_DEF(STATUS_GET_REPLY_V13, - uint8_t i2cs_data; - -#define STATUS_FPGA_LOADED(x) ((x) & 0x01) - uint8_t status; /* BIT(0) - FPGA is loaded */ - ); +CMD_DEF(MPP, STATUS_GET); -CMD_DEF(STATUS_GET_REPLY, +CMD_DEF(MPP, STATUS_GET_REPLY, uint8_t i2cs_data; #define STATUS_FPGA_LOADED(x) ((x) & 0x01) @@ -175,170 +110,90 @@ CMD_DEF(STATUS_GET_REPLY, struct firmware_versions fw_versions; ); -CMD_DEF(EEPROM_SET, +CMD_DEF(MPP, EEPROM_SET, struct eeprom_table data; ); -CMD_DEF(CAPS_GET); +CMD_DEF(MPP, CAPS_GET); -CMD_DEF(CAPS_GET_REPLY, +CMD_DEF(MPP, CAPS_GET_REPLY, struct eeprom_table data; struct capabilities capabilities; struct capkey key; ); -CMD_DEF(CAPS_SET, +CMD_DEF(MPP, CAPS_SET, struct eeprom_table data; struct capabilities capabilities; struct capkey key; ); -CMD_DEF(EXTRAINFO_GET); +CMD_DEF(MPP, EXTRAINFO_GET); -CMD_DEF(EXTRAINFO_GET_REPLY, +CMD_DEF(MPP, EXTRAINFO_GET_REPLY, struct extrainfo info; ); -CMD_DEF(EXTRAINFO_SET, +CMD_DEF(MPP, EXTRAINFO_SET, struct extrainfo info; ); -CMD_DEF(RENUM); +CMD_DEF(MPP, RENUM); -CMD_DEF(EEPROM_BLK_RD, +CMD_DEF(MPP, EEPROM_BLK_RD, uint16_t offset; uint16_t len; ); -CMD_DEF(EEPROM_BLK_RD_REPLY, +CMD_DEF(MPP, EEPROM_BLK_RD_REPLY, uint16_t offset; uint8_t data[0]; ); -CMD_DEF(DEV_SEND_START, +CMD_DEF(MPP, DEV_SEND_START, uint8_t dest; char ihex_version[VERSION_LEN]; ); -CMD_DEF(DEV_SEND_END); +CMD_DEF(MPP, DEV_SEND_END); -CMD_DEF(DEV_SEND_SEG, +CMD_DEF(MPP, DEV_SEND_SEG, uint16_t offset; uint8_t data[0]; ); -CMD_DEF(RESET); -CMD_DEF(HALF_RESET); +CMD_DEF(MPP, RESET); +CMD_DEF(MPP, HALF_RESET); -CMD_DEF(SER_SEND, +CMD_DEF(MPP, SER_SEND, uint8_t data[0]; ); -CMD_DEF(SER_RECV, +CMD_DEF(MPP, SER_RECV, uint8_t data[0]; ); -CMD_DEF(TWS_WD_MODE_SET, +CMD_DEF(MPP, TWS_WD_MODE_SET, uint8_t wd_active; ); -CMD_DEF(TWS_WD_MODE_GET); -CMD_DEF(TWS_WD_MODE_GET_REPLY, +CMD_DEF(MPP, TWS_WD_MODE_GET); +CMD_DEF(MPP, TWS_WD_MODE_GET_REPLY, uint8_t wd_active; ); -CMD_DEF(TWS_PORT_SET, +CMD_DEF(MPP, TWS_PORT_SET, uint8_t portnum; ); -CMD_DEF(TWS_PORT_GET); -CMD_DEF(TWS_PORT_GET_REPLY, +CMD_DEF(MPP, TWS_PORT_GET); +CMD_DEF(MPP, TWS_PORT_GET_REPLY, uint8_t portnum; ); -CMD_DEF(TWS_PWR_GET); -CMD_DEF(TWS_PWR_GET_REPLY, +CMD_DEF(MPP, TWS_PWR_GET); +CMD_DEF(MPP, TWS_PWR_GET_REPLY, uint8_t power; ); -#undef CMD_DEF - -#define MEMBER(n) struct d_ ## n d_ ## n - -struct mpp_command { - struct mpp_header header; - union { - MEMBER(ACK); - MEMBER(PROTO_QUERY); - MEMBER(PROTO_REPLY); - MEMBER(STATUS_GET); - MEMBER(STATUS_GET_REPLY_V13); - MEMBER(STATUS_GET_REPLY); - MEMBER(EEPROM_SET); - MEMBER(CAPS_GET); - MEMBER(CAPS_GET_REPLY); - MEMBER(CAPS_SET); - MEMBER(EXTRAINFO_GET); - MEMBER(EXTRAINFO_GET_REPLY); - MEMBER(EXTRAINFO_SET); - MEMBER(RENUM); - MEMBER(EEPROM_BLK_RD); - MEMBER(EEPROM_BLK_RD_REPLY); - MEMBER(DEV_SEND_START); - MEMBER(DEV_SEND_SEG); - MEMBER(DEV_SEND_END); - MEMBER(RESET); - MEMBER(HALF_RESET); - MEMBER(SER_SEND); - MEMBER(SER_RECV); - /* Twinstar */ - MEMBER(TWS_WD_MODE_SET); - MEMBER(TWS_WD_MODE_GET); - MEMBER(TWS_WD_MODE_GET_REPLY); - MEMBER(TWS_PORT_SET); - MEMBER(TWS_PORT_GET); - MEMBER(TWS_PORT_GET_REPLY); - MEMBER(TWS_PWR_GET); - MEMBER(TWS_PWR_GET_REPLY); - uint8_t raw_data[0]; - } PACKED alt; -} PACKED; -#undef MEMBER - -#define CMD_FIELD(cmd, name, field) ((cmd)->alt.d_ ## name.field) - -enum mpp_ack_stat { - STAT_OK = 0x00, /* acknowledges previous command */ - STAT_FAIL = 0x01, /* Last command failed */ - STAT_RESET_FAIL = 0x02, /* reset failed */ - STAT_NODEST = 0x03, /* No destination is selected */ - STAT_MISMATCH = 0x04, /* Data mismatch */ - STAT_NOACCESS = 0x05, /* No access */ - STAT_BAD_CMD = 0x06, /* Bad command */ - STAT_TOO_SHORT = 0x07, /* Packet is too short */ - STAT_ERROFFS = 0x08, /* Offset error */ - STAT_NOCODE = 0x09, /* Source was not burned before */ - STAT_NO_LEEPROM = 0x0A, /* Large EEPROM was not found */ - STAT_NO_EEPROM = 0x0B, /* No EEPROM was found */ - STAT_WRITE_FAIL = 0x0C, /* Writing to device failed */ - STAT_FPGA_ERR = 0x0D, /* FPGA error */ - STAT_KEY_ERR = 0x0E, /* Bad Capabilities Key */ - STAT_NOCAPS_ERR = 0x0F, /* No matching capability */ - STAT_NOPWR_ERR = 0x10, /* No power on USB connector */ - STAT_CAPS_FPGA_ERR = 0x11, /* Setting of the capabilities while FPGA is loaded */ -}; - -enum eeprom_type { /* EEPROM_QUERY: i2cs(ID1, ID0) */ - EEPROM_TYPE_NONE = 0, - EEPROM_TYPE_SMALL = 1, - EEPROM_TYPE_LARGE = 2, - EEPROM_TYPE_UNUSED = 3, -}; - -enum dev_dest { - DEST_NONE = 0x00, - DEST_FPGA = 0x01, - DEST_EEPROM = 0x02, -}; - #endif /* MPP_H */ diff --git a/xpp/mpp_funcs.c b/xpp/mpp_funcs.c deleted file mode 100644 index 457455a..0000000 --- a/xpp/mpp_funcs.c +++ /dev/null @@ -1,1109 +0,0 @@ -/* - * Written by Oron Peled - * Copyright (C) 2008, Xorcom - * - * All rights reserved. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - * - */ - -#include -#include -#include -#include -#include -#include -#include "hexfile.h" -#include "astribank_usb.h" -#include "mpp_funcs.h" -#include "debug.h" - -static const char rcsid[] = "$Id$"; - -#define DBG_MASK 0x02 - -const char *ack_status_msg(uint8_t status) -{ - const static char *msgs[] = { - [STAT_OK] = "Acknowledges previous command", - [STAT_FAIL] = "Last command failed", - [STAT_RESET_FAIL] = "Reset failed", - [STAT_NODEST] = "No destination is selected", - [STAT_MISMATCH] = "Data mismatch", - [STAT_NOACCESS] = "No access", - [STAT_BAD_CMD] = "Bad command", - [STAT_TOO_SHORT] = "Packet is too short", - [STAT_ERROFFS] = "Offset error", - [STAT_NOCODE] = "Source was not burned before", - [STAT_NO_LEEPROM] = "Large EEPROM was not found", - [STAT_NO_EEPROM] = "No EEPROM was found", - [STAT_WRITE_FAIL] = "Writing to device failed", - [STAT_FPGA_ERR] = "FPGA error", - [STAT_KEY_ERR] = "Bad Capabilities Key", - [STAT_NOCAPS_ERR] = "No matching capability", - [STAT_NOPWR_ERR] = "No power on USB connector", - [STAT_CAPS_FPGA_ERR] = "Setting of the capabilities while FPGA is loaded", - }; - if(status > sizeof(msgs)/sizeof(msgs[0])) - return "ERROR CODE TOO LARGE"; - if(!msgs[status]) - return "MISSING ERROR CODE"; - return msgs[status]; -} - -const char *eeprom_type2str(enum eeprom_type et) -{ - const static char *msgs[] = { - [EEPROM_TYPE_NONE] = "NONE", - [EEPROM_TYPE_SMALL] = "SMALL", - [EEPROM_TYPE_LARGE] = "LARGE", - [EEPROM_TYPE_UNUSED] = "UNUSED", - }; - if(et > sizeof(msgs)/sizeof(msgs[0])) - return NULL; - return msgs[et]; -}; - -const char *dev_dest2str(enum dev_dest dest) -{ - const static char *msgs[] = { - [DEST_NONE] = "NONE", - [DEST_FPGA] = "FPGA", - [DEST_EEPROM] = "EEPROM", - }; - if(dest > sizeof(msgs)/sizeof(msgs[0])) - return NULL; - return msgs[dest]; -}; - -struct command_desc { - uint8_t op; - const char *name; - uint16_t len; -}; - -#define CMD_RECV(o) [MPP_ ## o] { \ - .op = MPP_ ## o, \ - .name = #o, \ - .len = sizeof(struct mpp_header) + sizeof(struct d_ ## o), \ - } - -#define CMD_SEND(o) [MPP_ ## o] { \ - .op = MPP_ ## o, \ - .name = #o, \ - .len = sizeof(struct mpp_header) + sizeof(struct d_ ## o), \ - } - -static const struct command_desc command_table[] = { - CMD_RECV(ACK), - CMD_SEND(PROTO_QUERY), - CMD_SEND(STATUS_GET), - CMD_RECV(STATUS_GET_REPLY), - CMD_SEND(EEPROM_SET), - CMD_SEND(CAPS_GET), - CMD_RECV(CAPS_GET_REPLY), - CMD_SEND(CAPS_SET), - CMD_SEND(EXTRAINFO_GET), - CMD_RECV(EXTRAINFO_GET_REPLY), - CMD_SEND(EXTRAINFO_SET), - CMD_RECV(PROTO_REPLY), - CMD_SEND(RENUM), - CMD_SEND(EEPROM_BLK_RD), - CMD_RECV(EEPROM_BLK_RD_REPLY), - CMD_SEND(DEV_SEND_SEG), - CMD_SEND(DEV_SEND_START), - CMD_SEND(DEV_SEND_END), - CMD_SEND(RESET), - CMD_SEND(HALF_RESET), - CMD_SEND(SER_SEND), - CMD_SEND(SER_RECV), - /* Twinstar */ - CMD_SEND(TWS_WD_MODE_SET), - CMD_SEND(TWS_WD_MODE_GET), - CMD_RECV(TWS_WD_MODE_GET_REPLY), - CMD_SEND(TWS_PORT_SET), - CMD_SEND(TWS_PORT_GET), - CMD_RECV(TWS_PORT_GET_REPLY), - CMD_SEND(TWS_PWR_GET), - CMD_RECV(TWS_PWR_GET_REPLY), -}; - -static const struct command_desc command_table_V13[] = { - CMD_RECV(ACK), - CMD_SEND(PROTO_QUERY), - CMD_SEND(STATUS_GET), - CMD_RECV(STATUS_GET_REPLY_V13), - CMD_SEND(EEPROM_SET), - CMD_SEND(CAPS_GET), - CMD_RECV(CAPS_GET_REPLY), - CMD_SEND(CAPS_SET), - CMD_SEND(EXTRAINFO_GET), - CMD_RECV(EXTRAINFO_GET_REPLY), - CMD_SEND(EXTRAINFO_SET), - CMD_RECV(PROTO_REPLY), - CMD_SEND(RENUM), - CMD_SEND(EEPROM_BLK_RD), - CMD_RECV(EEPROM_BLK_RD_REPLY), - CMD_SEND(DEV_SEND_SEG), - CMD_SEND(DEV_SEND_START), - CMD_SEND(DEV_SEND_END), - CMD_SEND(RESET), - CMD_SEND(HALF_RESET), - CMD_SEND(SER_SEND), - CMD_SEND(SER_RECV), - /* Twinstar */ - CMD_SEND(TWS_WD_MODE_SET), - CMD_SEND(TWS_WD_MODE_GET), - CMD_RECV(TWS_WD_MODE_GET_REPLY), - CMD_SEND(TWS_PORT_SET), - CMD_SEND(TWS_PORT_GET), - CMD_RECV(TWS_PORT_GET_REPLY), - CMD_SEND(TWS_PWR_GET), - CMD_RECV(TWS_PWR_GET_REPLY), -}; - -#undef CMD_SEND -#undef CMD_RECV - -struct cmd_queue { - struct cmd_queue *next; - struct cmd_queue *prev; - struct mpp_command *cmd; -}; - -static struct cmd_queue output_queue = { - .next = &output_queue, - .prev = &output_queue, - .cmd = NULL - }; - -void free_command(struct mpp_command *cmd) -{ - memset(cmd, 0, cmd->header.len); - free(cmd); -} - -const struct command_desc *get_command_desc(uint8_t protocol_version, uint8_t op) -{ - const struct command_desc *desc; - - switch(protocol_version) { - case MK_PROTO_VERSION(1,3): - if(op > sizeof(command_table_V13)/sizeof(command_table_V13[0])) { - //ERR("Invalid op=0x%X. Bigger than max valid op\n", op); - return NULL; - } - desc = &command_table_V13[op]; - if(!desc->name) - return NULL; - break; - default: - if(op > sizeof(command_table)/sizeof(command_table[0])) { - //ERR("Invalid op=0x%X. Bigger than max valid op\n", op); - return NULL; - } - desc = &command_table[op]; - if(!desc->name) - return NULL; - break; - } - return desc; -} - -struct mpp_command *new_command(uint8_t protocol_version, uint8_t op, uint16_t extra_data) -{ - struct mpp_command *cmd; - const struct command_desc *desc; - uint16_t len; - - desc = get_command_desc(protocol_version, op); - if(!desc) { - ERR("Unknown op=0x%X.\n", op); - return NULL; - } - DBG("OP=0x%X [%s] (extra_data %d)\n", op, desc->name, extra_data); - len = desc->len + extra_data; - if((cmd = malloc(len)) == NULL) { - ERR("Out of memory\n"); - return NULL; - } - cmd->header.op = op; - cmd->header.len = len; - cmd->header.seq = 0; /* Overwritten in send_usb() */ - return cmd; -} - -void dump_command(struct mpp_command *cmd) -{ - uint16_t len; - int i; - - len = cmd->header.len; - if(len < sizeof(struct mpp_header)) { - ERR("Command too short (%d)\n", len); - return; - } - INFO("DUMP: OP=0x%X len=%d seq=%d\n", - cmd->header.op, cmd->header.len, cmd->header.seq); - for(i = 0; i < len - sizeof(struct mpp_header); i++) { - INFO(" %2d. 0x%X\n", i, cmd->alt.raw_data[i]); - } -} - -int send_command(struct astribank_device *astribank, struct mpp_command *cmd, int timeout) -{ - int ret; - int len; - char *buf; - - len = cmd->header.len; - cmd->header.seq = astribank->tx_sequenceno; - - buf = (char *)cmd; - //printf("%s: len=%d\n", __FUNCTION__, len); -#if 0 - extern FILE *fp; - if(fp) { - int i; - - fprintf(fp, "%05d:", cmd->header.seq); - for(i = 0; i < len; i++) - fprintf(fp, " %02X", (uint8_t)buf[i]); - fprintf(fp, "\n"); - } -#endif - ret = send_usb(astribank, (char *)cmd, len, timeout); - if(ret < 0) { - DBG("send_usb failed ret=%d\n", ret); - } - astribank->tx_sequenceno++; - return ret; -} - -struct mpp_command *recv_command(struct astribank_device *astribank, int timeout) -{ - struct mpp_command *reply; - int ret; - - if((reply = malloc(PACKET_SIZE)) == NULL) { - ERR("Out of memory\n"); - goto err; - } - reply->header.len = 0; - ret = recv_usb(astribank, (char *)reply, PACKET_SIZE, timeout); - if(ret < 0) { - ERR("Receive from usb failed.\n"); - goto err; - } else if(ret == 0) { - goto err; /* No reply */ - } - if(ret != reply->header.len) { - ERR("Wrong length received: got %d bytes, but length field says %d bytes%s\n", - ret, reply->header.len, - (ret == 1)? ". Old USB firmware?": ""); - goto err; - } - //dump_packet(LOG_DEBUG, __FUNCTION__, (char *)reply, ret); - return reply; -err: - if(reply) { - memset(reply, 0, PACKET_SIZE); - free_command(reply); - } - return NULL; -} - - -__attribute__((warn_unused_result)) -int process_command(struct astribank_device *astribank, struct mpp_command *cmd, struct mpp_command **reply_ref) -{ - struct mpp_command *reply = NULL; - const struct command_desc *reply_desc; - const struct command_desc *expected; - const struct command_desc *cmd_desc; - uint8_t reply_op; - int ret; - - if(reply_ref) - *reply_ref = NULL; /* So the caller knows if a reply was received */ - reply_op = cmd->header.op | 0x80; - if(cmd->header.op == MPP_PROTO_QUERY) - astribank->mpp_proto_version = MPP_PROTOCOL_VERSION; /* bootstrap */ - cmd_desc = get_command_desc(astribank->mpp_proto_version, cmd->header.op); - expected = get_command_desc(astribank->mpp_proto_version, reply_op); - //printf("%s: len=%d\n", __FUNCTION__, cmd->header.len); - ret = send_command(astribank, cmd, TIMEOUT); - if(!reply_ref) { - DBG("No reply requested\n"); - goto out; - } - if(ret < 0) { - ERR("send_command failed: %d\n", ret); - goto out; - } - reply = recv_command(astribank, TIMEOUT); - if(!reply) { - ERR("recv_command failed\n"); - ret = -EPROTO; - goto out; - } - *reply_ref = reply; - if((reply->header.op & 0x80) != 0x80) { - ERR("Unexpected reply op=0x%02X, should have MSB set.\n", reply->header.op); - ret = -EPROTO; - goto out; - } - DBG("REPLY OP: 0x%X\n", reply->header.op); - reply_desc = get_command_desc(astribank->mpp_proto_version, reply->header.op); - if(!reply_desc) { - ERR("Unknown reply op=0x%02X\n", reply->header.op); - ret = -EPROTO; - goto out; - } - DBG("REPLY NAME: %s\n", reply_desc->name); - if(reply->header.op == MPP_ACK) { - int status = CMD_FIELD(reply, ACK, stat); - - if(expected) { - ERR("Expected OP=0x%02X: Got ACK(%d): %s\n", - reply_op, status, ack_status_msg(status)); - ret = -EPROTO; - goto out; - } else if(status != STAT_OK) { - - ERR("Got ACK (for OP=0x%X [%s]): %d - %s\n", - cmd->header.op, - cmd_desc->name, - status, - ack_status_msg(status)); -#if 0 - extern FILE *fp; - if(fp) { - fprintf(fp, "Got ACK(%d)\n", status); - } -#endif - ret = -EPROTO; - goto out; - } - /* Good expected ACK ... */ - } else if(reply->header.op != reply_op) { - ERR("Expected OP=0x%02X: Got OP=0x%02X\n", - reply_op, reply->header.op); - ret = -EPROTO; - goto out; - } - if(expected && expected->op != MPP_SER_RECV && expected->len != reply->header.len) { - ERR("Expected len=%d: Got len=%d\n", - expected->len, reply->header.len); - ret = -EPROTO; - goto out; - } - if(cmd->header.seq != reply->header.seq) { - ERR("Expected seq=%d: Got seq=%d\n", - cmd->header.seq, reply->header.seq); - ret = -EPROTO; - goto out; - } - ret = reply->header.len; /* All good, return the length */ - DBG("returning reply op 0x%X (%d bytes)\n", reply->header.op, ret); -out: - free_command(cmd); - if(!reply_ref && reply) - free_command(reply); - return ret; -} - -static int set_ihex_version(char *dst, const char *src) -{ - memcpy(dst, src, VERSION_LEN); - return 0; -} - -/* - * Protocol Commands - */ - -int mpp_proto_query(struct astribank_device *astribank) -{ - struct mpp_command *cmd; - struct mpp_command *reply; - int ret; - - DBG("\n"); - assert(astribank != NULL); - if((cmd = new_command(astribank->mpp_proto_version, MPP_PROTO_QUERY, 0)) == NULL) { - ERR("new_command failed\n"); - return -ENOMEM; - } - CMD_FIELD(cmd, PROTO_QUERY, proto_version) = MPP_PROTOCOL_VERSION; /* Protocol Version */ - ret = process_command(astribank, cmd, &reply); - if(ret < 0) { - ERR("process_command failed: %d\n", ret); - return ret; - } - astribank->mpp_proto_version = CMD_FIELD(reply, PROTO_REPLY, proto_version); - if(! MPP_SUPPORTED_VERSION(astribank->mpp_proto_version)) { - ERR("Got mpp protocol version: %02x (expected %02x)\n", - astribank->mpp_proto_version, - MPP_PROTOCOL_VERSION); - ret = -EPROTO; - goto out; - } - if(astribank->mpp_proto_version != MPP_PROTOCOL_VERSION) { - ERR("Deprecated (but working) MPP protocol version [%X]. Please upgrade to [%X] ASAP\n", - astribank->mpp_proto_version, MPP_PROTOCOL_VERSION); - } - DBG("Protocol version: %02x\n", astribank->mpp_proto_version); - ret = astribank->mpp_proto_version; - free_command(reply); -out: - return ret; -} - -int mpp_status_query(struct astribank_device *astribank) -{ - struct mpp_command *cmd; - struct mpp_command *reply; - int ret; - - DBG("\n"); - assert(astribank != NULL); - if((cmd = new_command(astribank->mpp_proto_version, MPP_STATUS_GET, 0)) == NULL) { - ERR("new_command failed\n"); - return -ENOMEM; - } - ret = process_command(astribank, cmd, &reply); - if(ret < 0) { - ERR("process_command failed: %d\n", ret); - return ret; - } - astribank->eeprom_type = 0x3 & (CMD_FIELD(reply, STATUS_GET_REPLY, i2cs_data) >> 3); - astribank->status = CMD_FIELD(reply, STATUS_GET_REPLY, status); - astribank->fw_versions = CMD_FIELD(reply, STATUS_GET_REPLY, fw_versions); - DBG("EEPROM TYPE: %02x\n", astribank->eeprom_type); - DBG("FPGA Firmware: %s\n", (astribank->status & 0x1) ? "Loaded" : "Empty"); - DBG("Firmware Versions: USB='%s' FPGA='%s' EEPROM='%s'\n", - astribank->fw_versions.usb, - astribank->fw_versions.fpga, - astribank->fw_versions.eeprom); - free_command(reply); - return ret; -} - -int mpp_eeprom_set(struct astribank_device *astribank, const struct eeprom_table *et) -{ - struct mpp_command *cmd; - struct mpp_command *reply; - int ret; - - DBG("\n"); - assert(astribank != NULL); - if((cmd = new_command(astribank->mpp_proto_version, MPP_EEPROM_SET, 0)) == NULL) { - ERR("new_command failed\n"); - return -ENOMEM; - } - memcpy(&CMD_FIELD(cmd, EEPROM_SET, data), et, sizeof(*et)); - ret = process_command(astribank, cmd, &reply); - if(ret < 0) { - ERR("process_command failed: %d\n", ret); - return ret; - } - free_command(reply); - return 0; -} - -int mpp_renumerate(struct astribank_device *astribank) -{ - struct mpp_command *cmd; - int ret; - - DBG("\n"); - assert(astribank != NULL); - if((cmd = new_command(astribank->mpp_proto_version, MPP_RENUM, 0)) == NULL) { - ERR("new_command failed\n"); - return -ENOMEM; - } - ret = process_command(astribank, cmd, NULL); - if(ret < 0) { - ERR("process_command failed: %d\n", ret); - return ret; - } - return 0; -} - -int mpp_caps_get(struct astribank_device *astribank, - struct eeprom_table *eeprom_table, - struct capabilities *capabilities, - struct capkey *key) -{ - struct mpp_command *cmd; - struct mpp_command *reply; - int ret; - - DBG("\n"); - assert(astribank != NULL); - if((cmd = new_command(astribank->mpp_proto_version, MPP_CAPS_GET, 0)) == NULL) { - ERR("new_command failed\n"); - return -ENOMEM; - } - ret = process_command(astribank, cmd, &reply); - if(ret < 0) { - ERR("process_command failed: %d\n", ret); - return ret; - } - assert(reply->header.op == MPP_CAPS_GET_REPLY); - if(eeprom_table) { - memcpy(eeprom_table, (void *)&CMD_FIELD(reply, CAPS_GET_REPLY, data), sizeof(*eeprom_table)); - } - if(capabilities) { - const struct capabilities *cap = &CMD_FIELD(reply, CAPS_GET_REPLY, capabilities); - - memcpy(capabilities, cap, sizeof(*capabilities)); - } - if(key) { - const struct capkey *k = &CMD_FIELD(reply, CAPS_GET_REPLY, key); - - memcpy(key, k, sizeof(*key)); - } - free_command(reply); - return 0; -} - -int mpp_caps_set(struct astribank_device *astribank, - const struct eeprom_table *eeprom_table, - const struct capabilities *capabilities, - const struct capkey *key) -{ - struct mpp_command *cmd; - struct mpp_command *reply; - int ret; - - DBG("\n"); - assert(astribank != NULL); - if((cmd = new_command(astribank->mpp_proto_version, MPP_CAPS_SET, 0)) == NULL) { - ERR("new_command failed\n"); - return -ENOMEM; - } - memcpy(&CMD_FIELD(cmd, CAPS_SET, data), eeprom_table, sizeof(*eeprom_table)); - memcpy(&CMD_FIELD(cmd, CAPS_SET, capabilities), capabilities, sizeof(*capabilities)); - memcpy(&CMD_FIELD(cmd, CAPS_SET, key), key, sizeof(*key)); - ret = process_command(astribank, cmd, &reply); - if(ret < 0) { - ERR("process_command failed: %d\n", ret); - return ret; - } - free_command(reply); - return 0; -} - -int mpp_extrainfo_get(struct astribank_device *astribank, struct extrainfo *info) -{ - struct mpp_command *cmd; - struct mpp_command *reply; - int ret; - - DBG("\n"); - assert(astribank != NULL); - if((cmd = new_command(astribank->mpp_proto_version, MPP_EXTRAINFO_GET, 0)) == NULL) { - ERR("new_command failed\n"); - return -ENOMEM; - } - ret = process_command(astribank, cmd, &reply); - if(ret < 0) { - ERR("process_command failed: %d\n", ret); - return ret; - } - assert(reply->header.op == MPP_EXTRAINFO_GET_REPLY); - if(info) { - memcpy(info, (void *)&CMD_FIELD(reply, EXTRAINFO_GET_REPLY, info), sizeof(*info)); - } - free_command(reply); - return 0; -} - -int mpp_extrainfo_set(struct astribank_device *astribank, const struct extrainfo *info) -{ - struct mpp_command *cmd; - struct mpp_command *reply; - int ret; - - DBG("\n"); - assert(astribank != NULL); - if((cmd = new_command(astribank->mpp_proto_version, MPP_EXTRAINFO_SET, 0)) == NULL) { - ERR("new_command failed\n"); - return -ENOMEM; - } - memcpy(&CMD_FIELD(cmd, EXTRAINFO_SET, info), info, sizeof(*info)); - ret = process_command(astribank, cmd, &reply); - if(ret < 0) { - ERR("process_command failed: %d\n", ret); - return ret; - } - free_command(reply); - return 0; -} - -int mpp_eeprom_blk_rd(struct astribank_device *astribank, uint8_t *buf, uint16_t offset, uint16_t len) -{ - struct mpp_command *cmd; - struct mpp_command *reply; - int ret; - int size; - - DBG("len = %d, offset = %d\n", len, offset); - assert(astribank != NULL); - if((cmd = new_command(astribank->mpp_proto_version, MPP_EEPROM_BLK_RD, 0)) == NULL) { - ERR("new_command failed\n"); - return -ENOMEM; - } - CMD_FIELD(cmd, EEPROM_BLK_RD, len) = len; - CMD_FIELD(cmd, EEPROM_BLK_RD, offset) = offset; - ret = process_command(astribank, cmd, &reply); - if(ret < 0) { - ERR("process_command failed: %d\n", ret); - size = ret; - goto out; - } - size = reply->header.len - sizeof(struct mpp_header) - sizeof(struct d_EEPROM_BLK_RD_REPLY); - INFO("size=%d offset=0x%X\n", size, CMD_FIELD(reply, EEPROM_BLK_RD_REPLY, offset)); - dump_packet(LOG_DEBUG, "BLK_RD", (char *)reply, ret); - if(size > len) { - ERR("Truncating reply (was %d, now %d)\n", size, len); - size = len; - } - memcpy(buf, CMD_FIELD(reply, EEPROM_BLK_RD_REPLY, data), size); -out: - free_command(reply); - return size; -} - -int mpp_send_start(struct astribank_device *astribank, enum dev_dest dest, const char *ihex_version) -{ - struct mpp_command *cmd; - struct mpp_command *reply = NULL; - int ret = 0; - - DBG("dest = %s ihex_version = '%s'\n", dev_dest2str(dest), ihex_version); - assert(astribank != NULL); - if((cmd = new_command(astribank->mpp_proto_version, MPP_DEV_SEND_START, 0)) == NULL) { - ERR("new_command failed\n"); - ret = -ENOMEM; - goto out; - } - CMD_FIELD(cmd, DEV_SEND_START, dest) = dest; - set_ihex_version(CMD_FIELD(cmd, DEV_SEND_START, ihex_version), ihex_version); - ret = process_command(astribank, cmd, &reply); - if(ret < 0) { - ERR("process_command failed: %d\n", ret); - goto out; - } -out: - if(reply) - free_command(reply); - astribank->burn_state = (ret == 0) - ? BURN_STATE_STARTED - : BURN_STATE_FAILED; - return ret; -} - -int mpp_send_end(struct astribank_device *astribank) -{ - struct mpp_command *cmd; - struct mpp_command *reply = NULL; - int ret = 0; - - DBG("\n"); - assert(astribank != NULL); - if((cmd = new_command(astribank->mpp_proto_version, MPP_DEV_SEND_END, 0)) == NULL) { - ERR("new_command failed\n"); - ret = -ENOMEM; - goto out; - } - ret = process_command(astribank, cmd, &reply); - if(ret < 0) { - ERR("process_command failed: %d\n", ret); - goto out; - } -out: - if(reply) - free_command(reply); - astribank->burn_state = (ret == 0) - ? BURN_STATE_ENDED - : BURN_STATE_FAILED; - return ret; -} - -int mpp_send_seg(struct astribank_device *astribank, const uint8_t *data, uint16_t offset, uint16_t len) -{ - struct mpp_command *cmd; - struct mpp_command *reply; - int ret; - - if(!astribank->burn_state == BURN_STATE_STARTED) { - ERR("Tried to send a segment while burn_state=%d\n", - astribank->burn_state); - return -EINVAL; - } - DBG("len = %d, offset = %d (0x%02X, 0x%02X)\n", len, offset, *data, *(data + 1)); - assert(astribank != NULL); - if((cmd = new_command(astribank->mpp_proto_version, MPP_DEV_SEND_SEG, len)) == NULL) { - ERR("new_command failed\n"); - return -ENOMEM; - } - CMD_FIELD(cmd, DEV_SEND_SEG, offset) = offset; - memcpy(CMD_FIELD(cmd, DEV_SEND_SEG, data), data, len); -#if 0 - { - FILE *fp; - if((fp = fopen("seg_data.bin", "a")) == NULL) { - perror("seg_data.bin"); - exit(1); - } - if(fwrite(CMD_FIELD(cmd, DEV_SEND_SEG, data), len, 1, fp) != 1) { - perror("fwrite"); - exit(1); - } - fclose(fp); - } -#endif - ret = process_command(astribank, cmd, &reply); - if(ret < 0) { - ERR("process_command failed: %d\n", ret); - return ret; - } - free_command(reply); - return 0; -} - -int mpp_reset(struct astribank_device *astribank, int full_reset) -{ - struct mpp_command *cmd; - int ret; - int op = (full_reset) ? MPP_RESET: MPP_HALF_RESET; - - DBG("full = %s\n", (full_reset) ? "YES" : "NO"); - assert(astribank != NULL); - if((cmd = new_command(astribank->mpp_proto_version, op, 0)) == NULL) { - ERR("new_command failed\n"); - return -ENOMEM; - } - ret = process_command(astribank, cmd, NULL); - if(ret < 0) { - ERR("process_command failed: %d\n", ret); - return ret; - } - return 0; -} - -int mpp_serial_cmd(struct astribank_device *astribank, const uint8_t *in, uint8_t *out, uint16_t len) -{ - struct mpp_command *cmd; - struct mpp_command *reply; - int ret; - uint8_t *data; - - DBG("len=%d\n", len); - assert(astribank != NULL); - if((cmd = new_command(astribank->mpp_proto_version, MPP_SER_SEND, len)) == NULL) { - ERR("new_command failed\n"); - return -ENOMEM; - } - data = CMD_FIELD(cmd, SER_SEND, data); - memcpy(data, in, len); - ret = process_command(astribank, cmd, &reply); - if(ret < 0) { - ERR("process_command failed: %d\n", ret); - return ret; - } - assert(reply->header.op == MPP_SER_RECV); - data = CMD_FIELD(reply, SER_RECV, data); - memcpy(out, data, len); - free_command(reply); - return 0; -} - -int mpps_card_info(struct astribank_device *astribank, int unit, uint8_t *card_type, uint8_t *card_status) -{ - struct card_info_send { - uint8_t ser_op; - uint8_t addr; - } *card_info_send; - struct card_info_recv { - uint8_t ser_op_undef; /* invalid data */ - uint8_t addr; - uint8_t card_full_type; /* (type << 4 | subtype) */ - uint8_t card_status; /* BIT(0) - PIC burned */ - } *card_info_recv; - uint8_t in[sizeof(struct card_info_recv)]; - uint8_t out[sizeof(struct card_info_recv)]; - int len; - int ret; - - len = sizeof(struct card_info_recv); - memset(in, 0, len); - memset(out, 0, len); - card_info_send = (struct card_info_send *)∈ - card_info_recv = (struct card_info_recv *)&out; - card_info_send->ser_op = SER_CARD_INFO_GET; - card_info_send->addr = (unit << 4); /* low nibble is subunit */ - ret = mpp_serial_cmd(astribank, in, out, len); - if(ret < 0) - return ret; - *card_type = card_info_recv->card_full_type; - *card_status = card_info_recv->card_status; - return 0; -} - -int mpp_tws_watchdog(struct astribank_device *astribank) -{ - struct mpp_command *cmd; - struct mpp_command *reply; - int ret; - - DBG("\n"); - assert(astribank != NULL); - if((cmd = new_command(astribank->mpp_proto_version, MPP_TWS_WD_MODE_GET, 0)) == NULL) { - ERR("new_command failed\n"); - return -ENOMEM; - } - ret = process_command(astribank, cmd, &reply); - if(ret < 0) { - ERR("process_command failed: %d\n", ret); - return ret; - } - ret = CMD_FIELD(reply, TWS_WD_MODE_GET_REPLY, wd_active); - DBG("wd_active=0x%X\n", ret); - free_command(reply); - return ret == 1; -} - -int mpp_tws_setwatchdog(struct astribank_device *astribank, int yes) -{ - struct mpp_command *cmd; - struct mpp_command *reply; - int ret; - - DBG("%s\n", (yes) ? "YES" : "NO"); - assert(astribank != NULL); - if((cmd = new_command(astribank->mpp_proto_version, MPP_TWS_WD_MODE_SET, 0)) == NULL) { - ERR("new_command failed\n"); - return -ENOMEM; - } - CMD_FIELD(cmd, TWS_WD_MODE_SET, wd_active) = (yes) ? 1 : 0; - ret = process_command(astribank, cmd, &reply); - if(ret < 0) { - ERR("process_command failed: %d\n", ret); - return ret; - } - free_command(reply); - return 0; -} - -int mpp_tws_powerstate(struct astribank_device *astribank) -{ - struct mpp_command *cmd; - struct mpp_command *reply; - int ret; - - DBG("\n"); - assert(astribank != NULL); - if((cmd = new_command(astribank->mpp_proto_version, MPP_TWS_PWR_GET, 0)) == NULL) { - ERR("new_command failed\n"); - return -ENOMEM; - } - ret = process_command(astribank, cmd, &reply); - if(ret < 0) { - ERR("process_command failed: %d\n", ret); - return ret; - } - ret = CMD_FIELD(reply, TWS_PWR_GET_REPLY, power); - DBG("power=0x%X\n", ret); - free_command(reply); - return ret; -} - -int mpp_tws_portnum(struct astribank_device *astribank) -{ - struct mpp_command *cmd; - struct mpp_command *reply; - int ret; - - DBG("\n"); - assert(astribank != NULL); - if((cmd = new_command(astribank->mpp_proto_version, MPP_TWS_PORT_GET, 0)) == NULL) { - ERR("new_command failed\n"); - return -ENOMEM; - } - ret = process_command(astribank, cmd, &reply); - if(ret < 0) { - ERR("process_command failed: %d\n", ret); - return ret; - } - ret = CMD_FIELD(reply, TWS_PORT_GET_REPLY, portnum); - DBG("portnum=0x%X\n", ret); - free_command(reply); - return ret; -} - -int mpp_tws_setportnum(struct astribank_device *astribank, uint8_t portnum) -{ - struct mpp_command *cmd; - int ret; - - DBG("\n"); - assert(astribank != NULL); - if(portnum >= 2) { - ERR("Invalid portnum (%d)\n", portnum); - return -EINVAL; - } - if((cmd = new_command(astribank->mpp_proto_version, MPP_TWS_PORT_SET, 0)) == NULL) { - ERR("new_command failed\n"); - return -ENOMEM; - } - CMD_FIELD(cmd, TWS_PORT_SET, portnum) = portnum; - ret = process_command(astribank, cmd, NULL); - if(ret < 0) { - ERR("process_command failed: %d\n", ret); - return ret; - } - return 0; -} - -/* - * Wrappers - */ - -struct astribank_device *mpp_init(const char devpath[]) -{ - struct astribank_device *astribank; - int ret; - - DBG("devpath='%s'\n", devpath); - if((astribank = astribank_open(devpath, 1)) == NULL) { - ERR("Opening astribank failed\n"); - return NULL; - } - ret = mpp_proto_query(astribank); - if(ret < 0) { - ERR("Protocol handshake failed: %d\n", ret); - goto err; - } - ret = mpp_status_query(astribank); - if(ret < 0) { - ERR("Status query failed: %d\n", ret); - goto err; - } - return astribank; - -err: - if (astribank) - astribank_close(astribank, 0); - return NULL; -} - -void mpp_exit(struct astribank_device *astribank) -{ - DBG("\n"); - astribank_close(astribank, 0); -} - -/* - * data structures - */ - -void show_eeprom(const struct eeprom_table *eprm, FILE *fp) -{ - int rmajor = (eprm->release >> 8) & 0xFF; - int rminor = eprm->release & 0xFF;; - char buf[BUFSIZ]; - - memset(buf, 0, LABEL_SIZE + 1); - memcpy(buf, eprm->label, LABEL_SIZE); - fprintf(fp, "EEPROM: %-15s: 0x%02X\n", "Source", eprm->source); - fprintf(fp, "EEPROM: %-15s: 0x%04X\n", "Vendor", eprm->vendor); - fprintf(fp, "EEPROM: %-15s: 0x%04X\n", "Product", eprm->product); - fprintf(fp, "EEPROM: %-15s: %d.%d\n", "Release", rmajor, rminor); - fprintf(fp, "EEPROM: %-15s: 0x%02X\n", "Config", eprm->config_byte); - fprintf(fp, "EEPROM: %-15s: '%s'\n", "Label", buf); -} - -void show_capabilities(const struct capabilities *capabilities, FILE *fp) -{ - fprintf(fp, "Capabilities: FXS ports: %2d\n", capabilities->ports_fxs); - fprintf(fp, "Capabilities: FXO ports: %2d\n", capabilities->ports_fxo); - fprintf(fp, "Capabilities: BRI ports: %2d\n", capabilities->ports_bri); - fprintf(fp, "Capabilities: PRI ports: %2d\n", capabilities->ports_pri); - fprintf(fp, "Capabilities: TwinStar : %s\n", - (CAP_EXTRA_TWINSTAR(capabilities)) ? "Yes" : "No"); -} - -void show_astribank_status(struct astribank_device *astribank, FILE *fp) -{ - char version_buf[BUFSIZ]; - int is_loaded = STATUS_FPGA_LOADED(astribank->status); - - fprintf(fp, "Astribank: EEPROM : %s\n", - eeprom_type2str(astribank->eeprom_type)); - fprintf(fp, "Astribank: FPGA status : %s\n", - is_loaded ? "Loaded" : "Empty"); - if(is_loaded) { - memset(version_buf, 0, sizeof(version_buf)); - memcpy(version_buf, astribank->fw_versions.fpga, VERSION_LEN); - fprintf(fp, "Astribank: FPGA version: %s\n", - version_buf); - } -} - -void show_extrainfo(const struct extrainfo *extrainfo, FILE *fp) -{ - fprintf(fp, "Extrainfo: : %s\n", (const char *)(extrainfo->text)); -} - -int twinstar_show(struct astribank_device *astribank, FILE *fp) -{ - int watchdog; - int powerstate; - int portnum; - int i; - - if(!astribank_has_twinstar(astribank)) { - fprintf(fp, "TwinStar: NO\n"); - return 0; - } - if((watchdog = mpp_tws_watchdog(astribank)) < 0) { - ERR("Failed getting TwinStar information\n"); - return watchdog; - } - if((powerstate = mpp_tws_powerstate(astribank)) < 0) { - ERR("Failed getting TwinStar powerstate\n"); - return powerstate; - } - if((portnum = mpp_tws_portnum(astribank)) < 0) { - ERR("Failed getting TwinStar portnum\n"); - return portnum; - } - fprintf(fp, "TwinStar: Connected to : USB-%1d\n", portnum); - fprintf(fp, "TwinStar: Watchdog : %s\n", - (watchdog) ? "on-guard" : "off-guard"); - for(i = 0; i < 2; i++) { - int pw = (1 << i) & powerstate; - - fprintf(fp, "TwinStar: USB-%1d POWER : %s\n", - i, (pw) ? "ON" : "OFF"); - } - return 0; -} - diff --git a/xpp/mpptalk.c b/xpp/mpptalk.c new file mode 100644 index 0000000..a8bf12a --- /dev/null +++ b/xpp/mpptalk.c @@ -0,0 +1,915 @@ +/* + * Written by Oron Peled + * Copyright (C) 2008, Xorcom + * + * All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + */ + +#include +#include +#include +#include +#include +#include "hexfile.h" +#include "astribank_usb.h" +#include "mpp.h" +#include "mpptalk.h" +#include +#include +#include + +static const char rcsid[] = "$Id$"; + +#define DBG_MASK 0x02 + +const char *ack_status_msg(uint8_t status) +{ + const static char *msgs[] = { + [STAT_OK] = "Acknowledges previous command", + [STAT_FAIL] = "Last command failed", + [STAT_RESET_FAIL] = "Reset failed", + [STAT_NODEST] = "No destination is selected", + [STAT_MISMATCH] = "Data mismatch", + [STAT_NOACCESS] = "No access", + [STAT_BAD_CMD] = "Bad command", + [STAT_TOO_SHORT] = "Packet is too short", + [STAT_ERROFFS] = "Offset error", + [STAT_NOCODE] = "Source was not burned before", + [STAT_NO_LEEPROM] = "Large EEPROM was not found", + [STAT_NO_EEPROM] = "No EEPROM was found", + [STAT_WRITE_FAIL] = "Writing to device failed", + [STAT_FPGA_ERR] = "FPGA error", + [STAT_KEY_ERR] = "Bad Capabilities Key", + [STAT_NOCAPS_ERR] = "No matching capability", + [STAT_NOPWR_ERR] = "No power on USB connector", + [STAT_CAPS_FPGA_ERR] = "Setting of the capabilities while FPGA is loaded", + }; + if(status > sizeof(msgs)/sizeof(msgs[0])) + return "ERROR CODE TOO LARGE"; + if(!msgs[status]) + return "MISSING ERROR CODE"; + return msgs[status]; +} + +const char *eeprom_type2str(int et) +{ + const static char *msgs[] = { + [EEPROM_TYPE_NONE] = "NONE", + [EEPROM_TYPE_SMALL] = "SMALL", + [EEPROM_TYPE_LARGE] = "LARGE", + [EEPROM_TYPE_UNUSED] = "UNUSED", + }; + if(et > sizeof(msgs)/sizeof(msgs[0])) + return NULL; + return msgs[et]; +}; + +const char *dev_dest2str(int dest) +{ + const static char *msgs[] = { + [DEST_NONE] = "NONE", + [DEST_FPGA] = "FPGA", + [DEST_EEPROM] = "EEPROM", + }; + if(dest > sizeof(msgs)/sizeof(msgs[0])) + return NULL; + return msgs[dest]; +}; + +union XTALK_PDATA(MPP) { + MEMBER(MPP, STATUS_GET); + MEMBER(MPP, STATUS_GET_REPLY); + MEMBER(MPP, EEPROM_SET); + MEMBER(MPP, CAPS_GET); + MEMBER(MPP, CAPS_GET_REPLY); + MEMBER(MPP, CAPS_SET); + MEMBER(MPP, EXTRAINFO_GET); + MEMBER(MPP, EXTRAINFO_GET_REPLY); + MEMBER(MPP, EXTRAINFO_SET); + MEMBER(MPP, RENUM); + MEMBER(MPP, EEPROM_BLK_RD); + MEMBER(MPP, EEPROM_BLK_RD_REPLY); + MEMBER(MPP, DEV_SEND_SEG); + MEMBER(MPP, DEV_SEND_START); + MEMBER(MPP, DEV_SEND_END); + MEMBER(MPP, RESET); + MEMBER(MPP, HALF_RESET); + MEMBER(MPP, SER_SEND); + MEMBER(MPP, SER_RECV); + /* Twinstar */ + MEMBER(MPP, TWS_WD_MODE_SET); + MEMBER(MPP, TWS_WD_MODE_GET); + MEMBER(MPP, TWS_WD_MODE_GET_REPLY); + MEMBER(MPP, TWS_PORT_SET); + MEMBER(MPP, TWS_PORT_GET); + MEMBER(MPP, TWS_PORT_GET_REPLY); + MEMBER(MPP, TWS_PWR_GET); + MEMBER(MPP, TWS_PWR_GET_REPLY); +} PACKED members; + +struct xtalk_protocol astribank_proto = { + .name = "ABNK", + .proto_version = 0x14, + .commands = { + CMD_SEND(MPP, STATUS_GET), + CMD_RECV(MPP, STATUS_GET_REPLY, NULL), + CMD_SEND(MPP, EEPROM_SET), + CMD_SEND(MPP, CAPS_GET), + CMD_RECV(MPP, CAPS_GET_REPLY, NULL), + CMD_SEND(MPP, CAPS_SET), + CMD_SEND(MPP, EXTRAINFO_GET), + CMD_RECV(MPP, EXTRAINFO_GET_REPLY, NULL), + CMD_SEND(MPP, EXTRAINFO_SET), + CMD_SEND(MPP, RENUM), + CMD_SEND(MPP, EEPROM_BLK_RD), + CMD_RECV(MPP, EEPROM_BLK_RD_REPLY, NULL), + CMD_SEND(MPP, DEV_SEND_SEG), + CMD_SEND(MPP, DEV_SEND_START), + CMD_SEND(MPP, DEV_SEND_END), + CMD_SEND(MPP, RESET), + CMD_SEND(MPP, HALF_RESET), + CMD_SEND(MPP, SER_SEND), + CMD_SEND(MPP, SER_RECV), + /* Twinstar */ + CMD_SEND(MPP, TWS_WD_MODE_SET), + CMD_SEND(MPP, TWS_WD_MODE_GET), + CMD_RECV(MPP, TWS_WD_MODE_GET_REPLY, NULL), + CMD_SEND(MPP, TWS_PORT_SET), + CMD_SEND(MPP, TWS_PORT_GET), + CMD_RECV(MPP, TWS_PORT_GET_REPLY, NULL), + CMD_SEND(MPP, TWS_PWR_GET), + CMD_RECV(MPP, TWS_PWR_GET_REPLY, NULL), + }, + .ack_statuses = { + } +}; + +struct cmd_queue { + struct cmd_queue *next; + struct cmd_queue *prev; + struct xtalk_command *cmd; +}; + +static struct cmd_queue output_queue = { + .next = &output_queue, + .prev = &output_queue, + .cmd = NULL + }; + +void dump_command(struct xtalk_command *cmd) +{ + uint16_t len; + int i; + + len = cmd->header.len; + if(len < sizeof(struct mpp_header)) { + ERR("Command too short (%d)\n", len); + return; + } + INFO("DUMP: OP=0x%X len=%d seq=%d\n", + cmd->header.op, cmd->header.len, cmd->header.seq); + for(i = 0; i < len - sizeof(struct mpp_header); i++) { + INFO(" %2d. 0x%X\n", i, cmd->alt.raw_data[i]); + } +} + + +static int set_ihex_version(char *dst, const char *src) +{ + memcpy(dst, src, VERSION_LEN); + return 0; +} + +/* + * Protocol Commands + */ + +int mpp_status_query(struct astribank_device *astribank) +{ + struct xtalk_command *cmd; + struct xtalk_command *reply; + struct xtalk_device *xtalk_dev; + int ret; + + DBG("\n"); + assert(astribank != NULL); + xtalk_dev = astribank->xtalk_dev; + if((cmd = new_command(xtalk_dev, MPP_STATUS_GET, 0)) == NULL) { + ERR("new_command failed\n"); + return -ENOMEM; + } + ret = process_command(xtalk_dev, cmd, &reply); + if(ret < 0) { + ERR("process_command failed: %d\n", ret); + return ret; + } + astribank->eeprom_type = 0x3 & (CMD_FIELD(reply, MPP, STATUS_GET_REPLY, i2cs_data) >> 3); + astribank->status = CMD_FIELD(reply, MPP, STATUS_GET_REPLY, status); + astribank->fw_versions = CMD_FIELD(reply, MPP, STATUS_GET_REPLY, fw_versions); + DBG("EEPROM TYPE: %02x\n", astribank->eeprom_type); + DBG("FPGA Firmware: %s\n", (astribank->status & 0x1) ? "Loaded" : "Empty"); + DBG("Firmware Versions: USB='%s' FPGA='%s' EEPROM='%s'\n", + astribank->fw_versions.usb, + astribank->fw_versions.fpga, + astribank->fw_versions.eeprom); + free_command(reply); + return ret; +} + +int mpp_eeprom_set(struct astribank_device *astribank, const struct eeprom_table *et) +{ + struct xtalk_command *cmd; + struct xtalk_command *reply; + struct xtalk_device *xtalk_dev; + int ret; + + DBG("\n"); + assert(astribank != NULL); + xtalk_dev = astribank->xtalk_dev; + if((cmd = new_command(xtalk_dev, MPP_EEPROM_SET, 0)) == NULL) { + ERR("new_command failed\n"); + return -ENOMEM; + } + memcpy(&CMD_FIELD(cmd, MPP, EEPROM_SET, data), et, sizeof(*et)); + ret = process_command(xtalk_dev, cmd, &reply); + if(ret < 0) { + ERR("process_command failed: %d\n", ret); + return ret; + } + free_command(reply); + return 0; +} + +int mpp_renumerate(struct astribank_device *astribank) +{ + struct xtalk_command *cmd; + struct xtalk_device *xtalk_dev; + int ret; + + DBG("\n"); + assert(astribank != NULL); + xtalk_dev = astribank->xtalk_dev; + if((cmd = new_command(xtalk_dev, MPP_RENUM, 0)) == NULL) { + ERR("new_command failed\n"); + return -ENOMEM; + } + ret = process_command(xtalk_dev, cmd, NULL); + if(ret < 0) { + ERR("process_command failed: %d\n", ret); + return ret; + } + return 0; +} + +int mpp_caps_get(struct astribank_device *astribank, + struct eeprom_table *eeprom_table, + struct capabilities *capabilities, + struct capkey *key) +{ + struct xtalk_command *cmd; + struct xtalk_command *reply; + struct xtalk_device *xtalk_dev; + int ret; + + DBG("\n"); + assert(astribank != NULL); + xtalk_dev = astribank->xtalk_dev; + if((cmd = new_command(xtalk_dev, MPP_CAPS_GET, 0)) == NULL) { + ERR("new_command failed\n"); + return -ENOMEM; + } + ret = process_command(xtalk_dev, cmd, &reply); + if(ret < 0) { + ERR("process_command failed: %d\n", ret); + return ret; + } + assert(reply->header.op == MPP_CAPS_GET_REPLY); + if(eeprom_table) { + memcpy(eeprom_table, (void *)&CMD_FIELD(reply, MPP, CAPS_GET_REPLY, data), sizeof(*eeprom_table)); + } + if(capabilities) { + const struct capabilities *cap = &CMD_FIELD(reply, MPP, CAPS_GET_REPLY, capabilities); + + memcpy(capabilities, cap, sizeof(*capabilities)); + } + if(key) { + const struct capkey *k = &CMD_FIELD(reply, MPP, CAPS_GET_REPLY, key); + + memcpy(key, k, sizeof(*key)); + } + free_command(reply); + return 0; +} + +int mpp_caps_set(struct astribank_device *astribank, + const struct eeprom_table *eeprom_table, + const struct capabilities *capabilities, + const struct capkey *key) +{ + struct xtalk_command *cmd; + struct xtalk_command *reply; + struct xtalk_device *xtalk_dev; + int ret; + + DBG("\n"); + assert(astribank != NULL); + xtalk_dev = astribank->xtalk_dev; + if((cmd = new_command(xtalk_dev, MPP_CAPS_SET, 0)) == NULL) { + ERR("new_command failed\n"); + return -ENOMEM; + } + memcpy(&CMD_FIELD(cmd, MPP, CAPS_SET, data), eeprom_table, sizeof(*eeprom_table)); + memcpy(&CMD_FIELD(cmd, MPP, CAPS_SET, capabilities), capabilities, sizeof(*capabilities)); + memcpy(&CMD_FIELD(cmd, MPP, CAPS_SET, key), key, sizeof(*key)); + ret = process_command(xtalk_dev, cmd, &reply); + if(ret < 0) { + ERR("process_command failed: %d\n", ret); + return ret; + } + free_command(reply); + return 0; +} + +int mpp_extrainfo_get(struct astribank_device *astribank, struct extrainfo *info) +{ + struct xtalk_command *cmd; + struct xtalk_command *reply; + struct xtalk_device *xtalk_dev; + int ret; + + DBG("\n"); + assert(astribank != NULL); + xtalk_dev = astribank->xtalk_dev; + if((cmd = new_command(xtalk_dev, MPP_EXTRAINFO_GET, 0)) == NULL) { + ERR("new_command failed\n"); + return -ENOMEM; + } + ret = process_command(xtalk_dev, cmd, &reply); + if(ret < 0) { + ERR("process_command failed: %d\n", ret); + return ret; + } + assert(reply->header.op == MPP_EXTRAINFO_GET_REPLY); + if(info) { + memcpy(info, (void *)&CMD_FIELD(reply, MPP, EXTRAINFO_GET_REPLY, info), sizeof(*info)); + } + free_command(reply); + return 0; +} + +int mpp_extrainfo_set(struct astribank_device *astribank, const struct extrainfo *info) +{ + struct xtalk_command *cmd; + struct xtalk_command *reply; + struct xtalk_device *xtalk_dev; + int ret; + + DBG("\n"); + assert(astribank != NULL); + xtalk_dev = astribank->xtalk_dev; + if((cmd = new_command(xtalk_dev, MPP_EXTRAINFO_SET, 0)) == NULL) { + ERR("new_command failed\n"); + return -ENOMEM; + } + memcpy(&CMD_FIELD(cmd, MPP, EXTRAINFO_SET, info), info, sizeof(*info)); + ret = process_command(xtalk_dev, cmd, &reply); + if(ret < 0) { + ERR("process_command failed: %d\n", ret); + return ret; + } + free_command(reply); + return 0; +} + +int mpp_eeprom_blk_rd(struct astribank_device *astribank, uint8_t *buf, uint16_t offset, uint16_t len) +{ + struct xtalk_command *cmd; + struct xtalk_command *reply; + struct xtalk_device *xtalk_dev; + int ret; + int size; + + DBG("len = %d, offset = %d\n", len, offset); + assert(astribank != NULL); + xtalk_dev = astribank->xtalk_dev; + if((cmd = new_command(xtalk_dev, MPP_EEPROM_BLK_RD, 0)) == NULL) { + ERR("new_command failed\n"); + return -ENOMEM; + } + CMD_FIELD(cmd, MPP, EEPROM_BLK_RD, len) = len; + CMD_FIELD(cmd, MPP, EEPROM_BLK_RD, offset) = offset; + ret = process_command(xtalk_dev, cmd, &reply); + if(ret < 0) { + ERR("process_command failed: %d\n", ret); + size = ret; + goto out; + } + size = reply->header.len - sizeof(struct mpp_header) - sizeof(XTALK_STRUCT(MPP, EEPROM_BLK_RD_REPLY)); + INFO("size=%d offset=0x%X\n", size, CMD_FIELD(reply, MPP, EEPROM_BLK_RD_REPLY, offset)); + dump_packet(LOG_DEBUG, DBG_MASK, "BLK_RD", (char *)reply, ret); + if(size > len) { + ERR("Truncating reply (was %d, now %d)\n", size, len); + size = len; + } + memcpy(buf, CMD_FIELD(reply, MPP, EEPROM_BLK_RD_REPLY, data), size); +out: + free_command(reply); + return size; +} + +int mpp_send_start(struct astribank_device *astribank, int dest, const char *ihex_version) +{ + struct xtalk_command *cmd; + struct xtalk_command *reply = NULL; + struct xtalk_device *xtalk_dev; + int ret = 0; + + DBG("dest = %s ihex_version = '%s'\n", dev_dest2str(dest), ihex_version); + assert(astribank != NULL); + xtalk_dev = astribank->xtalk_dev; + if((cmd = new_command(xtalk_dev, MPP_DEV_SEND_START, 0)) == NULL) { + ERR("new_command failed\n"); + ret = -ENOMEM; + goto out; + } + CMD_FIELD(cmd, MPP, DEV_SEND_START, dest) = dest; + set_ihex_version(CMD_FIELD(cmd, MPP, DEV_SEND_START, ihex_version), ihex_version); + ret = process_command(xtalk_dev, cmd, &reply); + if(ret < 0) { + ERR("process_command failed: %d\n", ret); + goto out; + } +out: + if(reply) + free_command(reply); + astribank->burn_state = (ret == 0) + ? BURN_STATE_STARTED + : BURN_STATE_FAILED; + return ret; +} + +int mpp_send_end(struct astribank_device *astribank) +{ + struct xtalk_command *cmd; + struct xtalk_command *reply = NULL; + struct xtalk_device *xtalk_dev; + int ret = 0; + + DBG("\n"); + assert(astribank != NULL); + xtalk_dev = astribank->xtalk_dev; + if((cmd = new_command(xtalk_dev, MPP_DEV_SEND_END, 0)) == NULL) { + ERR("new_command failed\n"); + ret = -ENOMEM; + goto out; + } + ret = process_command(xtalk_dev, cmd, &reply); + if(ret < 0) { + ERR("process_command failed: %d\n", ret); + goto out; + } +out: + if(reply) + free_command(reply); + astribank->burn_state = (ret == 0) + ? BURN_STATE_ENDED + : BURN_STATE_FAILED; + return ret; +} + +int mpp_send_seg(struct astribank_device *astribank, const uint8_t *data, uint16_t offset, uint16_t len) +{ + struct xtalk_command *cmd; + struct xtalk_command *reply; + struct xtalk_device *xtalk_dev; + int ret; + + assert(astribank != NULL); + xtalk_dev = astribank->xtalk_dev; + if(!astribank->burn_state == BURN_STATE_STARTED) { + ERR("Tried to send a segment while burn_state=%d\n", + astribank->burn_state); + return -EINVAL; + } + DBG("len = %d, offset = %d (0x%02X, 0x%02X)\n", len, offset, *data, *(data + 1)); + if((cmd = new_command(xtalk_dev, MPP_DEV_SEND_SEG, len)) == NULL) { + ERR("new_command failed\n"); + return -ENOMEM; + } + CMD_FIELD(cmd, MPP, DEV_SEND_SEG, offset) = offset; + memcpy(CMD_FIELD(cmd, MPP, DEV_SEND_SEG, data), data, len); +#if 0 + { + FILE *fp; + if((fp = fopen("seg_data.bin", "a")) == NULL) { + perror("seg_data.bin"); + exit(1); + } + if(fwrite(CMD_FIELD(cmd, MPP, DEV_SEND_SEG, data), len, 1, fp) != 1) { + perror("fwrite"); + exit(1); + } + fclose(fp); + } +#endif + ret = process_command(xtalk_dev, cmd, &reply); + if(ret < 0) { + ERR("process_command failed: %d\n", ret); + return ret; + } + free_command(reply); + return 0; +} + +int mpp_reset(struct astribank_device *astribank, int full_reset) +{ + struct xtalk_command *cmd; + struct xtalk_device *xtalk_dev; + int ret; + int op = (full_reset) ? MPP_RESET: MPP_HALF_RESET; + + DBG("full = %s\n", (full_reset) ? "YES" : "NO"); + assert(astribank != NULL); + xtalk_dev = astribank->xtalk_dev; + if((cmd = new_command(xtalk_dev, op, 0)) == NULL) { + ERR("new_command failed\n"); + return -ENOMEM; + } + ret = process_command(xtalk_dev, cmd, NULL); + if(ret < 0) { + ERR("process_command failed: %d\n", ret); + return ret; + } + return 0; +} + +int mpp_serial_cmd(struct astribank_device *astribank, const uint8_t *in, uint8_t *out, uint16_t len) +{ + struct xtalk_command *cmd; + struct xtalk_command *reply; + struct xtalk_device *xtalk_dev; + int ret; + uint8_t *data; + + DBG("len=%d\n", len); + assert(astribank != NULL); + xtalk_dev = astribank->xtalk_dev; + if((cmd = new_command(xtalk_dev, MPP_SER_SEND, len)) == NULL) { + ERR("new_command failed\n"); + return -ENOMEM; + } + data = CMD_FIELD(cmd, MPP, SER_SEND, data); + memcpy(data, in, len); + ret = process_command(xtalk_dev, cmd, &reply); + if(ret < 0) { + ERR("process_command failed: %d\n", ret); + return ret; + } + assert(reply->header.op == MPP_SER_RECV); + data = CMD_FIELD(reply, MPP, SER_RECV, data); + memcpy(out, data, len); + free_command(reply); + return 0; +} + +int mpps_card_info(struct astribank_device *astribank, int unit, uint8_t *card_type, uint8_t *card_status) +{ + struct card_info_send { + uint8_t ser_op; + uint8_t addr; + } *card_info_send; + struct card_info_recv { + uint8_t ser_op_undef; /* invalid data */ + uint8_t addr; + uint8_t card_full_type; /* (type << 4 | subtype) */ + uint8_t card_status; /* BIT(0) - PIC burned */ + } *card_info_recv; + uint8_t in[sizeof(struct card_info_recv)]; + uint8_t out[sizeof(struct card_info_recv)]; + int len; + int ret; + + len = sizeof(struct card_info_recv); + memset(in, 0, len); + memset(out, 0, len); + card_info_send = (struct card_info_send *)∈ + card_info_recv = (struct card_info_recv *)&out; + card_info_send->ser_op = SER_CARD_INFO_GET; + card_info_send->addr = (unit << 4); /* low nibble is subunit */ + ret = mpp_serial_cmd(astribank, in, out, len); + if(ret < 0) + return ret; + *card_type = card_info_recv->card_full_type; + *card_status = card_info_recv->card_status; + return 0; +} + +int mpp_tws_watchdog(struct astribank_device *astribank) +{ + struct xtalk_command *cmd; + struct xtalk_command *reply; + struct xtalk_device *xtalk_dev; + int ret; + + DBG("\n"); + assert(astribank != NULL); + xtalk_dev = astribank->xtalk_dev; + if((cmd = new_command(xtalk_dev, MPP_TWS_WD_MODE_GET, 0)) == NULL) { + ERR("new_command failed\n"); + return -ENOMEM; + } + ret = process_command(xtalk_dev, cmd, &reply); + if(ret < 0) { + ERR("process_command failed: %d\n", ret); + return ret; + } + ret = CMD_FIELD(reply, MPP, TWS_WD_MODE_GET_REPLY, wd_active); + DBG("wd_active=0x%X\n", ret); + free_command(reply); + return ret == 1; +} + +int mpp_tws_setwatchdog(struct astribank_device *astribank, int yes) +{ + struct xtalk_command *cmd; + struct xtalk_command *reply; + struct xtalk_device *xtalk_dev; + int ret; + + DBG("%s\n", (yes) ? "YES" : "NO"); + assert(astribank != NULL); + xtalk_dev = astribank->xtalk_dev; + if((cmd = new_command(xtalk_dev, MPP_TWS_WD_MODE_SET, 0)) == NULL) { + ERR("new_command failed\n"); + return -ENOMEM; + } + CMD_FIELD(cmd, MPP, TWS_WD_MODE_SET, wd_active) = (yes) ? 1 : 0; + ret = process_command(xtalk_dev, cmd, &reply); + if(ret < 0) { + ERR("process_command failed: %d\n", ret); + return ret; + } + free_command(reply); + return 0; +} + +int mpp_tws_powerstate(struct astribank_device *astribank) +{ + struct xtalk_command *cmd; + struct xtalk_command *reply; + struct xtalk_device *xtalk_dev; + int ret; + + DBG("\n"); + assert(astribank != NULL); + xtalk_dev = astribank->xtalk_dev; + if((cmd = new_command(xtalk_dev, MPP_TWS_PWR_GET, 0)) == NULL) { + ERR("new_command failed\n"); + return -ENOMEM; + } + ret = process_command(xtalk_dev, cmd, &reply); + if(ret < 0) { + ERR("process_command failed: %d\n", ret); + return ret; + } + ret = CMD_FIELD(reply, MPP, TWS_PWR_GET_REPLY, power); + DBG("power=0x%X\n", ret); + free_command(reply); + return ret; +} + +int mpp_tws_portnum(struct astribank_device *astribank) +{ + struct xtalk_command *cmd; + struct xtalk_command *reply; + struct xtalk_device *xtalk_dev; + int ret; + + DBG("\n"); + assert(astribank != NULL); + xtalk_dev = astribank->xtalk_dev; + if((cmd = new_command(xtalk_dev, MPP_TWS_PORT_GET, 0)) == NULL) { + ERR("new_command failed\n"); + return -ENOMEM; + } + ret = process_command(xtalk_dev, cmd, &reply); + if(ret < 0) { + ERR("process_command failed: %d\n", ret); + return ret; + } + ret = CMD_FIELD(reply, MPP, TWS_PORT_GET_REPLY, portnum); + DBG("portnum=0x%X\n", ret); + free_command(reply); + return ret; +} + +int mpp_tws_setportnum(struct astribank_device *astribank, uint8_t portnum) +{ + struct xtalk_command *cmd; + struct xtalk_device *xtalk_dev; + int ret; + + DBG("\n"); + assert(astribank != NULL); + xtalk_dev = astribank->xtalk_dev; + if(portnum >= 2) { + ERR("Invalid portnum (%d)\n", portnum); + return -EINVAL; + } + if((cmd = new_command(xtalk_dev, MPP_TWS_PORT_SET, 0)) == NULL) { + ERR("new_command failed\n"); + return -ENOMEM; + } + CMD_FIELD(cmd, MPP, TWS_PORT_SET, portnum) = portnum; + ret = process_command(xtalk_dev, cmd, NULL); + if(ret < 0) { + ERR("process_command failed: %d\n", ret); + return ret; + } + return 0; +} + +/* Adapters for xusb ops */ +static inline int xusb_close_func(void *priv) +{ + return xusb_close((struct xusb *)priv); +} + +static inline int xusb_send_func(void *priv, void *data, size_t len, int timeout) +{ + return xusb_send((struct xusb *)priv, data, len, timeout); +} + +static inline int xusb_recv_func(void *priv, void *data, size_t maxlen, int timeout) +{ + return xusb_recv((struct xusb *)priv, data, maxlen, timeout); +} + + +static struct xtalk_ops xusb_ops = { + .send_func = xusb_send_func, + .recv_func = xusb_recv_func, + .close_func = xusb_close_func, +}; + +/* + * Wrappers + */ + +struct astribank_device *mpp_init(const char devpath[], int iface_num) +{ + struct astribank_device *astribank = NULL; + struct xtalk_device *xtalk_dev = NULL; + struct xusb *xusb = NULL; + int packet_size; + int ret; + + DBG("devpath='%s' iface_num=%d\n", devpath, iface_num); + if((astribank = astribank_open(devpath, iface_num)) == NULL) { + ERR("Opening astribank failed\n"); + goto err; + } + xusb = astribank->xusb; + packet_size = xusb_packet_size(xusb); + if((xtalk_dev = xtalk_new(&xusb_ops, packet_size, xusb)) == NULL) { + ERR("Allocating new XTALK device failed\n"); + goto err; + } + astribank->xtalk_dev = xtalk_dev; + ret = xtalk_set_protocol(xtalk_dev, &astribank_proto); + if(ret < 0) { + ERR("MPP Protocol registration failed: %d\n", ret); + goto err; + } + ret = xtalk_proto_query(xtalk_dev); + if(ret < 0) { + ERR("Protocol handshake failed: %d\n", ret); + goto err; + } + ret = mpp_status_query(astribank); + if(ret < 0) { + ERR("Status query failed: %d\n", ret); + goto err; + } + return astribank; + +err: + if (astribank) { + astribank_close(astribank, 0); + astribank = NULL; + } + if(xtalk_dev) { + xtalk_delete(xtalk_dev); + xtalk_dev = NULL; + } + return NULL; +} + +void mpp_exit(struct astribank_device *astribank) +{ + DBG("\n"); + astribank_close(astribank, 0); +} + +/* + * data structures + */ + +void show_eeprom(const struct eeprom_table *eprm, FILE *fp) +{ + int rmajor = (eprm->release >> 8) & 0xFF; + int rminor = eprm->release & 0xFF;; + char buf[BUFSIZ]; + + memset(buf, 0, LABEL_SIZE + 1); + memcpy(buf, eprm->label, LABEL_SIZE); + fprintf(fp, "EEPROM: %-15s: 0x%02X\n", "Source", eprm->source); + fprintf(fp, "EEPROM: %-15s: 0x%04X\n", "Vendor", eprm->vendor); + fprintf(fp, "EEPROM: %-15s: 0x%04X\n", "Product", eprm->product); + fprintf(fp, "EEPROM: %-15s: %d.%d\n", "Release", rmajor, rminor); + fprintf(fp, "EEPROM: %-15s: 0x%02X\n", "Config", eprm->config_byte); + fprintf(fp, "EEPROM: %-15s: '%s'\n", "Label", buf); +} + +void show_capabilities(const struct capabilities *capabilities, FILE *fp) +{ + fprintf(fp, "Capabilities: FXS ports: %2d\n", capabilities->ports_fxs); + fprintf(fp, "Capabilities: FXO ports: %2d\n", capabilities->ports_fxo); + fprintf(fp, "Capabilities: BRI ports: %2d\n", capabilities->ports_bri); + fprintf(fp, "Capabilities: PRI ports: %2d\n", capabilities->ports_pri); + fprintf(fp, "Capabilities: ECHO ports: %2d\n", capabilities->ports_echo); + fprintf(fp, "Capabilities: TwinStar : %s\n", + (CAP_EXTRA_TWINSTAR(capabilities)) ? "Yes" : "No"); +} + +void show_astribank_status(struct astribank_device *astribank, FILE *fp) +{ + char version_buf[BUFSIZ]; + int is_loaded = STATUS_FPGA_LOADED(astribank->status); + + fprintf(fp, "Astribank: EEPROM : %s\n", + eeprom_type2str(astribank->eeprom_type)); + fprintf(fp, "Astribank: FPGA status : %s\n", + is_loaded ? "Loaded" : "Empty"); + if(is_loaded) { + memset(version_buf, 0, sizeof(version_buf)); + memcpy(version_buf, astribank->fw_versions.fpga, VERSION_LEN); + fprintf(fp, "Astribank: FPGA version: %s\n", + version_buf); + } +} + +void show_extrainfo(const struct extrainfo *extrainfo, FILE *fp) +{ + fprintf(fp, "Extrainfo: : %s\n", (const char *)(extrainfo->text)); +} + +int twinstar_show(struct astribank_device *astribank, FILE *fp) +{ + int watchdog; + int powerstate; + int portnum; + int i; + + if(!astribank_has_twinstar(astribank)) { + fprintf(fp, "TwinStar: NO\n"); + return 0; + } + if((watchdog = mpp_tws_watchdog(astribank)) < 0) { + ERR("Failed getting TwinStar information\n"); + return watchdog; + } + if((powerstate = mpp_tws_powerstate(astribank)) < 0) { + ERR("Failed getting TwinStar powerstate\n"); + return powerstate; + } + if((portnum = mpp_tws_portnum(astribank)) < 0) { + ERR("Failed getting TwinStar portnum\n"); + return portnum; + } + fprintf(fp, "TwinStar: Connected to : USB-%1d\n", portnum); + fprintf(fp, "TwinStar: Watchdog : %s\n", + (watchdog) ? "on-guard" : "off-guard"); + for(i = 0; i < 2; i++) { + int pw = (1 << i) & powerstate; + + fprintf(fp, "TwinStar: USB-%1d POWER : %s\n", + i, (pw) ? "ON" : "OFF"); + } + return 0; +} diff --git a/xpp/mpp_funcs.h b/xpp/mpptalk.h similarity index 85% rename from xpp/mpp_funcs.h rename to xpp/mpptalk.h index 59bbc7d..ca3e0f9 100644 --- a/xpp/mpp_funcs.h +++ b/xpp/mpptalk.h @@ -22,13 +22,22 @@ * */ +#include +#include + #include "mpp.h" #include "astribank_usb.h" -#define TIMEOUT 2000 +struct astribank_device; +struct eeprom_table; +struct extrainfo; +struct capabilities; +struct capkey; + +#define TIMEOUT 6000 /* high-level */ -struct astribank_device *mpp_init(const char devpath[]); +struct astribank_device *mpp_init(const char devpath[], int iface_num); void mpp_exit(struct astribank_device *astribank); int mpp_proto_query(struct astribank_device *astribank); int mpp_status_query(struct astribank_device *astribank); @@ -45,7 +54,7 @@ int mpp_caps_set(struct astribank_device *astribank, int mpp_extrainfo_get(struct astribank_device *astribank, struct extrainfo *info); int mpp_extrainfo_set(struct astribank_device *astribank, const struct extrainfo *info); int mpp_eeprom_blk_rd(struct astribank_device *astribank, uint8_t *buf, uint16_t offset, uint16_t len); -int mpp_send_start(struct astribank_device *astribank, enum dev_dest dest, const char *ihex_version); +int mpp_send_start(struct astribank_device *astribank, int dest, const char *ihex_version); int mpp_send_end(struct astribank_device *astribank); int mpp_send_seg(struct astribank_device *astribank, const uint8_t *data, uint16_t offset, uint16_t len); int mpp_reset(struct astribank_device *astribank, int full_reset); @@ -70,11 +79,6 @@ int mpp_tws_powerstate(struct astribank_device *astribank); int mpp_tws_portnum(struct astribank_device *astribank); int mpp_tws_setportnum(struct astribank_device *astribank, uint8_t portnum); -/* low-level */ -int process_command(struct astribank_device *astribank, struct mpp_command *cmd, struct mpp_command **reply_ref); -struct mpp_command *new_command(uint8_t protocol_version, uint8_t op, uint16_t extra_data); -void free_command(struct mpp_command *cmd); - -const char *dev_dest2str(enum dev_dest dest); +const char *dev_dest2str(int dest); #endif /* MPP_FUNCS_H */ diff --git a/xpp/mpptalk_defs.h b/xpp/mpptalk_defs.h new file mode 100644 index 0000000..e38f381 --- /dev/null +++ b/xpp/mpptalk_defs.h @@ -0,0 +1,111 @@ +#ifndef MPPTALK_DEFS_H +#define MPPTALK_DEFS_H +/* + * Written by Oron Peled + * Copyright (C) 2008,2009,2010 Xorcom + * + * All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + */ + +#include +/* + * MPP - Managment Processor Protocol definitions + */ + +/* + * OP Codes: + * MSB of op signifies a reply from device + */ +#define MPP_RENUM 0x0B /* Trigger USB renumeration */ +#define MPP_EEPROM_SET 0x0D + +/* AB capabilities */ +#define MPP_CAPS_GET 0x0E +#define MPP_CAPS_GET_REPLY 0x8E +#define MPP_CAPS_SET 0x0F + +#define MPP_DEV_SEND_START 0x05 +#define MPP_DEV_SEND_SEG 0x07 +#define MPP_DEV_SEND_END 0x09 + +/* Astribank Status */ +#define MPP_STATUS_GET 0x11 +#define MPP_STATUS_GET_REPLY 0x91 +#define MPP_STATUS_GET_REPLY_V13 0x91 /* backward compat */ + +/* Get extra vendor information */ +#define MPP_EXTRAINFO_GET 0x13 +#define MPP_EXTRAINFO_GET_REPLY 0x93 +#define MPP_EXTRAINFO_SET 0x15 /* Set extra vendor information */ + +#define MPP_EEPROM_BLK_RD 0x27 +#define MPP_EEPROM_BLK_RD_REPLY 0xA7 + +#define MPP_SER_SEND 0x37 +#define MPP_SER_RECV 0xB7 + +#define MPP_RESET 0x45 /* Reset both FPGA and USB firmwares */ +#define MPP_HALF_RESET 0x47 /* Reset only FPGA firmware */ + +/* Twinstar */ +#define MPP_TWS_WD_MODE_SET 0x31 /* Set watchdog off/on guard */ +#define MPP_TWS_WD_MODE_GET 0x32 /* Current watchdog mode */ +#define MPP_TWS_WD_MODE_GET_REPLY 0xB2 /* Current watchdog mode */ +#define MPP_TWS_PORT_SET 0x34 /* USB-[0/1] */ +#define MPP_TWS_PORT_GET 0x35 /* USB-[0/1] */ +#define MPP_TWS_PORT_GET_REPLY 0xB5 /* USB-[0/1] */ +#define MPP_TWS_PWR_GET 0x36 /* Power: bits -> USB ports */ +#define MPP_TWS_PWR_GET_REPLY 0xB6 /* Power: bits -> USB ports */ + +/* + * Statuses + */ +#define STAT_OK 0x00 /* acknowledges previous command */ +#define STAT_FAIL 0x01 /* Last command failed */ +#define STAT_RESET_FAIL 0x02 /* reset failed */ +#define STAT_NODEST 0x03 /* No destination is selected */ +#define STAT_MISMATCH 0x04 /* Data mismatch */ +#define STAT_NOACCESS 0x05 /* No access */ +#define STAT_BAD_CMD 0x06 /* Bad command */ +#define STAT_TOO_SHORT 0x07 /* Packet is too short */ +#define STAT_ERROFFS 0x08 /* Offset error */ +#define STAT_NOCODE 0x09 /* Source was not burned before */ +#define STAT_NO_LEEPROM 0x0A /* Large EEPROM was not found */ +#define STAT_NO_EEPROM 0x0B /* No EEPROM was found */ +#define STAT_WRITE_FAIL 0x0C /* Writing to device failed */ +#define STAT_FPGA_ERR 0x0D /* FPGA error */ +#define STAT_KEY_ERR 0x0E /* Bad Capabilities Key */ +#define STAT_NOCAPS_ERR 0x0F /* No matching capability */ +#define STAT_NOPWR_ERR 0x10 /* No power on USB connector */ +#define STAT_CAPS_FPGA_ERR 0x11 /* Setting of the capabilities while FPGA is loaded */ + +/* EEPROM_QUERY: i2cs(ID1, ID0) */ +enum eeprom_type { + EEPROM_TYPE_NONE = 0, + EEPROM_TYPE_SMALL = 1, + EEPROM_TYPE_LARGE = 2, + EEPROM_TYPE_UNUSED = 3, +}; + +enum dev_dest { + DEST_NONE = 0x00, + DEST_FPGA = 0x01, + DEST_EEPROM = 0x02, +}; + +#endif /* MPPTALK_DEFS_H */ diff --git a/xpp/pic_loader.c b/xpp/pic_loader.c index ed80f22..c6ed3f1 100644 --- a/xpp/pic_loader.c +++ b/xpp/pic_loader.c @@ -27,7 +27,8 @@ #include #include "hexfile.h" #include "pic_loader.h" -#include "debug.h" +#include +#include #define DBG_MASK 0x03 #define MAX_HEX_LINES 10000 @@ -87,16 +88,16 @@ int send_picline(struct astribank_device *astribank, uint8_t card_type, enum pic } DBG("PICLINE: pack_len=%d pcmd=%d\n", pack_len, pcmd); - dump_packet(LOG_DEBUG, "dump:picline[W]", (char *)phead, pack_len); + dump_packet(LOG_DEBUG, DBG_MASK, "dump:picline[W]", (char *)phead, pack_len); - ret = send_usb(astribank, buf, pack_len, TIMEOUT); + ret = xusb_send(astribank->xusb, buf, pack_len, TIMEOUT); if(ret < 0) { - ERR("send_usb failed: %d\n", ret); + ERR("xusb_send failed: %d\n", ret); return ret; } - DBG("send_usb: Written %d bytes\n", ret); + DBG("xusb_send: Written %d bytes\n", ret); if (recv_answer) { - ret = recv_usb(astribank, buf, sizeof(buf), TIMEOUT); + ret = xusb_recv(astribank->xusb, buf, sizeof(buf), TIMEOUT); if(ret <= 0) { ERR("No USB packs to read\n"); return ret; @@ -104,7 +105,7 @@ int send_picline(struct astribank_device *astribank, uint8_t card_type, enum pic phead = (struct xpp_packet_header *)buf; if(phead->header.op != PIC_REP_XOP) { ERR("Got unexpected reply OP=0x%02X\n", phead->header.op); - dump_packet(LOG_ERR, "hexline[ERR]", buf, ret); + dump_packet(LOG_ERR, DBG_MASK, "hexline[ERR]", buf, ret); return -EINVAL; } DBG("received OP=0x%02X, checksum=%02X\n", phead->header.op, phead->d.pic_packet.data[0]); @@ -180,18 +181,24 @@ static int pic_burn(struct astribank_device *astribank, const struct hexdata *he uint8_t card_type; int ret; unsigned int i; + const char *devstr; v = (v[0]) ? v : "Unknown"; assert(astribank != NULL); assert(hexdata != NULL); + devstr = xusb_devpath(astribank->xusb); if(!astribank->is_usb2) { - ERR("Skip PIC burning (not USB2)\n"); + ERR("%s: Skip PIC burning (not USB2)\n", devstr); return 0; } - INFO("Load PIC: %s (version %s)\n", hexdata->fname, hexdata->version_info); + INFO("%s [%s]: Loading PIC Firmware: %s (version %s)\n", + devstr, + xusb_serial(astribank->xusb), + hexdata->fname, + hexdata->version_info); basename = pic_basename(hexdata->fname, &card_type); if(!basename) { - ERR("Bad PIC filename '%s'. Abort.\n", hexdata->fname); + ERR("%s: Bad PIC filename '%s'. Abort.\n", devstr, hexdata->fname); return 0; } DBG("basename=%s card_type=%d maxlines=%d\n", @@ -200,9 +207,9 @@ static int pic_burn(struct astribank_device *astribank, const struct hexdata *he * Try to read extra left-overs from USB controller */ for(i = 2; i; i--) { - char buf[PACKET_SIZE]; + char buf[PACKET_SIZE]; - if(usb_bulk_read(astribank->handle, astribank->my_ep_in, buf, sizeof(buf), 1) <= 0) + if(xusb_recv(astribank->xusb, buf, sizeof(buf), 1) <= 0) break; } if((ret = send_picline(astribank, card_type, PIC_START_FLAG, 0, NULL, 0)) != 0) { @@ -215,13 +222,13 @@ static int pic_burn(struct astribank_device *astribank, const struct hexdata *he hexline = hexdata->lines[i]; if(!hexline) { - ERR("hexdata finished early (line %d)", i); + ERR("%s: hexdata finished early (line %d)", devstr, i); return 0; } if(hexline->d.content.header.tt == TT_DATA) { len = hexline->d.content.header.ll; /* don't send checksum */ if(len != 3) { - ERR("Bad line len %d\n", len); + ERR("%s: Bad line len %d\n", devstr, len); return 0; } data = hexline->d.content.tt_data.data; @@ -235,8 +242,8 @@ static int pic_burn(struct astribank_device *astribank, const struct hexdata *he } else if(hexline->d.content.header.tt == TT_EOF) { break; } else { - ERR("Unexpected TT = %d in line %d\n", - hexline->d.content.header.tt, i); + ERR("%s: Unexpected TT = %d in line %d\n", + devstr, hexline->d.content.header.tt, i); return 0; } } @@ -250,9 +257,11 @@ static int pic_burn(struct astribank_device *astribank, const struct hexdata *he int load_pic(struct astribank_device *astribank, int numfiles, char *filelist[]) { - int i; + int i; + const char *devstr; - DBG("Loading %d PIC files...\n", numfiles); + devstr = xusb_devpath(astribank->xusb); + DBG("%s: Loading %d PIC files...\n", devstr, numfiles); for(i = 0; i < numfiles; i++) { struct hexdata *picdata; const char *curr = filelist[i]; @@ -263,13 +272,13 @@ int load_pic(struct astribank_device *astribank, int numfiles, char *filelist[]) return -errno; } if(!pic_burn(astribank, picdata)) { - ERR("PIC %s burning failed\n", curr); + ERR("%s: PIC %s burning failed\n", devstr, curr); return -ENODEV; } free_hexdata(picdata); } if((i = send_picline(astribank, 0, PIC_ENDS_FLAG, 0, NULL, 0)) != 0) { - ERR("PIC end burning failed\n"); + ERR("%s: PIC end burning failed\n", devstr); return -ENODEV; } return 0; diff --git a/xpp/xpp_fxloader b/xpp/xpp_fxloader index 73a6c6e..e316d0e 100644 --- a/xpp/xpp_fxloader +++ b/xpp/xpp_fxloader @@ -146,15 +146,19 @@ load_usb_fw() { } load_fw_device() { - dev=$1 - fw=$2 + dev="$1" + fw="$2" debug "FPGA loading $fw into $dev" run_astribank_hexload -D "$dev" -F "$FIRMWARE_DIR/$fw" - pic_files=`echo "$FIRMWARE_DIR"/PIC_TYPE_[1-4].hex` - debug "PIC burning into $dev: $pic_files" - run_astribank_hexload -D "$dev" -p $pic_files - run_astribank_tool -D "$dev" -n # Do renumeration! - debug "PIC burning finished $pic_files" + if [ "$fw" = "FPGA_1161.hex" ]; then + pic_files=`echo "$FIRMWARE_DIR"/PIC_TYPE_[1-4].hex` + debug "PIC burning into $dev: $pic_files" + run_astribank_hexload -D "$dev" -p $pic_files + debug "PIC burning finished $pic_files" + fi + # Do renumeration! + run_astribank_tool -D "$dev" -n > /dev/null + debug "Reenumeration done." } # diff --git a/xpp/debug.c b/xpp/xtalk/debug.c similarity index 65% rename from xpp/debug.c rename to xpp/xtalk/debug.c index b8d3a70..eea2d82 100644 --- a/xpp/debug.c +++ b/xpp/xtalk/debug.c @@ -20,11 +20,14 @@ * */ + #include #include +#include #include #include -#include "debug.h" +#include +#include int verbose = LOG_INFO; int debug_mask = 0; @@ -41,13 +44,29 @@ void log_function(int level, int mask, const char *msg, ...) va_end(ap); } -void dump_packet(int loglevel, const char *msg, const char *buf, int len) +void dump_packet(int loglevel, int mask, const char *msg, const char *buf, int len) { int i; - log_function(loglevel, ~0, "%-15s:", msg); - for(i = 0; i < len; i++) - log_function(loglevel, ~0, " %02X", (uint8_t)buf[i]); - log_function(loglevel, ~0, "\n"); + if(mask & debug_mask) { + log_function(loglevel, ~0, "%-15s:", msg); + for(i = 0; i < len; i++) + log_function(loglevel, ~0, " %02X", (uint8_t)buf[i]); + log_function(loglevel, ~0, "\n"); + } } +/* from glibc info(1) */ +void print_backtrace (FILE *fp) +{ + void *array[10]; + size_t size; + char **strings; + size_t i; + + size = backtrace (array, 10); + strings = backtrace_symbols (array, size); + for (i = 0; i < size; i++) + fprintf (fp, "%s\n", strings[i]); + free (strings); +} diff --git a/xpp/debug.h b/xpp/xtalk/debug.h similarity index 86% rename from xpp/debug.h rename to xpp/xtalk/debug.h index 185848a..2d018d2 100644 --- a/xpp/debug.h +++ b/xpp/xtalk/debug.h @@ -23,6 +23,7 @@ */ #include +#include /* * Each module should define a unique DBG_MASK @@ -37,10 +38,12 @@ extern int debug_mask; void log_function(int level, int mask, const char *msg, ...) __attribute__(( format(printf, 3, 4) )); #define ERR(fmt, arg...) log_function(LOG_ERR, 0, "%s:%d: ERROR(%s): " fmt, __FILE__, __LINE__, __FUNCTION__, ## arg) +#define WARN(fmt, arg...) log_function(LOG_WARNING, 0, "WARNING: " fmt, ## arg) #define INFO(fmt, arg...) log_function(LOG_INFO, 0, "INFO: " fmt, ## arg) #define DBG(fmt, arg...) log_function(LOG_DEBUG, DBG_MASK, \ "%s:%d: DBG(%s): " fmt, __FILE__, __LINE__, __FUNCTION__, ## arg) -void dump_packet(int loglevel, const char *msg, const char *buf, int len); +void dump_packet(int loglevel, int mask, const char *msg, const char *buf, int len); +void print_backtrace (FILE *fp); #endif /* DEBUG_H */ diff --git a/xpp/xtalk/xlist.c b/xpp/xtalk/xlist.c new file mode 100644 index 0000000..d28debd --- /dev/null +++ b/xpp/xtalk/xlist.c @@ -0,0 +1,93 @@ +#include +#include +#include +#include + +struct xlist_node *xlist_new(void *data) +{ + struct xlist_node *list; + + if((list = malloc(sizeof(*list))) == NULL) + return NULL; + list->next = list; + list->prev = list; + list->data = data; + return list; +} + +void xlist_destroy(struct xlist_node *list, xlist_destructor_t destructor) +{ + struct xlist_node *curr; + struct xlist_node *next; + + if (! list) + return; + curr = list->next; + while(curr != list) { + next = curr->next; + if(destructor) + destructor(curr->data); + memset(curr, 0, sizeof(*curr)); + free(curr); + curr = next; + } + memset(list, 0, sizeof(*list)); + free(list); +} + +void xlist_append_item(struct xlist_node *list, struct xlist_node *item) +{ + assert(list); + assert(xlist_empty(item)); + item->next = list; + item->prev = list->prev; + list->prev->next = item; + list->prev = item; +} + +void xlist_prepend_item(struct xlist_node *list, struct xlist_node *item) +{ + assert(list); + assert(xlist_empty(item)); + item->prev = list; + item->next = list->next; + list->next->prev = item; + list->next = item; +} + +void xlist_remove_item(struct xlist_node *item) +{ + assert(item); + item->prev->next = item->next; + item->next->prev = item->prev; + item->next = item->prev = item; +} + +struct xlist_node *xlist_shift(struct xlist_node *list) +{ + struct xlist_node *item; + + if(!list) + return NULL; + if(xlist_empty(list)) + return NULL; + item = list->next; + xlist_remove_item(item); + return item; +} + +int xlist_empty(const struct xlist_node *list) +{ + assert(list); + return list->next == list && list->prev == list; +} + +size_t xlist_length(const struct xlist_node *list) +{ + struct xlist_node *curr; + size_t count = 0; + + for(curr = list->next; curr != list; curr = curr->next) + count++; + return count; +} diff --git a/xpp/xtalk/xlist.h b/xpp/xtalk/xlist.h new file mode 100644 index 0000000..4f7f818 --- /dev/null +++ b/xpp/xtalk/xlist.h @@ -0,0 +1,29 @@ +#ifndef XLIST_H +#define XLIST_H + +#ifdef __cplusplus +extern "C" +{ +#endif /* __cplusplus */ + +struct xlist_node { + void *data; + struct xlist_node *next; + struct xlist_node *prev; +}; + +typedef void (*xlist_destructor_t)(void *data); + +struct xlist_node *xlist_new(void *data); +void xlist_destroy(struct xlist_node *list, xlist_destructor_t destructor); +void xlist_append_item(struct xlist_node *list, struct xlist_node *item); +void xlist_remove_item(struct xlist_node *item); +struct xlist_node *xlist_shift(struct xlist_node *list); +int xlist_empty(const struct xlist_node *list); +size_t xlist_length(const struct xlist_node *list); + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + +#endif /* XLIST_H */ diff --git a/xpp/xtalk/xtalk.c b/xpp/xtalk/xtalk.c new file mode 100644 index 0000000..d3da5e0 --- /dev/null +++ b/xpp/xtalk/xtalk.c @@ -0,0 +1,497 @@ +/* + * Written by Oron Peled + * Copyright (C) 2009, Xorcom + * + * All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +static const char rcsid[] = "$Id$"; + +#define DBG_MASK 0x02 + +#define TIMEOUT 6000 + +/* + * Base XTALK device. A pointer to this struct + * should be included in the struct representing + * the dialect. + */ +struct xtalk_device { + void *transport_priv; /* e.g: struct xusb */ + struct xtalk_ops ops; + struct xtalk_protocol xproto; + uint8_t xtalk_proto_version; + uint8_t status; + size_t packet_size; + uint16_t tx_sequenceno; +}; + +CMD_DEF(XTALK, ACK, + uint8_t stat; + ); + +CMD_DEF(XTALK, PROTO_GET, + uint8_t proto_version; + uint8_t reserved; + ); + +CMD_DEF(XTALK, PROTO_GET_REPLY, + uint8_t proto_version; + uint8_t reserved; + ); + +union XTALK_PDATA(XTALK) { + MEMBER(XTALK, ACK); + MEMBER(XTALK, PROTO_GET); + MEMBER(XTALK, PROTO_GET_REPLY); +} PACKED members; + +struct xtalk_protocol xtalk_base = { + .name = "XTALK", + .proto_version = 0, + .commands = { + CMD_RECV(XTALK, ACK, NULL), + CMD_SEND(XTALK, PROTO_GET), + CMD_RECV(XTALK, PROTO_GET_REPLY, NULL), + }, + .ack_statuses = { + ACK_STAT(OK, "Acknowledges previous command"), + ACK_STAT(FAIL, "Last command failed"), + ACK_STAT(RESET_FAIL, "reset failed"), + ACK_STAT(NODEST, "No destination is selected"), + ACK_STAT(MISMATCH, "Data mismatch"), + ACK_STAT(NOACCESS, "No access"), + ACK_STAT(BAD_CMD, "Bad command"), + ACK_STAT(TOO_SHORT, "Packet is too short"), + ACK_STAT(ERROFFS, "Offset error (not used)"), + ACK_STAT(NO_LEEPROM, "Large EEPROM was not found"), + ACK_STAT(NO_EEPROM, "No EEPROM was found"), + ACK_STAT(WRITE_FAIL, "Writing to device failed"), + ACK_STAT(NOPWR_ERR, "No power on USB connector"), + } +}; + +void free_command(struct xtalk_command *cmd) +{ + if(!cmd) + return; + memset(cmd, 0, cmd->header.len); + free(cmd); +} + +static const struct xtalk_command_desc *get_command_desc(const struct xtalk_protocol *xproto, uint8_t op) +{ + const struct xtalk_command_desc *desc; + + if(!xproto) + return NULL; + desc = &xproto->commands[op]; + if(!desc->name) + return NULL; +#if 0 + DBG("%s version=%d, op=0x%X (%s)\n", + xproto->name, xproto->proto_version, + op, desc->name); +#endif + return desc; +} + +static const char *ack_status_msg(const struct xtalk_protocol *xproto, uint8_t status) +{ + const char *ack_status; + + if(!xproto) + return NULL; + ack_status = xproto->ack_statuses[status]; + DBG("%s status=0x%X (%s)\n", xproto->name, status, ack_status); + return ack_status; +} + +int xtalk_set_protocol(struct xtalk_device *xtalk_dev, const struct xtalk_protocol *xproto) +{ + const char *protoname = (xproto) ? xproto->name : "GLOBAL"; + int i; + + DBG("%s\n", protoname); + memset(&xtalk_dev->xproto, 0, sizeof(xtalk_dev->xproto)); + for(i = 0; i < MAX_OPS; i++) { + const struct xtalk_command_desc *desc; + + desc = get_command_desc(xproto, i); + if(desc) { + if(!IS_PRIVATE_OP(i)) { + ERR("Bad op=0x%X (should be in the range [0x%X-0x%X]\n", + i, PRIVATE_OP_FIRST, PRIVATE_OP_LAST); + return -EINVAL; + } + xtalk_dev->xproto.commands[i] = *desc; + DBG("private: op=0x%X (%s)\n", i, desc->name); + } else { + if(!IS_PRIVATE_OP(i)) { + const char *name; + + xtalk_dev->xproto.commands[i] = xtalk_base.commands[i]; + name = xtalk_dev->xproto.commands[i].name; + if(name) + DBG("global: op=0x%X (%s)\n", i, name); + } + } + } + for(i = 0; i < MAX_STATUS; i++) { + const char *stat_msg; + + stat_msg = (xproto) ? xproto->ack_statuses[i] : NULL; + if(stat_msg) { + if(!IS_PRIVATE_OP(i)) { + ERR("Bad status=0x%X (should be in the range [0x%X-0x%X]\n", + i, PRIVATE_OP_FIRST, PRIVATE_OP_LAST); + return -EINVAL; + } + xtalk_dev->xproto.ack_statuses[i] = stat_msg; + DBG("private: status=0x%X (%s)\n", i, stat_msg); + } else { + if(!IS_PRIVATE_OP(i)) { + const char *stat_msg; + + xtalk_dev->xproto.ack_statuses[i] = xtalk_base.ack_statuses[i]; + stat_msg = xtalk_dev->xproto.ack_statuses[i]; + if(stat_msg) + DBG("global: status=0x%X (%s)\n", i, stat_msg); + } + } + } + xtalk_dev->xproto.name = protoname; + xtalk_dev->xproto.proto_version = (xproto) ? xproto->proto_version : 0; + return 0; +} + +struct xtalk_command *new_command( + const struct xtalk_device *xtalk_dev, + uint8_t op, uint16_t extra_data) +{ + const struct xtalk_protocol *xproto; + struct xtalk_command *cmd; + const struct xtalk_command_desc *desc; + uint16_t len; + + xproto = &xtalk_dev->xproto; + desc = get_command_desc(xproto, op); + if(!desc) { + ERR("Unknown op=0x%X.\n", op); + return NULL; + } + DBG("OP=0x%X [%s] (extra_data %d)\n", op, desc->name, extra_data); + len = desc->len + extra_data; + if((cmd = malloc(len)) == NULL) { + ERR("Out of memory\n"); + return NULL; + } + if(extra_data) { + uint8_t *ptr = (uint8_t *)cmd; + + DBG("clear extra_data (%d bytes)\n", extra_data); + memset(ptr + desc->len, 0, extra_data); + } + cmd->header.op = op; + cmd->header.len = len; + cmd->header.seq = 0; /* Overwritten in send_usb() */ + return cmd; +} + +void xtalk_dump_command(struct xtalk_command *cmd) +{ + uint16_t len; + int i; + + len = cmd->header.len; + if(len < sizeof(struct xtalk_header)) { + ERR("Command too short (%d)\n", len); + return; + } + INFO("DUMP: OP=0x%X len=%d seq=%d\n", + cmd->header.op, cmd->header.len, cmd->header.seq); + for(i = 0; i < len - sizeof(struct xtalk_header); i++) { + INFO(" %2d. 0x%X\n", i, cmd->alt.raw_data[i]); + } +} + +static int send_command(struct xtalk_device *xtalk_dev, struct xtalk_command *cmd, int timeout) +{ + int ret; + int len; + char *buf; + void *priv = xtalk_dev->transport_priv; + + len = cmd->header.len; + cmd->header.seq = xtalk_dev->tx_sequenceno; + + buf = (char *)cmd; + //printf("%s: len=%d\n", __FUNCTION__, len); +#if 0 + extern FILE *fp; + if(fp) { + int i; + + fprintf(fp, "%05d:", cmd->header.seq); + for(i = 0; i < len; i++) + fprintf(fp, " %02X", (uint8_t)buf[i]); + fprintf(fp, "\n"); + } +#endif + ret = xtalk_dev->ops.send_func(priv, (char *)cmd, len, timeout); + if(ret < 0) { + DBG("send_func failed ret=%d\n", ret); + } + xtalk_dev->tx_sequenceno++; + return ret; +} + +static struct xtalk_command *recv_command(struct xtalk_device *xtalk_dev, int timeout) +{ + struct xtalk_command *reply; + void *priv = xtalk_dev->transport_priv; + int ret; + + if((reply = malloc(xtalk_dev->packet_size)) == NULL) { + ERR("Out of memory\n"); + goto err; + } + reply->header.len = 0; + ret = xtalk_dev->ops.recv_func(priv, (char *)reply, xtalk_dev->packet_size, timeout); + if(ret < 0) { + ERR("Receive from usb failed.\n"); + goto err; + } else if(ret == 0) { + goto err; /* No reply */ + } + if(ret != reply->header.len) { + ERR("Wrong length received: got %d bytes, but length field says %d bytes%s\n", + ret, reply->header.len, + (ret == 1)? ". Old USB firmware?": ""); + goto err; + } + //dump_packet(LOG_DEBUG, DBG_MASK, __FUNCTION__, (char *)reply, ret); + return reply; +err: + if(reply) { + memset(reply, 0, xtalk_dev->packet_size); + free_command(reply); + } + return NULL; +} + + +__attribute__((warn_unused_result)) +int process_command( + struct xtalk_device *xtalk_dev, + struct xtalk_command *cmd, + struct xtalk_command **reply_ref) +{ + const struct xtalk_protocol *xproto; + struct xtalk_command *reply = NULL; + const struct xtalk_command_desc *reply_desc; + const struct xtalk_command_desc *expected; + const struct xtalk_command_desc *cmd_desc; + uint8_t reply_op; + const char *protoname; + int ret; + + xproto = &xtalk_dev->xproto; + protoname = (xproto) ? xproto->name : "GLOBAL"; + if(reply_ref) + *reply_ref = NULL; /* So the caller knows if a reply was received */ + reply_op = cmd->header.op | XTALK_REPLY_MASK; + cmd_desc = get_command_desc(xproto, cmd->header.op); + expected = get_command_desc(xproto, reply_op); + //printf("%s: len=%d\n", __FUNCTION__, cmd->header.len); + ret = send_command(xtalk_dev, cmd, TIMEOUT); + if(!reply_ref) { + DBG("No reply requested\n"); + goto out; + } + if(ret < 0) { + ERR("send_command failed: %d\n", ret); + goto out; + } + reply = recv_command(xtalk_dev, TIMEOUT); + if(!reply) { + ERR("recv_command failed\n"); + ret = -EPROTO; + goto out; + } + *reply_ref = reply; + if((reply->header.op & 0x80) != 0x80) { + ERR("Unexpected reply op=0x%02X, should have MSB set.\n", reply->header.op); + ret = -EPROTO; + goto out; + } + DBG("REPLY OP: 0x%X\n", reply->header.op); + reply_desc = get_command_desc(xproto, reply->header.op); + if(!reply_desc) { + ERR("Unknown reply (proto=%s) op=0x%02X\n", protoname, reply->header.op); + ret = -EPROTO; + goto out; + } + DBG("REPLY NAME: %s\n", reply_desc->name); + if(reply->header.op == XTALK_ACK) { + int status = CMD_FIELD(reply, XTALK, ACK, stat); + + if(expected) { + ERR("Expected OP=0x%02X: Got ACK(%d): %s\n", + reply_op, status, ack_status_msg(xproto, status)); + ret = -EPROTO; + goto out; + } else if(status != STAT_OK) { + + ERR("Got ACK (for OP=0x%X [%s]): %d %s\n", + cmd->header.op, + cmd_desc->name, + status, ack_status_msg(xproto, status)); +#if 0 + extern FILE *fp; + if(fp) { + fprintf(fp, "Got ACK(%d)\n", status); + } +#endif + ret = -EPROTO; + goto out; + } + /* Good expected ACK ... */ + } else if(reply->header.op != reply_op) { + ERR("Expected OP=0x%02X: Got OP=0x%02X\n", + reply_op, reply->header.op); + ret = -EPROTO; + goto out; + } + if(expected && expected->len > reply->header.len) { + ERR("Expected len=%d: Got len=%d\n", + expected->len, reply->header.len); + ret = -EPROTO; + goto out; + } + if(cmd->header.seq != reply->header.seq) { + ERR("Expected seq=%d: Got seq=%d\n", + cmd->header.seq, reply->header.seq); + ret = -EPROTO; + goto out; + } + ret = reply->header.len; /* All good, return the length */ + DBG("returning reply op 0x%X (%d bytes)\n", reply->header.op, ret); +out: + free_command(cmd); + if(!reply_ref && reply) + free_command(reply); + return ret; +} + +/* + * Protocol Commands + */ + +int xtalk_proto_query(struct xtalk_device *xtalk_dev) +{ + struct xtalk_command *cmd; + struct xtalk_command *reply; + uint8_t proto_version; + int ret; + + DBG("\n"); + assert(xtalk_dev != NULL); + proto_version = xtalk_dev->xproto.proto_version; + if((cmd = new_command(xtalk_dev, XTALK_PROTO_GET, 0)) == NULL) { + ERR("new_command failed\n"); + return -ENOMEM; + } + CMD_FIELD(cmd, XTALK, PROTO_GET, proto_version) = proto_version; /* Protocol Version */ + ret = process_command(xtalk_dev, cmd, &reply); + if(ret < 0) { + ERR("process_command failed: %d\n", ret); + goto out; + } + xtalk_dev->xtalk_proto_version = CMD_FIELD(reply, XTALK, PROTO_GET_REPLY, proto_version); + if(xtalk_dev->xtalk_proto_version != proto_version) { + ERR("Got %s protocol version: 0x%02x (expected 0x%02x)\n", + xtalk_dev->xproto.name, + xtalk_dev->xtalk_proto_version, + proto_version); + ret = xtalk_dev->xtalk_proto_version; + goto out; + } + DBG("Protocol version: %02x\n", xtalk_dev->xtalk_proto_version); + ret = xtalk_dev->xtalk_proto_version; +out: + free_command(reply); + return ret; +} + +/* + * Wrappers + */ + +struct xtalk_device *xtalk_new(const struct xtalk_ops *ops, size_t packet_size, void *priv) +{ + struct xtalk_device *xtalk_dev; + int ret; + + DBG("\n"); + assert(ops != NULL); + if((xtalk_dev = malloc(sizeof(*xtalk_dev))) == NULL) { + ERR("Allocating XTALK device memory failed\n"); + return NULL; + } + memset(xtalk_dev, 0, sizeof(*xtalk_dev)); + memcpy((void *)&xtalk_dev->ops, (const void *)ops, sizeof(xtalk_dev->ops)); + xtalk_dev->transport_priv = priv; + xtalk_dev->packet_size = packet_size; + xtalk_dev->tx_sequenceno = 1; + ret = xtalk_set_protocol(xtalk_dev, NULL); + if(ret < 0) { + ERR("GLOBAL Protocol registration failed: %d\n", ret); + goto err; + } + return xtalk_dev; + +err: + if (xtalk_dev) + xtalk_delete(xtalk_dev); + return NULL; +} + +void xtalk_delete(struct xtalk_device *xtalk_dev) +{ + void *priv; + + if(!xtalk_dev) + return; + DBG("\n"); + priv = xtalk_dev->transport_priv; + assert(priv); + xtalk_dev->tx_sequenceno = 0; + assert(&xtalk_dev->ops != NULL); + assert(&xtalk_dev->ops.close_func != NULL); + xtalk_dev->ops.close_func(priv); +} diff --git a/xpp/xtalk/xtalk.h b/xpp/xtalk/xtalk.h new file mode 100644 index 0000000..4243b64 --- /dev/null +++ b/xpp/xtalk/xtalk.h @@ -0,0 +1,172 @@ +#ifndef XTALK_H +#define XTALK_H +/* + * Written by Oron Peled + * Copyright (C) 2009, Xorcom + * + * All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + */ + +#ifdef __cplusplus +extern "C" +{ +#endif /* __cplusplus */ + +/* + * XTALK - Base protocol for our USB devices + * It is meant to provide a common base for layered + * protocols (dialects) + */ + +#include +#include +/* Definitions common to the firmware (in include/ directory) */ +#include + +#ifdef __GNUC__ +#define PACKED __attribute__((packed)) +#else +#error "We do not know how your compiler packs structures" +#endif + +struct xtalk_device; +struct xtalk_command_desc; + +typedef int (*xtalk_cmd_callback_t)( + struct xtalk_device *xtalk_dev, + struct xtalk_command_desc *xtalk_cmd); + +/* Describe a single xtalk command */ +struct xtalk_command_desc { + uint8_t op; + const char *name; + xtalk_cmd_callback_t callback; + uint16_t len; /* Minimal length */ +}; + +/* Define a complete protocol */ +struct xtalk_protocol { + const char *name; + uint8_t proto_version; + struct xtalk_command_desc commands[MAX_OPS]; + const char *ack_statuses[MAX_STATUS]; +}; + +/* + * The common header of every xtalk command + * in every xtalk dialect. + */ +struct xtalk_header { + uint16_t len; + uint16_t seq; + uint8_t op; /* MSB: 0 - to device, 1 - from device */ +} PACKED; + +struct xtalk_command { + /* Common part */ + struct xtalk_header header; + /* Each dialect has its own data members */ + union private_data { + uint8_t raw_data[0]; + } PACKED alt; +} PACKED; + +/* + * Macros to unify access to protocol packets and fields: + * p - signify the dialect prefix (XTALK for base protocol) + * o - signify command op (e.g: ACK) + * cmd - A pointer to struct xtalk_command + * field - field name (e.g: raw_data) + */ +#define XTALK_STRUCT(p,o) p ## _struct_ ## o +#define XTALK_PDATA(o) xtalk_privdata_ ## o +#define CMD_FIELD(cmd, p, o, field) (((union XTALK_PDATA(p) *)&((cmd)->alt))->XTALK_STRUCT(p, o).field) +#define CMD_DEF(p, o, ...) struct XTALK_STRUCT(p, o) { \ + __VA_ARGS__ \ + } PACKED XTALK_STRUCT(p, o) +#define MEMBER(p, o) struct XTALK_STRUCT(p, o) XTALK_STRUCT(p, o) + +/* Wrappers for transport (xusb) functions */ +struct xtalk_ops { + int (*send_func)(void *transport_priv, void *data, size_t len, int timeout); + int (*recv_func)(void *transport_priv, void *data, size_t maxlen, int timeout); + int (*close_func)(void *transport_priv); +}; + +/* + * Base XTALK device. A pointer to this struct + * should be included in the struct representing + * the dialect. + */ +struct xtalk_device; + +/* high-level */ +struct xtalk_device *xtalk_new(const struct xtalk_ops *ops, size_t packet_size, void *transport_priv); +void xtalk_delete(struct xtalk_device *dev); +int xtalk_set_protocol(struct xtalk_device *xtalk_dev, const struct xtalk_protocol *xproto); +int xtalk_proto_query(struct xtalk_device *dev); +void xtalk_dump_command(struct xtalk_command *cmd); + +/* low-level */ +int process_command( + struct xtalk_device *dev, + struct xtalk_command *cmd, + struct xtalk_command **reply_ref); +struct xtalk_command *new_command( + const struct xtalk_device *xtalk_dev, + uint8_t op, uint16_t extra_data); +void free_command(struct xtalk_command *cmd); + +/* + * Convenience macros to define entries in a protocol command table: + * p - signify the dialect prefix (XTALK for base protocol) + * o - signify command op (e.g: ACK) + * cb - A callback function (type xtalk_cmd_callback_t) + */ +#define CMD_RECV(p,o,cb) \ + [p ## _ ## o | XTALK_REPLY_MASK] { \ + .op = p ## _ ## o | XTALK_REPLY_MASK, \ + .name = #o "_reply", \ + .callback = (cb), \ + .len = \ + sizeof(struct xtalk_header) + \ + sizeof(struct XTALK_STRUCT(p,o)), \ + } + +#define CMD_SEND(p,o) \ + [p ## _ ## o] { \ + .op = p ## _ ## o, \ + .name = #o, \ + .callback = NULL, \ + .len = \ + sizeof(struct xtalk_header) + \ + sizeof(struct XTALK_STRUCT(p,o)), \ + } + +/* + * Convenience macro to define statuses: + * x - status code (e.g: OK) + * m - status message (const char *) + */ +#define ACK_STAT(x,m) [ STAT_ ## x ] = (m) + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + +#endif /* XTALK_H */ diff --git a/xpp/xtalk/xtalk_defs.h b/xpp/xtalk/xtalk_defs.h new file mode 100644 index 0000000..d9c590b --- /dev/null +++ b/xpp/xtalk/xtalk_defs.h @@ -0,0 +1,40 @@ +#ifndef XTALK_DEFS_H +#define XTALK_DEFS_H + +#define MAX_OPS 256 /* single byte */ +#define MAX_STATUS 256 /* single byte */ + +#define XTALK_REPLY_MASK 0x80 /* Every reply has this bit */ + +#define PRIVATE_OP_FIRST 0x05 +#define PRIVATE_OP_LAST 0x7F +#define IS_PRIVATE_OP(x) ( \ + (((x) & ~(XTALK_REPLY_MASK)) >= PRIVATE_OP_FIRST) && \ + (((x) & ~(XTALK_REPLY_MASK)) <= PRIVATE_OP_LAST) \ + ) + +#define XTALK_ACK 0x80 +#define XTALK_PROTO_GET 0x01 +#define XTALK_PROTO_GET_REPLY (XTALK_PROTO_GET | XTALK_REPLY_MASK) +#define XTALK_FWVERS_GET 0x11 +#define XTALK_FWVERS_GET_REPLY (XTALK_FWVERS_GET | XTALK_REPLY_MASK) +#define XTALK_CAPS_GET 0x0E /* Get EEPROM table contents Product/Vendor Id ... */ +#define XTALK_CAPS_GET_REPLY (XTALK_CAPS_GET | XTALK_REPLY_MASK) + +/*------------- XTALK: statuses in ACK ---------------------------------------*/ +#define STAT_OK 0x00 /* OK */ +#define STAT_FAIL 0x01 /* last command failed */ +#define STAT_RESET_FAIL 0x02 /* reset failed */ +#define STAT_NODEST 0x03 /* No destination is selected */ +#define STAT_MISMATCH 0x04 /* Data mismatch */ +#define STAT_NOACCESS 0x05 /* No access */ +#define STAT_BAD_CMD 0x06 /* Bad command */ +#define STAT_TOO_SHORT 0x07 /* Packet is too short */ +#define STAT_ERROFFS 0x08 /* Offset error (not used) */ +#define STAT_NO_LEEPROM 0x0A /* Large EEPROM was not found */ +#define STAT_NO_EEPROM 0x0B /* No EEPROM was found */ +#define STAT_WRITE_FAIL 0x0C /* Writing to device failed */ +#define STAT_NOPWR_ERR 0x10 /* No power on USB connector */ + + +#endif /* XTALK_DEFS_H */ diff --git a/xpp/xtalk/xusb.c b/xpp/xtalk/xusb.c new file mode 100644 index 0000000..ebec5a9 --- /dev/null +++ b/xpp/xtalk/xusb.c @@ -0,0 +1,726 @@ +/* + * Written by Oron Peled + * Copyright (C) 2008, Xorcom + * + * All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + */ + +#define _GNU_SOURCE /* for memrchr() */ +#include +#include +#include +#include +#include +#include +#include +#include +#include + +static const char rcsid[] = "$Id$"; + +#define DBG_MASK 0x01 +#define TIMEOUT 500 + +struct xusb { + struct usb_device *dev; + usb_dev_handle *handle; + const struct xusb_spec *spec; + char iManufacturer[BUFSIZ]; + char iProduct[BUFSIZ]; + char iSerialNumber[BUFSIZ]; + char iInterface[BUFSIZ]; + char devpath_tail[PATH_MAX + 1]; + int bus_num; + int device_num; + int interface_num; + int ep_out; + int ep_in; + int is_usb2; + int is_claimed; + int is_open; + size_t packet_size; +}; + +void xusb_init_spec(struct xusb_spec *spec, char *name, + uint16_t vendor_id, uint16_t product_id, + int nifaces, int iface, int nep, int ep_out, int ep_in) +{ + DBG("Initialize %s: interfaces=%d using interface num=%d endpoints=%d (OUT=0x%2X, IN=0x%2X)\n", + name, nifaces, iface, nep, ep_out, ep_in); + memset(spec, 0, sizeof(*spec)); + spec->name = name; + spec->num_interfaces = nifaces; + spec->my_interface_num = iface; + spec->num_endpoints = nep; + spec->my_vendor_id = vendor_id; + spec->my_product_id = product_id; + spec->my_ep_in = ep_in; + spec->my_ep_out = ep_out; +} + +#define EP_OUT(xusb) ((xusb)->spec->my_ep_out) +#define EP_IN(xusb) ((xusb)->spec->my_ep_in) + +/* + * USB handling + */ + +static int get_usb_string(struct xusb *xusb, uint8_t item, char *buf, unsigned int len) +{ + char tmp[BUFSIZ]; + int ret; + + assert(xusb->handle); + if (!item) + return 0; + ret = usb_get_string_simple(xusb->handle, item, tmp, BUFSIZ); + if (ret <= 0) + return ret; + return snprintf(buf, len, "%s", tmp); +} + +static const struct usb_interface_descriptor *get_interface(const struct usb_device *dev, int my_interface_num, int num_interfaces) +{ + const struct usb_interface *interface; + const struct usb_interface_descriptor *iface_desc; + const struct usb_config_descriptor *config_desc; + int num_altsetting; + + config_desc = dev->config; + if (!config_desc) { + ERR("No configuration descriptor: strange USB1 controller?\n"); + return NULL; + } + if(num_interfaces && config_desc->bNumInterfaces != num_interfaces) { + DBG("Wrong number of interfaces: have %d need %d\n", + config_desc->bNumInterfaces, num_interfaces); + return NULL; + } + interface = &config_desc->interface[my_interface_num]; + assert(interface != NULL); + iface_desc = interface->altsetting; + num_altsetting = interface->num_altsetting; + assert(num_altsetting != 0); + assert(iface_desc != NULL); + return iface_desc; +} + +static int match_interface(const struct usb_device *dev, const struct xusb_spec *spec) +{ + const struct usb_device_descriptor *dev_desc; + const struct usb_interface_descriptor *iface_desc; + + //debug_mask = 0xFF; + //verbose = 1; + dev_desc = &dev->descriptor; + assert(dev_desc); + DBG("Checking: %04X:%04X interfaces=%d interface num=%d endpoints=%d: \"%s\"\n", + spec->my_vendor_id, + spec->my_product_id, + spec->num_interfaces, + spec->my_interface_num, + spec->num_endpoints, + spec->name); + if(dev_desc->idVendor != spec->my_vendor_id) { + DBG("Wrong vendor id 0x%X\n", dev_desc->idVendor); + return 0; + } + if(dev_desc->idProduct != spec->my_product_id) { + DBG("Wrong product id 0x%X\n", dev_desc->idProduct); + return 0; + } + if((iface_desc = get_interface(dev, spec->my_interface_num, spec->num_interfaces)) == NULL) { + ERR("Could not get interface descriptor of device: %s\n", usb_strerror()); + return 0; + } + if(iface_desc->bInterfaceClass != 0xFF) { + DBG("Wrong interface class 0x%X\n", iface_desc->bInterfaceClass); + return 0; + } + if(iface_desc->bInterfaceNumber != spec->my_interface_num) { + DBG("Wrong interface number %d (expected %d)\n", + iface_desc->bInterfaceNumber, spec->my_interface_num); + return 0; + } + if(iface_desc->bNumEndpoints != spec->num_endpoints) { + DBG("Wrong number of endpoints %d\n", iface_desc->bNumEndpoints); + return 0; + } + return 1; +} + +static int xusb_fill_strings(struct xusb *xusb) +{ + const struct usb_device_descriptor *dev_desc; + const struct usb_interface_descriptor *iface_desc; + + + dev_desc = &xusb->dev->descriptor; + assert(dev_desc); + if(get_usb_string(xusb, dev_desc->iManufacturer, xusb->iManufacturer, BUFSIZ) < 0) { + ERR("Failed reading iManufacturer string: %s\n", usb_strerror()); + return 0; + } + if(get_usb_string(xusb, dev_desc->iProduct, xusb->iProduct, BUFSIZ) < 0) { + ERR("Failed reading iProduct string: %s\n", usb_strerror()); + return 0; + } + if(get_usb_string(xusb, dev_desc->iSerialNumber, xusb->iSerialNumber, BUFSIZ) < 0) { + ERR("Failed reading iSerialNumber string: %s\n", usb_strerror()); + return 0; + } + if((iface_desc = get_interface(xusb->dev, xusb->interface_num, 0)) == NULL) { + ERR("Could not get interface descriptor of device: %s\n", usb_strerror()); + return 0; + } + if(get_usb_string(xusb, iface_desc->iInterface, xusb->iInterface, BUFSIZ) < 0) { + ERR("Failed reading iInterface string: %s\n", usb_strerror()); + return 0; + } + return 1; +} + +static int xusb_open(struct xusb *xusb) +{ + assert(xusb); + if (xusb->is_open) + return 1; + if((xusb->handle = usb_open(xusb->dev)) == NULL) { + ERR("Failed to open usb device '%s': %s\n", + xusb->devpath_tail, usb_strerror()); + return 0; + } + xusb->is_open = 1; + return 1; +} + +int xusb_claim_interface(struct xusb *xusb) +{ + const struct usb_device_descriptor *dev_desc; + int ret; + + assert(xusb); + xusb_open(xusb); /* If it's not open yet... */ + if(usb_claim_interface(xusb->handle, xusb->interface_num) != 0) { + ERR("usb_claim_interface %d in '%s': %s\n", + xusb->interface_num, xusb->devpath_tail, usb_strerror()); + return 0; + } + xusb->is_claimed = 1; + xusb_fill_strings(xusb); + dev_desc = &xusb->dev->descriptor; + DBG("ID=%04X:%04X Manufacturer=[%s] Product=[%s] SerialNumber=[%s] Interface=[%s]\n", + dev_desc->idVendor, + dev_desc->idProduct, + xusb->iManufacturer, + xusb->iProduct, + xusb->iSerialNumber, + xusb->iInterface); + if(usb_clear_halt(xusb->handle, EP_OUT(xusb)) != 0) { + ERR("Clearing output endpoint: %s\n", usb_strerror()); + return 0; + } + if(usb_clear_halt(xusb->handle, EP_IN(xusb)) != 0) { + ERR("Clearing input endpoint: %s\n", usb_strerror()); + return 0; + } + if((ret = xusb_flushread(xusb)) < 0) { + ERR("xusb_flushread failed: %d\n", ret); + return 0; + } + return 1; +} + +static void xusb_list_dump(struct xlist_node *xusb_list) +{ + struct xlist_node *curr; + struct xusb *xusb; + + for(curr = xusb_list->next; curr != xusb_list; curr = curr->next) { + struct usb_device *dev; + struct usb_bus *bus; + struct usb_device_descriptor *dev_desc; + + xusb = curr->data; + assert(xusb); + dev = xusb->dev; + assert(dev); + bus = dev->bus; + assert(bus); + dev_desc = &dev->descriptor; + assert(dev_desc); + DBG("usb:ID=%04X:%04X [%s / %s / %s], (%s/%s)\n", + dev_desc->idVendor, + dev_desc->idProduct, + xusb->iManufacturer, + xusb->iProduct, + xusb->iSerialNumber, + bus->dirname, + dev->filename + ); + } +} + +void xusb_destroy(struct xusb *xusb) +{ + if(xusb) { + xusb_close(xusb); + memset(xusb, 0, sizeof(*xusb)); + free(xusb); + } +} + +static struct xusb *xusb_new(struct usb_device *dev, const struct xusb_spec *spec) +{ + 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; + size_t max_packet_size; + int i; + struct xusb *xusb = NULL; + + /* + * Get information from the usb_device + */ + if((dev_desc = &dev->descriptor) == NULL) { + ERR("usb device without a device descriptor\n"); + goto fail; + } + if((config_desc = dev->config) == NULL) { + ERR("usb device without a configuration descriptor\n"); + goto fail; + } + interface = &config_desc->interface[spec->my_interface_num]; + iface_desc = interface->altsetting; + endpoint = iface_desc->endpoint; + /* Calculate max packet size */ + max_packet_size = PACKET_SIZE; + for(i = 0; i < iface_desc->bNumEndpoints; i++, endpoint++) { + DBG("Validating endpoint @ %d (interface %d)\n", i, spec->my_interface_num); + if(endpoint->bEndpointAddress == spec->my_ep_out || endpoint->bEndpointAddress == spec->my_ep_in) { + if(endpoint->wMaxPacketSize > PACKET_SIZE) { + ERR("Endpoint #%d wMaxPacketSize too large (%d)\n", i, endpoint->wMaxPacketSize); + goto fail; + } + if(endpoint->wMaxPacketSize < max_packet_size) { + max_packet_size = endpoint->wMaxPacketSize; + } + } + } + /* Fill xusb */ + if((xusb = malloc(sizeof(*xusb))) == NULL) { + ERR("Out of memory"); + goto fail; + } + memset(xusb, 0, sizeof(*xusb)); + xusb->dev = dev; + xusb->spec = spec; + sscanf(dev->bus->dirname, "%d", &xusb->bus_num); + sscanf(dev->filename, "%d", &xusb->device_num); + snprintf(xusb->devpath_tail, PATH_MAX, "%03d/%03d", + xusb->bus_num, xusb->device_num); + xusb->interface_num = spec->my_interface_num; + xusb->ep_out = spec->my_ep_out; + xusb->ep_in = spec->my_ep_in; + xusb->packet_size = max_packet_size; + xusb->is_usb2 = (max_packet_size == 512); + if (! xusb_open(xusb)) { + ERR("Failed opening device: %04X:%04X - %s\n", + dev_desc->idVendor, + dev_desc->idProduct, + xusb->devpath_tail); + goto fail; + } + DBG("%04X:%04X - %s\n", + dev_desc->idVendor, + dev_desc->idProduct, + xusb->devpath_tail); + return xusb; +fail: + xusb_destroy(xusb); + return NULL; +} + +struct xusb *xusb_find_iface(const char *devpath, int iface_num, int ep_out, int ep_in) +{ + struct usb_bus *bus; + + DBG("\n"); + usb_init(); + usb_find_busses(); + usb_find_devices(); + for (bus = usb_get_busses(); bus; bus = bus->next) { + int bus_num; + char tmppath[PATH_MAX + 1]; + struct usb_device *dev; + + tmppath[0] = '\0'; + sscanf(bus->dirname, "%d", &bus_num); + snprintf(tmppath, sizeof(tmppath), "%03d", bus_num); + DBG("Check bus %d: %s ? %s\n", bus_num, tmppath, devpath); + if (strncmp(tmppath, devpath, strlen(tmppath)) != 0) + continue; + DBG("Matched bus %d\n", bus_num); + for (dev = bus->devices; dev; dev = dev->next) { + struct usb_device_descriptor *dev_desc; + struct usb_config_descriptor *config_desc; + struct usb_interface *interface; + struct xusb_spec spec; + struct xusb *xusb; + int device_num; + + sscanf(dev->filename, "%d", &device_num); + DBG("Check device %d\n", device_num); + snprintf(tmppath, sizeof(tmppath), "%03d/%03d", bus_num, device_num); + if (strncmp(tmppath, devpath, strlen(tmppath)) != 0) + continue; + dev_desc = &dev->descriptor; + assert(dev_desc); + config_desc = dev->config; + assert(config_desc); + interface = config_desc->interface; + assert(interface); + INFO("Matched device %s: %X:%X\n", tmppath, dev_desc->idVendor, dev_desc->idProduct); + xusb_init_spec(&spec, "Astribank", + dev_desc->idVendor, dev_desc->idProduct, + config_desc->bNumInterfaces, + iface_num, + interface->altsetting->bNumEndpoints, + ep_out, ep_in); + if((xusb = xusb_new(dev, &spec)) == NULL) { + ERR("xusb allocation failed\n"); + } + return xusb; + } + } + return NULL; +} + +static const char *path_tail(const char *path) +{ + const char *p; + + assert(path != NULL); + /* Find last '/' */ + if((p = memrchr(path, '/', strlen(path))) == NULL) { + ERR("Missing a '/' in %s\n", path); + return NULL; + } + /* Search for a '/' before that */ + if((p = memrchr(path, '/', p - path)) == NULL) { + p = path; /* No more '/' */ + } else { + p++; /* skip '/' */ + } + return p; +} + +int xusb_filter_bypath(const struct xusb *xusb, void *data) +{ + const char *p; + const char *path = data; + + DBG("%s\n", path); + assert(path != NULL); + p = path_tail(path); + if(strcmp(xusb->devpath_tail, p) != 0) { + DBG("device path missmatch: '%s' != '%s'\n", xusb->devpath_tail, p); + return 0; + } + return 1; +} + +struct xusb *xusb_find_bypath(const struct xusb_spec *specs, int numspecs, const char *path) +{ + struct xlist_node *xlist; + struct xlist_node *head; + struct xusb *xusb; + + xlist = xusb_find_byproduct(specs, numspecs, xusb_filter_bypath, (void *)path); + head = xlist_shift(xlist); + if (!head) + return NULL; + if (! xlist_empty(xlist)) { + ERR("Too many matches (extra %zd) to '%s'\n", xlist_length(xlist), path); + return NULL; + } + xusb = head->data; + xlist_destroy(xlist, NULL); + return xusb; +} + +struct xlist_node *xusb_find_byproduct(const struct xusb_spec *specs, int numspecs, xusb_filter_t filterfunc, void *data) +{ + struct xlist_node *xlist; + struct usb_bus *bus; + struct usb_device *dev; + + DBG("specs(%d)\n", numspecs); + if((xlist = xlist_new(NULL)) == NULL) { + ERR("Failed allocation new xlist"); + goto fail_xlist; + } + usb_init(); + usb_find_busses(); + usb_find_devices(); + for (bus = usb_get_busses(); bus; bus = bus->next) { + for (dev = bus->devices; dev; dev = dev->next) { + struct usb_device_descriptor *dev_desc; + struct xlist_node *item; + int i; + + dev_desc = &dev->descriptor; + assert(dev_desc); + DBG("usb:%s/%s: ID=%04X:%04X\n", + dev->bus->dirname, + dev->filename, + dev_desc->idVendor, + dev_desc->idProduct); + for(i = 0; i < numspecs; i++) { + struct xusb *xusb; + const struct xusb_spec *sp = &specs[i]; + + if(!match_interface(dev, sp)) + continue; + if((xusb = xusb_new(dev, sp)) == NULL) { + ERR("xusb allocation failed\n"); + goto fail_malloc; + } + if(filterfunc && !filterfunc(xusb, data)) { + xusb_destroy(xusb); + continue; + } + item = xlist_new(xusb); + xlist_append_item(xlist, item); + break; + } + } + } + xusb_list_dump(xlist); + return xlist; +fail_malloc: + xlist_destroy(xlist, NULL); +fail_xlist: + return NULL; +} + +struct xusb *xusb_open_one(const struct xusb_spec *specs, int numspecs, xusb_filter_t filterfunc, void *data) +{ + struct xlist_node *xusb_list; + struct xlist_node *curr; + int num; + struct xusb *xusb = NULL; + + xusb_list = xusb_find_byproduct(specs, numspecs, filterfunc, data); + num = xlist_length(xusb_list); + DBG("total %d devices\n", num); + switch(num) { + case 0: + ERR("No matching device.\n"); + break; + case 1: + curr = xlist_shift(xusb_list); + xusb = curr->data; + xlist_destroy(curr, NULL); + xlist_destroy(xusb_list, NULL); + xusb_claim_interface(xusb); + xusb_showinfo(xusb); + break; + default: + ERR("Too many devices (%d). Aborting.\n", num); + break; + } + return xusb; +} + +int xusb_interface(struct xusb *xusb) +{ + return xusb->interface_num; +} + +size_t xusb_packet_size(const struct xusb *xusb) +{ + return xusb->packet_size; +} + +/* + * MP device handling + */ +void xusb_showinfo(const struct xusb *xusb) +{ + struct usb_device_descriptor *dev_desc; + struct usb_device *dev; + + assert(xusb != NULL); + dev = xusb->dev; + dev_desc = &dev->descriptor; + if(verbose <= LOG_INFO) { + INFO("usb:%s/%s: ID=%04X:%04X [%s / %s / %s]\n", + dev->bus->dirname, + dev->filename, + dev_desc->idVendor, + dev_desc->idProduct, + xusb->iManufacturer, + xusb->iProduct, + xusb->iSerialNumber); + } else { + printf("USB Bus/Device: [%s/%s] (%s,%s)\n", + dev->bus->dirname, + dev->filename, + (xusb->is_open) ? "open" : "closed", + (xusb->is_claimed) ? "claimed" : "unused"); + printf("USB Spec name: [%s]\n", xusb->spec->name); + printf("USB iManufacturer: [%s]\n", xusb->iManufacturer); + printf("USB iProduct: [%s]\n", xusb->iProduct); + printf("USB iSerialNumber: [%s]\n", xusb->iSerialNumber); + } +} + +const char *xusb_serial(const struct xusb *xusb) +{ + return xusb->iSerialNumber; +} + +const char *xusb_devpath(const struct xusb *xusb) +{ + return xusb->devpath_tail; +} + +const char *xusb_manufacturer(const struct xusb *xusb) +{ + return xusb->iManufacturer; +} + +const char *xusb_product(const struct xusb *xusb) +{ + return xusb->iProduct; +} + +uint16_t xusb_vendor_id(const struct xusb *xusb) +{ + return xusb->dev->descriptor.idVendor; +} + +uint16_t xusb_product_id(const struct xusb *xusb) +{ + return xusb->dev->descriptor.idProduct; +} + +const struct xusb_spec *xusb_spec(const struct xusb *xusb) +{ + return xusb->spec; +} + +int xusb_close(struct xusb *xusb) +{ + if(xusb) { + if(xusb->handle) { + assert(xusb->spec); + assert(xusb->spec->name); + DBG("Closing interface \"%s\"\n", xusb->spec->name); + if(xusb->is_claimed) { + if(usb_release_interface(xusb->handle, xusb->spec->my_interface_num) != 0) { + ERR("Releasing interface: usb: %s\n", usb_strerror()); + } + xusb->is_claimed = 0; + } + if(xusb->is_open) { + if(usb_close(xusb->handle) != 0) { + ERR("Closing device: usb: %s\n", usb_strerror()); + } + xusb->is_open = 0; + } + xusb->handle = NULL; + } + xusb = NULL; + } + return 0; +} + +int xusb_send(struct xusb *xusb, char *buf, int len, int timeout) +{ + int ret; + + dump_packet(LOG_DEBUG, DBG_MASK, __FUNCTION__, buf, len); + if(EP_OUT(xusb) & USB_ENDPOINT_IN) { + ERR("%s called with an input endpoint 0x%x\n", __FUNCTION__, EP_OUT(xusb)); + return -EINVAL; + } + ret = usb_bulk_write(xusb->handle, EP_OUT(xusb), buf, 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: (%d) %s\n", + EP_OUT(xusb), ret, usb_strerror()); + dump_packet(LOG_ERR, DBG_MASK, "xbus_send[ERR]", buf, len); + //exit(2); + } else { + DBG("bulk_write to endpoint 0x%x got ENODEV\n", EP_OUT(xusb)); + xusb_close(xusb); + } + return ret; + } else if(ret != len) { + ERR("bulk_write to endpoint 0x%x short write: (%d) %s\n", + EP_OUT(xusb), ret, usb_strerror()); + dump_packet(LOG_ERR, DBG_MASK, "xbus_send[ERR]", buf, len); + return -EFAULT; + } + return ret; +} + +int xusb_recv(struct xusb *xusb, char *buf, size_t len, int timeout) +{ + int ret; + + if(EP_IN(xusb) & USB_ENDPOINT_OUT) { + ERR("%s called with an output endpoint 0x%x\n", __FUNCTION__, EP_IN(xusb)); + return -EINVAL; + } + ret = usb_bulk_read(xusb->handle, EP_IN(xusb), buf, len, timeout); + if(ret < 0) { + DBG("bulk_read from endpoint 0x%x failed: (%d) %s\n", + EP_IN(xusb), ret, usb_strerror()); + memset(buf, 0, len); + return ret; + } + dump_packet(LOG_DEBUG, DBG_MASK, __FUNCTION__, buf, ret); + return ret; +} + +int xusb_flushread(struct xusb *xusb) +{ + char tmpbuf[BUFSIZ]; + int ret; + + DBG("starting...\n"); + memset(tmpbuf, 0, BUFSIZ); + ret = xusb_recv(xusb, tmpbuf, BUFSIZ, 1); + if(ret < 0 && ret != -ETIMEDOUT) { + ERR("ret=%d\n", ret); + return ret; + } else if(ret > 0) { + DBG("Got %d bytes:\n", ret); + dump_packet(LOG_DEBUG, DBG_MASK, __FUNCTION__, tmpbuf, ret); + } + return 0; +} diff --git a/xpp/xtalk/xusb.h b/xpp/xtalk/xusb.h new file mode 100644 index 0000000..65da029 --- /dev/null +++ b/xpp/xtalk/xusb.h @@ -0,0 +1,98 @@ +#ifndef XUSB_H +#define XUSB_H +/* + * Written by Oron Peled + * Copyright (C) 2008, Xorcom + * + * All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + */ + +#include +#include +#include +#include + +#ifdef __cplusplus +extern "C" +{ +#endif /* __cplusplus */ + +/* + * Xorcom usb handling + */ + +#define PACKET_SIZE 512 + +/* + * Specify the wanted interface + */ +struct xusb_spec { + /* Sanity checks so we know it is our device indeed */ + int num_interfaces; + int num_endpoints; + char *name; /* For debug/output purpose */ + /* What we will actually use */ + uint16_t my_vendor_id; + uint16_t my_product_id; + int my_interface_num; + int my_ep_out; + int my_ep_in; +}; + +void xusb_init_spec(struct xusb_spec *xusb_spec, char *name, + uint16_t vendor_id, uint16_t product_id, + int nifaces, int iface, int nep, int ep_out, int ep_in); + +struct xusb; + +/* + * Prototypes + */ +typedef int (*xusb_filter_t)(const struct xusb *xusb, void *data); +struct xlist_node *xusb_find_byproduct(const struct xusb_spec *specs, int numspecs, xusb_filter_t filterfunc, void *data); +struct xusb *xusb_find_bypath(const struct xusb_spec *specs, int numspecs, const char *path); +struct xusb *xusb_open_one(const struct xusb_spec *specs, int numspecs, xusb_filter_t filterfunc, void *data); +struct xusb *xusb_find_iface(const char *devpath, int iface_num, int ep_out, int ep_in); + +/* + * A convenience filter + */ +int xusb_filter_bypath(const struct xusb *xusb, void *data); + +int xusb_interface(struct xusb *xusb); +int xusb_claim_interface(struct xusb *xusb); +void xusb_destroy(struct xusb *xusb); +int xusb_close(struct xusb *xusb); +size_t xusb_packet_size(const struct xusb *xusb); +void xusb_showinfo(const struct xusb *xusb); +const char *xusb_serial(const struct xusb *xusb); +const char *xusb_manufacturer(const struct xusb *xusb); +const char *xusb_product(const struct xusb *xusb); +uint16_t xusb_vendor_id(const struct xusb *xusb); +uint16_t xusb_product_id(const struct xusb *xusb); +const char *xusb_devpath(const struct xusb *xusb); +const struct xusb_spec *xusb_spec(const struct xusb *xusb); +int xusb_send(struct xusb *xusb, char *buf, int len, int timeout); +int xusb_recv(struct xusb *xusb, char *buf, size_t len, int timeout); +int xusb_flushread(struct xusb *xusb); + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + +#endif /* XUSB_H */