[PATCH v2 1/2] usbip: vhci number of ports extension

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



This patch extends number of ports limitation in application (vhci) 
side.

To do so, vhci driver supports multiple host controllers. The number of 
controllers can be specified as a module parameter 'num_controllers'. 
The default is 1.

ex) # insmod vhci_hcd.ko num_controllers=4

Also, ports per controller is changed from 8 to USB_MAXCHILDREN (31). 
It can be modified with VHCI_NPORTS flag at module compilation.

So number of ports supported by vhci is 'num_controllers' * 31.

Sysfs structure is changes as following.
BEFORE:
    /sys/devices/platform
        +-- vhci
            +-- status
            +-- attach
            +-- detach
            +-- usbip_debug
AFTER: example for num_controllers=4
    /sys/devices/platform
        +-- vhci.0
        |   +-- nports
        |   +-- status.0
        |   +-- status.1
        |   +-- status.2
        |   +-- status.3
        |   +-- attach
        |   +-- detach
        |   +-- usbip_debug
        +-- vhci.1
        +-- vhci.2
        +-- vhci.3
        
vhci.N is shown for each host controller kobj. vhch.1, vhci.2, ... are 
shown only when num_controllers is more than 1. Only vhci.0 has user 
space interfaces. 'nports' is newly added to give ports-per-controller 
and number of controlles. Before that, number of ports is acquired by 
counting status lines. Status is divided for each controller to avoid 
page size (4KB) limitation.

Variable wording relating port has been corrected. 'port' represents id 
across multiple controllers. 'rhport (root hub port)' represents id 
within a controller.

Some unimportant info level messages are changed to debug level because 
they are too busy when using many ports.

NOTE: Syslog error messages "systemd-udevd[390]: error opening USB 
device 'descriptors' file" may be shown. They are not caused by this 
patch. It seems to be a systemd problem.

Signed-off-by: Nobuo Iwata <nobuo.iwata@xxxxxxxxxxxxxxx>
---
 drivers/usb/usbip/README             |   3 +
 drivers/usb/usbip/usbip_ux.c         |   2 +-
 drivers/usb/usbip/vhci.h             |  41 +-
 drivers/usb/usbip/vhci_hcd.c         | 259 ++++++++-----
 drivers/usb/usbip/vhci_rx.c          |  21 +-
 drivers/usb/usbip/vhci_sysfs.c       | 298 +++++++++++----
 tools/usb/usbip/libsrc/vhci_driver.c | 548 ++++++++++++++-------------
 tools/usb/usbip/libsrc/vhci_driver.h |  38 +-
 tools/usb/usbip/src/usbip_attach.c   |   8 +-
 tools/usb/usbip/src/usbip_port.c     |  13 +-
 tools/usb/usbip/src/usbipd_app.c     |  56 ++-
 11 files changed, 775 insertions(+), 512 deletions(-)

diff --git a/drivers/usb/usbip/README b/drivers/usb/usbip/README
index 41a2cf2..fce3d7f 100644
--- a/drivers/usb/usbip/README
+++ b/drivers/usb/usbip/README
@@ -1,3 +1,6 @@
+MODULE PARAMS:
+	- num_controllers : number of controllers. Default is 1.
+
 TODO:
 	- more discussion about the protocol
 	- testing
diff --git a/drivers/usb/usbip/usbip_ux.c b/drivers/usb/usbip/usbip_ux.c
index 97e6385..4abf0b2 100644
--- a/drivers/usb/usbip/usbip_ux.c
+++ b/drivers/usb/usbip/usbip_ux.c
@@ -396,7 +396,7 @@ static int usbip_ux_unlink(struct usbip_device *ud)
 	rcu_read_lock();
 	ux = rcu_dereference(ud->ux);
 	if (ux == NULL) {
-		pr_err("Unlink to unlinked ux.\n");
+		usbip_dbg_ux("Unlink to unlinked ux.\n");
 		rcu_read_unlock();
 		return -EINVAL;
 	}
diff --git a/drivers/usb/usbip/vhci.h b/drivers/usb/usbip/vhci.h
index a863a98..6c34075 100644
--- a/drivers/usb/usbip/vhci.h
+++ b/drivers/usb/usbip/vhci.h
@@ -1,5 +1,6 @@
 /*
  * Copyright (C) 2003-2008 Takahiro Hirofuchi
+ * Copyright (C) 2015 Nobuo Iwata
  *
  * This is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
@@ -72,7 +73,11 @@ struct vhci_unlink {
 };
 
 /* Number of supported ports. Value has an upperbound of USB_MAXCHILDREN */
-#define VHCI_NPORTS 8
+#ifndef VHCI_NPORTS
+#define VHCI_NPORTS USB_MAXCHILDREN
+#endif
+
+#define MAX_STATUS_NAME 16
 
 /* for usb_bus.hcpriv */
 struct vhci_hcd {
@@ -93,11 +98,16 @@ struct vhci_hcd {
 	struct vhci_device vdev[VHCI_NPORTS];
 };
 
-extern struct vhci_hcd *the_controller;
-extern const struct attribute_group dev_attr_group;
+extern int num_controllers;
+extern struct platform_device **the_pdevs;
+extern struct attribute_group dev_attr_group;
 
 /* vhci_hcd.c */
-void rh_port_connect(int rhport, enum usb_device_speed speed);
+void rh_port_connect(struct vhci_device *vdev, enum usb_device_speed speed);
+
+/* vhci_sysfs.c */
+int vhci_init_attr_group(void);
+void vhci_finish_attr_group(void);
 
 /* vhci_rx.c */
 struct urb *pickup_urb_and_free_priv(struct vhci_device *vdev, __u32 seqnum);
@@ -106,9 +116,14 @@ int vhci_rx_loop(void *data);
 /* vhci_tx.c */
 int vhci_tx_loop(void *data);
 
-static inline struct vhci_device *port_to_vdev(__u32 port)
+static inline __u32 port_to_rhport(__u32 port)
+{
+	return port % VHCI_NPORTS;
+}
+
+static inline int port_to_pdev_nr(__u32 port)
 {
-	return &the_controller->vdev[port];
+	return port / VHCI_NPORTS;
 }
 
 static inline struct vhci_hcd *hcd_to_vhci(struct usb_hcd *hcd)
@@ -116,14 +131,24 @@ static inline struct vhci_hcd *hcd_to_vhci(struct usb_hcd *hcd)
 	return (struct vhci_hcd *) (hcd->hcd_priv);
 }
 
+static inline struct device *hcd_dev(struct usb_hcd *hcd)
+{
+	return (hcd)->self.controller;
+}
+
+static inline const char *hcd_name(struct usb_hcd *hcd)
+{
+	return (hcd)->self.bus_name;
+}
+
 static inline struct usb_hcd *vhci_to_hcd(struct vhci_hcd *vhci)
 {
 	return container_of((void *) vhci, struct usb_hcd, hcd_priv);
 }
 
-static inline struct device *vhci_dev(struct vhci_hcd *vhci)
+static inline struct vhci_hcd *vdev_to_vhci(struct vhci_device *vdev)
 {
-	return vhci_to_hcd(vhci)->self.controller;
+	return container_of((void*)(vdev - vdev->rhport), struct vhci_hcd, vdev);
 }
 
 #endif /* __USBIP_VHCI_H */
diff --git a/drivers/usb/usbip/vhci_hcd.c b/drivers/usb/usbip/vhci_hcd.c
index 0ea5da0..97d3667 100644
--- a/drivers/usb/usbip/vhci_hcd.c
+++ b/drivers/usb/usbip/vhci_hcd.c
@@ -57,7 +57,10 @@ static int vhci_get_frame_number(struct usb_hcd *hcd);
 static const char driver_name[] = "vhci_hcd";
 static const char driver_desc[] = "USB/IP Virtual Host Controller";
 
-struct vhci_hcd *the_controller;
+int num_controllers = 1;
+module_param(num_controllers, int, 0);
+
+struct platform_device **the_pdevs;
 
 static const char * const bit_desc[] = {
 	"CONNECTION",		/*0*/
@@ -120,43 +123,57 @@ static void dump_port_status_diff(u32 prev_status, u32 new_status)
 	pr_debug("\n");
 }
 
-void rh_port_connect(int rhport, enum usb_device_speed speed)
+void rh_port_connect(struct vhci_device *vdev, enum usb_device_speed speed)
 {
+	struct vhci_hcd *vhci = vdev_to_vhci(vdev);
+	int rhport = vdev->rhport;
+	u32 status;
+
 	usbip_dbg_vhci_rh("rh_port_connect %d\n", rhport);
 
-	spin_lock(&the_controller->lock);
+	spin_lock(&vhci->lock);
 
-	the_controller->port_status[rhport] |= USB_PORT_STAT_CONNECTION
-		| (1 << USB_PORT_FEAT_C_CONNECTION);
+	status = vhci->port_status[rhport];
+
+	status |= USB_PORT_STAT_CONNECTION | (1 << USB_PORT_FEAT_C_CONNECTION);
 
 	switch (speed) {
 	case USB_SPEED_HIGH:
-		the_controller->port_status[rhport] |= USB_PORT_STAT_HIGH_SPEED;
+		status |= USB_PORT_STAT_HIGH_SPEED;
 		break;
 	case USB_SPEED_LOW:
-		the_controller->port_status[rhport] |= USB_PORT_STAT_LOW_SPEED;
+		status |= USB_PORT_STAT_LOW_SPEED;
 		break;
 	default:
 		break;
 	}
 
-	spin_unlock(&the_controller->lock);
+	vhci->port_status[rhport] = status;
 
-	usb_hcd_poll_rh_status(vhci_to_hcd(the_controller));
+	spin_unlock(&vhci->lock);
+
+	usb_hcd_poll_rh_status(vhci_to_hcd(vhci));
 }
 
