Linux kernel driver for the Microsoft Surface Laptop 3/4 (AMD) touchscreen, implementing the MSHW0231 / MSHW0162 V0 HID-over-SPI transport and a beta raw-heatmap multitouch pipeline on the AMD Cezanne FCH SPI controller.
Warning
Beta software. This is an experimental, reverse-engineered kernel driver. Use at your own risk. No warranty; provided "as is".
- Standard HID mode (default) provides single-touch only — basic tap, drag, and single-finger interaction. This is the qualified profile.
- A stylus/pen input node is published by the HID descriptor but is untested — pen behavior has not been observed or validated.
- No multi-touch in standard mode. Multi-touch requires the
beta raw pipeline (
raw_mode=1). - Raw mode is beta — functional on hardware, still under field review. Finger tracking is observed to degrade at 4 contacts; pipeline tuning is ongoing.
See docs/QUICKSTART.md for a 5-step install and
activation guide.
| Component | Detail |
|---|---|
| Model | Surface Laptop 4 (AMD Cezanne) / Surface Laptop 3 (AMD) |
| Touch ACPI ID | MSHW0231 (SL4, HID VID/PID: 0x045E/0x0C19) / MSHW0162 (SL3) |
| SPI Controller | AMDI0060 (AMD FCH SPI V2 at MMIO 0xFEC10000) |
| Protocol | HID-over-SPI Version 0 |
| Touch grid | 72×48 cells (SL4) / 78×52 cells (SL3) — selected by ACPI ID |
| Report rate | ~100 Hz (raw mode, field observation) |
| Feature | Implementation status | Release qualification |
|---|---|---|
| HID descriptor discovery | Implemented, with a hardcoded fallback | Hardware matrix required |
| Standard HID report forwarding | Implemented | Contact behavior requires hardware evidence |
| Raw CCL and multitouch pipeline | Implemented | Beta (functional on hardware, under field review) |
| Cold-boot retry and recovery | Implemented | Hardware matrix required |
| Candidate classification and per-cycle gain | Not implemented | Not planned for v1.x |
┌──────────────────────────────────────────────────────────────┐
│ Userspace: libinput / evdev ← hid-multitouch │
├──────────────────────────────────────────────────────────────┤
│ sl4a-spi-hid.ko (spi-hid-core.c, explicit opt-in only) │
│ ├─ HID LL driver (DESCREQ → DEVICE_DESC → RPT_DESC) │
│ ├─ IRQ-driven input (IRQ → SPI read → input_report) │
│ └─ Raw heatmap pipeline: │
│ baseline → peak gate → CCL → velocity → edge → │
│ split → centroid → pre-merge → Hungarian → │
│ EMA + deadband + stationary lock → MT emission │
├──────────────────────────────────────────────────────────────┤
│ sl4a-spi-amd.ko (spi-amd.c, explicit opt-in only) │
│ AMD FCH SPI controller V2 PIO driver │
│ TX/RX FIFO, chunked reads, opcode model │
├──────────────────────────────────────────────────────────────┤
│ Hardware: AMD FCH SPI @ 0xFEC10000 → MSHW0231 / MSHW0162 │
└──────────────────────────────────────────────────────────────┘
The raw multitouch pipeline is an experimental implementation that processes
the current 72×48 fallback grid into HID contacts. Its comparison targets and
unresolved frame-layout assumptions are recorded in docs/EVIDENCE.md.
| Stage | Function |
|---|---|
| c590 LUT | Byte-indexed CapImg sample → fixed-point: max(0, 10000 - ((i·22204 + 500)/1000 + 6000)) |
| Baseline | 30-frame asymmetric EMA per cell |
| Noise floor | c590 < 400 → suppressed (0.04 in the reference stack's fixed-point units) |
| Peak gate | Full radius-2 neighbourhood scan of touched cells, rise ≥200, max 20 peaks (equal-signal plateaus contribute one peak, anchored at the region's centre) |
| CCL flood-fill | 4-connected BFS, filters: n≥2, max_rise≥200, weight≥1000 |
| Velocity rejection | Blob must be within 6 cells of a detected peak |
| Edge penalty | Bottom edge ×0.23, other edges ×0.97 |
| Blob splitting | Multi-peak blobs (≥4 cells apart) split into sub-blobs |
| Centroid | Signal-weighted ×100 fixed-point on full blob extent |
| Eigenvalues | Second moments → touch major/minor/orientation |
| Pre-merge | Merge blobs within ghost_dist=6 (distance² < 36) |
| Hungarian | Assignment with multi-finger radii (1×2.2, 2×1.0, 3×2.8, 4×3.4, 5+×4.0) |
| EMA + deadband | Alpha=2 smoothing, ±0.2 cell deadband, 2-frame stationary lock |
| Lift lookback | Emit lift at position from 2 frames ago |
Read docs/SUPPORT.md before installing. This repository is
only for the Surface Laptop 3/4 AMD AMDI0060 + MSHW0231/MSHW0162 hardware
contracts.
The installer stages the modules through DKMS and then activates them right
away (Step 7): it binds the experimental modules as soon as it finishes, and
enables a systemd unit that keeps them bound on every future boot. Have recovery
access ready (a local console or a remote shell) before running it. On Secure
Boot systems the MOK key must be enrolled first; until it is, activation is
skipped and the boot unit does it after the enrollment reboot.
Modules use distinct sl4a-spi-amd and sl4a-spi-hid names and never replace
in-tree drivers.
See docs/COMPATIBILITY.md before treating a setup as
supported.
git clone https://github.com/Syax89/SL4A_TouchScreen.git
cd SL4A_TouchScreen
./tools/sl4a-touch.sh install --check
sudo ./tools/sl4a-touch.sh installinstall prompts interactively for a profile (standard HID, the supported
default, or the experimental raw multitouch profile) unless --standard or
--raw is given explicitly. --check performs a read-only ACPI and
build-prerequisite preflight and needs no root; --force only to investigate
unsupported hardware.
install activates the driver before it returns (Step 7), so have
local/remote recovery access available before running it. Two cases skip that
activation, and the installer says so when they apply: with Secure Boot the MOK
key must be enrolled first (the boot unit activates after the enrollment reboot),
and when the selected profile changes the load-time raw_mode parameter the
modules keep the previous profile until the next boot, where the boot unit
activates the new one. The
experimental controller can also be activated by hand with:
sudo ./tools/sl4a-touch.sh activateThe command refuses to displace existing AMDI0060 or touchscreen
(MSHW0231/MSHW0162) drivers, then
verifies both bindings. To recover after a failed experiment, run
sudo modprobe -r sl4a-spi-hid sl4a-spi-amd and reboot. Use
sudo ./tools/sl4a-touch.sh install --raw only for the experimental raw
heatmap profile. ./tools/sl4a-touch.sh status shows the installed version,
active profile, and whether the driver is currently loaded and bound;
sudo ./tools/sl4a-touch.sh logs collects a diagnostic bundle for bug reports.
The DKMS installer contains dependency guidance for Arch/CachyOS,
Ubuntu/Debian, Fedora, and openSUSE. Neither module exports aliases, so the
kernel never binds them on its own — the systemd unit install enables is what
repeats the binding after every boot. Secure Boot remains unqualified until recorded in the
compatibility matrix. See docs/ROLLBACK.md for the
complete rollback and upgrade procedure.
/etc/modprobe.d/sl4a-spi-hid.conf:
options sl4a_spi_hid raw_mode=N wire_double_opcode=1
The explicit raw profile written by sl4a-touch.sh install --raw uses
raw_mode=Y raw_input_beta=Y skip_getfeat=Y wire_double_opcode=1. Every raw control is experimental
and load-time-only. The complete release, diagnostic, and experimental contract
is in docs/PARAMETERS.md.
- Multi-touch in standard mode (
raw_mode=0) — the multi-touch input device is registered only by the raw pipeline (mshw0231-raw.c); standard mode forwards HID reports with no host-side tracking. - Pen input — the raw input device publishes touch contacts only and the driver contains no pen-specific handling, so pen behavior is unvalidated.
- Palm rejection — no palm/rejection stage exists in the pipeline.
- Other Surface models — the ACPI match tables accept only
MSHW0231/MSHW0162(touch) andAMDI0060(SPI controller).
| Issue | Fix |
|---|---|
| No touch after cold boot | Power off → unplug AC → wait 30s → reboot |
No touch after cold boot, but the driver looks ready (dmesg shows the descriptor, HID registered, ready) |
Set std_liveness_ms=8000 (echo 'options sl4a_spi_hid std_liveness_ms=8000' | sudo tee /etc/modprobe.d/sl4a-liveness.conf), cold boot, then read the standard-mode liveness line in dmesg: it reports the controller activity (IRQs) seen in that window, so a healthy idle device prints the alarm too (issue #4) |
No touch after cold boot and no RESET_RSP in dmesg at all |
Enable the backstop: echo 'options sl4a_spi_hid wait_reset_kick_ms=4000' | sudo tee /etc/modprobe.d/sl4a-kick.conf, then cold boot. dmesg then shows no RESET_RSP and no IRQ at all after 4000 ms, forcing DESCREQ, and the descriptor poller keeps reading until the device answers. A DESCREQ write to a silent controller failed 3 times line instead means the SPI write itself is failing (bus level), not that the device stayed quiet. If the touchscreen never comes back, power off, unplug AC, wait 30 s, reboot and report the log in issue #4 |
| No multi-touch (only single-touch) | Check raw_mode=Y in modprobe config |
| Fingers lost during fast movement | Increase blob_lift_frames |
| Jitter during pinch-to-zoom | Verify ema_alpha=2, stationary lock active |
| Module rejected (Secure Boot) | Enroll DKMS signing key via distribution MOK |
For development without DKMS (modules built this way are unsigned — turn Secure Boot off, or sign them yourself):
make -C /lib/modules/$(uname -r)/build M=$PWD/driver modules
sudo cp driver/sl4a-spi-amd.ko driver/sl4a-spi-hid.ko /lib/modules/$(uname -r)/updates/dkms/
sudo depmod -a
sudo ./tools/sl4a-touch.sh activateThe modules export no aliases, so the kernel never loads them on its own: after
a reboot run activate again, or use install, which also sets up the boot
unit that repeats the binding automatically.
| Document | Content |
|---|---|
| Wiki | Project wiki: protocol, pipeline, config, hardware |
docs/QUICKSTART.md |
5-step install and activation guide |
docs/HIDSPI_PROTOCOL.md |
HID-over-SPI V0 wire protocol |
docs/PIPELINE.md |
Touch pipeline specification |
docs/SPI_REGISTERS.md |
AMD FCH SPI controller registers |
docs/AMDI0060_CONTRACT.md |
AMDI0060 controller boundary and safety contract |
docs/CONFIG_TABLE.md |
Config table values |
docs/ACTIVATION.md |
Raw mode activation (SET_FEATURE ID5) |
docs/CONTACT_ABI.md |
Contact struct ABI |
docs/ETW_CSV_FORMAT.md |
Windows trace format |
docs/decomp/ |
Driver reference captures |
docs/SUPPORT.md |
Supported hardware and release profiles |
docs/COMPATIBILITY.md |
Hardware validation matrix |
docs/TESTING.md |
Reproducible validation procedure |
docs/EVIDENCE.md |
Evidence ledger and open discrepancies |
docs/HARDWARE_VALIDATION.md |
Blinded hardware-validation protocol and bounded input captures |
GPL-2.0. See LICENSE.