Linux 内核 SAA7164 驱动卡列表全解:Hauppauge HVR 系列 PCIe 电视卡型号识别与 card= 参数实战
【免费下载链接】linuxLinux kernel source tree项目地址: https://gitcode.com/GitHub_Trending/li/linux
本文围绕内核文档 saa7164-cardlist.rst 展开,系统梳理 NXP(原 Philips)SAA7164 PCIe 桥接芯片驱动的全部 14 个板卡条目(编号 0–13),结合 saa7164-cards.c、saa7164.h 与 saa7164-core.c 的源码实现,讲清"卡编号 → PCI 子系统 ID → 板卡自动识别 → card= 参数手动指定"的完整链路,并深入每块卡的端口(DVB/编码器/VBI)与处理单元(调谐器、解调器、EEPROM)硬件拓扑。读完本文,你既能读懂内核日志中的板卡识别信息,也能在自识别失败时准确使用card=<n>加载参数,还能对照源码理解 HVR2200/HVR2250/HVR2255/HVR2205 各型号的内部差异。
SAA7164 驱动与卡列表文档概述
SAA7164 是 NXP 面向 PCIe 总线推出的"桥接"媒体芯片,负责将模拟/数字电视前端(调谐器、解调器、编码器)与主机系统连接起来。在内核中,对应驱动位于 drivers/media/pci/saa7164/,由saa7164-cards.o、saa7164-core.o、saa7164-i2c.o、saa7164-dvb.o、saa7164-fw.o、saa7164-bus.o、saa7164-cmd.o、saa7164-api.o、saa7164-buffer.o、saa7164-encoder.o、saa7164-vbi.o等对象模块组成(见 Makefile),覆盖 DVB 前端、MPEG 编码器和 VBI 三类数据通路。
卡列表文档是这一类驱动的重要配套资料:它把"驱动内部板卡编号"与"板卡名称 + PCI 子系统 ID"一一对应,既是用户识别硬件的速查表,也是驱动开发者在新增板卡时维护的核心索引。在内核媒体子系统的 pci-cardlist.rst 中,saa7164 与 bttv、cx18、cx23885、cx88、ivtv、saa7134、zoran 等驱动并列,共同构成"PCI 驱动总览 + 各驱动卡列表"的文档体系。
SAA7164 完整卡列表(Card 0–13)
原文档使用 flat-table 给出了驱动支持的全部板卡。为便于检索,这里整理为等价表格:
| 卡编号 (Card number) | 卡名称 (Card name) | PCI 子系统 ID (PCI subsystem IDs) |
|---|---|---|
| 0 | Unknown | — |
| 1 | Generic Rev2 | — |
| 2 | Generic Rev3 | — |
| 3 | Hauppauge WinTV-HVR2250 | 0070:8880, 0070:8810 |
| 4 | Hauppauge WinTV-HVR2200 | 0070:8980 |
| 5 | Hauppauge WinTV-HVR2200 | 0070:8900 |
| 6 | Hauppauge WinTV-HVR2200 | 0070:8901 |
| 7 | Hauppauge WinTV-HVR2250 | 0070:8891, 0070:8851 |
| 8 | Hauppauge WinTV-HVR2250 | 0070:88A1 |
| 9 | Hauppauge WinTV-HVR2200 | 0070:8940 |
| 10 | Hauppauge WinTV-HVR2200 | 0070:8953 |
| 11 | Hauppauge WinTV-HVR2255(proto) | 0070:f111 |
| 12 | Hauppauge WinTV-HVR2255 | 0070:f111 |
| 13 | Hauppauge WinTV-HVR2205 | 0070:f123, 0070:f120 |
其中0070是 Hauppauge 公司的 PCI 子系统厂商 ID(subvendor),冒号后的四位十六进制为子系统设备 ID(subdevice)。可以看到:编号 11 与 12 共用子系统 ID0070:f111,但 11 是原型板(proto)条目,源码中该 ID 实际映射到正式板卡 12(原型条目仅为文档留档),这一点在源码部分会详细说明。
卡编号在源码中的枚举定义
文档中的"卡编号"并非随意编号,它们直接对应 saa7164.h 中的板卡枚举常量:
#define SAA7164_BOARD_NOAUTO UNSET #define SAA7164_BOARD_UNKNOWN 0 #define SAA7164_BOARD_UNKNOWN_REV2 1 #define SAA7164_BOARD_UNKNOWN_REV3 2 #define SAA7164_BOARD_HAUPPAUGE_HVR2250 3 #define SAA7164_BOARD_HAUPPAUGE_HVR2200 4 #define SAA7164_BOARD_HAUPPAUGE_HVR2200_2 5 #define SAA7164_BOARD_HAUPPAUGE_HVR2200_3 6 #define SAA7164_BOARD_HAUPPAUGE_HVR2250_2 7 #define SAA7164_BOARD_HAUPPAUGE_HVR2250_3 8 #define SAA7164_BOARD_HAUPPAUGE_HVR2200_4 9 #define SAA7164_BOARD_HAUPPAUGE_HVR2200_5 10 #define SAA7164_BOARD_HAUPPAUGE_HVR2255proto 11 #define SAA7164_BOARD_HAUPPAUGE_HVR2255 12 #define SAA7164_BOARD_HAUPPAUGE_HVR2205 13枚举值与文档编号完全一一对应。需要特别指出的是SAA7164_BOARD_NOAUTO(等于UNSET,即-1U)并不是一张真实板卡,而是"禁止自动识别、强制手动指定"的哨兵值;SAA7164_BOARD_UNKNOWN(0)、SAA7164_BOARD_UNKNOWN_REV2(1)、SAA7164_BOARD_UNKNOWN_REV3(2)则是兜底条目:其中 0 号Unknown在 saa7164-cards.c 中连chiprev(芯片版本)都没有设置,源码注释明确说明"桥接芯片在不清楚修订版本时加载固件是致命操作",因此 0 号条目仅用于占位;而 1/2 号Generic Rev2/Generic Rev3分别声明了SAA7164_CHIP_REV2/SAA7164_CHIP_REV3,源码注释称其"加载 v2 固件并转储描述符,用于新板卡 bringup 阶段",是硬件调试场景下的通用兜底配置。
PCI 子系统 ID 与板卡自动识别机制
如何获取 PCI 子系统 ID
SAA7164 是 PCIe 设备,可以通过标准的lspci工具查看其身份信息。按 pci-cardlist.rst 的说明:
lspci -nn显示 vendor/device PCI ID;lspci -vn的Subsystem:行显示子系统厂商 ID 与子系统设备 ID。
例如在一块 HVR2250 上,lspci -vn应能看到类似Subsystem: 0070:8880的输出,其中0070:8880正是文档第 3 行所列的子系统 ID,驱动据此即可自动判定为SAA7164_BOARD_HAUPPAUGE_HVR2250。
源码中的 ID 匹配表
自动识别的核心数据是 saa7164-cards.c 中的saa7164_subids[]表,它把"子系统厂商 ID + 子系统设备 ID"翻译成板卡枚举值:
struct saa7164_subid saa7164_subids[] = { { .subvendor = 0x0070, .subdevice = 0x8880, .card = SAA7164_BOARD_HAUPPAUGE_HVR2250, }, { .subvendor = 0x0070, .subdevice = 0x8810, .card = SAA7164_BOARD_HAUPPAUGE_HVR2250, }, { .subvendor = 0x0070, .subdevice = 0x8980, .card = SAA7164_BOARD_HAUPPAUGE_HVR2200, }, { .subvendor = 0x0070, .subdevice = 0x8900, .card = SAA7164_BOARD_HAUPPAUGE_HVR2200_2, }, { .subvendor = 0x0070, .subdevice = 0x8901, .card = SAA7164_BOARD_HAUPPAUGE_HVR2200_3, }, { .subvendor = 0x0070, .subdevice = 0x88A1, .card = SAA7164_BOARD_HAUPPAUGE_HVR2250_3, }, { .subvendor = 0x0070, .subdevice = 0x8891, .card = SAA7164_BOARD_HAUPPAUGE_HVR2250_2, }, { .subvendor = 0x0070, .subdevice = 0x8851, .card = SAA7164_BOARD_HAUPPAUGE_HVR2250_2, }, { .subvendor = 0x0070, .subdevice = 0x8940, .card = SAA7164_BOARD_HAUPPAUGE_HVR2200_4, }, { .subvendor = 0x0070, .subdevice = 0x8953, .card = SAA7164_BOARD_HAUPPAUGE_HVR2200_5, }, { .subvendor = 0x0070, .subdevice = 0xf111, .card = SAA7164_BOARD_HAUPPAUGE_HVR2255, }, { .subvendor = 0x0070, .subdevice = 0xf123, .card = SAA7164_BOARD_HAUPPAUGE_HVR2205, }, { .subvendor = 0x0070, .subdevice = 0xf120, .card = SAA7164_BOARD_HAUPPAUGE_HVR2205, }, };对比文档可知:0070:8880与0070:8810都映射到 HVR2250(即 3 号卡);0070:8891与0070:8851都映射到 HVR2250_2(7 号卡);而文档中标注为 "HVR2255(proto)" 的0070:f111在源码中实际映射为正式版SAA7164_BOARD_HAUPPAUGE_HVR2255(12 号卡),原型板条目SAA7164_BOARD_HAUPPAUGE_HVR2255proto(11 号)在saa7164_subids[]中被注释保留(源码注释原文:"Prototype card left here for documentation purposes.")。这说明:文档列表保留历史条目,但驱动实际行为以saa7164_subids[]表的映射为准。
自动识别流程
在 saa7164-core.c 中,板卡识别的逻辑顺序是:
- 若用户通过
card=<n>模块参数指定了合法编号(card[dev->nr] < saa7164_bcount),则优先使用该编号; - 否则遍历
saa7164_subids[],将设备上报的pci->subsystem_vendor/pci->subsystem_device与表中条目比对,命中即采用对应板卡枚举; - 若既无参数也未命中,调用
saa7164_card_list()打印错误日志。
SAA7164_MAXBOARDS定义为 8(saa7164.h),即驱动最多支持 8 块卡同时工作,card[]数组按dev->nr索引每块卡的参数。
card= 模块参数:手动指定板卡
为什么需要手动指定
如 pci-cardlist.rst 所述,不同产品有时会复用同一个 PCI 子系统 ID,导致自动识别可能选错配置;此外,全新板卡、无有效子系统 ID 的工程板也会导致识别失败。此时需要card=参数强制指定。
card= 的用法
加载模块时指定(假设目标板是 13 号 HVR2205):
modprobe saa7164 card=13或写入模块参数后重新加载:
echo "options saa7164 card=13" > /etc/modprobe.d/saa7164.conf modprobe -r saa7164 && modprobe saa7164参数无效时的内核提示
在 saa7164-cards.c 的saa7164_card_list()中,驱动会区分两种失败场景并打印指引:
- 设备的子系统厂商 ID 与设备 ID 均为 0(无有效子系统 ID)时,提示"板卡无法自动识别,请用
card=<n>insmod 参数绕过,并建议向厂商反馈"; - 子系统 ID 有效但不在
saa7164_subids[]中时,提示"板卡尚未被驱动识别,可尝试用card=<n>挑选现有配置之一,或升级到最新内核版本"。
无论哪种情况,驱动都会遍历saa7164_boards[]打印全部可选条目,格式为card=%d -> %s(如card=13 -> Hauppauge WinTV-HVR2205),方便用户对照本文的卡列表直接取用编号。板卡最终确认后,saa7164-core.c 会打印类似subsystem: 0070:f123, board: Hauppauge WinTV-HVR2205 [card=13,autodetected]的日志(card[...]括号内会标注是手动指定还是自动识别)。
板卡定义内部结构:端口与处理单元
saa7164_boards[]数组(saa7164-cards.c)是每张卡配置的"完整画像",由struct saa7164_board描述(saa7164.h),核心字段包括:
- name:板卡显示名;
- porta ~ portf:六个硬件端口的类型,取值来自
enum port_t(SAA7164_MPEG_DVB数字电视传输流、SAA7164_MPEG_ENCODERMPEG 编码器、SAA7164_MPEG_VBIVBI 垂直消隐期数据); - chiprev:芯片修订版本(
SAA7164_CHIP_REV2/SAA7164_CHIP_REV3); - unit[]:最多
SAA7164_MAX_UNITS(8)个"处理单元"描述。
处理单元(unit)的含义
SAA7164 桥接芯片的特殊之处在于:主机无法直接访问板上的 I2C 总线(saa7164-cards.c 的注释明确指出),所有对调谐器、解调器等器件的寄存器访问都必须通过设备固件提供的"处理单元"接口进行。因此驱动维护了一张"单元表",每个单元包含类型、唯一 ID、所在虚拟 I2C 总线号与器件地址。单元类型定义于 saa7164.h:SAA7164_UNIT_TUNER(调谐器)、SAA7164_UNIT_DIGITAL_DEMODULATOR(数字解调器)、SAA7164_UNIT_ANALOG_DEMODULATOR(模拟解调器)、SAA7164_UNIT_EEPROM(板载 EEPROM)、SAA7164_UNIT_ENCODER(编码器)等。
单元表还定义了i2c_reg_len(寄存器地址宽度,REGLEN_0bit/REGLEN_8bit/REGLEN_16bit,见 saa7164-cards.c),供虚拟 I2C 层在构造 API 命令时判断寄存器宽度。驱动提供saa7164_i2caddr_to_unitid()和saa7164_i2caddr_to_reglen()两个翻译函数(saa7164-cards.c),把内核标准 I2C 子系统的"总线号 + 器件地址"映射回 SAA7164 固件认识的 unit ID 与寄存器宽度,从而复用内核现有的 tuner/demod 驱动——这是本驱动架构设计的关键点。
三路虚拟 I2C 总线
单元表中出现的SAA7164_I2C_BUS_0/SAA7164_I2C_BUS_1/SAA7164_I2C_BUS_2(saa7164.h)对应桥接芯片内部的三路虚拟 I2C 总线,每块卡通常把两个调谐器/解调器对分挂在不同的总线上,例如 HVR2250 的 TDA18271-1 挂在 BUS_1、TDA18271-2 挂在 BUS_2。struct saa7164_dev中的i2c_bus[3](saa7164.h)即对应这三路总线实例。
各型号硬件配置差异:从单元表看板卡
卡列表中的多张 HVR2200/HVR2250 变体在硬件上并不完全相同,差异通过chiprev与unit[]单元表体现(以下均出自 saa7164-cards.c 中各板卡定义):
- HVR2200 系列(4/5/6/9/10 号):DVB-T 平台,双 TDA18271 调谐器 + 双 TDA10048 数字解调器。其中 5 号(
0070:8900)与 6 号(0070:8901)使用 Rev2 芯片,4 号(0070:8980)、9 号(0070:8940)使用 Rev3 芯片;5/6 号的单元 ID 分配与 4 号略有不同(如 5 号 TDA10048-1 的单元 ID 为 0x05、4 号为 0x1e)。10 号(0070:8953)比较特殊,它只启用了 porta/portb 两个 DVB 端口,且额外挂载了 TDA8290 模拟解调器。 - HVR2250 系列(3/7/8 号):ATSC/QAM 平台,双 TDA18271 调谐器 + 双 CX24228/S5H1411 数字解调器(每个解调器又分 TOP 与 QAM 两个单元条目)。3 号(
0070:8880/0070:8810)使用 Rev3 芯片;7 号(0070:8891/0070:8851)与 8 号(0070:88A1)在单元 ID 分配上相互错开(如 7 号第二个 TDA18271 的单元 ID 为 0x24、8 号为 0x22)。 - HVR2255(12 号,
0070:f111):ATSC/QAM 平台,双 SI2157 调谐器 + 双 LGDT3306 数字解调器,Rev3 芯片。调谐器使用REGLEN_0bit(无寄存器地址宽度的直写器件),与早期型号的REGLEN_8bit不同。 - HVR2205(13 号,
0070:f123/0070:f120):DVB-T/T2/C 平台,双 SI2157 调谐器 + 双 SI2168 数字解调器,Rev3 芯片,所有 I2C 器件均为REGLEN_0bit。
驱动在 saa7164-core.c 中遍历saa7164_boards[dev->board]的六个端口字段,按SAA7164_MPEG_DVB/SAA7164_MPEG_ENCODER/SAA7164_MPEG_VBI分别注册 DVB 前端、V4L2 编码器与 VBI 设备,因此卡列表中的端口配置直接决定了用户空间可见的/dev/dvb与/dev/video*设备数量。
EEPROM 与 GPIO 初始化
除单元表外,板卡定义还驱动了两类初始化逻辑:
saa7164_gpio_setup()(saa7164-cards.c)按板卡类型复位解调器:对 HVR2200/HVR2250 使用 GPIO 2/3 复位 s5h1411/tda10048 解调器,对 HVR2255 复位 lgdt3306 解调器,对 HVR2205 复位 si2168 解调器,并额外管理 GPIO 7 上的 Zilog IR Blaster 复位。saa7164_card_setup()(saa7164-cards.c)读取板载 EEPROM(通过saa7164_api_read_eeprom),由hauppauge_eeprom()调用tveeprom_hauppauge_analog()解析 Hauppauge 型号并校验支持范围(如 HVR2250 对应 88001/88021/88041/88061,HVR2200 对应 89519/89609/89619,HVR2205 对应 151009/151609,HVR2255 对应 151061),未知型号会打印警告。
驱动构建与模块加载
SAA7164 驱动的 Kconfig 条目(drivers/media/pci/saa7164/Kconfig):
config VIDEO_SAA7164 tristate "NXP SAA7164 support" depends on DVB_CORE && VIDEO_DEV && PCI && I2C select I2C_ALGOBIT select FW_LOADER select VIDEO_TUNER select VIDEO_TVEEPROM select DVB_TDA10048 if MEDIA_SUBDRV_AUTOSELECT select DVB_S5H1411 if MEDIA_SUBDRV_AUTOSELECT select MEDIA_TUNER_TDA18271 if MEDIA_SUBDRV_AUTOSELECT要点:
- 依赖
DVB_CORE(DVB 核心)、VIDEO_DEV(V4L2 框架)、PCI与I2C; - 自动选择
I2C_ALGOBIT(软件位操作 I2C 算法)、FW_LOADER(固件加载)、VIDEO_TUNER(调谐器通用层)、VIDEO_TVEEPROM(Hauppauge EEPROM 解析); - 在
MEDIA_SUBDRV_AUTOSELECT开启时,自动选择 TDA10048/S5H1411 解调器与 TDA18271 调谐器驱动; - 编译为模块时模块名为
saa7164(对应 Makefile 中的obj-$(CONFIG_VIDEO_SAA7164) += saa7164.o)。
典型使用场景(以手动指定 13 号 HVR2205 为例):
# 查看硬件是否被识别及当前匹配的板卡 dmesg | grep -i saa7164 # 手动指定卡编号后重新加载 sudo modprobe -r saa7164 sudo modprobe saa7164 card=13 # 确认识别结果与可用设备 lspci -vn | grep -A3 -i multimedia ls /dev/dvb/ /dev/video* 2>/dev/null排查速查:从卡列表定位问题
- 驱动未加载:确认内核已启用
CONFIG_VIDEO_SAA7164,并检查dmesg中是否提示固件缺失(驱动依赖FW_LOADER加载器件固件)。 card=<n>参数被拒绝:确认编号在 0–13 范围内,且小于saa7164_bcount(板卡表长度,由ARRAY_SIZE(saa7164_boards)计算,见 saa7164-cards.c)。- 识别到错误型号:先用
lspci -vn核对子系统 ID 是否与上表匹配;若 ID 不在表中,按dmesg中saa7164_card_list()打印的card=%d -> 名称列表挑选功能最接近的条目,并通过card=指定。 - 同 ID 复用导致误判:例如
0070:f111在文档中同时出现于 11 号(proto)与 12 号(正式版),源码实际映射为 12 号正式板卡;遇到此类"一 ID 多型号"情况,应优先以 saa7164-cards.c 的saa7164_subids[]为准,必要时用card=强制覆盖。 - 设备节点数量不符:对照本文各型号的端口配置(porta–portf),确认 DVB/编码器/VBI 端口数量与预期一致,例如 HVR2200/HVR2250 系列为"双 DVB + 双编码器 + 双 VBI",而 10 号 HVR2200_5 仅启用两个 DVB 端口。
结语
saa7164-cardlist.rst虽然只是一张 14 行的表格,但它是理解整个 SAA7164 驱动板卡支持矩阵的入口:卡编号对应 saa7164.h 的枚举、子系统 ID 对应 saa7164-cards.c 的匹配表、而每张卡的深层差异(芯片版本、六端口类型、调谐器/解调器单元拓扑、GPIO 复位与 EEPROM 校验)都沉淀在saa7164_boards[]的单元表中。掌握这张表,就等于同时掌握了"读内核日志、用 lspci 对号入座、以 card= 参数手动兜底"的完整排障三板斧。
【免费下载链接】linuxLinux kernel source tree项目地址: https://gitcode.com/GitHub_Trending/li/linux
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考