[PATCH 00/17] mouse: Provide some support for using a mouse

From: Simon Glass <sjg@chromium.org> This series resurects some old code that was never submitted, related to using Nuklear with U-Boot. It includes: - a very simple mouse uclass - sandbox mouse driver - USB mouse driver, useful on x86 - EFI mouse driver, useful when running as an EFI app - script updates to use the above with build-qemu and build-efi It also includes a few small patches for sandbox, tests and membuf Not everything is fully working at present: - Mouse works on x86 QEMU (after 'usb start') but not ARM - Mouse works on real hardware with EFI, but not with build-efi script - Mouse times out with 'usb start', even though it does actually work More work will be needed to tidy up these remaining issues. Simon Glass (17): membuf: Add a function to set up a static membuf sandbox: Add a way to set the window title test: Add newlines at the end of the img functions input: Add mouse support sandbox: sdl: Add support for mouse input input: sandbox: Provide a mouse driver input: Add a command to show mouse input sandbox: Enable the mouse sandbox: Provide a test for the mouse uclass usb: Add a USB mouse driver mouse: Provide a way to read clicks efi: Add the simple-pointer protocol efi: Provide a mouse driver for EFI efi: arm: x86: Enable the mouse script: Support mouse with build-efi/qemu scripts x86: emulation: Enable USB support qemu: Enable the mouse MAINTAINERS | 7 + arch/arm/dts/efi-arm_app.dts | 5 + arch/sandbox/cpu/sdl.c | 46 +++- arch/sandbox/cpu/start.c | 9 + arch/sandbox/dts/sandbox.dtsi | 4 + arch/sandbox/dts/test.dts | 4 + arch/sandbox/include/asm/sdl.h | 9 + arch/sandbox/include/asm/state.h | 2 + arch/sandbox/include/asm/test.h | 17 ++ arch/x86/dts/efi-x86_app.dts | 4 + cmd/Kconfig | 9 + cmd/Makefile | 1 + cmd/mouse.c | 69 ++++++ configs/qemu-x86_64_defconfig | 3 + configs/qemu-x86_defconfig | 3 + configs/tools-only_defconfig | 2 +- drivers/input/Kconfig | 29 +++ drivers/input/Makefile | 7 + drivers/input/efi_mouse.c | 221 +++++++++++++++++++ drivers/input/mouse-uclass.c | 72 +++++++ drivers/input/sandbox_mouse.c | 84 ++++++++ drivers/input/usb_mouse.c | 353 +++++++++++++++++++++++++++++++ include/dm/uclass-id.h | 1 + include/efi.h | 1 + include/efi_api.h | 29 +++ include/membuf.h | 17 +- include/mouse.h | 105 +++++++++ include/usb.h | 1 + lib/efi/device_path.c | 1 + lib/membuf.c | 8 + scripts/build-efi | 3 + scripts/build-qemu | 6 +- test/dm/Makefile | 1 + test/dm/mouse.c | 217 +++++++++++++++++++ test/lib/membuf.c | 19 ++ test/py/img/android.py | 2 +- test/py/img/armbian.py | 2 +- test/py/img/cedit.py | 2 +- test/py/img/chromeos.py | 2 +- test/py/img/common.py | 2 +- test/py/img/efi.py | 2 +- test/py/img/fedora.py | 2 +- test/py/img/localboot.py | 2 +- test/py/img/ubuntu.py | 2 +- 44 files changed, 1374 insertions(+), 13 deletions(-) create mode 100644 cmd/mouse.c create mode 100644 drivers/input/efi_mouse.c create mode 100644 drivers/input/mouse-uclass.c create mode 100644 drivers/input/sandbox_mouse.c create mode 100644 drivers/input/usb_mouse.c create mode 100644 include/mouse.h create mode 100644 test/dm/mouse.c -- 2.43.0 base-commit: f3005834f6822612feb627cf52338e123c723e2b branch: ape

