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-jared
blob64eb2ed1e1b8b19d9d0095f2c509645388eda123
1 /*\r
2  * This is Moxa UC7000 watch dog driver for CV case.\r
3  *\r
4  * History:\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  */\r
9 #define __KERNEL_SYSCALLS__\r
10 #include <linux/config.h>\r
11 #include <linux/proc_fs.h> /* Necessary because we use the proc fs */\r
12 #include <linux/version.h>\r
13 #include <linux/unistd.h>\r
14 #include <linux/string.h>\r
15 #include <linux/ctype.h>\r
16 #include <linux/module.h>\r
17 #include <linux/kernel.h>\r
18 #include <linux/miscdevice.h>\r
19 #include <linux/fcntl.h>\r
20 #include <linux/init.h>\r
21 #include <linux/poll.h>\r
22 #include <linux/spinlock.h>\r
23 #include <linux/delay.h>\r
24 #include <linux/timer.h>\r
25 #include <linux/ioport.h>\r
26 #include <linux/interrupt.h>\r
27 #include <linux/sched.h>\r
28 #include <linux/signal.h>\r
29 #include <linux/mm.h>\r
30 #include <asm/io.h>\r
31 #include <asm/uaccess.h>\r
32 #include <asm/system.h>\r
33 #include <asm/irq.h>\r
34 #include <asm/bitops.h>\r
35 #include <linux/reboot.h>\r
36 #if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,0)\r
37 #include <linux/workqueue.h>\r
38 #endif\r
40 #define CONFIG_ARCH_MOXACPU  // define for IA-24X/W3X1/W3X5 serials\r
42 #if defined (DA68X)\r
43 #include "x86_moxa_swtd.h"\r
44 #elif defined (CONFIG_CPU_IXP43X) || defined (ARCH_IXDP425) || defined (ARCH_IXDP422)\r
45 #include "ixp43x_moxa_swtd.h"\r
46 #elif defined(CONFIG_ARCH_MOXACPU)\r
47 #include "moxaart_moxa_swtd.h"\r
48 #elif defined(CONFIG_MACH_MOXA_IA261) || defined(CONFIG_MACH_MOXA_W406)\r
49 #include "ep93xx_moxa_swtd.h"\r
50 #endif\r
51 #ifndef WATCHDOG_NOWAYOUT\r
52 #define WATCHDOG_NOWAYOUT 0\r
53 #endif\r
55 static struct proc_dir_entry *swtd_proc_file;\r
56 static int                      opencounts=0;\r
57 static int                      swtduserenabled=0;\r
58 static unsigned long            swtdtime=DEFAULT_WATCHDOG_TIME;\r
59 static struct timer_list        timer_swtd;\r
60 static int                      bswtd_timeout = 0;\r
61 static int                      nowayout = WATCHDOG_NOWAYOUT;\r
62 static int                      debug = 0;\r
63 static char                     expect_close;\r
64 static spinlock_t               swtd_lock=SPIN_LOCK_UNLOCKED;\r
65 #if defined(CONFIG_MACH_MOXA_IA261)||defined(CONFIG_MACH_MOXA_W406)\r
66 static int                      pollcnt=0;\r
67 #endif\r
68 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,0)\r
69 static wait_queue_head_t swtd_queue; \r
70 #endif\r
72 // add by Jared Wu. 03-10-2009 Ack the watchdog instead of disable it.\r
73 // this means that if the kernel crashed, the hardware watchdog will\r
74 // reset in 15 sec.\r
75 static void swtd_ack(unsigned long swtd_ack_time)\r
76 {\r
77         if (debug)\r
78                 printk("<1>swtd_ack: swtd_time=%lu\n",swtd_ack_time);\r
79 #ifndef __WDT_TEST__\r
80 #if defined (DA68X)\r
81         superio_enter_config();\r
82         superio_set_logic_device(8);    //logic device 8\r
83         superio_set_reg((swtd_ack_time/1000), 0xF6);    //Reg:F6,30 sec\r
84 #elif defined (CONFIG_CPU_IXP43X) || defined (ARCH_IXDP425)\r
85         *IXP4XX_OSWK = IXP4XX_WDT_KEY;\r
86         *IXP4XX_OSWE = 0x0;\r
87         *IXP4XX_OSWT = WATCHDOG_COUNTER(swtd_ack_time);\r
88         *IXP4XX_OSWE = IXP4XX_WDT_COUNT_ENABLE | IXP4XX_WDT_RESET_ENABLE;\r
89         *IXP4XX_OSWK = 0;\r
90 #elif defined (ARCH_IXDP422)\r
91         *IXP425_OSWK = 0x482e;\r
92         *IXP425_OSWE = 0x0;\r
93         *IXP425_OSWT = WATCHDOG_COUNTER(swtd_ack_time);\r
94         *IXP425_OSWE = IXP4XX_WDOG_CNT_ENA | IXP4XX_WDOG_RST_ENA;\r
95         *IXP425_OSWK = 0;\r
96 #elif defined(CONFIG_ARCH_MOXACPU)\r
97         *(unsigned int *)(CPE_WATCHDOG_VA_BASE+4) = WATCHDOG_COUNTER(swtd_ack_time);\r
98         *(unsigned int *)(CPE_WATCHDOG_VA_BASE+8) = 0x5ab9;\r
99         *(unsigned int *)(CPE_WATCHDOG_VA_BASE+12) = 0x03;\r
100 #elif defined(CONFIG_MACH_MOXA_IA261)||defined(CONFIG_MACH_MOXA_W406)\r
101         // Not used\r
102 #endif\r
103 #endif\r
106 static void swtd_enable(void)\r
108         if (debug)\r
109                 printk("swtd_enable: swtdtime=%lu\n",swtdtime);\r
110 #ifndef __WDT_TEST__\r
111 #if defined (DA68X)\r
112         superio_enter_config();\r
113         superio_set_logic_device(8);    //logic device 8\r
114         superio_set_reg(1, 0x30);       //Reg:30 active WDT\r
115         superio_set_reg(0, 0xF5);       //Reg:F5\r
116         superio_set_reg(0, 0xF7);       //Reg:F7\r
117         superio_set_reg((swtdtime+WATCHDOG_DEFER_TIME)/1000, 0xF6);     //Reg:F6,30 sec\r
118 #elif defined (CONFIG_CPU_IXP43X) || defined (ARCH_IXDP425)\r
119         *IXP4XX_OSWK = IXP4XX_WDT_KEY;\r
120         *IXP4XX_OSWE = 0x0;\r
121         *IXP4XX_OSWT = WATCHDOG_COUNTER(swtdtime+WATCHDOG_DEFER_TIME);\r
122         *IXP4XX_OSWE = IXP4XX_WDT_COUNT_ENABLE | IXP4XX_WDT_RESET_ENABLE;\r
123         *IXP4XX_OSWK = 0;\r
124 #elif defined (ARCH_IXDP422)\r
125         *IXP425_OSWK = 0x482e;\r
126         *IXP425_OSWE = 0x0;\r
127         *IXP425_OSWT = WATCHDOG_COUNTER(swtdtime+WATCHDOG_DEFER_TIME);\r
128         //*IXP425_OSWE = IXP4XX_WDOG_CNT_ENA | IXP4XX_WDOG_INT_ENA | IXP4XX_WDOG_RST_ENA ;\r
129         *IXP425_OSWE = IXP4XX_WDOG_CNT_ENA | IXP4XX_WDOG_RST_ENA ;\r
130         *IXP425_OSWK = 0;\r
131 #elif defined(CONFIG_ARCH_MOXACPU)\r
132         *(unsigned int *)(CPE_WATCHDOG_VA_BASE+4) = WATCHDOG_COUNTER(swtdtime+WATCHDOG_DEFER_TIME);\r
133         *(unsigned int *)(CPE_WATCHDOG_VA_BASE+8) = 0x5ab9;\r
134         *(unsigned int *)(CPE_WATCHDOG_VA_BASE+12) = 0x03;\r
135 #elif defined(CONFIG_MACH_MOXA_IA261)||defined(CONFIG_MACH_MOXA_W406)\r
136         __raw_writew(0x5555, EP93XX_WATCHDOG_BASE);     // reset watchdog counter\r
137         __raw_writew(0xaaaa, EP93XX_WATCHDOG_BASE);     // enable watchdog\r
138 #endif\r
139 #endif\r
142 static void swtd_disable(void)\r
144         if (debug)\r
145                 printk("swtd_disable\n");\r
146 #ifndef __WDT_TEST__\r
147 #if defined (DA68X)\r
148         superio_enter_config();\r
149         superio_set_logic_device(8);    //logic device 8\r
150         superio_set_reg(0, 0xF6);       //Reg:F6 counter register\r
151 #elif defined (CONFIG_CPU_IXP43X) || defined (ARCH_IXDP425)\r
152         *IXP4XX_OSWK = IXP4XX_WDT_KEY;\r
153         *IXP4XX_OSWE = 0;\r
154         *IXP4XX_OSWK = 0;\r
155 #elif defined (ARCH_IXDP422)\r
156         *IXP425_OSWK = 0x482e;\r
157         *IXP425_OSWE = 0;\r
158         *IXP425_OSWK = 0;\r
159 #elif defined(CONFIG_ARCH_MOXACPU)\r
160         *(unsigned int *)(CPE_WATCHDOG_VA_BASE+12) = 0;\r
161 #elif defined(CONFIG_MACH_MOXA_IA261)||defined(CONFIG_MACH_MOXA_W406)\r
162         __raw_writew(0xaa55, EP93XX_WATCHDOG_BASE);\r
163 #endif\r
164 #endif\r
167 #if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,0)\r
168 static void swtd_reboot(void *unused)\r
170         char    *argv[2], *envp[5];\r
172         if ( in_interrupt() )\r
173                 return;\r
174         if ( !current->fs->root )\r
175                 return;\r
176 /*\r
177         argv[0] = "/bin/reboot";\r
178         argv[1] = 0;\r
179 */\r
180         argv[0] = "/sbin/reboot";\r
181         argv[1] = 0;\r
182         envp[0] = "HOME=/";\r
183         envp[1] = "PATH=/sbin:/bin:/usr/sbin:/usr/bin";\r
184         envp[2] = 0;\r
185         call_usermodehelper(argv[0], argv, envp, 0);\r
187 #else\r
188 static char     *argv_init[2]={"reboot", NULL};\r
189 static char     *envp_init[3]={"HOME=/", "TERM=linux", NULL};\r
191 static int swtd_reboot(void *unused)\r
193         interruptible_sleep_on(&swtd_queue);\r
194         printk("<1>exec reboot.\n");\r
195         execve("/sbin/reboot", argv_init, envp_init);\r
196         return 0;\r
198 #endif\r
200 #if defined (DA68X) || defined (ARCH_IXDP425) || defined(CONFIG_ARCH_MOXACPU)\r
201 DECLARE_WORK(rebootqueue, swtd_reboot, NULL);\r
202 #elif defined (CONFIG_CPU_IXP43X) || defined(CONFIG_MACH_MOXA_IA261) || defined(CONFIG_MACH_MOXA_W406)\r
203 DECLARE_WORK(rebootqueue, swtd_reboot);\r
204 #endif\r
206 static void swtd_poll(unsigned long ignore)\r
208         spin_lock(&swtd_lock);\r
209 #if defined(CONFIG_MACH_MOXA_IA261)||defined(CONFIG_MACH_MOXA_W406)\r
210         if ( pollcnt++ <= (swtdtime/WATCHDOG_ACK_JIFFIES) ) {\r
211                 timer_swtd.expires = jiffies + WATCHDOG_ACK_JIFFIES;\r
212                 add_timer(&timer_swtd);\r
213                 swtd_enable();\r
214                 spin_unlock(&swtd_lock);\r
215                 return ;\r
216         }\r
217         swtd_enable();\r
218         if (debug)\r
219                 printk("<1>swtd_poll: Now reboot the system.\n");\r
220         #ifndef __WDT_TEST__\r
221         schedule_work(&rebootqueue);\r
222         #endif\r
223         bswtd_timeout = 1;\r
224 #else  // (CONFIG_CPU_IXP43X) || defined(CONFIG_MACH_MOXA_IA261) || defined(CONFIG_MACH_MOXA_W406) || defined(CONFIG_ARCH_MOXACPU)\r
226         if ( swtduserenabled ) {\r
227                 swtd_ack(WATCHDOG_DEFER_TIME);\r
228                 if (debug)\r
229                         printk("<1>swtd_poll: Now reboot the system.\n");\r
230         #ifndef __WDT_TEST__\r
231                 #if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,0)\r
232                 schedule_work(&rebootqueue);\r
233                 #else\r
234                 /* Jared said, awake any swtd_reboot kernel thread */\r
235                 wake_up_interruptible(&swtd_queue);\r
236                 #endif\r
237         #endif\r
238                 bswtd_timeout = 1;\r
239         }\r
240         else\r
241         {\r
242                 if (debug)\r
243                         printk("swtd_poll: ack the hardware watchdog timer\n");\r
244         /* 1-17-2005 Jared said, if disable the watchdog, \r
245          * it would not reboot while the system is very busy \r
246          */\r
247                 timer_swtd.expires = jiffies +WATCHDOG_ACK_JIFFIES(swtdtime);\r
248                 add_timer(&timer_swtd);\r
249                 swtd_ack(swtdtime+WATCHDOG_DEFER_TIME);\r
250         }\r
251 #endif\r
252         spin_unlock(&swtd_lock);\r
255 ssize_t moxaswtd_proc_read(char *buffer,char **buffer_location,off_t offset, int buffer_length, int *eof, void *data)\r
257     int len=0; /* The number of bytes actually used */\r
258             \r
259     if (offset > 0) {\r
260       len =0;\r
261     }\r
262     else {\r
263         //Fill the buffer and get its length\r
264       len += sprintf(buffer+len,\r
265              "user enable\t: %d\n"\r
266              "ack time\t: %d msec\n"\r
267 #if defined (DA68X)\r
268              "hardware watchdog counter\t: %d sec\n"\r
269 #endif\r
270              ,swtduserenabled, (int)swtdtime \r
271 #if defined (DA68X)\r
272              ,superio_get_reg(0xF6)\r
273 #endif\r
274              );\r
275     }\r
276     return len;\r
279 static int swtd_open(struct inode *inode, struct file *file)\r
281         if ( MINOR(inode->i_rdev) != MOXA_WATCHDOG_MINOR )\r
282                 return -ENODEV;\r
283         \r
284         spin_lock_irq(&swtd_lock);\r
285 #if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,0)\r
286         if (nowayout)\r
287                 __module_get(THIS_MODULE);\r
288 #endif\r
289         bswtd_timeout = 0; // reset the timeout flag\r
290         opencounts++;\r
291         spin_unlock_irq(&swtd_lock);\r
293         return 0;\r
296 // Kernel ack the watchdog timer and reset the state machine\r
297 static void swtd_release_timer() {\r
298         swtdtime = DEFAULT_WATCHDOG_TIME;\r
299 #if defined(CONFIG_MACH_MOXA_IA261)||defined(CONFIG_MACH_MOXA_W406)\r
300         swtd_disable();\r
301         del_timer(&timer_swtd);\r
302 #else\r
303         mod_timer(&timer_swtd, jiffies + WATCHDOG_ACK_JIFFIES(swtdtime));\r
304         swtd_ack(swtdtime+WATCHDOG_DEFER_TIME);\r
305 #endif\r
306         swtduserenabled = 0;\r
307         bswtd_timeout = 0; // reset the timeout flag\r
311 static int swtd_release(struct inode *inode, struct file *file)\r
313 #if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,0)\r
314         sigset_t *sigset = &current->signal->shared_pending.signal;\r
315 #else\r
316         sigset_t *sigset = &current->pending.signal;\r
317 #endif\r
319         spin_lock_irq(&swtd_lock);\r
321         if (debug)\r
322                 printk("<1>swtd_release entry\n");\r
323         opencounts--;\r
325         if ( opencounts <= 0 ) {\r
326                 /*\r
327                  *      Shut off the timer.\r
328                  */\r
329                 if (expect_close == 42) {\r
330                         printk("<1>swtd_release: expect close\n");\r
331                         if ( !bswtd_timeout  ) {\r
332                                 swtd_release_timer();\r
333                         }\r
334                 }\r
335                 else if ( signal_pending(current) ) {\r
336                         if (debug)\r
337                                 printk("<1>swtd_release[%d] has signal pending\n",__LINE__);\r
338                         if ( sigismember (sigset, SIGKILL) || \\r
339                             sigismember (sigset, SIGINT) || \\r
340                             sigismember (sigset, SIGTERM) ) {\r
341                                 if (debug)\r
342                                         printk("<1>swtd_release[%d] get SIGKILL/SIGINT/SIGTERM signal\n",__LINE__);\r
343 #if 1 // For Taitung, 03-30-2009 should comment out this line\r
344                                 if ( !bswtd_timeout  ) {\r
345                                         swtd_release_timer();\r
346                                 }\r
347 #endif\r
348                         }\r
349 #if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,0)\r
350                 } else if ( current->signal->group_exit_code == SIGQUIT || \\r
351                         current->signal->group_exit_code == SIGILL || \\r
352                         current->signal->group_exit_code == SIGABRT || \\r
353                         current->signal->group_exit_code == SIGFPE || \\r
354                         current->signal->group_exit_code == SIGSEGV ) {\r
355                         if (debug)\r
356                                 printk("<1>swtd_release[%d] got coredump\n",__LINE__);\r
357                 }\r
358 #else\r
359                 } else if ( sigismember (sigset, SIGILL) || \\r
360                             sigismember (sigset, SIGABRT) || \\r
361                             sigismember (sigset, SIGFPE) || \\r
362                             sigismember (sigset, SIGSEGV) ) {\r
363                             if (debug)\r
364                                 printk("<1>swtd_release[%d] got coredump\n",__LINE__);\r
365                         }\r
366 #endif\r
367                 else {  // normal close the file handle\r
368                         if (debug)\r
369                                 printk("<1>swtd_release_l1[%d] kernel ack the watchdog timer\n",__LINE__);\r
370                         if ( !bswtd_timeout  ) {\r
371 #if 1 // For Taitung, 03-30-2009 should comment out this line\r
372                                 swtd_release_timer();\r
373 #endif\r
374                         }\r
375                 }\r
376                 expect_close = 0;\r
377         }\r
378         spin_unlock_irq(&swtd_lock);\r
380         return 0;\r
383 static int swtd_ioctl (struct inode *inode, struct file *file, unsigned int ioc_cmd, unsigned long arg)\r
385         unsigned long           time;\r
386         struct swtd_set_struct  nowset;\r
388         switch ( ioc_cmd ) {\r
389         case IOCTL_WATCHDOG_ENABLE :\r
390                 if ( copy_from_user(&time, (unsigned long *)arg, sizeof(unsigned long)) )\r
391                         return -EFAULT;\r
392                 if ( time < WATCHDOG_MIN_TIME || time > WATCHDOG_MAX_TIME )\r
393                         return -EINVAL;\r
394                 spin_lock_irq(&swtd_lock);\r
395                 if ( !bswtd_timeout ) {\r
396                         // Switch to user mode watchdog.\r
397                         // When the kernel timer timeout, the system will reboot\r
398                         swtduserenabled = 1;\r
399                         swtdtime = time;\r
400 #if defined(CONFIG_MACH_MOXA_IA261)||defined(CONFIG_MACH_MOXA_W406)\r
401                         pollcnt = 0;\r
402                         swtd_enable();\r
403                         if(timer_pending(&timer_swtd))\r
404                                 mod_timer(&timer_swtd, jiffies + WATCHDOG_ACK_JIFFIES);\r
405                         else\r
406                                 add_timer(&timer_swtd);\r
407 #else\r
408                         mod_timer(&timer_swtd, jiffies + WATCHDOG_ACK_JIFFIES(swtdtime));\r
409                         swtd_ack(swtdtime+WATCHDOG_DEFER_TIME);\r
410 #endif\r
411                 }\r
412                 spin_unlock_irq(&swtd_lock);\r
413                 break;\r
414         case IOCTL_WATCHDOG_DISABLE :\r
415                 spin_lock_irq(&swtd_lock);\r
416                 if ( swtduserenabled && !bswtd_timeout ) {\r
417 #if defined(CONFIG_MACH_MOXA_IA261)||defined(CONFIG_MACH_MOXA_W406)\r
418                         pollcnt=0;\r
419                         swtd_disable();\r
420                         del_timer(&timer_swtd);\r
421 #else\r
422                         // Switch to kernel mode watchdog.\r
423                         // The kernel timer will acknowledge the HW watchdog\r
424                         swtd_enable();\r
425                         mod_timer(&timer_swtd, jiffies + WATCHDOG_ACK_JIFFIES(swtdtime));\r
426 #endif\r
427                         swtdtime = DEFAULT_WATCHDOG_TIME;\r
428                         bswtd_timeout = 0; // reset the timeout flag\r
429                         swtduserenabled = 0;\r
430                 }\r
431                 spin_unlock_irq(&swtd_lock);\r
432                 break;\r
433         case IOCTL_WATCHDOG_GET_SETTING :\r
434                 nowset.mode = swtduserenabled;\r
435                 nowset.time = swtdtime;\r
436                 if ( copy_to_user((void *)arg, &nowset, sizeof(nowset)) )\r
437                         return -EFAULT;\r
438                 break;\r
439         case IOCTL_WATCHDOG_ACK :\r
440                 spin_lock_irq(&swtd_lock);\r
441                 if ( swtduserenabled && !bswtd_timeout ) {\r
442 #if defined(CONFIG_MACH_MOXA_IA261)||defined(CONFIG_MACH_MOXA_W406)\r
443                         pollcnt=0;\r
444                         swtd_enable();\r
445                         mod_timer(&timer_swtd, jiffies + WATCHDOG_ACK_JIFFIES);\r
446 #else\r
447                         // Switch to user mode watchdog.\r
448                         // When the kernel timer timeout, the system will reboot\r
449                         mod_timer(&timer_swtd, jiffies + WATCHDOG_ACK_JIFFIES(swtdtime));\r
450                         swtd_ack(swtdtime+WATCHDOG_DEFER_TIME);\r
451 #endif\r
452                 }\r
453                 spin_unlock_irq(&swtd_lock);\r
455                 break;\r
456         default:\r
457                 return -EINVAL;\r
458         }\r
459         return 0;\r
462 /*\r
463  *      swtd_write:\r
464  *      @file: file handle to the watchdog\r
465  *      @buf: buffer to write (unused as data does not matter here\r
466  *      @count: count of bytes\r
467  *      @ppos: pointer to the position to write. No seeks allowed\r
468  *\r
469  *      A write to a watchdog device is defined as a keepalive signal. Any\r
470  *      write of data will do, as we we don't define content meaning.\r
471  */\r
473 static ssize_t swtd_write(struct file *file, const char *buf, \\r
474                             size_t count, loff_t *ppos)\r
476         if (count)\r
477         {\r
478                 if (!nowayout)\r
479                 {\r
480                         size_t i;\r
482                         /* In case it was set long ago */\r
483 #if 0 // Comment out by Jared 2009-05-11, don't reset the expect_close flag\r
484                         expect_close = 0;\r
485 #endif\r
486                         for (i = 0; i != count; i++)\r
487                         {\r
488                                 char c;\r
489                                 if (get_user(c, buf + i))\r
490                                         return -EFAULT;\r
491                                 if (c == 'V')\r
492                                         expect_close = 42;\r
493                         }\r
494                 }\r
496                 /* someone wrote to us, we should restart timer */\r
497                 spin_lock_irq(&swtd_lock);\r
498                 if ( !bswtd_timeout ) {\r
499                         // Switch to user mode watchdog.\r
500                         // When the kernel timer timeout, the system will reboot\r
501                         swtduserenabled = 1;\r
502 #if defined(CONFIG_MACH_MOXA_IA261)||defined(CONFIG_MACH_MOXA_W406)\r
503                         pollcnt=0;\r
504                         mod_timer(&timer_swtd, jiffies + WATCHDOG_ACK_JIFFIES);\r
505                         swtd_enable();\r
506 #else\r
507                         mod_timer(&timer_swtd, jiffies + WATCHDOG_ACK_JIFFIES(swtdtime));\r
508                         swtd_ack(swtdtime+WATCHDOG_DEFER_TIME);\r
509 #endif\r
510                 }\r
511                 spin_unlock_irq(&swtd_lock);\r
513         }\r
514         return count;\r
517 static struct file_operations moxa_swtd_fops = {\r
518         .owner=THIS_MODULE,\r
519         .open=swtd_open,\r
520         .write=swtd_write,\r
521         .ioctl=swtd_ioctl,\r
522         .release=swtd_release,\r
523 };\r
525 static struct miscdevice wdt_miscdev = {\r
526         .minor = MOXA_WATCHDOG_MINOR,\r
527         .name = "swtd",\r
528         .fops = &moxa_swtd_fops,\r
529 };\r
531 static int __init moxaswtd_init(void) {\r
532         // register misc\r
533         if ( misc_register(&wdt_miscdev)!=0 ) {\r
534                 printk("Moxa DA-681/662-LX WatchDog: Register misc fail !\n");\r
535                 goto moxa_swtd_init_err1;\r
536         }\r
538         init_timer(&timer_swtd);\r
539         timer_swtd.function=swtd_poll;\r
540 #if defined(CONFIG_MACH_MOXA_IA261)||defined(CONFIG_MACH_MOXA_W406)\r
541         timer_swtd.expires = jiffies + WATCHDOG_ACK_JIFFIES;\r
542 #else\r
543         timer_swtd.expires = jiffies + WATCHDOG_ACK_JIFFIES(swtdtime);\r
544         add_timer(&timer_swtd);\r
545         swtd_enable();\r
546 #endif\r
548         swtd_proc_file = create_proc_read_entry("driver/swtd", 0644, NULL, moxaswtd_proc_read, NULL);\r
549         if ( !swtd_proc_file ) {\r
550                 printk("<1>moxaswtd_init:create_proc_read_entry() fail\n");\r
551                 goto moxa_swtd_init_err2;\r
552         }\r
554 #if defined (DA68X)\r
555         struct resource *base_res;\r
557         base_res = request_region(SUPERIO_CONFIG_PORT, 2, "swtd");\r
558         if (!base_res) {\r
559                 printk("<1>moxaswtd_init: can't get I/O address 0x%x\n", SUPERIO_CONFIG_PORT);\r
560                 goto moxa_swtd_init_err3;\r
561         }\r
562 #endif\r
564 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,0)\r
565         init_waitqueue_head  (&swtd_queue);\r
566         kernel_thread(swtd_reboot, NULL, CLONE_FS | CLONE_FILES | CLONE_SIGNAL);\r
567 #endif\r
569         printk (KERN_INFO "initialized. (nowayout=%d)\n", nowayout);\r
570         printk (KERN_INFO "initialized. (debug=%d)\n", debug);\r
572         return 0;\r
574 #if defined (DA68X)\r
575 moxa_swtd_init_err3:\r
576         remove_proc_entry("driver/swtd", NULL);\r
577 #endif\r
578 moxa_swtd_init_err2:\r
579         if(timer_pending(&timer_swtd))\r
580                 del_timer(&timer_swtd);\r
581         misc_deregister(&wdt_miscdev);\r
582 moxa_swtd_init_err1:\r
583         return -ENOMEM;\r
586 static void __exit moxaswtd_exit(void) {\r
588 #if defined (DA68X)\r
589         release_region(SUPERIO_CONFIG_PORT, 2);\r
590         superio_exit_config();\r
591 #endif\r
592         remove_proc_entry("driver/swtd", NULL);\r
593         swtd_disable();\r
594         if(timer_pending(&timer_swtd))\r
595                 del_timer(&timer_swtd);\r
596         if ( swtduserenabled ) {\r
597                 swtduserenabled = 0;\r
598                 opencounts = 0;\r
599         }\r
600         misc_deregister(&wdt_miscdev);\r
603 module_init(moxaswtd_init);\r
604 module_exit(moxaswtd_exit);\r
606 MODULE_AUTHOR("Jared_Wu@moxa.com.tw");\r
607 MODULE_LICENSE("GPL");\r
608 #if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,0)\r
609 module_param(nowayout, int, 0);\r
610 #else\r
611 MODULE_PARM(nowayout, "i");\r
612 #endif\r
613 MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default=CONFIG_WATCHDOG_NOWAYOUT)");\r
614 #if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,0)\r
615 module_param(debug, int, 0);\r
616 #else\r
617 MODULE_PARM(debug, "i");\r
618 #endif\r
619 MODULE_PARM_DESC(debug, "print the debug message in this driver");\r