summaryrefslogtreecommitdiff
path: root/xpp/xtalk
diff options
context:
space:
mode:
authorTzafrir Cohen <tzafrir.cohen@xorcom.com>2011-03-10 18:48:11 +0000
committerTzafrir Cohen <tzafrir.cohen@xorcom.com>2011-03-10 18:48:11 +0000
commit760d0a2a75aba6307550bf551c5eb06174c256b5 (patch)
treed526eeb7d5ce0aec9e4572f5df0cb3536a2632d1 /xpp/xtalk
parentcf84710ff24dd09e80f9e5ecfeb16ce15137ddc3 (diff)
xpp: use 'xtalk' for the USB access code
* Move most of the USB access code from xpp/ to xpp/xtalk/ . * astribank_tool and such tools can now use a shorter -D mmm/nnn rather than a full path. Signed-off-by: Oron Peled <oron.peled@xorcom.com> Acked-by: Tzafrir Cohen <tzafrir.cohen@xorcom.com> git-svn-id: http://svn.asterisk.org/svn/dahdi/tools/trunk@9825 a0bf4364-ded3-4de4-8d8a-66a801d63aff
Diffstat (limited to 'xpp/xtalk')
-rw-r--r--xpp/xtalk/debug.c72
-rw-r--r--xpp/xtalk/debug.h49
-rw-r--r--xpp/xtalk/xlist.c93
-rw-r--r--xpp/xtalk/xlist.h29
-rw-r--r--xpp/xtalk/xtalk.c497
-rw-r--r--xpp/xtalk/xtalk.h172
-rw-r--r--xpp/xtalk/xtalk_defs.h40
-rw-r--r--xpp/xtalk/xusb.c726
-rw-r--r--xpp/xtalk/xusb.h98
9 files changed, 1776 insertions, 0 deletions
diff --git a/xpp/xtalk/debug.c b/xpp/xtalk/debug.c
new file mode 100644
index 0000000..eea2d82
--- /dev/null
+++ b/xpp/xtalk/debug.c
@@ -0,0 +1,72 @@
+/*
+ * 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 <stdlib.h>
+#include <stdarg.h>
+#include <syslog.h>
+#include <execinfo.h>
+#include <debug.h>
+
+int verbose = LOG_INFO;
+int debug_mask = 0;
+
+void log_function(int level, int mask, const char *msg, ...)
+{
+ va_list ap;
+
+ va_start(ap, msg);
+ if(verbose >= level) {
+ if(level < LOG_DEBUG || (mask & debug_mask))
+ vfprintf(stderr, msg, ap);
+ }
+ va_end(ap);
+}
+
+void dump_packet(int loglevel, int mask, const char *msg, const char *buf, int len)
+{
+ int i;
+
+ if(mask & debug_mask) {
+ log_function(loglevel, ~0, "%-15s:", msg);
+ for(i = 0; i < len; i++)
+ log_function(loglevel, ~0, " %02X", (uint8_t)buf[i]);
+ log_function(loglevel, ~0, "\n");
+ }
+}
+
+/* from glibc info(1) */
+void print_backtrace (FILE *fp)
+{
+ void *array[10];
+ size_t size;
+ char **strings;
+ size_t i;
+
+ size = backtrace (array, 10);
+ strings = backtrace_symbols (array, size);
+ for (i = 0; i < size; i++)
+ fprintf (fp, "%s\n", strings[i]);
+ free (strings);
+}
diff --git a/xpp/xtalk/debug.h b/xpp/xtalk/debug.h
new file mode 100644
index 0000000..2d018d2
--- /dev/null
+++ b/xpp/xtalk/debug.h
@@ -0,0 +1,49 @@
+#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>
+
+/*
+ * Each module should define a unique DBG_MASK
+ */
+
+extern int verbose;
+extern int debug_mask;
+
+/*
+ * Logging
+ */
+void log_function(int level, int mask, const char *msg, ...) __attribute__(( format(printf, 3, 4) ));
+
+#define ERR(fmt, arg...) log_function(LOG_ERR, 0, "%s:%d: ERROR(%s): " fmt, __FILE__, __LINE__, __FUNCTION__, ## arg)
+#define WARN(fmt, arg...) log_function(LOG_WARNING, 0, "WARNING: " fmt, ## arg)
+#define INFO(fmt, arg...) log_function(LOG_INFO, 0, "INFO: " fmt, ## arg)
+#define DBG(fmt, arg...) log_function(LOG_DEBUG, DBG_MASK, \
+ "%s:%d: DBG(%s): " fmt, __FILE__, __LINE__, __FUNCTION__, ## arg)
+
+void dump_packet(int loglevel, int mask, const char *msg, const char *buf, int len);
+void print_backtrace (FILE *fp);
+
+#endif /* DEBUG_H */
diff --git a/xpp/xtalk/xlist.c b/xpp/xtalk/xlist.c
new file mode 100644
index 0000000..d28debd
--- /dev/null
+++ b/xpp/xtalk/xlist.c
@@ -0,0 +1,93 @@
+#include <assert.h>
+#include <stdlib.h>
+#include <string.h>
+#include <xlist.h>
+
+struct xlist_node *xlist_new(void *data)
+{
+ struct xlist_node *list;
+
+ if((list = malloc(sizeof(*list))) == NULL)
+ return NULL;
+ list->next = list;
+ list->prev = list;
+ list->data = data;
+ return list;
+}
+
+void xlist_destroy(struct xlist_node *list, xlist_destructor_t destructor)
+{
+ struct xlist_node *curr;
+ struct xlist_node *next;
+
+ if (! list)
+ return;
+ curr = list->next;
+ while(curr != list) {
+ next = curr->next;
+ if(destructor)
+ destructor(curr->data);
+ memset(curr, 0, sizeof(*curr));
+ free(curr);
+ curr = next;
+ }
+ memset(list, 0, sizeof(*list));
+ free(list);
+}
+
+void xlist_append_item(struct xlist_node *list, struct xlist_node *item)
+{
+ assert(list);
+ assert(xlist_empty(item));
+ item->next = list;
+ item->prev = list->prev;
+ list->prev->next = item;
+ list->prev = item;
+}
+
+void xlist_prepend_item(struct xlist_node *list, struct xlist_node *item)
+{
+ assert(list);
+ assert(xlist_empty(item));
+ item->prev = list;
+ item->next = list->next;
+ list->next->prev = item;
+ list->next = item;
+}
+
+void xlist_remove_item(struct xlist_node *item)
+{
+ assert(item);
+ item->prev->next = item->next;
+ item->next->prev = item->prev;
+ item->next = item->prev = item;
+}
+
+struct xlist_node *xlist_shift(struct xlist_node *list)
+{
+ struct xlist_node *item;
+
+ if(!list)
+ return NULL;
+ if(xlist_empty(list))
+ return NULL;
+ item = list->next;
+ xlist_remove_item(item);
+ return item;
+}
+
+int xlist_empty(const struct xlist_node *list)
+{
+ assert(list);
+ return list->next == list && list->prev == list;
+}
+
+size_t xlist_length(const struct xlist_node *list)
+{
+ struct xlist_node *curr;
+ size_t count = 0;
+
+ for(curr = list->next; curr != list; curr = curr->next)
+ count++;
+ return count;
+}
diff --git a/xpp/xtalk/xlist.h b/xpp/xtalk/xlist.h
new file mode 100644
index 0000000..4f7f818
--- /dev/null
+++ b/xpp/xtalk/xlist.h
@@ -0,0 +1,29 @@
+#ifndef XLIST_H
+#define XLIST_H
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif /* __cplusplus */
+
+struct xlist_node {
+ void *data;
+ struct xlist_node *next;
+ struct xlist_node *prev;
+};
+
+typedef void (*xlist_destructor_t)(void *data);
+
+struct xlist_node *xlist_new(void *data);
+void xlist_destroy(struct xlist_node *list, xlist_destructor_t destructor);
+void xlist_append_item(struct xlist_node *list, struct xlist_node *item);
+void xlist_remove_item(struct xlist_node *item);
+struct xlist_node *xlist_shift(struct xlist_node *list);
+int xlist_empty(const struct xlist_node *list);
+size_t xlist_length(const struct xlist_node *list);
+
+#ifdef __cplusplus
+}
+#endif /* __cplusplus */
+
+#endif /* XLIST_H */
diff --git a/xpp/xtalk/xtalk.c b/xpp/xtalk/xtalk.c
new file mode 100644
index 0000000..d3da5e0
--- /dev/null
+++ b/xpp/xtalk/xtalk.c
@@ -0,0 +1,497 @@
+/*
+ * Written by Oron Peled <oron@actcom.co.il>
+ * Copyright (C) 2009, Xorcom
+ *
+ * All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <assert.h>
+#include <errno.h>
+#include <arpa/inet.h>
+#include <xtalk.h>
+#include <debug.h>
+
+static const char rcsid[] = "$Id$";
+
+#define DBG_MASK 0x02
+
+#define TIMEOUT 6000
+
+/*
+ * Base XTALK device. A pointer to this struct
+ * should be included in the struct representing
+ * the dialect.
+ */
+struct xtalk_device {
+ void *transport_priv; /* e.g: struct xusb */
+ struct xtalk_ops ops;
+ struct xtalk_protocol xproto;
+ uint8_t xtalk_proto_version;
+ uint8_t status;
+ size_t packet_size;
+ uint16_t tx_sequenceno;
+};
+
+CMD_DEF(XTALK, ACK,
+ uint8_t stat;
+ );
+
+CMD_DEF(XTALK, PROTO_GET,
+ uint8_t proto_version;
+ uint8_t reserved;
+ );
+
+CMD_DEF(XTALK, PROTO_GET_REPLY,
+ uint8_t proto_version;
+ uint8_t reserved;
+ );
+
+union XTALK_PDATA(XTALK) {
+ MEMBER(XTALK, ACK);
+ MEMBER(XTALK, PROTO_GET);
+ MEMBER(XTALK, PROTO_GET_REPLY);
+} PACKED members;
+
+struct xtalk_protocol xtalk_base = {
+ .name = "XTALK",
+ .proto_version = 0,
+ .commands = {
+ CMD_RECV(XTALK, ACK, NULL),
+ CMD_SEND(XTALK, PROTO_GET),
+ CMD_RECV(XTALK, PROTO_GET_REPLY, NULL),
+ },
+ .ack_statuses = {
+ ACK_STAT(OK, "Acknowledges previous command"),
+ ACK_STAT(FAIL, "Last command failed"),
+ ACK_STAT(RESET_FAIL, "reset failed"),
+ ACK_STAT(NODEST, "No destination is selected"),
+ ACK_STAT(MISMATCH, "Data mismatch"),
+ ACK_STAT(NOACCESS, "No access"),
+ ACK_STAT(BAD_CMD, "Bad command"),
+ ACK_STAT(TOO_SHORT, "Packet is too short"),
+ ACK_STAT(ERROFFS, "Offset error (not used)"),
+ ACK_STAT(NO_LEEPROM, "Large EEPROM was not found"),
+ ACK_STAT(NO_EEPROM, "No EEPROM was found"),
+ ACK_STAT(WRITE_FAIL, "Writing to device failed"),
+ ACK_STAT(NOPWR_ERR, "No power on USB connector"),
+ }
+};
+
+void free_command(struct xtalk_command *cmd)
+{
+ if(!cmd)
+ return;
+ memset(cmd, 0, cmd->header.len);
+ free(cmd);
+}
+
+static const struct xtalk_command_desc *get_command_desc(const struct xtalk_protocol *xproto, uint8_t op)
+{
+ const struct xtalk_command_desc *desc;
+
+ if(!xproto)
+ return NULL;
+ desc = &xproto->commands[op];
+ if(!desc->name)
+ return NULL;
+#if 0
+ DBG("%s version=%d, op=0x%X (%s)\n",
+ xproto->name, xproto->proto_version,
+ op, desc->name);
+#endif
+ return desc;
+}
+
+static const char *ack_status_msg(const struct xtalk_protocol *xproto, uint8_t status)
+{
+ const char *ack_status;
+
+ if(!xproto)
+ return NULL;
+ ack_status = xproto->ack_statuses[status];
+ DBG("%s status=0x%X (%s)\n", xproto->name, status, ack_status);
+ return ack_status;
+}
+
+int xtalk_set_protocol(struct xtalk_device *xtalk_dev, const struct xtalk_protocol *xproto)
+{
+ const char *protoname = (xproto) ? xproto->name : "GLOBAL";
+ int i;
+
+ DBG("%s\n", protoname);
+ memset(&xtalk_dev->xproto, 0, sizeof(xtalk_dev->xproto));
+ for(i = 0; i < MAX_OPS; i++) {
+ const struct xtalk_command_desc *desc;
+
+ desc = get_command_desc(xproto, i);
+ if(desc) {
+ if(!IS_PRIVATE_OP(i)) {
+ ERR("Bad op=0x%X (should be in the range [0x%X-0x%X]\n",
+ i, PRIVATE_OP_FIRST, PRIVATE_OP_LAST);
+ return -EINVAL;
+ }
+ xtalk_dev->xproto.commands[i] = *desc;
+ DBG("private: op=0x%X (%s)\n", i, desc->name);
+ } else {
+ if(!IS_PRIVATE_OP(i)) {
+ const char *name;
+
+ xtalk_dev->xproto.commands[i] = xtalk_base.commands[i];
+ name = xtalk_dev->xproto.commands[i].name;
+ if(name)
+ DBG("global: op=0x%X (%s)\n", i, name);
+ }
+ }
+ }
+ for(i = 0; i < MAX_STATUS; i++) {
+ const char *stat_msg;
+
+ stat_msg = (xproto) ? xproto->ack_statuses[i] : NULL;
+ if(stat_msg) {
+ if(!IS_PRIVATE_OP(i)) {
+ ERR("Bad status=0x%X (should be in the range [0x%X-0x%X]\n",
+ i, PRIVATE_OP_FIRST, PRIVATE_OP_LAST);
+ return -EINVAL;
+ }
+ xtalk_dev->xproto.ack_statuses[i] = stat_msg;
+ DBG("private: status=0x%X (%s)\n", i, stat_msg);
+ } else {
+ if(!IS_PRIVATE_OP(i)) {
+ const char *stat_msg;
+
+ xtalk_dev->xproto.ack_statuses[i] = xtalk_base.ack_statuses[i];
+ stat_msg = xtalk_dev->xproto.ack_statuses[i];
+ if(stat_msg)
+ DBG("global: status=0x%X (%s)\n", i, stat_msg);
+ }
+ }
+ }
+ xtalk_dev->xproto.name = protoname;
+ xtalk_dev->xproto.proto_version = (xproto) ? xproto->proto_version : 0;
+ return 0;
+}
+
+struct xtalk_command *new_command(
+ const struct xtalk_device *xtalk_dev,
+ uint8_t op, uint16_t extra_data)
+{
+ const struct xtalk_protocol *xproto;
+ struct xtalk_command *cmd;
+ const struct xtalk_command_desc *desc;
+ uint16_t len;
+
+ xproto = &xtalk_dev->xproto;
+ desc = get_command_desc(xproto, op);
+ if(!desc) {
+ ERR("Unknown op=0x%X.\n", op);
+ return NULL;
+ }
+ DBG("OP=0x%X [%s] (extra_data %d)\n", op, desc->name, extra_data);
+ len = desc->len + extra_data;
+ if((cmd = malloc(len)) == NULL) {
+ ERR("Out of memory\n");
+ return NULL;
+ }
+ if(extra_data) {
+ uint8_t *ptr = (uint8_t *)cmd;
+
+ DBG("clear extra_data (%d bytes)\n", extra_data);
+ memset(ptr + desc->len, 0, extra_data);
+ }
+ cmd->header.op = op;
+ cmd->header.len = len;
+ cmd->header.seq = 0; /* Overwritten in send_usb() */
+ return cmd;
+}
+
+void xtalk_dump_command(struct xtalk_command *cmd)
+{
+ uint16_t len;
+ int i;
+
+ len = cmd->header.len;
+ if(len < sizeof(struct xtalk_header)) {
+ ERR("Command too short (%d)\n", len);
+ return;
+ }
+ INFO("DUMP: OP=0x%X len=%d seq=%d\n",
+ cmd->header.op, cmd->header.len, cmd->header.seq);
+ for(i = 0; i < len - sizeof(struct xtalk_header); i++) {
+ INFO(" %2d. 0x%X\n", i, cmd->alt.raw_data[i]);
+ }
+}
+
+static int send_command(struct xtalk_device *xtalk_dev, struct xtalk_command *cmd, int timeout)
+{
+ int ret;
+ int len;
+ char *buf;
+ void *priv = xtalk_dev->transport_priv;
+
+ len = cmd->header.len;
+ cmd->header.seq = xtalk_dev->tx_sequenceno;
+
+ buf = (char *)cmd;
+ //printf("%s: len=%d\n", __FUNCTION__, len);
+#if 0
+ extern FILE *fp;
+ if(fp) {
+ int i;
+
+ fprintf(fp, "%05d:", cmd->header.seq);
+ for(i = 0; i < len; i++)
+ fprintf(fp, " %02X", (uint8_t)buf[i]);
+ fprintf(fp, "\n");
+ }
+#endif
+ ret = xtalk_dev->ops.send_func(priv, (char *)cmd, len, timeout);
+ if(ret < 0) {
+ DBG("send_func failed ret=%d\n", ret);
+ }
+ xtalk_dev->tx_sequenceno++;
+ return ret;
+}
+
+static struct xtalk_command *recv_command(struct xtalk_device *xtalk_dev, int timeout)
+{
+ struct xtalk_command *reply;
+ void *priv = xtalk_dev->transport_priv;
+ int ret;
+
+ if((reply = malloc(xtalk_dev->packet_size)) == NULL) {
+ ERR("Out of memory\n");
+ goto err;
+ }
+ reply->header.len = 0;
+ ret = xtalk_dev->ops.recv_func(priv, (char *)reply, xtalk_dev->packet_size, timeout);
+ if(ret < 0) {
+ ERR("Receive from usb failed.\n");
+ goto err;
+ } else if(ret == 0) {
+ goto err; /* No reply */
+ }
+ if(ret != reply->header.len) {
+ ERR("Wrong length received: got %d bytes, but length field says %d bytes%s\n",
+ ret, reply->header.len,
+ (ret == 1)? ". Old USB firmware?": "");
+ goto err;
+ }
+ //dump_packet(LOG_DEBUG, DBG_MASK, __FUNCTION__, (char *)reply, ret);
+ return reply;
+err:
+ if(reply) {
+ memset(reply, 0, xtalk_dev->packet_size);
+ free_command(reply);
+ }
+ return NULL;
+}
+
+
+__attribute__((warn_unused_result))
+int process_command(
+ struct xtalk_device *xtalk_dev,
+ struct xtalk_command *cmd,
+ struct xtalk_command **reply_ref)
+{
+ const struct xtalk_protocol *xproto;
+ struct xtalk_command *reply = NULL;
+ const struct xtalk_command_desc *reply_desc;
+ const struct xtalk_command_desc *expected;
+ const struct xtalk_command_desc *cmd_desc;
+ uint8_t reply_op;
+ const char *protoname;
+ int ret;
+
+ xproto = &xtalk_dev->xproto;
+ protoname = (xproto) ? xproto->name : "GLOBAL";
+ if(reply_ref)
+ *reply_ref = NULL; /* So the caller knows if a reply was received */
+ reply_op = cmd->header.op | XTALK_REPLY_MASK;
+ cmd_desc = get_command_desc(xproto, cmd->header.op);
+ expected = get_command_desc(xproto, reply_op);
+ //printf("%s: len=%d\n", __FUNCTION__, cmd->header.len);
+ ret = send_command(xtalk_dev, cmd, TIMEOUT);
+ if(!reply_ref) {
+ DBG("No reply requested\n");
+ goto out;
+ }
+ if(ret < 0) {
+ ERR("send_command failed: %d\n", ret);
+ goto out;
+ }
+ reply = recv_command(xtalk_dev, TIMEOUT);
+ if(!reply) {
+ ERR("recv_command failed\n");
+ ret = -EPROTO;
+ goto out;
+ }
+ *reply_ref = reply;
+ if((reply->header.op & 0x80) != 0x80) {
+ ERR("Unexpected reply op=0x%02X, should have MSB set.\n", reply->header.op);
+ ret = -EPROTO;
+ goto out;
+ }
+ DBG("REPLY OP: 0x%X\n", reply->header.op);
+ reply_desc = get_command_desc(xproto, reply->header.op);
+ if(!reply_desc) {
+ ERR("Unknown reply (proto=%s) op=0x%02X\n", protoname, reply->header.op);
+ ret = -EPROTO;
+ goto out;
+ }
+ DBG("REPLY NAME: %s\n", reply_desc->name);
+ if(reply->header.op == XTALK_ACK) {
+ int status = CMD_FIELD(reply, XTALK, ACK, stat);
+
+ if(expected) {
+ ERR("Expected OP=0x%02X: Got ACK(%d): %s\n",
+ reply_op, status, ack_status_msg(xproto, status));
+ ret = -EPROTO;
+ goto out;
+ } else if(status != STAT_OK) {
+
+ ERR("Got ACK (for OP=0x%X [%s]): %d %s\n",
+ cmd->header.op,
+ cmd_desc->name,
+ status, ack_status_msg(xproto, status));
+#if 0
+ extern FILE *fp;
+ if(fp) {
+ fprintf(fp, "Got ACK(%d)\n", status);
+ }
+#endif
+ ret = -EPROTO;
+ goto out;
+ }
+ /* Good expected ACK ... */
+ } else if(reply->header.op != reply_op) {
+ ERR("Expected OP=0x%02X: Got OP=0x%02X\n",
+ reply_op, reply->header.op);
+ ret = -EPROTO;
+ goto out;
+ }
+ if(expected && expected->len > reply->header.len) {
+ ERR("Expected len=%d: Got len=%d\n",
+ expected->len, reply->header.len);
+ ret = -EPROTO;
+ goto out;
+ }
+ if(cmd->header.seq != reply->header.seq) {
+ ERR("Expected seq=%d: Got seq=%d\n",
+ cmd->header.seq, reply->header.seq);
+ ret = -EPROTO;
+ goto out;
+ }
+ ret = reply->header.len; /* All good, return the length */
+ DBG("returning reply op 0x%X (%d bytes)\n", reply->header.op, ret);
+out:
+ free_command(cmd);
+ if(!reply_ref && reply)
+ free_command(reply);
+ return ret;
+}
+
+/*
+ * Protocol Commands
+ */
+
+int xtalk_proto_query(struct xtalk_device *xtalk_dev)
+{
+ struct xtalk_command *cmd;
+ struct xtalk_command *reply;
+ uint8_t proto_version;
+ int ret;
+
+ DBG("\n");
+ assert(xtalk_dev != NULL);
+ proto_version = xtalk_dev->xproto.proto_version;
+ if((cmd = new_command(xtalk_dev, XTALK_PROTO_GET, 0)) == NULL) {
+ ERR("new_command failed\n");
+ return -ENOMEM;
+ }
+ CMD_FIELD(cmd, XTALK, PROTO_GET, proto_version) = proto_version; /* Protocol Version */
+ ret = process_command(xtalk_dev, cmd, &reply);
+ if(ret < 0) {
+ ERR("process_command failed: %d\n", ret);
+ goto out;
+ }
+ xtalk_dev->xtalk_proto_version = CMD_FIELD(reply, XTALK, PROTO_GET_REPLY, proto_version);
+ if(xtalk_dev->xtalk_proto_version != proto_version) {
+ ERR("Got %s protocol version: 0x%02x (expected 0x%02x)\n",
+ xtalk_dev->xproto.name,
+ xtalk_dev->xtalk_proto_version,
+ proto_version);
+ ret = xtalk_dev->xtalk_proto_version;
+ goto out;
+ }
+ DBG("Protocol version: %02x\n", xtalk_dev->xtalk_proto_version);
+ ret = xtalk_dev->xtalk_proto_version;
+out:
+ free_command(reply);
+ return ret;
+}
+
+/*
+ * Wrappers
+ */
+
+struct xtalk_device *xtalk_new(const struct xtalk_ops *ops, size_t packet_size, void *priv)
+{
+ struct xtalk_device *xtalk_dev;
+ int ret;
+
+ DBG("\n");
+ assert(ops != NULL);
+ if((xtalk_dev = malloc(sizeof(*xtalk_dev))) == NULL) {
+ ERR("Allocating XTALK device memory failed\n");
+ return NULL;
+ }
+ memset(xtalk_dev, 0, sizeof(*xtalk_dev));
+ memcpy((void *)&xtalk_dev->ops, (const void *)ops, sizeof(xtalk_dev->ops));
+ xtalk_dev->transport_priv = priv;
+ xtalk_dev->packet_size = packet_size;
+ xtalk_dev->tx_sequenceno = 1;
+ ret = xtalk_set_protocol(xtalk_dev, NULL);
+ if(ret < 0) {
+ ERR("GLOBAL Protocol registration failed: %d\n", ret);
+ goto err;
+ }
+ return xtalk_dev;
+
+err:
+ if (xtalk_dev)
+ xtalk_delete(xtalk_dev);
+ return NULL;
+}
+
+void xtalk_delete(struct xtalk_device *xtalk_dev)
+{
+ void *priv;
+
+ if(!xtalk_dev)
+ return;
+ DBG("\n");
+ priv = xtalk_dev->transport_priv;
+ assert(priv);
+ xtalk_dev->tx_sequenceno = 0;
+ assert(&xtalk_dev->ops != NULL);
+ assert(&xtalk_dev->ops.close_func != NULL);
+ xtalk_dev->ops.close_func(priv);
+}
diff --git a/xpp/xtalk/xtalk.h b/xpp/xtalk/xtalk.h
new file mode 100644
index 0000000..4243b64
--- /dev/null
+++ b/xpp/xtalk/xtalk.h
@@ -0,0 +1,172 @@
+#ifndef XTALK_H
+#define XTALK_H
+/*
+ * Written by Oron Peled <oron@actcom.co.il>
+ * Copyright (C) 2009, Xorcom
+ *
+ * All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ */
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif /* __cplusplus */
+
+/*
+ * XTALK - Base protocol for our USB devices
+ * It is meant to provide a common base for layered
+ * protocols (dialects)
+ */
+
+#include <stdint.h>
+#include <stdlib.h>
+/* Definitions common to the firmware (in include/ directory) */
+#include <xtalk_defs.h>
+
+#ifdef __GNUC__
+#define PACKED __attribute__((packed))
+#else
+#error "We do not know how your compiler packs structures"
+#endif
+
+struct xtalk_device;
+struct xtalk_command_desc;
+
+typedef int (*xtalk_cmd_callback_t)(
+ struct xtalk_device *xtalk_dev,
+ struct xtalk_command_desc *xtalk_cmd);
+
+/* Describe a single xtalk command */
+struct xtalk_command_desc {
+ uint8_t op;
+ const char *name;
+ xtalk_cmd_callback_t callback;
+ uint16_t len; /* Minimal length */
+};
+
+/* Define a complete protocol */
+struct xtalk_protocol {
+ const char *name;
+ uint8_t proto_version;
+ struct xtalk_command_desc commands[MAX_OPS];
+ const char *ack_statuses[MAX_STATUS];
+};
+
+/*
+ * The common header of every xtalk command
+ * in every xtalk dialect.
+ */
+struct xtalk_header {
+ uint16_t len;
+ uint16_t seq;
+ uint8_t op; /* MSB: 0 - to device, 1 - from device */
+} PACKED;
+
+struct xtalk_command {
+ /* Common part */
+ struct xtalk_header header;
+ /* Each dialect has its own data members */
+ union private_data {
+ uint8_t raw_data[0];
+ } PACKED alt;
+} PACKED;
+
+/*
+ * Macros to unify access to protocol packets and fields:
+ * p - signify the dialect prefix (XTALK for base protocol)
+ * o - signify command op (e.g: ACK)
+ * cmd - A pointer to struct xtalk_command
+ * field - field name (e.g: raw_data)
+ */
+#define XTALK_STRUCT(p,o) p ## _struct_ ## o
+#define XTALK_PDATA(o) xtalk_privdata_ ## o
+#define CMD_FIELD(cmd, p, o, field) (((union XTALK_PDATA(p) *)&((cmd)->alt))->XTALK_STRUCT(p, o).field)
+#define CMD_DEF(p, o, ...) struct XTALK_STRUCT(p, o) { \
+ __VA_ARGS__ \
+ } PACKED XTALK_STRUCT(p, o)
+#define MEMBER(p, o) struct XTALK_STRUCT(p, o) XTALK_STRUCT(p, o)
+
+/* Wrappers for transport (xusb) functions */
+struct xtalk_ops {
+ int (*send_func)(void *transport_priv, void *data, size_t len, int timeout);
+ int (*recv_func)(void *transport_priv, void *data, size_t maxlen, int timeout);
+ int (*close_func)(void *transport_priv);
+};
+
+/*
+ * Base XTALK device. A pointer to this struct
+ * should be included in the struct representing
+ * the dialect.
+ */
+struct xtalk_device;
+
+/* high-level */
+struct xtalk_device *xtalk_new(const struct xtalk_ops *ops, size_t packet_size, void *transport_priv);
+void xtalk_delete(struct xtalk_device *dev);
+int xtalk_set_protocol(struct xtalk_device *xtalk_dev, const struct xtalk_protocol *xproto);
+int xtalk_proto_query(struct xtalk_device *dev);
+void xtalk_dump_command(struct xtalk_command *cmd);
+
+/* low-level */
+int process_command(
+ struct xtalk_device *dev,
+ struct xtalk_command *cmd,
+ struct xtalk_command **reply_ref);
+struct xtalk_command *new_command(
+ const struct xtalk_device *xtalk_dev,
+ uint8_t op, uint16_t extra_data);
+void free_command(struct xtalk_command *cmd);
+
+/*
+ * Convenience macros to define entries in a protocol command table:
+ * p - signify the dialect prefix (XTALK for base protocol)
+ * o - signify command op (e.g: ACK)
+ * cb - A callback function (type xtalk_cmd_callback_t)
+ */
+#define CMD_RECV(p,o,cb) \
+ [p ## _ ## o | XTALK_REPLY_MASK] { \
+ .op = p ## _ ## o | XTALK_REPLY_MASK, \
+ .name = #o "_reply", \
+ .callback = (cb), \
+ .len = \
+ sizeof(struct xtalk_header) + \
+ sizeof(struct XTALK_STRUCT(p,o)), \
+ }
+
+#define CMD_SEND(p,o) \
+ [p ## _ ## o] { \
+ .op = p ## _ ## o, \
+ .name = #o, \
+ .callback = NULL, \
+ .len = \
+ sizeof(struct xtalk_header) + \
+ sizeof(struct XTALK_STRUCT(p,o)), \
+ }
+
+/*
+ * Convenience macro to define statuses:
+ * x - status code (e.g: OK)
+ * m - status message (const char *)
+ */
+#define ACK_STAT(x,m) [ STAT_ ## x ] = (m)
+
+#ifdef __cplusplus
+}
+#endif /* __cplusplus */
+
+#endif /* XTALK_H */
diff --git a/xpp/xtalk/xtalk_defs.h b/xpp/xtalk/xtalk_defs.h
new file mode 100644
index 0000000..d9c590b
--- /dev/null
+++ b/xpp/xtalk/xtalk_defs.h
@@ -0,0 +1,40 @@
+#ifndef XTALK_DEFS_H
+#define XTALK_DEFS_H
+
+#define MAX_OPS 256 /* single byte */
+#define MAX_STATUS 256 /* single byte */
+
+#define XTALK_REPLY_MASK 0x80 /* Every reply has this bit */
+
+#define PRIVATE_OP_FIRST 0x05
+#define PRIVATE_OP_LAST 0x7F
+#define IS_PRIVATE_OP(x) ( \
+ (((x) & ~(XTALK_REPLY_MASK)) >= PRIVATE_OP_FIRST) && \
+ (((x) & ~(XTALK_REPLY_MASK)) <= PRIVATE_OP_LAST) \
+ )
+
+#define XTALK_ACK 0x80
+#define XTALK_PROTO_GET 0x01
+#define XTALK_PROTO_GET_REPLY (XTALK_PROTO_GET | XTALK_REPLY_MASK)
+#define XTALK_FWVERS_GET 0x11
+#define XTALK_FWVERS_GET_REPLY (XTALK_FWVERS_GET | XTALK_REPLY_MASK)
+#define XTALK_CAPS_GET 0x0E /* Get EEPROM table contents Product/Vendor Id ... */
+#define XTALK_CAPS_GET_REPLY (XTALK_CAPS_GET | XTALK_REPLY_MASK)
+
+/*------------- XTALK: statuses in ACK ---------------------------------------*/
+#define STAT_OK 0x00 /* OK */
+#define STAT_FAIL 0x01 /* last command failed */
+#define STAT_RESET_FAIL 0x02 /* reset failed */
+#define STAT_NODEST 0x03 /* No destination is selected */
+#define STAT_MISMATCH 0x04 /* Data mismatch */
+#define STAT_NOACCESS 0x05 /* No access */
+#define STAT_BAD_CMD 0x06 /* Bad command */
+#define STAT_TOO_SHORT 0x07 /* Packet is too short */
+#define STAT_ERROFFS 0x08 /* Offset error (not used) */
+#define STAT_NO_LEEPROM 0x0A /* Large EEPROM was not found */
+#define STAT_NO_EEPROM 0x0B /* No EEPROM was found */
+#define STAT_WRITE_FAIL 0x0C /* Writing to device failed */
+#define STAT_NOPWR_ERR 0x10 /* No power on USB connector */
+
+
+#endif /* XTALK_DEFS_H */
diff --git a/xpp/xtalk/xusb.c b/xpp/xtalk/xusb.c
new file mode 100644
index 0000000..ebec5a9
--- /dev/null
+++ b/xpp/xtalk/xusb.c
@@ -0,0 +1,726 @@
+/*
+ * Written by Oron Peled <oron@actcom.co.il>
+ * Copyright (C) 2008, Xorcom
+ *
+ * All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ */
+
+#define _GNU_SOURCE /* for memrchr() */
+#include <stdio.h>
+#include <string.h>
+#include <assert.h>
+#include <errno.h>
+#include <stdarg.h>
+#include <syslog.h>
+#include <arpa/inet.h>
+#include <debug.h>
+#include <xusb.h>
+
+static const char rcsid[] = "$Id$";
+
+#define DBG_MASK 0x01
+#define TIMEOUT 500
+
+struct xusb {
+ struct usb_device *dev;
+ usb_dev_handle *handle;
+ const struct xusb_spec *spec;
+ char iManufacturer[BUFSIZ];
+ char iProduct[BUFSIZ];
+ char iSerialNumber[BUFSIZ];
+ char iInterface[BUFSIZ];
+ char devpath_tail[PATH_MAX + 1];
+ int bus_num;
+ int device_num;
+ int interface_num;
+ int ep_out;
+ int ep_in;
+ int is_usb2;
+ int is_claimed;
+ int is_open;
+ size_t packet_size;
+};
+
+void xusb_init_spec(struct xusb_spec *spec, char *name,
+ uint16_t vendor_id, uint16_t product_id,
+ int nifaces, int iface, int nep, int ep_out, int ep_in)
+{
+ DBG("Initialize %s: interfaces=%d using interface num=%d endpoints=%d (OUT=0x%2X, IN=0x%2X)\n",
+ name, nifaces, iface, nep, ep_out, ep_in);
+ memset(spec, 0, sizeof(*spec));
+ spec->name = name;
+ spec->num_interfaces = nifaces;
+ spec->my_interface_num = iface;
+ spec->num_endpoints = nep;
+ spec->my_vendor_id = vendor_id;
+ spec->my_product_id = product_id;
+ spec->my_ep_in = ep_in;
+ spec->my_ep_out = ep_out;
+}
+
+#define EP_OUT(xusb) ((xusb)->spec->my_ep_out)
+#define EP_IN(xusb) ((xusb)->spec->my_ep_in)
+
+/*
+ * USB handling
+ */
+
+static int get_usb_string(struct xusb *xusb, uint8_t item, char *buf, unsigned int len)
+{
+ char tmp[BUFSIZ];
+ int ret;
+
+ assert(xusb->handle);
+ if (!item)
+ return 0;
+ ret = usb_get_string_simple(xusb->handle, item, tmp, BUFSIZ);
+ if (ret <= 0)
+ return ret;
+ return snprintf(buf, len, "%s", tmp);
+}
+
+static const struct usb_interface_descriptor *get_interface(const struct usb_device *dev, int my_interface_num, int num_interfaces)
+{
+ const struct usb_interface *interface;
+ const struct usb_interface_descriptor *iface_desc;
+ const struct usb_config_descriptor *config_desc;
+ int num_altsetting;
+
+ config_desc = dev->config;
+ if (!config_desc) {
+ ERR("No configuration descriptor: strange USB1 controller?\n");
+ return NULL;
+ }
+ if(num_interfaces && config_desc->bNumInterfaces != num_interfaces) {
+ DBG("Wrong number of interfaces: have %d need %d\n",
+ config_desc->bNumInterfaces, num_interfaces);
+ return NULL;
+ }
+ interface = &config_desc->interface[my_interface_num];
+ assert(interface != NULL);
+ iface_desc = interface->altsetting;
+ num_altsetting = interface->num_altsetting;
+ assert(num_altsetting != 0);
+ assert(iface_desc != NULL);
+ return iface_desc;
+}
+
+static int match_interface(const struct usb_device *dev, const struct xusb_spec *spec)
+{
+ const struct usb_device_descriptor *dev_desc;
+ const struct usb_interface_descriptor *iface_desc;
+
+ //debug_mask = 0xFF;
+ //verbose = 1;
+ dev_desc = &dev->descriptor;
+ assert(dev_desc);
+ DBG("Checking: %04X:%04X interfaces=%d interface num=%d endpoints=%d: \"%s\"\n",
+ spec->my_vendor_id,
+ spec->my_product_id,
+ spec->num_interfaces,
+ spec->my_interface_num,
+ spec->num_endpoints,
+ spec->name);
+ if(dev_desc->idVendor != spec->my_vendor_id) {
+ DBG("Wrong vendor id 0x%X\n", dev_desc->idVendor);
+ return 0;
+ }
+ if(dev_desc->idProduct != spec->my_product_id) {
+ DBG("Wrong product id 0x%X\n", dev_desc->idProduct);
+ return 0;
+ }
+ if((iface_desc = get_interface(dev, spec->my_interface_num, spec->num_interfaces)) == NULL) {
+ ERR("Could not get interface descriptor of device: %s\n", usb_strerror());
+ return 0;
+ }
+ if(iface_desc->bInterfaceClass != 0xFF) {
+ DBG("Wrong interface class 0x%X\n", iface_desc->bInterfaceClass);
+ return 0;
+ }
+ if(iface_desc->bInterfaceNumber != spec->my_interface_num) {
+ DBG("Wrong interface number %d (expected %d)\n",
+ iface_desc->bInterfaceNumber, spec->my_interface_num);
+ return 0;
+ }
+ if(iface_desc->bNumEndpoints != spec->num_endpoints) {
+ DBG("Wrong number of endpoints %d\n", iface_desc->bNumEndpoints);
+ return 0;
+ }
+ return 1;
+}
+
+static int xusb_fill_strings(struct xusb *xusb)
+{
+ const struct usb_device_descriptor *dev_desc;
+ const struct usb_interface_descriptor *iface_desc;
+
+
+ dev_desc = &xusb->dev->descriptor;
+ assert(dev_desc);
+ if(get_usb_string(xusb, dev_desc->iManufacturer, xusb->iManufacturer, BUFSIZ) < 0) {
+ ERR("Failed reading iManufacturer string: %s\n", usb_strerror());
+ return 0;
+ }
+ if(get_usb_string(xusb, dev_desc->iProduct, xusb->iProduct, BUFSIZ) < 0) {
+ ERR("Failed reading iProduct string: %s\n", usb_strerror());
+ return 0;
+ }
+ if(get_usb_string(xusb, dev_desc->iSerialNumber, xusb->iSerialNumber, BUFSIZ) < 0) {
+ ERR("Failed reading iSerialNumber string: %s\n", usb_strerror());
+ return 0;
+ }
+ if((iface_desc = get_interface(xusb->dev, xusb->interface_num, 0)) == NULL) {
+ ERR("Could not get interface descriptor of device: %s\n", usb_strerror());
+ return 0;
+ }
+ if(get_usb_string(xusb, iface_desc->iInterface, xusb->iInterface, BUFSIZ) < 0) {
+ ERR("Failed reading iInterface string: %s\n", usb_strerror());
+ return 0;
+ }
+ return 1;
+}
+
+static int xusb_open(struct xusb *xusb)
+{
+ assert(xusb);
+ if (xusb->is_open)
+ return 1;
+ if((xusb->handle = usb_open(xusb->dev)) == NULL) {
+ ERR("Failed to open usb device '%s': %s\n",
+ xusb->devpath_tail, usb_strerror());
+ return 0;
+ }
+ xusb->is_open = 1;
+ return 1;
+}
+
+int xusb_claim_interface(struct xusb *xusb)
+{
+ const struct usb_device_descriptor *dev_desc;
+ int ret;
+
+ assert(xusb);
+ xusb_open(xusb); /* If it's not open yet... */
+ if(usb_claim_interface(xusb->handle, xusb->interface_num) != 0) {
+ ERR("usb_claim_interface %d in '%s': %s\n",
+ xusb->interface_num, xusb->devpath_tail, usb_strerror());
+ return 0;
+ }
+ xusb->is_claimed = 1;
+ xusb_fill_strings(xusb);
+ dev_desc = &xusb->dev->descriptor;
+ DBG("ID=%04X:%04X Manufacturer=[%s] Product=[%s] SerialNumber=[%s] Interface=[%s]\n",
+ dev_desc->idVendor,
+ dev_desc->idProduct,
+ xusb->iManufacturer,
+ xusb->iProduct,
+ xusb->iSerialNumber,
+ xusb->iInterface);
+ if(usb_clear_halt(xusb->handle, EP_OUT(xusb)) != 0) {
+ ERR("Clearing output endpoint: %s\n", usb_strerror());
+ return 0;
+ }
+ if(usb_clear_halt(xusb->handle, EP_IN(xusb)) != 0) {
+ ERR("Clearing input endpoint: %s\n", usb_strerror());
+ return 0;
+ }
+ if((ret = xusb_flushread(xusb)) < 0) {
+ ERR("xusb_flushread failed: %d\n", ret);
+ return 0;
+ }
+ return 1;
+}
+
+static void xusb_list_dump(struct xlist_node *xusb_list)
+{
+ struct xlist_node *curr;
+ struct xusb *xusb;
+
+ for(curr = xusb_list->next; curr != xusb_list; curr = curr->next) {
+ struct usb_device *dev;
+ struct usb_bus *bus;
+ struct usb_device_descriptor *dev_desc;
+
+ xusb = curr->data;
+ assert(xusb);
+ dev = xusb->dev;
+ assert(dev);
+ bus = dev->bus;
+ assert(bus);
+ dev_desc = &dev->descriptor;
+ assert(dev_desc);
+ DBG("usb:ID=%04X:%04X [%s / %s / %s], (%s/%s)\n",
+ dev_desc->idVendor,
+ dev_desc->idProduct,
+ xusb->iManufacturer,
+ xusb->iProduct,
+ xusb->iSerialNumber,
+ bus->dirname,
+ dev->filename
+ );
+ }
+}
+
+void xusb_destroy(struct xusb *xusb)
+{
+ if(xusb) {
+ xusb_close(xusb);
+ memset(xusb, 0, sizeof(*xusb));
+ free(xusb);
+ }
+}
+
+static struct xusb *xusb_new(struct usb_device *dev, const struct xusb_spec *spec)
+{
+ struct usb_device_descriptor *dev_desc;
+ struct usb_config_descriptor *config_desc;
+ struct usb_interface *interface;
+ struct usb_interface_descriptor *iface_desc;
+ struct usb_endpoint_descriptor *endpoint;
+ size_t max_packet_size;
+ int i;
+ struct xusb *xusb = NULL;
+
+ /*
+ * Get information from the usb_device
+ */
+ if((dev_desc = &dev->descriptor) == NULL) {
+ ERR("usb device without a device descriptor\n");
+ goto fail;
+ }
+ if((config_desc = dev->config) == NULL) {
+ ERR("usb device without a configuration descriptor\n");
+ goto fail;
+ }
+ interface = &config_desc->interface[spec->my_interface_num];
+ iface_desc = interface->altsetting;
+ endpoint = iface_desc->endpoint;
+ /* Calculate max packet size */
+ max_packet_size = PACKET_SIZE;
+ for(i = 0; i < iface_desc->bNumEndpoints; i++, endpoint++) {
+ DBG("Validating endpoint @ %d (interface %d)\n", i, spec->my_interface_num);
+ if(endpoint->bEndpointAddress == spec->my_ep_out || endpoint->bEndpointAddress == spec->my_ep_in) {
+ if(endpoint->wMaxPacketSize > PACKET_SIZE) {
+ ERR("Endpoint #%d wMaxPacketSize too large (%d)\n", i, endpoint->wMaxPacketSize);
+ goto fail;
+ }
+ if(endpoint->wMaxPacketSize < max_packet_size) {
+ max_packet_size = endpoint->wMaxPacketSize;
+ }
+ }
+ }
+ /* Fill xusb */
+ if((xusb = malloc(sizeof(*xusb))) == NULL) {
+ ERR("Out of memory");
+ goto fail;
+ }
+ memset(xusb, 0, sizeof(*xusb));
+ xusb->dev = dev;
+ xusb->spec = spec;
+ sscanf(dev->bus->dirname, "%d", &xusb->bus_num);
+ sscanf(dev->filename, "%d", &xusb->device_num);
+ snprintf(xusb->devpath_tail, PATH_MAX, "%03d/%03d",
+ xusb->bus_num, xusb->device_num);
+ xusb->interface_num = spec->my_interface_num;
+ xusb->ep_out = spec->my_ep_out;
+ xusb->ep_in = spec->my_ep_in;
+ xusb->packet_size = max_packet_size;
+ xusb->is_usb2 = (max_packet_size == 512);
+ if (! xusb_open(xusb)) {
+ ERR("Failed opening device: %04X:%04X - %s\n",
+ dev_desc->idVendor,
+ dev_desc->idProduct,
+ xusb->devpath_tail);
+ goto fail;
+ }
+ DBG("%04X:%04X - %s\n",
+ dev_desc->idVendor,
+ dev_desc->idProduct,
+ xusb->devpath_tail);
+ return xusb;
+fail:
+ xusb_destroy(xusb);
+ return NULL;
+}
+
+struct xusb *xusb_find_iface(const char *devpath, int iface_num, int ep_out, int ep_in)
+{
+ struct usb_bus *bus;
+
+ DBG("\n");
+ usb_init();
+ usb_find_busses();
+ usb_find_devices();
+ for (bus = usb_get_busses(); bus; bus = bus->next) {
+ int bus_num;
+ char tmppath[PATH_MAX + 1];
+ struct usb_device *dev;
+
+ tmppath[0] = '\0';
+ sscanf(bus->dirname, "%d", &bus_num);
+ snprintf(tmppath, sizeof(tmppath), "%03d", bus_num);
+ DBG("Check bus %d: %s ? %s\n", bus_num, tmppath, devpath);
+ if (strncmp(tmppath, devpath, strlen(tmppath)) != 0)
+ continue;
+ DBG("Matched bus %d\n", bus_num);
+ for (dev = bus->devices; dev; dev = dev->next) {
+ struct usb_device_descriptor *dev_desc;
+ struct usb_config_descriptor *config_desc;
+ struct usb_interface *interface;
+ struct xusb_spec spec;
+ struct xusb *xusb;
+ int device_num;
+
+ sscanf(dev->filename, "%d", &device_num);
+ DBG("Check device %d\n", device_num);
+ snprintf(tmppath, sizeof(tmppath), "%03d/%03d", bus_num, device_num);
+ if (strncmp(tmppath, devpath, strlen(tmppath)) != 0)
+ continue;
+ dev_desc = &dev->descriptor;
+ assert(dev_desc);
+ config_desc = dev->config;
+ assert(config_desc);
+ interface = config_desc->interface;
+ assert(interface);
+ INFO("Matched device %s: %X:%X\n", tmppath, dev_desc->idVendor, dev_desc->idProduct);
+ xusb_init_spec(&spec, "Astribank",
+ dev_desc->idVendor, dev_desc->idProduct,
+ config_desc->bNumInterfaces,
+ iface_num,
+ interface->altsetting->bNumEndpoints,
+ ep_out, ep_in);
+ if((xusb = xusb_new(dev, &spec)) == NULL) {
+ ERR("xusb allocation failed\n");
+ }
+ return xusb;
+ }
+ }
+ return NULL;
+}
+
+static const char *path_tail(const char *path)
+{
+ const char *p;
+
+ assert(path != NULL);
+ /* Find last '/' */
+ if((p = memrchr(path, '/', strlen(path))) == NULL) {
+ ERR("Missing a '/' in %s\n", path);
+ return NULL;
+ }
+ /* Search for a '/' before that */
+ if((p = memrchr(path, '/', p - path)) == NULL) {
+ p = path; /* No more '/' */
+ } else {
+ p++; /* skip '/' */
+ }
+ return p;
+}
+
+int xusb_filter_bypath(const struct xusb *xusb, void *data)
+{
+ const char *p;
+ const char *path = data;
+
+ DBG("%s\n", path);
+ assert(path != NULL);
+ p = path_tail(path);
+ if(strcmp(xusb->devpath_tail, p) != 0) {
+ DBG("device path missmatch: '%s' != '%s'\n", xusb->devpath_tail, p);
+ return 0;
+ }
+ return 1;
+}
+
+struct xusb *xusb_find_bypath(const struct xusb_spec *specs, int numspecs, const char *path)
+{
+ struct xlist_node *xlist;
+ struct xlist_node *head;
+ struct xusb *xusb;
+
+ xlist = xusb_find_byproduct(specs, numspecs, xusb_filter_bypath, (void *)path);
+ head = xlist_shift(xlist);
+ if (!head)
+ return NULL;
+ if (! xlist_empty(xlist)) {
+ ERR("Too many matches (extra %zd) to '%s'\n", xlist_length(xlist), path);
+ return NULL;
+ }
+ xusb = head->data;
+ xlist_destroy(xlist, NULL);
+ return xusb;
+}
+
+struct xlist_node *xusb_find_byproduct(const struct xusb_spec *specs, int numspecs, xusb_filter_t filterfunc, void *data)
+{
+ struct xlist_node *xlist;
+ struct usb_bus *bus;
+ struct usb_device *dev;
+
+ DBG("specs(%d)\n", numspecs);
+ if((xlist = xlist_new(NULL)) == NULL) {
+ ERR("Failed allocation new xlist");
+ goto fail_xlist;
+ }
+ usb_init();
+ usb_find_busses();
+ usb_find_devices();
+ for (bus = usb_get_busses(); bus; bus = bus->next) {
+ for (dev = bus->devices; dev; dev = dev->next) {
+ struct usb_device_descriptor *dev_desc;
+ struct xlist_node *item;
+ int i;
+
+ dev_desc = &dev->descriptor;
+ assert(dev_desc);
+ DBG("usb:%s/%s: ID=%04X:%04X\n",
+ dev->bus->dirname,
+ dev->filename,
+ dev_desc->idVendor,
+ dev_desc->idProduct);
+ for(i = 0; i < numspecs; i++) {
+ struct xusb *xusb;
+ const struct xusb_spec *sp = &specs[i];
+
+ if(!match_interface(dev, sp))
+ continue;
+ if((xusb = xusb_new(dev, sp)) == NULL) {
+ ERR("xusb allocation failed\n");
+ goto fail_malloc;
+ }
+ if(filterfunc && !filterfunc(xusb, data)) {
+ xusb_destroy(xusb);
+ continue;
+ }
+ item = xlist_new(xusb);
+ xlist_append_item(xlist, item);
+ break;
+ }
+ }
+ }
+ xusb_list_dump(xlist);
+ return xlist;
+fail_malloc:
+ xlist_destroy(xlist, NULL);
+fail_xlist:
+ return NULL;
+}
+
+struct xusb *xusb_open_one(const struct xusb_spec *specs, int numspecs, xusb_filter_t filterfunc, void *data)
+{
+ struct xlist_node *xusb_list;
+ struct xlist_node *curr;
+ int num;
+ struct xusb *xusb = NULL;
+
+ xusb_list = xusb_find_byproduct(specs, numspecs, filterfunc, data);
+ num = xlist_length(xusb_list);
+ DBG("total %d devices\n", num);
+ switch(num) {
+ case 0:
+ ERR("No matching device.\n");
+ break;
+ case 1:
+ curr = xlist_shift(xusb_list);
+ xusb = curr->data;
+ xlist_destroy(curr, NULL);
+ xlist_destroy(xusb_list, NULL);
+ xusb_claim_interface(xusb);
+ xusb_showinfo(xusb);
+ break;
+ default:
+ ERR("Too many devices (%d). Aborting.\n", num);
+ break;
+ }
+ return xusb;
+}
+
+int xusb_interface(struct xusb *xusb)
+{
+ return xusb->interface_num;
+}
+
+size_t xusb_packet_size(const struct xusb *xusb)
+{
+ return xusb->packet_size;
+}
+
+/*
+ * MP device handling
+ */
+void xusb_showinfo(const struct xusb *xusb)
+{
+ struct usb_device_descriptor *dev_desc;
+ struct usb_device *dev;
+
+ assert(xusb != NULL);
+ dev = xusb->dev;
+ dev_desc = &dev->descriptor;
+ if(verbose <= LOG_INFO) {
+ INFO("usb:%s/%s: ID=%04X:%04X [%s / %s / %s]\n",
+ dev->bus->dirname,
+ dev->filename,
+ dev_desc->idVendor,
+ dev_desc->idProduct,
+ xusb->iManufacturer,
+ xusb->iProduct,
+ xusb->iSerialNumber);
+ } else {
+ printf("USB Bus/Device: [%s/%s] (%s,%s)\n",
+ dev->bus->dirname,
+ dev->filename,
+ (xusb->is_open) ? "open" : "closed",
+ (xusb->is_claimed) ? "claimed" : "unused");
+ printf("USB Spec name: [%s]\n", xusb->spec->name);
+ printf("USB iManufacturer: [%s]\n", xusb->iManufacturer);
+ printf("USB iProduct: [%s]\n", xusb->iProduct);
+ printf("USB iSerialNumber: [%s]\n", xusb->iSerialNumber);
+ }
+}
+
+const char *xusb_serial(const struct xusb *xusb)
+{
+ return xusb->iSerialNumber;
+}
+
+const char *xusb_devpath(const struct xusb *xusb)
+{
+ return xusb->devpath_tail;
+}
+
+const char *xusb_manufacturer(const struct xusb *xusb)
+{
+ return xusb->iManufacturer;
+}
+
+const char *xusb_product(const struct xusb *xusb)
+{
+ return xusb->iProduct;
+}
+
+uint16_t xusb_vendor_id(const struct xusb *xusb)
+{
+ return xusb->dev->descriptor.idVendor;
+}
+
+uint16_t xusb_product_id(const struct xusb *xusb)
+{
+ return xusb->dev->descriptor.idProduct;
+}
+
+const struct xusb_spec *xusb_spec(const struct xusb *xusb)
+{
+ return xusb->spec;
+}
+
+int xusb_close(struct xusb *xusb)
+{
+ if(xusb) {
+ if(xusb->handle) {
+ assert(xusb->spec);
+ assert(xusb->spec->name);
+ DBG("Closing interface \"%s\"\n", xusb->spec->name);
+ if(xusb->is_claimed) {
+ if(usb_release_interface(xusb->handle, xusb->spec->my_interface_num) != 0) {
+ ERR("Releasing interface: usb: %s\n", usb_strerror());
+ }
+ xusb->is_claimed = 0;
+ }
+ if(xusb->is_open) {
+ if(usb_close(xusb->handle) != 0) {
+ ERR("Closing device: usb: %s\n", usb_strerror());
+ }
+ xusb->is_open = 0;
+ }
+ xusb->handle = NULL;
+ }
+ xusb = NULL;
+ }
+ return 0;
+}
+
+int xusb_send(struct xusb *xusb, char *buf, int len, int timeout)
+{
+ int ret;
+
+ dump_packet(LOG_DEBUG, DBG_MASK, __FUNCTION__, buf, len);
+ if(EP_OUT(xusb) & USB_ENDPOINT_IN) {
+ ERR("%s called with an input endpoint 0x%x\n", __FUNCTION__, EP_OUT(xusb));
+ return -EINVAL;
+ }
+ ret = usb_bulk_write(xusb->handle, EP_OUT(xusb), buf, len, timeout);
+ if(ret < 0) {
+ /*
+ * If the device was gone, it may be the
+ * result of renumeration. Ignore it.
+ */
+ if(ret != -ENODEV) {
+ ERR("bulk_write to endpoint 0x%x failed: (%d) %s\n",
+ EP_OUT(xusb), ret, usb_strerror());
+ dump_packet(LOG_ERR, DBG_MASK, "xbus_send[ERR]", buf, len);
+ //exit(2);
+ } else {
+ DBG("bulk_write to endpoint 0x%x got ENODEV\n", EP_OUT(xusb));
+ xusb_close(xusb);
+ }
+ return ret;
+ } else if(ret != len) {
+ ERR("bulk_write to endpoint 0x%x short write: (%d) %s\n",
+ EP_OUT(xusb), ret, usb_strerror());
+ dump_packet(LOG_ERR, DBG_MASK, "xbus_send[ERR]", buf, len);
+ return -EFAULT;
+ }
+ return ret;
+}
+
+int xusb_recv(struct xusb *xusb, char *buf, size_t len, int timeout)
+{
+ int ret;
+
+ if(EP_IN(xusb) & USB_ENDPOINT_OUT) {
+ ERR("%s called with an output endpoint 0x%x\n", __FUNCTION__, EP_IN(xusb));
+ return -EINVAL;
+ }
+ ret = usb_bulk_read(xusb->handle, EP_IN(xusb), buf, len, timeout);
+ if(ret < 0) {
+ DBG("bulk_read from endpoint 0x%x failed: (%d) %s\n",
+ EP_IN(xusb), ret, usb_strerror());
+ memset(buf, 0, len);
+ return ret;
+ }
+ dump_packet(LOG_DEBUG, DBG_MASK, __FUNCTION__, buf, ret);
+ return ret;
+}
+
+int xusb_flushread(struct xusb *xusb)
+{
+ char tmpbuf[BUFSIZ];
+ int ret;
+
+ DBG("starting...\n");
+ memset(tmpbuf, 0, BUFSIZ);
+ ret = xusb_recv(xusb, tmpbuf, BUFSIZ, 1);
+ if(ret < 0 && ret != -ETIMEDOUT) {
+ ERR("ret=%d\n", ret);
+ return ret;
+ } else if(ret > 0) {
+ DBG("Got %d bytes:\n", ret);
+ dump_packet(LOG_DEBUG, DBG_MASK, __FUNCTION__, tmpbuf, ret);
+ }
+ return 0;
+}
diff --git a/xpp/xtalk/xusb.h b/xpp/xtalk/xusb.h
new file mode 100644
index 0000000..65da029
--- /dev/null
+++ b/xpp/xtalk/xusb.h
@@ -0,0 +1,98 @@
+#ifndef XUSB_H
+#define XUSB_H
+/*
+ * Written by Oron Peled <oron@actcom.co.il>
+ * Copyright (C) 2008, Xorcom
+ *
+ * All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ */
+
+#include <stdio.h>
+#include <stdint.h>
+#include <usb.h>
+#include <xlist.h>
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif /* __cplusplus */
+
+/*
+ * Xorcom usb handling
+ */
+
+#define PACKET_SIZE 512
+
+/*
+ * Specify the wanted interface
+ */
+struct xusb_spec {
+ /* Sanity checks so we know it is our device indeed */
+ int num_interfaces;
+ int num_endpoints;
+ char *name; /* For debug/output purpose */
+ /* What we will actually use */
+ uint16_t my_vendor_id;
+ uint16_t my_product_id;
+ int my_interface_num;
+ int my_ep_out;
+ int my_ep_in;
+};
+
+void xusb_init_spec(struct xusb_spec *xusb_spec, char *name,
+ uint16_t vendor_id, uint16_t product_id,
+ int nifaces, int iface, int nep, int ep_out, int ep_in);
+
+struct xusb;
+
+/*
+ * Prototypes
+ */
+typedef int (*xusb_filter_t)(const struct xusb *xusb, void *data);
+struct xlist_node *xusb_find_byproduct(const struct xusb_spec *specs, int numspecs, xusb_filter_t filterfunc, void *data);
+struct xusb *xusb_find_bypath(const struct xusb_spec *specs, int numspecs, const char *path);
+struct xusb *xusb_open_one(const struct xusb_spec *specs, int numspecs, xusb_filter_t filterfunc, void *data);
+struct xusb *xusb_find_iface(const char *devpath, int iface_num, int ep_out, int ep_in);
+
+/*
+ * A convenience filter
+ */
+int xusb_filter_bypath(const struct xusb *xusb, void *data);
+
+int xusb_interface(struct xusb *xusb);
+int xusb_claim_interface(struct xusb *xusb);
+void xusb_destroy(struct xusb *xusb);
+int xusb_close(struct xusb *xusb);
+size_t xusb_packet_size(const struct xusb *xusb);
+void xusb_showinfo(const struct xusb *xusb);
+const char *xusb_serial(const struct xusb *xusb);
+const char *xusb_manufacturer(const struct xusb *xusb);
+const char *xusb_product(const struct xusb *xusb);
+uint16_t xusb_vendor_id(const struct xusb *xusb);
+uint16_t xusb_product_id(const struct xusb *xusb);
+const char *xusb_devpath(const struct xusb *xusb);
+const struct xusb_spec *xusb_spec(const struct xusb *xusb);
+int xusb_send(struct xusb *xusb, char *buf, int len, int timeout);
+int xusb_recv(struct xusb *xusb, char *buf, size_t len, int timeout);
+int xusb_flushread(struct xusb *xusb);
+
+#ifdef __cplusplus
+}
+#endif /* __cplusplus */
+
+#endif /* XUSB_H */