diff options
author | sidhartk <sidhartk@bnru02.(none)> | 2010-12-14 17:34:35 +0530 |
---|---|---|
committer | Jonas ABERG <jonas.aberg@stericsson.com> | 2010-12-14 17:29:07 +0100 |
commit | b0897f45370d34efdaa2a4fb349b23048d173097 (patch) | |
tree | 102ef810bcd9dc959ded35bf5fd1b2d1c0ee86fc /drivers/usb | |
parent | 033519a8fae48f118cd1426d13356632ac2e2967 (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.c | 27 | ||||
-rw-r--r-- | drivers/usb/gadget/f_acm.c | 82 | ||||
-rw-r--r-- | drivers/usb/gadget/f_adb.c | 20 | ||||
-rw-r--r-- | drivers/usb/gadget/f_ecm.c | 91 | ||||
-rw-r--r-- | drivers/usb/gadget/f_mass_storage.c | 28 |
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) |