| David Brownell | 40982be | 2008-06-19 17:52:58 -0700 | [diff] [blame] | 1 | /* | 
|  | 2 | * composite.c - infrastructure for Composite USB Gadgets | 
|  | 3 | * | 
|  | 4 | * Copyright (C) 2006-2008 David Brownell | 
|  | 5 | * | 
|  | 6 | * This program is free software; you can redistribute it and/or modify | 
|  | 7 | * it under the terms of the GNU General Public License as published by | 
|  | 8 | * the Free Software Foundation; either version 2 of the License, or | 
|  | 9 | * (at your option) any later version. | 
| David Brownell | 40982be | 2008-06-19 17:52:58 -0700 | [diff] [blame] | 10 | */ | 
|  | 11 |  | 
|  | 12 | /* #define VERBOSE_DEBUG */ | 
|  | 13 |  | 
|  | 14 | #include <linux/kallsyms.h> | 
|  | 15 | #include <linux/kernel.h> | 
|  | 16 | #include <linux/slab.h> | 
| Paul Gortmaker | 6eb0de8 | 2011-07-03 16:09:31 -0400 | [diff] [blame] | 17 | #include <linux/module.h> | 
| David Brownell | 40982be | 2008-06-19 17:52:58 -0700 | [diff] [blame] | 18 | #include <linux/device.h> | 
| Michal Nazarewicz | ad1a810 | 2010-08-12 17:43:46 +0200 | [diff] [blame] | 19 | #include <linux/utsname.h> | 
| David Brownell | 40982be | 2008-06-19 17:52:58 -0700 | [diff] [blame] | 20 |  | 
|  | 21 | #include <linux/usb/composite.h> | 
| Tatyana Brokhman | bdb64d7 | 2011-06-29 16:41:50 +0300 | [diff] [blame] | 22 | #include <asm/unaligned.h> | 
| David Brownell | 40982be | 2008-06-19 17:52:58 -0700 | [diff] [blame] | 23 |  | 
|  | 24 | /* | 
|  | 25 | * The code in this file is utility code, used to build a gadget driver | 
|  | 26 | * from one or more "function" drivers, one or more "configuration" | 
|  | 27 | * objects, and a "usb_composite_driver" by gluing them together along | 
|  | 28 | * with the relevant device-wide data. | 
|  | 29 | */ | 
|  | 30 |  | 
|  | 31 | /* big enough to hold our biggest descriptor */ | 
| Robert Lukassen | dd0543e | 2010-03-30 14:14:01 +0200 | [diff] [blame] | 32 | #define USB_BUFSIZ	1024 | 
| David Brownell | 40982be | 2008-06-19 17:52:58 -0700 | [diff] [blame] | 33 |  | 
|  | 34 | static struct usb_composite_driver *composite; | 
| Michal Nazarewicz | 07a18bd | 2010-08-12 17:43:54 +0200 | [diff] [blame] | 35 | static int (*composite_gadget_bind)(struct usb_composite_dev *cdev); | 
| David Brownell | 40982be | 2008-06-19 17:52:58 -0700 | [diff] [blame] | 36 |  | 
| Lucas De Marchi | 25985ed | 2011-03-30 22:57:33 -0300 | [diff] [blame] | 37 | /* Some systems will need runtime overrides for the  product identifiers | 
| David Brownell | 40982be | 2008-06-19 17:52:58 -0700 | [diff] [blame] | 38 | * published in the device descriptor, either numbers or strings or both. | 
|  | 39 | * String parameters are in UTF-8 (superset of ASCII's 7 bit characters). | 
|  | 40 | */ | 
|  | 41 |  | 
|  | 42 | static ushort idVendor; | 
|  | 43 | module_param(idVendor, ushort, 0); | 
|  | 44 | MODULE_PARM_DESC(idVendor, "USB Vendor ID"); | 
|  | 45 |  | 
|  | 46 | static ushort idProduct; | 
|  | 47 | module_param(idProduct, ushort, 0); | 
|  | 48 | MODULE_PARM_DESC(idProduct, "USB Product ID"); | 
|  | 49 |  | 
|  | 50 | static ushort bcdDevice; | 
|  | 51 | module_param(bcdDevice, ushort, 0); | 
|  | 52 | MODULE_PARM_DESC(bcdDevice, "USB Device version (BCD)"); | 
|  | 53 |  | 
|  | 54 | static char *iManufacturer; | 
|  | 55 | module_param(iManufacturer, charp, 0); | 
|  | 56 | MODULE_PARM_DESC(iManufacturer, "USB Manufacturer string"); | 
|  | 57 |  | 
|  | 58 | static char *iProduct; | 
|  | 59 | module_param(iProduct, charp, 0); | 
|  | 60 | MODULE_PARM_DESC(iProduct, "USB Product string"); | 
|  | 61 |  | 
|  | 62 | static char *iSerialNumber; | 
|  | 63 | module_param(iSerialNumber, charp, 0); | 
|  | 64 | MODULE_PARM_DESC(iSerialNumber, "SerialNumber string"); | 
|  | 65 |  | 
| Michal Nazarewicz | ad1a810 | 2010-08-12 17:43:46 +0200 | [diff] [blame] | 66 | static char composite_manufacturer[50]; | 
|  | 67 |  | 
| David Brownell | 40982be | 2008-06-19 17:52:58 -0700 | [diff] [blame] | 68 | /*-------------------------------------------------------------------------*/ | 
| Tatyana Brokhman | 48767a4 | 2011-06-28 16:33:49 +0300 | [diff] [blame] | 69 | /** | 
|  | 70 | * next_ep_desc() - advance to the next EP descriptor | 
|  | 71 | * @t: currect pointer within descriptor array | 
|  | 72 | * | 
|  | 73 | * Return: next EP descriptor or NULL | 
|  | 74 | * | 
|  | 75 | * Iterate over @t until either EP descriptor found or | 
|  | 76 | * NULL (that indicates end of list) encountered | 
|  | 77 | */ | 
|  | 78 | static struct usb_descriptor_header** | 
|  | 79 | next_ep_desc(struct usb_descriptor_header **t) | 
|  | 80 | { | 
|  | 81 | for (; *t; t++) { | 
|  | 82 | if ((*t)->bDescriptorType == USB_DT_ENDPOINT) | 
|  | 83 | return t; | 
|  | 84 | } | 
|  | 85 | return NULL; | 
|  | 86 | } | 
|  | 87 |  | 
|  | 88 | /* | 
|  | 89 | * for_each_ep_desc()- iterate over endpoint descriptors in the | 
|  | 90 | *		descriptors list | 
|  | 91 | * @start:	pointer within descriptor array. | 
|  | 92 | * @ep_desc:	endpoint descriptor to use as the loop cursor | 
|  | 93 | */ | 
|  | 94 | #define for_each_ep_desc(start, ep_desc) \ | 
|  | 95 | for (ep_desc = next_ep_desc(start); \ | 
|  | 96 | ep_desc; ep_desc = next_ep_desc(ep_desc+1)) | 
|  | 97 |  | 
|  | 98 | /** | 
|  | 99 | * config_ep_by_speed() - configures the given endpoint | 
|  | 100 | * according to gadget speed. | 
|  | 101 | * @g: pointer to the gadget | 
|  | 102 | * @f: usb function | 
|  | 103 | * @_ep: the endpoint to configure | 
|  | 104 | * | 
|  | 105 | * Return: error code, 0 on success | 
|  | 106 | * | 
|  | 107 | * This function chooses the right descriptors for a given | 
|  | 108 | * endpoint according to gadget speed and saves it in the | 
|  | 109 | * endpoint desc field. If the endpoint already has a descriptor | 
|  | 110 | * assigned to it - overwrites it with currently corresponding | 
|  | 111 | * descriptor. The endpoint maxpacket field is updated according | 
|  | 112 | * to the chosen descriptor. | 
|  | 113 | * Note: the supplied function should hold all the descriptors | 
|  | 114 | * for supported speeds | 
|  | 115 | */ | 
|  | 116 | int config_ep_by_speed(struct usb_gadget *g, | 
|  | 117 | struct usb_function *f, | 
|  | 118 | struct usb_ep *_ep) | 
|  | 119 | { | 
|  | 120 | struct usb_endpoint_descriptor *chosen_desc = NULL; | 
|  | 121 | struct usb_descriptor_header **speed_desc = NULL; | 
|  | 122 |  | 
| Tatyana Brokhman | bdb64d7 | 2011-06-29 16:41:50 +0300 | [diff] [blame] | 123 | struct usb_ss_ep_comp_descriptor *comp_desc = NULL; | 
|  | 124 | int want_comp_desc = 0; | 
|  | 125 |  | 
| Tatyana Brokhman | 48767a4 | 2011-06-28 16:33:49 +0300 | [diff] [blame] | 126 | struct usb_descriptor_header **d_spd; /* cursor for speed desc */ | 
|  | 127 |  | 
|  | 128 | if (!g || !f || !_ep) | 
|  | 129 | return -EIO; | 
|  | 130 |  | 
|  | 131 | /* select desired speed */ | 
|  | 132 | switch (g->speed) { | 
| Tatyana Brokhman | bdb64d7 | 2011-06-29 16:41:50 +0300 | [diff] [blame] | 133 | case USB_SPEED_SUPER: | 
|  | 134 | if (gadget_is_superspeed(g)) { | 
|  | 135 | speed_desc = f->ss_descriptors; | 
|  | 136 | want_comp_desc = 1; | 
|  | 137 | break; | 
|  | 138 | } | 
|  | 139 | /* else: Fall trough */ | 
| Tatyana Brokhman | 48767a4 | 2011-06-28 16:33:49 +0300 | [diff] [blame] | 140 | case USB_SPEED_HIGH: | 
|  | 141 | if (gadget_is_dualspeed(g)) { | 
|  | 142 | speed_desc = f->hs_descriptors; | 
|  | 143 | break; | 
|  | 144 | } | 
|  | 145 | /* else: fall through */ | 
|  | 146 | default: | 
|  | 147 | speed_desc = f->descriptors; | 
|  | 148 | } | 
|  | 149 | /* find descriptors */ | 
|  | 150 | for_each_ep_desc(speed_desc, d_spd) { | 
|  | 151 | chosen_desc = (struct usb_endpoint_descriptor *)*d_spd; | 
|  | 152 | if (chosen_desc->bEndpointAddress == _ep->address) | 
|  | 153 | goto ep_found; | 
|  | 154 | } | 
|  | 155 | return -EIO; | 
|  | 156 |  | 
|  | 157 | ep_found: | 
|  | 158 | /* commit results */ | 
| Kuninori Morimoto | 29cc889 | 2011-08-23 03:12:03 -0700 | [diff] [blame] | 159 | _ep->maxpacket = usb_endpoint_maxp(chosen_desc); | 
| Tatyana Brokhman | 48767a4 | 2011-06-28 16:33:49 +0300 | [diff] [blame] | 160 | _ep->desc = chosen_desc; | 
| Tatyana Brokhman | bdb64d7 | 2011-06-29 16:41:50 +0300 | [diff] [blame] | 161 | _ep->comp_desc = NULL; | 
|  | 162 | _ep->maxburst = 0; | 
|  | 163 | _ep->mult = 0; | 
|  | 164 | if (!want_comp_desc) | 
|  | 165 | return 0; | 
| Tatyana Brokhman | 48767a4 | 2011-06-28 16:33:49 +0300 | [diff] [blame] | 166 |  | 
| Tatyana Brokhman | bdb64d7 | 2011-06-29 16:41:50 +0300 | [diff] [blame] | 167 | /* | 
|  | 168 | * Companion descriptor should follow EP descriptor | 
|  | 169 | * USB 3.0 spec, #9.6.7 | 
|  | 170 | */ | 
|  | 171 | comp_desc = (struct usb_ss_ep_comp_descriptor *)*(++d_spd); | 
|  | 172 | if (!comp_desc || | 
|  | 173 | (comp_desc->bDescriptorType != USB_DT_SS_ENDPOINT_COMP)) | 
|  | 174 | return -EIO; | 
|  | 175 | _ep->comp_desc = comp_desc; | 
|  | 176 | if (g->speed == USB_SPEED_SUPER) { | 
|  | 177 | switch (usb_endpoint_type(_ep->desc)) { | 
|  | 178 | case USB_ENDPOINT_XFER_BULK: | 
|  | 179 | case USB_ENDPOINT_XFER_INT: | 
|  | 180 | _ep->maxburst = comp_desc->bMaxBurst; | 
|  | 181 | break; | 
|  | 182 | case USB_ENDPOINT_XFER_ISOC: | 
|  | 183 | /* mult: bits 1:0 of bmAttributes */ | 
|  | 184 | _ep->mult = comp_desc->bmAttributes & 0x3; | 
|  | 185 | break; | 
|  | 186 | default: | 
|  | 187 | /* Do nothing for control endpoints */ | 
|  | 188 | break; | 
|  | 189 | } | 
|  | 190 | } | 
| Tatyana Brokhman | 48767a4 | 2011-06-28 16:33:49 +0300 | [diff] [blame] | 191 | return 0; | 
|  | 192 | } | 
| David Brownell | 40982be | 2008-06-19 17:52:58 -0700 | [diff] [blame] | 193 |  | 
|  | 194 | /** | 
|  | 195 | * usb_add_function() - add a function to a configuration | 
|  | 196 | * @config: the configuration | 
|  | 197 | * @function: the function being added | 
|  | 198 | * Context: single threaded during gadget setup | 
|  | 199 | * | 
|  | 200 | * After initialization, each configuration must have one or more | 
|  | 201 | * functions added to it.  Adding a function involves calling its @bind() | 
|  | 202 | * method to allocate resources such as interface and string identifiers | 
|  | 203 | * and endpoints. | 
|  | 204 | * | 
|  | 205 | * This function returns the value of the function's bind(), which is | 
|  | 206 | * zero for success else a negative errno value. | 
|  | 207 | */ | 
| Michal Nazarewicz | 28824b1 | 2010-05-05 12:53:13 +0200 | [diff] [blame] | 208 | int usb_add_function(struct usb_configuration *config, | 
| David Brownell | 40982be | 2008-06-19 17:52:58 -0700 | [diff] [blame] | 209 | struct usb_function *function) | 
|  | 210 | { | 
|  | 211 | int	value = -EINVAL; | 
|  | 212 |  | 
|  | 213 | DBG(config->cdev, "adding '%s'/%p to config '%s'/%p\n", | 
|  | 214 | function->name, function, | 
|  | 215 | config->label, config); | 
|  | 216 |  | 
|  | 217 | if (!function->set_alt || !function->disable) | 
|  | 218 | goto done; | 
|  | 219 |  | 
|  | 220 | function->config = config; | 
|  | 221 | list_add_tail(&function->list, &config->functions); | 
|  | 222 |  | 
|  | 223 | /* REVISIT *require* function->bind? */ | 
|  | 224 | if (function->bind) { | 
|  | 225 | value = function->bind(config, function); | 
|  | 226 | if (value < 0) { | 
|  | 227 | list_del(&function->list); | 
|  | 228 | function->config = NULL; | 
|  | 229 | } | 
|  | 230 | } else | 
|  | 231 | value = 0; | 
|  | 232 |  | 
|  | 233 | /* We allow configurations that don't work at both speeds. | 
|  | 234 | * If we run into a lowspeed Linux system, treat it the same | 
|  | 235 | * as full speed ... it's the function drivers that will need | 
|  | 236 | * to avoid bulk and ISO transfers. | 
|  | 237 | */ | 
|  | 238 | if (!config->fullspeed && function->descriptors) | 
|  | 239 | config->fullspeed = true; | 
|  | 240 | if (!config->highspeed && function->hs_descriptors) | 
|  | 241 | config->highspeed = true; | 
| Tatyana Brokhman | bdb64d7 | 2011-06-29 16:41:50 +0300 | [diff] [blame] | 242 | if (!config->superspeed && function->ss_descriptors) | 
|  | 243 | config->superspeed = true; | 
| David Brownell | 40982be | 2008-06-19 17:52:58 -0700 | [diff] [blame] | 244 |  | 
|  | 245 | done: | 
|  | 246 | if (value) | 
|  | 247 | DBG(config->cdev, "adding '%s'/%p --> %d\n", | 
|  | 248 | function->name, function, value); | 
|  | 249 | return value; | 
|  | 250 | } | 
|  | 251 |  | 
|  | 252 | /** | 
| David Brownell | 60beed9 | 2008-08-18 17:38:22 -0700 | [diff] [blame] | 253 | * usb_function_deactivate - prevent function and gadget enumeration | 
|  | 254 | * @function: the function that isn't yet ready to respond | 
|  | 255 | * | 
|  | 256 | * Blocks response of the gadget driver to host enumeration by | 
|  | 257 | * preventing the data line pullup from being activated.  This is | 
|  | 258 | * normally called during @bind() processing to change from the | 
|  | 259 | * initial "ready to respond" state, or when a required resource | 
|  | 260 | * becomes available. | 
|  | 261 | * | 
|  | 262 | * For example, drivers that serve as a passthrough to a userspace | 
|  | 263 | * daemon can block enumeration unless that daemon (such as an OBEX, | 
|  | 264 | * MTP, or print server) is ready to handle host requests. | 
|  | 265 | * | 
|  | 266 | * Not all systems support software control of their USB peripheral | 
|  | 267 | * data pullups. | 
|  | 268 | * | 
|  | 269 | * Returns zero on success, else negative errno. | 
|  | 270 | */ | 
|  | 271 | int usb_function_deactivate(struct usb_function *function) | 
|  | 272 | { | 
|  | 273 | struct usb_composite_dev	*cdev = function->config->cdev; | 
| Felipe Balbi | b2bdf3a | 2009-02-12 15:09:47 +0200 | [diff] [blame] | 274 | unsigned long			flags; | 
| David Brownell | 60beed9 | 2008-08-18 17:38:22 -0700 | [diff] [blame] | 275 | int				status = 0; | 
|  | 276 |  | 
| Felipe Balbi | b2bdf3a | 2009-02-12 15:09:47 +0200 | [diff] [blame] | 277 | spin_lock_irqsave(&cdev->lock, flags); | 
| David Brownell | 60beed9 | 2008-08-18 17:38:22 -0700 | [diff] [blame] | 278 |  | 
|  | 279 | if (cdev->deactivations == 0) | 
|  | 280 | status = usb_gadget_disconnect(cdev->gadget); | 
|  | 281 | if (status == 0) | 
|  | 282 | cdev->deactivations++; | 
|  | 283 |  | 
| Felipe Balbi | b2bdf3a | 2009-02-12 15:09:47 +0200 | [diff] [blame] | 284 | spin_unlock_irqrestore(&cdev->lock, flags); | 
| David Brownell | 60beed9 | 2008-08-18 17:38:22 -0700 | [diff] [blame] | 285 | return status; | 
|  | 286 | } | 
|  | 287 |  | 
|  | 288 | /** | 
|  | 289 | * usb_function_activate - allow function and gadget enumeration | 
|  | 290 | * @function: function on which usb_function_activate() was called | 
|  | 291 | * | 
|  | 292 | * Reverses effect of usb_function_deactivate().  If no more functions | 
|  | 293 | * are delaying their activation, the gadget driver will respond to | 
|  | 294 | * host enumeration procedures. | 
|  | 295 | * | 
|  | 296 | * Returns zero on success, else negative errno. | 
|  | 297 | */ | 
|  | 298 | int usb_function_activate(struct usb_function *function) | 
|  | 299 | { | 
|  | 300 | struct usb_composite_dev	*cdev = function->config->cdev; | 
|  | 301 | int				status = 0; | 
|  | 302 |  | 
|  | 303 | spin_lock(&cdev->lock); | 
|  | 304 |  | 
|  | 305 | if (WARN_ON(cdev->deactivations == 0)) | 
|  | 306 | status = -EINVAL; | 
|  | 307 | else { | 
|  | 308 | cdev->deactivations--; | 
|  | 309 | if (cdev->deactivations == 0) | 
|  | 310 | status = usb_gadget_connect(cdev->gadget); | 
|  | 311 | } | 
|  | 312 |  | 
|  | 313 | spin_unlock(&cdev->lock); | 
|  | 314 | return status; | 
|  | 315 | } | 
|  | 316 |  | 
|  | 317 | /** | 
| David Brownell | 40982be | 2008-06-19 17:52:58 -0700 | [diff] [blame] | 318 | * usb_interface_id() - allocate an unused interface ID | 
|  | 319 | * @config: configuration associated with the interface | 
|  | 320 | * @function: function handling the interface | 
|  | 321 | * Context: single threaded during gadget setup | 
|  | 322 | * | 
|  | 323 | * usb_interface_id() is called from usb_function.bind() callbacks to | 
|  | 324 | * allocate new interface IDs.  The function driver will then store that | 
|  | 325 | * ID in interface, association, CDC union, and other descriptors.  It | 
| Lucas De Marchi | 25985ed | 2011-03-30 22:57:33 -0300 | [diff] [blame] | 326 | * will also handle any control requests targeted at that interface, | 
| David Brownell | 40982be | 2008-06-19 17:52:58 -0700 | [diff] [blame] | 327 | * particularly changing its altsetting via set_alt().  There may | 
|  | 328 | * also be class-specific or vendor-specific requests to handle. | 
|  | 329 | * | 
|  | 330 | * All interface identifier should be allocated using this routine, to | 
|  | 331 | * ensure that for example different functions don't wrongly assign | 
|  | 332 | * different meanings to the same identifier.  Note that since interface | 
| Lucas De Marchi | 25985ed | 2011-03-30 22:57:33 -0300 | [diff] [blame] | 333 | * identifiers are configuration-specific, functions used in more than | 
| David Brownell | 40982be | 2008-06-19 17:52:58 -0700 | [diff] [blame] | 334 | * one configuration (or more than once in a given configuration) need | 
|  | 335 | * multiple versions of the relevant descriptors. | 
|  | 336 | * | 
|  | 337 | * Returns the interface ID which was allocated; or -ENODEV if no | 
|  | 338 | * more interface IDs can be allocated. | 
|  | 339 | */ | 
| Michal Nazarewicz | 28824b1 | 2010-05-05 12:53:13 +0200 | [diff] [blame] | 340 | int usb_interface_id(struct usb_configuration *config, | 
| David Brownell | 40982be | 2008-06-19 17:52:58 -0700 | [diff] [blame] | 341 | struct usb_function *function) | 
|  | 342 | { | 
|  | 343 | unsigned id = config->next_interface_id; | 
|  | 344 |  | 
|  | 345 | if (id < MAX_CONFIG_INTERFACES) { | 
|  | 346 | config->interface[id] = function; | 
|  | 347 | config->next_interface_id = id + 1; | 
|  | 348 | return id; | 
|  | 349 | } | 
|  | 350 | return -ENODEV; | 
|  | 351 | } | 
|  | 352 |  | 
|  | 353 | static int config_buf(struct usb_configuration *config, | 
|  | 354 | enum usb_device_speed speed, void *buf, u8 type) | 
|  | 355 | { | 
|  | 356 | struct usb_config_descriptor	*c = buf; | 
|  | 357 | void				*next = buf + USB_DT_CONFIG_SIZE; | 
|  | 358 | int				len = USB_BUFSIZ - USB_DT_CONFIG_SIZE; | 
|  | 359 | struct usb_function		*f; | 
|  | 360 | int				status; | 
|  | 361 |  | 
|  | 362 | /* write the config descriptor */ | 
|  | 363 | c = buf; | 
|  | 364 | c->bLength = USB_DT_CONFIG_SIZE; | 
|  | 365 | c->bDescriptorType = type; | 
|  | 366 | /* wTotalLength is written later */ | 
|  | 367 | c->bNumInterfaces = config->next_interface_id; | 
|  | 368 | c->bConfigurationValue = config->bConfigurationValue; | 
|  | 369 | c->iConfiguration = config->iConfiguration; | 
|  | 370 | c->bmAttributes = USB_CONFIG_ATT_ONE | config->bmAttributes; | 
| David Brownell | 36e893d | 2008-09-12 09:39:06 -0700 | [diff] [blame] | 371 | c->bMaxPower = config->bMaxPower ? : (CONFIG_USB_GADGET_VBUS_DRAW / 2); | 
| David Brownell | 40982be | 2008-06-19 17:52:58 -0700 | [diff] [blame] | 372 |  | 
|  | 373 | /* There may be e.g. OTG descriptors */ | 
|  | 374 | if (config->descriptors) { | 
|  | 375 | status = usb_descriptor_fillbuf(next, len, | 
|  | 376 | config->descriptors); | 
|  | 377 | if (status < 0) | 
|  | 378 | return status; | 
|  | 379 | len -= status; | 
|  | 380 | next += status; | 
|  | 381 | } | 
|  | 382 |  | 
|  | 383 | /* add each function's descriptors */ | 
|  | 384 | list_for_each_entry(f, &config->functions, list) { | 
|  | 385 | struct usb_descriptor_header **descriptors; | 
|  | 386 |  | 
| Tatyana Brokhman | bdb64d7 | 2011-06-29 16:41:50 +0300 | [diff] [blame] | 387 | switch (speed) { | 
|  | 388 | case USB_SPEED_SUPER: | 
|  | 389 | descriptors = f->ss_descriptors; | 
|  | 390 | break; | 
|  | 391 | case USB_SPEED_HIGH: | 
| David Brownell | 40982be | 2008-06-19 17:52:58 -0700 | [diff] [blame] | 392 | descriptors = f->hs_descriptors; | 
| Tatyana Brokhman | bdb64d7 | 2011-06-29 16:41:50 +0300 | [diff] [blame] | 393 | break; | 
|  | 394 | default: | 
| David Brownell | 40982be | 2008-06-19 17:52:58 -0700 | [diff] [blame] | 395 | descriptors = f->descriptors; | 
| Tatyana Brokhman | bdb64d7 | 2011-06-29 16:41:50 +0300 | [diff] [blame] | 396 | } | 
|  | 397 |  | 
| David Brownell | 40982be | 2008-06-19 17:52:58 -0700 | [diff] [blame] | 398 | if (!descriptors) | 
|  | 399 | continue; | 
|  | 400 | status = usb_descriptor_fillbuf(next, len, | 
|  | 401 | (const struct usb_descriptor_header **) descriptors); | 
|  | 402 | if (status < 0) | 
|  | 403 | return status; | 
|  | 404 | len -= status; | 
|  | 405 | next += status; | 
|  | 406 | } | 
|  | 407 |  | 
|  | 408 | len = next - buf; | 
|  | 409 | c->wTotalLength = cpu_to_le16(len); | 
|  | 410 | return len; | 
|  | 411 | } | 
|  | 412 |  | 
|  | 413 | static int config_desc(struct usb_composite_dev *cdev, unsigned w_value) | 
|  | 414 | { | 
|  | 415 | struct usb_gadget		*gadget = cdev->gadget; | 
|  | 416 | struct usb_configuration	*c; | 
|  | 417 | u8				type = w_value >> 8; | 
|  | 418 | enum usb_device_speed		speed = USB_SPEED_UNKNOWN; | 
|  | 419 |  | 
| Tatyana Brokhman | bdb64d7 | 2011-06-29 16:41:50 +0300 | [diff] [blame] | 420 | if (gadget->speed == USB_SPEED_SUPER) | 
|  | 421 | speed = gadget->speed; | 
|  | 422 | else if (gadget_is_dualspeed(gadget)) { | 
|  | 423 | int	hs = 0; | 
| David Brownell | 40982be | 2008-06-19 17:52:58 -0700 | [diff] [blame] | 424 | if (gadget->speed == USB_SPEED_HIGH) | 
|  | 425 | hs = 1; | 
|  | 426 | if (type == USB_DT_OTHER_SPEED_CONFIG) | 
|  | 427 | hs = !hs; | 
|  | 428 | if (hs) | 
|  | 429 | speed = USB_SPEED_HIGH; | 
|  | 430 |  | 
|  | 431 | } | 
|  | 432 |  | 
|  | 433 | /* This is a lookup by config *INDEX* */ | 
|  | 434 | w_value &= 0xff; | 
|  | 435 | list_for_each_entry(c, &cdev->configs, list) { | 
|  | 436 | /* ignore configs that won't work at this speed */ | 
| Tatyana Brokhman | bdb64d7 | 2011-06-29 16:41:50 +0300 | [diff] [blame] | 437 | switch (speed) { | 
|  | 438 | case USB_SPEED_SUPER: | 
|  | 439 | if (!c->superspeed) | 
|  | 440 | continue; | 
|  | 441 | break; | 
|  | 442 | case USB_SPEED_HIGH: | 
| David Brownell | 40982be | 2008-06-19 17:52:58 -0700 | [diff] [blame] | 443 | if (!c->highspeed) | 
|  | 444 | continue; | 
| Tatyana Brokhman | bdb64d7 | 2011-06-29 16:41:50 +0300 | [diff] [blame] | 445 | break; | 
|  | 446 | default: | 
| David Brownell | 40982be | 2008-06-19 17:52:58 -0700 | [diff] [blame] | 447 | if (!c->fullspeed) | 
|  | 448 | continue; | 
|  | 449 | } | 
| Tatyana Brokhman | bdb64d7 | 2011-06-29 16:41:50 +0300 | [diff] [blame] | 450 |  | 
| David Brownell | 40982be | 2008-06-19 17:52:58 -0700 | [diff] [blame] | 451 | if (w_value == 0) | 
|  | 452 | return config_buf(c, speed, cdev->req->buf, type); | 
|  | 453 | w_value--; | 
|  | 454 | } | 
|  | 455 | return -EINVAL; | 
|  | 456 | } | 
|  | 457 |  | 
|  | 458 | static int count_configs(struct usb_composite_dev *cdev, unsigned type) | 
|  | 459 | { | 
|  | 460 | struct usb_gadget		*gadget = cdev->gadget; | 
|  | 461 | struct usb_configuration	*c; | 
|  | 462 | unsigned			count = 0; | 
|  | 463 | int				hs = 0; | 
| Tatyana Brokhman | bdb64d7 | 2011-06-29 16:41:50 +0300 | [diff] [blame] | 464 | int				ss = 0; | 
| David Brownell | 40982be | 2008-06-19 17:52:58 -0700 | [diff] [blame] | 465 |  | 
|  | 466 | if (gadget_is_dualspeed(gadget)) { | 
|  | 467 | if (gadget->speed == USB_SPEED_HIGH) | 
|  | 468 | hs = 1; | 
| Tatyana Brokhman | bdb64d7 | 2011-06-29 16:41:50 +0300 | [diff] [blame] | 469 | if (gadget->speed == USB_SPEED_SUPER) | 
|  | 470 | ss = 1; | 
| David Brownell | 40982be | 2008-06-19 17:52:58 -0700 | [diff] [blame] | 471 | if (type == USB_DT_DEVICE_QUALIFIER) | 
|  | 472 | hs = !hs; | 
|  | 473 | } | 
|  | 474 | list_for_each_entry(c, &cdev->configs, list) { | 
|  | 475 | /* ignore configs that won't work at this speed */ | 
| Tatyana Brokhman | bdb64d7 | 2011-06-29 16:41:50 +0300 | [diff] [blame] | 476 | if (ss) { | 
|  | 477 | if (!c->superspeed) | 
|  | 478 | continue; | 
|  | 479 | } else if (hs) { | 
| David Brownell | 40982be | 2008-06-19 17:52:58 -0700 | [diff] [blame] | 480 | if (!c->highspeed) | 
|  | 481 | continue; | 
|  | 482 | } else { | 
|  | 483 | if (!c->fullspeed) | 
|  | 484 | continue; | 
|  | 485 | } | 
|  | 486 | count++; | 
|  | 487 | } | 
|  | 488 | return count; | 
|  | 489 | } | 
|  | 490 |  | 
| Tatyana Brokhman | bdb64d7 | 2011-06-29 16:41:50 +0300 | [diff] [blame] | 491 | /** | 
|  | 492 | * bos_desc() - prepares the BOS descriptor. | 
|  | 493 | * @cdev: pointer to usb_composite device to generate the bos | 
|  | 494 | *	descriptor for | 
|  | 495 | * | 
|  | 496 | * This function generates the BOS (Binary Device Object) | 
|  | 497 | * descriptor and its device capabilities descriptors. The BOS | 
|  | 498 | * descriptor should be supported by a SuperSpeed device. | 
|  | 499 | */ | 
|  | 500 | static int bos_desc(struct usb_composite_dev *cdev) | 
|  | 501 | { | 
|  | 502 | struct usb_ext_cap_descriptor	*usb_ext; | 
|  | 503 | struct usb_ss_cap_descriptor	*ss_cap; | 
|  | 504 | struct usb_dcd_config_params	dcd_config_params; | 
|  | 505 | struct usb_bos_descriptor	*bos = cdev->req->buf; | 
|  | 506 |  | 
|  | 507 | bos->bLength = USB_DT_BOS_SIZE; | 
|  | 508 | bos->bDescriptorType = USB_DT_BOS; | 
|  | 509 |  | 
|  | 510 | bos->wTotalLength = cpu_to_le16(USB_DT_BOS_SIZE); | 
|  | 511 | bos->bNumDeviceCaps = 0; | 
|  | 512 |  | 
|  | 513 | /* | 
|  | 514 | * A SuperSpeed device shall include the USB2.0 extension descriptor | 
|  | 515 | * and shall support LPM when operating in USB2.0 HS mode. | 
|  | 516 | */ | 
|  | 517 | usb_ext = cdev->req->buf + le16_to_cpu(bos->wTotalLength); | 
|  | 518 | bos->bNumDeviceCaps++; | 
|  | 519 | le16_add_cpu(&bos->wTotalLength, USB_DT_USB_EXT_CAP_SIZE); | 
|  | 520 | usb_ext->bLength = USB_DT_USB_EXT_CAP_SIZE; | 
|  | 521 | usb_ext->bDescriptorType = USB_DT_DEVICE_CAPABILITY; | 
|  | 522 | usb_ext->bDevCapabilityType = USB_CAP_TYPE_EXT; | 
|  | 523 | usb_ext->bmAttributes = cpu_to_le32(USB_LPM_SUPPORT); | 
|  | 524 |  | 
|  | 525 | /* | 
|  | 526 | * The Superspeed USB Capability descriptor shall be implemented by all | 
|  | 527 | * SuperSpeed devices. | 
|  | 528 | */ | 
|  | 529 | ss_cap = cdev->req->buf + le16_to_cpu(bos->wTotalLength); | 
|  | 530 | bos->bNumDeviceCaps++; | 
|  | 531 | le16_add_cpu(&bos->wTotalLength, USB_DT_USB_SS_CAP_SIZE); | 
|  | 532 | ss_cap->bLength = USB_DT_USB_SS_CAP_SIZE; | 
|  | 533 | ss_cap->bDescriptorType = USB_DT_DEVICE_CAPABILITY; | 
|  | 534 | ss_cap->bDevCapabilityType = USB_SS_CAP_TYPE; | 
|  | 535 | ss_cap->bmAttributes = 0; /* LTM is not supported yet */ | 
|  | 536 | ss_cap->wSpeedSupported = cpu_to_le16(USB_LOW_SPEED_OPERATION | | 
|  | 537 | USB_FULL_SPEED_OPERATION | | 
|  | 538 | USB_HIGH_SPEED_OPERATION | | 
|  | 539 | USB_5GBPS_OPERATION); | 
|  | 540 | ss_cap->bFunctionalitySupport = USB_LOW_SPEED_OPERATION; | 
|  | 541 |  | 
|  | 542 | /* Get Controller configuration */ | 
|  | 543 | if (cdev->gadget->ops->get_config_params) | 
|  | 544 | cdev->gadget->ops->get_config_params(&dcd_config_params); | 
|  | 545 | else { | 
| Felipe Balbi | 089b837 | 2011-10-10 09:43:44 +0300 | [diff] [blame] | 546 | dcd_config_params.bU1devExitLat = USB_DEFAULT_U1_DEV_EXIT_LAT; | 
| Tatyana Brokhman | bdb64d7 | 2011-06-29 16:41:50 +0300 | [diff] [blame] | 547 | dcd_config_params.bU2DevExitLat = | 
| Felipe Balbi | 089b837 | 2011-10-10 09:43:44 +0300 | [diff] [blame] | 548 | cpu_to_le16(USB_DEFAULT_U2_DEV_EXIT_LAT); | 
| Tatyana Brokhman | bdb64d7 | 2011-06-29 16:41:50 +0300 | [diff] [blame] | 549 | } | 
|  | 550 | ss_cap->bU1devExitLat = dcd_config_params.bU1devExitLat; | 
|  | 551 | ss_cap->bU2DevExitLat = dcd_config_params.bU2DevExitLat; | 
|  | 552 |  | 
|  | 553 | return le16_to_cpu(bos->wTotalLength); | 
|  | 554 | } | 
|  | 555 |  | 
| David Brownell | 40982be | 2008-06-19 17:52:58 -0700 | [diff] [blame] | 556 | static void device_qual(struct usb_composite_dev *cdev) | 
|  | 557 | { | 
|  | 558 | struct usb_qualifier_descriptor	*qual = cdev->req->buf; | 
|  | 559 |  | 
|  | 560 | qual->bLength = sizeof(*qual); | 
|  | 561 | qual->bDescriptorType = USB_DT_DEVICE_QUALIFIER; | 
|  | 562 | /* POLICY: same bcdUSB and device type info at both speeds */ | 
|  | 563 | qual->bcdUSB = cdev->desc.bcdUSB; | 
|  | 564 | qual->bDeviceClass = cdev->desc.bDeviceClass; | 
|  | 565 | qual->bDeviceSubClass = cdev->desc.bDeviceSubClass; | 
|  | 566 | qual->bDeviceProtocol = cdev->desc.bDeviceProtocol; | 
|  | 567 | /* ASSUME same EP0 fifo size at both speeds */ | 
| Sebastian Andrzej Siewior | 765f5b8 | 2011-06-23 14:26:11 +0200 | [diff] [blame] | 568 | qual->bMaxPacketSize0 = cdev->gadget->ep0->maxpacket; | 
| David Brownell | 40982be | 2008-06-19 17:52:58 -0700 | [diff] [blame] | 569 | qual->bNumConfigurations = count_configs(cdev, USB_DT_DEVICE_QUALIFIER); | 
| David Lopo | c24f422 | 2008-07-01 13:14:17 -0700 | [diff] [blame] | 570 | qual->bRESERVED = 0; | 
| David Brownell | 40982be | 2008-06-19 17:52:58 -0700 | [diff] [blame] | 571 | } | 
|  | 572 |  | 
|  | 573 | /*-------------------------------------------------------------------------*/ | 
|  | 574 |  | 
|  | 575 | static void reset_config(struct usb_composite_dev *cdev) | 
|  | 576 | { | 
|  | 577 | struct usb_function		*f; | 
|  | 578 |  | 
|  | 579 | DBG(cdev, "reset config\n"); | 
|  | 580 |  | 
|  | 581 | list_for_each_entry(f, &cdev->config->functions, list) { | 
|  | 582 | if (f->disable) | 
|  | 583 | f->disable(f); | 
| Laurent Pinchart | 5242658 | 2009-10-21 00:03:38 +0200 | [diff] [blame] | 584 |  | 
|  | 585 | bitmap_zero(f->endpoints, 32); | 
| David Brownell | 40982be | 2008-06-19 17:52:58 -0700 | [diff] [blame] | 586 | } | 
|  | 587 | cdev->config = NULL; | 
|  | 588 | } | 
|  | 589 |  | 
|  | 590 | static int set_config(struct usb_composite_dev *cdev, | 
|  | 591 | const struct usb_ctrlrequest *ctrl, unsigned number) | 
|  | 592 | { | 
|  | 593 | struct usb_gadget	*gadget = cdev->gadget; | 
|  | 594 | struct usb_configuration *c = NULL; | 
|  | 595 | int			result = -EINVAL; | 
|  | 596 | unsigned		power = gadget_is_otg(gadget) ? 8 : 100; | 
|  | 597 | int			tmp; | 
|  | 598 |  | 
| David Brownell | 40982be | 2008-06-19 17:52:58 -0700 | [diff] [blame] | 599 | if (number) { | 
|  | 600 | list_for_each_entry(c, &cdev->configs, list) { | 
|  | 601 | if (c->bConfigurationValue == number) { | 
| Tatyana Brokhman | bdb64d7 | 2011-06-29 16:41:50 +0300 | [diff] [blame] | 602 | /* | 
|  | 603 | * We disable the FDs of the previous | 
|  | 604 | * configuration only if the new configuration | 
|  | 605 | * is a valid one | 
|  | 606 | */ | 
|  | 607 | if (cdev->config) | 
|  | 608 | reset_config(cdev); | 
| David Brownell | 40982be | 2008-06-19 17:52:58 -0700 | [diff] [blame] | 609 | result = 0; | 
|  | 610 | break; | 
|  | 611 | } | 
|  | 612 | } | 
|  | 613 | if (result < 0) | 
|  | 614 | goto done; | 
| Tatyana Brokhman | bdb64d7 | 2011-06-29 16:41:50 +0300 | [diff] [blame] | 615 | } else { /* Zero configuration value - need to reset the config */ | 
|  | 616 | if (cdev->config) | 
|  | 617 | reset_config(cdev); | 
| David Brownell | 40982be | 2008-06-19 17:52:58 -0700 | [diff] [blame] | 618 | result = 0; | 
| Tatyana Brokhman | bdb64d7 | 2011-06-29 16:41:50 +0300 | [diff] [blame] | 619 | } | 
| David Brownell | 40982be | 2008-06-19 17:52:58 -0700 | [diff] [blame] | 620 |  | 
| Michal Nazarewicz | e538dfd | 2011-08-30 17:11:19 +0200 | [diff] [blame] | 621 | INFO(cdev, "%s config #%d: %s\n", | 
|  | 622 | usb_speed_string(gadget->speed), | 
|  | 623 | number, c ? c->label : "unconfigured"); | 
| David Brownell | 40982be | 2008-06-19 17:52:58 -0700 | [diff] [blame] | 624 |  | 
|  | 625 | if (!c) | 
|  | 626 | goto done; | 
|  | 627 |  | 
|  | 628 | cdev->config = c; | 
|  | 629 |  | 
|  | 630 | /* Initialize all interfaces by setting them to altsetting zero. */ | 
|  | 631 | for (tmp = 0; tmp < MAX_CONFIG_INTERFACES; tmp++) { | 
|  | 632 | struct usb_function	*f = c->interface[tmp]; | 
| Laurent Pinchart | 5242658 | 2009-10-21 00:03:38 +0200 | [diff] [blame] | 633 | struct usb_descriptor_header **descriptors; | 
| David Brownell | 40982be | 2008-06-19 17:52:58 -0700 | [diff] [blame] | 634 |  | 
|  | 635 | if (!f) | 
|  | 636 | break; | 
|  | 637 |  | 
| Laurent Pinchart | 5242658 | 2009-10-21 00:03:38 +0200 | [diff] [blame] | 638 | /* | 
|  | 639 | * Record which endpoints are used by the function. This is used | 
|  | 640 | * to dispatch control requests targeted at that endpoint to the | 
|  | 641 | * function's setup callback instead of the current | 
|  | 642 | * configuration's setup callback. | 
|  | 643 | */ | 
| Tatyana Brokhman | bdb64d7 | 2011-06-29 16:41:50 +0300 | [diff] [blame] | 644 | switch (gadget->speed) { | 
|  | 645 | case USB_SPEED_SUPER: | 
|  | 646 | descriptors = f->ss_descriptors; | 
|  | 647 | break; | 
|  | 648 | case USB_SPEED_HIGH: | 
| Laurent Pinchart | 5242658 | 2009-10-21 00:03:38 +0200 | [diff] [blame] | 649 | descriptors = f->hs_descriptors; | 
| Tatyana Brokhman | bdb64d7 | 2011-06-29 16:41:50 +0300 | [diff] [blame] | 650 | break; | 
|  | 651 | default: | 
| Laurent Pinchart | 5242658 | 2009-10-21 00:03:38 +0200 | [diff] [blame] | 652 | descriptors = f->descriptors; | 
| Tatyana Brokhman | bdb64d7 | 2011-06-29 16:41:50 +0300 | [diff] [blame] | 653 | } | 
| Laurent Pinchart | 5242658 | 2009-10-21 00:03:38 +0200 | [diff] [blame] | 654 |  | 
|  | 655 | for (; *descriptors; ++descriptors) { | 
|  | 656 | struct usb_endpoint_descriptor *ep; | 
|  | 657 | int addr; | 
|  | 658 |  | 
|  | 659 | if ((*descriptors)->bDescriptorType != USB_DT_ENDPOINT) | 
|  | 660 | continue; | 
|  | 661 |  | 
|  | 662 | ep = (struct usb_endpoint_descriptor *)*descriptors; | 
|  | 663 | addr = ((ep->bEndpointAddress & 0x80) >> 3) | 
|  | 664 | |  (ep->bEndpointAddress & 0x0f); | 
|  | 665 | set_bit(addr, f->endpoints); | 
|  | 666 | } | 
|  | 667 |  | 
| David Brownell | 40982be | 2008-06-19 17:52:58 -0700 | [diff] [blame] | 668 | result = f->set_alt(f, tmp, 0); | 
|  | 669 | if (result < 0) { | 
|  | 670 | DBG(cdev, "interface %d (%s/%p) alt 0 --> %d\n", | 
|  | 671 | tmp, f->name, f, result); | 
|  | 672 |  | 
|  | 673 | reset_config(cdev); | 
|  | 674 | goto done; | 
|  | 675 | } | 
| Roger Quadros | 1b9ba00 | 2011-05-09 13:08:06 +0300 | [diff] [blame] | 676 |  | 
|  | 677 | if (result == USB_GADGET_DELAYED_STATUS) { | 
|  | 678 | DBG(cdev, | 
|  | 679 | "%s: interface %d (%s) requested delayed status\n", | 
|  | 680 | __func__, tmp, f->name); | 
|  | 681 | cdev->delayed_status++; | 
|  | 682 | DBG(cdev, "delayed_status count %d\n", | 
|  | 683 | cdev->delayed_status); | 
|  | 684 | } | 
| David Brownell | 40982be | 2008-06-19 17:52:58 -0700 | [diff] [blame] | 685 | } | 
|  | 686 |  | 
|  | 687 | /* when we return, be sure our power usage is valid */ | 
| David Brownell | 36e893d | 2008-09-12 09:39:06 -0700 | [diff] [blame] | 688 | power = c->bMaxPower ? (2 * c->bMaxPower) : CONFIG_USB_GADGET_VBUS_DRAW; | 
| David Brownell | 40982be | 2008-06-19 17:52:58 -0700 | [diff] [blame] | 689 | done: | 
|  | 690 | usb_gadget_vbus_draw(gadget, power); | 
| Roger Quadros | 1b9ba00 | 2011-05-09 13:08:06 +0300 | [diff] [blame] | 691 | if (result >= 0 && cdev->delayed_status) | 
|  | 692 | result = USB_GADGET_DELAYED_STATUS; | 
| David Brownell | 40982be | 2008-06-19 17:52:58 -0700 | [diff] [blame] | 693 | return result; | 
|  | 694 | } | 
|  | 695 |  | 
|  | 696 | /** | 
|  | 697 | * usb_add_config() - add a configuration to a device. | 
|  | 698 | * @cdev: wraps the USB gadget | 
|  | 699 | * @config: the configuration, with bConfigurationValue assigned | 
| Uwe Kleine-König | c9bfff9 | 2010-08-12 17:43:55 +0200 | [diff] [blame] | 700 | * @bind: the configuration's bind function | 
| David Brownell | 40982be | 2008-06-19 17:52:58 -0700 | [diff] [blame] | 701 | * Context: single threaded during gadget setup | 
|  | 702 | * | 
| Uwe Kleine-König | c9bfff9 | 2010-08-12 17:43:55 +0200 | [diff] [blame] | 703 | * One of the main tasks of a composite @bind() routine is to | 
| David Brownell | 40982be | 2008-06-19 17:52:58 -0700 | [diff] [blame] | 704 | * add each of the configurations it supports, using this routine. | 
|  | 705 | * | 
| Uwe Kleine-König | c9bfff9 | 2010-08-12 17:43:55 +0200 | [diff] [blame] | 706 | * This function returns the value of the configuration's @bind(), which | 
| David Brownell | 40982be | 2008-06-19 17:52:58 -0700 | [diff] [blame] | 707 | * is zero for success else a negative errno value.  Binding configurations | 
|  | 708 | * assigns global resources including string IDs, and per-configuration | 
|  | 709 | * resources such as interface IDs and endpoints. | 
|  | 710 | */ | 
| Michal Nazarewicz | 28824b1 | 2010-05-05 12:53:13 +0200 | [diff] [blame] | 711 | int usb_add_config(struct usb_composite_dev *cdev, | 
| Uwe Kleine-König | c9bfff9 | 2010-08-12 17:43:55 +0200 | [diff] [blame] | 712 | struct usb_configuration *config, | 
|  | 713 | int (*bind)(struct usb_configuration *)) | 
| David Brownell | 40982be | 2008-06-19 17:52:58 -0700 | [diff] [blame] | 714 | { | 
|  | 715 | int				status = -EINVAL; | 
|  | 716 | struct usb_configuration	*c; | 
|  | 717 |  | 
|  | 718 | DBG(cdev, "adding config #%u '%s'/%p\n", | 
|  | 719 | config->bConfigurationValue, | 
|  | 720 | config->label, config); | 
|  | 721 |  | 
| Uwe Kleine-König | c9bfff9 | 2010-08-12 17:43:55 +0200 | [diff] [blame] | 722 | if (!config->bConfigurationValue || !bind) | 
| David Brownell | 40982be | 2008-06-19 17:52:58 -0700 | [diff] [blame] | 723 | goto done; | 
|  | 724 |  | 
|  | 725 | /* Prevent duplicate configuration identifiers */ | 
|  | 726 | list_for_each_entry(c, &cdev->configs, list) { | 
|  | 727 | if (c->bConfigurationValue == config->bConfigurationValue) { | 
|  | 728 | status = -EBUSY; | 
|  | 729 | goto done; | 
|  | 730 | } | 
|  | 731 | } | 
|  | 732 |  | 
|  | 733 | config->cdev = cdev; | 
|  | 734 | list_add_tail(&config->list, &cdev->configs); | 
|  | 735 |  | 
|  | 736 | INIT_LIST_HEAD(&config->functions); | 
|  | 737 | config->next_interface_id = 0; | 
|  | 738 |  | 
| Uwe Kleine-König | c9bfff9 | 2010-08-12 17:43:55 +0200 | [diff] [blame] | 739 | status = bind(config); | 
| David Brownell | 40982be | 2008-06-19 17:52:58 -0700 | [diff] [blame] | 740 | if (status < 0) { | 
|  | 741 | list_del(&config->list); | 
|  | 742 | config->cdev = NULL; | 
|  | 743 | } else { | 
|  | 744 | unsigned	i; | 
|  | 745 |  | 
| Tatyana Brokhman | bdb64d7 | 2011-06-29 16:41:50 +0300 | [diff] [blame] | 746 | DBG(cdev, "cfg %d/%p speeds:%s%s%s\n", | 
| David Brownell | 40982be | 2008-06-19 17:52:58 -0700 | [diff] [blame] | 747 | config->bConfigurationValue, config, | 
| Tatyana Brokhman | bdb64d7 | 2011-06-29 16:41:50 +0300 | [diff] [blame] | 748 | config->superspeed ? " super" : "", | 
| David Brownell | 40982be | 2008-06-19 17:52:58 -0700 | [diff] [blame] | 749 | config->highspeed ? " high" : "", | 
|  | 750 | config->fullspeed | 
|  | 751 | ? (gadget_is_dualspeed(cdev->gadget) | 
|  | 752 | ? " full" | 
|  | 753 | : " full/low") | 
|  | 754 | : ""); | 
|  | 755 |  | 
|  | 756 | for (i = 0; i < MAX_CONFIG_INTERFACES; i++) { | 
|  | 757 | struct usb_function	*f = config->interface[i]; | 
|  | 758 |  | 
|  | 759 | if (!f) | 
|  | 760 | continue; | 
|  | 761 | DBG(cdev, "  interface %d = %s/%p\n", | 
|  | 762 | i, f->name, f); | 
|  | 763 | } | 
|  | 764 | } | 
|  | 765 |  | 
| Uwe Kleine-König | c9bfff9 | 2010-08-12 17:43:55 +0200 | [diff] [blame] | 766 | /* set_alt(), or next bind(), sets up | 
| David Brownell | 40982be | 2008-06-19 17:52:58 -0700 | [diff] [blame] | 767 | * ep->driver_data as needed. | 
|  | 768 | */ | 
|  | 769 | usb_ep_autoconfig_reset(cdev->gadget); | 
|  | 770 |  | 
|  | 771 | done: | 
|  | 772 | if (status) | 
|  | 773 | DBG(cdev, "added config '%s'/%u --> %d\n", config->label, | 
|  | 774 | config->bConfigurationValue, status); | 
|  | 775 | return status; | 
|  | 776 | } | 
|  | 777 |  | 
|  | 778 | /*-------------------------------------------------------------------------*/ | 
|  | 779 |  | 
|  | 780 | /* We support strings in multiple languages ... string descriptor zero | 
|  | 781 | * says which languages are supported.  The typical case will be that | 
|  | 782 | * only one language (probably English) is used, with I18N handled on | 
|  | 783 | * the host side. | 
|  | 784 | */ | 
|  | 785 |  | 
|  | 786 | static void collect_langs(struct usb_gadget_strings **sp, __le16 *buf) | 
|  | 787 | { | 
|  | 788 | const struct usb_gadget_strings	*s; | 
|  | 789 | u16				language; | 
|  | 790 | __le16				*tmp; | 
|  | 791 |  | 
|  | 792 | while (*sp) { | 
|  | 793 | s = *sp; | 
|  | 794 | language = cpu_to_le16(s->language); | 
|  | 795 | for (tmp = buf; *tmp && tmp < &buf[126]; tmp++) { | 
|  | 796 | if (*tmp == language) | 
|  | 797 | goto repeat; | 
|  | 798 | } | 
|  | 799 | *tmp++ = language; | 
|  | 800 | repeat: | 
|  | 801 | sp++; | 
|  | 802 | } | 
|  | 803 | } | 
|  | 804 |  | 
|  | 805 | static int lookup_string( | 
|  | 806 | struct usb_gadget_strings	**sp, | 
|  | 807 | void				*buf, | 
|  | 808 | u16				language, | 
|  | 809 | int				id | 
|  | 810 | ) | 
|  | 811 | { | 
|  | 812 | struct usb_gadget_strings	*s; | 
|  | 813 | int				value; | 
|  | 814 |  | 
|  | 815 | while (*sp) { | 
|  | 816 | s = *sp++; | 
|  | 817 | if (s->language != language) | 
|  | 818 | continue; | 
|  | 819 | value = usb_gadget_get_string(s, id, buf); | 
|  | 820 | if (value > 0) | 
|  | 821 | return value; | 
|  | 822 | } | 
|  | 823 | return -EINVAL; | 
|  | 824 | } | 
|  | 825 |  | 
|  | 826 | static int get_string(struct usb_composite_dev *cdev, | 
|  | 827 | void *buf, u16 language, int id) | 
|  | 828 | { | 
|  | 829 | struct usb_configuration	*c; | 
|  | 830 | struct usb_function		*f; | 
|  | 831 | int				len; | 
| Michal Nazarewicz | ad1a810 | 2010-08-12 17:43:46 +0200 | [diff] [blame] | 832 | const char			*str; | 
| David Brownell | 40982be | 2008-06-19 17:52:58 -0700 | [diff] [blame] | 833 |  | 
|  | 834 | /* Yes, not only is USB's I18N support probably more than most | 
|  | 835 | * folk will ever care about ... also, it's all supported here. | 
|  | 836 | * (Except for UTF8 support for Unicode's "Astral Planes".) | 
|  | 837 | */ | 
|  | 838 |  | 
|  | 839 | /* 0 == report all available language codes */ | 
|  | 840 | if (id == 0) { | 
|  | 841 | struct usb_string_descriptor	*s = buf; | 
|  | 842 | struct usb_gadget_strings	**sp; | 
|  | 843 |  | 
|  | 844 | memset(s, 0, 256); | 
|  | 845 | s->bDescriptorType = USB_DT_STRING; | 
|  | 846 |  | 
|  | 847 | sp = composite->strings; | 
|  | 848 | if (sp) | 
|  | 849 | collect_langs(sp, s->wData); | 
|  | 850 |  | 
|  | 851 | list_for_each_entry(c, &cdev->configs, list) { | 
|  | 852 | sp = c->strings; | 
|  | 853 | if (sp) | 
|  | 854 | collect_langs(sp, s->wData); | 
|  | 855 |  | 
|  | 856 | list_for_each_entry(f, &c->functions, list) { | 
|  | 857 | sp = f->strings; | 
|  | 858 | if (sp) | 
|  | 859 | collect_langs(sp, s->wData); | 
|  | 860 | } | 
|  | 861 | } | 
|  | 862 |  | 
| Roel Kluin | 417b57b | 2009-08-06 16:09:51 -0700 | [diff] [blame] | 863 | for (len = 0; len <= 126 && s->wData[len]; len++) | 
| David Brownell | 40982be | 2008-06-19 17:52:58 -0700 | [diff] [blame] | 864 | continue; | 
|  | 865 | if (!len) | 
|  | 866 | return -EINVAL; | 
|  | 867 |  | 
|  | 868 | s->bLength = 2 * (len + 1); | 
|  | 869 | return s->bLength; | 
|  | 870 | } | 
|  | 871 |  | 
| Michal Nazarewicz | ad1a810 | 2010-08-12 17:43:46 +0200 | [diff] [blame] | 872 | /* Otherwise, look up and return a specified string.  First | 
|  | 873 | * check if the string has not been overridden. | 
|  | 874 | */ | 
|  | 875 | if (cdev->manufacturer_override == id) | 
|  | 876 | str = iManufacturer ?: composite->iManufacturer ?: | 
|  | 877 | composite_manufacturer; | 
|  | 878 | else if (cdev->product_override == id) | 
|  | 879 | str = iProduct ?: composite->iProduct; | 
|  | 880 | else if (cdev->serial_override == id) | 
|  | 881 | str = iSerialNumber; | 
|  | 882 | else | 
|  | 883 | str = NULL; | 
|  | 884 | if (str) { | 
|  | 885 | struct usb_gadget_strings strings = { | 
|  | 886 | .language = language, | 
|  | 887 | .strings  = &(struct usb_string) { 0xff, str } | 
|  | 888 | }; | 
|  | 889 | return usb_gadget_get_string(&strings, 0xff, buf); | 
|  | 890 | } | 
|  | 891 |  | 
|  | 892 | /* String IDs are device-scoped, so we look up each string | 
|  | 893 | * table we're told about.  These lookups are infrequent; | 
|  | 894 | * simpler-is-better here. | 
| David Brownell | 40982be | 2008-06-19 17:52:58 -0700 | [diff] [blame] | 895 | */ | 
|  | 896 | if (composite->strings) { | 
|  | 897 | len = lookup_string(composite->strings, buf, language, id); | 
|  | 898 | if (len > 0) | 
|  | 899 | return len; | 
|  | 900 | } | 
|  | 901 | list_for_each_entry(c, &cdev->configs, list) { | 
|  | 902 | if (c->strings) { | 
|  | 903 | len = lookup_string(c->strings, buf, language, id); | 
|  | 904 | if (len > 0) | 
|  | 905 | return len; | 
|  | 906 | } | 
|  | 907 | list_for_each_entry(f, &c->functions, list) { | 
|  | 908 | if (!f->strings) | 
|  | 909 | continue; | 
|  | 910 | len = lookup_string(f->strings, buf, language, id); | 
|  | 911 | if (len > 0) | 
|  | 912 | return len; | 
|  | 913 | } | 
|  | 914 | } | 
|  | 915 | return -EINVAL; | 
|  | 916 | } | 
|  | 917 |  | 
|  | 918 | /** | 
|  | 919 | * usb_string_id() - allocate an unused string ID | 
|  | 920 | * @cdev: the device whose string descriptor IDs are being allocated | 
|  | 921 | * Context: single threaded during gadget setup | 
|  | 922 | * | 
|  | 923 | * @usb_string_id() is called from bind() callbacks to allocate | 
|  | 924 | * string IDs.  Drivers for functions, configurations, or gadgets will | 
|  | 925 | * then store that ID in the appropriate descriptors and string table. | 
|  | 926 | * | 
| Michal Nazarewicz | f2adc4f | 2010-06-16 12:07:59 +0200 | [diff] [blame] | 927 | * All string identifier should be allocated using this, | 
|  | 928 | * @usb_string_ids_tab() or @usb_string_ids_n() routine, to ensure | 
|  | 929 | * that for example different functions don't wrongly assign different | 
|  | 930 | * meanings to the same identifier. | 
| David Brownell | 40982be | 2008-06-19 17:52:58 -0700 | [diff] [blame] | 931 | */ | 
| Michal Nazarewicz | 28824b1 | 2010-05-05 12:53:13 +0200 | [diff] [blame] | 932 | int usb_string_id(struct usb_composite_dev *cdev) | 
| David Brownell | 40982be | 2008-06-19 17:52:58 -0700 | [diff] [blame] | 933 | { | 
|  | 934 | if (cdev->next_string_id < 254) { | 
| Michal Nazarewicz | f2adc4f | 2010-06-16 12:07:59 +0200 | [diff] [blame] | 935 | /* string id 0 is reserved by USB spec for list of | 
|  | 936 | * supported languages */ | 
|  | 937 | /* 255 reserved as well? -- mina86 */ | 
| David Brownell | 40982be | 2008-06-19 17:52:58 -0700 | [diff] [blame] | 938 | cdev->next_string_id++; | 
|  | 939 | return cdev->next_string_id; | 
|  | 940 | } | 
|  | 941 | return -ENODEV; | 
|  | 942 | } | 
|  | 943 |  | 
| Michal Nazarewicz | f2adc4f | 2010-06-16 12:07:59 +0200 | [diff] [blame] | 944 | /** | 
|  | 945 | * usb_string_ids() - allocate unused string IDs in batch | 
|  | 946 | * @cdev: the device whose string descriptor IDs are being allocated | 
|  | 947 | * @str: an array of usb_string objects to assign numbers to | 
|  | 948 | * Context: single threaded during gadget setup | 
|  | 949 | * | 
|  | 950 | * @usb_string_ids() is called from bind() callbacks to allocate | 
|  | 951 | * string IDs.  Drivers for functions, configurations, or gadgets will | 
|  | 952 | * then copy IDs from the string table to the appropriate descriptors | 
|  | 953 | * and string table for other languages. | 
|  | 954 | * | 
|  | 955 | * All string identifier should be allocated using this, | 
|  | 956 | * @usb_string_id() or @usb_string_ids_n() routine, to ensure that for | 
|  | 957 | * example different functions don't wrongly assign different meanings | 
|  | 958 | * to the same identifier. | 
|  | 959 | */ | 
|  | 960 | int usb_string_ids_tab(struct usb_composite_dev *cdev, struct usb_string *str) | 
|  | 961 | { | 
|  | 962 | int next = cdev->next_string_id; | 
|  | 963 |  | 
|  | 964 | for (; str->s; ++str) { | 
|  | 965 | if (unlikely(next >= 254)) | 
|  | 966 | return -ENODEV; | 
|  | 967 | str->id = ++next; | 
|  | 968 | } | 
|  | 969 |  | 
|  | 970 | cdev->next_string_id = next; | 
|  | 971 |  | 
|  | 972 | return 0; | 
|  | 973 | } | 
|  | 974 |  | 
|  | 975 | /** | 
|  | 976 | * usb_string_ids_n() - allocate unused string IDs in batch | 
| Randy Dunlap | d187abb | 2010-08-11 12:07:13 -0700 | [diff] [blame] | 977 | * @c: the device whose string descriptor IDs are being allocated | 
| Michal Nazarewicz | f2adc4f | 2010-06-16 12:07:59 +0200 | [diff] [blame] | 978 | * @n: number of string IDs to allocate | 
|  | 979 | * Context: single threaded during gadget setup | 
|  | 980 | * | 
|  | 981 | * Returns the first requested ID.  This ID and next @n-1 IDs are now | 
| Randy Dunlap | d187abb | 2010-08-11 12:07:13 -0700 | [diff] [blame] | 982 | * valid IDs.  At least provided that @n is non-zero because if it | 
| Michal Nazarewicz | f2adc4f | 2010-06-16 12:07:59 +0200 | [diff] [blame] | 983 | * is, returns last requested ID which is now very useful information. | 
|  | 984 | * | 
|  | 985 | * @usb_string_ids_n() is called from bind() callbacks to allocate | 
|  | 986 | * string IDs.  Drivers for functions, configurations, or gadgets will | 
|  | 987 | * then store that ID in the appropriate descriptors and string table. | 
|  | 988 | * | 
|  | 989 | * All string identifier should be allocated using this, | 
|  | 990 | * @usb_string_id() or @usb_string_ids_n() routine, to ensure that for | 
|  | 991 | * example different functions don't wrongly assign different meanings | 
|  | 992 | * to the same identifier. | 
|  | 993 | */ | 
|  | 994 | int usb_string_ids_n(struct usb_composite_dev *c, unsigned n) | 
|  | 995 | { | 
|  | 996 | unsigned next = c->next_string_id; | 
|  | 997 | if (unlikely(n > 254 || (unsigned)next + n > 254)) | 
|  | 998 | return -ENODEV; | 
|  | 999 | c->next_string_id += n; | 
|  | 1000 | return next + 1; | 
|  | 1001 | } | 
|  | 1002 |  | 
|  | 1003 |  | 
| David Brownell | 40982be | 2008-06-19 17:52:58 -0700 | [diff] [blame] | 1004 | /*-------------------------------------------------------------------------*/ | 
|  | 1005 |  | 
|  | 1006 | static void composite_setup_complete(struct usb_ep *ep, struct usb_request *req) | 
|  | 1007 | { | 
|  | 1008 | if (req->status || req->actual != req->length) | 
|  | 1009 | DBG((struct usb_composite_dev *) ep->driver_data, | 
|  | 1010 | "setup complete --> %d, %d/%d\n", | 
|  | 1011 | req->status, req->actual, req->length); | 
|  | 1012 | } | 
|  | 1013 |  | 
|  | 1014 | /* | 
|  | 1015 | * The setup() callback implements all the ep0 functionality that's | 
|  | 1016 | * not handled lower down, in hardware or the hardware driver(like | 
|  | 1017 | * device and endpoint feature flags, and their status).  It's all | 
|  | 1018 | * housekeeping for the gadget function we're implementing.  Most of | 
|  | 1019 | * the work is in config and function specific setup. | 
|  | 1020 | */ | 
|  | 1021 | static int | 
|  | 1022 | composite_setup(struct usb_gadget *gadget, const struct usb_ctrlrequest *ctrl) | 
|  | 1023 | { | 
|  | 1024 | struct usb_composite_dev	*cdev = get_gadget_data(gadget); | 
|  | 1025 | struct usb_request		*req = cdev->req; | 
|  | 1026 | int				value = -EOPNOTSUPP; | 
| Tatyana Brokhman | bdb64d7 | 2011-06-29 16:41:50 +0300 | [diff] [blame] | 1027 | int				status = 0; | 
| David Brownell | 40982be | 2008-06-19 17:52:58 -0700 | [diff] [blame] | 1028 | u16				w_index = le16_to_cpu(ctrl->wIndex); | 
| Bryan Wu | 0888951 | 2009-01-08 00:21:19 +0800 | [diff] [blame] | 1029 | u8				intf = w_index & 0xFF; | 
| David Brownell | 40982be | 2008-06-19 17:52:58 -0700 | [diff] [blame] | 1030 | u16				w_value = le16_to_cpu(ctrl->wValue); | 
|  | 1031 | u16				w_length = le16_to_cpu(ctrl->wLength); | 
|  | 1032 | struct usb_function		*f = NULL; | 
| Laurent Pinchart | 5242658 | 2009-10-21 00:03:38 +0200 | [diff] [blame] | 1033 | u8				endp; | 
| David Brownell | 40982be | 2008-06-19 17:52:58 -0700 | [diff] [blame] | 1034 |  | 
|  | 1035 | /* partial re-init of the response message; the function or the | 
|  | 1036 | * gadget might need to intercept e.g. a control-OUT completion | 
|  | 1037 | * when we delegate to it. | 
|  | 1038 | */ | 
|  | 1039 | req->zero = 0; | 
|  | 1040 | req->complete = composite_setup_complete; | 
| Maulik Mankad | 2edb11c | 2011-02-22 19:08:42 +0530 | [diff] [blame] | 1041 | req->length = 0; | 
| David Brownell | 40982be | 2008-06-19 17:52:58 -0700 | [diff] [blame] | 1042 | gadget->ep0->driver_data = cdev; | 
|  | 1043 |  | 
|  | 1044 | switch (ctrl->bRequest) { | 
|  | 1045 |  | 
|  | 1046 | /* we handle all standard USB descriptors */ | 
|  | 1047 | case USB_REQ_GET_DESCRIPTOR: | 
|  | 1048 | if (ctrl->bRequestType != USB_DIR_IN) | 
|  | 1049 | goto unknown; | 
|  | 1050 | switch (w_value >> 8) { | 
|  | 1051 |  | 
|  | 1052 | case USB_DT_DEVICE: | 
|  | 1053 | cdev->desc.bNumConfigurations = | 
|  | 1054 | count_configs(cdev, USB_DT_DEVICE); | 
| Tatyana Brokhman | bdb64d7 | 2011-06-29 16:41:50 +0300 | [diff] [blame] | 1055 | cdev->desc.bMaxPacketSize0 = | 
|  | 1056 | cdev->gadget->ep0->maxpacket; | 
|  | 1057 | if (gadget_is_superspeed(gadget)) { | 
| Sebastian Andrzej Siewior | a8f2115 | 2011-07-19 20:21:52 +0200 | [diff] [blame] | 1058 | if (gadget->speed >= USB_SPEED_SUPER) { | 
| Tatyana Brokhman | bdb64d7 | 2011-06-29 16:41:50 +0300 | [diff] [blame] | 1059 | cdev->desc.bcdUSB = cpu_to_le16(0x0300); | 
| Sebastian Andrzej Siewior | a8f2115 | 2011-07-19 20:21:52 +0200 | [diff] [blame] | 1060 | cdev->desc.bMaxPacketSize0 = 9; | 
|  | 1061 | } else { | 
| Tatyana Brokhman | bdb64d7 | 2011-06-29 16:41:50 +0300 | [diff] [blame] | 1062 | cdev->desc.bcdUSB = cpu_to_le16(0x0210); | 
| Sebastian Andrzej Siewior | a8f2115 | 2011-07-19 20:21:52 +0200 | [diff] [blame] | 1063 | } | 
| Tatyana Brokhman | bdb64d7 | 2011-06-29 16:41:50 +0300 | [diff] [blame] | 1064 | } | 
|  | 1065 |  | 
| David Brownell | 40982be | 2008-06-19 17:52:58 -0700 | [diff] [blame] | 1066 | value = min(w_length, (u16) sizeof cdev->desc); | 
|  | 1067 | memcpy(req->buf, &cdev->desc, value); | 
|  | 1068 | break; | 
|  | 1069 | case USB_DT_DEVICE_QUALIFIER: | 
| Tatyana Brokhman | bdb64d7 | 2011-06-29 16:41:50 +0300 | [diff] [blame] | 1070 | if (!gadget_is_dualspeed(gadget) || | 
|  | 1071 | gadget->speed >= USB_SPEED_SUPER) | 
| David Brownell | 40982be | 2008-06-19 17:52:58 -0700 | [diff] [blame] | 1072 | break; | 
|  | 1073 | device_qual(cdev); | 
|  | 1074 | value = min_t(int, w_length, | 
|  | 1075 | sizeof(struct usb_qualifier_descriptor)); | 
|  | 1076 | break; | 
|  | 1077 | case USB_DT_OTHER_SPEED_CONFIG: | 
| Tatyana Brokhman | bdb64d7 | 2011-06-29 16:41:50 +0300 | [diff] [blame] | 1078 | if (!gadget_is_dualspeed(gadget) || | 
|  | 1079 | gadget->speed >= USB_SPEED_SUPER) | 
| David Brownell | 40982be | 2008-06-19 17:52:58 -0700 | [diff] [blame] | 1080 | break; | 
|  | 1081 | /* FALLTHROUGH */ | 
|  | 1082 | case USB_DT_CONFIG: | 
|  | 1083 | value = config_desc(cdev, w_value); | 
|  | 1084 | if (value >= 0) | 
|  | 1085 | value = min(w_length, (u16) value); | 
|  | 1086 | break; | 
|  | 1087 | case USB_DT_STRING: | 
|  | 1088 | value = get_string(cdev, req->buf, | 
|  | 1089 | w_index, w_value & 0xff); | 
|  | 1090 | if (value >= 0) | 
|  | 1091 | value = min(w_length, (u16) value); | 
|  | 1092 | break; | 
| Tatyana Brokhman | bdb64d7 | 2011-06-29 16:41:50 +0300 | [diff] [blame] | 1093 | case USB_DT_BOS: | 
|  | 1094 | if (gadget_is_superspeed(gadget)) { | 
|  | 1095 | value = bos_desc(cdev); | 
|  | 1096 | value = min(w_length, (u16) value); | 
|  | 1097 | } | 
|  | 1098 | break; | 
| David Brownell | 40982be | 2008-06-19 17:52:58 -0700 | [diff] [blame] | 1099 | } | 
|  | 1100 | break; | 
|  | 1101 |  | 
|  | 1102 | /* any number of configs can work */ | 
|  | 1103 | case USB_REQ_SET_CONFIGURATION: | 
|  | 1104 | if (ctrl->bRequestType != 0) | 
|  | 1105 | goto unknown; | 
|  | 1106 | if (gadget_is_otg(gadget)) { | 
|  | 1107 | if (gadget->a_hnp_support) | 
|  | 1108 | DBG(cdev, "HNP available\n"); | 
|  | 1109 | else if (gadget->a_alt_hnp_support) | 
|  | 1110 | DBG(cdev, "HNP on another port\n"); | 
|  | 1111 | else | 
|  | 1112 | VDBG(cdev, "HNP inactive\n"); | 
|  | 1113 | } | 
|  | 1114 | spin_lock(&cdev->lock); | 
|  | 1115 | value = set_config(cdev, ctrl, w_value); | 
|  | 1116 | spin_unlock(&cdev->lock); | 
|  | 1117 | break; | 
|  | 1118 | case USB_REQ_GET_CONFIGURATION: | 
|  | 1119 | if (ctrl->bRequestType != USB_DIR_IN) | 
|  | 1120 | goto unknown; | 
|  | 1121 | if (cdev->config) | 
|  | 1122 | *(u8 *)req->buf = cdev->config->bConfigurationValue; | 
|  | 1123 | else | 
|  | 1124 | *(u8 *)req->buf = 0; | 
|  | 1125 | value = min(w_length, (u16) 1); | 
|  | 1126 | break; | 
|  | 1127 |  | 
|  | 1128 | /* function drivers must handle get/set altsetting; if there's | 
|  | 1129 | * no get() method, we know only altsetting zero works. | 
|  | 1130 | */ | 
|  | 1131 | case USB_REQ_SET_INTERFACE: | 
|  | 1132 | if (ctrl->bRequestType != USB_RECIP_INTERFACE) | 
|  | 1133 | goto unknown; | 
| Jassi Brar | ff085de | 2011-02-06 17:39:17 +0900 | [diff] [blame] | 1134 | if (!cdev->config || intf >= MAX_CONFIG_INTERFACES) | 
| David Brownell | 40982be | 2008-06-19 17:52:58 -0700 | [diff] [blame] | 1135 | break; | 
| Bryan Wu | 0888951 | 2009-01-08 00:21:19 +0800 | [diff] [blame] | 1136 | f = cdev->config->interface[intf]; | 
| David Brownell | 40982be | 2008-06-19 17:52:58 -0700 | [diff] [blame] | 1137 | if (!f) | 
|  | 1138 | break; | 
| Bryan Wu | dd4dff8 | 2009-01-08 00:21:18 +0800 | [diff] [blame] | 1139 | if (w_value && !f->set_alt) | 
| David Brownell | 40982be | 2008-06-19 17:52:58 -0700 | [diff] [blame] | 1140 | break; | 
|  | 1141 | value = f->set_alt(f, w_index, w_value); | 
| Roger Quadros | 1b9ba00 | 2011-05-09 13:08:06 +0300 | [diff] [blame] | 1142 | if (value == USB_GADGET_DELAYED_STATUS) { | 
|  | 1143 | DBG(cdev, | 
|  | 1144 | "%s: interface %d (%s) requested delayed status\n", | 
|  | 1145 | __func__, intf, f->name); | 
|  | 1146 | cdev->delayed_status++; | 
|  | 1147 | DBG(cdev, "delayed_status count %d\n", | 
|  | 1148 | cdev->delayed_status); | 
|  | 1149 | } | 
| David Brownell | 40982be | 2008-06-19 17:52:58 -0700 | [diff] [blame] | 1150 | break; | 
|  | 1151 | case USB_REQ_GET_INTERFACE: | 
|  | 1152 | if (ctrl->bRequestType != (USB_DIR_IN|USB_RECIP_INTERFACE)) | 
|  | 1153 | goto unknown; | 
| Jassi Brar | ff085de | 2011-02-06 17:39:17 +0900 | [diff] [blame] | 1154 | if (!cdev->config || intf >= MAX_CONFIG_INTERFACES) | 
| David Brownell | 40982be | 2008-06-19 17:52:58 -0700 | [diff] [blame] | 1155 | break; | 
| Bryan Wu | 0888951 | 2009-01-08 00:21:19 +0800 | [diff] [blame] | 1156 | f = cdev->config->interface[intf]; | 
| David Brownell | 40982be | 2008-06-19 17:52:58 -0700 | [diff] [blame] | 1157 | if (!f) | 
|  | 1158 | break; | 
|  | 1159 | /* lots of interfaces only need altsetting zero... */ | 
|  | 1160 | value = f->get_alt ? f->get_alt(f, w_index) : 0; | 
|  | 1161 | if (value < 0) | 
|  | 1162 | break; | 
|  | 1163 | *((u8 *)req->buf) = value; | 
|  | 1164 | value = min(w_length, (u16) 1); | 
|  | 1165 | break; | 
| Tatyana Brokhman | bdb64d7 | 2011-06-29 16:41:50 +0300 | [diff] [blame] | 1166 |  | 
|  | 1167 | /* | 
|  | 1168 | * USB 3.0 additions: | 
|  | 1169 | * Function driver should handle get_status request. If such cb | 
|  | 1170 | * wasn't supplied we respond with default value = 0 | 
|  | 1171 | * Note: function driver should supply such cb only for the first | 
|  | 1172 | * interface of the function | 
|  | 1173 | */ | 
|  | 1174 | case USB_REQ_GET_STATUS: | 
|  | 1175 | if (!gadget_is_superspeed(gadget)) | 
|  | 1176 | goto unknown; | 
|  | 1177 | if (ctrl->bRequestType != (USB_DIR_IN | USB_RECIP_INTERFACE)) | 
|  | 1178 | goto unknown; | 
|  | 1179 | value = 2;	/* This is the length of the get_status reply */ | 
|  | 1180 | put_unaligned_le16(0, req->buf); | 
|  | 1181 | if (!cdev->config || intf >= MAX_CONFIG_INTERFACES) | 
|  | 1182 | break; | 
|  | 1183 | f = cdev->config->interface[intf]; | 
|  | 1184 | if (!f) | 
|  | 1185 | break; | 
|  | 1186 | status = f->get_status ? f->get_status(f) : 0; | 
|  | 1187 | if (status < 0) | 
|  | 1188 | break; | 
|  | 1189 | put_unaligned_le16(status & 0x0000ffff, req->buf); | 
|  | 1190 | break; | 
|  | 1191 | /* | 
|  | 1192 | * Function drivers should handle SetFeature/ClearFeature | 
|  | 1193 | * (FUNCTION_SUSPEND) request. function_suspend cb should be supplied | 
|  | 1194 | * only for the first interface of the function | 
|  | 1195 | */ | 
|  | 1196 | case USB_REQ_CLEAR_FEATURE: | 
|  | 1197 | case USB_REQ_SET_FEATURE: | 
|  | 1198 | if (!gadget_is_superspeed(gadget)) | 
|  | 1199 | goto unknown; | 
|  | 1200 | if (ctrl->bRequestType != (USB_DIR_OUT | USB_RECIP_INTERFACE)) | 
|  | 1201 | goto unknown; | 
|  | 1202 | switch (w_value) { | 
|  | 1203 | case USB_INTRF_FUNC_SUSPEND: | 
|  | 1204 | if (!cdev->config || intf >= MAX_CONFIG_INTERFACES) | 
|  | 1205 | break; | 
|  | 1206 | f = cdev->config->interface[intf]; | 
|  | 1207 | if (!f) | 
|  | 1208 | break; | 
|  | 1209 | value = 0; | 
|  | 1210 | if (f->func_suspend) | 
|  | 1211 | value = f->func_suspend(f, w_index >> 8); | 
|  | 1212 | if (value < 0) { | 
|  | 1213 | ERROR(cdev, | 
|  | 1214 | "func_suspend() returned error %d\n", | 
|  | 1215 | value); | 
|  | 1216 | value = 0; | 
|  | 1217 | } | 
|  | 1218 | break; | 
|  | 1219 | } | 
|  | 1220 | break; | 
| David Brownell | 40982be | 2008-06-19 17:52:58 -0700 | [diff] [blame] | 1221 | default: | 
|  | 1222 | unknown: | 
|  | 1223 | VDBG(cdev, | 
|  | 1224 | "non-core control req%02x.%02x v%04x i%04x l%d\n", | 
|  | 1225 | ctrl->bRequestType, ctrl->bRequest, | 
|  | 1226 | w_value, w_index, w_length); | 
|  | 1227 |  | 
| Laurent Pinchart | 5242658 | 2009-10-21 00:03:38 +0200 | [diff] [blame] | 1228 | /* functions always handle their interfaces and endpoints... | 
|  | 1229 | * punt other recipients (other, WUSB, ...) to the current | 
| David Brownell | 40982be | 2008-06-19 17:52:58 -0700 | [diff] [blame] | 1230 | * configuration code. | 
|  | 1231 | * | 
|  | 1232 | * REVISIT it could make sense to let the composite device | 
|  | 1233 | * take such requests too, if that's ever needed:  to work | 
|  | 1234 | * in config 0, etc. | 
|  | 1235 | */ | 
| Laurent Pinchart | 5242658 | 2009-10-21 00:03:38 +0200 | [diff] [blame] | 1236 | switch (ctrl->bRequestType & USB_RECIP_MASK) { | 
|  | 1237 | case USB_RECIP_INTERFACE: | 
| Jassi Brar | ff085de | 2011-02-06 17:39:17 +0900 | [diff] [blame] | 1238 | if (!cdev->config || intf >= MAX_CONFIG_INTERFACES) | 
| Maulik Mankad | 3c47eb0 | 2011-01-13 18:19:56 +0530 | [diff] [blame] | 1239 | break; | 
|  | 1240 | f = cdev->config->interface[intf]; | 
| Laurent Pinchart | 5242658 | 2009-10-21 00:03:38 +0200 | [diff] [blame] | 1241 | break; | 
|  | 1242 |  | 
|  | 1243 | case USB_RECIP_ENDPOINT: | 
|  | 1244 | endp = ((w_index & 0x80) >> 3) | (w_index & 0x0f); | 
|  | 1245 | list_for_each_entry(f, &cdev->config->functions, list) { | 
|  | 1246 | if (test_bit(endp, f->endpoints)) | 
|  | 1247 | break; | 
|  | 1248 | } | 
|  | 1249 | if (&f->list == &cdev->config->functions) | 
| David Brownell | 40982be | 2008-06-19 17:52:58 -0700 | [diff] [blame] | 1250 | f = NULL; | 
| Laurent Pinchart | 5242658 | 2009-10-21 00:03:38 +0200 | [diff] [blame] | 1251 | break; | 
| David Brownell | 40982be | 2008-06-19 17:52:58 -0700 | [diff] [blame] | 1252 | } | 
| Laurent Pinchart | 5242658 | 2009-10-21 00:03:38 +0200 | [diff] [blame] | 1253 |  | 
|  | 1254 | if (f && f->setup) | 
|  | 1255 | value = f->setup(f, ctrl); | 
|  | 1256 | else { | 
| David Brownell | 40982be | 2008-06-19 17:52:58 -0700 | [diff] [blame] | 1257 | struct usb_configuration	*c; | 
|  | 1258 |  | 
|  | 1259 | c = cdev->config; | 
|  | 1260 | if (c && c->setup) | 
|  | 1261 | value = c->setup(c, ctrl); | 
|  | 1262 | } | 
|  | 1263 |  | 
|  | 1264 | goto done; | 
|  | 1265 | } | 
|  | 1266 |  | 
|  | 1267 | /* respond with data transfer before status phase? */ | 
| Roger Quadros | 1b9ba00 | 2011-05-09 13:08:06 +0300 | [diff] [blame] | 1268 | if (value >= 0 && value != USB_GADGET_DELAYED_STATUS) { | 
| David Brownell | 40982be | 2008-06-19 17:52:58 -0700 | [diff] [blame] | 1269 | req->length = value; | 
|  | 1270 | req->zero = value < w_length; | 
|  | 1271 | value = usb_ep_queue(gadget->ep0, req, GFP_ATOMIC); | 
|  | 1272 | if (value < 0) { | 
|  | 1273 | DBG(cdev, "ep_queue --> %d\n", value); | 
|  | 1274 | req->status = 0; | 
|  | 1275 | composite_setup_complete(gadget->ep0, req); | 
|  | 1276 | } | 
| Roger Quadros | 1b9ba00 | 2011-05-09 13:08:06 +0300 | [diff] [blame] | 1277 | } else if (value == USB_GADGET_DELAYED_STATUS && w_length != 0) { | 
|  | 1278 | WARN(cdev, | 
|  | 1279 | "%s: Delayed status not supported for w_length != 0", | 
|  | 1280 | __func__); | 
| David Brownell | 40982be | 2008-06-19 17:52:58 -0700 | [diff] [blame] | 1281 | } | 
|  | 1282 |  | 
|  | 1283 | done: | 
|  | 1284 | /* device either stalls (value < 0) or reports success */ | 
|  | 1285 | return value; | 
|  | 1286 | } | 
|  | 1287 |  | 
|  | 1288 | static void composite_disconnect(struct usb_gadget *gadget) | 
|  | 1289 | { | 
|  | 1290 | struct usb_composite_dev	*cdev = get_gadget_data(gadget); | 
|  | 1291 | unsigned long			flags; | 
|  | 1292 |  | 
|  | 1293 | /* REVISIT:  should we have config and device level | 
|  | 1294 | * disconnect callbacks? | 
|  | 1295 | */ | 
|  | 1296 | spin_lock_irqsave(&cdev->lock, flags); | 
|  | 1297 | if (cdev->config) | 
|  | 1298 | reset_config(cdev); | 
| Michal Nazarewicz | 3f3e12d | 2010-06-21 13:57:08 +0200 | [diff] [blame] | 1299 | if (composite->disconnect) | 
|  | 1300 | composite->disconnect(cdev); | 
| David Brownell | 40982be | 2008-06-19 17:52:58 -0700 | [diff] [blame] | 1301 | spin_unlock_irqrestore(&cdev->lock, flags); | 
|  | 1302 | } | 
|  | 1303 |  | 
|  | 1304 | /*-------------------------------------------------------------------------*/ | 
|  | 1305 |  | 
| Fabien Chouteau | f48cf80 | 2010-04-23 14:21:26 +0200 | [diff] [blame] | 1306 | static ssize_t composite_show_suspended(struct device *dev, | 
|  | 1307 | struct device_attribute *attr, | 
|  | 1308 | char *buf) | 
|  | 1309 | { | 
|  | 1310 | struct usb_gadget *gadget = dev_to_usb_gadget(dev); | 
|  | 1311 | struct usb_composite_dev *cdev = get_gadget_data(gadget); | 
|  | 1312 |  | 
|  | 1313 | return sprintf(buf, "%d\n", cdev->suspended); | 
|  | 1314 | } | 
|  | 1315 |  | 
|  | 1316 | static DEVICE_ATTR(suspended, 0444, composite_show_suspended, NULL); | 
|  | 1317 |  | 
| Michal Nazarewicz | 28824b1 | 2010-05-05 12:53:13 +0200 | [diff] [blame] | 1318 | static void | 
| David Brownell | 40982be | 2008-06-19 17:52:58 -0700 | [diff] [blame] | 1319 | composite_unbind(struct usb_gadget *gadget) | 
|  | 1320 | { | 
|  | 1321 | struct usb_composite_dev	*cdev = get_gadget_data(gadget); | 
|  | 1322 |  | 
|  | 1323 | /* composite_disconnect() must already have been called | 
|  | 1324 | * by the underlying peripheral controller driver! | 
|  | 1325 | * so there's no i/o concurrency that could affect the | 
|  | 1326 | * state protected by cdev->lock. | 
|  | 1327 | */ | 
|  | 1328 | WARN_ON(cdev->config); | 
|  | 1329 |  | 
|  | 1330 | while (!list_empty(&cdev->configs)) { | 
|  | 1331 | struct usb_configuration	*c; | 
|  | 1332 |  | 
|  | 1333 | c = list_first_entry(&cdev->configs, | 
|  | 1334 | struct usb_configuration, list); | 
|  | 1335 | while (!list_empty(&c->functions)) { | 
|  | 1336 | struct usb_function		*f; | 
|  | 1337 |  | 
|  | 1338 | f = list_first_entry(&c->functions, | 
|  | 1339 | struct usb_function, list); | 
|  | 1340 | list_del(&f->list); | 
|  | 1341 | if (f->unbind) { | 
|  | 1342 | DBG(cdev, "unbind function '%s'/%p\n", | 
|  | 1343 | f->name, f); | 
|  | 1344 | f->unbind(c, f); | 
|  | 1345 | /* may free memory for "f" */ | 
|  | 1346 | } | 
|  | 1347 | } | 
|  | 1348 | list_del(&c->list); | 
|  | 1349 | if (c->unbind) { | 
|  | 1350 | DBG(cdev, "unbind config '%s'/%p\n", c->label, c); | 
|  | 1351 | c->unbind(c); | 
|  | 1352 | /* may free memory for "c" */ | 
|  | 1353 | } | 
|  | 1354 | } | 
|  | 1355 | if (composite->unbind) | 
|  | 1356 | composite->unbind(cdev); | 
|  | 1357 |  | 
|  | 1358 | if (cdev->req) { | 
|  | 1359 | kfree(cdev->req->buf); | 
|  | 1360 | usb_ep_free_request(gadget->ep0, cdev->req); | 
|  | 1361 | } | 
| Pavankumar Kondeti | daba580 | 2010-12-16 14:32:25 +0530 | [diff] [blame] | 1362 | device_remove_file(&gadget->dev, &dev_attr_suspended); | 
| David Brownell | 40982be | 2008-06-19 17:52:58 -0700 | [diff] [blame] | 1363 | kfree(cdev); | 
|  | 1364 | set_gadget_data(gadget, NULL); | 
|  | 1365 | composite = NULL; | 
|  | 1366 | } | 
|  | 1367 |  | 
| Michal Nazarewicz | ad1a810 | 2010-08-12 17:43:46 +0200 | [diff] [blame] | 1368 | static u8 override_id(struct usb_composite_dev *cdev, u8 *desc) | 
| David Brownell | 40982be | 2008-06-19 17:52:58 -0700 | [diff] [blame] | 1369 | { | 
| Michal Nazarewicz | ad1a810 | 2010-08-12 17:43:46 +0200 | [diff] [blame] | 1370 | if (!*desc) { | 
|  | 1371 | int ret = usb_string_id(cdev); | 
|  | 1372 | if (unlikely(ret < 0)) | 
|  | 1373 | WARNING(cdev, "failed to override string ID\n"); | 
|  | 1374 | else | 
|  | 1375 | *desc = ret; | 
| David Brownell | 40982be | 2008-06-19 17:52:58 -0700 | [diff] [blame] | 1376 | } | 
| David Brownell | 40982be | 2008-06-19 17:52:58 -0700 | [diff] [blame] | 1377 |  | 
| Michal Nazarewicz | ad1a810 | 2010-08-12 17:43:46 +0200 | [diff] [blame] | 1378 | return *desc; | 
| David Brownell | 40982be | 2008-06-19 17:52:58 -0700 | [diff] [blame] | 1379 | } | 
|  | 1380 |  | 
| Michal Nazarewicz | 28824b1 | 2010-05-05 12:53:13 +0200 | [diff] [blame] | 1381 | static int composite_bind(struct usb_gadget *gadget) | 
| David Brownell | 40982be | 2008-06-19 17:52:58 -0700 | [diff] [blame] | 1382 | { | 
|  | 1383 | struct usb_composite_dev	*cdev; | 
|  | 1384 | int				status = -ENOMEM; | 
|  | 1385 |  | 
|  | 1386 | cdev = kzalloc(sizeof *cdev, GFP_KERNEL); | 
|  | 1387 | if (!cdev) | 
|  | 1388 | return status; | 
|  | 1389 |  | 
|  | 1390 | spin_lock_init(&cdev->lock); | 
|  | 1391 | cdev->gadget = gadget; | 
|  | 1392 | set_gadget_data(gadget, cdev); | 
|  | 1393 | INIT_LIST_HEAD(&cdev->configs); | 
|  | 1394 |  | 
|  | 1395 | /* preallocate control response and buffer */ | 
|  | 1396 | cdev->req = usb_ep_alloc_request(gadget->ep0, GFP_KERNEL); | 
|  | 1397 | if (!cdev->req) | 
|  | 1398 | goto fail; | 
|  | 1399 | cdev->req->buf = kmalloc(USB_BUFSIZ, GFP_KERNEL); | 
|  | 1400 | if (!cdev->req->buf) | 
|  | 1401 | goto fail; | 
|  | 1402 | cdev->req->complete = composite_setup_complete; | 
|  | 1403 | gadget->ep0->driver_data = cdev; | 
|  | 1404 |  | 
|  | 1405 | cdev->bufsiz = USB_BUFSIZ; | 
|  | 1406 | cdev->driver = composite; | 
|  | 1407 |  | 
| Parirajan Muthalagu | 37b5801 | 2010-08-25 16:33:26 +0530 | [diff] [blame] | 1408 | /* | 
|  | 1409 | * As per USB compliance update, a device that is actively drawing | 
|  | 1410 | * more than 100mA from USB must report itself as bus-powered in | 
|  | 1411 | * the GetStatus(DEVICE) call. | 
|  | 1412 | */ | 
|  | 1413 | if (CONFIG_USB_GADGET_VBUS_DRAW <= USB_SELF_POWER_VBUS_MAX_DRAW) | 
|  | 1414 | usb_gadget_set_selfpowered(gadget); | 
| David Brownell | 40982be | 2008-06-19 17:52:58 -0700 | [diff] [blame] | 1415 |  | 
|  | 1416 | /* interface and string IDs start at zero via kzalloc. | 
|  | 1417 | * we force endpoints to start unassigned; few controller | 
|  | 1418 | * drivers will zero ep->driver_data. | 
|  | 1419 | */ | 
|  | 1420 | usb_ep_autoconfig_reset(cdev->gadget); | 
|  | 1421 |  | 
|  | 1422 | /* composite gadget needs to assign strings for whole device (like | 
|  | 1423 | * serial number), register function drivers, potentially update | 
|  | 1424 | * power state and consumption, etc | 
|  | 1425 | */ | 
| Michal Nazarewicz | 07a18bd | 2010-08-12 17:43:54 +0200 | [diff] [blame] | 1426 | status = composite_gadget_bind(cdev); | 
| David Brownell | 40982be | 2008-06-19 17:52:58 -0700 | [diff] [blame] | 1427 | if (status < 0) | 
|  | 1428 | goto fail; | 
|  | 1429 |  | 
|  | 1430 | cdev->desc = *composite->dev; | 
| David Brownell | 40982be | 2008-06-19 17:52:58 -0700 | [diff] [blame] | 1431 |  | 
| Greg Kroah-Hartman | dbb442b | 2010-12-16 15:52:30 -0800 | [diff] [blame] | 1432 | /* standardized runtime overrides for device ID data */ | 
|  | 1433 | if (idVendor) | 
|  | 1434 | cdev->desc.idVendor = cpu_to_le16(idVendor); | 
|  | 1435 | if (idProduct) | 
|  | 1436 | cdev->desc.idProduct = cpu_to_le16(idProduct); | 
|  | 1437 | if (bcdDevice) | 
|  | 1438 | cdev->desc.bcdDevice = cpu_to_le16(bcdDevice); | 
|  | 1439 |  | 
| Marek Belisko | 78bff3c | 2010-10-27 10:19:01 +0200 | [diff] [blame] | 1440 | /* string overrides */ | 
| Michal Nazarewicz | ad1a810 | 2010-08-12 17:43:46 +0200 | [diff] [blame] | 1441 | if (iManufacturer || !cdev->desc.iManufacturer) { | 
|  | 1442 | if (!iManufacturer && !composite->iManufacturer && | 
|  | 1443 | !*composite_manufacturer) | 
|  | 1444 | snprintf(composite_manufacturer, | 
|  | 1445 | sizeof composite_manufacturer, | 
|  | 1446 | "%s %s with %s", | 
|  | 1447 | init_utsname()->sysname, | 
|  | 1448 | init_utsname()->release, | 
|  | 1449 | gadget->name); | 
| David Brownell | 40982be | 2008-06-19 17:52:58 -0700 | [diff] [blame] | 1450 |  | 
| Michal Nazarewicz | ad1a810 | 2010-08-12 17:43:46 +0200 | [diff] [blame] | 1451 | cdev->manufacturer_override = | 
|  | 1452 | override_id(cdev, &cdev->desc.iManufacturer); | 
|  | 1453 | } | 
|  | 1454 |  | 
|  | 1455 | if (iProduct || (!cdev->desc.iProduct && composite->iProduct)) | 
|  | 1456 | cdev->product_override = | 
|  | 1457 | override_id(cdev, &cdev->desc.iProduct); | 
|  | 1458 |  | 
|  | 1459 | if (iSerialNumber) | 
|  | 1460 | cdev->serial_override = | 
|  | 1461 | override_id(cdev, &cdev->desc.iSerialNumber); | 
|  | 1462 |  | 
|  | 1463 | /* has userspace failed to provide a serial number? */ | 
|  | 1464 | if (composite->needs_serial && !cdev->desc.iSerialNumber) | 
|  | 1465 | WARNING(cdev, "userspace failed to provide iSerialNumber\n"); | 
|  | 1466 |  | 
|  | 1467 | /* finish up */ | 
| Fabien Chouteau | f48cf80 | 2010-04-23 14:21:26 +0200 | [diff] [blame] | 1468 | status = device_create_file(&gadget->dev, &dev_attr_suspended); | 
|  | 1469 | if (status) | 
|  | 1470 | goto fail; | 
|  | 1471 |  | 
| David Brownell | 40982be | 2008-06-19 17:52:58 -0700 | [diff] [blame] | 1472 | INFO(cdev, "%s ready\n", composite->name); | 
|  | 1473 | return 0; | 
|  | 1474 |  | 
|  | 1475 | fail: | 
|  | 1476 | composite_unbind(gadget); | 
|  | 1477 | return status; | 
|  | 1478 | } | 
|  | 1479 |  | 
|  | 1480 | /*-------------------------------------------------------------------------*/ | 
|  | 1481 |  | 
|  | 1482 | static void | 
|  | 1483 | composite_suspend(struct usb_gadget *gadget) | 
|  | 1484 | { | 
|  | 1485 | struct usb_composite_dev	*cdev = get_gadget_data(gadget); | 
|  | 1486 | struct usb_function		*f; | 
|  | 1487 |  | 
| David Brownell | 8942939 | 2009-03-19 14:14:17 -0700 | [diff] [blame] | 1488 | /* REVISIT:  should we have config level | 
| David Brownell | 40982be | 2008-06-19 17:52:58 -0700 | [diff] [blame] | 1489 | * suspend/resume callbacks? | 
|  | 1490 | */ | 
|  | 1491 | DBG(cdev, "suspend\n"); | 
|  | 1492 | if (cdev->config) { | 
|  | 1493 | list_for_each_entry(f, &cdev->config->functions, list) { | 
|  | 1494 | if (f->suspend) | 
|  | 1495 | f->suspend(f); | 
|  | 1496 | } | 
|  | 1497 | } | 
| David Brownell | 8942939 | 2009-03-19 14:14:17 -0700 | [diff] [blame] | 1498 | if (composite->suspend) | 
|  | 1499 | composite->suspend(cdev); | 
| Fabien Chouteau | f48cf80 | 2010-04-23 14:21:26 +0200 | [diff] [blame] | 1500 |  | 
|  | 1501 | cdev->suspended = 1; | 
| Hao Wu | b23f2f9 | 2010-11-29 15:17:03 +0800 | [diff] [blame] | 1502 |  | 
|  | 1503 | usb_gadget_vbus_draw(gadget, 2); | 
| David Brownell | 40982be | 2008-06-19 17:52:58 -0700 | [diff] [blame] | 1504 | } | 
|  | 1505 |  | 
|  | 1506 | static void | 
|  | 1507 | composite_resume(struct usb_gadget *gadget) | 
|  | 1508 | { | 
|  | 1509 | struct usb_composite_dev	*cdev = get_gadget_data(gadget); | 
|  | 1510 | struct usb_function		*f; | 
| Hao Wu | b23f2f9 | 2010-11-29 15:17:03 +0800 | [diff] [blame] | 1511 | u8				maxpower; | 
| David Brownell | 40982be | 2008-06-19 17:52:58 -0700 | [diff] [blame] | 1512 |  | 
| David Brownell | 8942939 | 2009-03-19 14:14:17 -0700 | [diff] [blame] | 1513 | /* REVISIT:  should we have config level | 
| David Brownell | 40982be | 2008-06-19 17:52:58 -0700 | [diff] [blame] | 1514 | * suspend/resume callbacks? | 
|  | 1515 | */ | 
|  | 1516 | DBG(cdev, "resume\n"); | 
| David Brownell | 8942939 | 2009-03-19 14:14:17 -0700 | [diff] [blame] | 1517 | if (composite->resume) | 
|  | 1518 | composite->resume(cdev); | 
| David Brownell | 40982be | 2008-06-19 17:52:58 -0700 | [diff] [blame] | 1519 | if (cdev->config) { | 
|  | 1520 | list_for_each_entry(f, &cdev->config->functions, list) { | 
|  | 1521 | if (f->resume) | 
|  | 1522 | f->resume(f); | 
|  | 1523 | } | 
| Hao Wu | b23f2f9 | 2010-11-29 15:17:03 +0800 | [diff] [blame] | 1524 |  | 
|  | 1525 | maxpower = cdev->config->bMaxPower; | 
|  | 1526 |  | 
|  | 1527 | usb_gadget_vbus_draw(gadget, maxpower ? | 
|  | 1528 | (2 * maxpower) : CONFIG_USB_GADGET_VBUS_DRAW); | 
| David Brownell | 40982be | 2008-06-19 17:52:58 -0700 | [diff] [blame] | 1529 | } | 
| Fabien Chouteau | f48cf80 | 2010-04-23 14:21:26 +0200 | [diff] [blame] | 1530 |  | 
|  | 1531 | cdev->suspended = 0; | 
| David Brownell | 40982be | 2008-06-19 17:52:58 -0700 | [diff] [blame] | 1532 | } | 
|  | 1533 |  | 
|  | 1534 | /*-------------------------------------------------------------------------*/ | 
|  | 1535 |  | 
|  | 1536 | static struct usb_gadget_driver composite_driver = { | 
| Tatyana Brokhman | bdb64d7 | 2011-06-29 16:41:50 +0300 | [diff] [blame] | 1537 | #ifdef CONFIG_USB_GADGET_SUPERSPEED | 
|  | 1538 | .speed		= USB_SPEED_SUPER, | 
|  | 1539 | #else | 
| David Brownell | 40982be | 2008-06-19 17:52:58 -0700 | [diff] [blame] | 1540 | .speed		= USB_SPEED_HIGH, | 
| Tatyana Brokhman | bdb64d7 | 2011-06-29 16:41:50 +0300 | [diff] [blame] | 1541 | #endif | 
| David Brownell | 40982be | 2008-06-19 17:52:58 -0700 | [diff] [blame] | 1542 |  | 
| Michal Nazarewicz | 915c8be | 2009-11-09 14:15:25 +0100 | [diff] [blame] | 1543 | .unbind		= composite_unbind, | 
| David Brownell | 40982be | 2008-06-19 17:52:58 -0700 | [diff] [blame] | 1544 |  | 
|  | 1545 | .setup		= composite_setup, | 
|  | 1546 | .disconnect	= composite_disconnect, | 
|  | 1547 |  | 
|  | 1548 | .suspend	= composite_suspend, | 
|  | 1549 | .resume		= composite_resume, | 
|  | 1550 |  | 
|  | 1551 | .driver	= { | 
|  | 1552 | .owner		= THIS_MODULE, | 
|  | 1553 | }, | 
|  | 1554 | }; | 
|  | 1555 |  | 
|  | 1556 | /** | 
| Michal Nazarewicz | 07a18bd | 2010-08-12 17:43:54 +0200 | [diff] [blame] | 1557 | * usb_composite_probe() - register a composite driver | 
| David Brownell | 40982be | 2008-06-19 17:52:58 -0700 | [diff] [blame] | 1558 | * @driver: the driver to register | 
| Michal Nazarewicz | 07a18bd | 2010-08-12 17:43:54 +0200 | [diff] [blame] | 1559 | * @bind: the callback used to allocate resources that are shared across the | 
|  | 1560 | *	whole device, such as string IDs, and add its configurations using | 
|  | 1561 | *	@usb_add_config().  This may fail by returning a negative errno | 
|  | 1562 | *	value; it should return zero on successful initialization. | 
| David Brownell | 40982be | 2008-06-19 17:52:58 -0700 | [diff] [blame] | 1563 | * Context: single threaded during gadget setup | 
|  | 1564 | * | 
|  | 1565 | * This function is used to register drivers using the composite driver | 
|  | 1566 | * framework.  The return value is zero, or a negative errno value. | 
|  | 1567 | * Those values normally come from the driver's @bind method, which does | 
|  | 1568 | * all the work of setting up the driver to match the hardware. | 
|  | 1569 | * | 
|  | 1570 | * On successful return, the gadget is ready to respond to requests from | 
|  | 1571 | * the host, unless one of its components invokes usb_gadget_disconnect() | 
|  | 1572 | * while it was binding.  That would usually be done in order to wait for | 
|  | 1573 | * some userspace participation. | 
|  | 1574 | */ | 
| Jassi Brar | 05c3eeb | 2011-02-06 18:47:18 +0900 | [diff] [blame] | 1575 | int usb_composite_probe(struct usb_composite_driver *driver, | 
| Michal Nazarewicz | 07a18bd | 2010-08-12 17:43:54 +0200 | [diff] [blame] | 1576 | int (*bind)(struct usb_composite_dev *cdev)) | 
| David Brownell | 40982be | 2008-06-19 17:52:58 -0700 | [diff] [blame] | 1577 | { | 
| Michal Nazarewicz | 07a18bd | 2010-08-12 17:43:54 +0200 | [diff] [blame] | 1578 | if (!driver || !driver->dev || !bind || composite) | 
| David Brownell | 40982be | 2008-06-19 17:52:58 -0700 | [diff] [blame] | 1579 | return -EINVAL; | 
|  | 1580 |  | 
|  | 1581 | if (!driver->name) | 
|  | 1582 | driver->name = "composite"; | 
| Jassi Brar | 05c3eeb | 2011-02-06 18:47:18 +0900 | [diff] [blame] | 1583 | if (!driver->iProduct) | 
|  | 1584 | driver->iProduct = driver->name; | 
| David Brownell | 40982be | 2008-06-19 17:52:58 -0700 | [diff] [blame] | 1585 | composite_driver.function =  (char *) driver->name; | 
|  | 1586 | composite_driver.driver.name = driver->name; | 
| Tatyana Brokhman | 35a0e0b | 2011-06-29 16:41:49 +0300 | [diff] [blame] | 1587 | composite_driver.speed = min((u8)composite_driver.speed, | 
|  | 1588 | (u8)driver->max_speed); | 
| David Brownell | 40982be | 2008-06-19 17:52:58 -0700 | [diff] [blame] | 1589 | composite = driver; | 
| Michal Nazarewicz | 07a18bd | 2010-08-12 17:43:54 +0200 | [diff] [blame] | 1590 | composite_gadget_bind = bind; | 
| David Brownell | 40982be | 2008-06-19 17:52:58 -0700 | [diff] [blame] | 1591 |  | 
| Uwe Kleine-König | b0fca50 | 2010-08-12 17:43:53 +0200 | [diff] [blame] | 1592 | return usb_gadget_probe_driver(&composite_driver, composite_bind); | 
| David Brownell | 40982be | 2008-06-19 17:52:58 -0700 | [diff] [blame] | 1593 | } | 
|  | 1594 |  | 
|  | 1595 | /** | 
|  | 1596 | * usb_composite_unregister() - unregister a composite driver | 
|  | 1597 | * @driver: the driver to unregister | 
|  | 1598 | * | 
|  | 1599 | * This function is used to unregister drivers using the composite | 
|  | 1600 | * driver framework. | 
|  | 1601 | */ | 
| Michal Nazarewicz | 28824b1 | 2010-05-05 12:53:13 +0200 | [diff] [blame] | 1602 | void usb_composite_unregister(struct usb_composite_driver *driver) | 
| David Brownell | 40982be | 2008-06-19 17:52:58 -0700 | [diff] [blame] | 1603 | { | 
|  | 1604 | if (composite != driver) | 
|  | 1605 | return; | 
|  | 1606 | usb_gadget_unregister_driver(&composite_driver); | 
|  | 1607 | } | 
| Roger Quadros | 1b9ba00 | 2011-05-09 13:08:06 +0300 | [diff] [blame] | 1608 |  | 
|  | 1609 | /** | 
|  | 1610 | * usb_composite_setup_continue() - Continue with the control transfer | 
|  | 1611 | * @cdev: the composite device who's control transfer was kept waiting | 
|  | 1612 | * | 
|  | 1613 | * This function must be called by the USB function driver to continue | 
|  | 1614 | * with the control transfer's data/status stage in case it had requested to | 
|  | 1615 | * delay the data/status stages. A USB function's setup handler (e.g. set_alt()) | 
|  | 1616 | * can request the composite framework to delay the setup request's data/status | 
|  | 1617 | * stages by returning USB_GADGET_DELAYED_STATUS. | 
|  | 1618 | */ | 
|  | 1619 | void usb_composite_setup_continue(struct usb_composite_dev *cdev) | 
|  | 1620 | { | 
|  | 1621 | int			value; | 
|  | 1622 | struct usb_request	*req = cdev->req; | 
|  | 1623 | unsigned long		flags; | 
|  | 1624 |  | 
|  | 1625 | DBG(cdev, "%s\n", __func__); | 
|  | 1626 | spin_lock_irqsave(&cdev->lock, flags); | 
|  | 1627 |  | 
|  | 1628 | if (cdev->delayed_status == 0) { | 
|  | 1629 | WARN(cdev, "%s: Unexpected call\n", __func__); | 
|  | 1630 |  | 
|  | 1631 | } else if (--cdev->delayed_status == 0) { | 
|  | 1632 | DBG(cdev, "%s: Completing delayed status\n", __func__); | 
|  | 1633 | req->length = 0; | 
|  | 1634 | value = usb_ep_queue(cdev->gadget->ep0, req, GFP_ATOMIC); | 
|  | 1635 | if (value < 0) { | 
|  | 1636 | DBG(cdev, "ep_queue --> %d\n", value); | 
|  | 1637 | req->status = 0; | 
|  | 1638 | composite_setup_complete(cdev->gadget->ep0, req); | 
|  | 1639 | } | 
|  | 1640 | } | 
|  | 1641 |  | 
|  | 1642 | spin_unlock_irqrestore(&cdev->lock, flags); | 
|  | 1643 | } | 
|  | 1644 |  |