Commit 9496c745 authored by Oliver Neukum's avatar Oliver Neukum Committed by Greg Kroah-Hartman

[PATCH] USB: correct error handling in usb_driver_claim_interface()

this function races with itself, doesn't return errors and races with
releasing interfaces. This patch fixes it by changing the function
prototype, introducing locking and having a correct order in
releasing interfaces.

  - API change to check errors in usb_driver_claim_interface and
    fix a race condition between releasing and reclaiming an interface
parent 09a12dff
...@@ -261,24 +261,27 @@ usb_epnum_to_ep_desc(struct usb_device *dev, unsigned epnum) ...@@ -261,24 +261,27 @@ usb_epnum_to_ep_desc(struct usb_device *dev, unsigned epnum)
* *
* Few drivers should need to use this routine, since the most natural * Few drivers should need to use this routine, since the most natural
* way to bind to an interface is to return the private data from * way to bind to an interface is to return the private data from
* the driver's probe() method. Any driver that does use this must * the driver's probe() method.
* first be sure that no other driver has claimed the interface, by
* checking with usb_interface_claimed().
*/ */
void usb_driver_claim_interface(struct usb_driver *driver, struct usb_interface *iface, void* priv) int usb_driver_claim_interface(struct usb_driver *driver, struct usb_interface *iface, void* priv)
{ {
if (!iface || !driver) if (!iface || !driver)
return; return -EINVAL;
// FIXME change API to report an error in this case lock_kernel();
if (iface->driver) if (iface->driver) {
unlock_kernel();
err ("%s driver booted %s off interface %p", err ("%s driver booted %s off interface %p",
driver->name, iface->driver->name, iface); driver->name, iface->driver->name, iface);
else return -EBUSY;
} else {
dbg("%s driver claimed interface %p", driver->name, iface); dbg("%s driver claimed interface %p", driver->name, iface);
}
iface->driver = driver; iface->driver = driver;
usb_set_intfdata(iface, priv); usb_set_intfdata(iface, priv);
unlock_kernel();
return 0;
} }
/** /**
...@@ -324,11 +327,11 @@ void usb_driver_release_interface(struct usb_driver *driver, struct usb_interfac ...@@ -324,11 +327,11 @@ void usb_driver_release_interface(struct usb_driver *driver, struct usb_interfac
if (iface->driver && iface->driver != driver) if (iface->driver && iface->driver != driver)
return; return;
iface->driver = NULL;
usb_set_intfdata(iface, NULL);
usb_set_interface(interface_to_usbdev(iface), usb_set_interface(interface_to_usbdev(iface),
iface->altsetting[0].desc.bInterfaceNumber, iface->altsetting[0].desc.bInterfaceNumber,
0); 0);
usb_set_intfdata(iface, NULL);
iface->driver = NULL;
} }
/** /**
......
...@@ -290,7 +290,7 @@ extern struct usb_device *usb_find_device(u16 vendor_id, u16 product_id); ...@@ -290,7 +290,7 @@ extern struct usb_device *usb_find_device(u16 vendor_id, u16 product_id);
extern int usb_get_current_frame_number (struct usb_device *usb_dev); extern int usb_get_current_frame_number (struct usb_device *usb_dev);
/* used these for multi-interface device registration */ /* used these for multi-interface device registration */
extern void usb_driver_claim_interface(struct usb_driver *driver, extern int usb_driver_claim_interface(struct usb_driver *driver,
struct usb_interface *iface, void* priv); struct usb_interface *iface, void* priv);
extern int usb_interface_claimed(struct usb_interface *iface); extern int usb_interface_claimed(struct usb_interface *iface);
extern void usb_driver_release_interface(struct usb_driver *driver, extern void usb_driver_release_interface(struct usb_driver *driver,
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment