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