xref: /illumos-gate/usr/src/uts/i86pc/io/acpi_drv/acpi_drv.c (revision 02f22325adceea5762fbc7f49cee82e407e8f3a1)
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 };
326 static struct acpi_drv_output_state *outputs = NULL;
327 static int noutput = 0;
328 
329 struct acpi_drv_display_state {
330 	struct acpi_drv_dev dev;
331 	int mode;
332 	int noutput;
333 } display;
334 
335 static int acpi_drv_attach(dev_info_t *devi, ddi_attach_cmd_t cmd);
336 static int acpi_drv_detach(dev_info_t *devi, ddi_detach_cmd_t cmd);
337 static int acpi_drv_getinfo(dev_info_t *dip, ddi_info_cmd_t cmd, void *arg,
338     void **resultp);
339 static int acpi_drv_open(dev_t *devp, int flag, int otyp, cred_t *crp);
340 static int acpi_drv_close(dev_t dev, int flag, int otyp, cred_t *crp);
341 static int acpi_drv_ioctl(dev_t dev, int cmd, intptr_t arg, int mode,
342     cred_t *cr, int *rval);
343 static int acpi_drv_chpoll(dev_t dev, short events, int anyyet,
344     short *reventsp, struct pollhead **phpp);
345 static int acpi_drv_ac_ioctl(int index, int cmd, intptr_t arg, int mode,
346     cred_t *cr, int *rval);
347 static int acpi_drv_cbat_ioctl(int index, int cmd, intptr_t arg, int mode,
348     cred_t *cr, int *rval);
349 static int acpi_drv_lid_ioctl(int index, int cmd, intptr_t arg, int mode,
350     cred_t *cr, int *rval);
351 static int acpi_drv_output_ioctl(int index, int cmd, intptr_t arg, int mode,
352     cred_t *cr, int *rval);
353 #ifdef DEBUG
354 static void acpi_drv_printf(struct acpi_drv_dev *devp, uint_t lev,
355     const char *fmt, ...);
356 #endif
357 
358 /*
359  * Output device functions
360  */
361 static int acpi_drv_output_init(ACPI_HANDLE hdl, struct acpi_drv_dev *dev);
362 static void acpi_drv_output_notify(ACPI_HANDLE hdl, UINT32 val, void *ctx);
363 static int acpi_drv_output_get_state(struct acpi_drv_output_state *op);
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, *tail;
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 = tail = op;
1870 				} else {
1871 					tail->next = op;
1872 					tail = op;
1873 				}
1874 				noutput++;
1875 				devp = (struct acpi_drv_dev *)op;
1876 				devp->op = op;
1877 				devp->hdl = ohl;
1878 				(void) acpi_drv_obj_init(devp);
1879 			}
1880 			dp->noutput = noutput;
1881 		}
1882 		return (AE_OK);
1883 	} else {
1884 		ACPI_DRV_DBG(CE_WARN, NULL, "acpi_drv_find_cb(): "
1885 		    "Unknown device");
1886 		return (AE_ERROR);
1887 	}
1888 
1889 	devp->hdl = ObjHandle;
1890 
1891 	/* Try to get as many working objs as possible */
1892 	(void) acpi_drv_obj_init(devp);
1893 	return (AE_OK);
1894 }
1895 
1896 static int
1897 acpi_drv_acpi_init()
1898 {
1899 	int *retp, type;
1900 	int status = ACPI_DRV_ERR;
1901 
1902 	/* Check to see if ACPI CA services are available */
1903 	if (AcpiSubsystemStatus() != AE_OK) {
1904 		ACPI_DRV_DBG(CE_WARN, NULL, "ACPI CA not ready");
1905 		return (status);
1906 	}
1907 
1908 	/* Init Control Method Batterys */
1909 	type = ACPI_DRV_TYPE_CBAT;
1910 	if (ACPI_SUCCESS(AcpiGetDevices(ACPI_DEVNAME_CBAT, acpi_drv_find_cb,
1911 	    &type, (void *)&retp)) && nbat) {
1912 		status = ACPI_DRV_OK;
1913 	}
1914 
1915 	/* Init AC */
1916 	type = ACPI_DRV_TYPE_AC;
1917 	if (ACPI_SUCCESS(AcpiGetDevices(ACPI_DEVNAME_AC, acpi_drv_find_cb,
1918 	    &type, (void *)&retp)) && nac) {
1919 		status = ACPI_DRV_OK;
1920 	}
1921 
1922 	/* Init LID */
1923 	type = ACPI_DRV_TYPE_LID;
1924 	if (ACPI_SUCCESS(AcpiGetDevices(ACPI_DEVNAME_LID, acpi_drv_find_cb,
1925 	    &type, (void *)&retp)) && nlid) {
1926 		status = ACPI_DRV_OK;
1927 	}
1928 
1929 	/* Init Output Devices */
1930 	type = ACPI_DRV_TYPE_OUTPUT;
1931 	if (ACPI_SUCCESS(AcpiGetDevices(NULL, acpi_drv_find_cb,
1932 	    &type, (void *)&retp)) && noutput) {
1933 		status = ACPI_DRV_OK;
1934 	}
1935 
1936 	acpi_drv_update_cap(1);
1937 
1938 	return (status);
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; op != NULL; op = op->next) {
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 		kmem_free(op, sizeof (struct acpi_drv_output_state));
1971 	}
1972 }
1973 
1974 /*ARGSUSED*/
1975 static int
1976 acpi_drv_kstat_power_update(kstat_t *ksp, int flag)
1977 {
1978 	if (flag == KSTAT_WRITE) {
1979 		return (EACCES);
1980 	}
1981 
1982 	mutex_enter(&acpi_drv_mutex);
1983 	if (acpi_drv_psr_type == ACPI_DRV_TYPE_UNKNOWN) {
1984 		mutex_exit(&acpi_drv_mutex);
1985 		return (EIO);
1986 	}
1987 	kstat_named_setstr(&acpi_drv_power_kstat.acpi_drv_power,
1988 	    acpi_drv_psr_type == ACPI_DRV_TYPE_AC ? AC : BATTERY);
1989 	acpi_drv_power_kstat.acpi_drv_supported_battery_count.value.ui32 =
1990 	    (uint32_t)nbat;
1991 	mutex_exit(&acpi_drv_mutex);
1992 
1993 	return (0);
1994 }
1995 
1996 /*ARGSUSED*/
1997 static int
1998 acpi_drv_kstat_warn_update(kstat_t *ksp, int flag)
1999 {
2000 	if (flag == KSTAT_WRITE) {
2001 		int ret = 0;
2002 		acpi_drv_warn_t bw;
2003 		acpi_drv_warn_kstat_t kbw;
2004 
2005 		kbw = *(acpi_drv_warn_kstat_t *)acpi_drv_warn_ksp->ks_data;
2006 
2007 		mutex_enter(&acpi_drv_mutex);
2008 		bw.bw_enabled  = kbw.acpi_drv_bw_enabled.value.ui32;
2009 		bw.bw_charge_warn = kbw.acpi_drv_bw_charge_warn.value.ui32;
2010 		bw.bw_charge_low = kbw.acpi_drv_bw_charge_low.value.ui32;
2011 		ret = acpi_drv_set_warn(&bw);
2012 		mutex_exit(&acpi_drv_mutex);
2013 
2014 		return (ret);
2015 	} else {
2016 		acpi_drv_warn_kstat_t *wp = &acpi_drv_warn_kstat;
2017 
2018 		mutex_enter(&acpi_drv_mutex);
2019 		wp->acpi_drv_bw_enabled.value.ui32 = acpi_drv_warn_enabled;
2020 		wp->acpi_drv_bw_charge_warn.value.ui32 = acpi_drv_syn_warn_per;
2021 		wp->acpi_drv_bw_charge_low.value.ui32 = acpi_drv_syn_low_per;
2022 		mutex_exit(&acpi_drv_mutex);
2023 
2024 		return (0);
2025 	}
2026 }
2027 
2028 static int
2029 acpi_drv_kstat_bif_update(kstat_t *ksp, int flag)
2030 {
2031 	struct acpi_drv_cbat_state *bp;
2032 	acpi_bif_t *bif;
2033 	acpi_drv_bif_kstat_t *kp;
2034 
2035 	if (flag == KSTAT_WRITE) {
2036 		return (EACCES);
2037 	}
2038 
2039 	bp = (struct acpi_drv_cbat_state *)ksp->ks_private;
2040 	mutex_enter(&acpi_drv_mutex);
2041 
2042 	if (acpi_drv_cbat_present(bp) <= 0) {
2043 		mutex_exit(&acpi_drv_mutex);
2044 		return (ENXIO);
2045 	}
2046 
2047 	bzero(&bif, sizeof (bif));
2048 	if (acpi_drv_update_bif(bp) != ACPI_DRV_OK) {
2049 		mutex_exit(&acpi_drv_mutex);
2050 		return (ENXIO);
2051 	}
2052 
2053 	bif = &bp->bif_cache;
2054 	kp = &acpi_drv_bif_kstat;
2055 
2056 	/* Update BIF */
2057 	kp->acpi_drv_bif_unit.value.ui32 = bif->bif_unit;
2058 	kp->acpi_drv_bif_design_cap.value.ui32 = bif->bif_design_cap;
2059 	kp->acpi_drv_bif_last_cap.value.ui32 = bif->bif_last_cap;
2060 	kp->acpi_drv_bif_tech.value.ui32 = bif->bif_tech;
2061 	kp->acpi_drv_bif_voltage.value.ui32 = bif->bif_voltage;
2062 	kp->acpi_drv_bif_warn_cap.value.ui32 = bif->bif_warn_cap;
2063 	kp->acpi_drv_bif_low_cap.value.ui32 = bif->bif_low_cap;
2064 	kp->acpi_drv_bif_gran1_cap.value.ui32 = bif->bif_gran1_cap;
2065 	kp->acpi_drv_bif_gran2_cap.value.ui32 = bif->bif_gran2_cap;
2066 
2067 	kstat_named_setstr(&kp->acpi_drv_bif_model, bif->bif_model);
2068 	kstat_named_setstr(&kp->acpi_drv_bif_serial, bif->bif_serial);
2069 	kstat_named_setstr(&kp->acpi_drv_bif_type, bif->bif_type);
2070 	kstat_named_setstr(&kp->acpi_drv_bif_oem_info, bif->bif_oem_info);
2071 
2072 	mutex_exit(&acpi_drv_mutex);
2073 	return (0);
2074 }
2075 
2076 static int
2077 acpi_drv_kstat_bst_update(kstat_t *ksp, int flag)
2078 {
2079 	struct acpi_drv_cbat_state *bp;
2080 	acpi_bst_t *bst;
2081 	acpi_drv_bst_kstat_t *kp;
2082 
2083 	if (flag == KSTAT_WRITE) {
2084 		return (EACCES);
2085 	}
2086 
2087 	bp = (struct acpi_drv_cbat_state *)ksp->ks_private;
2088 	mutex_enter(&acpi_drv_mutex);
2089 
2090 	if (acpi_drv_cbat_present(bp) <= 0) {
2091 		mutex_exit(&acpi_drv_mutex);
2092 		return (ENXIO);
2093 	}
2094 
2095 	bzero(&bst, sizeof (bst));
2096 	if (acpi_drv_update_bst(bp) != ACPI_DRV_OK) {
2097 		mutex_exit(&acpi_drv_mutex);
2098 		return (ENXIO);
2099 	}
2100 
2101 	bst = &bp->bst_cache;
2102 	kp = &acpi_drv_bst_kstat;
2103 
2104 	/* Update BST */
2105 	kp->acpi_drv_bst_state.value.ui32 = bst->bst_state;
2106 	kp->acpi_drv_bst_rate.value.ui32 = bst->bst_rate;
2107 	kp->acpi_drv_bst_rem_cap.value.ui32 = bst->bst_rem_cap;
2108 	kp->acpi_drv_bst_voltage.value.ui32 = bst->bst_voltage;
2109 
2110 	mutex_exit(&acpi_drv_mutex);
2111 	return (0);
2112 }
2113 
2114 static int
2115 acpi_drv_kstat_init(void)
2116 {
2117 	char name[KSTAT_STRLEN];
2118 	struct acpi_drv_cbat_state *bp;
2119 
2120 	/*
2121 	 * Allocate, initialize and install powerstatus and
2122 	 * supported_battery_count kstat.
2123 	 */
2124 	acpi_drv_power_ksp = kstat_create(ACPI_DRV_NAME, 0,
2125 	    ACPI_DRV_POWER_KSTAT_NAME, "misc",
2126 	    KSTAT_TYPE_NAMED,
2127 	    sizeof (acpi_drv_power_kstat) / sizeof (kstat_named_t),
2128 	    KSTAT_FLAG_VIRTUAL);
2129 	if (acpi_drv_power_ksp == NULL) {
2130 		ACPI_DRV_DBG(CE_WARN, NULL,
2131 		    "kstat_create(%s) fail", ACPI_DRV_POWER_KSTAT_NAME);
2132 		return (ACPI_DRV_ERR);
2133 	}
2134 
2135 	acpi_drv_power_ksp->ks_data = &acpi_drv_power_kstat;
2136 	acpi_drv_power_ksp->ks_update = acpi_drv_kstat_power_update;
2137 	acpi_drv_power_ksp->ks_data_size += MAXNAMELEN;
2138 	kstat_install(acpi_drv_power_ksp);
2139 
2140 	/*
2141 	 * Allocate, initialize and install battery_capacity_warning kstat.
2142 	 */
2143 	acpi_drv_warn_ksp = kstat_create(ACPI_DRV_NAME, 0,
2144 	    ACPI_DRV_BTWARN_KSTAT_NAME, "misc",
2145 	    KSTAT_TYPE_NAMED,
2146 	    sizeof (acpi_drv_warn_kstat) / sizeof (kstat_named_t),
2147 	    KSTAT_FLAG_VIRTUAL | KSTAT_FLAG_WRITABLE);
2148 	if (acpi_drv_warn_ksp == NULL) {
2149 		ACPI_DRV_DBG(CE_WARN, NULL,
2150 		    "kstat_create(%s) fail", ACPI_DRV_BTWARN_KSTAT_NAME);
2151 		return (ACPI_DRV_ERR);
2152 	}
2153 
2154 	acpi_drv_warn_ksp->ks_data = &acpi_drv_warn_kstat;
2155 	acpi_drv_warn_ksp->ks_update = acpi_drv_kstat_warn_update;
2156 	kstat_install(acpi_drv_warn_ksp);
2157 
2158 	/*
2159 	 * Allocate, initialize and install BIF and BST kstat
2160 	 * for each battery.
2161 	 */
2162 	for (bp = &acpi_drv_cbat[0]; bp < &acpi_drv_cbat[ACPI_DRV_MAX_BAT_NUM];
2163 	    bp++) {
2164 		if (bp->dev.valid) {
2165 			kstat_t *ksp;
2166 
2167 			/* BIF kstat */
2168 			(void) snprintf(name, KSTAT_STRLEN-1, "%s%d",
2169 			    ACPI_DRV_BIF_KSTAT_NAME, bp->dev.index);
2170 			ksp = kstat_create(ACPI_DRV_NAME, 0,
2171 			    name, "misc", KSTAT_TYPE_NAMED,
2172 			    sizeof (acpi_drv_bif_kstat) /
2173 			    sizeof (kstat_named_t), KSTAT_FLAG_VIRTUAL);
2174 			if (ksp == NULL) {
2175 				ACPI_DRV_DBG(CE_WARN, NULL,
2176 				    "kstat_create(%s) fail", name);
2177 				return (ACPI_DRV_ERR);
2178 			}
2179 			ACPI_DRV_DBG(CE_NOTE, NULL, "kstat_create(%s) ok",
2180 			    name);
2181 
2182 			bp->bat_bif_ksp = ksp;
2183 			ksp->ks_data = &acpi_drv_bif_kstat;
2184 			ksp->ks_update = acpi_drv_kstat_bif_update;
2185 			ksp->ks_data_size += MAXNAMELEN * 4;
2186 			ksp->ks_private = bp;
2187 
2188 			kstat_install(ksp);
2189 
2190 			/* BST kstat */
2191 			(void) snprintf(name, KSTAT_STRLEN-1, "%s%d",
2192 			    ACPI_DRV_BST_KSTAT_NAME, bp->dev.index);
2193 			ksp = kstat_create(ACPI_DRV_NAME, 0, name, "misc",
2194 			    KSTAT_TYPE_NAMED,
2195 			    sizeof (acpi_drv_bst_kstat) /
2196 			    sizeof (kstat_named_t),
2197 			    KSTAT_FLAG_VIRTUAL);
2198 			if (ksp == NULL) {
2199 				ACPI_DRV_DBG(CE_WARN, NULL,
2200 				    "kstat_create(%s) fail", name);
2201 				return (ACPI_DRV_ERR);
2202 			}
2203 			ACPI_DRV_DBG(CE_NOTE, NULL, "kstat_create(%s) ok",
2204 			    name);
2205 
2206 			bp->bat_bst_ksp = ksp;
2207 			ksp->ks_data = &acpi_drv_bst_kstat;
2208 			ksp->ks_update = acpi_drv_kstat_bst_update;
2209 			ksp->ks_data_size += MAXNAMELEN * 4;
2210 			ksp->ks_private = bp;
2211 
2212 			kstat_install(ksp);
2213 		}
2214 	}
2215 
2216 	return (ACPI_DRV_OK);
2217 }
2218 
2219 static void
2220 acpi_drv_kstat_fini()
2221 {
2222 	struct acpi_drv_cbat_state *bp;
2223 
2224 	if (acpi_drv_power_ksp != NULL) {
2225 		kstat_delete(acpi_drv_power_ksp);
2226 	}
2227 	if (acpi_drv_warn_ksp != NULL) {
2228 		kstat_delete(acpi_drv_warn_ksp);
2229 	}
2230 	for (bp = &acpi_drv_cbat[0]; bp < &acpi_drv_cbat[ACPI_DRV_MAX_BAT_NUM];
2231 	    bp++) {
2232 		if (bp->dev.valid) {
2233 			if (bp->bat_bif_ksp != NULL) {
2234 				kstat_delete(bp->bat_bif_ksp);
2235 			}
2236 			if (bp->bat_bst_ksp != NULL) {
2237 				kstat_delete(bp->bat_bst_ksp);
2238 			}
2239 		}
2240 	}
2241 }
2242 
2243 static int
2244 acpi_drv_set_int(ACPI_HANDLE dev, char *method, uint32_t aint)
2245 {
2246 	ACPI_OBJECT_LIST al;
2247 	ACPI_OBJECT ao;
2248 
2249 	al.Pointer = &ao;
2250 	al.Count = 1;
2251 	ao.Type = ACPI_TYPE_INTEGER;
2252 	ao.Integer.Value = aint;
2253 	return (AcpiEvaluateObject(dev, method, &al, NULL));
2254 }
2255 
2256 static int
2257 acpi_drv_output_init(ACPI_HANDLE hdl, struct acpi_drv_dev *dev)
2258 {
2259 	struct acpi_drv_output_state *op;
2260 	int adr;
2261 	ACPI_BUFFER buf1, buf2;
2262 	ACPI_OBJECT *objp;
2263 	char str[256];
2264 
2265 	if (acpica_eval_int(hdl, "_ADR", &adr) != AE_OK) {
2266 		return (ACPI_DRV_ERR);
2267 	}
2268 
2269 	op = dev->op;
2270 	op->adr = adr;
2271 
2272 	buf1.Pointer = str;
2273 	buf1.Length = sizeof (str);
2274 
2275 	if (!ACPI_FAILURE(AcpiGetName(hdl, ACPI_FULL_PATHNAME, &buf1))) {
2276 		ACPI_DRV_DBG(CE_NOTE, NULL, "Pathname=%s\n",
2277 		    (char *)buf1.Pointer);
2278 	}
2279 
2280 	buf2.Length = ACPI_ALLOCATE_BUFFER;
2281 	if (ACPI_SUCCESS(AcpiEvaluateObjectTyped(hdl, "_BCL",
2282 	    NULL, &buf2, ACPI_TYPE_PACKAGE))) {
2283 		int i, j, k, l, m, nlev, tmp;
2284 
2285 		ACPI_DRV_DBG(CE_NOTE, NULL, "_BCL supported\n");
2286 		objp = buf2.Pointer;
2287 		/*
2288 		 * op->nlev will be needed to free op->levels.
2289 		 */
2290 		op->nlev = nlev = objp->Package.Count;
2291 		op->levels = kmem_zalloc(nlev * sizeof (uint32_t),
2292 		    KM_SLEEP);
2293 		/*
2294 		 * Get all the supported brightness levels.
2295 		 */
2296 		for (i = 0; i < nlev; i++) {
2297 			ACPI_OBJECT *o = &objp->Package.Elements[i];
2298 			int lev = o->Integer.Value;
2299 
2300 			ACPI_DRV_DBG(CE_NOTE, NULL, "acpi_drv_output_init() "
2301 			    "brlev=%d i=%d nlev=%d\n", lev, i, nlev);
2302 			if (o->Type != ACPI_TYPE_INTEGER) {
2303 				continue;
2304 			}
2305 			op->levels[i] = lev;
2306 		}
2307 
2308 		/*
2309 		 * Sort the brightness levels.
2310 		 */
2311 		for (j = 0; j < nlev; j++) {
2312 			for (k = 0; k < nlev - 1; k++) {
2313 				if (op->levels[k] > op->levels[k+1]) {
2314 					tmp = op->levels[k+1];
2315 					op->levels[k+1] = op->levels[k];
2316 					op->levels[k] = tmp;
2317 				}
2318 			}
2319 		}
2320 
2321 		/*
2322 		 * The first two levels could be duplicated, so remove
2323 		 * any duplicates.
2324 		 */
2325 		for (l = 0; l < nlev - 1; l++) {
2326 			if (op->levels[l] == op->levels[l+1]) {
2327 				for (m = l + 1; m < nlev - 1; m++) {
2328 					op->levels[m] = op->levels[m+1];
2329 				}
2330 				nlev--;
2331 			}
2332 		}
2333 		op->num_levels = nlev;
2334 
2335 		AcpiOsFree(objp);
2336 		(void) acpi_drv_output_get_level(op);
2337 		ACPI_DRV_DBG(CE_NOTE, NULL, "acpi_drv_output_init(): "
2338 		    "create minor "
2339 		    "node for dev->adr=%"PRIu64, dev->adr);
2340 	} else {
2341 		ACPI_DRV_DBG(CE_NOTE, NULL, "_BCL NOT supported\n");
2342 	}
2343 
2344 	(void) acpi_drv_output_get_state(op);
2345 	return (ACPI_DRV_OK);
2346 }
2347 
2348 /*ARGSUSED*/
2349 static int
2350 acpi_drv_output_ioctl(int index, int cmd, intptr_t arg, int mode, cred_t *cr,
2351     int *rval)
2352 {
2353 	struct acpi_drv_output_state *op;
2354 	int res = 0;
2355 	op = acpi_drv_idx2output(index);
2356 	if (!op || op->dev.valid != 1) {
2357 		return (ENXIO);
2358 	}
2359 
2360 	switch (cmd) {
2361 	case ACPI_DRV_IOC_INFO: {
2362 		struct acpi_drv_output_info inf;
2363 		inf.adr = op->adr;
2364 		inf.nlev = op->num_levels;
2365 		if (copyout(&inf, (void *)arg, sizeof (inf))) {
2366 			res = EFAULT;
2367 		}
2368 		break;
2369 	}
2370 
2371 	case ACPI_DRV_IOC_LEVELS:
2372 		if (copyout(op->levels, (void *)arg,
2373 		    sizeof (*op->levels) * op->num_levels)) {
2374 			res = EFAULT;
2375 		}
2376 		break;
2377 
2378 	case ACPI_DRV_IOC_STATUS: {
2379 		/*
2380 		 * Need to get the current levels through ACPI first
2381 		 * then go through array of levels to find index.
2382 		 */
2383 		struct acpi_drv_output_status status;
2384 		int i;
2385 
2386 		status.state = op->state;
2387 		status.num_levels = op->num_levels;
2388 		status.cur_level = op->cur_level;
2389 		for (i = 0; i < op->num_levels; i++) {
2390 			if (op->levels[i] == op->cur_level) {
2391 				status.cur_level_index = i;
2392 			ACPI_DRV_DBG(CE_NOTE, NULL, "ACPI_DRV_IOC_STATUS "
2393 			    "cur_level_index %d\n", i);
2394 				break;
2395 			}
2396 		}
2397 		if (copyout(&status, (void *)arg, sizeof (status))) {
2398 			res = EFAULT;
2399 		}
2400 		break;
2401 	}
2402 
2403 	case ACPI_DRV_IOC_SET_BRIGHTNESS: {
2404 		int level;
2405 
2406 		if (drv_priv(cr)) {
2407 			res = EPERM;
2408 			break;
2409 		}
2410 		if (copyin((void *)arg, &level, sizeof (level))) {
2411 			res = EFAULT;
2412 			break;
2413 		}
2414 		ACPI_DRV_DBG(CE_NOTE, NULL,
2415 		    "ACPI_DRV_IOC_SET_BRIGHTNESS level=%d\n", level);
2416 		if (acpi_drv_output_set_level(op, level) != ACPI_DRV_OK) {
2417 			res = EFAULT;
2418 		}
2419 		break;
2420 	}
2421 
2422 	default:
2423 		res = EINVAL;
2424 		break;
2425 	}
2426 	return (res);
2427 }
2428 
2429 static struct acpi_drv_output_state *
2430 acpi_drv_idx2output(int idx)
2431 {
2432 	struct acpi_drv_output_state *op = outputs;
2433 
2434 	while ((op != NULL) && (op->dev.index != idx)) {
2435 		op = op->next;
2436 	}
2437 	return (op);
2438 }
2439 
2440 /*
2441  * Output device status:
2442  *
2443  * Bits		Definition
2444  *
2445  * 0		Output connector exists in the system now.
2446  * 1		Output is activated.
2447  * 2		Output is ready to switch.
2448  * 3		Output is not defective.
2449  * 4		Device is attached (optional).
2450  * 5-31		Reserved (must be zero).
2451  */
2452 static int
2453 acpi_drv_output_get_state(struct acpi_drv_output_state *op)
2454 {
2455 	if (acpica_eval_int(op->dev.hdl, "_DCS", &op->state) != AE_OK) {
2456 		op->state = 0;
2457 		return (ACPI_DRV_ERR);
2458 	}
2459 	return (ACPI_DRV_OK);
2460 }
2461 
2462 /*
2463  * Get the current brightness level and index.
2464  */
2465 static int
2466 acpi_drv_output_get_level(struct acpi_drv_output_state *op)
2467 {
2468 	int i;
2469 
2470 	if (acpica_eval_int(op->dev.hdl, "_BQC", &op->cur_level) != AE_OK) {
2471 		op->cur_level = ACPI_DRV_NTF_UNKNOWN;
2472 		return (ACPI_DRV_ERR);
2473 	}
2474 	for (i = 0; i < op->num_levels; i++) {
2475 		if (op->levels[i] == op->cur_level) {
2476 			op->cur_level_index = i;
2477 			ACPI_DRV_DBG(CE_NOTE, NULL,
2478 			    "acpi_drv_output_get_level(): "
2479 			    "cur_level = %d, cur_level_index = %d\n",
2480 			    op->cur_level, i);
2481 			break;
2482 		}
2483 	}
2484 	return (ACPI_DRV_OK);
2485 }
2486 
2487 static int
2488 acpi_drv_output_set_level(struct acpi_drv_output_state *op, uint32_t level)
2489 {
2490 	if (acpi_drv_set_int(op->dev.hdl, "_BCM", op->levels[level]) !=
2491 	    AE_OK) {
2492 		return (ACPI_DRV_ERR);
2493 	}
2494 	op->cur_level = op->levels[level];
2495 	op->cur_level_index = level;
2496 	return (ACPI_DRV_OK);
2497 }
2498 
2499 static void
2500 acpi_drv_output_notify(ACPI_HANDLE hdl, UINT32 val, void *ctx)
2501 {
2502 	struct acpi_drv_dev *dev = ctx;
2503 	struct acpi_drv_output_state *op = dev->op;
2504 
2505 	ACPI_DRV_DBG(CE_NOTE, NULL, "acpi_drv_output_notify() val=0x%x\n", val);
2506 	mutex_enter(&acpi_drv_mutex);
2507 	ACPI_DRV_PRT_NOTIFY(hdl, val);
2508 	switch (val) {
2509 	case 0x86: /* increase brightness */
2510 		if (op->cur_level_index < op->num_levels - 1) {
2511 			if (acpi_drv_output_set_level(op,
2512 			    op->cur_level_index + 1) != AE_OK) {
2513 				break;
2514 			}
2515 		}
2516 		acpi_drv_gen_sysevent(&op->dev, ESC_PWRCTL_BRIGHTNESS_UP, 0);
2517 		break;
2518 	case 0x87: /* decrease brightness */
2519 		if (op->cur_level_index > 0) {
2520 			if (acpi_drv_output_set_level(op,
2521 			    op->cur_level_index - 1) != AE_OK) {
2522 				break;
2523 			}
2524 		}
2525 		acpi_drv_gen_sysevent(&op->dev, ESC_PWRCTL_BRIGHTNESS_DOWN, 0);
2526 		break;
2527 	default:
2528 		break;
2529 	}
2530 	mutex_exit(&acpi_drv_mutex);
2531 }
2532 
2533 /*
2534  * Set the display control modes of display switching and brightness
2535  * from BIOS or OSPM.
2536  */
2537 static void
2538 acpi_drv_display_set_mode(struct acpi_drv_display_state *dp, int state)
2539 {
2540 	if (acpi_drv_set_int(dp->dev.hdl, "_DOS", state) != AE_OK) {
2541 		ACPI_DRV_DBG(CE_WARN, NULL, "Cannot set display mode %d\n",
2542 		    state);
2543 	}
2544 }
2545