diff options
author | Endre Kollar <taxy443@gmail.com> | 2010-07-27 12:39:30 +0200 |
---|---|---|
committer | Greg Kroah-Hartman <gregkh@suse.de> | 2010-07-27 11:06:29 -0700 |
commit | aa5873e96271611ae55586f65e49ea1fab90cb88 (patch) | |
tree | b2a0c0b5d06976b262e4403225d6ca3bc8380daf /drivers/staging/usbip/stub_dev.c | |
parent | 125ed824d3d03f5c470cf98aca757fd9423c49ab (diff) |
Staging: usbip: fix multiple interfaces
The stub_probe function instantiates an stub_dev object for all
interfaces. Wich causes a problem. The stub_dev object belongs to their
own interfaces. This patch creates the sdev object at the first
stub_probe call, the other calls associate the interfaces to this.
Signed-off-by: Endre Kollar <taxy443@gmail.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
Diffstat (limited to 'drivers/staging/usbip/stub_dev.c')
-rw-r--r-- | drivers/staging/usbip/stub_dev.c | 101 |
1 files changed, 91 insertions, 10 deletions
diff --git a/drivers/staging/usbip/stub_dev.c b/drivers/staging/usbip/stub_dev.c index 1f4085116927..b6b753a49346 100644 --- a/drivers/staging/usbip/stub_dev.c +++ b/drivers/staging/usbip/stub_dev.c @@ -393,11 +393,14 @@ static int stub_probe(struct usb_interface *interface, struct stub_device *sdev = NULL; const char *udev_busid = dev_name(interface->dev.parent); int err = 0; + struct bus_id_priv *busid_priv; dev_dbg(&interface->dev, "Enter\n"); /* check we should claim or not by busid_table */ - if (match_busid(udev_busid)) { + busid_priv = get_busid_priv(udev_busid); + if (!busid_priv || (busid_priv->status == STUB_BUSID_REMOV) || + (busid_priv->status == STUB_BUSID_OTHER)) { dev_info(&interface->dev, "this device %s is not in match_busid table. skip!\n", udev_busid); @@ -422,30 +425,80 @@ static int stub_probe(struct usb_interface *interface, return -ENODEV; } + + if (busid_priv->status == STUB_BUSID_ALLOC) { + busid_priv->interf_count++; + sdev = busid_priv->sdev; + if (!sdev) + return -ENODEV; + + dev_info(&interface->dev, + "USB/IP Stub: register a new interface " + "(bus %u dev %u ifn %u)\n", udev->bus->busnum, udev->devnum, + interface->cur_altsetting->desc.bInterfaceNumber); + + /* set private data to usb_interface */ + usb_set_intfdata(interface, sdev); + + err = stub_add_files(&interface->dev); + if (err) { + dev_err(&interface->dev, "create sysfs files for %s\n", + udev_busid); + usb_set_intfdata(interface, NULL); + busid_priv->interf_count--; + + return err; + } + + return 0; + } + /* ok. this is my device. */ sdev = stub_device_alloc(interface); if (!sdev) return -ENOMEM; - dev_info(&interface->dev, "USB/IP Stub: register a new interface " + dev_info(&interface->dev, "USB/IP Stub: register a new device " "(bus %u dev %u ifn %u)\n", udev->bus->busnum, udev->devnum, interface->cur_altsetting->desc.bInterfaceNumber); + busid_priv->interf_count = 0; + busid_priv->shutdown_busid = 0; + /* set private data to usb_interface */ usb_set_intfdata(interface, sdev); + busid_priv->interf_count++; + + busid_priv->sdev = sdev; err = stub_add_files(&interface->dev); if (err) { dev_err(&interface->dev, "create sysfs files for %s\n", udev_busid); - usb_set_intfdata(interface, 0); + usb_set_intfdata(interface, NULL); + busid_priv->interf_count = 0; + + busid_priv->sdev = NULL; stub_device_free(sdev); return err; } + busid_priv->status = STUB_BUSID_ALLOC; return 0; } +static void shutdown_busid(struct bus_id_priv *busid_priv) +{ + if (busid_priv->sdev && !busid_priv->shutdown_busid) { + busid_priv->shutdown_busid = 1; + usbip_event_add(&busid_priv->sdev->ud, SDEV_EVENT_REMOVED); + + /* 2. wait for the stop of the event handler */ + usbip_stop_eh(&busid_priv->sdev->ud); + } + +} + /* * called in usb_disconnect() or usb_deregister() @@ -453,10 +506,21 @@ static int stub_probe(struct usb_interface *interface, */ static void stub_disconnect(struct usb_interface *interface) { - struct stub_device *sdev = usb_get_intfdata(interface); + struct stub_device *sdev; + const char *udev_busid = dev_name(interface->dev.parent); + struct bus_id_priv *busid_priv; + + busid_priv = get_busid_priv(udev_busid); usbip_udbg("Enter\n"); + if (!busid_priv) { + BUG(); + return; + } + + sdev = usb_get_intfdata(interface); + /* get stub_device */ if (!sdev) { err(" could not get device from inteface data"); @@ -466,22 +530,39 @@ static void stub_disconnect(struct usb_interface *interface) usb_set_intfdata(interface, NULL); - /* * NOTE: * rx/tx threads are invoked for each usb_device. */ stub_remove_files(&interface->dev); - /* 1. shutdown the current connection */ - usbip_event_add(&sdev->ud, SDEV_EVENT_REMOVED); + /*If usb reset called from event handler*/ + if (busid_priv->sdev->ud.eh.thread == current) { + busid_priv->interf_count--; + return; + } + + if (busid_priv->interf_count > 1) { + busid_priv->interf_count--; + shutdown_busid(busid_priv); + return; + } + + busid_priv->interf_count = 0; - /* 2. wait for the stop of the event handler */ - usbip_stop_eh(&sdev->ud); + + /* 1. shutdown the current connection */ + shutdown_busid(busid_priv); /* 3. free sdev */ + busid_priv->sdev = NULL; stub_device_free(sdev); - + if (busid_priv->status == STUB_BUSID_ALLOC) { + busid_priv->status = STUB_BUSID_ADDED; + } else { + busid_priv->status = STUB_BUSID_OTHER; + del_match_busid((char *)udev_busid); + } usbip_udbg("bye\n"); } |