WARNING - OLD ARCHIVES

This is an archived copy of the Xen.org mailing list, which we have preserved to ensure that existing links to archives are not broken. The live archive, which contains the latest emails, can be found at http://lists.xen.org/
   
 
 
Xen 
 
Home Products Support Community News
 
   
 

xen-changelog

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

To: xen-changelog@xxxxxxxxxxxxxxxxxxx
Subject: [Xen-changelog] [linux-2.6.18-xen] PVUSB: Fixes and updates
From: "Xen patchbot-linux-2.6.18-xen" <patchbot-linux-2.6.18-xen@xxxxxxxxxxxxxxxxxxx>
Date: Wed, 07 Oct 2009 02:30:20 -0700
Delivery-date: Wed, 07 Oct 2009 02:30:34 -0700
Envelope-to: www-data@xxxxxxxxxxxxxxxxxxx
List-help: <mailto:xen-changelog-request@lists.xensource.com?subject=help>
List-id: BK change log <xen-changelog.lists.xensource.com>
List-post: <mailto:xen-changelog@lists.xensource.com>
List-subscribe: <http://lists.xensource.com/mailman/listinfo/xen-changelog>, <mailto:xen-changelog-request@lists.xensource.com?subject=subscribe>
List-unsubscribe: <http://lists.xensource.com/mailman/listinfo/xen-changelog>, <mailto:xen-changelog-request@lists.xensource.com?subject=unsubscribe>
Reply-to: xen-devel@xxxxxxxxxxxxxxxxxxx
Sender: xen-changelog-bounces@xxxxxxxxxxxxxxxxxxx
# 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

<Prev in Thread] Current Thread [Next in Thread>
  • [Xen-changelog] [linux-2.6.18-xen] PVUSB: Fixes and updates, Xen patchbot-linux-2.6.18-xen <=