3. struct fb_fix_screeninfo 详解:id、smem_start、smem_len、type、visual 等字段配置
struct fb_fix_screeninfo 是帧缓冲驱动中描述“固定硬件特性”的核心结构体。与可变参数结构体 fb_var_screeninfo 不同,fb_fix_screeninfo 中的字段在硬件初始化后通常不再改变,它向用户空间暴露了帧缓冲设备的内存映射地址、长度、显示类型等底层物理属性。正确配置该结构体是驱动能够被 fbmem.c 核心层正确注册、用户空间能够通过 mmap 直接操作显存的前提。
核心原则:
fb_fix_screeninfo 描述的是“硬件是什么”,而 fb_var_screeninfo 描述的是“当前模式是什么”。前者在 fb_setup 或 fb_probe 阶段一次性填充,后者可能随 FBIOGET_VSCREENINFO / FBIOPUT_VSCREENINFO 动态变化。
3.1 结构体全景与关键字段速查
该结构体定义在 include/uapi/linux/fb.h 中。以下表格列出了驱动初始化时必须关注的字段及其配置要点:
| 字段名 | 类型 | 配置要点 | 典型值 / 说明 |
|---|---|---|---|
id |
char[16] |
设备标识字符串,必须唯一且以 '\0' 结尾 |
"mydrvfb"、"s3cfb" |
smem_start |
unsigned long |
显存物理起始地址,用于 mmap 映射 |
dma_alloc_coherent 返回的物理地址 |
smem_len |
__u32 |
显存总长度(字节),必须 ≥ 屏幕所需帧缓冲区大小 | screen_size 或 width * height * bpp / 8 |
type |
__u32 |
帧缓冲类型,决定像素排列与访问方式 | FB_TYPE_PACKED_PIXELS(最常用) |
visual |
__u32 |
颜色视觉模式,决定颜色映射方式 | FB_VISUAL_TRUECOLOR、FB_VISUAL_PSEUDOCOLOR |
line_length |
__u16 |
一行像素占用的字节数(含对齐填充) | width * bpp / 8 向上对齐到 4/8 字节 |
mmio_start |
unsigned long |
控制寄存器 MMIO 物理地址(可选) | platform_get_resource 获取的物理地址 |
mmio_len |
__u32 |
MMIO 区域长度 | 寄存器地址范围大小 |
accel |
__u16 |
硬件加速能力标志 | FB_ACCEL_NONE(无加速) |
避坑提示:
id 字段长度限制为 16 字节(含终止符),超过 15 个字符的字符串会导致内核缓冲区溢出。建议使用固定短名称,如 "fb_ili9341"。
3.2 字段深度解析与配置场景
3.2.1 id:设备标识的“身份证”
id 字段在用户空间通过 FBIOGET_FSCREENINFO 读取,用于识别具体硬件驱动。它不参与内核逻辑判断,但影响调试与用户态工具(如 fbset -i)的输出。配置时需注意:
- 必须使用
strncpy或snprintf确保不超过 15 个字符。 - 建议与驱动名称或设备树 compatible 属性对应,便于故障定位。
- 示例:
strncpy(fix->id, "mylcd_drv", sizeof(fix->id) - 1);
3.2.2 smem_start 与 smem_len:显存映射的基石
这两个字段是帧缓冲驱动最关键的配置项。smem_start 必须是物理地址,用户空间通过 mmap 将该物理地址映射到进程虚拟空间。配置流程如下:
- 在 probe 函数中分配 DMA 缓冲区:
dma_alloc_coherent(dev, size, &dma_phys, GFP_KERNEL)。 - 将返回的物理地址赋值给
smem_start:fix->smem_start = dma_phys。 - 将分配的大小赋值给
smem_len:fix->smem_len = size。 - 将虚拟地址保存到
info->screen_base,供驱动内部操作。
常见错误: 直接使用
kmalloc 分配内存并赋值给 smem_start。kmalloc 返回的是虚拟地址,不是物理地址,会导致 mmap 失败或访问错误内存。必须使用 dma_alloc_coherent 或 ioremap 处理物理地址。
3.2.3 type:像素排列方式
type 字段定义了帧缓冲中像素数据的组织格式。最常用的枚举值如下:
| 枚举值 | 含义 | 适用场景 |
|---|---|---|
FB_TYPE_PACKED_PIXELS |
像素数据连续紧密排列,无间隔 | 绝大多数 LCD、HDMI 显示设备 |
FB_TYPE_PLANES |
像素数据按位平面分离存储 | 早期 VGA 显卡、某些单色显示器 |
FB_TYPE_INTERLEAVED_PLANES |
位平面交错排列 | 某些特殊硬件帧缓冲 |
FB_TYPE_TEXT |
非图形模式,仅文本字符 | 终端控制台帧缓冲 |
对于现代嵌入式 LCD 控制器,几乎总是配置为 FB_TYPE_PACKED_PIXELS。
3.2.4 visual:颜色视觉模型
visual 字段决定了颜色映射方式,直接影响用户空间如何解释像素值。常见配置:
- FB_VISUAL_TRUECOLOR:每个像素直接包含 RGB 分量,无需查色表。适用于 16/24/32 bpp 的 LCD。
- FB_VISUAL_PSEUDOCOLOR:像素值是查色表索引,需要设置
fb_cmap。适用于 8 bpp 及以下的显示设备。 - FB_VISUAL_MONO01 / FB_VISUAL_MONO10:单色显示,0 代表黑或白取决于具体值。
- FB_VISUAL_DIRECTCOLOR:每个像素的 R/G/B 分量各自独立查表,较少使用。
配置决策树: 如果硬件支持 16 bpp 以上且 RGB 分量直接编码 → 使用
FB_VISUAL_TRUECOLOR;如果硬件仅支持 8 bpp 且需要调色板 → 使用 FB_VISUAL_PSEUDOCOLOR 并实现 fb_ops.fb_setcolreg。
3.3 字段配置关系与初始化流程 SVG
下图展示了在驱动 probe 函数中,fb_fix_screeninfo 各字段的配置顺序与依赖关系:
3.4 完整配置代码示例
以下代码片段展示了在 probe 函数中配置 fb_fix_screeninfo 的典型实现:
static int myfb_probe(struct platform_device *pdev)
{
struct fb_info *info;
struct fb_fix_screeninfo *fix;
struct resource *res;
dma_addr_t dma_phys;
void __iomem *vaddr;
size_t screen_size;
// 1. 分配 fb_info
info = framebuffer_alloc(0, &pdev->dev);
if (!info)
return -ENOMEM;
fix = &info->fix;
// 2. 分配 DMA 显存(物理连续)
screen_size = 800 * 480 * 32 / 8; // 800x480, 32bpp
vaddr = dma_alloc_coherent(&pdev->dev, screen_size,
&dma_phys, GFP_KERNEL);
if (!vaddr) {
framebuffer_release(info);
return -ENOMEM;
}
info->screen_base = vaddr;
info->screen_size = screen_size;
// 3. 配置 fix 固定信息
strncpy(fix->id, "my800x480", sizeof(fix->id) - 1);
fix->smem_start = (unsigned long)dma_phys;
fix->smem_len = screen_size;
fix->type = FB_TYPE_PACKED_PIXELS;
fix->visual = FB_VISUAL_TRUECOLOR;
fix->line_length = 800 * 32 / 8; // 3200 bytes per line
fix->accel = FB_ACCEL_NONE;
// 4. 可选:MMIO 寄存器区域
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
if (res) {
fix->mmio_start = res->start;
fix->mmio_len = resource_size(res);
}
// 5. 配置可变参数与操作函数(略)
info->var = myfb_default_var;
info->fbops = &myfb_ops;
info->flags = FBINFO_DEFAULT;
// 6. 注册帧缓冲
if (register_framebuffer(info) < 0) {
dma_free_coherent(&pdev->dev, screen_size,
vaddr, dma_phys);
framebuffer_release(info);
return -EINVAL;
}
platform_set_drvdata(pdev, info);
return 0;
}
3.5 字段配置检查清单
在提交驱动代码前,建议逐项核对以下配置项:
| 检查项 | 通过标准 | 失败后果 |
|---|---|---|
id 长度 |
≤ 15 字符,以 '\0' 结尾 |
内核字符串操作越界 |
smem_start 物理地址 |
来自 dma_alloc_coherent 或 ioremap |
mmap 失败或访问错误内存 |
smem_len 大小 |
≥ var.xres * var.yres * var.bits_per_pixel / 8 |
屏幕显示不全或内存越界 |
type 与硬件匹配 |
使用 FB_TYPE_PACKED_PIXELS(非平面模式) |
用户空间无法正确解析像素 |
visual 与颜色深度匹配 |
≥16bpp 用 TRUECOLOR;≤8bpp 用 PSEUDOCOLOR | 颜色显示完全错误 |
line_length 对齐 |
通常 4 字节或 8 字节对齐 | 部分硬件 DMA 传输异常 |
调试技巧: 在
register_framebuffer 之后,可以通过 cat /sys/class/graphics/fb0/fix 查看当前 fix 信息,或使用 fbset -i 检查 id、smem_len、line_length 等字段是否与预期一致。