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 #include "opt_acpi.h"
31ee6020c9SYoshihiro Takahashi #include <sys/param.h>
32e2e050c8SConrad Meyer #include <sys/bus.h>
33e2e050c8SConrad Meyer #include <sys/eventhandler.h>
34ee6020c9SYoshihiro Takahashi #include <sys/kernel.h>
35ee6020c9SYoshihiro Takahashi #include <sys/malloc.h>
36ee6020c9SYoshihiro Takahashi #include <sys/module.h>
37f3118682SNate Lawson #include <sys/power.h>
38ee6020c9SYoshihiro Takahashi
39129d3046SJung-uk Kim #include <contrib/dev/acpica/include/acpi.h>
40129d3046SJung-uk Kim
41ee6020c9SYoshihiro Takahashi #include <dev/acpica/acpivar.h>
42ee6020c9SYoshihiro Takahashi
43276cd921SNate Lawson #define _COMPONENT ACPI_OEM
44276cd921SNate Lawson ACPI_MODULE_NAME("Panasonic")
45276cd921SNate Lawson
46ee6020c9SYoshihiro Takahashi /* Debug */
47ee6020c9SYoshihiro Takahashi #undef ACPI_PANASONIC_DEBUG
48ee6020c9SYoshihiro Takahashi
49ee6020c9SYoshihiro Takahashi /* Operations */
50ee6020c9SYoshihiro Takahashi #define HKEY_SET 0
51ee6020c9SYoshihiro Takahashi #define HKEY_GET 1
52ee6020c9SYoshihiro Takahashi
53ee6020c9SYoshihiro Takahashi /* Functions */
54f3118682SNate Lawson #define HKEY_REG_LCD_BRIGHTNESS_MAX_AC 0x02
55f3118682SNate Lawson #define HKEY_REG_LCD_BRIGHTNESS_MIN_AC 0x03
56f3118682SNate Lawson #define HKEY_REG_LCD_BRIGHTNESS_AC 0x04
57f3118682SNate Lawson #define HKEY_REG_LCD_BRIGHTNESS_MAX_DC 0x05
58f3118682SNate Lawson #define HKEY_REG_LCD_BRIGHTNESS_MIN_DC 0x06
59f3118682SNate Lawson #define HKEY_REG_LCD_BRIGHTNESS_DC 0x07
60ee6020c9SYoshihiro Takahashi #define HKEY_REG_SOUND_MUTE 0x08
61ee6020c9SYoshihiro Takahashi
62ee6020c9SYoshihiro Takahashi /* Field definitions */
63ee6020c9SYoshihiro Takahashi #define HKEY_LCD_BRIGHTNESS_BITS 4
64ee6020c9SYoshihiro Takahashi #define HKEY_LCD_BRIGHTNESS_DIV ((1 << HKEY_LCD_BRIGHTNESS_BITS) - 1)
65ee6020c9SYoshihiro Takahashi
66ee6020c9SYoshihiro Takahashi struct acpi_panasonic_softc {
67ee6020c9SYoshihiro Takahashi device_t dev;
68ee6020c9SYoshihiro Takahashi ACPI_HANDLE handle;
69ee6020c9SYoshihiro Takahashi
70ee6020c9SYoshihiro Takahashi struct sysctl_ctx_list sysctl_ctx;
71ee6020c9SYoshihiro Takahashi struct sysctl_oid *sysctl_tree;
72f3118682SNate Lawson
73f3118682SNate Lawson eventhandler_tag power_evh;
74ee6020c9SYoshihiro Takahashi };
75ee6020c9SYoshihiro Takahashi
76ee6020c9SYoshihiro Takahashi /* Prototype for HKEY functions for getting/setting a value. */
77ee6020c9SYoshihiro Takahashi typedef int hkey_fn_t(ACPI_HANDLE, int, UINT32 *);
78ee6020c9SYoshihiro Takahashi
79ee6020c9SYoshihiro Takahashi static int acpi_panasonic_probe(device_t dev);
80ee6020c9SYoshihiro Takahashi static int acpi_panasonic_attach(device_t dev);
81ee6020c9SYoshihiro Takahashi static int acpi_panasonic_detach(device_t dev);
82e3545bccSWarner Losh static int acpi_panasonic_shutdown(device_t dev);
83ee6020c9SYoshihiro Takahashi static int acpi_panasonic_sysctl(SYSCTL_HANDLER_ARGS);
849a179dd8SJung-uk Kim static UINT64 acpi_panasonic_sinf(ACPI_HANDLE h, UINT64 index);
859a179dd8SJung-uk Kim static void acpi_panasonic_sset(ACPI_HANDLE h, UINT64 index,
869a179dd8SJung-uk Kim UINT64 val);
87ee6020c9SYoshihiro Takahashi static int acpi_panasonic_hkey_event(struct acpi_panasonic_softc *sc,
88ee6020c9SYoshihiro Takahashi ACPI_HANDLE h, UINT32 *arg);
89ee6020c9SYoshihiro Takahashi static void acpi_panasonic_hkey_action(struct acpi_panasonic_softc *sc,
90ee6020c9SYoshihiro Takahashi ACPI_HANDLE h, UINT32 key);
91ee6020c9SYoshihiro Takahashi static void acpi_panasonic_notify(ACPI_HANDLE h, UINT32 notify,
92ee6020c9SYoshihiro Takahashi void *context);
93f3118682SNate Lawson static void acpi_panasonic_power_profile(void *arg);
94ee6020c9SYoshihiro Takahashi
95be223480SNate Lawson static hkey_fn_t hkey_lcd_brightness_max;
96f3118682SNate Lawson static hkey_fn_t hkey_lcd_brightness_min;
97be223480SNate Lawson static hkey_fn_t hkey_lcd_brightness;
98be223480SNate Lawson static hkey_fn_t hkey_sound_mute;
99e8a162f4SNate Lawson ACPI_SERIAL_DECL(panasonic, "ACPI Panasonic extras");
100be223480SNate Lawson
101ee6020c9SYoshihiro Takahashi /* Table of sysctl names and HKEY functions to call. */
102ee6020c9SYoshihiro Takahashi static struct {
103ee6020c9SYoshihiro Takahashi char *name;
104ee6020c9SYoshihiro Takahashi hkey_fn_t *handler;
105ee6020c9SYoshihiro Takahashi } sysctl_table[] = {
106ee6020c9SYoshihiro Takahashi /* name, handler */
107ee6020c9SYoshihiro Takahashi {"lcd_brightness_max", hkey_lcd_brightness_max},
108f3118682SNate Lawson {"lcd_brightness_min", hkey_lcd_brightness_min},
109ee6020c9SYoshihiro Takahashi {"lcd_brightness", hkey_lcd_brightness},
110ee6020c9SYoshihiro Takahashi {"sound_mute", hkey_sound_mute},
111ee6020c9SYoshihiro Takahashi {NULL, NULL}
112ee6020c9SYoshihiro Takahashi };
113ee6020c9SYoshihiro Takahashi
114ee6020c9SYoshihiro Takahashi static device_method_t acpi_panasonic_methods[] = {
115ee6020c9SYoshihiro Takahashi DEVMETHOD(device_probe, acpi_panasonic_probe),
116ee6020c9SYoshihiro Takahashi DEVMETHOD(device_attach, acpi_panasonic_attach),
117ee6020c9SYoshihiro Takahashi DEVMETHOD(device_detach, acpi_panasonic_detach),
118bb05b80cSNate Lawson DEVMETHOD(device_shutdown, acpi_panasonic_shutdown),
119ee6020c9SYoshihiro Takahashi
12061bfd867SSofian Brabez DEVMETHOD_END
121ee6020c9SYoshihiro Takahashi };
122ee6020c9SYoshihiro Takahashi
123ee6020c9SYoshihiro Takahashi static driver_t acpi_panasonic_driver = {
124ee6020c9SYoshihiro Takahashi "acpi_panasonic",
125ee6020c9SYoshihiro Takahashi acpi_panasonic_methods,
126ee6020c9SYoshihiro Takahashi sizeof(struct acpi_panasonic_softc),
127ee6020c9SYoshihiro Takahashi };
128ee6020c9SYoshihiro Takahashi
129*90161e72SJohn Baldwin DRIVER_MODULE(acpi_panasonic, acpi, acpi_panasonic_driver, 0, 0);
130ee6020c9SYoshihiro Takahashi MODULE_DEPEND(acpi_panasonic, acpi, 1, 1, 1);
131ee6020c9SYoshihiro Takahashi
132ee6020c9SYoshihiro Takahashi static int
acpi_panasonic_probe(device_t dev)133ee6020c9SYoshihiro Takahashi acpi_panasonic_probe(device_t dev)
134ee6020c9SYoshihiro Takahashi {
135ee6020c9SYoshihiro Takahashi static char *mat_ids[] = { "MAT0019", NULL };
1365efca36fSTakanori Watanabe int rv;
137ee6020c9SYoshihiro Takahashi
138ee6020c9SYoshihiro Takahashi if (acpi_disabled("panasonic") ||
139ee6020c9SYoshihiro Takahashi device_get_unit(dev) != 0)
140ee6020c9SYoshihiro Takahashi return (ENXIO);
1415efca36fSTakanori Watanabe rv = ACPI_ID_PROBE(device_get_parent(dev), dev, mat_ids, NULL);
142ee6020c9SYoshihiro Takahashi
1435efca36fSTakanori Watanabe if (rv <= 0)
144ee6020c9SYoshihiro Takahashi device_set_desc(dev, "Panasonic Notebook Hotkeys");
1455efca36fSTakanori Watanabe return (rv);
146ee6020c9SYoshihiro Takahashi }
147ee6020c9SYoshihiro Takahashi
148ee6020c9SYoshihiro Takahashi static int
acpi_panasonic_attach(device_t dev)149ee6020c9SYoshihiro Takahashi acpi_panasonic_attach(device_t dev)
150ee6020c9SYoshihiro Takahashi {
151ee6020c9SYoshihiro Takahashi struct acpi_panasonic_softc *sc;
152ee6020c9SYoshihiro Takahashi struct acpi_softc *acpi_sc;
153ee6020c9SYoshihiro Takahashi ACPI_STATUS status;
154ee6020c9SYoshihiro Takahashi int i;
155ee6020c9SYoshihiro Takahashi
156ee6020c9SYoshihiro Takahashi sc = device_get_softc(dev);
157ee6020c9SYoshihiro Takahashi sc->dev = dev;
158ee6020c9SYoshihiro Takahashi sc->handle = acpi_get_handle(dev);
159ee6020c9SYoshihiro Takahashi
160ee6020c9SYoshihiro Takahashi acpi_sc = acpi_device_get_parent_softc(dev);
161ee6020c9SYoshihiro Takahashi
162ee6020c9SYoshihiro Takahashi /* Build sysctl tree */
163ee6020c9SYoshihiro Takahashi sysctl_ctx_init(&sc->sysctl_ctx);
164ee6020c9SYoshihiro Takahashi sc->sysctl_tree = SYSCTL_ADD_NODE(&sc->sysctl_ctx,
165ee6020c9SYoshihiro Takahashi SYSCTL_CHILDREN(acpi_sc->acpi_sysctl_tree), OID_AUTO,
1667029da5cSPawel Biernacki "panasonic", CTLFLAG_RD | CTLFLAG_MPSAFE, 0, "");
167ee6020c9SYoshihiro Takahashi for (i = 0; sysctl_table[i].name != NULL; i++) {
168ee6020c9SYoshihiro Takahashi SYSCTL_ADD_PROC(&sc->sysctl_ctx,
169ee6020c9SYoshihiro Takahashi SYSCTL_CHILDREN(sc->sysctl_tree), OID_AUTO,
170ee6020c9SYoshihiro Takahashi sysctl_table[i].name,
1717029da5cSPawel Biernacki CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_ANYBODY |
1726237a1ccSAlexander Motin CTLFLAG_MPSAFE, sc, i, acpi_panasonic_sysctl, "I", "");
173ee6020c9SYoshihiro Takahashi }
174ee6020c9SYoshihiro Takahashi
175ee6020c9SYoshihiro Takahashi #if 0
176ee6020c9SYoshihiro Takahashi /* Activate hotkeys */
177ee6020c9SYoshihiro Takahashi status = AcpiEvaluateObject(sc->handle, "", NULL, NULL);
178ee6020c9SYoshihiro Takahashi if (ACPI_FAILURE(status)) {
179ee6020c9SYoshihiro Takahashi device_printf(dev, "enable FN keys failed\n");
180ee6020c9SYoshihiro Takahashi sysctl_ctx_free(&sc->sysctl_ctx);
181ee6020c9SYoshihiro Takahashi return (ENXIO);
182ee6020c9SYoshihiro Takahashi }
183ee6020c9SYoshihiro Takahashi #endif
184ee6020c9SYoshihiro Takahashi
185ee6020c9SYoshihiro Takahashi /* Handle notifies */
186ee6020c9SYoshihiro Takahashi status = AcpiInstallNotifyHandler(sc->handle, ACPI_DEVICE_NOTIFY,
187ee6020c9SYoshihiro Takahashi acpi_panasonic_notify, sc);
188ee6020c9SYoshihiro Takahashi if (ACPI_FAILURE(status)) {
189ee6020c9SYoshihiro Takahashi device_printf(dev, "couldn't install notify handler - %s\n",
190ee6020c9SYoshihiro Takahashi AcpiFormatException(status));
191ee6020c9SYoshihiro Takahashi sysctl_ctx_free(&sc->sysctl_ctx);
192ee6020c9SYoshihiro Takahashi return (ENXIO);
193ee6020c9SYoshihiro Takahashi }
194ee6020c9SYoshihiro Takahashi
195f3118682SNate Lawson /* Install power profile event handler */
196f3118682SNate Lawson sc->power_evh = EVENTHANDLER_REGISTER(power_profile_change,
197f3118682SNate Lawson acpi_panasonic_power_profile, sc->handle, 0);
198f3118682SNate Lawson
199ee6020c9SYoshihiro Takahashi return (0);
200ee6020c9SYoshihiro Takahashi }
201ee6020c9SYoshihiro Takahashi
202ee6020c9SYoshihiro Takahashi static int
acpi_panasonic_detach(device_t dev)203ee6020c9SYoshihiro Takahashi acpi_panasonic_detach(device_t dev)
204ee6020c9SYoshihiro Takahashi {
205ee6020c9SYoshihiro Takahashi struct acpi_panasonic_softc *sc;
206ee6020c9SYoshihiro Takahashi
207ee6020c9SYoshihiro Takahashi sc = device_get_softc(dev);
208ee6020c9SYoshihiro Takahashi
209f3118682SNate Lawson /* Remove power profile event handler */
210f3118682SNate Lawson EVENTHANDLER_DEREGISTER(power_profile_change, sc->power_evh);
211f3118682SNate Lawson
212ee6020c9SYoshihiro Takahashi /* Remove notify handler */
213ee6020c9SYoshihiro Takahashi AcpiRemoveNotifyHandler(sc->handle, ACPI_DEVICE_NOTIFY,
214ee6020c9SYoshihiro Takahashi acpi_panasonic_notify);
215ee6020c9SYoshihiro Takahashi
216ee6020c9SYoshihiro Takahashi /* Free sysctl tree */
217ee6020c9SYoshihiro Takahashi sysctl_ctx_free(&sc->sysctl_ctx);
218ee6020c9SYoshihiro Takahashi
219ee6020c9SYoshihiro Takahashi return (0);
220ee6020c9SYoshihiro Takahashi }
221ee6020c9SYoshihiro Takahashi
222e3545bccSWarner Losh static int
acpi_panasonic_shutdown(device_t dev)223bb05b80cSNate Lawson acpi_panasonic_shutdown(device_t dev)
224bb05b80cSNate Lawson {
225bb05b80cSNate Lawson struct acpi_panasonic_softc *sc;
226bb05b80cSNate Lawson int mute;
227bb05b80cSNate Lawson
228bb05b80cSNate Lawson /* Mute the main audio during reboot to prevent static burst to speaker. */
229bb05b80cSNate Lawson sc = device_get_softc(dev);
230bb05b80cSNate Lawson mute = 1;
231bb05b80cSNate Lawson hkey_sound_mute(sc->handle, HKEY_SET, &mute);
232e3545bccSWarner Losh return (0);
233bb05b80cSNate Lawson }
234bb05b80cSNate Lawson
235ee6020c9SYoshihiro Takahashi static int
acpi_panasonic_sysctl(SYSCTL_HANDLER_ARGS)236ee6020c9SYoshihiro Takahashi acpi_panasonic_sysctl(SYSCTL_HANDLER_ARGS)
237ee6020c9SYoshihiro Takahashi {
238ee6020c9SYoshihiro Takahashi struct acpi_panasonic_softc *sc;
239ee6020c9SYoshihiro Takahashi UINT32 arg;
240ee6020c9SYoshihiro Takahashi int function, error;
241ee6020c9SYoshihiro Takahashi hkey_fn_t *handler;
242ee6020c9SYoshihiro Takahashi
243ee6020c9SYoshihiro Takahashi sc = (struct acpi_panasonic_softc *)oidp->oid_arg1;
244ee6020c9SYoshihiro Takahashi function = oidp->oid_arg2;
245ee6020c9SYoshihiro Takahashi handler = sysctl_table[function].handler;
246ee6020c9SYoshihiro Takahashi
247ee6020c9SYoshihiro Takahashi /* Get the current value from the appropriate function. */
248e8a162f4SNate Lawson ACPI_SERIAL_BEGIN(panasonic);
249ee6020c9SYoshihiro Takahashi error = handler(sc->handle, HKEY_GET, &arg);
250ee6020c9SYoshihiro Takahashi if (error != 0)
251e8a162f4SNate Lawson goto out;
252ee6020c9SYoshihiro Takahashi
253ee6020c9SYoshihiro Takahashi /* Send the current value to the user and return if no new value. */
254ee6020c9SYoshihiro Takahashi error = sysctl_handle_int(oidp, &arg, 0, req);
255ee6020c9SYoshihiro Takahashi if (error != 0 || req->newptr == NULL)
256e8a162f4SNate Lawson goto out;
257ee6020c9SYoshihiro Takahashi
258ee6020c9SYoshihiro Takahashi /* Set the new value via the appropriate function. */
259ee6020c9SYoshihiro Takahashi error = handler(sc->handle, HKEY_SET, &arg);
260ee6020c9SYoshihiro Takahashi
261e8a162f4SNate Lawson out:
2629f65aa03SNate Lawson ACPI_SERIAL_END(panasonic);
263ee6020c9SYoshihiro Takahashi return (error);
264ee6020c9SYoshihiro Takahashi }
265ee6020c9SYoshihiro Takahashi
2669a179dd8SJung-uk Kim static UINT64
acpi_panasonic_sinf(ACPI_HANDLE h,UINT64 index)2679a179dd8SJung-uk Kim acpi_panasonic_sinf(ACPI_HANDLE h, UINT64 index)
268ee6020c9SYoshihiro Takahashi {
269ee6020c9SYoshihiro Takahashi ACPI_BUFFER buf;
270ee6020c9SYoshihiro Takahashi ACPI_OBJECT *res;
2719a179dd8SJung-uk Kim UINT64 ret;
272ee6020c9SYoshihiro Takahashi
273e8a162f4SNate Lawson ACPI_SERIAL_ASSERT(panasonic);
274ee6020c9SYoshihiro Takahashi ret = -1;
275ee6020c9SYoshihiro Takahashi buf.Length = ACPI_ALLOCATE_BUFFER;
276ee6020c9SYoshihiro Takahashi buf.Pointer = NULL;
277ee6020c9SYoshihiro Takahashi AcpiEvaluateObject(h, "SINF", NULL, &buf);
278ee6020c9SYoshihiro Takahashi res = (ACPI_OBJECT *)buf.Pointer;
279ee6020c9SYoshihiro Takahashi if (res->Type == ACPI_TYPE_PACKAGE)
280ee6020c9SYoshihiro Takahashi ret = res->Package.Elements[index].Integer.Value;
281ee6020c9SYoshihiro Takahashi AcpiOsFree(buf.Pointer);
282ee6020c9SYoshihiro Takahashi
283ee6020c9SYoshihiro Takahashi return (ret);
284ee6020c9SYoshihiro Takahashi }
285ee6020c9SYoshihiro Takahashi
286ee6020c9SYoshihiro Takahashi static void
acpi_panasonic_sset(ACPI_HANDLE h,UINT64 index,UINT64 val)2879a179dd8SJung-uk Kim acpi_panasonic_sset(ACPI_HANDLE h, UINT64 index, UINT64 val)
288ee6020c9SYoshihiro Takahashi {
289ee6020c9SYoshihiro Takahashi ACPI_OBJECT_LIST args;
290ee6020c9SYoshihiro Takahashi ACPI_OBJECT obj[2];
291ee6020c9SYoshihiro Takahashi
292e8a162f4SNate Lawson ACPI_SERIAL_ASSERT(panasonic);
293ee6020c9SYoshihiro Takahashi obj[0].Type = ACPI_TYPE_INTEGER;
294ee6020c9SYoshihiro Takahashi obj[0].Integer.Value = index;
295ee6020c9SYoshihiro Takahashi obj[1].Type = ACPI_TYPE_INTEGER;
296ee6020c9SYoshihiro Takahashi obj[1].Integer.Value = val;
297ee6020c9SYoshihiro Takahashi args.Count = 2;
298ee6020c9SYoshihiro Takahashi args.Pointer = obj;
299ee6020c9SYoshihiro Takahashi AcpiEvaluateObject(h, "SSET", &args, NULL);
300ee6020c9SYoshihiro Takahashi }
301ee6020c9SYoshihiro Takahashi
302ee6020c9SYoshihiro Takahashi static int
hkey_lcd_brightness_max(ACPI_HANDLE h,int op,UINT32 * val)303ee6020c9SYoshihiro Takahashi hkey_lcd_brightness_max(ACPI_HANDLE h, int op, UINT32 *val)
304ee6020c9SYoshihiro Takahashi {
305f3118682SNate Lawson int reg;
306ee6020c9SYoshihiro Takahashi
307e8a162f4SNate Lawson ACPI_SERIAL_ASSERT(panasonic);
308f3118682SNate Lawson reg = (power_profile_get_state() == POWER_PROFILE_PERFORMANCE) ?
309f3118682SNate Lawson HKEY_REG_LCD_BRIGHTNESS_MAX_AC : HKEY_REG_LCD_BRIGHTNESS_MAX_DC;
310f3118682SNate Lawson
311ee6020c9SYoshihiro Takahashi switch (op) {
312ee6020c9SYoshihiro Takahashi case HKEY_SET:
313f3118682SNate Lawson return (EPERM);
314ee6020c9SYoshihiro Takahashi break;
315ee6020c9SYoshihiro Takahashi case HKEY_GET:
316f3118682SNate Lawson *val = acpi_panasonic_sinf(h, reg);
317f3118682SNate Lawson break;
318f3118682SNate Lawson }
319f3118682SNate Lawson
320f3118682SNate Lawson return (0);
321f3118682SNate Lawson }
322f3118682SNate Lawson
323f3118682SNate Lawson static int
hkey_lcd_brightness_min(ACPI_HANDLE h,int op,UINT32 * val)324f3118682SNate Lawson hkey_lcd_brightness_min(ACPI_HANDLE h, int op, UINT32 *val)
325f3118682SNate Lawson {
326f3118682SNate Lawson int reg;
327f3118682SNate Lawson
328f3118682SNate Lawson ACPI_SERIAL_ASSERT(panasonic);
329f3118682SNate Lawson reg = (power_profile_get_state() == POWER_PROFILE_PERFORMANCE) ?
330f3118682SNate Lawson HKEY_REG_LCD_BRIGHTNESS_MIN_AC : HKEY_REG_LCD_BRIGHTNESS_MIN_DC;
331f3118682SNate Lawson
332f3118682SNate Lawson switch (op) {
333f3118682SNate Lawson case HKEY_SET:
334f3118682SNate Lawson return (EPERM);
335f3118682SNate Lawson break;
336f3118682SNate Lawson case HKEY_GET:
337f3118682SNate Lawson *val = acpi_panasonic_sinf(h, reg);
338ee6020c9SYoshihiro Takahashi break;
339ee6020c9SYoshihiro Takahashi }
340ee6020c9SYoshihiro Takahashi
341ee6020c9SYoshihiro Takahashi return (0);
342ee6020c9SYoshihiro Takahashi }
343ee6020c9SYoshihiro Takahashi
344ee6020c9SYoshihiro Takahashi static int
hkey_lcd_brightness(ACPI_HANDLE h,int op,UINT32 * val)345ee6020c9SYoshihiro Takahashi hkey_lcd_brightness(ACPI_HANDLE h, int op, UINT32 *val)
346ee6020c9SYoshihiro Takahashi {
347f3118682SNate Lawson int reg;
348f3118682SNate Lawson UINT32 max, min;
349f3118682SNate Lawson
350f3118682SNate Lawson reg = (power_profile_get_state() == POWER_PROFILE_PERFORMANCE) ?
351f3118682SNate Lawson HKEY_REG_LCD_BRIGHTNESS_AC : HKEY_REG_LCD_BRIGHTNESS_DC;
352ee6020c9SYoshihiro Takahashi
353e8a162f4SNate Lawson ACPI_SERIAL_ASSERT(panasonic);
354ee6020c9SYoshihiro Takahashi switch (op) {
355ee6020c9SYoshihiro Takahashi case HKEY_SET:
356f3118682SNate Lawson hkey_lcd_brightness_max(h, HKEY_GET, &max);
357f3118682SNate Lawson hkey_lcd_brightness_min(h, HKEY_GET, &min);
358f3118682SNate Lawson if (*val < min || *val > max)
359ee6020c9SYoshihiro Takahashi return (EINVAL);
360f3118682SNate Lawson acpi_panasonic_sset(h, reg, *val);
361ee6020c9SYoshihiro Takahashi break;
362ee6020c9SYoshihiro Takahashi case HKEY_GET:
363f3118682SNate Lawson *val = acpi_panasonic_sinf(h, reg);
364ee6020c9SYoshihiro Takahashi break;
365ee6020c9SYoshihiro Takahashi }
366ee6020c9SYoshihiro Takahashi
367ee6020c9SYoshihiro Takahashi return (0);
368ee6020c9SYoshihiro Takahashi }
369ee6020c9SYoshihiro Takahashi
370ee6020c9SYoshihiro Takahashi static int
hkey_sound_mute(ACPI_HANDLE h,int op,UINT32 * val)371ee6020c9SYoshihiro Takahashi hkey_sound_mute(ACPI_HANDLE h, int op, UINT32 *val)
372ee6020c9SYoshihiro Takahashi {
373ee6020c9SYoshihiro Takahashi
374e8a162f4SNate Lawson ACPI_SERIAL_ASSERT(panasonic);
375ee6020c9SYoshihiro Takahashi switch (op) {
376ee6020c9SYoshihiro Takahashi case HKEY_SET:
377ee6020c9SYoshihiro Takahashi if (*val != 0 && *val != 1)
378ee6020c9SYoshihiro Takahashi return (EINVAL);
379ee6020c9SYoshihiro Takahashi acpi_panasonic_sset(h, HKEY_REG_SOUND_MUTE, *val);
380ee6020c9SYoshihiro Takahashi break;
381ee6020c9SYoshihiro Takahashi case HKEY_GET:
382ee6020c9SYoshihiro Takahashi *val = acpi_panasonic_sinf(h, HKEY_REG_SOUND_MUTE);
383ee6020c9SYoshihiro Takahashi break;
384ee6020c9SYoshihiro Takahashi }
385ee6020c9SYoshihiro Takahashi
386ee6020c9SYoshihiro Takahashi return (0);
387ee6020c9SYoshihiro Takahashi }
388ee6020c9SYoshihiro Takahashi
389ee6020c9SYoshihiro Takahashi static int
acpi_panasonic_hkey_event(struct acpi_panasonic_softc * sc,ACPI_HANDLE h,UINT32 * arg)390ee6020c9SYoshihiro Takahashi acpi_panasonic_hkey_event(struct acpi_panasonic_softc *sc, ACPI_HANDLE h,
391ee6020c9SYoshihiro Takahashi UINT32 *arg)
392ee6020c9SYoshihiro Takahashi {
393ee6020c9SYoshihiro Takahashi ACPI_BUFFER buf;
394ee6020c9SYoshihiro Takahashi ACPI_OBJECT *res;
3959a179dd8SJung-uk Kim UINT64 val;
396ee6020c9SYoshihiro Takahashi int status;
397ee6020c9SYoshihiro Takahashi
398e8a162f4SNate Lawson ACPI_SERIAL_ASSERT(panasonic);
399ee6020c9SYoshihiro Takahashi status = ENXIO;
400ee6020c9SYoshihiro Takahashi
401ee6020c9SYoshihiro Takahashi buf.Length = ACPI_ALLOCATE_BUFFER;
402ee6020c9SYoshihiro Takahashi buf.Pointer = NULL;
403ee6020c9SYoshihiro Takahashi AcpiEvaluateObject(h, "HINF", NULL, &buf);
404ee6020c9SYoshihiro Takahashi res = (ACPI_OBJECT *)buf.Pointer;
405ee6020c9SYoshihiro Takahashi if (res->Type != ACPI_TYPE_INTEGER) {
406ee6020c9SYoshihiro Takahashi device_printf(sc->dev, "HINF returned non-integer\n");
407ee6020c9SYoshihiro Takahashi goto end;
408ee6020c9SYoshihiro Takahashi }
409ee6020c9SYoshihiro Takahashi val = res->Integer.Value;
410ee6020c9SYoshihiro Takahashi #ifdef ACPI_PANASONIC_DEBUG
411ee6020c9SYoshihiro Takahashi device_printf(sc->dev, "%s button Fn+F%d\n",
412ee6020c9SYoshihiro Takahashi (val & 0x80) ? "Pressed" : "Released",
413ee6020c9SYoshihiro Takahashi (int)(val & 0x7f));
414ee6020c9SYoshihiro Takahashi #endif
415ee6020c9SYoshihiro Takahashi if ((val & 0x7f) > 0 && (val & 0x7f) < 11) {
416ee6020c9SYoshihiro Takahashi *arg = val;
417ee6020c9SYoshihiro Takahashi status = 0;
418ee6020c9SYoshihiro Takahashi }
419ee6020c9SYoshihiro Takahashi end:
420ee6020c9SYoshihiro Takahashi if (buf.Pointer)
421ee6020c9SYoshihiro Takahashi AcpiOsFree(buf.Pointer);
422ee6020c9SYoshihiro Takahashi
423ee6020c9SYoshihiro Takahashi return (status);
424ee6020c9SYoshihiro Takahashi }
425ee6020c9SYoshihiro Takahashi
426ee6020c9SYoshihiro Takahashi static void
acpi_panasonic_hkey_action(struct acpi_panasonic_softc * sc,ACPI_HANDLE h,UINT32 key)427ee6020c9SYoshihiro Takahashi acpi_panasonic_hkey_action(struct acpi_panasonic_softc *sc, ACPI_HANDLE h,
428ee6020c9SYoshihiro Takahashi UINT32 key)
429ee6020c9SYoshihiro Takahashi {
43014ecccdaSYoshihiro Takahashi struct acpi_softc *acpi_sc;
431f3118682SNate Lawson int arg, max, min;
432ee6020c9SYoshihiro Takahashi
43314ecccdaSYoshihiro Takahashi acpi_sc = acpi_device_get_parent_softc(sc->dev);
43414ecccdaSYoshihiro Takahashi
435e8a162f4SNate Lawson ACPI_SERIAL_ASSERT(panasonic);
436ee6020c9SYoshihiro Takahashi switch (key) {
437ee6020c9SYoshihiro Takahashi case 1:
438ee6020c9SYoshihiro Takahashi /* Decrease LCD brightness. */
439f3118682SNate Lawson hkey_lcd_brightness_max(h, HKEY_GET, &max);
440f3118682SNate Lawson hkey_lcd_brightness_min(h, HKEY_GET, &min);
441ee6020c9SYoshihiro Takahashi hkey_lcd_brightness(h, HKEY_GET, &arg);
442f3118682SNate Lawson arg -= max / HKEY_LCD_BRIGHTNESS_DIV;
443f3118682SNate Lawson if (arg < min)
444f3118682SNate Lawson arg = min;
445f3118682SNate Lawson else if (arg > max)
446f3118682SNate Lawson arg = max;
447ee6020c9SYoshihiro Takahashi hkey_lcd_brightness(h, HKEY_SET, &arg);
448ee6020c9SYoshihiro Takahashi break;
449ee6020c9SYoshihiro Takahashi case 2:
450ee6020c9SYoshihiro Takahashi /* Increase LCD brightness. */
451f3118682SNate Lawson hkey_lcd_brightness_max(h, HKEY_GET, &max);
452f3118682SNate Lawson hkey_lcd_brightness_min(h, HKEY_GET, &min);
453ee6020c9SYoshihiro Takahashi hkey_lcd_brightness(h, HKEY_GET, &arg);
454f3118682SNate Lawson arg += max / HKEY_LCD_BRIGHTNESS_DIV;
455f3118682SNate Lawson if (arg < min)
456f3118682SNate Lawson arg = min;
457f3118682SNate Lawson else if (arg > max)
458f3118682SNate Lawson arg = max;
459ee6020c9SYoshihiro Takahashi hkey_lcd_brightness(h, HKEY_SET, &arg);
460ee6020c9SYoshihiro Takahashi break;
461ee6020c9SYoshihiro Takahashi case 4:
462ee6020c9SYoshihiro Takahashi /* Toggle sound mute. */
463ee6020c9SYoshihiro Takahashi hkey_sound_mute(h, HKEY_GET, &arg);
464ee6020c9SYoshihiro Takahashi if (arg)
465ee6020c9SYoshihiro Takahashi arg = 0;
466ee6020c9SYoshihiro Takahashi else
467ee6020c9SYoshihiro Takahashi arg = 1;
468ee6020c9SYoshihiro Takahashi hkey_sound_mute(h, HKEY_SET, &arg);
469ee6020c9SYoshihiro Takahashi break;
47014ecccdaSYoshihiro Takahashi case 7:
47114ecccdaSYoshihiro Takahashi /* Suspend. */
472d6da5e88SYoshihiro Takahashi acpi_event_sleep_button_sleep(acpi_sc);
47314ecccdaSYoshihiro Takahashi break;
474ee6020c9SYoshihiro Takahashi }
475ee6020c9SYoshihiro Takahashi }
476ee6020c9SYoshihiro Takahashi
477ee6020c9SYoshihiro Takahashi static void
acpi_panasonic_notify(ACPI_HANDLE h,UINT32 notify,void * context)478ee6020c9SYoshihiro Takahashi acpi_panasonic_notify(ACPI_HANDLE h, UINT32 notify, void *context)
479ee6020c9SYoshihiro Takahashi {
480ee6020c9SYoshihiro Takahashi struct acpi_panasonic_softc *sc;
4816eb9bbf3SMatt Jacob UINT32 key = 0;
482ee6020c9SYoshihiro Takahashi
483ee6020c9SYoshihiro Takahashi sc = (struct acpi_panasonic_softc *)context;
484ee6020c9SYoshihiro Takahashi
485ee6020c9SYoshihiro Takahashi switch (notify) {
486ee6020c9SYoshihiro Takahashi case 0x80:
487e8a162f4SNate Lawson ACPI_SERIAL_BEGIN(panasonic);
488ee6020c9SYoshihiro Takahashi if (acpi_panasonic_hkey_event(sc, h, &key) == 0) {
489ee6020c9SYoshihiro Takahashi acpi_panasonic_hkey_action(sc, h, key);
490ee6020c9SYoshihiro Takahashi acpi_UserNotify("Panasonic", h, (uint8_t)key);
491ee6020c9SYoshihiro Takahashi }
492e8a162f4SNate Lawson ACPI_SERIAL_END(panasonic);
493ee6020c9SYoshihiro Takahashi break;
494a8fefd0eSShunsuke Akiyama case 0x81:
495a8fefd0eSShunsuke Akiyama if (!bootverbose)
496a8fefd0eSShunsuke Akiyama break;
497a8fefd0eSShunsuke Akiyama /* FALLTHROUGH */
498ee6020c9SYoshihiro Takahashi default:
499be223480SNate Lawson device_printf(sc->dev, "unknown notify: %#x\n", notify);
500ee6020c9SYoshihiro Takahashi break;
501ee6020c9SYoshihiro Takahashi }
502ee6020c9SYoshihiro Takahashi }
503f3118682SNate Lawson
504f3118682SNate Lawson static void
acpi_panasonic_power_profile(void * arg)505f3118682SNate Lawson acpi_panasonic_power_profile(void *arg)
506f3118682SNate Lawson {
507f3118682SNate Lawson ACPI_HANDLE handle;
508f3118682SNate Lawson UINT32 brightness;
509f3118682SNate Lawson
510f3118682SNate Lawson handle = (ACPI_HANDLE)arg;
511f3118682SNate Lawson
512f3118682SNate Lawson /* Reset current brightness according to new power state. */
513f3118682SNate Lawson ACPI_SERIAL_BEGIN(panasonic);
514f3118682SNate Lawson hkey_lcd_brightness(handle, HKEY_GET, &brightness);
515f3118682SNate Lawson hkey_lcd_brightness(handle, HKEY_SET, &brightness);
516f3118682SNate Lawson ACPI_SERIAL_END(panasonic);
517f3118682SNate Lawson }
518