2. fb_info 结构体成员总览:主要字段分类

帧缓冲驱动的核心数据结构是 fb_info,它位于 include/linux/fb.h 中,是驱动与内核帧缓冲层之间的唯一契约。一个完整的 fb_info 实例包含了描述硬件能力、当前显示模式、操作接口以及驱动私有状态的全部信息。本章按功能将其成员划分为四大类:固定信息、可变信息、操作函数 和 私有数据,并逐一说明每类字段的配置要点。

配置原则:固定信息在驱动生命周期内只赋值一次;可变信息随显示模式切换而更新;操作函数必须全部实现,否则内核可能拒绝注册;私有数据是驱动与硬件交互的桥梁,分配与释放必须配对。
fb_info 结构体四大分类关系图 fb_info 固定信息 可变信息 操作函数 私有数据 硬件能力 当前模式 驱动接口 硬件上下文

2.1 固定信息(fb_fix_screeninfo)

fb_fix_screeninfo 描述显示控制器的硬件固有属性,这些属性在驱动加载后不会随显示模式改变。驱动初始化时通过 fb_info.fix 字段赋值。

成员类型说明配置要点
idchar[16]驱动名称标识不超过16字符,用于 /proc/fb 显示
smem_startunsigned long帧缓冲物理基地址必须与硬件寄存器一致,非PCI设备可为0
smem_len__u32帧缓冲总长度(字节)至少覆盖最大分辨率所需显存
type__u32显示类型(FB_TYPE_PACKED_PIXELS等)绝大多数使用 FB_TYPE_PACKED_PIXELS
visual__u32颜色模式(FB_VISUAL_TRUECOLOR等)根据硬件颜色格式选择
line_length__u32一行像素的字节数由驱动根据分辨率计算,通常为 xres_virtual * bpp / 8
mmio_startunsigned longMMIO 物理基地址控制寄存器映射地址
mmio_len__u32MMIO 区域长度必须与硬件寄存器空间匹配
accel__u16硬件加速类型无加速填 FB_ACCEL_NONE
常见错误:忘记设置 line_length 或设置错误会导致用户空间计算帧缓冲偏移时出现花屏。建议在 fb_set_par() 回调中根据当前虚拟分辨率重新计算并更新该字段。

2.2 可变信息(fb_var_screeninfo)

fb_var_screeninfo 描述当前显示模式的可配置参数,包括分辨率、颜色深度、时序等。用户空间通过 FBIOPUT_VSCREENINFO ioctl 修改这些值,驱动需在 fb_ops.fb_set_par() 中响应变化。

成员类型说明配置要点
xres / yres__u32可见分辨率必须 ≤ xres_virtual / yres_virtual
xres_virtual / yres_virtual__u32虚拟分辨率(含显存中未显示部分)用于双缓冲或滚动,乘积 * bpp ≤ smem_len * 8
bits_per_pixel__u32每像素位数(bpp)常见值:16、24、32
red / green / blue / transpstruct fb_bitfield颜色通道位域TRUECOLOR 模式必须正确设置偏移和长度
pixclock__u32像素时钟(皮秒)决定刷新率,需根据硬件 PLL 计算
left_margin / right_margin / upper_margin / lower_margin__u32显示时序消隐参数必须符合显示器规格,否则黑屏
hsync_len / vsync_len__u32同步脉冲宽度单位:像素/行
vmode__u32显示模式(FB_VMODE_NONINTERLACED等)通常为 FB_VMODE_NONINTERLACED
时序验证:不要假设用户空间传入的时序参数一定合法。驱动应在 fb_check_var() 回调中校验所有时序值,超出硬件范围时返回 -EINVAL 或自动修正到最近的有效值。

2.3 操作函数(fb_ops)

fb_ops 是驱动向内核帧缓冲层注册的函数指针集合,所有与硬件交互的操作都通过这个结构体间接调用。内核帧缓冲层在 ioctl 路径中自动分发请求到对应的回调。

