Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
31 changes: 31 additions & 0 deletions kmsdrm/build_info.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
Ubuntu 22.04.5 LTS (GNU/Linux 5.15.167.4-microsoft-standard-WSL2 x86_64)

Download tool chain from https://github.com/trimui/toolchain_sdk_smartpro_s.git
File is sdk_tg5050_linux_v1.0.0.tgz
Unzip it at your linux home
tar -xvf sdk_tg5050_linux_v1.0.0.tgz
cd sdk_tg5050_linux_v1.0.0
git clone https://github.com/pcercuei/kmsgrab.git
cp kmsgrab_tsp.patch ./kmsgrab
cp export_tg5050.sh ./kmsgrab
(-->insert kmsgrab_tsp.patch and export_tg5050.sh to kmsgrab repo directory)
cd kmsgrab
patch -p1 < kmsgrab_tsp.patch
source ./export_tg5050.sh
mkdir -p build && cd build
cmake .. \
-DCMAKE_C_COMPILER=$CC \
-DCMAKE_CXX_COMPILER=$CXX \
-DCMAKE_C_FLAGS="--sysroot=$SYSROOT" \
-DCMAKE_EXE_LINKER_FLAGS="--sysroot=$SYSROOT" \
-DCMAKE_FIND_ROOT_PATH=$SYSROOT \
-DCMAKE_FIND_ROOT_PATH_MODE_PROGRAM=NEVER \
-DCMAKE_FIND_ROOT_PATH_MODE_LIBRARY=ONLY \
-DCMAKE_FIND_ROOT_PATH_MODE_INCLUDE=ONLY
make -j$(nproc)


I have already uploaded kmsgrab.c with the patch applied.
kmsgrab binary also included
/mnt/SDCARD/spruce/bin64/kmsgrab
Usage: kmsgrab <output.png>
30 changes: 30 additions & 0 deletions kmsdrm/export_tg5050.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
#!/bin/bash

# 1. Base SDK and Toolchain paths (use your sdk_path)
export SDK_PATH="/home/ark/sdk_tg5050_linux_v1.0.0"
export TOOLCHAIN_BIN="$SDK_PATH/host/opt/ext-toolchain/bin"
export CROSS_COMPILE="aarch64-none-linux-gnu-"

# 2. Verified Sysroot path
# Contains: /usr/lib/libc_nonshared.a and /usr/include/libdrm
export SYSROOT="$SDK_PATH/host/aarch64-buildroot-linux-gnu/sysroot"

# 3. Update PATH to include the cross-compiler
export PATH="$TOOLCHAIN_BIN:$PATH"

# 4. Standard Compiler variables
export CC="${CROSS_COMPILE}gcc"
export CXX="${CROSS_COMPILE}g++"

# 5. Configuration for CMake and Pkg-Config
# Using verified /usr/lib/pkgconfig directory
export PKG_CONFIG_PATH="$SYSROOT/usr/lib/pkgconfig"
export PKG_CONFIG_LIBDIR="$SYSROOT/usr/lib/pkgconfig"
export PKG_CONFIG_SYSROOT_DIR="$SYSROOT"

echo "-------------------------------------------------------"
echo "✅ TG5050 (A523) Verified Environment Loaded"
echo "SDK_PATH: $SDK_PATH"
echo "SYSROOT: $SYSROOT"
echo "CC: $CC"
echo "-------------------------------------------------------"
Binary file added kmsdrm/kmsgrab
Binary file not shown.
248 changes: 248 additions & 0 deletions kmsdrm/kmsgrab.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,248 @@
// SPDX-License-Identifier: GPL-2.0-only
/*
* KMS/DRM screenshot tool
*
* Copyright (c) 2021 Paul Cercueil <paul@crapouillou.net>
* Modified for A523 (TrimUI Smart Pro) support
*/

#include <drm.h>
#include <drm_fourcc.h>
#include <drm_mode.h>
#include <errno.h>
#include <fcntl.h>
#include <inttypes.h>
#include <png.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <sys/mman.h>
#include <unistd.h>
#include <xf86drm.h>
#include <xf86drmMode.h>

typedef struct {
uint8_t r, g, b;
} uint24_t;

static inline uint24_t rgb16_to_24(uint16_t px)
{
uint24_t pixel;

pixel.b = (px & 0x1f) << 3;
pixel.g = (px & 0x7e0) >> 3;
pixel.r = (px & 0xf800) >> 8;

return pixel;
}


static inline uint24_t rgb32_to_24(uint32_t px)
{
uint24_t pixel;

pixel.b = px & 0xff;
pixel.g = (px >> 8) & 0xff;
pixel.r = (px >> 16) & 0xff;

return pixel;
}


static inline void convert_to_24(drmModeFB *fb, uint24_t *to, void *from)
{
unsigned int len = fb->width * fb->height;

if (fb->bpp == 16) {
uint16_t *ptr = from;
while (len--)
*to++ = rgb16_to_24(*ptr++);
} else {
uint32_t *ptr = from;
while (len--)
*to++ = rgb32_to_24(*ptr++);
}
}

