Index | Thread | Search

From:
Miod Vallat <miod@online.fr>
Subject:
Re: return of the chromebook keyboard diff
To:
tech@openbsd.org
Date:
Thu, 30 Jan 2025 20:35:43 +0000

Download raw body.

Thread
Updated diff:
- adds LEN0071 to the "might need pckbc@acpi" list
- fixes and adds a few comments
- reworks match logic to run faster

Index: share/man/man4/acpi.4
===================================================================
RCS file: /OpenBSD/src/share/man/man4/acpi.4,v
diff -u -p -u -p -r1.76 acpi.4
--- share/man/man4/acpi.4	5 Nov 2024 11:12:48 -0000	1.76
+++ share/man/man4/acpi.4	30 Jan 2025 20:26:07 -0000
@@ -132,6 +132,8 @@ Intel OnChip System Fabric device
 Intelligent Platform Management Interface driver
 .It Xr pchgpio 4
 Intel PCH GPIO controller
+.It Xr pckbc 4
+Keyboard controller
 .It Xr pluart 4
 ARM PrimeCell PL011 UART
 .It Xr qcgpio 4
Index: share/man/man4/pckbc.4
===================================================================
RCS file: /OpenBSD/src/share/man/man4/pckbc.4,v
diff -u -p -u -p -r1.18 pckbc.4
--- share/man/man4/pckbc.4	26 Sep 2010 20:39:08 -0000	1.18
+++ share/man/man4/pckbc.4	30 Jan 2025 20:26:07 -0000
@@ -33,6 +33,7 @@
 .Nd PC (ISA) keyboard controller driver
 .Sh SYNOPSIS
 .Cd "pckbc* at isa? flags 0x00           " Pq "alpha, amd64, i386, loongson"
+.Cd "pckbc* at acpi? flags 0x00          " Pq "amd64"
 .Cd "pckbc* at ebus?                     " Pq "sparc64"
 .Cd "pckbd* at pckbc?"
 .Cd "pms*   at pckbc?"
@@ -40,21 +41,17 @@
 The
 .Nm
 driver handles resource allocation and device attachment for the
-traditional PC/AT keyboard controller.
-It provides two logical connections for child devices, the
+traditional PC/AT keyboard controller, or emulations thereof.
+It provides up to two logical connections for child devices, the
 .Dq keyboard
 slot for a keyboard and the
 .Dq auxiliary
-slot for mice (the latter might be missing in older keyboard controllers).
-.\" .Pp
-.\" The optional
-.\" .Dq slot
-.\" locator argument can be used to force unusual connections of devices to
-.\" logical slots.
-.\" This feature is for experimentation only, it will not be
-.\" useful in normal operation.
+slot for mice (the latter might be missing in older keyboard controllers,
+or recent emulations).
 .Pp
 To avoid attaching a phantom PS/2 keyboard device, the
+.Nm isa 4
+attachment of the
 .Nm
 driver will attempt to detect USB legacy keyboard emulation on amd64 and i386
 systems.
@@ -62,7 +59,19 @@ Unfortunately, the detection heuristics 
 PS/2 keyboard.
 The keyboard can be forced to attach on these systems, by changing the
 device flags to 1.
+.Pp
+The
+.Nm acpi 4
+attachment of the
+.Nm
+driver defaults to attach to only a well-known list of devices where it would
+perform better than its legacy
+.Nm isa 4
+attachment.
+It is possible to force it to always attach, by changing its
+device flags to 1.
 .Sh SEE ALSO
+.Xr acpi 4 ,
 .Xr ebus 4 ,
 .Xr intro 4 ,
 .Xr isa 4 ,
Index: sys/arch/amd64/conf/GENERIC
===================================================================
RCS file: /OpenBSD/src/sys/arch/amd64/conf/GENERIC,v
diff -u -p -u -p -r1.530 GENERIC
--- sys/arch/amd64/conf/GENERIC	26 Nov 2024 21:45:35 -0000	1.530
+++ sys/arch/amd64/conf/GENERIC	30 Jan 2025 20:26:07 -0000
@@ -86,6 +86,7 @@ ipmi0		at acpi? disable
 ccpmic*		at iic?
 tipmic*		at iic?
 intelpmc*	at acpi?
+pckbc*		at acpi?
 
 efi0		at bios0
 mpbios0		at bios0
