ChangeSet 1.1455.1.26, 2003/07/15 14:54:08-07:00, david-b@pacbell.net [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. drivers/usb/gadget/zero.c | 80 +++++++++++++++++++++++++++++++++------------- 1 files changed, 58 insertions(+), 22 deletions(-) diff -Nru a/drivers/usb/gadget/zero.c b/drivers/usb/gadget/zero.c --- a/drivers/usb/gadget/zero.c Thu Jul 17 17:04:29 2003 +++ b/drivers/usb/gadget/zero.c Thu Jul 17 17:04:29 2003 @@ -92,7 +92,7 @@ /*-------------------------------------------------------------------------*/ -#define DRIVER_VERSION "19 Feb 2003" +#define DRIVER_VERSION "Bastille Day 2003" static const char shortname [] = "zero"; static const char longname [] = "Gadget Zero"; @@ -160,18 +160,18 @@ #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 * can support all USB transfer types. * - * It only supports three configurations (numbered 1, 2, or 3) - * with two interfaces each ... there's partial hardware support - * for set_configuration and set_interface, preventing some more - * interesting config/interface/endpoint arrangements. + * These supports three or four configurations, with fixed numbers. + * The hardware interprets SET_INTERFACE, net effect is that you + * can't use altsettings or reset the interfaces independently. + * So stick to a single interface. */ -#ifdef CONFIG_USB_ZERO_PXA250 -#define CHIP "pxa250" +#ifdef CONFIG_USB_ZERO_PXA2XX +#define CHIP "pxa2xx" #define DRIVER_VERSION_NUM 0x0103 #define EP0_MAXPACKET 16 static const char EP_OUT_NAME [] = "ep12out-bulk"; @@ -291,9 +291,12 @@ static unsigned buflen = 4096; static unsigned qlen = 32; +static unsigned pattern = 0; module_param (buflen, 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 @@ -497,8 +500,8 @@ /* * config descriptors are also handcrafted. these must agree with code - * that sets configurations, and with code managing interface altsettings. - * other complexity may come from: + * that sets configurations, and with code managing interfaces and their + * altsettings. other complexity may come from: * * - high speed support, including "other speed config" rules * - multiple configurations @@ -506,7 +509,7 @@ * - embedded class or vendor-specific descriptors * * 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 * should include an altsetting to test interrupt transfers, including @@ -608,16 +611,29 @@ struct usb_request *req ) { - int i; + unsigned i; + u8 *buf = req->buf; - for (i = 0; i < req->actual; i++) { - if (((u8 *)req->buf) [i] != 0) { - ERROR (dev, "nonzero OUT byte from host, " - "buf [%d] = %d\n", - i, ((u8 *)req->buf) [i]); - usb_ep_set_halt (ep); - return -EINVAL; + for (i = 0; i < req->actual; i++, buf++) { + switch (pattern) { + /* all-zeroes has no synchronization issues */ + case 0: + 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); + return -EINVAL; } return 0; } @@ -629,7 +645,18 @@ struct usb_request *req ) { - memset (req->buf, 0, req->length); + unsigned i; + u8 *buf = req->buf; + + switch (pattern) { + case 0: + 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 @@ -651,10 +678,13 @@ break; /* this endpoint is normally active while we're configured */ + case -ECONNABORTED: /* hardware forced ep reset */ case -ECONNRESET: /* request dequeued */ case -ESHUTDOWN: /* disconnect from host */ VDEBUG (dev, "%s gone (%d), %d/%d\n", ep->name, status, req->actual, req->length); + if (ep == dev->out_ep) + check_read_data (dev, ep, req); free_ep_req (ep, req); return; @@ -693,6 +723,9 @@ memset (req->buf, 0, req->length); 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); if (status) { struct zero_dev *dev = ep->driver_data; @@ -801,6 +834,8 @@ * rely on the hardware driver to clean up on disconnect or * endpoint disable. */ + case -ECONNABORTED: /* hardware forced ep reset */ + case -ECONNRESET: /* request dequeued */ case -ESHUTDOWN: /* disconnect from host */ free_ep_req (ep, req); return; @@ -905,7 +940,7 @@ * * note that some device controller hardware will constrain what this * 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 zero_set_config (struct zero_dev *dev, unsigned number, int gfp_flags) @@ -1046,7 +1081,8 @@ break; /* 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: if (ctrl->bRequestType != USB_RECIP_INTERFACE)