Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

Merge git://git.kernel.org/pub/scm/linux/kernel/git/wim/linux-2.6-watchdog

* git://git.kernel.org/pub/scm/linux/kernel/git/wim/linux-2.6-watchdog: (33 commits)
[WATCHDOG] remove experimental on iTCO_wdt.c
[WATCHDOG] Atmel AT91RM9200 rename.
[WATCHDOG] includes for sample watchdog program.
[WATCHDOG] watchdog/iTCO_wdt: fix bug related to gcc uninit warning
[WATCHDOG] add ich8 support to iTCO_wdt.c (patch 2)
[WATCHDOG] add ich8 support to iTCO_wdt.c
[WATCHDOG] ioremap balanced with iounmap for drivers/char/watchdog/s3c2410_wdt.c
[WATCHDOG] w83697hf/hg WDT driver - Kconfig patch
[WATCHDOG] w83697hf/hg WDT driver - autodetect patch
[WATCHDOG] w83697hf/hg WDT driver - patch 16
[WATCHDOG] w83697hf/hg WDT driver - patch 15
[WATCHDOG] w83697hf/hg WDT driver - patch 14
[WATCHDOG] w83697hf/hg WDT driver - patch 13
[WATCHDOG] w83697hf/hg WDT driver - patch 12
[WATCHDOG] w83697hf/hg WDT driver - patch 11
[WATCHDOG] w83697hf/hg WDT driver - patch 10
[WATCHDOG] w83697hf/hg WDT driver - patch 9
[WATCHDOG] w83697hf/hg WDT driver - patch 8
[WATCHDOG] w83697hf/hg WDT driver - patch 7
[WATCHDOG] w83697hf/hg WDT driver - patch 6
...

