From d3ac1a87b228bcd231d19acf1ebe9844b7639237 Mon Sep 17 00:00:00 2001 From: Gerd Hoffmann Date: Fri, 2 Sep 2011 13:05:13 +0200 Subject: usb-storage: fix NULL pointer dereference. When a usb packet is canceled we need to check whenever we actually have a scsi request in flight before we try to cancel it. Signed-off-by: Gerd Hoffmann --- hw/usb-msd.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) (limited to 'hw') diff --git a/hw/usb-msd.c b/hw/usb-msd.c index e92434c..08d2d2a 100644 --- a/hw/usb-msd.c +++ b/hw/usb-msd.c @@ -325,7 +325,10 @@ static int usb_msd_handle_control(USBDevice *dev, USBPacket *p, static void usb_msd_cancel_io(USBDevice *dev, USBPacket *p) { MSDState *s = DO_UPCAST(MSDState, dev, dev); - scsi_req_cancel(s->req); + + if (s->req) { + scsi_req_cancel(s->req); + } } static int usb_msd_handle_data(USBDevice *dev, USBPacket *p) -- cgit v1.1 From 3393bc105d58e1f4a27d9a8e7062da9cef260cc3 Mon Sep 17 00:00:00 2001 From: Gerd Hoffmann Date: Thu, 15 Sep 2011 09:20:02 +0200 Subject: usb-hub: need to check dev->attached commit 891fb2cd4592b6fe76106a69e0ca40efbf82726a did that for all host controllers, the usb hub was left out by accident. Signed-off-by: Gerd Hoffmann --- hw/usb-hub.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'hw') diff --git a/hw/usb-hub.c b/hw/usb-hub.c index 286e3ad..39382c7 100644 --- a/hw/usb-hub.c +++ b/hw/usb-hub.c @@ -289,7 +289,7 @@ static int usb_hub_handle_control(USBDevice *dev, USBPacket *p, port->wPortStatus |= PORT_STAT_SUSPEND; break; case PORT_RESET: - if (dev) { + if (dev && dev->attached) { usb_send_msg(dev, USB_MSG_RESET); port->wPortChange |= PORT_STAT_C_RESET; /* set enable bit */ @@ -429,7 +429,7 @@ static int usb_hub_broadcast_packet(USBHubState *s, USBPacket *p) for(i = 0; i < NUM_PORTS; i++) { port = &s->ports[i]; dev = port->port.dev; - if (dev && (port->wPortStatus & PORT_STAT_ENABLE)) { + if (dev && dev->attached && (port->wPortStatus & PORT_STAT_ENABLE)) { ret = usb_handle_packet(dev, p); if (ret != USB_RET_NODEV) { return ret; -- cgit v1.1 From e0b8e72dd95f5fe133c8bb952a464814ca06fe8b Mon Sep 17 00:00:00 2001 From: Gerd Hoffmann Date: Thu, 15 Sep 2011 12:10:21 +0200 Subject: usb: fix port reset commit 891fb2cd4592b6fe76106a69e0ca40efbf82726a removed the implicit detach before (re-)attaching in usb_attach(). Some usb host controllers used that behavior though to do a port reset by a detach+attach sequence. This patch establishes old behavior by adding a new usb_reset() function for port resets and putting it into use, thereby also unifying port reset behavior of all host controllers. The patch also adds asserts to usb_attach() and usb_detach() to make sure the calls are symmetrical. Signed-off-by: Gerd Hoffmann --- hw/usb-ehci.c | 4 ++-- hw/usb-ohci.c | 2 +- hw/usb-uhci.c | 2 +- hw/usb.c | 12 ++++++++++++ hw/usb.h | 1 + 5 files changed, 17 insertions(+), 4 deletions(-) (limited to 'hw') diff --git a/hw/usb-ehci.c b/hw/usb-ehci.c index 27376a2..bd374c1 100644 --- a/hw/usb-ehci.c +++ b/hw/usb-ehci.c @@ -880,6 +880,7 @@ static void ehci_reset(void *opaque) } if (devs[i] && devs[i]->attached) { usb_attach(&s->ports[i]); + usb_send_msg(devs[i], USB_MSG_RESET); } } ehci_queues_rip_all(s); @@ -978,8 +979,7 @@ static void handle_port_status_write(EHCIState *s, int port, uint32_t val) if (!(val & PORTSC_PRESET) &&(*portsc & PORTSC_PRESET)) { trace_usb_ehci_port_reset(port, 0); if (dev && dev->attached) { - usb_attach(&s->ports[port]); - usb_send_msg(dev, USB_MSG_RESET); + usb_reset(&s->ports[port]); *portsc &= ~PORTSC_CSC; } diff --git a/hw/usb-ohci.c b/hw/usb-ohci.c index c3be65a..5e10e21 100644 --- a/hw/usb-ohci.c +++ b/hw/usb-ohci.c @@ -449,7 +449,7 @@ static void ohci_reset(void *opaque) port = &ohci->rhport[i]; port->ctrl = 0; if (port->port.dev && port->port.dev->attached) { - usb_attach(&port->port); + usb_reset(&port->port); } } if (ohci->async_td) { diff --git a/hw/usb-uhci.c b/hw/usb-uhci.c index 17992cf..171d787 100644 --- a/hw/usb-uhci.c +++ b/hw/usb-uhci.c @@ -341,7 +341,7 @@ static void uhci_reset(void *opaque) port = &s->ports[i]; port->ctrl = 0x0080; if (port->port.dev && port->port.dev->attached) { - usb_attach(&port->port); + usb_reset(&port->port); } } diff --git a/hw/usb.c b/hw/usb.c index fa90204..2216efe 100644 --- a/hw/usb.c +++ b/hw/usb.c @@ -33,6 +33,7 @@ void usb_attach(USBPort *port) assert(dev != NULL); assert(dev->attached); + assert(dev->state == USB_STATE_NOTATTACHED); port->ops->attach(port); usb_send_msg(dev, USB_MSG_ATTACH); } @@ -42,10 +43,21 @@ void usb_detach(USBPort *port) USBDevice *dev = port->dev; assert(dev != NULL); + assert(dev->state != USB_STATE_NOTATTACHED); port->ops->detach(port); usb_send_msg(dev, USB_MSG_DETACH); } +void usb_reset(USBPort *port) +{ + USBDevice *dev = port->dev; + + assert(dev != NULL); + usb_detach(port); + usb_attach(port); + usb_send_msg(dev, USB_MSG_RESET); +} + void usb_wakeup(USBDevice *dev) { if (dev->remote_wakeup && dev->port && dev->port->ops->wakeup) { diff --git a/hw/usb.h b/hw/usb.h index c08d469..c6e1870 100644 --- a/hw/usb.h +++ b/hw/usb.h @@ -306,6 +306,7 @@ void usb_cancel_packet(USBPacket * p); void usb_attach(USBPort *port); void usb_detach(USBPort *port); +void usb_reset(USBPort *port); void usb_wakeup(USBDevice *dev); int usb_generic_handle_packet(USBDevice *s, USBPacket *p); void usb_generic_async_ctrl_complete(USBDevice *s, USBPacket *p); -- cgit v1.1 From 8d11b78c9a243ae2d9cf27a15216f8554b6fc63d Mon Sep 17 00:00:00 2001 From: Peter Maydell Date: Wed, 14 Sep 2011 18:49:00 +0100 Subject: hw/usb-ohci: Fix OHCI_TD_T1 bit position definition The OHCI Transfer Descriptor T (DataToggle) bits are 24 and 25; fix an error which accidentally overlaid them both on the same bit. Signed-off-by: Peter Maydell Signed-off-by: Gerd Hoffmann --- hw/usb-ohci.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'hw') diff --git a/hw/usb-ohci.c b/hw/usb-ohci.c index 5e10e21..e14ced8 100644 --- a/hw/usb-ohci.c +++ b/hw/usb-ohci.c @@ -150,7 +150,7 @@ static void ohci_async_cancel_device(OHCIState *ohci, USBDevice *dev); #define OHCI_TD_DI_SHIFT 21 #define OHCI_TD_DI_MASK (7< Date: Wed, 14 Sep 2011 18:48:59 +0100 Subject: hw/usb-ohci: Honour endpoint maximum packet size Honour the maximum packet size for endpoints; this applies when sending non-isochronous data and means we transfer only as much as the endpoint allows, leaving the transfer descriptor on the list for another go next time around. This allows usb-net to work when connected to an OHCI controller model. Signed-off-by: Peter Maydell Signed-off-by: Gerd Hoffmann --- hw/usb-ohci.c | 37 +++++++++++++++++++++++++++---------- 1 file changed, 27 insertions(+), 10 deletions(-) (limited to 'hw') diff --git a/hw/usb-ohci.c b/hw/usb-ohci.c index e14ced8..c2981c5 100644 --- a/hw/usb-ohci.c +++ b/hw/usb-ohci.c @@ -872,7 +872,7 @@ static int ohci_service_iso_td(OHCIState *ohci, struct ohci_ed *ed, static int ohci_service_td(OHCIState *ohci, struct ohci_ed *ed) { int dir; - size_t len = 0; + size_t len = 0, pktlen = 0; #ifdef DEBUG_PACKET const char *str = NULL; #endif @@ -940,20 +940,30 @@ static int ohci_service_td(OHCIState *ohci, struct ohci_ed *ed) len = (td.be - td.cbp) + 1; } - if (len && dir != OHCI_TD_DIR_IN && !completion) { - ohci_copy_td(ohci, &td, ohci->usb_buf, len, 0); + pktlen = len; + if (len && dir != OHCI_TD_DIR_IN) { + /* The endpoint may not allow us to transfer it all now */ + pktlen = (ed->flags & OHCI_ED_MPS_MASK) >> OHCI_ED_MPS_SHIFT; + if (pktlen > len) { + pktlen = len; + } + if (!completion) { + ohci_copy_td(ohci, &td, ohci->usb_buf, pktlen, 0); + } } } flag_r = (td.flags & OHCI_TD_R) != 0; #ifdef DEBUG_PACKET - DPRINTF(" TD @ 0x%.8x %" PRId64 " bytes %s r=%d cbp=0x%.8x be=0x%.8x\n", - addr, (int64_t)len, str, flag_r, td.cbp, td.be); + DPRINTF(" TD @ 0x%.8x %" PRId64 " of %" PRId64 + " bytes %s r=%d cbp=0x%.8x be=0x%.8x\n", + addr, (int64_t)pktlen, (int64_t)len, str, flag_r, td.cbp, td.be); - if (len > 0 && dir != OHCI_TD_DIR_IN) { + if (pktlen > 0 && dir != OHCI_TD_DIR_IN) { DPRINTF(" data:"); - for (i = 0; i < len; i++) + for (i = 0; i < pktlen; i++) { printf(" %.2x", ohci->usb_buf[i]); + } DPRINTF("\n"); } #endif @@ -982,7 +992,7 @@ static int ohci_service_td(OHCIState *ohci, struct ohci_ed *ed) usb_packet_setup(&ohci->usb_packet, pid, OHCI_BM(ed->flags, ED_FA), OHCI_BM(ed->flags, ED_EN)); - usb_packet_addbuf(&ohci->usb_packet, ohci->usb_buf, len); + usb_packet_addbuf(&ohci->usb_packet, ohci->usb_buf, pktlen); ret = usb_handle_packet(dev, &ohci->usb_packet); if (ret != USB_RET_NODEV) break; @@ -1005,12 +1015,12 @@ static int ohci_service_td(OHCIState *ohci, struct ohci_ed *ed) DPRINTF("\n"); #endif } else { - ret = len; + ret = pktlen; } } /* Writeback */ - if (ret == len || (dir == OHCI_TD_DIR_IN && ret >= 0 && flag_r)) { + if (ret == pktlen || (dir == OHCI_TD_DIR_IN && ret >= 0 && flag_r)) { /* Transmission succeeded. */ if (ret == len) { td.cbp = 0; @@ -1026,6 +1036,12 @@ static int ohci_service_td(OHCIState *ohci, struct ohci_ed *ed) OHCI_SET_BM(td.flags, TD_CC, OHCI_CC_NOERROR); OHCI_SET_BM(td.flags, TD_EC, 0); + if ((dir != OHCI_TD_DIR_IN) && (ret != len)) { + /* Partial packet transfer: TD not ready to retire yet */ + goto exit_no_retire; + } + + /* Setting ED_C is part of the TD retirement process */ ed->head &= ~OHCI_ED_C; if (td.flags & OHCI_TD_T0) ed->head |= OHCI_ED_C; @@ -1066,6 +1082,7 @@ static int ohci_service_td(OHCIState *ohci, struct ohci_ed *ed) i = OHCI_BM(td.flags, TD_DI); if (i < ohci->done_count) ohci->done_count = i; +exit_no_retire: ohci_put_td(ohci, addr, &td); return OHCI_BM(td.flags, TD_CC) != OHCI_CC_NOERROR; } -- cgit v1.1 From 3a3286bf0be8582854b3d451700ae38849b83b7c Mon Sep 17 00:00:00 2001 From: Gerd Hoffmann Date: Wed, 12 Oct 2011 12:54:35 +0200 Subject: usb-hid: activate usb tablet / mouse after migration. qemu uses the ps/2 mouse by default. The usb tablet (or mouse) is activated as soon as qemu sees some guest activity on the device, i.e. polling for HID events. That used to work fine for both fresh boot and migration. Remote wakeup support changed the picture though: There will be no polling after migration in case the guest suspended the usb bus, waiting for wakeup events. Result is that the ps/2 mouse stays active. Fix this by activating the usb tablet / mouse in post_load() in case the guest enabled remote wakeup. Signed-off-by: Gerd Hoffmann --- hw/usb-hid.c | 11 +++++++++++ 1 file changed, 11 insertions(+) (limited to 'hw') diff --git a/hw/usb-hid.c b/hw/usb-hid.c index ba79466..a110c74 100644 --- a/hw/usb-hid.c +++ b/hw/usb-hid.c @@ -527,10 +527,21 @@ static int usb_keyboard_initfn(USBDevice *dev) return usb_hid_initfn(dev, HID_KEYBOARD); } +static int usb_ptr_post_load(void *opaque, int version_id) +{ + USBHIDState *s = opaque; + + if (s->dev.remote_wakeup) { + hid_pointer_activate(&s->hid); + } + return 0; +} + static const VMStateDescription vmstate_usb_ptr = { .name = "usb-ptr", .version_id = 1, .minimum_version_id = 1, + .post_load = usb_ptr_post_load, .fields = (VMStateField []) { VMSTATE_USB_DEVICE(dev, USBHIDState), VMSTATE_HID_POINTER_DEVICE(hid, USBHIDState), -- cgit v1.1 From 80cf7cf74f29a219e02b50f27c12b1c792ebf99b Mon Sep 17 00:00:00 2001 From: Gerd Hoffmann Date: Thu, 13 Oct 2011 12:52:47 +0200 Subject: usb-hub: don't trigger assert on packet completion. Calling usb_packet_complete() recursively when passing up the completion event up the chain for devices connected via usb hub will trigger an assert. So don't do that, make the usb hub emulation call the upstream completion callback directly instead. Based on a patch from Stefan Hajnoczi Signed-off-by: Gerd Hoffmann --- hw/usb-hub.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) (limited to 'hw') diff --git a/hw/usb-hub.c b/hw/usb-hub.c index 39382c7..09c6516 100644 --- a/hw/usb-hub.c +++ b/hw/usb-hub.c @@ -207,10 +207,14 @@ static void usb_hub_complete(USBPort *port, USBPacket *packet) /* * Just pass it along upstream for now. * - * If we ever inplement usb 2.0 split transactions this will + * If we ever implement usb 2.0 split transactions this will * become a little more complicated ... + * + * Can't use usb_packet_complete() here because packet->owner is + * cleared already, go call the ->complete() callback directly + * instead. */ - usb_packet_complete(&s->dev, packet); + s->dev.port->ops->complete(s->dev.port, packet); } static void usb_hub_handle_reset(USBDevice *dev) -- cgit v1.1