|
@@ -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");
|
|
|
}
|