Skip site navigation (1)Skip section navigation (2)
Date:      Sun, 21 Jun 2009 13:20:36 +0200
From:      Michael <freebsdusb@bindone.de>
To:        freebsd-acpi@freebsd.org
Cc:        c.r.n.a@wanadoo.fr, "Paul B. Mahol" <onemda@gmail.com>
Subject:   Two new acpi modules, acpi_wmi and acpi_hp
Message-ID:  <4A3E1784.2050406@bindone.de>

next in thread | raw e-mail | index | archive | help
This is a multi-part message in MIME format.
--------------000106060507010904000207
Content-Type: text/plain; charset=ISO-8859-1
Content-Transfer-Encoding: 7bit

Hello,

I wrote two new acpi modules last year and finally found the time to fix
them, add some missing features and write man pages.

This is the first time I'm writing kernel code for FreeBSD, so please
excuse me if I failed to apply to all style conventions (I tried to
follow style(9) as closely as possible).

acpi_wmi is an ACPI to WMI mapping driver (this is used by HP and Acer
notebooks and potentially others), so this could also be used to
implement additional drivers on (see for more details on WMI and ACPI:
http://www.microsoft.com/whdc/system/pnppwr/wmi/wmi-acpi.mspx).
It provides /dev/wmistat, example output:
cat /dev/wmistat
GUID                                  INST EXPE METH STR EVENT OID
{5FB7F034-2C63-45E9-BE91-3D44E2C707E4}   1 NO   WMAA NO  NO    AA
{95F24279-4D7B-4334-9387-ACCDC67EF61C}   1 NO   NO   NO  0x80+ -
{2B814318-4BE8-4707-9D84-A190A859B5D0}   1 NO   NO   NO  0xA0  -
{05901221-D566-11D1-B2F0-00A0C9062910}   1 NO   NO   NO  NO    AB
{1F4C91EB-DC5C-460B-951D-C7CB9B4B8D5E}   1 NO   WMBA NO  NO    BA
{2D114B49-2DFB-4130-B8FE-4A3C09E75133}  57 NO   NO   NO  NO    BC
{988D08E3-68F4-4C35-AF3E-6A1B8106F83C}  20 NO   NO   NO  NO    BD
{14EA9746-CE1F-4098-A0E0-7045CB4DA745}   1 NO   NO   NO  NO    BE
{322F2028-0F84-4901-988E-015176049E2D}   2 NO   NO   NO  NO    BF
{8232DE3D-663D-4327-A8F4-E293ADB9BF05}   0 NO   NO   NO  NO    BG
{8F1F6436-9F42-42C8-BADC-0E9424F20C9A}   0 NO   NO   NO  NO    BH
{8F1F6435-9F42-42C8-BADC-0E9424F20C9A}   0 NO   NO   NO  NO    BI

acpi_hp is a driver that uses acpi_wmi to provide HP specific features.
These include:
- Activate/deactivate WLAN
- Activate/deactivate WWAN
- Activate/deactivate Bluetooth
- Auto activate/deactiavte based on hw radio status
- Devd notifications
- On air status for different
- Controls ambient light sensor
- Get docking status
- Read BIOS settings through /dev/hpcmi, example output:
Flash Media Reader                         Disable
USB Ports including Express Card slot      Enable
1394 Port                                  Enable
Cardbus Slot                               Disable
Express Card Slot                          Disable
F9, F10 and F12 Delay(Sec)                 0
USB Device Detection Delay (Sec)           0
Multiboot                                  Enable
Express Boot Popup Delay(Sec)              0
CD-ROM Boot                                Enable
Floppy Boot                                Disable
Internal Network Adapter Boot              Disable
Internal Network Adapter Boot Mode         PXE
Swap Fn/Ctrl Key                           Disable
USB Legacy Support                         Disable
Parallel Port Mode                         ECP
...

The man pages included in the patch (man acpi_hp / man acpi_wmi) give
you detailed information about all sysctls and devices.

The patch attached (acpi_wmi_and_acpi_hp.patch) has been tested against
7.2-RELEASE and everything compiles cleanly, although my tests have been
on 8-CURRENT (but the snapshot is older than 7.2), so I expect this to
work ok on 7.2. The patch might fail against CURRENT though, this is why
I also attached patches.tgz, which contains individual patches per file.
I only tested this on i386 and the patch only changes i386 specific
things (I have no idea if this could possibly work on amd64, especially
because all the other acpi_support modules seem to be i386 only). Also
note, that I could only test this on my own machine (HP Compaq 8510p),
which features WLAN/BT/WLAN, so I don't know if the readings will be
sane if your machine doesn't feature a WWAN chip. In theory this should
work for many different HP models.

Installation instructions (replace MYKERNEL with your kernel name):

mkdir /usr/src/sys/modules/acpi/acpi_wmi
mkdir /usr/src/sys/modules/acpi/acpi_hp
patch -d /usr/src < acpi_wmi_and_acpi_hp.patch
cd /usr/src/share/man/man4/man4.i386
make all && make install
cd /usr/src/sys/i386/conf
config MYKERNEL
cd ../compile/MYKERNEL
make cleandepend && make depend
make all
make install
reboot
.
.
.
kldload acpi_hp
cat /dev/wmistat
sysctl -a | grep acpi_hp.0
sysctl dev.acpi_hp.0.als = 0
cat /dev/hpcmi
sysctl dev.acpi_hp.0.cmi_detail=7
cat /dev/hpcmi

It would be nice to get some feedback on this and maybe someone else can
implement vendor specific ACPI modules for other WMI based laptops now.

cheers
Michael

--------------000106060507010904000207
Content-Type: text/plain;
 name="acpi_wmi_and_acpi_hp.patch"
Content-Transfer-Encoding: 7bit
Content-Disposition: inline;
 filename="acpi_wmi_and_acpi_hp.patch"

--- sys/i386/conf/NOTES~	2008-12-29 04:48:16.000000000 +0100
+++ sys/i386/conf/NOTES	2009-06-21 12:10:16.000000000 +0100
@@ -471,6 +471,9 @@
 options 	ACPI_DEBUG
 #!options 	ACPI_NO_SEMAPHORES
 
+# ACPI WMI Mapping driver
+device          acpi_wmi
+
 # ACPI Asus Desktop Extras. (voltage, temp, fan)
 device		acpi_aiboost
 
@@ -480,6 +483,9 @@
 # ACPI Fujitsu Extras (Buttons)
 device		acpi_fujitsu
 
+# ACPI extras driver for HP laptops
+device         acpi_hp
+
 # ACPI extras driver for IBM laptops
 device         acpi_ibm
 
--- sys/modules/acpi/Makefile~	2008-12-29 04:41:59.000000000 +0100
+++ sys/modules/acpi/Makefile	2009-06-21 12:10:59.000000000 +0100
@@ -4,7 +4,7 @@
 SUBDIR=		acpi
 .endif
 
-SUBDIR+=	acpi_aiboost acpi_asus acpi_fujitsu acpi_ibm		\
+SUBDIR+=	acpi_wmi acpi_aiboost acpi_asus acpi_fujitsu acpi_hp acpi_ibm		\
 		acpi_panasonic acpi_sony acpi_toshiba acpi_video	\
 		acpi_dock
 
--- share/man/man4/man4.i386/acpi_hp.4~	2009-06-21 12:09:58.000000000 +0200
+++ share/man/man4/man4.i386/acpi_hp.4	2009-06-21 12:10:21.229934511 +0200
@@ -0,0 +1,273 @@
+.\" Copyright (c) 2009 Michael Gmelin
+.\" 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 June 21, 2009
+.Dt ACPI_HP 4 i386
+.Os
+.Sh NAME
+.Nm acpi_hp
+.Nd "ACPI extras driver for HP laptops"
+.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_hp"
+.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_hp_load="YES"
+.Ed
+.Sh DESCRIPTION
+The
+.Nm
+driver provides support for ACPI-controlled features found on HP laptops
+that use a WMI enabled BIOS (e.g. HP Compaq 8510p and 6510p).
+.Pp
+The main purpose of this driver is to provide an interface,
+accessible via
+.Xr sysctl 8 ,
+.Xr devd 8 and
+.Xr devfs 8 ,
+through which applications can determine and change the status of
+various laptop components and BIOS settings.
+.Pp
+.Ss Xr devd 8 Ss Events
+Devd events received by
+.Xr devd 8
+provide the following information:
+.Pp
+.Bl -tag -width "subsystem" -offset indent -compact
+.It system
+.Qq Li ACPI
+.It subsystem
+.Qq Li HP
+.It type
+The source of the event in the ACPI namespace.
+The value depends on the model.
+.It notify
+Event code (see below).
+.El
+.Pp
+Event codes:
+.Pp
+.Bl -tag -width "0xc0" -offset indent -compact
+.It Li 0xc0
+WLAN on air status changed to 0 (not on air)
+.It Li 0xc1
+WLAN on air status changed to 1 (on air)
+.It Li 0xd0
+Bluetooth on air status changed to 0 (not on air)
+.It Li 0xd1
+Bluetooth on air status changed to 1 (on air)
+.It Li 0xe0
+WWAN on air status changed to 0 (not on air)
+.It Li 0xe1
+WWAN on air status changed to 1 (on air)
+.El
+.Ss Xr devfs 8 Ss Device
+You can read /dev/hpcmi to see your current BIOS settings. The detail level
+can be adjusted by setting the sysctl 
+.Va cmi_detail
+as described below.
+.Sh SYSCTL VARIABLES
+The following sysctls are currently implemented:
+.Ss WLAN:
+.Bl -tag -width indent
+.It Va dev.acpi_hp.0.wlan_enabled
+Toggle WLAN chip activity. 
+.It Va dev.acpi_hp.0.wlan_radio
+(read-only)
+WLAN radio status (controlled by hardware switch)
+.It Va dev.acpi_hp.0.wlan_on_air
+(read-only)
+WLAN on air (chip enabled, hardware switch enabled + enabled in BIOS)
+.It Va dev.acpi_hp.0.wlan_enabled_if_radio_on
+If set to 1, the WLAN chip will be enabled if the radio is turned on
+.It Va dev.acpi_hp.0.wlan_disable_if_radio_off
+If set to 1, the WLAN chip will be disabled if the radio is turned off
+.El
+.Ss Bluetooth:
+.Bl -tag -width indent
+.It Va dev.acpi_hp.0.bt_enabled
+Toggle Bluetooth chip activity. 
+.It Va dev.acpi_hp.0.bt_radio
+(read-only)
+Bluetooth radio status (controlled by hardware switch)
+.It Va dev.acpi_hp.0.bt_on_air
+(read-only)
+Bluetooth on air (chip enabled, hardware switch enabled + enabled in BIOS)
+.It Va dev.acpi_hp.0.bt_enabled_if_radio_on
+If set to 1, the Bluetooth chip will be enabled if the radio is turned on
+.It Va dev.acpi_hp.0.bt_disable_if_radio_off
+If set to 1, the Bluetooth chip will be disabled if the radio is turned off
+.El
+.Ss WWAN:
+.Bl -tag -width indent
+.It Va dev.acpi_hp.0.wwan_enabled
+Toggle WWAN chip activity. 
+.It Va dev.acpi_hp.0.wwan_radio
+(read-only)
+WWAN radio status (controlled by hardware switch)
+.It Va dev.acpi_hp.0.wwan_on_air
+(read-only)
+WWAN on air (chip enabled, hardware switch enabled + enabled in BIOS)
+.It Va dev.acpi_hp.0.wwan_enabled_if_radio_on
+If set to 1, the WWAN chip will be enabled if the radio is turned on
+.It Va dev.acpi_hp.0.wwan_disable_if_radio_off
+If set to 1, the WWAN chip will be disabled if the radio is turned off
+.El
+.Ss Misc:
+.Bl -tag -width indent
+.It Va dev.acpi_hp.0.als_enabled
+Toggle ambient light sensor (ALS)
+.It Va dev.acpi_hp.0.display
+(read-only)
+Display status (bitmask)
+.It Va dev.acpi_hp.0.hdd_temperature
+(read-only)
+HDD temperature
+.It Va dev.acpi_hp.0.is_docked
+(read-only)
+Docking station status (1 if docked)
+.It Va dev.acpi_hp.0.cmi_detail
+Bitmask to control detail level in /dev/hpcmi output (values can be ORed).
+.Bl -tag -width "0x01" -offset indent -compact
+.It Li 0x01
+Show path component of BIOS setting
+.It Li 0x02
+Show a list of valid options for the BIOS setting
+.It Li 0x04
+Show additional flags of BIOS setting (ReadOnly etc.)
+.El
+.El
+.Pp
+Defaults for these sysctls can be set in
+.Xr sysctl.conf 5 .
+.Sh FILES
+.Bl -tag -width ".Pa /dev/hpcmi"
+.It Pa /dev/hpcmi
+Interface to read BIOS settings
+.El
+.Sh EXAMPLES
+The following can be added to
+.Xr devd.conf 5
+in order disable the LAN interface when WLAN on air and reenable if it's
+not:
+.Bd -literal -offset indent
+notify 0 {
+	match "system"          "ACPI";
+	match "subsystem"       "HP";
+	match "notify"          "0xc0";
+	action                  "ifconfig em0 up";
+};
+
+notify 0 {
+	match "system"          "ACPI";
+	match "subsystem"       "HP";
+	match "notify"          "0xc1";
+	action                  "ifconfig em0 down";
+};
+.Ed
+.Pp
+Enable the ambient light sensor:
+.Bd -literal -offset indent
+sysctl dev.acpi_hp.0.als_enabled=1
+.Ed
+.Pp
+Enable Bluetooth:
+.Bd -literal -offset indent
+sysctl dev.acpi_hp.0.bt_enabled=1
+.Ed
+.Pp
+Get BIOS settings:
+.Bd -literal -offset indent
+cat /dev/hpcmi
+
+Serial Port                                Disable              
+Infrared Port                              Enable               
+Parallel Port                              Disable              
+Flash Media Reader                         Disable              
+USB Ports including Express Card slot      Enable               
+1394 Port                                  Enable               
+Cardbus Slot                               Disable              
+Express Card Slot                          Disable   
+(...)
+.Ed
+.Pp
+Set maximum detail level for /dev/hpcmi output:
+.Bd -literal -offset indent
+sysctl dev.acpi_hp.0.cmi_detail=7
+.Ed
+.Pp
+
+
+
+.Sh SEE ALSO
+.Xr acpi 4 ,
+.Xr acpi_wmi 4 ,
+.Xr sysctl.conf 5 ,
+.Xr devd 8 ,
+.Xr devfs 8 ,
+.Xr sysctl 8
+.Sh HISTORY
+The
+.Nm
+device driver first appeared in
+.Fx CURRENT .
+.Sh AUTHORS
+.An -nosplit
+The
+.Nm
+driver was written by
+.An Michael Gmelin Aq freebsd@grem.de
+.Pp
+It has been inspired by hp-wmi driver, which implements a subset of these   
+features (hotkeys) on Linux.
+.Pp
+.Bl -tag -width indent
+.It HP CMI whitepaper:
+http://h20331.www2.hp.com/Hpsub/downloads/cmi_whitepaper.pdf
+.It wmi-hp for Linux:
+http://www.kernel.org
+.It WMI and ACPI:
+http://www.microsoft.com/whdc/system/pnppwr/wmi/wmi-acpi.mspx
+.El
+.Pp
+This manual page was written by
+.An Michael Gmelin Aq freebsd@grem.de
+.Sh BUGS
+This driver is experimental and has only been tested on CURRENT i386 on an
+HP Compaq 8510p which featured all supported wireless devices (WWAN/BT/WLAN).
+Expect undefined results when operating on different hardware.
+.Pp
+Loading the driver is slow. Reading from /dev/hpcmi is even slower.
+.Pp
+Additional features like HP specific sensor readings or writing BIOS
+settings are not supported.
--- sys/dev/acpi_support/acpi_hp.c~	2009-06-21 12:09:58.000000000 +0200
+++ sys/dev/acpi_support/acpi_hp.c	2009-06-21 12:10:55.256712496 +0200
@@ -0,0 +1,1042 @@
+/*-
+ * Copyright (c) 2009 Michael Gmelin <freebsd@grem.de>
+ * 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$");
+
+/*
+ * Driver for extra ACPI-controlled features found on HP laptops
+ * that use a WMI enabled BIOS (e.g. HP Compaq 8510p and 6510p).
+ * Allows to control and read status of integrated hardware and read
+ * BIOS settings through CMI.
+ * Inspired by the hp-wmi driver, which implements a subset of these
+ * features (hotkeys) on Linux.
+ *
+ * HP CMI whitepaper: http://h20331.www2.hp.com/Hpsub/downloads/cmi_whitepaper.pdf
+ * wmi-hp for Linux: http://www.kernel.org
+ * WMI and ACPI: http://www.microsoft.com/whdc/system/pnppwr/wmi/wmi-acpi.mspx
+ */
+
+#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/acpi.h>
+#include <dev/acpica/acpivar.h>
+#include "acpi_wmi_if.h"
+
+#define _COMPONENT	ACPI_OEM
+ACPI_MODULE_NAME("HP")
+
+#define ACPI_HP_WMI_EVENT_GUID			"95F24279-4D7B-4334-9387-ACCDC67EF61C"
+#define ACPI_HP_WMI_BIOS_GUID			"5FB7F034-2C63-45E9-BE91-3D44E2C707E4"
+#define ACPI_HP_WMI_CMI_GUID			"2D114B49-2DFB-4130-B8FE-4A3C09E75133"
+
+#define ACPI_HP_WMI_DISPLAY_COMMAND		0x1
+#define ACPI_HP_WMI_HDDTEMP_COMMAND		0x2
+#define ACPI_HP_WMI_ALS_COMMAND			0x3
+#define ACPI_HP_WMI_DOCK_COMMAND		0x4
+#define ACPI_HP_WMI_WIRELESS_COMMAND		0x5
+
+#define ACPI_HP_METHOD_WLAN_ENABLED			1
+#define ACPI_HP_METHOD_WLAN_RADIO			2
+#define ACPI_HP_METHOD_WLAN_ON_AIR			3
+#define ACPI_HP_METHOD_WLAN_ENABLE_IF_RADIO_ON		4
+#define ACPI_HP_METHOD_WLAN_DISABLE_IF_RADIO_OFF	5
+#define ACPI_HP_METHOD_BLUETOOTH_ENABLED		6
+#define ACPI_HP_METHOD_BLUETOOTH_RADIO			7
+#define ACPI_HP_METHOD_BLUETOOTH_ON_AIR			8
+#define ACPI_HP_METHOD_BLUETOOTH_ENABLE_IF_RADIO_ON	9
+#define ACPI_HP_METHOD_BLUETOOTH_DISABLE_IF_RADIO_OFF	10
+#define ACPI_HP_METHOD_WWAN_ENABLED			11
+#define ACPI_HP_METHOD_WWAN_RADIO			12
+#define ACPI_HP_METHOD_WWAN_ON_AIR			13
+#define ACPI_HP_METHOD_WWAN_ENABLE_IF_RADIO_ON		14
+#define ACPI_HP_METHOD_WWAN_DISABLE_IF_RADIO_OFF	15
+#define ACPI_HP_METHOD_ALS				16
+#define ACPI_HP_METHOD_DISPLAY				17
+#define ACPI_HP_METHOD_HDDTEMP				18
+#define ACPI_HP_METHOD_DOCK				19
+#define ACPI_HP_METHOD_CMI_DETAIL			20
+
+#define HP_MASK_WWAN_ON_AIR			0x1000000
+#define HP_MASK_BLUETOOTH_ON_AIR		0x10000
+#define HP_MASK_WLAN_ON_AIR			0x100
+#define HP_MASK_WWAN_RADIO			0x8000000
+#define HP_MASK_BLUETOOTH_RADIO			0x80000
+#define HP_MASK_WLAN_RADIO			0x800
+#define HP_MASK_WWAN_ENABLED			0x2000000
+#define HP_MASK_BLUETOOTH_ENABLED		0x20000
+#define HP_MASK_WLAN_ENABLED			0x200
+
+#define ACPI_HP_CMI_DETAIL_PATHS		0x01
+#define ACPI_HP_CMI_DETAIL_ENUMS		0x02
+#define ACPI_HP_CMI_DETAIL_FLAGS		0x04
+
+struct acpi_hp_inst_seq_pair {
+	UINT32	sequence;	/* sequence number as suggested by cmi bios */
+	UINT8	instance;	/* object instance on guid */
+};
+
+struct acpi_hp_softc {
+	device_t	dev;
+	ACPI_HANDLE	handle;
+	device_t	wmi_dev;
+	int		has_notify;			/* notification GUID found */
+	int		has_cmi;			/* CMI GUID found */
+	int		cmi_detail;			/* CMI detail level (controlled by sysctl) */
+	int		wlan_enable_if_radio_on;	/* controlled by sysctl */
+	int		wlan_disable_if_radio_off;	/* controlled by sysctl */
+	int		bluetooth_enable_if_radio_on;	/* controlled by sysctl */
+	int		bluetooth_disable_if_radio_off;	/* controlled by sysctl */
+	int		wwan_enable_if_radio_on;	/* controlled by sysctl */
+	int		wwan_disable_if_radio_off;	/* controlled by sysctl */
+	int		was_wlan_on_air;		/* last known WLAN on air status */
+	int		was_bluetooth_on_air;		/* last known Bluetooth in air status */
+	int		was_wwan_on_air;		/* last known WWAN on air status */
+	struct sysctl_ctx_list	*sysctl_ctx;
+	struct sysctl_oid	*sysctl_tree;
+	struct cdev	*hpcmi_dev_t;			/* hpcmi device handle */
+	struct sbuf	hpcmi_sbuf;			/* /dev/hpcmi output sbuf */
+	pid_t		hpcmi_open_pid;			/* pid operating on /dev/hpcmi */
+	int		hpcmi_bufptr;			/* current pointer position in /dev/hpcmi output buffer */
+	int		cmi_order_size;			/* size of cmi_order list */
+	struct acpi_hp_inst_seq_pair cmi_order[128];	/* list of CMI instances ordered by BIOS suggested sequence */
+};
+
+static struct {
+	char	*name;
+	int	method;
+	char	*description;
+	int	access;
+} acpi_hp_sysctls[] = {
+	{
+		.name		= "wlan_enabled",
+		.method		= ACPI_HP_METHOD_WLAN_ENABLED,
+		.description	= "Enable/Disable WLAN (WiFi)",
+		.access		= CTLTYPE_INT | CTLFLAG_RW
+	},
+	{
+		.name		= "wlan_radio",
+		.method		= ACPI_HP_METHOD_WLAN_RADIO,
+		.description	= "WLAN radio status",
+		.access		= CTLTYPE_INT | CTLFLAG_RD
+	},
+	{
+		.name		= "wlan_on_air",
+		.method		= ACPI_HP_METHOD_WLAN_ON_AIR,
+		.description	= "WLAN radio ready to use (enabled and radio)",
+		.access		= CTLTYPE_INT | CTLFLAG_RD
+	},
+	{
+		.name		= "wlan_enable_if_radio_on",
+		.method		= ACPI_HP_METHOD_WLAN_ENABLE_IF_RADIO_ON,
+		.description	= "Enable WLAN if radio is turned on",
+		.access		= CTLTYPE_INT | CTLFLAG_RW
+	},
+	{
+		.name		= "wlan_disable_if_radio_off",
+		.method		= ACPI_HP_METHOD_WLAN_DISABLE_IF_RADIO_OFF,
+		.description	= "Disable WLAN if radio is turned off",
+		.access		= CTLTYPE_INT | CTLFLAG_RW
+	},
+	{
+		.name		= "bt_enabled",
+		.method		= ACPI_HP_METHOD_BLUETOOTH_ENABLED,
+		.description	= "Enable/Disable Bluetooth",
+		.access		= CTLTYPE_INT | CTLFLAG_RW
+	},
+	{
+		.name		= "bt_radio",
+		.method		= ACPI_HP_METHOD_BLUETOOTH_RADIO,
+		.description	= "Bluetooth radio status",
+		.access		= CTLTYPE_INT | CTLFLAG_RD
+	},
+	{
+		.name		= "bt_on_air",
+		.method		= ACPI_HP_METHOD_BLUETOOTH_ON_AIR,
+		.description	= "Bluetooth radio ready to use (enabled and radio)",
+		.access		= CTLTYPE_INT | CTLFLAG_RD
+	},
+	{
+		.name		= "bt_enable_if_radio_on",
+		.method		= ACPI_HP_METHOD_BLUETOOTH_ENABLE_IF_RADIO_ON,
+		.description	= "Enable bluetooth if radio is turned on",
+		.access		= CTLTYPE_INT | CTLFLAG_RW
+	},
+	{
+		.name		= "bt_disable_if_radio_off",
+		.method		= ACPI_HP_METHOD_BLUETOOTH_DISABLE_IF_RADIO_OFF,
+		.description	= "Disable bluetooth if radio is turned off",
+		.access		= CTLTYPE_INT | CTLFLAG_RW
+	},
+	{
+		.name		= "wwan_enabled",
+		.method		= ACPI_HP_METHOD_WWAN_ENABLED,
+		.description	= "Enable/Disable WWAN (UMTS)",
+		.access		= CTLTYPE_INT | CTLFLAG_RW
+	},
+	{
+		.name		= "wwan_radio",
+		.method		= ACPI_HP_METHOD_WWAN_RADIO,
+		.description	= "WWAN radio status",
+		.access		= CTLTYPE_INT | CTLFLAG_RD
+	},
+	{
+		.name		= "wwan_on_air",
+		.method		= ACPI_HP_METHOD_WWAN_ON_AIR,
+		.description	= "WWAN radio ready to use (enabled and radio)",
+		.access		= CTLTYPE_INT | CTLFLAG_RD
+	},
+	{
+		.name		= "wwan_enable_if_radio_on",
+		.method		= ACPI_HP_METHOD_WWAN_ENABLE_IF_RADIO_ON,
+		.description	= "Enable WWAN if radio is turned on",
+		.access		= CTLTYPE_INT | CTLFLAG_RW
+	},
+	{
+		.name		= "wwan_disable_if_radio_off",
+		.method		= ACPI_HP_METHOD_WWAN_DISABLE_IF_RADIO_OFF,
+		.description	= "Disable WWAN if radio is turned off",
+		.access		= CTLTYPE_INT | CTLFLAG_RW
+	},
+	{
+		.name		= "als_enabled",
+		.method		= ACPI_HP_METHOD_ALS,
+		.description	= "Enable/Disable ALS (Ambient light sensor)",
+		.access		= CTLTYPE_INT | CTLFLAG_RW
+	},
+	{
+		.name		= "display",
+		.method		= ACPI_HP_METHOD_DISPLAY,
+		.description	= "Display status",
+		.access		= CTLTYPE_INT | CTLFLAG_RD
+	},
+	{
+		.name		= "hdd_temperature",
+		.method		= ACPI_HP_METHOD_HDDTEMP,
+		.description	= "HDD temperature",
+		.access		= CTLTYPE_INT | CTLFLAG_RD
+	},
+	{
+		.name		= "is_docked",
+		.method		= ACPI_HP_METHOD_DOCK,
+		.description	= "Docking station status",
+		.access		= CTLTYPE_INT | CTLFLAG_RD
+	},
+	{
+		.name		= "cmi_detail",
+		.method		= ACPI_HP_METHOD_CMI_DETAIL,
+		.description	= "Details shown in CMI output (cat /dev/hpcmi)",
+		.access		= CTLTYPE_INT | CTLFLAG_RW
+	},
+
+	{ NULL, 0, NULL, 0 }
+};
+
+ACPI_SERIAL_DECL(hp, "HP ACPI-WMI Mapping");
+
+static int	acpi_hp_probe(device_t dev);
+static int	acpi_hp_attach(device_t dev);
+static int	acpi_hp_detach(device_t dev);
+
+static void	acpi_hp_evaluate_auto_on_off(struct acpi_hp_softc* sc);
+static int	acpi_hp_sysctl(SYSCTL_HANDLER_ARGS);
+static int	acpi_hp_sysctl_set(struct acpi_hp_softc *sc, int method, int arg, int oldarg);
+static int	acpi_hp_sysctl_get(struct acpi_hp_softc *sc, int method);
+static int	acpi_hp_exec_wmi_command(device_t wmi_dev, int command, int is_write, int val);
+static void	acpi_hp_notify(ACPI_HANDLE h, UINT32 notify, void *context);
+static int	acpi_hp_get_cmi_block(device_t wmi_dev, const char* guid, UINT8 instance, 
+		    char* outbuf, size_t outsize, UINT32* sequence, int detail);
+static void	acpi_hp_hex_decode(char* buffer);
+
+static d_open_t	acpi_hp_hpcmi_open;
+static d_close_t acpi_hp_hpcmi_close;
+static d_read_t	acpi_hp_hpcmi_read;
+
+/* handler /dev/hpcmi device */
+static struct cdevsw hpcmi_cdevsw = {
+	.d_version = D_VERSION,
+	.d_open = acpi_hp_hpcmi_open,
+	.d_close = acpi_hp_hpcmi_close,
+	.d_read = acpi_hp_hpcmi_read,
+	.d_name = "hpcmi",
+};
+
+static device_method_t acpi_hp_methods[] = {
+	DEVMETHOD(device_probe, acpi_hp_probe),
+	DEVMETHOD(device_attach, acpi_hp_attach),
+	DEVMETHOD(device_detach, acpi_hp_detach),
+	{0, 0}
+};
+
+static driver_t	acpi_hp_driver = {
+	"acpi_hp",
+	acpi_hp_methods,
+	sizeof(struct acpi_hp_softc),
+};
+
+static devclass_t acpi_hp_devclass;
+
+DRIVER_MODULE(acpi_hp, acpi, acpi_hp_driver, acpi_hp_devclass,
+		0, 0);
+MODULE_DEPEND(acpi_hp, acpi_wmi, 1, 1, 1);
+MODULE_DEPEND(acpi_hp, acpi, 1, 1, 1);
+
+static void	
+acpi_hp_evaluate_auto_on_off(struct acpi_hp_softc *sc)
+{
+	int wireless;
+	int new_wlan_status;
+	int new_bluetooth_status;
+	int new_wwan_status;
+
+	wireless = acpi_hp_exec_wmi_command(sc->wmi_dev, ACPI_HP_WMI_WIRELESS_COMMAND, 0, 0);
+	new_wlan_status = -1;
+	new_bluetooth_status = -1;
+	new_wwan_status = -1;
+
+	device_printf(sc->wmi_dev, "Wireless status is %x\n", wireless);
+	if (sc->wlan_disable_if_radio_off && !(wireless & HP_MASK_WLAN_RADIO) &&  (wireless & HP_MASK_WLAN_ENABLED)) {
+		acpi_hp_exec_wmi_command(sc->wmi_dev, ACPI_HP_WMI_WIRELESS_COMMAND, 1, 0x100);
+		new_wlan_status = 0;
+	}
+	else if (sc->wlan_enable_if_radio_on && (wireless & HP_MASK_WLAN_RADIO) &&  !(wireless & HP_MASK_WLAN_ENABLED)) {
+		acpi_hp_exec_wmi_command(sc->wmi_dev, ACPI_HP_WMI_WIRELESS_COMMAND, 1, 0x101);
+		new_wlan_status = 1;
+	}
+	if (sc->bluetooth_disable_if_radio_off && !(wireless & HP_MASK_BLUETOOTH_RADIO) &&  (wireless & HP_MASK_BLUETOOTH_ENABLED)) {
+		acpi_hp_exec_wmi_command(sc->wmi_dev, ACPI_HP_WMI_WIRELESS_COMMAND, 1, 0x200);
+		new_bluetooth_status = 0;
+	}
+	else if (sc->bluetooth_enable_if_radio_on && (wireless & HP_MASK_BLUETOOTH_RADIO) &&  !(wireless & HP_MASK_BLUETOOTH_ENABLED)) {
+		acpi_hp_exec_wmi_command(sc->wmi_dev, ACPI_HP_WMI_WIRELESS_COMMAND, 1, 0x202);
+		new_bluetooth_status = 1;
+	}
+	if (sc->wwan_disable_if_radio_off && !(wireless & HP_MASK_WWAN_RADIO) &&  (wireless & HP_MASK_WWAN_ENABLED)) {
+		acpi_hp_exec_wmi_command(sc->wmi_dev, ACPI_HP_WMI_WIRELESS_COMMAND, 1, 0x400);
+		new_wwan_status = 0;
+	}
+	else if (sc->wwan_enable_if_radio_on && (wireless & HP_MASK_WWAN_RADIO) &&  !(wireless & HP_MASK_WWAN_ENABLED)) {
+		acpi_hp_exec_wmi_command(sc->wmi_dev, ACPI_HP_WMI_WIRELESS_COMMAND, 1, 0x404);
+		new_wwan_status = 1;
+	}
+
+	if (new_wlan_status == -1) {
+		new_wlan_status = (wireless & HP_MASK_WLAN_ON_AIR);
+		if ((new_wlan_status?1:0) != sc->was_wlan_on_air) {
+			sc->was_wlan_on_air = sc->was_wlan_on_air?0:1;
+			device_printf(sc->wmi_dev, "WLAN on air changed to %i (new_wlan_status is %i)\n", sc->was_wlan_on_air, new_wlan_status);
+			acpi_UserNotify("HP", sc->handle, 0xc0+sc->was_wlan_on_air);
+		}
+	}
+	if (new_bluetooth_status == -1) {
+		new_bluetooth_status = (wireless & HP_MASK_BLUETOOTH_ON_AIR);
+		if ((new_bluetooth_status?1:0) != sc->was_bluetooth_on_air) {
+			sc->was_bluetooth_on_air = sc->was_bluetooth_on_air?0:1;
+			device_printf(sc->wmi_dev, "BLUETOOTH on air changed to %i (new_bluetooth_status is %i)\n", sc->was_bluetooth_on_air, new_bluetooth_status);
+			acpi_UserNotify("HP", sc->handle, 0xd0+sc->was_bluetooth_on_air);
+		}
+	}
+	if (new_wwan_status == -1) {
+		new_wwan_status = (wireless & HP_MASK_WWAN_ON_AIR);
+		if ((new_wwan_status?1:0) != sc->was_wwan_on_air) {
+			sc->was_wwan_on_air = sc->was_wwan_on_air?0:1;
+			device_printf(sc->wmi_dev, "WWAN on air changed to %i (new_wwan_status is %i)\n", sc->was_wwan_on_air, new_wwan_status);
+			acpi_UserNotify("HP", sc->handle, 0xe0+sc->was_wwan_on_air);
+		}
+	}
+}
+
+static int
+acpi_hp_probe(device_t dev)
+{
+	if (acpi_disabled("hp") || device_get_unit(dev) != 0)
+		return (ENXIO);
+	device_set_desc(dev, "HP ACPI-WMI Mapping");
+	return (0);
+}
+
+static int
+acpi_hp_attach(device_t dev)
+{
+	struct acpi_hp_softc	*sc;
+	struct acpi_softc	*acpi_sc;
+	devclass_t		wmi_devclass;
+	int arg;
+
+	ACPI_FUNCTION_TRACE((char *)(uintptr_t) __func__);
+
+	sc = device_get_softc(dev);
+	sc->dev = dev;
+	sc->handle = acpi_get_handle(dev);
+	sc->has_notify = 0;
+	sc->has_cmi = 0;
+	sc->bluetooth_enable_if_radio_on = 0;
+	sc->bluetooth_disable_if_radio_off = 0;
+	sc->wlan_enable_if_radio_on = 0;
+	sc->wlan_disable_if_radio_off = 0;
+	sc->wlan_enable_if_radio_on = 0;
+	sc->wlan_disable_if_radio_off = 0;
+	sc->was_wlan_on_air = 0;
+	sc->was_bluetooth_on_air = 0;
+	sc->was_wwan_on_air = 0;
+	sc->cmi_detail = 0;
+	sc->cmi_order_size = -1;
+	memset(sc->cmi_order, 0, sizeof(sc->cmi_order));
+	acpi_sc = acpi_device_get_parent_softc(dev);
+
+	if (!(wmi_devclass = devclass_find ("acpi_wmi"))) {
+		device_printf(dev, "Couldn't find acpi_wmi devclass\n");
+		return (EINVAL);
+	}
+	if (!(sc->wmi_dev = devclass_get_device(wmi_devclass, 0))) {
+		device_printf(dev, "Couldn't find acpi_wmi device\n");
+		return (EINVAL);
+	}
+	if (!ACPI_WMI_PROVIDES_GUID_STRING(sc->wmi_dev, ACPI_HP_WMI_BIOS_GUID)) {
+		device_printf(dev, "WMI device does not provide the HP BIOS GUID\n");
+		return (EINVAL);
+	}
+	if (ACPI_WMI_PROVIDES_GUID_STRING(sc->wmi_dev, ACPI_HP_WMI_EVENT_GUID)) {
+		device_printf(dev, "HP event GUID detected, installing event handler\n");
+		if (ACPI_WMI_INSTALL_EVENT_HANDLER(sc->wmi_dev, ACPI_HP_WMI_EVENT_GUID, acpi_hp_notify, dev)) {
+			device_printf(dev, "Could not install notification handler!\n");
+		}
+		else {
+			sc->has_notify = 1;
+		}
+	}
+	if (ACPI_WMI_PROVIDES_GUID_STRING(sc->wmi_dev, ACPI_HP_WMI_CMI_GUID)) {
+		device_printf(dev, "HP CMI GUID detected\n");
+		sc->has_cmi = 1;
+	}
+
+	if (sc->has_cmi) {
+		sc->hpcmi_dev_t = make_dev(&hpcmi_cdevsw, 0, UID_ROOT, GID_WHEEL, 0644, "hpcmi");
+		sc->hpcmi_dev_t->si_drv1 = sc;
+		sc->hpcmi_open_pid = 0;
+		sc->hpcmi_bufptr = -1;
+	}
+
+	ACPI_SERIAL_BEGIN(hp);
+
+	sc->sysctl_ctx = device_get_sysctl_ctx(dev);
+	sc->sysctl_tree = device_get_sysctl_tree(dev);
+	for (int i = 0; acpi_hp_sysctls[i].name != NULL; ++i) {
+		arg = 0;
+		if ((!sc->has_notify &&
+		    (acpi_hp_sysctls[i].method == ACPI_HP_METHOD_WLAN_ENABLE_IF_RADIO_ON ||
+		    acpi_hp_sysctls[i].method == ACPI_HP_METHOD_WLAN_DISABLE_IF_RADIO_OFF ||
+		    acpi_hp_sysctls[i].method == ACPI_HP_METHOD_BLUETOOTH_ENABLE_IF_RADIO_ON ||
+		    acpi_hp_sysctls[i].method == ACPI_HP_METHOD_BLUETOOTH_DISABLE_IF_RADIO_OFF ||
+		    acpi_hp_sysctls[i].method == ACPI_HP_METHOD_WWAN_ENABLE_IF_RADIO_ON ||
+		    acpi_hp_sysctls[i].method == ACPI_HP_METHOD_WWAN_DISABLE_IF_RADIO_OFF)) ||
+		    (arg = acpi_hp_sysctl_get(sc, acpi_hp_sysctls[i].method)) < 0) {
+			continue;
+		}
+		if (acpi_hp_sysctls[i].method == ACPI_HP_METHOD_WLAN_ON_AIR) {
+			sc->was_wlan_on_air = arg;
+		}
+		else if (acpi_hp_sysctls[i].method == ACPI_HP_METHOD_BLUETOOTH_ON_AIR) {
+			sc->was_bluetooth_on_air = arg;
+		}
+		else if (acpi_hp_sysctls[i].method == ACPI_HP_METHOD_WWAN_ON_AIR) {
+			sc->was_wwan_on_air = arg;
+		}
+
+		SYSCTL_ADD_PROC(sc->sysctl_ctx,
+		SYSCTL_CHILDREN(sc->sysctl_tree), OID_AUTO,
+			acpi_hp_sysctls[i].name, acpi_hp_sysctls[i].access,
+			sc, i, acpi_hp_sysctl, "I",
+			acpi_hp_sysctls[i].description);
+	}
+	ACPI_SERIAL_END(hp);
+
+	return (0);
+}
+
+static int
+acpi_hp_detach(device_t dev)
+{
+	int ret;
+	
+	ACPI_FUNCTION_TRACE((char *)(uintptr_t) __func__);
+	struct acpi_hp_softc *sc = device_get_softc(dev);
+	if (sc->has_cmi && sc->hpcmi_open_pid != 0) {
+		ret = EBUSY;
+	}
+	else {
+		if (sc->has_notify) {
+			ACPI_WMI_REMOVE_EVENT_HANDLER(dev, ACPI_HP_WMI_EVENT_GUID);
+		}
+		if (sc->hpcmi_bufptr != -1) {
+			sbuf_delete(&sc->hpcmi_sbuf);
+			sc->hpcmi_bufptr = -1;
+		}
+		sc->hpcmi_open_pid = 0;
+		destroy_dev(sc->hpcmi_dev_t);
+		ret = 0;
+	}
+	return (ret);
+}
+
+static int
+acpi_hp_sysctl(SYSCTL_HANDLER_ARGS)
+{
+	struct acpi_hp_softc *sc;
+	int	arg;
+	int oldarg;
+	int	error = 0;
+	int	function;
+	int	method;
+	
+	ACPI_FUNCTION_TRACE((char *)(uintptr_t)__func__);
+
+	sc = (struct acpi_hp_softc *)oidp->oid_arg1;
+	function = oidp->oid_arg2;
+	method = acpi_hp_sysctls[function].method;
+
+	ACPI_SERIAL_BEGIN(hp);
+	arg = acpi_hp_sysctl_get(sc, method);
+	oldarg = arg;
+	error = sysctl_handle_int(oidp, &arg, 0, req);
+	if (!error && req->newptr != NULL) {
+		error = acpi_hp_sysctl_set(sc, method, arg, oldarg);
+	}
+	ACPI_SERIAL_END(hp);
+
+	return (error);
+}
+
+static int
+acpi_hp_sysctl_get(struct acpi_hp_softc *sc, int method)
+{
+	int val = 0;
+
+	ACPI_FUNCTION_TRACE((char *)(uintptr_t)__func__);
+	ACPI_SERIAL_ASSERT(hp);
+
+	switch (method) {
+	case ACPI_HP_METHOD_WLAN_ENABLED:
+		val = acpi_hp_exec_wmi_command(sc->wmi_dev, ACPI_HP_WMI_WIRELESS_COMMAND, 0, 0);
+		val = ((val & HP_MASK_WLAN_ENABLED) != 0);
+		break;
+	case ACPI_HP_METHOD_WLAN_RADIO:
+		val = acpi_hp_exec_wmi_command(sc->wmi_dev, ACPI_HP_WMI_WIRELESS_COMMAND, 0, 0);
+		val = ((val & HP_MASK_WLAN_RADIO) != 0);
+		break;
+	case ACPI_HP_METHOD_WLAN_ON_AIR:
+		val = acpi_hp_exec_wmi_command(sc->wmi_dev, ACPI_HP_WMI_WIRELESS_COMMAND, 0, 0);
+		val = ((val & HP_MASK_WLAN_ON_AIR) != 0);
+		break;
+	case ACPI_HP_METHOD_WLAN_ENABLE_IF_RADIO_ON:
+		val = sc->wlan_enable_if_radio_on;
+		break;
+	case ACPI_HP_METHOD_WLAN_DISABLE_IF_RADIO_OFF:
+		val = sc->wlan_disable_if_radio_off;
+		break;
+	case ACPI_HP_METHOD_BLUETOOTH_ENABLED:
+		val = acpi_hp_exec_wmi_command(sc->wmi_dev, ACPI_HP_WMI_WIRELESS_COMMAND, 0, 0);
+		val = ((val & HP_MASK_BLUETOOTH_ENABLED) != 0);
+		break;
+	case ACPI_HP_METHOD_BLUETOOTH_RADIO:
+		val = acpi_hp_exec_wmi_command(sc->wmi_dev, ACPI_HP_WMI_WIRELESS_COMMAND, 0, 0);
+		val = ((val & HP_MASK_BLUETOOTH_RADIO) != 0);
+		break;
+	case ACPI_HP_METHOD_BLUETOOTH_ON_AIR:
+		val = acpi_hp_exec_wmi_command(sc->wmi_dev, ACPI_HP_WMI_WIRELESS_COMMAND, 0, 0);
+		val = ((val & HP_MASK_BLUETOOTH_ON_AIR) != 0);
+		break;
+	case ACPI_HP_METHOD_BLUETOOTH_ENABLE_IF_RADIO_ON:
+		val = sc->bluetooth_enable_if_radio_on;
+		break;
+	case ACPI_HP_METHOD_BLUETOOTH_DISABLE_IF_RADIO_OFF:
+		val = sc->bluetooth_disable_if_radio_off;
+		break;
+	case ACPI_HP_METHOD_WWAN_ENABLED:
+		val = acpi_hp_exec_wmi_command(sc->wmi_dev, ACPI_HP_WMI_WIRELESS_COMMAND, 0, 0);
+		val = ((val & HP_MASK_WWAN_ENABLED) != 0);
+		break;
+	case ACPI_HP_METHOD_WWAN_RADIO:
+		val = acpi_hp_exec_wmi_command(sc->wmi_dev, ACPI_HP_WMI_WIRELESS_COMMAND, 0, 0);
+		val = ((val & HP_MASK_WWAN_RADIO) != 0);
+		break;
+	case ACPI_HP_METHOD_WWAN_ON_AIR:
+		val = acpi_hp_exec_wmi_command(sc->wmi_dev, ACPI_HP_WMI_WIRELESS_COMMAND, 0, 0);
+		val = ((val & HP_MASK_WWAN_ON_AIR) != 0);
+		break;
+	case ACPI_HP_METHOD_WWAN_ENABLE_IF_RADIO_ON:
+		val = sc->wwan_enable_if_radio_on;
+		break;
+	case ACPI_HP_METHOD_WWAN_DISABLE_IF_RADIO_OFF:
+		val = sc->wwan_disable_if_radio_off;
+		break;
+	case ACPI_HP_METHOD_ALS:
+		val = acpi_hp_exec_wmi_command(sc->wmi_dev, ACPI_HP_WMI_ALS_COMMAND, 0, 0);
+		break;
+	case ACPI_HP_METHOD_DISPLAY:
+		val = acpi_hp_exec_wmi_command(sc->wmi_dev, ACPI_HP_WMI_DISPLAY_COMMAND, 0, 0);
+		break;
+	case ACPI_HP_METHOD_HDDTEMP:
+		val = acpi_hp_exec_wmi_command(sc->wmi_dev, ACPI_HP_WMI_HDDTEMP_COMMAND, 0, 0);
+		break;
+	case ACPI_HP_METHOD_DOCK:
+		val = acpi_hp_exec_wmi_command(sc->wmi_dev, ACPI_HP_WMI_DOCK_COMMAND, 0, 0);
+		break;
+	case ACPI_HP_METHOD_CMI_DETAIL:
+		val = sc->cmi_detail;
+		break;
+	}
+	return (val);
+}
+
+static int
+acpi_hp_sysctl_set(struct acpi_hp_softc *sc, int method, int arg, int oldarg)
+{
+	ACPI_FUNCTION_TRACE((char *)(uintptr_t)__func__);
+	ACPI_SERIAL_ASSERT(hp);
+
+	if (method != ACPI_HP_METHOD_CMI_DETAIL)
+		arg = arg?1:0;
+
+	if (arg != oldarg) {
+		switch (method) {
+		case ACPI_HP_METHOD_WLAN_ENABLED:
+			return (acpi_hp_exec_wmi_command(sc->wmi_dev, ACPI_HP_WMI_WIRELESS_COMMAND, 1, arg?0x101:0x100));
+		case ACPI_HP_METHOD_WLAN_ENABLE_IF_RADIO_ON:
+			sc->wlan_enable_if_radio_on = arg;
+			acpi_hp_evaluate_auto_on_off(sc);
+			break;
+		case ACPI_HP_METHOD_WLAN_DISABLE_IF_RADIO_OFF:
+			sc->wlan_disable_if_radio_off = arg;
+			acpi_hp_evaluate_auto_on_off(sc);
+			break;
+		case ACPI_HP_METHOD_BLUETOOTH_ENABLED:
+			return (acpi_hp_exec_wmi_command(sc->wmi_dev, ACPI_HP_WMI_WIRELESS_COMMAND, 1, arg?0x202:0x200));
+		case ACPI_HP_METHOD_BLUETOOTH_ENABLE_IF_RADIO_ON:
+			sc->bluetooth_enable_if_radio_on = arg;
+			acpi_hp_evaluate_auto_on_off(sc);
+			break;
+		case ACPI_HP_METHOD_BLUETOOTH_DISABLE_IF_RADIO_OFF:
+			sc->bluetooth_disable_if_radio_off = arg?1:0;
+			acpi_hp_evaluate_auto_on_off(sc);
+			break;
+		case ACPI_HP_METHOD_WWAN_ENABLED:
+			return (acpi_hp_exec_wmi_command(sc->wmi_dev, ACPI_HP_WMI_WIRELESS_COMMAND, 1, arg?0x404:0x400));
+		case ACPI_HP_METHOD_WWAN_ENABLE_IF_RADIO_ON:
+			sc->wwan_enable_if_radio_on = arg?1:0;
+			acpi_hp_evaluate_auto_on_off(sc);
+			break;
+		case ACPI_HP_METHOD_WWAN_DISABLE_IF_RADIO_OFF:
+			sc->wwan_disable_if_radio_off = arg?1:0;
+			acpi_hp_evaluate_auto_on_off(sc);
+			break;
+		case ACPI_HP_METHOD_ALS:
+			return (acpi_hp_exec_wmi_command(sc->wmi_dev, ACPI_HP_WMI_ALS_COMMAND, 1, arg?1:0));
+		case ACPI_HP_METHOD_CMI_DETAIL:
+			sc->cmi_detail = arg;
+			break;
+		}
+	}
+	return (0);
+}
+
+static __inline void acpi_hp_free_buffer(ACPI_BUFFER* buf) {
+	if (buf && buf->Pointer) {
+		AcpiOsFree(buf->Pointer);
+	}
+}
+
+static void
+acpi_hp_notify(ACPI_HANDLE h, UINT32 notify, void *context)
+{
+	device_t dev = context;
+	ACPI_FUNCTION_TRACE_U32((char *)(uintptr_t)__func__, notify);
+
+	struct acpi_hp_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_BUFFER && obj->Buffer.Length == 8) {
+		if (*((UINT8 *) obj->Buffer.Pointer) == 0x5) {
+			acpi_hp_evaluate_auto_on_off(sc);
+		}
+	}
+	acpi_hp_free_buffer(&response);
+}
+
+static int
+acpi_hp_exec_wmi_command(device_t wmi_dev, int command, int is_write, int val)
+{
+	UINT32 params[5] = {0x55434553, is_write?2:1, command, is_write?4:0, val};
+	UINT32* result;
+	ACPI_OBJECT *obj;
+	ACPI_BUFFER in = { sizeof(params), &params };
+	ACPI_BUFFER out = { ACPI_ALLOCATE_BUFFER, NULL };
+	int retval;
+	
+	if (ACPI_FAILURE(ACPI_WMI_EVALUATE_CALL(wmi_dev, ACPI_HP_WMI_BIOS_GUID, 0, 0x3, &in, &out))) {
+		acpi_hp_free_buffer(&out);
+		return (-EINVAL);
+	}
+	obj = out.Pointer;
+	if (!obj || obj->Type != ACPI_TYPE_BUFFER) {
+		acpi_hp_free_buffer(&out);
+		return (-EINVAL);
+	}
+	result = (UINT32*) obj->Buffer.Pointer;
+	retval = result[2];
+	if (result[1] > 0) {
+		retval = result[1];
+	}
+	acpi_hp_free_buffer(&out);
+	return (retval);
+}
+
+static __inline char* acpi_hp_get_string_from_object(ACPI_OBJECT* obj, char* dst, size_t size) {
+	int length;
+	dst[0] = 0;
+	if (obj->Type == ACPI_TYPE_STRING) {
+		length = obj->String.Length+1;
+		if (length > size) {
+			length = size - 1;
+		}
+		strlcpy(dst, obj->String.Pointer, length);
+		acpi_hp_hex_decode(dst);
+	}
+	return (dst);
+}
+
+
+/*
+ * Read BIOS Setting block in instance "instance".
+ * The block returned is ACPI_TYPE_PACKAGE which should contain the following elements:
+ * Index Meaning
+ * 0     Setting Name [string]
+ * 1     Value (comma separated, asterisk marks the current value) [string]
+ * 2     Path within the bios hierarchy [string]
+ * 3     IsReadOnly [int]
+ * 4     DisplayInUI [int]
+ * 5     RequiresPhysicalPresence [int]
+ * 6     Sequence for ordering within the bios settings (absolute) [int]
+ * 7     Length of prerequisites array [int]
+ * 8     Prerequisite1 [string]
+ * 9     Prerequisite2 [string]
+ * 10    Prerequisite3 [string]
+ * 11    Current value (in case of enum) [string] / Array length [int]
+ * 12    Enum length [int] / Array values
+ * 13ff  Enum value at index x [string]
+ */
+static int
+acpi_hp_get_cmi_block(device_t wmi_dev, const char* guid, UINT8 instance, char* outbuf, size_t outsize, UINT32* sequence, int detail)
+{
+	ACPI_OBJECT *obj;
+	ACPI_BUFFER out = { ACPI_ALLOCATE_BUFFER, NULL };
+	int i;
+	int outlen;
+	int size = 255;
+	int has_enums = 0;
+	char string_buffer[size];
+	int enumbase;
+
+	outlen = 0;
+	outbuf[0] = 0;	
+	if (ACPI_FAILURE(ACPI_WMI_GET_BLOCK(wmi_dev, guid, instance, &out))) {
+		acpi_hp_free_buffer(&out);
+		return (-EINVAL);
+	}
+	obj = out.Pointer;
+	if (!obj && obj->Type != ACPI_TYPE_PACKAGE) {
+		acpi_hp_free_buffer(&out);
+		return (-EINVAL);
+	}
+
+	/* check if this matches our expectations based on our limited knowledge */
+	if (obj->Package.Count >= 13 &&
+	    obj->Package.Elements[0].Type == ACPI_TYPE_STRING &&
+	    obj->Package.Elements[1].Type == ACPI_TYPE_STRING &&
+	    obj->Package.Elements[2].Type == ACPI_TYPE_STRING &&
+	    obj->Package.Elements[3].Type == ACPI_TYPE_INTEGER &&
+	    obj->Package.Elements[4].Type == ACPI_TYPE_INTEGER &&
+	    obj->Package.Elements[5].Type == ACPI_TYPE_INTEGER &&
+	    obj->Package.Elements[6].Type == ACPI_TYPE_INTEGER &&
+	    obj->Package.Elements[7].Type == ACPI_TYPE_INTEGER &&
+	    obj->Package.Elements[8].Type == ACPI_TYPE_STRING &&
+	    obj->Package.Elements[9].Type == ACPI_TYPE_STRING &&
+	    obj->Package.Elements[10].Type == ACPI_TYPE_STRING &&
+	    ((obj->Package.Elements[11].Type == ACPI_TYPE_STRING &&
+	    obj->Package.Elements[12].Type == ACPI_TYPE_INTEGER &&
+	    obj->Package.Count >= 13+obj->Package.Elements[12].Integer.Value) ||
+	    (obj->Package.Elements[11].Type == ACPI_TYPE_INTEGER &&
+	    obj->Package.Count >= 12+obj->Package.Elements[11].Integer.Value))
+	    ) {
+		enumbase = obj->Package.Elements[11].Type == ACPI_TYPE_STRING?12:11;
+		if (detail & ACPI_HP_CMI_DETAIL_PATHS) {
+			strlcat(outbuf, acpi_hp_get_string_from_object(&obj->Package.Elements[2], string_buffer, size), outsize);
+			outlen += 48;
+			while (strlen(outbuf) < outlen)
+				strlcat(outbuf, " ", outsize);
+		} 
+		strlcat(outbuf, acpi_hp_get_string_from_object(&obj->Package.Elements[0], string_buffer, size), outsize);
+		outlen += 43;
+		while (strlen(outbuf) < outlen)
+			strlcat(outbuf, " ", outsize);
+		if (enumbase == 12)
+			strlcat(outbuf, acpi_hp_get_string_from_object(&obj->Package.Elements[11], string_buffer, size), outsize);
+		outlen += 21;
+		while (strlen(outbuf) < outlen)
+			strlcat(outbuf, " ", outsize);
+		for (i = 0; i < strlen(outbuf); ++i)
+			if (outbuf[i] == '\\')
+				outbuf[i] = '/';
+		if (detail & ACPI_HP_CMI_DETAIL_ENUMS) {
+			for (i = enumbase+1; i < enumbase+1 + obj->Package.Elements[enumbase].Integer.Value; ++i) {
+				acpi_hp_get_string_from_object(&obj->Package.Elements[i], string_buffer, size);
+				if (strlen(string_buffer) > 1 || (strlen(string_buffer) == 1 && string_buffer[0] != ' ')) {
+					if (has_enums)
+						strlcat(outbuf, "/", outsize);
+					else
+						strlcat(outbuf, " (", outsize);
+					strlcat(outbuf, string_buffer, outsize);
+					has_enums = 1;
+				}
+			}
+		}
+		if (has_enums)
+			strlcat(outbuf, ")", outsize);
+		if (detail & ACPI_HP_CMI_DETAIL_FLAGS) {
+			strlcat(outbuf, obj->Package.Elements[3].Integer.Value?" [ReadOnly]":"", outsize);
+			strlcat(outbuf, obj->Package.Elements[4].Integer.Value?"":" [NOUI]", outsize);
+			strlcat(outbuf, obj->Package.Elements[5].Integer.Value?" [RPP]":"", outsize);
+		}
+		*sequence = (UINT32) obj->Package.Elements[6].Integer.Value;
+	}
+	acpi_hp_free_buffer(&out);
+	return (0);
+}
+
+
+
+/*
+ * Convert given two digit hex string (hexin) to an UINT8 referenced
+ * by byteout.
+ * Return != 0 if the was a problem (invalid input)
+ */
+static __inline int acpi_hp_hex_to_int(const UINT8 *hexin, UINT8 *byteout)
+{
+	unsigned int hi;
+	unsigned int lo;
+
+	hi = hexin[0];
+	lo = hexin[1];
+	if ('0' <= hi && hi <= '9')
+		hi -= '0';
+	else if ('A' <= hi && hi <= 'F')
+		hi -= ('A' - 10);
+	else if ('a' <= hi && hi <= 'f')
+		hi -= ('a' - 10);
+	else
+		return (1);
+	if ('0' <= lo && lo <= '9')
+		lo -= '0';
+	else if ('A' <= lo && lo <= 'F')
+		lo -= ('A' - 10);
+	else if ('a' <= lo && lo <= 'f')
+		lo -= ('a' - 10);
+	else
+		return (1);
+	*byteout = (hi << 4) + lo;
+	return (0);
+}
+
+
+static void
+acpi_hp_hex_decode(char* buffer)
+{
+	int i;
+	int length = strlen(buffer);
+	UINT8 *uin;
+	UINT8 uout;
+
+	if (((int)length/2)*2 == length || length < 10) return;
+
+	for (i = 0; i<length; ++i) {
+		if (!((i+1)%3)) {
+			if (buffer[i] != ' ')
+				return;
+		}
+		else 
+			if (!((buffer[i] >= '0' && buffer[i] <= '9') ||
+		    	    (buffer[i] >= 'A' && buffer[i] <= 'F')))
+				return;			
+	}
+
+	for (i = 0; i<length; i += 3) {
+		uin = &buffer[i];
+		uout = 0;
+		acpi_hp_hex_to_int(uin, &uout);
+		buffer[i/3] = (char) uout;
+	}
+	buffer[(length+1)/3] = 0;
+}
+
+
+/*
+ * open hpcmi device
+ */
+static int
+acpi_hp_hpcmi_open(struct cdev* dev, int flags, int mode, struct thread *td)
+{
+	struct acpi_hp_softc *sc;
+	int ret;
+
+	if (dev == NULL || dev->si_drv1 == NULL)
+		return (EBADF);
+	sc = dev->si_drv1;
+
+	ACPI_SERIAL_BEGIN(hp);
+	if (sc->hpcmi_open_pid != 0) {
+		ret = EBUSY;
+	}
+	else {
+		if (sbuf_new(&sc->hpcmi_sbuf, NULL, 4096, SBUF_AUTOEXTEND) == NULL) {
+			ret = ENXIO;
+		} else {
+			sc->hpcmi_open_pid = td->td_proc->p_pid;
+			sc->hpcmi_bufptr = 0;
+			ret = 0;
+		}
+	}
+	ACPI_SERIAL_END(hp);
+	return (ret);
+}
+
+/*
+ * close hpcmi device
+ */
+static int
+acpi_hp_hpcmi_close(struct cdev* dev, int flags, int mode, struct thread *td)
+{
+	struct acpi_hp_softc *sc;
+	int ret;
+
+	if (dev == NULL || dev->si_drv1 == NULL)
+		return (EBADF);
+	sc = dev->si_drv1;
+
+	ACPI_SERIAL_BEGIN(hp);
+	if (sc->hpcmi_open_pid == 0) {
+		ret = EBADF;
+	}
+	else {
+		if (sc->hpcmi_bufptr != -1) {
+			sbuf_delete(&sc->hpcmi_sbuf);
+			sc->hpcmi_bufptr = -1;
+		}
+		sc->hpcmi_open_pid = 0;
+		ret = 0;
+	}
+	ACPI_SERIAL_END(hp);
+	return (ret);
+}
+
+/*
+ * Read from hpcmi bios information
+ */
+static int
+acpi_hp_hpcmi_read(struct cdev *dev, struct uio *buf, int flag)
+{
+	struct acpi_hp_softc *sc;
+	int pos, i, l, ret;
+	UINT8 instance;
+	UINT32 sequence;
+	int linesize = 1025;
+	char line[linesize];
+
+	if (dev == NULL || dev->si_drv1 == NULL)
+		return (EBADF);
+	sc = dev->si_drv1;
+	
+	ACPI_SERIAL_BEGIN(hp);
+	if (sc->hpcmi_open_pid != buf->uio_td->td_proc->p_pid || sc->hpcmi_bufptr == -1) {
+		ret = EBADF;
+	}
+	else {
+		if (!sbuf_done(&sc->hpcmi_sbuf)) {
+			if (sc->cmi_order_size < 0) {
+				sc->cmi_order_size = 0;
+				for (instance = 0; instance < 128; ++instance) {
+					if (acpi_hp_get_cmi_block(sc->wmi_dev, ACPI_HP_WMI_CMI_GUID, instance, line, linesize, &sequence, sc->cmi_detail)) {
+						instance = 128;
+					}
+					else {
+						pos = sc->cmi_order_size;
+						for (i=0; i<sc->cmi_order_size && i<127; ++i) {
+							if (sc->cmi_order[i].sequence > sequence) {
+								pos = i;
+								break; 							
+							}
+						}
+						for (i=sc->cmi_order_size; i>pos; --i) {
+							sc->cmi_order[i].sequence = sc->cmi_order[i-1].sequence;
+							sc->cmi_order[i].instance = sc->cmi_order[i-1].instance;
+						}
+						sc->cmi_order[pos].sequence = sequence;
+						sc->cmi_order[pos].instance = instance;
+						sc->cmi_order_size++;
+					}
+				}
+			}
+			for (i=0; i<sc->cmi_order_size; ++i) {
+				if (!acpi_hp_get_cmi_block(sc->wmi_dev, ACPI_HP_WMI_CMI_GUID, sc->cmi_order[i].instance, line, linesize, &sequence, sc->cmi_detail)) {
+					sbuf_printf(&sc->hpcmi_sbuf, "%s\n", line);
+				}
+			}
+			sbuf_finish(&sc->hpcmi_sbuf);
+		}
+		if (sbuf_len(&sc->hpcmi_sbuf) <= 0) {
+			sbuf_delete(&sc->hpcmi_sbuf);
+			sc->hpcmi_bufptr = -1;
+			sc->hpcmi_open_pid = 0;
+			ret = ENOMEM;
+		} else {
+			l = min(buf->uio_resid, sbuf_len(&sc->hpcmi_sbuf) - sc->hpcmi_bufptr);
+			ret = (l > 0)?uiomove(sbuf_data(&sc->hpcmi_sbuf) + sc->hpcmi_bufptr, l, buf) : 0;
+			sc->hpcmi_bufptr += l;
+		}
+	}
+	ACPI_SERIAL_END(hp);
+	return (ret);
+}
--- share/man/man4/man4.i386/acpi_wmi.4~	2009-06-21 12:09:58.000000000 +0200
+++ share/man/man4/man4.i386/acpi_wmi.4	2009-06-21 12:10:57.178932778 +0200
@@ -0,0 +1,97 @@
+.\" Copyright (c) 2009 Michael Gmelin
+.\" 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 June 21, 2009
+.Dt ACPI_WMI 4 i386
+.Os
+.Sh NAME
+.Nm acpi_wmi
+.Nd "ACPI to WMI mapping driver"
+.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_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_wmi_load="YES"
+.Ed
+.Sh DESCRIPTION
+The
+.Nm
+driver provides an interface for vendor specific WMI implementations 
+(e.g. HP and Acer laptops). It creates /dev/wmistat, which can be read to get
+information about GUIDs found in the system.
+.Sh FILES
+.Bl -tag -width /dev/wmistat -compact
+.It Pa /dev/wmistat
+WMI status device.
+.El
+.Sh EXAMPLES
+.Bd Literal
+root# cat /dev/wmistat
+
+GUID                                  INST EXPE METH STR EVENT OID
+{5FB7F034-2C63-45E9-BE91-3D44E2C707E4}   1 NO   WMAA NO  NO    AA
+{95F24279-4D7B-4334-9387-ACCDC67EF61C}   1 NO   NO   NO  0x80+ -
+{2B814318-4BE8-4707-9D84-A190A859B5D0}   1 NO   NO   NO  0xA0  -
+{05901221-D566-11D1-B2F0-00A0C9062910}   1 NO   NO   NO  NO    AB
+{1F4C91EB-DC5C-460B-951D-C7CB9B4B8D5E}   1 NO   WMBA NO  NO    BA
+{2D114B49-2DFB-4130-B8FE-4A3C09E75133}  57 NO   NO   NO  NO    BC
+{988D08E3-68F4-4C35-AF3E-6A1B8106F83C}  20 NO   NO   NO  NO    BD
+{14EA9746-CE1F-4098-A0E0-7045CB4DA745}   1 NO   NO   NO  NO    BE
+{322F2028-0F84-4901-988E-015176049E2D}   2 NO   NO   NO  NO    BF
+{8232DE3D-663D-4327-A8F4-E293ADB9BF05}   0 NO   NO   NO  NO    BG
+{8F1F6436-9F42-42C8-BADC-0E9424F20C9A}   0 NO   NO   NO  NO    BH
+{8F1F6435-9F42-42C8-BADC-0E9424F20C9A}   0 NO   NO   NO  NO    BI
+.Ed
+
+.Sh SEE ALSO
+.Xr acpi 4 ,
+.Sh HISTORY
+The
+.Nm
+device driver first appeared in
+.Fx CURRENT .
+.Sh AUTHORS
+.An -nosplit
+The
+.Nm
+driver was written by
+.An Michael Gmelin Aq freebsd@grem.de
+.Pp
+Work has been inspired by the Linux acpi-wmi driver written by Carlos Corbacho
+.Pp
+See http://www.microsoft.com/whdc/system/pnppwr/wmi/wmi-acpi.mspx for
+the specification of ACPI-WMI.
+.Pp
+This manual page was written by
+.An Michael Gmelin Aq freebsd@grem.de
--- sys/dev/acpi_support/acpi_wmi.c~	2009-06-21 12:09:58.000000000 +0200
+++ sys/dev/acpi_support/acpi_wmi.c	2009-06-21 12:10:26.901562330 +0200
@@ -0,0 +1,911 @@
+/*-
+ * Copyright (c) 2009 Michael Gmelin <freebsd@grem.de>
+ * 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$");
+
+/*
+ * Driver for acpi-wmi mapping, provides an interface for vendor specific
+ * implementations (e.g. HP and Acer laptops).
+ * Inspired by the ACPI-WMI mapping driver (c) 2008-2008 Carlos Corbacho which
+ * implements this functionality for Linux.
+ *
+ * WMI and ACPI: http://www.microsoft.com/whdc/system/pnppwr/wmi/wmi-acpi.mspx
+ * acpi-wmi for Linux: http://www.kernel.org
+ */
+
+#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/malloc.h>
+#include <sys/sbuf.h>
+#include <sys/module.h>
+#include <sys/bus.h>
+
+#include <contrib/dev/acpica/acpi.h>
+#include <dev/acpica/acpivar.h>
+#include "acpi_wmi_if.h"
+
+MALLOC_DEFINE(M_ACPIWMI, "acpiwmi", "ACPI-WMI mapping");
+
+#define _COMPONENT	ACPI_OEM
+ACPI_MODULE_NAME("ACPI_WMI");
+
+#define ACPI_WMI_REGFLAG_EXPENSIVE	0x1	/* GUID flag: Expensive operation */
+#define ACPI_WMI_REGFLAG_METHOD		0x2	/* GUID flag: Method call */
+#define ACPI_WMI_REGFLAG_STRING		0x4	/* GUID flag: String */
+#define ACPI_WMI_REGFLAG_EVENT		0x8	/* GUID flag: Event */
+
+/*
+ * acpi_wmi driver private structure
+ */
+struct acpi_wmi_softc {
+	device_t	wmi_dev;		/* wmi device id */
+	ACPI_HANDLE	wmi_handle;		/* handle of the PNP0C14 node */
+	device_t	ec_dev;			/* acpi_ec0 */
+	struct cdev	*wmistat_dev_t;		/* wmistat device handle */
+	struct sbuf	wmistat_sbuf;		/* sbuf for /dev/wmistat output */
+	pid_t		wmistat_open_pid;	/* pid currently operating in /dev/wmistat */
+	int		wmistat_bufptr;		/* /dev/wmistat ptr to current buffer position */
+};
+
+/*
+ * Struct that holds information about 
+ * about a single GUID entry in _WDG
+ */
+struct guid_info {
+	char	guid[16];		/* 16 byte non human readable GUID */
+	char	oid[2];			/* object id or event notify id (first byte) */
+	UINT8	max_instance;		/* highest instance known for this GUID */
+	UINT8	flags;			/* ACPI_WMI_REGFLAG_%s */
+};
+
+/* WExx event generation state (on/off) */
+enum event_generation_state {
+	EVENT_GENERATION_ON = 1,
+	EVENT_GENERATION_OFF = 0
+};
+
+
+/*
+ * Information about one entry in _WDG.
+ * List of those is used to lookup information by GUID.
+ */
+struct wmi_info {
+	TAILQ_ENTRY(wmi_info)	wmi_list;
+	struct guid_info		ginfo;			/* information on guid */
+	ACPI_NOTIFY_HANDLER	event_handler;		/* client provided event handler */
+	void			*event_handler_user_data;	/* cookie to send when calling event_handler */
+};
+TAILQ_HEAD(wmi_info_list_head, wmi_info) wmi_info_list = TAILQ_HEAD_INITIALIZER(wmi_info_list);
+
+ACPI_SERIAL_DECL(acpi_wmi, "ACPI-WMI Mapping");
+
+/* public interface - declaration */
+/* standard device interface*/
+static int		acpi_wmi_probe(device_t dev);
+static int		acpi_wmi_attach(device_t dev);
+static int		acpi_wmi_detach(device_t dev);
+/* see acpi_wmi_if.m */
+static int		acpi_wmi_provides_guid_string_method(device_t dev, const char *guid_string);
+static ACPI_STATUS	acpi_wmi_evaluate_call_method(device_t dev, const char *guid_string, 
+			    UINT8 instance, UINT32 method_id, const ACPI_BUFFER *in, ACPI_BUFFER *out);
+static ACPI_STATUS	acpi_wmi_install_event_handler_method(device_t dev, const char *guid_string, 
+			    ACPI_NOTIFY_HANDLER handler, void *data);
+static ACPI_STATUS	acpi_wmi_remove_event_handler_method(device_t dev, const char *guid_string);
+static ACPI_STATUS	acpi_wmi_get_event_data_method(device_t dev, UINT32 event_id, ACPI_BUFFER *out);
+static ACPI_STATUS	acpi_wmi_get_block_method(device_t dev, const char *guid_string, 
+			    UINT8 instance, ACPI_BUFFER *out);
+static ACPI_STATUS	acpi_wmi_set_block_method(device_t dev, const char *guid_string,
+			    UINT8 instance, const ACPI_BUFFER *in);
+/* private interface - declaration */
+/* callbacks */
+static void		acpi_wmi_notify_handler(ACPI_HANDLE h, UINT32 notify, void *context);
+static ACPI_STATUS	acpi_wmi_ec_handler(UINT32 function, ACPI_PHYSICAL_ADDRESS address,
+			    UINT32 width, ACPI_INTEGER *value, void *context, 
+			    void *region_context);
+/* helpers */
+static ACPI_STATUS	acpi_wmi_read_wdg_blocks(ACPI_HANDLE h);
+static ACPI_STATUS	acpi_wmi_toggle_we_event_generation(device_t dev, struct wmi_info *winfo,
+			    enum event_generation_state state);
+static int		acpi_wmi_guid_string_to_guid(const UINT8 *guid_string, UINT8 *guid);
+static struct wmi_info* acpi_wmi_lookup_wmi_info_by_guid_string(const char *guid_string);
+
+static d_open_t acpi_wmi_wmistat_open;
+static d_close_t acpi_wmi_wmistat_close;
+static d_read_t acpi_wmi_wmistat_read;
+
+/* handler /dev/wmistat device */
+static struct cdevsw wmistat_cdevsw = {
+	.d_version = D_VERSION,
+	.d_open = acpi_wmi_wmistat_open,
+	.d_close = acpi_wmi_wmistat_close,
+	.d_read = acpi_wmi_wmistat_read,
+	.d_name = "wmistat",
+};
+
+
+static device_method_t acpi_wmi_methods[] = {
+	/* Device interface */
+	DEVMETHOD(device_probe,	acpi_wmi_probe),
+	DEVMETHOD(device_attach,	acpi_wmi_attach),
+	DEVMETHOD(device_detach,	acpi_wmi_detach),
+
+	/* acpi_wmi interface */
+	DEVMETHOD(acpi_wmi_provides_guid_string, acpi_wmi_provides_guid_string_method),
+	DEVMETHOD(acpi_wmi_evaluate_call, acpi_wmi_evaluate_call_method),
+	DEVMETHOD(acpi_wmi_install_event_handler, acpi_wmi_install_event_handler_method),
+	DEVMETHOD(acpi_wmi_remove_event_handler, acpi_wmi_remove_event_handler_method),
+	DEVMETHOD(acpi_wmi_get_event_data, acpi_wmi_get_event_data_method),
+	DEVMETHOD(acpi_wmi_get_block, acpi_wmi_get_block_method),
+	DEVMETHOD(acpi_wmi_set_block, acpi_wmi_set_block_method),
+
+	{0, 0}
+};
+
+static driver_t acpi_wmi_driver = {
+	"acpi_wmi",
+	acpi_wmi_methods,
+	sizeof(struct acpi_wmi_softc),
+};
+
+static devclass_t acpi_wmi_devclass;
+DRIVER_MODULE(acpi_wmi, acpi, acpi_wmi_driver, acpi_wmi_devclass, 0, 0);
+MODULE_VERSION(acpi_wmi, 1);
+MODULE_DEPEND(acpi_wmi, acpi, 1, 1, 1);
+static char *wmi_ids[] = {"PNP0C14", "PNP0c14", NULL};
+
+/*
+ * Probe for the PNP0C14 ACPI node
+ */
+static int
+acpi_wmi_probe(device_t dev)
+{
+	if (acpi_disabled("wmi") || 
+	    ACPI_ID_PROBE(device_get_parent(dev), dev, wmi_ids) == NULL)
+		return (ENXIO);
+	device_set_desc(dev, "ACPI-WMI mapping");
+	return (0);
+}
+
+/*
+ * Attach the device by:
+ * - Looking for the first ACPI EC device
+ * - Install the notify handler
+ * - Install the EC address space handler
+ * - Look for the _WDG node and read GUID information blocks
+ */
+static int
+acpi_wmi_attach(device_t dev)
+{
+	struct acpi_wmi_softc *sc;
+	int ret;
+	ACPI_STATUS status;
+
+	ACPI_FUNCTION_TRACE((char *)(uintptr_t)__func__);
+	sc = device_get_softc(dev);
+	ret = ENXIO;
+
+	ACPI_SERIAL_BEGIN(acpi_wmi);
+	sc->wmi_dev = dev;
+	sc->wmi_handle = acpi_get_handle(dev);
+	TAILQ_INIT(&wmi_info_list);
+	/* XXX Only works with one EC, but nearly all systems only have one. */
+	if ((sc->ec_dev = devclass_get_device(devclass_find("acpi_ec"), 0)) == NULL)
+		device_printf(dev, "cannot find EC device\n");
+	else if (ACPI_FAILURE((status = AcpiInstallNotifyHandler(sc->wmi_handle, 
+		    ACPI_DEVICE_NOTIFY, acpi_wmi_notify_handler, sc)))) 
+		device_printf(sc->wmi_dev, "couldn't install notify handler - %s\n", AcpiFormatException(status));
+	else if (ACPI_FAILURE((status = AcpiInstallAddressSpaceHandler(sc->wmi_handle, 
+		    ACPI_ADR_SPACE_EC, acpi_wmi_ec_handler, NULL, sc)))) {
+		device_printf(sc->wmi_dev, "couldn't install EC handler - %s\n", AcpiFormatException(status));
+		AcpiRemoveNotifyHandler(sc->wmi_handle, ACPI_DEVICE_NOTIFY, acpi_wmi_notify_handler);
+	} else if (ACPI_FAILURE((status = acpi_wmi_read_wdg_blocks(sc->wmi_handle)))) {
+		device_printf(sc->wmi_dev, "couldn't parse _WDG - %s\n", AcpiFormatException(status));
+		AcpiRemoveNotifyHandler(sc->wmi_handle, ACPI_DEVICE_NOTIFY, acpi_wmi_notify_handler);
+		AcpiRemoveAddressSpaceHandler(sc->wmi_handle, ACPI_ADR_SPACE_EC, acpi_wmi_ec_handler);
+	} else {
+		sc->wmistat_dev_t = make_dev(&wmistat_cdevsw, 0, UID_ROOT, GID_WHEEL, 0644, "wmistat");
+		sc->wmistat_dev_t->si_drv1 = sc;
+		sc->wmistat_open_pid = 0;
+		sc->wmistat_bufptr = -1;
+		ret = 0;
+	}
+	ACPI_SERIAL_END(acpi_wmi);
+	return (ret);
+}
+
+/*
+ * Detach the driver by:
+ * - Removing notification handler
+ * - Removing address space handler
+ * - Turning off event generation for all WExx event activated by
+ *   child drivers
+ */
+static int
+acpi_wmi_detach(device_t dev)
+{
+	struct wmi_info *winfo, *tmp;
+	struct acpi_wmi_softc *sc;
+	int ret;
+
+	ACPI_FUNCTION_TRACE((char *)(uintptr_t)__func__);
+	sc = device_get_softc(dev);
+	ACPI_SERIAL_BEGIN(acpi_wmi);
+
+	if (sc->wmistat_open_pid != 0) {
+		ret = EBUSY;
+	} else {
+		AcpiRemoveNotifyHandler(sc->wmi_handle, ACPI_DEVICE_NOTIFY, acpi_wmi_notify_handler);
+		AcpiRemoveAddressSpaceHandler(sc->wmi_handle, ACPI_ADR_SPACE_EC, acpi_wmi_ec_handler);
+		TAILQ_FOREACH_SAFE(winfo, &wmi_info_list, wmi_list, tmp) {
+			if (winfo->event_handler)
+				acpi_wmi_toggle_we_event_generation(dev, winfo, EVENT_GENERATION_OFF);
+			TAILQ_REMOVE(&wmi_info_list, winfo, wmi_list);
+			free(winfo, M_ACPIWMI);
+		}
+		if (sc->wmistat_bufptr != -1) {
+			sbuf_delete(&sc->wmistat_sbuf);
+			sc->wmistat_bufptr = -1;
+		}
+		sc->wmistat_open_pid = 0;
+		destroy_dev(sc->wmistat_dev_t);
+		ret = 0;
+	}
+	ACPI_SERIAL_END(acpi_wmi);
+	return (ret);
+}
+
+
+/*
+ * Check if the given GUID string (human readable format AABBCCDD-EEFF-GGHH-IIJJ-KKLLMMNNOOPP)
+ * exists within _WDG
+ */
+static int
+acpi_wmi_provides_guid_string_method(device_t dev, const char *guid_string)
+{
+	int ret;
+
+	ACPI_FUNCTION_TRACE((char *)(uintptr_t)__func__);
+	ACPI_SERIAL_BEGIN(acpi_wmi);
+	ret = (acpi_wmi_lookup_wmi_info_by_guid_string(guid_string) == NULL)?0:1;
+	ACPI_SERIAL_END(acpi_wmi);
+	return (ret);
+}
+
+/*
+ * Call a method "method_id" on the given GUID block
+ * write result into user provided output buffer
+ */
+static ACPI_STATUS
+acpi_wmi_evaluate_call_method(device_t dev, const char *guid_string, UINT8 instance, 
+	UINT32 method_id, const ACPI_BUFFER *in, ACPI_BUFFER *out)
+{
+	ACPI_OBJECT params[3];
+	ACPI_OBJECT_LIST input;
+	char method[5] = "WMxx";
+	struct wmi_info *winfo;
+	struct acpi_wmi_softc *sc;
+	ACPI_STATUS status;
+
+	ACPI_FUNCTION_TRACE((char *)(uintptr_t)__func__);
+
+	sc = device_get_softc(dev);
+	ACPI_SERIAL_BEGIN(acpi_wmi);
+	if ((winfo = acpi_wmi_lookup_wmi_info_by_guid_string(guid_string)) == NULL)
+		status = AE_NOT_FOUND;
+	else if (!(winfo->ginfo.flags & ACPI_WMI_REGFLAG_METHOD))
+		status = AE_BAD_DATA;
+	else if (instance > winfo->ginfo.max_instance)
+		status = AE_BAD_PARAMETER;
+	else {
+		params[0].Type = ACPI_TYPE_INTEGER;
+		params[0].Integer.Value = instance;
+		params[1].Type = ACPI_TYPE_INTEGER;
+		params[1].Integer.Value = method_id;
+		input.Pointer = params;
+		input.Count = 2;
+		if (in) {
+			params[2].Type = (winfo->ginfo.flags & ACPI_WMI_REGFLAG_STRING)
+			    ?ACPI_TYPE_STRING:ACPI_TYPE_BUFFER;
+			params[2].Buffer.Length = in->Length;
+			params[2].Buffer.Pointer = in->Pointer;
+			input.Count = 3;
+		}
+		method[2] = winfo->ginfo.oid[0];
+		method[3] = winfo->ginfo.oid[1];
+		status = AcpiEvaluateObject(sc->wmi_handle, method, &input, out);
+	}
+	ACPI_SERIAL_END(acpi_wmi);
+	return (status);
+}
+
+/*
+ * Install a user provided event_handler on the given GUID
+ * provided *data will be passed on callback
+ * If there is already an existing event handler registered it will be silently discarded
+ */
+static ACPI_STATUS
+acpi_wmi_install_event_handler_method(device_t dev, const char *guid_string,
+	ACPI_NOTIFY_HANDLER event_handler, void *data)
+{
+	struct wmi_info *winfo;
+	ACPI_STATUS status;
+
+	ACPI_FUNCTION_TRACE((char *)(uintptr_t)__func__);
+
+	status = AE_OK;
+	ACPI_SERIAL_BEGIN(acpi_wmi);
+	if (guid_string == NULL || event_handler == NULL)
+		status = AE_BAD_PARAMETER;
+	else if ((winfo = acpi_wmi_lookup_wmi_info_by_guid_string(guid_string)) == NULL)
+		status = AE_NOT_EXIST;
+	else if (winfo->event_handler != NULL || 
+	    (status = acpi_wmi_toggle_we_event_generation(dev, winfo, EVENT_GENERATION_ON)) == AE_OK) {
+		winfo->event_handler = event_handler;
+		winfo->event_handler_user_data = data;
+	}
+	ACPI_SERIAL_END(acpi_wmi);
+	return (status);
+}
+
+/*
+ * Remove a previously installed event handler from the given GUID
+ * If there was none installed, this call is silently discarded and reported as AE_OK
+ */
+static ACPI_STATUS
+acpi_wmi_remove_event_handler_method(device_t dev, const char *guid_string)
+{
+	struct wmi_info *winfo;
+	ACPI_STATUS status;
+
+	ACPI_FUNCTION_TRACE((char *)(uintptr_t)__func__);
+
+	status = AE_OK;
+	ACPI_SERIAL_BEGIN(acpi_wmi);
+	if (guid_string &&
+	    (winfo = acpi_wmi_lookup_wmi_info_by_guid_string(guid_string)) != NULL &&
+	    winfo->event_handler)
+	{
+		status = acpi_wmi_toggle_we_event_generation(dev, winfo, EVENT_GENERATION_OFF);
+		winfo->event_handler = NULL;
+		winfo->event_handler_user_data = NULL;
+	}
+	ACPI_SERIAL_END(acpi_wmi);
+	return (status);
+}
+
+/*
+ * Get details on an event received through a callback registered
+ * through ACPI_WMI_REMOVE_EVENT_HANDLER into a user provided output buffer.
+ * (event_id equals "notify" passed in the callback)
+ */
+static ACPI_STATUS
+acpi_wmi_get_event_data_method(device_t dev, UINT32 event_id, ACPI_BUFFER *out)
+{
+	ACPI_OBJECT_LIST input;
+	ACPI_OBJECT params[1];
+	struct acpi_wmi_softc *sc;
+	struct wmi_info *winfo;
+	ACPI_STATUS status;
+
+	ACPI_FUNCTION_TRACE((char *)(uintptr_t)__func__);
+
+	sc = device_get_softc(dev);
+	status = AE_NOT_FOUND;	
+	ACPI_SERIAL_BEGIN(acpi_wmi);
+	params[0].Type = ACPI_TYPE_INTEGER;
+	params[0].Integer.Value = event_id;
+	input.Pointer = params;
+	input.Count = 1;
+	TAILQ_FOREACH(winfo, &wmi_info_list, wmi_list) {
+		if ((winfo->ginfo.flags & ACPI_WMI_REGFLAG_EVENT) &&
+		    ((UINT8) winfo->ginfo.oid[0] == event_id)) {
+			status = AcpiEvaluateObject(sc->wmi_handle, "_WED", &input, out);
+			break;
+		}
+	}
+	ACPI_SERIAL_END(acpi_wmi);
+	return (status);
+}
+
+/*
+ * Read a block of data from the given GUID (using WQxx (query))
+ * Will be returned in a user provided buffer (out).
+ * If the method is marked as expensive (ACPI_WMI_REGFLAG_EXPENSIVE)
+ * we will first call the WCxx control method to lock the node to
+ * lock the node for data collection and release it afterwards.
+ * (Failed WCxx calls are ignored to "support" broken implementations)
+ */
+static ACPI_STATUS
+acpi_wmi_get_block_method(device_t dev, const char *guid_string, UINT8 instance, 
+	ACPI_BUFFER *out)
+{
+	char wc_method[5] = "WCxx";
+	char wq_method[5] = "WQxx";
+	ACPI_OBJECT_LIST wc_input;
+	ACPI_OBJECT_LIST wq_input;
+	ACPI_OBJECT wc_params[1];
+	ACPI_OBJECT wq_params[1];
+	ACPI_HANDLE wc_handle;
+	struct acpi_wmi_softc *sc;
+	struct wmi_info *winfo;
+	ACPI_STATUS status;
+	ACPI_STATUS wc_status;
+
+	ACPI_FUNCTION_TRACE((char *)(uintptr_t)__func__);
+
+	sc = device_get_softc(dev);
+	wc_status = AE_ERROR;
+	ACPI_SERIAL_BEGIN(acpi_wmi);
+	if (guid_string == NULL || out == NULL)
+		status = AE_BAD_PARAMETER;
+	else if ((winfo = acpi_wmi_lookup_wmi_info_by_guid_string(guid_string)) == NULL)
+		status = AE_ERROR;
+	else if (instance > winfo->ginfo.max_instance)
+		status = AE_BAD_PARAMETER;
+	else if ((winfo->ginfo.flags & ACPI_WMI_REGFLAG_EVENT) || 
+	    (winfo->ginfo.flags & ACPI_WMI_REGFLAG_METHOD))
+		status = AE_ERROR;
+	else {
+		wq_params[0].Type = ACPI_TYPE_INTEGER;
+		wq_params[0].Integer.Value = instance;
+		wq_input.Pointer = wq_params;
+		wq_input.Count = 1;
+		if (winfo->ginfo.flags & ACPI_WMI_REGFLAG_EXPENSIVE) {
+			wc_params[0].Type = ACPI_TYPE_INTEGER;
+			wc_params[0].Integer.Value = 1;
+			wc_input.Pointer = wc_params;
+			wc_input.Count = 1;
+			wc_method[2] = winfo->ginfo.oid[0];
+			wc_method[3] = winfo->ginfo.oid[1];
+			wc_status = AcpiGetHandle(sc->wmi_handle, wc_method, &wc_handle);
+			if (ACPI_SUCCESS(wc_status))
+				wc_status = AcpiEvaluateObject(wc_handle, wc_method, &wc_input, NULL);
+		}
+		wq_method[2] = winfo->ginfo.oid[0];
+		wq_method[3] = winfo->ginfo.oid[1];
+		status = AcpiEvaluateObject(sc->wmi_handle, wq_method, &wq_input, out);
+		if ((winfo->ginfo.flags & ACPI_WMI_REGFLAG_EXPENSIVE) && ACPI_SUCCESS(wc_status)) {
+			wc_params[0].Integer.Value = 0;
+			status = AcpiEvaluateObject(wc_handle, wc_method, &wc_input, NULL);  /* XXX this might be the wrong status to return? */
+		}
+	}
+	ACPI_SERIAL_END(acpi_wmi);
+	return (status);
+}
+
+/*
+ * Write a block of data to the given GUID (using WSxx)
+ */
+static ACPI_STATUS
+acpi_wmi_set_block_method(device_t dev, const char *guid_string, UINT8 instance, 
+	const ACPI_BUFFER *in)
+{
+	char method[5] = "WSxx";
+	ACPI_OBJECT_LIST input;
+	ACPI_OBJECT params[2];
+	struct wmi_info *winfo;
+	struct acpi_wmi_softc *sc;
+	ACPI_STATUS status;
+
+	ACPI_FUNCTION_TRACE((char *)(uintptr_t)__func__);
+
+	sc = device_get_softc(dev);
+	ACPI_SERIAL_BEGIN(acpi_wmi);
+	if (guid_string == NULL || in == NULL)
+		status = AE_BAD_DATA;
+	else if ((winfo = acpi_wmi_lookup_wmi_info_by_guid_string(guid_string)) 
+	    == NULL)
+		status = AE_ERROR;
+	else if (instance > winfo->ginfo.max_instance)
+		status = AE_BAD_PARAMETER;
+	else if ((winfo->ginfo.flags & ACPI_WMI_REGFLAG_EVENT) || 
+	    (winfo->ginfo.flags & ACPI_WMI_REGFLAG_METHOD))
+		status = AE_ERROR;
+	else {
+		params[0].Type = ACPI_TYPE_INTEGER;
+		params[0].Integer.Value = instance;
+		input.Pointer = params;
+		input.Count = 2;
+		params[1].Type = (winfo->ginfo.flags & ACPI_WMI_REGFLAG_STRING)
+		    ?ACPI_TYPE_STRING:ACPI_TYPE_BUFFER;
+		params[1].Buffer.Length = in->Length;
+		params[1].Buffer.Pointer = in->Pointer;
+		method[2] = winfo->ginfo.oid[0];
+		method[3] = winfo->ginfo.oid[1];
+		status = AcpiEvaluateObject(sc->wmi_handle, method, &input, NULL);
+	}
+	ACPI_SERIAL_END(acpi_wmi);
+	return (status);
+}
+
+/*
+ * Handle events received and dispatch them to 
+ * stakeholders that registered through ACPI_WMI_INSTALL_EVENT_HANDLER
+ */
+static void 
+acpi_wmi_notify_handler(ACPI_HANDLE h, UINT32 notify, void *context)
+{
+	ACPI_NOTIFY_HANDLER handler;
+	void *handler_data;
+	struct wmi_info *winfo;
+
+	ACPI_FUNCTION_TRACE_U32((char *)(uintptr_t)__func__, notify);
+
+	handler = NULL;
+	handler_data = NULL;
+	ACPI_SERIAL_BEGIN(acpi_wmi);
+	TAILQ_FOREACH(winfo, &wmi_info_list, wmi_list) {
+		if ((winfo->ginfo.flags & ACPI_WMI_REGFLAG_EVENT) &&
+				((UINT8) winfo->ginfo.oid[0] == notify)) {
+			if (winfo->event_handler) {
+				handler = winfo->event_handler;
+				handler_data = winfo->event_handler_user_data;
+				break;
+			}
+		}
+	}
+	ACPI_SERIAL_END(acpi_wmi);
+	if (handler) {
+		handler(h, notify, handler_data);
+	}
+}
+
+/*
+ * Handle EC address space notifications reveived on the WDG node
+ * (this mimics EcAddressSpaceHandler in acpi_ec.c)
+ */
+static ACPI_STATUS
+acpi_wmi_ec_handler(UINT32 function, ACPI_PHYSICAL_ADDRESS address, UINT32 width, 
+	ACPI_INTEGER *value, void *context, void *region_context)
+{
+	struct acpi_wmi_softc *sc;
+	int i;
+	ACPI_INTEGER ec_data;
+	UINT8 ec_addr;
+	ACPI_STATUS status;
+
+	ACPI_FUNCTION_TRACE_U32((char *)(uintptr_t)__func__, (UINT32)Address);
+
+	sc = (struct acpi_wmi_softc *)context;
+	if (width % 8 != 0 || value == NULL || context == NULL)
+		return (AE_BAD_PARAMETER);
+	if (address + (width / 8) - 1 > 0xFF)
+		return (AE_BAD_ADDRESS);
+	if (function == ACPI_READ)
+		*value = 0;
+	ec_addr = address;
+	status = AE_ERROR;
+
+	for (i = 0; i < width; i += 8, ++ec_addr) {
+		switch (function) {
+		case ACPI_READ:
+			status = ACPI_EC_READ(sc->ec_dev, ec_addr, &ec_data, 1);
+			if (ACPI_SUCCESS(status))
+				*value |= ((ACPI_INTEGER)ec_data) << i;
+		break;
+		case ACPI_WRITE:
+			ec_data = (UINT8)((*value) >> i);
+			status = ACPI_EC_WRITE(sc->ec_dev, ec_addr, ec_data, 1);
+			break;
+		default:
+			device_printf(sc->wmi_dev, "invalid acpi_wmi_ec_handler function %d\n",
+			    function);
+			status = AE_BAD_PARAMETER;
+			break;
+		}
+		if (ACPI_FAILURE(status))
+			break;
+	}
+	return (status);
+}
+
+/*
+ * Read GUID blocks from the _WDG node
+ * into wmi_info_list.
+ */
+static ACPI_STATUS
+acpi_wmi_read_wdg_blocks(ACPI_HANDLE h)
+{
+	ACPI_BUFFER out = {ACPI_ALLOCATE_BUFFER, NULL};
+	struct guid_info *ginfo;
+	ACPI_OBJECT *obj;
+	struct wmi_info *winfo;
+	UINT32 i;
+	UINT32 wdg_block_count;
+	ACPI_STATUS status;
+
+	ACPI_FUNCTION_TRACE((char *)(uintptr_t)__func__);
+
+	ACPI_SERIAL_ASSERT(acpi_wmi);
+	if (ACPI_FAILURE(status = AcpiEvaluateObject(h, "_WDG", NULL, &out)))
+		return (status);
+	obj = (ACPI_OBJECT*) out.Pointer;
+	wdg_block_count = obj->Buffer.Length / sizeof(struct guid_info);
+	if ((ginfo = malloc(obj->Buffer.Length, M_ACPIWMI, M_NOWAIT)) == NULL) {
+		AcpiOsFree(out.Pointer);
+		return (AE_NO_MEMORY);
+	}
+	memcpy(ginfo, obj->Buffer.Pointer, obj->Buffer.Length);
+	for (i = 0; i < wdg_block_count; ++i) {
+		if ((winfo = malloc(sizeof(struct wmi_info), M_ACPIWMI, M_NOWAIT | M_ZERO)) == NULL) {
+			AcpiOsFree(out.Pointer);
+			free(ginfo, M_ACPIWMI);
+			return (AE_NO_MEMORY);
+		}
+		winfo->ginfo = ginfo[i];
+		TAILQ_INSERT_TAIL(&wmi_info_list, winfo, wmi_list);
+	}
+	AcpiOsFree(out.Pointer);
+	free(ginfo, M_ACPIWMI);
+	return (status);
+}
+
+/*
+ * Toggle event generation in for the given GUID (passed by winfo)
+ * Turn on to get notified (through acpi_wmi_notify_handler) if eventy happen
+ * on the given GUID.
+ */
+static ACPI_STATUS
+acpi_wmi_toggle_we_event_generation(device_t dev, struct wmi_info *winfo, enum event_generation_state state)
+{
+	char method[5] = "WExx";
+	ACPI_OBJECT_LIST input;
+	ACPI_OBJECT params[1];
+	struct acpi_wmi_softc *sc;
+	ACPI_STATUS status;
+
+	ACPI_FUNCTION_TRACE((char *)(uintptr_t)__func__);
+
+	sc = device_get_softc(dev);
+	ACPI_SERIAL_ASSERT(acpi_wmi);
+	params[0].Type = ACPI_TYPE_INTEGER;
+	params[0].Integer.Value = state==EVENT_GENERATION_ON?1:0;
+	input.Pointer = params;
+	input.Count = 1;
+	
+	UINT8 hi = ((UINT8) winfo->ginfo.oid[0]) >> 4;
+	UINT8 lo = ((UINT8) winfo->ginfo.oid[0]) & 0xf;
+	method[2] = (hi > 9 ? hi + 55: hi + 48);
+	method[3] = (lo > 9 ? lo + 55: lo + 48);
+	status = AcpiEvaluateObject(sc->wmi_handle, method, &input, NULL);
+	if (status == AE_NOT_FOUND) status = AE_OK;
+	return (status);
+}
+
+/*
+ * Convert given two digit hex string (hexin) to an UINT8 referenced
+ * by byteout.
+ * Return != 0 if the was a problem (invalid input)
+ */
+static __inline int acpi_wmi_hex_to_int(const UINT8 *hexin, UINT8 *byteout)
+{
+	unsigned int hi;
+	unsigned int lo;
+
+	hi = hexin[0];
+	lo = hexin[1];
+	if ('0' <= hi && hi <= '9')
+		hi -= '0';
+	else if ('A' <= hi && hi <= 'F')
+		hi -= ('A' - 10);
+	else if ('a' <= hi && hi <= 'f')
+		hi -= ('a' - 10);
+	else
+		return (1);
+	if ('0' <= lo && lo <= '9')
+		lo -= '0';
+	else if ('A' <= lo && lo <= 'F')
+		lo -= ('A' - 10);
+	else if ('a' <= lo && lo <= 'f')
+		lo -= ('a' - 10);
+	else
+		return (1);
+	*byteout = (hi << 4) + lo;
+	return (0);
+}
+
+/*
+ * Convert a human readable 36 character GUID into a 16byte machine readable one.
+ * The basic algorithm looks as follows:
+ * Input:  AABBCCDD-EEFF-GGHH-IIJJ-KKLLMMNNOOPP
+ * Output: DCBAFEHGIJKLMNOP
+ * (AA BB CC etc. represent two digit hex numbers == bytes)
+ * Return != 0 if passed guid string is invalid
+ */
+static int
+acpi_wmi_guid_string_to_guid(const UINT8 *guid_string, UINT8 *guid)
+{
+	static const int mapping[20] = {3, 2, 1, 0, -1, 5, 4, -1, 7, 6, -1, 8, 9, 
+	    -1, 10, 11, 12, 13, 14, 15};
+	int i;
+
+	for (i = 0; i < 20; ++i, ++guid_string) {
+		if (mapping[i] >= 0) {
+			if (acpi_wmi_hex_to_int(guid_string, &guid[mapping[i]]))
+				return (-1);
+			++guid_string;
+		} else if (*guid_string != '-')
+			return (-1);
+	}
+	return (0);
+}
+
+/*
+ * Lookup a wmi_info structure in wmi_list based on a
+ * human readable GUID
+ * Return NULL if the GUID is unknown in the _WDG
+ */
+static struct wmi_info*
+acpi_wmi_lookup_wmi_info_by_guid_string(const char *guid_string)
+{
+	char guid[16];
+	struct wmi_info *winfo;
+
+	ACPI_FUNCTION_TRACE((char *)(uintptr_t)__func__);
+
+	ACPI_SERIAL_ASSERT(acpi_wmi);
+
+	if (!acpi_wmi_guid_string_to_guid(guid_string, guid)) {
+		TAILQ_FOREACH(winfo, &wmi_info_list, wmi_list) {
+			if (!memcmp(winfo->ginfo.guid, guid, 16)) {
+				return (winfo);
+			}
+		}
+	}
+	return (NULL);
+}
+
+/*
+ * open wmistat device
+ */
+static int
+acpi_wmi_wmistat_open(struct cdev* dev, int flags, int mode, struct thread *td)
+{
+	struct acpi_wmi_softc *sc;
+	int ret;
+
+	if (dev == NULL || dev->si_drv1 == NULL)
+		return (EBADF);
+	sc = dev->si_drv1;
+
+	ACPI_SERIAL_BEGIN(acpi_wmi);
+	if (sc->wmistat_open_pid != 0) {
+		ret = EBUSY;
+	}
+	else {
+		if (sbuf_new(&sc->wmistat_sbuf, NULL, 4096, SBUF_AUTOEXTEND) == NULL) {
+			ret = ENXIO;
+		} else {
+			sc->wmistat_open_pid = td->td_proc->p_pid;
+			sc->wmistat_bufptr = 0;
+			ret = 0;
+		}
+	}
+	ACPI_SERIAL_END(acpi_wmi);
+	return (ret);
+}
+
+/*
+ * close wmistat device
+ */
+static int
+acpi_wmi_wmistat_close(struct cdev* dev, int flags, int mode, struct thread *td)
+{
+	struct acpi_wmi_softc *sc;
+	int ret;
+
+	if (dev == NULL || dev->si_drv1 == NULL)
+		return (EBADF);
+	sc = dev->si_drv1;
+
+	ACPI_SERIAL_BEGIN(acpi_wmi);
+	if (sc->wmistat_open_pid == 0) {
+		ret = EBADF;
+	}
+	else {
+		if (sc->wmistat_bufptr != -1) {
+			sbuf_delete(&sc->wmistat_sbuf);
+			sc->wmistat_bufptr = -1;
+		}
+		sc->wmistat_open_pid = 0;
+		ret = 0;
+	}
+	ACPI_SERIAL_END(acpi_wmi);
+	return (ret);
+}
+
+/*
+ * Read from wmistat guid information
+ */
+static int
+acpi_wmi_wmistat_read(struct cdev *dev, struct uio *buf, int flag)
+{
+	struct acpi_wmi_softc *sc;
+	struct wmi_info *winfo;
+	int l;
+	int ret;
+	UINT8* guid;
+
+	if (dev == NULL || dev->si_drv1 == NULL)
+		return (EBADF);
+	sc = dev->si_drv1;
+	
+	ACPI_SERIAL_BEGIN(acpi_wmi);
+	if (sc->wmistat_open_pid != buf->uio_td->td_proc->p_pid ||
+			sc->wmistat_bufptr == -1) {
+		ret = EBADF;
+	}
+	else {
+		if (!sbuf_done(&sc->wmistat_sbuf)) {
+			sbuf_printf(&sc->wmistat_sbuf, "GUID                                  INST EXPE METH STR EVENT OID\n");
+			TAILQ_FOREACH(winfo, &wmi_info_list, wmi_list) {
+				guid = (UINT8*)winfo->ginfo.guid;
+				sbuf_printf(&sc->wmistat_sbuf,
+					"{%02X%02X%02X%02X-%02X%02X-%02X%02X-%02X%02X-%02X%02X%02X%02X%02X%02X} %3d %-5s",
+					guid[3], guid[2], guid[1], guid[0],
+					guid[5], guid[4],
+					guid[7], guid[6],
+					guid[8], guid[9],
+					guid[10], guid[11], guid[12], guid[13], guid[14], guid[15],
+					winfo->ginfo.max_instance,
+					(winfo->ginfo.flags&ACPI_WMI_REGFLAG_EXPENSIVE)?"YES":"NO"
+					);
+				if (winfo->ginfo.flags&ACPI_WMI_REGFLAG_METHOD)
+					sbuf_printf(&sc->wmistat_sbuf, "WM%c%c ",
+					winfo->ginfo.oid[0], winfo->ginfo.oid[1]);
+				else
+					sbuf_printf(&sc->wmistat_sbuf, "NO   ");
+				sbuf_printf(&sc->wmistat_sbuf, "%-4s",
+					(winfo->ginfo.flags&ACPI_WMI_REGFLAG_STRING)?"YES":"NO"
+					);
+				if (winfo->ginfo.flags&ACPI_WMI_REGFLAG_EVENT)
+					sbuf_printf(&sc->wmistat_sbuf, "0x%02X%s -\n",
+					(UINT8)winfo->ginfo.oid[0], winfo->event_handler==NULL?" ":"+");
+				else
+					sbuf_printf(&sc->wmistat_sbuf, "NO    %c%c\n", 
+						winfo->ginfo.oid[0], winfo->ginfo.oid[1]);
+			}
+			sbuf_finish(&sc->wmistat_sbuf);
+		}
+		if (sbuf_len(&sc->wmistat_sbuf) <= 0) {
+			sbuf_delete(&sc->wmistat_sbuf);
+			sc->wmistat_bufptr = -1;
+			sc->wmistat_open_pid = 0;
+			ret = ENOMEM;
+		} else {
+			l = min(buf->uio_resid, sbuf_len(&sc->wmistat_sbuf) - sc->wmistat_bufptr);
+			ret = (l > 0)?uiomove(sbuf_data(&sc->wmistat_sbuf) + sc->wmistat_bufptr, l, buf) : 0;
+			sc->wmistat_bufptr += l;
+		}
+	}
+	ACPI_SERIAL_END(acpi_wmi);
+	return (ret);
+}
--- sys/dev/acpi_support/acpi_wmi_if.m~	2009-06-21 12:09:58.000000000 +0200
+++ sys/dev/acpi_support/acpi_wmi_if.m	2009-06-21 12:13:23.546375847 +0200
@@ -0,0 +1,144 @@
+#-
+# Copyright (c) 2009 Michael Gmelin
+# 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/acpic_support/acpi_wmi_if.m,v 1.0 2008/11/23 16:33:00 rmg Exp $
+#
+
+#include <sys/bus.h>
+#include <sys/types.h>
+#include <contrib/dev/acpica/acpi.h>
+
+INTERFACE acpi_wmi;
+
+#
+# Default implementation for acpi_wmi_generic_provides_guid_string().
+#
+CODE {
+	static int
+	acpi_wmi_generic_provides_guid_string(device_t dev, const char* guid_string)
+	{
+		return 0;
+	}
+};
+
+
+#
+# Check if given GUID exists in WMI
+#
+# device_t dev:	Device to probe
+# const char* guid_string: String form of the GUID
+#
+METHOD int provides_guid_string {
+	device_t	dev;
+	const char*	guid_string;
+} DEFAULT acpi_wmi_generic_provides_guid_string;
+
+#
+# Evaluate a WMI method call
+#
+# device_t dev:  Device to use
+# const char* guid_string:  String form of the GUID
+# UINT8 instance: instance id
+# UINT32 method_id: method to call
+# const ACPI_BUFFER* in: input data
+# ACPI_BUFFER* out: output buffer
+#
+METHOD ACPI_STATUS evaluate_call {
+	device_t	dev;
+	const char	*guid_string;
+	UINT8		instance;
+	UINT32		method_id;
+	const ACPI_BUFFER *in;
+	ACPI_BUFFER	*out;
+};
+
+#
+# Get content of a WMI block
+#
+# device_t dev:  Device to use
+# const char* guid_string:  String form of the GUID
+# UINT8 instance: instance id
+# ACPI_BUFFER* out: output buffer
+#
+METHOD ACPI_STATUS get_block {
+	device_t	dev;
+	const char	*guid_string;
+	UINT8		instance;
+	ACPI_BUFFER	*out;
+};
+#
+# Write to a WMI data block
+#
+# device_t dev:  Device to use
+# const char* guid_string:  String form of the GUID
+# UINT8 instance: instance id
+# const ACPI_BUFFER* in: input data
+#
+METHOD ACPI_STATUS set_block {
+	device_t	dev;
+	const char	*guid_string;
+	UINT8		instance;
+	const ACPI_BUFFER *in;
+};
+
+#
+# Install wmi event handler
+#
+# device_t dev:  Device to use
+# const char* guid_string:  String form of the GUID
+# ACPI_NOTIFY_HANDLER handler: Handler
+# void* data: Payload
+#
+METHOD ACPI_STATUS install_event_handler {
+	device_t	dev;
+	const char	*guid_string;
+	ACPI_NOTIFY_HANDLER handler;
+	void		*data;
+};
+
+#
+# Remove wmi event handler
+#
+# device_t dev:  Device to use
+# const char* guid_string:  String form of the GUID
+#
+METHOD ACPI_STATUS remove_event_handler {
+	device_t	dev;
+	const char	*guid_string;
+};
+
+
+#
+# Get event data associated to an event
+#
+# device_t dev:  Device to use
+# UINT32 event_id: event id
+# ACPI_BUFFER* out: output buffer
+#
+METHOD ACPI_STATUS get_event_data {
+	device_t	dev;
+	UINT32		event_id;
+	ACPI_BUFFER	*out;
+};
--- sys/modules/acpi/acpi_hp/Makefile~	2009-06-21 12:09:58.000000000 +0200
+++ sys/modules/acpi/acpi_hp/Makefile	2009-06-21 12:10:33.000000000 +0100
@@ -0,0 +1,9 @@
+# $FreeBSD: src/sys/modules/acpi/acpi_hp/Makefile,v 1.3 2004/12/13 04:59:35 imp Exp $
+
+.PATH:		${.CURDIR}/../../../dev/acpi_support
+KMOD=		acpi_hp
+CFLAGS+=	-I${.CURDIR}/../../../contrib/dev/acpica
+SRCS=		acpi_hp.c opt_acpi.h device_if.h bus_if.h acpi_if.h acpi_wmi_if.h
+SRCS+=		opt_ddb.h
+
+.include <bsd.kmod.mk>
--- sys/modules/acpi/acpi_wmi/Makefile~	2009-06-21 12:09:58.000000000 +0200
+++ sys/modules/acpi/acpi_wmi/Makefile	2009-06-21 12:10:39.000000000 +0100
@@ -0,0 +1,10 @@
+#	$FreeBSD: src/sys/modules/acpi/acpi_wmi/Makefile,v 1.7 2007/06/24 20:36:51 njl Exp $
+
+.PATH:	${.CURDIR}/../../../dev/acpi_support
+
+KMOD=	acpi_wmi
+CFLAGS+= -I${.CURDIR}/../../../contrib/dev/acpica
+SRCS=	acpi_wmi.c
+SRCS+=	opt_acpi.h acpi_if.h bus_if.h device_if.h acpi_wmi_if.h
+
+.include <bsd.kmod.mk>
--- sys/conf/files.i386~	2008-12-29 04:46:14.000000000 +0100
+++ sys/conf/files.i386	2009-06-21 12:10:14.000000000 +0100
@@ -226,6 +226,7 @@
 dev/syscons/scvtb.c		optional sc
 dev/uart/uart_cpu_i386.c	optional uart
 dev/acpica/acpi_if.m		standard
