summary refs log tree commit diff stats
path: root/hw/usb-ohci.c
diff options
context:
space:
mode:
Diffstat (limited to 'hw/usb-ohci.c')
-rw-r--r--hw/usb-ohci.c37
1 files changed, 36 insertions, 1 deletions
diff --git a/hw/usb-ohci.c b/hw/usb-ohci.c
index a67556af41..5d2ae01235 100644
--- a/hw/usb-ohci.c
+++ b/hw/usb-ohci.c
@@ -367,6 +367,22 @@ static void ohci_detach(USBPort *port1)
         ohci_set_interrupt(s, OHCI_INTR_RHSC);
 }
 
+static void ohci_wakeup(USBDevice *dev)
+{
+    USBBus *bus = usb_bus_from_device(dev);
+    OHCIState *s = container_of(bus, OHCIState, bus);
+    int portnum = dev->port->index;
+    OHCIPort *port = &s->rhport[portnum];
+    if (port->ctrl & OHCI_PORT_PSS) {
+        DPRINTF("usb-ohci: port %d: wakeup\n", portnum);
+        port->ctrl |= OHCI_PORT_PSSC;
+        port->ctrl &= ~OHCI_PORT_PSS;
+        if ((s->ctl & OHCI_CTL_HCFS) == OHCI_USB_SUSPEND) {
+            ohci_set_interrupt(s, OHCI_INTR_RD);
+        }
+    }
+}
+
 /* Reset the controller */
 static void ohci_reset(void *opaque)
 {
@@ -1575,6 +1591,10 @@ static void ohci_mem_write(void *ptr, target_phys_addr_t addr, uint32_t val)
         ohci->hcca = val & OHCI_HCCA_MASK;
         break;
 
+    case 7: /* HcPeriodCurrentED */
+        /* Ignore writes to this read-only register, Linux does them */
+        break;
+
     case 8: /* HcControlHeadED */
         ohci->ctrl_head = val & OHCI_EDPTR_MASK;
         break;
@@ -1644,6 +1664,16 @@ static void ohci_mem_write(void *ptr, target_phys_addr_t addr, uint32_t val)
     }
 }
 
+static void ohci_device_destroy(USBBus *bus, USBDevice *dev)
+{
+    OHCIState *ohci = container_of(bus, OHCIState, bus);
+
+    if (ohci->async_td && ohci->usb_packet.owner == dev) {
+        usb_cancel_packet(&ohci->usb_packet);
+        ohci->async_td = 0;
+    }
+}
+
 /* Only dword reads are defined on OHCI register space */
 static CPUReadMemoryFunc * const ohci_readfn[3]={
     ohci_mem_read,
@@ -1661,9 +1691,14 @@ static CPUWriteMemoryFunc * const ohci_writefn[3]={
 static USBPortOps ohci_port_ops = {
     .attach = ohci_attach,
     .detach = ohci_detach,
+    .wakeup = ohci_wakeup,
     .complete = ohci_async_complete_packet,
 };
 
+static USBBusOps ohci_bus_ops = {
+    .device_destroy = ohci_device_destroy,
+};
+
 static void usb_ohci_init(OHCIState *ohci, DeviceState *dev,
                           int num_ports, uint32_t localmem_base)
 {
@@ -1691,7 +1726,7 @@ static void usb_ohci_init(OHCIState *ohci, DeviceState *dev,
 
     ohci->name = dev->info->name;
 
-    usb_bus_new(&ohci->bus, dev);
+    usb_bus_new(&ohci->bus, &ohci_bus_ops, dev);
     ohci->num_ports = num_ports;
     for (i = 0; i < num_ports; i++) {
         usb_register_port(&ohci->bus, &ohci->rhport[i].port, ohci, i, &ohci_port_ops,