+1170 -24
+2
Documentation/watchdog/src/watchdog-simple.c
··· 1 + #include <stdio.h> 1 2 #include <stdlib.h> 3 + #include <unistd.h> 2 4 #include <fcntl.h> 3 5 4 6 int main(int argc, const char *argv[]) {
+1 -1
arch/arm/configs/at91rm9200dk_defconfig
··· 577 577 # Watchdog Device Drivers 578 578 # 579 579 # CONFIG_SOFT_WATCHDOG is not set 580 - CONFIG_AT91_WATCHDOG=y 580 + CONFIG_AT91RM9200_WATCHDOG=y 581 581 582 582 # 583 583 # USB-based Watchdog Cards
+1 -1
arch/arm/configs/at91rm9200ek_defconfig
··· 558 558 # Watchdog Device Drivers 559 559 # 560 560 # CONFIG_SOFT_WATCHDOG is not set 561 - CONFIG_AT91_WATCHDOG=y 561 + CONFIG_AT91RM9200_WATCHDOG=y 562 562 563 563 # 564 564 # USB-based Watchdog Cards
+1 -1
arch/arm/configs/csb337_defconfig
··· 615 615 # Watchdog Device Drivers 616 616 # 617 617 # CONFIG_SOFT_WATCHDOG is not set 618 - CONFIG_AT91_WATCHDOG=y 618 + CONFIG_AT91RM9200_WATCHDOG=y 619 619 620 620 # 621 621 # USB-based Watchdog Cards
+1 -1
arch/arm/configs/csb637_defconfig
··· 615 615 # Watchdog Device Drivers 616 616 # 617 617 # CONFIG_SOFT_WATCHDOG is not set 618 - CONFIG_AT91_WATCHDOG=y 618 + CONFIG_AT91RM9200_WATCHDOG=y 619 619 620 620 # 621 621 # USB-based Watchdog Cards
+1 -1
arch/arm/configs/kafa_defconfig
··· 560 560 # Watchdog Device Drivers 561 561 # 562 562 # CONFIG_SOFT_WATCHDOG is not set 563 - CONFIG_AT91_WATCHDOG=y 563 + CONFIG_AT91RM9200_WATCHDOG=y 564 564 # CONFIG_NVRAM is not set 565 565 # CONFIG_DTLK is not set 566 566 # CONFIG_R3964 is not set
+1 -1
arch/arm/configs/onearm_defconfig
··· 607 607 # Watchdog Device Drivers 608 608 # 609 609 # CONFIG_SOFT_WATCHDOG is not set 610 - CONFIG_AT91_WATCHDOG=y 610 + CONFIG_AT91RM9200_WATCHDOG=y 611 611 612 612 # 613 613 # USB-based Watchdog Cards
+51 -14
drivers/char/watchdog/Kconfig
··· 13 13 subsequently opening the file and then failing to write to it for 14 14 longer than 1 minute will result in rebooting the machine. This 15 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 17 implementation entirely in software (which can sometimes fail to 18 18 reboot the machine) and a driver for hardware watchdog boards, which 19 19 are more robust and can also keep track of the temperature inside ··· 60 60 61 61 # ARM Architecture 62 62 63 - config AT91_WATCHDOG 63 + config AT91RM9200_WATCHDOG 64 64 tristate "AT91RM9200 watchdog" 65 65 depends on WATCHDOG && ARCH_AT91RM9200 66 66 help ··· 71 71 tristate "DC21285 watchdog" 72 72 depends on WATCHDOG && FOOTBRIDGE 73 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 75 here if you wish to use this. Alternatively say M to compile the 76 76 driver as a module, which will be called wdt285. 77 77 ··· 269 269 Most people will say N. 270 270 271 271 config IBMASR 272 - tristate "IBM Automatic Server Restart" 273 - depends on WATCHDOG && X86 274 - help 272 + tristate "IBM Automatic Server Restart" 273 + depends on WATCHDOG && X86 274 + help 275 275 This is the driver for the IBM Automatic Server Restart watchdog 276 - timer builtin into some eServer xSeries machines. 276 + timer built-in into some eServer xSeries machines. 277 277 278 278 To compile this driver as a module, choose M here: the 279 279 module will be called ibmasr. ··· 316 316 To compile this driver as a module, choose M here: the 317 317 module will be called i8xx_tco. 318 318 319 + Note: This driver will be removed in the near future. Please 320 + use the Intel TCO Timer/Watchdog driver. 321 + 319 322 config ITCO_WDT 320 - tristate "Intel TCO Timer/Watchdog (EXPERIMENTAL)" 321 - depends on WATCHDOG && (X86 || IA64) && PCI && EXPERIMENTAL 323 + tristate "Intel TCO Timer/Watchdog" 324 + depends on WATCHDOG && (X86 || IA64) && PCI 322 325 ---help--- 323 326 Hardware driver for the intel TCO timer based watchdog devices. 324 327 These drivers are included in the Intel 82801 I/O Controller 325 - Hub family 'from ICH0 up to ICH7) and in the Intel 6300ESB 328 + Hub family (from ICH0 up to ICH8) and in the Intel 6300ESB 326 329 controller hub. 327 330 328 331 The TCO (Total Cost of Ownership) timer is a watchdog timer ··· 398 395 To compile this driver as a module, choose M here: the 399 396 module will be called cpu5wdt. 400 397 398 + config SMSC37B787_WDT 399 + tristate "Winbond SMsC37B787 Watchdog Timer" 400 + depends on WATCHDOG && X86 401 + ---help--- 402 + This is the driver for the hardware watchdog component on the 403 + Winbond SMsC37B787 chipset as used on the NetRunner Mainboard 404 + from Vision Systems and maybe others. 405 + 406 + This watchdog simply watches your kernel to make sure it doesn't 407 + freeze, and if it does, it reboots your computer after a certain 408 + amount of time. 409 + 410 + Usually a userspace daemon will notify the kernel WDT driver that 411 + userspace is still alive, at regular intervals. 412 + 413 + To compile this driver as a module, choose M here: the 414 + module will be called smsc37b787_wdt. 415 + 416 + Most people will say N. 417 + 401 418 config W83627HF_WDT 402 419 tristate "W83627HF Watchdog Timer" 403 420 depends on WATCHDOG && X86 ··· 430 407 431 408 To compile this driver as a module, choose M here: the 432 409 module will be called w83627hf_wdt. 410 + 411 + Most people will say N. 412 + 413 + config W83697HF_WDT 414 + tristate "W83697HF/W83697HG Watchdog Timer" 415 + depends on WATCHDOG && X86 416 + ---help--- 417 + This is the driver for the hardware watchdog on the W83697HF/HG 418 + chipset as used in Dedibox/VIA motherboards (and likely others). 419 + This watchdog simply watches your kernel to make sure it doesn't 420 + freeze, and if it does, it reboots your computer after a certain 421 + amount of time. 422 + 423 + To compile this driver as a module, choose M here: the 424 + module will be called w83697hf_wdt. 433 425 434 426 Most people will say N. 435 427 ··· 481 443 depends on WATCHDOG && X86 482 444 ---help--- 483 445 If you are using a ZF Micro MachZ processor, say Y here, otherwise 484 - N. This is the driver for the watchdog timer builtin on that 446 + N. This is the driver for the watchdog timer built-in on that 485 447 processor using ZF-Logic interface. This watchdog simply watches 486 448 your kernel to make sure it doesn't freeze, and if it does, it 487 449 reboots your computer after a certain amount of time. ··· 509 471 510 472 To compile this driver as a module, choose M here: the 511 473 module will be called sbc_epx_c3. 512 - 513 474 514 475 # PowerPC Architecture 515 476 ··· 539 502 help 540 503 This driver adds watchdog support for the RTAS watchdog. 541 504 542 - To compile this driver as a module, choose M here. The module 505 + To compile this driver as a module, choose M here. The module 543 506 will be called wdrtas. 544 507 545 508 # MIPS Architecture ··· 593 556 help 594 557 If you say Y here, user applications will be able to mmap the 595 558 WDT/CPG registers. 596 - # 559 + 597 560 # SPARC64 Architecture 598 561 599 562 config WATCHDOG_CP1XXX
+3 -1
drivers/char/watchdog/Makefile
··· 23 23 obj-$(CONFIG_USBPCWATCHDOG) += pcwd_usb.o 24 24 25 25 # ARM Architecture 26 - obj-$(CONFIG_AT91_WATCHDOG) += at91_wdt.o 26 + obj-$(CONFIG_AT91RM9200_WATCHDOG) += at91rm9200_wdt.o 27 27 obj-$(CONFIG_OMAP_WATCHDOG) += omap_wdt.o 28 28 obj-$(CONFIG_21285_WATCHDOG) += wdt285.o 29 29 obj-$(CONFIG_977_WATCHDOG) += wdt977.o ··· 53 53 obj-$(CONFIG_60XX_WDT) += sbc60xxwdt.o 54 54 obj-$(CONFIG_SBC8360_WDT) += sbc8360.o 55 55 obj-$(CONFIG_CPU5_WDT) += cpu5wdt.o 56 + obj-$(CONFIG_SMSC37B787_WDT) += smsc37b787_wdt.o 56 57 obj-$(CONFIG_W83627HF_WDT) += w83627hf_wdt.o 58 + obj-$(CONFIG_W83697HF_WDT) += w83697hf_wdt.o 57 59 obj-$(CONFIG_W83877F_WDT) += w83877f_wdt.o 58 60 obj-$(CONFIG_W83977F_WDT) += w83977f_wdt.o 59 61 obj-$(CONFIG_MACHZ_WDT) += machzwd.o
drivers/char/watchdog/at91_wdt.c drivers/char/watchdog/at91rm9200_wdt.c
+18 -3
drivers/char/watchdog/iTCO_wdt.c
··· 35 35 * 82801GDH (ICH7DH) : document number 307013-002, 307014-009, 36 36 * 82801GBM (ICH7-M) : document number 307013-002, 307014-009, 37 37 * 82801GHM (ICH7-M DH) : document number 307013-002, 307014-009, 38 + * 82801HB (ICH8) : document number 313056-002, 313057-004, 39 + * 82801HR (ICH8R) : document number 313056-002, 313057-004, 40 + * 82801HH (ICH8DH) : document number 313056-002, 313057-004, 41 + * 82801HO (ICH8DO) : document number 313056-002, 313057-004, 38 42 * 6300ESB (6300ESB) : document number 300641-003 39 43 */ 40 44 ··· 49 45 /* Module and version information */ 50 46 #define DRV_NAME "iTCO_wdt" 51 47 #define DRV_VERSION "1.00" 52 - #define DRV_RELDATE "30-Jul-2006" 48 + #define DRV_RELDATE "08-Oct-2006" 53 49 #define PFX DRV_NAME ": " 54 50 55 51 /* Includes */ ··· 89 85 TCO_ICH7, /* ICH7 & ICH7R */ 90 86 TCO_ICH7M, /* ICH7-M */ 91 87 TCO_ICH7MDH, /* ICH7-M DH */ 88 + TCO_ICH8, /* ICH8 & ICH8R */ 89 + TCO_ICH8DH, /* ICH8DH */ 90 + TCO_ICH8DO, /* ICH8DO */ 92 91 }; 93 92 94 93 static struct { ··· 115 108 {"ICH7 or ICH7R", 2}, 116 109 {"ICH7-M", 2}, 117 110 {"ICH7-M DH", 2}, 111 + {"ICH8 or ICH8R", 2}, 112 + {"ICH8DH", 2}, 113 + {"ICH8DO", 2}, 118 114 {NULL,0} 119 115 }; 120 116 ··· 145 135 { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ICH7_0, PCI_ANY_ID, PCI_ANY_ID, 0, 0, TCO_ICH7 }, 146 136 { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ICH7_1, PCI_ANY_ID, PCI_ANY_ID, 0, 0, TCO_ICH7M }, 147 137 { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ICH7_31, PCI_ANY_ID, PCI_ANY_ID, 0, 0, TCO_ICH7MDH }, 138 + { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ICH8_0, PCI_ANY_ID, PCI_ANY_ID, 0, 0, TCO_ICH8 }, 139 + { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ICH8_2, PCI_ANY_ID, PCI_ANY_ID, 0, 0, TCO_ICH8DH }, 140 + { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ICH8_3, PCI_ANY_ID, PCI_ANY_ID, 0, 0, TCO_ICH8DO }, 148 141 { 0, }, /* End of list */ 149 142 }; 150 143 MODULE_DEVICE_TABLE (pci, iTCO_wdt_pci_tbl); ··· 368 355 spin_unlock(&iTCO_wdt_private.io_lock); 369 356 370 357 *time_left = (val8 * 6) / 10; 371 - } 358 + } else 359 + return -EINVAL; 372 360 return 0; 373 361 } 374 362 ··· 440 426 { 441 427 int new_options, retval = -EINVAL; 442 428 int new_heartbeat; 443 - int time_left; 444 429 void __user *argp = (void __user *)arg; 445 430 int __user *p = argp; 446 431 static struct watchdog_info ident = { ··· 499 486 500 487 case WDIOC_GETTIMELEFT: 501 488 { 489 + int time_left; 490 + 502 491 if (iTCO_wdt_get_timeleft(&time_left)) 503 492 return -EINVAL; 504 493
+5
drivers/char/watchdog/s3c2410_wdt.c
··· 380 380 res = platform_get_resource(pdev, IORESOURCE_IRQ, 0); 381 381 if (res == NULL) { 382 382 printk(KERN_INFO PFX "failed to get irq resource\n"); 383 + iounmap(wdt_base); 383 384 return -ENOENT; 384 385 } 385 386 386 387 ret = request_irq(res->start, s3c2410wdt_irq, 0, pdev->name, pdev); 387 388 if (ret != 0) { 388 389 printk(KERN_INFO PFX "failed to install irq (%d)\n", ret); 390 + iounmap(wdt_base); 389 391 return ret; 390 392 } 391 393 392 394 wdt_clock = clk_get(&pdev->dev, "watchdog"); 393 395 if (wdt_clock == NULL) { 394 396 printk(KERN_INFO PFX "failed to find watchdog clock source\n"); 397 + iounmap(wdt_base); 395 398 return -ENOENT; 396 399 } 397 400 ··· 418 415 if (ret) { 419 416 printk (KERN_ERR PFX "cannot register miscdev on minor=%d (%d)\n", 420 417 WATCHDOG_MINOR, ret); 418 + iounmap(wdt_base); 421 419 return ret; 422 420 } 423 421 ··· 455 451 wdt_clock = NULL; 456 452 } 457 453 454 + iounmap(wdt_base); 458 455 misc_deregister(&s3c2410wdt_miscdev); 459 456 return 0; 460 457 }
+627
drivers/char/watchdog/smsc37b787_wdt.c
··· 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)");
+8
drivers/char/watchdog/w83627hf_wdt.c
··· 33 33 #include <linux/notifier.h> 34 34 #include <linux/reboot.h> 35 35 #include <linux/init.h> 36 + #include <linux/spinlock.h> 36 37 37 38 #include <asm/io.h> 38 39 #include <asm/uaccess.h> ··· 45 44 46 45 static unsigned long wdt_is_open; 47 46 static char expect_close; 47 + static spinlock_t io_lock; 48 48 49 49 /* You must set this - there is no sane way to probe for this board. */ 50 50 static int wdt_io = 0x2E; ··· 112 110 static void 113 111 wdt_ctrl(int timeout) 114 112 { 113 + spin_lock(&io_lock); 114 + 115 115 w83627hf_select_wd_register(); 116 116 117 117 outb_p(0xF6, WDT_EFER); /* Select CRF6 */ 118 118 outb_p(timeout, WDT_EFDR); /* Write Timeout counter to CRF6 */ 119 119 120 120 w83627hf_unselect_wd_register(); 121 + 122 + spin_unlock(&io_lock); 121 123 } 122 124 123 125 static int ··· 308 302 wdt_init(void) 309 303 { 310 304 int ret; 305 + 306 + spin_lock_init(&io_lock); 311 307 312 308 printk(KERN_INFO "WDT driver for the Winbond(TM) W83627HF Super I/O chip initialising.\n"); 313 309
+450
drivers/char/watchdog/w83697hf_wdt.c
··· 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);