summaryrefslogtreecommitdiffstats
path: root/sys/dev/acpi_support/acpi_ibm.c
diff options
context:
space:
mode:
authormarkus <markus@FreeBSD.org>2005-06-09 20:17:32 +0000
committermarkus <markus@FreeBSD.org>2005-06-09 20:17:32 +0000
commit0d56bd279353ad2af80137f9ab046c65152267e6 (patch)
treefe46c9c584b03d45fd6b6a359c7b5b3e9e0a6e79 /sys/dev/acpi_support/acpi_ibm.c
parent7a9b003ce5c89fb242246f4edde01e66fdb5a39d (diff)
downloadFreeBSD-src-0d56bd279353ad2af80137f9ab046c65152267e6.zip
FreeBSD-src-0d56bd279353ad2af80137f9ab046c65152267e6.tar.gz
Import a mostly rewritten and extended version of acpi_ibm:
- Restructured for easier extensibility and maintainability - To be more uniform with the other ACPI extras drivers and to better reflect their actual meaning, some sysctls were moved: o brightness -> lcd_brightness o keylight -> thinklight o enable -> events o misckey -> hotkey o avail_mask -> availmask o key_mask -> eventmask - New "initialmask" sysctl, which holds the initial eventmask - The "wlan" sysctl is now read-only, since writing to it didn't have any effect - The "version" sysctl was removed, since it seems to be the same (0x100) on all models I have seen - Support for more hotkeys by the "hotkey" sysctl - Improved support of ACPI events. Disabled by default, since it unexpectedly changes the behaviour of some keys. (on my T41p there are now 24 different keypress events that get reported) - write support for: volume, mute, lcd_brightness and thinklight - led(4) interface for the thinklight [1] - New sysctls "fan" and "fan_speed" to support reading of fan status and speed - New sysctl "thermal" to support reading of up to 8 thermal sensors Reviewed by: philip Approved by: philip Submitted by: simon [1] Inspired by: The Linux ibm_acpi driver by Borislav Deianov http://ibm-acpi.sourceforge.net/ The ThinkPad Button program (tpb) by Markus Braun http://www.nongnu.org/tpb/ Thanks to: brueffer, dvl, njl, philip, simon, takawata and the many testers from freebsd-acpi@ and freebsd-mobile@
Diffstat (limited to 'sys/dev/acpi_support/acpi_ibm.c')
-rw-r--r--sys/dev/acpi_support/acpi_ibm.c1054
1 files changed, 724 insertions, 330 deletions
diff --git a/sys/dev/acpi_support/acpi_ibm.c b/sys/dev/acpi_support/acpi_ibm.c
index eaf07c9..c7ac547 100644
--- a/sys/dev/acpi_support/acpi_ibm.c
+++ b/sys/dev/acpi_support/acpi_ibm.c
@@ -1,5 +1,6 @@
/*-
* Copyright (c) 2004 Takanori Watanabe
+ * Copyright (c) 2005 Markus Brueffer <markus@FreeBSD.org>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -27,6 +28,15 @@
#include <sys/cdefs.h>
__FBSDID("$FreeBSD$");
+/*
+ * Driver for extra ACPI-controlled gadgets found on IBM ThinkPad laptops.
+ * Inspired by the ibm-acpi and tpb projects which implement these features
+ * on Linux.
+ *
+ * acpi-ibm: <http://ibm-acpi.sourceforge.net/>
+ * tpb: <http://www.nongnu.org/tpb/>
+ */
+
#include "opt_acpi.h"
#include <sys/param.h>
#include <sys/kernel.h>
@@ -36,68 +46,208 @@ __FBSDID("$FreeBSD$");
#include "acpi_if.h"
#include <sys/module.h>
#include <dev/acpica/acpivar.h>
+#include <dev/led/led.h>
#include <sys/sysctl.h>
#include <machine/clock.h>
#define _COMPONENT ACPI_OEM
ACPI_MODULE_NAME("IBM")
-#define IBM_RTC_MISCKEY 0x65
-#define IBM_RTC_BRIGHTNESS 0x6c
-#define IBM_RTC_MASK_BRI 0x7
-#define IBM_RTC_MASK_BRKEY 0x40
-#define IBM_RTC_KEYLIGHT 0x66
-#define IBM_RTC_MASK_KEYLIGHT 0x10
-#define IBM_RTC_VOLUME 0x6e
-#define IBM_RTC_MASK_VOL 0xf
-#define IBM_RTC_MASK_MUTE 0x40
-#define IBM_RTC_MASK_VOLKEY 0x80
-
-#define IBM_NAME_GET_WIRELESS "GBDC"
-#define IBM_NAME_SET_WIRELESS "SBDC"
-#define IBM_NAME_INTERFACE_VERSION "MHKV"
-#define IBM_NAME_AVAIL_MASK "MHKA"
-#define IBM_NAME_CURRENT_MASK "MHKN"
-#define IBM_NAME_MODIFY_MASK "MHKM"
-#define IBM_NAME_GET_EVENT "MHKP"
-#define IBM_NAME_ENABLE "MHKC"
-#if 0
-/* TPX31 Specific? */
-#define IBM_UCMS_VOLDN 0x0
-#define IBM_UCMS_VOLUP 0x1
-#define IBM_UCMS_MUTE 0x2
-#define IBM_UCMS_BRIUP 0x4
-#define IBM_UCMS_BRIDN 0x5
-#define IBM_UCMS_KEYLIGHT 0xe
-#endif
+/* Internal methods */
+#define ACPI_IBM_METHOD_EVENTS 1
+#define ACPI_IBM_METHOD_EVENTMASK 2
+#define ACPI_IBM_METHOD_HOTKEY 3
+#define ACPI_IBM_METHOD_BRIGHTNESS 4
+#define ACPI_IBM_METHOD_VOLUME 5
+#define ACPI_IBM_METHOD_MUTE 6
+#define ACPI_IBM_METHOD_THINKLIGHT 7
+#define ACPI_IBM_METHOD_BLUETOOTH 8
+#define ACPI_IBM_METHOD_WLAN 9
+#define ACPI_IBM_METHOD_FANSPEED 10
+#define ACPI_IBM_METHOD_FANSTATUS 11
+#define ACPI_IBM_METHOD_THERMAL 12
+
+/* Hotkeys/Buttons */
+#define IBM_RTC_HOTKEY1 0x64
+#define IBM_RTC_MASK_HOME (1 << 0)
+#define IBM_RTC_MASK_SEARCH (1 << 1)
+#define IBM_RTC_MASK_MAIL (1 << 2)
+#define IBM_RTC_MASK_WLAN (1 << 5)
+#define IBM_RTC_HOTKEY2 0x65
+#define IBM_RTC_MASK_THINKPAD (1 << 3)
+#define IBM_RTC_MASK_ZOOM (1 << 5)
+#define IBM_RTC_MASK_VIDEO (1 << 6)
+#define IBM_RTC_MASK_HIBERNATE (1 << 7)
+#define IBM_RTC_THINKLIGHT 0x66
+#define IBM_RTC_MASK_THINKLIGHT (1 << 4)
+#define IBM_RTC_SCREENEXPAND 0x67
+#define IBM_RTC_MASK_SCREENEXPAND (1 << 5)
+#define IBM_RTC_BRIGHTNESS 0x6c
+#define IBM_RTC_MASK_BRIGHTNESS (1 << 5)
+#define IBM_RTC_VOLUME 0x6e
+#define IBM_RTC_MASK_VOLUME (1 << 7)
+
+/* Embedded Controller registers */
+#define IBM_EC_BRIGHTNESS 0x31
+#define IBM_EC_MASK_BRI 0x7
+#define IBM_EC_VOLUME 0x30
+#define IBM_EC_MASK_VOL 0xf
+#define IBM_EC_MASK_MUTE (1 << 6)
+#define IBM_EC_FANSTATUS 0x2F
+#define IBM_EC_MASK_FANSTATUS (1 << 7)
+#define IBM_EC_FANSPEED 0x84
+
+/* CMOS Commands */
+#define IBM_CMOS_VOLUME_DOWN 0
+#define IBM_CMOS_VOLUME_UP 1
+#define IBM_CMOS_VOLUME_MUTE 2
+#define IBM_CMOS_BRIGHTNESS_UP 4
+#define IBM_CMOS_BRIGHTNESS_DOWN 5
+
+/* ACPI methods */
+#define IBM_NAME_KEYLIGHT "KBLT"
+#define IBM_NAME_WLAN_BT_GET "GBDC"
+#define IBM_NAME_WLAN_BT_SET "SBDC"
+#define IBM_NAME_MASK_BT (1 << 1)
+#define IBM_NAME_MASK_WLAN (1 << 2)
+#define IBM_NAME_THERMAL_GET "TMP7"
+#define IBM_NAME_THERMAL_UPDT "UPDT"
+
+#define IBM_NAME_EVENTS_STATUS_GET "DHKC"
+#define IBM_NAME_EVENTS_MASK_GET "DHKN"
+#define IBM_NAME_EVENTS_STATUS_SET "MHKC"
+#define IBM_NAME_EVENTS_MASK_SET "MHKM"
+#define IBM_NAME_EVENTS_GET "MHKP"
+#define IBM_NAME_EVENTS_AVAILMASK "MHKA"
+
+#define ABS(x) (((x) < 0)? -(x) : (x))
struct acpi_ibm_softc {
- unsigned int ibm_version;
- unsigned int ibm_availmask;
- unsigned int ibm_initialmask;
- int ibm_enable;
- int device_flag;
-#define IBM_MHKN_AVAIL 1
-#define IBM_MHKM_AVAIL 2
- struct sysctl_oid *oid_bluetooth;
- struct sysctl_oid *oid_wlan;
+ device_t dev;
+ ACPI_HANDLE handle;
+
+ /* Embedded controller */
+ device_t ec_dev;
+ ACPI_HANDLE ec_handle;
+
+ /* CMOS */
+ ACPI_HANDLE cmos_handle;
+
+ /* Fan status */
+ ACPI_HANDLE fan_handle;
+ int fan_levels;
+
+ /* Keylight commands and states */
+ ACPI_HANDLE light_handle;
+ int light_cmd_on;
+ int light_cmd_off;
+ int light_val;
+ int light_get_supported;
+ int light_set_supported;
+ struct cdev *led_dev;
+
+ int wlan_bt_flags;
+ int thermal_updt_supported;
+
+ unsigned int events_availmask;
+ unsigned int events_initialmask;
+ int events_mask_supported;
+ int events_enable;
+
+ struct sysctl_ctx_list *sysctl_ctx;
+ struct sysctl_oid *sysctl_tree;
+};
+
+static struct {
+ char *name;
+ int method;
+ char *description;
+ int access;
+} acpi_ibm_sysctls[] = {
+ {
+ .name = "events",
+ .method = ACPI_IBM_METHOD_EVENTS,
+ .description = "ACPI events enable",
+ .access = CTLTYPE_INT | CTLFLAG_RW
+ },
+ {
+ .name = "eventmask",
+ .method = ACPI_IBM_METHOD_EVENTMASK,
+ .description = "ACPI eventmask",
+ .access = CTLTYPE_INT | CTLFLAG_RW
+ },
+ {
+ .name = "hotkey",
+ .method = ACPI_IBM_METHOD_HOTKEY,
+ .description = "Key Status",
+ .access = CTLTYPE_INT | CTLFLAG_RD
+ },
+ {
+ .name = "lcd_brightness",
+ .method = ACPI_IBM_METHOD_BRIGHTNESS,
+ .description = "LCD Brightness",
+ .access = CTLTYPE_INT | CTLFLAG_RW
+ },
+ {
+ .name = "volume",
+ .method = ACPI_IBM_METHOD_VOLUME,
+ .description = "Volume",
+ .access = CTLTYPE_INT | CTLFLAG_RW
+ },
+ {
+ .name = "mute",
+ .method = ACPI_IBM_METHOD_MUTE,
+ .description = "Mute",
+ .access = CTLTYPE_INT | CTLFLAG_RW
+ },
+ {
+ .name = "thinklight",
+ .method = ACPI_IBM_METHOD_THINKLIGHT,
+ .description = "Thinklight enable",
+ .access = CTLTYPE_INT | CTLFLAG_RW
+ },
+ {
+ .name = "bluetooth",
+ .method = ACPI_IBM_METHOD_BLUETOOTH,
+ .description = "Bluetooth enable",
+ .access = CTLTYPE_INT | CTLFLAG_RW
+ },
+ {
+ .name = "wlan",
+ .method = ACPI_IBM_METHOD_WLAN,
+ .description = "WLAN enable",
+ .access = CTLTYPE_INT | CTLFLAG_RD
+ },
+ {
+ .name = "fan_speed",
+ .method = ACPI_IBM_METHOD_FANSPEED,
+ .description = "Fan speed",
+ .access = CTLTYPE_INT | CTLFLAG_RD
+ },
+ {
+ .name = "fan",
+ .method = ACPI_IBM_METHOD_FANSTATUS,
+ .description = "Fan enable",
+ .access = CTLTYPE_INT | CTLFLAG_RD
+ },
+
+ { NULL, 0, NULL, 0 }
};
+ACPI_SERIAL_DECL(ibm, "ACPI IBM extras");
+
static int acpi_ibm_probe(device_t dev);
static int acpi_ibm_attach(device_t dev);
static int acpi_ibm_detach(device_t dev);
-static void
-acpi_ibm_notify_handler(ACPI_HANDLE h, UINT32 notify,
- void *context);
-static int sysctl_acpi_ibm_mask_handler(SYSCTL_HANDLER_ARGS);
-static int sysctl_acpi_ibm_enable_handler(SYSCTL_HANDLER_ARGS);
-static int sysctl_acpi_ibm_misckey_handler(SYSCTL_HANDLER_ARGS);
-static int sysctl_acpi_ibm_volume_handler(SYSCTL_HANDLER_ARGS);
-static int sysctl_acpi_ibm_mute_handler(SYSCTL_HANDLER_ARGS);
-static int sysctl_acpi_ibm_brightness_handler(SYSCTL_HANDLER_ARGS);
-static int sysctl_acpi_ibm_keylight_handler(SYSCTL_HANDLER_ARGS);
-static int sysctl_acpi_ibm_wireless_handler(SYSCTL_HANDLER_ARGS);
-static int acpi_ibm_enable_mask(device_t dev, int val);
+
+static int acpi_ibm_sysctl(SYSCTL_HANDLER_ARGS);
+static int acpi_ibm_sysctl_init(struct acpi_ibm_softc *sc, int method);
+static int acpi_ibm_sysctl_get(struct acpi_ibm_softc *sc, int method);
+static int acpi_ibm_sysctl_set(struct acpi_ibm_softc *sc, int method, int val);
+
+static int acpi_ibm_eventmask_set(struct acpi_ibm_softc *sc, int val);
+static int acpi_ibm_thermal_sysctl(SYSCTL_HANDLER_ARGS);
+static void acpi_ibm_notify(ACPI_HANDLE h, UINT32 notify, void *context);
static device_method_t acpi_ibm_methods[] = {
/* Device interface */
@@ -119,138 +269,116 @@ static devclass_t acpi_ibm_devclass;
DRIVER_MODULE(acpi_ibm, acpi, acpi_ibm_driver, acpi_ibm_devclass,
0, 0);
MODULE_DEPEND(acpi_ibm, acpi, 1, 1, 1);
-static char *ibm_id[] = {"IBM0068", NULL};
+static char *ibm_ids[] = {"IBM0068", NULL};
-static int
-acpi_ibm_probe(device_t dev)
+static void
+ibm_led(void *softc, int onoff)
{
- struct acpi_ibm_softc *sc;
- int ret = ENXIO;
-
- sc = device_get_softc(dev);
-
- if (ACPI_ID_PROBE(device_get_parent(dev), dev, ibm_id)) {
- device_set_desc(dev, "IBM ThinkPad Button");
- ret = 0;
- }
- return (ret);
+ ACPI_SERIAL_BEGIN(ibm);
+ acpi_ibm_sysctl_set((struct acpi_ibm_softc*)softc,
+ ACPI_IBM_METHOD_THINKLIGHT, onoff);
+ ACPI_SERIAL_END(ibm);
}
static int
-acpi_ibm_call_two_method(device_t dev, char *name, int val1, int val2)
+acpi_ibm_probe(device_t dev)
{
- ACPI_OBJECT arg [2];
- ACPI_OBJECT_LIST args = {.Count = 2,.Pointer = arg};
- arg[0].Type = ACPI_TYPE_INTEGER;
- arg[0].Integer.Value = val1;
- arg[1].Type = ACPI_TYPE_INTEGER;
- arg[1].Integer.Value = val2;
- return AcpiEvaluateObject(acpi_get_handle(dev), name, &args, NULL);
+ if (acpi_disabled("ibm") ||
+ ACPI_ID_PROBE(device_get_parent(dev), dev, ibm_ids) == NULL ||
+ device_get_unit(dev) != 0)
+ return (ENXIO);
+
+ device_set_desc(dev, "IBM ThinkPad ACPI Extras");
+
+ return (0);
}
static int
acpi_ibm_attach(device_t dev)
{
- struct acpi_ibm_softc *sc;
- ACPI_STATUS status;
- ACPI_HANDLE h;
- int dummy;
- struct sysctl_oid *oid;
+ struct acpi_ibm_softc *sc;
+ struct acpi_softc *acpi_sc;
+ devclass_t ec_devclass;
+
ACPI_FUNCTION_TRACE((char *)(uintptr_t) __func__);
sc = device_get_softc(dev);
- sc->device_flag = 0;
- if (ACPI_FAILURE
- (acpi_GetInteger(acpi_get_handle(dev), IBM_NAME_INTERFACE_VERSION, &sc->ibm_version))) {
- sc->ibm_version = 0;
+ sc->dev = dev;
+ sc->handle = acpi_get_handle(dev);
+
+ acpi_sc = acpi_device_get_parent_softc(dev);
+
+ /* Look for the first embedded controller */
+ if (!(ec_devclass = devclass_find ("acpi_ec"))) {
+ if (bootverbose)
+ device_printf(dev, "Couldn't find acpi_ec devclass\n");
+ return (EINVAL);
+ }
+ if (!(sc->ec_dev = devclass_get_device(ec_devclass, 0))) {
+ if (bootverbose)
+ device_printf(dev, "Couldn't find acpi_ec device\n");
+ return (EINVAL);
+ }
+ sc->ec_handle = acpi_get_handle(sc->ec_dev);
+
+ ACPI_SERIAL_BEGIN(ibm);
+
+ /* Get the sysctl tree */
+ sc->sysctl_ctx = device_get_sysctl_ctx(dev);
+ sc->sysctl_tree = device_get_sysctl_tree(dev);
+
+ /* Look for event mask and hook up the nodes */
+ sc->events_mask_supported = ACPI_SUCCESS(acpi_GetInteger(sc->handle,
+ IBM_NAME_EVENTS_MASK_GET, &sc->events_initialmask));
+
+ if (sc->events_mask_supported) {
+ SYSCTL_ADD_INT(sc->sysctl_ctx,
+ SYSCTL_CHILDREN(sc->sysctl_tree), OID_AUTO,
+ "initialmask", CTLFLAG_RD,
+ &sc->events_initialmask, 0, "Initial eventmask");
+
+ /* The availmask is the bitmask of supported events */
+ if (ACPI_FAILURE(acpi_GetInteger(sc->handle,
+ IBM_NAME_EVENTS_AVAILMASK, &sc->events_availmask)))
+ sc->events_availmask = 0xffffffff;
+
+ SYSCTL_ADD_INT(sc->sysctl_ctx,
+ SYSCTL_CHILDREN(sc->sysctl_tree), OID_AUTO,
+ "availmask", CTLFLAG_RD,
+ &sc->events_availmask, 0, "Mask of supported events");
+ }
+
+ /* Hook up proc nodes */
+ for (int i = 0; acpi_ibm_sysctls[i].name != NULL; i++) {
+ if (!acpi_ibm_sysctl_init(sc, acpi_ibm_sysctls[i].method))
+ continue;
+
+ SYSCTL_ADD_PROC(sc->sysctl_ctx,
+ SYSCTL_CHILDREN(sc->sysctl_tree), OID_AUTO,
+ acpi_ibm_sysctls[i].name, acpi_ibm_sysctls[i].access,
+ sc, i, acpi_ibm_sysctl, "I",
+ acpi_ibm_sysctls[i].description);
}
- device_printf(dev, "Version %x\n", sc->ibm_version);
- if (ACPI_FAILURE
- (acpi_GetInteger(acpi_get_handle(dev), IBM_NAME_AVAIL_MASK, &sc->ibm_availmask)))
- sc->ibm_availmask = 0xffffffff;
-
- if (ACPI_FAILURE
- (acpi_GetInteger(acpi_get_handle(dev), IBM_NAME_CURRENT_MASK, &sc->ibm_initialmask)))
- sc->ibm_initialmask = 0xffffffff;
- else
- sc->device_flag |= IBM_MHKN_AVAIL;
-
- if (ACPI_SUCCESS(status = AcpiGetHandle(acpi_get_handle(dev), IBM_NAME_MODIFY_MASK, &h)))
- sc->device_flag |= IBM_MHKM_AVAIL;
- else
- printf("%s\n", AcpiFormatException(status));
-
- device_printf(dev, "Available Mask %x\n", sc->ibm_availmask);
- device_printf(dev, "Initial Mask %x\n", sc->ibm_initialmask);
- /* Install Specific Handler */
- status = AcpiInstallNotifyHandler(acpi_get_handle(dev), ACPI_DEVICE_NOTIFY, acpi_ibm_notify_handler, dev);
- SYSCTL_ADD_PROC(device_get_sysctl_ctx(dev),
- SYSCTL_CHILDREN(device_get_sysctl_tree(dev)),
- OID_AUTO, "key_mask", CTLTYPE_INT | CTLFLAG_RW,
- dev, 0,
- sysctl_acpi_ibm_mask_handler, "I", "Hot key mask");
- SYSCTL_ADD_INT(device_get_sysctl_ctx(dev),
- SYSCTL_CHILDREN(device_get_sysctl_tree(dev)),
- OID_AUTO, "version", CTLFLAG_RD,
- &sc->ibm_version, 0, "Interface version");
- SYSCTL_ADD_INT(device_get_sysctl_ctx(dev),
- SYSCTL_CHILDREN(device_get_sysctl_tree(dev)),
- OID_AUTO, "avail_mask", CTLFLAG_RD,
- &sc->ibm_availmask, 0, "Available Key mask");
- if (ACPI_FAILURE(acpi_SetInteger(acpi_get_handle(dev), IBM_NAME_ENABLE, 1)))
- goto fail;
- sc->ibm_enable = 1;
- SYSCTL_ADD_PROC(device_get_sysctl_ctx(dev),
- SYSCTL_CHILDREN(device_get_sysctl_tree(dev)),
- OID_AUTO, "enable", CTLTYPE_INT | CTLFLAG_RW,
- dev, 0,
- sysctl_acpi_ibm_enable_handler, "I", "Hot key enable");
- SYSCTL_ADD_PROC(device_get_sysctl_ctx(dev),
- SYSCTL_CHILDREN(device_get_sysctl_tree(dev)),
- OID_AUTO, "misckey", CTLTYPE_INT | CTLFLAG_RD,
- dev, 0,
- sysctl_acpi_ibm_misckey_handler, "I", "Key Status: Poll me");
- SYSCTL_ADD_PROC(device_get_sysctl_ctx(dev),
- SYSCTL_CHILDREN(device_get_sysctl_tree(dev)),
- OID_AUTO, "brightness", CTLTYPE_INT | CTLFLAG_RD,
- dev, 0,
- sysctl_acpi_ibm_brightness_handler, "I", "Brightness");
-
- SYSCTL_ADD_PROC(device_get_sysctl_ctx(dev),
- SYSCTL_CHILDREN(device_get_sysctl_tree(dev)),
- OID_AUTO, "volume", CTLTYPE_INT | CTLFLAG_RD,
- dev, 0,
- sysctl_acpi_ibm_volume_handler, "I", "Volume");
-
- SYSCTL_ADD_PROC(device_get_sysctl_ctx(dev),
- SYSCTL_CHILDREN(device_get_sysctl_tree(dev)),
- OID_AUTO, "mute", CTLTYPE_INT | CTLFLAG_RD,
- dev, 0,
- sysctl_acpi_ibm_mute_handler, "I", "Muting");
-
-
- SYSCTL_ADD_PROC(device_get_sysctl_ctx(dev),
- SYSCTL_CHILDREN(device_get_sysctl_tree(dev)),
- OID_AUTO, "keylight", CTLTYPE_INT | CTLFLAG_RD,
- dev, 0,
- sysctl_acpi_ibm_keylight_handler, "I", "Key Light");
- if (ACPI_SUCCESS(acpi_GetInteger(acpi_get_handle(dev), IBM_NAME_GET_WIRELESS, &dummy))) {
- oid = SYSCTL_ADD_PROC(device_get_sysctl_ctx(dev),
- SYSCTL_CHILDREN(device_get_sysctl_tree(dev)),
- OID_AUTO, "bluetooth", CTLTYPE_INT | CTLFLAG_RW, dev, 0,
- sysctl_acpi_ibm_wireless_handler, "I", "Bluetooth Enable");
- sc->oid_bluetooth = oid;
- oid = SYSCTL_ADD_PROC(device_get_sysctl_ctx(dev),
- SYSCTL_CHILDREN(device_get_sysctl_tree(dev)),
- OID_AUTO, "wlan", CTLTYPE_INT | CTLFLAG_RW, dev, 0,
- sysctl_acpi_ibm_wireless_handler, "I", "WLAN Enable");
- sc->oid_wlan = oid;
+
+ /* Hook up thermal node */
+ if (acpi_ibm_sysctl_init(sc, ACPI_IBM_METHOD_THERMAL)) {
+ SYSCTL_ADD_PROC(sc->sysctl_ctx,
+ SYSCTL_CHILDREN(sc->sysctl_tree), OID_AUTO,
+ "thermal", CTLTYPE_STRING | CTLFLAG_RD,
+ sc, 0, acpi_ibm_thermal_sysctl, "I",
+ "Thermal zones");
}
- return_VALUE(0);
-fail:
- device_printf(dev, "FAILED\n");
- AcpiRemoveNotifyHandler(acpi_get_handle(dev), ACPI_DEVICE_NOTIFY, acpi_ibm_notify_handler);
- return_VALUE(EINVAL);
+
+ ACPI_SERIAL_END(ibm);
+
+ /* Handle notifies */
+ AcpiInstallNotifyHandler(sc->handle, ACPI_DEVICE_NOTIFY,
+ acpi_ibm_notify, dev);
+
+ /* Hook up light to led(4) */
+ sc->led_dev = led_create(ibm_led, sc, "thinklight");
+
+ return (0);
}
static int
@@ -259,214 +387,480 @@ acpi_ibm_detach(device_t dev)
ACPI_FUNCTION_TRACE((char *)(uintptr_t) __func__);
struct acpi_ibm_softc *sc = device_get_softc(dev);
- acpi_SetInteger(acpi_get_handle(dev), IBM_NAME_ENABLE, 0);
- acpi_ibm_enable_mask(dev, sc->ibm_initialmask);
- AcpiRemoveNotifyHandler(acpi_get_handle(dev), ACPI_DEVICE_NOTIFY, acpi_ibm_notify_handler);
- return_VALUE(0);
-}
-#if 0
-static int
-acpi_ibm_suspend(device_t dev)
-{
- struct acpi_ibm_softc *sc = device_get_softc(dev);
- return_VALUE(0);
-}
+ /* Disable events and restore eventmask */
+ ACPI_SERIAL_BEGIN(ibm);
+ acpi_ibm_sysctl_set(sc, ACPI_IBM_METHOD_EVENTS, 0);
+ acpi_ibm_sysctl_set(sc, ACPI_IBM_METHOD_EVENTMASK, sc->events_initialmask);
+ ACPI_SERIAL_END(ibm);
-static int
-acpi_ibm_resume(device_t dev)
-{
+ AcpiRemoveNotifyHandler(sc->handle, ACPI_DEVICE_NOTIFY, acpi_ibm_notify);
+
+ led_destroy(sc->led_dev);
return (0);
}
-#endif
-static void
-acpi_ibm_notify_handler(ACPI_HANDLE h, UINT32 notify,
- void *context)
+
+static int
+acpi_ibm_eventmask_set(struct acpi_ibm_softc *sc, int val)
{
- int mhkp , arg, type;
- device_t dev = context;
- struct acpi_ibm_softc *sc = device_get_softc(dev);
+ ACPI_OBJECT arg[2];
+ ACPI_OBJECT_LIST args;
+ ACPI_STATUS status;
- printf("IBM:NOTIFY:%x\n", notify);
- if (notify != 0x80) {
- printf("Unknown notify\n");
- }
- for (;;) {
+ ACPI_FUNCTION_TRACE((char *)(uintptr_t)__func__);
+ ACPI_SERIAL_ASSERT(ibm);
- acpi_GetInteger(acpi_get_handle(dev), IBM_NAME_GET_EVENT, &mhkp);
+ args.Count = 2;
+ args.Pointer = arg;
+ arg[0].Type = ACPI_TYPE_INTEGER;
+ arg[1].Type = ACPI_TYPE_INTEGER;
- if (mhkp == 0) {
- break;
- }
- printf("notify:%x\n", mhkp);
+ for (int i = 0; i < 32; ++i) {
+ arg[0].Integer.Value = i+1;
+ arg[1].Integer.Value = (((1 << i) & val) != 0);
+ status = AcpiEvaluateObject(sc->handle,
+ IBM_NAME_EVENTS_MASK_SET, &args, NULL);
- type = (mhkp >> 12) & 0xf;
- arg = mhkp & 0xfff;
- switch (type) {
- case 1:
- if (!(sc->ibm_availmask & (1 << (arg - 1)))) {
- printf("Unknown key %d\n", arg);
- break;
- }
- acpi_UserNotify("IBM", h, (arg & 0xff));
- break;
- default:
- break;
- }
+ if (ACPI_FAILURE(status))
+ return (status);
}
+
+ return (0);
}
static int
-acpi_ibm_enable_mask(device_t dev, int val)
+acpi_ibm_sysctl(SYSCTL_HANDLER_ARGS)
{
- int i;
- struct acpi_ibm_softc *sc = device_get_softc(dev);
-
- if (!(sc->device_flag | IBM_MHKM_AVAIL)) {
- return -1;
- }
- for (i = 0; i < 32; i++) {
- acpi_ibm_call_two_method(dev, IBM_NAME_MODIFY_MASK, i + 1, 1);
- if (!((1 << i) & val))
- acpi_ibm_call_two_method(dev, IBM_NAME_MODIFY_MASK, i + 1, 0);
- }
- return 0;
+ struct acpi_ibm_softc *sc;
+ int arg;
+ int error = 0;
+ int function;
+ int method;
+
+ ACPI_FUNCTION_TRACE((char *)(uintptr_t)__func__);
+
+ sc = (struct acpi_ibm_softc *)oidp->oid_arg1;
+ function = oidp->oid_arg2;
+ method = acpi_ibm_sysctls[function].method;
+
+ ACPI_SERIAL_BEGIN(ibm);
+ arg = acpi_ibm_sysctl_get(sc, method);
+ error = sysctl_handle_int(oidp, &arg, 0, req);
+
+ /* Sanity check */
+ if (error != 0 || req->newptr == NULL)
+ goto out;
+
+ /* Update */
+ error = acpi_ibm_sysctl_set(sc, method, arg);
+
+out:
+ ACPI_SERIAL_END(ibm);
+ return (error);
}
static int
-sysctl_acpi_ibm_mask_handler(SYSCTL_HANDLER_ARGS)
+acpi_ibm_sysctl_get(struct acpi_ibm_softc *sc, int method)
{
- device_t dev = arg1;
- int val = 0xffffffff;
- int error = 0;
-
- struct acpi_ibm_softc *sc = device_get_softc(dev);
+ ACPI_INTEGER val_ec;
+ int val = 0, key;
+
+ ACPI_FUNCTION_TRACE((char *)(uintptr_t)__func__);
+ ACPI_SERIAL_ASSERT(ibm);
+
+ switch (method) {
+ case ACPI_IBM_METHOD_EVENTS:
+ acpi_GetInteger(sc->handle, IBM_NAME_EVENTS_STATUS_GET, &val);
+ break;
+
+ case ACPI_IBM_METHOD_EVENTMASK:
+ if (sc->events_mask_supported)
+ acpi_GetInteger(sc->handle, IBM_NAME_EVENTS_MASK_GET, &val);
+ break;
+
+ case ACPI_IBM_METHOD_HOTKEY:
+ /*
+ * Construct the hotkey as a bitmask as illustrated below.
+ * Note that whenever a key was pressed, the respecting bit
+ * toggles and nothing else changes.
+ * +--+--+-+-+-+-+-+-+-+-+-+-+
+ * |11|10|9|8|7|6|5|4|3|2|1|0|
+ * +--+--+-+-+-+-+-+-+-+-+-+-+
+ * | | | | | | | | | | | |
+ * | | | | | | | | | | | +- Home Button
+ * | | | | | | | | | | +--- Search Button
+ * | | | | | | | | | +----- Mail Button
+ * | | | | | | | | +------- Thinkpad Button
+ * | | | | | | | +--------- Zoom (Fn + Space)
+ * | | | | | | +----------- WLAN Button
+ * | | | | | +------------- Video Button
+ * | | | | +--------------- Hibernate Button
+ * | | | +----------------- Thinklight Button
+ * | | +------------------- Screen expand (Fn + F8)
+ * | +--------------------- Brightness
+ * +------------------------ Volume/Mute
+ */
+ key = rtcin(IBM_RTC_HOTKEY1);
+ val = (IBM_RTC_MASK_HOME | IBM_RTC_MASK_SEARCH | IBM_RTC_MASK_MAIL | IBM_RTC_MASK_WLAN) & key;
+ key = rtcin(IBM_RTC_HOTKEY2);
+ val |= (IBM_RTC_MASK_THINKPAD | IBM_RTC_MASK_VIDEO | IBM_RTC_MASK_HIBERNATE) & key;
+ val |= (IBM_RTC_MASK_ZOOM & key) >> 1;
+ key = rtcin(IBM_RTC_THINKLIGHT);
+ val |= (IBM_RTC_MASK_THINKLIGHT & key) << 4;
+ key = rtcin(IBM_RTC_SCREENEXPAND);
+ val |= (IBM_RTC_MASK_THINKLIGHT & key) << 4;
+ key = rtcin(IBM_RTC_BRIGHTNESS);
+ val |= (IBM_RTC_MASK_BRIGHTNESS & key) << 5;
+ key = rtcin(IBM_RTC_VOLUME);
+ val |= (IBM_RTC_MASK_VOLUME & key) << 4;
+ break;
+
+ case ACPI_IBM_METHOD_BRIGHTNESS:
+ ACPI_EC_READ(sc->ec_dev, IBM_EC_BRIGHTNESS, &val_ec, 1);
+ val = val_ec & IBM_EC_MASK_BRI;
+ break;
+
+ case ACPI_IBM_METHOD_VOLUME:
+ ACPI_EC_READ(sc->ec_dev, IBM_EC_VOLUME, &val_ec, 1);
+ val = val_ec &IBM_EC_MASK_VOL;
+ break;
+
+ case ACPI_IBM_METHOD_MUTE:
+ ACPI_EC_READ(sc->ec_dev, IBM_EC_VOLUME, &val_ec, 1);
+ val = ((val_ec & IBM_EC_MASK_MUTE) == IBM_EC_MASK_MUTE);
+ break;
+
+ case ACPI_IBM_METHOD_THINKLIGHT:
+ if (sc->light_get_supported)
+ acpi_GetInteger(sc->ec_handle, IBM_NAME_KEYLIGHT, &val);
+ else
+ val = sc->light_val;
+ break;
+
+ case ACPI_IBM_METHOD_BLUETOOTH:
+ acpi_GetInteger(sc->handle, IBM_NAME_WLAN_BT_GET, &val);
+ sc->wlan_bt_flags = val;
+ val = ((val & IBM_NAME_MASK_BT) != 0);
+ break;
+
+ case ACPI_IBM_METHOD_WLAN:
+ acpi_GetInteger(sc->handle, IBM_NAME_WLAN_BT_GET, &val);
+ sc->wlan_bt_flags = val;
+ val = ((val & IBM_NAME_MASK_WLAN) != 0);
+ break;
+
+ case ACPI_IBM_METHOD_FANSPEED:
+ if (sc->fan_handle) {
+ if(ACPI_FAILURE(acpi_GetInteger(sc->fan_handle, NULL, &val)))
+ val = -1;
+ }
+ else {
+ ACPI_EC_READ(sc->ec_dev, IBM_EC_FANSPEED, &val_ec, 2);
+ val = val_ec;
+ }
+ break;
- if (sc->device_flag & IBM_MHKN_AVAIL)
- acpi_GetInteger(acpi_get_handle(dev), IBM_NAME_CURRENT_MASK, &val);
+ case ACPI_IBM_METHOD_FANSTATUS:
+ if (!sc->fan_handle) {
+ ACPI_EC_READ(sc->ec_dev, IBM_EC_FANSTATUS, &val_ec, 1);
+ val = (val_ec & IBM_EC_MASK_FANSTATUS) == IBM_EC_MASK_FANSTATUS;
+ }
+ else
+ val = -1;
+ break;
+ }
- error = sysctl_handle_int(oidp, &val, 0, req);
+ return (val);
+}
- if (error || !req->newptr)
- return error;
+static int
+acpi_ibm_sysctl_set(struct acpi_ibm_softc *sc, int method, int arg)
+{
+ int val, step;
+ ACPI_INTEGER val_ec;
+ ACPI_OBJECT Arg;
+ ACPI_OBJECT_LIST Args;
+ ACPI_STATUS status;
+
+ ACPI_FUNCTION_TRACE((char *)(uintptr_t)__func__);
+ ACPI_SERIAL_ASSERT(ibm);
+
+ switch (method) {
+ case ACPI_IBM_METHOD_EVENTS:
+ if (arg < 0 || arg > 1)
+ return (EINVAL);
+
+ status = acpi_SetInteger(sc->handle, IBM_NAME_EVENTS_STATUS_SET, arg);
+ if (ACPI_FAILURE(status))
+ return (status);
+ if (sc->events_mask_supported)
+ return acpi_ibm_eventmask_set(sc, sc->events_availmask);
+ break;
+
+ case ACPI_IBM_METHOD_EVENTMASK:
+ if (sc->events_mask_supported)
+ return acpi_ibm_eventmask_set(sc, arg);
+ break;
+
+ case ACPI_IBM_METHOD_BRIGHTNESS:
+ if (arg < 0 || arg > 7)
+ return (EINVAL);
+
+ if (sc->cmos_handle) {
+ /* Read the current brightness */
+ status = ACPI_EC_READ(sc->ec_dev, IBM_EC_BRIGHTNESS, &val_ec, 1);
+ if (ACPI_FAILURE(status))
+ return (status);
+ val = val_ec & IBM_EC_MASK_BRI;
+
+ Args.Count = 1;
+ Args.Pointer = &Arg;
+ Arg.Type = ACPI_TYPE_INTEGER;
+ Arg.Integer.Value = (arg > val) ? IBM_CMOS_BRIGHTNESS_UP : IBM_CMOS_BRIGHTNESS_DOWN;
+
+ step = (arg > val) ? 1 : -1;
+ for (int i = val; i != arg; i += step) {
+ status = AcpiEvaluateObject(sc->cmos_handle, NULL, &Args, NULL);
+ if (ACPI_FAILURE(status))
+ break;
+ }
+ }
+ return ACPI_EC_WRITE(sc->ec_dev, IBM_EC_BRIGHTNESS, arg, 1);
+ break;
+
+ case ACPI_IBM_METHOD_VOLUME:
+ if (arg < 0 || arg > 14)
+ return (EINVAL);
+
+ if (sc->cmos_handle) {
+ status = ACPI_EC_READ(sc->ec_dev, IBM_EC_VOLUME, &val_ec, 1);
+ if (ACPI_FAILURE(status))
+ return (status);
+ val = val_ec & IBM_EC_MASK_VOL;
+
+ Args.Count = 1;
+ Args.Pointer = &Arg;
+ Arg.Type = ACPI_TYPE_INTEGER;
+ Arg.Integer.Value = (arg > val) ? IBM_CMOS_VOLUME_UP : IBM_CMOS_VOLUME_DOWN;
+
+ step = (arg > val) ? 1 : -1;
+ for (int i = val; i != arg; i += step) {
+ status = AcpiEvaluateObject(sc->cmos_handle, NULL, &Args, NULL);
+ if (ACPI_FAILURE(status))
+ break;
+ }
+ }
+ return ACPI_EC_WRITE(sc->ec_dev, IBM_EC_VOLUME, arg + (val_ec & (~IBM_EC_MASK_VOL)), 1);
+ break;
+
+ case ACPI_IBM_METHOD_MUTE:
+ if (arg < 0 || arg > 1)
+ return (EINVAL);
+
+ if (sc->cmos_handle) {
+ status = ACPI_EC_READ(sc->ec_dev, IBM_EC_VOLUME, &val_ec, 1);
+ if (ACPI_FAILURE(status))
+ return (status);
+ val = val_ec & IBM_EC_MASK_VOL;
+
+ Args.Count = 1;
+ Args.Pointer = &Arg;
+ Arg.Type = ACPI_TYPE_INTEGER;
+ Arg.Integer.Value = IBM_CMOS_VOLUME_MUTE;
+
+ status = AcpiEvaluateObject(sc->cmos_handle, NULL, &Args, NULL);
+ if (ACPI_FAILURE(status))
+ break;
+ }
+ return ACPI_EC_WRITE(sc->ec_dev, IBM_EC_VOLUME, (arg==1) ? val_ec | IBM_EC_MASK_MUTE : val_ec & (~IBM_EC_MASK_MUTE), 1);
+ break;
+
+ case ACPI_IBM_METHOD_THINKLIGHT:
+ if (arg < 0 || arg > 1)
+ return (EINVAL);
+
+ if (sc->light_set_supported) {
+ Args.Count = 1;
+ Args.Pointer = &Arg;
+ Arg.Type = ACPI_TYPE_INTEGER;
+ Arg.Integer.Value = arg ? sc->light_cmd_on : sc->light_cmd_off;
+
+ status = AcpiEvaluateObject(sc->light_handle, NULL, &Args, NULL);
+ if (ACPI_SUCCESS(status))
+ sc->light_val = arg;
+ return (status);
+ }
+ break;
- val &= sc->ibm_availmask;
- val |= sc->ibm_initialmask;
+ case ACPI_IBM_METHOD_BLUETOOTH:
+ if (arg < 0 || arg > 1)
+ return (EINVAL);
- acpi_ibm_enable_mask(dev, val);
+ val = (arg == 1) ? sc->wlan_bt_flags | IBM_NAME_MASK_BT : sc->wlan_bt_flags & (~IBM_NAME_MASK_BT);
+ return acpi_SetInteger(sc->handle, IBM_NAME_WLAN_BT_SET, val);
+ break;
+ }
- return 0;
+ return (0);
}
-static int
-sysctl_acpi_ibm_misckey_handler(SYSCTL_HANDLER_ARGS)
+static int
+acpi_ibm_sysctl_init(struct acpi_ibm_softc *sc, int method)
{
- int val , error;
- val = rtcin(IBM_RTC_MISCKEY);
- error = sysctl_handle_int(oidp, &val, 0, req);
- if (error || !req->newptr)
- return error;
- return 0;
-}
+ int dummy;
+ ACPI_OBJECT_TYPE cmos_t;
+ ACPI_HANDLE ledb_handle;
+
+ switch (method) {
+ case ACPI_IBM_METHOD_EVENTS:
+ /* Events are disabled by default */
+ return (TRUE);
+
+ case ACPI_IBM_METHOD_EVENTMASK:
+ return (sc->events_mask_supported);
+
+ case ACPI_IBM_METHOD_HOTKEY:
+ case ACPI_IBM_METHOD_BRIGHTNESS:
+ case ACPI_IBM_METHOD_VOLUME:
+ case ACPI_IBM_METHOD_MUTE:
+ /* EC is required here, which was aready checked before */
+ return (TRUE);
+
+ case ACPI_IBM_METHOD_THINKLIGHT:
+ sc->cmos_handle = NULL;
+ sc->light_get_supported = ACPI_SUCCESS(acpi_GetInteger(sc->ec_handle, IBM_NAME_KEYLIGHT, &dummy));
+
+ if ((ACPI_SUCCESS(AcpiGetHandle(sc->handle, "\\UCMS", &sc->light_handle)) ||
+ ACPI_SUCCESS(AcpiGetHandle(sc->handle, "\\CMOS", &sc->light_handle)) ||
+ ACPI_SUCCESS(AcpiGetHandle(sc->handle, "\\CMS", &sc->light_handle))) &&
+ ACPI_SUCCESS(AcpiGetType(sc->light_handle, &cmos_t)) &&
+ cmos_t == ACPI_TYPE_METHOD) {
+ sc->light_cmd_on = 0x0c;
+ sc->light_cmd_off = 0x0d;
+ sc->cmos_handle = sc->light_handle;
+ }
+ else if (ACPI_SUCCESS(AcpiGetHandle(sc->handle, "\\LGHT", &sc->light_handle))) {
+ sc->light_cmd_on = 1;
+ sc->light_cmd_off = 0;
+ }
+ else
+ sc->light_handle = NULL;
+ sc->light_set_supported = (sc->light_handle &&
+ ACPI_FAILURE(AcpiGetHandle(sc->ec_handle, "LEDB", &ledb_handle)));
-static int
-sysctl_acpi_ibm_brightness_handler(SYSCTL_HANDLER_ARGS)
-{
- int val , error;
- val = rtcin(IBM_RTC_BRIGHTNESS);
- val &= IBM_RTC_MASK_BRI;
- error = sysctl_handle_int(oidp, &val, 0, req);
- if (error || !req->newptr)
- return error;
- return 0;
+ if (sc->light_get_supported || sc->light_set_supported) {
+ sc->light_val = 0;
+ return (TRUE);
+ }
+ else
+ return (FALSE);
+
+ case ACPI_IBM_METHOD_BLUETOOTH:
+ case ACPI_IBM_METHOD_WLAN:
+ if (ACPI_SUCCESS(acpi_GetInteger(sc->handle, IBM_NAME_WLAN_BT_GET, &dummy)))
+ return (TRUE);
+ return (FALSE);
+
+ case ACPI_IBM_METHOD_FANSPEED:
+ /*
+ * Some models report the fan speed in levels from 0-7
+ * Newer models report it contiguously
+ */
+ sc->fan_levels =
+ (ACPI_SUCCESS(AcpiGetHandle(sc->handle, "GFAN", &sc->fan_handle)) ||
+ ACPI_SUCCESS(AcpiGetHandle(sc->handle, "\\FSPD", &sc->fan_handle)));
+ return (TRUE);
+
+ case ACPI_IBM_METHOD_FANSTATUS:
+ /*
+ * Fan status is only supported on those models,
+ * which report fan RPM contiguously, not in levels
+ */
+ if (sc->fan_levels)
+ return (FALSE);
+ return (TRUE);
+
+ case ACPI_IBM_METHOD_THERMAL:
+ if (ACPI_SUCCESS(acpi_GetInteger(sc->ec_handle, IBM_NAME_THERMAL_GET, &dummy))) {
+ sc->thermal_updt_supported = ACPI_SUCCESS(acpi_GetInteger(sc->ec_handle, IBM_NAME_THERMAL_UPDT, &dummy));
+ return (TRUE);
+ }
+ return (FALSE);
+ }
+ return (FALSE);
}
-static int
-sysctl_acpi_ibm_mute_handler(SYSCTL_HANDLER_ARGS)
+static int
+acpi_ibm_thermal_sysctl(SYSCTL_HANDLER_ARGS)
{
- int val , error;
- val = rtcin(IBM_RTC_VOLUME);
- val = ((val & IBM_RTC_MASK_MUTE) == IBM_RTC_MASK_MUTE);
-
- error = sysctl_handle_int(oidp, &val, 0, req);
- if (error || !req->newptr)
- return error;
- return 0;
-}
+ struct acpi_ibm_softc *sc;
+ int error = 0;
+ char temp_cmd[] = "TMP0";
+ int temp[8];
+
+ ACPI_FUNCTION_TRACE((char *)(uintptr_t)__func__);
+
+ sc = (struct acpi_ibm_softc *)oidp->oid_arg1;
+
+ ACPI_SERIAL_BEGIN(ibm);
+
+ for (int i = 0; i < 8; ++i) {
+ temp_cmd[3] = '0' + i;
+
+ /*
+ * The TMPx methods seem to return +/- 128 or 0
+ * when the respecting sensor is not available
+ */
+ if (ACPI_FAILURE(acpi_GetInteger(sc->ec_handle, temp_cmd,
+ &temp[i])) || ABS(temp[i]) == 128 || temp[i] == 0)
+ temp[i] = -1;
+ else if (sc->thermal_updt_supported)
+ /* Temperature is reported in tenth of Kelvin */
+ temp[i] = (temp[i] - 2732 + 5) / 10;
+ }
-static int
-sysctl_acpi_ibm_keylight_handler(SYSCTL_HANDLER_ARGS)
-{
- int val , error;
- val = ((rtcin(IBM_RTC_KEYLIGHT) & IBM_RTC_MASK_KEYLIGHT)
- == IBM_RTC_MASK_KEYLIGHT);
-
- error = sysctl_handle_int(oidp, &val, 0, req);
- if (error || !req->newptr)
- return error;
- return 0;
-}
+ error = sysctl_handle_opaque(oidp, &temp, 8*sizeof(int), req);
-static int
-sysctl_acpi_ibm_volume_handler(SYSCTL_HANDLER_ARGS)
-{
- int val , error;
- val = rtcin(IBM_RTC_VOLUME);
- val &= IBM_RTC_MASK_VOL;
- error = sysctl_handle_int(oidp, &val, 0, req);
- if (error || !req->newptr)
- return error;
- return 0;
+ ACPI_SERIAL_END(ibm);
+ return (error);
}
-static int
-sysctl_acpi_ibm_enable_handler(SYSCTL_HANDLER_ARGS)
+static void
+acpi_ibm_notify(ACPI_HANDLE h, UINT32 notify, void *context)
{
- device_t dev = arg1;
+ int event, arg, type;
+ device_t dev = context;
struct acpi_ibm_softc *sc = device_get_softc(dev);
- int error = 0;
-
- error = sysctl_handle_int(oidp, &sc->ibm_enable, 0, req);
- if (error || !req->newptr)
- return error;
+ ACPI_FUNCTION_TRACE_U32((char *)(uintptr_t)__func__, notify);
- if (sc->ibm_enable)
- sc->ibm_enable = 1;
- else
- sc->ibm_enable = 0;
- acpi_SetInteger(acpi_get_handle(dev), IBM_NAME_ENABLE, sc->ibm_enable);
-
- return 0;
-}
+ printf("IBM:NOTIFY:%x\n", notify);
+ if (notify != 0x80)
+ printf("Unknown notify\n");
-static int
-sysctl_acpi_ibm_wireless_handler(SYSCTL_HANDLER_ARGS)
-{
- device_t dev = arg1;
- struct acpi_ibm_softc *sc = device_get_softc(dev);
- int error = 0, val, oldval, mask;
- if (sc->oid_bluetooth == oidp) {
- mask = 2;
- } else if (sc->oid_wlan == oidp) {
- mask = 4;
- } else {
- printf("WARNING: wrong handler invoked\n");
- return ENOENT;
- }
+ for (;;) {
+ acpi_GetInteger(acpi_get_handle(dev), IBM_NAME_EVENTS_GET, &event);
- acpi_GetInteger(acpi_get_handle(dev), IBM_NAME_GET_WIRELESS, &oldval);
- val = !((oldval & mask) == 0);
- error = sysctl_handle_int(oidp, &val, 0, req);
+ if (event == 0)
+ break;
- if (error || !req->newptr)
- return error;
- oldval &= (~mask);
- if (val)
- oldval |= mask;
- acpi_SetInteger(acpi_get_handle(dev), IBM_NAME_SET_WIRELESS, oldval);
- return 0;
+ printf("notify:%x\n", event);
+ type = (event >> 12) & 0xf;
+ arg = event & 0xfff;
+ switch (type) {
+ case 1:
+ if (!(sc->events_availmask & (1 << (arg - 1)))) {
+ printf("Unknown key %d\n", arg);
+ break;
+ }
+ /* Notify devd(8) */
+ acpi_UserNotify("IBM", h, (arg & 0xff));
+ break;
+ default:
+ break;
+ }
+ }
}
OpenPOWER on IntegriCloud