Compare commits
36 Commits
v2.11.0-rc
...
next
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
31cca182bf | ||
|
|
75eedd6fa6 | ||
|
|
b54ec6efd3 | ||
|
|
754d981621 | ||
|
|
dc95a1164f | ||
|
|
9631938e90 | ||
|
|
55679791b5 | ||
|
|
ba09742a3f | ||
|
|
e4197cc499 | ||
|
|
abd139ae91 | ||
|
|
6b2c6d72d8 | ||
|
|
f64500c986 | ||
|
|
424157834d | ||
|
|
95d03118cb | ||
|
|
99e3c572d1 | ||
|
|
6057ef25e9 | ||
|
|
e1da7b5284 | ||
|
|
f105a09eda | ||
|
|
212b247e68 | ||
|
|
f225a5692c | ||
|
|
cffc5158cc | ||
|
|
42850dba35 | ||
|
|
06ae8473d7 | ||
|
|
dbb5ba6db6 | ||
|
|
2097f1adc5 | ||
|
|
d02361e99f | ||
|
|
77a3d8b0a7 | ||
|
|
bd49fc9d95 | ||
|
|
0e6b068e89 | ||
|
|
9c61e40187 | ||
|
|
5ee15a2337 | ||
|
|
01faf597d6 | ||
|
|
48b25e849f | ||
|
|
d239b8dc4d | ||
|
|
4676ad6671 | ||
|
|
b471526700 |
9
.gitignore
vendored
9
.gitignore
vendored
@@ -11,6 +11,8 @@
|
||||
.deps
|
||||
.libs
|
||||
.dirstamp
|
||||
.version
|
||||
/.pc
|
||||
Makefile
|
||||
Makefile.in
|
||||
auxdir/
|
||||
@@ -28,6 +30,7 @@ dahdi_cfg
|
||||
dahdi_diag
|
||||
dahdi_maint
|
||||
dahdi_monitor
|
||||
dahdi_pcap
|
||||
dahdi_scan
|
||||
dahdi_speed
|
||||
dahdi_test
|
||||
@@ -67,4 +70,10 @@ xpp/test_parse
|
||||
xpp/twinstar.8
|
||||
xpp/xpp_blink.8
|
||||
xpp/xpp_sync.8
|
||||
xpp/xtalk/xlist_test
|
||||
xpp/xtalk/xtalk_raw_test
|
||||
xpp/xtalk/xtalk_send
|
||||
xpp/xtalk/xtalk_test
|
||||
xpp/xtalk/xusb_test
|
||||
xpp/xtalk/xusb_test_bypath
|
||||
zonedata.lo
|
||||
|
||||
@@ -5,7 +5,7 @@ LEGACY_MAKE = \
|
||||
top_srcdir=$(top_srcdir) \
|
||||
srcdir=$(srcdir)
|
||||
|
||||
CFLAGS = -g -Wall -O2 $(DAHDI_INCLUDE)
|
||||
CFLAGS += -g -Wall -O2 $(DAHDI_INCLUDE)
|
||||
if DAHDI_DEVMODE
|
||||
CFLAGS += \
|
||||
-Werror \
|
||||
@@ -74,14 +74,15 @@ libtonezone_la_SOURCES = \
|
||||
dahdiinclude_HEADERS = tonezone.h
|
||||
libtonezone_la_CFLAGS = $(CFLAGS) -I$(srcdir) -DBUILDING_TONEZONE
|
||||
libtonezone_la_LDFLAGS = -version-info "$(LTZ_CURRENT):$(LTZ_REVISION):$(LTZ_AGE)"
|
||||
libtonezone_la_LIBADD = -lm
|
||||
|
||||
if PBX_PCAP
|
||||
noinst_PROGRAMS += dahdi_pcap
|
||||
dahdi_pcap_LDADD = -lpcap
|
||||
endif
|
||||
|
||||
patlooptest_LDADD = libtonezone.la -lm
|
||||
fxstest_LDADD = libtonezone.la -lm
|
||||
patlooptest_LDADD = libtonezone.la
|
||||
fxstest_LDADD = libtonezone.la
|
||||
fxotune_LDADD = -lm
|
||||
dahdi_speed_CFLAGS = -O2
|
||||
|
||||
@@ -93,7 +94,7 @@ dahdi_tool_CFLAGS = $(CFLAGS) $(NEWT_INCLUDE)
|
||||
dahdi_tool_LDADD = $(NEWT_LIB)
|
||||
endif
|
||||
|
||||
dahdi_cfg_LDFLAGS = -lm -lpthread
|
||||
dahdi_cfg_LDFLAGS = -lpthread
|
||||
dahdi_cfg_LDADD = libtonezone.la
|
||||
|
||||
udevrulesdir = @udevrulesdir@
|
||||
|
||||
@@ -69,10 +69,10 @@ genconf_parameters.sample: xpp/genconf_parameters
|
||||
README.html: README system.conf.asciidoc init.conf.asciidoc tonezones.txt \
|
||||
UPGRADE.txt genconf_parameters.asciidoc assigned-spans.conf.asciidoc \
|
||||
span-types.conf.asciidoc
|
||||
$(ASCIIDOC) -n -a toc -a toclevels=4 $<
|
||||
TZ=UTC $(ASCIIDOC) -n -a toc -a toclevels=4 $<
|
||||
|
||||
README.Astribank.html: xpp/README.Astribank
|
||||
$(ASCIIDOC) -o $@ -n -a toc -a toclevels=4 $<
|
||||
TZ=UTC $(ASCIIDOC) -o $@ -n -a toc -a toclevels=4 $<
|
||||
|
||||
# on Debian: this requires the full groff, not just groff-base.
|
||||
%.8.html: %.8
|
||||
@@ -86,7 +86,7 @@ install: all install-programs
|
||||
@echo "### DAHDI tools installed successfully."
|
||||
@echo "### If you have not done so before, install init scripts with:"
|
||||
@echo "###"
|
||||
@echo "### make config"
|
||||
@echo "### make install-config"
|
||||
@echo "###"
|
||||
@echo "###################################################"
|
||||
|
||||
|
||||
@@ -68,6 +68,8 @@ elif [ -d ${1}/.git ]; then
|
||||
# options.
|
||||
VERSION=GIT-`git rev-parse --short --verify HEAD`${MODIFIED}
|
||||
fi
|
||||
VERSION=${VERSION##*/} # Remove leading slashes: upsteram/2.10.2
|
||||
VERSION=${VERSION#[1-9]%} # Remove 1% from tag (tag from Debian epoch)
|
||||
echo ${VERSION}
|
||||
else
|
||||
PARTS=`LANG=C git log --pretty=full | grep -F "git-svn-id:" | head -1 | awk '{print $2;}' | sed -e s:^.*/svn/$2/:: | sed -e 's:/: :g' | sed -e 's/@.*$//g'`
|
||||
|
||||
82
configure.ac
82
configure.ac
@@ -68,8 +68,6 @@ AC_CONFIG_HEADER(autoconfig.h)
|
||||
# This needs to be before any macros that use the C compiler
|
||||
AC_GNU_SOURCE
|
||||
|
||||
AC_CHECK_HEADERS([sys/soundcard.h linux/soundcard.h])
|
||||
|
||||
AC_CHECK_TOOL([LD], [ld])
|
||||
|
||||
# Checks for programs.
|
||||
@@ -160,6 +158,22 @@ else
|
||||
fi
|
||||
AC_SUBST(DAHDI_DECLARATION_AFTER_STATEMENT)
|
||||
|
||||
# Checks for header files.
|
||||
AC_CHECK_HEADERS([sys/soundcard.h linux/soundcard.h])
|
||||
AC_CHECK_HEADERS([arpa/inet.h fcntl.h limits.h netinet/in.h stdint.h stdlib.h string.h sys/ioctl.h sys/param.h sys/socket.h sys/time.h syslog.h unistd.h])
|
||||
|
||||
# Checks for typedefs, structures, and compiler characteristics.
|
||||
AC_C_INLINE
|
||||
AC_TYPE_SIZE_T
|
||||
AC_TYPE_SSIZE_T
|
||||
AC_TYPE_UINT16_T
|
||||
AC_TYPE_UINT32_T
|
||||
AC_TYPE_UINT8_T
|
||||
|
||||
# Checks for libraries.
|
||||
AC_CHECK_LIB([m], [cos])
|
||||
AC_CHECK_LIB([pthread], [pthread_create])
|
||||
|
||||
AST_EXT_LIB_SETUP([DAHDI], [DAHDI], [dahdi])
|
||||
AST_EXT_LIB_SETUP([NEWT], [newt], [newt])
|
||||
AST_EXT_LIB_SETUP([USB], [usb], [usb])
|
||||
@@ -181,6 +195,67 @@ AM_CONDITIONAL([PBX_NEWT], [test "$PBX_NEWT" = "1"])
|
||||
AM_CONDITIONAL([PBX_PCAP], [test "$PBX_PCAP" = "1" -a "$DAHDI_TXMIRROR" = "1"])
|
||||
|
||||
AC_CHECK_FUNCS([semtimedop])
|
||||
AC_CHECK_FUNCS([alarm bzero gettimeofday memset pow regcomp select socket strcasecmp strchr strdup strerror strrchr strstr strtol strtoul])
|
||||
AC_FUNC_ERROR_AT_LINE
|
||||
AC_FUNC_MALLOC
|
||||
|
||||
# What the user asked for? libusb/libusbx
|
||||
AC_ARG_WITH([libusbx],
|
||||
[AS_HELP_STRING([--without-libusbx], [Disable libusbx @<:@default=check@:>@])],
|
||||
[],
|
||||
[with_libusbx=check])
|
||||
AC_ARG_WITH([libusb],
|
||||
[AS_HELP_STRING([--without-libusb], [Disable libusb-0.1 @<:@default=check@:>@])],
|
||||
[],
|
||||
[with_libusb=check])
|
||||
|
||||
# LIBUSBX tests
|
||||
have_libusbx=
|
||||
AS_IF([test "$with_libusbx" != "no"],
|
||||
[PKG_CHECK_MODULES([LIBUSBX], [libusb-1.0],
|
||||
[AC_CHECK_LIB([usb-1.0], [libusb_error_name],
|
||||
[
|
||||
have_libusbx="yes"
|
||||
AC_DEFINE([HAVE_LIBUSBX], [1], [Define to 1 if you have <libusb.h>.])
|
||||
AC_SUBST([PBX_USB], [1])
|
||||
], [
|
||||
if test "$with_libusbx" != "yes"; then
|
||||
AC_MSG_NOTICE([Ignoring old libusb-1.0, trying fallback to old libusb])
|
||||
fi
|
||||
])
|
||||
], [:])
|
||||
], [])
|
||||
|
||||
AS_IF([test "$with_libusbx" = "yes" -a "$have_libusbx" = ""],
|
||||
[AC_MSG_ERROR([No libusbx found (--with-libusbx was given)])])
|
||||
|
||||
# LIBUSB tests
|
||||
have_libusb=
|
||||
AS_IF([test "$with_libusb" != "no"],
|
||||
[AS_IF([test "$have_libusbx" != ""],
|
||||
[
|
||||
AS_IF([test "$with_libusbx" = "check"], [
|
||||
AC_MSG_NOTICE([Skipping LIBUSB tests (have good LIBUSBX)])
|
||||
])
|
||||
], [
|
||||
PKG_CHECK_MODULES([LIBUSB], [libusb],
|
||||
[
|
||||
have_libusb="yes"
|
||||
AC_SUBST([PBX_USB], [1])
|
||||
]
|
||||
[AC_DEFINE([HAVE_LIBUSB], [1], [Define to 1 if you have <usb.h>.])],
|
||||
[:]
|
||||
)
|
||||
])
|
||||
], [])
|
||||
|
||||
AS_IF([test "$with_libusb" = "yes" -a "$have_libusb" = ""],
|
||||
[AC_MSG_ERROR([No libusb found (--with-libusb was given)])])
|
||||
|
||||
AM_CONDITIONAL([LIBUSBX], [test "$have_libusbx" != ""])
|
||||
AM_CONDITIONAL([LIBUSB], [test "$have_libusb" != ""])
|
||||
AM_CONDITIONAL([PBX_USB], [test "$PBX_USB" = "1"])
|
||||
|
||||
|
||||
PBX_HDLC=0
|
||||
AC_MSG_CHECKING([for GENERIC_HDLC_VERSION version 4 in linux/hdlc.h])
|
||||
@@ -296,8 +371,6 @@ fi
|
||||
|
||||
AC_SUBST(PPPD_VERSION)
|
||||
|
||||
AM_CONDITIONAL([PBX_USB], [test "$PBX_USB" = "1"])
|
||||
|
||||
# Taken from octasic-helper
|
||||
AC_SUBST([USE_OCTASIC], [yes])
|
||||
AM_CONDITIONAL([USE_OCTASIC], [test "$USE_OCTASIC" = 'yes'])
|
||||
@@ -314,6 +387,7 @@ AC_CONFIG_FILES([
|
||||
hotplug/Makefile
|
||||
ppp/Makefile
|
||||
xpp/Makefile
|
||||
xpp/xtalk/Makefile
|
||||
xpp/oct612x/Makefile
|
||||
xpp/perl_modules/Makefile
|
||||
])
|
||||
|
||||
@@ -48,7 +48,7 @@ __dahdi_span_types() {
|
||||
has_cmd=0
|
||||
for (( i=0; i < COMP_CWORD; i++)); do
|
||||
case "${COMP_WORDS[$i]}" in
|
||||
dumpconfig | list | set)
|
||||
dumpconfig | list | set | compare)
|
||||
has_cmd=1
|
||||
break
|
||||
;;
|
||||
@@ -69,7 +69,7 @@ __dahdi_span_types() {
|
||||
grep -l '[EJT]1' /sys/devices/pci0000:00/0000:00:10.4/usb1/1-1/xbus-00/*/spantype 2>/dev/null | sed -e 's|/spantype||') )
|
||||
else
|
||||
COMPREPLY=( ${COMPREPLY[@]} $(compgen -W \
|
||||
'dumpconfig list set' -- $cur) )
|
||||
'dumpconfig list set compare' -- $cur) )
|
||||
fi
|
||||
;;
|
||||
esac
|
||||
|
||||
38
dahdi_cfg.c
38
dahdi_cfg.c
@@ -90,11 +90,9 @@ static struct dahdi_lineconfig lc[DAHDI_MAX_SPANS];
|
||||
|
||||
static struct dahdi_chanconfig cc[DAHDI_MAX_CHANNELS];
|
||||
|
||||
static int current_span = 0;
|
||||
static int only_span = 0;
|
||||
static int restrict_channels = 0;
|
||||
static int selected_channels[DAHDI_MAX_CHANNELS];
|
||||
static int chan2span[DAHDI_MAX_CHANNELS];
|
||||
static int declared_spans[DAHDI_MAX_SPANS];
|
||||
|
||||
static struct dahdi_attach_echocan ae[DAHDI_MAX_CHANNELS];
|
||||
@@ -333,20 +331,9 @@ static char *trim(char *buf)
|
||||
|
||||
static int skip_channel(int x)
|
||||
{
|
||||
int spanno = chan2span[x];
|
||||
|
||||
if (restrict_channels) {
|
||||
if (!selected_channels[x])
|
||||
return 1;
|
||||
/* sanity check */
|
||||
if (only_span) {
|
||||
if (spanno != 0 && only_span != spanno) {
|
||||
fprintf(stderr,
|
||||
"Only span %d. Skip selected channel %d from span %d\n",
|
||||
only_span, x, spanno);
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (only_span && !declared_spans[only_span]) {
|
||||
fprintf(stderr,
|
||||
@@ -354,8 +341,6 @@ static int skip_channel(int x)
|
||||
only_span);
|
||||
exit(1);
|
||||
}
|
||||
if (only_span && only_span != spanno)
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
@@ -442,7 +427,6 @@ int spanconfig(char *keyword, char *args)
|
||||
error("Span number should be a valid span number, not '%s'\n", realargs[0]);
|
||||
return -1;
|
||||
}
|
||||
current_span = span;
|
||||
declared_spans[span] = 1;
|
||||
res = sscanf(realargs[1], "%d", &timing);
|
||||
if ((res != 1) || (timing < 0) || (timing > MAX_TIMING)) {
|
||||
@@ -615,7 +599,6 @@ static int chanconfig(char *keyword, char *args)
|
||||
int master=0;
|
||||
int dacschan = 0;
|
||||
char *idle;
|
||||
int is_digital;
|
||||
bzero(chans, sizeof(chans));
|
||||
strtok(args, ":");
|
||||
idle = strtok(NULL, ":");
|
||||
@@ -627,7 +610,6 @@ static int chanconfig(char *keyword, char *args)
|
||||
if (res <= 0)
|
||||
return -1;
|
||||
for (x=1;x<DAHDI_MAX_CHANNELS;x++) {
|
||||
is_digital = 0;
|
||||
if (chans[x]) {
|
||||
if (slineno[x]) {
|
||||
error("Channel %d already configured as '%s' at line %d\n", x, sig[x], slineno[x]);
|
||||
@@ -673,7 +655,6 @@ static int chanconfig(char *keyword, char *args)
|
||||
return -1;
|
||||
cc[x].sigtype = DAHDI_SIG_CAS;
|
||||
sig[x] = sigtype_to_str(cc[x].sigtype);
|
||||
is_digital = 1;
|
||||
} else if (!strcasecmp(keyword, "dacs")) {
|
||||
/* Setup channel for monitor */
|
||||
cc[x].idlebits = dacschan;
|
||||
@@ -684,7 +665,6 @@ static int chanconfig(char *keyword, char *args)
|
||||
cc[dacschan].sigtype = DAHDI_SIG_DACS;
|
||||
sig[x] = sigtype_to_str(cc[dacschan].sigtype);
|
||||
dacschan++;
|
||||
is_digital = 1;
|
||||
} else if (!strcasecmp(keyword, "dacsrbs")) {
|
||||
/* Setup channel for monitor */
|
||||
cc[x].idlebits = dacschan;
|
||||
@@ -694,7 +674,6 @@ static int chanconfig(char *keyword, char *args)
|
||||
cc[dacschan].idlebits = x;
|
||||
cc[dacschan].sigtype = DAHDI_SIG_DACS_RBS;
|
||||
sig[x] = sigtype_to_str(cc[dacschan].sigtype);
|
||||
is_digital = 1;
|
||||
dacschan++;
|
||||
} else if (!strcasecmp(keyword, "unused")) {
|
||||
cc[x].sigtype = 0;
|
||||
@@ -702,7 +681,6 @@ static int chanconfig(char *keyword, char *args)
|
||||
} else if (!strcasecmp(keyword, "indclear") || !strcasecmp(keyword, "bchan")) {
|
||||
cc[x].sigtype = DAHDI_SIG_CLEAR;
|
||||
sig[x] = sigtype_to_str(cc[x].sigtype);
|
||||
is_digital = 1;
|
||||
} else if (!strcasecmp(keyword, "clear")) {
|
||||
sig[x] = sigtype_to_str(DAHDI_SIG_CLEAR);
|
||||
if (master) {
|
||||
@@ -712,7 +690,6 @@ static int chanconfig(char *keyword, char *args)
|
||||
cc[x].sigtype = DAHDI_SIG_CLEAR;
|
||||
master = x;
|
||||
}
|
||||
is_digital = 1;
|
||||
} else if (!strcasecmp(keyword, "rawhdlc")) {
|
||||
sig[x] = sigtype_to_str(DAHDI_SIG_HDLCRAW);
|
||||
if (master) {
|
||||
@@ -722,7 +699,6 @@ static int chanconfig(char *keyword, char *args)
|
||||
cc[x].sigtype = DAHDI_SIG_HDLCRAW;
|
||||
master = x;
|
||||
}
|
||||
is_digital = 1;
|
||||
} else if (!strcasecmp(keyword, "nethdlc")) {
|
||||
sig[x] = sigtype_to_str(DAHDI_SIG_HDLCNET);
|
||||
memset(cc[x].netdev_name, 0, sizeof(cc[x].netdev_name));
|
||||
@@ -736,7 +712,6 @@ static int chanconfig(char *keyword, char *args)
|
||||
}
|
||||
master = x;
|
||||
}
|
||||
is_digital = 1;
|
||||
} else if (!strcasecmp(keyword, "fcshdlc")) {
|
||||
sig[x] = sigtype_to_str(DAHDI_SIG_HDLCFCS);
|
||||
if (master) {
|
||||
@@ -746,19 +721,15 @@ static int chanconfig(char *keyword, char *args)
|
||||
cc[x].sigtype = DAHDI_SIG_HDLCFCS;
|
||||
master = x;
|
||||
}
|
||||
is_digital = 1;
|
||||
} else if (!strcasecmp(keyword, "dchan")) {
|
||||
sig[x] = "D-channel";
|
||||
cc[x].sigtype = DAHDI_SIG_HDLCFCS;
|
||||
is_digital = 1;
|
||||
} else if (!strcasecmp(keyword, "hardhdlc")) {
|
||||
sig[x] = "Hardware assisted D-channel";
|
||||
cc[x].sigtype = DAHDI_SIG_HARDHDLC;
|
||||
is_digital = 1;
|
||||
} else if (!strcasecmp(keyword, "mtp2")) {
|
||||
sig[x] = "MTP2";
|
||||
cc[x].sigtype = DAHDI_SIG_MTP2;
|
||||
is_digital = 1;
|
||||
} else {
|
||||
fprintf(stderr, "Huh? (%s)\n", keyword);
|
||||
}
|
||||
@@ -770,11 +741,6 @@ static int chanconfig(char *keyword, char *args)
|
||||
fprintf(stderr, "WARNING: idlebits are not valid on %s channels.\n", sig[x]);
|
||||
}
|
||||
}
|
||||
|
||||
if (is_digital)
|
||||
chan2span[x] = current_span;
|
||||
else
|
||||
current_span = 0;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
@@ -1617,6 +1583,10 @@ int main(int argc, char *argv[])
|
||||
fprintf(stderr, "%s\n", dahdi_tools_version);
|
||||
}
|
||||
|
||||
if (!restrict_channels && only_span) {
|
||||
error("-S requires -C\n");
|
||||
goto finish;
|
||||
}
|
||||
if (!restrict_channels && !only_span) {
|
||||
bool all_assigned = wait_for_all_spans_assigned(5);
|
||||
|
||||
|
||||
@@ -66,6 +66,8 @@ usage() {
|
||||
echo >&2 " add - assign spans, according to /etc/dahdi/assigned-spans.conf"
|
||||
echo >&2 " remove - unassign spans"
|
||||
echo >&2 " list - human-readable list of all spans"
|
||||
echo >&2 " matched - found spans matched in configuration"
|
||||
echo >&2 " unmatched - found spans not matched in configuration"
|
||||
echo >&2 " dumpconfig - dump current state as new configuration"
|
||||
echo >&2 ""
|
||||
echo >&2 " options:"
|
||||
@@ -109,7 +111,7 @@ while true ; do
|
||||
break
|
||||
;;
|
||||
*)
|
||||
echo "Internal error!"
|
||||
echo >&2 "Internal error!"
|
||||
exit 1
|
||||
;;
|
||||
esac
|
||||
@@ -215,10 +217,10 @@ unassign_all_spans() {
|
||||
sort | while read spandir; do
|
||||
local_spanno=`cat "$spandir/local_spanno"`
|
||||
if [ "$dry_run" = true ]; then
|
||||
echo "(dry-run) unassign $device $local_spanno"
|
||||
echo >&2 "(dry-run) unassign $device $local_spanno"
|
||||
continue
|
||||
fi
|
||||
echo "unassign $device $local_spanno"
|
||||
echo >&2 "unassign $device $local_spanno"
|
||||
if ! echo "$local_spanno" > "$device/unassign_span"; then
|
||||
echo >&2 "$0: failed unassigning '$local_spanno' in '$device'"
|
||||
fi
|
||||
@@ -245,12 +247,12 @@ assign_device_spans() {
|
||||
if [ -d "$span" ]; then
|
||||
span_local_spanno=`cat "$span/local_spanno"`
|
||||
if [ "$span_local_spanno" != "$local_spanno" ]; then
|
||||
echo "WARNING: $span_local_spanno != $local_spanno"
|
||||
echo >&2 "WARNING: $span_local_spanno != $local_spanno"
|
||||
fi
|
||||
echo "$device [$local_spanno] already assigned to span $spanno. Skipping..."
|
||||
echo >&2 "$device [$local_spanno] already assigned to span $spanno. Skipping..."
|
||||
continue
|
||||
fi
|
||||
echo "assign $device: $s"
|
||||
echo >&2 "assign $device: $s"
|
||||
if ! echo "$s" > "$device/assign_span"; then
|
||||
echo >&2 "$0: failed assigning '$s' to '$device'"
|
||||
fi
|
||||
@@ -267,21 +269,21 @@ match_device() {
|
||||
# We use case to enable shell-style globbing in configuration
|
||||
case "$hardware_id" in
|
||||
$id)
|
||||
[ "$verbose" = true ] && echo "match by hwid ($id ~ $hardware_id): $spanspecs"
|
||||
[ "$verbose" = true ] && echo >&2 "match by hwid ($id ~ $hardware_id): $spanspecs"
|
||||
assign_device_spans "$device"
|
||||
;;
|
||||
esac
|
||||
# We use case to enable shell-style globbing in configuration
|
||||
case "$location" in
|
||||
$id)
|
||||
[ "$verbose" = true ] && echo "match by location ($id ~ $location): $spanspecs"
|
||||
[ "$verbose" = true ] && echo >&2 "match by location ($id ~ $location): $spanspecs"
|
||||
assign_device_spans "$device"
|
||||
;;
|
||||
esac
|
||||
# We use case to enable shell-style globbing in configuration
|
||||
case "$devpath" in
|
||||
$id)
|
||||
[ "$verbose" = true ] && echo "match by devpath ($id ~ $devpath): $spanspecs"
|
||||
[ "$verbose" = true ] && echo >&2 "match by devpath ($id ~ $devpath): $spanspecs"
|
||||
assign_device_spans "$device"
|
||||
;;
|
||||
esac
|
||||
@@ -293,7 +295,7 @@ assign_devices() {
|
||||
echo >&2 "$0: Missing '$DAHDISASSIGNEDSPANSCONF'"
|
||||
exit 1
|
||||
fi
|
||||
echo "using '$DAHDISASSIGNEDSPANSCONF'"
|
||||
echo >&2 "using '$DAHDISASSIGNEDSPANSCONF'"
|
||||
for device in $DEVICES
|
||||
do
|
||||
match_device "$device"
|
||||
@@ -303,13 +305,71 @@ assign_devices() {
|
||||
auto_assign_devices() {
|
||||
for device in $DEVICES
|
||||
do
|
||||
echo "auto-assign $device"
|
||||
echo >&2 "auto-assign $device"
|
||||
if [ "$dry_run" != true ]; then
|
||||
echo 1 > "$device/auto_assign"
|
||||
fi
|
||||
done
|
||||
}
|
||||
|
||||
dev_match_conf() {
|
||||
local devpath="$1"
|
||||
local location="$2"
|
||||
local hardware_id="$3"
|
||||
local local_spanno="$4"
|
||||
filter_conf | while read id spanspecs
|
||||
do
|
||||
spanno=`echo "$spanspecs" | cut -d: -f1`
|
||||
match_dev=no
|
||||
# We use case to enable shell-style globbing in configuration
|
||||
case "$hardware_id" in
|
||||
$id)
|
||||
match_dev=yes
|
||||
;;
|
||||
esac
|
||||
# We use case to enable shell-style globbing in configuration
|
||||
case "$location" in
|
||||
$id)
|
||||
match_dev=yes
|
||||
;;
|
||||
esac
|
||||
# We use case to enable shell-style globbing in configuration
|
||||
case "$devpath" in
|
||||
$id)
|
||||
match_dev=yes
|
||||
;;
|
||||
esac
|
||||
if [ "$match_dev" = 'yes' -a "$local_spanno" = "$spanno" ]; then
|
||||
#printf "%-8s (%s) %-14s %s %s\n" "$local_spanno" "$spanno" "[$hardware_id]" "$location" "$devpath"
|
||||
echo "[$hardware_id]:$local_spanno"
|
||||
fi
|
||||
done
|
||||
}
|
||||
|
||||
list_devices() {
|
||||
wanted="$1"
|
||||
if [ ! -f "$DAHDISASSIGNEDSPANSCONF" ]; then
|
||||
echo >&2 "$0: Missing '$DAHDISASSIGNEDSPANSCONF'"
|
||||
exit 1
|
||||
fi
|
||||
echo >&2 "using '$DAHDISASSIGNEDSPANSCONF'"
|
||||
for device in $DEVICES
|
||||
do
|
||||
devpath=`cd "$device" && pwd -P`
|
||||
location='@'`attr_clean "$device/location"`
|
||||
hardware_id=`attr_clean "$device/hardware_id"`
|
||||
for local_spanno in `cut -d: -f1 "$device/spantype"`
|
||||
do
|
||||
found=`dev_match_conf "$devpath" "$location" "$hardware_id" "$local_spanno"`
|
||||
if [ "$wanted" = "unmatched" ]; then
|
||||
[ -z "$found" ] && echo "[$hardware_id]:$local_spanno"
|
||||
else
|
||||
[ -z "$found" ] || echo "[$hardware_id]:$local_spanno"
|
||||
fi
|
||||
done
|
||||
done
|
||||
}
|
||||
|
||||
case "$action" in
|
||||
auto)
|
||||
auto_assign_devices
|
||||
@@ -326,6 +386,12 @@ list)
|
||||
dumpconfig)
|
||||
dump_config
|
||||
;;
|
||||
matched)
|
||||
list_devices "matched"
|
||||
;;
|
||||
unmatched)
|
||||
list_devices "unmatched"
|
||||
;;
|
||||
*)
|
||||
echo >&2 "Bad action='$action'"
|
||||
usage
|
||||
|
||||
@@ -69,6 +69,7 @@ usage() {
|
||||
echo >&2 "Usage: $0 [options] action [devpath ...]"
|
||||
echo >&2 " action:"
|
||||
echo >&2 " set - set spans to E1/T1 according to /etc/dahdi/span-types.conf"
|
||||
echo >&2 " compare - show config values that differ from system"
|
||||
echo >&2 " list - human-readable list of all spans"
|
||||
echo >&2 " dumpconfig - dump current state in /etc/dahdi/span-types.conf format"
|
||||
echo >&2 ""
|
||||
@@ -88,6 +89,8 @@ if [ $? != 0 ]; then
|
||||
usage
|
||||
fi
|
||||
|
||||
compare=false
|
||||
|
||||
# Note the quotes around `$TEMP': they are essential!
|
||||
eval set -- "$TEMP"
|
||||
|
||||
@@ -321,13 +324,26 @@ handle_span() {
|
||||
echo >&2 "Set $devname span $spanno = $val"
|
||||
fi
|
||||
if [ "$dry_run" != 'true' ]; then
|
||||
echo "$spanno:$val" > "$attr_file"
|
||||
if [ "$compare" = 'true' ]; then
|
||||
config="$spanno:$val"
|
||||
system=`grep "$spanno:" "$attr_file"`
|
||||
if [ "$config" != "$system" ]; then
|
||||
|
||||
active_val=`echo $system | cut -d: -f2`
|
||||
echo "$devname $spanno $val $active_val" >>"$compare_results_file"
|
||||
fi
|
||||
else
|
||||
echo "$spanno:$val" > "$attr_file"
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
done
|
||||
}
|
||||
|
||||
set_all_devices() {
|
||||
span_differs='false'
|
||||
SPANS_DIFFER='false'
|
||||
|
||||
if [ ! -f "$DAHDISPANTYPESCONF" ]; then
|
||||
echo >&2 "$0: Missing configuration '$DAHDISPANTYPESCONF'"
|
||||
exit 1
|
||||
@@ -348,6 +364,16 @@ set_all_devices() {
|
||||
esac
|
||||
done
|
||||
done
|
||||
if [ "$compare" = 'true' ]; then
|
||||
if [ -s "$compare_results_file" ]; then
|
||||
echo "# Device Unit Config Active"
|
||||
cat "$compare_results_file"
|
||||
rm -f "$compare_results_file"
|
||||
exit 5
|
||||
fi
|
||||
rm -f "$compare_results_file"
|
||||
exit 0
|
||||
fi
|
||||
}
|
||||
|
||||
case "$action" in
|
||||
@@ -360,6 +386,11 @@ dumpconfig)
|
||||
set)
|
||||
set_all_devices
|
||||
;;
|
||||
compare)
|
||||
compare=true
|
||||
compare_results_file=`mktemp`
|
||||
set_all_devices
|
||||
;;
|
||||
*)
|
||||
usage
|
||||
;;
|
||||
|
||||
@@ -64,7 +64,7 @@ void hup_handler(int sig)
|
||||
printf("\n--- Results after %d passes ---\n", pass);
|
||||
printf("Best: %.3f%% -- Worst: %.3f%% -- Average: %f%%\n",
|
||||
best, worst, pass ? total/pass : 100.00);
|
||||
printf("Cummulative Accuracy (not per pass): %0.3f\n",
|
||||
printf("Cumulative Accuracy (not per pass): %0.3f\n",
|
||||
pass ? accuracy : 0.0);
|
||||
exit(0);
|
||||
}
|
||||
|
||||
@@ -41,10 +41,8 @@ Only shutdown spans.
|
||||
|
||||
.B \-S \fISPAN
|
||||
.RS
|
||||
Only apply changes to span no. \fISPAN\fR. For a digital span (with
|
||||
a 'span=' line in the configuration file) this will do. For an analog
|
||||
span you'll have to explicitly tell dahdi_cfg the range of channels,
|
||||
using \-C .
|
||||
Only apply changes to span no. \fISPAN\fR. You also need to specify the
|
||||
range of channels in the span explicitly with \-C.
|
||||
.RE
|
||||
|
||||
.B \-f
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
dahdi_span_types \- set line modes of DAHDI spans before assignment
|
||||
.SH SYNOPSIS
|
||||
|
||||
.B dahdi_span_types [\fIoptions\fB] <list|dumpconfig|set> \fB[\fIdevpath \fB...]
|
||||
.B dahdi_span_types [\fIoptions\fB] <list|dumpconfig|compare|set> \fB[\fIdevpath \fB...]
|
||||
|
||||
.SH DESCRIPTION
|
||||
The span type (the line mode: E1/T1/J1) must be set to a span before
|
||||
@@ -58,6 +58,16 @@ device(s) specified in the command line (or all devices, if none
|
||||
specified).
|
||||
.RE
|
||||
|
||||
.B compare
|
||||
.RS
|
||||
Compare the settings on the system to those in the configuration file.
|
||||
For each line that applies to a device on the system, print it if the
|
||||
value to be set and the active value on the system differ.
|
||||
|
||||
The exit status is 0 if there is no difference and non-zero if a
|
||||
difference was detected.
|
||||
.RE
|
||||
|
||||
.B list
|
||||
.RS
|
||||
List line modes for all spans in the system which may be set with
|
||||
|
||||
@@ -7,7 +7,7 @@ dahdi_tool \- Shows status of DAHDI interfaces
|
||||
.B dahdi_tool
|
||||
|
||||
.SH DESCRIPTION
|
||||
dahdi_tool shows the current status the DAHDI inteface cards plugged
|
||||
dahdi_tool shows the current status the DAHDI interface cards plugged
|
||||
to the computer.
|
||||
|
||||
It displays values like Current Alarms, SyncSource, Tx/Rx
|
||||
|
||||
@@ -33,7 +33,7 @@ is generated in the current directory.
|
||||
fxotune just reads the settings from fxotune.conf into the FXO modules.
|
||||
|
||||
You are advised to run fxotune on all FXO ports you have that support
|
||||
it and that are connected. Note that the tunning is affected by e.g.
|
||||
it and that are connected. Note that the tuning is affected by e.g.
|
||||
the physical parameters of the connection, and thus if it has been
|
||||
radically changed, you may need to re-run fxotune.
|
||||
|
||||
@@ -44,7 +44,7 @@ cards and clones) do not have the hardware to support such tuning.
|
||||
The tuning process needs a clear line to do the tuning. In order to do
|
||||
that, it runs in cycles of the following: sets the line off-hook, dials
|
||||
a dial string (which should set the PSTN provider waiting for the next
|
||||
digit), and then starts tuning. It has a limited ammount of time for
|
||||
digit), and then starts tuning. It has a limited amount of time for
|
||||
tuning before the PSTN gives up and gives a busy tone. So after a while
|
||||
it hangs up and starts a new cycle.
|
||||
|
||||
@@ -180,7 +180,7 @@ so if you stop it half-way, you may get a half-configured system. If you
|
||||
have already tuned your FXO channels and wish to test-run fxotune again,
|
||||
you are advised to backup /etc/fxotune.conf .
|
||||
|
||||
The default for \-m is 18 seconds. This asusmes that you get a clear line
|
||||
The default for \-m is 18 seconds. This assumes that you get a clear line
|
||||
for at least 18 seconds. It is advised that you test that timeout earlier
|
||||
by connecting a phone to the FXO line, dialing 4 (or whatever dial string
|
||||
you put with \-n) and see how much time of silence you have.
|
||||
|
||||
@@ -22,4 +22,9 @@ devices_by_registration_time | \
|
||||
done
|
||||
|
||||
# Now handle Astribanks
|
||||
LC_ALL=C dahdi_registration -Rv on
|
||||
unmatched="`dahdi_span_assignments unmatched`"
|
||||
if [ -n "$unmatched" ]; then
|
||||
# Only if astribanks are not matched in span-assignments.conf
|
||||
# TODO: have dahdi_registration run only on "$unmatched"
|
||||
LC_ALL=C dahdi_registration -Rv on
|
||||
fi
|
||||
|
||||
18
hotplug/handle_device.d/30-xpp-sync
Executable file
18
hotplug/handle_device.d/30-xpp-sync
Executable file
@@ -0,0 +1,18 @@
|
||||
#! /bin/sh
|
||||
|
||||
# Run xpp_sync whenever an Astribank is connected.
|
||||
|
||||
# May be set in /etc/dahdi/init.conf
|
||||
XPP_SYNC=${XPP_SYNC:-auto}
|
||||
|
||||
case "$ACTION" in
|
||||
add) ;;
|
||||
*) exit 0 ;;
|
||||
esac
|
||||
|
||||
case "${DEVPATH##*/}" in
|
||||
astribanks:*) ;;
|
||||
*) exit 0 ;;
|
||||
esac
|
||||
|
||||
xpp_sync "$XPP_SYNC"
|
||||
2
patgen.c
2
patgen.c
@@ -45,7 +45,6 @@
|
||||
#define BLOCK_SIZE 2041
|
||||
#define DEVICE "/dev/dahdi/channel"
|
||||
|
||||
static const char rcsid[] = "$Id$";
|
||||
char *prog_name;
|
||||
|
||||
static void usage(void)
|
||||
@@ -53,7 +52,6 @@ static void usage(void)
|
||||
fprintf(stderr, "Usage: %s <dahdi_chan>\n", prog_name);
|
||||
fprintf(stderr, " e.g.: %s /dev/dahdi/55\n", prog_name);
|
||||
fprintf(stderr, " %s 455\n", prog_name);
|
||||
fprintf(stderr, "%s version %s\n", prog_name, rcsid);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
|
||||
@@ -44,7 +44,6 @@
|
||||
#define BLOCK_SIZE 2039
|
||||
#define DEVICE "/dev/dahdi/channel"
|
||||
|
||||
static const char rcsid[] = "$Id$";
|
||||
char *prog_name;
|
||||
|
||||
static void usage(void)
|
||||
@@ -52,7 +51,6 @@ static void usage(void)
|
||||
fprintf(stderr, "Usage: %s <dahdi_chan>\n", prog_name);
|
||||
fprintf(stderr, " e.g.: %s /dev/dahdi/55\n", prog_name);
|
||||
fprintf(stderr, " %s 455\n", prog_name);
|
||||
fprintf(stderr, "%s version %s\n", prog_name, rcsid);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
|
||||
5
xpp/50-dahdi.conf
Normal file
5
xpp/50-dahdi.conf
Normal file
@@ -0,0 +1,5 @@
|
||||
# A dracut.conf(5) snippet
|
||||
# Disable loading the Astribank (xpp_usb) drivers. This is because
|
||||
# it relies on files in the root filesystem:
|
||||
# See https://issues.asterisk.org/jira/browse/DAHLIN-352
|
||||
omit_drivers+=" xpp_usb "
|
||||
@@ -3,10 +3,12 @@ all-local: $(perl_checks)
|
||||
|
||||
SUBDIRS =
|
||||
|
||||
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 += \
|
||||
@@ -22,7 +24,7 @@ if PERL
|
||||
SUBDIRS += perl_modules
|
||||
|
||||
%.8: %
|
||||
@if file "$^" | cut -d: -f2 | grep -q perl; then \
|
||||
@if file "$^" | cut -d: -f2 | grep -q -iw perl; then \
|
||||
if pod2man --section 8 $^ > $@; then \
|
||||
echo " GEN $@"; \
|
||||
else \
|
||||
@@ -57,34 +59,41 @@ udevrulesdir = @udevrulesdir@
|
||||
udevrules_DATA = xpp.rules
|
||||
|
||||
dist_sbin_SCRIPTS = $(perl_scripts)
|
||||
man_MANS = $(perl_mans)
|
||||
man_MANS += $(perl_mans)
|
||||
CLEANFILES = $(perl_checks) $(perl_mans)
|
||||
|
||||
dracutconfdir = @prefix@/lib/dracut/dracut.conf.d
|
||||
dracutconf_DATA = 50-dahdi.conf
|
||||
|
||||
if PBX_USB
|
||||
|
||||
SUBDIRS += oct612x
|
||||
SUBDIRS += oct612x xtalk
|
||||
|
||||
if LIBUSBX
|
||||
USB_CFLAGS = $(LIBUSBX_CFLAGS)
|
||||
USB_LIBS = $(LIBUSBX_LIBS)
|
||||
USB_NAME = libusbx
|
||||
else
|
||||
if LIBUSB
|
||||
USB_CFLAGS = $(LIBUSB_CFLAGS)
|
||||
USB_LIBS = $(LIBUSB_LIBS)
|
||||
USB_NAME = libusb
|
||||
endif
|
||||
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 \
|
||||
astribank_license.c \
|
||||
astribank_license.h \
|
||||
#
|
||||
|
||||
libastribank_la_CFLAGS = $(GLOBAL_CFLAGS)
|
||||
libastribank_la_LIBADD = xtalk/libxtalk.la
|
||||
|
||||
if USE_OCTASIC
|
||||
libecholoader_la_SOURCES = \
|
||||
@@ -113,7 +122,7 @@ test_parse_LDADD = libhexfile.la
|
||||
|
||||
astribank_tool_SOURCES = astribank_tool.c
|
||||
astribank_tool_CFLAGS = $(GLOBAL_CFLAGS)
|
||||
astribank_tool_LDFLAGS = $(USB_LIB)
|
||||
astribank_tool_LDFLAGS = $(USB_LIBS)
|
||||
astribank_tool_LDADD = libastribank.la
|
||||
|
||||
astribank_hexload_SOURCES = \
|
||||
@@ -123,7 +132,7 @@ astribank_hexload_SOURCES = \
|
||||
#
|
||||
|
||||
astribank_hexload_CFLAGS = $(GLOBAL_CFLAGS) $(OCTASIC_CFLAGS)
|
||||
astribank_hexload_LDFLAGS = $(USB_LIB)
|
||||
astribank_hexload_LDFLAGS = $(USB_LIBS)
|
||||
astribank_hexload_LDADD = \
|
||||
libhexfile.la \
|
||||
libastribank.la \
|
||||
@@ -131,14 +140,8 @@ astribank_hexload_LDADD = \
|
||||
oct612x/liboctasic.la \
|
||||
#
|
||||
|
||||
astribank_allow_SOURCES = \
|
||||
astribank_allow.c \
|
||||
astribank_license.c \
|
||||
astribank_license.h \
|
||||
#
|
||||
|
||||
astribank_allow_CFLAGS = $(GLOBAL_CFLAGS)
|
||||
astribank_allow_LDFLAGS = $(USB_LIB)
|
||||
astribank_allow_LDFLAGS = $(USB_LIBS)
|
||||
astribank_allow_LDADD = libastribank.la
|
||||
|
||||
man_pages = \
|
||||
@@ -148,6 +151,7 @@ man_pages = \
|
||||
astribank_is_starting.8
|
||||
|
||||
man_MANS += $(man_pages)
|
||||
|
||||
endif
|
||||
|
||||
EXTRA_DIST = \
|
||||
|
||||
@@ -47,9 +47,9 @@ Apart from the standard DAHDI build requirements, you also need:
|
||||
|
||||
* *libusb development headers* to build the Astribank firmware tools
|
||||
(astribank_tool, astribank_hexload, astribank_allow).
|
||||
This is typically the package libusb-dev on Debian (and derivatives
|
||||
like Ubuntu) or libusb-devel on RedHat (and derivatives like
|
||||
CentOS/Trixbox).
|
||||
This is typically the package libusb-1.0-0-dev on Debian (and
|
||||
derivatives such as Ubuntu) or libusbx-devel on RedHat (and derivatives
|
||||
such as CentOS).
|
||||
* *Echo Canceller Module firmware*: If you have an Astribank with an
|
||||
echo canceller module, see the following section.
|
||||
|
||||
@@ -1257,8 +1257,8 @@ Astribanks Synchronization Source
|
||||
If there is more than one Astribank on the system, all the Astribanks
|
||||
keep their clock in sync. Optionally the Astribanks can synchronize
|
||||
their clock to the master DAHDI device (in case it is a different DAHDI
|
||||
device). Normally you just use the default init.d script or run
|
||||
explicitly:
|
||||
device). Normally it would be run automatically from the udev hooks
|
||||
run on device plug (handle_device), but you can also run it explicitly:
|
||||
|
||||
xpp_sync auto
|
||||
|
||||
@@ -1488,6 +1488,9 @@ other side.
|
||||
current. That is: which ones are connected to an active FXS on the
|
||||
other side.
|
||||
|
||||
===== /sys/bus/astribanks/devices/xbus-NN/NN:M:P/hwid
|
||||
Prints <module type>.<module subtype>. Both are small numbers.
|
||||
|
||||
===== /sys/bus/astribanks/devices/xbus-NN/NN:M:P/offhook
|
||||
Shows ports that are (1) or are not (0) off-hook. When a channel is
|
||||
not off-hook. For BRI and E1/T1 the value is 1 if the span is in use.
|
||||
|
||||
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,13 +31,11 @@
|
||||
#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$";
|
||||
|
||||
#define DBG_MASK 0x80
|
||||
|
||||
static char *progname;
|
||||
@@ -55,28 +53,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 +108,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 +142,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 +169,6 @@ int main(int argc, char *argv[])
|
||||
if (file != stdout)
|
||||
fclose(file);
|
||||
}
|
||||
mpp_exit(astribank);
|
||||
astribank_destroy(astribank);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -117,7 +117,7 @@ Examples:
|
||||
1:T1,2:T1,*:E1 \- First and second ports are T1, the rest are E1.
|
||||
.RE
|
||||
|
||||
If the \fB\-S\fR is not given, the PRI default is determined by the existance of the \fB\-A-fR option.
|
||||
If the \fB\-S\fR is not given, the PRI default is determined by the existence of the \fB\-A-fR option.
|
||||
.RE
|
||||
|
||||
.SH SEE ALSO
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -94,22 +94,27 @@ wait_for_udev() {
|
||||
UDEV_SETTLE_MAX_TIME=10
|
||||
|
||||
echo "Waiting for udev to settle down..."
|
||||
if [ -x /sbin/udevsettle ]; then
|
||||
# Old system, stand-alone udevsettle command
|
||||
/sbin/udevsettle --timeout="$UDEV_SETTLE_MAX_TIME"
|
||||
udevsettle_cmd=
|
||||
if [ -x /bin/udevadm ]; then
|
||||
udevsettle_cmd="/bin/udevadm settle"
|
||||
elif [ -x /sbin/udevadm ]; then
|
||||
# Assume modern system, udevadm has settle parameter
|
||||
if ! /sbin/udevadm settle --timeout="$UDEV_SETTLE_MAX_TIME"
|
||||
then
|
||||
echo "udevadm failed ($?)."
|
||||
echo "Fallback to sleep $UDEV_SETTLE_MAX_TIME seconds."
|
||||
sleep "$UDEV_SETTLE_MAX_TIME"
|
||||
fi
|
||||
udevsettle_cmd="/sbin/udevadm settle"
|
||||
elif [ -x /sbin/udevsettle ]; then
|
||||
udevsettle_cmd="/sbin/udevsettle"
|
||||
else
|
||||
echo "No udevsettle/udevadm."
|
||||
echo "Fallback to sleep $UDEV_SETTLE_MAX_TIME seconds."
|
||||
sleep "$UDEV_SETTLE_MAX_TIME"
|
||||
return
|
||||
fi
|
||||
|
||||
if ! $udevsettle_cmd --timeout="$UDEV_SETTLE_MAX_TIME"
|
||||
then
|
||||
echo "udevadm failed ($?)."
|
||||
echo "Fallback to sleep $UDEV_SETTLE_MAX_TIME seconds."
|
||||
sleep "$UDEV_SETTLE_MAX_TIME"
|
||||
fi
|
||||
|
||||
sleep 1 # Wait a bit more (races)
|
||||
}
|
||||
|
||||
|
||||
@@ -83,7 +83,7 @@ Q: Why do you use a semaphore?
|
||||
A: because, unlike the filesystem, it is writable at any given time.
|
||||
|
||||
.SH BUGS
|
||||
Option ordering matter. The \fB\-v\fR and \fB\-d\fR options should preceed
|
||||
Option ordering matter. The \fB\-v\fR and \fB\-d\fR options should precede
|
||||
the actions (\fB\-a\fR, \fB\-r\fR and \fB\-w\fR).
|
||||
The \fB\-t\fItimeout\fR option should preceed the \fB\-w\fR option.
|
||||
|
||||
|
||||
@@ -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
|
||||
@@ -72,94 +72,15 @@ static int reset_kind(const char *arg)
|
||||
if(strcasecmp(reset_kinds[i].name, arg) == 0)
|
||||
return reset_kinds[i].type_code;
|
||||
}
|
||||
ERR("Uknown reset kind '%s'\n", arg);
|
||||
ERR("Unknown reset kind '%s'\n", 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
|
||||
@@ -244,19 +157,19 @@ int main(int argc, char *argv[])
|
||||
ERR("Bad reset kind '%s'\n", opt_reset);
|
||||
return 1;
|
||||
}
|
||||
DBG("Reseting (%s)\n", opt_reset);
|
||||
if((ret = mpp_reset(astribank, full_reset)) < 0) {
|
||||
ERR("%s Reseting astribank failed: %d\n",
|
||||
DBG("Resetting (%s)\n", opt_reset);
|
||||
if((ret = mpp_reset(mpp, full_reset)) < 0) {
|
||||
ERR("%s Resetting astribank failed: %d\n",
|
||||
(full_reset) ? "Full" : "Half", ret);
|
||||
}
|
||||
goto out;
|
||||
}
|
||||
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 */
|
||||
@@ -109,9 +109,15 @@ foreach my $xbus (Dahdi::Xpp::xbuses($sorter)) {
|
||||
system @cmd;
|
||||
warn "Failed '@cmd' (status=$?)\n" if $?;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (defined($on) && $on) {
|
||||
if ($opts{'R'} || ! $default_auto_assign) {
|
||||
# wait for UDEV to do its stuff
|
||||
system "dahdi_waitfor_span_assignments assigned";
|
||||
}
|
||||
}
|
||||
foreach my $xbus (Dahdi::Xpp::xbuses($sorter)) {
|
||||
foreach my $xpd (Dahdi::Xpp::Xpd::telephony_devs($xbus->xpds())) {
|
||||
my $spanno = $xpd->xpd_getattr('span');
|
||||
myprintf "\t%-10s: ", $xpd->fqn;
|
||||
|
||||
@@ -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 */
|
||||
|
||||
@@ -28,8 +28,6 @@
|
||||
#include <ctype.h>
|
||||
#include "hexfile.h"
|
||||
|
||||
static const char rcsid[] = "$Id$";
|
||||
|
||||
static parse_hexfile_report_func_t report_func = NULL;
|
||||
|
||||
parse_hexfile_report_func_t parse_hexfile_set_reporting(parse_hexfile_report_func_t rf)
|
||||
|
||||
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 */
|
||||
@@ -1,3 +1,5 @@
|
||||
GLOBAL_CFLAGS = -Wall -Werror
|
||||
|
||||
OCTASIC_DEFINES = \
|
||||
-DPTR_TYPE=uint32_t \
|
||||
-DcOCT6100_INTERNAL_SUPER_ARRAY_SIZE=1024 \
|
||||
@@ -84,6 +86,7 @@ noinst_HEADERS = \
|
||||
#
|
||||
|
||||
liboctasic_la_CFLAGS = \
|
||||
$(GLOBAL_CFLAGS) \
|
||||
$(OCTASIC_DEFINES) \
|
||||
$(OCTASIC_CFLAGS)
|
||||
|
||||
|
||||
@@ -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 */
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
# Load firmware into the Xorcom Astribank device:
|
||||
SUBSYSTEM=="usb", ACTION=="add", \
|
||||
ENV{PRODUCT}=="e4e4/11[3456][013]/*", ENV{DEVTYPE}!="usb_interface", \
|
||||
OPTIONS+="event_timeout=180" \
|
||||
RUN+="/usr/share/dahdi/xpp_fxloader udev $env{PRODUCT}"
|
||||
|
||||
# Hotplug hook for Astribank up/down
|
||||
|
||||
@@ -349,7 +349,7 @@ load_fw_device() {
|
||||
echo "WARNING: ECHO burning was skipped (no capabilities)"
|
||||
fi
|
||||
fi
|
||||
pic_files=`echo "$FIRMWARE_DIR"/PIC_TYPE_[1-4].hex`
|
||||
pic_files=`echo "$FIRMWARE_DIR"/PIC_TYPE_[1-46].hex`
|
||||
debug "PIC burning into $dev: begin $pic_files"
|
||||
run_astribank_hexload -D "$dev" -p $pic_files
|
||||
debug "PIC burning into $dev: end $pic_files"
|
||||
@@ -443,7 +443,7 @@ fpga_firmware_all_devices() {
|
||||
reset_fpga() {
|
||||
devices=`filter_devs 'e4e4/11[3456][124]/*'`
|
||||
totaldevs=`numdevs 'e4e4/11[3456][124]/*'`
|
||||
echo >&2 -- "Reseting devices [$totaldevs devices]"
|
||||
echo >&2 -- "Resetting devices [$totaldevs devices]"
|
||||
echo "$devices" | grep -v '^$' | while read id_str dev
|
||||
do
|
||||
(
|
||||
|
||||
@@ -64,7 +64,7 @@ sub do_select(@) {
|
||||
foreach my $xpd (@_) {
|
||||
my $xbus = $xpd->xbus;
|
||||
my $busnum = $xbus->name;
|
||||
die "Uknown bus name" unless $busnum;
|
||||
die "Unknown bus name" unless $busnum;
|
||||
$busnum =~ s/XBUS-//;
|
||||
die "bad bus name" unless $busnum =~ /^\d+$/;
|
||||
#printf "Setting sync: %-10s (%s)\n", $xpd->fqn, $xpd->type;
|
||||
|
||||
88
xpp/xtalk/Makefile.am
Normal file
88
xpp/xtalk/Makefile.am
Normal file
@@ -0,0 +1,88 @@
|
||||
VISIBILITY_DEFS = -DXTALK_DLL -DXTALK_DLL_EXPORTS
|
||||
COMMON_CFLAGS = \
|
||||
-Wall \
|
||||
-Wno-unknown-pragmas \
|
||||
-Werror \
|
||||
$(VISIBILITY_DEFS) \
|
||||
$(CFLAG_VISIBILITY)
|
||||
|
||||
AM_CFLAGS = $(COMMON_CFLAGS)
|
||||
|
||||
|
||||
if LIBUSBX
|
||||
USB_CFLAGS = $(LIBUSBX_CFLAGS)
|
||||
USB_LIBS = $(LIBUSBX_LIBS)
|
||||
USB_NAME = libusbx
|
||||
else
|
||||
if LIBUSB
|
||||
USB_CFLAGS = $(LIBUSB_CFLAGS)
|
||||
USB_LIBS = $(LIBUSB_LIBS)
|
||||
USB_NAME = libusb
|
||||
endif
|
||||
endif
|
||||
|
||||
noinst_PROGRAMS = xlist_test xusb_test xusb_test_bypath xtalk_test xtalk_raw_test xtalk_send
|
||||
noinst_LTLIBRARIES = libxtalk.la
|
||||
dist_noinst_HEADERS = \
|
||||
xtalk_base.h \
|
||||
xusb_common.h \
|
||||
include/xtalk/proto_raw.h \
|
||||
include/xtalk/api_defs.h \
|
||||
include/xtalk/xlist.h \
|
||||
include/xtalk/proto_sync.h \
|
||||
include/xtalk/xusb_iface.h \
|
||||
include/xtalk/proto.h \
|
||||
include/xtalk/debug.h \
|
||||
include/xtalk/xusb.h \
|
||||
include/xtalk/firmware_defs.h \
|
||||
include/xtalk/xtalk_iface.h \
|
||||
#
|
||||
|
||||
libxtalk_la_CFLAGS = \
|
||||
$(COMMON_CFLAGS) \
|
||||
-I$(srcdir)/include \
|
||||
-I$(srcdir) \
|
||||
$(USB_CFLAGS) \
|
||||
-DXTALK_OPTIONS_FILE=\"/etc/dahdi/xpp.conf\"
|
||||
|
||||
libxtalk_la_LDFLAGS = #
|
||||
libxtalk_la_LIBADD = $(USB_LIBS)
|
||||
libxtalk_la_SOURCES = \
|
||||
$(dist_noinst_HEADERS) \
|
||||
xtalk_sync.c \
|
||||
xtalk_raw.c \
|
||||
xtalk_base.c \
|
||||
xlist.c \
|
||||
debug.c \
|
||||
xtalk-xusb.c \
|
||||
xusb_common.c
|
||||
if LIBUSBX
|
||||
libxtalk_la_SOURCES += xusb_libusbx.c
|
||||
else
|
||||
if LIBUSB
|
||||
libxtalk_la_SOURCES += xusb_libusb.c
|
||||
endif
|
||||
endif
|
||||
libxtalk_la_DEPENDENCIES = $(libxtalk_la_SOURCES)
|
||||
|
||||
xtalk_send_CFLAGS = $(COMMON_CFLAGS) -I$(srcdir)/include -I$(srcdir)
|
||||
xtalk_send_LDADD = libxtalk.la $(USB_LIBS)
|
||||
|
||||
xtalk_test_CFLAGS = $(COMMON_CFLAGS) -I$(srcdir)/include -I$(srcdir)
|
||||
xtalk_test_LDADD = libxtalk.la $(USB_LIBS)
|
||||
|
||||
xtalk_raw_test_CFLAGS = $(COMMON_CFLAGS) -I$(srcdir)/include -I$(srcdir)
|
||||
xtalk_raw_test_LDADD = libxtalk.la $(USB_LIBS)
|
||||
|
||||
xusb_test_CFLAGS = $(COMMON_CFLAGS) -I$(srcdir)/include -I$(srcdir)
|
||||
xusb_test_LDADD = libxtalk.la $(USB_LIBS)
|
||||
|
||||
xusb_test_bypath_CFLAGS = $(COMMON_CFLAGS) -I$(srcdir)/include -I$(srcdir)
|
||||
xusb_test_bypath_LDADD = libxtalk.la $(USB_LIBS)
|
||||
|
||||
xlist_test_CFLAGS = $(COMMON_CFLAGS) -I$(srcdir)/include -I$(srcdir)
|
||||
xlist_test_LDADD = libxtalk.la $(USB_LIBS)
|
||||
|
||||
DISTCLEANFILES = xtalk.pc xtalk-uninstalled.pc
|
||||
|
||||
EXTRA_DIST = $(man_MANS)
|
||||
@@ -27,7 +27,8 @@
|
||||
#include <stdarg.h>
|
||||
#include <syslog.h>
|
||||
#include <execinfo.h>
|
||||
#include <debug.h>
|
||||
#include <xtalk/debug.h>
|
||||
#include <autoconfig.h>
|
||||
|
||||
int verbose = LOG_INFO;
|
||||
int debug_mask;
|
||||
|
||||
38
xpp/xtalk/include/xtalk/api_defs.h
Normal file
38
xpp/xtalk/include/xtalk/api_defs.h
Normal file
@@ -0,0 +1,38 @@
|
||||
#ifndef XTALK_API_DEFS_H
|
||||
#define XTALK_API_DEFS_H
|
||||
|
||||
/*
|
||||
* Visibility settings: taken from:
|
||||
* http://gcc.gnu.org/wiki/Visibility
|
||||
*/
|
||||
|
||||
/* Generic helper definitions for shared library support */
|
||||
#if __GNUC__ >= 4
|
||||
#define XTALK_HELPER_DLL_IMPORT __attribute__ ((visibility ("default")))
|
||||
#define XTALK_HELPER_DLL_EXPORT __attribute__ ((visibility ("default")))
|
||||
#define XTALK_HELPER_DLL_LOCAL __attribute__ ((visibility ("hidden")))
|
||||
#else
|
||||
#define XTALK_HELPER_DLL_IMPORT
|
||||
#define XTALK_HELPER_DLL_EXPORT
|
||||
#define XTALK_HELPER_DLL_LOCAL
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Now we use the generic helper definitions above to define XTALK_API and XTALK_LOCAL.
|
||||
* XTALK_API is used for the public API symbols. It either DLL imports or DLL exports (or does nothing for static build)
|
||||
* XTALK_LOCAL is used for non-api symbols.
|
||||
*/
|
||||
|
||||
#ifdef XTALK_DLL /* defined if XTALK is compiled as a DLL */
|
||||
#ifdef XTALK_DLL_EXPORTS /* defined if we are building the XTALK DLL (instead of using it) */
|
||||
#define XTALK_API XTALK_HELPER_DLL_EXPORT
|
||||
#else
|
||||
#define XTALK_API XTALK_HELPER_DLL_IMPORT
|
||||
#endif /* XTALK_DLL_EXPORTS */
|
||||
#define XTALK_LOCAL XTALK_HELPER_DLL_LOCAL
|
||||
#else /* XTALK_DLL is not defined: this means XTALK is a static lib. */
|
||||
#define XTALK_API
|
||||
#define XTALK_LOCAL
|
||||
#endif /* XTALK_DLL */
|
||||
|
||||
#endif /* XTALK_API_DEFS_H */
|
||||
53
xpp/xtalk/include/xtalk/debug.h
Normal file
53
xpp/xtalk/include/xtalk/debug.h
Normal file
@@ -0,0 +1,53 @@
|
||||
#ifndef DEBUG_H
|
||||
#define DEBUG_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 <syslog.h>
|
||||
#include <stdio.h>
|
||||
#include <xtalk/api_defs.h>
|
||||
|
||||
/*
|
||||
* Each module should define a unique DBG_MASK
|
||||
*/
|
||||
|
||||
XTALK_API extern int verbose;
|
||||
XTALK_API extern int debug_mask;
|
||||
|
||||
/*
|
||||
* Logging
|
||||
*/
|
||||
XTALK_API void log_function(int level, int mask, const char *msg, ...)
|
||||
__attribute__((format(printf, 3, 4)));
|
||||
|
||||
#define ERR(fmt, arg...) log_function(LOG_ERR, 0, "%s:%d: ERROR(%s): " fmt, \
|
||||
__FILE__, __LINE__, __func__, ## arg)
|
||||
#define WARN(fmt, arg...) log_function(LOG_WARNING, 0, "WARNING: " fmt, ## arg)
|
||||
#define INFO(fmt, arg...) log_function(LOG_INFO, 0, "INFO: " fmt, ## arg)
|
||||
#define DBG(fmt, arg...) log_function(LOG_DEBUG, DBG_MASK, \
|
||||
"%s:%d: DBG(%s): " fmt, __FILE__, __LINE__, __func__, ## arg)
|
||||
|
||||
XTALK_API void dump_packet(int loglevel, int mask, const char *msg,
|
||||
const char *buf, int len);
|
||||
XTALK_API void print_backtrace(FILE *fp);
|
||||
|
||||
#endif /* DEBUG_H */
|
||||
@@ -1,5 +1,5 @@
|
||||
#ifndef XTALK_DEFS_H
|
||||
#define XTALK_DEFS_H
|
||||
#ifndef XTALK_FIRMWARE_DEFS_H
|
||||
#define XTALK_FIRMWARE_DEFS_H
|
||||
|
||||
#define MAX_OPS 256 /* single byte */
|
||||
#define MAX_STATUS 256 /* single byte */
|
||||
@@ -8,18 +8,17 @@
|
||||
|
||||
#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 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 0x0E /* Get EEPROM table contents Product/Vendor Id ... */
|
||||
#define XTALK_CAPS_GET_REPLY (XTALK_CAPS_GET | XTALK_REPLY_MASK)
|
||||
|
||||
/*------------- XTALK: statuses in ACK ---------------------------------------*/
|
||||
@@ -38,4 +37,4 @@
|
||||
#define STAT_NOPWR_ERR 0x10 /* No power on USB connector */
|
||||
|
||||
|
||||
#endif /* XTALK_DEFS_H */
|
||||
#endif /* XTALK_FIRMWARE_DEFS_H */
|
||||
@@ -1,5 +1,5 @@
|
||||
#ifndef XTALK_H
|
||||
#define XTALK_H
|
||||
#ifndef XTALK_PROTO_H
|
||||
#define XTALK_PROTO_H
|
||||
/*
|
||||
* Written by Oron Peled <oron@actcom.co.il>
|
||||
* Copyright (C) 2009, Xorcom
|
||||
@@ -35,8 +35,8 @@ extern "C"
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdlib.h>
|
||||
/* Definitions common to the firmware (in include/ directory) */
|
||||
#include <xtalk_defs.h>
|
||||
#include <xtalk/api_defs.h>
|
||||
#include <xtalk/firmware_defs.h>
|
||||
|
||||
#ifdef __GNUC__
|
||||
#define PACKED __attribute__((packed))
|
||||
@@ -44,18 +44,25 @@ extern "C"
|
||||
#error "We do not know how your compiler packs structures"
|
||||
#endif
|
||||
|
||||
struct xtalk_device;
|
||||
struct xtalk_base;
|
||||
struct xtalk_command_desc;
|
||||
struct xtalk_command;
|
||||
|
||||
/*
|
||||
* Callbacks should return negative errno's
|
||||
* in case of errors.
|
||||
* They are called from process_command() and their
|
||||
* return values are propagated back.
|
||||
*/
|
||||
typedef int (*xtalk_cmd_callback_t)(
|
||||
struct xtalk_device *xtalk_dev,
|
||||
struct xtalk_command_desc *xtalk_cmd);
|
||||
const struct xtalk_base *xtalk_base,
|
||||
const struct xtalk_command_desc *cmd_desc,
|
||||
struct xtalk_command *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 */
|
||||
};
|
||||
|
||||
@@ -102,12 +109,13 @@ struct xtalk_command {
|
||||
__VA_ARGS__ \
|
||||
} PACKED XTALK_STRUCT(p, o)
|
||||
#define MEMBER(p, o) struct XTALK_STRUCT(p, o) XTALK_STRUCT(p, o)
|
||||
#define XTALK_OP(p, o) (p ## _ ## o)
|
||||
|
||||
/* Wrappers for transport (xusb) functions */
|
||||
struct xtalk_ops {
|
||||
int (*send_func)(void *transport_priv, void *data, size_t len,
|
||||
int (*send_func)(void *transport_priv, const char *data, size_t len,
|
||||
int timeout);
|
||||
int (*recv_func)(void *transport_priv, void *data, size_t maxlen,
|
||||
int (*recv_func)(void *transport_priv, char *data, size_t maxlen,
|
||||
int timeout);
|
||||
int (*close_func)(void *transport_priv);
|
||||
};
|
||||
@@ -117,38 +125,39 @@ struct xtalk_ops {
|
||||
* should be included in the struct representing
|
||||
* the dialect.
|
||||
*/
|
||||
struct xtalk_device;
|
||||
struct xtalk_base;
|
||||
struct xusb_iface;
|
||||
|
||||
/* 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);
|
||||
XTALK_API struct xtalk_base *xtalk_base_new_on_xusb(struct xusb_iface *xusb_iface);
|
||||
XTALK_API struct xtalk_base *xtalk_base_new(const struct xtalk_ops *ops,
|
||||
size_t packet_size, void *priv);
|
||||
XTALK_API void xtalk_base_delete(struct xtalk_base *xtalk_base);
|
||||
XTALK_API struct xusb_iface *xusb_iface_of_xtalk_base(const struct xtalk_base *xtalk_base);
|
||||
XTALK_API const char *xtalk_protocol_name(const struct xtalk_base *dev);
|
||||
XTALK_API int xtalk_cmd_callback(struct xtalk_base *xtalk_base, int op,
|
||||
xtalk_cmd_callback_t callback,
|
||||
xtalk_cmd_callback_t *old_callback);
|
||||
XTALK_API void xtalk_dump_command(struct xtalk_command *cmd);
|
||||
XTALK_API int xtalk_set_timeout(struct xtalk_base *dev, int new_timeout);
|
||||
|
||||
/* 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,
|
||||
XTALK_API const char *ack_status_msg(const struct xtalk_protocol *xproto,
|
||||
uint8_t status);
|
||||
XTALK_API struct xtalk_command *new_command(
|
||||
const struct xtalk_base *xtalk_base,
|
||||
uint8_t op, uint16_t extra_data);
|
||||
void free_command(struct xtalk_command *cmd);
|
||||
XTALK_API 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) \
|
||||
#define CMD_RECV(p, o) \
|
||||
[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)), \
|
||||
@@ -158,7 +167,6 @@ void free_command(struct xtalk_command *cmd);
|
||||
[p ## _ ## o] = { \
|
||||
.op = (p ## _ ## o), \
|
||||
.name = (#o), \
|
||||
.callback = NULL, \
|
||||
.len = \
|
||||
sizeof(struct xtalk_header) + \
|
||||
sizeof(struct XTALK_STRUCT(p, o)), \
|
||||
@@ -175,4 +183,4 @@ void free_command(struct xtalk_command *cmd);
|
||||
}
|
||||
#endif /* __cplusplus */
|
||||
|
||||
#endif /* XTALK_H */
|
||||
#endif /* XTALK_PROTO_H */
|
||||
76
xpp/xtalk/include/xtalk/proto_raw.h
Normal file
76
xpp/xtalk/include/xtalk/proto_raw.h
Normal file
@@ -0,0 +1,76 @@
|
||||
#ifndef XTALK_PROTO_RAW_H
|
||||
#define XTALK_PROTO_RAW_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 */
|
||||
|
||||
/*
|
||||
* XTALKSYNC - Base synchronous protocol for our USB devices
|
||||
* It is meant to provide a common base for layered
|
||||
* protocols (dialects)
|
||||
*/
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdlib.h>
|
||||
#include <xtalk/api_defs.h>
|
||||
#include <xtalk/proto.h>
|
||||
#include <xtalk/firmware_defs.h>
|
||||
|
||||
#ifdef __GNUC__
|
||||
#define PACKED __attribute__((packed))
|
||||
#else
|
||||
#error "We do not know how your compiler packs structures"
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Base XTALK device. A pointer to this struct
|
||||
* should be included in the struct representing
|
||||
* the dialect.
|
||||
*/
|
||||
struct xtalk_raw;
|
||||
struct xusb;
|
||||
|
||||
XTALK_API struct xtalk_raw *xtalk_raw_new(struct xtalk_base *xtalk_base);
|
||||
XTALK_API void xtalk_raw_delete(struct xtalk_raw *xraw);
|
||||
XTALK_API int xtalk_raw_set_protocol(struct xtalk_raw *xtalk_base,
|
||||
const struct xtalk_protocol *xproto);
|
||||
XTALK_API int xtalk_raw_cmd_recv(struct xtalk_raw *xraw,
|
||||
struct xtalk_command **reply_ref);
|
||||
XTALK_API int xtalk_raw_cmd_send(struct xtalk_raw *xraw, const char *buf, int len,
|
||||
uint16_t *tx_seq);
|
||||
|
||||
/*
|
||||
* These are low-level interfaces that receive/send arbitrary buffers
|
||||
* Be carefull, as that allow to send illegal Xtalk packets
|
||||
*/
|
||||
XTALK_API int xtalk_raw_buffer_recv(struct xtalk_raw *xraw, char *buf, int len);
|
||||
XTALK_API int xtalk_raw_buffer_send(struct xtalk_raw *xraw, const char *buf, int len);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif /* __cplusplus */
|
||||
|
||||
#endif /* XTALK_PROTO_RAW_H */
|
||||
75
xpp/xtalk/include/xtalk/proto_sync.h
Normal file
75
xpp/xtalk/include/xtalk/proto_sync.h
Normal file
@@ -0,0 +1,75 @@
|
||||
#ifndef XTALK_PROTO_SYNC_H
|
||||
#define XTALK_PROTO_SYNC_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.
|
||||
*
|
||||
*/
|
||||
|
||||
#include <xtalk/api_defs.h>
|
||||
#include <xtalk/proto.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C"
|
||||
{
|
||||
#endif /* __cplusplus */
|
||||
|
||||
/*
|
||||
* XTALKSYNC - Base synchronous protocol for our USB devices
|
||||
* It is meant to provide a common base for layered
|
||||
* protocols (dialects)
|
||||
*/
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdlib.h>
|
||||
#include <xtalk/firmware_defs.h>
|
||||
|
||||
#ifdef __GNUC__
|
||||
#define PACKED __attribute__((packed))
|
||||
#else
|
||||
#error "We do not know how your compiler packs structures"
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Base XTALK device. A pointer to this struct
|
||||
* should be included in the struct representing
|
||||
* the dialect.
|
||||
*/
|
||||
struct xtalk_sync;
|
||||
struct xusb;
|
||||
|
||||
/* high-level */
|
||||
XTALK_API struct xtalk_sync *xtalk_sync_new(struct xtalk_base *xtalk_base);
|
||||
XTALK_API void xtalk_sync_delete(struct xtalk_sync *xtalk_sync);
|
||||
XTALK_API int xtalk_sync_set_protocol(struct xtalk_sync *xtalk_base,
|
||||
const struct xtalk_protocol *xproto);
|
||||
XTALK_API int xtalk_proto_query(struct xtalk_sync *dev);
|
||||
|
||||
/* low-level */
|
||||
XTALK_API int process_command(
|
||||
struct xtalk_sync *dev,
|
||||
struct xtalk_command *cmd,
|
||||
struct xtalk_command **reply_ref,
|
||||
uint16_t *sequence_number);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif /* __cplusplus */
|
||||
|
||||
#endif /* XTALK_PROTO_SYNC_H */
|
||||
32
xpp/xtalk/include/xtalk/xlist.h
Normal file
32
xpp/xtalk/include/xtalk/xlist.h
Normal file
@@ -0,0 +1,32 @@
|
||||
#ifndef XLIST_H
|
||||
#define XLIST_H
|
||||
|
||||
#include <xtalk/api_defs.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C"
|
||||
{
|
||||
#endif /* __cplusplus */
|
||||
|
||||
struct xlist_node {
|
||||
void *data;
|
||||
struct xlist_node *next;
|
||||
struct xlist_node *prev;
|
||||
};
|
||||
|
||||
typedef void (*xlist_destructor_t)(void *data);
|
||||
|
||||
XTALK_API struct xlist_node *xlist_new(void *data);
|
||||
XTALK_API void xlist_destroy(struct xlist_node *list, xlist_destructor_t destructor);
|
||||
XTALK_API void xlist_append_list(struct xlist_node *list1, struct xlist_node *list2);
|
||||
XTALK_API void xlist_append_item(struct xlist_node *list, struct xlist_node *item);
|
||||
XTALK_API void xlist_remove_item(struct xlist_node *item);
|
||||
XTALK_API struct xlist_node *xlist_shift(struct xlist_node *list);
|
||||
XTALK_API int xlist_empty(const struct xlist_node *list);
|
||||
XTALK_API size_t xlist_length(const struct xlist_node *list);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif /* __cplusplus */
|
||||
|
||||
#endif /* XLIST_H */
|
||||
19
xpp/xtalk/include/xtalk/xtalk_iface.h
Normal file
19
xpp/xtalk/include/xtalk/xtalk_iface.h
Normal file
@@ -0,0 +1,19 @@
|
||||
/*
|
||||
* Wrappers for swig/python integration
|
||||
*/
|
||||
|
||||
struct Command {
|
||||
struct xtalk_command *command;
|
||||
};
|
||||
|
||||
struct Xtalksync {
|
||||
struct xtalk_base *xtalk_base;
|
||||
struct xtalk_sync *xtalk_sync;
|
||||
struct XusbIface *py_xusb_iface;
|
||||
};
|
||||
|
||||
struct Xtalkraw {
|
||||
struct xtalk_base *xtalk_base;
|
||||
struct xtalk_raw *xtalk_raw;
|
||||
struct XusbIface *py_xusb_iface;
|
||||
};
|
||||
115
xpp/xtalk/include/xtalk/xusb.h
Normal file
115
xpp/xtalk/include/xtalk/xusb.h
Normal file
@@ -0,0 +1,115 @@
|
||||
#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 <xtalk/api_defs.h>
|
||||
#include <xtalk/xlist.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C"
|
||||
{
|
||||
#endif /* __cplusplus */
|
||||
|
||||
/*
|
||||
* Xorcom usb handling
|
||||
*/
|
||||
|
||||
#define PACKET_SIZE 512
|
||||
|
||||
/*
|
||||
* Specify the wanted device
|
||||
*/
|
||||
struct xusb_spec {
|
||||
char *name; /* For debug/output purpose */
|
||||
/* What we will actually use */
|
||||
uint16_t vendor_id;
|
||||
uint16_t product_id;
|
||||
};
|
||||
|
||||
#define SPEC_HEAD(vendor_id_, product_id_, name_) \
|
||||
{ \
|
||||
.name = (name_), \
|
||||
.vendor_id = (vendor_id_), \
|
||||
.product_id = (product_id_), \
|
||||
}
|
||||
|
||||
XTALK_API void xusb_init_spec(struct xusb_spec *xusb_spec,
|
||||
char *name, uint16_t vendor_id, uint16_t product_id);
|
||||
|
||||
struct xusb_device;
|
||||
struct xusb_iface;
|
||||
|
||||
/*
|
||||
* Prototypes
|
||||
*/
|
||||
typedef int (*xusb_filter_t)(const struct xusb_device *xusb_device, void *data);
|
||||
XTALK_API struct xlist_node *xusb_find_byproduct(const struct xusb_spec *specs,
|
||||
int numspecs, xusb_filter_t filterfunc, void *data);
|
||||
XTALK_API struct xusb_device *xusb_find_bypath(const char *path);
|
||||
XTALK_API struct xusb_iface *xusb_open_one(const struct xusb_spec *specs, int numspecs,
|
||||
int interface_num,
|
||||
xusb_filter_t filterfunc, void *data);
|
||||
|
||||
/*
|
||||
* A convenience filter
|
||||
*/
|
||||
XTALK_API int xusb_filter_bypath(const struct xusb_device *xusb_device, void *data);
|
||||
|
||||
/* Device management */
|
||||
XTALK_API const struct xusb_spec *xusb_spec(const struct xusb_device *xusb_device);
|
||||
XTALK_API void xusb_destroy(struct xusb_device *xusb_device);
|
||||
XTALK_API size_t xusb_packet_size(const struct xusb_device *xusb_device);
|
||||
XTALK_API void xusb_showinfo(const struct xusb_device *xusb_device);
|
||||
XTALK_API const char *xusb_serial(const struct xusb_device *xusb_device);
|
||||
XTALK_API const char *xusb_manufacturer(const struct xusb_device *xusb_device);
|
||||
XTALK_API const char *xusb_product(const struct xusb_device *xusb_device);
|
||||
XTALK_API uint16_t xusb_bus_num(const struct xusb_device *xusb_device);
|
||||
XTALK_API uint16_t xusb_device_num(const struct xusb_device *xusb_device);
|
||||
XTALK_API uint16_t xusb_vendor_id(const struct xusb_device *xusb_device);
|
||||
XTALK_API uint16_t xusb_product_id(const struct xusb_device *xusb_device);
|
||||
XTALK_API const char *xusb_devpath(const struct xusb_device *xusb_device);
|
||||
XTALK_API const struct xusb_spec *xusb_device_spec(const struct xusb_device *xusb_device);
|
||||
XTALK_API struct xusb_iface *xusb_find_iface(const char *devpath,
|
||||
int iface_num,
|
||||
int ep_out,
|
||||
int ep_in,
|
||||
struct xusb_spec *dummy_spec);
|
||||
XTALK_API int xusb_claim(struct xusb_device *xusb_device, unsigned int interface_num,
|
||||
struct xusb_iface **iface);
|
||||
XTALK_API void xusb_release(struct xusb_iface *iface);
|
||||
XTALK_API int xusb_is_claimed(struct xusb_iface *iface);
|
||||
XTALK_API struct xusb_iface *xusb_interface_of(const struct xusb_device *dev, int num);
|
||||
XTALK_API struct xusb_device *xusb_deviceof(struct xusb_iface *iface);
|
||||
XTALK_API const char *xusb_interface_name(const struct xusb_iface *iface);
|
||||
XTALK_API int xusb_interface_num(const struct xusb_iface *iface);
|
||||
XTALK_API int xusb_send(struct xusb_iface *iface, const char *buf, int len, int timeout);
|
||||
XTALK_API int xusb_recv(struct xusb_iface *iface, char *buf, size_t len, int timeout);
|
||||
XTALK_API int xusb_flushread(struct xusb_iface *iface);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif /* __cplusplus */
|
||||
|
||||
#endif /* XUSB_H */
|
||||
43
xpp/xtalk/include/xtalk/xusb_iface.h
Normal file
43
xpp/xtalk/include/xtalk/xusb_iface.h
Normal file
@@ -0,0 +1,43 @@
|
||||
/*
|
||||
* Wrappers for swig/python integration
|
||||
*/
|
||||
|
||||
#ifdef SWIG
|
||||
%feature("docstring", "Represents the specification of wanted USB device") Spec;
|
||||
#endif
|
||||
struct Spec {
|
||||
#ifdef SWIG
|
||||
%immutable spec;
|
||||
%immutable ref_count;
|
||||
#endif
|
||||
struct xusb_spec *spec;
|
||||
int ref_count;
|
||||
};
|
||||
|
||||
#ifdef SWIG
|
||||
%feature("docstring", "Represents a single USB device") XusbDev;
|
||||
#endif
|
||||
struct XusbDev {
|
||||
#ifdef SWIG
|
||||
%immutable spec;
|
||||
%immutable xusb_device;
|
||||
%immutable ref_count;
|
||||
#endif
|
||||
struct Spec *spec_wrapper;
|
||||
struct xusb_device *xusb_device;
|
||||
int ref_count;
|
||||
};
|
||||
|
||||
#ifdef SWIG
|
||||
%feature("docstring", "Represents a single USB interface") XusbIface;
|
||||
#endif
|
||||
struct XusbIface {
|
||||
#ifdef SWIG
|
||||
%immutable dev_wrapper;
|
||||
%immutable iface;
|
||||
#endif
|
||||
struct XusbDev *dev_wrapper; /* for ref-counting */
|
||||
struct xusb_iface *iface;
|
||||
};
|
||||
|
||||
|
||||
@@ -1,7 +1,8 @@
|
||||
#include <assert.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <xlist.h>
|
||||
#include <xtalk/xlist.h>
|
||||
#include <autoconfig.h>
|
||||
|
||||
struct xlist_node *xlist_new(void *data)
|
||||
{
|
||||
@@ -36,6 +37,17 @@ void xlist_destroy(struct xlist_node *list, xlist_destructor_t destructor)
|
||||
free(list);
|
||||
}
|
||||
|
||||
void xlist_append_list(struct xlist_node *list1, struct xlist_node *list2)
|
||||
{
|
||||
struct xlist_node *curr;
|
||||
|
||||
assert(list1);
|
||||
assert(list2);
|
||||
|
||||
while ((curr = xlist_shift(list2)) != NULL)
|
||||
xlist_append_item(list1, curr);
|
||||
}
|
||||
|
||||
void xlist_append_item(struct xlist_node *list, struct xlist_node *item)
|
||||
{
|
||||
assert(list);
|
||||
|
||||
73
xpp/xtalk/xlist_test.c
Normal file
73
xpp/xtalk/xlist_test.c
Normal file
@@ -0,0 +1,73 @@
|
||||
#include <assert.h>
|
||||
#include <stdio.h>
|
||||
#include <xtalk/xlist.h>
|
||||
#include <autoconfig.h>
|
||||
|
||||
void dump_list(const struct xlist_node *list)
|
||||
{
|
||||
struct xlist_node *curr;
|
||||
const char *p;
|
||||
int len;
|
||||
|
||||
len = xlist_length(list);
|
||||
p = list->data;
|
||||
printf("dumping list: %s[%d]\n", p, len);
|
||||
for (curr = list->next; curr != list; curr = curr->next) {
|
||||
p = curr->data;
|
||||
printf("> %s\n", p);
|
||||
}
|
||||
}
|
||||
|
||||
void string_destructor(void *data)
|
||||
{
|
||||
const char *p = data;
|
||||
|
||||
printf("destroy: '%s'\n", p);
|
||||
}
|
||||
|
||||
int main()
|
||||
{
|
||||
struct xlist_node *list1;
|
||||
struct xlist_node *list2;
|
||||
struct xlist_node *list3;
|
||||
struct xlist_node *item1;
|
||||
struct xlist_node *item2;
|
||||
struct xlist_node *item3;
|
||||
|
||||
list1 = xlist_new("list1");
|
||||
list2 = xlist_new("list2");
|
||||
list3 = xlist_new("list3");
|
||||
item1 = xlist_new("item1");
|
||||
item2 = xlist_new("item2");
|
||||
item3 = xlist_new("item3");
|
||||
assert(xlist_empty(list1));
|
||||
assert(xlist_empty(list2));
|
||||
assert(xlist_empty(list3));
|
||||
assert(xlist_empty(item1));
|
||||
assert(xlist_empty(item2));
|
||||
assert(xlist_empty(item3));
|
||||
dump_list(list1);
|
||||
dump_list(list2);
|
||||
xlist_append_item(list1, item1);
|
||||
assert(!xlist_empty(list1));
|
||||
xlist_append_item(list1, item2);
|
||||
xlist_append_item(list1, item3);
|
||||
dump_list(list1);
|
||||
xlist_remove_item(item2);
|
||||
assert(!xlist_empty(list1));
|
||||
xlist_append_item(list2, item2);
|
||||
assert(!xlist_empty(list2));
|
||||
dump_list(list1);
|
||||
dump_list(list2);
|
||||
xlist_shift(list1);
|
||||
dump_list(list1);
|
||||
xlist_append_list(list1, list2);
|
||||
dump_list(list1);
|
||||
xlist_append_item(list3, item1);
|
||||
xlist_append_list(list1, list3);
|
||||
dump_list(list1);
|
||||
xlist_destroy(list1, string_destructor);
|
||||
xlist_destroy(list2, string_destructor);
|
||||
xlist_destroy(list3, string_destructor);
|
||||
return 0;
|
||||
}
|
||||
70
xpp/xtalk/xtalk-xusb.c
Normal file
70
xpp/xtalk/xtalk-xusb.c
Normal file
@@ -0,0 +1,70 @@
|
||||
/*
|
||||
* Written by Oron Peled <oron@actcom.co.il>
|
||||
* Copyright (C) 2012, 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.
|
||||
*
|
||||
*/
|
||||
|
||||
/*
|
||||
* Convenience wrappers for xtalk_base over xusb
|
||||
*/
|
||||
#include <assert.h>
|
||||
#include <xtalk/debug.h>
|
||||
#include <xtalk/xusb.h>
|
||||
#include <autoconfig.h>
|
||||
#include "xtalk_base.h"
|
||||
|
||||
static inline int close_func(void *priv)
|
||||
{
|
||||
struct xusb_iface *iface = (struct xusb_iface *)priv;
|
||||
xusb_release(iface);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline int send_func(void *priv, const char *data, size_t len, int timeout)
|
||||
{
|
||||
return xusb_send((struct xusb_iface *)priv, data, len, timeout);
|
||||
}
|
||||
|
||||
static inline int recv_func(void *priv, char *data, size_t maxlen, int timeout)
|
||||
{
|
||||
return xusb_recv((struct xusb_iface *)priv, data, maxlen, timeout);
|
||||
}
|
||||
|
||||
|
||||
static struct xtalk_ops xtalk_ops = {
|
||||
.send_func = send_func,
|
||||
.recv_func = recv_func,
|
||||
.close_func = close_func,
|
||||
};
|
||||
|
||||
struct xtalk_base *xtalk_base_new_on_xusb(struct xusb_iface *xusb_iface)
|
||||
{
|
||||
struct xtalk_base *xtalk_base;
|
||||
int packet_size;
|
||||
|
||||
assert(xusb_iface);
|
||||
packet_size = xusb_packet_size(xusb_deviceof(xusb_iface));
|
||||
|
||||
xtalk_base = xtalk_base_new(&xtalk_ops, packet_size, xusb_iface);
|
||||
if (!xtalk_base) {
|
||||
ERR("Failed creating the xtalk device abstraction\n");
|
||||
return NULL;
|
||||
}
|
||||
return xtalk_base;
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
350
xpp/xtalk/xtalk_base.c
Normal file
350
xpp/xtalk/xtalk_base.c
Normal file
@@ -0,0 +1,350 @@
|
||||
/*
|
||||
* 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/debug.h>
|
||||
#include <autoconfig.h>
|
||||
#include "xtalk_base.h"
|
||||
|
||||
#define DBG_MASK 0x02
|
||||
|
||||
void free_command(struct xtalk_command *cmd)
|
||||
{
|
||||
if (!cmd)
|
||||
return;
|
||||
memset(cmd, 0, cmd->header.len);
|
||||
free(cmd);
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
const char *xtalk_protocol_name(const struct xtalk_base *xtalk_base)
|
||||
{
|
||||
const struct xtalk_protocol *xproto;
|
||||
|
||||
xproto = &xtalk_base->xproto;
|
||||
return (xproto) ? xproto->name : "";
|
||||
}
|
||||
|
||||
int xtalk_set_protocol(struct xtalk_base *xtalk_base,
|
||||
const struct xtalk_protocol *xproto_base,
|
||||
const struct xtalk_protocol *xproto)
|
||||
{
|
||||
const char *protoname = (xproto) ? xproto->name : "GLOBAL";
|
||||
int i;
|
||||
|
||||
DBG("%s\n", protoname);
|
||||
memset(&xtalk_base->xproto, 0, sizeof(xtalk_base->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_base->xproto.commands[i] = *desc;
|
||||
DBG("private: op=0x%X (%s)\n", i, desc->name);
|
||||
} else {
|
||||
if (!IS_PRIVATE_OP(i)) {
|
||||
const char *name;
|
||||
|
||||
xtalk_base->xproto.commands[i] =
|
||||
xproto_base->commands[i];
|
||||
name = xtalk_base->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) {
|
||||
xtalk_base->xproto.ack_statuses[i] = stat_msg;
|
||||
DBG("private: status=0x%X (%s)\n", i, stat_msg);
|
||||
} else {
|
||||
const char *global_msg;
|
||||
|
||||
xtalk_base->xproto.ack_statuses[i] =
|
||||
xproto_base->ack_statuses[i];
|
||||
global_msg = xtalk_base->xproto.ack_statuses[i];
|
||||
if (global_msg)
|
||||
DBG("global: status=0x%X (%s)\n",
|
||||
i, global_msg);
|
||||
}
|
||||
}
|
||||
xtalk_base->xproto.name = protoname;
|
||||
xtalk_base->xproto.proto_version = (xproto) ? xproto->proto_version : 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int xtalk_cmd_callback(struct xtalk_base *xtalk_base, int op,
|
||||
xtalk_cmd_callback_t callback,
|
||||
xtalk_cmd_callback_t *old_callback)
|
||||
{
|
||||
const struct xtalk_protocol *xproto;
|
||||
const struct xtalk_command_desc *desc;
|
||||
|
||||
xproto = &xtalk_base->xproto;
|
||||
desc = get_command_desc(xproto, op);
|
||||
if (!desc)
|
||||
DBG("Unknown op=0x%X.\n", op);
|
||||
if (old_callback)
|
||||
*old_callback = xtalk_base->callbacks[op];
|
||||
if (callback) {
|
||||
xtalk_base->callbacks[op] = callback;
|
||||
DBG("OP=0x%X [%s] -- set callback to %p\n",
|
||||
op,
|
||||
(desc) ? desc->name : "",
|
||||
callback);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
struct xtalk_command *new_command(
|
||||
const struct xtalk_base *xtalk_base,
|
||||
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_base->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]);
|
||||
}
|
||||
|
||||
int xtalk_set_timeout(struct xtalk_base *dev, int new_timeout)
|
||||
{
|
||||
int old_timeout = dev->default_timeout;
|
||||
dev->default_timeout = new_timeout;
|
||||
return old_timeout;
|
||||
}
|
||||
|
||||
int send_buffer(struct xtalk_base *xtalk_base, const char *buf, int len)
|
||||
{
|
||||
int ret;
|
||||
void *priv = xtalk_base->transport_priv;
|
||||
int timeout = xtalk_base->default_timeout;
|
||||
|
||||
ret = xtalk_base->ops.send_func(priv, buf, len, timeout);
|
||||
if (ret < 0)
|
||||
DBG("%s: failed ret=%d\n", __func__, ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
int recv_buffer(struct xtalk_base *xtalk_base, char *buf, int len)
|
||||
{
|
||||
void *priv = xtalk_base->transport_priv;
|
||||
int timeout = xtalk_base->default_timeout;
|
||||
int ret;
|
||||
|
||||
ret = xtalk_base->ops.recv_func(priv, buf, len, timeout);
|
||||
if (ret < 0) {
|
||||
DBG("Receive from usb failed (ret=%d)\n", ret);
|
||||
goto out;
|
||||
} else if (ret == 0) {
|
||||
DBG("No reply\n");
|
||||
goto out; /* No reply */
|
||||
}
|
||||
DBG("Received %d bytes\n", ret);
|
||||
out:
|
||||
return ret;
|
||||
}
|
||||
|
||||
int send_command(struct xtalk_base *xtalk_base,
|
||||
struct xtalk_command *cmd, uint16_t *tx_seq)
|
||||
{
|
||||
int ret;
|
||||
int len;
|
||||
|
||||
len = cmd->header.len;
|
||||
cmd->header.seq = xtalk_base->tx_sequenceno;
|
||||
ret = send_buffer(xtalk_base, (const char *)cmd, len);
|
||||
if (ret < 0)
|
||||
DBG("%s: failed ret=%d\n", __func__, ret);
|
||||
else if (tx_seq)
|
||||
*tx_seq = xtalk_base->tx_sequenceno++;
|
||||
return ret;
|
||||
}
|
||||
|
||||
int recv_command(struct xtalk_base *xtalk_base,
|
||||
struct xtalk_command **reply_ref)
|
||||
{
|
||||
struct xtalk_command *reply;
|
||||
size_t psize = xtalk_base->packet_size;
|
||||
int ret;
|
||||
|
||||
reply = malloc(psize);
|
||||
if (!reply) {
|
||||
ERR("Out of memory\n");
|
||||
ret = -ENOMEM;
|
||||
goto err;
|
||||
}
|
||||
reply->header.len = 0;
|
||||
ret = recv_buffer(xtalk_base, (char *)reply, psize);
|
||||
if (ret < 0) {
|
||||
DBG("%s: calling recv_buffer() failed (ret=%d)\n", __func__, ret);
|
||||
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); */
|
||||
*reply_ref = reply;
|
||||
return ret;
|
||||
err:
|
||||
if (reply) {
|
||||
memset(reply, 0, psize);
|
||||
free_command(reply);
|
||||
*reply_ref = NULL;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*
|
||||
* Wrappers
|
||||
*/
|
||||
|
||||
struct xtalk_base *xtalk_base_new(const struct xtalk_ops *ops,
|
||||
size_t packet_size, void *priv)
|
||||
{
|
||||
struct xtalk_base *xtalk_base;
|
||||
|
||||
DBG("\n");
|
||||
assert(ops != NULL);
|
||||
xtalk_base = calloc(1, sizeof(*xtalk_base));
|
||||
if (!xtalk_base) {
|
||||
ERR("Allocating XTALK device memory failed\n");
|
||||
return NULL;
|
||||
}
|
||||
memcpy((void *)&xtalk_base->ops, (const void *)ops,
|
||||
sizeof(xtalk_base->ops));
|
||||
xtalk_base->packet_size = packet_size;
|
||||
xtalk_base->transport_priv = priv;
|
||||
xtalk_base->tx_sequenceno = 1;
|
||||
xtalk_base->default_timeout = 2000; /* millies */
|
||||
return xtalk_base;
|
||||
}
|
||||
|
||||
void xtalk_base_delete(struct xtalk_base *xtalk_base)
|
||||
{
|
||||
void *priv;
|
||||
|
||||
if (!xtalk_base)
|
||||
return;
|
||||
DBG("\n");
|
||||
priv = xtalk_base->transport_priv;
|
||||
assert(priv);
|
||||
xtalk_base->tx_sequenceno = 0;
|
||||
assert(&xtalk_base->ops != NULL);
|
||||
assert(&xtalk_base->ops.close_func != NULL);
|
||||
xtalk_base->ops.close_func(priv);
|
||||
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;
|
||||
}
|
||||
73
xpp/xtalk/xtalk_base.h
Normal file
73
xpp/xtalk/xtalk_base.h
Normal file
@@ -0,0 +1,73 @@
|
||||
#ifndef XTALK_BASE_H
|
||||
#define XTALK_BASE_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.
|
||||
*
|
||||
*/
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdlib.h>
|
||||
#include <xtalk/proto.h>
|
||||
#include <xtalk/firmware_defs.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C"
|
||||
{
|
||||
#endif /* __cplusplus */
|
||||
|
||||
/*
|
||||
* Base XTALK device. A pointer to this struct
|
||||
* should be included in the struct representing
|
||||
* the dialect.
|
||||
*/
|
||||
struct xtalk_base {
|
||||
void *transport_priv; /* e.g: struct xusb */
|
||||
struct xtalk_ops ops;
|
||||
struct xtalk_protocol xproto;
|
||||
xtalk_cmd_callback_t callbacks[MAX_OPS];
|
||||
uint8_t xtalk_proto_version;
|
||||
uint8_t status;
|
||||
size_t packet_size;
|
||||
uint16_t tx_sequenceno;
|
||||
int default_timeout; /* in millies */
|
||||
};
|
||||
|
||||
int xtalk_set_protocol(struct xtalk_base *xtalk_base,
|
||||
const struct xtalk_protocol *xproto_base,
|
||||
const struct xtalk_protocol *xproto);
|
||||
const struct xtalk_command_desc *get_command_desc(
|
||||
const struct xtalk_protocol *xproto, uint8_t op);
|
||||
int send_command(struct xtalk_base *xtalk_base,
|
||||
struct xtalk_command *cmd, uint16_t *tx_seq);
|
||||
int recv_command(struct xtalk_base *xtalk_base,
|
||||
struct xtalk_command **reply_ref);
|
||||
|
||||
/*
|
||||
* These are low-level interfaces that receive/send arbitrary buffers
|
||||
* Be carefull, as that allow to send illegal Xtalk packets
|
||||
*/
|
||||
int send_buffer(struct xtalk_base *xtalk_base, const char *buf, int len);
|
||||
int recv_buffer(struct xtalk_base *xtalk_base, char *buf, int len);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif /* __cplusplus */
|
||||
|
||||
#endif /* XTALK_BASE_H */
|
||||
221
xpp/xtalk/xtalk_raw.c
Normal file
221
xpp/xtalk/xtalk_raw.c
Normal file
@@ -0,0 +1,221 @@
|
||||
/*
|
||||
* 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/debug.h>
|
||||
#include <xtalk/proto_raw.h>
|
||||
#include <autoconfig.h>
|
||||
#include "xtalk_base.h"
|
||||
|
||||
#define DBG_MASK 0x02
|
||||
|
||||
/*
|
||||
* Base XTALK device. A pointer to this struct
|
||||
* should be included in the struct representing
|
||||
* the dialect.
|
||||
*/
|
||||
struct xtalk_raw {
|
||||
struct xtalk_base *xtalk_base;
|
||||
};
|
||||
|
||||
CMD_DEF(XTALK, ACK,
|
||||
uint8_t stat;
|
||||
);
|
||||
|
||||
union XTALK_PDATA(XTALK) {
|
||||
MEMBER(XTALK, ACK);
|
||||
} PACKED members;
|
||||
|
||||
const struct xtalk_protocol xtalk_raw_proto = {
|
||||
.name = "XTALK-RAW",
|
||||
.proto_version = 0,
|
||||
.commands = {
|
||||
CMD_RECV(XTALK, ACK),
|
||||
},
|
||||
.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"),
|
||||
}
|
||||
};
|
||||
|
||||
struct xtalk_raw *xtalk_raw_new(struct xtalk_base *xtalk_base)
|
||||
{
|
||||
struct xtalk_raw *xtalk_raw;
|
||||
int ret;
|
||||
|
||||
assert(xtalk_base);
|
||||
xtalk_raw = calloc(1, sizeof(*xtalk_raw));
|
||||
if (!xtalk_raw) {
|
||||
ERR("Allocating XTALK device memory failed\n");
|
||||
return NULL;
|
||||
}
|
||||
xtalk_raw->xtalk_base = xtalk_base;
|
||||
ret = xtalk_set_protocol(xtalk_raw->xtalk_base, &xtalk_raw_proto, NULL);
|
||||
if (ret < 0) {
|
||||
ERR("GLOBAL Protocol registration failed: %d\n", ret);
|
||||
goto err;
|
||||
}
|
||||
DBG("%s: xtalk_raw=%p\n", __func__, xtalk_raw);
|
||||
return xtalk_raw;
|
||||
err:
|
||||
xtalk_raw_delete(xtalk_raw);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void xtalk_raw_delete(struct xtalk_raw *xtalk_raw)
|
||||
{
|
||||
if (xtalk_raw) {
|
||||
memset(xtalk_raw, 0, sizeof(*xtalk_raw));
|
||||
free(xtalk_raw);
|
||||
}
|
||||
}
|
||||
|
||||
int xtalk_raw_set_protocol(struct xtalk_raw *xtalk_raw,
|
||||
const struct xtalk_protocol *xproto)
|
||||
{
|
||||
return xtalk_set_protocol(xtalk_raw->xtalk_base, &xtalk_raw_proto, xproto);
|
||||
}
|
||||
|
||||
int xtalk_raw_cmd_send(struct xtalk_raw *xtalk_raw, const char *buf, int len,
|
||||
uint16_t *tx_seq)
|
||||
{
|
||||
struct xtalk_command *cmd;
|
||||
char *p;
|
||||
int ret;
|
||||
|
||||
p = malloc(len);
|
||||
if (!p) {
|
||||
ERR("allocation failed (%d bytes)\n", len);
|
||||
return -ENOMEM;
|
||||
}
|
||||
cmd = (struct xtalk_command *)p;
|
||||
memcpy(p, buf, len);
|
||||
cmd->header.len = len;
|
||||
|
||||
ret = send_command(xtalk_raw->xtalk_base, cmd, tx_seq);
|
||||
if (ret < 0) {
|
||||
DBG("%s: send_command(%d bytes) failed ret=%d\n",
|
||||
__func__, len, ret);
|
||||
goto out;
|
||||
}
|
||||
DBG("%s(%d bytes, tx_seq=%d)\n", __func__, len, *tx_seq);
|
||||
out:
|
||||
free(p);
|
||||
return ret;
|
||||
}
|
||||
|
||||
__attribute__((warn_unused_result))
|
||||
int xtalk_raw_cmd_recv(struct xtalk_raw *xtalk_raw,
|
||||
struct xtalk_command **reply_ref)
|
||||
{
|
||||
struct xtalk_base *xtalk_base;
|
||||
const struct xtalk_protocol *xproto;
|
||||
struct xtalk_command *reply = NULL;
|
||||
const struct xtalk_command_desc *reply_desc;
|
||||
const char *protoname;
|
||||
int ret;
|
||||
xtalk_cmd_callback_t callback;
|
||||
|
||||
xtalk_base = xtalk_raw->xtalk_base;
|
||||
xproto = &xtalk_base->xproto;
|
||||
protoname = (xproto) ? xproto->name : "GLOBAL";
|
||||
/* So the caller knows if a reply was received */
|
||||
if (reply_ref)
|
||||
*reply_ref = NULL;
|
||||
ret = recv_command(xtalk_base, &reply);
|
||||
if (ret <= 0) {
|
||||
DBG("%s: failed (xproto = %s, ret = %d)\n",
|
||||
__func__, protoname, ret);
|
||||
goto err;
|
||||
}
|
||||
DBG("REPLY OP: 0x%X\n", reply->header.op);
|
||||
if (debug_mask & DBG_MASK)
|
||||
xtalk_dump_command(reply);
|
||||
/* reply_desc may be NULL (raw reply to application) */
|
||||
reply_desc = get_command_desc(xproto, reply->header.op);
|
||||
if (reply->header.op == XTALK_ACK) {
|
||||
int status = CMD_FIELD(reply, XTALK, ACK, stat);
|
||||
|
||||
if (status != STAT_OK) {
|
||||
ERR("Got NACK(seq=%d): %d %s\n",
|
||||
reply->header.seq,
|
||||
status,
|
||||
ack_status_msg(xproto, status));
|
||||
}
|
||||
/* Good expected ACK ... */
|
||||
}
|
||||
DBG("got reply seq=%d op=0x%X (%d bytes)\n",
|
||||
reply->header.seq,
|
||||
reply->header.op,
|
||||
ret);
|
||||
/* Find if there is associated callback */
|
||||
ret = xtalk_cmd_callback(xtalk_base, reply->header.op, NULL, &callback);
|
||||
if (ret < 0) {
|
||||
ERR("Failed getting callback for op=0x%X\n", reply->header.op);
|
||||
goto err;
|
||||
}
|
||||
if (callback) {
|
||||
/* Override return value with callback return value */
|
||||
ret = callback(xtalk_base, reply_desc, reply);
|
||||
DBG("%s: callback for 0x%X returned %d\n", __func__,
|
||||
reply->header.op, ret);
|
||||
}
|
||||
if (reply_ref)
|
||||
*reply_ref = reply;
|
||||
return 0;
|
||||
err:
|
||||
if (reply)
|
||||
free_command(reply);
|
||||
return ret;
|
||||
}
|
||||
|
||||
int xtalk_raw_buffer_send(struct xtalk_raw *xraw, const char *buf, int len)
|
||||
{
|
||||
dump_packet(LOG_DEBUG, DBG_MASK, __func__, buf, len);
|
||||
return send_buffer(xraw->xtalk_base, buf, len);
|
||||
}
|
||||
|
||||
int xtalk_raw_buffer_recv(struct xtalk_raw *xraw, char *buf, int len)
|
||||
{
|
||||
int ret;
|
||||
|
||||
ret = recv_buffer(xraw->xtalk_base, buf, len);
|
||||
if (ret >= 0)
|
||||
dump_packet(LOG_DEBUG, DBG_MASK, __func__, buf, ret);
|
||||
return ret;
|
||||
}
|
||||
207
xpp/xtalk/xtalk_raw_test.c
Normal file
207
xpp/xtalk/xtalk_raw_test.c
Normal file
@@ -0,0 +1,207 @@
|
||||
#include <assert.h>
|
||||
#include <errno.h>
|
||||
#include <getopt.h>
|
||||
#include <stdio.h>
|
||||
#include <stdint.h>
|
||||
#include <string.h>
|
||||
#include <xtalk/debug.h>
|
||||
#include <xtalk/xusb.h>
|
||||
#include <xtalk/proto_raw.h>
|
||||
#include <autoconfig.h>
|
||||
|
||||
static char *progname;
|
||||
|
||||
#define DBG_MASK 0x10
|
||||
|
||||
static void usage()
|
||||
{
|
||||
fprintf(stderr, "Usage: %s [options...] -D <device> [hexnum ....]\n",
|
||||
progname);
|
||||
fprintf(stderr, "\tOptions:\n");
|
||||
fprintf(stderr, "\t\t[-v] # Increase verbosity\n");
|
||||
fprintf(stderr,
|
||||
"\t\t[-d mask] # Debug mask (0xFF for everything)\n");
|
||||
fprintf(stderr, "\tDevice:\n");
|
||||
fprintf(stderr, "\t\t/proc/bus/usb/<bus>/<dev>\n");
|
||||
fprintf(stderr, "\t\t/dev/bus/usb/<bus>/<dev>\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
static void xusb_destructor(void *data)
|
||||
{
|
||||
struct xusb_device *xusb_device = data;
|
||||
xusb_destroy(xusb_device);
|
||||
}
|
||||
|
||||
static const struct test_struct {
|
||||
struct xusb_spec spec;
|
||||
int interface_num;
|
||||
} known_devices[] = {
|
||||
{ SPEC_HEAD(0xe4e4, 0x1162, "astribank2-FPGA"), 0 },
|
||||
{{}, 0 },
|
||||
};
|
||||
|
||||
int proto_ack_cb(
|
||||
const struct xtalk_base *xtalk_base,
|
||||
const struct xtalk_command_desc *cmd_desc,
|
||||
struct xtalk_command *cmd)
|
||||
{
|
||||
const char *name = (cmd_desc->name) ? cmd_desc->name : "RAW";
|
||||
|
||||
printf("%s: op=0x%X (%s): len=%d\n", __func__,
|
||||
cmd_desc->op, name, cmd->header.len);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Not const, because we override proto_version for testing
|
||||
*/
|
||||
static struct xtalk_protocol xtalk_raw_test_base = {
|
||||
.name = "XTALK_TEST",
|
||||
.proto_version = 0, /* Modified in test_device() */
|
||||
.commands = {
|
||||
},
|
||||
.ack_statuses = {
|
||||
}
|
||||
};
|
||||
|
||||
static int test_device(struct xusb_iface *xusb_iface, int timeout)
|
||||
{
|
||||
struct xtalk_base *xtalk_base = NULL;
|
||||
struct xtalk_raw *xtalk_raw = NULL;
|
||||
struct xtalk_command *reply;
|
||||
uint16_t tx_seq;
|
||||
int ret;
|
||||
|
||||
xtalk_base = xtalk_base_new_on_xusb(xusb_iface);
|
||||
if (!xtalk_base) {
|
||||
ERR("Failed creating the xtalk device abstraction\n");
|
||||
ret = -ENOMEM;
|
||||
goto err;
|
||||
}
|
||||
xtalk_raw = xtalk_raw_new(xtalk_base);
|
||||
if (!xtalk_raw) {
|
||||
ERR("Failed creating the xtalk sync device abstraction\n");
|
||||
ret = -ENOMEM;
|
||||
goto err;
|
||||
}
|
||||
ret = xtalk_set_timeout(xtalk_base, timeout);
|
||||
INFO("Original timeout=%d, now set to %d\n", ret, timeout);
|
||||
/* override constness for testing */
|
||||
ret = xtalk_raw_set_protocol(xtalk_raw, &xtalk_raw_test_base);
|
||||
if (ret < 0) {
|
||||
ERR("%s Protocol registration failed: %d\n",
|
||||
xtalk_raw_test_base.name, ret);
|
||||
ret = -EPROTO;
|
||||
goto err;
|
||||
}
|
||||
ret = xtalk_cmd_callback(xtalk_base, XTALK_OP(XTALK, ACK), proto_ack_cb, NULL);
|
||||
if (ret < 0) {
|
||||
ERR("%s Callback registration failed: %d\n",
|
||||
xtalk_raw_test_base.name, ret);
|
||||
ret = -EPROTO;
|
||||
goto err;
|
||||
}
|
||||
INFO("Device and Protocol are ready\n");
|
||||
ret = xtalk_raw_cmd_send(xtalk_raw, "abcdef", 6, &tx_seq);
|
||||
if (ret < 0) {
|
||||
ERR("Failed sending raw command: %d\n", ret);
|
||||
ret = -EPROTO;
|
||||
goto err;
|
||||
}
|
||||
do {
|
||||
ret = xtalk_raw_cmd_recv(xtalk_raw, &reply);
|
||||
if (ret < 0) {
|
||||
if (ret == -ETIMEDOUT) {
|
||||
printf("timeout\n");
|
||||
continue;
|
||||
}
|
||||
ERR("Read error (ret=%d)\n", ret);
|
||||
goto err;
|
||||
}
|
||||
assert(reply);
|
||||
printf("Got %d (len=%d)\n", reply->header.op, reply->header.len);
|
||||
} while (1);
|
||||
err:
|
||||
if (xtalk_raw)
|
||||
xtalk_raw_delete(xtalk_raw);
|
||||
if (xtalk_base)
|
||||
xtalk_base_delete(xtalk_base);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int run_spec(int i, xusb_filter_t filter, char *devpath, int timeout)
|
||||
{
|
||||
const struct xusb_spec *s = &known_devices[i].spec;
|
||||
int interface_num = known_devices[i].interface_num;
|
||||
struct xlist_node *xlist;
|
||||
struct xlist_node *curr;
|
||||
struct xusb_device *xusb_device;
|
||||
int success = 1;
|
||||
|
||||
if (!s->name)
|
||||
return 0;
|
||||
xlist = xusb_find_byproduct(s, 1, filter, devpath);
|
||||
if (!xlist_length(xlist))
|
||||
return 1;
|
||||
INFO("total %zd devices of type %s\n", xlist_length(xlist), s->name);
|
||||
for (curr = xlist_shift(xlist); curr; curr = xlist_shift(xlist)) {
|
||||
struct xusb_iface *xusb_iface;
|
||||
int ret;
|
||||
|
||||
xusb_device = curr->data;
|
||||
xusb_showinfo(xusb_device);
|
||||
INFO("Testing interface %d\n", interface_num);
|
||||
ret = xusb_claim(xusb_device, interface_num, &xusb_iface);
|
||||
if (ret == 0) {
|
||||
ret = test_device(xusb_iface, timeout);
|
||||
if (ret < 0)
|
||||
success = 0;
|
||||
}
|
||||
xusb_destroy(xusb_device);
|
||||
}
|
||||
xlist_destroy(xlist, xusb_destructor);
|
||||
return success;
|
||||
}
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
char *devpath = NULL;
|
||||
const char options[] = "vd:D:EFpt:";
|
||||
xusb_filter_t filter = NULL;
|
||||
int timeout = 500; /* millies */
|
||||
int i;
|
||||
|
||||
progname = argv[0];
|
||||
while (1) {
|
||||
int c;
|
||||
|
||||
c = getopt(argc, argv, options);
|
||||
if (c == -1)
|
||||
break;
|
||||
|
||||
switch (c) {
|
||||
case 'D':
|
||||
devpath = optarg;
|
||||
filter = xusb_filter_bypath;
|
||||
break;
|
||||
case 'v':
|
||||
verbose++;
|
||||
break;
|
||||
case 't':
|
||||
timeout = strtoul(optarg, NULL, 0);
|
||||
break;
|
||||
case 'd':
|
||||
debug_mask = strtoul(optarg, NULL, 0);
|
||||
break;
|
||||
case 'h':
|
||||
default:
|
||||
ERR("Unknown option '%c'\n", c);
|
||||
usage();
|
||||
}
|
||||
}
|
||||
i = 0;
|
||||
while (run_spec(i, filter, devpath, timeout))
|
||||
i++;
|
||||
return 0;
|
||||
}
|
||||
49
xpp/xtalk/xtalk_send.8
Normal file
49
xpp/xtalk/xtalk_send.8
Normal file
@@ -0,0 +1,49 @@
|
||||
.\" Hey, EMACS: -*- nroff -*-
|
||||
.\" (C) Copyright 2013 Oron Peled <oron@actcom.co.il>,
|
||||
.\"
|
||||
.TH XTALK_SEND 8 "March 14, 2013"
|
||||
.\"
|
||||
.\" Some roff macros, for reference:
|
||||
.\" .nh disable hyphenation
|
||||
.\" .hy enable hyphenation
|
||||
.\" .ad l left justify
|
||||
.\" .ad b justify to both left and right margins
|
||||
.\" .nf disable filling
|
||||
.\" .fi enable filling
|
||||
.\" .br insert line break
|
||||
.\" .sp <n> insert n+1 empty lines
|
||||
.\" for manpage-specific macros, see man(7)
|
||||
.SH NAME
|
||||
xtalk_send \- send arbitrary packets to XTALK devices
|
||||
.SH SYNOPSIS
|
||||
.B xtalk_send
|
||||
.RI [ options ] " hexnum" ...
|
||||
.br
|
||||
.SH DESCRIPTION
|
||||
This manual page documents briefly the \fBxtalk_send\fP command.
|
||||
.PP
|
||||
\fBxtalk_send\fP is a program that send arbitrary packets to Xorcom devices
|
||||
that use the XTALK protocol.
|
||||
.SH OPTIONS
|
||||
A summary of options is included below:
|
||||
.TP
|
||||
.B \-I <iface_num>
|
||||
Specify USB interface number (default 1).
|
||||
.TP
|
||||
.B \-t <timeout>
|
||||
Timeout from send until an answer is received (default 500).
|
||||
.TP
|
||||
.B \-Q
|
||||
Query protocol version. This is only valid for synchronous XTALK protocols.
|
||||
Usually, these protocols are bound to USB interface 1.
|
||||
.TP
|
||||
.B \-h
|
||||
Show summary of options.
|
||||
.TP
|
||||
.B \-v
|
||||
Increase output verbosity.
|
||||
.TP
|
||||
.B \-d <mask>
|
||||
Debug mask. Use 0xFF for everything.
|
||||
.SH AUTHOR
|
||||
Oron Peled <oron@actcom.co.il>
|
||||
220
xpp/xtalk/xtalk_send.c
Normal file
220
xpp/xtalk/xtalk_send.c
Normal file
@@ -0,0 +1,220 @@
|
||||
/*
|
||||
* Written by Oron Peled <oron@actcom.co.il>
|
||||
* Copyright (C) 2008-2011, 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 <getopt.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include <errno.h>
|
||||
#include <assert.h>
|
||||
#include <arpa/inet.h>
|
||||
#include <xtalk/debug.h>
|
||||
#include <xtalk/xusb.h>
|
||||
#include <xtalk/proto_sync.h>
|
||||
#include <autoconfig.h>
|
||||
|
||||
#define DBG_MASK 0x80
|
||||
|
||||
static char *progname;
|
||||
static int timeout = 500; /* msec */
|
||||
static int iface_num = 1;
|
||||
|
||||
static void usage()
|
||||
{
|
||||
fprintf(stderr, "Usage: %s [options...] -D <busnum>/<devnum> [hexnum ....]\n",
|
||||
progname);
|
||||
fprintf(stderr, "\tOptions:\n");
|
||||
fprintf(stderr,
|
||||
"\t\t[-I<iface_num>] # Interface number (default %d)\n",
|
||||
iface_num);
|
||||
fprintf(stderr,
|
||||
"\t\t[-t<timeout>] # Timeout (default %d)\n",
|
||||
timeout);
|
||||
fprintf(stderr, "\t\t[-Q] # Query protocol version\n");
|
||||
fprintf(stderr, "\t\t[-v] # Increase verbosity\n");
|
||||
fprintf(stderr,
|
||||
"\t\t[-d mask] # Debug mask (0xFF for everything)\n");
|
||||
fprintf(stderr, "\t\t[-h] # This help\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
/***** XTALK Interface *****************************************************/
|
||||
static const struct xtalk_protocol xtalk_protocol = {
|
||||
.name = "XTALK-DERIVED",
|
||||
.proto_version = 0,
|
||||
.commands = {
|
||||
},
|
||||
.ack_statuses = {
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
/***** XUSB Interface ******************************************************/
|
||||
|
||||
static int sendto_device(struct xusb_iface *iface, int nargs, char *args[])
|
||||
{
|
||||
char *reply = NULL;
|
||||
char *buf = NULL;
|
||||
int ret = 0;
|
||||
int i;
|
||||
|
||||
assert(nargs >= 0);
|
||||
if (!nargs)
|
||||
goto out;
|
||||
buf = malloc(nargs);
|
||||
if (!buf) {
|
||||
ERR("Out of memory for %d command bytes\n", nargs);
|
||||
ret = -ENOMEM;
|
||||
goto out;
|
||||
}
|
||||
for (i = 0; i < nargs; i++) {
|
||||
int val = strtoul(args[i], NULL, 16);
|
||||
printf("%d> 0x%02X\n", i, val);
|
||||
buf[i] = val;
|
||||
}
|
||||
ret = xusb_send(iface, buf, nargs, timeout);
|
||||
if (ret < 0) {
|
||||
ERR("xusb_send failed ret=%d\n", ret);
|
||||
goto out;
|
||||
}
|
||||
reply = malloc(PACKET_SIZE);
|
||||
if (!reply) {
|
||||
ERR("Out of memory\n");
|
||||
ret = -ENOMEM;
|
||||
goto out;
|
||||
}
|
||||
ret = xusb_recv(iface, reply, PACKET_SIZE, timeout);
|
||||
if (ret < 0) {
|
||||
ERR("Receive from usb failed.\n");
|
||||
goto out;
|
||||
}
|
||||
dump_packet(LOG_INFO, 0, "REPLY", reply, ret);
|
||||
ret = 0;
|
||||
out:
|
||||
if (reply)
|
||||
free(reply);
|
||||
if (buf)
|
||||
free(buf);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int show_protocol(struct xtalk_sync *xtalk_sync, struct xusb_iface *iface)
|
||||
{
|
||||
int ret;
|
||||
|
||||
ret = xtalk_sync_set_protocol(xtalk_sync, &xtalk_protocol);
|
||||
if (ret < 0) {
|
||||
ERR("%s Protocol registration failed: %s\n",
|
||||
xtalk_protocol.name, strerror(-ret));
|
||||
return ret;
|
||||
}
|
||||
ret = xtalk_proto_query(xtalk_sync);
|
||||
if (ret < 0) {
|
||||
ERR("Protocol query error: %s\n", strerror(-ret));
|
||||
return ret;
|
||||
}
|
||||
INFO("usb:%s: Protocol version 0x%X\n", xusb_devpath(xusb_deviceof(iface)), ret);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
char *devpath = NULL;
|
||||
struct xusb_device *xusb_device;
|
||||
struct xtalk_base *xtalk_base;
|
||||
struct xtalk_sync *xtalk_sync;
|
||||
struct xusb_iface *iface;
|
||||
const char options[] = "vd:D:t:I:i:o:Q";
|
||||
int query = 0;
|
||||
int ret;
|
||||
|
||||
progname = argv[0];
|
||||
while (1) {
|
||||
int c;
|
||||
|
||||
c = getopt(argc, argv, options);
|
||||
if (c == -1)
|
||||
break;
|
||||
|
||||
switch (c) {
|
||||
case 'D':
|
||||
devpath = optarg;
|
||||
break;
|
||||
case 'I':
|
||||
iface_num = strtoul(optarg, NULL, 0);
|
||||
break;
|
||||
case 't':
|
||||
timeout = strtoul(optarg, NULL, 0);
|
||||
break;
|
||||
case 'Q':
|
||||
query++;
|
||||
break;
|
||||
case 'v':
|
||||
verbose++;
|
||||
break;
|
||||
case 'd':
|
||||
debug_mask = strtoul(optarg, NULL, 0);
|
||||
break;
|
||||
case 'h':
|
||||
default:
|
||||
ERR("Unknown option '%c'\n", c);
|
||||
usage();
|
||||
}
|
||||
}
|
||||
if (!devpath) {
|
||||
ERR("Missing device path\n");
|
||||
usage();
|
||||
}
|
||||
xusb_device = xusb_find_bypath(devpath);
|
||||
if (!xusb_device) {
|
||||
ERR("No XUSB device found\n");
|
||||
return 1;
|
||||
}
|
||||
ret = xusb_claim(xusb_device, iface_num, &iface);
|
||||
if (ret < 0) {
|
||||
ERR("Claiming interface #%d failed (ret = %d)\n", iface_num, ret);
|
||||
return 1;
|
||||
}
|
||||
xusb_showinfo(xusb_deviceof(iface));
|
||||
xtalk_base = xtalk_base_new_on_xusb(iface);
|
||||
if (!xtalk_base) {
|
||||
ERR("Failed creating the xtalk device abstraction\n");
|
||||
return 1;
|
||||
}
|
||||
xtalk_sync = xtalk_sync_new(xtalk_base);
|
||||
if (!xtalk_sync) {
|
||||
ERR("Failed creating the xtalk device abstraction\n");
|
||||
return 1;
|
||||
}
|
||||
if (query) {
|
||||
ret = show_protocol(xtalk_sync, iface);
|
||||
if (ret < 0)
|
||||
return 1;
|
||||
}
|
||||
ret = sendto_device(iface, argc - optind, argv + optind);
|
||||
if (ret < 0)
|
||||
ERR("Command failed: %d\n", ret);
|
||||
xtalk_sync_delete(xtalk_sync);
|
||||
xtalk_base_delete(xtalk_base);
|
||||
xusb_destroy(xusb_deviceof(iface));
|
||||
return 0;
|
||||
}
|
||||
290
xpp/xtalk/xtalk_sync.c
Normal file
290
xpp/xtalk/xtalk_sync.c
Normal file
@@ -0,0 +1,290 @@
|
||||
/*
|
||||
* 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/debug.h>
|
||||
#include <xtalk/proto_sync.h>
|
||||
#include <autoconfig.h>
|
||||
#include "xtalk_base.h"
|
||||
|
||||
#define DBG_MASK 0x02
|
||||
|
||||
/*
|
||||
* Base XTALK device. A pointer to this struct
|
||||
* should be included in the struct representing
|
||||
* the dialect.
|
||||
*/
|
||||
struct xtalk_sync {
|
||||
struct xtalk_base *xtalk_base;
|
||||
};
|
||||
|
||||
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;
|
||||
|
||||
const struct xtalk_protocol xtalk_sync_proto = {
|
||||
.name = "XTALK-SYNC",
|
||||
.proto_version = 0,
|
||||
.commands = {
|
||||
CMD_RECV(XTALK, ACK),
|
||||
CMD_SEND(XTALK, PROTO_GET),
|
||||
CMD_RECV(XTALK, PROTO_GET_REPLY),
|
||||
},
|
||||
.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"),
|
||||
}
|
||||
};
|
||||
|
||||
struct xtalk_sync *xtalk_sync_new(struct xtalk_base *xtalk_base)
|
||||
{
|
||||
struct xtalk_sync *xtalk_sync;
|
||||
int ret;
|
||||
|
||||
assert(xtalk_base);
|
||||
xtalk_sync = calloc(1, sizeof(*xtalk_sync));
|
||||
if (!xtalk_sync) {
|
||||
ERR("Allocating XTALK device memory failed\n");
|
||||
return NULL;
|
||||
}
|
||||
xtalk_sync->xtalk_base = xtalk_base;
|
||||
ret = xtalk_set_protocol(xtalk_sync->xtalk_base, &xtalk_sync_proto, NULL);
|
||||
if (ret < 0) {
|
||||
ERR("GLOBAL Protocol registration failed: %d\n", ret);
|
||||
goto err;
|
||||
}
|
||||
DBG("%s: xtalk_sync=%p\n", __func__, xtalk_sync);
|
||||
return xtalk_sync;
|
||||
err:
|
||||
xtalk_sync_delete(xtalk_sync);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void xtalk_sync_delete(struct xtalk_sync *xtalk_sync)
|
||||
{
|
||||
if (xtalk_sync) {
|
||||
memset(xtalk_sync, 0, sizeof(*xtalk_sync));
|
||||
free(xtalk_sync);
|
||||
}
|
||||
}
|
||||
|
||||
int xtalk_sync_set_protocol(struct xtalk_sync *xtalk_sync,
|
||||
const struct xtalk_protocol *xproto)
|
||||
{
|
||||
return xtalk_set_protocol(xtalk_sync->xtalk_base, &xtalk_sync_proto, xproto);
|
||||
}
|
||||
|
||||
__attribute__((warn_unused_result))
|
||||
int process_command(
|
||||
struct xtalk_sync *xtalk_sync,
|
||||
struct xtalk_command *cmd,
|
||||
struct xtalk_command **reply_ref,
|
||||
uint16_t *tx_seq)
|
||||
{
|
||||
struct xtalk_base *xtalk_base;
|
||||
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;
|
||||
xtalk_cmd_callback_t callback;
|
||||
|
||||
xtalk_base = xtalk_sync->xtalk_base;
|
||||
xproto = &xtalk_base->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_base, cmd, tx_seq);
|
||||
if (ret < 0) {
|
||||
ERR("send_command failed: %d\n", ret);
|
||||
goto out;
|
||||
}
|
||||
if (!reply_ref) {
|
||||
DBG("No reply requested\n");
|
||||
goto out;
|
||||
}
|
||||
ret = recv_command(xtalk_base, &reply);
|
||||
if (ret <= 0) {
|
||||
DBG("recv_command failed (ret = %d)\n", ret);
|
||||
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;
|
||||
}
|
||||
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);
|
||||
dump_packet(LOG_ERR, 0, __func__, (const char *)reply, ret);
|
||||
ret = -EPROTO;
|
||||
goto out;
|
||||
}
|
||||
DBG("REPLY OP: 0x%X [%s]\n", reply->header.op, reply_desc->name);
|
||||
if (reply->header.op == XTALK_ACK) {
|
||||
uint8_t 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;
|
||||
}
|
||||
/* Find if there is associated callback */
|
||||
ret = xtalk_cmd_callback(xtalk_base, reply->header.op, NULL, &callback);
|
||||
if (ret < 0) {
|
||||
ERR("Failed getting callback for op=0x%X\n", reply->header.op);
|
||||
goto out;
|
||||
}
|
||||
ret = reply->header.len; /* All good, return the length */
|
||||
DBG("got reply op 0x%X (%d bytes)\n", reply->header.op, ret);
|
||||
if (callback) {
|
||||
/* Override return value with callback return value */
|
||||
ret = callback(xtalk_base, reply_desc, reply);
|
||||
DBG("%s: callback for 0x%X returned %d\n", __func__,
|
||||
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_sync *xtalk_sync)
|
||||
{
|
||||
struct xtalk_base *xtalk_base;
|
||||
struct xtalk_command *cmd;
|
||||
struct xtalk_command *reply;
|
||||
uint8_t proto_version;
|
||||
int ret;
|
||||
uint16_t tx_seq;
|
||||
|
||||
DBG("\n");
|
||||
assert(xtalk_sync != NULL);
|
||||
xtalk_base = xtalk_sync->xtalk_base;
|
||||
proto_version = xtalk_base->xproto.proto_version;
|
||||
cmd = new_command(xtalk_base, XTALK_OP(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;
|
||||
CMD_FIELD(cmd, XTALK, PROTO_GET, reserved) = 0; /* RESERVED */
|
||||
ret = process_command(xtalk_sync, cmd, &reply, &tx_seq);
|
||||
if (ret < 0) {
|
||||
ERR("process_command failed: %d\n", ret);
|
||||
goto out;
|
||||
}
|
||||
xtalk_base->xtalk_proto_version =
|
||||
CMD_FIELD(reply, XTALK, PROTO_GET_REPLY, proto_version);
|
||||
if (xtalk_base->xtalk_proto_version != proto_version) {
|
||||
DBG("Got %s protocol version: 0x%02x (expected 0x%02x)\n",
|
||||
xtalk_base->xproto.name,
|
||||
xtalk_base->xtalk_proto_version,
|
||||
proto_version);
|
||||
ret = xtalk_base->xtalk_proto_version;
|
||||
goto out;
|
||||
}
|
||||
DBG("Protocol version: %02x (tx_seq = %d)\n",
|
||||
xtalk_base->xtalk_proto_version, tx_seq);
|
||||
ret = xtalk_base->xtalk_proto_version;
|
||||
out:
|
||||
free_command(reply);
|
||||
return ret;
|
||||
}
|
||||
199
xpp/xtalk/xtalk_test.c
Normal file
199
xpp/xtalk/xtalk_test.c
Normal file
@@ -0,0 +1,199 @@
|
||||
#include <errno.h>
|
||||
#include <getopt.h>
|
||||
#include <stdio.h>
|
||||
#include <stdint.h>
|
||||
#include <string.h>
|
||||
#include <xtalk/debug.h>
|
||||
#include <xtalk/xusb.h>
|
||||
#include <xtalk/proto_sync.h>
|
||||
#include <autoconfig.h>
|
||||
|
||||
static char *progname;
|
||||
|
||||
#define DBG_MASK 0x10
|
||||
|
||||
static void usage()
|
||||
{
|
||||
fprintf(stderr, "Usage: %s [options...] -D <device> [hexnum ....]\n",
|
||||
progname);
|
||||
fprintf(stderr, "\tOptions:\n");
|
||||
fprintf(stderr, "\t\t[-v] # Increase verbosity\n");
|
||||
fprintf(stderr,
|
||||
"\t\t[-d mask] # Debug mask (0xFF for everything)\n");
|
||||
fprintf(stderr, "\tDevice:\n");
|
||||
fprintf(stderr, "\t\t/proc/bus/usb/<bus>/<dev>\n");
|
||||
fprintf(stderr, "\t\t/dev/bus/usb/<bus>/<dev>\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
static void xusb_destructor(void *data)
|
||||
{
|
||||
struct xusb_device *xusb_device = data;
|
||||
xusb_destroy(xusb_device);
|
||||
}
|
||||
|
||||
#define KNOWN_DEV(p, i, v, d) \
|
||||
{ SPEC_HEAD(0xe4e4, (p), (d)), (i), (v) }
|
||||
|
||||
static const struct test_struct {
|
||||
struct xusb_spec spec;
|
||||
int interface_num;
|
||||
uint8_t proto_version;
|
||||
} known_devices[] = {
|
||||
/* PROD I V NAME */
|
||||
KNOWN_DEV(0x1161, 1, 0x14, "astribank2-USB"),
|
||||
KNOWN_DEV(0x1162, 1, 0x14, "astribank2-FPGA"),
|
||||
KNOWN_DEV(0x1191, 1, 0x10, "xpanel"),
|
||||
KNOWN_DEV(0x1183, 1, 0x11, "multi-ps"),
|
||||
KNOWN_DEV(0x11a3, 0, 0x01, "auth-dongle"),
|
||||
KNOWN_DEV(0xbb01, 1, 0x10, "iwc"),
|
||||
KNOWN_DEV(0, 0, 0, NULL),
|
||||
};
|
||||
|
||||
int proto_get_reply_cb(
|
||||
const struct xtalk_base *xtalk_base,
|
||||
const struct xtalk_command_desc *cmd_desc,
|
||||
struct xtalk_command *cmd)
|
||||
{
|
||||
INFO("CALLBACK: op=0x%X (%s): len=%d\n",
|
||||
cmd_desc->op, cmd_desc->name, cmd->header.len);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Not const, because we override proto_version for testing
|
||||
*/
|
||||
static struct xtalk_protocol xtalk_test_base = {
|
||||
.name = "XTALK_TEST",
|
||||
.proto_version = 0, /* Modified in test_device() */
|
||||
.commands = {
|
||||
},
|
||||
.ack_statuses = {
|
||||
}
|
||||
};
|
||||
|
||||
static int test_device(struct xusb_iface *xusb_iface, uint8_t wanted_version, int timeout)
|
||||
{
|
||||
struct xtalk_base *xtalk_base;
|
||||
struct xtalk_sync *xtalk_sync;
|
||||
int proto_version;
|
||||
int ret;
|
||||
|
||||
xtalk_base = xtalk_base_new_on_xusb(xusb_iface);
|
||||
if (!xtalk_base) {
|
||||
ERR("Failed creating the xtalk device abstraction\n");
|
||||
return -ENOMEM;
|
||||
}
|
||||
xtalk_sync = xtalk_sync_new(xtalk_base);
|
||||
if (!xtalk_sync) {
|
||||
ERR("Failed creating the xtalk sync device abstraction\n");
|
||||
return -ENOMEM;
|
||||
}
|
||||
ret = xtalk_set_timeout(xtalk_base, timeout);
|
||||
INFO("Original timeout=%d, now set to %d\n", ret, timeout);
|
||||
/* override constness for testing */
|
||||
xtalk_test_base.proto_version = wanted_version;
|
||||
ret = xtalk_sync_set_protocol(xtalk_sync, &xtalk_test_base);
|
||||
if (ret < 0) {
|
||||
ERR("%s Protocol registration failed: %d\n",
|
||||
xtalk_test_base.name, ret);
|
||||
return -EPROTO;
|
||||
}
|
||||
ret = xtalk_cmd_callback(xtalk_base, XTALK_OP(XTALK, PROTO_GET_REPLY), proto_get_reply_cb, NULL);
|
||||
if (ret < 0) {
|
||||
ERR("%s Callback registration failed: %d\n",
|
||||
xtalk_test_base.name, ret);
|
||||
return -EPROTO;
|
||||
}
|
||||
proto_version = xtalk_proto_query(xtalk_sync);
|
||||
if (proto_version < 0) {
|
||||
ERR("Protocol query error: %s\n", strerror(-proto_version));
|
||||
return proto_version;
|
||||
}
|
||||
if (proto_version != xtalk_test_base.proto_version) {
|
||||
ERR("Bad protocol version: 0x%02x\n", proto_version);
|
||||
return -EPROTO;
|
||||
}
|
||||
INFO("Device and Protocol are ready (proto_version=0x%X)\n",
|
||||
proto_version);
|
||||
xtalk_sync_delete(xtalk_sync);
|
||||
xtalk_base_delete(xtalk_base);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int run_spec(int i, xusb_filter_t filter, char *devpath, int timeout)
|
||||
{
|
||||
const struct xusb_spec *s = &known_devices[i].spec;
|
||||
int interface_num = known_devices[i].interface_num;
|
||||
uint8_t proto_version = known_devices[i].proto_version;
|
||||
struct xlist_node *xlist;
|
||||
struct xlist_node *curr;
|
||||
struct xusb_device *xusb_device;
|
||||
int success = 1;
|
||||
|
||||
if (!s->name)
|
||||
return 0;
|
||||
xlist = xusb_find_byproduct(s, 1, filter, devpath);
|
||||
if (!xlist_length(xlist))
|
||||
return 1;
|
||||
INFO("total %zd devices of type %s\n", xlist_length(xlist), s->name);
|
||||
for (curr = xlist_shift(xlist); curr; curr = xlist_shift(xlist)) {
|
||||
struct xusb_iface *xusb_iface;
|
||||
int ret;
|
||||
|
||||
xusb_device = curr->data;
|
||||
xusb_showinfo(xusb_device);
|
||||
INFO("Testing interface %d\n", interface_num);
|
||||
ret = xusb_claim(xusb_device, interface_num, &xusb_iface);
|
||||
if (ret == 0) {
|
||||
ret = test_device(xusb_iface, proto_version, timeout);
|
||||
if (ret < 0)
|
||||
success = 0;
|
||||
}
|
||||
xusb_destroy(xusb_device);
|
||||
}
|
||||
xlist_destroy(xlist, xusb_destructor);
|
||||
return success;
|
||||
}
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
char *devpath = NULL;
|
||||
const char options[] = "vd:D:EFpt:";
|
||||
xusb_filter_t filter = NULL;
|
||||
int timeout = 500; /* millies */
|
||||
int i;
|
||||
|
||||
progname = argv[0];
|
||||
while (1) {
|
||||
int c;
|
||||
|
||||
c = getopt(argc, argv, options);
|
||||
if (c == -1)
|
||||
break;
|
||||
|
||||
switch (c) {
|
||||
case 'D':
|
||||
devpath = optarg;
|
||||
filter = xusb_filter_bypath;
|
||||
break;
|
||||
case 'v':
|
||||
verbose++;
|
||||
break;
|
||||
case 't':
|
||||
timeout = strtoul(optarg, NULL, 0);
|
||||
break;
|
||||
case 'd':
|
||||
debug_mask = strtoul(optarg, NULL, 0);
|
||||
break;
|
||||
case 'h':
|
||||
default:
|
||||
ERR("Unknown option '%c'\n", c);
|
||||
usage();
|
||||
}
|
||||
}
|
||||
i = 0;
|
||||
while (run_spec(i, filter, devpath, timeout))
|
||||
i++;
|
||||
return 0;
|
||||
}
|
||||
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 */
|
||||
434
xpp/xtalk/xusb_common.c
Normal file
434
xpp/xtalk/xusb_common.c
Normal file
@@ -0,0 +1,434 @@
|
||||
#define _GNU_SOURCE /* for memrchr() */
|
||||
#include <assert.h>
|
||||
#include <ctype.h>
|
||||
#include <errno.h>
|
||||
#include <stdarg.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <xtalk/debug.h>
|
||||
#include <autoconfig.h>
|
||||
#include "xusb_common.h"
|
||||
|
||||
#define DBG_MASK 0x01
|
||||
|
||||
const char *xusb_tt_name(enum xusb_transfer_type tt)
|
||||
{
|
||||
switch (tt) {
|
||||
case XUSB_TT_BULK: return "BULK";
|
||||
case XUSB_TT_INTERRUPT: return "INTERRUPT";
|
||||
case XUSB_TT_ILLEGAL:
|
||||
break;
|
||||
}
|
||||
return "ILLEGAL";
|
||||
}
|
||||
|
||||
/* GCC versions before 4.6 did not support neither push and pop on
|
||||
* the diagnostic pragma nor applying it inside a function.
|
||||
*/
|
||||
#ifndef HAVE_GCC_PRAGMA_DIAG_STACK
|
||||
#pragma GCC diagnostic ignored "-Wformat-security"
|
||||
#endif
|
||||
int xusb_printf(const struct xusb_iface *iface, int level, int debug_mask,
|
||||
const char *prefix, const char *fmt, ...)
|
||||
{
|
||||
int n;
|
||||
va_list ap;
|
||||
char fmtbuf[BUFSIZ];
|
||||
char tmpbuf[BUFSIZ];
|
||||
|
||||
snprintf(fmtbuf, sizeof(fmtbuf), "%s%03d/%03d[%d] %s",
|
||||
prefix,
|
||||
xusb_bus_num(iface->xusb_device),
|
||||
xusb_device_num(iface->xusb_device),
|
||||
xusb_interface_num(iface),
|
||||
fmt);
|
||||
va_start(ap, fmt);
|
||||
n = vsnprintf(tmpbuf, sizeof(tmpbuf), fmtbuf, ap);
|
||||
va_end(ap);
|
||||
#ifdef HAVE_GCC_PRAGMA_DIAG_STACK
|
||||
#pragma GCC diagnostic push
|
||||
#pragma GCC diagnostic ignored "-Wformat-security"
|
||||
#endif
|
||||
log_function(level, debug_mask, tmpbuf);
|
||||
#ifdef HAVE_GCC_PRAGMA_DIAG_STACK
|
||||
#pragma GCC diagnostic pop
|
||||
#endif
|
||||
return n;
|
||||
}
|
||||
#ifndef HAVE_GCC_PRAGMA_DIAG_STACK
|
||||
#pragma GCC diagnostic error "-Wformat-security"
|
||||
#endif
|
||||
|
||||
int xusb_printf_details(const struct xusb_iface *iface, int level, int debug_mask,
|
||||
const char *file, int line, const char *severity, const char *func,
|
||||
const char *fmt, ...)
|
||||
{
|
||||
int n;
|
||||
va_list ap;
|
||||
char prefix[BUFSIZ];
|
||||
char tmpbuf[BUFSIZ];
|
||||
|
||||
va_start(ap, fmt);
|
||||
vsnprintf(tmpbuf, sizeof(tmpbuf), fmt, ap);
|
||||
va_end(ap);
|
||||
snprintf(prefix, sizeof(prefix), "%s:%d: %s(%s): ",
|
||||
file, line, severity, func);
|
||||
va_start(ap, fmt);
|
||||
n = xusb_printf(iface, level, DBG_MASK, prefix, tmpbuf);
|
||||
va_end(ap);
|
||||
return n;
|
||||
}
|
||||
|
||||
void xusb_init_spec(struct xusb_spec *spec, char *name,
|
||||
uint16_t vendor_id, uint16_t product_id)
|
||||
{
|
||||
DBG("Initialize [%02X:%02X] - %s\n", vendor_id, product_id, name);
|
||||
memset(spec, 0, sizeof(*spec));
|
||||
spec->name = name;
|
||||
spec->vendor_id = vendor_id;
|
||||
spec->product_id = product_id;
|
||||
}
|
||||
|
||||
const struct xusb_spec *xusb_device_spec(const struct xusb_device *xusb_device)
|
||||
{
|
||||
return xusb_device->spec;
|
||||
}
|
||||
|
||||
/*
|
||||
* Match the string "tail" as the tail of string "path"
|
||||
* Returns 1 in case they match, 0 otherwise
|
||||
*/
|
||||
int match_devpath(const char *path, const char *tail)
|
||||
{
|
||||
int len_path = strlen(path);
|
||||
int len_tail = strlen(tail);
|
||||
int path_offset = len_path - len_tail;
|
||||
|
||||
if (path_offset < 0)
|
||||
return 0;
|
||||
return strstr(path + path_offset, tail) != NULL;
|
||||
}
|
||||
|
||||
int match_device(const struct xusb_device *xusb_device,
|
||||
const struct xusb_spec *spec)
|
||||
{
|
||||
assert(xusb_device);
|
||||
DBG("Checking: %04X:%04X: "
|
||||
"\"%s\"\n",
|
||||
spec->vendor_id,
|
||||
spec->product_id,
|
||||
spec->name);
|
||||
if (xusb_device->idVendor != spec->vendor_id) {
|
||||
DBG("Wrong vendor id 0x%X\n", xusb_device->idVendor);
|
||||
return 0;
|
||||
}
|
||||
if (xusb_device->idProduct != spec->product_id) {
|
||||
DBG("Wrong product id 0x%X\n", xusb_device->idProduct);
|
||||
return 0;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
struct xusb_device *xusb_deviceof(struct xusb_iface *iface)
|
||||
{
|
||||
return iface->xusb_device;
|
||||
}
|
||||
|
||||
int xusb_is_claimed(struct xusb_iface *iface)
|
||||
{
|
||||
return iface->is_claimed != 0;
|
||||
}
|
||||
|
||||
struct xusb_iface *xusb_interface_of(const struct xusb_device *dev, int num)
|
||||
{
|
||||
return dev->interfaces[num];
|
||||
}
|
||||
|
||||
#define XUSB_IFACE_DUMP(prefix, level, iface) \
|
||||
XUSB_PRINT((iface), level, "%s%d\tep_out=0x%2X ep_in=0x%02X [%s]\n", \
|
||||
(prefix), \
|
||||
(iface)->interface_num, \
|
||||
(iface)->ep_out, \
|
||||
(iface)->ep_in, \
|
||||
(iface)->iInterface)
|
||||
|
||||
void xusb_list_dump(struct xlist_node *xusb_list)
|
||||
{
|
||||
struct xlist_node *curr;
|
||||
struct xusb_device *xusb_device;
|
||||
|
||||
for (curr = xusb_list->next; curr != xusb_list; curr = curr->next) {
|
||||
struct xusb_iface **piface;
|
||||
|
||||
xusb_device = curr->data;
|
||||
assert(xusb_device);
|
||||
DBG("%s: usb:ID=%04X:%04X [%s / %s / %s]\n",
|
||||
xusb_device->devpath_tail,
|
||||
xusb_device->idVendor,
|
||||
xusb_device->idProduct,
|
||||
xusb_device->iManufacturer,
|
||||
xusb_device->iProduct,
|
||||
xusb_device->iSerialNumber
|
||||
);
|
||||
for (piface = xusb_device->interfaces; *piface; piface++)
|
||||
XUSB_IFACE_DUMP("\t", DEBUG, *piface);
|
||||
}
|
||||
}
|
||||
|
||||
void xusb_destroy_interface(struct xusb_iface *iface)
|
||||
{
|
||||
if (iface) {
|
||||
xusb_release(iface);
|
||||
XUSB_DBG(iface, "MEM: FREE interface\n");
|
||||
memset(iface, 0, sizeof(*iface));
|
||||
free(iface);
|
||||
iface = 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_device *xusb_device, void *data)
|
||||
{
|
||||
const char *p;
|
||||
const char *path = data;
|
||||
|
||||
DBG("%s\n", path);
|
||||
assert(path != NULL);
|
||||
p = path_tail(path);
|
||||
if (strcmp(xusb_device->devpath_tail, p) != 0) {
|
||||
DBG("%s: device path mismatch (!= '%s')\n",
|
||||
xusb_device->devpath_tail, p);
|
||||
return 0;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
struct xusb_iface *xusb_open_one(const struct xusb_spec *specs, int numspecs,
|
||||
int interface_num,
|
||||
xusb_filter_t filterfunc, void *data)
|
||||
{
|
||||
struct xlist_node *xusb_list;
|
||||
struct xlist_node *curr;
|
||||
int num;
|
||||
struct xusb_device *xusb_device = NULL;
|
||||
struct xusb_iface *iface = NULL;
|
||||
int ret;
|
||||
|
||||
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_device = curr->data;
|
||||
xlist_destroy(curr, NULL);
|
||||
xlist_destroy(xusb_list, NULL);
|
||||
ret = xusb_claim(xusb_device, interface_num, &iface);
|
||||
if (ret < 0) {
|
||||
ERR("%s: Failed claiming interface %d (ret = %d)\n",
|
||||
xusb_device->devpath_tail,
|
||||
interface_num,
|
||||
ret);
|
||||
xusb_destroy(xusb_device);
|
||||
return NULL;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
ERR("Too many devices (%d). Aborting.\n", num);
|
||||
break;
|
||||
}
|
||||
return iface;
|
||||
}
|
||||
|
||||
int xusb_interface_num(const struct xusb_iface *iface)
|
||||
{
|
||||
return iface->interface_num;
|
||||
}
|
||||
|
||||
uint16_t xusb_vendor_id(const struct xusb_device *xusb_device)
|
||||
{
|
||||
return xusb_device->idVendor;
|
||||
}
|
||||
|
||||
uint16_t xusb_product_id(const struct xusb_device *xusb_device)
|
||||
{
|
||||
return xusb_device->idProduct;
|
||||
}
|
||||
|
||||
size_t xusb_packet_size(const struct xusb_device *xusb_device)
|
||||
{
|
||||
return xusb_device->packet_size;
|
||||
}
|
||||
|
||||
const char *xusb_serial(const struct xusb_device *xusb_device)
|
||||
{
|
||||
return xusb_device->iSerialNumber;
|
||||
}
|
||||
|
||||
const char *xusb_devpath(const struct xusb_device *xusb_device)
|
||||
{
|
||||
return xusb_device->devpath_tail;
|
||||
}
|
||||
|
||||
uint16_t xusb_bus_num(const struct xusb_device *xusb_device)
|
||||
{
|
||||
return xusb_device->bus_num;
|
||||
}
|
||||
|
||||
uint16_t xusb_device_num(const struct xusb_device *xusb_device)
|
||||
{
|
||||
return xusb_device->device_num;
|
||||
}
|
||||
|
||||
const char *xusb_interface_name(const struct xusb_iface *iface)
|
||||
{
|
||||
return iface->iInterface;
|
||||
}
|
||||
|
||||
const char *xusb_manufacturer(const struct xusb_device *xusb_device)
|
||||
{
|
||||
return xusb_device->iManufacturer;
|
||||
}
|
||||
|
||||
const char *xusb_product(const struct xusb_device *xusb_device)
|
||||
{
|
||||
return xusb_device->iProduct;
|
||||
}
|
||||
|
||||
const struct xusb_spec *xusb_spec(const struct xusb_device *xusb_device)
|
||||
{
|
||||
return xusb_device->spec;
|
||||
}
|
||||
|
||||
int xusb_flushread(struct xusb_iface *iface)
|
||||
{
|
||||
char tmpbuf[BUFSIZ];
|
||||
int ret;
|
||||
|
||||
XUSB_DBG(iface, "starting...\n");
|
||||
memset(tmpbuf, 0, BUFSIZ);
|
||||
ret = xusb_recv(iface, tmpbuf, BUFSIZ, 1);
|
||||
if (ret < 0 && ret != -ETIMEDOUT) {
|
||||
XUSB_ERR(iface, "ret=%d\n", ret);
|
||||
return ret;
|
||||
} else if (ret > 0) {
|
||||
XUSB_DBG(iface, "Got %d bytes:\n", ret);
|
||||
dump_packet(LOG_DEBUG, DBG_MASK, __func__, tmpbuf, ret);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int use_clear_halt = 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;
|
||||
}
|
||||
ERR("Unknown XTALK_OPTIONS content: '%s'\n", option_string);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
int xtalk_option_use_clear_halt(void)
|
||||
{
|
||||
return use_clear_halt;
|
||||
}
|
||||
|
||||
static void chomp(char *buf)
|
||||
{
|
||||
char *p;
|
||||
int len;
|
||||
|
||||
if (!buf)
|
||||
return;
|
||||
len = strlen(buf);
|
||||
for (p = buf + len - 1; p >= buf && isspace(*p); p--)
|
||||
*p = '\0';
|
||||
}
|
||||
|
||||
static const char *OPTION_VAR = "XTALK_OPTIONS";
|
||||
|
||||
/* Caller should free the returned string if it is not NULL */
|
||||
static char *read_options(const char *fname)
|
||||
{
|
||||
FILE *fp;
|
||||
char buf[BUFSIZ];
|
||||
char *p;
|
||||
char *ret_buf;
|
||||
|
||||
fp = fopen(fname, "r");
|
||||
if (!fp) {
|
||||
DBG("Failed opening '$fname': %s\n", strerror(errno));
|
||||
return NULL;
|
||||
}
|
||||
while (fgets(buf, sizeof(buf), fp) != NULL) {
|
||||
chomp(buf);
|
||||
if (buf[0] == '\0' || buf[0] == '#')
|
||||
continue;
|
||||
if (strncmp(buf, OPTION_VAR, strlen(OPTION_VAR)) != 0)
|
||||
continue;
|
||||
/* fprintf(stderr, "INPUT> '%s'\n", p); */
|
||||
p = buf + strlen(OPTION_VAR);
|
||||
while (*p && (isspace(*p) || *p == '='))
|
||||
p++;
|
||||
ret_buf = malloc(sizeof(buf));
|
||||
strcpy(ret_buf, p); /* Cannot overflow */
|
||||
return ret_buf;
|
||||
}
|
||||
fclose(fp);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
int xtalk_parse_options(void)
|
||||
{
|
||||
char *xtalk_options;
|
||||
char *saveptr;
|
||||
char *token;
|
||||
int ret;
|
||||
int free_options = 0;
|
||||
|
||||
xtalk_options = getenv("XTALK_OPTIONS");
|
||||
if (!xtalk_options) {
|
||||
xtalk_options = read_options(XTALK_OPTIONS_FILE);
|
||||
if (!xtalk_options)
|
||||
return 0;
|
||||
free_options = 1;
|
||||
}
|
||||
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);
|
||||
}
|
||||
if (free_options)
|
||||
free(xtalk_options);
|
||||
return 0;
|
||||
}
|
||||
104
xpp/xtalk/xusb_common.h
Normal file
104
xpp/xtalk/xusb_common.h
Normal file
@@ -0,0 +1,104 @@
|
||||
#ifndef XUSB_COMMON_H
|
||||
#define XUSB_COMMON_H
|
||||
/*
|
||||
* Written by Oron Peled <oron@actcom.co.il>
|
||||
* Copyright (C) 2012, 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 <limits.h>
|
||||
#include <xtalk/xusb.h>
|
||||
|
||||
/*
|
||||
* XTALK_OPTIONS:
|
||||
* - "use-clear-halt"
|
||||
* - "no-use-clear-halt"
|
||||
*/
|
||||
int xtalk_parse_options(void);
|
||||
int xtalk_option_use_clear_halt(void);
|
||||
|
||||
enum xusb_transfer_type {
|
||||
XUSB_TT_ILLEGAL = 0,
|
||||
XUSB_TT_BULK,
|
||||
XUSB_TT_INTERRUPT,
|
||||
};
|
||||
|
||||
struct xusb_iface {
|
||||
struct xusb_device *xusb_device;
|
||||
int interface_num;
|
||||
int ep_out;
|
||||
int ep_in;
|
||||
enum xusb_transfer_type transfer_type;
|
||||
int is_claimed;
|
||||
char iInterface[BUFSIZ];
|
||||
};
|
||||
struct libusb_implementation;
|
||||
|
||||
#define XUSB_MAX_INTERFACES 32
|
||||
|
||||
struct xusb_device {
|
||||
struct libusb_implementation *impl;
|
||||
const struct xusb_spec *spec;
|
||||
int idVendor;
|
||||
int idProduct;
|
||||
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 is_usb2;
|
||||
size_t packet_size;
|
||||
struct xusb_iface *interfaces[XUSB_MAX_INTERFACES];
|
||||
};
|
||||
|
||||
#define EP_OUT(iface) ((iface)->ep_out)
|
||||
#define EP_IN(iface) ((iface)->ep_in)
|
||||
|
||||
int match_devpath(const char *path, const char *tail);
|
||||
int match_device(const struct xusb_device *xusb_device,
|
||||
const struct xusb_spec *spec);
|
||||
void xusb_list_dump(struct xlist_node *xusb_list);
|
||||
void xusb_destroy_interface(struct xusb_iface *iface);
|
||||
int xusb_close(struct xusb_device *xusb_device);
|
||||
|
||||
enum xusb_transfer_type xusb_transfer_type(const struct xusb_iface *iface);
|
||||
const char *xusb_tt_name(enum xusb_transfer_type tt);
|
||||
|
||||
|
||||
int xusb_printf(const struct xusb_iface *iface, int level, int debug_mask,
|
||||
const char *prefix, const char *fmt, ...);
|
||||
|
||||
int xusb_printf_details(const struct xusb_iface *iface, int level, int debug_mask,
|
||||
const char *file, int line, const char *severity, const char *func,
|
||||
const char *fmt, ...);
|
||||
|
||||
#define XUSB_PRINT(iface, level, fmt, arg...) \
|
||||
xusb_printf(iface, LOG_ ## level, 0, #level ": ", fmt, ## arg)
|
||||
|
||||
#define XUSB_PRINT_DETAILS(iface, level, debug_mask, fmt, arg...) \
|
||||
xusb_printf_details(iface, LOG_ ## level, debug_mask, \
|
||||
__FILE__, __LINE__, #level, __func__, fmt, ## arg)
|
||||
|
||||
#define XUSB_INFO(iface, fmt, arg...) XUSB_PRINT(iface, INFO, fmt, ## arg)
|
||||
#define XUSB_ERR(iface, fmt, arg...) XUSB_PRINT_DETAILS(iface, ERR, 0, fmt, ## arg)
|
||||
#define XUSB_DBG(iface, fmt, arg...) XUSB_PRINT_DETAILS(iface, DEBUG, DBG_MASK, fmt, ## arg)
|
||||
|
||||
#endif /* XUSB_COMMON_H */
|
||||
843
xpp/xtalk/xusb_libusb.c
Normal file
843
xpp/xtalk/xusb_libusb.c
Normal file
@@ -0,0 +1,843 @@
|
||||
/*
|
||||
* 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 <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <assert.h>
|
||||
#include <errno.h>
|
||||
#include <stdarg.h>
|
||||
#include <syslog.h>
|
||||
#include <arpa/inet.h>
|
||||
#include <sys/time.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/ipc.h>
|
||||
#include <sys/sem.h>
|
||||
#include <usb.h>
|
||||
#include <xtalk/debug.h>
|
||||
#include <xtalk/xusb.h>
|
||||
#include <autoconfig.h>
|
||||
#include "xusb_common.h"
|
||||
|
||||
#define DBG_MASK 0x01
|
||||
#define TIMEOUT 500
|
||||
#define MAX_RETRIES 10
|
||||
|
||||
#define EP_IS_IN(ep) (((ep) & USB_ENDPOINT_DIR_MASK) == USB_ENDPOINT_IN)
|
||||
#define EP_IS_OUT(ep) (((ep) & USB_ENDPOINT_DIR_MASK) == USB_ENDPOINT_OUT)
|
||||
|
||||
struct libusb_implementation {
|
||||
struct usb_device *dev;
|
||||
usb_dev_handle *handle;
|
||||
struct usb_config_descriptor *config_desc;
|
||||
};
|
||||
|
||||
static void xusb_init();
|
||||
|
||||
/*
|
||||
* USB handling
|
||||
*/
|
||||
|
||||
static int get_usb_string(struct xusb_device *xusb_device, uint8_t item, char *buf)
|
||||
{
|
||||
char tmp[BUFSIZ];
|
||||
int ret;
|
||||
|
||||
if (!xusb_device->impl->handle) {
|
||||
ERR("%s: device closed\n", xusb_device->devpath_tail);
|
||||
return -ENXIO;
|
||||
}
|
||||
if (!item)
|
||||
return 0;
|
||||
ret = usb_get_string_simple(xusb_device->impl->handle, item, tmp, BUFSIZ);
|
||||
if (ret <= 0)
|
||||
return ret;
|
||||
return snprintf(buf, BUFSIZ, "%s", tmp);
|
||||
}
|
||||
|
||||
static const struct usb_interface_descriptor *get_iface_descriptor(
|
||||
const struct xusb_device *xusb_device, int i)
|
||||
{
|
||||
const struct usb_config_descriptor *config_desc;
|
||||
const struct usb_interface *interface;
|
||||
const struct usb_interface_descriptor *iface_desc;
|
||||
int num_altsetting;
|
||||
|
||||
assert(xusb_device);
|
||||
assert(xusb_device->impl);
|
||||
config_desc = xusb_device->impl->config_desc;
|
||||
assert(config_desc);
|
||||
assert(config_desc->bNumInterfaces < XUSB_MAX_INTERFACES);
|
||||
if (i >= XUSB_MAX_INTERFACES)
|
||||
return NULL;
|
||||
interface = &config_desc->interface[i];
|
||||
assert(interface != NULL);
|
||||
iface_desc = interface->altsetting;
|
||||
num_altsetting = interface->num_altsetting;
|
||||
assert(num_altsetting != 0);
|
||||
assert(iface_desc != NULL);
|
||||
return iface_desc;
|
||||
}
|
||||
|
||||
#define GET_USB_STRING(xusb_device, from, item) \
|
||||
get_usb_string((xusb_device), (from)->item, (xusb_device)->item)
|
||||
|
||||
static int xusb_fill_strings(struct xusb_device *xusb_device, int interface_num)
|
||||
{
|
||||
const struct usb_device_descriptor *dev_desc;
|
||||
const struct usb_interface_descriptor *iface_desc;
|
||||
struct xusb_iface *iface = xusb_device->interfaces[interface_num];
|
||||
int ret;
|
||||
|
||||
dev_desc = &xusb_device->impl->dev->descriptor;
|
||||
assert(dev_desc);
|
||||
ret = GET_USB_STRING(xusb_device, dev_desc, iManufacturer);
|
||||
if (ret < 0) {
|
||||
XUSB_ERR(iface, "Failed reading iManufacturer string: %s\n",
|
||||
usb_strerror());
|
||||
return 0;
|
||||
}
|
||||
ret = GET_USB_STRING(xusb_device, dev_desc, iProduct);
|
||||
if (ret < 0) {
|
||||
XUSB_ERR(iface, "Failed reading iProduct string: %s\n",
|
||||
usb_strerror());
|
||||
return 0;
|
||||
}
|
||||
ret = GET_USB_STRING(xusb_device, dev_desc, iSerialNumber);
|
||||
if (ret < 0) {
|
||||
XUSB_ERR(iface, "Failed reading iSerialNumber string: %s\n",
|
||||
usb_strerror());
|
||||
return 0;
|
||||
}
|
||||
iface_desc = get_iface_descriptor(xusb_device, interface_num);
|
||||
if (!iface_desc) {
|
||||
XUSB_ERR(iface, "Could not get interface descriptor of device\n");
|
||||
return 0;
|
||||
}
|
||||
ret = GET_USB_STRING(xusb_device, iface_desc, iInterface);
|
||||
if (ret < 0) {
|
||||
XUSB_ERR(iface, "Failed reading iInterface string: %s\n",
|
||||
usb_strerror());
|
||||
return 0;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int xusb_open(struct xusb_device *xusb_device)
|
||||
{
|
||||
int ret = 0;
|
||||
|
||||
assert(xusb_device);
|
||||
DBG("%s\n", xusb_device->devpath_tail);
|
||||
if (xusb_device->impl->handle) {
|
||||
ERR("%s: already open\n", xusb_device->devpath_tail);
|
||||
ret = -EBUSY;
|
||||
goto out;
|
||||
}
|
||||
xusb_device->impl->handle = usb_open(xusb_device->impl->dev);
|
||||
if (!xusb_device->impl->handle) {
|
||||
ERR("%s: Failed to open usb device: %s\n",
|
||||
xusb_device->devpath_tail,
|
||||
usb_strerror());
|
||||
xusb_device->impl->handle = NULL;
|
||||
goto out;
|
||||
}
|
||||
return 1;
|
||||
out:
|
||||
return ret;
|
||||
}
|
||||
|
||||
void xusb_release(struct xusb_iface *iface)
|
||||
{
|
||||
if (iface && iface->is_claimed) {
|
||||
usb_dev_handle *handle;
|
||||
int ret;
|
||||
|
||||
assert(iface->xusb_device);
|
||||
handle = iface->xusb_device->impl->handle;
|
||||
XUSB_DBG(iface, "Releasing interface\n");
|
||||
if (!handle) {
|
||||
XUSB_ERR(iface, "device closed\n");
|
||||
iface->is_claimed = 0;
|
||||
return;
|
||||
}
|
||||
ret = usb_release_interface(handle, iface->interface_num);
|
||||
if (ret < 0)
|
||||
XUSB_ERR(iface, "Releasing interface: %s\n",
|
||||
usb_strerror());
|
||||
iface->is_claimed = 0;
|
||||
}
|
||||
}
|
||||
|
||||
static int xusb_clear_halt(struct xusb_iface *xusb_iface)
|
||||
{
|
||||
struct xusb_device *xusb_device;
|
||||
int ret = 0;
|
||||
int ep;
|
||||
|
||||
xusb_device = xusb_iface->xusb_device;
|
||||
/*
|
||||
* WE DO NOT CALL HALT for problematic devices:
|
||||
* - It cause problem with our usb-dongle (cypress CY7C63803, interrupt driven)
|
||||
*/
|
||||
if (xusb_device->idVendor == 0xe4e4 && xusb_device->idProduct == 0x11a3) {
|
||||
XUSB_DBG(xusb_iface, "Skipping clear_halt()\n");
|
||||
goto out;
|
||||
}
|
||||
if (!xtalk_option_use_clear_halt()) {
|
||||
XUSB_DBG(xusb_iface, "Don't use clear_halt()\n");
|
||||
goto out;
|
||||
}
|
||||
ep = EP_OUT(xusb_iface);
|
||||
ret = usb_clear_halt(xusb_device->impl->handle, ep);
|
||||
if (ret < 0) {
|
||||
XUSB_ERR(xusb_iface, "Clearing output endpoint 0x%02X: %s\n",
|
||||
ep, usb_strerror());
|
||||
goto out;
|
||||
}
|
||||
ep = EP_IN(xusb_iface);
|
||||
ret = usb_clear_halt(xusb_device->impl->handle, ep);
|
||||
if (ret < 0) {
|
||||
XUSB_ERR(xusb_iface, "Clearing input endpoint 0x%02X: %s\n",
|
||||
ep, usb_strerror());
|
||||
goto out;
|
||||
}
|
||||
out:
|
||||
return ret;
|
||||
}
|
||||
|
||||
int xusb_claim(struct xusb_device *xusb_device, unsigned int interface_num,
|
||||
struct xusb_iface **xusb_iface)
|
||||
{
|
||||
struct xusb_iface *iface = NULL;
|
||||
enum xusb_transfer_type iface_tt = XUSB_TT_ILLEGAL;
|
||||
int ret = 0;
|
||||
|
||||
*xusb_iface = NULL;
|
||||
assert(xusb_device);
|
||||
if (!xusb_device->impl->handle) {
|
||||
XUSB_ERR(iface, "device closed\n");
|
||||
ret = -ENXIO;
|
||||
goto failed;
|
||||
}
|
||||
if (interface_num >= XUSB_MAX_INTERFACES) {
|
||||
ERR("%s: interface number %d is too big\n",
|
||||
xusb_device->devpath_tail, interface_num);
|
||||
ret = -EINVAL;
|
||||
goto failed;
|
||||
}
|
||||
iface = xusb_device->interfaces[interface_num];
|
||||
if (!iface) {
|
||||
ERR("%s: No interface number %d\n",
|
||||
xusb_device->devpath_tail, interface_num);
|
||||
ret = -EINVAL;
|
||||
goto failed;
|
||||
}
|
||||
if (iface->is_claimed) {
|
||||
XUSB_ERR(iface, "Already claimed\n");
|
||||
ret = -EBUSY;
|
||||
goto failed;
|
||||
}
|
||||
ret = usb_claim_interface(xusb_device->impl->handle, iface->interface_num);
|
||||
if (ret < 0) {
|
||||
XUSB_ERR(iface, "usb_claim_interface: %s\n", usb_strerror());
|
||||
goto failed;
|
||||
}
|
||||
iface->is_claimed = 1;
|
||||
iface_tt = xusb_transfer_type(iface);
|
||||
if (iface_tt == XUSB_TT_ILLEGAL) {
|
||||
ret = -ENOTSUP;
|
||||
goto failed;
|
||||
}
|
||||
iface->transfer_type = iface_tt;
|
||||
ret = xusb_clear_halt(iface);
|
||||
if (ret < 0)
|
||||
goto failed;
|
||||
ret = xusb_flushread(iface);
|
||||
if (ret < 0) {
|
||||
XUSB_ERR(iface, "xusb_flushread failed: %s\n", usb_strerror());
|
||||
goto failed;
|
||||
}
|
||||
xusb_fill_strings(xusb_device, interface_num);
|
||||
XUSB_DBG(iface, "ID=%04X:%04X Manufacturer=[%s] Product=[%s] "
|
||||
"SerialNumber=[%s] Interface=[%s] TT=%s\n",
|
||||
xusb_device->idVendor,
|
||||
xusb_device->idProduct,
|
||||
xusb_device->iManufacturer,
|
||||
xusb_device->iProduct,
|
||||
xusb_device->iSerialNumber,
|
||||
iface->iInterface,
|
||||
xusb_tt_name(iface->transfer_type));
|
||||
*xusb_iface = iface;
|
||||
return 0;
|
||||
failed:
|
||||
xusb_release(iface);
|
||||
return ret;
|
||||
}
|
||||
|
||||
void xusb_destroy(struct xusb_device *xusb_device)
|
||||
{
|
||||
if (xusb_device) {
|
||||
struct xusb_iface **piface;
|
||||
struct libusb_implementation *impl;
|
||||
|
||||
for (piface = xusb_device->interfaces; *piface; piface++) {
|
||||
xusb_destroy_interface(*piface);
|
||||
*piface = NULL;
|
||||
}
|
||||
impl = xusb_device->impl;
|
||||
if (impl) {
|
||||
if (impl->handle) {
|
||||
xusb_close(xusb_device);
|
||||
impl->handle = NULL;
|
||||
}
|
||||
}
|
||||
DBG("%s: MEM: FREE device\n", xusb_device->devpath_tail);
|
||||
memset(xusb_device, 0, sizeof(*xusb_device));
|
||||
free(xusb_device);
|
||||
xusb_device = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
static int init_interfaces(struct xusb_device *xusb_device)
|
||||
{
|
||||
const struct usb_config_descriptor *config_desc;
|
||||
const struct usb_interface_descriptor *iface_desc;
|
||||
struct xusb_iface *iface;
|
||||
int max_packet_size = 0;
|
||||
int packet_size;
|
||||
int if_idx;
|
||||
|
||||
assert(xusb_device);
|
||||
assert(xusb_device->impl);
|
||||
config_desc = xusb_device->impl->config_desc;
|
||||
assert(config_desc);
|
||||
assert(config_desc->bNumInterfaces < XUSB_MAX_INTERFACES);
|
||||
for (if_idx = 0; if_idx < config_desc->bNumInterfaces; if_idx++) {
|
||||
int ep_idx;
|
||||
|
||||
iface_desc = get_iface_descriptor(xusb_device, if_idx);
|
||||
if (iface_desc->bInterfaceNumber != if_idx) {
|
||||
ERR("%s: interface %d is number %d\n",
|
||||
xusb_device->devpath_tail,
|
||||
if_idx, iface_desc->bInterfaceNumber);
|
||||
return -EINVAL;
|
||||
}
|
||||
if (iface_desc->bNumEndpoints != 2) {
|
||||
ERR("%s: interface %d has %d endpoints\n",
|
||||
xusb_device->devpath_tail,
|
||||
if_idx, iface_desc->bNumEndpoints);
|
||||
return -EINVAL;
|
||||
}
|
||||
iface = calloc(sizeof(*iface), 1);
|
||||
if (!iface) {
|
||||
ERR("%s: interface %d -- out of memory\n",
|
||||
xusb_device->devpath_tail, if_idx);
|
||||
return -ENOMEM;
|
||||
}
|
||||
DBG("MEM: ALLOC interface: %p\n", iface);
|
||||
xusb_device->interfaces[if_idx] = iface;
|
||||
iface->xusb_device = xusb_device;
|
||||
iface->interface_num = iface_desc->bInterfaceNumber;
|
||||
|
||||
/* Search Endpoints */
|
||||
iface->ep_in = 0;
|
||||
iface->ep_out = 0;
|
||||
for (ep_idx = 0; ep_idx < iface_desc->bNumEndpoints; ep_idx++) {
|
||||
int ep_num;
|
||||
|
||||
ep_num = iface_desc->endpoint[ep_idx].bEndpointAddress;
|
||||
packet_size = iface_desc->endpoint[ep_idx].wMaxPacketSize;
|
||||
if (!max_packet_size || packet_size < max_packet_size)
|
||||
max_packet_size = packet_size;
|
||||
if (EP_IS_OUT(ep_num))
|
||||
iface->ep_out = ep_num;
|
||||
if (EP_IS_IN(ep_num))
|
||||
iface->ep_in = ep_num;
|
||||
}
|
||||
/* Validation */
|
||||
if (!iface->ep_out) {
|
||||
ERR("%s[%d]: Missing output endpoint\n",
|
||||
xusb_device->devpath_tail, if_idx);
|
||||
return -EINVAL;
|
||||
}
|
||||
if (!iface->ep_in) {
|
||||
ERR("%s[%d]: Missing input endpoint\n",
|
||||
xusb_device->devpath_tail, if_idx);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
iface->is_claimed = 0;
|
||||
XUSB_DBG(iface, "ep_out=0x%X ep_in=0x%X packet_size=%d\n",
|
||||
iface->ep_out, iface->ep_in, max_packet_size);
|
||||
}
|
||||
if (xusb_device->packet_size < max_packet_size)
|
||||
xusb_device->packet_size = max_packet_size;
|
||||
xusb_device->is_usb2 = (xusb_device->packet_size == 512);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct xusb_device *xusb_new(struct usb_device *dev,
|
||||
const struct xusb_spec *spec,
|
||||
xusb_filter_t filterfunc,
|
||||
void *data)
|
||||
{
|
||||
struct usb_device_descriptor *dev_desc;
|
||||
int ret;
|
||||
struct xusb_device *xusb_device = NULL;
|
||||
|
||||
xusb_device = calloc(sizeof(*xusb_device) + sizeof(struct libusb_implementation), 1);
|
||||
if (!xusb_device) {
|
||||
ERR("Out of memory");
|
||||
goto fail;
|
||||
}
|
||||
DBG("MEM: ALLOC device: %p\n", xusb_device);
|
||||
/* Fill xusb_device */
|
||||
xusb_device->impl = (void *)xusb_device + sizeof(*xusb_device);
|
||||
xusb_device->impl->dev = dev;
|
||||
xusb_device->spec = spec;
|
||||
/*
|
||||
* Get information from the usb_device
|
||||
*/
|
||||
dev_desc = &dev->descriptor;
|
||||
if (!dev_desc) {
|
||||
ERR("usb device without a device descriptor\n");
|
||||
goto fail;
|
||||
}
|
||||
xusb_device->idVendor = dev_desc->idVendor;
|
||||
xusb_device->idProduct = dev_desc->idProduct;
|
||||
sscanf(dev->bus->dirname, "%d", &xusb_device->bus_num);
|
||||
sscanf(dev->filename, "%d", &xusb_device->device_num);
|
||||
snprintf(xusb_device->devpath_tail, PATH_MAX, "%03d/%03d",
|
||||
xusb_device->bus_num, xusb_device->device_num);
|
||||
if (!match_device(xusb_device, spec)) {
|
||||
DBG("[%04X:%04X] did not match\n",
|
||||
xusb_device->idVendor, xusb_device->idProduct);
|
||||
goto fail;
|
||||
}
|
||||
xusb_device->impl->config_desc = dev->config;
|
||||
if (!xusb_device->impl->config_desc) {
|
||||
ERR("usb device without a configuration descriptor\n");
|
||||
goto fail;
|
||||
}
|
||||
ret = init_interfaces(xusb_device);
|
||||
if (ret < 0) {
|
||||
ERR("%s: init_interfaces() failed (ret = %d)\n",
|
||||
xusb_device->devpath_tail, ret);
|
||||
goto fail;
|
||||
}
|
||||
if (!xusb_open(xusb_device)) {
|
||||
ERR("%s: Failed opening device: %04X:%04X\n",
|
||||
xusb_device->devpath_tail,
|
||||
xusb_device->idVendor,
|
||||
xusb_device->idProduct);
|
||||
goto fail;
|
||||
}
|
||||
DBG("%s: %04X:%04X\n",
|
||||
xusb_device->devpath_tail,
|
||||
xusb_device->idVendor,
|
||||
xusb_device->idProduct);
|
||||
return xusb_device;
|
||||
fail:
|
||||
xusb_destroy(xusb_device);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
struct xusb_iface *xusb_find_iface(const char *devpath,
|
||||
int iface_num,
|
||||
int ep_out,
|
||||
int ep_in,
|
||||
struct xusb_spec *dummy_spec)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
struct xusb_device *xusb_find_bypath(const char *path)
|
||||
{
|
||||
struct usb_bus *bus;
|
||||
struct usb_device *dev;
|
||||
char devpath_tail[PATH_MAX];
|
||||
struct xusb_spec *spec;
|
||||
|
||||
DBG("path='%s'\n", path);
|
||||
spec = calloc(sizeof(*spec), 1);
|
||||
if (!spec) {
|
||||
ERR("Failed allocating spec\n");
|
||||
goto failed;
|
||||
}
|
||||
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 xusb_device *xusb_device = NULL;
|
||||
|
||||
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);
|
||||
snprintf(devpath_tail, PATH_MAX, "%3s/%3s",
|
||||
dev->bus->dirname, dev->filename);
|
||||
if (!match_devpath(path, devpath_tail))
|
||||
continue;
|
||||
DBG("Found: usb:%s/%s: ID=%04X:%04X\n",
|
||||
dev->bus->dirname,
|
||||
dev->filename,
|
||||
dev_desc->idVendor,
|
||||
dev_desc->idProduct);
|
||||
xusb_init_spec(spec, "<BYPATH>",
|
||||
dev_desc->idVendor, dev_desc->idProduct);
|
||||
xusb_device = xusb_new(dev, spec, NULL, NULL);
|
||||
if (!xusb_device) {
|
||||
ERR("Failed creating xusb for %s\n",
|
||||
devpath_tail);
|
||||
xusb_init_spec(spec, "<EMPTY>", 0, 0);
|
||||
continue;
|
||||
}
|
||||
return xusb_device;
|
||||
}
|
||||
}
|
||||
failed:
|
||||
if (spec)
|
||||
free(spec);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
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 failed;
|
||||
}
|
||||
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_device *xusb_device;
|
||||
const struct xusb_spec *sp = &specs[i];
|
||||
|
||||
xusb_device = xusb_new(dev, sp, filterfunc, data);
|
||||
if (!xusb_device)
|
||||
continue;
|
||||
if (filterfunc && !filterfunc(xusb_device, data)) {
|
||||
DBG("%s: %04X:%04X filtered out\n",
|
||||
xusb_device->devpath_tail,
|
||||
dev_desc->idVendor,
|
||||
dev_desc->idProduct);
|
||||
xusb_destroy(xusb_device);
|
||||
continue;
|
||||
}
|
||||
item = xlist_new(xusb_device);
|
||||
xlist_append_item(xlist, item);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
xusb_list_dump(xlist);
|
||||
return xlist;
|
||||
failed:
|
||||
if (xlist)
|
||||
xlist_destroy(xlist, NULL);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void xusb_showinfo(const struct xusb_device *xusb_device)
|
||||
{
|
||||
struct usb_device_descriptor *dev_desc;
|
||||
struct usb_device *dev;
|
||||
const struct xusb_iface **piface;
|
||||
|
||||
assert(xusb_device);
|
||||
dev = xusb_device->impl->dev;
|
||||
assert(dev);
|
||||
dev_desc = &dev->descriptor;
|
||||
assert(dev_desc);
|
||||
if (verbose <= LOG_INFO) {
|
||||
INFO("%s: [%04X:%04X] [%s / %s / %s]\n",
|
||||
xusb_device->devpath_tail,
|
||||
dev_desc->idVendor,
|
||||
dev_desc->idProduct,
|
||||
xusb_device->iManufacturer,
|
||||
xusb_device->iProduct,
|
||||
xusb_device->iSerialNumber);
|
||||
} else {
|
||||
printf("USB Bus/Device: [%s/%s] (%s)\n",
|
||||
dev->bus->dirname,
|
||||
dev->filename,
|
||||
(xusb_device->impl->handle) ? "open" : "closed");
|
||||
printf("USB Spec name: [%s]\n", xusb_device->spec->name);
|
||||
printf("USB iManufacturer: [%s]\n", xusb_device->iManufacturer);
|
||||
printf("USB iProduct: [%s]\n", xusb_device->iProduct);
|
||||
printf("USB iSerialNumber: [%s]\n", xusb_device->iSerialNumber);
|
||||
piface = (const struct xusb_iface **)xusb_device->interfaces;
|
||||
for (; *piface; piface++) {
|
||||
printf("USB Interface[%d]: ep_out=0x%02X ep_in=0x%02X claimed=%d [%s]\n",
|
||||
(*piface)->interface_num,
|
||||
(*piface)->ep_out,
|
||||
(*piface)->ep_in,
|
||||
(*piface)->is_claimed,
|
||||
(*piface)->iInterface);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int xusb_close(struct xusb_device *xusb_device)
|
||||
{
|
||||
if (xusb_device && xusb_device->impl && xusb_device->impl->handle) {
|
||||
assert(xusb_device->spec);
|
||||
assert(xusb_device->spec->name);
|
||||
DBG("%s: Closing device \"%s\"\n",
|
||||
xusb_device->devpath_tail,
|
||||
xusb_device->spec->name);
|
||||
usb_close(xusb_device->impl->handle);
|
||||
xusb_device->impl->handle = NULL;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
enum xusb_transfer_type xusb_transfer_type(const struct xusb_iface *iface)
|
||||
{
|
||||
const struct xusb_device *xusb_device;
|
||||
const struct usb_interface_descriptor *iface_desc;
|
||||
const struct usb_endpoint_descriptor *ep;
|
||||
enum xusb_transfer_type ret = XUSB_TT_ILLEGAL;
|
||||
|
||||
assert(iface);
|
||||
xusb_device = iface->xusb_device;
|
||||
assert(xusb_device);
|
||||
iface_desc = get_iface_descriptor(xusb_device, iface->interface_num);
|
||||
assert(iface_desc);
|
||||
ep = iface_desc->endpoint;
|
||||
assert(ep);
|
||||
switch (ep->bmAttributes) {
|
||||
case USB_ENDPOINT_TYPE_CONTROL:
|
||||
case USB_ENDPOINT_TYPE_ISOCHRONOUS:
|
||||
break;
|
||||
case USB_ENDPOINT_TYPE_BULK:
|
||||
ret = XUSB_TT_BULK;
|
||||
break;
|
||||
case USB_ENDPOINT_TYPE_INTERRUPT:
|
||||
ret = XUSB_TT_INTERRUPT;
|
||||
break;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
int xusb_send(struct xusb_iface *iface, const char *buf, int len, int timeout)
|
||||
{
|
||||
struct xusb_device *xusb_device = iface->xusb_device;
|
||||
int ep_out = EP_OUT(iface);
|
||||
int retries = 0;
|
||||
int ret;
|
||||
|
||||
dump_packet(LOG_DEBUG, DBG_MASK, __func__, buf, len);
|
||||
if (!xusb_device->impl->handle) {
|
||||
XUSB_ERR(iface, "device closed\n");
|
||||
return -ENXIO;
|
||||
}
|
||||
if (!EP_IS_OUT(ep_out)) {
|
||||
XUSB_ERR(iface, "%s called with an input endpoint 0x%x\n",
|
||||
__func__, ep_out);
|
||||
return -EINVAL;
|
||||
}
|
||||
retry_write:
|
||||
switch (iface->transfer_type) {
|
||||
case XUSB_TT_BULK:
|
||||
ret = usb_bulk_write(xusb_device->impl->handle, ep_out, (char *)buf, len, timeout);
|
||||
break;
|
||||
case XUSB_TT_INTERRUPT:
|
||||
ret = usb_interrupt_write(xusb_device->impl->handle, ep_out, (char *)buf, len, timeout);
|
||||
break;
|
||||
default:
|
||||
ret = -EINVAL;
|
||||
break;
|
||||
}
|
||||
if (ret < 0) {
|
||||
/*
|
||||
* If the device was gone, it may be the
|
||||
* result of renumeration. Ignore it.
|
||||
*/
|
||||
if (ret != -ENODEV) {
|
||||
XUSB_ERR(iface, "write to endpoint 0x%x failed: (%d) %s\n",
|
||||
ep_out, ret, usb_strerror());
|
||||
dump_packet(LOG_ERR, DBG_MASK, "xusb_send[ERR]",
|
||||
buf, len);
|
||||
/*exit(2);*/
|
||||
} else {
|
||||
XUSB_DBG(iface, "write to endpoint 0x%x got ENODEV\n",
|
||||
ep_out);
|
||||
xusb_close(xusb_device);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
if (!ret) {
|
||||
|
||||
XUSB_ERR(iface, "write to endpoint 0x%x short write[%d]: (%d)\n",
|
||||
ep_out, retries, ret);
|
||||
if (retries++ > MAX_RETRIES)
|
||||
return -EFAULT;
|
||||
usleep(100);
|
||||
goto retry_write;
|
||||
}
|
||||
if (ret != len) {
|
||||
XUSB_ERR(iface, "write to endpoint 0x%x short write: (%d) %s\n",
|
||||
ep_out, ret, usb_strerror());
|
||||
dump_packet(LOG_ERR, DBG_MASK, "xusb_send[ERR]", buf, len);
|
||||
return -EFAULT;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
int xusb_recv(struct xusb_iface *iface, char *buf, size_t len, int timeout)
|
||||
{
|
||||
struct xusb_device *xusb_device = iface->xusb_device;
|
||||
int ep_in = EP_IN(iface);
|
||||
int retries = 0;
|
||||
int ret;
|
||||
|
||||
if (!xusb_device->impl->handle) {
|
||||
XUSB_ERR(iface, "device closed\n");
|
||||
return -ENXIO;
|
||||
}
|
||||
if (!EP_IS_IN(ep_in)) {
|
||||
XUSB_ERR(iface, "called with an output endpoint 0x%x\n", ep_in);
|
||||
return -EINVAL;
|
||||
}
|
||||
retry_read:
|
||||
switch (iface->transfer_type) {
|
||||
case XUSB_TT_BULK:
|
||||
ret = usb_bulk_read(xusb_device->impl->handle, ep_in, buf, len, timeout);
|
||||
break;
|
||||
case XUSB_TT_INTERRUPT:
|
||||
ret = usb_interrupt_read(xusb_device->impl->handle, ep_in, buf, len, timeout);
|
||||
break;
|
||||
default:
|
||||
ret = -EAFNOSUPPORT;
|
||||
break;
|
||||
}
|
||||
if (ret < 0) {
|
||||
XUSB_DBG(iface, "read from endpoint 0x%x failed: (%d) %s\n",
|
||||
ep_in, ret, usb_strerror());
|
||||
memset(buf, 0, len);
|
||||
return ret;
|
||||
}
|
||||
if (!ret) {
|
||||
XUSB_ERR(iface, "read to endpoint 0x%x short read[%d]: (%d)\n",
|
||||
ep_in, retries, ret);
|
||||
if (retries++ > MAX_RETRIES)
|
||||
return -EFAULT;
|
||||
usleep(100);
|
||||
goto retry_read;
|
||||
}
|
||||
dump_packet(LOG_DEBUG, DBG_MASK, __func__, buf, ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*
|
||||
* 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;
|
||||
|
||||
void __attribute__((constructor)) xusb_init(void)
|
||||
{
|
||||
xtalk_parse_options();
|
||||
if (!getenv("XUSB_NOLOCK"))
|
||||
xusb_lock_usb();
|
||||
if (!initizalized) {
|
||||
usb_init();
|
||||
initizalized = 1;
|
||||
}
|
||||
usb_find_busses();
|
||||
usb_find_devices();
|
||||
if (!getenv("XUSB_NOLOCK"))
|
||||
xusb_unlock_usb();
|
||||
}
|
||||
826
xpp/xtalk/xusb_libusbx.c
Normal file
826
xpp/xtalk/xusb_libusbx.c
Normal file
@@ -0,0 +1,826 @@
|
||||
/*
|
||||
* Written by Oron Peled <oron@actcom.co.il>
|
||||
* Copyright (C) 2012, 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 <stdarg.h>
|
||||
#include <syslog.h>
|
||||
#include <arpa/inet.h>
|
||||
#include <libusb.h>
|
||||
#include <xtalk/debug.h>
|
||||
#include <xtalk/xusb.h>
|
||||
#include <autoconfig.h>
|
||||
#include "xusb_common.h"
|
||||
|
||||
#define DBG_MASK 0x01
|
||||
#define TIMEOUT 500
|
||||
|
||||
#define EP_IS_IN(ep) (((ep) & LIBUSB_ENDPOINT_DIR_MASK) == LIBUSB_ENDPOINT_IN)
|
||||
#define EP_IS_OUT(ep) (((ep) & LIBUSB_ENDPOINT_DIR_MASK) == LIBUSB_ENDPOINT_OUT)
|
||||
|
||||
struct libusb_implementation {
|
||||
struct libusb_device *dev;
|
||||
struct libusb_device_handle *handle;
|
||||
struct libusb_config_descriptor *config_desc;
|
||||
};
|
||||
|
||||
void __attribute__((constructor)) xusb_init(void)
|
||||
{
|
||||
int ret;
|
||||
|
||||
xtalk_parse_options();
|
||||
ret = libusb_init(NULL);
|
||||
if (ret < 0) {
|
||||
ERR("libusb_init() failed: ret=%d\n", ret);
|
||||
abort();
|
||||
}
|
||||
}
|
||||
|
||||
void __attribute__((destructor)) xusb_fini(void)
|
||||
{
|
||||
libusb_exit(NULL);
|
||||
}
|
||||
|
||||
/*
|
||||
* Translate libusbx error codes to regular errno
|
||||
*/
|
||||
static int errno_map(int libusb_err)
|
||||
{
|
||||
int ret = -libusb_err;
|
||||
#define ERRNO_MAP(libusb, errno) [-(libusb)] = errno
|
||||
static const int error_codes[] = {
|
||||
ERRNO_MAP(LIBUSB_SUCCESS, 0),
|
||||
ERRNO_MAP(LIBUSB_ERROR_IO, EIO),
|
||||
ERRNO_MAP(LIBUSB_ERROR_INVALID_PARAM, EINVAL),
|
||||
ERRNO_MAP(LIBUSB_ERROR_ACCESS, EACCES),
|
||||
ERRNO_MAP(LIBUSB_ERROR_NO_DEVICE, ENODEV),
|
||||
ERRNO_MAP(LIBUSB_ERROR_NOT_FOUND, ENOENT),
|
||||
ERRNO_MAP(LIBUSB_ERROR_BUSY, EBUSY),
|
||||
ERRNO_MAP(LIBUSB_ERROR_TIMEOUT, ETIMEDOUT),
|
||||
ERRNO_MAP(LIBUSB_ERROR_OVERFLOW, EOVERFLOW),
|
||||
ERRNO_MAP(LIBUSB_ERROR_PIPE, EPIPE),
|
||||
ERRNO_MAP(LIBUSB_ERROR_INTERRUPTED, EINTR),
|
||||
ERRNO_MAP(LIBUSB_ERROR_NO_MEM, ENOMSG),
|
||||
ERRNO_MAP(LIBUSB_ERROR_NOT_SUPPORTED, ENOTSUP),
|
||||
ERRNO_MAP(LIBUSB_ERROR_OTHER, EPROTO),
|
||||
};
|
||||
#undef ERRNO_MAP
|
||||
if (ret < 0 || ret > sizeof(error_codes)/sizeof(error_codes[0])) {
|
||||
ERR("%s: Bad return code %d\n", __func__, -ret);
|
||||
return -EPROTO;
|
||||
}
|
||||
return -(error_codes[ret]);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* USB handling
|
||||
*/
|
||||
|
||||
static int get_usb_string(struct xusb_device *xusb_device, uint8_t item, char *buf)
|
||||
{
|
||||
unsigned char tmp[BUFSIZ];
|
||||
int ret;
|
||||
|
||||
if (!xusb_device->impl->handle) {
|
||||
ERR("%s: device closed\n", xusb_device->devpath_tail);
|
||||
return -ENXIO;
|
||||
}
|
||||
if (!item)
|
||||
return 0;
|
||||
ret = libusb_get_string_descriptor_ascii(xusb_device->impl->handle, item,
|
||||
tmp, BUFSIZ);
|
||||
if (ret <= 0)
|
||||
return errno_map(ret);
|
||||
return snprintf(buf, BUFSIZ, "%s", tmp);
|
||||
}
|
||||
|
||||
static const struct libusb_interface_descriptor *get_iface_descriptor(
|
||||
const struct xusb_device *xusb_device, int i)
|
||||
{
|
||||
const struct libusb_config_descriptor *config_desc;
|
||||
const struct libusb_interface *interface;
|
||||
const struct libusb_interface_descriptor *iface_desc;
|
||||
|
||||
assert(xusb_device);
|
||||
assert(xusb_device->impl);
|
||||
config_desc = xusb_device->impl->config_desc;
|
||||
assert(config_desc);
|
||||
assert(config_desc->bNumInterfaces < XUSB_MAX_INTERFACES);
|
||||
if (i >= XUSB_MAX_INTERFACES)
|
||||
return NULL;
|
||||
interface = &config_desc->interface[i];
|
||||
iface_desc = interface->altsetting;
|
||||
return iface_desc;
|
||||
}
|
||||
|
||||
#define GET_USB_STRING(xusb_device, from, item) \
|
||||
get_usb_string((xusb_device), (from)->item, (xusb_device)->item)
|
||||
|
||||
static int xusb_fill_strings(struct xusb_device *xusb_device, int interface_num)
|
||||
{
|
||||
struct libusb_device_descriptor dev_desc;
|
||||
const struct libusb_interface_descriptor *iface_desc;
|
||||
struct xusb_iface *iface = xusb_device->interfaces[interface_num];
|
||||
int ret;
|
||||
|
||||
assert(xusb_device);
|
||||
assert(xusb_device->impl);
|
||||
ret = libusb_get_device_descriptor(xusb_device->impl->dev, &dev_desc);
|
||||
if (ret) {
|
||||
XUSB_ERR(iface, "libusb_get_device_descriptor() failed: %s\n",
|
||||
libusb_error_name(ret));
|
||||
return errno_map(ret);
|
||||
}
|
||||
ret = GET_USB_STRING(xusb_device, &dev_desc, iManufacturer);
|
||||
if (ret < 0) {
|
||||
XUSB_ERR(iface, "Failed reading iManufacturer string: %s\n",
|
||||
libusb_error_name(ret));
|
||||
return 0;
|
||||
}
|
||||
ret = GET_USB_STRING(xusb_device, &dev_desc, iProduct);
|
||||
if (ret < 0) {
|
||||
XUSB_ERR(iface, "Failed reading iProduct string: %s\n",
|
||||
libusb_error_name(ret));
|
||||
return 0;
|
||||
}
|
||||
ret = GET_USB_STRING(xusb_device, &dev_desc, iSerialNumber);
|
||||
if (ret < 0) {
|
||||
XUSB_ERR(iface, "Failed reading iSerialNumber string: %s\n",
|
||||
libusb_error_name(ret));
|
||||
return 0;
|
||||
}
|
||||
iface_desc = get_iface_descriptor(xusb_device, interface_num);
|
||||
if (!iface_desc) {
|
||||
XUSB_ERR(iface, "Could not get interface descriptor of device\n");
|
||||
return 0;
|
||||
}
|
||||
ret = get_usb_string(xusb_device, iface_desc->iInterface, iface->iInterface);
|
||||
if (ret < 0) {
|
||||
XUSB_ERR(iface, "Failed reading iInterface string: %s\n",
|
||||
libusb_error_name(ret));
|
||||
return 0;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int xusb_open(struct xusb_device *xusb_device)
|
||||
{
|
||||
int ret = 0;
|
||||
|
||||
DBG("%s\n", xusb_device->devpath_tail);
|
||||
if (xusb_device->impl->handle) {
|
||||
ERR("%s: already open\n", xusb_device->devpath_tail);
|
||||
ret = -EBUSY;
|
||||
goto out;
|
||||
}
|
||||
ret = libusb_open(xusb_device->impl->dev, &(xusb_device->impl->handle));
|
||||
if (ret < 0) {
|
||||
ERR("%s: Failed to open usb device: %s\n",
|
||||
xusb_device->devpath_tail,
|
||||
libusb_error_name(ret));
|
||||
ret = errno_map(ret);
|
||||
xusb_device->impl->handle = NULL;
|
||||
goto out;
|
||||
}
|
||||
out:
|
||||
return ret;
|
||||
}
|
||||
|
||||
void xusb_release(struct xusb_iface *iface)
|
||||
{
|
||||
if (iface && iface->is_claimed) {
|
||||
struct libusb_device_handle *handle;
|
||||
|
||||
assert(iface->xusb_device);
|
||||
handle = iface->xusb_device->impl->handle;
|
||||
XUSB_DBG(iface, "Releasing interface\n");
|
||||
if (!handle) {
|
||||
XUSB_ERR(iface, "device closed\n");
|
||||
iface->is_claimed = 0;
|
||||
return;
|
||||
}
|
||||
int ret = libusb_release_interface(handle, iface->interface_num);
|
||||
if (ret < 0)
|
||||
XUSB_ERR(iface, "Releasing interface: %s\n",
|
||||
libusb_error_name(ret));
|
||||
iface->is_claimed = 0;
|
||||
}
|
||||
}
|
||||
|
||||
static int xusb_clear_halt(struct xusb_iface *xusb_iface)
|
||||
{
|
||||
struct xusb_device *xusb_device;
|
||||
int ret = 0;
|
||||
int ep;
|
||||
|
||||
xusb_device = xusb_iface->xusb_device;
|
||||
/*
|
||||
* WE DO NOT CALL HALT for problematic devices:
|
||||
* - It cause problem with our usb-dongle (cypress CY7C63803, interrupt driven)
|
||||
*/
|
||||
if (xusb_device->idVendor == 0xe4e4 && xusb_device->idProduct == 0x11a3) {
|
||||
XUSB_DBG(xusb_iface, "Skipping clear_halt()\n");
|
||||
goto out;
|
||||
}
|
||||
if (!xtalk_option_use_clear_halt()) {
|
||||
XUSB_DBG(xusb_iface, "Don't use clear_halt()\n");
|
||||
goto out;
|
||||
}
|
||||
ep = EP_OUT(xusb_iface);
|
||||
ret = libusb_clear_halt(xusb_device->impl->handle, ep);
|
||||
if (ret < 0) {
|
||||
XUSB_ERR(xusb_iface, "Clearing output endpoint 0x%02X: %s\n",
|
||||
ep, libusb_error_name(ret));
|
||||
ret = errno_map(ret);
|
||||
goto out;
|
||||
}
|
||||
ep = EP_IN(xusb_iface);
|
||||
ret = libusb_clear_halt(xusb_device->impl->handle, ep);
|
||||
if (ret < 0) {
|
||||
XUSB_ERR(xusb_iface, "Clearing input endpoint 0x%02X: %s\n",
|
||||
ep, libusb_error_name(ret));
|
||||
ret = errno_map(ret);
|
||||
goto out;
|
||||
}
|
||||
out:
|
||||
return ret;
|
||||
}
|
||||
|
||||
int xusb_claim(struct xusb_device *xusb_device, unsigned int interface_num,
|
||||
struct xusb_iface **xusb_iface)
|
||||
{
|
||||
struct xusb_iface *iface = NULL;
|
||||
enum xusb_transfer_type iface_tt = XUSB_TT_ILLEGAL;
|
||||
int ret = 0;
|
||||
|
||||
*xusb_iface = NULL;
|
||||
assert(xusb_device);
|
||||
if (!xusb_device->impl->handle) {
|
||||
ERR("%s: device closed\n", xusb_device->devpath_tail);
|
||||
return -ENXIO;
|
||||
}
|
||||
if (interface_num >= XUSB_MAX_INTERFACES) {
|
||||
ERR("%s: interface number %d is too big\n",
|
||||
xusb_device->devpath_tail, interface_num);
|
||||
ret = -EINVAL;
|
||||
goto failed;
|
||||
}
|
||||
iface = xusb_device->interfaces[interface_num];
|
||||
if (!iface) {
|
||||
ERR("%s: No interface number %d\n",
|
||||
xusb_device->devpath_tail, interface_num);
|
||||
ret = -EINVAL;
|
||||
goto failed;
|
||||
}
|
||||
if (iface->is_claimed) {
|
||||
XUSB_ERR(iface, "Already claimed\n");
|
||||
ret = -EBUSY;
|
||||
goto failed;
|
||||
}
|
||||
ret = libusb_claim_interface(xusb_device->impl->handle, iface->interface_num);
|
||||
if (ret < 0) {
|
||||
XUSB_ERR(iface, "libusb_claim_interface: %s\n",
|
||||
libusb_error_name(ret));
|
||||
ret = errno_map(ret);
|
||||
goto failed;
|
||||
}
|
||||
iface->is_claimed = 1;
|
||||
iface_tt = xusb_transfer_type(iface);
|
||||
if (iface_tt == XUSB_TT_ILLEGAL) {
|
||||
ret = -ENOTSUP;
|
||||
goto failed;
|
||||
}
|
||||
iface->transfer_type = iface_tt;
|
||||
xusb_fill_strings(xusb_device, interface_num);
|
||||
XUSB_DBG(iface, "ID=%04X:%04X Manufacturer=[%s] Product=[%s] "
|
||||
"SerialNumber=[%s] Interface=[%s] TT=%s\n",
|
||||
xusb_device->idVendor,
|
||||
xusb_device->idProduct,
|
||||
xusb_device->iManufacturer,
|
||||
xusb_device->iProduct,
|
||||
xusb_device->iSerialNumber,
|
||||
iface->iInterface,
|
||||
xusb_tt_name(iface->transfer_type));
|
||||
ret = xusb_clear_halt(iface);
|
||||
if (ret < 0)
|
||||
goto failed;
|
||||
ret = xusb_flushread(iface);
|
||||
if (ret < 0) {
|
||||
XUSB_ERR(iface, "xusb_flushread failed: %d\n", ret);
|
||||
goto failed;
|
||||
}
|
||||
*xusb_iface = iface;
|
||||
return 0;
|
||||
failed:
|
||||
if (iface)
|
||||
xusb_release(iface);
|
||||
return ret;
|
||||
}
|
||||
|
||||
void xusb_destroy(struct xusb_device *xusb_device)
|
||||
{
|
||||
if (xusb_device) {
|
||||
struct xusb_iface **piface;
|
||||
struct libusb_implementation *impl;
|
||||
|
||||
for (piface = xusb_device->interfaces; *piface; piface++) {
|
||||
xusb_destroy_interface(*piface);
|
||||
*piface = NULL;
|
||||
}
|
||||
impl = xusb_device->impl;
|
||||
if (impl) {
|
||||
if (impl->handle) {
|
||||
xusb_close(xusb_device);
|
||||
impl->handle = NULL;
|
||||
}
|
||||
if (impl->config_desc)
|
||||
libusb_free_config_descriptor(impl->config_desc);
|
||||
}
|
||||
DBG("%s: MEM: FREE device\n", xusb_device->devpath_tail);
|
||||
memset(xusb_device, 0, sizeof(*xusb_device));
|
||||
free(xusb_device);
|
||||
xusb_device = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
static int init_interfaces(struct xusb_device *xusb_device)
|
||||
{
|
||||
const struct libusb_config_descriptor *config_desc;
|
||||
const struct libusb_interface_descriptor *iface_desc;
|
||||
struct xusb_iface *iface;
|
||||
int max_packet_size = 0;
|
||||
int packet_size;
|
||||
int if_idx;
|
||||
|
||||
assert(xusb_device);
|
||||
assert(xusb_device->impl);
|
||||
config_desc = xusb_device->impl->config_desc;
|
||||
assert(config_desc->bNumInterfaces < XUSB_MAX_INTERFACES);
|
||||
for (if_idx = 0; if_idx < config_desc->bNumInterfaces; if_idx++) {
|
||||
int ep_idx;
|
||||
|
||||
iface_desc = get_iface_descriptor(xusb_device, if_idx);
|
||||
if (iface_desc->bInterfaceNumber != if_idx) {
|
||||
ERR("%s: interface %d is number %d\n",
|
||||
xusb_device->devpath_tail,
|
||||
if_idx, iface_desc->bInterfaceNumber);
|
||||
return -EINVAL;
|
||||
}
|
||||
if (iface_desc->bNumEndpoints != 2) {
|
||||
ERR("%s: interface %d has %d endpoints\n",
|
||||
xusb_device->devpath_tail,
|
||||
if_idx, iface_desc->bNumEndpoints);
|
||||
return -EINVAL;
|
||||
}
|
||||
iface = calloc(sizeof(*iface), 1);
|
||||
if (!iface) {
|
||||
ERR("%s: interface %d -- out of memory\n",
|
||||
xusb_device->devpath_tail, if_idx);
|
||||
return -ENOMEM;
|
||||
}
|
||||
DBG("MEM: ALLOC interface: %p\n", iface);
|
||||
xusb_device->interfaces[if_idx] = iface;
|
||||
iface->xusb_device = xusb_device;
|
||||
iface->interface_num = iface_desc->bInterfaceNumber;
|
||||
|
||||
/* Search Endpoints */
|
||||
iface->ep_in = 0;
|
||||
iface->ep_out = 0;
|
||||
for (ep_idx = 0; ep_idx < iface_desc->bNumEndpoints; ep_idx++) {
|
||||
int ep_num;
|
||||
|
||||
ep_num = iface_desc->endpoint[ep_idx].bEndpointAddress;
|
||||
packet_size = libusb_get_max_packet_size(xusb_device->impl->dev, ep_num);
|
||||
if (!max_packet_size || packet_size < max_packet_size)
|
||||
max_packet_size = packet_size;
|
||||
if (EP_IS_OUT(ep_num))
|
||||
iface->ep_out = ep_num;
|
||||
if (EP_IS_IN(ep_num))
|
||||
iface->ep_in = ep_num;
|
||||
}
|
||||
/* Validation */
|
||||
if (!iface->ep_out) {
|
||||
ERR("%s[%d]: Missing output endpoint\n",
|
||||
xusb_device->devpath_tail, if_idx);
|
||||
return -EINVAL;
|
||||
}
|
||||
if (!iface->ep_in) {
|
||||
ERR("%s[%d]: Missing input endpoint\n",
|
||||
xusb_device->devpath_tail, if_idx);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
iface->is_claimed = 0;
|
||||
XUSB_DBG(iface, "ep_out=0x%X ep_in=0x%X packet_size=%d\n",
|
||||
iface->ep_out, iface->ep_in, max_packet_size);
|
||||
}
|
||||
if (xusb_device->packet_size < max_packet_size)
|
||||
xusb_device->packet_size = max_packet_size;
|
||||
xusb_device->is_usb2 = (xusb_device->packet_size == 512);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct xusb_device *xusb_new(struct libusb_device *dev,
|
||||
const struct xusb_spec *spec)
|
||||
{
|
||||
struct libusb_device_descriptor dev_desc;
|
||||
int ret;
|
||||
struct xusb_device *xusb_device = NULL;
|
||||
|
||||
xusb_device = calloc(sizeof(*xusb_device) + sizeof(struct libusb_implementation), 1);
|
||||
if (!xusb_device) {
|
||||
ERR("Out of memory");
|
||||
goto fail;
|
||||
}
|
||||
DBG("MEM: ALLOC device: %p\n", xusb_device);
|
||||
/* Fill xusb_device */
|
||||
xusb_device->impl = (void *)xusb_device + sizeof(*xusb_device);
|
||||
xusb_device->impl->dev = dev;
|
||||
xusb_device->spec = spec;
|
||||
xusb_device->bus_num = libusb_get_bus_number(dev);
|
||||
xusb_device->device_num = libusb_get_device_address(dev);
|
||||
snprintf(xusb_device->devpath_tail, PATH_MAX, "%03d/%03d",
|
||||
xusb_device->bus_num, xusb_device->device_num);
|
||||
/*
|
||||
* Opening the device
|
||||
*/
|
||||
ret = xusb_open(xusb_device);
|
||||
if (ret < 0) {
|
||||
ERR("%s: Failed to open usb device: %s\n",
|
||||
xusb_device->devpath_tail,
|
||||
strerror(-ret));
|
||||
goto fail;
|
||||
}
|
||||
/*
|
||||
* Get information from the usb_device
|
||||
*/
|
||||
ret = libusb_get_device_descriptor(dev, &dev_desc);
|
||||
if (ret) {
|
||||
ERR("%s: libusb_get_device_descriptor() failed: %s\n",
|
||||
xusb_device->devpath_tail,
|
||||
libusb_error_name(ret));
|
||||
goto fail;
|
||||
}
|
||||
xusb_device->idVendor = dev_desc.idVendor;
|
||||
xusb_device->idProduct = dev_desc.idProduct;
|
||||
if (!match_device(xusb_device, spec)) {
|
||||
DBG("[%04X:%04X] did not match\n",
|
||||
xusb_device->idVendor, xusb_device->idProduct);
|
||||
goto fail;
|
||||
}
|
||||
DBG("%s: process [%X:%X]\n",
|
||||
xusb_device->devpath_tail,
|
||||
xusb_device->idVendor,
|
||||
xusb_device->idProduct);
|
||||
ret = libusb_get_config_descriptor(dev, 0, &xusb_device->impl->config_desc);
|
||||
if (ret) {
|
||||
ERR("%s: libusb_get_config_descriptor() failed: %s\n",
|
||||
xusb_device->devpath_tail,
|
||||
libusb_error_name(ret));
|
||||
goto fail;
|
||||
}
|
||||
ret = init_interfaces(xusb_device);
|
||||
if (ret < 0) {
|
||||
ERR("%s: init_interfaces() failed (ret = %d)\n",
|
||||
xusb_device->devpath_tail, ret);
|
||||
goto fail;
|
||||
}
|
||||
DBG("%s: Created %04X:%04X\n",
|
||||
xusb_device->devpath_tail,
|
||||
xusb_device->idVendor,
|
||||
xusb_device->idProduct);
|
||||
return xusb_device;
|
||||
fail:
|
||||
xusb_destroy(xusb_device);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
struct xusb_iface *xusb_find_iface(const char *devpath,
|
||||
int iface_num,
|
||||
int ep_out,
|
||||
int ep_in,
|
||||
struct xusb_spec *dummy_spec)
|
||||
{
|
||||
ERR("FIXME: Unimplemented yet\n");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
struct xusb_device *xusb_find_bypath(const char *path)
|
||||
{
|
||||
struct xusb_spec *spec;
|
||||
libusb_device **list;
|
||||
ssize_t cnt;
|
||||
int i;
|
||||
|
||||
DBG("path='%s'\n", path);
|
||||
spec = calloc(sizeof(*spec), 1);
|
||||
if (!spec) {
|
||||
ERR("Failed allocating spec\n");
|
||||
goto failed;
|
||||
}
|
||||
cnt = libusb_get_device_list(NULL, &list);
|
||||
if (cnt < 0) {
|
||||
ERR("libusb_get_device_list() failed");
|
||||
goto failed;
|
||||
}
|
||||
for (i = 0; i < cnt; i++) {
|
||||
struct libusb_device_descriptor dev_desc;
|
||||
libusb_device *dev = list[i];
|
||||
struct xusb_device *xusb_device;
|
||||
char devpath_tail[PATH_MAX];
|
||||
int bus_num;
|
||||
int device_num;
|
||||
int ret;
|
||||
|
||||
bus_num = libusb_get_bus_number(dev);
|
||||
device_num = libusb_get_device_address(dev);
|
||||
snprintf(devpath_tail, PATH_MAX, "%03d/%03d",
|
||||
bus_num, device_num);
|
||||
if (!match_devpath(path, devpath_tail))
|
||||
continue;
|
||||
ret = libusb_get_device_descriptor(dev, &dev_desc);
|
||||
if (ret < 0) {
|
||||
ERR("usb device without a device descriptor\n");
|
||||
continue;
|
||||
}
|
||||
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);
|
||||
xusb_device = xusb_new(dev, spec);
|
||||
if (!xusb_device) {
|
||||
ERR("Failed creating xusb for %s\n",
|
||||
devpath_tail);
|
||||
xusb_init_spec(spec, "<EMPTY>", 0, 0);
|
||||
continue;
|
||||
}
|
||||
return xusb_device;
|
||||
}
|
||||
failed:
|
||||
if (spec)
|
||||
free(spec);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
struct xlist_node *xusb_find_byproduct(const struct xusb_spec *specs,
|
||||
int numspecs, xusb_filter_t filterfunc, void *data)
|
||||
{
|
||||
struct xlist_node *xlist;
|
||||
libusb_device **list;
|
||||
ssize_t cnt;
|
||||
int i;
|
||||
|
||||
DBG("specs(%d)\n", numspecs);
|
||||
xlist = xlist_new(NULL);
|
||||
if (!xlist) {
|
||||
ERR("Failed allocation new xlist");
|
||||
goto cleanup;
|
||||
}
|
||||
cnt = libusb_get_device_list(NULL, &list);
|
||||
if (cnt < 0) {
|
||||
ERR("libusb_get_device_list() failed");
|
||||
goto cleanup;
|
||||
}
|
||||
for (i = 0; i < cnt; i++) {
|
||||
struct libusb_device_descriptor dev_desc;
|
||||
libusb_device *dev = list[i];
|
||||
struct xlist_node *item;
|
||||
int ret;
|
||||
int j;
|
||||
|
||||
ret = libusb_get_device_descriptor(dev, &dev_desc);
|
||||
if (ret < 0) {
|
||||
ERR("usb device without a device descriptor\n");
|
||||
continue;
|
||||
}
|
||||
for (j = 0; j < numspecs; j++) {
|
||||
struct xusb_device *xusb_device;
|
||||
const struct xusb_spec *sp = &specs[j];
|
||||
|
||||
xusb_device = xusb_new(dev, sp);
|
||||
if (!xusb_device)
|
||||
continue;
|
||||
if (filterfunc && !filterfunc(xusb_device, data)) {
|
||||
DBG("%s: %04X:%04X filtered out\n",
|
||||
xusb_device->devpath_tail,
|
||||
dev_desc.idVendor,
|
||||
dev_desc.idProduct);
|
||||
xusb_destroy(xusb_device);
|
||||
continue;
|
||||
}
|
||||
item = xlist_new(xusb_device);
|
||||
xlist_append_item(xlist, item);
|
||||
break;
|
||||
}
|
||||
}
|
||||
xusb_list_dump(xlist);
|
||||
return xlist;
|
||||
cleanup:
|
||||
if (xlist)
|
||||
xlist_destroy(xlist, NULL);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void xusb_showinfo(const struct xusb_device *xusb_device)
|
||||
{
|
||||
struct libusb_device_descriptor dev_desc;
|
||||
struct libusb_device *dev;
|
||||
const struct xusb_iface **piface;
|
||||
int ret;
|
||||
|
||||
assert(xusb_device);
|
||||
dev = xusb_device->impl->dev;
|
||||
ret = libusb_get_device_descriptor(dev, &dev_desc);
|
||||
if (ret < 0) {
|
||||
ERR("%s: usb device without a device descriptor\n",
|
||||
xusb_device->devpath_tail);
|
||||
return;
|
||||
}
|
||||
if (verbose <= LOG_INFO) {
|
||||
INFO("%s: [%04X:%04X] [%s / %s / %s]\n",
|
||||
xusb_device->devpath_tail,
|
||||
dev_desc.idVendor,
|
||||
dev_desc.idProduct,
|
||||
xusb_device->iManufacturer,
|
||||
xusb_device->iProduct,
|
||||
xusb_device->iSerialNumber);
|
||||
} else {
|
||||
printf("USB Bus/Device: [%03d/%03d] (%s)\n",
|
||||
xusb_device->bus_num,
|
||||
xusb_device->device_num,
|
||||
(xusb_device->impl->handle) ? "open" : "closed");
|
||||
printf("USB Spec name: [%s]\n", xusb_device->spec->name);
|
||||
printf("USB iManufacturer: [%s]\n", xusb_device->iManufacturer);
|
||||
printf("USB iProduct: [%s]\n", xusb_device->iProduct);
|
||||
printf("USB iSerialNumber: [%s]\n", xusb_device->iSerialNumber);
|
||||
piface = (const struct xusb_iface **)xusb_device->interfaces;
|
||||
for (; *piface; piface++) {
|
||||
printf("USB Interface[%d]: ep_out=0x%02X ep_in=0x%02X claimed=%d [%s]\n",
|
||||
(*piface)->interface_num,
|
||||
(*piface)->ep_out,
|
||||
(*piface)->ep_in,
|
||||
(*piface)->is_claimed,
|
||||
(*piface)->iInterface);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int xusb_close(struct xusb_device *xusb_device)
|
||||
{
|
||||
if (xusb_device && xusb_device->impl && xusb_device->impl->handle) {
|
||||
assert(xusb_device->spec);
|
||||
assert(xusb_device->spec->name);
|
||||
DBG("%s: Closing device \"%s\"\n",
|
||||
xusb_device->devpath_tail,
|
||||
xusb_device->spec->name);
|
||||
libusb_close(xusb_device->impl->handle);
|
||||
xusb_device->impl->handle = NULL;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
enum xusb_transfer_type xusb_transfer_type(const struct xusb_iface *iface)
|
||||
{
|
||||
const struct xusb_device *xusb_device;
|
||||
const struct libusb_interface_descriptor *iface_desc;
|
||||
const struct libusb_endpoint_descriptor *ep;
|
||||
enum xusb_transfer_type ret = XUSB_TT_ILLEGAL;
|
||||
|
||||
assert(iface);
|
||||
xusb_device = iface->xusb_device;
|
||||
assert(xusb_device);
|
||||
iface_desc = get_iface_descriptor(xusb_device, iface->interface_num);
|
||||
assert(iface_desc);
|
||||
ep = iface_desc->endpoint;
|
||||
assert(ep);
|
||||
switch (ep->bmAttributes) {
|
||||
case LIBUSB_TRANSFER_TYPE_CONTROL:
|
||||
case LIBUSB_TRANSFER_TYPE_ISOCHRONOUS:
|
||||
break;
|
||||
case LIBUSB_TRANSFER_TYPE_BULK:
|
||||
ret = XUSB_TT_BULK;
|
||||
break;
|
||||
case LIBUSB_TRANSFER_TYPE_INTERRUPT:
|
||||
ret = XUSB_TT_INTERRUPT;
|
||||
break;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
int xusb_send(struct xusb_iface *iface, const char *buf, int len, int timeout)
|
||||
{
|
||||
struct xusb_device *xusb_device = iface->xusb_device;
|
||||
int actual_len;
|
||||
int ep_out = EP_OUT(iface);
|
||||
int ret;
|
||||
|
||||
if (!xusb_device->impl->handle) {
|
||||
ERR("%s: device closed\n", xusb_device->devpath_tail);
|
||||
return -ENXIO;
|
||||
}
|
||||
dump_packet(LOG_DEBUG, DBG_MASK, __func__, buf, len);
|
||||
if (!EP_IS_OUT(ep_out)) {
|
||||
XUSB_ERR(iface, "%s called with an input endpoint 0x%x\n",
|
||||
__func__, ep_out);
|
||||
return -EINVAL;
|
||||
}
|
||||
switch (iface->transfer_type) {
|
||||
case XUSB_TT_BULK:
|
||||
ret = libusb_bulk_transfer(xusb_device->impl->handle, ep_out,
|
||||
(unsigned char *)buf, len, &actual_len, timeout);
|
||||
break;
|
||||
case XUSB_TT_INTERRUPT:
|
||||
ret = libusb_interrupt_transfer(xusb_device->impl->handle, ep_out,
|
||||
(unsigned char *)buf, len, &actual_len, timeout);
|
||||
break;
|
||||
default:
|
||||
ret = -EAFNOSUPPORT;
|
||||
break;
|
||||
}
|
||||
if (ret) {
|
||||
/*
|
||||
* If the device was gone, it may be the
|
||||
* result of renumeration. Ignore it.
|
||||
*/
|
||||
if (ret != LIBUSB_ERROR_NO_DEVICE) {
|
||||
XUSB_ERR(iface, "write to endpoint 0x%x failed: (%d) %s\n",
|
||||
ep_out, ret, libusb_error_name(ret));
|
||||
dump_packet(LOG_ERR, DBG_MASK, "xbus_send[ERR]",
|
||||
buf, len);
|
||||
/*exit(2);*/
|
||||
} else {
|
||||
XUSB_DBG(iface, "write to endpoint 0x%x got ENODEV\n",
|
||||
ep_out);
|
||||
xusb_close(xusb_device);
|
||||
}
|
||||
return errno_map(ret);
|
||||
} else if (actual_len != len) {
|
||||
XUSB_ERR(iface, "write to endpoint 0x%x short write: (%d) %s\n",
|
||||
ep_out, ret, libusb_error_name(ret));
|
||||
dump_packet(LOG_ERR, DBG_MASK, "xbus_send[ERR]", buf, len);
|
||||
return -EFAULT;
|
||||
}
|
||||
return actual_len;
|
||||
}
|
||||
|
||||
int xusb_recv(struct xusb_iface *iface, char *buf, size_t len, int timeout)
|
||||
{
|
||||
struct xusb_device *xusb_device = iface->xusb_device;
|
||||
int actual_len;
|
||||
int ep_in = EP_IN(iface);
|
||||
int ret;
|
||||
|
||||
if (!xusb_device->impl->handle) {
|
||||
ERR("%s: device closed\n", xusb_device->devpath_tail);
|
||||
return -ENXIO;
|
||||
}
|
||||
if (!EP_IS_IN(ep_in)) {
|
||||
XUSB_ERR(iface, "%s called with an output endpoint 0x%x\n",
|
||||
__func__, ep_in);
|
||||
return -EINVAL;
|
||||
}
|
||||
switch (iface->transfer_type) {
|
||||
case XUSB_TT_BULK:
|
||||
ret = libusb_bulk_transfer(xusb_device->impl->handle, ep_in,
|
||||
(unsigned char *)buf, len, &actual_len, timeout);
|
||||
break;
|
||||
case XUSB_TT_INTERRUPT:
|
||||
ret = libusb_interrupt_transfer(xusb_device->impl->handle, ep_in,
|
||||
(unsigned char *)buf, len, &actual_len, timeout);
|
||||
break;
|
||||
default:
|
||||
ret = -EAFNOSUPPORT;
|
||||
break;
|
||||
}
|
||||
if (ret < 0) {
|
||||
XUSB_DBG(iface, "read from endpoint 0x%x failed: (%d) %s\n",
|
||||
ep_in, ret, libusb_error_name(ret));
|
||||
memset(buf, 0, len);
|
||||
return errno_map(ret);
|
||||
}
|
||||
dump_packet(LOG_DEBUG, DBG_MASK, __func__, buf, actual_len);
|
||||
return actual_len;
|
||||
}
|
||||
124
xpp/xtalk/xusb_test.c
Normal file
124
xpp/xtalk/xusb_test.c
Normal file
@@ -0,0 +1,124 @@
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
#include <xtalk/debug.h>
|
||||
#include <xtalk/xusb.h>
|
||||
#include <autoconfig.h>
|
||||
|
||||
static char *progname;
|
||||
|
||||
static void usage()
|
||||
{
|
||||
fprintf(stderr, "Usage: %s [options...] -D <device> [hexnum ....]\n",
|
||||
progname);
|
||||
fprintf(stderr, "\tOptions:\n");
|
||||
fprintf(stderr, "\t\t[-v] # Increase verbosity\n");
|
||||
fprintf(stderr,
|
||||
"\t\t[-d mask] # Debug mask (0xFF for everything)\n");
|
||||
fprintf(stderr, "\tDevice:\n");
|
||||
fprintf(stderr, "\t\t/proc/bus/usb/<bus>/<dev>\n");
|
||||
fprintf(stderr, "\t\t/dev/bus/usb/<bus>/<dev>\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
static void xusb_destructor(void *data)
|
||||
{
|
||||
struct xusb_device *xusb_device = data;
|
||||
xusb_destroy(xusb_device);
|
||||
}
|
||||
|
||||
#define XUSB_IFACE_DESC(p, i, d) \
|
||||
{ SPEC_HEAD(0xe4e4, (p), (d)), (i) }
|
||||
|
||||
static struct xusb_iface_description {
|
||||
struct xusb_spec spec;
|
||||
int interface_num;
|
||||
} test_specs[] = {
|
||||
/* 115x */
|
||||
XUSB_IFACE_DESC(0x1150, 1, "old-astribank-NOFW"),
|
||||
XUSB_IFACE_DESC(0x1151, 1, "old-astribank-USB"),
|
||||
XUSB_IFACE_DESC(0x1152, 1, "old-astribank-FPGA"),
|
||||
|
||||
/* 116x */
|
||||
XUSB_IFACE_DESC(0x1160, 1, "astribank2-NOFW"),
|
||||
XUSB_IFACE_DESC(0x1161, 1, "astribank2-USB"),
|
||||
XUSB_IFACE_DESC(0x1162, 1, "astribank2-FPGA"),
|
||||
XUSB_IFACE_DESC(0x1163, 1, "astribank2-TWINSTAR"),
|
||||
XUSB_IFACE_DESC(0x1191, 1, "xpanel"),
|
||||
XUSB_IFACE_DESC(0x1183, 1, "multi-ps"),
|
||||
XUSB_IFACE_DESC(0x11a3, 0, "auth-dongle"),
|
||||
XUSB_IFACE_DESC(0xbb01, 0, "iwc"),
|
||||
{},
|
||||
};
|
||||
|
||||
static int run_spec(int i, xusb_filter_t filter, char *devpath)
|
||||
{
|
||||
struct xusb_iface_description *desc = &test_specs[i];
|
||||
struct xusb_spec *s = &desc->spec;
|
||||
struct xlist_node *xlist;
|
||||
struct xlist_node *curr;
|
||||
int interface_num = desc->interface_num;
|
||||
int num_devs;
|
||||
|
||||
if (!s->name)
|
||||
return 0;
|
||||
xlist = xusb_find_byproduct(s, 1, filter, devpath);
|
||||
num_devs = (xlist) ? xlist_length(xlist) : 0;
|
||||
INFO("total %d devices of type %s (interface=%d)\n",
|
||||
num_devs, s->name, interface_num);
|
||||
for (curr = xlist_shift(xlist); curr; curr = xlist_shift(xlist)) {
|
||||
struct xusb_device *xusb_device;
|
||||
struct xusb_iface *iface;
|
||||
int ret;
|
||||
|
||||
xusb_device = curr->data;
|
||||
ret = xusb_claim(xusb_device, interface_num, &iface);
|
||||
if (ret < 0) {
|
||||
ERR("%s: xusb_claim() failed (ret = %d)\n",
|
||||
xusb_devpath(xusb_device), ret);
|
||||
continue;
|
||||
}
|
||||
xusb_showinfo(xusb_device);
|
||||
xusb_release(iface);
|
||||
}
|
||||
xlist_destroy(xlist, xusb_destructor);
|
||||
return 1;
|
||||
}
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
char *devpath = NULL;
|
||||
const char options[] = "vd:D:EFp";
|
||||
xusb_filter_t filter = NULL;
|
||||
int i;
|
||||
|
||||
progname = argv[0];
|
||||
while (1) {
|
||||
int c;
|
||||
|
||||
c = getopt(argc, argv, options);
|
||||
if (c == -1)
|
||||
break;
|
||||
|
||||
switch (c) {
|
||||
case 'D':
|
||||
devpath = optarg;
|
||||
filter = xusb_filter_bypath;
|
||||
break;
|
||||
case 'v':
|
||||
verbose++;
|
||||
break;
|
||||
case 'd':
|
||||
debug_mask = strtoul(optarg, NULL, 0);
|
||||
break;
|
||||
case 'h':
|
||||
default:
|
||||
ERR("Unknown option '%c'\n", c);
|
||||
usage();
|
||||
}
|
||||
}
|
||||
i = 0;
|
||||
while (run_spec(i, filter, devpath))
|
||||
i++;
|
||||
return 0;
|
||||
}
|
||||
76
xpp/xtalk/xusb_test_bypath.c
Normal file
76
xpp/xtalk/xusb_test_bypath.c
Normal file
@@ -0,0 +1,76 @@
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
#include <xtalk/debug.h>
|
||||
#include <xtalk/xusb.h>
|
||||
#include <autoconfig.h>
|
||||
|
||||
static char *progname;
|
||||
|
||||
static void usage()
|
||||
{
|
||||
fprintf(stderr, "Usage: %s [options...] <busnum>/<devnum> ...\n", progname);
|
||||
fprintf(stderr, "\tOptions:\n");
|
||||
fprintf(stderr, "\t\t[-v] # Increase verbosity\n");
|
||||
fprintf(stderr,
|
||||
"\t\t[-d mask] # Debug mask (0xFF for everything)\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
static int check_devpath(const char *devpath)
|
||||
{
|
||||
const struct xusb_spec *spec;
|
||||
struct xusb_device *xusb_dev;
|
||||
struct xusb_iface *iface;
|
||||
int ret;
|
||||
|
||||
printf("Checking %s: ", devpath);
|
||||
fflush(stdout);
|
||||
xusb_dev = xusb_find_bypath(devpath);
|
||||
if (!xusb_dev) {
|
||||
ERR("missing %s\n", devpath);
|
||||
return 1;
|
||||
}
|
||||
spec = xusb_device_spec(xusb_dev);
|
||||
printf("Found: %04x:%04x\n", spec->vendor_id, spec->product_id);
|
||||
ret = xusb_claim(xusb_dev, 1, &iface);
|
||||
if (ret < 0) {
|
||||
ERR("%s: xusb_claim() failed (ret = %d)\n",
|
||||
xusb_devpath(xusb_dev), ret);
|
||||
return 1;
|
||||
}
|
||||
xusb_showinfo(xusb_dev);
|
||||
xusb_release(iface);
|
||||
return 1;
|
||||
}
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
const char options[] = "vd:";
|
||||
int i;
|
||||
|
||||
progname = argv[0];
|
||||
while (1) {
|
||||
int c;
|
||||
|
||||
c = getopt(argc, argv, options);
|
||||
if (c == -1)
|
||||
break;
|
||||
|
||||
switch (c) {
|
||||
case 'v':
|
||||
verbose++;
|
||||
break;
|
||||
case 'd':
|
||||
debug_mask = strtoul(optarg, NULL, 0);
|
||||
break;
|
||||
case 'h':
|
||||
default:
|
||||
ERR("Unknown option '%c'\n", c);
|
||||
usage();
|
||||
}
|
||||
}
|
||||
for (i = optind; i < argc; i++)
|
||||
check_devpath(argv[i]);
|
||||
return 0;
|
||||
}
|
||||
Reference in New Issue
Block a user