framebuffer介绍
framebuffer 帧缓冲,是linux内核虚拟出来的一个设备,向应用层提供的一个统一标准接口的显示设备。
从驱动视角来看,framebuffer是一个典型的字符设备,而且创建类 /sys/class/graphics

显示原理
裸机中lcd的显示原理
soc中有cpu、ddr、lcd控制器。
lcd显示器主要包括lcd驱动器和lcd屏幕。
lcd控制器与lcd驱动器通过排线链接,我们通过初始化lcd控制器,在ddr中划分出一部分内存作为显存,与lcd显示形成一种映射。cpu之后仅仅需要将需要显示的内容放在ddr中即可,lcd控制器会自己把ddr中的内容刷新到lcd驱动器中。

操作系统中lcd显示原理
驱动负责建立ddr与lcd显示的映射关系,需要申请内存,初始化lcd控制器,并使用不同的虚拟内存映射同一个物理内存,两个不同的虚拟地址分别是内核空间和应用空间,即mmap技术。
应用负责把要显示的内容放在ddr中。
framebuffer使用
(1)获取设备文件 /dev/fb0
(2)获取设备信息 #include <linux/fb.h>
(3)mmap做映射
(4)填充framebuffer
framebuffer应用
编写应用代码如下,使用交叉编译工具编译后放到nfs中,方便开发板运行。
cpp
#include <stdio.h>
#include <fcntl.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <linux/fb.h>
#include <sys/ioctl.h>
#include <sys/mman.h>
#define DEVICE_NAME "/dev/fb0"
#define WIDTH 1024
#define HEIGHT 600
void draw_pixel(unsigned int width,unsigned int height,unsigned int color);
unsigned int *mapped_mem = NULL;
int main() {
int fd = -1, ret = -1;
struct fb_var_screeninfo vinfo;
struct fb_fix_screeninfo finfo;
//获取设备文件描述符
fd = open(DEVICE_NAME, O_RDWR);
if (fd == -1) {
perror("Error opening device");
return 1;
}
printf("Framebuffer device opened successfully: %s\n", DEVICE_NAME);
//获取设备信息
ret = ioctl(fd, FBIOGET_VSCREENINFO, &vinfo);
if (ret == -1) {
perror("Error getting video screen info");
close(fd);
return 1;
}
ret = ioctl(fd, FBIOGET_FSCREENINFO, &finfo);
if (ret == -1) {
perror("Error getting fixed screen info");
close(fd);
return 1;
}
printf("Video screen info:\n");
printf(" xres: %d\n", vinfo.xres);
printf(" yres: %d\n", vinfo.yres);
printf(" bits_per_pixel: %d\n", vinfo.bits_per_pixel);
printf(" xres_virtual: %d\n", vinfo.xres_virtual);
printf(" yres_virtual: %d\n", vinfo.yres_virtual);
printf(" xoffset: %d\n", vinfo.xoffset);
printf(" yoffset: %d\n", vinfo.yoffset);
printf("Fixed screen info:\n");
printf(" smem_start: %p\n", (void*)finfo.smem_start);
printf(" smem_len: %u\n", finfo.smem_len);
//mmap映射地址
mapped_mem = mmap(NULL, finfo.smem_len, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
if (mapped_mem == MAP_FAILED) {
perror("Error mapping framebuffer memory");
close(fd);
return 1;
}
printf("Framebuffer memory mapped to: %p\n", mapped_mem);
draw_pixel(WIDTH, HEIGHT, 0x00FF0000);
close(fd);
printf("Framebuffer device closed successfully: %s\n", DEVICE_NAME);
return 0;
}
void draw_pixel(unsigned int width,unsigned int height,unsigned int color) {
unsigned int x,y;
for(y=0;y<height;y++) {
for(x=0;x<width;x++) {
//在此处添加绘制像素的代码
*(mapped_mem + y * width + x) = color;
}
}
}
重要头文件<linux/fb.h>
该头文件在交叉编译工具中自带

可用命令宏定义
cpp
#define FBIOGET_VSCREENINFO 0x4600 // Get video screen info
#define FBIOPUT_VSCREENINFO 0x4601 // Set video screen info
#define FBIOGET_FSCREENINFO 0x4602 // Get fixed screen info
不可变参数结构体

可变参数结构体
虚拟分辨率:我们可以设置不同大小的frambuffer,在显示器上实现缩小或者放大后的部分显示

framebuffer驱动
驱动框架
驱动框架fbmem.c
kernel/drivers/video/fbmem.c中注册了字符设备,并且创建了graphics类,提供了
int register_framebuffer(struct fb_info *fb_info)
int unregister_framebuffer(struct fb_info *fb_info)
接口给驱动编写者来注册fb设备

proc_creat函数为fb创建了proc文件,可以通过cat /proc/fb来验证

系统创建好了fb结构体 fb_info

建立了指针组成的数组,一共是32个
__read_mostly:优化,告诉编译器这玩意一般用来读

registered_fb的数组下标就是次设备号,也是fb_info结构体中node成员数值

注册接口就是把填充好的fb_info结构体填充到内核信息中,也就是说驱动负责填充fb_info之后申请注册即可。

fb_var_to_videomode开始确定显示模式,跳入modedb.c文件中执行
属性功能fbsys.c
kernel/drivers/video/fbsys.c文件处理fb在/sys目录下的属性与功能



显示模式modedb.c
kernel/drivers/video/modedb.c文件用于管理显示模式(VGA、HDMI、DP)

这里定义了一些常见的显示模式,没有你想要的那也没关系

这里通过fb_info结构体里面的var结构体信息填充mode结构体
通知信息fb_notify.c
kernel/drivers/video/fb_notify.c文件用于管理fb通知消息
硬件驱动
驱动主体s3cfb.c
kernel/drivers/video/samsung/s3cfb.c文件是驱动主体,真正开始实现硬件初始化,初始化为platform类设备,具体硬件函数调用s3cfb_fimd6x.c



分辨率、长宽、像素位、帧频率、极性

开机动画:



硬件控制s3cfb_fimd6x.c
kernel/drivers/video/samsung/s3cfb_fimd6x.c文件提供大量对lcd的硬件控制函数

平台驱动mach-x210.c
kernel/arch/arm/mach-s5pv210/mach-x210.c文件提供platform_devices



创建平台总线类设备,并注册
硬件信息devs.c
kernel/arch/arm/plat-s5p/devs.c文件提供硬件描述信息

