|
@@ -78,6 +78,7 @@ struct usb_hub {
|
|
u8 indicator[USB_MAXCHILDREN];
|
|
u8 indicator[USB_MAXCHILDREN];
|
|
struct delayed_work leds;
|
|
struct delayed_work leds;
|
|
struct delayed_work init_work;
|
|
struct delayed_work init_work;
|
|
|
|
+ void **port_owners;
|
|
};
|
|
};
|
|
|
|
|
|
|
|
|
|
@@ -860,19 +861,17 @@ static int hub_configure(struct usb_hub *hub,
|
|
u16 wHubCharacteristics;
|
|
u16 wHubCharacteristics;
|
|
unsigned int pipe;
|
|
unsigned int pipe;
|
|
int maxp, ret;
|
|
int maxp, ret;
|
|
- char *message;
|
|
|
|
|
|
+ char *message = "out of memory";
|
|
|
|
|
|
hub->buffer = usb_buffer_alloc(hdev, sizeof(*hub->buffer), GFP_KERNEL,
|
|
hub->buffer = usb_buffer_alloc(hdev, sizeof(*hub->buffer), GFP_KERNEL,
|
|
&hub->buffer_dma);
|
|
&hub->buffer_dma);
|
|
if (!hub->buffer) {
|
|
if (!hub->buffer) {
|
|
- message = "can't allocate hub irq buffer";
|
|
|
|
ret = -ENOMEM;
|
|
ret = -ENOMEM;
|
|
goto fail;
|
|
goto fail;
|
|
}
|
|
}
|
|
|
|
|
|
hub->status = kmalloc(sizeof(*hub->status), GFP_KERNEL);
|
|
hub->status = kmalloc(sizeof(*hub->status), GFP_KERNEL);
|
|
if (!hub->status) {
|
|
if (!hub->status) {
|
|
- message = "can't kmalloc hub status buffer";
|
|
|
|
ret = -ENOMEM;
|
|
ret = -ENOMEM;
|
|
goto fail;
|
|
goto fail;
|
|
}
|
|
}
|
|
@@ -880,7 +879,6 @@ static int hub_configure(struct usb_hub *hub,
|
|
|
|
|
|
hub->descriptor = kmalloc(sizeof(*hub->descriptor), GFP_KERNEL);
|
|
hub->descriptor = kmalloc(sizeof(*hub->descriptor), GFP_KERNEL);
|
|
if (!hub->descriptor) {
|
|
if (!hub->descriptor) {
|
|
- message = "can't kmalloc hub descriptor";
|
|
|
|
ret = -ENOMEM;
|
|
ret = -ENOMEM;
|
|
goto fail;
|
|
goto fail;
|
|
}
|
|
}
|
|
@@ -904,6 +902,12 @@ static int hub_configure(struct usb_hub *hub,
|
|
dev_info (hub_dev, "%d port%s detected\n", hdev->maxchild,
|
|
dev_info (hub_dev, "%d port%s detected\n", hdev->maxchild,
|
|
(hdev->maxchild == 1) ? "" : "s");
|
|
(hdev->maxchild == 1) ? "" : "s");
|
|
|
|
|
|
|
|
+ hub->port_owners = kzalloc(hdev->maxchild * sizeof(void *), GFP_KERNEL);
|
|
|
|
+ if (!hub->port_owners) {
|
|
|
|
+ ret = -ENOMEM;
|
|
|
|
+ goto fail;
|
|
|
|
+ }
|
|
|
|
+
|
|
wHubCharacteristics = le16_to_cpu(hub->descriptor->wHubCharacteristics);
|
|
wHubCharacteristics = le16_to_cpu(hub->descriptor->wHubCharacteristics);
|
|
|
|
|
|
if (wHubCharacteristics & HUB_CHAR_COMPOUND) {
|
|
if (wHubCharacteristics & HUB_CHAR_COMPOUND) {
|
|
@@ -1082,7 +1086,6 @@ static int hub_configure(struct usb_hub *hub,
|
|
|
|
|
|
hub->urb = usb_alloc_urb(0, GFP_KERNEL);
|
|
hub->urb = usb_alloc_urb(0, GFP_KERNEL);
|
|
if (!hub->urb) {
|
|
if (!hub->urb) {
|
|
- message = "couldn't allocate interrupt urb";
|
|
|
|
ret = -ENOMEM;
|
|
ret = -ENOMEM;
|
|
goto fail;
|
|
goto fail;
|
|
}
|
|
}
|
|
@@ -1131,11 +1134,13 @@ static void hub_disconnect(struct usb_interface *intf)
|
|
hub_quiesce(hub, HUB_DISCONNECT);
|
|
hub_quiesce(hub, HUB_DISCONNECT);
|
|
|
|
|
|
usb_set_intfdata (intf, NULL);
|
|
usb_set_intfdata (intf, NULL);
|
|
|
|
+ hub->hdev->maxchild = 0;
|
|
|
|
|
|
if (hub->hdev->speed == USB_SPEED_HIGH)
|
|
if (hub->hdev->speed == USB_SPEED_HIGH)
|
|
highspeed_hubs--;
|
|
highspeed_hubs--;
|
|
|
|
|
|
usb_free_urb(hub->urb);
|
|
usb_free_urb(hub->urb);
|
|
|
|
+ kfree(hub->port_owners);
|
|
kfree(hub->descriptor);
|
|
kfree(hub->descriptor);
|
|
kfree(hub->status);
|
|
kfree(hub->status);
|
|
usb_buffer_free(hub->hdev, sizeof(*hub->buffer), hub->buffer,
|
|
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)
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+/*
|
|
|
|
+ * Allow user programs to claim ports on a hub. When a device is attached
|
|
|
|
+ * to one of these "claimed" ports, the program will "own" the device.
|
|
|
|
+ */
|
|
|
|
+static int find_port_owner(struct usb_device *hdev, unsigned port1,
|
|
|
|
+ void ***ppowner)
|
|
|
|
+{
|
|
|
|
+ if (hdev->state == USB_STATE_NOTATTACHED)
|
|
|
|
+ return -ENODEV;
|
|
|
|
+ if (port1 == 0 || port1 > hdev->maxchild)
|
|
|
|
+ return -EINVAL;
|
|
|
|
+
|
|
|
|
+ /* This assumes that devices not managed by the hub driver
|
|
|
|
+ * will always have maxchild equal to 0.
|
|
|
|
+ */
|
|
|
|
+ *ppowner = &(hdev_to_hub(hdev)->port_owners[port1 - 1]);
|
|
|
|
+ return 0;
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+/* In the following three functions, the caller must hold hdev's lock */
|
|
|
|
+int usb_hub_claim_port(struct usb_device *hdev, unsigned port1, void *owner)
|
|
|
|
+{
|
|
|
|
+ int rc;
|
|
|
|
+ void **powner;
|
|
|
|
+
|
|
|
|
+ rc = find_port_owner(hdev, port1, &powner);
|
|
|
|
+ if (rc)
|
|
|
|
+ return rc;
|
|
|
|
+ if (*powner)
|
|
|
|
+ return -EBUSY;
|
|
|
|
+ *powner = owner;
|
|
|
|
+ return rc;
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+int usb_hub_release_port(struct usb_device *hdev, unsigned port1, void *owner)
|
|
|
|
+{
|
|
|
|
+ int rc;
|
|
|
|
+ void **powner;
|
|
|
|
+
|
|
|
|
+ rc = find_port_owner(hdev, port1, &powner);
|
|
|
|
+ if (rc)
|
|
|
|
+ return rc;
|
|
|
|
+ if (*powner != owner)
|
|
|
|
+ return -ENOENT;
|
|
|
|
+ *powner = NULL;
|
|
|
|
+ return rc;
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+void usb_hub_release_all_ports(struct usb_device *hdev, void *owner)
|
|
|
|
+{
|
|
|
|
+ int n;
|
|
|
|
+ void **powner;
|
|
|
|
+
|
|
|
|
+ n = find_port_owner(hdev, 1, &powner);
|
|
|
|
+ if (n == 0) {
|
|
|
|
+ for (; n < hdev->maxchild; (++n, ++powner)) {
|
|
|
|
+ if (*powner == owner)
|
|
|
|
+ *powner = NULL;
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+/* The caller must hold udev's lock */
|
|
|
|
+bool usb_device_is_owned(struct usb_device *udev)
|
|
|
|
+{
|
|
|
|
+ struct usb_hub *hub;
|
|
|
|
+
|
|
|
|
+ if (udev->state == USB_STATE_NOTATTACHED || !udev->parent)
|
|
|
|
+ return false;
|
|
|
|
+ hub = hdev_to_hub(udev->parent);
|
|
|
|
+ return !!hub->port_owners[udev->portnum - 1];
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
|
|
static void recursively_mark_NOTATTACHED(struct usb_device *udev)
|
|
static void recursively_mark_NOTATTACHED(struct usb_device *udev)
|
|
{
|
|
{
|