[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

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