Skip site navigation (1)Skip section navigation (2)
Date:      Sat, 27 Jun 2009 13:24:59 +0200
From:      Michael Gmelin <freebsdusb@bindone.de>
To:        Rui Paulo <rpaulo@freebsd.org>, freebsd-acpi@freebsd.org
Cc:        "Paul B. Mahol" <onemda@gmail.com>
Subject:   Patches to acpi_hp
Message-ID:  <4A46018B.90709@bindone.de>

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

Hello,

please find attached a patch to acpi_hp.c and acpi_hp.4 (and the
complete files as well).

This patch brings:
- sysctl dev.acpi_hp.0.verbose to toggle debug output
- A modification so this can deal with different array lengths
  when reading the CMI BIOS - now it works ok on HP Compaq nx7300
  as well.
- Document sysctl in man page
- Add a section to manpage about hardware that has been reported
  to work ok

Installation instructions (against latest CURRENT):
patch -d /usr/src < /path/to/acpi_hp.patch
cd /usr/src/sys/modules/acpi/acpi_hp
make all && make install
cd /usr/src/share/man/man4
make all && make install

cheers
Michael


--------------090600020803080001000309
Content-Type: text/plain;
 name="acpi_hp.4"
Content-Transfer-Encoding: 7bit
Content-Disposition: inline;
 filename="acpi_hp.4"

.\" 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
.It Va dev.acpi_hp.0.verbose
(read-only)
Set verbosity level
.El
.Pp
Defaults for these sysctls can be set in
.Xr sysctl.conf 5 .
.Sh HARDWARE
The
.Nm
driver has been reported to support the following hardware:
.Pp
.Bl -bullet -compact
.It
HP Compaq 8510p
.It
HP Compaq nx7300
.El
.Pp
It should work on most HP laptops that feature a WMI enabled BIOS.
.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.

--------------090600020803080001000309
Content-Type: text/plain;
 name="acpi_hp.c"
Content-Transfer-Encoding: 7bit
Content-Disposition: inline;
 filename="acpi_hp.c"

/*-
 * 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/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("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 ACPI_HP_METHOD_VERBOSE				21

#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
						   (set by sysctl) */
	int		verbose;		/* add debug output */
	int		wlan_enable_if_radio_on;	/* set by sysctl */
	int		wlan_disable_if_radio_off;	/* set by sysctl */
	int		bluetooth_enable_if_radio_on;	/* set by sysctl */
	int		bluetooth_disable_if_radio_off;	/* set by sysctl */
	int		wwan_enable_if_radio_on;	/* set by sysctl */
	int		wwan_disable_if_radio_off;	/* set by sysctl */
	int		was_wlan_on_air;		/* last known WLAN
							   on air status */
	int		was_bluetooth_on_air;		/* last known BT
							   on 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
	},
	{
		.name		= "verbose",
		.method		= ACPI_HP_METHOD_VERBOSE,
		.description	= "Verbosity level",
		.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;

	if (sc->verbose)
		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;
			if (sc->verbose)
				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;
			if (sc->verbose)
				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;
			if (sc->verbose)
				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;
	sc->verbose = 0;
	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;
	case ACPI_HP_METHOD_VERBOSE:
		val = sc->verbose;
		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 &&
	    method != ACPI_HP_METHOD_VERBOSE)
		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;
		case ACPI_HP_METHOD_VERBOSE:
			sc->verbose = 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..8+[7] PrerequisiteN [string]
 * 9+[7]    Current value (in case of enum) [string] / Array length [int]
 * 10+[7]   Enum length [int] / Array values
 * 11+[7]ff 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;
	int		valuebase = 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);
	}

	if (obj->Package.Count >= 8 &&
	    obj->Package.Elements[7].Type == ACPI_TYPE_INTEGER) {
	    valuebase = 8 + obj->Package.Elements[7].Integer.Value;
	}

	/* check if this matches our expectations based on limited knowledge */
	if (valuebase > 7 && obj->Package.Count > valuebase + 1 &&
	    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[valuebase].Type == ACPI_TYPE_STRING &&
	    obj->Package.Elements[valuebase+1].Type == ACPI_TYPE_INTEGER &&
	    obj->Package.Count > valuebase + 
	        obj->Package.Elements[valuebase+1].Integer.Value
	   ) {
		enumbase = valuebase + 1;
		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);
		strlcat(outbuf, acpi_hp_get_string_from_object(
				&obj->Package.Elements[valuebase], 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);
}

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

