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

[Xen-devel] [PATCH 2/3] PVUSB update and bugfix: backend part



Signed-off-by: Noboru Iwamatsu <n_iwamatsu@xxxxxxxxxxxxxx>

diff -r 4ac3e1d6605c -r 3be939975ad6 drivers/xen/usbback/interface.c
--- a/drivers/xen/usbback/interface.c   Tue Sep 29 11:23:06 2009 +0100
+++ b/drivers/xen/usbback/interface.c   Tue Oct 06 15:18:27 2009 +0900
@@ -48,7 +48,7 @@
 static LIST_HEAD(usbif_list);
 static DEFINE_SPINLOCK(usbif_list_lock);
 
-usbif_t *find_usbif(int dom_id, int dev_id)
+usbif_t *find_usbif(domid_t domid, unsigned int handle)
 {
        usbif_t *usbif;
        int found = 0;
@@ -56,8 +56,8 @@
 
        spin_lock_irqsave(&usbif_list_lock, flags);
        list_for_each_entry(usbif, &usbif_list, usbif_list) {
-               if (usbif->domid == dom_id
-                       && usbif->handle == dev_id) {
+               if (usbif->domid == domid
+                       && usbif->handle == handle) {
                        found = 1;
                        break;
                }
@@ -82,16 +82,16 @@
 
        usbif->domid = domid;
        usbif->handle = handle;
-       spin_lock_init(&usbif->ring_lock);
+       spin_lock_init(&usbif->urb_ring_lock);
+       spin_lock_init(&usbif->conn_ring_lock);
        atomic_set(&usbif->refcnt, 0);
        init_waitqueue_head(&usbif->wq);
        init_waitqueue_head(&usbif->waiting_to_free);
-       spin_lock_init(&usbif->plug_lock);
-       INIT_LIST_HEAD(&usbif->plugged_devices);
+       spin_lock_init(&usbif->stub_lock);
+       INIT_LIST_HEAD(&usbif->stub_list);
        spin_lock_init(&usbif->addr_lock);
-       for (i = 0; i < USB_DEV_ADDR_SIZE; i++) {
+       for (i = 0; i < USB_DEV_ADDR_SIZE; i++)
                usbif->addr_table[i] = NULL;
-       }
 
        spin_lock_irqsave(&usbif_list_lock, flags);
        list_add(&usbif->usbif_list, &usbif_list);
@@ -100,70 +100,109 @@
        return usbif;
 }
 
-static int map_frontend_page(usbif_t *usbif, unsigned long shared_page)
+static int map_frontend_pages(usbif_t *usbif,
+                               grant_ref_t urb_ring_ref,
+                               grant_ref_t conn_ring_ref)
 {
        struct gnttab_map_grant_ref op;
 
-       gnttab_set_map_op(&op, (unsigned long)usbif->ring_area->addr,
-                         GNTMAP_host_map, shared_page, usbif->domid);
+       gnttab_set_map_op(&op, (unsigned long)usbif->urb_ring_area->addr,
+                         GNTMAP_host_map, urb_ring_ref, usbif->domid);
 
        if (HYPERVISOR_grant_table_op(GNTTABOP_map_grant_ref, &op, 1))
                BUG();
 
        if (op.status) {
-               printk(KERN_ERR "grant table operation failure\n");
+               printk(KERN_ERR "grant table failure mapping urb_ring_ref\n");
                return op.status;
        }
 
-       usbif->shmem_ref = shared_page;
-       usbif->shmem_handle = op.handle;
+       usbif->urb_shmem_ref = urb_ring_ref;
+       usbif->urb_shmem_handle = op.handle;
+
+       gnttab_set_map_op(&op, (unsigned long)usbif->conn_ring_area->addr,
+                         GNTMAP_host_map, conn_ring_ref, usbif->domid);
+
+       if (HYPERVISOR_grant_table_op(GNTTABOP_map_grant_ref, &op, 1))
+               BUG();
+
+       if (op.status) {
+               struct gnttab_unmap_grant_ref unop;
+               gnttab_set_unmap_op(&unop,
+                               (unsigned long) usbif->urb_ring_area->addr,
+                               GNTMAP_host_map, usbif->urb_shmem_handle);
+               VOID(HYPERVISOR_grant_table_op(GNTTABOP_unmap_grant_ref, &unop,
+                               1));
+               printk(KERN_ERR "grant table failure mapping conn_ring_ref\n");
+               return op.status;
+       }
+
+       usbif->conn_shmem_ref = conn_ring_ref;
+       usbif->conn_shmem_handle = op.handle;
 
        return 0;
 }
 
-static void unmap_frontend_page(usbif_t *usbif)
+static void unmap_frontend_pages(usbif_t *usbif)
 {
        struct gnttab_unmap_grant_ref op;
 
-       gnttab_set_unmap_op(&op, (unsigned long)usbif->ring_area->addr,
-                           GNTMAP_host_map, usbif->shmem_handle);
+       gnttab_set_unmap_op(&op, (unsigned long)usbif->urb_ring_area->addr,
+                           GNTMAP_host_map, usbif->urb_shmem_handle);
+
+       if (HYPERVISOR_grant_table_op(GNTTABOP_unmap_grant_ref, &op, 1))
+               BUG();
+
+       gnttab_set_unmap_op(&op, (unsigned long)usbif->conn_ring_area->addr,
+                           GNTMAP_host_map, usbif->conn_shmem_handle);
 
        if (HYPERVISOR_grant_table_op(GNTTABOP_unmap_grant_ref, &op, 1))
                BUG();
 }
 
-int usbif_map(usbif_t *usbif, unsigned long shared_page, unsigned int evtchn)
+int usbif_map(usbif_t *usbif, unsigned long urb_ring_ref,
+               unsigned long conn_ring_ref, unsigned int evtchn)
 {
-       int err;
-       usbif_sring_t *sring;
+       int err = -ENOMEM;
+
+       usbif_urb_sring_t *urb_sring;
+       usbif_conn_sring_t *conn_sring;
 
        if (usbif->irq)
                return 0;
 
-       if ((usbif->ring_area = alloc_vm_area(PAGE_SIZE)) == NULL)
-               return -ENOMEM;
+       if ((usbif->urb_ring_area = alloc_vm_area(PAGE_SIZE)) == NULL)
+               return err;
+       if ((usbif->conn_ring_area = alloc_vm_area(PAGE_SIZE)) == NULL)
+               goto fail_alloc;
 
-       err = map_frontend_page(usbif, shared_page);
-       if (err) {
-               free_vm_area(usbif->ring_area);
-               return err;
-       }
-
-       sring = (usbif_sring_t *) usbif->ring_area->addr;
-       BACK_RING_INIT(&usbif->ring, sring, PAGE_SIZE);
+       err = map_frontend_pages(usbif, urb_ring_ref, conn_ring_ref);
+       if (err)
+               goto fail_map;
 
        err = bind_interdomain_evtchn_to_irqhandler(
-                       usbif->domid, evtchn, usbbk_be_int, 0, "usbif-backend", 
usbif);
+                       usbif->domid, evtchn, usbbk_be_int, 0,
+                       "usbif-backend", usbif);
        if (err < 0)
-       {
-               unmap_frontend_page(usbif);
-               free_vm_area(usbif->ring_area);
-               usbif->ring.sring = NULL;
-               return err;
-       }
+               goto fail_evtchn;
        usbif->irq = err;
 
+       urb_sring = (usbif_urb_sring_t *) usbif->urb_ring_area->addr;
+       BACK_RING_INIT(&usbif->urb_ring, urb_sring, PAGE_SIZE);
+
+       conn_sring = (usbif_conn_sring_t *) usbif->conn_ring_area->addr;
+       BACK_RING_INIT(&usbif->conn_ring, conn_sring, PAGE_SIZE);
+
        return 0;
+
+fail_evtchn:
+       unmap_frontend_pages(usbif);
+fail_map:
+       free_vm_area(usbif->conn_ring_area);
+fail_alloc:
+       free_vm_area(usbif->urb_ring_area);
+
+       return err;
 }
 
 void usbif_disconnect(usbif_t *usbif)
@@ -176,12 +215,12 @@
                usbif->xenusbd = NULL;
        }
 
