├── .gitignore ├── Makefile ├── Makefile-cross ├── README.md └── main.c /.gitignore: -------------------------------------------------------------------------------- 1 | *.o 2 | fbtest 3 | *.swp 4 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | # Makefile for natively compiling the fbtest program 2 | # 3 | 4 | CC = gcc 5 | CFLAGS = -O2 -Wall 6 | 7 | OBJS = main.o 8 | 9 | TARGET = fbtest 10 | 11 | $(TARGET): $(OBJS) 12 | $(CC) $(CFLAGS) $(OBJS) -o $(TARGET) 13 | 14 | %.o: %.c 15 | $(CC) $(CFLAGS) -c -o $@ $< 16 | 17 | 18 | .PHONY: clean 19 | clean: 20 | rm -f $(OBJS) $(TARGET) 21 | 22 | -------------------------------------------------------------------------------- /Makefile-cross: -------------------------------------------------------------------------------- 1 | # Makefile for cross-compiling the fbtest program 2 | # 3 | # Export an OETMP environment variable that points to the 4 | # same location as TMPDIR in build/conf/local.conf 5 | # 6 | 7 | ### cross-build defs ### 8 | 9 | ifeq ($(strip $(OETMP)),) 10 | # make things fail if OETMP not defined by pointing OETMP 11 | # at an invalid location 12 | OETMP=/tmp 13 | endif 14 | 15 | TOOLDIR = $(OETMP)/sysroots/`uname -m`-linux/usr/bin 16 | STAGEDIR = ${OETMP}/sysroots/overo/usr 17 | 18 | # soft-floating point 19 | #CC = ${TOOLDIR}/armv7a-vfp-neon-poky-linux-gnueabi/arm-poky-linux-gnueabi-gcc 20 | 21 | # hard-floating point 22 | CC = ${TOOLDIR}/cortexa8hf-vfp-neon-poky-linux-gnueabi/arm-poky-linux-gnueabi-gcc 23 | 24 | CFLAGS = -O2 -Wall 25 | 26 | LIBDIR = $(STAGEDIR)/lib 27 | INCDIR = $(STAGEDIR)/include 28 | 29 | ### end cross-build defs ### 30 | 31 | 32 | OBJS = main.o 33 | 34 | TARGET = fbtest 35 | 36 | $(TARGET): $(OBJS) 37 | $(CC) $(CFLAGS) -L $(LIBDIR) $(OBJS) -o $(TARGET) 38 | 39 | %.o: %.c 40 | $(CC) $(CFLAGS) -I $(INCDIR) -c -o $@ $< 41 | 42 | 43 | # purely for my convenience ;-) 44 | install: $(TARGET) 45 | scp -o UserKnownHostsFile=/dev/null -o StrictHostKeyChecking=no $(TARGET) root@192.168.10.111:/home/root 46 | 47 | 48 | .PHONY: clean 49 | clean: 50 | rm -f $(OBJS) $(TARGET) 51 | 52 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ## fbtest 2 | 3 | A simple program to draw a rectangle of fixed color to the 4 | Linux frame buffer display. The rectangle will have a border 5 | of fixed color, 10 pixels wide. 6 | 7 | Used for display driver development. 8 | 9 | #### Cross-compiling 10 | 11 | Assuming a Yocto built toolchain 12 | 13 | export OETMP= 14 | make -f Makefile-cross 15 | 16 | The default `Makefile-cross` assumes a hard-fp built gcc. 17 | 18 | Comment the hard-fp line and uncomment the soft-fp line if 19 | that's what you have. 20 | 21 | #### Natively compiling 22 | 23 | make 24 | 25 | #### Running 26 | 27 | root@overo:~# ./fbtest -h 28 | 29 | Usage ./fbtest: [-r] [-g] [-b] [-B] 30 | All colors default to 0xff 31 | The border color applies to all rgb and is 10 pixels wide 32 | If border is not provided, none is drawn. 33 | The index defaults to 0, if your FB has more than 1 buffers, you can set it. 34 | If set the index to -1, we will use all buffers for 20 times. 35 | 36 | Examples 37 | 38 | root@overo:~# ./fbtest 39 | root@overo:~# ./fbtest -r0x40 40 | root@overo:~# ./fbtest -r0x40 -g0 -b0 41 | root@overo:~# ./fbtest -r0x80 -g0 -b0 42 | root@overo:~# ./fbtest -r0xff -g0 -b0 43 | root@overo:~# ./fbtest -r0x40 -g0 -b0 44 | root@overo:~# ./fbtest -r0x40 -g0x40 -b0 45 | root@overo:~# ./fbtest -r0x40 -g0x40 -b0x30 46 | root@overo:~# ./fbtest -r0x40 -g0x40 -b0x30 -B0xaa 47 | root@overo:~# ./fbtest -r0x40 -g0x40 -b0x30 -B0xaa -i -1 48 | 49 | #### Stop the blinking cursor 50 | 51 | Kernel command line parameter 52 | 53 | vt.global_cursor_default=0 54 | 55 | 56 | #### Wake the framebuffer when it blanks 57 | 58 | echo 0 > /sys/class/graphics/fb0/blank 59 | 60 | -------------------------------------------------------------------------------- /main.c: -------------------------------------------------------------------------------- 1 | /* 2 | Simple framebuffer testing program 3 | 4 | Set the screen to a given color. For use in developing Linux 5 | display drivers. 6 | 7 | Copyright (c) 2014, Jumpnow Technologies, LLC 8 | All rights reserved. 9 | 10 | Redistribution and use in source and binary forms, with or without 11 | modification, are permitted provided that the following conditions 12 | are met: 13 | 14 | 1. Redistributions of source code must retain the above copyright 15 | notice, this list of conditions and the following disclaimer. 16 | 17 | 2. Redistributions in binary form must reproduce the above copyright 18 | notice, this list of conditions and the following disclaimer in the 19 | documentation and/or other materials provided with the distribution. 20 | 21 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 22 | "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 23 | LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 24 | A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 25 | HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 26 | SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED 27 | TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 28 | PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF 29 | LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 30 | NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 31 | SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 32 | 33 | Ideas taken from the Yocto Project psplash program. 34 | */ 35 | 36 | #include 37 | #include 38 | #include 39 | #include 40 | #include 41 | #include 42 | #include 43 | #include 44 | #include 45 | #include 46 | #include 47 | #include 48 | #include 49 | #include 50 | 51 | struct fb_config 52 | { 53 | int fd; 54 | int width; 55 | int height; 56 | int height_virtual; 57 | int bpp; 58 | int stride; 59 | int red_offset; 60 | int red_length; 61 | int green_offset; 62 | int green_length; 63 | int blue_offset; 64 | int blue_length; 65 | int transp_offset; 66 | int transp_length; 67 | int buffer_num; 68 | char *data; 69 | char *base; 70 | }; 71 | 72 | void dump_vscreeninfo(struct fb_var_screeninfo *fvsi) 73 | { 74 | printf("======= FB VAR SCREENINFO =======\n"); 75 | printf("xres: %d\n", fvsi->xres); 76 | printf("yres: %d\n", fvsi->yres); 77 | printf("yres_virtual: %d\n", fvsi->yres_virtual); 78 | printf("buffer number: %d\n", fvsi->yres_virtual / fvsi->yres); 79 | printf("bpp : %d\n", fvsi->bits_per_pixel); 80 | printf("red bits :\n"); 81 | printf(" offset : %d\n", fvsi->red.offset); 82 | printf(" length : %d\n", fvsi->red.length); 83 | printf(" msb_right: %d\n", fvsi->red.msb_right); 84 | printf("green bits :\n"); 85 | printf(" offset : %d\n", fvsi->green.offset); 86 | printf(" length : %d\n", fvsi->green.length); 87 | printf(" msb_right: %d\n", fvsi->green.msb_right); 88 | printf("blue bits :\n"); 89 | printf(" offset : %d\n", fvsi->blue.offset); 90 | printf(" length : %d\n", fvsi->blue.length); 91 | printf(" msb_right: %d\n", fvsi->blue.msb_right); 92 | printf("transp bits :\n"); 93 | printf(" offset : %d\n", fvsi->transp.offset); 94 | printf(" length : %d\n", fvsi->transp.length); 95 | printf(" msb_right: %d\n", fvsi->transp.msb_right); 96 | 97 | printf("=================================\n"); 98 | } 99 | 100 | void dump_fscreeninfo(struct fb_fix_screeninfo *ffsi) 101 | { 102 | printf("======= FB FIX SCREENINFO =======\n"); 103 | printf("id : %s\n", ffsi->id); 104 | printf("smem_start : 0x%08lX\n", ffsi->smem_start); 105 | printf("smem_len : %u\n", ffsi->smem_len); 106 | printf("line_length : %u\n", ffsi->line_length); 107 | printf("=================================\n"); 108 | } 109 | 110 | void plot_pixel(struct fb_config *fb, int x, int y, int r, int g, int b) 111 | { 112 | int offset = (y * fb->stride) + (x * (fb->bpp >> 3)); 113 | int r_o = fb->red_offset/fb->red_length; 114 | int g_o = fb->green_offset/fb->green_length; 115 | int b_o = fb->blue_offset/fb->blue_length; 116 | *(fb->data + offset + r_o) = r; 117 | *(fb->data + offset + g_o) = g; 118 | *(fb->data + offset + b_o) = b; 119 | if (fb->transp_length != 0) 120 | *(fb->data + offset + fb->transp_offset/fb->transp_length) = 255; 121 | } 122 | 123 | void draw_rect(struct fb_config *fb, int x, int y, int w, int h, int r, int g, int b) 124 | { 125 | int dx, dy; 126 | 127 | for (dy = 0; dy < h; dy++) { 128 | for (dx = 0; dx < w; dx++) { 129 | plot_pixel(fb, x + dx, y + dy, r, g, b); 130 | } 131 | } 132 | } 133 | 134 | void clear_screen(struct fb_config *fb, int r, int g, int b) 135 | { 136 | draw_rect(fb, 0, 0, fb->width, fb->height, r, g, b); 137 | } 138 | 139 | void usage(const char *argv_0) 140 | { 141 | printf("\nUsage %s: [-r] [-g] [-b] [-B] [-i]\n", argv_0); 142 | printf(" All colors default to 0xff\n"); 143 | printf(" The border color applies to all rgb and is 10 pixels wide\n"); 144 | printf(" If border is not provided, none is drawn.\n"); 145 | printf(" The index defaults to 0, if your FB has more than 1 buffers, you can set it.\n"); 146 | printf(" If set the index to -1, we will use all buffers for 20 times.\n"); 147 | exit(1); 148 | } 149 | 150 | int main(int argc, char **argv) 151 | { 152 | int fd; 153 | unsigned long offset; 154 | struct fb_var_screeninfo fvsi; 155 | struct fb_fix_screeninfo ffsi; 156 | struct fb_config fb; 157 | int red = 0xff; 158 | int green = 0xff; 159 | int blue = 0xff; 160 | int border = -1; 161 | int opt; 162 | int index = 0; 163 | int loop = 0; 164 | 165 | while ((opt = getopt(argc, argv, "r:g:b:B:i:h")) != -1) { 166 | switch (opt) { 167 | case 'r': 168 | red = 0xff & strtol(optarg, NULL, 0); 169 | break; 170 | 171 | case 'g': 172 | green = 0xff & strtol(optarg, NULL, 0); 173 | break; 174 | 175 | case 'b': 176 | blue = 0xff & strtol(optarg, NULL, 0); 177 | break; 178 | 179 | case 'B': 180 | border = 0xff & strtol(optarg, NULL, 0); 181 | break; 182 | 183 | case 'i': 184 | index = strtol(optarg, NULL, 0); 185 | break; 186 | 187 | default: 188 | usage(argv[0]); 189 | break; 190 | } 191 | } 192 | 193 | memset(&fb, 0, sizeof(fb)); 194 | 195 | if ((fd = open("/dev/fb0", O_RDWR)) < 0) { 196 | perror("open"); 197 | exit(1); 198 | } 199 | 200 | if (ioctl(fd, FBIOGET_VSCREENINFO, &fvsi) < 0) { 201 | perror("ioctl(FBIOGET_VSCREENINFO)"); 202 | close(fd); 203 | exit(1); 204 | } 205 | 206 | dump_vscreeninfo(&fvsi); 207 | 208 | if (ioctl(fd, FBIOGET_FSCREENINFO, &ffsi) < 0) { 209 | perror("ioctl(FBIOGET_FSCREENINFO)"); 210 | close(fd); 211 | exit(1); 212 | } 213 | 214 | dump_fscreeninfo(&ffsi); 215 | 216 | fb.fd = fd; 217 | fb.width = fvsi.xres; 218 | fb.height = fvsi.yres; 219 | fb.height_virtual = fvsi.yres_virtual; 220 | fb.bpp = fvsi.bits_per_pixel; 221 | fb.stride = ffsi.line_length; 222 | fb.red_offset = fvsi.red.offset; 223 | fb.red_length = fvsi.red.length; 224 | fb.green_offset = fvsi.green.offset; 225 | fb.green_length = fvsi.green.length; 226 | fb.blue_offset = fvsi.blue.offset; 227 | fb.blue_length = fvsi.blue.length; 228 | fb.transp_offset = fvsi.transp.offset; 229 | fb.transp_length = fvsi.transp.length; 230 | fb.buffer_num = fb.height_virtual / fb.height; 231 | 232 | if (index == -1) { 233 | index = 0; 234 | loop = 20; 235 | } 236 | if (index > fb.buffer_num - 1 || index < 0) { 237 | printf("Invalid index.\n"); 238 | exit(1); 239 | } 240 | 241 | if (fb.red_length != 8 || fb.green_length != 8 || fb.blue_length != 8) { 242 | printf("Don't support this color format\n"); 243 | goto SKIP_DRAW; 244 | } 245 | 246 | fb.base = (char *)mmap((caddr_t) NULL, ffsi.smem_len, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0); 247 | 248 | if (fb.base == (char *)-1) { 249 | perror("mmap"); 250 | close(fd); 251 | exit(1); 252 | } 253 | 254 | offset = (unsigned long) ffsi.smem_start % (unsigned long) getpagesize(); 255 | 256 | do { 257 | fb.data = fb.base + offset + (fb.stride * fb.height) * index; 258 | if (border == -1) { 259 | clear_screen(&fb, red, green, blue); 260 | } 261 | else { 262 | clear_screen(&fb, border, border, border); 263 | 264 | // draw a rect 10 pixels in from each border in the color chosen 265 | draw_rect(&fb, 10, 10, fb.width - 20, fb.height - 20, red, green, blue); 266 | } 267 | fvsi.yoffset = index * fvsi.yres; 268 | printf("data addr = %p, yoffset = %d\n", fb.data, fvsi.yoffset); 269 | ioctl(fb.fd, FBIOPAN_DISPLAY, &fvsi); 270 | if (fb.buffer_num > 1) 271 | index = (index + 1) % fb.buffer_num; 272 | red = 255 - red; 273 | green = 255 - green; 274 | blue = 255 - blue; 275 | }while(loop--); 276 | 277 | SKIP_DRAW: 278 | 279 | close(fd); 280 | 281 | return 0; 282 | } 283 | 284 | --------------------------------------------------------------------------------