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 1/3] PVUSB update and bugfix: frontend part

To: xen-devel@xxxxxxxxxxxxxxxxxxx
Subject: [Xen-devel] [PATCH 1/3] PVUSB update and bugfix: frontend part
From: Noboru Iwamatsu <n_iwamatsu@xxxxxxxxxxxxxx>
Date: Wed, 07 Oct 2009 16:27:49 +0900
Delivery-date: Wed, 07 Oct 2009 00:29:40 -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/usbfront/usbfront-dbg.c
--- a/drivers/xen/usbfront/usbfront-dbg.c       Tue Sep 29 11:23:06 2009 +0100
+++ b/drivers/xen/usbfront/usbfront-dbg.c       Tue Oct 06 15:18:27 2009 +0900
@@ -60,7 +60,7 @@
 
        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 @@
 #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 4ac3e1d6605c -r 3be939975ad6 drivers/xen/usbfront/usbfront-hcd.c
--- a/drivers/xen/usbfront/usbfront-hcd.c       Tue Sep 29 11:23:06 2009 +0100
+++ b/drivers/xen/usbfront/usbfront-hcd.c       Tue Oct 06 15:18:27 2009 +0900
@@ -54,7 +54,7 @@
        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 @@
        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,70 +102,14 @@
        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()
  * non-error returns are promise to giveback the urb later
  */
@@ -197,11 +142,6 @@
 
 /*
  * 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 @@
        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 4ac3e1d6605c -r 3be939975ad6 drivers/xen/usbfront/usbfront-hub.c
--- a/drivers/xen/usbfront/usbfront-hub.c       Tue Sep 29 11:23:06 2009 +0100
+++ b/drivers/xen/usbfront/usbfront-hub.c       Tue Oct 06 15:18:27 2009 +0900
@@ -50,15 +50,16 @@
 {
        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;
@@ -86,6 +87,9 @@
 {
        int port;
 
+       if (portnum < 1 || portnum > info->rh_numports)
+               return; /* invalid port number */
+
        port = portnum - 1;
        if (info->devices[port].speed != speed) {
                switch (speed) {
@@ -107,30 +111,6 @@
        }
 }
 
-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));
-}
-
 /*
  * SetPortFeature(PORT_SUSPENDED)
  */
@@ -214,7 +194,7 @@
 {
        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,57 +207,51 @@
        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;
+       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);
        }
-
-       /* suspend any active ports*/
-       for (i = 1; i <= ports; i++) {
-               rhport_suspend(info, i);
-       }
+       spin_unlock_irq(&info->lock);
 
        del_timer_sync(&info->watchdog);
 
-       spin_unlock_irq(&info->lock);
-
-       return 0;
+       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);
-       /* resume any suspended ports*/
-       for (i = 1; i <= ports; i++) {
-               rhport_resume(info, i);
+       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);
        }
-       hcd->state = HC_STATE_RUNNING;
        spin_unlock_irq(&info->lock);
-       return 0;
+
+       return ret;
 }
 #endif
-#endif
 
 static void xenhcd_hub_descriptor(struct usbfront_info *info,
                                  struct usb_hub_descriptor *desc)
@@ -295,8 +269,8 @@
        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 @@
        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 @@
                if (!wIndex || wIndex > ports)
                        goto error;
 
