2. FrameBuffer 核心数据结构详解

FrameBuffer 子系统的核心围绕三个关键数据结构展开:fb_info(设备描述符)、fb_ops(操作函数表)、fb_var_screeninfo(可变参数)和 fb_fix_screeninfo(固定参数)。理解这些结构是掌握 FrameBuffer 驱动开发的基础,也是后续迁移到 DRM 时对比差异的关键。

学习提示: 这四个结构体定义在 include/linux/fb.h 中。建议在阅读本节时,同时打开内核源码中的该头文件对照学习。

2.1 整体架构关系

下图展示了四个核心数据结构在 FrameBuffer 驱动中的组织关系:

FrameBuffer 核心数据结构关系图 struct fb_info FrameBuffer 设备描述符 struct fb_ops 操作函数表 struct fb_var_screeninfo 可变屏幕参数 struct fb_fix_screeninfo 固定屏幕参数 关键说明 • fb_info 是 FrameBuffer 驱动的核心结构,包含设备所有信息。 • fb_ops 提供硬件操作接口,驱动开发者必须实现。 • fb_var_screeninfo 描述用户可修改的显示参数(分辨率、位深等)。 • fb_fix_screeninfo 描述硬件固定的参数(显存地址、行长等)。 • 用户空间通过 ioctl 读取/设置 var 和 fix 信息。 • 驱动初始化时填充 fb_info,并注册到内核。

2.2 struct fb_info — 设备描述符

struct fb_info 是 FrameBuffer 驱动的核心结构体,每个 Framebuffer 设备对应一个实例。它包含了设备的所有信息:操作函数、屏幕参数、设备状态、私有数据等。

2.2.1 关键字段

字段名 类型 描述
fbops struct fb_ops * 指向操作函数表的指针
var struct fb_var_screeninfo 可变屏幕参数(分辨率、位深等)
fix struct fb_fix_screeninfo 固定屏幕参数(显存地址、行长等)
screen_base char __iomem * 显存虚拟地址基址
screen_size unsigned long 显存大小(字节)
device struct device * 关联的 Linux 设备结构
par void * 驱动私有数据指针
state int 设备状态(如 FBINFO_STATE_RUNNING)
flags u32 设备标志位
node int 设备编号(如 /dev/fb0 的 0)

2.2.2 驱动初始化示例

static struct fb_info *my_fb_info;

static int myfb_probe(struct platform_device *pdev)
{
    int ret;

    // 1. 分配 fb_info 结构
    my_fb_info = framebuffer_alloc(0, &pdev->dev);
    if (!my_fb_info)
        return -ENOMEM;

    // 2. 设置操作函数表
    my_fb_info->fbops = &myfb_ops;

    // 3. 设置固定参数
    strcpy(my_fb_info->fix.id, "myfb");
    my_fb_info->fix.smem_start = dma_alloc_coherent(...);
    my_fb_info->fix.smem_len = 800 * 600 * 4; // 32bpp
    my_fb_info->fix.line_length = 800 * 4;

    // 4. 设置可变参数
    my_fb_info->var.xres = 800;
    my_fb_info->var.yres = 600;
    my_fb_info->var.bits_per_pixel = 32;

    // 5. 设置显存地址
    my_fb_info->screen_base = ioremap(my_fb_info->fix.smem_start,
                                       my_fb_info->fix.smem_len);
    my_fb_info->screen_size = my_fb_info->fix.smem_len;

    // 6. 注册 FrameBuffer 设备
    ret = register_framebuffer(my_fb_info);
    if (ret) {
        framebuffer_release(my_fb_info);
        return ret;
    }

    return 0;
}
注意事项: 在驱动卸载时,必须先调用 unregister_framebuffer() 注销设备,再调用 framebuffer_release() 释放内存。顺序不可颠倒,否则可能导致内核崩溃。

2.3 struct fb_ops — 操作函数表

struct fb_ops 定义了 FrameBuffer 设备的所有操作接口。驱动开发者需要根据硬件特性实现其中的回调函数。内核通过这个函数表来操作具体的显示硬件。

2.3.1 核心回调函数

