2 * This is Moxa UC7000 watch dog driver for CV case.
\r
5 * Date Aurhor Comment
\r
6 * 09-15-2004 Victor Yu. Create it. I name it sWatchDog
\r
7 * 06-10-2005 Jared Wu. Fix the watch dog devic driver bug. kernel_thread() is a system call cannot be invoke in timer timeout interrupt. I move it to the moxa_swtd_init()
\r
8 * 06-18-2009 Wade Liang Change to interrupt mode for flash problem
\r
10 #define __KERNEL_SYSCALLS__
\r
11 #include <linux/config.h>
\r
12 #include <linux/proc_fs.h> /* Necessary because we use the proc fs */
\r
13 #include <linux/version.h>
\r
14 #include <linux/unistd.h>
\r
15 #include <linux/string.h>
\r
16 #include <linux/ctype.h>
\r
17 #include <linux/module.h>
\r
18 #include <linux/kernel.h>
\r
19 #include <linux/miscdevice.h>
\r
20 #include <linux/fcntl.h>
\r
21 #include <linux/init.h>
\r
22 #include <linux/poll.h>
\r
23 #include <linux/spinlock.h>
\r
24 #include <linux/delay.h>
\r
25 #include <linux/timer.h>
\r
26 #include <linux/ioport.h>
\r
27 #include <linux/interrupt.h>
\r
28 #include <linux/sched.h>
\r
29 #include <linux/signal.h>
\r
30 #include <linux/mm.h>
\r
32 #include <asm/uaccess.h>
\r
33 #include <asm/system.h>
\r
34 #include <asm/irq.h>
\r
35 #include <asm/bitops.h>
\r
36 #include <linux/reboot.h>
\r
37 #include <asm/types.h>
\r
38 #include <linux/notifier.h>
\r
39 #if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,0)
\r
40 #include <linux/workqueue.h>
\r
43 #define CONFIG_ARCH_MOXACPU // define for IA-24X/W3X1/W3X5 serials
\r
46 #include "x86_moxa_swtd.h"
\r
47 #elif defined (CONFIG_CPU_IXP43X) || defined (ARCH_IXDP425) || defined (ARCH_IXDP422)
\r
48 #include "ixp43x_moxa_swtd.h"
\r
49 #elif defined(CONFIG_ARCH_MOXACPU)
\r
50 #include "moxaart_moxa_swtd.h"
\r
51 #elif defined(CONFIG_MACH_MOXA_IA261) || defined(CONFIG_MACH_MOXA_W406)
\r
52 #include "ep93xx_moxa_swtd.h"
\r
54 #ifndef WATCHDOG_NOWAYOUT
\r
55 #define WATCHDOG_NOWAYOUT 0
\r
58 static struct proc_dir_entry *swtd_proc_file;
\r
59 static int opencounts=0;
\r
60 static int swtduserenabled=0;
\r
61 static unsigned long swtdtime=DEFAULT_WATCHDOG_TIME;
\r
62 static struct timer_list timer_swtd;
\r
63 static int bswtd_timeout = 0;
\r
64 static int nowayout = WATCHDOG_NOWAYOUT;
\r
65 static int debug = 0;
\r
66 static char expect_close;
\r
67 static spinlock_t swtd_lock=SPIN_LOCK_UNLOCKED;
\r
68 static int irq_res=-1;
\r
69 static unsigned long flags=0;
\r
70 #if defined(CONFIG_MACH_MOXA_IA261)||defined(CONFIG_MACH_MOXA_W406)
\r
71 static int pollcnt=0;
\r
73 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,0)
\r
74 static wait_queue_head_t swtd_queue;
\r
77 // add by Jared Wu. 03-10-2009 Ack the watchdog instead of disable it.
\r
78 // this means that if the kernel crashed, the hardware watchdog will
\r
80 static void swtd_ack(unsigned long swtd_ack_time)
\r
83 printk("<1>swtd_ack: swtd_time=%lu\n",swtd_ack_time);
\r
84 #ifndef __WDT_TEST__
\r
86 superio_enter_config();
\r
87 superio_set_logic_device(8); //logic device 8
\r
88 superio_set_reg((swtd_ack_time/1000), 0xF6); //Reg:F6,30 sec
\r
89 #elif defined (CONFIG_CPU_IXP43X) || defined (ARCH_IXDP425)
\r
90 *IXP4XX_OSWK = IXP4XX_WDT_KEY;
\r
92 *IXP4XX_OSWT = WATCHDOG_COUNTER(swtd_ack_time);
\r
93 *IXP4XX_OSWE = IXP4XX_WDT_COUNT_ENABLE | IXP4XX_WDT_RESET_ENABLE;
\r
95 #elif defined (ARCH_IXDP422)
\r
96 *IXP425_OSWK = 0x482e;
\r
98 *IXP425_OSWT = WATCHDOG_COUNTER(swtd_ack_time);
\r
99 *IXP425_OSWE = IXP4XX_WDOG_CNT_ENA | IXP4XX_WDOG_RST_ENA;
\r
101 #elif defined(CONFIG_ARCH_MOXACPU)
\r
102 *(unsigned int *)(CPE_WATCHDOG_VA_BASE+4) = WATCHDOG_COUNTER(swtd_ack_time);
\r
103 *(unsigned int *)(CPE_WATCHDOG_VA_BASE+8) = 0x5ab9;
\r
104 /* Change to interrupt mode 0x05, reset mode is 0x03*/
\r
105 *(unsigned int *)(CPE_WATCHDOG_VA_BASE+12) = 0x05;
\r
106 #elif defined(CONFIG_MACH_MOXA_IA261)||defined(CONFIG_MACH_MOXA_W406)
\r
112 static void swtd_enable(void)
\r
115 printk("swtd_enable: swtdtime=%lu\n",swtdtime+WATCHDOG_DEFER_TIME);
\r
116 #ifndef __WDT_TEST__
\r
117 #if defined (DA68X)
\r
118 superio_enter_config();
\r
119 superio_set_logic_device(8); //logic device 8
\r
120 superio_set_reg(1, 0x30); //Reg:30 active WDT
\r
121 superio_set_reg(0, 0xF5); //Reg:F5
\r
122 superio_set_reg(0, 0xF7); //Reg:F7
\r
123 superio_set_reg((swtdtime+WATCHDOG_DEFER_TIME)/1000, 0xF6); //Reg:F6,30 sec
\r
124 #elif defined (CONFIG_CPU_IXP43X) || defined (ARCH_IXDP425)
\r
125 *IXP4XX_OSWK = IXP4XX_WDT_KEY;
\r
126 *IXP4XX_OSWE = 0x0;
\r
127 *IXP4XX_OSWT = WATCHDOG_COUNTER(swtdtime+WATCHDOG_DEFER_TIME);
\r
128 *IXP4XX_OSWE = IXP4XX_WDT_COUNT_ENABLE | IXP4XX_WDT_RESET_ENABLE;
\r
130 #elif defined (ARCH_IXDP422)
\r
131 *IXP425_OSWK = 0x482e;
\r
132 *IXP425_OSWE = 0x0;
\r
133 *IXP425_OSWT = WATCHDOG_COUNTER(swtdtime+WATCHDOG_DEFER_TIME);
\r
134 //*IXP425_OSWE = IXP4XX_WDOG_CNT_ENA | IXP4XX_WDOG_INT_ENA | IXP4XX_WDOG_RST_ENA ;
\r
135 *IXP425_OSWE = IXP4XX_WDOG_CNT_ENA | IXP4XX_WDOG_RST_ENA ;
\r
137 #elif defined(CONFIG_ARCH_MOXACPU)
\r
138 *(unsigned int *)(CPE_WATCHDOG_VA_BASE+4) = WATCHDOG_COUNTER(swtdtime+WATCHDOG_DEFER_TIME);
\r
139 *(unsigned int *)(CPE_WATCHDOG_VA_BASE+8) = 0x5ab9;
\r
140 *(unsigned int *)(CPE_WATCHDOG_VA_BASE+12) = 0x03;
\r
141 #elif defined(CONFIG_MACH_MOXA_IA261)||defined(CONFIG_MACH_MOXA_W406)
\r
142 __raw_writew(0x5555, EP93XX_WATCHDOG_BASE); // reset watchdog counter
\r
143 __raw_writew(0xaaaa, EP93XX_WATCHDOG_BASE); // enable watchdog
\r
148 static void swtd_disable(void)
\r
151 printk("swtd_disable\n");
\r
152 #ifndef __WDT_TEST__
\r
153 #if defined (DA68X)
\r
154 superio_enter_config();
\r
155 superio_set_logic_device(8); //logic device 8
\r
156 superio_set_reg(0, 0xF6); //Reg:F6 counter register
\r
157 #elif defined (CONFIG_CPU_IXP43X) || defined (ARCH_IXDP425)
\r
158 *IXP4XX_OSWK = IXP4XX_WDT_KEY;
\r
161 #elif defined (ARCH_IXDP422)
\r
162 *IXP425_OSWK = 0x482e;
\r
165 #elif defined(CONFIG_ARCH_MOXACPU)
\r
166 *(unsigned int *)(CPE_WATCHDOG_VA_BASE+12) = 0;
\r
167 #elif defined(CONFIG_MACH_MOXA_IA261)||defined(CONFIG_MACH_MOXA_W406)
\r
168 __raw_writew(0xaa55, EP93XX_WATCHDOG_BASE);
\r
173 #if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,0)
\r
174 static void swtd_reboot(void *unused)
\r
176 char *argv[2], *envp[5];
\r
178 if ( in_interrupt() )
\r
180 if ( !current->fs->root )
\r
183 argv[0] = "/bin/reboot";
\r
186 argv[0] = "/sbin/reboot";
\r
188 envp[0] = "HOME=/";
\r
189 envp[1] = "PATH=/sbin:/bin:/usr/sbin:/usr/bin";
\r
191 call_usermodehelper(argv[0], argv, envp, 0);
\r
194 static char *argv_init[2]={"reboot", NULL};
\r
195 static char *envp_init[3]={"HOME=/", "TERM=linux", NULL};
\r
197 static int swtd_reboot(void *unused)
\r
199 interruptible_sleep_on(&swtd_queue);
\r
200 printk("<1>exec reboot.\n");
\r
201 execve("/sbin/reboot", argv_init, envp_init);
\r
206 #if defined (DA68X) || defined (ARCH_IXDP425) || defined(CONFIG_ARCH_MOXACPU)
\r
207 DECLARE_WORK(rebootqueue, swtd_reboot, NULL);
\r
208 #elif defined (CONFIG_CPU_IXP43X) || defined(CONFIG_MACH_MOXA_IA261) || defined(CONFIG_MACH_MOXA_W406)
\r
209 DECLARE_WORK(rebootqueue, swtd_reboot);
\r
212 static void swtd_poll(unsigned long ignore)
\r
214 spin_lock(&swtd_lock);
\r
215 #if defined(CONFIG_MACH_MOXA_IA261)||defined(CONFIG_MACH_MOXA_W406)
\r
216 if ( pollcnt++ <= (swtdtime/WATCHDOG_ACK_JIFFIES) ) {
\r
217 timer_swtd.expires = jiffies + WATCHDOG_ACK_JIFFIES;
\r
218 add_timer(&timer_swtd);
\r
220 spin_unlock(&swtd_lock);
\r
225 printk("<1>swtd_poll: Now reboot the system.\n");
\r
226 #ifndef __WDT_TEST__
\r
227 schedule_work(&rebootqueue);
\r
230 #else // (CONFIG_CPU_IXP43X) || defined(CONFIG_MACH_MOXA_IA261) || defined(CONFIG_MACH_MOXA_W406) || defined(CONFIG_ARCH_MOXACPU)
\r
232 if ( swtduserenabled ) {
\r
233 swtd_ack(WATCHDOG_DEFER_TIME);
\r
235 printk("<1>swtd_poll: Now reboot the system.\n");
\r
236 #ifndef __WDT_TEST__
\r
237 #if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,0)
\r
238 schedule_work(&rebootqueue);
\r
240 /* Jared said, awake any swtd_reboot kernel thread */
\r
241 wake_up_interruptible(&swtd_queue);
\r
249 printk("swtd_poll: ack the hardware watchdog timer\n");
\r
250 /* 1-17-2005 Jared said, if disable the watchdog,
\r
251 * it would not reboot while the system is very busy
\r
253 timer_swtd.expires = jiffies +WATCHDOG_ACK_JIFFIES(swtdtime);
\r
254 add_timer(&timer_swtd);
\r
255 swtd_ack(swtdtime+WATCHDOG_DEFER_TIME);
\r
258 spin_unlock(&swtd_lock);
\r
261 ssize_t moxaswtd_proc_read(char *buffer,char **buffer_location,off_t offset, int buffer_length, int *eof, void *data)
\r
263 int len=0; /* The number of bytes actually used */
\r
269 //Fill the buffer and get its length
\r
270 len += sprintf(buffer+len,
\r
271 "user enable\t: %d\n"
\r
272 "ack time\t: %d msec\n"
\r
273 #if defined (DA68X)
\r
274 "hardware watchdog counter\t: %d sec\n"
\r
276 ,swtduserenabled, (int)swtdtime
\r
277 #if defined (DA68X)
\r
278 ,superio_get_reg(0xF6)
\r
285 static int swtd_open(struct inode *inode, struct file *file)
\r
287 if ( MINOR(inode->i_rdev) != MOXA_WATCHDOG_MINOR )
\r
290 spin_lock_irq(&swtd_lock);
\r
291 #if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,0)
\r
293 __module_get(THIS_MODULE);
\r
295 bswtd_timeout = 0; // reset the timeout flag
\r
297 spin_unlock_irq(&swtd_lock);
\r
302 // Kernel ack the watchdog timer and reset the state machine
\r
303 static void swtd_release_timer(void) {
\r
304 swtdtime = DEFAULT_WATCHDOG_TIME;
\r
305 #if defined(CONFIG_MACH_MOXA_IA261)||defined(CONFIG_MACH_MOXA_W406)
\r
307 del_timer(&timer_swtd);
\r
309 mod_timer(&timer_swtd, jiffies + WATCHDOG_ACK_JIFFIES(swtdtime));
\r
310 swtd_ack(swtdtime+WATCHDOG_DEFER_TIME);
\r
312 swtduserenabled = 0;
\r
313 bswtd_timeout = 0; // reset the timeout flag
\r
317 static int swtd_release(struct inode *inode, struct file *file)
\r
319 #if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,0)
\r
320 sigset_t *sigset = ¤t->signal->shared_pending.signal;
\r
322 sigset_t *sigset = ¤t->pending.signal;
\r
325 spin_lock_irq(&swtd_lock);
\r
328 printk("<1>swtd_release entry\n");
\r
331 if ( opencounts <= 0 ) {
\r
333 * Shut off the timer.
\r
335 if (expect_close == 42) {
\r
336 printk("<1>swtd_release: expect close\n");
\r
337 if ( !bswtd_timeout ) {
\r
338 swtd_release_timer();
\r
341 else if ( signal_pending(current) ) {
\r
343 printk("<1>swtd_release[%d] has signal pending\n",__LINE__);
\r
344 if ( sigismember (sigset, SIGKILL) || \
\r
345 sigismember (sigset, SIGINT) || \
\r
346 sigismember (sigset, SIGTERM) ) {
\r
348 printk("<1>swtd_release[%d] get SIGKILL/SIGINT/SIGTERM signal\n",__LINE__);
\r
349 #if 1 // For Taitung, 03-30-2009 should comment out this line
\r
350 if ( !bswtd_timeout ) {
\r
351 swtd_release_timer();
\r
355 #if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,0)
\r
356 } else if ( current->signal->group_exit_code == SIGQUIT || \
\r
357 current->signal->group_exit_code == SIGILL || \
\r
358 current->signal->group_exit_code == SIGABRT || \
\r
359 current->signal->group_exit_code == SIGFPE || \
\r
360 current->signal->group_exit_code == SIGSEGV ) {
\r
362 printk("<1>swtd_release[%d] got coredump\n",__LINE__);
\r
365 } else if ( sigismember (sigset, SIGILL) || \
\r
366 sigismember (sigset, SIGABRT) || \
\r
367 sigismember (sigset, SIGFPE) || \
\r
368 sigismember (sigset, SIGSEGV) ) {
\r
370 printk("<1>swtd_release[%d] got coredump\n",__LINE__);
\r
373 else { // normal close the file handle
\r
375 printk("<1>swtd_release_l1[%d] kernel ack the watchdog timer\n",__LINE__);
\r
376 if ( !bswtd_timeout ) {
\r
377 #if 1 // For Taitung, 03-30-2009 should comment out this line
\r
378 swtd_release_timer();
\r
384 spin_unlock_irq(&swtd_lock);
\r
389 static int swtd_ioctl (struct inode *inode, struct file *file, unsigned int ioc_cmd, unsigned long arg)
\r
391 unsigned long time;
\r
392 struct swtd_set_struct nowset;
\r
394 switch ( ioc_cmd ) {
\r
395 case IOCTL_WATCHDOG_ENABLE :
\r
396 if ( copy_from_user(&time, (unsigned long *)arg, sizeof(unsigned long)) )
\r
398 if ( time < WATCHDOG_MIN_TIME || time > WATCHDOG_MAX_TIME )
\r
400 spin_lock_irq(&swtd_lock);
\r
401 if ( !bswtd_timeout ) {
\r
402 // Switch to user mode watchdog.
\r
403 // When the kernel timer timeout, the system will reboot
\r
404 swtduserenabled = 1;
\r
406 #if defined(CONFIG_MACH_MOXA_IA261)||defined(CONFIG_MACH_MOXA_W406)
\r
409 if(timer_pending(&timer_swtd))
\r
410 mod_timer(&timer_swtd, jiffies + WATCHDOG_ACK_JIFFIES);
\r
412 add_timer(&timer_swtd);
\r
414 mod_timer(&timer_swtd, jiffies + WATCHDOG_ACK_JIFFIES(swtdtime));
\r
415 swtd_ack(swtdtime+WATCHDOG_DEFER_TIME);
\r
418 spin_unlock_irq(&swtd_lock);
\r
420 case IOCTL_WATCHDOG_DISABLE :
\r
421 spin_lock_irq(&swtd_lock);
\r
422 if ( swtduserenabled && !bswtd_timeout ) {
\r
423 #if defined(CONFIG_MACH_MOXA_IA261)||defined(CONFIG_MACH_MOXA_W406)
\r
426 del_timer(&timer_swtd);
\r
428 // Switch to kernel mode watchdog.
\r
429 // The kernel timer will acknowledge the HW watchdog
\r
431 mod_timer(&timer_swtd, jiffies + WATCHDOG_ACK_JIFFIES(swtdtime));
\r
433 swtdtime = DEFAULT_WATCHDOG_TIME;
\r
434 bswtd_timeout = 0; // reset the timeout flag
\r
435 swtduserenabled = 0;
\r
437 spin_unlock_irq(&swtd_lock);
\r
439 case IOCTL_WATCHDOG_GET_SETTING :
\r
440 nowset.mode = swtduserenabled;
\r
441 nowset.time = swtdtime;
\r
442 if ( copy_to_user((void *)arg, &nowset, sizeof(nowset)) )
\r
445 case IOCTL_WATCHDOG_ACK :
\r
446 spin_lock_irq(&swtd_lock);
\r
447 if ( swtduserenabled && !bswtd_timeout ) {
\r
448 #if defined(CONFIG_MACH_MOXA_IA261)||defined(CONFIG_MACH_MOXA_W406)
\r
451 mod_timer(&timer_swtd, jiffies + WATCHDOG_ACK_JIFFIES);
\r
453 // Switch to user mode watchdog.
\r
454 // When the kernel timer timeout, the system will reboot
\r
455 mod_timer(&timer_swtd, jiffies + WATCHDOG_ACK_JIFFIES(swtdtime));
\r
456 swtd_ack(swtdtime+WATCHDOG_DEFER_TIME);
\r
459 spin_unlock_irq(&swtd_lock);
\r
470 * @file: file handle to the watchdog
\r
471 * @buf: buffer to write (unused as data does not matter here
\r
472 * @count: count of bytes
\r
473 * @ppos: pointer to the position to write. No seeks allowed
\r
475 * A write to a watchdog device is defined as a keepalive signal. Any
\r
476 * write of data will do, as we we don't define content meaning.
\r
479 static ssize_t swtd_write(struct file *file, const char *buf, \
\r
480 size_t count, loff_t *ppos)
\r
488 /* In case it was set long ago */
\r
489 #if 0 // Comment out by Jared 2009-05-11, don't reset the expect_close flag
\r
492 for (i = 0; i != count; i++)
\r
495 if (get_user(c, buf + i))
\r
502 /* someone wrote to us, we should restart timer */
\r
503 spin_lock_irq(&swtd_lock);
\r
504 if ( !bswtd_timeout ) {
\r
505 // Switch to user mode watchdog.
\r
506 // When the kernel timer timeout, the system will reboot
\r
507 swtduserenabled = 1;
\r
508 #if defined(CONFIG_MACH_MOXA_IA261)||defined(CONFIG_MACH_MOXA_W406)
\r
510 mod_timer(&timer_swtd, jiffies + WATCHDOG_ACK_JIFFIES);
\r
513 mod_timer(&timer_swtd, jiffies + WATCHDOG_ACK_JIFFIES(swtdtime));
\r
514 swtd_ack(swtdtime+WATCHDOG_DEFER_TIME);
\r
517 spin_unlock_irq(&swtd_lock);
\r
523 /* IRQ handler: for hw watchdog and system reboot will call */
\r
524 static irqreturn_t swtd_interrupt_handler(int irq, void *dev_id, struct pt_regs *regs)
\r
527 local_irq_save(flags);
\r
529 printk("swtd_interrupt_handler: enter\n");
\r
531 /* Reset flash state */
\r
532 *( volatile u16 *)(CPE_FLASH_VA_BASE+0x55*2) = 0xb0;//Suspend block erase
\r
533 *( volatile u16 *)(CPE_FLASH_VA_BASE+0x55*2) = 0xff;//Change to read array mode
\r
535 /* Call hardware reboot */
\r
536 *(unsigned int *)(CPE_WATCHDOG_VA_BASE+4) = 1;
\r
537 *(unsigned int *)(CPE_WATCHDOG_VA_BASE+8) = 0x5ab9;
\r
538 *(unsigned int *)(CPE_WATCHDOG_VA_BASE+12) = 0x03;
\r
542 local_irq_restore(flags);
\r
543 return IRQ_HANDLED;
\r
548 static int swtd_panic_handler(struct notifier_block *this,
\r
549 unsigned long event,
\r
552 /* Avoid the software interrupt of swtd_ack */
\r
553 spin_lock_bh(&swtd_lock);
\r
555 if (debug) printk("swtd_panic_handler: enter\n");
\r
557 /* Reset flash state */
\r
558 if (debug) printk("swtd_panic_handler: reset flash state\n");
\r
559 *( volatile u16 *)(CPE_FLASH_VA_BASE+0x55*2) = 0xb0;//Suspend block erase
\r
560 *( volatile u16 *)(CPE_FLASH_VA_BASE+0x55*2) = 0xff;//Change to read array mode
\r
562 /* Call hardware reboot */
\r
563 if (debug) printk("swtd_panic_handler: call hardware rebooot\n");
\r
564 *(unsigned int *)(CPE_WATCHDOG_VA_BASE+4) = 1;
\r
565 *(unsigned int *)(CPE_WATCHDOG_VA_BASE+8) = 0x5ab9;
\r
566 *(unsigned int *)(CPE_WATCHDOG_VA_BASE+12) = 0x03;
\r
571 spin_unlock_bh(&swtd_lock);
\r
574 /* Structure for notification */
\r
575 static struct notifier_block swtd_panic_notifier = {
\r
576 swtd_panic_handler,
\r
578 150 /* priority: INT_MAX >= x >= 0 */
\r
581 static struct file_operations moxa_swtd_fops = {
\r
582 .owner=THIS_MODULE,
\r
586 .release=swtd_release,
\r
589 static struct miscdevice wdt_miscdev = {
\r
590 .minor = MOXA_WATCHDOG_MINOR,
\r
592 .fops = &moxa_swtd_fops,
\r
595 static int __init moxaswtd_init(void) {
\r
597 /* Register misc */
\r
598 if ( misc_register(&wdt_miscdev)!=0 ) {
\r
599 printk("Moxa DA-681/662-LX WatchDog: Register misc fail !\n");
\r
600 goto moxa_swtd_init_err1;
\r
603 /* Register IRQ handler */
\r
604 irq_res= request_irq(IRQ_WATCHDOG, swtd_interrupt_handler,
\r
605 SA_INTERRUPT,"swtd_irq",
\r
608 printk( KERN_EMERG "swtd: can't get assigned irq %i\n", IRQ_WATCHDOG);
\r
612 /* Resister panic handler */
\r
613 notifier_chain_register(&panic_notifier_list, &swtd_panic_notifier);
\r
616 init_timer(&timer_swtd);
\r
617 timer_swtd.function=swtd_poll;
\r
618 #if defined(CONFIG_MACH_MOXA_IA261)||defined(CONFIG_MACH_MOXA_W406)
\r
619 timer_swtd.expires = jiffies + WATCHDOG_ACK_JIFFIES;
\r
621 timer_swtd.expires = jiffies + WATCHDOG_ACK_JIFFIES(swtdtime);
\r
622 add_timer(&timer_swtd);
\r
626 /* Create proc file */
\r
627 swtd_proc_file = create_proc_read_entry("driver/swtd", 0644, NULL, moxaswtd_proc_read, NULL);
\r
628 if ( !swtd_proc_file ) {
\r
629 printk("<1>moxaswtd_init:create_proc_read_entry() fail\n");
\r
630 goto moxa_swtd_init_err2;
\r
633 #if defined (DA68X)
\r
634 struct resource *base_res;
\r
636 base_res = request_region(SUPERIO_CONFIG_PORT, 2, "swtd");
\r
638 printk("<1>moxaswtd_init: can't get I/O address 0x%x\n", SUPERIO_CONFIG_PORT);
\r
639 goto moxa_swtd_init_err3;
\r
643 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,0)
\r
644 init_waitqueue_head (&swtd_queue);
\r
645 kernel_thread(swtd_reboot, NULL, CLONE_FS | CLONE_FILES | CLONE_SIGNAL);
\r
648 printk (KERN_INFO "initialized. (nowayout=%d)\n", nowayout);
\r
649 printk (KERN_INFO "initialized. (debug=%d)\n", debug);
\r
653 #if defined (DA68X)
\r
654 moxa_swtd_init_err3:
\r
655 remove_proc_entry("driver/swtd", NULL);
\r
657 moxa_swtd_init_err2:
\r
658 if(timer_pending(&timer_swtd))
\r
659 del_timer(&timer_swtd);
\r
660 misc_deregister(&wdt_miscdev);
\r
661 moxa_swtd_init_err1:
\r
665 static void __exit moxaswtd_exit(void) {
\r
667 #if defined (DA68X)
\r
668 release_region(SUPERIO_CONFIG_PORT, 2);
\r
669 superio_exit_config();
\r
671 remove_proc_entry("driver/swtd", NULL);
\r
673 if(timer_pending(&timer_swtd))
\r
674 del_timer(&timer_swtd);
\r
675 if ( swtduserenabled ) {
\r
676 swtduserenabled = 0;
\r
679 misc_deregister(&wdt_miscdev);
\r
682 free_irq(IRQ_WATCHDOG, NULL);
\r
684 /* Free panic hander */
\r
685 notifier_chain_unregister(&panic_notifier_list, &swtd_panic_notifier);
\r
689 module_init(moxaswtd_init);
\r
690 module_exit(moxaswtd_exit);
\r
692 MODULE_AUTHOR("Jared_Wu@moxa.com.tw");
\r
693 MODULE_LICENSE("GPL");
\r
694 #if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,0)
\r
695 module_param(nowayout, int, 0);
\r
697 MODULE_PARM(nowayout, "i");
\r
699 MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default=CONFIG_WATCHDOG_NOWAYOUT)");
\r
700 #if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,0)
\r
701 module_param(debug, int, 0);
\r
703 MODULE_PARM(debug, "i");
\r
705 MODULE_PARM_DESC(debug, "print the debug message in this driver");
\r