u-boot/test/dm/usb.c
Michael Walle c03b7612ea usb: provide a device tree node to USB devices
It is possible to specify a device tree node for an USB device. This is
useful if you have a static USB setup and want to use aliases which
point to these nodes, like on the Raspberry Pi.
The nodes are matched against their hub port number, the compatible
strings are not matched for now.

Signed-off-by: Michael Walle <michael@walle.cc>
Reviewed-by: Marek Vasut <marex@denx.de>
Reviewed-by: Simon Glass <sjg@chromium.org>
2020-06-11 20:52:11 -06:00

438 lines
10 KiB
C

// SPDX-License-Identifier: GPL-2.0+
/*
* Copyright (C) 2015 Google, Inc
*/
#include <common.h>
#include <console.h>
#include <dm.h>
#include <part.h>
#include <usb.h>
#include <asm/io.h>
#include <asm/state.h>
#include <asm/test.h>
#include <dm/device-internal.h>
#include <dm/test.h>
#include <dm/uclass-internal.h>
#include <test/ut.h>
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, DM_TESTF_SCAN_PDATA | DM_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 udevice *dev;
struct blk_desc *dev_desc;
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));
/* 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_assertok(usb_stop());
return 0;
}
DM_TEST(dm_test_usb_flash, DM_TESTF_SCAN_PDATA | DM_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, DM_TESTF_SCAN_PDATA | DM_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, DM_TESTF_SCAN_PDATA | DM_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, DM_TESTF_SCAN_PDATA | DM_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. <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_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@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, getc());
}
ut_asserteq(0, tstc());
}
ut_assertok(usb_stop());
return 0;
}
DM_TEST(dm_test_usb_keyb, DM_TESTF_SCAN_PDATA | DM_TESTF_SCAN_FDT);