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 #if 0 // mask by Victor Yu. 05-15-2006
\r
52 static spinlock_t swtdlock=SPIN_LOCK_UNLOCKED;
\r
54 static int opencounts=0;
\r
55 static int swtduserenabled=0;
\r
56 static unsigned long swtdtime=DEFAULT_WATCHDOG_TIME;
\r
57 static struct timer_list swtdtimer;
\r
58 static struct work_struct rebootqueue;
\r
60 static void swtd_enable(void)
\r
62 *(unsigned int *)(CPE_WATCHDOG_VA_BASE+4) = WATCHDOG_COUNTER(swtdtime+WATCHDOG_TOL_COUNT_TIME);
\r
63 *(unsigned int *)(CPE_WATCHDOG_VA_BASE+8) = 0x5ab9;
\r
64 *(unsigned int *)(CPE_WATCHDOG_VA_BASE+12) = 0x03;
\r
67 static void swtd_disable(void)
\r
69 *(unsigned int *)(CPE_WATCHDOG_VA_BASE+12) = 0;
\r
72 #define IOCTL_WATCHDOG_ENABLE 1 // enable watch dog and set time (unint msec)
\r
73 #define IOCTL_WATCHDOG_DISABLE 2 // disable watch dog, kernle do it
\r
74 #define IOCTL_WATCHDOG_GET_SETTING 3 // get now setting about mode and time
\r
75 #define IOCTL_WATCHDOG_ACK 4 // to ack watch dog
\r
76 struct swtd_set_struct {
\r
80 static int swtd_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg)
\r
83 struct swtd_set_struct nowset;
\r
84 unsigned long flags;
\r
87 case IOCTL_WATCHDOG_ENABLE :
\r
88 if ( copy_from_user(&time, (void *)arg, sizeof(time)) )
\r
90 if ( time < WATCHDOG_MIN_TIME || time > WATCHDOG_MAX_TIME )
\r
92 #if 0 // mask by Victor Yu. 05-15-2006
\r
93 spin_lock(&swtdlock);
\r
94 del_timer(&swtdtimer);
\r
97 swtduserenabled = 1;
\r
98 swtdtimer.expires = jiffies + WATCHDOG_JIFFIES(swtdtime);
\r
99 add_timer(&swtdtimer);
\r
101 spin_unlock(&swtdlock);
\r
102 #else // add by Victor Yu. 05-15-2006
\r
105 if ( swtduserenabled ) {
\r
107 del_timer(&swtdtimer);
\r
110 swtduserenabled = 1;
\r
111 swtdtimer.expires = jiffies + WATCHDOG_JIFFIES(swtdtime);
\r
112 add_timer(&swtdtimer);
\r
114 restore_flags(flags);
\r
117 case IOCTL_WATCHDOG_DISABLE :
\r
118 #if 0 // mask by Victor Yu. 05-15-2006
\r
119 spin_lock(&swtdlock);
\r
120 if ( swtduserenabled ) {
\r
122 del_timer(&swtdtimer);
\r
123 swtduserenabled = 0;
\r
124 swtdtime = DEFAULT_WATCHDOG_TIME;
\r
125 swtdtimer.expires = jiffies + WATCHDOG_JIFFIES(swtdtime);
\r
126 add_timer(&swtdtimer);
\r
129 spin_unlock(&swtdlock);
\r
130 #else // add by Victor Yu. 05-15-2006
\r
133 if ( swtduserenabled ) {
\r
135 del_timer(&swtdtimer);
\r
136 swtduserenabled = 0;
\r
138 restore_flags(flags);
\r
141 case IOCTL_WATCHDOG_GET_SETTING :
\r
142 nowset.mode = swtduserenabled;
\r
143 nowset.time = swtdtime;
\r
144 if ( copy_to_user((void *)arg, &nowset, sizeof(nowset)) )
\r
147 case IOCTL_WATCHDOG_ACK :
\r
148 #if 0 // mask by Victor Yu. 05-15-2006
\r
149 spin_lock(&swtdlock);
\r
150 if ( swtduserenabled ) {
\r
152 del_timer(&swtdtimer);
\r
153 swtdtimer.expires = jiffies + WATCHDOG_JIFFIES(swtdtime);
\r
154 add_timer(&swtdtimer);
\r
157 spin_unlock(&swtdlock);
\r
158 #else // add by Victor Yu. 05-15-2006
\r
161 if ( swtduserenabled ) {
\r
163 del_timer(&swtdtimer);
\r
164 swtdtimer.expires = jiffies + WATCHDOG_JIFFIES(swtdtime);
\r
165 add_timer(&swtdtimer);
\r
168 restore_flags(flags);
\r
177 static int swtd_open(struct inode *inode, struct file *file)
\r
179 unsigned long flags;
\r
181 if ( MINOR(inode->i_rdev) != MOXA_WATCHDOG_MINOR )
\r
183 #if 0 // mask by Victor Yu. 05-15-2006
\r
184 spin_lock(&swtdlock);
\r
186 spin_unlock(&swtdlock);
\r
187 #else // add by Victor Yu. 05-15-2006
\r
190 #if 0 // mask by Victor Yu. 05-15-2006
\r
191 if ( swtduserenabled == 0 ) {
\r
192 swtduserenabled = 1;
\r
193 swtdtimer.expires = jiffies + WATCHDOG_JIFFIES(swtdtime);
\r
194 add_timer(&swtdtimer);
\r
199 restore_flags(flags);
\r
204 static int swtd_release(struct inode *inode, struct file *file)
\r
206 unsigned long flags;
\r
208 #if 0 // mask by Victor Yu. 05-15-2006
\r
209 spin_lock(&swtdlock);
\r
210 #else // add by Victor Yu. 05-15-2006
\r
214 dbg_printk("swtd_release entry.\n");
\r
216 if ( opencounts <= 0 ) {
\r
217 #if 0 // mask by Victor Yu. 02-23-2006
\r
218 if ( signal_pending(current) ) {
\r
219 dbg_printk("swtd_release has signal pending\n");
\r
220 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
221 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
222 if ( sigismember(¤t->parent->blocked, SIGKILL) ) {
\r
223 dbg_printk("swtd_release get SIGKILL signal\n");
\r
224 goto swtd_release_l1;
\r
226 if ( sigismember(¤t->blocked, SIGKILL) ) {
\r
227 dbg_printk("swtd_release get SIGKILL signal\n");
\r
228 goto swtd_release_l1;
\r
230 if ( sigismember(¤t->parent->blocked, SIGCHLD) ) {
\r
231 dbg_printk("swtd_release get SIGCHLD signal\n");
\r
232 goto swtd_release_l1;
\r
234 if ( sigismember(¤t->blocked, SIGCHLD) ) {
\r
235 dbg_printk("swtd_release get SIGCHLD signal\n");
\r
236 goto swtd_release_l1;
\r
238 if ( sigismember(¤t->parent->blocked, SIGTERM) ) {
\r
239 dbg_printk("swtd_release get SIGTERM signal\n");
\r
240 goto swtd_release_l1;
\r
242 if ( sigismember(¤t->blocked, SIGTERM) ) {
\r
243 dbg_printk("swtd_release get SIGTERM signal\n");
\r
244 goto swtd_release_l1;
\r
246 if ( sigismember(¤t->parent->blocked, SIGINT) ) {
\r
247 dbg_printk("swtd_release get SIGINT signal\n");
\r
248 goto swtd_release_l1;
\r
250 if ( sigismember(¤t->blocked, SIGINT) ) {
\r
251 dbg_printk("swtd_release get SIGINT signal\n");
\r
252 goto swtd_release_l1;
\r
254 #ifdef VICTOR_DEBUG // add by Victor Yu. 02-23-2006
\r
255 if ( sigismember(¤t->parent->blocked, SIGSTOP) ) {
\r
256 dbg_printk("swtd_release get SIGSTOP signal\n");
\r
258 if ( sigismember(¤t->parent->blocked, SIGHUP) ) {
\r
259 dbg_printk("swtd_release get SIGHUP signal\n");
\r
261 if ( sigismember(¤t->parent->blocked, SIGQUIT) ) {
\r
262 dbg_printk("swtd_release get SIGQUIT signal\n");
\r
264 if ( sigismember(¤t->parent->blocked, SIGTSTP) ) {
\r
265 dbg_printk("swtd_release get SIGTSTP signal\n");
\r
267 if ( sigismember(¤t->parent->blocked, SIGABRT) ) {
\r
268 dbg_printk("swtd_release get SIGABRT signal\n");
\r
270 if ( sigismember(¤t->parent->blocked, SIGSEGV) ) {
\r
271 dbg_printk("swtd_release get SIGSEGV signal\n");
\r
274 } else { // normal close the file handle
\r
277 if ( swtduserenabled ) {
\r
279 del_timer(&swtdtimer);
\r
280 swtduserenabled = 0;
\r
281 #if 0 // mask by Victor Yu. 05-15-2006
\r
282 swtdtime = DEFAULT_WATCHDOG_TIME;
\r
283 swtdtimer.expires = jiffies + WATCHDOG_JIFFIES(swtdtime);
\r
284 add_timer(&swtdtimer);
\r
288 #if 0 // mask by Victor Yu. 02-23-2006
\r
293 #if 0 // mask by Victor Yu. 05-15-1006
\r
294 spin_unlock(&swtdlock);
\r
295 #else // add by Victor Yu. 05-15-2006
\r
296 restore_flags(flags);
\r
301 static void swtd_reboot(void *unused)
\r
303 char *argv[2], *envp[5];
\r
305 if ( in_interrupt() )
\r
307 if ( !current->fs->root )
\r
309 argv[0] = "/sbin/reboot";
\r
311 envp[0] = "HOME=/";
\r
312 envp[1] = "PATH=/sbin:/bin:/usr/sbin:/usr/bin";
\r
314 call_usermodehelper(argv[0], argv, envp, 0);
\r
317 static void swtd_poll(unsigned long ignore)
\r
319 unsigned long flags;
\r
321 #if 0 // mask by Victor Yu. 05-15-2006
\r
322 spin_lock(&swtdlock);
\r
323 #else // add by Victor Yu. 05-15-2006
\r
328 del_timer(&swtdtimer);
\r
329 #if 0 // mask by Victor Yu. 05-15-2006
\r
330 if ( swtduserenabled ) {
\r
331 dbg_printk("Now reboot the system.\n");
\r
332 schedule_work(&rebootqueue);
\r
334 swtdtimer.expires = jiffies + WATCHDOG_JIFFIES(swtdtime);
\r
335 add_timer(&swtdtimer);
\r
338 spin_unlock(&swtdlock);
\r
339 #else // add by Victor Yu. 05-15-2006
\r
340 dbg_printk("Now reboot the system.\n");
\r
341 schedule_work(&rebootqueue);
\r
342 restore_flags(flags);
\r
346 static int swtd_proc_output(char *buf)
\r
352 "user enable\t: %d\n"
\r
353 "ack time\t: %d msec\n",
\r
354 swtduserenabled, (int)swtdtime);
\r
358 static int swtd_read_proc(char *page, char **start, off_t off, int count, int *eof, void *data)
\r
360 int len=swtd_proc_output(page);
\r
362 if ( len <= off + count )
\r
364 *start = page + off;
\r
373 static struct file_operations swtd_fops = {
\r
378 release:swtd_release,
\r
380 static struct miscdevice swtd_dev = {
\r
381 MOXA_WATCHDOG_MINOR,
\r
386 static void __exit moxa_swtd_exit(void)
\r
388 unsigned long flags;
\r
390 #if 0 // mask by Victor Yu. 05-15-2006
\r
391 spin_lock(&swtdlock);
\r
392 #else // add by Victor Yu. 05-15-2006
\r
396 if ( swtduserenabled ) {
\r
398 del_timer(&swtdtimer);
\r
399 swtduserenabled = 0;
\r
402 #if 0 // mask by Victor Yu. 05-15-2006
\r
403 spin_unlock(&swtdlock);
\r
404 #else // add by Victor Yu. 05-15-2006
\r
405 restore_flags(flags);
\r
407 misc_deregister(&swtd_dev);
\r
410 static int __init moxa_swtd_init(void)
\r
413 if ( misc_register(&swtd_dev) ) {
\r
414 printk("Moxa ART CPU WatchDog: Register misc fail !\n");
\r
415 goto moxa_swtd_init_err;
\r
417 INIT_WORK(&rebootqueue, swtd_reboot, NULL);
\r
418 #if 0 // mask by Victor Yu. 05-15-2006
\r
419 spin_lock(&swtdlock);
\r
421 init_timer(&swtdtimer);
\r
422 swtdtimer.function = swtd_poll;
\r
423 #if 0 // mask by Victor Yu. 05-15-2006
\r
424 swtdtimer.expires = jiffies + WATCHDOG_JIFFIES(swtdtime);
\r
425 add_timer(&swtdtimer);
\r
427 spin_unlock(&swtdlock);
\r
429 create_proc_read_entry("driver/swtd", 0, 0, swtd_read_proc, NULL);
\r
430 printk("Moxa ART CPU WatchDog driver v" MOXA_WATCHDOG_VERSION "\n");
\r
434 moxa_swtd_init_err:
\r
435 misc_deregister(&swtd_dev);
\r
439 module_init(moxa_swtd_init);
\r
440 module_exit(moxa_swtd_exit);
\r
442 MODULE_AUTHOR("Victor Yu");
\r
443 MODULE_LICENSE("GPL");
\r