xpp: migrate everything to libxtalk
* Build new libxtalk as local convenience library * Have new mpptalk.[ch] and astribank.[ch] wrap the new API * Modify all tools to use the new API Signed-off-by: Oron Peled <oron.peled@xorcom.com> Signed-off-by: Tzafrir Cohen <tzafrir.cohen@xorcom.com>
This commit is contained in:
parent
9c61e40187
commit
0e6b068e89
@ -8,7 +8,7 @@ man_MANS =
|
||||
|
||||
# FIXME: try to improve code, so we can use $(PEDANTIC)
|
||||
#PEDANTIC = -ansi -pedantic -std=c99
|
||||
GLOBAL_CFLAGS = -I$(srcdir) -I$(srcdir)/xtalk $(PEDANTIC)
|
||||
GLOBAL_CFLAGS = -I$(srcdir) -I$(srcdir)/xtalk/include $(PEDANTIC) -Wall
|
||||
|
||||
if DAHDI_DEVMODE
|
||||
GLOBAL_CFLAGS += \
|
||||
@ -81,24 +81,14 @@ endif
|
||||
noinst_LTLIBRARIES = libastribank.la libecholoader.la libhexfile.la
|
||||
|
||||
libastribank_la_SOURCES = \
|
||||
astribank_usb.c \
|
||||
astribank_usb.h \
|
||||
astribank.c \
|
||||
astribank.h \
|
||||
mpptalk.c \
|
||||
mpptalk.h \
|
||||
mpp.h \
|
||||
mpptalk_defs.h \
|
||||
xtalk/debug.c \
|
||||
xtalk/debug.h \
|
||||
xtalk/xlist.c \
|
||||
xtalk/xlist.h \
|
||||
xtalk/xtalk.c \
|
||||
xtalk/xtalk.h \
|
||||
xtalk/xtalk_defs.h \
|
||||
xtalk/xusb.c \
|
||||
xtalk/xusb.h \
|
||||
#
|
||||
|
||||
libastribank_la_CFLAGS = $(GLOBAL_CFLAGS)
|
||||
libastribank_la_LIBADD = xtalk/libxtalk.la
|
||||
|
||||
if USE_OCTASIC
|
||||
libecholoader_la_SOURCES = \
|
||||
|
177
xpp/astribank.c
Normal file
177
xpp/astribank.c
Normal file
@ -0,0 +1,177 @@
|
||||
#include <assert.h>
|
||||
#include <errno.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <xtalk/debug.h>
|
||||
#include <xtalk/xusb.h>
|
||||
#include "mpptalk.h"
|
||||
#include "astribank.h"
|
||||
|
||||
#define DBG_MASK 0x08
|
||||
|
||||
struct astribank {
|
||||
struct xusb_device *xusb_device;
|
||||
struct xusb_iface *xpp_iface;
|
||||
struct xusb_iface *mpp_iface;
|
||||
struct mpp_device *mpp;
|
||||
char *path;
|
||||
};
|
||||
|
||||
|
||||
struct astribank *astribank_new(const char *path)
|
||||
{
|
||||
struct astribank *ab;
|
||||
|
||||
ab = calloc(sizeof(*ab), 1);
|
||||
if (!ab) {
|
||||
ERR("%s: Failed allocating Astribank device\n", path);
|
||||
goto err;
|
||||
}
|
||||
ab->xusb_device = xusb_find_bypath(path);
|
||||
if (!ab->xusb_device) {
|
||||
ERR("%s: Cannot find Astribank\n", path);
|
||||
goto err;
|
||||
}
|
||||
ab->path = strdup(path);
|
||||
if (!ab->path) {
|
||||
ERR("%s: Failed allocating Astribank path\n", path);
|
||||
goto err;
|
||||
}
|
||||
return ab;
|
||||
err:
|
||||
astribank_destroy(ab);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void astribank_destroy(struct astribank *ab)
|
||||
{
|
||||
if (ab) {
|
||||
if (ab->path)
|
||||
free(ab->path);
|
||||
if (ab->xpp_iface)
|
||||
xusb_release(ab->xpp_iface);
|
||||
if (ab->mpp) {
|
||||
mpp_delete(ab->mpp); /* this also closes the underlying xusb */
|
||||
ab->mpp = NULL;
|
||||
}
|
||||
if (ab->xusb_device) {
|
||||
xusb_destroy(ab->xusb_device);
|
||||
ab->xusb_device = NULL;
|
||||
}
|
||||
free(ab);
|
||||
ab = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
struct xusb_iface *astribank_xpp_open(struct astribank *ab)
|
||||
{
|
||||
int ret;
|
||||
|
||||
ret = xusb_claim(ab->xusb_device, 0, &ab->xpp_iface);
|
||||
if (ret < 0) {
|
||||
ERR("%s: Cannot claim XPP interface\n", ab->path);
|
||||
goto err;
|
||||
}
|
||||
DBG("%s: Claimed Astribank XPP interface\n", ab->path);
|
||||
return ab->xpp_iface;
|
||||
err:
|
||||
if (ab->xpp_iface)
|
||||
xusb_release(ab->xpp_iface);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
struct mpp_device *astribank_mpp_open(struct astribank *ab)
|
||||
{
|
||||
int ret;
|
||||
|
||||
ret = xusb_claim(ab->xusb_device, 1, &ab->mpp_iface);
|
||||
if (ret < 0) {
|
||||
ERR("%s: Cannot claim MPP interface\n", ab->path);
|
||||
goto err;
|
||||
}
|
||||
DBG("%s: Claimed Astribank MPP interface\n", ab->path);
|
||||
ab->mpp = mpp_new(ab->mpp_iface);
|
||||
if (!ab->mpp) {
|
||||
ERR("Failed initializing MPP protocol\n");
|
||||
goto err;
|
||||
}
|
||||
ret = mpp_status_query(ab->mpp);
|
||||
if (ret < 0) {
|
||||
ERR("status query failed (ret=%d)\n", ret);
|
||||
goto err;
|
||||
}
|
||||
return ab->mpp;
|
||||
err:
|
||||
if (ab->mpp) {
|
||||
mpp_delete(ab->mpp); /* this also closes the underlying xusb */
|
||||
ab->mpp = NULL;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
struct xusb_device *xusb_dev_of_astribank(const struct astribank *ab)
|
||||
{
|
||||
assert(ab->xusb_device);
|
||||
return ab->xusb_device;
|
||||
}
|
||||
|
||||
const char *astribank_devpath(const struct astribank *ab)
|
||||
{
|
||||
return xusb_devpath(ab->xusb_device);
|
||||
}
|
||||
|
||||
const char *astribank_serial(const struct astribank *ab)
|
||||
{
|
||||
return xusb_serial(ab->xusb_device);
|
||||
}
|
||||
|
||||
void show_astribank_info(const struct astribank *ab)
|
||||
{
|
||||
struct xusb_device *xusb_device;
|
||||
|
||||
assert(ab != NULL);
|
||||
xusb_device = ab->xusb_device;
|
||||
assert(xusb_device != NULL);
|
||||
if(verbose <= LOG_INFO) {
|
||||
xusb_showinfo(xusb_device);
|
||||
} else {
|
||||
const struct xusb_spec *spec;
|
||||
|
||||
spec = xusb_spec(xusb_device);
|
||||
printf("USB Bus/Device: [%s]\n", xusb_devpath(xusb_device));
|
||||
printf("USB Firmware Type: [%s]\n", spec->name);
|
||||
printf("USB iSerialNumber: [%s]\n", xusb_serial(xusb_device));
|
||||
printf("USB iManufacturer: [%s]\n", xusb_manufacturer(xusb_device));
|
||||
printf("USB iProduct: [%s]\n", xusb_product(xusb_device));
|
||||
}
|
||||
}
|
||||
|
||||
int astribank_send(struct astribank *ab, int interface_num, const char *buf, int len, int timeout)
|
||||
{
|
||||
struct xusb_iface *iface;
|
||||
|
||||
if (interface_num == 0)
|
||||
iface = ab->xpp_iface;
|
||||
else if (interface_num == 1)
|
||||
iface = ab->mpp_iface;
|
||||
else {
|
||||
ERR("Unknown interface number (%d)\n", interface_num);
|
||||
return -EINVAL;
|
||||
}
|
||||
return xusb_send(iface, buf, len, timeout);
|
||||
}
|
||||
|
||||
int astribank_recv(struct astribank *ab, int interface_num, char *buf, size_t len, int timeout)
|
||||
{
|
||||
struct xusb_iface *iface;
|
||||
|
||||
if (interface_num == 0)
|
||||
iface = ab->xpp_iface;
|
||||
else if (interface_num == 1)
|
||||
iface = ab->mpp_iface;
|
||||
else {
|
||||
ERR("Unknown interface number (%d)\n", interface_num);
|
||||
return -EINVAL;
|
||||
}
|
||||
return xusb_recv(iface, buf, len, timeout);
|
||||
}
|
33
xpp/astribank.h
Normal file
33
xpp/astribank.h
Normal file
@ -0,0 +1,33 @@
|
||||
#ifndef ASTRIBANK_H
|
||||
#define ASTRIBANK_H
|
||||
|
||||
#include <mpptalk.h>
|
||||
|
||||
struct astribank *astribank_new(const char *path);
|
||||
void astribank_destroy(struct astribank *ab);
|
||||
void show_astribank_info(const struct astribank *ab);
|
||||
|
||||
struct xusb_iface *astribank_xpp_open(struct astribank *ab);
|
||||
struct mpp_device *astribank_mpp_open(struct astribank *ab);
|
||||
|
||||
struct xusb_device *xusb_dev_of_astribank(const struct astribank *ab);
|
||||
const char *astribank_devpath(const struct astribank *ab);
|
||||
const char *astribank_serial(const struct astribank *ab);
|
||||
|
||||
int astribank_send(struct astribank *ab, int interface_num, const char *buf, int len, int timeout);
|
||||
int astribank_recv(struct astribank *ab, int interface_num, char *buf, size_t len, int timeout);
|
||||
|
||||
|
||||
#define AB_REPORT(report_type, astribank, fmt, ...) \
|
||||
report_type("%s [%s]: " fmt, \
|
||||
astribank_devpath(astribank), \
|
||||
astribank_serial(astribank), \
|
||||
## __VA_ARGS__)
|
||||
|
||||
#define AB_INFO(astribank, fmt, ...) \
|
||||
AB_REPORT(INFO, astribank, fmt, ## __VA_ARGS__)
|
||||
|
||||
#define AB_ERR(astribank, fmt, ...) \
|
||||
AB_REPORT(ERR, astribank, fmt, ## __VA_ARGS__)
|
||||
|
||||
#endif /* ASTRIBANK_H */
|
@ -31,9 +31,9 @@
|
||||
#include <sys/types.h>
|
||||
#include <arpa/inet.h>
|
||||
#include <ctype.h>
|
||||
#include "mpp.h"
|
||||
#include <xtalk/debug.h>
|
||||
#include "mpptalk.h"
|
||||
#include <debug.h>
|
||||
#include "astribank.h"
|
||||
#include "astribank_license.h"
|
||||
|
||||
static const char rcsid[] = "$Id$";
|
||||
@ -55,28 +55,11 @@ static void usage()
|
||||
exit(1);
|
||||
}
|
||||
|
||||
static int capabilities_burn(
|
||||
struct astribank_device *astribank,
|
||||
struct eeprom_table *eeprom_table,
|
||||
struct capabilities *capabilities,
|
||||
struct capkey *key)
|
||||
{
|
||||
int ret;
|
||||
|
||||
INFO("Burning capabilities\n");
|
||||
ret = mpp_caps_set(astribank, eeprom_table, capabilities, key);
|
||||
if(ret < 0) {
|
||||
ERR("Capabilities burning failed: %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
INFO("Done\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
char *devpath = NULL;
|
||||
struct astribank_device *astribank;
|
||||
struct astribank *astribank;
|
||||
struct mpp_device *mpp;
|
||||
struct eeprom_table eeprom_table;
|
||||
struct capabilities caps;
|
||||
struct capkey key;
|
||||
@ -127,16 +110,19 @@ int main(int argc, char *argv[])
|
||||
usage();
|
||||
}
|
||||
DBG("Startup %s\n", devpath);
|
||||
if((astribank = mpp_init(devpath, 1)) == NULL) {
|
||||
ERR("Failed initializing MPP\n");
|
||||
astribank = astribank_new(devpath);
|
||||
if(!astribank) {
|
||||
ERR("Failed initializing Astribank\n");
|
||||
return 1;
|
||||
}
|
||||
if(astribank->eeprom_type != EEPROM_TYPE_LARGE) {
|
||||
mpp = astribank_mpp_open(astribank);
|
||||
ret = mpp_eeprom_type(mpp);
|
||||
if(ret != EEPROM_TYPE_LARGE) {
|
||||
ERR("Cannot use this program with astribank EEPROM type %d (need %d)\n",
|
||||
astribank->eeprom_type, EEPROM_TYPE_LARGE);
|
||||
ret, EEPROM_TYPE_LARGE);
|
||||
return 1;
|
||||
}
|
||||
ret = mpp_caps_get(astribank, &eeprom_table, &caps, &key);
|
||||
ret = mpp_caps_get(mpp, &eeprom_table, &caps, &key);
|
||||
if(ret < 0) {
|
||||
ERR("Failed to get original capabilities: %d\n", ret);
|
||||
return 1;
|
||||
@ -158,8 +144,13 @@ int main(int argc, char *argv[])
|
||||
return 1;
|
||||
}
|
||||
show_capabilities(&caps, stderr);
|
||||
if (capabilities_burn(astribank, &eeprom_table, &caps, &key) < 0)
|
||||
INFO("Burning capabilities\n");
|
||||
ret = mpp_caps_set(mpp, &eeprom_table, &caps, &key);
|
||||
if(ret < 0) {
|
||||
ERR("Capabilities burning failed: %d\n", ret);
|
||||
return 1;
|
||||
}
|
||||
INFO("Done\n");
|
||||
if (file != stdin)
|
||||
fclose(file);
|
||||
} else {
|
||||
@ -180,6 +171,6 @@ int main(int argc, char *argv[])
|
||||
if (file != stdout)
|
||||
fclose(file);
|
||||
}
|
||||
mpp_exit(astribank);
|
||||
astribank_destroy(astribank);
|
||||
return 0;
|
||||
}
|
||||
|
@ -28,13 +28,14 @@
|
||||
#include <errno.h>
|
||||
#include <assert.h>
|
||||
#include <arpa/inet.h>
|
||||
#include <debug.h>
|
||||
#include <autoconfig.h>
|
||||
#include <xtalk/debug.h>
|
||||
#include <xtalk/xusb.h>
|
||||
#include "hexfile.h"
|
||||
#include "mpptalk.h"
|
||||
#include "astribank.h"
|
||||
#include "pic_loader.h"
|
||||
#include "echo_loader.h"
|
||||
#include "astribank_usb.h"
|
||||
#include "../autoconfig.h"
|
||||
|
||||
#define DBG_MASK 0x80
|
||||
#define MAX_HEX_LINES 64000
|
||||
@ -61,7 +62,7 @@ static void usage()
|
||||
exit(1);
|
||||
}
|
||||
|
||||
int handle_hexline(struct astribank_device *astribank, struct hexline *hexline)
|
||||
int handle_hexline(struct mpp_device *mpp, struct hexline *hexline)
|
||||
{
|
||||
uint16_t len;
|
||||
uint16_t offset_dummy;
|
||||
@ -69,7 +70,7 @@ int handle_hexline(struct astribank_device *astribank, struct hexline *hexline)
|
||||
int ret;
|
||||
|
||||
assert(hexline);
|
||||
assert(astribank);
|
||||
assert(mpp);
|
||||
if(hexline->d.content.header.tt != TT_DATA) {
|
||||
DBG("Non data record type = %d\n", hexline->d.content.header.tt);
|
||||
return 0;
|
||||
@ -77,7 +78,7 @@ int handle_hexline(struct astribank_device *astribank, struct hexline *hexline)
|
||||
len = hexline->d.content.header.ll;
|
||||
offset_dummy = hexline->d.content.header.offset;
|
||||
data = hexline->d.content.tt_data.data;
|
||||
if((ret = mpp_send_seg(astribank, data, offset_dummy, len)) < 0) {
|
||||
if((ret = mpp_send_seg(mpp, data, offset_dummy, len)) < 0) {
|
||||
ERR("Failed hexfile send line: %d\n", ret);
|
||||
return -EINVAL;
|
||||
}
|
||||
@ -100,7 +101,7 @@ static void print_parse_errors(int level, const char *msg, ...)
|
||||
}
|
||||
}
|
||||
|
||||
static int load_hexfile(struct astribank_device *astribank, const char *hexfile, enum dev_dest dest)
|
||||
static int load_hexfile(struct mpp_device *mpp, const char *hexfile, enum dev_dest dest)
|
||||
{
|
||||
struct hexdata *hexdata = NULL;
|
||||
int finished = 0;
|
||||
@ -108,19 +109,24 @@ static int load_hexfile(struct astribank_device *astribank, const char *hexfile,
|
||||
unsigned i;
|
||||
char star[] = "+\\+|+/+-";
|
||||
const char *devstr;
|
||||
struct xusb_device *xusb_device;
|
||||
struct xusb_iface *xusb_iface;
|
||||
|
||||
|
||||
parse_hexfile_set_reporting(print_parse_errors);
|
||||
if((hexdata = parse_hexfile(hexfile, MAX_HEX_LINES)) == NULL) {
|
||||
perror(hexfile);
|
||||
return -errno;
|
||||
}
|
||||
devstr = xusb_devpath(astribank->xusb);
|
||||
xusb_iface = xubs_iface_of_mpp(mpp);
|
||||
xusb_device = xusb_deviceof(xusb_iface);
|
||||
devstr = xusb_devpath(xusb_device);
|
||||
INFO("%s [%s]: Loading %s Firmware: %s (version %s)\n",
|
||||
devstr,
|
||||
xusb_serial(astribank->xusb),
|
||||
xusb_serial(xusb_device),
|
||||
dev_dest2str(dest),
|
||||
hexdata->fname, hexdata->version_info);
|
||||
if((ret = mpp_send_start(astribank, dest, hexdata->version_info)) < 0) {
|
||||
if((ret = mpp_send_start(mpp, dest, hexdata->version_info)) < 0) {
|
||||
ERR("%s: Failed hexfile send start: %d\n", devstr, ret);
|
||||
return ret;
|
||||
}
|
||||
@ -142,7 +148,7 @@ static int load_hexfile(struct astribank_device *astribank, const char *hexfile,
|
||||
finished = 1;
|
||||
continue;
|
||||
}
|
||||
if((ret = handle_hexline(astribank, hexline)) < 0) {
|
||||
if((ret = handle_hexline(mpp, hexline)) < 0) {
|
||||
ERR("%s: Failed hexfile sending in lineno %d (ret=%d)\n", devstr, i, ret);;
|
||||
return ret;
|
||||
}
|
||||
@ -151,7 +157,7 @@ static int load_hexfile(struct astribank_device *astribank, const char *hexfile,
|
||||
putchar('\n');
|
||||
fflush(stdout);
|
||||
}
|
||||
if((ret = mpp_send_end(astribank)) < 0) {
|
||||
if((ret = mpp_send_end(mpp)) < 0) {
|
||||
ERR("%s: Failed hexfile send end: %d\n", devstr, ret);
|
||||
return ret;
|
||||
}
|
||||
@ -178,7 +184,6 @@ int main(int argc, char *argv[])
|
||||
int opt_sum = 0;
|
||||
enum dev_dest dest = DEST_NONE;
|
||||
const char options[] = "vd:D:EFOopAS:";
|
||||
int iface_num;
|
||||
int ret;
|
||||
|
||||
progname = argv[0];
|
||||
@ -247,7 +252,6 @@ int main(int argc, char *argv[])
|
||||
" and -p options are mutually exclusive, if neither is used then -o should present\n");
|
||||
usage();
|
||||
}
|
||||
iface_num = (opt_dest) ? 1 : 0;
|
||||
if(!opt_pic && !opt_ecver) {
|
||||
if(optind != argc - 1) {
|
||||
ERR("Got %d hexfile names (Need exactly one hexfile)\n",
|
||||
@ -270,29 +274,43 @@ int main(int argc, char *argv[])
|
||||
/*
|
||||
* MPP Interface
|
||||
*/
|
||||
struct astribank_device *astribank;
|
||||
struct astribank *astribank;
|
||||
struct mpp_device *mpp;
|
||||
|
||||
if((astribank = mpp_init(devpath, iface_num)) == NULL) {
|
||||
astribank = astribank_new(devpath);
|
||||
if(!astribank) {
|
||||
ERR("%s: Opening astribank failed\n", devpath);
|
||||
return 1;
|
||||
}
|
||||
//show_astribank_info(astribank);
|
||||
if(load_hexfile(astribank, argv[optind], dest) < 0) {
|
||||
mpp = astribank_mpp_open(astribank);
|
||||
if(!mpp) {
|
||||
ERR("%s: Opening astribank XPP interface failed\n", devpath);
|
||||
return 1;
|
||||
}
|
||||
show_astribank_info(astribank);
|
||||
if(load_hexfile(mpp, argv[optind], dest) < 0) {
|
||||
ERR("%s: Loading firmware to %s failed\n", devpath, dev_dest2str(dest));
|
||||
return 1;
|
||||
}
|
||||
astribank_close(astribank, 0);
|
||||
astribank_destroy(astribank);
|
||||
} else if(opt_pic || opt_echo || opt_ecver) {
|
||||
/*
|
||||
* XPP Interface
|
||||
*/
|
||||
struct astribank_device *astribank;
|
||||
struct astribank *astribank;
|
||||
struct xusb_iface *xpp_iface;
|
||||
|
||||
if((astribank = astribank_open(devpath, iface_num)) == NULL) {
|
||||
astribank = astribank_new(devpath);
|
||||
if (!astribank) {
|
||||
ERR("%s: Opening astribank failed\n", devpath);
|
||||
return 1;
|
||||
}
|
||||
//show_astribank_info(astribank);
|
||||
xpp_iface = astribank_xpp_open(astribank);
|
||||
if(!xpp_iface) {
|
||||
ERR("%s: Opening astribank XPP interface failed\n", devpath);
|
||||
return 1;
|
||||
}
|
||||
show_astribank_info(astribank);
|
||||
#if HAVE_OCTASIC
|
||||
if (opt_ecver) {
|
||||
if((ret = echo_ver(astribank)) < 0) {
|
||||
@ -315,7 +333,7 @@ int main(int argc, char *argv[])
|
||||
}
|
||||
#endif
|
||||
}
|
||||
astribank_close(astribank, 0);
|
||||
astribank_destroy(astribank);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
@ -24,7 +24,7 @@
|
||||
#include <stdio.h>
|
||||
#include <ctype.h>
|
||||
#include <string.h>
|
||||
#include <debug.h>
|
||||
#include <xtalk/debug.h>
|
||||
#include "astribank_license.h"
|
||||
|
||||
#define ARRAY_SIZE(a) (sizeof(a)/sizeof((a)[0]))
|
||||
|
@ -1,7 +1,7 @@
|
||||
#ifndef ASTRIBANK_ALLOW_H
|
||||
#define ASTRIBANK_ALLOW_H
|
||||
|
||||
#include "mpp.h"
|
||||
#include "mpptalk.h"
|
||||
|
||||
enum license_markers {
|
||||
LICENSE_MARKER_NONE = 0,
|
||||
|
@ -28,10 +28,10 @@
|
||||
#include <getopt.h>
|
||||
#include <sys/types.h>
|
||||
#include <arpa/inet.h>
|
||||
#include "astribank_usb.h"
|
||||
#include <xtalk/debug.h>
|
||||
#include <xtalk/xusb.h>
|
||||
#include "mpptalk.h"
|
||||
#include <debug.h>
|
||||
#include <xusb.h>
|
||||
#include "astribank.h"
|
||||
|
||||
#define DBG_MASK 0x80
|
||||
/* if enabled, adds support for resetting pre-MPP USB firmware - if we
|
||||
@ -76,90 +76,11 @@ static int reset_kind(const char *arg)
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
static int show_hardware(struct astribank_device *astribank)
|
||||
{
|
||||
int ret;
|
||||
struct eeprom_table eeprom_table;
|
||||
struct capabilities capabilities;
|
||||
struct extrainfo extrainfo;
|
||||
|
||||
ret = mpp_caps_get(astribank, &eeprom_table, &capabilities, NULL);
|
||||
if(ret < 0)
|
||||
return ret;
|
||||
show_eeprom(&eeprom_table, stdout);
|
||||
show_astribank_status(astribank, stdout);
|
||||
if(astribank->eeprom_type == EEPROM_TYPE_LARGE) {
|
||||
show_capabilities(&capabilities, stdout);
|
||||
if(STATUS_FPGA_LOADED(astribank->status)) {
|
||||
uint8_t unit;
|
||||
uint8_t card_status;
|
||||
uint8_t card_type;
|
||||
uint8_t fpga_configuration;
|
||||
uint8_t status;
|
||||
|
||||
for(unit = 0; unit < 5; unit++) {
|
||||
ret = mpps_card_info(astribank, unit, &card_type, &card_status);
|
||||
if(ret < 0)
|
||||
return ret;
|
||||
printf("CARD %d: type=%x.%x %s\n", unit,
|
||||
((card_type >> 4) & 0xF), (card_type & 0xF),
|
||||
((card_status & 0x1) ? "PIC" : "NOPIC"));
|
||||
}
|
||||
ret = mpps_stat(astribank, unit, &fpga_configuration, &status);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
printf("FPGA: %-17s: %d\n", "Configuration num", fpga_configuration);
|
||||
printf("FPGA: %-17s: %s\n", "Watchdog Timer",
|
||||
(SER_STAT_WATCHDOG_READY(status)) ? "ready" : "expired");
|
||||
printf("FPGA: %-17s: %s\n", "XPD Alive",
|
||||
(SER_STAT_XPD_ALIVE(status)) ? "yes" : "no");
|
||||
}
|
||||
ret = mpp_extrainfo_get(astribank, &extrainfo);
|
||||
if(ret < 0)
|
||||
return ret;
|
||||
show_extrainfo(&extrainfo, stdout);
|
||||
if(CAP_EXTRA_TWINSTAR(&capabilities)) {
|
||||
twinstar_show(astribank, stdout);
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
#ifdef SUPPORT_OLD_RESET
|
||||
/* Try to reset a device using USB_FW.hex, up to Xorcom rev. 6885 */
|
||||
int old_reset(const char* devpath)
|
||||
{
|
||||
struct astribank_device *astribank;
|
||||
int ret;
|
||||
struct {
|
||||
uint8_t op;
|
||||
} PACKED header = {0x20}; /* PT_RESET */
|
||||
char *buf = (char*) &header;
|
||||
|
||||
/* Note that the function re-opens the connection to the Astribank
|
||||
* as any reference to the previous connection was lost when mpp_open
|
||||
* returned NULL as the astribank reference. */
|
||||
astribank = astribank_open(devpath, 1);
|
||||
if (!astribank) {
|
||||
DBG("Failed re-opening astribank device for old_reset\n");
|
||||
return -ENODEV;
|
||||
}
|
||||
ret = xusb_send(astribank->xusb, buf, 1, 5000);
|
||||
|
||||
/* If we just had a reenumeration, we may get -ENODEV */
|
||||
if(ret < 0 && ret != -ENODEV)
|
||||
return ret;
|
||||
/* We don't astribank_close(), as it has likely been
|
||||
* reenumerated by now. */
|
||||
return 0;
|
||||
}
|
||||
#endif /* SUPPORT_OLD_RESET */
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
char *devpath = NULL;
|
||||
struct astribank_device *astribank;
|
||||
struct astribank *astribank;
|
||||
struct mpp_device *mpp;
|
||||
const char options[] = "vd:D:nr:p:w:Q";
|
||||
int opt_renumerate = 0;
|
||||
char *opt_port = NULL;
|
||||
@ -218,20 +139,12 @@ int main(int argc, char *argv[])
|
||||
usage();
|
||||
}
|
||||
DBG("Startup %s\n", devpath);
|
||||
if((astribank = mpp_init(devpath, 1)) == NULL) {
|
||||
ERR("Failed initializing MPP\n");
|
||||
#ifdef SUPPORT_OLD_RESET
|
||||
DBG("opt_reset = %s\n", opt_reset);
|
||||
if (opt_reset) {
|
||||
DBG("Trying old reset method\n");
|
||||
if ((ret = old_reset(devpath)) != 0) {
|
||||
ERR("Old reset method failed as well: %d\n", ret);
|
||||
}
|
||||
}
|
||||
#endif /* SUPPORT_OLD_RESET */
|
||||
|
||||
astribank = astribank_new(devpath);
|
||||
if(!astribank) {
|
||||
ERR("Failed initializing Astribank\n");
|
||||
return 1;
|
||||
}
|
||||
mpp = astribank_mpp_open(astribank);
|
||||
/*
|
||||
* First process reset options. We want to be able
|
||||
* to reset minimal USB firmwares even if they don't
|
||||
@ -245,7 +158,7 @@ int main(int argc, char *argv[])
|
||||
return 1;
|
||||
}
|
||||
DBG("Reseting (%s)\n", opt_reset);
|
||||
if((ret = mpp_reset(astribank, full_reset)) < 0) {
|
||||
if((ret = mpp_reset(mpp, full_reset)) < 0) {
|
||||
ERR("%s Reseting astribank failed: %d\n",
|
||||
(full_reset) ? "Full" : "Half", ret);
|
||||
}
|
||||
@ -253,10 +166,10 @@ int main(int argc, char *argv[])
|
||||
}
|
||||
show_astribank_info(astribank);
|
||||
if(opt_query) {
|
||||
show_hardware(astribank);
|
||||
show_hardware(mpp);
|
||||
} else if(opt_renumerate) {
|
||||
DBG("Renumerate\n");
|
||||
if((ret = mpp_renumerate(astribank)) < 0) {
|
||||
if((ret = mpp_renumerate(mpp)) < 0) {
|
||||
ERR("Renumerating astribank failed: %d\n", ret);
|
||||
}
|
||||
} else if(opt_watchdog) {
|
||||
@ -264,24 +177,24 @@ int main(int argc, char *argv[])
|
||||
|
||||
DBG("TWINSTAR: Setting watchdog %s-guard\n",
|
||||
(watchdogstate) ? "on" : "off");
|
||||
if((ret = mpp_tws_setwatchdog(astribank, watchdogstate)) < 0) {
|
||||
if((ret = mpp_tws_setwatchdog(mpp, watchdogstate)) < 0) {
|
||||
ERR("Failed to set watchdog to %d\n", watchdogstate);
|
||||
return 1;
|
||||
}
|
||||
} else if(opt_port) {
|
||||
int new_portnum = strtoul(opt_port, NULL, 0);
|
||||
int tws_portnum = mpp_tws_portnum(astribank);
|
||||
int tws_portnum = mpp_tws_portnum(mpp);
|
||||
char *msg = (new_portnum == tws_portnum)
|
||||
? " Same same, never mind..."
|
||||
: "";
|
||||
|
||||
DBG("TWINSTAR: Setting portnum to %d.%s\n", new_portnum, msg);
|
||||
if((ret = mpp_tws_setportnum(astribank, new_portnum)) < 0) {
|
||||
if((ret = mpp_tws_setportnum(mpp, new_portnum)) < 0) {
|
||||
ERR("Failed to set USB portnum to %d\n", new_portnum);
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
out:
|
||||
mpp_exit(astribank);
|
||||
astribank_destroy(astribank);
|
||||
return 0;
|
||||
}
|
||||
|
@ -1,276 +0,0 @@
|
||||
/*
|
||||
* 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 <unistd.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <assert.h>
|
||||
#include <errno.h>
|
||||
#include <stdarg.h>
|
||||
#include <syslog.h>
|
||||
#include <arpa/inet.h>
|
||||
#include <xusb.h>
|
||||
#include "astribank_usb.h"
|
||||
#include <debug.h>
|
||||
|
||||
static const char rcsid[] = "$Id$";
|
||||
|
||||
#define DBG_MASK 0x01
|
||||
#define TIMEOUT 500
|
||||
|
||||
#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), \
|
||||
}
|
||||
|
||||
#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),
|
||||
TYPE_ENTRY("BURNED-MULTI", 0x1164, 2, 1, 2, MP_EP_OUT, MP_EP_IN),
|
||||
TYPE_ENTRY("USB-BURN", 0x1112, 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
|
||||
|
||||
//static int verbose = LOG_DEBUG;
|
||||
|
||||
/*
|
||||
* USB handling
|
||||
*/
|
||||
struct astribank_device *astribank_open(const char devpath[], int iface_num)
|
||||
{
|
||||
struct astribank_device *astribank = NULL;
|
||||
struct xusb *xusb;
|
||||
|
||||
DBG("devpath='%s' iface_num=%d\n", devpath, iface_num);
|
||||
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;
|
||||
if (xusb_claim_interface(astribank->xusb) < 0) {
|
||||
ERR("xusb_claim_interface failed\n");
|
||||
goto fail;
|
||||
}
|
||||
astribank->tx_sequenceno = 1;
|
||||
return astribank;
|
||||
fail:
|
||||
if (astribank) {
|
||||
free(astribank);
|
||||
astribank = NULL;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/*
|
||||
* MP device handling
|
||||
*/
|
||||
void show_astribank_info(const struct astribank_device *astribank)
|
||||
{
|
||||
struct xusb *xusb;
|
||||
|
||||
assert(astribank != NULL);
|
||||
xusb = astribank->xusb;
|
||||
assert(xusb != NULL);
|
||||
if(verbose <= LOG_INFO) {
|
||||
xusb_showinfo(xusb);
|
||||
} else {
|
||||
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->xusb) {
|
||||
xusb_close(astribank->xusb);
|
||||
astribank->xusb = NULL;
|
||||
}
|
||||
astribank->tx_sequenceno = 0;
|
||||
}
|
||||
|
||||
#if 0
|
||||
int flush_read(struct astribank_device *astribank)
|
||||
{
|
||||
char tmpbuf[BUFSIZ];
|
||||
int ret;
|
||||
|
||||
DBG("starting...\n");
|
||||
memset(tmpbuf, 0, BUFSIZ);
|
||||
ret = recv_usb(astribank, 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;
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
int release_isvalid(uint16_t release)
|
||||
{
|
||||
uint8_t rmajor = (release >> 8) & 0xFF;
|
||||
uint8_t rminor = release & 0xFF;
|
||||
|
||||
return (rmajor > 0) &&
|
||||
(rmajor < 10) &&
|
||||
(rminor > 0) &&
|
||||
(rminor < 10);
|
||||
}
|
||||
|
||||
int label_isvalid(const char *label)
|
||||
{
|
||||
int len;
|
||||
int goodlen;
|
||||
const char GOOD_CHARS[] =
|
||||
"abcdefghijklmnopqrstuvwxyz"
|
||||
"ABCDEFGHIJKLMNOPQRSTUVWXYZ"
|
||||
"0123456789"
|
||||
"-_.";
|
||||
|
||||
len = strlen(label);
|
||||
goodlen = strspn(label, GOOD_CHARS);
|
||||
if(len > LABEL_SIZE) {
|
||||
ERR("Label too long (%d > %d)\n", len, LABEL_SIZE);
|
||||
return 0;
|
||||
}
|
||||
if(goodlen != len) {
|
||||
ERR("Bad character in label (pos=%d)\n", goodlen);
|
||||
return 0;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
int eeprom_fill(struct eeprom_table *eprm,
|
||||
const char *vendor,
|
||||
const char *product,
|
||||
const char *release,
|
||||
const char *label)
|
||||
{
|
||||
uint16_t val;
|
||||
|
||||
eprm->source = 0xC0;
|
||||
eprm->config_byte = 0;
|
||||
if(vendor) {
|
||||
val = strtoul(vendor, NULL, 0);
|
||||
if(!val) {
|
||||
ERR("Invalid vendor '%s'\n",
|
||||
vendor);
|
||||
return -EINVAL;
|
||||
}
|
||||
eprm->vendor = val;
|
||||
}
|
||||
if(product) {
|
||||
val = strtoul(product, NULL, 0);
|
||||
if(!val) {
|
||||
ERR("Invalid product '%s'\n",
|
||||
product);
|
||||
return -EINVAL;
|
||||
}
|
||||
eprm->product = val;
|
||||
}
|
||||
if(release) {
|
||||
int release_major = 0;
|
||||
int release_minor = 0;
|
||||
uint16_t value;
|
||||
|
||||
if(sscanf(release, "%d.%d", &release_major, &release_minor) != 2) {
|
||||
ERR("Failed to parse release number '%s'\n", release);
|
||||
return -EINVAL;
|
||||
}
|
||||
value = (release_major << 8) | release_minor;
|
||||
DBG("Parsed release(%d): major=%d, minor=%d\n",
|
||||
value, release_major, release_minor);
|
||||
if(!release_isvalid(value)) {
|
||||
ERR("Invalid release number 0x%X\n", value);
|
||||
return -EINVAL;
|
||||
}
|
||||
eprm->release = value;
|
||||
}
|
||||
if(label) {
|
||||
/* padding */
|
||||
if(!label_isvalid(label)) {
|
||||
ERR("Invalid label '%s'\n", label);
|
||||
return -EINVAL;
|
||||
}
|
||||
memset(eprm->label, 0, LABEL_SIZE);
|
||||
memcpy(eprm->label, label, strlen(label));
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int astribank_has_twinstar(struct astribank_device *astribank)
|
||||
{
|
||||
uint16_t product_series;
|
||||
|
||||
assert(astribank != NULL);
|
||||
product_series = xusb_product_id(astribank->xusb);
|
||||
product_series &= 0xFFF0;
|
||||
if(product_series == 0x1160) /* New boards */
|
||||
return 1;
|
||||
return 0;
|
||||
}
|
||||
|
@ -1,113 +0,0 @@
|
||||
#ifndef ASTRIBANK_USB_H
|
||||
#define ASTRIBANK_USB_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 <xusb.h>
|
||||
#include <xtalk.h>
|
||||
#include "mpp.h"
|
||||
|
||||
/*
|
||||
* Astribank handling
|
||||
*/
|
||||
|
||||
#define PACKET_SIZE 512
|
||||
|
||||
/* USB Endpoints */
|
||||
#define MP_EP_OUT 0x04 /* Managment processor */
|
||||
#define MP_EP_IN 0x88 /* Managment processor */
|
||||
|
||||
#define XPP_EP_OUT 0x02 /* XPP */
|
||||
#define XPP_EP_IN 0x86 /* XPP */
|
||||
|
||||
/* USB firmware types */
|
||||
#define USB_11xx 0
|
||||
#define USB_FIRMWARE_II 1
|
||||
#define USB_PIC 2
|
||||
|
||||
struct interface_type {
|
||||
int type_code;
|
||||
int num_interfaces;
|
||||
int my_interface_num;
|
||||
int num_endpoints;
|
||||
int my_ep_out;
|
||||
int my_ep_in;
|
||||
char *name;
|
||||
int endpoints[4]; /* for matching */
|
||||
};
|
||||
|
||||
enum eeprom_burn_state {
|
||||
BURN_STATE_NONE = 0,
|
||||
BURN_STATE_STARTED = 1,
|
||||
BURN_STATE_ENDED = 2,
|
||||
BURN_STATE_FAILED = 3,
|
||||
};
|
||||
|
||||
struct astribank_device {
|
||||
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 iInterface[BUFSIZ];
|
||||
int is_usb2;
|
||||
enum eeprom_type eeprom_type;
|
||||
enum eeprom_burn_state burn_state;
|
||||
uint8_t status;
|
||||
uint8_t mpp_proto_version;
|
||||
struct eeprom_table *eeprom;
|
||||
struct firmware_versions fw_versions;
|
||||
uint16_t tx_sequenceno;
|
||||
};
|
||||
|
||||
/*
|
||||
* Prototypes
|
||||
*/
|
||||
struct astribank_device *astribank_open(const char devpath[], int iface_num);
|
||||
void astribank_close(struct astribank_device *astribank, int disconnected);
|
||||
void show_astribank_info(const struct astribank_device *astribank);
|
||||
int send_usb(struct astribank_device *astribank, char *buf, int len, int timeout);
|
||||
int recv_usb(struct astribank_device *astribank, char *buf, size_t len, int timeout);
|
||||
int flush_read(struct astribank_device *astribank);
|
||||
int eeprom_fill(struct eeprom_table *eprm,
|
||||
const char *vendor,
|
||||
const char *product,
|
||||
const char *release,
|
||||
const char *label);
|
||||
int astribank_has_twinstar(struct astribank_device *astribank);
|
||||
int label_isvalid(const char *label);
|
||||
|
||||
#define AB_REPORT(report_type, astribank, fmt, ...) \
|
||||
report_type("%s [%s]: " fmt, \
|
||||
xusb_devpath((astribank)->xusb), \
|
||||
xusb_serial((astribank)->xusb), \
|
||||
## __VA_ARGS__)
|
||||
|
||||
#define AB_INFO(astribank, fmt, ...) \
|
||||
AB_REPORT(INFO, astribank, fmt, ## __VA_ARGS__)
|
||||
|
||||
#define AB_ERR(astribank, fmt, ...) \
|
||||
AB_REPORT(ERR, astribank, fmt, ## __VA_ARGS__)
|
||||
|
||||
#endif /* ASTRIBANK_USB_H */
|
@ -28,12 +28,21 @@
|
||||
#include <limits.h>
|
||||
#include <regex.h>
|
||||
#include <sys/time.h>
|
||||
#include "echo_loader.h"
|
||||
#include "debug.h"
|
||||
#include <unistd.h>
|
||||
#include <oct6100api/oct6100_api.h>
|
||||
#include <xtalk/debug.h>
|
||||
#include <xtalk/xusb.h>
|
||||
#include <astribank.h>
|
||||
#include "echo_loader.h"
|
||||
#include "parse_span_specs.h"
|
||||
|
||||
#define DBG_MASK 0x03
|
||||
#ifdef __GNUC__
|
||||
#define PACKED __attribute__((packed))
|
||||
#else
|
||||
#define PACKED
|
||||
#endif
|
||||
|
||||
#define DBG_MASK 0x10
|
||||
#define TIMEOUT 1000
|
||||
#define ECHO_MAX_CHANS 128
|
||||
#define ECHO_RIN_STREAM 0
|
||||
@ -53,7 +62,7 @@ static float oct_fw_load_timeout = 2.0;
|
||||
struct echo_mod {
|
||||
tPOCT6100_INSTANCE_API pApiInstance;
|
||||
UINT32 ulEchoChanHndl[256];
|
||||
struct astribank_device *astribank;
|
||||
struct astribank *astribank;
|
||||
int maxchans;
|
||||
};
|
||||
|
||||
@ -100,9 +109,9 @@ static struct usb_buffer {
|
||||
} usb_buffer;
|
||||
|
||||
|
||||
static void usb_buffer_init(struct astribank_device *astribank, struct usb_buffer *ub)
|
||||
static void usb_buffer_init(struct astribank *astribank, struct usb_buffer *ub)
|
||||
{
|
||||
ub->max_len = xusb_packet_size(astribank->xusb);
|
||||
ub->max_len = xusb_packet_size(xusb_dev_of_astribank(astribank));
|
||||
ub->curr = 0;
|
||||
ub->min_send = INT_MAX;
|
||||
ub->max_send = 0;
|
||||
@ -120,7 +129,7 @@ static long usb_buffer_usec(struct usb_buffer *ub)
|
||||
(now.tv_usec - ub->start.tv_usec);
|
||||
}
|
||||
|
||||
static void usb_buffer_showstatistics(struct astribank_device *astribank, struct usb_buffer *ub)
|
||||
static void usb_buffer_showstatistics(struct astribank *astribank, struct usb_buffer *ub)
|
||||
{
|
||||
long usec;
|
||||
|
||||
@ -133,7 +142,7 @@ static void usb_buffer_showstatistics(struct astribank_device *astribank, struct
|
||||
usec / 1000, usec / ub->num_sends);
|
||||
}
|
||||
|
||||
static int usb_buffer_flush(struct astribank_device *astribank, struct usb_buffer *ub)
|
||||
static int usb_buffer_flush(struct astribank *astribank, struct usb_buffer *ub)
|
||||
{
|
||||
int ret;
|
||||
long t;
|
||||
@ -142,7 +151,7 @@ static int usb_buffer_flush(struct astribank_device *astribank, struct usb_buffe
|
||||
|
||||
if (ub->curr == 0)
|
||||
return 0;
|
||||
ret = xusb_send(astribank->xusb, ub->data, ub->curr, TIMEOUT);
|
||||
ret = astribank_send(astribank, 0, ub->data, ub->curr, TIMEOUT);
|
||||
if (ret < 0) {
|
||||
AB_ERR(astribank, "xusb_send failed: %d\n", ret);
|
||||
return ret;
|
||||
@ -175,7 +184,7 @@ static int usb_buffer_flush(struct astribank_device *astribank, struct usb_buffe
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int usb_buffer_append(struct astribank_device *astribank, struct usb_buffer *ub,
|
||||
static int usb_buffer_append(struct astribank *astribank, struct usb_buffer *ub,
|
||||
char *buf, int len)
|
||||
{
|
||||
if (ub->curr + len >= ub->max_len) {
|
||||
@ -188,7 +197,7 @@ static int usb_buffer_append(struct astribank_device *astribank, struct usb_buff
|
||||
return len;
|
||||
}
|
||||
|
||||
static int usb_buffer_send(struct astribank_device *astribank, struct usb_buffer *ub,
|
||||
static int usb_buffer_send(struct astribank *astribank, struct usb_buffer *ub,
|
||||
char *buf, int len, int timeout, int recv_answer)
|
||||
{
|
||||
int ret = 0;
|
||||
@ -209,7 +218,7 @@ static int usb_buffer_send(struct astribank_device *astribank, struct usb_buffer
|
||||
ret = usb_buffer_flush(astribank, ub);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
ret = xusb_recv(astribank->xusb, buf, PACKET_SIZE, TIMEOUT);
|
||||
ret = astribank_recv(astribank, 0, buf, PACKET_SIZE, TIMEOUT);
|
||||
if (ret <= 0) {
|
||||
AB_ERR(astribank, "No USB packs to read: %s\n", strerror(-ret));
|
||||
return -EINVAL;
|
||||
@ -239,7 +248,7 @@ static int usb_buffer_send(struct astribank_device *astribank, struct usb_buffer
|
||||
return ret;
|
||||
}
|
||||
|
||||
int spi_send(struct astribank_device *astribank, uint16_t addr, uint16_t data, int recv_answer, int ver)
|
||||
int spi_send(struct astribank *astribank, uint16_t addr, uint16_t data, int recv_answer, int ver)
|
||||
{
|
||||
int ret;
|
||||
char buf[PACKET_SIZE];
|
||||
@ -272,7 +281,7 @@ int spi_send(struct astribank_device *astribank, uint16_t addr, uint16_t data, i
|
||||
return ret;
|
||||
}
|
||||
|
||||
int test_send(struct astribank_device *astribank)
|
||||
int test_send(struct astribank *astribank)
|
||||
{
|
||||
int ret;
|
||||
char buf[PACKET_SIZE];
|
||||
@ -300,7 +309,7 @@ int test_send(struct astribank_device *astribank)
|
||||
return ret;
|
||||
}
|
||||
|
||||
int echo_send_data(struct astribank_device *astribank, const unsigned int addr, const unsigned int data)
|
||||
int echo_send_data(struct astribank *astribank, const unsigned int addr, const unsigned int data)
|
||||
{
|
||||
int ret;
|
||||
/* DBG("SEND: %04X -> [%04X]\n", data, addr);
|
||||
@ -330,7 +339,7 @@ failed:
|
||||
return ret;
|
||||
}
|
||||
|
||||
int echo_recv_data(struct astribank_device *astribank, const unsigned int addr)
|
||||
int echo_recv_data(struct astribank *astribank, const unsigned int addr)
|
||||
{
|
||||
unsigned int data = 0x00;
|
||||
int ret;
|
||||
@ -452,7 +461,7 @@ UINT32 Oct6100UserDriverWriteApi(tPOCT6100_WRITE_PARAMS f_pWriteParams)
|
||||
const unsigned int addr = f_pWriteParams->ulWriteAddress;
|
||||
const unsigned int data = f_pWriteParams->usWriteData;
|
||||
const struct echo_mod *echo_mod = (struct echo_mod *)(f_pWriteParams->pProcessContext);
|
||||
struct astribank_device *astribank = echo_mod->astribank;
|
||||
struct astribank *astribank = echo_mod->astribank;
|
||||
int ret;
|
||||
|
||||
ret = echo_send_data(astribank, addr, data);
|
||||
@ -469,7 +478,7 @@ UINT32 Oct6100UserDriverWriteSmearApi(tPOCT6100_WRITE_SMEAR_PARAMS f_pSmearParam
|
||||
unsigned int data;
|
||||
unsigned int len;
|
||||
const struct echo_mod *echo_mod;
|
||||
struct astribank_device *astribank;
|
||||
struct astribank *astribank;
|
||||
unsigned int i;
|
||||
|
||||
len = f_pSmearParams->ulWriteLength;
|
||||
@ -495,7 +504,7 @@ UINT32 Oct6100UserDriverWriteBurstApi(tPOCT6100_WRITE_BURST_PARAMS f_pBurstParam
|
||||
unsigned int data;
|
||||
unsigned int len = f_pBurstParams->ulWriteLength;
|
||||
const struct echo_mod *echo_mod = (struct echo_mod *)f_pBurstParams->pProcessContext;
|
||||
struct astribank_device *astribank = echo_mod->astribank;
|
||||
struct astribank *astribank = echo_mod->astribank;
|
||||
unsigned int i;
|
||||
|
||||
for (i = 0; i < len; i++) {
|
||||
@ -516,7 +525,7 @@ UINT32 Oct6100UserDriverReadApi(tPOCT6100_READ_PARAMS f_pReadParams)
|
||||
{
|
||||
const unsigned int addr = f_pReadParams->ulReadAddress;
|
||||
const struct echo_mod *echo_mod;
|
||||
struct astribank_device *astribank;
|
||||
struct astribank *astribank;
|
||||
int ret;
|
||||
|
||||
echo_mod = (struct echo_mod *)f_pReadParams->pProcessContext;
|
||||
@ -535,7 +544,7 @@ UINT32 Oct6100UserDriverReadBurstApi(tPOCT6100_READ_BURST_PARAMS f_pBurstParams)
|
||||
unsigned int addr;
|
||||
unsigned int len;
|
||||
const struct echo_mod *echo_mod;
|
||||
struct astribank_device *astribank;
|
||||
struct astribank *astribank;
|
||||
unsigned int i;
|
||||
|
||||
len = f_pBurstParams->ulReadLength;
|
||||
@ -555,13 +564,13 @@ UINT32 Oct6100UserDriverReadBurstApi(tPOCT6100_READ_BURST_PARAMS f_pBurstParams)
|
||||
return cOCT6100_ERR_OK;
|
||||
}
|
||||
|
||||
inline int get_ver(struct astribank_device *astribank)
|
||||
inline int get_ver(struct astribank *astribank)
|
||||
{
|
||||
return spi_send(astribank, 0, 0, 1, 1);
|
||||
}
|
||||
|
||||
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
||||
UINT32 init_octasic(char *filename, struct astribank_device *astribank, struct span_specs *span_specs)
|
||||
UINT32 init_octasic(char *filename, struct astribank *astribank, struct span_specs *span_specs)
|
||||
{
|
||||
int cpld_ver;
|
||||
struct echo_mod *echo_mod;
|
||||
@ -838,7 +847,7 @@ UINT32 init_octasic(char *filename, struct astribank_device *astribank, struct s
|
||||
}
|
||||
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
||||
|
||||
int load_echo(struct astribank_device *astribank, char *filename, int default_is_alaw, const char *span_spec)
|
||||
int load_echo(struct astribank *astribank, char *filename, int default_is_alaw, const char *span_spec)
|
||||
{
|
||||
int ret;
|
||||
UINT32 octasic_status;
|
||||
@ -868,7 +877,7 @@ int load_echo(struct astribank_device *astribank, char *filename, int default_is
|
||||
return 0;
|
||||
}
|
||||
|
||||
int echo_ver(struct astribank_device *astribank)
|
||||
int echo_ver(struct astribank *astribank)
|
||||
{
|
||||
usb_buffer_init(astribank, &usb_buffer);
|
||||
return get_ver(astribank);
|
||||
|
@ -23,10 +23,10 @@
|
||||
*/
|
||||
|
||||
#include <stdint.h>
|
||||
#include "astribank_usb.h"
|
||||
#include "astribank.h"
|
||||
|
||||
int spi_send(struct astribank_device *astribank, uint16_t addr, uint16_t data, int recv_answer, int ver);
|
||||
int load_echo(struct astribank_device *astribank, char *filename, int is_alaw, const char *span_spec);
|
||||
int echo_ver(struct astribank_device *astribank);
|
||||
int spi_send(struct astribank *astribank, uint16_t addr, uint16_t data, int recv_answer, int ver);
|
||||
int load_echo(struct astribank *astribank, char *filename, int is_alaw, const char *span_spec);
|
||||
int echo_ver(struct astribank *astribank);
|
||||
|
||||
#endif /* ECHO_LOADER_H */
|
||||
|
202
xpp/mpp.h
202
xpp/mpp.h
@ -1,202 +0,0 @@
|
||||
#ifndef MPP_H
|
||||
#define MPP_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.
|
||||
*
|
||||
*/
|
||||
|
||||
/*
|
||||
* MPP - Managment Processor Protocol definitions
|
||||
*/
|
||||
|
||||
#include <mpptalk_defs.h>
|
||||
#include <stdint.h>
|
||||
#include <xtalk.h>
|
||||
|
||||
#ifdef __GNUC__
|
||||
#define PACKED __attribute__((packed))
|
||||
#else
|
||||
#error "We do not know how your compiler packs structures"
|
||||
#endif
|
||||
|
||||
#define MK_PROTO_VERSION(major, minor) (((major) << 4) | (0x0F & (minor)))
|
||||
|
||||
#define MPP_PROTOCOL_VERSION MK_PROTO_VERSION(1,4)
|
||||
#define MPP_SUPPORTED_VERSION(x) ((x) == MK_PROTO_VERSION(1,3) || (x) == MK_PROTO_VERSION(1,4))
|
||||
|
||||
/*
|
||||
* The eeprom_table is common to all eeprom types.
|
||||
*/
|
||||
#define LABEL_SIZE 8
|
||||
struct eeprom_table {
|
||||
uint8_t source; /* C0 - small eeprom, C2 - large eeprom */
|
||||
uint16_t vendor;
|
||||
uint16_t product;
|
||||
uint16_t release; /* BCD encoded release */
|
||||
uint8_t config_byte; /* Must be 0 */
|
||||
uint8_t label[LABEL_SIZE];
|
||||
} PACKED;
|
||||
|
||||
#define VERSION_LEN 6
|
||||
struct firmware_versions {
|
||||
char usb[VERSION_LEN];
|
||||
char fpga[VERSION_LEN];
|
||||
char eeprom[VERSION_LEN];
|
||||
} PACKED;
|
||||
|
||||
struct capabilities {
|
||||
uint8_t ports_fxs;
|
||||
uint8_t ports_fxo;
|
||||
uint8_t ports_bri;
|
||||
uint8_t ports_pri;
|
||||
uint8_t extra_features; /* BIT(0) - TwinStar */
|
||||
uint8_t ports_echo;
|
||||
uint8_t reserved[2];
|
||||
uint32_t timestamp;
|
||||
} PACKED;
|
||||
|
||||
#define CAP_EXTRA_TWINSTAR(c) ((c)->extra_features & 0x01)
|
||||
#define CAP_EXTRA_TWINSTAR_SET(c) do {(c)->extra_features |= 0x01;} while (0)
|
||||
#define CAP_EXTRA_TWINSTAR_CLR(c) do {(c)->extra_features &= ~0x01;} while (0)
|
||||
|
||||
#define KEYSIZE 16
|
||||
|
||||
struct capkey {
|
||||
uint8_t k[KEYSIZE];
|
||||
} PACKED;
|
||||
|
||||
struct extrainfo {
|
||||
char text[EXTRAINFO_SIZE];
|
||||
} PACKED;
|
||||
|
||||
struct mpp_header {
|
||||
uint16_t len;
|
||||
uint16_t seq;
|
||||
uint8_t op; /* MSB: 0 - to device, 1 - from device */
|
||||
} PACKED;
|
||||
|
||||
enum mpp_ser_op {
|
||||
SER_CARD_INFO_GET = 0x1,
|
||||
SER_STAT_GET = 0x3,
|
||||
/* Status bits */
|
||||
#define SER_STAT_WATCHDOG_READY(s) ((s) & 0x01)
|
||||
#define SER_STAT_XPD_ALIVE(s) ((s) & 0x02)
|
||||
};
|
||||
|
||||
/* Individual commands structure */
|
||||
|
||||
CMD_DEF(MPP, STATUS_GET);
|
||||
|
||||
|
||||
CMD_DEF(MPP, STATUS_GET_REPLY,
|
||||
uint8_t i2cs_data;
|
||||
|
||||
#define STATUS_FPGA_LOADED(x) ((x) & 0x01)
|
||||
uint8_t status; /* BIT(0) - FPGA is loaded */
|
||||
struct firmware_versions fw_versions;
|
||||
);
|
||||
|
||||
CMD_DEF(MPP, EEPROM_SET,
|
||||
struct eeprom_table data;
|
||||
);
|
||||
|
||||
CMD_DEF(MPP, CAPS_GET);
|
||||
|
||||
CMD_DEF(MPP, CAPS_GET_REPLY,
|
||||
struct eeprom_table data;
|
||||
struct capabilities capabilities;
|
||||
struct capkey key;
|
||||
);
|
||||
|
||||
CMD_DEF(MPP, CAPS_SET,
|
||||
struct eeprom_table data;
|
||||
struct capabilities capabilities;
|
||||
struct capkey key;
|
||||
);
|
||||
|
||||
CMD_DEF(MPP, EXTRAINFO_GET);
|
||||
|
||||
CMD_DEF(MPP, EXTRAINFO_GET_REPLY,
|
||||
struct extrainfo info;
|
||||
);
|
||||
|
||||
CMD_DEF(MPP, EXTRAINFO_SET,
|
||||
struct extrainfo info;
|
||||
);
|
||||
|
||||
CMD_DEF(MPP, RENUM);
|
||||
|
||||
CMD_DEF(MPP, EEPROM_BLK_RD,
|
||||
uint16_t offset;
|
||||
uint16_t len;
|
||||
);
|
||||
|
||||
CMD_DEF(MPP, EEPROM_BLK_RD_REPLY,
|
||||
uint16_t offset;
|
||||
uint8_t data[0];
|
||||
);
|
||||
|
||||
CMD_DEF(MPP, DEV_SEND_START,
|
||||
uint8_t dest;
|
||||
char ihex_version[VERSION_LEN];
|
||||
);
|
||||
|
||||
CMD_DEF(MPP, DEV_SEND_END);
|
||||
|
||||
CMD_DEF(MPP, DEV_SEND_SEG,
|
||||
uint16_t offset;
|
||||
uint8_t data[0];
|
||||
);
|
||||
|
||||
CMD_DEF(MPP, RESET);
|
||||
CMD_DEF(MPP, HALF_RESET);
|
||||
|
||||
CMD_DEF(MPP, SER_SEND,
|
||||
uint8_t data[0];
|
||||
);
|
||||
|
||||
CMD_DEF(MPP, SER_RECV,
|
||||
uint8_t data[0];
|
||||
);
|
||||
|
||||
CMD_DEF(MPP, TWS_WD_MODE_SET,
|
||||
uint8_t wd_active;
|
||||
);
|
||||
|
||||
CMD_DEF(MPP, TWS_WD_MODE_GET);
|
||||
CMD_DEF(MPP, TWS_WD_MODE_GET_REPLY,
|
||||
uint8_t wd_active;
|
||||
);
|
||||
|
||||
CMD_DEF(MPP, TWS_PORT_SET,
|
||||
uint8_t portnum;
|
||||
);
|
||||
|
||||
CMD_DEF(MPP, TWS_PORT_GET);
|
||||
CMD_DEF(MPP, TWS_PORT_GET_REPLY,
|
||||
uint8_t portnum;
|
||||
);
|
||||
|
||||
CMD_DEF(MPP, TWS_PWR_GET);
|
||||
CMD_DEF(MPP, TWS_PWR_GET_REPLY,
|
||||
uint8_t power;
|
||||
);
|
||||
|
||||
#endif /* MPP_H */
|
771
xpp/mpptalk.c
771
xpp/mpptalk.c
File diff suppressed because it is too large
Load Diff
194
xpp/mpptalk.h
194
xpp/mpptalk.h
@ -1,5 +1,5 @@
|
||||
#ifndef MPP_FUNCS_H
|
||||
#define MPP_FUNCS_H
|
||||
#ifndef MPPTALK_H
|
||||
#define MPPTALK_H
|
||||
/*
|
||||
* Written by Oron Peled <oron@actcom.co.il>
|
||||
* Copyright (C) 2008, Xorcom
|
||||
@ -22,64 +22,152 @@
|
||||
*
|
||||
*/
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#include "mpp.h"
|
||||
#include "astribank_usb.h"
|
||||
|
||||
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[], 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);
|
||||
int mpp_eeprom_set(struct astribank_device *astribank, const struct eeprom_table *et);
|
||||
int mpp_renumerate(struct astribank_device *astribank);
|
||||
int mpp_caps_get(struct astribank_device *astribank,
|
||||
struct eeprom_table *et,
|
||||
struct capabilities *cap,
|
||||
struct capkey *key);
|
||||
int mpp_caps_set(struct astribank_device *astribank,
|
||||
const struct eeprom_table *eeprom_table,
|
||||
const struct capabilities *capabilities,
|
||||
const struct capkey *key);
|
||||
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, 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);
|
||||
int mpp_serial_cmd(struct astribank_device *astribank, const uint8_t *in, uint8_t *out, uint16_t len);
|
||||
void show_eeprom(const struct eeprom_table *eprm, FILE *fp);
|
||||
void show_capabilities(const struct capabilities *capabilities, FILE *fp);
|
||||
void show_astribank_status(struct astribank_device *astribank, FILE *fp);
|
||||
void show_extrainfo(const struct extrainfo *extrainfo, FILE *fp);
|
||||
int twinstar_show(struct astribank_device *astribank, FILE *fp);
|
||||
#ifdef __cplusplus
|
||||
extern "C"
|
||||
{
|
||||
#endif /* __cplusplus */
|
||||
|
||||
/*
|
||||
* Serial commands to FPGA
|
||||
* MPPTALK - Example XTALK dialect
|
||||
*/
|
||||
int mpps_card_info(struct astribank_device *astribank, int unit, uint8_t *card_type, uint8_t *card_status);
|
||||
int mpps_stat(struct astribank_device *astribank, int unit, uint8_t *maincard_version, uint8_t *status);
|
||||
|
||||
#include <xtalk/proto.h>
|
||||
#include <xtalk/proto_sync.h>
|
||||
|
||||
#ifdef __GNUC__
|
||||
#define PACKED __attribute__((packed))
|
||||
#else
|
||||
#define PACKED
|
||||
#endif
|
||||
|
||||
/*---------------- Common types --------------------*/
|
||||
|
||||
/*
|
||||
* The eeprom_table is common to all eeprom types.
|
||||
*/
|
||||
#define LABEL_SIZE 8
|
||||
struct eeprom_table {
|
||||
uint8_t source; /* C0 - small eeprom, C2 - large eeprom */
|
||||
uint16_t vendor;
|
||||
uint16_t product;
|
||||
uint16_t release; /* BCD encoded release */
|
||||
uint8_t config_byte; /* Must be 0 */
|
||||
uint8_t label[LABEL_SIZE];
|
||||
} PACKED;
|
||||
|
||||
#define VERSION_LEN 6
|
||||
struct firmware_versions {
|
||||
char usb[VERSION_LEN];
|
||||
char fpga[VERSION_LEN];
|
||||
char eeprom[VERSION_LEN];
|
||||
} PACKED;
|
||||
|
||||
struct capabilities {
|
||||
uint8_t ports_fxs;
|
||||
uint8_t ports_fxo;
|
||||
uint8_t ports_bri;
|
||||
uint8_t ports_pri;
|
||||
uint8_t extra_features; /* BIT(0) - TwinStar */
|
||||
uint8_t ports_echo;
|
||||
uint8_t reserved[2];
|
||||
uint32_t timestamp;
|
||||
} PACKED;
|
||||
|
||||
#define CAP_EXTRA_TWINSTAR(c) ((c)->extra_features & 0x01)
|
||||
#define CAP_EXTRA_TWINSTAR_SET(c) do {(c)->extra_features |= 0x01;} while (0)
|
||||
#define CAP_EXTRA_TWINSTAR_CLR(c) do {(c)->extra_features &= ~0x01;} while (0)
|
||||
|
||||
#define KEYSIZE 16
|
||||
struct capkey {
|
||||
uint8_t k[KEYSIZE];
|
||||
} PACKED;
|
||||
|
||||
#define EXTRAINFO_SIZE 24
|
||||
struct extrainfo {
|
||||
char text[EXTRAINFO_SIZE];
|
||||
} PACKED;
|
||||
|
||||
struct mpp_header {
|
||||
uint16_t len;
|
||||
uint16_t seq;
|
||||
uint8_t op; /* MSB: 0 - to device, 1 - from device */
|
||||
} PACKED;
|
||||
|
||||
enum mpp_ser_op {
|
||||
SER_CARD_INFO_GET = 0x1,
|
||||
SER_STAT_GET = 0x3,
|
||||
/* Status bits */
|
||||
#define SER_STAT_WATCHDOG_READY(s) ((s) & 0x01)
|
||||
#define SER_STAT_XPD_ALIVE(s) ((s) & 0x02)
|
||||
};
|
||||
|
||||
/* 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,
|
||||
};
|
||||
|
||||
|
||||
/*---------------- PROTOCOL ------------------------*/
|
||||
/* API */
|
||||
struct mpp_device;
|
||||
|
||||
struct mpp_device *mpp_new(struct xusb_iface *iface);
|
||||
void mpp_delete(struct mpp_device *dev);
|
||||
struct xusb_iface *xubs_iface_of_mpp(struct mpp_device *mpp);
|
||||
int mpp_status_query(struct mpp_device *mpp_dev);
|
||||
|
||||
enum eeprom_type mpp_eeprom_type(struct mpp_device *mpp_dev);
|
||||
|
||||
void show_eeprom(const struct eeprom_table *eprm, FILE *fp);
|
||||
void show_capabilities(const struct capabilities *capabilities, FILE *fp);
|
||||
void show_astribank_status(struct mpp_device *mpp_dev, FILE *fp);
|
||||
void show_extrainfo(const struct extrainfo *extrainfo, FILE *fp);
|
||||
int twinstar_show(struct mpp_device *mpp, FILE *fp);
|
||||
int show_hardware(struct mpp_device *mpp_dev);
|
||||
|
||||
int mpp_renumerate(struct mpp_device *mpp_dev);
|
||||
int mpp_send_start(struct mpp_device *mpp_dev, int dest, const char *ihex_version);
|
||||
int mpp_send_end(struct mpp_device *mpp_dev);
|
||||
int mpp_send_seg(struct mpp_device *mpp_dev, const uint8_t *data, uint16_t offset, uint16_t len);
|
||||
int mpp_reset(struct mpp_device *mpp_dev, int full_reset);
|
||||
|
||||
int mpp_caps_get(struct mpp_device *mpp_dev,
|
||||
struct eeprom_table *eeprom_table,
|
||||
struct capabilities *capabilities,
|
||||
struct capkey *key);
|
||||
int mpp_caps_set(struct mpp_device *mpp_dev,
|
||||
const struct eeprom_table *eeprom_table,
|
||||
const struct capabilities *capabilities,
|
||||
const struct capkey *key);
|
||||
|
||||
/*
|
||||
* serial sub-protocol to FPGA
|
||||
*/
|
||||
int mpps_card_info(struct mpp_device *mpp, int unit, uint8_t *card_type, uint8_t *card_status);
|
||||
int mpps_stat(struct mpp_device *mpp, int unit, uint8_t *maincard_version, uint8_t *status);
|
||||
|
||||
/*
|
||||
* Twinstar
|
||||
*/
|
||||
int mpp_tws_watchdog(struct astribank_device *astribank);
|
||||
int mpp_tws_setwatchdog(struct astribank_device *astribank, int yes);
|
||||
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);
|
||||
int mpp_tws_watchdog(struct mpp_device *mpp);
|
||||
int mpp_tws_setwatchdog(struct mpp_device *mpp, int yes);
|
||||
int mpp_tws_powerstate(struct mpp_device *mpp);
|
||||
int mpp_tws_portnum(struct mpp_device *mpp);
|
||||
int mpp_tws_setportnum(struct mpp_device *mpp, uint8_t portnum);
|
||||
|
||||
const char *dev_dest2str(int dest);
|
||||
|
||||
#endif /* MPP_FUNCS_H */
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif /* __cplusplus */
|
||||
|
||||
#endif /* MPPTALK_H */
|
||||
|
@ -1,113 +0,0 @@
|
||||
#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,
|
||||
};
|
||||
|
||||
#define EXTRAINFO_SIZE 24
|
||||
|
||||
#endif /* MPPTALK_DEFS_H */
|
@ -25,12 +25,12 @@
|
||||
#include <stdlib.h>
|
||||
#include <errno.h>
|
||||
#include <regex.h>
|
||||
#include <xtalk/debug.h>
|
||||
#include <xtalk/xusb.h>
|
||||
#include "hexfile.h"
|
||||
#include "pic_loader.h"
|
||||
#include <debug.h>
|
||||
#include <xusb.h>
|
||||
|
||||
#define DBG_MASK 0x03
|
||||
#define DBG_MASK 0x20
|
||||
#define MAX_HEX_LINES 10000
|
||||
#define TIMEOUT 500
|
||||
|
||||
@ -57,7 +57,7 @@ struct xpp_packet_header {
|
||||
} d;
|
||||
} PACKED;
|
||||
|
||||
int send_picline(struct astribank_device *astribank, uint8_t card_type, enum pic_command pcmd, int offs, uint8_t *data, int data_len)
|
||||
int send_picline(struct astribank *ab, uint8_t card_type, enum pic_command pcmd, int offs, uint8_t *data, int data_len)
|
||||
{
|
||||
int recv_answer = 0;
|
||||
char buf[PACKET_SIZE];
|
||||
@ -65,7 +65,7 @@ int send_picline(struct astribank_device *astribank, uint8_t card_type, enum pic
|
||||
int pack_len;
|
||||
int ret;
|
||||
|
||||
assert(astribank != NULL);
|
||||
assert(ab != NULL);
|
||||
pack_len = data_len + sizeof(phead->header) + sizeof(phead->d.pic_packet.pic_header);
|
||||
phead->header.len = pack_len;
|
||||
phead->header.op = PIC_REQ_XOP;
|
||||
@ -90,14 +90,14 @@ 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, DBG_MASK, "dump:picline[W]", (char *)phead, pack_len);
|
||||
|
||||
ret = xusb_send(astribank->xusb, buf, pack_len, TIMEOUT);
|
||||
ret = astribank_send(ab, 0, buf, pack_len, TIMEOUT);
|
||||
if(ret < 0) {
|
||||
ERR("xusb_send failed: %d\n", ret);
|
||||
ERR("astribank_send failed: %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
DBG("xusb_send: Written %d bytes\n", ret);
|
||||
DBG("astribank_send: Written %d bytes\n", ret);
|
||||
if (recv_answer) {
|
||||
ret = xusb_recv(astribank->xusb, buf, sizeof(buf), TIMEOUT);
|
||||
ret = astribank_recv(ab, 0, buf, sizeof(buf), TIMEOUT);
|
||||
if(ret <= 0) {
|
||||
ERR("No USB packs to read\n");
|
||||
return ret;
|
||||
@ -172,7 +172,7 @@ static const char *pic_basename(const char *fname, uint8_t *card_type)
|
||||
/*
|
||||
* Returns: true on success, false on failure
|
||||
*/
|
||||
static int pic_burn(struct astribank_device *astribank, const struct hexdata *hexdata)
|
||||
static int pic_burn(struct astribank *ab, const struct hexdata *hexdata)
|
||||
{
|
||||
const char *v = hexdata->version_info;
|
||||
const char *basename;
|
||||
@ -182,18 +182,21 @@ static int pic_burn(struct astribank_device *astribank, const struct hexdata *he
|
||||
int ret;
|
||||
unsigned int i;
|
||||
const char *devstr;
|
||||
const struct xusb_device *xusb;
|
||||
|
||||
v = (v[0]) ? v : "Unknown";
|
||||
assert(astribank != NULL);
|
||||
assert(ab != NULL);
|
||||
assert(hexdata != NULL);
|
||||
devstr = xusb_devpath(astribank->xusb);
|
||||
if(!astribank->is_usb2) {
|
||||
xusb = xusb_dev_of_astribank(ab);
|
||||
devstr = xusb_devpath(xusb);
|
||||
i = xusb_packet_size(xusb);
|
||||
if(i != 512) {
|
||||
ERR("%s: Skip PIC burning (not USB2)\n", devstr);
|
||||
return 0;
|
||||
}
|
||||
INFO("%s [%s]: Loading PIC Firmware: %s (version %s)\n",
|
||||
devstr,
|
||||
xusb_serial(astribank->xusb),
|
||||
xusb_serial(xusb),
|
||||
hexdata->fname,
|
||||
hexdata->version_info);
|
||||
basename = pic_basename(hexdata->fname, &card_type);
|
||||
@ -209,10 +212,10 @@ static int pic_burn(struct astribank_device *astribank, const struct hexdata *he
|
||||
for(i = 2; i; i--) {
|
||||
char buf[PACKET_SIZE];
|
||||
|
||||
if(xusb_recv(astribank->xusb, buf, sizeof(buf), 1) <= 0)
|
||||
if (astribank_recv(ab, 0, buf, sizeof(buf), TIMEOUT) <= 0)
|
||||
break;
|
||||
}
|
||||
if((ret = send_picline(astribank, card_type, PIC_START_FLAG, 0, NULL, 0)) != 0) {
|
||||
if((ret = send_picline(ab, card_type, PIC_START_FLAG, 0, NULL, 0)) != 0) {
|
||||
perror("Failed sending start hexline");
|
||||
return 0;
|
||||
}
|
||||
@ -233,7 +236,7 @@ static int pic_burn(struct astribank_device *astribank, const struct hexdata *he
|
||||
}
|
||||
data = hexline->d.content.tt_data.data;
|
||||
check_sum ^= data[0] ^ data[1] ^ data[2];
|
||||
ret = send_picline(astribank, card_type, PIC_DATA_FLAG,
|
||||
ret = send_picline(ab, card_type, PIC_DATA_FLAG,
|
||||
hexline->d.content.header.offset, data, len);
|
||||
if(ret) {
|
||||
perror("Failed sending data hexline");
|
||||
@ -247,7 +250,7 @@ static int pic_burn(struct astribank_device *astribank, const struct hexdata *he
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
if((ret = send_picline(astribank, card_type, PIC_END_FLAG, 0, &check_sum, 1)) != 0) {
|
||||
if((ret = send_picline(ab, card_type, PIC_END_FLAG, 0, &check_sum, 1)) != 0) {
|
||||
perror("Failed sending end hexline");
|
||||
return 0;
|
||||
}
|
||||
@ -255,12 +258,12 @@ static int pic_burn(struct astribank_device *astribank, const struct hexdata *he
|
||||
return 1;
|
||||
}
|
||||
|
||||
int load_pic(struct astribank_device *astribank, int numfiles, char *filelist[])
|
||||
int load_pic(struct astribank *ab, int numfiles, char *filelist[])
|
||||
{
|
||||
int i;
|
||||
const char *devstr;
|
||||
|
||||
devstr = xusb_devpath(astribank->xusb);
|
||||
devstr = xusb_devpath(xusb_dev_of_astribank(ab));
|
||||
DBG("%s: Loading %d PIC files...\n", devstr, numfiles);
|
||||
for(i = 0; i < numfiles; i++) {
|
||||
struct hexdata *picdata;
|
||||
@ -271,13 +274,13 @@ int load_pic(struct astribank_device *astribank, int numfiles, char *filelist[])
|
||||
perror(curr);
|
||||
return -errno;
|
||||
}
|
||||
if(!pic_burn(astribank, picdata)) {
|
||||
if(!pic_burn(ab, picdata)) {
|
||||
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) {
|
||||
if((i = send_picline(ab, 0, PIC_ENDS_FLAG, 0, NULL, 0)) != 0) {
|
||||
ERR("%s: PIC end burning failed\n", devstr);
|
||||
return -ENODEV;
|
||||
}
|
||||
|
@ -23,7 +23,7 @@
|
||||
*/
|
||||
|
||||
#include <stdint.h>
|
||||
#include "astribank_usb.h"
|
||||
#include "astribank.h"
|
||||
|
||||
/*
|
||||
* Astribank PIC loading
|
||||
@ -39,8 +39,8 @@ enum pic_command {
|
||||
#define PIC_PACK_LEN 0x0B
|
||||
#define PIC_LINE_LEN 0x03
|
||||
|
||||
int send_picline(struct astribank_device *astribank, uint8_t card_type,
|
||||
int send_picline(struct astribank *astribank, uint8_t card_type,
|
||||
enum pic_command pcmd, int offs, uint8_t *data, int data_len);
|
||||
int load_pic(struct astribank_device *astribank, int numfiles, char *filelist[]);
|
||||
int load_pic(struct astribank *astribank, int numfiles, char *filelist[]);
|
||||
|
||||
#endif /* PIC_LOADER_H */
|
||||
|
@ -19,12 +19,7 @@ noinst_PROGRAMS = xlist_test xusb_test xusb_test_bypath xtalk_test xtalk_raw_te
|
||||
sbin_PROGRAMS = xtalk_send
|
||||
noinst_LTLIBRARIES = libxtalk.la
|
||||
dist_noinst_HEADERS = \
|
||||
debug.h \
|
||||
xlist.h \
|
||||
xtalk.h \
|
||||
xtalk_base.h \
|
||||
xtalk_defs.h \
|
||||
xusb.h \
|
||||
xusb_common.h \
|
||||
include/xtalk/proto_raw.h \
|
||||
include/xtalk/api_defs.h \
|
||||
|
@ -1,497 +0,0 @@
|
||||
/*
|
||||
* 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>
|
||||
|
||||
#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;
|
||||
cmd = malloc(len);
|
||||
if (!cmd) {
|
||||
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;
|
||||
void *priv = xtalk_dev->transport_priv;
|
||||
|
||||
len = cmd->header.len;
|
||||
cmd->header.seq = xtalk_dev->tx_sequenceno;
|
||||
|
||||
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;
|
||||
size_t psize = xtalk_dev->packet_size;
|
||||
int ret;
|
||||
|
||||
reply = malloc(psize);
|
||||
if (!reply) {
|
||||
ERR("Out of memory\n");
|
||||
goto err;
|
||||
}
|
||||
reply->header.len = 0;
|
||||
ret = xtalk_dev->ops.recv_func(priv, (char *)reply, psize, 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, __func__, (char *)reply, ret); */
|
||||
return reply;
|
||||
err:
|
||||
if (reply) {
|
||||
memset(reply, 0, psize);
|
||||
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";
|
||||
/* So the caller knows if a reply was received */
|
||||
if (reply_ref)
|
||||
*reply_ref = NULL;
|
||||
reply_op = cmd->header.op | XTALK_REPLY_MASK;
|
||||
cmd_desc = get_command_desc(xproto, cmd->header.op);
|
||||
expected = get_command_desc(xproto, reply_op);
|
||||
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));
|
||||
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;
|
||||
cmd = new_command(xtalk_dev, XTALK_PROTO_GET, 0);
|
||||
if (!cmd) {
|
||||
ERR("new_command failed\n");
|
||||
return -ENOMEM;
|
||||
}
|
||||
/* Protocol Version */
|
||||
CMD_FIELD(cmd, XTALK, PROTO_GET, proto_version) = proto_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) {
|
||||
DBG("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);
|
||||
xtalk_dev = malloc(sizeof(*xtalk_dev));
|
||||
if (!xtalk_dev) {
|
||||
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);
|
||||
}
|
@ -1,178 +0,0 @@
|
||||
#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 XTALK_CMD_PTR(cmd, p) ((union XTALK_PDATA(p)*)&((cmd)->alt))
|
||||
#define CMD_FIELD(cmd, p, o, field) \
|
||||
(XTALK_CMD_PTR(cmd, p)->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 */
|
@ -351,3 +351,8 @@ void xtalk_base_delete(struct xtalk_base *xtalk_base)
|
||||
memset(xtalk_base, 0, sizeof(*xtalk_base));
|
||||
free(xtalk_base);
|
||||
}
|
||||
|
||||
struct xusb_iface *xusb_iface_of_xtalk_base(const struct xtalk_base *xtalk_base)
|
||||
{
|
||||
return xtalk_base->transport_priv;
|
||||
}
|
||||
|
@ -1,41 +0,0 @@
|
||||
#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)
|
||||
/* Get EEPROM table contents Product/Vendor Id ... */
|
||||
#define XTALK_CAPS_GET 0x0E
|
||||
#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 */
|
943
xpp/xtalk/xusb.c
943
xpp/xtalk/xusb.c
@ -1,943 +0,0 @@
|
||||
/*
|
||||
* 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>
|
||||
#include <sys/time.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/ipc.h>
|
||||
#include <sys/sem.h>
|
||||
|
||||
#define DBG_MASK 0x01
|
||||
#define TIMEOUT 500
|
||||
#define MAX_RETRIES 10
|
||||
|
||||
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;
|
||||
};
|
||||
|
||||
static void xusb_init();
|
||||
|
||||
/*
|
||||
* XTALK_OPTIONS:
|
||||
* A white-space separated list of options, read from the environment
|
||||
* variable of that name. Existing options:
|
||||
*
|
||||
* - "use-clear-halt" -- force USB "clear_halt" operation during
|
||||
* device initialization (this is the default)
|
||||
* - "no-use-clear-halt" -- force no USB "clear_halt" operation during
|
||||
* device initialization
|
||||
* - "no-lock" -- prevent using global sempahore to serialize libusb
|
||||
* initialization. Previously done via "XUSB_NOLOCK"
|
||||
* environment variable.
|
||||
*/
|
||||
int xtalk_parse_options(void);
|
||||
int xtalk_option_use_clear_halt(void);
|
||||
int xtalk_option_no_lock(void);
|
||||
|
||||
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%02X, IN=0x%02X)\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)
|
||||
{
|
||||
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, BUFSIZ, "%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;
|
||||
|
||||
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;
|
||||
}
|
||||
iface_desc = get_interface(dev, spec->my_interface_num,
|
||||
spec->num_interfaces);
|
||||
if (!iface_desc) {
|
||||
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;
|
||||
}
|
||||
|
||||
#define GET_USB_STRING(xusb, from, item) \
|
||||
get_usb_string((xusb), (from)->item, xusb->item)
|
||||
|
||||
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) < 0) {
|
||||
ERR("Failed reading iManufacturer string: %s\n",
|
||||
usb_strerror());
|
||||
return 0;
|
||||
}
|
||||
if (GET_USB_STRING(xusb, dev_desc, iProduct) < 0) {
|
||||
ERR("Failed reading iProduct string: %s\n",
|
||||
usb_strerror());
|
||||
return 0;
|
||||
}
|
||||
if (GET_USB_STRING(xusb, dev_desc, iSerialNumber) < 0) {
|
||||
ERR("Failed reading iSerialNumber string: %s\n",
|
||||
usb_strerror());
|
||||
return 0;
|
||||
}
|
||||
iface_desc = get_interface(xusb->dev, xusb->interface_num, 0);
|
||||
if (!iface_desc) {
|
||||
ERR("Could not get interface descriptor of device: %s\n",
|
||||
usb_strerror());
|
||||
return 0;
|
||||
}
|
||||
if (GET_USB_STRING(xusb, iface_desc, iInterface) < 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;
|
||||
xusb->handle = usb_open(xusb->dev);
|
||||
if (!xusb->handle) {
|
||||
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 (xtalk_option_use_clear_halt()) {
|
||||
DBG("Using clear_halt()\n");
|
||||
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;
|
||||
}
|
||||
}
|
||||
ret = xusb_flushread(xusb);
|
||||
if (ret < 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
|
||||
*/
|
||||
dev_desc = &dev->descriptor;
|
||||
if (!dev_desc) {
|
||||
ERR("usb device without a device descriptor\n");
|
||||
goto fail;
|
||||
}
|
||||
config_desc = dev->config;
|
||||
if (!config_desc) {
|
||||
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("EP #%d wMaxPacketSize too large (%d)\n",
|
||||
i, endpoint->wMaxPacketSize);
|
||||
goto fail;
|
||||
}
|
||||
if (endpoint->wMaxPacketSize < max_packet_size)
|
||||
max_packet_size = endpoint->wMaxPacketSize;
|
||||
}
|
||||
}
|
||||
/* Fill xusb */
|
||||
xusb = malloc(sizeof(*xusb));
|
||||
if (!xusb) {
|
||||
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 xusb_spec *dummy_spec)
|
||||
{
|
||||
struct usb_bus *bus;
|
||||
|
||||
DBG("\n");
|
||||
xusb_init();
|
||||
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 *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);
|
||||
DBG("Matched device %s: %X:%X\n", tmppath,
|
||||
dev_desc->idVendor, dev_desc->idProduct);
|
||||
assert(dummy_spec);
|
||||
xusb_init_spec(dummy_spec, "<none>",
|
||||
dev_desc->idVendor, dev_desc->idProduct,
|
||||
config_desc->bNumInterfaces,
|
||||
iface_num,
|
||||
interface->altsetting->bNumEndpoints,
|
||||
ep_out, ep_in);
|
||||
xusb = xusb_new(dev, dummy_spec);
|
||||
if (!xusb)
|
||||
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 '/' */
|
||||
p = memrchr(path, '/', strlen(path));
|
||||
if (!p) {
|
||||
ERR("Missing a '/' in %s\n", path);
|
||||
return NULL;
|
||||
}
|
||||
/* Search for a '/' before that */
|
||||
p = memrchr(path, '/', p - path);
|
||||
if (!p)
|
||||
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);
|
||||
xlist = xlist_new(NULL);
|
||||
if (!xlist) {
|
||||
ERR("Failed allocation new xlist");
|
||||
goto fail_xlist;
|
||||
}
|
||||
xusb_init();
|
||||
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;
|
||||
xusb = xusb_new(dev, sp);
|
||||
if (!xusb) {
|
||||
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);
|
||||
if (!xusb_claim_interface(xusb)) {
|
||||
xusb_destroy(xusb);
|
||||
return NULL;
|
||||
}
|
||||
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;
|
||||
int retries = 0;
|
||||
|
||||
dump_packet(LOG_DEBUG, DBG_MASK, __func__, buf, len);
|
||||
if (EP_OUT(xusb) & USB_ENDPOINT_IN) {
|
||||
ERR("%s called with an input endpoint 0x%x\n",
|
||||
__func__, EP_OUT(xusb));
|
||||
return -EINVAL;
|
||||
}
|
||||
retry_write:
|
||||
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, "xusb_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;
|
||||
}
|
||||
if (!ret) {
|
||||
ERR("bulk_write to endpoint 0x%x short write[%d]: (%d)\n",
|
||||
EP_OUT(xusb), retries, ret);
|
||||
if (retries++ > MAX_RETRIES)
|
||||
return -EFAULT;
|
||||
usleep(100);
|
||||
goto retry_write;
|
||||
}
|
||||
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, "xusb_send[ERR]", buf, len);
|
||||
return -EFAULT;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
int xusb_recv(struct xusb *xusb, char *buf, size_t len, int timeout)
|
||||
{
|
||||
int ret;
|
||||
int retries = 0;
|
||||
|
||||
if (EP_IN(xusb) & USB_ENDPOINT_OUT) {
|
||||
ERR("%s called with an output endpoint 0x%x\n",
|
||||
__func__, EP_IN(xusb));
|
||||
return -EINVAL;
|
||||
}
|
||||
retry_read:
|
||||
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;
|
||||
}
|
||||
if (!ret) {
|
||||
ERR("bulk_read to endpoint 0x%x short read[%d]: (%d)\n",
|
||||
EP_IN(xusb), retries, ret);
|
||||
if (retries++ > MAX_RETRIES)
|
||||
return -EFAULT;
|
||||
usleep(100);
|
||||
goto retry_read;
|
||||
}
|
||||
dump_packet(LOG_DEBUG, DBG_MASK, __func__, 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, __func__, tmpbuf, ret);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Serialize calls to usb_find_busses()/usb_find_devices()
|
||||
*/
|
||||
|
||||
static const key_t SEM_KEY = 0x1a2b3c4d;
|
||||
static int semid = -1; /* Failure */
|
||||
|
||||
static void xusb_lock_usb()
|
||||
{
|
||||
struct sembuf sembuf;
|
||||
|
||||
while (semid < 0) {
|
||||
/* Maybe it was already created? */
|
||||
semid = semget(SEM_KEY, 1, 0);
|
||||
if (semid < 0) {
|
||||
/* No, let's create ourselves */
|
||||
semid = semget(SEM_KEY, 1, IPC_CREAT | IPC_EXCL | 0644);
|
||||
if (semid < 0) {
|
||||
/* Someone else won the race to create it */
|
||||
if (errno != ENOENT)
|
||||
ERR("%s: semget() failed: %s\n",
|
||||
__func__, strerror(errno));
|
||||
/* Retry */
|
||||
continue;
|
||||
}
|
||||
/* Initialize */
|
||||
if (semctl(semid, 0, SETVAL, 1) < 0)
|
||||
ERR("%s: SETVAL() failed: %s\n",
|
||||
__func__, strerror(errno));
|
||||
}
|
||||
}
|
||||
DBG("%d: LOCKING\n", getpid());
|
||||
sembuf.sem_num = 0;
|
||||
sembuf.sem_op = -1;
|
||||
sembuf.sem_flg = SEM_UNDO;
|
||||
if (semop(semid, &sembuf, 1) < 0)
|
||||
ERR("%s: semop() failed: %s\n", __func__, strerror(errno));
|
||||
DBG("%d: LOCKED\n", getpid());
|
||||
}
|
||||
|
||||
static void xusb_unlock_usb()
|
||||
{
|
||||
struct sembuf sembuf;
|
||||
|
||||
DBG("%d: UNLOCKING\n", getpid());
|
||||
sembuf.sem_num = 0;
|
||||
sembuf.sem_op = 1;
|
||||
sembuf.sem_flg = SEM_UNDO;
|
||||
if (semop(semid, &sembuf, 1) < 0)
|
||||
ERR("%s: semop() failed: %s\n", __func__, strerror(errno));
|
||||
DBG("%d: UNLOCKED\n", getpid());
|
||||
}
|
||||
|
||||
static int initizalized;
|
||||
|
||||
static void xusb_init()
|
||||
{
|
||||
if (!initizalized) {
|
||||
xtalk_parse_options();
|
||||
if (!xtalk_option_no_lock())
|
||||
xusb_lock_usb();
|
||||
usb_init();
|
||||
usb_find_busses();
|
||||
usb_find_devices();
|
||||
initizalized = 1;
|
||||
if (!xtalk_option_no_lock())
|
||||
xusb_unlock_usb();
|
||||
}
|
||||
}
|
||||
|
||||
/* XTALK option handling */
|
||||
static int use_clear_halt = 1;
|
||||
static int libusb_no_lock = 0;
|
||||
|
||||
static int xtalk_one_option(const char *option_string)
|
||||
{
|
||||
if (strcmp(option_string, "use-clear-halt") == 0) {
|
||||
use_clear_halt = 1;
|
||||
return 0;
|
||||
}
|
||||
if (strcmp(option_string, "no-use-clear-halt") == 0) {
|
||||
use_clear_halt = 0;
|
||||
return 0;
|
||||
}
|
||||
if (strcmp(option_string, "no-lock") == 0) {
|
||||
libusb_no_lock = 1;
|
||||
return 0;
|
||||
}
|
||||
ERR("Unknown XTALK_OPTIONS content: '%s'\n", option_string);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
int xtalk_option_use_clear_halt(void)
|
||||
{
|
||||
return use_clear_halt;
|
||||
}
|
||||
|
||||
int xtalk_option_no_lock(void)
|
||||
{
|
||||
return libusb_no_lock;
|
||||
}
|
||||
|
||||
int xtalk_parse_options(void)
|
||||
{
|
||||
char *xtalk_options;
|
||||
char *saveptr;
|
||||
char *token;
|
||||
int ret;
|
||||
|
||||
xtalk_options = getenv("XTALK_OPTIONS");
|
||||
if (!xtalk_options)
|
||||
return 0;
|
||||
token = strtok_r(xtalk_options, " \t", &saveptr);
|
||||
while (token) {
|
||||
ret = xtalk_one_option(token);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
token = strtok_r(NULL, " \t", &saveptr);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
102
xpp/xtalk/xusb.h
102
xpp/xtalk/xusb.h
@ -1,102 +0,0 @@
|
||||
#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, struct xusb_spec *dummy);
|
||||
|
||||
/*
|
||||
* 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 */
|
@ -566,7 +566,7 @@ struct xusb_device *xusb_find_bypath(const char *path)
|
||||
ERR("usb device without a device descriptor\n");
|
||||
continue;
|
||||
}
|
||||
INFO("Found: %04x:%04x %s\n",
|
||||
DBG("Found: %04x:%04x %s\n",
|
||||
dev_desc.idVendor, dev_desc.idProduct, devpath_tail);
|
||||
xusb_init_spec(spec, "<BYPATH>",
|
||||
dev_desc.idVendor, dev_desc.idProduct);
|
||||
|
Loading…
Reference in New Issue
Block a user