/* <linux/usb/composite.h> */ #ifndef __LINUX_USB_COMPOSITE_H #define __LINUX_USB_COMPOSITE_H #ifdef __KERNEL__ #include <linux/usb/ch9.h> #include <linux/usb_gadget.h> /* Support for composite configs, built from distinct function drivers. * Example: one offering both network and mass storage functionality. */ struct usb_composite_dev; struct usb_composite_driver; /** * struct usb_function - describes one function of a composite configuration * @name: for diagnostics, identifies the function * @strings: tables of strings, keyed by identifiers assigned during bind() * and language IDs provided in control requests * @descriptors: table of low/full speed descriptors, using interface and * string identifiers assigned during bind() * @hs_descriptors: table of high speed descriptors, using interface and * string identifiers assigned during bind(); or null * @function: each function is on the usb_composite.function list when the * composite gadget is initialized, and then places itself in the right * position(s) in usb_composite.functions[] during bind() * @bind: before the gadget can register, all of its functions bind() to the * available resources including identifiers for strings, interfaces, * and endpoints * @unbind: before the gadget can unregister, all of its functions unbind() * the resources they have allocated. * @setup: used for SET_INTERFACE, SET_CONFIGURATION, and interface-specific * control requests * @disconnect: used to notify functions when the host has disconnected * @suspend: notifies functions when the host stops sending USB traffic * @disconnect: notifies functions when the host reactivates the USB link * * A single USB function uses one or more interfaces, and supports dual speed * operation on appropriate hardware. * * Only one instance of a function may be associated with a given composite * configuration. Accordingly, data which a function driver needs in order * to implement any callback can reasonably be static to that driver's module, * or part of a structure within which the function struct has been embedded. */ struct usb_function { const char *name; struct usb_gadget_strings **strings; const struct usb_descriptor_header **descriptors; const struct usb_descriptor_header **hs_descriptors; struct list_head function; void *private_data; /* REVISIT want multi-config at *same* speed too ... * e.g. one has RNDIS, another has CDC-Ethernet * not just high speed versions of each. */ int (*bind)(struct usb_composite_dev *, struct usb_function *); void (*unbind)(struct usb_composite_dev *, struct usb_function *); int (*setup)(struct usb_composite_dev *, const struct usb_ctrlrequest *,struct usb_function *); void (*disconnect)(struct usb_composite_dev *,struct usb_function *); void (*suspend)(struct usb_composite_dev *); void (*resume)(struct usb_composite_dev *); }; /** * struct usb_composite_driver -- groups functions into one gadget config * @name: for diagnostics, identifies the driver * @dev: descriptor for the device * @strings: tables of strings, keyed by identifiers assigned during bind() * and language IDs provided in control requests * @bind: Used to build the list of functions, and to allocate for resources * shared across the whole device such as string IDs. This can update * device and configuration descriptors before functions bind(). * @unbind: optionally reverses bind() * @setup: optionally used to delegate class and vendor control requests * * As with any gadget driver, there may be only one per system. Data that a * composite gadget driver needs to implement any callback can reasonably be * static to that driver's module, or part of a structure within which the * driver struct has been embedded. * * FIXME device descriptor shouldn't be part of a per-config structure... */ struct usb_composite_driver { const char *name; const struct usb_device_descriptor *dev; struct usb_gadget_strings **strings; /* REVISIT want a general "add more descriptors for config N" * hook; OTG should fall out naturally */ int (*bind)(struct usb_composite_dev *); int (*unbind)(struct usb_composite_dev *); int (*setup)(struct usb_composite_dev *, const struct usb_ctrlrequest *); void (*suspend)(struct usb_composite_dev *); void (*suspend)(struct usb_composite_dev *); /* REVISIT disconnect(), suspend(), resume() too ?? */ }; extern int usb_composite_register(struct usb_composite_driver *); extern void usb_composite_unregister(struct usb_composite_driver *); #define MAX_COMPOSITE_INTERFACES 8 /* max 16 */ /** * struct usb_composite_device - represents one composite usb gadget * @gadget: read-only, abstracts the gadget's usb peripheral controller * @req: used for control responses; buffer is pre-allocated * @bufsiz: size of buffer pre-allocated in @req * @dev: device descriptor * @functions: each function on this list after driver->bind() returns * will be bound and initialized * @config: configuration descriptor; if the device is not configured, * its bConfigurationValue is zero and other fields are ignored * * REVISIT: this represents a composite configuration, and should * be renamed accordingly... */ struct usb_composite_dev { /* lock protects writes to all fields of this structure */ spinlock_t lock; struct usb_gadget *gadget; struct usb_request *req; unsigned bufsiz; struct usb_device_descriptor dev; struct usb_config_descriptor config; /* REVISIT need per-function state hook ... maybe a * (void*) returned from bind() and passed to callbacks? * arguably, interface descriptors are part of that... */ struct list_head functions; struct usb_composite_driver *driver; /* fields in the config descriptor */ u8 iConfiguration; u8 bmAttributes; u8 bMaxPower; /* INTERNALS -- not for function drivers */ u8 next_string_id; u8 next_interface_id; void *current_bind; struct usb_function *interface[MAX_COMPOSITE_INTERFACES]; struct usb_qualifier_descriptor qual; }; /* IDs may be assigned ONLY during function driver bind() */ extern int usb_composite_string_id(struct usb_composite_dev *c); extern int usb_composite_interface_id(struct usb_composite_dev *c); static inline void usb_composite_add_function(struct usb_composite_dev *c, struct usb_function *f) { list_add_tail(&f->function, &c->functions); } #endif /* __KERNEL__ */ #endif /* __LINUX_USB_COMPOSITE_H */
/* * composite.c - infrastructure for Composite USB Gadgets * * Copyright (C) 2006-2007 David Brownell * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ /* #define VERBOSE_DEBUG */ #include <linux/kernel.h> #include <linux/slab.h> #include <linux/device.h> #include <linux/usb/g_composite.h> /* * The code in this file is utility code, used to build a gadget driver * from one or more "function" drivers and a "usb_composite_driver" to * glue them together along with the relevant device-wide data. */ #define DBG(comp, fmt, args...) \ dev_dbg(&(comp)->gadget->dev , fmt , ## args) #define VDBG(comp, fmt, args...) \ dev_vdbg(&(comp)->gadget->dev , fmt , ## args) #define ERROR(comp, fmt, args...) \ dev_err(&(comp)->gadget->dev , fmt , ## args) #define WARN(comp, fmt, args...) \ dev_warn(&(comp)->gadget->dev , fmt , ## args) #define INFO(comp, fmt, args...) \ dev_info(&(comp)->gadget->dev , fmt , ## args) /* big enough to hold our biggest descriptor */ #define USB_BUFSIZ 512 static struct usb_composite_driver *composite; static struct usb_composite_dev *cdev; /* Some systems will need runtime overrides for the product identifers * published in the device descriptor, either numbers or strings or both. * String parameters are in UTF-8 (superset of ASCII's 7 bit characters). */ #if 0 static ushort idVendor; module_param(idVendor, ushort, S_IRUGO); MODULE_PARM_DESC(idVendor, "USB Vendor ID"); static ushort idProduct; module_param(idProduct, ushort, S_IRUGO); MODULE_PARM_DESC(idProduct, "USB Product ID"); static ushort bcdDevice; module_param(bcdDevice, ushort, S_IRUGO); MODULE_PARM_DESC(bcdDevice, "USB Device version (BCD)"); static char *iManufacturer; module_param(iManufacturer, charp, S_IRUGO); MODULE_PARM_DESC(iManufacturer, "USB Manufacturer string"); static char *iProduct; module_param(iProduct, charp, S_IRUGO); MODULE_PARM_DESC(iProduct, "USB Product string"); static char *iSerialNumber; module_param(iSerialNumber, charp, S_IRUGO); MODULE_PARM_DESC(iSerialNumber, "SerialNumber string"); #endif /*-------------------------------------------------------------------------*/ /* To simplify, we expect to have only ONE real configuration, working the * same no matter what speed it connects with. A given function may expose * multiple interfaces. Each interface includes its descriptor, plus optional * class and endpoint descriptors (as usual). * * Note that the configuration numbers are *NOT* related to how many configs * a device has ... some hardware places restrictions on config numbers. * So having a single configuration, number 3, would be fine. * * REVISIT we do need to lift this restriction, at least for RNDIS. * For PXA compat, stick to config numbers 1, 2, and 3; for SH, just 1. */ #define CONFIG_NUMBER 1 static int config_buf(void *buf, u8 type) { struct usb_config_descriptor *c = buf; void *next = buf + USB_DT_CONFIG_SIZE; int len = USB_BUFSIZ - USB_DT_CONFIG_SIZE; int hs; struct usb_function *f; INFO(cdev, "config buf\n"); if (gadget_is_dualspeed(cdev->gadget)) { hs = (cdev->gadget->speed == USB_SPEED_HIGH); if (type == USB_DT_OTHER_SPEED_CONFIG) hs = !hs; } else hs = 0; /* write a config descriptor */ *c = cdev->config; c->bLength = USB_DT_CONFIG_SIZE; c->bDescriptorType = type; c->bConfigurationValue = CONFIG_NUMBER; c->iConfiguration = cdev->iConfiguration; c->bmAttributes = USB_CONFIG_ATT_ONE | cdev->bmAttributes; c->bMaxPower = cdev->bMaxPower; INFO(cdev, "device config\n"); /* REVISIT some configurations might need other descriptors, * independent of the interfaces they implement ... notably * OTG descriptors. */ /* add each function's descriptors */ INFO(cdev, "speed: %d\n",hs); list_for_each_entry(f, &cdev->functions, function) { int status; status = usb_descriptor_fillbuf(next, len, hs ? f->hs_descriptors : f->descriptors); if (status < 0) return status; len -= status; next += status; INFO(cdev, "interface config\n"); } len = next - buf; c->wTotalLength = cpu_to_le16(len); return len; } /*-------------------------------------------------------------------------*/ static void composite_reset_config(struct usb_ctrlrequest *req) { struct usb_function *f; int result; DBG(cdev, "reset config\n"); req->bRequestType = USB_DIR_OUT | USB_TYPE_STANDARD | USB_RECIP_DEVICE; req->bRequest = USB_REQ_SET_CONFIGURATION; list_for_each_entry(f, &cdev->functions, function) { result = f->setup(cdev, req,f); if (result < 0) DBG(cdev, "reset function %s --> %d\n", f->name, result); } cdev->config.bConfigurationValue = 0; } static int composite_set_config(const struct usb_ctrlrequest *ctrl, unsigned number) { int result = 0; int tmp; struct usb_gadget *gadget = cdev->gadget; struct usb_ctrlrequest req; memset(&req, 0, sizeof req); /* for now function drivers should assume SET_CONFIGURATION means * reset/deconfigure, with SET_INTERFACE to each interface used * to activate some altsetting in "the single" configuration. */ composite_reset_config(&req); switch (number) { default: result = -EINVAL; req.wValue = cpu_to_le16(0); /* FALLTHROUGH */ case 0: for (tmp = 0; tmp < MAX_COMPOSITE_INTERFACES; tmp++) { struct usb_function *f = cdev->interface[tmp]; if (!f) continue; f->setup(cdev, ctrl, f); } usb_gadget_vbus_draw(gadget, gadget_is_otg(gadget) ? 8 : 100); break; case CONFIG_NUMBER: req.bRequestType = USB_DIR_OUT | USB_TYPE_STANDARD | USB_RECIP_INTERFACE; req.bRequest = USB_REQ_SET_INTERFACE; for (tmp = 0; tmp < MAX_COMPOSITE_INTERFACES; tmp++) { struct usb_function *f = cdev->interface[tmp]; if (!f) continue; req.wIndex = cpu_to_le16(tmp); result = f->setup(cdev, &req, f); if (result < 0) { DBG(cdev, "interface %d/%s alt 0--> %d\n", tmp, f->name, result); (void) composite_set_config(ctrl, 0); return result; } } cdev->config.bConfigurationValue = number; usb_gadget_vbus_draw(gadget, 2 * cdev->config.bMaxPower); break; } INFO(cdev, "%s speed config #%d\n", ({ char *speed; switch (gadget->speed) { case USB_SPEED_LOW: speed = "low"; break; case USB_SPEED_FULL: speed = "full"; break; case USB_SPEED_HIGH: speed = "high"; break; default: speed = "?"; break; } ; speed; }), number); return result; } /*-------------------------------------------------------------------------*/ static void composite_collect_langs(struct usb_gadget_strings **sp, __le16 *buf) { const struct usb_gadget_strings *s; u16 language; __le16 *tmp; while (*sp) { s = *sp; language = cpu_to_le16(s->language); for (tmp = buf; *tmp && tmp < &buf[126]; tmp++) { if (*tmp == language) goto repeat; } *tmp++ = language; repeat: sp++; } } static int composite_check_string( struct usb_gadget_strings **sp, void *buf, u16 language, int id ) { struct usb_gadget_strings *s; int value; while (*sp) { s = *sp++; if (s->language != language) continue; value = usb_gadget_get_string(s, id, buf); if (value > 0) return value; } return -EINVAL; } static int composite_lookup_string(void *buf, u16 language, int id) { struct usb_function *f; int len; /* 0 == report all available language codes */ if (id == 0) { struct usb_string_descriptor *s = buf; struct usb_gadget_strings **sp; memset(s, 0, 256); s->bDescriptorType = USB_DT_STRING; sp = composite->strings; if (sp) composite_collect_langs(sp, s->wData); list_for_each_entry(f, &cdev->functions, function) { sp = f->strings; if (sp) composite_collect_langs(sp, s->wData); } for (len = 0; s->wData[len] && len <= 126; len++) continue; if (!len) return -EINVAL; s->bLength = 2 * (len + 1); return s->bLength; } /* otherwise, look up and return a specified string */ if (composite->strings) { len = composite_check_string(composite->strings, buf, language, id); if (len > 0) return len; } list_for_each_entry(f, &cdev->functions, function) { if (!f->strings) continue; len = composite_check_string(f->strings, buf, language, id); if (len > 0) return len; } return -EINVAL; } /*-------------------------------------------------------------------------*/ static void composite_setup_complete(struct usb_ep *ep, struct usb_request *req) { if (req->status || req->actual != req->length) DBG((struct usb_composite_dev *) ep->driver_data, "setup complete --> %d, %d/%d\n", req->status, req->actual, req->length); } /* * The setup() callback implements all the ep0 functionality that's * not handled lower down, in hardware or the hardware driver(like * device and endpoint feature flags, and their status). It's all * housekeeping for the gadget function we're implementing. Most of * the work is in config-specific setup. */ static int composite_setup(struct usb_gadget *gadget, const struct usb_ctrlrequest *ctrl) { struct usb_composite_dev *cdev = get_gadget_data(gadget); struct usb_request *req = cdev->req; int value = -EOPNOTSUPP; u16 w_index = le16_to_cpu(ctrl->wIndex); u16 w_value = le16_to_cpu(ctrl->wValue); u16 w_length = le16_to_cpu(ctrl->wLength); int tmp,result; /* partial re-init of the response message; the function or the * gadget might need to intercept e.g. a control-OUT completion. */ req->zero = 0; req->complete = composite_setup_complete; gadget->ep0->driver_data = cdev; INFO(cdev, "control req %02x.%02x v %04x i %04x l %d\n", ctrl->bRequestType, ctrl->bRequest, w_value, w_index, w_length); if((ctrl->bRequestType&USB_TYPE_MASK) != USB_TYPE_STANDARD) { for (tmp = 0; tmp < MAX_COMPOSITE_INTERFACES; tmp++) { struct usb_function *f = cdev->interface[tmp]; if (!f) continue; result = f->setup(cdev, ctrl, f); if(result > 0) value = result; value = min(w_length, (u16) value); } ((char *)(req->buf))[value]=0; INFO(cdev, "Result Len: %d %s\n",value,&req->buf[2]); } else { switch (ctrl->bRequest) { case USB_REQ_GET_DESCRIPTOR: if (ctrl->bRequestType != USB_DIR_IN) goto unknown; switch (w_value >> 8) { case USB_DT_DEVICE: value = min(w_length, (u16) sizeof cdev->dev); memcpy(req->buf, &cdev->dev, value); break; case USB_DT_DEVICE_QUALIFIER: if (!gadget_is_dualspeed(gadget)) break; value = min(w_length, (u16) sizeof cdev->qual); memcpy(req->buf, &cdev->qual, value); break; case USB_DT_OTHER_SPEED_CONFIG: if (!gadget_is_dualspeed(gadget)) break; /* FALLTHROUGH */ case USB_DT_CONFIG: INFO(cdev, "Get Config Descriptor\n"); /* one config ... so it must always be index 0 */ if (w_value & 0xff) break; value = config_buf(req->buf, w_value >> 8); if (value >= 0) value = min(w_length, (u16) value); break; case USB_DT_STRING: value = composite_lookup_string(req->buf, w_index, w_value & 0xff); if (value >= 0) value = min(w_length, (u16) value); break; } break; /* currently one config, two speeds */ case USB_REQ_SET_CONFIGURATION: if (ctrl->bRequestType != 0) goto unknown; if (gadget->a_hnp_support) DBG(cdev, "HNP available\n"); else if (gadget->a_alt_hnp_support) DBG(cdev, "HNP needs a different root port\n"); else VDBG(cdev, "HNP inactive\n"); spin_lock(&cdev->lock); value = composite_set_config(ctrl, w_value); spin_unlock(&cdev->lock); break; case USB_REQ_GET_CONFIGURATION: if (ctrl->bRequestType != USB_DIR_IN) goto unknown; *(u8 *)req->buf = cdev->config.bConfigurationValue; value = min(w_length, (u16) 1); break; /* function drivers must handle get/set altsetting */ case USB_REQ_SET_INTERFACE: if (ctrl->bRequestType != USB_RECIP_INTERFACE) goto unknown; if (!cdev->config.bConfigurationValue || w_index >= MAX_COMPOSITE_INTERFACES || !cdev->interface[w_index]) break; spin_lock(&cdev->lock); value = cdev->interface[w_index]->setup(cdev, ctrl, cdev->interface[w_index]); spin_unlock(&cdev->lock); break; case USB_REQ_GET_INTERFACE: if (ctrl->bRequestType != (USB_DIR_IN|USB_RECIP_INTERFACE)) goto unknown; if (!cdev->config.bConfigurationValue || w_index >= MAX_COMPOSITE_INTERFACES || !cdev->interface[w_index]) break; spin_lock(&cdev->lock); /* function must set cdev->req->buf[0] */ value = cdev->interface[w_index]->setup(cdev, ctrl, cdev->interface[w_index]); spin_unlock(&cdev->lock); value = min(w_length, (u16) 1); break; default: unknown: VDBG(cdev, "unknown control req%02x.%02x v%04x i%04x l%d\n", ctrl->bRequestType, ctrl->bRequest, w_value, w_index, w_length); } } /* respond with data transfer before status phase? */ if (value >= 0) { req->length = value; req->zero = (value < w_length) && ((value % gadget->ep0->maxpacket) == 0); value = usb_ep_queue(gadget->ep0, req, GFP_ATOMIC); if (value < 0) { INFO(cdev, "ep_queue --> %d\n", value); req->status = 0; composite_setup_complete(gadget->ep0, req); } } /* device either stalls (value < 0) or reports success */ return value; } static void composite_disconnect(struct usb_gadget *gadget) { struct usb_composite_dev *cdev = get_gadget_data(gadget); unsigned long flags; struct usb_ctrlrequest req; DBG(cdev, "disconnect\n"); memset(&req, 0, sizeof req); spin_lock_irqsave(&cdev->lock, flags); composite_reset_config(&req); spin_unlock_irqrestore(&cdev->lock, flags); } /*-------------------------------------------------------------------------*/ static void /* __init_or_exit */ composite_unbind(struct usb_gadget *gadget) { struct usb_composite_dev *cdev = get_gadget_data(gadget); struct usb_function *f; DBG(cdev, "unbind\n"); list_for_each_entry(f, &cdev->functions, function) { if (f->unbind) f->unbind(cdev, f); if (f == cdev->current_bind) break; } if (composite->unbind) composite->unbind(cdev); if (cdev->req) { kfree(cdev->req->buf); usb_ep_free_request(gadget->ep0, cdev->req); } kfree(cdev); set_gadget_data(gadget, NULL); composite = NULL; } static void string_override_one(struct usb_gadget_strings *tab, u8 id, const char *s) { struct usb_string *str = tab->strings; for (str = tab->strings; str->s; str++) { if (str->id == id) { str->s = s; return; } } } static void string_override(struct usb_gadget_strings **tab, u8 id, const char *s) { while (*tab) { string_override_one(*tab, id, s); tab++; } } static int __init composite_bind(struct usb_gadget *gadget) { struct usb_function *f; int status = -ENOMEM; if (cdev) return -EBUSY; cdev = kzalloc(sizeof *cdev, GFP_KERNEL); if (!cdev) return status; spin_lock_init(&cdev->lock); cdev->gadget = gadget; set_gadget_data(gadget, cdev); INIT_LIST_HEAD(&cdev->functions); /* preallocate control response and buffer */ cdev->req = usb_ep_alloc_request(gadget->ep0, GFP_KERNEL); if (!cdev->req) goto fail; cdev->req->buf = kmalloc(USB_BUFSIZ, GFP_KERNEL); if (!cdev->req->buf) goto fail; cdev->req->complete = composite_setup_complete; gadget->ep0->driver_data = cdev; cdev->bufsiz = USB_BUFSIZ; cdev->driver = composite; usb_gadget_set_selfpowered(gadget); /* interface and string IDs start at zero */ usb_ep_autoconfig_reset(gadget); /* composite gadget needs to assign strings for whole device (like * serial number), register function drivers, potentially update * power state and consumption, etc */ cdev->current_bind = gadget; status = composite->bind(cdev); if (status < 0) goto fail; cdev->current_bind = NULL; cdev->dev = *composite->dev; cdev->dev.bMaxPacketSize0 = gadget->ep0->maxpacket; /* standardized runtime overrides for device ID data */ /*if (idVendor) cdev->dev.idVendor = idVendor; if (idProduct) cdev->dev.idProduct = idProduct; if (bcdDevice) cdev->dev.bcdDevice = bcdDevice; if (cdev->dev.iManufacturer && iManufacturer) string_override(composite->strings, cdev->dev.iManufacturer, iManufacturer); if (cdev->dev.iProduct && iProduct) string_override(composite->strings, cdev->dev.iProduct, iProduct); if (cdev->dev.iSerialNumber && iSerialNumber) string_override(composite->strings, cdev->dev.iSerialNumber, iSerialNumber);*/ /* function binding involves updating interface, class, and * endpoint descriptors: * - allocating any string IDs needed (interface, class) * - allocating interface IDs (ditto) * - allocating endpoints (endpoint, class) * - allocating non-USB resources (buffers etc) * * NOTE: we assume that if there are multiple controllers, they * are all the same type (e.g. net2280 in pci slots) so functions * never need different descriptors. */ list_for_each_entry(f, &cdev->functions, function) { if (!f->bind || !f->setup) { status = -EINVAL; goto fail; } cdev->current_bind = f; status = f->bind(cdev, f); if (status < 0) goto fail; if ((gadget_is_dualspeed(gadget) && !f->hs_descriptors) || !f->descriptors) { status = -ENXIO; goto fail; } } cdev->current_bind = NULL; cdev->config.bNumInterfaces = cdev->next_interface_id; /* REVISIT eventually we want e.g. RNDIS and non-RNDIS configs, * at each available device speed ... */ cdev->dev.bNumConfigurations = 1; if (gadget_is_dualspeed(gadget)) { cdev->qual.bLength = sizeof cdev->qual; cdev->qual.bDescriptorType = USB_DT_DEVICE_QUALIFIER; cdev->qual.bcdUSB = cdev->dev.bcdUSB; cdev->qual.bDeviceClass = cdev->dev.bDeviceClass; cdev->qual.bDeviceProtocol = cdev->dev.bDeviceProtocol; /* assume ep0 uses the same value for both speeds ... */ cdev->qual.bMaxPacketSize0 = cdev->dev.bMaxPacketSize0; cdev->qual.bNumConfigurations = cdev->dev.bNumConfigurations; } INFO(cdev, "%s ready\n", composite->name); return 0; fail: composite_unbind(gadget); return status; } /* * usb_composite_string_id() is called from bind() callbacks to allocate * a new string ID. The function (or composite gadget) driver will then * store that ID in the appropriate descriptors and string table. */ int usb_composite_string_id(struct usb_composite_dev *cdev) { if (cdev->current_bind && cdev->next_string_id < 254) { /* string id 0 is reserved */ cdev->next_string_id++; return cdev->next_string_id; } return -ENODEV; } /* * usb_composite_interface_id() is called from bind() callbacks to * allocate a new interface ID. The function (or composite gadget) * driver will then store that ID in interface, association, cdc union, * and other appropriate descriptors. */ int usb_composite_interface_id(struct usb_composite_dev *cdev) { if (cdev->next_interface_id < MAX_COMPOSITE_INTERFACES && cdev->current_bind) { cdev->interface[cdev->next_interface_id] = cdev->current_bind; return cdev->next_interface_id++; } return -ENODEV; } /*-------------------------------------------------------------------------*/ static void composite_suspend(struct usb_gadget *gadget) { struct usb_function *f; DBG(cdev, "suspend\n"); /* revisit -- iterate cdev->interface? */ list_for_each_entry(f, &cdev->functions, function) { if (!f->suspend) continue; f->suspend(cdev); } } static void composite_resume(struct usb_gadget *gadget) { struct usb_function *f; DBG(cdev, "resume\n"); /* revisit -- iterate cdev->interface? */ list_for_each_entry(f, &cdev->functions, function) { if (!f->resume) continue; f->resume(cdev); } } /*-------------------------------------------------------------------------*/ static struct usb_gadget_driver composite_driver = { .speed = USB_SPEED_FULL, .bind = composite_bind, .unbind = __exit_p(composite_unbind), .setup = composite_setup, .disconnect = composite_disconnect, .suspend = composite_suspend, .resume = composite_resume, .driver = { .owner = THIS_MODULE, }, }; int usb_composite_register(struct usb_composite_driver *d) { if (!d || !d->dev || !d->bind || composite) return -EINVAL; if (!d->name) d->name = "composite"; composite_driver.function = (char *) d->name; composite_driver.driver.name = d->name; composite = d; return usb_gadget_register_driver(&composite_driver); } void usb_composite_unregister(struct usb_composite_driver *d) { if (composite != d) return; usb_gadget_unregister_driver(&composite_driver); } /* * composite.c - infrastructure for Composite USB Gadgets * * Copyright (C) 2006-2007 David Brownell * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ /* #define VERBOSE_DEBUG */ #include <linux/kernel.h> #include <linux/slab.h> #include <linux/device.h> #include <linux/usb/g_composite.h> /* * The code in this file is utility code, used to build a gadget driver * from one or more "function" drivers and a "usb_composite_driver" to * glue them together along with the relevant device-wide data. */ #define DBG(comp, fmt, args...) \ dev_dbg(&(comp)->gadget->dev , fmt , ## args) #define VDBG(comp, fmt, args...) \ dev_vdbg(&(comp)->gadget->dev , fmt , ## args) #define ERROR(comp, fmt, args...) \ dev_err(&(comp)->gadget->dev , fmt , ## args) #define WARN(comp, fmt, args...) \ dev_warn(&(comp)->gadget->dev , fmt , ## args) #define INFO(comp, fmt, args...) \ dev_info(&(comp)->gadget->dev , fmt , ## args) /* big enough to hold our biggest descriptor */ #define USB_BUFSIZ 512 static struct usb_composite_driver *composite; static struct usb_composite_dev *cdev; /* Some systems will need runtime overrides for the product identifers * published in the device descriptor, either numbers or strings or both. * String parameters are in UTF-8 (superset of ASCII's 7 bit characters). */ #if 0 static ushort idVendor; module_param(idVendor, ushort, S_IRUGO); MODULE_PARM_DESC(idVendor, "USB Vendor ID"); static ushort idProduct; module_param(idProduct, ushort, S_IRUGO); MODULE_PARM_DESC(idProduct, "USB Product ID"); static ushort bcdDevice; module_param(bcdDevice, ushort, S_IRUGO); MODULE_PARM_DESC(bcdDevice, "USB Device version (BCD)"); static char *iManufacturer; module_param(iManufacturer, charp, S_IRUGO); MODULE_PARM_DESC(iManufacturer, "USB Manufacturer string"); static char *iProduct; module_param(iProduct, charp, S_IRUGO); MODULE_PARM_DESC(iProduct, "USB Product string"); static char *iSerialNumber; module_param(iSerialNumber, charp, S_IRUGO); MODULE_PARM_DESC(iSerialNumber, "SerialNumber string"); #endif /*-------------------------------------------------------------------------*/ /* To simplify, we expect to have only ONE real configuration, working the * same no matter what speed it connects with. A given function may expose * multiple interfaces. Each interface includes its descriptor, plus optional * class and endpoint descriptors (as usual). * * Note that the configuration numbers are *NOT* related to how many configs * a device has ... some hardware places restrictions on config numbers. * So having a single configuration, number 3, would be fine. * * REVISIT we do need to lift this restriction, at least for RNDIS. * For PXA compat, stick to config numbers 1, 2, and 3; for SH, just 1. */ #define CONFIG_NUMBER 1 static int config_buf(void *buf, u8 type) { struct usb_config_descriptor *c = buf; void *next = buf + USB_DT_CONFIG_SIZE; int len = USB_BUFSIZ - USB_DT_CONFIG_SIZE; int hs; struct usb_function *f; INFO(cdev, "config buf\n"); if (gadget_is_dualspeed(cdev->gadget)) { hs = (cdev->gadget->speed == USB_SPEED_HIGH); if (type == USB_DT_OTHER_SPEED_CONFIG) hs = !hs; } else hs = 0; /* write a config descriptor */ *c = cdev->config; c->bLength = USB_DT_CONFIG_SIZE; c->bDescriptorType = type; c->bConfigurationValue = CONFIG_NUMBER; c->iConfiguration = cdev->iConfiguration; c->bmAttributes = USB_CONFIG_ATT_ONE | cdev->bmAttributes; c->bMaxPower = cdev->bMaxPower; INFO(cdev, "device config\n"); /* REVISIT some configurations might need other descriptors, * independent of the interfaces they implement ... notably * OTG descriptors. */ /* add each function's descriptors */ INFO(cdev, "speed: %d\n",hs); list_for_each_entry(f, &cdev->functions, function) { int status; status = usb_descriptor_fillbuf(next, len, hs ? f->hs_descriptors : f->descriptors); if (status < 0) return status; len -= status; next += status; INFO(cdev, "interface config\n"); } len = next - buf; c->wTotalLength = cpu_to_le16(len); return len; } /*-------------------------------------------------------------------------*/ static void composite_reset_config(struct usb_ctrlrequest *req) { struct usb_function *f; int result; DBG(cdev, "reset config\n"); req->bRequestType = USB_DIR_OUT | USB_TYPE_STANDARD | USB_RECIP_DEVICE; req->bRequest = USB_REQ_SET_CONFIGURATION; list_for_each_entry(f, &cdev->functions, function) { result = f->setup(cdev, req,f); if (result < 0) DBG(cdev, "reset function %s --> %d\n", f->name, result); } cdev->config.bConfigurationValue = 0; } static int composite_set_config(const struct usb_ctrlrequest *ctrl, unsigned number) { int result = 0; int tmp; struct usb_gadget *gadget = cdev->gadget; struct usb_ctrlrequest req; memset(&req, 0, sizeof req); /* for now function drivers should assume SET_CONFIGURATION means * reset/deconfigure, with SET_INTERFACE to each interface used * to activate some altsetting in "the single" configuration. */ composite_reset_config(&req); switch (number) { default: result = -EINVAL; req.wValue = cpu_to_le16(0); /* FALLTHROUGH */ case 0: for (tmp = 0; tmp < MAX_COMPOSITE_INTERFACES; tmp++) { struct usb_function *f = cdev->interface[tmp]; if (!f) continue; f->setup(cdev, ctrl, f); } usb_gadget_vbus_draw(gadget, gadget_is_otg(gadget) ? 8 : 100); break; case CONFIG_NUMBER: req.bRequestType = USB_DIR_OUT | USB_TYPE_STANDARD | USB_RECIP_INTERFACE; req.bRequest = USB_REQ_SET_INTERFACE; for (tmp = 0; tmp < MAX_COMPOSITE_INTERFACES; tmp++) { struct usb_function *f = cdev->interface[tmp]; if (!f) continue; req.wIndex = cpu_to_le16(tmp); result = f->setup(cdev, &req, f); if (result < 0) { DBG(cdev, "interface %d/%s alt 0--> %d\n", tmp, f->name, result); (void) composite_set_config(ctrl, 0); return result; } } cdev->config.bConfigurationValue = number; usb_gadget_vbus_draw(gadget, 2 * cdev->config.bMaxPower); break; } INFO(cdev, "%s speed config #%d\n", ({ char *speed; switch (gadget->speed) { case USB_SPEED_LOW: speed = "low"; break; case USB_SPEED_FULL: speed = "full"; break; case USB_SPEED_HIGH: speed = "high"; break; default: speed = "?"; break; } ; speed; }), number); return result; } /*-------------------------------------------------------------------------*/ static void composite_collect_langs(struct usb_gadget_strings **sp, __le16 *buf) { const struct usb_gadget_strings *s; u16 language; __le16 *tmp; while (*sp) { s = *sp; language = cpu_to_le16(s->language); for (tmp = buf; *tmp && tmp < &buf[126]; tmp++) { if (*tmp == language) goto repeat; } *tmp++ = language; repeat: sp++; } } static int composite_check_string( struct usb_gadget_strings **sp, void *buf, u16 language, int id ) { struct usb_gadget_strings *s; int value; while (*sp) { s = *sp++; if (s->language != language) continue; value = usb_gadget_get_string(s, id, buf); if (value > 0) return value; } return -EINVAL; } static int composite_lookup_string(void *buf, u16 language, int id) { struct usb_function *f; int len; /* 0 == report all available language codes */ if (id == 0) { struct usb_string_descriptor *s = buf; struct usb_gadget_strings **sp; memset(s, 0, 256); s->bDescriptorType = USB_DT_STRING; sp = composite->strings; if (sp) composite_collect_langs(sp, s->wData); list_for_each_entry(f, &cdev->functions, function) { sp = f->strings; if (sp) composite_collect_langs(sp, s->wData); } for (len = 0; s->wData[len] && len <= 126; len++) continue; if (!len) return -EINVAL; s->bLength = 2 * (len + 1); return s->bLength; } /* otherwise, look up and return a specified string */ if (composite->strings) { len = composite_check_string(composite->strings, buf, language, id); if (len > 0) return len; } list_for_each_entry(f, &cdev->functions, function) { if (!f->strings) continue; len = composite_check_string(f->strings, buf, language, id); if (len > 0) return len; } return -EINVAL; } /*-------------------------------------------------------------------------*/ static void composite_setup_complete(struct usb_ep *ep, struct usb_request *req) { if (req->status || req->actual != req->length) DBG((struct usb_composite_dev *) ep->driver_data, "setup complete --> %d, %d/%d\n", req->status, req->actual, req->length); } /* * The setup() callback implements all the ep0 functionality that's * not handled lower down, in hardware or the hardware driver(like * device and endpoint feature flags, and their status). It's all * housekeeping for the gadget function we're implementing. Most of * the work is in config-specific setup. */ static int composite_setup(struct usb_gadget *gadget, const struct usb_ctrlrequest *ctrl) { struct usb_composite_dev *cdev = get_gadget_data(gadget); struct usb_request *req = cdev->req; int value = -EOPNOTSUPP; u16 w_index = le16_to_cpu(ctrl->wIndex); u16 w_value = le16_to_cpu(ctrl->wValue); u16 w_length = le16_to_cpu(ctrl->wLength); int tmp,result; /* partial re-init of the response message; the function or the * gadget might need to intercept e.g. a control-OUT completion. */ req->zero = 0; req->complete = composite_setup_complete; gadget->ep0->driver_data = cdev; INFO(cdev, "control req %02x.%02x v %04x i %04x l %d\n", ctrl->bRequestType, ctrl->bRequest, w_value, w_index, w_length); if((ctrl->bRequestType&USB_TYPE_MASK) != USB_TYPE_STANDARD) { for (tmp = 0; tmp < MAX_COMPOSITE_INTERFACES; tmp++) { struct usb_function *f = cdev->interface[tmp]; if (!f) continue; result = f->setup(cdev, ctrl, f); if(result > 0) value = result; value = min(w_length, (u16) value); } ((char *)(req->buf))[value]=0; INFO(cdev, "Result Len: %d %s\n",value,&req->buf[2]); } else { switch (ctrl->bRequest) { case USB_REQ_GET_DESCRIPTOR: if (ctrl->bRequestType != USB_DIR_IN) goto unknown; switch (w_value >> 8) { case USB_DT_DEVICE: value = min(w_length, (u16) sizeof cdev->dev); memcpy(req->buf, &cdev->dev, value); break; case USB_DT_DEVICE_QUALIFIER: if (!gadget_is_dualspeed(gadget)) break; value = min(w_length, (u16) sizeof cdev->qual); memcpy(req->buf, &cdev->qual, value); break; case USB_DT_OTHER_SPEED_CONFIG: if (!gadget_is_dualspeed(gadget)) break; /* FALLTHROUGH */ case USB_DT_CONFIG: INFO(cdev, "Get Config Descriptor\n"); /* one config ... so it must always be index 0 */ if (w_value & 0xff) break; value = config_buf(req->buf, w_value >> 8); if (value >= 0) value = min(w_length, (u16) value); break; case USB_DT_STRING: value = composite_lookup_string(req->buf, w_index, w_value & 0xff); if (value >= 0) value = min(w_length, (u16) value); break; } break; /* currently one config, two speeds */ case USB_REQ_SET_CONFIGURATION: if (ctrl->bRequestType != 0) goto unknown; if (gadget->a_hnp_support) DBG(cdev, "HNP available\n"); else if (gadget->a_alt_hnp_support) DBG(cdev, "HNP needs a different root port\n"); else VDBG(cdev, "HNP inactive\n"); spin_lock(&cdev->lock); value = composite_set_config(ctrl, w_value); spin_unlock(&cdev->lock); break; case USB_REQ_GET_CONFIGURATION: if (ctrl->bRequestType != USB_DIR_IN) goto unknown; *(u8 *)req->buf = cdev->config.bConfigurationValue; value = min(w_length, (u16) 1); break; /* function drivers must handle get/set altsetting */ case USB_REQ_SET_INTERFACE: if (ctrl->bRequestType != USB_RECIP_INTERFACE) goto unknown; if (!cdev->config.bConfigurationValue || w_index >= MAX_COMPOSITE_INTERFACES || !cdev->interface[w_index]) break; spin_lock(&cdev->lock); value = cdev->interface[w_index]->setup(cdev, ctrl, cdev->interface[w_index]); spin_unlock(&cdev->lock); break; case USB_REQ_GET_INTERFACE: if (ctrl->bRequestType != (USB_DIR_IN|USB_RECIP_INTERFACE)) goto unknown; if (!cdev->config.bConfigurationValue || w_index >= MAX_COMPOSITE_INTERFACES || !cdev->interface[w_index]) break; spin_lock(&cdev->lock); /* function must set cdev->req->buf[0] */ value = cdev->interface[w_index]->setup(cdev, ctrl, cdev->interface[w_index]); spin_unlock(&cdev->lock); value = min(w_length, (u16) 1); break; default: unknown: VDBG(cdev, "unknown control req%02x.%02x v%04x i%04x l%d\n", ctrl->bRequestType, ctrl->bRequest, w_value, w_index, w_length); } } /* respond with data transfer before status phase? */ if (value >= 0) { req->length = value; req->zero = (value < w_length) && ((value % gadget->ep0->maxpacket) == 0); value = usb_ep_queue(gadget->ep0, req, GFP_ATOMIC); if (value < 0) { INFO(cdev, "ep_queue --> %d\n", value); req->status = 0; composite_setup_complete(gadget->ep0, req); } } /* device either stalls (value < 0) or reports success */ return value; } static void composite_disconnect(struct usb_gadget *gadget) { struct usb_composite_dev *cdev = get_gadget_data(gadget); unsigned long flags; struct usb_ctrlrequest req; DBG(cdev, "disconnect\n"); memset(&req, 0, sizeof req); spin_lock_irqsave(&cdev->lock, flags); composite_reset_config(&req); spin_unlock_irqrestore(&cdev->lock, flags); } /*-------------------------------------------------------------------------*/ static void /* __init_or_exit */ composite_unbind(struct usb_gadget *gadget) { struct usb_composite_dev *cdev = get_gadget_data(gadget); struct usb_function *f; DBG(cdev, "unbind\n"); list_for_each_entry(f, &cdev->functions, function) { if (f->unbind) f->unbind(cdev, f); if (f == cdev->current_bind) break; } if (composite->unbind) composite->unbind(cdev); if (cdev->req) { kfree(cdev->req->buf); usb_ep_free_request(gadget->ep0, cdev->req); } kfree(cdev); set_gadget_data(gadget, NULL); composite = NULL; } static void string_override_one(struct usb_gadget_strings *tab, u8 id, const char *s) { struct usb_string *str = tab->strings; for (str = tab->strings; str->s; str++) { if (str->id == id) { str->s = s; return; } } } static void string_override(struct usb_gadget_strings **tab, u8 id, const char *s) { while (*tab) { string_override_one(*tab, id, s); tab++; } } static int __init composite_bind(struct usb_gadget *gadget) { struct usb_function *f; int status = -ENOMEM; if (cdev) return -EBUSY; cdev = kzalloc(sizeof *cdev, GFP_KERNEL); if (!cdev) return status; spin_lock_init(&cdev->lock); cdev->gadget = gadget; set_gadget_data(gadget, cdev); INIT_LIST_HEAD(&cdev->functions); /* preallocate control response and buffer */ cdev->req = usb_ep_alloc_request(gadget->ep0, GFP_KERNEL); if (!cdev->req) goto fail; cdev->req->buf = kmalloc(USB_BUFSIZ, GFP_KERNEL); if (!cdev->req->buf) goto fail; cdev->req->complete = composite_setup_complete; gadget->ep0->driver_data = cdev; cdev->bufsiz = USB_BUFSIZ; cdev->driver = composite; usb_gadget_set_selfpowered(gadget); /* interface and string IDs start at zero */ usb_ep_autoconfig_reset(gadget); /* composite gadget needs to assign strings for whole device (like * serial number), register function drivers, potentially update * power state and consumption, etc */ cdev->current_bind = gadget; status = composite->bind(cdev); if (status < 0) goto fail; cdev->current_bind = NULL; cdev->dev = *composite->dev; cdev->dev.bMaxPacketSize0 = gadget->ep0->maxpacket; /* standardized runtime overrides for device ID data */ /*if (idVendor) cdev->dev.idVendor = idVendor; if (idProduct) cdev->dev.idProduct = idProduct; if (bcdDevice) cdev->dev.bcdDevice = bcdDevice; if (cdev->dev.iManufacturer && iManufacturer) string_override(composite->strings, cdev->dev.iManufacturer, iManufacturer); if (cdev->dev.iProduct && iProduct) string_override(composite->strings, cdev->dev.iProduct, iProduct); if (cdev->dev.iSerialNumber && iSerialNumber) string_override(composite->strings, cdev->dev.iSerialNumber, iSerialNumber);*/ /* function binding involves updating interface, class, and * endpoint descriptors: * - allocating any string IDs needed (interface, class) * - allocating interface IDs (ditto) * - allocating endpoints (endpoint, class) * - allocating non-USB resources (buffers etc) * * NOTE: we assume that if there are multiple controllers, they * are all the same type (e.g. net2280 in pci slots) so functions * never need different descriptors. */ list_for_each_entry(f, &cdev->functions, function) { if (!f->bind || !f->setup) { status = -EINVAL; goto fail; } cdev->current_bind = f; status = f->bind(cdev, f); if (status < 0) goto fail; if ((gadget_is_dualspeed(gadget) && !f->hs_descriptors) || !f->descriptors) { status = -ENXIO; goto fail; } } cdev->current_bind = NULL; cdev->config.bNumInterfaces = cdev->next_interface_id; /* REVISIT eventually we want e.g. RNDIS and non-RNDIS configs, * at each available device speed ... */ cdev->dev.bNumConfigurations = 1; if (gadget_is_dualspeed(gadget)) { cdev->qual.bLength = sizeof cdev->qual; cdev->qual.bDescriptorType = USB_DT_DEVICE_QUALIFIER; cdev->qual.bcdUSB = cdev->dev.bcdUSB; cdev->qual.bDeviceClass = cdev->dev.bDeviceClass; cdev->qual.bDeviceProtocol = cdev->dev.bDeviceProtocol; /* assume ep0 uses the same value for both speeds ... */ cdev->qual.bMaxPacketSize0 = cdev->dev.bMaxPacketSize0; cdev->qual.bNumConfigurations = cdev->dev.bNumConfigurations; } INFO(cdev, "%s ready\n", composite->name); return 0; fail: composite_unbind(gadget); return status; } /* * usb_composite_string_id() is called from bind() callbacks to allocate * a new string ID. The function (or composite gadget) driver will then * store that ID in the appropriate descriptors and string table. */ int usb_composite_string_id(struct usb_composite_dev *cdev) { if (cdev->current_bind && cdev->next_string_id < 254) { /* string id 0 is reserved */ cdev->next_string_id++; return cdev->next_string_id; } return -ENODEV; } /* * usb_composite_interface_id() is called from bind() callbacks to * allocate a new interface ID. The function (or composite gadget) * driver will then store that ID in interface, association, cdc union, * and other appropriate descriptors. */ int usb_composite_interface_id(struct usb_composite_dev *cdev) { if (cdev->next_interface_id < MAX_COMPOSITE_INTERFACES && cdev->current_bind) { cdev->interface[cdev->next_interface_id] = cdev->current_bind; return cdev->next_interface_id++; } return -ENODEV; } /*-------------------------------------------------------------------------*/ static void composite_suspend(struct usb_gadget *gadget) { struct usb_function *f; DBG(cdev, "suspend\n"); /* revisit -- iterate cdev->interface? */ list_for_each_entry(f, &cdev->functions, function) { if (!f->suspend) continue; f->suspend(cdev); } } static void composite_resume(struct usb_gadget *gadget) { struct usb_function *f; DBG(cdev, "resume\n"); /* revisit -- iterate cdev->interface? */ list_for_each_entry(f, &cdev->functions, function) { if (!f->resume) continue; f->resume(cdev); } } /*-------------------------------------------------------------------------*/ static struct usb_gadget_driver composite_driver = { .speed = USB_SPEED_FULL, .bind = composite_bind, .unbind = __exit_p(composite_unbind), .setup = composite_setup, .disconnect = composite_disconnect, .suspend = composite_suspend, .resume = composite_resume, .driver = { .owner = THIS_MODULE, }, }; int usb_composite_register(struct usb_composite_driver *d) { if (!d || !d->dev || !d->bind || composite) return -EINVAL; if (!d->name) d->name = "composite"; composite_driver.function = (char *) d->name; composite_driver.driver.name = d->name; composite = d; return usb_gadget_register_driver(&composite_driver); } void usb_composite_unregister(struct usb_composite_driver *d) { if (composite != d) return; usb_gadget_unregister_driver(&composite_driver); }