acpi_panasonic.c revision 202771
1212700Sjkim/*-
2212700Sjkim * Copyright (c) 2003 OGAWA Takaya <t-ogawa@triaez.kaisei.org>
3212700Sjkim * Copyright (c) 2004 TAKAHASHI Yoshihiro <nyan@FreeBSD.org>
4212700Sjkim * All rights Reserved.
5212700Sjkim *
6212700Sjkim * Redistribution and use in source and binary forms, with or without
7212700Sjkim * modification, are permitted provided that the following conditions
8212700Sjkim * are met:
9212700Sjkim * 1. Redistributions of source code must retain the above copyright
10212700Sjkim *    notice, this list of conditions and the following disclaimer.
11212700Sjkim * 2. Redistributions in binary form must reproduce the above copyright
12212700Sjkim *    notice, this list of conditions and the following disclaimer in the
13212700Sjkim *    documentation and/or other materials provided with the distribution.
14212700Sjkim *
15212700Sjkim * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
16212700Sjkim * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17212700Sjkim * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18212700Sjkim * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
19212700Sjkim * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20212700Sjkim * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
21212700Sjkim * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22212700Sjkim * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
23212700Sjkim * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24212700Sjkim * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
25212700Sjkim * SUCH DAMAGE.
26212700Sjkim *
27212700Sjkim */
28212700Sjkim
29212700Sjkim#include <sys/cdefs.h>
30212700Sjkim__FBSDID("$FreeBSD: head/sys/dev/acpi_support/acpi_panasonic.c 202771 2010-01-21 21:14:28Z jkim $");
31212700Sjkim
32212700Sjkim#include "opt_acpi.h"
33212700Sjkim#include <sys/param.h>
34212700Sjkim#include <sys/kernel.h>
35212700Sjkim#include <sys/malloc.h>
36212700Sjkim#include <sys/module.h>
37212700Sjkim#include <sys/bus.h>
38212700Sjkim#include <sys/power.h>
39212700Sjkim
40212700Sjkim#include <contrib/dev/acpica/include/acpi.h>
41212700Sjkim
42212700Sjkim#include <dev/acpica/acpivar.h>
43212700Sjkim
44212700Sjkim#define _COMPONENT	ACPI_OEM
45212700SjkimACPI_MODULE_NAME("Panasonic")
46212700Sjkim
47212700Sjkim/* Debug */
48212700Sjkim#undef	ACPI_PANASONIC_DEBUG
49212700Sjkim
50212700Sjkim/* Operations */
51212700Sjkim#define	HKEY_SET	0
52212700Sjkim#define	HKEY_GET	1
53212700Sjkim
54212700Sjkim/* Functions */
55212700Sjkim#define	HKEY_REG_LCD_BRIGHTNESS_MAX_AC	0x02
56212700Sjkim#define	HKEY_REG_LCD_BRIGHTNESS_MIN_AC	0x03
57212700Sjkim#define	HKEY_REG_LCD_BRIGHTNESS_AC	0x04
58212700Sjkim#define	HKEY_REG_LCD_BRIGHTNESS_MAX_DC	0x05
59212700Sjkim#define	HKEY_REG_LCD_BRIGHTNESS_MIN_DC	0x06
60212700Sjkim#define	HKEY_REG_LCD_BRIGHTNESS_DC	0x07
61212700Sjkim#define	HKEY_REG_SOUND_MUTE		0x08
62212700Sjkim
63212700Sjkim/* Field definitions */
64212700Sjkim#define	HKEY_LCD_BRIGHTNESS_BITS	4
65212700Sjkim#define	HKEY_LCD_BRIGHTNESS_DIV		((1 << HKEY_LCD_BRIGHTNESS_BITS) - 1)
66212700Sjkim
67212700Sjkimstruct acpi_panasonic_softc {
68212700Sjkim	device_t	dev;
69212700Sjkim	ACPI_HANDLE	handle;
70212700Sjkim
71212700Sjkim	struct sysctl_ctx_list	sysctl_ctx;
72212700Sjkim	struct sysctl_oid	*sysctl_tree;
73212700Sjkim
74212700Sjkim	eventhandler_tag	power_evh;
75212700Sjkim};
76212700Sjkim
77212700Sjkim/* Prototype for HKEY functions for getting/setting a value. */
78212700Sjkimtypedef int hkey_fn_t(ACPI_HANDLE, int, UINT32 *);
79212700Sjkim
80212700Sjkimstatic int	acpi_panasonic_probe(device_t dev);
81212700Sjkimstatic int	acpi_panasonic_attach(device_t dev);
82212700Sjkimstatic int	acpi_panasonic_detach(device_t dev);
83212700Sjkimstatic int	acpi_panasonic_shutdown(device_t dev);
84212700Sjkimstatic int	acpi_panasonic_sysctl(SYSCTL_HANDLER_ARGS);
85212700Sjkimstatic UINT64	acpi_panasonic_sinf(ACPI_HANDLE h, UINT64 index);
86212700Sjkimstatic void	acpi_panasonic_sset(ACPI_HANDLE h, UINT64 index,
87212700Sjkim		    UINT64 val);
88212700Sjkimstatic int	acpi_panasonic_hkey_event(struct acpi_panasonic_softc *sc,
89212700Sjkim		    ACPI_HANDLE h, UINT32 *arg);
90212700Sjkimstatic void	acpi_panasonic_hkey_action(struct acpi_panasonic_softc *sc,
91212700Sjkim		    ACPI_HANDLE h, UINT32 key);
92212700Sjkimstatic void	acpi_panasonic_notify(ACPI_HANDLE h, UINT32 notify,
93212700Sjkim		    void *context);
94212700Sjkimstatic void	acpi_panasonic_power_profile(void *arg);
95212700Sjkim
96212700Sjkimstatic hkey_fn_t	hkey_lcd_brightness_max;
97212700Sjkimstatic hkey_fn_t	hkey_lcd_brightness_min;
98212700Sjkimstatic hkey_fn_t	hkey_lcd_brightness;
99212700Sjkimstatic hkey_fn_t	hkey_sound_mute;
100212700SjkimACPI_SERIAL_DECL(panasonic, "ACPI Panasonic extras");
101212700Sjkim
102212700Sjkim/* Table of sysctl names and HKEY functions to call. */
103212700Sjkimstatic struct {
104212700Sjkim	char		*name;
105212700Sjkim	hkey_fn_t	*handler;
106212700Sjkim} sysctl_table[] = {
107212700Sjkim	/* name,		handler */
108212700Sjkim	{"lcd_brightness_max",	hkey_lcd_brightness_max},
109212700Sjkim	{"lcd_brightness_min",	hkey_lcd_brightness_min},
110212700Sjkim	{"lcd_brightness",	hkey_lcd_brightness},
111212700Sjkim	{"sound_mute",		hkey_sound_mute},
112212700Sjkim	{NULL, NULL}
113212700Sjkim};
114212700Sjkim
115212700Sjkimstatic device_method_t acpi_panasonic_methods[] = {
116212700Sjkim	DEVMETHOD(device_probe,		acpi_panasonic_probe),
117212700Sjkim	DEVMETHOD(device_attach,	acpi_panasonic_attach),
118212700Sjkim	DEVMETHOD(device_detach,	acpi_panasonic_detach),
119212700Sjkim	DEVMETHOD(device_shutdown,	acpi_panasonic_shutdown),
120212700Sjkim
121212700Sjkim	{0, 0}
122212700Sjkim};
123212700Sjkim
124212700Sjkimstatic driver_t acpi_panasonic_driver = {
125212700Sjkim	"acpi_panasonic",
126212700Sjkim	acpi_panasonic_methods,
127212700Sjkim	sizeof(struct acpi_panasonic_softc),
128212700Sjkim};
129212700Sjkim
130212700Sjkimstatic devclass_t acpi_panasonic_devclass;
131212700Sjkim
132212700SjkimDRIVER_MODULE(acpi_panasonic, acpi, acpi_panasonic_driver,
133212700Sjkim    acpi_panasonic_devclass, 0, 0);
134212700SjkimMODULE_DEPEND(acpi_panasonic, acpi, 1, 1, 1);
135212700Sjkim
136212700Sjkimstatic int
137212700Sjkimacpi_panasonic_probe(device_t dev)
138212700Sjkim{
139212700Sjkim	static char *mat_ids[] = { "MAT0019", NULL };
140212700Sjkim
141212700Sjkim	if (acpi_disabled("panasonic") ||
142212700Sjkim	    ACPI_ID_PROBE(device_get_parent(dev), dev, mat_ids) == NULL ||
143212700Sjkim	    device_get_unit(dev) != 0)
144212700Sjkim		return (ENXIO);
145212700Sjkim
146212700Sjkim	device_set_desc(dev, "Panasonic Notebook Hotkeys");
147212700Sjkim	return (0);
148212700Sjkim}
149212700Sjkim
150212700Sjkimstatic int
151212700Sjkimacpi_panasonic_attach(device_t dev)
152212700Sjkim{
153212700Sjkim	struct acpi_panasonic_softc *sc;
154212700Sjkim	struct acpi_softc *acpi_sc;
155212700Sjkim	ACPI_STATUS status;
156212700Sjkim	int i;
157212700Sjkim
158212700Sjkim	sc = device_get_softc(dev);
159212700Sjkim	sc->dev = dev;
160212700Sjkim	sc->handle = acpi_get_handle(dev);
161212700Sjkim
162212700Sjkim	acpi_sc = acpi_device_get_parent_softc(dev);
163212700Sjkim
164212700Sjkim	/* Build sysctl tree */
165212700Sjkim	sysctl_ctx_init(&sc->sysctl_ctx);
166212700Sjkim	sc->sysctl_tree = SYSCTL_ADD_NODE(&sc->sysctl_ctx,
167212700Sjkim	    SYSCTL_CHILDREN(acpi_sc->acpi_sysctl_tree), OID_AUTO,
168212700Sjkim	    "panasonic", CTLFLAG_RD, 0, "");
169212700Sjkim	for (i = 0; sysctl_table[i].name != NULL; i++) {
170212700Sjkim		SYSCTL_ADD_PROC(&sc->sysctl_ctx,
171212700Sjkim		    SYSCTL_CHILDREN(sc->sysctl_tree), OID_AUTO,
172212700Sjkim		    sysctl_table[i].name,
173212700Sjkim		    CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_ANYBODY,
174212700Sjkim		    sc, i, acpi_panasonic_sysctl, "I", "");
175212700Sjkim	}
176212700Sjkim
177212700Sjkim#if 0
178212700Sjkim	/* Activate hotkeys */
179212700Sjkim	status = AcpiEvaluateObject(sc->handle, "", NULL, NULL);
180212700Sjkim	if (ACPI_FAILURE(status)) {
181212700Sjkim		device_printf(dev, "enable FN keys failed\n");
182212700Sjkim		sysctl_ctx_free(&sc->sysctl_ctx);
183212700Sjkim		return (ENXIO);
184212700Sjkim	}
185212700Sjkim#endif
186212700Sjkim
187212700Sjkim	/* Handle notifies */
188212700Sjkim	status = AcpiInstallNotifyHandler(sc->handle, ACPI_DEVICE_NOTIFY,
189212700Sjkim	    acpi_panasonic_notify, sc);
190212700Sjkim	if (ACPI_FAILURE(status)) {
191212700Sjkim		device_printf(dev, "couldn't install notify handler - %s\n",
192212700Sjkim		    AcpiFormatException(status));
193212700Sjkim		sysctl_ctx_free(&sc->sysctl_ctx);
194212700Sjkim		return (ENXIO);
195212700Sjkim	}
196212700Sjkim
197212700Sjkim	/* Install power profile event handler */
198212700Sjkim	sc->power_evh = EVENTHANDLER_REGISTER(power_profile_change,
199212700Sjkim	    acpi_panasonic_power_profile, sc->handle, 0);
200212700Sjkim
201212700Sjkim	return (0);
202212700Sjkim}
203212700Sjkim
204212700Sjkimstatic int
205212700Sjkimacpi_panasonic_detach(device_t dev)
206212700Sjkim{
207212700Sjkim	struct acpi_panasonic_softc *sc;
208212700Sjkim
209212700Sjkim	sc = device_get_softc(dev);
210212700Sjkim
211212700Sjkim	/* Remove power profile event handler */
212212700Sjkim	EVENTHANDLER_DEREGISTER(power_profile_change, sc->power_evh);
213212700Sjkim
214212700Sjkim	/* Remove notify handler */
215212700Sjkim	AcpiRemoveNotifyHandler(sc->handle, ACPI_DEVICE_NOTIFY,
216212700Sjkim	    acpi_panasonic_notify);
217212700Sjkim
218212700Sjkim	/* Free sysctl tree */
219212700Sjkim	sysctl_ctx_free(&sc->sysctl_ctx);
220212700Sjkim
221212700Sjkim	return (0);
222212700Sjkim}
223212700Sjkim
224212700Sjkimstatic int
225212700Sjkimacpi_panasonic_shutdown(device_t dev)
226212700Sjkim{
227212700Sjkim	struct acpi_panasonic_softc *sc;
228212700Sjkim	int mute;
229212700Sjkim
230212700Sjkim	/* Mute the main audio during reboot to prevent static burst to speaker. */
231212700Sjkim	sc = device_get_softc(dev);
232212700Sjkim	mute = 1;
233212700Sjkim	hkey_sound_mute(sc->handle, HKEY_SET, &mute);
234212700Sjkim	return (0);
235212700Sjkim}
236212700Sjkim
237212700Sjkimstatic int
238212700Sjkimacpi_panasonic_sysctl(SYSCTL_HANDLER_ARGS)
239212700Sjkim{
240212700Sjkim	struct acpi_panasonic_softc *sc;
241212700Sjkim	UINT32 arg;
242212700Sjkim	int function, error;
243212700Sjkim	hkey_fn_t *handler;
244212700Sjkim
245212700Sjkim	sc = (struct acpi_panasonic_softc *)oidp->oid_arg1;
246212700Sjkim	function = oidp->oid_arg2;
247212700Sjkim	handler = sysctl_table[function].handler;
248212700Sjkim
249212700Sjkim	/* Get the current value from the appropriate function. */
250212700Sjkim	ACPI_SERIAL_BEGIN(panasonic);
251212700Sjkim	error = handler(sc->handle, HKEY_GET, &arg);
252212700Sjkim	if (error != 0)
253212700Sjkim		goto out;
254212700Sjkim
255212700Sjkim	/* Send the current value to the user and return if no new value. */
256212700Sjkim	error = sysctl_handle_int(oidp, &arg, 0, req);
257212700Sjkim	if (error != 0 || req->newptr == NULL)
258212700Sjkim		goto out;
259212700Sjkim
260212700Sjkim	/* Set the new value via the appropriate function. */
261212700Sjkim	error = handler(sc->handle, HKEY_SET, &arg);
262212700Sjkim
263212700Sjkimout:
264212700Sjkim	ACPI_SERIAL_END(panasonic);
265212700Sjkim	return (error);
266212700Sjkim}
267212700Sjkim
268212700Sjkimstatic UINT64
269212700Sjkimacpi_panasonic_sinf(ACPI_HANDLE h, UINT64 index)
270212700Sjkim{
271212700Sjkim	ACPI_BUFFER buf;
272212700Sjkim	ACPI_OBJECT *res;
273212700Sjkim	UINT64 ret;
274212700Sjkim
275212700Sjkim	ACPI_SERIAL_ASSERT(panasonic);
276212700Sjkim	ret = -1;
277212700Sjkim	buf.Length = ACPI_ALLOCATE_BUFFER;
278212700Sjkim	buf.Pointer = NULL;
279212700Sjkim	AcpiEvaluateObject(h, "SINF", NULL, &buf);
280212700Sjkim	res = (ACPI_OBJECT *)buf.Pointer;
281212700Sjkim	if (res->Type == ACPI_TYPE_PACKAGE)
282212700Sjkim		ret = res->Package.Elements[index].Integer.Value;
283212700Sjkim	AcpiOsFree(buf.Pointer);
284212700Sjkim
285212700Sjkim	return (ret);
286212700Sjkim}
287212700Sjkim
288212700Sjkimstatic void
289212700Sjkimacpi_panasonic_sset(ACPI_HANDLE h, UINT64 index, UINT64 val)
290212700Sjkim{
291212700Sjkim	ACPI_OBJECT_LIST args;
292212700Sjkim	ACPI_OBJECT obj[2];
293212700Sjkim
294212700Sjkim	ACPI_SERIAL_ASSERT(panasonic);
295212700Sjkim	obj[0].Type = ACPI_TYPE_INTEGER;
296212700Sjkim	obj[0].Integer.Value = index;
297212700Sjkim	obj[1].Type = ACPI_TYPE_INTEGER;
298212700Sjkim	obj[1].Integer.Value = val;
299212700Sjkim	args.Count = 2;
300212700Sjkim	args.Pointer = obj;
301212700Sjkim	AcpiEvaluateObject(h, "SSET", &args, NULL);
302212700Sjkim}
303212700Sjkim
304212700Sjkimstatic int
305212700Sjkimhkey_lcd_brightness_max(ACPI_HANDLE h, int op, UINT32 *val)
306212700Sjkim{
307212700Sjkim	int reg;
308212700Sjkim
309212700Sjkim	ACPI_SERIAL_ASSERT(panasonic);
310212700Sjkim	reg = (power_profile_get_state() == POWER_PROFILE_PERFORMANCE) ?
311212700Sjkim	    HKEY_REG_LCD_BRIGHTNESS_MAX_AC : HKEY_REG_LCD_BRIGHTNESS_MAX_DC;
312212700Sjkim
313212700Sjkim	switch (op) {
314212700Sjkim	case HKEY_SET:
315212700Sjkim		return (EPERM);
316212700Sjkim		break;
317212700Sjkim	case HKEY_GET:
318212700Sjkim		*val = acpi_panasonic_sinf(h, reg);
319212700Sjkim		break;
320212700Sjkim	}
321212700Sjkim
322212700Sjkim	return (0);
323212700Sjkim}
324212700Sjkim
325212700Sjkimstatic int
326212700Sjkimhkey_lcd_brightness_min(ACPI_HANDLE h, int op, UINT32 *val)
327212700Sjkim{
328212700Sjkim	int reg;
329212700Sjkim
330212700Sjkim	ACPI_SERIAL_ASSERT(panasonic);
331212700Sjkim	reg = (power_profile_get_state() == POWER_PROFILE_PERFORMANCE) ?
332212700Sjkim	    HKEY_REG_LCD_BRIGHTNESS_MIN_AC : HKEY_REG_LCD_BRIGHTNESS_MIN_DC;
333212700Sjkim
334212700Sjkim	switch (op) {
335212700Sjkim	case HKEY_SET:
336212700Sjkim		return (EPERM);
337212700Sjkim		break;
338212700Sjkim	case HKEY_GET:
339212700Sjkim		*val = acpi_panasonic_sinf(h, reg);
340212700Sjkim		break;
341212700Sjkim	}
342212700Sjkim
343212700Sjkim	return (0);
344212700Sjkim}
345212700Sjkim
346212700Sjkimstatic int
347212700Sjkimhkey_lcd_brightness(ACPI_HANDLE h, int op, UINT32 *val)
348212700Sjkim{
349212700Sjkim	int reg;
350212700Sjkim	UINT32 max, min;
351212700Sjkim
352212700Sjkim	reg = (power_profile_get_state() == POWER_PROFILE_PERFORMANCE) ?
353212700Sjkim	    HKEY_REG_LCD_BRIGHTNESS_AC : HKEY_REG_LCD_BRIGHTNESS_DC;
354212700Sjkim
355212700Sjkim	ACPI_SERIAL_ASSERT(panasonic);
356212700Sjkim	switch (op) {
357212700Sjkim	case HKEY_SET:
358212700Sjkim		hkey_lcd_brightness_max(h, HKEY_GET, &max);
359212700Sjkim		hkey_lcd_brightness_min(h, HKEY_GET, &min);
360212700Sjkim		if (*val < min || *val > max)
361212700Sjkim			return (EINVAL);
362212700Sjkim		acpi_panasonic_sset(h, reg, *val);
363212700Sjkim		break;
364212700Sjkim	case HKEY_GET:
365212700Sjkim		*val = acpi_panasonic_sinf(h, reg);
366212700Sjkim		break;
367212700Sjkim	}
368212700Sjkim
369212700Sjkim	return (0);
370212700Sjkim}
371212700Sjkim
372212700Sjkimstatic int
373212700Sjkimhkey_sound_mute(ACPI_HANDLE h, int op, UINT32 *val)
374212700Sjkim{
375212700Sjkim
376212700Sjkim	ACPI_SERIAL_ASSERT(panasonic);
377212700Sjkim	switch (op) {
378212700Sjkim	case HKEY_SET:
379212700Sjkim		if (*val != 0 && *val != 1)
380212700Sjkim			return (EINVAL);
381212700Sjkim		acpi_panasonic_sset(h, HKEY_REG_SOUND_MUTE, *val);
382212700Sjkim		break;
383212700Sjkim	case HKEY_GET:
384212700Sjkim		*val = acpi_panasonic_sinf(h, HKEY_REG_SOUND_MUTE);
385212700Sjkim		break;
386212700Sjkim	}
387212700Sjkim
388212700Sjkim	return (0);
389212700Sjkim}
390212700Sjkim
391212700Sjkimstatic int
392212700Sjkimacpi_panasonic_hkey_event(struct acpi_panasonic_softc *sc, ACPI_HANDLE h,
393212700Sjkim    UINT32 *arg)
394212700Sjkim{
395212700Sjkim	ACPI_BUFFER buf;
396212700Sjkim	ACPI_OBJECT *res;
397212700Sjkim	UINT64 val;
398212700Sjkim	int status;
399212700Sjkim
400212700Sjkim	ACPI_SERIAL_ASSERT(panasonic);
401212700Sjkim	status = ENXIO;
402212700Sjkim
403212700Sjkim	buf.Length = ACPI_ALLOCATE_BUFFER;
404212700Sjkim	buf.Pointer = NULL;
405212700Sjkim	AcpiEvaluateObject(h, "HINF", NULL, &buf);
406212700Sjkim	res = (ACPI_OBJECT *)buf.Pointer;
407212700Sjkim	if (res->Type != ACPI_TYPE_INTEGER) {
408212700Sjkim		device_printf(sc->dev, "HINF returned non-integer\n");
409212700Sjkim		goto end;
410212700Sjkim	}
411212700Sjkim	val = res->Integer.Value;
412212700Sjkim#ifdef ACPI_PANASONIC_DEBUG
413212700Sjkim	device_printf(sc->dev, "%s button Fn+F%d\n",
414212700Sjkim		      (val & 0x80) ? "Pressed" : "Released",
415212700Sjkim		      (int)(val & 0x7f));
416212700Sjkim#endif
417212700Sjkim	if ((val & 0x7f) > 0 && (val & 0x7f) < 11) {
418212700Sjkim		*arg = val;
419212700Sjkim		status = 0;
420212700Sjkim	}
421212700Sjkimend:
422212700Sjkim	if (buf.Pointer)
423212700Sjkim		AcpiOsFree(buf.Pointer);
424212700Sjkim
425212700Sjkim	return (status);
426212700Sjkim}
427212700Sjkim
428212700Sjkimstatic void
429212700Sjkimacpi_panasonic_hkey_action(struct acpi_panasonic_softc *sc, ACPI_HANDLE h,
430212700Sjkim    UINT32 key)
431212700Sjkim{
432212700Sjkim	struct acpi_softc *acpi_sc;
433212700Sjkim	int arg, max, min;
434212700Sjkim
435212700Sjkim	acpi_sc = acpi_device_get_parent_softc(sc->dev);
436212700Sjkim
437212700Sjkim	ACPI_SERIAL_ASSERT(panasonic);
438212700Sjkim	switch (key) {
439212700Sjkim	case 1:
440212700Sjkim		/* Decrease LCD brightness. */
441212700Sjkim		hkey_lcd_brightness_max(h, HKEY_GET, &max);
442212700Sjkim		hkey_lcd_brightness_min(h, HKEY_GET, &min);
443212700Sjkim		hkey_lcd_brightness(h, HKEY_GET, &arg);
444212700Sjkim		arg -= max / HKEY_LCD_BRIGHTNESS_DIV;
445212700Sjkim		if (arg < min)
446212700Sjkim			arg = min;
447212700Sjkim		else if (arg > max)
448212700Sjkim			arg = max;
449212700Sjkim		hkey_lcd_brightness(h, HKEY_SET, &arg);
450212700Sjkim		break;
451212700Sjkim	case 2:
452212700Sjkim		/* Increase LCD brightness. */
453212700Sjkim		hkey_lcd_brightness_max(h, HKEY_GET, &max);
454212700Sjkim		hkey_lcd_brightness_min(h, HKEY_GET, &min);
455212700Sjkim		hkey_lcd_brightness(h, HKEY_GET, &arg);
456212700Sjkim		arg += max / HKEY_LCD_BRIGHTNESS_DIV;
457212700Sjkim		if (arg < min)
458212700Sjkim			arg = min;
459212700Sjkim		else if (arg > max)
460212700Sjkim			arg = max;
461212700Sjkim		hkey_lcd_brightness(h, HKEY_SET, &arg);
462212700Sjkim		break;
463212700Sjkim	case 4:
464212700Sjkim		/* Toggle sound mute. */
465212700Sjkim		hkey_sound_mute(h, HKEY_GET, &arg);
466212700Sjkim		if (arg)
467212700Sjkim			arg = 0;
468212700Sjkim		else
469212700Sjkim			arg = 1;
470212700Sjkim		hkey_sound_mute(h, HKEY_SET, &arg);
471212700Sjkim		break;
472212700Sjkim	case 7:
473212700Sjkim		/* Suspend. */
474212700Sjkim		acpi_event_sleep_button_sleep(acpi_sc);
475212700Sjkim		break;
476212700Sjkim	}
477212700Sjkim}
478212700Sjkim
479212700Sjkimstatic void
480212700Sjkimacpi_panasonic_notify(ACPI_HANDLE h, UINT32 notify, void *context)
481212700Sjkim{
482212700Sjkim	struct acpi_panasonic_softc *sc;
483212700Sjkim	UINT32 key = 0;
484212700Sjkim
485212700Sjkim	sc = (struct acpi_panasonic_softc *)context;
486212700Sjkim
487212700Sjkim	switch (notify) {
488212700Sjkim	case 0x80:
489212700Sjkim		ACPI_SERIAL_BEGIN(panasonic);
490212700Sjkim		if (acpi_panasonic_hkey_event(sc, h, &key) == 0) {
491212700Sjkim			acpi_panasonic_hkey_action(sc, h, key);
492212700Sjkim			acpi_UserNotify("Panasonic", h, (uint8_t)key);
493212700Sjkim		}
494212700Sjkim		ACPI_SERIAL_END(panasonic);
495212700Sjkim		break;
496212700Sjkim	default:
497212700Sjkim		device_printf(sc->dev, "unknown notify: %#x\n", notify);
498212700Sjkim		break;
499212700Sjkim	}
500212700Sjkim}
501212700Sjkim
502212700Sjkimstatic void
503212700Sjkimacpi_panasonic_power_profile(void *arg)
504212700Sjkim{
505212700Sjkim	ACPI_HANDLE handle;
506212700Sjkim	UINT32 brightness;
507212700Sjkim
508212700Sjkim	handle = (ACPI_HANDLE)arg;
509212700Sjkim
510212700Sjkim	/* Reset current brightness according to new power state. */
511212700Sjkim	ACPI_SERIAL_BEGIN(panasonic);
512212700Sjkim	hkey_lcd_brightness(handle, HKEY_GET, &brightness);
513212700Sjkim	hkey_lcd_brightness(handle, HKEY_SET, &brightness);
514212700Sjkim	ACPI_SERIAL_END(panasonic);
515212700Sjkim}
516212700Sjkim