Skip to content

Internal trackpad tagged as external by udev on T2 Macs — libinput palm rejection (disable-while-typing) never engages #752

Description

@ratandeepbansal

Summary

On T2 Macs the internal trackpad is tagged ID_INPUT_TOUCHPAD_INTEGRATION=external by
systemd-udev. libinput deliberately refuses disable-while-typing (DWT) on external touchpads,
so palm rejection never engages and a palm resting on the trackpad moves the cursor and
relocates the caret while typing. On a 16" MacBook Pro this makes typing genuinely painful.

The cause is a t2bce_vhci hub-descriptor detail, so it should affect every T2 Mac, on
every distro, with no distro-specific configuration involved. I've confirmed the full chain on
a MacBookPro16,1 and fixed it locally with a udev hwdb override; a cleaner fix in the VHCI
driver would cover all models at once. Details and both patches below.

Root cause

The T2 tunnels the internal keyboard, trackpad, camera, ALS, headset and Touch Bar over the
virtual USB host controller instead of real USB ports:

/devices/pci0000:00/0000:00:1b.0/0000:04:00.1/t2bce_core/t2bce_core/t2bce_vhci/usb7/7-5/7-5:1.2/0003:05AC:0340.0005/input/input6/event6

Every device behind that virtual hub reports removable=unknown — although all of them are
soldered to the logic board and can never be unplugged:

