ChangeSet 1.1290.15.25, 2004/03/17 15:07:43-08:00, david-b@pacbell.net [PATCH] USB: gadget zero, simplified controller-specific configuration Simplify "gadget zero" compile-time configuration. This removes several controller-specific compile-time config options; the others are about to be autoconfigured. - HIGHSPEED replaced by CONFIG_USB_GADGET_DUALSPEED - Default to self-powered operation - There's no UI for remote wakeup It also uses the new config_buf utilities, so it's a bit easier to see what's really going on (this driver implements four configurations). drivers/usb/gadget/Makefile | 2 drivers/usb/gadget/zero.c | 193 +++++++++++++++++++++----------------------- 2 files changed, 94 insertions(+), 101 deletions(-) diff -Nru a/drivers/usb/gadget/Makefile b/drivers/usb/gadget/Makefile --- a/drivers/usb/gadget/Makefile Wed Mar 17 15:48:15 2004 +++ b/drivers/usb/gadget/Makefile Wed Mar 17 15:48:15 2004 @@ -16,7 +16,7 @@ controller-$(CONFIG_USB_GOKU) += goku_udc.o # ... and only one of these, too; kbuild/kconfig don't help though. -g_zero-objs := zero.o usbstring.o +g_zero-objs := zero.o usbstring.o config.o obj-$(CONFIG_USB_ZERO) += g_zero.o g_ether-objs := ether.o usbstring.o config.o diff -Nru a/drivers/usb/gadget/zero.c b/drivers/usb/gadget/zero.c --- a/drivers/usb/gadget/zero.c Wed Mar 17 15:48:15 2004 +++ b/drivers/usb/gadget/zero.c Wed Mar 17 15:48:15 2004 @@ -1,7 +1,7 @@ /* * zero.c -- Gadget Zero, for USB development * - * Copyright (C) 2003 David Brownell + * Copyright (C) 2003-2004 David Brownell * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -101,6 +101,11 @@ /*-------------------------------------------------------------------------*/ /* + * driver assumes self-powered hardware, and + * has no way for users to trigger remote wakeup. + */ + +/* * hardware-specific configuration, controlled by which device * controller driver was configured. * @@ -108,11 +113,6 @@ * DRIVER_VERSION_NUM ... alerts the host side driver to differences * EP_*_NAME ... which endpoints do we use for which purpose? * EP_*_NUM ... numbers for them (often limited by hardware) - * HIGHSPEED ... define if ep0 and descriptors need high speed support - * MAX_USB_POWER ... define if we use other than 100 mA bus current - * SELFPOWER ... if we can run on bus power, zero - * WAKEUP ... if hardware supports remote wakeup AND we will issue the - * usb_gadget_wakeup() call to initiate it, USB_CONFIG_ATT_WAKEUP * * add other defines for other portability issues, like hardware that * for some reason doesn't handle full speed bulk maxpacket of 64. @@ -136,9 +136,6 @@ #define EP_OUT_NUM 2 static const char EP_IN_NAME [] = "ep-b"; #define EP_IN_NUM 2 -#define HIGHSPEED -/* specific hardware configs could be bus-powered */ -/* supports remote wakeup, but this driver doesn't */ #endif /* @@ -159,8 +156,6 @@ #define EP_OUT_NUM 12 static const char EP_IN_NAME [] = "ep11in-bulk"; #define EP_IN_NUM 11 -/* doesn't support bus-powered operation */ -/* supports remote wakeup, but this driver doesn't */ #endif /* @@ -181,8 +176,6 @@ #define EP_OUT_NUM 1 static const char EP_IN_NAME [] = "ep2in-bulk"; #define EP_IN_NUM 2 -/* doesn't support bus-powered operation */ -/* doesn't support remote wakeup? */ #endif /* @@ -197,7 +190,6 @@ #define EP_OUT_NUM 1 static const char EP_IN_NAME [] = "ep2-bulk"; #define EP_IN_NUM 2 -/* doesn't support remote wakeup */ #endif /*-------------------------------------------------------------------------*/ @@ -206,30 +198,6 @@ # error Configure some USB peripheral controller driver! #endif -/* power usage is config specific. - * hardware that supports remote wakeup defaults to disabling it. - */ - -#ifndef SELFPOWER -/* default: say we're self-powered */ -#define SELFPOWER USB_CONFIG_ATT_SELFPOWER -/* else: - * - SELFPOWER value must be zero - * - MAX_USB_POWER may be nonzero. - */ -#endif - -#ifndef MAX_USB_POWER -/* any hub supports this steady state bus power consumption */ -#define MAX_USB_POWER 100 /* mA */ -#endif - -#ifndef WAKEUP -/* default: this driver won't do remote wakeup */ -#define WAKEUP 0 -/* else value must be USB_CONFIG_ATT_WAKEUP */ -#endif - /*-------------------------------------------------------------------------*/ /* big enough to hold our biggest descriptor */ @@ -284,8 +252,8 @@ /* * Normally the "loopback" configuration is second (index 1) so * it's not the default. Here's where to change that order, to - * work better with hosts (like Linux ... for now!) where config - * changes are problematic. + * work better with hosts where config changes are problematic. + * Or controllers (like superh) that only support one config. */ static int loopdefault = 0; @@ -306,7 +274,7 @@ /* Thanks to NetChip Technologies for donating this product ID. * - * DO NOT REUSE THESE IDs with any other driver!! Ever!! + * DO NOT REUSE THESE IDs with a protocol-incompatible driver!! Ever!! * Instead: allocate your own, using normal USB-IF procedures. */ #define DRIVER_VENDOR_NUM 0x0525 /* NetChip */ @@ -358,8 +326,8 @@ .bNumInterfaces = 1, .bConfigurationValue = CONFIG_SOURCE_SINK, .iConfiguration = STRING_SOURCE_SINK, - .bmAttributes = USB_CONFIG_ATT_ONE | SELFPOWER | WAKEUP, - .bMaxPower = (MAX_USB_POWER + 1) / 2, + .bmAttributes = USB_CONFIG_ATT_ONE | USB_CONFIG_ATT_SELFPOWER, + .bMaxPower = 1, /* self-powered */ }; static const struct usb_config_descriptor @@ -371,8 +339,8 @@ .bNumInterfaces = 1, .bConfigurationValue = CONFIG_LOOPBACK, .iConfiguration = STRING_LOOPBACK, - .bmAttributes = USB_CONFIG_ATT_ONE | SELFPOWER | WAKEUP, - .bMaxPower = (MAX_USB_POWER + 1) / 2, + .bmAttributes = USB_CONFIG_ATT_ONE | USB_CONFIG_ATT_SELFPOWER, + .bMaxPower = 1, /* self-powered */ }; /* one interface in each configuration */ @@ -419,7 +387,21 @@ .wMaxPacketSize = __constant_cpu_to_le16 (64), }; -#ifdef HIGHSPEED +static const struct usb_descriptor_header *fs_source_sink_function [] = { + (struct usb_descriptor_header *) &source_sink_intf, + (struct usb_descriptor_header *) &fs_sink_desc, + (struct usb_descriptor_header *) &fs_source_desc, + 0, +}; + +static const struct usb_descriptor_header *fs_loopback_function [] = { + (struct usb_descriptor_header *) &loopback_intf, + (struct usb_descriptor_header *) &fs_sink_desc, + (struct usb_descriptor_header *) &fs_source_desc, + 0, +}; + +#ifdef CONFIG_USB_GADGET_DUALSPEED /* * usb 2.0 devices need to expose both high speed and full speed @@ -430,22 +412,20 @@ * for the config descriptor. */ -static const struct usb_endpoint_descriptor +static struct usb_endpoint_descriptor hs_source_desc = { .bLength = USB_DT_ENDPOINT_SIZE, .bDescriptorType = USB_DT_ENDPOINT, - .bEndpointAddress = EP_IN_NUM | USB_DIR_IN, .bmAttributes = USB_ENDPOINT_XFER_BULK, .wMaxPacketSize = __constant_cpu_to_le16 (512), }; -static const struct usb_endpoint_descriptor +static struct usb_endpoint_descriptor hs_sink_desc = { .bLength = USB_DT_ENDPOINT_SIZE, .bDescriptorType = USB_DT_ENDPOINT, - .bEndpointAddress = EP_OUT_NUM, .bmAttributes = USB_ENDPOINT_XFER_BULK, .wMaxPacketSize = __constant_cpu_to_le16 (512), }; @@ -461,6 +441,20 @@ .bNumConfigurations = 2, }; +static const struct usb_descriptor_header *hs_source_sink_function [] = { + (struct usb_descriptor_header *) &source_sink_intf, + (struct usb_descriptor_header *) &hs_source_desc, + (struct usb_descriptor_header *) &hs_sink_desc, + 0, +}; + +static const struct usb_descriptor_header *hs_loopback_function [] = { + (struct usb_descriptor_header *) &loopback_intf, + (struct usb_descriptor_header *) &hs_source_desc, + (struct usb_descriptor_header *) &hs_sink_desc, + 0, +}; + /* maxpacket and other transfer characteristics vary by speed. */ #define ep_desc(g,hs,fs) (((g)->speed==USB_SPEED_HIGH)?(hs):(fs)) @@ -469,13 +463,14 @@ /* if there's no high speed support, maxpacket doesn't change. */ #define ep_desc(g,hs,fs) fs -#endif /* !HIGHSPEED */ +#endif /* !CONFIG_USB_GADGET_DUALSPEED */ +static char manufacturer [40]; static char serial [40]; /* static strings, in iso 8859/1 */ static struct usb_string strings [] = { - { STRING_MANUFACTURER, UTS_SYSNAME " " UTS_RELEASE " with " CHIP, }, + { STRING_MANUFACTURER, manufacturer, }, { STRING_PRODUCT, longname, }, { STRING_SERIAL, serial, }, { STRING_LOOPBACK, loopback, }, @@ -507,60 +502,42 @@ * device?) */ static int -config_buf (enum usb_device_speed speed, +config_buf (struct usb_gadget *gadget, u8 *buf, u8 type, unsigned index) { - int is_source_sink; - const unsigned config_len = USB_DT_CONFIG_SIZE - + USB_DT_INTERFACE_SIZE - + 2 * USB_DT_ENDPOINT_SIZE; -#ifdef HIGHSPEED - int hs; + int is_source_sink; + int len; + const struct usb_descriptor_header **function; +#ifdef CONFIG_USB_GADGET_DUALSPEED + int hs = (gadget->speed == USB_SPEED_HIGH); #endif + /* two configurations will always be index 0 and index 1 */ if (index > 1) return -EINVAL; - if (config_len > USB_BUFSIZ) - return -EDOM; is_source_sink = loopdefault ? (index == 1) : (index == 0); - /* config (or other speed config) */ - if (is_source_sink) - memcpy (buf, &source_sink_config, USB_DT_CONFIG_SIZE); - else - memcpy (buf, &loopback_config, USB_DT_CONFIG_SIZE); - buf [1] = type; - ((struct usb_config_descriptor *) buf)->wTotalLength - = __constant_cpu_to_le16 (config_len); - buf += USB_DT_CONFIG_SIZE; - - /* one interface */ - if (is_source_sink) - memcpy (buf, &source_sink_intf, USB_DT_INTERFACE_SIZE); - else - memcpy (buf, &loopback_intf, USB_DT_INTERFACE_SIZE); - buf += USB_DT_INTERFACE_SIZE; - - /* the endpoints in that interface (at that speed) */ -#ifdef HIGHSPEED - hs = (speed == USB_SPEED_HIGH); +#ifdef CONFIG_USB_GADGET_DUALSPEED if (type == USB_DT_OTHER_SPEED_CONFIG) hs = !hs; - if (hs) { - memcpy (buf, &hs_source_desc, USB_DT_ENDPOINT_SIZE); - buf += USB_DT_ENDPOINT_SIZE; - memcpy (buf, &hs_sink_desc, USB_DT_ENDPOINT_SIZE); - buf += USB_DT_ENDPOINT_SIZE; - } else + if (hs) + function = is_source_sink + ? hs_source_sink_function + : hs_loopback_function; + else #endif - { - memcpy (buf, &fs_source_desc, USB_DT_ENDPOINT_SIZE); - buf += USB_DT_ENDPOINT_SIZE; - memcpy (buf, &fs_sink_desc, USB_DT_ENDPOINT_SIZE); - buf += USB_DT_ENDPOINT_SIZE; - } - - return config_len; + function = is_source_sink + ? fs_source_sink_function + : fs_loopback_function; + + len = usb_gadget_config_buf (is_source_sink + ? &source_sink_config + : &loopback_config, + buf, USB_BUFSIZ, function); + if (len < 0) + return len; + ((struct usb_config_descriptor *) buf)->bDescriptorType = type; + return len; } /*-------------------------------------------------------------------------*/ @@ -1024,17 +1001,21 @@ value = min (ctrl->wLength, (u16) sizeof device_desc); memcpy (req->buf, &device_desc, value); break; -#ifdef HIGHSPEED +#ifdef CONFIG_USB_GADGET_DUALSPEED case USB_DT_DEVICE_QUALIFIER: + if (!gadget->is_dualspeed) + break; value = min (ctrl->wLength, (u16) sizeof dev_qualifier); memcpy (req->buf, &dev_qualifier, value); break; case USB_DT_OTHER_SPEED_CONFIG: + if (!gadget->is_dualspeed) + break; // FALLTHROUGH -#endif /* HIGHSPEED */ +#endif /* CONFIG_USB_GADGET_DUALSPEED */ case USB_DT_CONFIG: - value = config_buf (gadget->speed, req->buf, + value = config_buf (gadget, req->buf, ctrl->wValue >> 8, ctrl->wValue & 0xff); if (value >= 0) @@ -1217,14 +1198,26 @@ dev->req->complete = zero_setup_complete; device_desc.bMaxPacketSize0 = gadget->ep0->maxpacket; -#ifdef HIGHSPEED + +#ifdef CONFIG_USB_GADGET_DUALSPEED /* assume ep0 uses the same value for both speeds ... */ dev_qualifier.bMaxPacketSize0 = device_desc.bMaxPacketSize0; + + /* and that all endpoints are dual-speed */ + hs_source_desc.bEndpointAddress = fs_source_desc.bEndpointAddress; + hs_sink_desc.bEndpointAddress = fs_sink_desc.bEndpointAddress; #endif 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", + gadget->name); + return 0; enomem: @@ -1235,7 +1228,7 @@ /*-------------------------------------------------------------------------*/ static struct usb_gadget_driver zero_driver = { -#ifdef HIGHSPEED +#ifdef CONFIG_USB_GADGET_DUALSPEED .speed = USB_SPEED_HIGH, #else .speed = USB_SPEED_FULL,