From: Simon Glass <sjg@chromium.org> Add a way to set up a membuf with some pre-loaded data, so it is possible to read it out using membuf_readline(), etc. Signed-off-by: Simon Glass <sjg@chromium.org> --- include/membuf.h | 17 ++++++++++++++++- lib/membuf.c | 8 ++++++++ test/lib/membuf.c | 19 +++++++++++++++++++ 3 files changed, 43 insertions(+), 1 deletion(-) diff --git a/include/membuf.h b/include/membuf.h index b495a72652b..3352faa0606 100644 --- a/include/membuf.h +++ b/include/membuf.h @@ -222,7 +222,9 @@ int membuf_readline(struct membuf *mb, char *str, int maxlen, int minch, int membuf_extend_by(struct membuf *mb, int by, int max); /** - * membuf_init() - set up a new membuff using an existing membuff + * membuf_init() - set up a new membuff using an existing buffer + * + * The buffer is initially empty * * @mb: membuff to set up * @buff: Address of buffer @@ -230,6 +232,19 @@ int membuf_extend_by(struct membuf *mb, int by, int max); */ void membuf_init(struct membuf *mb, char *buff, int size); +/** + * membuf_init_with_data() - set up a new membuff using existing data + * + * The buffer is set up to contain the provided data. with its size set to + * @size + 1 (less MEMBUF_FULL), so that there is enough space for the head/tail + * differece. + * + * @mb: membuff to set up + * @buff: Address of buffer + * @size: Number of bytes to put into the membuf + */ +void membuf_init_with_data(struct membuf *mb, char *buff, int size); + /** * membuf_uninit() - clear a membuff so it can no longer be used * diff --git a/lib/membuf.c b/lib/membuf.c index 016430ae988..47a1b06664a 100644 --- a/lib/membuf.c +++ b/lib/membuf.c @@ -405,6 +405,14 @@ void membuf_init(struct membuf *mb, char *buff, int size) membuf_purge(mb); } +void membuf_init_with_data(struct membuf *mb, char *buff, int size) +{ + char *data; + + membuf_init(mb, buff, size + !MEMBUF_FULL); + membuf_putraw(mb, size, true, &data); +} + int membuf_new(struct membuf *mb, int size) { mb->start = malloc(size); diff --git a/test/lib/membuf.c b/test/lib/membuf.c index f36332ff7b6..2e7de9cdc57 100644 --- a/test/lib/membuf.c +++ b/test/lib/membuf.c @@ -242,3 +242,22 @@ static int lib_test_membuf_readline(struct unit_test_state *uts) return 0; } LIB_TEST(lib_test_membuf_readline, 0); + +/* test membuf_readline() with generated data */ +static int lib_test_membuf_init(struct unit_test_state *uts) +{ + struct membuf mb; + char buf[10], out[10]; + int len; + + strcpy(buf, "hello"); + len = strlen(buf); + membuf_init_with_data(&mb, buf, len); + ut_asserteq_ptr(buf, mb.start); + ut_asserteq(len, membuf_avail(&mb)); + ut_asserteq(len, membuf_readline(&mb, out, sizeof(out), 0, false)); + ut_asserteq_str("hello", out); + + return 0; +} +LIB_TEST(lib_test_membuf_init, 0); -- 2.43.0

From: Simon Glass <sjg@chromium.org> Add a new option to set the window title for U-Boot sandbox. This is helpful when different sandbox instances are used for different purposes at the same time. Signed-off-by: Simon Glass <sjg@chromium.org> --- arch/sandbox/cpu/sdl.c | 3 ++- arch/sandbox/cpu/start.c | 9 +++++++++ arch/sandbox/include/asm/state.h | 2 ++ 3 files changed, 13 insertions(+), 1 deletion(-) diff --git a/arch/sandbox/cpu/sdl.c b/arch/sandbox/cpu/sdl.c index ed84646bdab..5a323a607f1 100644 --- a/arch/sandbox/cpu/sdl.c +++ b/arch/sandbox/cpu/sdl.c @@ -157,7 +157,8 @@ int sandbox_sdl_init_display(int width, int height, int log2_bpp, log2_bpp = 5; sdl.depth = 1 << log2_bpp; sdl.pitch = sdl.width * sdl.depth / 8; - sdl.screen = SDL_CreateWindow("U-Boot", SDL_WINDOWPOS_UNDEFINED, + sdl.screen = SDL_CreateWindow(state->window_title ? : "U-Boot", + SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, sdl.vis_width, sdl.vis_height, SDL_WINDOW_RESIZABLE); if (!sdl.screen) { diff --git a/arch/sandbox/cpu/start.c b/arch/sandbox/cpu/start.c index 556d1985ccc..43adc4cdb4f 100644 --- a/arch/sandbox/cpu/start.c +++ b/arch/sandbox/cpu/start.c @@ -187,6 +187,15 @@ static int sandbox_cmdline_cb_fdt(struct sandbox_state *state, const char *arg) } SANDBOX_CMDLINE_OPT_SHORT(fdt, 'd', 1, "Specify U-Boot's control FDT"); +static int sandbox_cmdline_cb_title(struct sandbox_state *state, + const char *arg) +{ + state->window_title = arg; + + return 0; +} +SANDBOX_CMDLINE_OPT_SHORT(title, 'W', 1, "Set the window title to display"); + static int sandbox_cmdline_cb_default_fdt(struct sandbox_state *state, const char *arg) { diff --git a/arch/sandbox/include/asm/state.h b/arch/sandbox/include/asm/state.h index 1c9f45d18eb..af92f4e6fcd 100644 --- a/arch/sandbox/include/asm/state.h +++ b/arch/sandbox/include/asm/state.h @@ -189,6 +189,8 @@ struct sandbox_state { struct list_head mapmem_head; /* struct sandbox_mapmem_entry */ bool hwspinlock; /* Hardware Spinlock status */ bool allow_memio; /* Allow readl() etc. to work */ + /* Title to use for LCD window, NULL for default */ + const char *window_title; void *other_fdt_buf; /* 'other' FDT blob used by tests */ int other_size; /* size of other FDT blob */ -- 2.43.0

From: Simon Glass <sjg@chromium.org> The functions which create images lack a newline at the end of the file. Add one, for consistency. Signed-off-by: Simon Glass <sjg@chromium.org> --- test/py/img/android.py | 2 +- test/py/img/armbian.py | 2 +- test/py/img/cedit.py | 2 +- test/py/img/chromeos.py | 2 +- test/py/img/common.py | 2 +- test/py/img/efi.py | 2 +- test/py/img/fedora.py | 2 +- test/py/img/localboot.py | 2 +- test/py/img/ubuntu.py | 2 +- 9 files changed, 9 insertions(+), 9 deletions(-) diff --git a/test/py/img/android.py b/test/py/img/android.py index 44d15fe35a7..a703a68f790 100644 --- a/test/py/img/android.py +++ b/test/py/img/android.py @@ -143,4 +143,4 @@ def setup_android_image(config, log): print(f'wrote to {fname}') - return fname \ No newline at end of file + return fname diff --git a/test/py/img/armbian.py b/test/py/img/armbian.py index 4db40fd5070..e1ae9b0aae9 100644 --- a/test/py/img/armbian.py +++ b/test/py/img/armbian.py @@ -129,4 +129,4 @@ booti ${kernel_addr_r} ${ramdisk_addr_r} ${fdt_addr_r} img = DiskHelper(config, mmc_dev, 'mmc', True) img.add_fs(fsh, DiskHelper.EXT4) img.create() - fsh.cleanup() \ No newline at end of file + fsh.cleanup() diff --git a/test/py/img/cedit.py b/test/py/img/cedit.py index dd6c5de44bb..564cb985dc1 100644 --- a/test/py/img/cedit.py +++ b/test/py/img/cedit.py @@ -22,4 +22,4 @@ def setup_cedit_file(config, log): expo_tool = os.path.join(config.source_dir, 'tools/expo.py') outfname = 'cedit.dtb' utils.run_and_log_no_ubman( - log, f'{expo_tool} -e {inhname} -l {infname} -o {outfname}') \ No newline at end of file + log, f'{expo_tool} -e {inhname} -l {infname} -o {outfname}') diff --git a/test/py/img/chromeos.py b/test/py/img/chromeos.py index 6217b5310f1..24884402c92 100644 --- a/test/py/img/chromeos.py +++ b/test/py/img/chromeos.py @@ -151,4 +151,4 @@ def setup_cros_image(config, log): with open(fname, 'wb') as outf: outf.write(disk_data) - return fname \ No newline at end of file + return fname diff --git a/test/py/img/common.py b/test/py/img/common.py index 80f9c124fc8..c9be6a22362 100644 --- a/test/py/img/common.py +++ b/test/py/img/common.py @@ -85,4 +85,4 @@ def setup_extlinux_image(config, log, devnum, basename, vmlinux, initrd, dtbdir, img.add_fs(ext4, DiskHelper.EXT4) img.create() - fsh.cleanup() \ No newline at end of file + fsh.cleanup() diff --git a/test/py/img/efi.py b/test/py/img/efi.py index fbb39c24063..8239b4c247f 100644 --- a/test/py/img/efi.py +++ b/test/py/img/efi.py @@ -34,4 +34,4 @@ def setup_efi_image(config): img = DiskHelper(config, devnum, 'flash', True) img.add_fs(fsh, DiskHelper.VFAT) img.create() - fsh.cleanup() \ No newline at end of file + fsh.cleanup() diff --git a/test/py/img/fedora.py b/test/py/img/fedora.py index ffa546d1cfe..8d3407d065e 100644 --- a/test/py/img/fedora.py +++ b/test/py/img/fedora.py @@ -32,4 +32,4 @@ label Fedora-Workstation-armhfp-31-1.9 (5.3.7-301.fc31.armv7hl) fdtdir /%s/ initrd /%s''' % (vmlinux, dtbdir, initrd) setup_extlinux_image(config, log, devnum, basename, vmlinux, - initrd, dtbdir, script) \ No newline at end of file + initrd, dtbdir, script) diff --git a/test/py/img/localboot.py b/test/py/img/localboot.py index 62a65f33cf0..e83a0cbaa82 100644 --- a/test/py/img/localboot.py +++ b/test/py/img/localboot.py @@ -24,4 +24,4 @@ LABEL local vmlinux = 'vmlinuz' initrd = 'initrd.img' setup_extlinux_image(config, log, mmc_dev, 'mmc', vmlinux, initrd, None, - script) \ No newline at end of file + script) diff --git a/test/py/img/ubuntu.py b/test/py/img/ubuntu.py index 4fe54cb679b..06e8251c05b 100644 --- a/test/py/img/ubuntu.py +++ b/test/py/img/ubuntu.py @@ -44,4 +44,4 @@ label l0r initrd /boot/%s ''' % (vmlinux, initrd, vmlinux, initrd) setup_extlinux_image(config, log, devnum, basename, vmlinux, initrd, dtbdir, - script) \ No newline at end of file + script) -- 2.43.0

From: Simon Glass <sjg@chromium.org> When running a simple GUI it is useful to support a mouse. This is similar to what is provided in UEFI's boot menu. Add a simple uclass and a way to read the mouse position. For sandbox add a driver that reads the position from SDL. Disable input for the tools-only build, since it is of no use there and causes build failures. Signed-off-by: Simon Glass <sjg@chromium.org> --- MAINTAINERS | 7 ++++ configs/tools-only_defconfig | 2 +- drivers/input/Kconfig | 9 ++++ drivers/input/Makefile | 2 + drivers/input/mouse-uclass.c | 29 +++++++++++++ include/dm/uclass-id.h | 1 + include/mouse.h | 80 ++++++++++++++++++++++++++++++++++++ 7 files changed, 129 insertions(+), 1 deletion(-) create mode 100644 drivers/input/mouse-uclass.c create mode 100644 include/mouse.h diff --git a/MAINTAINERS b/MAINTAINERS index 5d05281633d..e858331455c 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -1251,6 +1251,13 @@ S: Maintained T: git https://source.denx.de/u-boot/custodians/u-boot-i2c.git F: drivers/i2c/ +INPUT +M: Simon Glass <sjg@chromium.org> +S: Maintained +T: git https://concept.u-boot.org/u-boot/u-boot.git +F: drivers/input +F: include/mouse.h + KWBIMAGE / KWBOOT TOOLS M: Pali Rohár <pali@kernel.org> M: Marek Behún <kabel@kernel.org> diff --git a/configs/tools-only_defconfig b/configs/tools-only_defconfig index 9e4866b494c..f3c35e1a8bb 100644 --- a/configs/tools-only_defconfig +++ b/configs/tools-only_defconfig @@ -5,7 +5,6 @@ CONFIG_DEFAULT_DEVICE_TREE="sandbox" CONFIG_SYS_LOAD_ADDR=0x0 CONFIG_PCI=y # CONFIG_SANDBOX_SDL is not set -# CONFIG_ULIB is not set # CONFIG_EFI_LOADER is not set CONFIG_ANDROID_BOOT_IMAGE=y CONFIG_TIMESTAMP=y @@ -30,6 +29,7 @@ CONFIG_NO_NET=y CONFIG_AXI=y CONFIG_AXI_SANDBOX=y CONFIG_SANDBOX_GPIO=y +# CONFIG_INPUT is not set CONFIG_PCI_SANDBOX=y CONFIG_DM_RTC=y CONFIG_SOUND=y diff --git a/drivers/input/Kconfig b/drivers/input/Kconfig index c2b365af11d..6bfee40ccac 100644 --- a/drivers/input/Kconfig +++ b/drivers/input/Kconfig @@ -100,3 +100,12 @@ config TWL4030_INPUT bool "Enable TWL4030 Input controller" help Enable TWL4030 Input controller + +config MOUSE + bool "Support for mice and other pointing devices" + default y if SANDBOX + help + This allows U-Boot to access mouse input, typically needed for + graphics boot menus and the like. The driver can provide mouse + events based on user interaction and these can be used to control + U-Boot's operation. diff --git a/drivers/input/Makefile b/drivers/input/Makefile index 8d4107b8848..7ed7eba3e8c 100644 --- a/drivers/input/Makefile +++ b/drivers/input/Makefile @@ -15,3 +15,5 @@ obj-$(CONFIG_I8042_KEYB) += i8042.o obj-$(CONFIG_TEGRA_KEYBOARD) += input.o tegra-kbc.o obj-$(CONFIG_TWL4030_INPUT) += twl4030.o endif + +obj-$(CONFIG_MOUSE) += mouse-uclass.o diff --git a/drivers/input/mouse-uclass.c b/drivers/input/mouse-uclass.c new file mode 100644 index 00000000000..f42ef346c5c --- /dev/null +++ b/drivers/input/mouse-uclass.c @@ -0,0 +1,29 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Copyright 2019 Google LLC + * Written by Simon Glass <sjg@chromium.org> + */ + +#include <dm.h> +#include <errno.h> +#include <mouse.h> + +int mouse_get_event(struct udevice *dev, struct mouse_event *evt) +{ + struct mouse_ops *ops = mouse_get_ops(dev); + int ret; + + if (!ops->get_event) + return -ENOSYS; + + ret = ops->get_event(dev, evt); + if (ret) + return ret; + + return 0; +} + +UCLASS_DRIVER(mouse) = { + .id = UCLASS_MOUSE, + .name = "mouse", +}; diff --git a/include/dm/uclass-id.h b/include/dm/uclass-id.h index c558c95f465..a424ef00fc9 100644 --- a/include/dm/uclass-id.h +++ b/include/dm/uclass-id.h @@ -97,6 +97,7 @@ enum uclass_id { UCLASS_MISC, /* Miscellaneous device */ UCLASS_MMC, /* SD / MMC card or chip */ UCLASS_MOD_EXP, /* RSA Mod Exp device */ + UCLASS_MOUSE, /* Mouse, trackpad or other pointing device */ UCLASS_MTD, /* Memory Technology Device (MTD) device */ UCLASS_MUX, /* Multiplexer device */ UCLASS_NOP, /* No-op devices */ diff --git a/include/mouse.h b/include/mouse.h new file mode 100644 index 00000000000..c96c63918ea --- /dev/null +++ b/include/mouse.h @@ -0,0 +1,80 @@ +/* SPDX-License-Identifier: GPL-2.0+ */ +/* + * Mouse/trackpad/touchscreen input uclass + * + * Copyright 2020 Google LLC + */ + +#ifndef _MOUSE_H +#define _MOUSE_H + +struct udevice; + +enum mouse_ev_t { + MOUSE_EV_NULL, + MOUSE_EV_MOTION, + MOUSE_EV_BUTTON, +}; + +enum mouse_state_t { + BUTTON_LEFT = 1 << 0, + BUTTON_MIDDLE = 1 << 1, + BUTTON_RIGHT = 1 << 2, + BUTTON_SCROLL_PLUS = 1 << 3, + BUTTON_SCROLL_MINUS = 1 << 4, +}; + +enum mouse_press_state_t { + BUTTON_RELEASED = 0, + BUTTON_PRESSED, +}; + +/** + * struct mouse_event - information about a mouse event + * + * @type: Mouse event ype + */ +struct mouse_event { + enum mouse_ev_t type; + union { + /** + * @state: Mouse state (enum mouse_state_t bitmask) + * @x: X position of mouse + * @y: Y position of mouse + * @xrel: Relative motion in X direction + * @yrel: Relative motion in Y direction + */ + struct mouse_motion { + unsigned char state; + unsigned short x; + unsigned short y; + short xrel; + short yrel; + } motion; + + /** + * @button: Button number that was pressed/released (BUTTON_...) + * @state: BUTTON_PRESSED / BUTTON_RELEASED + * @clicks: number of clicks (normally 1; 2 = double-click) + * @x: X position of mouse + * @y: Y position of mouse + */ + struct mouse_button { + unsigned char button; + unsigned char press_state; + unsigned char clicks; + unsigned short x; + unsigned short y; + } button; + }; +}; + +struct mouse_ops { + int (*get_event)(struct udevice *dev, struct mouse_event *event); +}; + +#define mouse_get_ops(dev) ((struct mouse_ops *)(dev)->driver->ops) + +int mouse_get_event(struct udevice *dev, struct mouse_event *event); + +#endif -- 2.43.0

Am 15. September 2025 12:46:45 MESZ schrieb Simon Glass <sjg@u-boot.org>:
From: Simon Glass <sjg@chromium.org>
When running a simple GUI it is useful to support a mouse. This is similar to what is provided in UEFI's boot menu. Add a simple uclass and a way to read the mouse position.
For sandbox add a driver that reads the position from SDL. Disable input for the tools-only build, since it is of no use there and causes build failures.
Signed-off-by: Simon Glass <sjg@chromium.org> ---
MAINTAINERS | 7 ++++ configs/tools-only_defconfig | 2 +- drivers/input/Kconfig | 9 ++++ drivers/input/Makefile | 2 + drivers/input/mouse-uclass.c | 29 +++++++++++++ include/dm/uclass-id.h | 1 + include/mouse.h | 80 ++++++++++++++++++++++++++++++++++++ 7 files changed, 129 insertions(+), 1 deletion(-) create mode 100644 drivers/input/mouse-uclass.c create mode 100644 include/mouse.h
diff --git a/MAINTAINERS b/MAINTAINERS index 5d05281633d..e858331455c 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -1251,6 +1251,13 @@ S: Maintained T: git https://source.denx.de/u-boot/custodians/u-boot-i2c.git F: drivers/i2c/
+INPUT +M: Simon Glass <sjg@chromium.org> +S: Maintained +T: git https://concept.u-boot.org/u-boot/u-boot.git +F: drivers/input +F: include/mouse.h + KWBIMAGE / KWBOOT TOOLS M: Pali Rohár <pali@kernel.org> M: Marek Behún <kabel@kernel.org> diff --git a/configs/tools-only_defconfig b/configs/tools-only_defconfig index 9e4866b494c..f3c35e1a8bb 100644 --- a/configs/tools-only_defconfig +++ b/configs/tools-only_defconfig @@ -5,7 +5,6 @@ CONFIG_DEFAULT_DEVICE_TREE="sandbox" CONFIG_SYS_LOAD_ADDR=0x0 CONFIG_PCI=y # CONFIG_SANDBOX_SDL is not set -# CONFIG_ULIB is not set # CONFIG_EFI_LOADER is not set CONFIG_ANDROID_BOOT_IMAGE=y CONFIG_TIMESTAMP=y @@ -30,6 +29,7 @@ CONFIG_NO_NET=y CONFIG_AXI=y CONFIG_AXI_SANDBOX=y CONFIG_SANDBOX_GPIO=y +# CONFIG_INPUT is not set CONFIG_PCI_SANDBOX=y CONFIG_DM_RTC=y CONFIG_SOUND=y diff --git a/drivers/input/Kconfig b/drivers/input/Kconfig index c2b365af11d..6bfee40ccac 100644 --- a/drivers/input/Kconfig +++ b/drivers/input/Kconfig @@ -100,3 +100,12 @@ config TWL4030_INPUT bool "Enable TWL4030 Input controller" help Enable TWL4030 Input controller + +config MOUSE + bool "Support for mice and other pointing devices" + default y if SANDBOX + help + This allows U-Boot to access mouse input, typically needed for + graphics boot menus and the like. The driver can provide mouse + events based on user interaction and these can be used to control + U-Boot's operation. diff --git a/drivers/input/Makefile b/drivers/input/Makefile index 8d4107b8848..7ed7eba3e8c 100644 --- a/drivers/input/Makefile +++ b/drivers/input/Makefile @@ -15,3 +15,5 @@ obj-$(CONFIG_I8042_KEYB) += i8042.o obj-$(CONFIG_TEGRA_KEYBOARD) += input.o tegra-kbc.o obj-$(CONFIG_TWL4030_INPUT) += twl4030.o endif + +obj-$(CONFIG_MOUSE) += mouse-uclass.o diff --git a/drivers/input/mouse-uclass.c b/drivers/input/mouse-uclass.c new file mode 100644 index 00000000000..f42ef346c5c --- /dev/null +++ b/drivers/input/mouse-uclass.c @@ -0,0 +1,29 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Copyright 2019 Google LLC + * Written by Simon Glass <sjg@chromium.org> + */ + +#include <dm.h> +#include <errno.h> +#include <mouse.h> + +int mouse_get_event(struct udevice *dev, struct mouse_event *evt) +{ + struct mouse_ops *ops = mouse_get_ops(dev); + int ret; + + if (!ops->get_event) + return -ENOSYS; + + ret = ops->get_event(dev, evt); + if (ret) + return ret; + + return 0; +} + +UCLASS_DRIVER(mouse) = { + .id = UCLASS_MOUSE, + .name = "mouse",
Libvirt defaults to virtio-tablet. Usb-mouse did not work for me in a spice terminal. Will this class encompass tablets, too? Best regards Heinrich
+}; diff --git a/include/dm/uclass-id.h b/include/dm/uclass-id.h index c558c95f465..a424ef00fc9 100644 --- a/include/dm/uclass-id.h +++ b/include/dm/uclass-id.h @@ -97,6 +97,7 @@ enum uclass_id { UCLASS_MISC, /* Miscellaneous device */ UCLASS_MMC, /* SD / MMC card or chip */ UCLASS_MOD_EXP, /* RSA Mod Exp device */ + UCLASS_MOUSE, /* Mouse, trackpad or other pointing device */ UCLASS_MTD, /* Memory Technology Device (MTD) device */ UCLASS_MUX, /* Multiplexer device */ UCLASS_NOP, /* No-op devices */ diff --git a/include/mouse.h b/include/mouse.h new file mode 100644 index 00000000000..c96c63918ea --- /dev/null +++ b/include/mouse.h @@ -0,0 +1,80 @@ +/* SPDX-License-Identifier: GPL-2.0+ */ +/* + * Mouse/trackpad/touchscreen input uclass + * + * Copyright 2020 Google LLC + */ + +#ifndef _MOUSE_H +#define _MOUSE_H + +struct udevice; + +enum mouse_ev_t { + MOUSE_EV_NULL, + MOUSE_EV_MOTION, + MOUSE_EV_BUTTON, +}; + +enum mouse_state_t { + BUTTON_LEFT = 1 << 0, + BUTTON_MIDDLE = 1 << 1, + BUTTON_RIGHT = 1 << 2, + BUTTON_SCROLL_PLUS = 1 << 3, + BUTTON_SCROLL_MINUS = 1 << 4, +}; + +enum mouse_press_state_t { + BUTTON_RELEASED = 0, + BUTTON_PRESSED, +}; + +/** + * struct mouse_event - information about a mouse event + * + * @type: Mouse event ype + */ +struct mouse_event { + enum mouse_ev_t type; + union { + /** + * @state: Mouse state (enum mouse_state_t bitmask) + * @x: X position of mouse + * @y: Y position of mouse + * @xrel: Relative motion in X direction + * @yrel: Relative motion in Y direction + */ + struct mouse_motion { + unsigned char state; + unsigned short x; + unsigned short y; + short xrel; + short yrel; + } motion; + + /** + * @button: Button number that was pressed/released (BUTTON_...) + * @state: BUTTON_PRESSED / BUTTON_RELEASED + * @clicks: number of clicks (normally 1; 2 = double-click) + * @x: X position of mouse + * @y: Y position of mouse + */ + struct mouse_button { + unsigned char button; + unsigned char press_state; + unsigned char clicks; + unsigned short x; + unsigned short y; + } button; + }; +}; + +struct mouse_ops { + int (*get_event)(struct udevice *dev, struct mouse_event *event); +}; + +#define mouse_get_ops(dev) ((struct mouse_ops *)(dev)->driver->ops) + +int mouse_get_event(struct udevice *dev, struct mouse_event *event); + +#endif

Hi Heinrich, On Mon, 15 Sept 2025 at 05:36, Heinrich Schuchardt <xypron.glpk@gmx.de> wrote:
Am 15. September 2025 12:46:45 MESZ schrieb Simon Glass <sjg@u-boot.org>:
From: Simon Glass <sjg@chromium.org>
When running a simple GUI it is useful to support a mouse. This is similar to what is provided in UEFI's boot menu. Add a simple uclass and a way to read the mouse position.
For sandbox add a driver that reads the position from SDL. Disable input for the tools-only build, since it is of no use there and causes build failures.
Signed-off-by: Simon Glass <sjg@chromium.org> ---
MAINTAINERS | 7 ++++ configs/tools-only_defconfig | 2 +- drivers/input/Kconfig | 9 ++++ drivers/input/Makefile | 2 + drivers/input/mouse-uclass.c | 29 +++++++++++++ include/dm/uclass-id.h | 1 + include/mouse.h | 80 ++++++++++++++++++++++++++++++++++++ 7 files changed, 129 insertions(+), 1 deletion(-) create mode 100644 drivers/input/mouse-uclass.c create mode 100644 include/mouse.h
diff --git a/MAINTAINERS b/MAINTAINERS index 5d05281633d..e858331455c 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -1251,6 +1251,13 @@ S: Maintained T: git https://source.denx.de/u-boot/custodians/u-boot-i2c.git F: drivers/i2c/
+INPUT +M: Simon Glass <sjg@chromium.org> +S: Maintained +T: git https://concept.u-boot.org/u-boot/u-boot.git +F: drivers/input +F: include/mouse.h + KWBIMAGE / KWBOOT TOOLS M: Pali Rohár <pali@kernel.org> M: Marek Behún <kabel@kernel.org> diff --git a/configs/tools-only_defconfig b/configs/tools-only_defconfig index 9e4866b494c..f3c35e1a8bb 100644 --- a/configs/tools-only_defconfig +++ b/configs/tools-only_defconfig @@ -5,7 +5,6 @@ CONFIG_DEFAULT_DEVICE_TREE="sandbox" CONFIG_SYS_LOAD_ADDR=0x0 CONFIG_PCI=y # CONFIG_SANDBOX_SDL is not set -# CONFIG_ULIB is not set # CONFIG_EFI_LOADER is not set CONFIG_ANDROID_BOOT_IMAGE=y CONFIG_TIMESTAMP=y @@ -30,6 +29,7 @@ CONFIG_NO_NET=y CONFIG_AXI=y CONFIG_AXI_SANDBOX=y CONFIG_SANDBOX_GPIO=y +# CONFIG_INPUT is not set CONFIG_PCI_SANDBOX=y CONFIG_DM_RTC=y CONFIG_SOUND=y diff --git a/drivers/input/Kconfig b/drivers/input/Kconfig index c2b365af11d..6bfee40ccac 100644 --- a/drivers/input/Kconfig +++ b/drivers/input/Kconfig @@ -100,3 +100,12 @@ config TWL4030_INPUT bool "Enable TWL4030 Input controller" help Enable TWL4030 Input controller + +config MOUSE + bool "Support for mice and other pointing devices" + default y if SANDBOX + help + This allows U-Boot to access mouse input, typically needed for + graphics boot menus and the like. The driver can provide mouse + events based on user interaction and these can be used to control + U-Boot's operation. diff --git a/drivers/input/Makefile b/drivers/input/Makefile index 8d4107b8848..7ed7eba3e8c 100644 --- a/drivers/input/Makefile +++ b/drivers/input/Makefile @@ -15,3 +15,5 @@ obj-$(CONFIG_I8042_KEYB) += i8042.o obj-$(CONFIG_TEGRA_KEYBOARD) += input.o tegra-kbc.o obj-$(CONFIG_TWL4030_INPUT) += twl4030.o endif + +obj-$(CONFIG_MOUSE) += mouse-uclass.o diff --git a/drivers/input/mouse-uclass.c b/drivers/input/mouse-uclass.c new file mode 100644 index 00000000000..f42ef346c5c --- /dev/null +++ b/drivers/input/mouse-uclass.c @@ -0,0 +1,29 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Copyright 2019 Google LLC + * Written by Simon Glass <sjg@chromium.org> + */ + +#include <dm.h> +#include <errno.h> +#include <mouse.h> + +int mouse_get_event(struct udevice *dev, struct mouse_event *evt) +{ + struct mouse_ops *ops = mouse_get_ops(dev); + int ret; + + if (!ops->get_event) + return -ENOSYS; + + ret = ops->get_event(dev, evt); + if (ret) + return ret; + + return 0; +} + +UCLASS_DRIVER(mouse) = { + .id = UCLASS_MOUSE, + .name = "mouse",
Libvirt defaults to virtio-tablet. Usb-mouse did not work for me in a spice terminal. Will this class encompass tablets, too?
So long as the mouse driver can handle it, yes. For spice, would that be virtio-tablet? Regards, Simon
Best regards
Heinrich
+}; diff --git a/include/dm/uclass-id.h b/include/dm/uclass-id.h index c558c95f465..a424ef00fc9 100644 --- a/include/dm/uclass-id.h +++ b/include/dm/uclass-id.h @@ -97,6 +97,7 @@ enum uclass_id { UCLASS_MISC, /* Miscellaneous device */ UCLASS_MMC, /* SD / MMC card or chip */ UCLASS_MOD_EXP, /* RSA Mod Exp device */ + UCLASS_MOUSE, /* Mouse, trackpad or other pointing device */ UCLASS_MTD, /* Memory Technology Device (MTD) device */ UCLASS_MUX, /* Multiplexer device */ UCLASS_NOP, /* No-op devices */ diff --git a/include/mouse.h b/include/mouse.h new file mode 100644 index 00000000000..c96c63918ea --- /dev/null +++ b/include/mouse.h @@ -0,0 +1,80 @@ +/* SPDX-License-Identifier: GPL-2.0+ */ +/* + * Mouse/trackpad/touchscreen input uclass + * + * Copyright 2020 Google LLC + */ + +#ifndef _MOUSE_H +#define _MOUSE_H + +struct udevice; + +enum mouse_ev_t { + MOUSE_EV_NULL, + MOUSE_EV_MOTION, + MOUSE_EV_BUTTON, +}; + +enum mouse_state_t { + BUTTON_LEFT = 1 << 0, + BUTTON_MIDDLE = 1 << 1, + BUTTON_RIGHT = 1 << 2, + BUTTON_SCROLL_PLUS = 1 << 3, + BUTTON_SCROLL_MINUS = 1 << 4, +}; + +enum mouse_press_state_t { + BUTTON_RELEASED = 0, + BUTTON_PRESSED, +}; + +/** + * struct mouse_event - information about a mouse event + * + * @type: Mouse event ype + */ +struct mouse_event { + enum mouse_ev_t type; + union { + /** + * @state: Mouse state (enum mouse_state_t bitmask) + * @x: X position of mouse + * @y: Y position of mouse + * @xrel: Relative motion in X direction + * @yrel: Relative motion in Y direction + */ + struct mouse_motion { + unsigned char state; + unsigned short x; + unsigned short y; + short xrel; + short yrel; + } motion; + + /** + * @button: Button number that was pressed/released (BUTTON_...) + * @state: BUTTON_PRESSED / BUTTON_RELEASED + * @clicks: number of clicks (normally 1; 2 = double-click) + * @x: X position of mouse + * @y: Y position of mouse + */ + struct mouse_button { + unsigned char button; + unsigned char press_state; + unsigned char clicks; + unsigned short x; + unsigned short y; + } button; + }; +}; + +struct mouse_ops { + int (*get_event)(struct udevice *dev, struct mouse_event *event); +}; + +#define mouse_get_ops(dev) ((struct mouse_ops *)(dev)->driver->ops) + +int mouse_get_event(struct udevice *dev, struct mouse_event *event); + +#endif
-- -- Simon Glass Executive Director Email: sjg@u-boot.org Phone: +1 970 834 3498 u-boot.org

From: Simon Glass <sjg@chromium.org> Allow mouse input to be reported from sandbox using SDL. Signed-off-by: Simon Glass <sjg@chromium.org> --- arch/sandbox/cpu/sdl.c | 43 ++++++++++++++++++++++++++++++++++ arch/sandbox/include/asm/sdl.h | 9 +++++++ 2 files changed, 52 insertions(+) diff --git a/arch/sandbox/cpu/sdl.c b/arch/sandbox/cpu/sdl.c index 5a323a607f1..fa431010b11 100644 --- a/arch/sandbox/cpu/sdl.c +++ b/arch/sandbox/cpu/sdl.c @@ -4,6 +4,7 @@ */ #include <errno.h> +#include <mouse.h> #include <unistd.h> #include <stdbool.h> #include <sysreset.h> @@ -67,6 +68,7 @@ static struct sdl_info { SDL_Renderer *renderer; SDL_Window *screen; int src_depth; + struct mouse_event mouse; } sdl; static void sandbox_sdl_poll_events(void) @@ -84,10 +86,50 @@ static void sandbox_sdl_poll_events(void) puts("LCD window closed - quitting\n"); sysreset_walk(SYSRESET_POWER_OFF); break; + case SDL_MOUSEMOTION: { + struct mouse_event *m = &sdl.mouse; + + m->type = MOUSE_EV_MOTION; + m->motion.state = 0; + m->motion.x = event.motion.x; + m->motion.y = event.motion.y; + m->motion.xrel = event.motion.xrel; + m->motion.yrel = event.motion.yrel; + break; + } + case SDL_MOUSEBUTTONDOWN: + case SDL_MOUSEBUTTONUP: { + struct mouse_event *m = &sdl.mouse; + + m->type = MOUSE_EV_BUTTON; + if (event.button.button == SDL_BUTTON_LEFT) + m->button.button = BUTTON_LEFT; + else if (event.button.button == SDL_BUTTON_MIDDLE) + m->button.button = BUTTON_MIDDLE; + else if (event.button.button == SDL_BUTTON_RIGHT) + m->button.button = BUTTON_RIGHT; + m->button.press_state = event.type == + SDL_MOUSEBUTTONDOWN ? + BUTTON_PRESSED : BUTTON_RELEASED; + m->button.x = event.button.x; + m->button.y = event.motion.y; + break; + } } } } +int sandbox_sdl_get_mouse_event(struct mouse_event *evt) +{ + if (sdl.mouse.type == MOUSE_EV_NULL) + return -EAGAIN; + + *evt = sdl.mouse; + sdl.mouse.type = MOUSE_EV_NULL; + + return 0; +} + static int sandbox_sdl_ensure_init(void) { if (!sdl.inited) { @@ -522,6 +564,7 @@ int sandbox_sdl_sound_init(int rate, int channels) sdl.sample_rate = wanted.freq; sdl.cur_buf = 0; sdl.running = false; + sdl.mouse.type = MOUSE_EV_NULL; return 0; diff --git a/arch/sandbox/include/asm/sdl.h b/arch/sandbox/include/asm/sdl.h index ee4991f7c24..86368c8a0a6 100644 --- a/arch/sandbox/include/asm/sdl.h +++ b/arch/sandbox/include/asm/sdl.h @@ -9,6 +9,8 @@ #include <errno.h> #include <video.h> +struct mouse_event; + #ifdef CONFIG_SANDBOX_SDL /** @@ -104,6 +106,8 @@ int sandbox_sdl_sound_init(int rate, int channels); */ int sandbox_sdl_set_bpp(struct udevice *dev, enum video_log2_bpp l2bpp); +int sandbox_sdl_get_mouse_event(struct mouse_event *evt); + #else static inline int sandbox_sdl_init_display(int width, int height, int log2_bpp, bool double_size) @@ -157,6 +161,11 @@ static inline int sandbox_sdl_set_bpp(struct udevice *dev, return -ENOSYS; } +static inline int sandbox_sdl_get_mouse_event(struct mouse_event *evt) +{ + return -ENODEV; +} + #endif #endif -- 2.43.0

From: Simon Glass <sjg@chromium.org> Add a sandbox driver for the mouse, so it can be used as an input device. Signed-off-by: Simon Glass <sjg@chromium.org> --- drivers/input/Kconfig | 1 + drivers/input/Makefile | 3 +++ drivers/input/sandbox_mouse.c | 35 +++++++++++++++++++++++++++++++++++ 3 files changed, 39 insertions(+) create mode 100644 drivers/input/sandbox_mouse.c diff --git a/drivers/input/Kconfig b/drivers/input/Kconfig index 6bfee40ccac..101257f9767 100644 --- a/drivers/input/Kconfig +++ b/drivers/input/Kconfig @@ -103,6 +103,7 @@ config TWL4030_INPUT config MOUSE bool "Support for mice and other pointing devices" + depends on INPUT default y if SANDBOX help This allows U-Boot to access mouse input, typically needed for diff --git a/drivers/input/Makefile b/drivers/input/Makefile index 7ed7eba3e8c..8c5a395a540 100644 --- a/drivers/input/Makefile +++ b/drivers/input/Makefile @@ -17,3 +17,6 @@ obj-$(CONFIG_TWL4030_INPUT) += twl4030.o endif obj-$(CONFIG_MOUSE) += mouse-uclass.o +ifdef CONFIG_MOUSE +obj-$(CONFIG_SANDBOX) += sandbox_mouse.o +endif diff --git a/drivers/input/sandbox_mouse.c b/drivers/input/sandbox_mouse.c new file mode 100644 index 00000000000..4aedf0fdf2d --- /dev/null +++ b/drivers/input/sandbox_mouse.c @@ -0,0 +1,35 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Copyright 2020 Google LLC + * Written by Simon Glass <sjg@chromium.org> + */ + +#include <dm.h> +#include <mouse.h> +#include <asm/sdl.h> + +static int mouse_sandbox_get_event(struct udevice *dev, + struct mouse_event *event) +{ + int ret; + + ret = sandbox_sdl_get_mouse_event(event); + + return ret; +} + +const struct mouse_ops mouse_sandbox_ops = { + .get_event = mouse_sandbox_get_event, +}; + +static const struct udevice_id mouse_sandbox_ids[] = { + { .compatible = "sandbox,mouse" }, + { } +}; + +U_BOOT_DRIVER(mouse_sandbox) = { + .name = "mouse_sandbox", + .id = UCLASS_MOUSE, + .of_match = mouse_sandbox_ids, + .ops = &mouse_sandbox_ops, +}; -- 2.43.0

From: Simon Glass <sjg@chromium.org> This reads mouse input and shows it on the terminal. It is useful for testing mice. Signed-off-by: Simon Glass <sjg@chromium.org> --- cmd/Kconfig | 9 +++++++ cmd/Makefile | 1 + cmd/mouse.c | 69 ++++++++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 79 insertions(+) create mode 100644 cmd/mouse.c diff --git a/cmd/Kconfig b/cmd/Kconfig index 8037827930b..af79770b4c6 100644 --- a/cmd/Kconfig +++ b/cmd/Kconfig @@ -2971,6 +2971,15 @@ config CMD_LOG maximum log level for emitting of records). It also provides access to a command used for testing the log system. +config CMD_MOUSE + bool "mouse - Show mouse input" + default y if MOUSE + help + This shows the data produced by a mouse. If a mouse device is + available records are printed when the mouse is moved. This can be + useful for checking that a mouse is working correctly within + U-Boot. + config CMD_TRACE bool "trace - Support tracing of function calls and timing" depends on TRACE diff --git a/cmd/Makefile b/cmd/Makefile index 75ef9fab922..1d65703b625 100644 --- a/cmd/Makefile +++ b/cmd/Makefile @@ -129,6 +129,7 @@ obj-$(CONFIG_CMD_CLONE) += clone.o ifneq ($(CONFIG_CMD_NAND)$(CONFIG_CMD_SF),) obj-y += legacy-mtd-utils.o endif +obj-$(CONFIG_CMD_MOUSE) += mouse.o obj-$(CONFIG_CMD_MUX) += mux.o obj-$(CONFIG_CMD_NAND) += nand.o ifdef CONFIG_NET diff --git a/cmd/mouse.c b/cmd/mouse.c new file mode 100644 index 00000000000..60210b9f868 --- /dev/null +++ b/cmd/mouse.c @@ -0,0 +1,69 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Mouse testing + * + * Copyright 2020 Google LLC + * Written by Simon Glass <sjg@chromium.org> + */ + +#include <command.h> +#include <console.h> +#include <dm.h> +#include <mouse.h> +#include <u-boot/schedule.h> + +static int do_mouse_dump(struct cmd_tbl *cmdtp, int flag, int argc, + char *const argv[]) +{ + struct udevice *dev; + bool running; + int count; + int ret; + + ret = uclass_first_device_err(UCLASS_MOUSE, &dev); + if (ret) { + printf("Mouse not found (err=%d)\n", ret); + return CMD_RET_FAILURE; + } + for (running = true, count = 0; running;) { + struct mouse_event evt; + + ret = mouse_get_event(dev, &evt); + if (!ret) { + switch (evt.type) { + case MOUSE_EV_BUTTON: { + struct mouse_button *but = &evt.button; + + printf("button: button==%d, press=%d, clicks=%d, X=%d, Y=%d\n", + but->button, but->press_state, + but->clicks, but->x, but->y); + break; + } + case MOUSE_EV_MOTION: { + struct mouse_motion *motion = &evt.motion; + printf("motion: Xrel=%d, Yrel=%d, X=%d, Y=%d, but=%d\n", + motion->xrel, motion->yrel, motion->x, + motion->y, motion->state); + break; + } + case MOUSE_EV_NULL: + break; + } + count++; + } else if (ret != -EAGAIN) { + return log_msg_ret("get_event", ret); + } + schedule(); + if (ctrlc()) + running = false; + } + printf("%d events received\n", count); + + return 0; +} + +static char mouse_help_text[] = + "dump - Dump input from a mouse"; + +U_BOOT_CMD_WITH_SUBCMDS(mouse, "Mouse input", mouse_help_text, + U_BOOT_SUBCMD_MKENT(dump, 1, 1, do_mouse_dump)); -- 2.43.0

From: Simon Glass <sjg@chromium.org> Provide a devicetree fragment to enable a mouse for sandbox. Signed-off-by: Simon Glass <sjg@chromium.org> --- arch/sandbox/dts/sandbox.dtsi | 4 ++++ arch/sandbox/dts/test.dts | 4 ++++ 2 files changed, 8 insertions(+) diff --git a/arch/sandbox/dts/sandbox.dtsi b/arch/sandbox/dts/sandbox.dtsi index dd18bd26352..48e34a7aee5 100644 --- a/arch/sandbox/dts/sandbox.dtsi +++ b/arch/sandbox/dts/sandbox.dtsi @@ -203,6 +203,10 @@ }; }; + mouse { + compatible = "sandbox,mouse"; + }; + pci@0 { pci@1e,0 { compatible = "sandbox,pmc"; diff --git a/arch/sandbox/dts/test.dts b/arch/sandbox/dts/test.dts index b79f06ce0fe..6a199965d36 100644 --- a/arch/sandbox/dts/test.dts +++ b/arch/sandbox/dts/test.dts @@ -591,6 +591,10 @@ test5-gpios = <&gpio_a 19>; }; + mouse { + compatible = "sandbox,mouse"; + }; + mmio-bus@0 { #address-cells = <1>; #size-cells = <1>; -- 2.43.0

From: Simon Glass <sjg@chromium.org> Provide a few simple tests for two methods available in the mouse uclass. Signed-off-by: Simon Glass <sjg@chromium.org> --- arch/sandbox/include/asm/test.h | 17 ++++++ drivers/input/sandbox_mouse.c | 49 +++++++++++++++++ test/dm/Makefile | 1 + test/dm/mouse.c | 96 +++++++++++++++++++++++++++++++++ 4 files changed, 163 insertions(+) create mode 100644 test/dm/mouse.c diff --git a/arch/sandbox/include/asm/test.h b/arch/sandbox/include/asm/test.h index 4df39fac1da..499db42804c 100644 --- a/arch/sandbox/include/asm/test.h +++ b/arch/sandbox/include/asm/test.h @@ -11,6 +11,7 @@ #include <pci_ids.h> struct unit_test_state; +struct mouse_event; /* The sandbox driver always permits an I2C device with this address */ #define SANDBOX_I2C_TEST_ADDR 0x59 @@ -361,4 +362,20 @@ bool sandbox_sf_bootdev_enabled(void); */ void sandbox_sf_set_enable_bootdevs(bool enable); +/** + * sandbox_mouse_set_test_mode() - Enable/disable test mode for sandbox mouse + * + * @dev: Mouse device + * @test_mode: true to enable test mode, false to use SDL + */ +void sandbox_mouse_set_test_mode(struct udevice *dev, bool test_mode); + +/** + * sandbox_mouse_inject() - Inject a mouse event for testing + * + * @dev: Mouse device (must be in test mode) + * @event: Event to inject + */ +void sandbox_mouse_inject(struct udevice *dev, struct mouse_event *event); + #endif diff --git a/drivers/input/sandbox_mouse.c b/drivers/input/sandbox_mouse.c index 4aedf0fdf2d..ba271242b1a 100644 --- a/drivers/input/sandbox_mouse.c +++ b/drivers/input/sandbox_mouse.c @@ -8,11 +8,29 @@ #include <mouse.h> #include <asm/sdl.h> +struct sandbox_mouse_priv { + bool test_mode; + struct mouse_event test_event; + bool test_event_pending; +}; + static int mouse_sandbox_get_event(struct udevice *dev, struct mouse_event *event) { + struct sandbox_mouse_priv *priv = dev_get_priv(dev); int ret; + /* If in test mode, return test event if pending */ + if (priv->test_mode) { + if (priv->test_event_pending) { + *event = priv->test_event; + priv->test_event_pending = false; + return 0; + } else { + return -EAGAIN; + } + } + ret = sandbox_sdl_get_mouse_event(event); return ret; @@ -27,9 +45,40 @@ static const struct udevice_id mouse_sandbox_ids[] = { { } }; +/** + * sandbox_mouse_set_test_mode() - Enable/disable test mode + * + * @dev: Mouse device + * @test_mode: true to enable test mode, false to use SDL + */ +void sandbox_mouse_set_test_mode(struct udevice *dev, bool test_mode) +{ + struct sandbox_mouse_priv *priv = dev_get_priv(dev); + + priv->test_mode = test_mode; + priv->test_event_pending = false; +} + +/** + * sandbox_mouse_inject() - Inject a mouse event for testing + * + * @dev: Mouse device (must be in test mode) + * @event: Event to inject + */ +void sandbox_mouse_inject(struct udevice *dev, struct mouse_event *event) +{ + struct sandbox_mouse_priv *priv = dev_get_priv(dev); + + if (priv->test_mode) { + priv->test_event = *event; + priv->test_event_pending = true; + } +} + U_BOOT_DRIVER(mouse_sandbox) = { .name = "mouse_sandbox", .id = UCLASS_MOUSE, .of_match = mouse_sandbox_ids, .ops = &mouse_sandbox_ops, + .priv_auto = sizeof(struct sandbox_mouse_priv), }; diff --git a/test/dm/Makefile b/test/dm/Makefile index eab78d3ac4a..b38de3e12d0 100644 --- a/test/dm/Makefile +++ b/test/dm/Makefile @@ -68,6 +68,7 @@ obj-$(CONFIG_DM_MDIO_MUX) += mdio_mux.o obj-$(CONFIG_MEMORY) += memory.o obj-$(CONFIG_MISC) += misc.o obj-$(CONFIG_DM_MMC) += mmc.o +obj-$(CONFIG_MOUSE) += mouse.o obj-$(CONFIG_CMD_MUX) += mux-cmd.o obj-$(CONFIG_MULTIPLEXER) += mux-emul.o obj-$(CONFIG_MUX_MMIO) += mux-mmio.o diff --git a/test/dm/mouse.c b/test/dm/mouse.c new file mode 100644 index 00000000000..f9c2e88c43a --- /dev/null +++ b/test/dm/mouse.c @@ -0,0 +1,96 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Tests for the driver model mouse API + * + * Copyright 2025 Google LLC + * Written by Simon Glass <sjg@chromium.org> + */ + +#include <dm.h> +#include <mouse.h> +#include <dm/test.h> +#include <test/test.h> +#include <test/ut.h> +#include <asm/test.h> + +static int dm_test_mouse_basic(struct unit_test_state *uts) +{ + struct udevice *dev; + + ut_assertok(uclass_first_device_err(UCLASS_MOUSE, &dev)); + + /* put mouse in test mode */ + sandbox_mouse_set_test_mode(dev, true); + + return 0; +} +DM_TEST(dm_test_mouse_basic, UTF_SCAN_PDATA | UTF_SCAN_FDT); + +static int dm_test_mouse_motion(struct unit_test_state *uts) +{ + struct udevice *dev; + struct mouse_event event, inject; + + ut_assertok(uclass_first_device_err(UCLASS_MOUSE, &dev)); + + /* put mouse in test mode */ + sandbox_mouse_set_test_mode(dev, true); + + /* inject a motion event */ + inject.type = MOUSE_EV_MOTION; + inject.motion.state = 0; + inject.motion.x = 100; + inject.motion.y = 200; + inject.motion.xrel = 10; + inject.motion.yrel = 20; + + sandbox_mouse_inject(dev, &inject); + + /* get and verify the event */ + ut_assertok(mouse_get_event(dev, &event)); + ut_asserteq(MOUSE_EV_MOTION, event.type); + ut_asserteq(0, event.motion.state); + ut_asserteq(100, event.motion.x); + ut_asserteq(200, event.motion.y); + ut_asserteq(10, event.motion.xrel); + ut_asserteq(20, event.motion.yrel); + + /* verify no more events are pending */ + ut_asserteq(-EAGAIN, mouse_get_event(dev, &event)); + + return 0; +} +DM_TEST(dm_test_mouse_motion, UTF_SCAN_PDATA | UTF_SCAN_FDT); + +static int dm_test_mouse_button(struct unit_test_state *uts) +{ + struct udevice *dev; + struct mouse_event event, inject; + + ut_assertok(uclass_first_device_err(UCLASS_MOUSE, &dev)); + + /* put mouse in test mode */ + sandbox_mouse_set_test_mode(dev, true); + + /* inject a button press event */ + inject.type = MOUSE_EV_BUTTON; + inject.button.button = BUTTON_LEFT; + inject.button.press_state = BUTTON_PRESSED; + inject.button.clicks = 1; + inject.button.x = 150; + inject.button.y = 250; + + sandbox_mouse_inject(dev, &inject); + + /* get and verify the event */ + ut_assertok(mouse_get_event(dev, &event)); + ut_asserteq(MOUSE_EV_BUTTON, event.type); + ut_asserteq(BUTTON_LEFT, event.button.button); + ut_asserteq(BUTTON_PRESSED, event.button.press_state); + ut_asserteq(1, event.button.clicks); + ut_asserteq(150, event.button.x); + ut_asserteq(250, event.button.y); + + return 0; +} +DM_TEST(dm_test_mouse_button, UTF_SCAN_PDATA | UTF_SCAN_FDT); -- 2.43.0

From: Simon Glass <sjg@chromium.org> Add a basic mouse driver for USB mice. It only handles very basic mice so assumes that the reports are in the basic format described by the USB HID specification 1.11. Signed-off-by: Simon Glass <sjg@chromium.org> --- drivers/input/Kconfig | 8 + drivers/input/Makefile | 1 + drivers/input/usb_mouse.c | 353 ++++++++++++++++++++++++++++++++++++++ include/usb.h | 1 + 4 files changed, 363 insertions(+) create mode 100644 drivers/input/usb_mouse.c diff --git a/drivers/input/Kconfig b/drivers/input/Kconfig index 101257f9767..e98471c7c2e 100644 --- a/drivers/input/Kconfig +++ b/drivers/input/Kconfig @@ -110,3 +110,11 @@ config MOUSE graphics boot menus and the like. The driver can provide mouse events based on user interaction and these can be used to control U-Boot's operation. + +config USB_MOUSE + bool "USB mouse support" + help + This enables using a USB mouse to control a feature in U-Boot, + typically a boot menu. The driver uses the USB boot interface of + the mouse and attempts to auto-configure itself for normal + operation. diff --git a/drivers/input/Makefile b/drivers/input/Makefile index 8c5a395a540..797284ad8f8 100644 --- a/drivers/input/Makefile +++ b/drivers/input/Makefile @@ -20,3 +20,4 @@ obj-$(CONFIG_MOUSE) += mouse-uclass.o ifdef CONFIG_MOUSE obj-$(CONFIG_SANDBOX) += sandbox_mouse.o endif +obj-$(CONFIG_USB_MOUSE) += usb_mouse.o diff --git a/drivers/input/usb_mouse.c b/drivers/input/usb_mouse.c new file mode 100644 index 00000000000..74f093a4b5a --- /dev/null +++ b/drivers/input/usb_mouse.c @@ -0,0 +1,353 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * USB mouse driver (parts taken from usb_kbd.c) + * + * (C) Copyright 2001 + * Denis Peter, MPL AG Switzerland + * + * Part of this source has been derived from the Linux USB project. + * + * Copyright 2025 Simon Glass <sjg@chromium.org> + */ + +#define LOG_CATEGORY UCLASS_MOUSE + +#include <dm.h> +#include <log.h> +#include <malloc.h> +#include <mouse.h> +#include <time.h> +#include <usb.h> + +enum { + RPT_BUTTON, + RPT_XREL, + RPT_YREL, + RPT_SCROLLY, +}; + +struct usb_mouse_priv { + unsigned long intpipe; + int intpktsize; + int intinterval; + unsigned long last_report; + struct int_queue *intq; + + u32 repeat_delay; + + int xrel; + int yrel; + int x; + int y; + int buttons; + int old_buttons; + int yscroll; + /* + * TODO(sjg@chromium.org): Use an array instead, with the + * DM_FLAG_ALLOC_PRIV_DMA flag + */ + s8 *buf; + + u8 flags; +}; + +/* Interrupt service routine */ +static int usb_mouse_irq_worker(struct udevice *dev) +{ + struct usb_mouse_priv *priv = dev_get_priv(dev); + s8 *buf = priv->buf; + + priv->buttons = buf[RPT_BUTTON]; + priv->xrel = buf[RPT_XREL]; + if (priv->xrel < -127) + priv->xrel = 0; + priv->yrel = buf[RPT_YREL]; + if (priv->yrel < -127) + priv->yrel = 0; + priv->yscroll = buf[RPT_SCROLLY]; + + return 1; +} + +/* Mouse interrupt handler */ +static int usb_mouse_irq(struct usb_device *udev) +{ + struct udevice *dev = udev->dev; + + if (udev->irq_status || udev->irq_act_len != USB_MOUSE_BOOT_REPORT_SIZE) { + log_warning("Error %lx, len %d\n", udev->irq_status, + udev->irq_act_len); + return 1; + } + + return usb_mouse_irq_worker(dev); +} + +/* Interrupt polling */ +static void usb_mouse_poll_for_event(struct udevice *dev) +{ + struct usb_device *udev = dev_get_parent_priv(dev); + struct usb_mouse_priv *priv = dev_get_priv(dev); + int ret; + + if (IS_ENABLED(CONFIG_SYS_USB_EVENT_POLL)) { + /* Submit an interrupt transfer request */ + if (usb_int_msg(udev, priv->intpipe, priv->buf, + priv->intpktsize, priv->intinterval, true) >= 0) + usb_mouse_irq_worker(dev); + } else if (IS_ENABLED(CONFIG_SYS_USB_EVENT_POLL_VIA_CONTROL_EP) || + IS_ENABLED(CONFIG_SYS_USB_EVENT_POLL_VIA_INT_QUEUE)) { + bool got_report = false; + + if (IS_ENABLED(CONFIG_SYS_USB_EVENT_POLL_VIA_CONTROL_EP)) { + struct usb_interface *iface; + + iface = &udev->config.if_desc[0]; + ret = usb_get_report(udev, iface->desc.bInterfaceNumber, + 1, 0, priv->buf, + USB_MOUSE_BOOT_REPORT_SIZE); + printf("control ret=%d\b", ret); + } else { + if (poll_int_queue(udev, priv->intq)) { + usb_mouse_irq_worker(dev); + /* We've consumed all queued int packets, create new */ + destroy_int_queue(udev, priv->intq); + priv->intq = create_int_queue(udev, + priv->intpipe, 1, + USB_MOUSE_BOOT_REPORT_SIZE, priv->buf, + priv->intinterval); + got_report = true; + } + } + if (got_report) + priv->last_report = get_timer(0); + } +} + +static int usb_mouse_get_event(struct udevice *dev, struct mouse_event *event) +{ + struct usb_mouse_priv *priv = dev_get_priv(dev); + + if (priv->buttons != priv->old_buttons) { + struct mouse_button *but = &event->button; + u8 diff; + int i; + + event->type = MOUSE_EV_BUTTON; + diff = priv->buttons ^ priv->old_buttons; + log_debug("buttons=%d, old=%d, diff=%d\n", priv->buttons, + priv->old_buttons, diff); + for (i = 0; i < 3; i++) { + u8 mask = 1 << i; + + if (diff && mask) { + but->button = i; + but->press_state = priv->buttons & mask; + but->clicks = 1; + but->x = priv->x; + but->y = priv->y; + priv->old_buttons ^= mask; + break; + } + } + log_debug("- end: buttons=%d, old=%d, diff=%d\n", priv->buttons, + priv->old_buttons, diff); + } else if (priv->xrel || priv->yrel) { + struct mouse_motion *motion = &event->motion; + + priv->x += priv->xrel; + priv->x = max(priv->x, 0); + priv->x = min(priv->x, 0xffff); + + priv->y += priv->yrel; + priv->y = max(priv->y, 0); + priv->y = min(priv->y, 0xffff); + + event->type = MOUSE_EV_MOTION; + motion->state = priv->buttons; + motion->x = priv->x; + motion->y = priv->y; + motion->xrel = priv->xrel; + motion->yrel = priv->yrel; + priv->xrel = 0; + priv->yrel = 0; + } else { + usb_mouse_poll_for_event(dev); + return -EAGAIN; + } + + return 0; +} + +static int check_mouse(struct usb_device *udev, int ifnum) +{ + struct usb_endpoint_descriptor *ep; + struct usb_interface *iface; + + if (udev->descriptor.bNumConfigurations != 1) + return log_msg_ret("cmn", -EINVAL); + + iface = &udev->config.if_desc[ifnum]; + + log_debug("USB device: class=%d, subclass=%d, protocol=%d\n", + iface->desc.bInterfaceClass, iface->desc.bInterfaceSubClass, + iface->desc.bInterfaceProtocol); + + if (iface->desc.bInterfaceClass != USB_CLASS_HID) + return log_msg_ret("cmc", -EINVAL); + + if (iface->desc.bInterfaceSubClass != USB_SUB_HID_BOOT && + iface->desc.bInterfaceSubClass != 0) + return log_msg_ret("cms", -EINVAL); + + /* Accept any HID device with subclass 0 or boot protocol */ + if (iface->desc.bInterfaceSubClass == 0) { + log_debug("Accepting HID device subclass 0 (tablet/other)\n"); + /* TODO: check endpoints for all devices */ + } else { + /* For boot-protocol devices, check for mouse protocol */ + if (iface->desc.bInterfaceProtocol != USB_PROT_HID_MOUSE) + return log_msg_ret("cmp", -EINVAL); + } + + if (iface->desc.bNumEndpoints != 1) + return log_msg_ret("num endpoints", -EINVAL); + + ep = &iface->ep_desc[0]; + + /* Check if endpoint 1 is interrupt endpoint */ + if (!(ep->bEndpointAddress & 0x80)) + return log_msg_ret("cmi", -EINVAL); + + if ((ep->bmAttributes & 3) != 3) + return log_msg_ret("cma", -EINVAL); + + return 0; +} + +/* probes the USB device dev for mouse type */ +static int usb_mouse_probe(struct udevice *dev) +{ + struct usb_device *udev = dev_get_parent_priv(dev); + struct usb_mouse_priv *priv = dev_get_priv(dev); + struct usb_endpoint_descriptor *ep; + struct usb_interface *iface; + const int ifnum = 0; + int ret; + + ret = check_mouse(udev, ifnum); + if (ret) { + log_warning("Mouse detect fail (err=%d)\n", ret); + + return log_msg_ret("ump", ret); + } + log_debug("USB mouse: found set protocol...\n"); + + /* allocate input buffer aligned and sized to USB DMA alignment */ + priv->buf = memalign(USB_DMA_MINALIGN, + roundup(USB_MOUSE_BOOT_REPORT_SIZE, + USB_DMA_MINALIGN)); + + /* Insert private data into USB device structure */ + udev->privptr = priv; + + /* Set IRQ handler */ + udev->irq_handle = usb_mouse_irq; + + iface = &udev->config.if_desc[ifnum]; + ep = &iface->ep_desc[0]; + priv->intpipe = usb_rcvintpipe(udev, ep->bEndpointAddress); + priv->intpktsize = min(usb_maxpacket(udev, priv->intpipe), + USB_MOUSE_BOOT_REPORT_SIZE); + priv->intinterval = ep->bInterval; + priv->last_report = -1; + + /* We found a USB Keyboard, install it. */ + usb_set_protocol(udev, iface->desc.bInterfaceNumber, 0); + + log_debug("Found set idle...\n"); + usb_set_idle(udev, iface->desc.bInterfaceNumber, 0, 0); + + log_debug("Enable interrupt pipe...\n"); + if (IS_ENABLED(CONFIG_SYS_USB_EVENT_POLL_VIA_INT_QUEUE)) { + priv->intq = create_int_queue(udev, priv->intpipe, 1, + USB_MOUSE_BOOT_REPORT_SIZE, + priv->buf, priv->intinterval); + printf("priv->intq %p\n", priv->intq); + ret = priv->intq ? 0 : -EBUSY; + } else if (IS_ENABLED(CONFIG_SYS_USB_EVENT_POLL_VIA_CONTROL_EP)) { + ret = usb_get_report(udev, iface->desc.bInterfaceNumber, 1, 0, + priv->buf, USB_MOUSE_BOOT_REPORT_SIZE); + } else { + ret = usb_int_msg(udev, priv->intpipe, priv->buf, + priv->intpktsize, priv->intinterval, false); + } + if (ret < 0) { + log_warning("Failed to get mouse state from device %04x:%04x (err=%d): ignoring\n", + udev->descriptor.idVendor, + udev->descriptor.idProduct, ret); + /* + * don't abort - QEMU emulation may not support initial state + * read + */ + } + log_debug("USB mouse OK\n"); + + return 0; +} + +static int usb_mouse_remove(struct udevice *dev) +{ + struct usb_device *udev = dev_get_parent_priv(dev); + struct usb_mouse_priv *priv = dev_get_priv(dev); + + if (IS_ENABLED(CONFIG_SYS_USB_EVENT_POLL_VIA_INT_QUEUE)) + destroy_int_queue(udev, priv->intq); + free(priv->buf); + + return 0; +} + +const struct mouse_ops usb_mouse_ops = { + .get_event = usb_mouse_get_event, +}; + +static const struct udevice_id usb_mouse_ids[] = { + { .compatible = "usb-mouse" }, + { } +}; + +U_BOOT_DRIVER(usb_mouse) = { + .name = "usb_mouse", + .id = UCLASS_MOUSE, + .of_match = usb_mouse_ids, + .ops = &usb_mouse_ops, + .probe = usb_mouse_probe, + .remove = usb_mouse_remove, + .priv_auto = sizeof(struct usb_mouse_priv), +}; + +static const struct usb_device_id mouse_id_table[] = { + { + /* Standard USB HID boot mouse */ + .match_flags = USB_DEVICE_ID_MATCH_INT_CLASS | + USB_DEVICE_ID_MATCH_INT_SUBCLASS | + USB_DEVICE_ID_MATCH_INT_PROTOCOL, + .bInterfaceClass = USB_CLASS_HID, + .bInterfaceSubClass = USB_SUB_HID_BOOT, + .bInterfaceProtocol = USB_PROT_HID_MOUSE, + }, + { + /* + * Generic HID device (includes tablets and other pointing + * devices) + */ + .match_flags = USB_DEVICE_ID_MATCH_INT_CLASS | + USB_DEVICE_ID_MATCH_INT_SUBCLASS, + .bInterfaceClass = USB_CLASS_HID, + .bInterfaceSubClass = 0, /* None/generic */ + }, + { } +}; + +U_BOOT_USB_DEVICE(usb_mouse, mouse_id_table); diff --git a/include/usb.h b/include/usb.h index be37ed272e1..7e05ef26d6b 100644 --- a/include/usb.h +++ b/include/usb.h @@ -255,6 +255,7 @@ int usb_host_eth_scan(int mode); * Appendix B of HID Device Class Definition 1.11 */ #define USB_KBD_BOOT_REPORT_SIZE 8 +#define USB_MOUSE_BOOT_REPORT_SIZE 8 /* * usb_init() - initialize the USB Controllers -- 2.43.0

From: Simon Glass <sjg@chromium.org> A mouse click is defined as pressing the mouse and then releasing it over a given spot. Add a function the tracks the mouse state and returns the most recent mouse click, if any. Signed-off-by: Simon Glass <sjg@chromium.org> --- drivers/input/mouse-uclass.c | 43 +++++++++++++ include/mouse.h | 25 ++++++++ test/dm/mouse.c | 121 +++++++++++++++++++++++++++++++++++ 3 files changed, 189 insertions(+) diff --git a/drivers/input/mouse-uclass.c b/drivers/input/mouse-uclass.c index f42ef346c5c..256642ef55e 100644 --- a/drivers/input/mouse-uclass.c +++ b/drivers/input/mouse-uclass.c @@ -23,7 +23,50 @@ int mouse_get_event(struct udevice *dev, struct mouse_event *evt) return 0; } +int mouse_get_click(struct udevice *dev, int *xp, int *yp) +{ + struct mouse_uc_priv *uc_priv = dev_get_uclass_priv(dev); + struct mouse_event event; + int ret; + + /* Get one mouse event */ + ret = mouse_get_event(dev, &event); + if (ret) + return -EAGAIN; /* No event available */ + + /* Only process button events for left button */ + if (event.type == MOUSE_EV_BUTTON && + event.button.button == BUTTON_LEFT) { + enum mouse_press_state_t new_state = event.button.press_state; + bool pending = false; + + /* Detect press->release transition (click) */ + if (uc_priv->left_button_state == BUTTON_PRESSED && + new_state == BUTTON_RELEASED) { + pending = true; + uc_priv->click_x = event.button.x; + uc_priv->click_y = event.button.y; + } + + /* Update button state */ + uc_priv->left_button_state = new_state; + + /* If we just detected a click, return it */ + if (pending) { + if (xp) + *xp = uc_priv->click_x; + if (yp) + *yp = uc_priv->click_y; + + return 0; + } + } + + return -EAGAIN; +} + UCLASS_DRIVER(mouse) = { .id = UCLASS_MOUSE, .name = "mouse", + .per_device_auto = sizeof(struct mouse_uc_priv), }; diff --git a/include/mouse.h b/include/mouse.h index c96c63918ea..0d20f8ffdbc 100644 --- a/include/mouse.h +++ b/include/mouse.h @@ -8,6 +8,8 @@ #ifndef _MOUSE_H #define _MOUSE_H +#include <stdbool.h> + struct udevice; enum mouse_ev_t { @@ -29,6 +31,19 @@ enum mouse_press_state_t { BUTTON_PRESSED, }; +/** + * struct mouse_uc_priv - private data for mouse uclass + * + * @left_button_state: Current state of left button (BUTTON_PRESSED/BUTTON_RELEASED) + * @click_x: X coordinate where the click occurred + * @click_y: Y coordinate where the click occurred + */ +struct mouse_uc_priv { + enum mouse_press_state_t left_button_state; + int click_x; + int click_y; +}; + /** * struct mouse_event - information about a mouse event * @@ -77,4 +92,14 @@ struct mouse_ops { int mouse_get_event(struct udevice *dev, struct mouse_event *event); +/** + * mouse_get_click() - Check if a left mouse button click has occurred + * + * @dev: Mouse device + * @xp: Returns X coordinate of click (can be NULL) + * @yp: Returns Y coordinate of click (can be NULL) + * Returns: 0 if a click has occurred, -EAGAIN if no click pending + */ +int mouse_get_click(struct udevice *dev, int *xp, int *py); + #endif diff --git a/test/dm/mouse.c b/test/dm/mouse.c index f9c2e88c43a..1b4c2b5f60f 100644 --- a/test/dm/mouse.c +++ b/test/dm/mouse.c @@ -94,3 +94,124 @@ static int dm_test_mouse_button(struct unit_test_state *uts) return 0; } DM_TEST(dm_test_mouse_button, UTF_SCAN_PDATA | UTF_SCAN_FDT); + +static int dm_test_mouse_click(struct unit_test_state *uts) +{ + struct udevice *dev; + struct mouse_event inject; + int x, y; + + ut_assertok(uclass_first_device_err(UCLASS_MOUSE, &dev)); + + /* put mouse in test mode */ + sandbox_mouse_set_test_mode(dev, true); + + /* test that no click is detected initially */ + ut_asserteq(-EAGAIN, mouse_get_click(dev, &x, &y)); + + /* inject a left button press */ + inject.type = MOUSE_EV_BUTTON; + inject.button.button = BUTTON_LEFT; + inject.button.press_state = BUTTON_PRESSED; + inject.button.clicks = 1; + inject.button.x = 300; + inject.button.y = 400; + + sandbox_mouse_inject(dev, &inject); + + /* + * calling mouse_get_click() should not detect a click yet (press + * only) + */ + ut_asserteq(-EAGAIN, mouse_get_click(dev, &x, &y)); + + /* inject a left button release */ + inject.type = MOUSE_EV_BUTTON; + inject.button.button = BUTTON_LEFT; + inject.button.press_state = BUTTON_RELEASED; + inject.button.clicks = 1; + inject.button.x = 300; + inject.button.y = 400; + + sandbox_mouse_inject(dev, &inject); + + /* now mouse_get_click() should detect the click */ + ut_assertok(mouse_get_click(dev, &x, &y)); + ut_asserteq(300, x); + ut_asserteq(400, y); + + /* verify no more clicks are pending */ + ut_asserteq(-EAGAIN, mouse_get_click(dev, &x, &y)); + + return 0; +} +DM_TEST(dm_test_mouse_click, UTF_SCAN_PDATA | UTF_SCAN_FDT); + +static int dm_test_mouse_click_no_coordinates(struct unit_test_state *uts) +{ + struct udevice *dev; + struct mouse_event inject; + + ut_assertok(uclass_first_device_err(UCLASS_MOUSE, &dev)); + + /* put mouse in test mode */ + sandbox_mouse_set_test_mode(dev, true); + + /* inject press and release to create a click */ + inject.type = MOUSE_EV_BUTTON; + inject.button.button = BUTTON_LEFT; + inject.button.press_state = BUTTON_PRESSED; + inject.button.clicks = 1; + inject.button.x = 500; + inject.button.y = 600; + sandbox_mouse_inject(dev, &inject); + + /* process the press event */ + ut_asserteq(-EAGAIN, mouse_get_click(dev, NULL, NULL)); + + inject.button.press_state = BUTTON_RELEASED; + sandbox_mouse_inject(dev, &inject); + + /* + * now test that click is detected without coordinate return + */ + ut_assertok(mouse_get_click(dev, NULL, NULL)); + + return 0; +} +DM_TEST(dm_test_mouse_click_no_coordinates, UTF_SCAN_PDATA | UTF_SCAN_FDT); + +static int dm_test_mouse_right_button(struct unit_test_state *uts) +{ + struct udevice *dev; + struct mouse_event inject; + int x, y; + + ut_assertok(uclass_first_device_err(UCLASS_MOUSE, &dev)); + + /* put mouse in test mode */ + sandbox_mouse_set_test_mode(dev, true); + + /* + * right button events should not be detected as clicks by + * mouse_get_click() + */ + inject.type = MOUSE_EV_BUTTON; + inject.button.button = BUTTON_RIGHT; + inject.button.press_state = BUTTON_PRESSED; + inject.button.clicks = 1; + inject.button.x = 100; + inject.button.y = 200; + sandbox_mouse_inject(dev, &inject); + + ut_asserteq(-EAGAIN, mouse_get_click(dev, &x, &y)); + + inject.button.press_state = BUTTON_RELEASED; + sandbox_mouse_inject(dev, &inject); + + /* still no click detected since it was right button */ + ut_asserteq(-EAGAIN, mouse_get_click(dev, &x, &y)); + + return 0; +} +DM_TEST(dm_test_mouse_right_button, UTF_SCAN_PDATA | UTF_SCAN_FDT); -- 2.43.0

