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