--- share/man/man4/acpi_hp.4.orig	2009-06-26 12:50:30.005708266 +0200
+++ share/man/man4/acpi_hp.4	2009-06-26 13:03:16.331066657 +0200
@@ -166,10 +166,26 @@
 .It Li 0x04
 Show additional flags of BIOS setting (ReadOnly etc.)
 .El
+.It Va dev.acpi_hp.0.verbose
+(read-only)
+Set verbosity level
 .El
 .Pp
 Defaults for these sysctls can be set in
 .Xr sysctl.conf 5 .
+.Sh HARDWARE
+The
+.Nm
+driver has been reported to support the following hardware:
+.Pp
+.Bl -bullet -compact
+.It
+HP Compaq 8510p
+.It
+HP Compaq nx7300
+.El
+.Pp
+It should work on most HP laptops that feature a WMI enabled BIOS.
 .Sh FILES
 .Bl -tag -width ".Pa /dev/hpcmi"
 .It Pa /dev/hpcmi
--- sys/dev/acpi_support/acpi_hp.c.orig	2009-06-26 12:43:35.676585431 +0200
+++ sys/dev/acpi_support/acpi_hp.c	2009-06-26 12:54:46.509994426 +0200
@@ -92,6 +92,7 @@
 #define ACPI_HP_METHOD_HDDTEMP				18
 #define ACPI_HP_METHOD_DOCK				19
 #define ACPI_HP_METHOD_CMI_DETAIL			20
+#define ACPI_HP_METHOD_VERBOSE				21
 
 #define HP_MASK_WWAN_ON_AIR			0x1000000
 #define HP_MASK_BLUETOOTH_ON_AIR		0x10000
@@ -120,6 +121,7 @@
 	int		has_cmi;		/* CMI GUID found */
 	int		cmi_detail;		/* CMI detail level
 						   (set by sysctl) */
+	int		verbose;		/* add debug output */
 	int		wlan_enable_if_radio_on;	/* set by sysctl */
 	int		wlan_disable_if_radio_off;	/* set by sysctl */
 	int		bluetooth_enable_if_radio_on;	/* set by sysctl */
@@ -274,6 +276,12 @@
 				    "(cat /dev/hpcmi)",
 		.access		= CTLTYPE_INT | CTLFLAG_RW
 	},
+	{
+		.name		= "verbose",
+		.method		= ACPI_HP_METHOD_VERBOSE,
+		.description	= "Verbosity level",
+		.access		= CTLTYPE_INT | CTLFLAG_RW
+	},
 
 	{ NULL, 0, NULL, 0 }
 };
@@ -333,10 +341,10 @@
 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;
+	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);
@@ -344,7 +352,8 @@
 	new_bluetooth_status = -1;
 	new_wwan_status = -1;
 
-	device_printf(sc->wmi_dev, "Wireless status is %x\n", wireless);
+	if (sc->verbose)
+		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,
@@ -390,10 +399,11 @@
 		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);
+			if (sc->verbose)
+				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);
 		}
@@ -403,9 +413,12 @@
 		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);
+			if (sc->verbose)
+				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);
 		}
@@ -414,9 +427,11 @@
 		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);
+			if (sc->verbose)
+				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);
 		}
@@ -439,7 +454,7 @@
 	struct acpi_hp_softc	*sc;
 	struct acpi_softc	*acpi_sc;
 	devclass_t		wmi_devclass;
