aboutsummaryrefslogtreecommitdiff
path: root/drivers/usb
diff options
context:
space:
mode:
authorsidhartk <sidhartk@bnru02.(none)>2010-12-14 17:34:35 +0530
committerJonas ABERG <jonas.aberg@stericsson.com>2010-12-14 17:29:07 +0100
commitb0897f45370d34efdaa2a4fb349b23048d173097 (patch)
tree102ef810bcd9dc959ded35bf5fd1b2d1c0ee86fc /drivers/usb
parent033519a8fae48f118cd1426d13356632ac2e2967 (diff)
[Android]: USB:Fixed soft attach/detach issue
Re-binding functionality is added to update interface id's and the descriptors before a soft reset when any usb function is added or removed dynamically. ST-Ericsson ID:271729 Change-Id: I96f6703e7a77d5a5c20a2b15f7afe49c6dbc26d1 Signed-off-by: sidhartk <sidhartha.kalra@stericsson.com> Reviewed-on: http://gerrit.lud.stericsson.com/gerrit/10318 Reviewed-by: QATOOLS Reviewed-by: Jonas ABERG <jonas.aberg@stericsson.com>
Diffstat (limited to 'drivers/usb')
-rw-r--r--drivers/usb/gadget/android.c27
-rw-r--r--drivers/usb/gadget/f_acm.c82
-rw-r--r--drivers/usb/gadget/f_adb.c20
-rw-r--r--drivers/usb/gadget/f_ecm.c91
-rw-r--r--drivers/usb/gadget/f_mass_storage.c28
5 files changed, 245 insertions, 3 deletions
diff --git a/drivers/usb/gadget/android.c b/drivers/usb/gadget/android.c
index ed4f5739cb9..5e778e624a1 100644
--- a/drivers/usb/gadget/android.c
+++ b/drivers/usb/gadget/android.c
@@ -64,6 +64,7 @@ struct android_dev {
struct android_usb_product *products;
int num_functions;
char **functions;
+ u8 bound;
int product_id;
int version;
@@ -134,6 +135,29 @@ static void bind_functions(struct android_dev *dev)
else
printk(KERN_ERR "function %s not found in bind_functions\n", name);
}
+ dev->bound = 1;
+}
+
+static void rebind_functions(struct android_dev *dev)
+
+{
+ struct android_usb_function *android_f;
+ struct usb_function *f;
+
+ dev->config->next_interface_id = 0;
+ list_for_each_entry(f, &dev->config->functions, list) {
+ if (f->disabled)
+ continue;
+
+ /* rebind our functions if they are enabled */
+ android_f = get_function(f->name);
+ if (android_f && android_f->rebind_config)
+ android_f->rebind_config(dev->config, f);
+ else
+ printk(KERN_ERR "function %s not found in rebind_functions\n",
+ f->name);
+ }
+ dev->config->interface[dev->config->next_interface_id] = NULL;
}
static int android_bind_config(struct usb_configuration *c)
@@ -345,6 +369,8 @@ void android_enable_function(struct usb_function *f, int enable)
device_desc.idProduct = __constant_cpu_to_le16(product_id);
if (dev->cdev)
dev->cdev->desc.idProduct = device_desc.idProduct;
+ if (dev->bound)
+ rebind_functions(dev);
usb_composite_force_reset(dev->cdev);
}
}
@@ -361,6 +387,7 @@ static int android_probe(struct platform_device *pdev)
dev->num_products = pdata->num_products;
dev->functions = pdata->functions;
dev->num_functions = pdata->num_functions;
+ dev->bound = 0;
if (pdata->vendor_id)
device_desc.idVendor =
__constant_cpu_to_le16(pdata->vendor_id);
diff --git a/drivers/usb/gadget/f_acm.c b/drivers/usb/gadget/f_acm.c
index ddbb98861be..7cc8228bf49 100644
--- a/drivers/usb/gadget/f_acm.c
+++ b/drivers/usb/gadget/f_acm.c
@@ -794,9 +794,91 @@ int acm_function_bind_config(struct usb_configuration *c)
return ret;
}
+static int acm_function_rebind_config(struct usb_configuration *c,
+ struct usb_function *f)
+{
+ struct usb_composite_dev *cdev = c->cdev;
+ struct f_acm *acm = func_to_acm(f);
+ int status1, status2 = 0;
+ struct usb_descriptor_header **desc = f->descriptors;
+
+ /* re-allocate instance-specific interface IDs, and patch descriptors */
+ status1 = usb_interface_id(c, f);
+ if (status1 < 0)
+ goto fail;
+ acm->ctrl_id = status1;
+
+ acm_iad_descriptor.bFirstInterface = status1;
+ acm_control_interface_desc.bInterfaceNumber = status1;
+ acm_union_desc .bMasterInterface0 = status1;
+
+ ((struct usb_interface_assoc_descriptor *)desc[0])
+ ->bFirstInterface = status1;
+ ((struct usb_interface_descriptor *)desc[1])
+ ->bInterfaceNumber = status1;
+ ((struct usb_cdc_union_desc *)desc[5])
+ ->bMasterInterface0 = status1;
+
+ status2 = usb_interface_id(c, f);
+ if (status2 < 0)
+ goto fail;
+ acm->data_id = status2;
+
+ acm_data_interface_desc.bInterfaceNumber = status2;
+ acm_union_desc.bSlaveInterface0 = status2;
+ acm_call_mgmt_descriptor.bDataInterface = status2;
+
+ ((struct usb_interface_descriptor *)desc[7])
+ ->bInterfaceNumber = status2;
+ ((struct usb_cdc_union_desc *)desc[5])
+ ->bSlaveInterface0 = status2;
+ ((struct usb_cdc_call_mgmt_descriptor *)desc[3])
+ ->bDataInterface = status2;
+
+ if (gadget_is_dualspeed(c->cdev->gadget)) {
+ desc = f->hs_descriptors;
+
+ ((struct usb_interface_assoc_descriptor *)desc[0])
+ ->bFirstInterface = status1;
+ ((struct usb_interface_descriptor *)desc[1])
+ ->bInterfaceNumber = status1;
+ ((struct usb_cdc_union_desc *)desc[5])
+ ->bMasterInterface0 = status1;
+
+ ((struct usb_interface_descriptor *)desc[7])
+ ->bInterfaceNumber = status2;
+ ((struct usb_cdc_union_desc *)desc[5])
+ ->bSlaveInterface0 = status2;
+ ((struct usb_cdc_call_mgmt_descriptor *)desc[3])
+ ->bDataInterface = status2;
+ }
+
+ return 0;
+
+fail:
+ if (acm->notify_req)
+ gs_free_req(acm->notify, acm->notify_req);
+
+ /* we might as well release our claims on endpoints */
+ if (acm->notify)
+ acm->notify->driver_data = NULL;
+ if (acm->port.out)
+ acm->port.out->driver_data = NULL;
+ if (acm->port.in)
+ acm->port.in->driver_data = NULL;
+
+ ERROR(cdev, "%s/%p: can't re-bind, err %d %d\n",
+ f->name, f, status1, status2);
+
+ if (status2 < 0)
+ status1 = status2;
+ return status1;
+}
+
static struct android_usb_function acm_function = {
.name = "acm",
.bind_config = acm_function_bind_config,
+ .rebind_config = acm_function_rebind_config,
};
static int __init init(void)
diff --git a/drivers/usb/gadget/f_adb.c b/drivers/usb/gadget/f_adb.c
index a0b0774b955..0de890d4763 100644
--- a/drivers/usb/gadget/f_adb.c
+++ b/drivers/usb/gadget/f_adb.c
@@ -613,7 +613,7 @@ static int adb_bind_config(struct usb_configuration *c)
dev->function.disable = adb_function_disable;
/* start disabled */
- dev->function.disabled = 1;
+ dev->function.disabled = 0;
/* _adb_dev must be set before calling usb_gadget_register_driver */
_adb_dev = dev;
@@ -641,9 +641,27 @@ err1:
return ret;
}
+static int adb_rebind_config(struct usb_configuration *c,
+ struct usb_function *f)
+{
+ struct usb_composite_dev *cdev = c->cdev;
+ struct adb_dev *dev = func_to_dev(f);
+ int id;
+ int ret;
+
+ /* re-allocate interface ID(s) */
+ id = usb_interface_id(c, f);
+ if (id < 0)
+ return id;
+ adb_interface_desc.bInterfaceNumber = id;
+
+ return 0;
+}
+
static struct android_usb_function adb_function = {
.name = "adb",
.bind_config = adb_bind_config,
+ .rebind_config = adb_rebind_config,
};
static int __init init(void)
diff --git a/drivers/usb/gadget/f_ecm.c b/drivers/usb/gadget/f_ecm.c
index 0ac29e0e8cc..28cb0109717 100644
--- a/drivers/usb/gadget/f_ecm.c
+++ b/drivers/usb/gadget/f_ecm.c
@@ -871,7 +871,7 @@ static int __init ecm_probe(struct platform_device *pdev)
}
static struct platform_driver ecm_platform_driver = {
- .driver = { .name = "ecm", },
+ .driver = { .name = "cdc_ethernet", },
.probe = ecm_probe,
};
@@ -896,9 +896,96 @@ int ecm_function_bind_config(struct usb_configuration *c)
return ret;
}
+static int ecm_function_rebind_config(struct usb_configuration *c,
+ struct usb_function *f)
+{
+
+ struct usb_composite_dev *cdev = c->cdev;
+ struct f_ecm *ecm = func_to_ecm(f);
+ int status1, status2 = 0;
+ struct usb_descriptor_header **desc = f->descriptors;
+
+ /* re-allocate instance-specific interface IDs */
+ status1 = usb_interface_id(c, f);
+ if (status1 < 0)
+ goto fail;
+ ecm->ctrl_id = status1;
+
+ ecm_iad_descriptor.bFirstInterface = status1;
+ ecm_control_intf.bInterfaceNumber = status1;
+ ecm_union_desc.bMasterInterface0 = status1;
+
+ ((struct usb_interface_assoc_descriptor *)desc[0])
+ ->bFirstInterface = status1;
+ ((struct usb_interface_descriptor *)desc[1])
+ ->bInterfaceNumber = status1;
+ ((struct usb_cdc_union_desc *)desc[3])
+ ->bMasterInterface0 = status1;
+
+ status2 = usb_interface_id(c, f);
+ if (status2 < 0)
+ goto fail;
+ ecm->data_id = status2;
+
+ ecm_data_nop_intf.bInterfaceNumber = status2;
+ ecm_data_intf.bInterfaceNumber = status2;
+ ecm_union_desc.bSlaveInterface0 = status2;
+
+ ((struct usb_interface_descriptor *)desc[6])
+ ->bInterfaceNumber = status2;
+ ((struct usb_interface_descriptor *)desc[7])
+ ->bInterfaceNumber = status2;
+ ((struct usb_cdc_union_desc *)desc[3])
+ ->bSlaveInterface0 = status2;
+
+ if (gadget_is_dualspeed(c->cdev->gadget)) {
+ desc = f->hs_descriptors;
+ ((struct usb_interface_assoc_descriptor *)desc[0])
+ ->bFirstInterface = status1;
+ ((struct usb_interface_descriptor *)desc[1])
+ ->bInterfaceNumber = status1;
+ ((struct usb_cdc_union_desc *)desc[3])
+ ->bMasterInterface0 = status1;
+
+ ((struct usb_interface_descriptor *)desc[6])
+ ->bInterfaceNumber = status2;
+ ((struct usb_interface_descriptor *)desc[7])
+ ->bInterfaceNumber = status2;
+ ((struct usb_cdc_union_desc *)desc[3])
+ ->bSlaveInterface0 = status2;
+ }
+
+ return 0;
+
+fail:
+ if (f->descriptors)
+ usb_free_descriptors(f->descriptors);
+
+ if (ecm->notify_req) {
+ kfree(ecm->notify_req->buf);
+ usb_ep_free_request(ecm->notify, ecm->notify_req);
+ }
+
+ /* we might as well release our claims on endpoints */
+ if (ecm->notify)
+ ecm->notify->driver_data = NULL;
+ if (ecm->port.out)
+ ecm->port.out_ep->driver_data = NULL;
+ if (ecm->port.in)
+ ecm->port.in_ep->driver_data = NULL;
+
+ ERROR(cdev, "%s: can't re-bind, err %d %d\n",
+ f->name, status1, status2);
+
+ if (status2 < 0)
+ status1 = status2;
+ return status1;
+}
+
static struct android_usb_function ecm_function = {
- .name = "ecm",
+ .name = "cdc_ethernet",
.bind_config = ecm_function_bind_config,
+ .rebind_config = ecm_function_rebind_config,
};
static int __init init(void)
diff --git a/drivers/usb/gadget/f_mass_storage.c b/drivers/usb/gadget/f_mass_storage.c
index c0d3b8e547c..e2a3c63bd59 100644
--- a/drivers/usb/gadget/f_mass_storage.c
+++ b/drivers/usb/gadget/f_mass_storage.c
@@ -3179,9 +3179,37 @@ int mass_storage_bind_config(struct usb_configuration *c)
return fsg_add(c->cdev, c, common);
}
+static int mass_storage_rebind_config(struct usb_configuration *c,
+ struct usb_function *f)
+{
+ struct fsg_dev *fsg = fsg_from_func(f);
+ struct usb_gadget *gadget = c->cdev->gadget;
+ int i;
+
+ fsg->gadget = gadget;
+
+ /* New interface */
+ i = usb_interface_id(c, f);
+ if (i < 0)
+ return i;
+ fsg_intf_desc.bInterfaceNumber = i;
+ fsg->interface_number = i;
+
+#ifndef FSG_NO_OTG
+ ((struct usb_interface_assoc_descriptor *)f->descriptors[1]
+ ->bFirstInterface = i;
+#else
+ ((struct usb_interface_assoc_descriptor *)f->descriptors[0])
+ ->bFirstInterface = i;
+#endif
+
+ return 0;
+}
+
static struct android_usb_function mass_storage_function = {
.name = FUNCTION_NAME,
.bind_config = mass_storage_bind_config,
+ .rebind_config = mass_storage_rebind_config,
};
static int __init init(void)