-       spin_lock_irqsave(&usbif->plug_lock, flags);
-       list_for_each_entry_safe(stub, tmp, &usbif->plugged_devices, 
plugged_list) {
+       spin_lock_irqsave(&usbif->stub_lock, flags);
+       list_for_each_entry_safe(stub, tmp, &usbif->stub_list, dev_list) {
                usbbk_unlink_urbs(stub);
                detach_device_without_lock(usbif, stub);
        }
-       spin_unlock_irqrestore(&usbif->plug_lock, flags);
+       spin_unlock_irqrestore(&usbif->stub_lock, flags);
 
        wait_event(usbif->waiting_to_free, atomic_read(&usbif->refcnt) == 0);
 
@@ -190,10 +229,12 @@
                usbif->irq = 0;
        }
 
-       if (usbif->ring.sring) {
-               unmap_frontend_page(usbif);
-               free_vm_area(usbif->ring_area);
-               usbif->ring.sring = NULL;
+       if (usbif->urb_ring.sring) {
+               unmap_frontend_pages(usbif);
+               free_vm_area(usbif->urb_ring_area);
+               free_vm_area(usbif->conn_ring_area);
+               usbif->urb_ring.sring = NULL;
+               usbif->conn_ring.sring = NULL;
        }
 }
 
diff -r 4ac3e1d6605c -r 3be939975ad6 drivers/xen/usbback/usbback.c
--- a/drivers/xen/usbback/usbback.c     Tue Sep 29 11:23:06 2009 +0100
+++ b/drivers/xen/usbback/usbback.c     Tue Oct 06 15:18:27 2009 +0900
@@ -107,7 +107,7 @@
 #define pending_handle(_req, _seg) \
        (pending_grant_handles[vaddr_pagenr(_req, _seg)])
 
-static pending_req_t* alloc_req(void)
+static pending_req_t *alloc_req(void)
 {
        pending_req_t *req = NULL;
        unsigned long flags;
@@ -222,7 +222,7 @@
        }
 }
 
-static int usbbk_alloc_urb(usbif_request_t *req, pending_req_t *pending_req)
+static int usbbk_alloc_urb(usbif_urb_request_t *req, pending_req_t 
*pending_req)
 {
        int ret;
 
@@ -298,21 +298,21 @@
                                        int32_t actual_length, int32_t 
error_count, uint16_t start_frame)
 {
        usbif_t *usbif = pending_req->usbif;
-       usbif_response_t *ring_res;
+       usbif_urb_response_t *res;
        unsigned long flags;
        int notify;
 
-       spin_lock_irqsave(&usbif->ring_lock, flags);
-       ring_res = RING_GET_RESPONSE(&usbif->ring, usbif->ring.rsp_prod_pvt);
-       ring_res->id = pending_req->id;
-       ring_res->status = status;
-       ring_res->actual_length = actual_length;
-       ring_res->error_count = error_count;
-       ring_res->start_frame = start_frame;
-       usbif->ring.rsp_prod_pvt++;
+       spin_lock_irqsave(&usbif->urb_ring_lock, flags);
+       res = RING_GET_RESPONSE(&usbif->urb_ring, usbif->urb_ring.rsp_prod_pvt);
+       res->id = pending_req->id;
+       res->status = status;
+       res->actual_length = actual_length;
+       res->error_count = error_count;
+       res->start_frame = start_frame;
+       usbif->urb_ring.rsp_prod_pvt++;
        barrier();
-       RING_PUSH_RESPONSES_AND_CHECK_NOTIFY(&usbif->ring, notify);
-       spin_unlock_irqrestore(&usbif->ring_lock, flags);
+       RING_PUSH_RESPONSES_AND_CHECK_NOTIFY(&usbif->urb_ring, notify);
+       spin_unlock_irqrestore(&usbif->urb_ring_lock, flags);
 
        if (notify)
                notify_remote_via_irq(usbif->irq);
@@ -346,7 +346,7 @@
 }
 
 static int usbbk_gnttab_map(usbif_t *usbif,
-                       usbif_request_t *req, pending_req_t *pending_req)
+                       usbif_urb_request_t *req, pending_req_t *pending_req)
 {
        int i, ret;
        unsigned int nr_segs;
@@ -434,7 +434,7 @@
        return ret;
 }
 
