ftp://ftp.kernel.org/pub/linux/kernel/v2.6/linux-2.6.6.tar.bz2
[linux-2.6.git] / arch / i386 / mach-voyager / voyager_thread.c
1 /* -*- mode: c; c-basic-offset: 8 -*- */
2
3 /* Copyright (C) 2001
4  *
5  * Author: J.E.J.Bottomley@HansenPartnership.com
6  *
7  * linux/arch/i386/kernel/voyager_thread.c
8  *
9  * This module provides the machine status monitor thread for the
10  * voyager architecture.  This allows us to monitor the machine
11  * environment (temp, voltage, fan function) and the front panel and
12  * internal UPS.  If a fault is detected, this thread takes corrective
13  * action (usually just informing init)
14  * */
15
16 #include <linux/module.h>
17 #include <linux/config.h>
18 #include <linux/mm.h>
19 #include <linux/kernel_stat.h>
20 #include <linux/delay.h>
21 #include <linux/mc146818rtc.h>
22 #include <linux/smp_lock.h>
23 #include <linux/init.h>
24 #include <linux/bootmem.h>
25 #include <linux/kmod.h>
26 #include <linux/completion.h>
27 #include <linux/sched.h>
28 #include <asm/desc.h>
29 #include <asm/voyager.h>
30 #include <asm/vic.h>
31 #include <asm/pgalloc.h>
32 #include <asm/mtrr.h>
33 #include <asm/msr.h>
34
35 #include <linux/irq.h>
36
37 #define THREAD_NAME "kvoyagerd"
38
39 /* external variables */
40 int kvoyagerd_running = 0;
41 DECLARE_MUTEX_LOCKED(kvoyagerd_sem);
42
43 static int thread(void *);
44
45 static __u8 set_timeout = 0;
46
47 /* Start the machine monitor thread.  Return 1 if OK, 0 if fail */
48 static int __init
49 voyager_thread_start(void)
50 {
51         if(kernel_thread(thread, NULL, CLONE_KERNEL) < 0) {
52                 /* This is serious, but not fatal */
53                 printk(KERN_ERR "Voyager: Failed to create system monitor thread!!!\n");
54                 return 1;
55         }
56         return 0;
57 }
58
59 static int
60 execute(const char *string)
61 {
62         int ret;
63
64         char *envp[] = {
65                 "HOME=/",
66                 "TERM=linux",
67                 "PATH=/sbin:/usr/sbin:/bin:/usr/bin",
68                 NULL,
69         };
70         char *argv[] = {
71                 "/bin/bash",
72                 "-c",
73                 (char *)string,
74                 NULL,
75         };
76
77         if ((ret = call_usermodehelper(argv[0], argv, envp, 1)) != 0) {
78                 printk(KERN_ERR "Voyager failed to run \"%s\": %i\n",
79                        string, ret);
80         }
81         return ret;
82 }
83
84 static void
85 check_from_kernel(void)
86 {
87         if(voyager_status.switch_off) {
88                 
89                 /* FIXME: This should be configureable via proc */
90                 execute("umask 600; echo 0 > /etc/initrunlvl; kill -HUP 1");
91         } else if(voyager_status.power_fail) {
92                 VDEBUG(("Voyager daemon detected AC power failure\n"));
93                 
94                 /* FIXME: This should be configureable via proc */
95                 execute("umask 600; echo F > /etc/powerstatus; kill -PWR 1");
96                 set_timeout = 1;
97         }
98 }
99
100 static void
101 check_continuing_condition(void)
102 {
103         if(voyager_status.power_fail) {
104                 __u8 data;
105                 voyager_cat_psi(VOYAGER_PSI_SUBREAD, 
106                                 VOYAGER_PSI_AC_FAIL_REG, &data);
107                 if((data & 0x1f) == 0) {
108                         /* all power restored */
109                         printk(KERN_NOTICE "VOYAGER AC power restored, cancelling shutdown\n");
110                         /* FIXME: should be user configureable */
111                         execute("umask 600; echo O > /etc/powerstatus; kill -PWR 1");
112                         set_timeout = 0;
113                 }
114         }
115 }
116
117 static void
118 wakeup(unsigned long unused)
119 {
120         up(&kvoyagerd_sem);
121 }
122
123 static int
124 thread(void *unused)
125 {
126         struct timer_list wakeup_timer;
127
128         kvoyagerd_running = 1;
129
130         reparent_to_init();
131         daemonize(THREAD_NAME);
132
133         set_timeout = 0;
134
135         init_timer(&wakeup_timer);
136
137         sigfillset(&current->blocked);
138         current->signal->tty = NULL;
139
140         printk(KERN_NOTICE "Voyager starting monitor thread\n");
141
142         for(;;) {
143                 down_interruptible(&kvoyagerd_sem);
144                 VDEBUG(("Voyager Daemon awoken\n"));
145                 if(voyager_status.request_from_kernel == 0) {
146                         /* probably awoken from timeout */
147                         check_continuing_condition();
148                 } else {
149                         check_from_kernel();
150                         voyager_status.request_from_kernel = 0;
151                 }
152                 if(set_timeout) {
153                         del_timer(&wakeup_timer);
154                         wakeup_timer.expires = HZ + jiffies;
155                         wakeup_timer.function = wakeup;
156                         add_timer(&wakeup_timer);
157                 }
158         }
159 }
160
161 static void __exit
162 voyager_thread_stop(void)
163 {
164         /* FIXME: do nothing at the moment */
165 }
166
167 module_init(voyager_thread_start);
168 //module_exit(voyager_thread_stop);