From ec6b220aa7a334ccbd0fcb41d35c66560fc78a11 Mon Sep 17 00:00:00 2001 From: tzafrir Date: Sat, 8 Jul 2006 00:43:31 +0000 Subject: 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 --- xpp/xpp_usb.c | 445 +++++++++++++++++++++++++++++++--------------------------- 1 file changed, 241 insertions(+), 204 deletions(-) (limited to 'xpp/xpp_usb.c') 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 - * Copyright (C) 2004-2005, Xorcom + * Copyright (C) 2004-2006, Xorcom * * All rights reserved. * @@ -30,6 +30,7 @@ #include #include #include +#include #include /* for udelay */ #include #include @@ -37,11 +38,16 @@ #include #include #include +#include /* 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 "); MODULE_LICENSE("GPL"); -MODULE_VERSION("$Id$"); +MODULE_VERSION(ZAPTEL_VERSION); module_init(xpp_usb_init); module_exit(xpp_usb_cleanup); -- cgit v1.2.3