回调函数原型必须实现典型职责
fb_openint (*)(struct fb_info *, int)否打开计数、资源引用
fb_releaseint (*)(struct fb_info *, int)否释放用户态引用
fb_read / fb_writessize_t (*)(...)否直接读写帧缓冲(默认使用 memcpy)
fb_check_varint (*)(struct fb_var_screeninfo *, struct fb_info *)是校验并修正可变参数
fb_set_parint (*)(struct fb_info *)是根据 var 配置硬件寄存器
fb_setcolregint (*)(unsigned, unsigned, unsigned, unsigned, unsigned, struct fb_info *)伪彩色必须设置颜色查找表(CLUT)
fb_blankint (*)(int, struct fb_info *)否电源管理:关闭/开启显示
fb_pan_displayint (*)(struct fb_var_screeninfo *, struct fb_info *)否虚拟显示滚动
fb_fillrect / fb_copyarea / fb_imageblitvoid (*)(...)否图形加速(无加速可填 cfb_* 系列)
fb_ioctlint (*)(struct fb_info *, unsigned int, unsigned long)否自定义 ioctl 扩展
// 最小化 fb_ops 配置示例
static struct fb_ops myfb_ops = {
    .owner          = THIS_MODULE,
    .fb_check_var   = myfb_check_var,
    .fb_set_par     = myfb_set_par,
    .fb_setcolreg   = myfb_setcolreg,
    .fb_fillrect    = cfb_fillrect,    // 使用内核通用实现
    .fb_copyarea    = cfb_copyarea,
    .fb_imageblit   = cfb_imageblit,
};
加速回调:如果硬件不支持 2D 加速,直接使用 cfb_fillrect、cfb_copyarea、cfb_imageblit 这三个内核提供的软件实现,避免留下空指针导致内核崩溃。

2.4 私有数据(par / pseudo_palette / screen_base)

私有数据是驱动与硬件之间的上下文通道,帧缓冲层不解析其内容,完全由驱动自主管理。合理组织私有数据可以大幅提高代码可维护性。

成员类型用途配置要点
parvoid *驱动私有数据结构指针通常包含硬件寄存器虚拟地址、时钟配置、电源状态等
pseudo_palette__u32 *伪彩色/真彩色调色板缓存TRUECOLOR 模式时用于缓存颜色转换值,大小通常为 16 个 __u32
screen_basechar __iomem *帧缓冲虚拟地址由 ioremap() 或 dma_alloc_coherent() 返回
screen_sizeunsigned long帧缓冲虚拟地址空间大小必须与 smem_len 一致
fbopsstruct fb_ops *指向操作函数结构体通常指向静态全局的 fb_ops 实例
devicestruct device *关联的 Linux 设备结构体由 platform_device 或 pci_dev 传入
nodeint帧缓冲设备号(/dev/fbN)由 register_framebuffer() 自动分配
// 私有数据结构体典型定义
struct myfb_par {
    void __iomem    *regs;          // 控制寄存器虚拟地址
    unsigned long   regs_phys;      // 控制寄存器物理地址
    unsigned long   regs_size;      // 寄存器空间大小
    int             irq;            // 中断号
    struct clk      *pixel_clk;     // 像素时钟
    struct regulator *power;        // 电源控制
    u32             pseudo_palette[16]; // 调色板缓存
};
内存管理:par 指向的内存通常在 probe() 中使用 devm_kzalloc() 分配,由设备驱动模型自动释放。screen_base 如果是通过 ioremap() 映射的,必须在 remove() 中调用 iounmap() 释放。
fb_info 初始化流程与字段依赖关系 1. 分配 fb_info 2. 填充 fix 固定信息 3. 设置默认 var 可变信息 4. 注册 fb_ops 操作函数 5. 分配并初始化 par 6. register_framebuffer() 依赖:硬件寄存器地址、显存大小 line_length 可暂填,set_par 时更新 依赖:fix.smem_len 必须已赋值 xres*yres*bpp ≤ smem_len*8 依赖:fb_check_var / fb_set_par 必须实现,否则注册失败 依赖:screen_base 必须 ioremap par 中保存硬件上下文

2.5 字段配置优先级与常见陷阱

在初始化 fb_info 时,字段之间存在隐式依赖关系。以下列表总结了配置顺序和常见错误:

  • 先 fix 后 var:smem_len 必须在设置 xres_virtual * yres_virtual * bpp / 8 之前确定,否则可能超出显存范围。
  • screen_base 与 smem_start 一致:如果使用 ioremap() 映射物理显存,screen_base 必须指向映射后的虚拟地址,smem_start 保持物理地址不变。
  • pseudo_palette 生命周期:该指针指向的缓存必须在 fb_info 注销前有效。推荐将其嵌入 par 结构体或使用静态数组。
  • fbops 不能为 NULL:即使所有回调都使用默认实现,fbops 指针也必须指向一个有效的 fb_ops 实例,且 .owner 必须设置为 THIS_MODULE。
  • node 由内核赋值:驱动不要手动修改 node 字段,register_framebuffer() 会自动分配设备号。
致命错误:如果 fb_check_var 或 fb_set_par 为 NULL,register_framebuffer() 会直接返回 -EINVAL,驱动加载失败。这是内核帧缓冲层最严格的校验之一,务必在注册前确认这两个回调已赋值。

2.6 小结