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-devel

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

To: xen-devel@xxxxxxxxxxxxxxxxxxx
Subject: [Xen-devel] [PATCH 2/3] PVUSB update and bugfix: backend part
From: Noboru Iwamatsu <n_iwamatsu@xxxxxxxxxxxxxx>
Date: Wed, 07 Oct 2009 16:28:08 +0900
Delivery-date: Wed, 07 Oct 2009 00:32:16 -0700
Envelope-to: www-data@xxxxxxxxxxxxxxxxxxx
List-help: <mailto:xen-devel-request@lists.xensource.com?subject=help>
List-id: Xen developer discussion <xen-devel.lists.xensource.com>
List-post: <mailto:xen-devel@lists.xensource.com>
List-subscribe: <http://lists.xensource.com/mailman/listinfo/xen-devel>, <mailto:xen-devel-request@lists.xensource.com?subject=subscribe>
List-unsubscribe: <http://lists.xensource.com/mailman/listinfo/xen-devel>, <mailto:xen-devel-request@lists.xensource.com?subject=unsubscribe>
Sender: xen-devel-bounces@xxxxxxxxxxxxxxxxxxx
User-agent: Thunderbird 2.0.0.23 (Windows/20090812)
Signed-off-by: Noboru Iwamatsu <n_iwamatsu@xxxxxxxxxxxxxx>

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