summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--share/man/man4/Makefile2
-rw-r--r--share/man/man4/acpi_asus.41
-rw-r--r--share/man/man4/acpi_asus_wmi.490
-rw-r--r--sys/conf/files1
-rw-r--r--sys/dev/acpi_support/acpi_asus_wmi.c651
-rw-r--r--sys/modules/acpi/Makefile2
-rw-r--r--sys/modules/acpi/acpi_asus_wmi/Makefile9
7 files changed, 755 insertions, 1 deletions
diff --git a/share/man/man4/Makefile b/share/man/man4/Makefile
index e5a2f4c..972200d 100644
--- a/share/man/man4/Makefile
+++ b/share/man/man4/Makefile
@@ -4,6 +4,7 @@
MAN= aac.4 \
acpi.4 \
${_acpi_asus.4} \
+ ${_acpi_asus_wmi.4} \
${_acpi_dock.4} \
${_acpi_fujitsu.4} \
${_acpi_hp.4} \
@@ -698,6 +699,7 @@ MLINKS+=zyd.4 if_zyd.4
.if ${MACHINE_CPUARCH} == "amd64" || ${MACHINE_CPUARCH} == "i386"
_acpi_asus.4= acpi_asus.4
+_acpi_asus_wmi.4= acpi_asus_wmi.4
_acpi_dock.4= acpi_dock.4
_acpi_fujitsu.4=acpi_fujitsu.4
_acpi_hp.4= acpi_hp.4
diff --git a/share/man/man4/acpi_asus.4 b/share/man/man4/acpi_asus.4
index f3b99da..1921adc 100644
--- a/share/man/man4/acpi_asus.4
+++ b/share/man/man4/acpi_asus.4
@@ -157,6 +157,7 @@ Defaults for these variables can be set in
which is parsed at boot-time.
.Sh SEE ALSO
.Xr acpi 4 ,
+.Xr acpi_asus_wmi 4 ,
.Xr acpi_video 4 ,
.Xr sysctl.conf 5 ,
.Xr sysctl 8
diff --git a/share/man/man4/acpi_asus_wmi.4 b/share/man/man4/acpi_asus_wmi.4
new file mode 100644
index 0000000..bbc565f
--- /dev/null
+++ b/share/man/man4/acpi_asus_wmi.4
@@ -0,0 +1,90 @@
+.\"
+.\" Copyright (c) 2012 Alexander Motin <mav@FreeBSD.org>
+.\" 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$
+.\"
+.Dd July 2, 2012
+.Dt ACPI_ASUS_WMI 4
+.Os
+.Sh NAME
+.Nm acpi_asus_wmi
+.Nd Asus Laptop WMI Extras
+.Sh SYNOPSIS
+To compile this driver into the kernel,
+place the following line in your
+kernel configuration file:
+.Bd -ragged -offset indent
+.Cd "device acpi_asus_wmi"
+.Ed
+.Pp
+Alternatively, to load the driver as a
+module at boot time, place the following line in
+.Xr loader.conf 5 :
+.Bd -literal -offset indent
+acpi_asus_wmi_load="YES"
+.Ed
+.Sh DESCRIPTION
+The
+.Nm
+driver provides support for the extra WMI-controlled gadgets, such as hotkeys
+and leds, found on Asus laptops.
+It allows one to use the
+.Xr sysctl 8
+interface to manipulate the brightness of the LCD panel and keyboard backlight,
+power on/off different internal components, such as WiFi, Bluetooth, camera,
+cardreader, etc, read some sensors.
+Hotkey events are passed to
+.Xr devd 8
+for easy handling in userspace with the default configuration in
+.Pa /etc/devd/asus.conf .
+Some hotkey events, such as keyboard backlight and touchpad control, are
+handled inside the driver.
+.Sh SYSCTL VARIABLES
+The following sysctls are currently implemented:
+.Bl -tag -width indent
+.It Va dev.acpi_asus_wmi.0.handle_keys
+Specifies whether driver should handle some harwdare keys, such as keyboard
+backlight, internally.
+.El
+.Pp
+Number of other variables under the same sysctl branch are model-specific.
+.Pp
+Defaults for these variables can be set in
+.Xr sysctl.conf 5 ,
+which is parsed at boot-time.
+.Sh SEE ALSO
+.Xr acpi 4 ,
+.Xr acpi_asus 4 ,
+.Xr acpi_video 4 ,
+.Xr sysctl.conf 5 ,
+.Xr devd 8 ,
+.Xr sysctl 8
+.Sh HISTORY
+The
+.Nm
+driver first appeared in
+.Fx 10.0 .
+.Sh AUTHORS
+.An Alexander Motib Aq mav@FreeBSD.org .
diff --git a/sys/conf/files b/sys/conf/files
index 9bc5f2c..c303e03 100644
--- a/sys/conf/files
+++ b/sys/conf/files
@@ -576,6 +576,7 @@ dev/aac/aac_linux.c optional aac compat_linux
dev/aac/aac_pci.c optional aac pci
dev/acpi_support/acpi_wmi.c optional acpi_wmi acpi
dev/acpi_support/acpi_asus.c optional acpi_asus acpi
+dev/acpi_support/acpi_asus_wmi.c optional acpi_asus_wmi acpi
dev/acpi_support/acpi_fujitsu.c optional acpi_fujitsu acpi
dev/acpi_support/acpi_hp.c optional acpi_hp acpi
dev/acpi_support/acpi_ibm.c optional acpi_ibm acpi
diff --git a/sys/dev/acpi_support/acpi_asus_wmi.c b/sys/dev/acpi_support/acpi_asus_wmi.c
new file mode 100644
index 0000000..9e2a498
--- /dev/null
+++ b/sys/dev/acpi_support/acpi_asus_wmi.c
@@ -0,0 +1,651 @@
+/*-
+ * Copyright (c) 2012 Alexander Motin <mav@FreeBSD.org>
+ * 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.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include "opt_acpi.h"
+#include <sys/param.h>
+#include <sys/conf.h>
+#include <sys/uio.h>
+#include <sys/proc.h>
+#include <sys/kernel.h>
+#include <sys/bus.h>
+#include <sys/sbuf.h>
+#include <sys/module.h>
+#include <sys/sysctl.h>
+
+#include <contrib/dev/acpica/include/acpi.h>
+#include <contrib/dev/acpica/include/accommon.h>
+#include <dev/acpica/acpivar.h>
+#include "acpi_wmi_if.h"
+
+#define _COMPONENT ACPI_OEM
+ACPI_MODULE_NAME("ASUS-WMI")
+
+#define ACPI_ASUS_WMI_MGMT_GUID "97845ED0-4E6D-11DE-8A39-0800200C9A66"
+#define ACPI_ASUS_WMI_EVENT_GUID "0B3CBB35-E3C2-45ED-91C2-4C5A6D195D1C"
+#define ACPI_EEEPC_WMI_EVENT_GUID "ABBC0F72-8EA1-11D1-00A0-C90629100000"
+
+/* WMI Methods */
+#define ASUS_WMI_METHODID_SPEC 0x43455053
+#define ASUS_WMI_METHODID_SFUN 0x4E554653
+#define ASUS_WMI_METHODID_DSTS 0x53544344
+#define ASUS_WMI_METHODID_DSTS2 0x53545344
+#define ASUS_WMI_METHODID_DEVS 0x53564544
+#define ASUS_WMI_METHODID_INIT 0x54494E49
+#define ASUS_WMI_METHODID_HKEY 0x59454B48
+
+#define ASUS_WMI_UNSUPPORTED_METHOD 0xFFFFFFFE
+
+/* Wireless */
+#define ASUS_WMI_DEVID_HW_SWITCH 0x00010001
+#define ASUS_WMI_DEVID_WIRELESS_LED 0x00010002
+#define ASUS_WMI_DEVID_CWAP 0x00010003
+#define ASUS_WMI_DEVID_WLAN 0x00010011
+#define ASUS_WMI_DEVID_BLUETOOTH 0x00010013
+#define ASUS_WMI_DEVID_GPS 0x00010015
+#define ASUS_WMI_DEVID_WIMAX 0x00010017
+#define ASUS_WMI_DEVID_WWAN3G 0x00010019
+#define ASUS_WMI_DEVID_UWB 0x00010021
+
+/* LEDs */
+#define ASUS_WMI_DEVID_LED1 0x00020011
+#define ASUS_WMI_DEVID_LED2 0x00020012
+#define ASUS_WMI_DEVID_LED3 0x00020013
+#define ASUS_WMI_DEVID_LED4 0x00020014
+#define ASUS_WMI_DEVID_LED5 0x00020015
+#define ASUS_WMI_DEVID_LED6 0x00020016
+
+/* Backlight and Brightness */
+#define ASUS_WMI_DEVID_BACKLIGHT 0x00050011
+#define ASUS_WMI_DEVID_BRIGHTNESS 0x00050012
+#define ASUS_WMI_DEVID_KBD_BACKLIGHT 0x00050021
+#define ASUS_WMI_DEVID_LIGHT_SENSOR 0x00050022
+
+/* Misc */
+#define ASUS_WMI_DEVID_CAMERA 0x00060013
+#define ASUS_WMI_DEVID_CARDREADER 0x00080013
+#define ASUS_WMI_DEVID_TOUCHPAD 0x00100011
+#define ASUS_WMI_DEVID_TOUCHPAD_LED 0x00100012
+#define ASUS_WMI_DEVID_THERMAL_CTRL 0x00110011
+#define ASUS_WMI_DEVID_FAN_CTRL 0x00110012
+#define ASUS_WMI_DEVID_PROCESSOR_STATE 0x00120012
+
+/* DSTS masks */
+#define ASUS_WMI_DSTS_STATUS_BIT 0x00000001
+#define ASUS_WMI_DSTS_UNKNOWN_BIT 0x00000002
+#define ASUS_WMI_DSTS_PRESENCE_BIT 0x00010000
+#define ASUS_WMI_DSTS_USER_BIT 0x00020000
+#define ASUS_WMI_DSTS_BIOS_BIT 0x00040000
+#define ASUS_WMI_DSTS_BRIGHTNESS_MASK 0x000000FF
+#define ASUS_WMI_DSTS_MAX_BRIGTH_MASK 0x0000FF00
+
+
+struct acpi_asus_wmi_softc {
+ device_t dev;
+ device_t wmi_dev;
+ const char *notify_guid;
+ struct sysctl_ctx_list *sysctl_ctx;
+ struct sysctl_oid *sysctl_tree;
+ int dsts_id;
+ int handle_keys;
+};
+
+static struct {
+ char *name;
+ int dev_id;
+ char *description;
+ int access;
+} acpi_asus_wmi_sysctls[] = {
+ {
+ .name = "hw_switch",
+ .dev_id = ASUS_WMI_DEVID_HW_SWITCH,
+ .description = "hw_switch",
+ .access = CTLTYPE_INT | CTLFLAG_RW
+ },
+ {
+ .name = "wireless_led",
+ .dev_id = ASUS_WMI_DEVID_WIRELESS_LED,
+ .description = "Wireless LED control",
+ .access = CTLTYPE_INT | CTLFLAG_RW
+ },
+ {
+ .name = "cwap",
+ .dev_id = ASUS_WMI_DEVID_CWAP,
+ .description = "Alt+F2 function",
+ .access = CTLTYPE_INT | CTLFLAG_RW
+ },
+ {
+ .name = "wlan",
+ .dev_id = ASUS_WMI_DEVID_WLAN,
+ .description = "WLAN power control",
+ .access = CTLTYPE_INT | CTLFLAG_RW
+ },
+ {
+ .name = "bluetooth",
+ .dev_id = ASUS_WMI_DEVID_BLUETOOTH,
+ .description = "Bluetooth power control",
+ .access = CTLTYPE_INT | CTLFLAG_RW
+ },
+ {
+ .name = "gps",
+ .dev_id = ASUS_WMI_DEVID_GPS,
+ .description = "GPS power control",
+ .access = CTLTYPE_INT | CTLFLAG_RW
+ },
+ {
+ .name = "wimax",
+ .dev_id = ASUS_WMI_DEVID_WIMAX,
+ .description = "WiMAX power control",
+ .access = CTLTYPE_INT | CTLFLAG_RW
+ },
+ {
+ .name = "wwan3g",
+ .dev_id = ASUS_WMI_DEVID_WWAN3G,
+ .description = "WWAN-3G power control",
+ .access = CTLTYPE_INT | CTLFLAG_RW
+ },
+ {
+ .name = "uwb",
+ .dev_id = ASUS_WMI_DEVID_UWB,
+ .description = "UWB power control",
+ .access = CTLTYPE_INT | CTLFLAG_RW
+ },
+ {
+ .name = "led1",
+ .dev_id = ASUS_WMI_DEVID_LED1,
+ .description = "LED1 control",
+ .access = CTLTYPE_INT | CTLFLAG_RW
+ },
+ {
+ .name = "led2",
+ .dev_id = ASUS_WMI_DEVID_LED2,
+ .description = "LED2 control",
+ .access = CTLTYPE_INT | CTLFLAG_RW
+ },
+ {
+ .name = "led3",
+ .dev_id = ASUS_WMI_DEVID_LED3,
+ .description = "LED3 control",
+ .access = CTLTYPE_INT | CTLFLAG_RW
+ },
+ {
+ .name = "led4",
+ .dev_id = ASUS_WMI_DEVID_LED4,
+ .description = "LED4 control",
+ .access = CTLTYPE_INT | CTLFLAG_RW
+ },
+ {
+ .name = "led5",
+ .dev_id = ASUS_WMI_DEVID_LED5,
+ .description = "LED5 control",
+ .access = CTLTYPE_INT | CTLFLAG_RW
+ },
+ {
+ .name = "led6",
+ .dev_id = ASUS_WMI_DEVID_LED6,
+ .description = "LED6 control",
+ .access = CTLTYPE_INT | CTLFLAG_RW
+ },
+ {
+ .name = "backlight",
+ .dev_id = ASUS_WMI_DEVID_BACKLIGHT,
+ .description = "LCD backlight on/off control",
+ .access = CTLTYPE_INT | CTLFLAG_RW
+ },
+ {
+ .name = "brightness",
+ .dev_id = ASUS_WMI_DEVID_BRIGHTNESS,
+ .description = "LCD backlight brightness control",
+ .access = CTLTYPE_INT | CTLFLAG_RW
+ },
+ {
+ .name = "kbd_backlight",
+ .dev_id = ASUS_WMI_DEVID_KBD_BACKLIGHT,
+ .description = "Keyboard backlight brightness control",
+ .access = CTLTYPE_INT | CTLFLAG_RW
+ },
+ {
+ .name = "light_sensor",
+ .dev_id = ASUS_WMI_DEVID_LIGHT_SENSOR,
+ .description = "Ambient light sensor",
+ .access = CTLTYPE_INT | CTLFLAG_RW
+ },
+ {
+ .name = "camera",
+ .dev_id = ASUS_WMI_DEVID_CAMERA,
+ .description = "Camera power control",
+ .access = CTLTYPE_INT | CTLFLAG_RW
+ },
+ {
+ .name = "cardreader",
+ .dev_id = ASUS_WMI_DEVID_CARDREADER,
+ .description = "Cardreader power control",
+ .access = CTLTYPE_INT | CTLFLAG_RW
+ },
+ {
+ .name = "touchpad",
+ .dev_id = ASUS_WMI_DEVID_TOUCHPAD,
+ .description = "Touchpad control",
+ .access = CTLTYPE_INT | CTLFLAG_RW
+ },
+ {
+ .name = "touchpad_led",
+ .dev_id = ASUS_WMI_DEVID_TOUCHPAD_LED,
+ .description = "Touchpad LED control",
+ .access = CTLTYPE_INT | CTLFLAG_RW
+ },
+ {
+ .name = "themperature",
+ .dev_id = ASUS_WMI_DEVID_THERMAL_CTRL,
+ .description = "Temperature (C)",
+ .access = CTLTYPE_INT | CTLFLAG_RD
+ },
+ {
+ .name = "fan_speed",
+ .dev_id = ASUS_WMI_DEVID_FAN_CTRL,
+ .description = "Fan speed (0-3)",
+ .access = CTLTYPE_INT | CTLFLAG_RD
+ },
+ {
+ .name = "processor_state",
+ .dev_id = ASUS_WMI_DEVID_PROCESSOR_STATE,
+ .description = "Processor state",
+ .access = CTLTYPE_INT | CTLFLAG_RW
+ },
+ { NULL, 0, NULL, 0 }
+};
+
+ACPI_SERIAL_DECL(asus_wmi, "ASUS WMI device");
+
+static void acpi_asus_wmi_identify(driver_t *driver, device_t parent);
+static int acpi_asus_wmi_probe(device_t dev);
+static int acpi_asus_wmi_attach(device_t dev);
+static int acpi_asus_wmi_detach(device_t dev);
+
+static int acpi_asus_wmi_sysctl(SYSCTL_HANDLER_ARGS);
+static int acpi_asus_wmi_sysctl_set(struct acpi_asus_wmi_softc *sc, int dev_id,
+ int arg, int oldarg);
+static int acpi_asus_wmi_sysctl_get(struct acpi_asus_wmi_softc *sc, int dev_id);
+static int acpi_asus_wmi_evaluate_method(device_t wmi_dev, int method,
+ UINT32 arg0, UINT32 arg1, UINT32 *retval);
+static int acpi_wpi_asus_get_devstate(struct acpi_asus_wmi_softc *sc,
+ UINT32 dev_id, UINT32 *retval);
+static int acpi_wpi_asus_set_devstate(struct acpi_asus_wmi_softc *sc,
+ UINT32 dev_id, UINT32 ctrl_param, UINT32 *retval);
+static void acpi_asus_wmi_notify(ACPI_HANDLE h, UINT32 notify, void *context);
+
+static device_method_t acpi_asus_wmi_methods[] = {
+ DEVMETHOD(device_identify, acpi_asus_wmi_identify),
+ DEVMETHOD(device_probe, acpi_asus_wmi_probe),
+ DEVMETHOD(device_attach, acpi_asus_wmi_attach),
+ DEVMETHOD(device_detach, acpi_asus_wmi_detach),
+ {0, 0}
+};
+
+static driver_t acpi_asus_wmi_driver = {
+ "acpi_asus_wmi",
+ acpi_asus_wmi_methods,
+ sizeof(struct acpi_asus_wmi_softc),
+};
+
+static devclass_t acpi_asus_wmi_devclass;
+
+DRIVER_MODULE(acpi_asus_wmi, acpi_wmi, acpi_asus_wmi_driver,
+ acpi_asus_wmi_devclass, 0, 0);
+MODULE_DEPEND(acpi_asus_wmi, acpi_wmi, 1, 1, 1);
+MODULE_DEPEND(acpi_asus_wmi, acpi, 1, 1, 1);
+
+static void
+acpi_asus_wmi_identify(driver_t *driver, device_t parent)
+{
+
+ /* Don't do anything if driver is disabled. */
+ if (acpi_disabled("asus_wmi"))
+ return;
+
+ /* Add only a single device instance. */
+ if (device_find_child(parent, "acpi_asus_wmi", -1) != NULL)
+ return;
+
+ /* Check management GUID to see whether system is compatible. */
+ if (!ACPI_WMI_PROVIDES_GUID_STRING(parent,
+ ACPI_ASUS_WMI_MGMT_GUID))
+ return;
+
+ if (BUS_ADD_CHILD(parent, 0, "acpi_asus_wmi", -1) == NULL)
+ device_printf(parent, "add acpi_asus_wmi child failed\n");
+}
+
+static int
+acpi_asus_wmi_probe(device_t dev)
+{
+
+ if (!ACPI_WMI_PROVIDES_GUID_STRING(device_get_parent(dev),
+ ACPI_ASUS_WMI_MGMT_GUID))
+ return (EINVAL);
+ device_set_desc(dev, "ASUS WMI device");
+ return (0);
+}
+
+static int
+acpi_asus_wmi_attach(device_t dev)
+{
+ struct acpi_asus_wmi_softc *sc;
+ UINT32 val;
+ int dev_id, i;
+
+ ACPI_FUNCTION_TRACE((char *)(uintptr_t) __func__);
+
+ sc = device_get_softc(dev);
+ sc->dev = dev;
+ sc->wmi_dev = device_get_parent(dev);
+ sc->handle_keys = 1;
+
+ /* Check management GUID. */
+ if (!ACPI_WMI_PROVIDES_GUID_STRING(sc->wmi_dev,
+ ACPI_ASUS_WMI_MGMT_GUID)) {
+ device_printf(dev,
+ "WMI device does not provide the ASUS management GUID\n");
+ return (EINVAL);
+ }
+
+ /* Find proper DSTS method. */
+ sc->dsts_id = ASUS_WMI_METHODID_DSTS;
+next:
+ for (i = 0; acpi_asus_wmi_sysctls[i].name != NULL; ++i) {
+ dev_id = acpi_asus_wmi_sysctls[i].dev_id;
+ if (acpi_wpi_asus_get_devstate(sc, dev_id, &val))
+ continue;
+ break;
+ }
+ if (acpi_asus_wmi_sysctls[i].name == NULL) {
+ if (sc->dsts_id == ASUS_WMI_METHODID_DSTS) {
+ sc->dsts_id = ASUS_WMI_METHODID_DSTS2;
+ goto next;
+ } else {
+ device_printf(dev, "Can not detect DSTS method ID\n");
+ return (EINVAL);
+ }
+ }
+
+ /* Find proper and attach to notufy GUID. */
+ if (ACPI_WMI_PROVIDES_GUID_STRING(sc->wmi_dev,
+ ACPI_ASUS_WMI_EVENT_GUID))
+ sc->notify_guid = ACPI_ASUS_WMI_EVENT_GUID;
+ else if (ACPI_WMI_PROVIDES_GUID_STRING(sc->wmi_dev,
+ ACPI_EEEPC_WMI_EVENT_GUID))
+ sc->notify_guid = ACPI_EEEPC_WMI_EVENT_GUID;
+ else
+ sc->notify_guid = NULL;
+ if (sc->notify_guid != NULL) {
+ if (ACPI_WMI_INSTALL_EVENT_HANDLER(sc->wmi_dev,
+ sc->notify_guid, acpi_asus_wmi_notify, dev))
+ sc->notify_guid = NULL;
+ }
+ if (sc->notify_guid == NULL)
+ device_printf(dev, "Could not install event handler!\n");
+
+ /* Initialize. */
+ if (!acpi_asus_wmi_evaluate_method(sc->wmi_dev,
+ ASUS_WMI_METHODID_INIT, 0, 0, &val) && bootverbose)
+ device_printf(dev, "Initialization: %#x\n", val);
+ if (!acpi_asus_wmi_evaluate_method(sc->wmi_dev,
+ ASUS_WMI_METHODID_SPEC, 0, 0x9, &val) && bootverbose)
+ device_printf(dev, "WMI BIOS version: %d.%d\n",
+ val >> 16, val & 0xFF);
+ if (!acpi_asus_wmi_evaluate_method(sc->wmi_dev,
+ ASUS_WMI_METHODID_SFUN, 0, 0, &val) && bootverbose)
+ device_printf(dev, "SFUN value: %#x\n", val);
+
+ ACPI_SERIAL_BEGIN(asus_wmi);
+
+ sc->sysctl_ctx = device_get_sysctl_ctx(dev);
+ sc->sysctl_tree = device_get_sysctl_tree(dev);
+ SYSCTL_ADD_INT(sc->sysctl_ctx,
+ SYSCTL_CHILDREN(sc->sysctl_tree), OID_AUTO,
+ "handle_keys", CTLFLAG_RW, &sc->handle_keys,
+ 0, "Handle some hardware keys inside the driver");
+ for (i = 0; acpi_asus_wmi_sysctls[i].name != NULL; ++i) {
+ dev_id = acpi_asus_wmi_sysctls[i].dev_id;
+ if (acpi_wpi_asus_get_devstate(sc, dev_id, &val))
+ continue;
+ switch (dev_id) {
+ case ASUS_WMI_DEVID_THERMAL_CTRL:
+ case ASUS_WMI_DEVID_PROCESSOR_STATE:
+ case ASUS_WMI_DEVID_FAN_CTRL:
+ case ASUS_WMI_DEVID_BRIGHTNESS:
+ if (val == 0)
+ continue;
+ break;
+ default:
+ if ((val & ASUS_WMI_DSTS_PRESENCE_BIT) == 0)
+ continue;
+ break;
+ }
+
+ SYSCTL_ADD_PROC(sc->sysctl_ctx,
+ SYSCTL_CHILDREN(sc->sysctl_tree), OID_AUTO,
+ acpi_asus_wmi_sysctls[i].name,
+ acpi_asus_wmi_sysctls[i].access,
+ sc, i, acpi_asus_wmi_sysctl, "I",
+ acpi_asus_wmi_sysctls[i].description);
+ }
+ ACPI_SERIAL_END(asus_wmi);
+
+ return (0);
+}
+
+static int
+acpi_asus_wmi_detach(device_t dev)
+{
+ struct acpi_asus_wmi_softc *sc = device_get_softc(dev);
+
+ ACPI_FUNCTION_TRACE((char *)(uintptr_t) __func__);
+
+ if (sc->notify_guid)
+ ACPI_WMI_REMOVE_EVENT_HANDLER(dev, sc->notify_guid);
+
+ return (0);
+}
+
+static int
+acpi_asus_wmi_sysctl(SYSCTL_HANDLER_ARGS)
+{
+ struct acpi_asus_wmi_softc *sc;
+ int arg;
+ int oldarg;
+ int error = 0;
+ int function;
+ int dev_id;
+
+ ACPI_FUNCTION_TRACE((char *)(uintptr_t)__func__);
+
+ sc = (struct acpi_asus_wmi_softc *)oidp->oid_arg1;
+ function = oidp->oid_arg2;
+ dev_id = acpi_asus_wmi_sysctls[function].dev_id;
+
+ ACPI_SERIAL_BEGIN(asus_wmi);
+ arg = acpi_asus_wmi_sysctl_get(sc, dev_id);
+ oldarg = arg;
+ error = sysctl_handle_int(oidp, &arg, 0, req);
+ if (!error && req->newptr != NULL)
+ error = acpi_asus_wmi_sysctl_set(sc, dev_id, arg, oldarg);
+ ACPI_SERIAL_END(asus_wmi);
+
+ return (error);
+}
+
+static int
+acpi_asus_wmi_sysctl_get(struct acpi_asus_wmi_softc *sc, int dev_id)
+{
+ UINT32 val = 0;
+
+ ACPI_FUNCTION_TRACE((char *)(uintptr_t)__func__);
+ ACPI_SERIAL_ASSERT(asus_wmi);
+
+ acpi_wpi_asus_get_devstate(sc, dev_id, &val);
+
+ switch(dev_id) {
+ case ASUS_WMI_DEVID_THERMAL_CTRL:
+ val = (val - 2732 + 5) / 10;
+ break;
+ case ASUS_WMI_DEVID_PROCESSOR_STATE:
+ case ASUS_WMI_DEVID_FAN_CTRL:
+ break;
+ case ASUS_WMI_DEVID_BRIGHTNESS:
+ val &= ASUS_WMI_DSTS_BRIGHTNESS_MASK;
+ break;
+ case ASUS_WMI_DEVID_KBD_BACKLIGHT:
+ val &= 0x7;
+ break;
+ default:
+ if (val & ASUS_WMI_DSTS_UNKNOWN_BIT)
+ val = -1;
+ else
+ val = !!(val & ASUS_WMI_DSTS_STATUS_BIT);
+ break;
+ }
+
+ return (val);
+}
+
+static int
+acpi_asus_wmi_sysctl_set(struct acpi_asus_wmi_softc *sc, int dev_id, int arg, int oldarg)
+{
+ ACPI_FUNCTION_TRACE((char *)(uintptr_t)__func__);
+ ACPI_SERIAL_ASSERT(asus_wmi);
+
+ switch(dev_id) {
+ case ASUS_WMI_DEVID_KBD_BACKLIGHT:
+ arg = min(0x7, arg);
+ if (arg != 0)
+ arg |= 0x80;
+ break;
+ }
+
+ acpi_wpi_asus_set_devstate(sc, dev_id, arg, NULL);
+
+ return (0);
+}
+
+static __inline void
+acpi_asus_wmi_free_buffer(ACPI_BUFFER* buf) {
+ if (buf && buf->Pointer) {
+ AcpiOsFree(buf->Pointer);
+ }
+}
+
+static void
+acpi_asus_wmi_notify(ACPI_HANDLE h, UINT32 notify, void *context)
+{
+ device_t dev = context;
+ ACPI_FUNCTION_TRACE_U32((char *)(uintptr_t)__func__, notify);
+ UINT32 val;
+ int code = 0;
+
+ struct acpi_asus_wmi_softc *sc = device_get_softc(dev);
+ ACPI_BUFFER response = { ACPI_ALLOCATE_BUFFER, NULL };
+ ACPI_OBJECT *obj;
+ ACPI_WMI_GET_EVENT_DATA(sc->wmi_dev, notify, &response);
+ obj = (ACPI_OBJECT*) response.Pointer;
+ if (obj && obj->Type == ACPI_TYPE_INTEGER) {
+ code = obj->Integer.Value;
+ acpi_UserNotify("ASUS", ACPI_ROOT_OBJECT,
+ code);
+ }
+ if (code && sc->handle_keys) {
+ /* Keyboard backlight control. */
+ if (code == 0xc4 || code == 0xc5) {
+ acpi_wpi_asus_get_devstate(sc,
+ ASUS_WMI_DEVID_KBD_BACKLIGHT, &val);
+ val &= 0x7;
+ if (code == 0xc4) {
+ if (val < 0x7)
+ val++;
+ } else if (val > 0)
+ val--;
+ if (val != 0)
+ val |= 0x80;
+ acpi_wpi_asus_set_devstate(sc,
+ ASUS_WMI_DEVID_KBD_BACKLIGHT, val, NULL);
+ }
+ /* Touchpad control. */
+ if (code == 0x6b) {
+ acpi_wpi_asus_get_devstate(sc,
+ ASUS_WMI_DEVID_TOUCHPAD, &val);
+ val = !(val & 1);
+ acpi_wpi_asus_set_devstate(sc,
+ ASUS_WMI_DEVID_TOUCHPAD, val, NULL);
+ }
+ }
+ acpi_asus_wmi_free_buffer(&response);
+}
+
+static int
+acpi_asus_wmi_evaluate_method(device_t wmi_dev, int method,
+ UINT32 arg0, UINT32 arg1, UINT32 *retval)
+{
+ UINT32 params[2] = { arg0, arg1 };
+ UINT32 result;
+ ACPI_OBJECT *obj;
+ ACPI_BUFFER in = { sizeof(params), &params };
+ ACPI_BUFFER out = { ACPI_ALLOCATE_BUFFER, NULL };
+
+ if (ACPI_FAILURE(ACPI_WMI_EVALUATE_CALL(wmi_dev,
+ ACPI_ASUS_WMI_MGMT_GUID, 1, method, &in, &out))) {
+ acpi_asus_wmi_free_buffer(&out);
+ return (-EINVAL);
+ }
+ obj = out.Pointer;
+ if (obj && obj->Type == ACPI_TYPE_INTEGER)
+ result = (UINT32) obj->Integer.Value;
+ else
+ result = 0;
+ acpi_asus_wmi_free_buffer(&out);
+ if (retval)
+ *retval = result;
+ return (result == ASUS_WMI_UNSUPPORTED_METHOD ? -ENODEV : 0);
+}
+
+static int
+acpi_wpi_asus_get_devstate(struct acpi_asus_wmi_softc *sc,
+ UINT32 dev_id, UINT32 *retval)
+{
+
+ return (acpi_asus_wmi_evaluate_method(sc->wmi_dev,
+ sc->dsts_id, dev_id, 0, retval));
+}
+
+static int
+acpi_wpi_asus_set_devstate(struct acpi_asus_wmi_softc *sc,
+ UINT32 dev_id, UINT32 ctrl_param, UINT32 *retval)
+{
+
+ return (acpi_asus_wmi_evaluate_method(sc->wmi_dev,
+ ASUS_WMI_METHODID_DEVS, dev_id, ctrl_param, retval));
+}
diff --git a/sys/modules/acpi/Makefile b/sys/modules/acpi/Makefile
index 9390064..04c6dfc 100644
--- a/sys/modules/acpi/Makefile
+++ b/sys/modules/acpi/Makefile
@@ -1,6 +1,6 @@
# $FreeBSD$
-SUBDIR= acpi_asus acpi_fujitsu acpi_hp acpi_ibm \
+SUBDIR= acpi_asus acpi_asus_wmi acpi_fujitsu acpi_hp acpi_ibm \
acpi_panasonic acpi_sony acpi_toshiba acpi_video \
acpi_dock acpi_wmi aibs
diff --git a/sys/modules/acpi/acpi_asus_wmi/Makefile b/sys/modules/acpi/acpi_asus_wmi/Makefile
new file mode 100644
index 0000000..a5ff32a
--- /dev/null
+++ b/sys/modules/acpi/acpi_asus_wmi/Makefile
@@ -0,0 +1,9 @@
+# $FreeBSD$
+
+.PATH: ${.CURDIR}/../../../dev/acpi_support
+
+KMOD= acpi_asus_wmi
+CFLAGS+=-I${.CURDIR}/../../../dev/acpi_support
+SRCS= acpi_asus_wmi.c opt_acpi.h acpi_if.h acpi_wmi_if.h device_if.h bus_if.h
+
+.include <bsd.kmod.mk>
OpenPOWER on IntegriCloud