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