aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAlan Stern <stern@rowland.harvard.edu>2009-06-29 10:56:54 -0400
committerGreg Kroah-Hartman <gregkh@suse.de>2009-09-23 09:46:22 -0400
commit7cbe5dca399a50ce8aa74314b1d276e2fb904e1b (patch)
treef7a565f3d2f5e9584faffa69d8e8545d4e0c4cdb
parent831baa4915de465357b25c471bbb9b36472024df (diff)
USB: add API for userspace drivers to "claim" ports
This patch (as1258) implements a feature that users have been asking for: It gives programs the ability to "claim" a port on a hub, via a new usbfs ioctl. A device plugged into a "claimed" port will not be touched by the kernel beyond the immediate necessities of initialization and enumeration. In particular, when a device is plugged into a "claimed" port, the kernel will not select and install a configuration. And when a config is installed by usbfs or sysfs, the kernel will not probe any drivers for any of the interfaces. (However the kernel will fetch various string descriptors during enumeration. One could argue that this isn't really necessary, but the strings are exported in sysfs.) The patch does not guarantee exclusive access to these devices; it is still possible for more than one program to open the device file concurrently. Programs are responsible for coordinating access among themselves. A demonstration program showing how to use the new interface can be found in an attachment to http://marc.info/?l=linux-usb&m=124345857431452&w=2 The patch also makes a small simplification to the hub driver, replacing a bunch of more-or-less useless variants of "out of memory" with a single message. Signed-off-by: Alan Stern <stern@rowland.harvard.edu> Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
-rw-r--r--drivers/usb/core/devio.c35
-rw-r--r--drivers/usb/core/driver.c3
-rw-r--r--drivers/usb/core/generic.c4
-rw-r--r--drivers/usb/core/hub.c88
-rw-r--r--drivers/usb/core/usb.h7
-rw-r--r--include/linux/usbdevice_fs.h2
6 files changed, 133 insertions, 6 deletions
diff --git a/drivers/usb/core/devio.c b/drivers/usb/core/devio.c
index 4247eccf858c..165de5d59005 100644
--- a/drivers/usb/core/devio.c
+++ b/drivers/usb/core/devio.c
@@ -52,6 +52,7 @@
52 52
53#include "hcd.h" /* for usbcore internals */ 53#include "hcd.h" /* for usbcore internals */
54#include "usb.h" 54#include "usb.h"
55#include "hub.h"
55 56
56#define USB_MAXBUS 64 57#define USB_MAXBUS 64
57#define USB_DEVICE_MAX USB_MAXBUS * 128 58#define USB_DEVICE_MAX USB_MAXBUS * 128
@@ -655,6 +656,7 @@ static int usbdev_release(struct inode *inode, struct file *file)
655 struct async *as; 656 struct async *as;
656 657
657 usb_lock_device(dev); 658 usb_lock_device(dev);
659 usb_hub_release_all_ports(dev, ps);
658 660
659 /* Protect against simultaneous open */ 661 /* Protect against simultaneous open */
660 mutex_lock(&usbfs_mutex); 662 mutex_lock(&usbfs_mutex);
@@ -1548,6 +1550,29 @@ static int proc_ioctl_compat(struct dev_state *ps, compat_uptr_t arg)
1548} 1550}
1549#endif 1551#endif
1550 1552
1553static int proc_claim_port(struct dev_state *ps, void __user *arg)
1554{
1555 unsigned portnum;
1556 int rc;
1557
1558 if (get_user(portnum, (unsigned __user *) arg))
1559 return -EFAULT;
1560 rc = usb_hub_claim_port(ps->dev, portnum, ps);
1561 if (rc == 0)
1562 snoop(&ps->dev->dev, "port %d claimed by process %d: %s\n",
1563 portnum, task_pid_nr(current), current->comm);
1564 return rc;
1565}
1566
1567static int proc_release_port(struct dev_state *ps, void __user *arg)
1568{
1569 unsigned portnum;
1570
1571 if (get_user(portnum, (unsigned __user *) arg))
1572 return -EFAULT;
1573 return usb_hub_release_port(ps->dev, portnum, ps);
1574}
1575
1551/* 1576/*
1552 * NOTE: All requests here that have interface numbers as parameters 1577 * NOTE: All requests here that have interface numbers as parameters
1553 * are assuming that somehow the configuration has been prevented from 1578 * are assuming that somehow the configuration has been prevented from
@@ -1689,6 +1714,16 @@ static int usbdev_ioctl(struct inode *inode, struct file *file,
1689 snoop(&dev->dev, "%s: IOCTL\n", __func__); 1714 snoop(&dev->dev, "%s: IOCTL\n", __func__);
1690 ret = proc_ioctl_default(ps, p); 1715 ret = proc_ioctl_default(ps, p);
1691 break; 1716 break;
1717
1718 case USBDEVFS_CLAIM_PORT:
1719 snoop(&dev->dev, "%s: CLAIM_PORT\n", __func__);
1720 ret = proc_claim_port(ps, p);
1721 break;
1722
1723 case USBDEVFS_RELEASE_PORT:
1724 snoop(&dev->dev, "%s: RELEASE_PORT\n", __func__);
1725 ret = proc_release_port(ps, p);
1726 break;
1692 } 1727 }
1693 usb_unlock_device(dev); 1728 usb_unlock_device(dev);
1694 if (ret >= 0) 1729 if (ret >= 0)
diff --git a/drivers/usb/core/driver.c b/drivers/usb/core/driver.c
index 69e5773abfce..1bad4e5a6abb 100644
--- a/drivers/usb/core/driver.c
+++ b/drivers/usb/core/driver.c
@@ -207,6 +207,9 @@ static int usb_probe_interface(struct device *dev)
207 207
208 intf->needs_binding = 0; 208 intf->needs_binding = 0;
209 209
210 if (usb_device_is_owned(udev))
211 return -ENODEV;
212
210 if (udev->authorized == 0) { 213 if (udev->authorized == 0) {
211 dev_err(&intf->dev, "Device is not authorized for usage\n"); 214 dev_err(&intf->dev, "Device is not authorized for usage\n");
212 return -ENODEV; 215 return -ENODEV;
diff --git a/drivers/usb/core/generic.c b/drivers/usb/core/generic.c
index 30ecac3af15a..05e6d313961e 100644
--- a/drivers/usb/core/generic.c
+++ b/drivers/usb/core/generic.c
@@ -158,7 +158,9 @@ static int generic_probe(struct usb_device *udev)
158 /* Choose and set the configuration. This registers the interfaces 158 /* Choose and set the configuration. This registers the interfaces
159 * with the driver core and lets interface drivers bind to them. 159 * with the driver core and lets interface drivers bind to them.
160 */ 160 */
161 if (udev->authorized == 0) 161 if (usb_device_is_owned(udev))
162 ; /* Don't configure if the device is owned */
163 else if (udev->authorized == 0)
162 dev_err(&udev->dev, "Device is not authorized for usage\n"); 164 dev_err(&udev->dev, "Device is not authorized for usage\n");
163 else { 165 else {
164 c = usb_choose_configuration(udev); 166 c = usb_choose_configuration(udev);
diff --git a/drivers/usb/core/hub.c b/drivers/usb/core/hub.c
index 71f86c60d83c..cb54420ed583 100644
--- a/drivers/usb/core/hub.c
+++ b/drivers/usb/core/hub.c
@@ -78,6 +78,7 @@ struct usb_hub {
78 u8 indicator[USB_MAXCHILDREN]; 78 u8 indicator[USB_MAXCHILDREN];
79 struct delayed_work leds; 79 struct delayed_work leds;
80 struct delayed_work init_work; 80 struct delayed_work init_work;
81 void **port_owners;
81}; 82};
82 83
83 84
@@ -860,19 +861,17 @@ static int hub_configure(struct usb_hub *hub,
860 u16 wHubCharacteristics; 861 u16 wHubCharacteristics;
861 unsigned int pipe; 862 unsigned int pipe;
862 int maxp, ret; 863 int maxp, ret;
863 char *message; 864 char *message = "out of memory";
864 865
865 hub->buffer = usb_buffer_alloc(hdev, sizeof(*hub->buffer), GFP_KERNEL, 866 hub->buffer = usb_buffer_alloc(hdev, sizeof(*hub->buffer), GFP_KERNEL,
866 &hub->buffer_dma); 867 &hub->buffer_dma);
867 if (!hub->buffer) { 868 if (!hub->buffer) {
868 message = "can't allocate hub irq buffer";
869 ret = -ENOMEM; 869 ret = -ENOMEM;
870 goto fail; 870 goto fail;
871 } 871 }
872 872
873 hub->status = kmalloc(sizeof(*hub->status), GFP_KERNEL); 873 hub->status = kmalloc(sizeof(*hub->status), GFP_KERNEL);
874 if (!hub->status) { 874 if (!hub->status) {
875 message = "can't kmalloc hub status buffer";
876 ret = -ENOMEM; 875 ret = -ENOMEM;
877 goto fail; 876 goto fail;
878 } 877 }
@@ -880,7 +879,6 @@ static int hub_configure(struct usb_hub *hub,
880 879
881 hub->descriptor = kmalloc(sizeof(*hub->descriptor), GFP_KERNEL); 880 hub->descriptor = kmalloc(sizeof(*hub->descriptor), GFP_KERNEL);
882 if (!hub->descriptor) { 881 if (!hub->descriptor) {
883 message = "can't kmalloc hub descriptor";
884 ret = -ENOMEM; 882 ret = -ENOMEM;
885 goto fail; 883 goto fail;
886 } 884 }
@@ -904,6 +902,12 @@ static int hub_configure(struct usb_hub *hub,
904 dev_info (hub_dev, "%d port%s detected\n", hdev->maxchild, 902 dev_info (hub_dev, "%d port%s detected\n", hdev->maxchild,
905 (hdev->maxchild == 1) ? "" : "s"); 903 (hdev->maxchild == 1) ? "" : "s");
906 904
905 hub->port_owners = kzalloc(hdev->maxchild * sizeof(void *), GFP_KERNEL);
906 if (!hub->port_owners) {
907 ret = -ENOMEM;
908 goto fail;
909 }
910
907 wHubCharacteristics = le16_to_cpu(hub->descriptor->wHubCharacteristics); 911 wHubCharacteristics = le16_to_cpu(hub->descriptor->wHubCharacteristics);
908 912
909 if (wHubCharacteristics & HUB_CHAR_COMPOUND) { 913 if (wHubCharacteristics & HUB_CHAR_COMPOUND) {
@@ -1082,7 +1086,6 @@ static int hub_configure(struct usb_hub *hub,
1082 1086
1083 hub->urb = usb_alloc_urb(0, GFP_KERNEL); 1087 hub->urb = usb_alloc_urb(0, GFP_KERNEL);
1084 if (!hub->urb) { 1088 if (!hub->urb) {
1085 message = "couldn't allocate interrupt urb";
1086 ret = -ENOMEM; 1089 ret = -ENOMEM;
1087 goto fail; 1090 goto fail;
1088 } 1091 }
@@ -1131,11 +1134,13 @@ static void hub_disconnect(struct usb_interface *intf)
1131 hub_quiesce(hub, HUB_DISCONNECT); 1134 hub_quiesce(hub, HUB_DISCONNECT);
1132 1135
1133 usb_set_intfdata (intf, NULL); 1136 usb_set_intfdata (intf, NULL);
1137 hub->hdev->maxchild = 0;
1134 1138
1135 if (hub->hdev->speed == USB_SPEED_HIGH) 1139 if (hub->hdev->speed == USB_SPEED_HIGH)
1136 highspeed_hubs--; 1140 highspeed_hubs--;
1137 1141
1138 usb_free_urb(hub->urb); 1142 usb_free_urb(hub->urb);
1143 kfree(hub->port_owners);
1139 kfree(hub->descriptor); 1144 kfree(hub->descriptor);
1140 kfree(hub->status); 1145 kfree(hub->status);
1141 usb_buffer_free(hub->hdev, sizeof(*hub->buffer), hub->buffer, 1146 usb_buffer_free(hub->hdev, sizeof(*hub->buffer), hub->buffer,
@@ -1250,6 +1255,79 @@ hub_ioctl(struct usb_interface *intf, unsigned int code, void *user_data)
1250 } 1255 }
1251} 1256}
1252 1257
1258/*
1259 * Allow user programs to claim ports on a hub. When a device is attached
1260 * to one of these "claimed" ports, the program will "own" the device.
1261 */
1262static int find_port_owner(struct usb_device *hdev, unsigned port1,
1263 void ***ppowner)
1264{
1265 if (hdev->state == USB_STATE_NOTATTACHED)
1266 return -ENODEV;
1267 if (port1 == 0 || port1 > hdev->maxchild)
1268 return -EINVAL;
1269
1270 /* This assumes that devices not managed by the hub driver
1271 * will always have maxchild equal to 0.
1272 */
1273 *ppowner = &(hdev_to_hub(hdev)->port_owners[port1 - 1]);
1274 return 0;
1275}
1276
1277/* In the following three functions, the caller must hold hdev's lock */
1278int usb_hub_claim_port(struct usb_device *hdev, unsigned port1, void *owner)
1279{
1280 int rc;
1281 void **powner;
1282
1283 rc = find_port_owner(hdev, port1, &powner);
1284 if (rc)
1285 return rc;
1286 if (*powner)
1287 return -EBUSY;
1288 *powner = owner;
1289 return rc;
1290}
1291
1292int usb_hub_release_port(struct usb_device *hdev, unsigned port1, void *owner)
1293{
1294 int rc;
1295 void **powner;
1296
1297 rc = find_port_owner(hdev, port1, &powner);
1298 if (rc)
1299 return rc;
1300 if (*powner != owner)
1301 return -ENOENT;
1302 *powner = NULL;
1303 return rc;
1304}
1305
1306void usb_hub_release_all_ports(struct usb_device *hdev, void *owner)
1307{
1308 int n;
1309 void **powner;
1310
1311 n = find_port_owner(hdev, 1, &powner);
1312 if (n == 0) {
1313 for (; n < hdev->maxchild; (++n, ++powner)) {
1314 if (*powner == owner)
1315 *powner = NULL;
1316 }
1317 }
1318}
1319
1320/* The caller must hold udev's lock */
1321bool usb_device_is_owned(struct usb_device *udev)
1322{
1323 struct usb_hub *hub;
1324
1325 if (udev->state == USB_STATE_NOTATTACHED || !udev->parent)
1326 return false;
1327 hub = hdev_to_hub(udev->parent);
1328 return !!hub->port_owners[udev->portnum - 1];
1329}
1330
1253 1331
1254static void recursively_mark_NOTATTACHED(struct usb_device *udev) 1332static void recursively_mark_NOTATTACHED(struct usb_device *udev)
1255{ 1333{
diff --git a/drivers/usb/core/usb.h b/drivers/usb/core/usb.h
index c0e0ae2bb8e7..9a8b15e6377a 100644
--- a/drivers/usb/core/usb.h
+++ b/drivers/usb/core/usb.h
@@ -37,6 +37,13 @@ extern int usb_match_device(struct usb_device *dev,
37extern void usb_forced_unbind_intf(struct usb_interface *intf); 37extern void usb_forced_unbind_intf(struct usb_interface *intf);
38extern void usb_rebind_intf(struct usb_interface *intf); 38extern void usb_rebind_intf(struct usb_interface *intf);
39 39
40extern int usb_hub_claim_port(struct usb_device *hdev, unsigned port,
41 void *owner);
42extern int usb_hub_release_port(struct usb_device *hdev, unsigned port,
43 void *owner);
44extern void usb_hub_release_all_ports(struct usb_device *hdev, void *owner);
45extern bool usb_device_is_owned(struct usb_device *udev);
46
40extern int usb_hub_init(void); 47extern int usb_hub_init(void);
41extern void usb_hub_cleanup(void); 48extern void usb_hub_cleanup(void);
42extern int usb_major_init(void); 49extern int usb_major_init(void);
diff --git a/include/linux/usbdevice_fs.h b/include/linux/usbdevice_fs.h
index 0044d9b4cb85..00ceebeb9e5c 100644
--- a/include/linux/usbdevice_fs.h
+++ b/include/linux/usbdevice_fs.h
@@ -175,4 +175,6 @@ struct usbdevfs_ioctl32 {
175#define USBDEVFS_CLEAR_HALT _IOR('U', 21, unsigned int) 175#define USBDEVFS_CLEAR_HALT _IOR('U', 21, unsigned int)
176#define USBDEVFS_DISCONNECT _IO('U', 22) 176#define USBDEVFS_DISCONNECT _IO('U', 22)
177#define USBDEVFS_CONNECT _IO('U', 23) 177#define USBDEVFS_CONNECT _IO('U', 23)
178#define USBDEVFS_CLAIM_PORT _IOR('U', 24, unsigned int)
179#define USBDEVFS_RELEASE_PORT _IOR('U', 25, unsigned int)
178#endif /* _LINUX_USBDEVICE_FS_H */ 180#endif /* _LINUX_USBDEVICE_FS_H */