2. Framebuffer基础回顾:FB设备驱动模型、核心数据结构与关键操作函数

在深入DRM之前,必须牢固掌握Framebuffer(FB)设备驱动模型。FB是Linux内核中最早用于显示输出的统一抽象层,它将显示缓冲区抽象为一个可直接读写的内存区域,用户空间通过/dev/fbX设备节点操作显示。本节从驱动模型、核心数据结构struct fb_info以及关键操作函数三个维度进行系统回顾。

2.1 FB设备驱动模型架构

FB驱动模型采用“平台设备驱动”或“PCI设备驱动”的注册方式,核心是struct fb_info实例的分配、初始化与注册。整体架构分为三层:

  • 硬件层:包含LCD控制器、DMA引擎、显存(VRAM)等物理资源。
  • 驱动层:实现struct fb_ops中的回调函数,管理显存映射、寄存器配置、电源控制。
  • 核心层:内核fbcon(帧缓冲控制台)和fbmem(帧缓冲内存管理)提供统一的文件操作接口。
关键认知:FB模型将显示设备简化为“一块内存+一组控制寄存器”,所有上层图形栈(X11、Wayland、Qt)最终通过mmap映射显存进行像素操作。
FB设备驱动模型分层架构 FB设备驱动模型分层架构 用户空间:/dev/fbX | fbcon | X11/Wayland 内核核心层:fbmem.c | fbcon.c | fb_defio.c 驱动层:struct fb_info + struct fb_ops 实现 硬件层:LCD控制器 | DMA引擎 | VRAM显存 说明:用户空间通过系统调用进入核心层,核心层调用驱动层fb_ops,驱动层直接操作硬件寄存器

2.2 核心数据结构:struct fb_info

struct fb_info是FB驱动的“心脏”,每个显示设备对应一个实例。该结构体定义在linux/fb.h中,包含以下关键字段:

字段 类型 作用描述
fbops struct fb_ops * 指向操作函数表,驱动必须实现
fb_var_screeninfo struct fb_var_screeninfo 可变参数:分辨率、位深、时序、虚拟分辨率
fb_fix_screeninfo struct fb_fix_screeninfo 固定参数:显存物理地址、长度、行字节数
screen_base void __iomem * 显存虚拟地址基址,用于CPU直接访问
screen_size unsigned long 显存总大小(字节)
device struct device * 关联的Linux设备模型节点
par void * 驱动私有数据指针,存放硬件寄存器基址等
pseudo_palette u32 * 伪调色板,用于8bpp索引色模式
移植经验:在嵌入式平台移植时,screen_base通常通过ioremap或dma_alloc_coherent获得。par字段是驱动私有数据的“万能口袋”,建议将寄存器基址、时钟结构体、GPIO描述符等全部放入自定义结构体,通过par指针访问。
struct fb_info 核心字段关系 struct fb_info 核心字段关系 struct fb_info fbops → struct fb_ops fb_var_screeninfo fb_fix_screeninfo screen_base / screen_size par (私有数据) 说明:fb_var_screeninfo 和 fb_fix_screeninfo 共同描述显示模式与显存布局 驱动通过 fbops 回调响应应用层的 ioctl 查询/设置请求

2.3 关键操作函数:struct fb_ops

struct fb_ops是驱动与内核核心层的“契约”,驱动必须实现其中部分回调。以下是移植中最常涉及的函数:

函数原型 触发时机 典型实现内容
fb_open / fb_release 应用层open/close /dev/fbX 电源管理计数、时钟使能/禁能
fb_setcolreg 设置调色板寄存器(伪彩色模式) 写入硬件CLUT(颜色查找表)
fb_blank 控制台切换或电源管理事件 开关LCD背光、进入/退出睡眠模式
fb_check_var 应用层通过FBIOPUT_VSCREENINFO设置模式前 验证分辨率、时序、位深是否在硬件能力内,修正非法参数
fb_set_par 参数验证通过后,实际配置硬件 设置LCD控制器寄存器:HBP、HFP、VBP、VFP、像素时钟分频
fb_pan_display 应用层请求虚拟分辨率平移 更新显存起始偏移地址寄存器,实现无撕裂滚动
fb_mmap 应用层mmap映射显存 将物理显存映射到用户空间虚拟地址
fb_ioctl 自定义ioctl命令 扩展硬件特定功能(如背光亮度、旋转角度)
常见移植陷阱:
  • fb_check_var 必须严格校验时序参数,否则可能导致硬件锁死或花屏。
  • fb_set_par 中配置像素时钟时,注意PLL分频系数计算,避免超出LCD面板规格。
  • fb_mmap 必须使用 pgprot_noncached 或 pgprot_writecombine 设置显存缓存属性,否则CPU写入无法被DMA及时看到。

