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 注册设备。
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 通常用于实现双缓冲滚动,驱动需确保虚拟分辨率对应的显存不超出实际分配大小。
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 中的回调函数则负责验证参数、更新硬件寄存器。
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。