aboutsummaryrefslogtreecommitdiff
path: root/hw/usb-ehci.c
diff options
context:
space:
mode:
authorGerd Hoffmann <kraxel@redhat.com>2011-08-26 14:13:48 +0200
committerGerd Hoffmann <kraxel@redhat.com>2011-09-07 09:58:16 +0200
commit2fe80192ba82fe298fe656c80d7e5981929393a6 (patch)
treebede8cf4b284aa3f4aee2b3989fe22d8ebbf17f7 /hw/usb-ehci.c
parentc0e5750bc35366b7231693d9ae433bea9a485ef0 (diff)
usb-ehci: handle siTDs
This patch adds code to do minimal siTD handling, which is basically just following the next pointer. This is good enougth to handle the inactive siTDs used by FreeBSD. Active siTDs are skipped too as we don't have split transfer support in qemu, additionally a warning is printed. Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
Diffstat (limited to 'hw/usb-ehci.c')
-rw-r--r--hw/usb-ehci.c43
1 files changed, 42 insertions, 1 deletions
diff --git a/hw/usb-ehci.c b/hw/usb-ehci.c
index 47a7fb9de4..d8ef0cb422 100644
--- a/hw/usb-ehci.c
+++ b/hw/usb-ehci.c
@@ -149,6 +149,7 @@ typedef enum {
EST_FETCHENTRY,
EST_FETCHQH,
EST_FETCHITD,
+ EST_FETCHSITD,
EST_ADVANCEQUEUE,
EST_FETCHQTD,
EST_EXECUTE,
@@ -646,6 +647,13 @@ static void ehci_trace_itd(EHCIState *s, target_phys_addr_t addr, EHCIitd *itd)
get_field(itd->bufptr[0], ITD_BUFPTR_DEVADDR));
}
+static void ehci_trace_sitd(EHCIState *s, target_phys_addr_t addr,
+ EHCIsitd *sitd)
+{
+ trace_usb_ehci_sitd(addr, sitd->next,
+ (bool)(sitd->results & SITD_RESULTS_ACTIVE));
+}
+
/* queue management */
static EHCIQueue *ehci_alloc_queue(EHCIState *ehci, int async)
@@ -1584,8 +1592,13 @@ static int ehci_state_fetchentry(EHCIState *ehci, int async)
again = 1;
break;
+ case NLPTR_TYPE_STITD:
+ ehci_set_state(ehci, async, EST_FETCHSITD);
+ again = 1;
+ break;
+
default:
- // TODO: handle siTD and FSTN types
+ /* TODO: handle FSTN type */
fprintf(stderr, "FETCHENTRY: entry at %X is of type %d "
"which is not supported yet\n", entry, NLPTR_TYPE_GET(entry));
return -1;
@@ -1701,6 +1714,30 @@ static int ehci_state_fetchitd(EHCIState *ehci, int async)
return 1;
}
+static int ehci_state_fetchsitd(EHCIState *ehci, int async)
+{
+ uint32_t entry;
+ EHCIsitd sitd;
+
+ assert(!async);
+ entry = ehci_get_fetch_addr(ehci, async);
+
+ get_dwords(NLPTR_GET(entry), (uint32_t *)&sitd,
+ sizeof(EHCIsitd) >> 2);
+ ehci_trace_sitd(ehci, entry, &sitd);
+
+ if (!(sitd.results & SITD_RESULTS_ACTIVE)) {
+ /* siTD is not active, nothing to do */;
+ } else {
+ /* TODO: split transfers are not implemented */
+ fprintf(stderr, "WARNING: Skipping active siTD\n");
+ }
+
+ ehci_set_fetch_addr(ehci, async, sitd.next);
+ ehci_set_state(ehci, async, EST_FETCHENTRY);
+ return 1;
+}
+
/* Section 4.10.2 - paragraph 3 */
static int ehci_state_advqueue(EHCIQueue *q, int async)
{
@@ -1976,6 +2013,10 @@ static void ehci_advance_state(EHCIState *ehci,
again = ehci_state_fetchitd(ehci, async);
break;
+ case EST_FETCHSITD:
+ again = ehci_state_fetchsitd(ehci, async);
+ break;
+
case EST_ADVANCEQUEUE:
again = ehci_state_advqueue(q, async);
break;