Compare commits

..

No commits in common. "71debd0be2555d5dd3afc45387e0e2de2f403e07" and "7597f17f9ecde32b8803e7d7ede9aa6387a78dbc" have entirely different histories.

24 changed files with 3524 additions and 64 deletions

2
.gitignore vendored
View File

@ -5,5 +5,5 @@ positions.txt
volume.txt
.claude/
audio/
docker-arm64/.build
docker/.build

View File

@ -7,11 +7,11 @@ This file provides guidance to Claude Code (claude.ai/code) when working with co
SDLamp2 is a simple SDL2-based audio player written in C, designed for a child to use. It plays long m4a/mp3 files (fairy tale cassette rips) with a cassette-player-like UI: rewind, stop, play, fast-forward, next tape. Inspired by Winamp.
See `docs/sdlamp2-fsd.md` for the full functional specification and changelog.
See `docs/TOOLCHAIN.md` for target device details and the arm64 Docker build container.
See `docs/TOOLCHAIN.md` for cross-compilation toolchain details and the aarch64 migration plan.
## Build and Run
**Dependencies:** SDL2, SDL2_image, FFmpeg libraries (libavformat, libavcodec, libavutil, libswresample). Installed via system package manager (native) or via apt inside the arm64 Docker container.
**Dependencies:** SDL2, SDL2_image, FFmpeg libraries (libavformat, libavcodec, libavutil, libswresample). Installed via system package manager (native) or into the Buildroot sysroot (cross-compile).
```sh
make # native build — uses pkg-config
@ -19,12 +19,10 @@ make clean # remove build artifacts
./build/sdlamp2 [audio_directory]
```
Building for the arm64 target device via the Docker container (from the `docker-arm64/` directory):
Cross-compilation inside the Docker toolchain container (where `CROSS_COMPILE` and `PREFIX` are set by the environment):
```sh
make build # one-shot: build sdlamp2 inside arm64 container
make shell # interactive shell inside the arm64 container
make clean # remove the Docker image
make # picks up CROSS_COMPILE and PREFIX automatically
```
The controls spritesheet (`controls.png`) is embedded in the binary. If an external `controls.png` exists in the current working directory it takes precedence, allowing custom skins. Audio directory defaults to cwd if not specified.

View File

@ -1,8 +0,0 @@
FROM ubuntu:22.04
ENV DEBIAN_FRONTEND=noninteractive
RUN apt-get update && apt-get install -y --no-install-recommends \
build-essential pkg-config \
libsdl2-dev libsdl2-image-dev \
libavformat-dev libavcodec-dev libavutil-dev libswresample-dev \
&& rm -rf /var/lib/apt/lists/*
WORKDIR /workspace

View File

@ -1,25 +0,0 @@
.PHONY: shell build clean
IMAGE_NAME = arm64-dev
PROJECT_DIR := $(shell cd .. && pwd)
CONTAINER_NAME = $(shell docker ps -f "ancestor=$(IMAGE_NAME)" --format "{{.Names}}")
.build: Dockerfile
docker build --platform linux/arm64 -t $(IMAGE_NAME) .
touch .build
ifeq ($(CONTAINER_NAME),)
shell: .build
docker run --platform linux/arm64 -it --rm -v "$(PROJECT_DIR)":/workspace $(IMAGE_NAME) /bin/bash
else
shell:
docker exec -it $(CONTAINER_NAME) /bin/bash
endif
build: .build
docker run --platform linux/arm64 --rm -v "$(PROJECT_DIR)":/workspace $(IMAGE_NAME) make
clean:
docker rmi $(IMAGE_NAME)
rm -f .build

42
docker/Dockerfile Normal file
View File

@ -0,0 +1,42 @@
FROM debian/eol:buster-slim
ENV DEBIAN_FRONTEND noninteractive
ENV TZ=Europe/Brussels
RUN ln -snf /usr/share/zoneinfo/$TZ /etc/localtime && echo $TZ > /etc/timezone
RUN apt-get -y update && apt-get -y install \
bc \
build-essential \
bzip2 \
bzr \
cmake \
cmake-curses-gui \
cpio \
device-tree-compiler \
git \
imagemagick \
libncurses5-dev \
locales \
make \
p7zip-full \
rsync \
sharutils \
scons \
tree \
unzip \
vim \
wget \
zip \
&& rm -rf /var/lib/apt/lists/*
RUN mkdir -p /root/workspace
WORKDIR /root
COPY support .
RUN ./build-toolchain.sh
RUN cat ./setup-env.sh >> .bashrc
VOLUME /root/workspace
WORKDIR /root/workspace
CMD ["/bin/bash"]

30
docker/Makefile Normal file
View File

@ -0,0 +1,30 @@
.PHONY: shell
.PHONY: clean
TOOLCHAIN_NAME=rg35xx-toolchain
WORKSPACE_DIR := $(shell pwd)/workspace
CONTAINER_NAME=$(shell docker ps -f "ancestor=$(TOOLCHAIN_NAME)" --format "{{.Names}}")
BOLD=$(shell tput bold)
NORM=$(shell tput sgr0)
.build: Dockerfile
$(info $(BOLD)Building $(TOOLCHAIN_NAME)...$(NORM))
mkdir -p ./workspace
docker build -t $(TOOLCHAIN_NAME) .
touch .build
ifeq ($(CONTAINER_NAME),)
shell: .build
$(info $(BOLD)Starting $(TOOLCHAIN_NAME)...$(NORM))
docker run -it --rm -v "$(WORKSPACE_DIR)":/root/workspace $(TOOLCHAIN_NAME) /bin/bash
else
shell:
$(info $(BOLD)Connecting to running $(TOOLCHAIN_NAME)...$(NORM))
docker exec -it $(CONTAINER_NAME) /bin/bash
endif
clean:
$(info $(BOLD)Removing $(TOOLCHAIN_NAME)...$(NORM))
docker rmi $(TOOLCHAIN_NAME)
rm -f .build

View File

@ -0,0 +1,41 @@
#!/bin/sh
BUILDROOT_VERSION=2017.11
set -xe
if [ -d ~/buildroot ]; then
rm -rf ~/buildroot
else
sed -i -e 's/# en_US.UTF-8 UTF-8/en_US.UTF-8 UTF-8/' /etc/locale.gen
locale-gen
fi
cd ~
BUILDROOT_NAME=buildroot-$BUILDROOT_VERSION
wget https://buildroot.org/downloads/$BUILDROOT_NAME.tar.gz
tar -xf ./$BUILDROOT_NAME.tar.gz
rm -f ./$BUILDROOT_NAME.tar.gz
mv ./$BUILDROOT_NAME ./buildroot
# patches for buildroot packages
cd ~/patches
for FILE in $(find . -type f -name "*.patch" 2>/dev/null); do
cp $FILE ~/buildroot/$FILE
done
cd ~/buildroot
# patches for buildroot itself
patch -p1 < ~/toolchain-expose-BR2_TOOLCHAIN_EXTRA_EXTERNAL_LIBS-for-all-toolchain-types-2017.11.1.diff
cp ~/rg35xx-buildroot-$BUILDROOT_VERSION.config ./.config
if [ -f ~/rg35xx-toolchain.tar.xz ]; then
tar -xf ~/rg35xx-toolchain.tar.xz -C /opt
else
export FORCE_UNSAFE_CONFIGURE=1
make oldconfig
make world
~/install-toolchain.sh
fi

41
docker/support/hwcap.h Normal file
View File

@ -0,0 +1,41 @@
/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */
#ifndef __ASMARM_HWCAP_H
#define __ASMARM_HWCAP_H
/*
* HWCAP flags - for elf_hwcap (in kernel) and AT_HWCAP
*/
#define HWCAP_SWP (1 << 0)
#define HWCAP_HALF (1 << 1)
#define HWCAP_THUMB (1 << 2)
#define HWCAP_26BIT (1 << 3) /* Play it safe */
#define HWCAP_FAST_MULT (1 << 4)
#define HWCAP_FPA (1 << 5)
#define HWCAP_VFP (1 << 6)
#define HWCAP_EDSP (1 << 7)
#define HWCAP_JAVA (1 << 8)
#define HWCAP_IWMMXT (1 << 9)
#define HWCAP_CRUNCH (1 << 10)
#define HWCAP_THUMBEE (1 << 11)
#define HWCAP_NEON (1 << 12)
#define HWCAP_VFPv3 (1 << 13)
#define HWCAP_VFPv3D16 (1 << 14) /* also set for VFPv4-D16 */
#define HWCAP_TLS (1 << 15)
#define HWCAP_VFPv4 (1 << 16)
#define HWCAP_IDIVA (1 << 17)
#define HWCAP_IDIVT (1 << 18)
#define HWCAP_VFPD32 (1 << 19) /* set if VFP has 32 regs (not 16) */
#define HWCAP_IDIV (HWCAP_IDIVA | HWCAP_IDIVT)
#define HWCAP_LPAE (1 << 20)
#define HWCAP_EVTSTRM (1 << 21)
/*
* HWCAP2 flags - for elf_hwcap2 (in kernel) and AT_HWCAP2
*/
#define HWCAP2_AES (1 << 0)
#define HWCAP2_PMULL (1 << 1)
#define HWCAP2_SHA1 (1 << 2)
#define HWCAP2_SHA2 (1 << 3)
#define HWCAP2_CRC32 (1 << 4)
#endif /* __ASMARM_HWCAP_H */

