diff options
Diffstat (limited to 'drivers/watchdog/i6300esb.c')
-rw-r--r-- | drivers/watchdog/i6300esb.c | 101 |
1 files changed, 64 insertions, 37 deletions
diff --git a/drivers/watchdog/i6300esb.c b/drivers/watchdog/i6300esb.c index 74f951c18b90..2dbe83570d65 100644 --- a/drivers/watchdog/i6300esb.c +++ b/drivers/watchdog/i6300esb.c | |||
@@ -13,7 +13,7 @@ | |||
13 | * | 13 | * |
14 | * The timer is implemented in the following I/O controller hubs: | 14 | * The timer is implemented in the following I/O controller hubs: |
15 | * (See the intel documentation on http://developer.intel.com.) | 15 | * (See the intel documentation on http://developer.intel.com.) |
16 | * 6300ESB chip : document number 300641-003 | 16 | * 6300ESB chip : document number 300641-004 |
17 | * | 17 | * |
18 | * 2004YYZZ Ross Biro | 18 | * 2004YYZZ Ross Biro |
19 | * Initial version 0.01 | 19 | * Initial version 0.01 |
@@ -34,7 +34,7 @@ | |||
34 | #include <linux/mm.h> | 34 | #include <linux/mm.h> |
35 | #include <linux/miscdevice.h> | 35 | #include <linux/miscdevice.h> |
36 | #include <linux/watchdog.h> | 36 | #include <linux/watchdog.h> |
37 | #include <linux/reboot.h> | 37 | #include <linux/platform_device.h> |
38 | #include <linux/init.h> | 38 | #include <linux/init.h> |
39 | #include <linux/pci.h> | 39 | #include <linux/pci.h> |
40 | #include <linux/ioport.h> | 40 | #include <linux/ioport.h> |
@@ -42,7 +42,7 @@ | |||
42 | #include <linux/io.h> | 42 | #include <linux/io.h> |
43 | 43 | ||
44 | /* Module and version information */ | 44 | /* Module and version information */ |
45 | #define ESB_VERSION "0.03" | 45 | #define ESB_VERSION "0.04" |
46 | #define ESB_MODULE_NAME "i6300ESB timer" | 46 | #define ESB_MODULE_NAME "i6300ESB timer" |
47 | #define ESB_DRIVER_NAME ESB_MODULE_NAME ", v" ESB_VERSION | 47 | #define ESB_DRIVER_NAME ESB_MODULE_NAME ", v" ESB_VERSION |
48 | #define PFX ESB_MODULE_NAME ": " | 48 | #define PFX ESB_MODULE_NAME ": " |
@@ -81,6 +81,7 @@ static unsigned long timer_alive; | |||
81 | static struct pci_dev *esb_pci; | 81 | static struct pci_dev *esb_pci; |
82 | static unsigned short triggered; /* The status of the watchdog upon boot */ | 82 | static unsigned short triggered; /* The status of the watchdog upon boot */ |
83 | static char esb_expect_close; | 83 | static char esb_expect_close; |
84 | static struct platform_device *esb_platform_device; | ||
84 | 85 | ||
85 | /* module parameters */ | 86 | /* module parameters */ |
86 | /* 30 sec default heartbeat (1 < heartbeat < 2*1023) */ | 87 | /* 30 sec default heartbeat (1 < heartbeat < 2*1023) */ |
@@ -114,13 +115,18 @@ static inline void esb_unlock_registers(void) | |||
114 | writeb(ESB_UNLOCK2, ESB_RELOAD_REG); | 115 | writeb(ESB_UNLOCK2, ESB_RELOAD_REG); |
115 | } | 116 | } |
116 | 117 | ||
117 | static void esb_timer_start(void) | 118 | static int esb_timer_start(void) |
118 | { | 119 | { |
119 | u8 val; | 120 | u8 val; |
120 | 121 | ||
122 | spin_lock(&esb_lock); | ||
123 | esb_unlock_registers(); | ||
124 | writew(ESB_WDT_RELOAD, ESB_RELOAD_REG); | ||
121 | /* Enable or Enable + Lock? */ | 125 | /* Enable or Enable + Lock? */ |
122 | val = 0x02 | (nowayout ? 0x01 : 0x00); | 126 | val = 0x02 | (nowayout ? 0x01 : 0x00); |
123 | pci_write_config_byte(esb_pci, ESB_LOCK_REG, val); | 127 | pci_write_config_byte(esb_pci, ESB_LOCK_REG, val); |
128 | spin_unlock(&esb_lock); | ||
129 | return 0; | ||
124 | } | 130 | } |
125 | 131 | ||
126 | static int esb_timer_stop(void) | 132 | static int esb_timer_stop(void) |
@@ -207,7 +213,6 @@ static int esb_open(struct inode *inode, struct file *file) | |||
207 | return -EBUSY; | 213 | return -EBUSY; |
208 | 214 | ||
209 | /* Reload and activate timer */ | 215 | /* Reload and activate timer */ |
210 | esb_timer_keepalive(); | ||
211 | esb_timer_start(); | 216 | esb_timer_start(); |
212 | 217 | ||
213 | return nonseekable_open(inode, file); | 218 | return nonseekable_open(inode, file); |
@@ -240,7 +245,8 @@ static ssize_t esb_write(struct file *file, const char __user *data, | |||
240 | * five months ago... */ | 245 | * five months ago... */ |
241 | esb_expect_close = 0; | 246 | esb_expect_close = 0; |
242 | 247 | ||
243 | /* scan to see whether or not we got the magic character */ | 248 | /* scan to see whether or not we got the |
249 | * magic character */ | ||
244 | for (i = 0; i != len; i++) { | 250 | for (i = 0; i != len; i++) { |
245 | char c; | 251 | char c; |
246 | if (get_user(c, data + i)) | 252 | if (get_user(c, data + i)) |
@@ -292,7 +298,6 @@ static long esb_ioctl(struct file *file, unsigned int cmd, unsigned long arg) | |||
292 | } | 298 | } |
293 | 299 | ||
294 | if (new_options & WDIOS_ENABLECARD) { | 300 | if (new_options & WDIOS_ENABLECARD) { |
295 | esb_timer_keepalive(); | ||
296 | esb_timer_start(); | 301 | esb_timer_start(); |
297 | retval = 0; | 302 | retval = 0; |
298 | } | 303 | } |
@@ -319,19 +324,6 @@ static long esb_ioctl(struct file *file, unsigned int cmd, unsigned long arg) | |||
319 | } | 324 | } |
320 | 325 | ||
321 | /* | 326 | /* |
322 | * Notify system | ||
323 | */ | ||
324 | |||
325 | static int esb_notify_sys(struct notifier_block *this, | ||
326 | unsigned long code, void *unused) | ||
327 | { | ||
328 | if (code == SYS_DOWN || code == SYS_HALT) | ||
329 | esb_timer_stop(); /* Turn the WDT off */ | ||
330 | |||
331 | return NOTIFY_DONE; | ||
332 | } | ||
333 | |||
334 | /* | ||
335 | * Kernel Interfaces | 327 | * Kernel Interfaces |
336 | */ | 328 | */ |
337 | 329 | ||
@@ -350,10 +342,6 @@ static struct miscdevice esb_miscdev = { | |||
350 | .fops = &esb_fops, | 342 | .fops = &esb_fops, |
351 | }; | 343 | }; |
352 | 344 | ||
353 | static struct notifier_block esb_notifier = { | ||
354 | .notifier_call = esb_notify_sys, | ||
355 | }; | ||
356 | |||
357 | /* | 345 | /* |
358 | * Data for PCI driver interface | 346 | * Data for PCI driver interface |
359 | * | 347 | * |
@@ -372,7 +360,7 @@ MODULE_DEVICE_TABLE(pci, esb_pci_tbl); | |||
372 | * Init & exit routines | 360 | * Init & exit routines |
373 | */ | 361 | */ |
374 | 362 | ||
375 | static unsigned char __init esb_getdevice(void) | 363 | static unsigned char __devinit esb_getdevice(void) |
376 | { | 364 | { |
377 | u8 val1; | 365 | u8 val1; |
378 | unsigned short val2; | 366 | unsigned short val2; |
@@ -443,7 +431,7 @@ err_devput: | |||
443 | return 0; | 431 | return 0; |
444 | } | 432 | } |
445 | 433 | ||
446 | static int __init watchdog_init(void) | 434 | static int __devinit esb_probe(struct platform_device *dev) |
447 | { | 435 | { |
448 | int ret; | 436 | int ret; |
449 | 437 | ||
@@ -459,19 +447,13 @@ static int __init watchdog_init(void) | |||
459 | "heartbeat value must be 1<heartbeat<2046, using %d\n", | 447 | "heartbeat value must be 1<heartbeat<2046, using %d\n", |
460 | heartbeat); | 448 | heartbeat); |
461 | } | 449 | } |
462 | ret = register_reboot_notifier(&esb_notifier); | ||
463 | if (ret != 0) { | ||
464 | printk(KERN_ERR PFX | ||
465 | "cannot register reboot notifier (err=%d)\n", ret); | ||
466 | goto err_unmap; | ||
467 | } | ||
468 | 450 | ||
469 | ret = misc_register(&esb_miscdev); | 451 | ret = misc_register(&esb_miscdev); |
470 | if (ret != 0) { | 452 | if (ret != 0) { |
471 | printk(KERN_ERR PFX | 453 | printk(KERN_ERR PFX |
472 | "cannot register miscdev on minor=%d (err=%d)\n", | 454 | "cannot register miscdev on minor=%d (err=%d)\n", |
473 | WATCHDOG_MINOR, ret); | 455 | WATCHDOG_MINOR, ret); |
474 | goto err_notifier; | 456 | goto err_unmap; |
475 | } | 457 | } |
476 | esb_timer_stop(); | 458 | esb_timer_stop(); |
477 | printk(KERN_INFO PFX | 459 | printk(KERN_INFO PFX |
@@ -479,8 +461,6 @@ static int __init watchdog_init(void) | |||
479 | BASEADDR, heartbeat, nowayout); | 461 | BASEADDR, heartbeat, nowayout); |
480 | return 0; | 462 | return 0; |
481 | 463 | ||
482 | err_notifier: | ||
483 | unregister_reboot_notifier(&esb_notifier); | ||
484 | err_unmap: | 464 | err_unmap: |
485 | iounmap(BASEADDR); | 465 | iounmap(BASEADDR); |
486 | /* err_release: */ | 466 | /* err_release: */ |
@@ -492,7 +472,7 @@ err_unmap: | |||
492 | return ret; | 472 | return ret; |
493 | } | 473 | } |
494 | 474 | ||
495 | static void __exit watchdog_cleanup(void) | 475 | static int __devexit esb_remove(struct platform_device *dev) |
496 | { | 476 | { |
497 | /* Stop the timer before we leave */ | 477 | /* Stop the timer before we leave */ |
498 | if (!nowayout) | 478 | if (!nowayout) |
@@ -500,11 +480,58 @@ static void __exit watchdog_cleanup(void) | |||
500 | 480 | ||
501 | /* Deregister */ | 481 | /* Deregister */ |
502 | misc_deregister(&esb_miscdev); | 482 | misc_deregister(&esb_miscdev); |
503 | unregister_reboot_notifier(&esb_notifier); | ||
504 | iounmap(BASEADDR); | 483 | iounmap(BASEADDR); |
505 | pci_release_region(esb_pci, 0); | 484 | pci_release_region(esb_pci, 0); |
506 | pci_disable_device(esb_pci); | 485 | pci_disable_device(esb_pci); |
507 | pci_dev_put(esb_pci); | 486 | pci_dev_put(esb_pci); |
487 | return 0; | ||
488 | } | ||
489 | |||
490 | static void esb_shutdown(struct platform_device *dev) | ||
491 | { | ||
492 | esb_timer_stop(); | ||
493 | } | ||
494 | |||
495 | static struct platform_driver esb_platform_driver = { | ||
496 | .probe = esb_probe, | ||
497 | .remove = __devexit_p(esb_remove), | ||
498 | .shutdown = esb_shutdown, | ||
499 | .driver = { | ||
500 | .owner = THIS_MODULE, | ||
501 | .name = ESB_MODULE_NAME, | ||
502 | }, | ||
503 | }; | ||
504 | |||
505 | static int __init watchdog_init(void) | ||
506 | { | ||
507 | int err; | ||
508 | |||
509 | printk(KERN_INFO PFX "Intel 6300ESB WatchDog Timer Driver v%s\n", | ||
510 | ESB_VERSION); | ||
511 | |||
512 | err = platform_driver_register(&esb_platform_driver); | ||
513 | if (err) | ||
514 | return err; | ||
515 | |||
516 | esb_platform_device = platform_device_register_simple(ESB_MODULE_NAME, | ||
517 | -1, NULL, 0); | ||
518 | if (IS_ERR(esb_platform_device)) { | ||
519 | err = PTR_ERR(esb_platform_device); | ||
520 | goto unreg_platform_driver; | ||
521 | } | ||
522 | |||
523 | return 0; | ||
524 | |||
525 | unreg_platform_driver: | ||
526 | platform_driver_unregister(&esb_platform_driver); | ||
527 | return err; | ||
528 | } | ||
529 | |||
530 | static void __exit watchdog_cleanup(void) | ||
531 | { | ||
532 | platform_device_unregister(esb_platform_device); | ||
533 | platform_driver_unregister(&esb_platform_driver); | ||
534 | printk(KERN_INFO PFX "Watchdog Module Unloaded.\n"); | ||
508 | } | 535 | } |
509 | 536 | ||
510 | module_init(watchdog_init); | 537 | module_init(watchdog_init); |