Modification for dynamic device registration and unregistration.

1. kernel config

Followings are added.

USBIP_VHCI_HC_PORTS: Number of ports per USB/IP virtual host 
controller. The default is 8 - same as current VHCI_NPORTS.
USBIP_VHCI_MAX_HCS: Muximum number of USB/IP virtual host controllers. 
The default is 1.
USBIP_VHCI_INIT_HCS: Initial number of USB/IP virtual host controllers. 
The default is 1.
Static number of devices: USBIP_VHCI_NR_HCS in patch 1/3 is removed 
with this patch.

2. view from sysfs

Sysfs structure is changed as following.

BEFORE this patchset:
    /sys/devices/platform
        +-- vhci
            +-- status
            +-- attach
            +-- detach
            +-- usbip_debug

AFTER: example for CONFIG_USBIP_INIT_HCS=2 CONFIG_USBIP_MAX_HCS=4
At the beginning
    /sys/devices/platform
        +-- vhci
        |   +-- nports
        |   +-- status
        |   +-- status.1
        |   +-- status.2
        |   +-- status.3
        |   +-- attach
        |   +-- detach
        |   +-- usbip_debug
        +-- vhci.1

The status files are shown to the maximum number of devices. Port 
status in status.2 and status.3 represents as free but corresponding 
devices are not yes registered.
When all ports in status and status.1 are used, userspace tool requests 
'attach' to a port in status.2 then vhci.2 will be registred. The limit 
is defined with USBIP_VHCI_MAX_NCS.

By preparing muximum number of status files, there's no need to 
introduce additional operations for userspace tool.

When number of free ports becomes more than USBIP_VHCI_HC_PORTS * 
VHCI_FREE_HCS(2), a free controller other than the first one will be 
unregistered. It will be invoked by 'detach' operation and other error 
situations which ports are released.

Signed-off-by: Nobuo Iwata <nobuo.iw...@fujixerox.co.jp>
---
 drivers/usb/usbip/Kconfig      |  17 ++-
 drivers/usb/usbip/vhci.h       |  36 ++++-
 drivers/usb/usbip/vhci_hcd.c   | 251 ++++++++++++++++++++++++++++-----
 drivers/usb/usbip/vhci_rx.c    |  10 +-
 drivers/usb/usbip/vhci_sysfs.c |  49 ++++---
 drivers/usb/usbip/vhci_tx.c    |   6 +-
 6 files changed, 294 insertions(+), 75 deletions(-)

diff --git a/drivers/usb/usbip/Kconfig b/drivers/usb/usbip/Kconfig
index 29492c7..d11b548 100644
--- a/drivers/usb/usbip/Kconfig
+++ b/drivers/usb/usbip/Kconfig
@@ -34,8 +34,8 @@ config USBIP_VHCI_HC_PORTS
          host controller driver, this defines number of ports per
          USB/IP virtual host controller.
 
-config USBIP_VHCI_NR_HCS
-       int "Number of USB/IP virtual host controllers"
+config USBIP_VHCI_MAX_HCS
+       int "Maximum number of USB/IP virtual host controllers"
        range 1 128
        default 1
        depends on USBIP_VHCI_HCD
@@ -43,7 +43,18 @@ config USBIP_VHCI_NR_HCS
          To increase number of ports available for USB/IP virtual
          host controller driver, this defines number of USB/IP
          virtual host controllers as if adding physical host
-         controllers.
+         controllers. This defines the maximum number.
+
+config USBIP_VHCI_INIT_HCS
+       int "Initial number of USB/IP virtual host controllers"
+       range 1 USBIP_VHCI_MAX_HCS
+       default 1
+       depends on USBIP_VHCI_MAX_HCS
+       ---help---
+         To increase number of ports available for USB/IP virtual
+         host controller driver, this defines number of USB/IP
+         virtual host controllers as if adding physical host
+         controllers. This defines the number at initializing.
 
 config USBIP_HOST
        tristate "Host driver"
