Commit 354e8872 authored by Alan Stern's avatar Alan Stern Committed by Greg Kroah-Hartman

[PATCH] USB Gadget: Use configuration-buffer library in file-storage

This patch imports the config-buffer library into the file-storage gadget,
simplifying and decreasing the amount of code needed for assembling
configuration descriptors.  It also changes the driver to remove any
pretense at bus-powered operation and to use the new DUALSPEED
configuration option.  This is in line with recent changes made to other
gadget drivers.
parent 6334e786
...@@ -13,7 +13,7 @@ g_zero-objs := zero.o usbstring.o config.o epautoconf.o ...@@ -13,7 +13,7 @@ g_zero-objs := zero.o usbstring.o config.o epautoconf.o
g_ether-objs := ether.o usbstring.o config.o epautoconf.o g_ether-objs := ether.o usbstring.o config.o epautoconf.o
g_serial-objs := serial.o usbstring.o g_serial-objs := serial.o usbstring.o
gadgetfs-objs := inode.o gadgetfs-objs := inode.o
g_file_storage-objs := file_storage.o usbstring.o g_file_storage-objs := file_storage.o usbstring.o config.o
ifeq ($(CONFIG_USB_ETH_RNDIS),y) ifeq ($(CONFIG_USB_ETH_RNDIS),y)
g_ether-objs += rndis.o g_ether-objs += rndis.o
......
...@@ -263,6 +263,12 @@ MODULE_LICENSE("Dual BSD/GPL"); ...@@ -263,6 +263,12 @@ MODULE_LICENSE("Dual BSD/GPL");
/*-------------------------------------------------------------------------*/ /*-------------------------------------------------------------------------*/
/*
* This 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.
...@@ -273,9 +279,6 @@ MODULE_LICENSE("Dual BSD/GPL"); ...@@ -273,9 +279,6 @@ MODULE_LICENSE("Dual BSD/GPL");
* EP_*_NUM ... numbers for them (often limited by hardware) * EP_*_NUM ... numbers for them (often limited by hardware)
* FS_BULK_IN_MAXPACKET ... maxpacket value for full-speed bulk-in ep * FS_BULK_IN_MAXPACKET ... maxpacket value for full-speed bulk-in ep
* FS_BULK_OUT_MAXPACKET ... maxpacket value for full-speed bulk-out ep * FS_BULK_OUT_MAXPACKET ... maxpacket value for full-speed bulk-out ep
* 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
* NO_BULK_STALL ... bulk endpoint halts don't work well so avoid them * NO_BULK_STALL ... bulk endpoint halts don't work well so avoid them
*/ */
...@@ -298,7 +301,6 @@ static const char EP_BULK_OUT_NAME[] = "ep-b"; ...@@ -298,7 +301,6 @@ static const char EP_BULK_OUT_NAME[] = "ep-b";
#define FS_BULK_OUT_MAXPACKET 64 #define FS_BULK_OUT_MAXPACKET 64
static const char EP_INTR_IN_NAME[] = "ep-e"; static const char EP_INTR_IN_NAME[] = "ep-e";
#define EP_INTR_IN_NUM 5 #define EP_INTR_IN_NUM 5
#define HIGHSPEED
#endif #endif
...@@ -319,7 +321,6 @@ static const char EP_BULK_OUT_NAME[] = "ep-b"; ...@@ -319,7 +321,6 @@ static const char EP_BULK_OUT_NAME[] = "ep-b";
#define FS_BULK_OUT_MAXPACKET 64 #define FS_BULK_OUT_MAXPACKET 64
static const char EP_INTR_IN_NAME[] = "ep-e"; static const char EP_INTR_IN_NAME[] = "ep-e";
#define EP_INTR_IN_NUM 5 #define EP_INTR_IN_NUM 5
#define HIGHSPEED
#endif #endif
...@@ -396,25 +397,6 @@ static const char EP_INTR_IN_NAME [] = "ep3-bulk"; ...@@ -396,25 +397,6 @@ static const char EP_INTR_IN_NAME [] = "ep3-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
/* We don't support remote wake-up */
#ifdef NO_BULK_STALL #ifdef NO_BULK_STALL
#define CAN_STALL 0 #define CAN_STALL 0
#else #else
...@@ -1015,11 +997,11 @@ config_desc = { ...@@ -1015,11 +997,11 @@ config_desc = {
.bLength = sizeof config_desc, .bLength = sizeof config_desc,
.bDescriptorType = USB_DT_CONFIG, .bDescriptorType = USB_DT_CONFIG,
/* wTotalLength adjusted during bind() */ /* wTotalLength computed by usb_gadget_config_buf() */
.bNumInterfaces = 1, .bNumInterfaces = 1,
.bConfigurationValue = CONFIG_VALUE, .bConfigurationValue = CONFIG_VALUE,
.bmAttributes = USB_CONFIG_ATT_ONE | SELFPOWER, .bmAttributes = USB_CONFIG_ATT_ONE | USB_CONFIG_ATT_SELFPOWER,
.bMaxPower = (MAX_USB_POWER + 1) / 2, .bMaxPower = 1, // self-powered
}; };
/* There is only one interface. */ /* There is only one interface. */
...@@ -1069,7 +1051,16 @@ fs_intr_in_desc = { ...@@ -1069,7 +1051,16 @@ fs_intr_in_desc = {
.bInterval = 32, // frames -> 32 ms .bInterval = 32, // frames -> 32 ms
}; };
#ifdef HIGHSPEED static const struct usb_descriptor_header *fs_function[] = {
(struct usb_descriptor_header *) &intf_desc,
(struct usb_descriptor_header *) &fs_bulk_in_desc,
(struct usb_descriptor_header *) &fs_bulk_out_desc,
(struct usb_descriptor_header *) &fs_intr_in_desc,
NULL,
};
#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
...@@ -1079,47 +1070,52 @@ fs_intr_in_desc = { ...@@ -1079,47 +1070,52 @@ fs_intr_in_desc = {
* and a "device qualifier" ... plus more construction options * and a "device qualifier" ... plus more construction options
* for the config descriptor. * for the config descriptor.
*/ */
static const struct usb_endpoint_descriptor static struct usb_qualifier_descriptor
dev_qualifier = {
.bLength = sizeof dev_qualifier,
.bDescriptorType = USB_DT_DEVICE_QUALIFIER,
.bcdUSB = __constant_cpu_to_le16(0x0200),
.bDeviceClass = USB_CLASS_PER_INTERFACE,
.bNumConfigurations = 1,
};
static struct usb_endpoint_descriptor
hs_bulk_in_desc = { hs_bulk_in_desc = {
.bLength = USB_DT_ENDPOINT_SIZE, .bLength = USB_DT_ENDPOINT_SIZE,
.bDescriptorType = USB_DT_ENDPOINT, .bDescriptorType = USB_DT_ENDPOINT,
.bEndpointAddress = EP_BULK_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_bulk_out_desc = { hs_bulk_out_desc = {
.bLength = USB_DT_ENDPOINT_SIZE, .bLength = USB_DT_ENDPOINT_SIZE,
.bDescriptorType = USB_DT_ENDPOINT, .bDescriptorType = USB_DT_ENDPOINT,
.bEndpointAddress = EP_BULK_OUT_NUM,
.bmAttributes = USB_ENDPOINT_XFER_BULK, .bmAttributes = USB_ENDPOINT_XFER_BULK,
.wMaxPacketSize = __constant_cpu_to_le16(512), .wMaxPacketSize = __constant_cpu_to_le16(512),
.bInterval = 1, // NAK every 1 uframe .bInterval = 1, // NAK every 1 uframe
}; };
static const struct usb_endpoint_descriptor static struct usb_endpoint_descriptor
hs_intr_in_desc = { hs_intr_in_desc = {
.bLength = USB_DT_ENDPOINT_SIZE, .bLength = USB_DT_ENDPOINT_SIZE,
.bDescriptorType = USB_DT_ENDPOINT, .bDescriptorType = USB_DT_ENDPOINT,
.bEndpointAddress = EP_INTR_IN_NUM | USB_DIR_IN,
.bmAttributes = USB_ENDPOINT_XFER_INT, .bmAttributes = USB_ENDPOINT_XFER_INT,
.wMaxPacketSize = __constant_cpu_to_le16(2), .wMaxPacketSize = __constant_cpu_to_le16(2),
.bInterval = 9, // 2**(9-1) = 256 uframes -> 32 ms .bInterval = 9, // 2**(9-1) = 256 uframes -> 32 ms
}; };
static struct usb_qualifier_descriptor static const struct usb_descriptor_header *hs_function[] = {
dev_qualifier = { (struct usb_descriptor_header *) &intf_desc,
.bLength = sizeof dev_qualifier, (struct usb_descriptor_header *) &hs_bulk_in_desc,
.bDescriptorType = USB_DT_DEVICE_QUALIFIER, (struct usb_descriptor_header *) &hs_bulk_out_desc,
(struct usb_descriptor_header *) &hs_intr_in_desc,
.bcdUSB = __constant_cpu_to_le16(0x0200), NULL,
.bDeviceClass = USB_CLASS_PER_INTERFACE,
.bNumConfigurations = 1,
}; };
/* Maxpacket and other transfer characteristics vary by speed. */ /* Maxpacket and other transfer characteristics vary by speed. */
...@@ -1127,22 +1123,23 @@ dev_qualifier = { ...@@ -1127,22 +1123,23 @@ dev_qualifier = {
#else #else
/* If there's no high speed support, maxpacket doesn't change. */ /* If there's no high speed support, always use the full-speed descriptor. */
#define ep_desc(g,fs,hs) fs #define ep_desc(g,fs,hs) fs
#endif /* !HIGHSPEED */ #endif /* !CONFIG_USB_GADGET_DUALSPEED */
/* The CBI specification limits the serial string to 12 uppercase hexadecimal /* The CBI specification limits the serial string to 12 uppercase hexadecimal
* characters. */ * characters. */
static char manufacturer[40];
static char serial[13]; static char serial[13];
/* Static strings, in ISO 8859/1 */ /* Static strings, in UTF-8 (for simplicity we use only ASCII characters) */
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},
{ } // end of list {}
}; };
static struct usb_gadget_strings stringtab = { static struct usb_gadget_strings stringtab = {
...@@ -1152,61 +1149,33 @@ static struct usb_gadget_strings stringtab = { ...@@ -1152,61 +1149,33 @@ static struct usb_gadget_strings stringtab = {
/* /*
* Config descriptors are handcrafted. They must agree with the code * Config descriptors must agree with the code that sets configurations
* that sets configurations and with code managing interfaces and their * and with code managing interfaces and their altsettings. They must
* altsettings. They must also handle different speeds and other-speed * also handle different speeds and other-speed requests.
* requests.
*/ */
static int populate_config_buf(enum usb_device_speed speed, static int populate_config_buf(enum usb_device_speed speed,
u8 *buf0, u8 type, unsigned index) u8 *buf, u8 type, unsigned index)
{ {
u8 *buf = buf0; int len;
#ifdef HIGHSPEED const struct usb_descriptor_header **function;
int hs;
#endif
if (index > 0) if (index > 0)
return -EINVAL; return -EINVAL;
if (config_desc.wTotalLength > EP0_BUFSIZE)
return -EDOM;
/* Config (or other speed config) */
memcpy(buf, &config_desc, USB_DT_CONFIG_SIZE);
buf[1] = type;
buf += USB_DT_CONFIG_SIZE;
/* Interface */
memcpy(buf, &intf_desc, USB_DT_INTERFACE_SIZE);
buf += USB_DT_INTERFACE_SIZE;
/* The endpoints in the interface (at that speed) */ #ifdef CONFIG_USB_GADGET_DUALSPEED
#ifdef HIGHSPEED
hs = (speed == USB_SPEED_HIGH);
if (type == USB_DT_OTHER_SPEED_CONFIG) if (type == USB_DT_OTHER_SPEED_CONFIG)
hs = !hs; speed = (USB_SPEED_FULL + USB_SPEED_HIGH) - speed;
if (hs) { if (speed == USB_SPEED_HIGH)
memcpy(buf, &hs_bulk_in_desc, USB_DT_ENDPOINT_SIZE); function = hs_function;
buf += USB_DT_ENDPOINT_SIZE; else
memcpy(buf, &hs_bulk_out_desc, USB_DT_ENDPOINT_SIZE);
buf += USB_DT_ENDPOINT_SIZE;
if (transport_is_cbi()) {
memcpy(buf, &hs_intr_in_desc, USB_DT_ENDPOINT_SIZE);
buf += USB_DT_ENDPOINT_SIZE;
}
} else
#endif #endif
{ function = fs_function;
memcpy(buf, &fs_bulk_in_desc, USB_DT_ENDPOINT_SIZE);
buf += USB_DT_ENDPOINT_SIZE;
memcpy(buf, &fs_bulk_out_desc, USB_DT_ENDPOINT_SIZE);
buf += USB_DT_ENDPOINT_SIZE;
if (transport_is_cbi()) {
memcpy(buf, &fs_intr_in_desc, USB_DT_ENDPOINT_SIZE);
buf += USB_DT_ENDPOINT_SIZE;
}
}
return buf - buf0; len = usb_gadget_config_buf(&config_desc, buf, EP0_BUFSIZE, function);
if (len < 0)
return len;
((struct usb_config_descriptor *) buf)->bDescriptorType = type;
return len;
} }
...@@ -1505,22 +1474,26 @@ static int standard_setup_req(struct fsg_dev *fsg, ...@@ -1505,22 +1474,26 @@ static int standard_setup_req(struct fsg_dev *fsg,
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:
VDBG(fsg, "get device qualifier\n"); VDBG(fsg, "get device qualifier\n");
if (!fsg->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:
VDBG(fsg, "get other-speed config descriptor\n"); VDBG(fsg, "get other-speed config descriptor\n");
if (!fsg->gadget->is_dualspeed)
break;
goto get_config; goto get_config;
#endif /* HIGHSPEED */ #endif
case USB_DT_CONFIG: case USB_DT_CONFIG:
VDBG(fsg, "get configuration descriptor\n"); VDBG(fsg, "get configuration descriptor\n");
#ifdef HIGHSPEED #ifdef CONFIG_USB_GADGET_DUALSPEED
get_config: get_config:
#endif /* HIGHSPEED */ #endif
value = populate_config_buf(fsg->gadget->speed, value = populate_config_buf(fsg->gadget->speed,
req->buf, req->buf,
ctrl->wValue >> 8, ctrl->wValue >> 8,
...@@ -3258,6 +3231,7 @@ static int do_set_interface(struct fsg_dev *fsg, int altsetting) ...@@ -3258,6 +3231,7 @@ static int do_set_interface(struct fsg_dev *fsg, int altsetting)
if ((rc = enable_endpoint(fsg, fsg->bulk_out, d)) != 0) if ((rc = enable_endpoint(fsg, fsg->bulk_out, d)) != 0)
goto reset; goto reset;
fsg->bulk_out_enabled = 1; fsg->bulk_out_enabled = 1;
fsg->bulk_out_maxpacket = d->wMaxPacketSize;
if (transport_is_cbi()) { if (transport_is_cbi()) {
d = ep_desc(fsg->gadget, &fs_intr_in_desc, &hs_intr_in_desc); d = ep_desc(fsg->gadget, &fs_intr_in_desc, &hs_intr_in_desc);
...@@ -3964,19 +3938,27 @@ static int __init fsg_bind(struct usb_gadget *gadget) ...@@ -3964,19 +3938,27 @@ static int __init fsg_bind(struct usb_gadget *gadget)
/* Fix up the descriptors */ /* Fix up the descriptors */
device_desc.bMaxPacketSize0 = fsg->ep0->maxpacket; device_desc.bMaxPacketSize0 = fsg->ep0->maxpacket;
#ifdef HIGHSPEED
dev_qualifier.bMaxPacketSize0 = fsg->ep0->maxpacket; // ???
#endif
device_desc.idVendor = cpu_to_le16(mod_data.vendor); device_desc.idVendor = cpu_to_le16(mod_data.vendor);
device_desc.idProduct = cpu_to_le16(mod_data.product); device_desc.idProduct = cpu_to_le16(mod_data.product);
device_desc.bcdDevice = cpu_to_le16(mod_data.release); device_desc.bcdDevice = cpu_to_le16(mod_data.release);
i = (transport_is_cbi() ? 3 : 2); // Number of endpoints i = (transport_is_cbi() ? 3 : 2); // Number of endpoints
config_desc.wTotalLength = USB_DT_CONFIG_SIZE + USB_DT_INTERFACE_SIZE
+ USB_DT_ENDPOINT_SIZE * i;
intf_desc.bNumEndpoints = i; intf_desc.bNumEndpoints = i;
intf_desc.bInterfaceSubClass = mod_data.protocol_type; intf_desc.bInterfaceSubClass = mod_data.protocol_type;
intf_desc.bInterfaceProtocol = mod_data.transport_type; intf_desc.bInterfaceProtocol = mod_data.transport_type;
fs_function[i+1] = NULL;
#ifdef CONFIG_USB_GADGET_DUALSPEED
hs_function[i+1] = NULL;
/* Assume ep0 uses the same maxpacket value for both speeds */
dev_qualifier.bMaxPacketSize0 = fsg->ep0->maxpacket;
/* Assume that all endpoint addresses are the same for both speeds */
hs_bulk_in_desc.bEndpointAddress = fs_bulk_in_desc.bEndpointAddress;
hs_bulk_out_desc.bEndpointAddress = fs_bulk_out_desc.bEndpointAddress;
hs_intr_in_desc.bEndpointAddress = fs_intr_in_desc.bEndpointAddress;
#endif
/* Find all the endpoints we will use */ /* Find all the endpoints we will use */
gadget_for_each_ep(ep, gadget) { gadget_for_each_ep(ep, gadget) {
...@@ -3993,8 +3975,6 @@ static int __init fsg_bind(struct usb_gadget *gadget) ...@@ -3993,8 +3975,6 @@ static int __init fsg_bind(struct usb_gadget *gadget)
rc = -ENOTSUPP; rc = -ENOTSUPP;
goto out; goto out;
} }
fsg->bulk_out_maxpacket = (gadget->speed == USB_SPEED_HIGH ? 512 :
FS_BULK_OUT_MAXPACKET);
rc = -ENOMEM; rc = -ENOMEM;
...@@ -4023,6 +4003,10 @@ static int __init fsg_bind(struct usb_gadget *gadget) ...@@ -4023,6 +4003,10 @@ static int __init fsg_bind(struct usb_gadget *gadget)
/* This should reflect the actual gadget power source */ /* This should reflect the actual gadget power source */
usb_gadget_set_selfpowered(gadget); usb_gadget_set_selfpowered(gadget);
snprintf(manufacturer, sizeof manufacturer,
UTS_SYSNAME " " UTS_RELEASE " with %s",
gadget->name);
/* On a real device, serial[] would be loaded from permanent /* On a real device, serial[] would be loaded from permanent
* storage. We just encode it from the driver version string. */ * storage. We just encode it from the driver version string. */
for (i = 0; i < sizeof(serial) - 2; i += 2) { for (i = 0; i < sizeof(serial) - 2; i += 2) {
...@@ -4082,7 +4066,7 @@ static int __init fsg_bind(struct usb_gadget *gadget) ...@@ -4082,7 +4066,7 @@ static int __init fsg_bind(struct usb_gadget *gadget)
/*-------------------------------------------------------------------------*/ /*-------------------------------------------------------------------------*/
static struct usb_gadget_driver fsg_driver = { static struct usb_gadget_driver fsg_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