cleanup
[linux-2.4.21-pre4.git] / drivers / char / wdt977.c
1 /*
2  *      Wdt977  0.02:   A Watchdog Device for Netwinder W83977AF chip
3  *
4  *      (c) Copyright 1998 Rebel.com (Woody Suwalski <woody@netwinder.org>)
5  *
6  *                      -----------------------
7  *
8  *      This program is free software; you can redistribute it and/or
9  *      modify it under the terms of the GNU General Public License
10  *      as published by the Free Software Foundation; either version
11  *      2 of the License, or (at your option) any later version.
12  *
13  *                      -----------------------
14  *      14-Dec-2001 Matt Domsch <Matt_Domsch@dell.com>
15  *           Added nowayout module option to override CONFIG_WATCHDOG_NOWAYOUT
16  */
17  
18 #include <linux/module.h>
19 #include <linux/config.h>
20 #include <linux/types.h>
21 #include <linux/kernel.h>
22 #include <linux/fs.h>
23 #include <linux/miscdevice.h>
24 #include <linux/init.h>
25 #include <linux/smp_lock.h>
26
27 #include <asm/io.h>
28 #include <asm/system.h>
29 #include <asm/mach-types.h>
30
31 #define WATCHDOG_MINOR  130
32
33 static  int timeout = 3;
34 static  int timer_alive;
35 static  int testmode;
36 static  int expect_close = 0;
37
38 #ifdef CONFIG_WATCHDOG_NOWAYOUT
39 static int nowayout = 1;
40 #else
41 static int nowayout = 0;
42 #endif
43
44 MODULE_PARM(nowayout,"i");
45 MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default=CONFIG_WATCHDOG_NOWAYOUT)");
46
47
48 /*
49  *      Allow only one person to hold it open
50  */
51  
52 static int wdt977_open(struct inode *inode, struct file *file)
53 {
54         if(timer_alive)
55                 return -EBUSY;
56         if (nowayout) {
57                 MOD_INC_USE_COUNT;
58         }
59         timer_alive++;
60
61         //max timeout value = 255 minutes (0xFF). Write 0 to disable WatchDog.
62         if (timeout>255)
63             timeout = 255;
64
65         printk(KERN_INFO "Watchdog: active, current timeout %d min.\n",timeout);
66
67         // unlock the SuperIO chip
68         outb(0x87,0x370); 
69         outb(0x87,0x370); 
70         
71         //select device Aux2 (device=8) and set watchdog regs F2, F3 and F4
72         //F2 has the timeout in minutes
73         //F3 could be set to the POWER LED blink (with GP17 set to PowerLed)
74         //   at timeout, and to reset timer on kbd/mouse activity (not now)
75         //F4 is used to just clear the TIMEOUT'ed state (bit 0)
76         
77         outb(0x07,0x370);
78         outb(0x08,0x371);
79         outb(0xF2,0x370);
80         outb(timeout,0x371);
81         outb(0xF3,0x370);
82         outb(0x00,0x371);       //another setting is 0E for kbd/mouse/LED
83         outb(0xF4,0x370);
84         outb(0x00,0x371);
85         
86         //at last select device Aux1 (dev=7) and set GP16 as a watchdog output
87         if (!testmode)
88         {
89                 outb(0x07,0x370);
90                 outb(0x07,0x371);
91                 outb(0xE6,0x370);
92                 outb(0x08,0x371);
93         }
94                 
95         // lock the SuperIO chip
96         outb(0xAA,0x370); 
97
98         return 0;
99 }
100
101 static int wdt977_release(struct inode *inode, struct file *file)
102 {
103         /*
104          *      Shut off the timer.
105          *      Lock it in if it's a module and we set nowayout
106          */
107         lock_kernel();
108         if (expect_close) {
109
110                 // unlock the SuperIO chip
111                 outb(0x87,0x370); 
112                 outb(0x87,0x370); 
113         
114                 //select device Aux2 (device=8) and set watchdog regs F2,F3 and F4
115                 //F3 is reset to its default state
116                 //F4 can clear the TIMEOUT'ed state (bit 0) - back to default
117                 //We can not use GP17 as a PowerLed, as we use its usage as a RedLed
118         
119                 outb(0x07,0x370);
120                 outb(0x08,0x371);
121                 outb(0xF2,0x370);
122                 outb(0xFF,0x371);
123                 outb(0xF3,0x370);
124                 outb(0x00,0x371);
125                 outb(0xF4,0x370);
126                 outb(0x00,0x371);
127                 outb(0xF2,0x370);
128                 outb(0x00,0x371);
129         
130                 //at last select device Aux1 (dev=7) and set GP16 as a watchdog output
131                 outb(0x07,0x370);
132                 outb(0x07,0x371);
133                 outb(0xE6,0x370);
134                 outb(0x08,0x371);
135         
136                 // lock the SuperIO chip
137                 outb(0xAA,0x370);
138                 printk(KERN_INFO "Watchdog: shutdown.\n");
139         } else {
140                 printk(KERN_CRIT "WDT device closed unexpectedly.  WDT will not stop!\n");
141         }
142
143         timer_alive=0;
144         unlock_kernel();
145
146         return 0;
147 }
148
149 static ssize_t wdt977_write(struct file *file, const char *data, size_t len, loff_t *ppos)
150 {
151         if (!nowayout) {
152                 size_t i;
153
154                 /* In case it was set long ago */
155                 expect_close = 0;
156
157                 for (i = 0; i != len; i++) {
158                         char c;
159                         if (get_user(c, data + i))
160                                 return -EFAULT;
161                         if (c == 'V')
162                                 expect_close = 1;
163                 }
164         }
165
166         //max timeout value = 255 minutes (0xFF). Write 0 to disable WatchDog.
167         if (timeout>255)
168             timeout = 255;
169
170         /*
171          *      Refresh the timer.
172          */
173                 
174         //we have a hw bug somewhere, so each 977 minute is actually only 30sec
175         //as such limit the max timeout to half of max of 255 minutes...
176 //      if (timeout>126)
177 //          timeout = 126;
178         
179         // unlock the SuperIO chip
180         outb(0x87,0x370); 
181         outb(0x87,0x370); 
182         
183         //select device Aux2 (device=8) and kicks watchdog reg F2
184         //F2 has the timeout in minutes
185         
186         outb(0x07,0x370);
187         outb(0x08,0x371);
188         outb(0xF2,0x370);
189         outb(timeout,0x371);
190         
191         // lock the SuperIO chip
192         outb(0xAA,0x370); 
193         
194         return 1;
195 }
196
197 static struct file_operations wdt977_fops=
198 {
199         owner:          THIS_MODULE,
200         write:          wdt977_write,
201         open:           wdt977_open,
202         release:        wdt977_release,
203 };
204
205 static struct miscdevice wdt977_miscdev=
206 {
207         WATCHDOG_MINOR,
208         "watchdog",
209         &wdt977_fops
210 };
211
212 static int __init nwwatchdog_init(void)
213 {
214         if (!machine_is_netwinder())
215                 return -ENODEV;
216
217         misc_register(&wdt977_miscdev);
218         printk(KERN_INFO "NetWinder Watchdog sleeping.\n");
219         return 0;
220 }       
221
222 static void __exit nwwatchdog_exit(void)
223 {
224         misc_deregister(&wdt977_miscdev);
225 }
226
227 EXPORT_NO_SYMBOLS;
228
229 module_init(nwwatchdog_init);
230 module_exit(nwwatchdog_exit);
231
232 MODULE_LICENSE("GPL");