diff --git a/drivers/usb/usbip/vhci.h b/drivers/usb/usbip/vhci.h
index 88b71c4..ba893a7 100644
--- a/drivers/usb/usbip/vhci.h
+++ b/drivers/usb/usbip/vhci.h
@@ -51,6 +51,9 @@ struct vhci_device {
 
        /* vhci_tx thread sleeps for this queue */
        wait_queue_head_t waitq_tx;
+
+       /* denotes port is in-use */
+       atomic_t using_port;
 };
 
 /* urb->hcpriv, use container_of() */
@@ -79,12 +82,21 @@ struct vhci_unlink {
 #define VHCI_HC_PORTS 8
 #endif
 
-#ifdef CONFIG_USBIP_VHCI_NR_HCS
-#define VHCI_NR_HCS CONFIG_USBIP_VHCI_NR_HCS
+#ifdef CONFIG_USBIP_VHCI_MAX_HCS
+#define VHCI_MAX_HCS CONFIG_USBIP_VHCI_MAX_HCS
+#else
+#define VHCI_MAX_HCS 1
+#endif
+
+#ifdef CONFIG_USBIP_VHCI_INIT_HCS
+#define VHCI_INIT_HCS CONFIG_USBIP_VHCI_INIT_HCS
 #else
-#define VHCI_NR_HCS 1
+#define VHCI_INIT_HCS 1
 #endif
 
+/* VHCI_FREE_HCS * VHCI_HC_PORTS: ports to keep free at unregister */
+#define VHCI_FREE_HCS 2
+
 #define MAX_STATUS_NAME 16
 
 /* for usb_bus.hcpriv */
@@ -98,6 +110,8 @@ struct vhci_hcd {
 
        atomic_t seqnum;
 
+       unsigned int using_ports;
+
        /*
         * NOTE:
         * wIndex shows the port number and begins from 1.
@@ -106,12 +120,18 @@ struct vhci_hcd {
        struct vhci_device vdev[VHCI_HC_PORTS];
 };
 
+extern int vhci_max_controllers;
+extern int vhci_init_controllers;
 extern int vhci_num_controllers;
 extern struct platform_device **vhci_pdevs;
 extern struct attribute_group vhci_attr_group;
 
 /* vhci_hcd.c */
 void rh_port_connect(struct vhci_device *vdev, enum usb_device_speed speed);
+int vhci_get_device(__u32 pdev_nr, __u32 rhport,
+                   struct vhci_hcd **vhci, struct vhci_device **vdev);
+void vhci_put_device(struct vhci_device *vdev);
+void vhci_event_add(struct usbip_device *ud, unsigned long event);
 
 /* vhci_sysfs.c */
 int vhci_init_attr_group(void);
@@ -160,4 +180,14 @@ static inline struct vhci_hcd *vdev_to_vhci(struct 
vhci_device *vdev)
                        (void *)(vdev - vdev->rhport), struct vhci_hcd, vdev);
 }
 
+static inline int pdev_id2nr(int id)
+{
+       return (id < 0) ? 0 : id;
+}
+
+static inline int pdev_nr2id(int nr)
+{
+       return (nr == 0) ? -1 : nr;
+}
+
 #endif /* __USBIP_VHCI_H */
diff --git a/drivers/usb/usbip/vhci_hcd.c b/drivers/usb/usbip/vhci_hcd.c
index 2ddac11..fe085d8 100644
--- a/drivers/usb/usbip/vhci_hcd.c
+++ b/drivers/usb/usbip/vhci_hcd.c
@@ -57,10 +57,22 @@ 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";
 
-int vhci_num_controllers = VHCI_NR_HCS;
+int vhci_max_controllers = VHCI_MAX_HCS;
+int vhci_init_controllers = VHCI_INIT_HCS;
+int vhci_num_controllers;
 
+static spinlock_t pdevs_lock;
 struct platform_device **vhci_pdevs;
 