-static void rh_port_disconnect(int rhport)
+static void rh_port_disconnect(struct vhci_device *vdev)
 {
+	struct vhci_hcd *vhci = vdev_to_vhci(vdev);
+	int rhport = vdev->rhport;
+	u32 status;
+
 	usbip_dbg_vhci_rh("rh_port_disconnect %d\n", rhport);
 
-	spin_lock(&the_controller->lock);
+	spin_lock(&vhci->lock);
+
+	status = vhci->port_status[rhport];
 
-	the_controller->port_status[rhport] &= ~USB_PORT_STAT_CONNECTION;
-	the_controller->port_status[rhport] |=
-					(1 << USB_PORT_FEAT_C_CONNECTION);
+	status &= ~USB_PORT_STAT_CONNECTION;
+	status |= (1 << USB_PORT_FEAT_C_CONNECTION);
 
-	spin_unlock(&the_controller->lock);
-	usb_hcd_poll_rh_status(vhci_to_hcd(the_controller));
+	vhci->port_status[rhport] = status;
+
+	spin_unlock(&vhci->lock);
+	usb_hcd_poll_rh_status(vhci_to_hcd(vhci));
 }
 
 #define PORT_C_MASK				\
@@ -411,14 +428,25 @@ static int vhci_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue,
 
 static struct vhci_device *get_vdev(struct usb_device *udev)
 {
-	int i;
+	struct platform_device *pdev;
+	struct usb_hcd *hcd;
+	struct vhci_hcd *vhci;
+	int pdev_nr, rhport;
 
 	if (!udev)
 		return NULL;
 
-	for (i = 0; i < VHCI_NPORTS; i++)
-		if (the_controller->vdev[i].udev == udev)
-			return port_to_vdev(i);
+	for(pdev_nr=0;pdev_nr<num_controllers;pdev_nr++) {
+		pdev = *(the_pdevs + pdev_nr);
+		if (pdev == NULL) continue;
+		hcd = platform_get_drvdata(pdev);
+		if (hcd == NULL) continue;
+		vhci = hcd_to_vhci(hcd);
+		for (rhport = 0;rhport < VHCI_NPORTS;rhport++) {
+			if (vhci->vdev[rhport].udev == udev)
+				return &vhci->vdev[rhport];
+		}
+	}
 
 	return NULL;
 }
