qemu-devel
[Top][All Lists]
Advanced

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

Re: [Qemu-devel] Large USB patch


From: Lonnie Mendez
Subject: Re: [Qemu-devel] Large USB patch
Date: Sun, 30 Apr 2006 15:56:52 -0500
User-agent: Mozilla Thunderbird 1.0.7 (X11/20050923)

Attached is another patch to implement the said resume code. With this patch, devices attached to windows xp guest are able to resume the controller when necessary. Before, if a device was attached to the usbhub and windows had the root hub set for power savings then the bus would stay suspended.

It implements the function usb_wakeup_controller which can be called with a USBDevice handle for the device that is causing the event.
--- a/qemu/hw/usb-uhci.c        2006-04-30 14:32:43.000000000 -0500
+++ b/qemu/hw/usb-uhci.c        2006-04-30 15:03:46.000000000 -0500
@@ -102,6 +102,7 @@
 } UHCI_QH;
 
 static int uhci_attach (USBDevice *hub, USBDevice *dev, int portnum);
+static void uhci_resume (void *opaque);
 
 static void uhci_update_irq (UHCIState *s)
 {
@@ -338,13 +339,6 @@
     UHCIPort  *port;
     int i;
 
-    // wakeup the controller if suspended
-    if (s->cmd & UHCI_CMD_EGSM) {
-        s->cmd |= UHCI_CMD_FGR;
-        s->status |= UHCI_STS_RD;
-        uhci_update_irq(s);
-    }
-
     if (dev) {
         if( portnum >= NB_PORTS ) {
 #ifdef DEBUG        
@@ -385,6 +379,9 @@
             port->ctrl |= UHCI_PORT_LSDA;
         else
             port->ctrl &= ~UHCI_PORT_LSDA;
+
+        uhci_resume(s);
+
         /* send the attach message */
         port->dev= dev;
         port->dev->handle_msg (port->dev, USB_MSG_ATTACH);
@@ -401,6 +398,9 @@
             port->ctrl &= ~UHCI_PORT_EN;
             port->ctrl |= UHCI_PORT_ENC;
         }
+
+        uhci_resume(s);
+
         if (port->dev) {
             /* send the detach message */
             port->dev->handle_msg(port->dev, USB_MSG_DETACH);
@@ -412,6 +412,21 @@
     }
 }
 
+/* signal resume if controller suspended */
+static void uhci_resume (void *opaque)
+{
+    UHCIState *s = (UHCIState *)opaque;
+
+    if (!s)
+        return;
+
+    if (s->cmd & UHCI_CMD_EGSM) {
+        s->cmd |= UHCI_CMD_FGR;
+        s->status |= UHCI_STS_RD;
+        uhci_update_irq(s);
+    }
+}
+
 static int uhci_broadcast_packet(UHCIState *s, uint8_t pid, 
                                  uint8_t devaddr, uint8_t devep,
                                  uint8_t *data, int len)
@@ -732,6 +738,7 @@
         dev->speed= USB_SPEED_FULL;
         dev->state= USB_STATE_ATTACHED;
         dev->handle_attach= &uhci_attach;
+        dev->handle_resume= &uhci_resume;
         for(i = 0; i < NB_PORTS; i++) {
             s->ports[i].dev= NULL;
         }
--- a/qemu/hw/usb.h     2006-04-30 14:32:43.000000000 -0500
+++ b/qemu/hw/usb.h     2006-04-30 15:14:23.000000000 -0500
@@ -187,6 +187,7 @@
     int         (*handle_data)    (USBDevice *dev, int pid, uint8_t devep,
                                    uint8_t *data, int len);
     int         (*handle_attach)  (USBDevice *hub, USBDevice *dev, int 
portnum);
+    void        (*handle_resume)  (void *opaque);
 };
 
 /* Maximum of simultaneous USB Devices including all USB Controllers */
@@ -212,6 +213,9 @@
 USBDevice*  usb_find_device             (char *path);
 char*       usb_find_name               (USBDevice *device);
 
+/* resumes a suspended controller that given device is attached to */
+void usb_wakeup_controller(USBDevice *dev);
+
 /* function which adds or removes the usb devices according to usb_tree */
 int         usb_update_devices          (PCIBus *pci_bus);
 /* functions which show info on the available usb devices - used by monitor.c*/
--- a/qemu/hw/usb.c     2006-04-30 14:32:43.000000000 -0500
+++ b/qemu/hw/usb.c     2006-04-30 15:14:35.000000000 -0500
@@ -401,6 +408,27 @@
     }
 }
 
+/* communicate resume to host controller */
+void usb_wakeup_controller(USBDevice *dev)
+{
+    USBTree *tree = usb_tree;
+    USBDevice *controller = NULL;
+    char bus_path[5];
+
+    if (dev == NULL)
+        return;
+
+    for (; tree != NULL; tree= tree->next) {
+        if (tree->dev == dev) { // have match - next find root controller
+            strncpy(bus_path, tree->path, 3);
+            controller = usb_find_device(bus_path);
+            if (controller && controller->handle_resume) // send resume if 
implemented
+                controller->handle_resume(controller->opaque);
+            break;
+        }
+    }
+}
+
 /* remove a usb device, the following steps are taken:
     1. find the device
     2. let his father know 
@@ -608,6 +636,7 @@
         dev->handle_msg=        &usb_dummy_handle_msg;
         dev->handle_data=       &usb_dummy_handle_data;
         dev->handle_attach=     &usb_dummy_handle_attach;
+        dev->handle_resume=     NULL;
     }
     return dev;
 }
--- a/qemu/hw/usb-hub.c 2006-04-30 14:33:29.000000000 -0500
+++ b/qemu/hw/usb-hub.c 2006-04-30 15:13:22.000000000 -0500
@@ -212,12 +212,20 @@
             port->wPortStatus |= PORT_STAT_LOW_SPEED;
         else
             port->wPortStatus &= ~PORT_STAT_LOW_SPEED;
+
+        if (hub->remote_wakeup)
+            usb_wakeup_controller(dev);
+
         port->dev = dev;
         port->dev->handle_msg (port->dev, USB_MSG_ATTACH);
         return portnum;    
     } else {
         port = &s->ports[portnum];
         dev = port->dev;
+
+        if (hub->remote_wakeup)
+            usb_wakeup_controller(dev);
+
         if (dev) {
             port->wPortStatus &= ~PORT_STAT_CONNECTION;
             port->wPortChange |= PORT_STAT_C_CONNECTION;

reply via email to

[Prev in Thread] Current Thread [Next in Thread]