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