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