1. 帧缓冲驱动基础:核心概念与架构解析

帧缓冲(Framebuffer)是 Linux 内核中为显示设备提供的一种抽象层,它将显存映射到用户空间,使应用程序可以直接操作像素数据,而无需关心底层显示控制器的具体寄存器细节。本章从设备概念、软件架构和核心数据结构三个维度,建立帧缓冲驱动的完整知识基座。

1.1 帧缓冲设备概念

帧缓冲设备在 Linux 中表现为 /dev/fb0、/dev/fb1 等字符设备,用户程序通过 mmap() 将显存映射到进程地址空间,直接读写像素数据。其核心特征包括:

  • 统一接口:无论底层是 LCD、HDMI 还是 VGA,用户态均通过 ioctl 和 mmap 操作。
  • 双缓冲支持:通过 FBIOPAN_DISPLAY 实现页切换,避免撕裂。
  • 硬件无关性:驱动层封装了时序、时钟、DMA 等硬件细节。
关键理解:帧缓冲不是 GPU 或 3D 加速器,它只提供最基础的像素帧操作,适合嵌入式设备、控制台和轻量级 GUI。

1.2 fbdev 架构分层

fbdev(Framebuffer Device)是 Linux 内核中帧缓冲驱动的标准框架,分为三层:

层次 文件/模块 职责
用户空间 应用程序 / libdrm 通过 open/ioctl/mmap 访问帧缓冲
核心层 drivers/video/fbdev/core/fbmem.c 设备注册、文件操作接口、ioctl 分发
硬件驱动层 drivers/video/fbdev/*/xxxfb.c 具体显示控制器初始化、寄存器配置、DMA 设置

核心层与硬件驱动层通过 struct fb_info 和 struct fb_ops 交互,驱动只需填充这些结构体并调用 register_framebuffer() 即可完成注册。

fbdev 三层软件架构 用户空间 应用程序 / GUI 库 / 控制台 核心层 (fbmem.c) 设备注册 / 文件操作 / ioctl 分发 硬件驱动层 (xxxfb.c) 显示控制器初始化 / 寄存器配置 / DMA 交互接口:struct fb_info + struct fb_ops → register_framebuffer()

1.3 核心数据结构:struct fb_info

struct fb_info 是帧缓冲驱动的中枢,每个注册的帧缓冲设备对应一个实例。它包含了设备的所有状态、操作函数指针、参数配置和私有数据。定义位于 include/linux/fb.h,主要字段如下:

字段 类型 说明
fbops struct fb_ops * 操作函数表,包括 fb_open/fb_release/fb_ioctl/fb_mmap/fb_setcolreg 等
var struct fb_var_screeninfo 可变参数:分辨率、位深、时序、虚拟分辨率、偏移量
fix struct fb_fix_screeninfo 固定参数:显存物理地址、长度、行宽、类型
screen_base char __iomem * 显存虚拟地址基址,用户 mmap 的映射源
screen_size unsigned long 显存总大小(字节)
device struct device * 关联的 Linux 设备模型节点
par void * 驱动私有数据指针,用于存放硬件寄存器基址、时钟配置等
pseudo_palette void * 伪调色板,用于 8/16 位色深下的颜色查找表
state int 设备状态:FBINFO_STATE_RUNNING / FBINFO_STATE_SUSPENDED
驱动开发要点:自定义 ioctl 扩展时,fbops->fb_ioctl 是入口函数,通过 fb_info->par 访问硬件私有数据,通过 fb_info->var 和 fb_info->fix 获取当前显示参数。

1.4 struct fb_ops 操作函数表

struct fb_ops 定义了驱动必须实现或可选实现的回调函数,核心成员包括:

  • fb_open / fb_release:设备打开/关闭时的钩子,可用于电源管理或引用计数。
  • fb_read / fb_write:通过 read/write 系统调用访问显存,通常直接读写 screen_base。
  • fb_ioctl:自定义 ioctl 命令的入口,也是本课程扩展开发的核心战场。
  • fb_mmap:将显存映射到用户空间,通常调用 pgprot_noncached() 设置缓存属性。
  • fb_setcolreg:设置颜色寄存器,用于伪彩色模式下的调色板更新。
  • fb_pan_display:实现虚拟屏幕的平移,用于双缓冲或滚动。
  • fb_blank:控制显示器的开关/休眠。
// 典型的 fb_ops 定义示例
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_ioctl       = myfb_ioctl,      // 自定义 ioctl 入口
    .fb_mmap        = myfb_mmap,
    .fb_setcolreg   = myfb_setcolreg,
    .fb_pan_display = myfb_pan_display,
    .fb_blank       = myfb_blank,
};

1.5 可变参数与固定参数结构体

struct fb_var_screeninfo 和 struct fb_fix_screeninfo 分别描述可动态调整和硬件固定的显示属性:

结构体 关键字段 说明
fb_var_screeninfo xres, yres, bits_per_pixel 可见分辨率与色深
xres_virtual, yres_virtual 虚拟分辨率(可大于可见区域,用于双缓冲)
pixclock, left_margin, right_margin 显示时序参数(像素时钟、行/场消隐)
activate 参数生效模式:立即 / 下次刷新
fb_fix_screeninfo smem_start, smem_len 显存物理地址与长度
line_length 一行像素占用的字节数(含对齐填充)
type, visual 显示类型(PACKED_PIXELS/PLANAR)与颜色模式(TRUECOLOR/PSEUDOCOLOR)
struct fb_info 核心字段关系 struct fb_info fbops → struct fb_ops var → fb_var_screeninfo fix → fb_fix_screeninfo screen_base / screen_size par → 驱动私有数据 pseudo_palette 驱动初始化流程:分配 fb_info → 填充 fb_ops/var/fix/par → register_framebuffer() 自定义 ioctl 通过 fb_ioctl 回调访问 fb_info 所有字段

1.6 设备注册与注销流程

帧缓冲驱动的生命周期管理遵循标准的平台驱动模型:

  1. probe 阶段:分配 struct fb_info(framebuffer_alloc()),填充 fbops/var/fix/par,申请显存 DMA 缓冲区,最后调用 register_framebuffer() 注册到核心层。
  2. 运行阶段:用户通过 /dev/fbX 访问,核心层通过 fb_info 分发操作到驱动回调。
  3. remove 阶段:调用 unregister_framebuffer() 注销设备,释放显存和 fb_info(framebuffer_release())。
// 驱动 probe 函数简化示例
static int myfb_probe(struct platform_device *pdev)
{
    struct fb_info *fbi;
    struct myfb_par *par;

    // 1. 分配 fb_info 及私有数据
    fbi = framebuffer_alloc(sizeof(struct myfb_par), &pdev->dev);
    if (!fbi)
        return -ENOMEM;

    par = fbi->par;
    // 2. 填充操作函数表
    fbi->fbops = &myfb_ops;
    // 3. 设置可变参数(分辨率、色深)
    fbi->var.xres = 800;
    fbi->var.yres = 600;
    fbi->var.bits_per_pixel = 32;
    // 4. 设置固定参数(显存地址、行宽)
    fbi->fix.smem_start = dma_alloc_coherent(...);
    fbi->fix.smem_len = 800 * 600 * 4;
    fbi->fix.line_length = 800 * 4;
    // 5. 注册帧缓冲设备
    if (register_framebuffer(fbi) < 0) {
        framebuffer_release(fbi);
        return -EINVAL;
    }
    platform_set_drvdata(pdev, fbi);
    return 0;
}
常见陷阱:fb_info->screen_base 必须使用 ioremap 或 dma_alloc_coherent 映射,不能直接使用物理地址;fb_ops 中的 owner 必须设置为 THIS_MODULE,否则模块卸载时可能导致内核崩溃。

1.7 本章小结