diff options
-rw-r--r-- | drivers/watchdog/wdt977.c | 148 |
1 files changed, 74 insertions, 74 deletions
diff --git a/drivers/watchdog/wdt977.c b/drivers/watchdog/wdt977.c index fb4b876c9fda..bdc28e522f03 100644 --- a/drivers/watchdog/wdt977.c +++ b/drivers/watchdog/wdt977.c | |||
@@ -19,7 +19,8 @@ | |||
19 | * 07-Jul-2003 Daniele Bellucci: Audit return code of misc_register in | 19 | * 07-Jul-2003 Daniele Bellucci: Audit return code of misc_register in |
20 | * nwwatchdog_init. | 20 | * nwwatchdog_init. |
21 | * 25-Oct-2005 Woody Suwalski: Convert addresses to #defs, add spinlocks | 21 | * 25-Oct-2005 Woody Suwalski: Convert addresses to #defs, add spinlocks |
22 | * remove limitiation to be used on Netwinders only | 22 | * remove limitiation to be used on |
23 | * Netwinders only | ||
23 | */ | 24 | */ |
24 | 25 | ||
25 | #include <linux/module.h> | 26 | #include <linux/module.h> |
@@ -33,11 +34,11 @@ | |||
33 | #include <linux/watchdog.h> | 34 | #include <linux/watchdog.h> |
34 | #include <linux/notifier.h> | 35 | #include <linux/notifier.h> |
35 | #include <linux/reboot.h> | 36 | #include <linux/reboot.h> |
37 | #include <linux/io.h> | ||
38 | #include <linux/uaccess.h> | ||
36 | 39 | ||
37 | #include <asm/io.h> | ||
38 | #include <asm/system.h> | 40 | #include <asm/system.h> |
39 | #include <asm/mach-types.h> | 41 | #include <asm/mach-types.h> |
40 | #include <asm/uaccess.h> | ||
41 | 42 | ||
42 | #define WATCHDOG_VERSION "0.04" | 43 | #define WATCHDOG_VERSION "0.04" |
43 | #define WATCHDOG_NAME "Wdt977" | 44 | #define WATCHDOG_NAME "Wdt977" |
@@ -45,7 +46,7 @@ | |||
45 | #define DRIVER_VERSION WATCHDOG_NAME " driver, v" WATCHDOG_VERSION "\n" | 46 | #define DRIVER_VERSION WATCHDOG_NAME " driver, v" WATCHDOG_VERSION "\n" |
46 | 47 | ||
47 | #define IO_INDEX_PORT 0x370 /* on some systems it can be 0x3F0 */ | 48 | #define IO_INDEX_PORT 0x370 /* on some systems it can be 0x3F0 */ |
48 | #define IO_DATA_PORT (IO_INDEX_PORT+1) | 49 | #define IO_DATA_PORT (IO_INDEX_PORT + 1) |
49 | 50 | ||
50 | #define UNLOCK_DATA 0x87 | 51 | #define UNLOCK_DATA 0x87 |
51 | #define LOCK_DATA 0xAA | 52 | #define LOCK_DATA 0xAA |
@@ -62,13 +63,16 @@ static char expect_close; | |||
62 | static DEFINE_SPINLOCK(spinlock); | 63 | static DEFINE_SPINLOCK(spinlock); |
63 | 64 | ||
64 | module_param(timeout, int, 0); | 65 | module_param(timeout, int, 0); |
65 | MODULE_PARM_DESC(timeout,"Watchdog timeout in seconds (60..15300), default=" __MODULE_STRING(DEFAULT_TIMEOUT) ")"); | 66 | MODULE_PARM_DESC(timeout, "Watchdog timeout in seconds (60..15300), default=" |
67 | __MODULE_STRING(DEFAULT_TIMEOUT) ")"); | ||
66 | module_param(testmode, int, 0); | 68 | module_param(testmode, int, 0); |
67 | MODULE_PARM_DESC(testmode,"Watchdog testmode (1 = no reboot), default=0"); | 69 | MODULE_PARM_DESC(testmode, "Watchdog testmode (1 = no reboot), default=0"); |
68 | 70 | ||
69 | static int nowayout = WATCHDOG_NOWAYOUT; | 71 | static int nowayout = WATCHDOG_NOWAYOUT; |
70 | module_param(nowayout, int, 0); | 72 | module_param(nowayout, int, 0); |
71 | MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default=" __MODULE_STRING(WATCHDOG_NOWAYOUT) ")"); | 73 | MODULE_PARM_DESC(nowayout, |
74 | "Watchdog cannot be stopped once started (default=" | ||
75 | __MODULE_STRING(WATCHDOG_NOWAYOUT) ")"); | ||
72 | 76 | ||
73 | /* | 77 | /* |
74 | * Start the watchdog | 78 | * Start the watchdog |
@@ -95,14 +99,16 @@ static int wdt977_start(void) | |||
95 | outb_p(0xF2, IO_INDEX_PORT); | 99 | outb_p(0xF2, IO_INDEX_PORT); |
96 | outb_p(timeoutM, IO_DATA_PORT); | 100 | outb_p(timeoutM, IO_DATA_PORT); |
97 | outb_p(0xF3, IO_INDEX_PORT); | 101 | outb_p(0xF3, IO_INDEX_PORT); |
98 | outb_p(0x00, IO_DATA_PORT); /* another setting is 0E for kbd/mouse/LED */ | 102 | outb_p(0x00, IO_DATA_PORT); /* another setting is 0E for |
103 | kbd/mouse/LED */ | ||
99 | outb_p(0xF4, IO_INDEX_PORT); | 104 | outb_p(0xF4, IO_INDEX_PORT); |
100 | outb_p(0x00, IO_DATA_PORT); | 105 | outb_p(0x00, IO_DATA_PORT); |
101 | 106 | ||
102 | /* at last select device Aux1 (dev=7) and set GP16 as a watchdog output */ | 107 | /* At last select device Aux1 (dev=7) and set GP16 as a |
103 | /* in test mode watch the bit 1 on F4 to indicate "triggered" */ | 108 | * watchdog output. In test mode watch the bit 1 on F4 to |
104 | if (!testmode) | 109 | * indicate "triggered" |
105 | { | 110 | */ |
111 | if (!testmode) { | ||
106 | outb_p(DEVICE_REGISTER, IO_INDEX_PORT); | 112 | outb_p(DEVICE_REGISTER, IO_INDEX_PORT); |
107 | outb_p(0x07, IO_DATA_PORT); | 113 | outb_p(0x07, IO_DATA_PORT); |
108 | outb_p(0xE6, IO_INDEX_PORT); | 114 | outb_p(0xE6, IO_INDEX_PORT); |
@@ -147,7 +153,8 @@ static int wdt977_stop(void) | |||
147 | outb_p(0xF2, IO_INDEX_PORT); | 153 | outb_p(0xF2, IO_INDEX_PORT); |
148 | outb_p(0x00, IO_DATA_PORT); | 154 | outb_p(0x00, IO_DATA_PORT); |
149 | 155 | ||
150 | /* at last select device Aux1 (dev=7) and set GP16 as a watchdog output */ | 156 | /* at last select device Aux1 (dev=7) and set |
157 | GP16 as a watchdog output */ | ||
151 | outb_p(DEVICE_REGISTER, IO_INDEX_PORT); | 158 | outb_p(DEVICE_REGISTER, IO_INDEX_PORT); |
152 | outb_p(0x07, IO_DATA_PORT); | 159 | outb_p(0x07, IO_DATA_PORT); |
153 | outb_p(0xE6, IO_INDEX_PORT); | 160 | outb_p(0xE6, IO_INDEX_PORT); |
@@ -202,16 +209,18 @@ static int wdt977_set_timeout(int t) | |||
202 | tmrval = (t + 59) / 60; | 209 | tmrval = (t + 59) / 60; |
203 | 210 | ||
204 | if (machine_is_netwinder()) { | 211 | if (machine_is_netwinder()) { |
205 | /* we have a hw bug somewhere, so each 977 minute is actually only 30sec | 212 | /* we have a hw bug somewhere, so each 977 minute is actually |
206 | * this limits the max timeout to half of device max of 255 minutes... | 213 | * only 30sec. This limits the max timeout to half of device |
214 | * max of 255 minutes... | ||
207 | */ | 215 | */ |
208 | tmrval += tmrval; | 216 | tmrval += tmrval; |
209 | } | 217 | } |
210 | 218 | ||
211 | if ((tmrval < 1) || (tmrval > 255)) | 219 | if (tmrval < 1 || tmrval > 255) |
212 | return -EINVAL; | 220 | return -EINVAL; |
213 | 221 | ||
214 | /* timeout is the timeout in seconds, timeoutM is the timeout in minutes) */ | 222 | /* timeout is the timeout in seconds, timeoutM is |
223 | the timeout in minutes) */ | ||
215 | timeout = t; | 224 | timeout = t; |
216 | timeoutM = tmrval; | 225 | timeoutM = tmrval; |
217 | return 0; | 226 | return 0; |
@@ -243,7 +252,7 @@ static int wdt977_get_status(int *status) | |||
243 | 252 | ||
244 | spin_unlock_irqrestore(&spinlock, flags); | 253 | spin_unlock_irqrestore(&spinlock, flags); |
245 | 254 | ||
246 | *status=0; | 255 | *status = 0; |
247 | if (new_status & 1) | 256 | if (new_status & 1) |
248 | *status |= WDIOF_CARDRESET; | 257 | *status |= WDIOF_CARDRESET; |
249 | 258 | ||
@@ -258,7 +267,7 @@ static int wdt977_get_status(int *status) | |||
258 | static int wdt977_open(struct inode *inode, struct file *file) | 267 | static int wdt977_open(struct inode *inode, struct file *file) |
259 | { | 268 | { |
260 | /* If the watchdog is alive we don't need to start it again */ | 269 | /* If the watchdog is alive we don't need to start it again */ |
261 | if( test_and_set_bit(0,&timer_alive) ) | 270 | if (test_and_set_bit(0, &timer_alive)) |
262 | return -EBUSY; | 271 | return -EBUSY; |
263 | 272 | ||
264 | if (nowayout) | 273 | if (nowayout) |
@@ -274,13 +283,13 @@ static int wdt977_release(struct inode *inode, struct file *file) | |||
274 | * Shut off the timer. | 283 | * Shut off the timer. |
275 | * Lock it in if it's a module and we set nowayout | 284 | * Lock it in if it's a module and we set nowayout |
276 | */ | 285 | */ |
277 | if (expect_close == 42) | 286 | if (expect_close == 42) { |
278 | { | ||
279 | wdt977_stop(); | 287 | wdt977_stop(); |
280 | clear_bit(0,&timer_alive); | 288 | clear_bit(0, &timer_alive); |
281 | } else { | 289 | } else { |
282 | wdt977_keepalive(); | 290 | wdt977_keepalive(); |
283 | printk(KERN_CRIT PFX "Unexpected close, not stopping watchdog!\n"); | 291 | printk(KERN_CRIT PFX |
292 | "Unexpected close, not stopping watchdog!\n"); | ||
284 | } | 293 | } |
285 | expect_close = 0; | 294 | expect_close = 0; |
286 | return 0; | 295 | return 0; |
@@ -301,17 +310,14 @@ static int wdt977_release(struct inode *inode, struct file *file) | |||
301 | static ssize_t wdt977_write(struct file *file, const char __user *buf, | 310 | static ssize_t wdt977_write(struct file *file, const char __user *buf, |
302 | size_t count, loff_t *ppos) | 311 | size_t count, loff_t *ppos) |
303 | { | 312 | { |
304 | if (count) | 313 | if (count) { |
305 | { | 314 | if (!nowayout) { |
306 | if (!nowayout) | ||
307 | { | ||
308 | size_t i; | 315 | size_t i; |
309 | 316 | ||
310 | /* In case it was set long ago */ | 317 | /* In case it was set long ago */ |
311 | expect_close = 0; | 318 | expect_close = 0; |
312 | 319 | ||
313 | for (i = 0; i != count; i++) | 320 | for (i = 0; i != count; i++) { |
314 | { | ||
315 | char c; | 321 | char c; |
316 | if (get_user(c, buf + i)) | 322 | if (get_user(c, buf + i)) |
317 | return -EFAULT; | 323 | return -EFAULT; |
@@ -326,6 +332,14 @@ static ssize_t wdt977_write(struct file *file, const char __user *buf, | |||
326 | return count; | 332 | return count; |
327 | } | 333 | } |
328 | 334 | ||
335 | static const struct watchdog_info ident = { | ||
336 | .options = WDIOF_SETTIMEOUT | | ||
337 | WDIOF_MAGICCLOSE | | ||
338 | WDIOF_KEEPALIVEPING, | ||
339 | .firmware_version = 1, | ||
340 | .identity = WATCHDOG_NAME, | ||
341 | }; | ||
342 | |||
329 | /* | 343 | /* |
330 | * wdt977_ioctl: | 344 | * wdt977_ioctl: |
331 | * @inode: inode of the device | 345 | * @inode: inode of the device |
@@ -337,16 +351,8 @@ static ssize_t wdt977_write(struct file *file, const char __user *buf, | |||
337 | * according to their available features. | 351 | * according to their available features. |
338 | */ | 352 | */ |
339 | 353 | ||
340 | static struct watchdog_info ident = { | 354 | static long wdt977_ioctl(struct file *file, unsigned int cmd, |
341 | .options = WDIOF_SETTIMEOUT | | 355 | unsigned long arg) |
342 | WDIOF_MAGICCLOSE | | ||
343 | WDIOF_KEEPALIVEPING, | ||
344 | .firmware_version = 1, | ||
345 | .identity = WATCHDOG_NAME, | ||
346 | }; | ||
347 | |||
348 | static int wdt977_ioctl(struct inode *inode, struct file *file, | ||
349 | unsigned int cmd, unsigned long arg) | ||
350 | { | 356 | { |
351 | int status; | 357 | int status; |
352 | int new_options, retval = -EINVAL; | 358 | int new_options, retval = -EINVAL; |
@@ -358,8 +364,7 @@ static int wdt977_ioctl(struct inode *inode, struct file *file, | |||
358 | 364 | ||
359 | uarg.i = (int __user *)arg; | 365 | uarg.i = (int __user *)arg; |
360 | 366 | ||
361 | switch(cmd) | 367 | switch (cmd) { |
362 | { | ||
363 | default: | 368 | default: |
364 | return -ENOTTY; | 369 | return -ENOTTY; |
365 | 370 | ||
@@ -379,7 +384,7 @@ static int wdt977_ioctl(struct inode *inode, struct file *file, | |||
379 | return 0; | 384 | return 0; |
380 | 385 | ||
381 | case WDIOC_SETOPTIONS: | 386 | case WDIOC_SETOPTIONS: |
382 | if (get_user (new_options, uarg.i)) | 387 | if (get_user(new_options, uarg.i)) |
383 | return -EFAULT; | 388 | return -EFAULT; |
384 | 389 | ||
385 | if (new_options & WDIOS_DISABLECARD) { | 390 | if (new_options & WDIOS_DISABLECARD) { |
@@ -413,23 +418,21 @@ static int wdt977_ioctl(struct inode *inode, struct file *file, | |||
413 | static int wdt977_notify_sys(struct notifier_block *this, unsigned long code, | 418 | static int wdt977_notify_sys(struct notifier_block *this, unsigned long code, |
414 | void *unused) | 419 | void *unused) |
415 | { | 420 | { |
416 | if(code==SYS_DOWN || code==SYS_HALT) | 421 | if (code == SYS_DOWN || code == SYS_HALT) |
417 | wdt977_stop(); | 422 | wdt977_stop(); |
418 | return NOTIFY_DONE; | 423 | return NOTIFY_DONE; |
419 | } | 424 | } |
420 | 425 | ||
421 | static const struct file_operations wdt977_fops= | 426 | static const struct file_operations wdt977_fops = { |
422 | { | ||
423 | .owner = THIS_MODULE, | 427 | .owner = THIS_MODULE, |
424 | .llseek = no_llseek, | 428 | .llseek = no_llseek, |
425 | .write = wdt977_write, | 429 | .write = wdt977_write, |
426 | .ioctl = wdt977_ioctl, | 430 | .unlocked_ioctl = wdt977_ioctl, |
427 | .open = wdt977_open, | 431 | .open = wdt977_open, |
428 | .release = wdt977_release, | 432 | .release = wdt977_release, |
429 | }; | 433 | }; |
430 | 434 | ||
431 | static struct miscdevice wdt977_miscdev= | 435 | static struct miscdevice wdt977_miscdev = { |
432 | { | ||
433 | .minor = WATCHDOG_MINOR, | 436 | .minor = WATCHDOG_MINOR, |
434 | .name = "watchdog", | 437 | .name = "watchdog", |
435 | .fops = &wdt977_fops, | 438 | .fops = &wdt977_fops, |
@@ -443,51 +446,48 @@ static int __init wd977_init(void) | |||
443 | { | 446 | { |
444 | int rc; | 447 | int rc; |
445 | 448 | ||
446 | //if (!machine_is_netwinder()) | ||
447 | // return -ENODEV; | ||
448 | |||
449 | printk(KERN_INFO PFX DRIVER_VERSION); | 449 | printk(KERN_INFO PFX DRIVER_VERSION); |
450 | 450 | ||
451 | /* Check that the timeout value is within it's range ; if not reset to the default */ | 451 | /* Check that the timeout value is within its range; |
452 | if (wdt977_set_timeout(timeout)) | 452 | if not reset to the default */ |
453 | { | 453 | if (wdt977_set_timeout(timeout)) { |
454 | wdt977_set_timeout(DEFAULT_TIMEOUT); | 454 | wdt977_set_timeout(DEFAULT_TIMEOUT); |
455 | printk(KERN_INFO PFX "timeout value must be 60<timeout<15300, using %d\n", | 455 | printk(KERN_INFO PFX |
456 | DEFAULT_TIMEOUT); | 456 | "timeout value must be 60 < timeout < 15300, using %d\n", |
457 | DEFAULT_TIMEOUT); | ||
457 | } | 458 | } |
458 | 459 | ||
459 | /* on Netwinder the IOports are already reserved by | 460 | /* on Netwinder the IOports are already reserved by |
460 | * arch/arm/mach-footbridge/netwinder-hw.c | 461 | * arch/arm/mach-footbridge/netwinder-hw.c |
461 | */ | 462 | */ |
462 | if (!machine_is_netwinder()) | 463 | if (!machine_is_netwinder()) { |
463 | { | 464 | if (!request_region(IO_INDEX_PORT, 2, WATCHDOG_NAME)) { |
464 | if (!request_region(IO_INDEX_PORT, 2, WATCHDOG_NAME)) | 465 | printk(KERN_ERR PFX |
465 | { | 466 | "I/O address 0x%04x already in use\n", |
466 | printk(KERN_ERR PFX "I/O address 0x%04x already in use\n", | 467 | IO_INDEX_PORT); |
467 | IO_INDEX_PORT); | ||
468 | rc = -EIO; | 468 | rc = -EIO; |
469 | goto err_out; | 469 | goto err_out; |
470 | } | 470 | } |
471 | } | 471 | } |
472 | 472 | ||
473 | rc = register_reboot_notifier(&wdt977_notifier); | 473 | rc = register_reboot_notifier(&wdt977_notifier); |
474 | if (rc) | 474 | if (rc) { |
475 | { | 475 | printk(KERN_ERR PFX |
476 | printk(KERN_ERR PFX "cannot register reboot notifier (err=%d)\n", | 476 | "cannot register reboot notifier (err=%d)\n", rc); |
477 | rc); | ||
478 | goto err_out_region; | 477 | goto err_out_region; |
479 | } | 478 | } |
480 | 479 | ||
481 | rc = misc_register(&wdt977_miscdev); | 480 | rc = misc_register(&wdt977_miscdev); |
482 | if (rc) | 481 | if (rc) { |
483 | { | 482 | printk(KERN_ERR PFX |
484 | printk(KERN_ERR PFX "cannot register miscdev on minor=%d (err=%d)\n", | 483 | "cannot register miscdev on minor=%d (err=%d)\n", |
485 | wdt977_miscdev.minor, rc); | 484 | wdt977_miscdev.minor, rc); |
486 | goto err_out_reboot; | 485 | goto err_out_reboot; |
487 | } | 486 | } |
488 | 487 | ||
489 | printk(KERN_INFO PFX "initialized. timeout=%d sec (nowayout=%d, testmode=%i)\n", | 488 | printk(KERN_INFO PFX |
490 | timeout, nowayout, testmode); | 489 | "initialized. timeout=%d sec (nowayout=%d, testmode=%i)\n", |
490 | timeout, nowayout, testmode); | ||
491 | 491 | ||
492 | return 0; | 492 | return 0; |
493 | 493 | ||
@@ -495,7 +495,7 @@ err_out_reboot: | |||
495 | unregister_reboot_notifier(&wdt977_notifier); | 495 | unregister_reboot_notifier(&wdt977_notifier); |
496 | err_out_region: | 496 | err_out_region: |
497 | if (!machine_is_netwinder()) | 497 | if (!machine_is_netwinder()) |
498 | release_region(IO_INDEX_PORT,2); | 498 | release_region(IO_INDEX_PORT, 2); |
499 | err_out: | 499 | err_out: |
500 | return rc; | 500 | return rc; |
501 | } | 501 | } |
@@ -505,7 +505,7 @@ static void __exit wd977_exit(void) | |||
505 | wdt977_stop(); | 505 | wdt977_stop(); |
506 | misc_deregister(&wdt977_miscdev); | 506 | misc_deregister(&wdt977_miscdev); |
507 | unregister_reboot_notifier(&wdt977_notifier); | 507 | unregister_reboot_notifier(&wdt977_notifier); |
508 | release_region(IO_INDEX_PORT,2); | 508 | release_region(IO_INDEX_PORT, 2); |
509 | } | 509 | } |
510 | 510 | ||
511 | module_init(wd977_init); | 511 | module_init(wd977_init); |