From: Junjie Cao <[email protected]>

A TD marked isochronous must become inactive on NAK. Send such a TD
to the keyboard's interrupt endpoint, then inject a key and check
that the inactive TD does not consume it. A new ordinary TD must
still return that report.

Removing the isochronous ACTIVE-bit clearing in uhci_complete_td()
fails this test.

Signed-off-by: Junjie Cao <[email protected]>
---
 tests/qtest/usb-hcd-uhci-test.c | 38 ++++++++++++++++++++++++---------
 1 file changed, 28 insertions(+), 10 deletions(-)

diff --git a/tests/qtest/usb-hcd-uhci-test.c b/tests/qtest/usb-hcd-uhci-test.c
index 5c2b6cef7c..bad279e9a2 100644
--- a/tests/qtest/usb-hcd-uhci-test.c
+++ b/tests/qtest/usb-hcd-uhci-test.c
@@ -64,13 +64,17 @@ static uint32_t uhci_step(UHCITransferTest *t)
 }
 
 static void uhci_submit(UHCITransferTest *t, unsigned int pid, unsigned int ep,
-                        unsigned int len, bool data1)
+                        unsigned int len, bool data1, bool iso)
 {
     unsigned int i;
-    uint32_t ctrl = TD_CTRL_ACTIVE | TD_CTRL_IOC | 0x7ff |
-                    (3 << TD_CTRL_ERROR_SHIFT);
+    uint32_t ctrl = TD_CTRL_ACTIVE | TD_CTRL_IOC | 0x7ff;
 
     uhci_writew(t, UHCI_USBCMD, 0);
+    if (iso) {
+        ctrl |= TD_CTRL_IOS;
+    } else {
+        ctrl |= 3 << TD_CTRL_ERROR_SHIFT;
+    }
     uhci_mem_writel(t, t->td, UHCI_LINK_END);
     uhci_mem_writel(t, t->td + 4, ctrl);
     uhci_mem_writel(t, t->td + 8, pid | (ep << 15) | (data1 << 19) |
@@ -79,7 +83,8 @@ static void uhci_submit(UHCITransferTest *t, unsigned int 
pid, unsigned int ep,
     uhci_mem_writel(t, t->qh, UHCI_LINK_END);
     uhci_mem_writel(t, t->qh + 4, t->td);
     for (i = 0; i < 1024; i++) {
-        uhci_mem_writel(t, t->mem + 4 * i, t->qh | UHCI_LINK_QH);
+        uhci_mem_writel(t, t->mem + 4 * i,
+                        iso ? t->td : t->qh | UHCI_LINK_QH);
     }
     uhci_writew(t, UHCI_USBSTS, UHCI_STS_USBINT | UHCI_STS_USBERR);
     uhci_writew(t, UHCI_USBCMD, UHCI_CMD_RS);
@@ -133,15 +138,16 @@ static void uhci_transfer_init(UHCITransferTest *t)
 
     /* Configure the keyboard's interrupt endpoint through EP0 first. */
     qtest_memwrite(t->qs->qts, t->data, setup, sizeof(setup));
-    uhci_submit(t, UHCI_PID_SETUP, 0, sizeof(setup), false);
+    uhci_submit(t, UHCI_PID_SETUP, 0, sizeof(setup), false, false);
     uhci_expect_complete(t, sizeof(setup));
-    uhci_submit(t, UHCI_PID_IN, 0, 0, true);
+    uhci_submit(t, UHCI_PID_IN, 0, 0, true, false);
     uhci_expect_complete(t, 0);
 }
 
-static void test_uhci_nak(void)
+static void test_uhci_nak(gconstpointer opaque)
 {
     const uint8_t expected[] = { 0, 0, 4, 0, 0, 0, 0, 0 };
+    const bool iso = GPOINTER_TO_UINT(opaque);
     UHCITransferTest t;
     uint8_t report[sizeof(expected)];
     uint32_t ctrl;
@@ -149,11 +155,11 @@ static void test_uhci_nak(void)
 
     uhci_transfer_init(&t);
     qtest_memset(t.qs->qts, t.data, 0xa5, sizeof(report));
-    uhci_submit(&t, UHCI_PID_IN, 1, sizeof(report), false);
+    uhci_submit(&t, UHCI_PID_IN, 1, sizeof(report), false, iso);
     for (i = 0; i < 3; i++) {
         ctrl = uhci_step(&t);
         g_assert_cmphex(ctrl & (TD_CTRL_ACTIVE | TD_CTRL_NAK), ==,
-                        TD_CTRL_NAK | TD_CTRL_ACTIVE);
+                        TD_CTRL_NAK | (iso ? 0 : TD_CTRL_ACTIVE));
         g_assert_cmpuint((ctrl + 1) & 0x7ff, ==, 0);
     }
     qtest_memread(t.qs->qts, t.data, report, sizeof(report));
@@ -165,6 +171,15 @@ static void test_uhci_nak(void)
         "{'execute': 'input-send-event', 'arguments': {'events': ["
         "{'type': 'key', 'data': {'down': true, "
         "'key': {'type': 'qcode', 'data': 'a'}}}]}}");
+    if (iso) {
+        /* An inactive isochronous TD must not consume the new report. */
+        g_assert_cmphex(uhci_step(&t), ==, ctrl);
+        qtest_memread(t.qs->qts, t.data, report, sizeof(report));
+        for (i = 0; i < sizeof(report); i++) {
+            g_assert_cmphex(report[i], ==, 0xa5);
+        }
+        uhci_submit(&t, UHCI_PID_IN, 1, sizeof(report), false, false);
+    }
     uhci_expect_complete(&t, sizeof(report));
     qtest_memread(t.qs->qts, t.data, report, sizeof(report));
     g_assert_cmpmem(report, sizeof(report), expected, sizeof(expected));
@@ -231,7 +246,10 @@ int main(int argc, char **argv)
         qtest_add_func("/uhci/pci/hotplug/usb-storage", 
test_usb_storage_hotplug);
     }
     if (qtest_has_device("usb-kbd")) {
-        qtest_add_func("/uhci/pci/intr-nak", test_uhci_nak);
+        qtest_add_data_func("/uhci/pci/intr-nak", GUINT_TO_POINTER(false),
+                            test_uhci_nak);
+        qtest_add_data_func("/uhci/pci/iso-nak", GUINT_TO_POINTER(true),
+                            test_uhci_nak);
     }
 
     if (strcmp(arch, "i386") == 0 || strcmp(arch, "x86_64") == 0) {
-- 
2.43.0


Reply via email to