From: Miod Vallat Subject: Re: return of the chromebook keyboard diff To: tech@openbsd.org Date: Thu, 30 Jan 2025 20:35:43 +0000 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 +#include +#include +#include + +#include + +#include +#include +#include +#include + +#include +#include + +/* + * 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 ||