3 * Date Aurhor Comment
\r
4 * 02-23-2006 Victor Yu. Create it.
\r
6 //#define __KERNEL_SYSCALLS__
\r
7 #include <linux/config.h>
\r
8 #include <linux/proc_fs.h>
\r
9 #include <linux/devfs_fs_kernel.h>
\r
10 #include <linux/unistd.h>
\r
11 #include <linux/string.h>
\r
12 #include <linux/ctype.h>
\r
13 #include <linux/module.h>
\r
14 #include <linux/kernel.h>
\r
15 #include <linux/miscdevice.h>
\r
16 #include <linux/fcntl.h>
\r
17 #include <linux/init.h>
\r
18 #include <linux/poll.h>
\r
19 #include <linux/spinlock.h>
\r
20 #include <linux/delay.h>
\r
21 #include <linux/timer.h>
\r
22 #include <linux/ioport.h>
\r
23 #include <linux/interrupt.h>
\r
24 #include <linux/sched.h>
\r
25 #include <linux/signal.h>
\r
26 #include <linux/mm.h>
\r
27 #include <linux/kmod.h>
\r
29 #include <asm/uaccess.h>
\r
30 #include <asm/system.h>
\r
31 #include <asm/irq.h>
\r
32 #include <asm/bitops.h>
\r
34 //#define VICTOR_DEBUG
\r
36 #define dbg_printk(x...) printk(x)
\r
38 #define dbg_printk(x...)
\r
41 #define MOXA_WATCHDOG_VERSION "1.0"
\r
42 #define MOXA_WATCHDOG_MINOR 106
\r
43 #define DEFAULT_WATCHDOG_TIME (30UL*1000UL) // 30 seconds
\r
44 #define WATCHDOG_MIN_TIME 50UL // 50 msec
\r
45 #define WATCHDOG_MAX_TIME (60UL*1000UL) // 60 seconds
\r
46 #define WATCHDOG_TOL_TIME (500UL) // 500 msec, for watchdog timer polling
\r
47 #define WATCHDOG_TOL_COUNT_TIME (1000UL) // 1 seconds, for watchdog timer count
\r
48 #define WATCHDOG_COUNTER(x) ((APB_CLK/1000UL)*(x))
\r
49 #define WATCHDOG_JIFFIES(x) ((((x)+WATCHDOG_TOL_TIME)*HZ)/1000UL)
\r
51 static spinlock_t swtdlock=SPIN_LOCK_UNLOCKED;
\r
52 static int opencounts=0;
\r
53 static int swtduserenabled=0;
\r
54 static unsigned long swtdtime=DEFAULT_WATCHDOG_TIME;
\r
55 static struct timer_list swtdtimer;
\r
56 static struct work_struct rebootqueue;
\r
58 static void swtd_enable(void)
\r
60 *(unsigned int *)(CPE_WATCHDOG_VA_BASE+4) = WATCHDOG_COUNTER(swtdtime+WATCHDOG_TOL_COUNT_TIME);
\r
61 *(unsigned int *)(CPE_WATCHDOG_VA_BASE+8) = 0x5ab9;
\r
62 *(unsigned int *)(CPE_WATCHDOG_VA_BASE+12) = 0x03;
\r
65 static void swtd_disable(void)
\r
67 *(unsigned int *)(CPE_WATCHDOG_VA_BASE+12) = 0;
\r
70 #define IOCTL_WATCHDOG_ENABLE 1 // enable watch dog and set time (unint msec)
\r
71 #define IOCTL_WATCHDOG_DISABLE 2 // disable watch dog, kernle do it
\r
72 #define IOCTL_WATCHDOG_GET_SETTING 3 // get now setting about mode and time
\r
73 #define IOCTL_WATCHDOG_ACK 4 // to ack watch dog
\r
74 struct swtd_set_struct {
\r
78 static int swtd_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg)
\r
81 struct swtd_set_struct nowset;
\r
84 case IOCTL_WATCHDOG_ENABLE :
\r
85 if ( copy_from_user(&time, (void *)arg, sizeof(time)) )
\r
87 if ( time < WATCHDOG_MIN_TIME || time > WATCHDOG_MAX_TIME )
\r
89 spin_lock(&swtdlock);
\r
91 del_timer(&swtdtimer);
\r
93 swtduserenabled = 1;
\r
94 swtdtimer.expires = jiffies + WATCHDOG_JIFFIES(swtdtime);
\r
95 add_timer(&swtdtimer);
\r
97 spin_unlock(&swtdlock);
\r
99 case IOCTL_WATCHDOG_DISABLE :
\r
100 spin_lock(&swtdlock);
\r
101 if ( swtduserenabled ) {
\r
103 del_timer(&swtdtimer);
\r
104 swtduserenabled = 0;
\r
105 swtdtime = DEFAULT_WATCHDOG_TIME;
\r
106 swtdtimer.expires = jiffies + WATCHDOG_JIFFIES(swtdtime);
\r
107 add_timer(&swtdtimer);
\r
110 spin_unlock(&swtdlock);
\r
112 case IOCTL_WATCHDOG_GET_SETTING :
\r
113 nowset.mode = swtduserenabled;
\r
114 nowset.time = swtdtime;
\r
115 if ( copy_to_user((void *)arg, &nowset, sizeof(nowset)) )
\r
118 case IOCTL_WATCHDOG_ACK :
\r
119 spin_lock(&swtdlock);
\r
120 if ( swtduserenabled ) {
\r
122 del_timer(&swtdtimer);
\r
123 swtdtimer.expires = jiffies + WATCHDOG_JIFFIES(swtdtime);
\r
124 add_timer(&swtdtimer);
\r
127 spin_unlock(&swtdlock);
\r
135 static int swtd_open(struct inode *inode, struct file *file)
\r
137 if ( MINOR(inode->i_rdev) != MOXA_WATCHDOG_MINOR )
\r
139 spin_lock(&swtdlock);
\r
141 spin_unlock(&swtdlock);
\r
145 static int swtd_release(struct inode *inode, struct file *file)
\r
147 spin_lock(&swtdlock);
\r
148 dbg_printk("swtd_release entry.\n");
\r
150 if ( opencounts <= 0 ) {
\r
151 #if 0 // mask by Victor Yu. 02-23-2006
\r
152 if ( signal_pending(current) ) {
\r
153 dbg_printk("swtd_release has signal pending\n");
\r
154 dbg_printk("parent signal blocked=0x%x,0x%x, pending=0x%x,0x%x\n", current->parent->blocked.sig[0], current->parent->blocked.sig[1], current->parent->pending.signal.sig[0], current->parent->pending.signal.sig[1]);
\r
155 dbg_printk("signal blocked=0x%x,0x%x, pending=0x%x,0x%x\n", current->blocked.sig[0], current->blocked.sig[1], current->pending.signal.sig[0], current->pending.signal.sig[1]);
\r
156 if ( sigismember(¤t->parent->blocked, SIGKILL) ) {
\r
157 dbg_printk("swtd_release get SIGKILL signal\n");
\r
158 goto swtd_release_l1;
\r
160 if ( sigismember(¤t->blocked, SIGKILL) ) {
\r
161 dbg_printk("swtd_release get SIGKILL signal\n");
\r
162 goto swtd_release_l1;
\r
164 if ( sigismember(¤t->parent->blocked, SIGCHLD) ) {
\r
165 dbg_printk("swtd_release get SIGCHLD signal\n");
\r
166 goto swtd_release_l1;
\r
168 if ( sigismember(¤t->blocked, SIGCHLD) ) {
\r
169 dbg_printk("swtd_release get SIGCHLD signal\n");
\r
170 goto swtd_release_l1;
\r
172 if ( sigismember(¤t->parent->blocked, SIGTERM) ) {
\r
173 dbg_printk("swtd_release get SIGTERM signal\n");
\r
174 goto swtd_release_l1;
\r
176 if ( sigismember(¤t->blocked, SIGTERM) ) {
\r
177 dbg_printk("swtd_release get SIGTERM signal\n");
\r
178 goto swtd_release_l1;
\r
180 if ( sigismember(¤t->parent->blocked, SIGINT) ) {
\r
181 dbg_printk("swtd_release get SIGINT signal\n");
\r
182 goto swtd_release_l1;
\r
184 if ( sigismember(¤t->blocked, SIGINT) ) {
\r
185 dbg_printk("swtd_release get SIGINT signal\n");
\r
186 goto swtd_release_l1;
\r
188 #ifdef VICTOR_DEBUG // add by Victor Yu. 02-23-2006
\r
189 if ( sigismember(¤t->parent->blocked, SIGSTOP) ) {
\r
190 dbg_printk("swtd_release get SIGSTOP signal\n");
\r
192 if ( sigismember(¤t->parent->blocked, SIGHUP) ) {
\r
193 dbg_printk("swtd_release get SIGHUP signal\n");
\r
195 if ( sigismember(¤t->parent->blocked, SIGQUIT) ) {
\r
196 dbg_printk("swtd_release get SIGQUIT signal\n");
\r
198 if ( sigismember(¤t->parent->blocked, SIGTSTP) ) {
\r
199 dbg_printk("swtd_release get SIGTSTP signal\n");
\r
201 if ( sigismember(¤t->parent->blocked, SIGABRT) ) {
\r
202 dbg_printk("swtd_release get SIGABRT signal\n");
\r
204 if ( sigismember(¤t->parent->blocked, SIGSEGV) ) {
\r
205 dbg_printk("swtd_release get SIGSEGV signal\n");
\r
208 } else { // normal close the file handle
\r
211 if ( swtduserenabled ) {
\r
213 del_timer(&swtdtimer);
\r
214 swtduserenabled = 0;
\r
215 swtdtime = DEFAULT_WATCHDOG_TIME;
\r
216 swtdtimer.expires = jiffies + WATCHDOG_JIFFIES(swtdtime);
\r
217 add_timer(&swtdtimer);
\r
220 #if 0 // mask by Victor Yu. 02-23-2006
\r
225 spin_unlock(&swtdlock);
\r
229 static void swtd_reboot(void *unused)
\r
231 char *argv[2], *envp[5];
\r
233 if ( in_interrupt() )
\r
235 if ( !current->fs->root )
\r
237 argv[0] = "/sbin/reboot";
\r
239 envp[0] = "HOME=/";
\r
240 envp[1] = "PATH=/sbin:/bin:/usr/sbin:/usr/bin";
\r
242 call_usermodehelper(argv[0], argv, envp, 0);
\r
245 #define VICTOR_TEMP_CODE
\r
246 static void swtd_poll(unsigned long ignore)
\r
248 spin_lock(&swtdlock);
\r
249 #ifndef VICTOR_TEMP_CODE
\r
252 del_timer(&swtdtimer);
\r
253 if ( swtduserenabled ) {
\r
254 dbg_printk("Now reboot the system.\n");
\r
255 schedule_work(&rebootqueue);
\r
257 #ifdef VICTOR_TEMP_CODE
\r
260 swtdtimer.expires = jiffies + WATCHDOG_JIFFIES(swtdtime);
\r
261 add_timer(&swtdtimer);
\r
264 spin_unlock(&swtdlock);
\r
267 static int swtd_proc_output(char *buf)
\r
273 "user enable\t: %d\n"
\r
274 "ack time\t: %d msec\n",
\r
275 swtduserenabled, (int)swtdtime);
\r
279 static int swtd_read_proc(char *page, char **start, off_t off, int count, int *eof, void *data)
\r
281 int len=swtd_proc_output(page);
\r
283 if ( len <= off + count )
\r
285 *start = page + off;
\r
294 static struct file_operations swtd_fops = {
\r
299 release:swtd_release,
\r
301 static struct miscdevice swtd_dev = {
\r
302 MOXA_WATCHDOG_MINOR,
\r
307 static void __exit moxa_swtd_exit(void)
\r
309 spin_lock(&swtdlock);
\r
311 del_timer(&swtdtimer);
\r
312 spin_unlock(&swtdlock);
\r
313 misc_deregister(&swtd_dev);
\r
316 static int __init moxa_swtd_init(void)
\r
319 if ( misc_register(&swtd_dev) ) {
\r
320 printk("Moxa ART CPU WatchDog: Register misc fail !\n");
\r
321 goto moxa_swtd_init_err;
\r
323 *(volatile unsigned int *)(CPE_PMU_VA_BASE + 0x10) |= 0x20;
\r
324 INIT_WORK(&rebootqueue, swtd_reboot, NULL);
\r
325 spin_lock(&swtdlock);
\r
326 init_timer(&swtdtimer);
\r
327 swtdtimer.function = swtd_poll;
\r
328 swtdtimer.expires = jiffies + WATCHDOG_JIFFIES(swtdtime);
\r
329 add_timer(&swtdtimer);
\r
331 spin_unlock(&swtdlock);
\r
332 create_proc_read_entry("driver/swtd", 0, 0, swtd_read_proc, NULL);
\r
333 printk("Moxa ART CPU WatchDog driver v" MOXA_WATCHDOG_VERSION "\n");
\r
337 moxa_swtd_init_err:
\r
338 misc_deregister(&swtd_dev);
\r
342 module_init(moxa_swtd_init);
\r
343 module_exit(moxa_swtd_exit);
\r
345 MODULE_AUTHOR("Victor Yu");
\r
346 MODULE_LICENSE("GPL");
\r