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