From 602bfb87fc09d6478ea6b43b94fa0b31481fd66f Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Sat, 8 Sep 2012 20:02:05 +0200 Subject: [PATCH] --- yaml --- r: 325855 b: refs/heads/master c: 0837e7e5270bd5547ba5763f11611dc43f677b3d h: refs/heads/master i: 325853: 0825cef34b96bd68f25fb70cea4a9b9a99a63d68 325851: 22d62217891ba439a4ae8c458141989cf01a03a2 325847: 9e5df3730c730ba00615e52eef1d361b91c7b01d 325839: 77e02625a95700e44713beb28ccaaca17c4d1aaf 325823: 03fb2b4eb5ba2ce149f0a821c12fa1642388a734 v: v3 --- [refs] | 2 +- trunk/drivers/usb/core/devio.c | 35 ++++++++++++++++++++++++++++++ trunk/include/linux/usbdevice_fs.h | 14 ++++++++++++ 3 files changed, 50 insertions(+), 1 deletion(-) diff --git a/[refs] b/[refs] index a760bc66eb6b..53be04f8a61b 100644 --- a/[refs] +++ b/[refs] @@ -1,2 +1,2 @@ --- -refs/heads/master: ba2f9dff6c914b91005f687a9d75c8eac110d323 +refs/heads/master: 0837e7e5270bd5547ba5763f11611dc43f677b3d diff --git a/trunk/drivers/usb/core/devio.c b/trunk/drivers/usb/core/devio.c index ebb8a9de8b5f..e0356cb859b5 100644 --- a/trunk/drivers/usb/core/devio.c +++ b/trunk/drivers/usb/core/devio.c @@ -1928,6 +1928,38 @@ static int proc_get_capabilities(struct dev_state *ps, void __user *arg) return 0; } +static int proc_disconnect_claim(struct dev_state *ps, void __user *arg) +{ + struct usbdevfs_disconnect_claim dc; + struct usb_interface *intf; + + if (copy_from_user(&dc, arg, sizeof(dc))) + return -EFAULT; + + intf = usb_ifnum_to_if(ps->dev, dc.interface); + if (!intf) + return -EINVAL; + + if (intf->dev.driver) { + struct usb_driver *driver = to_usb_driver(intf->dev.driver); + + if ((dc.flags & USBDEVFS_DISCONNECT_CLAIM_IF_DRIVER) && + strncmp(dc.driver, intf->dev.driver->name, + sizeof(dc.driver)) != 0) + return -EBUSY; + + if ((dc.flags & USBDEVFS_DISCONNECT_CLAIM_EXCEPT_DRIVER) && + strncmp(dc.driver, intf->dev.driver->name, + sizeof(dc.driver)) == 0) + return -EBUSY; + + dev_dbg(&intf->dev, "disconnect by usbfs\n"); + usb_driver_release_interface(driver, intf); + } + + return claimintf(ps, dc.interface); +} + /* * NOTE: All requests here that have interface numbers as parameters * 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, case USBDEVFS_GET_CAPABILITIES: ret = proc_get_capabilities(ps, p); break; + case USBDEVFS_DISCONNECT_CLAIM: + ret = proc_disconnect_claim(ps, p); + break; } usb_unlock_device(dev); if (ret >= 0) diff --git a/trunk/include/linux/usbdevice_fs.h b/trunk/include/linux/usbdevice_fs.h index 3b74666be027..4abe28e41cbc 100644 --- a/trunk/include/linux/usbdevice_fs.h +++ b/trunk/include/linux/usbdevice_fs.h @@ -131,6 +131,19 @@ struct usbdevfs_hub_portinfo { #define USBDEVFS_CAP_NO_PACKET_SIZE_LIM 0x04 #define USBDEVFS_CAP_BULK_SCATTER_GATHER 0x08 +/* USBDEVFS_DISCONNECT_CLAIM flags & struct */ + +/* disconnect-and-claim if the driver matches the driver field */ +#define USBDEVFS_DISCONNECT_CLAIM_IF_DRIVER 0x01 +/* disconnect-and-claim except when the driver matches the driver field */ +#define USBDEVFS_DISCONNECT_CLAIM_EXCEPT_DRIVER 0x02 + +struct usbdevfs_disconnect_claim { + unsigned int interface; + unsigned int flags; + char driver[USBDEVFS_MAXDRIVERNAME + 1]; +}; + #ifdef __KERNEL__ #ifdef CONFIG_COMPAT #include @@ -211,5 +224,6 @@ struct usbdevfs_ioctl32 { #define USBDEVFS_CLAIM_PORT _IOR('U', 24, unsigned int) #define USBDEVFS_RELEASE_PORT _IOR('U', 25, unsigned int) #define USBDEVFS_GET_CAPABILITIES _IOR('U', 26, __u32) +#define USBDEVFS_DISCONNECT_CLAIM _IOR('U', 27, struct usbdevfs_disconnect_claim) #endif /* _LINUX_USBDEVICE_FS_H */