$ for d in /sys/bus/usb/devices/*/; do r=$(cat "$d/removable" 2>/dev/null); \
    [ -n "$r" ] && echo "$(basename $d): $r  $(cat $d/product 2>/dev/null)"; done
7-1: unknown  Apple T2 Controller
7-2: unknown  FaceTime HD Camera (Built-in)
7-3: unknown  Ambient Light Sensor
7-4: unknown  Headset
7-5: unknown  Apple Internal Keyboard / Trackpad
7-6: unknown  Touch Bar Display
7-7: unknown  Touch Bar Backlight
usb7: unknown  BCE VHCI Host Controller

For comparison, the real xHCI controllers on the same machine classify their ports correctly
(usb1-port1: hotplug, usb2-port1: not used), while every VHCI port reads unknown.

systemd's /usr/lib/udev/rules.d/65-integration.rules then falls through to its
"unknown means assume external" line:

DRIVERS=="usb", ATTRS{devpath}!="0", ATTRS{removable}=="removable|unknown", \
    ENV{ID_INTEGRATION}="external", GOTO="libinput_integration_compat"

(ATTRS{devpath} is 5 for the keyboard/trackpad, so the !="0" guard passes.) The last line
of the same file propagates the guess to the touchpad property libinput actually reads:

ENV{ID_INPUT_TOUCHPAD}=="1", ENV{ID_INPUT_TOUCHPAD_INTEGRATION}="$env{ID_INTEGRATION}"

libinput's tp_init_dwt() bails out for external touchpads → DWT never initialises → no palm
rejection.

Why the keyboard half is already fine

DWT needs an internal keyboard to pair with, and that half already works: libinput ships

[Apple Internal Keyboard]
MatchName=*Apple Inc. Apple Internal Keyboard*
AttrKeyboardIntegration=internal

in 50-system-apple.quirks, which matches by name and is unaffected by the udev tag. Only the
touchpad side is broken.

Why this needs hwdb rather than a libinput quirk

libinput's quirks system has AttrKeyboardIntegration and AttrPointingStickIntegration, but
no touchpad-integration key (strings /usr/lib/libinput.so.10 — only those two exist). For
touchpads, integration comes solely from the udev property, and hwdb is the sanctioned override:
65-integration.rules itself carries the comment "must be loaded before 70-touchpad.rules to
allow hwdb quirks to override."

Workaround (works today, per model)

/etc/udev/hwdb.d/61-t2-trackpad-internal.hwdb:

touchpad:usb:v05acp0340:*
 ID_INPUT_TOUCHPAD_INTEGRATION=internal
sudo systemd-hwdb update
sudo udevadm trigger --subsystem-match=input --action=change
# then log out and back in

Two caveats worth documenting alongside it:

  1. A re-login (or reboot) is required. libinput reads the integration tag when it opens
    the device; the compositor has had the event node open since login. A udev change event
    does not trigger a re-open, and a compositor config reload doesn't help.
  2. p0340 is MacBookPro16,1-specific. Product IDs differ per model — a MacBook Air 2019
    reports 05ac:027a (per the lsusb posted in T2-Ubuntu#178). So this needs either a
    per-model table or a broader match.

I verified the blast radius before applying: a udevadm test-builtin dry-run diffed against the
live device changed exactly two properties (ID_INTEGRATION, ID_INPUT_TOUCHPAD_INTEGRATION).
ID_USB_DRIVER, DEVNAME, MAJOR/MINOR, LIBINPUT_DEVICE_GROUP and the size hints were
untouched, and the device stayed bound to magicmouse. It is metadata only — I grepped every
module under /lib/modules/7.1.8-*-t2/ for ID_INPUT_TOUCHPAD_INTEGRATION and got zero hits;
the only consumer on the system is libinput.so.10.

Palm rejection has been working correctly here since the re-login.

Proper fix — t2bce_vhci should advertise a compound device

The per-model hwdb table is a workaround for something the VHCI can state correctly once.
Everything behind that virtual hub is permanently attached, which is exactly what the USB
spec's compound device means.

In drivers/staging/t2bce/t2bce_vhci/vhci.c, bce_vhci_hub_control() answers
GetHubDescriptor with:

hd->wHubCharacteristics = HUB_CHAR_INDV_PORT_LPSM | HUB_CHAR_INDV_PORT_OCPM;

and the preceding memset(hd, 0, sizeof(*hd)) leaves u.hs.DeviceRemovable[] all zeros.
set_usb_port_removable() in drivers/usb/core/hub.c gates the whole DeviceRemovable check
behind the compound bit:

	if (!(wHubCharacteristics & HUB_CHAR_COMPOUND))
		return;
	...
		if (hub->descriptor->u.hs.DeviceRemovable[port / 8] & (1 << (port % 8)))
			removable = false;

so with the bit clear the device is left DEVICE_REMOVABLE_UNKNOWN. Setting the compound bit
and marking the ports non-removable should make it report fixed:

-        hd->wHubCharacteristics = HUB_CHAR_INDV_PORT_LPSM | HUB_CHAR_INDV_PORT_OCPM;
+        /* Everything behind the VHCI is soldered to the logic board. */
+        hd->wHubCharacteristics = HUB_CHAR_INDV_PORT_LPSM | HUB_CHAR_INDV_PORT_OCPM |
+                                  HUB_CHAR_COMPOUND;
+        memset(hd->u.hs.DeviceRemovable, 0xff, sizeof(hd->u.hs.DeviceRemovable));

That would fix the udev guess for every T2 Mac and every device behind the VHCI at once,
with no product-ID list to maintain, and it's semantically more accurate than what the
descriptor currently claims.

To be clear about what I have and haven't tested: the hwdb workaround is applied and
confirmed working on my machine. The driver change above is a reasoned proposal from reading
the two sources quoted — I have not built or run it. Happy to build a kernel and test it on
MacBookPro16,1 if that's useful, and to send it as a PR if the approach looks right. I wasn't
sure where a linux-t2-patches change should be discussed since that repo has issues disabled,
hence filing here — please move or redirect me.

What I'd suggest for the wiki either way

A short section (FAQ or the trackpad/input guide) covering: the symptom, the hwdb snippet, the
product IDs per model, and — importantly — the log out and back in step, which is the part
most likely to make someone conclude the fix didn't work.

Environment

Model MacBookPro16,1 (MacBook Pro 16" 2019)
Distro Omarchy 4.0.0.alpha (Arch), Hyprland
Kernel linux-t2 7.1.8.arch1-3
systemd 261.2-1
libinput 1.31.3-1
Trackpad 05ac:0340, magicmouse HID driver, /dev/input/event6

Related

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions