diff options
author | Peter Maydell <peter.maydell@linaro.org> | 2016-01-08 11:24:15 +0000 |
---|---|---|
committer | Peter Maydell <peter.maydell@linaro.org> | 2016-01-08 11:24:15 +0000 |
commit | 9df2513730c5902813f575a74ac9303388fd029d (patch) | |
tree | 1a89eddbe1d9e368a0a8e004ceaec734dc32a56c | |
parent | d9767f1bfa1f21f23e51403697be55d5c6280d94 (diff) | |
parent | 087462c7739869e9b888c06c06c8f1bbfd99779c (diff) | |
download | qemu-9df2513730c5902813f575a74ac9303388fd029d.zip qemu-9df2513730c5902813f575a74ac9303388fd029d.tar.gz qemu-9df2513730c5902813f575a74ac9303388fd029d.tar.bz2 |
Merge remote-tracking branch 'remotes/kraxel/tags/pull-usb-20160108-1' into staging
usb: mtp and ohci fixes.
# gpg: Signature made Fri 08 Jan 2016 10:14:59 GMT using RSA key ID D3E87138
# gpg: Good signature from "Gerd Hoffmann (work) <kraxel@redhat.com>"
# gpg: aka "Gerd Hoffmann <gerd@kraxel.org>"
# gpg: aka "Gerd Hoffmann (private) <kraxel@gmail.com>"
* remotes/kraxel/tags/pull-usb-20160108-1:
ohci: clear pending SOF on suspend
ohci: delay first SOF interrupt
usb-mtp: fix call to trace function
usb-mtp: use safe variant when cleaning events list
ohci: fix command HostControllerReset
ohci: fix Host Controller USBRESET
ohci: split reset method in 3 parts
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
-rw-r--r-- | hw/usb/dev-mtp.c | 6 | ||||
-rw-r--r-- | hw/usb/hcd-ohci.c | 83 |
2 files changed, 56 insertions, 33 deletions
diff --git a/hw/usb/dev-mtp.c b/hw/usb/dev-mtp.c index af056c7..4177a87 100644 --- a/hw/usb/dev-mtp.c +++ b/hw/usb/dev-mtp.c @@ -502,9 +502,9 @@ static void inotify_watchfn(void *arg) entry = g_new0(MTPMonEntry, 1); entry->handle = o->handle; entry->event = EVT_OBJ_REMOVED; - usb_mtp_object_free(s, o); trace_usb_mtp_inotify_event(s->dev.addr, o->path, event->mask, "Obj Deleted"); + usb_mtp_object_free(s, o); break; case IN_MODIFY: @@ -556,7 +556,7 @@ static int usb_mtp_inotify_init(MTPState *s) static void usb_mtp_inotify_cleanup(MTPState *s) { - MTPMonEntry *e; + MTPMonEntry *e, *p; if (!s->inotifyfd) { return; @@ -565,7 +565,7 @@ static void usb_mtp_inotify_cleanup(MTPState *s) qemu_set_fd_handler(s->inotifyfd, NULL, NULL, s); close(s->inotifyfd); - QTAILQ_FOREACH(e, &s->events, next) { + QTAILQ_FOREACH_SAFE(e, &s->events, next, p) { QTAILQ_REMOVE(&s->events, e, next); g_free(e); } diff --git a/hw/usb/hcd-ohci.c b/hw/usb/hcd-ohci.c index 7d65818..efeaf73 100644 --- a/hw/usb/hcd-ohci.c +++ b/hw/usb/hcd-ohci.c @@ -439,15 +439,37 @@ static void ohci_stop_endpoints(OHCIState *ohci) } } -/* Reset the controller */ -static void ohci_reset(void *opaque) +static void ohci_roothub_reset(OHCIState *ohci) { - OHCIState *ohci = opaque; OHCIPort *port; int i; ohci_bus_stop(ohci); - ohci->ctl = 0; + ohci->rhdesc_a = OHCI_RHA_NPS | ohci->num_ports; + ohci->rhdesc_b = 0x0; /* Impl. specific */ + ohci->rhstatus = 0; + + for (i = 0; i < ohci->num_ports; i++) { + port = &ohci->rhport[i]; + port->ctrl = 0; + if (port->port.dev && port->port.dev->attached) { + usb_port_reset(&port->port); + } + } + if (ohci->async_td) { + usb_cancel_packet(&ohci->usb_packet); + ohci->async_td = 0; + } + ohci_stop_endpoints(ohci); +} + +/* Reset the controller */ +static void ohci_soft_reset(OHCIState *ohci) +{ + trace_usb_ohci_reset(ohci->name); + + ohci_bus_stop(ohci); + ohci->ctl = (ohci->ctl & OHCI_CTL_IR) | OHCI_USB_SUSPEND; ohci->old_ctl = 0; ohci->status = 0; ohci->intr_status = 0; @@ -470,25 +492,13 @@ static void ohci_reset(void *opaque) ohci->frame_number = 0; ohci->pstart = 0; ohci->lst = OHCI_LS_THRESH; +} - ohci->rhdesc_a = OHCI_RHA_NPS | ohci->num_ports; - ohci->rhdesc_b = 0x0; /* Impl. specific */ - ohci->rhstatus = 0; - - for (i = 0; i < ohci->num_ports; i++) - { - port = &ohci->rhport[i]; - port->ctrl = 0; - if (port->port.dev && port->port.dev->attached) { - usb_port_reset(&port->port); - } - } - if (ohci->async_td) { - usb_cancel_packet(&ohci->usb_packet); - ohci->async_td = 0; - } - ohci_stop_endpoints(ohci); - trace_usb_ohci_reset(ohci->name); +static void ohci_hard_reset(OHCIState *ohci) +{ + ohci_soft_reset(ohci); + ohci->ctl = 0; + ohci_roothub_reset(ohci); } /* Get an array of dwords from main memory */ @@ -1231,11 +1241,16 @@ static int ohci_service_ed_list(OHCIState *ohci, uint32_t head, int completion) return active; } -/* Generate a SOF event, and set a timer for EOF */ -static void ohci_sof(OHCIState *ohci) +/* set a timer for EOF */ +static void ohci_eof_timer(OHCIState *ohci) { ohci->sof_time = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL); timer_mod(ohci->eof_timer, ohci->sof_time + usb_frame_time); +} +/* Set a timer for EOF and generate a SOF event */ +static void ohci_sof(OHCIState *ohci) +{ + ohci_eof_timer(ohci); ohci_set_interrupt(ohci, OHCI_INTR_SF); } @@ -1343,7 +1358,12 @@ static int ohci_bus_start(OHCIState *ohci) trace_usb_ohci_start(ohci->name); - ohci_sof(ohci); + /* Delay the first SOF event by one frame time as + * linux driver is not ready to receive it and + * can meet some race conditions + */ + + ohci_eof_timer(ohci); return 1; } @@ -1436,12 +1456,15 @@ static void ohci_set_ctl(OHCIState *ohci, uint32_t val) break; case OHCI_USB_SUSPEND: ohci_bus_stop(ohci); + /* clear pending SF otherwise linux driver loops in ohci_irq() */ + ohci->intr_status &= ~OHCI_INTR_SF; + ohci_intr_update(ohci); break; case OHCI_USB_RESUME: trace_usb_ohci_resume(ohci->name); break; case OHCI_USB_RESET: - ohci_reset(ohci); + ohci_roothub_reset(ohci); break; } } @@ -1704,7 +1727,7 @@ static void ohci_mem_write(void *opaque, ohci->status |= val; if (ohci->status & OHCI_STATUS_HCR) - ohci_reset(ohci); + ohci_soft_reset(ohci); break; case 3: /* HcInterruptStatus */ @@ -1783,7 +1806,7 @@ static void ohci_mem_write(void *opaque, case 25: /* HcHReset */ ohci->hreset = val & ~OHCI_HRESET_FSBIR; if (val & OHCI_HRESET_FSBIR) - ohci_reset(ohci); + ohci_hard_reset(ohci); break; case 26: /* HcHInterruptEnable */ @@ -1960,7 +1983,7 @@ static void usb_ohci_reset_pci(DeviceState *d) OHCIPCIState *ohci = PCI_OHCI(dev); OHCIState *s = &ohci->state; - ohci_reset(s); + ohci_hard_reset(s); } #define TYPE_SYSBUS_OHCI "sysbus-ohci" @@ -1993,7 +2016,7 @@ static void usb_ohci_reset_sysbus(DeviceState *dev) OHCISysBusState *s = SYSBUS_OHCI(dev); OHCIState *ohci = &s->ohci; - ohci_reset(ohci); + ohci_hard_reset(ohci); } static Property ohci_pci_properties[] = { |