diff options
Diffstat (limited to 'hw/usb-ohci.c')
-rw-r--r-- | hw/usb-ohci.c | 37 |
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, |