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:
- 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.
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
Summary
On T2 Macs the internal trackpad is tagged
ID_INPUT_TOUCHPAD_INTEGRATION=externalbysystemd-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_vhcihub-descriptor detail, so it should affect every T2 Mac, onevery 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:
Every device behind that virtual hub reports
removable=unknown— although all of them aresoldered to the logic board and can never be unplugged:
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 readsunknown.systemd's
/usr/lib/udev/rules.d/65-integration.rulesthen falls through to its"unknown means assume external" line:
(
ATTRS{devpath}is5for the keyboard/trackpad, so the!="0"guard passes.) The last lineof the same file propagates the guess to the touchpad property libinput actually reads:
libinput's
tp_init_dwt()bails out for external touchpads → DWT never initialises → no palmrejection.
Why the keyboard half is already fine
DWT needs an internal keyboard to pair with, and that half already works: libinput ships
in
50-system-apple.quirks, which matches by name and is unaffected by the udev tag. Only thetouchpad side is broken.
Why this needs hwdb rather than a libinput quirk
libinput's quirks system has
AttrKeyboardIntegrationandAttrPointingStickIntegration, butno touchpad-integration key (
strings /usr/lib/libinput.so.10— only those two exist). Fortouchpads, integration comes solely from the udev property, and hwdb is the sanctioned override:
65-integration.rulesitself carries the comment "must be loaded before 70-touchpad.rules toallow hwdb quirks to override."
Workaround (works today, per model)
/etc/udev/hwdb.d/61-t2-trackpad-internal.hwdb:sudo systemd-hwdb update sudo udevadm trigger --subsystem-match=input --action=change # then log out and back inTwo caveats worth documenting alongside it:
the device; the compositor has had the event node open since login. A udev
changeeventdoes not trigger a re-open, and a compositor config reload doesn't help.
p0340is MacBookPro16,1-specific. Product IDs differ per model — a MacBook Air 2019reports
05ac:027a(per thelsusbposted in T2-Ubuntu#178). So this needs either aper-model table or a broader match.
I verified the blast radius before applying: a
udevadm test-builtindry-run diffed against thelive device changed exactly two properties (
ID_INTEGRATION,ID_INPUT_TOUCHPAD_INTEGRATION).ID_USB_DRIVER,DEVNAME,MAJOR/MINOR,LIBINPUT_DEVICE_GROUPand the size hints wereuntouched, and the device stayed bound to
magicmouse. It is metadata only — I grepped everymodule under
/lib/modules/7.1.8-*-t2/forID_INPUT_TOUCHPAD_INTEGRATIONand 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_vhcishould advertise a compound deviceThe 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()answersGetHubDescriptorwith:and the preceding
memset(hd, 0, sizeof(*hd))leavesu.hs.DeviceRemovable[]all zeros.set_usb_port_removable()indrivers/usb/core/hub.cgates the wholeDeviceRemovablecheckbehind the compound bit:
so with the bit clear the device is left
DEVICE_REMOVABLE_UNKNOWN. Setting the compound bitand marking the ports non-removable should make it report
fixed: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-patcheschange 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
linux-t27.1.8.arch1-305ac:0340,magicmouseHID driver,/dev/input/event6Related
lsusboutput is thesource for the MacBook Air 2019 product ID above.
remembering if this is ever fixed globally: users who want the old behaviour can turn DWT off
in their compositor.