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