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), 157143794Sphilip {0, 0} 158143794Sphilip}; 159143794Sphilip 160143794Sphilipstatic driver_t acpi_fujitsu_driver = { 161143794Sphilip "acpi_fujitsu", 162143794Sphilip acpi_fujitsu_methods, 163143794Sphilip sizeof(struct acpi_fujitsu_softc), 164143794Sphilip}; 165143794Sphilip 166155020Sphilip/* Prototype for function hotkeys for getting/setting a value. */ 167143794Sphilipstatic int acpi_fujitsu_method_get(struct acpi_fujitsu_softc *sc, int method); 168143794Sphilipstatic int acpi_fujitsu_method_set(struct acpi_fujitsu_softc *sc, int method, int value); 169143794Sphilip 170143794Sphilipstatic char *fujitsu_ids[] = { "FUJ02B1", NULL }; 171143794Sphilip 172155020SphilipACPI_SERIAL_DECL(fujitsu, "Fujitsu Function Hotkeys"); 173143794Sphilip 174143794Sphilip/* sysctl names and function calls */ 175143794Sphilipstatic struct { 176143794Sphilip char *name; 177143794Sphilip int method; 178143794Sphilip char *description; 179143794Sphilip} sysctl_table[] = { 180143794Sphilip { 181143794Sphilip .name = "mute", 182143794Sphilip .method = METHOD_MUTE, 183143794Sphilip .description = "Speakers/headphones mute status" 184143794Sphilip }, 185143794Sphilip { 186143794Sphilip .name = "pointer_enable", 187143794Sphilip .method = METHOD_GMOU, 188143794Sphilip .description = "Enable and disable the internal pointer" 189143794Sphilip }, 190143794Sphilip { 191143794Sphilip .name = "lcd_brightness", 192143794Sphilip .method = METHOD_GBLL, 193143794Sphilip .description = "Brightness level of the LCD panel" 194143794Sphilip }, 195143794Sphilip { 196216376Savg .name = "lcd_brightness", 197216376Savg .method = METHOD_GBLS, 198216376Savg .description = "Brightness level of the LCD panel" 199216376Savg }, 200216376Savg { 201143794Sphilip .name = "volume", 202143794Sphilip .method = METHOD_GVOL, 203143794Sphilip .description = "Speakers/headphones volume level" 204143794Sphilip }, 205155020Sphilip { 206155020Sphilip .name = "volume_radix", 207155020Sphilip .method = METHOD_RVOL, 208155020Sphilip .description = "Number of volume level steps" 209155020Sphilip }, 210155020Sphilip { 211155020Sphilip .name = "lcd_brightness_radix", 212155020Sphilip .method = METHOD_RBLL, 213155020Sphilip .description = "Number of brightness level steps" 214155020Sphilip }, 215143794Sphilip 216143794Sphilip { NULL, 0, NULL } 217143794Sphilip}; 218143794Sphilip 219143794Sphilipstatic devclass_t acpi_fujitsu_devclass; 220143794SphilipDRIVER_MODULE(acpi_fujitsu, acpi, acpi_fujitsu_driver, 221143794Sphilip acpi_fujitsu_devclass, 0, 0); 222143794SphilipMODULE_DEPEND(acpi_fujitsu, acpi, 1, 1, 1); 223143794SphilipMODULE_VERSION(acpi_fujitsu, 1); 224143794Sphilip 225143794Sphilipstatic int 226143794Sphilipacpi_fujitsu_probe(device_t dev) 227143794Sphilip{ 228155020Sphilip char *name; 229155020Sphilip char buffer[64]; 230143794Sphilip 231155020Sphilip name = ACPI_ID_PROBE(device_get_parent(dev), dev, fujitsu_ids); 232155020Sphilip if (acpi_disabled("fujitsu") || name == NULL || 233155020Sphilip device_get_unit(dev) > 1) 234143794Sphilip return (ENXIO); 235143794Sphilip 236155020Sphilip sprintf(buffer, "Fujitsu Function Hotkeys %s", name); 237155020Sphilip device_set_desc_copy(dev, buffer); 238143794Sphilip 239143794Sphilip return (0); 240143794Sphilip} 241143794Sphilip 242143794Sphilipstatic int 243143794Sphilipacpi_fujitsu_attach(device_t dev) 244143794Sphilip{ 245143794Sphilip struct acpi_fujitsu_softc *sc; 246143794Sphilip 247143794Sphilip ACPI_FUNCTION_TRACE((char *)(uintptr_t)__func__); 248143794Sphilip 249143794Sphilip sc = device_get_softc(dev); 250143794Sphilip sc->dev = dev; 251143794Sphilip sc->handle = acpi_get_handle(dev); 252143794Sphilip 253143794Sphilip /* Install notification handler */ 254143794Sphilip AcpiInstallNotifyHandler(sc->handle, ACPI_DEVICE_NOTIFY, 255143794Sphilip acpi_fujitsu_notify_handler, sc); 256143794Sphilip 257182864Sed /* Snag our default values for the hotkeys / hotkey states. */ 258144623Sphilip ACPI_SERIAL_BEGIN(fujitsu); 259144623Sphilip if (!acpi_fujitsu_init(sc)) 260155020Sphilip device_printf(dev, "Couldn't initialize hotkey states!\n"); 261144623Sphilip ACPI_SERIAL_END(fujitsu); 262143794Sphilip 263143794Sphilip return (0); 264143794Sphilip} 265143794Sphilip 266143794Sphilip/* 267143794Sphilip * Called when the system is being suspended, simply 268143794Sphilip * set an event to be signalled when we wake up. 269143794Sphilip */ 270143794Sphilipstatic int 271143794Sphilipacpi_fujitsu_suspend(device_t dev) 272143794Sphilip{ 273143794Sphilip 274143794Sphilip return (0); 275143794Sphilip} 276143794Sphilip 277143794Sphilipstatic int 278143794Sphilipacpi_fujitsu_resume(device_t dev) 279143794Sphilip{ 280143794Sphilip struct acpi_fujitsu_softc *sc; 281143794Sphilip ACPI_STATUS status; 282143794Sphilip 283143794Sphilip sc = device_get_softc(dev); 284143794Sphilip 285143794Sphilip /* 286143794Sphilip * The pointer needs to be re-enabled for 287143794Sphilip * some revisions of the P series (2120). 288143794Sphilip */ 289143794Sphilip ACPI_SERIAL_BEGIN(fujitsu); 290143794Sphilip 291155020Sphilip if(sc->gmou.exists) { 292155020Sphilip status = acpi_SetInteger(sc->handle, "SMOU", 1); 293155020Sphilip if (ACPI_FAILURE(status)) 294155020Sphilip device_printf(sc->dev, "Couldn't enable pointer\n"); 295155020Sphilip } 296143794Sphilip ACPI_SERIAL_END(fujitsu); 297143794Sphilip 298143794Sphilip return (0); 299143794Sphilip} 300143794Sphilip 301143794Sphilipstatic void 302143794Sphilipacpi_fujitsu_notify_status_changed(void *arg) 303143794Sphilip{ 304143794Sphilip struct acpi_fujitsu_softc *sc; 305143794Sphilip 306143794Sphilip ACPI_FUNCTION_TRACE((char *)(uintptr_t)__func__); 307143794Sphilip 308143794Sphilip sc = (struct acpi_fujitsu_softc *)arg; 309143794Sphilip 310143794Sphilip /* 311143794Sphilip * Since our notify function is called, we know something has 312143794Sphilip * happened. So the only reason for acpi_fujitsu_update to fail 313143794Sphilip * is if we can't find what has changed or an error occurs. 314143794Sphilip */ 315143794Sphilip ACPI_SERIAL_BEGIN(fujitsu); 316143794Sphilip acpi_fujitsu_update(sc); 317143794Sphilip ACPI_SERIAL_END(fujitsu); 318143794Sphilip} 319143794Sphilip 320143794Sphilip 321143794Sphilipstatic void 322143794Sphilipacpi_fujitsu_notify_handler(ACPI_HANDLE h, uint32_t notify, void *context) 323143794Sphilip{ 324143794Sphilip struct acpi_fujitsu_softc *sc; 325143794Sphilip 326143794Sphilip ACPI_FUNCTION_TRACE_U32((char *)(uintptr_t)__func__, notify); 327143794Sphilip 328143794Sphilip sc = (struct acpi_fujitsu_softc *)context; 329143794Sphilip 330143794Sphilip switch (notify) { 331143794Sphilip case ACPI_NOTIFY_STATUS_CHANGED: 332167814Sjkim AcpiOsExecute(OSL_NOTIFY_HANDLER, 333143794Sphilip acpi_fujitsu_notify_status_changed, sc); 334143794Sphilip break; 335143794Sphilip default: 336143794Sphilip /* unknown notification value */ 337143794Sphilip break; 338143794Sphilip } 339143794Sphilip} 340143794Sphilip 341143794Sphilipstatic int 342143794Sphilipacpi_fujitsu_detach(device_t dev) 343143794Sphilip{ 344143794Sphilip struct acpi_fujitsu_softc *sc; 345143794Sphilip 346143794Sphilip sc = device_get_softc(dev); 347143794Sphilip AcpiRemoveNotifyHandler(sc->handle, ACPI_DEVICE_NOTIFY, 348143794Sphilip acpi_fujitsu_notify_handler); 349143794Sphilip 350143794Sphilip sysctl_ctx_free(&sc->sysctl_ctx); 351143794Sphilip 352143794Sphilip return (0); 353143794Sphilip} 354143794Sphilip 355143794Sphilip/* 356143794Sphilip * Initializes the names of the ACPI control methods and grabs 357155020Sphilip * the current state of all of the ACPI hotkeys into the softc. 358143794Sphilip */ 359143794Sphilipstatic uint8_t 360143794Sphilipacpi_fujitsu_init(struct acpi_fujitsu_softc *sc) 361143794Sphilip{ 362143794Sphilip struct acpi_softc *acpi_sc; 363155020Sphilip int i, exists; 364143794Sphilip 365143794Sphilip ACPI_SERIAL_ASSERT(fujitsu); 366143794Sphilip 367143794Sphilip /* Setup all of the names for each control method */ 368143794Sphilip sc->_sta.name = "_STA"; 369143794Sphilip sc->gbll.name = "GBLL"; 370216376Savg sc->gbls.name = "GBLS"; 371143794Sphilip sc->ghks.name = "GHKS"; 372143794Sphilip sc->gmou.name = "GMOU"; 373143794Sphilip sc->gsif.name = "GSIF"; 374143794Sphilip sc->gvol.name = "GVOL"; 375155020Sphilip sc->ghks.name = "GHKS"; 376155020Sphilip sc->gsif.name = "GSIF"; 377143794Sphilip sc->rbll.name = "RBLL"; 378143794Sphilip sc->rvol.name = "RVOL"; 379143794Sphilip 380155020Sphilip /* Determine what hardware functionality is available */ 381155020Sphilip acpi_fujitsu_check_hardware(sc); 382155020Sphilip 383143794Sphilip /* Build the sysctl tree */ 384143794Sphilip acpi_sc = acpi_device_get_parent_softc(sc->dev); 385143794Sphilip sysctl_ctx_init(&sc->sysctl_ctx); 386143794Sphilip sc->sysctl_tree = SYSCTL_ADD_NODE(&sc->sysctl_ctx, 387143794Sphilip SYSCTL_CHILDREN(acpi_sc->acpi_sysctl_tree), 388143794Sphilip OID_AUTO, "fujitsu", CTLFLAG_RD, 0, ""); 389143794Sphilip 390143794Sphilip for (i = 0; sysctl_table[i].name != NULL; i++) { 391155020Sphilip switch(sysctl_table[i].method) { 392155020Sphilip case METHOD_GMOU: 393155020Sphilip exists = sc->gmou.exists; 394155020Sphilip break; 395155020Sphilip case METHOD_GBLL: 396155020Sphilip exists = sc->gbll.exists; 397155020Sphilip break; 398216376Savg case METHOD_GBLS: 399216376Savg exists = sc->gbls.exists; 400216376Savg break; 401155020Sphilip case METHOD_GVOL: 402155020Sphilip case METHOD_MUTE: 403155020Sphilip exists = sc->gvol.exists; 404155020Sphilip break; 405155020Sphilip case METHOD_RVOL: 406155020Sphilip exists = sc->rvol.exists; 407155020Sphilip break; 408155020Sphilip case METHOD_RBLL: 409155020Sphilip exists = sc->rbll.exists; 410155020Sphilip break; 411155020Sphilip default: 412155020Sphilip /* Allow by default */ 413155020Sphilip exists = 1; 414155020Sphilip break; 415155020Sphilip } 416155020Sphilip if(!exists) 417155020Sphilip continue; 418143794Sphilip SYSCTL_ADD_PROC(&sc->sysctl_ctx, 419143794Sphilip SYSCTL_CHILDREN(sc->sysctl_tree), OID_AUTO, 420143794Sphilip sysctl_table[i].name, 421143794Sphilip CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_ANYBODY, 422143794Sphilip sc, i, acpi_fujitsu_sysctl, "I", 423143794Sphilip sysctl_table[i].description); 424143794Sphilip } 425143794Sphilip 426155020Sphilip 427155020Sphilip /* Set the hotkeys to their initial states */ 428143794Sphilip if (!acpi_fujitsu_update(sc)) { 429155020Sphilip device_printf(sc->dev, "Couldn't init hotkey states\n"); 430143794Sphilip return (FALSE); 431143794Sphilip } 432143794Sphilip 433143794Sphilip return (TRUE); 434143794Sphilip} 435143794Sphilip 436143794Sphilipstatic int 437143794Sphilipacpi_fujitsu_sysctl(SYSCTL_HANDLER_ARGS) 438143794Sphilip{ 439143794Sphilip struct acpi_fujitsu_softc *sc; 440143794Sphilip int method; 441143794Sphilip int arg; 442143794Sphilip int function_num, error = 0; 443143794Sphilip 444143794Sphilip sc = (struct acpi_fujitsu_softc *)oidp->oid_arg1; 445143794Sphilip function_num = oidp->oid_arg2; 446143794Sphilip method = sysctl_table[function_num].method; 447143794Sphilip 448143794Sphilip ACPI_SERIAL_BEGIN(fujitsu); 449143794Sphilip 450143794Sphilip /* Get the current value */ 451143794Sphilip arg = acpi_fujitsu_method_get(sc, method); 452143794Sphilip error = sysctl_handle_int(oidp, &arg, 0, req); 453143794Sphilip 454143794Sphilip if (error != 0 || req->newptr == NULL) 455143794Sphilip goto out; 456143794Sphilip 457143794Sphilip /* Update the value */ 458143794Sphilip error = acpi_fujitsu_method_set(sc, method, arg); 459143794Sphilip 460143794Sphilipout: 461143794Sphilip ACPI_SERIAL_END(fujitsu); 462143794Sphilip return (error); 463143794Sphilip} 464143794Sphilip 465143794Sphilipstatic int 466143794Sphilipacpi_fujitsu_method_get(struct acpi_fujitsu_softc *sc, int method) 467143794Sphilip{ 468143794Sphilip struct int_nameval nv; 469143794Sphilip ACPI_STATUS status; 470143794Sphilip 471143794Sphilip ACPI_SERIAL_ASSERT(fujitsu); 472143794Sphilip 473143794Sphilip switch (method) { 474143794Sphilip case METHOD_GBLL: 475143794Sphilip nv = sc->gbll; 476143794Sphilip break; 477216376Savg case METHOD_GBLS: 478216376Savg nv = sc->gbls; 479216376Savg break; 480143794Sphilip case METHOD_GMOU: 481143794Sphilip nv = sc->gmou; 482143794Sphilip break; 483143794Sphilip case METHOD_GVOL: 484143794Sphilip case METHOD_MUTE: 485143794Sphilip nv = sc->gvol; 486143794Sphilip break; 487155020Sphilip case METHOD_GHKS: 488155020Sphilip nv = sc->ghks; 489155020Sphilip break; 490155020Sphilip case METHOD_GSIF: 491155020Sphilip nv = sc->gsif; 492155020Sphilip break; 493155020Sphilip case METHOD_RBLL: 494155020Sphilip nv = sc->rbll; 495155020Sphilip break; 496155020Sphilip case METHOD_RVOL: 497155020Sphilip nv = sc->rvol; 498155020Sphilip break; 499143794Sphilip default: 500143794Sphilip return (FALSE); 501143794Sphilip } 502143794Sphilip 503155020Sphilip if(!nv.exists) 504155020Sphilip return (EINVAL); 505155020Sphilip 506143794Sphilip status = acpi_GetInteger(sc->handle, nv.name, &nv.value); 507143794Sphilip if (ACPI_FAILURE(status)) { 508155020Sphilip device_printf(sc->dev, "Couldn't query method (%s)\n", nv.name); 509143794Sphilip return (FALSE); 510143794Sphilip } 511143794Sphilip 512143794Sphilip if (method == METHOD_MUTE) { 513143794Sphilip sc->bIsMuted = (uint8_t)((nv.value & VOLUME_MUTE_BIT) != 0); 514143794Sphilip return (sc->bIsMuted); 515143794Sphilip } 516143794Sphilip 517143794Sphilip nv.value &= GENERAL_SETTING_BITS; 518143794Sphilip return (nv.value); 519143794Sphilip} 520143794Sphilip 521143794Sphilipstatic int 522143794Sphilipacpi_fujitsu_method_set(struct acpi_fujitsu_softc *sc, int method, int value) 523143794Sphilip{ 524143794Sphilip struct int_nameval nv; 525143794Sphilip ACPI_STATUS status; 526143794Sphilip char *control; 527143794Sphilip int changed; 528143794Sphilip 529143794Sphilip ACPI_SERIAL_ASSERT(fujitsu); 530143794Sphilip 531143794Sphilip switch (method) { 532143794Sphilip case METHOD_GBLL: 533143794Sphilip changed = BRIGHT_CHANGED; 534143794Sphilip control = "SBLL"; 535143794Sphilip nv = sc->gbll; 536143794Sphilip break; 537216376Savg case METHOD_GBLS: 538216376Savg changed = BRIGHT_CHANGED; 539216376Savg control = "SBL2"; 540216376Savg nv = sc->gbls; 541216376Savg break; 542143794Sphilip case METHOD_GMOU: 543143794Sphilip changed = MOUSE_CHANGED; 544143794Sphilip control = "SMOU"; 545143794Sphilip nv = sc->gmou; 546143794Sphilip break; 547143794Sphilip case METHOD_GVOL: 548143794Sphilip case METHOD_MUTE: 549143794Sphilip changed = VOLUME_CHANGED; 550143794Sphilip control = "SVOL"; 551143794Sphilip nv = sc->gvol; 552143794Sphilip break; 553143794Sphilip default: 554143794Sphilip return (EINVAL); 555143794Sphilip } 556143794Sphilip 557155020Sphilip if(!nv.exists) 558155020Sphilip return (EINVAL); 559155020Sphilip 560143794Sphilip if (method == METHOD_MUTE) { 561143794Sphilip if (value == 1) 562143794Sphilip value = nv.value | VOLUME_MUTE_BIT; 563143794Sphilip else if (value == 0) 564143794Sphilip value = nv.value & ~VOLUME_MUTE_BIT; 565143794Sphilip else 566143794Sphilip return (EINVAL); 567143794Sphilip } 568143794Sphilip 569143794Sphilip status = acpi_SetInteger(sc->handle, control, value); 570143794Sphilip if (ACPI_FAILURE(status)) { 571143794Sphilip device_printf(sc->dev, "Couldn't update %s\n", control); 572155020Sphilip return (FALSE); 573143794Sphilip } 574143794Sphilip 575143794Sphilip sc->lastValChanged = changed; 576143794Sphilip return (0); 577143794Sphilip} 578143794Sphilip 579143794Sphilip/* 580155020Sphilip * Query the get methods to determine what functionality is available 581155020Sphilip * from the hardware function hotkeys. 582143794Sphilip */ 583143794Sphilipstatic uint8_t 584155020Sphilipacpi_fujitsu_check_hardware(struct acpi_fujitsu_softc *sc) 585143794Sphilip{ 586155020Sphilip int val; 587143794Sphilip 588143794Sphilip ACPI_SERIAL_ASSERT(fujitsu); 589155020Sphilip /* save the hotkey bitmask */ 590155020Sphilip if (ACPI_FAILURE(acpi_GetInteger(sc->handle, 591155020Sphilip sc->gsif.name, &(sc->gsif.value)))) { 592155020Sphilip sc->gsif.exists = 0; 593155020Sphilip device_printf(sc->dev, "Couldn't query bitmask value\n"); 594155020Sphilip } else { 595155020Sphilip sc->gsif.exists = 1; 596155020Sphilip } 597143794Sphilip 598143794Sphilip /* System Volume Level */ 599143794Sphilip if (ACPI_FAILURE(acpi_GetInteger(sc->handle, 600155020Sphilip sc->gvol.name, &val))) { 601155020Sphilip sc->gvol.exists = 0; 602155020Sphilip } else { 603155020Sphilip sc->gvol.exists = 1; 604143794Sphilip } 605143794Sphilip 606155020Sphilip if (ACPI_FAILURE(acpi_GetInteger(sc->handle, 607216376Savg sc->gbls.name, &val))) { 608216376Savg sc->gbls.exists = 0; 609216376Savg } else { 610216376Savg sc->gbls.exists = 1; 611216376Savg } 612216376Savg 613216376Savg // don't add if we can use the new method 614216376Savg if (sc->gbls.exists || ACPI_FAILURE(acpi_GetInteger(sc->handle, 615155020Sphilip sc->gbll.name, &val))) { 616155020Sphilip sc->gbll.exists = 0; 617155020Sphilip } else { 618155020Sphilip sc->gbll.exists = 1; 619155020Sphilip } 620143794Sphilip 621155020Sphilip if (ACPI_FAILURE(acpi_GetInteger(sc->handle, 622155020Sphilip sc->ghks.name, &val))) { 623155020Sphilip sc->ghks.exists = 0; 624155020Sphilip } else { 625155020Sphilip sc->ghks.exists = 1; 626143794Sphilip } 627143794Sphilip 628143794Sphilip if (ACPI_FAILURE(acpi_GetInteger(sc->handle, 629155020Sphilip sc->gmou.name, &val))) { 630155020Sphilip sc->gmou.exists = 0; 631155020Sphilip } else { 632155020Sphilip sc->gmou.exists = 1; 633143794Sphilip } 634143794Sphilip 635155020Sphilip if (ACPI_FAILURE(acpi_GetInteger(sc->handle, 636155020Sphilip sc->rbll.name, &val))) { 637155020Sphilip sc->rbll.exists = 0; 638155020Sphilip } else { 639155020Sphilip sc->rbll.exists = 1; 640143794Sphilip } 641143794Sphilip 642143794Sphilip if (ACPI_FAILURE(acpi_GetInteger(sc->handle, 643155020Sphilip sc->rvol.name, &val))) { 644155020Sphilip sc->rvol.exists = 0; 645155020Sphilip } else { 646155020Sphilip sc->rvol.exists = 1; 647143794Sphilip } 648143794Sphilip 649155020Sphilip return (TRUE); 650155020Sphilip} 651143794Sphilip 652155020Sphilip/* 653155020Sphilip * Query each of the ACPI control methods that contain information we're 654155020Sphilip * interested in. We check the return values from the control methods and 655155020Sphilip * adjust any state variables if they should be adjusted. 656155020Sphilip */ 657155020Sphilipstatic uint8_t 658155020Sphilipacpi_fujitsu_update(struct acpi_fujitsu_softc *sc) 659155020Sphilip{ 660155020Sphilip int changed; 661155020Sphilip struct acpi_softc *acpi_sc; 662143794Sphilip 663155020Sphilip acpi_sc = acpi_device_get_parent_softc(sc->dev); 664143794Sphilip 665155020Sphilip ACPI_SERIAL_ASSERT(fujitsu); 666155020Sphilip if(sc->gsif.exists) 667155020Sphilip changed = sc->gsif.value & acpi_fujitsu_method_get(sc,METHOD_GHKS); 668155020Sphilip else 669155020Sphilip changed = 0; 670143794Sphilip 671155020Sphilip /* System Volume Level */ 672155020Sphilip if(sc->gvol.exists) { 673155020Sphilip if (ACPI_FAILURE(acpi_GetInteger(sc->handle, 674155020Sphilip sc->gvol.name, &(sc->gvol.value)))) { 675155020Sphilip device_printf(sc->dev, "Couldn't query volume level\n"); 676155020Sphilip return (FALSE); 677155020Sphilip } 678155020Sphilip 679155020Sphilip if (changed & VOLUME_CHANGED) { 680155020Sphilip sc->bIsMuted = 681155020Sphilip (uint8_t)((sc->gvol.value & VOLUME_MUTE_BIT) != 0); 682155020Sphilip 683155020Sphilip /* Clear the modification bit */ 684155020Sphilip sc->gvol.value &= VOLUME_SETTING_BITS; 685155020Sphilip 686155020Sphilip if (sc->bIsMuted) { 687155020Sphilip acpi_UserNotify("FUJITSU", sc->handle, FN_MUTE); 688155020Sphilip ACPI_VPRINT(sc->dev, acpi_sc, "Volume is now mute\n"); 689155020Sphilip } else 690155020Sphilip ACPI_VPRINT(sc->dev, acpi_sc, "Volume is now %d\n", 691155020Sphilip sc->gvol.value); 692155020Sphilip 693155020Sphilip acpi_UserNotify("FUJITSU", sc->handle, FN_VOLUME); 694155020Sphilip } 695143794Sphilip } 696143794Sphilip 697155020Sphilip /* Internal mouse pointer (eraserhead) */ 698155020Sphilip if(sc->gmou.exists) { 699155020Sphilip if (ACPI_FAILURE(acpi_GetInteger(sc->handle, 700155020Sphilip sc->gmou.name, &(sc->gmou.value)))) { 701155020Sphilip device_printf(sc->dev, "Couldn't query pointer state\n"); 702155020Sphilip return (FALSE); 703155020Sphilip } 704155020Sphilip 705155020Sphilip if (changed & MOUSE_CHANGED) { 706155020Sphilip sc->bIntPtrEnabled = (uint8_t)(sc->gmou.value & 0x1); 707155020Sphilip 708155020Sphilip /* Clear the modification bit */ 709155020Sphilip sc->gmou.value &= MOUSE_SETTING_BITS; 710155020Sphilip 711216376Savg /* Set the value in case it is not hardware controlled */ 712216376Savg acpi_fujitsu_method_set(sc, METHOD_GMOU, sc->gmou.value); 713216376Savg 714155020Sphilip acpi_UserNotify("FUJITSU", sc->handle, FN_POINTER_ENABLE); 715155020Sphilip 716155020Sphilip ACPI_VPRINT(sc->dev, acpi_sc, "Internal pointer is now %s\n", 717155020Sphilip (sc->bIntPtrEnabled) ? "enabled" : "disabled"); 718155020Sphilip } 719155020Sphilip } 720155020Sphilip 721216376Savg /* Screen Brightness Level P8XXX */ 722216376Savg if(sc->gbls.exists) { 723216376Savg if (ACPI_FAILURE(acpi_GetInteger(sc->handle, 724216376Savg sc->gbls.name, &(sc->gbls.value)))) { 725216376Savg device_printf(sc->dev, "Couldn't query P8XXX brightness level\n"); 726216376Savg return (FALSE); 727216376Savg } 728216376Savg if (changed & BRIGHT_CHANGED) { 729216376Savg /* No state to record here. */ 730216376Savg 731216376Savg /* Clear the modification bit */ 732216376Savg sc->gbls.value &= BRIGHTNESS_SETTING_BITS; 733216376Savg 734216376Savg /* Set the value in case it is not hardware controlled */ 735216376Savg acpi_fujitsu_method_set(sc, METHOD_GBLS, sc->gbls.value); 736216376Savg 737216376Savg acpi_UserNotify("FUJITSU", sc->handle, FN_LCD_BRIGHTNESS); 738216376Savg 739216376Savg ACPI_VPRINT(sc->dev, acpi_sc, "P8XXX Brightness level is now %d\n", 740216376Savg sc->gbls.value); 741216376Savg } 742216376Savg } 743216376Savg 744155020Sphilip /* Screen Brightness Level */ 745155020Sphilip if(sc->gbll.exists) { 746155020Sphilip if (ACPI_FAILURE(acpi_GetInteger(sc->handle, 747155020Sphilip sc->gbll.name, &(sc->gbll.value)))) { 748155020Sphilip device_printf(sc->dev, "Couldn't query brightness level\n"); 749155020Sphilip return (FALSE); 750155020Sphilip } 751155020Sphilip 752155020Sphilip if (changed & BRIGHT_CHANGED) { 753155020Sphilip /* No state to record here. */ 754155020Sphilip 755155020Sphilip /* Clear the modification bit */ 756155020Sphilip sc->gbll.value &= BRIGHTNESS_SETTING_BITS; 757155020Sphilip 758155020Sphilip acpi_UserNotify("FUJITSU", sc->handle, FN_LCD_BRIGHTNESS); 759155020Sphilip 760155020Sphilip ACPI_VPRINT(sc->dev, acpi_sc, "Brightness level is now %d\n", 761155020Sphilip sc->gbll.value); 762155020Sphilip } 763155020Sphilip } 764155020Sphilip 765155020Sphilip sc->lastValChanged = changed; 766143794Sphilip return (TRUE); 767143794Sphilip} 768