summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorXinyu Chen <b03824@freescale.com>2011-10-20 09:55:51 +0800
committerXinyu Chen <xinyu.chen@freescale.com>2011-10-24 13:55:47 +0800
commit0cd6cf6a4a33820d5b3f0a281eadfa0d7ecace49 (patch)
tree0df59bc84f895f890c90979c16708bc8f0fce14c
parent71fc603712bd7e4f75fc7028dbbaf29d94a77527 (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.c39
-rw-r--r--drivers/usb/gadget/composite.c26
-rw-r--r--include/linux/usb/android_composite.h1
-rw-r--r--include/linux/usb/composite.h2
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);