View File

@ -0,0 +1,12 @@
#!/bin/sh
mkdir -p /opt/rg35xx-toolchain
if [ -d /opt/rg35xx-toolchain/usr ]; then
rm -fr /opt/rg35xx-toolchain/usr
fi
cp -rf ~/buildroot/output/host/usr/ /opt/rg35xx-toolchain/
# this version of buildroot doesn't have relocate-sdk.sh yet so we bring our own
cp ~/relocate-sdk.sh /opt/rg35xx-toolchain/
cp ~/sdk-location /opt/rg35xx-toolchain/
cp ~/hwcap.h /opt/rg35xx-toolchain/usr/arm-buildroot-linux-gnueabihf/sysroot/usr/include/asm/
/opt/rg35xx-toolchain/relocate-sdk.sh

View File

@ -0,0 +1,3 @@
#!/bin/sh
cp ~/buildroot/output/images/rootfs.ext2 ~/workspace/rootfs.img

View File

@ -0,0 +1,7 @@
#!/bin/sh
cd /opt/
tar --xz -cvf rg35xx-toolchain.tar.xz rg35xx-toolchain/
mv rg35xx-toolchain.tar.xz ~/workspace/
printf "rg35xx-toolchain.tar.xz can be shared as a blob\nby placing in support before calling 'make shell'\n"

View File

@ -0,0 +1,33 @@
Subject: Workaround change in glibc
Temporary workaround to compile with glibc 2.28, which
deprecated some constants
Based on the workaround made for the tools/m4 package
--- a/lib/stdio-impl.h
+++ b/lib/stdio-impl.h
@@ -18,6 +18,12 @@
the same implementation of stdio extension API, except that some fields
have different naming conventions, or their access requires some casts. */
+/* Glibc 2.28 made _IO_IN_BACKUP private. For now, work around this
+ problem by defining it ourselves. FIXME: Do not rely on glibc
+ internals. */
+#if !defined _IO_IN_BACKUP && defined _IO_EOF_SEEN
+# define _IO_IN_BACKUP 0x100
+#endif
/* BSD stdio derived implementations. */
--- a/lib/fseterr.c
+++ b/lib/fseterr.c
@@ -29,7 +29,7 @@
/* Most systems provide FILE as a struct and the necessary bitmask in
<stdio.h>, because they need it for implementing getc() and putc() as
fast macros. */
-#if defined _IO_ftrylockfile || __GNU_LIBRARY__ == 1 /* GNU libc, BeOS, Haiku, Linux libc5 */
+#if defined _IO_EOF_SEEN || __GNU_LIBRARY__ == 1 /* GNU libc, BeOS, Haiku, Linux libc5 */
fp->_flags |= _IO_ERR_SEEN;
#elif defined __sferror || defined __DragonFly__ /* FreeBSD, NetBSD, OpenBSD, DragonFly, Mac OS X, Cygwin */
fp_->_flags |= __SERR;