Index: sys/arch/amd64/conf/RAMDISK
===================================================================
RCS file: /OpenBSD/src/sys/arch/amd64/conf/RAMDISK,v
diff -u -p -u -p -r1.87 RAMDISK
--- sys/arch/amd64/conf/RAMDISK	12 Aug 2024 18:43:41 -0000	1.87
+++ sys/arch/amd64/conf/RAMDISK	30 Jan 2025 20:26:07 -0000
@@ -37,6 +37,7 @@ acpimadt0	at acpi?
 com0		at acpi? addr 0x3f8
 com1		at acpi? addr 0x2f8
 com*		at acpi?
+pckbc*		at acpi?
 
 mpbios0		at bios0
 
Index: sys/arch/amd64/conf/RAMDISK_CD
===================================================================
RCS file: /OpenBSD/src/sys/arch/amd64/conf/RAMDISK_CD,v
diff -u -p -u -p -r1.209 RAMDISK_CD
--- sys/arch/amd64/conf/RAMDISK_CD	26 Nov 2024 21:45:35 -0000	1.209
+++ sys/arch/amd64/conf/RAMDISK_CD	30 Jan 2025 20:26:07 -0000
@@ -56,6 +56,7 @@ com1		at acpi? addr 0x2f8
 com2		at acpi? addr 0x3e8
 com*		at acpi?
 glkgpio*	at acpi?
+pckbc*		at acpi?
 
 mpbios0		at bios0
 