+static spinlock_t using_ports_lock;
+static unsigned int vhci_using_ports;
+
+static int pdevs_init_completed;
+static atomic_t pdevs_init_count;
+
+static wait_queue_head_t pdevs_waitq;
+static int pdev_nr_started;
+
 static const char * const bit_desc[] = {
        "CONNECTION",           /*0*/
        "ENABLE",               /*1*/
@@ -439,7 +451,7 @@ static struct vhci_device *get_vdev(struct usb_device *udev)
        if (!udev)
                return NULL;
 
-       for (pdev_nr = 0; pdev_nr < vhci_num_controllers; pdev_nr++) {
+       for (pdev_nr = 0; pdev_nr < vhci_max_controllers; pdev_nr++) {
                pdev = *(vhci_pdevs + pdev_nr);
                if (pdev == NULL)
                        continue;
@@ -470,7 +482,7 @@ static void vhci_tx_urb(struct urb *urb)
 
        priv = kzalloc(sizeof(struct vhci_priv), GFP_ATOMIC);
        if (!priv) {
-               usbip_event_add(&vdev->ud, VDEV_EVENT_ERROR_MALLOC);
+               vhci_event_add(&vdev->ud, VDEV_EVENT_ERROR_MALLOC);
                return;
        }
 
@@ -726,7 +738,7 @@ static int vhci_urb_dequeue(struct usb_hcd *hcd, struct urb 
*urb, int status)
                if (!unlink) {
                        spin_unlock(&vdev->priv_lock);
                        spin_unlock_irqrestore(&vhci->lock, flags);
-                       usbip_event_add(&vdev->ud, VDEV_EVENT_ERROR_MALLOC);
+                       vhci_event_add(&vdev->ud, VDEV_EVENT_ERROR_MALLOC);
                        return -ENOMEM;
                }
 
@@ -867,7 +879,6 @@ static void vhci_shutdown_connection(struct usbip_device 
*ud)
        pr_info("disconnect device\n");
 }
 
-
 static void vhci_device_reset(struct usbip_device *ud)
 {
        struct vhci_device *vdev = container_of(ud, struct vhci_device, ud);
@@ -888,15 +899,20 @@ static void vhci_device_reset(struct usbip_device *ud)
        ud->status = VDEV_ST_NULL;
 
        spin_unlock_irqrestore(&ud->lock, flags);
+
+       vhci_put_device(vdev);
 }
 
 static void vhci_device_unusable(struct usbip_device *ud)
 {
+       struct vhci_device *vdev = container_of(ud, struct vhci_device, ud);
        unsigned long flags;
 
        spin_lock_irqsave(&ud->lock, flags);
        ud->status = VDEV_ST_ERROR;
        spin_unlock_irqrestore(&ud->lock, flags);
+
+       vhci_put_device(vdev);
 }
 
 static void vhci_device_init(struct vhci_device *vdev)
@@ -906,6 +922,7 @@ static void vhci_device_init(struct vhci_device *vdev)
        vdev->ud.side   = USBIP_VHCI;
        vdev->ud.status = VDEV_ST_NULL;
        spin_lock_init(&vdev->ud.lock);
+       atomic_set(&vdev->using_port, 0);
 
        INIT_LIST_HEAD(&vdev->priv_rx);
        INIT_LIST_HEAD(&vdev->priv_tx);
@@ -922,7 +939,7 @@ static void vhci_device_init(struct vhci_device *vdev)
        usbip_start_eh(&vdev->ud);
 }
 
-static int hcd_name_to_id(const char *name)
+static int hcd_name_to_pdev_nr(const char *name)
 {
        char *c;
        long val;
@@ -942,7 +959,7 @@ static int hcd_name_to_id(const char *name)
 static int vhci_start(struct usb_hcd *hcd)
 {
        struct vhci_hcd *vhci = hcd_to_vhci(hcd);
-       int id, rhport;
+       int pdev_nr, rhport;
        int err = 0;
 
        usbip_dbg_vhci_hc("enter vhci_start\n");
@@ -958,18 +975,19 @@ static int vhci_start(struct usb_hcd *hcd)
 
        atomic_set(&vhci->seqnum, 0);
        spin_lock_init(&vhci->lock);
+       vhci->using_ports = 0;
 
        hcd->power_budget = 0; /* no limit */
        hcd->uses_new_polling = 1;
 
-       id = hcd_name_to_id(hcd_name(hcd));
-       if (id < 0) {
+       pdev_nr = hcd_name_to_pdev_nr(hcd_name(hcd));
+       if (pdev_nr < 0) {
                pr_err("invalid vhci name %s\n", hcd_name(hcd));
                return -EINVAL;
        }
 
        /* vhci_hcd is now ready to be controlled through sysfs */
-       if (id == 0) {
+       if (pdev_nr == 0) {
                err = vhci_init_attr_group();
                if (err) {
                        pr_err("init attr group\n");
@@ -984,19 +1002,26 @@ static int vhci_start(struct usb_hcd *hcd)
                pr_info("created sysfs %s\n", hcd_name(hcd));
        }
 
+       if (atomic_dec_and_test(&pdevs_init_count))
+               pdevs_init_completed = 1;
+       if (pdevs_init_completed)
+               atomic_set(&pdevs_init_count, -1);
+       pdev_nr_started = pdev_nr;
+       wake_up(&pdevs_waitq);
+
        return 0;
 }
 
 static void vhci_stop(struct usb_hcd *hcd)
 {
        struct vhci_hcd *vhci = hcd_to_vhci(hcd);
-       int id, rhport;
+       int pdev_nr, rhport;
 
        usbip_dbg_vhci_hc("stop VHCI controller\n");
 
        /* 1. remove the userland interface of vhci_hcd */
-       id = hcd_name_to_id(hcd_name(hcd));
-       if (id == 0) {
+       pdev_nr = hcd_name_to_pdev_nr(hcd_name(hcd));
+       if (pdev_nr == 0) {
                sysfs_remove_group(&hcd_dev(hcd)->kobj, &vhci_attr_group);
                vhci_finish_attr_group();
        }
@@ -1005,7 +1030,7 @@ static void vhci_stop(struct usb_hcd *hcd)
        for (rhport = 0; rhport < VHCI_HC_PORTS; rhport++) {
                struct vhci_device *vdev = &vhci->vdev[rhport];
 
-               usbip_event_add(&vdev->ud, VDEV_EVENT_REMOVED);
+               vhci_event_add(&vdev->ud, VDEV_EVENT_REMOVED);
                usbip_stop_eh(&vdev->ud);
        }
 }
@@ -1200,49 +1225,199 @@ static struct platform_driver vhci_driver = {
        },
 };
 
-static int add_platform_device(int id)
+static int __add_platform_device(int pdev_nr)
 {
        struct platform_device *pdev;
-       int dev_nr;
-
-       if (id == 0)
-               dev_nr = -1;
-       else
-               dev_nr = id;
+       int id = pdev_nr2id(pdev_nr);
 
-       pdev = platform_device_register_simple(driver_name, dev_nr, NULL, 0);
-       if (pdev == NULL)
+       pdev = platform_device_register_simple(driver_name, id, NULL, 0);
+       if (pdev == NULL) {
+               pr_err("failed to register pdev\n");
                return -ENODEV;
+       }
+
+       *(vhci_pdevs + pdev_nr) = pdev;
+       ++vhci_num_controllers;
 
-       *(vhci_pdevs + id) = pdev;
        return 0;
 }
 
+static void __del_platform_device(int pdev_nr)
+{
+       struct platform_device *pdev = *(vhci_pdevs + pdev_nr);
+
+       if (!pdev)
+               return;
+
+       usbip_dbg_vhci_rh("deleting pdev %d\n", pdev_nr);
+       *(vhci_pdevs + pdev_nr) = NULL;
+       vhci_num_controllers--;
+       platform_device_unregister(pdev);
+}
+
+static void __del_platform_devices(void)
+{
+       int i;
+
+       for (i = 0; i < vhci_max_controllers; i++)
+               __del_platform_device(i);
+       sysfs_remove_link(&platform_bus.kobj, driver_name);
+}
+
 static void del_platform_devices(void)
 {
+       spin_lock(&pdevs_lock);
+       __del_platform_devices();
+       spin_unlock(&pdevs_lock);
+}
+
+static void __vhci_get_device(struct platform_device *pdev, __u32 rhport,
+                             struct vhci_hcd **vhci, struct vhci_device **vdev)
+{
+       struct usb_hcd *hcd;
+       unsigned long flags;
+
+       spin_lock_irqsave(&using_ports_lock, flags);
+       hcd = platform_get_drvdata(pdev);
+       *vhci = hcd_to_vhci(hcd);
+       *vdev = &((*vhci)->vdev[rhport]);
+       vhci_using_ports++;
+       ((*vhci)->using_ports)++;
+       atomic_set(&((*vdev)->using_port), 1);
+       spin_unlock_irqrestore(&using_ports_lock, flags);
+}
+
+int vhci_get_device(__u32 pdev_nr, __u32 rhport,
+                   struct vhci_hcd **vhci, struct vhci_device **vdev)
+{
        struct platform_device *pdev;
-       int i;
+       unsigned long flags;
+       int ret;
 
-       for (i = 0; i < vhci_num_controllers; i++) {
-               pdev = *(vhci_pdevs + i);
-               if (pdev != NULL)
-                       platform_device_unregister(pdev);
-               *(vhci_pdevs + i) = NULL;
+       if (wait_event_interruptible(pdevs_waitq, pdevs_init_completed))
+               return -ERESTARTSYS;
+
+       spin_lock_irqsave(&pdevs_lock, flags);
+
+       pdev = *(vhci_pdevs + pdev_nr);
+       if (pdev) {
+               __vhci_get_device(pdev, rhport, vhci, vdev);
+               spin_unlock_irqrestore(&pdevs_lock, flags);
+               return 0;
        }
-       sysfs_remove_link(&platform_bus.kobj, driver_name);
+
+       pdev_nr_started = -1;
+
+       ret = __add_platform_device(pdev_nr);
+       if (ret) {
+               spin_unlock_irqrestore(&pdevs_lock, flags);
+               return ret;
+       }
+
+       usbip_dbg_vhci_rh("waiting pdev started %d\n", pdev_nr);
+       if (wait_event_interruptible(pdevs_waitq,
+                                    pdev_nr_started == pdev_nr)) {
+               spin_unlock_irqrestore(&pdevs_lock, flags);
+               return -ERESTARTSYS;
+       }
+       usbip_dbg_vhci_rh("end of waiting pdev start %d\n", pdev_nr);
+
+       pdev = *(vhci_pdevs + pdev_nr);
+       __vhci_get_device(pdev, rhport, vhci, vdev);
+
+       spin_unlock_irqrestore(&pdevs_lock, flags);
+
+       return 0;
+}
+
+void vhci_put_device(struct vhci_device *vdev)
+{
+       struct vhci_hcd *vhci;
+       unsigned long flags;
+
+       if (!atomic_dec_and_test(&vdev->using_port))
+               return;
+
+       spin_lock_irqsave(&using_ports_lock, flags);
+       vhci = vdev_to_vhci(vdev);
+       (vhci->using_ports)--;
+       vhci_using_ports--;
+       spin_unlock_irqrestore(&using_ports_lock, flags);
+}
+
+static int __try_del_platform_device(void)
+{
+       int pdev_nr;
+       struct platform_device *pdev;
+       struct vhci_hcd *vhci;
+
+       for (pdev_nr = (vhci_max_controllers - 1); pdev_nr > 0; pdev_nr--) {
+               pdev = *(vhci_pdevs + pdev_nr);
+               if (!pdev)
+                       continue;
+               vhci = hcd_to_vhci(platform_get_drvdata(pdev));
+               if (!vhci->using_ports) {
+                       __del_platform_device(pdev_nr);
+                       return 1;
+               }
+       }
+       return 0;
+}
+
+static void try_del_platform_device(void)
+{
+       unsigned long flags;
+       unsigned int free_ports;
+
+       if (!spin_trylock_irqsave(&pdevs_lock, flags)) {
+               usbip_dbg_vhci_rh("recursive call or exitting\n");
+               return;
+       }
+       usbip_dbg_vhci_rh("trying del pdev\n");
+
+       if (vhci_num_controllers > vhci_init_controllers) {
+               free_ports = (vhci_num_controllers * VHCI_HC_PORTS)
+                               - vhci_using_ports;
+               usbip_dbg_vhci_rh("%d free ports in %d hcs\n",
+                                 free_ports, vhci_num_controllers);
+               /* free_pots will be decremented with this event */
+               if (free_ports >=  (VHCI_HC_PORTS * VHCI_FREE_HCS))
+                       __try_del_platform_device();
+       }
+
+       spin_unlock_irqrestore(&pdevs_lock, flags);
+}
+
+void vhci_event_add(struct usbip_device *ud, unsigned long event)
+{
+       usbip_dbg_vhci_rh("adding event %lu\n", event);
+
+       if (event != VDEV_EVENT_REMOVED && !usbip_in_eh(current))
+               try_del_platform_device();
+
+       usbip_event_add(ud, event);
 }
 
 static int __init vhci_hcd_init(void)
 {
-       int i, ret;
+       int pdev_nr, ret;
 
        if (usb_disabled())
                return -ENODEV;
 
-       if (vhci_num_controllers < 1)
-               vhci_num_controllers = 1;
+       if (vhci_max_controllers < 1)
+               vhci_max_controllers = 1;
+       if (vhci_init_controllers < 1)
+               vhci_init_controllers = 1;
+       if (vhci_init_controllers > vhci_max_controllers)
+               vhci_init_controllers = vhci_max_controllers;
 
-       vhci_pdevs = kcalloc(vhci_num_controllers, sizeof(void *), GFP_KERNEL);
+       spin_lock_init(&pdevs_lock);
+       spin_lock_init(&using_ports_lock);
+       init_waitqueue_head(&pdevs_waitq);
+       atomic_set(&pdevs_init_count, vhci_init_controllers);
+
+       vhci_pdevs = kcalloc(vhci_max_controllers, sizeof(void *), GFP_KERNEL);
        if (vhci_pdevs == NULL)
                return -ENOMEM;
 
@@ -1250,8 +1425,8 @@ static int __init vhci_hcd_init(void)
        if (ret)
                goto err_driver_register;
 
-       for (i = 0; i < vhci_num_controllers; i++) {
-               ret = add_platform_device(i);
+       for (pdev_nr = 0; pdev_nr < vhci_init_controllers; pdev_nr++) {
+               ret = __add_platform_device(pdev_nr);
                if (ret)
                        goto err_platform_device_register;
        }
@@ -1260,7 +1435,7 @@ static int __init vhci_hcd_init(void)
        return ret;
 
 err_platform_device_register:
-       del_platform_devices();
+       __del_platform_devices();
        platform_driver_unregister(&vhci_driver);
 err_driver_register:
        kfree(vhci_pdevs);
diff --git a/drivers/usb/usbip/vhci_rx.c b/drivers/usb/usbip/vhci_rx.c
index fc2d319..bea43f7 100644
--- a/drivers/usb/usbip/vhci_rx.c
+++ b/drivers/usb/usbip/vhci_rx.c
@@ -83,7 +83,7 @@ static void vhci_recv_ret_submit(struct vhci_device *vdev,
                pr_err("cannot find a urb of seqnum %u\n", pdu->base.seqnum);
                pr_info("max seqnum %d\n",
                        atomic_read(&vhci->seqnum));
-               usbip_event_add(ud, VDEV_EVENT_ERROR_TCP);
+               vhci_event_add(ud, VDEV_EVENT_ERROR_TCP);
                return;
        }
 
@@ -222,18 +222,18 @@ static void vhci_rx_pdu(struct usbip_device *ud)
                } else if (ret != -ERESTARTSYS)
                        pr_info("xmit failed %d\n", ret);
 
-               usbip_event_add(ud, VDEV_EVENT_ERROR_TCP);
+               vhci_event_add(ud, VDEV_EVENT_ERROR_TCP);
                return;
        }
        if (ret == 0) {
                pr_info("connection closed");
-               usbip_event_add(ud, VDEV_EVENT_DOWN);
+               vhci_event_add(ud, VDEV_EVENT_DOWN);
                return;
        }
        if (ret != sizeof(pdu)) {
                pr_err("received pdu size is %d, should be %d\n", ret,
                       (unsigned int)sizeof(pdu));
-               usbip_event_add(ud, VDEV_EVENT_ERROR_TCP);
+               vhci_event_add(ud, VDEV_EVENT_ERROR_TCP);
                return;
        }
 
@@ -253,7 +253,7 @@ static void vhci_rx_pdu(struct usbip_device *ud)
                /* NOT REACHED */
                pr_err("unknown pdu %u\n", pdu.base.command);
                usbip_dump_header(&pdu);
-               usbip_event_add(ud, VDEV_EVENT_ERROR_TCP);
+               vhci_event_add(ud, VDEV_EVENT_ERROR_TCP);
                break;
        }
 }
diff --git a/drivers/usb/usbip/vhci_sysfs.c b/drivers/usb/usbip/vhci_sysfs.c
index c404017..91bde37 100644
--- a/drivers/usb/usbip/vhci_sysfs.c
+++ b/drivers/usb/usbip/vhci_sysfs.c
@@ -30,15 +30,15 @@
 /* TODO: refine locking ?*/
 
 /* Sysfs entry to show port status */
-static ssize_t status_show_vhci(int pdev_nr, char *out)
+static ssize_t status_show_vhci(int pdev_nr, struct platform_device *pdev,
+                               char *out)
 {
-       struct platform_device *pdev = *(vhci_pdevs + pdev_nr);
        struct vhci_hcd *vhci;
        char *s = out;
        int i = 0;
        unsigned long flags;
 
-       if (!pdev || !out) {
+       if (!out) {
                usbip_dbg_vhci_sysfs("show status error\n");
                return 0;
        }
@@ -86,7 +86,7 @@ static ssize_t status_show_vhci(int pdev_nr, char *out)
        return out - s;
 }
 
-static ssize_t status_show_not_ready(int pdev_nr, char *out)
+static ssize_t status_show_idle(int pdev_nr, char *out)
 {
        char *s = out;
        int i = 0;
@@ -94,7 +94,7 @@ static ssize_t status_show_not_ready(int pdev_nr, char *out)
        for (i = 0; i < VHCI_HC_PORTS; i++) {
                out += sprintf(out, "%04u %03u ",
                                    (pdev_nr * VHCI_HC_PORTS) + i,
-                                   VDEV_ST_NOTASSIGNED);
+                                   VDEV_ST_NULL);
                out += sprintf(out, "000 00000000 0000000000000000 0-0");
                out += sprintf(out, "\n");
        }
@@ -123,15 +123,20 @@ static ssize_t status_show(struct device *dev,
 {
        char *s = out;
        int pdev_nr;
+       struct platform_device *pdev = NULL;
 
        out += sprintf(out,
                       "port sta spd dev      socket           local_busid\n");
 
        pdev_nr = status_name_to_id(attr->attr.name);
        if (pdev_nr < 0)
-               out += status_show_not_ready(pdev_nr, out);
+               return 0;
+
+       pdev = *(vhci_pdevs + pdev_nr);
+       if (pdev)
+               out += status_show_vhci(pdev_nr, pdev, out);
        else
-               out += status_show_vhci(pdev_nr, out);
+               out += status_show_idle(pdev_nr, out);
 
        return out - s;
 }
@@ -141,7 +146,7 @@ static ssize_t nports_show(struct device *dev, struct 
device_attribute *attr,
 {
        char *s = out;
 
-       out += sprintf(out, "%d\n", VHCI_HC_PORTS * vhci_num_controllers);
+       out += sprintf(out, "%d\n", VHCI_HC_PORTS * vhci_max_controllers);
        return out - s;
 }
 static DEVICE_ATTR_RO(nports);
@@ -172,14 +177,14 @@ static int vhci_port_disconnect(struct vhci_hcd *vhci, 
__u32 rhport)
        spin_unlock(&vdev->ud.lock);
        spin_unlock_irqrestore(&vhci->lock, flags);
 
-       usbip_event_add(&vdev->ud, VDEV_EVENT_DOWN);
+       vhci_event_add(&vdev->ud, VDEV_EVENT_DOWN);
 
        return 0;
 }
 
 static int valid_port(__u32 pdev_nr, __u32 rhport)
 {
-       if (pdev_nr >= vhci_num_controllers) {
+       if (pdev_nr >= vhci_max_controllers) {
                pr_err("pdev %u\n", pdev_nr);
                return 0;
        }
@@ -261,7 +266,6 @@ static ssize_t store_attach(struct device *dev, struct 
device_attribute *attr,
        struct socket *socket;
        int sockfd = 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 err;
@@ -287,18 +291,16 @@ static ssize_t store_attach(struct device *dev, struct 
device_attribute *attr,
        if (!valid_args(pdev_nr, rhport, speed))
                return -EINVAL;
 
-       hcd = platform_get_drvdata(*(vhci_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];
+       err = vhci_get_device(pdev_nr, rhport, &vhci, &vdev);
+       if (err)
+               return err;
 
        /* Extract socket from fd. */
        socket = sockfd_lookup(sockfd, &err);
-       if (!socket)
+       if (!socket) {
+               vhci_put_device(vdev);
                return -EINVAL;
+       }
 
        /* now need lock until setting vdev status as used */
 
@@ -312,6 +314,7 @@ static ssize_t store_attach(struct device *dev, struct 
device_attribute *attr,
                spin_unlock_irqrestore(&vhci->lock, flags);
 
                sockfd_put(socket);
+               vhci_put_device(vdev);
 
                dev_err(dev, "port %d already used\n", rhport);
                return -EINVAL;
@@ -367,12 +370,12 @@ static int init_status_attrs(void)
 {
        int id;
 
-       status_attrs = kcalloc(vhci_num_controllers, sizeof(struct status_attr),
+       status_attrs = kcalloc(vhci_max_controllers, sizeof(struct status_attr),
                               GFP_KERNEL);
        if (status_attrs == NULL)
                return -ENOMEM;
 
-       for (id = 0; id < vhci_num_controllers; id++)
+       for (id = 0; id < vhci_max_controllers; id++)
                set_status_attr(id);
 
        return 0;
@@ -392,7 +395,7 @@ int vhci_init_attr_group(void)
        struct attribute **attrs;
        int ret, i;
 
-       attrs = kcalloc((vhci_num_controllers + 5), sizeof(struct attribute *),
+       attrs = kcalloc((vhci_max_controllers + 5), sizeof(struct attribute *),
                        GFP_KERNEL);
        if (attrs == NULL)
                return -ENOMEM;
@@ -406,7 +409,7 @@ int vhci_init_attr_group(void)
        *(attrs + 1) = &dev_attr_detach.attr;
        *(attrs + 2) = &dev_attr_attach.attr;
        *(attrs + 3) = &dev_attr_usbip_debug.attr;
-       for (i = 0; i < vhci_num_controllers; i++)
+       for (i = 0; i < vhci_max_controllers; i++)
                *(attrs + i + 4) = &((status_attrs + i)->attr.attr);
        vhci_attr_group.attrs = attrs;
        return 0;
diff --git a/drivers/usb/usbip/vhci_tx.c b/drivers/usb/usbip/vhci_tx.c
index 3e7878f..94f9c0a 100644
--- a/drivers/usb/usbip/vhci_tx.c
+++ b/drivers/usb/usbip/vhci_tx.c
@@ -106,7 +106,7 @@ static int vhci_send_cmd_submit(struct vhci_device *vdev)
 
                        iso_buffer = usbip_alloc_iso_desc_pdu(urb, &len);
                        if (!iso_buffer) {
-                               usbip_event_add(&vdev->ud,
+                               vhci_event_add(&vdev->ud,
                                                SDEV_EVENT_ERROR_MALLOC);
                                return -1;
                        }
@@ -121,7 +121,7 @@ static int vhci_send_cmd_submit(struct vhci_device *vdev)
                        pr_err("sendmsg failed!, ret=%d for %zd\n", ret,
                               txsize);
                        kfree(iso_buffer);
-                       usbip_event_add(&vdev->ud, VDEV_EVENT_ERROR_TCP);
+                       vhci_event_add(&vdev->ud, VDEV_EVENT_ERROR_TCP);
                        return -1;
                }
 
@@ -190,7 +190,7 @@ static int vhci_send_cmd_unlink(struct vhci_device *vdev)
                if (ret != txsize) {
                        pr_err("sendmsg failed!, ret=%d for %zd\n", ret,
                               txsize);
-                       usbip_event_add(&vdev->ud, VDEV_EVENT_ERROR_TCP);
+                       vhci_event_add(&vdev->ud, VDEV_EVENT_ERROR_TCP);
                        return -1;
                }
 
-- 
2.1.0

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

Reply via email to