Page Menu
Home
FreeBSD
Search
Configure Global Search
Log In
Files
F167494735
D58867.diff
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Flag For Later
Award Token
Size
35 KB
Referenced Files
None
Subscribers
None
D58867.diff
View Options
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
Details
Attached
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)
Attached To
Mode
D58867: acpi_apple: Apple platform ACPI driver,
Attached
Detach File
Event Timeline
Log In to Comment