2.4 驱动注册与注销流程

一个典型的FB驱动加载流程如下:

  1. 分配fb_info:调用 framebuffer_alloc() 分配 struct fb_info 实例。
  2. 填充固定参数:设置 fb_fix_screeninfo 中的 smem_start(物理地址)、smem_len(显存大小)、line_length(行字节数)。
  3. 填充可变参数:设置 fb_var_screeninfo 的默认分辨率、位深、时序。
  4. 注册fb_ops:将实现的回调函数指针赋值给 fb_info->fbops。
  5. 注册设备:调用 register_framebuffer() 将设备注册到内核。
  6. 注销:模块卸载时调用 unregister_framebuffer() 和 framebuffer_release()。
FB驱动注册与注销流程 FB驱动注册与注销流程 1. framebuffer_alloc() 分配fb_info 2. 填充 fix / var screeninfo 3. 赋值 fbops 回调函数指针 4. register_framebuffer() 注册 5. 卸载时 unregister + release 注意:register_framebuffer() 成功后,/dev/fbX 节点自动创建,用户空间即可操作

2.5 用户空间操作示例

以下代码展示应用层如何通过FB接口获取显示参数并直接绘制像素:

#include <stdio.h>
#include <stdlib.h>
#include <fcntl.h>
#include <unistd.h>
#include <sys/mman.h>
#include <linux/fb.h>

int main() {
    int fbfd = open("/dev/fb0", O_RDWR);
    if (fbfd < 0) { perror("open"); return -1; }

    struct fb_var_screeninfo vinfo;
    struct fb_fix_screeninfo finfo;

    // 获取可变参数(分辨率、位深)
    ioctl(fbfd, FBIOGET_VSCREENINFO, &vinfo);
    // 获取固定参数(显存地址、行字节数)
    ioctl(fbfd, FBIOGET_FSCREENINFO, &finfo);

    printf("分辨率: %dx%d, 位深: %d\n",
           vinfo.xres, vinfo.yres, vinfo.bits_per_pixel);

    long screensize = finfo.line_length * vinfo.yres;
    char *fbp = mmap(NULL, screensize, PROT_READ | PROT_WRITE,
                     MAP_SHARED, fbfd, 0);
    if (fbp == MAP_FAILED) { perror("mmap"); close(fbfd); return -1; }

    // 将屏幕中间区域填充为红色 (RGB565: 0xF800)
    int x = vinfo.xres / 2, y = vinfo.yres / 2;
    long location = (x + vinfo.xres * y) * (vinfo.bits_per_pixel / 8);
    *((unsigned short *)(fbp + location)) = 0xF800;

    munmap(fbp, screensize);
    close(fbfd);
    return 0;
}
移植要点:上述代码在DRM框架下不再适用。DRM要求通过drmModeSetCrtc、drmModeAddFB等API操作,且显存映射通过drmPrimeHandleToFD或mmap on drm fd完成。理解FB的ioctl模型有助于对比理解DRM的drmModeObject体系。

2.6 FB与DRM核心差异速览

对比维度 Framebuffer (FB) Direct Rendering Manager (DRM)
设备节点 /dev/fbX /dev/dri/cardX
核心数据结构 struct fb_info struct drm_device + struct drm_crtc + struct drm_plane
显存管理 单一线性显存,无GEM/DMA-BUF GEM对象 + DMA-BUF导出/导入
多图层支持 不支持硬件图层叠加 支持多个plane叠加合成
垂直同步 无原生VSync控制 通过page_flip事件精确控制
GPU加速 无直接支持 原生集成GPU命令提交
现代显示特性 不支持HDMI/DP音频、HDR、自适应同步 完整支持