From a883261f07ff56fbabf3516e41f90efd5d4c9b80 Mon Sep 17 00:00:00 2001 From: Clement Dieperink Date: Tue, 28 Apr 2026 14:21:06 +0200 Subject: [PATCH 1/4] add BPP support in framebuffer and mask fcntl not implemented when setfd + cloexec --- .gitignore | 6 +++--- so3/devices/fb/pl111.c | 7 ++++++- so3/devices/fb/ramfb.c | 4 ++++ so3/devices/fb/virtfb.c | 8 +++++++- so3/fs/vfs.c | 15 +++++++++++++++ so3/include/fb.h | 2 ++ so3/include/vfs.h | 5 +++++ so3/soo/drivers/vfbdevfront/vfbdev.c | 6 ++++++ so3/soo/include/soo/dev/vfbdev.h | 1 + so3/syscall.tbl | 3 +++ 10 files changed, 52 insertions(+), 5 deletions(-) diff --git a/.gitignore b/.gitignore index 2633d745d..20896d4a5 100755 --- a/.gitignore +++ b/.gitignore @@ -42,9 +42,9 @@ agency/rootfs/target/** # except the followings: -!.gitignore #Don't ignore the ignore file ;-) -!.github -!*.tmpl #TaMPLate files for the man documentation +!.gitignore +!.github +!*.tmpl !.clang-format !buildroot/** !buildroot/docs/manual/*.mk diff --git a/so3/devices/fb/pl111.c b/so3/devices/fb/pl111.c index 0c75e86d0..73701f1eb 100644 --- a/so3/devices/fb/pl111.c +++ b/so3/devices/fb/pl111.c @@ -35,6 +35,7 @@ #define HRES 1024 #define VRES 768 +#define BPP 32 /* assume 32bpp */ /* Register address offsets */ #define CLCD_TIM0 0x000 @@ -120,8 +121,12 @@ int fb_ioctl(int fd, unsigned long cmd, unsigned long args) *((uint32_t *) args) = VRES; return 0; + case IOCTL_FB_BPP: + *((uint32_t *) args) = BPP; + return 0; + case IOCTL_FB_SIZE: - *((uint32_t *) args) = HRES * VRES * 4; /* assume 24bpp */ + *((uint32_t *) args) = HRES * VRES * BPP / 8; return 0; default: diff --git a/so3/devices/fb/ramfb.c b/so3/devices/fb/ramfb.c index 455439fbc..54dfc18e0 100644 --- a/so3/devices/fb/ramfb.c +++ b/so3/devices/fb/ramfb.c @@ -295,6 +295,10 @@ int fb_ioctl(int fd, unsigned long cmd, unsigned long args) *((uint32_t *) args) = RAMFB_DRIVER_VIDEO_HEIGHT; return 0; + case IOCTL_FB_BPP: + *((uint32_t *) args) = __fbi->mode.bpp; + return 0; + case IOCTL_FB_SIZE: *((uint32_t *) args) = RAMFB_DRIVER_VIDEO_HEIGHT * RAMFB_DRIVER_VIDEO_WIDTH * __fbi->mode.bpp / 8; /* assume 32bpp */ diff --git a/so3/devices/fb/virtfb.c b/so3/devices/fb/virtfb.c index 0cf977776..0c1c11247 100644 --- a/so3/devices/fb/virtfb.c +++ b/so3/devices/fb/virtfb.c @@ -22,6 +22,8 @@ #include +#define BPP 32 /* assume 32bpp */ + typedef struct { void *vaddr; uint32_t hres, vres; @@ -48,7 +50,11 @@ static int fb_ioctl(int fd, unsigned long cmd, unsigned long args) return 0; case IOCTL_FB_SIZE: - *((uint32_t *) args) = priv->hres * priv->vres * 4; /* assume 24bpp */ + *((uint32_t *) args) = priv->hres * priv->vres * BPP / 8; + return 0; + + case IOCTL_FB_BPP: + *((uint32_t *) args) = BPP; return 0; case IOCTL_FB_IS_REAL: diff --git a/so3/fs/vfs.c b/so3/fs/vfs.c index 47c5e1c42..eba694914 100644 --- a/so3/fs/vfs.c +++ b/so3/fs/vfs.c @@ -1096,6 +1096,21 @@ SYSCALL_DEFINE3(readv, unsigned long, fd, const struct iovec *, vec, unsigned lo return total; } +/** + * TODO: implement the function, currently only used to mask message + * when the flags CLOEXEC is set due to user-space function opendir + * calling fcntl with CLOEXEC flag (used by ls). + */ +SYSCALL_DEFINE3(fcntl, unsigned int, fd, unsigned int, cmd, unsigned long, arg) +{ + if ((cmd == F_SETFD) && (arg == FD_CLOEXEC)) { + return 0; + } + + printk("%s: unsupported command and args %x - %lx\n", __func__, cmd, arg); + return -ENOSYS; +} + static void vfs_gfd_init(void) { memset(open_fds, 0, MAX_FDS * sizeof(struct fd *)); diff --git a/so3/include/fb.h b/so3/include/fb.h index 96540eb3d..2baa6cd08 100644 --- a/so3/include/fb.h +++ b/so3/include/fb.h @@ -30,4 +30,6 @@ */ #define IOCTL_FB_IS_REAL 4 +#define IOCTL_FB_BPP 5 /* Bit per pixel. */ + #endif /* FB_H */ diff --git a/so3/include/vfs.h b/so3/include/vfs.h index d4e7b7a6d..59a5f8994 100644 --- a/so3/include/vfs.h +++ b/so3/include/vfs.h @@ -52,6 +52,10 @@ #define O_TMPFILE 020040000 #define O_NDELAY O_NONBLOCK +/* fcntl command and args for masking CLOEXEC */ +#define F_SETFD 2 +#define FD_CLOEXEC 1 + #define MAX_FDS 128 #define FILENAME_MAX 100 @@ -183,6 +187,7 @@ SYSCALL_DECLARE(lseek, int fd, off_t off, int whence); SYSCALL_DECLARE(_llseek, int fd, unsigned long offset_high, unsigned long offset_low, off_t *result, unsigned whence); SYSCALL_DECLARE(writev, unsigned long fd, const struct iovec *vec, unsigned long vlen); SYSCALL_DECLARE(readv, unsigned long fd, const struct iovec *vec, unsigned long vlen); +SYSCALL_DECLARE(fcntl, unsigned int fd, unsigned int cmd, unsigned long arg); /* VFS common interface */ diff --git a/so3/soo/drivers/vfbdevfront/vfbdev.c b/so3/soo/drivers/vfbdevfront/vfbdev.c index 30fa11eaf..b50eec242 100644 --- a/so3/soo/drivers/vfbdevfront/vfbdev.c +++ b/so3/soo/drivers/vfbdevfront/vfbdev.c @@ -48,6 +48,7 @@ typedef struct { uint32_t hres; uint32_t vres; + uint32_t bpp; size_t memory_size; addr_t fb_paddr; } vfbdev_priv_t; @@ -247,6 +248,7 @@ static void retrieve_data(vfbdev_priv_t *priv) priv->hres = ring_rsp->hres; priv->vres = ring_rsp->vres; + priv->bpp = ring_rsp->bpp; priv->memory_size = ring_rsp->memory_size; vdevfront_processing_end(vfbdev_dev); @@ -307,6 +309,10 @@ static int vfbdev_ioctl(int fd, unsigned long cmd, unsigned long args) *((uint32_t *) args) = priv->vres; return 0; + case IOCTL_FB_BPP: + *((uint32_t *) args) = priv->bpp; + return 0; + case IOCTL_FB_SIZE: *((uint32_t *) args) = priv->memory_size; return 0; diff --git a/so3/soo/include/soo/dev/vfbdev.h b/so3/soo/include/soo/dev/vfbdev.h index 991cbf7b1..e544ee419 100644 --- a/so3/soo/include/soo/dev/vfbdev.h +++ b/so3/soo/include/soo/dev/vfbdev.h @@ -33,6 +33,7 @@ typedef struct { typedef struct { uint32_t hres; uint32_t vres; + uint32_t bpp; uint64_t memory_size; } vfbdev_response_t; diff --git a/so3/syscall.tbl b/so3/syscall.tbl index 8a1147545..7bc1e50c2 100644 --- a/so3/syscall.tbl +++ b/so3/syscall.tbl @@ -71,6 +71,9 @@ sendto sendto NET setsockopt setsockopt NET brk brk PROC_ENV +# Only used to suppress warning about setting CLOEXEC flags +fcntl fcntl + # TODO: implement. Heavily used in MUSL, so remove warning about it for now. munmap empty From 1df52e65e23d321dc0bbef700b5450c0eaa103ee Mon Sep 17 00:00:00 2001 From: Clement Dieperink Date: Mon, 11 May 2026 15:17:32 +0200 Subject: [PATCH 2/4] add vinput frontend and fixes for HDMI on rpi4 --- so3/arch/arm64/rpi4_64/include/mach/ipamap.h | 47 +++ so3/configs/virt64_capsule_defconfig | 3 +- so3/devices/input/soo_kbd.c | 32 +- so3/devices/input/soo_mse.c | 31 +- so3/dts/rpi4_64_capsule.dts | 23 ++ so3/dts/virt64_capsule.dts | 16 + so3/soo/drivers/Kconfig | 5 + so3/soo/drivers/Makefile | 1 + so3/soo/drivers/vinputfront/Makefile | 1 + so3/soo/drivers/vinputfront/vinput.c | 300 +++++++++++++++++++ so3/soo/include/soo/dev/vinput.h | 61 ++++ so3/soo/kernel/vbstore/vbstore_me.c | 12 + usr/lib/slv/slv_fb.c | 20 +- usr/lib/slv/slv_fb.h | 1 + 14 files changed, 516 insertions(+), 37 deletions(-) create mode 100644 so3/soo/drivers/vinputfront/Makefile create mode 100644 so3/soo/drivers/vinputfront/vinput.c create mode 100644 so3/soo/include/soo/dev/vinput.h diff --git a/so3/arch/arm64/rpi4_64/include/mach/ipamap.h b/so3/arch/arm64/rpi4_64/include/mach/ipamap.h index c8672ce14..c39efff6a 100644 --- a/so3/arch/arm64/rpi4_64/include/mach/ipamap.h +++ b/so3/arch/arm64/rpi4_64/include/mach/ipamap.h @@ -30,6 +30,53 @@ ipamap_t agency_ipamap[] = { .size = 0x04000000, }, + + /* VC memory*/ + { + .ipa_addr = 0x3ea00000, + .phys_addr = 0x3ea00000, + .size = 0x600000, + }, + + /* HDMI 0 memory spaces */ + { + .ipa_addr = 0x7ef00000, + .phys_addr = 0x7ef00000, + .size = 0x3000, + }, + { + .ipa_addr = 0x7ef04000, + .phys_addr = 0x7ef04000, + .size = 0x1000, + }, + { + .ipa_addr = 0x7ef20000, + .phys_addr = 0x7ef20000, + .size = 0x1000, + }, + { + .ipa_addr = 0x7e206000, + .phys_addr = 0x7e206000, + .size = 0x1000, + }, + { + .ipa_addr = 0xf0000000, + .phys_addr = 0xf0000000, + .size = 0x10000000, + }, + + /* PCI */ + { + .ipa_addr = 0x7d500000, + .phys_addr = 0x7d500000, + .size = 0x10000, + }, + { + .ipa_addr = 0x600000000, + .phys_addr = 0x600000000, + .size = 0x40000000, + }, + /* Null pointer exception */ { .ipa_addr = 0x0, diff --git a/so3/configs/virt64_capsule_defconfig b/so3/configs/virt64_capsule_defconfig index 789ff4081..0eb6b71fd 100644 --- a/so3/configs/virt64_capsule_defconfig +++ b/so3/configs/virt64_capsule_defconfig @@ -43,7 +43,7 @@ CONFIG_IO_MAPPING_BASE=0xffff900000000000 # CONFIG_I2C is not set # CONFIG_NET is not set # CONFIG_FB is not set -# CONFIG_INPUT is not set +CONFIG_INPUT=y # CONFIG_NS16550 is not set CONFIG_UART_LL_PADDR=0x09000000 CONFIG_SOO_SERIAL=y @@ -105,3 +105,4 @@ CONFIG_VUART_FRONTEND=y # CONFIG_VSENSEJ_FRONTEND is not set CONFIG_VLOGS_FRONTEND=y CONFIG_VFBDEV_FRONTEND=y +CONFIG_VINPUT_FRONTEND=y diff --git a/so3/devices/input/soo_kbd.c b/so3/devices/input/soo_kbd.c index 6f81acf16..5b9b57912 100644 --- a/so3/devices/input/soo_kbd.c +++ b/so3/devices/input/soo_kbd.c @@ -35,13 +35,15 @@ #include +#include + /* Value of the last pressed key. */ struct ps2_key last_key = { .value = 0, .state = 0 }; /* ioctl commands. */ #define GET_KEY 0 -int ioctl_keyboard(int fd, unsigned long cmd, unsigned long args); +static int ioctl_keyboard(int fd, unsigned long cmd, unsigned long args); /* Device info. */ @@ -97,24 +99,24 @@ void soo_input_event(unsigned int type, unsigned int code, int value) return; } - /* - * Ignore "key released" events. A key is released in the ioctl so the - * client can read it. - */ - if (!value) { - return; - } - if (last_key.state & KEY_ST_SHIFT) { - last_key.value = s_eta[code]; + if (code <= sizeof(s_eta)) { + last_key.value = s_eta[code]; + } } else { - last_key.value = eta[code]; + if (code <= sizeof(eta)) { + last_key.value = eta[code]; + } } - last_key.state |= KEY_ST_PRESSED; + if (value == 1) { + last_key.state |= KEY_ST_PRESSED; + } else if (value == 0) { + last_key.state &= ~KEY_ST_PRESSED; + } } -int ioctl_keyboard(int fd, unsigned long cmd, unsigned long args) +static int ioctl_keyboard(int fd, unsigned long cmd, unsigned long args) { switch (cmd) { case GET_KEY: @@ -131,11 +133,11 @@ int ioctl_keyboard(int fd, unsigned long cmd, unsigned long args) return 0; } -int init_keyboard(dev_t *dev) +static int init_keyboard(dev_t *dev, int fdt_offset) { /* Register the input device so it can be accessed from user space. */ devclass_register(dev, &vkbd_cdev); return 0; } -REGISTER_DRIVER_POSTCORE("keyboard,soo_input", init_keyboard); +REGISTER_DRIVER_POSTCORE("soo-input,keyboard", init_keyboard); diff --git a/so3/devices/input/soo_mse.c b/so3/devices/input/soo_mse.c index 6e8e8eeb8..dc6761831 100644 --- a/so3/devices/input/soo_mse.c +++ b/so3/devices/input/soo_mse.c @@ -35,6 +35,8 @@ #include +#include + /* * Maximal horizontal and vertical resolution of the display. * To be set via the ioctl SET_SIZE command. @@ -54,7 +56,7 @@ struct ps2_mouse state = { .x = 0, .y = 0, .left = 0, .right = 0, .middle = 0 }; #define GET_STATE 0 #define SET_SIZE 1 -int ioctl_mouse(int fd, unsigned long cmd, unsigned long args); +static int ioctl_mouse(int fd, unsigned long cmd, unsigned long args); /* Device info. */ @@ -66,7 +68,7 @@ struct devclass vmse_cdev = { .fops = &vmse_fops, }; -void so3virt_mse_event(unsigned int type, unsigned int code, int value) +void soo_mse_event(unsigned int type, unsigned int code, int value) { DBG("Input event: %u %u %d\n", type, code, value); @@ -83,36 +85,25 @@ void so3virt_mse_event(unsigned int type, unsigned int code, int value) state.y = value * res.v / 10000; } } else if (type == EV_KEY) { - /* - * Here we only set the button states to "pressed". Their state - * will be changed to "released" once the state has been read, - * e.g. in the ioctl. So the client has the time to read the - * button states. - */ - if ((code == BTN_LEFT || code == BTN_TOUCH) && value) { + if ((code == BTN_LEFT || code == BTN_TOUCH)) { state.left = value; - } else if (code == BTN_MIDDLE && value) { + } else if (code == BTN_MIDDLE) { state.middle = value; - } else if (code == BTN_RIGHT && value) { + } else if (code == BTN_RIGHT) { state.right = value; } } - DBG("xy[%04d, %04d]; %03s %03s %03s\n", state.x, state.y, state.left ? "LFT" : "", state.middle ? "MID" : "", + DBG("xy[%04d, %04d]; %3s %3s %3s\n", state.x, state.y, state.left ? "LFT" : "", state.middle ? "MID" : "", state.right ? "RGT" : ""); } -int ioctl_mouse(int fd, unsigned long cmd, unsigned long args) +static int ioctl_mouse(int fd, unsigned long cmd, unsigned long args) { switch (cmd) { case GET_STATE: /* Return the mouse coordinates and button states. */ *((struct ps2_mouse *) args) = state; - - /* Reset the button states. */ - state.left = 0; - state.right = 0; - state.middle = 0; break; case SET_SIZE: @@ -128,11 +119,11 @@ int ioctl_mouse(int fd, unsigned long cmd, unsigned long args) return 0; } -int init_mouse(dev_t *dev) +static int init_mouse(dev_t *dev, int fdt_offset) { /* Register the input device so it can be accessed from user space. */ devclass_register(dev, &vmse_cdev); return 0; } -REGISTER_DRIVER_POSTCORE("mouse,so3virt", init_mouse); +REGISTER_DRIVER_POSTCORE("soo-input,mouse", init_mouse); diff --git a/so3/dts/rpi4_64_capsule.dts b/so3/dts/rpi4_64_capsule.dts index 02b672ecf..4bd5cb908 100644 --- a/so3/dts/rpi4_64_capsule.dts +++ b/so3/dts/rpi4_64_capsule.dts @@ -63,6 +63,16 @@ status = "ok"; }; + soo-keyboard { + compatible = "soo-input,keyboard"; + status = "ok"; + }; + + soo-mouse { + compatible = "soo-input,mouse"; + status = "ok"; + }; + /* * GIC interrupt controller - BCM2711 GIC-400 addresses. * GICD at 0xFF841000: stage-2 fault -> AVZ MMIO emulation. @@ -118,6 +128,19 @@ compatible = "vlogs,frontend"; status = "ok"; }; + + /* Enabling framebuffer support */ + vfbdev { + compatible = "vfbdev,frontend"; + status = "ok"; + }; + + + /* Enabling vinput support */ + vinput { + compatible = "vinput,frontend"; + status = "ok"; + }; }; }; diff --git a/so3/dts/virt64_capsule.dts b/so3/dts/virt64_capsule.dts index b90966b6e..88b87ac83 100644 --- a/so3/dts/virt64_capsule.dts +++ b/so3/dts/virt64_capsule.dts @@ -63,6 +63,16 @@ status = "ok"; }; + soo-keyboard { + compatible = "soo-input,keyboard"; + status = "ok"; + }; + + soo-mouse { + compatible = "soo-input,mouse"; + status = "ok"; + }; + /* GIC interrupt controller */ gic: interrupt-controller@0x08000000 { compatible = "intc,gic"; @@ -120,6 +130,12 @@ compatible = "vfbdev,frontend"; status = "ok"; }; + + /* Enabling input support */ + vinput { + compatible = "vinput,frontend"; + status = "ok"; + }; }; }; diff --git a/so3/soo/drivers/Kconfig b/so3/soo/drivers/Kconfig index 72206c751..d28e2bd40 100644 --- a/so3/soo/drivers/Kconfig +++ b/so3/soo/drivers/Kconfig @@ -25,5 +25,10 @@ config VLOGS_FRONTEND config VFBDEV_FRONTEND bool "vfbdev framebuffer driver" +config VINPUT_FRONTEND + bool "vinput driver for mouse and keyboard" + select INPUT + select SOO_INPUT + endmenu diff --git a/so3/soo/drivers/Makefile b/so3/soo/drivers/Makefile index 3dca29327..8591d3b91 100644 --- a/so3/soo/drivers/Makefile +++ b/so3/soo/drivers/Makefile @@ -7,3 +7,4 @@ obj-$(CONFIG_VSENSELED_FRONTEND) += vsenseledfront/ obj-$(CONFIG_VSENSEJ_FRONTEND) += vsensejfront/ obj-$(CONFIG_VLOGS_FRONTEND) += vlogsfront/ obj-$(CONFIG_VFBDEV_FRONTEND) += vfbdevfront/ +obj-$(CONFIG_VINPUT_FRONTEND) += vinputfront/ diff --git a/so3/soo/drivers/vinputfront/Makefile b/so3/soo/drivers/vinputfront/Makefile new file mode 100644 index 000000000..e080f44f9 --- /dev/null +++ b/so3/soo/drivers/vinputfront/Makefile @@ -0,0 +1 @@ +obj-y := vinput.o diff --git a/so3/soo/drivers/vinputfront/vinput.c b/so3/soo/drivers/vinputfront/vinput.c new file mode 100644 index 000000000..1dd1c4f6c --- /dev/null +++ b/so3/soo/drivers/vinputfront/vinput.c @@ -0,0 +1,300 @@ +/* + * Copyright (C) 2026 Clément Dieperink + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + * + */ + +#if 1 +#define DEBUG +#endif + +#include +#include +#include +#include +#include + +#include + +#include + +#include +#include +#include +#include +#include + +#include + +#include + +typedef struct { + /* Must be the first field */ + vinput_t vinput; + + tcb_t *reader_thread; + completion_t reader_wait; + atomic_t running; + +} vinput_priv_t; + +/* Our unique instance. */ +static struct vbus_device *vdev_console = NULL; + +static irq_return_t vinput_interrupt(int irq, void *dev_id) +{ + struct vbus_device *vdev = (struct vbus_device *) dev_id; + vinput_priv_t *vinput_priv = (vinput_priv_t *) dev_get_drvdata(vdev->dev); + + complete(&vinput_priv->reader_wait); + + return IRQ_COMPLETED; +} + +static int get_source(vinput_response_t *ring_rsp) +{ + switch (ring_rsp->type) { + case EV_ABS: + case EV_REL: + return SRC_MOUSE; + + case EV_KEY: + /* Mouse button codes are before joystick codes */ + if (BTN_MOUSE <= ring_rsp->code && ring_rsp->code < BTN_JOYSTICK) + return SRC_MOUSE; + + if (ring_rsp->code == BTN_TOUCH) + return SRC_MOUSE; + + return SRC_KEYBOARD; + + default: + /* We do not use other types */ + return SRC_UNKNOWN; + } +} + +static void *vinput_key_thread(void *args) +{ + vinput_response_t *ring_rsp; + vinput_priv_t *vinput_priv; + + vinput_priv = (vinput_priv_t *) dev_get_drvdata(vdev_console->dev); + BUG_ON(!vinput_priv); + + /* Always perform a wait on the completion since we always get an interrupt + * per byte (hence a complete will be aised up). + */ + + while (atomic_read(&vinput_priv->running)) { + vdevfront_processing_begin(vdev_console); + + while ((ring_rsp = vinput_get_ring_response(&vinput_priv->vinput.ring)) == NULL) { + vdevfront_processing_end(vdev_console); + + wait_for_completion(&vinput_priv->reader_wait); + + if (!atomic_read(&vinput_priv->running)) + return NULL; + + vdevfront_processing_begin(vdev_console); + } + + vdevfront_processing_end(vdev_console); + + switch (get_source(ring_rsp)) { + case SRC_MOUSE: + soo_mse_event(ring_rsp->type, ring_rsp->code, ring_rsp->value); + break; + + case SRC_KEYBOARD: + soo_input_event(ring_rsp->type, ring_rsp->code, ring_rsp->value); + break; + + default: + DBG("[vinput] Unknown input source for %d - %d\n", ring_rsp->type, ring_rsp->code); + break; + } + } + + return NULL; +} + +static void vinput_probe(struct vbus_device *vdev) +{ + unsigned int evtchn; + vinput_sring_t *sring; + struct vbus_transaction vbt; + vinput_priv_t *vinput_priv; + + DBG0("[vinput] Frontend probe\n"); + + if (vdev->state == VbusStateConnected) + return; + + vinput_priv = dev_get_drvdata(vdev->dev); + + /* Local instance */ + vdev_console = vdev; + + init_completion(&vinput_priv->reader_wait); + + DBG("Frontend: Setup ring\n"); + + /* Prepare to set up the ring. */ + + vinput_priv->vinput.ring_ref = GRANT_INVALID_REF; + + /* Allocate an event channel associated to the ring */ + vbus_alloc_evtchn(vdev, &evtchn); + + vinput_priv->vinput.irq = bind_evtchn_to_irq_handler(evtchn, vinput_interrupt, NULL, vdev); + vinput_priv->vinput.evtchn = evtchn; + + /* Allocate a shared page for the ring */ + sring = (vinput_sring_t *) get_free_vpage(); + if (!sring) { + lprintk("%s - line %d: Allocating shared ring failed for device %s\n", __func__, __LINE__, vdev->nodename); + BUG(); + } + + SHARED_RING_INIT(sring); + FRONT_RING_INIT(&vinput_priv->vinput.ring, sring, PAGE_SIZE); + + /* Prepare the shared to page to be visible on the other end */ + + vinput_priv->vinput.ring_ref = vbus_grant_ring(vdev, phys_to_pfn(virt_to_phys_pt((addr_t) vinput_priv->vinput.ring.sring))); + + vbus_transaction_start(&vbt); + + vbus_printf(vbt, vdev->nodename, "ring-ref", "%u", vinput_priv->vinput.ring_ref); + vbus_printf(vbt, vdev->nodename, "ring-evtchn", "%u", vinput_priv->vinput.evtchn); + + vbus_transaction_end(vbt); + + vinput_priv->reader_thread = kernel_thread(vinput_key_thread, "vinput_reader_thread", NULL, 0); +} + +/* At this point, the FE is not connected. */ +static void vinput_reconfiguring(struct vbus_device *vdev) +{ + int res; + struct vbus_transaction vbt; + vinput_priv_t *vinput_priv = dev_get_drvdata(vdev->dev); + + DBG0("[vinput] Frontend reconfiguring\n"); + /* The shared page already exists */ + /* Re-init */ + + gnttab_end_foreign_access(vinput_priv->vinput.ring_ref); + + DBG("Frontend: Setup ring\n"); + + /* Prepare to set up the ring. */ + + vinput_priv->vinput.ring_ref = GRANT_INVALID_REF; + + SHARED_RING_INIT(vinput_priv->vinput.ring.sring); + FRONT_RING_INIT(&vinput_priv->vinput.ring, vinput_priv->vinput.ring.sring, PAGE_SIZE); + + /* Prepare the shared to page to be visible on the other end */ + + res = vbus_grant_ring(vdev, phys_to_pfn(virt_to_phys_pt((addr_t) vinput_priv->vinput.ring.sring))); + if (res < 0) + BUG(); + + vinput_priv->vinput.ring_ref = res; + + vbus_transaction_start(&vbt); + + vbus_printf(vbt, vdev->nodename, "ring-ref", "%u", vinput_priv->vinput.ring_ref); + vbus_printf(vbt, vdev->nodename, "ring-evtchn", "%u", vinput_priv->vinput.evtchn); + + vbus_transaction_end(vbt); +} + +static void vinput_shutdown(struct vbus_device *vdev) +{ + DBG0("[vinput] Frontend shutdown\n"); +} + +static void vinput_closed(struct vbus_device *vdev) +{ + vinput_priv_t *vinput_priv = dev_get_drvdata(vdev->dev); + + DBG0("[vinput] Frontend close\n"); + + /** + * Free the ring and deallocate the proper data. + */ + + /* Free resources associated with old device channel. */ + if (vinput_priv->vinput.ring_ref != GRANT_INVALID_REF) { + gnttab_end_foreign_access(vinput_priv->vinput.ring_ref); + free_vpage((addr_t) vinput_priv->vinput.ring.sring); + + vinput_priv->vinput.ring_ref = GRANT_INVALID_REF; + vinput_priv->vinput.ring.sring = NULL; + } + + if (vinput_priv->vinput.irq) + unbind_from_irqhandler(vinput_priv->vinput.irq); + + vinput_priv->vinput.irq = 0; +} + +static void vinput_suspend(struct vbus_device *vdev) +{ + DBG0("[vinput] Frontend suspend\n"); +} + +static void vinput_resume(struct vbus_device *vdev) +{ + DBG0("[vinput] Frontend resume\n"); +} + +static void vinput_connected(struct vbus_device *vdev) +{ + DBG0("[vinput] Frontend connected\n"); +} + +vdrvfront_t vinputdrv = { .probe = vinput_probe, + .reconfiguring = vinput_reconfiguring, + .shutdown = vinput_shutdown, + .closed = vinput_closed, + .suspend = vinput_suspend, + .resume = vinput_resume, + .connected = vinput_connected }; + +static int vinput_init(dev_t *dev, int fdt_offset) +{ + vinput_priv_t *vinput_priv; + + vinput_priv = malloc(sizeof(vinput_priv_t)); + BUG_ON(!vinput_priv); + + memset(vinput_priv, 0, sizeof(vinput_priv_t)); + + dev_set_drvdata(dev, vinput_priv); + + vdevfront_init(VINPUT_NAME, &vinputdrv); + + atomic_set(&vinput_priv->running, 1); + vinput_priv->reader_thread = NULL; + + return 0; +} + +REGISTER_DRIVER_POSTCORE("vinput,frontend", vinput_init); diff --git a/so3/soo/include/soo/dev/vinput.h b/so3/soo/include/soo/dev/vinput.h new file mode 100644 index 000000000..a74105831 --- /dev/null +++ b/so3/soo/include/soo/dev/vinput.h @@ -0,0 +1,61 @@ +/* + * Copyright (C) 2016-2018 Baptiste Delporte + * Copyright (C) 2018-2019 Daniel Rossier + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + * + */ + +#ifndef VINPUT_H +#define VINPUT_H + +#include +#include +#include + +#define VINPUT_NAME "vinput" +#define VINPUT_PREFIX "[" VINPUT_NAME "] " + +#define SRC_UNKNOWN -1 +#define SRC_MOUSE 0 +#define SRC_KEYBOARD 1 + +typedef struct { + /* No request */ +} vinput_request_t; + +typedef struct { + unsigned int type; + unsigned int code; + int value; +} vinput_response_t; + +DEFINE_RING_TYPES(vinput, vinput_request_t, vinput_response_t); + +typedef struct { + /* Must be the first field */ + vdevfront_t vdevfront; + + vinput_front_ring_t ring; + unsigned int irq; + + grant_ref_t ring_ref; + uint32_t evtchn; + +} vinput_t; + +void soo_mse_event(unsigned int type, unsigned int code, int value); +void soo_input_event(unsigned int type, unsigned int code, int value); + +#endif /* VINPUT_H */ diff --git a/so3/soo/kernel/vbstore/vbstore_me.c b/so3/soo/kernel/vbstore/vbstore_me.c index fa88f2bea..9462c9734 100644 --- a/so3/soo/kernel/vbstore/vbstore_me.c +++ b/so3/soo/kernel/vbstore/vbstore_me.c @@ -253,6 +253,12 @@ void remove_vbstore_entries(void) DBG("%s: removing vfbdev from vbstore...\n", __func__); vbstore_dev_remove(ME_domID(), "vfbdev"); } + + fdt_node = fdt_find_compatible_node(__fdt_addr, "vinput,frontend"); + if (fdt_device_is_available(__fdt_addr, fdt_node)) { + DBG("%s: removing vinput from vbstore...\n", __func__); + vbstore_dev_remove(ME_domID(), "vinput"); + } } /* @@ -305,6 +311,12 @@ void vbstore_devices_populate(void) DBG("%s: init vfbdev...\n", __func__); vbstore_dev_init(ME_domID(), "vfbdev", false, "vfbdev,frontend"); } + + fdt_node = fdt_find_compatible_node(__fdt_addr, "vinput,frontend"); + if (fdt_device_is_available(__fdt_addr, fdt_node)) { + DBG("%s: init vinput...\n", __func__); + vbstore_dev_init(ME_domID(), "vinput", false, "vinput,frontend"); + } } void vbstore_trigger_dev_probe(void) diff --git a/usr/lib/slv/slv_fb.c b/usr/lib/slv/slv_fb.c index 58258502f..318027a35 100644 --- a/usr/lib/slv/slv_fb.c +++ b/usr/lib/slv/slv_fb.c @@ -35,6 +35,7 @@ typedef struct { int fd; void *fbp; size_t fb_size; + uint32_t bpp; bool is_real; } slv_fb_priv_t; @@ -64,7 +65,8 @@ int slv_fb_init(slv_fb_t *fb) /* Get screen resolution. */ if (ioctl(priv->fd, IOCTL_FB_HRES, &fb->hres) || ioctl(priv->fd, IOCTL_FB_VRES, &fb->vres) || - ioctl(priv->fd, IOCTL_FB_SIZE, &priv->fb_size)) { + ioctl(priv->fd, IOCTL_FB_SIZE, &priv->fb_size) || + ioctl(priv->fd, IOCTL_FB_BPP, &priv->bpp)) { printf("Couldn't get framebuffer resolution.\n"); return -1; } @@ -108,6 +110,22 @@ int slv_fb_init(slv_fb_t *fb) * the lvgl buffer (buf) into our real framebuffer. */ lv_display_t *disp = lv_display_create(fb->hres, fb->vres); + + switch (priv->bpp) { + case 16: + lv_display_set_color_format(disp, LV_COLOR_FORMAT_RGB565); + break; + case 24: + lv_display_set_color_format(disp, LV_COLOR_FORMAT_RGB888); + break; + case 32: + lv_display_set_color_format(disp, LV_COLOR_FORMAT_XRGB8888); + break; + default: + printf("Not supported color format (%d bits)\n", priv->bpp); + return -1; + } + lv_display_set_buffers(disp, buf, NULL, priv->fb_size, LV_DISPLAY_RENDER_MODE_DIRECT); diff --git a/usr/lib/slv/slv_fb.h b/usr/lib/slv/slv_fb.h index c38e6a8da..d4dc7768a 100644 --- a/usr/lib/slv/slv_fb.h +++ b/usr/lib/slv/slv_fb.h @@ -27,6 +27,7 @@ #define IOCTL_FB_VRES 2 #define IOCTL_FB_SIZE 3 #define IOCTL_FB_IS_REAL 4 +#define IOCTL_FB_BPP 5 #define FB_DEV "/dev/fb" From 2948bdf9fec3041d0902fd62070f1f9f0e1ccf3c Mon Sep 17 00:00:00 2001 From: Clement Dieperink Date: Mon, 11 May 2026 15:37:41 +0200 Subject: [PATCH 3/4] cleanup --- .gitignore | 2 ++ so3/soo/drivers/vinputfront/vinput.c | 2 +- so3/soo/include/soo/dev/vinput.h | 3 +-- 3 files changed, 4 insertions(+), 3 deletions(-) diff --git a/.gitignore b/.gitignore index 20896d4a5..c69db6ef6 100755 --- a/.gitignore +++ b/.gitignore @@ -42,8 +42,10 @@ agency/rootfs/target/** # except the followings: +#Don't ignore the ignore file ;-) !.gitignore !.github +#TaMPLate files for the man documentation !*.tmpl !.clang-format !buildroot/** diff --git a/so3/soo/drivers/vinputfront/vinput.c b/so3/soo/drivers/vinputfront/vinput.c index 1dd1c4f6c..49b53e478 100644 --- a/so3/soo/drivers/vinputfront/vinput.c +++ b/so3/soo/drivers/vinputfront/vinput.c @@ -16,7 +16,7 @@ * */ -#if 1 +#if 0 #define DEBUG #endif diff --git a/so3/soo/include/soo/dev/vinput.h b/so3/soo/include/soo/dev/vinput.h index a74105831..a37b693fc 100644 --- a/so3/soo/include/soo/dev/vinput.h +++ b/so3/soo/include/soo/dev/vinput.h @@ -1,6 +1,5 @@ /* - * Copyright (C) 2016-2018 Baptiste Delporte - * Copyright (C) 2018-2019 Daniel Rossier + * Copyright (C) 2026 Clément Dieperink * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as From eb0f2b80f8277283ef4627953a18c5a2afd3ab14 Mon Sep 17 00:00:00 2001 From: Clement Dieperink Date: Mon, 11 May 2026 16:07:20 +0200 Subject: [PATCH 4/4] clang-format --- so3/arch/arm64/rpi4_64/include/mach/ipamap.h | 1 - so3/soo/drivers/vinputfront/vinput.c | 15 ++++++++------- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/so3/arch/arm64/rpi4_64/include/mach/ipamap.h b/so3/arch/arm64/rpi4_64/include/mach/ipamap.h index c39efff6a..4dca8f0f7 100644 --- a/so3/arch/arm64/rpi4_64/include/mach/ipamap.h +++ b/so3/arch/arm64/rpi4_64/include/mach/ipamap.h @@ -30,7 +30,6 @@ ipamap_t agency_ipamap[] = { .size = 0x04000000, }, - /* VC memory*/ { .ipa_addr = 0x3ea00000, diff --git a/so3/soo/drivers/vinputfront/vinput.c b/so3/soo/drivers/vinputfront/vinput.c index 49b53e478..1b6a7f581 100644 --- a/so3/soo/drivers/vinputfront/vinput.c +++ b/so3/soo/drivers/vinputfront/vinput.c @@ -175,7 +175,8 @@ static void vinput_probe(struct vbus_device *vdev) /* Prepare the shared to page to be visible on the other end */ - vinput_priv->vinput.ring_ref = vbus_grant_ring(vdev, phys_to_pfn(virt_to_phys_pt((addr_t) vinput_priv->vinput.ring.sring))); + vinput_priv->vinput.ring_ref = + vbus_grant_ring(vdev, phys_to_pfn(virt_to_phys_pt((addr_t) vinput_priv->vinput.ring.sring))); vbus_transaction_start(&vbt); @@ -271,12 +272,12 @@ static void vinput_connected(struct vbus_device *vdev) } vdrvfront_t vinputdrv = { .probe = vinput_probe, - .reconfiguring = vinput_reconfiguring, - .shutdown = vinput_shutdown, - .closed = vinput_closed, - .suspend = vinput_suspend, - .resume = vinput_resume, - .connected = vinput_connected }; + .reconfiguring = vinput_reconfiguring, + .shutdown = vinput_shutdown, + .closed = vinput_closed, + .suspend = vinput_suspend, + .resume = vinput_resume, + .connected = vinput_connected }; static int vinput_init(dev_t *dev, int fdt_offset) {