Camera Support - linux-surface/linux-surface GitHub Wiki
Running the cameras on Surface is a work in progress.
Check out https://github.com/linux-surface/linux-surface/issues/91#issuecomment-1917874317 for links to ongoing discussions.
Please note that where your camera is marked as working (✅), the image quality is not expected to be perfect yet. The algorithms are still undergoing development, and need some camera specific tuning.
This page will detail the steps required to be able to get the camera working on your device, with the current latest support.
If you have successfully enabled your camera on a device not yet in this table, please update it:
Device | ISP | Front | Back | IR |
---|---|---|---|---|
Surface Go | IPU3 | OV5693 ✅ | OV8865 ✅ | OV7251 🚫 |
Surface Go 2 | IPU3 | OV5693 ✅ | OV8865 ✅ | OV7251 🚫 |
Surface Go 3 | IPU3 | OV5693 ✅ | OV8865 ✅ | OV7251 🚫 |
Surface Pro 4 | IPU3 | OV5693 ✅ | OV8865 ✅ | OV7251 🚫 |
Surface Pro 5 | IPU3 | OV5693 ✅ | OV8865 ✅ | OV7251 🚫 |
Surface Pro 6 | IPU3 | OV5693 ✅ | OV8865 ✅ | OV7251 🚫 |
Surface Pro 7 | IPU4 | OV5693 🚫 | OV8865 🚫 | OV7251 🚫 |
Surface Pro 7+ | IPU6 | OV5693 🚫 | OV8865 🚫 | OV7251 🚫 |
Surface Pro 8 | IPU6 | OV5693 🚫 | OV13858 🚫 | VD55G0 🚫 |
Surface Pro 9 (Intel) | IPU6 | OV5693 🚫 | OV13858 🚫 | VD55G0 (?) 🚫 |
Surface Book 1 | IPU3 | OV5693 ✅ | OV8865 ✅ | OV7251 🚫 |
Surface Book 2 13" | IPU3 | OV5693 ✅ | OV8865 ✅ | OV7251 🚫 |
Surface Book 3 | IPU4 | OV5693 🚫 | OV8865 🚫 | OV7251 🚫 |
Surface Laptop 1 | IPU3 | OV9734 🚫 | N/A | OV7251 🚫 |
Surface Laptop 2 | IPU3 | OV9734 🚫 | N/A | OV7251 🚫 |
Surface Laptop 3 (Intel) | IPU4 | OV9734 🚫 | N/A | OV7251 🚫 |
Surface Laptop 3 (AMD) | (USB/UVC) | OV5693 ✅ | N/A | OV7251 ✅ |
Surface Laptop 4 | (USB/UVC) | ✅ | N/A | ? |
Surface Laptop 5 | (USB/UVC) | ? | N/A | ? |
Surface Laptop Studio | (USB/UVC) | ? | N/A | ? |
The Surface Pro 7, Surface Laptop 3 (Intel) and the Surface Book 3 use an IPU4 which can not be supported at this time
Kernel patches and drivers are required to be built to support your device.
The best way to obtain these for a Surface device is to use one of the binary releases provided by this repository.
Alternatively, you can also build a kernel yourself and apply the cameras.patch
found in this repository under patches/<version>/cameras.patch
(e.g. patches/v5.12/cameras.patch
).
Supporting the Camera on the Surface range requires extending the Intel IPU3 driver to support the Windows based ACPI definitions. This is being handled by an extension to the IPU3-CIO2 driver called the CIO2-Bridge.
The IPU3 used by the Surface requires some firmware to support the devices which is loaded at runtime.
On Ubuntu-based systems, this firmware is provided by the 'linux-firmware' package.
For Fedora the firmware is provided by the intel-vsc-firmware
package.
According to this response, for Debian, the ipu3 firmware is provided by firmware-misc-nonfree
from the nonfree repo. The .bin file is named irci_irci_ecr-master_20161208_0213_20170112_1500.bin
and must be renamed and moved to /lib/firmware/intel/ipu3-fw.bin
.
The file:
/lib/firmware/intel/ipu3-fw.bin
is required to be present at kernel boot time to support loading of the IPU3 IMGU device.
To test the cameras on the Surface devices we need libcamera to provide the userspace support required to operate the cameras.
Some flavours of Linux have repositories containing versions of libcamera, which you can install without building libcamera from source.
Use apt to install libcamera packages:
sudo apt install libcamera0.2 gstreamer1.0-libcamera libcamera-ipa pipewire-libcamera libcamera-tools
It has been reported that, on Fedora 36, as long as you have linux-surface kernel 5.18 or newer installed, you should be able to install libcamera components via dnf
:
sudo dnf install libcamera libcamera-tools libcamera-qcam libcamera-gstreamer libcamera-ipa pipewire-plugin-libcamera
If you're using an immutable variant of Fedora (Silverblue, Kinoite,Sericea, etc), you should use rpm-ostree
:
rpm-ostree install libcamera libcamera-tools libcamera-qcam libcamera-gstreamer libcamera-ipa pipewire-plugin-libcamera
Arch now ships a stable libcamera
package (pacman -S libcamera
). You may also want to install the following packages:
-
libcamera-tools
forcam
andqcam
-
gst-plugin-libcamera
for the gstreamer libcamera plugin (required to use applications that don't directly support libcamera)
Both clang and gcc are supported compilers.
First install the required dependencies (e.g. on Debian/Ubuntu, a '\' denotes the line is continued)
$ sudo apt install \
build-essential meson ninja-build pkg-config libgnutls28-dev openssl \
python3-pip python3-yaml python3-ply python3-jinja2 \
qtbase5-dev libqt5core5a libqt5gui5 libqt5widgets5 qttools5-dev-tools \
libtiff-dev libevent-dev libyaml-dev \
gstreamer1.0-tools libgstreamer1.0-dev libgstreamer-plugins-base1.0-dev
And now obtain and build libcamera:
$ sudo apt install git
$ git clone https://git.libcamera.org/libcamera/libcamera.git
$ cd libcamera
Configure libcamera minimally for the Surface
$ meson build -Dpipelines=uvcvideo,vimc,ipu3 -Dipas=vimc,ipu3 -Dprefix=/usr -Dgstreamer=enabled -Dv4l2=true -Dbuildtype=release
$ ninja -C build
$ sudo ninja -C build install
Running on a fresh system, I needed to run this, and it doesn't hurt to be sure (but shouldn't be needed):
$ ldconfig
If your distro doesn't provide meson>=0.55, you can use the following methods to install the latest meson for building:
$ sudo pip3 install -U meson
Usually you shouldn't use sudo pip
because it might conflict with your distro's package manager. However, it is a documented method to install meson. And if you have different versions installed for user and system-wide, or only install meson for user, sudo ninja -C build install
might not work.
MPR is like AUR for Debian/Ubuntu. To use it, you need to install makedeb.
After installing makedeb, pull meson's PKGBUILD from MBR:
$ git clone https://mpr.hunterwittenborn.com/meson.git
$ cd meson
$ cat PKGBUILD # Have a look at the PKGBUILD
If your apt version is lower than 1.9, makedeb cannot install the dependencies for you, and you'll need to install the packages in makedepends
array manually. Then build and install the package:
$ makedeb -si
Alternatively, use the method above to install MPR helper tap, and install meson through tap:
$ tap install meson
Make sure your user is part of the 'video' group. (you only need to do this once on the machine)
$ sudo usermod -aG video $USER
$ newgrp video
Now you can run cam --list and you should see the sensor listed
$ cam --list
Available cameras:
1: Internal front camera (\*SB*.PCI0.LNK1)
and running qcam should (all being well) get you a view of the video capture.
$ qcam
Cheese uses Gstreamer to read from cameras, and should work as long as the gstreamer libcamerasrc plugin is correctly built and installed.
Since version 116, Firefox added experimental support to pipewire camera. Navigate to about:config
, enable media.webrtc.camera.allow-pipewire
and restart Firefox. Make sure the plugin pipewire-plugin-libcamera
is installed in your distribution.
Right now only applications using libcamera (directly or indirectly, e.g. via the gstreamer plugin) are supported.
It is, however, possible to use gstreamer to create a loopback device.
To do this, you have to install v4l2loopback-dkms
(if you're using Secure Boot you have to also follow this guide: https://github.com/umlaeute/v4l2loopback/wiki/Secure-Boot) and run
sudo modprobe v4l2loopback video_nr=42 card_label="virtualcam" exclusive_caps=1
to set up the kernel module and
gst-launch-1.0 libcamerasrc camera-name='\\\_SB_.PCI0.I2C2.CAMF' ! \
video/x-raw,width=1280,height=720,framerate=30/1,format=NV12 \
! videoconvert ! video/x-raw,format=YUY2 ! queue ! \
v4l2sink device=/dev/video42
to create the loopback device.
Note that you may need to change camera-name
, v4l2sink device
, and/or other parameters for your setup.
If issues occur, you maybe need to remove queue !
from the command:
gst-launch-1.0 libcamerasrc camera-name='\\\_SB_.PCI0.I2C2.CAMF' ! \
video/x-raw,width=1280,height=720,framerate=30/1,format=NV12 \
! videoconvert ! video/x-raw,format=YUY2 ! \
v4l2sink device=/dev/video42
This guide also explains how to automatically load v4l2loopback on startup and how to create a terminal command to start the cameras quicker: https://neilzone.co.uk/2021/08/working-front-and-rear-cameras-on-debian-11-on-a-surface-pro-6-surfacebook-2-and-surface-go/
Device | ISP | Front Sensor | Front Module | Rear Sensor | Rear Module | IR Sensor | IR Module |
---|---|---|---|---|---|---|---|
SGo1 | IPU3 | OV5693 | YHCU | OV8865 | YHCT | OV7251 | YHCV |
SGo2/3 | IPU3 | OV5693 | YHCU | OV8865 | YHCT | OV7251 | YHCV |
SB1 | IPU3 | OV5693 | MSHW0070 | OV8865 | MSHW0071 | OV7251 | MSHW0072 |
SB2 13" | IPU3 | OV5693 | MSHW0140 | OV8865 | MSHW0141 | OV7251 | MSHW0142 |
SB2 15" | IPU3 | OV5693 | MSHW0150 | OV8865 | MSHW0151 | OV7251 | MSHW0152 |
SB3 13" | IPU4 | OV5693 | MSHW0210 | OV8865 | MSHW0211 | OV7251 | MSHW0212 |
SB3 15" | IPU4 | OV5693 | MSHW0200 | OV8865 | MSHW0201 | OV7251 | MSHW0202 |
SL1 | IPU3 | OV9734 | MSHW0073 | - | - | OV7251 | MSHW0074 |
SL2 | IPU3 | OV9734 | MSHW0073 | - | - | OV7251 | MSHW0074 |
SP4 | IPU3 | OV5693 | MSHW0070 | OV8865 | MSHW0071 | OV7251 | MSHW0072 |
SP5 | IPU3 | OV5693 | MSHW0120 | OV8865 | MSHW0121 | OV7251 | MSHW0122 |
SP6 | IPU3 | OV5693 | MSHW0120 | OV8865 | MSHW0121 | OV7251 | MSHW0122 |
SP7 | IPU4 | OV5693 | MSHW0190 | OV8865 | MSHW0191 | OV7251 | MSHW0192 |
Note: SL3 and SLGo1 use generic USB cameras and work out of the box.
Sensor ID | ACPI ID |
---|---|
AR0330 | APTA0330 |
IMX135 | INT3471 |
OV2680 | OVTI2680 |
OV2740 | INT3474 |
OV5648 | OVTI5648 |
OV5693 | INT33BE |
OV7251 | INT347E |
OV8835 | OV8835, OVTI8835 |
OV8865 | INT347A |
OV9734 | OVTI9734 |
For some of the work to build camera support, reverse engineering the settings made by the Windows drivers for either the camera devices or their supporting ICs is necessary. One way to do this is to talk to the i2c devices directly and read the registers to discover the settings. A mandatory first step is informing Windows that direct user access to those devices is allowed.
To perform that operation you will first need the microsoft asl compiler tool. This lets you extract and insert modified DSDT tables in Windows.
Once you've got that tool built, you need to edit the DSDT table to tell Windows to expose the I2C device for the PMIC. Run asl.exe /tab=DSDT
to get a file named DSDT.asl in the current directory. You then need to make edits following this guide to add a section to the DSDT that creates an MSFT8000 dummy device and adds an I2cSerialBus entry describing the I2C Bus that the target device sits on, for example:
Device(RHPX)
{
Name(_HID, "MSFT8000")
Name(_CID, "MSFT8000")
Name(_UID, 1)
Name(_CRS, ResourceTemplate()
{
I2CSerialBus(0xFFFF, , 0, , "\\_SB.PCI0.I2C2", , ,) // in this case, we want to grant access to the I2C2 bus
})
Name(_DSD, Package()
{
ToUUID("daffd814-6eba-4d8c-8a91-bc9bbf4aa301"),
Package()
{
Package(2) { "bus-I2C-I2C2", Package() { 0 }}, // The 0 here is the index of the related resource in _CRS
}
})
}
You also need to increase the version number of the table in the `DefinitionBlock() or the edits will be ignored
Once that's done, compile the edited DSDT.asl using asl.exe DSDT.ASL
. If it throws compiler errors you'll have to fix them. If you can't get it working using this tool you can actually boot Linux and try using iasl, which is Intel's equivalent and seems to work a lot better. You'd have to transfer the compiled file back to Windows somehow.
Once the file's compiled, you insert it using asl.exe /loadtable -v DSDT.AML
.
Pay attention to the output of the command as you may need to enable test signing mode (bcdedit /set testsigning on
) and disable secure boot.
Finally, you need to reboot.
To talk to the I2C devices themselves, use the I2cTestTool. Build that and run I2cTestTool <<addr>> <<busname>>
to connect to the device. For example to connect to the device at 0x4d on I2C bus 2 the command would be I2cTestTool 0x4d I2C2
. You can then perform read and write operations over I2C. To read a register value you use the writeread
command, sending the address of the register followed by the number of registers you want to read, for example writeread {30 0a} 2
to read 0x300a and 0x300b, which on Omnivision sensors is usually the chip's ID.
The I2C workaround should not be required any more. This is fixed in the linux-surface kernels, and the fix should be heading upstream to other distribution kernels. This section is kept for reference only.
On a Surface Go 2 a workaround is required to enable the front camera support: The kernel needs to have the following command line parameter added to the boot arguments.
acpi_enforce_resources=lax
Where to put this is quite platform specific, however continuing the assumption that an Ubuntu or Debian based system is in use, we can infer that the system uses grub.
On the Surface Go device itself, edit the file "/etc/default/grub" and update the GRUB_CMDLINE_LINUX_DEFAULT entry to add the workaround:
-GRUB_CMDLINE_LINUX_DEFAULT="quiet splash"
+GRUB_CMDLINE_LINUX_DEFAULT="quiet splash acpi_enforce_resources=lax"