Commit 3e4a8764 authored by David Brownell's avatar David Brownell Committed by Greg Kroah-Hartman

[PATCH] USB gadget: gadget zero, simplified controller-specific configuration

This removes several controller-specific #define, and
converts to using the config_buf utilities.  Depends
on the patch I submitted yesterday.  Looking simpler!


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).
parent 29a611ab
...@@ -8,7 +8,7 @@ obj-$(CONFIG_USB_GOKU) += goku_udc.o ...@@ -8,7 +8,7 @@ obj-$(CONFIG_USB_GOKU) += goku_udc.o
# #
# USB gadget drivers # USB gadget drivers
# #
g_zero-objs := zero.o usbstring.o g_zero-objs := zero.o usbstring.o config.o
g_ether-objs := ether.o usbstring.o config.o g_ether-objs := ether.o usbstring.o config.o
g_serial-objs := serial.o usbstring.o g_serial-objs := serial.o usbstring.o
gadgetfs-objs := inode.o usbstring.o gadgetfs-objs := inode.o usbstring.o
......
/* /*
* zero.c -- Gadget Zero, for USB development * zero.c -- Gadget Zero, for USB development
* *
* Copyright (C) 2003 David Brownell * Copyright (C) 2003-2004 David Brownell
* All rights reserved. * All rights reserved.
* *
* Redistribution and use in source and binary forms, with or without * Redistribution and use in source and binary forms, with or without
...@@ -102,6 +102,11 @@ static const char loopback [] = "loop input to output"; ...@@ -102,6 +102,11 @@ static const char loopback [] = "loop input to output";
/*-------------------------------------------------------------------------*/ /*-------------------------------------------------------------------------*/
/*
* driver assumes self-powered hardware, and
* has no way for users to trigger remote wakeup.
*/
/* /*
* hardware-specific configuration, controlled by which device * hardware-specific configuration, controlled by which device
* controller driver was configured. * controller driver was configured.
...@@ -110,11 +115,6 @@ static const char loopback [] = "loop input to output"; ...@@ -110,11 +115,6 @@ static const char loopback [] = "loop input to output";
* DRIVER_VERSION_NUM ... alerts the host side driver to differences * DRIVER_VERSION_NUM ... alerts the host side driver to differences
* EP_*_NAME ... which endpoints do we use for which purpose? * EP_*_NAME ... which endpoints do we use for which purpose?
* EP_*_NUM ... numbers for them (often limited by hardware) * 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 * add other defines for other portability issues, like hardware that
* for some reason doesn't handle full speed bulk maxpacket of 64. * for some reason doesn't handle full speed bulk maxpacket of 64.
...@@ -138,9 +138,6 @@ static const char EP_OUT_NAME [] = "ep-a"; ...@@ -138,9 +138,6 @@ static const char EP_OUT_NAME [] = "ep-a";
#define EP_OUT_NUM 2 #define EP_OUT_NUM 2
static const char EP_IN_NAME [] = "ep-b"; static const char EP_IN_NAME [] = "ep-b";
#define EP_IN_NUM 2 #define EP_IN_NUM 2
#define HIGHSPEED
/* specific hardware configs could be bus-powered */
/* supports remote wakeup, but this driver doesn't */
#endif #endif
/* /*
...@@ -161,8 +158,6 @@ static const char EP_OUT_NAME [] = "ep12out-bulk"; ...@@ -161,8 +158,6 @@ static const char EP_OUT_NAME [] = "ep12out-bulk";
#define EP_OUT_NUM 12 #define EP_OUT_NUM 12
static const char EP_IN_NAME [] = "ep11in-bulk"; static const char EP_IN_NAME [] = "ep11in-bulk";
#define EP_IN_NUM 11 #define EP_IN_NUM 11
/* doesn't support bus-powered operation */
/* supports remote wakeup, but this driver doesn't */
#endif #endif
/* /*
...@@ -183,8 +178,6 @@ static const char EP_OUT_NAME [] = "ep1out-bulk"; ...@@ -183,8 +178,6 @@ static const char EP_OUT_NAME [] = "ep1out-bulk";
#define EP_OUT_NUM 1 #define EP_OUT_NUM 1
static const char EP_IN_NAME [] = "ep2in-bulk"; static const char EP_IN_NAME [] = "ep2in-bulk";
#define EP_IN_NUM 2 #define EP_IN_NUM 2
/* doesn't support bus-powered operation */
/* doesn't support remote wakeup? */
#endif #endif
/* /*
...@@ -199,7 +192,6 @@ static const char EP_OUT_NAME [] = "ep1-bulk"; ...@@ -199,7 +192,6 @@ static const char EP_OUT_NAME [] = "ep1-bulk";
#define EP_OUT_NUM 1 #define EP_OUT_NUM 1
static const char EP_IN_NAME [] = "ep2-bulk"; static const char EP_IN_NAME [] = "ep2-bulk";
#define EP_IN_NUM 2 #define EP_IN_NUM 2
/* doesn't support remote wakeup */
#endif #endif
/*-------------------------------------------------------------------------*/ /*-------------------------------------------------------------------------*/
...@@ -208,30 +200,6 @@ static const char EP_IN_NAME [] = "ep2-bulk"; ...@@ -208,30 +200,6 @@ static const char EP_IN_NAME [] = "ep2-bulk";
# error Configure some USB peripheral controller driver! # error Configure some USB peripheral controller driver!
#endif #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 */ /* big enough to hold our biggest descriptor */
...@@ -290,8 +258,8 @@ module_param (pattern, uint, S_IRUGO|S_IWUSR); ...@@ -290,8 +258,8 @@ 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
* it's not the default. Here's where to change that order, to * it's not the default. Here's where to change that order, to
* work better with hosts (like Linux ... for now!) where config * work better with hosts where config changes are problematic.
* changes are problematic. * Or controllers (like superh) that only support one config.
*/ */
static int loopdefault = 0; static int loopdefault = 0;
...@@ -301,7 +269,7 @@ module_param (loopdefault, bool, S_IRUGO|S_IWUSR); ...@@ -301,7 +269,7 @@ module_param (loopdefault, bool, S_IRUGO|S_IWUSR);
/* Thanks to NetChip Technologies for donating this product ID. /* 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. * Instead: allocate your own, using normal USB-IF procedures.
*/ */
#define DRIVER_VENDOR_NUM 0x0525 /* NetChip */ #define DRIVER_VENDOR_NUM 0x0525 /* NetChip */
...@@ -353,8 +321,8 @@ source_sink_config = { ...@@ -353,8 +321,8 @@ source_sink_config = {
.bNumInterfaces = 1, .bNumInterfaces = 1,
.bConfigurationValue = CONFIG_SOURCE_SINK, .bConfigurationValue = CONFIG_SOURCE_SINK,
.iConfiguration = STRING_SOURCE_SINK, .iConfiguration = STRING_SOURCE_SINK,
.bmAttributes = USB_CONFIG_ATT_ONE | SELFPOWER | WAKEUP, .bmAttributes = USB_CONFIG_ATT_ONE | USB_CONFIG_ATT_SELFPOWER,
.bMaxPower = (MAX_USB_POWER + 1) / 2, .bMaxPower = 1, /* self-powered */
}; };
static const struct usb_config_descriptor static const struct usb_config_descriptor
...@@ -366,8 +334,8 @@ loopback_config = { ...@@ -366,8 +334,8 @@ loopback_config = {
.bNumInterfaces = 1, .bNumInterfaces = 1,
.bConfigurationValue = CONFIG_LOOPBACK, .bConfigurationValue = CONFIG_LOOPBACK,
.iConfiguration = STRING_LOOPBACK, .iConfiguration = STRING_LOOPBACK,
.bmAttributes = USB_CONFIG_ATT_ONE | SELFPOWER | WAKEUP, .bmAttributes = USB_CONFIG_ATT_ONE | USB_CONFIG_ATT_SELFPOWER,
.bMaxPower = (MAX_USB_POWER + 1) / 2, .bMaxPower = 1, /* self-powered */
}; };
/* one interface in each configuration */ /* one interface in each configuration */
...@@ -414,7 +382,21 @@ fs_sink_desc = { ...@@ -414,7 +382,21 @@ fs_sink_desc = {
.wMaxPacketSize = __constant_cpu_to_le16 (64), .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 * usb 2.0 devices need to expose both high speed and full speed
...@@ -425,22 +407,20 @@ fs_sink_desc = { ...@@ -425,22 +407,20 @@ fs_sink_desc = {
* for the config descriptor. * for the config descriptor.
*/ */
static const struct usb_endpoint_descriptor static struct usb_endpoint_descriptor
hs_source_desc = { hs_source_desc = {
.bLength = USB_DT_ENDPOINT_SIZE, .bLength = USB_DT_ENDPOINT_SIZE,
.bDescriptorType = USB_DT_ENDPOINT, .bDescriptorType = USB_DT_ENDPOINT,
.bEndpointAddress = EP_IN_NUM | USB_DIR_IN,
.bmAttributes = USB_ENDPOINT_XFER_BULK, .bmAttributes = USB_ENDPOINT_XFER_BULK,
.wMaxPacketSize = __constant_cpu_to_le16 (512), .wMaxPacketSize = __constant_cpu_to_le16 (512),
}; };
static const struct usb_endpoint_descriptor static struct usb_endpoint_descriptor
hs_sink_desc = { hs_sink_desc = {
.bLength = USB_DT_ENDPOINT_SIZE, .bLength = USB_DT_ENDPOINT_SIZE,
.bDescriptorType = USB_DT_ENDPOINT, .bDescriptorType = USB_DT_ENDPOINT,
.bEndpointAddress = EP_OUT_NUM,
.bmAttributes = USB_ENDPOINT_XFER_BULK, .bmAttributes = USB_ENDPOINT_XFER_BULK,
.wMaxPacketSize = __constant_cpu_to_le16 (512), .wMaxPacketSize = __constant_cpu_to_le16 (512),
}; };
...@@ -456,6 +436,20 @@ dev_qualifier = { ...@@ -456,6 +436,20 @@ dev_qualifier = {
.bNumConfigurations = 2, .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. */ /* maxpacket and other transfer characteristics vary by speed. */
#define ep_desc(g,hs,fs) (((g)->speed==USB_SPEED_HIGH)?(hs):(fs)) #define ep_desc(g,hs,fs) (((g)->speed==USB_SPEED_HIGH)?(hs):(fs))
...@@ -464,13 +458,14 @@ dev_qualifier = { ...@@ -464,13 +458,14 @@ dev_qualifier = {
/* if there's no high speed support, maxpacket doesn't change. */ /* if there's no high speed support, maxpacket doesn't change. */
#define ep_desc(g,hs,fs) fs #define ep_desc(g,hs,fs) fs
#endif /* !HIGHSPEED */ #endif /* !CONFIG_USB_GADGET_DUALSPEED */
static char manufacturer [40];
static char serial [40]; static char serial [40];
/* static strings, in iso 8859/1 */ /* static strings, in iso 8859/1 */
static struct usb_string strings [] = { static struct usb_string strings [] = {
{ STRING_MANUFACTURER, UTS_SYSNAME " " UTS_RELEASE " with " CHIP, }, { STRING_MANUFACTURER, manufacturer, },
{ STRING_PRODUCT, longname, }, { STRING_PRODUCT, longname, },
{ STRING_SERIAL, serial, }, { STRING_SERIAL, serial, },
{ STRING_LOOPBACK, loopback, }, { STRING_LOOPBACK, loopback, },
...@@ -502,60 +497,42 @@ static struct usb_gadget_strings stringtab = { ...@@ -502,60 +497,42 @@ static struct usb_gadget_strings stringtab = {
* device?) * device?)
*/ */
static int static int
config_buf (enum usb_device_speed speed, config_buf (struct usb_gadget *gadget,
u8 *buf, u8 type, unsigned index) u8 *buf, u8 type, unsigned index)
{ {
int is_source_sink; int is_source_sink;
const unsigned config_len = USB_DT_CONFIG_SIZE int len;
+ USB_DT_INTERFACE_SIZE const struct usb_descriptor_header **function;
+ 2 * USB_DT_ENDPOINT_SIZE; #ifdef CONFIG_USB_GADGET_DUALSPEED
#ifdef HIGHSPEED int hs = (gadget->speed == USB_SPEED_HIGH);
int hs;
#endif #endif
/* two configurations will always be index 0 and index 1 */ /* two configurations will always be index 0 and index 1 */
if (index > 1) if (index > 1)
return -EINVAL; return -EINVAL;
if (config_len > USB_BUFSIZ)
return -EDOM;
is_source_sink = loopdefault ? (index == 1) : (index == 0); is_source_sink = loopdefault ? (index == 1) : (index == 0);
/* config (or other speed config) */ #ifdef CONFIG_USB_GADGET_DUALSPEED
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);
if (type == USB_DT_OTHER_SPEED_CONFIG) if (type == USB_DT_OTHER_SPEED_CONFIG)
hs = !hs; hs = !hs;
if (hs) { if (hs)
memcpy (buf, &hs_source_desc, USB_DT_ENDPOINT_SIZE); function = is_source_sink
buf += USB_DT_ENDPOINT_SIZE; ? hs_source_sink_function
memcpy (buf, &hs_sink_desc, USB_DT_ENDPOINT_SIZE); : hs_loopback_function;
buf += USB_DT_ENDPOINT_SIZE; else
} else
#endif #endif
{ function = is_source_sink
memcpy (buf, &fs_source_desc, USB_DT_ENDPOINT_SIZE); ? fs_source_sink_function
buf += USB_DT_ENDPOINT_SIZE; : fs_loopback_function;
memcpy (buf, &fs_sink_desc, USB_DT_ENDPOINT_SIZE);
buf += USB_DT_ENDPOINT_SIZE; len = usb_gadget_config_buf (is_source_sink
} ? &source_sink_config
: &loopback_config,
return config_len; buf, USB_BUFSIZ, function);
if (len < 0)
return len;
((struct usb_config_descriptor *) buf)->bDescriptorType = type;
return len;
} }
/*-------------------------------------------------------------------------*/ /*-------------------------------------------------------------------------*/
...@@ -1019,17 +996,21 @@ zero_setup (struct usb_gadget *gadget, const struct usb_ctrlrequest *ctrl) ...@@ -1019,17 +996,21 @@ zero_setup (struct usb_gadget *gadget, const struct usb_ctrlrequest *ctrl)
value = min (ctrl->wLength, (u16) sizeof device_desc); value = min (ctrl->wLength, (u16) sizeof device_desc);
memcpy (req->buf, &device_desc, value); memcpy (req->buf, &device_desc, value);
break; break;
#ifdef HIGHSPEED #ifdef CONFIG_USB_GADGET_DUALSPEED
case USB_DT_DEVICE_QUALIFIER: case USB_DT_DEVICE_QUALIFIER:
if (!gadget->is_dualspeed)
break;
value = min (ctrl->wLength, (u16) sizeof dev_qualifier); value = min (ctrl->wLength, (u16) sizeof dev_qualifier);
memcpy (req->buf, &dev_qualifier, value); memcpy (req->buf, &dev_qualifier, value);
break; break;
case USB_DT_OTHER_SPEED_CONFIG: case USB_DT_OTHER_SPEED_CONFIG:
if (!gadget->is_dualspeed)
break;
// FALLTHROUGH // FALLTHROUGH
#endif /* HIGHSPEED */ #endif /* CONFIG_USB_GADGET_DUALSPEED */
case USB_DT_CONFIG: case USB_DT_CONFIG:
value = config_buf (gadget->speed, req->buf, value = config_buf (gadget, req->buf,
ctrl->wValue >> 8, ctrl->wValue >> 8,
ctrl->wValue & 0xff); ctrl->wValue & 0xff);
if (value >= 0) if (value >= 0)
...@@ -1212,14 +1193,26 @@ zero_bind (struct usb_gadget *gadget) ...@@ -1212,14 +1193,26 @@ zero_bind (struct usb_gadget *gadget)
dev->req->complete = zero_setup_complete; dev->req->complete = zero_setup_complete;
device_desc.bMaxPacketSize0 = gadget->ep0->maxpacket; device_desc.bMaxPacketSize0 = gadget->ep0->maxpacket;
#ifdef HIGHSPEED
#ifdef CONFIG_USB_GADGET_DUALSPEED
/* assume ep0 uses the same value for both speeds ... */ /* assume ep0 uses the same value for both speeds ... */
dev_qualifier.bMaxPacketSize0 = device_desc.bMaxPacketSize0; 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 #endif
gadget->ep0->driver_data = dev; gadget->ep0->driver_data = dev;
INFO (dev, "%s, version: " DRIVER_VERSION "\n", longname); 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; return 0;
enomem: enomem:
...@@ -1230,7 +1223,7 @@ zero_bind (struct usb_gadget *gadget) ...@@ -1230,7 +1223,7 @@ zero_bind (struct usb_gadget *gadget)
/*-------------------------------------------------------------------------*/ /*-------------------------------------------------------------------------*/
static struct usb_gadget_driver zero_driver = { static struct usb_gadget_driver zero_driver = {
#ifdef HIGHSPEED #ifdef CONFIG_USB_GADGET_DUALSPEED
.speed = USB_SPEED_HIGH, .speed = USB_SPEED_HIGH,
#else #else
.speed = USB_SPEED_FULL, .speed = USB_SPEED_FULL,
......
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