diff options
Diffstat (limited to 'drivers/char/watchdog')
54 files changed, 4365 insertions, 139 deletions
diff --git a/drivers/char/watchdog/Kconfig b/drivers/char/watchdog/Kconfig index fff89c2d88fd..ea09d0c974ea 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 | ||
@@ -165,6 +165,24 @@ config EP93XX_WATCHDOG | |||
165 | To compile this driver as a module, choose M here: the | 165 | To compile this driver as a module, choose M here: the |
166 | module will be called ep93xx_wdt. | 166 | module will be called ep93xx_wdt. |
167 | 167 | ||
168 | config OMAP_WATCHDOG | ||
169 | tristate "OMAP Watchdog" | ||
170 | depends on WATCHDOG && (ARCH_OMAP16XX || ARCH_OMAP24XX) | ||
171 | help | ||
172 | Support for TI OMAP1610/OMAP1710/OMAP2420 watchdog. Say 'Y' here to | ||
173 | enable the OMAP1610/OMAP1710 watchdog timer. | ||
174 | |||
175 | config PNX4008_WATCHDOG | ||
176 | tristate "PNX4008 Watchdog" | ||
177 | depends on WATCHDOG && ARCH_PNX4008 | ||
178 | help | ||
179 | Say Y here if to include support for the watchdog timer | ||
180 | in the PNX4008 processor. | ||
181 | This driver can be built as a module by choosing M. The module | ||
182 | will be called pnx4008_wdt. | ||
183 | |||
184 | Say N if you are unsure. | ||
185 | |||
168 | # X86 (i386 + ia64 + x86_64) Architecture | 186 | # X86 (i386 + ia64 + x86_64) Architecture |
169 | 187 | ||
170 | config ACQUIRE_WDT | 188 | config ACQUIRE_WDT |
@@ -251,11 +269,11 @@ config IB700_WDT | |||
251 | Most people will say N. | 269 | Most people will say N. |
252 | 270 | ||
253 | config IBMASR | 271 | config IBMASR |
254 | tristate "IBM Automatic Server Restart" | 272 | tristate "IBM Automatic Server Restart" |
255 | depends on WATCHDOG && X86 | 273 | depends on WATCHDOG && X86 |
256 | help | 274 | help |
257 | This is the driver for the IBM Automatic Server Restart watchdog | 275 | This is the driver for the IBM Automatic Server Restart watchdog |
258 | timer builtin into some eServer xSeries machines. | 276 | timer built-in into some eServer xSeries machines. |
259 | 277 | ||
260 | To compile this driver as a module, choose M here: the | 278 | To compile this driver as a module, choose M here: the |
261 | module will be called ibmasr. | 279 | module will be called ibmasr. |
@@ -298,6 +316,38 @@ config I8XX_TCO | |||
298 | To compile this driver as a module, choose M here: the | 316 | To compile this driver as a module, choose M here: the |
299 | module will be called i8xx_tco. | 317 | module will be called i8xx_tco. |
300 | 318 | ||
319 | Note: This driver will be removed in the near future. Please | ||
320 | use the Intel TCO Timer/Watchdog driver. | ||
321 | |||
322 | config ITCO_WDT | ||
323 | tristate "Intel TCO Timer/Watchdog" | ||
324 | depends on WATCHDOG && (X86 || IA64) && PCI | ||
325 | ---help--- | ||
326 | Hardware driver for the intel TCO timer based watchdog devices. | ||
327 | These drivers are included in the Intel 82801 I/O Controller | ||
328 | Hub family (from ICH0 up to ICH8) and in the Intel 6300ESB | ||
329 | controller hub. | ||
330 | |||
331 | The TCO (Total Cost of Ownership) timer is a watchdog timer | ||
332 | that will reboot the machine after its second expiration. The | ||
333 | expiration time can be configured with the "heartbeat" parameter. | ||
334 | |||
335 | On some motherboards the driver may fail to reset the chipset's | ||
336 | NO_REBOOT flag which prevents the watchdog from rebooting the | ||
337 | machine. If this is the case you will get a kernel message like | ||
338 | "failed to reset NO_REBOOT flag, reboot disabled by hardware". | ||
339 | |||
340 | To compile this driver as a module, choose M here: the | ||
341 | module will be called iTCO_wdt. | ||
342 | |||
343 | config ITCO_VENDOR_SUPPORT | ||
344 | bool "Intel TCO Timer/Watchdog Specific Vendor Support" | ||
345 | depends on ITCO_WDT | ||
346 | ---help--- | ||
347 | Add vendor specific support to the intel TCO timer based watchdog | ||
348 | devices. At this moment we only have additional support for some | ||
349 | SuperMicro Inc. motherboards. | ||
350 | |||
301 | config SC1200_WDT | 351 | config SC1200_WDT |
302 | tristate "National Semiconductor PC87307/PC97307 (ala SC1200) Watchdog" | 352 | tristate "National Semiconductor PC87307/PC97307 (ala SC1200) Watchdog" |
303 | depends on WATCHDOG && X86 | 353 | depends on WATCHDOG && X86 |
@@ -321,6 +371,20 @@ config SCx200_WDT | |||
321 | 371 | ||
322 | If compiled as a module, it will be called scx200_wdt. | 372 | If compiled as a module, it will be called scx200_wdt. |
323 | 373 | ||
374 | config PC87413_WDT | ||
375 | tristate "NS PC87413 watchdog" | ||
376 | depends on WATCHDOG && X86 | ||
377 | ---help--- | ||
378 | This is the driver for the hardware watchdog on the PC87413 chipset | ||
379 | This watchdog simply watches your kernel to make sure it doesn't | ||
380 | freeze, and if it does, it reboots your computer after a certain | ||
381 | amount of time. | ||
382 | |||
383 | To compile this driver as a module, choose M here: the | ||
384 | module will be called pc87413_wdt. | ||
385 | |||
386 | Most people will say N. | ||
387 | |||
324 | config 60XX_WDT | 388 | config 60XX_WDT |
325 | tristate "SBC-60XX Watchdog Timer" | 389 | tristate "SBC-60XX Watchdog Timer" |
326 | depends on WATCHDOG && X86 | 390 | depends on WATCHDOG && X86 |
@@ -356,6 +420,26 @@ config CPU5_WDT | |||
356 | To compile this driver as a module, choose M here: the | 420 | To compile this driver as a module, choose M here: the |
357 | module will be called cpu5wdt. | 421 | module will be called cpu5wdt. |
358 | 422 | ||
423 | config SMSC37B787_WDT | ||
424 | tristate "Winbond SMsC37B787 Watchdog Timer" | ||
425 | depends on WATCHDOG && X86 | ||
426 | ---help--- | ||
427 | This is the driver for the hardware watchdog component on the | ||
428 | Winbond SMsC37B787 chipset as used on the NetRunner Mainboard | ||
429 | from Vision Systems and maybe others. | ||
430 | |||
431 | This watchdog simply watches your kernel to make sure it doesn't | ||
432 | freeze, and if it does, it reboots your computer after a certain | ||
433 | amount of time. | ||
434 | |||
435 | Usually a userspace daemon will notify the kernel WDT driver that | ||
436 | userspace is still alive, at regular intervals. | ||
437 | |||
438 | To compile this driver as a module, choose M here: the | ||
439 | module will be called smsc37b787_wdt. | ||
440 | |||
441 | Most people will say N. | ||
442 | |||
359 | config W83627HF_WDT | 443 | config W83627HF_WDT |
360 | tristate "W83627HF Watchdog Timer" | 444 | tristate "W83627HF Watchdog Timer" |
361 | depends on WATCHDOG && X86 | 445 | depends on WATCHDOG && X86 |
@@ -371,6 +455,21 @@ config W83627HF_WDT | |||
371 | 455 | ||
372 | Most people will say N. | 456 | Most people will say N. |
373 | 457 | ||
458 | config W83697HF_WDT | ||
459 | tristate "W83697HF/W83697HG Watchdog Timer" | ||
460 | depends on WATCHDOG && X86 | ||
461 | ---help--- | ||
462 | This is the driver for the hardware watchdog on the W83697HF/HG | ||
463 | chipset as used in Dedibox/VIA motherboards (and likely others). | ||
464 | This watchdog simply watches your kernel to make sure it doesn't | ||
465 | freeze, and if it does, it reboots your computer after a certain | ||
466 | amount of time. | ||
467 | |||
468 | To compile this driver as a module, choose M here: the | ||
469 | module will be called w83697hf_wdt. | ||
470 | |||
471 | Most people will say N. | ||
472 | |||
374 | config W83877F_WDT | 473 | config W83877F_WDT |
375 | tristate "W83877F (EMACS) Watchdog Timer" | 474 | tristate "W83877F (EMACS) Watchdog Timer" |
376 | depends on WATCHDOG && X86 | 475 | depends on WATCHDOG && X86 |
@@ -404,7 +503,7 @@ config MACHZ_WDT | |||
404 | depends on WATCHDOG && X86 | 503 | depends on WATCHDOG && X86 |
405 | ---help--- | 504 | ---help--- |
406 | If you are using a ZF Micro MachZ processor, say Y here, otherwise | 505 | If you are using a ZF Micro MachZ processor, say Y here, otherwise |
407 | N. This is the driver for the watchdog timer builtin on that | 506 | N. This is the driver for the watchdog timer built-in on that |
408 | processor using ZF-Logic interface. This watchdog simply watches | 507 | processor using ZF-Logic interface. This watchdog simply watches |
409 | your kernel to make sure it doesn't freeze, and if it does, it | 508 | your kernel to make sure it doesn't freeze, and if it does, it |
410 | reboots your computer after a certain amount of time. | 509 | reboots your computer after a certain amount of time. |
@@ -433,7 +532,6 @@ config SBC_EPX_C3_WATCHDOG | |||
433 | To compile this driver as a module, choose M here: the | 532 | To compile this driver as a module, choose M here: the |
434 | module will be called sbc_epx_c3. | 533 | module will be called sbc_epx_c3. |
435 | 534 | ||
436 | |||
437 | # PowerPC Architecture | 535 | # PowerPC Architecture |
438 | 536 | ||
439 | config 8xx_WDT | 537 | config 8xx_WDT |
@@ -463,7 +561,7 @@ config WATCHDOG_RTAS | |||
463 | help | 561 | help |
464 | This driver adds watchdog support for the RTAS watchdog. | 562 | This driver adds watchdog support for the RTAS watchdog. |
465 | 563 | ||
466 | To compile this driver as a module, choose M here. The module | 564 | To compile this driver as a module, choose M here. The module |
467 | will be called wdrtas. | 565 | will be called wdrtas. |
468 | 566 | ||
469 | # MIPS Architecture | 567 | # MIPS Architecture |
@@ -477,6 +575,16 @@ config INDYDOG | |||
477 | timer expired and no process has written to /dev/watchdog during | 575 | timer expired and no process has written to /dev/watchdog during |
478 | that time. | 576 | that time. |
479 | 577 | ||
578 | config WDT_RM9K_GPI | ||
579 | tristate "RM9000/GPI hardware watchdog" | ||
580 | depends on WATCHDOG && CPU_RM9000 | ||
581 | help | ||
582 | Watchdog implementation using the GPI hardware found on | ||
583 | PMC-Sierra RM9xxx CPUs. | ||
584 | |||
585 | To compile this driver as a module, choose M here: the | ||
586 | module will be called rm9k_wdt. | ||
587 | |||
480 | # S390 Architecture | 588 | # S390 Architecture |
481 | 589 | ||
482 | config ZVM_WATCHDOG | 590 | config ZVM_WATCHDOG |
@@ -510,6 +618,14 @@ config SH_WDT | |||
510 | To compile this driver as a module, choose M here: the | 618 | To compile this driver as a module, choose M here: the |
511 | module will be called shwdt. | 619 | module will be called shwdt. |
512 | 620 | ||
621 | config SH_WDT_MMAP | ||
622 | bool "Allow mmap of SH WDT" | ||
623 | default n | ||
624 | depends on SH_WDT | ||
625 | help | ||
626 | If you say Y here, user applications will be able to mmap the | ||
627 | WDT/CPG registers. | ||
628 | |||
513 | # SPARC64 Architecture | 629 | # SPARC64 Architecture |
514 | 630 | ||
515 | config WATCHDOG_CP1XXX | 631 | config WATCHDOG_CP1XXX |
diff --git a/drivers/char/watchdog/Makefile b/drivers/char/watchdog/Makefile index 6ab77b61a643..2cd8ff8d10ac 100644 --- a/drivers/char/watchdog/Makefile +++ b/drivers/char/watchdog/Makefile | |||
@@ -23,7 +23,8 @@ 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_21285_WATCHDOG) += wdt285.o | 28 | obj-$(CONFIG_21285_WATCHDOG) += wdt285.o |
28 | obj-$(CONFIG_977_WATCHDOG) += wdt977.o | 29 | obj-$(CONFIG_977_WATCHDOG) += wdt977.o |
29 | obj-$(CONFIG_IXP2000_WATCHDOG) += ixp2000_wdt.o | 30 | obj-$(CONFIG_IXP2000_WATCHDOG) += ixp2000_wdt.o |
@@ -32,6 +33,7 @@ obj-$(CONFIG_S3C2410_WATCHDOG) += s3c2410_wdt.o | |||
32 | obj-$(CONFIG_SA1100_WATCHDOG) += sa1100_wdt.o | 33 | obj-$(CONFIG_SA1100_WATCHDOG) += sa1100_wdt.o |
33 | obj-$(CONFIG_MPCORE_WATCHDOG) += mpcore_wdt.o | 34 | obj-$(CONFIG_MPCORE_WATCHDOG) += mpcore_wdt.o |
34 | obj-$(CONFIG_EP93XX_WATCHDOG) += ep93xx_wdt.o | 35 | obj-$(CONFIG_EP93XX_WATCHDOG) += ep93xx_wdt.o |
36 | obj-$(CONFIG_PNX4008_WATCHDOG) += pnx4008_wdt.o | ||
35 | 37 | ||
36 | # X86 (i386 + ia64 + x86_64) Architecture | 38 | # X86 (i386 + ia64 + x86_64) Architecture |
37 | obj-$(CONFIG_ACQUIRE_WDT) += acquirewdt.o | 39 | obj-$(CONFIG_ACQUIRE_WDT) += acquirewdt.o |
@@ -45,12 +47,16 @@ obj-$(CONFIG_IBMASR) += ibmasr.o | |||
45 | obj-$(CONFIG_WAFER_WDT) += wafer5823wdt.o | 47 | obj-$(CONFIG_WAFER_WDT) += wafer5823wdt.o |
46 | obj-$(CONFIG_I6300ESB_WDT) += i6300esb.o | 48 | obj-$(CONFIG_I6300ESB_WDT) += i6300esb.o |
47 | obj-$(CONFIG_I8XX_TCO) += i8xx_tco.o | 49 | obj-$(CONFIG_I8XX_TCO) += i8xx_tco.o |
50 | obj-$(CONFIG_ITCO_WDT) += iTCO_wdt.o iTCO_vendor_support.o | ||
48 | obj-$(CONFIG_SC1200_WDT) += sc1200wdt.o | 51 | obj-$(CONFIG_SC1200_WDT) += sc1200wdt.o |
49 | obj-$(CONFIG_SCx200_WDT) += scx200_wdt.o | 52 | obj-$(CONFIG_SCx200_WDT) += scx200_wdt.o |
53 | obj-$(CONFIG_PC87413_WDT) += pc87413_wdt.o | ||
50 | obj-$(CONFIG_60XX_WDT) += sbc60xxwdt.o | 54 | obj-$(CONFIG_60XX_WDT) += sbc60xxwdt.o |
51 | obj-$(CONFIG_SBC8360_WDT) += sbc8360.o | 55 | obj-$(CONFIG_SBC8360_WDT) += sbc8360.o |
52 | obj-$(CONFIG_CPU5_WDT) += cpu5wdt.o | 56 | obj-$(CONFIG_CPU5_WDT) += cpu5wdt.o |
57 | obj-$(CONFIG_SMSC37B787_WDT) += smsc37b787_wdt.o | ||
53 | obj-$(CONFIG_W83627HF_WDT) += w83627hf_wdt.o | 58 | obj-$(CONFIG_W83627HF_WDT) += w83627hf_wdt.o |
59 | obj-$(CONFIG_W83697HF_WDT) += w83697hf_wdt.o | ||
54 | obj-$(CONFIG_W83877F_WDT) += w83877f_wdt.o | 60 | obj-$(CONFIG_W83877F_WDT) += w83877f_wdt.o |
55 | obj-$(CONFIG_W83977F_WDT) += w83977f_wdt.o | 61 | obj-$(CONFIG_W83977F_WDT) += w83977f_wdt.o |
56 | obj-$(CONFIG_MACHZ_WDT) += machzwd.o | 62 | obj-$(CONFIG_MACHZ_WDT) += machzwd.o |
@@ -67,6 +73,7 @@ obj-$(CONFIG_WATCHDOG_RTAS) += wdrtas.o | |||
67 | 73 | ||
68 | # MIPS Architecture | 74 | # MIPS Architecture |
69 | obj-$(CONFIG_INDYDOG) += indydog.o | 75 | obj-$(CONFIG_INDYDOG) += indydog.o |
76 | obj-$(CONFIG_WDT_RM9K_GPI) += rm9k_wdt.o | ||
70 | 77 | ||
71 | # S390 Architecture | 78 | # S390 Architecture |
72 | 79 | ||
diff --git a/drivers/char/watchdog/acquirewdt.c b/drivers/char/watchdog/acquirewdt.c index c77fe3cf2852..154d67e591e5 100644 --- a/drivers/char/watchdog/acquirewdt.c +++ b/drivers/char/watchdog/acquirewdt.c | |||
@@ -183,7 +183,7 @@ static int acq_ioctl(struct inode *inode, struct file *file, unsigned int cmd, | |||
183 | } | 183 | } |
184 | 184 | ||
185 | default: | 185 | default: |
186 | return -ENOIOCTLCMD; | 186 | return -ENOTTY; |
187 | } | 187 | } |
188 | } | 188 | } |
189 | 189 | ||
diff --git a/drivers/char/watchdog/advantechwdt.c b/drivers/char/watchdog/advantechwdt.c index 8069be445edc..9d732769ba01 100644 --- a/drivers/char/watchdog/advantechwdt.c +++ b/drivers/char/watchdog/advantechwdt.c | |||
@@ -176,7 +176,7 @@ advwdt_ioctl(struct inode *inode, struct file *file, unsigned int cmd, | |||
176 | } | 176 | } |
177 | 177 | ||
178 | default: | 178 | default: |
179 | return -ENOIOCTLCMD; | 179 | return -ENOTTY; |
180 | } | 180 | } |
181 | return 0; | 181 | return 0; |
182 | } | 182 | } |
diff --git a/drivers/char/watchdog/alim1535_wdt.c b/drivers/char/watchdog/alim1535_wdt.c index c5c94e4c9495..01b0d132ee41 100644 --- a/drivers/char/watchdog/alim1535_wdt.c +++ b/drivers/char/watchdog/alim1535_wdt.c | |||
@@ -236,7 +236,7 @@ static int ali_ioctl(struct inode *inode, struct file *file, | |||
236 | return put_user(timeout, p); | 236 | return put_user(timeout, p); |
237 | 237 | ||
238 | default: | 238 | default: |
239 | return -ENOIOCTLCMD; | 239 | return -ENOTTY; |
240 | } | 240 | } |
241 | } | 241 | } |
242 | 242 | ||
@@ -330,17 +330,20 @@ static int __init ali_find_watchdog(void) | |||
330 | u32 wdog; | 330 | u32 wdog; |
331 | 331 | ||
332 | /* Check for a 1535 series bridge */ | 332 | /* Check for a 1535 series bridge */ |
333 | pdev = pci_find_device(PCI_VENDOR_ID_AL, 0x1535, NULL); | 333 | pdev = pci_get_device(PCI_VENDOR_ID_AL, 0x1535, NULL); |
334 | if(pdev == NULL) | 334 | if(pdev == NULL) |
335 | return -ENODEV; | 335 | return -ENODEV; |
336 | pci_dev_put(pdev); | ||
336 | 337 | ||
337 | /* Check for the a 7101 PMU */ | 338 | /* Check for the a 7101 PMU */ |
338 | pdev = pci_find_device(PCI_VENDOR_ID_AL, 0x7101, NULL); | 339 | pdev = pci_get_device(PCI_VENDOR_ID_AL, 0x7101, NULL); |
339 | if(pdev == NULL) | 340 | if(pdev == NULL) |
340 | return -ENODEV; | 341 | return -ENODEV; |
341 | 342 | ||
342 | if(pci_enable_device(pdev)) | 343 | if(pci_enable_device(pdev)) { |
344 | pci_dev_put(pdev); | ||
343 | return -EIO; | 345 | return -EIO; |
346 | } | ||
344 | 347 | ||
345 | ali_pci = pdev; | 348 | ali_pci = pdev; |
346 | 349 | ||
@@ -447,6 +450,7 @@ static void __exit watchdog_exit(void) | |||
447 | /* Deregister */ | 450 | /* Deregister */ |
448 | unregister_reboot_notifier(&ali_notifier); | 451 | unregister_reboot_notifier(&ali_notifier); |
449 | misc_deregister(&ali_miscdev); | 452 | misc_deregister(&ali_miscdev); |
453 | pci_dev_put(ali_pci); | ||
450 | } | 454 | } |
451 | 455 | ||
452 | module_init(watchdog_init); | 456 | module_init(watchdog_init); |
diff --git a/drivers/char/watchdog/alim7101_wdt.c b/drivers/char/watchdog/alim7101_wdt.c index ffd7684f999b..bf25d0a55a99 100644 --- a/drivers/char/watchdog/alim7101_wdt.c +++ b/drivers/char/watchdog/alim7101_wdt.c | |||
@@ -77,7 +77,8 @@ static struct pci_dev *alim7101_pmu; | |||
77 | 77 | ||
78 | static int nowayout = WATCHDOG_NOWAYOUT; | 78 | static int nowayout = WATCHDOG_NOWAYOUT; |
79 | module_param(nowayout, int, 0); | 79 | module_param(nowayout, int, 0); |
80 | MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default=CONFIG_WATCHDOG_NOWAYOUT)"); | 80 | MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default=" |
81 | __stringify(CONFIG_WATCHDOG_NOWAYOUT) ")"); | ||
81 | 82 | ||
82 | /* | 83 | /* |
83 | * Whack the dog | 84 | * Whack the dog |
@@ -277,7 +278,7 @@ static int fop_ioctl(struct inode *inode, struct file *file, unsigned int cmd, u | |||
277 | case WDIOC_GETTIMEOUT: | 278 | case WDIOC_GETTIMEOUT: |
278 | return put_user(timeout, p); | 279 | return put_user(timeout, p); |
279 | default: | 280 | default: |
280 | return -ENOIOCTLCMD; | 281 | return -ENOTTY; |
281 | } | 282 | } |
282 | } | 283 | } |
283 | 284 | ||
@@ -333,6 +334,7 @@ static void __exit alim7101_wdt_unload(void) | |||
333 | /* Deregister */ | 334 | /* Deregister */ |
334 | misc_deregister(&wdt_miscdev); | 335 | misc_deregister(&wdt_miscdev); |
335 | unregister_reboot_notifier(&wdt_notifier); | 336 | unregister_reboot_notifier(&wdt_notifier); |
337 | pci_dev_put(alim7101_pmu); | ||
336 | } | 338 | } |
337 | 339 | ||
338 | static int __init alim7101_wdt_init(void) | 340 | static int __init alim7101_wdt_init(void) |
@@ -342,7 +344,8 @@ static int __init alim7101_wdt_init(void) | |||
342 | char tmp; | 344 | char tmp; |
343 | 345 | ||
344 | printk(KERN_INFO PFX "Steve Hill <steve@navaho.co.uk>.\n"); | 346 | printk(KERN_INFO PFX "Steve Hill <steve@navaho.co.uk>.\n"); |
345 | alim7101_pmu = pci_find_device(PCI_VENDOR_ID_AL, PCI_DEVICE_ID_AL_M7101,NULL); | 347 | alim7101_pmu = pci_get_device(PCI_VENDOR_ID_AL, PCI_DEVICE_ID_AL_M7101, |
348 | NULL); | ||
346 | if (!alim7101_pmu) { | 349 | if (!alim7101_pmu) { |
347 | printk(KERN_INFO PFX "ALi M7101 PMU not present - WDT not set\n"); | 350 | printk(KERN_INFO PFX "ALi M7101 PMU not present - WDT not set\n"); |
348 | return -EBUSY; | 351 | return -EBUSY; |
@@ -351,21 +354,23 @@ static int __init alim7101_wdt_init(void) | |||
351 | /* Set the WDT in the PMU to 1 second */ | 354 | /* Set the WDT in the PMU to 1 second */ |
352 | pci_write_config_byte(alim7101_pmu, ALI_7101_WDT, 0x02); | 355 | pci_write_config_byte(alim7101_pmu, ALI_7101_WDT, 0x02); |
353 | 356 | ||
354 | ali1543_south = pci_find_device(PCI_VENDOR_ID_AL, PCI_DEVICE_ID_AL_M1533, NULL); | 357 | ali1543_south = pci_get_device(PCI_VENDOR_ID_AL, PCI_DEVICE_ID_AL_M1533, |
358 | NULL); | ||
355 | if (!ali1543_south) { | 359 | if (!ali1543_south) { |
356 | printk(KERN_INFO PFX "ALi 1543 South-Bridge not present - WDT not set\n"); | 360 | printk(KERN_INFO PFX "ALi 1543 South-Bridge not present - WDT not set\n"); |
357 | return -EBUSY; | 361 | goto err_out; |
358 | } | 362 | } |
359 | pci_read_config_byte(ali1543_south, 0x5e, &tmp); | 363 | pci_read_config_byte(ali1543_south, 0x5e, &tmp); |
364 | pci_dev_put(ali1543_south); | ||
360 | if ((tmp & 0x1e) == 0x00) { | 365 | if ((tmp & 0x1e) == 0x00) { |
361 | if (!use_gpio) { | 366 | if (!use_gpio) { |
362 | printk(KERN_INFO PFX "Detected old alim7101 revision 'a1d'. If this is a cobalt board, set the 'use_gpio' module parameter.\n"); | 367 | printk(KERN_INFO PFX "Detected old alim7101 revision 'a1d'. If this is a cobalt board, set the 'use_gpio' module parameter.\n"); |
363 | return -EBUSY; | 368 | goto err_out; |
364 | } | 369 | } |
365 | nowayout = 1; | 370 | nowayout = 1; |
366 | } else if ((tmp & 0x1e) != 0x12 && (tmp & 0x1e) != 0x00) { | 371 | } else if ((tmp & 0x1e) != 0x12 && (tmp & 0x1e) != 0x00) { |
367 | printk(KERN_INFO PFX "ALi 1543 South-Bridge does not have the correct revision number (???1001?) - WDT not set\n"); | 372 | printk(KERN_INFO PFX "ALi 1543 South-Bridge does not have the correct revision number (???1001?) - WDT not set\n"); |
368 | return -EBUSY; | 373 | goto err_out; |
369 | } | 374 | } |
370 | 375 | ||
371 | if(timeout < 1 || timeout > 3600) /* arbitrary upper limit */ | 376 | if(timeout < 1 || timeout > 3600) /* arbitrary upper limit */ |
@@ -404,12 +409,23 @@ static int __init alim7101_wdt_init(void) | |||
404 | err_out_miscdev: | 409 | err_out_miscdev: |
405 | misc_deregister(&wdt_miscdev); | 410 | misc_deregister(&wdt_miscdev); |
406 | err_out: | 411 | err_out: |
412 | pci_dev_put(alim7101_pmu); | ||
407 | return rc; | 413 | return rc; |
408 | } | 414 | } |
409 | 415 | ||
410 | module_init(alim7101_wdt_init); | 416 | module_init(alim7101_wdt_init); |
411 | module_exit(alim7101_wdt_unload); | 417 | module_exit(alim7101_wdt_unload); |
412 | 418 | ||
419 | static struct pci_device_id alim7101_pci_tbl[] __devinitdata = { | ||
420 | { PCI_VENDOR_ID_AL, PCI_DEVICE_ID_AL_M1533, | ||
421 | PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, | ||
422 | { PCI_VENDOR_ID_AL, PCI_DEVICE_ID_AL_M7101, | ||
423 | PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, | ||
424 | { } | ||
425 | }; | ||
426 | |||
427 | MODULE_DEVICE_TABLE(pci, alim7101_pci_tbl); | ||
428 | |||
413 | MODULE_AUTHOR("Steve Hill"); | 429 | MODULE_AUTHOR("Steve Hill"); |
414 | MODULE_DESCRIPTION("ALi M7101 PMU Computer Watchdog Timer driver"); | 430 | MODULE_DESCRIPTION("ALi M7101 PMU Computer Watchdog Timer driver"); |
415 | MODULE_LICENSE("GPL"); | 431 | MODULE_LICENSE("GPL"); |
diff --git a/drivers/char/watchdog/at91_wdt.c b/drivers/char/watchdog/at91rm9200_wdt.c index cc266715ea32..cb86967e2c5f 100644 --- a/drivers/char/watchdog/at91_wdt.c +++ b/drivers/char/watchdog/at91rm9200_wdt.c | |||
@@ -21,6 +21,7 @@ | |||
21 | #include <linux/watchdog.h> | 21 | #include <linux/watchdog.h> |
22 | #include <asm/bitops.h> | 22 | #include <asm/bitops.h> |
23 | #include <asm/uaccess.h> | 23 | #include <asm/uaccess.h> |
24 | #include <asm/arch/at91_st.h> | ||
24 | 25 | ||
25 | 26 | ||
26 | #define WDT_DEFAULT_TIME 5 /* seconds */ | 27 | #define WDT_DEFAULT_TIME 5 /* seconds */ |
@@ -168,7 +169,7 @@ static int at91_wdt_ioctl(struct inode *inode, struct file *file, | |||
168 | return 0; | 169 | return 0; |
169 | 170 | ||
170 | default: | 171 | default: |
171 | return -ENOIOCTLCMD; | 172 | return -ENOTTY; |
172 | } | 173 | } |
173 | } | 174 | } |
174 | 175 | ||
diff --git a/drivers/char/watchdog/booke_wdt.c b/drivers/char/watchdog/booke_wdt.c index e3cefc538b40..488902231cc2 100644 --- a/drivers/char/watchdog/booke_wdt.c +++ b/drivers/char/watchdog/booke_wdt.c | |||
@@ -125,7 +125,7 @@ static int booke_wdt_ioctl (struct inode *inode, struct file *file, | |||
125 | return -EINVAL; | 125 | return -EINVAL; |
126 | return 0; | 126 | return 0; |
127 | default: | 127 | default: |
128 | return -ENOIOCTLCMD; | 128 | return -ENOTTY; |
129 | } | 129 | } |
130 | 130 | ||
131 | return 0; | 131 | return 0; |
diff --git a/drivers/char/watchdog/cpu5wdt.c b/drivers/char/watchdog/cpu5wdt.c index 04c7e49918db..00bdabb90f27 100644 --- a/drivers/char/watchdog/cpu5wdt.c +++ b/drivers/char/watchdog/cpu5wdt.c | |||
@@ -183,7 +183,7 @@ static int cpu5wdt_ioctl(struct inode *inode, struct file *file, unsigned int cm | |||
183 | } | 183 | } |
184 | break; | 184 | break; |
185 | default: | 185 | default: |
186 | return -ENOIOCTLCMD; | 186 | return -ENOTTY; |
187 | } | 187 | } |
188 | return 0; | 188 | return 0; |
189 | } | 189 | } |
diff --git a/drivers/char/watchdog/ep93xx_wdt.c b/drivers/char/watchdog/ep93xx_wdt.c index 77c8a955ae9e..01cf123b1616 100644 --- a/drivers/char/watchdog/ep93xx_wdt.c +++ b/drivers/char/watchdog/ep93xx_wdt.c | |||
@@ -144,7 +144,7 @@ static int | |||
144 | ep93xx_wdt_ioctl(struct inode *inode, struct file *file, unsigned int cmd, | 144 | ep93xx_wdt_ioctl(struct inode *inode, struct file *file, unsigned int cmd, |
145 | unsigned long arg) | 145 | unsigned long arg) |
146 | { | 146 | { |
147 | int ret = -ENOIOCTLCMD; | 147 | int ret = -ENOTTY; |
148 | 148 | ||
149 | switch (cmd) { | 149 | switch (cmd) { |
150 | case WDIOC_GETSUPPORT: | 150 | case WDIOC_GETSUPPORT: |
diff --git a/drivers/char/watchdog/eurotechwdt.c b/drivers/char/watchdog/eurotechwdt.c index 62dbccb2f6df..e228d6e173ce 100644 --- a/drivers/char/watchdog/eurotechwdt.c +++ b/drivers/char/watchdog/eurotechwdt.c | |||
@@ -153,7 +153,7 @@ static void eurwdt_activate_timer(void) | |||
153 | * Kernel methods. | 153 | * Kernel methods. |
154 | */ | 154 | */ |
155 | 155 | ||
156 | static irqreturn_t eurwdt_interrupt(int irq, void *dev_id, struct pt_regs *regs) | 156 | static irqreturn_t eurwdt_interrupt(int irq, void *dev_id) |
157 | { | 157 | { |
158 | printk(KERN_CRIT "timeout WDT timeout\n"); | 158 | printk(KERN_CRIT "timeout WDT timeout\n"); |
159 | 159 | ||
@@ -240,7 +240,7 @@ static int eurwdt_ioctl(struct inode *inode, struct file *file, | |||
240 | 240 | ||
241 | switch(cmd) { | 241 | switch(cmd) { |
242 | default: | 242 | default: |
243 | return -ENOIOCTLCMD; | 243 | return -ENOTTY; |
244 | 244 | ||
245 | case WDIOC_GETSUPPORT: | 245 | case WDIOC_GETSUPPORT: |
246 | return copy_to_user(argp, &ident, sizeof(ident)) ? -EFAULT : 0; | 246 | return copy_to_user(argp, &ident, sizeof(ident)) ? -EFAULT : 0; |
diff --git a/drivers/char/watchdog/i6300esb.c b/drivers/char/watchdog/i6300esb.c index 870539eabbf3..fb64df4d7c87 100644 --- a/drivers/char/watchdog/i6300esb.c +++ b/drivers/char/watchdog/i6300esb.c | |||
@@ -315,7 +315,7 @@ static int esb_ioctl (struct inode *inode, struct file *file, | |||
315 | return put_user(heartbeat, p); | 315 | return put_user(heartbeat, p); |
316 | 316 | ||
317 | default: | 317 | default: |
318 | return -ENOIOCTLCMD; | 318 | return -ENOTTY; |
319 | } | 319 | } |
320 | } | 320 | } |
321 | 321 | ||
diff --git a/drivers/char/watchdog/i8xx_tco.c b/drivers/char/watchdog/i8xx_tco.c index 8385dd36eefe..e0627d79707b 100644 --- a/drivers/char/watchdog/i8xx_tco.c +++ b/drivers/char/watchdog/i8xx_tco.c | |||
@@ -356,7 +356,7 @@ static int i8xx_tco_ioctl (struct inode *inode, struct file *file, | |||
356 | } | 356 | } |
357 | 357 | ||
358 | default: | 358 | default: |
359 | return -ENOIOCTLCMD; | 359 | return -ENOTTY; |
360 | } | 360 | } |
361 | } | 361 | } |
362 | 362 | ||
@@ -406,18 +406,18 @@ static struct notifier_block i8xx_tco_notifier = { | |||
406 | * want to register another driver on the same PCI id. | 406 | * want to register another driver on the same PCI id. |
407 | */ | 407 | */ |
408 | static struct pci_device_id i8xx_tco_pci_tbl[] = { | 408 | static struct pci_device_id i8xx_tco_pci_tbl[] = { |
409 | { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801AA_0, PCI_ANY_ID, PCI_ANY_ID, }, | 409 | { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801AA_0) }, |
410 | { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801AB_0, PCI_ANY_ID, PCI_ANY_ID, }, | 410 | { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801AB_0) }, |
411 | { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801BA_0, PCI_ANY_ID, PCI_ANY_ID, }, | 411 | { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801BA_0) }, |
412 | { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801BA_10, PCI_ANY_ID, PCI_ANY_ID, }, | 412 | { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801BA_10) }, |
413 | { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801CA_0, PCI_ANY_ID, PCI_ANY_ID, }, | 413 | { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801CA_0) }, |
414 | { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801CA_12, PCI_ANY_ID, PCI_ANY_ID, }, | 414 | { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801CA_12) }, |
415 | { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801DB_0, PCI_ANY_ID, PCI_ANY_ID, }, | 415 | { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801DB_0) }, |
416 | { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801DB_12, PCI_ANY_ID, PCI_ANY_ID, }, | 416 | { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801DB_12) }, |
417 | { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801E_0, PCI_ANY_ID, PCI_ANY_ID, }, | 417 | { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801E_0) }, |
418 | { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801EB_0, PCI_ANY_ID, PCI_ANY_ID, }, | 418 | { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801EB_0) }, |
419 | { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ESB_1, PCI_ANY_ID, PCI_ANY_ID, }, | 419 | { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ESB_1) }, |
420 | { 0, }, /* End of list */ | 420 | { }, /* End of list */ |
421 | }; | 421 | }; |
422 | MODULE_DEVICE_TABLE (pci, i8xx_tco_pci_tbl); | 422 | MODULE_DEVICE_TABLE (pci, i8xx_tco_pci_tbl); |
423 | 423 | ||
@@ -434,12 +434,11 @@ static unsigned char __init i8xx_tco_getdevice (void) | |||
434 | * Find the PCI device | 434 | * Find the PCI device |
435 | */ | 435 | */ |
436 | 436 | ||
437 | while ((dev = pci_find_device(PCI_ANY_ID, PCI_ANY_ID, dev)) != NULL) { | 437 | for_each_pci_dev(dev) |
438 | if (pci_match_id(i8xx_tco_pci_tbl, dev)) { | 438 | if (pci_match_id(i8xx_tco_pci_tbl, dev)) { |
439 | i8xx_tco_pci = dev; | 439 | i8xx_tco_pci = dev; |
440 | break; | 440 | break; |
441 | } | 441 | } |
442 | } | ||
443 | 442 | ||
444 | if (i8xx_tco_pci) { | 443 | if (i8xx_tco_pci) { |
445 | /* | 444 | /* |
@@ -454,6 +453,7 @@ static unsigned char __init i8xx_tco_getdevice (void) | |||
454 | /* Something's wrong here, ACPIBASE has to be set */ | 453 | /* Something's wrong here, ACPIBASE has to be set */ |
455 | if (badr == 0x0001 || badr == 0x0000) { | 454 | if (badr == 0x0001 || badr == 0x0000) { |
456 | printk (KERN_ERR PFX "failed to get TCOBASE address\n"); | 455 | printk (KERN_ERR PFX "failed to get TCOBASE address\n"); |
456 | pci_dev_put(i8xx_tco_pci); | ||
457 | return 0; | 457 | return 0; |
458 | } | 458 | } |
459 | 459 | ||
@@ -465,6 +465,7 @@ static unsigned char __init i8xx_tco_getdevice (void) | |||
465 | pci_read_config_byte (i8xx_tco_pci, 0xd4, &val1); | 465 | pci_read_config_byte (i8xx_tco_pci, 0xd4, &val1); |
466 | if (val1 & 0x02) { | 466 | if (val1 & 0x02) { |
467 | printk (KERN_ERR PFX "failed to reset NO_REBOOT flag, reboot disabled by hardware\n"); | 467 | printk (KERN_ERR PFX "failed to reset NO_REBOOT flag, reboot disabled by hardware\n"); |
468 | pci_dev_put(i8xx_tco_pci); | ||
468 | return 0; /* Cannot reset NO_REBOOT bit */ | 469 | return 0; /* Cannot reset NO_REBOOT bit */ |
469 | } | 470 | } |
470 | } | 471 | } |
@@ -476,6 +477,7 @@ static unsigned char __init i8xx_tco_getdevice (void) | |||
476 | if (!request_region (SMI_EN + 1, 1, "i8xx TCO")) { | 477 | if (!request_region (SMI_EN + 1, 1, "i8xx TCO")) { |
477 | printk (KERN_ERR PFX "I/O address 0x%04x already in use\n", | 478 | printk (KERN_ERR PFX "I/O address 0x%04x already in use\n", |
478 | SMI_EN + 1); | 479 | SMI_EN + 1); |
480 | pci_dev_put(i8xx_tco_pci); | ||
479 | return 0; | 481 | return 0; |
480 | } | 482 | } |
481 | val1 = inb (SMI_EN + 1); | 483 | val1 = inb (SMI_EN + 1); |
@@ -542,6 +544,7 @@ unreg_notifier: | |||
542 | unreg_region: | 544 | unreg_region: |
543 | release_region (TCOBASE, 0x10); | 545 | release_region (TCOBASE, 0x10); |
544 | out: | 546 | out: |
547 | pci_dev_put(i8xx_tco_pci); | ||
545 | return ret; | 548 | return ret; |
546 | } | 549 | } |
547 | 550 | ||
@@ -555,6 +558,8 @@ static void __exit watchdog_cleanup (void) | |||
555 | misc_deregister (&i8xx_tco_miscdev); | 558 | misc_deregister (&i8xx_tco_miscdev); |
556 | unregister_reboot_notifier(&i8xx_tco_notifier); | 559 | unregister_reboot_notifier(&i8xx_tco_notifier); |
557 | release_region (TCOBASE, 0x10); | 560 | release_region (TCOBASE, 0x10); |
561 | |||
562 | pci_dev_put(i8xx_tco_pci); | ||
558 | } | 563 | } |
559 | 564 | ||
560 | module_init(watchdog_init); | 565 | module_init(watchdog_init); |
diff --git a/drivers/char/watchdog/iTCO_vendor_support.c b/drivers/char/watchdog/iTCO_vendor_support.c new file mode 100644 index 000000000000..415083990097 --- /dev/null +++ b/drivers/char/watchdog/iTCO_vendor_support.c | |||
@@ -0,0 +1,307 @@ | |||
1 | /* | ||
2 | * intel TCO vendor specific watchdog driver support | ||
3 | * | ||
4 | * (c) Copyright 2006 Wim Van Sebroeck <wim@iguana.be>. | ||
5 | * | ||
6 | * This program is free software; you can redistribute it and/or | ||
7 | * modify it under the terms of the GNU General Public License | ||
8 | * as published by the Free Software Foundation; either version | ||
9 | * 2 of the License, or (at your option) any later version. | ||
10 | * | ||
11 | * Neither Wim Van Sebroeck nor Iguana vzw. admit liability nor | ||
12 | * provide warranty for any of this software. This material is | ||
13 | * provided "AS-IS" and at no charge. | ||
14 | */ | ||
15 | |||
16 | /* | ||
17 | * Includes, defines, variables, module parameters, ... | ||
18 | */ | ||
19 | |||
20 | /* Module and version information */ | ||
21 | #define DRV_NAME "iTCO_vendor_support" | ||
22 | #define DRV_VERSION "1.01" | ||
23 | #define DRV_RELDATE "11-Nov-2006" | ||
24 | #define PFX DRV_NAME ": " | ||
25 | |||
26 | /* Includes */ | ||
27 | #include <linux/module.h> /* For module specific items */ | ||
28 | #include <linux/moduleparam.h> /* For new moduleparam's */ | ||
29 | #include <linux/types.h> /* For standard types (like size_t) */ | ||
30 | #include <linux/errno.h> /* For the -ENODEV/... values */ | ||
31 | #include <linux/kernel.h> /* For printk/panic/... */ | ||
32 | #include <linux/init.h> /* For __init/__exit/... */ | ||
33 | #include <linux/ioport.h> /* For io-port access */ | ||
34 | |||
35 | #include <asm/io.h> /* For inb/outb/... */ | ||
36 | |||
37 | /* iTCO defines */ | ||
38 | #define SMI_EN acpibase + 0x30 /* SMI Control and Enable Register */ | ||
39 | #define TCOBASE acpibase + 0x60 /* TCO base address */ | ||
40 | #define TCO1_STS TCOBASE + 0x04 /* TCO1 Status Register */ | ||
41 | |||
42 | /* List of vendor support modes */ | ||
43 | #define SUPERMICRO_OLD_BOARD 1 /* SuperMicro Pentium 3 Era 370SSE+-OEM1/P3TSSE */ | ||
44 | #define SUPERMICRO_NEW_BOARD 2 /* SuperMicro Pentium 4 / Xeon 4 / EMT64T Era Systems */ | ||
45 | |||
46 | static int vendorsupport = 0; | ||
47 | module_param(vendorsupport, int, 0); | ||
48 | MODULE_PARM_DESC(vendorsupport, "iTCO vendor specific support mode, default=0 (none), 1=SuperMicro Pent3, 2=SuperMicro Pent4+"); | ||
49 | |||
50 | /* | ||
51 | * Vendor Specific Support | ||
52 | */ | ||
53 | |||
54 | /* | ||
55 | * Vendor Support: 1 | ||
56 | * Board: Super Micro Computer Inc. 370SSE+-OEM1/P3TSSE | ||
57 | * iTCO chipset: ICH2 | ||
58 | * | ||
59 | * Code contributed by: R. Seretny <lkpatches@paypc.com> | ||
60 | * Documentation obtained by R. Seretny from SuperMicro Technical Support | ||
61 | * | ||
62 | * To enable Watchdog function: | ||
63 | * BIOS setup -> Power -> TCO Logic SMI Enable -> Within5Minutes | ||
64 | * This setting enables SMI to clear the watchdog expired flag. | ||
65 | * If BIOS or CPU fail which may cause SMI hang, then system will | ||
66 | * reboot. When application starts to use watchdog function, | ||
67 | * application has to take over the control from SMI. | ||
68 | * | ||
69 | * For P3TSSE, J36 jumper needs to be removed to enable the Watchdog | ||
70 | * function. | ||
71 | * | ||
72 | * Note: The system will reboot when Expire Flag is set TWICE. | ||
73 | * So, if the watchdog timer is 20 seconds, then the maximum hang | ||
74 | * time is about 40 seconds, and the minimum hang time is about | ||
75 | * 20.6 seconds. | ||
76 | */ | ||
77 | |||
78 | static void supermicro_old_pre_start(unsigned long acpibase) | ||
79 | { | ||
80 | unsigned long val32; | ||
81 | |||
82 | val32 = inl(SMI_EN); | ||
83 | val32 &= 0xffffdfff; /* Turn off SMI clearing watchdog */ | ||
84 | outl(val32, SMI_EN); /* Needed to activate watchdog */ | ||
85 | } | ||
86 | |||
87 | static void supermicro_old_pre_stop(unsigned long acpibase) | ||
88 | { | ||
89 | unsigned long val32; | ||
90 | |||
91 | val32 = inl(SMI_EN); | ||
92 | val32 &= 0x00002000; /* Turn on SMI clearing watchdog */ | ||
93 | outl(val32, SMI_EN); /* Needed to deactivate watchdog */ | ||
94 | } | ||
95 | |||
96 | static void supermicro_old_pre_keepalive(unsigned long acpibase) | ||
97 | { | ||
98 | /* Reload TCO Timer (done in iTCO_wdt_keepalive) + */ | ||
99 | /* Clear "Expire Flag" (Bit 3 of TC01_STS register) */ | ||
100 | outb(0x08, TCO1_STS); | ||
101 | } | ||
102 | |||
103 | /* | ||
104 | * Vendor Support: 2 | ||
105 | * Board: Super Micro Computer Inc. P4SBx, P4DPx | ||
106 | * iTCO chipset: ICH4 | ||
107 | * | ||
108 | * Code contributed by: R. Seretny <lkpatches@paypc.com> | ||
109 | * Documentation obtained by R. Seretny from SuperMicro Technical Support | ||
110 | * | ||
111 | * To enable Watchdog function: | ||
112 | * 1. BIOS | ||
113 | * For P4SBx: | ||
114 | * BIOS setup -> Advanced -> Integrated Peripherals -> Watch Dog Feature | ||
115 | * For P4DPx: | ||
116 | * BIOS setup -> Advanced -> I/O Device Configuration -> Watch Dog | ||
117 | * This setting enables or disables Watchdog function. When enabled, the | ||
118 | * default watchdog timer is set to be 5 minutes (about 4’35â€). It is | ||
119 | * enough to load and run the OS. The application (service or driver) has | ||
120 | * to take over the control once OS is running up and before watchdog | ||
121 | * expires. | ||
122 | * | ||
123 | * 2. JUMPER | ||
124 | * For P4SBx: JP39 | ||
125 | * For P4DPx: JP37 | ||
126 | * This jumper is used for safety. Closed is enabled. This jumper | ||
127 | * prevents user enables watchdog in BIOS by accident. | ||
128 | * | ||
129 | * To enable Watch Dog function, both BIOS and JUMPER must be enabled. | ||
130 | * | ||
131 | * The documentation lists motherboards P4SBx and P4DPx series as of | ||
132 | * 20-March-2002. However, this code works flawlessly with much newer | ||
133 | * motherboards, such as my X6DHR-8G2 (SuperServer 6014H-82). | ||
134 | * | ||
135 | * The original iTCO driver as written does not actually reset the | ||
136 | * watchdog timer on these machines, as a result they reboot after five | ||
137 | * minutes. | ||
138 | * | ||
139 | * NOTE: You may leave the Watchdog function disabled in the SuperMicro | ||
140 | * BIOS to avoid a "boot-race"... This driver will enable watchdog | ||
141 | * functionality even if it's disabled in the BIOS once the /dev/watchdog | ||
142 | * file is opened. | ||
143 | */ | ||
144 | |||
145 | /* I/O Port's */ | ||
146 | #define SM_REGINDEX 0x2e /* SuperMicro ICH4+ Register Index */ | ||
147 | #define SM_DATAIO 0x2f /* SuperMicro ICH4+ Register Data I/O */ | ||
148 | |||
149 | /* Control Register's */ | ||
150 | #define SM_CTLPAGESW 0x07 /* SuperMicro ICH4+ Control Page Switch */ | ||
151 | #define SM_CTLPAGE 0x08 /* SuperMicro ICH4+ Control Page Num */ | ||
152 | |||
153 | #define SM_WATCHENABLE 0x30 /* Watchdog enable: Bit 0: 0=off, 1=on */ | ||
154 | |||
155 | #define SM_WATCHPAGE 0x87 /* Watchdog unlock control page */ | ||
156 | |||
157 | #define SM_ENDWATCH 0xAA /* Watchdog lock control page */ | ||
158 | |||
159 | #define SM_COUNTMODE 0xf5 /* Watchdog count mode select */ | ||
160 | /* (Bit 3: 0 = seconds, 1 = minutes */ | ||
161 | |||
162 | #define SM_WATCHTIMER 0xf6 /* 8-bits, Watchdog timer counter (RW) */ | ||
163 | |||
164 | #define SM_RESETCONTROL 0xf7 /* Watchdog reset control */ | ||
165 | /* Bit 6: timer is reset by kbd interrupt */ | ||
166 | /* Bit 7: timer is reset by mouse interrupt */ | ||
167 | |||
168 | static void supermicro_new_unlock_watchdog(void) | ||
169 | { | ||
170 | outb(SM_WATCHPAGE, SM_REGINDEX); /* Write 0x87 to port 0x2e twice */ | ||
171 | outb(SM_WATCHPAGE, SM_REGINDEX); | ||
172 | |||
173 | outb(SM_CTLPAGESW, SM_REGINDEX); /* Switch to watchdog control page */ | ||
174 | outb(SM_CTLPAGE, SM_DATAIO); | ||
175 | } | ||
176 | |||
177 | static void supermicro_new_lock_watchdog(void) | ||
178 | { | ||
179 | outb(SM_ENDWATCH, SM_REGINDEX); | ||
180 | } | ||
181 | |||
182 | static void supermicro_new_pre_start(unsigned int heartbeat) | ||
183 | { | ||
184 | unsigned int val; | ||
185 | |||
186 | supermicro_new_unlock_watchdog(); | ||
187 | |||
188 | /* Watchdog timer setting needs to be in seconds*/ | ||
189 | outb(SM_COUNTMODE, SM_REGINDEX); | ||
190 | val = inb(SM_DATAIO); | ||
191 | val &= 0xF7; | ||
192 | outb(val, SM_DATAIO); | ||
193 | |||
194 | /* Write heartbeat interval to WDOG */ | ||
195 | outb (SM_WATCHTIMER, SM_REGINDEX); | ||
196 | outb((heartbeat & 255), SM_DATAIO); | ||
197 | |||
198 | /* Make sure keyboard/mouse interrupts don't interfere */ | ||
199 | outb(SM_RESETCONTROL, SM_REGINDEX); | ||
200 | val = inb(SM_DATAIO); | ||
201 | val &= 0x3f; | ||
202 | outb(val, SM_DATAIO); | ||
203 | |||
204 | /* enable watchdog by setting bit 0 of Watchdog Enable to 1 */ | ||
205 | outb(SM_WATCHENABLE, SM_REGINDEX); | ||
206 | val = inb(SM_DATAIO); | ||
207 | val |= 0x01; | ||
208 | outb(val, SM_DATAIO); | ||
209 | |||
210 | supermicro_new_lock_watchdog(); | ||
211 | } | ||
212 | |||
213 | static void supermicro_new_pre_stop(void) | ||
214 | { | ||
215 | unsigned int val; | ||
216 | |||
217 | supermicro_new_unlock_watchdog(); | ||
218 | |||
219 | /* disable watchdog by setting bit 0 of Watchdog Enable to 0 */ | ||
220 | outb(SM_WATCHENABLE, SM_REGINDEX); | ||
221 | val = inb(SM_DATAIO); | ||
222 | val &= 0xFE; | ||
223 | outb(val, SM_DATAIO); | ||
224 | |||
225 | supermicro_new_lock_watchdog(); | ||
226 | } | ||
227 | |||
228 | static void supermicro_new_pre_set_heartbeat(unsigned int heartbeat) | ||
229 | { | ||
230 | supermicro_new_unlock_watchdog(); | ||
231 | |||
232 | /* reset watchdog timeout to heartveat value */ | ||
233 | outb(SM_WATCHTIMER, SM_REGINDEX); | ||
234 | outb((heartbeat & 255), SM_DATAIO); | ||
235 | |||
236 | supermicro_new_lock_watchdog(); | ||
237 | } | ||
238 | |||
239 | /* | ||
240 | * Generic Support Functions | ||
241 | */ | ||
242 | |||
243 | void iTCO_vendor_pre_start(unsigned long acpibase, | ||
244 | unsigned int heartbeat) | ||
245 | { | ||
246 | if (vendorsupport == SUPERMICRO_OLD_BOARD) | ||
247 | supermicro_old_pre_start(acpibase); | ||
248 | else if (vendorsupport == SUPERMICRO_NEW_BOARD) | ||
249 | supermicro_new_pre_start(heartbeat); | ||
250 | } | ||
251 | EXPORT_SYMBOL(iTCO_vendor_pre_start); | ||
252 | |||
253 | void iTCO_vendor_pre_stop(unsigned long acpibase) | ||
254 | { | ||
255 | if (vendorsupport == SUPERMICRO_OLD_BOARD) | ||
256 | supermicro_old_pre_stop(acpibase); | ||
257 | else if (vendorsupport == SUPERMICRO_NEW_BOARD) | ||
258 | supermicro_new_pre_stop(); | ||
259 | } | ||
260 | EXPORT_SYMBOL(iTCO_vendor_pre_stop); | ||
261 | |||
262 | void iTCO_vendor_pre_keepalive(unsigned long acpibase, unsigned int heartbeat) | ||
263 | { | ||
264 | if (vendorsupport == SUPERMICRO_OLD_BOARD) | ||
265 | supermicro_old_pre_keepalive(acpibase); | ||
266 | else if (vendorsupport == SUPERMICRO_NEW_BOARD) | ||
267 | supermicro_new_pre_set_heartbeat(heartbeat); | ||
268 | } | ||
269 | EXPORT_SYMBOL(iTCO_vendor_pre_keepalive); | ||
270 | |||
271 | void iTCO_vendor_pre_set_heartbeat(unsigned int heartbeat) | ||
272 | { | ||
273 | if (vendorsupport == SUPERMICRO_NEW_BOARD) | ||
274 | supermicro_new_pre_set_heartbeat(heartbeat); | ||
275 | } | ||
276 | EXPORT_SYMBOL(iTCO_vendor_pre_set_heartbeat); | ||
277 | |||
278 | int iTCO_vendor_check_noreboot_on(void) | ||
279 | { | ||
280 | switch(vendorsupport) { | ||
281 | case SUPERMICRO_OLD_BOARD: | ||
282 | return 0; | ||
283 | default: | ||
284 | return 1; | ||
285 | } | ||
286 | } | ||
287 | EXPORT_SYMBOL(iTCO_vendor_check_noreboot_on); | ||
288 | |||
289 | static int __init iTCO_vendor_init_module(void) | ||
290 | { | ||
291 | printk (KERN_INFO PFX "vendor-support=%d\n", vendorsupport); | ||
292 | return 0; | ||
293 | } | ||
294 | |||
295 | static void __exit iTCO_vendor_exit_module(void) | ||
296 | { | ||
297 | printk (KERN_INFO PFX "Module Unloaded\n"); | ||
298 | } | ||
299 | |||
300 | module_init(iTCO_vendor_init_module); | ||
301 | module_exit(iTCO_vendor_exit_module); | ||
302 | |||
303 | MODULE_AUTHOR("Wim Van Sebroeck <wim@iguana.be>, R. Seretny <lkpatches@paypc.com>"); | ||
304 | MODULE_DESCRIPTION("Intel TCO Vendor Specific WatchDog Timer Driver Support"); | ||
305 | MODULE_VERSION(DRV_VERSION); | ||
306 | MODULE_LICENSE("GPL"); | ||
307 | |||
diff --git a/drivers/char/watchdog/iTCO_wdt.c b/drivers/char/watchdog/iTCO_wdt.c new file mode 100644 index 000000000000..7eac922df867 --- /dev/null +++ b/drivers/char/watchdog/iTCO_wdt.c | |||
@@ -0,0 +1,772 @@ | |||
1 | /* | ||
2 | * intel TCO Watchdog Driver (Used in i82801 and i6300ESB chipsets) | ||
3 | * | ||
4 | * (c) Copyright 2006 Wim Van Sebroeck <wim@iguana.be>. | ||
5 | * | ||
6 | * This program is free software; you can redistribute it and/or | ||
7 | * modify it under the terms of the GNU General Public License | ||
8 | * as published by the Free Software Foundation; either version | ||
9 | * 2 of the License, or (at your option) any later version. | ||
10 | * | ||
11 | * Neither Wim Van Sebroeck nor Iguana vzw. admit liability nor | ||
12 | * provide warranty for any of this software. This material is | ||
13 | * provided "AS-IS" and at no charge. | ||
14 | * | ||
15 | * The TCO watchdog is implemented in the following I/O controller hubs: | ||
16 | * (See the intel documentation on http://developer.intel.com.) | ||
17 | * 82801AA (ICH) : document number 290655-003, 290677-014, | ||
18 | * 82801AB (ICHO) : document number 290655-003, 290677-014, | ||
19 | * 82801BA (ICH2) : document number 290687-002, 298242-027, | ||
20 | * 82801BAM (ICH2-M) : document number 290687-002, 298242-027, | ||
21 | * 82801CA (ICH3-S) : document number 290733-003, 290739-013, | ||
22 | * 82801CAM (ICH3-M) : document number 290716-001, 290718-007, | ||
23 | * 82801DB (ICH4) : document number 290744-001, 290745-020, | ||
24 | * 82801DBM (ICH4-M) : document number 252337-001, 252663-005, | ||
25 | * 82801E (C-ICH) : document number 273599-001, 273645-002, | ||
26 | * 82801EB (ICH5) : document number 252516-001, 252517-003, | ||
27 | * 82801ER (ICH5R) : document number 252516-001, 252517-003, | ||
28 | * 82801FB (ICH6) : document number 301473-002, 301474-007, | ||
29 | * 82801FR (ICH6R) : document number 301473-002, 301474-007, | ||
30 | * 82801FBM (ICH6-M) : document number 301473-002, 301474-007, | ||
31 | * 82801FW (ICH6W) : document number 301473-001, 301474-007, | ||
32 | * 82801FRW (ICH6RW) : document number 301473-001, 301474-007, | ||
33 | * 82801GB (ICH7) : document number 307013-002, 307014-009, | ||
34 | * 82801GR (ICH7R) : 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, | ||
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, | ||
42 | * 6300ESB (6300ESB) : document number 300641-003 | ||
43 | */ | ||
44 | |||
45 | /* | ||
46 | * Includes, defines, variables, module parameters, ... | ||
47 | */ | ||
48 | |||
49 | /* Module and version information */ | ||
50 | #define DRV_NAME "iTCO_wdt" | ||
51 | #define DRV_VERSION "1.01" | ||
52 | #define DRV_RELDATE "11-Nov-2006" | ||
53 | #define PFX DRV_NAME ": " | ||
54 | |||
55 | /* Includes */ | ||
56 | #include <linux/module.h> /* For module specific items */ | ||
57 | #include <linux/moduleparam.h> /* For new moduleparam's */ | ||
58 | #include <linux/types.h> /* For standard types (like size_t) */ | ||
59 | #include <linux/errno.h> /* For the -ENODEV/... values */ | ||
60 | #include <linux/kernel.h> /* For printk/panic/... */ | ||
61 | #include <linux/miscdevice.h> /* For MODULE_ALIAS_MISCDEV(WATCHDOG_MINOR) */ | ||
62 | #include <linux/watchdog.h> /* For the watchdog specific items */ | ||
63 | #include <linux/init.h> /* For __init/__exit/... */ | ||
64 | #include <linux/fs.h> /* For file operations */ | ||
65 | #include <linux/platform_device.h> /* For platform_driver framework */ | ||
66 | #include <linux/pci.h> /* For pci functions */ | ||
67 | #include <linux/ioport.h> /* For io-port access */ | ||
68 | #include <linux/spinlock.h> /* For spin_lock/spin_unlock/... */ | ||
69 | |||
70 | #include <asm/uaccess.h> /* For copy_to_user/put_user/... */ | ||
71 | #include <asm/io.h> /* For inb/outb/... */ | ||
72 | |||
73 | /* TCO related info */ | ||
74 | enum iTCO_chipsets { | ||
75 | TCO_ICH = 0, /* ICH */ | ||
76 | TCO_ICH0, /* ICH0 */ | ||
77 | TCO_ICH2, /* ICH2 */ | ||
78 | TCO_ICH2M, /* ICH2-M */ | ||
79 | TCO_ICH3, /* ICH3-S */ | ||
80 | TCO_ICH3M, /* ICH3-M */ | ||
81 | TCO_ICH4, /* ICH4 */ | ||
82 | TCO_ICH4M, /* ICH4-M */ | ||
83 | TCO_CICH, /* C-ICH */ | ||
84 | TCO_ICH5, /* ICH5 & ICH5R */ | ||
85 | TCO_6300ESB, /* 6300ESB */ | ||
86 | TCO_ICH6, /* ICH6 & ICH6R */ | ||
87 | TCO_ICH6M, /* ICH6-M */ | ||
88 | TCO_ICH6W, /* ICH6W & ICH6RW */ | ||
89 | TCO_ICH7, /* ICH7 & ICH7R */ | ||
90 | TCO_ICH7M, /* ICH7-M */ | ||
91 | TCO_ICH7MDH, /* ICH7-M DH */ | ||
92 | TCO_ICH8, /* ICH8 & ICH8R */ | ||
93 | TCO_ICH8DH, /* ICH8DH */ | ||
94 | TCO_ICH8DO, /* ICH8DO */ | ||
95 | }; | ||
96 | |||
97 | static struct { | ||
98 | char *name; | ||
99 | unsigned int iTCO_version; | ||
100 | } iTCO_chipset_info[] __devinitdata = { | ||
101 | {"ICH", 1}, | ||
102 | {"ICH0", 1}, | ||
103 | {"ICH2", 1}, | ||
104 | {"ICH2-M", 1}, | ||
105 | {"ICH3-S", 1}, | ||
106 | {"ICH3-M", 1}, | ||
107 | {"ICH4", 1}, | ||
108 | {"ICH4-M", 1}, | ||
109 | {"C-ICH", 1}, | ||
110 | {"ICH5 or ICH5R", 1}, | ||
111 | {"6300ESB", 1}, | ||
112 | {"ICH6 or ICH6R", 2}, | ||
113 | {"ICH6-M", 2}, | ||
114 | {"ICH6W or ICH6RW", 2}, | ||
115 | {"ICH7 or ICH7R", 2}, | ||
116 | {"ICH7-M", 2}, | ||
117 | {"ICH7-M DH", 2}, | ||
118 | {"ICH8 or ICH8R", 2}, | ||
119 | {"ICH8DH", 2}, | ||
120 | {"ICH8DO", 2}, | ||
121 | {NULL,0} | ||
122 | }; | ||
123 | |||
124 | /* | ||
125 | * This data only exists for exporting the supported PCI ids | ||
126 | * via MODULE_DEVICE_TABLE. We do not actually register a | ||
127 | * pci_driver, because the I/O Controller Hub has also other | ||
128 | * functions that probably will be registered by other drivers. | ||
129 | */ | ||
130 | static struct pci_device_id iTCO_wdt_pci_tbl[] = { | ||
131 | { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801AA_0, PCI_ANY_ID, PCI_ANY_ID, 0, 0, TCO_ICH }, | ||
132 | { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801AB_0, PCI_ANY_ID, PCI_ANY_ID, 0, 0, TCO_ICH0 }, | ||
133 | { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801BA_0, PCI_ANY_ID, PCI_ANY_ID, 0, 0, TCO_ICH2 }, | ||
134 | { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801BA_10, PCI_ANY_ID, PCI_ANY_ID, 0, 0, TCO_ICH2M }, | ||
135 | { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801CA_0, PCI_ANY_ID, PCI_ANY_ID, 0, 0, TCO_ICH3 }, | ||
136 | { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801CA_12, PCI_ANY_ID, PCI_ANY_ID, 0, 0, TCO_ICH3M }, | ||
137 | { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801DB_0, PCI_ANY_ID, PCI_ANY_ID, 0, 0, TCO_ICH4 }, | ||
138 | { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801DB_12, PCI_ANY_ID, PCI_ANY_ID, 0, 0, TCO_ICH4M }, | ||
139 | { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801E_0, PCI_ANY_ID, PCI_ANY_ID, 0, 0, TCO_CICH }, | ||
140 | { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801EB_0, PCI_ANY_ID, PCI_ANY_ID, 0, 0, TCO_ICH5 }, | ||
141 | { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ESB_1, PCI_ANY_ID, PCI_ANY_ID, 0, 0, TCO_6300ESB }, | ||
142 | { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ICH6_0, PCI_ANY_ID, PCI_ANY_ID, 0, 0, TCO_ICH6 }, | ||
143 | { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ICH6_1, PCI_ANY_ID, PCI_ANY_ID, 0, 0, TCO_ICH6M }, | ||
144 | { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ICH6_2, PCI_ANY_ID, PCI_ANY_ID, 0, 0, TCO_ICH6W }, | ||
145 | { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ICH7_0, PCI_ANY_ID, PCI_ANY_ID, 0, 0, TCO_ICH7 }, | ||
146 | { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ICH7_1, PCI_ANY_ID, PCI_ANY_ID, 0, 0, TCO_ICH7M }, | ||
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 }, | ||
151 | { 0, }, /* End of list */ | ||
152 | }; | ||
153 | MODULE_DEVICE_TABLE (pci, iTCO_wdt_pci_tbl); | ||
154 | |||
155 | /* Address definitions for the TCO */ | ||
156 | #define TCOBASE iTCO_wdt_private.ACPIBASE + 0x60 /* TCO base address */ | ||
157 | #define SMI_EN iTCO_wdt_private.ACPIBASE + 0x30 /* SMI Control and Enable Register */ | ||
158 | |||
159 | #define TCO_RLD TCOBASE + 0x00 /* TCO Timer Reload and Current Value */ | ||
160 | #define TCOv1_TMR TCOBASE + 0x01 /* TCOv1 Timer Initial Value */ | ||
161 | #define TCO_DAT_IN TCOBASE + 0x02 /* TCO Data In Register */ | ||
162 | #define TCO_DAT_OUT TCOBASE + 0x03 /* TCO Data Out Register */ | ||
163 | #define TCO1_STS TCOBASE + 0x04 /* TCO1 Status Register */ | ||
164 | #define TCO2_STS TCOBASE + 0x06 /* TCO2 Status Register */ | ||
165 | #define TCO1_CNT TCOBASE + 0x08 /* TCO1 Control Register */ | ||
166 | #define TCO2_CNT TCOBASE + 0x0a /* TCO2 Control Register */ | ||
167 | #define TCOv2_TMR TCOBASE + 0x12 /* TCOv2 Timer Initial Value */ | ||
168 | |||
169 | /* internal variables */ | ||
170 | static unsigned long is_active; | ||
171 | static char expect_release; | ||
172 | static struct { /* this is private data for the iTCO_wdt device */ | ||
173 | unsigned int iTCO_version; /* TCO version/generation */ | ||
174 | unsigned long ACPIBASE; /* The cards ACPIBASE address (TCOBASE = ACPIBASE+0x60) */ | ||
175 | unsigned long __iomem *gcs; /* NO_REBOOT flag is Memory-Mapped GCS register bit 5 (TCO version 2) */ | ||
176 | spinlock_t io_lock; /* the lock for io operations */ | ||
177 | struct pci_dev *pdev; /* the PCI-device */ | ||
178 | } iTCO_wdt_private; | ||
179 | |||
180 | static struct platform_device *iTCO_wdt_platform_device; /* the watchdog platform device */ | ||
181 | |||
182 | /* module parameters */ | ||
183 | #define WATCHDOG_HEARTBEAT 30 /* 30 sec default heartbeat */ | ||
184 | static int heartbeat = WATCHDOG_HEARTBEAT; /* in seconds */ | ||
185 | module_param(heartbeat, int, 0); | ||
186 | MODULE_PARM_DESC(heartbeat, "Watchdog heartbeat in seconds. (2<heartbeat<39 (TCO v1) or 613 (TCO v2), default=" __MODULE_STRING(WATCHDOG_HEARTBEAT) ")"); | ||
187 | |||
188 | static int nowayout = WATCHDOG_NOWAYOUT; | ||
189 | module_param(nowayout, int, 0); | ||
190 | MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default=CONFIG_WATCHDOG_NOWAYOUT)"); | ||
191 | |||
192 | /* iTCO Vendor Specific Support hooks */ | ||
193 | #ifdef CONFIG_ITCO_VENDOR_SUPPORT | ||
194 | extern void iTCO_vendor_pre_start(unsigned long, unsigned int); | ||
195 | extern void iTCO_vendor_pre_stop(unsigned long); | ||
196 | extern void iTCO_vendor_pre_keepalive(unsigned long, unsigned int); | ||
197 | extern void iTCO_vendor_pre_set_heartbeat(unsigned int); | ||
198 | extern int iTCO_vendor_check_noreboot_on(void); | ||
199 | #else | ||
200 | #define iTCO_vendor_pre_start(acpibase, heartbeat) {} | ||
201 | #define iTCO_vendor_pre_stop(acpibase) {} | ||
202 | #define iTCO_vendor_pre_keepalive(acpibase,heartbeat) {} | ||
203 | #define iTCO_vendor_pre_set_heartbeat(heartbeat) {} | ||
204 | #define iTCO_vendor_check_noreboot_on() 1 /* 1=check noreboot; 0=don't check */ | ||
205 | #endif | ||
206 | |||
207 | /* | ||
208 | * Some TCO specific functions | ||
209 | */ | ||
210 | |||
211 | static inline unsigned int seconds_to_ticks(int seconds) | ||
212 | { | ||
213 | /* the internal timer is stored as ticks which decrement | ||
214 | * every 0.6 seconds */ | ||
215 | return (seconds * 10) / 6; | ||
216 | } | ||
217 | |||
218 | static void iTCO_wdt_set_NO_REBOOT_bit(void) | ||
219 | { | ||
220 | u32 val32; | ||
221 | |||
222 | /* Set the NO_REBOOT bit: this disables reboots */ | ||
223 | if (iTCO_wdt_private.iTCO_version == 2) { | ||
224 | val32 = readl(iTCO_wdt_private.gcs); | ||
225 | val32 |= 0x00000020; | ||
226 | writel(val32, iTCO_wdt_private.gcs); | ||
227 | } else if (iTCO_wdt_private.iTCO_version == 1) { | ||
228 | pci_read_config_dword(iTCO_wdt_private.pdev, 0xd4, &val32); | ||
229 | val32 |= 0x00000002; | ||
230 | pci_write_config_dword(iTCO_wdt_private.pdev, 0xd4, val32); | ||
231 | } | ||
232 | } | ||
233 | |||
234 | static int iTCO_wdt_unset_NO_REBOOT_bit(void) | ||
235 | { | ||
236 | int ret = 0; | ||
237 | u32 val32; | ||
238 | |||
239 | /* Unset the NO_REBOOT bit: this enables reboots */ | ||
240 | if (iTCO_wdt_private.iTCO_version == 2) { | ||
241 | val32 = readl(iTCO_wdt_private.gcs); | ||
242 | val32 &= 0xffffffdf; | ||
243 | writel(val32, iTCO_wdt_private.gcs); | ||
244 | |||
245 | val32 = readl(iTCO_wdt_private.gcs); | ||
246 | if (val32 & 0x00000020) | ||
247 | ret = -EIO; | ||
248 | } else if (iTCO_wdt_private.iTCO_version == 1) { | ||
249 | pci_read_config_dword(iTCO_wdt_private.pdev, 0xd4, &val32); | ||
250 | val32 &= 0xfffffffd; | ||
251 | pci_write_config_dword(iTCO_wdt_private.pdev, 0xd4, val32); | ||
252 | |||
253 | pci_read_config_dword(iTCO_wdt_private.pdev, 0xd4, &val32); | ||
254 | if (val32 & 0x00000002) | ||
255 | ret = -EIO; | ||
256 | } | ||
257 | |||
258 | return ret; /* returns: 0 = OK, -EIO = Error */ | ||
259 | } | ||
260 | |||
261 | static int iTCO_wdt_start(void) | ||
262 | { | ||
263 | unsigned int val; | ||
264 | |||
265 | spin_lock(&iTCO_wdt_private.io_lock); | ||
266 | |||
267 | iTCO_vendor_pre_start(iTCO_wdt_private.ACPIBASE, heartbeat); | ||
268 | |||
269 | /* disable chipset's NO_REBOOT bit */ | ||
270 | if (iTCO_wdt_unset_NO_REBOOT_bit()) { | ||
271 | printk(KERN_ERR PFX "failed to reset NO_REBOOT flag, reboot disabled by hardware\n"); | ||
272 | return -EIO; | ||
273 | } | ||
274 | |||
275 | /* Bit 11: TCO Timer Halt -> 0 = The TCO timer is enabled to count */ | ||
276 | val = inw(TCO1_CNT); | ||
277 | val &= 0xf7ff; | ||
278 | outw(val, TCO1_CNT); | ||
279 | val = inw(TCO1_CNT); | ||
280 | spin_unlock(&iTCO_wdt_private.io_lock); | ||
281 | |||
282 | if (val & 0x0800) | ||
283 | return -1; | ||
284 | return 0; | ||
285 | } | ||
286 | |||
287 | static int iTCO_wdt_stop(void) | ||
288 | { | ||
289 | unsigned int val; | ||
290 | |||
291 | spin_lock(&iTCO_wdt_private.io_lock); | ||
292 | |||
293 | iTCO_vendor_pre_stop(iTCO_wdt_private.ACPIBASE); | ||
294 | |||
295 | /* Bit 11: TCO Timer Halt -> 1 = The TCO timer is disabled */ | ||
296 | val = inw(TCO1_CNT); | ||
297 | val |= 0x0800; | ||
298 | outw(val, TCO1_CNT); | ||
299 | val = inw(TCO1_CNT); | ||
300 | |||
301 | /* Set the NO_REBOOT bit to prevent later reboots, just for sure */ | ||
302 | iTCO_wdt_set_NO_REBOOT_bit(); | ||
303 | |||
304 | spin_unlock(&iTCO_wdt_private.io_lock); | ||
305 | |||
306 | if ((val & 0x0800) == 0) | ||
307 | return -1; | ||
308 | return 0; | ||
309 | } | ||
310 | |||
311 | static int iTCO_wdt_keepalive(void) | ||
312 | { | ||
313 | spin_lock(&iTCO_wdt_private.io_lock); | ||
314 | |||
315 | iTCO_vendor_pre_keepalive(iTCO_wdt_private.ACPIBASE, heartbeat); | ||
316 | |||
317 | /* Reload the timer by writing to the TCO Timer Counter register */ | ||
318 | if (iTCO_wdt_private.iTCO_version == 2) { | ||
319 | outw(0x01, TCO_RLD); | ||
320 | } else if (iTCO_wdt_private.iTCO_version == 1) { | ||
321 | outb(0x01, TCO_RLD); | ||
322 | } | ||
323 | |||
324 | spin_unlock(&iTCO_wdt_private.io_lock); | ||
325 | return 0; | ||
326 | } | ||
327 | |||
328 | static int iTCO_wdt_set_heartbeat(int t) | ||
329 | { | ||
330 | unsigned int val16; | ||
331 | unsigned char val8; | ||
332 | unsigned int tmrval; | ||
333 | |||
334 | tmrval = seconds_to_ticks(t); | ||
335 | /* from the specs: */ | ||
336 | /* "Values of 0h-3h are ignored and should not be attempted" */ | ||
337 | if (tmrval < 0x04) | ||
338 | return -EINVAL; | ||
339 | if (((iTCO_wdt_private.iTCO_version == 2) && (tmrval > 0x3ff)) || | ||
340 | ((iTCO_wdt_private.iTCO_version == 1) && (tmrval > 0x03f))) | ||
341 | return -EINVAL; | ||
342 | |||
343 | iTCO_vendor_pre_set_heartbeat(tmrval); | ||
344 | |||
345 | /* Write new heartbeat to watchdog */ | ||
346 | if (iTCO_wdt_private.iTCO_version == 2) { | ||
347 | spin_lock(&iTCO_wdt_private.io_lock); | ||
348 | val16 = inw(TCOv2_TMR); | ||
349 | val16 &= 0xfc00; | ||
350 | val16 |= tmrval; | ||
351 | outw(val16, TCOv2_TMR); | ||
352 | val16 = inw(TCOv2_TMR); | ||
353 | spin_unlock(&iTCO_wdt_private.io_lock); | ||
354 | |||
355 | if ((val16 & 0x3ff) != tmrval) | ||
356 | return -EINVAL; | ||
357 | } else if (iTCO_wdt_private.iTCO_version == 1) { | ||
358 | spin_lock(&iTCO_wdt_private.io_lock); | ||
359 | val8 = inb(TCOv1_TMR); | ||
360 | val8 &= 0xc0; | ||
361 | val8 |= (tmrval & 0xff); | ||
362 | outb(val8, TCOv1_TMR); | ||
363 | val8 = inb(TCOv1_TMR); | ||
364 | spin_unlock(&iTCO_wdt_private.io_lock); | ||
365 | |||
366 | if ((val8 & 0x3f) != tmrval) | ||
367 | return -EINVAL; | ||
368 | } | ||
369 | |||
370 | heartbeat = t; | ||
371 | return 0; | ||
372 | } | ||
373 | |||
374 | static int iTCO_wdt_get_timeleft (int *time_left) | ||
375 | { | ||
376 | unsigned int val16; | ||
377 | unsigned char val8; | ||
378 | |||
379 | /* read the TCO Timer */ | ||
380 | if (iTCO_wdt_private.iTCO_version == 2) { | ||
381 | spin_lock(&iTCO_wdt_private.io_lock); | ||
382 | val16 = inw(TCO_RLD); | ||
383 | val16 &= 0x3ff; | ||
384 | spin_unlock(&iTCO_wdt_private.io_lock); | ||
385 | |||
386 | *time_left = (val16 * 6) / 10; | ||
387 | } else if (iTCO_wdt_private.iTCO_version == 1) { | ||
388 | spin_lock(&iTCO_wdt_private.io_lock); | ||
389 | val8 = inb(TCO_RLD); | ||
390 | val8 &= 0x3f; | ||
391 | spin_unlock(&iTCO_wdt_private.io_lock); | ||
392 | |||
393 | *time_left = (val8 * 6) / 10; | ||
394 | } else | ||
395 | return -EINVAL; | ||
396 | return 0; | ||
397 | } | ||
398 | |||
399 | /* | ||
400 | * /dev/watchdog handling | ||
401 | */ | ||
402 | |||
403 | static int iTCO_wdt_open (struct inode *inode, struct file *file) | ||
404 | { | ||
405 | /* /dev/watchdog can only be opened once */ | ||
406 | if (test_and_set_bit(0, &is_active)) | ||
407 | return -EBUSY; | ||
408 | |||
409 | /* | ||
410 | * Reload and activate timer | ||
411 | */ | ||
412 | iTCO_wdt_keepalive(); | ||
413 | iTCO_wdt_start(); | ||
414 | return nonseekable_open(inode, file); | ||
415 | } | ||
416 | |||
417 | static int iTCO_wdt_release (struct inode *inode, struct file *file) | ||
418 | { | ||
419 | /* | ||
420 | * Shut off the timer. | ||
421 | */ | ||
422 | if (expect_release == 42) { | ||
423 | iTCO_wdt_stop(); | ||
424 | } else { | ||
425 | printk(KERN_CRIT PFX "Unexpected close, not stopping watchdog!\n"); | ||
426 | iTCO_wdt_keepalive(); | ||
427 | } | ||
428 | clear_bit(0, &is_active); | ||
429 | expect_release = 0; | ||
430 | return 0; | ||
431 | } | ||
432 | |||
433 | static ssize_t iTCO_wdt_write (struct file *file, const char __user *data, | ||
434 | size_t len, loff_t * ppos) | ||
435 | { | ||
436 | /* See if we got the magic character 'V' and reload the timer */ | ||
437 | if (len) { | ||
438 | if (!nowayout) { | ||
439 | size_t i; | ||
440 | |||
441 | /* note: just in case someone wrote the magic character | ||
442 | * five months ago... */ | ||
443 | expect_release = 0; | ||
444 | |||
445 | /* scan to see whether or not we got the magic character */ | ||
446 | for (i = 0; i != len; i++) { | ||
447 | char c; | ||
448 | if (get_user(c, data+i)) | ||
449 | return -EFAULT; | ||
450 | if (c == 'V') | ||
451 | expect_release = 42; | ||
452 | } | ||
453 | } | ||
454 | |||
455 | /* someone wrote to us, we should reload the timer */ | ||
456 | iTCO_wdt_keepalive(); | ||
457 | } | ||
458 | return len; | ||
459 | } | ||
460 | |||
461 | static int iTCO_wdt_ioctl (struct inode *inode, struct file *file, | ||
462 | unsigned int cmd, unsigned long arg) | ||
463 | { | ||
464 | int new_options, retval = -EINVAL; | ||
465 | int new_heartbeat; | ||
466 | void __user *argp = (void __user *)arg; | ||
467 | int __user *p = argp; | ||
468 | static struct watchdog_info ident = { | ||
469 | .options = WDIOF_SETTIMEOUT | | ||
470 | WDIOF_KEEPALIVEPING | | ||
471 | WDIOF_MAGICCLOSE, | ||
472 | .firmware_version = 0, | ||
473 | .identity = DRV_NAME, | ||
474 | }; | ||
475 | |||
476 | switch (cmd) { | ||
477 | case WDIOC_GETSUPPORT: | ||
478 | return copy_to_user(argp, &ident, | ||
479 | sizeof (ident)) ? -EFAULT : 0; | ||
480 | |||
481 | case WDIOC_GETSTATUS: | ||
482 | case WDIOC_GETBOOTSTATUS: | ||
483 | return put_user(0, p); | ||
484 | |||
485 | case WDIOC_KEEPALIVE: | ||
486 | iTCO_wdt_keepalive(); | ||
487 | return 0; | ||
488 | |||
489 | case WDIOC_SETOPTIONS: | ||
490 | { | ||
491 | if (get_user(new_options, p)) | ||
492 | return -EFAULT; | ||
493 | |||
494 | if (new_options & WDIOS_DISABLECARD) { | ||
495 | iTCO_wdt_stop(); | ||
496 | retval = 0; | ||
497 | } | ||
498 | |||
499 | if (new_options & WDIOS_ENABLECARD) { | ||
500 | iTCO_wdt_keepalive(); | ||
501 | iTCO_wdt_start(); | ||
502 | retval = 0; | ||
503 | } | ||
504 | |||
505 | return retval; | ||
506 | } | ||
507 | |||
508 | case WDIOC_SETTIMEOUT: | ||
509 | { | ||
510 | if (get_user(new_heartbeat, p)) | ||
511 | return -EFAULT; | ||
512 | |||
513 | if (iTCO_wdt_set_heartbeat(new_heartbeat)) | ||
514 | return -EINVAL; | ||
515 | |||
516 | iTCO_wdt_keepalive(); | ||
517 | /* Fall */ | ||
518 | } | ||
519 | |||
520 | case WDIOC_GETTIMEOUT: | ||
521 | return put_user(heartbeat, p); | ||
522 | |||
523 | case WDIOC_GETTIMELEFT: | ||
524 | { | ||
525 | int time_left; | ||
526 | |||
527 | if (iTCO_wdt_get_timeleft(&time_left)) | ||
528 | return -EINVAL; | ||
529 | |||
530 | return put_user(time_left, p); | ||
531 | } | ||
532 | |||
533 | default: | ||
534 | return -ENOTTY; | ||
535 | } | ||
536 | } | ||
537 | |||
538 | /* | ||
539 | * Kernel Interfaces | ||
540 | */ | ||
541 | |||
542 | static struct file_operations iTCO_wdt_fops = { | ||
543 | .owner = THIS_MODULE, | ||
544 | .llseek = no_llseek, | ||
545 | .write = iTCO_wdt_write, | ||
546 | .ioctl = iTCO_wdt_ioctl, | ||
547 | .open = iTCO_wdt_open, | ||
548 | .release = iTCO_wdt_release, | ||
549 | }; | ||
550 | |||
551 | static struct miscdevice iTCO_wdt_miscdev = { | ||
552 | .minor = WATCHDOG_MINOR, | ||
553 | .name = "watchdog", | ||
554 | .fops = &iTCO_wdt_fops, | ||
555 | }; | ||
556 | |||
557 | /* | ||
558 | * Init & exit routines | ||
559 | */ | ||
560 | |||
561 | static int iTCO_wdt_init(struct pci_dev *pdev, const struct pci_device_id *ent, struct platform_device *dev) | ||
562 | { | ||
563 | int ret; | ||
564 | u32 base_address; | ||
565 | unsigned long RCBA; | ||
566 | unsigned long val32; | ||
567 | |||
568 | /* | ||
569 | * Find the ACPI/PM base I/O address which is the base | ||
570 | * for the TCO registers (TCOBASE=ACPIBASE + 0x60) | ||
571 | * ACPIBASE is bits [15:7] from 0x40-0x43 | ||
572 | */ | ||
573 | pci_read_config_dword(pdev, 0x40, &base_address); | ||
574 | base_address &= 0x00007f80; | ||
575 | if (base_address == 0x00000000) { | ||
576 | /* Something's wrong here, ACPIBASE has to be set */ | ||
577 | printk(KERN_ERR PFX "failed to get TCOBASE address\n"); | ||
578 | pci_dev_put(pdev); | ||
579 | return -ENODEV; | ||
580 | } | ||
581 | iTCO_wdt_private.iTCO_version = iTCO_chipset_info[ent->driver_data].iTCO_version; | ||
582 | iTCO_wdt_private.ACPIBASE = base_address; | ||
583 | iTCO_wdt_private.pdev = pdev; | ||
584 | |||
585 | /* Get the Memory-Mapped GCS register, we need it for the NO_REBOOT flag (TCO v2) */ | ||
586 | /* To get access to it you have to read RCBA from PCI Config space 0xf0 | ||
587 | and use it as base. GCS = RCBA + ICH6_GCS(0x3410). */ | ||
588 | if (iTCO_wdt_private.iTCO_version == 2) { | ||
589 | pci_read_config_dword(pdev, 0xf0, &base_address); | ||
590 | RCBA = base_address & 0xffffc000; | ||
591 | iTCO_wdt_private.gcs = ioremap((RCBA + 0x3410),4); | ||
592 | } | ||
593 | |||
594 | /* Check chipset's NO_REBOOT bit */ | ||
595 | if (iTCO_wdt_unset_NO_REBOOT_bit() && iTCO_vendor_check_noreboot_on()) { | ||
596 | printk(KERN_ERR PFX "failed to reset NO_REBOOT flag, reboot disabled by hardware\n"); | ||
597 | ret = -ENODEV; /* Cannot reset NO_REBOOT bit */ | ||
598 | goto out; | ||
599 | } | ||
600 | |||
601 | /* Set the NO_REBOOT bit to prevent later reboots, just for sure */ | ||
602 | iTCO_wdt_set_NO_REBOOT_bit(); | ||
603 | |||
604 | /* Set the TCO_EN bit in SMI_EN register */ | ||
605 | if (!request_region(SMI_EN, 4, "iTCO_wdt")) { | ||
606 | printk(KERN_ERR PFX "I/O address 0x%04lx already in use\n", | ||
607 | SMI_EN ); | ||
608 | ret = -EIO; | ||
609 | goto out; | ||
610 | } | ||
611 | val32 = inl(SMI_EN); | ||
612 | val32 &= 0xffffdfff; /* Turn off SMI clearing watchdog */ | ||
613 | outl(val32, SMI_EN); | ||
614 | release_region(SMI_EN, 4); | ||
615 | |||
616 | /* The TCO I/O registers reside in a 32-byte range pointed to by the TCOBASE value */ | ||
617 | if (!request_region (TCOBASE, 0x20, "iTCO_wdt")) { | ||
618 | printk (KERN_ERR PFX "I/O address 0x%04lx already in use\n", | ||
619 | TCOBASE); | ||
620 | ret = -EIO; | ||
621 | goto out; | ||
622 | } | ||
623 | |||
624 | printk(KERN_INFO PFX "Found a %s TCO device (Version=%d, TCOBASE=0x%04lx)\n", | ||
625 | iTCO_chipset_info[ent->driver_data].name, | ||
626 | iTCO_chipset_info[ent->driver_data].iTCO_version, | ||
627 | TCOBASE); | ||
628 | |||
629 | /* Clear out the (probably old) status */ | ||
630 | outb(0, TCO1_STS); | ||
631 | outb(3, TCO2_STS); | ||
632 | |||
633 | /* Make sure the watchdog is not running */ | ||
634 | iTCO_wdt_stop(); | ||
635 | |||
636 | /* Check that the heartbeat value is within it's range ; if not reset to the default */ | ||
637 | if (iTCO_wdt_set_heartbeat(heartbeat)) { | ||
638 | iTCO_wdt_set_heartbeat(WATCHDOG_HEARTBEAT); | ||
639 | printk(KERN_INFO PFX "heartbeat value must be 2<heartbeat<39 (TCO v1) or 613 (TCO v2), using %d\n", | ||
640 | heartbeat); | ||
641 | } | ||
642 | |||
643 | ret = misc_register(&iTCO_wdt_miscdev); | ||
644 | if (ret != 0) { | ||
645 | printk(KERN_ERR PFX "cannot register miscdev on minor=%d (err=%d)\n", | ||
646 | WATCHDOG_MINOR, ret); | ||
647 | goto unreg_region; | ||
648 | } | ||
649 | |||
650 | printk (KERN_INFO PFX "initialized. heartbeat=%d sec (nowayout=%d)\n", | ||
651 | heartbeat, nowayout); | ||
652 | |||
653 | return 0; | ||
654 | |||
655 | unreg_region: | ||
656 | release_region (TCOBASE, 0x20); | ||
657 | out: | ||
658 | if (iTCO_wdt_private.iTCO_version == 2) | ||
659 | iounmap(iTCO_wdt_private.gcs); | ||
660 | pci_dev_put(iTCO_wdt_private.pdev); | ||
661 | iTCO_wdt_private.ACPIBASE = 0; | ||
662 | return ret; | ||
663 | } | ||
664 | |||
665 | static void iTCO_wdt_cleanup(void) | ||
666 | { | ||
667 | /* Stop the timer before we leave */ | ||
668 | if (!nowayout) | ||
669 | iTCO_wdt_stop(); | ||
670 | |||
671 | /* Deregister */ | ||
672 | misc_deregister(&iTCO_wdt_miscdev); | ||
673 | release_region(TCOBASE, 0x20); | ||
674 | if (iTCO_wdt_private.iTCO_version == 2) | ||
675 | iounmap(iTCO_wdt_private.gcs); | ||
676 | pci_dev_put(iTCO_wdt_private.pdev); | ||
677 | iTCO_wdt_private.ACPIBASE = 0; | ||
678 | } | ||
679 | |||
680 | static int iTCO_wdt_probe(struct platform_device *dev) | ||
681 | { | ||
682 | int found = 0; | ||
683 | struct pci_dev *pdev = NULL; | ||
684 | const struct pci_device_id *ent; | ||
685 | |||
686 | spin_lock_init(&iTCO_wdt_private.io_lock); | ||
687 | |||
688 | for_each_pci_dev(pdev) { | ||
689 | ent = pci_match_id(iTCO_wdt_pci_tbl, pdev); | ||
690 | if (ent) { | ||
691 | if (!(iTCO_wdt_init(pdev, ent, dev))) { | ||
692 | found++; | ||
693 | break; | ||
694 | } | ||
695 | } | ||
696 | } | ||
697 | |||
698 | if (!found) { | ||
699 | printk(KERN_INFO PFX "No card detected\n"); | ||
700 | return -ENODEV; | ||
701 | } | ||
702 | |||
703 | return 0; | ||
704 | } | ||
705 | |||
706 | static int iTCO_wdt_remove(struct platform_device *dev) | ||
707 | { | ||
708 | if (iTCO_wdt_private.ACPIBASE) | ||
709 | iTCO_wdt_cleanup(); | ||
710 | |||
711 | return 0; | ||
712 | } | ||
713 | |||
714 | static void iTCO_wdt_shutdown(struct platform_device *dev) | ||
715 | { | ||
716 | iTCO_wdt_stop(); | ||
717 | } | ||
718 | |||
719 | #define iTCO_wdt_suspend NULL | ||
720 | #define iTCO_wdt_resume NULL | ||
721 | |||
722 | static struct platform_driver iTCO_wdt_driver = { | ||
723 | .probe = iTCO_wdt_probe, | ||
724 | .remove = iTCO_wdt_remove, | ||
725 | .shutdown = iTCO_wdt_shutdown, | ||
726 | .suspend = iTCO_wdt_suspend, | ||
727 | .resume = iTCO_wdt_resume, | ||
728 | .driver = { | ||
729 | .owner = THIS_MODULE, | ||
730 | .name = DRV_NAME, | ||
731 | }, | ||
732 | }; | ||
733 | |||
734 | static int __init iTCO_wdt_init_module(void) | ||
735 | { | ||
736 | int err; | ||
737 | |||
738 | printk(KERN_INFO PFX "Intel TCO WatchDog Timer Driver v%s (%s)\n", | ||
739 | DRV_VERSION, DRV_RELDATE); | ||
740 | |||
741 | err = platform_driver_register(&iTCO_wdt_driver); | ||
742 | if (err) | ||
743 | return err; | ||
744 | |||
745 | iTCO_wdt_platform_device = platform_device_register_simple(DRV_NAME, -1, NULL, 0); | ||
746 | if (IS_ERR(iTCO_wdt_platform_device)) { | ||
747 | err = PTR_ERR(iTCO_wdt_platform_device); | ||
748 | goto unreg_platform_driver; | ||
749 | } | ||
750 | |||
751 | return 0; | ||
752 | |||
753 | unreg_platform_driver: | ||
754 | platform_driver_unregister(&iTCO_wdt_driver); | ||
755 | return err; | ||
756 | } | ||
757 | |||
758 | static void __exit iTCO_wdt_cleanup_module(void) | ||
759 | { | ||
760 | platform_device_unregister(iTCO_wdt_platform_device); | ||
761 | platform_driver_unregister(&iTCO_wdt_driver); | ||
762 | printk(KERN_INFO PFX "Watchdog Module Unloaded.\n"); | ||
763 | } | ||
764 | |||
765 | module_init(iTCO_wdt_init_module); | ||
766 | module_exit(iTCO_wdt_cleanup_module); | ||
767 | |||
768 | MODULE_AUTHOR("Wim Van Sebroeck <wim@iguana.be>"); | ||
769 | MODULE_DESCRIPTION("Intel TCO WatchDog Timer Driver"); | ||
770 | MODULE_VERSION(DRV_VERSION); | ||
771 | MODULE_LICENSE("GPL"); | ||
772 | MODULE_ALIAS_MISCDEV(WATCHDOG_MINOR); | ||
diff --git a/drivers/char/watchdog/ib700wdt.c b/drivers/char/watchdog/ib700wdt.c index fd95f7327798..c1ed209a138c 100644 --- a/drivers/char/watchdog/ib700wdt.c +++ b/drivers/char/watchdog/ib700wdt.c | |||
@@ -199,7 +199,7 @@ ibwdt_ioctl(struct inode *inode, struct file *file, unsigned int cmd, | |||
199 | break; | 199 | break; |
200 | 200 | ||
201 | default: | 201 | default: |
202 | return -ENOIOCTLCMD; | 202 | return -ENOTTY; |
203 | } | 203 | } |
204 | return 0; | 204 | return 0; |
205 | } | 205 | } |
diff --git a/drivers/char/watchdog/ibmasr.c b/drivers/char/watchdog/ibmasr.c index 26ceee7a4df0..dd6760f1a23b 100644 --- a/drivers/char/watchdog/ibmasr.c +++ b/drivers/char/watchdog/ibmasr.c | |||
@@ -295,7 +295,7 @@ static int asr_ioctl(struct inode *inode, struct file *file, | |||
295 | } | 295 | } |
296 | } | 296 | } |
297 | 297 | ||
298 | return -ENOIOCTLCMD; | 298 | return -ENOTTY; |
299 | } | 299 | } |
300 | 300 | ||
301 | static int asr_open(struct inode *inode, struct file *file) | 301 | static int asr_open(struct inode *inode, struct file *file) |
diff --git a/drivers/char/watchdog/indydog.c b/drivers/char/watchdog/indydog.c index dacc1c20a310..0bc239308989 100644 --- a/drivers/char/watchdog/indydog.c +++ b/drivers/char/watchdog/indydog.c | |||
@@ -112,7 +112,7 @@ static int indydog_ioctl(struct inode *inode, struct file *file, | |||
112 | 112 | ||
113 | switch (cmd) { | 113 | switch (cmd) { |
114 | default: | 114 | default: |
115 | return -ENOIOCTLCMD; | 115 | return -ENOTTY; |
116 | case WDIOC_GETSUPPORT: | 116 | case WDIOC_GETSUPPORT: |
117 | if (copy_to_user((struct watchdog_info *)arg, | 117 | if (copy_to_user((struct watchdog_info *)arg, |
118 | &ident, sizeof(ident))) | 118 | &ident, sizeof(ident))) |
diff --git a/drivers/char/watchdog/ixp2000_wdt.c b/drivers/char/watchdog/ixp2000_wdt.c index 692908819e26..fd955dbd588c 100644 --- a/drivers/char/watchdog/ixp2000_wdt.c +++ b/drivers/char/watchdog/ixp2000_wdt.c | |||
@@ -1,5 +1,5 @@ | |||
1 | /* | 1 | /* |
2 | * drivers/watchdog/ixp2000_wdt.c | 2 | * drivers/char/watchdog/ixp2000_wdt.c |
3 | * | 3 | * |
4 | * Watchdog driver for Intel IXP2000 network processors | 4 | * Watchdog driver for Intel IXP2000 network processors |
5 | * | 5 | * |
@@ -107,7 +107,7 @@ static int | |||
107 | ixp2000_wdt_ioctl(struct inode *inode, struct file *file, unsigned int cmd, | 107 | ixp2000_wdt_ioctl(struct inode *inode, struct file *file, unsigned int cmd, |
108 | unsigned long arg) | 108 | unsigned long arg) |
109 | { | 109 | { |
110 | int ret = -ENOIOCTLCMD; | 110 | int ret = -ENOTTY; |
111 | int time; | 111 | int time; |
112 | 112 | ||
113 | switch (cmd) { | 113 | switch (cmd) { |
diff --git a/drivers/char/watchdog/ixp4xx_wdt.c b/drivers/char/watchdog/ixp4xx_wdt.c index 9db5cf2c38c3..5864bb865cfe 100644 --- a/drivers/char/watchdog/ixp4xx_wdt.c +++ b/drivers/char/watchdog/ixp4xx_wdt.c | |||
@@ -1,5 +1,5 @@ | |||
1 | /* | 1 | /* |
2 | * drivers/watchdog/ixp4xx_wdt.c | 2 | * drivers/char/watchdog/ixp4xx_wdt.c |
3 | * | 3 | * |
4 | * Watchdog driver for Intel IXP4xx network processors | 4 | * Watchdog driver for Intel IXP4xx network processors |
5 | * | 5 | * |
@@ -102,7 +102,7 @@ static int | |||
102 | ixp4xx_wdt_ioctl(struct inode *inode, struct file *file, unsigned int cmd, | 102 | ixp4xx_wdt_ioctl(struct inode *inode, struct file *file, unsigned int cmd, |
103 | unsigned long arg) | 103 | unsigned long arg) |
104 | { | 104 | { |
105 | int ret = -ENOIOCTLCMD; | 105 | int ret = -ENOTTY; |
106 | int time; | 106 | int time; |
107 | 107 | ||
108 | switch (cmd) { | 108 | switch (cmd) { |
diff --git a/drivers/char/watchdog/machzwd.c b/drivers/char/watchdog/machzwd.c index 23734e07fb22..276577d08fba 100644 --- a/drivers/char/watchdog/machzwd.c +++ b/drivers/char/watchdog/machzwd.c | |||
@@ -329,7 +329,7 @@ static int zf_ioctl(struct inode *inode, struct file *file, unsigned int cmd, | |||
329 | break; | 329 | break; |
330 | 330 | ||
331 | default: | 331 | default: |
332 | return -ENOIOCTLCMD; | 332 | return -ENOTTY; |
333 | } | 333 | } |
334 | 334 | ||
335 | return 0; | 335 | return 0; |
@@ -426,8 +426,7 @@ static int __init zf_init(void) | |||
426 | printk(KERN_INFO PFX ": MachZ ZF-Logic Watchdog driver initializing.\n"); | 426 | printk(KERN_INFO PFX ": MachZ ZF-Logic Watchdog driver initializing.\n"); |
427 | 427 | ||
428 | ret = zf_get_ZFL_version(); | 428 | ret = zf_get_ZFL_version(); |
429 | printk("%#x\n", ret); | 429 | if ((!ret) || (ret == 0xffff)) { |
430 | if((!ret) || (ret != 0xffff)){ | ||
431 | printk(KERN_WARNING PFX ": no ZF-Logic found\n"); | 430 | printk(KERN_WARNING PFX ": no ZF-Logic found\n"); |
432 | return -ENODEV; | 431 | return -ENODEV; |
433 | } | 432 | } |
diff --git a/drivers/char/watchdog/mixcomwd.c b/drivers/char/watchdog/mixcomwd.c index ae943324d251..c2dac0aa1d62 100644 --- a/drivers/char/watchdog/mixcomwd.c +++ b/drivers/char/watchdog/mixcomwd.c | |||
@@ -185,7 +185,7 @@ static int mixcomwd_ioctl(struct inode *inode, struct file *file, | |||
185 | mixcomwd_ping(); | 185 | mixcomwd_ping(); |
186 | break; | 186 | break; |
187 | default: | 187 | default: |
188 | return -ENOIOCTLCMD; | 188 | return -ENOTTY; |
189 | } | 189 | } |
190 | return 0; | 190 | return 0; |
191 | } | 191 | } |
diff --git a/drivers/char/watchdog/mpc83xx_wdt.c b/drivers/char/watchdog/mpc83xx_wdt.c index a480903ee1a5..18ca752e2f90 100644 --- a/drivers/char/watchdog/mpc83xx_wdt.c +++ b/drivers/char/watchdog/mpc83xx_wdt.c | |||
@@ -125,7 +125,7 @@ static int mpc83xx_wdt_ioctl(struct inode *inode, struct file *file, | |||
125 | case WDIOC_GETTIMEOUT: | 125 | case WDIOC_GETTIMEOUT: |
126 | return put_user(timeout_sec, p); | 126 | return put_user(timeout_sec, p); |
127 | default: | 127 | default: |
128 | return -ENOIOCTLCMD; | 128 | return -ENOTTY; |
129 | } | 129 | } |
130 | } | 130 | } |
131 | 131 | ||
diff --git a/drivers/char/watchdog/mpc8xx_wdt.c b/drivers/char/watchdog/mpc8xx_wdt.c index 35dd9e6e1140..8aaed10dd499 100644 --- a/drivers/char/watchdog/mpc8xx_wdt.c +++ b/drivers/char/watchdog/mpc8xx_wdt.c | |||
@@ -126,7 +126,7 @@ static int mpc8xx_wdt_ioctl(struct inode *inode, struct file *file, | |||
126 | break; | 126 | break; |
127 | 127 | ||
128 | default: | 128 | default: |
129 | return -ENOIOCTLCMD; | 129 | return -ENOTTY; |
130 | } | 130 | } |
131 | 131 | ||
132 | return 0; | 132 | return 0; |
diff --git a/drivers/char/watchdog/mpcore_wdt.c b/drivers/char/watchdog/mpcore_wdt.c index 54b3c56ead0d..3404a9c67f08 100644 --- a/drivers/char/watchdog/mpcore_wdt.c +++ b/drivers/char/watchdog/mpcore_wdt.c | |||
@@ -64,7 +64,7 @@ MODULE_PARM_DESC(mpcore_noboot, "MPcore watchdog action, set to 1 to ignore rebo | |||
64 | * This is the interrupt handler. Note that we only use this | 64 | * This is the interrupt handler. Note that we only use this |
65 | * in testing mode, so don't actually do a reboot here. | 65 | * in testing mode, so don't actually do a reboot here. |
66 | */ | 66 | */ |
67 | static irqreturn_t mpcore_wdt_fire(int irq, void *arg, struct pt_regs *regs) | 67 | static irqreturn_t mpcore_wdt_fire(int irq, void *arg) |
68 | { | 68 | { |
69 | struct mpcore_wdt *wdt = arg; | 69 | struct mpcore_wdt *wdt = arg; |
70 | 70 | ||
@@ -221,7 +221,7 @@ static int mpcore_wdt_ioctl(struct inode *inode, struct file *file, | |||
221 | } uarg; | 221 | } uarg; |
222 | 222 | ||
223 | if (_IOC_DIR(cmd) && _IOC_SIZE(cmd) > sizeof(uarg)) | 223 | if (_IOC_DIR(cmd) && _IOC_SIZE(cmd) > sizeof(uarg)) |
224 | return -ENOIOCTLCMD; | 224 | return -ENOTTY; |
225 | 225 | ||
226 | if (_IOC_DIR(cmd) & _IOC_WRITE) { | 226 | if (_IOC_DIR(cmd) & _IOC_WRITE) { |
227 | ret = copy_from_user(&uarg, (void __user *)arg, _IOC_SIZE(cmd)); | 227 | ret = copy_from_user(&uarg, (void __user *)arg, _IOC_SIZE(cmd)); |
@@ -271,7 +271,7 @@ static int mpcore_wdt_ioctl(struct inode *inode, struct file *file, | |||
271 | break; | 271 | break; |
272 | 272 | ||
273 | default: | 273 | default: |
274 | return -ENOIOCTLCMD; | 274 | return -ENOTTY; |
275 | } | 275 | } |
276 | 276 | ||
277 | if (ret == 0 && _IOC_DIR(cmd) & _IOC_READ) { | 277 | if (ret == 0 && _IOC_DIR(cmd) & _IOC_READ) { |
diff --git a/drivers/char/watchdog/mv64x60_wdt.c b/drivers/char/watchdog/mv64x60_wdt.c index 5c8fab345b40..b887cdb01334 100644 --- a/drivers/char/watchdog/mv64x60_wdt.c +++ b/drivers/char/watchdog/mv64x60_wdt.c | |||
@@ -160,7 +160,7 @@ static int mv64x60_wdt_ioctl(struct inode *inode, struct file *file, | |||
160 | break; | 160 | break; |
161 | 161 | ||
162 | default: | 162 | default: |
163 | return -ENOIOCTLCMD; | 163 | return -ENOTTY; |
164 | } | 164 | } |
165 | 165 | ||
166 | return 0; | 166 | return 0; |
diff --git a/drivers/char/watchdog/omap_wdt.c b/drivers/char/watchdog/omap_wdt.c new file mode 100644 index 000000000000..5dbd7dc2936f --- /dev/null +++ b/drivers/char/watchdog/omap_wdt.c | |||
@@ -0,0 +1,390 @@ | |||
1 | /* | ||
2 | * linux/drivers/char/watchdog/omap_wdt.c | ||
3 | * | ||
4 | * Watchdog driver for the TI OMAP 16xx & 24xx 32KHz (non-secure) watchdog | ||
5 | * | ||
6 | * Author: MontaVista Software, Inc. | ||
7 | * <gdavis@mvista.com> or <source@mvista.com> | ||
8 | * | ||
9 | * 2003 (c) MontaVista Software, Inc. This file is licensed under the | ||
10 | * terms of the GNU General Public License version 2. This program is | ||
11 | * licensed "as is" without any warranty of any kind, whether express | ||
12 | * or implied. | ||
13 | * | ||
14 | * History: | ||
15 | * | ||
16 | * 20030527: George G. Davis <gdavis@mvista.com> | ||
17 | * Initially based on linux-2.4.19-rmk7-pxa1/drivers/char/sa1100_wdt.c | ||
18 | * (c) Copyright 2000 Oleg Drokin <green@crimea.edu> | ||
19 | * Based on SoftDog driver by Alan Cox <alan@redhat.com> | ||
20 | * | ||
21 | * Copyright (c) 2004 Texas Instruments. | ||
22 | * 1. Modified to support OMAP1610 32-KHz watchdog timer | ||
23 | * 2. Ported to 2.6 kernel | ||
24 | * | ||
25 | * Copyright (c) 2005 David Brownell | ||
26 | * Use the driver model and standard identifiers; handle bigger timeouts. | ||
27 | */ | ||
28 | |||
29 | #include <linux/module.h> | ||
30 | #include <linux/types.h> | ||
31 | #include <linux/kernel.h> | ||
32 | #include <linux/fs.h> | ||
33 | #include <linux/mm.h> | ||
34 | #include <linux/miscdevice.h> | ||
35 | #include <linux/watchdog.h> | ||
36 | #include <linux/reboot.h> | ||
37 | #include <linux/smp_lock.h> | ||
38 | #include <linux/init.h> | ||
39 | #include <linux/err.h> | ||
40 | #include <linux/platform_device.h> | ||
41 | #include <linux/moduleparam.h> | ||
42 | #include <linux/clk.h> | ||
43 | |||
44 | #include <asm/io.h> | ||
45 | #include <asm/uaccess.h> | ||
46 | #include <asm/hardware.h> | ||
47 | #include <asm/bitops.h> | ||
48 | |||
49 | #include <asm/arch/prcm.h> | ||
50 | |||
51 | #include "omap_wdt.h" | ||
52 | |||
53 | static unsigned timer_margin; | ||
54 | module_param(timer_margin, uint, 0); | ||
55 | MODULE_PARM_DESC(timer_margin, "initial watchdog timeout (in seconds)"); | ||
56 | |||
57 | static int omap_wdt_users; | ||
58 | static struct clk *armwdt_ck = NULL; | ||
59 | static struct clk *mpu_wdt_ick = NULL; | ||
60 | static struct clk *mpu_wdt_fck = NULL; | ||
61 | |||
62 | static unsigned int wdt_trgr_pattern = 0x1234; | ||
63 | |||
64 | static void omap_wdt_ping(void) | ||
65 | { | ||
66 | /* wait for posted write to complete */ | ||
67 | while ((omap_readl(OMAP_WATCHDOG_WPS)) & 0x08) | ||
68 | cpu_relax(); | ||
69 | wdt_trgr_pattern = ~wdt_trgr_pattern; | ||
70 | omap_writel(wdt_trgr_pattern, (OMAP_WATCHDOG_TGR)); | ||
71 | /* wait for posted write to complete */ | ||
72 | while ((omap_readl(OMAP_WATCHDOG_WPS)) & 0x08) | ||
73 | cpu_relax(); | ||
74 | /* reloaded WCRR from WLDR */ | ||
75 | } | ||
76 | |||
77 | static void omap_wdt_enable(void) | ||
78 | { | ||
79 | /* Sequence to enable the watchdog */ | ||
80 | omap_writel(0xBBBB, OMAP_WATCHDOG_SPR); | ||
81 | while ((omap_readl(OMAP_WATCHDOG_WPS)) & 0x10) | ||
82 | cpu_relax(); | ||
83 | omap_writel(0x4444, OMAP_WATCHDOG_SPR); | ||
84 | while ((omap_readl(OMAP_WATCHDOG_WPS)) & 0x10) | ||
85 | cpu_relax(); | ||
86 | } | ||
87 | |||
88 | static void omap_wdt_disable(void) | ||
89 | { | ||
90 | /* sequence required to disable watchdog */ | ||
91 | omap_writel(0xAAAA, OMAP_WATCHDOG_SPR); /* TIMER_MODE */ | ||
92 | while (omap_readl(OMAP_WATCHDOG_WPS) & 0x10) | ||
93 | cpu_relax(); | ||
94 | omap_writel(0x5555, OMAP_WATCHDOG_SPR); /* TIMER_MODE */ | ||
95 | while (omap_readl(OMAP_WATCHDOG_WPS) & 0x10) | ||
96 | cpu_relax(); | ||
97 | } | ||
98 | |||
99 | static void omap_wdt_adjust_timeout(unsigned new_timeout) | ||
100 | { | ||
101 | if (new_timeout < TIMER_MARGIN_MIN) | ||
102 | new_timeout = TIMER_MARGIN_DEFAULT; | ||
103 | if (new_timeout > TIMER_MARGIN_MAX) | ||
104 | new_timeout = TIMER_MARGIN_MAX; | ||
105 | timer_margin = new_timeout; | ||
106 | } | ||
107 | |||
108 | static void omap_wdt_set_timeout(void) | ||
109 | { | ||
110 | u32 pre_margin = GET_WLDR_VAL(timer_margin); | ||
111 | |||
112 | /* just count up at 32 KHz */ | ||
113 | while (omap_readl(OMAP_WATCHDOG_WPS) & 0x04) | ||
114 | cpu_relax(); | ||
115 | omap_writel(pre_margin, OMAP_WATCHDOG_LDR); | ||
116 | while (omap_readl(OMAP_WATCHDOG_WPS) & 0x04) | ||
117 | cpu_relax(); | ||
118 | } | ||
119 | |||
120 | /* | ||
121 | * Allow only one task to hold it open | ||
122 | */ | ||
123 | |||
124 | static int omap_wdt_open(struct inode *inode, struct file *file) | ||
125 | { | ||
126 | if (test_and_set_bit(1, (unsigned long *)&omap_wdt_users)) | ||
127 | return -EBUSY; | ||
128 | |||
129 | if (cpu_is_omap16xx()) | ||
130 | clk_enable(armwdt_ck); /* Enable the clock */ | ||
131 | |||
132 | if (cpu_is_omap24xx()) { | ||
133 | clk_enable(mpu_wdt_ick); /* Enable the interface clock */ | ||
134 | clk_enable(mpu_wdt_fck); /* Enable the functional clock */ | ||
135 | } | ||
136 | |||
137 | /* initialize prescaler */ | ||
138 | while (omap_readl(OMAP_WATCHDOG_WPS) & 0x01) | ||
139 | cpu_relax(); | ||
140 | omap_writel((1 << 5) | (PTV << 2), OMAP_WATCHDOG_CNTRL); | ||
141 | while (omap_readl(OMAP_WATCHDOG_WPS) & 0x01) | ||
142 | cpu_relax(); | ||
143 | |||
144 | omap_wdt_set_timeout(); | ||
145 | omap_wdt_enable(); | ||
146 | return 0; | ||
147 | } | ||
148 | |||
149 | static int omap_wdt_release(struct inode *inode, struct file *file) | ||
150 | { | ||
151 | /* | ||
152 | * Shut off the timer unless NOWAYOUT is defined. | ||
153 | */ | ||
154 | #ifndef CONFIG_WATCHDOG_NOWAYOUT | ||
155 | omap_wdt_disable(); | ||
156 | |||
157 | if (cpu_is_omap16xx()) { | ||
158 | clk_disable(armwdt_ck); /* Disable the clock */ | ||
159 | clk_put(armwdt_ck); | ||
160 | armwdt_ck = NULL; | ||
161 | } | ||
162 | |||
163 | if (cpu_is_omap24xx()) { | ||
164 | clk_disable(mpu_wdt_ick); /* Disable the clock */ | ||
165 | clk_disable(mpu_wdt_fck); /* Disable the clock */ | ||
166 | clk_put(mpu_wdt_ick); | ||
167 | clk_put(mpu_wdt_fck); | ||
168 | mpu_wdt_ick = NULL; | ||
169 | mpu_wdt_fck = NULL; | ||
170 | } | ||
171 | #else | ||
172 | printk(KERN_CRIT "omap_wdt: Unexpected close, not stopping!\n"); | ||
173 | #endif | ||
174 | omap_wdt_users = 0; | ||
175 | return 0; | ||
176 | } | ||
177 | |||
178 | static ssize_t | ||
179 | omap_wdt_write(struct file *file, const char __user *data, | ||
180 | size_t len, loff_t *ppos) | ||
181 | { | ||
182 | /* Refresh LOAD_TIME. */ | ||
183 | if (len) | ||
184 | omap_wdt_ping(); | ||
185 | return len; | ||
186 | } | ||
187 | |||
188 | static int | ||
189 | omap_wdt_ioctl(struct inode *inode, struct file *file, | ||
190 | unsigned int cmd, unsigned long arg) | ||
191 | { | ||
192 | int new_margin; | ||
193 | static struct watchdog_info ident = { | ||
194 | .identity = "OMAP Watchdog", | ||
195 | .options = WDIOF_SETTIMEOUT, | ||
196 | .firmware_version = 0, | ||
197 | }; | ||
198 | |||
199 | switch (cmd) { | ||
200 | default: | ||
201 | return -ENOIOCTLCMD; | ||
202 | case WDIOC_GETSUPPORT: | ||
203 | return copy_to_user((struct watchdog_info __user *)arg, &ident, | ||
204 | sizeof(ident)); | ||
205 | case WDIOC_GETSTATUS: | ||
206 | return put_user(0, (int __user *)arg); | ||
207 | case WDIOC_GETBOOTSTATUS: | ||
208 | if (cpu_is_omap16xx()) | ||
209 | return put_user(omap_readw(ARM_SYSST), | ||
210 | (int __user *)arg); | ||
211 | if (cpu_is_omap24xx()) | ||
212 | return put_user(omap_prcm_get_reset_sources(), | ||
213 | (int __user *)arg); | ||
214 | case WDIOC_KEEPALIVE: | ||
215 | omap_wdt_ping(); | ||
216 | return 0; | ||
217 | case WDIOC_SETTIMEOUT: | ||
218 | if (get_user(new_margin, (int __user *)arg)) | ||
219 | return -EFAULT; | ||
220 | omap_wdt_adjust_timeout(new_margin); | ||
221 | |||
222 | omap_wdt_disable(); | ||
223 | omap_wdt_set_timeout(); | ||
224 | omap_wdt_enable(); | ||
225 | |||
226 | omap_wdt_ping(); | ||
227 | /* Fall */ | ||
228 | case WDIOC_GETTIMEOUT: | ||
229 | return put_user(timer_margin, (int __user *)arg); | ||
230 | } | ||
231 | } | ||
232 | |||
233 | static struct file_operations omap_wdt_fops = { | ||
234 | .owner = THIS_MODULE, | ||
235 | .write = omap_wdt_write, | ||
236 | .ioctl = omap_wdt_ioctl, | ||
237 | .open = omap_wdt_open, | ||
238 | .release = omap_wdt_release, | ||
239 | }; | ||
240 | |||
241 | static struct miscdevice omap_wdt_miscdev = { | ||
242 | .minor = WATCHDOG_MINOR, | ||
243 | .name = "watchdog", | ||
244 | .fops = &omap_wdt_fops | ||
245 | }; | ||
246 | |||
247 | static int __init omap_wdt_probe(struct platform_device *pdev) | ||
248 | { | ||
249 | struct resource *res, *mem; | ||
250 | int ret; | ||
251 | |||
252 | /* reserve static register mappings */ | ||
253 | res = platform_get_resource(pdev, IORESOURCE_MEM, 0); | ||
254 | if (!res) | ||
255 | return -ENOENT; | ||
256 | |||
257 | mem = request_mem_region(res->start, res->end - res->start + 1, | ||
258 | pdev->name); | ||
259 | if (mem == NULL) | ||
260 | return -EBUSY; | ||
261 | |||
262 | platform_set_drvdata(pdev, mem); | ||
263 | |||
264 | omap_wdt_users = 0; | ||
265 | |||
266 | if (cpu_is_omap16xx()) { | ||
267 | armwdt_ck = clk_get(&pdev->dev, "armwdt_ck"); | ||
268 | if (IS_ERR(armwdt_ck)) { | ||
269 | ret = PTR_ERR(armwdt_ck); | ||
270 | armwdt_ck = NULL; | ||
271 | goto fail; | ||
272 | } | ||
273 | } | ||
274 | |||
275 | if (cpu_is_omap24xx()) { | ||
276 | mpu_wdt_ick = clk_get(&pdev->dev, "mpu_wdt_ick"); | ||
277 | if (IS_ERR(mpu_wdt_ick)) { | ||
278 | ret = PTR_ERR(mpu_wdt_ick); | ||
279 | mpu_wdt_ick = NULL; | ||
280 | goto fail; | ||
281 | } | ||
282 | mpu_wdt_fck = clk_get(&pdev->dev, "mpu_wdt_fck"); | ||
283 | if (IS_ERR(mpu_wdt_fck)) { | ||
284 | ret = PTR_ERR(mpu_wdt_fck); | ||
285 | mpu_wdt_fck = NULL; | ||
286 | goto fail; | ||
287 | } | ||
288 | } | ||
289 | |||
290 | omap_wdt_disable(); | ||
291 | omap_wdt_adjust_timeout(timer_margin); | ||
292 | |||
293 | omap_wdt_miscdev.dev = &pdev->dev; | ||
294 | ret = misc_register(&omap_wdt_miscdev); | ||
295 | if (ret) | ||
296 | goto fail; | ||
297 | |||
298 | pr_info("OMAP Watchdog Timer: initial timeout %d sec\n", timer_margin); | ||
299 | |||
300 | /* autogate OCP interface clock */ | ||
301 | omap_writel(0x01, OMAP_WATCHDOG_SYS_CONFIG); | ||
302 | return 0; | ||
303 | |||
304 | fail: | ||
305 | if (armwdt_ck) | ||
306 | clk_put(armwdt_ck); | ||
307 | if (mpu_wdt_ick) | ||
308 | clk_put(mpu_wdt_ick); | ||
309 | if (mpu_wdt_fck) | ||
310 | clk_put(mpu_wdt_fck); | ||
311 | release_resource(mem); | ||
312 | return ret; | ||
313 | } | ||
314 | |||
315 | static void omap_wdt_shutdown(struct platform_device *pdev) | ||
316 | { | ||
317 | omap_wdt_disable(); | ||
318 | } | ||
319 | |||
320 | static int omap_wdt_remove(struct platform_device *pdev) | ||
321 | { | ||
322 | struct resource *mem = platform_get_drvdata(pdev); | ||
323 | misc_deregister(&omap_wdt_miscdev); | ||
324 | release_resource(mem); | ||
325 | if (armwdt_ck) | ||
326 | clk_put(armwdt_ck); | ||
327 | if (mpu_wdt_ick) | ||
328 | clk_put(mpu_wdt_ick); | ||
329 | if (mpu_wdt_fck) | ||
330 | clk_put(mpu_wdt_fck); | ||
331 | return 0; | ||
332 | } | ||
333 | |||
334 | #ifdef CONFIG_PM | ||
335 | |||
336 | /* REVISIT ... not clear this is the best way to handle system suspend; and | ||
337 | * it's very inappropriate for selective device suspend (e.g. suspending this | ||
338 | * through sysfs rather than by stopping the watchdog daemon). Also, this | ||
339 | * may not play well enough with NOWAYOUT... | ||
340 | */ | ||
341 | |||
342 | static int omap_wdt_suspend(struct platform_device *pdev, pm_message_t state) | ||
343 | { | ||
344 | if (omap_wdt_users) | ||
345 | omap_wdt_disable(); | ||
346 | return 0; | ||
347 | } | ||
348 | |||
349 | static int omap_wdt_resume(struct platform_device *pdev) | ||
350 | { | ||
351 | if (omap_wdt_users) { | ||
352 | omap_wdt_enable(); | ||
353 | omap_wdt_ping(); | ||
354 | } | ||
355 | return 0; | ||
356 | } | ||
357 | |||
358 | #else | ||
359 | #define omap_wdt_suspend NULL | ||
360 | #define omap_wdt_resume NULL | ||
361 | #endif | ||
362 | |||
363 | static struct platform_driver omap_wdt_driver = { | ||
364 | .probe = omap_wdt_probe, | ||
365 | .remove = omap_wdt_remove, | ||
366 | .shutdown = omap_wdt_shutdown, | ||
367 | .suspend = omap_wdt_suspend, | ||
368 | .resume = omap_wdt_resume, | ||
369 | .driver = { | ||
370 | .owner = THIS_MODULE, | ||
371 | .name = "omap_wdt", | ||
372 | }, | ||
373 | }; | ||
374 | |||
375 | static int __init omap_wdt_init(void) | ||
376 | { | ||
377 | return platform_driver_register(&omap_wdt_driver); | ||
378 | } | ||
379 | |||
380 | static void __exit omap_wdt_exit(void) | ||
381 | { | ||
382 | platform_driver_unregister(&omap_wdt_driver); | ||
383 | } | ||
384 | |||
385 | module_init(omap_wdt_init); | ||
386 | module_exit(omap_wdt_exit); | ||
387 | |||
388 | MODULE_AUTHOR("George G. Davis"); | ||
389 | MODULE_LICENSE("GPL"); | ||
390 | MODULE_ALIAS_MISCDEV(WATCHDOG_MINOR); | ||
diff --git a/drivers/char/watchdog/omap_wdt.h b/drivers/char/watchdog/omap_wdt.h new file mode 100644 index 000000000000..52a532a5114a --- /dev/null +++ b/drivers/char/watchdog/omap_wdt.h | |||
@@ -0,0 +1,64 @@ | |||
1 | /* | ||
2 | * linux/drivers/char/watchdog/omap_wdt.h | ||
3 | * | ||
4 | * BRIEF MODULE DESCRIPTION | ||
5 | * OMAP Watchdog timer register definitions | ||
6 | * | ||
7 | * Copyright (C) 2004 Texas Instruments. | ||
8 | * | ||
9 | * This program is free software; you can redistribute it and/or modify it | ||
10 | * under the terms of the GNU General Public License as published by the | ||
11 | * Free Software Foundation; either version 2 of the License, or (at your | ||
12 | * option) any later version. | ||
13 | * | ||
14 | * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED | ||
15 | * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF | ||
16 | * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN | ||
17 | * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, | ||
18 | * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT | ||
19 | * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF | ||
20 | * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON | ||
21 | * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | ||
22 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF | ||
23 | * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | ||
24 | * | ||
25 | * You should have received a copy of the GNU General Public License along | ||
26 | * with this program; if not, write to the Free Software Foundation, Inc., | ||
27 | * 675 Mass Ave, Cambridge, MA 02139, USA. | ||
28 | */ | ||
29 | |||
30 | #ifndef _OMAP_WATCHDOG_H | ||
31 | #define _OMAP_WATCHDOG_H | ||
32 | |||
33 | #define OMAP1610_WATCHDOG_BASE 0xfffeb000 | ||
34 | #define OMAP2420_WATCHDOG_BASE 0x48022000 /*WDT Timer 2 */ | ||
35 | |||
36 | #ifdef CONFIG_ARCH_OMAP24XX | ||
37 | #define OMAP_WATCHDOG_BASE OMAP2420_WATCHDOG_BASE | ||
38 | #else | ||
39 | #define OMAP_WATCHDOG_BASE OMAP1610_WATCHDOG_BASE | ||
40 | #define RM_RSTST_WKUP 0 | ||
41 | #endif | ||
42 | |||
43 | #define OMAP_WATCHDOG_REV (OMAP_WATCHDOG_BASE + 0x00) | ||
44 | #define OMAP_WATCHDOG_SYS_CONFIG (OMAP_WATCHDOG_BASE + 0x10) | ||
45 | #define OMAP_WATCHDOG_STATUS (OMAP_WATCHDOG_BASE + 0x14) | ||
46 | #define OMAP_WATCHDOG_CNTRL (OMAP_WATCHDOG_BASE + 0x24) | ||
47 | #define OMAP_WATCHDOG_CRR (OMAP_WATCHDOG_BASE + 0x28) | ||
48 | #define OMAP_WATCHDOG_LDR (OMAP_WATCHDOG_BASE + 0x2c) | ||
49 | #define OMAP_WATCHDOG_TGR (OMAP_WATCHDOG_BASE + 0x30) | ||
50 | #define OMAP_WATCHDOG_WPS (OMAP_WATCHDOG_BASE + 0x34) | ||
51 | #define OMAP_WATCHDOG_SPR (OMAP_WATCHDOG_BASE + 0x48) | ||
52 | |||
53 | /* Using the prescaler, the OMAP watchdog could go for many | ||
54 | * months before firing. These limits work without scaling, | ||
55 | * with the 60 second default assumed by most tools and docs. | ||
56 | */ | ||
57 | #define TIMER_MARGIN_MAX (24 * 60 * 60) /* 1 day */ | ||
58 | #define TIMER_MARGIN_DEFAULT 60 /* 60 secs */ | ||
59 | #define TIMER_MARGIN_MIN 1 | ||
60 | |||
61 | #define PTV 0 /* prescale */ | ||
62 | #define GET_WLDR_VAL(secs) (0xffffffff - ((secs) * (32768/(1<<PTV))) + 1) | ||
63 | |||
64 | #endif /* _OMAP_WATCHDOG_H */ | ||
diff --git a/drivers/char/watchdog/pc87413_wdt.c b/drivers/char/watchdog/pc87413_wdt.c new file mode 100644 index 000000000000..1d447e32af41 --- /dev/null +++ b/drivers/char/watchdog/pc87413_wdt.c | |||
@@ -0,0 +1,635 @@ | |||
1 | /* | ||
2 | * NS pc87413-wdt Watchdog Timer driver for Linux 2.6.x.x | ||
3 | * | ||
4 | * This code is based on wdt.c with original copyright. | ||
5 | * | ||
6 | * (C) Copyright 2006 Sven Anders, <anders@anduras.de> | ||
7 | * and Marcus Junker, <junker@anduras.de> | ||
8 | * | ||
9 | * This program is free software; you can redistribute it and/or | ||
10 | * modify it under the terms of the GNU General Public License | ||
11 | * as published by the Free Software Foundation; either version | ||
12 | * 2 of the License, or (at your option) any later version. | ||
13 | * | ||
14 | * Neither Sven Anders, Marcus Junker nor ANDURAS AG | ||
15 | * admit liability nor provide warranty for any of this software. | ||
16 | * This material is provided "AS-IS" and at no charge. | ||
17 | * | ||
18 | * Release 1.1 | ||
19 | */ | ||
20 | |||
21 | #include <linux/module.h> | ||
22 | #include <linux/types.h> | ||
23 | #include <linux/miscdevice.h> | ||
24 | #include <linux/watchdog.h> | ||
25 | #include <linux/ioport.h> | ||
26 | #include <linux/delay.h> | ||
27 | #include <linux/notifier.h> | ||
28 | #include <linux/fs.h> | ||
29 | #include <linux/reboot.h> | ||
30 | #include <linux/init.h> | ||
31 | #include <linux/spinlock.h> | ||
32 | #include <linux/moduleparam.h> | ||
33 | #include <linux/version.h> | ||
34 | |||
35 | #include <asm/io.h> | ||
36 | #include <asm/uaccess.h> | ||
37 | #include <asm/system.h> | ||
38 | |||
39 | /* #define DEBUG 1 */ | ||
40 | |||
41 | #define DEFAULT_TIMEOUT 1 /* 1 minute */ | ||
42 | #define MAX_TIMEOUT 255 | ||
43 | |||
44 | #define VERSION "1.1" | ||
45 | #define MODNAME "pc87413 WDT" | ||
46 | #define PFX MODNAME ": " | ||
47 | #define DPFX MODNAME " - DEBUG: " | ||
48 | |||
49 | #define WDT_INDEX_IO_PORT (io+0) /* I/O port base (index register) */ | ||
50 | #define WDT_DATA_IO_PORT (WDT_INDEX_IO_PORT+1) | ||
51 | #define SWC_LDN 0x04 | ||
52 | #define SIOCFG2 0x22 /* Serial IO register */ | ||
53 | #define WDCTL 0x10 /* Watchdog-Timer-Controll-Register */ | ||
54 | #define WDTO 0x11 /* Watchdog timeout register */ | ||
55 | #define WDCFG 0x12 /* Watchdog config register */ | ||
56 | |||
57 | static int io = 0x2E; /* Address used on Portwell Boards */ | ||
58 | |||
59 | static int timeout = DEFAULT_TIMEOUT; /* timeout value */ | ||
60 | static unsigned long timer_enabled = 0; /* is the timer enabled? */ | ||
61 | |||
62 | static char expect_close; /* is the close expected? */ | ||
63 | |||
64 | static spinlock_t io_lock; /* to guard the watchdog from io races */ | ||
65 | |||
66 | static int nowayout = WATCHDOG_NOWAYOUT; | ||
67 | |||
68 | /* -- Low level function ----------------------------------------*/ | ||
69 | |||
70 | /* Select pins for Watchdog output */ | ||
71 | |||
72 | static inline void pc87413_select_wdt_out (void) | ||
73 | { | ||
74 | unsigned int cr_data = 0; | ||
75 | |||
76 | /* Step 1: Select multiple pin,pin55,as WDT output */ | ||
77 | |||
78 | outb_p(SIOCFG2, WDT_INDEX_IO_PORT); | ||
79 | |||
80 | cr_data = inb (WDT_DATA_IO_PORT); | ||
81 | |||
82 | cr_data |= 0x80; /* Set Bit7 to 1*/ | ||
83 | outb_p(SIOCFG2, WDT_INDEX_IO_PORT); | ||
84 | |||
85 | outb_p(cr_data, WDT_DATA_IO_PORT); | ||
86 | |||
87 | #ifdef DEBUG | ||
88 | printk(KERN_INFO DPFX "Select multiple pin,pin55,as WDT output:" | ||
89 | " Bit7 to 1: %d\n", cr_data); | ||
90 | #endif | ||
91 | } | ||
92 | |||
93 | /* Enable SWC functions */ | ||
94 | |||
95 | static inline void pc87413_enable_swc(void) | ||
96 | { | ||
97 | unsigned int cr_data=0; | ||
98 | |||
99 | /* Step 2: Enable SWC functions */ | ||
100 | |||
101 | outb_p(0x07, WDT_INDEX_IO_PORT); /* Point SWC_LDN (LDN=4) */ | ||
102 | outb_p(SWC_LDN, WDT_DATA_IO_PORT); | ||
103 | |||
104 | outb_p(0x30, WDT_INDEX_IO_PORT); /* Read Index 0x30 First */ | ||
105 | cr_data = inb(WDT_DATA_IO_PORT); | ||
106 | cr_data |= 0x01; /* Set Bit0 to 1 */ | ||
107 | outb_p(0x30, WDT_INDEX_IO_PORT); | ||
108 | outb_p(cr_data, WDT_DATA_IO_PORT); /* Index0x30_bit0P1 */ | ||
109 | |||
110 | #ifdef DEBUG | ||
111 | printk(KERN_INFO DPFX "pc87413 - Enable SWC functions\n"); | ||
112 | #endif | ||
113 | } | ||
114 | |||
115 | /* Read SWC I/O base address */ | ||
116 | |||
117 | static inline unsigned int pc87413_get_swc_base(void) | ||
118 | { | ||
119 | unsigned int swc_base_addr = 0; | ||
120 | unsigned char addr_l, addr_h = 0; | ||
121 | |||
122 | /* Step 3: Read SWC I/O Base Address */ | ||
123 | |||
124 | outb_p(0x60, WDT_INDEX_IO_PORT); /* Read Index 0x60 */ | ||
125 | addr_h = inb(WDT_DATA_IO_PORT); | ||
126 | |||
127 | outb_p(0x61, WDT_INDEX_IO_PORT); /* Read Index 0x61 */ | ||
128 | |||
129 | addr_l = inb(WDT_DATA_IO_PORT); | ||
130 | |||
131 | swc_base_addr = (addr_h << 8) + addr_l; | ||
132 | |||
133 | #ifdef DEBUG | ||
134 | printk(KERN_INFO DPFX "Read SWC I/O Base Address: low %d, high %d," | ||
135 | " res %d\n", addr_l, addr_h, swc_base_addr); | ||
136 | #endif | ||
137 | |||
138 | return swc_base_addr; | ||
139 | } | ||
140 | |||
141 | /* Select Bank 3 of SWC */ | ||
142 | |||
143 | static inline void pc87413_swc_bank3(unsigned int swc_base_addr) | ||
144 | { | ||
145 | /* Step 4: Select Bank3 of SWC */ | ||
146 | |||
147 | outb_p(inb(swc_base_addr + 0x0f) | 0x03, swc_base_addr + 0x0f); | ||
148 | |||
149 | #ifdef DEBUG | ||
150 | printk(KERN_INFO DPFX "Select Bank3 of SWC\n"); | ||
151 | #endif | ||
152 | } | ||
153 | |||
154 | /* Set watchdog timeout to x minutes */ | ||
155 | |||
156 | static inline void pc87413_programm_wdto(unsigned int swc_base_addr, | ||
157 | char pc87413_time) | ||
158 | { | ||
159 | /* Step 5: Programm WDTO, Twd. */ | ||
160 | |||
161 | outb_p(pc87413_time, swc_base_addr + WDTO); | ||
162 | |||
163 | #ifdef DEBUG | ||
164 | printk(KERN_INFO DPFX "Set WDTO to %d minutes\n", pc87413_time); | ||
165 | #endif | ||
166 | } | ||
167 | |||
168 | /* Enable WDEN */ | ||
169 | |||
170 | static inline void pc87413_enable_wden(unsigned int swc_base_addr) | ||
171 | { | ||
172 | /* Step 6: Enable WDEN */ | ||
173 | |||
174 | outb_p(inb (swc_base_addr + WDCTL) | 0x01, swc_base_addr + WDCTL); | ||
175 | |||
176 | #ifdef DEBUG | ||
177 | printk(KERN_INFO DPFX "Enable WDEN\n"); | ||
178 | #endif | ||
179 | } | ||
180 | |||
181 | /* Enable SW_WD_TREN */ | ||
182 | static inline void pc87413_enable_sw_wd_tren(unsigned int swc_base_addr) | ||
183 | { | ||
184 | /* Enable SW_WD_TREN */ | ||
185 | |||
186 | outb_p(inb (swc_base_addr + WDCFG) | 0x80, swc_base_addr + WDCFG); | ||
187 | |||
188 | #ifdef DEBUG | ||
189 | printk(KERN_INFO DPFX "Enable SW_WD_TREN\n"); | ||
190 | #endif | ||
191 | } | ||
192 | |||
193 | /* Disable SW_WD_TREN */ | ||
194 | |||
195 | static inline void pc87413_disable_sw_wd_tren(unsigned int swc_base_addr) | ||
196 | { | ||
197 | /* Disable SW_WD_TREN */ | ||
198 | |||
199 | outb_p(inb (swc_base_addr + WDCFG) & 0x7f, swc_base_addr + WDCFG); | ||
200 | |||
201 | #ifdef DEBUG | ||
202 | printk(KERN_INFO DPFX "pc87413 - Disable SW_WD_TREN\n"); | ||
203 | #endif | ||
204 | } | ||
205 | |||
206 | /* Enable SW_WD_TRG */ | ||
207 | |||
208 | static inline void pc87413_enable_sw_wd_trg(unsigned int swc_base_addr) | ||
209 | { | ||
210 | /* Enable SW_WD_TRG */ | ||
211 | |||
212 | outb_p(inb (swc_base_addr + WDCTL) | 0x80, swc_base_addr + WDCTL); | ||
213 | |||
214 | #ifdef DEBUG | ||
215 | printk(KERN_INFO DPFX "pc87413 - Enable SW_WD_TRG\n"); | ||
216 | #endif | ||
217 | } | ||
218 | |||
219 | /* Disable SW_WD_TRG */ | ||
220 | |||
221 | static inline void pc87413_disable_sw_wd_trg(unsigned int swc_base_addr) | ||
222 | { | ||
223 | /* Disable SW_WD_TRG */ | ||
224 | |||
225 | outb_p(inb (swc_base_addr + WDCTL) & 0x7f, swc_base_addr + WDCTL); | ||
226 | |||
227 | #ifdef DEBUG | ||
228 | printk(KERN_INFO DPFX "Disable SW_WD_TRG\n"); | ||
229 | #endif | ||
230 | } | ||
231 | |||
232 | /* -- Higher level functions ------------------------------------*/ | ||
233 | |||
234 | /* Enable the watchdog */ | ||
235 | |||
236 | static void pc87413_enable(void) | ||
237 | { | ||
238 | unsigned int swc_base_addr; | ||
239 | |||
240 | spin_lock(&io_lock); | ||
241 | |||
242 | pc87413_select_wdt_out(); | ||
243 | pc87413_enable_swc(); | ||
244 | swc_base_addr = pc87413_get_swc_base(); | ||
245 | pc87413_swc_bank3(swc_base_addr); | ||
246 | pc87413_programm_wdto(swc_base_addr, timeout); | ||
247 | pc87413_enable_wden(swc_base_addr); | ||
248 | pc87413_enable_sw_wd_tren(swc_base_addr); | ||
249 | pc87413_enable_sw_wd_trg(swc_base_addr); | ||
250 | |||
251 | spin_unlock(&io_lock); | ||
252 | } | ||
253 | |||
254 | /* Disable the watchdog */ | ||
255 | |||
256 | static void pc87413_disable(void) | ||
257 | { | ||
258 | unsigned int swc_base_addr; | ||
259 | |||
260 | spin_lock(&io_lock); | ||
261 | |||
262 | pc87413_select_wdt_out(); | ||
263 | pc87413_enable_swc(); | ||
264 | swc_base_addr = pc87413_get_swc_base(); | ||
265 | pc87413_swc_bank3(swc_base_addr); | ||
266 | pc87413_disable_sw_wd_tren(swc_base_addr); | ||
267 | pc87413_disable_sw_wd_trg(swc_base_addr); | ||
268 | pc87413_programm_wdto(swc_base_addr, 0); | ||
269 | |||
270 | spin_unlock(&io_lock); | ||
271 | } | ||
272 | |||
273 | /* Refresh the watchdog */ | ||
274 | |||
275 | static void pc87413_refresh(void) | ||
276 | { | ||
277 | unsigned int swc_base_addr; | ||
278 | |||
279 | spin_lock(&io_lock); | ||
280 | |||
281 | pc87413_select_wdt_out(); | ||
282 | pc87413_enable_swc(); | ||
283 | swc_base_addr = pc87413_get_swc_base(); | ||
284 | pc87413_swc_bank3(swc_base_addr); | ||
285 | pc87413_disable_sw_wd_tren(swc_base_addr); | ||
286 | pc87413_disable_sw_wd_trg(swc_base_addr); | ||
287 | pc87413_programm_wdto(swc_base_addr, timeout); | ||
288 | pc87413_enable_wden(swc_base_addr); | ||
289 | pc87413_enable_sw_wd_tren(swc_base_addr); | ||
290 | pc87413_enable_sw_wd_trg(swc_base_addr); | ||
291 | |||
292 | spin_unlock(&io_lock); | ||
293 | } | ||
294 | |||
295 | /* -- File operations -------------------------------------------*/ | ||
296 | |||
297 | /** | ||
298 | * pc87413_open: | ||
299 | * @inode: inode of device | ||
300 | * @file: file handle to device | ||
301 | * | ||
302 | */ | ||
303 | |||
304 | static int pc87413_open(struct inode *inode, struct file *file) | ||
305 | { | ||
306 | /* /dev/watchdog can only be opened once */ | ||
307 | |||
308 | if (test_and_set_bit(0, &timer_enabled)) | ||
309 | return -EBUSY; | ||
310 | |||
311 | if (nowayout) | ||
312 | __module_get(THIS_MODULE); | ||
313 | |||
314 | /* Reload and activate timer */ | ||
315 | pc87413_refresh(); | ||
316 | |||
317 | printk(KERN_INFO MODNAME "Watchdog enabled. Timeout set to" | ||
318 | " %d minute(s).\n", timeout); | ||
319 | |||
320 | return nonseekable_open(inode, file); | ||
321 | } | ||
322 | |||
323 | /** | ||
324 | * pc87413_release: | ||
325 | * @inode: inode to board | ||
326 | * @file: file handle to board | ||
327 | * | ||
328 | * The watchdog has a configurable API. There is a religious dispute | ||
329 | * between people who want their watchdog to be able to shut down and | ||
330 | * those who want to be sure if the watchdog manager dies the machine | ||
331 | * reboots. In the former case we disable the counters, in the latter | ||
332 | * case you have to open it again very soon. | ||
333 | */ | ||
334 | |||
335 | static int pc87413_release(struct inode *inode, struct file *file) | ||
336 | { | ||
337 | /* Shut off the timer. */ | ||
338 | |||
339 | if (expect_close == 42) { | ||
340 | pc87413_disable(); | ||
341 | printk(KERN_INFO MODNAME "Watchdog disabled," | ||
342 | " sleeping again...\n"); | ||
343 | } else { | ||
344 | printk(KERN_CRIT MODNAME "Unexpected close, not stopping" | ||
345 | " watchdog!\n"); | ||
346 | pc87413_refresh(); | ||
347 | } | ||
348 | |||
349 | clear_bit(0, &timer_enabled); | ||
350 | expect_close = 0; | ||
351 | |||
352 | return 0; | ||
353 | } | ||
354 | |||
355 | /** | ||
356 | * pc87413_status: | ||
357 | * | ||
358 | * return, if the watchdog is enabled (timeout is set...) | ||
359 | */ | ||
360 | |||
361 | |||
362 | static int pc87413_status(void) | ||
363 | { | ||
364 | return 0; /* currently not supported */ | ||
365 | } | ||
366 | |||
367 | /** | ||
368 | * pc87413_write: | ||
369 | * @file: file handle to the watchdog | ||
370 | * @data: data buffer to write | ||
371 | * @len: length in bytes | ||
372 | * @ppos: pointer to the position to write. No seeks allowed | ||
373 | * | ||
374 | * A write to a watchdog device is defined as a keepalive signal. Any | ||
375 | * write of data will do, as we we don't define content meaning. | ||
376 | */ | ||
377 | |||
378 | static ssize_t pc87413_write(struct file *file, const char __user *data, | ||
379 | size_t len, loff_t *ppos) | ||
380 | { | ||
381 | /* See if we got the magic character 'V' and reload the timer */ | ||
382 | if (len) { | ||
383 | if (!nowayout) { | ||
384 | size_t i; | ||
385 | |||
386 | /* reset expect flag */ | ||
387 | expect_close = 0; | ||
388 | |||
389 | /* scan to see whether or not we got the magic character */ | ||
390 | for (i = 0; i != len; i++) { | ||
391 | char c; | ||
392 | if (get_user(c, data+i)) | ||
393 | return -EFAULT; | ||
394 | if (c == 'V') | ||
395 | expect_close = 42; | ||
396 | } | ||
397 | } | ||
398 | |||
399 | /* someone wrote to us, we should reload the timer */ | ||
400 | pc87413_refresh(); | ||
401 | } | ||
402 | return len; | ||
403 | } | ||
404 | |||
405 | /** | ||
406 | * pc87413_ioctl: | ||
407 | * @inode: inode of the device | ||
408 | * @file: file handle to the device | ||
409 | * @cmd: watchdog command | ||
410 | * @arg: argument pointer | ||
411 | * | ||
412 | * The watchdog API defines a common set of functions for all watchdogs | ||
413 | * according to their available features. We only actually usefully support | ||
414 | * querying capabilities and current status. | ||
415 | */ | ||
416 | |||
417 | static int pc87413_ioctl(struct inode *inode, struct file *file, | ||
418 | unsigned int cmd, unsigned long arg) | ||
419 | { | ||
420 | int new_timeout; | ||
421 | |||
422 | union { | ||
423 | struct watchdog_info __user *ident; | ||
424 | int __user *i; | ||
425 | } uarg; | ||
426 | |||
427 | static struct watchdog_info ident = { | ||
428 | .options = WDIOF_KEEPALIVEPING | | ||
429 | WDIOF_SETTIMEOUT | | ||
430 | WDIOF_MAGICCLOSE, | ||
431 | .firmware_version = 1, | ||
432 | .identity = "PC87413(HF/F) watchdog" | ||
433 | }; | ||
434 | |||
435 | uarg.i = (int __user *)arg; | ||
436 | |||
437 | switch(cmd) { | ||
438 | default: | ||
439 | return -ENOTTY; | ||
440 | |||
441 | case WDIOC_GETSUPPORT: | ||
442 | return copy_to_user(uarg.ident, &ident, | ||
443 | sizeof(ident)) ? -EFAULT : 0; | ||
444 | |||
445 | case WDIOC_GETSTATUS: | ||
446 | return put_user(pc87413_status(), uarg.i); | ||
447 | |||
448 | case WDIOC_GETBOOTSTATUS: | ||
449 | return put_user(0, uarg.i); | ||
450 | |||
451 | case WDIOC_KEEPALIVE: | ||
452 | pc87413_refresh(); | ||
453 | #ifdef DEBUG | ||
454 | printk(KERN_INFO DPFX "keepalive\n"); | ||
455 | #endif | ||
456 | return 0; | ||
457 | |||
458 | case WDIOC_SETTIMEOUT: | ||
459 | if (get_user(new_timeout, uarg.i)) | ||
460 | return -EFAULT; | ||
461 | |||
462 | // the API states this is given in secs | ||
463 | new_timeout /= 60; | ||
464 | |||
465 | if (new_timeout < 0 || new_timeout > MAX_TIMEOUT) | ||
466 | return -EINVAL; | ||
467 | |||
468 | timeout = new_timeout; | ||
469 | pc87413_refresh(); | ||
470 | |||
471 | // fall through and return the new timeout... | ||
472 | |||
473 | case WDIOC_GETTIMEOUT: | ||
474 | |||
475 | new_timeout = timeout * 60; | ||
476 | |||
477 | return put_user(new_timeout, uarg.i); | ||
478 | |||
479 | case WDIOC_SETOPTIONS: | ||
480 | { | ||
481 | int options, retval = -EINVAL; | ||
482 | |||
483 | if (get_user(options, uarg.i)) | ||
484 | return -EFAULT; | ||
485 | |||
486 | if (options & WDIOS_DISABLECARD) { | ||
487 | pc87413_disable(); | ||
488 | retval = 0; | ||
489 | } | ||
490 | |||
491 | if (options & WDIOS_ENABLECARD) { | ||
492 | pc87413_enable(); | ||
493 | retval = 0; | ||
494 | } | ||
495 | |||
496 | return retval; | ||
497 | } | ||
498 | } | ||
499 | } | ||
500 | |||
501 | /* -- Notifier funtions -----------------------------------------*/ | ||
502 | |||
503 | /** | ||
504 | * notify_sys: | ||
505 | * @this: our notifier block | ||
506 | * @code: the event being reported | ||
507 | * @unused: unused | ||
508 | * | ||
509 | * Our notifier is called on system shutdowns. We want to turn the card | ||
510 | * off at reboot otherwise the machine will reboot again during memory | ||
511 | * test or worse yet during the following fsck. This would suck, in fact | ||
512 | * trust me - if it happens it does suck. | ||
513 | */ | ||
514 | |||
515 | static int pc87413_notify_sys(struct notifier_block *this, | ||
516 | unsigned long code, | ||
517 | void *unused) | ||
518 | { | ||
519 | if (code == SYS_DOWN || code == SYS_HALT) | ||
520 | { | ||
521 | /* Turn the card off */ | ||
522 | pc87413_disable(); | ||
523 | } | ||
524 | return NOTIFY_DONE; | ||
525 | } | ||
526 | |||
527 | /* -- Module's structures ---------------------------------------*/ | ||
528 | |||
529 | static struct file_operations pc87413_fops = { | ||
530 | .owner = THIS_MODULE, | ||
531 | .llseek = no_llseek, | ||
532 | .write = pc87413_write, | ||
533 | .ioctl = pc87413_ioctl, | ||
534 | .open = pc87413_open, | ||
535 | .release = pc87413_release, | ||
536 | }; | ||
537 | |||
538 | static struct notifier_block pc87413_notifier = | ||
539 | { | ||
540 | .notifier_call = pc87413_notify_sys, | ||
541 | }; | ||
542 | |||
543 | static struct miscdevice pc87413_miscdev= | ||
544 | { | ||
545 | .minor = WATCHDOG_MINOR, | ||
546 | .name = "watchdog", | ||
547 | .fops = &pc87413_fops | ||
548 | }; | ||
549 | |||
550 | /* -- Module init functions -------------------------------------*/ | ||
551 | |||
552 | /** | ||
553 | * pc87413_init: module's "constructor" | ||
554 | * | ||
555 | * Set up the WDT watchdog board. All we have to do is grab the | ||
556 | * resources we require and bitch if anyone beat us to them. | ||
557 | * The open() function will actually kick the board off. | ||
558 | */ | ||
559 | |||
560 | static int __init pc87413_init(void) | ||
561 | { | ||
562 | int ret; | ||
563 | |||
564 | spin_lock_init(&io_lock); | ||
565 | |||
566 | printk(KERN_INFO PFX "Version " VERSION " at io 0x%X\n", WDT_INDEX_IO_PORT); | ||
567 | |||
568 | /* request_region(io, 2, "pc87413"); */ | ||
569 | |||
570 | ret = register_reboot_notifier(&pc87413_notifier); | ||
571 | if (ret != 0) { | ||
572 | printk(KERN_ERR PFX "cannot register reboot notifier (err=%d)\n", | ||
573 | ret); | ||
574 | } | ||
575 | |||
576 | ret = misc_register(&pc87413_miscdev); | ||
577 | |||
578 | if (ret != 0) { | ||
579 | printk(KERN_ERR PFX "cannot register miscdev on minor=%d (err=%d)\n", | ||
580 | WATCHDOG_MINOR, ret); | ||
581 | unregister_reboot_notifier(&pc87413_notifier); | ||
582 | return ret; | ||
583 | } | ||
584 | |||
585 | printk(KERN_INFO PFX "initialized. timeout=%d min \n", timeout); | ||
586 | |||
587 | pc87413_enable(); | ||
588 | |||
589 | return 0; | ||
590 | } | ||
591 | |||
592 | /** | ||
593 | * pc87413_exit: module's "destructor" | ||
594 | * | ||
595 | * Unload the watchdog. You cannot do this with any file handles open. | ||
596 | * If your watchdog is set to continue ticking on close and you unload | ||
597 | * it, well it keeps ticking. We won't get the interrupt but the board | ||
598 | * will not touch PC memory so all is fine. You just have to load a new | ||
599 | * module in 60 seconds or reboot. | ||
600 | */ | ||
601 | |||
602 | static void __exit pc87413_exit(void) | ||
603 | { | ||
604 | /* Stop the timer before we leave */ | ||
605 | if (!nowayout) | ||
606 | { | ||
607 | pc87413_disable(); | ||
608 | printk(KERN_INFO MODNAME "Watchdog disabled.\n"); | ||
609 | } | ||
610 | |||
611 | misc_deregister(&pc87413_miscdev); | ||
612 | unregister_reboot_notifier(&pc87413_notifier); | ||
613 | /* release_region(io,2); */ | ||
614 | |||
615 | printk(MODNAME " watchdog component driver removed.\n"); | ||
616 | } | ||
617 | |||
618 | module_init(pc87413_init); | ||
619 | module_exit(pc87413_exit); | ||
620 | |||
621 | MODULE_AUTHOR("Sven Anders <anders@anduras.de>, Marcus Junker <junker@anduras.de>,"); | ||
622 | MODULE_DESCRIPTION("PC87413 WDT driver"); | ||
623 | MODULE_LICENSE("GPL"); | ||
624 | |||
625 | MODULE_ALIAS_MISCDEV(WATCHDOG_MINOR); | ||
626 | |||
627 | module_param(io, int, 0); | ||
628 | MODULE_PARM_DESC(io, MODNAME " I/O port (default: " __MODULE_STRING(io) ")."); | ||
629 | |||
630 | module_param(timeout, int, 0); | ||
631 | MODULE_PARM_DESC(timeout, "Watchdog timeout in minutes (default=" __MODULE_STRING(timeout) ")."); | ||
632 | |||
633 | module_param(nowayout, int, 0); | ||
634 | MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default=CONFIG_WATCHDOG_NOWAYOUT)"); | ||
635 | |||
diff --git a/drivers/char/watchdog/pcwd.c b/drivers/char/watchdog/pcwd.c index cd7d1b6a5d9f..8e1e6e48e0a7 100644 --- a/drivers/char/watchdog/pcwd.c +++ b/drivers/char/watchdog/pcwd.c | |||
@@ -49,7 +49,6 @@ | |||
49 | * More info available at http://www.berkprod.com/ or http://www.pcwatchdog.com/ | 49 | * More info available at http://www.berkprod.com/ or http://www.pcwatchdog.com/ |
50 | */ | 50 | */ |
51 | 51 | ||
52 | #include <linux/config.h> /* For CONFIG_WATCHDOG_NOWAYOUT/... */ | ||
53 | #include <linux/module.h> /* For module specific items */ | 52 | #include <linux/module.h> /* For module specific items */ |
54 | #include <linux/moduleparam.h> /* For new moduleparam's */ | 53 | #include <linux/moduleparam.h> /* For new moduleparam's */ |
55 | #include <linux/types.h> /* For standard types (like size_t) */ | 54 | #include <linux/types.h> /* For standard types (like size_t) */ |
@@ -572,7 +571,7 @@ static int pcwd_ioctl(struct inode *inode, struct file *file, | |||
572 | 571 | ||
573 | switch(cmd) { | 572 | switch(cmd) { |
574 | default: | 573 | default: |
575 | return -ENOIOCTLCMD; | 574 | return -ENOTTY; |
576 | 575 | ||
577 | case WDIOC_GETSUPPORT: | 576 | case WDIOC_GETSUPPORT: |
578 | if(copy_to_user(argp, &ident, sizeof(ident))) | 577 | if(copy_to_user(argp, &ident, sizeof(ident))) |
diff --git a/drivers/char/watchdog/pcwd_pci.c b/drivers/char/watchdog/pcwd_pci.c index c7cfd6dbfe1b..f4872c871063 100644 --- a/drivers/char/watchdog/pcwd_pci.c +++ b/drivers/char/watchdog/pcwd_pci.c | |||
@@ -31,7 +31,6 @@ | |||
31 | * Includes, defines, variables, module parameters, ... | 31 | * Includes, defines, variables, module parameters, ... |
32 | */ | 32 | */ |
33 | 33 | ||
34 | #include <linux/config.h> /* For CONFIG_WATCHDOG_NOWAYOUT/... */ | ||
35 | #include <linux/module.h> /* For module specific items */ | 34 | #include <linux/module.h> /* For module specific items */ |
36 | #include <linux/moduleparam.h> /* For new moduleparam's */ | 35 | #include <linux/moduleparam.h> /* For new moduleparam's */ |
37 | #include <linux/types.h> /* For standard types (like size_t) */ | 36 | #include <linux/types.h> /* For standard types (like size_t) */ |
@@ -541,7 +540,7 @@ static int pcipcwd_ioctl(struct inode *inode, struct file *file, | |||
541 | } | 540 | } |
542 | 541 | ||
543 | default: | 542 | default: |
544 | return -ENOIOCTLCMD; | 543 | return -ENOTTY; |
545 | } | 544 | } |
546 | } | 545 | } |
547 | 546 | ||
diff --git a/drivers/char/watchdog/pcwd_usb.c b/drivers/char/watchdog/pcwd_usb.c index b7ae73dcdd08..61138726b501 100644 --- a/drivers/char/watchdog/pcwd_usb.c +++ b/drivers/char/watchdog/pcwd_usb.c | |||
@@ -158,7 +158,7 @@ static struct usb_driver usb_pcwd_driver = { | |||
158 | }; | 158 | }; |
159 | 159 | ||
160 | 160 | ||
161 | static void usb_pcwd_intr_done(struct urb *urb, struct pt_regs *regs) | 161 | static void usb_pcwd_intr_done(struct urb *urb) |
162 | { | 162 | { |
163 | struct usb_pcwd_private *usb_pcwd = (struct usb_pcwd_private *)urb->context; | 163 | struct usb_pcwd_private *usb_pcwd = (struct usb_pcwd_private *)urb->context; |
164 | unsigned char *data = usb_pcwd->intr_buffer; | 164 | unsigned char *data = usb_pcwd->intr_buffer; |
@@ -445,7 +445,7 @@ static int usb_pcwd_ioctl(struct inode *inode, struct file *file, | |||
445 | } | 445 | } |
446 | 446 | ||
447 | default: | 447 | default: |
448 | return -ENOIOCTLCMD; | 448 | return -ENOTTY; |
449 | } | 449 | } |
450 | } | 450 | } |
451 | 451 | ||
@@ -561,8 +561,7 @@ static struct notifier_block usb_pcwd_notifier = { | |||
561 | */ | 561 | */ |
562 | static inline void usb_pcwd_delete (struct usb_pcwd_private *usb_pcwd) | 562 | static inline void usb_pcwd_delete (struct usb_pcwd_private *usb_pcwd) |
563 | { | 563 | { |
564 | if (usb_pcwd->intr_urb != NULL) | 564 | usb_free_urb(usb_pcwd->intr_urb); |
565 | usb_free_urb (usb_pcwd->intr_urb); | ||
566 | if (usb_pcwd->intr_buffer != NULL) | 565 | if (usb_pcwd->intr_buffer != NULL) |
567 | usb_buffer_free(usb_pcwd->udev, usb_pcwd->intr_size, | 566 | usb_buffer_free(usb_pcwd->udev, usb_pcwd->intr_size, |
568 | usb_pcwd->intr_buffer, usb_pcwd->intr_dma); | 567 | usb_pcwd->intr_buffer, usb_pcwd->intr_dma); |
@@ -635,7 +634,7 @@ static int usb_pcwd_probe(struct usb_interface *interface, const struct usb_devi | |||
635 | usb_pcwd->intr_size = (le16_to_cpu(endpoint->wMaxPacketSize) > 8 ? le16_to_cpu(endpoint->wMaxPacketSize) : 8); | 634 | usb_pcwd->intr_size = (le16_to_cpu(endpoint->wMaxPacketSize) > 8 ? le16_to_cpu(endpoint->wMaxPacketSize) : 8); |
636 | 635 | ||
637 | /* set up the memory buffer's */ | 636 | /* set up the memory buffer's */ |
638 | if (!(usb_pcwd->intr_buffer = usb_buffer_alloc(udev, usb_pcwd->intr_size, SLAB_ATOMIC, &usb_pcwd->intr_dma))) { | 637 | if (!(usb_pcwd->intr_buffer = usb_buffer_alloc(udev, usb_pcwd->intr_size, GFP_ATOMIC, &usb_pcwd->intr_dma))) { |
639 | printk(KERN_ERR PFX "Out of memory\n"); | 638 | printk(KERN_ERR PFX "Out of memory\n"); |
640 | goto error; | 639 | goto error; |
641 | } | 640 | } |
diff --git a/drivers/char/watchdog/pnx4008_wdt.c b/drivers/char/watchdog/pnx4008_wdt.c new file mode 100644 index 000000000000..3a55fc6abcd8 --- /dev/null +++ b/drivers/char/watchdog/pnx4008_wdt.c | |||
@@ -0,0 +1,361 @@ | |||
1 | /* | ||
2 | * drivers/char/watchdog/pnx4008_wdt.c | ||
3 | * | ||
4 | * Watchdog driver for PNX4008 board | ||
5 | * | ||
6 | * Authors: Dmitry Chigirev <source@mvista.com>, | ||
7 | * Vitaly Wool <vitalywool@gmail.com> | ||
8 | * Based on sa1100 driver, | ||
9 | * Copyright (C) 2000 Oleg Drokin <green@crimea.edu> | ||
10 | * | ||
11 | * 2005-2006 (c) MontaVista Software, Inc. This file is licensed under | ||
12 | * the terms of the GNU General Public License version 2. This program | ||
13 | * is licensed "as is" without any warranty of any kind, whether express | ||
14 | * or implied. | ||
15 | */ | ||
16 | |||
17 | #include <linux/module.h> | ||
18 | #include <linux/moduleparam.h> | ||
19 | #include <linux/types.h> | ||
20 | #include <linux/kernel.h> | ||
21 | #include <linux/fs.h> | ||
22 | #include <linux/miscdevice.h> | ||
23 | #include <linux/watchdog.h> | ||
24 | #include <linux/init.h> | ||
25 | #include <linux/bitops.h> | ||
26 | #include <linux/ioport.h> | ||
27 | #include <linux/device.h> | ||
28 | #include <linux/platform_device.h> | ||
29 | #include <linux/clk.h> | ||
30 | #include <linux/spinlock.h> | ||
31 | |||
32 | #include <asm/hardware.h> | ||
33 | #include <asm/uaccess.h> | ||
34 | #include <asm/io.h> | ||
35 | |||
36 | #define MODULE_NAME "PNX4008-WDT: " | ||
37 | |||
38 | /* WatchDog Timer - Chapter 23 Page 207 */ | ||
39 | |||
40 | #define DEFAULT_HEARTBEAT 19 | ||
41 | #define MAX_HEARTBEAT 60 | ||
42 | |||
43 | /* Watchdog timer register set definition */ | ||
44 | #define WDTIM_INT(p) ((p) + 0x0) | ||
45 | #define WDTIM_CTRL(p) ((p) + 0x4) | ||
46 | #define WDTIM_COUNTER(p) ((p) + 0x8) | ||
47 | #define WDTIM_MCTRL(p) ((p) + 0xC) | ||
48 | #define WDTIM_MATCH0(p) ((p) + 0x10) | ||
49 | #define WDTIM_EMR(p) ((p) + 0x14) | ||
50 | #define WDTIM_PULSE(p) ((p) + 0x18) | ||
51 | #define WDTIM_RES(p) ((p) + 0x1C) | ||
52 | |||
53 | /* WDTIM_INT bit definitions */ | ||
54 | #define MATCH_INT 1 | ||
55 | |||
56 | /* WDTIM_CTRL bit definitions */ | ||
57 | #define COUNT_ENAB 1 | ||
58 | #define RESET_COUNT (1<<1) | ||
59 | #define DEBUG_EN (1<<2) | ||
60 | |||
61 | /* WDTIM_MCTRL bit definitions */ | ||
62 | #define MR0_INT 1 | ||
63 | #undef RESET_COUNT0 | ||
64 | #define RESET_COUNT0 (1<<2) | ||
65 | #define STOP_COUNT0 (1<<2) | ||
66 | #define M_RES1 (1<<3) | ||
67 | #define M_RES2 (1<<4) | ||
68 | #define RESFRC1 (1<<5) | ||
69 | #define RESFRC2 (1<<6) | ||
70 | |||
71 | /* WDTIM_EMR bit definitions */ | ||
72 | #define EXT_MATCH0 1 | ||
73 | #define MATCH_OUTPUT_HIGH (2<<4) /*a MATCH_CTRL setting */ | ||
74 | |||
75 | /* WDTIM_RES bit definitions */ | ||
76 | #define WDOG_RESET 1 /* read only */ | ||
77 | |||
78 | #define WDOG_COUNTER_RATE 13000000 /*the counter clock is 13 MHz fixed */ | ||
79 | |||
80 | static int nowayout = WATCHDOG_NOWAYOUT; | ||
81 | static int heartbeat = DEFAULT_HEARTBEAT; | ||
82 | |||
83 | static spinlock_t io_lock; | ||
84 | static unsigned long wdt_status; | ||
85 | #define WDT_IN_USE 0 | ||
86 | #define WDT_OK_TO_CLOSE 1 | ||
87 | #define WDT_REGION_INITED 2 | ||
88 | #define WDT_DEVICE_INITED 3 | ||
89 | |||
90 | static unsigned long boot_status; | ||
91 | |||
92 | static struct resource *wdt_mem; | ||
93 | static void __iomem *wdt_base; | ||
94 | struct clk *wdt_clk; | ||
95 | |||
96 | static void wdt_enable(void) | ||
97 | { | ||
98 | spin_lock(&io_lock); | ||
99 | |||
100 | if (wdt_clk) | ||
101 | clk_set_rate(wdt_clk, 1); | ||
102 | |||
103 | /* stop counter, initiate counter reset */ | ||
104 | __raw_writel(RESET_COUNT, WDTIM_CTRL(wdt_base)); | ||
105 | /*wait for reset to complete. 100% guarantee event */ | ||
106 | while (__raw_readl(WDTIM_COUNTER(wdt_base))) | ||
107 | cpu_relax(); | ||
108 | /* internal and external reset, stop after that */ | ||
109 | __raw_writel(M_RES2 | STOP_COUNT0 | RESET_COUNT0, | ||
110 | WDTIM_MCTRL(wdt_base)); | ||
111 | /* configure match output */ | ||
112 | __raw_writel(MATCH_OUTPUT_HIGH, WDTIM_EMR(wdt_base)); | ||
113 | /* clear interrupt, just in case */ | ||
114 | __raw_writel(MATCH_INT, WDTIM_INT(wdt_base)); | ||
115 | /* the longest pulse period 65541/(13*10^6) seconds ~ 5 ms. */ | ||
116 | __raw_writel(0xFFFF, WDTIM_PULSE(wdt_base)); | ||
117 | __raw_writel(heartbeat * WDOG_COUNTER_RATE, WDTIM_MATCH0(wdt_base)); | ||
118 | /*enable counter, stop when debugger active */ | ||
119 | __raw_writel(COUNT_ENAB | DEBUG_EN, WDTIM_CTRL(wdt_base)); | ||
120 | |||
121 | spin_unlock(&io_lock); | ||
122 | } | ||
123 | |||
124 | static void wdt_disable(void) | ||
125 | { | ||
126 | spin_lock(&io_lock); | ||
127 | |||
128 | __raw_writel(0, WDTIM_CTRL(wdt_base)); /*stop counter */ | ||
129 | if (wdt_clk) | ||
130 | clk_set_rate(wdt_clk, 0); | ||
131 | |||
132 | spin_unlock(&io_lock); | ||
133 | } | ||
134 | |||
135 | static int pnx4008_wdt_open(struct inode *inode, struct file *file) | ||
136 | { | ||
137 | if (test_and_set_bit(WDT_IN_USE, &wdt_status)) | ||
138 | return -EBUSY; | ||
139 | |||
140 | clear_bit(WDT_OK_TO_CLOSE, &wdt_status); | ||
141 | |||
142 | wdt_enable(); | ||
143 | |||
144 | return nonseekable_open(inode, file); | ||
145 | } | ||
146 | |||
147 | static ssize_t | ||
148 | pnx4008_wdt_write(struct file *file, const char *data, size_t len, | ||
149 | loff_t * ppos) | ||
150 | { | ||
151 | /* Can't seek (pwrite) on this device */ | ||
152 | if (ppos != &file->f_pos) | ||
153 | return -ESPIPE; | ||
154 | |||
155 | if (len) { | ||
156 | if (!nowayout) { | ||
157 | size_t i; | ||
158 | |||
159 | clear_bit(WDT_OK_TO_CLOSE, &wdt_status); | ||
160 | |||
161 | for (i = 0; i != len; i++) { | ||
162 | char c; | ||
163 | |||
164 | if (get_user(c, data + i)) | ||
165 | return -EFAULT; | ||
166 | if (c == 'V') | ||
167 | set_bit(WDT_OK_TO_CLOSE, &wdt_status); | ||
168 | } | ||
169 | } | ||
170 | wdt_enable(); | ||
171 | } | ||
172 | |||
173 | return len; | ||
174 | } | ||
175 | |||
176 | static struct watchdog_info ident = { | ||
177 | .options = WDIOF_CARDRESET | WDIOF_MAGICCLOSE | | ||
178 | WDIOF_SETTIMEOUT | WDIOF_KEEPALIVEPING, | ||
179 | .identity = "PNX4008 Watchdog", | ||
180 | }; | ||
181 | |||
182 | static int | ||
183 | pnx4008_wdt_ioctl(struct inode *inode, struct file *file, unsigned int cmd, | ||
184 | unsigned long arg) | ||
185 | { | ||
186 | int ret = -ENOTTY; | ||
187 | int time; | ||
188 | |||
189 | switch (cmd) { | ||
190 | case WDIOC_GETSUPPORT: | ||
191 | ret = copy_to_user((struct watchdog_info *)arg, &ident, | ||
192 | sizeof(ident)) ? -EFAULT : 0; | ||
193 | break; | ||
194 | |||
195 | case WDIOC_GETSTATUS: | ||
196 | ret = put_user(0, (int *)arg); | ||
197 | break; | ||
198 | |||
199 | case WDIOC_GETBOOTSTATUS: | ||
200 | ret = put_user(boot_status, (int *)arg); | ||
201 | break; | ||
202 | |||
203 | case WDIOC_SETTIMEOUT: | ||
204 | ret = get_user(time, (int *)arg); | ||
205 | if (ret) | ||
206 | break; | ||
207 | |||
208 | if (time <= 0 || time > MAX_HEARTBEAT) { | ||
209 | ret = -EINVAL; | ||
210 | break; | ||
211 | } | ||
212 | |||
213 | heartbeat = time; | ||
214 | wdt_enable(); | ||
215 | /* Fall through */ | ||
216 | |||
217 | case WDIOC_GETTIMEOUT: | ||
218 | ret = put_user(heartbeat, (int *)arg); | ||
219 | break; | ||
220 | |||
221 | case WDIOC_KEEPALIVE: | ||
222 | wdt_enable(); | ||
223 | ret = 0; | ||
224 | break; | ||
225 | } | ||
226 | return ret; | ||
227 | } | ||
228 | |||
229 | static int pnx4008_wdt_release(struct inode *inode, struct file *file) | ||
230 | { | ||
231 | if (!test_bit(WDT_OK_TO_CLOSE, &wdt_status)) | ||
232 | printk(KERN_WARNING "WATCHDOG: Device closed unexpectdly\n"); | ||
233 | |||
234 | wdt_disable(); | ||
235 | clear_bit(WDT_IN_USE, &wdt_status); | ||
236 | clear_bit(WDT_OK_TO_CLOSE, &wdt_status); | ||
237 | |||
238 | return 0; | ||
239 | } | ||
240 | |||
241 | static struct file_operations pnx4008_wdt_fops = { | ||
242 | .owner = THIS_MODULE, | ||
243 | .llseek = no_llseek, | ||
244 | .write = pnx4008_wdt_write, | ||
245 | .ioctl = pnx4008_wdt_ioctl, | ||
246 | .open = pnx4008_wdt_open, | ||
247 | .release = pnx4008_wdt_release, | ||
248 | }; | ||
249 | |||
250 | static struct miscdevice pnx4008_wdt_miscdev = { | ||
251 | .minor = WATCHDOG_MINOR, | ||
252 | .name = "watchdog", | ||
253 | .fops = &pnx4008_wdt_fops, | ||
254 | }; | ||
255 | |||
256 | static int pnx4008_wdt_probe(struct platform_device *pdev) | ||
257 | { | ||
258 | int ret = 0, size; | ||
259 | struct resource *res; | ||
260 | |||
261 | spin_lock_init(&io_lock); | ||
262 | |||
263 | if (heartbeat < 1 || heartbeat > MAX_HEARTBEAT) | ||
264 | heartbeat = DEFAULT_HEARTBEAT; | ||
265 | |||
266 | printk(KERN_INFO MODULE_NAME | ||
267 | "PNX4008 Watchdog Timer: heartbeat %d sec\n", heartbeat); | ||
268 | |||
269 | res = platform_get_resource(pdev, IORESOURCE_MEM, 0); | ||
270 | if (res == NULL) { | ||
271 | printk(KERN_INFO MODULE_NAME | ||
272 | "failed to get memory region resouce\n"); | ||
273 | return -ENOENT; | ||
274 | } | ||
275 | |||
276 | size = res->end - res->start + 1; | ||
277 | wdt_mem = request_mem_region(res->start, size, pdev->name); | ||
278 | |||
279 | if (wdt_mem == NULL) { | ||
280 | printk(KERN_INFO MODULE_NAME "failed to get memory region\n"); | ||
281 | return -ENOENT; | ||
282 | } | ||
283 | wdt_base = (void __iomem *)IO_ADDRESS(res->start); | ||
284 | |||
285 | wdt_clk = clk_get(&pdev->dev, "wdt_ck"); | ||
286 | if (!wdt_clk) { | ||
287 | release_resource(wdt_mem); | ||
288 | kfree(wdt_mem); | ||
289 | goto out; | ||
290 | } else | ||
291 | clk_set_rate(wdt_clk, 1); | ||
292 | |||
293 | ret = misc_register(&pnx4008_wdt_miscdev); | ||
294 | if (ret < 0) { | ||
295 | printk(KERN_ERR MODULE_NAME "cannot register misc device\n"); | ||
296 | release_resource(wdt_mem); | ||
297 | kfree(wdt_mem); | ||
298 | clk_set_rate(wdt_clk, 0); | ||
299 | } else { | ||
300 | boot_status = (__raw_readl(WDTIM_RES(wdt_base)) & WDOG_RESET) ? | ||
301 | WDIOF_CARDRESET : 0; | ||
302 | wdt_disable(); /*disable for now */ | ||
303 | set_bit(WDT_DEVICE_INITED, &wdt_status); | ||
304 | } | ||
305 | |||
306 | out: | ||
307 | return ret; | ||
308 | } | ||
309 | |||
310 | static int pnx4008_wdt_remove(struct platform_device *pdev) | ||
311 | { | ||
312 | misc_deregister(&pnx4008_wdt_miscdev); | ||
313 | if (wdt_clk) { | ||
314 | clk_set_rate(wdt_clk, 0); | ||
315 | clk_put(wdt_clk); | ||
316 | wdt_clk = NULL; | ||
317 | } | ||
318 | if (wdt_mem) { | ||
319 | release_resource(wdt_mem); | ||
320 | kfree(wdt_mem); | ||
321 | wdt_mem = NULL; | ||
322 | } | ||
323 | return 0; | ||
324 | } | ||
325 | |||
326 | static struct platform_driver platform_wdt_driver = { | ||
327 | .driver = { | ||
328 | .name = "watchdog", | ||
329 | }, | ||
330 | .probe = pnx4008_wdt_probe, | ||
331 | .remove = pnx4008_wdt_remove, | ||
332 | }; | ||
333 | |||
334 | static int __init pnx4008_wdt_init(void) | ||
335 | { | ||
336 | return platform_driver_register(&platform_wdt_driver); | ||
337 | } | ||
338 | |||
339 | static void __exit pnx4008_wdt_exit(void) | ||
340 | { | ||
341 | return platform_driver_unregister(&platform_wdt_driver); | ||
342 | } | ||
343 | |||
344 | module_init(pnx4008_wdt_init); | ||
345 | module_exit(pnx4008_wdt_exit); | ||
346 | |||
347 | MODULE_AUTHOR("MontaVista Software, Inc. <source@mvista.com>"); | ||
348 | MODULE_DESCRIPTION("PNX4008 Watchdog Driver"); | ||
349 | |||
350 | module_param(heartbeat, int, 0); | ||
351 | MODULE_PARM_DESC(heartbeat, | ||
352 | "Watchdog heartbeat period in seconds from 1 to " | ||
353 | __MODULE_STRING(MAX_HEARTBEAT) ", default " | ||
354 | __MODULE_STRING(DEFAULT_HEARTBEAT)); | ||
355 | |||
356 | module_param(nowayout, int, 0); | ||
357 | MODULE_PARM_DESC(nowayout, | ||
358 | "Set to 1 to keep watchdog running after device release"); | ||
359 | |||
360 | MODULE_LICENSE("GPL"); | ||
361 | MODULE_ALIAS_MISCDEV(WATCHDOG_MINOR); | ||
diff --git a/drivers/char/watchdog/rm9k_wdt.c b/drivers/char/watchdog/rm9k_wdt.c new file mode 100644 index 000000000000..ec3909371c21 --- /dev/null +++ b/drivers/char/watchdog/rm9k_wdt.c | |||
@@ -0,0 +1,420 @@ | |||
1 | /* | ||
2 | * Watchdog implementation for GPI h/w found on PMC-Sierra RM9xxx | ||
3 | * chips. | ||
4 | * | ||
5 | * Copyright (C) 2004 by Basler Vision Technologies AG | ||
6 | * Author: Thomas Koeller <thomas.koeller@baslerweb.com> | ||
7 | * | ||
8 | * This program is free software; you can redistribute it and/or modify | ||
9 | * it under the terms of the GNU General Public License as published by | ||
10 | * the Free Software Foundation; either version 2 of the License, or | ||
11 | * (at your option) any later version. | ||
12 | * | ||
13 | * This program is distributed in the hope that it will be useful, | ||
14 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
16 | * GNU General Public License for more details. | ||
17 | * | ||
18 | * You should have received a copy of the GNU General Public License | ||
19 | * along with this program; if not, write to the Free Software | ||
20 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
21 | */ | ||
22 | |||
23 | #include <linux/platform_device.h> | ||
24 | #include <linux/module.h> | ||
25 | #include <linux/moduleparam.h> | ||
26 | #include <linux/interrupt.h> | ||
27 | #include <linux/fs.h> | ||
28 | #include <linux/reboot.h> | ||
29 | #include <linux/notifier.h> | ||
30 | #include <linux/miscdevice.h> | ||
31 | #include <linux/watchdog.h> | ||
32 | #include <asm/io.h> | ||
33 | #include <asm/atomic.h> | ||
34 | #include <asm/processor.h> | ||
35 | #include <asm/uaccess.h> | ||
36 | #include <asm/system.h> | ||
37 | #include <asm/rm9k-ocd.h> | ||
38 | |||
39 | #include <rm9k_wdt.h> | ||
40 | |||
41 | |||
42 | #define CLOCK 125000000 | ||
43 | #define MAX_TIMEOUT_SECONDS 32 | ||
44 | #define CPCCR 0x0080 | ||
45 | #define CPGIG1SR 0x0044 | ||
46 | #define CPGIG1ER 0x0054 | ||
47 | |||
48 | |||
49 | /* Function prototypes */ | ||
50 | static irqreturn_t wdt_gpi_irqhdl(int, void *, struct pt_regs *); | ||
51 | static void wdt_gpi_start(void); | ||
52 | static void wdt_gpi_stop(void); | ||
53 | static void wdt_gpi_set_timeout(unsigned int); | ||
54 | static int wdt_gpi_open(struct inode *, struct file *); | ||
55 | static int wdt_gpi_release(struct inode *, struct file *); | ||
56 | static ssize_t wdt_gpi_write(struct file *, const char __user *, size_t, loff_t *); | ||
57 | static long wdt_gpi_ioctl(struct file *, unsigned int, unsigned long); | ||
58 | static int wdt_gpi_notify(struct notifier_block *, unsigned long, void *); | ||
59 | static const struct resource *wdt_gpi_get_resource(struct platform_device *, const char *, unsigned int); | ||
60 | static int __init wdt_gpi_probe(struct device *); | ||
61 | static int __exit wdt_gpi_remove(struct device *); | ||
62 | |||
63 | |||
64 | static const char wdt_gpi_name[] = "wdt_gpi"; | ||
65 | static atomic_t opencnt; | ||
66 | static int expect_close; | ||
67 | static int locked; | ||
68 | |||
69 | |||
70 | /* These are set from device resources */ | ||
71 | static void __iomem * wd_regs; | ||
72 | static unsigned int wd_irq, wd_ctr; | ||
73 | |||
74 | |||
75 | /* Module arguments */ | ||
76 | static int timeout = MAX_TIMEOUT_SECONDS; | ||
77 | module_param(timeout, int, 0444); | ||
78 | MODULE_PARM_DESC(timeout, "Watchdog timeout in seconds"); | ||
79 | |||
80 | static unsigned long resetaddr = 0xbffdc200; | ||
81 | module_param(resetaddr, ulong, 0444); | ||
82 | MODULE_PARM_DESC(resetaddr, "Address to write to to force a reset"); | ||
83 | |||
84 | static unsigned long flagaddr = 0xbffdc104; | ||
85 | module_param(flagaddr, ulong, 0444); | ||
86 | MODULE_PARM_DESC(flagaddr, "Address to write to boot flags to"); | ||
87 | |||
88 | static int powercycle; | ||
89 | module_param(powercycle, bool, 0444); | ||
90 | MODULE_PARM_DESC(powercycle, "Cycle power if watchdog expires"); | ||
91 | |||
92 | static int nowayout = WATCHDOG_NOWAYOUT; | ||
93 | module_param(nowayout, bool, 0444); | ||
94 | MODULE_PARM_DESC(nowayout, "Watchdog cannot be disabled once started"); | ||
95 | |||
96 | |||
97 | /* Interrupt handler */ | ||
98 | static irqreturn_t wdt_gpi_irqhdl(int irq, void *ctxt, struct pt_regs *regs) | ||
99 | { | ||
100 | if (!unlikely(__raw_readl(wd_regs + 0x0008) & 0x1)) | ||
101 | return IRQ_NONE; | ||
102 | __raw_writel(0x1, wd_regs + 0x0008); | ||
103 | |||
104 | |||
105 | printk(KERN_CRIT "%s: watchdog expired - resetting system\n", | ||
106 | wdt_gpi_name); | ||
107 | |||
108 | *(volatile char *) flagaddr |= 0x01; | ||
109 | *(volatile char *) resetaddr = powercycle ? 0x01 : 0x2; | ||
110 | iob(); | ||
111 | while (1) | ||
112 | cpu_relax(); | ||
113 | } | ||
114 | |||
115 | |||
116 | /* Watchdog functions */ | ||
117 | static void wdt_gpi_start(void) | ||
118 | { | ||
119 | u32 reg; | ||
120 | |||
121 | lock_titan_regs(); | ||
122 | reg = titan_readl(CPGIG1ER); | ||
123 | titan_writel(reg | (0x100 << wd_ctr), CPGIG1ER); | ||
124 | iob(); | ||
125 | unlock_titan_regs(); | ||
126 | } | ||
127 | |||
128 | static void wdt_gpi_stop(void) | ||
129 | { | ||
130 | u32 reg; | ||
131 | |||
132 | lock_titan_regs(); | ||
133 | reg = titan_readl(CPCCR) & ~(0xf << (wd_ctr * 4)); | ||
134 | titan_writel(reg, CPCCR); | ||
135 | reg = titan_readl(CPGIG1ER); | ||
136 | titan_writel(reg & ~(0x100 << wd_ctr), CPGIG1ER); | ||
137 | iob(); | ||
138 | unlock_titan_regs(); | ||
139 | } | ||
140 | |||
141 | static void wdt_gpi_set_timeout(unsigned int to) | ||
142 | { | ||
143 | u32 reg; | ||
144 | const u32 wdval = (to * CLOCK) & ~0x0000000f; | ||
145 | |||
146 | lock_titan_regs(); | ||
147 | reg = titan_readl(CPCCR) & ~(0xf << (wd_ctr * 4)); | ||
148 | titan_writel(reg, CPCCR); | ||
149 | wmb(); | ||
150 | __raw_writel(wdval, wd_regs + 0x0000); | ||
151 | wmb(); | ||
152 | titan_writel(reg | (0x2 << (wd_ctr * 4)), CPCCR); | ||
153 | wmb(); | ||
154 | titan_writel(reg | (0x5 << (wd_ctr * 4)), CPCCR); | ||
155 | iob(); | ||
156 | unlock_titan_regs(); | ||
157 | } | ||
158 | |||
159 | |||
160 | /* /dev/watchdog operations */ | ||
161 | static int wdt_gpi_open(struct inode *inode, struct file *file) | ||
162 | { | ||
163 | int res; | ||
164 | |||
165 | if (unlikely(atomic_dec_if_positive(&opencnt) < 0)) | ||
166 | return -EBUSY; | ||
167 | |||
168 | expect_close = 0; | ||
169 | if (locked) { | ||
170 | module_put(THIS_MODULE); | ||
171 | free_irq(wd_irq, &miscdev); | ||
172 | locked = 0; | ||
173 | } | ||
174 | |||
175 | res = request_irq(wd_irq, wdt_gpi_irqhdl, SA_SHIRQ | SA_INTERRUPT, | ||
176 | wdt_gpi_name, &miscdev); | ||
177 | if (unlikely(res)) | ||
178 | return res; | ||
179 | |||
180 | wdt_gpi_set_timeout(timeout); | ||
181 | wdt_gpi_start(); | ||
182 | |||
183 | printk(KERN_INFO "%s: watchdog started, timeout = %u seconds\n", | ||
184 | wdt_gpi_name, timeout); | ||
185 | return nonseekable_open(inode, file); | ||
186 | } | ||
187 | |||
188 | static int wdt_gpi_release(struct inode *inode, struct file *file) | ||
189 | { | ||
190 | if (nowayout) { | ||
191 | printk(KERN_INFO "%s: no way out - watchdog left running\n", | ||
192 | wdt_gpi_name); | ||
193 | __module_get(THIS_MODULE); | ||
194 | locked = 1; | ||
195 | } else { | ||
196 | if (expect_close) { | ||
197 | wdt_gpi_stop(); | ||
198 | free_irq(wd_irq, &miscdev); | ||
199 | printk(KERN_INFO "%s: watchdog stopped\n", wdt_gpi_name); | ||
200 | } else { | ||
201 | printk(KERN_CRIT "%s: unexpected close() -" | ||
202 | " watchdog left running\n", | ||
203 | wdt_gpi_name); | ||
204 | wdt_gpi_set_timeout(timeout); | ||
205 | __module_get(THIS_MODULE); | ||
206 | locked = 1; | ||
207 | } | ||
208 | } | ||
209 | |||
210 | atomic_inc(&opencnt); | ||
211 | return 0; | ||
212 | } | ||
213 | |||
214 | static ssize_t | ||
215 | wdt_gpi_write(struct file *f, const char __user *d, size_t s, loff_t *o) | ||
216 | { | ||
217 | char val; | ||
218 | |||
219 | wdt_gpi_set_timeout(timeout); | ||
220 | expect_close = (s > 0) && !get_user(val, d) && (val == 'V'); | ||
221 | return s ? 1 : 0; | ||
222 | } | ||
223 | |||
224 | static long | ||
225 | wdt_gpi_ioctl(struct file *f, unsigned int cmd, unsigned long arg) | ||
226 | { | ||
227 | long res = -ENOTTY; | ||
228 | const long size = _IOC_SIZE(cmd); | ||
229 | int stat; | ||
230 | void __user *argp = (void __user *)arg; | ||
231 | static struct watchdog_info wdinfo = { | ||
232 | .identity = "RM9xxx/GPI watchdog", | ||
233 | .firmware_version = 0, | ||
234 | .options = WDIOF_SETTIMEOUT | WDIOF_KEEPALIVEPING | ||
235 | }; | ||
236 | |||
237 | if (unlikely(_IOC_TYPE(cmd) != WATCHDOG_IOCTL_BASE)) | ||
238 | return -ENOTTY; | ||
239 | |||
240 | if ((_IOC_DIR(cmd) & _IOC_READ) | ||
241 | && !access_ok(VERIFY_WRITE, arg, size)) | ||
242 | return -EFAULT; | ||
243 | |||
244 | if ((_IOC_DIR(cmd) & _IOC_WRITE) | ||
245 | && !access_ok(VERIFY_READ, arg, size)) | ||
246 | return -EFAULT; | ||
247 | |||
248 | expect_close = 0; | ||
249 | |||
250 | switch (cmd) { | ||
251 | case WDIOC_GETSUPPORT: | ||
252 | wdinfo.options = nowayout ? | ||
253 | WDIOF_SETTIMEOUT | WDIOF_KEEPALIVEPING : | ||
254 | WDIOF_SETTIMEOUT | WDIOF_KEEPALIVEPING | WDIOF_MAGICCLOSE; | ||
255 | res = __copy_to_user(argp, &wdinfo, size) ? -EFAULT : size; | ||
256 | break; | ||
257 | |||
258 | case WDIOC_GETSTATUS: | ||
259 | break; | ||
260 | |||
261 | case WDIOC_GETBOOTSTATUS: | ||
262 | stat = (*(volatile char *) flagaddr & 0x01) | ||
263 | ? WDIOF_CARDRESET : 0; | ||
264 | res = __copy_to_user(argp, &stat, size) ? | ||
265 | -EFAULT : size; | ||
266 | break; | ||
267 | |||
268 | case WDIOC_SETOPTIONS: | ||
269 | break; | ||
270 | |||
271 | case WDIOC_KEEPALIVE: | ||
272 | wdt_gpi_set_timeout(timeout); | ||
273 | res = size; | ||
274 | break; | ||
275 | |||
276 | case WDIOC_SETTIMEOUT: | ||
277 | { | ||
278 | int val; | ||
279 | if (unlikely(__copy_from_user(&val, argp, size))) { | ||
280 | res = -EFAULT; | ||
281 | break; | ||
282 | } | ||
283 | |||
284 | if (val > MAX_TIMEOUT_SECONDS) | ||
285 | val = MAX_TIMEOUT_SECONDS; | ||
286 | timeout = val; | ||
287 | wdt_gpi_set_timeout(val); | ||
288 | res = size; | ||
289 | printk(KERN_INFO "%s: timeout set to %u seconds\n", | ||
290 | wdt_gpi_name, timeout); | ||
291 | } | ||
292 | break; | ||
293 | |||
294 | case WDIOC_GETTIMEOUT: | ||
295 | res = __copy_to_user(argp, &timeout, size) ? | ||
296 | -EFAULT : size; | ||
297 | break; | ||
298 | } | ||
299 | |||
300 | return res; | ||
301 | } | ||
302 | |||
303 | |||
304 | /* Shutdown notifier */ | ||
305 | static int | ||
306 | wdt_gpi_notify(struct notifier_block *this, unsigned long code, void *unused) | ||
307 | { | ||
308 | if (code == SYS_DOWN || code == SYS_HALT) | ||
309 | wdt_gpi_stop(); | ||
310 | |||
311 | return NOTIFY_DONE; | ||
312 | } | ||
313 | |||
314 | |||
315 | /* Kernel interfaces */ | ||
316 | static struct file_operations fops = { | ||
317 | .owner = THIS_MODULE, | ||
318 | .open = wdt_gpi_open, | ||
319 | .release = wdt_gpi_release, | ||
320 | .write = wdt_gpi_write, | ||
321 | .unlocked_ioctl = wdt_gpi_ioctl, | ||
322 | }; | ||
323 | |||
324 | static struct miscdevice miscdev = { | ||
325 | .minor = WATCHDOG_MINOR, | ||
326 | .name = wdt_gpi_name, | ||
327 | .fops = &fops, | ||
328 | }; | ||
329 | |||
330 | static struct notifier_block wdt_gpi_shutdown = { | ||
331 | .notifier_call = wdt_gpi_notify, | ||
332 | }; | ||
333 | |||
334 | |||
335 | /* Init & exit procedures */ | ||
336 | static const struct resource * | ||
337 | wdt_gpi_get_resource(struct platform_device *pdv, const char *name, | ||
338 | unsigned int type) | ||
339 | { | ||
340 | char buf[80]; | ||
341 | if (snprintf(buf, sizeof buf, "%s_0", name) >= sizeof buf) | ||
342 | return NULL; | ||
343 | return platform_get_resource_byname(pdv, type, buf); | ||
344 | } | ||
345 | |||
346 | /* No hotplugging on the platform bus - use __init */ | ||
347 | static int __init wdt_gpi_probe(struct device *dev) | ||
348 | { | ||
349 | int res; | ||
350 | struct platform_device * const pdv = to_platform_device(dev); | ||
351 | const struct resource | ||
352 | * const rr = wdt_gpi_get_resource(pdv, WDT_RESOURCE_REGS, | ||
353 | IORESOURCE_MEM), | ||
354 | * const ri = wdt_gpi_get_resource(pdv, WDT_RESOURCE_IRQ, | ||
355 | IORESOURCE_IRQ), | ||
356 | * const rc = wdt_gpi_get_resource(pdv, WDT_RESOURCE_COUNTER, | ||
357 | 0); | ||
358 | |||
359 | if (unlikely(!rr || !ri || !rc)) | ||
360 | return -ENXIO; | ||
361 | |||
362 | wd_regs = ioremap_nocache(rr->start, rr->end + 1 - rr->start); | ||
363 | if (unlikely(!wd_regs)) | ||
364 | return -ENOMEM; | ||
365 | wd_irq = ri->start; | ||
366 | wd_ctr = rc->start; | ||
367 | res = misc_register(&miscdev); | ||
368 | if (res) | ||
369 | iounmap(wd_regs); | ||
370 | else | ||
371 | register_reboot_notifier(&wdt_gpi_shutdown); | ||
372 | return res; | ||
373 | } | ||
374 | |||
375 | static int __exit wdt_gpi_remove(struct device *dev) | ||
376 | { | ||
377 | int res; | ||
378 | |||
379 | unregister_reboot_notifier(&wdt_gpi_shutdown); | ||
380 | res = misc_deregister(&miscdev); | ||
381 | iounmap(wd_regs); | ||
382 | wd_regs = NULL; | ||
383 | return res; | ||
384 | } | ||
385 | |||
386 | |||
387 | /* Device driver init & exit */ | ||
388 | static struct device_driver wdt_gpi_driver = { | ||
389 | .name = (char *) wdt_gpi_name, | ||
390 | .bus = &platform_bus_type, | ||
391 | .owner = THIS_MODULE, | ||
392 | .probe = wdt_gpi_probe, | ||
393 | .remove = __exit_p(wdt_gpi_remove), | ||
394 | .shutdown = NULL, | ||
395 | .suspend = NULL, | ||
396 | .resume = NULL, | ||
397 | }; | ||
398 | |||
399 | static int __init wdt_gpi_init_module(void) | ||
400 | { | ||
401 | atomic_set(&opencnt, 1); | ||
402 | if (timeout > MAX_TIMEOUT_SECONDS) | ||
403 | timeout = MAX_TIMEOUT_SECONDS; | ||
404 | return driver_register(&wdt_gpi_driver); | ||
405 | } | ||
406 | |||
407 | static void __exit wdt_gpi_cleanup_module(void) | ||
408 | { | ||
409 | driver_unregister(&wdt_gpi_driver); | ||
410 | } | ||
411 | |||
412 | module_init(wdt_gpi_init_module); | ||
413 | module_exit(wdt_gpi_cleanup_module); | ||
414 | |||
415 | MODULE_AUTHOR("Thomas Koeller <thomas.koeller@baslerweb.com>"); | ||
416 | MODULE_DESCRIPTION("Basler eXcite watchdog driver for gpi devices"); | ||
417 | MODULE_VERSION("0.1"); | ||
418 | MODULE_LICENSE("GPL"); | ||
419 | MODULE_ALIAS_MISCDEV(WATCHDOG_MINOR); | ||
420 | |||
diff --git a/drivers/char/watchdog/s3c2410_wdt.c b/drivers/char/watchdog/s3c2410_wdt.c index be978e8ed754..18cb050c3862 100644 --- a/drivers/char/watchdog/s3c2410_wdt.c +++ b/drivers/char/watchdog/s3c2410_wdt.c | |||
@@ -62,7 +62,7 @@ | |||
62 | #define CONFIG_S3C2410_WATCHDOG_ATBOOT (0) | 62 | #define CONFIG_S3C2410_WATCHDOG_ATBOOT (0) |
63 | #define CONFIG_S3C2410_WATCHDOG_DEFAULT_TIME (15) | 63 | #define CONFIG_S3C2410_WATCHDOG_DEFAULT_TIME (15) |
64 | 64 | ||
65 | static int nowayout = WATCHDOG_NOWAYOUT; | 65 | static int nowayout = WATCHDOG_NOWAYOUT; |
66 | static int tmr_margin = CONFIG_S3C2410_WATCHDOG_DEFAULT_TIME; | 66 | static int tmr_margin = CONFIG_S3C2410_WATCHDOG_DEFAULT_TIME; |
67 | static int tmr_atboot = CONFIG_S3C2410_WATCHDOG_ATBOOT; | 67 | static int tmr_atboot = CONFIG_S3C2410_WATCHDOG_ATBOOT; |
68 | static int soft_noboot = 0; | 68 | static int soft_noboot = 0; |
@@ -213,11 +213,10 @@ static int s3c2410wdt_open(struct inode *inode, struct file *file) | |||
213 | if(down_trylock(&open_lock)) | 213 | if(down_trylock(&open_lock)) |
214 | return -EBUSY; | 214 | return -EBUSY; |
215 | 215 | ||
216 | if (nowayout) { | 216 | if (nowayout) |
217 | __module_get(THIS_MODULE); | 217 | __module_get(THIS_MODULE); |
218 | } else { | 218 | |
219 | allow_close = CLOSE_STATE_ALLOW; | 219 | allow_close = CLOSE_STATE_NOT; |
220 | } | ||
221 | 220 | ||
222 | /* start the timer */ | 221 | /* start the timer */ |
223 | s3c2410wdt_start(); | 222 | s3c2410wdt_start(); |
@@ -230,6 +229,7 @@ static int s3c2410wdt_release(struct inode *inode, struct file *file) | |||
230 | * Shut off the timer. | 229 | * Shut off the timer. |
231 | * Lock it in if it's a module and we set nowayout | 230 | * Lock it in if it's a module and we set nowayout |
232 | */ | 231 | */ |
232 | |||
233 | if (allow_close == CLOSE_STATE_ALLOW) { | 233 | if (allow_close == CLOSE_STATE_ALLOW) { |
234 | s3c2410wdt_stop(); | 234 | s3c2410wdt_stop(); |
235 | } else { | 235 | } else { |
@@ -288,7 +288,7 @@ static int s3c2410wdt_ioctl(struct inode *inode, struct file *file, | |||
288 | 288 | ||
289 | switch (cmd) { | 289 | switch (cmd) { |
290 | default: | 290 | default: |
291 | return -ENOIOCTLCMD; | 291 | return -ENOTTY; |
292 | 292 | ||
293 | case WDIOC_GETSUPPORT: | 293 | case WDIOC_GETSUPPORT: |
294 | return copy_to_user(argp, &s3c2410_wdt_ident, | 294 | return copy_to_user(argp, &s3c2410_wdt_ident, |
@@ -336,8 +336,7 @@ static struct miscdevice s3c2410wdt_miscdev = { | |||
336 | 336 | ||
337 | /* interrupt handler code */ | 337 | /* interrupt handler code */ |
338 | 338 | ||
339 | static irqreturn_t s3c2410wdt_irq(int irqno, void *param, | 339 | static irqreturn_t s3c2410wdt_irq(int irqno, void *param) |
340 | struct pt_regs *regs) | ||
341 | { | 340 | { |
342 | printk(KERN_INFO PFX "Watchdog timer expired!\n"); | 341 | printk(KERN_INFO PFX "Watchdog timer expired!\n"); |
343 | 342 | ||
@@ -381,18 +380,21 @@ static int s3c2410wdt_probe(struct platform_device *pdev) | |||
381 | res = platform_get_resource(pdev, IORESOURCE_IRQ, 0); | 380 | res = platform_get_resource(pdev, IORESOURCE_IRQ, 0); |
382 | if (res == NULL) { | 381 | if (res == NULL) { |
383 | 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); | ||
384 | return -ENOENT; | 384 | return -ENOENT; |
385 | } | 385 | } |
386 | 386 | ||
387 | ret = request_irq(res->start, s3c2410wdt_irq, 0, pdev->name, pdev); | 387 | ret = request_irq(res->start, s3c2410wdt_irq, 0, pdev->name, pdev); |
388 | if (ret != 0) { | 388 | if (ret != 0) { |
389 | 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); | ||
390 | return ret; | 391 | return ret; |
391 | } | 392 | } |
392 | 393 | ||
393 | wdt_clock = clk_get(&pdev->dev, "watchdog"); | 394 | wdt_clock = clk_get(&pdev->dev, "watchdog"); |
394 | if (wdt_clock == NULL) { | 395 | if (wdt_clock == NULL) { |
395 | 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); | ||
396 | return -ENOENT; | 398 | return -ENOENT; |
397 | } | 399 | } |
398 | 400 | ||
@@ -416,6 +418,7 @@ static int s3c2410wdt_probe(struct platform_device *pdev) | |||
416 | if (ret) { | 418 | if (ret) { |
417 | 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", |
418 | WATCHDOG_MINOR, ret); | 420 | WATCHDOG_MINOR, ret); |
421 | iounmap(wdt_base); | ||
419 | return ret; | 422 | return ret; |
420 | } | 423 | } |
421 | 424 | ||
@@ -452,6 +455,7 @@ static int s3c2410wdt_remove(struct platform_device *dev) | |||
452 | wdt_clock = NULL; | 455 | wdt_clock = NULL; |
453 | } | 456 | } |
454 | 457 | ||
458 | iounmap(wdt_base); | ||
455 | misc_deregister(&s3c2410wdt_miscdev); | 459 | misc_deregister(&s3c2410wdt_miscdev); |
456 | return 0; | 460 | return 0; |
457 | } | 461 | } |
diff --git a/drivers/char/watchdog/sa1100_wdt.c b/drivers/char/watchdog/sa1100_wdt.c index 1fc16d995788..33c1137f17d6 100644 --- a/drivers/char/watchdog/sa1100_wdt.c +++ b/drivers/char/watchdog/sa1100_wdt.c | |||
@@ -90,7 +90,7 @@ static struct watchdog_info ident = { | |||
90 | static int sa1100dog_ioctl(struct inode *inode, struct file *file, | 90 | static int sa1100dog_ioctl(struct inode *inode, struct file *file, |
91 | unsigned int cmd, unsigned long arg) | 91 | unsigned int cmd, unsigned long arg) |
92 | { | 92 | { |
93 | int ret = -ENOIOCTLCMD; | 93 | int ret = -ENOTTY; |
94 | int time; | 94 | int time; |
95 | void __user *argp = (void __user *)arg; | 95 | void __user *argp = (void __user *)arg; |
96 | int __user *p = argp; | 96 | int __user *p = argp; |
diff --git a/drivers/char/watchdog/sbc60xxwdt.c b/drivers/char/watchdog/sbc60xxwdt.c index 4663c2fd53cd..c7b2045bc76b 100644 --- a/drivers/char/watchdog/sbc60xxwdt.c +++ b/drivers/char/watchdog/sbc60xxwdt.c | |||
@@ -235,7 +235,7 @@ static int fop_ioctl(struct inode *inode, struct file *file, unsigned int cmd, | |||
235 | switch(cmd) | 235 | switch(cmd) |
236 | { | 236 | { |
237 | default: | 237 | default: |
238 | return -ENOIOCTLCMD; | 238 | return -ENOTTY; |
239 | case WDIOC_GETSUPPORT: | 239 | case WDIOC_GETSUPPORT: |
240 | return copy_to_user(argp, &ident, sizeof(ident))?-EFAULT:0; | 240 | return copy_to_user(argp, &ident, sizeof(ident))?-EFAULT:0; |
241 | case WDIOC_GETSTATUS: | 241 | case WDIOC_GETSTATUS: |
diff --git a/drivers/char/watchdog/sbc_epx_c3.c b/drivers/char/watchdog/sbc_epx_c3.c index bfc475dabe6d..8882b427d24f 100644 --- a/drivers/char/watchdog/sbc_epx_c3.c +++ b/drivers/char/watchdog/sbc_epx_c3.c | |||
@@ -141,7 +141,7 @@ static int epx_c3_ioctl(struct inode *inode, struct file *file, | |||
141 | 141 | ||
142 | return retval; | 142 | return retval; |
143 | default: | 143 | default: |
144 | return -ENOIOCTLCMD; | 144 | return -ENOTTY; |
145 | } | 145 | } |
146 | } | 146 | } |
147 | 147 | ||
diff --git a/drivers/char/watchdog/sc1200wdt.c b/drivers/char/watchdog/sc1200wdt.c index 7c3cf293a5af..e3239833e4b0 100644 --- a/drivers/char/watchdog/sc1200wdt.c +++ b/drivers/char/watchdog/sc1200wdt.c | |||
@@ -180,7 +180,7 @@ static int sc1200wdt_ioctl(struct inode *inode, struct file *file, unsigned int | |||
180 | 180 | ||
181 | switch (cmd) { | 181 | switch (cmd) { |
182 | default: | 182 | default: |
183 | return -ENOIOCTLCMD; /* Keep Pavel Machek amused ;) */ | 183 | return -ENOTTY; |
184 | 184 | ||
185 | case WDIOC_GETSUPPORT: | 185 | case WDIOC_GETSUPPORT: |
186 | if (copy_to_user(argp, &ident, sizeof ident)) | 186 | if (copy_to_user(argp, &ident, sizeof ident)) |
@@ -392,7 +392,7 @@ static int __init sc1200wdt_init(void) | |||
392 | if (io == -1) { | 392 | if (io == -1) { |
393 | printk(KERN_ERR PFX "io parameter must be specified\n"); | 393 | printk(KERN_ERR PFX "io parameter must be specified\n"); |
394 | ret = -EINVAL; | 394 | ret = -EINVAL; |
395 | goto out_clean; | 395 | goto out_pnp; |
396 | } | 396 | } |
397 | 397 | ||
398 | #if defined CONFIG_PNP | 398 | #if defined CONFIG_PNP |
@@ -405,7 +405,7 @@ static int __init sc1200wdt_init(void) | |||
405 | if (!request_region(io, io_len, SC1200_MODULE_NAME)) { | 405 | if (!request_region(io, io_len, SC1200_MODULE_NAME)) { |
406 | printk(KERN_ERR PFX "Unable to register IO port %#x\n", io); | 406 | printk(KERN_ERR PFX "Unable to register IO port %#x\n", io); |
407 | ret = -EBUSY; | 407 | ret = -EBUSY; |
408 | goto out_clean; | 408 | goto out_pnp; |
409 | } | 409 | } |
410 | 410 | ||
411 | ret = sc1200wdt_probe(); | 411 | ret = sc1200wdt_probe(); |
@@ -435,6 +435,11 @@ out_rbt: | |||
435 | out_io: | 435 | out_io: |
436 | release_region(io, io_len); | 436 | release_region(io, io_len); |
437 | 437 | ||
438 | out_pnp: | ||
439 | #if defined CONFIG_PNP | ||
440 | if (isapnp) | ||
441 | pnp_unregister_driver(&scl200wdt_pnp_driver); | ||
442 | #endif | ||
438 | goto out_clean; | 443 | goto out_clean; |
439 | } | 444 | } |
440 | 445 | ||
diff --git a/drivers/char/watchdog/sc520_wdt.c b/drivers/char/watchdog/sc520_wdt.c index 2c7c9db71be8..caec37ba750a 100644 --- a/drivers/char/watchdog/sc520_wdt.c +++ b/drivers/char/watchdog/sc520_wdt.c | |||
@@ -290,7 +290,7 @@ static int fop_ioctl(struct inode *inode, struct file *file, unsigned int cmd, | |||
290 | switch(cmd) | 290 | switch(cmd) |
291 | { | 291 | { |
292 | default: | 292 | default: |
293 | return -ENOIOCTLCMD; | 293 | return -ENOTTY; |
294 | case WDIOC_GETSUPPORT: | 294 | case WDIOC_GETSUPPORT: |
295 | return copy_to_user(argp, &ident, sizeof(ident))?-EFAULT:0; | 295 | return copy_to_user(argp, &ident, sizeof(ident))?-EFAULT:0; |
296 | case WDIOC_GETSTATUS: | 296 | case WDIOC_GETSTATUS: |
diff --git a/drivers/char/watchdog/scx200_wdt.c b/drivers/char/watchdog/scx200_wdt.c index c561299a5537..fc0e0347f9d2 100644 --- a/drivers/char/watchdog/scx200_wdt.c +++ b/drivers/char/watchdog/scx200_wdt.c | |||
@@ -166,7 +166,7 @@ static int scx200_wdt_ioctl(struct inode *inode, struct file *file, | |||
166 | 166 | ||
167 | switch (cmd) { | 167 | switch (cmd) { |
168 | default: | 168 | default: |
169 | return -ENOIOCTLCMD; | 169 | return -ENOTTY; |
170 | case WDIOC_GETSUPPORT: | 170 | case WDIOC_GETSUPPORT: |
171 | if(copy_to_user(argp, &ident, sizeof(ident))) | 171 | if(copy_to_user(argp, &ident, sizeof(ident))) |
172 | return -EFAULT; | 172 | return -EFAULT; |
diff --git a/drivers/char/watchdog/shwdt.c b/drivers/char/watchdog/shwdt.c index 1355038f1044..dc403629aeb3 100644 --- a/drivers/char/watchdog/shwdt.c +++ b/drivers/char/watchdog/shwdt.c | |||
@@ -27,7 +27,7 @@ | |||
27 | #include <linux/notifier.h> | 27 | #include <linux/notifier.h> |
28 | #include <linux/ioport.h> | 28 | #include <linux/ioport.h> |
29 | #include <linux/fs.h> | 29 | #include <linux/fs.h> |
30 | 30 | #include <linux/mm.h> | |
31 | #include <asm/io.h> | 31 | #include <asm/io.h> |
32 | #include <asm/uaccess.h> | 32 | #include <asm/uaccess.h> |
33 | #include <asm/watchdog.h> | 33 | #include <asm/watchdog.h> |
@@ -125,7 +125,6 @@ static void sh_wdt_start(void) | |||
125 | 125 | ||
126 | /** | 126 | /** |
127 | * sh_wdt_stop - Stop the Watchdog | 127 | * sh_wdt_stop - Stop the Watchdog |
128 | * | ||
129 | * Stops the watchdog. | 128 | * Stops the watchdog. |
130 | */ | 129 | */ |
131 | static void sh_wdt_stop(void) | 130 | static void sh_wdt_stop(void) |
@@ -141,22 +140,20 @@ static void sh_wdt_stop(void) | |||
141 | 140 | ||
142 | /** | 141 | /** |
143 | * sh_wdt_keepalive - Keep the Userspace Watchdog Alive | 142 | * sh_wdt_keepalive - Keep the Userspace Watchdog Alive |
144 | * | ||
145 | * The Userspace watchdog got a KeepAlive: schedule the next heartbeat. | 143 | * The Userspace watchdog got a KeepAlive: schedule the next heartbeat. |
146 | */ | 144 | */ |
147 | static void sh_wdt_keepalive(void) | 145 | static inline void sh_wdt_keepalive(void) |
148 | { | 146 | { |
149 | next_heartbeat = jiffies + (heartbeat * HZ); | 147 | next_heartbeat = jiffies + (heartbeat * HZ); |
150 | } | 148 | } |
151 | 149 | ||
152 | /** | 150 | /** |
153 | * sh_wdt_set_heartbeat - Set the Userspace Watchdog heartbeat | 151 | * sh_wdt_set_heartbeat - Set the Userspace Watchdog heartbeat |
154 | * | ||
155 | * Set the Userspace Watchdog heartbeat | 152 | * Set the Userspace Watchdog heartbeat |
156 | */ | 153 | */ |
157 | static int sh_wdt_set_heartbeat(int t) | 154 | static int sh_wdt_set_heartbeat(int t) |
158 | { | 155 | { |
159 | if ((t < 1) || (t > 3600)) /* arbitrary upper limit */ | 156 | if (unlikely((t < 1) || (t > 3600))) /* arbitrary upper limit */ |
160 | return -EINVAL; | 157 | return -EINVAL; |
161 | 158 | ||
162 | heartbeat = t; | 159 | heartbeat = t; |
@@ -165,7 +162,6 @@ static int sh_wdt_set_heartbeat(int t) | |||
165 | 162 | ||
166 | /** | 163 | /** |
167 | * sh_wdt_ping - Ping the Watchdog | 164 | * sh_wdt_ping - Ping the Watchdog |
168 | * | ||
169 | * @data: Unused | 165 | * @data: Unused |
170 | * | 166 | * |
171 | * Clears overflow bit, resets timer counter. | 167 | * Clears overflow bit, resets timer counter. |
@@ -182,14 +178,13 @@ static void sh_wdt_ping(unsigned long data) | |||
182 | sh_wdt_write_cnt(0); | 178 | sh_wdt_write_cnt(0); |
183 | 179 | ||
184 | mod_timer(&timer, next_ping_period(clock_division_ratio)); | 180 | mod_timer(&timer, next_ping_period(clock_division_ratio)); |
185 | } else { | 181 | } else |
186 | printk(KERN_WARNING PFX "Heartbeat lost! Will not ping the watchdog\n"); | 182 | printk(KERN_WARNING PFX "Heartbeat lost! Will not ping " |
187 | } | 183 | "the watchdog\n"); |
188 | } | 184 | } |
189 | 185 | ||
190 | /** | 186 | /** |
191 | * sh_wdt_open - Open the Device | 187 | * sh_wdt_open - Open the Device |
192 | * | ||
193 | * @inode: inode of device | 188 | * @inode: inode of device |
194 | * @file: file handle of device | 189 | * @file: file handle of device |
195 | * | 190 | * |
@@ -209,7 +204,6 @@ static int sh_wdt_open(struct inode *inode, struct file *file) | |||
209 | 204 | ||
210 | /** | 205 | /** |
211 | * sh_wdt_close - Close the Device | 206 | * sh_wdt_close - Close the Device |
212 | * | ||
213 | * @inode: inode of device | 207 | * @inode: inode of device |
214 | * @file: file handle of device | 208 | * @file: file handle of device |
215 | * | 209 | * |
@@ -220,7 +214,8 @@ static int sh_wdt_close(struct inode *inode, struct file *file) | |||
220 | if (shwdt_expect_close == 42) { | 214 | if (shwdt_expect_close == 42) { |
221 | sh_wdt_stop(); | 215 | sh_wdt_stop(); |
222 | } else { | 216 | } else { |
223 | printk(KERN_CRIT PFX "Unexpected close, not stopping watchdog!\n"); | 217 | printk(KERN_CRIT PFX "Unexpected close, not " |
218 | "stopping watchdog!\n"); | ||
224 | sh_wdt_keepalive(); | 219 | sh_wdt_keepalive(); |
225 | } | 220 | } |
226 | 221 | ||
@@ -232,7 +227,6 @@ static int sh_wdt_close(struct inode *inode, struct file *file) | |||
232 | 227 | ||
233 | /** | 228 | /** |
234 | * sh_wdt_write - Write to Device | 229 | * sh_wdt_write - Write to Device |
235 | * | ||
236 | * @file: file handle of device | 230 | * @file: file handle of device |
237 | * @buf: buffer to write | 231 | * @buf: buffer to write |
238 | * @count: length of buffer | 232 | * @count: length of buffer |
@@ -264,8 +258,56 @@ static ssize_t sh_wdt_write(struct file *file, const char *buf, | |||
264 | } | 258 | } |
265 | 259 | ||
266 | /** | 260 | /** |
267 | * sh_wdt_ioctl - Query Device | 261 | * sh_wdt_mmap - map WDT/CPG registers into userspace |
262 | * @file: file structure for the device | ||
263 | * @vma: VMA to map the registers into | ||
264 | * | ||
265 | * A simple mmap() implementation for the corner cases where the counter | ||
266 | * needs to be mapped in userspace directly. Due to the relatively small | ||
267 | * size of the area, neighbouring registers not necessarily tied to the | ||
268 | * CPG will also be accessible through the register page, so this remains | ||
269 | * configurable for users that really know what they're doing. | ||
268 | * | 270 | * |
271 | * Additionaly, the register page maps in the CPG register base relative | ||
272 | * to the nearest page-aligned boundary, which requires that userspace do | ||
273 | * the appropriate CPU subtype math for calculating the page offset for | ||
274 | * the counter value. | ||
275 | */ | ||
276 | static int sh_wdt_mmap(struct file *file, struct vm_area_struct *vma) | ||
277 | { | ||
278 | int ret = -ENOSYS; | ||
279 | |||
280 | #ifdef CONFIG_SH_WDT_MMAP | ||
281 | unsigned long addr; | ||
282 | |||
283 | /* Only support the simple cases where we map in a register page. */ | ||
284 | if (((vma->vm_end - vma->vm_start) != PAGE_SIZE) || vma->vm_pgoff) | ||
285 | return -EINVAL; | ||
286 | |||
287 | /* | ||
288 | * Pick WTCNT as the start, it's usually the first register after the | ||
289 | * FRQCR, and neither one are generally page-aligned out of the box. | ||
290 | */ | ||
291 | addr = WTCNT & ~(PAGE_SIZE - 1); | ||
292 | |||
293 | vma->vm_flags |= VM_IO; | ||
294 | vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot); | ||
295 | |||
296 | if (io_remap_pfn_range(vma, vma->vm_start, addr >> PAGE_SHIFT, | ||
297 | PAGE_SIZE, vma->vm_page_prot)) { | ||
298 | printk(KERN_ERR PFX "%s: io_remap_pfn_range failed\n", | ||
299 | __FUNCTION__); | ||
300 | return -EAGAIN; | ||
301 | } | ||
302 | |||
303 | ret = 0; | ||
304 | #endif | ||
305 | |||
306 | return ret; | ||
307 | } | ||
308 | |||
309 | /** | ||
310 | * sh_wdt_ioctl - Query Device | ||
269 | * @inode: inode of device | 311 | * @inode: inode of device |
270 | * @file: file handle of device | 312 | * @file: file handle of device |
271 | * @cmd: watchdog command | 313 | * @cmd: watchdog command |
@@ -318,7 +360,7 @@ static int sh_wdt_ioctl(struct inode *inode, struct file *file, | |||
318 | 360 | ||
319 | return retval; | 361 | return retval; |
320 | default: | 362 | default: |
321 | return -ENOIOCTLCMD; | 363 | return -ENOTTY; |
322 | } | 364 | } |
323 | 365 | ||
324 | return 0; | 366 | return 0; |
@@ -326,7 +368,6 @@ static int sh_wdt_ioctl(struct inode *inode, struct file *file, | |||
326 | 368 | ||
327 | /** | 369 | /** |
328 | * sh_wdt_notify_sys - Notifier Handler | 370 | * sh_wdt_notify_sys - Notifier Handler |
329 | * | ||
330 | * @this: notifier block | 371 | * @this: notifier block |
331 | * @code: notifier event | 372 | * @code: notifier event |
332 | * @unused: unused | 373 | * @unused: unused |
@@ -337,9 +378,8 @@ static int sh_wdt_ioctl(struct inode *inode, struct file *file, | |||
337 | static int sh_wdt_notify_sys(struct notifier_block *this, | 378 | static int sh_wdt_notify_sys(struct notifier_block *this, |
338 | unsigned long code, void *unused) | 379 | unsigned long code, void *unused) |
339 | { | 380 | { |
340 | if (code == SYS_DOWN || code == SYS_HALT) { | 381 | if (code == SYS_DOWN || code == SYS_HALT) |
341 | sh_wdt_stop(); | 382 | sh_wdt_stop(); |
342 | } | ||
343 | 383 | ||
344 | return NOTIFY_DONE; | 384 | return NOTIFY_DONE; |
345 | } | 385 | } |
@@ -351,10 +391,12 @@ static const struct file_operations sh_wdt_fops = { | |||
351 | .ioctl = sh_wdt_ioctl, | 391 | .ioctl = sh_wdt_ioctl, |
352 | .open = sh_wdt_open, | 392 | .open = sh_wdt_open, |
353 | .release = sh_wdt_close, | 393 | .release = sh_wdt_close, |
394 | .mmap = sh_wdt_mmap, | ||
354 | }; | 395 | }; |
355 | 396 | ||
356 | static struct watchdog_info sh_wdt_info = { | 397 | static struct watchdog_info sh_wdt_info = { |
357 | .options = WDIOF_KEEPALIVEPING | WDIOF_SETTIMEOUT | WDIOF_MAGICCLOSE, | 398 | .options = WDIOF_KEEPALIVEPING | WDIOF_SETTIMEOUT | |
399 | WDIOF_MAGICCLOSE, | ||
358 | .firmware_version = 1, | 400 | .firmware_version = 1, |
359 | .identity = "SH WDT", | 401 | .identity = "SH WDT", |
360 | }; | 402 | }; |
@@ -371,7 +413,6 @@ static struct miscdevice sh_wdt_miscdev = { | |||
371 | 413 | ||
372 | /** | 414 | /** |
373 | * sh_wdt_init - Initialize module | 415 | * sh_wdt_init - Initialize module |
374 | * | ||
375 | * Registers the device and notifier handler. Actual device | 416 | * Registers the device and notifier handler. Actual device |
376 | * initialization is handled by sh_wdt_open(). | 417 | * initialization is handled by sh_wdt_open(). |
377 | */ | 418 | */ |
@@ -381,15 +422,15 @@ static int __init sh_wdt_init(void) | |||
381 | 422 | ||
382 | if ((clock_division_ratio < 0x5) || (clock_division_ratio > 0x7)) { | 423 | if ((clock_division_ratio < 0x5) || (clock_division_ratio > 0x7)) { |
383 | clock_division_ratio = WTCSR_CKS_4096; | 424 | clock_division_ratio = WTCSR_CKS_4096; |
384 | printk(KERN_INFO PFX "clock_division_ratio value must be 0x5<=x<=0x7, using %d\n", | 425 | printk(KERN_INFO PFX "clock_division_ratio value must " |
385 | clock_division_ratio); | 426 | "be 0x5<=x<=0x7, using %d\n", clock_division_ratio); |
386 | } | 427 | } |
387 | 428 | ||
388 | if (sh_wdt_set_heartbeat(heartbeat)) | 429 | rc = sh_wdt_set_heartbeat(heartbeat); |
389 | { | 430 | if (unlikely(rc)) { |
390 | heartbeat = WATCHDOG_HEARTBEAT; | 431 | heartbeat = WATCHDOG_HEARTBEAT; |
391 | printk(KERN_INFO PFX "heartbeat value must be 1<=x<=3600, using %d\n", | 432 | printk(KERN_INFO PFX "heartbeat value must " |
392 | heartbeat); | 433 | "be 1<=x<=3600, using %d\n", heartbeat); |
393 | } | 434 | } |
394 | 435 | ||
395 | init_timer(&timer); | 436 | init_timer(&timer); |
@@ -397,15 +438,16 @@ static int __init sh_wdt_init(void) | |||
397 | timer.data = 0; | 438 | timer.data = 0; |
398 | 439 | ||
399 | rc = register_reboot_notifier(&sh_wdt_notifier); | 440 | rc = register_reboot_notifier(&sh_wdt_notifier); |
400 | if (rc) { | 441 | if (unlikely(rc)) { |
401 | printk(KERN_ERR PFX "Can't register reboot notifier (err=%d)\n", rc); | 442 | printk(KERN_ERR PFX "Can't register reboot notifier (err=%d)\n", |
443 | rc); | ||
402 | return rc; | 444 | return rc; |
403 | } | 445 | } |
404 | 446 | ||
405 | rc = misc_register(&sh_wdt_miscdev); | 447 | rc = misc_register(&sh_wdt_miscdev); |
406 | if (rc) { | 448 | if (unlikely(rc)) { |
407 | printk(KERN_ERR PFX "Can't register miscdev on minor=%d (err=%d)\n", | 449 | printk(KERN_ERR PFX "Can't register miscdev on " |
408 | sh_wdt_miscdev.minor, rc); | 450 | "minor=%d (err=%d)\n", sh_wdt_miscdev.minor, rc); |
409 | unregister_reboot_notifier(&sh_wdt_notifier); | 451 | unregister_reboot_notifier(&sh_wdt_notifier); |
410 | return rc; | 452 | return rc; |
411 | } | 453 | } |
@@ -418,7 +460,6 @@ static int __init sh_wdt_init(void) | |||
418 | 460 | ||
419 | /** | 461 | /** |
420 | * sh_wdt_exit - Deinitialize module | 462 | * sh_wdt_exit - Deinitialize module |
421 | * | ||
422 | * Unregisters the device and notifier handler. Actual device | 463 | * Unregisters the device and notifier handler. Actual device |
423 | * deinitialization is handled by sh_wdt_close(). | 464 | * deinitialization is handled by sh_wdt_close(). |
424 | */ | 465 | */ |
@@ -434,14 +475,13 @@ MODULE_LICENSE("GPL"); | |||
434 | MODULE_ALIAS_MISCDEV(WATCHDOG_MINOR); | 475 | MODULE_ALIAS_MISCDEV(WATCHDOG_MINOR); |
435 | 476 | ||
436 | module_param(clock_division_ratio, int, 0); | 477 | module_param(clock_division_ratio, int, 0); |
437 | MODULE_PARM_DESC(clock_division_ratio, "Clock division ratio. Valid ranges are from 0x5 (1.31ms) to 0x7 (5.25ms). Defaults to 0x7."); | 478 | MODULE_PARM_DESC(clock_division_ratio, "Clock division ratio. Valid ranges are from 0x5 (1.31ms) to 0x7 (5.25ms). (default=" __MODULE_STRING(clock_division_ratio) ")"); |
438 | 479 | ||
439 | module_param(heartbeat, int, 0); | 480 | module_param(heartbeat, int, 0); |
440 | MODULE_PARM_DESC(heartbeat, "Watchdog heartbeat in seconds. (1<=heartbeat<=3600, default=" __MODULE_STRING(WATCHDOG_HEARTBEAT) ")"); | 481 | MODULE_PARM_DESC(heartbeat, "Watchdog heartbeat in seconds. (1<=heartbeat<=3600, default=" __MODULE_STRING(WATCHDOG_HEARTBEAT) ")"); |
441 | 482 | ||
442 | module_param(nowayout, int, 0); | 483 | module_param(nowayout, int, 0); |
443 | MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default=CONFIG_WATCHDOG_NOWAYOUT)"); | 484 | MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default=" __MODULE_STRING(WATCHDOG_NOWAYOUT) ")"); |
444 | 485 | ||
445 | module_init(sh_wdt_init); | 486 | module_init(sh_wdt_init); |
446 | module_exit(sh_wdt_exit); | 487 | module_exit(sh_wdt_exit); |
447 | |||
diff --git a/drivers/char/watchdog/smsc37b787_wdt.c b/drivers/char/watchdog/smsc37b787_wdt.c new file mode 100644 index 000000000000..9f56913b484f --- /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/softdog.c b/drivers/char/watchdog/softdog.c index ef8da517545a..4067e1f8a368 100644 --- a/drivers/char/watchdog/softdog.c +++ b/drivers/char/watchdog/softdog.c | |||
@@ -203,7 +203,7 @@ static int softdog_ioctl(struct inode *inode, struct file *file, | |||
203 | }; | 203 | }; |
204 | switch (cmd) { | 204 | switch (cmd) { |
205 | default: | 205 | default: |
206 | return -ENOIOCTLCMD; | 206 | return -ENOTTY; |
207 | case WDIOC_GETSUPPORT: | 207 | case WDIOC_GETSUPPORT: |
208 | return copy_to_user(argp, &ident, | 208 | return copy_to_user(argp, &ident, |
209 | sizeof(ident)) ? -EFAULT : 0; | 209 | sizeof(ident)) ? -EFAULT : 0; |
diff --git a/drivers/char/watchdog/w83627hf_wdt.c b/drivers/char/watchdog/w83627hf_wdt.c index 13f16d41c2fd..07d4bff27226 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 |
@@ -223,7 +229,7 @@ wdt_ioctl(struct inode *inode, struct file *file, unsigned int cmd, | |||
223 | } | 229 | } |
224 | 230 | ||
225 | default: | 231 | default: |
226 | return -ENOIOCTLCMD; | 232 | return -ENOTTY; |
227 | } | 233 | } |
228 | return 0; | 234 | return 0; |
229 | } | 235 | } |
@@ -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 000000000000..7768b55487c8 --- /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); | ||
diff --git a/drivers/char/watchdog/w83877f_wdt.c b/drivers/char/watchdog/w83877f_wdt.c index ccf6c0915945..b0e5f84d6baf 100644 --- a/drivers/char/watchdog/w83877f_wdt.c +++ b/drivers/char/watchdog/w83877f_wdt.c | |||
@@ -252,7 +252,7 @@ static int fop_ioctl(struct inode *inode, struct file *file, unsigned int cmd, | |||
252 | switch(cmd) | 252 | switch(cmd) |
253 | { | 253 | { |
254 | default: | 254 | default: |
255 | return -ENOIOCTLCMD; | 255 | return -ENOTTY; |
256 | case WDIOC_GETSUPPORT: | 256 | case WDIOC_GETSUPPORT: |
257 | return copy_to_user(argp, &ident, sizeof(ident))?-EFAULT:0; | 257 | return copy_to_user(argp, &ident, sizeof(ident))?-EFAULT:0; |
258 | case WDIOC_GETSTATUS: | 258 | case WDIOC_GETSTATUS: |
diff --git a/drivers/char/watchdog/w83977f_wdt.c b/drivers/char/watchdog/w83977f_wdt.c index 98f4e17db70a..2c8d5d8bd4e8 100644 --- a/drivers/char/watchdog/w83977f_wdt.c +++ b/drivers/char/watchdog/w83977f_wdt.c | |||
@@ -393,7 +393,7 @@ static int wdt_ioctl(struct inode *inode, struct file *file, | |||
393 | switch(cmd) | 393 | switch(cmd) |
394 | { | 394 | { |
395 | default: | 395 | default: |
396 | return -ENOIOCTLCMD; | 396 | return -ENOTTY; |
397 | 397 | ||
398 | case WDIOC_GETSUPPORT: | 398 | case WDIOC_GETSUPPORT: |
399 | return copy_to_user(uarg.ident, &ident, sizeof(ident)) ? -EFAULT : 0; | 399 | return copy_to_user(uarg.ident, &ident, sizeof(ident)) ? -EFAULT : 0; |
diff --git a/drivers/char/watchdog/wafer5823wdt.c b/drivers/char/watchdog/wafer5823wdt.c index 2bb6a9d6ad28..163e028ef9ed 100644 --- a/drivers/char/watchdog/wafer5823wdt.c +++ b/drivers/char/watchdog/wafer5823wdt.c | |||
@@ -174,7 +174,7 @@ static int wafwdt_ioctl(struct inode *inode, struct file *file, unsigned int cmd | |||
174 | } | 174 | } |
175 | 175 | ||
176 | default: | 176 | default: |
177 | return -ENOIOCTLCMD; | 177 | return -ENOTTY; |
178 | } | 178 | } |
179 | return 0; | 179 | return 0; |
180 | } | 180 | } |
diff --git a/drivers/char/watchdog/wdrtas.c b/drivers/char/watchdog/wdrtas.c index 5c38cdf41731..1d64e277567d 100644 --- a/drivers/char/watchdog/wdrtas.c +++ b/drivers/char/watchdog/wdrtas.c | |||
@@ -385,7 +385,7 @@ wdrtas_ioctl(struct inode *inode, struct file *file, | |||
385 | return put_user(wdrtas_interval, argp); | 385 | return put_user(wdrtas_interval, argp); |
386 | 386 | ||
387 | default: | 387 | default: |
388 | return -ENOIOCTLCMD; | 388 | return -ENOTTY; |
389 | } | 389 | } |
390 | } | 390 | } |
391 | 391 | ||
diff --git a/drivers/char/watchdog/wdt.c b/drivers/char/watchdog/wdt.c index 70be81e39a61..517fbd8643f8 100644 --- a/drivers/char/watchdog/wdt.c +++ b/drivers/char/watchdog/wdt.c | |||
@@ -225,14 +225,13 @@ static int wdt_get_temperature(int *temperature) | |||
225 | * wdt_interrupt: | 225 | * wdt_interrupt: |
226 | * @irq: Interrupt number | 226 | * @irq: Interrupt number |
227 | * @dev_id: Unused as we don't allow multiple devices. | 227 | * @dev_id: Unused as we don't allow multiple devices. |
228 | * @regs: Unused. | ||
229 | * | 228 | * |
230 | * Handle an interrupt from the board. These are raised when the status | 229 | * Handle an interrupt from the board. These are raised when the status |
231 | * map changes in what the board considers an interesting way. That means | 230 | * map changes in what the board considers an interesting way. That means |
232 | * a failure condition occurring. | 231 | * a failure condition occurring. |
233 | */ | 232 | */ |
234 | 233 | ||
235 | static irqreturn_t wdt_interrupt(int irq, void *dev_id, struct pt_regs *regs) | 234 | static irqreturn_t wdt_interrupt(int irq, void *dev_id) |
236 | { | 235 | { |
237 | /* | 236 | /* |
238 | * Read the status register see what is up and | 237 | * Read the status register see what is up and |
@@ -341,7 +340,7 @@ static int wdt_ioctl(struct inode *inode, struct file *file, unsigned int cmd, | |||
341 | switch(cmd) | 340 | switch(cmd) |
342 | { | 341 | { |
343 | default: | 342 | default: |
344 | return -ENOIOCTLCMD; | 343 | return -ENOTTY; |
345 | case WDIOC_GETSUPPORT: | 344 | case WDIOC_GETSUPPORT: |
346 | return copy_to_user(argp, &ident, sizeof(ident))?-EFAULT:0; | 345 | return copy_to_user(argp, &ident, sizeof(ident))?-EFAULT:0; |
347 | 346 | ||
diff --git a/drivers/char/watchdog/wdt285.c b/drivers/char/watchdog/wdt285.c index 6555fb844f23..e4cf661dc890 100644 --- a/drivers/char/watchdog/wdt285.c +++ b/drivers/char/watchdog/wdt285.c | |||
@@ -46,7 +46,7 @@ static unsigned long timer_alive; | |||
46 | /* | 46 | /* |
47 | * If the timer expires.. | 47 | * If the timer expires.. |
48 | */ | 48 | */ |
49 | static void watchdog_fire(int irq, void *dev_id, struct pt_regs *regs) | 49 | static void watchdog_fire(int irq, void *dev_id) |
50 | { | 50 | { |
51 | printk(KERN_CRIT "Watchdog: Would Reboot.\n"); | 51 | printk(KERN_CRIT "Watchdog: Would Reboot.\n"); |
52 | *CSR_TIMER4_CNTL = 0; | 52 | *CSR_TIMER4_CNTL = 0; |
@@ -137,7 +137,7 @@ watchdog_ioctl(struct inode *inode, struct file *file, unsigned int cmd, | |||
137 | unsigned long arg) | 137 | unsigned long arg) |
138 | { | 138 | { |
139 | unsigned int new_margin; | 139 | unsigned int new_margin; |
140 | int ret = -ENOIOCTLCMD; | 140 | int ret = -ENOTTY; |
141 | 141 | ||
142 | switch(cmd) { | 142 | switch(cmd) { |
143 | case WDIOC_GETSUPPORT: | 143 | case WDIOC_GETSUPPORT: |
diff --git a/drivers/char/watchdog/wdt977.c b/drivers/char/watchdog/wdt977.c index a0935bc775f8..6253041b235b 100644 --- a/drivers/char/watchdog/wdt977.c +++ b/drivers/char/watchdog/wdt977.c | |||
@@ -361,7 +361,7 @@ static int wdt977_ioctl(struct inode *inode, struct file *file, | |||
361 | switch(cmd) | 361 | switch(cmd) |
362 | { | 362 | { |
363 | default: | 363 | default: |
364 | return -ENOIOCTLCMD; | 364 | return -ENOTTY; |
365 | 365 | ||
366 | case WDIOC_GETSUPPORT: | 366 | case WDIOC_GETSUPPORT: |
367 | return copy_to_user(uarg.ident, &ident, | 367 | return copy_to_user(uarg.ident, &ident, |
diff --git a/drivers/char/watchdog/wdt_pci.c b/drivers/char/watchdog/wdt_pci.c index 5918ca2c9c35..ce1261c5cbce 100644 --- a/drivers/char/watchdog/wdt_pci.c +++ b/drivers/char/watchdog/wdt_pci.c | |||
@@ -270,14 +270,13 @@ static int wdtpci_get_temperature(int *temperature) | |||
270 | * wdtpci_interrupt: | 270 | * wdtpci_interrupt: |
271 | * @irq: Interrupt number | 271 | * @irq: Interrupt number |
272 | * @dev_id: Unused as we don't allow multiple devices. | 272 | * @dev_id: Unused as we don't allow multiple devices. |
273 | * @regs: Unused. | ||
274 | * | 273 | * |
275 | * Handle an interrupt from the board. These are raised when the status | 274 | * Handle an interrupt from the board. These are raised when the status |
276 | * map changes in what the board considers an interesting way. That means | 275 | * map changes in what the board considers an interesting way. That means |
277 | * a failure condition occurring. | 276 | * a failure condition occurring. |
278 | */ | 277 | */ |
279 | 278 | ||
280 | static irqreturn_t wdtpci_interrupt(int irq, void *dev_id, struct pt_regs *regs) | 279 | static irqreturn_t wdtpci_interrupt(int irq, void *dev_id) |
281 | { | 280 | { |
282 | /* | 281 | /* |
283 | * Read the status register see what is up and | 282 | * Read the status register see what is up and |
@@ -386,7 +385,7 @@ static int wdtpci_ioctl(struct inode *inode, struct file *file, unsigned int cmd | |||
386 | switch(cmd) | 385 | switch(cmd) |
387 | { | 386 | { |
388 | default: | 387 | default: |
389 | return -ENOIOCTLCMD; | 388 | return -ENOTTY; |
390 | case WDIOC_GETSUPPORT: | 389 | case WDIOC_GETSUPPORT: |
391 | return copy_to_user(argp, &ident, sizeof(ident))?-EFAULT:0; | 390 | return copy_to_user(argp, &ident, sizeof(ident))?-EFAULT:0; |
392 | 391 | ||