@@ -427,6 +455,7 @@ static void vhci_tx_urb(struct urb *urb)
 {
 	struct vhci_device *vdev = get_vdev(urb->dev);
 	struct vhci_priv *priv;
+	struct vhci_hcd *vhci = vdev_to_vhci(vdev);
 
 	if (!vdev) {
 		pr_err("could not get virtual device");
@@ -441,7 +470,7 @@ static void vhci_tx_urb(struct urb *urb)
 
 	spin_lock(&vdev->priv_lock);
 
-	priv->seqnum = atomic_inc_return(&the_controller->seqnum);
+	priv->seqnum = atomic_inc_return(&vhci->seqnum);
 	if (priv->seqnum == 0xffff)
 		dev_info(&urb->dev->dev, "seqnum max\n");
 
@@ -459,33 +488,39 @@ static void vhci_tx_urb(struct urb *urb)
 static int vhci_urb_enqueue(struct usb_hcd *hcd, struct urb *urb,
 			    gfp_t mem_flags)
 {
+	struct vhci_hcd *vhci = hcd_to_vhci(hcd);
 	struct device *dev = &urb->dev->dev;
+	u8 portnum = urb->dev->portnum;
 	int ret = 0;
 	struct vhci_device *vdev;
 
 	usbip_dbg_vhci_hc("enter, usb_hcd %p urb %p mem_flags %d\n",
 			  hcd, urb, mem_flags);
 
+	if (portnum > VHCI_NPORTS) {
+		pr_err("invalid port number %d\n", portnum);
+		return -ENODEV;
+	}
+	vdev = &vhci->vdev[portnum-1];
+
 	/* patch to usb_sg_init() is in 2.5.60 */
 	BUG_ON(!urb->transfer_buffer && urb->transfer_buffer_length);
 
-	spin_lock(&the_controller->lock);
+	spin_lock(&vhci->lock);
 
 	if (urb->status != -EINPROGRESS) {
 		dev_err(dev, "URB already unlinked!, status %d\n", urb->status);
-		spin_unlock(&the_controller->lock);
+		spin_unlock(&vhci->lock);
 		return urb->status;
 	}
 
-	vdev = port_to_vdev(urb->dev->portnum-1);
-
 	/* refuse enqueue for dead connection */
 	spin_lock(&vdev->ud.lock);
 	if (vdev->ud.status == VDEV_ST_NULL ||
 	    vdev->ud.status == VDEV_ST_ERROR) {
 		dev_err(dev, "enqueue for inactive port %d\n", vdev->rhport);
 		spin_unlock(&vdev->ud.lock);
-		spin_unlock(&the_controller->lock);
+		spin_unlock(&vhci->lock);
 		return -ENODEV;
 	}
 	spin_unlock(&vdev->ud.lock);
@@ -558,17 +593,16 @@ static int vhci_urb_enqueue(struct usb_hcd *hcd, struct urb *urb,
 
 out:
 	vhci_tx_urb(urb);
-	spin_unlock(&the_controller->lock);
+	spin_unlock(&vhci->lock);
 
 	return 0;
 
 no_need_xmit:
 	usb_hcd_unlink_urb_from_ep(hcd, urb);
 no_need_unlink:
-	spin_unlock(&the_controller->lock);
+	spin_unlock(&vhci->lock);
 	if (!ret)
-		usb_hcd_giveback_urb(vhci_to_hcd(the_controller),
-				     urb, urb->status);
+		usb_hcd_giveback_urb(hcd, urb, urb->status);
 	return ret;
 }
 
@@ -620,18 +654,19 @@ no_need_unlink:
  */
 static int vhci_urb_dequeue(struct usb_hcd *hcd, struct urb *urb, int status)
 {
+	struct vhci_hcd *vhci = hcd_to_vhci(hcd);
 	struct vhci_priv *priv;
 	struct vhci_device *vdev;
 
 	pr_info("dequeue a urb %p\n", urb);
 
-	spin_lock(&the_controller->lock);
+	spin_lock(&vhci->lock);
 
 	priv = urb->hcpriv;
 	if (!priv) {
 		/* URB was never linked! or will be soon given back by
 		 * vhci_rx. */
-		spin_unlock(&the_controller->lock);
+		spin_unlock(&vhci->lock);
 		return -EIDRM;
 	}
 
@@ -640,7 +675,7 @@ static int vhci_urb_dequeue(struct usb_hcd *hcd, struct urb *urb, int status)
 
 		ret = usb_hcd_check_unlink_urb(hcd, urb, status);
 		if (ret) {
-			spin_unlock(&the_controller->lock);
+			spin_unlock(&vhci->lock);
 			return ret;
 		}
 	}
@@ -668,10 +703,9 @@ static int vhci_urb_dequeue(struct usb_hcd *hcd, struct urb *urb, int status)
 
 		usb_hcd_unlink_urb_from_ep(hcd, urb);
 
-		spin_unlock(&the_controller->lock);
-		usb_hcd_giveback_urb(vhci_to_hcd(the_controller), urb,
-				     urb->status);
-		spin_lock(&the_controller->lock);
+		spin_unlock(&vhci->lock);
+		usb_hcd_giveback_urb(vhci_to_hcd(vhci), urb, urb->status);
+		spin_lock(&vhci->lock);
 
 	} else {
 		/* tcp connection is alive */
@@ -683,12 +717,12 @@ static int vhci_urb_dequeue(struct usb_hcd *hcd, struct urb *urb, int status)
 		unlink = kzalloc(sizeof(struct vhci_unlink), GFP_ATOMIC);
 		if (!unlink) {
 			spin_unlock(&vdev->priv_lock);
-			spin_unlock(&the_controller->lock);
+			spin_unlock(&vhci->lock);
 			usbip_event_add(&vdev->ud, VDEV_EVENT_ERROR_MALLOC);
 			return -ENOMEM;
 		}
 
-		unlink->seqnum = atomic_inc_return(&the_controller->seqnum);
+		unlink->seqnum = atomic_inc_return(&vhci->seqnum);
 		if (unlink->seqnum == 0xffff)
 			pr_info("seqnum max\n");
 
@@ -704,7 +738,7 @@ static int vhci_urb_dequeue(struct usb_hcd *hcd, struct urb *urb, int status)
 		spin_unlock(&vdev->priv_lock);
 	}
 
-	spin_unlock(&the_controller->lock);
+	spin_unlock(&vhci->lock);
 
 	usbip_dbg_vhci_hc("leave\n");
 	return 0;
@@ -712,9 +746,11 @@ static int vhci_urb_dequeue(struct usb_hcd *hcd, struct urb *urb, int status)
 
 static void vhci_device_unlink_cleanup(struct vhci_device *vdev)
 {
+	struct vhci_hcd *vhci = vdev_to_vhci(vdev);
+	struct usb_hcd *hcd = vhci_to_hcd(vhci);
 	struct vhci_unlink *unlink, *tmp;
 
-	spin_lock(&the_controller->lock);
+	spin_lock(&vhci->lock);
 	spin_lock(&vdev->priv_lock);
 
 	list_for_each_entry_safe(unlink, tmp, &vdev->unlink_tx, list) {
@@ -743,24 +779,23 @@ static void vhci_device_unlink_cleanup(struct vhci_device *vdev)
 
 		urb->status = -ENODEV;
 
-		usb_hcd_unlink_urb_from_ep(vhci_to_hcd(the_controller), urb);
+		usb_hcd_unlink_urb_from_ep(hcd, urb);
 
 		list_del(&unlink->list);
 
 		spin_unlock(&vdev->priv_lock);
-		spin_unlock(&the_controller->lock);
+		spin_unlock(&vhci->lock);
 
-		usb_hcd_giveback_urb(vhci_to_hcd(the_controller), urb,
-				     urb->status);
+		usb_hcd_giveback_urb(hcd, urb, urb->status);
 
-		spin_lock(&the_controller->lock);
+		spin_lock(&vhci->lock);
 		spin_lock(&vdev->priv_lock);
 
 		kfree(unlink);
 	}
 
 	spin_unlock(&vdev->priv_lock);
-	spin_unlock(&the_controller->lock);
+	spin_unlock(&vhci->lock);
 }
 
 /*
@@ -816,7 +851,7 @@ static void vhci_shutdown_connection(struct usbip_device *ud)
 	 * is actually given back by vhci_rx after receiving its return pdu.
 	 *
 	 */
-	rh_port_disconnect(vdev->rhport);
+	rh_port_disconnect(vdev);
 
 	pr_info("disconnect device\n");
 }
@@ -852,7 +887,7 @@ static void vhci_device_unusable(struct usbip_device *ud)
 
 static void vhci_device_init(struct vhci_device *vdev)
 {
-	memset(vdev, 0, sizeof(*vdev));
+	memset(vdev, 0, sizeof(struct vhci_device));
 
 	vdev->ud.side   = USBIP_VHCI;
 	vdev->ud.status = VDEV_ST_NULL;
@@ -873,10 +908,27 @@ static void vhci_device_init(struct vhci_device *vdev)
 	usbip_start_eh(&vdev->ud);
 }
 
+static int hcd_name_to_id(const char *name)
+{
+	char *c;
+	long val;
+	int ret;
+
+	c = strchr(name, '.');
+	if (c == NULL) {
+		return -1;
+	}
+	ret = kstrtol(c+1, 10, &val);
+	if (ret < 0) {
+		return ret;
+	}
+	return val;
+}
+
 static int vhci_start(struct usb_hcd *hcd)
 {
 	struct vhci_hcd *vhci = hcd_to_vhci(hcd);
-	int rhport;
+	int id, rhport;
 	int err = 0;
 
 	usbip_dbg_vhci_hc("enter vhci_start\n");
@@ -896,11 +948,26 @@ static int vhci_start(struct usb_hcd *hcd)
 	hcd->power_budget = 0; /* no limit */
 	hcd->uses_new_polling = 1;
 
+	id = hcd_name_to_id(hcd_name(hcd));
+	if (id < 0) {
+		pr_err("invalid vhci name %s\n", hcd_name(hcd));
+		return -EINVAL;
+	}
+
 	/* vhci_hcd is now ready to be controlled through sysfs */
-	err = sysfs_create_group(&vhci_dev(vhci)->kobj, &dev_attr_group);
-	if (err) {
-		pr_err("create sysfs files\n");
-		return err;
+	if (id == 0) {
+		err = vhci_init_attr_group();
+		if (err) {
+			pr_err("init attr roup\n");
+			return err;
+		}
+		err = sysfs_create_group(&hcd_dev(hcd)->kobj, &dev_attr_group);
+		if (err) {
+			pr_err("create sysfs files\n");
+			vhci_finish_attr_group();
+			return err;
+		}
+		pr_info("created sysfs %s\n", hcd_name(hcd));
 	}
 
 	return 0;
@@ -909,12 +976,16 @@ static int vhci_start(struct usb_hcd *hcd)
 static void vhci_stop(struct usb_hcd *hcd)
 {
 	struct vhci_hcd *vhci = hcd_to_vhci(hcd);
-	int rhport = 0;
+	int id, rhport;
 
 	usbip_dbg_vhci_hc("stop VHCI controller\n");
 
 	/* 1. remove the userland interface of vhci_hcd */
-	sysfs_remove_group(&vhci_dev(vhci)->kobj, &dev_attr_group);
+	id = hcd_name_to_id(hcd_name(hcd));
+	if (id == 0) {
+		sysfs_remove_group(&hcd_dev(hcd)->kobj, &dev_attr_group);
+		vhci_finish_attr_group();
+	}
 
 	/* 2. shutdown all the ports of vhci_hcd */
 	for (rhport = 0; rhport < VHCI_NPORTS; rhport++) {
@@ -1009,9 +1080,6 @@ static int vhci_hcd_probe(struct platform_device *pdev)
 	}
 	hcd->has_tt = 1;
 
-	/* this is private data for vhci_hcd */
-	the_controller = hcd_to_vhci(hcd);
-
 	/*
 	 * Finish generic HCD structure initialization and register.
 	 * Call the driver's reset() and start() routines.
@@ -1020,7 +1088,6 @@ static int vhci_hcd_probe(struct platform_device *pdev)
 	if (ret != 0) {
 		pr_err("usb_add_hcd failed %d\n", ret);
 		usb_put_hcd(hcd);
-		the_controller = NULL;
 		return ret;
 	}
 
@@ -1043,7 +1110,6 @@ static int vhci_hcd_remove(struct platform_device *pdev)
 	 */
 	usb_remove_hcd(hcd);
 	usb_put_hcd(hcd);
-	the_controller = NULL;
 
 	return 0;
 }
@@ -1054,20 +1120,23 @@ static int vhci_hcd_remove(struct platform_device *pdev)
 static int vhci_hcd_suspend(struct platform_device *pdev, pm_message_t state)
 {
 	struct usb_hcd *hcd;
-	int rhport = 0;
+	struct vhci_hcd *vhci;
+	int rhport;
 	int connected = 0;
 	int ret = 0;
 
 	hcd = platform_get_drvdata(pdev);
+	if (!hcd)
+		return 0;
+	vhci = hcd_to_vhci(hcd);
 
-	spin_lock(&the_controller->lock);
+	spin_lock(&vhci->lock);
 
 	for (rhport = 0; rhport < VHCI_NPORTS; rhport++)
-		if (the_controller->port_status[rhport] &
-		    USB_PORT_STAT_CONNECTION)
+		if (vhci->port_status[rhport] & USB_PORT_STAT_CONNECTION)
 			connected += 1;
 
-	spin_unlock(&the_controller->lock);
+	spin_unlock(&vhci->lock);
 
 	if (connected > 0) {
 		dev_info(&pdev->dev,
@@ -1089,6 +1158,8 @@ static int vhci_hcd_resume(struct platform_device *pdev)
 	dev_dbg(&pdev->dev, "%s\n", __func__);
 
 	hcd = platform_get_drvdata(pdev);
+	if (!hcd)
+		return 0;
 	set_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags);
 	usb_hcd_poll_rh_status(hcd);
 
@@ -1112,52 +1183,70 @@ static struct platform_driver vhci_driver = {
 	},
 };
 
-/*
- * The VHCI 'device' is 'virtual'; not a real plug&play hardware.
- * We need to add this virtual device as a platform device arbitrarily:
- *	1. platform_device_register()
- */
-static void the_pdev_release(struct device *dev)
+static int add_platform_device(int id)
 {
+	struct platform_device *pdev;
+	
+	pdev = platform_device_register_simple(driver_name, id, NULL, 0);
+	if (pdev == NULL) {
+                return -ENODEV;
+	}
+	*(the_pdevs + id) = pdev;
+	return 0;
 }
 
-static struct platform_device the_pdev = {
-	/* should be the same name as driver_name */
-	.name = driver_name,
-	.id = -1,
-	.dev = {
-		.release = the_pdev_release,
-	},
-};
+static void del_platform_devices(void)
+{
+	struct platform_device *pdev;
+	int i;
+
+	for(i=0;i<num_controllers;i++) {
+		pdev = *(the_pdevs + i);
+		if (pdev != NULL) {
+			platform_device_unregister(pdev);
+		}
+		*(the_pdevs + i) = NULL;
+	}
+}
 
 static int __init vhci_hcd_init(void)
 {
-	int ret;
+	int i, ret;
 
 	if (usb_disabled())
 		return -ENODEV;
 
+	the_pdevs = kzalloc(sizeof(void*) * num_controllers, GFP_KERNEL);
+	if (the_pdevs == NULL)
+		return -ENOMEM;
+
 	ret = platform_driver_register(&vhci_driver);
 	if (ret)
 		goto err_driver_register;
 
-	ret = platform_device_register(&the_pdev);
-	if (ret)
-		goto err_platform_device_register;
+	for(i=0;i<num_controllers;i++) {
+		ret = add_platform_device(i);
+		if (ret) {
+			goto err_platform_device_register;
+		}
+	}
 
 	pr_info(DRIVER_DESC " v" USBIP_VERSION "\n");
 	return ret;
 
 err_platform_device_register:
+	del_platform_devices();
 	platform_driver_unregister(&vhci_driver);
 err_driver_register:
+	kfree(the_pdevs);
 	return ret;
 }
 
 static void __exit vhci_hcd_exit(void)
 {
-	platform_device_unregister(&the_pdev);
+	del_platform_devices();
 	platform_driver_unregister(&vhci_driver);
+	kfree(the_pdevs);
 }
 
 module_init(vhci_hcd_init);
diff --git a/drivers/usb/usbip/vhci_rx.c b/drivers/usb/usbip/vhci_rx.c
index 4300bf1..5674e75 100644
--- a/drivers/usb/usbip/vhci_rx.c
+++ b/drivers/usb/usbip/vhci_rx.c
@@ -71,6 +71,7 @@ struct urb *pickup_urb_and_free_priv(struct vhci_device *vdev, __u32 seqnum)
 static void vhci_recv_ret_submit(struct vhci_device *vdev,
 				 struct usbip_header *pdu)
 {
+	struct vhci_hcd *vhci = vdev_to_vhci(vdev);
 	struct usbip_device *ud = &vdev->ud;
 	struct urb *urb;
 
@@ -81,7 +82,7 @@ static void vhci_recv_ret_submit(struct vhci_device *vdev,
 	if (!urb) {
 		pr_err("cannot find a urb of seqnum %u\n", pdu->base.seqnum);
 		pr_info("max seqnum %d\n",
-			atomic_read(&the_controller->seqnum));
+			atomic_read(&vhci->seqnum));
 		usbip_event_add(ud, VDEV_EVENT_ERROR_TCP);
 		return;
 	}
@@ -105,11 +106,11 @@ static void vhci_recv_ret_submit(struct vhci_device *vdev,
 
 	usbip_dbg_vhci_rx("now giveback urb %p\n", urb);
 
-	spin_lock(&the_controller->lock);
-	usb_hcd_unlink_urb_from_ep(vhci_to_hcd(the_controller), urb);
-	spin_unlock(&the_controller->lock);
+	spin_lock(&vhci->lock);
+	usb_hcd_unlink_urb_from_ep(vhci_to_hcd(vhci), urb);
+	spin_unlock(&vhci->lock);
 
-	usb_hcd_giveback_urb(vhci_to_hcd(the_controller), urb, urb->status);
+	usb_hcd_giveback_urb(vhci_to_hcd(vhci), urb, urb->status);
 
 	usbip_dbg_vhci_rx("Leave\n");
 }
@@ -141,6 +142,7 @@ static struct vhci_unlink *dequeue_pending_unlink(struct vhci_device *vdev,
 static void vhci_recv_ret_unlink(struct vhci_device *vdev,
 				 struct usbip_header *pdu)
 {
+	struct vhci_hcd *vhci = vdev_to_vhci(vdev);
 	struct vhci_unlink *unlink;
 	struct urb *urb;
 
@@ -172,12 +174,11 @@ static void vhci_recv_ret_unlink(struct vhci_device *vdev,
 		urb->status = pdu->u.ret_unlink.status;
 		pr_info("urb->status %d\n", urb->status);
 
-		spin_lock(&the_controller->lock);
-		usb_hcd_unlink_urb_from_ep(vhci_to_hcd(the_controller), urb);
-		spin_unlock(&the_controller->lock);
+		spin_lock(&vhci->lock);
+		usb_hcd_unlink_urb_from_ep(vhci_to_hcd(vhci), urb);
+		spin_unlock(&vhci->lock);
 
-		usb_hcd_giveback_urb(vhci_to_hcd(the_controller), urb,
-				     urb->status);
+		usb_hcd_giveback_urb(vhci_to_hcd(vhci), urb, urb->status);
 	}
 
 	kfree(unlink);
diff --git a/drivers/usb/usbip/vhci_sysfs.c b/drivers/usb/usbip/vhci_sysfs.c
index f04f15d..64ee286 100644
--- a/drivers/usb/usbip/vhci_sysfs.c
+++ b/drivers/usb/usbip/vhci_sysfs.c
@@ -21,6 +21,8 @@
 #include <linux/kthread.h>
 #include <linux/file.h>
 #include <linux/net.h>
+#include <linux/platform_device.h>
+#include <linux/slab.h>
 
 #include "usbip_common.h"
 #include "vhci.h"
@@ -28,35 +30,34 @@
 /* TODO: refine locking ?*/
 
 /* Sysfs entry to show port status */
-static ssize_t status_show(struct device *dev, struct device_attribute *attr,
-			   char *out)
+/*
+ * output example:
+ * prt sta spd dev      socket           ux               local_busid
+ * 000 004 000 00010002         c5a7bb80                0 1-2.3
+ * 001 004 000 00020003         d8cee980                0 2-3.4
+ *
+ * IP address can be retrieved from a socket pointer address by looking
+ * up /proc/net/{tcp,tcp6}. Also, a userland program may remember a
+ * port number and its peer IP address.
+ */
+static ssize_t status_show_vhci(int pdev_nr, char *out)
 {
+	struct platform_device *pdev = *(the_pdevs + pdev_nr);
+	struct vhci_hcd *vhci;
 	char *s = out;
 	int i = 0;
 
-	BUG_ON(!the_controller || !out);
+	BUG_ON(!pdev || !out);
+	vhci = hcd_to_vhci(platform_get_drvdata(pdev));
 
-	spin_lock(&the_controller->lock);
-
-	/*
-	 * output example:
-	 * prt sta spd dev      socket           ux               local_busid
-	 * 000 004 000 00010002         c5a7bb80                0 1-2.3
-	 * 001 004 000 00020003         d8cee980                0 2-3.4
-	 *
-	 * IP address can be retrieved from a socket pointer address by looking
-	 * up /proc/net/{tcp,tcp6}. Also, a userland program may remember a
-	 * port number and its peer IP address.
-	 */
-	out += sprintf(out,
-		       "prt sta spd dev      socket           "
-		       "ux               local_busid\n");
+	spin_lock(&vhci->lock);
 
 	for (i = 0; i < VHCI_NPORTS; i++) {
-		struct vhci_device *vdev = port_to_vdev(i);
+		struct vhci_device *vdev = &vhci->vdev[i];
 
 		spin_lock(&vdev->ud.lock);
-		out += sprintf(out, "%03u %03u ", i, vdev->ud.status);
+		out += sprintf(out, "%03u %03u ",
+			       (pdev_nr * VHCI_NPORTS) + i, vdev->ud.status);
 
 		if (vdev->ud.status == VDEV_ST_USED) {
 			out += sprintf(out, "%03u %08x ",
@@ -80,61 +81,137 @@ static ssize_t status_show(struct device *dev, struct device_attribute *attr,
 		spin_unlock(&vdev->ud.lock);
 	}
 
-	spin_unlock(&the_controller->lock);
+	spin_unlock(&vhci->lock);
 
 	return out - s;
 }
-static DEVICE_ATTR_RO(status);
+
+static ssize_t status_show_not_ready(int pdev_nr, char *out)
+{
+	char *s = out;
+	int i = 0;
+
+	for (i = 0; i < VHCI_NPORTS; i++) {
+		out += sprintf(out, "%03u %03u ", (pdev_nr * VHCI_NPORTS) + i,
+				    VDEV_ST_NOTASSIGNED);
+		out += sprintf(out, "000 00000000 0000000000000000 "
+				    "0000000000000000 0-0");
+	}
+	return out - s;
+}
+
+static int status_name_to_id(const char *name)
+{
+	char *c;
+	long val;
+	int ret;
+
+	c = strchr(name, '.');
+	if (c == NULL) {
+		return -1;
+	}
+	ret = kstrtol(c+1, 10, &val);
+	if (ret < 0) {
+		return ret;
+	}
+	return val;
+}
+
+ssize_t vhci_status_show(struct device *dev, struct device_attribute *attr,
+			 char *out)
+{
+	char *s = out;
+	int pdev_nr;
+
+	out += sprintf(out,
+		       "prt sta spd dev      socket           "
+		       "ux               local_busid\n");
+
+	pdev_nr = status_name_to_id(attr->attr.name);
+	if (pdev_nr < 0) {
+		out += status_show_not_ready(pdev_nr, out);
+	} else {
+		out += status_show_vhci(pdev_nr, out);
+	}
+	return out - s;
+}
+
+static ssize_t nports_show(struct device *dev, struct device_attribute *attr,
+			   char *out)
+{
+	char *s = out;
+	out += sprintf(out, "%d %d\n", VHCI_NPORTS, num_controllers);
+	return out - s;
+}
+static DEVICE_ATTR_RO(nports);
 
 /* Sysfs entry to shutdown a virtual connection */
-static int vhci_port_disconnect(__u32 rhport)
+static int vhci_port_disconnect(struct vhci_hcd *vhci, __u32 rhport)
 {
-	struct vhci_device *vdev;
+	struct vhci_device *vdev = &vhci->vdev[rhport];
 
 	usbip_dbg_vhci_sysfs("enter\n");
 
 	/* lock */
-	spin_lock(&the_controller->lock);
-
-	vdev = port_to_vdev(rhport);
-
+	spin_lock(&vhci->lock);
 	spin_lock(&vdev->ud.lock);
+
 	if (vdev->ud.status == VDEV_ST_NULL) {
 		pr_err("not connected %d\n", vdev->ud.status);
 
 		/* unlock */
 		spin_unlock(&vdev->ud.lock);
-		spin_unlock(&the_controller->lock);
+		spin_unlock(&vhci->lock);
 
 		return -EINVAL;
 	}
 
 	/* unlock */
 	spin_unlock(&vdev->ud.lock);
-	spin_unlock(&the_controller->lock);
+	spin_unlock(&vhci->lock);
 
 	usbip_event_add(&vdev->ud, VDEV_EVENT_DOWN);
 
 	return 0;
 }
 
+static int valid_port(__u32 pdev_nr, __u32 rhport)
+{
+	if (pdev_nr >= num_controllers) {
+		pr_err("pdev %u\n", pdev_nr);
+		return 0;
+	}
+	if (rhport >= VHCI_NPORTS) {
+		pr_err("rhport %u\n", rhport);
+		return 0;
+	}
+	return 1;
+}
+
 static ssize_t store_detach(struct device *dev, struct device_attribute *attr,
 			    const char *buf, size_t count)
 {
-	int err;
-	__u32 rhport = 0;
+	__u32 port = 0, pdev_nr = 0, rhport = 0;
+	struct usb_hcd *hcd;
+	int ret;
 
-	if (sscanf(buf, "%u", &rhport) != 1)
+	if (sscanf(buf, "%u", &port) != 1)
 		return -EINVAL;
 
-	/* check rhport */
-	if (rhport >= VHCI_NPORTS) {
-		dev_err(dev, "invalid port %u\n", rhport);
+	pdev_nr = port_to_pdev_nr(port);
+	rhport = port_to_rhport(port);
+
+	if (!valid_port(pdev_nr, rhport)) {
 		return -EINVAL;
 	}
+	hcd = platform_get_drvdata(*(the_pdevs + pdev_nr));
+	if (hcd == NULL) {
+		dev_err(dev, "port is not ready %u\n", port);
+		return -EAGAIN;
+	}
 
-	err = vhci_port_disconnect(rhport);
-	if (err < 0)
+	ret = vhci_port_disconnect(hcd_to_vhci(hcd), rhport);
+	if (ret < 0)
 		return -EINVAL;
 
 	usbip_dbg_vhci_sysfs("Leave\n");
@@ -143,16 +220,12 @@ static ssize_t store_detach(struct device *dev, struct device_attribute *attr,
 }
 static DEVICE_ATTR(detach, S_IWUSR, NULL, store_detach);
 
-/* Sysfs entry to establish a virtual connection */
-static int valid_args(__u32 rhport, enum usb_device_speed speed)
+static int valid_args(__u32 pdev_nr, __u32 rhport, enum usb_device_speed speed)
 {
-	/* check rhport */
-	if (rhport >= VHCI_NPORTS) {
-		pr_err("port %u\n", rhport);
-		return -EINVAL;
+	if (!valid_port(pdev_nr, rhport)) {
+		return 0;
 	}
 
-	/* check speed */
 	switch (speed) {
 	case USB_SPEED_LOW:
 	case USB_SPEED_FULL:
@@ -162,12 +235,13 @@ static int valid_args(__u32 rhport, enum usb_device_speed speed)
 	default:
 		pr_err("Failed attach request for unsupported USB speed: %s\n",
 			usb_speed_string(speed));
-		return -EINVAL;
+		return 0;
 	}
 
-	return 0;
+	return 1;
 }
 
+/* Sysfs entry to establish a virtual connection */
 /*
  * To start a new USB/IP attachment, a userland program needs to setup a TCP
  * connection and then write its socket descriptor with remote device
@@ -182,9 +256,11 @@ static int valid_args(__u32 rhport, enum usb_device_speed speed)
 static ssize_t store_attach(struct device *dev, struct device_attribute *attr,
 			    const char *buf, size_t count)
 {
-	struct vhci_device *vdev;
 	int sockfd = 0;
-	__u32 rhport = 0, devid = 0, speed = 0;
+	__u32 port = 0, pdev_nr = 0, rhport = 0, devid = 0, speed = 0;
+	struct usb_hcd *hcd;
+	struct vhci_hcd *vhci;
+	struct vhci_device *vdev;
 	int ret;
 
 	/*
@@ -193,27 +269,38 @@ static ssize_t store_attach(struct device *dev, struct device_attribute *attr,
 	 * @devid: unique device identifier in a remote host
 	 * @speed: usb device speed in a remote host
 	 */
-	if (sscanf(buf, "%u %u %u %u", &rhport, &sockfd, &devid, &speed) != 4)
+	if (sscanf(buf, "%u %u %u %u", &port, &sockfd, &devid, &speed) != 4)
 		return -EINVAL;
 
-	usbip_dbg_vhci_sysfs("rhport(%u) sockfd(%u) devid(%u) speed(%u)\n",
-			     rhport, sockfd, devid, speed);
+	pdev_nr = port_to_pdev_nr(port);
+	rhport = port_to_rhport(port);
+
+	usbip_dbg_vhci_sysfs("port(%u) pdev(%d) rhport(%u) "
+			     "sockfd(%u) devid(%u) speed(%u)\n",
+			     port, pdev_nr, rhport, sockfd, devid, speed);
 
 	/* check received parameters */
-	if (valid_args(rhport, speed) < 0)
+	if (!valid_args(pdev_nr, rhport, speed))
 		return -EINVAL;
 
+	hcd = platform_get_drvdata(*(the_pdevs + pdev_nr));
+	if (hcd == NULL) {
+		dev_err(dev, "port %d is not ready\n", port);
+		return -EAGAIN;
+	}
+	vhci = hcd_to_vhci(hcd);
+	vdev = &vhci->vdev[rhport];
+ 
 	/* now need lock until setting vdev status as used */
 
 	/* begin a lock */
-	spin_lock(&the_controller->lock);
-	vdev = port_to_vdev(rhport);
+	spin_lock(&vhci->lock);
 	spin_lock(&vdev->ud.lock);
 
 	if (vdev->ud.status != VDEV_ST_NULL) {
 		/* end of the lock */
 		spin_unlock(&vdev->ud.lock);
-		spin_unlock(&the_controller->lock);
+		spin_unlock(&vhci->lock);
 
 		dev_err(dev, "port %d already used\n", rhport);
 		return -EINVAL;
@@ -222,39 +309,112 @@ static ssize_t store_attach(struct device *dev, struct device_attribute *attr,
 	ret = usbip_trx_ops->link(&vdev->ud, sockfd);
 	if (ret) {
 		spin_unlock(&vdev->ud.lock);
-		spin_unlock(&the_controller->lock);
+		spin_unlock(&vhci->lock);
 		return ret;
 	}
 
 	dev_info(dev,
-		 "rhport(%u) sockfd(%d) devid(%u) speed(%u) speed_str(%s)\n",
-		 rhport, sockfd, devid, speed, usb_speed_string(speed));
+		 "pdev(%u) rhport(%u) sockfd(%d) devid(%u) "
+		 "speed(%u) speed_str(%s)\n",
+		 pdev_nr, rhport, sockfd, devid,
+		 speed, usb_speed_string(speed));
 
 	vdev->devid         = devid;
 	vdev->speed         = speed;
 	vdev->ud.status     = VDEV_ST_NOTASSIGNED;
 
 	spin_unlock(&vdev->ud.lock);
-	spin_unlock(&the_controller->lock);
+	spin_unlock(&vhci->lock);
 	/* end the lock */
 
 	vdev->ud.tcp_rx = kthread_get_run(vhci_rx_loop, &vdev->ud, "vhci_rx");
 	vdev->ud.tcp_tx = kthread_get_run(vhci_tx_loop, &vdev->ud, "vhci_tx");
 
-	rh_port_connect(rhport, speed);
+	rh_port_connect(vdev, speed);
 
 	return count;
 }
 static DEVICE_ATTR(attach, S_IWUSR, NULL, store_attach);
 
-static struct attribute *dev_attrs[] = {
-	&dev_attr_status.attr,
-	&dev_attr_detach.attr,
-	&dev_attr_attach.attr,
-	&dev_attr_usbip_debug.attr,
-	NULL,
+#define MAX_STATUS_NAME 16
+
+struct status_attr {
+	struct device_attribute attr;
+	char name[MAX_STATUS_NAME+1];
 };
 
-const struct attribute_group dev_attr_group = {
-	.attrs = dev_attrs,
+static struct status_attr *status_attrs = NULL;
+
+static void set_status_attr(int id)
+{
+	struct status_attr *status = status_attrs + id;
+
+	snprintf(status->name, MAX_STATUS_NAME+1, "status.%d", id);
+	status->attr.attr.name = status->name;
+	status->attr.attr.mode = S_IRUGO;
+	status->attr.show = vhci_status_show;
+}
+
+static int init_status_attrs(void)
+{
+	int id;
+
+	BUG_ON(status_attrs);
+	status_attrs = kzalloc(num_controllers * sizeof(struct status_attr),
+			       GFP_KERNEL);
+	if (status_attrs == NULL) {
+		pr_err("failed to alloc status attrs\n");
+		return -ENOMEM;
+	}
+	for(id=0;id<num_controllers;id++) {
+		set_status_attr(id);
+	}
+	return 0;
+}
+
+static void finish_status_attrs(void)
+{
+	if (status_attrs) {
+		kfree(status_attrs);
+	}
+}
+
+struct attribute_group dev_attr_group = {
+	.attrs = NULL,
 };
+
+int vhci_init_attr_group(void)
+{
+	struct attribute **attrs;
+	int ret, i;
+
+	BUG_ON(dev_attr_group.attrs);
+	attrs = kzalloc((num_controllers+5) * sizeof(struct attribute *),
+			GFP_KERNEL);
+	if (attrs == NULL) {
+		pr_err("failed to alloc attr group\n");
+		return -ENOMEM;
+	}
+	ret = init_status_attrs();
+	if (ret) {
+		kfree(attrs);
+		return ret;
+	}
+	*attrs     = &dev_attr_nports.attr;
+	*(attrs+1) = &dev_attr_detach.attr;
+	*(attrs+2) = &dev_attr_attach.attr;
+	*(attrs+3) = &dev_attr_usbip_debug.attr;
+	for(i=0;i<num_controllers;i++) {
+		*(attrs + i + 4) = &((status_attrs + i)->attr.attr);
+	}
+	dev_attr_group.attrs = attrs;
+	return 0;
+}
+
+void vhci_finish_attr_group(void)
+{
+	finish_status_attrs();
+	if (dev_attr_group.attrs) {
+		kfree(dev_attr_group.attrs);
+	}
+}
diff --git a/tools/usb/usbip/libsrc/vhci_driver.c b/tools/usb/usbip/libsrc/vhci_driver.c
index b0d3c18..ee43799 100644
--- a/tools/usb/usbip/libsrc/vhci_driver.c
+++ b/tools/usb/usbip/libsrc/vhci_driver.c
@@ -15,11 +15,39 @@
 #undef  PROGNAME
 #define PROGNAME "libusbip"
 
-struct usbip_vhci_driver *vhci_driver;
-struct udev *udev_context;
+static struct udev *udev_context = NULL;
 
-static struct usbip_imported_device *
-imported_device_init(struct usbip_imported_device *idev, char *busid)
+/* /sys/devices/platform/vhci_hcd.0 */
+static  struct udev_device *vhci_hc_device = NULL;
+
+static int vhci_nports;
+static int num_controllers;
+
+#define OPEN_MODE_FIRST      0
+#define OPEN_MODE_REOPEN     1
+
+static int open_hc_device(int mode)
+{
+	if (vhci_hc_device && mode == OPEN_MODE_REOPEN) {
+		udev_device_unref(vhci_hc_device);
+	}
+
+	vhci_hc_device = udev_device_new_from_subsystem_sysname(udev_context,
+				USBIP_VHCI_BUS_TYPE, USBIP_VHCI_DRV_NAME ".0");
+	if (!vhci_hc_device) {
+		err("udev_device_new_from_subsystem_sysname failed");
+		return -1;
+	}
+	return 0;
+}
+
+static void close_hc_device(void)
+{
+	udev_device_unref(vhci_hc_device);
+	vhci_hc_device = NULL;
+}
+
+static int imported_device_init(struct usbip_vhci_device *vdev, char *busid)
 {
 	struct udev_device *sudev;
 
@@ -27,327 +55,193 @@ imported_device_init(struct usbip_imported_device *idev, char *busid)
 						       "usb", busid);
 	if (!sudev) {
 		dbg("udev_device_new_from_subsystem_sysname failed: %s", busid);
-		goto err;
+		return -1;
 	}
-	read_usb_device(sudev, &idev->udev);
+	read_usb_device(sudev, &vdev->udev);
 	udev_device_unref(sudev);
 
-	return idev;
-
-err:
-	return NULL;
+	return 0;
 }
 
+struct status_context {
+	int controller;
+	const char *c;
+};
 
+#define MAX_STATUS_NAME 16
 
-static int parse_status(const char *value)
+static int status_open(struct status_context *ctx, int mode)
 {
-	int ret = 0;
-	char *c;
-
-
-	for (int i = 0; i < vhci_driver->nports; i++)
-		memset(&vhci_driver->idev[i], 0, sizeof(vhci_driver->idev[i]));
+	char name[MAX_STATUS_NAME+1];
 
+	if (mode == OPEN_MODE_FIRST) {
+		ctx->controller = 0;
+	} else {
+		(ctx->controller)++;
+	}
+	ctx->c = NULL;
 
-	/* skip a header line */
-	c = strchr(value, '\n');
-	if (!c)
+	if (ctx->controller >= num_controllers) {
 		return -1;
-	c++;
-
-	while (*c != '\0') {
-		int port, status, speed, devid;
-		unsigned long socket, ux;
-		char lbusid[SYSFS_BUS_ID_SIZE];
-
-		ret = sscanf(c, "%d %d %d %x %lx %lx %31s\n",
-				&port, &status, &speed,
-				&devid, &socket, &ux, lbusid);
-
-		if (ret < 7) {
-			dbg("sscanf failed: %d", ret);
-			BUG();
-		}
-
-		dbg("port %d status %d speed %d devid %x",
-				port, status, speed, devid);
-		dbg("socket %lx ux %lx lbusid %s", socket, ux, lbusid);
-
-
-		/* if a device is connected, look at it */
-		{
-			struct usbip_imported_device *idev = &vhci_driver->idev[port];
-
-			idev->port	= port;
-			idev->status	= status;
-
-			idev->devid	= devid;
-
-			idev->busnum	= (devid >> 16);
-			idev->devnum	= (devid & 0x0000ffff);
-
-			if (idev->status != VDEV_ST_NULL
-			    && idev->status != VDEV_ST_NOTASSIGNED) {
-				idev = imported_device_init(idev, lbusid);
-				if (!idev) {
-					dbg("imported_device_init failed");
-					return -1;
-				}
-			}
-		}
-
-
-		/* go to the next line */
-		c = strchr(c, '\n');
-		if (!c)
-			break;
-		c++;
 	}
 
-	dbg("exit");
-
-	return 0;
-}
-
-static int refresh_imported_device_list(void)
-{
-	const char *attr_status;
+	if (open_hc_device(OPEN_MODE_REOPEN)) {
+		return -1;
+	}
 
-	attr_status = udev_device_get_sysattr_value(vhci_driver->hc_device,
-					       "status");
-	if (!attr_status) {
-		err("udev_device_get_sysattr_value failed");
+	snprintf(name, MAX_STATUS_NAME+1, "status.%d", ctx->controller);
+	ctx->c = udev_device_get_sysattr_value(vhci_hc_device, name);
+	if (ctx->c == NULL) {
+		err("udev_device_get_sysattr_value status failed");
 		return -1;
 	}
 
-	return parse_status(attr_status);
+	return 0;
 }
 
-static int get_nports(void)
+static int status_next_line(struct status_context *ctx)
 {
-	char *c;
-	int nports = 0;
-	const char *attr_status;
-
-	attr_status = udev_device_get_sysattr_value(vhci_driver->hc_device,
-					       "status");
-	if (!attr_status) {
-		err("udev_device_get_sysattr_value failed");
-		return -1;
-	}
-
-	/* skip a header line */
-	c = strchr(attr_status, '\n');
-	if (!c)
-		return 0;
-	c++;
+	const char *c = ctx->c;
 
-	while (*c != '\0') {
-		/* go to the next line */
-		c = strchr(c, '\n');
-		if (!c)
-			return nports;
-		c++;
-		nports += 1;
+	while((c = strchr(c, '\n')) == NULL) {
+		if (status_open(ctx, OPEN_MODE_REOPEN)) {
+			return -1;
+		}
+		c = ctx->c;
 	}
-
-	return nports;
+	ctx->c = c + 1;
+	return 0;
 }
 
-/*
- * Read the given port's record.
- *
- * To avoid buffer overflow we will read the entire line and
- * validate each part's size. The initial buffer is padded by 4 to
- * accommodate the 2 spaces, 1 newline and an additional character
- * which is needed to properly validate the 3rd part without it being
- * truncated to an acceptable length.
- */
-static int read_record(int rhport, char *host, unsigned long host_len,
-		char *port, unsigned long port_len, char *busid)
+static int status_get_device(struct status_context *ctx,
+			     struct usbip_vhci_device *vdev)
 {
-	int part;
-	FILE *file;
-	char path[PATH_MAX+1];
-	char *buffer, *start, *end;
-	char delim[] = {' ', ' ', '\n'};
-	int max_len[] = {(int)host_len, (int)port_len, SYSFS_BUS_ID_SIZE};
-	size_t buffer_len = host_len + port_len + SYSFS_BUS_ID_SIZE + 4;
+	int port, status, speed, devid;
+	unsigned long socket, ux;
+	char lbusid[SYSFS_BUS_ID_SIZE];
+	int ret;
 
-	buffer = (char*)malloc(buffer_len);
-	if (!buffer)
+	if (status_next_line(ctx)) {
 		return -1;
+	}
+	memset(vdev, 0, sizeof(struct usbip_vhci_device));
 
-	snprintf(path, PATH_MAX, VHCI_STATE_PATH"/port%d", rhport);
-
-	file = fopen(path, "r");
-	if (!file) {
-		err("fopen");
-		free(buffer);
+	if (ctx->c == NULL || *(ctx->c) == '\0') {
+		dbg("no more data to scan");
 		return -1;
 	}
 
-	if (fgets(buffer, buffer_len, file) == NULL) {
-		err("fgets");
-		free(buffer);
-		fclose(file);
-		return -1;
+	ret = sscanf(ctx->c, "%d %d %d %x %lx %lx %31s\n",
+				&port, &status, &speed, &devid,
+				&socket, &ux, lbusid);
+	if (ret < 7) {
+		dbg("sscanf failed: %d", ret);
+		BUG();
 	}
-	fclose(file);
 
-	/* validate the length of each of the 3 parts */
-	start = buffer;
-	for (part = 0; part < 3; part++) {
-		end = strchr(start, delim[part]);
-		if (end == NULL || (end - start) > max_len[part]) {
-			free(buffer);
+	dbg("port %d status %d speed %d devid %x", port, status, speed, devid);
+	dbg("socket %lx ux %lx lbusid %s", socket, ux, lbusid);
+
+	vdev->port	= port;
+	vdev->status	= status;
+	vdev->devid	= devid;
+	vdev->busnum	= (devid >> 16);
+	vdev->devnum	= (devid & 0x0000ffff);
+
+	if (vdev->status != VDEV_ST_NULL &&
+	    vdev->status != VDEV_ST_NOTASSIGNED) {
+		if (imported_device_init(vdev, lbusid)) {
+			dbg("imported_device_init failed");
 			return -1;
 		}
-		start = end + 1;
 	}
 
-	if (sscanf(buffer, "%s %s %s\n", host, port, busid) != 3) {
-		err("sscanf");
-		free(buffer);
-		return -1;
-	}
-
-	free(buffer);
-
 	return 0;
 }
 
-#define OPEN_HC_MODE_FIRST	0
-#define OPEN_HC_MODE_REOPEN	1
+static void status_close(struct status_context *ctx)
+{
+	ctx->c = NULL;
+}
 
-static int open_hc_device(int mode)
+static int get_nports(void)
 {
-	if (mode == OPEN_HC_MODE_REOPEN) {
-		udev_device_unref(vhci_driver->hc_device);
+	const char *attr_nports;
+
+	attr_nports = udev_device_get_sysattr_value(vhci_hc_device, "nports");
+	if (!attr_nports) {
+		err("udev_device_get_sysattr_value failed");
+		return -1;
 	}
 
-	vhci_driver->hc_device =
-		udev_device_new_from_subsystem_sysname(udev_context,
-						       USBIP_VHCI_BUS_TYPE,
-						       USBIP_VHCI_DRV_NAME);
-	if (!vhci_driver->hc_device) {
-		err("udev_device_new_from_subsystem_sysname failed");
+	if (sscanf(attr_nports, "%d %d", &vhci_nports, &num_controllers) != 2) {
+		err("invalid nports format");
 		return -1;
 	}
+
 	return 0;
 }
 
-/* ---------------------------------------------------------------------- */
-
 int usbip_vhci_driver_open(void)
 {
 	udev_context = udev_new();
 	if (!udev_context) {
 		err("udev_new failed");
-		return -1;
+		goto err_out;
 	}
 
-	vhci_driver = (struct usbip_vhci_driver *)
-			calloc(1, sizeof(struct usbip_vhci_driver));
-
-	if (open_hc_device(OPEN_HC_MODE_FIRST)) {
-		goto err_free_driver;
+	if (open_hc_device(OPEN_MODE_FIRST)) {
+		goto err_unref_udev;
 	}
 
-	vhci_driver->nports = get_nports();
-
-	dbg("available ports: %d", vhci_driver->nports);
-
-	if (refresh_imported_device_list())
-		goto err_unref_device;
+	if (get_nports() || vhci_nports <= 0 || num_controllers <= 0) {
+		err("failed to get nports");
+		goto err_close_hc;
+	} 
+	dbg("available ports: %d * %d", vhci_nports, num_controllers);
 
 	return 0;
 
-err_unref_device:
-	udev_device_unref(vhci_driver->hc_device);
-err_free_driver:
-	if (vhci_driver)
-		free(vhci_driver);
-
-	vhci_driver = NULL;
-
+err_close_hc:
+	close_hc_device();	
+err_unref_udev:
 	udev_unref(udev_context);
-
+	udev_context = NULL;
+err_out:
 	return -1;
 }
 
-
 void usbip_vhci_driver_close(void)
 {
-	if (!vhci_driver)
-		return;
-
-	udev_device_unref(vhci_driver->hc_device);
-
-	free(vhci_driver);
-
-	vhci_driver = NULL;
-
-	udev_unref(udev_context);
-}
-
+	close_hc_device();
 
-int usbip_vhci_refresh_device_list(void)
-{
-	if (open_hc_device(OPEN_HC_MODE_REOPEN))
-		goto err;
-	if (refresh_imported_device_list())
-		goto err;
-
-	return 0;
-err:
-	dbg("failed to refresh device list");
-	return -1;
+	if (udev_context) {
+		udev_unref(udev_context);
+	}
 }
 
-
 int usbip_vhci_get_free_port(void)
 {
-	for (int i = 0; i < vhci_driver->nports; i++) {
-		if (vhci_driver->idev[i].status == VDEV_ST_NULL)
-			return i;
-	}
+	struct status_context context;
+	struct usbip_vhci_device vdev;
 
-	return -1;
-}
-
-struct usbip_imported_device *usbip_vhci_get_device(int port)
-{
-	for (int i = 0; i < vhci_driver->nports; i++) {
-		if (vhci_driver->idev[i].port == port)
-			return vhci_driver->idev + i;
+	if (status_open(&context, OPEN_MODE_FIRST)) {
+		return -1;
 	}
-	return NULL;
-}
-
-struct usbip_imported_device *usbip_vhci_find_device(
-				const char *host, const char *busid)
-{
-	int ret;
-	char rhost[NI_MAXHOST] = "unknown host";
-	char rserv[NI_MAXSERV] = "unknown port";
-	char rbusid[SYSFS_BUS_ID_SIZE];
-
-	for (int i = 0; i < vhci_driver->nports; i++) {
-		ret = read_record(vhci_driver->idev[i].port, rhost, NI_MAXHOST,
-				rserv, NI_MAXSERV, rbusid);
-		if (!ret &&
-			!strncmp(host, rhost, NI_MAXHOST) &&
-			!strncmp(busid, rbusid, SYSFS_BUS_ID_SIZE)) {
-			return vhci_driver->idev + i;
+	while(!status_get_device(&context, &vdev)) {
+		if (vdev.status == VDEV_ST_NULL) {
+			dbg("found free port %d", vdev.port);
+			status_close(&context);
+			return vdev.port;
 		}
 	}
-	return NULL;
+	status_close(&context);
+	return -1;
 }
 
-int usbip_vhci_attach_device2(uint8_t port, int sockfd, uint32_t devid,
-		uint32_t speed) {
+static int usbip_vhci_attach_device2(int port, int sockfd, uint32_t devid,
+		uint32_t speed)
+{
 	char buff[200]; /* what size should be ? */
 	char attach_attr_path[SYSFS_PATH_MAX];
 	char attr_attach[] = "attach";
@@ -358,7 +252,7 @@ int usbip_vhci_attach_device2(uint8_t port, int sockfd, uint32_t devid,
 			port, sockfd, devid, speed);
 	dbg("writing: %s", buff);
 
-	path = udev_device_get_syspath(vhci_driver->hc_device);
+	path = udev_device_get_syspath(vhci_hc_device);
 	snprintf(attach_attr_path, sizeof(attach_attr_path), "%s/%s",
 		 path, attr_attach);
 	dbg("attach attribute path: %s", attach_attr_path);
@@ -380,7 +274,7 @@ static unsigned long get_devid(uint8_t busnum, uint8_t devnum)
 }
 
 /* will be removed */
-int usbip_vhci_attach_device(uint8_t port, int sockfd, uint8_t busnum,
+int usbip_vhci_attach_device(int port, int sockfd, uint8_t busnum,
 		uint8_t devnum, uint32_t speed)
 {
 	int devid = get_devid(busnum, devnum);
@@ -388,7 +282,7 @@ int usbip_vhci_attach_device(uint8_t port, int sockfd, uint8_t busnum,
 	return usbip_vhci_attach_device2(port, sockfd, devid, speed);
 }
 
-int usbip_vhci_detach_device(uint8_t port)
+int usbip_vhci_detach_device(int port)
 {
 	char detach_attr_path[SYSFS_PATH_MAX];
 	char attr_detach[] = "detach";
@@ -399,7 +293,7 @@ int usbip_vhci_detach_device(uint8_t port)
 	snprintf(buff, sizeof(buff), "%u", port);
 	dbg("writing: %s", buff);
 
-	path = udev_device_get_syspath(vhci_driver->hc_device);
+	path = udev_device_get_syspath(vhci_hc_device);
 	snprintf(detach_attr_path, sizeof(detach_attr_path), "%s/%s",
 		 path, attr_detach);
 	dbg("detach attribute path: %s", detach_attr_path);
@@ -415,7 +309,99 @@ int usbip_vhci_detach_device(uint8_t port)
 	return 0;
 }
 
-int usbip_vhci_imported_device_dump(struct usbip_imported_device *idev)
+/*
+ * Read the given port's record.
+ *
+ * To avoid buffer overflow we will read the entire line and
+ * validate each part's size. The initial buffer is padded by 4 to
+ * accommodate the 2 spaces, 1 newline and an additional character
+ * which is needed to properly validate the 3rd part without it being
+ * truncated to an acceptable length.
+ */
+static int read_record(int port, char *host, unsigned long host_len,
+		char *port_s, unsigned long port_slen, char *busid)
+{
+	int part;
+	FILE *file;
+	char path[PATH_MAX+1];
+	char *buffer, *start, *end;
+	char delim[] = {' ', ' ', '\n'};
+	int max_len[] = {(int)host_len, (int)port_slen, SYSFS_BUS_ID_SIZE};
+	size_t buffer_len = host_len + port_slen + SYSFS_BUS_ID_SIZE + 4;
+
+	buffer = (char*)malloc(buffer_len);
+	if (!buffer)
+		return -1;
+
+	snprintf(path, PATH_MAX, VHCI_STATE_PATH"/port%d", port);
+
+	file = fopen(path, "r");
+	if (!file) {
+		err("fopen %s", path);
+		free(buffer);
+		return -1;
+	}
+
+	if (fgets(buffer, buffer_len, file) == NULL) {
+		err("fgets %s", path);
+		free(buffer);
+		fclose(file);
+		return -1;
+	}
+	fclose(file);
+
+	/* validate the length of each of the 3 parts */
+	start = buffer;
+	for (part = 0; part < 3; part++) {
+		end = strchr(start, delim[part]);
+		if (end == NULL || (end - start) > max_len[part]) {
+			free(buffer);
+			return -1;
+		}
+		start = end + 1;
+	}
+
+	if (sscanf(buffer, "%s %s %s\n", host, port_s, busid) != 3) {
+		err("sscanf");
+		free(buffer);
+		return -1;
+	}
+
+	free(buffer);
+
+	return 0;
+}
+
+int usbip_vhci_find_device(const char *host, const char *busid)
+{
+	int ret;
+	char rhost[NI_MAXHOST] = "unknown host";
+	char rserv[NI_MAXSERV] = "unknown port";
+	char rbusid[SYSFS_BUS_ID_SIZE];
+	struct status_context context;
+	struct usbip_vhci_device vdev;
+
+	if (status_open(&context, OPEN_MODE_FIRST)) {
+		return -1;
+	}
+	while(!status_get_device(&context, &vdev)) {
+		if (vdev.status != VDEV_ST_USED) {
+			continue;
+		}
+		ret = read_record(vdev.port, rhost, NI_MAXHOST,
+				  rserv, NI_MAXSERV, rbusid);
+		if (!ret &&
+			!strncmp(host, rhost, NI_MAXHOST) &&
+			!strncmp(busid, rbusid, SYSFS_BUS_ID_SIZE)) {
+			status_close(&context);
+			return vdev.port;
+		}
+	}
+	status_close(&context);
+	return -1;
+}
+
+static int usbip_vhci_imported_device_dump(struct usbip_vhci_device *vdev)
 {
 	char product_name[100];
 	char host[NI_MAXHOST] = "unknown host";
@@ -424,43 +410,69 @@ int usbip_vhci_imported_device_dump(struct usbip_imported_device *idev)
 	int ret;
 	int read_record_error = 0;
 
-	if (idev->status == VDEV_ST_NULL || idev->status == VDEV_ST_NOTASSIGNED)
+	if (vdev->status == VDEV_ST_NULL || vdev->status == VDEV_ST_NOTASSIGNED)
 		return 0;
 
-	ret = read_record(idev->port, host, sizeof(host), serv, sizeof(serv),
+	ret = read_record(vdev->port, host, sizeof(host), serv, sizeof(serv),
 			  remote_busid);
 	if (ret) {
 		err("read_record");
 		read_record_error = 1;
 	}
 
-	printf("Port %02d: <%s> at %s\n", idev->port,
-	       usbip_status_string(idev->status),
-	       usbip_speed_string(idev->udev.speed));
+	printf("Port %02d: <%s> at %s\n", vdev->port,
+	       usbip_status_string(vdev->status),
+	       usbip_speed_string(vdev->udev.speed));
 
 	usbip_names_get_product(product_name, sizeof(product_name),
-				idev->udev.idVendor, idev->udev.idProduct);
+				vdev->udev.idVendor, vdev->udev.idProduct);
 
 	printf("       %s\n",  product_name);
 
 	if (!read_record_error) {
-		printf("%10s -> usbip://%s:%s/%s\n", idev->udev.busid,
+		printf("%10s -> usbip://%s:%s/%s\n", vdev->udev.busid,
 		       host, serv, remote_busid);
 		printf("%10s -> remote bus/dev %03d/%03d\n", " ",
-		       idev->busnum, idev->devnum);
+		       vdev->busnum, vdev->devnum);
 	} else {
 		printf("%10s -> unknown host, remote port and remote busid\n",
-		       idev->udev.busid);
+		       vdev->udev.busid);
 		printf("%10s -> remote bus/dev %03d/%03d\n", " ",
-		       idev->busnum, idev->devnum);
+		       vdev->busnum, vdev->devnum);
+	}
+
+	return 0;
+}
+
+int usbip_vhci_imported_devices_dump(void)
+{
+	struct status_context context;
+	struct usbip_vhci_device vdev;
+
+	if (status_open(&context, OPEN_MODE_FIRST)) {
+		goto err_out;
 	}
+	while(!status_get_device(&context, &vdev)) {
+		if (vdev.status == VDEV_ST_NULL ||
+		    vdev.status == VDEV_ST_NOTASSIGNED) {
+			continue;
+		}
+		if (usbip_vhci_imported_device_dump(&vdev)) {
+			goto err_close;
+		}
+	}
+	status_close(&context);
 
 	return 0;
+err_close:
+	status_close(&context);
+err_out:
+	return -1;
 }
 
 #define MAX_BUFF 100
-int usbip_vhci_create_record(const char *host, const char *port,
-			     const char *busid, int rhport)
+int usbip_vhci_create_record(const char *host, const char *port_s,
+			     const char *busid, int port)
 {
 	int fd;
 	char path[PATH_MAX+1];
@@ -482,14 +494,14 @@ int usbip_vhci_create_record(const char *host, const char *port,
 			return -1;
 	}
 
-	snprintf(path, PATH_MAX, VHCI_STATE_PATH"/port%d", rhport);
+	snprintf(path, PATH_MAX, VHCI_STATE_PATH"/port%d", port);
 
 	fd = open(path, O_WRONLY|O_CREAT|O_TRUNC, S_IRWXU);
 	if (fd < 0)
 		return -1;
 
 	snprintf(buff, MAX_BUFF, "%s %s %s\n",
-			host, port, busid);
+			host, port_s, busid);
 
 	ret = write(fd, buff, strlen(buff));
 	if (ret != (ssize_t) strlen(buff)) {
@@ -502,11 +514,11 @@ int usbip_vhci_create_record(const char *host, const char *port,
 	return 0;
 }
 
-int usbip_vhci_delete_record(int rhport)
+int usbip_vhci_delete_record(int port)
 {
 	char path[PATH_MAX+1];
 
-	snprintf(path, PATH_MAX, VHCI_STATE_PATH"/port%d", rhport);
+	snprintf(path, PATH_MAX, VHCI_STATE_PATH"/port%d", port);
 
 	remove(path);
 	rmdir(VHCI_STATE_PATH);
diff --git a/tools/usb/usbip/libsrc/vhci_driver.h b/tools/usb/usbip/libsrc/vhci_driver.h
index a8ff4e8..8d28999 100644
--- a/tools/usb/usbip/libsrc/vhci_driver.h
+++ b/tools/usb/usbip/libsrc/vhci_driver.h
@@ -12,56 +12,34 @@
 #include "usbip_common.h"
 
 #define USBIP_VHCI_BUS_TYPE "platform"
-#define MAXNPORT 128
 
-struct usbip_imported_device {
-	uint8_t port;
+struct usbip_vhci_device {
+	int      port;
 	uint32_t status;
 
 	uint32_t devid;
 
-	uint8_t busnum;
-	uint8_t devnum;
+	uint8_t  busnum;
+	uint8_t  devnum;
 
 	/* usbip_class_device list */
 	struct usbip_usb_device udev;
 };
 
-struct usbip_vhci_driver {
-
-	/* /sys/devices/platform/vhci_hcd */
-	struct udev_device *hc_device;
-
-	int nports;
-	struct usbip_imported_device idev[MAXNPORT];
-};
-
-
-extern struct usbip_vhci_driver *vhci_driver;
-
 int usbip_vhci_driver_open(void);
 void usbip_vhci_driver_close(void);
 
-int  usbip_vhci_refresh_device_list(void);
-
-
 int usbip_vhci_get_free_port(void);
-struct usbip_imported_device *usbip_vhci_get_device(int port);
-struct usbip_imported_device *usbip_vhci_find_device(
-                const char *host, const char *busid);
-int usbip_vhci_attach_device2(uint8_t port, int sockfd, uint32_t devid,
-		uint32_t speed);
 
-/* will be removed */
-int usbip_vhci_attach_device(uint8_t port, int sockfd, uint8_t busnum,
+int usbip_vhci_attach_device(int port, int sockfd, uint8_t busnum,
 		uint8_t devnum, uint32_t speed);
+int usbip_vhci_detach_device(int port);
 
-int usbip_vhci_detach_device(uint8_t port);
+int usbip_vhci_find_device(const char *host, const char *busid);
+int usbip_vhci_imported_devices_dump(void);
 
 int usbip_vhci_create_record(const char *host, const char *port,
 		const char *busid, int rhport);
 int usbip_vhci_delete_record(int rhport);
 
-int usbip_vhci_imported_device_dump(struct usbip_imported_device *idev);
-
 #endif /* __VHCI_DRIVER_H */
diff --git a/tools/usb/usbip/src/usbip_attach.c b/tools/usb/usbip/src/usbip_attach.c
index 9d242ab..3c747c0 100644
--- a/tools/usb/usbip/src/usbip_attach.c
+++ b/tools/usb/usbip/src/usbip_attach.c
@@ -137,7 +137,7 @@ int usbip_attach_device(const char *host, const char *port, const char *busid)
 	usbip_sock_t *sock;
 	usbip_ux_t *ux;
 	int rc;
-	int rhport;
+	int port_nr;
 
 	sock = usbip_conn_ops.open(host, port);
 	if (!sock) {
@@ -151,13 +151,13 @@ int usbip_attach_device(const char *host, const char *port, const char *busid)
 		goto err_close_conn;
 	}
 
-	rhport = query_import_device(sock, busid);
-	if (rhport < 0) {
+	port_nr = query_import_device(sock, busid);
+	if (port_nr < 0) {
 		err("query");
 		goto err_cleanup_ux;
 	}
 
-	rc = usbip_vhci_create_record(host, port, busid, rhport);
+	rc = usbip_vhci_create_record(host, port, busid, port_nr);
 	if (rc < 0) {
 		err("record connection");
 		goto err_cleanup_ux;
diff --git a/tools/usb/usbip/src/usbip_port.c b/tools/usb/usbip/src/usbip_port.c
index b3a6ee1..29042c8 100644
--- a/tools/usb/usbip/src/usbip_port.c
+++ b/tools/usb/usbip/src/usbip_port.c
@@ -27,8 +27,6 @@ void usbip_port_usage(void)
 
 int usbip_list_imported_devices(void)
 {
-	int i;
-	struct usbip_imported_device *idev;
 	int ret;
 
 	if (usbip_names_init(USBIDS_FILE))
@@ -36,18 +34,17 @@ int usbip_list_imported_devices(void)
 
 	ret = usbip_vhci_driver_open();
 	if (ret < 0) {
-		err("open vhci_driver");
+		err("open vhci driver");
 		goto err_names_free;
 	}
 
 	printf("Imported USB devices\n");
 	printf("====================\n");
 
-	for (i = 0; i < vhci_driver->nports; i++) {
-		idev = &vhci_driver->idev[i];
-
-		if (usbip_vhci_imported_device_dump(idev) < 0)
-			goto err_driver_close;
+	ret = usbip_vhci_imported_devices_dump();
+	if (ret < 0) {
+		err("dump vhci devices");
+		goto err_driver_close;
 	}
 
 	usbip_vhci_driver_close();
diff --git a/tools/usb/usbip/src/usbipd_app.c b/tools/usb/usbip/src/usbipd_app.c
index 06bcb10..00b359b 100644
--- a/tools/usb/usbip/src/usbipd_app.c
+++ b/tools/usb/usbip/src/usbipd_app.c
@@ -82,7 +82,7 @@ static int recv_request_export(usbip_sock_t *sock,
 	struct op_export_request req;
 	struct op_export_reply reply;
 	usbip_ux_t *ux;
-	int rhport = 0;
+	int port_nr = 0;
 	int error = 0;
 	int rc;
 
@@ -102,8 +102,8 @@ static int recv_request_export(usbip_sock_t *sock,
 		return -1;
 	}
 
-	rhport = import_device(sock, &req.udev);
-	if (rhport < 0) {
+	port_nr = import_device(sock, &req.udev);
+	if (port_nr < 0) {
 		dbg("export request busid %s: failed", req.udev.busid);
 		error = 1;
 	}
@@ -128,17 +128,20 @@ static int recv_request_export(usbip_sock_t *sock,
 		return -1;
 	}
 
-	rc = usbip_vhci_create_record(host, port, req.udev.busid, rhport);
-	if (rc < 0) {
-		err("record connection");
-		return -1;
-	}
+	if (!error) {
+		rc = usbip_vhci_create_record(host, port,
+					      req.udev.busid, port_nr);
+		if (rc < 0) {
+			err("record connection");
+			return -1;
+		}
 
-	dbg("export request busid %s: complete", req.udev.busid);
+		dbg("export request busid %s: complete", req.udev.busid);
 
-	if (ux != NULL) {
-		usbip_ux_start(ux);
-		usbip_ux_join(ux);
+		if (ux != NULL) {
+			usbip_ux_start(ux);
+			usbip_ux_join(ux);
+		}
 	}
 	usbip_ux_cleanup(&ux);
 
@@ -147,28 +150,27 @@ static int recv_request_export(usbip_sock_t *sock,
 
 static int unimport_device(const char *host, struct usbip_usb_device *udev)
 {
-	int rc;
-	struct usbip_imported_device *idev;
+	int port, rc;
 
-	idev = usbip_vhci_find_device(host, udev->busid);
-	if (idev == NULL) {
+	port = usbip_vhci_find_device(host, udev->busid);
+	if (port < 0) {
 		err("no imported port %s %s", host, udev->busid);
 		return -1;
 	}
 
-	rc = usbip_vhci_detach_device(idev->port);
+	rc = usbip_vhci_detach_device(port);
 	if (rc < 0) {
-		err("no imported port %d %s %s", idev->port, host, udev->busid);
+		err("no imported port %d %s %s", port, host, udev->busid);
 		return -1;
 	}
-	return idev->port;
+	return port;
 }
 
 static int recv_request_unexport(usbip_sock_t *sock, const char *host)
 {
 	struct op_unexport_request req;
 	struct op_unexport_reply reply;
-	int rhport = 0;
+	int port_nr = 0;
 	int error = 0;
 	int rc;
 
@@ -182,8 +184,8 @@ static int recv_request_unexport(usbip_sock_t *sock, const char *host)
 	}
 	PACK_OP_UNEXPORT_REQUEST(0, &req);
 
-	rhport = unimport_device(host, &req.udev);
-	if (rhport < 0) {
+	port_nr = unimport_device(host, &req.udev);
+	if (port_nr < 0) {
 		error = 1;
 	}
 
@@ -209,7 +211,9 @@ static int recv_request_unexport(usbip_sock_t *sock, const char *host)
 		return -1;
 	}
 
-	usbip_vhci_delete_record(rhport);
+	if (!error) {
+		usbip_vhci_delete_record(port_nr);
+	}
 
 	dbg("unexport request busid %s: complete", req.udev.busid);
 
@@ -227,12 +231,6 @@ int usbip_recv_pdu(usbip_sock_t *sock, const char *host, const char *port)
 		return -1;
 	}
 
-	ret = usbip_vhci_refresh_device_list();
-	if (ret < 0) {
-		dbg("could not refresh device list: %d", ret);
-		return -1;
-	}
-
 	info("received request: %#0x(%d)", code, sock->fd);
 	switch (code) {
 	case OP_REQ_EXPORT:
-- 
2.1.0

--
To unsubscribe from this list: send the line "unsubscribe linux-usb" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at  http://vger.kernel.org/majordomo-info.html




[Index of Archives]     [Linux Media]     [Linux Input]     [Linux Audio Users]     [Yosemite News]     [Linux Kernel]     [Linux SCSI]     [Old Linux USB Devel Archive]

  Powered by Linux