4. fb_var_screeninfo 详解:可变参数结构体

fb_var_screeninfo 是 Framebuffer 驱动中描述显示设备可变参数的核心结构体。与固定不变的 fb_fix_screeninfo 不同,该结构体中的字段允许在运行时通过 FBIOPUT_VSCREENINFO 命令动态修改,从而实现分辨率切换、位深调整、像素格式变更以及时序参数重配等操作。本章将逐一拆解其关键字段,并给出典型配置示例。

核心概念: 可变参数结构体是用户态与内核态之间协商显示模式的桥梁。应用程序通过设置该结构体,驱动据此重新配置硬件控制器,实现显示模式的动态切换。

4.1 结构体总览与关键字段

fb_var_screeninfo 定义在 include/uapi/linux/fb.h 中,主要包含以下四大类参数:

参数类别 字段名 说明 典型值示例
分辨率 xres / yres 可见分辨率(有效显示区域) 1024 / 768
xres_virtual / yres_virtual 虚拟分辨率(含离屏缓存) 1024 / 768
位深与像素格式 bits_per_pixel 每个像素占用的比特数 32
red / green / blue / transp 各颜色分量的位偏移与长度 见 4.3 节
时序参数 pixclock 像素时钟周期(皮秒) 40000
left_margin / right_margin / upper_margin / lower_margin / hsync_len / vsync_len 行场消隐与同步脉冲宽度 见 4.4 节
同步与标志 sync / vmode 同步极性、隔行/渐进模式 FB_SYNC_HOR_HIGH_ACT

4.2 分辨率配置:可见与虚拟

分辨率字段分为可见分辨率和虚拟分辨率两组:

  • xres / yres:实际显示在屏幕上的像素宽度和高度。
  • xres_virtual / yres_virtual:Framebuffer 内存中实际分配的宽度和高度。虚拟分辨率可以大于可见分辨率,用于实现双缓冲、滚动显示等高级功能。
配置原则: 虚拟分辨率必须 ≥ 可见分辨率。当虚拟分辨率大于可见分辨率时,可通过设置 xoffset / yoffset 实现视口平移。
/* 典型配置:1024x768,虚拟分辨率与可见相同 */
info->var.xres = 1024;
info->var.yres = 768;
info->var.xres_virtual = 1024;
info->var.yres_virtual = 768;

4.3 位深与像素格式:颜色分量描述

bits_per_pixel 决定每个像素占用的比特数,常见值为 16、24、32。像素格式由 red、green、blue、transp 四个 fb_bitfield 结构体描述:

struct fb_bitfield {
    __u32 offset;   /* 颜色分量在像素中的起始位偏移 */
    __u32 length;   /* 颜色分量占用的比特数 */
    __u32 msb_right;/* 0: 左对齐(MSB 在最高位),非0: 右对齐 */
};

以下为三种常见像素格式的配置对照:

格式 bpp Red (offset/length) Green (offset/length) Blue (offset/length) Transp (offset/length)
RGB565 16 11 / 5 5 / 6 0 / 5 0 / 0
RGB888 24 16 / 8 8 / 8 0 / 8 0 / 0
ARGB8888 32 16 / 8 8 / 8 0 / 8 24 / 8
/* ARGB8888 格式配置示例 */
info->var.bits_per_pixel = 32;
info->var.red.offset   = 16; info->var.red.length   = 8;
info->var.green.offset = 8;  info->var.green.length = 8;
info->var.blue.offset  = 0;  info->var.blue.length  = 8;
info->var.transp.offset= 24; info->var.transp.length= 8;

4.4 时序参数:像素时钟与消隐区

时序参数决定了显示控制器如何扫描每一行和每一帧。关键字段包括:

  • pixclock:像素时钟周期,单位皮秒(ps)。频率 = 1e12 / pixclock (Hz)。
  • left_margin / right_margin:行消隐前肩和后肩(像素数)。
  • upper_margin / lower_margin:场消隐前肩和后肩(行数)。
  • hsync_len / vsync_len:行同步脉冲宽度(像素数)和场同步脉冲宽度(行数)。