-	int arg;
+	int			arg;
 
 	ACPI_FUNCTION_TRACE((char *)(uintptr_t) __func__);
 
@@ -459,6 +474,7 @@
 	sc->was_wwan_on_air = 0;
 	sc->cmi_detail = 0;
 	sc->cmi_order_size = -1;
+	sc->verbose = 0;
 	memset(sc->cmi_order, 0, sizeof(sc->cmi_order));
 	acpi_sc = acpi_device_get_parent_softc(dev);
 
@@ -551,7 +567,7 @@
 static int
 acpi_hp_detach(device_t dev)
 {
-	int ret;
+	int	ret;
 	
 	ACPI_FUNCTION_TRACE((char *)(uintptr_t) __func__);
 	struct acpi_hp_softc *sc = device_get_softc(dev);
@@ -578,12 +594,12 @@
 static int
 acpi_hp_sysctl(SYSCTL_HANDLER_ARGS)
 {
-	struct acpi_hp_softc *sc;
-	int	arg;
-	int oldarg;
-	int	error = 0;
-	int	function;
-	int	method;
+	struct acpi_hp_softc	*sc;
+	int			arg;
+	int			oldarg;
+	int			error = 0;
+	int			function;
+	int			method;
 	
 	ACPI_FUNCTION_TRACE((char *)(uintptr_t)__func__);
 
@@ -606,7 +622,7 @@
 static int
 acpi_hp_sysctl_get(struct acpi_hp_softc *sc, int method)
 {
-	int val = 0;
+	int	val = 0;
 
 	ACPI_FUNCTION_TRACE((char *)(uintptr_t)__func__);
 	ACPI_SERIAL_ASSERT(hp);
@@ -694,6 +710,9 @@
 	case ACPI_HP_METHOD_CMI_DETAIL:
 		val = sc->cmi_detail;
 		break;
+	case ACPI_HP_METHOD_VERBOSE:
+		val = sc->verbose;
+		break;
 	}
 
 	return (val);
@@ -705,7 +724,8 @@
 	ACPI_FUNCTION_TRACE((char *)(uintptr_t)__func__);
 	ACPI_SERIAL_ASSERT(hp);
 
-	if (method != ACPI_HP_METHOD_CMI_DETAIL)
+	if (method != ACPI_HP_METHOD_CMI_DETAIL &&
+	    method != ACPI_HP_METHOD_VERBOSE)
 		arg = arg?1:0;
 
 	if (arg != oldarg) {
@@ -753,6 +773,9 @@
 		case ACPI_HP_METHOD_CMI_DETAIL:
 			sc->cmi_detail = arg;
 			break;
+		case ACPI_HP_METHOD_VERBOSE:
+			sc->verbose = arg;
+			break;
 		}
 	}
 
@@ -788,15 +811,15 @@
 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 };
+	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,
@@ -821,7 +844,8 @@
 
 static __inline char*
 acpi_hp_get_string_from_object(ACPI_OBJECT* obj, char* dst, size_t size) {
-	int length;
+	int	length;
+
 	dst[0] = 0;
 	if (obj->Type == ACPI_TYPE_STRING) {
 		length = obj->String.Length+1;
@@ -841,33 +865,32 @@
  * 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]
+ * 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..8+[7] PrerequisiteN [string]
+ * 9+[7]    Current value (in case of enum) [string] / Array length [int]
+ * 10+[7]   Enum length [int] / Array values
+ * 11+[7]ff 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;
+	ACPI_OBJECT	*obj;
+	ACPI_BUFFER	out = { ACPI_ALLOCATE_BUFFER, NULL };
+	int		i;
+	int		outlen;
+	int		size = 255;
+	int		has_enums = 0;
+	int		valuebase = 0;
+	char		string_buffer[size];
+	int		enumbase;
 
 	outlen = 0;
 	outbuf[0] = 0;	
@@ -881,8 +904,13 @@
 		return (-EINVAL);
 	}
 
+	if (obj->Package.Count >= 8 &&
+	    obj->Package.Elements[7].Type == ACPI_TYPE_INTEGER) {
+	    valuebase = 8 + obj->Package.Elements[7].Integer.Value;
+	}
+
 	/* check if this matches our expectations based on limited knowledge */
-	if (obj->Package.Count >= 13 &&
+	if (valuebase > 7 && obj->Package.Count > valuebase + 1 &&
 	    obj->Package.Elements[0].Type == ACPI_TYPE_STRING &&
 	    obj->Package.Elements[1].Type == ACPI_TYPE_STRING &&
 	    obj->Package.Elements[2].Type == ACPI_TYPE_STRING &&
@@ -890,20 +918,12 @@
 	    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;
+	    obj->Package.Elements[valuebase].Type == ACPI_TYPE_STRING &&
+	    obj->Package.Elements[valuebase+1].Type == ACPI_TYPE_INTEGER &&
+	    obj->Package.Count > valuebase + 
+	        obj->Package.Elements[valuebase+1].Integer.Value
+	   ) {
+		enumbase = valuebase + 1;
 		if (detail & ACPI_HP_CMI_DETAIL_PATHS) {
 			strlcat(outbuf, acpi_hp_get_string_from_object(
 				&obj->Package.Elements[2], string_buffer, size),
@@ -918,11 +938,10 @@
 		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);
+		strlcat(outbuf, acpi_hp_get_string_from_object(
+				&obj->Package.Elements[valuebase], string_buffer, 
+				size),
+				outsize);
 		outlen += 21;
 		while (strlen(outbuf) < outlen)
 			strlcat(outbuf, " ", outsize);
@@ -930,7 +949,7 @@
 			if (outbuf[i] == '\\')
 				outbuf[i] = '/';
 		if (detail & ACPI_HP_CMI_DETAIL_ENUMS) {
-			for (i = enumbase+1; i < enumbase + 1 +
+			for (i = enumbase + 1; i < enumbase + 1 +
 			    obj->Package.Elements[enumbase].Integer.Value;
 			    ++i) {
 				acpi_hp_get_string_from_object(
@@ -974,8 +993,8 @@
  */
 static __inline int acpi_hp_hex_to_int(const UINT8 *hexin, UINT8 *byteout)
 {
-	unsigned int hi;
-	unsigned int lo;
+	unsigned int	hi;
+	unsigned int	lo;
 
 	hi = hexin[0];
 	lo = hexin[1];
@@ -1004,10 +1023,10 @@
 static void
 acpi_hp_hex_decode(char* buffer)
 {
-	int i;
-	int length = strlen(buffer);
-	UINT8 *uin;
-	UINT8 uout;
+	int	i;
+	int	length = strlen(buffer);
+	UINT8	*uin;
+	UINT8	uout;
 
 	if (((int)length/2)*2 == length || length < 10) return;
 
@@ -1038,8 +1057,8 @@
 static int
 acpi_hp_hpcmi_open(struct cdev* dev, int flags, int mode, struct thread *td)
 {
-	struct acpi_hp_softc *sc;
-	int ret;
+	struct acpi_hp_softc	*sc;
+	int			ret;
 
 	if (dev == NULL || dev->si_drv1 == NULL)
 		return (EBADF);
@@ -1070,8 +1089,8 @@
 static int
 acpi_hp_hpcmi_close(struct cdev* dev, int flags, int mode, struct thread *td)
 {
-	struct acpi_hp_softc *sc;
-	int ret;
+	struct acpi_hp_softc	*sc;
+	int			ret;
 
 	if (dev == NULL || dev->si_drv1 == NULL)
 		return (EBADF);
@@ -1100,12 +1119,12 @@
 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];
+	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);

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

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
8+Pz7/n5P7EUM4QA8AAA
--------------090600020803080001000309--



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