aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/usb/gadget/composite.c
diff options
context:
space:
mode:
authorSebastian Andrzej Siewior <bigeasy@linutronix.de>2012-12-23 15:09:55 -0500
committerFelipe Balbi <balbi@ti.com>2013-01-21 13:52:37 -0500
commit779d516ca91d796cb37bd0760282d08f90661ee2 (patch)
tree8e5157be9c343294f4270e2b1d9fe1aa0d69bd1f /drivers/usb/gadget/composite.c
parentafd2e186bd7e58dc9d298ff5fb5a2fc30578867e (diff)
usb: gadget: composite: don't call driver's unbind() if bind() failed
Lets assume nokia_bind() starts with "return -EINVAL". After loading the gadget we end up with: |udc dummy_udc.0: registering UDC driver [g_nokia] |BUG: unable to handle kernel NULL pointer dereference at 00000040 |IP: [<c11f9555>] __list_add+0x25/0xf0 |Call Trace: | [<c12d4e21>] rollback_registered+0x21/0x40 | [<c12d513f>] unregister_netdevice_queue+0x4f/0xa0 | [<c12d5259>] unregister_netdev+0x19/0x30 | [<f81335b2>] gphonet_cleanup+0x32/0x50 [g_nokia] | [<f8133f1c>] nokia_unbind+0x1c/0x2a [g_nokia] | [<f802509f>] __composite_unbind.constprop.10+0x4f/0xb0 [libcomposite] | [<f80255be>] composite_bind+0x1ae/0x230 [libcomposite] | [<c129e576>] usb_gadget_probe_driver+0xc6/0x1b0 | [<f8024aba>] usb_composite_probe+0x7a/0xa0 [libcomposite] That is crash from nokia_unbind() invoked via nokia_bind(). This crash will look different we if make it until usb_string_ids_tab() before we enter an error condition in the probe function. nokia_bind_config() tries to clean up which is IMHO the right thing to do. Leaving things as-is and hoping that its unbind() will clean it up is kinda backwards. Especially since the bind function never succeeded so it can't know how much it needs to clean up. This fixes the behaviour by not calling the driver's unbind function if its bind function failed. Signed-off-by: Sebastian Andrzej Siewior <bigeasy@linutronix.de> Signed-off-by: Felipe Balbi <balbi@ti.com>
Diffstat (limited to 'drivers/usb/gadget/composite.c')
-rw-r--r--drivers/usb/gadget/composite.c12
1 files changed, 8 insertions, 4 deletions
diff --git a/drivers/usb/gadget/composite.c b/drivers/usb/gadget/composite.c
index 71475b6d8568..9db000013f5d 100644
--- a/drivers/usb/gadget/composite.c
+++ b/drivers/usb/gadget/composite.c
@@ -1349,8 +1349,7 @@ static ssize_t composite_show_suspended(struct device *dev,
1349 1349
1350static DEVICE_ATTR(suspended, 0444, composite_show_suspended, NULL); 1350static DEVICE_ATTR(suspended, 0444, composite_show_suspended, NULL);
1351 1351
1352static void 1352static void __composite_unbind(struct usb_gadget *gadget, bool unbind_driver)
1353composite_unbind(struct usb_gadget *gadget)
1354{ 1353{
1355 struct usb_composite_dev *cdev = get_gadget_data(gadget); 1354 struct usb_composite_dev *cdev = get_gadget_data(gadget);
1356 1355
@@ -1367,7 +1366,7 @@ composite_unbind(struct usb_gadget *gadget)
1367 struct usb_configuration, list); 1366 struct usb_configuration, list);
1368 remove_config(cdev, c); 1367 remove_config(cdev, c);
1369 } 1368 }
1370 if (cdev->driver->unbind) 1369 if (cdev->driver->unbind && unbind_driver)
1371 cdev->driver->unbind(cdev); 1370 cdev->driver->unbind(cdev);
1372 1371
1373 if (cdev->req) { 1372 if (cdev->req) {
@@ -1380,6 +1379,11 @@ composite_unbind(struct usb_gadget *gadget)
1380 set_gadget_data(gadget, NULL); 1379 set_gadget_data(gadget, NULL);
1381} 1380}
1382 1381
1382static void composite_unbind(struct usb_gadget *gadget)
1383{
1384 __composite_unbind(gadget, true);
1385}
1386
1383static void update_unchanged_dev_desc(struct usb_device_descriptor *new, 1387static void update_unchanged_dev_desc(struct usb_device_descriptor *new,
1384 const struct usb_device_descriptor *old) 1388 const struct usb_device_descriptor *old)
1385{ 1389{
@@ -1488,7 +1492,7 @@ static int composite_bind(struct usb_gadget *gadget,
1488 return 0; 1492 return 0;
1489 1493
1490fail: 1494fail:
1491 composite_unbind(gadget); 1495 __composite_unbind(gadget, false);
1492 return status; 1496 return status;
1493} 1497}
1494 1498