Index: sys/dev/acpi/acpi.c
===================================================================
RCS file: /OpenBSD/src/sys/dev/acpi/acpi.c,v
diff -u -p -u -p -r1.440 acpi.c
--- sys/dev/acpi/acpi.c	23 Jan 2025 11:24:34 -0000	1.440
+++ sys/dev/acpi/acpi.c	30 Jan 2025 20:26:07 -0000
@@ -3037,12 +3037,9 @@ const char *acpi_skip_hids[] = {
 
 /* ISA devices for which we attach a driver later */
 const char *acpi_isa_hids[] = {
-	"PNP0303",	/* IBM Enhanced Keyboard (101/102-key, PS/2 Mouse) */
 	"PNP0400",	/* Standard LPT Parallel Port */
 	"PNP0401",	/* ECP Parallel Port */
 	"PNP0700",	/* PC-class Floppy Disk Controller */
-	"PNP0F03",	/* Microsoft PS/2-style Mouse */
-	"PNP0F13",	/* PS/2 Mouse */
 	NULL
 };
 
Index: sys/dev/acpi/files.acpi
===================================================================
RCS file: /OpenBSD/src/sys/dev/acpi/files.acpi,v
diff -u -p -u -p -r1.71 files.acpi
--- sys/dev/acpi/files.acpi	4 Aug 2024 11:05:18 -0000	1.71
+++ sys/dev/acpi/files.acpi	30 Jan 2025 20:26:07 -0000
@@ -289,3 +289,7 @@ file	dev/acpi/iosf_acpi.c		iosf_acpi
 device	intelpmc
 attach	intelpmc at acpi
 file	dev/acpi/intelpmc.c		intelpmc
+
+# PS/2 Keyboard Controller
+attach	pckbc at acpi with pckbc_acpi
+file	dev/acpi/pckbc_acpi.c		pckbc_acpi
Index: sys/dev/acpi/pckbc_acpi.c
===================================================================
RCS file: sys/dev/acpi/pckbc_acpi.c
diff -N sys/dev/acpi/pckbc_acpi.c
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ sys/dev/acpi/pckbc_acpi.c	30 Jan 2025 20:26:07 -0000
@@ -0,0 +1,552 @@
+/*	$OpenBSD$	*/
+/*
+ * Copyright (c) 2024, 2025, Miodrag Vallat.
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+/*
+ * Copyright (c) 1998
+ *	Matthias Drochner.  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/device.h>
+#include <sys/malloc.h>
+
+#include <machine/bus.h>
+
+#include <dev/acpi/acpidev.h>
+#include <dev/acpi/acpivar.h>
+#include <dev/acpi/amltypes.h>
+#include <dev/acpi/dsdt.h>
+
+#include <dev/ic/i8042reg.h>
+#include <dev/ic/pckbcvar.h>
+
+/*
+ * This driver is more complicated than it should have to be, as it needs
+ * to gather the needs of pckbc (2 I/O ports, and up to 2 interrupts),
+ * which may be scattered across two ACPI nodes.
+ * Because of this, it is able to attach to two different ACPI nodes,
+ * but the second attachment "hijacks" the first one's softc struct, so
+ * that all the required data is gathered in one place.
+ */
+
+int	pckbc_acpi_match(struct device *, void *, void *);
+void	pckbc_acpi_attach(struct device *, struct device *, void *);
+int	pckbc_acpi_activate(struct device *, int);
+
+struct pckbc_acpi_softc {
+	struct pckbc_softc sc;
+	void *sc_ih[2];
+	unsigned int sc_nints;
+};
+
+const struct cfattach pckbc_acpi_ca = {
+	.ca_devsize = sizeof(struct pckbc_acpi_softc),
+	.ca_match = pckbc_acpi_match,
+	.ca_attach = pckbc_acpi_attach,
+	.ca_activate = pckbc_acpi_activate
+};
+
+struct pckbc_acpi_gpio_intr {
+	struct aml_node *node;
+	uint16_t pin;
+	uint16_t flags;
+};
+
+struct pckbc_acpi_crs_data {
+	struct aml_node *basenode;
+	struct pckbc_acpi_gpio_intr intrs[2];
+	unsigned int nints;
+};
+
+int	pckbc_acpi_match_kbd(struct device *, void *, void *);
+int	pckbc_acpi_match_mou(struct device *, void *, void *,
+	    struct pckbc_acpi_softc *);
+void	pckbc_acpi_attach_kbd(struct device *, struct device *, void *);
+void	pckbc_acpi_attach_mou(struct device *, struct device *, void *);
+struct pckbc_acpi_softc *pckbc_acpi_find(int);
+int	pckbc_acpi_getgpioirqcount(int, union acpi_resource *, void *);
+int	pckbc_acpi_getgpioirqdata(int, union acpi_resource *, void *);
+int	pckbc_acpi_get_nirq(struct device *, struct acpi_attach_args *);
+void	pckbc_acpi_get_gpioirqdata(struct device *, struct aml_node *,
+	    struct pckbc_acpi_crs_data *);
+int	pckbc_acpi_gpio_intr_wrapper(void *);
+
+int
+pckbc_acpi_match(struct device *parent, void *match, void *aux)
+{
+	struct pckbc_acpi_softc *sc = pckbc_acpi_find(1);
+	if (sc == NULL)	/* no pckbc@acpi attachment yet */
+		return pckbc_acpi_match_kbd(parent, match, aux);
+	else
+		return pckbc_acpi_match_mou(parent, match, aux, sc);
+}
+
+void
+pckbc_acpi_attach(struct device *parent, struct device *self, void *aux)
+{
+	struct pckbc_acpi_softc *sc = pckbc_acpi_find(2);
+	if (sc == NULL)	/* no second pckbc@acpi attachment yet */
+		return pckbc_acpi_attach_kbd(parent, self, aux);
+	else
+		return pckbc_acpi_attach_mou(parent, self, aux);
+}
+
+const char *pckbc_acpi_cids_kbd[] = {
+	/* Devices which are known to require this pckbc@acpi attachment. */
+	"GOOG000A",	/* Chromebook built-in keyboard */
+	"LEN0071",	/* Built-in keyboard found on various Lenovo systems */
+	"MSFT0001",	/* Built-in keyboard found on various systems */
+	NULL,
+
+	/* Generic keyboard match, which can be enabled using cf_flags. */
+	"PNP0303",	/* IBM Enhanced Keyboard (101/102-key, PS/2 Mouse) */
+	NULL
+};
+
+/*
+ * Matching logic for the keyboard node. We want two I/O ports, at least
+ * one interrupt, and either a HID match or a CID match (if allowed).
+ */
+int
+pckbc_acpi_match_kbd(struct device *parent, void *match, void *aux)
+{
+	struct acpi_attach_args *aaa = aux;
+	struct cfdata *cf = match;
+	int rv;
+
+	if (aaa->aaa_naddr < 2)
+		return 0;
+	rv = acpi_matchhids(aaa, pckbc_acpi_cids_kbd, cf->cf_driver->cd_name);
+	if (rv == 0 && (cf->cf_flags & 0x0001) != 0)
+		rv = acpi_matchhids(aaa,
+		    pckbc_acpi_cids_kbd + nitems(pckbc_acpi_cids_kbd) - 2,
+		    cf->cf_driver->cd_name);
+	if (rv == 0)
+		return 0;
+	/* perform the expensive checks last */
+	if (pckbc_acpi_get_nirq(parent, aaa) < 1)
+		return 0;
+	return rv;
+}
+
+const char *pckbc_acpi_cids_mou[] = {
+	"PNP0F03",	/* Microsoft PS/2-style Mouse */
+	"PNP0F13",	/* PS/2 Mouse */
+	NULL
+};
+
+/*
+ * Matching logic for the mouse node. We want a previous keyboard to have
+ * attached, and want an interrupt if the keyboard node didn't have two.
+ */
+int
+pckbc_acpi_match_mou(struct device *parent, void *match, void *aux,
+    struct pckbc_acpi_softc *pasc)
+{
+	struct acpi_attach_args *aaa = aux;
+	struct cfdata *cf = match;
+	int rv;
+
+	/*
+	 * We only need to attach the mouse node if the keyboard attachment
+	 * succeeded, we need interrupt information for the aux slot, and
+	 * this acpi node provides it.
+	 */
+	if (pasc->sc_nints == 0 || pasc->sc_nints == nitems(pasc->sc_ih))
+		return 0;
+	rv = acpi_matchhids(aaa, pckbc_acpi_cids_mou, cf->cf_driver->cd_name);
+	if (rv == 0)
+		return 0;
+	/* perform the expensive checks last */
+	if (pckbc_acpi_get_nirq(parent, aaa) < 1)
+		return 0;
+	return rv;
+}
+
+int
+pckbc_acpi_activate(struct device *self, int act)
+{
+	struct pckbc_acpi_softc *pasc = (struct pckbc_acpi_softc *)self;
+	struct pckbc_softc *sc = &pasc->sc;
+	int rv = 0;
+
+	switch (act) {
+	case DVACT_SUSPEND:
+		rv = config_activate_children(self, act);
+		pckbc_stop(sc);
+		break;
+	case DVACT_RESUME:
+		pckbc_reset(sc);
+		rv = config_activate_children(self, act);
+		break;
+	default:
+		rv = config_activate_children(self, act);
+		break;
+	}
+	return rv;
+}
+
+void
+pckbc_acpi_attach_kbd(struct device *parent, struct device *self, void *aux)
+{
+	struct pckbc_acpi_softc *pasc = (struct pckbc_acpi_softc *)self;
+	struct pckbc_softc *sc = &pasc->sc;
+	struct acpi_attach_args *aaa = aux;
+	struct pckbc_internal *t;
+	struct pckbc_acpi_crs_data crsdata;
+	bus_space_handle_t ioh_d, ioh_c;
+	int irq, rv;
+
+	if (aaa->aaa_nirq == 0)
+		pckbc_acpi_get_gpioirqdata(parent, aaa->aaa_node, &crsdata);
+
+	printf(" addr 0x%llx/0x%llx 0x%llx/0x%llx", aaa->aaa_addr[0],
+	    aaa->aaa_size[0], aaa->aaa_addr[1], aaa->aaa_size[1]);
+	if (aaa->aaa_nirq == 0) {
+		printf(" gpio irq pin");
+		for (irq = 0; irq < crsdata.nints && irq < nitems(pasc->sc_ih);
+		    irq++)
+			printf(" %d", crsdata.intrs[irq].pin);
+	} else {
+		printf(" irq");
+		for (irq = 0; irq < aaa->aaa_nirq && irq < nitems(pasc->sc_ih);
+		    irq++)
+			printf(" %d", aaa->aaa_irq[irq]);
+	}
+	printf(": \"%s\"", aaa->aaa_dev);
+
+	if (aaa->aaa_nirq == 0) {
+		for (irq = 0; irq < crsdata.nints; irq++) {
+			struct acpi_gpio *gpio = crsdata.intrs[irq].node->gpio;
+			gpio->intr_establish(gpio->cookie,
+			    crsdata.intrs[irq].pin, crsdata.intrs[irq].flags,
+			    pckbc_acpi_gpio_intr_wrapper, pasc);
+			pasc->sc_nints++;
+			if (pasc->sc_nints == nitems(pasc->sc_ih))
+				break;
+		}
+	} else {
+		for (irq = 0; irq < aaa->aaa_nirq; irq++) {
+			pasc->sc_ih[pasc->sc_nints] = acpi_intr_establish(
+			    aaa->aaa_irq[irq], aaa->aaa_irq_flags[irq], IPL_TTY,
+			    pckbcintr, pasc, self->dv_xname);
+			if (pasc->sc_ih[pasc->sc_nints] == NULL) {
+				printf(": can't establish interrupt %d\n",
+				    aaa->aaa_irq[irq]);
+				goto fail_intr;
+			}
+			pasc->sc_nints++;
+			if (pasc->sc_nints == nitems(pasc->sc_ih))
+				break;
+		}
+	}
+
+	if (pckbc_is_console(aaa->aaa_bst[0], aaa->aaa_addr[0])) {
+		t = &pckbc_consdata;
+		pckbc_console_attached = 1;
+		/* t->t_cmdbyte was initialized by cnattach */
+	} else {
+		if ((rv = bus_space_map(aaa->aaa_bst[0], aaa->aaa_addr[0], 1, 0,
+		    &ioh_d)) != 0) {
+			printf(": couldn't map data port (%d)\n", rv);
+			goto fail_mapd;
+		}
+		if ((rv = bus_space_map(aaa->aaa_bst[1], aaa->aaa_addr[1], 1, 0,
+		    &ioh_c)) != 0) {
+			printf(": couldn't map command port (%d)\n", rv);
+			goto fail_mapc;
+		}
+
+		t = malloc(sizeof(*t), M_DEVBUF, M_WAITOK | M_ZERO);
+		/*
+		 * pckbc should theoretically be updated to use separate
+		 * bus_space_tag_t for the data and command ports, since on
+		 * this particular attachment they appear as separate I/O
+		 * resources. But since these are I/O resources, all
+		 * aaa_bst[] are identical, so we can avoid this change
+		 * for the time being as long as the logic in
+		 * acpi_parse_resources() does not change.
+		 */
+		t->t_iot = aaa->aaa_bst[0];
+		t->t_ioh_d = ioh_d;
+		t->t_ioh_c = ioh_c;
+		t->t_cmdbyte = KC8_CPU; /* Enable ports */
+	}
+
+	t->t_sc = sc;
+	sc->id = t;
+
+	printf("\n");
+
+	/*
+	 * Make sure pckbc@isa will not try to attach.
+	 */
+	{
+		extern int pckbc_acpi;
+		pckbc_acpi = 1;
+	}
+
+	pckbc_attach(sc, 0);
+	return;
+
+ fail_mapc:
+	bus_space_unmap(aaa->aaa_bst[0], ioh_d, 1);
+ fail_mapd:
+ fail_intr:
+	if (aaa->aaa_nirq == 0) {
+		/* XXX there is no way to disestablish GPIO interrupts */
+	} else {
+		for (irq = pasc->sc_nints - 1; irq >= 0; irq--)
+			acpi_intr_disestablish(pasc->sc_ih[irq]);
+	}
+	pasc->sc_nints = 0;
+}
+
+void
+pckbc_acpi_attach_mou(struct device *parent, struct device *self, void *aux)
+{
+	struct pckbc_acpi_softc *pasc = pckbc_acpi_find(1);
+	struct acpi_attach_args *aaa = aux;
+	struct pckbc_acpi_crs_data crsdata;
+	int irq, base;
+
+	if (aaa->aaa_nirq == 0)
+		pckbc_acpi_get_gpioirqdata(parent, aaa->aaa_node, &crsdata);
+
+	if (aaa->aaa_nirq == 0) {
+		printf(" gpio irq pin");
+		for (irq = 0; irq < crsdata.nints &&
+		    irq < nitems(pasc->sc_ih) - pasc->sc_nints; irq++)
+			printf(" %d", crsdata.intrs[irq].pin);
+	} else {
+		printf(" irq");
+		for (irq = 0; irq < aaa->aaa_nirq &&
+		    irq < nitems(pasc->sc_ih) - pasc->sc_nints; irq++)
+			printf(" %d", aaa->aaa_irq[irq]);
+	}
+	printf(": \"%s\"", aaa->aaa_dev);
+
+	base = pasc->sc_nints;
+	if (aaa->aaa_nirq == 0) {
+		for (irq = 0; irq < crsdata.nints; irq++) {
+			struct acpi_gpio *gpio = crsdata.intrs[irq].node->gpio;
+			gpio->intr_establish(gpio->cookie,
+			    crsdata.intrs[irq].pin, crsdata.intrs[irq].flags,
+			    pckbc_acpi_gpio_intr_wrapper, pasc);
+			pasc->sc_nints++;
+			if (pasc->sc_nints == nitems(pasc->sc_ih))
+				break;
+		}
+	} else {
+		for (irq = 0; irq < aaa->aaa_nirq; irq++) {
+			pasc->sc_ih[pasc->sc_nints] = acpi_intr_establish(
+			    aaa->aaa_irq[irq], aaa->aaa_irq_flags[irq], IPL_TTY,
+			    pckbcintr, pasc, self->dv_xname);
+			if (pasc->sc_ih[pasc->sc_nints] == NULL) {
+				printf(": can't establish interrupt %d\n",
+				    aaa->aaa_irq[irq]);
+				goto fail_intr;
+			}
+			pasc->sc_nints++;
+			if (pasc->sc_nints == nitems(pasc->sc_ih))
+				break;
+		}
+	}
+
+	printf("\n");
+	return;
+
+ fail_intr:
+	if (aaa->aaa_nirq == 0) {
+		/* XXX there is no way to disestablish GPIO interrupts */
+	} else {
+		for (irq = pasc->sc_nints - 1; irq >= base; irq--)
+			acpi_intr_disestablish(pasc->sc_ih[irq]);
+	}
+	pasc->sc_nints = base;
+}
+
+struct pckbc_acpi_softc *
+pckbc_acpi_find(int nth)
+{
+	/*
+	 * Iterate over all pckbc attachments. The `nth' argument tells
+	 * us which pckbc@acpi device to return.
+	 *
+	 * Note that, at `match' time, the device we may end up attaching
+	 * is not found, but at `attach' time, it will be found.
+	 */
+	extern struct cfdriver pckbc_cd;
+	struct device *sc;
+	int devno;
+
+	for (devno = 0; devno < pckbc_cd.cd_ndevs; devno++) {
+		if ((sc = pckbc_cd.cd_devs[devno]) == NULL)
+			continue;
+		if (sc->dv_cfdata->cf_attach != &pckbc_acpi_ca)
+			continue;
+		if (--nth == 0)
+			return (struct pckbc_acpi_softc *)sc;
+	}
+
+	return NULL;
+}
+
+/*
+ * _CRS resource walker, which only counts GPIO interrupts.
+ */
+int
+pckbc_acpi_get_nirq(struct device *acpidev, struct acpi_attach_args *aaa)
+{
+	struct aml_value val;
+	struct pckbc_acpi_crs_data crsdata;
+
+	/*
+	 * We can probably safely assume there won't be a mix of regular
+	 * and GPIO interrupts.
+	 */
+	if (aaa->aaa_nirq != 0)
+		return aaa->aaa_nirq;
+
+	memset(&crsdata, 0, sizeof crsdata);
+	crsdata.basenode = aaa->aaa_node;
+	if (aml_evalname((struct acpi_softc *)acpidev, aaa->aaa_node, "_CRS",
+	    0, NULL, &val) != 0)
+		return 0;
+	if (val.type == AML_OBJTYPE_BUFFER && val.length >= 5)
+		aml_parse_resource(&val, pckbc_acpi_getgpioirqcount, &crsdata);
+	aml_freevalue(&val);
+	return crsdata.nints;
+}
+
+/*
+ * Callback for the above routine.
+ */
+int
+pckbc_acpi_getgpioirqcount(int crsidx, union acpi_resource *crs, void *arg)
+{
+	struct pckbc_acpi_crs_data *crsdata = arg;
+	struct aml_node *node;
+
+	if (crsdata->nints == nitems(crsdata->intrs))
+		return 0;
+
+	switch (AML_CRSTYPE(crs)) {
+	case LR_GPIO:
+		if (crs->lr_gpio.type != LR_GPIO_INT)
+			break;
+		node = aml_searchname(crsdata->basenode,
+		    (char *)&crs->pad[crs->lr_gpio.res_off]);
+		/*
+		 * No need to count interrupts if no gpio driver has
+		 * attached, as we won't be able to do anything with
+		 * them.
+		 * That's a bit paranoid but that's also in order to
+		 * make sure we won't try to supersede pckbc@isa
+		 * (legacy) unless we really have a chance to work
+		 * better than it.
+		 */
+		if (node != NULL && node->gpio != NULL)
+			crsdata->nints++;
+		break;
+	}
+	return 0;
+}
+
+/*
+ * _CRS resource walker, which only registers GPIO interrupt details.
+ */
+void
+pckbc_acpi_get_gpioirqdata(struct device *acpidev, struct aml_node *basenode,
+    struct pckbc_acpi_crs_data *crsdata)
+{
+	struct aml_value val;
+
+	memset(crsdata, 0, sizeof *crsdata);
+	crsdata->basenode = basenode;
+	if (aml_evalname((struct acpi_softc *)acpidev, basenode, "_CRS",
+	    0, NULL, &val) != 0)
+		return;
+	if (val.type == AML_OBJTYPE_BUFFER && val.length >= 5)
+		aml_parse_resource(&val, pckbc_acpi_getgpioirqdata, crsdata);
+	aml_freevalue(&val);
+}
+
+/*
+ * Callback for the above routine.
+ */
+int
+pckbc_acpi_getgpioirqdata(int crsidx, union acpi_resource *crs, void *arg)
+{
+	struct pckbc_acpi_crs_data *crsdata = arg;
+	struct aml_node *node;
+
+	if (crsdata->nints == nitems(crsdata->intrs))
+		return 0;
+
+	switch (AML_CRSTYPE(crs)) {
+	case LR_GPIO:
+		if (crs->lr_gpio.type != LR_GPIO_INT)
+			break;
+		node = aml_searchname(crsdata->basenode,
+		    (char *)&crs->pad[crs->lr_gpio.res_off]);
+		if (node != NULL && node->gpio != NULL) {
+			crsdata->intrs[crsdata->nints].node = node;
+			crsdata->intrs[crsdata->nints].pin =
+			    *(uint16_t *)&crs->pad[crs->lr_gpio.pin_off];
+			crsdata->intrs[crsdata->nints].flags =
+			    crs->lr_gpio.tflags;
+			crsdata->nints++;
+		}
+		break;
+	}
+	return 0;
+}
+
+/*
+ * Wrapper for GPIO interrupts, to enforce IPL_TTY.
+ */
+int
+pckbc_acpi_gpio_intr_wrapper(void *arg)
+{
+	int s, rv;
+
+	s = spltty();
+	rv = pckbcintr(arg);
+	splx(s);
+	return rv;
+}
Index: sys/dev/ic/pckbc.c
===================================================================
RCS file: /OpenBSD/src/sys/dev/ic/pckbc.c,v
diff -u -p -u -p -r1.55 pckbc.c
--- sys/dev/ic/pckbc.c	26 Aug 2023 15:01:00 -0000	1.55
+++ sys/dev/ic/pckbc.c	30 Jan 2025 20:26:07 -0000
@@ -89,6 +89,10 @@ int pckbc_console_attached;
 int pckbc_console;
 static struct pckbc_slotdata pckbc_cons_slotdata;
 
+#ifdef __HAVE_ACPI
+int pckbc_acpi;
+#endif
+
 static int pckbc_wait_output(bus_space_tag_t, bus_space_handle_t);
 
 static int pckbc_get8042cmd(struct pckbc_internal *);
Index: sys/dev/isa/pckbc_isa.c
===================================================================
RCS file: /OpenBSD/src/sys/dev/isa/pckbc_isa.c,v
diff -u -p -u -p -r1.19 pckbc_isa.c
--- sys/dev/isa/pckbc_isa.c	18 Aug 2015 06:54:00 -0000	1.19
+++ sys/dev/isa/pckbc_isa.c	30 Jan 2025 20:26:07 -0000
@@ -56,6 +56,15 @@ pckbc_isa_match(struct device *parent, v
 	bus_space_handle_t ioh_d, ioh_c;
 	int res;
 
+#ifdef __HAVE_ACPI
+	/* Don't try anything if pckbc@acpi has claimed the keyboard. */
+	{
+		extern int pckbc_acpi;
+		if (pckbc_acpi)
+			return 0;
+	}
+#endif
+
 	/* If values are hardwired to something that they can't be, punt. */
 	if ((ia->ia_iobase != IOBASEUNK && ia->ia_iobase != IO_KBD) ||
 	    ia->ia_maddr != MADDRUNK ||