From 299aa1c6df1a308cc4d49666e7eb75655c0d40ce Mon Sep 17 00:00:00 2001 From: Gerd Hoffmann Date: Thu, 23 Feb 2012 15:24:24 +0100 Subject: usb-hid: fix tablet activation Activate usb hid pointer devices (mouse+tablet) unconditionally on polls, even if we NAK the poll due to lack of new events. Signed-off-by: Gerd Hoffmann --- hw/usb-hid.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/hw/usb-hid.c b/hw/usb-hid.c index 7fc0bd81a..37bca78ec 100644 --- a/hw/usb-hid.c +++ b/hw/usb-hid.c @@ -466,6 +466,9 @@ static int usb_hid_handle_data(USBDevice *dev, USBPacket *p) case USB_TOKEN_IN: if (p->ep->nr == 1) { int64_t curtime = qemu_get_clock_ns(vm_clock); + if (hs->kind == HID_MOUSE || hs->kind == HID_TABLET) { + hid_pointer_activate(hs); + } if (!hid_has_events(hs) && (!hs->idle || hs->next_idle_clock - curtime > 0)) { return USB_RET_NAK; -- cgit v1.2.3 From 81d37739dfded2ebd992f3bf8ae5d6cb1a0558cc Mon Sep 17 00:00:00 2001 From: Gerd Hoffmann Date: Thu, 23 Feb 2012 14:24:00 +0100 Subject: usb-ehci: fix reset Two reset fixes: * pick up s->usbcmd value after ehci_reset call to make sure it keeps the reset value and doesn't get rubbish filled in when val is written back to the mmio register array later on. * make sure the frame timer is zapped on reset. Signed-off-by: Gerd Hoffmann --- hw/usb-ehci.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/hw/usb-ehci.c b/hw/usb-ehci.c index e69981430..b9da26ada 100644 --- a/hw/usb-ehci.c +++ b/hw/usb-ehci.c @@ -912,6 +912,7 @@ static void ehci_reset(void *opaque) } } ehci_queues_rip_all(s); + qemu_del_timer(s->frame_timer); } static uint32_t ehci_mem_readb(void *ptr, target_phys_addr_t addr) @@ -1070,7 +1071,7 @@ static void ehci_mem_writel(void *ptr, target_phys_addr_t addr, uint32_t val) if (val & USBCMD_HCRESET) { ehci_reset(s); - val &= ~USBCMD_HCRESET; + val = s->usbcmd; } /* not supporting dynamic frame list size at the moment */ -- cgit v1.2.3 From 326700e35d2ac05ab83b91bf4857eedcdc049a30 Mon Sep 17 00:00:00 2001 From: Gerd Hoffmann Date: Fri, 27 Jan 2012 14:17:59 +0100 Subject: usb-uhci: cleanup UHCIAsync allocation & initialization. Signed-off-by: Gerd Hoffmann --- hw/usb-uhci.c | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/hw/usb-uhci.c b/hw/usb-uhci.c index 2280dc792..ca87290bf 100644 --- a/hw/usb-uhci.c +++ b/hw/usb-uhci.c @@ -159,15 +159,9 @@ typedef struct UHCI_QH { static UHCIAsync *uhci_async_alloc(UHCIState *s) { - UHCIAsync *async = g_malloc(sizeof(UHCIAsync)); + UHCIAsync *async = g_new0(UHCIAsync, 1); - memset(&async->packet, 0, sizeof(async->packet)); async->uhci = s; - async->valid = 0; - async->td = 0; - async->token = 0; - async->done = 0; - async->isoc = 0; usb_packet_init(&async->packet); pci_dma_sglist_init(&async->sgl, &s->dev, 1); -- cgit v1.2.3 From f8af1e889b7f314cd38a642d28bc3362c1790c97 Mon Sep 17 00:00:00 2001 From: Gerd Hoffmann Date: Fri, 27 Jan 2012 14:17:06 +0100 Subject: usb-uhci: add UHCIQueue UHCIAsync structs (in-flight requests) grouped in UHCIQueue now. Each (active) usb endpoint gets its own UHCIQueue. Signed-off-by: Gerd Hoffmann --- hw/usb-uhci.c | 209 +++++++++++++++++++++++++++++++++------------------------- 1 file changed, 118 insertions(+), 91 deletions(-) diff --git a/hw/usb-uhci.c b/hw/usb-uhci.c index ca87290bf..b8b336fca 100644 --- a/hw/usb-uhci.c +++ b/hw/usb-uhci.c @@ -95,23 +95,32 @@ static const char *pid2str(int pid) #endif typedef struct UHCIState UHCIState; +typedef struct UHCIAsync UHCIAsync; +typedef struct UHCIQueue UHCIQueue; /* * Pending async transaction. * 'packet' must be the first field because completion * handler does "(UHCIAsync *) pkt" cast. */ -typedef struct UHCIAsync { + +struct UHCIAsync { USBPacket packet; QEMUSGList sgl; - UHCIState *uhci; + UHCIQueue *queue; QTAILQ_ENTRY(UHCIAsync) next; uint32_t td; - uint32_t token; - int8_t valid; uint8_t isoc; uint8_t done; -} UHCIAsync; +}; + +struct UHCIQueue { + uint32_t token; + UHCIState *uhci; + QTAILQ_ENTRY(UHCIQueue) next; + QTAILQ_HEAD(, UHCIAsync) asyncs; + int8_t valid; +}; typedef struct UHCIPort { USBPort port; @@ -137,7 +146,7 @@ struct UHCIState { uint32_t pending_int_mask; /* Active packets */ - QTAILQ_HEAD(,UHCIAsync) async_pending; + QTAILQ_HEAD(, UHCIQueue) queues; uint8_t num_ports_vmstate; /* Properties */ @@ -157,56 +166,90 @@ typedef struct UHCI_QH { uint32_t el_link; } UHCI_QH; -static UHCIAsync *uhci_async_alloc(UHCIState *s) +static inline int32_t uhci_queue_token(UHCI_TD *td) +{ + /* covers ep, dev, pid -> identifies the endpoint */ + return td->token & 0x7ffff; +} + +static UHCIQueue *uhci_queue_get(UHCIState *s, UHCI_TD *td) +{ + uint32_t token = uhci_queue_token(td); + UHCIQueue *queue; + + QTAILQ_FOREACH(queue, &s->queues, next) { + if (queue->token == token) { + return queue; + } + } + + queue = g_new0(UHCIQueue, 1); + queue->uhci = s; + queue->token = token; + QTAILQ_INIT(&queue->asyncs); + QTAILQ_INSERT_HEAD(&s->queues, queue, next); + return queue; +} + +static void uhci_queue_free(UHCIQueue *queue) +{ + UHCIState *s = queue->uhci; + + QTAILQ_REMOVE(&s->queues, queue, next); + g_free(queue); +} + +static UHCIAsync *uhci_async_alloc(UHCIQueue *queue) { UHCIAsync *async = g_new0(UHCIAsync, 1); - async->uhci = s; + async->queue = queue; usb_packet_init(&async->packet); - pci_dma_sglist_init(&async->sgl, &s->dev, 1); + pci_dma_sglist_init(&async->sgl, &queue->uhci->dev, 1); return async; } -static void uhci_async_free(UHCIState *s, UHCIAsync *async) +static void uhci_async_free(UHCIAsync *async) { usb_packet_cleanup(&async->packet); qemu_sglist_destroy(&async->sgl); g_free(async); } -static void uhci_async_link(UHCIState *s, UHCIAsync *async) +static void uhci_async_link(UHCIAsync *async) { - QTAILQ_INSERT_HEAD(&s->async_pending, async, next); + UHCIQueue *queue = async->queue; + QTAILQ_INSERT_TAIL(&queue->asyncs, async, next); } -static void uhci_async_unlink(UHCIState *s, UHCIAsync *async) +static void uhci_async_unlink(UHCIAsync *async) { - QTAILQ_REMOVE(&s->async_pending, async, next); + UHCIQueue *queue = async->queue; + QTAILQ_REMOVE(&queue->asyncs, async, next); } -static void uhci_async_cancel(UHCIState *s, UHCIAsync *async) +static void uhci_async_cancel(UHCIAsync *async) { DPRINTF("uhci: cancel td 0x%x token 0x%x done %u\n", async->td, async->token, async->done); if (!async->done) usb_cancel_packet(&async->packet); - uhci_async_free(s, async); + uhci_async_free(async); } /* * Mark all outstanding async packets as invalid. * This is used for canceling them when TDs are removed by the HCD. */ -static UHCIAsync *uhci_async_validate_begin(UHCIState *s) +static void uhci_async_validate_begin(UHCIState *s) { - UHCIAsync *async; + UHCIQueue *queue; - QTAILQ_FOREACH(async, &s->async_pending, next) { - async->valid--; + QTAILQ_FOREACH(queue, &s->queues, next) { + queue->valid--; } - return NULL; } /* @@ -214,77 +257,74 @@ static UHCIAsync *uhci_async_validate_begin(UHCIState *s) */ static void uhci_async_validate_end(UHCIState *s) { - UHCIAsync *curr, *n; + UHCIQueue *queue, *n; + UHCIAsync *async; - QTAILQ_FOREACH_SAFE(curr, &s->async_pending, next, n) { - if (curr->valid > 0) { + QTAILQ_FOREACH_SAFE(queue, &s->queues, next, n) { + if (queue->valid > 0) { continue; } - uhci_async_unlink(s, curr); - uhci_async_cancel(s, curr); + while (!QTAILQ_EMPTY(&queue->asyncs)) { + async = QTAILQ_FIRST(&queue->asyncs); + uhci_async_unlink(async); + uhci_async_cancel(async); + } + uhci_queue_free(queue); } } static void uhci_async_cancel_device(UHCIState *s, USBDevice *dev) { + UHCIQueue *queue; UHCIAsync *curr, *n; - QTAILQ_FOREACH_SAFE(curr, &s->async_pending, next, n) { - if (!usb_packet_is_inflight(&curr->packet) || - curr->packet.ep->dev != dev) { - continue; + QTAILQ_FOREACH(queue, &s->queues, next) { + QTAILQ_FOREACH_SAFE(curr, &queue->asyncs, next, n) { + if (!usb_packet_is_inflight(&curr->packet) || + curr->packet.ep->dev != dev) { + continue; + } + uhci_async_unlink(curr); + uhci_async_cancel(curr); } - uhci_async_unlink(s, curr); - uhci_async_cancel(s, curr); } } static void uhci_async_cancel_all(UHCIState *s) { + UHCIQueue *queue; UHCIAsync *curr, *n; - QTAILQ_FOREACH_SAFE(curr, &s->async_pending, next, n) { - uhci_async_unlink(s, curr); - uhci_async_cancel(s, curr); + QTAILQ_FOREACH(queue, &s->queues, next) { + QTAILQ_FOREACH_SAFE(curr, &queue->asyncs, next, n) { + uhci_async_unlink(curr); + uhci_async_cancel(curr); + } } } -static UHCIAsync *uhci_async_find_td(UHCIState *s, uint32_t addr, uint32_t token) +static UHCIAsync *uhci_async_find_td(UHCIState *s, uint32_t addr, UHCI_TD *td) { + uint32_t token = uhci_queue_token(td); + UHCIQueue *queue; UHCIAsync *async; - UHCIAsync *match = NULL; - int count = 0; - - /* - * We're looking for the best match here. ie both td addr and token. - * Otherwise we return last good match. ie just token. - * It's ok to match just token because it identifies the transaction - * rather well, token includes: device addr, endpoint, size, etc. - * - * Also since we queue async transactions in reverse order by returning - * last good match we restores the order. - * - * It's expected that we wont have a ton of outstanding transactions. - * If we ever do we'd want to optimize this algorithm. - */ - - QTAILQ_FOREACH(async, &s->async_pending, next) { - if (async->token == token) { - /* Good match */ - match = async; - if (async->td == addr) { - /* Best match */ - break; - } + QTAILQ_FOREACH(queue, &s->queues, next) { + if (queue->token == token) { + break; } - count++; + } + if (queue == NULL) { + return NULL; } - if (count > 64) - fprintf(stderr, "uhci: warning lots of async transactions\n"); + QTAILQ_FOREACH(async, &queue->asyncs, next) { + if (async->td == addr) { + return async; + } + } - return match; + return NULL; } static void uhci_update_irq(UHCIState *s) @@ -753,8 +793,7 @@ static int uhci_handle_td(UHCIState *s, uint32_t addr, UHCI_TD *td, uint32_t *in { UHCIAsync *async; int len = 0, max_len; - uint8_t pid, isoc; - uint32_t token; + uint8_t pid; USBDevice *dev; USBEndpoint *ep; @@ -762,41 +801,29 @@ static int uhci_handle_td(UHCIState *s, uint32_t addr, UHCI_TD *td, uint32_t *in if (!(td->ctrl & TD_CTRL_ACTIVE)) return 1; - /* token field is not unique for isochronous requests, - * so use the destination buffer - */ - if (td->ctrl & TD_CTRL_IOS) { - token = td->buffer; - isoc = 1; - } else { - token = td->token; - isoc = 0; - } - - async = uhci_async_find_td(s, addr, token); + async = uhci_async_find_td(s, addr, td); if (async) { /* Already submitted */ - async->valid = 32; + async->queue->valid = 32; if (!async->done) return 1; - uhci_async_unlink(s, async); + uhci_async_unlink(async); goto done; } /* Allocate new packet */ - async = uhci_async_alloc(s); + async = uhci_async_alloc(uhci_queue_get(s, td)); if (!async) return 1; /* valid needs to be large enough to handle 10 frame delay * for initial isochronous requests */ - async->valid = 32; + async->queue->valid = 32; async->td = addr; - async->token = token; - async->isoc = isoc; + async->isoc = td->ctrl & TD_CTRL_IOS; max_len = ((td->token >> 21) + 1) & 0x7ff; pid = td->token & 0xff; @@ -821,14 +848,14 @@ static int uhci_handle_td(UHCIState *s, uint32_t addr, UHCI_TD *td, uint32_t *in default: /* invalid pid : frame interrupted */ - uhci_async_free(s, async); + uhci_async_free(async); s->status |= UHCI_STS_HCPERR; uhci_update_irq(s); return -1; } if (len == USB_RET_ASYNC) { - uhci_async_link(s, async); + uhci_async_link(async); return 2; } @@ -837,14 +864,14 @@ static int uhci_handle_td(UHCIState *s, uint32_t addr, UHCI_TD *td, uint32_t *in done: len = uhci_complete_td(s, td, async, int_mask); usb_packet_unmap(&async->packet); - uhci_async_free(s, async); + uhci_async_free(async); return len; } static void uhci_async_complete(USBPort *port, USBPacket *packet) { UHCIAsync *async = container_of(packet, UHCIAsync, packet); - UHCIState *s = async->uhci; + UHCIState *s = async->queue->uhci; DPRINTF("uhci: async complete. td 0x%x token 0x%x\n", async->td, async->token); @@ -859,14 +886,14 @@ static void uhci_async_complete(USBPort *port, USBPacket *packet) le32_to_cpus(&td.token); le32_to_cpus(&td.buffer); - uhci_async_unlink(s, async); + uhci_async_unlink(async); uhci_complete_td(s, &td, async, &int_mask); s->pending_int_mask |= int_mask; /* update the status bits of the TD */ val = cpu_to_le32(td.ctrl); pci_dma_write(&s->dev, (link & ~0xf) + 4, &val, sizeof(val)); - uhci_async_free(s, async); + uhci_async_free(async); } else { async->done = 1; uhci_process_frame(s); @@ -1142,7 +1169,7 @@ static int usb_uhci_common_initfn(PCIDevice *dev) } s->frame_timer = qemu_new_timer_ns(vm_clock, uhci_frame_timer, s); s->num_ports_vmstate = NB_PORTS; - QTAILQ_INIT(&s->async_pending); + QTAILQ_INIT(&s->queues); qemu_register_reset(uhci_reset, s); -- cgit v1.2.3 From 971a5a406ed3631797a6c83e47f6fc2e7d410f8f Mon Sep 17 00:00:00 2001 From: Gerd Hoffmann Date: Fri, 27 Jan 2012 16:38:42 +0100 Subject: usb-uhci: process uhci_handle_td return code via switch. Restruct the uhci_handle_td return code processing to make the control flow more clear and the code more readable. Signed-off-by: Gerd Hoffmann --- hw/usb-uhci.c | 66 +++++++++++++++++++++++++++++++++++------------------------ 1 file changed, 39 insertions(+), 27 deletions(-) diff --git a/hw/usb-uhci.c b/hw/usb-uhci.c index b8b336fca..13298aada 100644 --- a/hw/usb-uhci.c +++ b/hw/usb-uhci.c @@ -1029,49 +1029,61 @@ static void uhci_process_frame(UHCIState *s) pci_dma_write(&s->dev, (link & ~0xf) + 4, &val, sizeof(val)); } - if (ret < 0) { - /* interrupted frame */ - break; - } - - if (ret == 2 || ret == 1) { - DPRINTF("uhci: TD 0x%x %s. link 0x%x ctrl 0x%x token 0x%x qh 0x%x\n", - link, ret == 2 ? "pend" : "skip", - td.link, td.ctrl, td.token, curr_qh); + switch (ret) { + case -1: /* interrupted frame */ + goto out; + case 1: /* goto next queue */ + DPRINTF("uhci: TD 0x%x skip. " + "link 0x%x ctrl 0x%x token 0x%x qh 0x%x\n", + link, td.link, td.ctrl, td.token, curr_qh); link = curr_qh ? qh.link : td.link; continue; - } - /* completed TD */ + case 2: /* got USB_RET_ASYNC */ + DPRINTF("uhci: TD 0x%x async. " + "link 0x%x ctrl 0x%x token 0x%x qh 0x%x\n", + link, td.link, td.ctrl, td.token, curr_qh); + fprintf(stderr, "async td: link %x%s\n", + td.link, is_valid(td.link) ? " valid" : ""); + link = curr_qh ? qh.link : td.link; + continue; - DPRINTF("uhci: TD 0x%x done. link 0x%x ctrl 0x%x token 0x%x qh 0x%x\n", - link, td.link, td.ctrl, td.token, curr_qh); + case 0: /* completed TD */ + DPRINTF("uhci: TD 0x%x done. " + "link 0x%x ctrl 0x%x token 0x%x qh 0x%x\n", + link, td.link, td.ctrl, td.token, curr_qh); - link = td.link; - td_count++; - bytes_count += (td.ctrl & 0x7ff) + 1; + link = td.link; + td_count++; + bytes_count += (td.ctrl & 0x7ff) + 1; - if (curr_qh) { - /* update QH element link */ - qh.el_link = link; - val = cpu_to_le32(qh.el_link); - pci_dma_write(&s->dev, (curr_qh & ~0xf) + 4, &val, sizeof(val)); + if (curr_qh) { + /* update QH element link */ + qh.el_link = link; + val = cpu_to_le32(qh.el_link); + pci_dma_write(&s->dev, (curr_qh & ~0xf) + 4, &val, sizeof(val)); - if (!depth_first(link)) { - /* done with this QH */ + if (!depth_first(link)) { + /* done with this QH */ - DPRINTF("uhci: QH 0x%x done. link 0x%x elink 0x%x\n", - curr_qh, qh.link, qh.el_link); + DPRINTF("uhci: QH 0x%x done. link 0x%x elink 0x%x\n", + curr_qh, qh.link, qh.el_link); - curr_qh = 0; - link = qh.link; + curr_qh = 0; + link = qh.link; + } } + break; + + default: + assert(!"unknown return code"); } /* go to the next entry */ } +out: s->pending_int_mask |= int_mask; } -- cgit v1.2.3 From 5a248289a8db9e5c872435757165e086d42bece1 Mon Sep 17 00:00:00 2001 From: Gerd Hoffmann Date: Fri, 27 Jan 2012 17:27:31 +0100 Subject: usb-uhci: implement packet queuing When a usb device is busy processing a packet (and returns USB_RET_ASYNC), continue walking the transfer descriptor list and process them to fill the request queue. Signed-off-by: Gerd Hoffmann --- hw/usb-uhci.c | 33 +++++++++++++++++++++++++++++++-- 1 file changed, 31 insertions(+), 2 deletions(-) diff --git a/hw/usb-uhci.c b/hw/usb-uhci.c index 13298aada..70e388132 100644 --- a/hw/usb-uhci.c +++ b/hw/usb-uhci.c @@ -942,6 +942,34 @@ static int qhdb_insert(QhDb *db, uint32_t addr) return 0; } +static void uhci_fill_queue(UHCIState *s, UHCI_TD *td) +{ + uint32_t int_mask = 0; + uint32_t plink = td->link; + uint32_t token = uhci_queue_token(td); + UHCI_TD ptd; + int ret; + + fprintf(stderr, "%s: -- %x\n", __func__, token); + while (is_valid(plink)) { + pci_dma_read(&s->dev, plink & ~0xf, &ptd, sizeof(ptd)); + le32_to_cpus(&ptd.link); + le32_to_cpus(&ptd.ctrl); + le32_to_cpus(&ptd.token); + le32_to_cpus(&ptd.buffer); + if (!(ptd.ctrl & TD_CTRL_ACTIVE)) { + break; + } + if (uhci_queue_token(&ptd) != token) { + break; + } + ret = uhci_handle_td(s, plink, &ptd, &int_mask); + assert(ret == 2); /* got USB_RET_ASYNC */ + assert(int_mask == 0); + plink = ptd.link; + } +} + static void uhci_process_frame(UHCIState *s) { uint32_t frame_addr, link, old_td_ctrl, val, int_mask; @@ -1044,8 +1072,9 @@ static void uhci_process_frame(UHCIState *s) DPRINTF("uhci: TD 0x%x async. " "link 0x%x ctrl 0x%x token 0x%x qh 0x%x\n", link, td.link, td.ctrl, td.token, curr_qh); - fprintf(stderr, "async td: link %x%s\n", - td.link, is_valid(td.link) ? " valid" : ""); + if (is_valid(td.link)) { + uhci_fill_queue(s, &td); + } link = curr_qh ? qh.link : td.link; continue; -- cgit v1.2.3 From 7d1994f863c355f1906655f08d624582eeb30788 Mon Sep 17 00:00:00 2001 From: Gerd Hoffmann Date: Fri, 24 Feb 2012 10:44:05 +0100 Subject: usb-xhci: enable packet queuing qemu usb core has packet queues now, so flip lets the switch. Signed-off-by: Gerd Hoffmann --- hw/usb-xhci.c | 6 ------ 1 file changed, 6 deletions(-) diff --git a/hw/usb-xhci.c b/hw/usb-xhci.c index 008b0b571..fc5b542d9 100644 --- a/hw/usb-xhci.c +++ b/hw/usb-xhci.c @@ -1769,12 +1769,6 @@ static void xhci_kick_ep(XHCIState *xhci, unsigned int slotid, unsigned int epid epctx->retry = xfer; break; } - - /* - * Qemu usb can't handle multiple in-flight xfers. - * Stop here for now. - */ - break; } } -- cgit v1.2.3 From 808aeb98ffd9265da55a9ad3fceb86a7ac77107b Mon Sep 17 00:00:00 2001 From: Gerd Hoffmann Date: Fri, 24 Feb 2012 11:03:27 +0100 Subject: usb: add tracepoint for usb packet state changes. Signed-off-by: Gerd Hoffmann --- hw/usb.c | 27 +++++---------------------- trace-events | 3 +++ 2 files changed, 8 insertions(+), 22 deletions(-) diff --git a/hw/usb.c b/hw/usb.c index e5b8f335d..57fc5e3cf 100644 --- a/hw/usb.c +++ b/hw/usb.c @@ -26,6 +26,7 @@ #include "qemu-common.h" #include "usb.h" #include "iov.h" +#include "trace.h" void usb_attach(USBPort *port) { @@ -390,7 +391,6 @@ void usb_packet_init(USBPacket *p) void usb_packet_set_state(USBPacket *p, USBPacketState state) { -#ifdef DEBUG static const char *name[] = { [USB_PACKET_UNDEFINED] = "undef", [USB_PACKET_SETUP] = "setup", @@ -399,28 +399,11 @@ void usb_packet_set_state(USBPacket *p, USBPacketState state) [USB_PACKET_COMPLETE] = "complete", [USB_PACKET_CANCELED] = "canceled", }; - static const char *rets[] = { - [-USB_RET_NODEV] = "NODEV", - [-USB_RET_NAK] = "NAK", - [-USB_RET_STALL] = "STALL", - [-USB_RET_BABBLE] = "BABBLE", - [-USB_RET_ASYNC] = "ASYNC", - }; - char add[16] = ""; + USBDevice *dev = p->ep->dev; + USBBus *bus = usb_bus_from_device(dev); - if (state == USB_PACKET_COMPLETE) { - if (p->result < 0) { - snprintf(add, sizeof(add), " - %s", rets[-p->result]); - } else { - snprintf(add, sizeof(add), " - %d", p->result); - } - } - fprintf(stderr, "bus %s, port %s, dev %d, ep %d: packet %p: %s -> %s%s\n", - p->ep->dev->qdev.parent_bus->name, - p->ep->dev->port->path, - p->ep->dev->addr, p->ep->nr, - p, name[p->state], name[state], add); -#endif + trace_usb_packet_state_change(bus->busnr, dev->port->path, p->ep->nr, + p, name[p->state], name[state]); p->state = state; } diff --git a/trace-events b/trace-events index e918ff61f..c5d0f0f54 100644 --- a/trace-events +++ b/trace-events @@ -227,6 +227,9 @@ sun4m_iommu_page_get_flags(uint64_t pa, uint64_t iopte, uint32_t ret) "get flags sun4m_iommu_translate_pa(uint64_t addr, uint64_t pa, uint32_t iopte) "xlate dva %"PRIx64" => pa %"PRIx64" iopte = %x" sun4m_iommu_bad_addr(uint64_t addr) "bad addr %"PRIx64 +# hw/usb.c +usb_packet_state_change(int bus, const char *port, int ep, void *p, const char *o, const char *n) "bus %d, port %s, ep %d, packet %p, state %s -> %s" + # hw/usb-bus.c usb_port_claim(int bus, const char *port) "bus %d, port %s" usb_port_attach(int bus, const char *port) "bus %d, port %s" -- cgit v1.2.3 From aa0568ff2559d7717f4684af6a83d0bd1a125f56 Mon Sep 17 00:00:00 2001 From: Gerd Hoffmann Date: Mon, 27 Feb 2012 11:23:08 +0100 Subject: usb-ehci: sanity-check iso xfers This patch adds a sanity check to itd processing to make sure the endpoint addressed by the guest is actually an iso endpoint. Also verify that usb drivers don't return USB_RET_ASYNC which is illegal for iso xfers. Signed-off-by: Gerd Hoffmann --- hw/usb-ehci.c | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/hw/usb-ehci.c b/hw/usb-ehci.c index b9da26ada..048eb7663 100644 --- a/hw/usb-ehci.c +++ b/hw/usb-ehci.c @@ -1459,12 +1459,16 @@ static int ehci_process_itd(EHCIState *ehci, dev = ehci_find_device(ehci, devaddr); ep = usb_ep_get(dev, pid, endp); - usb_packet_setup(&ehci->ipacket, pid, ep); - usb_packet_map(&ehci->ipacket, &ehci->isgl); - - ret = usb_handle_packet(dev, &ehci->ipacket); - - usb_packet_unmap(&ehci->ipacket); + if (ep->type == USB_ENDPOINT_XFER_ISOC) { + usb_packet_setup(&ehci->ipacket, pid, ep); + usb_packet_map(&ehci->ipacket, &ehci->isgl); + ret = usb_handle_packet(dev, &ehci->ipacket); + assert(ret != USB_RET_ASYNC); + usb_packet_unmap(&ehci->ipacket); + } else { + DPRINTF("ISOCH: attempt to addess non-iso endpoint\n"); + ret = USB_RET_NAK; + } qemu_sglist_destroy(&ehci->isgl); #if 0 -- cgit v1.2.3 From 8db36e9dddb1b6fab3554a8c00d92268b33a487b Mon Sep 17 00:00:00 2001 From: Alon Levy Date: Sun, 26 Feb 2012 17:09:21 +0100 Subject: usb-desc: fix user trigerrable segfaults (!config) Check for dev->config being NULL in two places: USB_REQ_GET_CONFIGURATION and USB_REQ_GET_STATUS. The behavior of USB_REQ_GET_STATUS is unspecified in the Default state, that corresponds to dev->config being NULL (it defaults to NULL and is reset whenever a SET_CONFIGURATION with value 0, or attachment). I implemented it to correspond with the state before ed5a83ddd8c1d8ec7b1015315530cf29949e7c48, the commit moving SET_STATUS to usb-desc; if dev->config is not set we return whatever is in the first configuration. The behavior of USB_REQ_GET_CONFIGURATION is also undefined before any SET_CONFIGURATION, but here we just return 0 (same as specified for the Address state). A win7 guest failed to initialize the device before this patch, segfaulting when GET_STATUS was called with dev->config == NULL. With this patch the passthrough device still doesn't work but the failure is unrelated. Signed-off-by: Alon Levy Signed-off-by: Gerd Hoffmann --- hw/usb-desc.c | 20 +++++++++++++++++--- 1 file changed, 17 insertions(+), 3 deletions(-) diff --git a/hw/usb-desc.c b/hw/usb-desc.c index 3c3ed6a80..ccf85ade9 100644 --- a/hw/usb-desc.c +++ b/hw/usb-desc.c @@ -536,7 +536,11 @@ int usb_desc_handle_control(USBDevice *dev, USBPacket *p, break; case DeviceRequest | USB_REQ_GET_CONFIGURATION: - data[0] = dev->config->bConfigurationValue; + /* + * 9.4.2: 0 should be returned if the device is unconfigured, otherwise + * the non zero value of bConfigurationValue. + */ + data[0] = dev->config ? dev->config->bConfigurationValue : 0; ret = 1; break; case DeviceOutRequest | USB_REQ_SET_CONFIGURATION: @@ -544,9 +548,18 @@ int usb_desc_handle_control(USBDevice *dev, USBPacket *p, trace_usb_set_config(dev->addr, value, ret); break; - case DeviceRequest | USB_REQ_GET_STATUS: + case DeviceRequest | USB_REQ_GET_STATUS: { + const USBDescConfig *config = dev->config ? + dev->config : &dev->device->confs[0]; + data[0] = 0; - if (dev->config->bmAttributes & 0x40) { + /* + * Default state: Device behavior when this request is received while + * the device is in the Default state is not specified. + * We return the same value that a configured device would return if + * it used the first configuration. + */ + if (config->bmAttributes & 0x40) { data[0] |= 1 << USB_DEVICE_SELF_POWERED; } if (dev->remote_wakeup) { @@ -555,6 +568,7 @@ int usb_desc_handle_control(USBDevice *dev, USBPacket *p, data[1] = 0x00; ret = 2; break; + } case DeviceOutRequest | USB_REQ_CLEAR_FEATURE: if (value == USB_DEVICE_REMOTE_WAKEUP) { dev->remote_wakeup = 0; -- cgit v1.2.3 From 8c741c229f6402886412f142ca1252e8a6f258a5 Mon Sep 17 00:00:00 2001 From: Alon Levy Date: Sun, 26 Feb 2012 17:09:22 +0100 Subject: libcacard: link with glib for g_strndup Without it the produced library for make libcacard.la has an unresolved symbol. Signed-off-by: Alon Levy Signed-off-by: Gerd Hoffmann --- configure | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/configure b/configure index f9d533004..87474e9af 100755 --- a/configure +++ b/configure @@ -2571,8 +2571,8 @@ if test "$smartcard" != "no" ; then int main(void) { PK11_FreeSlot(0); return 0; } EOF smartcard_cflags="-I\$(SRC_PATH)/libcacard" - libcacard_libs=$($pkg_config --libs nss 2>/dev/null) - libcacard_cflags=$($pkg_config --cflags nss 2>/dev/null) + libcacard_libs="$($pkg_config --libs nss 2>/dev/null) $glib_libs" + libcacard_cflags="$($pkg_config --cflags nss 2>/dev/null) $glib_cflags" if $pkg_config --atleast-version=3.12.8 nss >/dev/null 2>&1 && \ compile_prog "$smartcard_cflags $libcacard_cflags" "$libcacard_libs"; then smartcard_nss="yes" -- cgit v1.2.3 From cff17894e37feef5f0410c9557d38c2f00850657 Mon Sep 17 00:00:00 2001 From: Alon Levy Date: Sun, 26 Feb 2012 17:09:23 +0100 Subject: usb-ccid: advertise SELF_POWERED Before commit ed5a83ddd8c1d8ec7b1015315530cf29949e7c48 each device provided it's own response to USB_REQ_GET_STATUS, but after it that response was based on bmAttributes, which was errounously set for usb-ccid as 0xa0 and not 0xe0. Signed-off-by: Alon Levy Signed-off-by: Gerd Hoffmann --- hw/usb-ccid.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/hw/usb-ccid.c b/hw/usb-ccid.c index 0b2ac8037..ce01e343c 100644 --- a/hw/usb-ccid.c +++ b/hw/usb-ccid.c @@ -447,7 +447,7 @@ static const USBDescDevice desc_device = { { .bNumInterfaces = 1, .bConfigurationValue = 1, - .bmAttributes = 0xa0, + .bmAttributes = 0xe0, .bMaxPower = 50, .nif = 1, .ifs = &desc_iface0, -- cgit v1.2.3 From 0082f4336e128a17d5f34e01de0fd29930e99b0d Mon Sep 17 00:00:00 2001 From: Alon Levy Date: Sun, 26 Feb 2012 17:09:24 +0100 Subject: libcacard: fix reported ATR length Signed-off-by: Alon Levy Signed-off-by: Gerd Hoffmann --- libcacard/vcardt.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/libcacard/vcardt.h b/libcacard/vcardt.h index 538bdde3d..d4d8e2ed1 100644 --- a/libcacard/vcardt.h +++ b/libcacard/vcardt.h @@ -26,8 +26,8 @@ typedef struct VCardEmulStruct VCardEmul; #define MAX_CHANNEL 4 /* create an ATR with appropriate historical bytes */ -#define VCARD_ATR_PREFIX(size) 0x3b, 0x66+(size), 0x00, 0xff, \ - 'V', 'C', 'A', 'R', 'D', '_' +#define VCARD_ATR_PREFIX(size) (0x3b, 0x68+(size), 0x00, 0xff, \ + 'V', 'C', 'A', 'R', 'D', '_') typedef enum { -- cgit v1.2.3 From df7871851eb327af0a612895738c0e1854fde00b Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Sun, 26 Feb 2012 16:14:48 +0100 Subject: usb-ehci: Handle ISO packets failing with an error other then NAK Before this patch the ehci code was not checking for any other errors other then USB_RET_NAK. This causes 2 problems: 1) Other errors are not reported to the guest. 2) When transactions with the ITD_XACT_IOC bit set completing with another error would not result in USBSTS_INT getting set. I hit this problem when unplugging devices while iso data was streaming from the device to the guest. When this happens it takes a while for the guest to process the unplugging and remove ISO transactions from the ehci schedule, in the mean time these transactions would complete with a result of USB_RET_NODEV, which was not handled. This lead to the Linux guest's usb subsystem "hanging", that is it would no longer see new usb devices getting plugged in and running for example lsusb would lead to a stuck (D state) lsusb process. This patch fixes this. Signed-off-by: Hans de Goede Signed-off-by: Gerd Hoffmann --- hw/usb-ehci.c | 22 +++++++++++++++++++--- 1 file changed, 19 insertions(+), 3 deletions(-) diff --git a/hw/usb-ehci.c b/hw/usb-ehci.c index 048eb7663..b95773f5b 100644 --- a/hw/usb-ehci.c +++ b/hw/usb-ehci.c @@ -1510,11 +1510,27 @@ static int ehci_process_itd(EHCIState *ehci, /* IN */ set_field(&itd->transact[i], ret, ITD_XACT_LENGTH); } - - if (itd->transact[i] & ITD_XACT_IOC) { - ehci_record_interrupt(ehci, USBSTS_INT); + } else { + switch (ret) { + default: + fprintf(stderr, "Unexpected iso usb result: %d\n", ret); + /* Fall through */ + case USB_RET_NODEV: + /* 3.3.2: XACTERR is only allowed on IN transactions */ + if (dir) { + itd->transact[i] |= ITD_XACT_XACTERR; + ehci_record_interrupt(ehci, USBSTS_ERRINT); + } + break; + case USB_RET_BABBLE: + itd->transact[i] |= ITD_XACT_BABBLE; + ehci_record_interrupt(ehci, USBSTS_ERRINT); + break; } } + if (itd->transact[i] & ITD_XACT_IOC) { + ehci_record_interrupt(ehci, USBSTS_INT); + } itd->transact[i] &= ~ITD_XACT_ACTIVE; } } -- cgit v1.2.3 From 01cd4e98dc6eed96519f44f03de893364e0601ab Mon Sep 17 00:00:00 2001 From: Gerd Hoffmann Date: Mon, 27 Feb 2012 13:08:25 +0100 Subject: ehci: drop old stuff Drop the "ehci under development" banner. Drop unused & inactive (#if 0) code. Signed-off-by: Gerd Hoffmann --- hw/usb-ehci.c | 30 +----------------------------- 1 file changed, 1 insertion(+), 29 deletions(-) diff --git a/hw/usb-ehci.c b/hw/usb-ehci.c index b95773f5b..afc8ccf45 100644 --- a/hw/usb-ehci.c +++ b/hw/usb-ehci.c @@ -1471,36 +1471,10 @@ static int ehci_process_itd(EHCIState *ehci, } qemu_sglist_destroy(&ehci->isgl); -#if 0 - /* In isoch, there is no facility to indicate a NAK so let's - * instead just complete a zero-byte transaction. Setting - * DBERR seems too draconian. - */ - - if (ret == USB_RET_NAK) { - if (ehci->isoch_pause > 0) { - DPRINTF("ISOCH: received a NAK but paused so returning\n"); - ehci->isoch_pause--; - return 0; - } else if (ehci->isoch_pause == -1) { - DPRINTF("ISOCH: recv NAK & isoch pause inactive, setting\n"); - // Pause frindex for up to 50 msec waiting for data from - // remote - ehci->isoch_pause = 50; - return 0; - } else { - DPRINTF("ISOCH: isoch pause timeout! return 0\n"); - ret = 0; - } - } else { - DPRINTF("ISOCH: received ACK, clearing pause\n"); - ehci->isoch_pause = -1; - } -#else if (ret == USB_RET_NAK) { + /* no data for us, so do a zero-length transfer */ ret = 0; } -#endif if (ret >= 0) { if (!dir) { @@ -2389,8 +2363,6 @@ static int usb_ehci_initfn(PCIDevice *dev) memory_region_init_io(&s->mem, &ehci_mem_ops, s, "ehci", MMIO_SIZE); pci_register_bar(&s->dev, 0, PCI_BASE_ADDRESS_SPACE_MEMORY, &s->mem); - fprintf(stderr, "*** EHCI support is under development ***\n"); - return 0; } -- cgit v1.2.3 From 52234bc00d5cf13cf96b3d632a4e0aa34cec08be Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Sun, 26 Feb 2012 16:14:43 +0100 Subject: usb-redir: Fix printing of device version The device version is in bcd format, which requires some special handling to print. Signed-off-by: Hans de Goede Signed-off-by: Gerd Hoffmann --- usb-redir.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/usb-redir.c b/usb-redir.c index a59b347f0..18204beb3 100644 --- a/usb-redir.c +++ b/usb-redir.c @@ -1049,8 +1049,10 @@ static void usbredir_device_connect(void *priv, usb_redir_cap_connect_device_version)) { INFO("attaching %s device %04x:%04x version %d.%d class %02x\n", speed, device_connect->vendor_id, device_connect->product_id, - device_connect->device_version_bcd >> 8, - device_connect->device_version_bcd & 0xff, + ((device_connect->device_version_bcd & 0xf000) >> 12) * 10 + + ((device_connect->device_version_bcd & 0x0f00) >> 8), + ((device_connect->device_version_bcd & 0x00f0) >> 4) * 10 + + ((device_connect->device_version_bcd & 0x000f) >> 0), device_connect->device_class); } else { INFO("attaching %s device %04x:%04x class %02x\n", speed, -- cgit v1.2.3 From 5b3bd68244c87e161ea309ed380f216acf7cd754 Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Sun, 26 Feb 2012 16:14:44 +0100 Subject: usb-redir: Always clear device state on filter reject Always call usbredir_device_disconnect() when usbredir_check_filter() fails to clean up all the device state (ie received endpoint info). Signed-off-by: Hans de Goede Signed-off-by: Gerd Hoffmann --- usb-redir.c | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/usb-redir.c b/usb-redir.c index 18204beb3..c98b14e16 100644 --- a/usb-redir.c +++ b/usb-redir.c @@ -958,7 +958,7 @@ static int usbredir_check_filter(USBRedirDevice *dev) { if (dev->interface_info.interface_count == 0) { ERROR("No interface info for device\n"); - return -1; + goto error; } if (dev->filter_rules) { @@ -966,7 +966,7 @@ static int usbredir_check_filter(USBRedirDevice *dev) usb_redir_cap_connect_device_version)) { ERROR("Device filter specified and peer does not have the " "connect_device_version capability\n"); - return -1; + goto error; } if (usbredirfilter_check( @@ -983,11 +983,15 @@ static int usbredir_check_filter(USBRedirDevice *dev) dev->device_info.product_id, dev->device_info.device_version_bcd, 0) != 0) { - return -1; + goto error; } } return 0; + +error: + usbredir_device_disconnect(dev); + return -1; } /* @@ -1113,7 +1117,6 @@ static void usbredir_interface_info(void *priv, if (usbredir_check_filter(dev)) { ERROR("Device no longer matches filter after interface info " "change, disconnecting!\n"); - usbredir_device_disconnect(dev); } } } -- cgit v1.2.3 From 097a66ef5f6138c22bfdd1cc218eb2704e5eef9c Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Sun, 26 Feb 2012 16:14:45 +0100 Subject: usb-redir: Let the usb-host know about our device filtering libusbredirparser-0.3.4 adds 2 new packets which allows us to notify the usb-host: -about the usb device filter we have (if any), so that it knows not the even try to redirect certain devices -when we reject a device based on filtering (in case it tries anyways) Signed-off-by: Hans de Goede Signed-off-by: Gerd Hoffmann --- configure | 2 +- usb-redir.c | 20 ++++++++++++++++++++ 2 files changed, 21 insertions(+), 1 deletion(-) diff --git a/configure b/configure index 87474e9af..d64b2de34 100755 --- a/configure +++ b/configure @@ -2592,7 +2592,7 @@ fi # check for usbredirparser for usb network redirection support if test "$usb_redir" != "no" ; then - if $pkg_config --atleast-version=0.3.3 libusbredirparser >/dev/null 2>&1 ; then + if $pkg_config --atleast-version=0.3.4 libusbredirparser >/dev/null 2>&1 ; then usb_redir="yes" usb_redir_cflags=$($pkg_config --cflags libusbredirparser 2>/dev/null) usb_redir_libs=$($pkg_config --libs libusbredirparser 2>/dev/null) diff --git a/usb-redir.c b/usb-redir.c index c98b14e16..6c92fd9db 100644 --- a/usb-redir.c +++ b/usb-redir.c @@ -106,6 +106,7 @@ struct AsyncURB { QTAILQ_ENTRY(AsyncURB)next; }; +static void usbredir_hello(void *priv, struct usb_redir_hello_header *h); static void usbredir_device_connect(void *priv, struct usb_redir_device_connect_header *device_connect); static void usbredir_device_disconnect(void *priv); @@ -802,6 +803,7 @@ static void usbredir_open_close_bh(void *opaque) dev->parser->log_func = usbredir_log; dev->parser->read_func = usbredir_read; dev->parser->write_func = usbredir_write; + dev->parser->hello_func = usbredir_hello; dev->parser->device_connect_func = usbredir_device_connect; dev->parser->device_disconnect_func = usbredir_device_disconnect; dev->parser->interface_info_func = usbredir_interface_info; @@ -820,6 +822,7 @@ static void usbredir_open_close_bh(void *opaque) dev->read_buf_size = 0; usbredirparser_caps_set_cap(caps, usb_redir_cap_connect_device_version); + usbredirparser_caps_set_cap(caps, usb_redir_cap_filter); usbredirparser_init(dev->parser, VERSION, caps, USB_REDIR_CAPS_SIZE, 0); usbredirparser_do_write(dev->parser); } @@ -991,6 +994,10 @@ static int usbredir_check_filter(USBRedirDevice *dev) error: usbredir_device_disconnect(dev); + if (usbredirparser_peer_has_cap(dev->parser, usb_redir_cap_filter)) { + usbredirparser_send_filter_reject(dev->parser); + usbredirparser_do_write(dev->parser); + } return -1; } @@ -1016,6 +1023,19 @@ static int usbredir_handle_status(USBRedirDevice *dev, } } +static void usbredir_hello(void *priv, struct usb_redir_hello_header *h) +{ + USBRedirDevice *dev = priv; + + /* Try to send the filter info now that we've the usb-host's caps */ + if (usbredirparser_peer_has_cap(dev->parser, usb_redir_cap_filter) && + dev->filter_rules) { + usbredirparser_send_filter_filter(dev->parser, dev->filter_rules, + dev->filter_rules_count); + usbredirparser_do_write(dev->parser); + } +} + static void usbredir_device_connect(void *priv, struct usb_redir_device_connect_header *device_connect) { -- cgit v1.2.3 From d86b8853e1f0c7ffb917a7a48f2e44bc3d8e9f8a Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Sun, 26 Feb 2012 16:14:46 +0100 Subject: usb-redir: Limit return values returned by iso packets The usbredir protocol uses a status of usb_redir_stall to indicate that an iso data stream has stopped (ie because the urbs failed on resubmit), but iso packets should never return a result of USB_RET_STALL, since iso endpoints cannot stall. So instead simply always return USB_RET_NAK on iso stream errors. Signed-off-by: Hans de Goede Signed-off-by: Gerd Hoffmann --- usb-redir.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/usb-redir.c b/usb-redir.c index 6c92fd9db..d9054633a 100644 --- a/usb-redir.c +++ b/usb-redir.c @@ -431,7 +431,7 @@ static int usbredir_handle_iso_data(USBRedirDevice *dev, USBPacket *p, /* Check iso_error for stream errors, otherwise its an underrun */ status = dev->endpoint[EP2I(ep)].iso_error; dev->endpoint[EP2I(ep)].iso_error = 0; - return usbredir_handle_status(dev, status, 0); + return status ? USB_RET_NAK : 0; } DPRINTF2("iso-token-in ep %02X status %d len %d queue-size: %d\n", ep, isop->status, isop->len, dev->endpoint[EP2I(ep)].bufpq_size); @@ -439,7 +439,7 @@ static int usbredir_handle_iso_data(USBRedirDevice *dev, USBPacket *p, status = isop->status; if (status != usb_redir_success) { bufp_free(dev, isop, ep); - return usbredir_handle_status(dev, status, 0); + return USB_RET_NAK; } len = isop->len; -- cgit v1.2.3 From e64722108c1342d499d408c386ce65794c44dd63 Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Sun, 26 Feb 2012 16:14:47 +0100 Subject: usb-redir: Return USB_RET_NAK when we've no data for an interrupt endpoint We should return USB_RET_NAK, rather then a 0 sized packet, when we've no data for an interrupt IN endpoint. Signed-off-by: Hans de Goede Signed-off-by: Gerd Hoffmann --- usb-redir.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/usb-redir.c b/usb-redir.c index d9054633a..755492f37 100644 --- a/usb-redir.c +++ b/usb-redir.c @@ -548,7 +548,10 @@ static int usbredir_handle_interrupt_data(USBRedirDevice *dev, /* Check interrupt_error for stream errors */ status = dev->endpoint[EP2I(ep)].interrupt_error; dev->endpoint[EP2I(ep)].interrupt_error = 0; - return usbredir_handle_status(dev, status, 0); + if (status) { + return usbredir_handle_status(dev, status, 0); + } + return USB_RET_NAK; } DPRINTF("interrupt-token-in ep %02X status %d len %d\n", ep, intp->status, intp->len); -- cgit v1.2.3 From 3741715cf2e54727fe3d9884ea6dcea68c7f7d4b Mon Sep 17 00:00:00 2001 From: Jan Kiszka Date: Mon, 27 Feb 2012 15:18:47 +0100 Subject: usb: Resolve warnings about unassigned bus on usb device creation When creating an USB device the old way, there is no way to specify the target bus. Thus the warning issued by usb_create makes no sense and rather confuses our users. Resolve this by passing a bus reference to the usbdevice_init handler and letting those handlers forward it to usb_create. Signed-off-by: Jan Kiszka Signed-off-by: Gerd Hoffmann --- hw/usb-bt.c | 4 ++-- hw/usb-bus.c | 18 ++++-------------- hw/usb-msd.c | 4 ++-- hw/usb-net.c | 4 ++-- hw/usb-serial.c | 8 ++++---- hw/usb.h | 7 ++++--- usb-bsd.c | 4 ++-- usb-linux.c | 4 ++-- vl.c | 7 ++++--- 9 files changed, 26 insertions(+), 34 deletions(-) diff --git a/hw/usb-bt.c b/hw/usb-bt.c index 649bdcf2d..23c39ecc2 100644 --- a/hw/usb-bt.c +++ b/hw/usb-bt.c @@ -498,14 +498,14 @@ static int usb_bt_initfn(USBDevice *dev) return 0; } -USBDevice *usb_bt_init(HCIInfo *hci) +USBDevice *usb_bt_init(USBBus *bus, HCIInfo *hci) { USBDevice *dev; struct USBBtState *s; if (!hci) return NULL; - dev = usb_create_simple(NULL /* FIXME */, "usb-bt-dongle"); + dev = usb_create_simple(bus, "usb-bt-dongle"); if (!dev) { return NULL; } diff --git a/hw/usb-bus.c b/hw/usb-bus.c index ae79a4527..70b7ebc08 100644 --- a/hw/usb-bus.c +++ b/hw/usb-bus.c @@ -203,13 +203,14 @@ typedef struct LegacyUSBFactory { const char *name; const char *usbdevice_name; - USBDevice *(*usbdevice_init)(const char *params); + USBDevice *(*usbdevice_init)(USBBus *bus, const char *params); } LegacyUSBFactory; static GSList *legacy_usb_factory; void usb_legacy_register(const char *typename, const char *usbdevice_name, - USBDevice *(*usbdevice_init)(const char *params)) + USBDevice *(*usbdevice_init)(USBBus *bus, + const char *params)) { if (usbdevice_name) { LegacyUSBFactory *f = g_malloc0(sizeof(*f)); @@ -224,17 +225,6 @@ USBDevice *usb_create(USBBus *bus, const char *name) { DeviceState *dev; -#if 1 - /* temporary stopgap until all usb is properly qdev-ified */ - if (!bus) { - bus = usb_bus_find(-1); - if (!bus) - return NULL; - error_report("%s: no bus specified, using \"%s\" for \"%s\"", - __FUNCTION__, bus->qbus.name, name); - } -#endif - dev = qdev_create(&bus->qbus, name); return USB_DEVICE(dev); } @@ -565,7 +555,7 @@ USBDevice *usbdevice_create(const char *cmdline) } return usb_create_simple(bus, f->name); } - return f->usbdevice_init(params); + return f->usbdevice_init(bus, params); } static void usb_device_class_init(ObjectClass *klass, void *data) diff --git a/hw/usb-msd.c b/hw/usb-msd.c index 5fbd2d021..c6f08a031 100644 --- a/hw/usb-msd.c +++ b/hw/usb-msd.c @@ -568,7 +568,7 @@ static int usb_msd_initfn(USBDevice *dev) return 0; } -static USBDevice *usb_msd_init(const char *filename) +static USBDevice *usb_msd_init(USBBus *bus, const char *filename) { static int nr=0; char id[8]; @@ -611,7 +611,7 @@ static USBDevice *usb_msd_init(const char *filename) } /* create guest device */ - dev = usb_create(NULL /* FIXME */, "usb-storage"); + dev = usb_create(bus, "usb-storage"); if (!dev) { return NULL; } diff --git a/hw/usb-net.c b/hw/usb-net.c index 49d5d4db6..22b82017e 100644 --- a/hw/usb-net.c +++ b/hw/usb-net.c @@ -1353,7 +1353,7 @@ static int usb_net_initfn(USBDevice *dev) return 0; } -static USBDevice *usb_net_init(const char *cmdline) +static USBDevice *usb_net_init(USBBus *bus, const char *cmdline) { USBDevice *dev; QemuOpts *opts; @@ -1371,7 +1371,7 @@ static USBDevice *usb_net_init(const char *cmdline) return NULL; } - dev = usb_create(NULL /* FIXME */, "usb-net"); + dev = usb_create(bus, "usb-net"); if (!dev) { return NULL; } diff --git a/hw/usb-serial.c b/hw/usb-serial.c index 52676e8f7..0aae379b2 100644 --- a/hw/usb-serial.c +++ b/hw/usb-serial.c @@ -492,7 +492,7 @@ static int usb_serial_initfn(USBDevice *dev) return 0; } -static USBDevice *usb_serial_init(const char *filename) +static USBDevice *usb_serial_init(USBBus *bus, const char *filename) { USBDevice *dev; CharDriverState *cdrv; @@ -535,7 +535,7 @@ static USBDevice *usb_serial_init(const char *filename) if (!cdrv) return NULL; - dev = usb_create(NULL /* FIXME */, "usb-serial"); + dev = usb_create(bus, "usb-serial"); if (!dev) { return NULL; } @@ -549,7 +549,7 @@ static USBDevice *usb_serial_init(const char *filename) return dev; } -static USBDevice *usb_braille_init(const char *unused) +static USBDevice *usb_braille_init(USBBus *bus, const char *unused) { USBDevice *dev; CharDriverState *cdrv; @@ -558,7 +558,7 @@ static USBDevice *usb_braille_init(const char *unused) if (!cdrv) return NULL; - dev = usb_create(NULL /* FIXME */, "usb-braille"); + dev = usb_create(bus, "usb-braille"); qdev_prop_set_chr(&dev->qdev, "chardev", cdrv); qdev_init_nofail(&dev->qdev); diff --git a/hw/usb.h b/hw/usb.h index 4470ea890..8e83697fb 100644 --- a/hw/usb.h +++ b/hw/usb.h @@ -373,12 +373,12 @@ void usb_generic_async_ctrl_complete(USBDevice *s, USBPacket *p); int set_usb_string(uint8_t *buf, const char *str); /* usb-linux.c */ -USBDevice *usb_host_device_open(const char *devname); +USBDevice *usb_host_device_open(USBBus *bus, const char *devname); int usb_host_device_close(const char *devname); void usb_host_info(Monitor *mon); /* usb-bt.c */ -USBDevice *usb_bt_init(HCIInfo *hci); +USBDevice *usb_bt_init(USBBus *bus, HCIInfo *hci); /* usb ports of the VM */ @@ -431,7 +431,8 @@ struct USBBusOps { void usb_bus_new(USBBus *bus, USBBusOps *ops, DeviceState *host); USBBus *usb_bus_find(int busnr); void usb_legacy_register(const char *typename, const char *usbdevice_name, - USBDevice *(*usbdevice_init)(const char *params)); + USBDevice *(*usbdevice_init)(USBBus *bus, + const char *params)); USBDevice *usb_create(USBBus *bus, const char *name); USBDevice *usb_create_simple(USBBus *bus, const char *name); USBDevice *usbdevice_create(const char *cmdline); diff --git a/usb-bsd.c b/usb-bsd.c index 4fa4b4215..ec2626662 100644 --- a/usb-bsd.c +++ b/usb-bsd.c @@ -298,7 +298,7 @@ static int usb_host_initfn(USBDevice *dev) return 0; } -USBDevice *usb_host_device_open(const char *devname) +USBDevice *usb_host_device_open(USBBus *guest_bus, const char *devname) { struct usb_device_info bus_info, dev_info; USBDevice *d = NULL, *ret = NULL; @@ -358,7 +358,7 @@ USBDevice *usb_host_device_open(const char *devname) goto fail_dfd; } - d = usb_create(NULL /* FIXME */, "usb-host"); + d = usb_create(guest_bus, "usb-host"); dev = DO_UPCAST(USBHostDevice, dev, d); if (dev_info.udi_speed == 1) { diff --git a/usb-linux.c b/usb-linux.c index 24700fc1f..47994f3ce 100644 --- a/usb-linux.c +++ b/usb-linux.c @@ -1443,13 +1443,13 @@ static void usb_host_register_types(void) type_init(usb_host_register_types) -USBDevice *usb_host_device_open(const char *devname) +USBDevice *usb_host_device_open(USBBus *bus, const char *devname) { struct USBAutoFilter filter; USBDevice *dev; char *p; - dev = usb_create(NULL /* FIXME */, "usb-host"); + dev = usb_create(bus, "usb-host"); if (strstr(devname, "auto:")) { if (parse_filter(devname, &filter) < 0) { diff --git a/vl.c b/vl.c index 1d4c3500a..4a7769637 100644 --- a/vl.c +++ b/vl.c @@ -1052,12 +1052,13 @@ static int usb_device_add(const char *devname) #ifndef CONFIG_LINUX /* only the linux version is qdev-ified, usb-bsd still needs this */ if (strstart(devname, "host:", &p)) { - dev = usb_host_device_open(p); + dev = usb_host_device_open(usb_bus_find(-1), p); } else #endif if (!strcmp(devname, "bt") || strstart(devname, "bt:", &p)) { - dev = usb_bt_init(devname[2] ? hci_init(p) : - bt_new_hci(qemu_find_bt_vlan(0))); + dev = usb_bt_init(usb_bus_find(-1), + devname[2] ? hci_init(p) + : bt_new_hci(qemu_find_bt_vlan(0))); } else { return -1; } -- cgit v1.2.3