// SPDX-License-Identifier: GPL-2.0+ /* * Copyright (C) 2015 Google, Inc */ #include #include #include #include #include #include #include #include #include #include #include #include #include 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) { struct udevice *bus; ut_asserteq(-ENODEV, uclass_get_device_by_seq(UCLASS_USB, 0, &bus)); ut_assertok(uclass_get_device(UCLASS_USB, 0, &bus)); ut_asserteq(-ENODEV, uclass_get_device_by_seq(UCLASS_USB, 2, &bus)); return 0; } 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 * covers scanning the bug, setting up a hub and a flash stick and reading * data from the flash stick. */ static int dm_test_usb_flash(struct unit_test_state *uts) { 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_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, 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) { struct udevice *dev; state_set_skip_delays(true); ut_assertok(usb_init()); ut_assertok(uclass_get_device(UCLASS_MASS_STORAGE, 0, &dev)); ut_assertok(uclass_get_device(UCLASS_MASS_STORAGE, 1, &dev)); ut_assertok(uclass_get_device(UCLASS_MASS_STORAGE, 2, &dev)); ut_assertok(usb_stop()); return 0; } 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) { struct udevice *hub; struct uclass *uc; int count = 0; int ret; ret = uclass_get(UCLASS_USB_HUB, &uc); if (ret) return ret; uclass_foreach_dev(hub, uc) { struct udevice *dev; count++; for (device_find_first_child(hub, &dev); dev; device_find_next_child(&dev)) { count++; } } return count; } /* 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; /* Scan and check that all devices are present */ state_set_skip_delays(true); ut_assertok(usb_init()); ut_assertok(uclass_get_device(UCLASS_MASS_STORAGE, 0, &dev)); ut_assertok(uclass_get_device(UCLASS_MASS_STORAGE, 1, &dev)); ut_assertok(uclass_get_device(UCLASS_MASS_STORAGE, 2, &dev)); ut_asserteq(6, count_usb_devices()); ut_assertok(usb_stop()); ut_asserteq(0, count_usb_devices()); return 0; } DM_TEST(dm_test_usb_stop, UT_TESTF_SCAN_PDATA | UT_TESTF_SCAN_FDT); /** * 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. and * * some special keys, e.g. * * some modifiers, e.g. and * * alternative keyboard layouts * * @uts: unit test state * Return: 0 on success */ 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[] = { /* */ {0x00, 0x04, "a"}, /* */ {0x00, 0x05, "b"}, /* */ {0x00, 0x06, "c"}, /* */ {0x00, 0x07, "d"}, /* */ {0x00, 0x08, "e"}, /* */ {0x00, 0x09, "f"}, /* */ {0x00, 0x0a, "g"}, /* */ {0x00, 0x0b, "h"}, /* */ {0x00, 0x0c, "i"}, /* */ {0x00, 0x0d, "j"}, /* */ {0x00, 0x0e, "k"}, /* */ {0x00, 0x0f, "l"}, /* */ {0x00, 0x10, "m"}, /* */ {0x00, 0x11, "n"}, /* */ {0x00, 0x12, "o"}, /*

*/ {0x00, 0x13, "p"}, /* */ {0x00, 0x14, "q"}, /* */ {0x00, 0x15, "r"}, /* */ {0x00, 0x16, "s"}, /* */ {0x00, 0x17, "t"}, /* */ {0x00, 0x18, "u"}, /* */ {0x00, 0x19, "v"}, /* */ {0x00, 0x1a, "w"}, /* */ {0x00, 0x1b, "x"}, /* */ {0x00, 0x1c, "y"}, /* */ {0x00, 0x1d, "z"}, /* */ {0x02, 0x04, "A"}, /* */ {0x20, 0x1d, "Z"}, /* */ {0x01, 0x04, "\x01"}, /* */ {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"}, /* <1> */ {0x02, 0x1e, "!"}, /* <2> */ {0x20, 0x1f, "@"}, /* <3> */ {0x02, 0x20, "#"}, /* <4> */ {0x20, 0x21, "$"}, /* <5> */ {0x02, 0x22, "%"}, /* <6> */ {0x20, 0x23, "^"}, /* <7> */ {0x02, 0x24, "&"}, /* <8> */ {0x20, 0x25, "*"}, /* <9> */ {0x02, 0x26, "("}, /* <0> */ {0x20, 0x27, ")"}, /* */ {0x00, 0x28, "\r"}, /* */ {0x00, 0x29, "\x1b"}, /* */ {0x00, 0x2a, "\x08"}, /* */ {0x00, 0x2b, "\x09"}, /* */ {0x00, 0x2c, " "}, /* */ {0x00, 0x2d, "-"}, /* */ {0x00, 0x2e, "="}, /* */ {0x00, 0x2f, "["}, /* */ {0x00, 0x30, "]"}, /* */ {0x00, 0x31, "\\"}, /* */ {0x00, 0x32, "#"}, /* */ {0x00, 0x33, ";"}, /* */ {0x00, 0x34, "'"}, /* */ {0x00, 0x35, "`"}, /* */ {0x00, 0x36, ","}, /* */ {0x00, 0x37, "."}, /* */ {0x00, 0x38, "/"}, /* */ {0x02, 0x28, "\r"}, /* */ {0x20, 0x29, "\x1b"}, /* */ {0x02, 0x2a, "\x08"}, /* */ {0x20, 0x2b, "\x09"}, /* */ {0x02, 0x2c, " "}, /* */ {0x20, 0x2d, "_"}, /* */ {0x02, 0x2e, "+"}, /* */ {0x20, 0x2f, "{"}, /* */ {0x02, 0x30, "}"}, /* */ {0x20, 0x31, "|"}, /* */ {0x02, 0x32, "~"}, /* */ {0x20, 0x33, ":"}, /* */ {0x02, 0x34, "\""}, /* */ {0x20, 0x35, "~"}, /* */ {0x02, 0x36, "<"}, /* */ {0x20, 0x37, ">"}, /* */ {0x02, 0x38, "?"}, #ifdef CONFIG_USB_KEYBOARD_FN_KEYS /* */ {0x00, 0x3a, "\x1bOP"}, /* */ {0x00, 0x3b, "\x1bOQ"}, /* */ {0x00, 0x3c, "\x1bOR"}, /* */ {0x00, 0x3d, "\x1bOS"}, /* */ {0x00, 0x3e, "\x1b[15~"}, /* */ {0x00, 0x3f, "\x1b[17~"}, /* */ {0x00, 0x40, "\x1b[18~"}, /* */ {0x00, 0x41, "\x1b[19~"}, /* */ {0x00, 0x42, "\x1b[20~"}, /* */ {0x00, 0x43, "\x1b[21~"}, /* */ {0x00, 0x44, "\x1b[23~"}, /* */ {0x00, 0x45, "\x1b[24~"}, /* */ {0x00, 0x49, "\x1b[2~"}, /* */ {0x00, 0x4a, "\x1b[H"}, /* */ {0x00, 0x4b, "\x1b[5~"}, /* */ {0x00, 0x4c, "\x1b[3~"}, /* */ {0x00, 0x4d, "\x1b[F"}, /* */ {0x00, 0x4e, "\x1b[6~"}, /* */ {0x00, 0x4f, "\x1b[C"}, /* */ {0x00, 0x50, "\x1b[D"}, /* */ {0x00, 0x51, "\x1b[B"}, /* */ {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@3", &dev)); /* * Add scan codes to the USB keyboard buffer. They should appear as * corresponding characters and escape sequences in stdin. */ 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, UT_TESTF_SCAN_PDATA | UT_TESTF_SCAN_FDT);