4. Framebuffer 核心数据结构

在 Linux Framebuffer 驱动架构中,用户空间通过 /dev/fbX 设备文件与显示硬件交互,而驱动内部则依赖三个核心数据结构来管理显示参数、硬件能力与内存映射。理解 struct fb_info、struct fb_var_screeninfo 和 struct fb_fix_screeninfo 是编写 Framebuffer 驱动的第一步。

核心要点:这三个结构体分别承担“驱动实例管理”、“可变显示参数”和“固定硬件参数”的角色,共同构成了用户态 ioctl 操作与内核态硬件控制之间的数据桥梁。

4.1 struct fb_info —— 驱动核心实例

struct fb_info 是 Framebuffer 驱动中最重要的数据结构,每个 Framebuffer 设备对应一个 fb_info 实例。它包含了设备的所有状态信息、操作函数指针、内存映射地址以及指向 var 和 fix 结构体的指针。

struct fb_info {
    struct fb_var_screeninfo var;   /* 可变参数:分辨率、位深、时序 */
    struct fb_fix_screeninfo fix;   /* 固定参数:内存起始、步长、类型 */
    struct fb_ops *fbops;           /* 操作函数集 */
    struct device *device;          /* 关联的设备结构体 */
    char __iomem *screen_base;      /* 显存虚拟地址基址 */
    unsigned long screen_size;      /* 显存总大小(字节) */
    struct fb_pixmap pixmap;        /* 像素映射辅助 */
    struct fb_deferred_io deferred_io; /* 延迟IO支持 */
    /* ... 其他成员 */
};
驱动开发提示:在 probe 函数中,开发者需要先分配 struct fb_info(使用 framebuffer_alloc),然后填充 var、fix 和 fbops,最后调用 register_framebuffer 注册设备。
struct fb_info 核心成员关系 struct fb_info fb_var_screeninfo var fb_fix_screeninfo fix fb_ops *fbops screen_base / screen_size device / pixmap deferred_io 说明:fb_info 是驱动核心,包含可变参数(var)、固定参数(fix)、操作函数集(fbops)和显存地址(screen_base)。 驱动注册时需完整填充这些成员,用户态通过 ioctl 间接访问 var 和 fix。

4.2 struct fb_var_screeninfo —— 可变显示参数

该结构体描述用户可动态调整的显示参数,包括分辨率、颜色深度、像素格式以及时序信息。用户态应用程序通过 FBIOPUT_VSCREENINFO 和 FBIOGET_VSCREENINFO ioctl 命令读写这些参数。

成员名 类型 描述 典型值
xres __u32 可见区域水平分辨率(像素) 1024
yres __u32 可见区域垂直分辨率(像素) 768
xres_virtual __u32 虚拟水平分辨率(支持双缓冲) 1024
yres_virtual __u32 虚拟垂直分辨率(支持双缓冲) 1536
bits_per_pixel __u32 每像素位数(颜色深度) 16 / 24 / 32
red / green / blue / transp struct fb_bitfield RGB 颜色分量位域偏移和长度 5-6-5 / 8-8-8-8
pixclock __u32 像素时钟(皮秒) 39683 (25.175MHz)
left_margin / right_margin __u32 水平消隐前后肩 48 / 16
upper_margin / lower_margin __u32 垂直消隐前后肩 33 / 10
hsync_len / vsync_len __u32 行/场同步脉冲宽度 96 / 2
vmode __u32 显示模式(非隔行/隔行/双扫描) FB_VMODE_NONINTERLACED
常见陷阱:用户态设置 bits_per_pixel 时,驱动必须检查硬件是否支持该深度。如果硬件只支持 16bpp,而用户请求 32bpp,驱动应在 fb_check_var 回调中修正参数或返回错误。另外,xres_virtual 和 yres_virtual 通常用于实现双缓冲滚动,驱动需确保虚拟分辨率对应的显存不超出实际分配大小。
fb_var_screeninfo 时序参数与显示扫描关系 显示时序参数与扫描行关系 一行完整扫描线(水平方向) HSYNC 左边界 可见区域 (xres 像素) 右边界 HSYNC 垂直方向:VSYNC + 上边界 + yres 可见行 + 下边界 + VSYNC 关键时序参数:pixclock 决定像素输出速率;hsync_len 和 vsync_len 控制同步脉冲宽度。 left_margin/right_margin 对应消隐前后肩,驱动需根据显示器 EDID 或硬件手册精确设置。 用户态通过 FBIOPUT_VSCREENINFO 设置这些参数,驱动在 fb_check_var 中验证合法性。

