xref: /freebsd/sys/dev/acpi_support/acpi_system76.c (revision f91464171d615b7e7720ac9ed67e2e86392d1b41)
1cdad5580SPouria Mousavizadeh Tehrani /*-
2cdad5580SPouria Mousavizadeh Tehrani  * SPDX-License-Identifier: BSD-2-Clause
3cdad5580SPouria Mousavizadeh Tehrani  *
4cdad5580SPouria Mousavizadeh Tehrani  * Copyright (c) 2026 Pouria Mousavizadeh Tehrani <pouria@FreeBSD.org>
5cdad5580SPouria Mousavizadeh Tehrani  * All rights reserved.
6cdad5580SPouria Mousavizadeh Tehrani  *
7cdad5580SPouria Mousavizadeh Tehrani  * Redistribution and use in source and binary forms, with or without
8cdad5580SPouria Mousavizadeh Tehrani  * modification, are permitted provided that the following conditions
9cdad5580SPouria Mousavizadeh Tehrani  * are met:
10cdad5580SPouria Mousavizadeh Tehrani  * 1. Redistributions of source code must retain the above copyright
11cdad5580SPouria Mousavizadeh Tehrani  *    notice, this list of conditions and the following disclaimer.
12cdad5580SPouria Mousavizadeh Tehrani  * 2. Redistributions in binary form must reproduce the above copyright
13cdad5580SPouria Mousavizadeh Tehrani  *    notice, this list of conditions and the following disclaimer in the
14cdad5580SPouria Mousavizadeh Tehrani  *    documentation and/or other materials provided with the distribution.
15cdad5580SPouria Mousavizadeh Tehrani  *
16cdad5580SPouria Mousavizadeh Tehrani  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
17cdad5580SPouria Mousavizadeh Tehrani  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18cdad5580SPouria Mousavizadeh Tehrani  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19cdad5580SPouria Mousavizadeh Tehrani  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
20cdad5580SPouria Mousavizadeh Tehrani  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21cdad5580SPouria Mousavizadeh Tehrani  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
22cdad5580SPouria Mousavizadeh Tehrani  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
23cdad5580SPouria Mousavizadeh Tehrani  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
24cdad5580SPouria Mousavizadeh Tehrani  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
25cdad5580SPouria Mousavizadeh Tehrani  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26cdad5580SPouria Mousavizadeh Tehrani  * SUCH DAMAGE.
27cdad5580SPouria Mousavizadeh Tehrani  */
28cdad5580SPouria Mousavizadeh Tehrani 
29fa4f625eSPouria Mousavizadeh Tehrani #include "opt_acpi.h"
30*f9146417SPouria Mousavizadeh Tehrani 
31cdad5580SPouria Mousavizadeh Tehrani #include <sys/param.h>
32cdad5580SPouria Mousavizadeh Tehrani #include <sys/bus.h>
33*f9146417SPouria Mousavizadeh Tehrani #include <sys/kernel.h>
34cdad5580SPouria Mousavizadeh Tehrani #include <sys/module.h>
35*f9146417SPouria Mousavizadeh Tehrani #include <sys/sysctl.h>
36cdad5580SPouria Mousavizadeh Tehrani 
37cdad5580SPouria Mousavizadeh Tehrani #include <contrib/dev/acpica/include/acpi.h>
38fa4f625eSPouria Mousavizadeh Tehrani #include <contrib/dev/acpica/include/accommon.h>
39cdad5580SPouria Mousavizadeh Tehrani 
40cdad5580SPouria Mousavizadeh Tehrani #include <dev/acpica/acpivar.h>
41105869a2SPouria Mousavizadeh Tehrani #include <dev/backlight/backlight.h>
42*f9146417SPouria Mousavizadeh Tehrani 
43105869a2SPouria Mousavizadeh Tehrani #include "backlight_if.h"
44105869a2SPouria Mousavizadeh Tehrani 
45cdad5580SPouria Mousavizadeh Tehrani #define _COMPONENT ACPI_OEM
46cdad5580SPouria Mousavizadeh Tehrani ACPI_MODULE_NAME("system76")
47cdad5580SPouria Mousavizadeh Tehrani 
48cdad5580SPouria Mousavizadeh Tehrani static char	*system76_ids[] = { "17761776", NULL };
49cdad5580SPouria Mousavizadeh Tehrani ACPI_SERIAL_DECL(system76, "System76 ACPI management");
50cdad5580SPouria Mousavizadeh Tehrani 
51cdad5580SPouria Mousavizadeh Tehrani struct acpi_ctrl {
52cdad5580SPouria Mousavizadeh Tehrani 	int	val;
53cdad5580SPouria Mousavizadeh Tehrani 	bool	exists;
54cdad5580SPouria Mousavizadeh Tehrani };
55cdad5580SPouria Mousavizadeh Tehrani 
56cdad5580SPouria Mousavizadeh Tehrani struct acpi_system76_softc {
57cdad5580SPouria Mousavizadeh Tehrani 	device_t	dev;
58cdad5580SPouria Mousavizadeh Tehrani 	ACPI_HANDLE	handle;
59cdad5580SPouria Mousavizadeh Tehrani 
60cdad5580SPouria Mousavizadeh Tehrani 	struct acpi_ctrl	kbb,	/* S76_CTRL_KBB */
61f87ba452SPouria Mousavizadeh Tehrani 				kbc,	/* S76_CTRL_KBC */
62f87ba452SPouria Mousavizadeh Tehrani 				bctl,	/* S76_CTRL_BCTL */
63f87ba452SPouria Mousavizadeh Tehrani 				bcth;	/* S76_CTRL_BCTH */
64cdad5580SPouria Mousavizadeh Tehrani 
65cdad5580SPouria Mousavizadeh Tehrani 	struct sysctl_ctx_list	sysctl_ctx;
66cdad5580SPouria Mousavizadeh Tehrani 	struct sysctl_oid	*sysctl_tree;
67105869a2SPouria Mousavizadeh Tehrani 	struct cdev	*kbb_bkl;
68105869a2SPouria Mousavizadeh Tehrani 	uint8_t		backlight_level;
69cdad5580SPouria Mousavizadeh Tehrani };
70cdad5580SPouria Mousavizadeh Tehrani 
71cdad5580SPouria Mousavizadeh Tehrani static int	acpi_system76_probe(device_t);
72cdad5580SPouria Mousavizadeh Tehrani static int	acpi_system76_attach(device_t);
73cdad5580SPouria Mousavizadeh Tehrani static int	acpi_system76_detach(device_t);
74105869a2SPouria Mousavizadeh Tehrani static int	acpi_system76_suspend(device_t);
75105869a2SPouria Mousavizadeh Tehrani static int	acpi_system76_resume(device_t);
76105869a2SPouria Mousavizadeh Tehrani static int	acpi_system76_shutdown(device_t);
77cdad5580SPouria Mousavizadeh Tehrani static void	acpi_system76_init(struct acpi_system76_softc *);
78cdad5580SPouria Mousavizadeh Tehrani static struct acpi_ctrl *
79cdad5580SPouria Mousavizadeh Tehrani 		acpi_system76_ctrl_map(struct acpi_system76_softc *, int);
80cdad5580SPouria Mousavizadeh Tehrani static int	acpi_system76_update(struct acpi_system76_softc *, int, bool);
81cdad5580SPouria Mousavizadeh Tehrani static int	acpi_system76_sysctl_handler(SYSCTL_HANDLER_ARGS);
82cdad5580SPouria Mousavizadeh Tehrani static void	acpi_system76_notify_handler(ACPI_HANDLE, uint32_t, void *);
83cdad5580SPouria Mousavizadeh Tehrani static void	acpi_system76_check(struct acpi_system76_softc *);
84105869a2SPouria Mousavizadeh Tehrani static int	acpi_system76_backlight_update_status(device_t dev,
85105869a2SPouria Mousavizadeh Tehrani 		    struct backlight_props *props);
86105869a2SPouria Mousavizadeh Tehrani static int	acpi_system76_backlight_get_status(device_t dev,
87105869a2SPouria Mousavizadeh Tehrani 		    struct backlight_props *props);
88105869a2SPouria Mousavizadeh Tehrani static int	acpi_system76_backlight_get_info(device_t dev,
89105869a2SPouria Mousavizadeh Tehrani 		    struct backlight_info *info);
90cdad5580SPouria Mousavizadeh Tehrani 
91cdad5580SPouria Mousavizadeh Tehrani /* methods */
92f87ba452SPouria Mousavizadeh Tehrani enum {
93f87ba452SPouria Mousavizadeh Tehrani 	S76_CTRL_KBB	= 1,	/* Keyboard Brightness */
94f87ba452SPouria Mousavizadeh Tehrani 	S76_CTRL_KBC	= 2,	/* Keyboard Color */
95*f9146417SPouria Mousavizadeh Tehrani 	S76_CTRL_BCTL	= 3,	/* Battery Charging Start Thresholds */
96*f9146417SPouria Mousavizadeh Tehrani 	S76_CTRL_BCTH	= 4,	/* Battery Charging End Thresholds */
97f87ba452SPouria Mousavizadeh Tehrani };
98f87ba452SPouria Mousavizadeh Tehrani #define	S76_CTRL_MAX	5
99cdad5580SPouria Mousavizadeh Tehrani 
100cdad5580SPouria Mousavizadeh Tehrani struct s76_ctrl_table {
101cdad5580SPouria Mousavizadeh Tehrani 	char	*name;
102cdad5580SPouria Mousavizadeh Tehrani 	char	*get_method;
103cdad5580SPouria Mousavizadeh Tehrani #define S76_CTRL_GKBB	"\\_SB.S76D.GKBB"
104cdad5580SPouria Mousavizadeh Tehrani #define S76_CTRL_GKBC	"\\_SB.S76D.GKBC"
105f87ba452SPouria Mousavizadeh Tehrani #define S76_CTRL_GBCT	"\\_SB.PCI0.LPCB.EC0.GBCT"
106cdad5580SPouria Mousavizadeh Tehrani 
107cdad5580SPouria Mousavizadeh Tehrani 	char	*set_method;
108cdad5580SPouria Mousavizadeh Tehrani #define S76_CTRL_SKBB	"\\_SB.S76D.SKBB"
109cdad5580SPouria Mousavizadeh Tehrani #define S76_CTRL_SKBC	"\\_SB.S76D.SKBC"
110f87ba452SPouria Mousavizadeh Tehrani #define S76_CTRL_SBCT	"\\_SB.PCI0.LPCB.EC0.SBCT"
111cdad5580SPouria Mousavizadeh Tehrani 
112cdad5580SPouria Mousavizadeh Tehrani 	char	*desc;
113cdad5580SPouria Mousavizadeh Tehrani };
114cdad5580SPouria Mousavizadeh Tehrani 
115cdad5580SPouria Mousavizadeh Tehrani static const struct s76_ctrl_table s76_sysctl_table[] = {
116cdad5580SPouria Mousavizadeh Tehrani 	[S76_CTRL_KBB] = {
117cdad5580SPouria Mousavizadeh Tehrani 		.name = "keyboard_backlight",
118cdad5580SPouria Mousavizadeh Tehrani 		.get_method = S76_CTRL_GKBB,
119cdad5580SPouria Mousavizadeh Tehrani 		.set_method = S76_CTRL_SKBB,
120cdad5580SPouria Mousavizadeh Tehrani 		.desc = "Keyboard Backlight",
121cdad5580SPouria Mousavizadeh Tehrani 	},
122cdad5580SPouria Mousavizadeh Tehrani 	[S76_CTRL_KBC] = {
123cdad5580SPouria Mousavizadeh Tehrani 		.name = "keyboard_color",
124cdad5580SPouria Mousavizadeh Tehrani 		.get_method = S76_CTRL_GKBC,
125cdad5580SPouria Mousavizadeh Tehrani 		.set_method = S76_CTRL_SKBC,
126cdad5580SPouria Mousavizadeh Tehrani 		.desc = "Keyboard Color",
127cdad5580SPouria Mousavizadeh Tehrani 	},
128f87ba452SPouria Mousavizadeh Tehrani 	[S76_CTRL_BCTL] = {
129*f9146417SPouria Mousavizadeh Tehrani 		.name = "battery_charge_min",
130f87ba452SPouria Mousavizadeh Tehrani 		.get_method = S76_CTRL_GBCT,
131f87ba452SPouria Mousavizadeh Tehrani 		.set_method = S76_CTRL_SBCT,
132*f9146417SPouria Mousavizadeh Tehrani 		.desc = "Start charging the battery when this threshold is reached (percentage)",
133f87ba452SPouria Mousavizadeh Tehrani 	},
134f87ba452SPouria Mousavizadeh Tehrani 	[S76_CTRL_BCTH] = {
135*f9146417SPouria Mousavizadeh Tehrani 		.name = "battery_charge_max",
136f87ba452SPouria Mousavizadeh Tehrani 		.get_method = S76_CTRL_GBCT,
137f87ba452SPouria Mousavizadeh Tehrani 		.set_method = S76_CTRL_SBCT,
138*f9146417SPouria Mousavizadeh Tehrani 		.desc = "Stop charging the battery when this threshold is reached (percentage)",
139f87ba452SPouria Mousavizadeh Tehrani 	},
140cdad5580SPouria Mousavizadeh Tehrani };
141cdad5580SPouria Mousavizadeh Tehrani 
142cdad5580SPouria Mousavizadeh Tehrani static device_method_t acpi_system76_methods[] = {
143105869a2SPouria Mousavizadeh Tehrani 	/* Device interface */
144cdad5580SPouria Mousavizadeh Tehrani 	DEVMETHOD(device_probe, acpi_system76_probe),
145cdad5580SPouria Mousavizadeh Tehrani 	DEVMETHOD(device_attach, acpi_system76_attach),
146cdad5580SPouria Mousavizadeh Tehrani 	DEVMETHOD(device_detach, acpi_system76_detach),
147105869a2SPouria Mousavizadeh Tehrani 	DEVMETHOD(device_suspend, acpi_system76_suspend),
148105869a2SPouria Mousavizadeh Tehrani 	DEVMETHOD(device_resume, acpi_system76_resume),
149105869a2SPouria Mousavizadeh Tehrani 	DEVMETHOD(device_shutdown, acpi_system76_shutdown),
150105869a2SPouria Mousavizadeh Tehrani 
151105869a2SPouria Mousavizadeh Tehrani 	/* Backlight interface */
152105869a2SPouria Mousavizadeh Tehrani         DEVMETHOD(backlight_update_status, acpi_system76_backlight_update_status),
153105869a2SPouria Mousavizadeh Tehrani         DEVMETHOD(backlight_get_status, acpi_system76_backlight_get_status),
154105869a2SPouria Mousavizadeh Tehrani         DEVMETHOD(backlight_get_info, acpi_system76_backlight_get_info),
155cdad5580SPouria Mousavizadeh Tehrani 
156cdad5580SPouria Mousavizadeh Tehrani 	DEVMETHOD_END
157cdad5580SPouria Mousavizadeh Tehrani };
158cdad5580SPouria Mousavizadeh Tehrani 
159cdad5580SPouria Mousavizadeh Tehrani /* Notify event */
160cdad5580SPouria Mousavizadeh Tehrani #define	ACPI_NOTIFY_BACKLIGHT_CHANGED	0x80
161cdad5580SPouria Mousavizadeh Tehrani #define	ACPI_NOTIFY_COLOR_TOGGLE	0x81
162cdad5580SPouria Mousavizadeh Tehrani #define	ACPI_NOTIFY_COLOR_DOWN		0x82
163cdad5580SPouria Mousavizadeh Tehrani #define	ACPI_NOTIFY_COLOR_UP		0x83
164cdad5580SPouria Mousavizadeh Tehrani #define	ACPI_NOTIFY_COLOR_CHANGED	0x84
165cdad5580SPouria Mousavizadeh Tehrani 
166cdad5580SPouria Mousavizadeh Tehrani static driver_t acpi_system76_driver = {
167cdad5580SPouria Mousavizadeh Tehrani 	"acpi_system76",
168cdad5580SPouria Mousavizadeh Tehrani 	acpi_system76_methods,
169cdad5580SPouria Mousavizadeh Tehrani 	sizeof(struct acpi_system76_softc)
170cdad5580SPouria Mousavizadeh Tehrani };
171cdad5580SPouria Mousavizadeh Tehrani 
172105869a2SPouria Mousavizadeh Tehrani static const uint32_t acpi_system76_backlight_levels[] = {
173105869a2SPouria Mousavizadeh Tehrani 	0, 6, 12, 18, 24, 30, 36, 42,
174105869a2SPouria Mousavizadeh Tehrani 	48, 54, 60, 66, 72, 78, 84, 100
175105869a2SPouria Mousavizadeh Tehrani };
176105869a2SPouria Mousavizadeh Tehrani 
177105869a2SPouria Mousavizadeh Tehrani static inline uint32_t
devstate_to_backlight(uint32_t val)178105869a2SPouria Mousavizadeh Tehrani devstate_to_backlight(uint32_t val)
179105869a2SPouria Mousavizadeh Tehrani {
180105869a2SPouria Mousavizadeh Tehrani 	return (acpi_system76_backlight_levels[val >> 4 & 0xf]);
181105869a2SPouria Mousavizadeh Tehrani }
182105869a2SPouria Mousavizadeh Tehrani 
183105869a2SPouria Mousavizadeh Tehrani static inline uint32_t
backlight_to_devstate(uint32_t bkl)184105869a2SPouria Mousavizadeh Tehrani backlight_to_devstate(uint32_t bkl)
185105869a2SPouria Mousavizadeh Tehrani {
186105869a2SPouria Mousavizadeh Tehrani 	int i;
187105869a2SPouria Mousavizadeh Tehrani 	uint32_t val;
188105869a2SPouria Mousavizadeh Tehrani 
189105869a2SPouria Mousavizadeh Tehrani 	for (i = 0; i < nitems(acpi_system76_backlight_levels); i++) {
190105869a2SPouria Mousavizadeh Tehrani 		if (bkl < acpi_system76_backlight_levels[i])
191105869a2SPouria Mousavizadeh Tehrani 			break;
192105869a2SPouria Mousavizadeh Tehrani 	}
193105869a2SPouria Mousavizadeh Tehrani 	val = (i - 1) * 16;
194105869a2SPouria Mousavizadeh Tehrani 	if (val > 224)
195105869a2SPouria Mousavizadeh Tehrani 		val = 255;
196105869a2SPouria Mousavizadeh Tehrani 	return (val);
197105869a2SPouria Mousavizadeh Tehrani }
198105869a2SPouria Mousavizadeh Tehrani 
199cdad5580SPouria Mousavizadeh Tehrani /*
200cdad5580SPouria Mousavizadeh Tehrani  * Returns corresponding acpi_ctrl of softc from method
201cdad5580SPouria Mousavizadeh Tehrani  */
202cdad5580SPouria Mousavizadeh Tehrani static struct acpi_ctrl *
acpi_system76_ctrl_map(struct acpi_system76_softc * sc,int method)203cdad5580SPouria Mousavizadeh Tehrani acpi_system76_ctrl_map(struct acpi_system76_softc *sc, int method)
204cdad5580SPouria Mousavizadeh Tehrani {
205cdad5580SPouria Mousavizadeh Tehrani 
206cdad5580SPouria Mousavizadeh Tehrani 	switch (method) {
207cdad5580SPouria Mousavizadeh Tehrani 	case S76_CTRL_KBB:
208cdad5580SPouria Mousavizadeh Tehrani 		return (&sc->kbb);
209cdad5580SPouria Mousavizadeh Tehrani 	case S76_CTRL_KBC:
210cdad5580SPouria Mousavizadeh Tehrani 		return (&sc->kbc);
211f87ba452SPouria Mousavizadeh Tehrani 	case S76_CTRL_BCTL:
212f87ba452SPouria Mousavizadeh Tehrani 		return (&sc->bctl);
213f87ba452SPouria Mousavizadeh Tehrani 	case S76_CTRL_BCTH:
214f87ba452SPouria Mousavizadeh Tehrani 		return (&sc->bcth);
215cdad5580SPouria Mousavizadeh Tehrani 	default:
216cdad5580SPouria Mousavizadeh Tehrani 		device_printf(sc->dev, "Driver received unknown method\n");
217cdad5580SPouria Mousavizadeh Tehrani 		return (NULL);
218cdad5580SPouria Mousavizadeh Tehrani 	}
219cdad5580SPouria Mousavizadeh Tehrani }
220cdad5580SPouria Mousavizadeh Tehrani 
221cdad5580SPouria Mousavizadeh Tehrani static int
acpi_system76_update(struct acpi_system76_softc * sc,int method,bool set)222cdad5580SPouria Mousavizadeh Tehrani acpi_system76_update(struct acpi_system76_softc *sc, int method, bool set)
223cdad5580SPouria Mousavizadeh Tehrani {
224cdad5580SPouria Mousavizadeh Tehrani 	struct acpi_ctrl *ctrl;
225cdad5580SPouria Mousavizadeh Tehrani 	ACPI_STATUS status;
226f87ba452SPouria Mousavizadeh Tehrani 	ACPI_BUFFER Buf;
227f87ba452SPouria Mousavizadeh Tehrani 	ACPI_OBJECT Arg[2], Obj;
228f87ba452SPouria Mousavizadeh Tehrani 	ACPI_OBJECT_LIST Args;
229cdad5580SPouria Mousavizadeh Tehrani 
230cdad5580SPouria Mousavizadeh Tehrani 	ACPI_FUNCTION_TRACE((char *)(uintptr_t)__func__);
231cdad5580SPouria Mousavizadeh Tehrani 	ACPI_SERIAL_ASSERT(system76);
232cdad5580SPouria Mousavizadeh Tehrani 
233cdad5580SPouria Mousavizadeh Tehrani 	if ((ctrl = acpi_system76_ctrl_map(sc, method)) == NULL)
234cdad5580SPouria Mousavizadeh Tehrani 		return (EINVAL);
235cdad5580SPouria Mousavizadeh Tehrani 
236f87ba452SPouria Mousavizadeh Tehrani 	switch (method) {
237f87ba452SPouria Mousavizadeh Tehrani 	case S76_CTRL_BCTL:
238f87ba452SPouria Mousavizadeh Tehrani 	case S76_CTRL_BCTH:
239f87ba452SPouria Mousavizadeh Tehrani 		Arg[0].Type = ACPI_TYPE_INTEGER;
240f87ba452SPouria Mousavizadeh Tehrani 		Arg[0].Integer.Value = method == S76_CTRL_BCTH ? 1 : 0;
241f87ba452SPouria Mousavizadeh Tehrani 		Args.Count = set ? 2 : 1;
242f87ba452SPouria Mousavizadeh Tehrani 		Args.Pointer = Arg;
243f87ba452SPouria Mousavizadeh Tehrani 		Buf.Length = sizeof(Obj);
244f87ba452SPouria Mousavizadeh Tehrani 		Buf.Pointer = &Obj;
245f87ba452SPouria Mousavizadeh Tehrani 
246f87ba452SPouria Mousavizadeh Tehrani 		if (set) {
247f87ba452SPouria Mousavizadeh Tehrani 			Arg[1].Type = ACPI_TYPE_INTEGER;
248f87ba452SPouria Mousavizadeh Tehrani 			Arg[1].Integer.Value = ctrl->val;
249f87ba452SPouria Mousavizadeh Tehrani 
250f87ba452SPouria Mousavizadeh Tehrani 			status = AcpiEvaluateObject(sc->handle,
251f87ba452SPouria Mousavizadeh Tehrani 			    s76_sysctl_table[method].set_method, &Args, &Buf);
252f87ba452SPouria Mousavizadeh Tehrani 		} else {
253f87ba452SPouria Mousavizadeh Tehrani 			status = AcpiEvaluateObject(sc->handle,
254f87ba452SPouria Mousavizadeh Tehrani 			    s76_sysctl_table[method].get_method, &Args, &Buf);
255f87ba452SPouria Mousavizadeh Tehrani 			if (ACPI_SUCCESS(status) &&
256f87ba452SPouria Mousavizadeh Tehrani 			    Obj.Type == ACPI_TYPE_INTEGER)
257f87ba452SPouria Mousavizadeh Tehrani 				ctrl->val = Obj.Integer.Value;
258f87ba452SPouria Mousavizadeh Tehrani 		}
259f87ba452SPouria Mousavizadeh Tehrani 		break;
260f87ba452SPouria Mousavizadeh Tehrani 	case S76_CTRL_KBB:
261f87ba452SPouria Mousavizadeh Tehrani 	case S76_CTRL_KBC:
262cdad5580SPouria Mousavizadeh Tehrani 		if (set)
263cdad5580SPouria Mousavizadeh Tehrani 			status = acpi_SetInteger(sc->handle, s76_sysctl_table[method].set_method,
264cdad5580SPouria Mousavizadeh Tehrani 			    ctrl->val);
265cdad5580SPouria Mousavizadeh Tehrani 		else
266cdad5580SPouria Mousavizadeh Tehrani 			status = acpi_GetInteger(sc->handle, s76_sysctl_table[method].get_method,
267cdad5580SPouria Mousavizadeh Tehrani 			    &ctrl->val);
268f87ba452SPouria Mousavizadeh Tehrani 		break;
269f87ba452SPouria Mousavizadeh Tehrani 	}
270f87ba452SPouria Mousavizadeh Tehrani 
271cdad5580SPouria Mousavizadeh Tehrani 	if (ACPI_FAILURE(status)) {
272cdad5580SPouria Mousavizadeh Tehrani 		device_printf(sc->dev, "Couldn't query method (%s)\n",
273cdad5580SPouria Mousavizadeh Tehrani 		    s76_sysctl_table[method].name);
274cdad5580SPouria Mousavizadeh Tehrani 		return (status);
275cdad5580SPouria Mousavizadeh Tehrani 	}
276cdad5580SPouria Mousavizadeh Tehrani 
277cdad5580SPouria Mousavizadeh Tehrani 	return (0);
278cdad5580SPouria Mousavizadeh Tehrani }
279cdad5580SPouria Mousavizadeh Tehrani 
280cdad5580SPouria Mousavizadeh Tehrani static void
acpi_system76_notify_update(void * arg)281cdad5580SPouria Mousavizadeh Tehrani acpi_system76_notify_update(void *arg)
282cdad5580SPouria Mousavizadeh Tehrani {
283cdad5580SPouria Mousavizadeh Tehrani 	struct acpi_system76_softc *sc;
284cdad5580SPouria Mousavizadeh Tehrani 	int method;
285cdad5580SPouria Mousavizadeh Tehrani 
286cdad5580SPouria Mousavizadeh Tehrani 	ACPI_FUNCTION_TRACE((char *)(uintptr_t)__func__);
287cdad5580SPouria Mousavizadeh Tehrani 
288cdad5580SPouria Mousavizadeh Tehrani 	sc = (struct acpi_system76_softc *)device_get_softc(arg);
289cdad5580SPouria Mousavizadeh Tehrani 
290cdad5580SPouria Mousavizadeh Tehrani 	ACPI_SERIAL_BEGIN(system76);
291f87ba452SPouria Mousavizadeh Tehrani 	for (method = 1; method < S76_CTRL_MAX; method++) {
292f87ba452SPouria Mousavizadeh Tehrani 		if (method == S76_CTRL_BCTL ||
293f87ba452SPouria Mousavizadeh Tehrani 		    method == S76_CTRL_BCTH)
294f87ba452SPouria Mousavizadeh Tehrani 			continue;
295cdad5580SPouria Mousavizadeh Tehrani 		acpi_system76_update(sc, method, false);
296f87ba452SPouria Mousavizadeh Tehrani 	}
297cdad5580SPouria Mousavizadeh Tehrani 	ACPI_SERIAL_END(system76);
298105869a2SPouria Mousavizadeh Tehrani 
299105869a2SPouria Mousavizadeh Tehrani 	if (sc->kbb_bkl != NULL)
300105869a2SPouria Mousavizadeh Tehrani 		sc->backlight_level = devstate_to_backlight(sc->kbb.val);
301cdad5580SPouria Mousavizadeh Tehrani }
302cdad5580SPouria Mousavizadeh Tehrani 
303cdad5580SPouria Mousavizadeh Tehrani static void
acpi_system76_check(struct acpi_system76_softc * sc)304cdad5580SPouria Mousavizadeh Tehrani acpi_system76_check(struct acpi_system76_softc *sc)
305cdad5580SPouria Mousavizadeh Tehrani {
306cdad5580SPouria Mousavizadeh Tehrani 	struct acpi_ctrl *ctrl;
307cdad5580SPouria Mousavizadeh Tehrani 	int method;
308cdad5580SPouria Mousavizadeh Tehrani 
309cdad5580SPouria Mousavizadeh Tehrani 	ACPI_FUNCTION_TRACE((char *)(uintptr_t)__func__);
310cdad5580SPouria Mousavizadeh Tehrani 	ACPI_SERIAL_ASSERT(system76);
311cdad5580SPouria Mousavizadeh Tehrani 
312cdad5580SPouria Mousavizadeh Tehrani 	for (method = 1; method < S76_CTRL_MAX; method++) {
313cdad5580SPouria Mousavizadeh Tehrani 		if ((ctrl = acpi_system76_ctrl_map(sc, method)) == NULL)
314cdad5580SPouria Mousavizadeh Tehrani 			continue;
315cdad5580SPouria Mousavizadeh Tehrani 
316f87ba452SPouria Mousavizadeh Tehrani 		/* available in all models */
317f87ba452SPouria Mousavizadeh Tehrani 		if (method == S76_CTRL_BCTL ||
318f87ba452SPouria Mousavizadeh Tehrani 		    method == S76_CTRL_BCTH) {
319f87ba452SPouria Mousavizadeh Tehrani 			ctrl->exists = true;
320f87ba452SPouria Mousavizadeh Tehrani 			acpi_system76_update(sc, method, false);
321f87ba452SPouria Mousavizadeh Tehrani 			continue;
322f87ba452SPouria Mousavizadeh Tehrani 		}
323f87ba452SPouria Mousavizadeh Tehrani 
324cdad5580SPouria Mousavizadeh Tehrani 		if (ACPI_FAILURE(acpi_GetInteger(sc->handle,
325cdad5580SPouria Mousavizadeh Tehrani 		    s76_sysctl_table[method].get_method, &ctrl->val))) {
326cdad5580SPouria Mousavizadeh Tehrani 			ctrl->exists = false;
327cdad5580SPouria Mousavizadeh Tehrani 			device_printf(sc->dev, "Driver can't control %s\n",
328cdad5580SPouria Mousavizadeh Tehrani 			    s76_sysctl_table[method].desc);
329cdad5580SPouria Mousavizadeh Tehrani 		} else {
330cdad5580SPouria Mousavizadeh Tehrani 			ctrl->exists = true;
331cdad5580SPouria Mousavizadeh Tehrani 			acpi_system76_update(sc, method, false);
332cdad5580SPouria Mousavizadeh Tehrani 		}
333cdad5580SPouria Mousavizadeh Tehrani 	}
334cdad5580SPouria Mousavizadeh Tehrani }
335cdad5580SPouria Mousavizadeh Tehrani 
336cdad5580SPouria Mousavizadeh Tehrani static void
acpi_system76_notify_handler(ACPI_HANDLE handle,uint32_t notify,void * ctx)337cdad5580SPouria Mousavizadeh Tehrani acpi_system76_notify_handler(ACPI_HANDLE handle, uint32_t notify, void *ctx)
338cdad5580SPouria Mousavizadeh Tehrani {
339cdad5580SPouria Mousavizadeh Tehrani 
340cdad5580SPouria Mousavizadeh Tehrani 	ACPI_FUNCTION_TRACE_U32((char *)(uintptr_t)__func__, notify);
341cdad5580SPouria Mousavizadeh Tehrani 
342cdad5580SPouria Mousavizadeh Tehrani 	switch (notify) {
343cdad5580SPouria Mousavizadeh Tehrani 	case ACPI_NOTIFY_BACKLIGHT_CHANGED:
344cdad5580SPouria Mousavizadeh Tehrani 	case ACPI_NOTIFY_COLOR_TOGGLE:
345cdad5580SPouria Mousavizadeh Tehrani 	case ACPI_NOTIFY_COLOR_DOWN:
346cdad5580SPouria Mousavizadeh Tehrani 	case ACPI_NOTIFY_COLOR_UP:
347cdad5580SPouria Mousavizadeh Tehrani 	case ACPI_NOTIFY_COLOR_CHANGED:
348cdad5580SPouria Mousavizadeh Tehrani 		AcpiOsExecute(OSL_NOTIFY_HANDLER,
349cdad5580SPouria Mousavizadeh Tehrani 		    acpi_system76_notify_update, ctx);
350cdad5580SPouria Mousavizadeh Tehrani 		break;
351cdad5580SPouria Mousavizadeh Tehrani 	default:
352cdad5580SPouria Mousavizadeh Tehrani 		break;
353cdad5580SPouria Mousavizadeh Tehrani 	}
354cdad5580SPouria Mousavizadeh Tehrani }
355cdad5580SPouria Mousavizadeh Tehrani 
356cdad5580SPouria Mousavizadeh Tehrani static int
acpi_system76_sysctl_handler(SYSCTL_HANDLER_ARGS)357cdad5580SPouria Mousavizadeh Tehrani acpi_system76_sysctl_handler(SYSCTL_HANDLER_ARGS)
358cdad5580SPouria Mousavizadeh Tehrani {
359f87ba452SPouria Mousavizadeh Tehrani 	struct acpi_ctrl *ctrl, *ctrl_cmp;
360cdad5580SPouria Mousavizadeh Tehrani 	struct acpi_system76_softc *sc;
361cdad5580SPouria Mousavizadeh Tehrani 	int val, method, error;
362f87ba452SPouria Mousavizadeh Tehrani 	bool update;
363cdad5580SPouria Mousavizadeh Tehrani 
364cdad5580SPouria Mousavizadeh Tehrani 	ACPI_FUNCTION_TRACE((char *)(uintptr_t)__func__);
365cdad5580SPouria Mousavizadeh Tehrani 
366cdad5580SPouria Mousavizadeh Tehrani 	sc = (struct acpi_system76_softc *)oidp->oid_arg1;
367cdad5580SPouria Mousavizadeh Tehrani 	method = oidp->oid_arg2;
368cdad5580SPouria Mousavizadeh Tehrani 	if ((ctrl = acpi_system76_ctrl_map(sc, method)) == NULL)
369cdad5580SPouria Mousavizadeh Tehrani 		return (EINVAL);
370cdad5580SPouria Mousavizadeh Tehrani 
371cdad5580SPouria Mousavizadeh Tehrani 	val = ctrl->val;
372cdad5580SPouria Mousavizadeh Tehrani 	error = sysctl_handle_int(oidp, &val, 0, req);
373cdad5580SPouria Mousavizadeh Tehrani 	if (error != 0) {
374cdad5580SPouria Mousavizadeh Tehrani 		device_printf(sc->dev, "Driver query failed\n");
375cdad5580SPouria Mousavizadeh Tehrani 		return (error);
376cdad5580SPouria Mousavizadeh Tehrani 	}
377cdad5580SPouria Mousavizadeh Tehrani 
378f87ba452SPouria Mousavizadeh Tehrani 	if (req->newptr == NULL) {
379f87ba452SPouria Mousavizadeh Tehrani 		/*
380*f9146417SPouria Mousavizadeh Tehrani 		 * ACPI will not notify us if battery thresholds changes
381f87ba452SPouria Mousavizadeh Tehrani 		 * outside this module. Therefore, always fetch those values.
382f87ba452SPouria Mousavizadeh Tehrani 		 */
383f87ba452SPouria Mousavizadeh Tehrani 		if (method != S76_CTRL_BCTL && method != S76_CTRL_BCTH)
384f87ba452SPouria Mousavizadeh Tehrani 			return (error);
385f87ba452SPouria Mousavizadeh Tehrani 		update = false;
386f87ba452SPouria Mousavizadeh Tehrani 	} else {
387cdad5580SPouria Mousavizadeh Tehrani 		/* Input validation */
388cdad5580SPouria Mousavizadeh Tehrani 		switch (method) {
389cdad5580SPouria Mousavizadeh Tehrani 		case S76_CTRL_KBB:
390cdad5580SPouria Mousavizadeh Tehrani 			if (val > UINT8_MAX || val < 0)
391cdad5580SPouria Mousavizadeh Tehrani 				return (EINVAL);
392105869a2SPouria Mousavizadeh Tehrani 			if (sc->kbb_bkl != NULL)
393105869a2SPouria Mousavizadeh Tehrani 				sc->backlight_level = devstate_to_backlight(val);
394cdad5580SPouria Mousavizadeh Tehrani 			break;
395cdad5580SPouria Mousavizadeh Tehrani 		case S76_CTRL_KBC:
396cdad5580SPouria Mousavizadeh Tehrani 			if (val >= (1 << 24) || val < 0)
397cdad5580SPouria Mousavizadeh Tehrani 				return (EINVAL);
398cdad5580SPouria Mousavizadeh Tehrani 			break;
399f87ba452SPouria Mousavizadeh Tehrani 		case S76_CTRL_BCTL:
400f87ba452SPouria Mousavizadeh Tehrani 			if ((ctrl_cmp = acpi_system76_ctrl_map(sc, S76_CTRL_BCTH)) == NULL)
401f87ba452SPouria Mousavizadeh Tehrani 				return (EINVAL);
402f87ba452SPouria Mousavizadeh Tehrani 			if (val > 100 || val < 0 || val >= ctrl_cmp->val)
403f87ba452SPouria Mousavizadeh Tehrani 				return (EINVAL);
404f87ba452SPouria Mousavizadeh Tehrani 			break;
405f87ba452SPouria Mousavizadeh Tehrani 		case S76_CTRL_BCTH:
406f87ba452SPouria Mousavizadeh Tehrani 			if ((ctrl_cmp = acpi_system76_ctrl_map(sc, S76_CTRL_BCTL)) == NULL)
407f87ba452SPouria Mousavizadeh Tehrani 				return (EINVAL);
408f87ba452SPouria Mousavizadeh Tehrani 			if (val > 100 || val < 0 || val <= ctrl_cmp->val)
409f87ba452SPouria Mousavizadeh Tehrani 				return (EINVAL);
410cdad5580SPouria Mousavizadeh Tehrani 			break;
411cdad5580SPouria Mousavizadeh Tehrani 		}
412cdad5580SPouria Mousavizadeh Tehrani 		ctrl->val = val;
413f87ba452SPouria Mousavizadeh Tehrani 		update = true;
414f87ba452SPouria Mousavizadeh Tehrani 	}
415cdad5580SPouria Mousavizadeh Tehrani 
416cdad5580SPouria Mousavizadeh Tehrani 	ACPI_SERIAL_BEGIN(system76);
417f87ba452SPouria Mousavizadeh Tehrani 	error = acpi_system76_update(sc, method, update);
418cdad5580SPouria Mousavizadeh Tehrani 	ACPI_SERIAL_END(system76);
419cdad5580SPouria Mousavizadeh Tehrani 	return (error);
420cdad5580SPouria Mousavizadeh Tehrani }
421cdad5580SPouria Mousavizadeh Tehrani 
422cdad5580SPouria Mousavizadeh Tehrani static void
acpi_system76_init(struct acpi_system76_softc * sc)423cdad5580SPouria Mousavizadeh Tehrani acpi_system76_init(struct acpi_system76_softc *sc)
424cdad5580SPouria Mousavizadeh Tehrani {
425cdad5580SPouria Mousavizadeh Tehrani 	struct acpi_softc *acpi_sc;
426cdad5580SPouria Mousavizadeh Tehrani 	struct acpi_ctrl *ctrl;
427cdad5580SPouria Mousavizadeh Tehrani 	uint32_t method;
428cdad5580SPouria Mousavizadeh Tehrani 
429cdad5580SPouria Mousavizadeh Tehrani 	ACPI_SERIAL_ASSERT(system76);
430cdad5580SPouria Mousavizadeh Tehrani 
431cdad5580SPouria Mousavizadeh Tehrani 	acpi_system76_check(sc);
432cdad5580SPouria Mousavizadeh Tehrani 	acpi_sc = acpi_device_get_parent_softc(sc->dev);
433cdad5580SPouria Mousavizadeh Tehrani 	sysctl_ctx_init(&sc->sysctl_ctx);
434cdad5580SPouria Mousavizadeh Tehrani 	sc->sysctl_tree = SYSCTL_ADD_NODE(&sc->sysctl_ctx,
435cdad5580SPouria Mousavizadeh Tehrani 	    SYSCTL_CHILDREN(acpi_sc->acpi_sysctl_tree), OID_AUTO, "s76",
436cdad5580SPouria Mousavizadeh Tehrani 	    CTLFLAG_RD | CTLFLAG_MPSAFE, 0, "system76 control");
437cdad5580SPouria Mousavizadeh Tehrani 
438cdad5580SPouria Mousavizadeh Tehrani 	for (method = 1; method < S76_CTRL_MAX; method++) {
439cdad5580SPouria Mousavizadeh Tehrani 		if ((ctrl = acpi_system76_ctrl_map(sc, method)) == NULL)
440cdad5580SPouria Mousavizadeh Tehrani 			continue;
441cdad5580SPouria Mousavizadeh Tehrani 
442cdad5580SPouria Mousavizadeh Tehrani 		if (!ctrl->exists)
443cdad5580SPouria Mousavizadeh Tehrani 			continue;
444cdad5580SPouria Mousavizadeh Tehrani 
445105869a2SPouria Mousavizadeh Tehrani 		if (method == S76_CTRL_KBB) {
446105869a2SPouria Mousavizadeh Tehrani 			sc->kbb_bkl = backlight_register("system76_keyboard", sc->dev);
447105869a2SPouria Mousavizadeh Tehrani 			if (sc->kbb_bkl == NULL)
448105869a2SPouria Mousavizadeh Tehrani 				device_printf(sc->dev, "Can not register backlight\n");
449105869a2SPouria Mousavizadeh Tehrani 			else
450105869a2SPouria Mousavizadeh Tehrani 				sc->backlight_level = devstate_to_backlight(sc->kbb.val);
451105869a2SPouria Mousavizadeh Tehrani 		}
452105869a2SPouria Mousavizadeh Tehrani 
453cdad5580SPouria Mousavizadeh Tehrani 		SYSCTL_ADD_PROC(&sc->sysctl_ctx,
454cdad5580SPouria Mousavizadeh Tehrani 		    SYSCTL_CHILDREN(sc->sysctl_tree), OID_AUTO, s76_sysctl_table[method].name,
455cdad5580SPouria Mousavizadeh Tehrani 		    CTLTYPE_UINT | CTLFLAG_RW | CTLFLAG_ANYBODY | CTLFLAG_MPSAFE,
456cdad5580SPouria Mousavizadeh Tehrani 		    sc, method, acpi_system76_sysctl_handler, "IU", s76_sysctl_table[method].desc);
457cdad5580SPouria Mousavizadeh Tehrani 	}
458cdad5580SPouria Mousavizadeh Tehrani }
459cdad5580SPouria Mousavizadeh Tehrani 
460cdad5580SPouria Mousavizadeh Tehrani static int
acpi_system76_backlight_update_status(device_t dev,struct backlight_props * props)461105869a2SPouria Mousavizadeh Tehrani acpi_system76_backlight_update_status(device_t dev, struct backlight_props
462105869a2SPouria Mousavizadeh Tehrani     *props)
463105869a2SPouria Mousavizadeh Tehrani {
464105869a2SPouria Mousavizadeh Tehrani 	struct acpi_system76_softc *sc;
465105869a2SPouria Mousavizadeh Tehrani 
466105869a2SPouria Mousavizadeh Tehrani 	sc = device_get_softc(dev);
467105869a2SPouria Mousavizadeh Tehrani 	if (sc->kbb.val != backlight_to_devstate(props->brightness)) {
468105869a2SPouria Mousavizadeh Tehrani 		sc->kbb.val = backlight_to_devstate(props->brightness);
469105869a2SPouria Mousavizadeh Tehrani 		acpi_system76_update(sc, S76_CTRL_KBB, true);
470105869a2SPouria Mousavizadeh Tehrani 	}
471105869a2SPouria Mousavizadeh Tehrani 	sc->backlight_level = props->brightness;
472105869a2SPouria Mousavizadeh Tehrani 
473105869a2SPouria Mousavizadeh Tehrani 	return (0);
474105869a2SPouria Mousavizadeh Tehrani }
475105869a2SPouria Mousavizadeh Tehrani 
476105869a2SPouria Mousavizadeh Tehrani static int
acpi_system76_backlight_get_status(device_t dev,struct backlight_props * props)477105869a2SPouria Mousavizadeh Tehrani acpi_system76_backlight_get_status(device_t dev, struct backlight_props *props)
478105869a2SPouria Mousavizadeh Tehrani {
479105869a2SPouria Mousavizadeh Tehrani 	struct acpi_system76_softc *sc;
480105869a2SPouria Mousavizadeh Tehrani 
481105869a2SPouria Mousavizadeh Tehrani 	sc = device_get_softc(dev);
482105869a2SPouria Mousavizadeh Tehrani 	props->brightness = sc->backlight_level;
483105869a2SPouria Mousavizadeh Tehrani 	props->nlevels = nitems(acpi_system76_backlight_levels);
484105869a2SPouria Mousavizadeh Tehrani 	memcpy(props->levels, acpi_system76_backlight_levels,
485105869a2SPouria Mousavizadeh Tehrani 	    sizeof(acpi_system76_backlight_levels));
486105869a2SPouria Mousavizadeh Tehrani 
487105869a2SPouria Mousavizadeh Tehrani         return (0);
488105869a2SPouria Mousavizadeh Tehrani }
489105869a2SPouria Mousavizadeh Tehrani 
490105869a2SPouria Mousavizadeh Tehrani static int
acpi_system76_backlight_get_info(device_t dev,struct backlight_info * info)491105869a2SPouria Mousavizadeh Tehrani acpi_system76_backlight_get_info(device_t dev, struct backlight_info *info)
492105869a2SPouria Mousavizadeh Tehrani {
493105869a2SPouria Mousavizadeh Tehrani         info->type = BACKLIGHT_TYPE_KEYBOARD;
494105869a2SPouria Mousavizadeh Tehrani         strlcpy(info->name, "System76 Keyboard", BACKLIGHTMAXNAMELENGTH);
495105869a2SPouria Mousavizadeh Tehrani 
496105869a2SPouria Mousavizadeh Tehrani         return (0);
497105869a2SPouria Mousavizadeh Tehrani }
498105869a2SPouria Mousavizadeh Tehrani 
499105869a2SPouria Mousavizadeh Tehrani static int
acpi_system76_attach(device_t dev)500cdad5580SPouria Mousavizadeh Tehrani acpi_system76_attach(device_t dev)
501cdad5580SPouria Mousavizadeh Tehrani {
502cdad5580SPouria Mousavizadeh Tehrani 	struct acpi_system76_softc *sc;
503cdad5580SPouria Mousavizadeh Tehrani 
504cdad5580SPouria Mousavizadeh Tehrani 	ACPI_FUNCTION_TRACE((char *)(uintptr_t)__func__);
505cdad5580SPouria Mousavizadeh Tehrani 
506cdad5580SPouria Mousavizadeh Tehrani 	sc = device_get_softc(dev);
507cdad5580SPouria Mousavizadeh Tehrani 	sc->dev = dev;
508cdad5580SPouria Mousavizadeh Tehrani 	sc->handle = acpi_get_handle(dev);
509cdad5580SPouria Mousavizadeh Tehrani 
510cdad5580SPouria Mousavizadeh Tehrani 	AcpiInstallNotifyHandler(sc->handle, ACPI_DEVICE_NOTIFY,
511cdad5580SPouria Mousavizadeh Tehrani 	    acpi_system76_notify_handler, dev);
512cdad5580SPouria Mousavizadeh Tehrani 
513cdad5580SPouria Mousavizadeh Tehrani 	ACPI_SERIAL_BEGIN(system76);
514cdad5580SPouria Mousavizadeh Tehrani 	acpi_system76_init(sc);
515cdad5580SPouria Mousavizadeh Tehrani 	ACPI_SERIAL_END(system76);
516cdad5580SPouria Mousavizadeh Tehrani 
517cdad5580SPouria Mousavizadeh Tehrani 	return (0);
518cdad5580SPouria Mousavizadeh Tehrani }
519cdad5580SPouria Mousavizadeh Tehrani 
520cdad5580SPouria Mousavizadeh Tehrani static int
acpi_system76_detach(device_t dev)521cdad5580SPouria Mousavizadeh Tehrani acpi_system76_detach(device_t dev)
522cdad5580SPouria Mousavizadeh Tehrani {
523cdad5580SPouria Mousavizadeh Tehrani 	struct acpi_system76_softc *sc;
524cdad5580SPouria Mousavizadeh Tehrani 
525cdad5580SPouria Mousavizadeh Tehrani 	sc = device_get_softc(dev);
526cdad5580SPouria Mousavizadeh Tehrani 	if (sysctl_ctx_free(&sc->sysctl_ctx) != 0)
527cdad5580SPouria Mousavizadeh Tehrani 		return (EBUSY);
528cdad5580SPouria Mousavizadeh Tehrani 
529105869a2SPouria Mousavizadeh Tehrani 	AcpiRemoveNotifyHandler(sc->handle, ACPI_SYSTEM_NOTIFY,
530105869a2SPouria Mousavizadeh Tehrani 	    acpi_system76_notify_handler);
531105869a2SPouria Mousavizadeh Tehrani 
532105869a2SPouria Mousavizadeh Tehrani 	if (sc->kbb_bkl != NULL)
533105869a2SPouria Mousavizadeh Tehrani 		backlight_destroy(sc->kbb_bkl);
534105869a2SPouria Mousavizadeh Tehrani 
535cdad5580SPouria Mousavizadeh Tehrani 	return (0);
536cdad5580SPouria Mousavizadeh Tehrani }
537cdad5580SPouria Mousavizadeh Tehrani 
538cdad5580SPouria Mousavizadeh Tehrani static int
acpi_system76_suspend(device_t dev)539105869a2SPouria Mousavizadeh Tehrani acpi_system76_suspend(device_t dev)
540105869a2SPouria Mousavizadeh Tehrani {
541105869a2SPouria Mousavizadeh Tehrani 	struct acpi_system76_softc *sc;
542105869a2SPouria Mousavizadeh Tehrani 	struct acpi_ctrl *ctrl;
543105869a2SPouria Mousavizadeh Tehrani 
544105869a2SPouria Mousavizadeh Tehrani 	sc = device_get_softc(dev);
545105869a2SPouria Mousavizadeh Tehrani 	if ((ctrl = acpi_system76_ctrl_map(sc, S76_CTRL_KBB)) != NULL) {
546105869a2SPouria Mousavizadeh Tehrani 		ctrl->val = 0;
547105869a2SPouria Mousavizadeh Tehrani 		acpi_system76_update(sc, S76_CTRL_KBB, true);
548105869a2SPouria Mousavizadeh Tehrani 	}
549105869a2SPouria Mousavizadeh Tehrani 
550105869a2SPouria Mousavizadeh Tehrani 	return (0);
551105869a2SPouria Mousavizadeh Tehrani }
552105869a2SPouria Mousavizadeh Tehrani 
553105869a2SPouria Mousavizadeh Tehrani static int
acpi_system76_resume(device_t dev)554105869a2SPouria Mousavizadeh Tehrani acpi_system76_resume(device_t dev)
555105869a2SPouria Mousavizadeh Tehrani {
556105869a2SPouria Mousavizadeh Tehrani 	struct acpi_system76_softc *sc;
557105869a2SPouria Mousavizadeh Tehrani 	struct acpi_ctrl *ctrl;
558105869a2SPouria Mousavizadeh Tehrani 
559105869a2SPouria Mousavizadeh Tehrani 	sc = device_get_softc(dev);
560105869a2SPouria Mousavizadeh Tehrani 	if ((ctrl = acpi_system76_ctrl_map(sc, S76_CTRL_KBB)) != NULL) {
561105869a2SPouria Mousavizadeh Tehrani 		ctrl->val = backlight_to_devstate(sc->backlight_level);
562105869a2SPouria Mousavizadeh Tehrani 		acpi_system76_update(sc, S76_CTRL_KBB, true);
563105869a2SPouria Mousavizadeh Tehrani 	}
564105869a2SPouria Mousavizadeh Tehrani 
565105869a2SPouria Mousavizadeh Tehrani 	return (0);
566105869a2SPouria Mousavizadeh Tehrani }
567105869a2SPouria Mousavizadeh Tehrani 
568105869a2SPouria Mousavizadeh Tehrani static int
acpi_system76_shutdown(device_t dev)569105869a2SPouria Mousavizadeh Tehrani acpi_system76_shutdown(device_t dev)
570105869a2SPouria Mousavizadeh Tehrani {
571105869a2SPouria Mousavizadeh Tehrani 	return (acpi_system76_detach(dev));
572105869a2SPouria Mousavizadeh Tehrani }
573105869a2SPouria Mousavizadeh Tehrani 
574105869a2SPouria Mousavizadeh Tehrani static int
acpi_system76_probe(device_t dev)575cdad5580SPouria Mousavizadeh Tehrani acpi_system76_probe(device_t dev)
576cdad5580SPouria Mousavizadeh Tehrani {
577cdad5580SPouria Mousavizadeh Tehrani 	int rv;
578cdad5580SPouria Mousavizadeh Tehrani 
579cdad5580SPouria Mousavizadeh Tehrani 	if (acpi_disabled("system76") || device_get_unit(dev) > 1)
580cdad5580SPouria Mousavizadeh Tehrani 		return (ENXIO);
581cdad5580SPouria Mousavizadeh Tehrani 	rv = ACPI_ID_PROBE(device_get_parent(dev), dev, system76_ids, NULL);
582cdad5580SPouria Mousavizadeh Tehrani 	if (rv > 0) {
583cdad5580SPouria Mousavizadeh Tehrani 		return (rv);
584cdad5580SPouria Mousavizadeh Tehrani 	}
585cdad5580SPouria Mousavizadeh Tehrani 
586cdad5580SPouria Mousavizadeh Tehrani 	return (BUS_PROBE_VENDOR);
587cdad5580SPouria Mousavizadeh Tehrani }
588cdad5580SPouria Mousavizadeh Tehrani 
589cdad5580SPouria Mousavizadeh Tehrani DRIVER_MODULE(acpi_system76, acpi, acpi_system76_driver, 0, 0);
590cdad5580SPouria Mousavizadeh Tehrani MODULE_VERSION(acpi_system76, 1);
591cdad5580SPouria Mousavizadeh Tehrani MODULE_DEPEND(acpi_system76, acpi, 1, 1, 1);
592105869a2SPouria Mousavizadeh Tehrani MODULE_DEPEND(acpi_system76, backlight, 1, 1, 1);
593