aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/usb
diff options
context:
space:
mode:
authorHans de Goede <hdegoede@redhat.com>2012-09-08 14:02:05 -0400
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>2012-09-10 14:10:37 -0400
commit0837e7e5270bd5547ba5763f11611dc43f677b3d (patch)
tree7815686351ce050a393cf5aecd52da5b92ea7119 /drivers/usb
parentba2f9dff6c914b91005f687a9d75c8eac110d323 (diff)
usbfs: Add a new disconnect-and-claim ioctl (v2)
Apps which deal with devices which also have a kernel driver, need to do the following: 1) Check which driver is attached, so as to not detach the wrong driver (ie detaching usbfs while another instance of the app is using the device) 2) Detach the kernel driver 3) Claim the interface Where moving from one step to the next for both 1-2 and 2-3 consists of a (small) race window. So currently such apps are racy and people just live with it. This patch adds a new ioctl which makes it possible for apps to do this in a race free manner. For flexibility apps can choose to: 1) Specify the driver to disconnect 2) Specify to disconnect any driver except for the one named by the app 3) Disconnect any driver Note that if there is no driver attached, the ioctl will just act like the regular claim-interface ioctl, this is by design, as returning an error for this condition would open a new bag of race-conditions. Changes in v2: -Fix indentation of if blocks where the condition spans multiple lines Signed-off-by: Hans de Goede <hdegoede@redhat.com> Acked-by: Alan Stern <stern@rowland.harvard.edu> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Diffstat (limited to 'drivers/usb')
-rw-r--r--drivers/usb/core/devio.c35
1 files changed, 35 insertions, 0 deletions
diff --git a/drivers/usb/core/devio.c b/drivers/usb/core/devio.c
index ebb8a9de8b5f..e0356cb859b5 100644
--- a/drivers/usb/core/devio.c
+++ b/drivers/usb/core/devio.c
@@ -1928,6 +1928,38 @@ static int proc_get_capabilities(struct dev_state *ps, void __user *arg)
1928 return 0; 1928 return 0;
1929} 1929}
1930 1930
1931static int proc_disconnect_claim(struct dev_state *ps, void __user *arg)
1932{
1933 struct usbdevfs_disconnect_claim dc;
1934 struct usb_interface *intf;
1935
1936 if (copy_from_user(&dc, arg, sizeof(dc)))
1937 return -EFAULT;
1938
1939 intf = usb_ifnum_to_if(ps->dev, dc.interface);
1940 if (!intf)
1941 return -EINVAL;
1942
1943 if (intf->dev.driver) {
1944 struct usb_driver *driver = to_usb_driver(intf->dev.driver);
1945
1946 if ((dc.flags & USBDEVFS_DISCONNECT_CLAIM_IF_DRIVER) &&
1947 strncmp(dc.driver, intf->dev.driver->name,
1948 sizeof(dc.driver)) != 0)
1949 return -EBUSY;
1950
1951 if ((dc.flags & USBDEVFS_DISCONNECT_CLAIM_EXCEPT_DRIVER) &&
1952 strncmp(dc.driver, intf->dev.driver->name,
1953 sizeof(dc.driver)) == 0)
1954 return -EBUSY;
1955
1956 dev_dbg(&intf->dev, "disconnect by usbfs\n");
1957 usb_driver_release_interface(driver, intf);
1958 }
1959
1960 return claimintf(ps, dc.interface);
1961}
1962
1931/* 1963/*
1932 * NOTE: All requests here that have interface numbers as parameters 1964 * NOTE: All requests here that have interface numbers as parameters
1933 * are assuming that somehow the configuration has been prevented from 1965 * are assuming that somehow the configuration has been prevented from
@@ -2101,6 +2133,9 @@ static long usbdev_do_ioctl(struct file *file, unsigned int cmd,
2101 case USBDEVFS_GET_CAPABILITIES: 2133 case USBDEVFS_GET_CAPABILITIES:
2102 ret = proc_get_capabilities(ps, p); 2134 ret = proc_get_capabilities(ps, p);
2103 break; 2135 break;
2136 case USBDEVFS_DISCONNECT_CLAIM:
2137 ret = proc_disconnect_claim(ps, p);
2138 break;
2104 } 2139 }
2105 usb_unlock_device(dev); 2140 usb_unlock_device(dev);
2106 if (ret >= 0) 2141 if (ret >= 0)