xref: /illumos-gate/usr/src/uts/common/io/power.c (revision 168c213023b7f347f11abfc72f448b0c621ab718)
1 
2 /*
3  * CDDL HEADER START
4  *
5  * The contents of this file are subject to the terms of the
6  * Common Development and Distribution License (the "License").
7  * You may not use this file except in compliance with the License.
8  *
9  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10  * or http://www.opensolaris.org/os/licensing.
11  * See the License for the specific language governing permissions
12  * and limitations under the License.
13  *
14  * When distributing Covered Code, include this CDDL HEADER in each
15  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16  * If applicable, add the following below this CDDL HEADER, with the
17  * fields enclosed by brackets "[]" replaced with your own identifying
18  * information: Portions Copyright [yyyy] [name of copyright owner]
19  *
20  * CDDL HEADER END
21  */
22 /*
23  * Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
24  * Use is subject to license terms.
25  */
26 
27 #pragma ident	"%Z%%M%	%I%	%E% SMI"
28 
29 /*
30  *	Power Button Driver
31  *
32  *	This driver handles interrupt generated by the power button on
33  *	platforms with "power" device node which has "button" property.
34  *	Currently, these platforms are:
35  *
36  *		ACPI-enabled x86/x64 platforms
37  *		Ultra-5_10, Ultra-80, Sun-Blade-100, Sun-Blade-150,
38  *		Sun-Blade-1500, Sun-Blade-2500,
39  *		Sun-Fire-V210, Sun-Fire-V240, Netra-240
40  *
41  *	Only one instance is allowed to attach.  In order to know when
42  *	an application that has opened the device is going away, a new
43  *	minor clone is created for each open(9E) request.  There are
44  *	allocations for creating minor clones between 1 and 255.  The ioctl
45  *	interface is defined by pbio(7I) and approved as part of
46  *	PSARC/1999/393 case.
47  */
48 
49 #include <sys/types.h>
50 #include <sys/conf.h>
51 #include <sys/ddi.h>
52 #include <sys/sunddi.h>
53 #include <sys/ddi_impldefs.h>
54 #include <sys/cmn_err.h>
55 #include <sys/errno.h>
56 #include <sys/modctl.h>
57 #include <sys/open.h>
58 #include <sys/stat.h>
59 #include <sys/poll.h>
60 #include <sys/pbio.h>
61 
62 #if defined(__sparc)
63 #include <sys/machsystm.h>
64 #endif
65 
66 #ifdef	ACPI_POWER_BUTTON
67 
68 #include <sys/acpi/acpi.h>
69 #include <sys/acpica.h>
70 
71 #else
72 
73 #include <sys/epic.h>
74 /*
75  * Some #defs that must be here as they differ for power.c
76  * and epic.c
77  */
78 #define	EPIC_REGS_OFFSET	0x00
79 #define	EPIC_REGS_LEN		0x82
80 
81 
82 /*
83  * This flag, which is set for platforms,  that have EPIC processor
84  * to process power button interrupt, helps in executing platform
85  * specific code.
86  */
87 static char 	hasEPIC = B_FALSE;
88 #endif	/* ACPI_POWER_BUTTON */
89 
90 /*
91  * Maximum number of clone minors that is allowed.  This value
92  * is defined relatively low to save memory.
93  */
94 #define	POWER_MAX_CLONE	256
95 
96 /*
97  * Minor number is instance << 8 + clone minor from range 1-255; clone 0
98  * is reserved for "original" minor.
99  */
100 #define	POWER_MINOR_TO_CLONE(minor) ((minor) & (POWER_MAX_CLONE - 1))
101 
102 /*
103  * Power Button Abort Delay
104  */
105 #define	ABORT_INCREMENT_DELAY	10
106 
107 /*
108  * FWARC 2005/687: power device compatible property
109  */
110 #define	POWER_DEVICE_TYPE "power-device-type"
111 
112 /*
113  * Driver global variables
114  */
115 static void *power_state;
116 static int power_inst = -1;
117 
118 static hrtime_t	power_button_debounce = NANOSEC/MILLISEC*10;
119 static hrtime_t power_button_abort_interval = 1.5 * NANOSEC;
120 static int	power_button_abort_presses = 3;
121 static int	power_button_abort_enable = 1;
122 static int	power_button_enable = 1;
123 
124 static int	power_button_pressed = 0;
125 static int	power_button_cancel = 0;
126 static int	power_button_timeouts = 0;
127 static int	timeout_cancel = 0;
128 static int	additional_presses = 0;
129 
130 /*
131  * Function prototypes
132  */
133 static int power_attach(dev_info_t *, ddi_attach_cmd_t);
134 static int power_detach(dev_info_t *, ddi_detach_cmd_t);
135 static int power_getinfo(dev_info_t *, ddi_info_cmd_t, void *, void **);
136 static int power_open(dev_t *, int, int, cred_t *);
137 static int power_close(dev_t, int, int, cred_t *);
138 static int power_ioctl(dev_t, int, intptr_t, int, cred_t *, int *);
139 static int power_chpoll(dev_t, short, int, short *, struct pollhead **);
140 #ifndef	ACPI_POWER_BUTTON
141 static uint_t power_high_intr(caddr_t);
142 #endif
143 static uint_t power_soft_intr(caddr_t);
144 static uint_t power_issue_shutdown(caddr_t);
145 static void power_timeout(caddr_t);
146 static void power_log_message(void);
147 
148 /*
149  * Structure used in the driver
150  */
151 struct power_soft_state {
152 	dev_info_t	*dip;		/* device info pointer */
153 	kmutex_t	power_mutex;	/* mutex lock */
154 	kmutex_t	power_intr_mutex; /* interrupt mutex lock */
155 	ddi_iblock_cookie_t soft_iblock_cookie; /* holds interrupt cookie */
156 	ddi_iblock_cookie_t high_iblock_cookie; /* holds interrupt cookie */
157 	ddi_softintr_t	softintr_id;	/* soft interrupt id */
158 	uchar_t		clones[POWER_MAX_CLONE]; /* array of minor clones */
159 	int		monitor_on;	/* clone monitoring the button event */
160 					/* clone 0 indicates no one is */
161 					/* monitoring the button event */
162 	pollhead_t	pollhd;		/* poll head struct */
163 	int		events;		/* bit map of occured events */
164 	int		shutdown_pending; /* system shutdown in progress */
165 #ifdef	ACPI_POWER_BUTTON
166 	boolean_t	fixed_attached;	/* true means fixed is attached */
167 	boolean_t	gpe_attached;	/* true means GPE is attached */
168 	ACPI_HANDLE	button_obj;	/* handle to device power button */
169 #else
170 	ddi_acc_handle_t power_rhandle; /* power button register handle */
171 	uint8_t		*power_btn_reg;	/* power button register address */
172 	uint8_t		power_btn_bit;	/* power button register bit */
173 	boolean_t	power_regs_mapped; /* flag to tell if regs mapped */
174 	boolean_t	power_btn_ioctl; /* flag to specify ioctl request */
175 #endif
176 };
177 
178 #ifdef	ACPI_POWER_BUTTON
179 static int power_attach_acpi(struct power_soft_state *softsp);
180 static void power_detach_acpi(struct power_soft_state *softsp);
181 static UINT32 power_acpi_fixed_event(void *ctx);
182 #else
183 static int power_setup_regs(struct power_soft_state *softsp);
184 static void power_free_regs(struct power_soft_state *softsp);
185 #endif	/* ACPI_POWER_BUTTON */
186 
187 /*
188  * Configuration data structures
189  */
190 static struct cb_ops power_cb_ops = {
191 	power_open,		/* open */
192 	power_close,		/* close */
193 	nodev,			/* strategy */
194 	nodev,			/* print */
195 	nodev,			/* dump */
196 	nodev,			/* read */
197 	nodev,			/* write */
198 	power_ioctl,		/* ioctl */
199 	nodev,			/* devmap */
200 	nodev,			/* mmap */
201 	nodev,			/* segmap */
202 	power_chpoll,		/* poll */
203 	ddi_prop_op,		/* cb_prop_op */
204 	NULL,			/* streamtab */
205 	D_MP | D_NEW,		/* Driver compatibility flag */
206 	CB_REV,			/* rev */
207 	nodev,			/* cb_aread */
208 	nodev			/* cb_awrite */
209 };
210 
211 static struct dev_ops power_ops = {
212 	DEVO_REV,		/* devo_rev, */
213 	0,			/* refcnt */
214 	power_getinfo,		/* getinfo */
215 	nulldev,		/* identify */
216 	nulldev,		/* probe */
217 	power_attach,		/* attach */
218 	power_detach,		/* detach */
219 	nodev,			/* reset */
220 	&power_cb_ops,		/* cb_ops */
221 	(struct bus_ops *)NULL,	/* bus_ops */
222 	NULL			/* power */
223 };
224 
225 static struct modldrv modldrv = {
226 	&mod_driverops,		/* Type of module.  This one is a driver */
227 	"power button driver v%I%",	/* name of module */
228 	&power_ops,		/* driver ops */
229 };
230 
231 static struct modlinkage modlinkage = {
232 	MODREV_1,
233 	(void *)&modldrv,
234 	NULL
235 };
236 
237 /*
238  * These are the module initialization routines.
239  */
240 
241 int
242 _init(void)
243 {
244 	int error;
245 
246 	if ((error = ddi_soft_state_init(&power_state,
247 	    sizeof (struct power_soft_state), 0)) != 0)
248 		return (error);
249 
250 	if ((error = mod_install(&modlinkage)) != 0)
251 		ddi_soft_state_fini(&power_state);
252 
253 	return (error);
254 }
255 
256 int
257 _fini(void)
258 {
259 	int error;
260 
261 	if ((error = mod_remove(&modlinkage)) == 0)
262 		ddi_soft_state_fini(&power_state);
263 
264 	return (error);
265 }
266 
267 int
268 _info(struct modinfo *modinfop)
269 {
270 	return (mod_info(&modlinkage, modinfop));
271 }
272 
273 /*ARGSUSED*/
274 static int
275 power_getinfo(dev_info_t *dip, ddi_info_cmd_t infocmd, void *arg,
276     void **result)
277 {
278 	struct power_soft_state *softsp;
279 
280 	if (power_inst == -1)
281 		return (DDI_FAILURE);
282 
283 	switch (infocmd) {
284 	case DDI_INFO_DEVT2DEVINFO:
285 		if ((softsp = ddi_get_soft_state(power_state, power_inst))
286 		    == NULL)
287 			return (DDI_FAILURE);
288 		*result = (void *)softsp->dip;
289 		return (DDI_SUCCESS);
290 
291 	case DDI_INFO_DEVT2INSTANCE:
292 		*result = (void *)(uintptr_t)power_inst;
293 		return (DDI_SUCCESS);
294 
295 	default:
296 		return (DDI_FAILURE);
297 	}
298 }
299 
300 static int
301 power_attach(dev_info_t *dip, ddi_attach_cmd_t cmd)
302 {
303 	struct power_soft_state *softsp;
304 
305 	switch (cmd) {
306 	case DDI_ATTACH:
307 		break;
308 	case DDI_RESUME:
309 		return (DDI_SUCCESS);
310 	default:
311 		return (DDI_FAILURE);
312 	}
313 
314 	/*
315 	 * If the power node doesn't have "button" property, quietly
316 	 * fail to attach.
317 	 */
318 	if (ddi_prop_exists(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS,
319 	    "button") == 0)
320 		return (DDI_FAILURE);
321 
322 	if (power_inst != -1)
323 		return (DDI_FAILURE);
324 
325 	power_inst = ddi_get_instance(dip);
326 
327 	if (ddi_soft_state_zalloc(power_state, power_inst) != DDI_SUCCESS)
328 		return (DDI_FAILURE);
329 
330 	if (ddi_create_minor_node(dip, "power_button", S_IFCHR,
331 	    (power_inst << 8) + 0, "ddi_power_button", 0) != DDI_SUCCESS)
332 		return (DDI_FAILURE);
333 
334 	softsp = ddi_get_soft_state(power_state, power_inst);
335 	softsp->dip = dip;
336 
337 #ifdef	ACPI_POWER_BUTTON
338 	(void) power_attach_acpi(softsp);
339 #else
340 	if (power_setup_regs(softsp) != DDI_SUCCESS) {
341 		cmn_err(CE_WARN, "power_attach: failed to setup registers");
342 		goto error;
343 	}
344 
345 	if (ddi_get_iblock_cookie(dip, 0,
346 	    &softsp->high_iblock_cookie) != DDI_SUCCESS) {
347 		cmn_err(CE_WARN, "power_attach: ddi_get_soft_iblock_cookie "
348 		    "failed.");
349 		goto error;
350 	}
351 	mutex_init(&softsp->power_intr_mutex, NULL, MUTEX_DRIVER,
352 	    softsp->high_iblock_cookie);
353 
354 	if (ddi_add_intr(dip, 0, &softsp->high_iblock_cookie, NULL,
355 	    power_high_intr, (caddr_t)softsp) != DDI_SUCCESS) {
356 		cmn_err(CE_WARN, "power_attach: failed to add high-level "
357 		    " interrupt handler.");
358 		mutex_destroy(&softsp->power_intr_mutex);
359 		goto error;
360 	}
361 #endif	/* ACPI_POWER_BUTTON */
362 
363 	if (ddi_get_soft_iblock_cookie(dip, DDI_SOFTINT_LOW,
364 	    &softsp->soft_iblock_cookie) != DDI_SUCCESS) {
365 		cmn_err(CE_WARN, "power_attach: ddi_get_soft_iblock_cookie "
366 		    "failed.");
367 		mutex_destroy(&softsp->power_intr_mutex);
368 		ddi_remove_intr(dip, 0, NULL);
369 		goto error;
370 	}
371 
372 	mutex_init(&softsp->power_mutex, NULL, MUTEX_DRIVER,
373 	    (void *)softsp->soft_iblock_cookie);
374 
375 	if (ddi_add_softintr(dip, DDI_SOFTINT_LOW, &softsp->softintr_id,
376 	    NULL, NULL, power_soft_intr, (caddr_t)softsp) != DDI_SUCCESS) {
377 		cmn_err(CE_WARN, "power_attach: failed to add soft "
378 		    "interrupt handler.");
379 		mutex_destroy(&softsp->power_mutex);
380 		mutex_destroy(&softsp->power_intr_mutex);
381 		ddi_remove_intr(dip, 0, NULL);
382 		goto error;
383 	}
384 
385 	ddi_report_dev(dip);
386 
387 	return (DDI_SUCCESS);
388 
389 error:
390 #ifdef	ACPI_POWER_BUTTON
391 	/*
392 	 * detach ACPI power button
393 	 */
394 	power_detach_acpi(softsp);
395 #else
396 	power_free_regs(softsp);
397 #endif	/* ACPI_POWER_BUTTON */
398 	ddi_remove_minor_node(dip, "power_button");
399 	ddi_soft_state_free(power_state, power_inst);
400 	return (DDI_FAILURE);
401 }
402 
403 /*ARGSUSED*/
404 /*
405  * This driver doesn't detach.
406  */
407 static int
408 power_detach(dev_info_t *dip, ddi_detach_cmd_t cmd)
409 {
410 	/*
411 	 * Since the "power" node has "reg" property, as part of
412 	 * the suspend operation, detach(9E) entry point is called.
413 	 * There is no state to save, since this register is used
414 	 * by OBP to power off the system and the state of the
415 	 * power off is preserved by hardware.
416 	 */
417 	return ((cmd == DDI_SUSPEND) ? DDI_SUCCESS :
418 	    DDI_FAILURE);
419 }
420 
421 
422 #ifndef	ACPI_POWER_BUTTON
423 /*
424  * Handler for the high-level interrupt.
425  */
426 static uint_t
427 power_high_intr(caddr_t arg)
428 {
429 	struct power_soft_state *softsp = (struct power_soft_state *)arg;
430 	ddi_acc_handle_t hdl = softsp->power_rhandle;
431 	uint8_t		reg;
432 
433 	hrtime_t tstamp;
434 	static hrtime_t o_tstamp = 0;
435 	static hrtime_t power_button_tstamp = 0;
436 	static int power_button_cnt;
437 
438 	if (softsp->power_regs_mapped) {
439 		mutex_enter(&softsp->power_intr_mutex);
440 
441 		/* Check if power button interrupt is delivered by EPIC HW */
442 		if (hasEPIC) {
443 			/* read isr - first issue command */
444 			EPIC_WR(hdl, softsp->power_btn_reg,
445 				EPIC_ATOM_INTR_READ);
446 			/* next, read the reg */
447 			EPIC_RD(hdl, softsp->power_btn_reg, reg);
448 
449 			if (reg & EPIC_FIRE_INTERRUPT) {  /* PB pressed */
450 				/* clear the interrupt */
451 				EPIC_WR(hdl, softsp->power_btn_reg,
452 					EPIC_ATOM_INTR_CLEAR);
453 			} else {
454 				if (!softsp->power_btn_ioctl) {
455 					mutex_exit(&softsp->power_intr_mutex);
456 					return (DDI_INTR_CLAIMED);
457 				}
458 				softsp->power_btn_ioctl = B_FALSE;
459 			}
460 		} else {
461 			reg = ddi_get8(hdl, softsp->power_btn_reg);
462 			if (reg & softsp->power_btn_bit) {
463 				reg &= softsp->power_btn_bit;
464 				ddi_put8(hdl, softsp->power_btn_reg, reg);
465 				(void) ddi_get8(hdl, softsp->power_btn_reg);
466 			} else {
467 				if (!softsp->power_btn_ioctl) {
468 					mutex_exit(&softsp->power_intr_mutex);
469 					return (DDI_INTR_CLAIMED);
470 				}
471 				softsp->power_btn_ioctl = B_FALSE;
472 			}
473 		}
474 		mutex_exit(&softsp->power_intr_mutex);
475 	}
476 
477 	tstamp = gethrtime();
478 
479 	/* need to deal with power button debounce */
480 	if (o_tstamp && (tstamp - o_tstamp) < power_button_debounce) {
481 		o_tstamp = tstamp;
482 		return (DDI_INTR_CLAIMED);
483 	}
484 	o_tstamp = tstamp;
485 
486 	power_button_cnt++;
487 
488 	mutex_enter(&softsp->power_intr_mutex);
489 	power_button_pressed++;
490 	mutex_exit(&softsp->power_intr_mutex);
491 
492 	/*
493 	 * If power button abort is enabled and power button was pressed
494 	 * power_button_abort_presses times within power_button_abort_interval
495 	 * then call abort_sequence_enter();
496 	 */
497 	if (power_button_abort_enable) {
498 		if (power_button_abort_presses == 1 ||
499 		    tstamp < (power_button_tstamp +
500 		    power_button_abort_interval)) {
501 			if (power_button_cnt == power_button_abort_presses) {
502 				mutex_enter(&softsp->power_intr_mutex);
503 				power_button_cancel += power_button_timeouts;
504 				power_button_pressed = 0;
505 				mutex_exit(&softsp->power_intr_mutex);
506 				power_button_cnt = 0;
507 				abort_sequence_enter("Power Button Abort");
508 				return (DDI_INTR_CLAIMED);
509 			}
510 		} else {
511 			power_button_cnt = 1;
512 			power_button_tstamp = tstamp;
513 		}
514 	}
515 
516 	if (!power_button_enable)
517 		return (DDI_INTR_CLAIMED);
518 
519 	/* post softint to issue timeout for power button action */
520 	if (softsp->softintr_id != NULL)
521 		ddi_trigger_softintr(softsp->softintr_id);
522 
523 	return (DDI_INTR_CLAIMED);
524 }
525 #endif	/* ifndef ACPI_POWER_BUTTON */
526 
527 /*
528  * Handle the softints....
529  *
530  * If only one softint is posted for several button presses, record
531  * the number of additional presses just incase this was actually not quite
532  * an Abort sequence so that we can log this event later.
533  *
534  * Issue a timeout with a duration being a fraction larger than
535  * the specified Abort interval inorder to perform a power down if required.
536  */
537 static uint_t
538 power_soft_intr(caddr_t arg)
539 {
540 	struct power_soft_state *softsp = (struct power_soft_state *)arg;
541 
542 	if (!power_button_abort_enable)
543 		return (power_issue_shutdown(arg));
544 
545 	mutex_enter(&softsp->power_intr_mutex);
546 	if (!power_button_pressed) {
547 		mutex_exit(&softsp->power_intr_mutex);
548 		return (DDI_INTR_CLAIMED);
549 	}
550 
551 	/*
552 	 * Schedule a timeout to do the necessary
553 	 * work for shutdown, only one timeout for
554 	 * n presses if power button was pressed
555 	 * more than once before softint fired
556 	 */
557 	if (power_button_pressed > 1)
558 		additional_presses += power_button_pressed - 1;
559 
560 	timeout_cancel = 0;
561 	power_button_pressed = 0;
562 	power_button_timeouts++;
563 	mutex_exit(&softsp->power_intr_mutex);
564 	(void) timeout((void(*)(void *))power_timeout,
565 	    softsp, NSEC_TO_TICK(power_button_abort_interval) +
566 	    ABORT_INCREMENT_DELAY);
567 
568 	return (DDI_INTR_CLAIMED);
569 }
570 
571 /*
572  * Upon receiving a timeout the following is determined:
573  *
574  * If an  Abort sequence was issued, then we cancel all outstanding timeouts
575  * and additional presses prior to the Abort sequence.
576  *
577  * If we had multiple timeouts issued and the abort sequence was not met,
578  * then we had more than one button press to power down the machine. We
579  * were probably trying to issue an abort. So log a message indicating this
580  * and cancel all outstanding timeouts.
581  *
582  * If we had just one timeout and the abort sequence was not met then
583  * we really did want to power down the machine, so call power_issue_shutdown()
584  * to do the work and schedule a power down
585  */
586 static void
587 power_timeout(caddr_t arg)
588 {
589 	struct power_soft_state *softsp = (struct power_soft_state *)arg;
590 	static int first = 0;
591 
592 	/*
593 	 * Abort was generated cancel all outstanding power
594 	 * button timeouts
595 	 */
596 	mutex_enter(&softsp->power_intr_mutex);
597 	if (power_button_cancel) {
598 		power_button_cancel--;
599 		power_button_timeouts--;
600 		if (!first) {
601 			first++;
602 			additional_presses = 0;
603 		}
604 		mutex_exit(&softsp->power_intr_mutex);
605 		return;
606 	}
607 	first = 0;
608 
609 	/*
610 	 * We get here if the timeout(s) have fired and they were
611 	 * not issued prior to an abort.
612 	 *
613 	 * If we had more than one press in the interval we were
614 	 * probably trying to issue an abort, but didnt press the
615 	 * required number within the interval. Hence cancel all
616 	 * timeouts and do not continue towards shutdown.
617 	 */
618 	if (!timeout_cancel) {
619 		timeout_cancel = power_button_timeouts +
620 		    additional_presses;
621 
622 		power_button_timeouts--;
623 		if (!power_button_timeouts)
624 			additional_presses = 0;
625 
626 		if (timeout_cancel > 1) {
627 			mutex_exit(&softsp->power_intr_mutex);
628 			cmn_err(CE_NOTE, "Power Button pressed "
629 			    "%d times, cancelling all requests",
630 			    timeout_cancel);
631 			return;
632 		}
633 		mutex_exit(&softsp->power_intr_mutex);
634 
635 		/* Go and do the work to request shutdown */
636 		(void) power_issue_shutdown((caddr_t)softsp);
637 		return;
638 	}
639 
640 	power_button_timeouts--;
641 	if (!power_button_timeouts)
642 		additional_presses = 0;
643 	mutex_exit(&softsp->power_intr_mutex);
644 }
645 
646 #ifdef ACPI_POWER_BUTTON
647 static void
648 do_shutdown(void)
649 {
650 	proc_t *initpp;
651 
652 	/*
653 	 * If we're still booting and init(1) isn't set up yet, simply halt.
654 	 */
655 	mutex_enter(&pidlock);
656 	initpp = prfind(P_INITPID);
657 	mutex_exit(&pidlock);
658 	if (initpp == NULL) {
659 		extern void halt(char *);
660 		halt("Power off the System");   /* just in case */
661 	}
662 
663 	/*
664 	 * else, graceful shutdown with inittab and all getting involved
665 	 */
666 	psignal(initpp, SIGPWR);
667 }
668 #endif
669 
670 static uint_t
671 power_issue_shutdown(caddr_t arg)
672 {
673 	struct power_soft_state *softsp = (struct power_soft_state *)arg;
674 
675 	mutex_enter(&softsp->power_mutex);
676 	softsp->events |= PB_BUTTON_PRESS;
677 	if (softsp->monitor_on != 0) {
678 		mutex_exit(&softsp->power_mutex);
679 		pollwakeup(&softsp->pollhd, POLLRDNORM);
680 		pollwakeup(&softsp->pollhd, POLLIN);
681 		return (DDI_INTR_CLAIMED);
682 	}
683 
684 	if (!softsp->shutdown_pending) {
685 		cmn_err(CE_WARN, "Power off requested from power button or "
686 		    "SC, powering down the system!");
687 		softsp->shutdown_pending = 1;
688 		do_shutdown();
689 
690 		/*
691 		 * Wait a while for "do_shutdown()" to shut down the system
692 		 * before logging an error message.
693 		 */
694 		(void) timeout((void(*)(void *))power_log_message, NULL,
695 		    100 * hz);
696 	}
697 	mutex_exit(&softsp->power_mutex);
698 
699 	return (DDI_INTR_CLAIMED);
700 }
701 
702 /*
703  * Open the device.
704  */
705 /*ARGSUSED*/
706 static int
707 power_open(dev_t *devp, int openflags, int otyp, cred_t *credp)
708 {
709 	struct power_soft_state *softsp;
710 	int clone;
711 
712 	if (otyp != OTYP_CHR)
713 		return (EINVAL);
714 
715 	if ((softsp = ddi_get_soft_state(power_state, power_inst)) ==
716 	    NULL)
717 		return (ENXIO);
718 
719 	mutex_enter(&softsp->power_mutex);
720 	for (clone = 1; clone < POWER_MAX_CLONE; clone++)
721 		if (!softsp->clones[clone])
722 			break;
723 
724 	if (clone == POWER_MAX_CLONE) {
725 		cmn_err(CE_WARN, "power_open: No more allocation left "
726 		    "to create a clone minor.");
727 		mutex_exit(&softsp->power_mutex);
728 		return (ENXIO);
729 	}
730 
731 	*devp = makedevice(getmajor(*devp), (power_inst << 8) + clone);
732 	softsp->clones[clone] = 1;
733 	mutex_exit(&softsp->power_mutex);
734 
735 	return (0);
736 }
737 
738 /*
739  * Close the device.
740  */
741 /*ARGSUSED*/
742 static  int
743 power_close(dev_t dev, int openflags, int otyp, cred_t *credp)
744 {
745 	struct power_soft_state *softsp;
746 	int clone;
747 
748 	if (otyp != OTYP_CHR)
749 		return (EINVAL);
750 
751 	if ((softsp = ddi_get_soft_state(power_state, power_inst)) ==
752 	    NULL)
753 		return (ENXIO);
754 
755 	clone = POWER_MINOR_TO_CLONE(getminor(dev));
756 	mutex_enter(&softsp->power_mutex);
757 	if (softsp->monitor_on == clone)
758 		softsp->monitor_on = 0;
759 	softsp->clones[clone] = 0;
760 	mutex_exit(&softsp->power_mutex);
761 
762 	return (0);
763 }
764 
765 /*ARGSUSED*/
766 static  int
767 power_ioctl(dev_t dev, int cmd, intptr_t arg, int mode, cred_t *cred_p,
768     int *rval_p)
769 {
770 	struct power_soft_state *softsp;
771 	int clone;
772 
773 	if ((softsp = ddi_get_soft_state(power_state, power_inst)) ==
774 	    NULL)
775 		return (ENXIO);
776 
777 	clone = POWER_MINOR_TO_CLONE(getminor(dev));
778 	switch (cmd) {
779 	case PB_BEGIN_MONITOR:
780 		mutex_enter(&softsp->power_mutex);
781 		if (softsp->monitor_on) {
782 			mutex_exit(&softsp->power_mutex);
783 			return (EBUSY);
784 		}
785 		softsp->monitor_on = clone;
786 		mutex_exit(&softsp->power_mutex);
787 		return (0);
788 
789 	case PB_END_MONITOR:
790 		mutex_enter(&softsp->power_mutex);
791 
792 		/*
793 		 * If PB_END_MONITOR is called without first
794 		 * calling PB_BEGIN_MONITOR, an error will be
795 		 * returned.
796 		 */
797 		if (!softsp->monitor_on) {
798 			mutex_exit(&softsp->power_mutex);
799 			return (ENXIO);
800 		}
801 
802 		/*
803 		 * This clone is not monitoring the button.
804 		 */
805 		if (softsp->monitor_on != clone) {
806 			mutex_exit(&softsp->power_mutex);
807 			return (EINVAL);
808 		}
809 		softsp->monitor_on = 0;
810 		mutex_exit(&softsp->power_mutex);
811 		return (0);
812 
813 	case PB_GET_EVENTS:
814 		mutex_enter(&softsp->power_mutex);
815 		if (ddi_copyout((void *)&softsp->events, (void *)arg,
816 		    sizeof (int), mode) != 0) {
817 			mutex_exit(&softsp->power_mutex);
818 			return (EFAULT);
819 		}
820 
821 		/*
822 		 * This ioctl returned the events detected since last
823 		 * call.  Note that any application can get the events
824 		 * and clear the event register.
825 		 */
826 		softsp->events = 0;
827 		mutex_exit(&softsp->power_mutex);
828 		return (0);
829 
830 	/*
831 	 * This ioctl is used by the test suite.
832 	 */
833 	case PB_CREATE_BUTTON_EVENT:
834 #ifdef	ACPI_POWER_BUTTON
835 		(UINT32)power_acpi_fixed_event((void *)softsp);
836 #else
837 		if (softsp->power_regs_mapped) {
838 			mutex_enter(&softsp->power_intr_mutex);
839 			softsp->power_btn_ioctl = B_TRUE;
840 			mutex_exit(&softsp->power_intr_mutex);
841 		}
842 		(void) power_high_intr((caddr_t)softsp);
843 #endif	/* ACPI_POWER_BUTTON */
844 		return (0);
845 
846 	default:
847 		return (ENOTTY);
848 	}
849 }
850 
851 /*ARGSUSED*/
852 static int
853 power_chpoll(dev_t dev, short events, int anyyet,
854     short *reventsp, struct pollhead **phpp)
855 {
856 	struct power_soft_state *softsp;
857 
858 	if ((softsp = ddi_get_soft_state(power_state, power_inst)) == NULL)
859 		return (ENXIO);
860 
861 	mutex_enter(&softsp->power_mutex);
862 	*reventsp = 0;
863 	if (softsp->events)
864 		*reventsp = POLLRDNORM|POLLIN;
865 	else {
866 		if (!anyyet)
867 			*phpp = &softsp->pollhd;
868 	}
869 	mutex_exit(&softsp->power_mutex);
870 
871 	return (0);
872 }
873 
874 static void
875 power_log_message(void)
876 {
877 	struct power_soft_state *softsp;
878 
879 	if ((softsp = ddi_get_soft_state(power_state, power_inst)) == NULL) {
880 		cmn_err(CE_WARN, "Failed to get internal state!");
881 		return;
882 	}
883 
884 	mutex_enter(&softsp->power_mutex);
885 	softsp->shutdown_pending = 0;
886 	cmn_err(CE_WARN, "Failed to shut down the system!");
887 	mutex_exit(&softsp->power_mutex);
888 }
889 
890 #ifdef	ACPI_POWER_BUTTON
891 /*
892  * Given a handle to a device object, locate a _PRW object
893  * if present and fetch the GPE info for this device object
894  */
895 static ACPI_STATUS
896 power_get_prw_gpe(ACPI_HANDLE dev, ACPI_HANDLE *gpe_dev, UINT32 *gpe_num)
897 {
898 	ACPI_BUFFER buf;
899 	ACPI_STATUS status;
900 	ACPI_HANDLE prw;
901 	ACPI_OBJECT *gpe;
902 
903 	/*
904 	 * Evaluate _PRW if present
905 	 */
906 	status = AcpiGetHandle(dev, "_PRW", &prw);
907 	if (status != AE_OK)
908 		return (status);
909 	buf.Length = ACPI_ALLOCATE_BUFFER;
910 	status = AcpiEvaluateObjectTyped(prw, NULL, NULL, &buf,
911 	    ACPI_TYPE_PACKAGE);
912 	if (status != AE_OK)
913 		return (status);
914 
915 	/*
916 	 * Sanity-check the package; need at least two elements
917 	 */
918 	status = AE_ERROR;
919 	if (((ACPI_OBJECT *)buf.Pointer)->Package.Count < 2)
920 		goto done;
921 
922 	gpe = &((ACPI_OBJECT *)buf.Pointer)->Package.Elements[0];
923 	if (gpe->Type == ACPI_TYPE_INTEGER) {
924 		*gpe_dev = NULL;
925 		*gpe_num = gpe->Integer.Value;
926 		status = AE_OK;
927 	} else if (gpe->Type == ACPI_TYPE_PACKAGE) {
928 		if ((gpe->Package.Count != 2) ||
929 		    (gpe->Package.Elements[0].Type != ACPI_TYPE_DEVICE) ||
930 		    (gpe->Package.Elements[1].Type != ACPI_TYPE_INTEGER))
931 			goto done;
932 		*gpe_dev = gpe->Package.Elements[0].Reference.Handle;
933 		*gpe_num = gpe->Package.Elements[1].Integer.Value;
934 		status = AE_OK;
935 	}
936 
937 done:
938 	AcpiOsFree(buf.Pointer);
939 	return (status);
940 }
941 
942 
943 /*
944  *
945  */
946 /*ARGSUSED*/
947 static ACPI_STATUS
948 acpi_device(ACPI_HANDLE obj, UINT32 nesting, void *context, void **rv)
949 {
950 
951 	*((ACPI_HANDLE *)context) = obj;
952 	return (AE_OK);
953 }
954 
955 /*
956  *
957  */
958 static ACPI_HANDLE
959 probe_acpi_pwrbutton()
960 {
961 	ACPI_HANDLE obj = NULL;
962 
963 	(void) AcpiGetDevices("PNP0C0C", acpi_device, (void *)&obj, NULL);
964 	return (obj);
965 }
966 
967 static UINT32
968 power_acpi_fixed_event(void *ctx)
969 {
970 
971 	mutex_enter(&((struct power_soft_state *)ctx)->power_intr_mutex);
972 	power_button_pressed++;
973 	mutex_exit(&((struct power_soft_state *)ctx)->power_intr_mutex);
974 
975 	/* post softint to issue timeout for power button action */
976 	if (((struct power_soft_state *)ctx)->softintr_id != NULL)
977 		ddi_trigger_softintr(
978 		    ((struct power_soft_state *)ctx)->softintr_id);
979 
980 	return (AE_OK);
981 }
982 
983 /*ARGSUSED*/
984 static void
985 power_acpi_notify_event(ACPI_HANDLE obj, UINT32 val, void *ctx)
986 {
987 	if (val == 0x80)
988 		(void) power_acpi_fixed_event(ctx);
989 }
990 
991 /*
992  *
993  */
994 static int
995 power_probe_method_button(struct power_soft_state *softsp)
996 {
997 	ACPI_HANDLE button_obj;
998 	UINT32 gpe_num;
999 	ACPI_HANDLE gpe_dev;
1000 
1001 	button_obj = probe_acpi_pwrbutton();
1002 	softsp->button_obj = button_obj;	/* remember obj */
1003 	if ((button_obj != NULL) &&
1004 	    (power_get_prw_gpe(button_obj, &gpe_dev, &gpe_num) == AE_OK) &&
1005 	    (AcpiSetGpeType(gpe_dev, gpe_num, ACPI_GPE_TYPE_WAKE_RUN) ==
1006 	    AE_OK) &&
1007 	    (AcpiEnableGpe(gpe_dev, gpe_num, ACPI_NOT_ISR) == AE_OK) &&
1008 	    (AcpiInstallNotifyHandler(button_obj, ACPI_DEVICE_NOTIFY,
1009 	    power_acpi_notify_event, (void*)softsp) == AE_OK))
1010 		return (1);
1011 	return (0);
1012 }
1013 
1014 /*
1015  *
1016  */
1017 static int
1018 power_probe_fixed_button(struct power_soft_state *softsp)
1019 {
1020 	FADT_DESCRIPTOR *fadt;
1021 
1022 	if (AcpiGetFirmwareTable(FADT_SIG, 1, ACPI_LOGICAL_ADDRESSING,
1023 	    (ACPI_TABLE_HEADER **) &fadt) != AE_OK)
1024 		return (0);
1025 
1026 	if (!fadt->PwrButton) {
1027 		if (AcpiInstallFixedEventHandler(ACPI_EVENT_POWER_BUTTON,
1028 		    power_acpi_fixed_event, (void *)softsp) == AE_OK)
1029 			return (1);
1030 	}
1031 	return (0);
1032 }
1033 
1034 
1035 /*
1036  *
1037  */
1038 static int
1039 power_attach_acpi(struct power_soft_state *softsp)
1040 {
1041 
1042 	/*
1043 	 * If we've attached anything already, return an error
1044 	 */
1045 	if ((softsp->gpe_attached) || (softsp->fixed_attached))
1046 		return (DDI_FAILURE);
1047 
1048 	/*
1049 	 * attempt to attach both a fixed-event handler and a GPE
1050 	 * handler; remember what we got
1051 	 */
1052 	softsp->fixed_attached = (power_probe_fixed_button(softsp) != 0);
1053 	softsp->gpe_attached = (power_probe_method_button(softsp) != 0);
1054 
1055 	/*
1056 	 * If we've attached anything now, return success
1057 	 */
1058 	if ((softsp->gpe_attached) || (softsp->fixed_attached))
1059 		return (DDI_SUCCESS);
1060 
1061 	return (DDI_FAILURE);
1062 }
1063 
1064 /*
1065  *
1066  */
1067 static void
1068 power_detach_acpi(struct power_soft_state *softsp)
1069 {
1070 	if (softsp->gpe_attached) {
1071 		if (AcpiRemoveNotifyHandler(softsp->button_obj,
1072 		    ACPI_DEVICE_NOTIFY, power_acpi_notify_event) != AE_OK)
1073 			cmn_err(CE_WARN, "!power: failed to remove Notify"
1074 			    " handler");
1075 	}
1076 
1077 	if (softsp->fixed_attached) {
1078 		if (AcpiRemoveFixedEventHandler(ACPI_EVENT_POWER_BUTTON,
1079 		    power_acpi_fixed_event) != AE_OK)
1080 			cmn_err(CE_WARN, "!power: failed to remove Power"
1081 			    " Button handler");
1082 	}
1083 }
1084 
1085 #else
1086 /*
1087  * Code for platforms that have EPIC processor for processing power
1088  * button interrupts.
1089  */
1090 static int
1091 power_setup_epic_regs(dev_info_t *dip, struct power_soft_state *softsp)
1092 {
1093 	ddi_device_acc_attr_t	attr;
1094 	uint8_t *reg_base;
1095 
1096 	attr.devacc_attr_version = DDI_DEVICE_ATTR_V0;
1097 	attr.devacc_attr_endian_flags = DDI_STRUCTURE_LE_ACC;
1098 	attr.devacc_attr_dataorder = DDI_STRICTORDER_ACC;
1099 	if (ddi_regs_map_setup(dip, 0, (caddr_t *)&reg_base,
1100 		EPIC_REGS_OFFSET, EPIC_REGS_LEN, &attr,
1101 		&softsp->power_rhandle) != DDI_SUCCESS) {
1102 		return (DDI_FAILURE);
1103 	}
1104 
1105 	softsp->power_btn_reg = reg_base;
1106 	softsp->power_regs_mapped = B_TRUE;
1107 
1108 	/* Clear power button interrupt first */
1109 	EPIC_WR(softsp->power_rhandle, softsp->power_btn_reg,
1110 		EPIC_ATOM_INTR_CLEAR);
1111 
1112 	/* Enable EPIC interrupt for power button single press event */
1113 	EPIC_WR(softsp->power_rhandle, softsp->power_btn_reg,
1114 		EPIC_ATOM_INTR_ENABLE);
1115 
1116 	/*
1117 	 * At this point, EPIC interrupt processing is fully initialised.
1118 	 */
1119 	hasEPIC = B_TRUE;
1120 	return (DDI_SUCCESS);
1121 }
1122 
1123 /*
1124  *
1125  * power button register definitions for acpi register on m1535d
1126  */
1127 #define	M1535D_PWR_BTN_REG_01		0x1
1128 #define	M1535D_PWR_BTN_EVENT_FLAG	0x1
1129 
1130 static int
1131 power_setup_m1535_regs(dev_info_t *dip, struct power_soft_state *softsp)
1132 {
1133 	ddi_device_acc_attr_t	attr;
1134 	uint8_t *reg_base;
1135 
1136 	attr.devacc_attr_version = DDI_DEVICE_ATTR_V0;
1137 	attr.devacc_attr_endian_flags = DDI_STRUCTURE_LE_ACC;
1138 	attr.devacc_attr_dataorder = DDI_STRICTORDER_ACC;
1139 	if (ddi_regs_map_setup(dip, 0, (caddr_t *)&reg_base, 0, 0, &attr,
1140 	    &softsp->power_rhandle) != DDI_SUCCESS) {
1141 		return (DDI_FAILURE);
1142 	}
1143 	softsp->power_btn_reg = &reg_base[M1535D_PWR_BTN_REG_01];
1144 	softsp->power_btn_bit = M1535D_PWR_BTN_EVENT_FLAG;
1145 	softsp->power_regs_mapped = B_TRUE;
1146 	return (DDI_SUCCESS);
1147 }
1148 
1149 /*
1150  * MBC Fire/SSI Interrupt Status Register definitions
1151  */
1152 #define	FIRE_SSI_ISR			0x0
1153 #define	FIRE_SSI_INTR_ENA		0x8
1154 #define	FIRE_SSI_SHUTDOWN_REQ		0x4
1155 
1156 static int
1157 power_setup_mbc_regs(dev_info_t *dip, struct power_soft_state *softsp)
1158 {
1159 	ddi_device_acc_attr_t   attr;
1160 	uint8_t *reg_base;
1161 	ddi_acc_handle_t hdl;
1162 	uint8_t reg;
1163 
1164 	attr.devacc_attr_version = DDI_DEVICE_ATTR_V0;
1165 	attr.devacc_attr_endian_flags = DDI_STRUCTURE_LE_ACC;
1166 	attr.devacc_attr_dataorder = DDI_STRICTORDER_ACC;
1167 	if (ddi_regs_map_setup(dip, 0, (caddr_t *)&reg_base, 0, 0, &attr,
1168 		&softsp->power_rhandle) != DDI_SUCCESS) {
1169 		return (DDI_FAILURE);
1170 	}
1171 	softsp->power_btn_reg = &reg_base[FIRE_SSI_ISR];
1172 	softsp->power_btn_bit = FIRE_SSI_SHUTDOWN_REQ;
1173 	hdl = softsp->power_rhandle;
1174 	/*
1175 	 * Clear MBC Fire Power Button interrupt, if set.
1176 	 */
1177 	reg = ddi_get8(hdl, softsp->power_btn_reg);
1178 	if (reg & softsp->power_btn_bit) {
1179 		reg &= softsp->power_btn_bit;
1180 		ddi_put8(hdl, softsp->power_btn_reg, reg);
1181 		(void) ddi_get8(hdl, softsp->power_btn_reg);
1182 	}
1183 	/*
1184 	 * Enable MBC Fire Power Button interrupt.
1185 	 */
1186 	reg = ddi_get8(hdl, &reg_base[FIRE_SSI_INTR_ENA]);
1187 	reg |= FIRE_SSI_SHUTDOWN_REQ;
1188 	ddi_put8(hdl, &reg_base[FIRE_SSI_INTR_ENA], reg);
1189 
1190 	softsp->power_regs_mapped = B_TRUE;
1191 
1192 	return (DDI_SUCCESS);
1193 }
1194 
1195 /*
1196  * Setup register map for the power button
1197  * NOTE:- we only map registers for platforms if
1198  * the OBP power device has any of the following
1199  * properties:
1200  *
1201  * a) Boston:  power-device-type set to "SUNW,mbc"
1202  * b) Seattle: power-device-type set to "SUNW,pic18lf65j10"
1203  * c) Chalupa: compatible set to "ali1535d+-power"
1204  *
1205  * Cases (a) and (b) are defined in FWARC 2005/687.
1206  * If none of the above conditions are true, then we
1207  * do not need to map in any registers, and this
1208  * function can simply return DDI_SUCCESS.
1209  */
1210 static int
1211 power_setup_regs(struct power_soft_state *softsp)
1212 {
1213 	char	*binding_name;
1214 	char	*power_type = NULL;
1215 	int	retval = DDI_SUCCESS;
1216 
1217 	softsp->power_regs_mapped = B_FALSE;
1218 	softsp->power_btn_ioctl = B_FALSE;
1219 	binding_name = ddi_binding_name(softsp->dip);
1220 	if (ddi_prop_lookup_string(DDI_DEV_T_ANY, softsp->dip,
1221 	    DDI_PROP_DONTPASS, POWER_DEVICE_TYPE,
1222 	    &power_type) == DDI_PROP_SUCCESS) {
1223 		if (strcmp(power_type, "SUNW,mbc") == 0) {
1224 			retval = power_setup_mbc_regs(softsp->dip, softsp);
1225 		} else if (strcmp(power_type, "SUNW,pic18lf65j10") == 0) {
1226 			retval = power_setup_epic_regs(softsp->dip, softsp);
1227 		} else {
1228 			cmn_err(CE_WARN, "unexpected power-device-type: %s\n",
1229 			    power_type);
1230 			retval = DDI_FAILURE;
1231 		}
1232 		ddi_prop_free(power_type);
1233 	} else if (strcmp(binding_name, "ali1535d+-power") == 0) {
1234 		retval = power_setup_m1535_regs(softsp->dip, softsp);
1235 	}
1236 
1237 	/*
1238 	 * If power-device-type does not exist AND the binding name is not
1239 	 * "ali1535d+-power", that means there is no additional HW and hence
1240 	 * no extra processing is necessary. In that case, retval should still
1241 	 * be set to its initial value of DDI_SUCCESS.
1242 	 */
1243 	return (retval);
1244 }
1245 
1246 static void
1247 power_free_regs(struct power_soft_state *softsp)
1248 {
1249 	if (softsp->power_regs_mapped)
1250 		ddi_regs_map_free(&softsp->power_rhandle);
1251 }
1252 #endif	/* ACPI_POWER_BUTTON */
1253