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

[Xen-changelog] [linux-2.6.18-xen] PVUSB: Fixes and updates



# HG changeset patch
# User Keir Fraser <keir.fraser@xxxxxxxxxx>
# Date 1254901320 -3600
# Node ID 498ac445a2a9bb3e8e01f1bca46fc22e49ad23cb
# Parent  7d57b5843b6587d2f220db0e43cb20b85de9baf7
PVUSB: Fixes and updates

- xenbus state flow changed.
  Whole of the flow is changed to be like netback/netfront.
  Reconfiguring/Reconfiguring are removed.

- New RING for hotplug notification added.

- USBIF_MAX_SEGMENTS_PER_REQUEST value is changed (10) to (16).
  According to this change, RING_SIZE is decreased from 32 to 16.
  This affects the performance. My flash drive's read throughput
  was dropped from 29MB/s to 18MB/s in the linux environment.
  However, Windows guest send urb with 64kB buffer(64KB = 4kB * 16).
  This is required.

- New port-setting interface
  xenbus_watch_path2 is added to usbback, port-setting interface
  is moved from sysfs to xenstore.
  Now, the port-rule is directly written to xenstore entry.
  Example.
  # xenstore-write /local/domain/0/backend/vusb/1/0/port/1 "2-1"
    (adding physical bus 2-1 to vusb-1-0 port 1)

- urb dequeue function completed.
  usbfront send unlink-request to usbback, and can cancel the urb
  that is submitted in the backend.

- New USB Spec version (USB1.1/USB2.0) selection support.
  usbfront can act as both USB1.1 and USB2.0 virtual host controller
  according to the xenstore entry key "usb-ver".

- experimental bus_suspend/bus_resume added to usbfront.

- various cleanups, bugfix, refactoring and codestyle-fix.

Signed-off-by: Noboru Iwamatsu <n_iwamatsu@xxxxxxxxxxxxxx>
---
 drivers/xen/usbback/interface.c     |  135 ++++++---
 drivers/xen/usbback/usbback.c       |  227 ++++++++++------
 drivers/xen/usbback/usbback.h       |   89 +++---
 drivers/xen/usbback/usbstub.c       |  498 +++++++++++++-----------------------
 drivers/xen/usbback/xenbus.c        |  257 +++++++++++-------
 drivers/xen/usbfront/usbfront-dbg.c |    5 
 drivers/xen/usbfront/usbfront-hcd.c |  130 ++-------
 drivers/xen/usbfront/usbfront-hub.c |  131 +++------
 drivers/xen/usbfront/usbfront-q.c   |  279 ++++++++++++++------
 drivers/xen/usbfront/usbfront.h     |   97 +++----
 drivers/xen/usbfront/xenbus.c       |  289 ++++++++++++--------
 include/xen/interface/io/usbif.h    |   46 ++-
 12 files changed, 1174 insertions(+), 1009 deletions(-)

diff -r 7d57b5843b65 -r 498ac445a2a9 drivers/xen/usbback/interface.c
--- a/drivers/xen/usbback/interface.c   Wed Oct 07 07:33:40 2009 +0100
+++ b/drivers/xen/usbback/interface.c   Wed Oct 07 08:42:00 2009 +0100
@@ -48,7 +48,7 @@ static LIST_HEAD(usbif_list);
 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 @@ usbif_t *find_usbif(int dom_id, int dev_
 
        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_t *usbif_alloc(domid_t domid, unsi
 
        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 @@ usbif_t *usbif_alloc(domid_t domid, unsi
        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();
-}
-
-int usbif_map(usbif_t *usbif, unsigned long shared_page, unsigned int evtchn)
-{
-       int err;
-       usbif_sring_t *sring;
+
+       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 urb_ring_ref,
+               unsigned long conn_ring_ref, unsigned int evtchn)
+{
+       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;
-
-       err = map_frontend_page(usbif, shared_page);
-       if (err) {
-               free_vm_area(usbif->ring_area);
+       if ((usbif->urb_ring_area = alloc_vm_area(PAGE_SIZE)) == NULL)
                return err;
-       }
-
-       sring = (usbif_sring_t *) usbif->ring_area->addr;
-       BACK_RING_INIT(&usbif->ring, sring, PAGE_SIZE);
+       if ((usbif->conn_ring_area = alloc_vm_area(PAGE_SIZE)) == NULL)
+               goto fail_alloc;
+
+       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 @@ void usbif_disconnect(usbif_t *usbif)
                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 @@ void usbif_disconnect(usbif_t *usbif)
                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 7d57b5843b65 -r 498ac445a2a9 drivers/xen/usbback/usbback.c
--- a/drivers/xen/usbback/usbback.c     Wed Oct 07 07:33:40 2009 +0100
+++ b/drivers/xen/usbback/usbback.c     Wed Oct 07 08:42:00 2009 +0100
@@ -107,7 +107,7 @@ static inline unsigned long vaddr(pendin
 #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 void copy_pages_to_buff(void *buf
        }
 }
 
-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 @@ static void usbbk_do_response(pending_re
                                        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++;
-       barrier();
-       RING_PUSH_RESPONSES_AND_CHECK_NOTIFY(&usbif->ring, notify);
-       spin_unlock_irqrestore(&usbif->ring_lock, flags);
+       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->urb_ring, notify);
+       spin_unlock_irqrestore(&usbif->urb_ring_lock, flags);
 
        if (notify)
                notify_remote_via_irq(usbif->irq);
@@ -346,7 +346,7 @@ static void usbbk_urb_complete(struct ur
 }
 
 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 @@ fail:
        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 @@ struct usbstub *find_attached_device(usb
        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 @@ struct usbstub *find_attached_device(usb
        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 @@ fail_response:
 }
 
 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 @@ static void dispatch_request_to_pending_
 
        barrier();
 
-       /*
-        * TODO:
-        * receive unlink request and cancel the urb in backend
-        */
-#if 0
-       if (unlikely(usb_pipeunlink(req->pipe))) {
-
-       }
-#endif
-
        usbif_get(usbif);
+
+       /* unlink request */
+       if (unlikely(usbif_pipeunlink(req->pipe))) {
+               process_unlink_req(usbif, req, pending_req);
+               return;
+       }
 
        if (usb_pipecontrol(req->pipe)) {
                if (check_and_submit_special_ctrlreq(usbif, req, pending_req))
@@ -927,18 +963,18 @@ fail_response:
 
 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 @@ static int usbbk_start_submit_urb(usbif_
                        break;
                }
 
-               ring_req = RING_GET_REQUEST(usb_ring, rc);
-               usb_ring->req_cons = ++rc;
-
-               dispatch_request_to_pending_reqs(usbif, ring_req,
+               req = RING_GET_REQUEST(urb_ring, rc);
+               urb_ring->req_cons = ++rc;
+
+               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_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();
-
-                if (usbbk_start_submit_urb(usbif))
-                        usbif->waiting_reqs = 1;
-        }
-
-        usbif->xenusbd = NULL;
-        usbif_put(usbif);
-
-        return 0;
+       usbif_t *usbif = (usbif_t *) arg;
+
+       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();
+
+               if (usbbk_start_submit_urb(usbif))
+                       usbif->waiting_reqs = 1;
+       }
+
+       usbif->xenusbd = NULL;
+       usbif_put(usbif);
+
+       return 0;
 }
 
 /*
- * attach the grabbed device to usbif.
+ * attach usbstub device to usbif.
  */
-void usbbk_plug_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;
+void usbbk_attach_device(usbif_t *usbif, struct usbstub *stub)
+{
+       unsigned long flags;
+
+       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 @@ void detach_device_without_lock(usbif_t 
 {
        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 @@ static int __init usbback_init(void)
        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 7d57b5843b65 -r 498ac445a2a9 drivers/xen/usbback/usbback.h
--- a/drivers/xen/usbback/usbback.h     Wed Oct 07 07:33:40 2009 +0100
+++ b/drivers/xen/usbback/usbback.h     Wed Oct 07 08:42:00 2009 +0100
@@ -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 @@ struct usbstub;
 #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 7d57b5843b65 -r 498ac445a2a9 drivers/xen/usbback/usbstub.c
--- a/drivers/xen/usbback/usbstub.c     Wed Oct 07 07:33:40 2009 +0100
+++ b/drivers/xen/usbback/usbstub.c     Wed Oct 07 08:42:00 2009 +0100
@@ -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);
-
-struct usbstub *find_grabbed_device(int dom_id, int dev_id, int portnum)
-{
-       struct usbstub *stub;
+static LIST_HEAD(port_list);
+static DEFINE_SPINLOCK(port_list_lock);
+
+struct vusb_port_id *find_portid_by_busid(const char *busid)
+{
+       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 @@ static struct usbstub *usbstub_alloc(str
                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)
-{
-       if (!stub)
-               return -EINVAL;
+static void usbstub_release(struct kref *kref)
+{
+       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)
-{
-       char *udev_busid = interface->dev.parent->bus_id;
-
-       if (!(strncmp(stub_id->bus_id, udev_busid, BUS_ID_SIZE))) {
-               return 1;
-       }
-
-       return 0;
-}
-
-static struct usbstub_id *usbstub_match(struct usb_interface *interface)
-{
-       struct usb_device *udev = interface_to_usbdev(interface);
-       struct usbstub_id *stub_id;
-       unsigned long flags;
-       int found = 0;
+}
+
+static inline void usbstub_get(struct usbstub *stub)
+{
+       kref_get(&stub->kref);
+}
+
+static inline void usbstub_put(struct usbstub *stub)
+{
+       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;
-
-       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;
+               goto out;
+
+       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;
-               }
-       }
-       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);
+               /* fall through */
+       default:
+               goto out;
+       }
+
+       stub = find_attached_device(usbif, portid->portnum);
+       if (!stub) {
+               /* new connection */
+               stub = usbstub_alloc(udev, portid);
                if (!stub)
                        return -ENOMEM;
-
-               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);
-               }
-
-       } else
-               retval = -ENODEV;
-
+               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 */
+       }
+
+       usbstub_get(stub);
+       usb_set_intfdata(intf, stub);
+       retval = 0;
+
+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);
-
-       usb_set_intfdata(interface, NULL);
+               = (struct usbstub *) usb_get_intfdata(intf);
+
+       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;
-}
-
-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,
+       usbstub_put(stub);
+}
+
+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);
-       }
-       spin_unlock_irqrestore(&usbstub_ids_lock, flags);
+                               &portid->phys_bus[0],
+                               portid->domid,
+                               portid->handle,
+                               portid->portnum);
+       }
+       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 @@ static struct usb_driver usbback_usb_dri
                .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)
