composite device

/* <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); 
} 




 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值