4.3 struct fb_fix_screeninfo —— 固定硬件参数

该结构体描述硬件固定的属性,在驱动初始化时设定,用户态只能读取(通过 FBIOGET_FSCREENINFO),不能修改。它主要提供显存映射信息和硬件能力标识。

struct fb_fix_screeninfo {
    char id[16];                /* 设备标识字符串,如 "s3cfb" */
    unsigned long smem_start;   /* 显存物理起始地址 */
    __u32 smem_len;             /* 显存总长度(字节) */
    __u32 type;                 /* 显示类型:FB_TYPE_PACKED_PIXELS 等 */
    __u32 type_aux;             /* 辅助类型(通常为 0) */
    __u32 visual;               /* 颜色模式:FB_VISUAL_TRUECOLOR 等 */
    __u16 xpanstep;             /* 硬件支持的 x 方向滚动步长 */
    __u16 ypanstep;             /* 硬件支持的 y 方向滚动步长 */
    __u16 ywrapstep;            /* 硬件支持的 y 方向环绕步长 */
    __u32 line_length;          /* 一行像素占用的字节数(步长) */
    unsigned long mmio_start;   /* 内存映射 IO 物理地址 */
    __u32 mmio_len;             /* 内存映射 IO 长度 */
    __u32 accel;                /* 硬件加速类型 */
    __u16 capabilities;         /* 能力标志位 */
    /* ... 保留字段 */
};
成员 说明 典型值
id 设备名称,用户态可通过 /sys/class/graphics/fb0/name 读取 "s3cfb" / "mxcfb"
smem_start 显存物理地址,用于 mmap 映射到用户空间 0x4E000000
smem_len 显存大小,决定最大分辨率支持 4 * 1024 * 1024
type 像素数据打包方式 FB_TYPE_PACKED_PIXELS
visual 颜色视觉模式 FB_VISUAL_TRUECOLOR
line_length 每行字节数 = xres * (bits_per_pixel / 8),可能因对齐而大于理论值 4096
accel 硬件加速类型,0 表示无加速 FB_ACCEL_NONE
mmap 映射关键:用户态应用程序通过 mmap(NULL, smem_len, PROT_READ|PROT_WRITE, MAP_SHARED, fd, 0) 将 smem_start 对应的物理显存映射到用户空间虚拟地址。驱动中 fb_mmap 回调负责建立页表映射,通常直接使用 remap_pfn_range 或 dma_mmap_coherent。

4.4 三个结构体的协作关系

在 Framebuffer 驱动中,这三个结构体通过 fb_info 串联成一个整体。用户态 ioctl 操作最终会转化为对 var 和 fix 的读写,而 fbops 中的回调函数则负责验证参数、更新硬件寄存器。

fb_info / fb_var / fb_fix 协作流程 用户态应用程序 ioctl struct fb_info fb_var_screeninfo fb_fix_screeninfo 硬件寄存器设置 显存 DMA 映射 用户态 ioctl → fb_info → 分别更新 var(时序/分辨率) 和 fix(内存/步长) → 驱动回调操作硬件

4.5 关键差异对比

对比维度 fb_var_screeninfo fb_fix_screeninfo
可修改性 用户态可读写(通过 ioctl) 用户态只读,驱动初始化时设定
主要内容 分辨率、位深、时序、颜色格式 显存地址、长度、步长、硬件类型
更新时机 运行时动态切换(如游戏改变分辨率) 驱动 probe 时固定,一般不变化
驱动回调 fb_check_var + fb_set_par 无直接回调,通过 fb_set_par 间接更新
用户态获取命令 FBIOGET_VSCREENINFO FBIOGET_FSCREENINFO
用户态设置命令 FBIOPUT_VSCREENINFO 不支持设置
最佳实践:在驱动 probe 函数中,先填充 fix 结构体(显存地址、长度、步长等硬件固定信息),再设置 var 的默认值(如 1024x768@16bpp)。fbops 中的 fb_check_var 回调负责验证用户传入的 var 参数是否合法,fb_set_par 则根据验证后的 var 配置硬件寄存器并更新 fix.line_length。