diff options
author | Gerd Hoffmann <kraxel@redhat.com> | 2013-11-20 14:10:19 +0100 |
---|---|---|
committer | Gerd Hoffmann <kraxel@redhat.com> | 2013-11-28 15:39:27 +0100 |
commit | e489df40caa96d895d9672d77f536f23c9e42f94 (patch) | |
tree | 66854719e81986f57b616785a646c55082810a4a /hw/usb | |
parent | 72391da50621c9f11bb8c57193ab2d1ad8bc5ad8 (diff) |
ehci: implement port wakeup
Update portsc register and raise irq in case a suspended
port is woken up, so remote wakeup works on our ehci ports.
Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
Diffstat (limited to 'hw/usb')
-rw-r--r-- | hw/usb/hcd-ehci.c | 18 |
1 files changed, 16 insertions, 2 deletions
diff --git a/hw/usb/hcd-ehci.c b/hw/usb/hcd-ehci.c index 22bdbf4a7d..8765f8f5a7 100644 --- a/hw/usb/hcd-ehci.c +++ b/hw/usb/hcd-ehci.c @@ -826,9 +826,9 @@ static void ehci_child_detach(USBPort *port, USBDevice *child) static void ehci_wakeup(USBPort *port) { EHCIState *s = port->opaque; - uint32_t portsc = s->portsc[port->index]; + uint32_t *portsc = &s->portsc[port->index]; - if (portsc & PORTSC_POWNER) { + if (*portsc & PORTSC_POWNER) { USBPort *companion = s->companion_ports[port->index]; if (companion->ops->wakeup) { companion->ops->wakeup(companion); @@ -836,6 +836,12 @@ static void ehci_wakeup(USBPort *port) return; } + if (*portsc & PORTSC_SUSPEND) { + trace_usb_ehci_port_wakeup(port->index); + *portsc |= PORTSC_FPRES; + ehci_raise_irq(s, USBSTS_PCD); + } + qemu_bh_schedule(s->async_bh); } @@ -1067,6 +1073,14 @@ static void ehci_port_write(void *ptr, hwaddr addr, } } + if ((val & PORTSC_SUSPEND) && !(*portsc & PORTSC_SUSPEND)) { + trace_usb_ehci_port_suspend(port); + } + if (!(val & PORTSC_FPRES) && (*portsc & PORTSC_FPRES)) { + trace_usb_ehci_port_resume(port); + val &= ~PORTSC_SUSPEND; + } + *portsc &= ~PORTSC_RO_MASK; *portsc |= val; trace_usb_ehci_portsc_change(addr + s->portscbase, addr >> 2, *portsc, old); |