+// SPDX-License-Identifier: GPL-2.0+
/*
* Copyright (C) 2015 Google, Inc
- *
- * SPDX-License-Identifier: GPL-2.0+
*/
#include <common.h>
#include <console.h>
#include <dm.h>
+#include <part.h>
#include <usb.h>
#include <asm/io.h>
#include <asm/state.h>
#include <dm/device-internal.h>
#include <dm/test.h>
#include <dm/uclass-internal.h>
+#include <test/test.h>
#include <test/ut.h>
-DECLARE_GLOBAL_DATA_PTR;
+struct keyboard_test_data {
+ const char modifiers;
+ const char scancode;
+ const char result[6];
+};
/* Test that sandbox USB works correctly */
static int dm_test_usb_base(struct unit_test_state *uts)
return 0;
}
-DM_TEST(dm_test_usb_base, DM_TESTF_SCAN_PDATA | DM_TESTF_SCAN_FDT);
+DM_TEST(dm_test_usb_base, UT_TESTF_SCAN_PDATA | UT_TESTF_SCAN_FDT);
/*
* Test that we can use the flash stick. This is more of a functional test. It
*/
static int dm_test_usb_flash(struct unit_test_state *uts)
{
- struct udevice *dev;
- struct blk_desc *dev_desc;
+ struct blk_desc *dev_desc, *chk;
+ struct udevice *dev, *blk;
char cmp[1024];
state_set_skip_delays(true);
ut_assertok(usb_init());
ut_assertok(uclass_get_device(UCLASS_MASS_STORAGE, 0, &dev));
ut_assertok(blk_get_device_by_str("usb", "0", &dev_desc));
+ chk = blk_get_by_device(dev);
+ ut_asserteq_ptr(chk, dev_desc);
+
+ ut_assertok(device_find_first_child_by_uclass(dev, UCLASS_BLK, &blk));
+ ut_asserteq_ptr(chk, blk_get_by_device(dev));
/* Read a few blocks and look for the string we expect */
ut_asserteq(512, dev_desc->blksz);
memset(cmp, '\0', sizeof(cmp));
- ut_asserteq(2, blk_dread(dev_desc, 0, 2, cmp));
- ut_assertok(strcmp(cmp, "this is a test"));
+ ut_asserteq(2, blk_read(blk, 0, 2, cmp));
+ ut_asserteq_str("this is a test", cmp);
+
+ strcpy(cmp, "another test");
+ ut_asserteq(1, blk_write(blk, 1, 1, cmp));
+
+ memset(cmp, '\0', sizeof(cmp));
+ ut_asserteq(2, blk_read(blk, 0, 2, cmp));
+ ut_asserteq_str("this is a test", cmp);
+ ut_asserteq_str("another test", cmp + 512);
+
+ memset(cmp, '\0', sizeof(cmp));
+ ut_asserteq(1, blk_write(blk, 1, 1, cmp));
+
+ memset(cmp, '\0', sizeof(cmp));
+ ut_asserteq(2, blk_read(blk, 0, 2, cmp));
+ ut_asserteq_str("this is a test", cmp);
+ ut_asserteq_str("", cmp + 512);
+
ut_assertok(usb_stop());
return 0;
}
-DM_TEST(dm_test_usb_flash, DM_TESTF_SCAN_PDATA | DM_TESTF_SCAN_FDT);
+DM_TEST(dm_test_usb_flash, UT_TESTF_SCAN_PDATA | UT_TESTF_SCAN_FDT);
/* test that we can handle multiple storage devices */
static int dm_test_usb_multi(struct unit_test_state *uts)
return 0;
}
-DM_TEST(dm_test_usb_multi, DM_TESTF_SCAN_PDATA | DM_TESTF_SCAN_FDT);
+DM_TEST(dm_test_usb_multi, UT_TESTF_SCAN_PDATA | UT_TESTF_SCAN_FDT);
+
+/* test that we have an associated ofnode with the usb device */
+static int dm_test_usb_fdt_node(struct unit_test_state *uts)
+{
+ struct udevice *dev;
+ ofnode node;
+
+ state_set_skip_delays(true);
+ ut_assertok(usb_init());
+ ut_assertok(uclass_get_device(UCLASS_MASS_STORAGE, 0, &dev));
+ node = ofnode_path("/usb@1/hub/usbstor@1");
+ ut_asserteq(1, ofnode_equal(node, dev_ofnode(dev)));
+ ut_assertok(uclass_get_device(UCLASS_MASS_STORAGE, 1, &dev));
+ ut_asserteq(1, ofnode_equal(ofnode_null(), dev_ofnode(dev)));
+ ut_assertok(uclass_get_device(UCLASS_MASS_STORAGE, 2, &dev));
+ node = ofnode_path("/usb@1/hub/usbstor@3");
+ ut_asserteq(1, ofnode_equal(node, dev_ofnode(dev)));
+ ut_assertok(usb_stop());
+
+ return 0;
+}
+DM_TEST(dm_test_usb_fdt_node, UT_TESTF_SCAN_PDATA | UT_TESTF_SCAN_FDT);
static int count_usb_devices(void)
{
return count;
}
-/* test that we can remove an emulated device and it is then not found */
-static int dm_test_usb_remove(struct unit_test_state *uts)
+/* test that no USB devices are found after we stop the stack */
+static int dm_test_usb_stop(struct unit_test_state *uts)
{
- struct udevice *dev, *emul;
+ struct udevice *dev;
/* Scan and check that all devices are present */
state_set_skip_delays(true);
ut_assertok(uclass_get_device(UCLASS_MASS_STORAGE, 2, &dev));
ut_asserteq(6, count_usb_devices());
ut_assertok(usb_stop());
- ut_asserteq(6, count_usb_devices());
-
- /* Remove the second emulation device */
- ut_assertok(uclass_find_device_by_name(UCLASS_USB_EMUL, "flash-stick@1",
- &dev));
- ut_assertok(device_unbind(dev));
-
- /* Rescan - only the first and third should be present */
- ut_assertok(usb_init());
- ut_assertok(uclass_get_device(UCLASS_MASS_STORAGE, 0, &dev));
- ut_assertok(usb_emul_find_for_dev(dev, &emul));
- ut_asserteq_str("flash-stick@0", emul->name);
- ut_assertok(uclass_get_device(UCLASS_MASS_STORAGE, 1, &dev));
- ut_assertok(usb_emul_find_for_dev(dev, &emul));
- ut_asserteq_str("flash-stick@2", emul->name);
-
- ut_asserteq(-ENODEV, uclass_get_device(UCLASS_MASS_STORAGE, 2, &dev));
-
- ut_asserteq(5, count_usb_devices());
- ut_assertok(usb_stop());
- ut_asserteq(5, count_usb_devices());
-
- return 0;
-}
-DM_TEST(dm_test_usb_remove, DM_TESTF_SCAN_PDATA | DM_TESTF_SCAN_FDT);
-
-const char usb_tree_base[] =
-" 1 Hub (12 Mb/s, 100mA)\n"
-" | sandbox hub 2345\n"
-" |\n"
-" |\b+-2 Mass Storage (12 Mb/s, 100mA)\n"
-" | sandbox flash flash-stick@0\n"
-" | \n"
-" |\b+-3 Mass Storage (12 Mb/s, 100mA)\n"
-" | sandbox flash flash-stick@1\n"
-" | \n"
-" |\b+-4 Mass Storage (12 Mb/s, 100mA)\n"
-" | sandbox flash flash-stick@2\n"
-" | \n"
-" |\b+-5 Human Interface (12 Mb/s, 100mA)\n"
-" sandbox keyboard keyb@3\n"
-" \n";
-
-/* test that the 'usb tree' command output looks correct */
-static int dm_test_usb_tree(struct unit_test_state *uts)
-{
- char *data;
- int len;
-
- state_set_skip_delays(true);
- ut_assertok(usb_init());
- console_record_reset_enable();
- usb_show_tree();
- len = membuff_getraw(&gd->console_out, -1, true, &data);
- if (len)
- data[len] = '\0';
- ut_asserteq_str(usb_tree_base, data);
- ut_assertok(usb_stop());
-
- return 0;
-}
-DM_TEST(dm_test_usb_tree, DM_TESTF_SCAN_PDATA | DM_TESTF_SCAN_FDT);
-
-const char usb_tree_remove[] =
-" 1 Hub (12 Mb/s, 100mA)\n"
-" | sandbox hub 2345\n"
-" |\n"
-" |\b+-2 Mass Storage (12 Mb/s, 100mA)\n"
-" | sandbox flash flash-stick@0\n"
-" | \n"
-" |\b+-3 Mass Storage (12 Mb/s, 100mA)\n"
-" | sandbox flash flash-stick@2\n"
-" | \n"
-" |\b+-4 Human Interface (12 Mb/s, 100mA)\n"
-" sandbox keyboard keyb@3\n"
-" \n";
-
-/*
- * test that the 'usb tree' command output looks correct when we remove a
- * device
- */
-static int dm_test_usb_tree_remove(struct unit_test_state *uts)
-{
- struct udevice *dev;
- char *data;
- int len;
-
- /* Remove the second emulation device */
- ut_assertok(uclass_find_device_by_name(UCLASS_USB_EMUL, "flash-stick@1",
- &dev));
- ut_assertok(device_unbind(dev));
-
- state_set_skip_delays(true);
- ut_assertok(usb_init());
- console_record_reset_enable();
- usb_show_tree();
- len = membuff_getraw(&gd->console_out, -1, true, &data);
- if (len)
- data[len] = '\0';
- ut_asserteq_str(usb_tree_remove, data);
- ut_assertok(usb_stop());
+ ut_asserteq(0, count_usb_devices());
return 0;
}
-DM_TEST(dm_test_usb_tree_remove, DM_TESTF_SCAN_PDATA | DM_TESTF_SCAN_FDT);
-
-const char usb_tree_reorder[] =
-" 1 Hub (12 Mb/s, 100mA)\n"
-" | sandbox hub 2345\n"
-" |\n"
-" |\b+-2 Mass Storage (12 Mb/s, 100mA)\n"
-" | sandbox flash flash-stick@0\n"
-" | \n"
-" |\b+-3 Mass Storage (12 Mb/s, 100mA)\n"
-" | sandbox flash flash-stick@2\n"
-" | \n"
-" |\b+-4 Human Interface (12 Mb/s, 100mA)\n"
-" | sandbox keyboard keyb@3\n"
-" | \n"
-" |\b+-5 Mass Storage (12 Mb/s, 100mA)\n"
-" sandbox flash flash-stick@1\n"
-" \n";
+DM_TEST(dm_test_usb_stop, UT_TESTF_SCAN_PDATA | UT_TESTF_SCAN_FDT);
-/*
- * test that the 'usb tree' command output looks correct when we reorder two
- * devices.
+/**
+ * dm_test_usb_keyb() - test USB keyboard driver
+ *
+ * This test copies USB keyboard scan codes into the key buffer of the USB
+ * keyboard emulation driver. These are picked up during emulated interrupts
+ * by the USB keyboard driver and converted to characters and escape sequences.
+ * The test then reads and verifies these characters and escape sequences from
+ * the standard input.
+ *
+ * TODO: The following features are not yet tested:
+ *
+ * * LED status
+ * * caps-lock
+ * * num-lock
+ * * numerical pad keys
+ *
+ * TODO: The following features are not yet implemented by the USB keyboard
+ * driver and therefore not tested:
+ *
+ * * modifiers for non-alpha-numeric keys, e.g. <SHIFT><TAB> and <ALT><F4>
+ * * some special keys, e.g. <PRINT>
+ * * some modifiers, e.g. <ALT> and <META>
+ * * alternative keyboard layouts
+ *
+ * @uts: unit test state
+ * Return: 0 on success
*/
-static int dm_test_usb_tree_reorder(struct unit_test_state *uts)
-{
- struct udevice *dev, *parent;
- char *data;
- int len;
-
- /* Remove the second emulation device */
- ut_assertok(uclass_find_device_by_name(UCLASS_USB_EMUL, "flash-stick@1",
- &dev));
- parent = dev->parent;
-
- /* Reorder the devices in the parent list and uclass list */
- list_del(&dev->sibling_node);
- list_add_tail(&dev->sibling_node, &parent->child_head);
-
- list_del(&dev->uclass_node);
- list_add_tail(&dev->uclass_node, &dev->uclass->dev_head);
-
- state_set_skip_delays(true);
- ut_assertok(usb_init());
- console_record_reset_enable();
- usb_show_tree();
- len = membuff_getraw(&gd->console_out, -1, true, &data);
- if (len)
- data[len] = '\0';
- ut_asserteq_str(usb_tree_reorder, data);
- ut_assertok(usb_stop());
-
- return 0;
-}
-DM_TEST(dm_test_usb_tree_reorder, DM_TESTF_SCAN_PDATA | DM_TESTF_SCAN_FDT);
-
static int dm_test_usb_keyb(struct unit_test_state *uts)
{
struct udevice *dev;
+ const struct keyboard_test_data *pos;
+ const struct keyboard_test_data kbd_test_data[] = {
+ /* <A> */
+ {0x00, 0x04, "a"},
+ /* <B> */
+ {0x00, 0x05, "b"},
+ /* <C> */
+ {0x00, 0x06, "c"},
+ /* <D> */
+ {0x00, 0x07, "d"},
+ /* <E> */
+ {0x00, 0x08, "e"},
+ /* <F> */
+ {0x00, 0x09, "f"},
+ /* <G> */
+ {0x00, 0x0a, "g"},
+ /* <H> */
+ {0x00, 0x0b, "h"},
+ /* <I> */
+ {0x00, 0x0c, "i"},
+ /* <J> */
+ {0x00, 0x0d, "j"},
+ /* <K> */
+ {0x00, 0x0e, "k"},
+ /* <L> */
+ {0x00, 0x0f, "l"},
+ /* <M> */
+ {0x00, 0x10, "m"},
+ /* <N> */
+ {0x00, 0x11, "n"},
+ /* <O> */
+ {0x00, 0x12, "o"},
+ /* <P> */
+ {0x00, 0x13, "p"},
+ /* <Q> */
+ {0x00, 0x14, "q"},
+ /* <R> */
+ {0x00, 0x15, "r"},
+ /* <S> */
+ {0x00, 0x16, "s"},
+ /* <T> */
+ {0x00, 0x17, "t"},
+ /* <U> */
+ {0x00, 0x18, "u"},
+ /* <V> */
+ {0x00, 0x19, "v"},
+ /* <W> */
+ {0x00, 0x1a, "w"},
+ /* <X> */
+ {0x00, 0x1b, "x"},
+ /* <Y> */
+ {0x00, 0x1c, "y"},
+ /* <Z> */
+ {0x00, 0x1d, "z"},
+
+ /* <LEFT-SHIFT><A> */
+ {0x02, 0x04, "A"},
+ /* <RIGHT-SHIFT><Z> */
+ {0x20, 0x1d, "Z"},
+
+ /* <LEFT-CONTROL><A> */
+ {0x01, 0x04, "\x01"},
+ /* <RIGHT-CONTROL><Z> */
+ {0x10, 0x1d, "\x1a"},
+
+ /* <1> */
+ {0x00, 0x1e, "1"},
+ /* <2> */
+ {0x00, 0x1f, "2"},
+ /* <3> */
+ {0x00, 0x20, "3"},
+ /* <4> */
+ {0x00, 0x21, "4"},
+ /* <5> */
+ {0x00, 0x22, "5"},
+ /* <6> */
+ {0x00, 0x23, "6"},
+ /* <7> */
+ {0x00, 0x24, "7"},
+ /* <8> */
+ {0x00, 0x25, "8"},
+ /* <9> */
+ {0x00, 0x26, "9"},
+ /* <0> */
+ {0x00, 0x27, "0"},
+
+ /* <LEFT-SHIFT><1> */
+ {0x02, 0x1e, "!"},
+ /* <RIGHT-SHIFT><2> */
+ {0x20, 0x1f, "@"},
+ /* <LEFT-SHIFT><3> */
+ {0x02, 0x20, "#"},
+ /* <RIGHT-SHIFT><4> */
+ {0x20, 0x21, "$"},
+ /* <LEFT-SHIFT><5> */
+ {0x02, 0x22, "%"},
+ /* <RIGHT-SHIFT><6> */
+ {0x20, 0x23, "^"},
+ /* <LEFT-SHIFT><7> */
+ {0x02, 0x24, "&"},
+ /* <RIGHT-SHIFT><8> */
+ {0x20, 0x25, "*"},
+ /* <LEFT-SHIFT><9> */
+ {0x02, 0x26, "("},
+ /* <RIGHT-SHIFT><0> */
+ {0x20, 0x27, ")"},
+
+ /* <ENTER> */
+ {0x00, 0x28, "\r"},
+ /* <ESCAPE> */
+ {0x00, 0x29, "\x1b"},
+ /* <BACKSPACE> */
+ {0x00, 0x2a, "\x08"},
+ /* <TAB> */
+ {0x00, 0x2b, "\x09"},
+ /* <SPACE> */
+ {0x00, 0x2c, " "},
+ /* <MINUS> */
+ {0x00, 0x2d, "-"},
+ /* <EQUAL> */
+ {0x00, 0x2e, "="},
+ /* <LEFT BRACE> */
+ {0x00, 0x2f, "["},
+ /* <RIGHT BRACE> */
+ {0x00, 0x30, "]"},
+ /* <BACKSLASH> */
+ {0x00, 0x31, "\\"},
+ /* <HASH-TILDE> */
+ {0x00, 0x32, "#"},
+ /* <SEMICOLON> */
+ {0x00, 0x33, ";"},
+ /* <APOSTROPHE> */
+ {0x00, 0x34, "'"},
+ /* <GRAVE> */
+ {0x00, 0x35, "`"},
+ /* <COMMA> */
+ {0x00, 0x36, ","},
+ /* <DOT> */
+ {0x00, 0x37, "."},
+ /* <SLASH> */
+ {0x00, 0x38, "/"},
+
+ /* <LEFT-SHIFT><ENTER> */
+ {0x02, 0x28, "\r"},
+ /* <RIGHT-SHIFT><ESCAPE> */
+ {0x20, 0x29, "\x1b"},
+ /* <LEFT-SHIFT><BACKSPACE> */
+ {0x02, 0x2a, "\x08"},
+ /* <RIGHT-SHIFT><TAB> */
+ {0x20, 0x2b, "\x09"},
+ /* <LEFT-SHIFT><SPACE> */
+ {0x02, 0x2c, " "},
+ /* <MINUS> */
+ {0x20, 0x2d, "_"},
+ /* <LEFT-SHIFT><EQUAL> */
+ {0x02, 0x2e, "+"},
+ /* <RIGHT-SHIFT><LEFT BRACE> */
+ {0x20, 0x2f, "{"},
+ /* <LEFT-SHIFT><RIGHT BRACE> */
+ {0x02, 0x30, "}"},
+ /* <RIGHT-SHIFT><BACKSLASH> */
+ {0x20, 0x31, "|"},
+ /* <LEFT-SHIFT><HASH-TILDE> */
+ {0x02, 0x32, "~"},
+ /* <RIGHT-SHIFT><SEMICOLON> */
+ {0x20, 0x33, ":"},
+ /* <LEFT-SHIFT><APOSTROPHE> */
+ {0x02, 0x34, "\""},
+ /* <RIGHT-SHIFT><GRAVE> */
+ {0x20, 0x35, "~"},
+ /* <LEFT-SHIFT><COMMA> */
+ {0x02, 0x36, "<"},
+ /* <RIGHT-SHIFT><DOT> */
+ {0x20, 0x37, ">"},
+ /* <LEFT-SHIFT><SLASH> */
+ {0x02, 0x38, "?"},
+#ifdef CONFIG_USB_KEYBOARD_FN_KEYS
+ /* <F1> */
+ {0x00, 0x3a, "\x1bOP"},
+ /* <F2> */
+ {0x00, 0x3b, "\x1bOQ"},
+ /* <F3> */
+ {0x00, 0x3c, "\x1bOR"},
+ /* <F4> */
+ {0x00, 0x3d, "\x1bOS"},
+ /* <F5> */
+ {0x00, 0x3e, "\x1b[15~"},
+ /* <F6> */
+ {0x00, 0x3f, "\x1b[17~"},
+ /* <F7> */
+ {0x00, 0x40, "\x1b[18~"},
+ /* <F8> */
+ {0x00, 0x41, "\x1b[19~"},
+ /* <F9> */
+ {0x00, 0x42, "\x1b[20~"},
+ /* <F10> */
+ {0x00, 0x43, "\x1b[21~"},
+ /* <F11> */
+ {0x00, 0x44, "\x1b[23~"},
+ /* <F12> */
+ {0x00, 0x45, "\x1b[24~"},
+ /* <INSERT> */
+ {0x00, 0x49, "\x1b[2~"},
+ /* <HOME> */
+ {0x00, 0x4a, "\x1b[H"},
+ /* <PAGE UP> */
+ {0x00, 0x4b, "\x1b[5~"},
+ /* <DELETE> */
+ {0x00, 0x4c, "\x1b[3~"},
+ /* <END> */
+ {0x00, 0x4d, "\x1b[F"},
+ /* <PAGE DOWN> */
+ {0x00, 0x4e, "\x1b[6~"},
+ /* <RIGHT> */
+ {0x00, 0x4f, "\x1b[C"},
+ /* <LEFT> */
+ {0x00, 0x50, "\x1b[D"},
+ /* <DOWN> */
+ {0x00, 0x51, "\x1b[B"},
+ /* <UP> */
+ {0x00, 0x52, "\x1b[A"},
+#endif /* CONFIG_USB_KEYBOARD_FN_KEYS */
+
+ /* End of list */
+ {0x00, 0x00, "\0"}
+ };
+
state_set_skip_delays(true);
ut_assertok(usb_init());
/* Initially there should be no characters */
ut_asserteq(0, tstc());
- ut_assertok(uclass_get_device_by_name(UCLASS_USB_EMUL, "keyb",
+ ut_assertok(uclass_get_device_by_name(UCLASS_USB_EMUL, "keyb@3",
&dev));
/*
- * Add a string to the USB keyboard buffer - it should appear in
- * stdin
+ * Add scan codes to the USB keyboard buffer. They should appear as
+ * corresponding characters and escape sequences in stdin.
*/
- ut_assertok(sandbox_usb_keyb_add_string(dev, "ab"));
- ut_asserteq(1, tstc());
- ut_asserteq('a', getc());
- ut_asserteq(1, tstc());
- ut_asserteq('b', getc());
- ut_asserteq(0, tstc());
+ for (pos = kbd_test_data; pos->scancode; ++pos) {
+ const char *c;
+ char scancodes[USB_KBD_BOOT_REPORT_SIZE] = {0};
+
+ scancodes[0] = pos->modifiers;
+ scancodes[2] = pos->scancode;
+
+ ut_assertok(sandbox_usb_keyb_add_string(dev, scancodes));
+ for (c = pos->result; *c; ++c) {
+ ut_asserteq(1, tstc());
+ ut_asserteq(*c, getchar());
+ }
+ ut_asserteq(0, tstc());
+ }
ut_assertok(usb_stop());
return 0;
}
-DM_TEST(dm_test_usb_keyb, DM_TESTF_SCAN_PDATA | DM_TESTF_SCAN_FDT);
+DM_TEST(dm_test_usb_keyb, UT_TESTF_SCAN_PDATA | UT_TESTF_SCAN_FDT);