Add acpi_asus_wmi(4) -- driver for random extras found on WMI-compatible

Asus laptops. It is alike to acpi_asus(4), but uses WMI interface instead
of separate ACPI device.

On Asus EeePC T101MT netbook it allows to handle hotkeys and on/off WLAN,
Bluetooth, LCD backlight, camera, cardreader and touchpad.

On Asus UX31A ultrabook it allows to handle hotkeys, on/off WLAN, Bluetooth,
Wireless LED, control keyboard backlight brightness, monitor temperature
and fan speed. LCD brightness control doesn't work now for unknown reason,
possibly requiring some video card initialization.

Sponsored by:	iXsystems, Inc.
This commit is contained in:
Alexander Motin 2012-07-02 08:31:29 +00:00
parent 35d393bf63
commit 461a98a279
7 changed files with 755 additions and 1 deletions

View File

@ -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

View File

@ -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

View File

@ -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 .

View File

@ -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

View File

@ -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));
}

View File

@ -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

View File

@ -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>