├── LICENSE.txt ├── Makefile ├── README.md ├── fbinfo.c ├── fbmmap.c └── vconsole.c /LICENSE.txt: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2020 Hugo Rodde 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | # Commands. 2 | RM ?= rm -f 3 | 4 | # Flags. 5 | CFLAGS ?= -Wall -Wextra -Werror 6 | 7 | # Programs. 8 | PROGRAMS := fbinfo fbmmap vconsole 9 | 10 | # Make targets, leverage implicit rules. 11 | .PHONY: all 12 | all: $(PROGRAMS) 13 | 14 | .PHONY: clean 15 | clean: 16 | $(RM) $(PROGRAMS) 17 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Playground with the Linux Framebuffer 2 | 3 | ## What is a frame buffer device? 4 | 5 | Taken from Geert Uytterhoeven's framebuffer.txt in the linux kernel sources: 6 | 7 | > A framebuffer device is an abstraction for the graphic hardware. It represents 8 | > the frame buffer of some video hardware, and allows application software to 9 | > access the graphic hardware through a well-defined interface, so that the 10 | > software doesn't need to know anything about the low-level interface stuff. 11 | 12 | ## Why use the frame buffer directly? 13 | 14 | The frame buffer device is a very low-level interface to display something on 15 | the screen. Speaking about an embedded GUI there are several reasons to use the 16 | frame buffer directly instead of a Window manager: 17 | 18 | - simple: just write the pixels to a memory 19 | - fast: no window manager which means fast boot and less overhead 20 | - portable: independently from the distribution every Linux system has a frame 21 | buffer device so it's compatible with all of them 22 | 23 | More detailed information can be found in the great manifest for Raspberry Pi 24 | Wiki about the [framebuffer][framebuffer] and the [framebuffer 25 | console][framebuffer-console]. 26 | 27 | ## Compile examples 28 | 29 | Single C source file should compile well on any Unix OS with `make` command: 30 | 31 | make [all|clean] 32 | 33 | It leverages [Make implicit rules][make-implicit-rules]. 34 | 35 | ### Credits 36 | 37 | For `fbinfo`, see [low level graphics on Raspberry Pi][fbinfo]. For `fbmmap`, 38 | see [enabling the linux framebuffer][fbmmap] from Qt docs. 39 | 40 | ## Commands 41 | 42 | ### Quickly output bytes to `linuxfb` 43 | 44 | One may need `sudo` depending on the file permissions to run [dd][dd]. 45 | Error like `No space left on device` is expected. 46 | 47 | # Output random pixel noise 48 | dd if=/dev/urandom of=/dev/fb0 49 | 50 | # Clear framebuffer 51 | dd if=/dev/zero of=/dev/fb0 52 | 53 | ### Get information about a framebuffer 54 | 55 | Print detailed information. Optional `fb` parameter to fall back on default. 56 | 57 | fbset -fb /dev/fb0 -i 58 | 59 | Initialize the framebuffer if _disabled_ by a remapping of the framebuffer 60 | console via a [kernel parameter][kernel-parameter]. Soft reset when coupled with 61 | clear framebuffer command. A call like `con2fbmap 1 0` is needed to actually get 62 | the framebuffer working with `linuxfb` API. 63 | 64 | fbset -fb /dev/fb0 "640x480-60" 65 | 66 | See `/etc/fb.modes`. 67 | 68 | ### Disable cursor blinking in framebuffer console 69 | 70 | vt.global_cursor_default=0 71 | 72 | ### Disable framebuffer console before boot 73 | 74 | Add this kernel parameter to disable console framebuffer `fb0`: 75 | 76 | fbcon=map:1 77 | 78 | From [The Framebuffer Console][kernel-framebuffer-console]: 79 | 80 | > 3 . fbcon=map:<0123> 81 | 82 | > This is an interesting option. It tells which driver gets mapped to which 83 | > console. The value '0123' is a sequence that gets repeated until the total 84 | > length is 64 which is the number of consoles available. In the above example, 85 | > it is expanded to 012301230123... and the mapping will be: 86 | 87 | > tty | 1 2 3 4 5 6 7 8 9 ... 88 | > fb | 0 1 2 3 0 1 2 3 0 ... 89 | 90 | > (`cat /proc/fb` should tell you what the fb numbers are) 91 | 92 | > One side effect that may be useful is using a map value that exceeds the 93 | > number of loaded fb drivers. For example, if only one driver is available, 94 | > `fb0`, adding `fbcon=map:1` tells fbcon not to take over the console. 95 | 96 | > Later on, when you want to map the console the to the framebuffer device, you 97 | > can use the `con2fbmap` utility. 98 | 99 | More details about the [con2fbmap utility][con2fbmap]. 100 | With hints here on [where to put such a piece of code][etc-rc-local]. 101 | 102 | ## TFT LCD display modules 103 | 104 | As per [Linux Framebuffer drivers for small TFT LCD display][git-notro-fbtft]: 105 | 106 | > 2015-01-19 107 | > The FBTFT drivers are now in the Linux kernel staging tree: 108 | > https://git.kernel.org/cgit/linux/kernel/git/gregkh/staging.git/tree/drivers/staging/fbtft?h=staging-testing 109 | > Development in this github repo has ceased. 110 | 111 | If one wants to read someone struggling to setup its [LCD driver at 112 | boot][lcd-driver-boot], as of Octobre 2015. Hence a little outdated. 113 | 114 | ## Going further 115 | 116 | Read the [Framebuffer API][kernel-framebuffer-api] official documentation: 117 | 118 | > This document describes the frame buffer API used by applications to interact with 119 | > frame buffer devices. In-kernel APIs between device drivers and the frame buffer 120 | > core are not described. 121 | 122 | > Due to a lack of documentation in the original frame buffer API, drivers 123 | > behaviours differ in subtle (and not so subtle) ways. This document describes the 124 | > recommended API implementation, but applications should be prepared to deal with 125 | > different behaviours 126 | 127 | Read the [Framebuffer HOWTO][framebuffer-howto] by Alex Buell (2010): 128 | 129 | > This document describes how to use the framebuffer devices in Linux with a 130 | > variety of platforms. This also includes how to set up multi-headed 131 | > displays. 132 | 133 | Some chapters that are interesting in our case: 134 | 135 | Table of Contents 136 | 1. Contributors 137 | 2. What is a framebuffer device? 138 | 3. What advantages does framebuffer devices have? 139 | 4. Using framebuffer devices on x86 platforms 140 | 10. Using framebuffer devices on ARM platforms 141 | 13. Changing Console Modes 142 | 17. Looking for further information 143 | 144 | Read the interesting documentation from [Toradex][framebuffer-linux]. 145 | 146 | > The framebuffer (fbdev) is a character device providing access to graphics 147 | > hardware. Beside the framebuffer, other interfaces exist to access graphics 148 | > hardware such as the DRI (direct rendering interface) or proprietary interfaces 149 | > (NVIDIA drivers). 150 | > 151 | > Typically, the framebuffer doesn't support any 2D/3D hardware acceleration. 152 | > 153 | > The i.MX 6 kernel comes with an open source fbdev driver called 154 | > mxcfb. The X-Server driver is closed source and called vivante. 155 | > 156 | > The i.MX 7 and i.MX 6ULL kernels come with an open source fbdev driver, mxsfb. 157 | 158 | [make-implicit-rules]:https://www.gnu.org/software/make/manual/html_node/Implicit-Rules.html 159 | [fbinfo]:http://raspberrycompote.blogspot.com/2012/12/low-level-graphics-on-raspberry-pi-part_9509.html 160 | [fbmmap]:https://doc.qt.io/archives/3.3/emb-framebuffer-howto.html 161 | [lfb-commandline]:https://unix.stackexchange.com/questions/192206 162 | [framebuffer-console]:https://github.com/FrankBau/raspi-repo-manifest/wiki/fbcon 163 | [framebuffer]:https://github.com/FrankBau/raspi-repo-manifest/wiki/framebuffer 164 | [kernel-parameter]:https://github.com/FrankBau/raspi-repo-manifest/wiki/kernel-parameter 165 | [dd]:https://github.com/FrankBau/raspi-repo-manifest/wiki/dd 166 | [kernel-framebuffer-api]:https://www.kernel.org/doc/Documentation/fb/api.txt 167 | [kernel-framebuffer-console]:https://www.kernel.org/doc/Documentation/fb/fbcon.txt 168 | [con2fbmap]:https://github.com/notro/fbtft/wiki/Framebuffer-use#console 169 | [etc-rc-local]:https://www.raspberrypi.org/forums/viewtopic.php?t=222402 170 | [git-notro-fbtft]:https://github.com/notro/fbtft 171 | [lcd-driver-boot]:https://www.raspberrypi.org/forums/viewtopic.php?t=123676 172 | [framebuffer-howto]:https://www.tldp.org/HOWTO/text/Framebuffer-HOWTO 173 | [framebuffer-linux]:https://developer.toradex.com/knowledge-base/framebuffer-linux 174 | -------------------------------------------------------------------------------- /fbinfo.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | int main() 10 | { 11 | int fbfd; 12 | struct fb_var_screeninfo vinfo; 13 | 14 | /* Open the framebuffer device file for reading and writing. */ 15 | fbfd = open("/dev/fb0", O_RDWR); 16 | if (fbfd == -1) 17 | { 18 | perror("Failed to open framebuffer device"); 19 | exit(1); 20 | } 21 | printf("The framebuffer device opened.\n"); 22 | 23 | /* Get variable screen information. */ 24 | if (ioctl(fbfd, FBIOGET_VSCREENINFO, &vinfo)) 25 | { 26 | close(fbfd); 27 | perror("Failed to read variable information"); 28 | exit(2); 29 | } 30 | printf("%dx%d, %d bpp\n", vinfo.xres, vinfo.yres, vinfo.bits_per_pixel); 31 | printf("rotate=%d\n", vinfo.rotate); 32 | printf("activate=%d\n", vinfo.activate); 33 | 34 | /* Blank display. */ 35 | if (ioctl(fbfd, FBIOBLANK, 0)) 36 | { 37 | close(fbfd); 38 | perror("Failed to blank display"); 39 | exit(3); 40 | } 41 | 42 | /* Close file descriptor. */ 43 | close(fbfd); 44 | 45 | return 0; 46 | } 47 | -------------------------------------------------------------------------------- /fbmmap.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | int main() 10 | { 11 | int fbfd; 12 | char *fbp; 13 | struct fb_var_screeninfo vinfo; 14 | struct fb_fix_screeninfo finfo; 15 | 16 | /* Open the file for reading and writing. */ 17 | fbfd = open("/dev/fb0", O_RDWR); 18 | if (fbfd == -1) 19 | { 20 | perror("Failed to open framebuffer device"); 21 | exit(1); 22 | } 23 | printf("The framebuffer device was opened successfully.\n"); 24 | 25 | /* Get fixed screen information. */ 26 | if (ioctl(fbfd, FBIOGET_FSCREENINFO, &finfo) == -1) 27 | { 28 | close(fbfd); 29 | perror("Failed to read fixed information"); 30 | exit(2); 31 | } 32 | 33 | /* Get variable screen information. */ 34 | if (ioctl(fbfd, FBIOGET_VSCREENINFO, &vinfo) == -1) 35 | { 36 | close(fbfd); 37 | perror("Failed to read variable information"); 38 | exit(3); 39 | } 40 | 41 | printf("%dx%d, %d bpp\n", vinfo.xres, vinfo.yres, vinfo.bits_per_pixel); 42 | printf("rotate=%d\n", vinfo.rotate); 43 | printf("activate=%d\n", vinfo.activate); 44 | 45 | /* Figure out the size of the screen in bytes. */ 46 | long int screensize = vinfo.xres * vinfo.yres * vinfo.bits_per_pixel / 8; 47 | 48 | /* Map the device to memory. */ 49 | fbp = (char *) mmap(0, screensize, PROT_READ | PROT_WRITE, MAP_SHARED, fbfd, 0); 50 | if ((long) fbp == -1) 51 | { 52 | close(fbfd); 53 | perror("Failed to map framebuffer device to memory"); 54 | exit(4); 55 | } 56 | printf("The framebuffer device was mapped to memory successfully.\n"); 57 | 58 | /* Paint a pretty screen. */ 59 | unsigned int x, y; 60 | long int location; 61 | for (y = 0; y < vinfo.yres; y++) 62 | { 63 | for (x = 0; x < vinfo.xres; x++) 64 | { 65 | location = (x+vinfo.xoffset) * (vinfo.bits_per_pixel/8) + 66 | (y+vinfo.yoffset) * finfo.line_length; 67 | 68 | if (vinfo.bits_per_pixel == 32) 69 | { 70 | *(fbp + location) = 100; // Some blue. 71 | *(fbp + location + 1) = 15+(x-100)/2; // A little green. 72 | *(fbp + location + 2) = 200-(y-100)/5; // A lot of red. 73 | *(fbp + location + 3) = 0; // No transparency. 74 | } 75 | else // Assume 16 bpp. 76 | { 77 | int b = 10; // Some blue. 78 | int g = (x-100)/6; // A little green. 79 | int r = 31-(y-100)/16; // A lot of red. 80 | unsigned short int t = r<<11 | g << 5 | b; 81 | *((unsigned short int*)(fbp + location)) = t; 82 | } 83 | 84 | } 85 | } 86 | printf("The framebuffer device was painted successfully.\n"); 87 | 88 | /* Close memory mapped and file descriptor. */ 89 | munmap(fbp, screensize); 90 | close(fbfd); 91 | 92 | return 0; 93 | } 94 | -------------------------------------------------------------------------------- /vconsole.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | #include 6 | #include 7 | 8 | int main(int argc, char **argv) 9 | { 10 | int fd; 11 | 12 | if (argc < 2) 13 | { 14 | fprintf(stderr, "Could not read virtual console device.\n"); 15 | return 1; 16 | } 17 | 18 | fd = open(argv[1], O_RDWR); 19 | if (!fd) 20 | { 21 | fprintf(stderr, "Could not open virtual console.\n"); 22 | return 1; 23 | } 24 | 25 | if (ioctl(fd, KDSETMODE, KD_GRAPHICS)) 26 | { 27 | fprintf(stderr, "Could not set virtual console to KD_GRAPHICS mode.\n"); 28 | return 1; 29 | } 30 | } 31 | --------------------------------------------------------------------------------