xref: /illumos-gate/usr/src/uts/i86pc/io/acpi_drv/acpi_drv.c (revision ce17336ed725d3b7fdff67bf0a0ee2b55018fec6)
1d2ec54f7Sphitran /*
2d2ec54f7Sphitran  * CDDL HEADER START
3d2ec54f7Sphitran  *
4d2ec54f7Sphitran  * The contents of this file are subject to the terms of the
5d2ec54f7Sphitran  * Common Development and Distribution License (the "License").
6d2ec54f7Sphitran  * You may not use this file except in compliance with the License.
7d2ec54f7Sphitran  *
8d2ec54f7Sphitran  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9d2ec54f7Sphitran  * or http://www.opensolaris.org/os/licensing.
10d2ec54f7Sphitran  * See the License for the specific language governing permissions
11d2ec54f7Sphitran  * and limitations under the License.
12d2ec54f7Sphitran  *
13d2ec54f7Sphitran  * When distributing Covered Code, include this CDDL HEADER in each
14d2ec54f7Sphitran  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15d2ec54f7Sphitran  * If applicable, add the following below this CDDL HEADER, with the
16d2ec54f7Sphitran  * fields enclosed by brackets "[]" replaced with your own identifying
17d2ec54f7Sphitran  * information: Portions Copyright [yyyy] [name of copyright owner]
18d2ec54f7Sphitran  *
19d2ec54f7Sphitran  * CDDL HEADER END
20d2ec54f7Sphitran  */
21d2ec54f7Sphitran 
22d2ec54f7Sphitran /*
232d6b5ea7SGuoli Shu  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
24d2ec54f7Sphitran  * Use is subject to license terms.
25d2ec54f7Sphitran  */
2628b6fd27SHans Rosenfeld /*
2728b6fd27SHans Rosenfeld  * Copyright 2015 Hans Rosenfeld <rosenfeld@grumpf.hope-2000.org>
2828b6fd27SHans Rosenfeld  */
29d2ec54f7Sphitran 
30d2ec54f7Sphitran /*
312d6b5ea7SGuoli Shu  * Driver for ACPI Battery, Lid, and Hotkey Control
32d2ec54f7Sphitran  */
332d6b5ea7SGuoli Shu #include <sys/hotkey_drv.h>
34d2ec54f7Sphitran #include <sys/sysevent/pwrctl.h>
35d2ec54f7Sphitran 
36d2ec54f7Sphitran 
37d2ec54f7Sphitran #define	ACPI_DRV_MOD_STRING		"ACPI driver"
38d2ec54f7Sphitran 
39d2ec54f7Sphitran #define	ACPI_DRV_MAX_BAT_NUM		8
40d2ec54f7Sphitran #define	ACPI_DRV_MAX_AC_NUM		10
41d2ec54f7Sphitran 
42d2ec54f7Sphitran #define	BST_FLAG_DISCHARGING		(0x1)
43d2ec54f7Sphitran #define	BST_FLAG_CHARGING		(0x2)
44d2ec54f7Sphitran #define	BST_FLAG_CRITICAL		(0x4)
45d2ec54f7Sphitran 
46d2ec54f7Sphitran /* Set if the battery is present */
47d2ec54f7Sphitran #define	STA_FLAG_BATT_PRESENT		(0x10)
48d2ec54f7Sphitran 
49d2ec54f7Sphitran #define	ACPI_DEVNAME_CBAT		"PNP0C0A"
50d2ec54f7Sphitran #define	ACPI_DEVNAME_AC			"ACPI0003"
51d2ec54f7Sphitran #define	ACPI_DEVNAME_LID		"PNP0C0D"
52d2ec54f7Sphitran 
53d2ec54f7Sphitran #define	ACPI_DRV_EVENTS			(POLLIN | POLLRDNORM)
54d2ec54f7Sphitran 
55d2ec54f7Sphitran #ifdef DEBUG
56d2ec54f7Sphitran 
57d2ec54f7Sphitran #define	ACPI_DRV_PRINT_BUFFER_SIZE	512
58d2ec54f7Sphitran static char acpi_drv_prt_buf[ACPI_DRV_PRINT_BUFFER_SIZE];
59d2ec54f7Sphitran static kmutex_t acpi_drv_prt_mutex;
60d2ec54f7Sphitran 
61d2ec54f7Sphitran static int acpi_drv_debug = 0;
62d2ec54f7Sphitran #define	ACPI_DRV_DBG(lev, devp, ...) \
63d2ec54f7Sphitran 	do { \
64d2ec54f7Sphitran 		if (acpi_drv_debug) acpi_drv_printf((devp), \
65d2ec54f7Sphitran (lev), __VA_ARGS__); \
66d2ec54f7Sphitran _NOTE(CONSTCOND) } while (0)
67d2ec54f7Sphitran #define	ACPI_DRV_PRT_NOTIFY(hdl, val) \
68d2ec54f7Sphitran 	do { \
69d2ec54f7Sphitran 		if (acpi_drv_debug) acpi_drv_prt_notify((hdl), (val)); \
70d2ec54f7Sphitran _NOTE(CONSTCOND) } while (0)
71d2ec54f7Sphitran 
72d2ec54f7Sphitran #else
73d2ec54f7Sphitran 
74d2ec54f7Sphitran #define	ACPI_DRV_DBG(lev, devp, ...)
75d2ec54f7Sphitran #define	ACPI_DRV_PRT_NOTIFY(hdl, val)
76d2ec54f7Sphitran 
77d2ec54f7Sphitran #endif /* DEBUG */
78d2ec54f7Sphitran 
79d2ec54f7Sphitran /* ACPI notify types */
80d2ec54f7Sphitran enum acpi_drv_notify {
81d2ec54f7Sphitran 	ACPI_DRV_NTF_UNKNOWN = -1,	/* No notifications seen, ever. */
82d2ec54f7Sphitran 	ACPI_DRV_NTF_CHANGED,
83d2ec54f7Sphitran 	ACPI_DRV_NTF_OK
84d2ec54f7Sphitran };
85d2ec54f7Sphitran 
86d2ec54f7Sphitran static int acpi_drv_dev_present(struct acpi_drv_dev *);
87d2ec54f7Sphitran #define	acpi_drv_ac_present(a)	(((a)->dev.type == ACPI_DRV_TYPE_AC) ? \
88d2ec54f7Sphitran 				acpi_drv_dev_present(&(a)->dev) : -1)
89d2ec54f7Sphitran #define	acpi_drv_cbat_present(a)	(((a)->dev.type == ACPI_DRV_TYPE_CBAT) \
90d2ec54f7Sphitran 					? acpi_drv_dev_present(&(a)->dev) : -1)
91d2ec54f7Sphitran 
92d2ec54f7Sphitran static dev_info_t *acpi_drv_dip = NULL;
93d2ec54f7Sphitran static kmutex_t acpi_drv_mutex;
94d2ec54f7Sphitran static struct pollhead acpi_drv_pollhead;
9528b6fd27SHans Rosenfeld static timeout_id_t acpi_drv_cbat_rescan_timeout;
96d2ec54f7Sphitran 
97d2ec54f7Sphitran /* Control Method Battery state */
98d2ec54f7Sphitran struct acpi_drv_cbat_state {
99d2ec54f7Sphitran 	struct acpi_drv_dev dev;
100d2ec54f7Sphitran 	/* Caches of _BST and _BIF */
101d2ec54f7Sphitran 	enum acpi_drv_notify bat_bifok;
102d2ec54f7Sphitran 	acpi_bif_t bif_cache;
103d2ec54f7Sphitran 	enum acpi_drv_notify bat_bstok;
104d2ec54f7Sphitran 	acpi_bst_t bst_cache;
105d2ec54f7Sphitran 
106d2ec54f7Sphitran 	uint32_t charge_warn;
107d2ec54f7Sphitran 	uint32_t charge_low;
108d2ec54f7Sphitran 
109d2ec54f7Sphitran 	kstat_t *bat_bif_ksp;
110d2ec54f7Sphitran 	kstat_t *bat_bst_ksp;
111d2ec54f7Sphitran } acpi_drv_cbat[ACPI_DRV_MAX_BAT_NUM];
112630ff078Sphitran static int nbat = 0;
113d2ec54f7Sphitran 
114d2ec54f7Sphitran /*
115d2ec54f7Sphitran  * Synthesis battery state
116d2ec54f7Sphitran  * When there are multiple batteries present, the battery subsystem
117d2ec54f7Sphitran  * is not required to perform any synthesis of a composite battery
118d2ec54f7Sphitran  * from the data of the separate batteries. In cases where the
119d2ec54f7Sphitran  * battery subsystem does not synthesize a composite battery from
120d2ec54f7Sphitran  * the separate battery's data, the OS must provide that synthesis.
121d2ec54f7Sphitran  */
122d2ec54f7Sphitran static uint32_t acpi_drv_syn_rem_cap;
123d2ec54f7Sphitran static uint32_t acpi_drv_syn_last_cap;
124d2ec54f7Sphitran static uint32_t acpi_drv_syn_oem_warn_cap;
125d2ec54f7Sphitran static uint32_t acpi_drv_syn_oem_low_cap;
126d2ec54f7Sphitran 
127d2ec54f7Sphitran static int acpi_drv_warn_enabled;
128d2ec54f7Sphitran static uint32_t acpi_drv_syn_warn_per;
129d2ec54f7Sphitran static uint32_t acpi_drv_syn_low_per;
130d2ec54f7Sphitran static uint32_t acpi_drv_syn_warn_cap;
131d2ec54f7Sphitran static uint32_t acpi_drv_syn_low_cap;
132d2ec54f7Sphitran /* Tracking boundery passing of _BST charge levels */
133d2ec54f7Sphitran static uint32_t acpi_drv_syn_last_level;
134d2ec54f7Sphitran 
135d2ec54f7Sphitran /* AC state */
136d2ec54f7Sphitran static struct acpi_drv_ac_state {
137d2ec54f7Sphitran 	struct acpi_drv_dev dev;
138d2ec54f7Sphitran } acpi_drv_ac[ACPI_DRV_MAX_AC_NUM];
139630ff078Sphitran static int nac = 0;
140d2ec54f7Sphitran 
141d2ec54f7Sphitran /*
142d2ec54f7Sphitran  * Current power source device
143d2ec54f7Sphitran  * Note: assume only one device can be the power source device.
144d2ec54f7Sphitran  */
145d2ec54f7Sphitran static int acpi_drv_psr_type = ACPI_DRV_TYPE_UNKNOWN;
146d2ec54f7Sphitran static struct acpi_drv_dev *acpi_drv_psr_devp = NULL;
147d2ec54f7Sphitran 
148d2ec54f7Sphitran struct obj_desc {
149d2ec54f7Sphitran 	char *name;
150d2ec54f7Sphitran 	int offset;
151d2ec54f7Sphitran 	int size;
152d2ec54f7Sphitran 	int type;
153d2ec54f7Sphitran };
154d2ec54f7Sphitran 
155d2ec54f7Sphitran /* Object copy definitions */
156d2ec54f7Sphitran #define	OFFSETOF(s, m)		((size_t)(&(((s *)0)->m)))
157d2ec54f7Sphitran #define	SIZEOF(s, m)		(sizeof (((s *)0)->m))
158d2ec54f7Sphitran #define	FIELD(n, s, m, t) \
159d2ec54f7Sphitran 	{ n, OFFSETOF(s, m), SIZEOF(s, m), t }
160d2ec54f7Sphitran #define	FIELD_NULL		{ NULL, -1, 0, ACPI_TYPE_ANY }
161d2ec54f7Sphitran 
162d2ec54f7Sphitran static struct obj_desc bif_desc[] = {
163d2ec54f7Sphitran 	FIELD("bif_unit",	acpi_bif_t, bif_unit,	ACPI_TYPE_INTEGER),
164d2ec54f7Sphitran 	FIELD("bif_design_cap", acpi_bif_t, bif_design_cap, ACPI_TYPE_INTEGER),
165d2ec54f7Sphitran 	FIELD("bif_last_cap",	acpi_bif_t, bif_last_cap,   ACPI_TYPE_INTEGER),
166d2ec54f7Sphitran 	FIELD("bif_tech",	acpi_bif_t, bif_tech,	ACPI_TYPE_INTEGER),
167d2ec54f7Sphitran 	FIELD("bif_voltage",	acpi_bif_t, bif_voltage, ACPI_TYPE_INTEGER),
168d2ec54f7Sphitran 	FIELD("bif_warn_cap",	acpi_bif_t, bif_warn_cap, ACPI_TYPE_INTEGER),
169d2ec54f7Sphitran 	FIELD("bif_low_cap",	acpi_bif_t, bif_low_cap,  ACPI_TYPE_INTEGER),
170d2ec54f7Sphitran 	FIELD("bif_gran1_cap",	acpi_bif_t, bif_gran1_cap, ACPI_TYPE_INTEGER),
171d2ec54f7Sphitran 	FIELD("bif_gran2_cap",	acpi_bif_t, bif_gran2_cap, ACPI_TYPE_INTEGER),
172d2ec54f7Sphitran 	FIELD("bif_model",	acpi_bif_t, bif_model,	ACPI_TYPE_STRING),
173d2ec54f7Sphitran 	FIELD("bif_serial",	acpi_bif_t, bif_serial,	ACPI_TYPE_STRING),
174d2ec54f7Sphitran 	FIELD("bif_type",	acpi_bif_t, bif_type,	ACPI_TYPE_STRING),
175d2ec54f7Sphitran 	FIELD("bif_oem_info",	acpi_bif_t, bif_oem_info, ACPI_TYPE_STRING),
176d2ec54f7Sphitran 	FIELD_NULL
177d2ec54f7Sphitran };
178d2ec54f7Sphitran 
179d2ec54f7Sphitran static struct obj_desc bst_desc[] = {
180d2ec54f7Sphitran 	FIELD("bst_state",   acpi_bst_t, bst_state,	ACPI_TYPE_INTEGER),
181d2ec54f7Sphitran 	FIELD("bst_rate",    acpi_bst_t, bst_rate,	ACPI_TYPE_INTEGER),
182d2ec54f7Sphitran 	FIELD("bst_rem_cap", acpi_bst_t, bst_rem_cap,	ACPI_TYPE_INTEGER),
183d2ec54f7Sphitran 	FIELD("bst_voltage", acpi_bst_t, bst_voltage,	ACPI_TYPE_INTEGER),
184d2ec54f7Sphitran 	FIELD_NULL
185d2ec54f7Sphitran };
186d2ec54f7Sphitran 
187d2ec54f7Sphitran /* kstat definitions */
188d2ec54f7Sphitran static kstat_t *acpi_drv_power_ksp;
189d2ec54f7Sphitran static kstat_t *acpi_drv_warn_ksp;
190d2ec54f7Sphitran 
191d2ec54f7Sphitran acpi_drv_power_kstat_t acpi_drv_power_kstat = {
192d2ec54f7Sphitran 	{ SYSTEM_POWER,			KSTAT_DATA_STRING },
193d2ec54f7Sphitran 	{ SUPPORTED_BATTERY_COUNT,	KSTAT_DATA_UINT32 },
194d2ec54f7Sphitran };
195d2ec54f7Sphitran 
196d2ec54f7Sphitran acpi_drv_warn_kstat_t acpi_drv_warn_kstat = {
197d2ec54f7Sphitran 	{ BW_ENABLED,			KSTAT_DATA_UINT32 },
198d2ec54f7Sphitran 	{ BW_POWEROFF_THRESHOLD,	KSTAT_DATA_UINT32 },
199d2ec54f7Sphitran 	{ BW_SHUTDOWN_THRESHOLD,	KSTAT_DATA_UINT32 },
200d2ec54f7Sphitran };
201d2ec54f7Sphitran 
202d2ec54f7Sphitran /* BIF */
203d2ec54f7Sphitran acpi_drv_bif_kstat_t acpi_drv_bif_kstat = {
204d2ec54f7Sphitran 	{ BIF_UNIT,		KSTAT_DATA_UINT32 },
205d2ec54f7Sphitran 	{ BIF_DESIGN_CAP,	KSTAT_DATA_UINT32 },
206d2ec54f7Sphitran 	{ BIF_LAST_CAP,		KSTAT_DATA_UINT32 },
207d2ec54f7Sphitran 	{ BIF_TECH,		KSTAT_DATA_UINT32 },
208d2ec54f7Sphitran 	{ BIF_VOLTAGE,		KSTAT_DATA_UINT32 },
209d2ec54f7Sphitran 	{ BIF_WARN_CAP,		KSTAT_DATA_UINT32 },
210d2ec54f7Sphitran 	{ BIF_LOW_CAP,		KSTAT_DATA_UINT32 },
211d2ec54f7Sphitran 	{ BIF_GRAN1_CAP,	KSTAT_DATA_UINT32 },
212d2ec54f7Sphitran 	{ BIF_GRAN2_CAP,	KSTAT_DATA_UINT32 },
213d2ec54f7Sphitran 	{ BIF_MODEL,		KSTAT_DATA_STRING },
214d2ec54f7Sphitran 	{ BIF_SERIAL,		KSTAT_DATA_STRING },
215d2ec54f7Sphitran 	{ BIF_TYPE,		KSTAT_DATA_STRING },
216d2ec54f7Sphitran 	{ BIF_OEM_INFO,		KSTAT_DATA_STRING },
217d2ec54f7Sphitran };
218d2ec54f7Sphitran 
219d2ec54f7Sphitran /* BST */
220d2ec54f7Sphitran acpi_drv_bst_kstat_t acpi_drv_bst_kstat = {
221d2ec54f7Sphitran 	{ BST_STATE,		KSTAT_DATA_UINT32 },
222d2ec54f7Sphitran 	{ BST_RATE,		KSTAT_DATA_UINT32 },
223d2ec54f7Sphitran 	{ BST_REM_CAP,		KSTAT_DATA_UINT32 },
224d2ec54f7Sphitran 	{ BST_VOLTAGE,		KSTAT_DATA_UINT32 },
225d2ec54f7Sphitran };
226d2ec54f7Sphitran 
227d2ec54f7Sphitran struct acpi_drv_lid_state {
228d2ec54f7Sphitran 	struct acpi_drv_dev dev;
229d2ec54f7Sphitran 	enum acpi_drv_notify state_ok;
230d2ec54f7Sphitran 	int state;
231d2ec54f7Sphitran } lid;
232630ff078Sphitran static int nlid = 0;
233d2ec54f7Sphitran 
2342d6b5ea7SGuoli Shu struct hotkey_drv acpi_hotkey;
235d2ec54f7Sphitran 
236d2ec54f7Sphitran static int acpi_drv_attach(dev_info_t *devi, ddi_attach_cmd_t cmd);
237d2ec54f7Sphitran static int acpi_drv_detach(dev_info_t *devi, ddi_detach_cmd_t cmd);
238d2ec54f7Sphitran static int acpi_drv_getinfo(dev_info_t *dip, ddi_info_cmd_t cmd, void *arg,
239d2ec54f7Sphitran     void **resultp);
240d2ec54f7Sphitran static int acpi_drv_open(dev_t *devp, int flag, int otyp, cred_t *crp);
241d2ec54f7Sphitran static int acpi_drv_close(dev_t dev, int flag, int otyp, cred_t *crp);
242d2ec54f7Sphitran static int acpi_drv_ioctl(dev_t dev, int cmd, intptr_t arg, int mode,
243d2ec54f7Sphitran     cred_t *cr, int *rval);
244d2ec54f7Sphitran static int acpi_drv_chpoll(dev_t dev, short events, int anyyet,
245d2ec54f7Sphitran     short *reventsp, struct pollhead **phpp);
246d2ec54f7Sphitran static int acpi_drv_ac_ioctl(int index, int cmd, intptr_t arg, int mode,
247d2ec54f7Sphitran     cred_t *cr, int *rval);
248d2ec54f7Sphitran static int acpi_drv_cbat_ioctl(int index, int cmd, intptr_t arg, int mode,
249d2ec54f7Sphitran     cred_t *cr, int *rval);
250d2ec54f7Sphitran static int acpi_drv_lid_ioctl(int index, int cmd, intptr_t arg, int mode,
251d2ec54f7Sphitran     cred_t *cr, int *rval);
252d2ec54f7Sphitran #ifdef DEBUG
253d2ec54f7Sphitran static void acpi_drv_printf(struct acpi_drv_dev *devp, uint_t lev,
254d2ec54f7Sphitran     const char *fmt, ...);
255d2ec54f7Sphitran #endif
256d2ec54f7Sphitran 
257d2ec54f7Sphitran static int acpi_drv_update_bif(struct acpi_drv_cbat_state *bp);
258d2ec54f7Sphitran static int acpi_drv_update_bst(struct acpi_drv_cbat_state *bp);
259d2ec54f7Sphitran static int acpi_drv_update_lid(struct acpi_drv_dev *bp);
260d2ec54f7Sphitran static int acpi_drv_set_warn(acpi_drv_warn_t *bwp);
261d2ec54f7Sphitran static struct acpi_drv_cbat_state *acpi_drv_idx2cbat(int idx);
262d2ec54f7Sphitran static struct acpi_drv_ac_state *acpi_drv_idx2ac(int idx);
263d2ec54f7Sphitran static int acpi_drv_acpi_init(void);
264d2ec54f7Sphitran static void acpi_drv_acpi_fini(void);
265d2ec54f7Sphitran static int acpi_drv_kstat_init(void);
266d2ec54f7Sphitran static void acpi_drv_kstat_fini(void);
267d2ec54f7Sphitran 
26828b6fd27SHans Rosenfeld static int acpi_drv_kstat_bif_update(kstat_t *, int);
26928b6fd27SHans Rosenfeld static int acpi_drv_kstat_bst_update(kstat_t *, int);
27028b6fd27SHans Rosenfeld 
27128b6fd27SHans Rosenfeld static void acpi_drv_cbat_rescan(void *);
27228b6fd27SHans Rosenfeld 
273d2ec54f7Sphitran static struct cb_ops acpi_drv_cb_ops = {
274d2ec54f7Sphitran 	acpi_drv_open,		/* open */
275d2ec54f7Sphitran 	acpi_drv_close,		/* close */
276d2ec54f7Sphitran 	nodev,			/* strategy */
277d2ec54f7Sphitran 	nodev,			/* print */
278d2ec54f7Sphitran 	nodev,			/* dump */
279d2ec54f7Sphitran 	nodev,			/* read */
280d2ec54f7Sphitran 	nodev,			/* write */
281d2ec54f7Sphitran 	acpi_drv_ioctl,		/* ioctl */
282d2ec54f7Sphitran 	nodev,			/* devmap */
283d2ec54f7Sphitran 	nodev,			/* mmap */
284d2ec54f7Sphitran 	nodev,			/* segmap */
285d2ec54f7Sphitran 	acpi_drv_chpoll,		/* chpoll */
286d2ec54f7Sphitran 	ddi_prop_op,		/* prop_op */
287d2ec54f7Sphitran 	NULL,			/* streamtab */
288d2ec54f7Sphitran 	D_NEW | D_MP,
289d2ec54f7Sphitran 	CB_REV,
290d2ec54f7Sphitran 	nodev,
291d2ec54f7Sphitran 	nodev
292d2ec54f7Sphitran };
293d2ec54f7Sphitran 
294d2ec54f7Sphitran static struct dev_ops acpi_drv_dev_ops = {
295d2ec54f7Sphitran 	DEVO_REV,
296d2ec54f7Sphitran 	0,			/* refcnt */
297d2ec54f7Sphitran 	acpi_drv_getinfo,	/* getinfo */
298d2ec54f7Sphitran 	nulldev,		/* identify */
299d2ec54f7Sphitran 	nulldev,		/* probe */
300d2ec54f7Sphitran 	acpi_drv_attach,	/* attach */
301d2ec54f7Sphitran 	acpi_drv_detach,	/* detach */
302d2ec54f7Sphitran 	nodev,			/* reset */
303d2ec54f7Sphitran 	&acpi_drv_cb_ops,
304d2ec54f7Sphitran 	NULL,			/* no bus operations */
30519397407SSherry Moore 	NULL,			/* power */
30619397407SSherry Moore 	ddi_quiesce_not_needed,	/* quiesce */
307d2ec54f7Sphitran };
308d2ec54f7Sphitran 
309d2ec54f7Sphitran static struct modldrv modldrv1 = {
310d2ec54f7Sphitran 	&mod_driverops,
311d2ec54f7Sphitran 	ACPI_DRV_MOD_STRING,
312d2ec54f7Sphitran 	&acpi_drv_dev_ops
313d2ec54f7Sphitran };
314d2ec54f7Sphitran 
315d2ec54f7Sphitran static struct modlinkage modlinkage = {
316d2ec54f7Sphitran 	MODREV_1,
317d2ec54f7Sphitran 	(void *)&modldrv1,
318d2ec54f7Sphitran 	NULL,
319d2ec54f7Sphitran };
320d2ec54f7Sphitran 
321d2ec54f7Sphitran int
_init(void)322d2ec54f7Sphitran _init(void)
323d2ec54f7Sphitran {
324d2ec54f7Sphitran 	int ret;
325d2ec54f7Sphitran 
326d2ec54f7Sphitran 	mutex_init(&acpi_drv_mutex, NULL, MUTEX_DRIVER, NULL);
327d2ec54f7Sphitran #ifdef DEBUG
328d2ec54f7Sphitran 	mutex_init(&acpi_drv_prt_mutex, NULL, MUTEX_DRIVER, NULL);
329d2ec54f7Sphitran #endif
330d2ec54f7Sphitran 
331d2ec54f7Sphitran 	if ((ret = mod_install(&modlinkage)) != 0) {
332d2ec54f7Sphitran 		mutex_destroy(&acpi_drv_mutex);
333d2ec54f7Sphitran #ifdef DEBUG
334d2ec54f7Sphitran 		mutex_destroy(&acpi_drv_prt_mutex);
335d2ec54f7Sphitran #endif
336d2ec54f7Sphitran 	}
337d2ec54f7Sphitran 	return (ret);
338d2ec54f7Sphitran }
339d2ec54f7Sphitran 
340d2ec54f7Sphitran int
_fini(void)341d2ec54f7Sphitran _fini(void)
342d2ec54f7Sphitran {
343d2ec54f7Sphitran 	int ret;
344d2ec54f7Sphitran 
345d2ec54f7Sphitran 	if ((ret = mod_remove(&modlinkage)) == 0) {
346d2ec54f7Sphitran #ifdef DEBUG
347d2ec54f7Sphitran 		mutex_destroy(&acpi_drv_prt_mutex);
348d2ec54f7Sphitran #endif
349d2ec54f7Sphitran 		mutex_destroy(&acpi_drv_mutex);
350d2ec54f7Sphitran 	}
351d2ec54f7Sphitran 
352d2ec54f7Sphitran 	return (ret);
353d2ec54f7Sphitran }
354d2ec54f7Sphitran 
355d2ec54f7Sphitran int
_info(struct modinfo * mp)356d2ec54f7Sphitran _info(struct modinfo *mp)
357d2ec54f7Sphitran {
358d2ec54f7Sphitran 	return (mod_info(&modlinkage, mp));
359d2ec54f7Sphitran }
360d2ec54f7Sphitran 
361d2ec54f7Sphitran static int
acpi_drv_attach(dev_info_t * devi,ddi_attach_cmd_t cmd)362d2ec54f7Sphitran acpi_drv_attach(dev_info_t *devi, ddi_attach_cmd_t cmd)
363d2ec54f7Sphitran {
364d2ec54f7Sphitran 	switch (cmd) {
365d2ec54f7Sphitran 	case DDI_ATTACH:
366d2ec54f7Sphitran 		/* Limit to one instance of driver */
367d2ec54f7Sphitran 		if (acpi_drv_dip) {
368d2ec54f7Sphitran 			return (DDI_FAILURE);
369d2ec54f7Sphitran 		}
370d2ec54f7Sphitran 		break;
371d2ec54f7Sphitran 	case DDI_RESUME:
372d2ec54f7Sphitran 	case DDI_PM_RESUME:
373d2ec54f7Sphitran 		return (DDI_SUCCESS);
374d2ec54f7Sphitran 	default:
375d2ec54f7Sphitran 		return (DDI_FAILURE);
376d2ec54f7Sphitran 	}
377d2ec54f7Sphitran 
378d2ec54f7Sphitran 	acpi_drv_dip = devi;
379d2ec54f7Sphitran 
380d2ec54f7Sphitran 	/* Init ACPI related stuff */
381d2ec54f7Sphitran 	if (acpi_drv_acpi_init() != ACPI_DRV_OK) {
382d2ec54f7Sphitran 		goto error;
383d2ec54f7Sphitran 	}
384d2ec54f7Sphitran 
385d2ec54f7Sphitran 	/* Init kstat related stuff */
386d2ec54f7Sphitran 	if (acpi_drv_kstat_init() != ACPI_DRV_OK) {
387d2ec54f7Sphitran 		goto error;
388d2ec54f7Sphitran 	}
389d2ec54f7Sphitran 
39028b6fd27SHans Rosenfeld 	acpi_drv_cbat_rescan_timeout = timeout(acpi_drv_cbat_rescan, NULL,
39128b6fd27SHans Rosenfeld 	    drv_usectohz(MICROSEC));
392d2ec54f7Sphitran 
393d2ec54f7Sphitran 	return (DDI_SUCCESS);
394d2ec54f7Sphitran 
395d2ec54f7Sphitran error:
396d2ec54f7Sphitran 	ddi_remove_minor_node(devi, NULL);
397d2ec54f7Sphitran 	acpi_drv_kstat_fini();
398d2ec54f7Sphitran 	acpi_drv_acpi_fini();
399d2ec54f7Sphitran 	acpi_drv_dip = NULL;
400d2ec54f7Sphitran 	return (DDI_FAILURE);
401d2ec54f7Sphitran }
402d2ec54f7Sphitran 
403d2ec54f7Sphitran static int
acpi_drv_detach(dev_info_t * devi,ddi_detach_cmd_t cmd)404d2ec54f7Sphitran acpi_drv_detach(dev_info_t *devi, ddi_detach_cmd_t cmd)
405d2ec54f7Sphitran {
40628b6fd27SHans Rosenfeld 	timeout_id_t tmp_rescan_timeout;
40728b6fd27SHans Rosenfeld 
408d2ec54f7Sphitran 	if (cmd != DDI_DETACH) {
409d2ec54f7Sphitran 		return (DDI_FAILURE);
410d2ec54f7Sphitran 	}
411d2ec54f7Sphitran 
41228b6fd27SHans Rosenfeld 	/*
41328b6fd27SHans Rosenfeld 	 * Clear the timeout id to indicate that the handler should not
41428b6fd27SHans Rosenfeld 	 * reschedule itself.
41528b6fd27SHans Rosenfeld 	 */
41628b6fd27SHans Rosenfeld 	mutex_enter(&acpi_drv_mutex);
41728b6fd27SHans Rosenfeld 	tmp_rescan_timeout = acpi_drv_cbat_rescan_timeout;
41828b6fd27SHans Rosenfeld 	acpi_drv_cbat_rescan_timeout = 0;
41928b6fd27SHans Rosenfeld 	mutex_exit(&acpi_drv_mutex);
42028b6fd27SHans Rosenfeld 
42128b6fd27SHans Rosenfeld 	(void) untimeout(tmp_rescan_timeout);
42228b6fd27SHans Rosenfeld 
423d2ec54f7Sphitran 	mutex_enter(&acpi_drv_mutex);
424d2ec54f7Sphitran 	ddi_remove_minor_node(devi, NULL);
425d2ec54f7Sphitran 
426d2ec54f7Sphitran 	acpi_drv_kstat_fini();
427d2ec54f7Sphitran 	acpi_drv_acpi_fini();
428d2ec54f7Sphitran 	mutex_exit(&acpi_drv_mutex);
429d2ec54f7Sphitran 	return (DDI_SUCCESS);
430d2ec54f7Sphitran }
431d2ec54f7Sphitran 
432d2ec54f7Sphitran /* ARGSUSED */
433d2ec54f7Sphitran static int
acpi_drv_getinfo(dev_info_t * dip,ddi_info_cmd_t cmd,void * arg,void ** resultp)434d2ec54f7Sphitran acpi_drv_getinfo(dev_info_t *dip, ddi_info_cmd_t cmd, void *arg, void **resultp)
435d2ec54f7Sphitran {
436d2ec54f7Sphitran 	switch (cmd) {
437d2ec54f7Sphitran 	case DDI_INFO_DEVT2DEVINFO:
438d2ec54f7Sphitran 		*resultp = acpi_drv_dip;
439d2ec54f7Sphitran 		return (DDI_SUCCESS);
440d2ec54f7Sphitran 	case DDI_INFO_DEVT2INSTANCE:
441d2ec54f7Sphitran 		*resultp = (void*) 0;
442d2ec54f7Sphitran 		return (DDI_SUCCESS);
443d2ec54f7Sphitran 	default:
444d2ec54f7Sphitran 		return (DDI_FAILURE);
445d2ec54f7Sphitran 	}
446d2ec54f7Sphitran }
447d2ec54f7Sphitran 
448d2ec54f7Sphitran /*ARGSUSED*/
449d2ec54f7Sphitran static int
acpi_drv_open(dev_t * devp,int flag,int otyp,cred_t * crp)450d2ec54f7Sphitran acpi_drv_open(dev_t *devp, int flag, int otyp, cred_t *crp)
451d2ec54f7Sphitran {
452d2ec54f7Sphitran 	if (acpi_drv_dip == NULL) {
453d2ec54f7Sphitran 		return (ENXIO);
454d2ec54f7Sphitran 	}
455d2ec54f7Sphitran 
456d2ec54f7Sphitran 	return (0);
457d2ec54f7Sphitran }
458d2ec54f7Sphitran 
459d2ec54f7Sphitran /*ARGSUSED*/
460d2ec54f7Sphitran static int
acpi_drv_close(dev_t dev,int flag,int otyp,cred_t * crp)461d2ec54f7Sphitran acpi_drv_close(dev_t dev, int flag, int otyp, cred_t *crp)
462d2ec54f7Sphitran {
463d2ec54f7Sphitran 	return (0);
464d2ec54f7Sphitran }
465d2ec54f7Sphitran 
466d2ec54f7Sphitran /*ARGSUSED*/
467d2ec54f7Sphitran static int
acpi_drv_ioctl(dev_t dev,int cmd,intptr_t arg,int mode,cred_t * cr,int * rval)468d2ec54f7Sphitran acpi_drv_ioctl(dev_t dev, int cmd, intptr_t arg, int mode, cred_t *cr,
469d2ec54f7Sphitran     int *rval)
470d2ec54f7Sphitran {
471d2ec54f7Sphitran 	int minor;
472d2ec54f7Sphitran 	int type, index;
473d2ec54f7Sphitran 	int res = 0;
474d2ec54f7Sphitran 
475d2ec54f7Sphitran 	minor = getminor(dev);
476d2ec54f7Sphitran 	type = MINOR2TYPE(minor);
477d2ec54f7Sphitran 	index = MINOR2IDX(minor);
478d2ec54f7Sphitran 
479d2ec54f7Sphitran 	mutex_enter(&acpi_drv_mutex);
480d2ec54f7Sphitran 
481d2ec54f7Sphitran 	switch (type) {
482d2ec54f7Sphitran 	case ACPI_DRV_TYPE_CBAT:
483d2ec54f7Sphitran 		res = acpi_drv_cbat_ioctl(index, cmd, arg, mode, cr, rval);
484d2ec54f7Sphitran 		break;
485d2ec54f7Sphitran 	case ACPI_DRV_TYPE_AC:
486d2ec54f7Sphitran 		res = acpi_drv_ac_ioctl(index, cmd, arg, mode, cr, rval);
487d2ec54f7Sphitran 		break;
488d2ec54f7Sphitran 	case ACPI_DRV_TYPE_LID:
489d2ec54f7Sphitran 		res = acpi_drv_lid_ioctl(index, cmd, arg, mode, cr, rval);
490d2ec54f7Sphitran 		break;
4912d6b5ea7SGuoli Shu 	case ACPI_DRV_TYPE_HOTKEY:
4922d6b5ea7SGuoli Shu 		res = acpi_drv_hotkey_ioctl(cmd, arg, mode, cr, rval);
493d2ec54f7Sphitran 		break;
494d2ec54f7Sphitran 	default:
495d2ec54f7Sphitran 		res = EINVAL;
496d2ec54f7Sphitran 		break;
497d2ec54f7Sphitran 	}
498d2ec54f7Sphitran 
499d2ec54f7Sphitran 	mutex_exit(&acpi_drv_mutex);
500d2ec54f7Sphitran 	return (res);
501d2ec54f7Sphitran }
502d2ec54f7Sphitran 
503d2ec54f7Sphitran /*ARGSUSED*/
504d2ec54f7Sphitran static int
acpi_drv_cbat_ioctl(int index,int cmd,intptr_t arg,int mode,cred_t * cr,int * rval)505d2ec54f7Sphitran acpi_drv_cbat_ioctl(int index, int cmd, intptr_t arg, int mode, cred_t *cr,
506d2ec54f7Sphitran     int *rval)
507d2ec54f7Sphitran {
508d2ec54f7Sphitran 	int res = 0;
509d2ec54f7Sphitran 	acpi_drv_warn_t bwarn;
510d2ec54f7Sphitran 	struct acpi_drv_cbat_state *bp;
511d2ec54f7Sphitran 
512d2ec54f7Sphitran 	ASSERT(mutex_owned(&acpi_drv_mutex));
513d2ec54f7Sphitran 
514d2ec54f7Sphitran 	bp = acpi_drv_idx2cbat(index);
515d2ec54f7Sphitran 	if (!bp || bp->dev.valid != 1) {
516d2ec54f7Sphitran 		return (ENXIO);
517d2ec54f7Sphitran 	}
518d2ec54f7Sphitran 
519d2ec54f7Sphitran 	switch (cmd) {
520d2ec54f7Sphitran 	/*
521d2ec54f7Sphitran 	 * Return _BIF(Battery Information) of battery[index],
522d2ec54f7Sphitran 	 * if battery plugged.
523d2ec54f7Sphitran 	 */
524d2ec54f7Sphitran 	case ACPI_DRV_IOC_INFO:
525d2ec54f7Sphitran 		if (bp->dev.present == 0) {
526d2ec54f7Sphitran 			res = ENXIO;
527d2ec54f7Sphitran 			break;
528d2ec54f7Sphitran 		}
529d2ec54f7Sphitran 
530d2ec54f7Sphitran 		res = acpi_drv_update_bif(bp);
531d2ec54f7Sphitran 		if (res != ACPI_DRV_OK) {
532d2ec54f7Sphitran 			break;
533d2ec54f7Sphitran 		}
534d2ec54f7Sphitran 		if (copyout(&bp->bif_cache, (void *)arg,
535d2ec54f7Sphitran 		    sizeof (bp->bif_cache))) {
536d2ec54f7Sphitran 			res = EFAULT;
537d2ec54f7Sphitran 		}
538d2ec54f7Sphitran 		break;
539d2ec54f7Sphitran 
540d2ec54f7Sphitran 	/*
541d2ec54f7Sphitran 	 * Return _BST(Battery Status) of battery[index],
542d2ec54f7Sphitran 	 * if battery plugged.
543d2ec54f7Sphitran 	 */
544d2ec54f7Sphitran 	case ACPI_DRV_IOC_STATUS:
545d2ec54f7Sphitran 		if (bp->dev.present == 0) {
546d2ec54f7Sphitran 			res = ENXIO;
547d2ec54f7Sphitran 			break;
548d2ec54f7Sphitran 		}
549d2ec54f7Sphitran 
550d2ec54f7Sphitran 		res = acpi_drv_update_bst(bp);
551d2ec54f7Sphitran 		if (res != ACPI_DRV_OK) {
552d2ec54f7Sphitran 			break;
553d2ec54f7Sphitran 		}
554d2ec54f7Sphitran 		if (copyout(&bp->bst_cache, (void *)arg,
555d2ec54f7Sphitran 		    sizeof (bp->bst_cache))) {
556d2ec54f7Sphitran 			res = EFAULT;
557d2ec54f7Sphitran 		}
558d2ec54f7Sphitran 		break;
559d2ec54f7Sphitran 
560d2ec54f7Sphitran 	/* Return the state of the battery bays in the system */
561d2ec54f7Sphitran 	case ACPI_DRV_IOC_BAY:
562d2ec54f7Sphitran 		{
563d2ec54f7Sphitran 			batt_bay_t bay;
564d2ec54f7Sphitran 
565d2ec54f7Sphitran 			bay.bay_number = nbat;
566d2ec54f7Sphitran 			bay.battery_map = 0;
567d2ec54f7Sphitran 			for (bp = &acpi_drv_cbat[0];
568d2ec54f7Sphitran 			    bp < &acpi_drv_cbat[ACPI_DRV_MAX_BAT_NUM]; bp++) {
569d2ec54f7Sphitran 				if (bp->dev.valid) {
570d2ec54f7Sphitran 					if (bp->dev.present) {
571d2ec54f7Sphitran 						bay.battery_map |=
572d2ec54f7Sphitran 						    (1 << bp->dev.index);
573d2ec54f7Sphitran 					}
574d2ec54f7Sphitran 				}
575d2ec54f7Sphitran 			}
576d2ec54f7Sphitran 			if (copyout(&bay, (void *)arg, sizeof (bay))) {
577d2ec54f7Sphitran 				res = EFAULT;
578d2ec54f7Sphitran 				break;
579d2ec54f7Sphitran 			}
580d2ec54f7Sphitran 		}
581d2ec54f7Sphitran 		break;
582d2ec54f7Sphitran 
583d2ec54f7Sphitran 	/*
584d2ec54f7Sphitran 	 * Return the current power source device if available:
585d2ec54f7Sphitran 	 * 0 -- battery supplying power
586d2ec54f7Sphitran 	 * 1 -- AC supplying power
587d2ec54f7Sphitran 	 */
588d2ec54f7Sphitran 	case ACPI_DRV_IOC_POWER_STATUS:
589d2ec54f7Sphitran 		{
590d2ec54f7Sphitran 			int val;
591d2ec54f7Sphitran 
592d2ec54f7Sphitran 			/* State not available */
593d2ec54f7Sphitran 			if (acpi_drv_psr_type == ACPI_DRV_TYPE_UNKNOWN) {
594d2ec54f7Sphitran 				res = ENXIO;
595d2ec54f7Sphitran 				break;
596d2ec54f7Sphitran 			}
597d2ec54f7Sphitran 			val = (acpi_drv_psr_type == ACPI_DRV_TYPE_AC) ? 1 : 0;
598d2ec54f7Sphitran 			if (copyout(&val, (void *)arg, sizeof (val))) {
599d2ec54f7Sphitran 				res = EFAULT;
600d2ec54f7Sphitran 				break;
601d2ec54f7Sphitran 			}
602d2ec54f7Sphitran 		}
603d2ec54f7Sphitran 		break;
604d2ec54f7Sphitran 
605d2ec54f7Sphitran 	/* Get charge-warn and charge-low levels for the whole system */
606d2ec54f7Sphitran 	case ACPI_DRV_IOC_GET_WARNING:
607d2ec54f7Sphitran 		bwarn.bw_enabled = acpi_drv_warn_enabled;
608d2ec54f7Sphitran 		bwarn.bw_charge_warn = acpi_drv_syn_warn_per;
609d2ec54f7Sphitran 		bwarn.bw_charge_low = acpi_drv_syn_low_per;
610*ce17336eSAndy Fiddaman 		if (copyout(&bwarn, (void *)arg, sizeof (bwarn))) {
611d2ec54f7Sphitran 			res = EFAULT;
612d2ec54f7Sphitran 		}
613d2ec54f7Sphitran 		break;
614d2ec54f7Sphitran 
615d2ec54f7Sphitran 	/* Set charge-warn and charge-low levels for the whole system */
616d2ec54f7Sphitran 	case ACPI_DRV_IOC_SET_WARNING:
617d2ec54f7Sphitran 		if (drv_priv(cr)) {
618d2ec54f7Sphitran 			res = EPERM;
619d2ec54f7Sphitran 			break;
620d2ec54f7Sphitran 		}
621d2ec54f7Sphitran 		if (copyin((void *)arg, &bwarn, sizeof (bwarn))) {
622d2ec54f7Sphitran 			res = EFAULT;
623d2ec54f7Sphitran 			break;
624d2ec54f7Sphitran 		}
625d2ec54f7Sphitran 		res = acpi_drv_set_warn(&bwarn);
626d2ec54f7Sphitran 		break;
627d2ec54f7Sphitran 
628d2ec54f7Sphitran 	default:
629d2ec54f7Sphitran 		res = EINVAL;
630d2ec54f7Sphitran 		break;
631d2ec54f7Sphitran 	}
632d2ec54f7Sphitran 
633d2ec54f7Sphitran 	return (res);
634d2ec54f7Sphitran }
635d2ec54f7Sphitran 
636d2ec54f7Sphitran /*ARGSUSED*/
637d2ec54f7Sphitran static int
acpi_drv_ac_ioctl(int index,int cmd,intptr_t arg,int mode,cred_t * cr,int * rval)638d2ec54f7Sphitran acpi_drv_ac_ioctl(int index, int cmd, intptr_t arg, int mode, cred_t *cr,
639d2ec54f7Sphitran     int *rval)
640d2ec54f7Sphitran {
641d2ec54f7Sphitran 	int res = 0;
642d2ec54f7Sphitran 	int ac_state;
643d2ec54f7Sphitran 	struct acpi_drv_ac_state *acp;
644d2ec54f7Sphitran 
645d2ec54f7Sphitran 	ASSERT(mutex_owned(&acpi_drv_mutex));
646d2ec54f7Sphitran 
647d2ec54f7Sphitran 	acp = acpi_drv_idx2ac(index);
648d2ec54f7Sphitran 	if (!acp || acp->dev.valid != 1) {
649d2ec54f7Sphitran 		return (ENXIO);
650d2ec54f7Sphitran 	}
651d2ec54f7Sphitran 
652d2ec54f7Sphitran 	switch (cmd) {
653d2ec54f7Sphitran 	/* Return the number of AC adapters in the system */
654d2ec54f7Sphitran 	case ACPI_DRV_IOC_AC_COUNT:
655d2ec54f7Sphitran 		if (copyout(&nac, (void *)arg, sizeof (nac))) {
656d2ec54f7Sphitran 			res = EFAULT;
657d2ec54f7Sphitran 		}
658d2ec54f7Sphitran 		break;
659d2ec54f7Sphitran 
660d2ec54f7Sphitran 	/*
661d2ec54f7Sphitran 	 * Return the state of AC[index] if available:
662d2ec54f7Sphitran 	 * 0 -- Off-line
663d2ec54f7Sphitran 	 * 1 -- On-line
664d2ec54f7Sphitran 	 */
665d2ec54f7Sphitran 	case ACPI_DRV_IOC_POWER_STATUS:
666d2ec54f7Sphitran 		if (!acp || acp->dev.valid != 1) {
667d2ec54f7Sphitran 			res = ENXIO;
668d2ec54f7Sphitran 			break;
669d2ec54f7Sphitran 		}
670d2ec54f7Sphitran 		/* State not available */
671d2ec54f7Sphitran 		if ((ac_state = acpi_drv_ac_present(acp)) == -1) {
672d2ec54f7Sphitran 			res = ENXIO;
673d2ec54f7Sphitran 			break;
674d2ec54f7Sphitran 		}
675d2ec54f7Sphitran 		if (copyout(&ac_state, (void *)arg, sizeof (ac_state))) {
676d2ec54f7Sphitran 			res = EFAULT;
677d2ec54f7Sphitran 		}
678d2ec54f7Sphitran 		break;
679d2ec54f7Sphitran 
680d2ec54f7Sphitran 	default:
681d2ec54f7Sphitran 		res = EINVAL;
682d2ec54f7Sphitran 		break;
683d2ec54f7Sphitran 	}
684d2ec54f7Sphitran 
685d2ec54f7Sphitran 	return (res);
686d2ec54f7Sphitran }
687d2ec54f7Sphitran 
688d2ec54f7Sphitran /*ARGSUSED*/
689d2ec54f7Sphitran static int
acpi_drv_lid_ioctl(int index,int cmd,intptr_t arg,int mode,cred_t * cr,int * rval)690d2ec54f7Sphitran acpi_drv_lid_ioctl(int index, int cmd, intptr_t arg, int mode, cred_t *cr,
691d2ec54f7Sphitran     int *rval)
692d2ec54f7Sphitran {
693d2ec54f7Sphitran 	int res = 0;
694d2ec54f7Sphitran 
695076d97abSPhi Tran 	/*
696076d97abSPhi Tran 	 * lid.state 0 means lid is closed.
697076d97abSPhi Tran 	 * lid.state non-zero means lid is open.
698076d97abSPhi Tran 	 */
699d2ec54f7Sphitran 	switch (cmd) {
700d2ec54f7Sphitran 	case ACPI_DRV_IOC_LID_STATUS:
701d2ec54f7Sphitran 		if (lid.state_ok == ACPI_DRV_NTF_UNKNOWN) {
702d2ec54f7Sphitran 			/* State not available */
703d2ec54f7Sphitran 			res = acpi_drv_update_lid(&lid.dev);
704d2ec54f7Sphitran 			if (res != ACPI_DRV_OK) {
705d2ec54f7Sphitran 				res = ENXIO;
706d2ec54f7Sphitran 				break;
707d2ec54f7Sphitran 			}
708d2ec54f7Sphitran 		}
709d2ec54f7Sphitran 		if (copyout(&lid.state, (void *)arg, sizeof (lid.state))) {
710d2ec54f7Sphitran 			res = EFAULT;
711076d97abSPhi Tran 		}
712d2ec54f7Sphitran 		break;
713076d97abSPhi Tran 	case ACPI_DRV_IOC_LID_UPDATE:
714076d97abSPhi Tran 		res = acpi_drv_update_lid(&lid.dev);
715076d97abSPhi Tran 		if (res != ACPI_DRV_OK) {
716076d97abSPhi Tran 			res = ENXIO;
717076d97abSPhi Tran 			break;
718076d97abSPhi Tran 		}
719076d97abSPhi Tran 		if (copyout(&lid.state, (void *)arg, sizeof (lid.state))) {
720076d97abSPhi Tran 			res = EFAULT;
721d2ec54f7Sphitran 		}
722d2ec54f7Sphitran 		break;
723d2ec54f7Sphitran 
724d2ec54f7Sphitran 	default:
725d2ec54f7Sphitran 		res = EINVAL;
726d2ec54f7Sphitran 		break;
727d2ec54f7Sphitran 	}
728d2ec54f7Sphitran 	return (res);
729d2ec54f7Sphitran }
730d2ec54f7Sphitran 
731d2ec54f7Sphitran /*ARGSUSED*/
732d2ec54f7Sphitran static int
acpi_drv_chpoll(dev_t dev,short events,int anyyet,short * reventsp,struct pollhead ** phpp)733d2ec54f7Sphitran acpi_drv_chpoll(dev_t dev, short events, int anyyet,  short *reventsp,
734d2ec54f7Sphitran     struct pollhead **phpp)
735d2ec54f7Sphitran {
736d2ec54f7Sphitran 	if (!anyyet) {
737d2ec54f7Sphitran 		*phpp = &acpi_drv_pollhead;
738d2ec54f7Sphitran 	}
739d2ec54f7Sphitran 	*reventsp = 0;
740d2ec54f7Sphitran 	return (0);
741d2ec54f7Sphitran }
742d2ec54f7Sphitran 
743d2ec54f7Sphitran #ifdef DEBUG
744d2ec54f7Sphitran static void
acpi_drv_printf(struct acpi_drv_dev * devp,uint_t lev,const char * fmt,...)745d2ec54f7Sphitran acpi_drv_printf(struct acpi_drv_dev *devp, uint_t lev,
746d2ec54f7Sphitran     const char *fmt, ...)
747d2ec54f7Sphitran {
748d2ec54f7Sphitran 	va_list args;
749d2ec54f7Sphitran 
750d2ec54f7Sphitran 	mutex_enter(&acpi_drv_prt_mutex);
751d2ec54f7Sphitran 
752d2ec54f7Sphitran 	va_start(args, fmt);
753d2ec54f7Sphitran 	(void) vsprintf(acpi_drv_prt_buf, fmt, args);
754d2ec54f7Sphitran 	va_end(args);
755d2ec54f7Sphitran 
756d2ec54f7Sphitran 	if (devp) {
757d2ec54f7Sphitran 		cmn_err(lev, "%s.%s: %s", devp->hid, devp->uid,
758d2ec54f7Sphitran 		    acpi_drv_prt_buf);
759d2ec54f7Sphitran 	} else {
760d2ec54f7Sphitran 		cmn_err(lev, "%s", acpi_drv_prt_buf);
761d2ec54f7Sphitran 	}
762d2ec54f7Sphitran 	mutex_exit(&acpi_drv_prt_mutex);
763d2ec54f7Sphitran }
764d2ec54f7Sphitran 
765d2ec54f7Sphitran static void
acpi_drv_prt_notify(ACPI_HANDLE hdl,UINT32 val)766d2ec54f7Sphitran acpi_drv_prt_notify(ACPI_HANDLE hdl, UINT32 val)
767d2ec54f7Sphitran {
768d2ec54f7Sphitran 	ACPI_BUFFER buf;
769d2ec54f7Sphitran 	char str[1024];
770d2ec54f7Sphitran 
771d2ec54f7Sphitran 	buf.Length = sizeof (str);
772d2ec54f7Sphitran 	buf.Pointer = str;
773c1374a13SSurya Prakki 	(void) AcpiGetName(hdl, ACPI_FULL_PATHNAME, &buf);
774d2ec54f7Sphitran 	cmn_err(CE_NOTE, "AcpiNotify(%s, 0x%02x)", str, val);
775d2ec54f7Sphitran }
776d2ec54f7Sphitran #endif /* DEBUG */
777d2ec54f7Sphitran 
7782d6b5ea7SGuoli Shu void
acpi_drv_gen_sysevent(struct acpi_drv_dev * devp,char * ev,uint32_t val)779d2ec54f7Sphitran acpi_drv_gen_sysevent(struct acpi_drv_dev *devp, char *ev, uint32_t val)
780d2ec54f7Sphitran {
781d2ec54f7Sphitran 	nvlist_t *attr_list = NULL;
782d2ec54f7Sphitran 	int err;
783d2ec54f7Sphitran 	char pathname[MAXPATHLEN];
784d2ec54f7Sphitran 
785d2ec54f7Sphitran 	/* Allocate and build sysevent attribute list */
786d2ec54f7Sphitran 	err = nvlist_alloc(&attr_list, NV_UNIQUE_NAME_TYPE, DDI_NOSLEEP);
787d2ec54f7Sphitran 	if (err != 0) {
788d2ec54f7Sphitran 		ACPI_DRV_DBG(CE_WARN, NULL,
789d2ec54f7Sphitran 		    "cannot allocate memory for sysevent attributes\n");
790d2ec54f7Sphitran 		return;
791d2ec54f7Sphitran 	}
792d2ec54f7Sphitran 
793d2ec54f7Sphitran 	/* Add attributes */
794d2ec54f7Sphitran 	err = nvlist_add_string(attr_list, PWRCTL_DEV_HID, devp->hid);
795d2ec54f7Sphitran 	if (err != 0) {
796d2ec54f7Sphitran 		ACPI_DRV_DBG(CE_WARN, NULL,
797d2ec54f7Sphitran 		    "Failed to add attr [%s] for %s/%s event",
798d2ec54f7Sphitran 		    PWRCTL_DEV_HID, EC_PWRCTL, ev);
799d2ec54f7Sphitran 		nvlist_free(attr_list);
800d2ec54f7Sphitran 		return;
801d2ec54f7Sphitran 	}
802d2ec54f7Sphitran 
803d2ec54f7Sphitran 	err = nvlist_add_string(attr_list, PWRCTL_DEV_UID, devp->uid);
804d2ec54f7Sphitran 	if (err != 0) {
805d2ec54f7Sphitran 		ACPI_DRV_DBG(CE_WARN, NULL,
806d2ec54f7Sphitran 		    "Failed to add attr [%s] for %s/%s event",
807d2ec54f7Sphitran 		    PWRCTL_DEV_UID, EC_PWRCTL, ev);
808d2ec54f7Sphitran 		nvlist_free(attr_list);
809d2ec54f7Sphitran 		return;
810d2ec54f7Sphitran 	}
811d2ec54f7Sphitran 
812d2ec54f7Sphitran 	err = nvlist_add_uint32(attr_list, PWRCTL_DEV_INDEX, devp->index);
813d2ec54f7Sphitran 	if (err != 0) {
814d2ec54f7Sphitran 		ACPI_DRV_DBG(CE_WARN, NULL,
815d2ec54f7Sphitran 		    "Failed to add attr [%s] for %s/%s event",
816d2ec54f7Sphitran 		    PWRCTL_DEV_INDEX, EC_PWRCTL, ev);
817d2ec54f7Sphitran 		nvlist_free(attr_list);
818d2ec54f7Sphitran 		return;
819d2ec54f7Sphitran 	}
820d2ec54f7Sphitran 
821d2ec54f7Sphitran 	(void) ddi_pathname(acpi_drv_dip, pathname);
822d2ec54f7Sphitran 	err = nvlist_add_string(attr_list, PWRCTL_DEV_PHYS_PATH, pathname);
823d2ec54f7Sphitran 	if (err != 0) {
824d2ec54f7Sphitran 		ACPI_DRV_DBG(CE_WARN, NULL,
825d2ec54f7Sphitran 		    "Failed to add attr [%s] for %s/%s event",
826d2ec54f7Sphitran 		    PWRCTL_DEV_PHYS_PATH, EC_PWRCTL, ev);
827d2ec54f7Sphitran 		nvlist_free(attr_list);
828d2ec54f7Sphitran 		return;
829d2ec54f7Sphitran 	}
830d2ec54f7Sphitran 
831d2ec54f7Sphitran 	if (strcmp(ev, ESC_PWRCTL_WARN) && strcmp(ev, ESC_PWRCTL_LOW)) {
832d2ec54f7Sphitran 		goto finish;
833d2ec54f7Sphitran 	}
834d2ec54f7Sphitran 
835d2ec54f7Sphitran 	err = nvlist_add_uint32(attr_list, PWRCTL_CHARGE_LEVEL, val);
836d2ec54f7Sphitran 	if (err != 0) {
837d2ec54f7Sphitran 		ACPI_DRV_DBG(CE_WARN, NULL,
838d2ec54f7Sphitran 		    "Failed to add attr [%s] for %s/%s event",
839d2ec54f7Sphitran 		    PWRCTL_CHARGE_LEVEL, EC_PWRCTL, ev);
840d2ec54f7Sphitran 		nvlist_free(attr_list);
841d2ec54f7Sphitran 		return;
842d2ec54f7Sphitran 	}
843d2ec54f7Sphitran 
844d2ec54f7Sphitran finish:
845d2ec54f7Sphitran 	ACPI_DRV_DBG(CE_NOTE, NULL, "SysEv(%s, %s.%s, %d)",
846d2ec54f7Sphitran 	    ev, devp->hid, devp->uid, val);
847d2ec54f7Sphitran 	/* Generate/log sysevent */
848d2ec54f7Sphitran 	err = ddi_log_sysevent(acpi_drv_dip, DDI_VENDOR_SUNW, EC_PWRCTL,
849d2ec54f7Sphitran 	    ev, attr_list, NULL, DDI_NOSLEEP);
850d2ec54f7Sphitran #ifdef DEBUG
851d2ec54f7Sphitran 	if (err != DDI_SUCCESS) {
852d2ec54f7Sphitran 		ACPI_DRV_DBG(CE_WARN, NULL,
853d2ec54f7Sphitran 		    "cannot log sysevent, err code %x\n", err);
854d2ec54f7Sphitran 	}
855d2ec54f7Sphitran #endif
856d2ec54f7Sphitran 
857d2ec54f7Sphitran 	nvlist_free(attr_list);
858d2ec54f7Sphitran }
859d2ec54f7Sphitran 
860d2ec54f7Sphitran static int
acpi_drv_obj_copy(ACPI_OBJECT * op,char * bp,struct obj_desc * dp)861d2ec54f7Sphitran acpi_drv_obj_copy(ACPI_OBJECT *op, char *bp, struct obj_desc *dp)
862d2ec54f7Sphitran {
863d2ec54f7Sphitran 	ACPI_OBJECT *ep;
864d2ec54f7Sphitran 	char *fp;
865d2ec54f7Sphitran 
866d2ec54f7Sphitran 	ep = &op->Package.Elements[0];
867d2ec54f7Sphitran 	for (; dp->offset != -1; dp++) {
868d2ec54f7Sphitran 		fp = bp + dp->offset;
869d2ec54f7Sphitran 		if (dp->type == ACPI_TYPE_INTEGER &&
870d2ec54f7Sphitran 		    ep->Type == dp->type) {
871d2ec54f7Sphitran #ifdef DEBUG
872d2ec54f7Sphitran 			if (dp->size <= 4) {
873d2ec54f7Sphitran 				ACPI_DRV_DBG(CE_NOTE, NULL, "\t%s: %u",
874d2ec54f7Sphitran 				    dp->name,
875d2ec54f7Sphitran 				    (uint32_t)ep->Integer.Value);
876d2ec54f7Sphitran 			} else {
877d2ec54f7Sphitran #ifdef _LP64
878d2ec54f7Sphitran 				ACPI_DRV_DBG(CE_NOTE, NULL, "\t%s: %lu",
879d2ec54f7Sphitran 				    dp->name, (uint64_t)ep->Integer.Value);
880d2ec54f7Sphitran 			}
881d2ec54f7Sphitran #else
882d2ec54f7Sphitran 				ACPI_DRV_DBG(CE_NOTE, NULL, "\t%s: %llu",
883d2ec54f7Sphitran 				    dp->name, (uint64_t)ep->Integer.Value);
884d2ec54f7Sphitran 			}
885d2ec54f7Sphitran #endif /* _LP64 */
886d2ec54f7Sphitran #endif /* DEBUG */
887d2ec54f7Sphitran 			*(uint32_t *)fp = ep->Integer.Value;
888d2ec54f7Sphitran 		} else if (dp->type == ACPI_TYPE_STRING &&
889d2ec54f7Sphitran 		    ep->Type == dp->type) {
890d2ec54f7Sphitran 			ACPI_DRV_DBG(CE_NOTE, NULL, "\t%s: \"%s\"",
891d2ec54f7Sphitran 			    dp->name, ep->String.Pointer);
892a3114836SGerry Liu 			(void) strlcpy(fp, ep->String.Pointer, dp->size);
893d2ec54f7Sphitran 		} else if (dp->type == ACPI_TYPE_STRING &&
894d2ec54f7Sphitran 		    ep->Type == ACPI_TYPE_BUFFER) {
895d2ec54f7Sphitran #ifdef DEBUG
896d2ec54f7Sphitran 			int len;
897d2ec54f7Sphitran 			char buf[MAXNAMELEN + 1];
898d2ec54f7Sphitran 
899d2ec54f7Sphitran 			len = (MAXNAMELEN < ep->Buffer.Length) ?
900d2ec54f7Sphitran 			    MAXNAMELEN : ep->Buffer.Length;
901d2ec54f7Sphitran 			bcopy(ep->Buffer.Pointer, buf, len);
902d2ec54f7Sphitran 			buf[len] = 0;
903d2ec54f7Sphitran 			ACPI_DRV_DBG(CE_NOTE, NULL, "\t%s: [%d] \"%s\"",
904d2ec54f7Sphitran 			    dp->name, len, buf);
905d2ec54f7Sphitran #endif
906d2ec54f7Sphitran 
907d2ec54f7Sphitran 			ASSERT(MAXNAMELEN >= ep->Buffer.Length);
908d2ec54f7Sphitran 			bcopy(ep->Buffer.Pointer, fp, ep->Buffer.Length);
909d2ec54f7Sphitran 		} else {
910d2ec54f7Sphitran 			ACPI_DRV_DBG(CE_WARN, NULL,
911d2ec54f7Sphitran 			    "Bad field at offset %d: type %d",
912d2ec54f7Sphitran 			    dp->offset, ep->Type);
913d2ec54f7Sphitran 			if (dp->type != ACPI_TYPE_STRING) {
914d2ec54f7Sphitran 				return (ACPI_DRV_ERR);
915d2ec54f7Sphitran 			}
916d2ec54f7Sphitran 		}
917d2ec54f7Sphitran 		ep++;
918d2ec54f7Sphitran 	}
919d2ec54f7Sphitran 
920d2ec54f7Sphitran 	return (ACPI_DRV_OK);
921d2ec54f7Sphitran }
922d2ec54f7Sphitran 
923d2ec54f7Sphitran /*
924d2ec54f7Sphitran  * Returns the current power source devices. Used for the AC adapter and is
925d2ec54f7Sphitran  * located under the AC adapter object in name space. Used to determine if
926d2ec54f7Sphitran  * system is running off the AC adapter. This will report that the system is
927d2ec54f7Sphitran  * not running on the AC adapter if any of the batteries in the system is
928d2ec54f7Sphitran  * being forced to discharge through _BMC.
929d2ec54f7Sphitran  *
930d2ec54f7Sphitran  * Return value:
931d2ec54f7Sphitran  *	 0 -- Off-line, ie. battery supplying system power
932d2ec54f7Sphitran  *	 1 -- On-line, ie. AC supplying system power
933d2ec54f7Sphitran  *	-1 -- Unknown, some error ocurred.
934d2ec54f7Sphitran  * Note: It will also update the driver ac state.
935d2ec54f7Sphitran  */
936d2ec54f7Sphitran static int
acpi_drv_get_psr(struct acpi_drv_ac_state * acp)937d2ec54f7Sphitran acpi_drv_get_psr(struct acpi_drv_ac_state *acp)
938d2ec54f7Sphitran {
939d2ec54f7Sphitran 	struct acpi_drv_dev *devp = &acp->dev;
940d2ec54f7Sphitran 	int ac;
941d2ec54f7Sphitran 
942d2ec54f7Sphitran 	if (!devp->valid) {
943d2ec54f7Sphitran 		ACPI_DRV_DBG(CE_WARN, NULL, "device not valid");
944d2ec54f7Sphitran 		return (-1);
945d2ec54f7Sphitran 	}
946d2ec54f7Sphitran 
947d2ec54f7Sphitran 	if (acpica_eval_int(devp->hdl, "_PSR", &ac) == AE_OK) {
948d2ec54f7Sphitran 		ACPI_DRV_DBG(CE_NOTE, devp, "_PSR = %d", ac);
949d2ec54f7Sphitran 		devp->present = ac;
950d2ec54f7Sphitran 	} else {
951d2ec54f7Sphitran 		ACPI_DRV_DBG(CE_WARN, NULL, "AcpiEval _PSR failed");
952d2ec54f7Sphitran 		devp->present = -1;
953d2ec54f7Sphitran 	}
954d2ec54f7Sphitran 
955d2ec54f7Sphitran 	return (ac);
956d2ec54f7Sphitran }
957d2ec54f7Sphitran 
958d2ec54f7Sphitran /*
959d2ec54f7Sphitran  * For most systems, the _STA for this device will always
960d2ec54f7Sphitran  * return a value with bits 0-3 set and will toggle bit 4
961d2ec54f7Sphitran  * to indicate the actual presence of a battery.
962d2ec54f7Sphitran  *
963d2ec54f7Sphitran  * Return value:
964d2ec54f7Sphitran  *	 0 -- battery not present
965d2ec54f7Sphitran  *	 1 -- battery present
966d2ec54f7Sphitran  *	-1 -- Unknown, some error ocurred.
967d2ec54f7Sphitran  * Note: It will also update the driver cbat state.
968d2ec54f7Sphitran  */
969d2ec54f7Sphitran static int
acpi_drv_get_sta(struct acpi_drv_cbat_state * bp)970d2ec54f7Sphitran acpi_drv_get_sta(struct acpi_drv_cbat_state *bp)
971d2ec54f7Sphitran {
972d2ec54f7Sphitran 	struct acpi_drv_dev *devp = &bp->dev;
973d2ec54f7Sphitran 	int val;
974d2ec54f7Sphitran 
975d2ec54f7Sphitran 	if (!devp->valid) {
976d2ec54f7Sphitran 		ACPI_DRV_DBG(CE_WARN, NULL, "device not valid");
977d2ec54f7Sphitran 		return (-1);
978d2ec54f7Sphitran 	}
979d2ec54f7Sphitran 
980d2ec54f7Sphitran 	if (acpica_eval_int(devp->hdl, "_STA", &val) == AE_OK) {
981d2ec54f7Sphitran 		ACPI_DRV_DBG(CE_NOTE, devp, "_STA = 0x%x", val);
982d2ec54f7Sphitran 		devp->present = ((val & STA_FLAG_BATT_PRESENT) != 0);
983d2ec54f7Sphitran 	} else {
984d2ec54f7Sphitran 		ACPI_DRV_DBG(CE_WARN, NULL, "AcpiEval _STA failed");
985d2ec54f7Sphitran 		devp->present = -1;
986d2ec54f7Sphitran 	}
987d2ec54f7Sphitran 
988d2ec54f7Sphitran 	return (val);
989d2ec54f7Sphitran }
990d2ec54f7Sphitran 
991d2ec54f7Sphitran static int
acpi_drv_update_bif(struct acpi_drv_cbat_state * bp)992d2ec54f7Sphitran acpi_drv_update_bif(struct acpi_drv_cbat_state *bp)
993d2ec54f7Sphitran {
994d2ec54f7Sphitran 	ACPI_BUFFER buf;
995d2ec54f7Sphitran 	ACPI_OBJECT *objp;
996d2ec54f7Sphitran 
997d2ec54f7Sphitran 	/* BIF is only available when battery plugged */
998d2ec54f7Sphitran 	ASSERT(bp->dev.present != 0);
999d2ec54f7Sphitran 
1000d2ec54f7Sphitran 	/* Update internal BIF cache */
1001d2ec54f7Sphitran 	bp->bat_bifok = ACPI_DRV_NTF_UNKNOWN;
1002d2ec54f7Sphitran 
1003d2ec54f7Sphitran 	buf.Length = ACPI_ALLOCATE_BUFFER;
1004d2ec54f7Sphitran 	if (ACPI_FAILURE(AcpiEvaluateObjectTyped(bp->dev.hdl, "_BIF",
1005d2ec54f7Sphitran 	    NULL, &buf, ACPI_TYPE_PACKAGE))) {
1006d2ec54f7Sphitran 		ACPI_DRV_DBG(CE_WARN, NULL, "AcpiEval _BIF failed");
1007d2ec54f7Sphitran 		return (ACPI_DRV_ERR);
1008d2ec54f7Sphitran 	}
1009d2ec54f7Sphitran 
1010d2ec54f7Sphitran 	objp = buf.Pointer;
1011d2ec54f7Sphitran 	ACPI_DRV_DBG(CE_NOTE, &bp->dev, "get _BIF");
1012d2ec54f7Sphitran 	if (acpi_drv_obj_copy(objp, (char *)&bp->bif_cache, bif_desc) ==
1013d2ec54f7Sphitran 	    ACPI_DRV_ERR) {
1014d2ec54f7Sphitran 		AcpiOsFree(objp);
1015d2ec54f7Sphitran 		return (ACPI_DRV_ERR);
1016d2ec54f7Sphitran 	}
1017d2ec54f7Sphitran 	AcpiOsFree(objp);
1018d2ec54f7Sphitran 	bp->bat_bifok = ACPI_DRV_NTF_OK;
1019d2ec54f7Sphitran 	return (ACPI_DRV_OK);
1020d2ec54f7Sphitran }
1021d2ec54f7Sphitran 
1022d2ec54f7Sphitran static int
acpi_drv_update_bst(struct acpi_drv_cbat_state * bp)1023d2ec54f7Sphitran acpi_drv_update_bst(struct acpi_drv_cbat_state *bp)
1024d2ec54f7Sphitran {
1025d2ec54f7Sphitran 	ACPI_BUFFER buf;
1026d2ec54f7Sphitran 	ACPI_OBJECT *objp;
1027d2ec54f7Sphitran 
1028d2ec54f7Sphitran 	/* BST is only available when battery plugged */
1029d2ec54f7Sphitran 	ASSERT(bp->dev.present != 0);
1030d2ec54f7Sphitran 
1031d2ec54f7Sphitran 	/* Update internal BST cache */
1032d2ec54f7Sphitran 	bp->bat_bstok = ACPI_DRV_NTF_UNKNOWN;
1033d2ec54f7Sphitran 
1034d2ec54f7Sphitran 	buf.Length = ACPI_ALLOCATE_BUFFER;
1035d2ec54f7Sphitran 	if (ACPI_FAILURE(AcpiEvaluateObjectTyped(bp->dev.hdl, "_BST",
1036d2ec54f7Sphitran 	    NULL, &buf, ACPI_TYPE_PACKAGE))) {
1037d2ec54f7Sphitran 		ACPI_DRV_DBG(CE_WARN, NULL, "AcpiEval _BST failed");
1038d2ec54f7Sphitran 		return (ACPI_DRV_ERR);
1039d2ec54f7Sphitran 	}
1040d2ec54f7Sphitran 
1041d2ec54f7Sphitran 	objp = buf.Pointer;
1042d2ec54f7Sphitran 	ACPI_DRV_DBG(CE_NOTE, &bp->dev, "get _BST");
1043d2ec54f7Sphitran 	if (acpi_drv_obj_copy(objp, (char *)&bp->bst_cache, bst_desc) ==
1044d2ec54f7Sphitran 	    ACPI_DRV_ERR) {
1045d2ec54f7Sphitran 		AcpiOsFree(objp);
1046d2ec54f7Sphitran 		return (ACPI_DRV_ERR);
1047d2ec54f7Sphitran 	}
1048d2ec54f7Sphitran 	AcpiOsFree(objp);
1049d2ec54f7Sphitran 
1050d2ec54f7Sphitran 	if (bp->bst_cache.bst_rate == 0) {
1051d2ec54f7Sphitran 		bp->bst_cache.bst_state &= ~(ACPI_DRV_BST_CHARGING |
1052d2ec54f7Sphitran 		    ACPI_DRV_BST_DISCHARGING);
1053d2ec54f7Sphitran 	}
1054d2ec54f7Sphitran 	bp->bat_bstok = ACPI_DRV_NTF_OK;
1055d2ec54f7Sphitran 	return (ACPI_DRV_OK);
1056d2ec54f7Sphitran }
1057d2ec54f7Sphitran 
1058d2ec54f7Sphitran /*
1059d2ec54f7Sphitran  * Return value:
1060d2ec54f7Sphitran  *	 1 -- device On-line
1061d2ec54f7Sphitran  *	 0 -- device Off-line
1062d2ec54f7Sphitran  *	-1 -- Unknown, some error ocurred.
1063d2ec54f7Sphitran  */
1064d2ec54f7Sphitran static int
acpi_drv_dev_present(struct acpi_drv_dev * devp)1065d2ec54f7Sphitran acpi_drv_dev_present(struct acpi_drv_dev *devp)
1066d2ec54f7Sphitran {
1067d2ec54f7Sphitran 	if (!devp->valid) {
1068d2ec54f7Sphitran 		ACPI_DRV_DBG(CE_WARN, NULL, "device not valid");
1069d2ec54f7Sphitran 		return (-1);
1070d2ec54f7Sphitran 	}
1071d2ec54f7Sphitran 
1072d2ec54f7Sphitran 	ASSERT(devp->type != ACPI_DRV_TYPE_UNKNOWN);
1073d2ec54f7Sphitran 
1074d2ec54f7Sphitran 	/* Update the device state */
1075d2ec54f7Sphitran 	if (devp->present == -1) {
1076d2ec54f7Sphitran 		if (devp->type == ACPI_DRV_TYPE_AC) {
1077d2ec54f7Sphitran 			(void) acpi_drv_get_psr((struct acpi_drv_ac_state *)
1078d2ec54f7Sphitran 			    devp);
1079d2ec54f7Sphitran 		} else if (devp->type == ACPI_DRV_TYPE_CBAT) {
1080d2ec54f7Sphitran 			(void) acpi_drv_get_sta((struct acpi_drv_cbat_state *)
1081d2ec54f7Sphitran 			    devp);
1082d2ec54f7Sphitran 		}
1083d2ec54f7Sphitran 	}
1084d2ec54f7Sphitran 
1085d2ec54f7Sphitran 	return (devp->present);
1086d2ec54f7Sphitran }
1087d2ec54f7Sphitran 
1088d2ec54f7Sphitran /*
1089d2ec54f7Sphitran  * Check if the device p existance state has changed.
1090d2ec54f7Sphitran  * Return value:
1091d2ec54f7Sphitran  *	 1 -- changed
1092d2ec54f7Sphitran  *	 0 -- no change
1093d2ec54f7Sphitran  *	-1 -- unknown
1094d2ec54f7Sphitran  */
1095d2ec54f7Sphitran static int
acpi_drv_update_present(struct acpi_drv_dev * p)1096d2ec54f7Sphitran acpi_drv_update_present(struct acpi_drv_dev *p)
1097d2ec54f7Sphitran {
1098d2ec54f7Sphitran 	int old_present = p->present;
1099d2ec54f7Sphitran 	int new_present;
1100d2ec54f7Sphitran 
1101d2ec54f7Sphitran 	ASSERT(p && p->valid);
1102d2ec54f7Sphitran 
1103d2ec54f7Sphitran 	p->present = -1;
1104d2ec54f7Sphitran 	new_present = acpi_drv_dev_present(p);
1105d2ec54f7Sphitran 	if (new_present == -1) {
1106d2ec54f7Sphitran 		return (-1);
1107d2ec54f7Sphitran 	}
1108d2ec54f7Sphitran 	if (new_present != old_present) {
1109d2ec54f7Sphitran 		return (1);
1110d2ec54f7Sphitran 	}
1111d2ec54f7Sphitran 	return (0);
1112d2ec54f7Sphitran }
1113d2ec54f7Sphitran 
1114d2ec54f7Sphitran static void
acpi_drv_set_psr(struct acpi_drv_dev * p)1115d2ec54f7Sphitran acpi_drv_set_psr(struct acpi_drv_dev *p)
1116d2ec54f7Sphitran {
1117d2ec54f7Sphitran 	acpi_drv_psr_devp = p;
1118d2ec54f7Sphitran 	if (p != NULL) {
1119d2ec54f7Sphitran 		ACPI_DRV_DBG(CE_NOTE, p, "psr = .");
1120d2ec54f7Sphitran 		acpi_drv_psr_type = p->type;
1121d2ec54f7Sphitran 	} else {
1122d2ec54f7Sphitran 		ACPI_DRV_DBG(CE_NOTE, p, "psr = ?");
1123d2ec54f7Sphitran 		acpi_drv_psr_type = ACPI_DRV_TYPE_UNKNOWN;
1124d2ec54f7Sphitran 	}
1125d2ec54f7Sphitran }
1126d2ec54f7Sphitran 
1127d2ec54f7Sphitran /*
1128d2ec54f7Sphitran  * OSPM can determine independent warning and low battery
1129d2ec54f7Sphitran  * capacity values based on the OEM-designed levels, but
1130d2ec54f7Sphitran  * cannot set these values lower than the OEM-designed values.
1131d2ec54f7Sphitran  */
1132d2ec54f7Sphitran static int
acpi_drv_set_warn(acpi_drv_warn_t * bwp)1133d2ec54f7Sphitran acpi_drv_set_warn(acpi_drv_warn_t *bwp)
1134d2ec54f7Sphitran {
1135d2ec54f7Sphitran 	uint32_t warn, low;
1136d2ec54f7Sphitran 
1137d2ec54f7Sphitran 	warn = acpi_drv_syn_last_cap * bwp->bw_charge_warn / 100;
1138d2ec54f7Sphitran 	low = acpi_drv_syn_last_cap * bwp->bw_charge_low / 100;
1139d2ec54f7Sphitran 
1140d2ec54f7Sphitran 	/* Update internal state */
1141d2ec54f7Sphitran 	if (bwp->bw_enabled) {
1142d2ec54f7Sphitran 		if (low >= warn || warn < acpi_drv_syn_oem_warn_cap ||
1143d2ec54f7Sphitran 		    low < acpi_drv_syn_oem_low_cap) {
1144d2ec54f7Sphitran 			ACPI_DRV_DBG(CE_WARN, NULL, "charge level error");
1145d2ec54f7Sphitran 			return (EINVAL);
1146d2ec54f7Sphitran 		}
1147d2ec54f7Sphitran 
1148d2ec54f7Sphitran 		ACPI_DRV_DBG(CE_NOTE, NULL, "set warn: warn=%d low=%d", warn,
1149d2ec54f7Sphitran 		    low);
1150d2ec54f7Sphitran 
1151d2ec54f7Sphitran 		acpi_drv_syn_warn_per = bwp->bw_charge_warn;
1152d2ec54f7Sphitran 		acpi_drv_syn_low_per = bwp->bw_charge_low;
1153d2ec54f7Sphitran 		acpi_drv_syn_warn_cap = warn;
1154d2ec54f7Sphitran 		acpi_drv_syn_low_cap = low;
1155d2ec54f7Sphitran 		acpi_drv_warn_enabled = 1;
1156d2ec54f7Sphitran 	} else {
1157d2ec54f7Sphitran 		acpi_drv_warn_enabled = 0;
1158d2ec54f7Sphitran 	}
1159d2ec54f7Sphitran 
1160d2ec54f7Sphitran 	return (0);
1161d2ec54f7Sphitran }
1162d2ec54f7Sphitran 
1163d2ec54f7Sphitran /*
1164d2ec54f7Sphitran  * Update information for the synthesis battery
1165d2ec54f7Sphitran  *
1166d2ec54f7Sphitran  * Note: Sometimes the value to be returned from _BST or _BIF will be
1167d2ec54f7Sphitran  * temporarily unknown. In this case, the method may return the value
1168d2ec54f7Sphitran  * 0xFFFFFFFF as a placeholder. When the value becomes known, the
1169d2ec54f7Sphitran  * appropriate notification (0x80 for _BST or 0x81 for BIF) should be
1170d2ec54f7Sphitran  * issued, in like manner to any other change in the data returned by
1171d2ec54f7Sphitran  * these methods. This will cause OSPM to re-evaluate the method obtaining
1172d2ec54f7Sphitran  * the correct data value.
1173d2ec54f7Sphitran  */
1174d2ec54f7Sphitran static void
acpi_drv_update_cap(int bif_changed)1175d2ec54f7Sphitran acpi_drv_update_cap(int bif_changed)
1176d2ec54f7Sphitran {
1177d2ec54f7Sphitran 	struct acpi_drv_cbat_state *bp;
1178d2ec54f7Sphitran 
1179d2ec54f7Sphitran 	if (bif_changed != 0) {
1180d2ec54f7Sphitran 		acpi_drv_syn_oem_warn_cap = 0xffffffff;
1181d2ec54f7Sphitran 		acpi_drv_syn_oem_low_cap = 0xffffffff;
1182d2ec54f7Sphitran 		acpi_drv_syn_last_cap = 0xffffffff;
1183d2ec54f7Sphitran 	}
1184d2ec54f7Sphitran 	acpi_drv_syn_last_level = acpi_drv_syn_rem_cap;
1185d2ec54f7Sphitran 	acpi_drv_syn_rem_cap = 0xffffffff; /* initially unknown */
1186d2ec54f7Sphitran 
1187d2ec54f7Sphitran 	for (bp = &acpi_drv_cbat[0]; bp < &acpi_drv_cbat[ACPI_DRV_MAX_BAT_NUM];
1188d2ec54f7Sphitran 	    bp++) {
1189d2ec54f7Sphitran 		if (bp->dev.valid) {
1190d2ec54f7Sphitran 			/* Escape the empty bays */
1191d2ec54f7Sphitran 			if (acpi_drv_cbat_present(bp) <= 0) {
1192d2ec54f7Sphitran 				continue;
1193d2ec54f7Sphitran 			}
1194d2ec54f7Sphitran 
1195d2ec54f7Sphitran 			if (bif_changed != 0 &&
1196d2ec54f7Sphitran 			    bp->bat_bifok == ACPI_DRV_NTF_OK) {
1197d2ec54f7Sphitran 				acpi_bif_t *bif;
1198d2ec54f7Sphitran 
1199d2ec54f7Sphitran 				bif = &bp->bif_cache;
1200d2ec54f7Sphitran 
1201d2ec54f7Sphitran 				if (acpi_drv_syn_last_cap == 0xffffffff) {
1202d2ec54f7Sphitran 					acpi_drv_syn_last_cap = 0;
1203d2ec54f7Sphitran 				}
1204d2ec54f7Sphitran 				acpi_drv_syn_last_cap += bif->bif_last_cap;
1205d2ec54f7Sphitran 
1206d2ec54f7Sphitran 				if (bif->bif_warn_cap == 0xffffffff ||
1207d2ec54f7Sphitran 				    bif->bif_low_cap == 0xffffffff) {
1208d2ec54f7Sphitran 					ACPI_DRV_DBG(CE_WARN, &bp->dev,
1209d2ec54f7Sphitran 					    "BIF value "
1210d2ec54f7Sphitran 					    "invalid, warn_cap=0x%x "
1211d2ec54f7Sphitran 					    "low_cap=0x%x", bif->bif_warn_cap,
1212d2ec54f7Sphitran 					    bif->bif_low_cap);
1213d2ec54f7Sphitran 					continue;
1214d2ec54f7Sphitran 				}
1215d2ec54f7Sphitran 				if (acpi_drv_syn_oem_warn_cap == 0xffffffff) {
1216d2ec54f7Sphitran 					acpi_drv_syn_oem_warn_cap = 0;
1217d2ec54f7Sphitran 				}
1218d2ec54f7Sphitran 				if (acpi_drv_syn_oem_low_cap == 0xffffffff) {
1219d2ec54f7Sphitran 					acpi_drv_syn_oem_low_cap = 0;
1220d2ec54f7Sphitran 				}
1221d2ec54f7Sphitran 
1222d2ec54f7Sphitran 				/*
1223d2ec54f7Sphitran 				 * Use the highest level as the synthesis
1224d2ec54f7Sphitran 				 * level.
1225d2ec54f7Sphitran 				 */
1226d2ec54f7Sphitran 				if (bif->bif_warn_cap >
1227d2ec54f7Sphitran 				    acpi_drv_syn_oem_warn_cap) {
1228d2ec54f7Sphitran 					acpi_drv_syn_oem_low_cap =
1229d2ec54f7Sphitran 					    bif->bif_low_cap;
1230d2ec54f7Sphitran 					acpi_drv_syn_oem_warn_cap =
1231d2ec54f7Sphitran 					    bif->bif_warn_cap;
1232d2ec54f7Sphitran 				}
1233d2ec54f7Sphitran 			}
1234d2ec54f7Sphitran #ifdef DEBUG
1235d2ec54f7Sphitran 			else if (bif_changed) {
1236d2ec54f7Sphitran 				ACPI_DRV_DBG(CE_NOTE, &bp->dev,
1237d2ec54f7Sphitran 				    "BIF not ready");
1238d2ec54f7Sphitran 			}
1239d2ec54f7Sphitran #endif
1240d2ec54f7Sphitran 
1241d2ec54f7Sphitran 			if (bp->bat_bstok == ACPI_DRV_NTF_OK) {
1242d2ec54f7Sphitran 				acpi_bst_t *bst;
1243d2ec54f7Sphitran 
1244d2ec54f7Sphitran 				bst = &bp->bst_cache;
1245d2ec54f7Sphitran 
1246d2ec54f7Sphitran 				/*
1247d2ec54f7Sphitran 				 * Batteries that are rechargeable and are in
1248d2ec54f7Sphitran 				 * the discharging state are required to return
1249d2ec54f7Sphitran 				 * a valid Battery Present Rate value.
1250d2ec54f7Sphitran 				 * 0xFFFFFFFF - Unknown rate/capacity
1251d2ec54f7Sphitran 				 */
1252d2ec54f7Sphitran 				if (bst->bst_rem_cap == 0xffffffff) {
1253d2ec54f7Sphitran 					ACPI_DRV_DBG(CE_WARN, &bp->dev,
1254d2ec54f7Sphitran 					    "BST value invalid, "
1255d2ec54f7Sphitran 					    "rate=0x%x cap=0x%x",
1256d2ec54f7Sphitran 					    bst->bst_rate, bst->bst_rem_cap);
1257d2ec54f7Sphitran 					continue;
1258d2ec54f7Sphitran 				}
1259d2ec54f7Sphitran 
1260d2ec54f7Sphitran 				if (acpi_drv_syn_rem_cap == 0xffffffff) {
1261d2ec54f7Sphitran 					acpi_drv_syn_rem_cap = 0;
1262d2ec54f7Sphitran 				}
1263d2ec54f7Sphitran 				acpi_drv_syn_rem_cap += bst->bst_rem_cap;
1264d2ec54f7Sphitran 				/* Check for overflow */
1265d2ec54f7Sphitran 				ASSERT(acpi_drv_syn_rem_cap >=
1266d2ec54f7Sphitran 				    bst->bst_rem_cap);
1267d2ec54f7Sphitran 			}
1268d2ec54f7Sphitran #ifdef DEBUG
1269d2ec54f7Sphitran 			else {
1270d2ec54f7Sphitran 				ACPI_DRV_DBG(CE_NOTE, &bp->dev,
1271d2ec54f7Sphitran 				    "BST not ready");
1272d2ec54f7Sphitran 			}
1273d2ec54f7Sphitran #endif
1274d2ec54f7Sphitran 		}
1275d2ec54f7Sphitran 	}
1276d2ec54f7Sphitran 
1277d2ec54f7Sphitran 	ACPI_DRV_DBG(CE_NOTE, NULL, "syn_cap: %d syn_oem_warn: %d "
1278d2ec54f7Sphitran 	    "syn_oem_low: %d", acpi_drv_syn_rem_cap, acpi_drv_syn_oem_warn_cap,
1279d2ec54f7Sphitran 	    acpi_drv_syn_oem_low_cap);
1280d2ec54f7Sphitran }
1281d2ec54f7Sphitran 
1282d2ec54f7Sphitran static struct acpi_drv_cbat_state *
acpi_drv_idx2cbat(int idx)1283d2ec54f7Sphitran acpi_drv_idx2cbat(int idx)
1284d2ec54f7Sphitran {
1285d2ec54f7Sphitran 	if (idx >= ACPI_DRV_MAX_BAT_NUM) {
1286d2ec54f7Sphitran 		return (NULL);
1287d2ec54f7Sphitran 	}
1288d2ec54f7Sphitran 	return (&acpi_drv_cbat[idx]);
1289d2ec54f7Sphitran }
1290d2ec54f7Sphitran 
1291d2ec54f7Sphitran static struct acpi_drv_ac_state *
acpi_drv_idx2ac(int idx)1292d2ec54f7Sphitran acpi_drv_idx2ac(int idx)
1293d2ec54f7Sphitran {
1294d2ec54f7Sphitran 	if (idx >= ACPI_DRV_MAX_AC_NUM) {
1295d2ec54f7Sphitran 		return (NULL);
1296d2ec54f7Sphitran 	}
1297d2ec54f7Sphitran 	return (&acpi_drv_ac[idx]);
1298d2ec54f7Sphitran }
1299d2ec54f7Sphitran 
1300d2ec54f7Sphitran /*ARGSUSED*/
1301d2ec54f7Sphitran static void
acpi_drv_cbat_notify(ACPI_HANDLE hdl,UINT32 val,void * ctx)1302d2ec54f7Sphitran acpi_drv_cbat_notify(ACPI_HANDLE hdl, UINT32 val, void *ctx)
1303d2ec54f7Sphitran {
1304d2ec54f7Sphitran 	struct acpi_drv_cbat_state *bp = ctx;
1305d2ec54f7Sphitran 	struct acpi_drv_dev *devp = &bp->dev;
1306d2ec54f7Sphitran 	int bif_changed;
1307d2ec54f7Sphitran 	uint32_t eval;
1308d2ec54f7Sphitran 	char *ev;
1309d2ec54f7Sphitran 	acpi_bst_t *bst;
1310d2ec54f7Sphitran 
1311d2ec54f7Sphitran 	mutex_enter(&acpi_drv_mutex);
1312d2ec54f7Sphitran 	ACPI_DRV_PRT_NOTIFY(hdl, val);
1313d2ec54f7Sphitran 
1314d2ec54f7Sphitran 	switch (val) {
1315d2ec54f7Sphitran 	/*
1316d2ec54f7Sphitran 	 * BST has changed
1317d2ec54f7Sphitran 	 * Whenever the Battery State value changes, the
1318d2ec54f7Sphitran 	 * system will generate an SCI to notify the OS.
1319d2ec54f7Sphitran 	 *
1320d2ec54f7Sphitran 	 * Note: trip point is not used to implement the
1321d2ec54f7Sphitran 	 * warning levels.
1322d2ec54f7Sphitran 	 */
1323d2ec54f7Sphitran 	case 0x80:
1324d2ec54f7Sphitran 		/*
1325d2ec54f7Sphitran 		 * We always get 0x80 and 0x81 at battery plug/unplug,
1326d2ec54f7Sphitran 		 * but 0x80 may come first. In case that situation, we have
1327d2ec54f7Sphitran 		 * to update battery present state here too to update bst
1328d2ec54f7Sphitran 		 * correctly.
1329d2ec54f7Sphitran 		 */
1330d2ec54f7Sphitran 		bif_changed = acpi_drv_update_present(devp);
1331d2ec54f7Sphitran 
1332d2ec54f7Sphitran 		if (devp->present == 0) {
133310702807SPhi Tran 			if (acpi_drv_psr_devp == devp) {
133410702807SPhi Tran 				acpi_drv_set_psr(NULL);
133510702807SPhi Tran 			}
133610702807SPhi Tran 			goto done;
1337d2ec54f7Sphitran 		}
1338d2ec54f7Sphitran 
1339d2ec54f7Sphitran 		if (acpi_drv_update_bst(bp) != ACPI_DRV_OK) {
1340d2ec54f7Sphitran 			break;
1341d2ec54f7Sphitran 		}
1342d2ec54f7Sphitran 		acpi_drv_update_cap(bif_changed);
1343d2ec54f7Sphitran 
1344d2ec54f7Sphitran 		bst = &bp->bst_cache;
1345d2ec54f7Sphitran 		eval = bst->bst_rem_cap;
1346d2ec54f7Sphitran 
1347d2ec54f7Sphitran 		if (bst->bst_state & BST_FLAG_DISCHARGING) {
1348d2ec54f7Sphitran 			acpi_drv_set_psr(devp);
1349d2ec54f7Sphitran 		}
1350d2ec54f7Sphitran 		/*
1351d2ec54f7Sphitran 		 * The Critical battery state indicates that all
1352d2ec54f7Sphitran 		 * available batteries are discharged and do not
1353d2ec54f7Sphitran 		 * appear to be able to supply power to run the
1354d2ec54f7Sphitran 		 * system any longer. When this occurs, the OS
1355d2ec54f7Sphitran 		 * should attempt to perform an emergency shutdown.
1356d2ec54f7Sphitran 		 * Right now we do not shutdown.  This would
1357d2ec54f7Sphitran 		 * need some discussion first since it could be
1358d2ec54f7Sphitran 		 * controversial.
1359d2ec54f7Sphitran 		 */
1360d2ec54f7Sphitran #ifdef DEBUG
1361d2ec54f7Sphitran 		if (bst->bst_state & BST_FLAG_CRITICAL) {
1362d2ec54f7Sphitran 			ACPI_DRV_DBG(CE_WARN, devp, "BST_FLAG_CRITICAL set");
1363d2ec54f7Sphitran 
1364d2ec54f7Sphitran 			/*
1365d2ec54f7Sphitran 			 * BST_FLAG_CRITICAL may set even with AC,
1366d2ec54f7Sphitran 			 * plugged, when plug/unplug battery. Check
1367d2ec54f7Sphitran 			 * to avoid erroneous shutdown.
1368d2ec54f7Sphitran 			 */
1369d2ec54f7Sphitran 			if (acpi_drv_psr_devp == devp &&
1370d2ec54f7Sphitran 			    bst->bst_rem_cap != 0xffffffff) {
1371d2ec54f7Sphitran 				ACPI_DRV_DBG(CE_WARN, NULL,
1372d2ec54f7Sphitran 				    "Battery in critical state");
1373d2ec54f7Sphitran 			}
1374d2ec54f7Sphitran 		} else
1375d2ec54f7Sphitran #endif
1376d2ec54f7Sphitran 		if (acpi_drv_warn_enabled &&
1377d2ec54f7Sphitran 		    (bst->bst_state & BST_FLAG_DISCHARGING)) {
1378d2ec54f7Sphitran 			/*
1379d2ec54f7Sphitran 			 * This value is an estimation of the amount of
1380d2ec54f7Sphitran 			 * energy or battery capacity required by the
1381d2ec54f7Sphitran 			 * system to transition to any supported sleeping
1382d2ec54f7Sphitran 			 * state. When the OS detects that the total
1383d2ec54f7Sphitran 			 * available battery capacity is less than this
1384d2ec54f7Sphitran 			 * value, it will transition the system to a user
1385d2ec54f7Sphitran 			 * defined system state (S1-S5).
1386d2ec54f7Sphitran 			 */
1387d2ec54f7Sphitran 			if (acpi_drv_syn_last_level > acpi_drv_syn_low_cap &&
1388d2ec54f7Sphitran 			    acpi_drv_syn_rem_cap <= acpi_drv_syn_low_cap) {
1389d2ec54f7Sphitran 				acpi_drv_gen_sysevent(devp, ESC_PWRCTL_LOW,
1390d2ec54f7Sphitran 				    eval);
1391d2ec54f7Sphitran 			/*
1392d2ec54f7Sphitran 			 * When the total available energy (mWh) or capacity
1393d2ec54f7Sphitran 			 * (mAh) in the batteries falls below this level,
1394d2ec54f7Sphitran 			 * the OS will notify the user through the UI.
1395d2ec54f7Sphitran 			 */
1396d2ec54f7Sphitran 			} else if (acpi_drv_syn_last_level >
1397d2ec54f7Sphitran 			    acpi_drv_syn_warn_cap &&
1398d2ec54f7Sphitran 			    acpi_drv_syn_rem_cap <= acpi_drv_syn_warn_cap) {
1399d2ec54f7Sphitran 				acpi_drv_gen_sysevent(devp, ESC_PWRCTL_WARN,
1400d2ec54f7Sphitran 				    eval);
1401d2ec54f7Sphitran 			}
1402d2ec54f7Sphitran 		}
1403d2ec54f7Sphitran 
140410702807SPhi Tran done:
1405d2ec54f7Sphitran 		acpi_drv_gen_sysevent(devp, ESC_PWRCTL_STATE_CHANGE, 0);
1406d2ec54f7Sphitran 		pollwakeup(&acpi_drv_pollhead, ACPI_DRV_EVENTS);
1407d2ec54f7Sphitran 		break;
1408d2ec54f7Sphitran 
140928b6fd27SHans Rosenfeld 	/* battery has been removed completely */
141028b6fd27SHans Rosenfeld 	case 0x03:
1411d2ec54f7Sphitran 	/* BIF has changed */
1412d2ec54f7Sphitran 	case 0x81:
1413d2ec54f7Sphitran 		/*
1414d2ec54f7Sphitran 		 * Note: Do not eliminate multiple ADD/REMOVE here,
1415d2ec54f7Sphitran 		 * because they may corresponding to different batterys.
1416d2ec54f7Sphitran 		 */
1417d2ec54f7Sphitran 		(void) acpi_drv_update_present(devp);
1418d2ec54f7Sphitran 		if (devp->present == 1) {
1419d2ec54f7Sphitran 			if (acpi_drv_update_bif(bp) != ACPI_DRV_OK) {
1420d2ec54f7Sphitran 				break;
1421d2ec54f7Sphitran 			}
1422d2ec54f7Sphitran 		}
1423d2ec54f7Sphitran 
1424d2ec54f7Sphitran 		acpi_drv_update_cap(1);
1425d2ec54f7Sphitran 
1426d2ec54f7Sphitran 		eval = devp->present;
1427d2ec54f7Sphitran 		ev = eval ? ESC_PWRCTL_ADD : ESC_PWRCTL_REMOVE;
1428d2ec54f7Sphitran 		acpi_drv_gen_sysevent(devp, ev, 0);
1429d2ec54f7Sphitran 		pollwakeup(&acpi_drv_pollhead, ACPI_DRV_EVENTS);
1430d2ec54f7Sphitran 		break;
1431d2ec54f7Sphitran 
1432d2ec54f7Sphitran 	case 0x82:
1433d2ec54f7Sphitran 	default:
1434d2ec54f7Sphitran 		break;
1435d2ec54f7Sphitran 	}
1436d2ec54f7Sphitran 
1437d2ec54f7Sphitran 	mutex_exit(&acpi_drv_mutex);
1438d2ec54f7Sphitran }
1439d2ec54f7Sphitran 
1440d2ec54f7Sphitran static int
acpi_drv_update_lid(struct acpi_drv_dev * p)1441d2ec54f7Sphitran acpi_drv_update_lid(struct acpi_drv_dev *p)
1442d2ec54f7Sphitran {
1443d2ec54f7Sphitran 	struct acpi_drv_lid_state *lp = (struct acpi_drv_lid_state *)p;
1444d2ec54f7Sphitran 
1445d2ec54f7Sphitran 	if (acpica_eval_int(p->hdl, "_LID", &lp->state) == AE_OK) {
1446d2ec54f7Sphitran 		lp->state_ok = ACPI_DRV_NTF_OK;
1447d2ec54f7Sphitran 		return (ACPI_DRV_OK);
1448d2ec54f7Sphitran 	}
1449d2ec54f7Sphitran 	return (ACPI_DRV_ERR);
1450d2ec54f7Sphitran }
1451d2ec54f7Sphitran 
1452d2ec54f7Sphitran /*ARGSUSED*/
1453d2ec54f7Sphitran static void
acpi_drv_ac_notify(ACPI_HANDLE hdl,UINT32 val,void * ctx)1454d2ec54f7Sphitran acpi_drv_ac_notify(ACPI_HANDLE hdl, UINT32 val, void *ctx)
1455d2ec54f7Sphitran {
1456d2ec54f7Sphitran 	struct acpi_drv_ac_state *acp = ctx;
1457d2ec54f7Sphitran 	struct acpi_drv_dev *devp = &acp->dev;
1458d2ec54f7Sphitran 	int old_present;
1459d2ec54f7Sphitran 	char *ev;
1460d2ec54f7Sphitran 	int eval;
1461d2ec54f7Sphitran 
1462d2ec54f7Sphitran 	ACPI_DRV_PRT_NOTIFY(hdl, val);
1463d2ec54f7Sphitran 	if (val != 0x80) {
1464d2ec54f7Sphitran 		return;
1465d2ec54f7Sphitran 	}
1466d2ec54f7Sphitran 
1467d2ec54f7Sphitran 	mutex_enter(&acpi_drv_mutex);
1468d2ec54f7Sphitran 	/*
1469d2ec54f7Sphitran 	 * Note: if unplug and then quickly plug back, two ADD
1470d2ec54f7Sphitran 	 * events will be generated.
1471d2ec54f7Sphitran 	 */
1472d2ec54f7Sphitran 	old_present = devp->present;
1473d2ec54f7Sphitran 	eval = acpi_drv_get_psr(acp);
1474d2ec54f7Sphitran 
1475d2ec54f7Sphitran 	/* Eliminate redundant events */
1476d2ec54f7Sphitran 	if (eval != -1 && eval != old_present) {
1477d2ec54f7Sphitran 		/* Keep tracking the current power source device */
1478d2ec54f7Sphitran 		if (eval == 1) {
1479d2ec54f7Sphitran 			ev = ESC_PWRCTL_ADD;
1480d2ec54f7Sphitran 			acpi_drv_set_psr(devp);
1481d2ec54f7Sphitran 		} else {
1482d2ec54f7Sphitran 			ev = ESC_PWRCTL_REMOVE;
1483d2ec54f7Sphitran 			/* If AC was supplying the power, it's not now */
1484d2ec54f7Sphitran 			if (acpi_drv_psr_devp == devp) {
1485d2ec54f7Sphitran 				acpi_drv_set_psr(NULL);
1486d2ec54f7Sphitran 			}
1487d2ec54f7Sphitran 		}
1488d2ec54f7Sphitran 
1489d2ec54f7Sphitran 		acpi_drv_gen_sysevent(devp, ev, 0);
1490d2ec54f7Sphitran 		pollwakeup(&acpi_drv_pollhead, ACPI_DRV_EVENTS);
1491d2ec54f7Sphitran 	}
1492d2ec54f7Sphitran 
1493d2ec54f7Sphitran 	mutex_exit(&acpi_drv_mutex);
1494d2ec54f7Sphitran }
1495d2ec54f7Sphitran 
1496d2ec54f7Sphitran static void
acpi_drv_lid_notify(ACPI_HANDLE hdl,UINT32 val,void * ctx)1497d2ec54f7Sphitran acpi_drv_lid_notify(ACPI_HANDLE hdl, UINT32 val, void *ctx)
1498d2ec54f7Sphitran {
1499d2ec54f7Sphitran 	struct acpi_drv_lid_state *p = ctx;
1500d2ec54f7Sphitran 
1501d2ec54f7Sphitran 	ACPI_DRV_PRT_NOTIFY(hdl, val);
1502d2ec54f7Sphitran 	if (val == 0x80) {
1503d2ec54f7Sphitran 		mutex_enter(&acpi_drv_mutex);
1504d2ec54f7Sphitran 		if (acpi_drv_update_lid(&p->dev) == ACPI_DRV_OK) {
1505d2ec54f7Sphitran 			acpi_drv_gen_sysevent(&p->dev, p->state ?
1506d2ec54f7Sphitran 			    ESC_PWRCTL_ADD : ESC_PWRCTL_REMOVE, 0);
1507d2ec54f7Sphitran 		}
1508d2ec54f7Sphitran 		mutex_exit(&acpi_drv_mutex);
1509d2ec54f7Sphitran 	}
1510d2ec54f7Sphitran }
1511d2ec54f7Sphitran 
1512d2ec54f7Sphitran static int
acpi_drv_obj_init(struct acpi_drv_dev * p)1513d2ec54f7Sphitran acpi_drv_obj_init(struct acpi_drv_dev *p)
1514d2ec54f7Sphitran {
1515d2ec54f7Sphitran 	ACPI_DEVICE_INFO *info;
1516d2ec54f7Sphitran 	ACPI_NOTIFY_HANDLER ntf_handler = NULL;
1517d2ec54f7Sphitran 	ACPI_STATUS ret;
151828b6fd27SHans Rosenfeld 	char name[KSTAT_STRLEN];
1519d2ec54f7Sphitran 
1520d2ec54f7Sphitran 	ASSERT(p != NULL && p->hdl != NULL);
1521d2ec54f7Sphitran 
1522d2ec54f7Sphitran 	p->valid = 0;
1523d2ec54f7Sphitran 
1524d2ec54f7Sphitran 	/* Info size is variable depending on existance of _CID */
152557190917SDana Myers 	ret = AcpiGetObjectInfo(p->hdl, &info);
1526d2ec54f7Sphitran 	if (ACPI_FAILURE(ret)) {
1527d2ec54f7Sphitran 		ACPI_DRV_DBG(CE_WARN, NULL,
1528d2ec54f7Sphitran 		    "AcpiGetObjectInfo() fail: %d", (int32_t)ret);
1529d2ec54f7Sphitran 		return (ACPI_DRV_ERR);
1530d2ec54f7Sphitran 	}
1531d2ec54f7Sphitran 
1532d2ec54f7Sphitran 	if ((info->Valid & ACPI_VALID_HID) == 0) {
1533d2ec54f7Sphitran 		ACPI_DRV_DBG(CE_WARN, NULL,
1534d2ec54f7Sphitran 		    "AcpiGetObjectInfo(): _HID not available");
1535a3114836SGerry Liu 		p->hid[0] = 0;
1536d2ec54f7Sphitran 	} else {
1537a3114836SGerry Liu 		(void) strlcpy(p->hid, info->HardwareId.String, ID_LEN);
1538d2ec54f7Sphitran 	}
1539d2ec54f7Sphitran 
1540d2ec54f7Sphitran 	/*
1541d2ec54f7Sphitran 	 * This object is optional, but is required when the device
1542d2ec54f7Sphitran 	 * has no other way to report a persistent unique device ID.
1543d2ec54f7Sphitran 	 */
1544d2ec54f7Sphitran 	if ((info->Valid & ACPI_VALID_UID) == 0) {
1545d2ec54f7Sphitran 		ACPI_DRV_DBG(CE_WARN, NULL,
1546d2ec54f7Sphitran 		    "AcpiGetObjectInfo(): _UID not available");
1547d2ec54f7Sphitran 		/* Use 0 as the default _UID */
1548a3114836SGerry Liu 		p->uid[0] = 0;
1549d2ec54f7Sphitran 	} else {
1550a3114836SGerry Liu 		(void) strlcpy(p->uid, info->UniqueId.String, ID_LEN);
1551d2ec54f7Sphitran 	}
1552d2ec54f7Sphitran 
155357190917SDana Myers 	AcpiOsFree(info);
1554d2ec54f7Sphitran 	p->valid = 1;
1555d2ec54f7Sphitran 
1556d2ec54f7Sphitran 	if (strcmp(p->hid, ACPI_DEVNAME_CBAT) == 0) {
1557d2ec54f7Sphitran 		struct acpi_drv_cbat_state *bp =
1558d2ec54f7Sphitran 		    (struct acpi_drv_cbat_state *)p;
155928b6fd27SHans Rosenfeld 		kstat_t *ksp;
1560d2ec54f7Sphitran 
1561d2ec54f7Sphitran 		p->type = ACPI_DRV_TYPE_CBAT;
1562d2ec54f7Sphitran 		p->index = nbat - 1;
1563d2ec54f7Sphitran 
1564d2ec54f7Sphitran 		/* Update device present state */
1565d2ec54f7Sphitran 		(void) acpi_drv_update_present(p);
1566d2ec54f7Sphitran 		if (p->present) {
1567d2ec54f7Sphitran 			(void) acpi_drv_update_bif(bp);
1568d2ec54f7Sphitran 			(void) acpi_drv_update_bst(bp);
1569d2ec54f7Sphitran 
1570d2ec54f7Sphitran 			/* Init the current power source */
1571d2ec54f7Sphitran 			if (bp->bst_cache.bst_state & BST_FLAG_DISCHARGING) {
1572d2ec54f7Sphitran 				acpi_drv_set_psr(p);
1573d2ec54f7Sphitran 			}
1574d2ec54f7Sphitran 		}
1575d2ec54f7Sphitran 		ntf_handler = acpi_drv_cbat_notify;
1576d2ec54f7Sphitran 		ACPI_DRV_DBG(CE_NOTE, p, "battery %s",
1577d2ec54f7Sphitran 		    (p->present ? "present" : "absent"));
157828b6fd27SHans Rosenfeld 
157928b6fd27SHans Rosenfeld 		/* Create minor node for battery */
158028b6fd27SHans Rosenfeld 		(void) snprintf(name, sizeof (name), "battery%d", p->index);
158128b6fd27SHans Rosenfeld 		if (ddi_create_minor_node(acpi_drv_dip, name, S_IFCHR,
158228b6fd27SHans Rosenfeld 		    MINOR_BATT(p->index), DDI_PSEUDO, 0) == DDI_FAILURE)
158328b6fd27SHans Rosenfeld 			ACPI_DRV_DBG(CE_WARN, NULL,
158428b6fd27SHans Rosenfeld 			    "%s: minor node create failed", name);
158528b6fd27SHans Rosenfeld 
158628b6fd27SHans Rosenfeld 		/*
158728b6fd27SHans Rosenfeld 		 * Allocate, initialize and install BIF and BST kstat
158828b6fd27SHans Rosenfeld 		 */
158928b6fd27SHans Rosenfeld 		/* BIF kstat */
159028b6fd27SHans Rosenfeld 		(void) snprintf(name, KSTAT_STRLEN-1, "%s%d",
159128b6fd27SHans Rosenfeld 		    ACPI_DRV_BIF_KSTAT_NAME, bp->dev.index);
159228b6fd27SHans Rosenfeld 		ksp = kstat_create(ACPI_DRV_NAME, 0, name, "misc",
159328b6fd27SHans Rosenfeld 		    KSTAT_TYPE_NAMED,
159428b6fd27SHans Rosenfeld 		    sizeof (acpi_drv_bif_kstat) / sizeof (kstat_named_t),
159528b6fd27SHans Rosenfeld 		    KSTAT_FLAG_VIRTUAL);
159628b6fd27SHans Rosenfeld 		if (ksp != NULL) {
159728b6fd27SHans Rosenfeld 			ACPI_DRV_DBG(CE_NOTE, NULL, "kstat_create(%s) ok",
159828b6fd27SHans Rosenfeld 			    name);
159928b6fd27SHans Rosenfeld 
160028b6fd27SHans Rosenfeld 			bp->bat_bif_ksp = ksp;
160128b6fd27SHans Rosenfeld 			ksp->ks_data = &acpi_drv_bif_kstat;
160228b6fd27SHans Rosenfeld 			ksp->ks_update = acpi_drv_kstat_bif_update;
160328b6fd27SHans Rosenfeld 			ksp->ks_data_size += MAXNAMELEN * 4;
160428b6fd27SHans Rosenfeld 			ksp->ks_private = bp;
160528b6fd27SHans Rosenfeld 
160628b6fd27SHans Rosenfeld 			kstat_install(ksp);
160728b6fd27SHans Rosenfeld 		} else {
160828b6fd27SHans Rosenfeld 			ACPI_DRV_DBG(CE_WARN, NULL,
160928b6fd27SHans Rosenfeld 			    "kstat_create(%s) fail", name);
161028b6fd27SHans Rosenfeld 		}
161128b6fd27SHans Rosenfeld 
161228b6fd27SHans Rosenfeld 		/* BST kstat */
161328b6fd27SHans Rosenfeld 		(void) snprintf(name, KSTAT_STRLEN-1, "%s%d",
161428b6fd27SHans Rosenfeld 		    ACPI_DRV_BST_KSTAT_NAME, bp->dev.index);
161528b6fd27SHans Rosenfeld 		ksp = kstat_create(ACPI_DRV_NAME, 0, name, "misc",
161628b6fd27SHans Rosenfeld 		    KSTAT_TYPE_NAMED,
161728b6fd27SHans Rosenfeld 		    sizeof (acpi_drv_bst_kstat) / sizeof (kstat_named_t),
161828b6fd27SHans Rosenfeld 		    KSTAT_FLAG_VIRTUAL);
161928b6fd27SHans Rosenfeld 		if (ksp != NULL) {
162028b6fd27SHans Rosenfeld 			ACPI_DRV_DBG(CE_NOTE, NULL, "kstat_create(%s) ok",
162128b6fd27SHans Rosenfeld 			    name);
162228b6fd27SHans Rosenfeld 
162328b6fd27SHans Rosenfeld 			bp->bat_bst_ksp = ksp;
162428b6fd27SHans Rosenfeld 			ksp->ks_data = &acpi_drv_bst_kstat;
162528b6fd27SHans Rosenfeld 			ksp->ks_update = acpi_drv_kstat_bst_update;
162628b6fd27SHans Rosenfeld 			ksp->ks_data_size += MAXNAMELEN * 4;
162728b6fd27SHans Rosenfeld 			ksp->ks_private = bp;
162828b6fd27SHans Rosenfeld 
162928b6fd27SHans Rosenfeld 			kstat_install(ksp);
163028b6fd27SHans Rosenfeld 		} else {
163128b6fd27SHans Rosenfeld 			ACPI_DRV_DBG(CE_WARN, NULL,
163228b6fd27SHans Rosenfeld 			    "kstat_create(%s) fail", name);
163328b6fd27SHans Rosenfeld 		}
1634d2ec54f7Sphitran 	} else if (strcmp(p->hid, ACPI_DEVNAME_AC) == 0) {
1635d2ec54f7Sphitran 		p->type = ACPI_DRV_TYPE_AC;
1636d2ec54f7Sphitran 		p->index = nac - 1;
1637d2ec54f7Sphitran 
1638d2ec54f7Sphitran 		/* Update device present state */
1639d2ec54f7Sphitran 		(void) acpi_drv_update_present(p);
1640d2ec54f7Sphitran 		if (p->present) {
1641d2ec54f7Sphitran 			/* Init the current power source */
1642d2ec54f7Sphitran 			acpi_drv_set_psr(p);
1643d2ec54f7Sphitran 		}
1644d2ec54f7Sphitran 		ntf_handler = acpi_drv_ac_notify;
1645d2ec54f7Sphitran 		ACPI_DRV_DBG(CE_NOTE, p, "AC %s",
1646d2ec54f7Sphitran 		    (p->present ? "on-line" : "off-line"));
164728b6fd27SHans Rosenfeld 
164828b6fd27SHans Rosenfeld 		/* Create minor node for AC */
164928b6fd27SHans Rosenfeld 		(void) snprintf(name, sizeof (name), "ac%d", p->index);
165028b6fd27SHans Rosenfeld 		if (ddi_create_minor_node(acpi_drv_dip, name, S_IFCHR,
165128b6fd27SHans Rosenfeld 		    MINOR_AC(p->index), DDI_PSEUDO, 0) == DDI_FAILURE)
165228b6fd27SHans Rosenfeld 			ACPI_DRV_DBG(CE_WARN, NULL,
165328b6fd27SHans Rosenfeld 			    "%s: minor node create failed", name);
1654d2ec54f7Sphitran 	} else if (strcmp(p->hid, ACPI_DEVNAME_LID) == 0) {
1655d2ec54f7Sphitran 		p->type = ACPI_DRV_TYPE_LID;
1656630ff078Sphitran 		p->index = 0;
1657d2ec54f7Sphitran 		lid.state_ok = ACPI_DRV_NTF_UNKNOWN;
1658d2ec54f7Sphitran 		(void) acpi_drv_update_lid(p);
1659d2ec54f7Sphitran 		ntf_handler = acpi_drv_lid_notify;
1660d2ec54f7Sphitran 		ACPI_DRV_DBG(CE_NOTE, p, "added");
166128b6fd27SHans Rosenfeld 
166228b6fd27SHans Rosenfeld 		/* Create minor node for lid. */
166328b6fd27SHans Rosenfeld 		if (ddi_create_minor_node(acpi_drv_dip, "lid", S_IFCHR,
166428b6fd27SHans Rosenfeld 		    MINOR_LID(p->index), DDI_PSEUDO, 0) == DDI_FAILURE)
166528b6fd27SHans Rosenfeld 			ACPI_DRV_DBG(CE_WARN, NULL,
166628b6fd27SHans Rosenfeld 			    "lid: minor node create failed");
1667d2ec54f7Sphitran 	} else {
1668d2ec54f7Sphitran 		ACPI_DRV_DBG(CE_NOTE, p, "unknown device");
1669d2ec54f7Sphitran 		p->valid = 0;
1670d2ec54f7Sphitran 	}
1671d2ec54f7Sphitran 
1672d2ec54f7Sphitran 	/* Register ACPI battery related events */
1673d2ec54f7Sphitran 	if (ntf_handler != NULL) {
1674d2ec54f7Sphitran 		if (ACPI_FAILURE(AcpiInstallNotifyHandler(p->hdl,
1675d2ec54f7Sphitran 		    ACPI_ALL_NOTIFY, ntf_handler, p))) {
1676d2ec54f7Sphitran 			ACPI_DRV_DBG(CE_NOTE, NULL,
1677d2ec54f7Sphitran 			    "Notify handler for %s.%s install failed",
1678d2ec54f7Sphitran 			    p->hid, p->uid);
1679d2ec54f7Sphitran 			return (ACPI_DRV_ERR);
1680d2ec54f7Sphitran 		}
1681d2ec54f7Sphitran 	}
1682d2ec54f7Sphitran 
1683d2ec54f7Sphitran 	return (ACPI_DRV_OK);
1684d2ec54f7Sphitran }
1685d2ec54f7Sphitran 
1686d2ec54f7Sphitran /*ARGSUSED*/
1687d2ec54f7Sphitran static ACPI_STATUS
acpi_drv_find_cb(ACPI_HANDLE ObjHandle,UINT32 NestingLevel,void * Context,void ** ReturnValue)1688d2ec54f7Sphitran acpi_drv_find_cb(ACPI_HANDLE ObjHandle, UINT32 NestingLevel, void *Context,
1689d2ec54f7Sphitran     void **ReturnValue)
1690d2ec54f7Sphitran {
1691630ff078Sphitran 	struct acpi_drv_dev *devp;
1692630ff078Sphitran 	int *type = (int *)Context;
1693d2ec54f7Sphitran 
1694630ff078Sphitran 	if (*type == ACPI_DRV_TYPE_CBAT) {
1695d2ec54f7Sphitran 		struct acpi_drv_cbat_state *bp;
1696d2ec54f7Sphitran 
169728b6fd27SHans Rosenfeld 		for (bp = acpi_drv_cbat;
169828b6fd27SHans Rosenfeld 		    bp != &acpi_drv_cbat[ACPI_DRV_MAX_BAT_NUM];
169928b6fd27SHans Rosenfeld 		    bp++)
170028b6fd27SHans Rosenfeld 			if (bp->dev.hdl == ObjHandle)
170128b6fd27SHans Rosenfeld 				return (AE_OK);
170228b6fd27SHans Rosenfeld 
1703d2ec54f7Sphitran 		if (nbat == ACPI_DRV_MAX_BAT_NUM) {
1704d2ec54f7Sphitran 			ACPI_DRV_DBG(CE_WARN, NULL,
1705d2ec54f7Sphitran 			    "Need to support more batteries: "
1706d2ec54f7Sphitran 			    "BATTERY_MAX = %d", ACPI_DRV_MAX_BAT_NUM);
1707d2ec54f7Sphitran 			return (AE_LIMIT);
1708d2ec54f7Sphitran 		}
1709d2ec54f7Sphitran 		bp = &acpi_drv_cbat[nbat++];
1710d2ec54f7Sphitran 		devp = (struct acpi_drv_dev *)bp;
1711630ff078Sphitran 	} else if (*type == ACPI_DRV_TYPE_AC) {
1712d2ec54f7Sphitran 		struct acpi_drv_ac_state *ap;
1713d2ec54f7Sphitran 
171428b6fd27SHans Rosenfeld 		for (ap = acpi_drv_ac;
171528b6fd27SHans Rosenfeld 		    ap != &acpi_drv_ac[ACPI_DRV_MAX_AC_NUM];
171628b6fd27SHans Rosenfeld 		    ap++)
171728b6fd27SHans Rosenfeld 			if (ap->dev.hdl == ObjHandle)
171828b6fd27SHans Rosenfeld 				return (AE_OK);
171928b6fd27SHans Rosenfeld 
1720d2ec54f7Sphitran 		if (nac == ACPI_DRV_MAX_AC_NUM) {
1721d2ec54f7Sphitran 			ACPI_DRV_DBG(CE_WARN, NULL, "Need to support more ACs: "
1722d2ec54f7Sphitran 			    "AC_MAX = %d", ACPI_DRV_MAX_AC_NUM);
1723d2ec54f7Sphitran 			return (AE_LIMIT);
1724d2ec54f7Sphitran 		}
1725d2ec54f7Sphitran 		ap = &acpi_drv_ac[nac++];
1726d2ec54f7Sphitran 		devp = (struct acpi_drv_dev *)ap;
1727630ff078Sphitran 	} else if (*type == ACPI_DRV_TYPE_LID) {
1728d2ec54f7Sphitran 		struct acpi_drv_lid_state *lp;
1729d2ec54f7Sphitran 
1730d2ec54f7Sphitran 		lp = &lid;
173128b6fd27SHans Rosenfeld 		if (lp->dev.hdl == ObjHandle)
173228b6fd27SHans Rosenfeld 			return (AE_OK);
173328b6fd27SHans Rosenfeld 
173428b6fd27SHans Rosenfeld 		nlid++;
1735d2ec54f7Sphitran 		devp = (struct acpi_drv_dev *)lp;
1736d2ec54f7Sphitran 	} else {
1737d2ec54f7Sphitran 		ACPI_DRV_DBG(CE_WARN, NULL, "acpi_drv_find_cb(): "
1738d2ec54f7Sphitran 		    "Unknown device");
1739d2ec54f7Sphitran 		return (AE_ERROR);
1740d2ec54f7Sphitran 	}
1741d2ec54f7Sphitran 
1742d2ec54f7Sphitran 	devp->hdl = ObjHandle;
1743d2ec54f7Sphitran 
1744d2ec54f7Sphitran 	/* Try to get as many working objs as possible */
1745d2ec54f7Sphitran 	(void) acpi_drv_obj_init(devp);
1746d2ec54f7Sphitran 	return (AE_OK);
1747d2ec54f7Sphitran }
1748d2ec54f7Sphitran 
174928b6fd27SHans Rosenfeld /*ARGSUSED*/
175028b6fd27SHans Rosenfeld static void
acpi_drv_cbat_rescan(void * arg)175128b6fd27SHans Rosenfeld acpi_drv_cbat_rescan(void *arg)
175228b6fd27SHans Rosenfeld {
175328b6fd27SHans Rosenfeld 	int *retp, type = ACPI_DRV_TYPE_CBAT;
175428b6fd27SHans Rosenfeld 
175528b6fd27SHans Rosenfeld 	mutex_enter(&acpi_drv_mutex);
175628b6fd27SHans Rosenfeld 
175728b6fd27SHans Rosenfeld 	/*
175828b6fd27SHans Rosenfeld 	 * The detach routine clears the timeout id to tell us not to
175928b6fd27SHans Rosenfeld 	 * reschedule ourselves. If thats the case there's also no point
176028b6fd27SHans Rosenfeld 	 * in looking for new ACPI battery devices, so just return.
176128b6fd27SHans Rosenfeld 	 */
176228b6fd27SHans Rosenfeld 	if (acpi_drv_cbat_rescan_timeout == 0) {
176328b6fd27SHans Rosenfeld 		mutex_exit(&acpi_drv_mutex);
176428b6fd27SHans Rosenfeld 		return;
176528b6fd27SHans Rosenfeld 	}
176628b6fd27SHans Rosenfeld 
176728b6fd27SHans Rosenfeld 	(void) AcpiGetDevices(ACPI_DEVNAME_CBAT, acpi_drv_find_cb, &type,
176828b6fd27SHans Rosenfeld 	    (void *)&retp);
176928b6fd27SHans Rosenfeld 
177028b6fd27SHans Rosenfeld 	acpi_drv_cbat_rescan_timeout = timeout(acpi_drv_cbat_rescan, NULL,
177128b6fd27SHans Rosenfeld 	    drv_usectohz(MICROSEC));
177228b6fd27SHans Rosenfeld 	mutex_exit(&acpi_drv_mutex);
177328b6fd27SHans Rosenfeld }
177428b6fd27SHans Rosenfeld 
1775d2ec54f7Sphitran static int
acpi_drv_acpi_init(void)177628b6fd27SHans Rosenfeld acpi_drv_acpi_init(void)
1777d2ec54f7Sphitran {
1778630ff078Sphitran 	int *retp, type;
1779630ff078Sphitran 	int status = ACPI_DRV_ERR;
17802d6b5ea7SGuoli Shu 	hotkey_drv_t *htkp;
1781d2ec54f7Sphitran 
1782d2ec54f7Sphitran 	/* Check to see if ACPI CA services are available */
1783d2ec54f7Sphitran 	if (AcpiSubsystemStatus() != AE_OK) {
1784d2ec54f7Sphitran 		ACPI_DRV_DBG(CE_WARN, NULL, "ACPI CA not ready");
1785630ff078Sphitran 		return (status);
1786d2ec54f7Sphitran 	}
1787d2ec54f7Sphitran 
1788d2ec54f7Sphitran 	/* Init Control Method Batterys */
1789630ff078Sphitran 	type = ACPI_DRV_TYPE_CBAT;
1790630ff078Sphitran 	if (ACPI_SUCCESS(AcpiGetDevices(ACPI_DEVNAME_CBAT, acpi_drv_find_cb,
1791630ff078Sphitran 	    &type, (void *)&retp)) && nbat) {
1792630ff078Sphitran 		status = ACPI_DRV_OK;
1793d2ec54f7Sphitran 	}
1794d2ec54f7Sphitran 
1795d2ec54f7Sphitran 	/* Init AC */
1796630ff078Sphitran 	type = ACPI_DRV_TYPE_AC;
1797630ff078Sphitran 	if (ACPI_SUCCESS(AcpiGetDevices(ACPI_DEVNAME_AC, acpi_drv_find_cb,
1798630ff078Sphitran 	    &type, (void *)&retp)) && nac) {
1799630ff078Sphitran 		status = ACPI_DRV_OK;
1800d2ec54f7Sphitran 	}
1801d2ec54f7Sphitran 
1802d2ec54f7Sphitran 	/* Init LID */
1803630ff078Sphitran 	type = ACPI_DRV_TYPE_LID;
1804630ff078Sphitran 	if (ACPI_SUCCESS(AcpiGetDevices(ACPI_DEVNAME_LID, acpi_drv_find_cb,
1805630ff078Sphitran 	    &type, (void *)&retp)) && nlid) {
1806630ff078Sphitran 		status = ACPI_DRV_OK;
1807d2ec54f7Sphitran 	}
1808d2ec54f7Sphitran 
18092d6b5ea7SGuoli Shu 	/* Init Hotkey Device */
18102d6b5ea7SGuoli Shu 	type = ACPI_DRV_TYPE_HOTKEY;
18112d6b5ea7SGuoli Shu 	htkp = &acpi_hotkey;
18122d6b5ea7SGuoli Shu 	bzero(htkp, sizeof (hotkey_drv_t));
18132d6b5ea7SGuoli Shu 	htkp->dip = acpi_drv_dip;
18142d6b5ea7SGuoli Shu 	htkp->hotkey_lock = &acpi_drv_mutex;
18152d6b5ea7SGuoli Shu 	if (hotkey_init(htkp) == ACPI_DRV_OK) {
1816630ff078Sphitran 		status = ACPI_DRV_OK;
1817d2ec54f7Sphitran 	}
1818d2ec54f7Sphitran 
1819d2ec54f7Sphitran 	acpi_drv_update_cap(1);
1820d2ec54f7Sphitran 
1821630ff078Sphitran 	return (status);
1822d2ec54f7Sphitran }
1823d2ec54f7Sphitran 
1824d2ec54f7Sphitran static void
acpi_drv_acpi_fini(void)1825d2ec54f7Sphitran acpi_drv_acpi_fini(void)
1826d2ec54f7Sphitran {
1827d2ec54f7Sphitran 	int i;
1828d2ec54f7Sphitran 	struct acpi_drv_cbat_state *bp;
1829d2ec54f7Sphitran 
1830d2ec54f7Sphitran 	for (bp = &acpi_drv_cbat[0]; bp < &acpi_drv_cbat[ACPI_DRV_MAX_BAT_NUM];
1831d2ec54f7Sphitran 	    bp++) {
1832d2ec54f7Sphitran 		if (bp->dev.valid) {
1833c1374a13SSurya Prakki 			(void) AcpiRemoveNotifyHandler(bp->dev.hdl,
1834c1374a13SSurya Prakki 			    ACPI_DEVICE_NOTIFY, acpi_drv_cbat_notify);
1835d2ec54f7Sphitran 		}
1836d2ec54f7Sphitran 	}
1837d2ec54f7Sphitran 	for (i = 0; i < nac; i++) {
1838c1374a13SSurya Prakki 		(void) AcpiRemoveNotifyHandler(acpi_drv_ac[i].dev.hdl,
1839d2ec54f7Sphitran 		    ACPI_DEVICE_NOTIFY, acpi_drv_ac_notify);
1840d2ec54f7Sphitran 	}
1841c1374a13SSurya Prakki 	(void) AcpiRemoveNotifyHandler(lid.dev.hdl, ACPI_DEVICE_NOTIFY,
1842d2ec54f7Sphitran 	    acpi_drv_lid_notify);
18432d6b5ea7SGuoli Shu 
18442d6b5ea7SGuoli Shu 	if (acpi_hotkey.hotkey_method != HOTKEY_METHOD_NONE)
18452d6b5ea7SGuoli Shu 		(void) hotkey_fini(&acpi_hotkey);
1846d2ec54f7Sphitran }
1847d2ec54f7Sphitran 
1848d2ec54f7Sphitran /*ARGSUSED*/
1849d2ec54f7Sphitran static int
acpi_drv_kstat_power_update(kstat_t * ksp,int flag)1850d2ec54f7Sphitran acpi_drv_kstat_power_update(kstat_t *ksp, int flag)
1851d2ec54f7Sphitran {
1852d2ec54f7Sphitran 	if (flag == KSTAT_WRITE) {
1853d2ec54f7Sphitran 		return (EACCES);
1854d2ec54f7Sphitran 	}
1855d2ec54f7Sphitran 
1856d2ec54f7Sphitran 	mutex_enter(&acpi_drv_mutex);
1857d2ec54f7Sphitran 	if (acpi_drv_psr_type == ACPI_DRV_TYPE_UNKNOWN) {
1858d2ec54f7Sphitran 		mutex_exit(&acpi_drv_mutex);
1859d2ec54f7Sphitran 		return (EIO);
1860d2ec54f7Sphitran 	}
1861d2ec54f7Sphitran 	kstat_named_setstr(&acpi_drv_power_kstat.acpi_drv_power,
1862d2ec54f7Sphitran 	    acpi_drv_psr_type == ACPI_DRV_TYPE_AC ? AC : BATTERY);
1863d2ec54f7Sphitran 	acpi_drv_power_kstat.acpi_drv_supported_battery_count.value.ui32 =
1864d2ec54f7Sphitran 	    (uint32_t)nbat;
1865d2ec54f7Sphitran 	mutex_exit(&acpi_drv_mutex);
1866d2ec54f7Sphitran 
1867d2ec54f7Sphitran 	return (0);
1868d2ec54f7Sphitran }
1869d2ec54f7Sphitran 
1870d2ec54f7Sphitran /*ARGSUSED*/
1871d2ec54f7Sphitran static int
acpi_drv_kstat_warn_update(kstat_t * ksp,int flag)1872d2ec54f7Sphitran acpi_drv_kstat_warn_update(kstat_t *ksp, int flag)
1873d2ec54f7Sphitran {
1874d2ec54f7Sphitran 	if (flag == KSTAT_WRITE) {
1875d2ec54f7Sphitran 		int ret = 0;
1876d2ec54f7Sphitran 		acpi_drv_warn_t bw;
1877d2ec54f7Sphitran 		acpi_drv_warn_kstat_t kbw;
1878d2ec54f7Sphitran 
1879d2ec54f7Sphitran 		kbw = *(acpi_drv_warn_kstat_t *)acpi_drv_warn_ksp->ks_data;
1880d2ec54f7Sphitran 
1881d2ec54f7Sphitran 		mutex_enter(&acpi_drv_mutex);
1882d2ec54f7Sphitran 		bw.bw_enabled  = kbw.acpi_drv_bw_enabled.value.ui32;
1883d2ec54f7Sphitran 		bw.bw_charge_warn = kbw.acpi_drv_bw_charge_warn.value.ui32;
1884d2ec54f7Sphitran 		bw.bw_charge_low = kbw.acpi_drv_bw_charge_low.value.ui32;
1885d2ec54f7Sphitran 		ret = acpi_drv_set_warn(&bw);
1886d2ec54f7Sphitran 		mutex_exit(&acpi_drv_mutex);
1887d2ec54f7Sphitran 
1888d2ec54f7Sphitran 		return (ret);
1889d2ec54f7Sphitran 	} else {
1890d2ec54f7Sphitran 		acpi_drv_warn_kstat_t *wp = &acpi_drv_warn_kstat;
1891d2ec54f7Sphitran 
1892d2ec54f7Sphitran 		mutex_enter(&acpi_drv_mutex);
1893d2ec54f7Sphitran 		wp->acpi_drv_bw_enabled.value.ui32 = acpi_drv_warn_enabled;
1894d2ec54f7Sphitran 		wp->acpi_drv_bw_charge_warn.value.ui32 = acpi_drv_syn_warn_per;
1895d2ec54f7Sphitran 		wp->acpi_drv_bw_charge_low.value.ui32 = acpi_drv_syn_low_per;
1896d2ec54f7Sphitran 		mutex_exit(&acpi_drv_mutex);
1897d2ec54f7Sphitran 
1898d2ec54f7Sphitran 		return (0);
1899d2ec54f7Sphitran 	}
1900d2ec54f7Sphitran }
1901d2ec54f7Sphitran 
1902d2ec54f7Sphitran static int
acpi_drv_kstat_bif_update(kstat_t * ksp,int flag)1903d2ec54f7Sphitran acpi_drv_kstat_bif_update(kstat_t *ksp, int flag)
1904d2ec54f7Sphitran {
1905d2ec54f7Sphitran 	struct acpi_drv_cbat_state *bp;
1906d2ec54f7Sphitran 	acpi_bif_t *bif;
1907d2ec54f7Sphitran 	acpi_drv_bif_kstat_t *kp;
1908d2ec54f7Sphitran 
1909d2ec54f7Sphitran 	if (flag == KSTAT_WRITE) {
1910d2ec54f7Sphitran 		return (EACCES);
1911d2ec54f7Sphitran 	}
1912d2ec54f7Sphitran 
1913d2ec54f7Sphitran 	bp = (struct acpi_drv_cbat_state *)ksp->ks_private;
1914d2ec54f7Sphitran 	mutex_enter(&acpi_drv_mutex);
1915d2ec54f7Sphitran 
1916d2ec54f7Sphitran 	if (acpi_drv_cbat_present(bp) <= 0) {
1917d2ec54f7Sphitran 		mutex_exit(&acpi_drv_mutex);
1918d2ec54f7Sphitran 		return (ENXIO);
1919d2ec54f7Sphitran 	}
1920d2ec54f7Sphitran 
1921d2ec54f7Sphitran 	bzero(&bif, sizeof (bif));
1922d2ec54f7Sphitran 	if (acpi_drv_update_bif(bp) != ACPI_DRV_OK) {
1923d2ec54f7Sphitran 		mutex_exit(&acpi_drv_mutex);
1924d2ec54f7Sphitran 		return (ENXIO);
1925d2ec54f7Sphitran 	}
1926d2ec54f7Sphitran 
1927d2ec54f7Sphitran 	bif = &bp->bif_cache;
1928d2ec54f7Sphitran 	kp = &acpi_drv_bif_kstat;
1929d2ec54f7Sphitran 
1930d2ec54f7Sphitran 	/* Update BIF */
1931d2ec54f7Sphitran 	kp->acpi_drv_bif_unit.value.ui32 = bif->bif_unit;
1932d2ec54f7Sphitran 	kp->acpi_drv_bif_design_cap.value.ui32 = bif->bif_design_cap;
1933d2ec54f7Sphitran 	kp->acpi_drv_bif_last_cap.value.ui32 = bif->bif_last_cap;
1934d2ec54f7Sphitran 	kp->acpi_drv_bif_tech.value.ui32 = bif->bif_tech;
1935d2ec54f7Sphitran 	kp->acpi_drv_bif_voltage.value.ui32 = bif->bif_voltage;
1936d2ec54f7Sphitran 	kp->acpi_drv_bif_warn_cap.value.ui32 = bif->bif_warn_cap;
1937d2ec54f7Sphitran 	kp->acpi_drv_bif_low_cap.value.ui32 = bif->bif_low_cap;
1938d2ec54f7Sphitran 	kp->acpi_drv_bif_gran1_cap.value.ui32 = bif->bif_gran1_cap;
1939d2ec54f7Sphitran 	kp->acpi_drv_bif_gran2_cap.value.ui32 = bif->bif_gran2_cap;
1940d2ec54f7Sphitran 
1941d2ec54f7Sphitran 	kstat_named_setstr(&kp->acpi_drv_bif_model, bif->bif_model);
1942d2ec54f7Sphitran 	kstat_named_setstr(&kp->acpi_drv_bif_serial, bif->bif_serial);
1943d2ec54f7Sphitran 	kstat_named_setstr(&kp->acpi_drv_bif_type, bif->bif_type);
1944d2ec54f7Sphitran 	kstat_named_setstr(&kp->acpi_drv_bif_oem_info, bif->bif_oem_info);
1945d2ec54f7Sphitran 
1946d2ec54f7Sphitran 	mutex_exit(&acpi_drv_mutex);
1947d2ec54f7Sphitran 	return (0);
1948d2ec54f7Sphitran }
1949d2ec54f7Sphitran 
1950d2ec54f7Sphitran static int
acpi_drv_kstat_bst_update(kstat_t * ksp,int flag)1951d2ec54f7Sphitran acpi_drv_kstat_bst_update(kstat_t *ksp, int flag)
1952d2ec54f7Sphitran {
1953d2ec54f7Sphitran 	struct acpi_drv_cbat_state *bp;
1954d2ec54f7Sphitran 	acpi_bst_t *bst;
1955d2ec54f7Sphitran 	acpi_drv_bst_kstat_t *kp;
1956d2ec54f7Sphitran 
1957d2ec54f7Sphitran 	if (flag == KSTAT_WRITE) {
1958d2ec54f7Sphitran 		return (EACCES);
1959d2ec54f7Sphitran 	}
1960d2ec54f7Sphitran 
1961d2ec54f7Sphitran 	bp = (struct acpi_drv_cbat_state *)ksp->ks_private;
1962d2ec54f7Sphitran 	mutex_enter(&acpi_drv_mutex);
1963d2ec54f7Sphitran 
1964d2ec54f7Sphitran 	if (acpi_drv_cbat_present(bp) <= 0) {
1965d2ec54f7Sphitran 		mutex_exit(&acpi_drv_mutex);
1966d2ec54f7Sphitran 		return (ENXIO);
1967d2ec54f7Sphitran 	}
1968d2ec54f7Sphitran 
1969d2ec54f7Sphitran 	bzero(&bst, sizeof (bst));
1970d2ec54f7Sphitran 	if (acpi_drv_update_bst(bp) != ACPI_DRV_OK) {
1971d2ec54f7Sphitran 		mutex_exit(&acpi_drv_mutex);
1972d2ec54f7Sphitran 		return (ENXIO);
1973d2ec54f7Sphitran 	}
1974d2ec54f7Sphitran 
1975d2ec54f7Sphitran 	bst = &bp->bst_cache;
1976d2ec54f7Sphitran 	kp = &acpi_drv_bst_kstat;
1977d2ec54f7Sphitran 
1978d2ec54f7Sphitran 	/* Update BST */
1979d2ec54f7Sphitran 	kp->acpi_drv_bst_state.value.ui32 = bst->bst_state;
1980d2ec54f7Sphitran 	kp->acpi_drv_bst_rate.value.ui32 = bst->bst_rate;
1981d2ec54f7Sphitran 	kp->acpi_drv_bst_rem_cap.value.ui32 = bst->bst_rem_cap;
1982d2ec54f7Sphitran 	kp->acpi_drv_bst_voltage.value.ui32 = bst->bst_voltage;
1983d2ec54f7Sphitran 
1984d2ec54f7Sphitran 	mutex_exit(&acpi_drv_mutex);
1985d2ec54f7Sphitran 	return (0);
1986d2ec54f7Sphitran }
1987d2ec54f7Sphitran 
1988d2ec54f7Sphitran static int
acpi_drv_kstat_init(void)1989d2ec54f7Sphitran acpi_drv_kstat_init(void)
1990d2ec54f7Sphitran {
1991d2ec54f7Sphitran 	/*
1992d2ec54f7Sphitran 	 * Allocate, initialize and install powerstatus and
1993d2ec54f7Sphitran 	 * supported_battery_count kstat.
1994d2ec54f7Sphitran 	 */
1995d2ec54f7Sphitran 	acpi_drv_power_ksp = kstat_create(ACPI_DRV_NAME, 0,
1996d2ec54f7Sphitran 	    ACPI_DRV_POWER_KSTAT_NAME, "misc",
1997d2ec54f7Sphitran 	    KSTAT_TYPE_NAMED,
1998d2ec54f7Sphitran 	    sizeof (acpi_drv_power_kstat) / sizeof (kstat_named_t),
1999d2ec54f7Sphitran 	    KSTAT_FLAG_VIRTUAL);
2000d2ec54f7Sphitran 	if (acpi_drv_power_ksp == NULL) {
2001d2ec54f7Sphitran 		ACPI_DRV_DBG(CE_WARN, NULL,
2002d2ec54f7Sphitran 		    "kstat_create(%s) fail", ACPI_DRV_POWER_KSTAT_NAME);
2003d2ec54f7Sphitran 		return (ACPI_DRV_ERR);
2004d2ec54f7Sphitran 	}
2005d2ec54f7Sphitran 
2006d2ec54f7Sphitran 	acpi_drv_power_ksp->ks_data = &acpi_drv_power_kstat;
2007d2ec54f7Sphitran 	acpi_drv_power_ksp->ks_update = acpi_drv_kstat_power_update;
2008d2ec54f7Sphitran 	acpi_drv_power_ksp->ks_data_size += MAXNAMELEN;
2009d2ec54f7Sphitran 	kstat_install(acpi_drv_power_ksp);
2010d2ec54f7Sphitran 
2011d2ec54f7Sphitran 	/*
2012d2ec54f7Sphitran 	 * Allocate, initialize and install battery_capacity_warning kstat.
2013d2ec54f7Sphitran 	 */
2014d2ec54f7Sphitran 	acpi_drv_warn_ksp = kstat_create(ACPI_DRV_NAME, 0,
2015d2ec54f7Sphitran 	    ACPI_DRV_BTWARN_KSTAT_NAME, "misc",
2016d2ec54f7Sphitran 	    KSTAT_TYPE_NAMED,
2017d2ec54f7Sphitran 	    sizeof (acpi_drv_warn_kstat) / sizeof (kstat_named_t),
2018d2ec54f7Sphitran 	    KSTAT_FLAG_VIRTUAL | KSTAT_FLAG_WRITABLE);
2019d2ec54f7Sphitran 	if (acpi_drv_warn_ksp == NULL) {
2020d2ec54f7Sphitran 		ACPI_DRV_DBG(CE_WARN, NULL,
2021d2ec54f7Sphitran 		    "kstat_create(%s) fail", ACPI_DRV_BTWARN_KSTAT_NAME);
2022d2ec54f7Sphitran 		return (ACPI_DRV_ERR);
2023d2ec54f7Sphitran 	}
2024d2ec54f7Sphitran 
2025d2ec54f7Sphitran 	acpi_drv_warn_ksp->ks_data = &acpi_drv_warn_kstat;
2026d2ec54f7Sphitran 	acpi_drv_warn_ksp->ks_update = acpi_drv_kstat_warn_update;
2027d2ec54f7Sphitran 	kstat_install(acpi_drv_warn_ksp);
2028d2ec54f7Sphitran 
2029d2ec54f7Sphitran 	return (ACPI_DRV_OK);
2030d2ec54f7Sphitran }
2031d2ec54f7Sphitran 
2032d2ec54f7Sphitran static void
acpi_drv_kstat_fini()2033d2ec54f7Sphitran acpi_drv_kstat_fini()
2034d2ec54f7Sphitran {
2035d2ec54f7Sphitran 	struct acpi_drv_cbat_state *bp;
2036d2ec54f7Sphitran 
2037d2ec54f7Sphitran 	if (acpi_drv_power_ksp != NULL) {
2038d2ec54f7Sphitran 		kstat_delete(acpi_drv_power_ksp);
2039d2ec54f7Sphitran 	}
2040d2ec54f7Sphitran 	if (acpi_drv_warn_ksp != NULL) {
2041d2ec54f7Sphitran 		kstat_delete(acpi_drv_warn_ksp);
2042d2ec54f7Sphitran 	}
2043d2ec54f7Sphitran 	for (bp = &acpi_drv_cbat[0]; bp < &acpi_drv_cbat[ACPI_DRV_MAX_BAT_NUM];
2044d2ec54f7Sphitran 	    bp++) {
2045d2ec54f7Sphitran 		if (bp->dev.valid) {
2046d2ec54f7Sphitran 			if (bp->bat_bif_ksp != NULL) {
2047d2ec54f7Sphitran 				kstat_delete(bp->bat_bif_ksp);
2048d2ec54f7Sphitran 			}
2049d2ec54f7Sphitran 			if (bp->bat_bst_ksp != NULL) {
2050d2ec54f7Sphitran 				kstat_delete(bp->bat_bst_ksp);
2051d2ec54f7Sphitran 			}
2052d2ec54f7Sphitran 		}
2053d2ec54f7Sphitran 	}
2054d2ec54f7Sphitran }
2055d2ec54f7Sphitran 
20562d6b5ea7SGuoli Shu int
acpi_drv_set_int(ACPI_HANDLE dev,char * method,uint32_t aint)2057d2ec54f7Sphitran acpi_drv_set_int(ACPI_HANDLE dev, char *method, uint32_t aint)
2058d2ec54f7Sphitran {
2059d2ec54f7Sphitran 	ACPI_OBJECT_LIST al;
2060d2ec54f7Sphitran 	ACPI_OBJECT ao;
2061d2ec54f7Sphitran 
2062d2ec54f7Sphitran 	al.Pointer = &ao;
2063d2ec54f7Sphitran 	al.Count = 1;
2064d2ec54f7Sphitran 	ao.Type = ACPI_TYPE_INTEGER;
2065d2ec54f7Sphitran 	ao.Integer.Value = aint;
2066d2ec54f7Sphitran 	return (AcpiEvaluateObject(dev, method, &al, NULL));
2067d2ec54f7Sphitran }
2068d2ec54f7Sphitran 
20692d6b5ea7SGuoli Shu int
acpi_drv_dev_init(struct acpi_drv_dev * p)20702d6b5ea7SGuoli Shu acpi_drv_dev_init(struct acpi_drv_dev *p)
2071d2ec54f7Sphitran {
20722d6b5ea7SGuoli Shu 	ACPI_DEVICE_INFO *info;
20732d6b5ea7SGuoli Shu 	ACPI_STATUS ret;
2074d2ec54f7Sphitran 
20752d6b5ea7SGuoli Shu 	ASSERT(p != NULL && p->hdl != NULL);
20762d6b5ea7SGuoli Shu 
20772d6b5ea7SGuoli Shu 	p->valid = 0;
20782d6b5ea7SGuoli Shu 
20792d6b5ea7SGuoli Shu 	/* Info size is variable depending on existance of _CID */
208057190917SDana Myers 	ret = AcpiGetObjectInfo(p->hdl, &info);
20812d6b5ea7SGuoli Shu 	if (ACPI_FAILURE(ret)) {
20822d6b5ea7SGuoli Shu 		ACPI_DRV_DBG(CE_WARN, NULL,
20832d6b5ea7SGuoli Shu 		    "AcpiGetObjectInfo() fail: %d", (int32_t)ret);
2084d2ec54f7Sphitran 		return (ACPI_DRV_ERR);
2085d2ec54f7Sphitran 	}
2086d2ec54f7Sphitran 
20872d6b5ea7SGuoli Shu 	if ((info->Valid & ACPI_VALID_HID) == 0) {
20882d6b5ea7SGuoli Shu 		ACPI_DRV_DBG(CE_WARN, NULL,
20892d6b5ea7SGuoli Shu 		    "!AcpiGetObjectInfo(): _HID not available");
2090a3114836SGerry Liu 		p->hid[0] = 0;
2091d2ec54f7Sphitran 	} else {
2092a3114836SGerry Liu 		(void) strlcpy(p->hid, info->HardwareId.String, ID_LEN);
2093d2ec54f7Sphitran 	}
2094d2ec54f7Sphitran 
2095d2ec54f7Sphitran 	/*
20962d6b5ea7SGuoli Shu 	 * This object is optional, but is required when the device
20972d6b5ea7SGuoli Shu 	 * has no other way to report a persistent unique device ID.
2098d2ec54f7Sphitran 	 */
20992d6b5ea7SGuoli Shu 	if ((info->Valid & ACPI_VALID_UID) == 0) {
21002d6b5ea7SGuoli Shu 		ACPI_DRV_DBG(CE_WARN, NULL,
21012d6b5ea7SGuoli Shu 		    "!AcpiGetObjectInfo(): _UID not available");
21022d6b5ea7SGuoli Shu 		/* Use 0 as the default _UID */
2103a3114836SGerry Liu 		p->uid[0] = 0;
21042d6b5ea7SGuoli Shu 	} else {
2105a3114836SGerry Liu 		(void) strlcpy(p->uid, info->UniqueId.String, ID_LEN);
21062d6b5ea7SGuoli Shu 	}
2107d2ec54f7Sphitran 
21082d6b5ea7SGuoli Shu 	if (info->Valid & ACPI_VALID_ADR) {
21092d6b5ea7SGuoli Shu 		p->valid = 1;
21102d6b5ea7SGuoli Shu 		p->type = ACPI_DRV_TYPE_HOTKEY;
2111d2ec54f7Sphitran 	}
21122d6b5ea7SGuoli Shu 
21132d6b5ea7SGuoli Shu 	AcpiOsFree(info);
21142d6b5ea7SGuoli Shu 
2115d2ec54f7Sphitran 	return (ACPI_DRV_OK);
2116d2ec54f7Sphitran }
2117