xref: /illumos-gate/usr/src/uts/i86pc/io/acpi_drv/acpi_drv.c (revision fe3e2633be44d2f5361a7bba26abeb80fcc04fbc)
1 /*
2  * CDDL HEADER START
3  *
4  * The contents of this file are subject to the terms of the
5  * Common Development and Distribution License (the "License").
6  * You may not use this file except in compliance with the License.
7  *
8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9  * or http://www.opensolaris.org/os/licensing.
10  * See the License for the specific language governing permissions
11  * and limitations under the License.
12  *
13  * When distributing Covered Code, include this CDDL HEADER in each
14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15  * If applicable, add the following below this CDDL HEADER, with the
16  * fields enclosed by brackets "[]" replaced with your own identifying
17  * information: Portions Copyright [yyyy] [name of copyright owner]
18  *
19  * CDDL HEADER END
20  */
21 
22 /*
23  * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
24  * Use is subject to license terms.
25  */
26 
27 /*
28  * Driver for ACPI Battery, Lid, and LCD Monitoring and Control
29  */
30 
31 #pragma ident	"%Z%%M%	%I%	%E% SMI"
32 
33 #include <sys/conf.h>
34 #include <sys/modctl.h>
35 #include <sys/ddi.h>
36 #include <sys/sunddi.h>
37 #include <sys/stat.h>
38 #include <sys/sysevent/eventdefs.h>
39 #include <sys/sysevent/pwrctl.h>
40 #include <sys/reboot.h>
41 #include <sys/sysmacros.h>
42 #include <sys/acpi/acpi.h>
43 #include <sys/acpica.h>
44 #include <sys/note.h>
45 #include <sys/acpi_drv.h>
46 
47 
48 #define	ACPI_DRV_MOD_STRING		"ACPI driver"
49 
50 #define	MINOR_SHIFT			8
51 #define	IDX_MASK			((1 << MINOR_SHIFT) - 1)
52 #define	MINOR_BATT(idx)			(ACPI_DRV_TYPE_CBAT << MINOR_SHIFT | \
53 					(idx))
54 #define	MINOR_AC(idx)			(ACPI_DRV_TYPE_AC << MINOR_SHIFT | \
55 					(idx))
56 #define	MINOR_LID(idx)			(ACPI_DRV_TYPE_LID << MINOR_SHIFT | \
57 					(idx))
58 #define	MINOR_DISPLAY(idx)		(ACPI_DRV_TYPE_DISPLAY << MINOR_SHIFT \
59 					| (idx))
60 #define	MINOR_OUTPUT(idx)		(ACPI_DRV_TYPE_OUTPUT << MINOR_SHIFT | \
61 					(idx))
62 #define	MINOR2IDX(minor)		((minor) & IDX_MASK)
63 #define	MINOR2TYPE(minor)		((minor) >> MINOR_SHIFT)
64 
65 #define	ACPI_DRV_OK			(0)
66 #define	ACPI_DRV_ERR			(1)
67 
68 #define	ACPI_DRV_MAX_BAT_NUM		8
69 #define	ACPI_DRV_MAX_AC_NUM		10
70 
71 #define	BST_FLAG_DISCHARGING		(0x1)
72 #define	BST_FLAG_CHARGING		(0x2)
73 #define	BST_FLAG_CRITICAL		(0x4)
74 
75 /* Set if the battery is present */
76 #define	STA_FLAG_BATT_PRESENT		(0x10)
77 
78 #define	ACPI_DEVNAME_CBAT		"PNP0C0A"
79 #define	ACPI_DEVNAME_AC			"ACPI0003"
80 #define	ACPI_DEVNAME_LID		"PNP0C0D"
81 
82 #define	ACPI_DRV_EVENTS			(POLLIN | POLLRDNORM)
83 
84 #ifdef DEBUG
85 
86 #define	ACPI_DRV_PRINT_BUFFER_SIZE	512
87 static char acpi_drv_prt_buf[ACPI_DRV_PRINT_BUFFER_SIZE];
88 static kmutex_t acpi_drv_prt_mutex;
89 
90 static int acpi_drv_debug = 0;
91 #define	ACPI_DRV_DBG(lev, devp, ...) \
92 	do { \
93 		if (acpi_drv_debug) acpi_drv_printf((devp), \
94 (lev), __VA_ARGS__); \
95 _NOTE(CONSTCOND) } while (0)
96 #define	ACPI_DRV_PRT_NOTIFY(hdl, val) \
97 	do { \
98 		if (acpi_drv_debug) acpi_drv_prt_notify((hdl), (val)); \
99 _NOTE(CONSTCOND) } while (0)
100 
101 #else
102 
103 #define	ACPI_DRV_DBG(lev, devp, ...)
104 #define	ACPI_DRV_PRT_NOTIFY(hdl, val)
105 
106 #endif /* DEBUG */
107 
108 /* ACPI notify types */
109 enum acpi_drv_notify {
110 	ACPI_DRV_NTF_UNKNOWN = -1,	/* No notifications seen, ever. */
111 	ACPI_DRV_NTF_CHANGED,
112 	ACPI_DRV_NTF_OK
113 };
114 
115 /* Battery device types */
116 enum acpi_drv_type {
117 	ACPI_DRV_TYPE_UNKNOWN,
118 	ACPI_DRV_TYPE_CBAT,
119 	ACPI_DRV_TYPE_AC,
120 	ACPI_DRV_TYPE_LID,
121 	ACPI_DRV_TYPE_DISPLAY,
122 	ACPI_DRV_TYPE_OUTPUT
123 };
124 
125 struct acpi_drv_dev {
126 	ACPI_HANDLE hdl;
127 	char hid[9];		/* ACPI HardwareId */
128 	char uid[9];		/* ACPI UniqueId */
129 	ACPI_INTEGER adr;	/* Bus device Id */
130 	int valid;		/* the device state is valid */
131 
132 	/*
133 	 * Unlike most other devices, when a battery is inserted or
134 	 * removed from the system, the device itself(the battery bay)
135 	 * is still considered to be present in the system.
136 	 *
137 	 * Value:
138 	 *    0 -- On-line
139 	 *    1 -- Off-line
140 	 *   -1 -- Unknown
141 	 */
142 	int present;
143 	enum acpi_drv_type type;
144 	int index;	/* device index */
145 	int minor;
146 
147 	struct acpi_drv_output_state *op;
148 	struct acpi_drv_display_state *dp;
149 };
150 
151 static int acpi_drv_dev_present(struct acpi_drv_dev *);
152 #define	acpi_drv_ac_present(a)	(((a)->dev.type == ACPI_DRV_TYPE_AC) ? \
153 				acpi_drv_dev_present(&(a)->dev) : -1)
154 #define	acpi_drv_cbat_present(a)	(((a)->dev.type == ACPI_DRV_TYPE_CBAT) \
155 					? acpi_drv_dev_present(&(a)->dev) : -1)
156 
157 static dev_info_t *acpi_drv_dip = NULL;
158 static kmutex_t acpi_drv_mutex;
159 static struct pollhead acpi_drv_pollhead;
160 
161 /* Control Method Battery state */
162 struct acpi_drv_cbat_state {
163 	struct acpi_drv_dev dev;
164 	/* Caches of _BST and _BIF */
165 	enum acpi_drv_notify bat_bifok;
166 	acpi_bif_t bif_cache;
167 	enum acpi_drv_notify bat_bstok;
168 	acpi_bst_t bst_cache;
169 
170 	uint32_t charge_warn;
171 	uint32_t charge_low;
172 
173 	kstat_t *bat_bif_ksp;
174 	kstat_t *bat_bst_ksp;
175 } acpi_drv_cbat[ACPI_DRV_MAX_BAT_NUM];
176 static int nbat = 0;
177 
178 /*
179  * Synthesis battery state
180  * When there are multiple batteries present, the battery subsystem
181  * is not required to perform any synthesis of a composite battery
182  * from the data of the separate batteries. In cases where the
183  * battery subsystem does not synthesize a composite battery from
184  * the separate battery's data, the OS must provide that synthesis.
185  */
186 static uint32_t acpi_drv_syn_rem_cap;
187 static uint32_t acpi_drv_syn_last_cap;
188 static uint32_t acpi_drv_syn_oem_warn_cap;
189 static uint32_t acpi_drv_syn_oem_low_cap;
190 
191 static int acpi_drv_warn_enabled;
192 static uint32_t acpi_drv_syn_warn_per;
193 static uint32_t acpi_drv_syn_low_per;
194 static uint32_t acpi_drv_syn_warn_cap;
195 static uint32_t acpi_drv_syn_low_cap;
196 /* Tracking boundery passing of _BST charge levels */
197 static uint32_t acpi_drv_syn_last_level;
198 
199 /* AC state */
200 static struct acpi_drv_ac_state {
201 	struct acpi_drv_dev dev;
202 } acpi_drv_ac[ACPI_DRV_MAX_AC_NUM];
203 static int nac = 0;
204 
205 /*
206  * Current power source device
207  * Note: assume only one device can be the power source device.
208  */
209 static int acpi_drv_psr_type = ACPI_DRV_TYPE_UNKNOWN;
210 static struct acpi_drv_dev *acpi_drv_psr_devp = NULL;
211 
212 struct obj_desc {
213 	char *name;
214 	int offset;
215 	int size;
216 	int type;
217 };
218 
219 /* Object copy definitions */
220 #define	OFFSETOF(s, m)		((size_t)(&(((s *)0)->m)))
221 #define	SIZEOF(s, m)		(sizeof (((s *)0)->m))
222 #define	FIELD(n, s, m, t) \
223 	{ n, OFFSETOF(s, m), SIZEOF(s, m), t }
224 #define	FIELD_NULL		{ NULL, -1, 0, ACPI_TYPE_ANY }
225 
226 static struct obj_desc bif_desc[] = {
227 	FIELD("bif_unit",	acpi_bif_t, bif_unit,	ACPI_TYPE_INTEGER),
228 	FIELD("bif_design_cap", acpi_bif_t, bif_design_cap, ACPI_TYPE_INTEGER),
229 	FIELD("bif_last_cap",	acpi_bif_t, bif_last_cap,   ACPI_TYPE_INTEGER),
230 	FIELD("bif_tech",	acpi_bif_t, bif_tech,	ACPI_TYPE_INTEGER),
231 	FIELD("bif_voltage",	acpi_bif_t, bif_voltage, ACPI_TYPE_INTEGER),
232 	FIELD("bif_warn_cap",	acpi_bif_t, bif_warn_cap, ACPI_TYPE_INTEGER),
233 	FIELD("bif_low_cap",	acpi_bif_t, bif_low_cap,  ACPI_TYPE_INTEGER),
234 	FIELD("bif_gran1_cap",	acpi_bif_t, bif_gran1_cap, ACPI_TYPE_INTEGER),
235 	FIELD("bif_gran2_cap",	acpi_bif_t, bif_gran2_cap, ACPI_TYPE_INTEGER),
236 	FIELD("bif_model",	acpi_bif_t, bif_model,	ACPI_TYPE_STRING),
237 	FIELD("bif_serial",	acpi_bif_t, bif_serial,	ACPI_TYPE_STRING),
238 	FIELD("bif_type",	acpi_bif_t, bif_type,	ACPI_TYPE_STRING),
239 	FIELD("bif_oem_info",	acpi_bif_t, bif_oem_info, ACPI_TYPE_STRING),
240 	FIELD_NULL
241 };
242 
243 static struct obj_desc bst_desc[] = {
244 	FIELD("bst_state",   acpi_bst_t, bst_state,	ACPI_TYPE_INTEGER),
245 	FIELD("bst_rate",    acpi_bst_t, bst_rate,	ACPI_TYPE_INTEGER),
246 	FIELD("bst_rem_cap", acpi_bst_t, bst_rem_cap,	ACPI_TYPE_INTEGER),
247 	FIELD("bst_voltage", acpi_bst_t, bst_voltage,	ACPI_TYPE_INTEGER),
248 	FIELD_NULL
249 };
250 
251 /* kstat definitions */
252 static kstat_t *acpi_drv_power_ksp;
253 static kstat_t *acpi_drv_warn_ksp;
254 
255 acpi_drv_power_kstat_t acpi_drv_power_kstat = {
256 	{ SYSTEM_POWER,			KSTAT_DATA_STRING },
257 	{ SUPPORTED_BATTERY_COUNT,	KSTAT_DATA_UINT32 },
258 };
259 
260 acpi_drv_warn_kstat_t acpi_drv_warn_kstat = {
261 	{ BW_ENABLED,			KSTAT_DATA_UINT32 },
262 	{ BW_POWEROFF_THRESHOLD,	KSTAT_DATA_UINT32 },
263 	{ BW_SHUTDOWN_THRESHOLD,	KSTAT_DATA_UINT32 },
264 };
265 
266 /* BIF */
267 acpi_drv_bif_kstat_t acpi_drv_bif_kstat = {
268 	{ BIF_UNIT,		KSTAT_DATA_UINT32 },
269 	{ BIF_DESIGN_CAP,	KSTAT_DATA_UINT32 },
270 	{ BIF_LAST_CAP,		KSTAT_DATA_UINT32 },
271 	{ BIF_TECH,		KSTAT_DATA_UINT32 },
272 	{ BIF_VOLTAGE,		KSTAT_DATA_UINT32 },
273 	{ BIF_WARN_CAP,		KSTAT_DATA_UINT32 },
274 	{ BIF_LOW_CAP,		KSTAT_DATA_UINT32 },
275 	{ BIF_GRAN1_CAP,	KSTAT_DATA_UINT32 },
276 	{ BIF_GRAN2_CAP,	KSTAT_DATA_UINT32 },
277 	{ BIF_MODEL,		KSTAT_DATA_STRING },
278 	{ BIF_SERIAL,		KSTAT_DATA_STRING },
279 	{ BIF_TYPE,		KSTAT_DATA_STRING },
280 	{ BIF_OEM_INFO,		KSTAT_DATA_STRING },
281 };
282 
283 /* BST */
284 acpi_drv_bst_kstat_t acpi_drv_bst_kstat = {
285 	{ BST_STATE,		KSTAT_DATA_UINT32 },
286 	{ BST_RATE,		KSTAT_DATA_UINT32 },
287 	{ BST_REM_CAP,		KSTAT_DATA_UINT32 },
288 	{ BST_VOLTAGE,		KSTAT_DATA_UINT32 },
289 };
290 
291 struct acpi_drv_lid_state {
292 	struct acpi_drv_dev dev;
293 	enum acpi_drv_notify state_ok;
294 	int state;
295 } lid;
296 static int nlid = 0;
297 
298 /* Output device status */
299 #define	ACPI_DRV_DCS_CONNECTOR_EXIST	(1 << 0)
300 #define	ACPI_DRV_DCS_ACTIVE		(1 << 1)
301 #define	ACPI_DRV_DCS_READY		(1 << 2)
302 #define	ACPI_DRV_DCS_FUNCTIONAL		(1 << 3)
303 #define	ACPI_DRV_DCS_ATTACHED		(1 << 4)
304 
305 /* _DOS default value is 1 */
306 /* _DOS bit 1:0 */
307 #define	ACPI_DRV_DOS_SWITCH_OS_DGS	0
308 #define	ACPI_DRV_DOS_SWITCH_BIOS	1
309 #define	ACPI_DRV_DOS_SWITCH_DGS_LOCKED	2
310 #define	ACPI_DRV_DOS_SWITCH_OS_EVENT	3
311 /* _DOS bit 2 */
312 #define	ACPI_DRV_DOS_BRIGHT_BIOS	(0 << 2)
313 #define	ACPI_DRV_DOS_BRIGHT_OS		(1 << 2)
314 
315 struct acpi_drv_output_state {
316 	struct acpi_drv_dev dev;
317 	uint32_t adr;
318 	uint32_t *levels;
319 	int num_levels; /* number of levels */
320 	int nlev; /* actual array size of levels */
321 	int cur_level;
322 	int cur_level_index;
323 	int state;
324 	struct acpi_drv_output_state *next;
325 	struct acpi_drv_output_state *tail;
326 };
327 static struct acpi_drv_output_state *outputs = NULL;
328 static int noutput = 0;
329 
330 struct acpi_drv_display_state {
331 	struct acpi_drv_dev dev;
332 	int mode;
333 	int noutput;
334 } display;
335 
336 static int acpi_drv_attach(dev_info_t *devi, ddi_attach_cmd_t cmd);
337 static int acpi_drv_detach(dev_info_t *devi, ddi_detach_cmd_t cmd);
338 static int acpi_drv_getinfo(dev_info_t *dip, ddi_info_cmd_t cmd, void *arg,
339     void **resultp);
340 static int acpi_drv_open(dev_t *devp, int flag, int otyp, cred_t *crp);
341 static int acpi_drv_close(dev_t dev, int flag, int otyp, cred_t *crp);
342 static int acpi_drv_ioctl(dev_t dev, int cmd, intptr_t arg, int mode,
343     cred_t *cr, int *rval);
344 static int acpi_drv_chpoll(dev_t dev, short events, int anyyet,
345     short *reventsp, struct pollhead **phpp);
346 static int acpi_drv_ac_ioctl(int index, int cmd, intptr_t arg, int mode,
347     cred_t *cr, int *rval);
348 static int acpi_drv_cbat_ioctl(int index, int cmd, intptr_t arg, int mode,
349     cred_t *cr, int *rval);
350 static int acpi_drv_lid_ioctl(int index, int cmd, intptr_t arg, int mode,
351     cred_t *cr, int *rval);
352 static int acpi_drv_output_ioctl(int index, int cmd, intptr_t arg, int mode,
353     cred_t *cr, int *rval);
354 #ifdef DEBUG
355 static void acpi_drv_printf(struct acpi_drv_dev *devp, uint_t lev,
356     const char *fmt, ...);
357 #endif
358 
359 /*
360  * Output device functions
361  */
362 static int acpi_drv_output_init(ACPI_HANDLE hdl, struct acpi_drv_dev *dev);
363 static void acpi_drv_output_notify(ACPI_HANDLE hdl, UINT32 val, void *ctx);
364 static int acpi_drv_output_get_level(struct acpi_drv_output_state *op);
365 static int acpi_drv_output_set_level(struct acpi_drv_output_state *op,
366     uint32_t level);
367 static struct acpi_drv_output_state *acpi_drv_idx2output(int idx);
368 
369 /*
370  * Display device functions
371  */
372 static void acpi_drv_display_set_mode(struct acpi_drv_display_state *dp,
373     int state);
374 
375 static int acpi_drv_update_bif(struct acpi_drv_cbat_state *bp);
376 static int acpi_drv_update_bst(struct acpi_drv_cbat_state *bp);
377 static int acpi_drv_update_lid(struct acpi_drv_dev *bp);
378 static int acpi_drv_set_warn(acpi_drv_warn_t *bwp);
379 static struct acpi_drv_cbat_state *acpi_drv_idx2cbat(int idx);
380 static struct acpi_drv_ac_state *acpi_drv_idx2ac(int idx);
381 static int acpi_drv_acpi_init(void);
382 static void acpi_drv_acpi_fini(void);
383 static int acpi_drv_kstat_init(void);
384 static void acpi_drv_kstat_fini(void);
385 
386 static struct cb_ops acpi_drv_cb_ops = {
387 	acpi_drv_open,		/* open */
388 	acpi_drv_close,		/* close */
389 	nodev,			/* strategy */
390 	nodev,			/* print */
391 	nodev,			/* dump */
392 	nodev,			/* read */
393 	nodev,			/* write */
394 	acpi_drv_ioctl,		/* ioctl */
395 	nodev,			/* devmap */
396 	nodev,			/* mmap */
397 	nodev,			/* segmap */
398 	acpi_drv_chpoll,		/* chpoll */
399 	ddi_prop_op,		/* prop_op */
400 	NULL,			/* streamtab */
401 	D_NEW | D_MP,
402 	CB_REV,
403 	nodev,
404 	nodev
405 };
406 
407 static struct dev_ops acpi_drv_dev_ops = {
408 	DEVO_REV,
409 	0,			/* refcnt */
410 	acpi_drv_getinfo,		/* getinfo */
411 	nulldev,		/* identify */
412 	nulldev,		/* probe */
413 	acpi_drv_attach,		/* attach */
414 	acpi_drv_detach,		/* detach */
415 	nodev,			/* reset */
416 	&acpi_drv_cb_ops,
417 	NULL,			/* no bus operations */
418 	NULL			/* power */
419 };
420 
421 static struct modldrv modldrv1 = {
422 	&mod_driverops,
423 	ACPI_DRV_MOD_STRING,
424 	&acpi_drv_dev_ops
425 };
426 
427 static struct modlinkage modlinkage = {
428 	MODREV_1,
429 	(void *)&modldrv1,
430 	NULL,
431 };
432 
433 int
434 _init(void)
435 {
436 	int ret;
437 
438 	mutex_init(&acpi_drv_mutex, NULL, MUTEX_DRIVER, NULL);
439 #ifdef DEBUG
440 	mutex_init(&acpi_drv_prt_mutex, NULL, MUTEX_DRIVER, NULL);
441 #endif
442 
443 	if ((ret = mod_install(&modlinkage)) != 0) {
444 		mutex_destroy(&acpi_drv_mutex);
445 #ifdef DEBUG
446 		mutex_destroy(&acpi_drv_prt_mutex);
447 #endif
448 	}
449 	return (ret);
450 }
451 
452 int
453 _fini(void)
454 {
455 	int ret;
456 
457 	if ((ret = mod_remove(&modlinkage)) == 0) {
458 #ifdef DEBUG
459 		mutex_destroy(&acpi_drv_prt_mutex);
460 #endif
461 		mutex_destroy(&acpi_drv_mutex);
462 	}
463 
464 	return (ret);
465 }
466 
467 int
468 _info(struct modinfo *mp)
469 {
470 	return (mod_info(&modlinkage, mp));
471 }
472 
473 static int
474 acpi_drv_attach(dev_info_t *devi, ddi_attach_cmd_t cmd)
475 {
476 	char name[20];
477 	int i;
478 	struct acpi_drv_cbat_state *bp;
479 	struct acpi_drv_output_state *op;
480 
481 	switch (cmd) {
482 	case DDI_ATTACH:
483 		/* Limit to one instance of driver */
484 		if (acpi_drv_dip) {
485 			return (DDI_FAILURE);
486 		}
487 		break;
488 	case DDI_RESUME:
489 	case DDI_PM_RESUME:
490 		return (DDI_SUCCESS);
491 	default:
492 		return (DDI_FAILURE);
493 	}
494 
495 	acpi_drv_dip = devi;
496 
497 	/* Init ACPI related stuff */
498 	if (acpi_drv_acpi_init() != ACPI_DRV_OK) {
499 		goto error;
500 	}
501 
502 	/* Init kstat related stuff */
503 	if (acpi_drv_kstat_init() != ACPI_DRV_OK) {
504 		goto error;
505 	}
506 
507 	/* Create minor node for each output. */
508 	for (op = outputs; op != NULL; op = op->next) {
509 		if (op->dev.valid) {
510 			(void) snprintf(name, sizeof (name), "output%d",
511 			    op->dev.index);
512 			if (ddi_create_minor_node(devi, name, S_IFCHR,
513 			    MINOR_OUTPUT(op->dev.index), DDI_PSEUDO, 0) ==
514 			    DDI_FAILURE) {
515 				ACPI_DRV_DBG(CE_WARN, NULL,
516 				    "%s: minor node create failed", name);
517 				goto error;
518 			}
519 		}
520 	}
521 
522 	/* Create minor node for display device. */
523 	if (ddi_create_minor_node(devi, "display", S_IFCHR, MINOR_DISPLAY(0),
524 	    DDI_PSEUDO, 0) == DDI_FAILURE) {
525 		ACPI_DRV_DBG(CE_WARN, NULL, "display: "
526 		    "minor node create failed");
527 		goto error;
528 	}
529 	/* Create minor node for lid. */
530 	if (ddi_create_minor_node(devi, "lid", S_IFCHR, MINOR_LID(0),
531 	    DDI_PSEUDO, 0) == DDI_FAILURE) {
532 		ACPI_DRV_DBG(CE_WARN, NULL, "lid: minor node create failed");
533 		goto error;
534 	}
535 	/* Create minor node for each battery and ac */
536 	for (bp = &acpi_drv_cbat[0]; bp < &acpi_drv_cbat[ACPI_DRV_MAX_BAT_NUM];
537 	    bp++) {
538 		if (bp->dev.valid) {
539 			(void) snprintf(name, sizeof (name), "battery%d",
540 			    bp->dev.index);
541 			if (ddi_create_minor_node(devi, name, S_IFCHR,
542 			    MINOR_BATT(bp->dev.index), DDI_PSEUDO, 0) ==
543 			    DDI_FAILURE) {
544 				ACPI_DRV_DBG(CE_WARN, NULL,
545 				    "%s: minor node create failed", name);
546 				goto error;
547 			}
548 		}
549 	}
550 	for (i = 0; i < nac; i++) {
551 		(void) snprintf(name, sizeof (name), "ac%d", i);
552 		if (ddi_create_minor_node(devi, name, S_IFCHR,
553 		    MINOR_AC(i), DDI_PSEUDO, 0) == DDI_FAILURE) {
554 			ACPI_DRV_DBG(CE_WARN, NULL,
555 			    "%s: minor node create failed", name);
556 			goto error;
557 		}
558 	}
559 
560 	return (DDI_SUCCESS);
561 
562 error:
563 	ddi_remove_minor_node(devi, NULL);
564 	acpi_drv_kstat_fini();
565 	acpi_drv_acpi_fini();
566 	acpi_drv_dip = NULL;
567 	return (DDI_FAILURE);
568 }
569 
570 static int
571 acpi_drv_detach(dev_info_t *devi, ddi_detach_cmd_t cmd)
572 {
573 	if (cmd != DDI_DETACH) {
574 		return (DDI_FAILURE);
575 	}
576 
577 	mutex_enter(&acpi_drv_mutex);
578 	ddi_remove_minor_node(devi, NULL);
579 
580 	acpi_drv_kstat_fini();
581 	acpi_drv_acpi_fini();
582 	mutex_exit(&acpi_drv_mutex);
583 	return (DDI_SUCCESS);
584 }
585 
586 /* ARGSUSED */
587 static int
588 acpi_drv_getinfo(dev_info_t *dip, ddi_info_cmd_t cmd, void *arg, void **resultp)
589 {
590 	switch (cmd) {
591 	case DDI_INFO_DEVT2DEVINFO:
592 		*resultp = acpi_drv_dip;
593 		return (DDI_SUCCESS);
594 	case DDI_INFO_DEVT2INSTANCE:
595 		*resultp = (void*) 0;
596 		return (DDI_SUCCESS);
597 	default:
598 		return (DDI_FAILURE);
599 	}
600 }
601 
602 /*ARGSUSED*/
603 static int
604 acpi_drv_open(dev_t *devp, int flag, int otyp, cred_t *crp)
605 {
606 	if (acpi_drv_dip == NULL) {
607 		return (ENXIO);
608 	}
609 
610 	return (0);
611 }
612 
613 /*ARGSUSED*/
614 static int
615 acpi_drv_close(dev_t dev, int flag, int otyp, cred_t *crp)
616 {
617 	return (0);
618 }
619 
620 /*ARGSUSED*/
621 static int
622 acpi_drv_ioctl(dev_t dev, int cmd, intptr_t arg, int mode, cred_t *cr,
623     int *rval)
624 {
625 	int minor;
626 	int type, index;
627 	int res = 0;
628 
629 	minor = getminor(dev);
630 	type = MINOR2TYPE(minor);
631 	index = MINOR2IDX(minor);
632 
633 	mutex_enter(&acpi_drv_mutex);
634 
635 	switch (type) {
636 	case ACPI_DRV_TYPE_CBAT:
637 		res = acpi_drv_cbat_ioctl(index, cmd, arg, mode, cr, rval);
638 		break;
639 	case ACPI_DRV_TYPE_AC:
640 		res = acpi_drv_ac_ioctl(index, cmd, arg, mode, cr, rval);
641 		break;
642 	case ACPI_DRV_TYPE_LID:
643 		res = acpi_drv_lid_ioctl(index, cmd, arg, mode, cr, rval);
644 		break;
645 	case ACPI_DRV_TYPE_OUTPUT:
646 		res = acpi_drv_output_ioctl(index, cmd, arg, mode, cr, rval);
647 		break;
648 	default:
649 		res = EINVAL;
650 		break;
651 	}
652 
653 	mutex_exit(&acpi_drv_mutex);
654 	return (res);
655 }
656 
657 /*ARGSUSED*/
658 static int
659 acpi_drv_cbat_ioctl(int index, int cmd, intptr_t arg, int mode, cred_t *cr,
660     int *rval)
661 {
662 	int res = 0;
663 	acpi_drv_warn_t bwarn;
664 	struct acpi_drv_cbat_state *bp;
665 
666 	ASSERT(mutex_owned(&acpi_drv_mutex));
667 
668 	bp = acpi_drv_idx2cbat(index);
669 	if (!bp || bp->dev.valid != 1) {
670 		return (ENXIO);
671 	}
672 
673 	switch (cmd) {
674 	/*
675 	 * Return _BIF(Battery Information) of battery[index],
676 	 * if battery plugged.
677 	 */
678 	case ACPI_DRV_IOC_INFO:
679 		if (bp->dev.present == 0) {
680 			res = ENXIO;
681 			break;
682 		}
683 
684 		res = acpi_drv_update_bif(bp);
685 		if (res != ACPI_DRV_OK) {
686 			break;
687 		}
688 		if (copyout(&bp->bif_cache, (void *)arg,
689 		    sizeof (bp->bif_cache))) {
690 			res = EFAULT;
691 		}
692 		break;
693 
694 	/*
695 	 * Return _BST(Battery Status) of battery[index],
696 	 * if battery plugged.
697 	 */
698 	case ACPI_DRV_IOC_STATUS:
699 		if (bp->dev.present == 0) {
700 			res = ENXIO;
701 			break;
702 		}
703 
704 		res = acpi_drv_update_bst(bp);
705 		if (res != ACPI_DRV_OK) {
706 			break;
707 		}
708 		if (copyout(&bp->bst_cache, (void *)arg,
709 		    sizeof (bp->bst_cache))) {
710 			res = EFAULT;
711 		}
712 		break;
713 
714 	/* Return the state of the battery bays in the system */
715 	case ACPI_DRV_IOC_BAY:
716 		{
717 			batt_bay_t bay;
718 
719 			bay.bay_number = nbat;
720 			bay.battery_map = 0;
721 			for (bp = &acpi_drv_cbat[0];
722 			    bp < &acpi_drv_cbat[ACPI_DRV_MAX_BAT_NUM]; bp++) {
723 				if (bp->dev.valid) {
724 					if (bp->dev.present) {
725 						bay.battery_map |=
726 						    (1 << bp->dev.index);
727 					}
728 				}
729 			}
730 			if (copyout(&bay, (void *)arg, sizeof (bay))) {
731 				res = EFAULT;
732 				break;
733 			}
734 		}
735 		break;
736 
737 	/*
738 	 * Return the current power source device if available:
739 	 * 0 -- battery supplying power
740 	 * 1 -- AC supplying power
741 	 */
742 	case ACPI_DRV_IOC_POWER_STATUS:
743 		{
744 			int val;
745 
746 			/* State not available */
747 			if (acpi_drv_psr_type == ACPI_DRV_TYPE_UNKNOWN) {
748 				res = ENXIO;
749 				break;
750 			}
751 			val = (acpi_drv_psr_type == ACPI_DRV_TYPE_AC) ? 1 : 0;
752 			if (copyout(&val, (void *)arg, sizeof (val))) {
753 				res = EFAULT;
754 				break;
755 			}
756 		}
757 		break;
758 
759 	/* Get charge-warn and charge-low levels for the whole system */
760 	case ACPI_DRV_IOC_GET_WARNING:
761 		bwarn.bw_enabled = acpi_drv_warn_enabled;
762 		bwarn.bw_charge_warn = acpi_drv_syn_warn_per;
763 		bwarn.bw_charge_low = acpi_drv_syn_low_per;
764 		if (copyout(&bwarn, (void *)arg, sizeof (&bwarn))) {
765 			res = EFAULT;
766 		}
767 		break;
768 
769 	/* Set charge-warn and charge-low levels for the whole system */
770 	case ACPI_DRV_IOC_SET_WARNING:
771 		if (drv_priv(cr)) {
772 			res = EPERM;
773 			break;
774 		}
775 		if (copyin((void *)arg, &bwarn, sizeof (bwarn))) {
776 			res = EFAULT;
777 			break;
778 		}
779 		res = acpi_drv_set_warn(&bwarn);
780 		break;
781 
782 	default:
783 		res = EINVAL;
784 		break;
785 	}
786 
787 	return (res);
788 }
789 
790 /*ARGSUSED*/
791 static int
792 acpi_drv_ac_ioctl(int index, int cmd, intptr_t arg, int mode, cred_t *cr,
793     int *rval)
794 {
795 	int res = 0;
796 	int ac_state;
797 	struct acpi_drv_ac_state *acp;
798 
799 	ASSERT(mutex_owned(&acpi_drv_mutex));
800 
801 	acp = acpi_drv_idx2ac(index);
802 	if (!acp || acp->dev.valid != 1) {
803 		return (ENXIO);
804 	}
805 
806 	switch (cmd) {
807 	/* Return the number of AC adapters in the system */
808 	case ACPI_DRV_IOC_AC_COUNT:
809 		if (copyout(&nac, (void *)arg, sizeof (nac))) {
810 			res = EFAULT;
811 		}
812 		break;
813 
814 	/*
815 	 * Return the state of AC[index] if available:
816 	 * 0 -- Off-line
817 	 * 1 -- On-line
818 	 */
819 	case ACPI_DRV_IOC_POWER_STATUS:
820 		if (!acp || acp->dev.valid != 1) {
821 			res = ENXIO;
822 			break;
823 		}
824 		/* State not available */
825 		if ((ac_state = acpi_drv_ac_present(acp)) == -1) {
826 			res = ENXIO;
827 			break;
828 		}
829 		if (copyout(&ac_state, (void *)arg, sizeof (ac_state))) {
830 			res = EFAULT;
831 		}
832 		break;
833 
834 	default:
835 		res = EINVAL;
836 		break;
837 	}
838 
839 	return (res);
840 }
841 
842 /*ARGSUSED*/
843 static int
844 acpi_drv_lid_ioctl(int index, int cmd, intptr_t arg, int mode, cred_t *cr,
845     int *rval)
846 {
847 	int res = 0;
848 
849 	switch (cmd) {
850 	case ACPI_DRV_IOC_LID_STATUS:
851 		if (lid.state_ok == ACPI_DRV_NTF_UNKNOWN) {
852 			/* State not available */
853 			res = acpi_drv_update_lid(&lid.dev);
854 			if (res != ACPI_DRV_OK) {
855 				res = ENXIO;
856 				break;
857 			}
858 		}
859 		if (copyout(&lid.state, (void *)arg, sizeof (lid.state))) {
860 			res = EFAULT;
861 			break;
862 		}
863 		break;
864 
865 	default:
866 		res = EINVAL;
867 		break;
868 	}
869 	return (res);
870 }
871 
872 /*ARGSUSED*/
873 static int
874 acpi_drv_chpoll(dev_t dev, short events, int anyyet,  short *reventsp,
875 	struct pollhead **phpp)
876 {
877 	if (!anyyet) {
878 		*phpp = &acpi_drv_pollhead;
879 	}
880 	*reventsp = 0;
881 	return (0);
882 }
883 
884 #ifdef DEBUG
885 static void
886 acpi_drv_printf(struct acpi_drv_dev *devp, uint_t lev,
887     const char *fmt, ...)
888 {
889 	va_list args;
890 
891 	mutex_enter(&acpi_drv_prt_mutex);
892 
893 	va_start(args, fmt);
894 	(void) vsprintf(acpi_drv_prt_buf, fmt, args);
895 	va_end(args);
896 
897 	if (devp) {
898 		cmn_err(lev, "%s.%s: %s", devp->hid, devp->uid,
899 		    acpi_drv_prt_buf);
900 	} else {
901 		cmn_err(lev, "%s", acpi_drv_prt_buf);
902 	}
903 	mutex_exit(&acpi_drv_prt_mutex);
904 }
905 
906 static void
907 acpi_drv_prt_notify(ACPI_HANDLE hdl, UINT32 val)
908 {
909 	ACPI_BUFFER buf;
910 	char str[1024];
911 
912 	buf.Length = sizeof (str);
913 	buf.Pointer = str;
914 	AcpiGetName(hdl, ACPI_FULL_PATHNAME, &buf);
915 	cmn_err(CE_NOTE, "AcpiNotify(%s, 0x%02x)", str, val);
916 }
917 #endif /* DEBUG */
918 
919 static void
920 acpi_drv_gen_sysevent(struct acpi_drv_dev *devp, char *ev, uint32_t val)
921 {
922 	nvlist_t *attr_list = NULL;
923 	int err;
924 	char pathname[MAXPATHLEN];
925 
926 	/* Allocate and build sysevent attribute list */
927 	err = nvlist_alloc(&attr_list, NV_UNIQUE_NAME_TYPE, DDI_NOSLEEP);
928 	if (err != 0) {
929 		ACPI_DRV_DBG(CE_WARN, NULL,
930 		    "cannot allocate memory for sysevent attributes\n");
931 		return;
932 	}
933 
934 	/* Add attributes */
935 	err = nvlist_add_string(attr_list, PWRCTL_DEV_HID, devp->hid);
936 	if (err != 0) {
937 		ACPI_DRV_DBG(CE_WARN, NULL,
938 		    "Failed to add attr [%s] for %s/%s event",
939 		    PWRCTL_DEV_HID, EC_PWRCTL, ev);
940 		nvlist_free(attr_list);
941 		return;
942 	}
943 
944 	err = nvlist_add_string(attr_list, PWRCTL_DEV_UID, devp->uid);
945 	if (err != 0) {
946 		ACPI_DRV_DBG(CE_WARN, NULL,
947 		    "Failed to add attr [%s] for %s/%s event",
948 		    PWRCTL_DEV_UID, EC_PWRCTL, ev);
949 		nvlist_free(attr_list);
950 		return;
951 	}
952 
953 	err = nvlist_add_uint32(attr_list, PWRCTL_DEV_INDEX, devp->index);
954 	if (err != 0) {
955 		ACPI_DRV_DBG(CE_WARN, NULL,
956 		    "Failed to add attr [%s] for %s/%s event",
957 		    PWRCTL_DEV_INDEX, EC_PWRCTL, ev);
958 		nvlist_free(attr_list);
959 		return;
960 	}
961 
962 	(void) ddi_pathname(acpi_drv_dip, pathname);
963 	err = nvlist_add_string(attr_list, PWRCTL_DEV_PHYS_PATH, pathname);
964 	if (err != 0) {
965 		ACPI_DRV_DBG(CE_WARN, NULL,
966 		    "Failed to add attr [%s] for %s/%s event",
967 		    PWRCTL_DEV_PHYS_PATH, EC_PWRCTL, ev);
968 		nvlist_free(attr_list);
969 		return;
970 	}
971 
972 	if (strcmp(ev, ESC_PWRCTL_WARN) && strcmp(ev, ESC_PWRCTL_LOW)) {
973 		goto finish;
974 	}
975 
976 	err = nvlist_add_uint32(attr_list, PWRCTL_CHARGE_LEVEL, val);
977 	if (err != 0) {
978 		ACPI_DRV_DBG(CE_WARN, NULL,
979 		    "Failed to add attr [%s] for %s/%s event",
980 		    PWRCTL_CHARGE_LEVEL, EC_PWRCTL, ev);
981 		nvlist_free(attr_list);
982 		return;
983 	}
984 
985 finish:
986 	ACPI_DRV_DBG(CE_NOTE, NULL, "SysEv(%s, %s.%s, %d)",
987 	    ev, devp->hid, devp->uid, val);
988 	/* Generate/log sysevent */
989 	err = ddi_log_sysevent(acpi_drv_dip, DDI_VENDOR_SUNW, EC_PWRCTL,
990 	    ev, attr_list, NULL, DDI_NOSLEEP);
991 #ifdef DEBUG
992 	if (err != DDI_SUCCESS) {
993 		ACPI_DRV_DBG(CE_WARN, NULL,
994 		    "cannot log sysevent, err code %x\n", err);
995 	}
996 #endif
997 
998 	nvlist_free(attr_list);
999 }
1000 
1001 static int
1002 acpi_drv_obj_copy(ACPI_OBJECT *op, char *bp, struct obj_desc *dp)
1003 {
1004 	ACPI_OBJECT *ep;
1005 	char *fp;
1006 
1007 	ep = &op->Package.Elements[0];
1008 	for (; dp->offset != -1; dp++) {
1009 		fp = bp + dp->offset;
1010 		if (dp->type == ACPI_TYPE_INTEGER &&
1011 		    ep->Type == dp->type) {
1012 #ifdef DEBUG
1013 			if (dp->size <= 4) {
1014 				ACPI_DRV_DBG(CE_NOTE, NULL, "\t%s: %u",
1015 				    dp->name,
1016 				    (uint32_t)ep->Integer.Value);
1017 			} else {
1018 #ifdef _LP64
1019 				ACPI_DRV_DBG(CE_NOTE, NULL, "\t%s: %lu",
1020 				    dp->name, (uint64_t)ep->Integer.Value);
1021 			}
1022 #else
1023 				ACPI_DRV_DBG(CE_NOTE, NULL, "\t%s: %llu",
1024 				    dp->name, (uint64_t)ep->Integer.Value);
1025 			}
1026 #endif /* _LP64 */
1027 #endif /* DEBUG */
1028 			*(uint32_t *)fp = ep->Integer.Value;
1029 		} else if (dp->type == ACPI_TYPE_STRING &&
1030 		    ep->Type == dp->type) {
1031 			ACPI_DRV_DBG(CE_NOTE, NULL, "\t%s: \"%s\"",
1032 			    dp->name, ep->String.Pointer);
1033 			(void) strncpy(fp, ep->String.Pointer, dp->size);
1034 		} else if (dp->type == ACPI_TYPE_STRING &&
1035 		    ep->Type == ACPI_TYPE_BUFFER) {
1036 #ifdef DEBUG
1037 			int len;
1038 			char buf[MAXNAMELEN + 1];
1039 
1040 			len = (MAXNAMELEN < ep->Buffer.Length) ?
1041 			    MAXNAMELEN : ep->Buffer.Length;
1042 			bcopy(ep->Buffer.Pointer, buf, len);
1043 			buf[len] = 0;
1044 			ACPI_DRV_DBG(CE_NOTE, NULL, "\t%s: [%d] \"%s\"",
1045 			    dp->name, len, buf);
1046 #endif
1047 
1048 			ASSERT(MAXNAMELEN >= ep->Buffer.Length);
1049 			bcopy(ep->Buffer.Pointer, fp, ep->Buffer.Length);
1050 		} else {
1051 			ACPI_DRV_DBG(CE_WARN, NULL,
1052 			    "Bad field at offset %d: type %d",
1053 			    dp->offset, ep->Type);
1054 			if (dp->type != ACPI_TYPE_STRING) {
1055 				return (ACPI_DRV_ERR);
1056 			}
1057 		}
1058 		ep++;
1059 	}
1060 
1061 	return (ACPI_DRV_OK);
1062 }
1063 
1064 /*
1065  * Returns the current power source devices. Used for the AC adapter and is
1066  * located under the AC adapter object in name space. Used to determine if
1067  * system is running off the AC adapter. This will report that the system is
1068  * not running on the AC adapter if any of the batteries in the system is
1069  * being forced to discharge through _BMC.
1070  *
1071  * Return value:
1072  *	 0 -- Off-line, ie. battery supplying system power
1073  *	 1 -- On-line, ie. AC supplying system power
1074  *	-1 -- Unknown, some error ocurred.
1075  * Note: It will also update the driver ac state.
1076  */
1077 static int
1078 acpi_drv_get_psr(struct acpi_drv_ac_state *acp)
1079 {
1080 	struct acpi_drv_dev *devp = &acp->dev;
1081 	int ac;
1082 
1083 	if (!devp->valid) {
1084 		ACPI_DRV_DBG(CE_WARN, NULL, "device not valid");
1085 		return (-1);
1086 	}
1087 
1088 	if (acpica_eval_int(devp->hdl, "_PSR", &ac) == AE_OK) {
1089 		ACPI_DRV_DBG(CE_NOTE, devp, "_PSR = %d", ac);
1090 		devp->present = ac;
1091 	} else {
1092 		ACPI_DRV_DBG(CE_WARN, NULL, "AcpiEval _PSR failed");
1093 		devp->present = -1;
1094 	}
1095 
1096 	return (ac);
1097 }
1098 
1099 /*
1100  * For most systems, the _STA for this device will always
1101  * return a value with bits 0-3 set and will toggle bit 4
1102  * to indicate the actual presence of a battery.
1103  *
1104  * Return value:
1105  *	 0 -- battery not present
1106  *	 1 -- battery present
1107  *	-1 -- Unknown, some error ocurred.
1108  * Note: It will also update the driver cbat state.
1109  */
1110 static int
1111 acpi_drv_get_sta(struct acpi_drv_cbat_state *bp)
1112 {
1113 	struct acpi_drv_dev *devp = &bp->dev;
1114 	int val;
1115 
1116 	if (!devp->valid) {
1117 		ACPI_DRV_DBG(CE_WARN, NULL, "device not valid");
1118 		return (-1);
1119 	}
1120 
1121 	if (acpica_eval_int(devp->hdl, "_STA", &val) == AE_OK) {
1122 		ACPI_DRV_DBG(CE_NOTE, devp, "_STA = 0x%x", val);
1123 		devp->present = ((val & STA_FLAG_BATT_PRESENT) != 0);
1124 	} else {
1125 		ACPI_DRV_DBG(CE_WARN, NULL, "AcpiEval _STA failed");
1126 		devp->present = -1;
1127 	}
1128 
1129 	return (val);
1130 }
1131 
1132 static int
1133 acpi_drv_update_bif(struct acpi_drv_cbat_state *bp)
1134 {
1135 	ACPI_BUFFER buf;
1136 	ACPI_OBJECT *objp;
1137 
1138 	/* BIF is only available when battery plugged */
1139 	ASSERT(bp->dev.present != 0);
1140 
1141 	/* Update internal BIF cache */
1142 	bp->bat_bifok = ACPI_DRV_NTF_UNKNOWN;
1143 
1144 	buf.Length = ACPI_ALLOCATE_BUFFER;
1145 	if (ACPI_FAILURE(AcpiEvaluateObjectTyped(bp->dev.hdl, "_BIF",
1146 	    NULL, &buf, ACPI_TYPE_PACKAGE))) {
1147 		ACPI_DRV_DBG(CE_WARN, NULL, "AcpiEval _BIF failed");
1148 		return (ACPI_DRV_ERR);
1149 	}
1150 
1151 	objp = buf.Pointer;
1152 	ACPI_DRV_DBG(CE_NOTE, &bp->dev, "get _BIF");
1153 	if (acpi_drv_obj_copy(objp, (char *)&bp->bif_cache, bif_desc) ==
1154 	    ACPI_DRV_ERR) {
1155 		AcpiOsFree(objp);
1156 		return (ACPI_DRV_ERR);
1157 	}
1158 	AcpiOsFree(objp);
1159 	bp->bat_bifok = ACPI_DRV_NTF_OK;
1160 	return (ACPI_DRV_OK);
1161 }
1162 
1163 static int
1164 acpi_drv_update_bst(struct acpi_drv_cbat_state *bp)
1165 {
1166 	ACPI_BUFFER buf;
1167 	ACPI_OBJECT *objp;
1168 
1169 	/* BST is only available when battery plugged */
1170 	ASSERT(bp->dev.present != 0);
1171 
1172 	/* Update internal BST cache */
1173 	bp->bat_bstok = ACPI_DRV_NTF_UNKNOWN;
1174 
1175 	buf.Length = ACPI_ALLOCATE_BUFFER;
1176 	if (ACPI_FAILURE(AcpiEvaluateObjectTyped(bp->dev.hdl, "_BST",
1177 	    NULL, &buf, ACPI_TYPE_PACKAGE))) {
1178 		ACPI_DRV_DBG(CE_WARN, NULL, "AcpiEval _BST failed");
1179 		return (ACPI_DRV_ERR);
1180 	}
1181 
1182 	objp = buf.Pointer;
1183 	ACPI_DRV_DBG(CE_NOTE, &bp->dev, "get _BST");
1184 	if (acpi_drv_obj_copy(objp, (char *)&bp->bst_cache, bst_desc) ==
1185 	    ACPI_DRV_ERR) {
1186 		AcpiOsFree(objp);
1187 		return (ACPI_DRV_ERR);
1188 	}
1189 	AcpiOsFree(objp);
1190 
1191 	if (bp->bst_cache.bst_rate == 0) {
1192 		bp->bst_cache.bst_state &= ~(ACPI_DRV_BST_CHARGING |
1193 		    ACPI_DRV_BST_DISCHARGING);
1194 	}
1195 	bp->bat_bstok = ACPI_DRV_NTF_OK;
1196 	return (ACPI_DRV_OK);
1197 }
1198 
1199 /*
1200  * Return value:
1201  *	 1 -- device On-line
1202  *	 0 -- device Off-line
1203  *	-1 -- Unknown, some error ocurred.
1204  */
1205 static int
1206 acpi_drv_dev_present(struct acpi_drv_dev *devp)
1207 {
1208 	if (!devp->valid) {
1209 		ACPI_DRV_DBG(CE_WARN, NULL, "device not valid");
1210 		return (-1);
1211 	}
1212 
1213 	ASSERT(devp->type != ACPI_DRV_TYPE_UNKNOWN);
1214 
1215 	/* Update the device state */
1216 	if (devp->present == -1) {
1217 		if (devp->type == ACPI_DRV_TYPE_AC) {
1218 			(void) acpi_drv_get_psr((struct acpi_drv_ac_state *)
1219 			    devp);
1220 		} else if (devp->type == ACPI_DRV_TYPE_CBAT) {
1221 			(void) acpi_drv_get_sta((struct acpi_drv_cbat_state *)
1222 			    devp);
1223 		}
1224 	}
1225 
1226 	return (devp->present);
1227 }
1228 
1229 /*
1230  * Check if the device p existance state has changed.
1231  * Return value:
1232  *	 1 -- changed
1233  *	 0 -- no change
1234  *	-1 -- unknown
1235  */
1236 static int
1237 acpi_drv_update_present(struct acpi_drv_dev *p)
1238 {
1239 	int old_present = p->present;
1240 	int new_present;
1241 
1242 	ASSERT(p && p->valid);
1243 
1244 	p->present = -1;
1245 	new_present = acpi_drv_dev_present(p);
1246 	if (new_present == -1) {
1247 		return (-1);
1248 	}
1249 	if (new_present != old_present) {
1250 		return (1);
1251 	}
1252 	return (0);
1253 }
1254 
1255 static void
1256 acpi_drv_set_psr(struct acpi_drv_dev *p)
1257 {
1258 	acpi_drv_psr_devp = p;
1259 	if (p != NULL) {
1260 		ACPI_DRV_DBG(CE_NOTE, p, "psr = .");
1261 		acpi_drv_psr_type = p->type;
1262 	} else {
1263 		ACPI_DRV_DBG(CE_NOTE, p, "psr = ?");
1264 		acpi_drv_psr_type = ACPI_DRV_TYPE_UNKNOWN;
1265 	}
1266 }
1267 
1268 /*
1269  * OSPM can determine independent warning and low battery
1270  * capacity values based on the OEM-designed levels, but
1271  * cannot set these values lower than the OEM-designed values.
1272  */
1273 static int
1274 acpi_drv_set_warn(acpi_drv_warn_t *bwp)
1275 {
1276 	uint32_t warn, low;
1277 
1278 	warn = acpi_drv_syn_last_cap * bwp->bw_charge_warn / 100;
1279 	low = acpi_drv_syn_last_cap * bwp->bw_charge_low / 100;
1280 
1281 	/* Update internal state */
1282 	if (bwp->bw_enabled) {
1283 		if (low >= warn || warn < acpi_drv_syn_oem_warn_cap ||
1284 		    low < acpi_drv_syn_oem_low_cap) {
1285 			ACPI_DRV_DBG(CE_WARN, NULL, "charge level error");
1286 			return (EINVAL);
1287 		}
1288 
1289 		ACPI_DRV_DBG(CE_NOTE, NULL, "set warn: warn=%d low=%d", warn,
1290 		    low);
1291 
1292 		acpi_drv_syn_warn_per = bwp->bw_charge_warn;
1293 		acpi_drv_syn_low_per = bwp->bw_charge_low;
1294 		acpi_drv_syn_warn_cap = warn;
1295 		acpi_drv_syn_low_cap = low;
1296 		acpi_drv_warn_enabled = 1;
1297 	} else {
1298 		acpi_drv_warn_enabled = 0;
1299 	}
1300 
1301 	return (0);
1302 }
1303 
1304 /*
1305  * Update information for the synthesis battery
1306  *
1307  * Note: Sometimes the value to be returned from _BST or _BIF will be
1308  * temporarily unknown. In this case, the method may return the value
1309  * 0xFFFFFFFF as a placeholder. When the value becomes known, the
1310  * appropriate notification (0x80 for _BST or 0x81 for BIF) should be
1311  * issued, in like manner to any other change in the data returned by
1312  * these methods. This will cause OSPM to re-evaluate the method obtaining
1313  * the correct data value.
1314  */
1315 static void
1316 acpi_drv_update_cap(int bif_changed)
1317 {
1318 	struct acpi_drv_cbat_state *bp;
1319 
1320 	if (bif_changed != 0) {
1321 		acpi_drv_syn_oem_warn_cap = 0xffffffff;
1322 		acpi_drv_syn_oem_low_cap = 0xffffffff;
1323 		acpi_drv_syn_last_cap = 0xffffffff;
1324 	}
1325 	acpi_drv_syn_last_level = acpi_drv_syn_rem_cap;
1326 	acpi_drv_syn_rem_cap = 0xffffffff; /* initially unknown */
1327 
1328 	for (bp = &acpi_drv_cbat[0]; bp < &acpi_drv_cbat[ACPI_DRV_MAX_BAT_NUM];
1329 	    bp++) {
1330 		if (bp->dev.valid) {
1331 			/* Escape the empty bays */
1332 			if (acpi_drv_cbat_present(bp) <= 0) {
1333 				continue;
1334 			}
1335 
1336 			if (bif_changed != 0 &&
1337 			    bp->bat_bifok == ACPI_DRV_NTF_OK) {
1338 				acpi_bif_t *bif;
1339 
1340 				bif = &bp->bif_cache;
1341 
1342 				if (acpi_drv_syn_last_cap == 0xffffffff) {
1343 					acpi_drv_syn_last_cap = 0;
1344 				}
1345 				acpi_drv_syn_last_cap += bif->bif_last_cap;
1346 
1347 				if (bif->bif_warn_cap == 0xffffffff ||
1348 				    bif->bif_low_cap == 0xffffffff) {
1349 					ACPI_DRV_DBG(CE_WARN, &bp->dev,
1350 					    "BIF value "
1351 					    "invalid, warn_cap=0x%x "
1352 					    "low_cap=0x%x", bif->bif_warn_cap,
1353 					    bif->bif_low_cap);
1354 					continue;
1355 				}
1356 				if (acpi_drv_syn_oem_warn_cap == 0xffffffff) {
1357 					acpi_drv_syn_oem_warn_cap = 0;
1358 				}
1359 				if (acpi_drv_syn_oem_low_cap == 0xffffffff) {
1360 					acpi_drv_syn_oem_low_cap = 0;
1361 				}
1362 
1363 				/*
1364 				 * Use the highest level as the synthesis
1365 				 * level.
1366 				 */
1367 				if (bif->bif_warn_cap >
1368 				    acpi_drv_syn_oem_warn_cap) {
1369 					acpi_drv_syn_oem_low_cap =
1370 					    bif->bif_low_cap;
1371 					acpi_drv_syn_oem_warn_cap =
1372 					    bif->bif_warn_cap;
1373 				}
1374 			}
1375 #ifdef DEBUG
1376 			else if (bif_changed) {
1377 				ACPI_DRV_DBG(CE_NOTE, &bp->dev,
1378 				    "BIF not ready");
1379 			}
1380 #endif
1381 
1382 			if (bp->bat_bstok == ACPI_DRV_NTF_OK) {
1383 				acpi_bst_t *bst;
1384 
1385 				bst = &bp->bst_cache;
1386 
1387 				/*
1388 				 * Batteries that are rechargeable and are in
1389 				 * the discharging state are required to return
1390 				 * a valid Battery Present Rate value.
1391 				 * 0xFFFFFFFF - Unknown rate/capacity
1392 				 */
1393 				if (bst->bst_rem_cap == 0xffffffff) {
1394 					ACPI_DRV_DBG(CE_WARN, &bp->dev,
1395 					    "BST value invalid, "
1396 					    "rate=0x%x cap=0x%x",
1397 					    bst->bst_rate, bst->bst_rem_cap);
1398 					continue;
1399 				}
1400 
1401 				if (acpi_drv_syn_rem_cap == 0xffffffff) {
1402 					acpi_drv_syn_rem_cap = 0;
1403 				}
1404 				acpi_drv_syn_rem_cap += bst->bst_rem_cap;
1405 				/* Check for overflow */
1406 				ASSERT(acpi_drv_syn_rem_cap >=
1407 				    bst->bst_rem_cap);
1408 			}
1409 #ifdef DEBUG
1410 			else {
1411 				ACPI_DRV_DBG(CE_NOTE, &bp->dev,
1412 				    "BST not ready");
1413 			}
1414 #endif
1415 		}
1416 	}
1417 
1418 	ACPI_DRV_DBG(CE_NOTE, NULL, "syn_cap: %d syn_oem_warn: %d "
1419 	    "syn_oem_low: %d", acpi_drv_syn_rem_cap, acpi_drv_syn_oem_warn_cap,
1420 	    acpi_drv_syn_oem_low_cap);
1421 }
1422 
1423 static struct acpi_drv_cbat_state *
1424 acpi_drv_idx2cbat(int idx)
1425 {
1426 	if (idx >= ACPI_DRV_MAX_BAT_NUM) {
1427 		return (NULL);
1428 	}
1429 	return (&acpi_drv_cbat[idx]);
1430 }
1431 
1432 static struct acpi_drv_ac_state *
1433 acpi_drv_idx2ac(int idx)
1434 {
1435 	if (idx >= ACPI_DRV_MAX_AC_NUM) {
1436 		return (NULL);
1437 	}
1438 	return (&acpi_drv_ac[idx]);
1439 }
1440 
1441 /*ARGSUSED*/
1442 static void
1443 acpi_drv_cbat_notify(ACPI_HANDLE hdl, UINT32 val, void *ctx)
1444 {
1445 	struct acpi_drv_cbat_state *bp = ctx;
1446 	struct acpi_drv_dev *devp = &bp->dev;
1447 	int bif_changed;
1448 	uint32_t eval;
1449 	char *ev;
1450 	acpi_bst_t *bst;
1451 
1452 	mutex_enter(&acpi_drv_mutex);
1453 	ACPI_DRV_PRT_NOTIFY(hdl, val);
1454 
1455 	switch (val) {
1456 	/*
1457 	 * BST has changed
1458 	 * Whenever the Battery State value changes, the
1459 	 * system will generate an SCI to notify the OS.
1460 	 *
1461 	 * Note: trip point is not used to implement the
1462 	 * warning levels.
1463 	 */
1464 	case 0x80:
1465 		/*
1466 		 * We always get 0x80 and 0x81 at battery plug/unplug,
1467 		 * but 0x80 may come first. In case that situation, we have
1468 		 * to update battery present state here too to update bst
1469 		 * correctly.
1470 		 */
1471 		bif_changed = acpi_drv_update_present(devp);
1472 
1473 		/* Omit events sent by empty battery slot */
1474 		if (devp->present == 0) {
1475 			break;
1476 		}
1477 
1478 		if (acpi_drv_update_bst(bp) != ACPI_DRV_OK) {
1479 			break;
1480 		}
1481 		acpi_drv_update_cap(bif_changed);
1482 
1483 		bst = &bp->bst_cache;
1484 		eval = bst->bst_rem_cap;
1485 
1486 		/*
1487 		 * Keep tracking the current power source device
1488 		 *
1489 		 * Note: Even no battery plugged, some system
1490 		 * send out 0x80 ACPI event. So make sure the battery
1491 		 * is present first.
1492 		 */
1493 		if (devp->present == 0) {
1494 			if (acpi_drv_psr_devp == devp) {
1495 				acpi_drv_set_psr(NULL);
1496 			}
1497 			break;
1498 		}
1499 		if (bst->bst_state & BST_FLAG_DISCHARGING) {
1500 			acpi_drv_set_psr(devp);
1501 		}
1502 		/*
1503 		 * The Critical battery state indicates that all
1504 		 * available batteries are discharged and do not
1505 		 * appear to be able to supply power to run the
1506 		 * system any longer. When this occurs, the OS
1507 		 * should attempt to perform an emergency shutdown.
1508 		 * Right now we do not shutdown.  This would
1509 		 * need some discussion first since it could be
1510 		 * controversial.
1511 		 */
1512 #ifdef DEBUG
1513 		if (bst->bst_state & BST_FLAG_CRITICAL) {
1514 			ACPI_DRV_DBG(CE_WARN, devp, "BST_FLAG_CRITICAL set");
1515 
1516 			/*
1517 			 * BST_FLAG_CRITICAL may set even with AC,
1518 			 * plugged, when plug/unplug battery. Check
1519 			 * to avoid erroneous shutdown.
1520 			 */
1521 			if (acpi_drv_psr_devp == devp &&
1522 			    bst->bst_rem_cap != 0xffffffff) {
1523 				ACPI_DRV_DBG(CE_WARN, NULL,
1524 				    "Battery in critical state");
1525 			}
1526 		} else
1527 #endif
1528 		if (acpi_drv_warn_enabled &&
1529 		    (bst->bst_state & BST_FLAG_DISCHARGING)) {
1530 			/*
1531 			 * This value is an estimation of the amount of
1532 			 * energy or battery capacity required by the
1533 			 * system to transition to any supported sleeping
1534 			 * state. When the OS detects that the total
1535 			 * available battery capacity is less than this
1536 			 * value, it will transition the system to a user
1537 			 * defined system state (S1-S5).
1538 			 */
1539 			if (acpi_drv_syn_last_level > acpi_drv_syn_low_cap &&
1540 			    acpi_drv_syn_rem_cap <= acpi_drv_syn_low_cap) {
1541 				acpi_drv_gen_sysevent(devp, ESC_PWRCTL_LOW,
1542 				    eval);
1543 			/*
1544 			 * When the total available energy (mWh) or capacity
1545 			 * (mAh) in the batteries falls below this level,
1546 			 * the OS will notify the user through the UI.
1547 			 */
1548 			} else if (acpi_drv_syn_last_level >
1549 			    acpi_drv_syn_warn_cap &&
1550 			    acpi_drv_syn_rem_cap <= acpi_drv_syn_warn_cap) {
1551 				acpi_drv_gen_sysevent(devp, ESC_PWRCTL_WARN,
1552 				    eval);
1553 			}
1554 		}
1555 
1556 		acpi_drv_gen_sysevent(devp, ESC_PWRCTL_STATE_CHANGE, 0);
1557 		pollwakeup(&acpi_drv_pollhead, ACPI_DRV_EVENTS);
1558 		break;
1559 
1560 	/* BIF has changed */
1561 	case 0x81:
1562 		/*
1563 		 * Note: Do not eliminate multiple ADD/REMOVE here,
1564 		 * because they may corresponding to different batterys.
1565 		 */
1566 		(void) acpi_drv_update_present(devp);
1567 		if (devp->present == 1) {
1568 			if (acpi_drv_update_bif(bp) != ACPI_DRV_OK) {
1569 				break;
1570 			}
1571 		}
1572 
1573 		acpi_drv_update_cap(1);
1574 
1575 		eval = devp->present;
1576 		ev = eval ? ESC_PWRCTL_ADD : ESC_PWRCTL_REMOVE;
1577 		acpi_drv_gen_sysevent(devp, ev, 0);
1578 		pollwakeup(&acpi_drv_pollhead, ACPI_DRV_EVENTS);
1579 		break;
1580 
1581 	case 0x82:
1582 	default:
1583 		break;
1584 	}
1585 
1586 	mutex_exit(&acpi_drv_mutex);
1587 }
1588 
1589 static int
1590 acpi_drv_update_lid(struct acpi_drv_dev *p)
1591 {
1592 	struct acpi_drv_lid_state *lp = (struct acpi_drv_lid_state *)p;
1593 
1594 	if (acpica_eval_int(p->hdl, "_LID", &lp->state) == AE_OK) {
1595 		lp->state_ok = ACPI_DRV_NTF_OK;
1596 		return (ACPI_DRV_OK);
1597 	}
1598 	return (ACPI_DRV_ERR);
1599 }
1600 
1601 /*ARGSUSED*/
1602 static void
1603 acpi_drv_ac_notify(ACPI_HANDLE hdl, UINT32 val, void *ctx)
1604 {
1605 	struct acpi_drv_ac_state *acp = ctx;
1606 	struct acpi_drv_dev *devp = &acp->dev;
1607 	int old_present;
1608 	char *ev;
1609 	int eval;
1610 
1611 	ACPI_DRV_PRT_NOTIFY(hdl, val);
1612 	if (val != 0x80) {
1613 		return;
1614 	}
1615 
1616 	mutex_enter(&acpi_drv_mutex);
1617 	/*
1618 	 * Note: if unplug and then quickly plug back, two ADD
1619 	 * events will be generated.
1620 	 */
1621 	old_present = devp->present;
1622 	eval = acpi_drv_get_psr(acp);
1623 
1624 	/* Eliminate redundant events */
1625 	if (eval != -1 && eval != old_present) {
1626 		/* Keep tracking the current power source device */
1627 		if (eval == 1) {
1628 			ev = ESC_PWRCTL_ADD;
1629 			acpi_drv_set_psr(devp);
1630 		} else {
1631 			ev = ESC_PWRCTL_REMOVE;
1632 			/* If AC was supplying the power, it's not now */
1633 			if (acpi_drv_psr_devp == devp) {
1634 				acpi_drv_set_psr(NULL);
1635 			}
1636 		}
1637 
1638 		acpi_drv_gen_sysevent(devp, ev, 0);
1639 		pollwakeup(&acpi_drv_pollhead, ACPI_DRV_EVENTS);
1640 	}
1641 
1642 	mutex_exit(&acpi_drv_mutex);
1643 }
1644 
1645 static void
1646 acpi_drv_lid_notify(ACPI_HANDLE hdl, UINT32 val, void *ctx)
1647 {
1648 	struct acpi_drv_lid_state *p = ctx;
1649 
1650 	ACPI_DRV_PRT_NOTIFY(hdl, val);
1651 	if (val == 0x80) {
1652 		mutex_enter(&acpi_drv_mutex);
1653 		if (acpi_drv_update_lid(&p->dev) == ACPI_DRV_OK) {
1654 			acpi_drv_gen_sysevent(&p->dev, p->state ?
1655 			    ESC_PWRCTL_ADD : ESC_PWRCTL_REMOVE, 0);
1656 		}
1657 		mutex_exit(&acpi_drv_mutex);
1658 	}
1659 }
1660 
1661 static int
1662 acpi_drv_obj_init(struct acpi_drv_dev *p)
1663 {
1664 	ACPI_DEVICE_INFO *info;
1665 	ACPI_BUFFER buf;
1666 	ACPI_NOTIFY_HANDLER ntf_handler = NULL;
1667 	ACPI_STATUS ret;
1668 
1669 	ASSERT(p != NULL && p->hdl != NULL);
1670 
1671 	p->valid = 0;
1672 
1673 	/* Info size is variable depending on existance of _CID */
1674 	buf.Length = ACPI_ALLOCATE_BUFFER;
1675 	ret = AcpiGetObjectInfo(p->hdl, &buf);
1676 	if (ACPI_FAILURE(ret)) {
1677 		ACPI_DRV_DBG(CE_WARN, NULL,
1678 		    "AcpiGetObjectInfo() fail: %d", (int32_t)ret);
1679 		return (ACPI_DRV_ERR);
1680 	}
1681 
1682 	info = buf.Pointer;
1683 	if ((info->Valid & ACPI_VALID_HID) == 0) {
1684 		ACPI_DRV_DBG(CE_WARN, NULL,
1685 		    "AcpiGetObjectInfo(): _HID not available");
1686 		(void) strncpy(p->uid, "\0", 9);
1687 	} else {
1688 		(void) strncpy(p->hid, info->HardwareId.Value, 9);
1689 	}
1690 	(void) strncpy(p->hid, info->HardwareId.Value, 9);
1691 
1692 	/*
1693 	 * This object is optional, but is required when the device
1694 	 * has no other way to report a persistent unique device ID.
1695 	 */
1696 	if ((info->Valid & ACPI_VALID_UID) == 0) {
1697 		ACPI_DRV_DBG(CE_WARN, NULL,
1698 		    "AcpiGetObjectInfo(): _UID not available");
1699 		/* Use 0 as the default _UID */
1700 		(void) strncpy(p->uid, "\0", 9);
1701 	} else {
1702 		(void) strncpy(p->uid, info->UniqueId.Value, 9);
1703 	}
1704 
1705 	p->valid = 1;
1706 
1707 	if (strcmp(p->hid, ACPI_DEVNAME_CBAT) == 0) {
1708 		struct acpi_drv_cbat_state *bp =
1709 		    (struct acpi_drv_cbat_state *)p;
1710 
1711 		p->type = ACPI_DRV_TYPE_CBAT;
1712 		p->index = nbat - 1;
1713 
1714 		/* Update device present state */
1715 		(void) acpi_drv_update_present(p);
1716 		if (p->present) {
1717 			(void) acpi_drv_update_bif(bp);
1718 			(void) acpi_drv_update_bst(bp);
1719 
1720 			/* Init the current power source */
1721 			if (bp->bst_cache.bst_state & BST_FLAG_DISCHARGING) {
1722 				acpi_drv_set_psr(p);
1723 			}
1724 		}
1725 		ntf_handler = acpi_drv_cbat_notify;
1726 		ACPI_DRV_DBG(CE_NOTE, p, "battery %s",
1727 		    (p->present ? "present" : "absent"));
1728 	} else if (strcmp(p->hid, ACPI_DEVNAME_AC) == 0) {
1729 		p->type = ACPI_DRV_TYPE_AC;
1730 		p->index = nac - 1;
1731 
1732 		/* Update device present state */
1733 		(void) acpi_drv_update_present(p);
1734 		if (p->present) {
1735 			/* Init the current power source */
1736 			acpi_drv_set_psr(p);
1737 		}
1738 		ntf_handler = acpi_drv_ac_notify;
1739 		ACPI_DRV_DBG(CE_NOTE, p, "AC %s",
1740 		    (p->present ? "on-line" : "off-line"));
1741 	} else if (strcmp(p->hid, ACPI_DEVNAME_LID) == 0) {
1742 		p->type = ACPI_DRV_TYPE_LID;
1743 		p->index = 0;
1744 		lid.state_ok = ACPI_DRV_NTF_UNKNOWN;
1745 		(void) acpi_drv_update_lid(p);
1746 		ntf_handler = acpi_drv_lid_notify;
1747 		ACPI_DRV_DBG(CE_NOTE, p, "added");
1748 	} else if (info->Valid & ACPI_VALID_ADR) {
1749 		p->adr = info->Address;
1750 		if (p->type == ACPI_DRV_TYPE_DISPLAY) {
1751 			p->index = 0;
1752 			/* Enable display control by OS */
1753 			display.mode = ACPI_DRV_DOS_SWITCH_OS_EVENT |
1754 			    ACPI_DRV_DOS_BRIGHT_OS;
1755 			acpi_drv_display_set_mode(&display, display.mode);
1756 		} else {
1757 			p->index = noutput - 1;
1758 			if (acpi_drv_output_init(p->hdl, p) == ACPI_DRV_ERR) {
1759 				p->valid = 0;
1760 				AcpiOsFree(info);
1761 				return (ACPI_DRV_ERR);
1762 			}
1763 			ntf_handler = acpi_drv_output_notify;
1764 			p->type = ACPI_DRV_TYPE_OUTPUT;
1765 		}
1766 	} else {
1767 		ACPI_DRV_DBG(CE_NOTE, p, "unknown device");
1768 		p->valid = 0;
1769 	}
1770 
1771 	/* Register ACPI battery related events */
1772 	if (ntf_handler != NULL) {
1773 		if (ACPI_FAILURE(AcpiInstallNotifyHandler(p->hdl,
1774 		    ACPI_ALL_NOTIFY, ntf_handler, p))) {
1775 			ACPI_DRV_DBG(CE_NOTE, NULL,
1776 			    "Notify handler for %s.%s install failed",
1777 			    p->hid, p->uid);
1778 			return (ACPI_DRV_ERR);
1779 		}
1780 	}
1781 
1782 	AcpiOsFree(info);
1783 	return (ACPI_DRV_OK);
1784 }
1785 
1786 /*ARGSUSED*/
1787 static ACPI_STATUS
1788 acpi_drv_find_cb(ACPI_HANDLE ObjHandle, UINT32 NestingLevel, void *Context,
1789     void **ReturnValue)
1790 {
1791 	struct acpi_drv_dev *devp;
1792 	int *type = (int *)Context;
1793 
1794 	if (*type == ACPI_DRV_TYPE_CBAT) {
1795 		struct acpi_drv_cbat_state *bp;
1796 
1797 		if (nbat == ACPI_DRV_MAX_BAT_NUM) {
1798 			ACPI_DRV_DBG(CE_WARN, NULL,
1799 			    "Need to support more batteries: "
1800 			    "BATTERY_MAX = %d", ACPI_DRV_MAX_BAT_NUM);
1801 			return (AE_LIMIT);
1802 		}
1803 		bp = &acpi_drv_cbat[nbat++];
1804 		devp = (struct acpi_drv_dev *)bp;
1805 	} else if (*type == ACPI_DRV_TYPE_AC) {
1806 		struct acpi_drv_ac_state *ap;
1807 
1808 		if (nac == ACPI_DRV_MAX_AC_NUM) {
1809 			ACPI_DRV_DBG(CE_WARN, NULL, "Need to support more ACs: "
1810 			    "AC_MAX = %d", ACPI_DRV_MAX_AC_NUM);
1811 			return (AE_LIMIT);
1812 		}
1813 		ap = &acpi_drv_ac[nac++];
1814 		devp = (struct acpi_drv_dev *)ap;
1815 	} else if (*type == ACPI_DRV_TYPE_LID) {
1816 		struct acpi_drv_lid_state *lp;
1817 
1818 		nlid++;
1819 		lp = &lid;
1820 		devp = (struct acpi_drv_dev *)lp;
1821 	} else if (*type == ACPI_DRV_TYPE_OUTPUT) {
1822 		int adr = 0;
1823 		ACPI_BUFFER buf1 = {ACPI_ALLOCATE_BUFFER, NULL};
1824 		ACPI_BUFFER buf2;
1825 		char str[256];
1826 		ACPI_HANDLE ohl = NULL;
1827 		struct acpi_drv_display_state *dp;
1828 		struct acpi_drv_output_state *op;
1829 
1830 		/*
1831 		 * Reduce the search by checking for support of _ADR
1832 		 * method.
1833 		 */
1834 		if (acpica_eval_int(ObjHandle, "_ADR", &adr) != AE_OK) {
1835 			return (AE_OK);
1836 		}
1837 
1838 		/*
1839 		 * Find the display device.
1840 		 */
1841 		if (ACPI_SUCCESS(AcpiEvaluateObjectTyped(ObjHandle, "_DOD",
1842 		    NULL, &buf1, ACPI_TYPE_PACKAGE))) {
1843 			AcpiOsFree(buf1.Pointer);
1844 
1845 			buf2.Pointer = str;
1846 			buf2.Length = sizeof (str);
1847 			if (!ACPI_FAILURE(AcpiGetName(ObjHandle,
1848 			    ACPI_FULL_PATHNAME, &buf2))) {
1849 				ACPI_DRV_DBG(CE_NOTE, NULL,
1850 				    "_DOD Supported Pathname=%s\n",
1851 				    (char *)buf2.Pointer);
1852 			}
1853 
1854 			dp = &display;
1855 			devp = (struct acpi_drv_dev *)dp;
1856 			devp->hdl = ObjHandle;
1857 			devp->type = ACPI_DRV_TYPE_DISPLAY;
1858 			(void) acpi_drv_obj_init(devp);
1859 
1860 			/*
1861 			 * Find the output devices.
1862 			 */
1863 			while (ACPI_SUCCESS(AcpiGetNextObject(ACPI_TYPE_DEVICE,
1864 			    ObjHandle, ohl, &ohl))) {
1865 				op = kmem_zalloc
1866 				    (sizeof (struct acpi_drv_output_state),
1867 				    KM_SLEEP);
1868 				if (outputs == NULL) {
1869 					outputs = op;
1870 					outputs->tail = op;
1871 				} else {
1872 					outputs->tail->next = op;
1873 					outputs->tail = op;
1874 				}
1875 
1876 				noutput++;
1877 				devp = (struct acpi_drv_dev *)op;
1878 				devp->op = op;
1879 				devp->hdl = ohl;
1880 				(void) acpi_drv_obj_init(devp);
1881 			}
1882 			dp->noutput = noutput;
1883 		}
1884 		return (AE_OK);
1885 	} else {
1886 		ACPI_DRV_DBG(CE_WARN, NULL, "acpi_drv_find_cb(): "
1887 		    "Unknown device");
1888 		return (AE_ERROR);
1889 	}
1890 
1891 	devp->hdl = ObjHandle;
1892 
1893 	/* Try to get as many working objs as possible */
1894 	(void) acpi_drv_obj_init(devp);
1895 	return (AE_OK);
1896 }
1897 
1898 static int
1899 acpi_drv_acpi_init()
1900 {
1901 	int *retp, type;
1902 	int status = ACPI_DRV_ERR;
1903 
1904 	/* Check to see if ACPI CA services are available */
1905 	if (AcpiSubsystemStatus() != AE_OK) {
1906 		ACPI_DRV_DBG(CE_WARN, NULL, "ACPI CA not ready");
1907 		return (status);
1908 	}
1909 
1910 	/* Init Control Method Batterys */
1911 	type = ACPI_DRV_TYPE_CBAT;
1912 	if (ACPI_SUCCESS(AcpiGetDevices(ACPI_DEVNAME_CBAT, acpi_drv_find_cb,
1913 	    &type, (void *)&retp)) && nbat) {
1914 		status = ACPI_DRV_OK;
1915 	}
1916 
1917 	/* Init AC */
1918 	type = ACPI_DRV_TYPE_AC;
1919 	if (ACPI_SUCCESS(AcpiGetDevices(ACPI_DEVNAME_AC, acpi_drv_find_cb,
1920 	    &type, (void *)&retp)) && nac) {
1921 		status = ACPI_DRV_OK;
1922 	}
1923 
1924 	/* Init LID */
1925 	type = ACPI_DRV_TYPE_LID;
1926 	if (ACPI_SUCCESS(AcpiGetDevices(ACPI_DEVNAME_LID, acpi_drv_find_cb,
1927 	    &type, (void *)&retp)) && nlid) {
1928 		status = ACPI_DRV_OK;
1929 	}
1930 
1931 	/* Init Output Devices */
1932 	type = ACPI_DRV_TYPE_OUTPUT;
1933 	if (ACPI_SUCCESS(AcpiGetDevices(NULL, acpi_drv_find_cb,
1934 	    &type, (void *)&retp)) && noutput) {
1935 		status = ACPI_DRV_OK;
1936 	}
1937 
1938 	acpi_drv_update_cap(1);
1939 
1940 	return (status);
1941 }
1942 
1943 static void
1944 acpi_drv_acpi_fini(void)
1945 {
1946 	int i;
1947 	struct acpi_drv_cbat_state *bp;
1948 	struct acpi_drv_output_state *op;
1949 
1950 	for (bp = &acpi_drv_cbat[0]; bp < &acpi_drv_cbat[ACPI_DRV_MAX_BAT_NUM];
1951 	    bp++) {
1952 		if (bp->dev.valid) {
1953 			AcpiRemoveNotifyHandler(bp->dev.hdl, ACPI_DEVICE_NOTIFY,
1954 			    acpi_drv_cbat_notify);
1955 		}
1956 	}
1957 	for (i = 0; i < nac; i++) {
1958 		AcpiRemoveNotifyHandler(acpi_drv_ac[i].dev.hdl,
1959 		    ACPI_DEVICE_NOTIFY, acpi_drv_ac_notify);
1960 	}
1961 	AcpiRemoveNotifyHandler(lid.dev.hdl, ACPI_DEVICE_NOTIFY,
1962 	    acpi_drv_lid_notify);
1963 	for (op = outputs; op != NULL; op = op->next) {
1964 		if (op->dev.valid) {
1965 			if (op->levels) {
1966 				kmem_free(op->levels,
1967 				    op->nlev * sizeof (uint32_t));
1968 			}
1969 			AcpiRemoveNotifyHandler(op->dev.hdl, ACPI_DEVICE_NOTIFY,
1970 			    acpi_drv_output_notify);
1971 		}
1972 		kmem_free(op, sizeof (struct acpi_drv_output_state));
1973 	}
1974 }
1975 
1976 /*ARGSUSED*/
1977 static int
1978 acpi_drv_kstat_power_update(kstat_t *ksp, int flag)
1979 {
1980 	if (flag == KSTAT_WRITE) {
1981 		return (EACCES);
1982 	}
1983 
1984 	mutex_enter(&acpi_drv_mutex);
1985 	if (acpi_drv_psr_type == ACPI_DRV_TYPE_UNKNOWN) {
1986 		mutex_exit(&acpi_drv_mutex);
1987 		return (EIO);
1988 	}
1989 	kstat_named_setstr(&acpi_drv_power_kstat.acpi_drv_power,
1990 	    acpi_drv_psr_type == ACPI_DRV_TYPE_AC ? AC : BATTERY);
1991 	acpi_drv_power_kstat.acpi_drv_supported_battery_count.value.ui32 =
1992 	    (uint32_t)nbat;
1993 	mutex_exit(&acpi_drv_mutex);
1994 
1995 	return (0);
1996 }
1997 
1998 /*ARGSUSED*/
1999 static int
2000 acpi_drv_kstat_warn_update(kstat_t *ksp, int flag)
2001 {
2002 	if (flag == KSTAT_WRITE) {
2003 		int ret = 0;
2004 		acpi_drv_warn_t bw;
2005 		acpi_drv_warn_kstat_t kbw;
2006 
2007 		kbw = *(acpi_drv_warn_kstat_t *)acpi_drv_warn_ksp->ks_data;
2008 
2009 		mutex_enter(&acpi_drv_mutex);
2010 		bw.bw_enabled  = kbw.acpi_drv_bw_enabled.value.ui32;
2011 		bw.bw_charge_warn = kbw.acpi_drv_bw_charge_warn.value.ui32;
2012 		bw.bw_charge_low = kbw.acpi_drv_bw_charge_low.value.ui32;
2013 		ret = acpi_drv_set_warn(&bw);
2014 		mutex_exit(&acpi_drv_mutex);
2015 
2016 		return (ret);
2017 	} else {
2018 		acpi_drv_warn_kstat_t *wp = &acpi_drv_warn_kstat;
2019 
2020 		mutex_enter(&acpi_drv_mutex);
2021 		wp->acpi_drv_bw_enabled.value.ui32 = acpi_drv_warn_enabled;
2022 		wp->acpi_drv_bw_charge_warn.value.ui32 = acpi_drv_syn_warn_per;
2023 		wp->acpi_drv_bw_charge_low.value.ui32 = acpi_drv_syn_low_per;
2024 		mutex_exit(&acpi_drv_mutex);
2025 
2026 		return (0);
2027 	}
2028 }
2029 
2030 static int
2031 acpi_drv_kstat_bif_update(kstat_t *ksp, int flag)
2032 {
2033 	struct acpi_drv_cbat_state *bp;
2034 	acpi_bif_t *bif;
2035 	acpi_drv_bif_kstat_t *kp;
2036 
2037 	if (flag == KSTAT_WRITE) {
2038 		return (EACCES);
2039 	}
2040 
2041 	bp = (struct acpi_drv_cbat_state *)ksp->ks_private;
2042 	mutex_enter(&acpi_drv_mutex);
2043 
2044 	if (acpi_drv_cbat_present(bp) <= 0) {
2045 		mutex_exit(&acpi_drv_mutex);
2046 		return (ENXIO);
2047 	}
2048 
2049 	bzero(&bif, sizeof (bif));
2050 	if (acpi_drv_update_bif(bp) != ACPI_DRV_OK) {
2051 		mutex_exit(&acpi_drv_mutex);
2052 		return (ENXIO);
2053 	}
2054 
2055 	bif = &bp->bif_cache;
2056 	kp = &acpi_drv_bif_kstat;
2057 
2058 	/* Update BIF */
2059 	kp->acpi_drv_bif_unit.value.ui32 = bif->bif_unit;
2060 	kp->acpi_drv_bif_design_cap.value.ui32 = bif->bif_design_cap;
2061 	kp->acpi_drv_bif_last_cap.value.ui32 = bif->bif_last_cap;
2062 	kp->acpi_drv_bif_tech.value.ui32 = bif->bif_tech;
2063 	kp->acpi_drv_bif_voltage.value.ui32 = bif->bif_voltage;
2064 	kp->acpi_drv_bif_warn_cap.value.ui32 = bif->bif_warn_cap;
2065 	kp->acpi_drv_bif_low_cap.value.ui32 = bif->bif_low_cap;
2066 	kp->acpi_drv_bif_gran1_cap.value.ui32 = bif->bif_gran1_cap;
2067 	kp->acpi_drv_bif_gran2_cap.value.ui32 = bif->bif_gran2_cap;
2068 
2069 	kstat_named_setstr(&kp->acpi_drv_bif_model, bif->bif_model);
2070 	kstat_named_setstr(&kp->acpi_drv_bif_serial, bif->bif_serial);
2071 	kstat_named_setstr(&kp->acpi_drv_bif_type, bif->bif_type);
2072 	kstat_named_setstr(&kp->acpi_drv_bif_oem_info, bif->bif_oem_info);
2073 
2074 	mutex_exit(&acpi_drv_mutex);
2075 	return (0);
2076 }
2077 
2078 static int
2079 acpi_drv_kstat_bst_update(kstat_t *ksp, int flag)
2080 {
2081 	struct acpi_drv_cbat_state *bp;
2082 	acpi_bst_t *bst;
2083 	acpi_drv_bst_kstat_t *kp;
2084 
2085 	if (flag == KSTAT_WRITE) {
2086 		return (EACCES);
2087 	}
2088 
2089 	bp = (struct acpi_drv_cbat_state *)ksp->ks_private;
2090 	mutex_enter(&acpi_drv_mutex);
2091 
2092 	if (acpi_drv_cbat_present(bp) <= 0) {
2093 		mutex_exit(&acpi_drv_mutex);
2094 		return (ENXIO);
2095 	}
2096 
2097 	bzero(&bst, sizeof (bst));
2098 	if (acpi_drv_update_bst(bp) != ACPI_DRV_OK) {
2099 		mutex_exit(&acpi_drv_mutex);
2100 		return (ENXIO);
2101 	}
2102 
2103 	bst = &bp->bst_cache;
2104 	kp = &acpi_drv_bst_kstat;
2105 
2106 	/* Update BST */
2107 	kp->acpi_drv_bst_state.value.ui32 = bst->bst_state;
2108 	kp->acpi_drv_bst_rate.value.ui32 = bst->bst_rate;
2109 	kp->acpi_drv_bst_rem_cap.value.ui32 = bst->bst_rem_cap;
2110 	kp->acpi_drv_bst_voltage.value.ui32 = bst->bst_voltage;
2111 
2112 	mutex_exit(&acpi_drv_mutex);
2113 	return (0);
2114 }
2115 
2116 static int
2117 acpi_drv_kstat_init(void)
2118 {
2119 	char name[KSTAT_STRLEN];
2120 	struct acpi_drv_cbat_state *bp;
2121 
2122 	/*
2123 	 * Allocate, initialize and install powerstatus and
2124 	 * supported_battery_count kstat.
2125 	 */
2126 	acpi_drv_power_ksp = kstat_create(ACPI_DRV_NAME, 0,
2127 	    ACPI_DRV_POWER_KSTAT_NAME, "misc",
2128 	    KSTAT_TYPE_NAMED,
2129 	    sizeof (acpi_drv_power_kstat) / sizeof (kstat_named_t),
2130 	    KSTAT_FLAG_VIRTUAL);
2131 	if (acpi_drv_power_ksp == NULL) {
2132 		ACPI_DRV_DBG(CE_WARN, NULL,
2133 		    "kstat_create(%s) fail", ACPI_DRV_POWER_KSTAT_NAME);
2134 		return (ACPI_DRV_ERR);
2135 	}
2136 
2137 	acpi_drv_power_ksp->ks_data = &acpi_drv_power_kstat;
2138 	acpi_drv_power_ksp->ks_update = acpi_drv_kstat_power_update;
2139 	acpi_drv_power_ksp->ks_data_size += MAXNAMELEN;
2140 	kstat_install(acpi_drv_power_ksp);
2141 
2142 	/*
2143 	 * Allocate, initialize and install battery_capacity_warning kstat.
2144 	 */
2145 	acpi_drv_warn_ksp = kstat_create(ACPI_DRV_NAME, 0,
2146 	    ACPI_DRV_BTWARN_KSTAT_NAME, "misc",
2147 	    KSTAT_TYPE_NAMED,
2148 	    sizeof (acpi_drv_warn_kstat) / sizeof (kstat_named_t),
2149 	    KSTAT_FLAG_VIRTUAL | KSTAT_FLAG_WRITABLE);
2150 	if (acpi_drv_warn_ksp == NULL) {
2151 		ACPI_DRV_DBG(CE_WARN, NULL,
2152 		    "kstat_create(%s) fail", ACPI_DRV_BTWARN_KSTAT_NAME);
2153 		return (ACPI_DRV_ERR);
2154 	}
2155 
2156 	acpi_drv_warn_ksp->ks_data = &acpi_drv_warn_kstat;
2157 	acpi_drv_warn_ksp->ks_update = acpi_drv_kstat_warn_update;
2158 	kstat_install(acpi_drv_warn_ksp);
2159 
2160 	/*
2161 	 * Allocate, initialize and install BIF and BST kstat
2162 	 * for each battery.
2163 	 */
2164 	for (bp = &acpi_drv_cbat[0]; bp < &acpi_drv_cbat[ACPI_DRV_MAX_BAT_NUM];
2165 	    bp++) {
2166 		if (bp->dev.valid) {
2167 			kstat_t *ksp;
2168 
2169 			/* BIF kstat */
2170 			(void) snprintf(name, KSTAT_STRLEN-1, "%s%d",
2171 			    ACPI_DRV_BIF_KSTAT_NAME, bp->dev.index);
2172 			ksp = kstat_create(ACPI_DRV_NAME, 0,
2173 			    name, "misc", KSTAT_TYPE_NAMED,
2174 			    sizeof (acpi_drv_bif_kstat) /
2175 			    sizeof (kstat_named_t), KSTAT_FLAG_VIRTUAL);
2176 			if (ksp == NULL) {
2177 				ACPI_DRV_DBG(CE_WARN, NULL,
2178 				    "kstat_create(%s) fail", name);
2179 				return (ACPI_DRV_ERR);
2180 			}
2181 			ACPI_DRV_DBG(CE_NOTE, NULL, "kstat_create(%s) ok",
2182 			    name);
2183 
2184 			bp->bat_bif_ksp = ksp;
2185 			ksp->ks_data = &acpi_drv_bif_kstat;
2186 			ksp->ks_update = acpi_drv_kstat_bif_update;
2187 			ksp->ks_data_size += MAXNAMELEN * 4;
2188 			ksp->ks_private = bp;
2189 
2190 			kstat_install(ksp);
2191 
2192 			/* BST kstat */
2193 			(void) snprintf(name, KSTAT_STRLEN-1, "%s%d",
2194 			    ACPI_DRV_BST_KSTAT_NAME, bp->dev.index);
2195 			ksp = kstat_create(ACPI_DRV_NAME, 0, name, "misc",
2196 			    KSTAT_TYPE_NAMED,
2197 			    sizeof (acpi_drv_bst_kstat) /
2198 			    sizeof (kstat_named_t),
2199 			    KSTAT_FLAG_VIRTUAL);
2200 			if (ksp == NULL) {
2201 				ACPI_DRV_DBG(CE_WARN, NULL,
2202 				    "kstat_create(%s) fail", name);
2203 				return (ACPI_DRV_ERR);
2204 			}
2205 			ACPI_DRV_DBG(CE_NOTE, NULL, "kstat_create(%s) ok",
2206 			    name);
2207 
2208 			bp->bat_bst_ksp = ksp;
2209 			ksp->ks_data = &acpi_drv_bst_kstat;
2210 			ksp->ks_update = acpi_drv_kstat_bst_update;
2211 			ksp->ks_data_size += MAXNAMELEN * 4;
2212 			ksp->ks_private = bp;
2213 
2214 			kstat_install(ksp);
2215 		}
2216 	}
2217 
2218 	return (ACPI_DRV_OK);
2219 }
2220 
2221 static void
2222 acpi_drv_kstat_fini()
2223 {
2224 	struct acpi_drv_cbat_state *bp;
2225 
2226 	if (acpi_drv_power_ksp != NULL) {
2227 		kstat_delete(acpi_drv_power_ksp);
2228 	}
2229 	if (acpi_drv_warn_ksp != NULL) {
2230 		kstat_delete(acpi_drv_warn_ksp);
2231 	}
2232 	for (bp = &acpi_drv_cbat[0]; bp < &acpi_drv_cbat[ACPI_DRV_MAX_BAT_NUM];
2233 	    bp++) {
2234 		if (bp->dev.valid) {
2235 			if (bp->bat_bif_ksp != NULL) {
2236 				kstat_delete(bp->bat_bif_ksp);
2237 			}
2238 			if (bp->bat_bst_ksp != NULL) {
2239 				kstat_delete(bp->bat_bst_ksp);
2240 			}
2241 		}
2242 	}
2243 }
2244 
2245 static int
2246 acpi_drv_set_int(ACPI_HANDLE dev, char *method, uint32_t aint)
2247 {
2248 	ACPI_OBJECT_LIST al;
2249 	ACPI_OBJECT ao;
2250 
2251 	al.Pointer = &ao;
2252 	al.Count = 1;
2253 	ao.Type = ACPI_TYPE_INTEGER;
2254 	ao.Integer.Value = aint;
2255 	return (AcpiEvaluateObject(dev, method, &al, NULL));
2256 }
2257 
2258 static int
2259 acpi_drv_output_init(ACPI_HANDLE hdl, struct acpi_drv_dev *dev)
2260 {
2261 	struct acpi_drv_output_state *op;
2262 	int adr;
2263 	ACPI_BUFFER buf1, buf2;
2264 	ACPI_OBJECT *objp;
2265 	char str[256];
2266 
2267 	if (acpica_eval_int(hdl, "_ADR", &adr) != AE_OK) {
2268 		return (ACPI_DRV_ERR);
2269 	}
2270 
2271 	op = dev->op;
2272 	op->adr = adr;
2273 
2274 	buf1.Pointer = str;
2275 	buf1.Length = sizeof (str);
2276 
2277 	if (!ACPI_FAILURE(AcpiGetName(hdl, ACPI_FULL_PATHNAME, &buf1))) {
2278 		ACPI_DRV_DBG(CE_NOTE, NULL, "Pathname=%s\n",
2279 		    (char *)buf1.Pointer);
2280 	}
2281 
2282 	buf2.Length = ACPI_ALLOCATE_BUFFER;
2283 	if (ACPI_SUCCESS(AcpiEvaluateObjectTyped(hdl, "_BCL",
2284 	    NULL, &buf2, ACPI_TYPE_PACKAGE))) {
2285 		int i, j, k, l, m, nlev, tmp;
2286 
2287 		ACPI_DRV_DBG(CE_NOTE, NULL, "_BCL supported\n");
2288 		objp = buf2.Pointer;
2289 		/*
2290 		 * op->nlev will be needed to free op->levels.
2291 		 */
2292 		op->nlev = nlev = objp->Package.Count;
2293 		op->levels = kmem_zalloc(nlev * sizeof (uint32_t),
2294 		    KM_SLEEP);
2295 		/*
2296 		 * Get all the supported brightness levels.
2297 		 */
2298 		for (i = 0; i < nlev; i++) {
2299 			ACPI_OBJECT *o = &objp->Package.Elements[i];
2300 			int lev = o->Integer.Value;
2301 
2302 			ACPI_DRV_DBG(CE_NOTE, NULL, "acpi_drv_output_init() "
2303 			    "brlev=%d i=%d nlev=%d\n", lev, i, nlev);
2304 			if (o->Type != ACPI_TYPE_INTEGER) {
2305 				continue;
2306 			}
2307 			op->levels[i] = lev;
2308 		}
2309 
2310 		/*
2311 		 * Sort the brightness levels.
2312 		 */
2313 		for (j = 0; j < nlev; j++) {
2314 			for (k = 0; k < nlev - 1; k++) {
2315 				if (op->levels[k] > op->levels[k+1]) {
2316 					tmp = op->levels[k+1];
2317 					op->levels[k+1] = op->levels[k];
2318 					op->levels[k] = tmp;
2319 				}
2320 			}
2321 		}
2322 
2323 		/*
2324 		 * The first two levels could be duplicated, so remove
2325 		 * any duplicates.
2326 		 */
2327 		for (l = 0; l < nlev - 1; l++) {
2328 			if (op->levels[l] == op->levels[l+1]) {
2329 				for (m = l + 1; m < nlev - 1; m++) {
2330 					op->levels[m] = op->levels[m+1];
2331 				}
2332 				nlev--;
2333 			}
2334 		}
2335 		op->num_levels = nlev;
2336 
2337 		AcpiOsFree(objp);
2338 		(void) acpi_drv_output_get_level(op);
2339 		ACPI_DRV_DBG(CE_NOTE, NULL, "acpi_drv_output_init(): "
2340 		    "create minor "
2341 		    "node for dev->adr=%"PRIu64, dev->adr);
2342 	} else {
2343 		ACPI_DRV_DBG(CE_NOTE, NULL, "_BCL NOT supported\n");
2344 	}
2345 
2346 	return (ACPI_DRV_OK);
2347 }
2348 
2349 /*ARGSUSED*/
2350 static int
2351 acpi_drv_output_ioctl(int index, int cmd, intptr_t arg, int mode, cred_t *cr,
2352     int *rval)
2353 {
2354 	struct acpi_drv_output_state *op;
2355 	int res = 0;
2356 	op = acpi_drv_idx2output(index);
2357 	if (!op || op->dev.valid != 1) {
2358 		return (ENXIO);
2359 	}
2360 
2361 	switch (cmd) {
2362 	case ACPI_DRV_IOC_INFO: {
2363 		struct acpi_drv_output_info inf;
2364 		inf.adr = op->adr;
2365 		inf.nlev = op->num_levels;
2366 		if (copyout(&inf, (void *)arg, sizeof (inf))) {
2367 			res = EFAULT;
2368 		}
2369 		break;
2370 	}
2371 
2372 	case ACPI_DRV_IOC_LEVELS:
2373 		if (copyout(op->levels, (void *)arg,
2374 		    sizeof (*op->levels) * op->num_levels)) {
2375 			res = EFAULT;
2376 		}
2377 		break;
2378 
2379 	case ACPI_DRV_IOC_STATUS: {
2380 		/*
2381 		 * Need to get the current levels through ACPI first
2382 		 * then go through array of levels to find index.
2383 		 */
2384 		struct acpi_drv_output_status status;
2385 		int i;
2386 
2387 		status.state = op->state;
2388 		status.num_levels = op->num_levels;
2389 		status.cur_level = op->cur_level;
2390 		for (i = 0; i < op->num_levels; i++) {
2391 			if (op->levels[i] == op->cur_level) {
2392 				status.cur_level_index = i;
2393 			ACPI_DRV_DBG(CE_NOTE, NULL, "ACPI_DRV_IOC_STATUS "
2394 			    "cur_level_index %d\n", i);
2395 				break;
2396 			}
2397 		}
2398 		if (copyout(&status, (void *)arg, sizeof (status))) {
2399 			res = EFAULT;
2400 		}
2401 		break;
2402 	}
2403 
2404 	case ACPI_DRV_IOC_SET_BRIGHTNESS: {
2405 		int level;
2406 
2407 		if (drv_priv(cr)) {
2408 			res = EPERM;
2409 			break;
2410 		}
2411 		if (copyin((void *)arg, &level, sizeof (level))) {
2412 			res = EFAULT;
2413 			break;
2414 		}
2415 		ACPI_DRV_DBG(CE_NOTE, NULL,
2416 		    "ACPI_DRV_IOC_SET_BRIGHTNESS level=%d\n", level);
2417 		if (acpi_drv_output_set_level(op, level) != ACPI_DRV_OK) {
2418 			res = EFAULT;
2419 		}
2420 		break;
2421 	}
2422 
2423 	default:
2424 		res = EINVAL;
2425 		break;
2426 	}
2427 	return (res);
2428 }
2429 
2430 static struct acpi_drv_output_state *
2431 acpi_drv_idx2output(int idx)
2432 {
2433 	struct acpi_drv_output_state *op = outputs;
2434 
2435 	while ((op != NULL) && (op->dev.index != idx)) {
2436 		op = op->next;
2437 	}
2438 	return (op);
2439 }
2440 
2441 /*
2442  * Get the current brightness level and index.
2443  */
2444 static int
2445 acpi_drv_output_get_level(struct acpi_drv_output_state *op)
2446 {
2447 	int i;
2448 
2449 	if (acpica_eval_int(op->dev.hdl, "_BQC", &op->cur_level) != AE_OK) {
2450 		op->cur_level = ACPI_DRV_NTF_UNKNOWN;
2451 		return (ACPI_DRV_ERR);
2452 	}
2453 	for (i = 0; i < op->num_levels; i++) {
2454 		if (op->levels[i] == op->cur_level) {
2455 			op->cur_level_index = i;
2456 			ACPI_DRV_DBG(CE_NOTE, NULL,
2457 			    "acpi_drv_output_get_level(): "
2458 			    "cur_level = %d, cur_level_index = %d\n",
2459 			    op->cur_level, i);
2460 			break;
2461 		}
2462 	}
2463 	return (ACPI_DRV_OK);
2464 }
2465 
2466 static int
2467 acpi_drv_output_set_level(struct acpi_drv_output_state *op, uint32_t level)
2468 {
2469 	if (acpi_drv_set_int(op->dev.hdl, "_BCM", op->levels[level]) !=
2470 	    AE_OK) {
2471 		return (ACPI_DRV_ERR);
2472 	}
2473 	op->cur_level = op->levels[level];
2474 	op->cur_level_index = level;
2475 	return (ACPI_DRV_OK);
2476 }
2477 
2478 static void
2479 acpi_drv_output_notify(ACPI_HANDLE hdl, UINT32 val, void *ctx)
2480 {
2481 	struct acpi_drv_dev *dev = ctx;
2482 	struct acpi_drv_output_state *op = dev->op;
2483 
2484 	ACPI_DRV_DBG(CE_NOTE, NULL, "acpi_drv_output_notify() val=0x%x\n", val);
2485 	mutex_enter(&acpi_drv_mutex);
2486 	ACPI_DRV_PRT_NOTIFY(hdl, val);
2487 	switch (val) {
2488 	case 0x86: /* increase brightness */
2489 		if (op->cur_level_index < op->num_levels - 1) {
2490 			if (acpi_drv_output_set_level(op,
2491 			    op->cur_level_index + 1) != AE_OK) {
2492 				break;
2493 			}
2494 		}
2495 		acpi_drv_gen_sysevent(&op->dev, ESC_PWRCTL_BRIGHTNESS_UP, 0);
2496 		break;
2497 	case 0x87: /* decrease brightness */
2498 		if (op->cur_level_index > 0) {
2499 			if (acpi_drv_output_set_level(op,
2500 			    op->cur_level_index - 1) != AE_OK) {
2501 				break;
2502 			}
2503 		}
2504 		acpi_drv_gen_sysevent(&op->dev, ESC_PWRCTL_BRIGHTNESS_DOWN, 0);
2505 		break;
2506 	default:
2507 		break;
2508 	}
2509 	mutex_exit(&acpi_drv_mutex);
2510 }
2511 
2512 /*
2513  * Set the display control modes of display switching and brightness
2514  * from BIOS or OSPM.
2515  */
2516 static void
2517 acpi_drv_display_set_mode(struct acpi_drv_display_state *dp, int state)
2518 {
2519 	if (acpi_drv_set_int(dp->dev.hdl, "_DOS", state) != AE_OK) {
2520 		ACPI_DRV_DBG(CE_WARN, NULL, "Cannot set display mode %d\n",
2521 		    state);
2522 	}
2523 }
2524