在 Debian 13 上让 Intel IPU6 摄像头工作
Dell Latitude 7450 = Intel Meteor Lake + Hynix HI556 sensor + IPU6 ISP,通过 USB-IO Bridge 连接。
Debian 13 + Linux 6.12(默认)+ mainline IPU6 子系统 + 浏览器 = 各种坑全踩齐。
本文记录把这台机器的摄像头从"灯不亮、/dev/video0没图"做到"Teams/Edge/Firefox/飞书全部可用"的完整过程。
整套修复跨越内核、固件、ACPI、用户态 HAL、GStreamer、v4l2loopback、PipeWire、Chromium 过滤规则等 11 个层级。一个组件都不能少。
硬件 / 软件起点
- 机器:Dell Latitude 7450(Intel Meteor Lake,2024 款)
- 传感器:Hynix HI556(前置摄像头)+ OV2740(IR 红外,本文不涉及)
- 桥接:通过 USB-IO Bridge(ACPI ID
INTC10D1/D2/D3,Dell 变种)暴露 GPIO/I2C/SPI - ISP:Intel IPU6 PCIe 设备
0000:00:05.0 - 操作系统:Debian 13 Trixie,默认内核 6.12.90+deb13
- 桌面:KDE Plasma(X11)
启动后症状:
lspci看到Intel Corporation Meteor Lake IPU,模块intel_ipu6_isys已加载/dev/video0到/dev/video47都有,但全是 IPU6 内部 isys media graph 节点- 任何应用打开都拿不到画面,摄像头隐私灯也不亮
dmesg | grep int3472死循环报错:cannot find GPIO chip INTC10D1:00, deferring
1. 诊断:摄像头链路在哪一环断了
lspci -k | grep -A2 Multimedia # IPU6 PCIe 设备
lsmod | grep -E 'ipu6|hi556' # 内核模块状态
ls /dev/video* /dev/media* # V4L2 设备节点
cam --list 2>&1 # libcamera 视角
sudo dmesg | grep -iE 'int3472|hi556|ipu6|INTC10' | head -50关键报错:
int3472-discrete INT3472:01: GPIO type 0x12 unknown; the sensor may not work
int3472-discrete INT3472:01: cannot find GPIO chip INTC10D1:00, deferring意思是 sensor 的电源/复位 GPIO 是经 USB-IO Bridge 提供的,但 mainline 内核 usbio 驱动没匹配到 Dell 的 ACPI ID INTC10D1。整条链直接卡在底层。
2. 用户态栈:bins + HAL + icamerasrc
Intel 在 Linux 上的 IPU6 用户态是闭源 blob + 开源胶水:
intel/ipu6-camera-bins— 专有 ISP 处理库intel/ipu6-camera-hal— HAL 框架intel/icamerasrc— GStreamer 元素
先装这三个:
sudo apt install -y \
build-essential meson ninja-build cmake pkg-config git ca-certificates \
autoconf automake libtool autoconf-archive \
python3-yaml python3-ply python3-jinja2 \
libdrm-dev libyaml-dev libssl-dev libgnutls28-dev libudev-dev libsystemd-dev \
libpython3-dev libevent-dev libtiff-dev libjpeg-dev \
libgstreamer1.0-dev libgstreamer-plugins-base1.0-dev \
gstreamer1.0-plugins-{base,good,bad} gstreamer1.0-tools \
v4l-utils2.1 ipu6-camera-bins(专有 blob)
sudo mkdir -p /opt/ipu6-src && cd /opt/ipu6-src
sudo git clone --depth=1 https://github.com/intel/ipu6-camera-bins.git
cd ipu6-camera-bins
sudo mkdir -p /lib/firmware/intel/ipu /usr/lib/x86_64-linux-gnu/pkgconfig
sudo cp -rv lib/firmware/intel/ipu/*.bin /lib/firmware/intel/ipu/
# 创建无版本后缀 symlink,链接器才能找到
for libpath in lib/lib*.so.*; do
libname=${libpath##*/}
sudo ln -sf "$libname" "lib/${libname%.*}"
done
sudo cp -Pv lib/lib*.so* /usr/lib/x86_64-linux-gnu/
sudo cp -Pv lib/lib*.a /usr/lib/x86_64-linux-gnu/ # 静态库也要拷!
sudo cp -rv include/* /usr/include/
sudo cp -rv lib/pkgconfig/* /usr/lib/x86_64-linux-gnu/pkgconfig/
sudo ldconfig坑 1:.a 文件必须拷,HAL 链接 libipu6epmtl.a 静态库。
2.2 ipu6-camera-hal
cd /opt/ipu6-src
sudo git clone --depth=1 https://github.com/intel/ipu6-camera-hal.git
cd ipu6-camera-hal && sudo mkdir -p build && cd build
sudo cmake \
-DCMAKE_BUILD_TYPE=Release \
-DIPU_VERSIONS="ipu6epmtl" \
-DUSE_PG_LITE_PIPE=ON \
-DBUILD_CAMHAL_PLUGIN=ON \
-DBUILD_CAMHAL_ADAPTOR=ON \
-DCMAKE_INSTALL_PREFIX=/usr \
-DCMAKE_INSTALL_LIBDIR=lib/x86_64-linux-gnu \
..
sudo make -j"$(nproc)" && sudo make install && sudo ldconfig坑 2:BUILD_CAMHAL_PLUGIN=ON 才让 cmake 在 TARGET_SUFFIX 里加平台后缀(-ipu6epmtl),否则 cmake 找的是无后缀 pkgconfig(ia_imaging)而不是装上的 ia_imaging-ipu6epmtl.pc。
坑 3:BUILD_CAMHAL_ADAPTOR=ON 同时打开才生成 libcamhal.pc,icamerasrc 需要这个 pkgconfig。
2.3 icamerasrc
cd /opt/ipu6-src
sudo git clone --depth=1 -b icamerasrc_slim_api https://github.com/intel/icamerasrc.git
cd icamerasrc
sudo bash -c 'export CHROME_SLIM_CAMHAL=ON && ./autogen.sh && make -j"$(nproc)" && make install && ldconfig'装到 /usr/lib/gstreamer-1.0/libgsticamerasrc.so(不是 Debian 默认的 multiarch 路径 /usr/lib/x86_64-linux-gnu/gstreamer-1.0/,每次用都要设 GST_PLUGIN_PATH=/usr/lib/gstreamer-1.0)。
3. IVSC 固件
Dell 7450 的摄像头通过 IVSC(Intel Visual Sensing Controller)中转,需要专门固件:
sudo apt install -t stable-backports firmware-misc-nonfree # 不一定有 IVSC
# 一般还是要从源拉:
cd /opt/ipu6-src
sudo git clone --depth=1 https://github.com/intel/ivsc-firmware.git
sudo mkdir -p /lib/firmware/intel/ivsc
sudo cp -v ivsc-firmware/firmware/*.bin /lib/firmware/intel/ivsc/ivsc_pkg_hi556_0.bin、ivsc_skucfg_hi556_0_1.bin、ivsc_pkg_int3537_0.bin 这几个对应 HI556 + INT3537。
4. 升级到 Linux 7.0(解决 int3472 GPIO type 0x12 unknown)
Debian 13 默认 6.12.90 内核的 intel_skl_int3472_discrete 不认识 GPIO type 0x12(IVSC handshake GPIO),导致 sensor 拿不到 power/reset 信号。Linux 7.0 已合入相关 patch:
sudo apt install -y -t stable-backports linux-image-amd64 linux-headers-amd64
sudo reboot # 默认引导 7.0坑 4:v4l2loopback DKMS 旧版(< 0.16)在 Linux 7.0 编译失败,要么先卸掉旧版让 dpkg 完成 kernel 安装,要么从 upstream master 装新版(本文后面会装)。
附带修 BE200 WiFi:Linux 7.0 启动后 WiFi 7 BE200 报固件版本不够:
sudo apt install -t stable-backports firmware-iwlwifi
sudo modprobe -r iwlwifi && sudo modprobe iwlwifi5. Patch usbio:让它认 Dell 的 INTC10D1/D2/D3
mainline usbio-gpio 只匹配 INTC1007(标准 MTL),Dell Latitude 7450 用 INTC10D1(变种 ID)。从 intel/ipu6-drivers clone 源码 patch 后 DKMS 重建:
cd /opt/ipu6-src
sudo git clone --depth=1 https://github.com/intel/ipu6-drivers.git
sudo cp -r ipu6-drivers /usr/src/usbio-0.2 # DKMS 会从这里编Patch GPIO/I2C/SPI 三个文件的 ACPI 表:
sudo sed -i '/{ "INTC1007" }/a\\t{ "INTC10D1" }, /* Dell Latitude */' \
/usr/src/usbio-0.2/drivers/gpio/gpio-usbio.c
sudo sed -i '/{ "INTC1008" }/a\\t{ "INTC10D2" }, /* Dell Latitude */' \
/usr/src/usbio-0.2/drivers/i2c/busses/i2c-usbio.c
# spi-usbio.c 同理加 INTC10D3注册到 DKMS:
sudo dkms add -m usbio -v 0.2
sudo dkms build -m usbio -v 0.2 -k "$(uname -r)"
sudo dkms install -m usbio -v 0.2 -k "$(uname -r)" --force
sudo depmod -a
sudo modprobe -r i2c-usbio gpio-usbio usbio
sudo modprobe usbio && sudo modprobe gpio-usbio && sudo modprobe i2c-usbio效果:之前 int3472: cannot find GPIO chip INTC10D1:00 死循环停了,sensor 的 i2c 设备 i2c-INT3537:00 出现在 /sys/bus/i2c/devices/。
6. Patch hi556:跳过 fwnode link-frequency 检查
sensor 终于能被 probe 了,但又卡新错:
hi556 i2c-INT3537:00: no link frequency 437000000 supported
hi556 i2c-INT3537:00: probe with driver hi556 failed with error -22原因:hi556 driver 读 fwnode 里的 link-frequencies 属性来跟 driver 内部 link_freq_menu_items[](只有 437MHz)对比,但 ipu_bridge 没给 USB-IO i2c bus 上的 sensor 配 swnode(它只扫 PCH I2C bus)。fwnode 上的 link-frequencies 是 IVSC bridge 设的某个不同值。
Patch hi556 让它跳过这个交叉校验:
sudo apt install -y linux-source-7.0
cd /tmp && tar -xf /usr/src/linux-source-7.0.tar.xz --wildcards \
"linux-source-7.0/drivers/media/i2c/hi556.c" --strip-components=4在 hi556_check_hwcfg() 的 frequency 校验循环前插一行 goto check_hwcfg_skip;,并在 check_hwcfg_error: 标签前加 check_hwcfg_skip::
+ /* Dell quirk: ipu_bridge can't annotate USB-IO i2c sensors */
+ goto check_hwcfg_skip;
for (i = 0; i < ARRAY_SIZE(link_freq_menu_items); i++) {
...
}
+check_hwcfg_skip:
check_hwcfg_error:
v4l2_fwnode_endpoint_free(&bus_cfg);写到 DKMS:
sudo mkdir -p /usr/src/hi556-dell-1.0
sudo cp hi556.c /usr/src/hi556-dell-1.0/
sudo tee /usr/src/hi556-dell-1.0/Makefile <<'EOF'
obj-m += hi556.o
KDIR ?= /lib/modules/$(shell uname -r)/build
PWD := $(shell pwd)
all:
$(MAKE) -C $(KDIR) M=$(PWD) modules
clean:
$(MAKE) -C $(KDIR) M=$(PWD) clean
EOF
sudo tee /usr/src/hi556-dell-1.0/dkms.conf <<EOF
PACKAGE_NAME=hi556-dell
PACKAGE_VERSION=1.0
MAKE[0]="make KDIR=/lib/modules/\$kernelver/build"
CLEAN="make clean"
AUTOINSTALL="yes"
BUILT_MODULE_NAME[0]="hi556"
BUILT_MODULE_LOCATION[0]="."
DEST_MODULE_LOCATION[0]="/updates"
EOF
sudo dkms add -m hi556-dell -v 1.0
sudo dkms build hi556-dell/1.0 -k "$(uname -r)"
sudo dkms install hi556-dell/1.0 -k "$(uname -r)" --force
sudo depmod -a
sudo modprobe -r hi556 && sudo modprobe hi556效果:hi556 i2c-INT3537:00: supply dovdd not found, using dummy regulator —— sensor 真正 probe 成功了。/dev/v4l-subdev* 出现新节点。
7. PSYS 权限
echo 'KERNEL=="ipu-psys*", MODE="0660", GROUP="video"' | \
sudo tee /etc/udev/rules.d/99-intel-ipu6.rules
sudo udevadm control --reload
sudo udevadm trigger /dev/ipu-psys0否则 HAL open(/dev/ipu-psys0) 报 EACCES,gst-launch 报 Failed to open PSYS。
8. 第一次出图!
export GST_PLUGIN_PATH=/usr/lib/gstreamer-1.0
gst-launch-1.0 icamerasrc num-buffers=10 ! \
video/x-raw,format=NV12,width=1280,height=720 ! fakesink
# 收到 EOS = 10 帧出齐 = 摄像头工作 ✓加 autovideosink 替换 fakesink 应该弹出窗口看到自己。
但是 —— Cheese / Edge / Chrome / Firefox / Teams 全都不能用。它们都不懂 GStreamer,只懂 V4L2 设备文件。
9. 桥接 icamerasrc → v4l2loopback
让浏览器和视频会议软件看到摄像头,要把 GStreamer 输出灌进一个虚拟 V4L2 capture 设备。
9.1 装新版 v4l2loopback
Debian 包的 v4l2loopback-dkms 0.15 在 Linux 7.0 编译失败,从 upstream master 装:
cd /opt/ipu6-src
sudo git clone --depth=1 https://github.com/v4l2loopback/v4l2loopback.git
sudo cp -a v4l2loopback /usr/src/v4l2loopback-master
sudo dkms add -m v4l2loopback -v master
sudo dkms build v4l2loopback/master -k "$(uname -r)"
sudo dkms install v4l2loopback/master -k "$(uname -r)" --force9.2 关键:选对 video 号
sudo tee /etc/modprobe.d/v4l2loopback.conf <<'EOF'
options v4l2loopback video_nr=49 card_label="IPU6 Camera (Bridged)" exclusive_caps=1 max_buffers=2
EOF坑 5:video_nr 必须在 0-63 范围内!Chromium 内核的 V4L2 设备扫描默认上限就是 64,超过这个范围浏览器看不到。IPU6 占 0-47,所以选 49 是合适的(48 偶尔会被 IPU6 抢)。
坑 6:exclusive_caps=1 必须开!Chromium 排除同时声明 V4L2_CAP_VIDEO_CAPTURE + V4L2_CAP_VIDEO_OUTPUT 的设备。exclusive_caps=1 让 device 在被打开时锁成单向,bridge 服务先打开作 OUTPUT 后,subsequent open 就拿 CAPTURE-only 视角,浏览器才认。
9.3 udev 规则 + 让 Chromium 把它当摄像头
sudo tee /etc/udev/rules.d/99-v4l2loopback-public.rules <<'EOF'
SUBSYSTEM=="video4linux", KERNEL=="video49", MODE="0666", \
ENV{ID_V4L_CAPABILITIES}=":capture:", ENV{ID_V4L_PRODUCT}="IPU6 Camera (Bridged)"
EOF
sudo udevadm control --reload
sudo modprobe v4l2loopback坑 7:ID_V4L_CAPABILITIES=":capture:" 这个 udev 属性 Chromium 必须看到,否则即使设备有 V4L2_CAP_VIDEO_CAPTURE 标志也会跳过。这条 udev rule 是 v4l2loopback 上 Chromium 兼容的隐藏关键。
9.4 systemd 桥接服务
sudo tee /usr/local/bin/ipu6-camera-bridge.sh <<'EOF'
#!/usr/bin/env bash
set -e
export GST_PLUGIN_PATH=/usr/lib/gstreamer-1.0
for i in {1..30}; do [[ -c /dev/video49 ]] && break; sleep 1; done
exec gst-launch-1.0 -q icamerasrc ! \
video/x-raw,format=NV12,width=1280,height=720,framerate=30/1 ! \
videoconvert ! video/x-raw,format=YUY2 ! \
v4l2sink device=/dev/video49
EOF
sudo chmod +x /usr/local/bin/ipu6-camera-bridge.sh
sudo tee /etc/systemd/system/ipu6-camera-bridge.service <<'EOF'
[Unit]
Description=IPU6 camera (icamerasrc) -> v4l2loopback bridge
After=systemd-modules-load.service
Wants=systemd-modules-load.service
[Service]
Type=simple
ExecStart=/usr/local/bin/ipu6-camera-bridge.sh
Restart=on-failure
RestartSec=3
EOF
sudo systemctl daemon-reload
# 注意:不要 enable,让用户按需启停10. 手动开关脚本 cam on/off
桥接服务一开摄像头隐私灯就亮(producer 在持续抓帧),所以不让它自启动,给用户一个简单切换:
sudo tee /usr/local/bin/cam <<'EOF'
#!/usr/bin/env bash
case "${1:-status}" in
on) sudo systemctl start ipu6-camera-bridge.service && echo "Camera ON (privacy LED lit)" ;;
off) sudo systemctl stop ipu6-camera-bridge.service && echo "Camera OFF (privacy LED off)" ;;
status) systemctl is-active ipu6-camera-bridge.service ;;
*) echo "Usage: cam {on|off|status}"; exit 2 ;;
esac
EOF
sudo chmod +x /usr/local/bin/cam
sudo tee /etc/sudoers.d/ipu6-camera-bridge <<EOF
${USER} ALL=(root) NOPASSWD: /usr/bin/systemctl start ipu6-camera-bridge.service, \
/usr/bin/systemctl stop ipu6-camera-bridge.service
EOF
sudo chmod 440 /etc/sudoers.d/ipu6-camera-bridge11. (可选)PipeWire 清理
PipeWire 默认把 IPU6 内部的 video0-47 全当 camera node 暴露,应用列表里会有 50+ 个"camera"。屏蔽掉内部节点,只留 Bridged:
sudo mkdir -p /etc/wireplumber/wireplumber.conf.d
sudo tee /etc/wireplumber/wireplumber.conf.d/51-hide-ipu6-isys.conf <<'EOF'
monitor.v4l2.rules = [
{
matches = [ { node.nick = "ipu6" } ]
actions = { update-props = { node.disabled = true } }
}
]
EOF
systemctl --user restart wireplumber12. 关于 flatpak Edge
flatpak 版 Edge(com.microsoft.Edge)无法用 —— 即使给了 --device=all,沙箱内的 V4L2 enumeration 拿不到 video49。装 deb 版:
curl -fsSL https://packages.microsoft.com/keys/microsoft.asc | \
sudo gpg --dearmor -o /usr/share/keyrings/microsoft.gpg
echo 'deb [arch=amd64 signed-by=/usr/share/keyrings/microsoft.gpg] \
https://packages.microsoft.com/repos/edge stable main' | \
sudo tee /etc/apt/sources.list.d/microsoft-edge.list
sudo apt update && sudo apt install -y microsoft-edge-stable
flatpak uninstall -y com.microsoft.Edge13. 验证
cam on
v4l2-ctl --device=/dev/video49 --all | head -25
# 期望看到:
# Driver name : v4l2 loopback
# Card type : IPU6 Camera (Bridged)
# Video input : 0 (loopback: ok) ← 关键:ok 不是 no signal
# Pixel Format: 'YUYV' 1280x720测试网页:
- https://test.webrtc.org/ — 跑完整 WebRTC 自检
- https://webrtc.github.io/samples/src/content/devices/input-output/ — 设备下拉选 "IPU6 Camera (Bridged)"
应用验证清单:
| 应用 | 状态 |
|---|---|
| Firefox(含 Teams Web 之外的网站) | ✅ |
| Microsoft Edge (deb) | ✅ |
| Chromium / Chrome (deb) | ✅ |
| Microsoft Teams(deb Edge 里跑 web 版) | ✅ |
| 飞书 Linux 客户端 | ✅ |
OBS Studio(V4L2 source 选 video49 / 或直接 GStreamer source icamerasrc) | ✅ |
| Cheese / Kamoso / GNOME Snapshot | ❌(应用本身 bug) |
| flatpak 版 Edge / Chrome | ❌(沙箱挡) |
| Firefox 打开 Teams Web | ❌(微软限制 Firefox) |
整体架构图
Hynix HI556 sensor (10-bit raw Bayer)
│
│ i2c (via INT3537 ACPI node)
│
USB-IO Bridge ← patched usbio DKMS (加 INTC10D1/D2/D3)
│
│ power/clock (via int3472, 配合 IVSC handshake GPIO)
│
IPU6 ISP (Meteor Lake)
│
│ process: demosaic → AWB → AE → AF → NV12
│
intel-ipu6-camera-hal (libcamhal.so + libipu6epmtl.so)
│
│ GStreamer element
│
icamerasrc (/usr/lib/gstreamer-1.0/libgsticamerasrc.so)
│
│ push frames (systemd service)
│
v4l2loopback /dev/video49 ← exclusive_caps=1, ID_V4L_CAPABILITIES=:capture:
│
│ open() by app
▼
Edge / Firefox / Teams / 飞书 / Zoom / OBS一句话总结
任何一个环节配置不对就全盘失效。 Linux + IPU6 + 浏览器 = 跨内核 / 固件 / ACPI / 用户态 HAL / GStreamer / v4l2loopback / udev / Chromium 过滤规则 / sandbox 11 层全对齐才能用。希望这篇文章能帮后来的人省几小时。
DKMS 包内核升级会自动重建,但万一某次升级出问题,本文每条命令都可以重新跑。
引用 / 资源
- Intel ipu6-camera-bins
- Intel ipu6-camera-hal
- Intel icamerasrc (
icamerasrc_slim_api分支) - Intel ipu6-drivers (含 USB-IO patches)
- Intel ivsc-firmware
- v4l2loopback (upstream master)
- Debian 13 trixie-backports(提供 Linux 7.0 内核与新固件包)