-static void usbbk_init_urb(usbif_request_t *req, pending_req_t *pending_req)
+static void usbbk_init_urb(usbif_urb_request_t *req, pending_req_t 
*pending_req)
 {
        unsigned int pipe;
        struct usb_device *udev = pending_req->stub->udev;
@@ -671,14 +671,14 @@
        int found = 0;
        unsigned long flags;
 
-       spin_lock_irqsave(&usbif->plug_lock, flags);
-       list_for_each_entry(stub, &usbif->plugged_devices, plugged_list) {
-               if (stub->id->portnum == portnum) {
+       spin_lock_irqsave(&usbif->stub_lock, flags);
+       list_for_each_entry(stub, &usbif->stub_list, dev_list) {
+               if (stub->portid->portnum == portnum) {
                        found = 1;
                        break;
                }
        }
-       spin_unlock_irqrestore(&usbif->plug_lock, flags);
+       spin_unlock_irqrestore(&usbif->stub_lock, flags);
 
        if (found)
                return stub;
@@ -686,7 +686,47 @@
        return NULL;
 }
 
-static int check_and_submit_special_ctrlreq(usbif_t *usbif, usbif_request_t 
*req, pending_req_t *pending_req)
+static void process_unlink_req(usbif_t *usbif,
+               usbif_urb_request_t *req, pending_req_t *pending_req)
+{
+       pending_req_t *unlink_req = NULL;
+       int devnum;
+       int ret = 0;
+       unsigned long flags;
+
+       devnum = usb_pipedevice(req->pipe);
+       if (unlikely(devnum == 0)) {
+               pending_req->stub = find_attached_device(usbif, 
usbif_pipeportnum(req->pipe));
+               if (unlikely(!pending_req->stub)) {
+                       ret = -ENODEV;
+                       goto fail_response;
+               }
+       } else {
+               if (unlikely(!usbif->addr_table[devnum])) {
+                       ret = -ENODEV;
+                       goto fail_response;
+               }
+               pending_req->stub = usbif->addr_table[devnum];
+       }
+
+       spin_lock_irqsave(&pending_req->stub->submitting_lock, flags);
+       list_for_each_entry(unlink_req, &pending_req->stub->submitting_list, 
urb_list) {
+               if (unlink_req->id == req->u.unlink.unlink_id) {
+                       ret = usb_unlink_urb(unlink_req->urb);
+                       break;
+               }
+       }
+       spin_unlock_irqrestore(&pending_req->stub->submitting_lock, flags);
+
+fail_response:
+       usbbk_do_response(pending_req, ret, 0, 0, 0);
+       usbif_put(usbif);
+       free_req(pending_req);
+       return;
+}
+
+static int check_and_submit_special_ctrlreq(usbif_t *usbif,
+               usbif_urb_request_t *req, pending_req_t *pending_req)
 {
        int devnum;
        struct usbstub *stub = NULL;
@@ -824,7 +864,7 @@
 }
 
 static void dispatch_request_to_pending_reqs(usbif_t *usbif,
-               usbif_request_t *req,
+               usbif_urb_request_t *req,
                pending_req_t *pending_req)
 {
        int ret;
@@ -834,17 +874,13 @@
 
        barrier();
 
-       /*
-        * TODO:
-        * receive unlink request and cancel the urb in backend
-        */
-#if 0
-       if (unlikely(usb_pipeunlink(req->pipe))) {
+       usbif_get(usbif);
 
+       /* unlink request */
+       if (unlikely(usbif_pipeunlink(req->pipe))) {
+               process_unlink_req(usbif, req, pending_req);
+               return;
        }
-#endif
-
-       usbif_get(usbif);
 
        if (usb_pipecontrol(req->pipe)) {
                if (check_and_submit_special_ctrlreq(usbif, req, pending_req))
@@ -927,18 +963,18 @@
 
 static int usbbk_start_submit_urb(usbif_t *usbif)
 {
-       usbif_back_ring_t *usb_ring = &usbif->ring;
-       usbif_request_t *ring_req;
+       usbif_urb_back_ring_t *urb_ring = &usbif->urb_ring;
+       usbif_urb_request_t *req;
        pending_req_t *pending_req;
        RING_IDX rc, rp;
        int more_to_do = 0;
 
-       rc = usb_ring->req_cons;
-       rp = usb_ring->sring->req_prod;
+       rc = urb_ring->req_cons;
+       rp = urb_ring->sring->req_prod;
        rmb();
 
        while (rc != rp) {
-               if (RING_REQUEST_CONS_OVERFLOW(usb_ring, rc)) {
+               if (RING_REQUEST_CONS_OVERFLOW(urb_ring, rc)) {
                        printk(KERN_WARNING "RING_REQUEST_CONS_OVERFLOW\n");
                        break;
                }
@@ -949,73 +985,100 @@
                        break;
                }
 
-               ring_req = RING_GET_REQUEST(usb_ring, rc);
-               usb_ring->req_cons = ++rc;
+               req = RING_GET_REQUEST(urb_ring, rc);
+               urb_ring->req_cons = ++rc;
 
-               dispatch_request_to_pending_reqs(usbif, ring_req,
+               dispatch_request_to_pending_reqs(usbif, req,
                                                        pending_req);
        }
 
-       RING_FINAL_CHECK_FOR_REQUESTS(&usbif->ring, more_to_do);
+       RING_FINAL_CHECK_FOR_REQUESTS(&usbif->urb_ring, more_to_do);
 
        cond_resched();
 
        return more_to_do;
 }
 
+void usbbk_hotplug_notify(usbif_t *usbif, int portnum, int speed)
+{
+       usbif_conn_back_ring_t *ring = &usbif->conn_ring;
+       usbif_conn_request_t *req;
+       usbif_conn_response_t *res;
+       unsigned long flags;
+       u16 id;
+       int notify;
+
+       spin_lock_irqsave(&usbif->conn_ring_lock, flags);
+
+       req = RING_GET_REQUEST(ring, ring->req_cons);;
+       id = req->id;
+       ring->req_cons++;
+       ring->sring->req_event = ring->req_cons + 1;
+
+       res = RING_GET_RESPONSE(ring, ring->rsp_prod_pvt);
+       res->id = id;
+       res->portnum = portnum;
+       res->speed = speed;
+       ring->rsp_prod_pvt++;
+       RING_PUSH_RESPONSES_AND_CHECK_NOTIFY(ring, notify);
+
+       spin_unlock_irqrestore(&usbif->conn_ring_lock, flags);
+
+       if (notify)
+               notify_remote_via_irq(usbif->irq);
+}
+
 int usbbk_schedule(void *arg)
 {
-        usbif_t *usbif = (usbif_t *)arg;
+       usbif_t *usbif = (usbif_t *) arg;
 
-        usbif_get(usbif);
+       usbif_get(usbif);
 
-        while(!kthread_should_stop()) {
-                wait_event_interruptible(
-                                usbif->wq,
-                                usbif->waiting_reqs || kthread_should_stop());
-                wait_event_interruptible(
-                                pending_free_wq,
-                                !list_empty(&pending_free) || 
kthread_should_stop());
-                usbif->waiting_reqs = 0;
-                smp_mb();
+       while (!kthread_should_stop()) {
+               wait_event_interruptible(
+                       usbif->wq,
+                       usbif->waiting_reqs || kthread_should_stop());
+               wait_event_interruptible(
+                       pending_free_wq,
+                       !list_empty(&pending_free) || kthread_should_stop());
+               usbif->waiting_reqs = 0;
+               smp_mb();
 
-                if (usbbk_start_submit_urb(usbif))
-                        usbif->waiting_reqs = 1;
-        }
+               if (usbbk_start_submit_urb(usbif))
+                       usbif->waiting_reqs = 1;
+       }
 
-        usbif->xenusbd = NULL;
-        usbif_put(usbif);
+       usbif->xenusbd = NULL;
+       usbif_put(usbif);
 
-        return 0;
+       return 0;
 }
 
 /*
- * attach the grabbed device to usbif.
+ * attach usbstub device to usbif.
  */
-void usbbk_plug_device(usbif_t *usbif, struct usbstub *stub)
+void usbbk_attach_device(usbif_t *usbif, struct usbstub *stub)
 {
        unsigned long flags;
 
-       spin_lock_irqsave(&usbif->plug_lock, flags);
-       list_add(&stub->plugged_list, &usbif->plugged_devices);
-       spin_unlock_irqrestore(&usbif->plug_lock, flags);
-       stub->plugged = 1;
+       spin_lock_irqsave(&usbif->stub_lock, flags);
+       list_add(&stub->dev_list, &usbif->stub_list);
+       spin_unlock_irqrestore(&usbif->stub_lock, flags);
        stub->usbif = usbif;
 }
 
 /*
- * detach the grabbed device from usbif.
+ * detach usbstub device from usbif.
  */
-void usbbk_unplug_device(usbif_t *usbif, struct usbstub *stub)
+void usbbk_detach_device(usbif_t *usbif, struct usbstub *stub)
 {
        unsigned long flags;
 
        if (stub->addr)
                usbbk_set_address(usbif, stub, stub->addr, 0);
-       spin_lock_irqsave(&usbif->plug_lock, flags);
-       list_del(&stub->plugged_list);
-       spin_unlock_irqrestore(&usbif->plug_lock, flags);
-       stub->plugged = 0;
+       spin_lock_irqsave(&usbif->stub_lock, flags);
+       list_del(&stub->dev_list);
+       spin_unlock_irqrestore(&usbif->stub_lock, flags);
        stub->usbif = NULL;
 }
 
@@ -1023,8 +1086,7 @@
 {
        if (stub->addr)
                usbbk_set_address(usbif, stub, stub->addr, 0);
-       list_del(&stub->plugged_list);
-       stub->plugged = 0;
+       list_del(&stub->dev_list);
        stub->usbif = NULL;
 }
 
@@ -1054,9 +1116,8 @@
        memset(pending_reqs, 0, sizeof(pending_reqs));
        INIT_LIST_HEAD(&pending_free);
 
-       for (i = 0; i < usbif_reqs; i++) {
+       for (i = 0; i < usbif_reqs; i++)
                list_add_tail(&pending_reqs[i].free_list, &pending_free);
-       }
 
        usbback_xenbus_init();
 
diff -r 4ac3e1d6605c -r 3be939975ad6 drivers/xen/usbback/usbback.h
--- a/drivers/xen/usbback/usbback.h     Tue Sep 29 11:23:06 2009 +0100
+++ b/drivers/xen/usbback/usbback.h     Tue Oct 06 15:18:27 2009 +0900
@@ -59,6 +59,7 @@
 #include <xen/gnttab.h>
 #include <xen/driver_util.h>
 #include <xen/interface/xen.h>
+#include <xen/xenbus.h>
 #include <xen/interface/io/usbif.h>
 
 struct usbstub;
@@ -66,89 +67,103 @@
 #define USB_DEV_ADDR_SIZE 128
 
 typedef struct usbif_st {
-       domid_t           domid;
-       unsigned int      handle;
+       domid_t domid;
+       unsigned int handle;
+       int num_ports;
+       enum usb_spec_version usb_ver;
+
        struct xenbus_device *xbdev;
        struct list_head usbif_list;
 
        unsigned int      irq;
 
-       usbif_back_ring_t ring;
-       struct vm_struct *ring_area;
+       usbif_urb_back_ring_t urb_ring;
+       usbif_conn_back_ring_t conn_ring;
+       struct vm_struct *urb_ring_area;
+       struct vm_struct *conn_ring_area;
 
-       spinlock_t ring_lock;
+       spinlock_t urb_ring_lock;
+       spinlock_t conn_ring_lock;
        atomic_t refcnt;
-       grant_handle_t shmem_handle;
-       grant_ref_t shmem_ref;
+
+       grant_handle_t urb_shmem_handle;
+       grant_ref_t urb_shmem_ref;
+       grant_handle_t conn_shmem_handle;
+       grant_ref_t conn_shmem_ref;
+
+       struct xenbus_watch backend_watch;
 
        /* device address lookup table */
+       struct usbstub *addr_table[USB_DEV_ADDR_SIZE];
        spinlock_t addr_lock;
-       struct usbstub *addr_table[USB_DEV_ADDR_SIZE];
 
-       /* plugged device list */
-       unsigned plaggable:1;
-       spinlock_t plug_lock;
-       struct list_head plugged_devices;
+       /* connected device list */
+       struct list_head stub_list;
+       spinlock_t stub_lock;
 
        /* request schedule */
        struct task_struct *xenusbd;
        unsigned int waiting_reqs;
        wait_queue_head_t waiting_to_free;
        wait_queue_head_t wq;
-
 } usbif_t;
 
-struct usbstub_id
-{
+struct vusb_port_id {
        struct list_head id_list;
 
-       char bus_id[BUS_ID_SIZE];
-       int dom_id;
-       int dev_id;
+       char phys_bus[BUS_ID_SIZE];
+       domid_t domid;
+       unsigned int handle;
        int portnum;
+       unsigned is_connected:1;
 };
 
-struct usbstub
-{
-       struct usbstub_id *id;
+struct usbstub {
+       struct kref kref;
+       struct list_head dev_list;
+
+       struct vusb_port_id *portid;
        struct usb_device *udev;
-       struct usb_interface *interface;
        usbif_t *usbif;
-
-       struct list_head grabbed_list;
-
-       unsigned plugged:1;
-       struct list_head plugged_list;
-
        int addr;
 
+       struct list_head submitting_list;
        spinlock_t submitting_lock;
-       struct list_head submitting_list;
 };
 
 usbif_t *usbif_alloc(domid_t domid, unsigned int handle);
 void usbif_disconnect(usbif_t *usbif);
 void usbif_free(usbif_t *usbif);
-int usbif_map(usbif_t *usbif, unsigned long shared_page, unsigned int evtchn);
+int usbif_map(usbif_t *usbif, unsigned long urb_ring_ref,
+               unsigned long conn_ring_ref, unsigned int evtchn);
 
 #define usbif_get(_b) (atomic_inc(&(_b)->refcnt))
 #define usbif_put(_b) \
        do { \
                if (atomic_dec_and_test(&(_b)->refcnt)) \
-               wake_up(&(_b)->waiting_to_free); \
+                       wake_up(&(_b)->waiting_to_free); \
        } while (0)
 
+usbif_t *find_usbif(domid_t domid, unsigned int handle);
 void usbback_xenbus_init(void);
 void usbback_xenbus_exit(void);
-
+struct vusb_port_id *find_portid_by_busid(const char *busid);
+struct vusb_port_id *find_portid(const domid_t domid,
+                                               const unsigned int handle,
+                                               const int portnum);
+int portid_add(const char *busid,
+                                       const domid_t domid,
+                                       const unsigned int handle,
+                                       const int portnum);
+int portid_remove(const domid_t domid,
+                                       const unsigned int handle,
+                                       const int portnum);
 irqreturn_t usbbk_be_int(int irq, void *dev_id, struct pt_regs *regs);
 int usbbk_schedule(void *arg);
 struct usbstub *find_attached_device(usbif_t *usbif, int port);
-struct usbstub *find_grabbed_device(int dom_id, int dev_id, int port);
-usbif_t *find_usbif(int dom_id, int dev_id);
-void usbback_reconfigure(usbif_t *usbif);
-void usbbk_plug_device(usbif_t *usbif, struct usbstub *stub);
-void usbbk_unplug_device(usbif_t *usbif, struct usbstub *stub);
+void usbbk_attach_device(usbif_t *usbif, struct usbstub *stub);
+void usbbk_detach_device(usbif_t *usbif, struct usbstub *stub);
+void usbbk_hotplug_notify(usbif_t *usbif, int portnum, int speed);
 void detach_device_without_lock(usbif_t *usbif, struct usbstub *stub);
 void usbbk_unlink_urbs(struct usbstub *stub);
 
diff -r 4ac3e1d6605c -r 3be939975ad6 drivers/xen/usbback/usbstub.c
--- a/drivers/xen/usbback/usbstub.c     Tue Sep 29 11:23:06 2009 +0100
+++ b/drivers/xen/usbback/usbstub.c     Tue Oct 06 15:18:27 2009 +0900
@@ -45,36 +45,106 @@
 
 #include "usbback.h"
 
-static LIST_HEAD(usbstub_ids);
-static DEFINE_SPINLOCK(usbstub_ids_lock);
-static LIST_HEAD(grabbed_devices);
-static DEFINE_SPINLOCK(grabbed_devices_lock);
+static LIST_HEAD(port_list);
+static DEFINE_SPINLOCK(port_list_lock);
 
-struct usbstub *find_grabbed_device(int dom_id, int dev_id, int portnum)
+struct vusb_port_id *find_portid_by_busid(const char *busid)
 {
-       struct usbstub *stub;
+       struct vusb_port_id *portid;
        int found = 0;
        unsigned long flags;
 
-       spin_lock_irqsave(&grabbed_devices_lock, flags);
-       list_for_each_entry(stub, &grabbed_devices, grabbed_list) {
-               if (stub->id->dom_id == dom_id
-                               && stub->id->dev_id == dev_id
-                               && stub->id->portnum == portnum) {
+       spin_lock_irqsave(&port_list_lock, flags);
+       list_for_each_entry(portid, &port_list, id_list) {
+               if (!(strncmp(portid->phys_bus, busid, BUS_ID_SIZE))) {
                        found = 1;
                        break;
                }
        }
-       spin_unlock_irqrestore(&grabbed_devices_lock, flags);
+       spin_unlock_irqrestore(&port_list_lock, flags);
 
        if (found)
-               return stub;
+               return portid;
 
        return NULL;
 }
 
-static struct usbstub *usbstub_alloc(struct usb_interface *interface,
-                                               struct usbstub_id *stub_id)
+struct vusb_port_id *find_portid(const domid_t domid,
+                                               const unsigned int handle,
+                                               const int portnum)
+{
+       struct vusb_port_id *portid;
+       int found = 0;
+       unsigned long flags;
+
+       spin_lock_irqsave(&port_list_lock, flags);
+       list_for_each_entry(portid, &port_list, id_list) {
+               if ((portid->domid == domid)
+                               && (portid->handle == handle)
+                               && (portid->portnum == portnum)) {
+                               found = 1;
+                               break;
+               }
+       }
+       spin_unlock_irqrestore(&port_list_lock, flags);
+
+       if (found)
+               return portid;
+
+       return NULL;
+}
+
+int portid_add(const char *busid,
+                                       const domid_t domid,
+                                       const unsigned int handle,
+                                       const int portnum)
+{
+       struct vusb_port_id *portid;
+       unsigned long flags;
+
+       portid = kzalloc(sizeof(*portid), GFP_KERNEL);
+       if (!portid)
+               return -ENOMEM;
+
+       portid->domid = domid;
+       portid->handle = handle;
+       portid->portnum = portnum;
+
+       strncpy(portid->phys_bus, busid, BUS_ID_SIZE);
+
+       spin_lock_irqsave(&port_list_lock, flags);
+       list_add(&portid->id_list, &port_list);
+       spin_unlock_irqrestore(&port_list_lock, flags);
+
+       return 0;
+}
+
+int portid_remove(const domid_t domid,
+                                       const unsigned int handle,
+                                       const int portnum)
+{
+       struct vusb_port_id *portid, *tmp;
+       int err = -ENOENT;
+       unsigned long flags;
+
+       spin_lock_irqsave(&port_list_lock, flags);
+       list_for_each_entry_safe(portid, tmp, &port_list, id_list) {
+               if (portid->domid == domid
+                               && portid->handle == handle
+                               && portid->portnum == portnum) {
+                       list_del(&portid->id_list);
+                       kfree(portid);
+
+                       err = 0;
+               }
+       }
+       spin_unlock_irqrestore(&port_list_lock, flags);
+
+       return err;
+}
+
+static struct usbstub *usbstub_alloc(struct usb_device *udev,
+                                               struct vusb_port_id *portid)
 {
        struct usbstub *stub;
 
@@ -83,314 +153,135 @@
                printk(KERN_ERR "no memory for alloc usbstub\n");
                return NULL;
        }
-
-       stub->udev = usb_get_dev(interface_to_usbdev(interface));
-       stub->interface = interface;
-       stub->id = stub_id;
+       kref_init(&stub->kref);
+       stub->udev = usb_get_dev(udev);
+       stub->portid = portid;
        spin_lock_init(&stub->submitting_lock);
        INIT_LIST_HEAD(&stub->submitting_list);
 
        return stub;
 }
 
-static int usbstub_free(struct usbstub *stub)
+static void usbstub_release(struct kref *kref)
 {
-       if (!stub)
-               return -EINVAL;
+       struct usbstub *stub;
+
+       stub = container_of(kref, struct usbstub, kref);
 
        usb_put_dev(stub->udev);
-       stub->interface = NULL;
        stub->udev = NULL;
-       stub->id = NULL;
+       stub->portid = NULL;
        kfree(stub);
-
-       return 0;
 }
 
-static int usbstub_match_one(struct usb_interface *interface,
-               struct usbstub_id *stub_id)
+static inline void usbstub_get(struct usbstub *stub)
 {
-       char *udev_busid = interface->dev.parent->bus_id;
-
-       if (!(strncmp(stub_id->bus_id, udev_busid, BUS_ID_SIZE))) {
-               return 1;
-       }
-
-       return 0;
+       kref_get(&stub->kref);
 }
 
-static struct usbstub_id *usbstub_match(struct usb_interface *interface)
+static inline void usbstub_put(struct usbstub *stub)
 {
-       struct usb_device *udev = interface_to_usbdev(interface);
-       struct usbstub_id *stub_id;
-       unsigned long flags;
-       int found = 0;
+       kref_put(&stub->kref, usbstub_release);
+}
+
+static int usbstub_probe(struct usb_interface *intf,
+               const struct usb_device_id *id)
+{
+       struct usb_device *udev = interface_to_usbdev(intf);
+       char *busid = intf->dev.parent->bus_id;
+       struct vusb_port_id *portid = NULL;
+       struct usbstub *stub = NULL;
+       usbif_t *usbif = NULL;
+       int retval = -ENODEV;
 
        /* hub currently not supported, so skip. */
        if (udev->descriptor.bDeviceClass ==  USB_CLASS_HUB)
-               return NULL;
+               goto out;
 
-       spin_lock_irqsave(&usbstub_ids_lock, flags);
-       list_for_each_entry(stub_id, &usbstub_ids, id_list) {
-               if (usbstub_match_one(interface, stub_id)) {
-                       found = 1;
+       portid = find_portid_by_busid(busid);
+       if (!portid)
+               goto out;
+
+       usbif = find_usbif(portid->domid, portid->handle);
+       if (!usbif)
+               goto out;
+
+       switch (udev->speed) {
+       case USB_SPEED_LOW:
+       case USB_SPEED_FULL:
+               break;
+       case USB_SPEED_HIGH:
+               if (usbif->usb_ver >= USB_VER_USB20)
                        break;
-               }
+               /* fall through */
+       default:
+               goto out;
        }
-       spin_unlock_irqrestore(&usbstub_ids_lock, flags);
 
-       if (found)
-               return stub_id;
-
-       return NULL;
-}
-
-static void add_to_grabbed_devices(struct usbstub *stub)
-{
-       unsigned long flags;
-
-       spin_lock_irqsave(&grabbed_devices_lock, flags);
-       list_add(&stub->grabbed_list, &grabbed_devices);
-       spin_unlock_irqrestore(&grabbed_devices_lock, flags);
-}
-
-static void remove_from_grabbed_devices(struct usbstub *stub)
-{
-       unsigned long flags;
-
-       spin_lock_irqsave(&grabbed_devices_lock, flags);
-       list_del(&stub->grabbed_list);
-       spin_unlock_irqrestore(&grabbed_devices_lock, flags);
-}
-
-static int usbstub_probe(struct usb_interface *interface,
-               const struct usb_device_id *id)
-{
-       struct usbstub_id *stub_id = NULL;
-       struct usbstub *stub = NULL;
-       usbif_t *usbif = NULL;
-       int retval = 0;
-
-       if ((stub_id = usbstub_match(interface))) {
-               stub = usbstub_alloc(interface, stub_id);
+       stub = find_attached_device(usbif, portid->portnum);
+       if (!stub) {
+               /* new connection */
+               stub = usbstub_alloc(udev, portid);
                if (!stub)
                        return -ENOMEM;
+               usbbk_attach_device(usbif, stub);
+               usbbk_hotplug_notify(usbif, portid->portnum, udev->speed);
+       } else {
+               /* maybe already called and connected by other intf */
+               if (strncmp(stub->portid->phys_bus, busid, BUS_ID_SIZE))
+                       goto out; /* invalid call */
+       }
 
-               usb_set_intfdata(interface, stub);
-               add_to_grabbed_devices(stub);
-               usbif = find_usbif(stub_id->dom_id, stub_id->dev_id);
-               if (usbif) {
-                       usbbk_plug_device(usbif, stub);
-                       usbback_reconfigure(usbif);
-               }
+       usbstub_get(stub);
+       usb_set_intfdata(intf, stub);
+       retval = 0;
 
-       } else
-               retval = -ENODEV;
-
+out:
        return retval;
 }
 
-static void usbstub_disconnect(struct usb_interface *interface)
+static void usbstub_disconnect(struct usb_interface *intf)
 {
        struct usbstub *stub
-               = (struct usbstub *) usb_get_intfdata(interface);
+               = (struct usbstub *) usb_get_intfdata(intf);
 
-       usb_set_intfdata(interface, NULL);
+       usb_set_intfdata(intf, NULL);
 
        if (!stub)
                return;
 
        if (stub->usbif) {
-               usbback_reconfigure(stub->usbif);
-               usbbk_unplug_device(stub->usbif, stub);
+               usbbk_hotplug_notify(stub->usbif, stub->portid->portnum, 0);
+               usbbk_detach_device(stub->usbif, stub);
        }
-
        usbbk_unlink_urbs(stub);
-
-       remove_from_grabbed_devices(stub);
-
-       usbstub_free(stub);
-
-       return;
+       usbstub_put(stub);
 }
 
-static inline int str_to_vport(const char *buf,
-                                       char *phys_bus,
-                                       int *dom_id,
-                                       int *dev_id,
-                                       int *port)
-{
-       char *p;
-       int len;
-       int err;
-
-       /* no physical bus */
-       if (!(p = strchr(buf, ':')))
-               return -EINVAL;
-
-       len = p - buf;
-
-       /* bad physical bus */
-       if (len + 1 > BUS_ID_SIZE)
-               return -EINVAL;
-
-       strlcpy(phys_bus, buf, len + 1);
-       err = sscanf(p + 1, "%d:%d:%d", dom_id, dev_id, port);
-       if (err == 3)
-               return 0;
-       else
-               return -EINVAL;
-}
-
-static int usbstub_id_add(const char *bus_id,
-                                       const int dom_id,
-                                       const int dev_id,
-                                       const int portnum)
-{
-       struct usbstub_id *stub_id;
-       unsigned long flags;
-
-       stub_id = kzalloc(sizeof(*stub_id), GFP_KERNEL);
-       if (!stub_id)
-               return -ENOMEM;
-
-       stub_id->dom_id = dom_id;
-       stub_id->dev_id = dev_id;
-       stub_id->portnum = portnum;
-
-       strncpy(stub_id->bus_id, bus_id, BUS_ID_SIZE);
-
-       spin_lock_irqsave(&usbstub_ids_lock, flags);
-       list_add(&stub_id->id_list, &usbstub_ids);
-       spin_unlock_irqrestore(&usbstub_ids_lock, flags);
-
-       return 0;
-}
-
-static int usbstub_id_remove(const char *phys_bus,
-                                       const int dom_id,
-                                       const int dev_id,
-                                       const int portnum)
-{
-       struct usbstub_id *stub_id, *tmp;
-       int err = -ENOENT;
-       unsigned long flags;
-
-       spin_lock_irqsave(&usbstub_ids_lock, flags);
-       list_for_each_entry_safe(stub_id, tmp, &usbstub_ids, id_list) {
-               if (stub_id->dom_id == dom_id
-                               && stub_id->dev_id == dev_id
-                               && stub_id->portnum == portnum) {
-                       list_del(&stub_id->id_list);
-                       kfree(stub_id);
-
-                       err = 0;
-               }
-       }
-       spin_unlock_irqrestore(&usbstub_ids_lock, flags);
-
-       return err;
-}
-
-static ssize_t usbstub_vport_add(struct device_driver *driver,
-               const char *buf, size_t count)
-{
-       int err = 0;
-
-       char bus_id[BUS_ID_SIZE];
-       int dom_id;
-       int dev_id;
-       int portnum;
-
-       err = str_to_vport(buf, &bus_id[0], &dom_id, &dev_id, &portnum);
-       if (err)
-               goto out;
-
-       err = usbstub_id_add(&bus_id[0], dom_id, dev_id, portnum);
-
-out:
-       if (!err)
-               err = count;
-       return err;
-}
-
-DRIVER_ATTR(new_vport, S_IWUSR, NULL, usbstub_vport_add);
-
-static ssize_t usbstub_vport_remove(struct device_driver *driver,
-               const char *buf, size_t count)
-{
-       int err = 0;
-
-       char bus_id[BUS_ID_SIZE];
-       int dom_id;
-       int dev_id;
-       int portnum;
-
-       err = str_to_vport(buf, &bus_id[0], &dom_id, &dev_id, &portnum);
-       if (err)
-               goto out;
-
-       err = usbstub_id_remove(&bus_id[0], dom_id, dev_id, portnum);
-
-out:
-       if (!err)
-               err = count;
-       return err;
-}
-
-DRIVER_ATTR(remove_vport, S_IWUSR, NULL, usbstub_vport_remove);
-
-static ssize_t usbstub_vport_show(struct device_driver *driver,
+static ssize_t usbstub_show_portids(struct device_driver *driver,
                char *buf)
 {
-       struct usbstub_id *stub_id;
+       struct vusb_port_id *portid;
        size_t count = 0;
        unsigned long flags;
 
-       spin_lock_irqsave(&usbstub_ids_lock, flags);
-       list_for_each_entry(stub_id, &usbstub_ids, id_list) {
+       spin_lock_irqsave(&port_list_lock, flags);
+       list_for_each_entry(portid, &port_list, id_list) {
                if (count >= PAGE_SIZE)
                        break;
                count += scnprintf((char *)buf + count, PAGE_SIZE - count,
                                "%s:%d:%d:%d\n",
-                               &stub_id->bus_id[0],
-                               stub_id->dom_id,
-                               stub_id->dev_id,
-                               stub_id->portnum);
+                               &portid->phys_bus[0],
+                               portid->domid,
+                               portid->handle,
+                               portid->portnum);
        }
-       spin_unlock_irqrestore(&usbstub_ids_lock, flags);
+       spin_unlock_irqrestore(&port_list_lock, flags);
 
        return count;
 }
 
-DRIVER_ATTR(vports, S_IRUSR, usbstub_vport_show, NULL);
-
-static ssize_t usbstub_devices_show(struct device_driver *driver,
-               char *buf)
-{
-       struct usbstub *stub;
-       size_t count = 0;
-       unsigned long flags;
-
-       spin_lock_irqsave(&grabbed_devices_lock, flags);
-       list_for_each_entry(stub, &grabbed_devices, grabbed_list) {
-               if (count >= PAGE_SIZE)
-                       break;
-
-               count += scnprintf((char *)buf + count, PAGE_SIZE - count,
-                                       "%u-%s:%u.%u\n",
-                                       stub->udev->bus->busnum,
-                                       stub->udev->devpath,
-                                       
stub->udev->config->desc.bConfigurationValue,
-                                       
stub->interface->cur_altsetting->desc.bInterfaceNumber);
-
-       }
-       spin_unlock_irqrestore(&grabbed_devices_lock, flags);
-
-       return count;
-}
-
-DRIVER_ATTR(grabbed_devices, S_IRUSR, usbstub_devices_show, NULL);
+DRIVER_ATTR(port_ids, S_IRUSR, usbstub_show_portids, NULL);
 
 /* table of devices that matches any usbdevice */
 static struct usb_device_id usbstub_table[] = {
@@ -404,44 +295,31 @@
                .probe = usbstub_probe,
                .disconnect = usbstub_disconnect,
                .id_table = usbstub_table,
+               .no_dynamic_id = 1,
 };
 
 int __init usbstub_init(void)
 {
-       int err;
+       int err;
 
        err = usb_register(&usbback_usb_driver);
-       if (err < 0)
+       if (err < 0) {
+               printk(KERN_ERR "usbback: usb_register failed (error %d)\n", 
err);
                goto out;
-       if (!err)
-               err = driver_create_file(&usbback_usb_driver.driver,
-                               &driver_attr_new_vport);
-       if (!err)
-               err = driver_create_file(&usbback_usb_driver.driver,
-                               &driver_attr_remove_vport);
-       if (!err)
-               err = driver_create_file(&usbback_usb_driver.driver,
-                               &driver_attr_vports);
-       if (!err)
-               err = driver_create_file(&usbback_usb_driver.driver,
-                               &driver_attr_grabbed_devices);
+       }
+
+       err = driver_create_file(&usbback_usb_driver.driver,
+                               &driver_attr_port_ids);
        if (err)
-               usbstub_exit();
+               usb_deregister(&usbback_usb_driver);
 
 out:
        return err;
 }
 
-void usbstub_exit(void)
+void __exit usbstub_exit(void)
 {
        driver_remove_file(&usbback_usb_driver.driver,
-                       &driver_attr_new_vport);
-       driver_remove_file(&usbback_usb_driver.driver,
-                       &driver_attr_remove_vport);
-       driver_remove_file(&usbback_usb_driver.driver,
-                               &driver_attr_vports);
-       driver_remove_file(&usbback_usb_driver.driver,
-                               &driver_attr_grabbed_devices);
-
+                               &driver_attr_port_ids);
        usb_deregister(&usbback_usb_driver);
 }
diff -r 4ac3e1d6605c -r 3be939975ad6 drivers/xen/usbback/xenbus.c
--- a/drivers/xen/usbback/xenbus.c      Tue Sep 29 11:23:06 2009 +0100
+++ b/drivers/xen/usbback/xenbus.c      Tue Oct 06 15:18:27 2009 +0900
@@ -43,29 +43,118 @@
  * DEALINGS IN THE SOFTWARE.
  */
 
-#include <xen/xenbus.h>
 #include "usbback.h"
 
 static int start_xenusbd(usbif_t *usbif)
 {
-        int err = 0;
-        char name[TASK_COMM_LEN];
+       int err = 0;
+       char name[TASK_COMM_LEN];
 
-        snprintf(name, TASK_COMM_LEN, "usbback.%d.%d", usbif->domid, 
usbif->handle);
-        usbif->xenusbd = kthread_run(usbbk_schedule, usbif, name);
-        if (IS_ERR(usbif->xenusbd)) {
-                err = PTR_ERR(usbif->xenusbd);
-                usbif->xenusbd = NULL;
-                xenbus_dev_error(usbif->xbdev, err, "start xenusbd");
-        }
-        return err;
+       snprintf(name, TASK_COMM_LEN, "usbback.%d.%d", usbif->domid,
+                       usbif->handle);
+       usbif->xenusbd = kthread_run(usbbk_schedule, usbif, name);
+       if (IS_ERR(usbif->xenusbd)) {
+               err = PTR_ERR(usbif->xenusbd);
+               usbif->xenusbd = NULL;
+               xenbus_dev_error(usbif->xbdev, err, "start xenusbd");
+       }
+
+       return err;
+}
+
+static void backend_changed(struct xenbus_watch *watch,
+                       const char **vec, unsigned int len)
+{
+       struct xenbus_transaction xbt;
+       int err;
+       int i;
+       char node[8];
+       char *busid;
+       struct vusb_port_id *portid = NULL;
+
+       usbif_t *usbif = container_of(watch, usbif_t, backend_watch);
+       struct xenbus_device *dev = usbif->xbdev;
+
+again:
+       err = xenbus_transaction_start(&xbt);
+       if (err) {
+               xenbus_dev_fatal(dev, err, "starting transaction");
+               return;
+       }
+
+       for (i = 1; i <= usbif->num_ports; i++) {
+               sprintf(node, "port/%d", i);
+               busid = xenbus_read(xbt, dev->nodename, node, NULL);
+               if (IS_ERR(busid)) {
+                       err = PTR_ERR(busid);
+                       xenbus_dev_fatal(dev, err, "reading port/%d", i);
+                       goto abort;
+               }
+
+               /*
+                * remove portid, if the port is not connected,
+                */
+               if (strlen(busid) == 0) {
+                       portid = find_portid(usbif->domid, usbif->handle, i);
+                       if (portid) {
+                               if (portid->is_connected)
+                                       xenbus_dev_fatal(dev, err,
+                                               "can't remove port/%d, unbind 
first", i);
+                               else
+                                       portid_remove(usbif->domid, 
usbif->handle, i);
+                       }
+                       continue; /* never configured, ignore */
+               }
+
+               /*
+                * add portid,
+                * if the port is not configured and not used from other usbif.
+                */
+               portid = find_portid(usbif->domid, usbif->handle, i);
+               if (portid) {
+                       if ((strncmp(portid->phys_bus, busid, BUS_ID_SIZE)))
+                               xenbus_dev_fatal(dev, err,
+                                       "can't add port/%d, remove first", i);
+                       else
+                               continue; /* already configured, ignore */
+               } else {
+                       if (find_portid_by_busid(busid))
+                               xenbus_dev_fatal(dev, err,
+                                       "can't add port/%d, busid already 
used", i);
+                       else
+                               portid_add(busid, usbif->domid, usbif->handle, 
i);
+               }
+       }
+
+       err = xenbus_transaction_end(xbt, 0);
+       if (err == -EAGAIN)
+               goto again;
+       if (err)
+               xenbus_dev_fatal(dev, err, "completing transaction");
+
+       return;
+
+abort:
+       xenbus_transaction_end(xbt, 1);
+
+       return;
 }
 
 static int usbback_remove(struct xenbus_device *dev)
 {
        usbif_t *usbif = dev->dev.driver_data;
+       int i;
+
+       if (usbif->backend_watch.node) {
+               unregister_xenbus_watch(&usbif->backend_watch);
+               kfree(usbif->backend_watch.node);
+               usbif->backend_watch.node = NULL;
+       }
 
        if (usbif) {
+               /* remove all ports */
+               for (i = 1; i <= usbif->num_ports; i++)
+                       portid_remove(usbif->domid, usbif->handle, i);
                usbif_disconnect(usbif);
                usbif_free(usbif);;
        }
@@ -79,12 +168,14 @@
 {
        usbif_t *usbif;
        unsigned int handle;
+       int num_ports;
+       int usb_ver;
        int err;
 
        if (usb_disabled())
                return -ENODEV;
 
-       handle = simple_strtoul(strrchr(dev->otherend,'/')+1, NULL, 0);
+       handle = simple_strtoul(strrchr(dev->otherend, '/') + 1, NULL, 0);
        usbif = usbif_alloc(dev->otherend_id, handle);
        if (!usbif) {
                xenbus_dev_fatal(dev, -ENOMEM, "allocating backend interface");
@@ -93,6 +184,34 @@
        usbif->xbdev = dev;
        dev->dev.driver_data = usbif;
 
+       err = xenbus_scanf(XBT_NIL, dev->nodename,
+                               "num-ports", "%d", &num_ports);
+       if (err != 1) {
+               xenbus_dev_fatal(dev, err, "reading num-ports");
+               goto fail;
+       }
+       if (num_ports < 1 || num_ports > USB_MAXCHILDREN) {
+               xenbus_dev_fatal(dev, err, "invalid num-ports");
+               goto fail;
+       }
+       usbif->num_ports = num_ports;
+
+       err = xenbus_scanf(XBT_NIL, dev->nodename,
+                               "usb-ver", "%d", &usb_ver);
+       if (err != 1) {
+               xenbus_dev_fatal(dev, err, "reading usb-ver");
+               goto fail;
+       }
+       switch (usb_ver) {
+       case USB_VER_USB11:
+       case USB_VER_USB20:
+               usbif->usb_ver = usb_ver;
+               break;
+       default:
+               xenbus_dev_fatal(dev, err, "invalid usb-ver");
+               goto fail;
+       }
+
        err = xenbus_switch_state(dev, XenbusStateInitWait);
        if (err)
                goto fail;
@@ -104,15 +223,17 @@
        return err;
 }
 
-static int connect_ring(usbif_t *usbif)
+static int connect_rings(usbif_t *usbif)
 {
        struct xenbus_device *dev = usbif->xbdev;
-       unsigned long ring_ref;
+       unsigned long urb_ring_ref;
+       unsigned long conn_ring_ref;
        unsigned int evtchn;
        int err;
 
        err = xenbus_gather(XBT_NIL, dev->otherend,
-                           "ring-ref", "%lu", &ring_ref,
+                           "urb-ring-ref", "%lu", &urb_ring_ref,
+                           "conn-ring-ref", "%lu", &conn_ring_ref,
                            "event-channel", "%u", &evtchn, NULL);
        if (err) {
                xenbus_dev_fatal(dev, err,
@@ -121,81 +242,32 @@
                return err;
        }
 
-       printk("usbback: ring-ref %ld, event-channel %d\n",
-              ring_ref, evtchn);
+       printk("usbback: urb-ring-ref %ld, conn-ring-ref %ld, event-channel 
%d\n",
+              urb_ring_ref, conn_ring_ref, evtchn);
 
-       err = usbif_map(usbif, ring_ref, evtchn);
+       err = usbif_map(usbif, urb_ring_ref, conn_ring_ref, evtchn);
        if (err) {
-               xenbus_dev_fatal(dev, err, "mapping ring-ref %lu port %u",
-                                ring_ref, evtchn);
+               xenbus_dev_fatal(dev, err,
+                               "mapping urb-ring-ref %lu conn-ring-ref %lu 
port %u",
+                               urb_ring_ref, conn_ring_ref, evtchn);
                return err;
        }
 
        return 0;
 }
 
-void usbback_do_hotplug(usbif_t *usbif)
-{
-       struct xenbus_transaction xbt;
-       struct xenbus_device *dev = usbif->xbdev;
-       struct usbstub *stub = NULL;
-       int err;
-       char port_str[8];
-       int i;
-       int num_ports;
-       int state;
-
-again:
-               err = xenbus_transaction_start(&xbt);
-               if (err) {
-                       xenbus_dev_fatal(dev, err, "starting transaction");
-                       return;
-               }
-
-               err = xenbus_scanf(xbt, dev->nodename,
-                                       "num-ports", "%d", &num_ports);
-
-               for (i = 1; i <= num_ports; i++) {
-                       stub = find_attached_device(usbif, i);
-                       if (stub)
-                               state = stub->udev->speed;
-                       else
-                               state = 0;
-                       sprintf(port_str, "port-%d", i);
-                       err = xenbus_printf(xbt, dev->nodename, port_str, "%d", 
state);
-                       if (err) {
-                               xenbus_dev_fatal(dev, err, "writing port-%d 
state", i);
-                               goto abort;
-                       }
-               }
-
-               err = xenbus_transaction_end(xbt, 0);
-               if (err == -EAGAIN)
-                       goto again;
-               if (err)
-                       xenbus_dev_fatal(dev, err, "completing transaction");
-
-               return;
-
-abort:
-               xenbus_transaction_end(xbt, 1);
-}
-
-void usbback_reconfigure(usbif_t *usbif)
-{
-       struct xenbus_device *dev = usbif->xbdev;
-
-       if (dev->state == XenbusStateConnected)
-               xenbus_switch_state(dev, XenbusStateReconfiguring);
-}
-
-void frontend_changed(struct xenbus_device *dev,
+static void frontend_changed(struct xenbus_device *dev,
                                     enum xenbus_state frontend_state)
 {
        usbif_t *usbif = dev->dev.driver_data;
        int err;
 
        switch (frontend_state) {
+       case XenbusStateInitialised:
+       case XenbusStateReconfiguring:
+       case XenbusStateReconfigured:
+               break;
+
        case XenbusStateInitialising:
                if (dev->state == XenbusStateClosed) {
                        printk("%s: %s: prepare for reconnect\n",
@@ -204,17 +276,18 @@
                }
                break;
 
-       case XenbusStateInitialised:
-               err = connect_ring(usbif);
+       case XenbusStateConnected:
+               if (dev->state == XenbusStateConnected)
+                       break;
+               err = connect_rings(usbif);
                if (err)
                        break;
-               start_xenusbd(usbif);
-               usbback_do_hotplug(usbif);
-               xenbus_switch_state(dev, XenbusStateConnected);
-               break;
-
-       case XenbusStateConnected:
-               if (dev->state == XenbusStateConnected)
+               err = start_xenusbd(usbif);
+               if (err)
+                       break;
+               err = xenbus_watch_path2(dev, dev->nodename, "port",
+                                       &usbif->backend_watch, backend_changed);
+               if (err)
                        break;
                xenbus_switch_state(dev, XenbusStateConnected);
                break;
@@ -226,13 +299,9 @@
 
        case XenbusStateClosed:
                xenbus_switch_state(dev, XenbusStateClosed);
-               break;
-
-       case XenbusStateReconfiguring:
-               usbback_do_hotplug(usbif);
-               xenbus_switch_state(dev, XenbusStateReconfigured);
-               break;
-
+               if (xenbus_dev_is_online(dev))
+                       break;
+               /* fall through if not online */
        case XenbusStateUnknown:
                device_unregister(&dev->dev);
                break;
_______________________________________________
Xen-devel mailing list
Xen-devel@xxxxxxxxxxxxxxxxxxx
http://lists.xensource.com/xen-devel

 


Rackspace

Lists.xenproject.org is hosted with RackSpace, monitoring our
servers 24x7x365 and backed by RackSpace's Fanatical Support®.