acpi_fujitsu.c revision 155020
1143794Sphilip/*- 2143794Sphilip * Copyright (c) 2002 Sean Bullington <seanATstalker.org> 3155020Sphilip * 2003-2006 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: head/sys/dev/acpi_support/acpi_fujitsu.c 155020 2006-01-29 23:52:02Z philip $"); 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 40150003Sobrien#include <contrib/dev/acpica/acpi.h> 41143794Sphilip#include <dev/acpica/acpivar.h> 42143794Sphilip 43143794Sphilip/* Hooks for the ACPI CA debugging infrastructure */ 44143794Sphilip#define _COMPONENT ACPI_OEM 45143794SphilipACPI_MODULE_NAME("Fujitsu") 46143794Sphilip 47155020Sphilip/* Change and update bits for the hotkeys */ 48143794Sphilip#define VOLUME_MUTE_BIT 0x40000000 49143794Sphilip 50143794Sphilip/* Values of settings */ 51143794Sphilip#define GENERAL_SETTING_BITS 0x0fffffff 52143794Sphilip#define MOUSE_SETTING_BITS GENERAL_SETTING_BITS 53143794Sphilip#define VOLUME_SETTING_BITS GENERAL_SETTING_BITS 54143794Sphilip#define BRIGHTNESS_SETTING_BITS GENERAL_SETTING_BITS 55143794Sphilip 56143794Sphilip/* Possible state changes */ 57155020Sphilip/* 58155020Sphilip * These are NOT arbitrary values. They are the 59155020Sphilip * GHKS return value from the device that says which 60155020Sphilip * hotkey is active. They should match up with a bit 61155020Sphilip * from the GSIF bitmask. 62155020Sphilip */ 63155020Sphilip#define BRIGHT_CHANGED 0x01 64155020Sphilip#define VOLUME_CHANGED 0x04 65155020Sphilip#define MOUSE_CHANGED 0x08 66155020Sphilip/* 67155020Sphilip * It is unknown which hotkey this bit is supposed to indicate, but 68155020Sphilip * according to values from GSIF this is a valid flag. 69155020Sphilip */ 70155020Sphilip#define UNKNOWN_CHANGED 0x10 71143794Sphilip 72143794Sphilip/* sysctl values */ 73143794Sphilip#define FN_MUTE 0 74143794Sphilip#define FN_POINTER_ENABLE 1 75143794Sphilip#define FN_LCD_BRIGHTNESS 2 76143794Sphilip#define FN_VOLUME 3 77143794Sphilip 78143794Sphilip/* Methods */ 79143794Sphilip#define METHOD_GBLL 1 80143794Sphilip#define METHOD_GMOU 2 81143794Sphilip#define METHOD_GVOL 3 82143794Sphilip#define METHOD_MUTE 4 83155020Sphilip#define METHOD_RBLL 5 84155020Sphilip#define METHOD_RVOL 6 85155020Sphilip#define METHOD_GSIF 7 86155020Sphilip#define METHOD_GHKS 8 87143794Sphilip 88143794Sphilip/* Notify event */ 89143794Sphilip#define ACPI_NOTIFY_STATUS_CHANGED 0x80 90143794Sphilip 91143794Sphilip/* 92143794Sphilip * Holds a control method name and its associated integer value. 93143794Sphilip * Only used for no-argument control methods which return a value. 94143794Sphilip */ 95143794Sphilipstruct int_nameval { 96143794Sphilip char *name; 97143794Sphilip int value; 98155020Sphilip int exists; 99143794Sphilip}; 100143794Sphilip 101143794Sphilip/* 102143794Sphilip * Driver extension for the FUJITSU ACPI driver. 103143794Sphilip */ 104143794Sphilipstruct acpi_fujitsu_softc { 105143794Sphilip device_t dev; 106143794Sphilip ACPI_HANDLE handle; 107143794Sphilip 108143794Sphilip /* Control methods */ 109143794Sphilip struct int_nameval _sta, /* unused */ 110143794Sphilip gbll, /* brightness */ 111155020Sphilip ghks, /* hotkey selector */ 112155020Sphilip gbuf, /* unused (buffer?) */ 113143794Sphilip gmou, /* mouse */ 114155020Sphilip gsif, /* function key bitmask */ 115143794Sphilip gvol, /* volume */ 116155020Sphilip rbll, /* number of brightness levels (radix) */ 117155020Sphilip rvol; /* number of volume levels (radix) */ 118143794Sphilip 119143794Sphilip /* State variables */ 120143794Sphilip uint8_t bIsMuted; /* Is volume muted */ 121143794Sphilip uint8_t bIntPtrEnabled; /* Is internal ptr enabled */ 122143794Sphilip uint32_t lastValChanged; /* The last value updated */ 123143794Sphilip 124143794Sphilip /* sysctl tree */ 125143794Sphilip struct sysctl_ctx_list sysctl_ctx; 126143794Sphilip struct sysctl_oid *sysctl_tree; 127143794Sphilip}; 128143794Sphilip 129143794Sphilip/* Driver entry point forward declarations. */ 130143794Sphilipstatic int acpi_fujitsu_probe(device_t dev); 131143794Sphilipstatic int acpi_fujitsu_attach(device_t dev); 132143794Sphilipstatic int acpi_fujitsu_detach(device_t dev); 133143794Sphilipstatic int acpi_fujitsu_suspend(device_t dev); 134143794Sphilipstatic int acpi_fujitsu_resume(device_t dev); 135143794Sphilip 136143794Sphilipstatic void acpi_fujitsu_notify_status_changed(void *arg); 137143794Sphilipstatic void acpi_fujitsu_notify_handler(ACPI_HANDLE h, uint32_t notify, void *context); 138143794Sphilipstatic int acpi_fujitsu_sysctl(SYSCTL_HANDLER_ARGS); 139143794Sphilip 140143794Sphilip/* Utility function declarations */ 141143794Sphilipstatic uint8_t acpi_fujitsu_update(struct acpi_fujitsu_softc *sc); 142143794Sphilipstatic uint8_t acpi_fujitsu_init(struct acpi_fujitsu_softc *sc); 143155020Sphilipstatic uint8_t acpi_fujitsu_check_hardware(struct acpi_fujitsu_softc *sc); 144143794Sphilip 145143794Sphilip/* Driver/Module specific structure definitions. */ 146143794Sphilipstatic device_method_t acpi_fujitsu_methods[] = { 147143794Sphilip /* Device interface */ 148143794Sphilip DEVMETHOD(device_probe, acpi_fujitsu_probe), 149143794Sphilip DEVMETHOD(device_attach, acpi_fujitsu_attach), 150143794Sphilip DEVMETHOD(device_detach, acpi_fujitsu_detach), 151143794Sphilip DEVMETHOD(device_suspend, acpi_fujitsu_suspend), 152143794Sphilip DEVMETHOD(device_resume, acpi_fujitsu_resume), 153143794Sphilip {0, 0} 154143794Sphilip}; 155143794Sphilip 156143794Sphilipstatic driver_t acpi_fujitsu_driver = { 157143794Sphilip "acpi_fujitsu", 158143794Sphilip acpi_fujitsu_methods, 159143794Sphilip sizeof(struct acpi_fujitsu_softc), 160143794Sphilip}; 161143794Sphilip 162155020Sphilip/* Prototype for function hotkeys for getting/setting a value. */ 163143794Sphilipstatic int acpi_fujitsu_method_get(struct acpi_fujitsu_softc *sc, int method); 164143794Sphilipstatic int acpi_fujitsu_method_set(struct acpi_fujitsu_softc *sc, int method, int value); 165143794Sphilip 166143794Sphilipstatic char *fujitsu_ids[] = { "FUJ02B1", NULL }; 167143794Sphilip 168155020SphilipACPI_SERIAL_DECL(fujitsu, "Fujitsu Function Hotkeys"); 169143794Sphilip 170143794Sphilip/* sysctl names and function calls */ 171143794Sphilipstatic struct { 172143794Sphilip char *name; 173143794Sphilip int method; 174143794Sphilip char *description; 175143794Sphilip} sysctl_table[] = { 176143794Sphilip { 177143794Sphilip .name = "mute", 178143794Sphilip .method = METHOD_MUTE, 179143794Sphilip .description = "Speakers/headphones mute status" 180143794Sphilip }, 181143794Sphilip { 182143794Sphilip .name = "pointer_enable", 183143794Sphilip .method = METHOD_GMOU, 184143794Sphilip .description = "Enable and disable the internal pointer" 185143794Sphilip }, 186143794Sphilip { 187143794Sphilip .name = "lcd_brightness", 188143794Sphilip .method = METHOD_GBLL, 189143794Sphilip .description = "Brightness level of the LCD panel" 190143794Sphilip }, 191143794Sphilip { 192143794Sphilip .name = "volume", 193143794Sphilip .method = METHOD_GVOL, 194143794Sphilip .description = "Speakers/headphones volume level" 195143794Sphilip }, 196155020Sphilip { 197155020Sphilip .name = "volume_radix", 198155020Sphilip .method = METHOD_RVOL, 199155020Sphilip .description = "Number of volume level steps" 200155020Sphilip }, 201155020Sphilip { 202155020Sphilip .name = "lcd_brightness_radix", 203155020Sphilip .method = METHOD_RBLL, 204155020Sphilip .description = "Number of brightness level steps" 205155020Sphilip }, 206143794Sphilip 207143794Sphilip { NULL, 0, NULL } 208143794Sphilip}; 209143794Sphilip 210143794Sphilipstatic devclass_t acpi_fujitsu_devclass; 211143794SphilipDRIVER_MODULE(acpi_fujitsu, acpi, acpi_fujitsu_driver, 212143794Sphilip acpi_fujitsu_devclass, 0, 0); 213143794SphilipMODULE_DEPEND(acpi_fujitsu, acpi, 1, 1, 1); 214143794SphilipMODULE_VERSION(acpi_fujitsu, 1); 215143794Sphilip 216143794Sphilipstatic int 217143794Sphilipacpi_fujitsu_probe(device_t dev) 218143794Sphilip{ 219155020Sphilip char *name; 220155020Sphilip char buffer[64]; 221143794Sphilip 222155020Sphilip name = ACPI_ID_PROBE(device_get_parent(dev), dev, fujitsu_ids); 223155020Sphilip if (acpi_disabled("fujitsu") || name == NULL || 224155020Sphilip device_get_unit(dev) > 1) 225143794Sphilip return (ENXIO); 226143794Sphilip 227155020Sphilip sprintf(buffer, "Fujitsu Function Hotkeys %s", name); 228155020Sphilip device_set_desc_copy(dev, buffer); 229143794Sphilip 230143794Sphilip return (0); 231143794Sphilip} 232143794Sphilip 233143794Sphilipstatic int 234143794Sphilipacpi_fujitsu_attach(device_t dev) 235143794Sphilip{ 236143794Sphilip struct acpi_fujitsu_softc *sc; 237143794Sphilip 238143794Sphilip ACPI_FUNCTION_TRACE((char *)(uintptr_t)__func__); 239143794Sphilip 240143794Sphilip sc = device_get_softc(dev); 241143794Sphilip sc->dev = dev; 242143794Sphilip sc->handle = acpi_get_handle(dev); 243143794Sphilip 244143794Sphilip /* Install notification handler */ 245143794Sphilip AcpiInstallNotifyHandler(sc->handle, ACPI_DEVICE_NOTIFY, 246143794Sphilip acpi_fujitsu_notify_handler, sc); 247143794Sphilip 248155020Sphilip /* Snag our default values for the hotkys / hotkey states. */ 249144623Sphilip ACPI_SERIAL_BEGIN(fujitsu); 250144623Sphilip if (!acpi_fujitsu_init(sc)) 251155020Sphilip device_printf(dev, "Couldn't initialize hotkey states!\n"); 252144623Sphilip ACPI_SERIAL_END(fujitsu); 253143794Sphilip 254143794Sphilip return (0); 255143794Sphilip} 256143794Sphilip 257143794Sphilip/* 258143794Sphilip * Called when the system is being suspended, simply 259143794Sphilip * set an event to be signalled when we wake up. 260143794Sphilip */ 261143794Sphilipstatic int 262143794Sphilipacpi_fujitsu_suspend(device_t dev) 263143794Sphilip{ 264143794Sphilip 265143794Sphilip return (0); 266143794Sphilip} 267143794Sphilip 268143794Sphilipstatic int 269143794Sphilipacpi_fujitsu_resume(device_t dev) 270143794Sphilip{ 271143794Sphilip struct acpi_fujitsu_softc *sc; 272143794Sphilip ACPI_STATUS status; 273143794Sphilip 274143794Sphilip sc = device_get_softc(dev); 275143794Sphilip 276143794Sphilip /* 277143794Sphilip * The pointer needs to be re-enabled for 278143794Sphilip * some revisions of the P series (2120). 279143794Sphilip */ 280143794Sphilip ACPI_SERIAL_BEGIN(fujitsu); 281143794Sphilip 282155020Sphilip if(sc->gmou.exists) { 283155020Sphilip status = acpi_SetInteger(sc->handle, "SMOU", 1); 284155020Sphilip if (ACPI_FAILURE(status)) 285155020Sphilip device_printf(sc->dev, "Couldn't enable pointer\n"); 286155020Sphilip } 287143794Sphilip ACPI_SERIAL_END(fujitsu); 288143794Sphilip 289143794Sphilip return (0); 290143794Sphilip} 291143794Sphilip 292143794Sphilipstatic void 293143794Sphilipacpi_fujitsu_notify_status_changed(void *arg) 294143794Sphilip{ 295143794Sphilip struct acpi_fujitsu_softc *sc; 296143794Sphilip 297143794Sphilip ACPI_FUNCTION_TRACE((char *)(uintptr_t)__func__); 298143794Sphilip 299143794Sphilip sc = (struct acpi_fujitsu_softc *)arg; 300143794Sphilip 301143794Sphilip /* 302143794Sphilip * Since our notify function is called, we know something has 303143794Sphilip * happened. So the only reason for acpi_fujitsu_update to fail 304143794Sphilip * is if we can't find what has changed or an error occurs. 305143794Sphilip */ 306143794Sphilip ACPI_SERIAL_BEGIN(fujitsu); 307143794Sphilip acpi_fujitsu_update(sc); 308143794Sphilip ACPI_SERIAL_END(fujitsu); 309143794Sphilip} 310143794Sphilip 311143794Sphilip 312143794Sphilipstatic void 313143794Sphilipacpi_fujitsu_notify_handler(ACPI_HANDLE h, uint32_t notify, void *context) 314143794Sphilip{ 315143794Sphilip struct acpi_fujitsu_softc *sc; 316143794Sphilip 317143794Sphilip ACPI_FUNCTION_TRACE_U32((char *)(uintptr_t)__func__, notify); 318143794Sphilip 319143794Sphilip sc = (struct acpi_fujitsu_softc *)context; 320143794Sphilip 321143794Sphilip switch (notify) { 322143794Sphilip case ACPI_NOTIFY_STATUS_CHANGED: 323143794Sphilip AcpiOsQueueForExecution(OSD_PRIORITY_LO, 324143794Sphilip acpi_fujitsu_notify_status_changed, sc); 325143794Sphilip break; 326143794Sphilip default: 327143794Sphilip /* unknown notification value */ 328143794Sphilip break; 329143794Sphilip } 330143794Sphilip} 331143794Sphilip 332143794Sphilipstatic int 333143794Sphilipacpi_fujitsu_detach(device_t dev) 334143794Sphilip{ 335143794Sphilip struct acpi_fujitsu_softc *sc; 336143794Sphilip 337143794Sphilip sc = device_get_softc(dev); 338143794Sphilip AcpiRemoveNotifyHandler(sc->handle, ACPI_DEVICE_NOTIFY, 339143794Sphilip acpi_fujitsu_notify_handler); 340143794Sphilip 341143794Sphilip sysctl_ctx_free(&sc->sysctl_ctx); 342143794Sphilip 343143794Sphilip return (0); 344143794Sphilip} 345143794Sphilip 346143794Sphilip/* 347143794Sphilip * Initializes the names of the ACPI control methods and grabs 348155020Sphilip * the current state of all of the ACPI hotkeys into the softc. 349143794Sphilip */ 350143794Sphilipstatic uint8_t 351143794Sphilipacpi_fujitsu_init(struct acpi_fujitsu_softc *sc) 352143794Sphilip{ 353143794Sphilip struct acpi_softc *acpi_sc; 354155020Sphilip int i, exists; 355143794Sphilip 356143794Sphilip ACPI_SERIAL_ASSERT(fujitsu); 357143794Sphilip 358143794Sphilip /* Setup all of the names for each control method */ 359143794Sphilip sc->_sta.name = "_STA"; 360143794Sphilip sc->gbll.name = "GBLL"; 361143794Sphilip sc->ghks.name = "GHKS"; 362143794Sphilip sc->gmou.name = "GMOU"; 363143794Sphilip sc->gsif.name = "GSIF"; 364143794Sphilip sc->gvol.name = "GVOL"; 365155020Sphilip sc->ghks.name = "GHKS"; 366155020Sphilip sc->gsif.name = "GSIF"; 367143794Sphilip sc->rbll.name = "RBLL"; 368143794Sphilip sc->rvol.name = "RVOL"; 369143794Sphilip 370155020Sphilip /* Determine what hardware functionality is available */ 371155020Sphilip acpi_fujitsu_check_hardware(sc); 372155020Sphilip 373143794Sphilip /* Build the sysctl tree */ 374143794Sphilip acpi_sc = acpi_device_get_parent_softc(sc->dev); 375143794Sphilip sysctl_ctx_init(&sc->sysctl_ctx); 376143794Sphilip sc->sysctl_tree = SYSCTL_ADD_NODE(&sc->sysctl_ctx, 377143794Sphilip SYSCTL_CHILDREN(acpi_sc->acpi_sysctl_tree), 378143794Sphilip OID_AUTO, "fujitsu", CTLFLAG_RD, 0, ""); 379143794Sphilip 380143794Sphilip for (i = 0; sysctl_table[i].name != NULL; i++) { 381155020Sphilip exists = 0; 382155020Sphilip switch(sysctl_table[i].method) { 383155020Sphilip case METHOD_GMOU: 384155020Sphilip exists = sc->gmou.exists; 385155020Sphilip break; 386155020Sphilip case METHOD_GBLL: 387155020Sphilip exists = sc->gbll.exists; 388155020Sphilip break; 389155020Sphilip case METHOD_GVOL: 390155020Sphilip case METHOD_MUTE: 391155020Sphilip exists = sc->gvol.exists; 392155020Sphilip break; 393155020Sphilip case METHOD_RVOL: 394155020Sphilip exists = sc->rvol.exists; 395155020Sphilip break; 396155020Sphilip case METHOD_RBLL: 397155020Sphilip exists = sc->rbll.exists; 398155020Sphilip break; 399155020Sphilip default: 400155020Sphilip /* Allow by default */ 401155020Sphilip exists = 1; 402155020Sphilip break; 403155020Sphilip } 404155020Sphilip if(!exists) 405155020Sphilip continue; 406143794Sphilip SYSCTL_ADD_PROC(&sc->sysctl_ctx, 407143794Sphilip SYSCTL_CHILDREN(sc->sysctl_tree), OID_AUTO, 408143794Sphilip sysctl_table[i].name, 409143794Sphilip CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_ANYBODY, 410143794Sphilip sc, i, acpi_fujitsu_sysctl, "I", 411143794Sphilip sysctl_table[i].description); 412143794Sphilip } 413143794Sphilip 414155020Sphilip 415155020Sphilip /* Set the hotkeys to their initial states */ 416143794Sphilip if (!acpi_fujitsu_update(sc)) { 417155020Sphilip device_printf(sc->dev, "Couldn't init hotkey states\n"); 418143794Sphilip return (FALSE); 419143794Sphilip } 420143794Sphilip 421143794Sphilip return (TRUE); 422143794Sphilip} 423143794Sphilip 424143794Sphilipstatic int 425143794Sphilipacpi_fujitsu_sysctl(SYSCTL_HANDLER_ARGS) 426143794Sphilip{ 427143794Sphilip struct acpi_fujitsu_softc *sc; 428143794Sphilip int method; 429143794Sphilip int arg; 430143794Sphilip int function_num, error = 0; 431143794Sphilip 432143794Sphilip sc = (struct acpi_fujitsu_softc *)oidp->oid_arg1; 433143794Sphilip function_num = oidp->oid_arg2; 434143794Sphilip method = sysctl_table[function_num].method; 435143794Sphilip 436143794Sphilip ACPI_SERIAL_BEGIN(fujitsu); 437143794Sphilip 438143794Sphilip /* Get the current value */ 439143794Sphilip arg = acpi_fujitsu_method_get(sc, method); 440143794Sphilip error = sysctl_handle_int(oidp, &arg, 0, req); 441143794Sphilip 442143794Sphilip if (error != 0 || req->newptr == NULL) 443143794Sphilip goto out; 444143794Sphilip 445143794Sphilip /* Update the value */ 446143794Sphilip error = acpi_fujitsu_method_set(sc, method, arg); 447143794Sphilip 448143794Sphilipout: 449143794Sphilip ACPI_SERIAL_END(fujitsu); 450143794Sphilip return (error); 451143794Sphilip} 452143794Sphilip 453143794Sphilipstatic int 454143794Sphilipacpi_fujitsu_method_get(struct acpi_fujitsu_softc *sc, int method) 455143794Sphilip{ 456143794Sphilip struct int_nameval nv; 457143794Sphilip ACPI_STATUS status; 458143794Sphilip 459143794Sphilip ACPI_SERIAL_ASSERT(fujitsu); 460143794Sphilip 461143794Sphilip switch (method) { 462143794Sphilip case METHOD_GBLL: 463143794Sphilip nv = sc->gbll; 464143794Sphilip break; 465143794Sphilip case METHOD_GMOU: 466143794Sphilip nv = sc->gmou; 467143794Sphilip break; 468143794Sphilip case METHOD_GVOL: 469143794Sphilip case METHOD_MUTE: 470143794Sphilip nv = sc->gvol; 471143794Sphilip break; 472155020Sphilip case METHOD_GHKS: 473155020Sphilip nv = sc->ghks; 474155020Sphilip break; 475155020Sphilip case METHOD_GSIF: 476155020Sphilip nv = sc->gsif; 477155020Sphilip break; 478155020Sphilip case METHOD_RBLL: 479155020Sphilip nv = sc->rbll; 480155020Sphilip break; 481155020Sphilip case METHOD_RVOL: 482155020Sphilip nv = sc->rvol; 483155020Sphilip break; 484143794Sphilip default: 485143794Sphilip return (FALSE); 486143794Sphilip } 487143794Sphilip 488155020Sphilip if(!nv.exists) 489155020Sphilip return (EINVAL); 490155020Sphilip 491143794Sphilip status = acpi_GetInteger(sc->handle, nv.name, &nv.value); 492143794Sphilip if (ACPI_FAILURE(status)) { 493155020Sphilip device_printf(sc->dev, "Couldn't query method (%s)\n", nv.name); 494143794Sphilip return (FALSE); 495143794Sphilip } 496143794Sphilip 497143794Sphilip if (method == METHOD_MUTE) { 498143794Sphilip sc->bIsMuted = (uint8_t)((nv.value & VOLUME_MUTE_BIT) != 0); 499143794Sphilip return (sc->bIsMuted); 500143794Sphilip } 501143794Sphilip 502143794Sphilip nv.value &= GENERAL_SETTING_BITS; 503143794Sphilip return (nv.value); 504143794Sphilip} 505143794Sphilip 506143794Sphilipstatic int 507143794Sphilipacpi_fujitsu_method_set(struct acpi_fujitsu_softc *sc, int method, int value) 508143794Sphilip{ 509143794Sphilip struct int_nameval nv; 510143794Sphilip ACPI_STATUS status; 511143794Sphilip char *control; 512143794Sphilip int changed; 513143794Sphilip 514143794Sphilip ACPI_SERIAL_ASSERT(fujitsu); 515143794Sphilip 516143794Sphilip switch (method) { 517143794Sphilip case METHOD_GBLL: 518143794Sphilip changed = BRIGHT_CHANGED; 519143794Sphilip control = "SBLL"; 520143794Sphilip nv = sc->gbll; 521143794Sphilip break; 522143794Sphilip case METHOD_GMOU: 523143794Sphilip changed = MOUSE_CHANGED; 524143794Sphilip control = "SMOU"; 525143794Sphilip nv = sc->gmou; 526143794Sphilip break; 527143794Sphilip case METHOD_GVOL: 528143794Sphilip case METHOD_MUTE: 529143794Sphilip changed = VOLUME_CHANGED; 530143794Sphilip control = "SVOL"; 531143794Sphilip nv = sc->gvol; 532143794Sphilip break; 533143794Sphilip default: 534143794Sphilip return (EINVAL); 535143794Sphilip } 536143794Sphilip 537155020Sphilip if(!nv.exists) 538155020Sphilip return (EINVAL); 539155020Sphilip 540143794Sphilip if (method == METHOD_MUTE) { 541143794Sphilip if (value == 1) 542143794Sphilip value = nv.value | VOLUME_MUTE_BIT; 543143794Sphilip else if (value == 0) 544143794Sphilip value = nv.value & ~VOLUME_MUTE_BIT; 545143794Sphilip else 546143794Sphilip return (EINVAL); 547143794Sphilip } 548143794Sphilip 549143794Sphilip status = acpi_SetInteger(sc->handle, control, value); 550143794Sphilip if (ACPI_FAILURE(status)) { 551143794Sphilip device_printf(sc->dev, "Couldn't update %s\n", control); 552155020Sphilip return (FALSE); 553143794Sphilip } 554143794Sphilip 555143794Sphilip sc->lastValChanged = changed; 556143794Sphilip return (0); 557143794Sphilip} 558143794Sphilip 559143794Sphilip/* 560155020Sphilip * Query the get methods to determine what functionality is available 561155020Sphilip * from the hardware function hotkeys. 562143794Sphilip */ 563143794Sphilipstatic uint8_t 564155020Sphilipacpi_fujitsu_check_hardware(struct acpi_fujitsu_softc *sc) 565143794Sphilip{ 566155020Sphilip int val; 567143794Sphilip struct acpi_softc *acpi_sc; 568143794Sphilip 569143794Sphilip acpi_sc = acpi_device_get_parent_softc(sc->dev); 570143794Sphilip 571143794Sphilip ACPI_SERIAL_ASSERT(fujitsu); 572155020Sphilip /* save the hotkey bitmask */ 573155020Sphilip if (ACPI_FAILURE(acpi_GetInteger(sc->handle, 574155020Sphilip sc->gsif.name, &(sc->gsif.value)))) { 575155020Sphilip sc->gsif.exists = 0; 576155020Sphilip device_printf(sc->dev, "Couldn't query bitmask value\n"); 577155020Sphilip } else { 578155020Sphilip sc->gsif.exists = 1; 579155020Sphilip } 580143794Sphilip 581143794Sphilip /* System Volume Level */ 582143794Sphilip if (ACPI_FAILURE(acpi_GetInteger(sc->handle, 583155020Sphilip sc->gvol.name, &val))) { 584155020Sphilip sc->gvol.exists = 0; 585155020Sphilip } else { 586155020Sphilip sc->gvol.exists = 1; 587143794Sphilip } 588143794Sphilip 589155020Sphilip if (ACPI_FAILURE(acpi_GetInteger(sc->handle, 590155020Sphilip sc->gbll.name, &val))) { 591155020Sphilip sc->gbll.exists = 0; 592155020Sphilip } else { 593155020Sphilip sc->gbll.exists = 1; 594155020Sphilip } 595143794Sphilip 596155020Sphilip if (ACPI_FAILURE(acpi_GetInteger(sc->handle, 597155020Sphilip sc->ghks.name, &val))) { 598155020Sphilip sc->ghks.exists = 0; 599155020Sphilip } else { 600155020Sphilip sc->ghks.exists = 1; 601143794Sphilip } 602143794Sphilip 603143794Sphilip if (ACPI_FAILURE(acpi_GetInteger(sc->handle, 604155020Sphilip sc->gmou.name, &val))) { 605155020Sphilip sc->gmou.exists = 0; 606155020Sphilip } else { 607155020Sphilip sc->gmou.exists = 1; 608143794Sphilip } 609143794Sphilip 610155020Sphilip if (ACPI_FAILURE(acpi_GetInteger(sc->handle, 611155020Sphilip sc->rbll.name, &val))) { 612155020Sphilip sc->rbll.exists = 0; 613155020Sphilip } else { 614155020Sphilip sc->rbll.exists = 1; 615143794Sphilip } 616143794Sphilip 617143794Sphilip if (ACPI_FAILURE(acpi_GetInteger(sc->handle, 618155020Sphilip sc->rvol.name, &val))) { 619155020Sphilip sc->rvol.exists = 0; 620155020Sphilip } else { 621155020Sphilip sc->rvol.exists = 1; 622143794Sphilip } 623143794Sphilip 624155020Sphilip return (TRUE); 625155020Sphilip} 626143794Sphilip 627155020Sphilip/* 628155020Sphilip * Query each of the ACPI control methods that contain information we're 629155020Sphilip * interested in. We check the return values from the control methods and 630155020Sphilip * adjust any state variables if they should be adjusted. 631155020Sphilip */ 632155020Sphilipstatic uint8_t 633155020Sphilipacpi_fujitsu_update(struct acpi_fujitsu_softc *sc) 634155020Sphilip{ 635155020Sphilip int changed; 636155020Sphilip struct acpi_softc *acpi_sc; 637143794Sphilip 638155020Sphilip acpi_sc = acpi_device_get_parent_softc(sc->dev); 639143794Sphilip 640155020Sphilip ACPI_SERIAL_ASSERT(fujitsu); 641155020Sphilip if(sc->gsif.exists) 642155020Sphilip changed = sc->gsif.value & acpi_fujitsu_method_get(sc,METHOD_GHKS); 643155020Sphilip else 644155020Sphilip changed = 0; 645143794Sphilip 646155020Sphilip /* System Volume Level */ 647155020Sphilip if(sc->gvol.exists) { 648155020Sphilip if (ACPI_FAILURE(acpi_GetInteger(sc->handle, 649155020Sphilip sc->gvol.name, &(sc->gvol.value)))) { 650155020Sphilip device_printf(sc->dev, "Couldn't query volume level\n"); 651155020Sphilip return (FALSE); 652155020Sphilip } 653155020Sphilip 654155020Sphilip if (changed & VOLUME_CHANGED) { 655155020Sphilip sc->bIsMuted = 656155020Sphilip (uint8_t)((sc->gvol.value & VOLUME_MUTE_BIT) != 0); 657155020Sphilip 658155020Sphilip /* Clear the modification bit */ 659155020Sphilip sc->gvol.value &= VOLUME_SETTING_BITS; 660155020Sphilip 661155020Sphilip if (sc->bIsMuted) { 662155020Sphilip acpi_UserNotify("FUJITSU", sc->handle, FN_MUTE); 663155020Sphilip ACPI_VPRINT(sc->dev, acpi_sc, "Volume is now mute\n"); 664155020Sphilip } else 665155020Sphilip ACPI_VPRINT(sc->dev, acpi_sc, "Volume is now %d\n", 666155020Sphilip sc->gvol.value); 667155020Sphilip 668155020Sphilip acpi_UserNotify("FUJITSU", sc->handle, FN_VOLUME); 669155020Sphilip } 670143794Sphilip } 671143794Sphilip 672155020Sphilip /* Internal mouse pointer (eraserhead) */ 673155020Sphilip if(sc->gmou.exists) { 674155020Sphilip if (ACPI_FAILURE(acpi_GetInteger(sc->handle, 675155020Sphilip sc->gmou.name, &(sc->gmou.value)))) { 676155020Sphilip device_printf(sc->dev, "Couldn't query pointer state\n"); 677155020Sphilip return (FALSE); 678155020Sphilip } 679155020Sphilip 680155020Sphilip if (changed & MOUSE_CHANGED) { 681155020Sphilip sc->bIntPtrEnabled = (uint8_t)(sc->gmou.value & 0x1); 682155020Sphilip 683155020Sphilip /* Clear the modification bit */ 684155020Sphilip sc->gmou.value &= MOUSE_SETTING_BITS; 685155020Sphilip 686155020Sphilip acpi_UserNotify("FUJITSU", sc->handle, FN_POINTER_ENABLE); 687155020Sphilip 688155020Sphilip ACPI_VPRINT(sc->dev, acpi_sc, "Internal pointer is now %s\n", 689155020Sphilip (sc->bIntPtrEnabled) ? "enabled" : "disabled"); 690155020Sphilip } 691155020Sphilip } 692155020Sphilip 693155020Sphilip /* Screen Brightness Level */ 694155020Sphilip if(sc->gbll.exists) { 695155020Sphilip if (ACPI_FAILURE(acpi_GetInteger(sc->handle, 696155020Sphilip sc->gbll.name, &(sc->gbll.value)))) { 697155020Sphilip device_printf(sc->dev, "Couldn't query brightness level\n"); 698155020Sphilip return (FALSE); 699155020Sphilip } 700155020Sphilip 701155020Sphilip if (changed & BRIGHT_CHANGED) { 702155020Sphilip /* No state to record here. */ 703155020Sphilip 704155020Sphilip /* Clear the modification bit */ 705155020Sphilip sc->gbll.value &= BRIGHTNESS_SETTING_BITS; 706155020Sphilip 707155020Sphilip acpi_UserNotify("FUJITSU", sc->handle, FN_LCD_BRIGHTNESS); 708155020Sphilip 709155020Sphilip ACPI_VPRINT(sc->dev, acpi_sc, "Brightness level is now %d\n", 710155020Sphilip sc->gbll.value); 711155020Sphilip } 712155020Sphilip } 713155020Sphilip 714155020Sphilip sc->lastValChanged = changed; 715143794Sphilip return (TRUE); 716143794Sphilip} 717