-               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);
+       if (err < 0) {
+               printk(KERN_ERR "usbback: usb_register failed (error %d)\n", 
err);
+               goto out;
+       }
+
+       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 7d57b5843b65 -r 498ac445a2a9 drivers/xen/usbback/xenbus.c
--- a/drivers/xen/usbback/xenbus.c      Wed Oct 07 07:33:40 2009 +0100
+++ b/drivers/xen/usbback/xenbus.c      Wed Oct 07 08:42:00 2009 +0100
@@ -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];
-
-        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;
+       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;
+}
+
+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 @@ static int usbback_probe(struct xenbus_d
 {
        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 @@ static int usbback_probe(struct xenbus_d
        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 @@ fail:
        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 @@ static int connect_ring(usbif_t *usbif)
                return err;
        }
 
-       printk("usbback: ring-ref %ld, event-channel %d\n",
-              ring_ref, evtchn);
-
-       err = usbif_map(usbif, 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, 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 @@ void frontend_changed(struct xenbus_devi
                }
                break;
 
-       case XenbusStateInitialised:
-               err = connect_ring(usbif);
-               if (err)
-                       break;
-               start_xenusbd(usbif);
-               usbback_do_hotplug(usbif);
-               xenbus_switch_state(dev, XenbusStateConnected);
-               break;
-
        case XenbusStateConnected:
                if (dev->state == XenbusStateConnected)
+                       break;
+               err = connect_rings(usbif);
+               if (err)
+                       break;
+               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 @@ void frontend_changed(struct xenbus_devi
 
        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;
diff -r 7d57b5843b65 -r 498ac445a2a9 drivers/xen/usbfront/usbfront-dbg.c
--- a/drivers/xen/usbfront/usbfront-dbg.c       Wed Oct 07 07:33:40 2009 +0100
+++ b/drivers/xen/usbfront/usbfront-dbg.c       Wed Oct 07 08:42:00 2009 +0100
@@ -60,7 +60,7 @@ static ssize_t show_statistics(struct cl
 
        spin_lock_irqsave(&info->lock, flags);
 
-       temp = scnprintf (next, size,
+       temp = scnprintf(next, size,
                        "bus %s, device %s\n"
                        "%s\n"
                        "xenhcd, hcd state %d\n",
@@ -74,7 +74,8 @@ static ssize_t show_statistics(struct cl
 #ifdef XENHCD_STATS
        temp = scnprintf(next, size,
                "complete %ld unlink %ld ring_full %ld\n",
-               info->stats.complete, info->stats.unlink, 
info->stats.ring_full);
+               info->stats.complete, info->stats.unlink,
+               info->stats.ring_full);
        size -= temp;
        next += temp;
 #endif
diff -r 7d57b5843b65 -r 498ac445a2a9 drivers/xen/usbfront/usbfront-hcd.c
--- a/drivers/xen/usbfront/usbfront-hcd.c       Wed Oct 07 07:33:40 2009 +0100
+++ b/drivers/xen/usbfront/usbfront-hcd.c       Wed Oct 07 08:42:00 2009 +0100
@@ -54,7 +54,7 @@ static void xenhcd_watchdog(unsigned lon
        unsigned long flags;
 
        spin_lock_irqsave(&info->lock, flags);
-       if (HC_IS_RUNNING(info_to_hcd(info)->state)) {
+       if (likely(HC_IS_RUNNING(info_to_hcd(info)->state))) {
                timer_action_done(info, TIMER_RING_WATCHDOG);
                xenhcd_giveback_unlinked_urbs(info);
                xenhcd_kick_pending_urbs(info);
@@ -70,9 +70,10 @@ static int xenhcd_setup(struct usb_hcd *
        struct usbfront_info *info = hcd_to_info(hcd);
 
        spin_lock_init(&info->lock);
-       INIT_LIST_HEAD(&info->pending_urbs);
-       INIT_LIST_HEAD(&info->inprogress_urbs);
-       INIT_LIST_HEAD(&info->unlinked_urbs);
+       INIT_LIST_HEAD(&info->pending_submit_list);
+       INIT_LIST_HEAD(&info->pending_unlink_list);
+       INIT_LIST_HEAD(&info->in_progress_list);
+       INIT_LIST_HEAD(&info->giveback_waiting_list);
        init_timer(&info->watchdog);
        info->watchdog.function = xenhcd_watchdog;
        info->watchdog.data = (unsigned long) info;
@@ -101,68 +102,12 @@ static void xenhcd_stop(struct usb_hcd *
        del_timer_sync(&info->watchdog);
        remove_debug_file(info);
        spin_lock_irq(&info->lock);
-       /*
-        * TODO: port power off, cancel all urbs.
-        */
-
-       if (HC_IS_RUNNING(hcd->state))
-               hcd->state = HC_STATE_HALT;
+       /* cancel all urbs */
+       hcd->state = HC_STATE_HALT;
+       xenhcd_cancel_all_enqueued_urbs(info);
+       xenhcd_giveback_unlinked_urbs(info);
        spin_unlock_irq(&info->lock);
 }
-
-/*
- * TODO: incomplete suspend/resume functions!
- */
-#if 0
-#ifdef CONFIG_PM
-/*
- * suspend running HC
- */
-static int xenhcd_suspend(struct usb_hcd *hcd, pm_message_t message)
-{
-       struct usbfront_info *info = hcd_to_info(hcd);
-       unsigned long flags;
-       int ret = 0;
-
-       spin_lock_irqsave(&info->lock, flags);
-       if (hcd->state != HC_STATE_SUSPENDED) {
-               ret = -EINVAL;
-               goto done;
-       }
-
-       /*
-        * TODO:
-        *      canceling all transfer, clear all hc queue,
-        *      stop kthread,
-        */
-
-       clear_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags);
-done:
-       spin_unlock_irqrestore(&info->lock, flags);
-
-       return ret;
-}
-
-/*
- * resume HC
- */
-static int xenhcd_resume(struct usb_hcd *hcd)
-{
-       struct usbfront_info *info = hcd_to_info(hcd);
-       int ret = -EINVAL;
-
-       set_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags);
-
-       /*
-        * TODO:
-        *      re-init HC.
-        *      resume all roothub ports.
-        */
-
-       return ret;
-}
-#endif
-#endif
 
 /*
  * called as .urb_enqueue()
@@ -197,11 +142,6 @@ done:
 
 /*
  * called as .urb_dequeue()
- *
- * just mark the urb as unlinked
- * if the urb is in pending_urbs, move to unlinked_urbs
- * TODO:
- *     canceling the urb transfer in backend
  */
 static int xenhcd_urb_dequeue(struct usb_hcd *hcd,
                                    struct urb *urb)
@@ -234,46 +174,54 @@ static int xenhcd_get_frame(struct usb_h
        return 0;
 }
 
-/*
- * TODO:
- * suspend/resume whole hcd and roothub
- */
 static const char hcd_name[] = "xen_hcd";
 
-struct hc_driver usbfront_hc_driver = {
+struct hc_driver xen_usb20_hc_driver = {
        .description = hcd_name,
-       .product_desc = DRIVER_DESC,
+       .product_desc = "Xen USB2.0 Virtual Host Controller",
        .hcd_priv_size = sizeof(struct usbfront_info),
        .flags = HCD_USB2,
 
-       /*
-        * basic HC lifecycle operations
-        */
+       /* basic HC lifecycle operations */
        .reset = xenhcd_setup,
        .start = xenhcd_run,
        .stop = xenhcd_stop,
-#if 0
-#ifdef CONFIG_PM
-       .suspend = xenhcd_suspend,
-       .resume = xenhcd_resume,
-#endif
-#endif
-       /*
-        * managing urb I/O
-        */
+
+       /* managing urb I/O */
        .urb_enqueue = xenhcd_urb_enqueue,
        .urb_dequeue = xenhcd_urb_dequeue,
        .get_frame_number = xenhcd_get_frame,
 
-       /*
-        * root hub operations
-        */
+       /* root hub operations */
        .hub_status_data = xenhcd_hub_status_data,
        .hub_control = xenhcd_hub_control,
-#if 0
 #ifdef CONFIG_PM
        .bus_suspend = xenhcd_bus_suspend,
        .bus_resume = xenhcd_bus_resume,
 #endif
+};
+
+struct hc_driver xen_usb11_hc_driver = {
+       .description = hcd_name,
+       .product_desc = "Xen USB1.1 Virtual Host Controller",
+       .hcd_priv_size = sizeof(struct usbfront_info),
+       .flags = HCD_USB11,
+
+       /* basic HC lifecycle operations */
+       .reset = xenhcd_setup,
+       .start = xenhcd_run,
+       .stop = xenhcd_stop,
+
+       /* managing urb I/O */
+       .urb_enqueue = xenhcd_urb_enqueue,
+       .urb_dequeue = xenhcd_urb_dequeue,
+       .get_frame_number = xenhcd_get_frame,
+
+       /* root hub operations */
+       .hub_status_data = xenhcd_hub_status_data,
+       .hub_control = xenhcd_hub_control,
+#ifdef CONFIG_PM
+       .bus_suspend = xenhcd_bus_suspend,
+       .bus_resume = xenhcd_bus_resume,
 #endif
 };
diff -r 7d57b5843b65 -r 498ac445a2a9 drivers/xen/usbfront/usbfront-hub.c
--- a/drivers/xen/usbfront/usbfront-hub.c       Wed Oct 07 07:33:40 2009 +0100
+++ b/drivers/xen/usbfront/usbfront-hub.c       Wed Oct 07 08:42:00 2009 +0100
@@ -50,15 +50,16 @@ void set_connect_state(struct usbfront_i
 {
        int port;
 
-       port = portnum -1;
+       port = portnum - 1;
        if (info->ports[port].status & USB_PORT_STAT_POWER) {
                switch (info->devices[port].speed) {
                case USB_SPEED_UNKNOWN:
-                       info->ports[port].status &= ~(USB_PORT_STAT_CONNECTION |
-                                                       USB_PORT_STAT_ENABLE |
-                                                       USB_PORT_STAT_LOW_SPEED 
|
-                                                       
USB_PORT_STAT_HIGH_SPEED |
-                                                       USB_PORT_STAT_SUSPEND);
+                       info->ports[port].status &=
+                               ~(USB_PORT_STAT_CONNECTION |
+                                       USB_PORT_STAT_ENABLE |
+                                       USB_PORT_STAT_LOW_SPEED |
+                                       USB_PORT_STAT_HIGH_SPEED |
+                                       USB_PORT_STAT_SUSPEND);
                        break;
                case USB_SPEED_LOW:
                        info->ports[port].status |= USB_PORT_STAT_CONNECTION;
@@ -85,6 +86,9 @@ void rhport_connect(struct usbfront_info
                                int portnum, enum usb_device_speed speed)
 {
        int port;
+
+       if (portnum < 1 || portnum > info->rh_numports)
+               return; /* invalid port number */
 
        port = portnum - 1;
        if (info->devices[port].speed != speed) {
@@ -105,30 +109,6 @@ void rhport_connect(struct usbfront_info
 
                set_connect_state(info, portnum);
        }
-}
-
-void rhport_disconnect(struct usbfront_info *info, int portnum)
-{
-       rhport_connect(info, portnum, USB_SPEED_UNKNOWN);
-}
-
-void xenhcd_rhport_state_change(struct usbfront_info *info,
-                               int portnum, enum usb_device_speed speed)
-{
-       int changed = 0;
-       unsigned long flags;
-
-       if (portnum < 1 || portnum > info->rh_numports)
-               return; /* invalid port number */
-
-       spin_lock_irqsave(&info->lock, flags);
-       rhport_connect(info, portnum, speed);
-       if (info->ports[portnum-1].c_connection)
-               changed = 1;
-       spin_unlock_irqrestore(&info->lock, flags);
-
-       if (changed)
-               usb_hcd_poll_rh_status(info_to_hcd(info));
 }
 
 /*
@@ -214,7 +194,7 @@ void rhport_reset(struct usbfront_info *
 {
        int port;
 
-       port = portnum -1;
+       port = portnum - 1;
        info->ports[port].status &= ~(USB_PORT_STAT_ENABLE
                                        | USB_PORT_STAT_LOW_SPEED
                                        | USB_PORT_STAT_HIGH_SPEED);
@@ -227,56 +207,50 @@ void rhport_reset(struct usbfront_info *
        info->ports[port].timeout = jiffies + msecs_to_jiffies(10);
 }
 
-#if 0
 #ifdef CONFIG_PM
 static int xenhcd_bus_suspend(struct usb_hcd *hcd)
 {
        struct usbfront_info *info = hcd_to_info(hcd);
+       int ret = 0;
        int i, ports;
 
        ports = info->rh_numports;
 
        spin_lock_irq(&info->lock);
-
-       if (HC_IS_RUNNING(hcd->state)) {
-               /*
-                * TODO:
-                * clean queue,
-                * stop all transfers,
-                * ...
-                */
-               hcd->state = HC_STATE_QUIESCING;
-       }
-
-       /* suspend any active ports*/
-       for (i = 1; i <= ports; i++) {
-               rhport_suspend(info, i);
-       }
+       if (!test_bit(HCD_FLAG_HW_ACCESSIBLE, &info->flags))
+               ret = -ESHUTDOWN;
+       else if (!info->dead) {
+               /* suspend any active ports*/
+               for (i = 1; i <= ports; i++)
+                       rhport_suspend(info, i);
+       }
+       spin_unlock_irq(&info->lock);
 
        del_timer_sync(&info->watchdog);
 
+       return ret;
+}
+
+static int xenhcd_bus_resume(struct usb_hcd *hcd)
+{
+       struct usbfront_info *info = hcd_to_info(hcd);
+       int ret = 0;
+       int i, ports;
+
+       ports = info->rh_numports;
+
+       spin_lock_irq(&info->lock);
+       if (!test_bit(HCD_FLAG_HW_ACCESSIBLE, &info->flags))
+               ret = -ESHUTDOWN;
+       else if (!info->dead) {
+               /* resume any suspended ports*/
+               for (i = 1; i <= ports; i++)
+                       rhport_resume(info, i);
+       }
        spin_unlock_irq(&info->lock);
 
-       return 0;
-}
-
-static int xenhcd_bus_resume(struct usb_hcd *hcd)
-{
-       struct usbfront_info *info = hcd_to_info(hcd);
-       int i, ports;
-
-       ports = info->rh_numports;
-
-       spin_lock_irq(&info->lock);
-       /* resume any suspended ports*/
-       for (i = 1; i <= ports; i++) {
-               rhport_resume(info, i);
-       }
-       hcd->state = HC_STATE_RUNNING;
-       spin_unlock_irq(&info->lock);
-       return 0;
-}
-#endif
+       return ret;
+}
 #endif
 
 static void xenhcd_hub_descriptor(struct usbfront_info *info,
@@ -295,8 +269,8 @@ static void xenhcd_hub_descriptor(struct
        desc->bDescLength = 7 + 2 * temp;
 
        /* bitmaps for DeviceRemovable and PortPwrCtrlMask */
-       memset (&desc->bitmap[0], 0, temp);
-       memset (&desc->bitmap[temp], 0xff, temp);
+       memset(&desc->bitmap[0], 0, temp);
+       memset(&desc->bitmap[temp], 0xff, temp);
 
        /* per-port over current reporting and no power switching */
        temp = 0x000a;
@@ -380,11 +354,6 @@ static int xenhcd_hub_control(struct usb
        int i;
        int changed = 0;
 
-#ifdef USBFRONT_DEBUG
-       WPRINTK("xenusb_hub_control(typeReq %x wValue %x wIndex %x)\n",
-              typeReq, wValue, wIndex);
-#endif
-
        spin_lock_irqsave(&info->lock, flags);
        switch (typeReq) {
        case ClearHubFeature:
@@ -394,7 +363,7 @@ static int xenhcd_hub_control(struct usb
                if (!wIndex || wIndex > ports)
                        goto error;
 
-               switch(wValue) {
+               switch (wValue) {
                case USB_PORT_FEAT_SUSPEND:
                        rhport_resume(info, wIndex);
                        break;
@@ -414,7 +383,7 @@ static int xenhcd_hub_control(struct usb
                break;
        case GetHubDescriptor:
                xenhcd_hub_descriptor(info,
-                                     (struct usb_hub_descriptor*) buf);
+                                     (struct usb_hub_descriptor *) buf);
                break;
        case GetHubStatus:
                /* always local power supply good and no over-current exists. */
@@ -444,7 +413,7 @@ static int xenhcd_hub_control(struct usb
                                info->devices[wIndex].status = 
USB_STATE_DEFAULT;
                        }
 
-                       switch(info->devices[wIndex].speed) {
+                       switch (info->devices[wIndex].speed) {
                        case USB_SPEED_LOW:
                                info->ports[wIndex].status |= 
USB_PORT_STAT_LOW_SPEED;
                                break;
@@ -466,7 +435,7 @@ static int xenhcd_hub_control(struct usb
                if (!wIndex || wIndex > ports)
                        goto error;
 
-               switch(wValue) {
+               switch (wValue) {
                case USB_PORT_FEAT_POWER:
                        rhport_power_on(info, wIndex);
                        break;
@@ -477,9 +446,8 @@ static int xenhcd_hub_control(struct usb
                        rhport_suspend(info, wIndex);
                        break;
                default:
-                       if ((info->ports[wIndex-1].status & 
USB_PORT_STAT_POWER) != 0) {
+                       if ((info->ports[wIndex-1].status & 
USB_PORT_STAT_POWER) != 0)
                                info->ports[wIndex-1].status |= (1 << wValue);
-                       }
                }
                break;
 
@@ -491,9 +459,8 @@ error:
 
        /* check status for each port */
        for (i = 0; i < ports; i++) {
-               if (info->ports[i].status & PORT_C_MASK) {
+               if (info->ports[i].status & PORT_C_MASK)
                        changed = 1;
-               }
        }
        if (changed)
                usb_hcd_poll_rh_status(hcd);
diff -r 7d57b5843b65 -r 498ac445a2a9 drivers/xen/usbfront/usbfront-q.c
--- a/drivers/xen/usbfront/usbfront-q.c Wed Oct 07 07:33:40 2009 +0100
+++ b/drivers/xen/usbfront/usbfront-q.c Wed Oct 07 08:42:00 2009 +0100
@@ -50,13 +50,13 @@ static struct urb_priv *alloc_urb_priv(s
        struct urb_priv *urbp;
 
        urbp = kmem_cache_zalloc(xenhcd_urbp_cachep, GFP_ATOMIC);
-       if (!urbp) {
+       if (!urbp)
                return NULL;
-       }
 
        urbp->urb = urb;
        urb->hcpriv = urbp;
        urbp->req_id = ~0;
+       urbp->unlink_req_id = ~0;
        INIT_LIST_HEAD(&urbp->list);
 
        return urbp;
@@ -73,7 +73,7 @@ static inline int get_id_from_freelist(
 {
        unsigned long free;
        free = info->shadow_free;
-       BUG_ON(free > USB_RING_SIZE);
+       BUG_ON(free >= USB_URB_RING_SIZE);
        info->shadow_free = info->shadow[free].req.id;
        info->shadow[free].req.id = (unsigned int)0x0fff; /* debug */
        return free;
@@ -90,7 +90,7 @@ static inline int count_pages(void *addr
 static inline int count_pages(void *addr, int length)
 {
        unsigned long start = (unsigned long) addr >> PAGE_SHIFT;
-       unsigned long end = (unsigned long) (addr + length + PAGE_SIZE -1) >> 
PAGE_SHIFT;
+       unsigned long end = (unsigned long) (addr + length + PAGE_SIZE - 1) >> 
PAGE_SHIFT;
        return end - start;
 }
 
@@ -108,7 +108,7 @@ static inline void xenhcd_gnttab_map(str
 
        len = length;
 
-       for(i = 0;i < nr_pages;i++){
+       for (i = 0; i < nr_pages; i++) {
                BUG_ON(!len);
 
                page = virt_to_page(addr);
@@ -116,7 +116,7 @@ static inline void xenhcd_gnttab_map(str
                offset = offset_in_page(addr);
 
                bytes = PAGE_SIZE - offset;
-               if(bytes > len)
+               if (bytes > len)
                        bytes = len;
 
                ref = gnttab_claim_grant_reference(gref_head);
@@ -132,7 +132,7 @@ static inline void xenhcd_gnttab_map(str
 }
 
 static int map_urb_for_request(struct usbfront_info *info, struct urb *urb,
-               usbif_request_t *req)
+               usbif_urb_request_t *req)
 {
        grant_ref_t gref_head;
        int nr_buff_pages = 0;
@@ -175,14 +175,12 @@ static int map_urb_for_request(struct us
                req->u.isoc.start_frame = urb->start_frame;
                req->u.isoc.number_of_packets = urb->number_of_packets;
                req->u.isoc.nr_frame_desc_segs = nr_isodesc_pages;
-               /*
-                * urb->number_of_packets must be > 0
-                */
+               /* urb->number_of_packets must be > 0 */
                if (unlikely(urb->number_of_packets <= 0))
                        BUG();
                xenhcd_gnttab_map(info, &urb->iso_frame_desc[0],
-                               sizeof(struct usb_iso_packet_descriptor) * 
urb->number_of_packets,
-                               &gref_head, &req->seg[nr_buff_pages], 
nr_isodesc_pages, 0);
+                       sizeof(struct usb_iso_packet_descriptor) * 
urb->number_of_packets,
+                       &gref_head, &req->seg[nr_buff_pages], nr_isodesc_pages, 
0);
                gnttab_free_grant_references(gref_head);
                break;
        case PIPE_INTERRUPT:
@@ -213,9 +211,12 @@ static void xenhcd_gnttab_done(struct us
 
        for (i = 0; i < nr_segs; i++)
                gnttab_end_foreign_access(shadow->req.seg[i].gref, 0UL);
-}
-
-static void xenhcd_giveback_urb(struct usbfront_info *info, struct urb *urb)
+
+       shadow->req.nr_buffer_segs = 0;
+       shadow->req.u.isoc.nr_frame_desc_segs = 0;
+}
+
+static void xenhcd_giveback_urb(struct usbfront_info *info, struct urb *urb, 
int status)
 __releases(info->lock)
 __acquires(info->lock)
 {
@@ -228,6 +229,9 @@ __acquires(info->lock)
        case -ENOENT:
                COUNT(info->stats.unlink);
                break;
+       case -EINPROGRESS:
+               urb->status = status;
+               /* falling through */
        default:
                COUNT(info->stats.complete);
        }
@@ -238,28 +242,35 @@ __acquires(info->lock)
 
 static inline int xenhcd_do_request(struct usbfront_info *info, struct 
urb_priv *urbp)
 {
-       usbif_request_t *ring_req;
+       usbif_urb_request_t *req;
        struct urb *urb = urbp->urb;
        uint16_t id;
        int notify;
        int ret = 0;
 
-       ring_req = RING_GET_REQUEST(&info->ring, info->ring.req_prod_pvt);
+       req = RING_GET_REQUEST(&info->urb_ring, info->urb_ring.req_prod_pvt);
        id = get_id_from_freelist(info);
-       ring_req->id = id;
-
-       ret = map_urb_for_request(info, urb, ring_req);
-       if (ret < 0) {
-               add_id_to_freelist(info, id);
-               return ret;
-       }
-
-       info->ring.req_prod_pvt++;
+       req->id = id;
+
+       if (unlikely(urbp->unlinked)) {
+               req->u.unlink.unlink_id = urbp->req_id;
+               req->pipe = usbif_setunlink_pipe(usbif_setportnum_pipe(
+                               urb->pipe, urb->dev->portnum));
+               urbp->unlink_req_id = id;
+       } else {
+               ret = map_urb_for_request(info, urb, req);
+               if (ret < 0) {
+                       add_id_to_freelist(info, id);
+                       return ret;
+               }
+               urbp->req_id = id;
+       }
+
+       info->urb_ring.req_prod_pvt++;
        info->shadow[id].urb = urb;
-       info->shadow[id].req = *ring_req;
-       urbp->req_id = id;
-
-       RING_PUSH_REQUESTS_AND_CHECK_NOTIFY(&info->ring, notify);
+       info->shadow[id].req = *req;
+
+       RING_PUSH_REQUESTS_AND_CHECK_NOTIFY(&info->urb_ring, notify);
        if (notify)
                notify_remote_via_irq(info->irq);
 
@@ -271,19 +282,19 @@ static void xenhcd_kick_pending_urbs(str
        struct urb_priv *urbp;
        int ret;
 
-       while (!list_empty(&info->pending_urbs)) {
-               if (RING_FULL(&info->ring)) {
+       while (!list_empty(&info->pending_submit_list)) {
+               if (RING_FULL(&info->urb_ring)) {
                        COUNT(info->stats.ring_full);
                        timer_action(info, TIMER_RING_WATCHDOG);
                        goto done;
                }
 
-               urbp = list_entry(info->pending_urbs.next, struct urb_priv, 
list);
+               urbp = list_entry(info->pending_submit_list.next, struct 
urb_priv, list);
                ret = xenhcd_do_request(info, urbp);
                if (ret == 0)
-                       list_move_tail(&urbp->list, &info->inprogress_urbs);
+                       list_move_tail(&urbp->list, &info->in_progress_list);
                else
-                       xenhcd_giveback_urb(info, urbp->urb);
+                       xenhcd_giveback_urb(info, urbp->urb, -ESHUTDOWN);
        }
        timer_action_done(info, TIMER_SCAN_PENDING_URBS);
 
@@ -291,12 +302,41 @@ done:
        return;
 }
 
+/*
+ * caller must lock info->lock
+ */
+static void xenhcd_cancel_all_enqueued_urbs(struct usbfront_info *info)
+{
+       struct urb_priv *urbp, *tmp;
+
+       list_for_each_entry_safe(urbp, tmp, &info->in_progress_list, list) {
+               if (!urbp->unlinked) {
+                       xenhcd_gnttab_done(&info->shadow[urbp->req_id]);
+                       barrier();
+                       if (urbp->urb->status == -EINPROGRESS)  /* not dequeued 
*/
+                               xenhcd_giveback_urb(info, urbp->urb, 
-ESHUTDOWN);
+                       else                                    /* dequeued */
+                               xenhcd_giveback_urb(info, urbp->urb, 
urbp->urb->status);
+               }
+               info->shadow[urbp->req_id].urb = NULL;
+       }
+
+       list_for_each_entry_safe(urbp, tmp, &info->pending_submit_list, list) {
+               xenhcd_giveback_urb(info, urbp->urb, -ESHUTDOWN);
+       }
+
+       return;
+}
+
+/*
+ * caller must lock info->lock
+ */
 static void xenhcd_giveback_unlinked_urbs(struct usbfront_info *info)
 {
        struct urb_priv *urbp, *tmp;
 
-       list_for_each_entry_safe(urbp, tmp, &info->unlinked_urbs, list) {
-               xenhcd_giveback_urb(info, urbp->urb);
+       list_for_each_entry_safe(urbp, tmp, &info->giveback_waiting_list, list) 
{
+               xenhcd_giveback_urb(info, urbp->urb, urbp->urb->status);
        }
 }
 
@@ -304,22 +344,22 @@ static int xenhcd_submit_urb(struct usbf
 {
        int ret = 0;
 
-       if (RING_FULL(&info->ring)) {
-               list_add_tail(&urbp->list, &info->pending_urbs);
+       if (RING_FULL(&info->urb_ring)) {
+               list_add_tail(&urbp->list, &info->pending_submit_list);
                COUNT(info->stats.ring_full);
                timer_action(info, TIMER_RING_WATCHDOG);
                goto done;
        }
 
-       if (!list_empty(&info->pending_urbs)) {
-               list_add_tail(&urbp->list, &info->pending_urbs);
+       if (!list_empty(&info->pending_submit_list)) {
+               list_add_tail(&urbp->list, &info->pending_submit_list);
                timer_action(info, TIMER_SCAN_PENDING_URBS);
                goto done;
        }
 
        ret = xenhcd_do_request(info, urbp);
        if (ret == 0)
-               list_add_tail(&urbp->list, &info->inprogress_urbs);
+               list_add_tail(&urbp->list, &info->in_progress_list);
 
 done:
        return ret;
@@ -327,26 +367,47 @@ done:
 
 static int xenhcd_unlink_urb(struct usbfront_info *info, struct urb_priv *urbp)
 {
+       int ret = 0;
+
+       /* already unlinked? */
        if (urbp->unlinked)
                return -EBUSY;
+
        urbp->unlinked = 1;
 
-       /* if the urb is in pending_urbs */
+       /* the urb is still in pending_submit queue */
        if (urbp->req_id == ~0) {
-               list_move_tail(&urbp->list, &info->unlinked_urbs);
+               list_move_tail(&urbp->list, &info->giveback_waiting_list);
                timer_action(info, TIMER_SCAN_PENDING_URBS);
-       }
-
-       /* TODO: send cancel request to backend */
-
-       return 0;
-}
-
-static int xenhcd_end_submit_urb(struct usbfront_info *info)
-{
-       usbif_response_t *ring_res;
+               goto done;
+       }
+
+       /* send unlink request to backend */
+       if (RING_FULL(&info->urb_ring)) {
+               list_move_tail(&urbp->list, &info->pending_unlink_list);
+               COUNT(info->stats.ring_full);
+               timer_action(info, TIMER_RING_WATCHDOG);
+               goto done;
+       }
+
+       if (!list_empty(&info->pending_unlink_list)) {
+               list_move_tail(&urbp->list, &info->pending_unlink_list);
+               timer_action(info, TIMER_SCAN_PENDING_URBS);
+               goto done;
+       }
+
+       ret = xenhcd_do_request(info, urbp);
+       if (ret == 0)
+               list_move_tail(&urbp->list, &info->in_progress_list);
+
+done:
+       return ret;
+}
+
+static int xenhcd_urb_request_done(struct usbfront_info *info)
+{
+       usbif_urb_response_t *res;
        struct urb *urb;
-       struct urb_priv *urbp;
 
        RING_IDX i, rp;
        uint16_t id;
@@ -354,35 +415,92 @@ static int xenhcd_end_submit_urb(struct 
        unsigned long flags;
 
        spin_lock_irqsave(&info->lock, flags);
-       rp = info->ring.sring->rsp_prod;
+
+       rp = info->urb_ring.sring->rsp_prod;
        rmb(); /* ensure we see queued responses up to "rp" */
 
-       for (i = info->ring.rsp_cons; i != rp; i++) {
-               ring_res = RING_GET_RESPONSE(&info->ring, i);
-               id = ring_res->id;
-               xenhcd_gnttab_done(&info->shadow[id]);
-               urb = info->shadow[id].urb;
+       for (i = info->urb_ring.rsp_cons; i != rp; i++) {
+               res = RING_GET_RESPONSE(&info->urb_ring, i);
+               id = res->id;
+
+               if (likely(usbif_pipesubmit(info->shadow[id].req.pipe))) {
+                       xenhcd_gnttab_done(&info->shadow[id]);
+                       urb = info->shadow[id].urb;
+                       barrier();
+                       if (likely(urb)) {
+                               urb->actual_length = res->actual_length;
+                               urb->error_count = res->error_count;
+                               urb->start_frame = res->start_frame;
+                               barrier();
+                               xenhcd_giveback_urb(info, urb, res->status);
+                       }
+               }
+
+               add_id_to_freelist(info, id);
+       }
+       info->urb_ring.rsp_cons = i;
+
+       if (i != info->urb_ring.req_prod_pvt)
+               RING_FINAL_CHECK_FOR_RESPONSES(&info->urb_ring, more_to_do);
+       else
+               info->urb_ring.sring->rsp_event = i + 1;
+
+       spin_unlock_irqrestore(&info->lock, flags);
+
+       cond_resched();
+
+       return more_to_do;
+}
+
+static int xenhcd_conn_notify(struct usbfront_info *info)
+{
+       usbif_conn_response_t *res;
+       usbif_conn_request_t *req;
+       RING_IDX rc, rp;
+       uint16_t id;
+       uint8_t portnum, speed;
+       int more_to_do = 0;
+       int notify;
+       int port_changed = 0;
+       unsigned long flags;
+
+       spin_lock_irqsave(&info->lock, flags);
+
+       rc = info->conn_ring.rsp_cons;
+       rp = info->conn_ring.sring->rsp_prod;
+       rmb(); /* ensure we see queued responses up to "rp" */
+
+       while (rc != rp) {
+               res = RING_GET_RESPONSE(&info->conn_ring, rc);
+               id = res->id;
+               portnum = res->portnum;
+               speed = res->speed;
+               info->conn_ring.rsp_cons = ++rc;
+
+               rhport_connect(info, portnum, speed);
+               if (info->ports[portnum-1].c_connection)
+                       port_changed = 1;
+
                barrier();
-               add_id_to_freelist(info, id);
-
-               urbp = (struct urb_priv *)urb->hcpriv;
-               if (likely(!urbp->unlinked)) {
-                       urb->status = ring_res->status;
-                       urb->actual_length = ring_res->actual_length;
-                       urb->error_count = ring_res->error_count;
-                       urb->start_frame = ring_res->start_frame;
-               }
-               barrier();
-               xenhcd_giveback_urb(info, urb);
-       }
-       info->ring.rsp_cons = i;
-
-       if (i != info->ring.req_prod_pvt)
-               RING_FINAL_CHECK_FOR_RESPONSES(&info->ring, more_to_do);
+
+               req = RING_GET_REQUEST(&info->conn_ring, 
info->conn_ring.req_prod_pvt);
+               req->id = id;
+               info->conn_ring.req_prod_pvt++;
+       }
+
+       if (rc != info->conn_ring.req_prod_pvt)
+               RING_FINAL_CHECK_FOR_RESPONSES(&info->conn_ring, more_to_do);
        else
-               info->ring.sring->rsp_event = i + 1;
+               info->conn_ring.sring->rsp_event = rc + 1;
+
+       RING_PUSH_REQUESTS_AND_CHECK_NOTIFY(&info->conn_ring, notify);
+       if (notify)
+               notify_remote_via_irq(info->irq);
 
        spin_unlock_irqrestore(&info->lock, flags);
+
+       if (port_changed)
+               usb_hcd_poll_rh_status(info_to_hcd(info));
 
        cond_resched();
 
@@ -400,7 +518,10 @@ int xenhcd_schedule(void *arg)
                info->waiting_resp = 0;
                smp_mb();
 
-               if (xenhcd_end_submit_urb(info))
+               if (xenhcd_urb_request_done(info))
+                       info->waiting_resp = 1;
+
+               if (xenhcd_conn_notify(info))
                        info->waiting_resp = 1;
        }
 
diff -r 7d57b5843b65 -r 498ac445a2a9 drivers/xen/usbfront/usbfront.h
--- a/drivers/xen/usbfront/usbfront.h   Wed Oct 07 07:33:40 2009 +0100
+++ b/drivers/xen/usbfront/usbfront.h   Wed Oct 07 08:42:00 2009 +0100
@@ -66,8 +66,6 @@
 #include "../../usb/core/hcd.h"
 #include "../../usb/core/hub.h"
 
-#define DRIVER_DESC "Xen USB2.0 Virtual Host Controller driver (usbfront)"
-
 static inline struct usbfront_info *hcd_to_info(struct usb_hcd *hcd)
 {
        return (struct usbfront_info *) (hcd->hcd_priv);
@@ -75,17 +73,16 @@ static inline struct usbfront_info *hcd_
 
 static inline struct usb_hcd *info_to_hcd(struct usbfront_info *info)
 {
-       return container_of ((void *) info, struct usb_hcd, hcd_priv);
-}
-
-/*
- * Private per-URB data
- */
+       return container_of((void *) info, struct usb_hcd, hcd_priv);
+}
+
+/* Private per-URB data */
 struct urb_priv {
        struct list_head list;
        struct urb *urb;
-       int req_id;     /* RING_REQUEST id */
-       unsigned unlinked:1; /* dequeued urb just marked */
+       int req_id;     /* RING_REQUEST id for submitting */
+       int unlink_req_id; /* RING_REQUEST id for unlinking */
+       unsigned unlinked:1; /* dequeued marker */
 };
 
 /* virtual roothub port status */
@@ -105,7 +102,7 @@ struct vdevice_status {
 
 /* RING request shadow */
 struct usb_shadow {
-       usbif_request_t req;
+       usbif_urb_request_t req;
        struct urb *urb;
 };
 
@@ -117,62 +114,46 @@ struct xenhcd_stats {
 };
 
 struct usbfront_info {
-       /*
-        * Virtual Host Controller has 3 queues.
-        *
-        * pending_urbs:
-        *      If xenhcd_urb_enqueue() called in RING_FULL state,
-        *      the enqueued urbs are added to this queue, and waits
-        *      to be sent to the backend.
-        *
-        * inprogress_urbs:
-        *      After xenhcd_urb_enqueue() called and RING_REQUEST sent,
-        *      the urbs are added to this queue and waits for RING_RESPONSE.
-        *
-        * unlinked_urbs:
-        *      When xenhcd_urb_dequeue() called, if the dequeued urb is
-        *      listed in pending_urbs, that urb is moved to this queue
-        *      and waits to be given back to the USB core.
-        */
-       struct list_head pending_urbs;
-       struct list_head inprogress_urbs;
-       struct list_head unlinked_urbs;
+       /* Virtual Host Controller has 4 urb queues */
+       struct list_head pending_submit_list;
+       struct list_head pending_unlink_list;
+       struct list_head in_progress_list;
+       struct list_head giveback_waiting_list;
+
        spinlock_t lock;
 
-       /*
-        * timer function that kick pending_urbs and unlink_urbs.
-        */
+       /* timer that kick pending and giveback waiting urbs */
+       struct timer_list watchdog;
        unsigned long actions;
-       struct timer_list watchdog;
-
-       /*
-        * Virtual roothub:
-        * Emulates the hub ports and the attached devices status.
-        * USB_MAXCHILDREN is defined (16) in include/linux/usb.h
-        */
+
+       /* virtual root hub */
        int rh_numports;
        struct rhport_status ports[USB_MAXCHILDREN];
        struct vdevice_status devices[USB_MAXCHILDREN];
 
+       /* Xen related staff */
+       struct xenbus_device *xbdev;
+       int urb_ring_ref;
+       int conn_ring_ref;
+       usbif_urb_front_ring_t urb_ring;
+       usbif_conn_front_ring_t conn_ring;
+
+       unsigned int irq; /* event channel */
+       struct usb_shadow shadow[USB_URB_RING_SIZE];
+       unsigned long shadow_free;
+
+       /* RING_RESPONSE thread */
+       struct task_struct *kthread;
+       wait_queue_head_t wq;
+       unsigned int waiting_resp;
+
+       /* xmit statistics */
 #ifdef XENHCD_STATS
        struct xenhcd_stats stats;
 #define COUNT(x) do { (x)++; } while (0)
 #else
 #define COUNT(x) do {} while (0)
 #endif
-
-       /* Xen related staff */
-       struct xenbus_device *xbdev;
-       int ring_ref;
-       usbif_front_ring_t ring;
-       unsigned int irq;
-       struct usb_shadow shadow[USB_RING_SIZE];
-       unsigned long shadow_free;
-
-       /* RING_RESPONSE thread */
-       struct task_struct *kthread;
-       wait_queue_head_t wq;
-       unsigned int waiting_resp;
 };
 
 #define XENHCD_RING_JIFFIES (HZ/200)
@@ -199,7 +180,7 @@ timer_action(struct usbfront_info *info,
        if (!test_and_set_bit(action, &info->actions)) {
                unsigned long t;
 
-               switch(action) {
+               switch (action) {
                case TIMER_RING_WATCHDOG:
                        t = XENHCD_RING_JIFFIES;
                        break;
@@ -211,6 +192,12 @@ timer_action(struct usbfront_info *info,
        }
 }
 
+extern struct kmem_cache *xenhcd_urbp_cachep;
+extern struct hc_driver xen_usb20_hc_driver;
+extern struct hc_driver xen_usb11_hc_driver;
 irqreturn_t xenhcd_int(int irq, void *dev_id, struct pt_regs *ptregs);
+void xenhcd_rhport_state_change(struct usbfront_info *info,
+                               int port, enum usb_device_speed speed);
+int xenhcd_schedule(void *arg);
 
 #endif /* __XEN_USBFRONT_H__ */
diff -r 7d57b5843b65 -r 498ac445a2a9 drivers/xen/usbfront/xenbus.c
--- a/drivers/xen/usbfront/xenbus.c     Wed Oct 07 07:33:40 2009 +0100
+++ b/drivers/xen/usbfront/xenbus.c     Wed Oct 07 08:42:00 2009 +0100
@@ -45,50 +45,70 @@
 
 #include "usbfront.h"
 
-extern struct hc_driver usbfront_hc_driver;
-extern struct kmem_cache *xenhcd_urbp_cachep;
-extern void xenhcd_rhport_state_change(struct usbfront_info *info,
-                                       int port, enum usb_device_speed speed);
-extern int xenhcd_schedule(void *arg);
-
 #define GRANT_INVALID_REF 0
 
-static void usbif_free(struct usbfront_info *info)
-{
-       if (info->ring_ref != GRANT_INVALID_REF) {
-               gnttab_end_foreign_access(info->ring_ref,
-                                         (unsigned long)info->ring.sring);
-               info->ring_ref = GRANT_INVALID_REF;
-               info->ring.sring = NULL;
-       }
+static void destroy_rings(struct usbfront_info *info)
+{
        if (info->irq)
                unbind_from_irqhandler(info->irq, info);
        info->irq = 0;
-}
-
-static int setup_usbring(struct xenbus_device *dev,
+
+       if (info->urb_ring_ref != GRANT_INVALID_REF) {
+               gnttab_end_foreign_access(info->urb_ring_ref,
+                                         (unsigned long)info->urb_ring.sring);
+               info->urb_ring_ref = GRANT_INVALID_REF;
+       }
+       info->urb_ring.sring = NULL;
+
+       if (info->conn_ring_ref != GRANT_INVALID_REF) {
+               gnttab_end_foreign_access(info->conn_ring_ref,
+                                         (unsigned long)info->conn_ring.sring);
+               info->conn_ring_ref = GRANT_INVALID_REF;
+       }
+       info->conn_ring.sring = NULL;
+}
+
+static int setup_rings(struct xenbus_device *dev,
                           struct usbfront_info *info)
 {
-       usbif_sring_t *sring;
+       usbif_urb_sring_t *urb_sring;
+       usbif_conn_sring_t *conn_sring;
        int err;
 
-       info->ring_ref= GRANT_INVALID_REF;
-
-       sring = (usbif_sring_t *)get_zeroed_page(GFP_NOIO|__GFP_HIGH);
-       if (!sring) {
-               xenbus_dev_fatal(dev, -ENOMEM, "allocating shared ring");
+       info->urb_ring_ref = GRANT_INVALID_REF;
+       info->conn_ring_ref = GRANT_INVALID_REF;
+
+       urb_sring = (usbif_urb_sring_t *)get_zeroed_page(GFP_NOIO|__GFP_HIGH);
+       if (!urb_sring) {
+               xenbus_dev_fatal(dev, -ENOMEM, "allocating urb ring");
                return -ENOMEM;
        }
-       SHARED_RING_INIT(sring);
-       FRONT_RING_INIT(&info->ring, sring, PAGE_SIZE);
-
-       err = xenbus_grant_ring(dev, virt_to_mfn(info->ring.sring));
+       SHARED_RING_INIT(urb_sring);
+       FRONT_RING_INIT(&info->urb_ring, urb_sring, PAGE_SIZE);
+
+       err = xenbus_grant_ring(dev, virt_to_mfn(info->urb_ring.sring));
        if (err < 0) {
-               free_page((unsigned long)sring);
-               info->ring.sring = NULL;
-               goto fail;
-       }
-       info->ring_ref = err;
+               free_page((unsigned long)urb_sring);
+               info->urb_ring.sring = NULL;
+               goto fail;
+       }
+       info->urb_ring_ref = err;
+
+       conn_sring = (usbif_conn_sring_t *)get_zeroed_page(GFP_NOIO|__GFP_HIGH);
+       if (!conn_sring) {
+               xenbus_dev_fatal(dev, -ENOMEM, "allocating conn ring");
+               return -ENOMEM;
+       }
+       SHARED_RING_INIT(conn_sring);
+       FRONT_RING_INIT(&info->conn_ring, conn_sring, PAGE_SIZE);
+
+       err = xenbus_grant_ring(dev, virt_to_mfn(info->conn_ring.sring));
+       if (err < 0) {
+               free_page((unsigned long)conn_sring);
+               info->conn_ring.sring = NULL;
+               goto fail;
+       }
+       info->conn_ring_ref = err;
 
        err = bind_listening_port_to_irqhandler(
                dev->otherend_id, xenhcd_int, SA_SAMPLE_RANDOM, "usbif", info);
@@ -101,7 +121,7 @@ static int setup_usbring(struct xenbus_d
 
        return 0;
 fail:
-       usbif_free(info);
+       destroy_rings(info);
        return err;
 }
 
@@ -112,7 +132,7 @@ static int talk_to_backend(struct xenbus
        struct xenbus_transaction xbt;
        int err;
 
-       err = setup_usbring(dev, info);
+       err = setup_rings(dev, info);
        if (err)
                goto out;
 
@@ -123,10 +143,17 @@ again:
                goto destroy_ring;
        }
 
-       err = xenbus_printf(xbt, dev->nodename, "ring-ref", "%u",
-                           info->ring_ref);
-       if (err) {
-               message = "writing ring-ref";
+       err = xenbus_printf(xbt, dev->nodename, "urb-ring-ref", "%u",
+                           info->urb_ring_ref);
+       if (err) {
+               message = "writing urb-ring-ref";
+               goto abort_transaction;
+       }
+
+       err = xenbus_printf(xbt, dev->nodename, "conn-ring-ref", "%u",
+                           info->conn_ring_ref);
+       if (err) {
+               message = "writing conn-ring-ref";
                goto abort_transaction;
        }
 
@@ -145,8 +172,6 @@ again:
                goto destroy_ring;
        }
 
-       xenbus_switch_state(dev, XenbusStateInitialised);
-
        return 0;
 
 abort_transaction:
@@ -154,10 +179,37 @@ abort_transaction:
        xenbus_dev_fatal(dev, err, "%s", message);
 
 destroy_ring:
-       usbif_free(info);
+       destroy_rings(info);
 
 out:
        return err;
+}
+
+static int connect(struct xenbus_device *dev)
+{
+       struct usbfront_info *info = dev->dev.driver_data;
+
+       usbif_conn_request_t *req;
+       int i, idx, err;
+       int notify;
+
+       err = talk_to_backend(dev, info);
+       if (err)
+               return err;
+
+       /* prepare ring for hotplug notification */
+       for (idx = 0, i = 0; i < USB_CONN_RING_SIZE; i++) {
+               req = RING_GET_REQUEST(&info->conn_ring, idx);
+               req->id = idx;
+               idx++;
+       }
+       info->conn_ring.req_prod_pvt = idx;
+
+       RING_PUSH_REQUESTS_AND_CHECK_NOTIFY(&info->conn_ring, notify);
+       if (notify)
+               notify_remote_via_irq(info->irq);
+
+       return 0;
 }
 
 static struct usb_hcd *create_hcd(struct xenbus_device *dev)
@@ -165,6 +217,7 @@ static struct usb_hcd *create_hcd(struct
        int i;
        int err = 0;
        int num_ports;
+       int usb_ver;
        struct usb_hcd *hcd = NULL;
        struct usbfront_info *info = NULL;
 
@@ -179,20 +232,38 @@ static struct usb_hcd *create_hcd(struct
                return ERR_PTR(-EINVAL);
        }
 
-       hcd = usb_create_hcd(&usbfront_hc_driver, &dev->dev, dev->dev.bus_id);
+       err = xenbus_scanf(XBT_NIL, dev->otherend,
+                                       "usb-ver", "%d", &usb_ver);
+       if (err != 1) {
+               xenbus_dev_fatal(dev, err, "reading usb-ver");
+               return ERR_PTR(-EINVAL);
+       }
+       switch (usb_ver) {
+       case USB_VER_USB11:
+               hcd = usb_create_hcd(&xen_usb11_hc_driver, &dev->dev, 
dev->dev.bus_id);
+               break;
+       case USB_VER_USB20:
+               hcd = usb_create_hcd(&xen_usb20_hc_driver, &dev->dev, 
dev->dev.bus_id);
+               break;
+       default:
+               xenbus_dev_fatal(dev, err, "invalid usb-ver");
+               return ERR_PTR(-EINVAL);
+       }
        if (!hcd) {
-               xenbus_dev_fatal(dev, err, "fail to allocate USB host 
controller");
+               xenbus_dev_fatal(dev, err,
+                               "fail to allocate USB host controller");
                return ERR_PTR(-ENOMEM);
        }
+
        info = hcd_to_info(hcd);
        info->xbdev = dev;
        info->rh_numports = num_ports;
 
-       for (i = 0; i < USB_RING_SIZE; i++) {
-               info->shadow[i].req.id = i+1;
+       for (i = 0; i < USB_URB_RING_SIZE; i++) {
+               info->shadow[i].req.id = i + 1;
                info->shadow[i].urb = NULL;
        }
-       info->shadow[USB_RING_SIZE-1].req.id = 0x0fff;
+       info->shadow[USB_URB_RING_SIZE-1].req.id = 0x0fff;
 
        return hcd;
 }
@@ -211,7 +282,8 @@ static int usbfront_probe(struct xenbus_
        hcd = create_hcd(dev);
        if (IS_ERR(hcd)) {
                err = PTR_ERR(hcd);
-               xenbus_dev_fatal(dev, err, "fail to create usb host 
controller");
+               xenbus_dev_fatal(dev, err,
+                               "fail to create usb host controller");
                goto fail;
        }
 
@@ -220,22 +292,19 @@ static int usbfront_probe(struct xenbus_
 
        err = usb_add_hcd(hcd, 0, 0);
        if (err != 0) {
-               xenbus_dev_fatal(dev, err, "fail to adding USB host 
controller");
+               xenbus_dev_fatal(dev, err,
+                               "fail to adding USB host controller");
                goto fail;
        }
 
        init_waitqueue_head(&info->wq);
        snprintf(name, TASK_COMM_LEN, "xenhcd.%d", hcd->self.busnum);
        info->kthread = kthread_run(xenhcd_schedule, info, name);
-        if (IS_ERR(info->kthread)) {
-                err = PTR_ERR(info->kthread);
-                info->kthread = NULL;
-                goto fail;
-        }
-
-       err = talk_to_backend(dev, info);
-       if (err)
-               goto fail;
+       if (IS_ERR(info->kthread)) {
+               err = PTR_ERR(info->kthread);
+               info->kthread = NULL;
+               goto fail;
+       }
 
        return 0;
 
@@ -245,68 +314,7 @@ fail:
        return err;
 }
 
-/*
- * 0=disconnected, 1=low_speed, 2=full_speed, 3=high_speed
- */
-static void usbfront_do_hotplug(struct usbfront_info *info)
-{
-       char port_str[8];
-       int i;
-       int err;
-       int state;
-
-       for (i = 1; i <= info->rh_numports; i++) {
-               sprintf(port_str, "port-%d", i);
-               err = xenbus_scanf(XBT_NIL, info->xbdev->otherend,
-                                       port_str, "%d", &state);
-               if (err == 1)
-                       xenhcd_rhport_state_change(info, i, state);
-       }
-}
-
-static void backend_changed(struct xenbus_device *dev,
-                                    enum xenbus_state backend_state)
-{
-       struct usbfront_info *info = dev->dev.driver_data;
-
-       switch (backend_state) {
-       case XenbusStateInitialising:
-       case XenbusStateInitWait:
-       case XenbusStateInitialised:
-       case XenbusStateUnknown:
-       case XenbusStateClosed:
-               break;
-
-       case XenbusStateConnected:
-               if (dev->state == XenbusStateConnected)
-                       break;
-               if (dev->state == XenbusStateInitialised)
-                       usbfront_do_hotplug(info);
-               xenbus_switch_state(dev, XenbusStateConnected);
-               break;
-
-       case XenbusStateClosing:
-               xenbus_frontend_closed(dev);
-               break;
-
-       case XenbusStateReconfiguring:
-               if (dev->state == XenbusStateConnected)
-                       xenbus_switch_state(dev, XenbusStateReconfiguring);
-               break;
-
-       case XenbusStateReconfigured:
-               usbfront_do_hotplug(info);
-               xenbus_switch_state(dev, XenbusStateConnected);
-               break;
-
-       default:
-               xenbus_dev_fatal(dev, -EINVAL, "saw state %d at frontend",
-                                backend_state);
-               break;
-       }
-}
-
-static int usbfront_remove(struct xenbus_device *dev)
+static void usbfront_disconnect(struct xenbus_device *dev)
 {
        struct usbfront_info *info = dev->dev.driver_data;
        struct usb_hcd *hcd = info_to_hcd(info);
@@ -316,7 +324,46 @@ static int usbfront_remove(struct xenbus
                kthread_stop(info->kthread);
                info->kthread = NULL;
        }
-       usbif_free(info);
+       xenbus_frontend_closed(dev);
+}
+
+static void backend_changed(struct xenbus_device *dev,
+                                    enum xenbus_state backend_state)
+{
+       switch (backend_state) {
+       case XenbusStateInitialising:
+       case XenbusStateInitialised:
+       case XenbusStateConnected:
+       case XenbusStateReconfiguring:
+       case XenbusStateReconfigured:
+       case XenbusStateUnknown:
+       case XenbusStateClosed:
+               break;
+
+       case XenbusStateInitWait:
+               if (dev->state != XenbusStateInitialising)
+                       break;
+               connect(dev);
+               xenbus_switch_state(dev, XenbusStateConnected);
+               break;
+
+       case XenbusStateClosing:
+               usbfront_disconnect(dev);
+               break;
+
+       default:
+               xenbus_dev_fatal(dev, -EINVAL, "saw state %d at frontend",
+                                backend_state);
+               break;
+       }
+}
+
+static int usbfront_remove(struct xenbus_device *dev)
+{
+       struct usbfront_info *info = dev->dev.driver_data;
+       struct usb_hcd *hcd = info_to_hcd(info);
+
+       destroy_rings(info);
        usb_put_hcd(hcd);
 
        return 0;
@@ -361,5 +408,5 @@ module_exit(usbfront_exit);
 module_exit(usbfront_exit);
 
 MODULE_AUTHOR("");
-MODULE_DESCRIPTION(DRIVER_DESC);
+MODULE_DESCRIPTION("Xen USB Virtual Host Controller driver (usbfront)");
 MODULE_LICENSE("Dual BSD/GPL");
diff -r 7d57b5843b65 -r 498ac445a2a9 include/xen/interface/io/usbif.h
--- a/include/xen/interface/io/usbif.h  Wed Oct 07 07:33:40 2009 +0100
+++ b/include/xen/interface/io/usbif.h  Wed Oct 07 08:42:00 2009 +0100
@@ -31,6 +31,13 @@
 #include "ring.h"
 #include "../grant_table.h"
 
+enum usb_spec_version {
+       USB_VER_UNKNOWN = 0,
+       USB_VER_USB11,
+       USB_VER_USB20,
+       USB_VER_USB30,  /* not supported yet */
+};
+
 /*
  *  USB pipe in usbif_request
  *
@@ -57,21 +64,26 @@
  *                           10 = control, 11 = bulk)
  */
 #define usbif_pipeportnum(pipe) ((pipe) & 0x1f)
-#define usbif_setportnum_pipe(pipe,portnum) \
+#define usbif_setportnum_pipe(pipe, portnum) \
        ((pipe)|(portnum))
+
 #define usbif_pipeunlink(pipe) ((pipe) & 0x20)
+#define usbif_pipesubmit(pipe) (!usbif_pipeunlink(pipe))
 #define usbif_setunlink_pipe(pipe) ((pipe)|(0x20))
 
 #define USBIF_BACK_MAX_PENDING_REQS (128)
-#define USBIF_MAX_SEGMENTS_PER_REQUEST (10)
+#define USBIF_MAX_SEGMENTS_PER_REQUEST (16)
 
+/*
+ * RING for transferring urbs.
+ */
 struct usbif_request_segment {
        grant_ref_t gref;
        uint16_t offset;
        uint16_t length;
 };
 
-struct usbif_request {
+struct usbif_urb_request {
        uint16_t id; /* request id */
        uint16_t nr_buffer_segs; /* number of urb->transfer_buffer segments */
 
@@ -104,18 +116,36 @@ struct usbif_request {
        /* urb data segments */
        struct usbif_request_segment seg[USBIF_MAX_SEGMENTS_PER_REQUEST];
 };
-typedef struct usbif_request usbif_request_t;
+typedef struct usbif_urb_request usbif_urb_request_t;
 
-struct usbif_response {
+struct usbif_urb_response {
        uint16_t id; /* request id */
        uint16_t start_frame;  /* start frame (ISO) */
        int32_t status; /* status (non-ISO) */
        int32_t actual_length; /* actual transfer length */
        int32_t error_count; /* number of ISO errors */
 };
-typedef struct usbif_response usbif_response_t;
+typedef struct usbif_urb_response usbif_urb_response_t;
 
-DEFINE_RING_TYPES(usbif, struct usbif_request, struct usbif_response);
-#define USB_RING_SIZE __RING_SIZE((struct usbif_sring *)0, PAGE_SIZE)
+DEFINE_RING_TYPES(usbif_urb, struct usbif_urb_request, struct 
usbif_urb_response);
+#define USB_URB_RING_SIZE __RING_SIZE((struct usbif_urb_sring *)0, PAGE_SIZE)
+
+/*
+ * RING for notifying connect/disconnect events to frontend
+ */
+struct usbif_conn_request {
+       uint16_t id;
+};
+typedef struct usbif_conn_request usbif_conn_request_t;
+
+struct usbif_conn_response {
+       uint16_t id; /* request id */
+       uint8_t portnum; /* port number */
+       uint8_t speed; /* usb_device_speed */
+};
+typedef struct usbif_conn_response usbif_conn_response_t;
+
+DEFINE_RING_TYPES(usbif_conn, struct usbif_conn_request, struct 
usbif_conn_response);
+#define USB_CONN_RING_SIZE __RING_SIZE((struct usbif_conn_sring *)0, PAGE_SIZE)
 
 #endif /* __XEN_PUBLIC_IO_USBIF_H__ */

_______________________________________________
Xen-changelog mailing list
Xen-changelog@xxxxxxxxxxxxxxxxxxx
http://lists.xensource.com/xen-changelog


 


Rackspace

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