2. fbdev 核心数据结构:struct fb_info、struct fb_var_screeninfo、struct fb_fix_screeninfo 的详细解析
在 Linux 内核 fbdev 子系统中,三个核心数据结构构成了整个显示框架的基石:struct fb_info 代表一个完整的帧缓冲设备实例,struct fb_var_screeninfo 描述可变显示参数,struct fb_fix_screeninfo 描述固定硬件参数。理解这三者的关系与内部细节,是进行兼容层设计与驱动迁移的前提。
核心概念: fbdev 采用“可变 + 固定”双结构描述显示模式。可变参数(分辨率、位深、时序)可由用户空间动态修改;固定参数(帧缓冲物理地址、内存大小、步长)由硬件决定,驱动初始化后通常不变。
2.1 struct fb_info:帧缓冲设备的核心实例
struct fb_info 是 fbdev 驱动中最重要的数据结构,每个注册的帧缓冲设备对应一个 fb_info 实例。它聚合了设备的所有状态、操作函数指针、底层内存管理和辅助数据。
struct fb_info {
atomic_t count; /* 引用计数 */
int node; /* 设备节点号(/dev/fbN 中的 N) */
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; /* 延迟 I/O 支持 */
struct fb_pixmap pixmap; /* 像素图辅助缓冲区 */
struct fb_pixmap sprite; /* 硬件光标辅助缓冲区 */
struct fb_cursor cursor; /* 光标状态 */
struct fb_monspecs monspecs; /* 显示器规格 */
struct fb_videomode *mode; /* 当前视频模式 */
struct fb_ops *fbops; /* 操作函数表 */
char __iomem *screen_base; /* 帧缓冲虚拟基地址 */
unsigned long screen_size; /* 帧缓冲总大小(字节) */
void *pseudo_palette; /* 伪调色板 */
struct fb_ops *fbops; /* 操作函数表 */
/* ... 更多辅助字段 */
};
迁移关注点: 在 DRM/KMS 兼容层设计中,
fb_info 的 screen_base 和 screen_size 是映射到 DRM GEM 对象的关键桥梁。fbops 中的 fb_open/fb_release/fb_ioctl 需要被兼容层拦截并转发到 DRM 核心。
struct fb_info 核心字段分类表
| 分类 | 字段名 | 说明 | 兼容层处理策略 |
|---|---|---|---|
| 设备标识 | node |
设备节点编号 | 由 DRM 主设备号映射 |
| 显示参数 | var |
可变参数(分辨率、位深) | 从 DRM CRTC/connector 状态转换 |
| 硬件参数 | fix |
固定参数(物理地址、步长) | 从 DRM GEM 对象属性填充 |
| 操作函数 | fbops |
驱动操作函数表 | 兼容层提供统一实现 |
| 内存管理 | screen_base |
帧缓冲虚拟地址 | 映射 DRM GEM 对象的 vaddr |
| 内存管理 | screen_size |
帧缓冲总大小 | 由 GEM 对象大小决定 |
| 辅助数据 | pseudo_palette |
伪调色板(8bpp 模式) | 兼容层模拟 |
2.2 struct fb_var_screeninfo:可变显示参数详解
struct fb_var_screeninfo 是用户空间与内核交互最频繁的结构体。它描述了显示模式中可由软件动态调整的参数,包括分辨率、颜色深度、像素时钟、时序参数等。应用程序通过 FBIOGET_VSCREENINFO 和 FBIOPUT_VSCREENINFO ioctl 进行读写。
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; /* 灰度标志(非零表示灰度) */
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]; /* 保留字段 */
};
可变参数关键字段分组
| 分组 | 字段 | 典型值示例 | 兼容层映射目标 |
|---|---|---|---|
| 分辨率 | xres, yres |
1920, 1080 | DRM connector 的 mode 信息 |
| 虚拟分辨率 | xres_virtual, yres_virtual |
1920, 2160(双缓冲) | DRM framebuffer 的宽高 |
| 颜色深度 | bits_per_pixel |
32 | DRM 像素格式(如 DRM_FORMAT_XRGB8888) |
| 位域 | red, green, blue, transp |
偏移 16,8,0;长度 8 | DRM 像素格式的位域定义 |
| 时序 | pixclock, left_margin, right_margin, hsync_len, upper_margin, lower_margin, vsync_len |
pixclock=14625 | DRM display mode 的时序字段 |
| 同步极性 | sync |
FB_SYNC_HOR_HIGH_ACT | DRM mode 的 flags |
| 旋转 | rotate |
0, 90, 180, 270 | DRM 旋转属性 |
迁移陷阱: fbdev 的
pixclock 单位是皮秒(picoseconds),而 DRM 的 clock 单位是 kHz。转换公式为:clock_khz = 1000000000 / pixclock_ps。位域结构 fb_bitfield 的 offset 和 length 需要精确映射到 DRM 四字符码(FourCC)格式的位布局。
2.3 struct fb_fix_screeninfo:固定硬件参数详解
struct fb_fix_screeninfo 描述帧缓冲设备的固定硬件特性,这些参数在驱动初始化时确定,用户空间只能读取(通过 FBIOGET_FSCREENINFO),不能修改。它提供了帧缓冲内存的物理布局信息。
struct fb_fix_screeninfo {
char id[16]; /* 设备标识字符串(如 "radeonfb") */
unsigned long smem_start; /* 帧缓冲物理起始地址 */
__u32 smem_len; /* 帧缓冲总长度(字节) */
__u32 type; /* 显示类型(如 FB_TYPE_PACKED_PIXELS) */
__u32 type_aux; /* 辅助类型(用于 interleaved 格式) */
__u32 visual; /* 颜色视觉类型(如 FB_VISUAL_TRUECOLOR) */
__u16 xpanstep; /* 水平 pan 步长(像素) */
__u16 ypanstep; /* 垂直 pan 步长(像素) */
__u16 ywrapstep; /* 垂直 wrap 步长(像素) */
__u32 line_length; /* 一行像素的字节数(步长) */
unsigned long mmio_start; /* 内存映射 I/O 物理起始地址 */
__u32 mmio_len; /* 内存映射 I/O 长度(字节) */
__u32 accel; /* 硬件加速类型 */
__u16 capabilities; /* 设备能力标志 */
__u16 reserved[2]; /* 保留字段 */
};
固定参数关键字段详解
| 字段 | 含义 | 典型值 | 兼容层实现方式 |
|---|---|---|---|
id |
设备标识字符串 | "drmfb" | 固定为 "drmfb" 或驱动名称 |
smem_start |
帧缓冲物理地址 | 0x10000000 | 从 DRM GEM 对象的物理地址获取(可能为 0 如果不可用) |
smem_len |
帧缓冲总大小 | 8294400 (1920×1080×4) | DRM GEM 对象大小 |
type |
显示类型 | FB_TYPE_PACKED_PIXELS | 固定为 PACKED_PIXELS |
visual |
颜色视觉类型 | FB_VISUAL_TRUECOLOR | 根据 DRM 像素格式确定 |
line_length |
行步长(字节) | 7680 (1920×4) | DRM framebuffer 的 pitch |
mmio_start |
MMIO 物理地址 | 0x10010000 | 从 DRM 设备获取(可能为 0) |
mmio_len |
MMIO 区域长度 | 65536 | 从 DRM 设备获取 |
兼容层实现要点:
smem_start 在兼容层中通常返回 0 或一个占位地址,因为 DRM 的 GEM 对象物理地址可能不连续或不可直接暴露给用户空间。用户空间应通过 mmap 操作获取虚拟地址,而非直接使用物理地址。line_length 必须与 DRM framebuffer 的 pitch 严格一致,否则会导致显示错位。
2.4 三结构体协作关系总结
三个核心数据结构在 fbdev 驱动中协同工作,形成完整的显示设备描述模型:
- struct fb_info:设备实例的“总控中心”,包含
var和fix作为子结构,以及操作函数表fbops和内存管理字段。 - struct fb_var_screeninfo:描述“软件可调”的显示模式参数,是用户空间配置显示的核心接口。
- struct fb_fix_screeninfo:描述“硬件固定”的内存布局参数,提供帧缓冲的物理描述。
兼容层设计核心原则: 在 DRM/KMS 兼容层中,
fb_info 作为“代理对象”存在,其 var 和 fix 字段的值从 DRM 核心状态动态转换而来,而非直接对应硬件寄存器。fbops 中的 ioctl 处理函数需要拦截 fbdev 特有的命令(如 FBIOPUT_VSCREENINFO),将其转换为 DRM 的 mode set 和 framebuffer 操作序列。