Appendix · reference

PineTab2 GPIO switches

Tablet-mode and lid/hall switch events through gpiokeys(4).

Identity

PartTablet-mode switch and lid/hall sensor
RoleKeyboard/tablet mode and cover-open/closed state
Bus / addressgpio-keys FDT child nodes
GPIO / IRQTablet mode: GPIO4_A4, active high; Hall sensor: GPIO0_A6, active low on v2.0
DTS event typelinux,input-type = <EV_SW>
DTS event codesSW_TABLET_MODE and SW_LID

Status — ◐ partial

The PineTab2 DTS does not describe these as normal keyboard buttons. Both nodes are switch events: SW_TABLET_MODE for keyboard/tablet state, and SW_LID for the v2.0 hall sensor. FreeBSD’s stock gpiokeys(4) path only treated linux,code as EV_KEY, which is right for power and volume buttons but wrong for these two tablet signals.

The local patch makes gpiokeys(4) read optional linux,input-type. Plain buttons still default to EV_KEY; EV_SW nodes advertise switch capabilities with evdev_support_sw() and report state with evdev_push_sw() instead of inventing keyboard scan codes.

Hardware proof is still pending. The first tablet session should verify that /dev/input/event* exposes SW_TABLET_MODE and SW_LID, then capture open/closed and keyboard-attached/detached transitions with evemu-record or libinput debug-events.

Patch

sys/dev/gpio/gpiokeys.c

@@ -83,6 +83,9 @@
83 83 #define SCAN_RELEASE 0x80
84 84 #define SCAN_CHAR(c) ((c) & 0x7f)
85 85
86 + #define GPIOKEYS_LINUX_EV_KEY 0x01
87 + #define GPIOKEYS_LINUX_EV_SW 0x05
88 +
86 89 #define GPIOKEYS_GLOBAL_NMOD 8 /* units */
87 90 #define GPIOKEYS_GLOBAL_NKEYCODE 6 /* units */
88 91 #define GPIOKEYS_GLOBAL_IN_BUF_SIZE (2*(GPIOKEYS_GLOBAL_NMOD + (2*GPIOKEYS_GLOBAL_NKEYCODE))) /* bytes */
@@ -105,6 +108,7 @@
105 108 struct mtx mtx;
106 109 #ifdef EVDEV_SUPPORT
107 110 uint32_t evcode;
111 + uint32_t evtype;
108 112 #endif
109 113 uint32_t keycode;
110 114 int autorepeat;
@@ -189,7 +193,10 @@
189 193 #ifdef EVDEV_SUPPORT
190 194 if (key->evcode != GPIOKEY_NONE &&
191 195 (evdev_rcpt_mask & EVDEV_RCPT_HW_KBD) != 0) {
192 evdev_push_key(sc->sc_evdev, key->evcode, pressed);
196 + if (key->evtype == EV_SW)
197 + evdev_push_sw(sc->sc_evdev, key->evcode, pressed);
198 + else
199 + evdev_push_key(sc->sc_evdev, key->evcode, pressed);
193 200 evdev_sync(sc->sc_evdev);
194 201 }
195 202 if (evdev_is_grabbed(sc->sc_evdev)) {
@@ -277,6 +284,7 @@
277 284 pcell_t prop;
278 285 char *name;
279 286 uint32_t code;
287 + uint32_t evtype;
280 288 int err;
281 289 const char *key_name;
282 290
@@ -284,6 +292,11 @@
284 292 key->parent_sc = sc;
285 293 callout_init_mtx(&key->debounce_callout, &key->mtx, 0);
286 294 callout_init_mtx(&key->repeat_callout, &key->mtx, 0);
295 + key->keycode = GPIOKEY_NONE;
296 + #ifdef EVDEV_SUPPORT
297 + key->evcode = GPIOKEY_NONE;
298 + key->evtype = EV_KEY;
299 + #endif
287 300
288 301 name = NULL;
289 302 if (OF_getprop_alloc(node, "label", (void **)&name) == -1)
@@ -313,14 +326,33 @@
313 326 key->keycode = fdt32_to_cpu(prop);
314 327 else if ((OF_getprop(node, "linux,code", &prop, sizeof(prop))) > 0) {
315 328 code = fdt32_to_cpu(prop);
316 key->keycode = gpiokey_map_linux_code(code);
317 if (key->keycode == GPIOKEY_NONE)
318 device_printf(sc->sc_dev, "<%s> failed to map linux,code value 0x%x\n",
319 key_name, code);
329 + evtype = GPIOKEYS_LINUX_EV_KEY;
330 + if (OF_getprop(node, "linux,input-type", &prop, sizeof(prop)) > 0)
331 + evtype = fdt32_to_cpu(prop);
332 + if (evtype == GPIOKEYS_LINUX_EV_SW) {
320 333 #ifdef EVDEV_SUPPORT
321 key->evcode = code;
322 evdev_support_key(sc->sc_evdev, code);
334 + key->evcode = code;
335 + key->evtype = EV_SW;
336 + evdev_support_event(sc->sc_evdev, EV_SW);
337 + evdev_support_sw(sc->sc_evdev, code);
338 + #else
339 + device_printf(sc->sc_dev, "<%s> EV_SW requires evdev support\n",
340 + key_name);
323 341 #endif
342 + } else if (evtype == GPIOKEYS_LINUX_EV_KEY) {
343 + key->keycode = gpiokey_map_linux_code(code);
344 + if (key->keycode == GPIOKEY_NONE)
345 + device_printf(sc->sc_dev, "<%s> failed to map linux,code value 0x%x\n",
346 + key_name, code);
347 + #ifdef EVDEV_SUPPORT
348 + key->evcode = code;
349 + key->evtype = EV_KEY;
350 + evdev_support_key(sc->sc_evdev, code);
351 + #endif
352 + } else {
353 + device_printf(sc->sc_dev, "<%s> unsupported linux,input-type value 0x%x\n",
354 + key_name, evtype);
355 + }
324 356 }
325 357 else
326 358 device_printf(sc->sc_dev, "<%s> no linux,code or freebsd,code property\n",

Bring-Up Predicate

After booting the PineTab2 kernel:

sysctl -a | grep gpiokeys
libinput debug-events

Expected first-pass evidence:

  1. The gpio-keys device attaches without “unsupported linux,input-type” messages.
  2. Toggling the keyboard attachment changes SW_TABLET_MODE.
  3. Moving the cover or a magnet over the hall sensor changes SW_LID.
  4. Neither switch produces stray key presses through the keyboard path.

Open Work