From patchwork Wed Feb 3 15:49:39 2010 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: "David S. Ahern" X-Patchwork-Id: 76736 Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by demeter.kernel.org (8.14.3/8.14.3) with ESMTP id o13Fodp9022859 for ; Wed, 3 Feb 2010 15:50:39 GMT Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S932521Ab0BCPto (ORCPT ); Wed, 3 Feb 2010 10:49:44 -0500 Received: from sj-iport-3.cisco.com ([171.71.176.72]:28361 "EHLO sj-iport-3.cisco.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S932517Ab0BCPtl (ORCPT ); Wed, 3 Feb 2010 10:49:41 -0500 Authentication-Results: sj-iport-3.cisco.com; dkim=neutral (message not signed) header.i=none X-Files: qemu-usb-isochronous.patch : 4663 X-IronPort-Anti-Spam-Filtered: true X-IronPort-Anti-Spam-Result: ApoEAD0qaUurR7Hu/2dsb2JhbADBHJgQhEUE X-IronPort-AV: E=Sophos;i="4.49,399,1262563200"; d="scan'208";a="210705922" Received: from sj-core-5.cisco.com ([171.71.177.238]) by sj-iport-3.cisco.com with ESMTP; 03 Feb 2010 15:49:40 +0000 Received: from [10.89.3.230] (rcdn-vpn-client-10-89-3-230.cisco.com [10.89.3.230]) by sj-core-5.cisco.com (8.13.8/8.14.3) with ESMTP id o13FndQf009317; Wed, 3 Feb 2010 15:49:40 GMT Message-ID: <4B699B13.60802@cisco.com> Date: Wed, 03 Feb 2010 08:49:39 -0700 From: "David S. Ahern" User-Agent: Mozilla/5.0 (X11; U; Linux x86_64; en-US; rv:1.9.1.7) Gecko/20100120 Fedora/3.0.1-1.fc11 Thunderbird/3.0.1 MIME-Version: 1.0 To: qemu-devel@nongnu.org, kvm-devel Subject: [PATCH] audio streaming from usb devices Sender: kvm-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: kvm@vger.kernel.org X-Greylist: IP, sender and recipient auto-whitelisted, not delayed by milter-greylist-4.2.3 (demeter.kernel.org [140.211.167.41]); Wed, 03 Feb 2010 15:50:39 +0000 (UTC) diff --git a/hw/usb-uhci.c b/hw/usb-uhci.c index fdbb4d1..19b4ce6 100644 --- a/hw/usb-uhci.c +++ b/hw/usb-uhci.c @@ -112,6 +112,7 @@ typedef struct UHCIAsync { uint32_t td; uint32_t token; int8_t valid; + uint8_t isoc; uint8_t done; uint8_t buffer[2048]; } UHCIAsync; @@ -131,6 +132,7 @@ typedef struct UHCIState { uint32_t fl_base_addr; /* frame list base address */ uint8_t sof_timing; uint8_t status2; /* bit 0 and 1 are used to generate UHCI_STS_USBINT */ + int64_t expire_time; QEMUTimer *frame_timer; UHCIPort ports[NB_PORTS]; @@ -164,6 +166,7 @@ static UHCIAsync *uhci_async_alloc(UHCIState *s) async->td = 0; async->token = 0; async->done = 0; + async->isoc = 0; async->next = NULL; return async; @@ -762,13 +765,25 @@ 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; + uint8_t pid, isoc; + uint32_t token; /* Is active ? */ if (!(td->ctrl & TD_CTRL_ACTIVE)) return 1; - async = uhci_async_find_td(s, addr, td->token); + /* 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); if (async) { /* Already submitted */ async->valid = 32; @@ -785,9 +800,13 @@ static int uhci_handle_td(UHCIState *s, uint32_t addr, UHCI_TD *td, uint32_t *in if (!async) return 1; - async->valid = 10; + /* valid needs to be large enough to handle 10 frame delay + * for initial isochronous requests + */ + async->valid = 32; async->td = addr; - async->token = td->token; + async->token = token; + async->isoc = isoc; max_len = ((td->token >> 21) + 1) & 0x7ff; pid = td->token & 0xff; @@ -841,9 +860,31 @@ static void uhci_async_complete(USBPacket *packet, void *opaque) dprintf("uhci: async complete. td 0x%x token 0x%x\n", async->td, async->token); - async->done = 1; + if (async->isoc) { + UHCI_TD td; + uint32_t link = async->td; + uint32_t int_mask = 0, val; + int len; + + cpu_physical_memory_read(link & ~0xf, (uint8_t *) &td, sizeof(td)); + le32_to_cpus(&td.link); + le32_to_cpus(&td.ctrl); + le32_to_cpus(&td.token); + le32_to_cpus(&td.buffer); + + uhci_async_unlink(s, async); + len = uhci_complete_td(s, &td, async, &int_mask); + s->pending_int_mask |= int_mask; - uhci_process_frame(s); + /* update the status bits of the TD */ + val = cpu_to_le32(td.ctrl); + cpu_physical_memory_write((link & ~0xf) + 4, + (const uint8_t *)&val, sizeof(val)); + uhci_async_free(s, async); + } else { + async->done = 1; + uhci_process_frame(s); + } } static int is_valid(uint32_t link) @@ -1005,13 +1046,15 @@ static void uhci_process_frame(UHCIState *s) /* go to the next entry */ } - s->pending_int_mask = int_mask; + s->pending_int_mask |= int_mask; } static void uhci_frame_timer(void *opaque) { UHCIState *s = opaque; - int64_t expire_time; + + /* prepare the timer for the next frame */ + s->expire_time += (get_ticks_per_sec() / FRAME_TIMER_FREQ); if (!(s->cmd & UHCI_CMD_RS)) { /* Full stop */ @@ -1029,6 +1072,7 @@ static void uhci_frame_timer(void *opaque) s->status |= UHCI_STS_USBINT; uhci_update_irq(s); } + s->pending_int_mask = 0; /* Start new frame */ s->frnum = (s->frnum + 1) & 0x7ff; @@ -1041,10 +1085,7 @@ static void uhci_frame_timer(void *opaque) uhci_async_validate_end(s); - /* prepare the timer for the next frame */ - expire_time = qemu_get_clock(vm_clock) + - (get_ticks_per_sec() / FRAME_TIMER_FREQ); - qemu_mod_timer(s->frame_timer, expire_time); + qemu_mod_timer(s->frame_timer, s->expire_time); } static void uhci_map(PCIDevice *pci_dev, int region_num, @@ -1078,6 +1119,8 @@ static int usb_uhci_common_initfn(UHCIState *s) usb_register_port(&s->bus, &s->ports[i].port, s, i, uhci_attach); } s->frame_timer = qemu_new_timer(vm_clock, uhci_frame_timer, s); + s->expire_time = qemu_get_clock(vm_clock) + + (get_ticks_per_sec() / FRAME_TIMER_FREQ); s->num_ports_vmstate = NB_PORTS; qemu_register_reset(uhci_reset, s);