diff options
-rw-r--r-- | drivers/usb/core/devio.c | 35 | ||||
-rw-r--r-- | drivers/usb/core/driver.c | 3 | ||||
-rw-r--r-- | drivers/usb/core/generic.c | 4 | ||||
-rw-r--r-- | drivers/usb/core/hub.c | 88 | ||||
-rw-r--r-- | drivers/usb/core/usb.h | 7 | ||||
-rw-r--r-- | include/linux/usbdevice_fs.h | 2 |
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 | ||
1553 | static 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 | |||
1567 | static 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 | */ | ||
1262 | static 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 */ | ||
1278 | int 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 | |||
1292 | int 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 | |||
1306 | void 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 */ | ||
1321 | bool 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 | ||
1254 | static void recursively_mark_NOTATTACHED(struct usb_device *udev) | 1332 | static 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, | |||
37 | extern void usb_forced_unbind_intf(struct usb_interface *intf); | 37 | extern void usb_forced_unbind_intf(struct usb_interface *intf); |
38 | extern void usb_rebind_intf(struct usb_interface *intf); | 38 | extern void usb_rebind_intf(struct usb_interface *intf); |
39 | 39 | ||
40 | extern int usb_hub_claim_port(struct usb_device *hdev, unsigned port, | ||
41 | void *owner); | ||
42 | extern int usb_hub_release_port(struct usb_device *hdev, unsigned port, | ||
43 | void *owner); | ||
44 | extern void usb_hub_release_all_ports(struct usb_device *hdev, void *owner); | ||
45 | extern bool usb_device_is_owned(struct usb_device *udev); | ||
46 | |||
40 | extern int usb_hub_init(void); | 47 | extern int usb_hub_init(void); |
41 | extern void usb_hub_cleanup(void); | 48 | extern void usb_hub_cleanup(void); |
42 | extern int usb_major_init(void); | 49 | extern 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 */ |