Annotation of prex-old/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 "dvs.h"
! 40:
! 41: /* #define DEBUG_PM 1 */
! 42:
! 43: #ifdef DEBUG_PM
! 44: #define pm_printf(fmt, args...) printk("pm: " fmt, ## args)
! 45: #else
! 46: #define pm_printf(fmt...) do {} while (0)
! 47: #endif
! 48:
! 49:
! 50: #ifdef CONFIG_PM_POWERSAVE
! 51: #define DEFAULT_POWER_POLICY PM_POWERSAVE
! 52: #else
! 53: #define DEFAULT_POWER_POLICY PM_PERFORMANCE
! 54: #endif
! 55:
! 56: static int pm_open(device_t dev, int mode);
! 57: static int pm_ioctl(device_t dev, int cmd, u_long arg);
! 58: static int pm_close(device_t dev);
! 59: static int pm_init(void);
! 60:
! 61: /*
! 62: * Driver structure
! 63: */
! 64: struct driver pm_drv = {
! 65: /* name */ "Power Management",
! 66: /* order */ 2,
! 67: /* init */ pm_init,
! 68: };
! 69:
! 70: static struct devio pm_io = {
! 71: /* open */ pm_open,
! 72: /* close */ pm_close,
! 73: /* read */ NULL,
! 74: /* write */ NULL,
! 75: /* ioctl */ pm_ioctl,
! 76: /* event */ NULL,
! 77: };
! 78:
! 79: static device_t pm_dev; /* Device object */
! 80: static int nr_open; /* Open count */
! 81:
! 82: /*
! 83: * Power mangement policy
! 84: */
! 85: static int power_policy;
! 86:
! 87: /*
! 88: * Idle timer
! 89: */
! 90: static struct timer idle_timer;
! 91: static u_long idle_count; /* Idling counter in sec */
! 92: static u_long suspend_timeout; /* Time until auto suspend in sec */
! 93:
! 94: /*
! 95: * Set system to suspend state
! 96: * Call to all devices and architecture depended code.
! 97: */
! 98: int
! 99: pm_suspend(void)
! 100: {
! 101: int err;
! 102:
! 103: pm_printf("Suspend system\n");
! 104: err = device_broadcast(EVT_SUSPEND, 1);
! 105: if (err)
! 106: return err;
! 107: machine_suspend();
! 108: return 0;
! 109: }
! 110:
! 111: /*
! 112: * Resume
! 113: */
! 114: int
! 115: pm_resume(void)
! 116: {
! 117: pm_printf("Resume system\n");
! 118: device_broadcast(EVT_RESUME, 1);
! 119: return 0;
! 120: }
! 121:
! 122: /*
! 123: * Power off system
! 124: * Call to all devices and architecture depended code.
! 125: */
! 126: int
! 127: pm_poweroff(void)
! 128: {
! 129: int err;
! 130:
! 131: pm_printf("Power off...\n");
! 132: err = device_broadcast(EVT_SHUTDOWN, 1);
! 133: if (err)
! 134: return err;
! 135: machine_poweroff();
! 136: return 0;
! 137: }
! 138:
! 139: /*
! 140: * Reboot system.
! 141: */
! 142: int
! 143: pm_reboot(void)
! 144: {
! 145: int err;
! 146:
! 147: pm_printf("rebooting...\n");
! 148: err = device_broadcast(EVT_SHUTDOWN, 1);
! 149: if (err)
! 150: return err;
! 151:
! 152: irq_lock();
! 153:
! 154: /*
! 155: * Do reset.
! 156: */
! 157: machine_reset();
! 158: return 0;
! 159: }
! 160:
! 161: /*
! 162: * Idle timer handler
! 163: */
! 164: static void
! 165: idle_timeout(u_long dummy)
! 166: {
! 167:
! 168: irq_lock();
! 169: idle_count++;
! 170: irq_unlock();
! 171: if (idle_count >= suspend_timeout)
! 172: pm_suspend();
! 173: else
! 174: timer_callout(&idle_timer, idle_timeout, 0, 1000);
! 175: }
! 176:
! 177: /*
! 178: * Set suspend timer
! 179: */
! 180: int
! 181: pm_settimer(u_long sec)
! 182: {
! 183:
! 184: sched_lock();
! 185: if (sec)
! 186: timer_callout(&idle_timer, idle_timeout, 0, 1000);
! 187: else
! 188: timer_stop(&idle_timer);
! 189: idle_count = 0;
! 190: suspend_timeout = sec;
! 191: sched_unlock();
! 192: return 0;
! 193: }
! 194:
! 195: /*
! 196: * Get power management timer
! 197: */
! 198: int
! 199: pm_gettimer(u_long *sec)
! 200: {
! 201:
! 202: *sec = suspend_timeout;
! 203: return 0;
! 204: }
! 205:
! 206: /*
! 207: * Reload idle timer
! 208: */
! 209: void
! 210: pm_active(void)
! 211: {
! 212:
! 213: idle_count = 0;
! 214: }
! 215:
! 216: /*
! 217: * Set power policy
! 218: */
! 219: static int
! 220: pm_setpolicy(int policy)
! 221: {
! 222:
! 223: if (policy != PM_POWERSAVE && policy != PM_PERFORMANCE)
! 224: return EINVAL;
! 225: #ifdef CONFIG_CPUFREQ
! 226: cpufreq_setpolicy(policy);
! 227: #endif
! 228: power_policy = policy;
! 229: return 0;
! 230: }
! 231:
! 232: /*
! 233: * Get current power policy
! 234: */
! 235: int
! 236: pm_getpolicy(void)
! 237: {
! 238:
! 239: return power_policy;
! 240: }
! 241:
! 242: /*
! 243: * Open the pm device.
! 244: *
! 245: * The open operation is allowed to only one task. This can protect
! 246: * the critical ioctl operation from some malicious tasks. For example,
! 247: * the power off should be done by the privileged task like a process
! 248: * server.
! 249: */
! 250: static int
! 251: pm_open(device_t dev, int mode)
! 252: {
! 253:
! 254: if (nr_open > 0)
! 255: return EBUSY;
! 256: nr_open++;
! 257: return 0;
! 258: }
! 259:
! 260: static int
! 261: pm_close(device_t dev)
! 262: {
! 263:
! 264: if (nr_open != 1)
! 265: return EINVAL;
! 266: nr_open--;
! 267: return 0;
! 268: }
! 269:
! 270: static int
! 271: pm_ioctl(device_t dev, int cmd, u_long arg)
! 272: {
! 273: int err = 0;
! 274: int policy;
! 275:
! 276: switch (cmd) {
! 277: case PMIOC_SET_POWER:
! 278: switch (arg) {
! 279: case POWER_SUSPEND:
! 280: pm_suspend();
! 281: break;
! 282: case POWER_OFF:
! 283: pm_poweroff();
! 284: break;
! 285: case POWER_REBOOT:
! 286: pm_reboot();
! 287: break;
! 288: default:
! 289: return EINVAL;
! 290: }
! 291: break;
! 292: case PMIOC_SET_POLICY:
! 293: err = pm_setpolicy((int)arg);
! 294: break;
! 295: case PMIOC_GET_POLICY:
! 296: policy = pm_getpolicy();
! 297: if (umem_copyout(&policy, (int *)arg, sizeof(int)))
! 298: return EFAULT;
! 299: break;
! 300: default:
! 301: return EINVAL;
! 302: }
! 303: return err;
! 304: }
! 305:
! 306: /*
! 307: * Initialize
! 308: */
! 309: static int
! 310: pm_init(void)
! 311: {
! 312:
! 313: /* Create device object */
! 314: pm_dev = device_create(&pm_io, "pm", DF_CHR);
! 315: ASSERT(pm_dev);
! 316:
! 317: nr_open = 0;
! 318: idle_count = 0;
! 319: suspend_timeout = 0;
! 320: power_policy = DEFAULT_POWER_POLICY;
! 321: timer_init(&idle_timer);
! 322: printk("pm: Default power policy is %s mode\n",
! 323: (power_policy == PM_POWERSAVE) ? "power save" : "performance");
! 324: return 0;
! 325: }
CVSweb