[BACK]Return to pm.c CVS log [TXT][DIR] Up to [local] / prex / dev / power

Annotation of prex/dev/power/pm.c, Revision 1.1

1.1     ! nbrk        1: /*-
        !             2:  * Copyright (c) 2005, Kohsuke Ohtani
        !             3:  * All rights reserved.
        !             4:  *
        !             5:  * Redistribution and use in source and binary forms, with or without
        !             6:  * modification, are permitted provided that the following conditions
        !             7:  * are met:
        !             8:  * 1. Redistributions of source code must retain the above copyright
        !             9:  *    notice, this list of conditions and the following disclaimer.
        !            10:  * 2. Redistributions in binary form must reproduce the above copyright
        !            11:  *    notice, this list of conditions and the following disclaimer in the
        !            12:  *    documentation and/or other materials provided with the distribution.
        !            13:  * 3. Neither the name of the author nor the names of any co-contributors
        !            14:  *    may be used to endorse or promote products derived from this software
        !            15:  *    without specific prior written permission.
        !            16:  *
        !            17:  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
        !            18:  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
        !            19:  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
        !            20:  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
        !            21:  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
        !            22:  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
        !            23:  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
        !            24:  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
        !            25:  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
        !            26:  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
        !            27:  * SUCH DAMAGE.
        !            28:  */
        !            29:
        !            30: /*
        !            31:  * pm.c - power management driver (hardware independent)
        !            32:  */
        !            33:
        !            34: #include <sys/ioctl.h>
        !            35: #include <driver.h>
        !            36: #include <machdep.h>
        !            37: #include <event.h>
        !            38: #include <pm.h>
        !            39: #include <cpufreq.h>
        !            40:
        !            41: /* #define DEBUG_PM 1 */
        !            42:
        !            43: #ifdef DEBUG_PM
        !            44: #define DPRINTF(a) printf a
        !            45: #else
        !            46: #define DPRINTF(a)
        !            47: #endif
        !            48:
        !            49: #ifdef CONFIG_PM_POWERSAVE
        !            50: #define DEFAULT_POWER_POLICY   PM_POWERSAVE
        !            51: #else
        !            52: #define DEFAULT_POWER_POLICY   PM_PERFORMANCE
        !            53: #endif
        !            54:
        !            55: static int pm_open(device_t dev, int mode);
        !            56: static int pm_ioctl(device_t dev, u_long cmd, void *arg);
        !            57: static int pm_close(device_t dev);
        !            58: static int pm_init(void);
        !            59:
        !            60: /*
        !            61:  * Driver structure
        !            62:  */
        !            63: struct driver pm_drv = {
        !            64:        /* name */      "Power Management",
        !            65:        /* order */     2,
        !            66:        /* init */      pm_init,
        !            67: };
        !            68:
        !            69: /*
        !            70:  * Device I/O table
        !            71:  */
        !            72: static struct devio pm_io = {
        !            73:        /* open */      pm_open,
        !            74:        /* close */     pm_close,
        !            75:        /* read */      NULL,
        !            76:        /* write */     NULL,
        !            77:        /* ioctl */     pm_ioctl,
        !            78:        /* event */     NULL,
        !            79: };
        !            80:
        !            81: static device_t pm_dev;                /* Device object */
        !            82: static int nr_open;            /* Open count */
        !            83:
        !            84: /*
        !            85:  * Power mangement policy
        !            86:  */
        !            87: static int power_policy;
        !            88:
        !            89: /*
        !            90:  * Idle timer
        !            91:  */
        !            92: static struct timer idle_timer;
        !            93: static u_long idle_count;      /* Idling counter in sec */
        !            94: static u_long suspend_timeout; /* Time until auto suspend in sec */
        !            95:
        !            96: /*
        !            97:  * Set system to suspend state
        !            98:  * Call to all devices and architecture depended code.
        !            99:  */
        !           100: int
        !           101: pm_suspend(void)
        !           102: {
        !           103:        int err;
        !           104:
        !           105:        DPRINTF(("Suspend system\n"));
        !           106:        err = device_broadcast(EVT_SUSPEND, 1);
        !           107:        if (err)
        !           108:                return err;
        !           109:        machine_suspend();
        !           110:        return 0;
        !           111: }
        !           112:
        !           113: /*
        !           114:  * Resume
        !           115:  */
        !           116: int
        !           117: pm_resume(void)
        !           118: {
        !           119:
        !           120:        DPRINTF(("Resume system\n"));
        !           121:        device_broadcast(EVT_RESUME, 1);
        !           122:        return 0;
        !           123: }
        !           124:
        !           125: /*
        !           126:  * Power off system
        !           127:  * Call to all devices and architecture depended code.
        !           128:  */
        !           129: int
        !           130: pm_poweroff(void)
        !           131: {
        !           132:        int err;
        !           133:
        !           134: #ifdef DEBUG
        !           135:        printf("power off...\n");
        !           136: #endif
        !           137:        err = device_broadcast(EVT_SHUTDOWN, 1);
        !           138:        if (err)
        !           139:                return err;
        !           140:        machine_poweroff();
        !           141:        return 0;
        !           142: }
        !           143:
        !           144: /*
        !           145:  * Reboot system.
        !           146:  */
        !           147: int
        !           148: pm_reboot(void)
        !           149: {
        !           150:        int err;
        !           151:
        !           152: #ifdef DEBUG
        !           153:        printf("rebooting...\n");
        !           154: #endif
        !           155:        err = device_broadcast(EVT_SHUTDOWN, 1);
        !           156:        if (err)
        !           157:                return err;
        !           158:
        !           159:        irq_lock();
        !           160:
        !           161:        /*
        !           162:         * Do reset.
        !           163:         */
        !           164:        machine_reset();
        !           165:        return 0;
        !           166: }
        !           167:
        !           168: /*
        !           169:  * Idle timer handler.
        !           170:  */
        !           171: static void
        !           172: idle_timeout(void *arg)
        !           173: {
        !           174:
        !           175:        irq_lock();
        !           176:        idle_count++;
        !           177:        irq_unlock();
        !           178:        if (idle_count >= suspend_timeout)
        !           179:                pm_suspend();
        !           180:        else
        !           181:                timer_callout(&idle_timer, 1000, &idle_timeout, NULL);
        !           182: }
        !           183:
        !           184: #if 0
        !           185: /*
        !           186:  * Set suspend timer.
        !           187:  */
        !           188: static int
        !           189: pm_settimer(u_long sec)
        !           190: {
        !           191:
        !           192:        sched_lock();
        !           193:        if (sec)
        !           194:                timer_callout(&idle_timer, 1000, &idle_timeout, NULL);
        !           195:        else
        !           196:                timer_stop(&idle_timer);
        !           197:        idle_count = 0;
        !           198:        suspend_timeout = sec;
        !           199:        sched_unlock();
        !           200:        return 0;
        !           201: }
        !           202:
        !           203: /*
        !           204:  * Get power management timer.
        !           205:  */
        !           206: static int
        !           207: pm_gettimer(u_long *sec)
        !           208: {
        !           209:
        !           210:        *sec = suspend_timeout;
        !           211:        return 0;
        !           212: }
        !           213: #endif
        !           214:
        !           215: /*
        !           216:  * Reload idle timer.
        !           217:  *
        !           218:  * A keyboard or mouse driver will call this routine when
        !           219:  * it detect the user activity like key press or mouse move.
        !           220:  */
        !           221: void
        !           222: pm_active(void)
        !           223: {
        !           224:
        !           225:        idle_count = 0;
        !           226: }
        !           227:
        !           228: /*
        !           229:  * Set power policy.
        !           230:  */
        !           231: static int
        !           232: pm_setpolicy(int policy)
        !           233: {
        !           234:
        !           235:        if (policy != PM_POWERSAVE && policy != PM_PERFORMANCE)
        !           236:                return EINVAL;
        !           237: #ifdef CONFIG_CPUFREQ
        !           238:        cpufreq_setpolicy(policy);
        !           239: #endif
        !           240:        power_policy = policy;
        !           241:        return 0;
        !           242: }
        !           243:
        !           244: /*
        !           245:  * Get current power policy.
        !           246:  */
        !           247: int
        !           248: pm_getpolicy(void)
        !           249: {
        !           250:
        !           251:        return power_policy;
        !           252: }
        !           253:
        !           254: /*
        !           255:  * Open the pm device.
        !           256:  *
        !           257:  * The open operation is allowed to only one task. This can protect
        !           258:  * the critical ioctl operation from some malicious tasks. For example,
        !           259:  * the power off should be done by the privileged task like a process
        !           260:  * server.
        !           261:  */
        !           262: static int
        !           263: pm_open(device_t dev, int mode)
        !           264: {
        !           265:
        !           266:        if (nr_open > 0)
        !           267:                return EBUSY;
        !           268:        nr_open++;
        !           269:        return 0;
        !           270: }
        !           271:
        !           272: static int
        !           273: pm_close(device_t dev)
        !           274: {
        !           275:
        !           276:        if (nr_open != 1)
        !           277:                return EINVAL;
        !           278:        nr_open--;
        !           279:        return 0;
        !           280: }
        !           281:
        !           282: static int
        !           283: pm_ioctl(device_t dev, u_long cmd, void *arg)
        !           284: {
        !           285:        int err = 0;
        !           286:        int policy, subcmd;
        !           287:
        !           288:        switch (cmd) {
        !           289:        case PMIOC_SET_POWER:
        !           290:                if (umem_copyin(arg, &subcmd, sizeof(int)))
        !           291:                        return EFAULT;
        !           292:
        !           293:                switch (subcmd) {
        !           294:                case POWER_SUSPEND:
        !           295:                        pm_suspend();
        !           296:                        break;
        !           297:                case POWER_OFF:
        !           298:                        pm_poweroff();
        !           299:                        break;
        !           300:                case POWER_REBOOT:
        !           301:                        pm_reboot();
        !           302:                        break;
        !           303:                default:
        !           304:                        return EINVAL;
        !           305:                }
        !           306:                break;
        !           307:
        !           308:        case PMIOC_SET_POLICY:
        !           309:                if (umem_copyin(arg, &policy, sizeof(int)))
        !           310:                        return EFAULT;
        !           311:                err = pm_setpolicy(policy);
        !           312:                break;
        !           313:
        !           314:        case PMIOC_GET_POLICY:
        !           315:                policy = pm_getpolicy();
        !           316:                if (umem_copyout(&policy, arg, sizeof(int)))
        !           317:                        return EFAULT;
        !           318:                break;
        !           319:        default:
        !           320:                return EINVAL;
        !           321:        }
        !           322:        return err;
        !           323: }
        !           324:
        !           325: /*
        !           326:  * Initialize
        !           327:  */
        !           328: static int
        !           329: pm_init(void)
        !           330: {
        !           331:
        !           332:        /* Create device object */
        !           333:        pm_dev = device_create(&pm_io, "pm", DF_CHR);
        !           334:        ASSERT(pm_dev);
        !           335:
        !           336:        nr_open = 0;
        !           337:        idle_count = 0;
        !           338:        suspend_timeout = 0;
        !           339:        power_policy = DEFAULT_POWER_POLICY;
        !           340:        timer_init(&idle_timer);
        !           341: #ifdef DEBUG
        !           342:        printf("pm: Default power policy is %s mode\n",
        !           343:               (power_policy == PM_POWERSAVE) ? "power save" : "performance");
        !           344: #endif
        !           345:        return 0;
        !           346: }

CVSweb