From 25d0643f6010f38068ba0a1b4514c9e1bc5bbdc3 Mon Sep 17 00:00:00 2001 From: wakeboxer <75230324+ljhmd0825@users.noreply.github.com> Date: Thu, 5 Feb 2026 10:48:46 +0900 Subject: [PATCH] Screenshot tool for SmartProS It might work on other 64-bit devices too... --- kmsdrm/build_info.txt | 31 +++++ kmsdrm/export_tg5050.sh | 30 +++++ kmsdrm/kmsgrab | Bin 0 -> 25560 bytes kmsdrm/kmsgrab.c | 248 +++++++++++++++++++++++++++++++++++++++ kmsdrm/kmsgrab_tsp.patch | 125 ++++++++++++++++++++ 5 files changed, 434 insertions(+) create mode 100644 kmsdrm/build_info.txt create mode 100644 kmsdrm/export_tg5050.sh create mode 100644 kmsdrm/kmsgrab create mode 100644 kmsdrm/kmsgrab.c create mode 100644 kmsdrm/kmsgrab_tsp.patch diff --git a/kmsdrm/build_info.txt b/kmsdrm/build_info.txt new file mode 100644 index 0000000..f6a5f4f --- /dev/null +++ b/kmsdrm/build_info.txt @@ -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 diff --git a/kmsdrm/export_tg5050.sh b/kmsdrm/export_tg5050.sh new file mode 100644 index 0000000..c22de6d --- /dev/null +++ b/kmsdrm/export_tg5050.sh @@ -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 "-------------------------------------------------------" \ No newline at end of file diff --git a/kmsdrm/kmsgrab b/kmsdrm/kmsgrab new file mode 100644 index 0000000000000000000000000000000000000000..603ee29d1bff8e47bedde83381f0344ad89979e6 GIT binary patch literal 25560 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 + * Modified for A523 (TrimUI Smart Pro) support + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +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 \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; +} diff --git a/kmsdrm/kmsgrab_tsp.patch b/kmsdrm/kmsgrab_tsp.patch new file mode 100644 index 0000000..816158b --- /dev/null +++ b/kmsdrm/kmsgrab_tsp.patch @@ -0,0 +1,125 @@ +diff --git a/kmsgrab.c b/kmsgrab.c +index 596baac..82e2df9 100644 +--- a/kmsgrab.c ++++ b/kmsgrab.c +@@ -3,6 +3,7 @@ + * KMS/DRM screenshot tool + * + * Copyright (c) 2021 Paul Cercueil ++ * Modified for A523 (TrimUI Smart Pro) support + */ + + #include +@@ -77,8 +78,9 @@ static int save_png(drmModeFB *fb, int prime_fd, const char *png_fn) + 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_PRIVATE, prime_fd, 0); ++ PROT_READ, MAP_SHARED, prime_fd, 0); + if (buffer == MAP_FAILED) { + ret = -errno; + fprintf(stderr, "Unable to mmap prime buffer\n"); +@@ -126,7 +128,7 @@ static int save_png(drmModeFB *fb, int prime_fd, const char *png_fn) + + // And save the final image + for (i = 0; i < fb->height; i++) +- row_pointers[i] = picture + i * fb->width * 3; ++ row_pointers[i] = (png_bytep)(picture + i * fb->width * 3); + + png_write_image(png, row_pointers); + png_write_end(png, info); +@@ -151,7 +153,7 @@ int main(int argc, char **argv) + { + int err, drm_fd, prime_fd, retval = EXIT_FAILURE; + unsigned int i, card; +- uint32_t fb_id, crtc_id; ++ uint32_t fb_id = 0, crtc_id = 0; + drmModePlaneRes *plane_res; + drmModePlane *plane; + drmModeFB *fb; +@@ -163,14 +165,12 @@ int main(int argc, char **argv) + goto out_return; + } + +- for (card = 0; ; card++) { ++ 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) { +- fprintf(stderr, "Could not open KMS/DRM device.\n"); +- goto out_return; +- } ++ if (drm_fd < 0) ++ continue; + + if (drmGetCap(drm_fd, DRM_CAP_DUMB_BUFFER, &has_dumb) >= 0 && + has_dumb) +@@ -179,21 +179,12 @@ int main(int argc, char **argv) + close(drm_fd); + } + +- drm_fd = open(buf, O_RDWR | O_CLOEXEC); +- if (drm_fd < 0) { +- fprintf(stderr, "Could not open KMS/DRM device.\n"); ++ if (card == 5) { ++ fprintf(stderr, "Could not find a valid DRM device.\n"); + goto out_return; + } + +- if (drmSetClientCap(drm_fd, DRM_CLIENT_CAP_ATOMIC, 1)) { +- fprintf(stderr, "Unable to set atomic cap.\n"); +- goto out_close_fd; +- } +- +- if (drmSetClientCap(drm_fd, DRM_CLIENT_CAP_UNIVERSAL_PLANES, 1)) { +- fprintf(stderr, "Unable to set universal planes cap.\n"); +- goto out_close_fd; +- } ++ drmSetClientCap(drm_fd, DRM_CLIENT_CAP_UNIVERSAL_PLANES, 1); + + plane_res = drmModeGetPlaneResources(drm_fd); + if (!plane_res) { +@@ -203,16 +194,20 @@ int main(int argc, char **argv) + + 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); + +- if (fb_id != 0 && crtc_id != 0) ++ /* Modified: Primary plane might not have a crtc_id on some planes */ ++ if (fb_id != 0) + break; + } + +- if (i == plane_res->count_planes) { +- fprintf(stderr, "No planes found\n"); ++ if (fb_id == 0) { ++ fprintf(stderr, "No active framebuffers found on planes\n"); + goto out_free_resources; + } + +@@ -226,7 +221,7 @@ int main(int argc, char **argv) + err = drmPrimeHandleToFD(drm_fd, fb->handle, O_RDONLY, &prime_fd); + if (err < 0) { + fprintf(stderr, "Failed to retrieve prime handler: %s\n", +- strerror(-err)); ++ strerror(errno)); + goto out_free_fb; + } + +@@ -237,6 +232,7 @@ int main(int argc, char **argv) + 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: