xref: /titanic_44/usr/src/uts/i86pc/io/ppm/acpippm.c (revision 89b43686db1fe9681d80a7cf5662730cb9378cae)
12df1fe9cSrandyf /*
22df1fe9cSrandyf  * CDDL HEADER START
32df1fe9cSrandyf  *
42df1fe9cSrandyf  * The contents of this file are subject to the terms of the
52df1fe9cSrandyf  * Common Development and Distribution License (the "License").
62df1fe9cSrandyf  * You may not use this file except in compliance with the License.
72df1fe9cSrandyf  *
82df1fe9cSrandyf  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
92df1fe9cSrandyf  * or http://www.opensolaris.org/os/licensing.
102df1fe9cSrandyf  * See the License for the specific language governing permissions
112df1fe9cSrandyf  * and limitations under the License.
122df1fe9cSrandyf  *
132df1fe9cSrandyf  * When distributing Covered Code, include this CDDL HEADER in each
142df1fe9cSrandyf  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
152df1fe9cSrandyf  * If applicable, add the following below this CDDL HEADER, with the
162df1fe9cSrandyf  * fields enclosed by brackets "[]" replaced with your own identifying
172df1fe9cSrandyf  * information: Portions Copyright [yyyy] [name of copyright owner]
182df1fe9cSrandyf  *
192df1fe9cSrandyf  * CDDL HEADER END
202df1fe9cSrandyf  */
212df1fe9cSrandyf 
222df1fe9cSrandyf /*
23b3dbb693Sgs150176  * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
242df1fe9cSrandyf  * Use is subject to license terms.
25*89b43686SBayard Bell  * Copyright (c) 2011 Bayard G. Bell. All rights reserved.
262df1fe9cSrandyf  */
272df1fe9cSrandyf 
282df1fe9cSrandyf #include <sys/types.h>
292df1fe9cSrandyf #include <sys/conf.h>
302df1fe9cSrandyf #include <sys/open.h>
312df1fe9cSrandyf #include <sys/modctl.h>
322df1fe9cSrandyf #include <sys/promif.h>
332df1fe9cSrandyf #include <sys/stat.h>
342df1fe9cSrandyf #include <sys/ddi_impldefs.h>
352df1fe9cSrandyf #include <sys/ddi.h>
362df1fe9cSrandyf #include <sys/sunddi.h>
372df1fe9cSrandyf #include <sys/epm.h>
382df1fe9cSrandyf #include <sys/acpi/acpi.h>
392df1fe9cSrandyf #include <sys/acpica.h>
402df1fe9cSrandyf #include <sys/psm_types.h>
412df1fe9cSrandyf 
422df1fe9cSrandyf /*
432df1fe9cSrandyf  *	ACPI Power Management Driver
442df1fe9cSrandyf  *
452df1fe9cSrandyf  *	acpippm deals with those bits of ppm functionality that
462df1fe9cSrandyf  *	must be mediated by ACPI
472df1fe9cSrandyf  *
482df1fe9cSrandyf  *	The routines in this driver is referenced by Platform
492df1fe9cSrandyf  *	Power Management driver of X86 workstation systems.
502df1fe9cSrandyf  *	acpippm driver is loaded because it is listed as a platform driver
512df1fe9cSrandyf  *	It is initially configured as a pseudo driver.
522df1fe9cSrandyf  */
53db2bae30SDana Myers extern void pc_tod_set_rtc_offsets(ACPI_TABLE_FADT *);
54137e2f25SGuoli Shu extern int acpica_use_safe_delay;
552df1fe9cSrandyf 
562df1fe9cSrandyf /*
572df1fe9cSrandyf  * Configuration Function prototypes and data structures
582df1fe9cSrandyf  */
592df1fe9cSrandyf static int	appm_attach(dev_info_t *, ddi_attach_cmd_t);
602df1fe9cSrandyf static int	appm_detach(dev_info_t *, ddi_detach_cmd_t);
612df1fe9cSrandyf static int	appm_getinfo(dev_info_t *, ddi_info_cmd_t, void *, void **);
622df1fe9cSrandyf static int	appm_open(dev_t *dev_p, int flag, int otyp, cred_t *cred_p);
632df1fe9cSrandyf static int	appm_close(dev_t dev, int flag, int otyp, cred_t *cred_p);
642df1fe9cSrandyf static int	appm_ioctl(dev_t, int, intptr_t, int, cred_t *, int *);
652df1fe9cSrandyf 
662df1fe9cSrandyf /*
672df1fe9cSrandyf  * Configuration data structures
682df1fe9cSrandyf  */
692df1fe9cSrandyf static struct cb_ops appm_cbops = {
702df1fe9cSrandyf 	appm_open,		/* open */
712df1fe9cSrandyf 	appm_close,		/* close */
722df1fe9cSrandyf 	nodev,			/* strategy */
732df1fe9cSrandyf 	nodev,			/* print */
742df1fe9cSrandyf 	nodev,			/* dump */
752df1fe9cSrandyf 	nodev,			/* read */
762df1fe9cSrandyf 	nodev,			/* write */
772df1fe9cSrandyf 	appm_ioctl,		/* ioctl */
782df1fe9cSrandyf 	nodev,			/* devmap */
792df1fe9cSrandyf 	nodev,			/* mmap */
802df1fe9cSrandyf 	nodev,			/* segmap */
812df1fe9cSrandyf 	nochpoll,		/* chpoll */
822df1fe9cSrandyf 	ddi_prop_op,		/* prop_op */
832df1fe9cSrandyf 	NULL,			/* stream */
842df1fe9cSrandyf 	D_MP | D_NEW,		/* flag */
852df1fe9cSrandyf 	CB_REV,			/* rev */
862df1fe9cSrandyf 	nodev,			/* aread */
872df1fe9cSrandyf 	nodev,			/* awrite */
882df1fe9cSrandyf };
892df1fe9cSrandyf 
902df1fe9cSrandyf static struct dev_ops appm_ops = {
912df1fe9cSrandyf 	DEVO_REV,		/* devo_rev */
922df1fe9cSrandyf 	0,			/* refcnt */
932df1fe9cSrandyf 	appm_getinfo,		/* getinfo */
942df1fe9cSrandyf 	nulldev,		/* identify */
952df1fe9cSrandyf 	nulldev,		/* probe */
962df1fe9cSrandyf 	appm_attach,		/* attach */
972df1fe9cSrandyf 	appm_detach,		/* detach */
982df1fe9cSrandyf 	nodev,			/* reset */
992df1fe9cSrandyf 	&appm_cbops,		/* cb_ops */
1002df1fe9cSrandyf 	NULL,			/* bus_ops */
10119397407SSherry Moore 	NULL,			/* power */
10219397407SSherry Moore 	ddi_quiesce_not_needed,		/* quiesce */
1032df1fe9cSrandyf };
1042df1fe9cSrandyf 
1052df1fe9cSrandyf extern struct mod_ops mod_driverops;
1062df1fe9cSrandyf 
1072df1fe9cSrandyf static struct modldrv modldrv = {
1082df1fe9cSrandyf 	&mod_driverops,
10919397407SSherry Moore 	"ACPI ppm driver",
1102df1fe9cSrandyf 	&appm_ops,
1112df1fe9cSrandyf };
1122df1fe9cSrandyf 
1132df1fe9cSrandyf static struct modlinkage modlinkage = {
1142df1fe9cSrandyf 	MODREV_1,
1152df1fe9cSrandyf 	&modldrv,
1162df1fe9cSrandyf 	NULL
1172df1fe9cSrandyf };
1182df1fe9cSrandyf 
1192df1fe9cSrandyf /*
1202df1fe9cSrandyf  * Driver state structure
1212df1fe9cSrandyf  */
1222df1fe9cSrandyf typedef struct {
1232df1fe9cSrandyf 	dev_info_t		*dip;
1242df1fe9cSrandyf 	ddi_acc_handle_t	devid_hndl;
1252df1fe9cSrandyf 	ddi_acc_handle_t	estar_hndl;
1262df1fe9cSrandyf 	int			lyropen;		/* ref count */
1272df1fe9cSrandyf } appm_unit;
1282df1fe9cSrandyf 
1292df1fe9cSrandyf /*
1302df1fe9cSrandyf  * Driver global variables
1312df1fe9cSrandyf  *
1322df1fe9cSrandyf  * appm_lock synchronize the access of lyr handle to each appm
1332df1fe9cSrandyf  * minor device, therefore write to tomatillo device is
1342df1fe9cSrandyf  * sequentialized.  Lyr protocol requires pairing up lyr open
1352df1fe9cSrandyf  * and close, so only a single reference is allowed per minor node.
1362df1fe9cSrandyf  */
1372df1fe9cSrandyf static void	*appm_statep;
1382df1fe9cSrandyf static kmutex_t  appm_lock;
1392df1fe9cSrandyf 
1402df1fe9cSrandyf /*
1412df1fe9cSrandyf  * S3 stuff:
1422df1fe9cSrandyf  */
1432df1fe9cSrandyf extern int acpi_enter_sleepstate(s3a_t *);
1442df1fe9cSrandyf extern int acpi_exit_sleepstate(s3a_t *);
1452df1fe9cSrandyf 
1462df1fe9cSrandyf 
1472df1fe9cSrandyf int
_init(void)1482df1fe9cSrandyf _init(void)
1492df1fe9cSrandyf {
1502df1fe9cSrandyf 	int	error;
1512df1fe9cSrandyf 
1522df1fe9cSrandyf 	if ((error = ddi_soft_state_init(&appm_statep,
1532df1fe9cSrandyf 	    sizeof (appm_unit), 0)) != DDI_SUCCESS) {
1542df1fe9cSrandyf 		return (error);
1552df1fe9cSrandyf 	}
1562df1fe9cSrandyf 
1572df1fe9cSrandyf 	mutex_init(&appm_lock, NULL, MUTEX_DRIVER, NULL);
1582df1fe9cSrandyf 
1592df1fe9cSrandyf 	if ((error = mod_install(&modlinkage)) != DDI_SUCCESS) {
1602df1fe9cSrandyf 		mutex_destroy(&appm_lock);
1612df1fe9cSrandyf 		ddi_soft_state_fini(&appm_statep);
1622df1fe9cSrandyf 		return (error);
1632df1fe9cSrandyf 	}
1642df1fe9cSrandyf 
1652df1fe9cSrandyf 	return (error);
1662df1fe9cSrandyf }
1672df1fe9cSrandyf 
1682df1fe9cSrandyf int
_fini(void)1692df1fe9cSrandyf _fini(void)
1702df1fe9cSrandyf {
1712df1fe9cSrandyf 	int	error;
1722df1fe9cSrandyf 
1732df1fe9cSrandyf 	if ((error = mod_remove(&modlinkage)) == DDI_SUCCESS) {
1742df1fe9cSrandyf 		mutex_destroy(&appm_lock);
1752df1fe9cSrandyf 		ddi_soft_state_fini(&appm_statep);
1762df1fe9cSrandyf 	}
1772df1fe9cSrandyf 
1782df1fe9cSrandyf 	return (error);
1792df1fe9cSrandyf 
1802df1fe9cSrandyf }
1812df1fe9cSrandyf 
1822df1fe9cSrandyf int
_info(struct modinfo * modinfop)1832df1fe9cSrandyf _info(struct modinfo *modinfop)
1842df1fe9cSrandyf {
1852df1fe9cSrandyf 	return (mod_info(&modlinkage, modinfop));
1862df1fe9cSrandyf }
1872df1fe9cSrandyf 
1882df1fe9cSrandyf 
1892df1fe9cSrandyf 
1902df1fe9cSrandyf /*
1912df1fe9cSrandyf  * Driver attach(9e) entry point
1922df1fe9cSrandyf  */
1932df1fe9cSrandyf static int
appm_attach(dev_info_t * dip,ddi_attach_cmd_t cmd)1942df1fe9cSrandyf appm_attach(dev_info_t *dip, ddi_attach_cmd_t cmd)
1952df1fe9cSrandyf {
1962df1fe9cSrandyf 	char	*str = "appm_attach";
1972df1fe9cSrandyf 	int		instance;
1982df1fe9cSrandyf 	appm_unit	*unitp;
199db2bae30SDana Myers 	ACPI_TABLE_FADT	*fadt = NULL;
2002df1fe9cSrandyf 	int		rv = DDI_SUCCESS;
2012df1fe9cSrandyf 
2022df1fe9cSrandyf 	switch (cmd) {
2032df1fe9cSrandyf 	case DDI_ATTACH:
2042df1fe9cSrandyf 		break;
2052df1fe9cSrandyf 	case DDI_RESUME:
2062df1fe9cSrandyf 		return (DDI_SUCCESS);
2072df1fe9cSrandyf 	default:
2082df1fe9cSrandyf 		cmn_err(CE_WARN, "%s: cmd %d unsupported.\n", str, cmd);
2092df1fe9cSrandyf 		return (DDI_FAILURE);
2102df1fe9cSrandyf 	}
2112df1fe9cSrandyf 
2122df1fe9cSrandyf 	instance = ddi_get_instance(dip);
2132df1fe9cSrandyf 	rv = ddi_soft_state_zalloc(appm_statep, instance);
2142df1fe9cSrandyf 	if (rv != DDI_SUCCESS) {
2152df1fe9cSrandyf 		cmn_err(CE_WARN, "%s: failed alloc for dev(%s@%s)",
2162df1fe9cSrandyf 		    str, ddi_binding_name(dip),
2172df1fe9cSrandyf 		    ddi_get_name_addr(dip) ? ddi_get_name_addr(dip) : " ");
2182df1fe9cSrandyf 		return (rv);
2192df1fe9cSrandyf 	}
2202df1fe9cSrandyf 
2212df1fe9cSrandyf 	if ((unitp = ddi_get_soft_state(appm_statep, instance)) == NULL) {
2222df1fe9cSrandyf 		rv = DDI_FAILURE;
2232df1fe9cSrandyf 		goto doerrs;
2242df1fe9cSrandyf 	}
2252df1fe9cSrandyf 
2262df1fe9cSrandyf 	/*
2272df1fe9cSrandyf 	 * Export "ddi-kernel-ioctl" property - prepared to support
2282df1fe9cSrandyf 	 * kernel ioctls (driver layering).
2292df1fe9cSrandyf 	 * XXX is this still needed?
2302df1fe9cSrandyf 	 * XXXX (RSF) Not that I am aware of.
2312df1fe9cSrandyf 	 */
2322df1fe9cSrandyf 	rv = ddi_prop_create(DDI_DEV_T_NONE, dip, DDI_PROP_CANSLEEP,
2332df1fe9cSrandyf 	    DDI_KERNEL_IOCTL, NULL, 0);
2342df1fe9cSrandyf 	if (rv != DDI_PROP_SUCCESS)
2352df1fe9cSrandyf 		goto doerrs;
2362df1fe9cSrandyf 
2372df1fe9cSrandyf 	ddi_report_dev(dip);
2382df1fe9cSrandyf 	unitp->dip = dip;
2392df1fe9cSrandyf 
2402df1fe9cSrandyf 	/*
2412df1fe9cSrandyf 	 * XXX here we would do whatever we need to to determine if the
2422df1fe9cSrandyf 	 * XXX platform supports ACPI, and fail the attach if not.
2432df1fe9cSrandyf 	 * XXX If it does, we do whatever setup is needed to get access to
2442df1fe9cSrandyf 	 * XXX ACPI register space.
2452df1fe9cSrandyf 	 */
2462df1fe9cSrandyf 
2472df1fe9cSrandyf 	unitp->lyropen = 0;
2482df1fe9cSrandyf 
2492df1fe9cSrandyf 	/*
2502df1fe9cSrandyf 	 * create minor node for kernel_ioctl calls
2512df1fe9cSrandyf 	 */
2522df1fe9cSrandyf 	rv = ddi_create_minor_node(dip, "acpi-ppm", S_IFCHR, instance, 0, 0);
2532df1fe9cSrandyf 	if (rv != DDI_SUCCESS)
2542df1fe9cSrandyf 		goto doerrs;
2552df1fe9cSrandyf 
256c5f4c424Sgs150176 	/* Get the FADT */
257db2bae30SDana Myers 	if (AcpiGetTable(ACPI_SIG_FADT, 1,
258c5f4c424Sgs150176 	    (ACPI_TABLE_HEADER **)&fadt) != AE_OK)
259c5f4c424Sgs150176 		return (rv);
260c5f4c424Sgs150176 
261c5f4c424Sgs150176 	/* Init the RTC offsets */
262c5f4c424Sgs150176 	if (fadt != NULL)
263c5f4c424Sgs150176 		pc_tod_set_rtc_offsets(fadt);
264b3dbb693Sgs150176 
2652df1fe9cSrandyf 	return (rv);
2662df1fe9cSrandyf 
2672df1fe9cSrandyf doerrs:
2682df1fe9cSrandyf 
2692df1fe9cSrandyf 	if (ddi_prop_exists(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS |
2702df1fe9cSrandyf 	    DDI_PROP_NOTPROM, DDI_KERNEL_IOCTL))
2712df1fe9cSrandyf 		ddi_prop_remove_all(dip);
2722df1fe9cSrandyf 
2732df1fe9cSrandyf 	ddi_soft_state_free(appm_statep, instance);
2742df1fe9cSrandyf 
2752df1fe9cSrandyf 	return (rv);
2762df1fe9cSrandyf }
2772df1fe9cSrandyf 
2782df1fe9cSrandyf 
2792df1fe9cSrandyf /*
2802df1fe9cSrandyf  * Driver getinfo(9e) entry routine
2812df1fe9cSrandyf  */
2822df1fe9cSrandyf /* ARGSUSED */
2832df1fe9cSrandyf static int
appm_getinfo(dev_info_t * dip,ddi_info_cmd_t cmd,void * arg,void ** result)2842df1fe9cSrandyf appm_getinfo(dev_info_t *dip, ddi_info_cmd_t cmd, void *arg, void **result)
2852df1fe9cSrandyf {
2862df1fe9cSrandyf 	appm_unit	*unitp;
2872df1fe9cSrandyf 	int		instance;
2882df1fe9cSrandyf 
2892df1fe9cSrandyf 	switch (cmd) {
2902df1fe9cSrandyf 	case DDI_INFO_DEVT2DEVINFO:
2912df1fe9cSrandyf 		instance = getminor((dev_t)arg);
2922df1fe9cSrandyf 		unitp = ddi_get_soft_state(appm_statep, instance);
2932df1fe9cSrandyf 		if (unitp == NULL) {
2942df1fe9cSrandyf 			return (DDI_FAILURE);
2952df1fe9cSrandyf 		}
2962df1fe9cSrandyf 		*result = (void *) unitp->dip;
2972df1fe9cSrandyf 		return (DDI_SUCCESS);
2982df1fe9cSrandyf 
2992df1fe9cSrandyf 	case DDI_INFO_DEVT2INSTANCE:
3002df1fe9cSrandyf 		instance = getminor((dev_t)arg);
3012df1fe9cSrandyf 		*result = (void *)(uintptr_t)instance;
3022df1fe9cSrandyf 		return (DDI_SUCCESS);
3032df1fe9cSrandyf 
3042df1fe9cSrandyf 	default:
3052df1fe9cSrandyf 		return (DDI_FAILURE);
3062df1fe9cSrandyf 	}
3072df1fe9cSrandyf }
3082df1fe9cSrandyf 
3092df1fe9cSrandyf 
3102df1fe9cSrandyf /*
3112df1fe9cSrandyf  * detach(9e)
3122df1fe9cSrandyf  */
3132df1fe9cSrandyf /* ARGSUSED */
3142df1fe9cSrandyf static int
appm_detach(dev_info_t * dip,ddi_detach_cmd_t cmd)3152df1fe9cSrandyf appm_detach(dev_info_t *dip, ddi_detach_cmd_t cmd)
3162df1fe9cSrandyf {
3172df1fe9cSrandyf 	char *str = "appm_detach";
3182df1fe9cSrandyf 
3192df1fe9cSrandyf 	switch (cmd) {
3202df1fe9cSrandyf 	case DDI_DETACH:
3212df1fe9cSrandyf 		return (DDI_FAILURE);
3222df1fe9cSrandyf 	case DDI_SUSPEND:
3232df1fe9cSrandyf 		return (DDI_SUCCESS);
3242df1fe9cSrandyf 	default:
3252df1fe9cSrandyf 		cmn_err(CE_WARN, "%s: cmd %d unsupported", str, cmd);
3262df1fe9cSrandyf 		return (DDI_FAILURE);
3272df1fe9cSrandyf 	}
3282df1fe9cSrandyf }
3292df1fe9cSrandyf 
3302df1fe9cSrandyf 
3312df1fe9cSrandyf /* ARGSUSED */
3322df1fe9cSrandyf static int
appm_open(dev_t * dev_p,int flag,int otyp,cred_t * cred_p)3332df1fe9cSrandyf appm_open(dev_t *dev_p, int flag, int otyp, cred_t *cred_p)
3342df1fe9cSrandyf {
3352df1fe9cSrandyf 	appm_unit	*unitp;
3362df1fe9cSrandyf 
3372df1fe9cSrandyf 	/* not intended to allow sysadmin level root process to open it */
3382df1fe9cSrandyf 	if (drv_priv(cred_p) != DDI_SUCCESS)
3392df1fe9cSrandyf 		return (EPERM);
3402df1fe9cSrandyf 
3412df1fe9cSrandyf 	if ((unitp = ddi_get_soft_state(
3422df1fe9cSrandyf 	    appm_statep, getminor(*dev_p))) == NULL) {
3432df1fe9cSrandyf 		cmn_err(CE_WARN, "appm_open: failed to get soft state!");
3442df1fe9cSrandyf 		return (DDI_FAILURE);
3452df1fe9cSrandyf 	}
3462df1fe9cSrandyf 
3472df1fe9cSrandyf 	mutex_enter(&appm_lock);
3482df1fe9cSrandyf 	if (unitp->lyropen != 0) {
3492df1fe9cSrandyf 		mutex_exit(&appm_lock);
3502df1fe9cSrandyf 		return (EBUSY);
3512df1fe9cSrandyf 	}
3522df1fe9cSrandyf 	unitp->lyropen++;
3532df1fe9cSrandyf 	mutex_exit(&appm_lock);
3542df1fe9cSrandyf 
3552df1fe9cSrandyf 	return (DDI_SUCCESS);
3562df1fe9cSrandyf }
3572df1fe9cSrandyf 
3582df1fe9cSrandyf 
3592df1fe9cSrandyf /* ARGSUSED */
3602df1fe9cSrandyf static int
appm_close(dev_t dev,int flag,int otyp,cred_t * cred_p)3612df1fe9cSrandyf appm_close(dev_t dev, int flag, int otyp, cred_t *cred_p)
3622df1fe9cSrandyf {
3632df1fe9cSrandyf 	appm_unit	*unitp;
3642df1fe9cSrandyf 
3652df1fe9cSrandyf 	if ((unitp =
3662df1fe9cSrandyf 	    ddi_get_soft_state(appm_statep, getminor(dev))) == NULL)
3672df1fe9cSrandyf 		return (DDI_FAILURE);
3682df1fe9cSrandyf 
3692df1fe9cSrandyf 	mutex_enter(&appm_lock);
3702df1fe9cSrandyf 	unitp->lyropen = 0;
3712df1fe9cSrandyf 	mutex_exit(&appm_lock);
3722df1fe9cSrandyf 
3732df1fe9cSrandyf 	return (DDI_SUCCESS);
3742df1fe9cSrandyf }
3752df1fe9cSrandyf 
3762df1fe9cSrandyf 
3772df1fe9cSrandyf /*
3782df1fe9cSrandyf  * must match ppm.conf
3792df1fe9cSrandyf  */
3802df1fe9cSrandyf #define	APPMIOC			('A' << 8)
3812df1fe9cSrandyf #define	APPMIOC_ENTER_S3	(APPMIOC | 1)	/* arg *s3a_t */
3822df1fe9cSrandyf #define	APPMIOC_EXIT_S3		(APPMIOC | 2)	/* arg *s3a_t */
3832df1fe9cSrandyf 
3842df1fe9cSrandyf /* ARGSUSED3 */
3852df1fe9cSrandyf static int
appm_ioctl(dev_t dev,int cmd,intptr_t arg,int flag,cred_t * cred_p,int * rval_p)3862df1fe9cSrandyf appm_ioctl(dev_t dev, int cmd, intptr_t arg, int flag,
3872df1fe9cSrandyf     cred_t *cred_p, int *rval_p)
3882df1fe9cSrandyf {
3892df1fe9cSrandyf 	static boolean_t	acpi_initted = B_FALSE;
3902df1fe9cSrandyf 	char			*str = "appm_ioctl";
3912df1fe9cSrandyf 	int			ret;
3922df1fe9cSrandyf 	s3a_t			*s3ap = (s3a_t *)arg;
3932df1fe9cSrandyf 
3942df1fe9cSrandyf 	PMD(PMD_SX, ("%s: called with %x\n", str, cmd))
3952df1fe9cSrandyf 
3962df1fe9cSrandyf 	if (drv_priv(cred_p) != 0) {
3972df1fe9cSrandyf 		PMD(PMD_SX, ("%s: EPERM\n", str))
3982df1fe9cSrandyf 		return (EPERM);
3992df1fe9cSrandyf 	}
4002df1fe9cSrandyf 
4012df1fe9cSrandyf 	if (ddi_get_soft_state(appm_statep, getminor(dev)) == NULL) {
4022df1fe9cSrandyf 		PMD(PMD_SX, ("%s: no soft state: EIO\n", str))
4032df1fe9cSrandyf 		return (EIO);
4042df1fe9cSrandyf 	}
4052df1fe9cSrandyf 
4062df1fe9cSrandyf 	if (!acpi_initted) {
4072df1fe9cSrandyf 		PMD(PMD_SX, ("%s: !acpi_initted\n", str))
4082df1fe9cSrandyf 		if (acpica_init() == 0) {
4092df1fe9cSrandyf 			acpi_initted = B_TRUE;
4102df1fe9cSrandyf 		} else {
4112df1fe9cSrandyf 			if (rval_p != NULL) {
4122df1fe9cSrandyf 				*rval_p = EINVAL;
4132df1fe9cSrandyf 			}
4142df1fe9cSrandyf 			PMD(PMD_SX, ("%s: EINVAL\n", str))
4152df1fe9cSrandyf 			return (EINVAL);
4162df1fe9cSrandyf 		}
4172df1fe9cSrandyf 	}
4182df1fe9cSrandyf 
4192df1fe9cSrandyf 	PMD(PMD_SX, ("%s: looking for cmd %x\n", str, cmd))
4202df1fe9cSrandyf 	switch (cmd) {
4212df1fe9cSrandyf 	case APPMIOC_ENTER_S3:
4222df1fe9cSrandyf 		/*
4232df1fe9cSrandyf 		 * suspend to RAM (ie S3)
4242df1fe9cSrandyf 		 */
4252df1fe9cSrandyf 		PMD(PMD_SX, ("%s: cmd %x, arg %p\n", str, cmd, (void *)arg))
426137e2f25SGuoli Shu 		acpica_use_safe_delay = 1;
4272df1fe9cSrandyf 		ret = acpi_enter_sleepstate(s3ap);
4282df1fe9cSrandyf 		break;
4292df1fe9cSrandyf 
4302df1fe9cSrandyf 	case APPMIOC_EXIT_S3:
4312df1fe9cSrandyf 		/*
4322df1fe9cSrandyf 		 * return from S3
4332df1fe9cSrandyf 		 */
4342df1fe9cSrandyf 		PMD(PMD_SX, ("%s: cmd %x, arg %p\n", str, cmd, (void *)arg))
4352df1fe9cSrandyf 		ret = acpi_exit_sleepstate(s3ap);
436137e2f25SGuoli Shu 		acpica_use_safe_delay = 0;
4372df1fe9cSrandyf 		break;
4382df1fe9cSrandyf 
4392df1fe9cSrandyf 	default:
4402df1fe9cSrandyf 		PMD(PMD_SX, ("%s: cmd %x unrecognized: ENOTTY\n", str, cmd))
4412df1fe9cSrandyf 		return (ENOTTY);
4422df1fe9cSrandyf 	}
4432df1fe9cSrandyf 
4442df1fe9cSrandyf 	/*
4452df1fe9cSrandyf 	 * upon failure return EINVAL
4462df1fe9cSrandyf 	 */
4472df1fe9cSrandyf 	if (ret != 0) {
4482df1fe9cSrandyf 		if (rval_p != NULL) {
4492df1fe9cSrandyf 			*rval_p = EINVAL;
4502df1fe9cSrandyf 		}
4512df1fe9cSrandyf 		return (EINVAL);
4522df1fe9cSrandyf 	}
4532df1fe9cSrandyf 
4542df1fe9cSrandyf 	return (0);
4552df1fe9cSrandyf }
456