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