-               switch(wValue) {
+               switch (wValue) {
                case USB_PORT_FEAT_SUSPEND:
                        rhport_resume(info, wIndex);
                        break;
@@ -414,7 +383,7 @@
                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 @@
                                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 @@
                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 @@
                        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 @@
 
        /* 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 4ac3e1d6605c -r 3be939975ad6 drivers/xen/usbfront/usbfront-q.c
--- a/drivers/xen/usbfront/usbfront-q.c Tue Sep 29 11:23:06 2009 +0100
+++ b/drivers/xen/usbfront/usbfront-q.c Tue Oct 06 15:18:27 2009 +0900
@@ -50,13 +50,13 @@
        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 @@
 {
        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, 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 @@
 
        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 @@
                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 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 @@
                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 @@
 
        for (i = 0; i < nr_segs; i++)
                gnttab_end_foreign_access(shadow->req.seg[i].gref, 0UL);
+
+       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)
+static void xenhcd_giveback_urb(struct usbfront_info *info, struct urb *urb, 
int status)
 __releases(info->lock)
 __acquires(info->lock)
 {
@@ -228,6 +229,9 @@
        case -ENOENT:
                COUNT(info->stats.unlink);
                break;
+       case -EINPROGRESS:
+               urb->status = status;
+               /* falling through */
        default:
                COUNT(info->stats.complete);
        }
@@ -238,28 +242,35 @@
 
 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;
+       req->id = id;
 
-       ret = map_urb_for_request(info, urb, ring_req);
-       if (ret < 0) {
-               add_id_to_freelist(info, id);
-               return ret;
+       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->ring.req_prod_pvt++;
+       info->urb_ring.req_prod_pvt++;
        info->shadow[id].urb = urb;
-       info->shadow[id].req = *ring_req;
-       urbp->req_id = id;
+       info->shadow[id].req = *req;
 
-       RING_PUSH_REQUESTS_AND_CHECK_NOTIFY(&info->ring, notify);
+       RING_PUSH_REQUESTS_AND_CHECK_NOTIFY(&info->urb_ring, notify);
        if (notify)
                notify_remote_via_irq(info->irq);
 
@@ -271,19 +282,19 @@
        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 @@
        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 @@
 {
        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 @@
 
 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);
+               goto done;
        }
 
-       /* TODO: send cancel request to backend */
+       /* 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;
+       }
 
-       return 0;
+       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_end_submit_urb(struct usbfront_info *info)
+static int xenhcd_urb_request_done(struct usbfront_info *info)
 {
-       usbif_response_t *ring_res;
+       usbif_urb_response_t *res;
        struct urb *urb;
-       struct urb_priv *urbp;
 
        RING_IDX i, rp;
        uint16_t id;
@@ -354,33 +415,35 @@
        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;
-               barrier();
+       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;
 
-               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);
+       if (i != info->urb_ring.req_prod_pvt)
+               RING_FINAL_CHECK_FOR_RESPONSES(&info->urb_ring, more_to_do);
        else
-               info->ring.sring->rsp_event = i + 1;
+               info->urb_ring.sring->rsp_event = i + 1;
 
        spin_unlock_irqrestore(&info->lock, flags);
 
@@ -389,6 +452,61 @@
        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();
+
+               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->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();
+
+       return more_to_do;
+}
+
 int xenhcd_schedule(void *arg)
 {
        struct usbfront_info *info = (struct usbfront_info *) arg;
@@ -400,7 +518,10 @@
                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 4ac3e1d6605c -r 3be939975ad6 drivers/xen/usbfront/usbfront.h
--- a/drivers/xen/usbfront/usbfront.h   Tue Sep 29 11:23:06 2009 +0100
+++ b/drivers/xen/usbfront/usbfront.h   Tue Oct 06 15:18:27 2009 +0900
@@ -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 usb_hcd *info_to_hcd(struct usbfront_info *info)
 {
-       return container_of ((void *) info, struct usb_hcd, hcd_priv);
+       return container_of((void *) info, struct usb_hcd, hcd_priv);
 }
 
-/*
- * Private per-URB data
- */
+/* 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 @@
 
 /* RING request shadow */
 struct usb_shadow {
-       usbif_request_t req;
+       usbif_urb_request_t req;
        struct urb *urb;
 };
 
@@ -117,62 +114,46 @@
 };
 
 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 @@
        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 @@
        }
 }
 
+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 4ac3e1d6605c -r 3be939975ad6 drivers/xen/usbfront/xenbus.c
--- a/drivers/xen/usbfront/xenbus.c     Tue Sep 29 11:23:06 2009 +0100
+++ b/drivers/xen/usbfront/xenbus.c     Tue Oct 06 15:18:27 2009 +0900
@@ -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)
+static void destroy_rings(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;
-       }
        if (info->irq)
                unbind_from_irqhandler(info->irq, info);
        info->irq = 0;
