aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/watchdog/w83877f_wdt.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/watchdog/w83877f_wdt.c')
-rw-r--r--drivers/watchdog/w83877f_wdt.c199
1 files changed, 101 insertions, 98 deletions
diff --git a/drivers/watchdog/w83877f_wdt.c b/drivers/watchdog/w83877f_wdt.c
index f510a3a595e6..24587d2060c4 100644
--- a/drivers/watchdog/w83877f_wdt.c
+++ b/drivers/watchdog/w83877f_wdt.c
@@ -23,13 +23,16 @@
23 * Added KERN_* tags to printks 23 * Added KERN_* tags to printks
24 * add CONFIG_WATCHDOG_NOWAYOUT support 24 * add CONFIG_WATCHDOG_NOWAYOUT support
25 * fix possible wdt_is_open race 25 * fix possible wdt_is_open race
26 * changed watchdog_info to correctly reflect what the driver offers 26 * changed watchdog_info to correctly reflect what
27 * added WDIOC_GETSTATUS, WDIOC_GETBOOTSTATUS, WDIOC_SETTIMEOUT, 27 * the driver offers
28 * added WDIOC_GETSTATUS, WDIOC_GETBOOTSTATUS,
29 * WDIOC_SETTIMEOUT,
28 * WDIOC_GETTIMEOUT, and WDIOC_SETOPTIONS ioctls 30 * WDIOC_GETTIMEOUT, and WDIOC_SETOPTIONS ioctls
29 * 09/8 - 2003 [wim@iguana.be] cleanup of trailing spaces 31 * 09/8 - 2003 [wim@iguana.be] cleanup of trailing spaces
30 * added extra printk's for startup problems 32 * added extra printk's for startup problems
31 * use module_param 33 * use module_param
32 * made timeout (the emulated heartbeat) a module_param 34 * made timeout (the emulated heartbeat) a
35 * module_param
33 * made the keepalive ping an internal subroutine 36 * made the keepalive ping an internal subroutine
34 * 37 *
35 * This WDT driver is different from most other Linux WDT 38 * This WDT driver is different from most other Linux WDT
@@ -51,8 +54,8 @@
51#include <linux/notifier.h> 54#include <linux/notifier.h>
52#include <linux/reboot.h> 55#include <linux/reboot.h>
53#include <linux/init.h> 56#include <linux/init.h>
54#include <asm/io.h> 57#include <linux/io.h>
55#include <asm/uaccess.h> 58#include <linux/uaccess.h>
56#include <asm/system.h> 59#include <asm/system.h>
57 60
58#define OUR_NAME "w83877f_wdt" 61#define OUR_NAME "w83877f_wdt"
@@ -80,14 +83,19 @@
80 */ 83 */
81 84
82#define WATCHDOG_TIMEOUT 30 /* 30 sec default timeout */ 85#define WATCHDOG_TIMEOUT 30 /* 30 sec default timeout */
83static int timeout = WATCHDOG_TIMEOUT; /* in seconds, will be multiplied by HZ to get seconds to wait for a ping */ 86/* in seconds, will be multiplied by HZ to get seconds to wait for a ping */
87static int timeout = WATCHDOG_TIMEOUT;
84module_param(timeout, int, 0); 88module_param(timeout, int, 0);
85MODULE_PARM_DESC(timeout, "Watchdog timeout in seconds. (1<=timeout<=3600, default=" __MODULE_STRING(WATCHDOG_TIMEOUT) ")"); 89MODULE_PARM_DESC(timeout,
90 "Watchdog timeout in seconds. (1<=timeout<=3600, default="
91 __MODULE_STRING(WATCHDOG_TIMEOUT) ")");
86 92
87 93
88static int nowayout = WATCHDOG_NOWAYOUT; 94static int nowayout = WATCHDOG_NOWAYOUT;
89module_param(nowayout, int, 0); 95module_param(nowayout, int, 0);
90MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default=" __MODULE_STRING(WATCHDOG_NOWAYOUT) ")"); 96MODULE_PARM_DESC(nowayout,
97 "Watchdog cannot be stopped once started (default="
98 __MODULE_STRING(WATCHDOG_NOWAYOUT) ")");
91 99
92static void wdt_timer_ping(unsigned long); 100static void wdt_timer_ping(unsigned long);
93static DEFINE_TIMER(timer, wdt_timer_ping, 0, 0); 101static DEFINE_TIMER(timer, wdt_timer_ping, 0, 0);
@@ -105,8 +113,7 @@ static void wdt_timer_ping(unsigned long data)
105 /* If we got a heartbeat pulse within the WDT_US_INTERVAL 113 /* If we got a heartbeat pulse within the WDT_US_INTERVAL
106 * we agree to ping the WDT 114 * we agree to ping the WDT
107 */ 115 */
108 if(time_before(jiffies, next_heartbeat)) 116 if (time_before(jiffies, next_heartbeat)) {
109 {
110 /* Ping the WDT */ 117 /* Ping the WDT */
111 spin_lock(&wdt_spinlock); 118 spin_lock(&wdt_spinlock);
112 119
@@ -118,9 +125,9 @@ static void wdt_timer_ping(unsigned long data)
118 125
119 spin_unlock(&wdt_spinlock); 126 spin_unlock(&wdt_spinlock);
120 127
121 } else { 128 } else
122 printk(KERN_WARNING PFX "Heartbeat lost! Will not ping the watchdog\n"); 129 printk(KERN_WARNING PFX
123 } 130 "Heartbeat lost! Will not ping the watchdog\n");
124} 131}
125 132
126/* 133/*
@@ -181,22 +188,21 @@ static void wdt_keepalive(void)
181 * /dev/watchdog handling 188 * /dev/watchdog handling
182 */ 189 */
183 190
184static ssize_t fop_write(struct file * file, const char __user * buf, size_t count, loff_t * ppos) 191static ssize_t fop_write(struct file *file, const char __user *buf,
192 size_t count, loff_t *ppos)
185{ 193{
186 /* See if we got the magic character 'V' and reload the timer */ 194 /* See if we got the magic character 'V' and reload the timer */
187 if(count) 195 if (count) {
188 { 196 if (!nowayout) {
189 if (!nowayout)
190 {
191 size_t ofs; 197 size_t ofs;
192 198
193 /* note: just in case someone wrote the magic character 199 /* note: just in case someone wrote the magic
194 * five months ago... */ 200 character five months ago... */
195 wdt_expect_close = 0; 201 wdt_expect_close = 0;
196 202
197 /* scan to see whether or not we got the magic character */ 203 /* scan to see whether or not we got the
198 for(ofs = 0; ofs != count; ofs++) 204 magic character */
199 { 205 for (ofs = 0; ofs != count; ofs++) {
200 char c; 206 char c;
201 if (get_user(c, buf + ofs)) 207 if (get_user(c, buf + ofs))
202 return -EFAULT; 208 return -EFAULT;
@@ -211,10 +217,10 @@ static ssize_t fop_write(struct file * file, const char __user * buf, size_t cou
211 return count; 217 return count;
212} 218}
213 219
214static int fop_open(struct inode * inode, struct file * file) 220static int fop_open(struct inode *inode, struct file *file)
215{ 221{
216 /* Just in case we're already talking to someone... */ 222 /* Just in case we're already talking to someone... */
217 if(test_and_set_bit(0, &wdt_is_open)) 223 if (test_and_set_bit(0, &wdt_is_open))
218 return -EBUSY; 224 return -EBUSY;
219 225
220 /* Good, fire up the show */ 226 /* Good, fire up the show */
@@ -222,78 +228,78 @@ static int fop_open(struct inode * inode, struct file * file)
222 return nonseekable_open(inode, file); 228 return nonseekable_open(inode, file);
223} 229}
224 230
225static int fop_close(struct inode * inode, struct file * file) 231static int fop_close(struct inode *inode, struct file *file)
226{ 232{
227 if(wdt_expect_close == 42) 233 if (wdt_expect_close == 42)
228 wdt_turnoff(); 234 wdt_turnoff();
229 else { 235 else {
230 del_timer(&timer); 236 del_timer(&timer);
231 printk(KERN_CRIT PFX "device file closed unexpectedly. Will not stop the WDT!\n"); 237 printk(KERN_CRIT PFX
238 "device file closed unexpectedly. Will not stop the WDT!\n");
232 } 239 }
233 clear_bit(0, &wdt_is_open); 240 clear_bit(0, &wdt_is_open);
234 wdt_expect_close = 0; 241 wdt_expect_close = 0;
235 return 0; 242 return 0;
236} 243}
237 244
238static int fop_ioctl(struct inode *inode, struct file *file, unsigned int cmd, 245static long fop_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
239 unsigned long arg)
240{ 246{
241 void __user *argp = (void __user *)arg; 247 void __user *argp = (void __user *)arg;
242 int __user *p = argp; 248 int __user *p = argp;
243 static struct watchdog_info ident= 249 static const struct watchdog_info ident = {
244 { 250 .options = WDIOF_KEEPALIVEPING | WDIOF_SETTIMEOUT
245 .options = WDIOF_KEEPALIVEPING | WDIOF_SETTIMEOUT | WDIOF_MAGICCLOSE, 251 | WDIOF_MAGICCLOSE,
246 .firmware_version = 1, 252 .firmware_version = 1,
247 .identity = "W83877F", 253 .identity = "W83877F",
248 }; 254 };
249 255
250 switch(cmd) 256 switch (cmd) {
257 case WDIOC_GETSUPPORT:
258 return copy_to_user(argp, &ident, sizeof(ident)) ? -EFAULT : 0;
259 case WDIOC_GETSTATUS:
260 case WDIOC_GETBOOTSTATUS:
261 return put_user(0, p);
262 case WDIOC_SETOPTIONS:
251 { 263 {
252 default: 264 int new_options, retval = -EINVAL;
253 return -ENOTTY;
254 case WDIOC_GETSUPPORT:
255 return copy_to_user(argp, &ident, sizeof(ident))?-EFAULT:0;
256 case WDIOC_GETSTATUS:
257 case WDIOC_GETBOOTSTATUS:
258 return put_user(0, p);
259 case WDIOC_KEEPALIVE:
260 wdt_keepalive();
261 return 0;
262 case WDIOC_SETOPTIONS:
263 {
264 int new_options, retval = -EINVAL;
265
266 if(get_user(new_options, p))
267 return -EFAULT;
268
269 if(new_options & WDIOS_DISABLECARD) {
270 wdt_turnoff();
271 retval = 0;
272 }
273 265
274 if(new_options & WDIOS_ENABLECARD) { 266 if (get_user(new_options, p))
275 wdt_startup(); 267 return -EFAULT;
276 retval = 0;
277 }
278 268
279 return retval; 269 if (new_options & WDIOS_DISABLECARD) {
270 wdt_turnoff();
271 retval = 0;
280 } 272 }
281 case WDIOC_SETTIMEOUT:
282 {
283 int new_timeout;
284 273
285 if(get_user(new_timeout, p)) 274 if (new_options & WDIOS_ENABLECARD) {
286 return -EFAULT; 275 wdt_startup();
276 retval = 0;
277 }
287 278
288 if(new_timeout < 1 || new_timeout > 3600) /* arbitrary upper limit */ 279 return retval;
289 return -EINVAL; 280 }
281 case WDIOC_KEEPALIVE:
282 wdt_keepalive();
283 return 0;
284 case WDIOC_SETTIMEOUT:
285 {
286 int new_timeout;
290 287
291 timeout = new_timeout; 288 if (get_user(new_timeout, p))
292 wdt_keepalive(); 289 return -EFAULT;
293 /* Fall through */ 290
294 } 291 /* arbitrary upper limit */
295 case WDIOC_GETTIMEOUT: 292 if (new_timeout < 1 || new_timeout > 3600)
296 return put_user(timeout, p); 293 return -EINVAL;
294
295 timeout = new_timeout;
296 wdt_keepalive();
297 /* Fall through */
298 }
299 case WDIOC_GETTIMEOUT:
300 return put_user(timeout, p);
301 default:
302 return -ENOTTY;
297 } 303 }
298} 304}
299 305
@@ -303,7 +309,7 @@ static const struct file_operations wdt_fops = {
303 .write = fop_write, 309 .write = fop_write,
304 .open = fop_open, 310 .open = fop_open,
305 .release = fop_close, 311 .release = fop_close,
306 .ioctl = fop_ioctl, 312 .unlocked_ioctl = fop_ioctl,
307}; 313};
308 314
309static struct miscdevice wdt_miscdev = { 315static struct miscdevice wdt_miscdev = {
@@ -319,7 +325,7 @@ static struct miscdevice wdt_miscdev = {
319static int wdt_notify_sys(struct notifier_block *this, unsigned long code, 325static int wdt_notify_sys(struct notifier_block *this, unsigned long code,
320 void *unused) 326 void *unused)
321{ 327{
322 if(code==SYS_DOWN || code==SYS_HALT) 328 if (code == SYS_DOWN || code == SYS_HALT)
323 wdt_turnoff(); 329 wdt_turnoff();
324 return NOTIFY_DONE; 330 return NOTIFY_DONE;
325} 331}
@@ -329,8 +335,7 @@ static int wdt_notify_sys(struct notifier_block *this, unsigned long code,
329 * turn the timebomb registers off. 335 * turn the timebomb registers off.
330 */ 336 */
331 337
332static struct notifier_block wdt_notifier= 338static struct notifier_block wdt_notifier = {
333{
334 .notifier_call = wdt_notify_sys, 339 .notifier_call = wdt_notify_sys,
335}; 340};
336 341
@@ -342,31 +347,29 @@ static void __exit w83877f_wdt_unload(void)
342 misc_deregister(&wdt_miscdev); 347 misc_deregister(&wdt_miscdev);
343 348
344 unregister_reboot_notifier(&wdt_notifier); 349 unregister_reboot_notifier(&wdt_notifier);
345 release_region(WDT_PING,1); 350 release_region(WDT_PING, 1);
346 release_region(ENABLE_W83877F_PORT,2); 351 release_region(ENABLE_W83877F_PORT, 2);
347} 352}
348 353
349static int __init w83877f_wdt_init(void) 354static int __init w83877f_wdt_init(void)
350{ 355{
351 int rc = -EBUSY; 356 int rc = -EBUSY;
352 357
353 if(timeout < 1 || timeout > 3600) /* arbitrary upper limit */ 358 if (timeout < 1 || timeout > 3600) { /* arbitrary upper limit */
354 {
355 timeout = WATCHDOG_TIMEOUT; 359 timeout = WATCHDOG_TIMEOUT;
356 printk(KERN_INFO PFX "timeout value must be 1<=x<=3600, using %d\n", 360 printk(KERN_INFO PFX
357 timeout); 361 "timeout value must be 1 <= x <= 3600, using %d\n",
362 timeout);
358 } 363 }
359 364
360 if (!request_region(ENABLE_W83877F_PORT, 2, "W83877F WDT")) 365 if (!request_region(ENABLE_W83877F_PORT, 2, "W83877F WDT")) {
361 {
362 printk(KERN_ERR PFX "I/O address 0x%04x already in use\n", 366 printk(KERN_ERR PFX "I/O address 0x%04x already in use\n",
363 ENABLE_W83877F_PORT); 367 ENABLE_W83877F_PORT);
364 rc = -EIO; 368 rc = -EIO;
365 goto err_out; 369 goto err_out;
366 } 370 }
367 371
368 if (!request_region(WDT_PING, 1, "W8387FF WDT")) 372 if (!request_region(WDT_PING, 1, "W8387FF WDT")) {
369 {
370 printk(KERN_ERR PFX "I/O address 0x%04x already in use\n", 373 printk(KERN_ERR PFX "I/O address 0x%04x already in use\n",
371 WDT_PING); 374 WDT_PING);
372 rc = -EIO; 375 rc = -EIO;
@@ -374,22 +377,22 @@ static int __init w83877f_wdt_init(void)
374 } 377 }
375 378
376 rc = register_reboot_notifier(&wdt_notifier); 379 rc = register_reboot_notifier(&wdt_notifier);
377 if (rc) 380 if (rc) {
378 { 381 printk(KERN_ERR PFX
379 printk(KERN_ERR PFX "cannot register reboot notifier (err=%d)\n", 382 "cannot register reboot notifier (err=%d)\n", rc);
380 rc);
381 goto err_out_region2; 383 goto err_out_region2;
382 } 384 }
383 385
384 rc = misc_register(&wdt_miscdev); 386 rc = misc_register(&wdt_miscdev);
385 if (rc) 387 if (rc) {
386 { 388 printk(KERN_ERR PFX
387 printk(KERN_ERR PFX "cannot register miscdev on minor=%d (err=%d)\n", 389 "cannot register miscdev on minor=%d (err=%d)\n",
388 wdt_miscdev.minor, rc); 390 wdt_miscdev.minor, rc);
389 goto err_out_reboot; 391 goto err_out_reboot;
390 } 392 }
391 393
392 printk(KERN_INFO PFX "WDT driver for W83877F initialised. timeout=%d sec (nowayout=%d)\n", 394 printk(KERN_INFO PFX
395 "WDT driver for W83877F initialised. timeout=%d sec (nowayout=%d)\n",
393 timeout, nowayout); 396 timeout, nowayout);
394 397
395 return 0; 398 return 0;
@@ -397,9 +400,9 @@ static int __init w83877f_wdt_init(void)
397err_out_reboot: 400err_out_reboot:
398 unregister_reboot_notifier(&wdt_notifier); 401 unregister_reboot_notifier(&wdt_notifier);
399err_out_region2: 402err_out_region2:
400 release_region(WDT_PING,1); 403 release_region(WDT_PING, 1);
401err_out_region1: 404err_out_region1:
402 release_region(ENABLE_W83877F_PORT,2); 405 release_region(ENABLE_W83877F_PORT, 2);
403err_out: 406err_out:
404 return rc; 407 return rc;
405} 408}