diff options
Diffstat (limited to 'drivers/usb/core/hub.c')
-rw-r--r-- | drivers/usb/core/hub.c | 126 |
1 files changed, 108 insertions, 18 deletions
diff --git a/drivers/usb/core/hub.c b/drivers/usb/core/hub.c index 71f86c60d83c..5ce839137ad6 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 | ||
@@ -162,8 +163,10 @@ static inline char *portspeed(int portstatus) | |||
162 | } | 163 | } |
163 | 164 | ||
164 | /* Note that hdev or one of its children must be locked! */ | 165 | /* Note that hdev or one of its children must be locked! */ |
165 | static inline struct usb_hub *hdev_to_hub(struct usb_device *hdev) | 166 | static struct usb_hub *hdev_to_hub(struct usb_device *hdev) |
166 | { | 167 | { |
168 | if (!hdev || !hdev->actconfig) | ||
169 | return NULL; | ||
167 | return usb_get_intfdata(hdev->actconfig->interface[0]); | 170 | return usb_get_intfdata(hdev->actconfig->interface[0]); |
168 | } | 171 | } |
169 | 172 | ||
@@ -372,7 +375,7 @@ static void kick_khubd(struct usb_hub *hub) | |||
372 | unsigned long flags; | 375 | unsigned long flags; |
373 | 376 | ||
374 | /* Suppress autosuspend until khubd runs */ | 377 | /* Suppress autosuspend until khubd runs */ |
375 | to_usb_interface(hub->intfdev)->pm_usage_cnt = 1; | 378 | atomic_set(&to_usb_interface(hub->intfdev)->pm_usage_cnt, 1); |
376 | 379 | ||
377 | spin_lock_irqsave(&hub_event_lock, flags); | 380 | spin_lock_irqsave(&hub_event_lock, flags); |
378 | if (!hub->disconnected && list_empty(&hub->event_list)) { | 381 | if (!hub->disconnected && list_empty(&hub->event_list)) { |
@@ -384,8 +387,10 @@ static void kick_khubd(struct usb_hub *hub) | |||
384 | 387 | ||
385 | void usb_kick_khubd(struct usb_device *hdev) | 388 | void usb_kick_khubd(struct usb_device *hdev) |
386 | { | 389 | { |
387 | /* FIXME: What if hdev isn't bound to the hub driver? */ | 390 | struct usb_hub *hub = hdev_to_hub(hdev); |
388 | kick_khubd(hdev_to_hub(hdev)); | 391 | |
392 | if (hub) | ||
393 | kick_khubd(hub); | ||
389 | } | 394 | } |
390 | 395 | ||
391 | 396 | ||
@@ -677,7 +682,8 @@ static void hub_activate(struct usb_hub *hub, enum hub_activation_type type) | |||
677 | msecs_to_jiffies(delay)); | 682 | msecs_to_jiffies(delay)); |
678 | 683 | ||
679 | /* Suppress autosuspend until init is done */ | 684 | /* Suppress autosuspend until init is done */ |
680 | to_usb_interface(hub->intfdev)->pm_usage_cnt = 1; | 685 | atomic_set(&to_usb_interface(hub->intfdev)-> |
686 | pm_usage_cnt, 1); | ||
681 | return; /* Continues at init2: below */ | 687 | return; /* Continues at init2: below */ |
682 | } else { | 688 | } else { |
683 | hub_power_on(hub, true); | 689 | hub_power_on(hub, true); |
@@ -854,25 +860,24 @@ static int hub_post_reset(struct usb_interface *intf) | |||
854 | static int hub_configure(struct usb_hub *hub, | 860 | static int hub_configure(struct usb_hub *hub, |
855 | struct usb_endpoint_descriptor *endpoint) | 861 | struct usb_endpoint_descriptor *endpoint) |
856 | { | 862 | { |
863 | struct usb_hcd *hcd; | ||
857 | struct usb_device *hdev = hub->hdev; | 864 | struct usb_device *hdev = hub->hdev; |
858 | struct device *hub_dev = hub->intfdev; | 865 | struct device *hub_dev = hub->intfdev; |
859 | u16 hubstatus, hubchange; | 866 | u16 hubstatus, hubchange; |
860 | u16 wHubCharacteristics; | 867 | u16 wHubCharacteristics; |
861 | unsigned int pipe; | 868 | unsigned int pipe; |
862 | int maxp, ret; | 869 | int maxp, ret; |
863 | char *message; | 870 | char *message = "out of memory"; |
864 | 871 | ||
865 | hub->buffer = usb_buffer_alloc(hdev, sizeof(*hub->buffer), GFP_KERNEL, | 872 | hub->buffer = usb_buffer_alloc(hdev, sizeof(*hub->buffer), GFP_KERNEL, |
866 | &hub->buffer_dma); | 873 | &hub->buffer_dma); |
867 | if (!hub->buffer) { | 874 | if (!hub->buffer) { |
868 | message = "can't allocate hub irq buffer"; | ||
869 | ret = -ENOMEM; | 875 | ret = -ENOMEM; |
870 | goto fail; | 876 | goto fail; |
871 | } | 877 | } |
872 | 878 | ||
873 | hub->status = kmalloc(sizeof(*hub->status), GFP_KERNEL); | 879 | hub->status = kmalloc(sizeof(*hub->status), GFP_KERNEL); |
874 | if (!hub->status) { | 880 | if (!hub->status) { |
875 | message = "can't kmalloc hub status buffer"; | ||
876 | ret = -ENOMEM; | 881 | ret = -ENOMEM; |
877 | goto fail; | 882 | goto fail; |
878 | } | 883 | } |
@@ -880,7 +885,6 @@ static int hub_configure(struct usb_hub *hub, | |||
880 | 885 | ||
881 | hub->descriptor = kmalloc(sizeof(*hub->descriptor), GFP_KERNEL); | 886 | hub->descriptor = kmalloc(sizeof(*hub->descriptor), GFP_KERNEL); |
882 | if (!hub->descriptor) { | 887 | if (!hub->descriptor) { |
883 | message = "can't kmalloc hub descriptor"; | ||
884 | ret = -ENOMEM; | 888 | ret = -ENOMEM; |
885 | goto fail; | 889 | goto fail; |
886 | } | 890 | } |
@@ -904,6 +908,12 @@ static int hub_configure(struct usb_hub *hub, | |||
904 | dev_info (hub_dev, "%d port%s detected\n", hdev->maxchild, | 908 | dev_info (hub_dev, "%d port%s detected\n", hdev->maxchild, |
905 | (hdev->maxchild == 1) ? "" : "s"); | 909 | (hdev->maxchild == 1) ? "" : "s"); |
906 | 910 | ||
911 | hub->port_owners = kzalloc(hdev->maxchild * sizeof(void *), GFP_KERNEL); | ||
912 | if (!hub->port_owners) { | ||
913 | ret = -ENOMEM; | ||
914 | goto fail; | ||
915 | } | ||
916 | |||
907 | wHubCharacteristics = le16_to_cpu(hub->descriptor->wHubCharacteristics); | 917 | wHubCharacteristics = le16_to_cpu(hub->descriptor->wHubCharacteristics); |
908 | 918 | ||
909 | if (wHubCharacteristics & HUB_CHAR_COMPOUND) { | 919 | if (wHubCharacteristics & HUB_CHAR_COMPOUND) { |
@@ -1052,6 +1062,19 @@ static int hub_configure(struct usb_hub *hub, | |||
1052 | dev_dbg(hub_dev, "%umA bus power budget for each child\n", | 1062 | dev_dbg(hub_dev, "%umA bus power budget for each child\n", |
1053 | hub->mA_per_port); | 1063 | hub->mA_per_port); |
1054 | 1064 | ||
1065 | /* Update the HCD's internal representation of this hub before khubd | ||
1066 | * starts getting port status changes for devices under the hub. | ||
1067 | */ | ||
1068 | hcd = bus_to_hcd(hdev->bus); | ||
1069 | if (hcd->driver->update_hub_device) { | ||
1070 | ret = hcd->driver->update_hub_device(hcd, hdev, | ||
1071 | &hub->tt, GFP_KERNEL); | ||
1072 | if (ret < 0) { | ||
1073 | message = "can't update HCD hub info"; | ||
1074 | goto fail; | ||
1075 | } | ||
1076 | } | ||
1077 | |||
1055 | ret = hub_hub_status(hub, &hubstatus, &hubchange); | 1078 | ret = hub_hub_status(hub, &hubstatus, &hubchange); |
1056 | if (ret < 0) { | 1079 | if (ret < 0) { |
1057 | message = "can't get hub status"; | 1080 | message = "can't get hub status"; |
@@ -1082,7 +1105,6 @@ static int hub_configure(struct usb_hub *hub, | |||
1082 | 1105 | ||
1083 | hub->urb = usb_alloc_urb(0, GFP_KERNEL); | 1106 | hub->urb = usb_alloc_urb(0, GFP_KERNEL); |
1084 | if (!hub->urb) { | 1107 | if (!hub->urb) { |
1085 | message = "couldn't allocate interrupt urb"; | ||
1086 | ret = -ENOMEM; | 1108 | ret = -ENOMEM; |
1087 | goto fail; | 1109 | goto fail; |
1088 | } | 1110 | } |
@@ -1131,11 +1153,13 @@ static void hub_disconnect(struct usb_interface *intf) | |||
1131 | hub_quiesce(hub, HUB_DISCONNECT); | 1153 | hub_quiesce(hub, HUB_DISCONNECT); |
1132 | 1154 | ||
1133 | usb_set_intfdata (intf, NULL); | 1155 | usb_set_intfdata (intf, NULL); |
1156 | hub->hdev->maxchild = 0; | ||
1134 | 1157 | ||
1135 | if (hub->hdev->speed == USB_SPEED_HIGH) | 1158 | if (hub->hdev->speed == USB_SPEED_HIGH) |
1136 | highspeed_hubs--; | 1159 | highspeed_hubs--; |
1137 | 1160 | ||
1138 | usb_free_urb(hub->urb); | 1161 | usb_free_urb(hub->urb); |
1162 | kfree(hub->port_owners); | ||
1139 | kfree(hub->descriptor); | 1163 | kfree(hub->descriptor); |
1140 | kfree(hub->status); | 1164 | kfree(hub->status); |
1141 | usb_buffer_free(hub->hdev, sizeof(*hub->buffer), hub->buffer, | 1165 | usb_buffer_free(hub->hdev, sizeof(*hub->buffer), hub->buffer, |
@@ -1250,6 +1274,79 @@ hub_ioctl(struct usb_interface *intf, unsigned int code, void *user_data) | |||
1250 | } | 1274 | } |
1251 | } | 1275 | } |
1252 | 1276 | ||
1277 | /* | ||
1278 | * Allow user programs to claim ports on a hub. When a device is attached | ||
1279 | * to one of these "claimed" ports, the program will "own" the device. | ||
1280 | */ | ||
1281 | static int find_port_owner(struct usb_device *hdev, unsigned port1, | ||
1282 | void ***ppowner) | ||
1283 | { | ||
1284 | if (hdev->state == USB_STATE_NOTATTACHED) | ||
1285 | return -ENODEV; | ||
1286 | if (port1 == 0 || port1 > hdev->maxchild) | ||
1287 | return -EINVAL; | ||
1288 | |||
1289 | /* This assumes that devices not managed by the hub driver | ||
1290 | * will always have maxchild equal to 0. | ||
1291 | */ | ||
1292 | *ppowner = &(hdev_to_hub(hdev)->port_owners[port1 - 1]); | ||
1293 | return 0; | ||
1294 | } | ||
1295 | |||
1296 | /* In the following three functions, the caller must hold hdev's lock */ | ||
1297 | int usb_hub_claim_port(struct usb_device *hdev, unsigned port1, void *owner) | ||
1298 | { | ||
1299 | int rc; | ||
1300 | void **powner; | ||
1301 | |||
1302 | rc = find_port_owner(hdev, port1, &powner); | ||
1303 | if (rc) | ||
1304 | return rc; | ||
1305 | if (*powner) | ||
1306 | return -EBUSY; | ||
1307 | *powner = owner; | ||
1308 | return rc; | ||
1309 | } | ||
1310 | |||
1311 | int usb_hub_release_port(struct usb_device *hdev, unsigned port1, void *owner) | ||
1312 | { | ||
1313 | int rc; | ||
1314 | void **powner; | ||
1315 | |||
1316 | rc = find_port_owner(hdev, port1, &powner); | ||
1317 | if (rc) | ||
1318 | return rc; | ||
1319 | if (*powner != owner) | ||
1320 | return -ENOENT; | ||
1321 | *powner = NULL; | ||
1322 | return rc; | ||
1323 | } | ||
1324 | |||
1325 | void usb_hub_release_all_ports(struct usb_device *hdev, void *owner) | ||
1326 | { | ||
1327 | int n; | ||
1328 | void **powner; | ||
1329 | |||
1330 | n = find_port_owner(hdev, 1, &powner); | ||
1331 | if (n == 0) { | ||
1332 | for (; n < hdev->maxchild; (++n, ++powner)) { | ||
1333 | if (*powner == owner) | ||
1334 | *powner = NULL; | ||
1335 | } | ||
1336 | } | ||
1337 | } | ||
1338 | |||
1339 | /* The caller must hold udev's lock */ | ||
1340 | bool usb_device_is_owned(struct usb_device *udev) | ||
1341 | { | ||
1342 | struct usb_hub *hub; | ||
1343 | |||
1344 | if (udev->state == USB_STATE_NOTATTACHED || !udev->parent) | ||
1345 | return false; | ||
1346 | hub = hdev_to_hub(udev->parent); | ||
1347 | return !!hub->port_owners[udev->portnum - 1]; | ||
1348 | } | ||
1349 | |||
1253 | 1350 | ||
1254 | static void recursively_mark_NOTATTACHED(struct usb_device *udev) | 1351 | static void recursively_mark_NOTATTACHED(struct usb_device *udev) |
1255 | { | 1352 | { |
@@ -2849,14 +2946,7 @@ static void hub_port_connect_change(struct usb_hub *hub, int port1, | |||
2849 | /* For a suspended device, treat this as a | 2946 | /* For a suspended device, treat this as a |
2850 | * remote wakeup event. | 2947 | * remote wakeup event. |
2851 | */ | 2948 | */ |
2852 | if (udev->do_remote_wakeup) | 2949 | status = remote_wakeup(udev); |
2853 | status = remote_wakeup(udev); | ||
2854 | |||
2855 | /* Otherwise leave it be; devices can't tell the | ||
2856 | * difference between suspended and disabled. | ||
2857 | */ | ||
2858 | else | ||
2859 | status = 0; | ||
2860 | #endif | 2950 | #endif |
2861 | 2951 | ||
2862 | } else { | 2952 | } else { |