aboutsummaryrefslogtreecommitdiff
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,