1143794Sphilip/*- 2143794Sphilip * Copyright (c) 2002 Sean Bullington <seanATstalker.org> 3216376Savg * 2003-2008 Anish Mistry <amistry@am-productions.biz> 4143794Sphilip * 2004 Mark Santcroos <marks@ripe.net> 5143794Sphilip * All Rights Reserved. 6143794Sphilip * 7143794Sphilip * Redistribution and use in source and binary forms, with or without 8143794Sphilip * modification, are permitted provided that the following conditions 9143794Sphilip * are met: 10143794Sphilip * 1. Redistributions of source code must retain the above copyright 11143794Sphilip * notice, this list of conditions and the following disclaimer. 12143794Sphilip * 2. Redistributions in binary form must reproduce the above copyright 13143794Sphilip * notice, this list of conditions and the following disclaimer in the 14143794Sphilip * documentation and/or other materials provided with the distribution. 15143794Sphilip * 16143794Sphilip * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 17143794Sphilip * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 18143794Sphilip * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 19143794Sphilip * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 20143794Sphilip * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 21143794Sphilip * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 22143794Sphilip * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 23143794Sphilip * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 24143794Sphilip * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 25143794Sphilip * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 26143794Sphilip * SUCH DAMAGE. 27143794Sphilip * 28143794Sphilip */ 29143794Sphilip 30143794Sphilip#include <sys/cdefs.h> 31143794Sphilip__FBSDID("$FreeBSD$"); 32143794Sphilip 33143794Sphilip#include "opt_acpi.h" 34143794Sphilip#include <sys/param.h> 35143794Sphilip#include <sys/kernel.h> 36143794Sphilip#include <sys/bus.h> 37143794Sphilip#include <sys/module.h> 38143794Sphilip#include <sys/sysctl.h> 39143794Sphilip 40193530Sjkim#include <contrib/dev/acpica/include/acpi.h> 41193530Sjkim#include <contrib/dev/acpica/include/accommon.h> 42193530Sjkim 43143794Sphilip#include <dev/acpica/acpivar.h> 44143794Sphilip 45143794Sphilip/* Hooks for the ACPI CA debugging infrastructure */ 46143794Sphilip#define _COMPONENT ACPI_OEM 47143794SphilipACPI_MODULE_NAME("Fujitsu") 48143794Sphilip 49155020Sphilip/* Change and update bits for the hotkeys */ 50143794Sphilip#define VOLUME_MUTE_BIT 0x40000000 51143794Sphilip 52143794Sphilip/* Values of settings */ 53143794Sphilip#define GENERAL_SETTING_BITS 0x0fffffff 54143794Sphilip#define MOUSE_SETTING_BITS GENERAL_SETTING_BITS 55143794Sphilip#define VOLUME_SETTING_BITS GENERAL_SETTING_BITS 56143794Sphilip#define BRIGHTNESS_SETTING_BITS GENERAL_SETTING_BITS 57143794Sphilip 58143794Sphilip/* Possible state changes */ 59155020Sphilip/* 60155020Sphilip * These are NOT arbitrary values. They are the 61155020Sphilip * GHKS return value from the device that says which 62155020Sphilip * hotkey is active. They should match up with a bit 63155020Sphilip * from the GSIF bitmask. 64155020Sphilip */ 65155020Sphilip#define BRIGHT_CHANGED 0x01 66155020Sphilip#define VOLUME_CHANGED 0x04 67155020Sphilip#define MOUSE_CHANGED 0x08 68155020Sphilip/* 69155020Sphilip * It is unknown which hotkey this bit is supposed to indicate, but 70155020Sphilip * according to values from GSIF this is a valid flag. 71155020Sphilip */ 72155020Sphilip#define UNKNOWN_CHANGED 0x10 73143794Sphilip 74143794Sphilip/* sysctl values */ 75143794Sphilip#define FN_MUTE 0 76143794Sphilip#define FN_POINTER_ENABLE 1 77143794Sphilip#define FN_LCD_BRIGHTNESS 2 78143794Sphilip#define FN_VOLUME 3 79143794Sphilip 80143794Sphilip/* Methods */ 81143794Sphilip#define METHOD_GBLL 1 82143794Sphilip#define METHOD_GMOU 2 83143794Sphilip#define METHOD_GVOL 3 84143794Sphilip#define METHOD_MUTE 4 85155020Sphilip#define METHOD_RBLL 5 86155020Sphilip#define METHOD_RVOL 6 87155020Sphilip#define METHOD_GSIF 7 88155020Sphilip#define METHOD_GHKS 8 89216376Savg#define METHOD_GBLS 9 90143794Sphilip 91143794Sphilip/* Notify event */ 92143794Sphilip#define ACPI_NOTIFY_STATUS_CHANGED 0x80 93143794Sphilip 94143794Sphilip/* 95143794Sphilip * Holds a control method name and its associated integer value. 96143794Sphilip * Only used for no-argument control methods which return a value. 97143794Sphilip */ 98143794Sphilipstruct int_nameval { 99143794Sphilip char *name; 100143794Sphilip int value; 101155020Sphilip int exists; 102143794Sphilip}; 103143794Sphilip 104143794Sphilip/* 105143794Sphilip * Driver extension for the FUJITSU ACPI driver. 106143794Sphilip */ 107143794Sphilipstruct acpi_fujitsu_softc { 108143794Sphilip device_t dev; 109143794Sphilip ACPI_HANDLE handle; 110143794Sphilip 111143794Sphilip /* Control methods */ 112143794Sphilip struct int_nameval _sta, /* unused */ 113143794Sphilip gbll, /* brightness */ 114216376Savg gbls, /* get brightness state */ 115155020Sphilip ghks, /* hotkey selector */ 116155020Sphilip gbuf, /* unused (buffer?) */ 117143794Sphilip gmou, /* mouse */ 118155020Sphilip gsif, /* function key bitmask */ 119143794Sphilip gvol, /* volume */ 120155020Sphilip rbll, /* number of brightness levels (radix) */ 121155020Sphilip rvol; /* number of volume levels (radix) */ 122143794Sphilip 123143794Sphilip /* State variables */ 124143794Sphilip uint8_t bIsMuted; /* Is volume muted */ 125143794Sphilip uint8_t bIntPtrEnabled; /* Is internal ptr enabled */ 126143794Sphilip uint32_t lastValChanged; /* The last value updated */ 127143794Sphilip 128143794Sphilip /* sysctl tree */ 129143794Sphilip struct sysctl_ctx_list sysctl_ctx; 130143794Sphilip struct sysctl_oid *sysctl_tree; 131143794Sphilip}; 132143794Sphilip 133143794Sphilip/* Driver entry point forward declarations. */ 134143794Sphilipstatic int acpi_fujitsu_probe(device_t dev); 135143794Sphilipstatic int acpi_fujitsu_attach(device_t dev); 136143794Sphilipstatic int acpi_fujitsu_detach(device_t dev); 137143794Sphilipstatic int acpi_fujitsu_suspend(device_t dev); 138143794Sphilipstatic int acpi_fujitsu_resume(device_t dev); 139143794Sphilip 140143794Sphilipstatic void acpi_fujitsu_notify_status_changed(void *arg); 141143794Sphilipstatic void acpi_fujitsu_notify_handler(ACPI_HANDLE h, uint32_t notify, void *context); 142143794Sphilipstatic int acpi_fujitsu_sysctl(SYSCTL_HANDLER_ARGS); 143143794Sphilip 144143794Sphilip/* Utility function declarations */ 145143794Sphilipstatic uint8_t acpi_fujitsu_update(struct acpi_fujitsu_softc *sc); 146143794Sphilipstatic uint8_t acpi_fujitsu_init(struct acpi_fujitsu_softc *sc); 147155020Sphilipstatic uint8_t acpi_fujitsu_check_hardware(struct acpi_fujitsu_softc *sc); 148143794Sphilip 149143794Sphilip/* Driver/Module specific structure definitions. */ 150143794Sphilipstatic device_method_t acpi_fujitsu_methods[] = { 151143794Sphilip /* Device interface */ 152143794Sphilip DEVMETHOD(device_probe, acpi_fujitsu_probe), 153143794Sphilip DEVMETHOD(device_attach, acpi_fujitsu_attach), 154143794Sphilip DEVMETHOD(device_detach, acpi_fujitsu_detach), 155143794Sphilip DEVMETHOD(device_suspend, acpi_fujitsu_suspend), 156143794Sphilip DEVMETHOD(device_resume, acpi_fujitsu_resume), 157246128Ssbz 158246128Ssbz DEVMETHOD_END 159143794Sphilip}; 160143794Sphilip 161143794Sphilipstatic driver_t acpi_fujitsu_driver = { 162143794Sphilip "acpi_fujitsu", 163143794Sphilip acpi_fujitsu_methods, 164143794Sphilip sizeof(struct acpi_fujitsu_softc), 165143794Sphilip}; 166143794Sphilip 167155020Sphilip/* Prototype for function hotkeys for getting/setting a value. */ 168143794Sphilipstatic int acpi_fujitsu_method_get(struct acpi_fujitsu_softc *sc, int method); 169143794Sphilipstatic int acpi_fujitsu_method_set(struct acpi_fujitsu_softc *sc, int method, int value); 170143794Sphilip 171143794Sphilipstatic char *fujitsu_ids[] = { "FUJ02B1", NULL }; 172143794Sphilip 173155020SphilipACPI_SERIAL_DECL(fujitsu, "Fujitsu Function Hotkeys"); 174143794Sphilip 175143794Sphilip/* sysctl names and function calls */ 176143794Sphilipstatic struct { 177143794Sphilip char *name; 178143794Sphilip int method; 179143794Sphilip char *description; 180143794Sphilip} sysctl_table[] = { 181143794Sphilip { 182143794Sphilip .name = "mute", 183143794Sphilip .method = METHOD_MUTE, 184143794Sphilip .description = "Speakers/headphones mute status" 185143794Sphilip }, 186143794Sphilip { 187143794Sphilip .name = "pointer_enable", 188143794Sphilip .method = METHOD_GMOU, 189143794Sphilip .description = "Enable and disable the internal pointer" 190143794Sphilip }, 191143794Sphilip { 192143794Sphilip .name = "lcd_brightness", 193143794Sphilip .method = METHOD_GBLL, 194143794Sphilip .description = "Brightness level of the LCD panel" 195143794Sphilip }, 196143794Sphilip { 197216376Savg .name = "lcd_brightness", 198216376Savg .method = METHOD_GBLS, 199216376Savg .description = "Brightness level of the LCD panel" 200216376Savg }, 201216376Savg { 202143794Sphilip .name = "volume", 203143794Sphilip .method = METHOD_GVOL, 204143794Sphilip .description = "Speakers/headphones volume level" 205143794Sphilip }, 206155020Sphilip { 207155020Sphilip .name = "volume_radix", 208155020Sphilip .method = METHOD_RVOL, 209155020Sphilip .description = "Number of volume level steps" 210155020Sphilip }, 211155020Sphilip { 212155020Sphilip .name = "lcd_brightness_radix", 213155020Sphilip .method = METHOD_RBLL, 214155020Sphilip .description = "Number of brightness level steps" 215155020Sphilip }, 216143794Sphilip 217143794Sphilip { NULL, 0, NULL } 218143794Sphilip}; 219143794Sphilip 220143794Sphilipstatic devclass_t acpi_fujitsu_devclass; 221143794SphilipDRIVER_MODULE(acpi_fujitsu, acpi, acpi_fujitsu_driver, 222143794Sphilip acpi_fujitsu_devclass, 0, 0); 223143794SphilipMODULE_DEPEND(acpi_fujitsu, acpi, 1, 1, 1); 224143794SphilipMODULE_VERSION(acpi_fujitsu, 1); 225143794Sphilip 226143794Sphilipstatic int 227143794Sphilipacpi_fujitsu_probe(device_t dev) 228143794Sphilip{ 229155020Sphilip char *name; 230155020Sphilip char buffer[64]; 231143794Sphilip 232155020Sphilip name = ACPI_ID_PROBE(device_get_parent(dev), dev, fujitsu_ids); 233155020Sphilip if (acpi_disabled("fujitsu") || name == NULL || 234155020Sphilip device_get_unit(dev) > 1) 235143794Sphilip return (ENXIO); 236143794Sphilip 237155020Sphilip sprintf(buffer, "Fujitsu Function Hotkeys %s", name); 238155020Sphilip device_set_desc_copy(dev, buffer); 239143794Sphilip 240143794Sphilip return (0); 241143794Sphilip} 242143794Sphilip 243143794Sphilipstatic int 244143794Sphilipacpi_fujitsu_attach(device_t dev) 245143794Sphilip{ 246143794Sphilip struct acpi_fujitsu_softc *sc; 247143794Sphilip 248143794Sphilip ACPI_FUNCTION_TRACE((char *)(uintptr_t)__func__); 249143794Sphilip 250143794Sphilip sc = device_get_softc(dev); 251143794Sphilip sc->dev = dev; 252143794Sphilip sc->handle = acpi_get_handle(dev); 253143794Sphilip 254143794Sphilip /* Install notification handler */ 255143794Sphilip AcpiInstallNotifyHandler(sc->handle, ACPI_DEVICE_NOTIFY, 256143794Sphilip acpi_fujitsu_notify_handler, sc); 257143794Sphilip 258182864Sed /* Snag our default values for the hotkeys / hotkey states. */ 259144623Sphilip ACPI_SERIAL_BEGIN(fujitsu); 260144623Sphilip if (!acpi_fujitsu_init(sc)) 261155020Sphilip device_printf(dev, "Couldn't initialize hotkey states!\n"); 262144623Sphilip ACPI_SERIAL_END(fujitsu); 263143794Sphilip 264143794Sphilip return (0); 265143794Sphilip} 266143794Sphilip 267143794Sphilip/* 268143794Sphilip * Called when the system is being suspended, simply 269143794Sphilip * set an event to be signalled when we wake up. 270143794Sphilip */ 271143794Sphilipstatic int 272143794Sphilipacpi_fujitsu_suspend(device_t dev) 273143794Sphilip{ 274143794Sphilip 275143794Sphilip return (0); 276143794Sphilip} 277143794Sphilip 278143794Sphilipstatic int 279143794Sphilipacpi_fujitsu_resume(device_t dev) 280143794Sphilip{ 281143794Sphilip struct acpi_fujitsu_softc *sc; 282143794Sphilip ACPI_STATUS status; 283143794Sphilip 284143794Sphilip sc = device_get_softc(dev); 285143794Sphilip 286143794Sphilip /* 287143794Sphilip * The pointer needs to be re-enabled for 288143794Sphilip * some revisions of the P series (2120). 289143794Sphilip */ 290143794Sphilip ACPI_SERIAL_BEGIN(fujitsu); 291143794Sphilip 292155020Sphilip if(sc->gmou.exists) { 293155020Sphilip status = acpi_SetInteger(sc->handle, "SMOU", 1); 294155020Sphilip if (ACPI_FAILURE(status)) 295155020Sphilip device_printf(sc->dev, "Couldn't enable pointer\n"); 296155020Sphilip } 297143794Sphilip ACPI_SERIAL_END(fujitsu); 298143794Sphilip 299143794Sphilip return (0); 300143794Sphilip} 301143794Sphilip 302143794Sphilipstatic void 303143794Sphilipacpi_fujitsu_notify_status_changed(void *arg) 304143794Sphilip{ 305143794Sphilip struct acpi_fujitsu_softc *sc; 306143794Sphilip 307143794Sphilip ACPI_FUNCTION_TRACE((char *)(uintptr_t)__func__); 308143794Sphilip 309143794Sphilip sc = (struct acpi_fujitsu_softc *)arg; 310143794Sphilip 311143794Sphilip /* 312143794Sphilip * Since our notify function is called, we know something has 313143794Sphilip * happened. So the only reason for acpi_fujitsu_update to fail 314143794Sphilip * is if we can't find what has changed or an error occurs. 315143794Sphilip */ 316143794Sphilip ACPI_SERIAL_BEGIN(fujitsu); 317143794Sphilip acpi_fujitsu_update(sc); 318143794Sphilip ACPI_SERIAL_END(fujitsu); 319143794Sphilip} 320143794Sphilip 321143794Sphilip 322143794Sphilipstatic void 323143794Sphilipacpi_fujitsu_notify_handler(ACPI_HANDLE h, uint32_t notify, void *context) 324143794Sphilip{ 325143794Sphilip struct acpi_fujitsu_softc *sc; 326143794Sphilip 327143794Sphilip ACPI_FUNCTION_TRACE_U32((char *)(uintptr_t)__func__, notify); 328143794Sphilip 329143794Sphilip sc = (struct acpi_fujitsu_softc *)context; 330143794Sphilip 331143794Sphilip switch (notify) { 332143794Sphilip case ACPI_NOTIFY_STATUS_CHANGED: 333167814Sjkim AcpiOsExecute(OSL_NOTIFY_HANDLER, 334143794Sphilip acpi_fujitsu_notify_status_changed, sc); 335143794Sphilip break; 336143794Sphilip default: 337143794Sphilip /* unknown notification value */ 338143794Sphilip break; 339143794Sphilip } 340143794Sphilip} 341143794Sphilip 342143794Sphilipstatic int 343143794Sphilipacpi_fujitsu_detach(device_t dev) 344143794Sphilip{ 345143794Sphilip struct acpi_fujitsu_softc *sc; 346143794Sphilip 347143794Sphilip sc = device_get_softc(dev); 348143794Sphilip AcpiRemoveNotifyHandler(sc->handle, ACPI_DEVICE_NOTIFY, 349143794Sphilip acpi_fujitsu_notify_handler); 350143794Sphilip 351143794Sphilip sysctl_ctx_free(&sc->sysctl_ctx); 352143794Sphilip 353143794Sphilip return (0); 354143794Sphilip} 355143794Sphilip 356143794Sphilip/* 357143794Sphilip * Initializes the names of the ACPI control methods and grabs 358155020Sphilip * the current state of all of the ACPI hotkeys into the softc. 359143794Sphilip */ 360143794Sphilipstatic uint8_t 361143794Sphilipacpi_fujitsu_init(struct acpi_fujitsu_softc *sc) 362143794Sphilip{ 363143794Sphilip struct acpi_softc *acpi_sc; 364155020Sphilip int i, exists; 365143794Sphilip 366143794Sphilip ACPI_SERIAL_ASSERT(fujitsu); 367143794Sphilip 368143794Sphilip /* Setup all of the names for each control method */ 369143794Sphilip sc->_sta.name = "_STA"; 370143794Sphilip sc->gbll.name = "GBLL"; 371216376Savg sc->gbls.name = "GBLS"; 372143794Sphilip sc->ghks.name = "GHKS"; 373143794Sphilip sc->gmou.name = "GMOU"; 374143794Sphilip sc->gsif.name = "GSIF"; 375143794Sphilip sc->gvol.name = "GVOL"; 376155020Sphilip sc->ghks.name = "GHKS"; 377155020Sphilip sc->gsif.name = "GSIF"; 378143794Sphilip sc->rbll.name = "RBLL"; 379143794Sphilip sc->rvol.name = "RVOL"; 380143794Sphilip 381155020Sphilip /* Determine what hardware functionality is available */ 382155020Sphilip acpi_fujitsu_check_hardware(sc); 383155020Sphilip 384143794Sphilip /* Build the sysctl tree */ 385143794Sphilip acpi_sc = acpi_device_get_parent_softc(sc->dev); 386143794Sphilip sysctl_ctx_init(&sc->sysctl_ctx); 387143794Sphilip sc->sysctl_tree = SYSCTL_ADD_NODE(&sc->sysctl_ctx, 388143794Sphilip SYSCTL_CHILDREN(acpi_sc->acpi_sysctl_tree), 389143794Sphilip OID_AUTO, "fujitsu", CTLFLAG_RD, 0, ""); 390143794Sphilip 391143794Sphilip for (i = 0; sysctl_table[i].name != NULL; i++) { 392155020Sphilip switch(sysctl_table[i].method) { 393155020Sphilip case METHOD_GMOU: 394155020Sphilip exists = sc->gmou.exists; 395155020Sphilip break; 396155020Sphilip case METHOD_GBLL: 397155020Sphilip exists = sc->gbll.exists; 398155020Sphilip break; 399216376Savg case METHOD_GBLS: 400216376Savg exists = sc->gbls.exists; 401216376Savg break; 402155020Sphilip case METHOD_GVOL: 403155020Sphilip case METHOD_MUTE: 404155020Sphilip exists = sc->gvol.exists; 405155020Sphilip break; 406155020Sphilip case METHOD_RVOL: 407155020Sphilip exists = sc->rvol.exists; 408155020Sphilip break; 409155020Sphilip case METHOD_RBLL: 410155020Sphilip exists = sc->rbll.exists; 411155020Sphilip break; 412155020Sphilip default: 413155020Sphilip /* Allow by default */ 414155020Sphilip exists = 1; 415155020Sphilip break; 416155020Sphilip } 417155020Sphilip if(!exists) 418155020Sphilip continue; 419143794Sphilip SYSCTL_ADD_PROC(&sc->sysctl_ctx, 420143794Sphilip SYSCTL_CHILDREN(sc->sysctl_tree), OID_AUTO, 421143794Sphilip sysctl_table[i].name, 422143794Sphilip CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_ANYBODY, 423143794Sphilip sc, i, acpi_fujitsu_sysctl, "I", 424143794Sphilip sysctl_table[i].description); 425143794Sphilip } 426143794Sphilip 427155020Sphilip 428155020Sphilip /* Set the hotkeys to their initial states */ 429143794Sphilip if (!acpi_fujitsu_update(sc)) { 430155020Sphilip device_printf(sc->dev, "Couldn't init hotkey states\n"); 431143794Sphilip return (FALSE); 432143794Sphilip } 433143794Sphilip 434143794Sphilip return (TRUE); 435143794Sphilip} 436143794Sphilip 437143794Sphilipstatic int 438143794Sphilipacpi_fujitsu_sysctl(SYSCTL_HANDLER_ARGS) 439143794Sphilip{ 440143794Sphilip struct acpi_fujitsu_softc *sc; 441143794Sphilip int method; 442143794Sphilip int arg; 443143794Sphilip int function_num, error = 0; 444143794Sphilip 445143794Sphilip sc = (struct acpi_fujitsu_softc *)oidp->oid_arg1; 446143794Sphilip function_num = oidp->oid_arg2; 447143794Sphilip method = sysctl_table[function_num].method; 448143794Sphilip 449143794Sphilip ACPI_SERIAL_BEGIN(fujitsu); 450143794Sphilip 451143794Sphilip /* Get the current value */ 452143794Sphilip arg = acpi_fujitsu_method_get(sc, method); 453143794Sphilip error = sysctl_handle_int(oidp, &arg, 0, req); 454143794Sphilip 455143794Sphilip if (error != 0 || req->newptr == NULL) 456143794Sphilip goto out; 457143794Sphilip 458143794Sphilip /* Update the value */ 459143794Sphilip error = acpi_fujitsu_method_set(sc, method, arg); 460143794Sphilip 461143794Sphilipout: 462143794Sphilip ACPI_SERIAL_END(fujitsu); 463143794Sphilip return (error); 464143794Sphilip} 465143794Sphilip 466143794Sphilipstatic int 467143794Sphilipacpi_fujitsu_method_get(struct acpi_fujitsu_softc *sc, int method) 468143794Sphilip{ 469143794Sphilip struct int_nameval nv; 470143794Sphilip ACPI_STATUS status; 471143794Sphilip 472143794Sphilip ACPI_SERIAL_ASSERT(fujitsu); 473143794Sphilip 474143794Sphilip switch (method) { 475143794Sphilip case METHOD_GBLL: 476143794Sphilip nv = sc->gbll; 477143794Sphilip break; 478216376Savg case METHOD_GBLS: 479216376Savg nv = sc->gbls; 480216376Savg break; 481143794Sphilip case METHOD_GMOU: 482143794Sphilip nv = sc->gmou; 483143794Sphilip break; 484143794Sphilip case METHOD_GVOL: 485143794Sphilip case METHOD_MUTE: 486143794Sphilip nv = sc->gvol; 487143794Sphilip break; 488155020Sphilip case METHOD_GHKS: 489155020Sphilip nv = sc->ghks; 490155020Sphilip break; 491155020Sphilip case METHOD_GSIF: 492155020Sphilip nv = sc->gsif; 493155020Sphilip break; 494155020Sphilip case METHOD_RBLL: 495155020Sphilip nv = sc->rbll; 496155020Sphilip break; 497155020Sphilip case METHOD_RVOL: 498155020Sphilip nv = sc->rvol; 499155020Sphilip break; 500143794Sphilip default: 501143794Sphilip return (FALSE); 502143794Sphilip } 503143794Sphilip 504155020Sphilip if(!nv.exists) 505155020Sphilip return (EINVAL); 506155020Sphilip 507143794Sphilip status = acpi_GetInteger(sc->handle, nv.name, &nv.value); 508143794Sphilip if (ACPI_FAILURE(status)) { 509155020Sphilip device_printf(sc->dev, "Couldn't query method (%s)\n", nv.name); 510143794Sphilip return (FALSE); 511143794Sphilip } 512143794Sphilip 513143794Sphilip if (method == METHOD_MUTE) { 514143794Sphilip sc->bIsMuted = (uint8_t)((nv.value & VOLUME_MUTE_BIT) != 0); 515143794Sphilip return (sc->bIsMuted); 516143794Sphilip } 517143794Sphilip 518143794Sphilip nv.value &= GENERAL_SETTING_BITS; 519143794Sphilip return (nv.value); 520143794Sphilip} 521143794Sphilip 522143794Sphilipstatic int 523143794Sphilipacpi_fujitsu_method_set(struct acpi_fujitsu_softc *sc, int method, int value) 524143794Sphilip{ 525143794Sphilip struct int_nameval nv; 526143794Sphilip ACPI_STATUS status; 527143794Sphilip char *control; 528143794Sphilip int changed; 529143794Sphilip 530143794Sphilip ACPI_SERIAL_ASSERT(fujitsu); 531143794Sphilip 532143794Sphilip switch (method) { 533143794Sphilip case METHOD_GBLL: 534143794Sphilip changed = BRIGHT_CHANGED; 535143794Sphilip control = "SBLL"; 536143794Sphilip nv = sc->gbll; 537143794Sphilip break; 538216376Savg case METHOD_GBLS: 539216376Savg changed = BRIGHT_CHANGED; 540216376Savg control = "SBL2"; 541216376Savg nv = sc->gbls; 542216376Savg break; 543143794Sphilip case METHOD_GMOU: 544143794Sphilip changed = MOUSE_CHANGED; 545143794Sphilip control = "SMOU"; 546143794Sphilip nv = sc->gmou; 547143794Sphilip break; 548143794Sphilip case METHOD_GVOL: 549143794Sphilip case METHOD_MUTE: 550143794Sphilip changed = VOLUME_CHANGED; 551143794Sphilip control = "SVOL"; 552143794Sphilip nv = sc->gvol; 553143794Sphilip break; 554143794Sphilip default: 555143794Sphilip return (EINVAL); 556143794Sphilip } 557143794Sphilip 558155020Sphilip if(!nv.exists) 559155020Sphilip return (EINVAL); 560155020Sphilip 561143794Sphilip if (method == METHOD_MUTE) { 562143794Sphilip if (value == 1) 563143794Sphilip value = nv.value | VOLUME_MUTE_BIT; 564143794Sphilip else if (value == 0) 565143794Sphilip value = nv.value & ~VOLUME_MUTE_BIT; 566143794Sphilip else 567143794Sphilip return (EINVAL); 568143794Sphilip } 569143794Sphilip 570143794Sphilip status = acpi_SetInteger(sc->handle, control, value); 571143794Sphilip if (ACPI_FAILURE(status)) { 572143794Sphilip device_printf(sc->dev, "Couldn't update %s\n", control); 573155020Sphilip return (FALSE); 574143794Sphilip } 575143794Sphilip 576143794Sphilip sc->lastValChanged = changed; 577143794Sphilip return (0); 578143794Sphilip} 579143794Sphilip 580143794Sphilip/* 581155020Sphilip * Query the get methods to determine what functionality is available 582155020Sphilip * from the hardware function hotkeys. 583143794Sphilip */ 584143794Sphilipstatic uint8_t 585155020Sphilipacpi_fujitsu_check_hardware(struct acpi_fujitsu_softc *sc) 586143794Sphilip{ 587155020Sphilip int val; 588143794Sphilip 589143794Sphilip ACPI_SERIAL_ASSERT(fujitsu); 590155020Sphilip /* save the hotkey bitmask */ 591155020Sphilip if (ACPI_FAILURE(acpi_GetInteger(sc->handle, 592155020Sphilip sc->gsif.name, &(sc->gsif.value)))) { 593155020Sphilip sc->gsif.exists = 0; 594155020Sphilip device_printf(sc->dev, "Couldn't query bitmask value\n"); 595155020Sphilip } else { 596155020Sphilip sc->gsif.exists = 1; 597155020Sphilip } 598143794Sphilip 599143794Sphilip /* System Volume Level */ 600143794Sphilip if (ACPI_FAILURE(acpi_GetInteger(sc->handle, 601155020Sphilip sc->gvol.name, &val))) { 602155020Sphilip sc->gvol.exists = 0; 603155020Sphilip } else { 604155020Sphilip sc->gvol.exists = 1; 605143794Sphilip } 606143794Sphilip 607155020Sphilip if (ACPI_FAILURE(acpi_GetInteger(sc->handle, 608216376Savg sc->gbls.name, &val))) { 609216376Savg sc->gbls.exists = 0; 610216376Savg } else { 611216376Savg sc->gbls.exists = 1; 612216376Savg } 613216376Savg 614216376Savg // don't add if we can use the new method 615216376Savg if (sc->gbls.exists || ACPI_FAILURE(acpi_GetInteger(sc->handle, 616155020Sphilip sc->gbll.name, &val))) { 617155020Sphilip sc->gbll.exists = 0; 618155020Sphilip } else { 619155020Sphilip sc->gbll.exists = 1; 620155020Sphilip } 621143794Sphilip 622155020Sphilip if (ACPI_FAILURE(acpi_GetInteger(sc->handle, 623155020Sphilip sc->ghks.name, &val))) { 624155020Sphilip sc->ghks.exists = 0; 625155020Sphilip } else { 626155020Sphilip sc->ghks.exists = 1; 627143794Sphilip } 628143794Sphilip 629143794Sphilip if (ACPI_FAILURE(acpi_GetInteger(sc->handle, 630155020Sphilip sc->gmou.name, &val))) { 631155020Sphilip sc->gmou.exists = 0; 632155020Sphilip } else { 633155020Sphilip sc->gmou.exists = 1; 634143794Sphilip } 635143794Sphilip 636155020Sphilip if (ACPI_FAILURE(acpi_GetInteger(sc->handle, 637155020Sphilip sc->rbll.name, &val))) { 638155020Sphilip sc->rbll.exists = 0; 639155020Sphilip } else { 640155020Sphilip sc->rbll.exists = 1; 641143794Sphilip } 642143794Sphilip 643143794Sphilip if (ACPI_FAILURE(acpi_GetInteger(sc->handle, 644155020Sphilip sc->rvol.name, &val))) { 645155020Sphilip sc->rvol.exists = 0; 646155020Sphilip } else { 647155020Sphilip sc->rvol.exists = 1; 648143794Sphilip } 649143794Sphilip 650155020Sphilip return (TRUE); 651155020Sphilip} 652143794Sphilip 653155020Sphilip/* 654155020Sphilip * Query each of the ACPI control methods that contain information we're 655155020Sphilip * interested in. We check the return values from the control methods and 656155020Sphilip * adjust any state variables if they should be adjusted. 657155020Sphilip */ 658155020Sphilipstatic uint8_t 659155020Sphilipacpi_fujitsu_update(struct acpi_fujitsu_softc *sc) 660155020Sphilip{ 661155020Sphilip int changed; 662155020Sphilip struct acpi_softc *acpi_sc; 663143794Sphilip 664155020Sphilip acpi_sc = acpi_device_get_parent_softc(sc->dev); 665143794Sphilip 666155020Sphilip ACPI_SERIAL_ASSERT(fujitsu); 667155020Sphilip if(sc->gsif.exists) 668155020Sphilip changed = sc->gsif.value & acpi_fujitsu_method_get(sc,METHOD_GHKS); 669155020Sphilip else 670155020Sphilip changed = 0; 671143794Sphilip 672155020Sphilip /* System Volume Level */ 673155020Sphilip if(sc->gvol.exists) { 674155020Sphilip if (ACPI_FAILURE(acpi_GetInteger(sc->handle, 675155020Sphilip sc->gvol.name, &(sc->gvol.value)))) { 676155020Sphilip device_printf(sc->dev, "Couldn't query volume level\n"); 677155020Sphilip return (FALSE); 678155020Sphilip } 679155020Sphilip 680155020Sphilip if (changed & VOLUME_CHANGED) { 681155020Sphilip sc->bIsMuted = 682155020Sphilip (uint8_t)((sc->gvol.value & VOLUME_MUTE_BIT) != 0); 683155020Sphilip 684155020Sphilip /* Clear the modification bit */ 685155020Sphilip sc->gvol.value &= VOLUME_SETTING_BITS; 686155020Sphilip 687155020Sphilip if (sc->bIsMuted) { 688155020Sphilip acpi_UserNotify("FUJITSU", sc->handle, FN_MUTE); 689155020Sphilip ACPI_VPRINT(sc->dev, acpi_sc, "Volume is now mute\n"); 690155020Sphilip } else 691155020Sphilip ACPI_VPRINT(sc->dev, acpi_sc, "Volume is now %d\n", 692155020Sphilip sc->gvol.value); 693155020Sphilip 694155020Sphilip acpi_UserNotify("FUJITSU", sc->handle, FN_VOLUME); 695155020Sphilip } 696143794Sphilip } 697143794Sphilip 698155020Sphilip /* Internal mouse pointer (eraserhead) */ 699155020Sphilip if(sc->gmou.exists) { 700155020Sphilip if (ACPI_FAILURE(acpi_GetInteger(sc->handle, 701155020Sphilip sc->gmou.name, &(sc->gmou.value)))) { 702155020Sphilip device_printf(sc->dev, "Couldn't query pointer state\n"); 703155020Sphilip return (FALSE); 704155020Sphilip } 705155020Sphilip 706155020Sphilip if (changed & MOUSE_CHANGED) { 707155020Sphilip sc->bIntPtrEnabled = (uint8_t)(sc->gmou.value & 0x1); 708155020Sphilip 709155020Sphilip /* Clear the modification bit */ 710155020Sphilip sc->gmou.value &= MOUSE_SETTING_BITS; 711155020Sphilip 712216376Savg /* Set the value in case it is not hardware controlled */ 713216376Savg acpi_fujitsu_method_set(sc, METHOD_GMOU, sc->gmou.value); 714216376Savg 715155020Sphilip acpi_UserNotify("FUJITSU", sc->handle, FN_POINTER_ENABLE); 716155020Sphilip 717155020Sphilip ACPI_VPRINT(sc->dev, acpi_sc, "Internal pointer is now %s\n", 718155020Sphilip (sc->bIntPtrEnabled) ? "enabled" : "disabled"); 719155020Sphilip } 720155020Sphilip } 721155020Sphilip 722216376Savg /* Screen Brightness Level P8XXX */ 723216376Savg if(sc->gbls.exists) { 724216376Savg if (ACPI_FAILURE(acpi_GetInteger(sc->handle, 725216376Savg sc->gbls.name, &(sc->gbls.value)))) { 726216376Savg device_printf(sc->dev, "Couldn't query P8XXX brightness level\n"); 727216376Savg return (FALSE); 728216376Savg } 729216376Savg if (changed & BRIGHT_CHANGED) { 730216376Savg /* No state to record here. */ 731216376Savg 732216376Savg /* Clear the modification bit */ 733216376Savg sc->gbls.value &= BRIGHTNESS_SETTING_BITS; 734216376Savg 735216376Savg /* Set the value in case it is not hardware controlled */ 736216376Savg acpi_fujitsu_method_set(sc, METHOD_GBLS, sc->gbls.value); 737216376Savg 738216376Savg acpi_UserNotify("FUJITSU", sc->handle, FN_LCD_BRIGHTNESS); 739216376Savg 740216376Savg ACPI_VPRINT(sc->dev, acpi_sc, "P8XXX Brightness level is now %d\n", 741216376Savg sc->gbls.value); 742216376Savg } 743216376Savg } 744216376Savg 745155020Sphilip /* Screen Brightness Level */ 746155020Sphilip if(sc->gbll.exists) { 747155020Sphilip if (ACPI_FAILURE(acpi_GetInteger(sc->handle, 748155020Sphilip sc->gbll.name, &(sc->gbll.value)))) { 749155020Sphilip device_printf(sc->dev, "Couldn't query brightness level\n"); 750155020Sphilip return (FALSE); 751155020Sphilip } 752155020Sphilip 753155020Sphilip if (changed & BRIGHT_CHANGED) { 754155020Sphilip /* No state to record here. */ 755155020Sphilip 756155020Sphilip /* Clear the modification bit */ 757155020Sphilip sc->gbll.value &= BRIGHTNESS_SETTING_BITS; 758155020Sphilip 759155020Sphilip acpi_UserNotify("FUJITSU", sc->handle, FN_LCD_BRIGHTNESS); 760155020Sphilip 761155020Sphilip ACPI_VPRINT(sc->dev, acpi_sc, "Brightness level is now %d\n", 762155020Sphilip sc->gbll.value); 763155020Sphilip } 764155020Sphilip } 765155020Sphilip 766155020Sphilip sc->lastValChanged = changed; 767143794Sphilip return (TRUE); 768143794Sphilip} 769