X-Git-Url: http://git.onelab.eu/?a=blobdiff_plain;f=drivers%2Fusb%2Fgadget%2Fzero.c;h=68e3d8f5da8947cb8d28cf17c2056b8829d04190;hb=43bc926fffd92024b46cafaf7350d669ba9ca884;hp=2e220d32881a0444f3264989d36be3fe5203f48b;hpb=5273a3df6485dc2ad6aa7ddd441b9a21970f003b;p=linux-2.6.git diff --git a/drivers/usb/gadget/zero.c b/drivers/usb/gadget/zero.c index 2e220d328..68e3d8f5d 100644 --- a/drivers/usb/gadget/zero.c +++ b/drivers/usb/gadget/zero.c @@ -75,8 +75,7 @@ #include #include #include -#include -#include +#include #include #include @@ -130,6 +129,9 @@ struct zero_dev { */ u8 config; struct usb_ep *in_ep, *out_ep; + + /* autoresume timer */ + struct timer_list resume; }; #define xprintk(d,level,fmt,args...) \ @@ -163,10 +165,16 @@ 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 (buflen, uint, S_IRUGO); +module_param (qlen, uint, S_IRUGO); module_param (pattern, uint, S_IRUGO|S_IWUSR); +/* + * if it's nonzero, autoresume says how many seconds to wait + * before trying to wake up the host after suspend. + */ +static unsigned autoresume = 0; +module_param (autoresume, uint, 0); /* * Normally the "loopback" configuration is second (index 1) so @@ -185,8 +193,13 @@ module_param (loopdefault, bool, S_IRUGO|S_IWUSR); * DO NOT REUSE THESE IDs with a protocol-incompatible driver!! Ever!! * Instead: allocate your own, using normal USB-IF procedures. */ +#ifndef CONFIG_USB_ZERO_HNPTEST #define DRIVER_VENDOR_NUM 0x0525 /* NetChip */ #define DRIVER_PRODUCT_NUM 0xa4a0 /* Linux-USB "Gadget Zero" */ +#else +#define DRIVER_VENDOR_NUM 0x1a0a /* OTG test device IDs */ +#define DRIVER_PRODUCT_NUM 0xbadd +#endif /*-------------------------------------------------------------------------*/ @@ -224,7 +237,7 @@ device_desc = { .bNumConfigurations = 2, }; -static const struct usb_config_descriptor +static struct usb_config_descriptor source_sink_config = { .bLength = sizeof source_sink_config, .bDescriptorType = USB_DT_CONFIG, @@ -237,7 +250,7 @@ source_sink_config = { .bMaxPower = 1, /* self-powered */ }; -static const struct usb_config_descriptor +static struct usb_config_descriptor loopback_config = { .bLength = sizeof loopback_config, .bDescriptorType = USB_DT_CONFIG, @@ -250,6 +263,14 @@ loopback_config = { .bMaxPower = 1, /* self-powered */ }; +static struct usb_otg_descriptor +otg_descriptor = { + .bLength = sizeof otg_descriptor, + .bDescriptorType = USB_DT_OTG, + + .bmAttributes = USB_OTG_SRP, +}; + /* one interface in each configuration */ static const struct usb_interface_descriptor @@ -293,17 +314,19 @@ fs_sink_desc = { }; static const struct usb_descriptor_header *fs_source_sink_function [] = { + (struct usb_descriptor_header *) &otg_descriptor, (struct usb_descriptor_header *) &source_sink_intf, (struct usb_descriptor_header *) &fs_sink_desc, (struct usb_descriptor_header *) &fs_source_desc, - 0, + NULL, }; static const struct usb_descriptor_header *fs_loopback_function [] = { + (struct usb_descriptor_header *) &otg_descriptor, (struct usb_descriptor_header *) &loopback_intf, (struct usb_descriptor_header *) &fs_sink_desc, (struct usb_descriptor_header *) &fs_source_desc, - 0, + NULL, }; #ifdef CONFIG_USB_GADGET_DUALSPEED @@ -347,17 +370,19 @@ dev_qualifier = { }; static const struct usb_descriptor_header *hs_source_sink_function [] = { + (struct usb_descriptor_header *) &otg_descriptor, (struct usb_descriptor_header *) &source_sink_intf, (struct usb_descriptor_header *) &hs_source_desc, (struct usb_descriptor_header *) &hs_sink_desc, - 0, + NULL, }; static const struct usb_descriptor_header *hs_loopback_function [] = { + (struct usb_descriptor_header *) &otg_descriptor, (struct usb_descriptor_header *) &loopback_intf, (struct usb_descriptor_header *) &hs_source_desc, (struct usb_descriptor_header *) &hs_sink_desc, - 0, + NULL, }; /* maxpacket and other transfer characteristics vary by speed. */ @@ -370,10 +395,10 @@ static const struct usb_descriptor_header *hs_loopback_function [] = { #endif /* !CONFIG_USB_GADGET_DUALSPEED */ -static char manufacturer [40]; +static char manufacturer [50]; static char serial [40]; -/* static strings, in iso 8859/1 */ +/* static strings, in UTF-8 */ static struct usb_string strings [] = { { STRING_MANUFACTURER, manufacturer, }, { STRING_PRODUCT, longname, }, @@ -435,6 +460,10 @@ config_buf (struct usb_gadget *gadget, ? fs_source_sink_function : fs_loopback_function; + /* for now, don't advertise srp-only devices */ + if (!gadget->is_otg) + function++; + len = usb_gadget_config_buf (is_source_sink ? &source_sink_config : &loopback_config, @@ -459,7 +488,7 @@ alloc_ep_req (struct usb_ep *ep, unsigned length) &req->dma, GFP_ATOMIC); if (!req->buf) { usb_ep_free_request (ep, req); - req = 0; + req = NULL; } } return req; @@ -476,7 +505,7 @@ static void free_ep_req (struct usb_ep *ep, struct usb_request *req) /* optionally require specific source/sink data patterns */ -static inline int +static int check_read_data ( struct zero_dev *dev, struct usb_ep *ep, @@ -510,7 +539,7 @@ check_read_data ( return 0; } -static inline void +static void reinit_write_data ( struct zero_dev *dev, struct usb_ep *ep, @@ -543,9 +572,10 @@ static void source_sink_complete (struct usb_ep *ep, struct usb_request *req) switch (status) { case 0: /* normal completion? */ - if (ep == dev->out_ep) + if (ep == dev->out_ep) { check_read_data (dev, ep, req); - else + memset (req->buf, 0x55, req->length); + } else reinit_write_data (dev, ep, req); break; @@ -583,20 +613,22 @@ static void source_sink_complete (struct usb_ep *ep, struct usb_request *req) } static struct usb_request * -source_sink_start_ep (struct usb_ep *ep, int gfp_flags) +source_sink_start_ep (struct usb_ep *ep, gfp_t gfp_flags) { struct usb_request *req; int status; req = alloc_ep_req (ep, buflen); if (!req) - return 0; + return NULL; 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); + else + memset (req->buf, 0x55, req->length); status = usb_ep_queue (ep, req, gfp_flags); if (status) { @@ -604,14 +636,14 @@ source_sink_start_ep (struct usb_ep *ep, int gfp_flags) ERROR (dev, "start %s --> %d\n", ep->name, status); free_ep_req (ep, req); - req = 0; + req = NULL; } return req; } static int -set_source_sink_config (struct zero_dev *dev, int gfp_flags) +set_source_sink_config (struct zero_dev *dev, gfp_t gfp_flags) { int result = 0; struct usb_ep *ep; @@ -715,7 +747,7 @@ static void loopback_complete (struct usb_ep *ep, struct usb_request *req) } static int -set_loopback_config (struct zero_dev *dev, int gfp_flags) +set_loopback_config (struct zero_dev *dev, gfp_t gfp_flags) { int result = 0; struct usb_ep *ep; @@ -795,13 +827,14 @@ static void zero_reset_config (struct zero_dev *dev) */ if (dev->in_ep) { usb_ep_disable (dev->in_ep); - dev->in_ep = 0; + dev->in_ep = NULL; } if (dev->out_ep) { usb_ep_disable (dev->out_ep); - dev->out_ep = 0; + dev->out_ep = NULL; } dev->config = 0; + del_timer (&dev->resume); } /* change our operational config. this code must agree with the code @@ -815,7 +848,7 @@ static void zero_reset_config (struct zero_dev *dev) * by limiting configuration choices (like the pxa2xx). */ static int -zero_set_config (struct zero_dev *dev, unsigned number, int gfp_flags) +zero_set_config (struct zero_dev *dev, unsigned number, gfp_t gfp_flags) { int result = 0; struct usb_gadget *gadget = dev->gadget; @@ -889,26 +922,30 @@ zero_setup (struct usb_gadget *gadget, const struct usb_ctrlrequest *ctrl) struct zero_dev *dev = get_gadget_data (gadget); struct usb_request *req = dev->req; int value = -EOPNOTSUPP; + u16 w_index = le16_to_cpu(ctrl->wIndex); + u16 w_value = le16_to_cpu(ctrl->wValue); + u16 w_length = le16_to_cpu(ctrl->wLength); /* usually this stores reply data in the pre-allocated ep0 buffer, * but config change events will reconfigure hardware. */ + req->zero = 0; switch (ctrl->bRequest) { case USB_REQ_GET_DESCRIPTOR: if (ctrl->bRequestType != USB_DIR_IN) goto unknown; - switch (ctrl->wValue >> 8) { + switch (w_value >> 8) { case USB_DT_DEVICE: - value = min (ctrl->wLength, (u16) sizeof device_desc); + value = min (w_length, (u16) sizeof device_desc); memcpy (req->buf, &device_desc, value); break; #ifdef CONFIG_USB_GADGET_DUALSPEED case USB_DT_DEVICE_QUALIFIER: if (!gadget->is_dualspeed) break; - value = min (ctrl->wLength, (u16) sizeof dev_qualifier); + value = min (w_length, (u16) sizeof dev_qualifier); memcpy (req->buf, &dev_qualifier, value); break; @@ -919,21 +956,22 @@ zero_setup (struct usb_gadget *gadget, const struct usb_ctrlrequest *ctrl) #endif /* CONFIG_USB_GADGET_DUALSPEED */ case USB_DT_CONFIG: value = config_buf (gadget, req->buf, - ctrl->wValue >> 8, - ctrl->wValue & 0xff); + w_value >> 8, + w_value & 0xff); if (value >= 0) - value = min (ctrl->wLength, (u16) value); + value = min (w_length, (u16) value); break; case USB_DT_STRING: /* wIndex == language code. * this driver only handles one language, you can - * add others even if they don't use iso8859/1 + * add string tables for other languages, using + * any UTF-8 characters */ value = usb_gadget_get_string (&stringtab, - ctrl->wValue & 0xff, req->buf); + w_value & 0xff, req->buf); if (value >= 0) - value = min (ctrl->wLength, (u16) value); + value = min (w_length, (u16) value); break; } break; @@ -942,15 +980,21 @@ zero_setup (struct usb_gadget *gadget, const struct usb_ctrlrequest *ctrl) case USB_REQ_SET_CONFIGURATION: if (ctrl->bRequestType != 0) goto unknown; + if (gadget->a_hnp_support) + DBG (dev, "HNP available\n"); + else if (gadget->a_alt_hnp_support) + DBG (dev, "HNP needs a different root port\n"); + else + VDBG (dev, "HNP inactive\n"); spin_lock (&dev->lock); - value = zero_set_config (dev, ctrl->wValue, GFP_ATOMIC); + value = zero_set_config (dev, w_value, GFP_ATOMIC); spin_unlock (&dev->lock); break; case USB_REQ_GET_CONFIGURATION: if (ctrl->bRequestType != USB_DIR_IN) goto unknown; *(u8 *)req->buf = dev->config; - value = min (ctrl->wLength, (u16) 1); + value = min (w_length, (u16) 1); break; /* until we add altsetting support, or other interfaces, @@ -961,7 +1005,7 @@ zero_setup (struct usb_gadget *gadget, const struct usb_ctrlrequest *ctrl) if (ctrl->bRequestType != USB_RECIP_INTERFACE) goto unknown; spin_lock (&dev->lock); - if (dev->config && ctrl->wIndex == 0 && ctrl->wValue == 0) { + if (dev->config && w_index == 0 && w_value == 0) { u8 config = dev->config; /* resets interface configuration, forgets about @@ -982,12 +1026,12 @@ zero_setup (struct usb_gadget *gadget, const struct usb_ctrlrequest *ctrl) goto unknown; if (!dev->config) break; - if (ctrl->wIndex != 0) { + if (w_index != 0) { value = -EDOM; break; } *(u8 *)req->buf = 0; - value = min (ctrl->wLength, (u16) 1); + value = min (w_length, (u16) 1); break; /* @@ -998,23 +1042,23 @@ zero_setup (struct usb_gadget *gadget, const struct usb_ctrlrequest *ctrl) case 0x5b: /* control WRITE test -- fill the buffer */ if (ctrl->bRequestType != (USB_DIR_OUT|USB_TYPE_VENDOR)) goto unknown; - if (ctrl->wValue || ctrl->wIndex) + if (w_value || w_index) break; /* just read that many bytes into the buffer */ - if (ctrl->wLength > USB_BUFSIZ) + if (w_length > USB_BUFSIZ) break; - value = ctrl->wLength; + value = w_length; break; case 0x5c: /* control READ test -- return the buffer */ if (ctrl->bRequestType != (USB_DIR_IN|USB_TYPE_VENDOR)) goto unknown; - if (ctrl->wValue || ctrl->wIndex) + if (w_value || w_index) break; /* expect those bytes are still in the buffer; send back */ - if (ctrl->wLength > USB_BUFSIZ - || ctrl->wLength != req->length) + if (w_length > USB_BUFSIZ + || w_length != req->length) break; - value = ctrl->wLength; + value = w_length; break; default: @@ -1022,12 +1066,13 @@ unknown: VDBG (dev, "unknown control req%02x.%02x v%04x i%04x l%d\n", ctrl->bRequestType, ctrl->bRequest, - ctrl->wValue, ctrl->wIndex, ctrl->wLength); + w_value, w_index, w_length); } /* respond with data transfer before status phase? */ if (value >= 0) { req->length = value; + req->zero = value < w_length; value = usb_ep_queue (gadget->ep0, req, GFP_ATOMIC); if (value < 0) { DBG (dev, "ep_queue --> %d\n", value); @@ -1060,9 +1105,24 @@ zero_disconnect (struct usb_gadget *gadget) */ } +static void +zero_autoresume (unsigned long _dev) +{ + struct zero_dev *dev = (struct zero_dev *) _dev; + int status; + + /* normally the host would be woken up for something + * more significant than just a timer firing... + */ + if (dev->gadget->speed != USB_SPEED_UNKNOWN) { + status = usb_gadget_wakeup (dev->gadget); + DBG (dev, "wakeup --> %d\n", status); + } +} + /*-------------------------------------------------------------------------*/ -static void +static void __exit zero_unbind (struct usb_gadget *gadget) { struct zero_dev *dev = get_gadget_data (gadget); @@ -1070,17 +1130,27 @@ zero_unbind (struct usb_gadget *gadget) DBG (dev, "unbind\n"); /* we've already been disconnected ... no i/o is active */ - if (dev->req) + if (dev->req) { + dev->req->length = USB_BUFSIZ; free_ep_req (gadget->ep0, dev->req); + } + del_timer_sync (&dev->resume); kfree (dev); - set_gadget_data (gadget, 0); + set_gadget_data (gadget, NULL); } -static int +static int __init zero_bind (struct usb_gadget *gadget) { struct zero_dev *dev; struct usb_ep *ep; + int gcnum; + + /* FIXME this can't yet work right with SH ... it has only + * one configuration, numbered one. + */ + if (gadget_is_sh(gadget)) + return -ENODEV; /* Bulk-only drivers like this one SHOULD be able to * autoconfigure on any sane usb controller driver, @@ -1103,33 +1173,10 @@ autoconf_fail: EP_OUT_NAME = ep->name; ep->driver_data = ep; /* claim */ - - /* - * DRIVER POLICY CHOICE: you may want to do this differently. - * One thing to avoid is reusing a bcdDevice revision code - * with different host-visible configurations or behavior - * restrictions -- using ep1in/ep2out vs ep1out/ep3in, etc - */ - if (gadget_is_net2280 (gadget)) { - device_desc.bcdDevice = __constant_cpu_to_le16 (0x0201); - } else if (gadget_is_pxa (gadget)) { - device_desc.bcdDevice = __constant_cpu_to_le16 (0x0203); -#if 0 - } else if (gadget_is_sh(gadget)) { - device_desc.bcdDevice = __constant_cpu_to_le16 (0x0204); - /* SH has only one configuration; see "loopdefault" */ - device_desc.bNumConfigurations = 1; - /* FIXME make 1 == default.bConfigurationValue */ -#endif - } else if (gadget_is_sa1100 (gadget)) { - device_desc.bcdDevice = __constant_cpu_to_le16 (0x0205); - } else if (gadget_is_goku (gadget)) { - device_desc.bcdDevice = __constant_cpu_to_le16 (0x0206); - } else if (gadget_is_mq11xx (gadget)) { - device_desc.bcdDevice = __constant_cpu_to_le16 (0x0207); - } else if (gadget_is_omap (gadget)) { - device_desc.bcdDevice = __constant_cpu_to_le16 (0x0208); - } else { + gcnum = usb_gadget_controller_number (gadget); + if (gcnum >= 0) + device_desc.bcdDevice = cpu_to_le16 (0x0200 + gcnum); + else { /* gadget zero is so simple (for now, no altsettings) that * it SHOULD NOT have problems with bulk-capable hardware. * so warn about unrcognized controllers, don't panic. @@ -1144,10 +1191,9 @@ autoconf_fail: /* ok, we made sense of the hardware ... */ - dev = kmalloc (sizeof *dev, SLAB_KERNEL); + dev = kzalloc(sizeof(*dev), SLAB_KERNEL); if (!dev) return -ENOMEM; - memset (dev, 0, sizeof *dev); spin_lock_init (&dev->lock); dev->gadget = gadget; set_gadget_data (gadget, dev); @@ -1174,16 +1220,30 @@ autoconf_fail: hs_sink_desc.bEndpointAddress = fs_sink_desc.bEndpointAddress; #endif + if (gadget->is_otg) { + otg_descriptor.bmAttributes |= USB_OTG_HNP, + source_sink_config.bmAttributes |= USB_CONFIG_ATT_WAKEUP; + loopback_config.bmAttributes |= USB_CONFIG_ATT_WAKEUP; + } + usb_gadget_set_selfpowered (gadget); + init_timer (&dev->resume); + dev->resume.function = zero_autoresume; + dev->resume.data = (unsigned long) dev; + if (autoresume) { + source_sink_config.bmAttributes |= USB_CONFIG_ATT_WAKEUP; + loopback_config.bmAttributes |= USB_CONFIG_ATT_WAKEUP; + } + gadget->ep0->driver_data = dev; INFO (dev, "%s, version: " DRIVER_VERSION "\n", longname); INFO (dev, "using %s, OUT %s IN %s\n", gadget->name, EP_OUT_NAME, EP_IN_NAME); - snprintf (manufacturer, sizeof manufacturer, - UTS_SYSNAME " " UTS_RELEASE " with %s", + snprintf (manufacturer, sizeof manufacturer, "%s %s with %s", + system_utsname.sysname, system_utsname.release, gadget->name); return 0; @@ -1193,6 +1253,33 @@ enomem: return -ENOMEM; } +/*-------------------------------------------------------------------------*/ + +static void +zero_suspend (struct usb_gadget *gadget) +{ + struct zero_dev *dev = get_gadget_data (gadget); + + if (gadget->speed == USB_SPEED_UNKNOWN) + return; + + if (autoresume) { + mod_timer (&dev->resume, jiffies + (HZ * autoresume)); + DBG (dev, "suspend, wakeup in %d seconds\n", autoresume); + } else + DBG (dev, "suspend\n"); +} + +static void +zero_resume (struct usb_gadget *gadget) +{ + struct zero_dev *dev = get_gadget_data (gadget); + + DBG (dev, "resume\n"); + del_timer (&dev->resume); +} + + /*-------------------------------------------------------------------------*/ static struct usb_gadget_driver zero_driver = { @@ -1203,16 +1290,17 @@ static struct usb_gadget_driver zero_driver = { #endif .function = (char *) longname, .bind = zero_bind, - .unbind = zero_unbind, + .unbind = __exit_p(zero_unbind), .setup = zero_setup, .disconnect = zero_disconnect, + .suspend = zero_suspend, + .resume = zero_resume, + .driver = { .name = (char *) shortname, - // .shutdown = ... - // .suspend = ... - // .resume = ... + .owner = THIS_MODULE, }, };