Linux图形栈之Framebuffer驱动

Linux图形栈之Framebuffer驱动

概述

开始记录工作学习中点滴知识,这是一个记录,也是总结。言归正传,Linux图形栈是一个非常庞大复杂的系统,然而今天我们就从framebuffer驱动开始抛砖,窥得其冰山一角。framebuffer就是帧缓存,也就是说开发者希望将图像写入帧缓存,就能看到显示设备上的图像,就是这么简单,而不必关心系统与底层显示设备的操作。即使在DRI(Direct Render Infrastructure)中也保留了framebuffer,特别对于嵌入式设备显示,framebuffer十分重要。

Framebuffer 框架简述

在linux系统中,framebuffer驱动框架已经实现(这里就不具体分析内核中框架了),所以写framebuffer驱动只需要按照系统接口写即可。framebuffer驱动最重要的是把GPU显存给映射到内核空间或者初始化LCD控制器。等到生成设备节点/dev/fbx,app就可以操作显存了,框架如下图所示:
framebuffer驱动框架图

在x86上写个Framebuffer驱动

既然有了思路,我们就开始在x86上具体写个驱动,然后再写个测试app显示图像。环境是ubuntu18.04,硬件是x86。在现代系统中,系统启动开始使用efi固件,所以在引导的过程中efi也会驱动显示器,并会保存屏幕的信息到screen_info中。

数据结构分析

先分析下数据结构,其中最重要的是fb_info,最后注册这个结构体生成fb设备,fb_var_screeninfo 和 fb_fix_screeninfo的值都可以从screen_info中获取。fb_ops 就是设备操作的函数,其中有一些由fb框架实现,自己实现的是下图中的两个函数。数据结构不复杂,但是很多都涉及和显示屏幕的一些参数,写该驱动前,最好先知道显示屏基本参数。
fb结构体

驱动结构分析

首先将平台设备驱动注册,在efi启动中会有efi-framebuffer设备,一旦注册,设备名匹配,则会调用myfb_probe函数。

static struct platform_driver myfb_driver = {                                                                                                                                                                   		    
	.driver = {
         .name = "efi-framebuffer",
     },
     .probe = myfb_probe,
     .remove = myfb_remove,
};  
builtin_platform_driver(myfb_driver);

在probe函数中,简单介绍下,获取显卡显存的地址将其映射到内核空间中,接着获取屏幕信息。具体可以看代码。
myfb_fix.smem_start = screen_info.lfb_base;

调试信息

在这里编译的是4.15.0的源码,将该驱动放入drivers/video/fbdev中,修改Makefile。注意在编译中需要把DRI关掉,以及选中framebuffer support。然后选中自己的驱动,关掉其他fb驱动。如下图,在内核启动中可以看到已经加载了自己的fb驱动了,并且能在系统中看到/dev/fb0,至此驱动编写成功。

Apr 24 08:51:06 bzm kernel: [    4.103360] myfb_probe
Apr 24 08:51:06 bzm kernel: [    4.103368] myfb: framebuffer at 0xe0000000, using 8100k, total 8100k
Apr 24 08:51:06 bzm kernel: [    4.103369] myfb: mode is 1920x108032, linelength=7680, pages=1
Apr 24 08:51:06 bzm kernel: [    4.103369] myfb: scrolling: redraw
Apr 24 08:51:06 bzm kernel: [    4.103370] myfb: Truecolor: size=8:8:8:8, shift=24:16:8:0
Apr 24 08:51:06 bzm kernel: [    4.103441] Console: switching to colour frame buffer device 240x67
Apr 24 08:51:06 bzm kernel: [    4.103461] fb0: EFI VGA frame buffer device

写个app测试

最后当然要测试下该驱动能否正常工作。编写测试app,写了一个colorbar,代码如下:

void draw_colorbar(int x, int y, unsigned char *p) 
{       
    int i, j, a, b;
    int width;
        
    width = x / 8;
        
    for (i = 0; i < y; i++) {                                                                                                                                                                               
        for (j = 0; j < x; j++) {
            a = j / width;
            b = j % width;
  //          printf("a = %d\n", a);
            switch (a) {
                case 0:
                    p[(a*width+b)*4 + 0 + i*x*4] = 255;
                    p[(a*width+b)*4 + 1 + i*x*4] = 255;
                    p[(a*width+b)*4 + 2 + i*x*4] = 255;
                    p[(a*width+b)*4 + 3 + i*x*4] = 255;
                    break;
                case 1:
                    p[(a*width+b)*4 + 0 + i*x*4] = 255;
                    p[(a*width+b)*4 + 1 + i*x*4] = 255;
                    p[(a*width+b)*4 + 2 + i*x*4] = 0;
                    p[(a*width+b)*4 + 3 + i*x*4] = 255;
                    break;
                case 2:
                    p[(a*width+b)*4 + 0 + i*x*4] = 0;
                    p[(a*width+b)*4 + 1 + i*x*4] = 255;
                    p[(a*width+b)*4 + 2 + i*x*4] = 255;
                    p[(a*width+b)*4 + 3 + i*x*4] = 255;
                    break;
                case 3:
                    p[(a*width+b)*4 + 0 + i*x*4] = 0;
                    p[(a*width+b)*4 + 1 + i*x*4] = 255;
                    p[(a*width+b)*4 + 2 + i*x*4] = 0;
                    p[(a*width+b)*4 + 3 + i*x*4] = 255;
                    break;
                case 4:
                    p[(a*width+b)*4 + 0 + i*x*4] = 255;
                    p[(a*width+b)*4 + 1 + i*x*4] = 0;
                    p[(a*width+b)*4 + 2 + i*x*4] = 255;
                    p[(a*width+b)*4 + 3 + i*x*4] = 255;
                    break;
                case 5:
                    p[(a*width+b)*4 + 0 + i*x*4] = 255;
                    p[(a*width+b)*4 + 1 + i*x*4] = 0;
                    p[(a*width+b)*4 + 2 + i*x*4] = 0;
                    p[(a*width+b)*4 + 3 + i*x*4] = 255;
                    break;
				case 6:
                    p[(a*width+b)*4 + 0 + i*x*4] = 0;
                    p[(a*width+b)*4 + 1 + i*x*4] = 0;
                    p[(a*width+b)*4 + 2 + i*x*4] = 255;
                    p[(a*width+b)*4 + 3 + i*x*4] = 255;
                    break;
                case 7:
                    p[(a*width+b)*4 + 0 + i*x*4] = 0;
                    p[(a*width+b)*4 + 1 + i*x*4] = 0;
                    p[(a*width+b)*4 + 2 + i*x*4] = 0;
                    p[(a*width+b)*4 + 3 + i*x*4] = 255;
                    break;
            }
        }
    }
}    

可以看到屏幕被分成8个竖条纹。
在这里插入图片描述
最后提供代码欢迎大家一起学习分享。
myfb驱动.

原创文章 7 获赞 3 访问量 4947

猜你喜欢

转载自blog.csdn.net/wwssttcc/article/details/105717002
今日推荐