acpi_panasonic.c revision 188162
1132501Snyan/*-
2132501Snyan * Copyright (c) 2003 OGAWA Takaya <t-ogawa@triaez.kaisei.org>
3146216Snyan * Copyright (c) 2004 TAKAHASHI Yoshihiro <nyan@FreeBSD.org>
4132501Snyan * All rights Reserved.
5132501Snyan *
6132501Snyan * Redistribution and use in source and binary forms, with or without
7132501Snyan * modification, are permitted provided that the following conditions
8132501Snyan * are met:
9132501Snyan * 1. Redistributions of source code must retain the above copyright
10132501Snyan *    notice, this list of conditions and the following disclaimer.
11132501Snyan * 2. Redistributions in binary form must reproduce the above copyright
12132501Snyan *    notice, this list of conditions and the following disclaimer in the
13132501Snyan *    documentation and/or other materials provided with the distribution.
14132501Snyan *
15132501Snyan * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
16132501Snyan * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17132501Snyan * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18132501Snyan * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
19132501Snyan * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20132501Snyan * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
21132501Snyan * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22132501Snyan * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
23132501Snyan * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24132501Snyan * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
25132501Snyan * SUCH DAMAGE.
26132501Snyan *
27132501Snyan */
28132501Snyan
29132501Snyan#include <sys/cdefs.h>
30132501Snyan__FBSDID("$FreeBSD: head/sys/dev/acpi_support/acpi_panasonic.c 188162 2009-02-05 18:39:33Z imp $");
31132501Snyan
32132501Snyan#include "opt_acpi.h"
33132501Snyan#include <sys/param.h>
34132501Snyan#include <sys/kernel.h>
35132501Snyan#include <sys/malloc.h>
36132501Snyan#include <sys/module.h>
37132501Snyan#include <sys/bus.h>
38137365Snjl#include <sys/power.h>
39132501Snyan
40150003Sobrien#include <contrib/dev/acpica/acpi.h>
41132501Snyan#include <dev/acpica/acpivar.h>
42132501Snyan
43138825Snjl#define _COMPONENT	ACPI_OEM
44138825SnjlACPI_MODULE_NAME("Panasonic")
45138825Snjl
46132501Snyan/* Debug */
47132501Snyan#undef	ACPI_PANASONIC_DEBUG
48132501Snyan
49132501Snyan/* Operations */
50132501Snyan#define	HKEY_SET	0
51132501Snyan#define	HKEY_GET	1
52132501Snyan
53132501Snyan/* Functions */
54137365Snjl#define	HKEY_REG_LCD_BRIGHTNESS_MAX_AC	0x02
55137365Snjl#define	HKEY_REG_LCD_BRIGHTNESS_MIN_AC	0x03
56137365Snjl#define	HKEY_REG_LCD_BRIGHTNESS_AC	0x04
57137365Snjl#define	HKEY_REG_LCD_BRIGHTNESS_MAX_DC	0x05
58137365Snjl#define	HKEY_REG_LCD_BRIGHTNESS_MIN_DC	0x06
59137365Snjl#define	HKEY_REG_LCD_BRIGHTNESS_DC	0x07
60132611Snjl#define	HKEY_REG_SOUND_MUTE		0x08
61132501Snyan
62132501Snyan/* Field definitions */
63132501Snyan#define	HKEY_LCD_BRIGHTNESS_BITS	4
64132501Snyan#define	HKEY_LCD_BRIGHTNESS_DIV		((1 << HKEY_LCD_BRIGHTNESS_BITS) - 1)
65132501Snyan
66132501Snyanstruct acpi_panasonic_softc {
67132501Snyan	device_t	dev;
68132501Snyan	ACPI_HANDLE	handle;
69132501Snyan
70132501Snyan	struct sysctl_ctx_list	sysctl_ctx;
71132501Snyan	struct sysctl_oid	*sysctl_tree;
72137365Snjl
73137365Snjl	eventhandler_tag	power_evh;
74132501Snyan};
75132501Snyan
76132501Snyan/* Prototype for HKEY functions for getting/setting a value. */
77132501Snyantypedef int hkey_fn_t(ACPI_HANDLE, int, UINT32 *);
78132501Snyan
79132501Snyanstatic int	acpi_panasonic_probe(device_t dev);
80132501Snyanstatic int	acpi_panasonic_attach(device_t dev);
81132501Snyanstatic int	acpi_panasonic_detach(device_t dev);
82188162Simpstatic int	acpi_panasonic_shutdown(device_t dev);
83132501Snyanstatic int	acpi_panasonic_sysctl(SYSCTL_HANDLER_ARGS);
84132611Snjlstatic ACPI_INTEGER acpi_panasonic_sinf(ACPI_HANDLE h, ACPI_INTEGER index);
85132501Snyanstatic void	acpi_panasonic_sset(ACPI_HANDLE h, ACPI_INTEGER index,
86132611Snjl		    ACPI_INTEGER val);
87132501Snyanstatic int	acpi_panasonic_hkey_event(struct acpi_panasonic_softc *sc,
88132611Snjl		    ACPI_HANDLE h, UINT32 *arg);
89132501Snyanstatic void	acpi_panasonic_hkey_action(struct acpi_panasonic_softc *sc,
90132611Snjl		    ACPI_HANDLE h, UINT32 key);
91132501Snyanstatic void	acpi_panasonic_notify(ACPI_HANDLE h, UINT32 notify,
92132611Snjl		    void *context);
93137365Snjlstatic void	acpi_panasonic_power_profile(void *arg);
94132501Snyan
95132611Snjlstatic hkey_fn_t	hkey_lcd_brightness_max;
96137365Snjlstatic hkey_fn_t	hkey_lcd_brightness_min;
97132611Snjlstatic hkey_fn_t	hkey_lcd_brightness;
98132611Snjlstatic hkey_fn_t	hkey_sound_mute;
99133629SnjlACPI_SERIAL_DECL(panasonic, "ACPI Panasonic extras");
100132611Snjl
101132501Snyan/* Table of sysctl names and HKEY functions to call. */
102132501Snyanstatic struct {
103132501Snyan	char		*name;
104132501Snyan	hkey_fn_t	*handler;
105132501Snyan} sysctl_table[] = {
106132501Snyan	/* name,		handler */
107132501Snyan	{"lcd_brightness_max",	hkey_lcd_brightness_max},
108137365Snjl	{"lcd_brightness_min",	hkey_lcd_brightness_min},
109132501Snyan	{"lcd_brightness",	hkey_lcd_brightness},
110132501Snyan	{"sound_mute",		hkey_sound_mute},
111132501Snyan	{NULL, NULL}
112132501Snyan};
113132501Snyan
114132501Snyanstatic device_method_t acpi_panasonic_methods[] = {
115132501Snyan	DEVMETHOD(device_probe,		acpi_panasonic_probe),
116132501Snyan	DEVMETHOD(device_attach,	acpi_panasonic_attach),
117132501Snyan	DEVMETHOD(device_detach,	acpi_panasonic_detach),
118170213Snjl	DEVMETHOD(device_shutdown,	acpi_panasonic_shutdown),
119132501Snyan
120132501Snyan	{0, 0}
121132501Snyan};
122132501Snyan
123132501Snyanstatic driver_t acpi_panasonic_driver = {
124132501Snyan	"acpi_panasonic",
125132501Snyan	acpi_panasonic_methods,
126132501Snyan	sizeof(struct acpi_panasonic_softc),
127132501Snyan};
128132501Snyan
129132501Snyanstatic devclass_t acpi_panasonic_devclass;
130132501Snyan
131132501SnyanDRIVER_MODULE(acpi_panasonic, acpi, acpi_panasonic_driver,
132132611Snjl    acpi_panasonic_devclass, 0, 0);
133132501SnyanMODULE_DEPEND(acpi_panasonic, acpi, 1, 1, 1);
134132501Snyan
135132501Snyanstatic int
136132501Snyanacpi_panasonic_probe(device_t dev)
137132501Snyan{
138132501Snyan	static char *mat_ids[] = { "MAT0019", NULL };
139132501Snyan
140132501Snyan	if (acpi_disabled("panasonic") ||
141132501Snyan	    ACPI_ID_PROBE(device_get_parent(dev), dev, mat_ids) == NULL ||
142132501Snyan	    device_get_unit(dev) != 0)
143132501Snyan		return (ENXIO);
144132501Snyan
145132501Snyan	device_set_desc(dev, "Panasonic Notebook Hotkeys");
146132501Snyan	return (0);
147132501Snyan}
148132501Snyan
149132501Snyanstatic int
150132501Snyanacpi_panasonic_attach(device_t dev)
151132501Snyan{
152132501Snyan	struct acpi_panasonic_softc *sc;
153132501Snyan	struct acpi_softc *acpi_sc;
154132501Snyan	ACPI_STATUS status;
155132501Snyan	int i;
156132501Snyan
157132501Snyan	sc = device_get_softc(dev);
158132501Snyan	sc->dev = dev;
159132501Snyan	sc->handle = acpi_get_handle(dev);
160132501Snyan
161132501Snyan	acpi_sc = acpi_device_get_parent_softc(dev);
162132501Snyan
163132501Snyan	/* Build sysctl tree */
164132501Snyan	sysctl_ctx_init(&sc->sysctl_ctx);
165132501Snyan	sc->sysctl_tree = SYSCTL_ADD_NODE(&sc->sysctl_ctx,
166132501Snyan	    SYSCTL_CHILDREN(acpi_sc->acpi_sysctl_tree), OID_AUTO,
167132501Snyan	    "panasonic", CTLFLAG_RD, 0, "");
168132501Snyan	for (i = 0; sysctl_table[i].name != NULL; i++) {
169132501Snyan		SYSCTL_ADD_PROC(&sc->sysctl_ctx,
170132611Snjl		    SYSCTL_CHILDREN(sc->sysctl_tree), OID_AUTO,
171132611Snjl		    sysctl_table[i].name,
172132611Snjl		    CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_ANYBODY,
173132611Snjl		    sc, i, acpi_panasonic_sysctl, "I", "");
174132501Snyan	}
175132501Snyan
176132501Snyan#if 0
177132501Snyan	/* Activate hotkeys */
178132501Snyan	status = AcpiEvaluateObject(sc->handle, "", NULL, NULL);
179132501Snyan	if (ACPI_FAILURE(status)) {
180132501Snyan		device_printf(dev, "enable FN keys failed\n");
181132501Snyan		sysctl_ctx_free(&sc->sysctl_ctx);
182132501Snyan		return (ENXIO);
183132501Snyan	}
184132501Snyan#endif
185132501Snyan
186170213Snjl	/* Handle notifies */
187132501Snyan	status = AcpiInstallNotifyHandler(sc->handle, ACPI_DEVICE_NOTIFY,
188132611Snjl	    acpi_panasonic_notify, sc);
189132501Snyan	if (ACPI_FAILURE(status)) {
190132501Snyan		device_printf(dev, "couldn't install notify handler - %s\n",
191132611Snjl		    AcpiFormatException(status));
192132501Snyan		sysctl_ctx_free(&sc->sysctl_ctx);
193132501Snyan		return (ENXIO);
194132501Snyan	}
195132501Snyan
196137365Snjl	/* Install power profile event handler */
197137365Snjl	sc->power_evh = EVENTHANDLER_REGISTER(power_profile_change,
198137365Snjl	    acpi_panasonic_power_profile, sc->handle, 0);
199137365Snjl
200132501Snyan	return (0);
201132501Snyan}
202132501Snyan
203132501Snyanstatic int
204132501Snyanacpi_panasonic_detach(device_t dev)
205132501Snyan{
206132501Snyan	struct acpi_panasonic_softc *sc;
207132501Snyan
208132501Snyan	sc = device_get_softc(dev);
209132501Snyan
210137365Snjl	/* Remove power profile event handler */
211137365Snjl	EVENTHANDLER_DEREGISTER(power_profile_change, sc->power_evh);
212137365Snjl
213132501Snyan	/* Remove notify handler */
214132501Snyan	AcpiRemoveNotifyHandler(sc->handle, ACPI_DEVICE_NOTIFY,
215132611Snjl	    acpi_panasonic_notify);
216132501Snyan
217132501Snyan	/* Free sysctl tree */
218132501Snyan	sysctl_ctx_free(&sc->sysctl_ctx);
219132501Snyan
220132501Snyan	return (0);
221132501Snyan}
222132501Snyan
223188162Simpstatic int
224170213Snjlacpi_panasonic_shutdown(device_t dev)
225170213Snjl{
226170213Snjl	struct acpi_panasonic_softc *sc;
227170213Snjl	int mute;
228170213Snjl
229170213Snjl	/* Mute the main audio during reboot to prevent static burst to speaker. */
230170213Snjl	sc = device_get_softc(dev);
231170213Snjl	mute = 1;
232170213Snjl	hkey_sound_mute(sc->handle, HKEY_SET, &mute);
233188162Simp	return (0);
234170213Snjl}
235170213Snjl
236132501Snyanstatic int
237132501Snyanacpi_panasonic_sysctl(SYSCTL_HANDLER_ARGS)
238132501Snyan{
239132501Snyan	struct acpi_panasonic_softc *sc;
240132501Snyan	UINT32 arg;
241132501Snyan	int function, error;
242132501Snyan	hkey_fn_t *handler;
243132501Snyan
244132501Snyan	sc = (struct acpi_panasonic_softc *)oidp->oid_arg1;
245132501Snyan	function = oidp->oid_arg2;
246132501Snyan	handler = sysctl_table[function].handler;
247132501Snyan
248170213Snjl	/* Get the current value from the appropriate function. */
249133629Snjl	ACPI_SERIAL_BEGIN(panasonic);
250132501Snyan	error = handler(sc->handle, HKEY_GET, &arg);
251132501Snyan	if (error != 0)
252133629Snjl		goto out;
253132501Snyan
254132501Snyan	/* Send the current value to the user and return if no new value. */
255132501Snyan	error = sysctl_handle_int(oidp, &arg, 0, req);
256132501Snyan	if (error != 0 || req->newptr == NULL)
257133629Snjl		goto out;
258132501Snyan
259132501Snyan	/* Set the new value via the appropriate function. */
260132501Snyan	error = handler(sc->handle, HKEY_SET, &arg);
261132501Snyan
262133629Snjlout:
263134258Snjl	ACPI_SERIAL_END(panasonic);
264132501Snyan	return (error);
265132501Snyan}
266132501Snyan
267132501Snyanstatic ACPI_INTEGER
268132501Snyanacpi_panasonic_sinf(ACPI_HANDLE h, ACPI_INTEGER index)
269132501Snyan{
270132501Snyan	ACPI_BUFFER buf;
271132501Snyan	ACPI_OBJECT *res;
272132501Snyan	ACPI_INTEGER ret;
273132501Snyan
274133629Snjl	ACPI_SERIAL_ASSERT(panasonic);
275132501Snyan	ret = -1;
276132501Snyan	buf.Length = ACPI_ALLOCATE_BUFFER;
277132501Snyan	buf.Pointer = NULL;
278132501Snyan	AcpiEvaluateObject(h, "SINF", NULL, &buf);
279132501Snyan	res = (ACPI_OBJECT *)buf.Pointer;
280132501Snyan	if (res->Type == ACPI_TYPE_PACKAGE)
281132501Snyan		ret = res->Package.Elements[index].Integer.Value;
282132501Snyan	AcpiOsFree(buf.Pointer);
283132501Snyan
284132501Snyan	return (ret);
285132501Snyan}
286132501Snyan
287132501Snyanstatic void
288132501Snyanacpi_panasonic_sset(ACPI_HANDLE h, ACPI_INTEGER index, ACPI_INTEGER val)
289132501Snyan{
290132501Snyan	ACPI_OBJECT_LIST args;
291132501Snyan	ACPI_OBJECT obj[2];
292132501Snyan
293133629Snjl	ACPI_SERIAL_ASSERT(panasonic);
294132501Snyan	obj[0].Type = ACPI_TYPE_INTEGER;
295132501Snyan	obj[0].Integer.Value = index;
296132501Snyan	obj[1].Type = ACPI_TYPE_INTEGER;
297132501Snyan	obj[1].Integer.Value = val;
298132501Snyan	args.Count = 2;
299132501Snyan	args.Pointer = obj;
300132501Snyan	AcpiEvaluateObject(h, "SSET", &args, NULL);
301132501Snyan}
302132501Snyan
303132501Snyanstatic int
304132501Snyanhkey_lcd_brightness_max(ACPI_HANDLE h, int op, UINT32 *val)
305132501Snyan{
306137365Snjl	int reg;
307132501Snyan
308133629Snjl	ACPI_SERIAL_ASSERT(panasonic);
309137365Snjl	reg = (power_profile_get_state() == POWER_PROFILE_PERFORMANCE) ?
310137365Snjl	    HKEY_REG_LCD_BRIGHTNESS_MAX_AC : HKEY_REG_LCD_BRIGHTNESS_MAX_DC;
311137365Snjl
312132501Snyan	switch (op) {
313132501Snyan	case HKEY_SET:
314137365Snjl		return (EPERM);
315132501Snyan		break;
316132501Snyan	case HKEY_GET:
317137365Snjl		*val = acpi_panasonic_sinf(h, reg);
318132501Snyan		break;
319132501Snyan	}
320132501Snyan
321132501Snyan	return (0);
322132501Snyan}
323132501Snyan
324132501Snyanstatic int
325137365Snjlhkey_lcd_brightness_min(ACPI_HANDLE h, int op, UINT32 *val)
326137365Snjl{
327137365Snjl	int reg;
328137365Snjl
329137365Snjl	ACPI_SERIAL_ASSERT(panasonic);
330137365Snjl	reg = (power_profile_get_state() == POWER_PROFILE_PERFORMANCE) ?
331137365Snjl	    HKEY_REG_LCD_BRIGHTNESS_MIN_AC : HKEY_REG_LCD_BRIGHTNESS_MIN_DC;
332137365Snjl
333137365Snjl	switch (op) {
334137365Snjl	case HKEY_SET:
335137365Snjl		return (EPERM);
336137365Snjl		break;
337137365Snjl	case HKEY_GET:
338137365Snjl		*val = acpi_panasonic_sinf(h, reg);
339137365Snjl		break;
340137365Snjl	}
341137365Snjl
342137365Snjl	return (0);
343137365Snjl}
344137365Snjl
345137365Snjlstatic int
346132501Snyanhkey_lcd_brightness(ACPI_HANDLE h, int op, UINT32 *val)
347132501Snyan{
348137365Snjl	int reg;
349137365Snjl	UINT32 max, min;
350132501Snyan
351137365Snjl	reg = (power_profile_get_state() == POWER_PROFILE_PERFORMANCE) ?
352137365Snjl	    HKEY_REG_LCD_BRIGHTNESS_AC : HKEY_REG_LCD_BRIGHTNESS_DC;
353137365Snjl
354133629Snjl	ACPI_SERIAL_ASSERT(panasonic);
355132501Snyan	switch (op) {
356132501Snyan	case HKEY_SET:
357137365Snjl		hkey_lcd_brightness_max(h, HKEY_GET, &max);
358137365Snjl		hkey_lcd_brightness_min(h, HKEY_GET, &min);
359137365Snjl		if (*val < min || *val > max)
360132501Snyan			return (EINVAL);
361137365Snjl		acpi_panasonic_sset(h, reg, *val);
362132501Snyan		break;
363132501Snyan	case HKEY_GET:
364137365Snjl		*val = acpi_panasonic_sinf(h, reg);
365132501Snyan		break;
366132501Snyan	}
367132501Snyan
368132501Snyan	return (0);
369132501Snyan}
370132501Snyan
371132501Snyanstatic int
372132501Snyanhkey_sound_mute(ACPI_HANDLE h, int op, UINT32 *val)
373132501Snyan{
374132501Snyan
375133629Snjl	ACPI_SERIAL_ASSERT(panasonic);
376132501Snyan	switch (op) {
377132501Snyan	case HKEY_SET:
378132501Snyan		if (*val != 0 && *val != 1)
379132501Snyan			return (EINVAL);
380132501Snyan		acpi_panasonic_sset(h, HKEY_REG_SOUND_MUTE, *val);
381132501Snyan		break;
382132501Snyan	case HKEY_GET:
383132501Snyan		*val = acpi_panasonic_sinf(h, HKEY_REG_SOUND_MUTE);
384132501Snyan		break;
385132501Snyan	}
386132501Snyan
387132501Snyan	return (0);
388132501Snyan}
389132501Snyan
390132501Snyanstatic int
391132501Snyanacpi_panasonic_hkey_event(struct acpi_panasonic_softc *sc, ACPI_HANDLE h,
392132611Snjl    UINT32 *arg)
393132501Snyan{
394132501Snyan	ACPI_BUFFER buf;
395132501Snyan	ACPI_OBJECT *res;
396132501Snyan	ACPI_INTEGER val;
397132501Snyan	int status;
398132501Snyan
399133629Snjl	ACPI_SERIAL_ASSERT(panasonic);
400132501Snyan	status = ENXIO;
401132501Snyan
402132501Snyan	buf.Length = ACPI_ALLOCATE_BUFFER;
403132501Snyan	buf.Pointer = NULL;
404132501Snyan	AcpiEvaluateObject(h, "HINF", NULL, &buf);
405132501Snyan	res = (ACPI_OBJECT *)buf.Pointer;
406132501Snyan	if (res->Type != ACPI_TYPE_INTEGER) {
407132501Snyan		device_printf(sc->dev, "HINF returned non-integer\n");
408132501Snyan		goto end;
409132501Snyan	}
410132501Snyan	val = res->Integer.Value;
411132501Snyan#ifdef ACPI_PANASONIC_DEBUG
412132501Snyan	device_printf(sc->dev, "%s button Fn+F%d\n",
413132501Snyan		      (val & 0x80) ? "Pressed" : "Released",
414132501Snyan		      (int)(val & 0x7f));
415132501Snyan#endif
416132501Snyan	if ((val & 0x7f) > 0 && (val & 0x7f) < 11) {
417132501Snyan		*arg = val;
418132501Snyan		status = 0;
419132501Snyan	}
420132501Snyanend:
421132501Snyan	if (buf.Pointer)
422132501Snyan		AcpiOsFree(buf.Pointer);
423132501Snyan
424132501Snyan	return (status);
425132501Snyan}
426132501Snyan
427132501Snyanstatic void
428132501Snyanacpi_panasonic_hkey_action(struct acpi_panasonic_softc *sc, ACPI_HANDLE h,
429132611Snjl    UINT32 key)
430132501Snyan{
431159253Snyan	struct acpi_softc *acpi_sc;
432137365Snjl	int arg, max, min;
433132501Snyan
434159253Snyan	acpi_sc = acpi_device_get_parent_softc(sc->dev);
435159253Snyan
436133629Snjl	ACPI_SERIAL_ASSERT(panasonic);
437132501Snyan	switch (key) {
438132501Snyan	case 1:
439132501Snyan		/* Decrease LCD brightness. */
440137365Snjl		hkey_lcd_brightness_max(h, HKEY_GET, &max);
441137365Snjl		hkey_lcd_brightness_min(h, HKEY_GET, &min);
442132501Snyan		hkey_lcd_brightness(h, HKEY_GET, &arg);
443137365Snjl		arg -= max / HKEY_LCD_BRIGHTNESS_DIV;
444137365Snjl		if (arg < min)
445137365Snjl			arg = min;
446137365Snjl		else if (arg > max)
447137365Snjl			arg = max;
448132501Snyan		hkey_lcd_brightness(h, HKEY_SET, &arg);
449132501Snyan		break;
450132501Snyan	case 2:
451132501Snyan		/* Increase LCD brightness. */
452137365Snjl		hkey_lcd_brightness_max(h, HKEY_GET, &max);
453137365Snjl		hkey_lcd_brightness_min(h, HKEY_GET, &min);
454132501Snyan		hkey_lcd_brightness(h, HKEY_GET, &arg);
455137365Snjl		arg += max / HKEY_LCD_BRIGHTNESS_DIV;
456137365Snjl		if (arg < min)
457137365Snjl			arg = min;
458137365Snjl		else if (arg > max)
459137365Snjl			arg = max;
460132501Snyan		hkey_lcd_brightness(h, HKEY_SET, &arg);
461132501Snyan		break;
462132501Snyan	case 4:
463132501Snyan		/* Toggle sound mute. */
464132501Snyan		hkey_sound_mute(h, HKEY_GET, &arg);
465132501Snyan		if (arg)
466132501Snyan			arg = 0;
467132501Snyan		else
468132501Snyan			arg = 1;
469132501Snyan		hkey_sound_mute(h, HKEY_SET, &arg);
470132501Snyan		break;
471159253Snyan	case 7:
472159253Snyan		/* Suspend. */
473159347Snyan		acpi_event_sleep_button_sleep(acpi_sc);
474159253Snyan		break;
475132501Snyan	}
476132501Snyan}
477132501Snyan
478132501Snyanstatic void
479132501Snyanacpi_panasonic_notify(ACPI_HANDLE h, UINT32 notify, void *context)
480132501Snyan{
481132501Snyan	struct acpi_panasonic_softc *sc;
482170871Smjacob	UINT32 key = 0;
483132501Snyan
484132501Snyan	sc = (struct acpi_panasonic_softc *)context;
485132501Snyan
486132501Snyan	switch (notify) {
487132501Snyan	case 0x80:
488133629Snjl		ACPI_SERIAL_BEGIN(panasonic);
489132501Snyan		if (acpi_panasonic_hkey_event(sc, h, &key) == 0) {
490132501Snyan			acpi_panasonic_hkey_action(sc, h, key);
491132501Snyan			acpi_UserNotify("Panasonic", h, (uint8_t)key);
492132501Snyan		}
493133629Snjl		ACPI_SERIAL_END(panasonic);
494132501Snyan		break;
495132501Snyan	default:
496132611Snjl		device_printf(sc->dev, "unknown notify: %#x\n", notify);
497132501Snyan		break;
498132501Snyan	}
499132501Snyan}
500137365Snjl
501137365Snjlstatic void
502137365Snjlacpi_panasonic_power_profile(void *arg)
503137365Snjl{
504137365Snjl	ACPI_HANDLE handle;
505137365Snjl	UINT32 brightness;
506137365Snjl
507137365Snjl	handle = (ACPI_HANDLE)arg;
508137365Snjl
509137365Snjl	/* Reset current brightness according to new power state. */
510137365Snjl	ACPI_SERIAL_BEGIN(panasonic);
511137365Snjl	hkey_lcd_brightness(handle, HKEY_GET, &brightness);
512137365Snjl	hkey_lcd_brightness(handle, HKEY_SET, &brightness);
513137365Snjl	ACPI_SERIAL_END(panasonic);
514137365Snjl}
515