From: Simon Glass <sjg@chromium.org> Add definitions for the simple-pointer protocol so that it can be used in drivers. Signed-off-by: Simon Glass <sjg@chromium.org> --- include/efi.h | 1 + include/efi_api.h | 29 +++++++++++++++++++++++++++++ lib/efi/device_path.c | 1 + 3 files changed, 31 insertions(+) diff --git a/include/efi.h b/include/efi.h index e9ca4840352..52f3a014f1d 100644 --- a/include/efi.h +++ b/include/efi.h @@ -176,6 +176,7 @@ extern const efi_guid_t efi_guid_loaded_image_device_path; extern const efi_guid_t efi_guid_device_path; extern const efi_guid_t efi_simple_file_system_protocol_guid; +extern const efi_guid_t efi_guid_simple_pointer; /* Generic EFI table header */ struct efi_table_hdr { diff --git a/include/efi_api.h b/include/efi_api.h index 00a9d29b8fe..70e24cb5fc9 100644 --- a/include/efi_api.h +++ b/include/efi_api.h @@ -977,6 +977,35 @@ struct efi_simple_text_input_protocol { struct efi_event *wait_for_key; }; +#define EFI_SIMPLE_POINTER_PROTOCOL_GUID \ + EFI_GUID(0x31878c87, 0x0b75, 0x11d5, \ + 0x9a, 0x4f, 0x00, 0x90, 0x27, 0x3f, 0xc1, 0x4d) + +struct efi_simple_pointer_mode { + u64 resolution_x; + u64 resolution_y; + u64 resolution_z; + bool left_button; + bool right_button; +}; + +struct efi_simple_pointer_state { + s32 relative_movement_x; + s32 relative_movement_y; + s32 relative_movement_z; + bool left_button; + bool right_button; +}; + +struct efi_simple_pointer_protocol { + efi_status_t (EFIAPI *reset)(struct efi_simple_pointer_protocol *this, + bool extended_verification); + efi_status_t (EFIAPI *get_state)(struct efi_simple_pointer_protocol *this, + struct efi_simple_pointer_state *state); + struct efi_event *wait_for_input; + struct efi_simple_pointer_mode *mode; +}; + #define EFI_DEVICE_PATH_TO_TEXT_PROTOCOL_GUID \ EFI_GUID(0x8b843e20, 0x8132, 0x4852, \ 0x90, 0xcc, 0x55, 0x1a, 0x4e, 0x4a, 0x7f, 0x1c) diff --git a/lib/efi/device_path.c b/lib/efi/device_path.c index b09ea030341..939bf5a0679 100644 --- a/lib/efi/device_path.c +++ b/lib/efi/device_path.c @@ -27,6 +27,7 @@ const efi_guid_t efi_global_variable_guid = EFI_GLOBAL_VARIABLE_GUID; const efi_guid_t efi_guid_device_path = EFI_DEVICE_PATH_PROTOCOL_GUID; const efi_guid_t efi_guid_loaded_image = EFI_LOADED_IMAGE_PROTOCOL_GUID; +const efi_guid_t efi_guid_simple_pointer = EFI_SIMPLE_POINTER_PROTOCOL_GUID; const efi_guid_t efi_guid_loaded_image_device_path = EFI_LOADED_IMAGE_DEVICE_PATH_PROTOCOL_GUID; const efi_guid_t efi_simple_file_system_protocol_guid = -- 2.43.0

From: Simon Glass <sjg@chromium.org> In some cases the device may have a touchpad or mouse, so it is useful to be able to use this in U-Boot. Add a simple driver for a mouse that uses the EFI simple-pointer protocol. Signed-off-by: Simon Glass <sjg@chromium.org> --- drivers/input/Kconfig | 12 ++- drivers/input/Makefile | 1 + drivers/input/efi_mouse.c | 221 ++++++++++++++++++++++++++++++++++++++ 3 files changed, 233 insertions(+), 1 deletion(-) create mode 100644 drivers/input/efi_mouse.c diff --git a/drivers/input/Kconfig b/drivers/input/Kconfig index e98471c7c2e..4bc94de0a0a 100644 --- a/drivers/input/Kconfig +++ b/drivers/input/Kconfig @@ -104,7 +104,7 @@ config TWL4030_INPUT config MOUSE bool "Support for mice and other pointing devices" depends on INPUT - default y if SANDBOX + default y if SANDBOX || EFI_APP help This allows U-Boot to access mouse input, typically needed for graphics boot menus and the like. The driver can provide mouse @@ -118,3 +118,13 @@ config USB_MOUSE typically a boot menu. The driver uses the USB boot interface of the mouse and attempts to auto-configure itself for normal operation. + +config EFI_MOUSE + bool "EFI mouse support" + depends on EFI_APP + default y if EFI_APP + help + This enables mouse support when U-Boot is running as an EFI + application. It uses the EFI Simple Pointer Protocol to access + mouse input from the underlying EFI firmware. This is useful + when U-Boot is used as an EFI boot manager or application. diff --git a/drivers/input/Makefile b/drivers/input/Makefile index 797284ad8f8..4debad9e713 100644 --- a/drivers/input/Makefile +++ b/drivers/input/Makefile @@ -21,3 +21,4 @@ ifdef CONFIG_MOUSE obj-$(CONFIG_SANDBOX) += sandbox_mouse.o endif obj-$(CONFIG_USB_MOUSE) += usb_mouse.o +obj-$(CONFIG_EFI_MOUSE) += efi_mouse.o diff --git a/drivers/input/efi_mouse.c b/drivers/input/efi_mouse.c new file mode 100644 index 00000000000..84347951f62 --- /dev/null +++ b/drivers/input/efi_mouse.c @@ -0,0 +1,221 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * EFI mouse driver using Simple Pointer Protocol + * + * Copyright 2025 Google LLC + * Written by Claude <noreply@anthropic.com> + */ + +#define LOG_CATEGORY UCLASS_MOUSE + +#include <dm.h> +#include <efi.h> +#include <efi_api.h> +#include <log.h> +#include <mouse.h> + +struct efi_mouse_priv { + struct efi_simple_pointer_protocol *pointer; + struct efi_simple_pointer_state last_state; + bool has_last_state; + int x, y; + int buttons; + int old_buttons; + struct efi_event *timer_event; +}; + +static int efi_mouse_get_event(struct udevice *dev, struct mouse_event *event) +{ + struct efi_mouse_priv *priv = dev_get_priv(dev); + struct efi_simple_pointer_state state; + efi_status_t ret; + int new_buttons; + if (!priv->pointer) + return -ENODEV; + + /* Use timer-based polling approach like EFI keyboard */ + if (priv->timer_event) { + struct efi_boot_services *boot = efi_get_boot(); + efi_uintn_t index; + struct efi_event *events[2]; + efi_uintn_t num_events = 1; + + events[0] = priv->timer_event; + if (priv->pointer->wait_for_input) { + events[1] = priv->pointer->wait_for_input; + num_events = 2; + } + + ret = boot->wait_for_event(num_events, events, &index); + if (ret != EFI_SUCCESS) + return -EAGAIN; + } + + /* Get current pointer state */ + ret = priv->pointer->get_state(priv->pointer, &state); + if (ret != EFI_SUCCESS) { + if (ret == EFI_NOT_READY) + return -EAGAIN; + printf("EFI mouse: get_state failed (ret=0x%lx)\n", ret); + return -EIO; + } + + /* Check for button changes */ + new_buttons = 0; + if (state.left_button) + new_buttons |= 1 << 0; + if (state.right_button) + new_buttons |= 1 << 1; + + if (new_buttons != priv->old_buttons) { + struct mouse_button *but = &event->button; + u8 diff = new_buttons ^ priv->old_buttons; + int i; + + event->type = MOUSE_EV_BUTTON; + /* Find first changed button */ + for (i = 0; i < 2; i++) { + u8 mask = 1 << i; + if (diff & mask) { + but->button = i; + but->press_state = (new_buttons & mask) ? 1 : 0; + but->clicks = 1; + but->x = priv->x; + but->y = priv->y; + priv->old_buttons ^= mask; + return 0; + } + } + } + + /* Check for movement */ + if (state.relative_movement_x || state.relative_movement_y) { + struct mouse_motion *motion = &event->motion; + + /* Update absolute position */ + priv->x += state.relative_movement_x; + priv->x = max(priv->x, 0); + priv->x = min(priv->x, 0xffff); + + priv->y += state.relative_movement_y; + priv->y = max(priv->y, 0); + priv->y = min(priv->y, 0xffff); + + event->type = MOUSE_EV_MOTION; + motion->state = new_buttons; + motion->x = priv->x; + motion->y = priv->y; + motion->xrel = state.relative_movement_x; + motion->yrel = state.relative_movement_y; + + priv->buttons = new_buttons; + return 0; + } + + priv->buttons = new_buttons; + + return -EAGAIN; +} + +static int efi_mouse_probe(struct udevice *dev) +{ + struct efi_mouse_priv *priv = dev_get_priv(dev); + struct efi_boot_services *boot = efi_get_boot(); + efi_status_t ret; + efi_handle_t *handles; + efi_uintn_t num_handles; + + log_debug("EFI mouse probe\n"); + + /* Find Simple Pointer Protocol handles */ + ret = boot->locate_handle_buffer(BY_PROTOCOL, &efi_guid_simple_pointer, + NULL, &num_handles, &handles); + if (ret != EFI_SUCCESS) { + printf("EFI mouse: No EFI pointer devices found (ret=0x%lx)\n", ret); + return -ENODEV; + } + + log_debug("Found %zu EFI pointer device(s)\n", num_handles); + + /* Use the first pointer device */ + ret = boot->open_protocol(handles[0], &efi_guid_simple_pointer, + (void **)&priv->pointer, efi_get_parent_image(), + NULL, EFI_OPEN_PROTOCOL_GET_PROTOCOL); + if (ret != EFI_SUCCESS) { + printf("EFI mouse: Failed to open EFI pointer protocol (ret=0x%lx)\n", ret); + efi_free_pool(handles); + return -ENODEV; + } + + efi_free_pool(handles); + + /* Reset the pointer device */ + ret = priv->pointer->reset(priv->pointer, false); + if (ret != EFI_SUCCESS) { + log_warning("Failed to reset EFI pointer device\n"); + /* Continue anyway - some devices might not support reset */ + } + + priv->x = 0; + priv->y = 0; + priv->buttons = 0; + priv->old_buttons = 0; + priv->has_last_state = false; + + /* Create a timer event for periodic checking */ + ret = boot->create_event(EVT_TIMER, TPL_NOTIFY, NULL, NULL, + &priv->timer_event); + if (ret != EFI_SUCCESS) { + printf("EFI mouse: Failed to create timer event (ret=0x%lx)\n", ret); + /* Continue without timer - fallback to direct polling */ + priv->timer_event = NULL; + } else { + /* Set timer to trigger every 10ms (100000 x 100ns = 10ms) */ + ret = boot->set_timer(priv->timer_event, EFI_TIMER_PERIODIC, 10000); + if (ret != EFI_SUCCESS) { + printf("EFI mouse: Failed to set timer (ret=0x%lx)\n", ret); + boot->close_event(priv->timer_event); + priv->timer_event = NULL; + } + } + + log_info("EFI mouse initialized\n"); + return 0; +} + +static int efi_mouse_remove(struct udevice *dev) +{ + struct efi_mouse_priv *priv = dev_get_priv(dev); + struct efi_boot_services *boot = efi_get_boot(); + + if (priv->timer_event) { + boot->close_event(priv->timer_event); + priv->timer_event = NULL; + } + + if (priv->pointer) { + /* Protocol will be automatically closed when the image is unloaded */ + priv->pointer = NULL; + } + + return 0; +} + +static const struct mouse_ops efi_mouse_ops = { + .get_event = efi_mouse_get_event, +}; + +static const struct udevice_id efi_mouse_ids[] = { + { .compatible = "efi,mouse" }, + { } +}; + +U_BOOT_DRIVER(efi_mouse) = { + .name = "efi_mouse", + .id = UCLASS_MOUSE, + .of_match = efi_mouse_ids, + .ops = &efi_mouse_ops, + .probe = efi_mouse_probe, + .remove = efi_mouse_remove, + .priv_auto = sizeof(struct efi_mouse_priv), +}; -- 2.43.0

From: Simon Glass <sjg@chromium.org> Provide a devicetree fragment to enable the mouse for x86 and arm, when running as an EFI app. Signed-off-by: Simon Glass <sjg@chromium.org> --- arch/arm/dts/efi-arm_app.dts | 5 +++++ arch/x86/dts/efi-x86_app.dts | 4 ++++ 2 files changed, 9 insertions(+) diff --git a/arch/arm/dts/efi-arm_app.dts b/arch/arm/dts/efi-arm_app.dts index 38cab04e510..d2a008fba6a 100644 --- a/arch/arm/dts/efi-arm_app.dts +++ b/arch/arm/dts/efi-arm_app.dts @@ -23,9 +23,14 @@ compatible = "efi,reset"; bootph-all; }; + efi-fb { compatible = "efi-fb"; bootph-some-ram; }; + mouse { + compatible = "efi,mouse"; + }; + }; diff --git a/arch/x86/dts/efi-x86_app.dts b/arch/x86/dts/efi-x86_app.dts index 59e2e402d5e..1daba34d5f0 100644 --- a/arch/x86/dts/efi-x86_app.dts +++ b/arch/x86/dts/efi-x86_app.dts @@ -30,4 +30,8 @@ bootph-some-ram; }; + mouse { + compatible = "efi,mouse"; + }; + }; -- 2.43.0

