aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-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 */