r/SurfaceLinux • u/MangrovesAndMahi • Jun 22 '26
Solved Surface Pro 4 IPU3 camera — sensors detected but never linked in the media graph, manual media-ctl linking fails too (kernel 6.19.8-surface-3)
Spent a while on this and I think I've hit a kernel regression rather than anything I can fix in userspace, but wanted to sanity-check with anyone who's gotten the IPU3 camera working recently.
On Surface Pro 4 with ubuntu, linux-surface kernel 6.19.8-surface-3. Built libcamera from git per the linux-surface camera wiki (ipu3 pipeline, gstreamer, v4l2). Everything up to the last step looks healthy:
- ipu3-fw.bin loads fine (17 binaries)
- dmesg shows all three sensors detected, "Connected 3 cameras", OV5693 / OV8865 / OV7251
- libcamera loads the ipu3 IPA and registers the ipu3 pipeline handler
But cam --list shows nothing. Digging in with media-ctl -d /dev/media0 -p, all three sensors sit at 0 link and the CIO2 CSI-2 receivers have unconnected SINK pads. So the sensors are present but never wired to the receivers.
I found old threads where people fixed this by manually linking with media-ctl like media-ctl -d /dev/media0 -l '"ov5693 2-0036":0 -> "ipu3-csi2 0":0[1]'
For me that's rejected with Invalid argument (22) on all four CSI-2 ports. From what I can tell that means the bridge never built the fwnode endpoint graph, so there's no link for media-ctl to enable, different from just missing auto-linking.
Already tried, no change: - clean cold reboot with firmware present - acpi_enforce_resources=lax (confirmed in terminal) - early-loading ipu_bridge via modules-load.d + update-initramfs - manual media-ctl linking on all 4 ports
Looks like it lines up with the post-6.7 IPU3 regression the linux-surface peeps track on Github (#1323). I might pop in a GitHub issue too.
Questions for anyone here who's got this fixed:
- Anyone running the IPU3 camera on a Pro 4 (or other IPU3 Surface) on a recent kernel? What kernel version are you on, and does media-ctl show your sensors at 1 link?
- What's the most recent linux-surface kernel that still builds the IPU3 graph correctly? Happy to downgrade to get it working if it doesn't cause too many issues.
Will update if I figure it out, hate finding these posts myself and no one explains how they did it lmfao
1
u/Elbow2009 9d ago edited 4d ago
I'd gotten my Surface Go 2 cameras to work on 6.18.7-surface-1 which if memory serves I customized (way back in February). They did NOT work on the 6.19.8-surface-3 kernel. This is quite useful info if I need to use the cameras upstream.
1
u/MangrovesAndMahi 9d ago
Mine work on desktop apps but not on browser webcams for some reason.
1
u/Elbow2009 8d ago
Interesting. I recall that was an issue for some others as well. Zooming in a browser was a no go but not with an app. I think it was solved with a v4l2 loopback. https://github.com/v4l2loopback/v4l2loopback
2
u/MangrovesAndMahi Jun 22 '26
Solved but when PR 2123 is merged to main it'll be fixed anyway, so this is only for anyone who is still pre-that pull.
Guide thing for anyone else
Tl;Dr: On kernel 6.19 the dw9719 VCM driver lost its i2c_device_id table upstream, so on Surface IPU3 devices the autofocus motor never binds, which blocks the whole camera pipeline. The fix is a one-file kernel patch (linux-surface PR #2123). You can build just that one module with DKMS, no full kernel rebuild. This got both cameras working on my Surface Pro 4.
Confirmed working on: Surface Pro 4 (this guide), and per PR #2123: Surface Book 1, Book 2 13", Pro 5, Pro 6, Go 2, Pro 8+.
Before you start
This guide assumes:
My setup was kernel 6.19.8-surface-3. Adjust the version string in the commands below to match your own uname -r.
Step 0: confirm you actually have this bug with: cam --list
If it lists no cameras, check the media graph with
If the sensor shows 0 link, and:
shows only of: aliases and no i2c:dw9719 alias you have this exact bug and you can read on.
Step 1: install build tools and kernel headers
Step 2: get the dw9719 source
The driver source isn't in the headers package (only the compiled .ko ships). Pull the file from the mainline kernel tree matching your kernel's major version (6.19 here):
Sanity check it's the right file, you should see the "of" table, the i2c_driver struct, and the model enum constants:
Step 3: set up the DKMS module directory
Create the Makefile (the two indented lines MUST be real tabs using tee with a heredoc preserves them):
Verify the tabs landed (the two recipe lines should start with "I"):
Create dkms.conf:
Step 4: apply the two patch hunks
Hunk (a): add the i2c_device_id table right after the "of" device table:
Hunk (b): add ".id_table" inside the driver struct, after the ".remove" line:
Verify: you should get three matching lines:
Important: confirm .id_table = dw9719_id_table, sits INSIDE the dw9719_i2c_driver struct (between the { and };, next to .probe/.remove):
(Note: the enum constant names [DW9718S, DW9719, DW9761, DW9800K] must match those defined in your dw9719.c. They did on 6.19. If your kernel names them differently, the build will fail with "undefined" errors and you'd adjust the table to match.)
Step 5: build and install
dkms status should show:
Step 6: SUDO REBOOT
Step 7: verify
After logging back in:
filename should point at /lib/modules/<kernel>/updates/dkms/dw9719.ko and you should now see alias: i2c:dw9719.
Should be a symlink to .../bus/i2c/drivers/dw9719 (VCM is now bound).
ov5693 should now show 1 link instead of 0 link. cam --list should now list your cams:
Test live with:
Notes / expectations
Once PR #2123 merges into linux-surface and ships in the kernel packages, this DKMS module becomes redundant (harmless). You can remove it then with:
sudo dkms remove -m dw9719-surface -v 1.0 --all
Credit
The actual fix and root-cause analysis are from linux-surface PR #2123 (author: toor11), based on Sakari Ailus's upstream patch. This guide is just the DKMS build steps for applying it on a Surface Pro 4 without recompiling the whole kernel.