回调函数 原型 说明
fb_open int (*fb_open)(struct fb_info *, int) 设备打开时调用,可用于初始化
fb_release int (*fb_release)(struct fb_info *, int) 设备关闭时调用,可用于清理
fb_read ssize_t (*fb_read)(struct fb_info *, char __user *, size_t, loff_t *) 从显存读取数据
fb_write ssize_t (*fb_write)(struct fb_info *, const char __user *, size_t, loff_t *) 向显存写入数据
fb_check_var int (*fb_check_var)(struct fb_var_screeninfo *, struct fb_info *) 检查可变参数是否合法
fb_set_par int (*fb_set_par)(struct fb_info *) 根据 var 设置硬件寄存器
fb_setcolreg int (*fb_setcolreg)(unsigned, unsigned, unsigned, unsigned, unsigned, struct fb_info *) 设置颜色寄存器(伪彩色模式)
fb_blank int (*fb_blank)(int, struct fb_info *) 控制屏幕开关/省电模式
fb_pan_display int (*fb_pan_display)(struct fb_var_screeninfo *, struct fb_info *) 实现显示平移(panning)
fb_mmap int (*fb_mmap)(struct fb_info *, struct vm_area_struct *) 实现显存 mmap 映射
fb_ioctl int (*fb_ioctl)(struct fb_info *, unsigned int, unsigned long) 处理自定义 ioctl 命令

2.3.2 典型实现模式

static struct fb_ops myfb_ops = {
    .owner          = THIS_MODULE,
    .fb_open        = myfb_open,
    .fb_release     = myfb_release,
    .fb_read        = myfb_read,
    .fb_write       = myfb_write,
    .fb_check_var   = myfb_check_var,
    .fb_set_par     = myfb_set_par,
    .fb_setcolreg   = myfb_setcolreg,
    .fb_blank       = myfb_blank,
    .fb_fillrect    = cfb_fillrect,   // 使用通用辅助函数
    .fb_copyarea    = cfb_copyarea,   // 使用通用辅助函数
    .fb_imageblit   = cfb_imageblit,  // 使用通用辅助函数
};

static int myfb_check_var(struct fb_var_screeninfo *var,
                          struct fb_info *info)
{
    // 检查分辨率是否在硬件支持范围内
    if (var->xres > 1920 || var->yres > 1080)
        return -EINVAL;

    // 检查位深是否支持
    if (var->bits_per_pixel != 16 && var->bits_per_pixel != 32)
        return -EINVAL;

    // 调整 xres_virtual 和 yres_virtual
    if (var->xres_virtual < var->xres)
        var->xres_virtual = var->xres;
    if (var->yres_virtual < var->yres)
        var->yres_virtual = var->yres;

    return 0;
}
最佳实践: 对于 fb_fillrect、fb_copyarea、fb_imageblit 这三个图形加速操作,如果硬件没有专门的加速引擎,可以直接使用内核提供的通用软件实现(cfb_fillrect、cfb_copyarea、cfb_imageblit)。这些函数在 include/linux/fb.h 中声明。

2.4 struct fb_var_screeninfo — 可变屏幕参数

struct fb_var_screeninfo 描述用户空间可以通过 ioctl 修改的显示参数。应用程序通过 FBIOPUT_VSCREENINFO 和 FBIOGET_VSCREENINFO 命令来设置和获取这些参数。

2.4.1 关键字段

字段名 类型 说明
xres __u32 可见分辨率:宽度(像素)
yres __u32 可见分辨率:高度(像素)
xres_virtual __u32 虚拟分辨率:宽度(像素),≥ xres
yres_virtual __u32 虚拟分辨率:高度(像素),≥ yres
xoffset __u32 虚拟到可见的 X 偏移
yoffset __u32 虚拟到可见的 Y 偏移
bits_per_pixel __u32 每像素位数(如 16、24、32)
grayscale __u32 灰度标志:0=彩色,非0=灰度
red struct fb_bitfield 红色通道位域信息
green struct fb_bitfield 绿色通道位域信息
blue struct fb_bitfield 蓝色通道位域信息
transp struct fb_bitfield 透明度/Alpha 通道位域信息
nonstd __u32 非标准格式标志(0=标准 RGB)
activate __u32 激活模式(立即/下次刷新)
height __u32 物理高度(毫米)
width __u32 物理宽度(毫米)
pixclock __u32 像素时钟(皮秒)
left_margin __u32 行同步前沿(像素)
right_margin __u32 行同步后沿(像素)
upper_margin __u32 帧同步前沿(行)
lower_margin __u32 帧同步后沿(行)
hsync_len __u32 行同步脉冲长度(像素)
vsync_len __u32 帧同步脉冲长度(行)
sync __u32 同步标志(FB_SYNC_*)
vmode __u32 视频模式(FB_VMODE_*)
rotate __u32 旋转角度(0/90/180/270)