+dev/acpi_support/acpi_wmi_if.m  standard
 dev/wpi/if_wpi.c		optional wpi
 i386/acpica/OsdEnvironment.c	optional acpi
 i386/acpica/acpi_machdep.c	optional acpi
--- sys/conf/files~	2008-12-29 04:45:44.000000000 +0100
+++ sys/conf/files	2009-06-21 12:10:44.000000000 +0100
@@ -375,9 +375,11 @@
 dev/aac/aac_disk.c		optional aac
 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_aiboost.c	optional acpi_aiboost acpi
 dev/acpi_support/acpi_asus.c	optional acpi_asus 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
 dev/acpi_support/acpi_panasonic.c optional acpi_panasonic acpi
 dev/acpi_support/acpi_sony.c	optional acpi_sony acpi
--- sys/conf/kmod.mk~	2008-12-29 04:44:41.000000000 +0100
+++ sys/conf/kmod.mk	2009-06-21 12:10:41.000000000 +0100
@@ -321,7 +321,7 @@
 .endfor
 .endif
 
-MFILES?= dev/acpica/acpi_if.m dev/ata/ata_if.m dev/eisa/eisa_if.m \
+MFILES?= dev/acpica/acpi_if.m dev/acpi_support/acpi_wmi_if.m dev/agp/agp_if.m dev/ata/ata_if.m dev/eisa/eisa_if.m \
 	dev/iicbus/iicbb_if.m dev/iicbus/iicbus_if.m \
 	dev/mmc/mmcbr_if.m dev/mmc/mmcbus_if.m \
 	dev/mii/miibus_if.m dev/ofw/ofw_bus_if.m \
--- share/man/man4/man4.i386/Makefile~	2009-06-21 12:36:50.000000000 +0200
+++ share/man/man4/man4.i386/Makefile	2009-06-21 12:36:50.000000000 +0200
@@ -3,10 +3,12 @@
 MAN=	acpi_aiboost.4 \
 	acpi_asus.4 \
 	acpi_fujitsu.4 \
+	acpi_hp.4 \
 	acpi_ibm.4 \
 	acpi_panasonic.4 \
 	acpi_sony.4 \
 	acpi_toshiba.4 \
+	acpi_wmi.4 \
 	aic.4 \
 	alpm.4 \
 	amdpm.4 \

--------------000106060507010904000207
Content-Type: application/octet-stream;
 name="patches.tgz"
Content-Transfer-Encoding: base64
Content-Disposition: attachment;
 filename="patches.tgz"

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
Xp6X5+V5eV6el+fleXlenv+bnv8fEDd+cACQAQA=
--------------000106060507010904000207--



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?4A3E1784.2050406>