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 0000000..603ee29 Binary files /dev/null and b/kmsdrm/kmsgrab differ diff --git a/kmsdrm/kmsgrab.c b/kmsdrm/kmsgrab.c new file mode 100644 index 0000000..82e2df9 --- /dev/null +++ b/kmsdrm/kmsgrab.c @@ -0,0 +1,248 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * KMS/DRM screenshot tool + * + * Copyright (c) 2021 Paul Cercueil + * 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: