summaryrefslogtreecommitdiff
path: root/xpp/xpp_usb.c
diff options
context:
space:
mode:
authortzafrir <tzafrir@5390a7c7-147a-4af0-8ec9-7488f05a26cb>2006-07-08 00:43:31 +0000
committertzafrir <tzafrir@5390a7c7-147a-4af0-8ec9-7488f05a26cb>2006-07-08 00:43:31 +0000
commitec6b220aa7a334ccbd0fcb41d35c66560fc78a11 (patch)
tree8ee3f2338f95b3fa67f8512adb8fe4842643c391 /xpp/xpp_usb.c
parent4e4b79bf56f6477b65973c869e5a8936aea27864 (diff)
xpp Release 1.1.0 :
* FPGA firmware now loaded from PC (for newer models) * Driver for the FXO module (xpd_fxo.ko) * Moved most userspace files to the subdirectory utils (see also next commit) * Explicit license for firmware files * Optionally avoid auto-registration * Registers initializations code is done by a userspace script. * Remove obsolete .inc initialization files (we use user-space init) * Added an install target to the utils dir. * Updated README.Astribank accordingly. * Using RBS signalling, as caller ID did not work well otherwise. * Better handling of USB protocol errors. * Fixed some procfs-related races. * per-card-module ioctls. * fxotune support. * opermode support (set through /etc/default/zaptel for now) * Userspace initialization script can also read registers. * Power calibration works (and implemented in perl) * some fine-tuning to the regster initialization parameters. * Leds turn on before registration and turn off after it. git-svn-id: http://svn.digium.com/svn/zaptel/branches/1.2@1212 5390a7c7-147a-4af0-8ec9-7488f05a26cb
Diffstat (limited to 'xpp/xpp_usb.c')
-rw-r--r--xpp/xpp_usb.c445
1 files changed, 241 insertions, 204 deletions
diff --git a/xpp/xpp_usb.c b/xpp/xpp_usb.c
index 83eee1a..4f81680 100644
--- a/xpp/xpp_usb.c
+++ b/xpp/xpp_usb.c
@@ -1,6 +1,6 @@
/*
* Written by Oron Peled <oron@actcom.co.il>
- * Copyright (C) 2004-2005, Xorcom
+ * Copyright (C) 2004-2006, Xorcom
*
* All rights reserved.
*
@@ -30,6 +30,7 @@
#include <linux/module.h>
#include <linux/init.h>
#include <linux/errno.h>
+#include <linux/interrupt.h>
#include <linux/delay.h> /* for udelay */
#include <linux/seq_file.h>
#include <asm/uaccess.h>
@@ -37,11 +38,16 @@
#include <asm/timex.h>
#include <linux/proc_fs.h>
#include <linux/usb.h>
+#include <version.h> /* For zaptel version */
#include "xpd.h"
#include "xproto.h"
-#include "xpp_zap.h"
+#include "xbus-core.h"
+#ifdef DEBUG
+#include "card_fxs.h"
+#include "card_fxo.h"
+#endif
-static const char revision[] = "$Revision$";
+static const char rcsid[] = "$Id$";
DEF_PARM(int, print_dbg, 0, "Print DBG statements"); /* must be before zap_debug.h */
@@ -52,13 +58,11 @@ DEF_PARM(int, print_dbg, 0, "Print DBG statements"); /* must be before zap_debug
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,14)
# define URB_ASYNC_UNLINK 0
#endif
-
#define USBDEV_MAX 10
/* Get a minor range for your devices from the usb maintainer */
#define USB_SKEL_MINOR_BASE 192
#ifdef CONFIG_PROC_FS
-#define PROC_XBUSES "xpp_usb"
#define PROC_USBXPP_SUMMARY "xpp_usb"
#endif
@@ -70,8 +74,9 @@ static cycles_t accumulate_diff;
struct xusb_model_info;
struct xusb_endpoint {
- int epnum;
- int max_size;
+ int ep_addr;
+ int max_size;
+ usb_complete_t callback;
};
static int xusb_packet_send(xbus_t *xbus, xpacket_t *pack);
@@ -110,18 +115,24 @@ static struct xusb_counters {
#define XUSB_COUNTER_MAX ARRAY_SIZE(xusb_counters)
+#define MAX_PENDING_WRITES 100
+
+enum xusb_dir {
+ XUSB_RECV = 0,
+ XUSB_SEND = 1,
+};
+
/*
* USB XPP Bus (a USB Device)
*/
-struct xpp_usb_bus {
+typedef struct xpp_usb_bus {
xbus_t *xbus;
struct usb_device *udev; /* save off the usb device pointer */
struct usb_interface *interface; /* the interface for this device */
unsigned char minor; /* the starting minor number for this device */
struct xusb_model_info *model_info;
- struct xusb_endpoint ep_in;
- struct xusb_endpoint ep_out;
+ struct xusb_endpoint endpoints[2]; /* RECV/SEND endpoints */
struct urb *read_urb;
@@ -129,12 +140,13 @@ struct xpp_usb_bus {
int present; /* if the device is not disconnected */
int reading; /* is the read_urb reading (listening) */
+ atomic_t pending_writes; /* submited but not out yet */
struct semaphore sem; /* locks this structure */
int counters[XUSB_COUNTER_MAX];
-};
+} xusb_t;
static spinlock_t xusb_lock = SPIN_LOCK_UNLOCKED;
-static struct xpp_usb_bus *xusb_array[USBDEV_MAX] = {};
+static xusb_t *xusb_array[USBDEV_MAX] = {};
static unsigned bus_count = 0;
@@ -153,7 +165,7 @@ static int xusb_release (struct inode *inode, struct file *file);
static void xusb_write_bulk_callback (struct urb *urb, struct pt_regs *regs);
#endif
static void xpp_urb_delete(struct urb *urb);
-static struct urb *xpp_urb_new(struct xpp_usb_bus *dev, unsigned int ep_addr, size_t size, usb_complete_t urb_cb);
+static struct urb *xpp_urb_new(xusb_t *dev, enum xusb_dir dir, size_t size);
static void xpp_send_callback(struct urb *urb, struct pt_regs *regs);
static void xpp_receive_callback(struct urb *urb, struct pt_regs *regs);
@@ -208,42 +220,34 @@ void xusb_packet_free(xbus_t *xbus, xpacket_t *p)
//DBG("Decremented packet_counter of bus %s (freed packet) to %d\n",
// xbus->busname, atomic_read(&xbus->packet_counter));
}
+
#endif
-static int xusb_packet_send(xbus_t *xbus, xpacket_t *pack)
+#ifndef DEBUG
+
+#define packet_debug(m, x, p)
+
+#else
+
+static void packet_debug(const char msg[], xusb_t *xusb, xpacket_t *pack)
{
- struct xpp_usb_bus *xusb = xbus->priv;
- struct urb *urb;
- int ret = 0;
- size_t size;
+ char title[XBUS_DESCLEN];
- BUG_ON(!pack);
- if(!xusb->present) {
- NOTICE("tried to send packets to non-exitant USB device. Ignored\n");
- goto error;
- }
-#if SOFT_SIMULATOR
- {
- int toxpd = XPD_NUM(pack->content.addr);
-
- if (xbus->sim[toxpd].softloop_xpd) {
- // "send" through loopback queue
- //DBG("%s: ENQUEUE toxpd=%d, opcode=%X\n", xbus->busname, toxpd, pack->content.opcode);
- XBUS_COUNTER(xbus, SOFTSIM_PACKETS)++;
- xbus_enqueue_packet(xbus, &xbus->sim_packet_queue, pack);
- ret = queue_work(xbus->sim_workqueue, &xbus->sim_work);
- if(ret < 0) {
- ERR("%s: queue_work failed with %d (ignoring)\n", __FUNCTION__, ret);
- goto error;
- }
- }
- return 0;
- }
+ if(pack->content.opcode == XPROTO_NAME(GLOBAL,PCM_READ)) {
+#ifdef DEBUG_PCM_TIMING
+ /*
+ * DEBUG: high-res timing of PCM_READ to PCM_WRITE
+ */
+ stamp_last_pcm_read = get_cycles();
#endif
- size = min(PACKET_LEN(pack), (size_t)xusb->ep_out.max_size);
- if(pack->content.opcode == XPROTO_NAME(GLOBAL,PCM_WRITE)) {
- XUSB_COUNTER(xusb, PCM_WRITES)++;
-
+#if 0
+ // fill_beep((u_char *)&PACKET_FIELD(pack, PCM_READS, pcm), 2); // Debugging BEEP
+ static int rate_limit;
+ if((rate_limit++ % 1000) < 10)
+ dump_packet("USB RECEIVE PCM", pack, print_dbg);
+#endif
+ return;
+ } else if(pack->content.opcode == XPROTO_NAME(GLOBAL,PCM_WRITE)) {
#ifdef DEBUG_PCM_TIMING
/*
* DEBUG: high-res timing of PCM_READ to PCM_WRITE
@@ -253,50 +257,96 @@ static int xusb_packet_send(xbus_t *xbus, xpacket_t *pack)
#endif
#if 0
static int rate_limit;
- if((rate_limit++ % 1009) < 3) {
+ if((rate_limit++ % 1000) < 10)
dump_packet("USB SEND PCM", pack, print_dbg);
- }
#endif
- } else {
- dump_packet("USB_PACKET_SEND", pack, print_dbg);
+ return;
+ } else if(pack->content.opcode == XPROTO_NAME(FXS, SLIC_WRITE)) {
+ slic_cmd_t *sc;
+
+ sc = &RPACKET_FIELD(pack, FXS, SLIC_WRITE, slic_cmd);
+ if(sc->bytes == 2 && sc->content.direct.reg_num == 0x06 && sc->content.direct.read) /* ignore SLIC_QUERY */
+ return;
+ if(sc->bytes == 2 && sc->content.direct.reg_num == DAA_VBAT_REGISTER && sc->content.direct.read) /* ignore DAA_QUERY */
+ return;
+ } else if(pack->content.opcode == XPROTO_NAME(FXS, SLIC_REPLY)) {
+ return;
+ }
+ snprintf(title, XBUS_DESCLEN, "%s: %s", msg, xusb->xbus->busname);
+ dump_packet(title, pack, print_dbg);
+}
+#endif
+
+static int xusb_packet_send(xbus_t *xbus, xpacket_t *pack)
+{
+ xusb_t *xusb;
+ struct urb *urb;
+ int ret = 0;
+ size_t size;
+ struct xusb_endpoint *xusb_ep;
+
+ BUG_ON(!pack);
+ BUG_ON(!xbus);
+ xusb = xbus->priv;
+ BUG_ON(!xusb);
+ if(!xusb->present) {
+ NOTICE("tried to send packets to non-exitant USB device. Ignored\n");
+ ret = -ENODEV;
+ goto out;
}
- urb = xpp_urb_new(xusb, xusb->ep_out.epnum, size, xpp_send_callback);
+ size = PACKET_LEN(pack);
+ xusb_ep = &xusb->endpoints[XUSB_SEND];
+ urb = xpp_urb_new(xusb, XUSB_SEND, size);
if (!urb) {
ERR("No free urbs available\n");
ret = -ENOMEM;
- goto error;
+ goto out;
}
+ packet_debug("USB_PACKET_SEND", xusb, pack);
/* FIXME: FIXME: FIXME: we use copy+free until low-level drivers allocate memory themselves */
memcpy(urb->transfer_buffer, &pack->content, size);
- xbus->ops->packet_free(xbus, pack);
- ret = usb_submit_urb(urb, GFP_KERNEL);
+ ret = usb_submit_urb(urb, GFP_ATOMIC);
if(ret < 0) {
- ERR("%s: failed submit_urb\n", __FUNCTION__);
- XUSB_COUNTER(xusb, TX_ERRORS)++;
+ ERR("%s: failed submit_urb: %d\n", __FUNCTION__, ret);
xpp_urb_delete(urb);
- return -EBADF;
+ ret = -EBADF;
+ goto out;
}
- return 0;
-error:
+ atomic_inc(&xusb->pending_writes);
+ if(atomic_read(&xusb->pending_writes) > MAX_PENDING_WRITES) {
+ static int rate_limit;
+
+ if((rate_limit++ % 1000) < 10)
+ ERR("%s: %s: more than %d pending writes. Dropping.\n", __FUNCTION__, xbus->busname, MAX_PENDING_WRITES);
+ ret = -ENODEV;
+ }
+ if(pack->content.opcode == XPROTO_NAME(GLOBAL,PCM_WRITE))
+ XUSB_COUNTER(xusb, PCM_WRITES)++;
+out:
+ if(ret < 0)
+ XUSB_COUNTER(xusb, TX_ERRORS)++;
xbus->ops->packet_free(xbus, pack); // FIXME: eventually will be done in the urb callback
return ret;
}
static void xpp_urb_delete(struct urb *urb)
{
+ BUG_ON(!urb);
// DBG("%s: (%d) %p %X", __FUNCTION__, urb->transfer_buffer_length, urb->transfer_buffer, urb->transfer_dma);
usb_buffer_free (urb->dev, urb->transfer_buffer_length,
urb->transfer_buffer,
urb->transfer_dma);
- usb_free_urb (urb);
+ usb_free_urb(urb);
}
-static struct urb *xpp_urb_new(struct xpp_usb_bus *dev, unsigned int ep_addr, size_t size, usb_complete_t urb_cb)
-
+static struct urb *xpp_urb_new(xusb_t *xusb, enum xusb_dir dir, size_t size)
{
- struct usb_device *udev = dev->udev;
+ struct usb_device *udev = xusb->udev;
+ struct xusb_endpoint *xusb_ep = &xusb->endpoints[dir];
+ unsigned int ep_addr = xusb_ep->ep_addr;
+ usb_complete_t urb_cb = xusb_ep->callback;
struct urb *urb;
unsigned char *buffer; /* the buffer to send data */
unsigned int epnum = ep_addr & USB_ENDPOINT_NUMBER_MASK;
@@ -304,6 +354,8 @@ static struct urb *xpp_urb_new(struct xpp_usb_bus *dev, unsigned int ep_addr, si
? usb_rcvbulkpipe(udev, epnum)
: usb_sndbulkpipe(udev, epnum);
+ if(size > xusb_ep->max_size)
+ return NULL;
urb = usb_alloc_urb(0, GFP_ATOMIC);
if (!urb) {
err("No free urbs available");
@@ -326,32 +378,36 @@ static struct urb *xpp_urb_new(struct xpp_usb_bus *dev, unsigned int ep_addr, si
usb_free_urb(urb);
return NULL;
}
- usb_fill_bulk_urb(urb, udev, pipe, buffer, size, urb_cb, dev);
+ usb_fill_bulk_urb(urb, udev, pipe, buffer, size, urb_cb, xusb);
return urb;
}
/*------------------------- XPP USB Bus Handling -------------------*/
-static struct xusb_model_info {
+#define XUSB_MODEL(ep_in,ep_out,type,str) \
+ { \
+ .in = { .ep_addr = (ep_in) }, \
+ .out = { .ep_addr = (ep_out) }, \
+ .bus_type = (type), \
+ .desc = (str) \
+ }
+
+static const struct xusb_model_info {
const char *desc;
struct xusb_endpoint in;
struct xusb_endpoint out;
xbus_type_t bus_type;
} model_table[] = {
- { .in = { .epnum = 0x86 }, .out = { .epnum = 0x2 }, .bus_type = FIRMWARE_LOOPBACK, .desc = "bulkloop.hex" },
- { .in = { .epnum = 0x86 }, .out = { .epnum = 0x2 }, .bus_type = FIRMWARE_LOOPBACK, .desc = "FPGA_bulkloop.hex" },
- { .in = { .epnum = 0x86 }, .out = { .epnum = 0x2 }, .bus_type = FIRMWARE_XPP, .desc = "FPGA_XPD.hex" },
+ XUSB_MODEL(0x86, 0x02, FIRMWARE_LOOPBACK, "bulkloop.hex"),
+ XUSB_MODEL(0x86, 0x02, FIRMWARE_LOOPBACK, "FPGA_bulkloop.hex"),
+ XUSB_MODEL(0x86, 0x02, FIRMWARE_XPP, "FPGA_XPD.hex"),
};
/* table of devices that work with this driver */
-static struct usb_device_id xusb_table [] = {
+static const struct usb_device_id xusb_table [] = {
// { USB_DEVICE(0x04B4, 0x8613) }, // default of cypress
- { USB_DEVICE(0x0547, 0x1002), .driver_info=(int)&model_table[0] }, // bulkloop.hex
-// { USB_DEVICE(0x04B4, 0x1004), .driver_info=(int)&model_table[1] }, // FPGA_bulkloop.hex
-// { USB_DEVICE(0x04B4, 0x1004), .driver_info=(int)&model_table[2] }, // FIXME: temporary test for Dima
- { USB_DEVICE(0xE4E4, 0x2211), .driver_info=(int)&model_table[2] }, // FPGA_XPD.hex
- //{ USB_DEVICE(0x0548, 0x1) },
- //{ USB_DEVICE(0x062a, 0x0) },
+ { USB_DEVICE(0xE4E4, 0x2211), .driver_info=(kernel_ulong_t)&model_table[2] }, // FPGA_XPD.hex
+ { USB_DEVICE(0xE4E4, 0x1132), .driver_info=(kernel_ulong_t)&model_table[2] }, // FPGA_XPD.hex
/* "Gadget Zero" firmware runs under Linux */
//{ USB_DEVICE(0x0525, 0xa4a0) },
{ } /* Terminating entry */
@@ -363,7 +419,7 @@ MODULE_DEVICE_TABLE (usb, xusb_table);
/* usb specific object needed to register this driver with the usb subsystem */
static struct usb_driver xusb_driver = {
#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,16)
- .owner = THIS_MODULE,
+ .owner = THIS_MODULE,
#endif
.name = "xpp_usb",
.probe = xusb_probe,
@@ -412,10 +468,12 @@ static struct usb_class_driver xusb_class = {
* check out the endpoints
* FIXME: Should be simplified (above 2.6.10) to use usb_dev->ep_in[0..16] and usb_dev->ep_out[0..16]
*/
-static int set_endpoints(struct xpp_usb_bus *xusb, struct usb_interface *interface, struct xusb_model_info *model_info)
+static int set_endpoints(xusb_t *xusb, struct usb_interface *interface, struct xusb_model_info *model_info)
{
struct usb_host_interface *iface_desc;
struct usb_endpoint_descriptor *endpoint;
+ struct xusb_endpoint *xusb_ep;
+ int ep_addr;
int i;
iface_desc = &interface->altsetting[0];
@@ -425,37 +483,40 @@ static int set_endpoints(struct xpp_usb_bus *xusb, struct usb_interface *interfa
for (i = 0; i < iface_desc->desc.bNumEndpoints; ++i) {
endpoint = &iface_desc->endpoint[i].desc;
- int epnum = endpoint->bEndpointAddress;
+ ep_addr = endpoint->bEndpointAddress;
if(!BULK_ENDPOINT(endpoint)) {
DBG("endpoint 0x%x is not bulk: mbAttributes=0x%X\n",
- epnum, endpoint->bmAttributes);
+ ep_addr, endpoint->bmAttributes);
continue;
}
- if(epnum & USB_DIR_IN) { // Input
- if(epnum == model_info->in.epnum) {
+ if(usb_pipein(ep_addr)) { // Input
+ if(ep_addr == model_info->in.ep_addr) {
if(endpoint->wMaxPacketSize < sizeof(xpacket_raw_t)) {
- ERR("USB input endpoint 0x%X support only wMaxPacketSize=%d (need USB-2)\n", epnum, endpoint->wMaxPacketSize);
- break;
+ NOTICE("USB input endpoint 0x%X support only wMaxPacketSize=%d (need USB-2)\n", ep_addr, endpoint->wMaxPacketSize);
}
- xusb->ep_in.epnum = epnum;
- xusb->ep_in.max_size = endpoint->wMaxPacketSize;
+ xusb_ep = &xusb->endpoints[XUSB_RECV];
+ xusb_ep->ep_addr = ep_addr;
+ xusb_ep->max_size = endpoint->wMaxPacketSize;
+ xusb_ep->callback = xpp_receive_callback;
}
- } else { // Output
- if(epnum == model_info->out.epnum) {
+ } else { // Output
+ if(ep_addr == model_info->out.ep_addr) {
if(endpoint->wMaxPacketSize < sizeof(xpacket_raw_t)) {
- ERR("USB output endpoint 0x%X support only wMaxPacketSize=%d (need USB-2)\n", epnum, endpoint->wMaxPacketSize);
- break;
+ NOTICE("USB output endpoint 0x%X support only wMaxPacketSize=%d (need USB-2)\n", ep_addr, endpoint->wMaxPacketSize);
}
- xusb->ep_out.epnum = epnum;
- xusb->ep_out.max_size = endpoint->wMaxPacketSize;
+ xusb_ep = &xusb->endpoints[XUSB_SEND];
+ xusb_ep->ep_addr = ep_addr;
+ xusb_ep->max_size = endpoint->wMaxPacketSize;
+ xusb_ep->callback = xpp_send_callback;
}
}
}
- if (!xusb->ep_in.epnum || !xusb->ep_out.epnum) {
+ if (!xusb->endpoints[XUSB_RECV].ep_addr || !xusb->endpoints[XUSB_SEND].ep_addr) {
ERR("Couldn't find bulk-in or bulk-out endpoints\n");
return 0;
}
+ DBG("in=0x%02X out=0x%02X\n", xusb->endpoints[XUSB_RECV].ep_addr, xusb->endpoints[XUSB_SEND].ep_addr);
return 1;
}
@@ -468,10 +529,11 @@ static int set_endpoints(struct xpp_usb_bus *xusb, struct usb_interface *interfa
static int xusb_probe(struct usb_interface *interface, const struct usb_device_id *id)
{
struct usb_device *udev = interface_to_usbdev(interface);
- struct xpp_usb_bus *xusb = NULL;
+ xusb_t *xusb = NULL;
struct xusb_model_info *model_info = (struct xusb_model_info*)id->driver_info;
- struct proc_dir_entry *procsummary;
- xbus_t *xbus;
+ struct proc_dir_entry *procsummary = NULL;
+ xbus_t *xbus = NULL;
+ struct xusb_endpoint *xusb_ep;
unsigned long flags;
int retval = -ENOMEM;
int i;
@@ -490,15 +552,16 @@ static int xusb_probe(struct usb_interface *interface, const struct usb_device_i
}
/* allocate memory for our device state and initialize it */
- xusb = kmalloc(sizeof(struct xpp_usb_bus), GFP_KERNEL);
+ xusb = kmalloc(sizeof(xusb_t), GFP_KERNEL);
if (xusb == NULL) {
ERR("xpp_usb: Unable to allocate new xpp usb bus\n");
retval = -ENOMEM;
goto probe_failed;
}
- memset(xusb, 0, sizeof(struct xpp_usb_bus));
+ memset(xusb, 0, sizeof(xusb_t));
init_MUTEX (&xusb->sem);
+ atomic_set(&xusb->pending_writes, 0);
xusb->udev = udev;
xusb->interface = interface;
xusb->model_info = model_info;
@@ -507,12 +570,14 @@ static int xusb_probe(struct usb_interface *interface, const struct usb_device_i
retval = -ENODEV;
goto probe_failed;
}
- xusb->read_urb = xpp_urb_new(xusb, xusb->ep_in.epnum, xusb->ep_in.max_size, xpp_receive_callback);
+ xusb_ep = &xusb->endpoints[XUSB_RECV];
+ xusb->read_urb = xpp_urb_new(xusb, XUSB_RECV, xusb_ep->max_size);
if (!xusb->read_urb) {
ERR("No free urbs available\n");
retval = -ENOMEM;
goto probe_failed;
}
+
/* allow device read, write and ioctl */
xusb->present = 1;
@@ -521,7 +586,7 @@ static int xusb_probe(struct usb_interface *interface, const struct usb_device_i
retval = usb_register_dev (interface, &xusb_class);
if (retval) {
/* something prevented us from registering this driver */
- ERR ("Not able to get a minor for this device.");
+ ERR ("Not able to get a minor for this device.\n");
goto probe_failed;
}
@@ -531,33 +596,31 @@ static int xusb_probe(struct usb_interface *interface, const struct usb_device_i
INFO ("USB XPP device now attached to minor %d\n", xusb->minor);
/* Allocate high level structures */
- xbus = xbus_new((model_info->bus_type == FIRMWARE_LOOPBACK) ? ~0 : 0);
+ xbus = xbus_new(&xusb_ops);
if(!xbus) {
retval = -ENOMEM;
goto probe_failed;
}
- xusb->xbus = xbus;
- xbus->priv = xusb;
xbus->bus_type = model_info->bus_type;
+ xbus->max_packet_size = min(xusb->endpoints[XUSB_SEND].max_size , xusb->endpoints[XUSB_RECV].max_size);
spin_lock_irqsave(&xusb_lock, flags);
for(i = 0; i < USBDEV_MAX; i++) {
if(xusb_array[i] == NULL)
break;
}
+ spin_unlock_irqrestore(&xusb_lock, flags);
if(i >= USBDEV_MAX) {
ERR("xpp_usb: Too many XPP USB buses\n");
retval = -ENOMEM;
goto probe_failed;
}
- spin_unlock_irqrestore(&xusb_lock, flags);
{
char path[XBUS_DESCLEN];
usb_make_path(udev, path, XBUS_DESCLEN); // May trunacte... ignore
snprintf(xbus->busdesc, XBUS_DESCLEN, "%s", path);
}
- xbus->ops = &xusb_ops;
DBG("GOT XPP USB BUS #%d: %s (type=%d)\n", i, xbus->busdesc, xbus->bus_type);
@@ -568,20 +631,22 @@ static int xusb_probe(struct usb_interface *interface, const struct usb_device_i
DBG("Creating proc entry " PROC_USBXPP_SUMMARY " in bus proc dir.\n");
procsummary = create_proc_read_entry(PROC_USBXPP_SUMMARY, 0444, xbus->proc_xbus_dir,
xusb_read_proc, xusb);
- //xbus->procsummary = 1; // temporary: not 0, for the condition below
if (!procsummary) {
ERR("Failed to create proc read entry for xbus %s\n", xbus->busname);
// FIXME: better error handling
retval = -EIO;
goto probe_failed;
}
+ procsummary->owner = THIS_MODULE;
#endif
+ bus_count++;
retval = usb_submit_urb(xusb->read_urb, GFP_ATOMIC);
if(retval < 0) {
ERR("%s: Failed to submit the receive URB errno=%d\n", __FUNCTION__, retval);
}
- bus_count++;
- xbus_activate(xusb->xbus);
+ xusb->xbus = xbus;
+ xbus->priv = xusb;
+ xbus_activate(xbus);
return retval;
probe_failed:
ERR("Failed to initialize xpp usb bus: %d\n", retval);
@@ -593,6 +658,13 @@ probe_failed:
usb_deregister_dev(interface, &xusb_class);
kfree(xusb);
}
+ if(xbus) {
+ if(procsummary) {
+ DBG("Remove proc_entry: " PROC_USBXPP_SUMMARY "\n");
+ remove_proc_entry(PROC_USBXPP_SUMMARY, xbus->proc_xbus_dir);
+ }
+ xbus_disconnect(xbus); // Blocking until fully deactivated!
+ }
return retval;
}
@@ -609,7 +681,7 @@ probe_failed:
*/
static void xusb_disconnect(struct usb_interface *interface)
{
- struct xpp_usb_bus *xusb;
+ xusb_t *xusb;
xbus_t *xbus;
int minor;
int i;
@@ -636,7 +708,7 @@ static void xusb_disconnect(struct usb_interface *interface)
}
#endif
xusb->present = 0;
- xbus_deactivate(xbus); // Blocking until fully deactivated!
+ xbus_disconnect(xbus); // Blocking until fully deactivated!
down (&xusb->sem);
@@ -645,6 +717,7 @@ static void xusb_disconnect(struct usb_interface *interface)
/* give back our minor */
usb_deregister_dev (interface, &xusb_class);
+ /* terminate an ongoing read */
/* terminate an ongoing write */
// FIXME: Does it really kill pending URB's?
@@ -657,59 +730,71 @@ static void xusb_disconnect(struct usb_interface *interface)
kfree(xusb);
up (&disconnect_sem);
- INFO("XUSB #%d now disconnected", minor);
+ INFO("XUSB #%d now disconnected\n", minor);
}
static void xpp_send_callback(struct urb *urb, struct pt_regs *regs)
{
- struct xpp_usb_bus *xusb = (struct xpp_usb_bus *)urb->context;
+ xusb_t *xusb = (xusb_t *)urb->context;
xbus_t *xbus = xusb->xbus;
BUG_ON(!xbus);
+ atomic_dec(&xusb->pending_writes);
/* sync/async unlink faults aren't errors */
if (urb->status && !(urb->status == -ENOENT || urb->status == -ECONNRESET)) {
static int rate_limit;
if((rate_limit++ % 1000) < 10)
- DBG("nonzero read bulk status received: %d", urb->status);
+ DBG("nonzero read bulk status received: %d\n", urb->status);
XUSB_COUNTER(xusb, TX_ERRORS)++;
}
+ xpp_urb_delete(urb);
if(!xusb->present) {
ERR("A packet from non-connected device?\n");
return;
}
- xpp_urb_delete(urb);
/* allow device read, write and ioctl */
XUSB_COUNTER(xusb, TX_PACKETS)++;
}
static void xpp_receive_callback(struct urb *urb, struct pt_regs *regs)
{
- struct xpp_usb_bus *xusb = (struct xpp_usb_bus *)urb->context;
- xbus_t *xbus = xusb->xbus;
-
- xpacket_t *pack;
- size_t size;
- int retval;
+ xusb_t *xusb = (xusb_t *)urb->context;
+ xbus_t *xbus;
+ xpacket_t *pack;
+ size_t size;
+ int retval;
+ bool do_resubmit = 1;
+ bool is_inuse = 0;
- BUG_ON(!xbus);
+ BUG_ON(!xusb);
+ xbus = xusb->xbus;
+ if(!xbus) {
+ NOTICE("spurious URB\n");
+ return;
+ }
if (urb->status) {
- /* sync/async unlink faults aren't errors */
- if (!(urb->status == -EOVERFLOW || urb->status == -EMSGSIZE)) {
- ERR("Dropped connection due to bad URB status: %d\n", urb->status);
- return;
- } else {
- DBG("nonzero read bulk status received: %d\n", urb->status);
- goto end;
+ DBG("nonzero read bulk status received: %d\n", urb->status);
+ XUSB_COUNTER(xusb, RX_ERRORS)++;
+ /* Free old URB, allocate a fresh one */
+ if(xusb->read_urb)
+ xpp_urb_delete(xusb->read_urb);
+ xusb->read_urb = xpp_urb_new(xusb, XUSB_RECV, xusb->endpoints[XUSB_RECV].max_size);
+ if (!xusb->read_urb) {
+ ERR("URB allocation failed\n");
+ do_resubmit = 0;;
}
+ goto end;
}
if(!down_read_trylock(&xbus->in_use)) {
ERR("%s: xbus is going down\n", __FUNCTION__);
- return;
+ do_resubmit = 0;
+ goto end;
}
+ is_inuse = 1;
if(!xusb->present) {
ERR("A packet from non-connected device?\n");
- up_read(&xbus->in_use);
- return;
+ do_resubmit = 0;
+ goto end;
}
pack = xbus->ops->packet_new(xbus, GFP_ATOMIC);
if(!pack) {
@@ -723,42 +808,21 @@ static void xpp_receive_callback(struct urb *urb, struct pt_regs *regs)
pack->datalen = size - sizeof(xpd_addr_t) - 1; // opcode size
// DBG("datalen of new packet: %d\n", pack->datalen);
- // Send UP
- if(pack->content.opcode == XPROTO_NAME(GLOBAL,PCM_READ)) {
+ packet_debug("USB_PACKET_RECEIVE", xusb, pack);
+ XUSB_COUNTER(xusb, RX_PACKETS)++;
+ if(pack->content.opcode == XPROTO_NAME(GLOBAL,PCM_READ))
XUSB_COUNTER(xusb, PCM_READS)++;
-
-#ifdef DEBUG_PCM_TIMING
- /*
- * DEBUG: high-res timing of PCM_READ to PCM_WRITE
- */
- stamp_last_pcm_read = get_cycles();
-#endif
- // fill_beep((u_char *)&PACKET_FIELD(pack, PCM_READS, pcm), 2); // Debugging BEEP
-#if 0
- static int rate_limit;
- if((rate_limit++ % 1000) == 0)
- dump_packet("USB RECEIVE PCM", pack, print_dbg);
-#endif
- } else if(pack->content.opcode == XPROTO_NAME(GLOBAL,PCM_WRITE)) { // FIRMWARE_LOOPBACK
-#if 0
- static int rate_limit;
- if((rate_limit++ % 1000) == 0)
- dump_packet("USB RECEIVE (LOOPBACK) PCM", pack, print_dbg);
-#endif
- } else {
- char title[XBUS_DESCLEN];
-
- snprintf(title, XBUS_DESCLEN, "USB_PACKET_RECEIVE callback (%s)", xbus->busname);
- dump_packet(title, pack, print_dbg);
- }
+ // Send UP
packet_receive(xbus, pack);
- XUSB_COUNTER(xusb, RX_PACKETS)++;
end:
- up_read(&xbus->in_use);
- retval = usb_submit_urb(urb, GFP_KERNEL);
- if (retval < 0) {
- ERR("failed re-submitting read urb, error %d\n", retval);
- return;
+ if(is_inuse)
+ up_read(&xbus->in_use);
+ if(do_resubmit) {
+ retval = usb_submit_urb(urb, GFP_ATOMIC);
+ if (retval < 0) {
+ ERR("failed re-submitting read urb, error %d\n", retval);
+ return;
+ }
}
}
@@ -768,14 +832,14 @@ end:
int __init xpp_usb_init(void)
{
int result;
- //struct xpp_usb_bus *xusb;
+ //xusb_t *xusb;
- INFO("%s revision %s\n", THIS_MODULE->name, revision);
+ INFO("%s revision %s\n", THIS_MODULE->name, ZAPTEL_VERSION);
/* register this driver with the USB subsystem */
result = usb_register(&xusb_driver);
if (result) {
- ERR("usb_register failed. Error number %d", result);
+ ERR("usb_register failed. Error number %d\n", result);
return result;
}
return 0;
@@ -784,34 +848,7 @@ int __init xpp_usb_init(void)
void __exit xpp_usb_cleanup(void)
{
- int i, j;
-
DBG("\n");
- for(i = 0; i < USBDEV_MAX; i++) {
- xbus_t *xbus;
-
- if(xusb_array[i] == NULL)
- continue;
- xbus = xusb_array[i]->xbus;
- if(!xbus) {
- ERR("%s: missing xbus. Skipping\n", __FUNCTION__);
- continue;
- }
- for(j = 0; j < MAX_XPDS; j++) {
- xpd_t *xpd = xpd_of(xbus, j);
-
- if(xpd) {
- if(xpd->id != j) {
- ERR("%s: BUG: xpd->id=%d != j=%d\n", __FUNCTION__, xpd->id, j);
- continue;
- }
-#if 0 // FIXME: retest after new driver start working
- CALL_XMETHOD(CHAN_ENABLE, xbus, xpd, 0xFF, 0); // Disable all hardware channels
- CALL_XMETHOD(LED, xbus, xpd, 0xFF, 1, 0); // FIXME: Show activated channels
-#endif
- }
- }
- }
/* deregister this driver with the USB subsystem */
usb_deregister(&xusb_driver);
}
@@ -822,31 +859,31 @@ void __exit xpp_usb_cleanup(void)
static int xusb_read_proc(char *page, char **start, off_t off, int count, int *eof, void *data)
{
- int len = 0;
- unsigned long flags;
+ int len = 0;
+ unsigned long flags;
+ int i;
//unsigned long stamp = jiffies;
- struct xpp_usb_bus *xusb = data;
+ xusb_t *xusb = data;
if(!xusb)
goto out;
// TODO: probably needs a per-xusb lock:
spin_lock_irqsave(&xusb_lock, flags);
- int i;
-
len += sprintf(page + len, "device: %d, #altsettings: %d, minor: %d\n"
- "\tBus Type:%d (Model Info: %s)\n"
- "\tIn: 0x%02X - Size: %d\n"
- "\tOut: 0x%02X - Size: %d\n",
+ "\tModel Info: Bus Type=%d (%s)\n"
+ "\tIn: 0x%02X - Size: %d)\n"
+ "\tOut: 0x%02X - Size: %d)\n",
xusb->udev->devnum,
xusb->interface->num_altsetting,
xusb->minor,
xusb->model_info->bus_type,
xusb->model_info->desc,
- xusb->ep_in.epnum,
- xusb->ep_in.max_size,
- xusb->ep_out.epnum,
- xusb->ep_out.max_size
+ xusb->endpoints[XUSB_RECV].ep_addr,
+ xusb->endpoints[XUSB_RECV].max_size,
+ xusb->endpoints[XUSB_SEND].ep_addr,
+ xusb->endpoints[XUSB_SEND].max_size
);
+ len += sprintf(page + len, "\npending_writes=%d\n", atomic_read(&xusb->pending_writes));
#ifdef DEBUG_PCM_TIMING
len += sprintf(page + len, "\nstamp_last_pcm_read=%lld accumulate_diff=%lld\n", stamp_last_pcm_read, accumulate_diff);
#endif
@@ -878,7 +915,7 @@ out:
MODULE_DESCRIPTION("XPP USB Driver");
MODULE_AUTHOR("Oron Peled <oron@actcom.co.il>");
MODULE_LICENSE("GPL");
-MODULE_VERSION("$Id$");
+MODULE_VERSION(ZAPTEL_VERSION);
module_init(xpp_usb_init);
module_exit(xpp_usb_cleanup);