static int save_png(drmModeFB *fb, int prime_fd, const char *png_fn)
{
png_bytep *row_pointers;
png_structp png;
png_infop info;
FILE *pngfile;
void *buffer, *picture;
unsigned int i;
int ret;

picture = malloc(fb->width * fb->height * 4);
if (!picture)
return -ENOMEM;

/* Modified: MAP_SHARED is required for A523/TSP S */
buffer = mmap(NULL, (fb->bpp >> 3) * fb->width * fb->height,
PROT_READ, MAP_SHARED, prime_fd, 0);
if (buffer == MAP_FAILED) {
ret = -errno;
fprintf(stderr, "Unable to mmap prime buffer\n");
goto out_free_picture;
}

/* Drop privileges, to write PNG with user rights */
seteuid(getuid());

pngfile = fopen(png_fn, "w+");
if (!pngfile) {
ret = -errno;
goto out_unmap_buffer;
}

png = png_create_write_struct(PNG_LIBPNG_VER_STRING,
NULL, NULL, NULL);
if (!png) {
ret = -errno;
goto out_fclose;
}

info = png_create_info_struct(png);
if (!info) {
ret = -errno;
goto out_free_png;
}

png_init_io(png, pngfile);
png_set_IHDR(png, info, fb->width, fb->height, 8,
PNG_COLOR_TYPE_RGB,
PNG_INTERLACE_NONE,
PNG_COMPRESSION_TYPE_BASE,
PNG_FILTER_TYPE_BASE);
png_write_info(png, info);

// Convert the picture to a format that can be written into the PNG file (rgb888)
convert_to_24(fb, picture, buffer);

row_pointers = malloc(sizeof(*row_pointers) * fb->height);
if (!row_pointers) {
ret = -ENOMEM;
goto out_free_info;
}

// And save the final image
for (i = 0; i < fb->height; i++)
row_pointers[i] = (png_bytep)(picture + i * fb->width * 3);

png_write_image(png, row_pointers);
png_write_end(png, info);

ret = 0;

free(row_pointers);
out_free_info:
png_destroy_write_struct(NULL, &info);
out_free_png:
png_destroy_write_struct(&png, NULL);
out_fclose:
fclose(pngfile);
out_unmap_buffer:
munmap(buffer, (fb->bpp >> 3) * fb->width * fb->height);
out_free_picture:
free(picture);
return ret;
}

int main(int argc, char **argv)
{
int err, drm_fd, prime_fd, retval = EXIT_FAILURE;
unsigned int i, card;
uint32_t fb_id = 0, crtc_id = 0;
drmModePlaneRes *plane_res;
drmModePlane *plane;
drmModeFB *fb;
char buf[256];
uint64_t has_dumb;

if (argc < 2) {
printf("Usage: kmsgrab <output.png>\n");
goto out_return;
}

for (card = 0; card < 5; card++) {
snprintf(buf, sizeof(buf), "/dev/dri/card%u", card);

drm_fd = open(buf, O_RDWR | O_CLOEXEC);
if (drm_fd < 0)
continue;

if (drmGetCap(drm_fd, DRM_CAP_DUMB_BUFFER, &has_dumb) >= 0 &&
has_dumb)
break;

close(drm_fd);
}

if (card == 5) {
fprintf(stderr, "Could not find a valid DRM device.\n");
goto out_return;
}

drmSetClientCap(drm_fd, DRM_CLIENT_CAP_UNIVERSAL_PLANES, 1);

plane_res = drmModeGetPlaneResources(drm_fd);
if (!plane_res) {
fprintf(stderr, "Unable to get plane resources.\n");
goto out_close_fd;
}

for (i = 0; i < plane_res->count_planes; i++) {
plane = drmModeGetPlane(drm_fd, plane_res->planes[i]);
if (!plane)
continue;

fb_id = plane->fb_id;
crtc_id = plane->crtc_id;
drmModeFreePlane(plane);

/* Modified: Primary plane might not have a crtc_id on some planes */
if (fb_id != 0)
break;
}

if (fb_id == 0) {
fprintf(stderr, "No active framebuffers found on planes\n");
goto out_free_resources;
}

fb = drmModeGetFB(drm_fd, fb_id);
if (!fb) {
fprintf(stderr, "Failed to get framebuffer %"PRIu32": %s\n",
fb_id, strerror(errno));
goto out_free_resources;
}

err = drmPrimeHandleToFD(drm_fd, fb->handle, O_RDONLY, &prime_fd);
if (err < 0) {
fprintf(stderr, "Failed to retrieve prime handler: %s\n",
strerror(errno));
goto out_free_fb;
}

err = save_png(fb, prime_fd, argv[1]);
if (err < 0) {
fprintf(stderr, "Failed to take screenshot: %s\n",
strerror(-err));
goto out_close_prime_fd;
}

printf("Screenshot saved to %s (FB ID: %u, %ux%u)\n", argv[1], fb_id, fb->width, fb->height);
retval = EXIT_SUCCESS;

out_close_prime_fd:
close(prime_fd);
out_free_fb:
drmModeFreeFB(fb);
out_free_resources:
drmModeFreePlaneResources(plane_res);
out_close_fd:
close(drm_fd);
out_return:
return retval;
}
Loading