Add acpi_fujitsu module for Fujitsu laptops.
authorAlexander Polakov <polachok@gmail.com>
Tue, 29 Sep 2009 20:58:51 +0000 (20:58 +0000)
committerAlexander Polakov <polachok@gmail.com>
Mon, 12 Oct 2009 06:17:31 +0000 (10:17 +0400)
Obtained-from: FreeBSD

sys/dev/acpica5/Makefile
sys/dev/acpica5/acpi_fujitsu/Makefile [new file with mode: 0644]
sys/dev/acpica5/acpi_fujitsu/acpi_fujitsu.c [new file with mode: 0644]

index 30574a6..c57eef2 100644 (file)
@@ -115,7 +115,7 @@ acpi_wakecode.h: acpi_wakecode.S
        ${MAKE} -f ${SYSDIR}/${OSACPI_MD_DIR}/Makefile \
                MAKESRCPATH=${SYSDIR}/${OSACPI_MD_DIR}
 
-SUBDIR=        acpi_asus acpi_thinkpad acpi_toshiba acpi_video aibs
+SUBDIR=        acpi_asus acpi_fujitsu acpi_thinkpad acpi_toshiba acpi_video aibs
 all: ${PROG} ${SUBDIR}
 
 .include <bsd.kmod.mk>
diff --git a/sys/dev/acpica5/acpi_fujitsu/Makefile b/sys/dev/acpica5/acpi_fujitsu/Makefile
new file mode 100644 (file)
index 0000000..8cc5f88
--- /dev/null
@@ -0,0 +1,5 @@
+KMOD=          acpi_fujitsu
+CFLAGS+=       -I${.OBJDIR}/.. -I${.CURDIR}/..
+SRCS=          acpi_fujitsu.c opt_acpi.h device_if.h bus_if.h
+
+.include <bsd.kmod.mk>
diff --git a/sys/dev/acpica5/acpi_fujitsu/acpi_fujitsu.c b/sys/dev/acpica5/acpi_fujitsu/acpi_fujitsu.c
new file mode 100644 (file)
index 0000000..6e698ee
--- /dev/null
@@ -0,0 +1,718 @@
+/*-
+ * Copyright (c) 2002 Sean Bullington <seanATstalker.org>
+ *               2003-2006 Anish Mistry <amistry@am-productions.biz>
+ *               2004 Mark Santcroos <marks@ripe.net>
+ * All Rights Reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD: src/sys/dev/acpi_support/acpi_fujitsu.c,v 1.7 2009/06/05 18:44:36 jkim
+ */
+
+#include <sys/cdefs.h>
+
+#include "opt_acpi.h"
+#include <sys/param.h>
+#include <sys/kernel.h>
+#include <sys/bus.h>
+#include <sys/module.h>
+#include <sys/sysctl.h>
+
+#include "acpi.h"
+#include "accommon.h"
+
+#include <dev/acpica5/acpivar.h>
+
+/* Hooks for the ACPI CA debugging infrastructure */
+#define _COMPONENT     ACPI_OEM
+ACPI_MODULE_NAME("Fujitsu")
+
+/* Change and update bits for the hotkeys */
+#define VOLUME_MUTE_BIT                0x40000000
+
+/* Values of settings */
+#define GENERAL_SETTING_BITS   0x0fffffff
+#define MOUSE_SETTING_BITS     GENERAL_SETTING_BITS
+#define VOLUME_SETTING_BITS    GENERAL_SETTING_BITS
+#define BRIGHTNESS_SETTING_BITS        GENERAL_SETTING_BITS
+
+/* Possible state changes */
+/*
+ * These are NOT arbitrary values.  They are the
+ * GHKS return value from the device that says which
+ * hotkey is active.  They should match up with a bit
+ * from the GSIF bitmask.
+ */
+#define BRIGHT_CHANGED 0x01
+#define VOLUME_CHANGED 0x04
+#define MOUSE_CHANGED  0x08
+/*
+ * It is unknown which hotkey this bit is supposed to indicate, but
+ * according to values from GSIF this is a valid flag.
+ */
+#define UNKNOWN_CHANGED        0x10
+
+/* sysctl values */
+#define FN_MUTE                        0
+#define FN_POINTER_ENABLE      1
+#define FN_LCD_BRIGHTNESS      2
+#define FN_VOLUME              3
+
+/* Methods */
+#define METHOD_GBLL    1
+#define METHOD_GMOU    2
+#define METHOD_GVOL    3
+#define METHOD_MUTE    4
+#define METHOD_RBLL    5
+#define METHOD_RVOL    6
+#define METHOD_GSIF    7
+#define METHOD_GHKS    8
+
+/* Notify event */
+#define        ACPI_NOTIFY_STATUS_CHANGED      0x80
+
+/*
+ * Holds a control method name and its associated integer value.
+ * Only used for no-argument control methods which return a value.
+ */
+struct int_nameval {
+       char    *name;
+       int     value;
+       int     exists;
+};
+
+/*
+ * Driver extension for the FUJITSU ACPI driver.
+ */
+struct acpi_fujitsu_softc {
+       device_t        dev;
+       ACPI_HANDLE     handle;
+
+       /* Control methods */
+       struct int_nameval      _sta,   /* unused */
+                               gbll,   /* brightness */
+                               ghks,   /* hotkey selector */
+                               gbuf,   /* unused (buffer?) */
+                               gmou,   /* mouse */
+                               gsif,   /* function key bitmask */
+                               gvol,   /* volume */
+                               rbll,   /* number of brightness levels (radix) */
+                               rvol;   /* number of volume levels (radix) */
+
+       /* State variables */
+       uint8_t         bIsMuted;       /* Is volume muted */
+       uint8_t         bIntPtrEnabled; /* Is internal ptr enabled */
+       uint32_t        lastValChanged; /* The last value updated */
+
+       /* sysctl tree */
+       struct sysctl_ctx_list  sysctl_ctx;
+       struct sysctl_oid       *sysctl_tree;
+};
+
+/* Driver entry point forward declarations. */
+static int     acpi_fujitsu_probe(device_t dev);
+static int     acpi_fujitsu_attach(device_t dev);
+static int     acpi_fujitsu_detach(device_t dev);
+static int     acpi_fujitsu_suspend(device_t dev);
+static int     acpi_fujitsu_resume(device_t dev);
+
+static void    acpi_fujitsu_notify_status_changed(void *arg);
+static void    acpi_fujitsu_notify_handler(ACPI_HANDLE h, uint32_t notify, void *context);
+static int     acpi_fujitsu_sysctl(SYSCTL_HANDLER_ARGS);
+
+/* Utility function declarations */
+static uint8_t acpi_fujitsu_update(struct acpi_fujitsu_softc *sc);
+static uint8_t acpi_fujitsu_init(struct acpi_fujitsu_softc *sc);
+static uint8_t acpi_fujitsu_check_hardware(struct acpi_fujitsu_softc *sc);
+
+/* Driver/Module specific structure definitions. */
+static device_method_t acpi_fujitsu_methods[] = {
+       /* Device interface */
+       DEVMETHOD(device_probe,         acpi_fujitsu_probe),
+       DEVMETHOD(device_attach,        acpi_fujitsu_attach),
+       DEVMETHOD(device_detach,        acpi_fujitsu_detach),
+       DEVMETHOD(device_suspend,       acpi_fujitsu_suspend),
+       DEVMETHOD(device_resume,        acpi_fujitsu_resume),
+       {0, 0}
+};
+
+static driver_t acpi_fujitsu_driver = {
+       "acpi_fujitsu",
+       acpi_fujitsu_methods,
+       sizeof(struct acpi_fujitsu_softc),
+};
+
+/* Prototype for function hotkeys for getting/setting a value. */
+static int acpi_fujitsu_method_get(struct acpi_fujitsu_softc *sc, int method);
+static int acpi_fujitsu_method_set(struct acpi_fujitsu_softc *sc, int method, int value);
+
+static char *fujitsu_ids[] = { "FUJ02B1", NULL };
+
+ACPI_SERIAL_DECL(fujitsu, "Fujitsu Function Hotkeys");
+
+/* sysctl names and function calls */
+static struct {
+       char            *name;
+       int             method;
+       char            *description;
+} sysctl_table[] = {
+       {
+               .name           = "mute",
+               .method         = METHOD_MUTE,
+               .description    = "Speakers/headphones mute status"
+       },
+       {
+               .name           = "pointer_enable",
+               .method         = METHOD_GMOU,
+               .description    = "Enable and disable the internal pointer"
+       },
+       {
+               .name           = "lcd_brightness",
+               .method         = METHOD_GBLL,
+               .description    = "Brightness level of the LCD panel"
+       },
+       {
+               .name           = "volume",
+               .method         = METHOD_GVOL,
+               .description    = "Speakers/headphones volume level"
+       },
+       {
+               .name           = "volume_radix",
+               .method         = METHOD_RVOL,
+               .description    = "Number of volume level steps"
+       },
+       {
+               .name           = "lcd_brightness_radix",
+               .method         = METHOD_RBLL,
+               .description    = "Number of brightness level steps"
+       },
+
+       { NULL, 0, NULL }
+};
+
+static devclass_t acpi_fujitsu_devclass;
+DRIVER_MODULE(acpi_fujitsu, acpi, acpi_fujitsu_driver,
+    acpi_fujitsu_devclass, 0, 0);
+MODULE_DEPEND(acpi_fujitsu, acpi, 1, 1, 1);
+MODULE_VERSION(acpi_fujitsu, 1);
+
+static int
+acpi_fujitsu_probe(device_t dev)
+{
+       char *name;
+       char buffer[64];
+
+       name = ACPI_ID_PROBE(device_get_parent(dev), dev, fujitsu_ids);
+       if (acpi_disabled("fujitsu") || name == NULL ||
+           device_get_unit(dev) > 1)
+               return (ENXIO);
+
+       ksprintf(buffer, "Fujitsu Function Hotkeys %s", name);
+       device_set_desc_copy(dev, buffer);
+
+       return (0);
+}
+
+static int
+acpi_fujitsu_attach(device_t dev)
+{
+       struct acpi_fujitsu_softc *sc;
+
+       ACPI_FUNCTION_TRACE((char *)(uintptr_t)__func__);
+
+       sc = device_get_softc(dev);
+       sc->dev = dev;
+       sc->handle = acpi_get_handle(dev);
+
+       /* Install notification handler */
+       AcpiInstallNotifyHandler(sc->handle, ACPI_DEVICE_NOTIFY,
+           acpi_fujitsu_notify_handler, sc);
+
+       /* Snag our default values for the hotkeys / hotkey states. */
+       ACPI_SERIAL_BEGIN(fujitsu);
+       if (!acpi_fujitsu_init(sc))
+               device_printf(dev, "Couldn't initialize hotkey states!\n");
+       ACPI_SERIAL_END(fujitsu);
+
+       return (0);
+}
+
+/*
+ * Called when the system is being suspended, simply
+ * set an event to be signalled when we wake up.
+ */
+static int
+acpi_fujitsu_suspend(device_t dev)
+{
+
+       return (0);
+}
+
+static int
+acpi_fujitsu_resume(device_t dev)
+{
+       struct acpi_fujitsu_softc   *sc;
+       ACPI_STATUS                 status;
+
+       sc = device_get_softc(dev);
+
+       /*
+        * The pointer needs to be re-enabled for
+        * some revisions of the P series (2120).
+        */
+       ACPI_SERIAL_BEGIN(fujitsu);
+
+       if(sc->gmou.exists) {
+               status = acpi_SetInteger(sc->handle, "SMOU", 1);
+               if (ACPI_FAILURE(status))
+                       device_printf(sc->dev, "Couldn't enable pointer\n");
+       }
+       ACPI_SERIAL_END(fujitsu);
+
+       return (0);
+}
+
+static void
+acpi_fujitsu_notify_status_changed(void *arg)
+{
+       struct acpi_fujitsu_softc *sc;
+
+       ACPI_FUNCTION_TRACE((char *)(uintptr_t)__func__);
+
+       sc = (struct acpi_fujitsu_softc *)arg;
+
+       /*
+        * Since our notify function is called, we know something has
+        * happened.  So the only reason for acpi_fujitsu_update to fail
+        * is if we can't find what has changed or an error occurs.
+        */
+       ACPI_SERIAL_BEGIN(fujitsu);
+       acpi_fujitsu_update(sc);
+       ACPI_SERIAL_END(fujitsu);
+}
+
+
+static void
+acpi_fujitsu_notify_handler(ACPI_HANDLE h, uint32_t notify, void *context)
+{
+       struct acpi_fujitsu_softc *sc;
+
+       ACPI_FUNCTION_TRACE_U32((char *)(uintptr_t)__func__, notify);
+
+       sc = (struct acpi_fujitsu_softc *)context;
+
+       switch (notify) {
+       case ACPI_NOTIFY_STATUS_CHANGED:
+               AcpiOsExecute(OSL_NOTIFY_HANDLER,
+                   acpi_fujitsu_notify_status_changed, sc);
+               break;
+       default:
+               /* unknown notification value */
+               break;
+       }
+}
+
+static int
+acpi_fujitsu_detach(device_t dev)
+{
+       struct acpi_fujitsu_softc *sc;
+
+       sc = device_get_softc(dev);
+       AcpiRemoveNotifyHandler(sc->handle, ACPI_DEVICE_NOTIFY,
+          acpi_fujitsu_notify_handler);
+
+       sysctl_ctx_free(&sc->sysctl_ctx);
+
+       return (0);
+}
+
+/*
+ * Initializes the names of the ACPI control methods and grabs
+ * the current state of all of the ACPI hotkeys into the softc.
+ */
+static uint8_t
+acpi_fujitsu_init(struct acpi_fujitsu_softc *sc)
+{
+       struct acpi_softc *acpi_sc;
+       int i, exists;
+
+       ACPI_SERIAL_ASSERT(fujitsu);
+
+       /* Setup all of the names for each control method */
+       sc->_sta.name = "_STA";
+       sc->gbll.name = "GBLL";
+       sc->ghks.name = "GHKS";
+       sc->gmou.name = "GMOU";
+       sc->gsif.name = "GSIF";
+       sc->gvol.name = "GVOL";
+       sc->ghks.name = "GHKS";
+       sc->gsif.name = "GSIF";
+       sc->rbll.name = "RBLL";
+       sc->rvol.name = "RVOL";
+
+       /* Determine what hardware functionality is available */
+       acpi_fujitsu_check_hardware(sc);
+
+       /* Build the sysctl tree */
+       acpi_sc = acpi_device_get_parent_softc(sc->dev);
+       sysctl_ctx_init(&sc->sysctl_ctx);
+       sc->sysctl_tree = SYSCTL_ADD_NODE(&sc->sysctl_ctx,
+           SYSCTL_CHILDREN(acpi_sc->acpi_sysctl_tree),
+           OID_AUTO, "fujitsu", CTLFLAG_RD, 0, "");
+
+       for (i = 0; sysctl_table[i].name != NULL; i++) {
+               exists = 0;
+               switch(sysctl_table[i].method) {
+                       case METHOD_GMOU:
+                               exists = sc->gmou.exists;
+                               break;
+                       case METHOD_GBLL:
+                               exists = sc->gbll.exists;
+                               break;
+                       case METHOD_GVOL:
+                       case METHOD_MUTE:
+                               exists = sc->gvol.exists;
+                               break;
+                       case METHOD_RVOL:
+                               exists = sc->rvol.exists;
+                               break;
+                       case METHOD_RBLL:
+                               exists = sc->rbll.exists;
+                               break;
+                       default:
+                               /* Allow by default */
+                               exists = 1;
+                               break;
+               }
+               if(!exists)
+                       continue;
+               SYSCTL_ADD_PROC(&sc->sysctl_ctx,
+                   SYSCTL_CHILDREN(sc->sysctl_tree), OID_AUTO,
+                   sysctl_table[i].name,
+                   CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_ANYBODY,
+                   sc, i, acpi_fujitsu_sysctl, "I",
+                   sysctl_table[i].description);
+       }
+
+
+       /* Set the hotkeys to their initial states */
+       if (!acpi_fujitsu_update(sc)) {
+               device_printf(sc->dev, "Couldn't init hotkey states\n");
+               return (FALSE);
+       }
+
+       return (TRUE);
+}
+
+static int
+acpi_fujitsu_sysctl(SYSCTL_HANDLER_ARGS)
+{
+       struct acpi_fujitsu_softc       *sc;
+       int                             method;
+       int                             arg;
+       int                             function_num, error = 0;
+
+       sc = (struct acpi_fujitsu_softc *)oidp->oid_arg1;
+       function_num = oidp->oid_arg2;
+       method = sysctl_table[function_num].method;
+
+       ACPI_SERIAL_BEGIN(fujitsu);
+
+       /* Get the current value */
+       arg = acpi_fujitsu_method_get(sc, method);
+       error = sysctl_handle_int(oidp, &arg, 0, req);
+
+       if (error != 0 || req->newptr == NULL)
+               goto out;
+
+       /* Update the value */
+       error = acpi_fujitsu_method_set(sc, method, arg);
+
+out:
+       ACPI_SERIAL_END(fujitsu);
+       return (error);
+}
+
+static int
+acpi_fujitsu_method_get(struct acpi_fujitsu_softc *sc, int method)
+{
+       struct int_nameval      nv;
+       ACPI_STATUS             status;
+
+       ACPI_SERIAL_ASSERT(fujitsu);
+
+       switch (method) {
+               case METHOD_GBLL:
+                       nv = sc->gbll;
+                       break;
+               case METHOD_GMOU:
+                       nv = sc->gmou;
+                       break;
+               case METHOD_GVOL:
+               case METHOD_MUTE:
+                       nv = sc->gvol;
+                       break;
+               case METHOD_GHKS:
+                       nv = sc->ghks;
+                       break;
+               case METHOD_GSIF:
+                       nv = sc->gsif;
+                       break;
+               case METHOD_RBLL:
+                       nv = sc->rbll;
+                       break;
+               case METHOD_RVOL:
+                       nv = sc->rvol;
+                       break;
+               default:
+                       return (FALSE);
+       }
+
+       if(!nv.exists)
+               return (EINVAL);
+
+       status = acpi_GetInteger(sc->handle, nv.name, &nv.value);
+       if (ACPI_FAILURE(status)) {
+               device_printf(sc->dev, "Couldn't query method (%s)\n", nv.name);
+               return (FALSE);
+       }
+
+       if (method == METHOD_MUTE) {
+               sc->bIsMuted = (uint8_t)((nv.value & VOLUME_MUTE_BIT) != 0);
+               return (sc->bIsMuted);
+       }
+
+       nv.value &= GENERAL_SETTING_BITS;
+       return (nv.value);
+}
+
+static int
+acpi_fujitsu_method_set(struct acpi_fujitsu_softc *sc, int method, int value)
+{
+       struct int_nameval      nv;
+       ACPI_STATUS             status;
+       char                    *control;
+       int                     changed;
+
+       ACPI_SERIAL_ASSERT(fujitsu);
+
+       switch (method) {
+               case METHOD_GBLL:
+                       changed = BRIGHT_CHANGED;
+                       control = "SBLL";
+                       nv = sc->gbll;
+                       break;
+               case METHOD_GMOU:
+                       changed = MOUSE_CHANGED;
+                       control = "SMOU";
+                       nv = sc->gmou;
+                       break;
+               case METHOD_GVOL:
+               case METHOD_MUTE:
+                       changed = VOLUME_CHANGED;
+                       control = "SVOL";
+                       nv = sc->gvol;
+                       break;
+               default:
+                       return (EINVAL);
+       }
+
+       if(!nv.exists)
+               return (EINVAL);
+
+       if (method == METHOD_MUTE) {
+               if (value == 1)
+                       value = nv.value | VOLUME_MUTE_BIT;
+               else if (value == 0)
+                       value = nv.value & ~VOLUME_MUTE_BIT;
+               else
+                       return (EINVAL);
+       }
+
+       status = acpi_SetInteger(sc->handle, control, value);
+       if (ACPI_FAILURE(status)) {
+               device_printf(sc->dev, "Couldn't update %s\n", control);
+               return (FALSE);
+       }
+
+       sc->lastValChanged = changed;
+       return (0);
+}
+
+/*
+ * Query the get methods to determine what functionality is available
+ * from the hardware function hotkeys.
+ */
+static uint8_t
+acpi_fujitsu_check_hardware(struct acpi_fujitsu_softc *sc)
+{
+       int val;
+       struct acpi_softc *acpi_sc;
+
+       acpi_sc = acpi_device_get_parent_softc(sc->dev);
+
+       ACPI_SERIAL_ASSERT(fujitsu);
+       /* save the hotkey bitmask */
+       if (ACPI_FAILURE(acpi_GetInteger(sc->handle,
+       sc->gsif.name, &(sc->gsif.value)))) {
+               sc->gsif.exists = 0;
+               device_printf(sc->dev, "Couldn't query bitmask value\n");
+       } else {
+               sc->gsif.exists = 1;
+       }
+
+       /* System Volume Level */
+       if (ACPI_FAILURE(acpi_GetInteger(sc->handle,
+           sc->gvol.name, &val))) {
+               sc->gvol.exists = 0;
+       } else {
+               sc->gvol.exists = 1;
+       }
+
+       if (ACPI_FAILURE(acpi_GetInteger(sc->handle,
+           sc->gbll.name, &val))) {
+               sc->gbll.exists = 0;
+       } else {
+               sc->gbll.exists = 1;
+       }
+
+       if (ACPI_FAILURE(acpi_GetInteger(sc->handle,
+           sc->ghks.name, &val))) {
+               sc->ghks.exists = 0;
+       } else {
+               sc->ghks.exists = 1;
+       }
+
+       if (ACPI_FAILURE(acpi_GetInteger(sc->handle,
+           sc->gmou.name, &val))) {
+               sc->gmou.exists = 0;
+       } else {
+               sc->gmou.exists = 1;
+       }
+
+       if (ACPI_FAILURE(acpi_GetInteger(sc->handle,
+           sc->rbll.name, &val))) {
+               sc->rbll.exists = 0;
+       } else {
+               sc->rbll.exists = 1;
+       }
+
+       if (ACPI_FAILURE(acpi_GetInteger(sc->handle,
+           sc->rvol.name, &val))) {
+               sc->rvol.exists = 0;
+       } else {
+               sc->rvol.exists = 1;
+       }
+
+       return (TRUE);
+}
+
+/*
+ * Query each of the ACPI control methods that contain information we're
+ * interested in. We check the return values from the control methods and
+ * adjust any state variables if they should be adjusted.
+ */
+static uint8_t
+acpi_fujitsu_update(struct acpi_fujitsu_softc *sc)
+{
+       int changed;
+       struct acpi_softc *acpi_sc;
+
+       acpi_sc = acpi_device_get_parent_softc(sc->dev);
+
+       ACPI_SERIAL_ASSERT(fujitsu);
+       if(sc->gsif.exists)
+               changed = sc->gsif.value & acpi_fujitsu_method_get(sc,METHOD_GHKS);
+       else
+               changed = 0;
+
+       /* System Volume Level */
+       if(sc->gvol.exists) {
+               if (ACPI_FAILURE(acpi_GetInteger(sc->handle,
+               sc->gvol.name, &(sc->gvol.value)))) {
+                       device_printf(sc->dev, "Couldn't query volume level\n");
+                       return (FALSE);
+               }
+       
+               if (changed & VOLUME_CHANGED) {
+                       sc->bIsMuted =
+                       (uint8_t)((sc->gvol.value & VOLUME_MUTE_BIT) != 0);
+       
+                       /* Clear the modification bit */
+                       sc->gvol.value &= VOLUME_SETTING_BITS;
+       
+                       if (sc->bIsMuted) {
+                               acpi_UserNotify("FUJITSU", sc->handle, FN_MUTE);
+                               ACPI_VPRINT(sc->dev, acpi_sc, "Volume is now mute\n");
+                       } else
+                               ACPI_VPRINT(sc->dev, acpi_sc, "Volume is now %d\n",
+                               sc->gvol.value);
+       
+                       acpi_UserNotify("FUJITSU", sc->handle, FN_VOLUME);
+               }
+       }
+
+       /* Internal mouse pointer (eraserhead) */
+       if(sc->gmou.exists) {
+               if (ACPI_FAILURE(acpi_GetInteger(sc->handle,
+               sc->gmou.name, &(sc->gmou.value)))) {
+                       device_printf(sc->dev, "Couldn't query pointer state\n");
+                       return (FALSE);
+               }
+       
+               if (changed & MOUSE_CHANGED) {
+                       sc->bIntPtrEnabled = (uint8_t)(sc->gmou.value & 0x1);
+       
+                       /* Clear the modification bit */
+                       sc->gmou.value &= MOUSE_SETTING_BITS;
+                       
+                       acpi_UserNotify("FUJITSU", sc->handle, FN_POINTER_ENABLE);
+       
+                       ACPI_VPRINT(sc->dev, acpi_sc, "Internal pointer is now %s\n",
+                       (sc->bIntPtrEnabled) ? "enabled" : "disabled");
+               }
+       }
+
+       /* Screen Brightness Level */
+       if(sc->gbll.exists) {
+               if (ACPI_FAILURE(acpi_GetInteger(sc->handle,
+               sc->gbll.name, &(sc->gbll.value)))) {
+                       device_printf(sc->dev, "Couldn't query brightness level\n");
+                       return (FALSE);
+               }
+       
+               if (changed & BRIGHT_CHANGED) {
+                       /* No state to record here. */
+       
+                       /* Clear the modification bit */
+                       sc->gbll.value &= BRIGHTNESS_SETTING_BITS;
+       
+                       acpi_UserNotify("FUJITSU", sc->handle, FN_LCD_BRIGHTNESS);
+       
+                       ACPI_VPRINT(sc->dev, acpi_sc, "Brightness level is now %d\n",
+                       sc->gbll.value);
+               }
+       }
+
+       sc->lastValChanged = changed;
+       return (TRUE);
+}