From nobody Sat Mar 7 15:27:52 2026 X-Original-To: dev-commits-src-main@mlmmj.nyi.freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2610:1c1:1:606c::19:1]) by mlmmj.nyi.freebsd.org (Postfix) with ESMTP id 4fSnGK0QvTz6TdpG for ; Sat, 07 Mar 2026 15:27:53 +0000 (UTC) (envelope-from git@FreeBSD.org) Received: from mxrelay.nyi.freebsd.org (mxrelay.nyi.freebsd.org [IPv6:2610:1c1:1:606c::19:3]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (4096 bits) server-digest SHA256 client-signature RSA-PSS (4096 bits) client-digest SHA256) (Client CN "mxrelay.nyi.freebsd.org", Issuer "R12" (not verified)) by mx1.freebsd.org (Postfix) with ESMTPS id 4fSnGJ6qFMz3Vfy for ; Sat, 07 Mar 2026 15:27:52 +0000 (UTC) (envelope-from git@FreeBSD.org) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=freebsd.org; s=dkim; t=1772897273; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:mime-version:mime-version:content-type:content-type: content-transfer-encoding:content-transfer-encoding; bh=9xUAc9rhqOZclIsNkdHfjyk6fc6pPicORe/oC52xwAU=; b=H8S6FAoKgdpOMruqZMjt4+UbJGX/Pk0+A/s3+TEOJVuUQ0qGEft4ysAvh6DDG3lPWTufBb yyEnbe3eCK9ApvEeuKq7TIPb8hfwgUm2POwbPFg6JteM6Y+z/3OklAAS9ewOU7OCPYBWdQ NF9qa8ltQGQdNso1s+UKmecDzLwFfFnl+CjzdFtlp/5+x8f68dP+E5aN0YWqolQee/iyYd /jxm3aoUxFaSTKE6TYuFhzJhCNFRJhBxItMPjvQaYt6yoy5wVLGGnBPfbwNNfuuikdQIs1 b6cA2FBG+v/BXdImlFTiHeiXRbui9+54Mfg58y9jxatXx6qgOo5sRin4vqQlkg== ARC-Seal: i=1; s=dkim; d=freebsd.org; t=1772897273; a=rsa-sha256; cv=none; b=Ppt01eN9NeUIZTgRJv9cgA9YAg5Y8mJuOePnsDto/FpYS5oTliybnQfgjsxB0tjW60voOr N+UxQgVp7emrsFw6rthlymS9J1gLUSjlsssNa5Nvh/B7HsOH0qcOfMyAtVkfj0kEUWkOW5 JMBMI9rHYslz+U+tKjqil6cxkcMd5MmIRHmYN3oLcSgJ9AJX5g3l4gHpl3PmDlhp1bWDBH WDGk6qML+R+bo2w5s8F4tWVSf31WuJrdls57RvIe/dXx6to+P8NlnnshAuKM6BM5Zk9TWb R0jG/4D4jm5vlhCfQIagRHGCFixx17+qWhe+Qi88mXU5isPd4afFGPddtDFunQ== ARC-Authentication-Results: i=1; mx1.freebsd.org; none ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=freebsd.org; s=dkim; t=1772897273; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:mime-version:mime-version:content-type:content-type: content-transfer-encoding:content-transfer-encoding; bh=9xUAc9rhqOZclIsNkdHfjyk6fc6pPicORe/oC52xwAU=; b=XrTiU85KSjWvcKR1J9WiM32AuTD+S5TDv/kKxUGNo4/NigpYIzAOAk1JsNZvoGwpaAJN3l TWsTmPk/ZFwoieRT0gq1d+Sx1hCp9hbeKpX3pzjS7mjKycwyKFdqXN+dDenujen6ffYvPr vs0yzHQboxOaDF30DL6aR/I4aoKtWORsAmeN+75P1duDPMMUZ1/tNd/lb1mUJsfYbKD8BH Qfjen34Jv0mu2MzyCdlRq4FvVL4q/pniMMAorLrcMPuahIeu4QPU118CkT9ihCC4Lq/RU+ rsdZXzrdFFadlBo50IdbEhZ3U4jpCcYuG4yfbeA/rOpTdLxQCi3PCtxxu3NBGw== Received: from gitrepo.freebsd.org (gitrepo.freebsd.org [IPv6:2610:1c1:1:6068::e6a:5]) by mxrelay.nyi.freebsd.org (Postfix) with ESMTP id 4fSnGJ6NkVz90 for ; Sat, 07 Mar 2026 15:27:52 +0000 (UTC) (envelope-from git@FreeBSD.org) Received: from git (uid 1279) (envelope-from git@FreeBSD.org) id 3b694 by gitrepo.freebsd.org (DragonFly Mail Agent v0.13+ on gitrepo.freebsd.org); Sat, 07 Mar 2026 15:27:52 +0000 To: src-committers@FreeBSD.org, dev-commits-src-all@FreeBSD.org, dev-commits-src-main@FreeBSD.org From: Pouria Mousavizadeh Tehrani Subject: git: cdad55809ef5 - main - acpi_system76: Support for acpi-controlled buttons on System76 List-Id: Commit messages for the main branch of the src repository List-Archive: https://lists.freebsd.org/archives/dev-commits-src-main List-Help: List-Post: List-Subscribe: List-Unsubscribe: X-BeenThere: dev-commits-src-main@freebsd.org Sender: owner-dev-commits-src-main@FreeBSD.org MIME-Version: 1.0 Content-Type: text/plain; charset=utf-8 Content-Transfer-Encoding: 8bit X-Git-Committer: pouria X-Git-Repository: src X-Git-Refname: refs/heads/main X-Git-Reftype: branch X-Git-Commit: cdad55809ef59239c3bbdc841ed307db68bb3971 Auto-Submitted: auto-generated Date: Sat, 07 Mar 2026 15:27:52 +0000 Message-Id: <69ac43f8.3b694.a8b5285@gitrepo.freebsd.org> The branch main has been updated by pouria: URL: https://cgit.FreeBSD.org/src/commit/?id=cdad55809ef59239c3bbdc841ed307db68bb3971 commit cdad55809ef59239c3bbdc841ed307db68bb3971 Author: Pouria Mousavizadeh Tehrani AuthorDate: 2026-03-06 17:15:49 +0000 Commit: Pouria Mousavizadeh Tehrani CommitDate: 2026-03-07 15:27:08 +0000 acpi_system76: Support for acpi-controlled buttons on System76 Add acpi_system76 for handling acpi-controlled buttons on System76 Laptops. Reviewed by: imp Differential Revision: https://reviews.freebsd.org/D55694 --- sys/conf/files | 1 + sys/dev/acpi_support/acpi_system76.c | 359 ++++++++++++++++++++++++++++++++ sys/modules/acpi/Makefile | 1 + sys/modules/acpi/acpi_system76/Makefile | 7 + sys/x86/conf/NOTES | 3 + 5 files changed, 371 insertions(+) diff --git a/sys/conf/files b/sys/conf/files index 632fddef2cb5..ceff5c9d6c16 100644 --- a/sys/conf/files +++ b/sys/conf/files @@ -744,6 +744,7 @@ dev/acpi_support/acpi_ibm.c optional acpi_ibm acpi dev/acpi_support/acpi_panasonic.c optional acpi_panasonic acpi dev/acpi_support/acpi_sbl_wmi.c optional acpi_sbl_wmi acpi dev/acpi_support/acpi_sony.c optional acpi_sony acpi +dev/acpi_support/acpi_system76.c optional acpi_system76 acpi dev/acpi_support/acpi_toshiba.c optional acpi_toshiba acpi dev/acpi_support/atk0110.c optional aibs acpi dev/acpica/Osd/OsdDebug.c optional acpi diff --git a/sys/dev/acpi_support/acpi_system76.c b/sys/dev/acpi_support/acpi_system76.c new file mode 100644 index 000000000000..916a9a61f471 --- /dev/null +++ b/sys/dev/acpi_support/acpi_system76.c @@ -0,0 +1,359 @@ +/*- + * SPDX-License-Identifier: BSD-2-Clause + * + * Copyright (c) 2026 Pouria Mousavizadeh Tehrani + * 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 AND CONTRIBUTORS ``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 OR CONTRIBUTORS 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 + +#define _COMPONENT ACPI_OEM +ACPI_MODULE_NAME("system76") + +static char *system76_ids[] = { "17761776", NULL }; +ACPI_SERIAL_DECL(system76, "System76 ACPI management"); + +struct acpi_ctrl { + int val; + bool exists; +}; + +struct acpi_system76_softc { + device_t dev; + ACPI_HANDLE handle; + + struct acpi_ctrl kbb, /* S76_CTRL_KBB */ + kbc; /* S76_CTRL_KBC */ + + struct sysctl_ctx_list sysctl_ctx; + struct sysctl_oid *sysctl_tree; +}; + +static int acpi_system76_probe(device_t); +static int acpi_system76_attach(device_t); +static int acpi_system76_detach(device_t); +static void acpi_system76_init(struct acpi_system76_softc *); +static struct acpi_ctrl * + acpi_system76_ctrl_map(struct acpi_system76_softc *, int); +static int acpi_system76_update(struct acpi_system76_softc *, int, bool); +static int acpi_system76_sysctl_handler(SYSCTL_HANDLER_ARGS); +static void acpi_system76_notify_handler(ACPI_HANDLE, uint32_t, void *); +static void acpi_system76_check(struct acpi_system76_softc *); + +/* methods */ +#define S76_CTRL_KBB 1 /* Keyboard Brightness */ +#define S76_CTRL_KBC 2 /* Keyboard Color */ +#define S76_CTRL_MAX 3 + +struct s76_ctrl_table { + char *name; + char *get_method; +#define S76_CTRL_GKBB "\\_SB.S76D.GKBB" +#define S76_CTRL_GKBC "\\_SB.S76D.GKBC" + + char *set_method; +#define S76_CTRL_SKBB "\\_SB.S76D.SKBB" +#define S76_CTRL_SKBC "\\_SB.S76D.SKBC" + + char *desc; +}; + +static const struct s76_ctrl_table s76_sysctl_table[] = { + [S76_CTRL_KBB] = { + .name = "keyboard_backlight", + .get_method = S76_CTRL_GKBB, + .set_method = S76_CTRL_SKBB, + .desc = "Keyboard Backlight", + }, + [S76_CTRL_KBC] = { + .name = "keyboard_color", + .get_method = S76_CTRL_GKBC, + .set_method = S76_CTRL_SKBC, + .desc = "Keyboard Color", + }, +}; + +static device_method_t acpi_system76_methods[] = { + DEVMETHOD(device_probe, acpi_system76_probe), + DEVMETHOD(device_attach, acpi_system76_attach), + DEVMETHOD(device_detach, acpi_system76_detach), + + DEVMETHOD_END +}; + +/* Notify event */ +#define ACPI_NOTIFY_BACKLIGHT_CHANGED 0x80 +#define ACPI_NOTIFY_COLOR_TOGGLE 0x81 +#define ACPI_NOTIFY_COLOR_DOWN 0x82 +#define ACPI_NOTIFY_COLOR_UP 0x83 +#define ACPI_NOTIFY_COLOR_CHANGED 0x84 + +static driver_t acpi_system76_driver = { + "acpi_system76", + acpi_system76_methods, + sizeof(struct acpi_system76_softc) +}; + +/* + * Returns corresponding acpi_ctrl of softc from method + */ +static struct acpi_ctrl * +acpi_system76_ctrl_map(struct acpi_system76_softc *sc, int method) +{ + + switch (method) { + case S76_CTRL_KBB: + return (&sc->kbb); + break; + case S76_CTRL_KBC: + return (&sc->kbc); + break; + default: + device_printf(sc->dev, "Driver received unknown method\n"); + return (NULL); + } +} + +static int +acpi_system76_update(struct acpi_system76_softc *sc, int method, bool set) +{ + struct acpi_ctrl *ctrl; + ACPI_STATUS status; + + ACPI_FUNCTION_TRACE((char *)(uintptr_t)__func__); + ACPI_SERIAL_ASSERT(system76); + + if ((ctrl = acpi_system76_ctrl_map(sc, method)) == NULL) + return (EINVAL); + + if (set) + status = acpi_SetInteger(sc->handle, s76_sysctl_table[method].set_method, + ctrl->val); + else + status = acpi_GetInteger(sc->handle, s76_sysctl_table[method].get_method, + &ctrl->val); + if (ACPI_FAILURE(status)) { + device_printf(sc->dev, "Couldn't query method (%s)\n", + s76_sysctl_table[method].name); + return (status); + } + + return (0); +} + +static void +acpi_system76_notify_update(void *arg) +{ + struct acpi_system76_softc *sc; + int method; + + ACPI_FUNCTION_TRACE((char *)(uintptr_t)__func__); + + sc = (struct acpi_system76_softc *)device_get_softc(arg); + + ACPI_SERIAL_BEGIN(system76); + for (method = 1; method < S76_CTRL_MAX; method++) + acpi_system76_update(sc, method, false); + ACPI_SERIAL_END(system76); +} + +static void +acpi_system76_check(struct acpi_system76_softc *sc) +{ + struct acpi_ctrl *ctrl; + int method; + + ACPI_FUNCTION_TRACE((char *)(uintptr_t)__func__); + ACPI_SERIAL_ASSERT(system76); + + for (method = 1; method < S76_CTRL_MAX; method++) { + if ((ctrl = acpi_system76_ctrl_map(sc, method)) == NULL) + continue; + + if (ACPI_FAILURE(acpi_GetInteger(sc->handle, + s76_sysctl_table[method].get_method, &ctrl->val))) { + ctrl->exists = false; + device_printf(sc->dev, "Driver can't control %s\n", + s76_sysctl_table[method].desc); + } else { + ctrl->exists = true; + acpi_system76_update(sc, method, false); + } + } +} + +static void +acpi_system76_notify_handler(ACPI_HANDLE handle, uint32_t notify, void *ctx) +{ + + ACPI_FUNCTION_TRACE_U32((char *)(uintptr_t)__func__, notify); + + switch (notify) { + case ACPI_NOTIFY_BACKLIGHT_CHANGED: + case ACPI_NOTIFY_COLOR_TOGGLE: + case ACPI_NOTIFY_COLOR_DOWN: + case ACPI_NOTIFY_COLOR_UP: + case ACPI_NOTIFY_COLOR_CHANGED: + AcpiOsExecute(OSL_NOTIFY_HANDLER, + acpi_system76_notify_update, ctx); + break; + default: + break; + } +} + +static int +acpi_system76_sysctl_handler(SYSCTL_HANDLER_ARGS) +{ + struct acpi_ctrl *ctrl; + struct acpi_system76_softc *sc; + int val, method, error; + + ACPI_FUNCTION_TRACE((char *)(uintptr_t)__func__); + + sc = (struct acpi_system76_softc *)oidp->oid_arg1; + method = oidp->oid_arg2; + if ((ctrl = acpi_system76_ctrl_map(sc, method)) == NULL) + return (EINVAL); + + val = ctrl->val; + error = sysctl_handle_int(oidp, &val, 0, req); + if (error != 0) { + device_printf(sc->dev, "Driver query failed\n"); + return (error); + } + if (req->newptr == NULL) + return (error); + + /* Input validation */ + switch (method) { + case S76_CTRL_KBB: + if (val > UINT8_MAX || val < 0) + return (EINVAL); + break; + case S76_CTRL_KBC: + if (val >= (1 << 24) || val < 0) + return (EINVAL); + break; + default: + break; + } + + ctrl->val = val; + + ACPI_SERIAL_BEGIN(system76); + error = acpi_system76_update(sc, method, true); + ACPI_SERIAL_END(system76); + return (error); +} + +static void +acpi_system76_init(struct acpi_system76_softc *sc) +{ + struct acpi_softc *acpi_sc; + struct acpi_ctrl *ctrl; + uint32_t method; + + ACPI_SERIAL_ASSERT(system76); + + acpi_system76_check(sc); + acpi_sc = acpi_device_get_parent_softc(sc->dev); + sysctl_ctx_init(&sc->sysctl_ctx); + sc->sysctl_tree = SYSCTL_ADD_NODE(&sc->sysctl_ctx, + SYSCTL_CHILDREN(acpi_sc->acpi_sysctl_tree), OID_AUTO, "s76", + CTLFLAG_RD | CTLFLAG_MPSAFE, 0, "system76 control"); + + for (method = 1; method < S76_CTRL_MAX; method++) { + if ((ctrl = acpi_system76_ctrl_map(sc, method)) == NULL) + continue; + + if (!ctrl->exists) + continue; + + SYSCTL_ADD_PROC(&sc->sysctl_ctx, + SYSCTL_CHILDREN(sc->sysctl_tree), OID_AUTO, s76_sysctl_table[method].name, + CTLTYPE_UINT | CTLFLAG_RW | CTLFLAG_ANYBODY | CTLFLAG_MPSAFE, + sc, method, acpi_system76_sysctl_handler, "IU", s76_sysctl_table[method].desc); + } +} + +static int +acpi_system76_attach(device_t dev) +{ + struct acpi_system76_softc *sc; + + ACPI_FUNCTION_TRACE((char *)(uintptr_t)__func__); + + sc = device_get_softc(dev); + sc->dev = dev; + sc->handle = acpi_get_handle(dev); + + AcpiInstallNotifyHandler(sc->handle, ACPI_DEVICE_NOTIFY, + acpi_system76_notify_handler, dev); + + ACPI_SERIAL_BEGIN(system76); + acpi_system76_init(sc); + ACPI_SERIAL_END(system76); + + return (0); +} + +static int +acpi_system76_detach(device_t dev) +{ + struct acpi_system76_softc *sc; + + sc = device_get_softc(dev); + if (sysctl_ctx_free(&sc->sysctl_ctx) != 0) + return (EBUSY); + + return (0); +} + +static int +acpi_system76_probe(device_t dev) +{ + int rv; + + if (acpi_disabled("system76") || device_get_unit(dev) > 1) + return (ENXIO); + rv = ACPI_ID_PROBE(device_get_parent(dev), dev, system76_ids, NULL); + if (rv > 0) { + return (rv); + } + + return (BUS_PROBE_VENDOR); +} + +DRIVER_MODULE(acpi_system76, acpi, acpi_system76_driver, 0, 0); +MODULE_VERSION(acpi_system76, 1); +MODULE_DEPEND(acpi_system76, acpi, 1, 1, 1); diff --git a/sys/modules/acpi/Makefile b/sys/modules/acpi/Makefile index 5040187e906f..265e6bd6cdcb 100644 --- a/sys/modules/acpi/Makefile +++ b/sys/modules/acpi/Makefile @@ -9,6 +9,7 @@ SUBDIR= \ acpi_panasonic \ acpi_sbl_wmi \ acpi_sony \ + acpi_system76 \ acpi_toshiba \ acpi_video \ acpi_wmi \ diff --git a/sys/modules/acpi/acpi_system76/Makefile b/sys/modules/acpi/acpi_system76/Makefile new file mode 100644 index 000000000000..86d2c91e712d --- /dev/null +++ b/sys/modules/acpi/acpi_system76/Makefile @@ -0,0 +1,7 @@ +.PATH: ${SRCTOP}/sys/dev/acpi_support + +KMOD= acpi_system76 +CFLAGS+=-I${SRCTOP}/sys/dev/acpi_support +SRCS= acpi_system76.c opt_acpi.h acpi_if.h device_if.h bus_if.h + +.include diff --git a/sys/x86/conf/NOTES b/sys/x86/conf/NOTES index 501d4159b129..877cbb3beb7f 100644 --- a/sys/x86/conf/NOTES +++ b/sys/x86/conf/NOTES @@ -178,6 +178,9 @@ device acpi_sbl_wmi # ACPI Sony extra (LCD brightness) device acpi_sony +# ACPI System76 extra (Keyboard brightness, Keyboard color) +device acpi_system76 + # ACPI Toshiba Extras (LCD backlight/brightness, video output, etc.) device acpi_toshiba