Page MenuHomeFreeBSD

D58867.diff
No OneTemporary

D58867.diff

diff --git a/share/man/man4/Makefile b/share/man/man4/Makefile
--- a/share/man/man4/Makefile
+++ b/share/man/man4/Makefile
@@ -14,6 +14,7 @@
MAN= aac.4 \
aacraid.4 \
acpi.4 \
+ ${_acpi_apple.4} \
${_acpi_asus.4} \
${_acpi_asus_wmi.4} \
${_acpi_dock.4} \
@@ -853,6 +854,10 @@
MLINKS+=${_wpi.4} ${_if_wpi.4}
MLINKS+=xl.4 if_xl.4
+.if ${MACHINE_CPUARCH} == "amd64"
+_acpi_apple.4= acpi_apple.4
+.endif
+
.if ${MACHINE_CPUARCH} == "amd64" || ${MACHINE_CPUARCH} == "i386"
_acpi_asus.4= acpi_asus.4
_acpi_asus_wmi.4= acpi_asus_wmi.4
diff --git a/share/man/man4/acpi_apple.4 b/share/man/man4/acpi_apple.4
new file mode 100644
--- /dev/null
+++ b/share/man/man4/acpi_apple.4
@@ -0,0 +1,91 @@
+.\" Copyright (c) 2026 Abdelkader Boudih <freebsd@seuros.com>
+.\"
+.\" SPDX-License-Identifier: BSD-2-Clause
+.\"
+.Dd August 16, 2026
+.Dt ACPI_APPLE 4
+.Os
+.Sh NAME
+.Nm acpi_apple
+.Nd Apple platform ACPI driver
+.Sh SYNOPSIS
+To compile this driver into the kernel,
+place the following lines in your
+kernel configuration file:
+.Bd -ragged -offset indent
+.Cd "device acpi_apple"
+.Cd "device backlight"
+.Ed
+.Pp
+Alternatively, to load the driver as a
+module at boot time, place the following line in
+.Xr loader.conf 5 Ns :
+.Bd -literal -offset indent
+acpi_apple_load="YES"
+.Ed
+.Sh DESCRIPTION
+The
+.Nm
+driver attaches to Apple platform ACPI devices found on Intel-based
+Mac computers and provides two independent functions through a single
+driver, selected by the ACPI hardware ID it matches:
+.Bl -tag -width indent
+.It APP9876 , APP000B
+Platform instance.
+Attaches to the PCH PMC companion
+.Pq T2 Macs, 2018 and later
+or the GMUX GPU multiplexer companion
+.Pq Intel Macs with discrete graphics, 2006-2020 .
+Arms Wake-on-LAN on shutdown for any interface with wake enabled
+.Pq e.g. Va dev.bge.N.wake=1 ,
+exposes the lid switch state, and restores the backlight when the
+lid is reopened.
+.It APP0002
+Backlight instance.
+Controls the panel backlight found on all Intel Macs with an internal
+display, and registers with the
+.Xr backlight 9
+framework.
+The correct control method is selected automatically.
+.El
+.Pp
+.Dv APP0001
+.Pq SMC companion
+is intentionally not claimed by this driver; it is owned by
+.Xr asmc 4 .
+.Sh SYSCTL VARIABLES
+The following variable is available under the platform instance's
+device sysctl node
+.Pq Va dev.acpi_apple.N :
+.Bl -tag -width indent
+.It Va dev.acpi_apple.N.lid
+.Pq read-only
+Current lid switch state: 1 if open, 0 if closed.
+.El
+.Sh HARDWARE
+The
+.Nm
+driver supports the Apple ACPI devices found in the DSDT of Intel-based
+Mac computers:
+.Pp
+.Bl -tag -width "APP9876" -compact
+.It APP9876
+PCH PMC companion, present on T2 Macs
+.Pq 2018 and later .
+.It APP000B
+GMUX GPU multiplexer, present on Intel Macs with discrete graphics
+.Pq 2006-2020 , including single-GPU Mac minis.
+.It APP0002
+Panel backlight, present on all Intel Macs with a built-in display.
+.El
+.Sh SEE ALSO
+.Xr acpi 4 ,
+.Xr asmc 4 ,
+.Xr backlight 9
+.Sh HISTORY
+The
+.Nm
+driver first appeared in
+.Fx 16.0 .
+.Sh AUTHORS
+.An Abdelkader Boudih Aq Mt freebsd@seuros.com
diff --git a/sys/conf/files b/sys/conf/files
--- a/sys/conf/files
+++ b/sys/conf/files
@@ -848,6 +848,9 @@
dev/alpm/alpm.c optional alpm pci
dev/amdpm/amdpm.c optional amdpm pci | nfpm pci
dev/amdsmb/amdsmb.c optional amdsmb pci
+dev/apple_acpi/apple_acpi.c optional acpi_apple acpi pci backlight
+dev/apple_acpi/apple_backlight.c optional acpi_apple acpi pci backlight
+dev/apple_acpi/wake_on_lan.c optional acpi_apple acpi pci backlight
#
dev/aq/aq_main.c optional aq
dev/aq/aq_media.c optional aq
diff --git a/sys/dev/apple_acpi/apple_acpi.h b/sys/dev/apple_acpi/apple_acpi.h
new file mode 100644
--- /dev/null
+++ b/sys/dev/apple_acpi/apple_acpi.h
@@ -0,0 +1,130 @@
+/*
+ * Copyright (c) 2026 Abdelkader Boudih <freebsd@seuros.com>
+ *
+ * SPDX-License-Identifier: BSD-2-Clause
+ */
+
+#ifndef _APPLE_ACPI_H_
+#define _APPLE_ACPI_H_
+
+#include <sys/param.h>
+#include <sys/bus.h>
+#include <sys/eventhandler.h>
+#include <sys/kernel.h>
+#include <sys/lock.h>
+#include <sys/module.h>
+#include <sys/mutex.h>
+#include <sys/sysctl.h>
+
+#include <contrib/dev/acpica/include/acpi.h>
+
+#include <dev/acpica/acpivar.h>
+#include <dev/backlight/backlight.h>
+
+#define ACPI_APPLE_PLATFORM 0x01 /* WoL + lid (APP000B/APP9876) */
+#define ACPI_APPLE_BACKLIGHT 0x02 /* panel backlight (APP0002) */
+
+/*
+ * Apple GMUX (GPU multiplexer) registers.
+ * On dual-GPU MacBook Pros, the GMUX owns the backlight PWM.
+ * Port offsets are relative to the GMUX resource base, consumed from
+ * the APP000B device's _CRS.
+ *
+ * Three I/O protocols exist:
+ * Classic (PIO) - pre-retina Macs: direct inb/outb at base+port.
+ * Indexed - retina Macs (2012-2015): write port number to
+ * GMUX_PORT_READ/WRITE, data at GMUX_PORT_VALUE.
+ * MMIO - T2 Macs: memory-mapped, select port+direction via
+ * GMUX_MMIO_PORT_SELECT, trigger with
+ * GMUX_MMIO_COMMAND_SEND, data at the port offset
+ * itself as a big-endian 32-bit value.
+ */
+#define GMUX_PORT_VERSION_MAJOR 0x04
+#define GMUX_PORT_VERSION_MINOR 0x05
+#define GMUX_PORT_VERSION_RELEASE 0x06
+#define GMUX_PORT_MAX_BRIGHTNESS 0x70
+#define GMUX_PORT_BRIGHTNESS 0x74
+#define GMUX_BRIGHTNESS_MASK 0x00ffffff
+
+/* Indexed GMUX registers */
+#define GMUX_PORT_VALUE 0xc2
+#define GMUX_PORT_READ 0xd0
+#define GMUX_PORT_WRITE 0xd4
+
+/*
+ * Indexed-GMUX detection: write a fixed 3-byte unlock sequence to
+ * PORT_INDEXED_{MAGIC1,MAGIC2,MAGIC3}, then read the same two ports
+ * back and expect them to echo GMUX_INDEXED_SIGNATURE.
+ */
+#define GMUX_PORT_INDEXED_MAGIC1 0xcc
+#define GMUX_PORT_INDEXED_MAGIC2 0xcd
+#define GMUX_PORT_INDEXED_MAGIC3 0xce
+#define GMUX_INDEXED_UNLOCK1 0xaa
+#define GMUX_INDEXED_UNLOCK2 0x55
+#define GMUX_INDEXED_UNLOCK3 0x00
+#define GMUX_INDEXED_SIGNATURE 0x55aa
+
+/* MMIO GMUX registers */
+#define GMUX_MMIO_PORT_SELECT 0x0e
+#define GMUX_MMIO_COMMAND_SEND 0x0f
+#define GMUX_MMIO_READ 0x00
+#define GMUX_MMIO_WRITE 0x40
+
+/* Minimum resource length needed to reach GMUX_PORT_BRIGHTNESS+4. */
+#define GMUX_MIN_IO_LEN (GMUX_PORT_BRIGHTNESS + 4)
+
+#define GMUX_TYPE_PIO 0
+#define GMUX_TYPE_INDEXED 1
+#define GMUX_TYPE_MMIO 2
+
+struct apple_bl_reg {
+ uint32_t offset;
+ uint32_t mask;
+ uint8_t shift;
+};
+
+struct apple_bl_hw {
+ const char *name;
+ int bar;
+ vm_size_t mapsize;
+ struct apple_bl_reg ctrl;
+ struct apple_bl_reg enable;
+ uint32_t enable_val;
+ struct apple_bl_reg max_reg;
+ uint32_t max;
+};
+
+struct acpi_apple_softc {
+ device_t dev;
+ ACPI_HANDLE handle;
+ int mode;
+
+ /* Backlight */
+ struct mtx bl_mtx; /* protects hw access + cache */
+ struct cdev *bl_cdev;
+ const struct apple_bl_hw *bl_hw;
+ void *bl_mmio; /* GPU BAR MMIO (non-GMUX) */
+ uint16_t bl_gmux_base; /* GMUX I/O port base, 0=none */
+ void *bl_gmux_mmio; /* GMUX MMIO base, NULL=none */
+ uint8_t bl_gmux_type; /* GMUX_TYPE_{PIO,INDEXED,MMIO} */
+ uint32_t bl_max;
+ uint32_t bl_brightness; /* cached desired percent 0..100 */
+};
+
+/* wake_on_lan.c */
+int acpi_apple_platform_attach(struct acpi_apple_softc *sc);
+void acpi_apple_platform_detach(struct acpi_apple_softc *sc);
+
+/* apple_backlight.c */
+int acpi_apple_backlight_attach(struct acpi_apple_softc *sc);
+void acpi_apple_backlight_detach(struct acpi_apple_softc *sc);
+void acpi_apple_backlight_restore(void);
+void acpi_apple_backlight_off(void);
+int acpi_apple_bl_update_status(device_t dev,
+ struct backlight_props *props);
+int acpi_apple_bl_get_status(device_t dev,
+ struct backlight_props *props);
+int acpi_apple_bl_get_info(device_t dev,
+ struct backlight_info *info);
+
+#endif /* _APPLE_ACPI_H_ */
diff --git a/sys/dev/apple_acpi/apple_acpi.c b/sys/dev/apple_acpi/apple_acpi.c
new file mode 100644
--- /dev/null
+++ b/sys/dev/apple_acpi/apple_acpi.c
@@ -0,0 +1,119 @@
+/*
+ * Copyright (c) 2026 Abdelkader Boudih <freebsd@seuros.com>
+ *
+ * SPDX-License-Identifier: BSD-2-Clause
+ */
+
+/*
+ * acpi_apple(4) - FreeBSD driver for Apple platform ACPI devices.
+ *
+ * Handles multiple Apple ACPI devices with a single driver:
+ *
+ * APP000B (GMUX) / APP9876 (PCH PMC) - platform instance:
+ * - Wake-on-LAN: walk ACPI namespace on shutdown, call _PSW(1) on
+ * any device with ACPI_FLAG_WAKE_ENABLED (dev.X.Y.wake=1).
+ * - Lid state: expose dev.acpi_apple.N.lid sysctl via \_SB.LID0._LID.
+ *
+ * APP0002 (PNLF) - backlight instance:
+ * - Panel backlight control via GPU PCI BAR MMIO registers.
+ * - Supports Intel PCH/CPU, Nvidia NV40/NV50, AMD R600+ families.
+ * - Registers with backlight(9) framework.
+ *
+ * OSDW() gates on OSYS==0x2710 ("Darwin"), installed via
+ * hw.acpi.apple_darwin_osi=1. _PSW on GIGE only fires if the bge(4)
+ * instance has ACPI_FLAG_WAKE_ENABLED (dev.bge.X.wake=1).
+ */
+
+#include <sys/cdefs.h>
+#include "opt_acpi.h"
+#include "apple_acpi.h"
+
+#include "backlight_if.h"
+
+#define _COMPONENT ACPI_OEM
+ACPI_MODULE_NAME("Apple")
+
+/*
+ * Attach to APP9876 (PCH PMC, T2 Macs), APP000B (GMUX, discrete GPU
+ * Macs), or APP0002 (panel backlight, all Intel Macs with display).
+ * APP0001 (SMC) is owned by asmc(4).
+ *
+ * BUS_PROBE_LOW_PRIORITY so a future apple_gmux driver can claim
+ * APP000B at default priority.
+ */
+static char *acpi_apple_ids[] = { "APP9876", "APP000B", "APP0002", NULL };
+
+static int
+acpi_apple_probe(device_t dev)
+{
+ int rv;
+
+ if (acpi_disabled("apple"))
+ return (ENXIO);
+ rv = ACPI_ID_PROBE(device_get_parent(dev), dev, acpi_apple_ids, NULL);
+ if (rv > 0)
+ return (rv);
+
+ if (acpi_MatchHid(acpi_get_handle(dev), "APP0002"))
+ device_set_desc(dev, "Apple Panel Backlight");
+ else
+ device_set_desc(dev, "Apple platform controller");
+
+ return (BUS_PROBE_LOW_PRIORITY);
+}
+
+static int
+acpi_apple_attach(device_t dev)
+{
+ struct acpi_apple_softc *sc;
+
+ sc = device_get_softc(dev);
+ sc->dev = dev;
+ sc->handle = acpi_get_handle(dev);
+
+ if (acpi_MatchHid(sc->handle, "APP0002"))
+ sc->mode = ACPI_APPLE_BACKLIGHT;
+ else
+ sc->mode = ACPI_APPLE_PLATFORM;
+
+ if (sc->mode == ACPI_APPLE_PLATFORM)
+ return (acpi_apple_platform_attach(sc));
+ else
+ return (acpi_apple_backlight_attach(sc));
+}
+
+static int
+acpi_apple_detach(device_t dev)
+{
+ struct acpi_apple_softc *sc;
+
+ sc = device_get_softc(dev);
+ if (sc->mode == ACPI_APPLE_PLATFORM)
+ acpi_apple_platform_detach(sc);
+ else
+ acpi_apple_backlight_detach(sc);
+ return (0);
+}
+
+static device_method_t acpi_apple_methods[] = {
+ DEVMETHOD(device_probe, acpi_apple_probe),
+ DEVMETHOD(device_attach, acpi_apple_attach),
+ DEVMETHOD(device_detach, acpi_apple_detach),
+
+ DEVMETHOD(backlight_update_status, acpi_apple_bl_update_status),
+ DEVMETHOD(backlight_get_status, acpi_apple_bl_get_status),
+ DEVMETHOD(backlight_get_info, acpi_apple_bl_get_info),
+
+ DEVMETHOD_END
+};
+
+static driver_t acpi_apple_driver = {
+ "acpi_apple",
+ acpi_apple_methods,
+ sizeof(struct acpi_apple_softc),
+};
+
+DRIVER_MODULE(acpi_apple, acpi, acpi_apple_driver, 0, 0);
+MODULE_DEPEND(acpi_apple, acpi, 1, 1, 1);
+MODULE_DEPEND(acpi_apple, backlight, 1, 1, 1);
+MODULE_VERSION(acpi_apple, 1);
diff --git a/sys/dev/apple_acpi/apple_backlight.c b/sys/dev/apple_acpi/apple_backlight.c
new file mode 100644
--- /dev/null
+++ b/sys/dev/apple_acpi/apple_backlight.c
@@ -0,0 +1,783 @@
+/*
+ * Copyright (c) 2026 Abdelkader Boudih <freebsd@seuros.com>
+ *
+ * SPDX-License-Identifier: BSD-2-Clause
+ */
+
+/*
+ * Apple panel backlight control.
+ *
+ * Two backends: GMUX (dual-GPU MacBook Pros, base+0x70/0x74 over PIO,
+ * indexed I/O, or MMIO depending on platform) and direct GPU PCI BAR
+ * MMIO (single-GPU Macs). GMUX is preferred whenever APP000B is
+ * present and its _CRS yields a working protocol.
+ */
+
+#include <sys/cdefs.h>
+#include "apple_acpi.h"
+
+#include <sys/endian.h>
+#include <sys/systm.h>
+
+#include <dev/backlight/backlight.h>
+#include <dev/pci/pcireg.h>
+#include <dev/pci/pcivar.h>
+#include <machine/cpufunc.h>
+#include <vm/vm.h>
+#include <vm/pmap.h>
+
+#include "backlight_if.h"
+
+ACPI_SERIAL_DECL(apple, "Apple ACPI");
+static struct acpi_apple_softc *apple_backlight_sc;
+
+static const struct apple_bl_hw apple_bl_intel_pch = {
+ .name = "intel_pch",
+ .bar = 0,
+ .mapsize = 0xc8258,
+ .ctrl = { 0xc8254, 0x0000FFFF, 0 },
+ .enable = { 0xc8250, 0xC0000000, 0 },
+ .enable_val = 0xC0000000,
+ .max_reg = { 0xc8254, 0xFFFF0000, 16 },
+ .max = 0xFFFF,
+};
+
+static const struct apple_bl_hw apple_bl_intel_cpu = {
+ .name = "intel_cpu",
+ .bar = 0,
+ .mapsize = 0xc8258,
+ .ctrl = { 0x48254, 0x0000FFFF, 0 },
+ .enable = { 0x48250, 0xC0000000, 0 },
+ .enable_val = 0xC0000000,
+ .max_reg = { 0xc8254, 0xFFFF0000, 16 },
+ .max = 0xFFFF,
+};
+
+static const struct apple_bl_hw apple_bl_nvidia_nv40 = {
+ .name = "nvidia_nv40",
+ .bar = 0,
+ .mapsize = 0x15f4,
+ .ctrl = { 0x15f0, 0x001F0000, 16 },
+ .max = 31,
+};
+
+static const struct apple_bl_hw apple_bl_nvidia_nv50 = {
+ .name = "nvidia_nv50",
+ .bar = 0,
+ .mapsize = 0x61c088,
+ .ctrl = { 0x61c084, 0x000007FF, 0 },
+ .enable = { 0x61c084, 0x80000000, 0 },
+ .enable_val = 0x80000000,
+ .max = 0x7FF,
+};
+
+static const struct apple_bl_hw apple_bl_amd_r600 = {
+ .name = "amd_r600",
+ .bar = 2,
+ .mapsize = 0x1730,
+ .ctrl = { 0x172c, 0x0000FF00, 8 },
+ .max = 255,
+};
+
+/* DCE10 (Tonga/Fiji, e.g. R9 M395/M395X, R9 Nano). */
+static const struct apple_bl_hw apple_bl_amd_dce10 = {
+ .name = "amd_dce10",
+ .bar = 2,
+ .mapsize = 0x1208c,
+ .ctrl = { 0x12080, 0x0000FFFF, 0 },
+ .enable = { 0x12080, 0x80000000, 0 },
+ .enable_val = 0x80000000,
+ .max_reg = { 0x12088, 0x0000FFFF, 0 },
+ .max = 0xFFFF,
+};
+
+struct apple_bl_match {
+ uint16_t vendor;
+ uint16_t dev_lo;
+ uint16_t dev_hi;
+ const struct apple_bl_hw *hw;
+};
+
+static const struct apple_bl_match apple_bl_matches[] = {
+ { 0x8086, 0x0100, 0x013f, &apple_bl_intel_cpu },
+ { 0x8086, 0x0140, 0x017f, &apple_bl_intel_cpu },
+ { 0x8086, 0, 0, &apple_bl_intel_pch },
+ { 0x10de, 0x0040, 0x03ff, &apple_bl_nvidia_nv40 },
+ { 0x10de, 0, 0, &apple_bl_nvidia_nv50 },
+ { 0x1002, 0x6920, 0x6939, &apple_bl_amd_dce10 },
+ { 0x1002, 0, 0, &apple_bl_amd_r600 },
+ { 0, 0, 0, NULL },
+};
+
+/* Classic (PIO) GMUX - pre-retina Macs. */
+static uint32_t
+gmux_pio_read32(uint16_t base, uint8_t port)
+{
+ return (inl(base + port));
+}
+
+static void
+gmux_pio_write32(uint16_t base, uint8_t port, uint32_t val)
+{
+ int i;
+
+ for (i = 0; i < 4; i++)
+ outb(base + port + i, (val >> (i * 8)) & 0xff);
+}
+
+/* Indexed GMUX - retina Macs (2012-2015). */
+static int
+gmux_index_wait_ready(uint16_t base)
+{
+ int i;
+ uint8_t gwr;
+
+ for (i = 0; i < 100; i++) {
+ gwr = inb(base + GMUX_PORT_WRITE);
+ if ((gwr & 0x01) == 0)
+ return (0);
+ inb(base + GMUX_PORT_READ);
+ DELAY(100);
+ }
+ return (ETIMEDOUT);
+}
+
+static int
+gmux_index_wait_complete(uint16_t base)
+{
+ int i;
+ uint8_t gwr;
+
+ for (i = 0; i < 100; i++) {
+ gwr = inb(base + GMUX_PORT_WRITE);
+ if ((gwr & 0x01) != 0) {
+ /* Acknowledge completion. */
+ inb(base + GMUX_PORT_READ);
+ return (0);
+ }
+ DELAY(100);
+ }
+ /* Clear stale status. */
+ inb(base + GMUX_PORT_READ);
+ return (ETIMEDOUT);
+}
+
+static uint32_t
+gmux_index_read32(uint16_t base, uint8_t port)
+{
+ uint32_t val;
+
+ gmux_index_wait_ready(base);
+ outb(base + GMUX_PORT_READ, port);
+ gmux_index_wait_complete(base);
+ val = inl(base + GMUX_PORT_VALUE);
+ return (val);
+}
+
+static void
+gmux_index_write32(uint16_t base, uint8_t port, uint32_t val)
+{
+ int i;
+
+ for (i = 0; i < 4; i++)
+ outb(base + GMUX_PORT_VALUE + i, (val >> (i * 8)) & 0xff);
+ gmux_index_wait_ready(base);
+ outb(base + GMUX_PORT_WRITE, port);
+ gmux_index_wait_complete(base);
+}
+
+/* MMIO GMUX - T2 Macs. */
+static inline uint8_t
+gmux_mmio_read8(void *mmio, uint8_t port)
+{
+ return (*(volatile uint8_t *)((char *)mmio + port));
+}
+
+static inline void
+gmux_mmio_write8(void *mmio, uint8_t port, uint8_t val)
+{
+ *(volatile uint8_t *)((char *)mmio + port) = val;
+}
+
+static int
+gmux_mmio_wait(void *mmio)
+{
+ int i;
+
+ for (i = 0; i < 200; i++) {
+ if (gmux_mmio_read8(mmio, GMUX_MMIO_COMMAND_SEND) == 0)
+ return (0);
+ DELAY(100);
+ }
+ return (ETIMEDOUT);
+}
+
+static uint32_t
+gmux_mmio_read32(void *mmio, uint8_t port)
+{
+ uint32_t val;
+
+ gmux_mmio_wait(mmio);
+ gmux_mmio_write8(mmio, GMUX_MMIO_PORT_SELECT, port);
+ gmux_mmio_write8(mmio, GMUX_MMIO_COMMAND_SEND,
+ GMUX_MMIO_READ | sizeof(val));
+ gmux_mmio_wait(mmio);
+ val = be32toh(*(volatile uint32_t *)mmio);
+ return (val);
+}
+
+static void
+gmux_mmio_write32(void *mmio, uint8_t port, uint32_t val)
+{
+ gmux_mmio_wait(mmio);
+ *(volatile uint32_t *)mmio = htobe32(val);
+ gmux_mmio_write8(mmio, GMUX_MMIO_PORT_SELECT, port);
+ gmux_mmio_write8(mmio, GMUX_MMIO_COMMAND_SEND,
+ GMUX_MMIO_WRITE | sizeof(val));
+ gmux_mmio_wait(mmio);
+}
+
+static uint32_t
+gmux_read32(struct acpi_apple_softc *sc, uint8_t port)
+{
+ if (sc->bl_gmux_type == GMUX_TYPE_MMIO)
+ return (gmux_mmio_read32(sc->bl_gmux_mmio, port));
+ if (sc->bl_gmux_type == GMUX_TYPE_INDEXED)
+ return (gmux_index_read32(sc->bl_gmux_base, port));
+ return (gmux_pio_read32(sc->bl_gmux_base, port));
+}
+
+static void
+gmux_write32(struct acpi_apple_softc *sc, uint8_t port, uint32_t val)
+{
+ if (sc->bl_gmux_type == GMUX_TYPE_MMIO)
+ gmux_mmio_write32(sc->bl_gmux_mmio, port, val);
+ else if (sc->bl_gmux_type == GMUX_TYPE_INDEXED)
+ gmux_index_write32(sc->bl_gmux_base, port, val);
+ else
+ gmux_pio_write32(sc->bl_gmux_base, port, val);
+}
+
+static inline bool
+apple_bl_gmux_active(struct acpi_apple_softc *sc)
+{
+ return (sc->bl_gmux_base != 0 || sc->bl_gmux_mmio != NULL);
+}
+
+static void
+apple_bl_gmux_teardown(struct acpi_apple_softc *sc)
+{
+ if (sc->bl_gmux_mmio != NULL) {
+ pmap_unmapdev(sc->bl_gmux_mmio, GMUX_MIN_IO_LEN);
+ sc->bl_gmux_mmio = NULL;
+ }
+ sc->bl_gmux_base = 0;
+}
+
+static inline uint32_t
+apple_bl_read(struct acpi_apple_softc *sc, uint32_t offset)
+{
+ return (*(volatile uint32_t *)((char *)sc->bl_mmio + offset));
+}
+
+static inline void
+apple_bl_write(struct acpi_apple_softc *sc, uint32_t offset, uint32_t val)
+{
+ *(volatile uint32_t *)((char *)sc->bl_mmio + offset) = val;
+}
+
+static int
+apple_bl_hw_get(struct acpi_apple_softc *sc)
+{
+ if (apple_bl_gmux_active(sc))
+ return (gmux_read32(sc,
+ GMUX_PORT_BRIGHTNESS) & GMUX_BRIGHTNESS_MASK);
+
+ return ((apple_bl_read(sc, sc->bl_hw->ctrl.offset) &
+ sc->bl_hw->ctrl.mask) >> sc->bl_hw->ctrl.shift);
+}
+
+/* Resolve max brightness, enable the PWM if needed, cache brightness. */
+static void
+apple_bl_mmio_init(struct acpi_apple_softc *sc, const struct apple_bl_hw *hw)
+{
+ uint32_t val;
+
+ if (hw->max_reg.offset != 0) {
+ sc->bl_max = (apple_bl_read(sc, hw->max_reg.offset) &
+ hw->max_reg.mask) >> hw->max_reg.shift;
+ if (sc->bl_max == 0)
+ sc->bl_max = hw->max;
+ } else {
+ sc->bl_max = hw->max;
+ }
+
+ if (hw->enable.offset != 0) {
+ val = apple_bl_read(sc, hw->enable.offset);
+ if ((val & hw->enable_val) != hw->enable_val) {
+ val |= hw->enable_val;
+ apple_bl_write(sc, hw->enable.offset, val);
+ }
+ }
+
+ if (sc->bl_max > 0)
+ sc->bl_brightness = apple_bl_hw_get(sc) * 100 / sc->bl_max;
+}
+
+static void
+apple_bl_hw_set(struct acpi_apple_softc *sc, int level)
+{
+ uint32_t val;
+
+ if (apple_bl_gmux_active(sc)) {
+ gmux_write32(sc, GMUX_PORT_BRIGHTNESS,
+ level & GMUX_BRIGHTNESS_MASK);
+ return;
+ }
+
+ val = apple_bl_read(sc, sc->bl_hw->ctrl.offset);
+ val = (val & ~sc->bl_hw->ctrl.mask) |
+ ((level << sc->bl_hw->ctrl.shift) & sc->bl_hw->ctrl.mask);
+ apple_bl_write(sc, sc->bl_hw->ctrl.offset, val);
+}
+
+static const struct apple_bl_hw *
+apple_bl_find_gpu(device_t *gpu_devp)
+{
+ const struct apple_bl_match *m;
+ device_t gpu;
+ uint16_t vendor, device;
+
+ gpu = pci_find_class(PCIC_DISPLAY, PCIS_DISPLAY_VGA);
+ if (gpu == NULL)
+ return (NULL);
+
+ vendor = pci_get_vendor(gpu);
+ device = pci_get_device(gpu);
+
+ for (m = apple_bl_matches; m->vendor != 0; m++) {
+ if (vendor != m->vendor)
+ continue;
+ if (m->dev_lo != 0 &&
+ (device < m->dev_lo || device > m->dev_hi))
+ continue;
+ *gpu_devp = gpu;
+ return (m->hw);
+ }
+
+ return (NULL);
+}
+
+static void *
+apple_bl_map_bar(device_t dev, device_t gpu, const struct apple_bl_hw *hw)
+{
+ uint64_t bar_addr;
+ uint32_t bar_lo, bar_hi;
+
+ bar_lo = pci_read_config(gpu, PCIR_BAR(hw->bar), 4);
+
+ if (PCI_BAR_IO(bar_lo)) {
+ device_printf(dev, "BAR%d is I/O, expected memory\n", hw->bar);
+ return (NULL);
+ }
+
+ if ((bar_lo & PCIM_BAR_MEM_TYPE) == PCIM_BAR_MEM_64) {
+ bar_hi = pci_read_config(gpu, PCIR_BAR(hw->bar) + 4, 4);
+ bar_addr = ((uint64_t)bar_hi << 32) |
+ (bar_lo & PCIM_BAR_MEM_BASE);
+ } else {
+ bar_addr = bar_lo & PCIM_BAR_MEM_BASE;
+ }
+
+ if (bar_addr == 0) {
+ device_printf(dev, "BAR%d address is zero\n", hw->bar);
+ return (NULL);
+ }
+
+ return (pmap_mapdev(bar_addr, hw->mapsize));
+}
+
+/*
+ * Probe for GMUX. Locate APP000B in the ACPI namespace by HID, consume
+ * its _CRS resource, and detect which I/O protocol the hardware speaks.
+ */
+#define GMUX_ACPI_HID "APP000B"
+
+struct apple_bl_gmux_crs {
+ uint16_t io_base;
+ uint32_t io_len;
+ uint64_t mem_base;
+};
+
+static ACPI_STATUS
+apple_bl_gmux_found(ACPI_HANDLE handle, UINT32 level __unused, void *ctx,
+ void **retval __unused)
+{
+ *(ACPI_HANDLE *)ctx = handle;
+ return (AE_CTRL_TERMINATE);
+}
+
+static ACPI_STATUS
+apple_bl_gmux_crs_cb(ACPI_RESOURCE *res, void *ctx)
+{
+ struct apple_bl_gmux_crs *crs = ctx;
+
+ switch (res->Type) {
+ case ACPI_RESOURCE_TYPE_IO:
+ crs->io_base = res->Data.Io.Minimum;
+ crs->io_len = res->Data.Io.AddressLength;
+ break;
+ case ACPI_RESOURCE_TYPE_FIXED_IO:
+ crs->io_base = res->Data.FixedIo.Address;
+ crs->io_len = res->Data.FixedIo.AddressLength;
+ break;
+ case ACPI_RESOURCE_TYPE_MEMORY32:
+ crs->mem_base = res->Data.Memory32.Minimum;
+ break;
+ case ACPI_RESOURCE_TYPE_FIXED_MEMORY32:
+ crs->mem_base = res->Data.FixedMemory32.Address;
+ break;
+ default:
+ break;
+ }
+ return (AE_OK);
+}
+
+static bool
+apple_bl_is_indexed(uint16_t base)
+{
+ uint16_t val;
+
+ outb(base + GMUX_PORT_INDEXED_MAGIC1, GMUX_INDEXED_UNLOCK1);
+ outb(base + GMUX_PORT_INDEXED_MAGIC2, GMUX_INDEXED_UNLOCK2);
+ outb(base + GMUX_PORT_INDEXED_MAGIC3, GMUX_INDEXED_UNLOCK3);
+
+ val = inb(base + GMUX_PORT_INDEXED_MAGIC1) |
+ ((uint16_t)inb(base + GMUX_PORT_INDEXED_MAGIC2) << 8);
+ return (val == GMUX_INDEXED_SIGNATURE);
+}
+
+static bool
+apple_bl_is_mmio(void *mmio)
+{
+ return (gmux_mmio_read8(mmio, GMUX_MMIO_COMMAND_SEND) != 0xff);
+}
+
+static bool
+apple_bl_find_gmux(struct acpi_apple_softc *sc)
+{
+ ACPI_HANDLE gmux_handle;
+ struct apple_bl_gmux_crs crs;
+ uint16_t base;
+ uint8_t ver_major, ver_minor, ver_release;
+ uint32_t version;
+
+ gmux_handle = NULL;
+ AcpiGetDevices(GMUX_ACPI_HID, apple_bl_gmux_found, &gmux_handle, NULL);
+ if (gmux_handle == NULL)
+ return (false);
+
+ bzero(&crs, sizeof(crs));
+ if (ACPI_FAILURE(AcpiWalkResources(gmux_handle, "_CRS",
+ apple_bl_gmux_crs_cb, &crs)))
+ return (false);
+
+ if (crs.io_base != 0 && crs.io_len >= GMUX_MIN_IO_LEN) {
+ base = crs.io_base;
+
+ /* Try direct PIO first (classic/pre-retina GMUX). */
+ ver_major = inb(base + GMUX_PORT_VERSION_MAJOR);
+ ver_minor = inb(base + GMUX_PORT_VERSION_MINOR);
+ ver_release = inb(base + GMUX_PORT_VERSION_RELEASE);
+
+ if (ver_major != 0xff || ver_minor != 0xff) {
+ sc->bl_gmux_base = base;
+ sc->bl_gmux_type = GMUX_TYPE_PIO;
+ device_printf(sc->dev,
+ "GMUX v%d.%d.%d [classic] at 0x%x\n",
+ ver_major, ver_minor, ver_release, base);
+ return (true);
+ }
+
+ /* Direct PIO returned 0xff - check for indexed GMUX. */
+ if (apple_bl_is_indexed(base)) {
+ sc->bl_gmux_base = base;
+ sc->bl_gmux_type = GMUX_TYPE_INDEXED;
+
+ version = gmux_index_read32(base,
+ GMUX_PORT_VERSION_MAJOR);
+ ver_major = (version >> 24) & 0xff;
+ ver_minor = (version >> 16) & 0xff;
+ ver_release = (version >> 8) & 0xff;
+
+ device_printf(sc->dev,
+ "GMUX v%d.%d.%d [indexed] at 0x%x\n",
+ ver_major, ver_minor, ver_release, base);
+ return (true);
+ }
+ }
+
+ /* No usable I/O resource - try the MMIO protocol (T2 GMUX). */
+ if (crs.mem_base == 0)
+ return (false);
+
+ sc->bl_gmux_mmio = pmap_mapdev(crs.mem_base, GMUX_MIN_IO_LEN);
+ if (sc->bl_gmux_mmio == NULL)
+ return (false);
+
+ if (!apple_bl_is_mmio(sc->bl_gmux_mmio)) {
+ pmap_unmapdev(sc->bl_gmux_mmio, GMUX_MIN_IO_LEN);
+ sc->bl_gmux_mmio = NULL;
+ return (false);
+ }
+
+ sc->bl_gmux_type = GMUX_TYPE_MMIO;
+
+ version = gmux_mmio_read32(sc->bl_gmux_mmio, GMUX_PORT_VERSION_MAJOR);
+ ver_major = (version >> 24) & 0xff;
+ ver_minor = (version >> 16) & 0xff;
+ ver_release = (version >> 8) & 0xff;
+
+ device_printf(sc->dev, "GMUX v%d.%d.%d [mmio] at %#jx\n",
+ ver_major, ver_minor, ver_release, (uintmax_t)crs.mem_base);
+ return (true);
+}
+
+static int
+acpi_apple_backlight_attach_gmux(struct acpi_apple_softc *sc)
+{
+ uint32_t raw_max;
+
+ mtx_init(&sc->bl_mtx, "apple_bl", NULL, MTX_DEF);
+
+ raw_max = gmux_read32(sc, GMUX_PORT_MAX_BRIGHTNESS) &
+ GMUX_BRIGHTNESS_MASK;
+ sc->bl_max = (raw_max > 0) ? raw_max : GMUX_BRIGHTNESS_MASK;
+
+ if (sc->bl_max > 0)
+ sc->bl_brightness = apple_bl_hw_get(sc) * 100 / sc->bl_max;
+
+ sc->bl_cdev = backlight_register("apple_bl", sc->dev);
+ if (sc->bl_cdev == NULL) {
+ device_printf(sc->dev, "cannot register backlight\n");
+ apple_bl_gmux_teardown(sc);
+ mtx_destroy(&sc->bl_mtx);
+ return (ENXIO);
+ }
+
+ device_printf(sc->dev, "gmux brightness %d/%d\n",
+ apple_bl_hw_get(sc), sc->bl_max);
+
+ ACPI_SERIAL_BEGIN(apple);
+ apple_backlight_sc = sc;
+ ACPI_SERIAL_END(apple);
+ return (0);
+}
+
+static void
+acpi_apple_backlight_deferred(void *arg)
+{
+ struct acpi_apple_softc *sc = arg;
+ device_t gpu;
+ const struct apple_bl_hw *hw;
+
+ hw = apple_bl_find_gpu(&gpu);
+ if (hw == NULL) {
+ device_printf(sc->dev, "no supported GPU found\n");
+ return;
+ }
+ sc->bl_hw = hw;
+
+ sc->bl_mmio = apple_bl_map_bar(sc->dev, gpu, hw);
+ if (sc->bl_mmio == NULL)
+ return;
+
+ mtx_init(&sc->bl_mtx, "apple_bl", NULL, MTX_DEF);
+ apple_bl_mmio_init(sc, hw);
+
+ sc->bl_cdev = backlight_register("apple_bl", sc->dev);
+ if (sc->bl_cdev == NULL) {
+ device_printf(sc->dev, "cannot register backlight\n");
+ mtx_destroy(&sc->bl_mtx);
+ pmap_unmapdev(sc->bl_mmio, hw->mapsize);
+ sc->bl_mmio = NULL;
+ return;
+ }
+
+ device_printf(sc->dev, "%s, brightness %d/%d\n",
+ hw->name, apple_bl_hw_get(sc), sc->bl_max);
+
+ ACPI_SERIAL_BEGIN(apple);
+ apple_backlight_sc = sc;
+ ACPI_SERIAL_END(apple);
+}
+
+static int
+acpi_apple_backlight_attach_mmio(struct acpi_apple_softc *sc)
+{
+ device_t gpu;
+ const struct apple_bl_hw *hw;
+
+ hw = apple_bl_find_gpu(&gpu);
+ if (hw == NULL) {
+ /*
+ * GPU not yet attached (ACPI bus enumerates before PCI).
+ * Defer the lookup until after all buses finish probing.
+ */
+ config_intrhook_oneshot(acpi_apple_backlight_deferred, sc);
+ return (0);
+ }
+ sc->bl_hw = hw;
+
+ sc->bl_mmio = apple_bl_map_bar(sc->dev, gpu, hw);
+ if (sc->bl_mmio == NULL)
+ return (ENXIO);
+
+ mtx_init(&sc->bl_mtx, "apple_bl", NULL, MTX_DEF);
+ apple_bl_mmio_init(sc, hw);
+
+ sc->bl_cdev = backlight_register("apple_bl", sc->dev);
+ if (sc->bl_cdev == NULL) {
+ device_printf(sc->dev, "cannot register backlight\n");
+ mtx_destroy(&sc->bl_mtx);
+ pmap_unmapdev(sc->bl_mmio, hw->mapsize);
+ sc->bl_mmio = NULL;
+ return (ENXIO);
+ }
+
+ device_printf(sc->dev, "%s, brightness %d/%d\n",
+ hw->name, apple_bl_hw_get(sc), sc->bl_max);
+
+ ACPI_SERIAL_BEGIN(apple);
+ apple_backlight_sc = sc;
+ ACPI_SERIAL_END(apple);
+ return (0);
+}
+
+int
+acpi_apple_backlight_attach(struct acpi_apple_softc *sc)
+{
+ if (apple_bl_find_gmux(sc))
+ return (acpi_apple_backlight_attach_gmux(sc));
+
+ return (acpi_apple_backlight_attach_mmio(sc));
+}
+
+void
+acpi_apple_backlight_detach(struct acpi_apple_softc *sc)
+{
+ bool had_gmux;
+
+ ACPI_SERIAL_BEGIN(apple);
+ if (apple_backlight_sc == sc)
+ apple_backlight_sc = NULL;
+ ACPI_SERIAL_END(apple);
+
+ had_gmux = apple_bl_gmux_active(sc);
+
+ if (sc->bl_cdev != NULL)
+ backlight_destroy(sc->bl_cdev);
+ if (sc->bl_mmio != NULL)
+ pmap_unmapdev(sc->bl_mmio, sc->bl_hw->mapsize);
+ apple_bl_gmux_teardown(sc);
+ if (sc->bl_cdev != NULL || sc->bl_mmio != NULL || had_gmux)
+ mtx_destroy(&sc->bl_mtx);
+}
+
+static inline bool
+apple_bl_ready(struct acpi_apple_softc *sc)
+{
+ return (sc->bl_hw != NULL || apple_bl_gmux_active(sc));
+}
+
+static inline int
+apple_bl_pct_to_hw(struct acpi_apple_softc *sc, int pct)
+{
+ int level;
+
+ level = pct * sc->bl_max / 100;
+ if (level > (int)sc->bl_max)
+ level = sc->bl_max;
+ return (level);
+}
+
+int
+acpi_apple_bl_update_status(device_t dev, struct backlight_props *props)
+{
+ struct acpi_apple_softc *sc;
+
+ sc = device_get_softc(dev);
+ if (!apple_bl_ready(sc))
+ return (ENXIO);
+ mtx_lock(&sc->bl_mtx);
+ apple_bl_hw_set(sc, apple_bl_pct_to_hw(sc, props->brightness));
+ sc->bl_brightness = props->brightness;
+ mtx_unlock(&sc->bl_mtx);
+
+ return (0);
+}
+
+int
+acpi_apple_bl_get_status(device_t dev, struct backlight_props *props)
+{
+ struct acpi_apple_softc *sc;
+
+ sc = device_get_softc(dev);
+ if (!apple_bl_ready(sc))
+ return (ENXIO);
+ props->brightness = sc->bl_brightness;
+ props->nlevels = 0;
+
+ return (0);
+}
+
+int
+acpi_apple_bl_get_info(device_t dev, struct backlight_info *info)
+{
+ info->type = BACKLIGHT_TYPE_PANEL;
+ strlcpy(info->name, "Apple Panel Backlight", BACKLIGHTMAXNAMELENGTH);
+ return (0);
+}
+
+/*
+ * Restore backlight to cached brightness. Called from the platform
+ * instance lid-open notify handler. Caller holds no locks.
+ */
+void
+acpi_apple_backlight_restore(void)
+{
+ struct acpi_apple_softc *sc;
+
+ ACPI_SERIAL_BEGIN(apple);
+ sc = apple_backlight_sc;
+ if (sc == NULL || !apple_bl_ready(sc)) {
+ ACPI_SERIAL_END(apple);
+ return;
+ }
+ mtx_lock(&sc->bl_mtx);
+ apple_bl_hw_set(sc, apple_bl_pct_to_hw(sc, sc->bl_brightness));
+ mtx_unlock(&sc->bl_mtx);
+ ACPI_SERIAL_END(apple);
+}
+
+/*
+ * Turn off backlight. Called from the platform instance lid-close
+ * notify handler. Does not change the cached brightness so that
+ * restore() brings it back on lid open.
+ */
+void
+acpi_apple_backlight_off(void)
+{
+ struct acpi_apple_softc *sc;
+
+ ACPI_SERIAL_BEGIN(apple);
+ sc = apple_backlight_sc;
+ if (sc == NULL || !apple_bl_ready(sc)) {
+ ACPI_SERIAL_END(apple);
+ return;
+ }
+ mtx_lock(&sc->bl_mtx);
+ apple_bl_hw_set(sc, 0);
+ mtx_unlock(&sc->bl_mtx);
+ ACPI_SERIAL_END(apple);
+}
diff --git a/sys/dev/apple_acpi/wake_on_lan.c b/sys/dev/apple_acpi/wake_on_lan.c
new file mode 100644
--- /dev/null
+++ b/sys/dev/apple_acpi/wake_on_lan.c
@@ -0,0 +1,163 @@
+/*
+ * Copyright (c) 2026 Abdelkader Boudih <freebsd@seuros.com>
+ *
+ * SPDX-License-Identifier: BSD-2-Clause
+ */
+
+/*
+ * Apple platform ACPI: Wake-on-LAN and lid state.
+ *
+ * Walks the ACPI namespace on shutdown calling _PSW(1) on any device
+ * with ACPI_FLAG_WAKE_ENABLED set, arming EC.EWOL for wake on magic
+ * packet. Also exposes lid state via sysctl.
+ */
+
+#include <sys/cdefs.h>
+#include "apple_acpi.h"
+
+/*
+ * APP9876 and APP000B attach concurrently as ACPI_APPLE_PLATFORM on T2
+ * Macs with a discrete GPU. Refcount the shutdown hook and lid notify
+ * handler here so the second instance's attach/detach doesn't reinstall
+ * or rip out the first instance's hooks.
+ */
+static struct mtx acpi_apple_platform_mtx;
+MTX_SYSINIT(acpi_apple_platform_mtx_init, &acpi_apple_platform_mtx,
+ "apple_platform", MTX_DEF);
+static int acpi_apple_platform_refs;
+static eventhandler_tag acpi_apple_shutdown_tag;
+static ACPI_HANDLE acpi_apple_lid_handle;
+
+static ACPI_STATUS
+acpi_apple_psw_cb(ACPI_HANDLE handle, UINT32 level __unused, void *context,
+ void **retval __unused)
+{
+ ACPI_HANDLE psw_handle;
+ device_t dev;
+ int enable;
+
+ enable = (int)(uintptr_t)context;
+
+ if (ACPI_FAILURE(AcpiGetHandle(handle, "_PSW", &psw_handle)))
+ return (AE_OK);
+
+ dev = acpi_get_device(handle);
+ if (dev == NULL)
+ return (AE_OK);
+
+ if (enable && (acpi_get_flags(dev) & ACPI_FLAG_WAKE_ENABLED) == 0)
+ return (AE_OK);
+
+ (void)acpi_SetInteger(handle, "_PSW", enable);
+ if (bootverbose)
+ device_printf(dev, "acpi_apple: _PSW(%d) on %s\n",
+ enable, acpi_name(handle));
+
+ return (AE_OK);
+}
+
+static void
+acpi_apple_arm_wol(void *arg __unused, int howto __unused)
+{
+ AcpiWalkNamespace(ACPI_TYPE_DEVICE, ACPI_ROOT_OBJECT,
+ ACPI_UINT32_MAX, acpi_apple_psw_cb, NULL,
+ (void *)(uintptr_t)1, NULL);
+}
+
+#define ACPI_NOTIFY_STATUS_CHANGED 0x80
+
+static int
+acpi_apple_lid_sysctl(SYSCTL_HANDLER_ARGS)
+{
+ ACPI_HANDLE lid_handle;
+ int val;
+
+ val = 0;
+ if (ACPI_SUCCESS(AcpiGetHandle(ACPI_ROOT_OBJECT,
+ "\\_SB.LID0", &lid_handle)))
+ acpi_GetInteger(lid_handle, "_LID", &val);
+ return (sysctl_handle_int(oidp, &val, 0, req));
+}
+
+/*
+ * Deferred lid event handler. Runs outside ACPI notify context
+ * via AcpiOsExecute(). Evaluate _LID and restore backlight on open.
+ */
+static void
+acpi_apple_lid_event(void *context __unused)
+{
+ int lid_open;
+
+ lid_open = 0;
+ if (acpi_apple_lid_handle != NULL)
+ acpi_GetInteger(acpi_apple_lid_handle, "_LID", &lid_open);
+
+ if (lid_open)
+ acpi_apple_backlight_restore();
+ else
+ acpi_apple_backlight_off();
+}
+
+static void
+acpi_apple_lid_notify(ACPI_HANDLE h __unused, UINT32 notify,
+ void *context __unused)
+{
+ if (notify == ACPI_NOTIFY_STATUS_CHANGED)
+ AcpiOsExecute(OSL_NOTIFY_HANDLER, acpi_apple_lid_event, NULL);
+}
+
+int
+acpi_apple_platform_attach(struct acpi_apple_softc *sc)
+{
+ struct sysctl_ctx_list *sctx;
+ struct sysctl_oid *tree;
+
+ sctx = device_get_sysctl_ctx(sc->dev);
+ tree = device_get_sysctl_tree(sc->dev);
+
+ SYSCTL_ADD_PROC(sctx, SYSCTL_CHILDREN(tree), OID_AUTO,
+ "lid", CTLTYPE_INT | CTLFLAG_RD | CTLFLAG_MPSAFE,
+ sc->dev, 0, acpi_apple_lid_sysctl, "I",
+ "Lid open (1) or closed (0)");
+
+ mtx_lock(&acpi_apple_platform_mtx);
+ if (acpi_apple_platform_refs++ == 0) {
+ acpi_apple_shutdown_tag = EVENTHANDLER_REGISTER(
+ shutdown_final, acpi_apple_arm_wol, NULL,
+ SHUTDOWN_PRI_LAST);
+
+ /* Install lid notify handler for backlight restore. */
+ if (ACPI_SUCCESS(AcpiGetHandle(ACPI_ROOT_OBJECT,
+ "\\_SB.LID0", &acpi_apple_lid_handle))) {
+ if (ACPI_SUCCESS(AcpiInstallNotifyHandler(
+ acpi_apple_lid_handle, ACPI_DEVICE_NOTIFY,
+ acpi_apple_lid_notify, NULL)))
+ device_printf(sc->dev,
+ "lid notify handler installed\n");
+ else
+ acpi_apple_lid_handle = NULL;
+ }
+ }
+ mtx_unlock(&acpi_apple_platform_mtx);
+
+ return (0);
+}
+
+void
+acpi_apple_platform_detach(struct acpi_apple_softc *sc __unused)
+{
+ mtx_lock(&acpi_apple_platform_mtx);
+ if (--acpi_apple_platform_refs == 0) {
+ if (acpi_apple_lid_handle != NULL) {
+ AcpiRemoveNotifyHandler(acpi_apple_lid_handle,
+ ACPI_DEVICE_NOTIFY, acpi_apple_lid_notify);
+ acpi_apple_lid_handle = NULL;
+ }
+ if (acpi_apple_shutdown_tag != NULL) {
+ EVENTHANDLER_DEREGISTER(shutdown_final,
+ acpi_apple_shutdown_tag);
+ acpi_apple_shutdown_tag = NULL;
+ }
+ }
+ mtx_unlock(&acpi_apple_platform_mtx);
+}
diff --git a/sys/modules/acpi/Makefile b/sys/modules/acpi/Makefile
--- a/sys/modules/acpi/Makefile
+++ b/sys/modules/acpi/Makefile
@@ -16,6 +16,11 @@
aibs
.endif
+.if ${MACHINE_CPUARCH} == "amd64"
+SUBDIR+= \
+ acpi_apple
+.endif
+
SUBDIR+= \
acpi_einj \
acpi_ged
diff --git a/sys/modules/acpi/acpi_apple/Makefile b/sys/modules/acpi/acpi_apple/Makefile
new file mode 100644
--- /dev/null
+++ b/sys/modules/acpi/acpi_apple/Makefile
@@ -0,0 +1,8 @@
+.PATH: ${SRCTOP}/sys/dev/apple_acpi
+
+KMOD= acpi_apple
+SRCS= apple_acpi.c wake_on_lan.c apple_backlight.c \
+ opt_acpi.h acpi_if.h bus_if.h device_if.h \
+ pci_if.h backlight_if.h
+
+.include <bsd.kmod.mk>

File Metadata

Mime Type
text/plain
Expires
Sun, Aug 23, 6:47 AM (23 m, 16 s)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
37006727
Default Alt Text
D58867.diff (35 KB)

Event Timeline