diff options
author | Xinyu Chen <b03824@freescale.com> | 2011-10-20 09:55:51 +0800 |
---|---|---|
committer | Xinyu Chen <xinyu.chen@freescale.com> | 2011-10-24 13:55:47 +0800 |
commit | 0cd6cf6a4a33820d5b3f0a281eadfa0d7ecace49 (patch) | |
tree | 0df59bc84f895f890c90979c16708bc8f0fce14c | |
parent | 71fc603712bd7e4f75fc7028dbbaf29d94a77527 (diff) |
ENGR00160401-1 usb: refine android gadget to support USB Accessory
Support different vendor/product id for different functions.
Support USB connection status switch.
Signed-off-by: Xinyu Chen <xinyu.chen@freescale.com>
-rw-r--r-- | drivers/usb/gadget/android.c | 39 | ||||
-rw-r--r-- | drivers/usb/gadget/composite.c | 26 | ||||
-rw-r--r-- | include/linux/usb/android_composite.h | 1 | ||||
-rw-r--r-- | include/linux/usb/composite.h | 2 |
4 files changed, 59 insertions, 9 deletions
diff --git a/drivers/usb/gadget/android.c b/drivers/usb/gadget/android.c index 00c09e61ff46..630368ee1763 100644 --- a/drivers/usb/gadget/android.c +++ b/drivers/usb/gadget/android.c @@ -57,6 +57,7 @@ struct android_dev { int num_functions; char **functions; int product_id; + int vendor_id; int version; struct wake_lock wake_lock; }; @@ -192,7 +193,7 @@ static int product_matches_functions(struct android_usb_product *p) return 1; } -static int get_product_id(struct android_dev *dev) +static int get_vendor_id(struct android_dev *dev) { struct android_usb_product *p = dev->products; int count = dev->num_products; @@ -200,6 +201,22 @@ static int get_product_id(struct android_dev *dev) if (p) { for (i = 0; i < count; i++, p++) { + if (p->vendor_id && product_matches_functions(p)) + return p->vendor_id; + } + } + /* use default vendor ID */ + return dev->vendor_id; +} + +static int get_product_id(struct android_dev *dev) +{ +struct android_usb_product *p = dev->products; +int count = dev->num_products; + int i; + + if (p) { + for (i = 0; i < count; i++, p++) { if (product_matches_functions(p)) return p->product_id; } @@ -212,7 +229,7 @@ static int android_bind(struct usb_composite_dev *cdev) { struct android_dev *dev = _android_dev; struct usb_gadget *gadget = cdev->gadget; - int gcnum, id, product_id, ret; + int gcnum, id, ret; /* Allocate string descriptor numbers ... note that string * contents can be overridden by the composite_dev glue. @@ -260,8 +277,9 @@ static int android_bind(struct usb_composite_dev *cdev) usb_gadget_set_selfpowered(gadget); dev->cdev = cdev; - product_id = get_product_id(dev); - device_desc.idProduct = __constant_cpu_to_le16(product_id); + device_desc.idVendor = __constant_cpu_to_le16(get_vendor_id(dev)); + device_desc.idProduct = __constant_cpu_to_le16(get_product_id(dev)); + cdev->desc.idVendor = device_desc.idVendor; cdev->desc.idProduct = device_desc.idProduct; return 0; @@ -286,7 +304,6 @@ void android_enable_function(struct usb_function *f, int enable) { struct android_dev *dev = _android_dev; int disable = !enable; - int product_id; if (!!f->disabled != disable) { usb_function_set_enabled(f, !disable); @@ -335,12 +352,15 @@ void android_enable_function(struct usb_function *f, int enable) usb_function_set_enabled(func, 0); } } - } + } #endif - product_id = get_product_id(dev); - device_desc.idProduct = __constant_cpu_to_le16(product_id); - if (dev->cdev) + device_desc.idVendor = __constant_cpu_to_le16(get_vendor_id(dev)); + device_desc.idProduct = __constant_cpu_to_le16(get_product_id(dev)); + + if (dev->cdev) { + dev->cdev->desc.idVendor = device_desc.idVendor; dev->cdev->desc.idProduct = device_desc.idProduct; + } usb_composite_force_reset(dev->cdev); } } @@ -378,6 +398,7 @@ static int android_probe(struct platform_device *pdev) if (pdata->vendor_id) device_desc.idVendor = __constant_cpu_to_le16(pdata->vendor_id); + dev->vendor_id = pdata->vendor_id; if (pdata->product_id) { dev->product_id = pdata->product_id; device_desc.idProduct = diff --git a/drivers/usb/gadget/composite.c b/drivers/usb/gadget/composite.c index 1ad488a76c3c..4ba4f8afcac2 100644 --- a/drivers/usb/gadget/composite.c +++ b/drivers/usb/gadget/composite.c @@ -824,6 +824,14 @@ composite_setup(struct usb_gadget *gadget, const struct usb_ctrlrequest *ctrl) u16 w_length = le16_to_cpu(ctrl->wLength); struct usb_function *f = NULL; u8 endp; + unsigned int flags; + + spin_lock_irqsave(&cdev->lock, flags); + if (!cdev->connected) { + cdev->connected = 1; + schedule_work(&cdev->switch_work); + } + spin_unlock_irqrestore(&cdev->lock, flags); /* partial re-init of the response message; the function or the * gadget might need to intercept e.g. a control-OUT completion @@ -1038,6 +1046,8 @@ static void composite_disconnect(struct usb_gadget *gadget) spin_lock_irqsave(&cdev->lock, flags); if (cdev->config) reset_config(cdev); + + cdev->connected = 0; if (cdev->mute_switch > 0) cdev->mute_switch--; else @@ -1100,6 +1110,7 @@ composite_unbind(struct usb_gadget *gadget) if (composite->unbind) composite->unbind(cdev); + switch_dev_unregister(&cdev->sw_connected); switch_dev_unregister(&cdev->sdev); if (cdev->req) { @@ -1140,6 +1151,17 @@ composite_switch_work(struct work_struct *data) struct usb_composite_dev *cdev = container_of(data, struct usb_composite_dev, switch_work); struct usb_configuration *config = cdev->config; + int connected; + unsigned long flags; + + spin_lock_irqsave(&cdev->lock, flags); + if (cdev->connected != cdev->sw_connected.state) { + connected = cdev->connected; + spin_unlock_irqrestore(&cdev->lock, flags); + switch_set_state(&cdev->sw_connected, connected); + } else { + spin_unlock_irqrestore(&cdev->lock, flags); + } if (config) switch_set_state(&cdev->sdev, config->bConfigurationValue); @@ -1198,6 +1220,10 @@ static int composite_bind(struct usb_gadget *gadget) if (status < 0) goto fail; + cdev->sw_connected.name = "usb_connected"; + status = switch_dev_register(&cdev->sw_connected); + if (status < 0) + goto fail; cdev->sdev.name = "usb_configuration"; status = switch_dev_register(&cdev->sdev); if (status < 0) diff --git a/include/linux/usb/android_composite.h b/include/linux/usb/android_composite.h index ac09dcb71775..a570b504230e 100644 --- a/include/linux/usb/android_composite.h +++ b/include/linux/usb/android_composite.h @@ -27,6 +27,7 @@ struct android_usb_function { }; struct android_usb_product { + __u16 vendor_id; /* Default product ID. */ __u16 product_id; diff --git a/include/linux/usb/composite.h b/include/linux/usb/composite.h index 9b665c50f6f8..63a65e504eff 100644 --- a/include/linux/usb/composite.h +++ b/include/linux/usb/composite.h @@ -347,8 +347,10 @@ struct usb_composite_dev { /* protects at least deactivation count */ spinlock_t lock; struct switch_dev sdev; + struct switch_dev sw_connected; struct work_struct switch_work; int mute_switch; + int connected; }; extern int usb_string_id(struct usb_composite_dev *c); |