diff options
| author | Linus Torvalds <torvalds@g5.osdl.org> | 2006-10-23 18:56:26 -0400 |
|---|---|---|
| committer | Linus Torvalds <torvalds@g5.osdl.org> | 2006-10-23 18:56:26 -0400 |
| commit | 6d03a68e6d5528630955452ec4b768dbde0dc00c (patch) | |
| tree | 56e843eec067ddba67fc098196b17e22c56d302f | |
| parent | 0c0e4668e0e65dd1404e8cf066d147235f95561d (diff) | |
| parent | cbf40d3f04c2c76a58f1183bb4a9a82fefb842e3 (diff) | |
Merge git://git.kernel.org/pub/scm/linux/kernel/git/wim/linux-2.6-watchdog
* git://git.kernel.org/pub/scm/linux/kernel/git/wim/linux-2.6-watchdog: (33 commits)
[WATCHDOG] remove experimental on iTCO_wdt.c
[WATCHDOG] Atmel AT91RM9200 rename.
[WATCHDOG] includes for sample watchdog program.
[WATCHDOG] watchdog/iTCO_wdt: fix bug related to gcc uninit warning
[WATCHDOG] add ich8 support to iTCO_wdt.c (patch 2)
[WATCHDOG] add ich8 support to iTCO_wdt.c
[WATCHDOG] ioremap balanced with iounmap for drivers/char/watchdog/s3c2410_wdt.c
[WATCHDOG] w83697hf/hg WDT driver - Kconfig patch
[WATCHDOG] w83697hf/hg WDT driver - autodetect patch
[WATCHDOG] w83697hf/hg WDT driver - patch 16
[WATCHDOG] w83697hf/hg WDT driver - patch 15
[WATCHDOG] w83697hf/hg WDT driver - patch 14
[WATCHDOG] w83697hf/hg WDT driver - patch 13
[WATCHDOG] w83697hf/hg WDT driver - patch 12
[WATCHDOG] w83697hf/hg WDT driver - patch 11
[WATCHDOG] w83697hf/hg WDT driver - patch 10
[WATCHDOG] w83697hf/hg WDT driver - patch 9
[WATCHDOG] w83697hf/hg WDT driver - patch 8
[WATCHDOG] w83697hf/hg WDT driver - patch 7
[WATCHDOG] w83697hf/hg WDT driver - patch 6
...
| -rw-r--r-- | Documentation/watchdog/src/watchdog-simple.c | 2 | ||||
| -rw-r--r-- | arch/arm/configs/at91rm9200dk_defconfig | 2 | ||||
| -rw-r--r-- | arch/arm/configs/at91rm9200ek_defconfig | 2 | ||||
| -rw-r--r-- | arch/arm/configs/csb337_defconfig | 2 | ||||
| -rw-r--r-- | arch/arm/configs/csb637_defconfig | 2 | ||||
| -rw-r--r-- | arch/arm/configs/kafa_defconfig | 2 | ||||
| -rw-r--r-- | arch/arm/configs/onearm_defconfig | 2 | ||||
| -rw-r--r-- | drivers/char/watchdog/Kconfig | 65 | ||||
| -rw-r--r-- | drivers/char/watchdog/Makefile | 4 | ||||
| -rw-r--r-- | drivers/char/watchdog/at91rm9200_wdt.c (renamed from drivers/char/watchdog/at91_wdt.c) | 0 | ||||
| -rw-r--r-- | drivers/char/watchdog/iTCO_wdt.c | 21 | ||||
| -rw-r--r-- | drivers/char/watchdog/s3c2410_wdt.c | 5 | ||||
| -rw-r--r-- | drivers/char/watchdog/smsc37b787_wdt.c | 627 | ||||
| -rw-r--r-- | drivers/char/watchdog/w83627hf_wdt.c | 8 | ||||
| -rw-r--r-- | drivers/char/watchdog/w83697hf_wdt.c | 450 |
15 files changed, 1170 insertions, 24 deletions
diff --git a/Documentation/watchdog/src/watchdog-simple.c b/Documentation/watchdog/src/watchdog-simple.c index 85cf17c486..47801bc7e7 100644 --- a/Documentation/watchdog/src/watchdog-simple.c +++ b/Documentation/watchdog/src/watchdog-simple.c | |||
| @@ -1,4 +1,6 @@ | |||
| 1 | #include <stdio.h> | ||
| 1 | #include <stdlib.h> | 2 | #include <stdlib.h> |
| 3 | #include <unistd.h> | ||
| 2 | #include <fcntl.h> | 4 | #include <fcntl.h> |
| 3 | 5 | ||
| 4 | int main(int argc, const char *argv[]) { | 6 | int main(int argc, const char *argv[]) { |
diff --git a/arch/arm/configs/at91rm9200dk_defconfig b/arch/arm/configs/at91rm9200dk_defconfig index c82e4667f4..b43041476e 100644 --- a/arch/arm/configs/at91rm9200dk_defconfig +++ b/arch/arm/configs/at91rm9200dk_defconfig | |||
| @@ -577,7 +577,7 @@ CONFIG_WATCHDOG_NOWAYOUT=y | |||
| 577 | # Watchdog Device Drivers | 577 | # Watchdog Device Drivers |
| 578 | # | 578 | # |
| 579 | # CONFIG_SOFT_WATCHDOG is not set | 579 | # CONFIG_SOFT_WATCHDOG is not set |
| 580 | CONFIG_AT91_WATCHDOG=y | 580 | CONFIG_AT91RM9200_WATCHDOG=y |
| 581 | 581 | ||
| 582 | # | 582 | # |
| 583 | # USB-based Watchdog Cards | 583 | # USB-based Watchdog Cards |
diff --git a/arch/arm/configs/at91rm9200ek_defconfig b/arch/arm/configs/at91rm9200ek_defconfig index b983fc59aa..d96fc8386e 100644 --- a/arch/arm/configs/at91rm9200ek_defconfig +++ b/arch/arm/configs/at91rm9200ek_defconfig | |||
| @@ -558,7 +558,7 @@ CONFIG_WATCHDOG_NOWAYOUT=y | |||
| 558 | # Watchdog Device Drivers | 558 | # Watchdog Device Drivers |
| 559 | # | 559 | # |
| 560 | # CONFIG_SOFT_WATCHDOG is not set | 560 | # CONFIG_SOFT_WATCHDOG is not set |
| 561 | CONFIG_AT91_WATCHDOG=y | 561 | CONFIG_AT91RM9200_WATCHDOG=y |
| 562 | 562 | ||
| 563 | # | 563 | # |
| 564 | # USB-based Watchdog Cards | 564 | # USB-based Watchdog Cards |
diff --git a/arch/arm/configs/csb337_defconfig b/arch/arm/configs/csb337_defconfig index a2d6fd398f..20e68250d8 100644 --- a/arch/arm/configs/csb337_defconfig +++ b/arch/arm/configs/csb337_defconfig | |||
| @@ -615,7 +615,7 @@ CONFIG_WATCHDOG_NOWAYOUT=y | |||
| 615 | # Watchdog Device Drivers | 615 | # Watchdog Device Drivers |
| 616 | # | 616 | # |
| 617 | # CONFIG_SOFT_WATCHDOG is not set | 617 | # CONFIG_SOFT_WATCHDOG is not set |
| 618 | CONFIG_AT91_WATCHDOG=y | 618 | CONFIG_AT91RM9200_WATCHDOG=y |
| 619 | 619 | ||
| 620 | # | 620 | # |
| 621 | # USB-based Watchdog Cards | 621 | # USB-based Watchdog Cards |
diff --git a/arch/arm/configs/csb637_defconfig b/arch/arm/configs/csb637_defconfig index 2a1ac6c60a..df8595ac03 100644 --- a/arch/arm/configs/csb637_defconfig +++ b/arch/arm/configs/csb637_defconfig | |||
| @@ -615,7 +615,7 @@ CONFIG_WATCHDOG_NOWAYOUT=y | |||
| 615 | # Watchdog Device Drivers | 615 | # Watchdog Device Drivers |
| 616 | # | 616 | # |
| 617 | # CONFIG_SOFT_WATCHDOG is not set | 617 | # CONFIG_SOFT_WATCHDOG is not set |
| 618 | CONFIG_AT91_WATCHDOG=y | 618 | CONFIG_AT91RM9200_WATCHDOG=y |
| 619 | 619 | ||
| 620 | # | 620 | # |
| 621 | # USB-based Watchdog Cards | 621 | # USB-based Watchdog Cards |
diff --git a/arch/arm/configs/kafa_defconfig b/arch/arm/configs/kafa_defconfig index 54fcd75779..a4cdafc154 100644 --- a/arch/arm/configs/kafa_defconfig +++ b/arch/arm/configs/kafa_defconfig | |||
| @@ -560,7 +560,7 @@ CONFIG_WATCHDOG_NOWAYOUT=y | |||
| 560 | # Watchdog Device Drivers | 560 | # Watchdog Device Drivers |
| 561 | # | 561 | # |
| 562 | # CONFIG_SOFT_WATCHDOG is not set | 562 | # CONFIG_SOFT_WATCHDOG is not set |
| 563 | CONFIG_AT91_WATCHDOG=y | 563 | CONFIG_AT91RM9200_WATCHDOG=y |
| 564 | # CONFIG_NVRAM is not set | 564 | # CONFIG_NVRAM is not set |
| 565 | # CONFIG_DTLK is not set | 565 | # CONFIG_DTLK is not set |
| 566 | # CONFIG_R3964 is not set | 566 | # CONFIG_R3964 is not set |
diff --git a/arch/arm/configs/onearm_defconfig b/arch/arm/configs/onearm_defconfig index cb1d94f904..9b9f2155af 100644 --- a/arch/arm/configs/onearm_defconfig +++ b/arch/arm/configs/onearm_defconfig | |||
| @@ -607,7 +607,7 @@ CONFIG_WATCHDOG_NOWAYOUT=y | |||
| 607 | # Watchdog Device Drivers | 607 | # Watchdog Device Drivers |
| 608 | # | 608 | # |
| 609 | # CONFIG_SOFT_WATCHDOG is not set | 609 | # CONFIG_SOFT_WATCHDOG is not set |
| 610 | CONFIG_AT91_WATCHDOG=y | 610 | CONFIG_AT91RM9200_WATCHDOG=y |
| 611 | 611 | ||
| 612 | # | 612 | # |
| 613 | # USB-based Watchdog Cards | 613 | # USB-based Watchdog Cards |
diff --git a/drivers/char/watchdog/Kconfig b/drivers/char/watchdog/Kconfig index 89e46d6dfc..0187b11853 100644 --- a/drivers/char/watchdog/Kconfig +++ b/drivers/char/watchdog/Kconfig | |||
| @@ -13,7 +13,7 @@ config WATCHDOG | |||
| 13 | subsequently opening the file and then failing to write to it for | 13 | subsequently opening the file and then failing to write to it for |
| 14 | longer than 1 minute will result in rebooting the machine. This | 14 | longer than 1 minute will result in rebooting the machine. This |
| 15 | could be useful for a networked machine that needs to come back | 15 | could be useful for a networked machine that needs to come back |
| 16 | online as fast as possible after a lock-up. There's both a watchdog | 16 | on-line as fast as possible after a lock-up. There's both a watchdog |
| 17 | implementation entirely in software (which can sometimes fail to | 17 | implementation entirely in software (which can sometimes fail to |
| 18 | reboot the machine) and a driver for hardware watchdog boards, which | 18 | reboot the machine) and a driver for hardware watchdog boards, which |
| 19 | are more robust and can also keep track of the temperature inside | 19 | are more robust and can also keep track of the temperature inside |
| @@ -60,7 +60,7 @@ config SOFT_WATCHDOG | |||
| 60 | 60 | ||
| 61 | # ARM Architecture | 61 | # ARM Architecture |
| 62 | 62 | ||
| 63 | config AT91_WATCHDOG | 63 | config AT91RM9200_WATCHDOG |
| 64 | tristate "AT91RM9200 watchdog" | 64 | tristate "AT91RM9200 watchdog" |
| 65 | depends on WATCHDOG && ARCH_AT91RM9200 | 65 | depends on WATCHDOG && ARCH_AT91RM9200 |
| 66 | help | 66 | help |
| @@ -71,7 +71,7 @@ config 21285_WATCHDOG | |||
| 71 | tristate "DC21285 watchdog" | 71 | tristate "DC21285 watchdog" |
| 72 | depends on WATCHDOG && FOOTBRIDGE | 72 | depends on WATCHDOG && FOOTBRIDGE |
| 73 | help | 73 | help |
| 74 | The Intel Footbridge chip contains a builtin watchdog circuit. Say Y | 74 | The Intel Footbridge chip contains a built-in watchdog circuit. Say Y |
| 75 | here if you wish to use this. Alternatively say M to compile the | 75 | here if you wish to use this. Alternatively say M to compile the |
| 76 | driver as a module, which will be called wdt285. | 76 | driver as a module, which will be called wdt285. |
| 77 | 77 | ||
| @@ -269,11 +269,11 @@ config IB700_WDT | |||
| 269 | Most people will say N. | 269 | Most people will say N. |
| 270 | 270 | ||
| 271 | config IBMASR | 271 | config IBMASR |
| 272 | tristate "IBM Automatic Server Restart" | 272 | tristate "IBM Automatic Server Restart" |
| 273 | depends on WATCHDOG && X86 | 273 | depends on WATCHDOG && X86 |
| 274 | help | 274 | help |
| 275 | This is the driver for the IBM Automatic Server Restart watchdog | 275 | This is the driver for the IBM Automatic Server Restart watchdog |
| 276 | timer builtin into some eServer xSeries machines. | 276 | timer built-in into some eServer xSeries machines. |
| 277 | 277 | ||
| 278 | To compile this driver as a module, choose M here: the | 278 | To compile this driver as a module, choose M here: the |
| 279 | module will be called ibmasr. | 279 | module will be called ibmasr. |
| @@ -316,13 +316,16 @@ config I8XX_TCO | |||
| 316 | To compile this driver as a module, choose M here: the | 316 | To compile this driver as a module, choose M here: the |
| 317 | module will be called i8xx_tco. | 317 | module will be called i8xx_tco. |
| 318 | 318 | ||
| 319 | Note: This driver will be removed in the near future. Please | ||
| 320 | use the Intel TCO Timer/Watchdog driver. | ||
| 321 | |||
| 319 | config ITCO_WDT | 322 | config ITCO_WDT |
| 320 | tristate "Intel TCO Timer/Watchdog (EXPERIMENTAL)" | 323 | tristate "Intel TCO Timer/Watchdog" |
| 321 | depends on WATCHDOG && (X86 || IA64) && PCI && EXPERIMENTAL | 324 | depends on WATCHDOG && (X86 || IA64) && PCI |
| 322 | ---help--- | 325 | ---help--- |
| 323 | Hardware driver for the intel TCO timer based watchdog devices. | 326 | Hardware driver for the intel TCO timer based watchdog devices. |
| 324 | These drivers are included in the Intel 82801 I/O Controller | 327 | These drivers are included in the Intel 82801 I/O Controller |
| 325 | Hub family 'from ICH0 up to ICH7) and in the Intel 6300ESB | 328 | Hub family (from ICH0 up to ICH8) and in the Intel 6300ESB |
| 326 | controller hub. | 329 | controller hub. |
| 327 | 330 | ||
| 328 | The TCO (Total Cost of Ownership) timer is a watchdog timer | 331 | The TCO (Total Cost of Ownership) timer is a watchdog timer |
| @@ -395,6 +398,26 @@ config CPU5_WDT | |||
| 395 | To compile this driver as a module, choose M here: the | 398 | To compile this driver as a module, choose M here: the |
| 396 | module will be called cpu5wdt. | 399 | module will be called cpu5wdt. |
| 397 | 400 | ||
| 401 | config SMSC37B787_WDT | ||
| 402 | tristate "Winbond SMsC37B787 Watchdog Timer" | ||
| 403 | depends on WATCHDOG && X86 | ||
| 404 | ---help--- | ||
| 405 | This is the driver for the hardware watchdog component on the | ||
| 406 | Winbond SMsC37B787 chipset as used on the NetRunner Mainboard | ||
| 407 | from Vision Systems and maybe others. | ||
| 408 | |||
| 409 | This watchdog simply watches your kernel to make sure it doesn't | ||
| 410 | freeze, and if it does, it reboots your computer after a certain | ||
| 411 | amount of time. | ||
| 412 | |||
| 413 | Usually a userspace daemon will notify the kernel WDT driver that | ||
| 414 | userspace is still alive, at regular intervals. | ||
| 415 | |||
| 416 | To compile this driver as a module, choose M here: the | ||
| 417 | module will be called smsc37b787_wdt. | ||
| 418 | |||
| 419 | Most people will say N. | ||
| 420 | |||
| 398 | config W83627HF_WDT | 421 | config W83627HF_WDT |
| 399 | tristate "W83627HF Watchdog Timer" | 422 | tristate "W83627HF Watchdog Timer" |
| 400 | depends on WATCHDOG && X86 | 423 | depends on WATCHDOG && X86 |
| @@ -410,6 +433,21 @@ config W83627HF_WDT | |||
| 410 | 433 | ||
| 411 | Most people will say N. | 434 | Most people will say N. |
| 412 | 435 | ||
| 436 | config W83697HF_WDT | ||
| 437 | tristate "W83697HF/W83697HG Watchdog Timer" | ||
| 438 | depends on WATCHDOG && X86 | ||
| 439 | ---help--- | ||
| 440 | This is the driver for the hardware watchdog on the W83697HF/HG | ||
| 441 | chipset as used in Dedibox/VIA motherboards (and likely others). | ||
| 442 | This watchdog simply watches your kernel to make sure it doesn't | ||
| 443 | freeze, and if it does, it reboots your computer after a certain | ||
| 444 | amount of time. | ||
| 445 | |||
| 446 | To compile this driver as a module, choose M here: the | ||
| 447 | module will be called w83697hf_wdt. | ||
| 448 | |||
| 449 | Most people will say N. | ||
| 450 | |||
| 413 | config W83877F_WDT | 451 | config W83877F_WDT |
| 414 | tristate "W83877F (EMACS) Watchdog Timer" | 452 | tristate "W83877F (EMACS) Watchdog Timer" |
| 415 | depends on WATCHDOG && X86 | 453 | depends on WATCHDOG && X86 |
| @@ -443,7 +481,7 @@ config MACHZ_WDT | |||
| 443 | depends on WATCHDOG && X86 | 481 | depends on WATCHDOG && X86 |
| 444 | ---help--- | 482 | ---help--- |
| 445 | If you are using a ZF Micro MachZ processor, say Y here, otherwise | 483 | If you are using a ZF Micro MachZ processor, say Y here, otherwise |
| 446 | N. This is the driver for the watchdog timer builtin on that | 484 | N. This is the driver for the watchdog timer built-in on that |
| 447 | processor using ZF-Logic interface. This watchdog simply watches | 485 | processor using ZF-Logic interface. This watchdog simply watches |
| 448 | your kernel to make sure it doesn't freeze, and if it does, it | 486 | your kernel to make sure it doesn't freeze, and if it does, it |
| 449 | reboots your computer after a certain amount of time. | 487 | reboots your computer after a certain amount of time. |
| @@ -472,7 +510,6 @@ config SBC_EPX_C3_WATCHDOG | |||
| 472 | To compile this driver as a module, choose M here: the | 510 | To compile this driver as a module, choose M here: the |
| 473 | module will be called sbc_epx_c3. | 511 | module will be called sbc_epx_c3. |
| 474 | 512 | ||
| 475 | |||
| 476 | # PowerPC Architecture | 513 | # PowerPC Architecture |
| 477 | 514 | ||
| 478 | config 8xx_WDT | 515 | config 8xx_WDT |
| @@ -502,7 +539,7 @@ config WATCHDOG_RTAS | |||
| 502 | help | 539 | help |
| 503 | This driver adds watchdog support for the RTAS watchdog. | 540 | This driver adds watchdog support for the RTAS watchdog. |
| 504 | 541 | ||
| 505 | To compile this driver as a module, choose M here. The module | 542 | To compile this driver as a module, choose M here. The module |
| 506 | will be called wdrtas. | 543 | will be called wdrtas. |
| 507 | 544 | ||
| 508 | # MIPS Architecture | 545 | # MIPS Architecture |
| @@ -556,7 +593,7 @@ config SH_WDT_MMAP | |||
| 556 | help | 593 | help |
| 557 | If you say Y here, user applications will be able to mmap the | 594 | If you say Y here, user applications will be able to mmap the |
| 558 | WDT/CPG registers. | 595 | WDT/CPG registers. |
| 559 | # | 596 | |
| 560 | # SPARC64 Architecture | 597 | # SPARC64 Architecture |
| 561 | 598 | ||
| 562 | config WATCHDOG_CP1XXX | 599 | config WATCHDOG_CP1XXX |
diff --git a/drivers/char/watchdog/Makefile b/drivers/char/watchdog/Makefile index 7f70abad46..3644049704 100644 --- a/drivers/char/watchdog/Makefile +++ b/drivers/char/watchdog/Makefile | |||
| @@ -23,7 +23,7 @@ obj-$(CONFIG_WDTPCI) += wdt_pci.o | |||
| 23 | obj-$(CONFIG_USBPCWATCHDOG) += pcwd_usb.o | 23 | obj-$(CONFIG_USBPCWATCHDOG) += pcwd_usb.o |
| 24 | 24 | ||
| 25 | # ARM Architecture | 25 | # ARM Architecture |
| 26 | obj-$(CONFIG_AT91_WATCHDOG) += at91_wdt.o | 26 | obj-$(CONFIG_AT91RM9200_WATCHDOG) += at91rm9200_wdt.o |
| 27 | obj-$(CONFIG_OMAP_WATCHDOG) += omap_wdt.o | 27 | obj-$(CONFIG_OMAP_WATCHDOG) += omap_wdt.o |
| 28 | obj-$(CONFIG_21285_WATCHDOG) += wdt285.o | 28 | obj-$(CONFIG_21285_WATCHDOG) += wdt285.o |
| 29 | obj-$(CONFIG_977_WATCHDOG) += wdt977.o | 29 | obj-$(CONFIG_977_WATCHDOG) += wdt977.o |
| @@ -53,7 +53,9 @@ obj-$(CONFIG_SCx200_WDT) += scx200_wdt.o | |||
| 53 | obj-$(CONFIG_60XX_WDT) += sbc60xxwdt.o | 53 | obj-$(CONFIG_60XX_WDT) += sbc60xxwdt.o |
| 54 | obj-$(CONFIG_SBC8360_WDT) += sbc8360.o | 54 | obj-$(CONFIG_SBC8360_WDT) += sbc8360.o |
| 55 | obj-$(CONFIG_CPU5_WDT) += cpu5wdt.o | 55 | obj-$(CONFIG_CPU5_WDT) += cpu5wdt.o |
| 56 | obj-$(CONFIG_SMSC37B787_WDT) += smsc37b787_wdt.o | ||
| 56 | obj-$(CONFIG_W83627HF_WDT) += w83627hf_wdt.o | 57 | obj-$(CONFIG_W83627HF_WDT) += w83627hf_wdt.o |
| 58 | obj-$(CONFIG_W83697HF_WDT) += w83697hf_wdt.o | ||
| 57 | obj-$(CONFIG_W83877F_WDT) += w83877f_wdt.o | 59 | obj-$(CONFIG_W83877F_WDT) += w83877f_wdt.o |
| 58 | obj-$(CONFIG_W83977F_WDT) += w83977f_wdt.o | 60 | obj-$(CONFIG_W83977F_WDT) += w83977f_wdt.o |
| 59 | obj-$(CONFIG_MACHZ_WDT) += machzwd.o | 61 | obj-$(CONFIG_MACHZ_WDT) += machzwd.o |
diff --git a/drivers/char/watchdog/at91_wdt.c b/drivers/char/watchdog/at91rm9200_wdt.c index 4e7a1145e7..4e7a1145e7 100644 --- a/drivers/char/watchdog/at91_wdt.c +++ b/drivers/char/watchdog/at91rm9200_wdt.c | |||
diff --git a/drivers/char/watchdog/iTCO_wdt.c b/drivers/char/watchdog/iTCO_wdt.c index aaac94db0d..b6f29cb8bd 100644 --- a/drivers/char/watchdog/iTCO_wdt.c +++ b/drivers/char/watchdog/iTCO_wdt.c | |||
| @@ -35,6 +35,10 @@ | |||
| 35 | * 82801GDH (ICH7DH) : document number 307013-002, 307014-009, | 35 | * 82801GDH (ICH7DH) : document number 307013-002, 307014-009, |
| 36 | * 82801GBM (ICH7-M) : document number 307013-002, 307014-009, | 36 | * 82801GBM (ICH7-M) : document number 307013-002, 307014-009, |
| 37 | * 82801GHM (ICH7-M DH) : document number 307013-002, 307014-009, | 37 | * 82801GHM (ICH7-M DH) : document number 307013-002, 307014-009, |
| 38 | * 82801HB (ICH8) : document number 313056-002, 313057-004, | ||
| 39 | * 82801HR (ICH8R) : document number 313056-002, 313057-004, | ||
| 40 | * 82801HH (ICH8DH) : document number 313056-002, 313057-004, | ||
| 41 | * 82801HO (ICH8DO) : document number 313056-002, 313057-004, | ||
| 38 | * 6300ESB (6300ESB) : document number 300641-003 | 42 | * 6300ESB (6300ESB) : document number 300641-003 |
| 39 | */ | 43 | */ |
| 40 | 44 | ||
| @@ -45,7 +49,7 @@ | |||
| 45 | /* Module and version information */ | 49 | /* Module and version information */ |
| 46 | #define DRV_NAME "iTCO_wdt" | 50 | #define DRV_NAME "iTCO_wdt" |
| 47 | #define DRV_VERSION "1.00" | 51 | #define DRV_VERSION "1.00" |
| 48 | #define DRV_RELDATE "30-Jul-2006" | 52 | #define DRV_RELDATE "08-Oct-2006" |
| 49 | #define PFX DRV_NAME ": " | 53 | #define PFX DRV_NAME ": " |
| 50 | 54 | ||
| 51 | /* Includes */ | 55 | /* Includes */ |
| @@ -85,6 +89,9 @@ enum iTCO_chipsets { | |||
| 85 | TCO_ICH7, /* ICH7 & ICH7R */ | 89 | TCO_ICH7, /* ICH7 & ICH7R */ |
| 86 | TCO_ICH7M, /* ICH7-M */ | 90 | TCO_ICH7M, /* ICH7-M */ |
| 87 | TCO_ICH7MDH, /* ICH7-M DH */ | 91 | TCO_ICH7MDH, /* ICH7-M DH */ |
| 92 | TCO_ICH8, /* ICH8 & ICH8R */ | ||
| 93 | TCO_ICH8DH, /* ICH8DH */ | ||
| 94 | TCO_ICH8DO, /* ICH8DO */ | ||
| 88 | }; | 95 | }; |
| 89 | 96 | ||
| 90 | static struct { | 97 | static struct { |
| @@ -108,6 +115,9 @@ static struct { | |||
| 108 | {"ICH7 or ICH7R", 2}, | 115 | {"ICH7 or ICH7R", 2}, |
| 109 | {"ICH7-M", 2}, | 116 | {"ICH7-M", 2}, |
| 110 | {"ICH7-M DH", 2}, | 117 | {"ICH7-M DH", 2}, |
| 118 | {"ICH8 or ICH8R", 2}, | ||
| 119 | {"ICH8DH", 2}, | ||
| 120 | {"ICH8DO", 2}, | ||
| 111 | {NULL,0} | 121 | {NULL,0} |
| 112 | }; | 122 | }; |
| 113 | 123 | ||
| @@ -135,6 +145,9 @@ static struct pci_device_id iTCO_wdt_pci_tbl[] = { | |||
| 135 | { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ICH7_0, PCI_ANY_ID, PCI_ANY_ID, 0, 0, TCO_ICH7 }, | 145 | { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ICH7_0, PCI_ANY_ID, PCI_ANY_ID, 0, 0, TCO_ICH7 }, |
| 136 | { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ICH7_1, PCI_ANY_ID, PCI_ANY_ID, 0, 0, TCO_ICH7M }, | 146 | { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ICH7_1, PCI_ANY_ID, PCI_ANY_ID, 0, 0, TCO_ICH7M }, |
| 137 | { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ICH7_31, PCI_ANY_ID, PCI_ANY_ID, 0, 0, TCO_ICH7MDH }, | 147 | { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ICH7_31, PCI_ANY_ID, PCI_ANY_ID, 0, 0, TCO_ICH7MDH }, |
| 148 | { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ICH8_0, PCI_ANY_ID, PCI_ANY_ID, 0, 0, TCO_ICH8 }, | ||
| 149 | { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ICH8_2, PCI_ANY_ID, PCI_ANY_ID, 0, 0, TCO_ICH8DH }, | ||
| 150 | { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ICH8_3, PCI_ANY_ID, PCI_ANY_ID, 0, 0, TCO_ICH8DO }, | ||
| 138 | { 0, }, /* End of list */ | 151 | { 0, }, /* End of list */ |
| 139 | }; | 152 | }; |
| 140 | MODULE_DEVICE_TABLE (pci, iTCO_wdt_pci_tbl); | 153 | MODULE_DEVICE_TABLE (pci, iTCO_wdt_pci_tbl); |
| @@ -355,7 +368,8 @@ static int iTCO_wdt_get_timeleft (int *time_left) | |||
| 355 | spin_unlock(&iTCO_wdt_private.io_lock); | 368 | spin_unlock(&iTCO_wdt_private.io_lock); |
| 356 | 369 | ||
| 357 | *time_left = (val8 * 6) / 10; | 370 | *time_left = (val8 * 6) / 10; |
| 358 | } | 371 | } else |
| 372 | return -EINVAL; | ||
| 359 | return 0; | 373 | return 0; |
| 360 | } | 374 | } |
| 361 | 375 | ||
| @@ -426,7 +440,6 @@ static int iTCO_wdt_ioctl (struct inode *inode, struct file *file, | |||
| 426 | { | 440 | { |
| 427 | int new_options, retval = -EINVAL; | 441 | int new_options, retval = -EINVAL; |
| 428 | int new_heartbeat; | 442 | int new_heartbeat; |
| 429 | int time_left; | ||
| 430 | void __user *argp = (void __user *)arg; | 443 | void __user *argp = (void __user *)arg; |
| 431 | int __user *p = argp; | 444 | int __user *p = argp; |
| 432 | static struct watchdog_info ident = { | 445 | static struct watchdog_info ident = { |
| @@ -486,6 +499,8 @@ static int iTCO_wdt_ioctl (struct inode *inode, struct file *file, | |||
| 486 | 499 | ||
| 487 | case WDIOC_GETTIMELEFT: | 500 | case WDIOC_GETTIMELEFT: |
| 488 | { | 501 | { |
| 502 | int time_left; | ||
| 503 | |||
| 489 | if (iTCO_wdt_get_timeleft(&time_left)) | 504 | if (iTCO_wdt_get_timeleft(&time_left)) |
| 490 | return -EINVAL; | 505 | return -EINVAL; |
| 491 | 506 | ||
diff --git a/drivers/char/watchdog/s3c2410_wdt.c b/drivers/char/watchdog/s3c2410_wdt.c index 68b1ca976d..18cb050c38 100644 --- a/drivers/char/watchdog/s3c2410_wdt.c +++ b/drivers/char/watchdog/s3c2410_wdt.c | |||
| @@ -380,18 +380,21 @@ static int s3c2410wdt_probe(struct platform_device *pdev) | |||
| 380 | res = platform_get_resource(pdev, IORESOURCE_IRQ, 0); | 380 | res = platform_get_resource(pdev, IORESOURCE_IRQ, 0); |
| 381 | if (res == NULL) { | 381 | if (res == NULL) { |
| 382 | printk(KERN_INFO PFX "failed to get irq resource\n"); | 382 | printk(KERN_INFO PFX "failed to get irq resource\n"); |
| 383 | iounmap(wdt_base); | ||
| 383 | return -ENOENT; | 384 | return -ENOENT; |
| 384 | } | 385 | } |
| 385 | 386 | ||
| 386 | ret = request_irq(res->start, s3c2410wdt_irq, 0, pdev->name, pdev); | 387 | ret = request_irq(res->start, s3c2410wdt_irq, 0, pdev->name, pdev); |
| 387 | if (ret != 0) { | 388 | if (ret != 0) { |
| 388 | printk(KERN_INFO PFX "failed to install irq (%d)\n", ret); | 389 | printk(KERN_INFO PFX "failed to install irq (%d)\n", ret); |
| 390 | iounmap(wdt_base); | ||
| 389 | return ret; | 391 | return ret; |
| 390 | } | 392 | } |
| 391 | 393 | ||
| 392 | wdt_clock = clk_get(&pdev->dev, "watchdog"); | 394 | wdt_clock = clk_get(&pdev->dev, "watchdog"); |
| 393 | if (wdt_clock == NULL) { | 395 | if (wdt_clock == NULL) { |
| 394 | printk(KERN_INFO PFX "failed to find watchdog clock source\n"); | 396 | printk(KERN_INFO PFX "failed to find watchdog clock source\n"); |
| 397 | iounmap(wdt_base); | ||
| 395 | return -ENOENT; | 398 | return -ENOENT; |
| 396 | } | 399 | } |
| 397 | 400 | ||
| @@ -415,6 +418,7 @@ static int s3c2410wdt_probe(struct platform_device *pdev) | |||
| 415 | if (ret) { | 418 | if (ret) { |
| 416 | printk (KERN_ERR PFX "cannot register miscdev on minor=%d (%d)\n", | 419 | printk (KERN_ERR PFX "cannot register miscdev on minor=%d (%d)\n", |
| 417 | WATCHDOG_MINOR, ret); | 420 | WATCHDOG_MINOR, ret); |
| 421 | iounmap(wdt_base); | ||
| 418 | return ret; | 422 | return ret; |
| 419 | } | 423 | } |
| 420 | 424 | ||
| @@ -451,6 +455,7 @@ static int s3c2410wdt_remove(struct platform_device *dev) | |||
| 451 | wdt_clock = NULL; | 455 | wdt_clock = NULL; |
| 452 | } | 456 | } |
| 453 | 457 | ||
| 458 | iounmap(wdt_base); | ||
| 454 | misc_deregister(&s3c2410wdt_miscdev); | 459 | misc_deregister(&s3c2410wdt_miscdev); |
| 455 | return 0; | 460 | return 0; |
| 456 | } | 461 | } |
diff --git a/drivers/char/watchdog/smsc37b787_wdt.c b/drivers/char/watchdog/smsc37b787_wdt.c new file mode 100644 index 0000000000..9f56913b48 --- /dev/null +++ b/drivers/char/watchdog/smsc37b787_wdt.c | |||
| @@ -0,0 +1,627 @@ | |||
| 1 | /* | ||
| 2 | * SMsC 37B787 Watchdog Timer driver for Linux 2.6.x.x | ||
| 3 | * | ||
| 4 | * Based on acquirewdt.c by Alan Cox <alan@redhat.com> | ||
| 5 | * and some other existing drivers | ||
| 6 | * | ||
| 7 | * This program is free software; you can redistribute it and/or | ||
| 8 | * modify it under the terms of the GNU General Public License | ||
| 9 | * as published by the Free Software Foundation; either version | ||
| 10 | * 2 of the License, or (at your option) any later version. | ||
| 11 | * | ||
| 12 | * The authors do NOT admit liability nor provide warranty for | ||
| 13 | * any of this software. This material is provided "AS-IS" in | ||
| 14 | * the hope that it may be useful for others. | ||
| 15 | * | ||
| 16 | * (C) Copyright 2003-2006 Sven Anders <anders@anduras.de> | ||
| 17 | * | ||
| 18 | * History: | ||
| 19 | * 2003 - Created version 1.0 for Linux 2.4.x. | ||
| 20 | * 2006 - Ported to Linux 2.6, added nowayout and MAGICCLOSE | ||
| 21 | * features. Released version 1.1 | ||
| 22 | * | ||
| 23 | * Theory of operation: | ||
| 24 | * | ||
| 25 | * A Watchdog Timer (WDT) is a hardware circuit that can | ||
| 26 | * reset the computer system in case of a software fault. | ||
| 27 | * You probably knew that already. | ||
| 28 | * | ||
| 29 | * Usually a userspace daemon will notify the kernel WDT driver | ||
| 30 | * via the /dev/watchdog special device file that userspace is | ||
| 31 | * still alive, at regular intervals. When such a notification | ||
| 32 | * occurs, the driver will usually tell the hardware watchdog | ||
| 33 | * that everything is in order, and that the watchdog should wait | ||
| 34 | * for yet another little while to reset the system. | ||
| 35 | * If userspace fails (RAM error, kernel bug, whatever), the | ||
| 36 | * notifications cease to occur, and the hardware watchdog will | ||
| 37 | * reset the system (causing a reboot) after the timeout occurs. | ||
| 38 | * | ||
| 39 | * Create device with: | ||
| 40 | * mknod /dev/watchdog c 10 130 | ||
| 41 | * | ||
| 42 | * For an example userspace keep-alive daemon, see: | ||
| 43 | * Documentation/watchdog/watchdog.txt | ||
| 44 | */ | ||
| 45 | |||
| 46 | #include <linux/module.h> | ||
| 47 | #include <linux/moduleparam.h> | ||
| 48 | #include <linux/types.h> | ||
| 49 | #include <linux/miscdevice.h> | ||
| 50 | #include <linux/watchdog.h> | ||
| 51 | #include <linux/delay.h> | ||
| 52 | #include <linux/fs.h> | ||
| 53 | #include <linux/ioport.h> | ||
| 54 | #include <linux/notifier.h> | ||
| 55 | #include <linux/reboot.h> | ||
| 56 | #include <linux/init.h> | ||
| 57 | #include <linux/spinlock.h> | ||
| 58 | |||
| 59 | #include <asm/io.h> | ||
| 60 | #include <asm/uaccess.h> | ||
| 61 | #include <asm/system.h> | ||
| 62 | |||
| 63 | /* enable support for minutes as units? */ | ||
| 64 | /* (does not always work correctly, so disabled by default!) */ | ||
| 65 | #define SMSC_SUPPORT_MINUTES | ||
| 66 | #undef SMSC_SUPPORT_MINUTES | ||
| 67 | |||
| 68 | #define MAX_TIMEOUT 255 | ||
| 69 | |||
| 70 | #define UNIT_SECOND 0 | ||
| 71 | #define UNIT_MINUTE 1 | ||
| 72 | |||
| 73 | #define MODNAME "smsc37b787_wdt: " | ||
| 74 | #define VERSION "1.1" | ||
| 75 | |||
| 76 | #define IOPORT 0x3F0 | ||
| 77 | #define IOPORT_SIZE 2 | ||
| 78 | #define IODEV_NO 8 | ||
| 79 | |||
| 80 | static int unit = UNIT_SECOND; /* timer's unit */ | ||
| 81 | static int timeout = 60; /* timeout value: default is 60 "units" */ | ||
| 82 | static unsigned long timer_enabled = 0; /* is the timer enabled? */ | ||
| 83 | |||
| 84 | static char expect_close; /* is the close expected? */ | ||
| 85 | |||
| 86 | static spinlock_t io_lock; /* to guard the watchdog from io races */ | ||
| 87 | |||
| 88 | static int nowayout = WATCHDOG_NOWAYOUT; | ||
| 89 | |||
| 90 | /* -- Low level function ----------------------------------------*/ | ||
| 91 | |||
| 92 | /* unlock the IO chip */ | ||
| 93 | |||
| 94 | static inline void open_io_config(void) | ||
| 95 | { | ||
| 96 | outb(0x55, IOPORT); | ||
| 97 | mdelay(1); | ||
| 98 | outb(0x55, IOPORT); | ||
| 99 | } | ||
| 100 | |||
| 101 | /* lock the IO chip */ | ||
| 102 | static inline void close_io_config(void) | ||
| 103 | { | ||
| 104 | outb(0xAA, IOPORT); | ||
| 105 | } | ||
| 106 | |||
| 107 | /* select the IO device */ | ||
| 108 | static inline void select_io_device(unsigned char devno) | ||
| 109 | { | ||
| 110 | outb(0x07, IOPORT); | ||
| 111 | outb(devno, IOPORT+1); | ||
| 112 | } | ||
| 113 | |||
| 114 | /* write to the control register */ | ||
| 115 | static inline void write_io_cr(unsigned char reg, unsigned char data) | ||
| 116 | { | ||
| 117 | outb(reg, IOPORT); | ||
| 118 | outb(data, IOPORT+1); | ||
| 119 | } | ||
| 120 | |||
| 121 | /* read from the control register */ | ||
| 122 | static inline char read_io_cr(unsigned char reg) | ||
| 123 | { | ||
| 124 | outb(reg, IOPORT); | ||
| 125 | return inb(IOPORT+1); | ||
| 126 | } | ||
| 127 | |||
| 128 | /* -- Medium level functions ------------------------------------*/ | ||
| 129 | |||
| 130 | static inline void gpio_bit12(unsigned char reg) | ||
| 131 | { | ||
| 132 | // -- General Purpose I/O Bit 1.2 -- | ||
| 133 | // Bit 0, In/Out: 0 = Output, 1 = Input | ||
| 134 | // Bit 1, Polarity: 0 = No Invert, 1 = Invert | ||
| 135 | // Bit 2, Group Enable Intr.: 0 = Disable, 1 = Enable | ||
| 136 | // Bit 3/4, Function select: 00 = GPI/O, 01 = WDT, 10 = P17, | ||
| 137 | // 11 = Either Edge Triggered Intr. 2 | ||
| 138 | // Bit 5/6 (Reserved) | ||
| 139 | // Bit 7, Output Type: 0 = Push Pull Bit, 1 = Open Drain | ||
| 140 | write_io_cr(0xE2, reg); | ||
| 141 | } | ||
| 142 | |||
| 143 | static inline void gpio_bit13(unsigned char reg) | ||
| 144 | { | ||
| 145 | // -- General Purpose I/O Bit 1.3 -- | ||
| 146 | // Bit 0, In/Out: 0 = Output, 1 = Input | ||
| 147 | // Bit 1, Polarity: 0 = No Invert, 1 = Invert | ||
| 148 | // Bit 2, Group Enable Intr.: 0 = Disable, 1 = Enable | ||
| 149 | // Bit 3, Function select: 0 = GPI/O, 1 = LED | ||
| 150 | // Bit 4-6 (Reserved) | ||
| 151 | // Bit 7, Output Type: 0 = Push Pull Bit, 1 = Open Drain | ||
| 152 | write_io_cr(0xE3, reg); | ||
| 153 | } | ||
| 154 | |||
| 155 | static inline void wdt_timer_units(unsigned char new_units) | ||
| 156 | { | ||
| 157 | // -- Watchdog timer units -- | ||
| 158 | // Bit 0-6 (Reserved) | ||
| 159 | // Bit 7, WDT Time-out Value Units Select | ||
| 160 | // (0 = Minutes, 1 = Seconds) | ||
| 161 | write_io_cr(0xF1, new_units); | ||
| 162 | } | ||
| 163 | |||
| 164 | static inline void wdt_timeout_value(unsigned char new_timeout) | ||
| 165 | { | ||
| 166 | // -- Watchdog Timer Time-out Value -- | ||
| 167 | // Bit 0-7 Binary coded units (0=Disabled, 1..255) | ||
| 168 | write_io_cr(0xF2, new_timeout); | ||
| 169 | } | ||
| 170 | |||
| 171 | static inline void wdt_timer_conf(unsigned char conf) | ||
| 172 | { | ||
| 173 | // -- Watchdog timer configuration -- | ||
| 174 | // Bit 0 Joystick enable: 0* = No Reset, 1 = Reset WDT upon Gameport I/O | ||
| 175 | // Bit 1 Keyboard enable: 0* = No Reset, 1 = Reset WDT upon KBD Intr. | ||
| 176 | // Bit 2 Mouse enable: 0* = No Reset, 1 = Reset WDT upon Mouse Intr. | ||
| 177 | // Bit 3 Reset the timer | ||
| 178 | // (Wrong in SMsC documentation? Given as: PowerLED Timout Enabled) | ||
| 179 | // Bit 4-7 WDT Interrupt Mapping: (0000* = Disabled, | ||
| 180 | // 0001=IRQ1, 0010=(Invalid), 0011=IRQ3 to 1111=IRQ15) | ||
| 181 | write_io_cr(0xF3, conf); | ||
| 182 | } | ||
| 183 | |||
| 184 | static inline void wdt_timer_ctrl(unsigned char reg) | ||
| 185 | { | ||
| 186 | // -- Watchdog timer control -- | ||
| 187 | // Bit 0 Status Bit: 0 = Timer counting, 1 = Timeout occured | ||
| 188 | // Bit 1 Power LED Toggle: 0 = Disable Toggle, 1 = Toggle at 1 Hz | ||
| 189 | // Bit 2 Force Timeout: 1 = Forces WD timeout event (self-cleaning) | ||
| 190 | // Bit 3 P20 Force Timeout enabled: | ||
| 191 | // 0 = P20 activity does not generate the WD timeout event | ||
| 192 | // 1 = P20 Allows rising edge of P20, from the keyboard | ||
| 193 | // controller, to force the WD timeout event. | ||
| 194 | // Bit 4 (Reserved) | ||
| 195 | // -- Soft power management -- | ||
| 196 | // Bit 5 Stop Counter: 1 = Stop software power down counter | ||
| 197 | // set via register 0xB8, (self-cleaning) | ||
| 198 | // (Upon read: 0 = Counter running, 1 = Counter stopped) | ||
| 199 | // Bit 6 Restart Counter: 1 = Restart software power down counter | ||
| 200 | // set via register 0xB8, (self-cleaning) | ||
| 201 | // Bit 7 SPOFF: 1 = Force software power down (self-cleaning) | ||
| 202 | |||
| 203 | write_io_cr(0xF4, reg); | ||
| 204 | } | ||
| 205 | |||
| 206 | /* -- Higher level functions ------------------------------------*/ | ||
| 207 | |||
| 208 | /* initialize watchdog */ | ||
| 209 | |||
| 210 | static void wb_smsc_wdt_initialize(void) | ||
| 211 | { | ||
| 212 | unsigned char old; | ||
| 213 | |||
| 214 | spin_lock(&io_lock); | ||
| 215 | open_io_config(); | ||
| 216 | select_io_device(IODEV_NO); | ||
| 217 | |||
| 218 | // enable the watchdog | ||
| 219 | gpio_bit13(0x08); // Select pin 80 = LED not GPIO | ||
| 220 | gpio_bit12(0x0A); // Set pin 79 = WDT not GPIO/Output/Polarity=Invert | ||
| 221 | |||
| 222 | // disable the timeout | ||
| 223 | wdt_timeout_value(0); | ||
| 224 | |||
| 225 | // reset control register | ||
| 226 | wdt_timer_ctrl(0x00); | ||
| 227 | |||
| 228 | // reset configuration register | ||
| 229 | wdt_timer_conf(0x00); | ||
| 230 | |||
| 231 | // read old (timer units) register | ||
| 232 | old = read_io_cr(0xF1) & 0x7F; | ||
| 233 | if (unit == UNIT_SECOND) old |= 0x80; // set to seconds | ||
| 234 | |||
| 235 | // set the watchdog timer units | ||
| 236 | wdt_timer_units(old); | ||
| 237 | |||
| 238 | close_io_config(); | ||
| 239 | spin_unlock(&io_lock); | ||
| 240 | } | ||
| 241 | |||
| 242 | /* shutdown the watchdog */ | ||
| 243 | |||
| 244 | static void wb_smsc_wdt_shutdown(void) | ||
| 245 | { | ||
| 246 | spin_lock(&io_lock); | ||
| 247 | open_io_config(); | ||
| 248 | select_io_device(IODEV_NO); | ||
| 249 | |||
| 250 | // disable the watchdog | ||
| 251 | gpio_bit13(0x09); | ||
| 252 | gpio_bit12(0x09); | ||
| 253 | |||
| 254 | // reset watchdog config register | ||
| 255 | wdt_timer_conf(0x00); | ||
| 256 | |||
| 257 | // reset watchdog control register | ||
| 258 | wdt_timer_ctrl(0x00); | ||
| 259 | |||
| 260 | // disable timeout | ||
| 261 | wdt_timeout_value(0x00); | ||
| 262 | |||
| 263 | close_io_config(); | ||
| 264 | spin_unlock(&io_lock); | ||
| 265 | } | ||
| 266 | |||
| 267 | /* set timeout => enable watchdog */ | ||
| 268 | |||
| 269 | static void wb_smsc_wdt_set_timeout(unsigned char new_timeout) | ||
| 270 | { | ||
| 271 | spin_lock(&io_lock); | ||
| 272 | open_io_config(); | ||
| 273 | select_io_device(IODEV_NO); | ||
| 274 | |||
| 275 | // set Power LED to blink, if we enable the timeout | ||
| 276 | wdt_timer_ctrl((new_timeout == 0) ? 0x00 : 0x02); | ||
| 277 | |||
| 278 | // set timeout value | ||
| 279 | wdt_timeout_value(new_timeout); | ||
| 280 | |||
| 281 | close_io_config(); | ||
| 282 | spin_unlock(&io_lock); | ||
| 283 | } | ||
| 284 | |||
| 285 | /* get timeout */ | ||
| 286 | |||
| 287 | static unsigned char wb_smsc_wdt_get_timeout(void) | ||
| 288 | { | ||
| 289 | unsigned char set_timeout; | ||
| 290 | |||
| 291 | spin_lock(&io_lock); | ||
| 292 | open_io_config(); | ||
| 293 | select_io_device(IODEV_NO); | ||
| 294 | set_timeout = read_io_cr(0xF2); | ||
| 295 | close_io_config(); | ||
| 296 | spin_unlock(&io_lock); | ||
| 297 | |||
| 298 | return set_timeout; | ||
| 299 | } | ||
| 300 | |||
| 301 | /* disable watchdog */ | ||
| 302 | |||
| 303 | static void wb_smsc_wdt_disable(void) | ||
| 304 | { | ||
| 305 | // set the timeout to 0 to disable the watchdog | ||
| 306 | wb_smsc_wdt_set_timeout(0); | ||
| 307 | } | ||
| 308 | |||
| 309 | /* enable watchdog by setting the current timeout */ | ||
| 310 | |||
| 311 | static void wb_smsc_wdt_enable(void) | ||
| 312 | { | ||
| 313 | // set the current timeout... | ||
| 314 | wb_smsc_wdt_set_timeout(timeout); | ||
| 315 | } | ||
| 316 | |||
| 317 | /* reset the timer */ | ||
| 318 | |||
| 319 | static void wb_smsc_wdt_reset_timer(void) | ||
| 320 | { | ||
| 321 | spin_lock(&io_lock); | ||
| 322 | open_io_config(); | ||
| 323 | select_io_device(IODEV_NO); | ||
| 324 | |||
| 325 | // reset the timer | ||
| 326 | wdt_timeout_value(timeout); | ||
| 327 | wdt_timer_conf(0x08); | ||
| 328 | |||
| 329 | close_io_config(); | ||
| 330 | spin_unlock(&io_lock); | ||
| 331 | } | ||
| 332 | |||
| 333 | /* return, if the watchdog is enabled (timeout is set...) */ | ||
| 334 | |||
| 335 | static int wb_smsc_wdt_status(void) | ||
| 336 | { | ||
| 337 | return (wb_smsc_wdt_get_timeout() == 0) ? 0 : WDIOF_KEEPALIVEPING; | ||
| 338 | } | ||
| 339 | |||
| 340 | |||
| 341 | /* -- File operations -------------------------------------------*/ | ||
| 342 | |||
| 343 | /* open => enable watchdog and set initial timeout */ | ||
| 344 | |||
| 345 | static int wb_smsc_wdt_open(struct inode *inode, struct file *file) | ||
| 346 | { | ||
| 347 | /* /dev/watchdog can only be opened once */ | ||
| 348 | |||
| 349 | if (test_and_set_bit(0, &timer_enabled)) | ||
| 350 | return -EBUSY; | ||
| 351 | |||
| 352 | if (nowayout) | ||
| 353 | __module_get(THIS_MODULE); | ||
| 354 | |||
| 355 | /* Reload and activate timer */ | ||
| 356 | wb_smsc_wdt_enable(); | ||
| 357 | |||
| 358 | printk(KERN_INFO MODNAME "Watchdog enabled. Timeout set to %d %s.\n", timeout, (unit == UNIT_SECOND) ? "second(s)" : "minute(s)"); | ||
| 359 | |||
| 360 | return nonseekable_open(inode, file); | ||
| 361 | } | ||
| 362 | |||
| 363 | /* close => shut off the timer */ | ||
| 364 | |||
| 365 | static int wb_smsc_wdt_release(struct inode *inode, struct file *file) | ||
| 366 | { | ||
| 367 | /* Shut off the timer. */ | ||
| 368 | |||
| 369 | if (expect_close == 42) { | ||
| 370 | wb_smsc_wdt_disable(); | ||
| 371 | printk(KERN_INFO MODNAME "Watchdog disabled, sleeping again...\n"); | ||
| 372 | } else { | ||
| 373 | printk(KERN_CRIT MODNAME "Unexpected close, not stopping watchdog!\n"); | ||
| 374 | wb_smsc_wdt_reset_timer(); | ||
| 375 | } | ||
| 376 | |||
| 377 | clear_bit(0, &timer_enabled); | ||
| 378 | expect_close = 0; | ||
| 379 | return 0; | ||
| 380 | } | ||
| 381 | |||
| 382 | /* write => update the timer to keep the machine alive */ | ||
| 383 | |||
| 384 | static ssize_t wb_smsc_wdt_write(struct file *file, const char __user *data, | ||
| 385 | size_t len, loff_t *ppos) | ||
| 386 | { | ||
| 387 | /* See if we got the magic character 'V' and reload the timer */ | ||
| 388 | if (len) { | ||
| 389 | if (!nowayout) { | ||
| 390 | size_t i; | ||
| 391 | |||
| 392 | /* reset expect flag */ | ||
| 393 | expect_close = 0; | ||
| 394 | |||
| 395 | /* scan to see whether or not we got the magic character */ | ||
| 396 | for (i = 0; i != len; i++) { | ||
| 397 | char c; | ||
| 398 | if (get_user(c, data+i)) | ||
| 399 | return -EFAULT; | ||
| 400 | if (c == 'V') | ||
| 401 | expect_close = 42; | ||
| 402 | } | ||
| 403 | } | ||
| 404 | |||
| 405 | /* someone wrote to us, we should reload the timer */ | ||
| 406 | wb_smsc_wdt_reset_timer(); | ||
| 407 | } | ||
| 408 | return len; | ||
| 409 | } | ||
| 410 | |||
| 411 | /* ioctl => control interface */ | ||
| 412 | |||
| 413 | static int wb_smsc_wdt_ioctl(struct inode *inode, struct file *file, | ||
| 414 | unsigned int cmd, unsigned long arg) | ||
| 415 | { | ||
| 416 | int new_timeout; | ||
| 417 | |||
| 418 | union { | ||
| 419 | struct watchdog_info __user *ident; | ||
| 420 | int __user *i; | ||
| 421 | } uarg; | ||
| 422 | |||
| 423 | static struct watchdog_info ident = { | ||
| 424 | .options = WDIOF_KEEPALIVEPING | | ||
| 425 | WDIOF_SETTIMEOUT | | ||
| 426 | WDIOF_MAGICCLOSE, | ||
| 427 | .firmware_version = 0, | ||
| 428 | .identity = "SMsC 37B787 Watchdog" | ||
| 429 | }; | ||
| 430 | |||
| 431 | uarg.i = (int __user *)arg; | ||
| 432 | |||
| 433 | switch (cmd) { | ||
| 434 | default: | ||
| 435 | return -ENOTTY; | ||
| 436 | |||
| 437 | case WDIOC_GETSUPPORT: | ||
| 438 | return copy_to_user(uarg.ident, &ident, | ||
| 439 | sizeof(ident)) ? -EFAULT : 0; | ||
| 440 | |||
| 441 | case WDIOC_GETSTATUS: | ||
| 442 | return put_user(wb_smsc_wdt_status(), uarg.i); | ||
| 443 | |||
| 444 | case WDIOC_GETBOOTSTATUS: | ||
| 445 | return put_user(0, uarg.i); | ||
| 446 | |||
| 447 | case WDIOC_KEEPALIVE: | ||
| 448 | wb_smsc_wdt_reset_timer(); | ||
| 449 | return 0; | ||
| 450 | |||
| 451 | case WDIOC_SETTIMEOUT: | ||
| 452 | if (get_user(new_timeout, uarg.i)) | ||
| 453 | return -EFAULT; | ||
| 454 | |||
| 455 | // the API states this is given in secs | ||
| 456 | if (unit == UNIT_MINUTE) | ||
| 457 | new_timeout /= 60; | ||
| 458 | |||
| 459 | if (new_timeout < 0 || new_timeout > MAX_TIMEOUT) | ||
| 460 | return -EINVAL; | ||
| 461 | |||
| 462 | timeout = new_timeout; | ||
| 463 | wb_smsc_wdt_set_timeout(timeout); | ||
| 464 | |||
| 465 | // fall through and return the new timeout... | ||
| 466 | |||
| 467 | case WDIOC_GETTIMEOUT: | ||
| 468 | |||
| 469 | new_timeout = timeout; | ||
| 470 | |||
| 471 | if (unit == UNIT_MINUTE) | ||
| 472 | new_timeout *= 60; | ||
| 473 | |||
| 474 | return put_user(new_timeout, uarg.i); | ||
| 475 | |||
| 476 | case WDIOC_SETOPTIONS: | ||
| 477 | { | ||
| 478 | int options, retval = -EINVAL; | ||
| 479 | |||
| 480 | if (get_user(options, uarg.i)) | ||
| 481 | return -EFAULT; | ||
| 482 | |||
| 483 | if (options & WDIOS_DISABLECARD) { | ||
| 484 | wb_smsc_wdt_disable(); | ||
| 485 | retval = 0; | ||
| 486 | } | ||
| 487 | |||
| 488 | if (options & WDIOS_ENABLECARD) { | ||
| 489 | wb_smsc_wdt_enable(); | ||
| 490 | retval = 0; | ||
| 491 | } | ||
| 492 | |||
| 493 | return retval; | ||
| 494 | } | ||
| 495 | } | ||
| 496 | } | ||
| 497 | |||
| 498 | /* -- Notifier funtions -----------------------------------------*/ | ||
| 499 | |||
| 500 | static int wb_smsc_wdt_notify_sys(struct notifier_block *this, unsigned long code, void *unused) | ||
| 501 | { | ||
| 502 | if (code == SYS_DOWN || code == SYS_HALT) | ||
| 503 | { | ||
| 504 | // set timeout to 0, to avoid possible race-condition | ||
| 505 | timeout = 0; | ||
| 506 | wb_smsc_wdt_disable(); | ||
| 507 | } | ||
| 508 | return NOTIFY_DONE; | ||
| 509 | } | ||
| 510 | |||
| 511 | /* -- Module's structures ---------------------------------------*/ | ||
| 512 | |||
| 513 | static struct file_operations wb_smsc_wdt_fops = | ||
| 514 | { | ||
| 515 | .owner = THIS_MODULE, | ||
| 516 | .llseek = no_llseek, | ||
| 517 | .write = wb_smsc_wdt_write, | ||
| 518 | .ioctl = wb_smsc_wdt_ioctl, | ||
| 519 | .open = wb_smsc_wdt_open, | ||
| 520 | .release = wb_smsc_wdt_release, | ||
| 521 | }; | ||
| 522 | |||
| 523 | static struct notifier_block wb_smsc_wdt_notifier = | ||
| 524 | { | ||
| 525 | .notifier_call = wb_smsc_wdt_notify_sys, | ||
| 526 | }; | ||
| 527 | |||
| 528 | static struct miscdevice wb_smsc_wdt_miscdev = | ||
| 529 | { | ||
| 530 | .minor = WATCHDOG_MINOR, | ||
| 531 | .name = "watchdog", | ||
| 532 | .fops = &wb_smsc_wdt_fops, | ||
| 533 | }; | ||
| 534 | |||
| 535 | /* -- Module init functions -------------------------------------*/ | ||
| 536 | |||
| 537 | /* module's "constructor" */ | ||
| 538 | |||
| 539 | static int __init wb_smsc_wdt_init(void) | ||
| 540 | { | ||
| 541 | int ret; | ||
| 542 | |||
| 543 | spin_lock_init(&io_lock); | ||
| 544 | |||
| 545 | printk("SMsC 37B787 watchdog component driver " VERSION " initialising...\n"); | ||
| 546 | |||
| 547 | if (!request_region(IOPORT, IOPORT_SIZE, "SMsC 37B787 watchdog")) { | ||
| 548 | printk(KERN_ERR MODNAME "Unable to register IO port %#x\n", IOPORT); | ||
| 549 | ret = -EBUSY; | ||
| 550 | goto out_pnp; | ||
| 551 | } | ||
| 552 | |||
| 553 | // set new maximum, if it's too big | ||
| 554 | if (timeout > MAX_TIMEOUT) | ||
| 555 | timeout = MAX_TIMEOUT; | ||
| 556 | |||
| 557 | // init the watchdog timer | ||
| 558 | wb_smsc_wdt_initialize(); | ||
| 559 | |||
| 560 | ret = register_reboot_notifier(&wb_smsc_wdt_notifier); | ||
| 561 | if (ret) { | ||
| 562 | printk(KERN_ERR MODNAME "Unable to register reboot notifier err = %d\n", ret); | ||
| 563 | goto out_io; | ||
| 564 | } | ||
| 565 | |||
| 566 | ret = misc_register(&wb_smsc_wdt_miscdev); | ||
| 567 | if (ret) { | ||
| 568 | printk(KERN_ERR MODNAME "Unable to register miscdev on minor %d\n", WATCHDOG_MINOR); | ||
| 569 | goto out_rbt; | ||
| 570 | } | ||
| 571 | |||
| 572 | // output info | ||
| 573 | printk(KERN_INFO MODNAME "Timeout set to %d %s.\n", timeout, (unit == UNIT_SECOND) ? "second(s)" : "minute(s)"); | ||
| 574 | printk(KERN_INFO MODNAME "Watchdog initialized and sleeping (nowayout=%d)...\n", nowayout); | ||
| 575 | |||
| 576 | // ret = 0 | ||
| 577 | |||
| 578 | out_clean: | ||
| 579 | return ret; | ||
| 580 | |||
| 581 | out_rbt: | ||
| 582 | unregister_reboot_notifier(&wb_smsc_wdt_notifier); | ||
| 583 | |||
| 584 | out_io: | ||
| 585 | release_region(IOPORT, IOPORT_SIZE); | ||
| 586 | |||
| 587 | out_pnp: | ||
| 588 | goto out_clean; | ||
| 589 | } | ||
| 590 | |||
| 591 | /* module's "destructor" */ | ||
| 592 | |||
| 593 | static void __exit wb_smsc_wdt_exit(void) | ||
| 594 | { | ||
| 595 | /* Stop the timer before we leave */ | ||
| 596 | if (!nowayout) | ||
| 597 | { | ||
| 598 | wb_smsc_wdt_shutdown(); | ||
| 599 | printk(KERN_INFO MODNAME "Watchdog disabled.\n"); | ||
| 600 | } | ||
| 601 | |||
| 602 | misc_deregister(&wb_smsc_wdt_miscdev); | ||
| 603 | unregister_reboot_notifier(&wb_smsc_wdt_notifier); | ||
| 604 | release_region(IOPORT, IOPORT_SIZE); | ||
| 605 | |||
| 606 | printk("SMsC 37B787 watchdog component driver removed.\n"); | ||
| 607 | } | ||
| 608 | |||
| 609 | module_init(wb_smsc_wdt_init); | ||
| 610 | module_exit(wb_smsc_wdt_exit); | ||
| 611 | |||
| 612 | MODULE_AUTHOR("Sven Anders <anders@anduras.de>"); | ||
| 613 | MODULE_DESCRIPTION("Driver for SMsC 37B787 watchdog component (Version " VERSION ")"); | ||
| 614 | MODULE_LICENSE("GPL"); | ||
| 615 | |||
| 616 | MODULE_ALIAS_MISCDEV(WATCHDOG_MINOR); | ||
| 617 | |||
| 618 | #ifdef SMSC_SUPPORT_MINUTES | ||
| 619 | module_param(unit, int, 0); | ||
| 620 | MODULE_PARM_DESC(unit, "set unit to use, 0=seconds or 1=minutes, default is 0"); | ||
| 621 | #endif | ||
| 622 | |||
| 623 | module_param(timeout, int, 0); | ||
| 624 | MODULE_PARM_DESC(timeout, "range is 1-255 units, default is 60"); | ||
| 625 | |||
| 626 | module_param(nowayout, int, 0); | ||
| 627 | MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default=CONFIG_WATCHDOG_NOWAYOUT)"); | ||
diff --git a/drivers/char/watchdog/w83627hf_wdt.c b/drivers/char/watchdog/w83627hf_wdt.c index b4adc527e6..07d4bff272 100644 --- a/drivers/char/watchdog/w83627hf_wdt.c +++ b/drivers/char/watchdog/w83627hf_wdt.c | |||
| @@ -33,6 +33,7 @@ | |||
| 33 | #include <linux/notifier.h> | 33 | #include <linux/notifier.h> |
| 34 | #include <linux/reboot.h> | 34 | #include <linux/reboot.h> |
| 35 | #include <linux/init.h> | 35 | #include <linux/init.h> |
| 36 | #include <linux/spinlock.h> | ||
| 36 | 37 | ||
| 37 | #include <asm/io.h> | 38 | #include <asm/io.h> |
| 38 | #include <asm/uaccess.h> | 39 | #include <asm/uaccess.h> |
| @@ -44,6 +45,7 @@ | |||
| 44 | 45 | ||
| 45 | static unsigned long wdt_is_open; | 46 | static unsigned long wdt_is_open; |
| 46 | static char expect_close; | 47 | static char expect_close; |
| 48 | static spinlock_t io_lock; | ||
| 47 | 49 | ||
| 48 | /* You must set this - there is no sane way to probe for this board. */ | 50 | /* You must set this - there is no sane way to probe for this board. */ |
| 49 | static int wdt_io = 0x2E; | 51 | static int wdt_io = 0x2E; |
| @@ -110,12 +112,16 @@ w83627hf_init(void) | |||
| 110 | static void | 112 | static void |
| 111 | wdt_ctrl(int timeout) | 113 | wdt_ctrl(int timeout) |
| 112 | { | 114 | { |
| 115 | spin_lock(&io_lock); | ||
| 116 | |||
| 113 | w83627hf_select_wd_register(); | 117 | w83627hf_select_wd_register(); |
| 114 | 118 | ||
| 115 | outb_p(0xF6, WDT_EFER); /* Select CRF6 */ | 119 | outb_p(0xF6, WDT_EFER); /* Select CRF6 */ |
| 116 | outb_p(timeout, WDT_EFDR); /* Write Timeout counter to CRF6 */ | 120 | outb_p(timeout, WDT_EFDR); /* Write Timeout counter to CRF6 */ |
| 117 | 121 | ||
| 118 | w83627hf_unselect_wd_register(); | 122 | w83627hf_unselect_wd_register(); |
| 123 | |||
| 124 | spin_unlock(&io_lock); | ||
| 119 | } | 125 | } |
| 120 | 126 | ||
| 121 | static int | 127 | static int |
| @@ -303,6 +309,8 @@ wdt_init(void) | |||
| 303 | { | 309 | { |
| 304 | int ret; | 310 | int ret; |
| 305 | 311 | ||
| 312 | spin_lock_init(&io_lock); | ||
| 313 | |||
| 306 | printk(KERN_INFO "WDT driver for the Winbond(TM) W83627HF Super I/O chip initialising.\n"); | 314 | printk(KERN_INFO "WDT driver for the Winbond(TM) W83627HF Super I/O chip initialising.\n"); |
| 307 | 315 | ||
| 308 | if (wdt_set_heartbeat(timeout)) { | 316 | if (wdt_set_heartbeat(timeout)) { |
diff --git a/drivers/char/watchdog/w83697hf_wdt.c b/drivers/char/watchdog/w83697hf_wdt.c new file mode 100644 index 0000000000..7768b55487 --- /dev/null +++ b/drivers/char/watchdog/w83697hf_wdt.c | |||
| @@ -0,0 +1,450 @@ | |||
| 1 | /* | ||
| 2 | * w83697hf/hg WDT driver | ||
| 3 | * | ||
| 4 | * (c) Copyright 2006 Samuel Tardieu <sam@rfc1149.net> | ||
| 5 | * (c) Copyright 2006 Marcus Junker <junker@anduras.de> | ||
| 6 | * | ||
| 7 | * Based on w83627hf_wdt.c which is based on advantechwdt.c | ||
| 8 | * which is based on wdt.c. | ||
| 9 | * Original copyright messages: | ||
| 10 | * | ||
| 11 | * (c) Copyright 2003 Pádraig Brady <P@draigBrady.com> | ||
| 12 | * | ||
| 13 | * (c) Copyright 2000-2001 Marek Michalkiewicz <marekm@linux.org.pl> | ||
| 14 | * | ||
| 15 | * (c) Copyright 1996 Alan Cox <alan@redhat.com>, All Rights Reserved. | ||
| 16 | * http://www.redhat.com | ||
| 17 | * | ||
| 18 | * This program is free software; you can redistribute it and/or | ||
| 19 | * modify it under the terms of the GNU General Public License | ||
| 20 | * as published by the Free Software Foundation; either version | ||
| 21 | * 2 of the License, or (at your option) any later version. | ||
| 22 | * | ||
| 23 | * Neither Marcus Junker nor ANDURAS AG admit liability nor provide | ||
| 24 | * warranty for any of this software. This material is provided | ||
| 25 | * "AS-IS" and at no charge. | ||
| 26 | */ | ||
| 27 | |||
| 28 | #include <linux/module.h> | ||
| 29 | #include <linux/moduleparam.h> | ||
| 30 | #include <linux/types.h> | ||
| 31 | #include <linux/miscdevice.h> | ||
| 32 | #include <linux/watchdog.h> | ||
| 33 | #include <linux/fs.h> | ||
| 34 | #include <linux/ioport.h> | ||
| 35 | #include <linux/notifier.h> | ||
| 36 | #include <linux/reboot.h> | ||
| 37 | #include <linux/init.h> | ||
| 38 | #include <linux/spinlock.h> | ||
| 39 | |||
| 40 | #include <asm/io.h> | ||
| 41 | #include <asm/uaccess.h> | ||
| 42 | #include <asm/system.h> | ||
| 43 | |||
| 44 | #define WATCHDOG_NAME "w83697hf/hg WDT" | ||
| 45 | #define PFX WATCHDOG_NAME ": " | ||
| 46 | #define WATCHDOG_TIMEOUT 60 /* 60 sec default timeout */ | ||
| 47 | |||
| 48 | static unsigned long wdt_is_open; | ||
| 49 | static char expect_close; | ||
| 50 | static spinlock_t io_lock; | ||
| 51 | |||
| 52 | /* You must set this - there is no sane way to probe for this board. */ | ||
| 53 | static int wdt_io = 0x2e; | ||
| 54 | module_param(wdt_io, int, 0); | ||
| 55 | MODULE_PARM_DESC(wdt_io, "w83697hf/hg WDT io port (default 0x2e, 0 = autodetect)"); | ||
| 56 | |||
| 57 | static int timeout = WATCHDOG_TIMEOUT; /* in seconds */ | ||
| 58 | module_param(timeout, int, 0); | ||
| 59 | MODULE_PARM_DESC(timeout, "Watchdog timeout in seconds. 1<= timeout <=255, default=" __MODULE_STRING(WATCHDOG_TIMEOUT) "."); | ||
| 60 | |||
| 61 | static int nowayout = WATCHDOG_NOWAYOUT; | ||
| 62 | module_param(nowayout, int, 0); | ||
| 63 | MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default=CONFIG_WATCHDOG_NOWAYOUT)"); | ||
| 64 | |||
| 65 | /* | ||
| 66 | * Kernel methods. | ||
| 67 | */ | ||
| 68 | |||
| 69 | #define W83697HF_EFER (wdt_io+0) /* Extended Function Enable Register */ | ||
| 70 | #define W83697HF_EFIR (wdt_io+0) /* Extended Function Index Register (same as EFER) */ | ||
| 71 | #define W83697HF_EFDR (wdt_io+1) /* Extended Function Data Register */ | ||
| 72 | |||
| 73 | static inline void | ||
| 74 | w83697hf_unlock(void) | ||
| 75 | { | ||
| 76 | outb_p(0x87, W83697HF_EFER); /* Enter extended function mode */ | ||
| 77 | outb_p(0x87, W83697HF_EFER); /* Again according to manual */ | ||
| 78 | } | ||
| 79 | |||
| 80 | static inline void | ||
| 81 | w83697hf_lock(void) | ||
| 82 | { | ||
| 83 | outb_p(0xAA, W83697HF_EFER); /* Leave extended function mode */ | ||
| 84 | } | ||
| 85 | |||
| 86 | /* | ||
| 87 | * The three functions w83697hf_get_reg(), w83697hf_set_reg() and | ||
| 88 | * w83697hf_write_timeout() must be called with the device unlocked. | ||
| 89 | */ | ||
| 90 | |||
| 91 | static unsigned char | ||
| 92 | w83697hf_get_reg(unsigned char reg) | ||
| 93 | { | ||
| 94 | outb_p(reg, W83697HF_EFIR); | ||
| 95 | return inb_p(W83697HF_EFDR); | ||
| 96 | } | ||
| 97 | |||
| 98 | static void | ||
| 99 | w83697hf_set_reg(unsigned char reg, unsigned char data) | ||
| 100 | { | ||
| 101 | outb_p(reg, W83697HF_EFIR); | ||
| 102 | outb_p(data, W83697HF_EFDR); | ||
| 103 | } | ||
| 104 | |||
| 105 | static void | ||
| 106 | w83697hf_write_timeout(int timeout) | ||
| 107 | { | ||
| 108 | w83697hf_set_reg(0xF4, timeout); /* Write Timeout counter to CRF4 */ | ||
| 109 | } | ||
| 110 | |||
| 111 | static void | ||
| 112 | w83697hf_select_wdt(void) | ||
| 113 | { | ||
| 114 | w83697hf_unlock(); | ||
| 115 | w83697hf_set_reg(0x07, 0x08); /* Switch to logic device 8 (GPIO2) */ | ||
| 116 | } | ||
| 117 | |||
| 118 | static inline void | ||
| 119 | w83697hf_deselect_wdt(void) | ||
| 120 | { | ||
| 121 | w83697hf_lock(); | ||
| 122 | } | ||
| 123 | |||
| 124 | static void | ||
| 125 | w83697hf_init(void) | ||
| 126 | { | ||
| 127 | unsigned char bbuf; | ||
| 128 | |||
| 129 | w83697hf_select_wdt(); | ||
| 130 | |||
| 131 | bbuf = w83697hf_get_reg(0x29); | ||
| 132 | bbuf &= ~0x60; | ||
| 133 | bbuf |= 0x20; | ||
| 134 | w83697hf_set_reg(0x29, bbuf); /* Set pin 119 to WDTO# mode (= CR29, WDT0) */ | ||
| 135 | |||
| 136 | bbuf = w83697hf_get_reg(0xF3); | ||
| 137 | bbuf &= ~0x04; | ||
| 138 | w83697hf_set_reg(0xF3, bbuf); /* Count mode is seconds */ | ||
| 139 | |||
| 140 | w83697hf_deselect_wdt(); | ||
| 141 | } | ||
| 142 | |||
| 143 | static int | ||
| 144 | wdt_ping(void) | ||
| 145 | { | ||
| 146 | spin_lock(&io_lock); | ||
| 147 | w83697hf_select_wdt(); | ||
| 148 | |||
| 149 | w83697hf_write_timeout(timeout); | ||
| 150 | |||
| 151 | w83697hf_deselect_wdt(); | ||
| 152 | spin_unlock(&io_lock); | ||
| 153 | return 0; | ||
| 154 | } | ||
| 155 | |||
| 156 | static int | ||
| 157 | wdt_enable(void) | ||
| 158 | { | ||
| 159 | spin_lock(&io_lock); | ||
| 160 | w83697hf_select_wdt(); | ||
| 161 | |||
| 162 | w83697hf_write_timeout(timeout); | ||
| 163 | w83697hf_set_reg(0x30, 1); /* Enable timer */ | ||
| 164 | |||
| 165 | w83697hf_deselect_wdt(); | ||
| 166 | spin_unlock(&io_lock); | ||
| 167 | return 0; | ||
| 168 | } | ||
| 169 | |||
| 170 | static int | ||
| 171 | wdt_disable(void) | ||
| 172 | { | ||
| 173 | spin_lock(&io_lock); | ||
| 174 | w83697hf_select_wdt(); | ||
| 175 | |||
| 176 | w83697hf_set_reg(0x30, 0); /* Disable timer */ | ||
| 177 | w83697hf_write_timeout(0); | ||
| 178 | |||
| 179 | w83697hf_deselect_wdt(); | ||
| 180 | spin_unlock(&io_lock); | ||
| 181 | return 0; | ||
| 182 | } | ||
| 183 | |||
| 184 | static int | ||
| 185 | wdt_set_heartbeat(int t) | ||
| 186 | { | ||
| 187 | if ((t < 1) || (t > 255)) | ||
| 188 | return -EINVAL; | ||
| 189 | |||
| 190 | timeout = t; | ||
| 191 | return 0; | ||
| 192 | } | ||
| 193 | |||
| 194 | static ssize_t | ||
| 195 | wdt_write(struct file *file, const char __user *buf, size_t count, loff_t *ppos) | ||
| 196 | { | ||
| 197 | if (count) { | ||
| 198 | if (!nowayout) { | ||
| 199 | size_t i; | ||
| 200 | |||
| 201 | expect_close = 0; | ||
| 202 | |||
| 203 | for (i = 0; i != count; i++) { | ||
| 204 | char c; | ||
| 205 | if (get_user(c, buf+i)) | ||
| 206 | return -EFAULT; | ||
| 207 | if (c == 'V') | ||
| 208 | expect_close = 42; | ||
| 209 | } | ||
| 210 | } | ||
| 211 | wdt_ping(); | ||
| 212 | } | ||
| 213 | return count; | ||
| 214 | } | ||
| 215 | |||
| 216 | static int | ||
| 217 | wdt_ioctl(struct inode *inode, struct file *file, unsigned int cmd, | ||
| 218 | unsigned long arg) | ||
| 219 | { | ||
| 220 | void __user *argp = (void __user *)arg; | ||
| 221 | int __user *p = argp; | ||
| 222 | int new_timeout; | ||
| 223 | static struct watchdog_info ident = { | ||
| 224 | .options = WDIOF_KEEPALIVEPING | WDIOF_SETTIMEOUT | WDIOF_MAGICCLOSE, | ||
| 225 | .firmware_version = 1, | ||
| 226 | .identity = "W83697HF WDT", | ||
| 227 | }; | ||
| 228 | |||
| 229 | switch (cmd) { | ||
| 230 | case WDIOC_GETSUPPORT: | ||
| 231 | if (copy_to_user(argp, &ident, sizeof(ident))) | ||
| 232 | return -EFAULT; | ||
| 233 | break; | ||
| 234 | |||
| 235 | case WDIOC_GETSTATUS: | ||
| 236 | case WDIOC_GETBOOTSTATUS: | ||
| 237 | return put_user(0, p); | ||
| 238 | |||
| 239 | case WDIOC_KEEPALIVE: | ||
| 240 | wdt_ping(); | ||
| 241 | break; | ||
| 242 | |||
| 243 | case WDIOC_SETTIMEOUT: | ||
| 244 | if (get_user(new_timeout, p)) | ||
| 245 | return -EFAULT; | ||
| 246 | if (wdt_set_heartbeat(new_timeout)) | ||
| 247 | return -EINVAL; | ||
| 248 | wdt_ping(); | ||
| 249 | /* Fall */ | ||
| 250 | |||
| 251 | case WDIOC_GETTIMEOUT: | ||
| 252 | return put_user(timeout, p); | ||
| 253 | |||
| 254 | case WDIOC_SETOPTIONS: | ||
| 255 | { | ||
| 256 | int options, retval = -EINVAL; | ||
| 257 | |||
| 258 | if (get_user(options, p)) | ||
| 259 | return -EFAULT; | ||
| 260 | |||
| 261 | if (options & WDIOS_DISABLECARD) { | ||
| 262 | wdt_disable(); | ||
| 263 | retval = 0; | ||
| 264 | } | ||
| 265 | |||
| 266 | if (options & WDIOS_ENABLECARD) { | ||
| 267 | wdt_enable(); | ||
| 268 | retval = 0; | ||
| 269 | } | ||
| 270 | |||
| 271 | return retval; | ||
| 272 | } | ||
| 273 | |||
| 274 | default: | ||
| 275 | return -ENOTTY; | ||
| 276 | } | ||
| 277 | return 0; | ||
| 278 | } | ||
| 279 | |||
| 280 | static int | ||
| 281 | wdt_open(struct inode *inode, struct file *file) | ||
| 282 | { | ||
| 283 | if (test_and_set_bit(0, &wdt_is_open)) | ||
| 284 | return -EBUSY; | ||
| 285 | /* | ||
| 286 | * Activate | ||
| 287 | */ | ||
| 288 | |||
| 289 | wdt_enable(); | ||
| 290 | return nonseekable_open(inode, file); | ||
| 291 | } | ||
| 292 | |||
| 293 | static int | ||
| 294 | wdt_close(struct inode *inode, struct file *file) | ||
| 295 | { | ||
| 296 | if (expect_close == 42) { | ||
| 297 | wdt_disable(); | ||
| 298 | } else { | ||
| 299 | printk (KERN_CRIT PFX "Unexpected close, not stopping watchdog!\n"); | ||
| 300 | wdt_ping(); | ||
| 301 | } | ||
| 302 | expect_close = 0; | ||
| 303 | clear_bit(0, &wdt_is_open); | ||
| 304 | return 0; | ||
| 305 | } | ||
| 306 | |||
| 307 | /* | ||
| 308 | * Notifier for system down | ||
| 309 | */ | ||
| 310 | |||
| 311 | static int | ||
| 312 | wdt_notify_sys(struct notifier_block *this, unsigned long code, | ||
| 313 | void *unused) | ||
| 314 | { | ||
| 315 | if (code == SYS_DOWN || code == SYS_HALT) { | ||
| 316 | /* Turn the WDT off */ | ||
| 317 | wdt_disable(); | ||
| 318 | } | ||
| 319 | return NOTIFY_DONE; | ||
| 320 | } | ||
| 321 | |||
| 322 | /* | ||
| 323 | * Kernel Interfaces | ||
| 324 | */ | ||
| 325 | |||
| 326 | static struct file_operations wdt_fops = { | ||
| 327 | .owner = THIS_MODULE, | ||
| 328 | .llseek = no_llseek, | ||
| 329 | .write = wdt_write, | ||
| 330 | .ioctl = wdt_ioctl, | ||
| 331 | .open = wdt_open, | ||
| 332 | .release = wdt_close, | ||
| 333 | }; | ||
| 334 | |||
| 335 | static struct miscdevice wdt_miscdev = { | ||
| 336 | .minor = WATCHDOG_MINOR, | ||
| 337 | .name = "watchdog", | ||
| 338 | .fops = &wdt_fops, | ||
| 339 | }; | ||
| 340 | |||
| 341 | /* | ||
| 342 | * The WDT needs to learn about soft shutdowns in order to | ||
| 343 | * turn the timebomb registers off. | ||
| 344 | */ | ||
| 345 | |||
| 346 | static struct notifier_block wdt_notifier = { | ||
| 347 | .notifier_call = wdt_notify_sys, | ||
| 348 | }; | ||
| 349 | |||
| 350 | static int | ||
| 351 | w83697hf_check_wdt(void) | ||
| 352 | { | ||
| 353 | if (!request_region(wdt_io, 2, WATCHDOG_NAME)) { | ||
| 354 | printk (KERN_ERR PFX "I/O address 0x%x already in use\n", wdt_io); | ||
| 355 | return -EIO; | ||
| 356 | } | ||
| 357 | |||
| 358 | printk (KERN_DEBUG PFX "Looking for watchdog at address 0x%x\n", wdt_io); | ||
| 359 | w83697hf_unlock(); | ||
| 360 | if (w83697hf_get_reg(0x20) == 0x60) { | ||
| 361 | printk (KERN_INFO PFX "watchdog found at address 0x%x\n", wdt_io); | ||
| 362 | w83697hf_lock(); | ||
| 363 | return 0; | ||
| 364 | } | ||
| 365 | w83697hf_lock(); /* Reprotect in case it was a compatible device */ | ||
| 366 | |||
| 367 | printk (KERN_INFO PFX "watchdog not found at address 0x%x\n", wdt_io); | ||
| 368 | release_region(wdt_io, 2); | ||
| 369 | return -EIO; | ||
| 370 | } | ||
| 371 | |||
| 372 | static int w83697hf_ioports[] = { 0x2e, 0x4e, 0x00 }; | ||
| 373 | |||
| 374 | static int __init | ||
| 375 | wdt_init(void) | ||
| 376 | { | ||
| 377 | int ret, i, found = 0; | ||
| 378 | |||
| 379 | spin_lock_init(&io_lock); | ||
| 380 | |||
| 381 | printk (KERN_INFO PFX "WDT driver for W83697HF/HG initializing\n"); | ||
| 382 | |||
| 383 | if (wdt_io == 0) { | ||
| 384 | /* we will autodetect the W83697HF/HG watchdog */ | ||
| 385 | for (i = 0; ((!found) && (w83697hf_ioports[i] != 0)); i++) { | ||
| 386 | wdt_io = w83697hf_ioports[i]; | ||
| 387 | if (!w83697hf_check_wdt()) | ||
| 388 | found++; | ||
| 389 | } | ||
| 390 | } else { | ||
| 391 | if (!w83697hf_check_wdt()) | ||
| 392 | found++; | ||
| 393 | } | ||
| 394 | |||
| 395 | if (!found) { | ||
| 396 | printk (KERN_ERR PFX "No W83697HF/HG could be found\n"); | ||
| 397 | ret = -EIO; | ||
| 398 | goto out; | ||
| 399 | } | ||
| 400 | |||
| 401 | w83697hf_init(); | ||
| 402 | wdt_disable(); /* Disable watchdog until first use */ | ||
| 403 | |||
| 404 | if (wdt_set_heartbeat(timeout)) { | ||
| 405 | wdt_set_heartbeat(WATCHDOG_TIMEOUT); | ||
| 406 | printk (KERN_INFO PFX "timeout value must be 1<=timeout<=255, using %d\n", | ||
| 407 | WATCHDOG_TIMEOUT); | ||
| 408 | } | ||
| 409 | |||
| 410 | ret = register_reboot_notifier(&wdt_notifier); | ||
| 411 | if (ret != 0) { | ||
| 412 | printk (KERN_ERR PFX "cannot register reboot notifier (err=%d)\n", | ||
| 413 | ret); | ||
| 414 | goto unreg_regions; | ||
| 415 | } | ||
| 416 | |||
| 417 | ret = misc_register(&wdt_miscdev); | ||
| 418 | if (ret != 0) { | ||
| 419 | printk (KERN_ERR PFX "cannot register miscdev on minor=%d (err=%d)\n", | ||
| 420 | WATCHDOG_MINOR, ret); | ||
| 421 | goto unreg_reboot; | ||
| 422 | } | ||
| 423 | |||
| 424 | printk (KERN_INFO PFX "initialized. timeout=%d sec (nowayout=%d)\n", | ||
| 425 | timeout, nowayout); | ||
| 426 | |||
| 427 | out: | ||
| 428 | return ret; | ||
| 429 | unreg_reboot: | ||
| 430 | unregister_reboot_notifier(&wdt_notifier); | ||
| 431 | unreg_regions: | ||
| 432 | release_region(wdt_io, 2); | ||
| 433 | goto out; | ||
| 434 | } | ||
| 435 | |||
| 436 | static void __exit | ||
| 437 | wdt_exit(void) | ||
| 438 | { | ||
| 439 | misc_deregister(&wdt_miscdev); | ||
| 440 | unregister_reboot_notifier(&wdt_notifier); | ||
| 441 | release_region(wdt_io, 2); | ||
| 442 | } | ||
| 443 | |||
| 444 | module_init(wdt_init); | ||
| 445 | module_exit(wdt_exit); | ||
| 446 | |||
| 447 | MODULE_LICENSE("GPL"); | ||
| 448 | MODULE_AUTHOR("Marcus Junker <junker@anduras.de>, Samuel Tardieu <sam@rfc1149.net>"); | ||
| 449 | MODULE_DESCRIPTION("w83697hf/hg WDT driver"); | ||
| 450 | MODULE_ALIAS_MISCDEV(WATCHDOG_MINOR); | ||
