ChangeSet 1.1148.6.10, 2003/10/14 16:48:25-07:00, david-b@pacbell.net [PATCH] USB: usb ethernet gadget Please update the ethernet "gadget" driver with this patch: - fixes an newish oops in some cdc shutdown paths - works on more 2.4 kernel variants - synchronizes with more recent 2.6 code - supports another controller (tc86c001 "goku_udc") The oops basically came from recent changes that seemed to behave on PXA hardware, but not the more functional CDC-capable stuff (like net2280). drivers/usb/gadget/ether.c | 130 +++++++++++++++++++++++++++------------------ 1 files changed, 80 insertions(+), 50 deletions(-) diff -Nru a/drivers/usb/gadget/ether.c b/drivers/usb/gadget/ether.c --- a/drivers/usb/gadget/ether.c Fri Oct 24 17:01:03 2003 +++ b/drivers/usb/gadget/ether.c Fri Oct 24 17:01:03 2003 @@ -23,8 +23,8 @@ // #define VERBOSE #include -#include #include +#include #include #include #include @@ -87,11 +87,12 @@ #endif /* 2.5 modified and renamed these */ - +#ifndef INIT_WORK #define work_struct tq_struct #define INIT_WORK INIT_TQUEUE #define schedule_work schedule_task #define flush_scheduled_work flush_scheduled_tasks +#endif /*-------------------------------------------------------------------------*/ @@ -117,28 +118,6 @@ /*-------------------------------------------------------------------------*/ -/* This driver keeps a variable number of requests queued, more at - * high speeds. (Numbers are just educated guesses, untuned.) - * Shrink the queue if memory is tight, or make it bigger to - * handle bigger traffic bursts between IRQs (assuming hw dma queues) - */ - -static unsigned qmult = 4; - -#define HS_FACTOR 5 - -#define qlen(gadget) \ - (qmult*((gadget->speed == USB_SPEED_HIGH) ? HS_FACTOR : 1)) - -/* defer IRQs on highspeed TX */ -#define TX_DELAY 8 - - -MODULE_PARM (qmult, "i"); -MODULE_PARM_DESC (qmult, "rx/tx buffering factor"); - -/*-------------------------------------------------------------------------*/ - /* Thanks to NetChip Technologies for donating this product ID. * * DO NOT REUSE THESE IDs with a protocol-incompatible driver!! Ever!! @@ -187,6 +166,7 @@ */ #ifdef CONFIG_USB_ETH_NET2280 #define CHIP "net2280" +#define DEFAULT_QLEN 4 /* has dma chaining */ #define DRIVER_VERSION_NUM 0x0111 #define EP0_MAXPACKET 64 static const char EP_OUT_NAME [] = "ep-a"; @@ -232,7 +212,7 @@ /* supports remote wakeup, but this driver doesn't */ /* no hw optimizations to apply */ -#define hw_optimize(g) do {} while (0); +#define hw_optimize(g) do {} while (0) #endif /* @@ -255,7 +235,28 @@ /* doesn't support remote wakeup? */ /* no hw optimizations to apply */ -#define hw_optimize(g) do {} while (0); +#define hw_optimize(g) do {} while (0) +#endif + +/* + * Toshiba TC86C001 ("Goku-S") UDC + * + * This has three semi-configurable full speed bulk/interrupt endpoints. + */ +#ifdef CONFIG_USB_ETH_GOKU +#define CHIP "goku" +#define DRIVER_VERSION_NUM 0x0116 +#define EP0_MAXPACKET 8 +static const char EP_OUT_NAME [] = "ep1-bulk"; +#define EP_OUT_NUM 1 +static const char EP_IN_NAME [] = "ep2-bulk"; +#define EP_IN_NUM 2 +static const char EP_STATUS_NAME [] = "ep3-bulk"; +#define EP_STATUS_NUM 3 +#define SELFPOWER USB_CONFIG_ATT_SELFPOWER +/* doesn't support remote wakeup */ + +#define hw_optimize(g) do {} while (0) #endif /*-------------------------------------------------------------------------*/ @@ -313,9 +314,32 @@ /*-------------------------------------------------------------------------*/ +#ifndef DEFAULT_QLEN +#define DEFAULT_QLEN 2 /* double buffering by default */ +#endif + +#ifdef HIGHSPEED + +static unsigned qmult = 5; +MODULE_PARM (qmult, "i"); + + +/* for dual-speed hardware, use deeper queues at highspeed */ +#define qlen(gadget) \ + (DEFAULT_QLEN*((gadget->speed == USB_SPEED_HIGH) ? qmult : 1)) + +/* also defer IRQs on highspeed TX */ +#define TX_DELAY DEFAULT_QLEN + +#else /* !HIGHSPEED ... full speed: */ +#define qlen(gadget) DEFAULT_QLEN +#endif + + +/*-------------------------------------------------------------------------*/ + #define xprintk(d,level,fmt,args...) \ - printk(level "%s %s: " fmt , shortname , (d)->gadget->dev.bus_id , \ - ## args) + printk(level "%s: " fmt , (d)->net->name , ## args) #ifdef DEBUG #undef DEBUG @@ -892,6 +916,8 @@ static void eth_reset_config (struct eth_dev *dev) { + struct usb_request *req; + if (dev->config == 0) return; @@ -900,17 +926,30 @@ netif_stop_queue (dev->net); netif_carrier_off (dev->net); - /* just disable endpoints, forcing completion of pending i/o. - * all our completion handlers free their requests in this case. + /* disable endpoints, forcing (synchronous) completion of + * pending i/o. then free the requests. */ if (dev->in_ep) { usb_ep_disable (dev->in_ep); + while (likely (!list_empty (&dev->tx_reqs))) { + req = container_of (dev->tx_reqs.next, + struct usb_request, list); + list_del (&req->list); + usb_ep_free_request (dev->in_ep, req); + } dev->in_ep = 0; } if (dev->out_ep) { usb_ep_disable (dev->out_ep); + while (likely (!list_empty (&dev->rx_reqs))) { + req = container_of (dev->rx_reqs.next, + struct usb_request, list); + list_del (&req->list); + usb_ep_free_request (dev->out_ep, req); + } dev->out_ep = 0; } + #ifdef EP_STATUS_NUM if (dev->status_ep) { usb_ep_disable (dev->status_ep); @@ -1676,7 +1715,7 @@ { struct eth_dev *dev = (struct eth_dev *) net->priv; - DEBUG (dev, "%s\n", __FUNCTION__); + VDEBUG (dev, "%s\n", __FUNCTION__); netif_stop_queue (net); DEBUG (dev, "stop stats: rx/tx %ld/%ld, errs %ld/%ld\n", @@ -1690,6 +1729,7 @@ usb_ep_disable (dev->out_ep); if (netif_carrier_ok (dev->net)) { DEBUG (dev, "host still using in/out endpoints\n"); + // FIXME idiom may leave toggle wrong here usb_ep_enable (dev->in_ep, dev->in); usb_ep_enable (dev->out_ep, dev->out); } @@ -1708,7 +1748,6 @@ eth_unbind (struct usb_gadget *gadget) { struct eth_dev *dev = get_gadget_data (gadget); - struct usb_request *req; DEBUG (dev, "unbind\n"); @@ -1721,19 +1760,6 @@ dev->req = 0; } - while (!list_empty (&dev->tx_reqs)) { - req = container_of (dev->tx_reqs.next, - struct usb_request, list); - list_del (&req->list); - usb_ep_free_request (dev->in_ep, req); - } - while (!list_empty (&dev->rx_reqs)) { - req = container_of (dev->rx_reqs.next, - struct usb_request, list); - list_del (&req->list); - usb_ep_free_request (dev->out_ep, req); - } - unregister_netdev (dev->net); dev_put (dev->net); @@ -1816,10 +1842,6 @@ dev->gadget = gadget; set_gadget_data (gadget, dev); gadget->ep0->driver_data = dev; - INFO (dev, "%s, " CHIP ", version: " DRIVER_VERSION "\n", driver_desc); -#ifdef DEV_CONFIG_CDC - INFO (dev, "CDC host enet %s\n", ethaddr); -#endif /* two kinds of host-initiated state changes: * - iff DATA transfer is active, carrier is "on" @@ -1830,8 +1852,16 @@ // SET_NETDEV_DEV (dev->net, &gadget->dev); status = register_netdev (dev->net); - if (status == 0) + if (status == 0) { + + INFO (dev, "%s, " CHIP ", version: " DRIVER_VERSION "\n", + driver_desc); +#ifdef DEV_CONFIG_CDC + INFO (dev, "CDC host enet %s\n", ethaddr); +#endif return status; + } + pr_debug("%s: register_netdev failed, %d\n", shortname, status); fail: eth_unbind (gadget); return status;