/* epdc-show-bitmap.c Displays a raw image to the EPDC framebuffer Parabola-rM is a free operating system for the reMarakble tablet. Copyright (C) 2020 Davis Remmel This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #include #include #include #include #include #include #include #include #include #include #include int main(int argc, char *argv[]) { if (argc < 2) { printf("Must pass an image as an argument.\n"); return 1; } int ret; int fb = open("/dev/fb0", O_RDWR); struct fb_var_screeninfo vinfo; ret = ioctl(fb, FBIOGET_VSCREENINFO, &vinfo); if (0 != ret) { printf("FBIOGET_VSCREENINFO failed with error %d" ", aborting\n", ret); return 1; } vinfo.xres = 1872; vinfo.yres = 1404; vinfo.pixclock = 160000000; vinfo.left_margin = 32; vinfo.right_margin = 326; vinfo.upper_margin = 4; vinfo.lower_margin = 12; vinfo.hsync_len = 44; vinfo.vsync_len = 1; vinfo.sync = 0; vinfo.vmode = FB_VMODE_NONINTERLACED; vinfo.accel_flags = 0; vinfo.activate = FB_ACTIVATE_FORCE; // Put screen info. Sometimes this fails when trying to set the // pixclock. This may be a bug in the driver's arithmetic. ret = ioctl(fb, FBIOPUT_VSCREENINFO, &vinfo); if (0 != ret) { fprintf(stderr, "FBIOPUT_VSCREENINFO failed with error " "%d, attempting To reset pixclock\n", ret); vinfo.pixclock = 6250; ioctl(fb, FBIOPUT_VSCREENINFO, &vinfo); vinfo.pixclock = 160000000; ret = ioctl(fb, FBIOPUT_VSCREENINFO, &vinfo); if (0 != ret) { fprintf(stderr, "FBIOPUT_VSCREENINFO failed " "with error %d, aborting\n", ret); return 1; } } printf("x:%d y:%d activate:%d bpp:%d rotate:%d hsync_len:%d" "vsync_len: %d sync:%d\n", vinfo.xres, vinfo.yres, vinfo.activate, vinfo.bits_per_pixel, vinfo.rotate, vinfo.hsync_len, vinfo.vsync_len, vinfo.sync); struct fb_fix_screeninfo finfo; ret = ioctl(fb, FBIOGET_FSCREENINFO, &finfo); if (0 != ret) { fprintf(stderr, "FBIOGET_FSCREENINFO failed with error " "%d, aborting\n", ret); return 1; } // In case the EPDC wasn't accessible ret = ioctl(fb, MXCFB_ENABLE_EPDC_ACCESS); if (0 != ret) { fprintf(stderr, "MXCFB_ENABLE_EPDC_ACCESS failed with " "error %d, aborting\n", ret); return 1; } // Set to partial mode to control update parameters __u32 aumode = AUTO_UPDATE_MODE_REGION_MODE; ret = ioctl(fb, MXCFB_SET_AUTO_UPDATE_MODE, &aumode); if (0 != ret) { fprintf(stderr, "MXCFB_SET_AUTO_UPDATE_MODE failed " "with error %d, aborting\n", ret); return 1; } // No artifacts in display output __u32 uscheme = UPDATE_SCHEME_SNAPSHOT; ret = ioctl(fb, MXCFB_SET_UPDATE_SCHEME, &uscheme); if (0 != ret) { fprintf(stderr, "MXCFB_SET_UPDATE_SCHEME failed with " "error %d, aborting\n", ret); return 1; } // Set up update (same region for all writes, gets reused) struct mxcfb_update_data bupdate; bupdate.update_region.left = 0; bupdate.update_region.top = 0; bupdate.update_region.width = 1872; bupdate.update_region.height = 1404; bupdate.waveform_mode = WAVEFORM_MODE_AUTO; bupdate.update_mode = UPDATE_MODE_FULL; bupdate.update_marker = 0; bupdate.temp = TEMP_USE_AMBIENT; bupdate.flags = 0; struct mxcfb_update_marker_data updm; updm.update_marker = 0; // mmap to framebuffer int buflength = vinfo.yres_virtual * finfo.line_length; printf("buflength %d\n", buflength); char * region = mmap(0, buflength, PROT_READ | PROT_WRITE, MAP_SHARED, fb, (off_t)0); if (region == MAP_FAILED) { fprintf(stderr, "map failed!\n"); return 1; } // Write black memset(region, 0x00, buflength); ioctl(fb, MXCFB_SEND_UPDATE, &bupdate); ioctl(fb, MXCFB_WAIT_FOR_UPDATE_COMPLETE, &updm); // Write white memset(region, 0xff, buflength); ioctl(fb, MXCFB_SEND_UPDATE, &bupdate); ioctl(fb, MXCFB_WAIT_FOR_UPDATE_COMPLETE, &updm); // Write image FILE *pattern = fopen(argv[1], "rb"); fseek(pattern, 0, SEEK_END); long psize = ftell(pattern); printf("psize is %d\n", psize); fseek(pattern, 0, SEEK_SET); if (psize != buflength) { fprintf(stderr, "Image must match framebuffer size\n"); return 1; } char *buffer = malloc(psize); fread(buffer, psize, 1, pattern); fclose(pattern); memcpy(region, buffer, psize); ret = ioctl(fb, MXCFB_SEND_UPDATE, &bupdate); ioctl(fb, MXCFB_WAIT_FOR_UPDATE_COMPLETE, &updm); if (0 != ret) { fprintf(stderr, "MXCFB_SEND_UPDATE failed with error " "%d, aborting\n", ret); return 1; } close(fb); return 0; }