From: Simon Glass <sjg@chromium.org> Provide arguments to QEMU to enable a mouse. Note that this does not work with EFI at present. Signed-off-by: Simon Glass <sjg@chromium.org> --- scripts/build-efi | 3 +++ scripts/build-qemu | 6 +++++- 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/scripts/build-efi b/scripts/build-efi index f4c96dad7bd..131aad50897 100755 --- a/scripts/build-efi +++ b/scripts/build-efi @@ -112,6 +112,9 @@ class BuildEfi: extra += ['-device', 'qemu-xhci', '-device', 'usb-kbd', '-device', 'usb-tablet'] extra += ['-display', 'default,show-cursor=on'] + else: # x86 + extra += ['-device', 'qemu-xhci', '-device', 'usb-kbd', + '-device', 'usb-tablet'] extra += ['-serial', 'mon:stdio'] serial_msg = '' if self.args.kvm: diff --git a/scripts/build-qemu b/scripts/build-qemu index 0bc312470de..62f0bc41fad 100755 --- a/scripts/build-qemu +++ b/scripts/build-qemu @@ -274,7 +274,11 @@ class BuildQemu: elif self.args.arch == 'arm': qemu_cmd.extend(['-device', 'virtio-gpu-pci']) qemu_cmd.extend(['-device', 'qemu-xhci', '-device', 'usb-kbd', - '-device', 'usb-tablet']) + '-device', 'usb-tablet', '-device', 'usb-mouse']) + qemu_cmd.extend(['-display', 'default,show-cursor=on']) + elif self.args.arch == 'x86': + qemu_cmd.extend(['-device', 'qemu-xhci']) + qemu_cmd.extend(['-device', 'usb-kbd', '-device', 'usb-tablet']) qemu_cmd.extend(['-display', 'default,show-cursor=on']) if not any(item.startswith('-serial') for item in self.qemu_extra): qemu_cmd.extend(['-serial', 'mon:stdio']) -- 2.43.0