2.4.2 位域结构 fb_bitfield

struct fb_bitfield {
    __u32 offset;   // 颜色分量在像素中的起始位偏移
    __u32 length;   // 颜色分量的位数
    __u32 msb_right; // MSB 在右侧标志(非0表示 MSB 在最低位)
};

// 示例:32bpp RGB888 格式
// red:   offset=16, length=8, msb_right=0
// green: offset=8,  length=8, msb_right=0
// blue:  offset=0,  length=8, msb_right=0

2.5 struct fb_fix_screeninfo — 固定屏幕参数

struct fb_fix_screeninfo 描述硬件固定的参数,用户空间只能读取(通过 FBIOGET_FSCREENINFO),不能修改。这些参数在驱动初始化时设置,通常在整个生命周期内保持不变。

2.5.1 关键字段

字段名 类型 说明
id char[16] 设备名称标识符
smem_start unsigned long 显存物理起始地址
smem_len __u32 显存总大小(字节)
type __u32 显示类型(FB_TYPE_*)
type_aux __u32 类型辅助信息
visual __u32 视觉类型(FB_VISUAL_*)
xpanstep __u16 水平平移步长(像素),0=不支持
ypanstep __u16 垂直平移步长(像素),0=不支持
ywrapstep __u16 垂直环绕步长(像素),0=不支持
line_length __u32 每行字节数(行距)
mmio_start unsigned long MMIO 物理起始地址
mmio_len __u32 MMIO 区域大小(字节)
accel __u32 硬件加速类型(FB_ACCEL_*)
capabilities __u16 硬件能力标志

2.5.2 常用视觉类型

宏定义 值 说明
FB_VISUAL_TRUECOLOR 2 真彩色(RGB 直接编码)
FB_VISUAL_PSEUDOCOLOR 3 伪彩色(通过颜色查找表)
FB_VISUAL_DIRECTCOLOR 4 直接彩色(每个通道有独立查找表)
FB_VISUAL_STATIC_PSEUDOCOLOR 8 静态伪彩色(查找表不可修改)
FB_VISUAL_MONO01 0 单色:0=白,1=黑
FB_VISUAL_MONO10 1 单色:0=黑,1=白

2.6 数据结构对比总结

下表从多个维度对比四个核心数据结构:

对比维度 fb_info fb_ops fb_var_screeninfo fb_fix_screeninfo
角色 设备描述符 操作函数表 可变参数 固定参数
用户访问 内核内部使用 内核内部使用 可读可写(ioctl) 只读(ioctl)
修改时机 驱动初始化 驱动初始化 运行时动态修改 驱动初始化固定
包含内容 所有子结构 + 设备状态 回调函数指针 分辨率、位深、时序 显存地址、行长、类型
对应 ioctl — — FBIOPUT_VSCREENINFO
FBIOGET_VSCREENINFO
FBIOGET_FSCREENINFO
驱动实现重点 分配、填充、注册 实现回调函数 check_var + set_par 初始化时正确填充

2.7 用户空间交互流程

下图展示了用户空间应用程序通过 ioctl 与 FrameBuffer 核心数据结构交互的完整流程:

用户空间与 FrameBuffer 数据结构交互流程 用户空间应用 /dev/fb0 系统调用层 ioctl / mmap / read / write fb 核心层 fbmem.c / fbcon.c 数据结构层 fb_info → fb_ops → fb_var_screeninfo / fb_fix_screeninfo 硬件层 ← 上一章 📖 返回目录 下一章 →