4. fbdev核心数据结构深度解析
帧缓冲设备驱动(fbdev)的核心在于三组紧密关联的数据结构:struct fb_info(设备抽象)、struct fb_var_screeninfo(可变参数)和 struct fb_fix_screeninfo(固定参数)。这三者构成了用户空间与内核空间交互的契约,也是驱动开发者必须掌握的第一组核心概念。
4.1 struct fb_info:帧缓冲设备的“身份证”
struct fb_info 是 fbdev 框架中最顶层的结构体,每个注册到系统的帧缓冲设备都对应一个 fb_info 实例。它聚合了设备的所有属性、操作函数和状态信息。
struct fb_info {
atomic_t count; /* 引用计数 */
int node; /* 设备节点号(如 /dev/fb0 的 0) */
int flags; /* 设备标志位 */
struct mutex lock; /* 互斥锁 */
struct mutex mm_lock; /* 内存映射锁 */
struct fb_var_screeninfo var; /* 可变屏幕参数(分辨率、位深等) */
struct fb_fix_screeninfo fix; /* 固定屏幕参数(物理地址、步长等) */
struct fb_ops *fbops; /* 操作函数集 */
struct device *device; /* 内核设备结构体 */
struct device *dev; /* 帧缓冲设备 */
int class_flag; /* 类标志 */
struct fb_deferred_io *fbdefio; /* 延迟IO支持 */
struct fb_pixmap pixmap; /* 像素映射辅助 */
struct fb_pixmap sprite; /* 光标/精灵映射 */
struct fb_cursor cursor; /* 光标状态 */
struct fb_monspecs monspecs; /* 显示器规格 */
struct fb_videomode *mode; /* 当前视频模式 */
struct fb_videomode *modelist; /* 支持的模式列表 */
struct fb_ops *fbops; /* 操作函数指针 */
char __iomem *screen_base; /* 帧缓冲虚拟基地址 */
unsigned long screen_size; /* 帧缓冲大小(字节) */
void *pseudo_palette; /* 伪调色板 */
struct fb_info *par; /* 驱动私有数据 */
};
4.1.1 fb_info 生命周期与注册流程
一个帧缓冲设备从注册到卸载的典型流程如下:
- 分配:调用 framebuffer_alloc(size) 分配 fb_info 及私有数据空间。
- 初始化:填充 var、fix、fbops、screen_base、screen_size 等字段。
- 注册:调用 register_framebuffer(fb_info) 将设备注册到系统。
- 用户交互:通过 /dev/fbX 节点进行 read/write/mmap/ioctl 操作。
- 注销:调用 unregister_framebuffer(fb_info) 移除设备。
- 释放:调用 framebuffer_release(fb_info) 释放内存。
4.2 struct fb_var_screeninfo:可变参数的“调色盘”
struct fb_var_screeninfo 描述的是用户空间可以动态修改的显示参数,包括分辨率、位深、时序、虚拟屏幕尺寸等。用户通过 FBIOPUT_VSCREENINFO ioctl 写入,通过 FBIOGET_VSCREENINFO 读取。
struct fb_var_screeninfo {
__u32 xres; /* 可见分辨率:宽度(像素) */
__u32 yres; /* 可见分辨率:高度(像素) */
__u32 xres_virtual; /* 虚拟分辨率:宽度(像素) */
__u32 yres_virtual; /* 虚拟分辨率:高度(像素) */
__u32 xoffset; /* 虚拟到可见的偏移:水平 */
__u32 yoffset; /* 虚拟到可见的偏移:垂直 */
__u32 bits_per_pixel; /* 每像素位数(bpp) */
__u32 grayscale; /* 灰度标志:0=彩色,非0=灰度 */
struct fb_bitfield red; /* 红色通道位域 */
struct fb_bitfield green; /* 绿色通道位域 */
struct fb_bitfield blue; /* 蓝色通道位域 */
struct fb_bitfield transp; /* 透明度通道位域 */
__u32 nonstd; /* 非标准像素格式标志 */
__u32 activate; /* 激活模式标志 */
__u32 height; /* 显示器物理高度(mm) */
__u32 width; /* 显示器物理宽度(mm) */
__u32 accel_flags; /* 硬件加速标志(已废弃) */
__u32 pixclock; /* 像素时钟(皮秒) */
__u32 left_margin; /* 行同步:左边距 */
__u32 right_margin; /* 行同步:右边距 */
__u32 upper_margin; /* 帧同步:上边距 */
__u32 lower_margin; /* 帧同步:下边距 */
__u32 hsync_len; /* 水平同步脉冲长度 */
__u32 vsync_len; /* 垂直同步脉冲长度 */
__u32 sync; /* 同步极性标志 */
__u32 vmode; /* 视频模式(隔行/逐行等) */
__u32 rotate; /* 旋转角度 */
__u32 colorspace; /* 色彩空间 */
__u32 reserved[4]; /* 保留字段 */
};
4.2.1 可变参数与显示模式切换
当用户空间修改 var 参数时,驱动必须通过 fb_check_var 验证参数的合法性,然后通过 fb_set_par 将参数应用到硬件。下表列出了常见分辨率对应的典型 var 参数值:
| 参数 | 640×480@60Hz | 1024×768@60Hz | 1920×1080@60Hz |
|---|---|---|---|
| xres / yres | 640 / 480 | 1024 / 768 | 1920 / 1080 |
| bits_per_pixel | 32 | 32 | 32 |
| pixclock (ps) | 39721 | 15384 | 6734 |
| left_margin | 48 | 160 | 88 |
| right_margin | 16 | 24 | 44 |
| upper_margin | 33 | 29 | 4 |
| lower_margin | 10 | 3 | 5 |
| hsync_len | 96 | 136 | 148 |
| vsync_len | 2 | 6 | 36 |
4.3 struct fb_fix_screeninfo:固定参数的“硬件铭牌”
struct fb_fix_screeninfo 描述的是硬件固定不变的参数,在设备生命周期内通常只读。用户空间通过 FBIOGET_FSCREENINFO ioctl 获取这些信息。
struct fb_fix_screeninfo {
char id[16]; /* 设备标识字符串(如 "CLFB") */
unsigned long smem_start; /* 帧缓冲物理起始地址 */
__u32 smem_len; /* 帧缓冲长度(字节) */
__u32 type; /* 显示类型(如 FB_TYPE_PACKED_PIXELS) */
__u32 type_aux; /* 辅助类型 */
__u32 visual; /* 颜色模式(真彩色/伪彩色等) */
__u16 xpanstep; /* 水平滚动步长(像素) */
__u16 ypanstep; /* 垂直滚动步长(像素) */
__u16 ywrapstep; /* 垂直环绕步长 */
__u32 line_length; /* 一行占用的字节数(步长) */
unsigned long mmio_start; /* 内存映射IO物理起始地址 */
__u32 mmio_len; /* 内存映射IO长度 */
__u32 accel; /* 硬件加速类型 */
__u16 capabilities; /* 能力标志 */
__u16 reserved[2]; /* 保留字段 */
};
4.3.1 固定参数关键字段解析
| 字段 | 含义 | 典型值/说明 |
|---|---|---|
| smem_start | 帧缓冲物理地址 | 用于 mmap 建立 DMA 映射,用户空间不可直接访问 |
| smem_len | 帧缓冲总大小 | 通常 = xres_virtual × yres_virtual × (bpp/8) |
| line_length | 一行像素的字节数 | 可能大于 xres × (bpp/8),因硬件对齐要求 |
| visual | 颜色模式 | FB_VISUAL_TRUECOLOR / FB_VISUAL_PSEUDOCOLOR / FB_VISUAL_DIRECTCOLOR |
| type | 像素排列类型 | FB_TYPE_PACKED_PIXELS(最常见)/ FB_TYPE_PLANES / FB_TYPE_INTERLEAVED_PLANES |
| xpanstep / ypanstep | 滚动步长 | 0 表示不支持硬件滚动,非0表示步长对齐要求 |
4.4 三者的协作关系与数据流
下图展示了 struct fb_info、fb_var_screeninfo、fb_fix_screeninfo 三者之间的协作关系,以及用户空间与内核空间的交互路径:
4.5 数据结构间的计算关系
fb_var_screeninfo 和 fb_fix_screeninfo 之间存在紧密的计算依赖关系,驱动在 fb_set_par 中必须根据 var 参数重新计算 fix 中的 line_length 和 smem_len:
/* 典型计算逻辑 */
static int myfb_set_par(struct fb_info *info)
{
struct fb_var_screeninfo *var = &info->var;
struct fb_fix_screeninfo *fix = &info->fix;
/* 计算每行字节数(需硬件对齐) */
int bpp = var->bits_per_pixel;
int line_length = var->xres_virtual * bpp / 8;
/* 硬件可能要求 4 字节、8 字节或 16 字节对齐 */
line_length = ALIGN(line_length, 16);
fix->line_length = line_length;
/* 计算帧缓冲总大小 */
fix->smem_len = line_length * var->yres_virtual;
/* 配置硬件时序寄存器 */
write_hw_timing(var->pixclock, var->left_margin, /* ... */);
/* 更新屏幕基地址(如果支持双缓冲) */
info->screen_base = info->par->framebuffer_base;
info->screen_size = fix->smem_len;
return 0;
}
4.6 颜色模式与位域解析
struct fb_bitfield 用于描述每个颜色通道在像素中的位置和宽度,是理解真彩色/直接色模式的关键:
struct fb_bitfield {
__u32 offset; /* 通道在像素中的起始位偏移 */
__u32 length; /* 通道占用的位数 */
__u32 msb_right;/* 最高有效位是否在右侧(通常为0) */
};
对于常见的 32 位 ARGB 格式,位域配置如下:
| 通道 | offset | length | 说明 |
|---|---|---|---|
| red | 16 | 8 | 红色通道位于 bit[23:16] |
| green | 8 | 8 | 绿色通道位于 bit[15:8] |
| blue | 0 | 8 | 蓝色通道位于 bit[7:0] |
| transp | 24 | 8 | 透明度通道位于 bit[31:24] |
4.7 本章小结
- struct fb_info 是帧缓冲设备的统一抽象,聚合了可变参数、固定参数、操作函数集和硬件状态。
- struct fb_var_screeninfo 提供用户空间可动态修改的显示参数,驱动需通过 fb_check_var 和 fb_set_par 完成验证与生效。
- struct fb_fix_screeninfo 描述硬件固定属性,用户空间通过它获取帧缓冲的物理布局和颜色模式。
- 三者的协作构成了 fbdev 框架的数据契约,理解它们之间的关系是编写正确帧缓冲驱动的基础。
- line_length 的对齐计算、位域的正确配置、虚拟屏幕与双缓冲的实现是实际开发中的关键难点。