From: Simon Glass <sjg@chromium.org> The mouse is typically connected via USB on x86, so enable this feature. Signed-off-by: Simon Glass <sjg@chromium.org> --- configs/qemu-x86_64_defconfig | 3 +++ configs/qemu-x86_defconfig | 3 +++ 2 files changed, 6 insertions(+) diff --git a/configs/qemu-x86_64_defconfig b/configs/qemu-x86_64_defconfig index 15a968e00c3..ac946612b4e 100644 --- a/configs/qemu-x86_64_defconfig +++ b/configs/qemu-x86_64_defconfig @@ -54,6 +54,9 @@ CONFIG_CMD_MEM_SEARCH=y CONFIG_CMD_IDE=y CONFIG_CMD_SPI=y CONFIG_CMD_USB=y +CONFIG_USB=y +CONFIG_USB_XHCI_HCD=y +CONFIG_USB_XHCI_PCI=y CONFIG_CMD_CAT=y # CONFIG_CMD_SETEXPR is not set CONFIG_BOOTP_BOOTFILESIZE=y diff --git a/configs/qemu-x86_defconfig b/configs/qemu-x86_defconfig index b531c73426d..b1fe8be705c 100644 --- a/configs/qemu-x86_defconfig +++ b/configs/qemu-x86_defconfig @@ -33,6 +33,9 @@ CONFIG_CMD_MEM_SEARCH=y CONFIG_CMD_IDE=y CONFIG_CMD_SPI=y CONFIG_CMD_USB=y +CONFIG_USB=y +CONFIG_USB_XHCI_HCD=y +CONFIG_USB_XHCI_PCI=y CONFIG_CMD_CAT=y # CONFIG_CMD_SETEXPR is not set CONFIG_BOOTP_BOOTFILESIZE=y -- 2.43.0

