/* fbpantest.c — empirically find the ioctl that pans /dev/fb0 by yoffset. * Confirmed already: fb0 is 480x720 RGB565, yres_virtual=1440 (double), * yoffset selects the displayed buffer, ypanstep=1. We try candidate ioctls * that set yoffset to the OTHER buffer and read yoffset back; whichever * changes it is the pan mechanism. We restore yoffset immediately. */ #include #include #include #include #include #include #include #include #define GETV 0x4600 static int get_info(int fd, uint32_t *yoff, uint32_t *yres) { unsigned char v[160]; memset(v, 0, sizeof v); if (ioctl(fd, GETV, v) < 0) return -1; *yres = *(uint32_t*)(v + 4); *yoff = *(uint32_t*)(v + 20); return 0; } static void write_yoffset_to(int fd, uint32_t cmd, uint32_t yoffset) { unsigned char v[160]; memset(v, 0, sizeof v); if (ioctl(fd, GETV, v) < 0) return; /* modify only the offset fields, keep everything else */ *(uint32_t*)(v + 16) = 0; *(uint32_t*)(v + 20) = yoffset; ioctl(fd, cmd, v); } int main(void) { int fd = open("/dev/fb0", O_RDWR); if (fd < 0) { perror("open /dev/fb0"); return 1; } uint32_t orig = 0, yres = 0; if (get_info(fd, &orig, &yres) < 0) { perror("getvar"); return 1; } uint32_t target = (orig < yres) ? yres : 0; printf("orig yoffset=%u yres=%u target(other buf)=%u\n", orig, yres, target); unsigned tests[] = { 0x4601, 0x4606 }; /* PUT_VSCREENINFO, PAN_DISPLAY(nr 0x06) */ for (unsigned i = 0; i < sizeof(tests)/sizeof(tests[0]); i++) { uint32_t cmd = tests[i]; write_yoffset_to(fd, cmd, target); uint32_t now = 0, tmp = 0; int ok = get_info(fd, &now, &tmp); printf(" cmd=0x%04X -> yoffset=%u (target %u) %s\n", cmd, now, target, (ok==0 && now==target) ? "*** PAN WORKS ***" : ""); /* restore */ if (ok == 0 && now == target) { write_yoffset_to(fd, cmd, orig); uint32_t back = 0; get_info(fd, &back, &tmp); printf(" restored to yoffset=%u\n", back); break; } } /* also probe FBIOBLANK candidate 0x4611 and 0x4603 just to report which blanks */ errno = 0; int b1 = ioctl(fd, 0x4603, 5); int e1 = errno; errno = 0; int b2 = ioctl(fd, 0x4611, 5); int e2 = errno; printf(" blank 0x4603(5) r=%d errno=%d ; 0x4611(5) r=%d errno=%d\n", b1, e1, b2, e2); /* ensure unblanked back to 0 regardless */ ioctl(fd, 0x4611, 0); /* unblank (works per launcher) */ close(fd); return 0; }