acpi_hp.c revision 250053
1194701Srpaulo/*- 2194701Srpaulo * Copyright (c) 2009 Michael Gmelin <freebsd@grem.de> 3194701Srpaulo * All rights reserved. 4194701Srpaulo * 5194701Srpaulo * Redistribution and use in source and binary forms, with or without 6194701Srpaulo * modification, are permitted provided that the following conditions 7194701Srpaulo * are met: 8194701Srpaulo * 1. Redistributions of source code must retain the above copyright 9194701Srpaulo * notice, this list of conditions and the following disclaimer. 10194701Srpaulo * 2. Redistributions in binary form must reproduce the above copyright 11194701Srpaulo * notice, this list of conditions and the following disclaimer in the 12194701Srpaulo * documentation and/or other materials provided with the distribution. 13194701Srpaulo * 14194701Srpaulo * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 15194701Srpaulo * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16194701Srpaulo * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17194701Srpaulo * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 18194701Srpaulo * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19194701Srpaulo * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20194701Srpaulo * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21194701Srpaulo * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 22194701Srpaulo * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 23194701Srpaulo * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 24194701Srpaulo * SUCH DAMAGE. 25194701Srpaulo */ 26194701Srpaulo 27194701Srpaulo#include <sys/cdefs.h> 28194701Srpaulo__FBSDID("$FreeBSD: head/sys/dev/acpi_support/acpi_hp.c 250053 2013-04-29 18:54:31Z jhb $"); 29194701Srpaulo 30194701Srpaulo/* 31194701Srpaulo * Driver for extra ACPI-controlled features found on HP laptops 32194701Srpaulo * that use a WMI enabled BIOS (e.g. HP Compaq 8510p and 6510p). 33194701Srpaulo * Allows to control and read status of integrated hardware and read 34194701Srpaulo * BIOS settings through CMI. 35194701Srpaulo * Inspired by the hp-wmi driver, which implements a subset of these 36194701Srpaulo * features (hotkeys) on Linux. 37194701Srpaulo * 38194701Srpaulo * HP CMI whitepaper: 39194701Srpaulo * http://h20331.www2.hp.com/Hpsub/downloads/cmi_whitepaper.pdf 40194701Srpaulo * wmi-hp for Linux: 41194701Srpaulo * http://www.kernel.org 42194701Srpaulo * WMI and ACPI: 43194701Srpaulo * http://www.microsoft.com/whdc/system/pnppwr/wmi/wmi-acpi.mspx 44194701Srpaulo */ 45194701Srpaulo 46194701Srpaulo#include "opt_acpi.h" 47194701Srpaulo#include <sys/param.h> 48194701Srpaulo#include <sys/conf.h> 49194701Srpaulo#include <sys/uio.h> 50194701Srpaulo#include <sys/proc.h> 51194701Srpaulo#include <sys/kernel.h> 52194701Srpaulo#include <sys/bus.h> 53194701Srpaulo#include <sys/sbuf.h> 54194701Srpaulo#include <sys/module.h> 55194701Srpaulo#include <sys/sysctl.h> 56194701Srpaulo 57194701Srpaulo#include <contrib/dev/acpica/include/acpi.h> 58194701Srpaulo#include <contrib/dev/acpica/include/accommon.h> 59194701Srpaulo#include <dev/acpica/acpivar.h> 60194701Srpaulo#include "acpi_wmi_if.h" 61194701Srpaulo 62194701Srpaulo#define _COMPONENT ACPI_OEM 63194701SrpauloACPI_MODULE_NAME("HP") 64194701Srpaulo 65194701Srpaulo#define ACPI_HP_WMI_EVENT_GUID "95F24279-4D7B-4334-9387-ACCDC67EF61C" 66194701Srpaulo#define ACPI_HP_WMI_BIOS_GUID "5FB7F034-2C63-45E9-BE91-3D44E2C707E4" 67194701Srpaulo#define ACPI_HP_WMI_CMI_GUID "2D114B49-2DFB-4130-B8FE-4A3C09E75133" 68194701Srpaulo 69194701Srpaulo#define ACPI_HP_WMI_DISPLAY_COMMAND 0x1 70194701Srpaulo#define ACPI_HP_WMI_HDDTEMP_COMMAND 0x2 71194701Srpaulo#define ACPI_HP_WMI_ALS_COMMAND 0x3 72194701Srpaulo#define ACPI_HP_WMI_DOCK_COMMAND 0x4 73194701Srpaulo#define ACPI_HP_WMI_WIRELESS_COMMAND 0x5 74194701Srpaulo 75194701Srpaulo#define ACPI_HP_METHOD_WLAN_ENABLED 1 76194701Srpaulo#define ACPI_HP_METHOD_WLAN_RADIO 2 77194701Srpaulo#define ACPI_HP_METHOD_WLAN_ON_AIR 3 78194701Srpaulo#define ACPI_HP_METHOD_WLAN_ENABLE_IF_RADIO_ON 4 79194701Srpaulo#define ACPI_HP_METHOD_WLAN_DISABLE_IF_RADIO_OFF 5 80194701Srpaulo#define ACPI_HP_METHOD_BLUETOOTH_ENABLED 6 81194701Srpaulo#define ACPI_HP_METHOD_BLUETOOTH_RADIO 7 82194701Srpaulo#define ACPI_HP_METHOD_BLUETOOTH_ON_AIR 8 83194701Srpaulo#define ACPI_HP_METHOD_BLUETOOTH_ENABLE_IF_RADIO_ON 9 84194701Srpaulo#define ACPI_HP_METHOD_BLUETOOTH_DISABLE_IF_RADIO_OFF 10 85194701Srpaulo#define ACPI_HP_METHOD_WWAN_ENABLED 11 86194701Srpaulo#define ACPI_HP_METHOD_WWAN_RADIO 12 87194701Srpaulo#define ACPI_HP_METHOD_WWAN_ON_AIR 13 88194701Srpaulo#define ACPI_HP_METHOD_WWAN_ENABLE_IF_RADIO_ON 14 89194701Srpaulo#define ACPI_HP_METHOD_WWAN_DISABLE_IF_RADIO_OFF 15 90194701Srpaulo#define ACPI_HP_METHOD_ALS 16 91194701Srpaulo#define ACPI_HP_METHOD_DISPLAY 17 92194701Srpaulo#define ACPI_HP_METHOD_HDDTEMP 18 93194701Srpaulo#define ACPI_HP_METHOD_DOCK 19 94194701Srpaulo#define ACPI_HP_METHOD_CMI_DETAIL 20 95195325Srpaulo#define ACPI_HP_METHOD_VERBOSE 21 96194701Srpaulo 97194701Srpaulo#define HP_MASK_WWAN_ON_AIR 0x1000000 98194701Srpaulo#define HP_MASK_BLUETOOTH_ON_AIR 0x10000 99194701Srpaulo#define HP_MASK_WLAN_ON_AIR 0x100 100194701Srpaulo#define HP_MASK_WWAN_RADIO 0x8000000 101194701Srpaulo#define HP_MASK_BLUETOOTH_RADIO 0x80000 102194701Srpaulo#define HP_MASK_WLAN_RADIO 0x800 103194701Srpaulo#define HP_MASK_WWAN_ENABLED 0x2000000 104194701Srpaulo#define HP_MASK_BLUETOOTH_ENABLED 0x20000 105194701Srpaulo#define HP_MASK_WLAN_ENABLED 0x200 106194701Srpaulo 107194701Srpaulo#define ACPI_HP_CMI_DETAIL_PATHS 0x01 108194701Srpaulo#define ACPI_HP_CMI_DETAIL_ENUMS 0x02 109194701Srpaulo#define ACPI_HP_CMI_DETAIL_FLAGS 0x04 110195185Srpaulo#define ACPI_HP_CMI_DETAIL_SHOW_MAX_INSTANCE 0x08 111194701Srpaulo 112194701Srpaulostruct acpi_hp_inst_seq_pair { 113194701Srpaulo UINT32 sequence; /* sequence number as suggested by cmi bios */ 114194701Srpaulo UINT8 instance; /* object instance on guid */ 115194701Srpaulo}; 116194701Srpaulo 117194701Srpaulostruct acpi_hp_softc { 118194701Srpaulo device_t dev; 119194701Srpaulo device_t wmi_dev; 120194701Srpaulo int has_notify; /* notification GUID found */ 121194701Srpaulo int has_cmi; /* CMI GUID found */ 122194701Srpaulo int cmi_detail; /* CMI detail level 123194701Srpaulo (set by sysctl) */ 124195325Srpaulo int verbose; /* add debug output */ 125194701Srpaulo int wlan_enable_if_radio_on; /* set by sysctl */ 126194701Srpaulo int wlan_disable_if_radio_off; /* set by sysctl */ 127194701Srpaulo int bluetooth_enable_if_radio_on; /* set by sysctl */ 128194701Srpaulo int bluetooth_disable_if_radio_off; /* set by sysctl */ 129194701Srpaulo int wwan_enable_if_radio_on; /* set by sysctl */ 130194701Srpaulo int wwan_disable_if_radio_off; /* set by sysctl */ 131194701Srpaulo int was_wlan_on_air; /* last known WLAN 132194701Srpaulo on air status */ 133194701Srpaulo int was_bluetooth_on_air; /* last known BT 134194701Srpaulo on air status */ 135194701Srpaulo int was_wwan_on_air; /* last known WWAN 136194701Srpaulo on air status */ 137194701Srpaulo struct sysctl_ctx_list *sysctl_ctx; 138194701Srpaulo struct sysctl_oid *sysctl_tree; 139194701Srpaulo struct cdev *hpcmi_dev_t; /* hpcmi device handle */ 140194701Srpaulo struct sbuf hpcmi_sbuf; /* /dev/hpcmi output sbuf */ 141194701Srpaulo pid_t hpcmi_open_pid; /* pid operating on 142194701Srpaulo /dev/hpcmi */ 143194701Srpaulo int hpcmi_bufptr; /* current pointer position 144194701Srpaulo in /dev/hpcmi output buffer 145194701Srpaulo */ 146194701Srpaulo int cmi_order_size; /* size of cmi_order list */ 147194701Srpaulo struct acpi_hp_inst_seq_pair cmi_order[128]; /* list of CMI 148194701Srpaulo instances ordered by BIOS suggested sequence */ 149194701Srpaulo}; 150194701Srpaulo 151194701Srpaulostatic struct { 152194701Srpaulo char *name; 153194701Srpaulo int method; 154194701Srpaulo char *description; 155194701Srpaulo int access; 156194701Srpaulo} acpi_hp_sysctls[] = { 157194701Srpaulo { 158194701Srpaulo .name = "wlan_enabled", 159194701Srpaulo .method = ACPI_HP_METHOD_WLAN_ENABLED, 160194701Srpaulo .description = "Enable/Disable WLAN (WiFi)", 161194701Srpaulo .access = CTLTYPE_INT | CTLFLAG_RW 162194701Srpaulo }, 163194701Srpaulo { 164194701Srpaulo .name = "wlan_radio", 165194701Srpaulo .method = ACPI_HP_METHOD_WLAN_RADIO, 166194701Srpaulo .description = "WLAN radio status", 167194701Srpaulo .access = CTLTYPE_INT | CTLFLAG_RD 168194701Srpaulo }, 169194701Srpaulo { 170194701Srpaulo .name = "wlan_on_air", 171194701Srpaulo .method = ACPI_HP_METHOD_WLAN_ON_AIR, 172194701Srpaulo .description = "WLAN radio ready to use (enabled and radio)", 173194701Srpaulo .access = CTLTYPE_INT | CTLFLAG_RD 174194701Srpaulo }, 175194701Srpaulo { 176194701Srpaulo .name = "wlan_enable_if_radio_on", 177194701Srpaulo .method = ACPI_HP_METHOD_WLAN_ENABLE_IF_RADIO_ON, 178194701Srpaulo .description = "Enable WLAN if radio is turned on", 179194701Srpaulo .access = CTLTYPE_INT | CTLFLAG_RW 180194701Srpaulo }, 181194701Srpaulo { 182194701Srpaulo .name = "wlan_disable_if_radio_off", 183194701Srpaulo .method = ACPI_HP_METHOD_WLAN_DISABLE_IF_RADIO_OFF, 184194701Srpaulo .description = "Disable WLAN if radio is turned off", 185194701Srpaulo .access = CTLTYPE_INT | CTLFLAG_RW 186194701Srpaulo }, 187194701Srpaulo { 188194701Srpaulo .name = "bt_enabled", 189194701Srpaulo .method = ACPI_HP_METHOD_BLUETOOTH_ENABLED, 190194701Srpaulo .description = "Enable/Disable Bluetooth", 191194701Srpaulo .access = CTLTYPE_INT | CTLFLAG_RW 192194701Srpaulo }, 193194701Srpaulo { 194194701Srpaulo .name = "bt_radio", 195194701Srpaulo .method = ACPI_HP_METHOD_BLUETOOTH_RADIO, 196194701Srpaulo .description = "Bluetooth radio status", 197194701Srpaulo .access = CTLTYPE_INT | CTLFLAG_RD 198194701Srpaulo }, 199194701Srpaulo { 200194701Srpaulo .name = "bt_on_air", 201194701Srpaulo .method = ACPI_HP_METHOD_BLUETOOTH_ON_AIR, 202194701Srpaulo .description = "Bluetooth radio ready to use" 203194701Srpaulo " (enabled and radio)", 204194701Srpaulo .access = CTLTYPE_INT | CTLFLAG_RD 205194701Srpaulo }, 206194701Srpaulo { 207194701Srpaulo .name = "bt_enable_if_radio_on", 208194701Srpaulo .method = ACPI_HP_METHOD_BLUETOOTH_ENABLE_IF_RADIO_ON, 209194701Srpaulo .description = "Enable bluetooth if radio is turned on", 210194701Srpaulo .access = CTLTYPE_INT | CTLFLAG_RW 211194701Srpaulo }, 212194701Srpaulo { 213194701Srpaulo .name = "bt_disable_if_radio_off", 214194701Srpaulo .method = ACPI_HP_METHOD_BLUETOOTH_DISABLE_IF_RADIO_OFF, 215194701Srpaulo .description = "Disable bluetooth if radio is turned off", 216194701Srpaulo .access = CTLTYPE_INT | CTLFLAG_RW 217194701Srpaulo }, 218194701Srpaulo { 219194701Srpaulo .name = "wwan_enabled", 220194701Srpaulo .method = ACPI_HP_METHOD_WWAN_ENABLED, 221194701Srpaulo .description = "Enable/Disable WWAN (UMTS)", 222194701Srpaulo .access = CTLTYPE_INT | CTLFLAG_RW 223194701Srpaulo }, 224194701Srpaulo { 225194701Srpaulo .name = "wwan_radio", 226194701Srpaulo .method = ACPI_HP_METHOD_WWAN_RADIO, 227194701Srpaulo .description = "WWAN radio status", 228194701Srpaulo .access = CTLTYPE_INT | CTLFLAG_RD 229194701Srpaulo }, 230194701Srpaulo { 231194701Srpaulo .name = "wwan_on_air", 232194701Srpaulo .method = ACPI_HP_METHOD_WWAN_ON_AIR, 233194701Srpaulo .description = "WWAN radio ready to use (enabled and radio)", 234194701Srpaulo .access = CTLTYPE_INT | CTLFLAG_RD 235194701Srpaulo }, 236194701Srpaulo { 237194701Srpaulo .name = "wwan_enable_if_radio_on", 238194701Srpaulo .method = ACPI_HP_METHOD_WWAN_ENABLE_IF_RADIO_ON, 239194701Srpaulo .description = "Enable WWAN if radio is turned on", 240194701Srpaulo .access = CTLTYPE_INT | CTLFLAG_RW 241194701Srpaulo }, 242194701Srpaulo { 243194701Srpaulo .name = "wwan_disable_if_radio_off", 244194701Srpaulo .method = ACPI_HP_METHOD_WWAN_DISABLE_IF_RADIO_OFF, 245194701Srpaulo .description = "Disable WWAN if radio is turned off", 246194701Srpaulo .access = CTLTYPE_INT | CTLFLAG_RW 247194701Srpaulo }, 248194701Srpaulo { 249194701Srpaulo .name = "als_enabled", 250194701Srpaulo .method = ACPI_HP_METHOD_ALS, 251194701Srpaulo .description = "Enable/Disable ALS (Ambient light sensor)", 252194701Srpaulo .access = CTLTYPE_INT | CTLFLAG_RW 253194701Srpaulo }, 254194701Srpaulo { 255194701Srpaulo .name = "display", 256194701Srpaulo .method = ACPI_HP_METHOD_DISPLAY, 257194701Srpaulo .description = "Display status", 258194701Srpaulo .access = CTLTYPE_INT | CTLFLAG_RD 259194701Srpaulo }, 260194701Srpaulo { 261194701Srpaulo .name = "hdd_temperature", 262194701Srpaulo .method = ACPI_HP_METHOD_HDDTEMP, 263194701Srpaulo .description = "HDD temperature", 264194701Srpaulo .access = CTLTYPE_INT | CTLFLAG_RD 265194701Srpaulo }, 266194701Srpaulo { 267194701Srpaulo .name = "is_docked", 268194701Srpaulo .method = ACPI_HP_METHOD_DOCK, 269194701Srpaulo .description = "Docking station status", 270194701Srpaulo .access = CTLTYPE_INT | CTLFLAG_RD 271194701Srpaulo }, 272194701Srpaulo { 273194701Srpaulo .name = "cmi_detail", 274194701Srpaulo .method = ACPI_HP_METHOD_CMI_DETAIL, 275194701Srpaulo .description = "Details shown in CMI output " 276194701Srpaulo "(cat /dev/hpcmi)", 277194701Srpaulo .access = CTLTYPE_INT | CTLFLAG_RW 278194701Srpaulo }, 279195325Srpaulo { 280195325Srpaulo .name = "verbose", 281195325Srpaulo .method = ACPI_HP_METHOD_VERBOSE, 282195325Srpaulo .description = "Verbosity level", 283195325Srpaulo .access = CTLTYPE_INT | CTLFLAG_RW 284195325Srpaulo }, 285194701Srpaulo 286194701Srpaulo { NULL, 0, NULL, 0 } 287194701Srpaulo}; 288194701Srpaulo 289194701SrpauloACPI_SERIAL_DECL(hp, "HP ACPI-WMI Mapping"); 290194701Srpaulo 291212251Savgstatic void acpi_hp_identify(driver_t *driver, device_t parent); 292194701Srpaulostatic int acpi_hp_probe(device_t dev); 293194701Srpaulostatic int acpi_hp_attach(device_t dev); 294194701Srpaulostatic int acpi_hp_detach(device_t dev); 295194701Srpaulo 296194701Srpaulostatic void acpi_hp_evaluate_auto_on_off(struct acpi_hp_softc* sc); 297194701Srpaulostatic int acpi_hp_sysctl(SYSCTL_HANDLER_ARGS); 298194701Srpaulostatic int acpi_hp_sysctl_set(struct acpi_hp_softc *sc, int method, 299194701Srpaulo int arg, int oldarg); 300194701Srpaulostatic int acpi_hp_sysctl_get(struct acpi_hp_softc *sc, int method); 301194701Srpaulostatic int acpi_hp_exec_wmi_command(device_t wmi_dev, int command, 302194701Srpaulo int is_write, int val); 303194701Srpaulostatic void acpi_hp_notify(ACPI_HANDLE h, UINT32 notify, void *context); 304194701Srpaulostatic int acpi_hp_get_cmi_block(device_t wmi_dev, const char* guid, 305194701Srpaulo UINT8 instance, char* outbuf, size_t outsize, 306194701Srpaulo UINT32* sequence, int detail); 307194701Srpaulostatic void acpi_hp_hex_decode(char* buffer); 308194701Srpaulo 309194701Srpaulostatic d_open_t acpi_hp_hpcmi_open; 310194701Srpaulostatic d_close_t acpi_hp_hpcmi_close; 311194701Srpaulostatic d_read_t acpi_hp_hpcmi_read; 312194701Srpaulo 313194701Srpaulo/* handler /dev/hpcmi device */ 314194701Srpaulostatic struct cdevsw hpcmi_cdevsw = { 315194701Srpaulo .d_version = D_VERSION, 316194701Srpaulo .d_open = acpi_hp_hpcmi_open, 317194701Srpaulo .d_close = acpi_hp_hpcmi_close, 318194701Srpaulo .d_read = acpi_hp_hpcmi_read, 319194701Srpaulo .d_name = "hpcmi", 320194701Srpaulo}; 321194701Srpaulo 322194701Srpaulostatic device_method_t acpi_hp_methods[] = { 323212251Savg DEVMETHOD(device_identify, acpi_hp_identify), 324194701Srpaulo DEVMETHOD(device_probe, acpi_hp_probe), 325194701Srpaulo DEVMETHOD(device_attach, acpi_hp_attach), 326194701Srpaulo DEVMETHOD(device_detach, acpi_hp_detach), 327246128Ssbz 328246128Ssbz DEVMETHOD_END 329194701Srpaulo}; 330194701Srpaulo 331194701Srpaulostatic driver_t acpi_hp_driver = { 332194701Srpaulo "acpi_hp", 333194701Srpaulo acpi_hp_methods, 334194701Srpaulo sizeof(struct acpi_hp_softc), 335194701Srpaulo}; 336194701Srpaulo 337194701Srpaulostatic devclass_t acpi_hp_devclass; 338194701Srpaulo 339212457SavgDRIVER_MODULE(acpi_hp, acpi_wmi, acpi_hp_driver, acpi_hp_devclass, 340194701Srpaulo 0, 0); 341194701SrpauloMODULE_DEPEND(acpi_hp, acpi_wmi, 1, 1, 1); 342194701SrpauloMODULE_DEPEND(acpi_hp, acpi, 1, 1, 1); 343194701Srpaulo 344194701Srpaulostatic void 345194701Srpauloacpi_hp_evaluate_auto_on_off(struct acpi_hp_softc *sc) 346194701Srpaulo{ 347195325Srpaulo int wireless; 348195325Srpaulo int new_wlan_status; 349195325Srpaulo int new_bluetooth_status; 350195325Srpaulo int new_wwan_status; 351194701Srpaulo 352194701Srpaulo wireless = acpi_hp_exec_wmi_command(sc->wmi_dev, 353194701Srpaulo ACPI_HP_WMI_WIRELESS_COMMAND, 0, 0); 354194701Srpaulo new_wlan_status = -1; 355194701Srpaulo new_bluetooth_status = -1; 356194701Srpaulo new_wwan_status = -1; 357194701Srpaulo 358195325Srpaulo if (sc->verbose) 359195325Srpaulo device_printf(sc->wmi_dev, "Wireless status is %x\n", wireless); 360194701Srpaulo if (sc->wlan_disable_if_radio_off && !(wireless & HP_MASK_WLAN_RADIO) 361194701Srpaulo && (wireless & HP_MASK_WLAN_ENABLED)) { 362194701Srpaulo acpi_hp_exec_wmi_command(sc->wmi_dev, 363194701Srpaulo ACPI_HP_WMI_WIRELESS_COMMAND, 1, 0x100); 364194701Srpaulo new_wlan_status = 0; 365194701Srpaulo } 366194701Srpaulo else if (sc->wlan_enable_if_radio_on && (wireless & HP_MASK_WLAN_RADIO) 367194701Srpaulo && !(wireless & HP_MASK_WLAN_ENABLED)) { 368194701Srpaulo acpi_hp_exec_wmi_command(sc->wmi_dev, 369194701Srpaulo ACPI_HP_WMI_WIRELESS_COMMAND, 1, 0x101); 370194701Srpaulo new_wlan_status = 1; 371194701Srpaulo } 372194701Srpaulo if (sc->bluetooth_disable_if_radio_off && 373194701Srpaulo !(wireless & HP_MASK_BLUETOOTH_RADIO) && 374194701Srpaulo (wireless & HP_MASK_BLUETOOTH_ENABLED)) { 375194701Srpaulo acpi_hp_exec_wmi_command(sc->wmi_dev, 376194701Srpaulo ACPI_HP_WMI_WIRELESS_COMMAND, 1, 0x200); 377194701Srpaulo new_bluetooth_status = 0; 378194701Srpaulo } 379194701Srpaulo else if (sc->bluetooth_enable_if_radio_on && 380194701Srpaulo (wireless & HP_MASK_BLUETOOTH_RADIO) && 381194701Srpaulo !(wireless & HP_MASK_BLUETOOTH_ENABLED)) { 382194701Srpaulo acpi_hp_exec_wmi_command(sc->wmi_dev, 383194701Srpaulo ACPI_HP_WMI_WIRELESS_COMMAND, 1, 0x202); 384194701Srpaulo new_bluetooth_status = 1; 385194701Srpaulo } 386194701Srpaulo if (sc->wwan_disable_if_radio_off && 387194701Srpaulo !(wireless & HP_MASK_WWAN_RADIO) && 388194701Srpaulo (wireless & HP_MASK_WWAN_ENABLED)) { 389194701Srpaulo acpi_hp_exec_wmi_command(sc->wmi_dev, 390194701Srpaulo ACPI_HP_WMI_WIRELESS_COMMAND, 1, 0x400); 391194701Srpaulo new_wwan_status = 0; 392194701Srpaulo } 393194701Srpaulo else if (sc->wwan_enable_if_radio_on && 394194701Srpaulo (wireless & HP_MASK_WWAN_RADIO) && 395194701Srpaulo !(wireless & HP_MASK_WWAN_ENABLED)) { 396194701Srpaulo acpi_hp_exec_wmi_command(sc->wmi_dev, 397194701Srpaulo ACPI_HP_WMI_WIRELESS_COMMAND, 1, 0x404); 398194701Srpaulo new_wwan_status = 1; 399194701Srpaulo } 400194701Srpaulo 401194701Srpaulo if (new_wlan_status == -1) { 402194701Srpaulo new_wlan_status = (wireless & HP_MASK_WLAN_ON_AIR); 403194701Srpaulo if ((new_wlan_status?1:0) != sc->was_wlan_on_air) { 404194701Srpaulo sc->was_wlan_on_air = sc->was_wlan_on_air?0:1; 405195325Srpaulo if (sc->verbose) 406195325Srpaulo device_printf(sc->wmi_dev, 407195325Srpaulo "WLAN on air changed to %i " 408195325Srpaulo "(new_wlan_status is %i)\n", 409195325Srpaulo sc->was_wlan_on_air, new_wlan_status); 410212251Savg acpi_UserNotify("HP", ACPI_ROOT_OBJECT, 411194701Srpaulo 0xc0+sc->was_wlan_on_air); 412194701Srpaulo } 413194701Srpaulo } 414194701Srpaulo if (new_bluetooth_status == -1) { 415194701Srpaulo new_bluetooth_status = (wireless & HP_MASK_BLUETOOTH_ON_AIR); 416194701Srpaulo if ((new_bluetooth_status?1:0) != sc->was_bluetooth_on_air) { 417194701Srpaulo sc->was_bluetooth_on_air = sc->was_bluetooth_on_air? 418194701Srpaulo 0:1; 419195325Srpaulo if (sc->verbose) 420195325Srpaulo device_printf(sc->wmi_dev, 421195325Srpaulo "BLUETOOTH on air changed" 422195325Srpaulo " to %i (new_bluetooth_status is %i)\n", 423195325Srpaulo sc->was_bluetooth_on_air, 424195325Srpaulo new_bluetooth_status); 425212251Savg acpi_UserNotify("HP", ACPI_ROOT_OBJECT, 426194701Srpaulo 0xd0+sc->was_bluetooth_on_air); 427194701Srpaulo } 428194701Srpaulo } 429194701Srpaulo if (new_wwan_status == -1) { 430194701Srpaulo new_wwan_status = (wireless & HP_MASK_WWAN_ON_AIR); 431194701Srpaulo if ((new_wwan_status?1:0) != sc->was_wwan_on_air) { 432194701Srpaulo sc->was_wwan_on_air = sc->was_wwan_on_air?0:1; 433195325Srpaulo if (sc->verbose) 434195325Srpaulo device_printf(sc->wmi_dev, 435195325Srpaulo "WWAN on air changed to %i" 436195325Srpaulo " (new_wwan_status is %i)\n", 437195325Srpaulo sc->was_wwan_on_air, new_wwan_status); 438212251Savg acpi_UserNotify("HP", ACPI_ROOT_OBJECT, 439194701Srpaulo 0xe0+sc->was_wwan_on_air); 440194701Srpaulo } 441194701Srpaulo } 442194701Srpaulo} 443194701Srpaulo 444212251Savgstatic void 445212251Savgacpi_hp_identify(driver_t *driver, device_t parent) 446212251Savg{ 447212251Savg 448212251Savg /* Don't do anything if driver is disabled. */ 449212251Savg if (acpi_disabled("hp")) 450212251Savg return; 451212251Savg 452212251Savg /* Add only a single device instance. */ 453212251Savg if (device_find_child(parent, "acpi_hp", -1) != NULL) 454212251Savg return; 455212251Savg 456212457Savg if (BUS_ADD_CHILD(parent, 0, "acpi_hp", -1) == NULL) 457212251Savg device_printf(parent, "add acpi_hp child failed\n"); 458212251Savg} 459212251Savg 460194701Srpaulostatic int 461194701Srpauloacpi_hp_probe(device_t dev) 462194701Srpaulo{ 463212251Savg 464194701Srpaulo device_set_desc(dev, "HP ACPI-WMI Mapping"); 465194701Srpaulo return (0); 466194701Srpaulo} 467194701Srpaulo 468194701Srpaulostatic int 469194701Srpauloacpi_hp_attach(device_t dev) 470194701Srpaulo{ 471194701Srpaulo struct acpi_hp_softc *sc; 472195325Srpaulo int arg; 473194701Srpaulo 474194701Srpaulo ACPI_FUNCTION_TRACE((char *)(uintptr_t) __func__); 475194701Srpaulo 476194701Srpaulo sc = device_get_softc(dev); 477194701Srpaulo sc->dev = dev; 478194701Srpaulo sc->has_notify = 0; 479194701Srpaulo sc->has_cmi = 0; 480194701Srpaulo sc->bluetooth_enable_if_radio_on = 0; 481194701Srpaulo sc->bluetooth_disable_if_radio_off = 0; 482194701Srpaulo sc->wlan_enable_if_radio_on = 0; 483194701Srpaulo sc->wlan_disable_if_radio_off = 0; 484194701Srpaulo sc->wlan_enable_if_radio_on = 0; 485194701Srpaulo sc->wlan_disable_if_radio_off = 0; 486194701Srpaulo sc->was_wlan_on_air = 0; 487194701Srpaulo sc->was_bluetooth_on_air = 0; 488194701Srpaulo sc->was_wwan_on_air = 0; 489194701Srpaulo sc->cmi_detail = 0; 490194701Srpaulo sc->cmi_order_size = -1; 491195325Srpaulo sc->verbose = 0; 492194701Srpaulo memset(sc->cmi_order, 0, sizeof(sc->cmi_order)); 493194701Srpaulo 494212457Savg sc->wmi_dev = device_get_parent(dev); 495194701Srpaulo if (!ACPI_WMI_PROVIDES_GUID_STRING(sc->wmi_dev, 496194701Srpaulo ACPI_HP_WMI_BIOS_GUID)) { 497194701Srpaulo device_printf(dev, 498194701Srpaulo "WMI device does not provide the HP BIOS GUID\n"); 499194701Srpaulo return (EINVAL); 500194701Srpaulo } 501194701Srpaulo if (ACPI_WMI_PROVIDES_GUID_STRING(sc->wmi_dev, 502194701Srpaulo ACPI_HP_WMI_EVENT_GUID)) { 503194701Srpaulo device_printf(dev, 504194701Srpaulo "HP event GUID detected, installing event handler\n"); 505194701Srpaulo if (ACPI_WMI_INSTALL_EVENT_HANDLER(sc->wmi_dev, 506194701Srpaulo ACPI_HP_WMI_EVENT_GUID, acpi_hp_notify, dev)) { 507194701Srpaulo device_printf(dev, 508194701Srpaulo "Could not install notification handler!\n"); 509194701Srpaulo } 510194701Srpaulo else { 511194701Srpaulo sc->has_notify = 1; 512194701Srpaulo } 513194701Srpaulo } 514195185Srpaulo if ((sc->has_cmi = 515195185Srpaulo ACPI_WMI_PROVIDES_GUID_STRING(sc->wmi_dev, ACPI_HP_WMI_CMI_GUID) 516195185Srpaulo )) { 517194701Srpaulo device_printf(dev, "HP CMI GUID detected\n"); 518194701Srpaulo } 519194701Srpaulo 520194701Srpaulo if (sc->has_cmi) { 521194701Srpaulo sc->hpcmi_dev_t = make_dev(&hpcmi_cdevsw, 0, UID_ROOT, 522194701Srpaulo GID_WHEEL, 0644, "hpcmi"); 523194701Srpaulo sc->hpcmi_dev_t->si_drv1 = sc; 524194701Srpaulo sc->hpcmi_open_pid = 0; 525194701Srpaulo sc->hpcmi_bufptr = -1; 526194701Srpaulo } 527194701Srpaulo 528194701Srpaulo ACPI_SERIAL_BEGIN(hp); 529194701Srpaulo 530194701Srpaulo sc->sysctl_ctx = device_get_sysctl_ctx(dev); 531194701Srpaulo sc->sysctl_tree = device_get_sysctl_tree(dev); 532194701Srpaulo for (int i = 0; acpi_hp_sysctls[i].name != NULL; ++i) { 533194701Srpaulo arg = 0; 534194701Srpaulo if ((!sc->has_notify && 535194701Srpaulo (acpi_hp_sysctls[i].method == 536194701Srpaulo ACPI_HP_METHOD_WLAN_ENABLE_IF_RADIO_ON || 537194701Srpaulo acpi_hp_sysctls[i].method == 538194701Srpaulo ACPI_HP_METHOD_WLAN_DISABLE_IF_RADIO_OFF || 539194701Srpaulo acpi_hp_sysctls[i].method == 540194701Srpaulo ACPI_HP_METHOD_BLUETOOTH_ENABLE_IF_RADIO_ON || 541194701Srpaulo acpi_hp_sysctls[i].method == 542194701Srpaulo ACPI_HP_METHOD_BLUETOOTH_DISABLE_IF_RADIO_OFF || 543194701Srpaulo acpi_hp_sysctls[i].method == 544194701Srpaulo ACPI_HP_METHOD_WWAN_ENABLE_IF_RADIO_ON || 545194701Srpaulo acpi_hp_sysctls[i].method == 546194701Srpaulo ACPI_HP_METHOD_WWAN_DISABLE_IF_RADIO_OFF)) || 547194701Srpaulo (arg = acpi_hp_sysctl_get(sc, 548194701Srpaulo acpi_hp_sysctls[i].method)) < 0) { 549194701Srpaulo continue; 550194701Srpaulo } 551194701Srpaulo if (acpi_hp_sysctls[i].method == ACPI_HP_METHOD_WLAN_ON_AIR) { 552194701Srpaulo sc->was_wlan_on_air = arg; 553194701Srpaulo } 554194701Srpaulo else if (acpi_hp_sysctls[i].method == 555194701Srpaulo ACPI_HP_METHOD_BLUETOOTH_ON_AIR) { 556194701Srpaulo sc->was_bluetooth_on_air = arg; 557194701Srpaulo } 558194701Srpaulo else if (acpi_hp_sysctls[i].method == 559194701Srpaulo ACPI_HP_METHOD_WWAN_ON_AIR) { 560194701Srpaulo sc->was_wwan_on_air = arg; 561194701Srpaulo } 562194701Srpaulo 563194701Srpaulo SYSCTL_ADD_PROC(sc->sysctl_ctx, 564194701Srpaulo SYSCTL_CHILDREN(sc->sysctl_tree), OID_AUTO, 565194701Srpaulo acpi_hp_sysctls[i].name, acpi_hp_sysctls[i].access, 566194701Srpaulo sc, i, acpi_hp_sysctl, "I", 567194701Srpaulo acpi_hp_sysctls[i].description); 568194701Srpaulo } 569194701Srpaulo ACPI_SERIAL_END(hp); 570194701Srpaulo 571194701Srpaulo return (0); 572194701Srpaulo} 573194701Srpaulo 574194701Srpaulostatic int 575194701Srpauloacpi_hp_detach(device_t dev) 576194701Srpaulo{ 577250053Sjhb struct acpi_hp_softc *sc; 578194701Srpaulo 579194701Srpaulo ACPI_FUNCTION_TRACE((char *)(uintptr_t) __func__); 580250053Sjhb sc = device_get_softc(dev); 581250053Sjhb if (sc->has_cmi && sc->hpcmi_open_pid != 0) 582250053Sjhb return (EBUSY); 583250053Sjhb 584250053Sjhb if (sc->has_notify) 585250053Sjhb ACPI_WMI_REMOVE_EVENT_HANDLER(dev, ACPI_HP_WMI_EVENT_GUID); 586250053Sjhb 587250053Sjhb if (sc->has_cmi) { 588194701Srpaulo if (sc->hpcmi_bufptr != -1) { 589194701Srpaulo sbuf_delete(&sc->hpcmi_sbuf); 590194701Srpaulo sc->hpcmi_bufptr = -1; 591194701Srpaulo } 592194701Srpaulo sc->hpcmi_open_pid = 0; 593194701Srpaulo destroy_dev(sc->hpcmi_dev_t); 594194701Srpaulo } 595194701Srpaulo 596250053Sjhb return (0); 597194701Srpaulo} 598194701Srpaulo 599194701Srpaulostatic int 600194701Srpauloacpi_hp_sysctl(SYSCTL_HANDLER_ARGS) 601194701Srpaulo{ 602195325Srpaulo struct acpi_hp_softc *sc; 603195325Srpaulo int arg; 604195325Srpaulo int oldarg; 605195325Srpaulo int error = 0; 606195325Srpaulo int function; 607195325Srpaulo int method; 608194701Srpaulo 609194701Srpaulo ACPI_FUNCTION_TRACE((char *)(uintptr_t)__func__); 610194701Srpaulo 611194701Srpaulo sc = (struct acpi_hp_softc *)oidp->oid_arg1; 612194701Srpaulo function = oidp->oid_arg2; 613194701Srpaulo method = acpi_hp_sysctls[function].method; 614194701Srpaulo 615194701Srpaulo ACPI_SERIAL_BEGIN(hp); 616194701Srpaulo arg = acpi_hp_sysctl_get(sc, method); 617194701Srpaulo oldarg = arg; 618194701Srpaulo error = sysctl_handle_int(oidp, &arg, 0, req); 619194701Srpaulo if (!error && req->newptr != NULL) { 620194701Srpaulo error = acpi_hp_sysctl_set(sc, method, arg, oldarg); 621194701Srpaulo } 622194701Srpaulo ACPI_SERIAL_END(hp); 623194701Srpaulo 624194701Srpaulo return (error); 625194701Srpaulo} 626194701Srpaulo 627194701Srpaulostatic int 628194701Srpauloacpi_hp_sysctl_get(struct acpi_hp_softc *sc, int method) 629194701Srpaulo{ 630195325Srpaulo int val = 0; 631194701Srpaulo 632194701Srpaulo ACPI_FUNCTION_TRACE((char *)(uintptr_t)__func__); 633194701Srpaulo ACPI_SERIAL_ASSERT(hp); 634194701Srpaulo 635194701Srpaulo switch (method) { 636194701Srpaulo case ACPI_HP_METHOD_WLAN_ENABLED: 637194701Srpaulo val = acpi_hp_exec_wmi_command(sc->wmi_dev, 638194701Srpaulo ACPI_HP_WMI_WIRELESS_COMMAND, 0, 0); 639194701Srpaulo val = ((val & HP_MASK_WLAN_ENABLED) != 0); 640194701Srpaulo break; 641194701Srpaulo case ACPI_HP_METHOD_WLAN_RADIO: 642194701Srpaulo val = acpi_hp_exec_wmi_command(sc->wmi_dev, 643194701Srpaulo ACPI_HP_WMI_WIRELESS_COMMAND, 0, 0); 644194701Srpaulo val = ((val & HP_MASK_WLAN_RADIO) != 0); 645194701Srpaulo break; 646194701Srpaulo case ACPI_HP_METHOD_WLAN_ON_AIR: 647194701Srpaulo val = acpi_hp_exec_wmi_command(sc->wmi_dev, 648194701Srpaulo ACPI_HP_WMI_WIRELESS_COMMAND, 0, 0); 649194701Srpaulo val = ((val & HP_MASK_WLAN_ON_AIR) != 0); 650194701Srpaulo break; 651194701Srpaulo case ACPI_HP_METHOD_WLAN_ENABLE_IF_RADIO_ON: 652194701Srpaulo val = sc->wlan_enable_if_radio_on; 653194701Srpaulo break; 654194701Srpaulo case ACPI_HP_METHOD_WLAN_DISABLE_IF_RADIO_OFF: 655194701Srpaulo val = sc->wlan_disable_if_radio_off; 656194701Srpaulo break; 657194701Srpaulo case ACPI_HP_METHOD_BLUETOOTH_ENABLED: 658194701Srpaulo val = acpi_hp_exec_wmi_command(sc->wmi_dev, 659194701Srpaulo ACPI_HP_WMI_WIRELESS_COMMAND, 0, 0); 660194701Srpaulo val = ((val & HP_MASK_BLUETOOTH_ENABLED) != 0); 661194701Srpaulo break; 662194701Srpaulo case ACPI_HP_METHOD_BLUETOOTH_RADIO: 663194701Srpaulo val = acpi_hp_exec_wmi_command(sc->wmi_dev, 664194701Srpaulo ACPI_HP_WMI_WIRELESS_COMMAND, 0, 0); 665194701Srpaulo val = ((val & HP_MASK_BLUETOOTH_RADIO) != 0); 666194701Srpaulo break; 667194701Srpaulo case ACPI_HP_METHOD_BLUETOOTH_ON_AIR: 668194701Srpaulo val = acpi_hp_exec_wmi_command(sc->wmi_dev, 669194701Srpaulo ACPI_HP_WMI_WIRELESS_COMMAND, 0, 0); 670194701Srpaulo val = ((val & HP_MASK_BLUETOOTH_ON_AIR) != 0); 671194701Srpaulo break; 672194701Srpaulo case ACPI_HP_METHOD_BLUETOOTH_ENABLE_IF_RADIO_ON: 673194701Srpaulo val = sc->bluetooth_enable_if_radio_on; 674194701Srpaulo break; 675194701Srpaulo case ACPI_HP_METHOD_BLUETOOTH_DISABLE_IF_RADIO_OFF: 676194701Srpaulo val = sc->bluetooth_disable_if_radio_off; 677194701Srpaulo break; 678194701Srpaulo case ACPI_HP_METHOD_WWAN_ENABLED: 679194701Srpaulo val = acpi_hp_exec_wmi_command(sc->wmi_dev, 680194701Srpaulo ACPI_HP_WMI_WIRELESS_COMMAND, 0, 0); 681194701Srpaulo val = ((val & HP_MASK_WWAN_ENABLED) != 0); 682194701Srpaulo break; 683194701Srpaulo case ACPI_HP_METHOD_WWAN_RADIO: 684194701Srpaulo val = acpi_hp_exec_wmi_command(sc->wmi_dev, 685194701Srpaulo ACPI_HP_WMI_WIRELESS_COMMAND, 0, 0); 686194701Srpaulo val = ((val & HP_MASK_WWAN_RADIO) != 0); 687194701Srpaulo break; 688194701Srpaulo case ACPI_HP_METHOD_WWAN_ON_AIR: 689194701Srpaulo val = acpi_hp_exec_wmi_command(sc->wmi_dev, 690194701Srpaulo ACPI_HP_WMI_WIRELESS_COMMAND, 0, 0); 691194701Srpaulo val = ((val & HP_MASK_WWAN_ON_AIR) != 0); 692194701Srpaulo break; 693194701Srpaulo case ACPI_HP_METHOD_WWAN_ENABLE_IF_RADIO_ON: 694194701Srpaulo val = sc->wwan_enable_if_radio_on; 695194701Srpaulo break; 696194701Srpaulo case ACPI_HP_METHOD_WWAN_DISABLE_IF_RADIO_OFF: 697194701Srpaulo val = sc->wwan_disable_if_radio_off; 698194701Srpaulo break; 699194701Srpaulo case ACPI_HP_METHOD_ALS: 700194701Srpaulo val = acpi_hp_exec_wmi_command(sc->wmi_dev, 701194701Srpaulo ACPI_HP_WMI_ALS_COMMAND, 0, 0); 702194701Srpaulo break; 703194701Srpaulo case ACPI_HP_METHOD_DISPLAY: 704194701Srpaulo val = acpi_hp_exec_wmi_command(sc->wmi_dev, 705194701Srpaulo ACPI_HP_WMI_DISPLAY_COMMAND, 0, 0); 706194701Srpaulo break; 707194701Srpaulo case ACPI_HP_METHOD_HDDTEMP: 708194701Srpaulo val = acpi_hp_exec_wmi_command(sc->wmi_dev, 709194701Srpaulo ACPI_HP_WMI_HDDTEMP_COMMAND, 0, 0); 710194701Srpaulo break; 711194701Srpaulo case ACPI_HP_METHOD_DOCK: 712194701Srpaulo val = acpi_hp_exec_wmi_command(sc->wmi_dev, 713194701Srpaulo ACPI_HP_WMI_DOCK_COMMAND, 0, 0); 714194701Srpaulo break; 715194701Srpaulo case ACPI_HP_METHOD_CMI_DETAIL: 716194701Srpaulo val = sc->cmi_detail; 717194701Srpaulo break; 718195325Srpaulo case ACPI_HP_METHOD_VERBOSE: 719195325Srpaulo val = sc->verbose; 720195325Srpaulo break; 721194701Srpaulo } 722194701Srpaulo 723194701Srpaulo return (val); 724194701Srpaulo} 725194701Srpaulo 726194701Srpaulostatic int 727194701Srpauloacpi_hp_sysctl_set(struct acpi_hp_softc *sc, int method, int arg, int oldarg) 728194701Srpaulo{ 729194701Srpaulo ACPI_FUNCTION_TRACE((char *)(uintptr_t)__func__); 730194701Srpaulo ACPI_SERIAL_ASSERT(hp); 731194701Srpaulo 732195325Srpaulo if (method != ACPI_HP_METHOD_CMI_DETAIL && 733195325Srpaulo method != ACPI_HP_METHOD_VERBOSE) 734194701Srpaulo arg = arg?1:0; 735194701Srpaulo 736194701Srpaulo if (arg != oldarg) { 737194701Srpaulo switch (method) { 738194701Srpaulo case ACPI_HP_METHOD_WLAN_ENABLED: 739194701Srpaulo return (acpi_hp_exec_wmi_command(sc->wmi_dev, 740194701Srpaulo ACPI_HP_WMI_WIRELESS_COMMAND, 1, 741194701Srpaulo arg?0x101:0x100)); 742194701Srpaulo case ACPI_HP_METHOD_WLAN_ENABLE_IF_RADIO_ON: 743194701Srpaulo sc->wlan_enable_if_radio_on = arg; 744194701Srpaulo acpi_hp_evaluate_auto_on_off(sc); 745194701Srpaulo break; 746194701Srpaulo case ACPI_HP_METHOD_WLAN_DISABLE_IF_RADIO_OFF: 747194701Srpaulo sc->wlan_disable_if_radio_off = arg; 748194701Srpaulo acpi_hp_evaluate_auto_on_off(sc); 749194701Srpaulo break; 750194701Srpaulo case ACPI_HP_METHOD_BLUETOOTH_ENABLED: 751194701Srpaulo return (acpi_hp_exec_wmi_command(sc->wmi_dev, 752194701Srpaulo ACPI_HP_WMI_WIRELESS_COMMAND, 1, 753194701Srpaulo arg?0x202:0x200)); 754194701Srpaulo case ACPI_HP_METHOD_BLUETOOTH_ENABLE_IF_RADIO_ON: 755194701Srpaulo sc->bluetooth_enable_if_radio_on = arg; 756194701Srpaulo acpi_hp_evaluate_auto_on_off(sc); 757194701Srpaulo break; 758194701Srpaulo case ACPI_HP_METHOD_BLUETOOTH_DISABLE_IF_RADIO_OFF: 759194701Srpaulo sc->bluetooth_disable_if_radio_off = arg?1:0; 760194701Srpaulo acpi_hp_evaluate_auto_on_off(sc); 761194701Srpaulo break; 762194701Srpaulo case ACPI_HP_METHOD_WWAN_ENABLED: 763194701Srpaulo return (acpi_hp_exec_wmi_command(sc->wmi_dev, 764194701Srpaulo ACPI_HP_WMI_WIRELESS_COMMAND, 1, 765194701Srpaulo arg?0x404:0x400)); 766194701Srpaulo case ACPI_HP_METHOD_WWAN_ENABLE_IF_RADIO_ON: 767194701Srpaulo sc->wwan_enable_if_radio_on = arg?1:0; 768194701Srpaulo acpi_hp_evaluate_auto_on_off(sc); 769194701Srpaulo break; 770194701Srpaulo case ACPI_HP_METHOD_WWAN_DISABLE_IF_RADIO_OFF: 771194701Srpaulo sc->wwan_disable_if_radio_off = arg?1:0; 772194701Srpaulo acpi_hp_evaluate_auto_on_off(sc); 773194701Srpaulo break; 774194701Srpaulo case ACPI_HP_METHOD_ALS: 775194701Srpaulo return (acpi_hp_exec_wmi_command(sc->wmi_dev, 776194701Srpaulo ACPI_HP_WMI_ALS_COMMAND, 1, 777194701Srpaulo arg?1:0)); 778194701Srpaulo case ACPI_HP_METHOD_CMI_DETAIL: 779194701Srpaulo sc->cmi_detail = arg; 780195185Srpaulo if ((arg & ACPI_HP_CMI_DETAIL_SHOW_MAX_INSTANCE) != 781195185Srpaulo (oldarg & ACPI_HP_CMI_DETAIL_SHOW_MAX_INSTANCE)) { 782195185Srpaulo sc->cmi_order_size = -1; 783195185Srpaulo } 784194701Srpaulo break; 785195325Srpaulo case ACPI_HP_METHOD_VERBOSE: 786195325Srpaulo sc->verbose = arg; 787195325Srpaulo break; 788194701Srpaulo } 789194701Srpaulo } 790194701Srpaulo 791194701Srpaulo return (0); 792194701Srpaulo} 793194701Srpaulo 794194701Srpaulostatic __inline void 795194701Srpauloacpi_hp_free_buffer(ACPI_BUFFER* buf) { 796194701Srpaulo if (buf && buf->Pointer) { 797194701Srpaulo AcpiOsFree(buf->Pointer); 798194701Srpaulo } 799194701Srpaulo} 800194701Srpaulo 801194701Srpaulostatic void 802194701Srpauloacpi_hp_notify(ACPI_HANDLE h, UINT32 notify, void *context) 803194701Srpaulo{ 804194701Srpaulo device_t dev = context; 805194701Srpaulo ACPI_FUNCTION_TRACE_U32((char *)(uintptr_t)__func__, notify); 806194701Srpaulo 807194701Srpaulo struct acpi_hp_softc *sc = device_get_softc(dev); 808194701Srpaulo ACPI_BUFFER response = { ACPI_ALLOCATE_BUFFER, NULL }; 809194701Srpaulo ACPI_OBJECT *obj; 810194701Srpaulo ACPI_WMI_GET_EVENT_DATA(sc->wmi_dev, notify, &response); 811194701Srpaulo obj = (ACPI_OBJECT*) response.Pointer; 812194701Srpaulo if (obj && obj->Type == ACPI_TYPE_BUFFER && obj->Buffer.Length == 8) { 813194701Srpaulo if (*((UINT8 *) obj->Buffer.Pointer) == 0x5) { 814194701Srpaulo acpi_hp_evaluate_auto_on_off(sc); 815194701Srpaulo } 816194701Srpaulo } 817194701Srpaulo acpi_hp_free_buffer(&response); 818194701Srpaulo} 819194701Srpaulo 820194701Srpaulostatic int 821194701Srpauloacpi_hp_exec_wmi_command(device_t wmi_dev, int command, int is_write, int val) 822194701Srpaulo{ 823195325Srpaulo UINT32 params[5] = { 0x55434553, 824195325Srpaulo is_write?2:1, 825195325Srpaulo command, 826195325Srpaulo is_write?4:0, 827195325Srpaulo val}; 828195325Srpaulo UINT32* result; 829195325Srpaulo ACPI_OBJECT *obj; 830195325Srpaulo ACPI_BUFFER in = { sizeof(params), ¶ms }; 831195325Srpaulo ACPI_BUFFER out = { ACPI_ALLOCATE_BUFFER, NULL }; 832194701Srpaulo int retval; 833194701Srpaulo 834194701Srpaulo if (ACPI_FAILURE(ACPI_WMI_EVALUATE_CALL(wmi_dev, ACPI_HP_WMI_BIOS_GUID, 835194701Srpaulo 0, 0x3, &in, &out))) { 836194701Srpaulo acpi_hp_free_buffer(&out); 837194701Srpaulo return (-EINVAL); 838194701Srpaulo } 839194701Srpaulo obj = out.Pointer; 840194701Srpaulo if (!obj || obj->Type != ACPI_TYPE_BUFFER) { 841194701Srpaulo acpi_hp_free_buffer(&out); 842194701Srpaulo return (-EINVAL); 843194701Srpaulo } 844194701Srpaulo result = (UINT32*) obj->Buffer.Pointer; 845194701Srpaulo retval = result[2]; 846194701Srpaulo if (result[1] > 0) { 847194701Srpaulo retval = result[1]; 848194701Srpaulo } 849194701Srpaulo acpi_hp_free_buffer(&out); 850194701Srpaulo 851194701Srpaulo return (retval); 852194701Srpaulo} 853194701Srpaulo 854194701Srpaulostatic __inline char* 855194701Srpauloacpi_hp_get_string_from_object(ACPI_OBJECT* obj, char* dst, size_t size) { 856195325Srpaulo int length; 857195325Srpaulo 858194701Srpaulo dst[0] = 0; 859194701Srpaulo if (obj->Type == ACPI_TYPE_STRING) { 860194701Srpaulo length = obj->String.Length+1; 861194701Srpaulo if (length > size) { 862194701Srpaulo length = size - 1; 863194701Srpaulo } 864194701Srpaulo strlcpy(dst, obj->String.Pointer, length); 865194701Srpaulo acpi_hp_hex_decode(dst); 866194701Srpaulo } 867194701Srpaulo 868194701Srpaulo return (dst); 869194701Srpaulo} 870194701Srpaulo 871194701Srpaulo 872194701Srpaulo/* 873194701Srpaulo * Read BIOS Setting block in instance "instance". 874194701Srpaulo * The block returned is ACPI_TYPE_PACKAGE which should contain the following 875194701Srpaulo * elements: 876194701Srpaulo * Index Meaning 877195325Srpaulo * 0 Setting Name [string] 878195325Srpaulo * 1 Value (comma separated, asterisk marks the current value) [string] 879195325Srpaulo * 2 Path within the bios hierarchy [string] 880195325Srpaulo * 3 IsReadOnly [int] 881195325Srpaulo * 4 DisplayInUI [int] 882195325Srpaulo * 5 RequiresPhysicalPresence [int] 883195325Srpaulo * 6 Sequence for ordering within the bios settings (absolute) [int] 884195325Srpaulo * 7 Length of prerequisites array [int] 885195325Srpaulo * 8..8+[7] PrerequisiteN [string] 886195325Srpaulo * 9+[7] Current value (in case of enum) [string] / Array length [int] 887195325Srpaulo * 10+[7] Enum length [int] / Array values 888195325Srpaulo * 11+[7]ff Enum value at index x [string] 889194701Srpaulo */ 890194701Srpaulostatic int 891194701Srpauloacpi_hp_get_cmi_block(device_t wmi_dev, const char* guid, UINT8 instance, 892194701Srpaulo char* outbuf, size_t outsize, UINT32* sequence, int detail) 893194701Srpaulo{ 894195325Srpaulo ACPI_OBJECT *obj; 895195325Srpaulo ACPI_BUFFER out = { ACPI_ALLOCATE_BUFFER, NULL }; 896195325Srpaulo int i; 897195325Srpaulo int outlen; 898195325Srpaulo int size = 255; 899195325Srpaulo int has_enums = 0; 900195325Srpaulo int valuebase = 0; 901195325Srpaulo char string_buffer[size]; 902195325Srpaulo int enumbase; 903194701Srpaulo 904194701Srpaulo outlen = 0; 905194701Srpaulo outbuf[0] = 0; 906194701Srpaulo if (ACPI_FAILURE(ACPI_WMI_GET_BLOCK(wmi_dev, guid, instance, &out))) { 907194701Srpaulo acpi_hp_free_buffer(&out); 908194701Srpaulo return (-EINVAL); 909194701Srpaulo } 910194701Srpaulo obj = out.Pointer; 911209055Sjkim if (!obj || obj->Type != ACPI_TYPE_PACKAGE) { 912194701Srpaulo acpi_hp_free_buffer(&out); 913194701Srpaulo return (-EINVAL); 914194701Srpaulo } 915194701Srpaulo 916195325Srpaulo if (obj->Package.Count >= 8 && 917195325Srpaulo obj->Package.Elements[7].Type == ACPI_TYPE_INTEGER) { 918195325Srpaulo valuebase = 8 + obj->Package.Elements[7].Integer.Value; 919195325Srpaulo } 920195325Srpaulo 921194701Srpaulo /* check if this matches our expectations based on limited knowledge */ 922195325Srpaulo if (valuebase > 7 && obj->Package.Count > valuebase + 1 && 923194701Srpaulo obj->Package.Elements[0].Type == ACPI_TYPE_STRING && 924194701Srpaulo obj->Package.Elements[1].Type == ACPI_TYPE_STRING && 925194701Srpaulo obj->Package.Elements[2].Type == ACPI_TYPE_STRING && 926194701Srpaulo obj->Package.Elements[3].Type == ACPI_TYPE_INTEGER && 927194701Srpaulo obj->Package.Elements[4].Type == ACPI_TYPE_INTEGER && 928194701Srpaulo obj->Package.Elements[5].Type == ACPI_TYPE_INTEGER && 929194701Srpaulo obj->Package.Elements[6].Type == ACPI_TYPE_INTEGER && 930195325Srpaulo obj->Package.Elements[valuebase].Type == ACPI_TYPE_STRING && 931195325Srpaulo obj->Package.Elements[valuebase+1].Type == ACPI_TYPE_INTEGER && 932195325Srpaulo obj->Package.Count > valuebase + 933195325Srpaulo obj->Package.Elements[valuebase+1].Integer.Value 934195325Srpaulo ) { 935195325Srpaulo enumbase = valuebase + 1; 936194701Srpaulo if (detail & ACPI_HP_CMI_DETAIL_PATHS) { 937194701Srpaulo strlcat(outbuf, acpi_hp_get_string_from_object( 938194701Srpaulo &obj->Package.Elements[2], string_buffer, size), 939194701Srpaulo outsize); 940194701Srpaulo outlen += 48; 941194701Srpaulo while (strlen(outbuf) < outlen) 942194701Srpaulo strlcat(outbuf, " ", outsize); 943194701Srpaulo } 944194701Srpaulo strlcat(outbuf, acpi_hp_get_string_from_object( 945194701Srpaulo &obj->Package.Elements[0], string_buffer, size), 946194701Srpaulo outsize); 947194701Srpaulo outlen += 43; 948194701Srpaulo while (strlen(outbuf) < outlen) 949194701Srpaulo strlcat(outbuf, " ", outsize); 950195325Srpaulo strlcat(outbuf, acpi_hp_get_string_from_object( 951195325Srpaulo &obj->Package.Elements[valuebase], string_buffer, 952195325Srpaulo size), 953195325Srpaulo outsize); 954194701Srpaulo outlen += 21; 955194701Srpaulo while (strlen(outbuf) < outlen) 956194701Srpaulo strlcat(outbuf, " ", outsize); 957194701Srpaulo for (i = 0; i < strlen(outbuf); ++i) 958194701Srpaulo if (outbuf[i] == '\\') 959194701Srpaulo outbuf[i] = '/'; 960194701Srpaulo if (detail & ACPI_HP_CMI_DETAIL_ENUMS) { 961195325Srpaulo for (i = enumbase + 1; i < enumbase + 1 + 962194701Srpaulo obj->Package.Elements[enumbase].Integer.Value; 963194701Srpaulo ++i) { 964194701Srpaulo acpi_hp_get_string_from_object( 965194701Srpaulo &obj->Package.Elements[i], string_buffer, 966194701Srpaulo size); 967194701Srpaulo if (strlen(string_buffer) > 1 || 968194701Srpaulo (strlen(string_buffer) == 1 && 969194701Srpaulo string_buffer[0] != ' ')) { 970194701Srpaulo if (has_enums) 971194701Srpaulo strlcat(outbuf, "/", outsize); 972194701Srpaulo else 973194701Srpaulo strlcat(outbuf, " (", outsize); 974194701Srpaulo strlcat(outbuf, string_buffer, outsize); 975194701Srpaulo has_enums = 1; 976194701Srpaulo } 977194701Srpaulo } 978194701Srpaulo } 979194701Srpaulo if (has_enums) 980194701Srpaulo strlcat(outbuf, ")", outsize); 981194701Srpaulo if (detail & ACPI_HP_CMI_DETAIL_FLAGS) { 982194701Srpaulo strlcat(outbuf, obj->Package.Elements[3].Integer.Value? 983194701Srpaulo " [ReadOnly]":"", outsize); 984194701Srpaulo strlcat(outbuf, obj->Package.Elements[4].Integer.Value? 985194701Srpaulo "":" [NOUI]", outsize); 986194701Srpaulo strlcat(outbuf, obj->Package.Elements[5].Integer.Value? 987194701Srpaulo " [RPP]":"", outsize); 988194701Srpaulo } 989194701Srpaulo *sequence = (UINT32) obj->Package.Elements[6].Integer.Value; 990194701Srpaulo } 991194701Srpaulo acpi_hp_free_buffer(&out); 992194701Srpaulo 993194701Srpaulo return (0); 994194701Srpaulo} 995194701Srpaulo 996194701Srpaulo 997194701Srpaulo 998194701Srpaulo/* 999194701Srpaulo * Convert given two digit hex string (hexin) to an UINT8 referenced 1000194701Srpaulo * by byteout. 1001194701Srpaulo * Return != 0 if the was a problem (invalid input) 1002194701Srpaulo */ 1003194701Srpaulostatic __inline int acpi_hp_hex_to_int(const UINT8 *hexin, UINT8 *byteout) 1004194701Srpaulo{ 1005195325Srpaulo unsigned int hi; 1006195325Srpaulo unsigned int lo; 1007194701Srpaulo 1008194701Srpaulo hi = hexin[0]; 1009194701Srpaulo lo = hexin[1]; 1010194701Srpaulo if ('0' <= hi && hi <= '9') 1011194701Srpaulo hi -= '0'; 1012194701Srpaulo else if ('A' <= hi && hi <= 'F') 1013194701Srpaulo hi -= ('A' - 10); 1014194701Srpaulo else if ('a' <= hi && hi <= 'f') 1015194701Srpaulo hi -= ('a' - 10); 1016194701Srpaulo else 1017194701Srpaulo return (1); 1018194701Srpaulo if ('0' <= lo && lo <= '9') 1019194701Srpaulo lo -= '0'; 1020194701Srpaulo else if ('A' <= lo && lo <= 'F') 1021194701Srpaulo lo -= ('A' - 10); 1022194701Srpaulo else if ('a' <= lo && lo <= 'f') 1023194701Srpaulo lo -= ('a' - 10); 1024194701Srpaulo else 1025194701Srpaulo return (1); 1026194701Srpaulo *byteout = (hi << 4) + lo; 1027194701Srpaulo 1028194701Srpaulo return (0); 1029194701Srpaulo} 1030194701Srpaulo 1031194701Srpaulo 1032194701Srpaulostatic void 1033194701Srpauloacpi_hp_hex_decode(char* buffer) 1034194701Srpaulo{ 1035195325Srpaulo int i; 1036195325Srpaulo int length = strlen(buffer); 1037195325Srpaulo UINT8 *uin; 1038195325Srpaulo UINT8 uout; 1039194701Srpaulo 1040194701Srpaulo if (((int)length/2)*2 == length || length < 10) return; 1041194701Srpaulo 1042194701Srpaulo for (i = 0; i<length; ++i) { 1043194701Srpaulo if (!((i+1)%3)) { 1044194701Srpaulo if (buffer[i] != ' ') 1045194701Srpaulo return; 1046194701Srpaulo } 1047194701Srpaulo else 1048194701Srpaulo if (!((buffer[i] >= '0' && buffer[i] <= '9') || 1049194701Srpaulo (buffer[i] >= 'A' && buffer[i] <= 'F'))) 1050194701Srpaulo return; 1051194701Srpaulo } 1052194701Srpaulo 1053194701Srpaulo for (i = 0; i<length; i += 3) { 1054194701Srpaulo uin = &buffer[i]; 1055194701Srpaulo uout = 0; 1056194701Srpaulo acpi_hp_hex_to_int(uin, &uout); 1057194701Srpaulo buffer[i/3] = (char) uout; 1058194701Srpaulo } 1059194701Srpaulo buffer[(length+1)/3] = 0; 1060194701Srpaulo} 1061194701Srpaulo 1062194701Srpaulo 1063194701Srpaulo/* 1064194701Srpaulo * open hpcmi device 1065194701Srpaulo */ 1066194701Srpaulostatic int 1067194701Srpauloacpi_hp_hpcmi_open(struct cdev* dev, int flags, int mode, struct thread *td) 1068194701Srpaulo{ 1069195325Srpaulo struct acpi_hp_softc *sc; 1070195325Srpaulo int ret; 1071194701Srpaulo 1072194701Srpaulo if (dev == NULL || dev->si_drv1 == NULL) 1073194701Srpaulo return (EBADF); 1074194701Srpaulo sc = dev->si_drv1; 1075194701Srpaulo 1076194701Srpaulo ACPI_SERIAL_BEGIN(hp); 1077194701Srpaulo if (sc->hpcmi_open_pid != 0) { 1078194701Srpaulo ret = EBUSY; 1079194701Srpaulo } 1080194701Srpaulo else { 1081194701Srpaulo if (sbuf_new(&sc->hpcmi_sbuf, NULL, 4096, SBUF_AUTOEXTEND) 1082194701Srpaulo == NULL) { 1083194701Srpaulo ret = ENXIO; 1084194701Srpaulo } else { 1085194701Srpaulo sc->hpcmi_open_pid = td->td_proc->p_pid; 1086194701Srpaulo sc->hpcmi_bufptr = 0; 1087194701Srpaulo ret = 0; 1088194701Srpaulo } 1089194701Srpaulo } 1090194701Srpaulo ACPI_SERIAL_END(hp); 1091194701Srpaulo 1092194701Srpaulo return (ret); 1093194701Srpaulo} 1094194701Srpaulo 1095194701Srpaulo/* 1096194701Srpaulo * close hpcmi device 1097194701Srpaulo */ 1098194701Srpaulostatic int 1099194701Srpauloacpi_hp_hpcmi_close(struct cdev* dev, int flags, int mode, struct thread *td) 1100194701Srpaulo{ 1101195325Srpaulo struct acpi_hp_softc *sc; 1102195325Srpaulo int ret; 1103194701Srpaulo 1104194701Srpaulo if (dev == NULL || dev->si_drv1 == NULL) 1105194701Srpaulo return (EBADF); 1106194701Srpaulo sc = dev->si_drv1; 1107194701Srpaulo 1108194701Srpaulo ACPI_SERIAL_BEGIN(hp); 1109194701Srpaulo if (sc->hpcmi_open_pid == 0) { 1110194701Srpaulo ret = EBADF; 1111194701Srpaulo } 1112194701Srpaulo else { 1113194701Srpaulo if (sc->hpcmi_bufptr != -1) { 1114194701Srpaulo sbuf_delete(&sc->hpcmi_sbuf); 1115194701Srpaulo sc->hpcmi_bufptr = -1; 1116194701Srpaulo } 1117194701Srpaulo sc->hpcmi_open_pid = 0; 1118194701Srpaulo ret = 0; 1119194701Srpaulo } 1120194701Srpaulo ACPI_SERIAL_END(hp); 1121194701Srpaulo 1122194701Srpaulo return (ret); 1123194701Srpaulo} 1124194701Srpaulo 1125194701Srpaulo/* 1126194701Srpaulo * Read from hpcmi bios information 1127194701Srpaulo */ 1128194701Srpaulostatic int 1129194701Srpauloacpi_hp_hpcmi_read(struct cdev *dev, struct uio *buf, int flag) 1130194701Srpaulo{ 1131195325Srpaulo struct acpi_hp_softc *sc; 1132195325Srpaulo int pos, i, l, ret; 1133195325Srpaulo UINT8 instance; 1134195325Srpaulo UINT8 maxInstance; 1135195325Srpaulo UINT32 sequence; 1136195325Srpaulo int linesize = 1025; 1137195325Srpaulo char line[linesize]; 1138194701Srpaulo 1139194701Srpaulo if (dev == NULL || dev->si_drv1 == NULL) 1140194701Srpaulo return (EBADF); 1141194701Srpaulo sc = dev->si_drv1; 1142194701Srpaulo 1143194701Srpaulo ACPI_SERIAL_BEGIN(hp); 1144194701Srpaulo if (sc->hpcmi_open_pid != buf->uio_td->td_proc->p_pid 1145194701Srpaulo || sc->hpcmi_bufptr == -1) { 1146194701Srpaulo ret = EBADF; 1147194701Srpaulo } 1148194701Srpaulo else { 1149194701Srpaulo if (!sbuf_done(&sc->hpcmi_sbuf)) { 1150194701Srpaulo if (sc->cmi_order_size < 0) { 1151195185Srpaulo maxInstance = sc->has_cmi; 1152195185Srpaulo if (!(sc->cmi_detail & 1153195185Srpaulo ACPI_HP_CMI_DETAIL_SHOW_MAX_INSTANCE) && 1154195185Srpaulo maxInstance > 0) { 1155195185Srpaulo maxInstance--; 1156195185Srpaulo } 1157194701Srpaulo sc->cmi_order_size = 0; 1158195185Srpaulo for (instance = 0; instance < maxInstance; 1159194701Srpaulo ++instance) { 1160194701Srpaulo if (acpi_hp_get_cmi_block(sc->wmi_dev, 1161194701Srpaulo ACPI_HP_WMI_CMI_GUID, instance, 1162194701Srpaulo line, linesize, &sequence, 1163194701Srpaulo sc->cmi_detail)) { 1164195185Srpaulo instance = maxInstance; 1165194701Srpaulo } 1166194701Srpaulo else { 1167194701Srpaulo pos = sc->cmi_order_size; 1168194701Srpaulo for (i=0; 1169194701Srpaulo i<sc->cmi_order_size && i<127; 1170194701Srpaulo ++i) { 1171194701Srpaulo if (sc->cmi_order[i].sequence > sequence) { 1172194701Srpaulo pos = i; 1173194701Srpaulo break; 1174194701Srpaulo } 1175194701Srpaulo } 1176194701Srpaulo for (i=sc->cmi_order_size; 1177194701Srpaulo i>pos; 1178194701Srpaulo --i) { 1179194701Srpaulo sc->cmi_order[i].sequence = 1180194701Srpaulo sc->cmi_order[i-1].sequence; 1181194701Srpaulo sc->cmi_order[i].instance = 1182194701Srpaulo sc->cmi_order[i-1].instance; 1183194701Srpaulo } 1184194701Srpaulo sc->cmi_order[pos].sequence = 1185194701Srpaulo sequence; 1186194701Srpaulo sc->cmi_order[pos].instance = 1187194701Srpaulo instance; 1188194701Srpaulo sc->cmi_order_size++; 1189194701Srpaulo } 1190194701Srpaulo } 1191194701Srpaulo } 1192194701Srpaulo for (i=0; i<sc->cmi_order_size; ++i) { 1193194701Srpaulo if (!acpi_hp_get_cmi_block(sc->wmi_dev, 1194194701Srpaulo ACPI_HP_WMI_CMI_GUID, 1195194701Srpaulo sc->cmi_order[i].instance, line, linesize, 1196194701Srpaulo &sequence, sc->cmi_detail)) { 1197194701Srpaulo sbuf_printf(&sc->hpcmi_sbuf, "%s\n", line); 1198194701Srpaulo } 1199194701Srpaulo } 1200194701Srpaulo sbuf_finish(&sc->hpcmi_sbuf); 1201194701Srpaulo } 1202194701Srpaulo if (sbuf_len(&sc->hpcmi_sbuf) <= 0) { 1203194701Srpaulo sbuf_delete(&sc->hpcmi_sbuf); 1204194701Srpaulo sc->hpcmi_bufptr = -1; 1205194701Srpaulo sc->hpcmi_open_pid = 0; 1206194701Srpaulo ret = ENOMEM; 1207194701Srpaulo } else { 1208194701Srpaulo l = min(buf->uio_resid, sbuf_len(&sc->hpcmi_sbuf) - 1209194701Srpaulo sc->hpcmi_bufptr); 1210194701Srpaulo ret = (l > 0)?uiomove(sbuf_data(&sc->hpcmi_sbuf) + 1211194701Srpaulo sc->hpcmi_bufptr, l, buf) : 0; 1212194701Srpaulo sc->hpcmi_bufptr += l; 1213194701Srpaulo } 1214194701Srpaulo } 1215194701Srpaulo ACPI_SERIAL_END(hp); 1216194701Srpaulo 1217194701Srpaulo return (ret); 1218194701Srpaulo} 1219