xref: /freebsd/sys/dev/acpi_support/acpi_panasonic.c (revision 90161e72eecd463919898b4e9c1e29dbeabe139d)
1ee6020c9SYoshihiro Takahashi /*-
2ee6020c9SYoshihiro Takahashi  * Copyright (c) 2003 OGAWA Takaya <t-ogawa@triaez.kaisei.org>
3914ee8baSYoshihiro Takahashi  * Copyright (c) 2004 TAKAHASHI Yoshihiro <nyan@FreeBSD.org>
4ee6020c9SYoshihiro Takahashi  * All rights Reserved.
5ee6020c9SYoshihiro Takahashi  *
6ee6020c9SYoshihiro Takahashi  * Redistribution and use in source and binary forms, with or without
7ee6020c9SYoshihiro Takahashi  * modification, are permitted provided that the following conditions
8ee6020c9SYoshihiro Takahashi  * are met:
9ee6020c9SYoshihiro Takahashi  * 1. Redistributions of source code must retain the above copyright
10ee6020c9SYoshihiro Takahashi  *    notice, this list of conditions and the following disclaimer.
11ee6020c9SYoshihiro Takahashi  * 2. Redistributions in binary form must reproduce the above copyright
12ee6020c9SYoshihiro Takahashi  *    notice, this list of conditions and the following disclaimer in the
13ee6020c9SYoshihiro Takahashi  *    documentation and/or other materials provided with the distribution.
14ee6020c9SYoshihiro Takahashi  *
15ee6020c9SYoshihiro Takahashi  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
16ee6020c9SYoshihiro Takahashi  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17ee6020c9SYoshihiro Takahashi  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18ee6020c9SYoshihiro Takahashi  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
19ee6020c9SYoshihiro Takahashi  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20ee6020c9SYoshihiro Takahashi  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
21ee6020c9SYoshihiro Takahashi  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22ee6020c9SYoshihiro Takahashi  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
23ee6020c9SYoshihiro Takahashi  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24ee6020c9SYoshihiro Takahashi  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
25ee6020c9SYoshihiro Takahashi  * SUCH DAMAGE.
26ee6020c9SYoshihiro Takahashi  *
27ee6020c9SYoshihiro Takahashi  */
28ee6020c9SYoshihiro Takahashi 
29ee6020c9SYoshihiro Takahashi #include <sys/cdefs.h>
30ee6020c9SYoshihiro Takahashi __FBSDID("$FreeBSD$");
31ee6020c9SYoshihiro Takahashi 
32ee6020c9SYoshihiro Takahashi #include "opt_acpi.h"
33ee6020c9SYoshihiro Takahashi #include <sys/param.h>
34e2e050c8SConrad Meyer #include <sys/bus.h>
35e2e050c8SConrad Meyer #include <sys/eventhandler.h>
36ee6020c9SYoshihiro Takahashi #include <sys/kernel.h>
37ee6020c9SYoshihiro Takahashi #include <sys/malloc.h>
38ee6020c9SYoshihiro Takahashi #include <sys/module.h>
39f3118682SNate Lawson #include <sys/power.h>
40ee6020c9SYoshihiro Takahashi 
41129d3046SJung-uk Kim #include <contrib/dev/acpica/include/acpi.h>
42129d3046SJung-uk Kim 
43ee6020c9SYoshihiro Takahashi #include <dev/acpica/acpivar.h>
44ee6020c9SYoshihiro Takahashi 
45276cd921SNate Lawson #define _COMPONENT	ACPI_OEM
46276cd921SNate Lawson ACPI_MODULE_NAME("Panasonic")
47276cd921SNate Lawson 
48ee6020c9SYoshihiro Takahashi /* Debug */
49ee6020c9SYoshihiro Takahashi #undef	ACPI_PANASONIC_DEBUG
50ee6020c9SYoshihiro Takahashi 
51ee6020c9SYoshihiro Takahashi /* Operations */
52ee6020c9SYoshihiro Takahashi #define	HKEY_SET	0
53ee6020c9SYoshihiro Takahashi #define	HKEY_GET	1
54ee6020c9SYoshihiro Takahashi 
55ee6020c9SYoshihiro Takahashi /* Functions */
56f3118682SNate Lawson #define	HKEY_REG_LCD_BRIGHTNESS_MAX_AC	0x02
57f3118682SNate Lawson #define	HKEY_REG_LCD_BRIGHTNESS_MIN_AC	0x03
58f3118682SNate Lawson #define	HKEY_REG_LCD_BRIGHTNESS_AC	0x04
59f3118682SNate Lawson #define	HKEY_REG_LCD_BRIGHTNESS_MAX_DC	0x05
60f3118682SNate Lawson #define	HKEY_REG_LCD_BRIGHTNESS_MIN_DC	0x06
61f3118682SNate Lawson #define	HKEY_REG_LCD_BRIGHTNESS_DC	0x07
62ee6020c9SYoshihiro Takahashi #define	HKEY_REG_SOUND_MUTE		0x08
63ee6020c9SYoshihiro Takahashi 
64ee6020c9SYoshihiro Takahashi /* Field definitions */
65ee6020c9SYoshihiro Takahashi #define	HKEY_LCD_BRIGHTNESS_BITS	4
66ee6020c9SYoshihiro Takahashi #define	HKEY_LCD_BRIGHTNESS_DIV		((1 << HKEY_LCD_BRIGHTNESS_BITS) - 1)
67ee6020c9SYoshihiro Takahashi 
68ee6020c9SYoshihiro Takahashi struct acpi_panasonic_softc {
69ee6020c9SYoshihiro Takahashi 	device_t	dev;
70ee6020c9SYoshihiro Takahashi 	ACPI_HANDLE	handle;
71ee6020c9SYoshihiro Takahashi 
72ee6020c9SYoshihiro Takahashi 	struct sysctl_ctx_list	sysctl_ctx;
73ee6020c9SYoshihiro Takahashi 	struct sysctl_oid	*sysctl_tree;
74f3118682SNate Lawson 
75f3118682SNate Lawson 	eventhandler_tag	power_evh;
76ee6020c9SYoshihiro Takahashi };
77ee6020c9SYoshihiro Takahashi 
78ee6020c9SYoshihiro Takahashi /* Prototype for HKEY functions for getting/setting a value. */
79ee6020c9SYoshihiro Takahashi typedef int hkey_fn_t(ACPI_HANDLE, int, UINT32 *);
80ee6020c9SYoshihiro Takahashi 
81ee6020c9SYoshihiro Takahashi static int	acpi_panasonic_probe(device_t dev);
82ee6020c9SYoshihiro Takahashi static int	acpi_panasonic_attach(device_t dev);
83ee6020c9SYoshihiro Takahashi static int	acpi_panasonic_detach(device_t dev);
84e3545bccSWarner Losh static int	acpi_panasonic_shutdown(device_t dev);
85ee6020c9SYoshihiro Takahashi static int	acpi_panasonic_sysctl(SYSCTL_HANDLER_ARGS);
869a179dd8SJung-uk Kim static UINT64	acpi_panasonic_sinf(ACPI_HANDLE h, UINT64 index);
879a179dd8SJung-uk Kim static void	acpi_panasonic_sset(ACPI_HANDLE h, UINT64 index,
889a179dd8SJung-uk Kim 		    UINT64 val);
89ee6020c9SYoshihiro Takahashi static int	acpi_panasonic_hkey_event(struct acpi_panasonic_softc *sc,
90ee6020c9SYoshihiro Takahashi 		    ACPI_HANDLE h, UINT32 *arg);
91ee6020c9SYoshihiro Takahashi static void	acpi_panasonic_hkey_action(struct acpi_panasonic_softc *sc,
92ee6020c9SYoshihiro Takahashi 		    ACPI_HANDLE h, UINT32 key);
93ee6020c9SYoshihiro Takahashi static void	acpi_panasonic_notify(ACPI_HANDLE h, UINT32 notify,
94ee6020c9SYoshihiro Takahashi 		    void *context);
95f3118682SNate Lawson static void	acpi_panasonic_power_profile(void *arg);
96ee6020c9SYoshihiro Takahashi 
97be223480SNate Lawson static hkey_fn_t	hkey_lcd_brightness_max;
98f3118682SNate Lawson static hkey_fn_t	hkey_lcd_brightness_min;
99be223480SNate Lawson static hkey_fn_t	hkey_lcd_brightness;
100be223480SNate Lawson static hkey_fn_t	hkey_sound_mute;
101e8a162f4SNate Lawson ACPI_SERIAL_DECL(panasonic, "ACPI Panasonic extras");
102be223480SNate Lawson 
103ee6020c9SYoshihiro Takahashi /* Table of sysctl names and HKEY functions to call. */
104ee6020c9SYoshihiro Takahashi static struct {
105ee6020c9SYoshihiro Takahashi 	char		*name;
106ee6020c9SYoshihiro Takahashi 	hkey_fn_t	*handler;
107ee6020c9SYoshihiro Takahashi } sysctl_table[] = {
108ee6020c9SYoshihiro Takahashi 	/* name,		handler */
109ee6020c9SYoshihiro Takahashi 	{"lcd_brightness_max",	hkey_lcd_brightness_max},
110f3118682SNate Lawson 	{"lcd_brightness_min",	hkey_lcd_brightness_min},
111ee6020c9SYoshihiro Takahashi 	{"lcd_brightness",	hkey_lcd_brightness},
112ee6020c9SYoshihiro Takahashi 	{"sound_mute",		hkey_sound_mute},
113ee6020c9SYoshihiro Takahashi 	{NULL, NULL}
114ee6020c9SYoshihiro Takahashi };
115ee6020c9SYoshihiro Takahashi 
116ee6020c9SYoshihiro Takahashi static device_method_t acpi_panasonic_methods[] = {
117ee6020c9SYoshihiro Takahashi 	DEVMETHOD(device_probe,		acpi_panasonic_probe),
118ee6020c9SYoshihiro Takahashi 	DEVMETHOD(device_attach,	acpi_panasonic_attach),
119ee6020c9SYoshihiro Takahashi 	DEVMETHOD(device_detach,	acpi_panasonic_detach),
120bb05b80cSNate Lawson 	DEVMETHOD(device_shutdown,	acpi_panasonic_shutdown),
121ee6020c9SYoshihiro Takahashi 
12261bfd867SSofian Brabez 	DEVMETHOD_END
123ee6020c9SYoshihiro Takahashi };
124ee6020c9SYoshihiro Takahashi 
125ee6020c9SYoshihiro Takahashi static driver_t acpi_panasonic_driver = {
126ee6020c9SYoshihiro Takahashi 	"acpi_panasonic",
127ee6020c9SYoshihiro Takahashi 	acpi_panasonic_methods,
128ee6020c9SYoshihiro Takahashi 	sizeof(struct acpi_panasonic_softc),
129ee6020c9SYoshihiro Takahashi };
130ee6020c9SYoshihiro Takahashi 
131*90161e72SJohn Baldwin DRIVER_MODULE(acpi_panasonic, acpi, acpi_panasonic_driver, 0, 0);
132ee6020c9SYoshihiro Takahashi MODULE_DEPEND(acpi_panasonic, acpi, 1, 1, 1);
133ee6020c9SYoshihiro Takahashi 
134ee6020c9SYoshihiro Takahashi static int
135ee6020c9SYoshihiro Takahashi acpi_panasonic_probe(device_t dev)
136ee6020c9SYoshihiro Takahashi {
137ee6020c9SYoshihiro Takahashi 	static char *mat_ids[] = { "MAT0019", NULL };
1385efca36fSTakanori Watanabe 	int rv;
139ee6020c9SYoshihiro Takahashi 
140ee6020c9SYoshihiro Takahashi 	if (acpi_disabled("panasonic") ||
141ee6020c9SYoshihiro Takahashi 	    device_get_unit(dev) != 0)
142ee6020c9SYoshihiro Takahashi 		return (ENXIO);
1435efca36fSTakanori Watanabe 	rv = ACPI_ID_PROBE(device_get_parent(dev), dev, mat_ids, NULL);
144ee6020c9SYoshihiro Takahashi 
1455efca36fSTakanori Watanabe 	if (rv <= 0)
146ee6020c9SYoshihiro Takahashi 		device_set_desc(dev, "Panasonic Notebook Hotkeys");
1475efca36fSTakanori Watanabe 	return (rv);
148ee6020c9SYoshihiro Takahashi }
149ee6020c9SYoshihiro Takahashi 
150ee6020c9SYoshihiro Takahashi static int
151ee6020c9SYoshihiro Takahashi acpi_panasonic_attach(device_t dev)
152ee6020c9SYoshihiro Takahashi {
153ee6020c9SYoshihiro Takahashi 	struct acpi_panasonic_softc *sc;
154ee6020c9SYoshihiro Takahashi 	struct acpi_softc *acpi_sc;
155ee6020c9SYoshihiro Takahashi 	ACPI_STATUS status;
156ee6020c9SYoshihiro Takahashi 	int i;
157ee6020c9SYoshihiro Takahashi 
158ee6020c9SYoshihiro Takahashi 	sc = device_get_softc(dev);
159ee6020c9SYoshihiro Takahashi 	sc->dev = dev;
160ee6020c9SYoshihiro Takahashi 	sc->handle = acpi_get_handle(dev);
161ee6020c9SYoshihiro Takahashi 
162ee6020c9SYoshihiro Takahashi 	acpi_sc = acpi_device_get_parent_softc(dev);
163ee6020c9SYoshihiro Takahashi 
164ee6020c9SYoshihiro Takahashi 	/* Build sysctl tree */
165ee6020c9SYoshihiro Takahashi 	sysctl_ctx_init(&sc->sysctl_ctx);
166ee6020c9SYoshihiro Takahashi 	sc->sysctl_tree = SYSCTL_ADD_NODE(&sc->sysctl_ctx,
167ee6020c9SYoshihiro Takahashi 	    SYSCTL_CHILDREN(acpi_sc->acpi_sysctl_tree), OID_AUTO,
1687029da5cSPawel Biernacki 	    "panasonic", CTLFLAG_RD | CTLFLAG_MPSAFE, 0, "");
169ee6020c9SYoshihiro Takahashi 	for (i = 0; sysctl_table[i].name != NULL; i++) {
170ee6020c9SYoshihiro Takahashi 		SYSCTL_ADD_PROC(&sc->sysctl_ctx,
171ee6020c9SYoshihiro Takahashi 		    SYSCTL_CHILDREN(sc->sysctl_tree), OID_AUTO,
172ee6020c9SYoshihiro Takahashi 		    sysctl_table[i].name,
1737029da5cSPawel Biernacki 		    CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_ANYBODY |
1746237a1ccSAlexander Motin 		    CTLFLAG_MPSAFE, sc, i, acpi_panasonic_sysctl, "I", "");
175ee6020c9SYoshihiro Takahashi 	}
176ee6020c9SYoshihiro Takahashi 
177ee6020c9SYoshihiro Takahashi #if 0
178ee6020c9SYoshihiro Takahashi 	/* Activate hotkeys */
179ee6020c9SYoshihiro Takahashi 	status = AcpiEvaluateObject(sc->handle, "", NULL, NULL);
180ee6020c9SYoshihiro Takahashi 	if (ACPI_FAILURE(status)) {
181ee6020c9SYoshihiro Takahashi 		device_printf(dev, "enable FN keys failed\n");
182ee6020c9SYoshihiro Takahashi 		sysctl_ctx_free(&sc->sysctl_ctx);
183ee6020c9SYoshihiro Takahashi 		return (ENXIO);
184ee6020c9SYoshihiro Takahashi 	}
185ee6020c9SYoshihiro Takahashi #endif
186ee6020c9SYoshihiro Takahashi 
187ee6020c9SYoshihiro Takahashi 	/* Handle notifies */
188ee6020c9SYoshihiro Takahashi 	status = AcpiInstallNotifyHandler(sc->handle, ACPI_DEVICE_NOTIFY,
189ee6020c9SYoshihiro Takahashi 	    acpi_panasonic_notify, sc);
190ee6020c9SYoshihiro Takahashi 	if (ACPI_FAILURE(status)) {
191ee6020c9SYoshihiro Takahashi 		device_printf(dev, "couldn't install notify handler - %s\n",
192ee6020c9SYoshihiro Takahashi 		    AcpiFormatException(status));
193ee6020c9SYoshihiro Takahashi 		sysctl_ctx_free(&sc->sysctl_ctx);
194ee6020c9SYoshihiro Takahashi 		return (ENXIO);
195ee6020c9SYoshihiro Takahashi 	}
196ee6020c9SYoshihiro Takahashi 
197f3118682SNate Lawson 	/* Install power profile event handler */
198f3118682SNate Lawson 	sc->power_evh = EVENTHANDLER_REGISTER(power_profile_change,
199f3118682SNate Lawson 	    acpi_panasonic_power_profile, sc->handle, 0);
200f3118682SNate Lawson 
201ee6020c9SYoshihiro Takahashi 	return (0);
202ee6020c9SYoshihiro Takahashi }
203ee6020c9SYoshihiro Takahashi 
204ee6020c9SYoshihiro Takahashi static int
205ee6020c9SYoshihiro Takahashi acpi_panasonic_detach(device_t dev)
206ee6020c9SYoshihiro Takahashi {
207ee6020c9SYoshihiro Takahashi 	struct acpi_panasonic_softc *sc;
208ee6020c9SYoshihiro Takahashi 
209ee6020c9SYoshihiro Takahashi 	sc = device_get_softc(dev);
210ee6020c9SYoshihiro Takahashi 
211f3118682SNate Lawson 	/* Remove power profile event handler */
212f3118682SNate Lawson 	EVENTHANDLER_DEREGISTER(power_profile_change, sc->power_evh);
213f3118682SNate Lawson 
214ee6020c9SYoshihiro Takahashi 	/* Remove notify handler */
215ee6020c9SYoshihiro Takahashi 	AcpiRemoveNotifyHandler(sc->handle, ACPI_DEVICE_NOTIFY,
216ee6020c9SYoshihiro Takahashi 	    acpi_panasonic_notify);
217ee6020c9SYoshihiro Takahashi 
218ee6020c9SYoshihiro Takahashi 	/* Free sysctl tree */
219ee6020c9SYoshihiro Takahashi 	sysctl_ctx_free(&sc->sysctl_ctx);
220ee6020c9SYoshihiro Takahashi 
221ee6020c9SYoshihiro Takahashi 	return (0);
222ee6020c9SYoshihiro Takahashi }
223ee6020c9SYoshihiro Takahashi 
224e3545bccSWarner Losh static int
225bb05b80cSNate Lawson acpi_panasonic_shutdown(device_t dev)
226bb05b80cSNate Lawson {
227bb05b80cSNate Lawson 	struct acpi_panasonic_softc *sc;
228bb05b80cSNate Lawson 	int mute;
229bb05b80cSNate Lawson 
230bb05b80cSNate Lawson 	/* Mute the main audio during reboot to prevent static burst to speaker. */
231bb05b80cSNate Lawson 	sc = device_get_softc(dev);
232bb05b80cSNate Lawson 	mute = 1;
233bb05b80cSNate Lawson 	hkey_sound_mute(sc->handle, HKEY_SET, &mute);
234e3545bccSWarner Losh 	return (0);
235bb05b80cSNate Lawson }
236bb05b80cSNate Lawson 
237ee6020c9SYoshihiro Takahashi static int
238ee6020c9SYoshihiro Takahashi acpi_panasonic_sysctl(SYSCTL_HANDLER_ARGS)
239ee6020c9SYoshihiro Takahashi {
240ee6020c9SYoshihiro Takahashi 	struct acpi_panasonic_softc *sc;
241ee6020c9SYoshihiro Takahashi 	UINT32 arg;
242ee6020c9SYoshihiro Takahashi 	int function, error;
243ee6020c9SYoshihiro Takahashi 	hkey_fn_t *handler;
244ee6020c9SYoshihiro Takahashi 
245ee6020c9SYoshihiro Takahashi 	sc = (struct acpi_panasonic_softc *)oidp->oid_arg1;
246ee6020c9SYoshihiro Takahashi 	function = oidp->oid_arg2;
247ee6020c9SYoshihiro Takahashi 	handler = sysctl_table[function].handler;
248ee6020c9SYoshihiro Takahashi 
249ee6020c9SYoshihiro Takahashi 	/* Get the current value from the appropriate function. */
250e8a162f4SNate Lawson 	ACPI_SERIAL_BEGIN(panasonic);
251ee6020c9SYoshihiro Takahashi 	error = handler(sc->handle, HKEY_GET, &arg);
252ee6020c9SYoshihiro Takahashi 	if (error != 0)
253e8a162f4SNate Lawson 		goto out;
254ee6020c9SYoshihiro Takahashi 
255ee6020c9SYoshihiro Takahashi 	/* Send the current value to the user and return if no new value. */
256ee6020c9SYoshihiro Takahashi 	error = sysctl_handle_int(oidp, &arg, 0, req);
257ee6020c9SYoshihiro Takahashi 	if (error != 0 || req->newptr == NULL)
258e8a162f4SNate Lawson 		goto out;
259ee6020c9SYoshihiro Takahashi 
260ee6020c9SYoshihiro Takahashi 	/* Set the new value via the appropriate function. */
261ee6020c9SYoshihiro Takahashi 	error = handler(sc->handle, HKEY_SET, &arg);
262ee6020c9SYoshihiro Takahashi 
263e8a162f4SNate Lawson out:
2649f65aa03SNate Lawson 	ACPI_SERIAL_END(panasonic);
265ee6020c9SYoshihiro Takahashi 	return (error);
266ee6020c9SYoshihiro Takahashi }
267ee6020c9SYoshihiro Takahashi 
2689a179dd8SJung-uk Kim static UINT64
2699a179dd8SJung-uk Kim acpi_panasonic_sinf(ACPI_HANDLE h, UINT64 index)
270ee6020c9SYoshihiro Takahashi {
271ee6020c9SYoshihiro Takahashi 	ACPI_BUFFER buf;
272ee6020c9SYoshihiro Takahashi 	ACPI_OBJECT *res;
2739a179dd8SJung-uk Kim 	UINT64 ret;
274ee6020c9SYoshihiro Takahashi 
275e8a162f4SNate Lawson 	ACPI_SERIAL_ASSERT(panasonic);
276ee6020c9SYoshihiro Takahashi 	ret = -1;
277ee6020c9SYoshihiro Takahashi 	buf.Length = ACPI_ALLOCATE_BUFFER;
278ee6020c9SYoshihiro Takahashi 	buf.Pointer = NULL;
279ee6020c9SYoshihiro Takahashi 	AcpiEvaluateObject(h, "SINF", NULL, &buf);
280ee6020c9SYoshihiro Takahashi 	res = (ACPI_OBJECT *)buf.Pointer;
281ee6020c9SYoshihiro Takahashi 	if (res->Type == ACPI_TYPE_PACKAGE)
282ee6020c9SYoshihiro Takahashi 		ret = res->Package.Elements[index].Integer.Value;
283ee6020c9SYoshihiro Takahashi 	AcpiOsFree(buf.Pointer);
284ee6020c9SYoshihiro Takahashi 
285ee6020c9SYoshihiro Takahashi 	return (ret);
286ee6020c9SYoshihiro Takahashi }
287ee6020c9SYoshihiro Takahashi 
288ee6020c9SYoshihiro Takahashi static void
2899a179dd8SJung-uk Kim acpi_panasonic_sset(ACPI_HANDLE h, UINT64 index, UINT64 val)
290ee6020c9SYoshihiro Takahashi {
291ee6020c9SYoshihiro Takahashi 	ACPI_OBJECT_LIST args;
292ee6020c9SYoshihiro Takahashi 	ACPI_OBJECT obj[2];
293ee6020c9SYoshihiro Takahashi 
294e8a162f4SNate Lawson 	ACPI_SERIAL_ASSERT(panasonic);
295ee6020c9SYoshihiro Takahashi 	obj[0].Type = ACPI_TYPE_INTEGER;
296ee6020c9SYoshihiro Takahashi 	obj[0].Integer.Value = index;
297ee6020c9SYoshihiro Takahashi 	obj[1].Type = ACPI_TYPE_INTEGER;
298ee6020c9SYoshihiro Takahashi 	obj[1].Integer.Value = val;
299ee6020c9SYoshihiro Takahashi 	args.Count = 2;
300ee6020c9SYoshihiro Takahashi 	args.Pointer = obj;
301ee6020c9SYoshihiro Takahashi 	AcpiEvaluateObject(h, "SSET", &args, NULL);
302ee6020c9SYoshihiro Takahashi }
303ee6020c9SYoshihiro Takahashi 
304ee6020c9SYoshihiro Takahashi static int
305ee6020c9SYoshihiro Takahashi hkey_lcd_brightness_max(ACPI_HANDLE h, int op, UINT32 *val)
306ee6020c9SYoshihiro Takahashi {
307f3118682SNate Lawson 	int reg;
308ee6020c9SYoshihiro Takahashi 
309e8a162f4SNate Lawson 	ACPI_SERIAL_ASSERT(panasonic);
310f3118682SNate Lawson 	reg = (power_profile_get_state() == POWER_PROFILE_PERFORMANCE) ?
311f3118682SNate Lawson 	    HKEY_REG_LCD_BRIGHTNESS_MAX_AC : HKEY_REG_LCD_BRIGHTNESS_MAX_DC;
312f3118682SNate Lawson 
313ee6020c9SYoshihiro Takahashi 	switch (op) {
314ee6020c9SYoshihiro Takahashi 	case HKEY_SET:
315f3118682SNate Lawson 		return (EPERM);
316ee6020c9SYoshihiro Takahashi 		break;
317ee6020c9SYoshihiro Takahashi 	case HKEY_GET:
318f3118682SNate Lawson 		*val = acpi_panasonic_sinf(h, reg);
319f3118682SNate Lawson 		break;
320f3118682SNate Lawson 	}
321f3118682SNate Lawson 
322f3118682SNate Lawson 	return (0);
323f3118682SNate Lawson }
324f3118682SNate Lawson 
325f3118682SNate Lawson static int
326f3118682SNate Lawson hkey_lcd_brightness_min(ACPI_HANDLE h, int op, UINT32 *val)
327f3118682SNate Lawson {
328f3118682SNate Lawson 	int reg;
329f3118682SNate Lawson 
330f3118682SNate Lawson 	ACPI_SERIAL_ASSERT(panasonic);
331f3118682SNate Lawson 	reg = (power_profile_get_state() == POWER_PROFILE_PERFORMANCE) ?
332f3118682SNate Lawson 	    HKEY_REG_LCD_BRIGHTNESS_MIN_AC : HKEY_REG_LCD_BRIGHTNESS_MIN_DC;
333f3118682SNate Lawson 
334f3118682SNate Lawson 	switch (op) {
335f3118682SNate Lawson 	case HKEY_SET:
336f3118682SNate Lawson 		return (EPERM);
337f3118682SNate Lawson 		break;
338f3118682SNate Lawson 	case HKEY_GET:
339f3118682SNate Lawson 		*val = acpi_panasonic_sinf(h, reg);
340ee6020c9SYoshihiro Takahashi 		break;
341ee6020c9SYoshihiro Takahashi 	}
342ee6020c9SYoshihiro Takahashi 
343ee6020c9SYoshihiro Takahashi 	return (0);
344ee6020c9SYoshihiro Takahashi }
345ee6020c9SYoshihiro Takahashi 
346ee6020c9SYoshihiro Takahashi static int
347ee6020c9SYoshihiro Takahashi hkey_lcd_brightness(ACPI_HANDLE h, int op, UINT32 *val)
348ee6020c9SYoshihiro Takahashi {
349f3118682SNate Lawson 	int reg;
350f3118682SNate Lawson 	UINT32 max, min;
351f3118682SNate Lawson 
352f3118682SNate Lawson 	reg = (power_profile_get_state() == POWER_PROFILE_PERFORMANCE) ?
353f3118682SNate Lawson 	    HKEY_REG_LCD_BRIGHTNESS_AC : HKEY_REG_LCD_BRIGHTNESS_DC;
354ee6020c9SYoshihiro Takahashi 
355e8a162f4SNate Lawson 	ACPI_SERIAL_ASSERT(panasonic);
356ee6020c9SYoshihiro Takahashi 	switch (op) {
357ee6020c9SYoshihiro Takahashi 	case HKEY_SET:
358f3118682SNate Lawson 		hkey_lcd_brightness_max(h, HKEY_GET, &max);
359f3118682SNate Lawson 		hkey_lcd_brightness_min(h, HKEY_GET, &min);
360f3118682SNate Lawson 		if (*val < min || *val > max)
361ee6020c9SYoshihiro Takahashi 			return (EINVAL);
362f3118682SNate Lawson 		acpi_panasonic_sset(h, reg, *val);
363ee6020c9SYoshihiro Takahashi 		break;
364ee6020c9SYoshihiro Takahashi 	case HKEY_GET:
365f3118682SNate Lawson 		*val = acpi_panasonic_sinf(h, reg);
366ee6020c9SYoshihiro Takahashi 		break;
367ee6020c9SYoshihiro Takahashi 	}
368ee6020c9SYoshihiro Takahashi 
369ee6020c9SYoshihiro Takahashi 	return (0);
370ee6020c9SYoshihiro Takahashi }
371ee6020c9SYoshihiro Takahashi 
372ee6020c9SYoshihiro Takahashi static int
373ee6020c9SYoshihiro Takahashi hkey_sound_mute(ACPI_HANDLE h, int op, UINT32 *val)
374ee6020c9SYoshihiro Takahashi {
375ee6020c9SYoshihiro Takahashi 
376e8a162f4SNate Lawson 	ACPI_SERIAL_ASSERT(panasonic);
377ee6020c9SYoshihiro Takahashi 	switch (op) {
378ee6020c9SYoshihiro Takahashi 	case HKEY_SET:
379ee6020c9SYoshihiro Takahashi 		if (*val != 0 && *val != 1)
380ee6020c9SYoshihiro Takahashi 			return (EINVAL);
381ee6020c9SYoshihiro Takahashi 		acpi_panasonic_sset(h, HKEY_REG_SOUND_MUTE, *val);
382ee6020c9SYoshihiro Takahashi 		break;
383ee6020c9SYoshihiro Takahashi 	case HKEY_GET:
384ee6020c9SYoshihiro Takahashi 		*val = acpi_panasonic_sinf(h, HKEY_REG_SOUND_MUTE);
385ee6020c9SYoshihiro Takahashi 		break;
386ee6020c9SYoshihiro Takahashi 	}
387ee6020c9SYoshihiro Takahashi 
388ee6020c9SYoshihiro Takahashi 	return (0);
389ee6020c9SYoshihiro Takahashi }
390ee6020c9SYoshihiro Takahashi 
391ee6020c9SYoshihiro Takahashi static int
392ee6020c9SYoshihiro Takahashi acpi_panasonic_hkey_event(struct acpi_panasonic_softc *sc, ACPI_HANDLE h,
393ee6020c9SYoshihiro Takahashi     UINT32 *arg)
394ee6020c9SYoshihiro Takahashi {
395ee6020c9SYoshihiro Takahashi 	ACPI_BUFFER buf;
396ee6020c9SYoshihiro Takahashi 	ACPI_OBJECT *res;
3979a179dd8SJung-uk Kim 	UINT64 val;
398ee6020c9SYoshihiro Takahashi 	int status;
399ee6020c9SYoshihiro Takahashi 
400e8a162f4SNate Lawson 	ACPI_SERIAL_ASSERT(panasonic);
401ee6020c9SYoshihiro Takahashi 	status = ENXIO;
402ee6020c9SYoshihiro Takahashi 
403ee6020c9SYoshihiro Takahashi 	buf.Length = ACPI_ALLOCATE_BUFFER;
404ee6020c9SYoshihiro Takahashi 	buf.Pointer = NULL;
405ee6020c9SYoshihiro Takahashi 	AcpiEvaluateObject(h, "HINF", NULL, &buf);
406ee6020c9SYoshihiro Takahashi 	res = (ACPI_OBJECT *)buf.Pointer;
407ee6020c9SYoshihiro Takahashi 	if (res->Type != ACPI_TYPE_INTEGER) {
408ee6020c9SYoshihiro Takahashi 		device_printf(sc->dev, "HINF returned non-integer\n");
409ee6020c9SYoshihiro Takahashi 		goto end;
410ee6020c9SYoshihiro Takahashi 	}
411ee6020c9SYoshihiro Takahashi 	val = res->Integer.Value;
412ee6020c9SYoshihiro Takahashi #ifdef ACPI_PANASONIC_DEBUG
413ee6020c9SYoshihiro Takahashi 	device_printf(sc->dev, "%s button Fn+F%d\n",
414ee6020c9SYoshihiro Takahashi 		      (val & 0x80) ? "Pressed" : "Released",
415ee6020c9SYoshihiro Takahashi 		      (int)(val & 0x7f));
416ee6020c9SYoshihiro Takahashi #endif
417ee6020c9SYoshihiro Takahashi 	if ((val & 0x7f) > 0 && (val & 0x7f) < 11) {
418ee6020c9SYoshihiro Takahashi 		*arg = val;
419ee6020c9SYoshihiro Takahashi 		status = 0;
420ee6020c9SYoshihiro Takahashi 	}
421ee6020c9SYoshihiro Takahashi end:
422ee6020c9SYoshihiro Takahashi 	if (buf.Pointer)
423ee6020c9SYoshihiro Takahashi 		AcpiOsFree(buf.Pointer);
424ee6020c9SYoshihiro Takahashi 
425ee6020c9SYoshihiro Takahashi 	return (status);
426ee6020c9SYoshihiro Takahashi }
427ee6020c9SYoshihiro Takahashi 
428ee6020c9SYoshihiro Takahashi static void
429ee6020c9SYoshihiro Takahashi acpi_panasonic_hkey_action(struct acpi_panasonic_softc *sc, ACPI_HANDLE h,
430ee6020c9SYoshihiro Takahashi     UINT32 key)
431ee6020c9SYoshihiro Takahashi {
43214ecccdaSYoshihiro Takahashi 	struct acpi_softc *acpi_sc;
433f3118682SNate Lawson 	int arg, max, min;
434ee6020c9SYoshihiro Takahashi 
43514ecccdaSYoshihiro Takahashi 	acpi_sc = acpi_device_get_parent_softc(sc->dev);
43614ecccdaSYoshihiro Takahashi 
437e8a162f4SNate Lawson 	ACPI_SERIAL_ASSERT(panasonic);
438ee6020c9SYoshihiro Takahashi 	switch (key) {
439ee6020c9SYoshihiro Takahashi 	case 1:
440ee6020c9SYoshihiro Takahashi 		/* Decrease LCD brightness. */
441f3118682SNate Lawson 		hkey_lcd_brightness_max(h, HKEY_GET, &max);
442f3118682SNate Lawson 		hkey_lcd_brightness_min(h, HKEY_GET, &min);
443ee6020c9SYoshihiro Takahashi 		hkey_lcd_brightness(h, HKEY_GET, &arg);
444f3118682SNate Lawson 		arg -= max / HKEY_LCD_BRIGHTNESS_DIV;
445f3118682SNate Lawson 		if (arg < min)
446f3118682SNate Lawson 			arg = min;
447f3118682SNate Lawson 		else if (arg > max)
448f3118682SNate Lawson 			arg = max;
449ee6020c9SYoshihiro Takahashi 		hkey_lcd_brightness(h, HKEY_SET, &arg);
450ee6020c9SYoshihiro Takahashi 		break;
451ee6020c9SYoshihiro Takahashi 	case 2:
452ee6020c9SYoshihiro Takahashi 		/* Increase LCD brightness. */
453f3118682SNate Lawson 		hkey_lcd_brightness_max(h, HKEY_GET, &max);
454f3118682SNate Lawson 		hkey_lcd_brightness_min(h, HKEY_GET, &min);
455ee6020c9SYoshihiro Takahashi 		hkey_lcd_brightness(h, HKEY_GET, &arg);
456f3118682SNate Lawson 		arg += max / HKEY_LCD_BRIGHTNESS_DIV;
457f3118682SNate Lawson 		if (arg < min)
458f3118682SNate Lawson 			arg = min;
459f3118682SNate Lawson 		else if (arg > max)
460f3118682SNate Lawson 			arg = max;
461ee6020c9SYoshihiro Takahashi 		hkey_lcd_brightness(h, HKEY_SET, &arg);
462ee6020c9SYoshihiro Takahashi 		break;
463ee6020c9SYoshihiro Takahashi 	case 4:
464ee6020c9SYoshihiro Takahashi 		/* Toggle sound mute. */
465ee6020c9SYoshihiro Takahashi 		hkey_sound_mute(h, HKEY_GET, &arg);
466ee6020c9SYoshihiro Takahashi 		if (arg)
467ee6020c9SYoshihiro Takahashi 			arg = 0;
468ee6020c9SYoshihiro Takahashi 		else
469ee6020c9SYoshihiro Takahashi 			arg = 1;
470ee6020c9SYoshihiro Takahashi 		hkey_sound_mute(h, HKEY_SET, &arg);
471ee6020c9SYoshihiro Takahashi 		break;
47214ecccdaSYoshihiro Takahashi 	case 7:
47314ecccdaSYoshihiro Takahashi 		/* Suspend. */
474d6da5e88SYoshihiro Takahashi 		acpi_event_sleep_button_sleep(acpi_sc);
47514ecccdaSYoshihiro Takahashi 		break;
476ee6020c9SYoshihiro Takahashi 	}
477ee6020c9SYoshihiro Takahashi }
478ee6020c9SYoshihiro Takahashi 
479ee6020c9SYoshihiro Takahashi static void
480ee6020c9SYoshihiro Takahashi acpi_panasonic_notify(ACPI_HANDLE h, UINT32 notify, void *context)
481ee6020c9SYoshihiro Takahashi {
482ee6020c9SYoshihiro Takahashi 	struct acpi_panasonic_softc *sc;
4836eb9bbf3SMatt Jacob 	UINT32 key = 0;
484ee6020c9SYoshihiro Takahashi 
485ee6020c9SYoshihiro Takahashi 	sc = (struct acpi_panasonic_softc *)context;
486ee6020c9SYoshihiro Takahashi 
487ee6020c9SYoshihiro Takahashi 	switch (notify) {
488ee6020c9SYoshihiro Takahashi 	case 0x80:
489e8a162f4SNate Lawson 		ACPI_SERIAL_BEGIN(panasonic);
490ee6020c9SYoshihiro Takahashi 		if (acpi_panasonic_hkey_event(sc, h, &key) == 0) {
491ee6020c9SYoshihiro Takahashi 			acpi_panasonic_hkey_action(sc, h, key);
492ee6020c9SYoshihiro Takahashi 			acpi_UserNotify("Panasonic", h, (uint8_t)key);
493ee6020c9SYoshihiro Takahashi 		}
494e8a162f4SNate Lawson 		ACPI_SERIAL_END(panasonic);
495ee6020c9SYoshihiro Takahashi 		break;
496a8fefd0eSShunsuke Akiyama 	case 0x81:
497a8fefd0eSShunsuke Akiyama 		if (!bootverbose)
498a8fefd0eSShunsuke Akiyama 			break;
499a8fefd0eSShunsuke Akiyama 		/* FALLTHROUGH */
500ee6020c9SYoshihiro Takahashi 	default:
501be223480SNate Lawson 		device_printf(sc->dev, "unknown notify: %#x\n", notify);
502ee6020c9SYoshihiro Takahashi 		break;
503ee6020c9SYoshihiro Takahashi 	}
504ee6020c9SYoshihiro Takahashi }
505f3118682SNate Lawson 
506f3118682SNate Lawson static void
507f3118682SNate Lawson acpi_panasonic_power_profile(void *arg)
508f3118682SNate Lawson {
509f3118682SNate Lawson 	ACPI_HANDLE handle;
510f3118682SNate Lawson 	UINT32 brightness;
511f3118682SNate Lawson 
512f3118682SNate Lawson 	handle = (ACPI_HANDLE)arg;
513f3118682SNate Lawson 
514f3118682SNate Lawson 	/* Reset current brightness according to new power state. */
515f3118682SNate Lawson 	ACPI_SERIAL_BEGIN(panasonic);
516f3118682SNate Lawson 	hkey_lcd_brightness(handle, HKEY_GET, &brightness);
517f3118682SNate Lawson 	hkey_lcd_brightness(handle, HKEY_SET, &brightness);
518f3118682SNate Lawson 	ACPI_SERIAL_END(panasonic);
519f3118682SNate Lawson }
520