From: Simon Glass <sjg@chromium.org> Enable the mouse when running on QEMU, for ARM and x86. This requires 'usb start' on x86. For ARM, the mouse does not work, perhaps related to the fact that the display does not work either. Signed-off-by: Simon Glass <sjg@chromium.org> --- drivers/input/Kconfig | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/input/Kconfig b/drivers/input/Kconfig index 4bc94de0a0a..7b34902dd7c 100644 --- a/drivers/input/Kconfig +++ b/drivers/input/Kconfig @@ -104,7 +104,7 @@ config TWL4030_INPUT config MOUSE bool "Support for mice and other pointing devices" depends on INPUT - default y if SANDBOX || EFI_APP + default y if SANDBOX || EFI_APP || MACH_QEMU help This allows U-Boot to access mouse input, typically needed for graphics boot menus and the like. The driver can provide mouse @@ -113,6 +113,7 @@ config MOUSE config USB_MOUSE bool "USB mouse support" + default y if MACH_QEMU help This enables using a USB mouse to control a feature in U-Boot, typically a boot menu. The driver uses the USB boot interface of -- 2.43.0

Am 15. September 2025 12:46:58 MESZ schrieb Simon Glass <sjg@u-boot.org>:
From: Simon Glass <sjg@chromium.org>
Enable the mouse when running on QEMU, for ARM and x86.
This requires 'usb start' on x86. For ARM, the mouse does not work, perhaps related to the fact that the display does not work either.
Signed-off-by: Simon Glass <sjg@chromium.org>
Libvirt typically uses virtio-tablet as input device. The spice terminal does not work with a mouse emulation. At least under Wayland. Best regards Heinrich
---
drivers/input/Kconfig | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/drivers/input/Kconfig b/drivers/input/Kconfig index 4bc94de0a0a..7b34902dd7c 100644 --- a/drivers/input/Kconfig +++ b/drivers/input/Kconfig @@ -104,7 +104,7 @@ config TWL4030_INPUT config MOUSE bool "Support for mice and other pointing devices" depends on INPUT - default y if SANDBOX || EFI_APP + default y if SANDBOX || EFI_APP || MACH_QEMU help This allows U-Boot to access mouse input, typically needed for graphics boot menus and the like. The driver can provide mouse @@ -113,6 +113,7 @@ config MOUSE
config USB_MOUSE bool "USB mouse support" + default y if MACH_QEMU help This enables using a USB mouse to control a feature in U-Boot, typically a boot menu. The driver uses the USB boot interface of

