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 <oron.peled@xorcom.com> Acked-by: Tzafrir Cohen <tzafrir.cohen@xorcom.com> git-svn-id: http://svn.astersk.org/svn/dahdi/tools/trunk@9825 17933a7a-c749-41c5-a318-cba88f637d49
This commit is contained in:
parent
366eccb556
commit
1c1fe1fd94
17
xpp/Makefile
17
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
|
||||
|
@ -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
|
||||
|
||||
|
@ -32,8 +32,8 @@
|
||||
#include <arpa/inet.h>
|
||||
#include <ctype.h>
|
||||
#include "mpp.h"
|
||||
#include "mpp_funcs.h"
|
||||
#include "debug.h"
|
||||
#include "mpptalk.h"
|
||||
#include <debug.h>
|
||||
|
||||
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;
|
||||
}
|
||||
|
@ -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
|
||||
|
||||
|
@ -27,9 +27,9 @@
|
||||
#include <errno.h>
|
||||
#include <assert.h>
|
||||
#include <arpa/inet.h>
|
||||
#include "debug.h"
|
||||
#include <debug.h>
|
||||
#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;
|
||||
|
@ -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
|
||||
|
||||
|
@ -28,8 +28,10 @@
|
||||
#include <getopt.h>
|
||||
#include <sys/types.h>
|
||||
#include <arpa/inet.h>
|
||||
#include "mpp_funcs.h"
|
||||
#include "debug.h"
|
||||
#include "astribank_usb.h"
|
||||
#include "mpptalk.h"
|
||||
#include <debug.h>
|
||||
#include <xusb.h>
|
||||
|
||||
#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);
|
||||
|
@ -30,39 +30,44 @@
|
||||
#include <stdarg.h>
|
||||
#include <syslog.h>
|
||||
#include <arpa/inet.h>
|
||||
#include <xusb.h>
|
||||
#include "astribank_usb.h"
|
||||
#include "debug.h"
|
||||
#include <debug.h>
|
||||
|
||||
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;
|
||||
|
@ -23,7 +23,8 @@
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <usb.h>
|
||||
#include <xusb.h>
|
||||
#include <xtalk.h>
|
||||
#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;
|
||||
};
|
||||
|
||||
|
211
xpp/mpp.h
211
xpp/mpp.h
@ -26,6 +26,10 @@
|
||||
* MPP - Managment Processor Protocol definitions
|
||||
*/
|
||||
|
||||
#include <mpptalk_defs.h>
|
||||
#include <stdint.h>
|
||||
#include <xtalk.h>
|
||||
|
||||
#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 */
|
||||
|
1109
xpp/mpp_funcs.c
1109
xpp/mpp_funcs.c
File diff suppressed because it is too large
Load Diff
915
xpp/mpptalk.c
Normal file
915
xpp/mpptalk.c
Normal file
@ -0,0 +1,915 @@
|
||||
/*
|
||||
* Written by Oron Peled <oron@actcom.co.il>
|
||||
* 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 <stdio.h>
|
||||
#include <string.h>
|
||||
#include <assert.h>
|
||||
#include <errno.h>
|
||||
#include <arpa/inet.h>
|
||||
#include "hexfile.h"
|
||||
#include "astribank_usb.h"
|
||||
#include "mpp.h"
|
||||
#include "mpptalk.h"
|
||||
#include <debug.h>
|
||||
#include <xusb.h>
|
||||
#include <xtalk.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(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;
|
||||
}
|
@ -22,13 +22,22 @@
|
||||
*
|
||||
*/
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#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 */
|
111
xpp/mpptalk_defs.h
Normal file
111
xpp/mpptalk_defs.h
Normal file
@ -0,0 +1,111 @@
|
||||
#ifndef MPPTALK_DEFS_H
|
||||
#define MPPTALK_DEFS_H
|
||||
/*
|
||||
* Written by Oron Peled <oron@actcom.co.il>
|
||||
* 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 <xtalk_defs.h>
|
||||
/*
|
||||
* 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 */
|
@ -27,7 +27,8 @@
|
||||
#include <regex.h>
|
||||
#include "hexfile.h"
|
||||
#include "pic_loader.h"
|
||||
#include "debug.h"
|
||||
#include <debug.h>
|
||||
#include <xusb.h>
|
||||
|
||||
#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;
|
||||
|
@ -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."
|
||||
}
|
||||
|
||||
#
|
||||
|
@ -20,11 +20,14 @@
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdint.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdarg.h>
|
||||
#include <syslog.h>
|
||||
#include "debug.h"
|
||||
#include <execinfo.h>
|
||||
#include <debug.h>
|
||||
|
||||
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);
|
||||
}
|
@ -23,6 +23,7 @@
|
||||
*/
|
||||
|
||||
#include <syslog.h>
|
||||
#include <stdio.h>
|
||||
|
||||
/*
|
||||
* 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 */
|
93
xpp/xtalk/xlist.c
Normal file
93
xpp/xtalk/xlist.c
Normal file
@ -0,0 +1,93 @@
|
||||
#include <assert.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <xlist.h>
|
||||
|
||||
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;
|
||||
}
|
29
xpp/xtalk/xlist.h
Normal file
29
xpp/xtalk/xlist.h
Normal file
@ -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 */
|
497
xpp/xtalk/xtalk.c
Normal file
497
xpp/xtalk/xtalk.c
Normal file
@ -0,0 +1,497 @@
|
||||
/*
|
||||
* Written by Oron Peled <oron@actcom.co.il>
|
||||
* 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 <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <assert.h>
|
||||
#include <errno.h>
|
||||
#include <arpa/inet.h>
|
||||
#include <xtalk.h>
|
||||
#include <debug.h>
|
||||
|
||||
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);
|
||||
}
|
172
xpp/xtalk/xtalk.h
Normal file
172
xpp/xtalk/xtalk.h
Normal file
@ -0,0 +1,172 @@
|
||||
#ifndef XTALK_H
|
||||
#define XTALK_H
|
||||
/*
|
||||
* Written by Oron Peled <oron@actcom.co.il>
|
||||
* 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 <stdint.h>
|
||||
#include <stdlib.h>
|
||||
/* Definitions common to the firmware (in include/ directory) */
|
||||
#include <xtalk_defs.h>
|
||||
|
||||
#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 */
|
40
xpp/xtalk/xtalk_defs.h
Normal file
40
xpp/xtalk/xtalk_defs.h
Normal file
@ -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 */
|
726
xpp/xtalk/xusb.c
Normal file
726
xpp/xtalk/xusb.c
Normal file
@ -0,0 +1,726 @@
|
||||
/*
|
||||
* Written by Oron Peled <oron@actcom.co.il>
|
||||
* 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 <stdio.h>
|
||||
#include <string.h>
|
||||
#include <assert.h>
|
||||
#include <errno.h>
|
||||
#include <stdarg.h>
|
||||
#include <syslog.h>
|
||||
#include <arpa/inet.h>
|
||||
#include <debug.h>
|
||||
#include <xusb.h>
|
||||
|
||||
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;
|
||||
}
|
98
xpp/xtalk/xusb.h
Normal file
98
xpp/xtalk/xusb.h
Normal file
@ -0,0 +1,98 @@
|
||||
#ifndef XUSB_H
|
||||
#define XUSB_H
|
||||
/*
|
||||
* Written by Oron Peled <oron@actcom.co.il>
|
||||
* 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 <stdio.h>
|
||||
#include <stdint.h>
|
||||
#include <usb.h>
|
||||
#include <xlist.h>
|
||||
|
||||
#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 */
|
Loading…
Reference in New Issue
Block a user