时序配置陷阱: 不同 LCD 控制器对消隐区的前后定义可能相反(HBP vs HFP)。务必参考硬件数据手册,确认 left_margin 对应的是 HBP(Horizontal Back Porch)还是 HFP(Horizontal Front Porch)。
/* 典型 1024x768 @60Hz 时序配置 */
info->var.pixclock      = 40000;   /* 25 MHz 像素时钟 */
info->var.left_margin   = 160;     /* HBP */
info->var.right_margin  = 24;      /* HFP */
info->var.upper_margin  = 23;      /* VBP */
info->var.lower_margin  = 3;       /* VFP */
info->var.hsync_len     = 136;     /* 行同步宽度 */
info->var.vsync_len     = 6;       /* 场同步宽度 */

4.5 同步与模式标志

sync 字段控制同步信号的极性:

宏定义 含义
FB_SYNC_HOR_HIGH_ACT 行同步高电平有效
FB_SYNC_VERT_HIGH_ACT 场同步高电平有效
FB_SYNC_EXT 外部同步
FB_SYNC_COMP_HIGH_ACT 复合同步高电平有效

vmode 字段指定扫描模式:

  • FB_VMODE_NONINTERLACED:渐进扫描(逐行)。
  • FB_VMODE_INTERLACED:隔行扫描。
  • FB_VMODE_DOUBLE:每行扫描两次。

4.6 可变参数配置流程图

以下 SVG 展示了从用户态请求到驱动配置 fb_var_screeninfo 的完整流程:

fb_var_screeninfo 配置流程图 用户态应用 FBIOPUT_VSCREENINFO fb_ops.fb_set_par() 解析 var 参数 配置硬件寄存器 更新 fb_info.var 说明:驱动在 fb_set_par() 中根据 var 参数重新初始化显示控制器,并更新 fb_info.var 为当前生效值

4.7 参数校验与回退机制

驱动在 fb_set_par() 中必须对用户传入的 fb_var_screeninfo 进行合法性校验:

  1. 分辨率范围检查:确保 xres / yres 不超过硬件支持的最大值。
  2. 位深支持检查:确认 bits_per_pixel 在硬件支持的位深列表中。
  3. 像素时钟范围检查:pixclock 必须在 PLL 可生成的范围内。
  4. 时序参数合理性检查:消隐区与同步宽度不能为负,且满足最小/最大约束。
最佳实践: 当用户传入的参数不被硬件支持时,驱动应尝试调整到最接近的合法值,并通过 FBIOPUT_VSCREENINFO 的返回值回写实际生效的参数。应用程序可通过 FBIAGET_VSCREENINFO 读取调整后的值。
/* 参数校验与回退示例 */
static int myfb_set_par(struct fb_info *info)
{
    struct fb_var_screeninfo *var = &info->var;

    /* 1. 检查分辨率 */
    if (var->xres > 1920 || var->yres > 1080)
        return -EINVAL;

    /* 2. 检查位深 */
    if (var->bits_per_pixel != 16 && var->bits_per_pixel != 32)
        var->bits_per_pixel = 32;  /* 回退到默认32bpp */

    /* 3. 检查像素时钟范围 */
    if (var->pixclock < 10000 || var->pixclock > 100000)
        var->pixclock = 40000;     /* 回退到25MHz */

    /* 4. 配置硬件寄存器 */
    myfb_set_timing(var);
    myfb_set_format(var);

    return 0;
}

4.8 常见配置错误与排查

错误现象 可能原因 排查方向
屏幕无显示 pixclock 超出 PLL 范围 检查时钟树配置,确认 PLL 输出频率
图像偏移或撕裂 消隐区参数配置错误 核对 HBP/HFP 与数据手册是否一致
颜色显示异常 像素格式 offset/length 配置错误 确认 RGB 分量在内存中的实际排列顺序
屏幕闪烁 刷新率过低或 vsync_len 异常 计算实际帧率,调整时序参数
调试技巧: 在 fb_set_par() 中添加 dev_dbg() 打印所有 var 参数,与硬件数据手册中的时序表逐项比对。使用示波器测量 HSYNC/VSYNC 波形是验证时序配置最直接的方法。