git: adc2c156acb5 - main - gpioaei: Add support for ACPI _EVT method

From: Vladimir Kondratyev <wulf_at_FreeBSD.org>
Date: Fri, 07 Mar 2025 16:01:03 UTC
The branch main has been updated by wulf:

URL: https://cgit.FreeBSD.org/src/commit/?id=adc2c156acb50bac6e8ec66b72cadc8910ce4975

commit adc2c156acb50bac6e8ec66b72cadc8910ce4975
Author:     Vladimir Kondratyev <wulf@FreeBSD.org>
AuthorDate: 2025-03-07 15:59:12 +0000
Commit:     Vladimir Kondratyev <wulf@FreeBSD.org>
CommitDate: 2025-03-07 15:59:12 +0000

    gpioaei: Add support for ACPI _EVT method
    
    This method is often used to process GPIO "Power on" button press on
    modern x86 laptops with S0ix sleep mode.
    
    Tested with patch from https://reviews.freebsd.org/D26407
    
    Sponsored by:   Future Crew LLC
    MFC after:      2 month
---
 sys/dev/gpio/gpioaei.c | 40 +++++++++++++++++++++++++++++++---------
 1 file changed, 31 insertions(+), 9 deletions(-)

diff --git a/sys/dev/gpio/gpioaei.c b/sys/dev/gpio/gpioaei.c
index 050f259a2127..f43674b53c7d 100644
--- a/sys/dev/gpio/gpioaei.c
+++ b/sys/dev/gpio/gpioaei.c
@@ -39,9 +39,16 @@
 #include <dev/gpio/gpiobusvar.h>
 #include <dev/gpio/acpi_gpiobusvar.h>
 
+enum gpio_aei_type {
+	ACPI_AEI_TYPE_UNKNOWN,
+	ACPI_AEI_TYPE_ELX,
+	ACPI_AEI_TYPE_EVT
+};
+
 struct gpio_aei_softc {
 	ACPI_HANDLE handle;
-	char objname[5];	/* "_EXX" or "_LXX" */
+	enum gpio_aei_type type;
+	int pin;
 	struct resource * intr_res;
 	int intr_rid;
 	void * intr_cookie;
@@ -60,8 +67,11 @@ gpio_aei_intr(void * arg)
 {
 	struct gpio_aei_softc * sc = arg;
 
-	/* Ask ACPI to run the appropriate _Exx or _Lxx method. */
-	AcpiEvaluateObject(sc->handle, sc->objname, NULL, NULL);
+	/* Ask ACPI to run the appropriate _EVT, _Exx or _Lxx method. */
+	if (sc->type == ACPI_AEI_TYPE_EVT)
+		acpi_SetInteger(sc->handle, NULL, sc->pin);
+	else
+		AcpiEvaluateObject(sc->handle, NULL, NULL, NULL);
 }
 
 static int
@@ -69,23 +79,35 @@ gpio_aei_attach(device_t dev)
 {
 	struct gpio_aei_softc * sc = device_get_softc(dev);
 	gpio_pin_t pin;
+	ACPI_HANDLE handle;
 	int err;
 
 	/* This is us. */
 	device_set_desc(dev, "ACPI Event Information Device");
 
 	/* Store parameters needed by gpio_aei_intr. */
-	sc->handle = acpi_gpiobus_get_handle(dev);
+	handle = acpi_gpiobus_get_handle(dev);
 	if (gpio_pin_get_by_acpi_index(dev, 0, &pin) != 0) {
 		device_printf(dev, "Unable to get the input pin\n");
 		return (ENXIO);
 	}
-	sprintf(sc->objname, "_%c%02X",
-	    (pin->flags & GPIO_INTR_EDGE_MASK) ? 'E' : 'L', pin->pin);
 
-	/* Support for GPIO pins > 255 is not implemented. */
-	if (pin->pin > 255) {
-		device_printf(dev, "ACPI Event Information Device does not support pins > 255");
+	sc->type = ACPI_AEI_TYPE_UNKNOWN;
+	sc->pin = pin->pin;
+	if (pin->pin <= 255) {
+		char objname[5];	/* "_EXX" or "_LXX" */
+		sprintf(objname, "_%c%02X",
+		    (pin->flags & GPIO_INTR_EDGE_MASK) ? 'E' : 'L', pin->pin);
+		if (ACPI_SUCCESS(AcpiGetHandle(handle, objname, &sc->handle)))
+			sc->type = ACPI_AEI_TYPE_ELX;
+	}
+	if (sc->type == ACPI_AEI_TYPE_UNKNOWN) {
+		if (ACPI_SUCCESS(AcpiGetHandle(handle, "_EVT", &sc->handle)))
+			sc->type = ACPI_AEI_TYPE_EVT;
+	}
+
+	if (sc->type == ACPI_AEI_TYPE_UNKNOWN) {
+		device_printf(dev, "ACPI Event Information Device type is unknown");
 		return (ENOTSUP);
 	}