Hi Heinrich, On Mon, 15 Sept 2025 at 05:30, Heinrich Schuchardt <xypron.glpk@gmx.de> wrote:
Am 15. September 2025 12:46:58 MESZ schrieb Simon Glass <sjg@u-boot.org>:
From: Simon Glass <sjg@chromium.org>
Enable the mouse when running on QEMU, for ARM and x86.
This requires 'usb start' on x86. For ARM, the mouse does not work, perhaps related to the fact that the display does not work either.
Signed-off-by: Simon Glass <sjg@chromium.org>
Libvirt typically uses virtio-tablet as input device. The spice terminal does not work with a mouse emulation. At least under Wayland.
OK, I sent a driver for that. To combine it with keyboard (which it seems is possible) will need some more effort. Regards, Simon
Best regards
Heinrich
---
drivers/input/Kconfig | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/drivers/input/Kconfig b/drivers/input/Kconfig index 4bc94de0a0a..7b34902dd7c 100644 --- a/drivers/input/Kconfig +++ b/drivers/input/Kconfig @@ -104,7 +104,7 @@ config TWL4030_INPUT config MOUSE bool "Support for mice and other pointing devices" depends on INPUT - default y if SANDBOX || EFI_APP + default y if SANDBOX || EFI_APP || MACH_QEMU help This allows U-Boot to access mouse input, typically needed for graphics boot menus and the like. The driver can provide mouse @@ -113,6 +113,7 @@ config MOUSE
config USB_MOUSE bool "USB mouse support" + default y if MACH_QEMU help This enables using a USB mouse to control a feature in U-Boot, typically a boot menu. The driver uses the USB boot interface of
-- -- Simon Glass Executive Director Email: sjg@u-boot.org Phone: +1 970 834 3498 u-boot.org
participants (2)
-
Heinrich Schuchardt
-
Simon Glass