aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPeter Maydell <peter.maydell@linaro.org>2016-01-08 11:24:15 +0000
committerPeter Maydell <peter.maydell@linaro.org>2016-01-08 11:24:15 +0000
commit9df2513730c5902813f575a74ac9303388fd029d (patch)
tree1a89eddbe1d9e368a0a8e004ceaec734dc32a56c
parentd9767f1bfa1f21f23e51403697be55d5c6280d94 (diff)
parent087462c7739869e9b888c06c06c8f1bbfd99779c (diff)
downloadqemu-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.c6
-rw-r--r--hw/usb/hcd-ohci.c83
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[] = {