+
+       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_usbring(struct xenbus_device *dev,
+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;
+       info->urb_ring_ref = GRANT_INVALID_REF;
+       info->conn_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");
+       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);
+       SHARED_RING_INIT(urb_sring);
+       FRONT_RING_INIT(&info->urb_ring, urb_sring, PAGE_SIZE);
 
-       err = xenbus_grant_ring(dev, virt_to_mfn(info->ring.sring));
+       err = xenbus_grant_ring(dev, virt_to_mfn(info->urb_ring.sring));
        if (err < 0) {
-               free_page((unsigned long)sring);
-               info->ring.sring = NULL;
+               free_page((unsigned long)urb_sring);
+               info->urb_ring.sring = NULL;
                goto fail;
        }
-       info->ring_ref = err;
+       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 @@
 
        return 0;
 fail:
-       usbif_free(info);
+       destroy_rings(info);
        return err;
 }
 
@@ -112,7 +132,7 @@
        struct xenbus_transaction xbt;
        int err;
 
-       err = setup_usbring(dev, info);
+       err = setup_rings(dev, info);
        if (err)
                goto out;
 
@@ -123,10 +143,17 @@
                goto destroy_ring;
        }
 
-       err = xenbus_printf(xbt, dev->nodename, "ring-ref", "%u",
-                           info->ring_ref);
+       err = xenbus_printf(xbt, dev->nodename, "urb-ring-ref", "%u",
+                           info->urb_ring_ref);
        if (err) {
-               message = "writing ring-ref";
+               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 @@
                goto destroy_ring;
        }
 
-       xenbus_switch_state(dev, XenbusStateInitialised);
-
        return 0;
 
 abort_transaction:
@@ -154,17 +179,45 @@
        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)
 {
        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 @@
                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 @@
        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 @@
 
        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)
+       if (IS_ERR(info->kthread)) {
+               err = PTR_ERR(info->kthread);
+               info->kthread = NULL;
                goto fail;
+       }
 
        return 0;
 
@@ -245,58 +314,41 @@
        return err;
 }
 
-/*
- * 0=disconnected, 1=low_speed, 2=full_speed, 3=high_speed
- */
-static void usbfront_do_hotplug(struct usbfront_info *info)
+static void usbfront_disconnect(struct xenbus_device *dev)
 {
-       char port_str[8];
-       int i;
-       int err;
-       int state;
+       struct usbfront_info *info = dev->dev.driver_data;
+       struct usb_hcd *hcd = info_to_hcd(info);
 
-       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);
+       usb_remove_hcd(hcd);
+       if (info->kthread) {
+               kthread_stop(info->kthread);
+               info->kthread = NULL;
        }
+       xenbus_frontend_closed(dev);
 }
 
 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 XenbusStateConnected:
+       case XenbusStateReconfiguring:
+       case XenbusStateReconfigured:
        case XenbusStateUnknown:
        case XenbusStateClosed:
                break;
 
-       case XenbusStateConnected:
-               if (dev->state == XenbusStateConnected)
+       case XenbusStateInitWait:
+               if (dev->state != XenbusStateInitialising)
                        break;
-               if (dev->state == XenbusStateInitialised)
-                       usbfront_do_hotplug(info);
+               connect(dev);
                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);
+               usbfront_disconnect(dev);
                break;
 
        default:
@@ -311,12 +363,7 @@
        struct usbfront_info *info = dev->dev.driver_data;
        struct usb_hcd *hcd = info_to_hcd(info);
 
-       usb_remove_hcd(hcd);
-       if (info->kthread) {
-               kthread_stop(info->kthread);
-               info->kthread = NULL;
-       }
-       usbif_free(info);
+       destroy_rings(info);
        usb_put_hcd(hcd);
 
        return 0;
@@ -361,5 +408,5 @@
 module_exit(usbfront_exit);
 
 MODULE_AUTHOR("");
-MODULE_DESCRIPTION(DRIVER_DESC);
+MODULE_DESCRIPTION("Xen USB Virtual Host Controller driver (usbfront)");
 MODULE_LICENSE("Dual BSD/GPL");
_______________________________________________
Xen-devel mailing list
Xen-devel@xxxxxxxxxxxxxxxxxxx
http://lists.xensource.com/xen-devel
<Prev in Thread] Current Thread [Next in Thread>