View File

@ -0,0 +1,40 @@
This patch prevents a conflict with glibc
--- a/misc/create_inode.c
+++ b/misc/create_inode.c
@@ -392,7 +392,7 @@ static ssize_t my_pread(int fd, void *buf, size_t count, off_t offset)
}
#endif /* !defined HAVE_PREAD64 && !defined HAVE_PREAD */
-static errcode_t copy_file_range(ext2_filsys fs, int fd, ext2_file_t e2_file,
+static errcode_t copy_file_chunk(ext2_filsys fs, int fd, ext2_file_t e2_file,
off_t start, off_t end, char *buf,
char *zerobuf)
{
@@ -466,7 +466,7 @@ static errcode_t try_lseek_copy(ext2_filsys fs, int fd, struct stat *statbuf,
data_blk = data & ~(fs->blocksize - 1);
hole_blk = (hole + (fs->blocksize - 1)) & ~(fs->blocksize - 1);
- err = copy_file_range(fs, fd, e2_file, data_blk, hole_blk, buf,
+ err = copy_file_chunk(fs, fd, e2_file, data_blk, hole_blk, buf,
zerobuf);
if (err)
return err;
@@ -516,7 +516,7 @@ static errcode_t try_fiemap_copy(ext2_filsys fs, int fd, ext2_file_t e2_file,
}
for (i = 0, ext = ext_buf; i < fiemap_buf->fm_mapped_extents;
i++, ext++) {
- err = copy_file_range(fs, fd, e2_file, ext->fe_logical,
+ err = copy_file_chunk(fs, fd, e2_file, ext->fe_logical,
ext->fe_logical + ext->fe_length,
buf, zerobuf);
if (err)
@@ -569,7 +569,7 @@ static errcode_t copy_file(ext2_filsys fs, int fd, struct stat *statbuf,
goto out;
#endif
- err = copy_file_range(fs, fd, e2_file, 0, statbuf->st_size, buf,
+ err = copy_file_chunk(fs, fd, e2_file, 0, statbuf->st_size, buf,
zerobuf);
out:
ext2fs_free_mem(&zerobuf);

View File

@ -0,0 +1,131 @@
From c79aedf13fe693da0fc5c4ff727aed5bd43526dc Mon Sep 17 00:00:00 2001
From: Hutson Betts <hutson@hyper-expanse.net>
Date: Thu, 10 Dec 2020 21:13:54 -0600
Subject: [PATCH] glibc 2.28
diff --git a/lib/fflush.c b/lib/fflush.c
index ef2a7f1..787790d 100644
--- a/lib/fflush.c
+++ b/lib/fflush.c
@@ -33,7 +33,7 @@
#undef fflush
-#if defined _IO_ftrylockfile || __GNU_LIBRARY__ == 1 /* GNU libc, BeOS, Haiku, Linux libc5 */
+#if defined _IO_EOF_SEEN || __GNU_LIBRARY__ == 1 /* GNU libc, BeOS, Haiku, Linux libc5 */
/* Clear the stream's ungetc buffer, preserving the value of ftello (fp). */
static void
@@ -72,7 +72,7 @@ clear_ungetc_buffer (FILE *fp)
#endif
-#if ! (defined _IO_ftrylockfile || __GNU_LIBRARY__ == 1 /* GNU libc, BeOS, Haiku, Linux libc5 */)
+#if ! (defined _IO_EOF_SEEN || __GNU_LIBRARY__ == 1 /* GNU libc, BeOS, Haiku, Linux libc5 */)
# if (defined __sferror || defined __DragonFly__ || defined __ANDROID__) && defined __SNPT
/* FreeBSD, NetBSD, OpenBSD, DragonFly, Mac OS X, Cygwin, Android */
@@ -148,7 +148,7 @@ rpl_fflush (FILE *stream)
if (stream == NULL || ! freading (stream))
return fflush (stream);
-#if defined _IO_ftrylockfile || __GNU_LIBRARY__ == 1 /* GNU libc, BeOS, Haiku, Linux libc5 */
+#if defined _IO_EOF_SEEN || __GNU_LIBRARY__ == 1 /* GNU libc, BeOS, Haiku, Linux libc5 */
clear_ungetc_buffer_preserving_position (stream);
diff --git a/lib/fpending.c b/lib/fpending.c
index ce93604..9fe7ffb 100644
--- a/lib/fpending.c
+++ b/lib/fpending.c
@@ -32,7 +32,7 @@ __fpending (FILE *fp)
/* Most systems provide FILE as a struct and the necessary bitmask in
<stdio.h>, because they need it for implementing getc() and putc() as
fast macros. */
-#if defined _IO_ftrylockfile || __GNU_LIBRARY__ == 1 /* GNU libc, BeOS, Haiku, Linux libc5 */
+#if defined _IO_EOF_SEEN || __GNU_LIBRARY__ == 1 /* GNU libc, BeOS, Haiku, Linux libc5 */
return fp->_IO_write_ptr - fp->_IO_write_base;
#elif defined __sferror || defined __DragonFly__ || defined __ANDROID__
/* FreeBSD, NetBSD, OpenBSD, DragonFly, Mac OS X, Cygwin, Android */
diff --git a/lib/fpurge.c b/lib/fpurge.c
index 53ee68c..7cba3a3 100644
--- a/lib/fpurge.c
+++ b/lib/fpurge.c
@@ -62,7 +62,7 @@ fpurge (FILE *fp)
/* Most systems provide FILE as a struct and the necessary bitmask in
<stdio.h>, because they need it for implementing getc() and putc() as
fast macros. */
-# if defined _IO_ftrylockfile || __GNU_LIBRARY__ == 1 /* GNU libc, BeOS, Haiku, Linux libc5 */
+# if defined _IO_EOF_SEEN || __GNU_LIBRARY__ == 1 /* GNU libc, BeOS, Haiku, Linux libc5 */
fp->_IO_read_end = fp->_IO_read_ptr;
fp->_IO_write_ptr = fp->_IO_write_base;
/* Avoid memory leak when there is an active ungetc buffer. */
diff --git a/lib/freadahead.c b/lib/freadahead.c
index cfc969b..5e43e13 100644
--- a/lib/freadahead.c
+++ b/lib/freadahead.c
@@ -25,7 +25,7 @@
size_t
freadahead (FILE *fp)
{
-#if defined _IO_ftrylockfile || __GNU_LIBRARY__ == 1 /* GNU libc, BeOS, Haiku, Linux libc5 */
+#if defined _IO_EOF_SEEN || __GNU_LIBRARY__ == 1 /* GNU libc, BeOS, Haiku, Linux libc5 */
if (fp->_IO_write_ptr > fp->_IO_write_base)
return 0;
return (fp->_IO_read_end - fp->_IO_read_ptr)
diff --git a/lib/freading.c b/lib/freading.c
index 05cb0b8..f1da5b9 100644
--- a/lib/freading.c
+++ b/lib/freading.c
@@ -31,7 +31,7 @@ freading (FILE *fp)
/* Most systems provide FILE as a struct and the necessary bitmask in
<stdio.h>, because they need it for implementing getc() and putc() as
fast macros. */
-# if defined _IO_ftrylockfile || __GNU_LIBRARY__ == 1 /* GNU libc, BeOS, Haiku, Linux libc5 */
+# if defined _IO_EOF_SEEN || __GNU_LIBRARY__ == 1 /* GNU libc, BeOS, Haiku, Linux libc5 */
return ((fp->_flags & _IO_NO_WRITES) != 0
|| ((fp->_flags & (_IO_NO_READS | _IO_CURRENTLY_PUTTING)) == 0
&& fp->_IO_read_base != NULL));
diff --git a/lib/fseeko.c b/lib/fseeko.c
index 0c01c4f..0601619 100644
--- a/lib/fseeko.c
+++ b/lib/fseeko.c
@@ -47,7 +47,7 @@ fseeko (FILE *fp, off_t offset, int whence)
#endif
/* These tests are based on fpurge.c. */
-#if defined _IO_ftrylockfile || __GNU_LIBRARY__ == 1 /* GNU libc, BeOS, Haiku, Linux libc5 */
+#if defined _IO_EOF_SEEN || __GNU_LIBRARY__ == 1 /* GNU libc, BeOS, Haiku, Linux libc5 */
if (fp->_IO_read_end == fp->_IO_read_ptr
&& fp->_IO_write_ptr == fp->_IO_write_base
&& fp->_IO_save_base == NULL)
@@ -123,7 +123,7 @@ fseeko (FILE *fp, off_t offset, int whence)
return -1;
}
-#if defined _IO_ftrylockfile || __GNU_LIBRARY__ == 1 /* GNU libc, BeOS, Haiku, Linux libc5 */
+#if defined _IO_EOF_SEEN || __GNU_LIBRARY__ == 1 /* GNU libc, BeOS, Haiku, Linux libc5 */
fp->_flags &= ~_IO_EOF_SEEN;
fp->_offset = pos;
#elif defined __sferror || defined __DragonFly__ || defined __ANDROID__
diff --git a/lib/stdio-impl.h b/lib/stdio-impl.h
index 766d693..75fe3ad 100644
--- a/lib/stdio-impl.h
+++ b/lib/stdio-impl.h
@@ -18,6 +18,12 @@
the same implementation of stdio extension API, except that some fields
have different naming conventions, or their access requires some casts. */
+/* Glibc 2.28 made _IO_IN_BACKUP private. For now, work around this
+ problem by defining it ourselves. FIXME: Do not rely on glibc
+ internals. */
+#if !defined _IO_IN_BACKUP && defined _IO_EOF_SEEN
+# define _IO_IN_BACKUP 0x100
+#endif
/* BSD stdio derived implementations. */
--
2.25.1

View File

@ -0,0 +1,99 @@
diff --git forkSrcPrefix/src/video/fbcon/SDL_fbkeys.h forkDstPrefix/src/video/fbcon/SDL_fbkeys.h
index 2b01b6b2e3588426e50dbf109e09e0fdb8755091..4acd13df4302185d27964859a58f8b09c25f13f3 100644
--- forkSrcPrefix/src/video/fbcon/SDL_fbkeys.h
+++ forkDstPrefix/src/video/fbcon/SDL_fbkeys.h
@@ -114,6 +114,15 @@
#define SCANCODE_F11 87
#define SCANCODE_F12 88
+/* RG35XX */
+#define SCANCODE_KATAKANA 90
+#define SCANCODE_HIRAGANA 91
+#define SCANCODE_HENKAN 92
+#define SCANCODE_KATAKANAHIRAGANA 93
+#define SCANCODE_MUHENKAN 94
+#define SCANCODE_KPJPCOMMA 95
+#define SCANCODE_POWER 116
+
#define SCANCODE_KEYPADENTER 96
#define SCANCODE_RIGHTCONTROL 97
#define SCANCODE_CONTROL 97
diff --git forkSrcPrefix/include/SDL_keysym.h forkDstPrefix/include/SDL_keysym.h
index f2ad12b81ef5725e3d975c9ad3a775fa50aa6cb6..7c348322a4d0434f4cd7349fdbd62026d4e65911 100644
--- forkSrcPrefix/include/SDL_keysym.h
+++ forkDstPrefix/include/SDL_keysym.h
@@ -296,6 +296,19 @@ typedef enum {
SDLK_UNDO = 322, /**< Atari keyboard has Undo */
/*@}*/
+ /** @name RG35XX keys */
+ /*@{*/
+ SDLK_KATAKANA = 323,
+ SDLK_HIRAGANA = 324,
+ SDLK_HENKAN = 325,
+ SDLK_KATAKANAHIRAGANA = 326,
+ SDLK_MUHENKAN = 327,
+ SDLK_KP_JPCOMMA = 328,
+ SDLK_KP_SLASH = 329,
+ SDLK_CURSORBLOCKUP = 330,
+ SDLK_CURSORBLOCKDOWN = 331,
+ /*@}*/
+
/* Add any other keys here */
SDLK_LAST
diff --git forkSrcPrefix/src/video/fbcon/SDL_fbevents.c forkDstPrefix/src/video/fbcon/SDL_fbevents.c
index 5e369a4a89c3157206abed1f4c4b8e27aef17024..c15d1b85b7f06757b24fb7f17dc73e6bab1c2148 100644
--- forkSrcPrefix/src/video/fbcon/SDL_fbevents.c
+++ forkDstPrefix/src/video/fbcon/SDL_fbevents.c
@@ -1133,6 +1133,41 @@ void FB_InitOSKeymap(_THIS)
case 127:
keymap[i] = SDLK_MENU;
break;
+
+ /* RG35XX */
+ case SCANCODE_KATAKANA:
+ keymap[i] = SDLK_KATAKANA;
+ break;
+ case SCANCODE_HIRAGANA:
+ keymap[i] = SDLK_HIRAGANA;
+ break;
+ case SCANCODE_HENKAN:
+ keymap[i] = SDLK_HENKAN;
+ break;
+ case SCANCODE_KATAKANAHIRAGANA:
+ keymap[i] = SDLK_KATAKANAHIRAGANA;
+ break;
+ case SCANCODE_MUHENKAN:
+ keymap[i] = SDLK_MUHENKAN;
+ break;
+ case SCANCODE_KPJPCOMMA:
+ keymap[i] = SDLK_KP_JPCOMMA;
+ break;
+ case SCANCODE_KEYPADENTER:
+ keymap[i] = SDLK_KP_ENTER;
+ break;
+ case SCANCODE_CURSORBLOCKUP:
+ keymap[i] = SDLK_CURSORBLOCKUP;
+ break;
+ case SCANCODE_CURSORBLOCKDOWN:
+ keymap[i] = SDLK_CURSORBLOCKDOWN;
+ break;
+ case SCANCODE_POWER: // this doesn't stick so we override below
+ keymap[i] = SDLK_POWER; // leaving this in just in case
+ break;
+
+
+
/* this should take care of all standard ascii keys */
default:
keymap[i] = KVAL(vga_keymap[0][i]);
@@ -1208,6 +1243,8 @@ void FB_InitOSKeymap(_THIS)
default: break;
}
}
+
+ keymap[116] = SDLK_POWER; // requires hard override for some reason
}
static SDL_keysym *TranslateKey(int scancode, SDL_keysym *keysym)

View File

@ -0,0 +1,35 @@
--- a/src/video/fbcon/SDL_fbvideo.c
+++ b/src/video/fbcon/SDL_fbvideo.c
@@ -1907,15 +1907,12 @@
static void FB_VideoQuit(_THIS)
{
int i, j;
+ const char *dontClearPixels = SDL_getenv("SDL_FBCON_DONT_CLEAR");
if ( this->screen ) {
- /* Clear screen and tell SDL not to free the pixels */
-
- const char *dontClearPixels = SDL_getenv("SDL_FBCON_DONT_CLEAR");
-
/* If the framebuffer is not to be cleared, make sure that we won't
* display the previous frame when disabling double buffering. */
- if ( dontClearPixels && flip_page == 0 ) {
+ if ( dontClearPixels && (this->screen->flags & SDL_DOUBLEBUF) && flip_page == 0 ) {
SDL_memcpy(flip_address[0], flip_address[1], this->screen->pitch * this->screen->h);
}
@@ -1969,7 +1966,13 @@
/* Restore the original video mode and palette */
if ( FB_InGraphicsMode(this) ) {
- FB_RestorePalette(this);
+ if (dontClearPixels) {
+ /* Restore only panning, keep current mode */
+ ioctl(console_fd, FBIOGET_VSCREENINFO, &saved_vinfo);
+ saved_vinfo.yoffset = saved_vinfo.xoffset = 0;
+ } else {
+ FB_RestorePalette(this);
+ }
ioctl(console_fd, FBIOPUT_VSCREENINFO, &saved_vinfo);
}

47
docker/support/relocate-sdk.sh Executable file
View File

@ -0,0 +1,47 @@
#!/bin/sh
#
if [ "$#" -ne 0 ]; then
echo "Run this script to relocate the buildroot SDK at that location"
exit 1
fi
FILEPATH="$(readlink -f "$0")"
NEWPATH="$(dirname "${FILEPATH}")"
cd "${NEWPATH}"
LOCFILE="sdk-location"
if [ ! -r "${LOCFILE}" ]; then
echo "Previous location of the buildroot SDK not found!"
exit 1
fi
OLDPATH="$(cat "${LOCFILE}")"
if [ "${NEWPATH}" = "${OLDPATH}" ]; then
echo "This buildroot SDK has already been relocated!"
exit 0
fi
# Check if the path substitution does work properly, e.g. a tree
# "/a/b/c" copied into "/a/b/c/a/b/c/" would not be allowed.
newpath="$(sed -e "s|${OLDPATH}|${NEWPATH}|g" "${LOCFILE}")"
if [ "${NEWPATH}" != "${newpath}" ]; then
echo "Something went wrong with substituting the path!"
echo "Please choose another location for your SDK!"
exit 1
fi
echo "Relocating the buildroot SDK from ${OLDPATH} to ${NEWPATH} ..."
# Make sure file uses the right language
export LC_ALL=C
# Replace the old path with the new one in all text files
grep -lr "${OLDPATH}" . | while read -r FILE ; do
if file -b --mime-type "${FILE}" | grep -q '^text/' && [ "${FILE}" != "${LOCFILE}" ]
then
sed -i "s|${OLDPATH}|${NEWPATH}|g" "${FILE}"
fi
done
# At the very end, we update the location file to not break the
# SDK if this script gets interruted.
sed -i "s|${OLDPATH}|${NEWPATH}|g" ${LOCFILE}

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1 @@
/root/buildroot/output/host

View File

@ -0,0 +1,4 @@
export PATH="/opt/rg35xx-toolchain/usr/bin:${PATH}:/opt/rg35xx-toolchain/usr/arm-buildroot-linux-gnueabihf/sysroot/bin"
export CROSS_COMPILE=/opt/rg35xx-toolchain/usr/bin/arm-buildroot-linux-gnueabihf-
export PREFIX=/opt/rg35xx-toolchain/usr/arm-buildroot-linux-gnueabihf/sysroot/usr
export UNION_PLATFORM=rg35xx

View File

@ -0,0 +1,89 @@
diff --git a/Config.in.legacy b/Config.in.legacy
index d4f3d04062..b3086300e6 100644
--- a/Config.in.legacy
+++ b/Config.in.legacy
@@ -147,6 +147,17 @@ endif
comment "Legacy options removed in 2017.11"
+config BR2_TOOLCHAIN_EXTRA_EXTERNAL_LIBS
+ string "toolchain-external extra libs option has been renamed"
+ help
+ The option BR2_TOOLCHAIN_EXTRA_EXTERNAL_LIBS has
+ been renamed to BR2_TOOLCHAIN_EXTRA_LIBS.
+
+config BR2_TOOLCHAIN_EXTRA_EXTERNAL_LIBS_WRAP
+ bool
+ default y if BR2_TOOLCHAIN_EXTRA_EXTERNAL_LIBS != ""
+ select BR2_LEGACY
+
config BR2_PACKAGE_RFKILL
bool "rfkill package removed"
select BR2_LEGACY
diff --git a/package/gcc/gcc-final/gcc-final.mk b/package/gcc/gcc-final/gcc-final.mk
index 30fb87856c..24d034b720 100644
--- a/package/gcc/gcc-final/gcc-final.mk
+++ b/package/gcc/gcc-final/gcc-final.mk
@@ -187,6 +187,8 @@ ifeq ($(BR2_GCC_ENABLE_OPENMP),y)
HOST_GCC_FINAL_USR_LIBS += libgomp
endif
+HOST_GCC_FINAL_USR_LIBS += $(call qstrip,$(BR2_TOOLCHAIN_EXTRA_LIBS))
+
ifneq ($(HOST_GCC_FINAL_USR_LIBS),)
define HOST_GCC_FINAL_INSTALL_STATIC_LIBS
for i in $(HOST_GCC_FINAL_USR_LIBS) ; do \
diff --git a/toolchain/Config.in b/toolchain/Config.in
index c9aa95985f..8f990cacb9 100644
--- a/toolchain/toolchain-common.in
+++ b/toolchain/toolchain-common.in
@@ -82,6 +82,19 @@ config BR2_TOOLCHAIN_GLIBC_GCONV_LIBS_LIST
Note: the full set of gconv libs are ~8MiB (on ARM).
+config BR2_TOOLCHAIN_EXTRA_LIBS
+ string "Extra toolchain libraries to be copied to target"
+ default ""
+ help
+ If your toolchain provides extra libraries that need to be
+ copied to the target filesystem, enter them here, separated
+ by spaces.
+
+ NOTE: The library name should not include a suffix or wildcard.
+
+ Examples where this can be useful is for adding debug libraries
+ to the target like the GCC libsanitizer (libasan/liblsan/...).
+
# This boolean is true if the toolchain provides a built-in full
# featured gettext implementation (glibc), and false if only a stub
# gettext implementation is provided (uclibc, musl)
diff --git a/toolchain/toolchain-external/pkg-toolchain-external.mk b/toolchain/toolchain-external/pkg-toolchain-external.mk
index 5147da0104..e339773a96 100644
--- a/toolchain/toolchain-external/pkg-toolchain-external.mk
+++ b/toolchain/toolchain-external/pkg-toolchain-external.mk
@@ -156,7 +156,7 @@ ifeq ($(BR2_TOOLCHAIN_HAS_DLANG),y)
TOOLCHAIN_EXTERNAL_LIBS += libgdruntime.so* libgphobos.so*
endif
-TOOLCHAIN_EXTERNAL_LIBS += $(call qstrip,$(BR2_TOOLCHAIN_EXTRA_EXTERNAL_LIBS))
+TOOLCHAIN_EXTERNAL_LIBS += $(call qstrip,$(BR2_TOOLCHAIN_EXTRA_LIBS))
#
diff --git a/toolchain/toolchain-external/toolchain-external-custom/Config.in.options b/toolchain/toolchain-external/toolchain-external-custom/Config.in.options
index a36747f490..fd95f8201b 100644
--- a/toolchain/toolchain-external/toolchain-external-custom/Config.in.options
+++ b/toolchain/toolchain-external/toolchain-external-custom/Config.in.options
@@ -438,12 +438,4 @@ config BR2_TOOLCHAIN_EXTERNAL_OPENMP
support. If you don't know, leave the default value,
Buildroot will tell you if it's correct or not.
-config BR2_TOOLCHAIN_EXTRA_EXTERNAL_LIBS
- string "Extra toolchain libraries to be copied to target"
- help
- If your external toolchain provides extra libraries that
- need to be copied to the target filesystem, enter them
- here, separated by spaces. They will be copied to the
- target's /lib directory.
-
endif

1
docker/workspace Symbolic link
View File

@ -0,0 +1 @@
../

View File

@ -1,6 +1,6 @@
# Cross-Compilation Toolchain
This document describes the target device and the arm64 Docker build container used to produce binaries for it.
This document describes the current Docker/Buildroot cross-compilation toolchain, the architecture mismatch with the target device, and possible approaches to fix it.
## Target Device
@ -39,35 +39,175 @@ All required shared libraries are pre-installed. Most are at `/usr/lib/`, some a
- A native aarch64 compile (e.g. inside an arm64 Docker container) produces working binaries
- Must link against glibc ≤ 2.35 (use GCC ≤ 12 to avoid GLIBCXX version mismatches)
## Build Container
## Current Toolchain Architecture
The `docker-arm64/` directory contains a Docker setup that runs an arm64 Ubuntu 22.04 container via QEMU user-mode emulation. This matches the target device exactly — same distro, same glibc 2.35, same library versions. The project's native `make` (using `pkg-config`) works as-is inside the container, no cross-compilation flags needed.
### Pipeline Overview
### Prerequisites
QEMU binfmt handlers must be registered on the host (one-time setup, persists across reboots):
The toolchain is built via a Docker container defined in `docker/`:
1. **`docker/Dockerfile`** — Debian Buster (EOL) base image, installs build dependencies (bc, build-essential, cmake, git, etc.), copies support scripts, runs `build-toolchain.sh`, sources `setup-env.sh` in `.bashrc`
2. **`docker/support/build-toolchain.sh`** — Downloads Buildroot 2017.11, applies patches, loads `rg35xx-buildroot-2017.11.config`, runs `make world`. If a pre-built `rg35xx-toolchain.tar.xz` exists, extracts that instead of rebuilding.
3. **`docker/support/install-toolchain.sh`** — Copies host tools from `buildroot/output/host/usr/` to `/opt/rg35xx-toolchain/usr/`, copies `hwcap.h` into the sysroot, runs `relocate-sdk.sh` to fix embedded paths.
4. **`docker/support/setup-env.sh`** — Sets environment variables:
```sh
docker run --privileged --rm tonistiigi/binfmt --install arm64
export PATH="/opt/rg35xx-toolchain/usr/bin:${PATH}:/opt/rg35xx-toolchain/usr/arm-buildroot-linux-gnueabihf/sysroot/bin"
export CROSS_COMPILE=/opt/rg35xx-toolchain/usr/bin/arm-buildroot-linux-gnueabihf-
export PREFIX=/opt/rg35xx-toolchain/usr/arm-buildroot-linux-gnueabihf/sysroot/usr
export UNION_PLATFORM=rg35xx
```
5. **`docker/support/package-toolchain.sh`** — Archives `/opt/rg35xx-toolchain` as `rg35xx-toolchain.tar.xz` for caching.
6. **`docker/support/relocate-sdk.sh`** — Rewrites hardcoded paths in SDK text files so the toolchain can live at a different filesystem location.
7. **`docker/Makefile`** — `make shell` builds the Docker image (tag `rg35xx-toolchain`) and drops into an interactive bash shell with `./workspace` mounted at `/root/workspace`.
### How the Main Makefile Uses It
The project `Makefile` detects `PREFIX` to switch modes:
- **Cross-compile** (PREFIX set): uses `-I$(PREFIX)/include` and `-L$(PREFIX)/lib` directly.
- **Native** (no PREFIX): uses `pkg-config` to find SDL2/FFmpeg.
`CROSS_COMPILE` is prepended to `gcc` to select the cross-compiler (e.g. `arm-buildroot-linux-gnueabihf-gcc`).
## The Problem
The Buildroot config targets **32-bit ARM Cortex-A9** but the Anbernic RG35XX runs a **64-bit aarch64 userland**.
The cross-compiled binary is `ELF 32-bit LSB executable, ARM, EABI5` while the device only has 64-bit aarch64 shared libraries. The binary cannot run — the dynamic linker and every `.so` it needs are the wrong architecture.
Key mismatched settings in the config:
| Setting | Current Value | Needed |
|---------|--------------|--------|
| `BR2_arm` | `y` (32-bit ARM) | `BR2_aarch64=y` |
| `BR2_cortex_a9` | `y` | Cortex-A53 or similar |
| `BR2_ARM_EABIHF` | `y` | LP64 ABI |
| `BR2_GCC_TARGET_ABI` | `aapcs-linux` | `lp64` |
| `BR2_GCC_TARGET_CPU` | `cortex-a9` | `cortex-a53` |
| `BR2_GCC_TARGET_FPU` | `neon` | (implicit in AArch64) |
| Sysroot triple | `arm-buildroot-linux-gnueabihf` | `aarch64-buildroot-linux-gnu` |
## Buildroot Config Details
**File:** `docker/support/rg35xx-buildroot-2017.11.config`
### Architecture
```
BR2_arm=y
BR2_cortex_a9=y
BR2_ARM_EABIHF=y
BR2_ARM_FPU_NEON=y
BR2_ARM_INSTRUCTIONS_THUMB2=y
```
### Usage
### Toolchain Versions
From the `docker-arm64/` directory:
| Component | Version |
|-----------|---------|
| Buildroot | 2017.11 |
| GCC | 7.2.0 (`BR2_GCC_VERSION_7_X`) |
| Binutils | 2.28.1 (`BR2_BINUTILS_VERSION_2_28_X`) |
| Kernel headers | 3.10.108 (`BR2_KERNEL_HEADERS_3_10`) |
| glibc | 2.28 (`BR2_TOOLCHAIN_BUILDROOT_GLIBC`) |
```sh
make build # one-shot: build sdlamp2 inside the container
make shell # interactive bash shell for development
make clean # remove the Docker image
### Packages Enabled
- **FFmpeg** — all encoders, decoders, muxers, demuxers, parsers, protocols, filters; nonfree codecs enabled
- **SDL2** — with KMS/DRM support, SDL2_image (PNG), SDL2_mixer, SDL2_net, SDL2_TTF
- **SDL 1.2** (legacy) — with framebuffer backend, SDL_image, SDL_TTF
- **ALSA** — PCM, mixer, raw MIDI, HWDEP, sequencer plugins
- **Graphics** — FreeType, libjpeg (SIMD), libpng, libdrm, zlib
- **Utilities** — evtest, tree
### Other Settings
- Optimization: size (`BR2_OPTIMIZE_S`)
- LTO and OpenMP enabled
- No stack smashing protection (`BR2_SSP_NONE`)
- Shared libraries only (`BR2_SHARED_LIBS`)
- Extra libs: libasan (`BR2_TOOLCHAIN_EXTRA_LIBS="libasan"`)
## Patches Applied
All patches live in `docker/support/patches/`.
### glibc 2.28 Compatibility Fixes
Three packages fail to build against glibc 2.28 because `_IO_ftrylockfile` was removed from the private API:
- **bison** (`package/bison/110-glibc-change-work-around.patch`) — replaces `_IO_ftrylockfile` checks with `_IO_EOF_SEEN`, adds `_IO_IN_BACKUP` macro
- **m4** (`package/m4/000-fix-fseeko.patch`) — same pattern across fflush.c, fpending.c, fpurge.c, freadahead.c, freading.c, fseeko.c, stdio-impl.h
- **e2fsprogs** (`package/e2fsprogs/000-fix-gcc-conflict.patch`) — renames `copy_file_range()` to `copy_file_chunk()` to avoid conflict with the new glibc function of the same name
### SDL 1.2 RG35XX Patches
- **`package/sdl/0003-rg35xx-sdlk-additions.patch`** — adds 9 RG35XX-specific scancodes and key mappings (KATAKANA, HIRAGANA, HENKAN, POWER, etc.) to SDL 1.2's framebuffer input driver. **Not relevant for SDL2.**
- **`package/sdl/0004-modernize-SDL_FBCON_DONT_CLEAR.patch`** — changes framebuffer clearing behavior: skips palette restoration and pixel clearing when `dontClearPixels` is set or `SDL_DOUBLEBUF` is used. **Not relevant for SDL2.**
### Buildroot Framework Patch
- **`toolchain-expose-BR2_TOOLCHAIN_EXTRA_EXTERNAL_LIBS-for-all-toolchain-types-2017.11.1.diff`** — backports `BR2_TOOLCHAIN_EXTRA_LIBS` config option so it works with the internal Buildroot toolchain (not just external). Required for the `libasan` extra lib.
## Possible Approaches
> **Update (2026-02):** Now that we've inspected the device (see [Target Device](#target-device)), approach A is confirmed to work — a native arm64 Docker container build produces binaries that run on the device with no issues. The Buildroot toolchain is unnecessary since all required shared libraries are already present on the device. Approaches B and C are kept below for historical reference.
### A: Native arm64 Docker Container Build (Confirmed Working)
Use `apt` with `dpkg --add-architecture arm64` inside a Debian Docker container to install aarch64 cross-compiler and libraries directly from Debian repos.
**Pros:**
- Modern toolchain (GCC 12+, recent glibc, recent FFmpeg/SDL2)
- No Buildroot config to maintain, no patches needed
- Fast setup — apt install instead of multi-hour Buildroot build
- Libraries match what's on the device (Debian-based firmware)
**Cons:**
- Library versions must match the device's firmware (or ship them)
- Less control over exact build options
**Outline:**
```dockerfile
FROM debian:bookworm
RUN dpkg --add-architecture arm64 && apt-get update && \
apt-get install -y gcc-aarch64-linux-gnu \
libsdl2-dev:arm64 libsdl2-image-dev:arm64 \
libavformat-dev:arm64 libavcodec-dev:arm64 \
libavutil-dev:arm64 libswresample-dev:arm64
```
The container mounts the project root at `/workspace`. Output binary is `build/sdlamp2` (`ELF 64-bit ARM aarch64`).
### B: Fix Buildroot Config for aarch64
### Image Contents
Stay with Buildroot but update the defconfig to target aarch64 instead of ARM.
- **Base:** `ubuntu:22.04` (arm64)
- **Build tools:** `build-essential`, `pkg-config`
- **SDL2:** `libsdl2-dev`, `libsdl2-image-dev`
- **FFmpeg:** `libavformat-dev`, `libavcodec-dev`, `libavutil-dev`, `libswresample-dev`
**Pros:**
- Minimal conceptual change — same pipeline, just different arch settings
- Full control over every library version
The image is tagged `arm64-dev` and is generic enough to reuse for other projects targeting the same device.
**Cons:**
- Buildroot 2017.11 is ancient and may not have good aarch64 support
- Would likely need to upgrade Buildroot to a modern release (2024.x)
- Upgrading Buildroot may break existing patches or require new ones
- Multi-hour rebuild from scratch
- Still maintaining a custom Buildroot config long-term
**Key config changes needed:**
```
BR2_aarch64=y
# Remove all BR2_arm, BR2_cortex_a9, BR2_ARM_* settings
# Update kernel headers to match device
```
### C: Skip Docker, Cross-Compile on Host Directly
Install `aarch64-linux-gnu-gcc` and aarch64 libraries on the host system (e.g. Arch Linux) without Docker.
**Pros:**
- Simplest setup — just `pacman -S aarch64-linux-gnu-gcc` and aarch64 libs
- No Docker overhead
- Fast iteration
**Cons:**
- Not reproducible across machines without documenting exact packages
- Harder to match device library versions
- Host distro package availability varies (Arch has good cross-compile support, others may not)

View File

@ -43,10 +43,6 @@ This document specifies the functional requirements for an SDL2 based media play
## 6. Changelog
### 2026-02-13 — arm64 Docker build container
- **New build container**: Replaced the broken Buildroot cross-compilation toolchain (`docker/`) with an arm64 Ubuntu 22.04 Docker container (`docker-arm64/`). Runs via QEMU user-mode emulation on x86 hosts and matches the target device exactly (same distro, same glibc, same library versions). The project's native `make` works as-is inside the container — no cross-compilation flags needed.
### 2026-02-13 — Replace build scripts with Makefile
- **Makefile**: Replaced `build.sh` (macOS) and `build_aarch64.sh` (Linux ARM) with a single `Makefile`. Native builds use `pkg-config` to resolve SDL2 and FFmpeg flags; cross-compilation uses `CROSS_COMPILE` and `PREFIX` environment variables set by the Docker/Buildroot toolchain.