Commit 1dd7d25a authored by David Brownell's avatar David Brownell Committed by Greg Kroah-Hartman

[PATCH] USB: gadget zero learns about pxa2xx udc

The original code needed some updates to work properly with
the USB Device Controller found in Intel's PXA 2xx processors.

  - SET_INTERFACE and SET_CONFIGURATION involve hardware
    automagic:  all endpoints get reset.  This is a PITA,
    and will likely get more work.  (Seems like the reset
    is only partial, hosts need to CLEAR_HALT themselves...)

    What this does is to handle -ECONNABORTED notifications
    from pxa2xx_udc, in those cases.  In general, gadget
    drivers need to reset endpoints themselves, since the
    lower levels (hardware!) won't know how the endpoints
    are allocated between interfaces and altsettings.

  - The config symbol will be CONFIG_USB_PXA2XX, since the
    same controller (modulo errata) is in several processors
    other than the "older" pxa250.

  - This also adds an "i/o pattern" parameter, so that it
    can continue to use the "all zeroes" pattern or switch
    to something else.  The initial "something else" is an
    easily predicted "mod63" pattern.
parent fa619857
...@@ -92,7 +92,7 @@ ...@@ -92,7 +92,7 @@
/*-------------------------------------------------------------------------*/ /*-------------------------------------------------------------------------*/
#define DRIVER_VERSION "19 Feb 2003" #define DRIVER_VERSION "Bastille Day 2003"
static const char shortname [] = "zero"; static const char shortname [] = "zero";
static const char longname [] = "Gadget Zero"; static const char longname [] = "Gadget Zero";
...@@ -160,18 +160,18 @@ static inline void hw_optimize (struct usb_gadget *gadget) ...@@ -160,18 +160,18 @@ static inline void hw_optimize (struct usb_gadget *gadget)
#endif #endif
/* /*
* PXA-250 UDC: widely used in second gen Linux-capable PDAs. * PXA-2xx UDC: widely used in second gen Linux-capable PDAs.
* *
* This has fifteen fixed-function full speed endpoints, and it * This has fifteen fixed-function full speed endpoints, and it
* can support all USB transfer types. * can support all USB transfer types.
* *
* It only supports three configurations (numbered 1, 2, or 3) * These supports three or four configurations, with fixed numbers.
* with two interfaces each ... there's partial hardware support * The hardware interprets SET_INTERFACE, net effect is that you
* for set_configuration and set_interface, preventing some more * can't use altsettings or reset the interfaces independently.
* interesting config/interface/endpoint arrangements. * So stick to a single interface.
*/ */
#ifdef CONFIG_USB_ZERO_PXA250 #ifdef CONFIG_USB_ZERO_PXA2XX
#define CHIP "pxa250" #define CHIP "pxa2xx"
#define DRIVER_VERSION_NUM 0x0103 #define DRIVER_VERSION_NUM 0x0103
#define EP0_MAXPACKET 16 #define EP0_MAXPACKET 16
static const char EP_OUT_NAME [] = "ep12out-bulk"; static const char EP_OUT_NAME [] = "ep12out-bulk";
...@@ -291,9 +291,12 @@ struct zero_dev { ...@@ -291,9 +291,12 @@ struct zero_dev {
static unsigned buflen = 4096; static unsigned buflen = 4096;
static unsigned qlen = 32; static unsigned qlen = 32;
static unsigned pattern = 0;
module_param (buflen, uint, S_IRUGO|S_IWUSR); module_param (buflen, uint, S_IRUGO|S_IWUSR);
module_param (qlen, uint, S_IRUGO|S_IWUSR); module_param (qlen, uint, S_IRUGO|S_IWUSR);
module_param (pattern, uint, S_IRUGO|S_IWUSR);
/* /*
* Normally the "loopback" configuration is second (index 1) so * Normally the "loopback" configuration is second (index 1) so
...@@ -497,8 +500,8 @@ static struct usb_gadget_strings stringtab = { ...@@ -497,8 +500,8 @@ static struct usb_gadget_strings stringtab = {
/* /*
* config descriptors are also handcrafted. these must agree with code * config descriptors are also handcrafted. these must agree with code
* that sets configurations, and with code managing interface altsettings. * that sets configurations, and with code managing interfaces and their
* other complexity may come from: * altsettings. other complexity may come from:
* *
* - high speed support, including "other speed config" rules * - high speed support, including "other speed config" rules
* - multiple configurations * - multiple configurations
...@@ -506,7 +509,7 @@ static struct usb_gadget_strings stringtab = { ...@@ -506,7 +509,7 @@ static struct usb_gadget_strings stringtab = {
* - embedded class or vendor-specific descriptors * - embedded class or vendor-specific descriptors
* *
* this handles high speed, and has a second config that could as easily * this handles high speed, and has a second config that could as easily
* have been an alternate interface setting. * have been an alternate interface setting (on most hardware).
* *
* NOTE: to demonstrate (and test) more USB capabilities, this driver * NOTE: to demonstrate (and test) more USB capabilities, this driver
* should include an altsetting to test interrupt transfers, including * should include an altsetting to test interrupt transfers, including
...@@ -608,17 +611,30 @@ check_read_data ( ...@@ -608,17 +611,30 @@ check_read_data (
struct usb_request *req struct usb_request *req
) )
{ {
int i; unsigned i;
u8 *buf = req->buf;
for (i = 0; i < req->actual; i++) { for (i = 0; i < req->actual; i++, buf++) {
if (((u8 *)req->buf) [i] != 0) { switch (pattern) {
ERROR (dev, "nonzero OUT byte from host, " /* all-zeroes has no synchronization issues */
"buf [%d] = %d\n", case 0:
i, ((u8 *)req->buf) [i]); if (*buf == 0)
continue;
break;
/* mod63 stays in sync with short-terminated transfers,
* or otherwise when host and gadget agree on how large
* each usb transfer request should be. resync is done
* with set_interface or set_config.
*/
case 1:
if (*buf == (u8)(i % 63))
continue;
break;
}
ERROR (dev, "bad OUT byte, buf [%d] = %d\n", i, *buf);
usb_ep_set_halt (ep); usb_ep_set_halt (ep);
return -EINVAL; return -EINVAL;
} }
}
return 0; return 0;
} }
...@@ -629,7 +645,18 @@ reinit_write_data ( ...@@ -629,7 +645,18 @@ reinit_write_data (
struct usb_request *req struct usb_request *req
) )
{ {
unsigned i;
u8 *buf = req->buf;
switch (pattern) {
case 0:
memset (req->buf, 0, req->length); memset (req->buf, 0, req->length);
break;
case 1:
for (i = 0; i < req->length; i++)
*buf++ = (u8) (i % 63);
break;
}
} }
/* if there is only one request in the queue, there'll always be an /* if there is only one request in the queue, there'll always be an
...@@ -651,10 +678,13 @@ static void source_sink_complete (struct usb_ep *ep, struct usb_request *req) ...@@ -651,10 +678,13 @@ static void source_sink_complete (struct usb_ep *ep, struct usb_request *req)
break; break;
/* this endpoint is normally active while we're configured */ /* this endpoint is normally active while we're configured */
case -ECONNABORTED: /* hardware forced ep reset */
case -ECONNRESET: /* request dequeued */ case -ECONNRESET: /* request dequeued */
case -ESHUTDOWN: /* disconnect from host */ case -ESHUTDOWN: /* disconnect from host */
VDEBUG (dev, "%s gone (%d), %d/%d\n", ep->name, status, VDEBUG (dev, "%s gone (%d), %d/%d\n", ep->name, status,
req->actual, req->length); req->actual, req->length);
if (ep == dev->out_ep)
check_read_data (dev, ep, req);
free_ep_req (ep, req); free_ep_req (ep, req);
return; return;
...@@ -693,6 +723,9 @@ source_sink_start_ep (struct usb_ep *ep, int gfp_flags) ...@@ -693,6 +723,9 @@ source_sink_start_ep (struct usb_ep *ep, int gfp_flags)
memset (req->buf, 0, req->length); memset (req->buf, 0, req->length);
req->complete = source_sink_complete; req->complete = source_sink_complete;
if (strcmp (ep->name, EP_IN_NAME) == 0)
reinit_write_data (ep->driver_data, ep, req);
status = usb_ep_queue (ep, req, gfp_flags); status = usb_ep_queue (ep, req, gfp_flags);
if (status) { if (status) {
struct zero_dev *dev = ep->driver_data; struct zero_dev *dev = ep->driver_data;
...@@ -801,6 +834,8 @@ static void loopback_complete (struct usb_ep *ep, struct usb_request *req) ...@@ -801,6 +834,8 @@ static void loopback_complete (struct usb_ep *ep, struct usb_request *req)
* rely on the hardware driver to clean up on disconnect or * rely on the hardware driver to clean up on disconnect or
* endpoint disable. * endpoint disable.
*/ */
case -ECONNABORTED: /* hardware forced ep reset */
case -ECONNRESET: /* request dequeued */
case -ESHUTDOWN: /* disconnect from host */ case -ESHUTDOWN: /* disconnect from host */
free_ep_req (ep, req); free_ep_req (ep, req);
return; return;
...@@ -905,7 +940,7 @@ static void zero_reset_config (struct zero_dev *dev) ...@@ -905,7 +940,7 @@ static void zero_reset_config (struct zero_dev *dev)
* *
* note that some device controller hardware will constrain what this * note that some device controller hardware will constrain what this
* code can do, perhaps by disallowing more than one configuration or * code can do, perhaps by disallowing more than one configuration or
* by limiting configuration choices (like the pxa250). * by limiting configuration choices (like the pxa2xx).
*/ */
static int static int
zero_set_config (struct zero_dev *dev, unsigned number, int gfp_flags) zero_set_config (struct zero_dev *dev, unsigned number, int gfp_flags)
...@@ -1046,7 +1081,8 @@ zero_setup (struct usb_gadget *gadget, const struct usb_ctrlrequest *ctrl) ...@@ -1046,7 +1081,8 @@ zero_setup (struct usb_gadget *gadget, const struct usb_ctrlrequest *ctrl)
break; break;
/* until we add altsetting support, or other interfaces, /* until we add altsetting support, or other interfaces,
* only 0/0 are possible. * only 0/0 are possible. pxa2xx only supports 0/0 (poorly)
* and already killed pending endpoint I/O.
*/ */
case USB_REQ_SET_INTERFACE: case USB_REQ_SET_INTERFACE:
if (ctrl->bRequestType != USB_RECIP_INTERFACE) if (ctrl->bRequestType != USB_RECIP_INTERFACE)
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment