aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/watchdog
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/watchdog')
-rw-r--r--drivers/watchdog/Kconfig33
-rw-r--r--drivers/watchdog/Makefile3
-rw-r--r--drivers/watchdog/alim1535_wdt.c20
-rw-r--r--drivers/watchdog/alim7101_wdt.c18
-rw-r--r--drivers/watchdog/ar7_wdt.c2
-rw-r--r--drivers/watchdog/at32ap700x_wdt.c69
-rw-r--r--drivers/watchdog/bfin_wdt.c4
-rw-r--r--drivers/watchdog/it8712f_wdt.c400
-rw-r--r--drivers/watchdog/mpc5200_wdt.c2
-rw-r--r--drivers/watchdog/mtx-1_wdt.c2
-rw-r--r--drivers/watchdog/sbc60xxwdt.c18
-rw-r--r--drivers/watchdog/sbc7240_wdt.c324
-rw-r--r--drivers/watchdog/scx200_wdt.c10
-rw-r--r--drivers/watchdog/shwdt.c2
-rw-r--r--drivers/watchdog/txx9wdt.c276
-rw-r--r--drivers/watchdog/w83877f_wdt.c18
-rw-r--r--drivers/watchdog/w83977f_wdt.c18
-rw-r--r--drivers/watchdog/wdt.c30
-rw-r--r--drivers/watchdog/wdt977.c18
19 files changed, 1192 insertions, 75 deletions
diff --git a/drivers/watchdog/Kconfig b/drivers/watchdog/Kconfig
index 2792bc1a7269..afcdc69e37d6 100644
--- a/drivers/watchdog/Kconfig
+++ b/drivers/watchdog/Kconfig
@@ -223,7 +223,7 @@ config DAVINCI_WATCHDOG
223 223
224config AT32AP700X_WDT 224config AT32AP700X_WDT
225 tristate "AT32AP700x watchdog" 225 tristate "AT32AP700x watchdog"
226 depends on CPU_AT32AP7000 226 depends on CPU_AT32AP700X
227 help 227 help
228 Watchdog timer embedded into AT32AP700x devices. This will reboot 228 Watchdog timer embedded into AT32AP700x devices. This will reboot
229 your system when the timeout is reached. 229 your system when the timeout is reached.
@@ -392,6 +392,16 @@ config ITCO_VENDOR_SUPPORT
392 devices. At this moment we only have additional support for some 392 devices. At this moment we only have additional support for some
393 SuperMicro Inc. motherboards. 393 SuperMicro Inc. motherboards.
394 394
395config IT8712F_WDT
396 tristate "IT8712F (Smart Guardian) Watchdog Timer"
397 depends on X86
398 ---help---
399 This is the driver for the built-in watchdog timer on the IT8712F
400 Super I/0 chipset used on many motherboards.
401
402 To compile this driver as a module, choose M here: the
403 module will be called it8712f_wdt.
404
395config SC1200_WDT 405config SC1200_WDT
396 tristate "National Semiconductor PC87307/PC97307 (ala SC1200) Watchdog" 406 tristate "National Semiconductor PC87307/PC97307 (ala SC1200) Watchdog"
397 depends on X86 407 depends on X86
@@ -456,6 +466,19 @@ config SBC8360_WDT
456 466
457 Most people will say N. 467 Most people will say N.
458 468
469config SBC7240_WDT
470 tristate "SBC Nano 7240 Watchdog Timer"
471 depends on X86_32
472 ---help---
473 This is the driver for the hardware watchdog found on the IEI
474 single board computers EPIC Nano 7240 (and likely others). This
475 watchdog simply watches your kernel to make sure it doesn't freeze,
476 and if it does, it reboots your computer after a certain amount of
477 time.
478
479 To compile this driver as a module, choose M here: the
480 module will be called sbc7240_wdt.
481
459config CPU5_WDT 482config CPU5_WDT
460 tristate "SMA CPU5 Watchdog" 483 tristate "SMA CPU5 Watchdog"
461 depends on X86 484 depends on X86
@@ -586,7 +609,7 @@ config SBC_EPX_C3_WATCHDOG
586 609
587config INDYDOG 610config INDYDOG
588 tristate "Indy/I2 Hardware Watchdog" 611 tristate "Indy/I2 Hardware Watchdog"
589 depends on SGI_IP22 612 depends on SGI_HAS_INDYDOG
590 help 613 help
591 Hardware driver for the Indy's/I2's watchdog. This is a 614 Hardware driver for the Indy's/I2's watchdog. This is a
592 watchdog timer that will reboot the machine after a 60 second 615 watchdog timer that will reboot the machine after a 60 second
@@ -616,6 +639,12 @@ config AR7_WDT
616 help 639 help
617 Hardware driver for the TI AR7 Watchdog Timer. 640 Hardware driver for the TI AR7 Watchdog Timer.
618 641
642config TXX9_WDT
643 tristate "Toshiba TXx9 Watchdog Timer"
644 depends on CPU_TX39XX || CPU_TX49XX
645 help
646 Hardware driver for the built-in watchdog timer on TXx9 MIPS SoCs.
647
619# PARISC Architecture 648# PARISC Architecture
620 649
621# POWERPC Architecture 650# POWERPC Architecture
diff --git a/drivers/watchdog/Makefile b/drivers/watchdog/Makefile
index 7d9e5734f8bb..ebc21146d40c 100644
--- a/drivers/watchdog/Makefile
+++ b/drivers/watchdog/Makefile
@@ -66,11 +66,13 @@ obj-$(CONFIG_IBMASR) += ibmasr.o
66obj-$(CONFIG_WAFER_WDT) += wafer5823wdt.o 66obj-$(CONFIG_WAFER_WDT) += wafer5823wdt.o
67obj-$(CONFIG_I6300ESB_WDT) += i6300esb.o 67obj-$(CONFIG_I6300ESB_WDT) += i6300esb.o
68obj-$(CONFIG_ITCO_WDT) += iTCO_wdt.o iTCO_vendor_support.o 68obj-$(CONFIG_ITCO_WDT) += iTCO_wdt.o iTCO_vendor_support.o
69obj-$(CONFIG_IT8712F_WDT) += it8712f_wdt.o
69obj-$(CONFIG_SC1200_WDT) += sc1200wdt.o 70obj-$(CONFIG_SC1200_WDT) += sc1200wdt.o
70obj-$(CONFIG_SCx200_WDT) += scx200_wdt.o 71obj-$(CONFIG_SCx200_WDT) += scx200_wdt.o
71obj-$(CONFIG_PC87413_WDT) += pc87413_wdt.o 72obj-$(CONFIG_PC87413_WDT) += pc87413_wdt.o
72obj-$(CONFIG_60XX_WDT) += sbc60xxwdt.o 73obj-$(CONFIG_60XX_WDT) += sbc60xxwdt.o
73obj-$(CONFIG_SBC8360_WDT) += sbc8360.o 74obj-$(CONFIG_SBC8360_WDT) += sbc8360.o
75obj-$(CONFIG_SBC7240_WDT) += sbc7240_wdt.o
74obj-$(CONFIG_CPU5_WDT) += cpu5wdt.o 76obj-$(CONFIG_CPU5_WDT) += cpu5wdt.o
75obj-$(CONFIG_SMSC37B787_WDT) += smsc37b787_wdt.o 77obj-$(CONFIG_SMSC37B787_WDT) += smsc37b787_wdt.o
76obj-$(CONFIG_W83627HF_WDT) += w83627hf_wdt.o 78obj-$(CONFIG_W83627HF_WDT) += w83627hf_wdt.o
@@ -91,6 +93,7 @@ obj-$(CONFIG_INDYDOG) += indydog.o
91obj-$(CONFIG_WDT_MTX1) += mtx-1_wdt.o 93obj-$(CONFIG_WDT_MTX1) += mtx-1_wdt.o
92obj-$(CONFIG_WDT_RM9K_GPI) += rm9k_wdt.o 94obj-$(CONFIG_WDT_RM9K_GPI) += rm9k_wdt.o
93obj-$(CONFIG_AR7_WDT) += ar7_wdt.o 95obj-$(CONFIG_AR7_WDT) += ar7_wdt.o
96obj-$(CONFIG_TXX9_WDT) += txx9wdt.o
94 97
95# PARISC Architecture 98# PARISC Architecture
96 99
diff --git a/drivers/watchdog/alim1535_wdt.c b/drivers/watchdog/alim1535_wdt.c
index b481cc0e32e4..2b1fbdb2fcf7 100644
--- a/drivers/watchdog/alim1535_wdt.c
+++ b/drivers/watchdog/alim1535_wdt.c
@@ -413,18 +413,18 @@ static int __init watchdog_init(void)
413 /* Calculate the watchdog's timeout */ 413 /* Calculate the watchdog's timeout */
414 ali_settimer(timeout); 414 ali_settimer(timeout);
415 415
416 ret = misc_register(&ali_miscdev); 416 ret = register_reboot_notifier(&ali_notifier);
417 if (ret != 0) { 417 if (ret != 0) {
418 printk(KERN_ERR PFX "cannot register miscdev on minor=%d (err=%d)\n", 418 printk(KERN_ERR PFX "cannot register reboot notifier (err=%d)\n",
419 WATCHDOG_MINOR, ret); 419 ret);
420 goto out; 420 goto out;
421 } 421 }
422 422
423 ret = register_reboot_notifier(&ali_notifier); 423 ret = misc_register(&ali_miscdev);
424 if (ret != 0) { 424 if (ret != 0) {
425 printk(KERN_ERR PFX "cannot register reboot notifier (err=%d)\n", 425 printk(KERN_ERR PFX "cannot register miscdev on minor=%d (err=%d)\n",
426 ret); 426 WATCHDOG_MINOR, ret);
427 goto unreg_miscdev; 427 goto unreg_reboot;
428 } 428 }
429 429
430 printk(KERN_INFO PFX "initialized. timeout=%d sec (nowayout=%d)\n", 430 printk(KERN_INFO PFX "initialized. timeout=%d sec (nowayout=%d)\n",
@@ -432,8 +432,8 @@ static int __init watchdog_init(void)
432 432
433out: 433out:
434 return ret; 434 return ret;
435unreg_miscdev: 435unreg_reboot:
436 misc_deregister(&ali_miscdev); 436 unregister_reboot_notifier(&ali_notifier);
437 goto out; 437 goto out;
438} 438}
439 439
@@ -449,8 +449,8 @@ static void __exit watchdog_exit(void)
449 ali_stop(); 449 ali_stop();
450 450
451 /* Deregister */ 451 /* Deregister */
452 unregister_reboot_notifier(&ali_notifier);
453 misc_deregister(&ali_miscdev); 452 misc_deregister(&ali_miscdev);
453 unregister_reboot_notifier(&ali_notifier);
454 pci_dev_put(ali_pci); 454 pci_dev_put(ali_pci);
455} 455}
456 456
diff --git a/drivers/watchdog/alim7101_wdt.c b/drivers/watchdog/alim7101_wdt.c
index 67aed9f8c362..238273c98656 100644
--- a/drivers/watchdog/alim7101_wdt.c
+++ b/drivers/watchdog/alim7101_wdt.c
@@ -377,18 +377,18 @@ static int __init alim7101_wdt_init(void)
377 timeout); 377 timeout);
378 } 378 }
379 379
380 rc = misc_register(&wdt_miscdev); 380 rc = register_reboot_notifier(&wdt_notifier);
381 if (rc) { 381 if (rc) {
382 printk(KERN_ERR PFX "cannot register miscdev on minor=%d (err=%d)\n", 382 printk(KERN_ERR PFX "cannot register reboot notifier (err=%d)\n",
383 wdt_miscdev.minor, rc); 383 rc);
384 goto err_out; 384 goto err_out;
385 } 385 }
386 386
387 rc = register_reboot_notifier(&wdt_notifier); 387 rc = misc_register(&wdt_miscdev);
388 if (rc) { 388 if (rc) {
389 printk(KERN_ERR PFX "cannot register reboot notifier (err=%d)\n", 389 printk(KERN_ERR PFX "cannot register miscdev on minor=%d (err=%d)\n",
390 rc); 390 wdt_miscdev.minor, rc);
391 goto err_out_miscdev; 391 goto err_out_reboot;
392 } 392 }
393 393
394 if (nowayout) { 394 if (nowayout) {
@@ -399,8 +399,8 @@ static int __init alim7101_wdt_init(void)
399 timeout, nowayout); 399 timeout, nowayout);
400 return 0; 400 return 0;
401 401
402err_out_miscdev: 402err_out_reboot:
403 misc_deregister(&wdt_miscdev); 403 unregister_reboot_notifier(&wdt_notifier);
404err_out: 404err_out:
405 pci_dev_put(alim7101_pmu); 405 pci_dev_put(alim7101_pmu);
406 return rc; 406 return rc;
diff --git a/drivers/watchdog/ar7_wdt.c b/drivers/watchdog/ar7_wdt.c
index cdaab8c3d3d0..2eb48c0df32c 100644
--- a/drivers/watchdog/ar7_wdt.c
+++ b/drivers/watchdog/ar7_wdt.c
@@ -279,7 +279,7 @@ static int ar7_wdt_ioctl(struct inode *inode, struct file *file,
279 } 279 }
280} 280}
281 281
282static struct file_operations ar7_wdt_fops = { 282static const struct file_operations ar7_wdt_fops = {
283 .owner = THIS_MODULE, 283 .owner = THIS_MODULE,
284 .write = ar7_wdt_write, 284 .write = ar7_wdt_write,
285 .ioctl = ar7_wdt_ioctl, 285 .ioctl = ar7_wdt_ioctl,
diff --git a/drivers/watchdog/at32ap700x_wdt.c b/drivers/watchdog/at32ap700x_wdt.c
index 54a516169d07..fb5ed6478f78 100644
--- a/drivers/watchdog/at32ap700x_wdt.c
+++ b/drivers/watchdog/at32ap700x_wdt.c
@@ -6,6 +6,19 @@
6 * This program is free software; you can redistribute it and/or modify 6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License version 2 as 7 * it under the terms of the GNU General Public License version 2 as
8 * published by the Free Software Foundation. 8 * published by the Free Software Foundation.
9 *
10 *
11 * Errata: WDT Clear is blocked after WDT Reset
12 *
13 * A watchdog timer event will, after reset, block writes to the WDT_CLEAR
14 * register, preventing the program to clear the next Watchdog Timer Reset.
15 *
16 * If you still want to use the WDT after a WDT reset a small code can be
17 * insterted at the startup checking the AVR32_PM.rcause register for WDT reset
18 * and use a GPIO pin to reset the system. This method requires that one of the
19 * GPIO pins are available and connected externally to the RESET_N pin. After
20 * the GPIO pin has pulled down the reset line the GPIO will be reset and leave
21 * the pin tristated with pullup.
9 */ 22 */
10 23
11#include <linux/init.h> 24#include <linux/init.h>
@@ -44,6 +57,13 @@ MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default="
44 57
45#define WDT_CLR 0x04 58#define WDT_CLR 0x04
46 59
60#define WDT_RCAUSE 0x10
61#define WDT_RCAUSE_POR 0
62#define WDT_RCAUSE_EXT 2
63#define WDT_RCAUSE_WDT 3
64#define WDT_RCAUSE_JTAG 4
65#define WDT_RCAUSE_SERP 5
66
47#define WDT_BIT(name) (1 << WDT_##name) 67#define WDT_BIT(name) (1 << WDT_##name)
48#define WDT_BF(name, value) ((value) << WDT_##name) 68#define WDT_BF(name, value) ((value) << WDT_##name)
49 69
@@ -56,6 +76,7 @@ struct wdt_at32ap700x {
56 void __iomem *regs; 76 void __iomem *regs;
57 spinlock_t io_lock; 77 spinlock_t io_lock;
58 int timeout; 78 int timeout;
79 int boot_status;
59 unsigned long users; 80 unsigned long users;
60 struct miscdevice miscdev; 81 struct miscdevice miscdev;
61}; 82};
@@ -126,7 +147,7 @@ static int at32_wdt_close(struct inode *inode, struct file *file)
126 at32_wdt_stop(); 147 at32_wdt_stop();
127 } else { 148 } else {
128 dev_dbg(wdt->miscdev.parent, 149 dev_dbg(wdt->miscdev.parent,
129 "Unexpected close, not stopping watchdog!\n"); 150 "unexpected close, not stopping watchdog!\n");
130 at32_wdt_pat(); 151 at32_wdt_pat();
131 } 152 }
132 clear_bit(1, &wdt->users); 153 clear_bit(1, &wdt->users);
@@ -154,6 +175,33 @@ static int at32_wdt_settimeout(int time)
154 return 0; 175 return 0;
155} 176}
156 177
178/*
179 * Get the watchdog status.
180 */
181static int at32_wdt_get_status(void)
182{
183 int rcause;
184 int status = 0;
185
186 rcause = wdt_readl(wdt, RCAUSE);
187
188 switch (rcause) {
189 case WDT_BIT(RCAUSE_EXT):
190 status = WDIOF_EXTERN1;
191 break;
192 case WDT_BIT(RCAUSE_WDT):
193 status = WDIOF_CARDRESET;
194 break;
195 case WDT_BIT(RCAUSE_POR): /* fall through */
196 case WDT_BIT(RCAUSE_JTAG): /* fall through */
197 case WDT_BIT(RCAUSE_SERP): /* fall through */
198 default:
199 break;
200 }
201
202 return status;
203}
204
157static struct watchdog_info at32_wdt_info = { 205static struct watchdog_info at32_wdt_info = {
158 .identity = "at32ap700x watchdog", 206 .identity = "at32ap700x watchdog",
159 .options = WDIOF_SETTIMEOUT | 207 .options = WDIOF_SETTIMEOUT |
@@ -194,10 +242,12 @@ static int at32_wdt_ioctl(struct inode *inode, struct file *file,
194 case WDIOC_GETTIMEOUT: 242 case WDIOC_GETTIMEOUT:
195 ret = put_user(wdt->timeout, p); 243 ret = put_user(wdt->timeout, p);
196 break; 244 break;
197 case WDIOC_GETSTATUS: /* fall through */ 245 case WDIOC_GETSTATUS:
198 case WDIOC_GETBOOTSTATUS:
199 ret = put_user(0, p); 246 ret = put_user(0, p);
200 break; 247 break;
248 case WDIOC_GETBOOTSTATUS:
249 ret = put_user(wdt->boot_status, p);
250 break;
201 case WDIOC_SETOPTIONS: 251 case WDIOC_SETOPTIONS:
202 ret = get_user(time, p); 252 ret = get_user(time, p);
203 if (ret) 253 if (ret)
@@ -282,8 +332,19 @@ static int __init at32_wdt_probe(struct platform_device *pdev)
282 dev_dbg(&pdev->dev, "could not map I/O memory\n"); 332 dev_dbg(&pdev->dev, "could not map I/O memory\n");
283 goto err_free; 333 goto err_free;
284 } 334 }
335
285 spin_lock_init(&wdt->io_lock); 336 spin_lock_init(&wdt->io_lock);
286 wdt->users = 0; 337 wdt->boot_status = at32_wdt_get_status();
338
339 /* Work-around for watchdog silicon errata. */
340 if (wdt->boot_status & WDIOF_CARDRESET) {
341 dev_info(&pdev->dev, "CPU must be reset with external "
342 "reset or POR due to silicon errata.\n");
343 ret = -EIO;
344 goto err_iounmap;
345 } else {
346 wdt->users = 0;
347 }
287 wdt->miscdev.minor = WATCHDOG_MINOR; 348 wdt->miscdev.minor = WATCHDOG_MINOR;
288 wdt->miscdev.name = "watchdog"; 349 wdt->miscdev.name = "watchdog";
289 wdt->miscdev.fops = &at32_wdt_fops; 350 wdt->miscdev.fops = &at32_wdt_fops;
diff --git a/drivers/watchdog/bfin_wdt.c b/drivers/watchdog/bfin_wdt.c
index 309d27913fc1..472be10f0686 100644
--- a/drivers/watchdog/bfin_wdt.c
+++ b/drivers/watchdog/bfin_wdt.c
@@ -71,7 +71,7 @@ static int nowayout = WATCHDOG_NOWAYOUT;
71static struct watchdog_info bfin_wdt_info; 71static struct watchdog_info bfin_wdt_info;
72static unsigned long open_check; 72static unsigned long open_check;
73static char expect_close; 73static char expect_close;
74static spinlock_t bfin_wdt_spinlock = SPIN_LOCK_UNLOCKED; 74static DEFINE_SPINLOCK(bfin_wdt_spinlock);
75 75
76/** 76/**
77 * bfin_wdt_keepalive - Keep the Userspace Watchdog Alive 77 * bfin_wdt_keepalive - Keep the Userspace Watchdog Alive
@@ -390,7 +390,7 @@ static struct platform_driver bfin_wdt_driver = {
390 .resume = bfin_wdt_resume, 390 .resume = bfin_wdt_resume,
391}; 391};
392 392
393static struct file_operations bfin_wdt_fops = { 393static const struct file_operations bfin_wdt_fops = {
394 .owner = THIS_MODULE, 394 .owner = THIS_MODULE,
395 .llseek = no_llseek, 395 .llseek = no_llseek,
396 .write = bfin_wdt_write, 396 .write = bfin_wdt_write,
diff --git a/drivers/watchdog/it8712f_wdt.c b/drivers/watchdog/it8712f_wdt.c
new file mode 100644
index 000000000000..1b6d7d1b715d
--- /dev/null
+++ b/drivers/watchdog/it8712f_wdt.c
@@ -0,0 +1,400 @@
1/*
2 * IT8712F "Smart Guardian" Watchdog support
3 *
4 * Copyright (c) 2006-2007 Jorge Boncompte - DTI2 <jorge@dti2.net>
5 *
6 * Based on info and code taken from:
7 *
8 * drivers/char/watchdog/scx200_wdt.c
9 * drivers/hwmon/it87.c
10 * IT8712F EC-LPC I/O Preliminary Specification 0.9.2.pdf
11 *
12 * This program is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU General Public License as
14 * published by the Free Software Foundation; either version 2 of the
15 * License, or (at your option) any later version.
16 *
17 * The author(s) of this software shall not be held liable for damages
18 * of any nature resulting due to the use of this software. This
19 * software is provided AS-IS with no warranties.
20 */
21
22#include <linux/module.h>
23#include <linux/moduleparam.h>
24#include <linux/init.h>
25#include <linux/miscdevice.h>
26#include <linux/watchdog.h>
27#include <linux/notifier.h>
28#include <linux/reboot.h>
29#include <linux/fs.h>
30#include <linux/pci.h>
31#include <linux/spinlock.h>
32
33#include <asm/uaccess.h>
34#include <asm/io.h>
35
36#define NAME "it8712f_wdt"
37
38MODULE_AUTHOR("Jorge Boncompte - DTI2 <jorge@dti2.net>");
39MODULE_DESCRIPTION("IT8712F Watchdog Driver");
40MODULE_LICENSE("GPL");
41MODULE_ALIAS_MISCDEV(WATCHDOG_MINOR);
42
43static int margin = 60; /* in seconds */
44module_param(margin, int, 0);
45MODULE_PARM_DESC(margin, "Watchdog margin in seconds");
46
47static int nowayout = WATCHDOG_NOWAYOUT;
48module_param(nowayout, int, 0);
49MODULE_PARM_DESC(nowayout, "Disable watchdog shutdown on close");
50
51static struct semaphore it8712f_wdt_sem;
52static unsigned expect_close;
53static spinlock_t io_lock;
54
55/* Dog Food address - We use the game port address */
56static unsigned short address;
57
58#define REG 0x2e /* The register to read/write */
59#define VAL 0x2f /* The value to read/write */
60
61#define LDN 0x07 /* Register: Logical device select */
62#define DEVID 0x20 /* Register: Device ID */
63#define DEVREV 0x22 /* Register: Device Revision */
64#define ACT_REG 0x30 /* LDN Register: Activation */
65#define BASE_REG 0x60 /* LDN Register: Base address */
66
67#define IT8712F_DEVID 0x8712
68
69#define LDN_GPIO 0x07 /* GPIO and Watch Dog Timer */
70#define LDN_GAME 0x09 /* Game Port */
71
72#define WDT_CONTROL 0x71 /* WDT Register: Control */
73#define WDT_CONFIG 0x72 /* WDT Register: Configuration */
74#define WDT_TIMEOUT 0x73 /* WDT Register: Timeout Value */
75
76#define WDT_RESET_GAME 0x10
77#define WDT_RESET_KBD 0x20
78#define WDT_RESET_MOUSE 0x40
79#define WDT_RESET_CIR 0x80
80
81#define WDT_UNIT_SEC 0x80 /* If 0 in MINUTES */
82
83#define WDT_OUT_PWROK 0x10
84#define WDT_OUT_KRST 0x40
85
86static int
87superio_inb(int reg)
88{
89 outb(reg, REG);
90 return inb(VAL);
91}
92
93static void
94superio_outb(int val, int reg)
95{
96 outb(reg, REG);
97 outb(val, VAL);
98}
99
100static int
101superio_inw(int reg)
102{
103 int val;
104 outb(reg++, REG);
105 val = inb(VAL) << 8;
106 outb(reg, REG);
107 val |= inb(VAL);
108 return val;
109}
110
111static inline void
112superio_select(int ldn)
113{
114 outb(LDN, REG);
115 outb(ldn, VAL);
116}
117
118static inline void
119superio_enter(void)
120{
121 spin_lock(&io_lock);
122 outb(0x87, REG);
123 outb(0x01, REG);
124 outb(0x55, REG);
125 outb(0x55, REG);
126}
127
128static inline void
129superio_exit(void)
130{
131 outb(0x02, REG);
132 outb(0x02, VAL);
133 spin_unlock(&io_lock);
134}
135
136static inline void
137it8712f_wdt_ping(void)
138{
139 inb(address);
140}
141
142static void
143it8712f_wdt_update_margin(void)
144{
145 int config = WDT_OUT_KRST | WDT_OUT_PWROK;
146
147 printk(KERN_INFO NAME ": timer margin %d seconds\n", margin);
148
149 /* The timeout register only has 8bits wide */
150 if (margin < 256)
151 config |= WDT_UNIT_SEC; /* else UNIT are MINUTES */
152 superio_outb(config, WDT_CONFIG);
153
154 superio_outb((margin > 255) ? (margin / 60) : margin, WDT_TIMEOUT);
155}
156
157static void
158it8712f_wdt_enable(void)
159{
160 printk(KERN_DEBUG NAME ": enabling watchdog timer\n");
161 superio_enter();
162 superio_select(LDN_GPIO);
163
164 superio_outb(WDT_RESET_GAME, WDT_CONTROL);
165
166 it8712f_wdt_update_margin();
167
168 superio_exit();
169
170 it8712f_wdt_ping();
171}
172
173static void
174it8712f_wdt_disable(void)
175{
176 printk(KERN_DEBUG NAME ": disabling watchdog timer\n");
177
178 superio_enter();
179 superio_select(LDN_GPIO);
180
181 superio_outb(0, WDT_CONFIG);
182 superio_outb(0, WDT_CONTROL);
183 superio_outb(0, WDT_TIMEOUT);
184
185 superio_exit();
186}
187
188static int
189it8712f_wdt_notify(struct notifier_block *this,
190 unsigned long code, void *unused)
191{
192 if (code == SYS_HALT || code == SYS_POWER_OFF)
193 if (!nowayout)
194 it8712f_wdt_disable();
195
196 return NOTIFY_DONE;
197}
198
199static struct notifier_block it8712f_wdt_notifier = {
200 .notifier_call = it8712f_wdt_notify,
201};
202
203static ssize_t
204it8712f_wdt_write(struct file *file, const char __user *data,
205 size_t len, loff_t *ppos)
206{
207 /* check for a magic close character */
208 if (len) {
209 size_t i;
210
211 it8712f_wdt_ping();
212
213 expect_close = 0;
214 for (i = 0; i < len; ++i) {
215 char c;
216 if (get_user(c, data+i))
217 return -EFAULT;
218 if (c == 'V')
219 expect_close = 42;
220 }
221 }
222
223 return len;
224}
225
226static int
227it8712f_wdt_ioctl(struct inode *inode, struct file *file,
228 unsigned int cmd, unsigned long arg)
229{
230 void __user *argp = (void __user *)arg;
231 int __user *p = argp;
232 static struct watchdog_info ident = {
233 .identity = "IT8712F Watchdog",
234 .firmware_version = 1,
235 .options = WDIOF_SETTIMEOUT | WDIOF_KEEPALIVEPING,
236 };
237 int new_margin;
238
239 switch (cmd) {
240 default:
241 return -ENOTTY;
242 case WDIOC_GETSUPPORT:
243 if (copy_to_user(argp, &ident, sizeof(ident)))
244 return -EFAULT;
245 return 0;
246 case WDIOC_GETSTATUS:
247 case WDIOC_GETBOOTSTATUS:
248 return put_user(0, p);
249 case WDIOC_KEEPALIVE:
250 it8712f_wdt_ping();
251 return 0;
252 case WDIOC_SETTIMEOUT:
253 if (get_user(new_margin, p))
254 return -EFAULT;
255 if (new_margin < 1)
256 return -EINVAL;
257 margin = new_margin;
258 superio_enter();
259 superio_select(LDN_GPIO);
260
261 it8712f_wdt_update_margin();
262
263 superio_exit();
264 it8712f_wdt_ping();
265 case WDIOC_GETTIMEOUT:
266 if (put_user(margin, p))
267 return -EFAULT;
268 return 0;
269 }
270}
271
272static int
273it8712f_wdt_open(struct inode *inode, struct file *file)
274{
275 /* only allow one at a time */
276 if (down_trylock(&it8712f_wdt_sem))
277 return -EBUSY;
278 it8712f_wdt_enable();
279
280 return nonseekable_open(inode, file);
281}
282
283static int
284it8712f_wdt_release(struct inode *inode, struct file *file)
285{
286 if (expect_close != 42) {
287 printk(KERN_WARNING NAME
288 ": watchdog device closed unexpectedly, will not"
289 " disable the watchdog timer\n");
290 } else if (!nowayout) {
291 it8712f_wdt_disable();
292 }
293 expect_close = 0;
294 up(&it8712f_wdt_sem);
295
296 return 0;
297}
298
299static const struct file_operations it8712f_wdt_fops = {
300 .owner = THIS_MODULE,
301 .llseek = no_llseek,
302 .write = it8712f_wdt_write,
303 .ioctl = it8712f_wdt_ioctl,
304 .open = it8712f_wdt_open,
305 .release = it8712f_wdt_release,
306};
307
308static struct miscdevice it8712f_wdt_miscdev = {
309 .minor = WATCHDOG_MINOR,
310 .name = "watchdog",
311 .fops = &it8712f_wdt_fops,
312};
313
314static int __init
315it8712f_wdt_find(unsigned short *address)
316{
317 int err = -ENODEV;
318 int chip_type;
319
320 superio_enter();
321 chip_type = superio_inw(DEVID);
322 if (chip_type != IT8712F_DEVID)
323 goto exit;
324
325 superio_select(LDN_GAME);
326 superio_outb(1, ACT_REG);
327 if (!(superio_inb(ACT_REG) & 0x01)) {
328 printk(KERN_ERR NAME ": Device not activated, skipping\n");
329 goto exit;
330 }
331
332 *address = superio_inw(BASE_REG);
333 if (*address == 0) {
334 printk(KERN_ERR NAME ": Base address not set, skipping\n");
335 goto exit;
336 }
337
338 err = 0;
339 printk(KERN_DEBUG NAME ": Found IT%04xF chip revision %d - "
340 "using DogFood address 0x%x\n",
341 chip_type, superio_inb(DEVREV) & 0x0f, *address);
342
343exit:
344 superio_exit();
345 return err;
346}
347
348static int __init
349it8712f_wdt_init(void)
350{
351 int err = 0;
352
353 spin_lock_init(&io_lock);
354
355 if (it8712f_wdt_find(&address))
356 return -ENODEV;
357
358 if (!request_region(address, 1, "IT8712F Watchdog")) {
359 printk(KERN_WARNING NAME ": watchdog I/O region busy\n");
360 return -EBUSY;
361 }
362
363 it8712f_wdt_disable();
364
365 sema_init(&it8712f_wdt_sem, 1);
366
367 err = register_reboot_notifier(&it8712f_wdt_notifier);
368 if (err) {
369 printk(KERN_ERR NAME ": unable to register reboot notifier\n");
370 goto out;
371 }
372
373 err = misc_register(&it8712f_wdt_miscdev);
374 if (err) {
375 printk(KERN_ERR NAME
376 ": cannot register miscdev on minor=%d (err=%d)\n",
377 WATCHDOG_MINOR, err);
378 goto reboot_out;
379 }
380
381 return 0;
382
383
384reboot_out:
385 unregister_reboot_notifier(&it8712f_wdt_notifier);
386out:
387 release_region(address, 1);
388 return err;
389}
390
391static void __exit
392it8712f_wdt_exit(void)
393{
394 misc_deregister(&it8712f_wdt_miscdev);
395 unregister_reboot_notifier(&it8712f_wdt_notifier);
396 release_region(address, 1);
397}
398
399module_init(it8712f_wdt_init);
400module_exit(it8712f_wdt_exit);
diff --git a/drivers/watchdog/mpc5200_wdt.c b/drivers/watchdog/mpc5200_wdt.c
index 11f6a111e75b..80a91d4cea11 100644
--- a/drivers/watchdog/mpc5200_wdt.c
+++ b/drivers/watchdog/mpc5200_wdt.c
@@ -158,7 +158,7 @@ static int mpc5200_wdt_release(struct inode *inode, struct file *file)
158 return 0; 158 return 0;
159} 159}
160 160
161static struct file_operations mpc5200_wdt_fops = { 161static const struct file_operations mpc5200_wdt_fops = {
162 .owner = THIS_MODULE, 162 .owner = THIS_MODULE,
163 .write = mpc5200_wdt_write, 163 .write = mpc5200_wdt_write,
164 .ioctl = mpc5200_wdt_ioctl, 164 .ioctl = mpc5200_wdt_ioctl,
diff --git a/drivers/watchdog/mtx-1_wdt.c b/drivers/watchdog/mtx-1_wdt.c
index dcfd401a7ad7..98451747d3cd 100644
--- a/drivers/watchdog/mtx-1_wdt.c
+++ b/drivers/watchdog/mtx-1_wdt.c
@@ -180,7 +180,7 @@ static ssize_t mtx1_wdt_write(struct file *file, const char *buf, size_t count,
180 return count; 180 return count;
181} 181}
182 182
183static struct file_operations mtx1_wdt_fops = { 183static const struct file_operations mtx1_wdt_fops = {
184 .owner = THIS_MODULE, 184 .owner = THIS_MODULE,
185 .llseek = no_llseek, 185 .llseek = no_llseek,
186 .ioctl = mtx1_wdt_ioctl, 186 .ioctl = mtx1_wdt_ioctl,
diff --git a/drivers/watchdog/sbc60xxwdt.c b/drivers/watchdog/sbc60xxwdt.c
index e4f3cb6090bc..ef76f01625e7 100644
--- a/drivers/watchdog/sbc60xxwdt.c
+++ b/drivers/watchdog/sbc60xxwdt.c
@@ -359,20 +359,20 @@ static int __init sbc60xxwdt_init(void)
359 } 359 }
360 } 360 }
361 361
362 rc = misc_register(&wdt_miscdev); 362 rc = register_reboot_notifier(&wdt_notifier);
363 if (rc) 363 if (rc)
364 { 364 {
365 printk(KERN_ERR PFX "cannot register miscdev on minor=%d (err=%d)\n", 365 printk(KERN_ERR PFX "cannot register reboot notifier (err=%d)\n",
366 wdt_miscdev.minor, rc); 366 rc);
367 goto err_out_region2; 367 goto err_out_region2;
368 } 368 }
369 369
370 rc = register_reboot_notifier(&wdt_notifier); 370 rc = misc_register(&wdt_miscdev);
371 if (rc) 371 if (rc)
372 { 372 {
373 printk(KERN_ERR PFX "cannot register reboot notifier (err=%d)\n", 373 printk(KERN_ERR PFX "cannot register miscdev on minor=%d (err=%d)\n",
374 rc); 374 wdt_miscdev.minor, rc);
375 goto err_out_miscdev; 375 goto err_out_reboot;
376 } 376 }
377 377
378 printk(KERN_INFO PFX "WDT driver for 60XX single board computer initialised. timeout=%d sec (nowayout=%d)\n", 378 printk(KERN_INFO PFX "WDT driver for 60XX single board computer initialised. timeout=%d sec (nowayout=%d)\n",
@@ -380,8 +380,8 @@ static int __init sbc60xxwdt_init(void)
380 380
381 return 0; 381 return 0;
382 382
383err_out_miscdev: 383err_out_reboot:
384 misc_deregister(&wdt_miscdev); 384 unregister_reboot_notifier(&wdt_notifier);
385err_out_region2: 385err_out_region2:
386 if ((wdt_stop != 0x45) && (wdt_stop != wdt_start)) 386 if ((wdt_stop != 0x45) && (wdt_stop != wdt_start))
387 release_region(wdt_stop,1); 387 release_region(wdt_stop,1);
diff --git a/drivers/watchdog/sbc7240_wdt.c b/drivers/watchdog/sbc7240_wdt.c
new file mode 100644
index 000000000000..4c8cefbd8627
--- /dev/null
+++ b/drivers/watchdog/sbc7240_wdt.c
@@ -0,0 +1,324 @@
1/*
2 * NANO7240 SBC Watchdog device driver
3 *
4 * Based on w83877f.c by Scott Jennings,
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License version 2 as
8 * published by the Free Software Foundation;
9 *
10 * Software distributed under the License is distributed on an "AS IS"
11 * basis, WITHOUT WARRANTY OF ANY KIND, either express or
12 * implied. See the License for the specific language governing
13 * rights and limitations under the License.
14 *
15 * (c) Copyright 2007 Gilles GIGAN <gilles.gigan@jcu.edu.au>
16 *
17 */
18
19#include <linux/fs.h>
20#include <linux/init.h>
21#include <linux/ioport.h>
22#include <linux/jiffies.h>
23#include <linux/module.h>
24#include <linux/moduleparam.h>
25#include <linux/miscdevice.h>
26#include <linux/notifier.h>
27#include <linux/reboot.h>
28#include <linux/types.h>
29#include <linux/watchdog.h>
30#include <asm/atomic.h>
31#include <asm/io.h>
32#include <asm/system.h>
33#include <asm/uaccess.h>
34
35#define SBC7240_PREFIX "sbc7240_wdt: "
36
37#define SBC7240_ENABLE_PORT 0x443
38#define SBC7240_DISABLE_PORT 0x043
39#define SBC7240_SET_TIMEOUT_PORT SBC7240_ENABLE_PORT
40#define SBC7240_MAGIC_CHAR 'V'
41
42#define SBC7240_TIMEOUT 30
43#define SBC7240_MAX_TIMEOUT 255
44static int timeout = SBC7240_TIMEOUT; /* in seconds */
45module_param(timeout, int, 0);
46MODULE_PARM_DESC(timeout, "Watchdog timeout in seconds. (1<=timeout<="
47 __MODULE_STRING(SBC7240_MAX_TIMEOUT) ", default="
48 __MODULE_STRING(SBC7240_TIMEOUT) ")");
49
50static int nowayout = WATCHDOG_NOWAYOUT;
51module_param(nowayout, int, 0);
52MODULE_PARM_DESC(nowayout, "Disable watchdog when closing device file");
53
54#define SBC7240_OPEN_STATUS_BIT 0
55#define SBC7240_ENABLED_STATUS_BIT 1
56#define SBC7240_EXPECT_CLOSE_STATUS_BIT 2
57static unsigned long wdt_status;
58
59/*
60 * Utility routines
61 */
62
63static void wdt_disable(void)
64{
65 /* disable the watchdog */
66 if (test_and_clear_bit(SBC7240_ENABLED_STATUS_BIT, &wdt_status)) {
67 inb_p(SBC7240_DISABLE_PORT);
68 printk(KERN_INFO SBC7240_PREFIX
69 "Watchdog timer is now disabled.\n");
70 }
71}
72
73static void wdt_enable(void)
74{
75 /* enable the watchdog */
76 if (!test_and_set_bit(SBC7240_ENABLED_STATUS_BIT, &wdt_status)) {
77 inb_p(SBC7240_ENABLE_PORT);
78 printk(KERN_INFO SBC7240_PREFIX
79 "Watchdog timer is now enabled.\n");
80 }
81}
82
83static int wdt_set_timeout(int t)
84{
85 if (t < 1 || t > SBC7240_MAX_TIMEOUT) {
86 printk(KERN_ERR SBC7240_PREFIX
87 "timeout value must be 1<=x<=%d\n",
88 SBC7240_MAX_TIMEOUT);
89 return -1;
90 }
91 /* set the timeout */
92 outb_p((unsigned)t, SBC7240_SET_TIMEOUT_PORT);
93 timeout = t;
94 printk(KERN_INFO SBC7240_PREFIX "timeout set to %d seconds\n", t);
95 return 0;
96}
97
98/* Whack the dog */
99static inline void wdt_keepalive(void)
100{
101 if (test_bit(SBC7240_ENABLED_STATUS_BIT, &wdt_status))
102 inb_p(SBC7240_ENABLE_PORT);
103}
104
105/*
106 * /dev/watchdog handling
107 */
108static ssize_t fop_write(struct file *file, const char __user *buf,
109 size_t count, loff_t *ppos)
110{
111 size_t i;
112 char c;
113
114 if (count) {
115 if (!nowayout) {
116 clear_bit(SBC7240_EXPECT_CLOSE_STATUS_BIT,
117 &wdt_status);
118
119 /* is there a magic char ? */
120 for (i = 0; i != count; i++) {
121 if (get_user(c, buf + i))
122 return -EFAULT;
123 if (c == SBC7240_MAGIC_CHAR) {
124 set_bit(SBC7240_EXPECT_CLOSE_STATUS_BIT,
125 &wdt_status);
126 break;
127 }
128 }
129 }
130
131 wdt_keepalive();
132 }
133
134 return count;
135}
136
137static int fop_open(struct inode *inode, struct file *file)
138{
139 if (test_and_set_bit(SBC7240_OPEN_STATUS_BIT, &wdt_status))
140 return -EBUSY;
141
142 wdt_enable();
143
144 return nonseekable_open(inode, file);
145}
146
147static int fop_close(struct inode *inode, struct file *file)
148{
149 if (test_and_clear_bit(SBC7240_EXPECT_CLOSE_STATUS_BIT, &wdt_status)
150 || !nowayout) {
151 wdt_disable();
152 } else {
153 printk(KERN_CRIT SBC7240_PREFIX
154 "Unexpected close, not stopping watchdog!\n");
155 wdt_keepalive();
156 }
157
158 clear_bit(SBC7240_OPEN_STATUS_BIT, &wdt_status);
159 return 0;
160}
161
162static struct watchdog_info ident = {
163 .options = WDIOF_KEEPALIVEPING|
164 WDIOF_SETTIMEOUT|
165 WDIOF_MAGICCLOSE,
166 .firmware_version = 1,
167 .identity = "SBC7240",
168};
169
170
171static int fop_ioctl(struct inode *inode, struct file *file, unsigned int cmd,
172 unsigned long arg)
173{
174 switch (cmd) {
175 case WDIOC_GETSUPPORT:
176 return copy_to_user
177 ((void __user *)arg, &ident, sizeof(ident))
178 ? -EFAULT : 0;
179 case WDIOC_GETSTATUS:
180 case WDIOC_GETBOOTSTATUS:
181 return put_user(0, (int __user *)arg);
182 case WDIOC_KEEPALIVE:
183 wdt_keepalive();
184 return 0;
185 case WDIOC_SETOPTIONS:{
186 int options;
187 int retval = -EINVAL;
188
189 if (get_user(options, (int __user *)arg))
190 return -EFAULT;
191
192 if (options & WDIOS_DISABLECARD) {
193 wdt_disable();
194 retval = 0;
195 }
196
197 if (options & WDIOS_ENABLECARD) {
198 wdt_enable();
199 retval = 0;
200 }
201
202 return retval;
203 }
204 case WDIOC_SETTIMEOUT:{
205 int new_timeout;
206
207 if (get_user(new_timeout, (int __user *)arg))
208 return -EFAULT;
209
210 if (wdt_set_timeout(new_timeout))
211 return -EINVAL;
212
213 /* Fall through */
214 }
215 case WDIOC_GETTIMEOUT:
216 return put_user(timeout, (int __user *)arg);
217 default:
218 return -ENOTTY;
219 }
220}
221
222static const struct file_operations wdt_fops = {
223 .owner = THIS_MODULE,
224 .llseek = no_llseek,
225 .write = fop_write,
226 .open = fop_open,
227 .release = fop_close,
228 .ioctl = fop_ioctl,
229};
230
231static struct miscdevice wdt_miscdev = {
232 .minor = WATCHDOG_MINOR,
233 .name = "watchdog",
234 .fops = &wdt_fops,
235};
236
237/*
238 * Notifier for system down
239 */
240
241static int wdt_notify_sys(struct notifier_block *this, unsigned long code,
242 void *unused)
243{
244 if (code == SYS_DOWN || code == SYS_HALT)
245 wdt_disable();
246 return NOTIFY_DONE;
247}
248
249static struct notifier_block wdt_notifier = {
250 .notifier_call = wdt_notify_sys,
251};
252
253static void __exit sbc7240_wdt_unload(void)
254{
255 printk(KERN_INFO SBC7240_PREFIX "Removing watchdog\n");
256 misc_deregister(&wdt_miscdev);
257
258 unregister_reboot_notifier(&wdt_notifier);
259 release_region(SBC7240_ENABLE_PORT, 1);
260}
261
262static int __init sbc7240_wdt_init(void)
263{
264 int rc = -EBUSY;
265
266 if (!request_region(SBC7240_ENABLE_PORT, 1, "SBC7240 WDT")) {
267 printk(KERN_ERR SBC7240_PREFIX
268 "I/O address 0x%04x already in use\n",
269 SBC7240_ENABLE_PORT);
270 rc = -EIO;
271 goto err_out;
272 }
273
274 /* The IO port 0x043 used to disable the watchdog
275 * is already claimed by the system timer, so we
276 * cant request_region() it ...*/
277
278 if (timeout < 1 || timeout > SBC7240_MAX_TIMEOUT) {
279 timeout = SBC7240_TIMEOUT;
280 printk(KERN_INFO SBC7240_PREFIX
281 "timeout value must be 1<=x<=%d, using %d\n",
282 SBC7240_MAX_TIMEOUT, timeout);
283 }
284 wdt_set_timeout(timeout);
285 wdt_disable();
286
287 rc = register_reboot_notifier(&wdt_notifier);
288 if (rc) {
289 printk(KERN_ERR SBC7240_PREFIX
290 "cannot register reboot notifier (err=%d)\n", rc);
291 goto err_out_region;
292 }
293
294 rc = misc_register(&wdt_miscdev);
295 if (rc) {
296 printk(KERN_ERR SBC7240_PREFIX
297 "cannot register miscdev on minor=%d (err=%d)\n",
298 wdt_miscdev.minor, rc);
299 goto err_out_reboot_notifier;
300 }
301
302 printk(KERN_INFO SBC7240_PREFIX
303 "Watchdog driver for SBC7240 initialised (nowayout=%d)\n",
304 nowayout);
305
306 return 0;
307
308err_out_reboot_notifier:
309 unregister_reboot_notifier(&wdt_notifier);
310err_out_region:
311 release_region(SBC7240_ENABLE_PORT, 1);
312err_out:
313 return rc;
314}
315
316module_init(sbc7240_wdt_init);
317module_exit(sbc7240_wdt_unload);
318
319MODULE_AUTHOR("Gilles Gigan");
320MODULE_DESCRIPTION("Watchdog device driver for single board"
321 " computers EPIC Nano 7240 from iEi");
322MODULE_LICENSE("GPL");
323MODULE_ALIAS_MISCDEV(WATCHDOG_MINOR);
324
diff --git a/drivers/watchdog/scx200_wdt.c b/drivers/watchdog/scx200_wdt.c
index d4fd0fa2f176..d55882bca319 100644
--- a/drivers/watchdog/scx200_wdt.c
+++ b/drivers/watchdog/scx200_wdt.c
@@ -231,17 +231,17 @@ static int __init scx200_wdt_init(void)
231 231
232 sema_init(&open_semaphore, 1); 232 sema_init(&open_semaphore, 1);
233 233
234 r = misc_register(&scx200_wdt_miscdev); 234 r = register_reboot_notifier(&scx200_wdt_notifier);
235 if (r) { 235 if (r) {
236 printk(KERN_ERR NAME ": unable to register reboot notifier");
236 release_region(scx200_cb_base + SCx200_WDT_OFFSET, 237 release_region(scx200_cb_base + SCx200_WDT_OFFSET,
237 SCx200_WDT_SIZE); 238 SCx200_WDT_SIZE);
238 return r; 239 return r;
239 } 240 }
240 241
241 r = register_reboot_notifier(&scx200_wdt_notifier); 242 r = misc_register(&scx200_wdt_miscdev);
242 if (r) { 243 if (r) {
243 printk(KERN_ERR NAME ": unable to register reboot notifier"); 244 unregister_reboot_notifier(&scx200_wdt_notifier);
244 misc_deregister(&scx200_wdt_miscdev);
245 release_region(scx200_cb_base + SCx200_WDT_OFFSET, 245 release_region(scx200_cb_base + SCx200_WDT_OFFSET,
246 SCx200_WDT_SIZE); 246 SCx200_WDT_SIZE);
247 return r; 247 return r;
@@ -252,8 +252,8 @@ static int __init scx200_wdt_init(void)
252 252
253static void __exit scx200_wdt_cleanup(void) 253static void __exit scx200_wdt_cleanup(void)
254{ 254{
255 unregister_reboot_notifier(&scx200_wdt_notifier);
256 misc_deregister(&scx200_wdt_miscdev); 255 misc_deregister(&scx200_wdt_miscdev);
256 unregister_reboot_notifier(&scx200_wdt_notifier);
257 release_region(scx200_cb_base + SCx200_WDT_OFFSET, 257 release_region(scx200_cb_base + SCx200_WDT_OFFSET,
258 SCx200_WDT_SIZE); 258 SCx200_WDT_SIZE);
259} 259}
diff --git a/drivers/watchdog/shwdt.c b/drivers/watchdog/shwdt.c
index cecbedd473a4..61dde863bd40 100644
--- a/drivers/watchdog/shwdt.c
+++ b/drivers/watchdog/shwdt.c
@@ -52,7 +52,7 @@
52 * overflow periods respectively. 52 * overflow periods respectively.
53 * 53 *
54 * Also, since we can't really expect userspace to be responsive enough 54 * Also, since we can't really expect userspace to be responsive enough
55 * before the overflow happens, we maintain two seperate timers .. One in 55 * before the overflow happens, we maintain two separate timers .. One in
56 * the kernel for clearing out WOVF every 2ms or so (again, this depends on 56 * the kernel for clearing out WOVF every 2ms or so (again, this depends on
57 * HZ == 1000), and another for monitoring userspace writes to the WDT device. 57 * HZ == 1000), and another for monitoring userspace writes to the WDT device.
58 * 58 *
diff --git a/drivers/watchdog/txx9wdt.c b/drivers/watchdog/txx9wdt.c
new file mode 100644
index 000000000000..328b3c7211ef
--- /dev/null
+++ b/drivers/watchdog/txx9wdt.c
@@ -0,0 +1,276 @@
1/*
2 * txx9wdt: A Hardware Watchdog Driver for TXx9 SoCs
3 *
4 * Copyright (C) 2007 Atsushi Nemoto <anemo@mba.ocn.ne.jp>
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License version 2 as
8 * published by the Free Software Foundation.
9 */
10#include <linux/module.h>
11#include <linux/moduleparam.h>
12#include <linux/types.h>
13#include <linux/miscdevice.h>
14#include <linux/watchdog.h>
15#include <linux/fs.h>
16#include <linux/reboot.h>
17#include <linux/init.h>
18#include <linux/uaccess.h>
19#include <linux/platform_device.h>
20#include <linux/clk.h>
21#include <linux/err.h>
22#include <linux/io.h>
23#include <asm/txx9tmr.h>
24
25#define TIMER_MARGIN 60 /* Default is 60 seconds */
26
27static int timeout = TIMER_MARGIN; /* in seconds */
28module_param(timeout, int, 0);
29MODULE_PARM_DESC(timeout,
30 "Watchdog timeout in seconds. "
31 "(0<timeout<((2^" __MODULE_STRING(TXX9_TIMER_BITS) ")/(IMCLK/256)), "
32 "default=" __MODULE_STRING(TIMER_MARGIN) ")");
33
34static int nowayout = WATCHDOG_NOWAYOUT;
35module_param(nowayout, int, 0);
36MODULE_PARM_DESC(nowayout,
37 "Watchdog cannot be stopped once started "
38 "(default=" __MODULE_STRING(WATCHDOG_NOWAYOUT) ")");
39
40#define WD_TIMER_CCD 7 /* 1/256 */
41#define WD_TIMER_CLK (clk_get_rate(txx9_imclk) / (2 << WD_TIMER_CCD))
42#define WD_MAX_TIMEOUT ((0xffffffff >> (32 - TXX9_TIMER_BITS)) / WD_TIMER_CLK)
43
44static unsigned long txx9wdt_alive;
45static int expect_close;
46static struct txx9_tmr_reg __iomem *txx9wdt_reg;
47static struct clk *txx9_imclk;
48
49static void txx9wdt_ping(void)
50{
51 __raw_writel(TXx9_TMWTMR_TWIE | TXx9_TMWTMR_TWC, &txx9wdt_reg->wtmr);
52}
53
54static void txx9wdt_start(void)
55{
56 __raw_writel(WD_TIMER_CLK * timeout, &txx9wdt_reg->cpra);
57 __raw_writel(WD_TIMER_CCD, &txx9wdt_reg->ccdr);
58 __raw_writel(0, &txx9wdt_reg->tisr); /* clear pending interrupt */
59 __raw_writel(TXx9_TMTCR_TCE | TXx9_TMTCR_CCDE | TXx9_TMTCR_TMODE_WDOG,
60 &txx9wdt_reg->tcr);
61 __raw_writel(TXx9_TMWTMR_TWIE | TXx9_TMWTMR_TWC, &txx9wdt_reg->wtmr);
62}
63
64static void txx9wdt_stop(void)
65{
66 __raw_writel(TXx9_TMWTMR_WDIS, &txx9wdt_reg->wtmr);
67 __raw_writel(__raw_readl(&txx9wdt_reg->tcr) & ~TXx9_TMTCR_TCE,
68 &txx9wdt_reg->tcr);
69}
70
71static int txx9wdt_open(struct inode *inode, struct file *file)
72{
73 if (test_and_set_bit(0, &txx9wdt_alive))
74 return -EBUSY;
75
76 if (__raw_readl(&txx9wdt_reg->tcr) & TXx9_TMTCR_TCE) {
77 clear_bit(0, &txx9wdt_alive);
78 return -EBUSY;
79 }
80
81 if (nowayout)
82 __module_get(THIS_MODULE);
83
84 txx9wdt_start();
85 return nonseekable_open(inode, file);
86}
87
88static int txx9wdt_release(struct inode *inode, struct file *file)
89{
90 if (expect_close)
91 txx9wdt_stop();
92 else {
93 printk(KERN_CRIT "txx9wdt: "
94 "Unexpected close, not stopping watchdog!\n");
95 txx9wdt_ping();
96 }
97 clear_bit(0, &txx9wdt_alive);
98 expect_close = 0;
99 return 0;
100}
101
102static ssize_t txx9wdt_write(struct file *file, const char __user *data,
103 size_t len, loff_t *ppos)
104{
105 if (len) {
106 if (!nowayout) {
107 size_t i;
108
109 expect_close = 0;
110 for (i = 0; i != len; i++) {
111 char c;
112 if (get_user(c, data + i))
113 return -EFAULT;
114 if (c == 'V')
115 expect_close = 1;
116 }
117 }
118 txx9wdt_ping();
119 }
120 return len;
121}
122
123static int txx9wdt_ioctl(struct inode *inode, struct file *file,
124 unsigned int cmd, unsigned long arg)
125{
126 void __user *argp = (void __user *)arg;
127 int __user *p = argp;
128 int new_timeout;
129 static struct watchdog_info ident = {
130 .options = WDIOF_SETTIMEOUT |
131 WDIOF_KEEPALIVEPING |
132 WDIOF_MAGICCLOSE,
133 .firmware_version = 0,
134 .identity = "Hardware Watchdog for TXx9",
135 };
136
137 switch (cmd) {
138 default:
139 return -ENOTTY;
140 case WDIOC_GETSUPPORT:
141 return copy_to_user(argp, &ident, sizeof(ident)) ? -EFAULT : 0;
142 case WDIOC_GETSTATUS:
143 case WDIOC_GETBOOTSTATUS:
144 return put_user(0, p);
145 case WDIOC_KEEPALIVE:
146 txx9wdt_ping();
147 return 0;
148 case WDIOC_SETTIMEOUT:
149 if (get_user(new_timeout, p))
150 return -EFAULT;
151 if (new_timeout < 1 || new_timeout > WD_MAX_TIMEOUT)
152 return -EINVAL;
153 timeout = new_timeout;
154 txx9wdt_stop();
155 txx9wdt_start();
156 /* Fall */
157 case WDIOC_GETTIMEOUT:
158 return put_user(timeout, p);
159 }
160}
161
162static int txx9wdt_notify_sys(struct notifier_block *this, unsigned long code,
163 void *unused)
164{
165 if (code == SYS_DOWN || code == SYS_HALT)
166 txx9wdt_stop();
167 return NOTIFY_DONE;
168}
169
170static const struct file_operations txx9wdt_fops = {
171 .owner = THIS_MODULE,
172 .llseek = no_llseek,
173 .write = txx9wdt_write,
174 .ioctl = txx9wdt_ioctl,
175 .open = txx9wdt_open,
176 .release = txx9wdt_release,
177};
178
179static struct miscdevice txx9wdt_miscdev = {
180 .minor = WATCHDOG_MINOR,
181 .name = "watchdog",
182 .fops = &txx9wdt_fops,
183};
184
185static struct notifier_block txx9wdt_notifier = {
186 .notifier_call = txx9wdt_notify_sys
187};
188
189static int __init txx9wdt_probe(struct platform_device *dev)
190{
191 struct resource *res;
192 int ret;
193
194 txx9_imclk = clk_get(NULL, "imbus_clk");
195 if (IS_ERR(txx9_imclk)) {
196 ret = PTR_ERR(txx9_imclk);
197 txx9_imclk = NULL;
198 goto exit;
199 }
200 ret = clk_enable(txx9_imclk);
201 if (ret) {
202 clk_put(txx9_imclk);
203 txx9_imclk = NULL;
204 goto exit;
205 }
206
207 res = platform_get_resource(dev, IORESOURCE_MEM, 0);
208 if (!res)
209 goto exit_busy;
210 if (!devm_request_mem_region(&dev->dev,
211 res->start, res->end - res->start + 1,
212 "txx9wdt"))
213 goto exit_busy;
214 txx9wdt_reg = devm_ioremap(&dev->dev,
215 res->start, res->end - res->start + 1);
216 if (!txx9wdt_reg)
217 goto exit_busy;
218
219 ret = register_reboot_notifier(&txx9wdt_notifier);
220 if (ret)
221 goto exit;
222
223 ret = misc_register(&txx9wdt_miscdev);
224 if (ret) {
225 unregister_reboot_notifier(&txx9wdt_notifier);
226 goto exit;
227 }
228
229 printk(KERN_INFO "Hardware Watchdog Timer for TXx9: "
230 "timeout=%d sec (max %ld) (nowayout= %d)\n",
231 timeout, WD_MAX_TIMEOUT, nowayout);
232
233 return 0;
234exit_busy:
235 ret = -EBUSY;
236exit:
237 if (txx9_imclk) {
238 clk_disable(txx9_imclk);
239 clk_put(txx9_imclk);
240 }
241 return ret;
242}
243
244static int __exit txx9wdt_remove(struct platform_device *dev)
245{
246 misc_deregister(&txx9wdt_miscdev);
247 unregister_reboot_notifier(&txx9wdt_notifier);
248 clk_disable(txx9_imclk);
249 clk_put(txx9_imclk);
250 return 0;
251}
252
253static struct platform_driver txx9wdt_driver = {
254 .remove = __exit_p(txx9wdt_remove),
255 .driver = {
256 .name = "txx9wdt",
257 .owner = THIS_MODULE,
258 },
259};
260
261static int __init watchdog_init(void)
262{
263 return platform_driver_probe(&txx9wdt_driver, txx9wdt_probe);
264}
265
266static void __exit watchdog_exit(void)
267{
268 platform_driver_unregister(&txx9wdt_driver);
269}
270
271module_init(watchdog_init);
272module_exit(watchdog_exit);
273
274MODULE_DESCRIPTION("TXx9 Watchdog Driver");
275MODULE_LICENSE("GPL");
276MODULE_ALIAS_MISCDEV(WATCHDOG_MINOR);
diff --git a/drivers/watchdog/w83877f_wdt.c b/drivers/watchdog/w83877f_wdt.c
index bcc9d48955de..f510a3a595e6 100644
--- a/drivers/watchdog/w83877f_wdt.c
+++ b/drivers/watchdog/w83877f_wdt.c
@@ -373,20 +373,20 @@ static int __init w83877f_wdt_init(void)
373 goto err_out_region1; 373 goto err_out_region1;
374 } 374 }
375 375
376 rc = misc_register(&wdt_miscdev); 376 rc = register_reboot_notifier(&wdt_notifier);
377 if (rc) 377 if (rc)
378 { 378 {
379 printk(KERN_ERR PFX "cannot register miscdev on minor=%d (err=%d)\n", 379 printk(KERN_ERR PFX "cannot register reboot notifier (err=%d)\n",
380 wdt_miscdev.minor, rc); 380 rc);
381 goto err_out_region2; 381 goto err_out_region2;
382 } 382 }
383 383
384 rc = register_reboot_notifier(&wdt_notifier); 384 rc = misc_register(&wdt_miscdev);
385 if (rc) 385 if (rc)
386 { 386 {
387 printk(KERN_ERR PFX "cannot register reboot notifier (err=%d)\n", 387 printk(KERN_ERR PFX "cannot register miscdev on minor=%d (err=%d)\n",
388 rc); 388 wdt_miscdev.minor, rc);
389 goto err_out_miscdev; 389 goto err_out_reboot;
390 } 390 }
391 391
392 printk(KERN_INFO PFX "WDT driver for W83877F initialised. timeout=%d sec (nowayout=%d)\n", 392 printk(KERN_INFO PFX "WDT driver for W83877F initialised. timeout=%d sec (nowayout=%d)\n",
@@ -394,8 +394,8 @@ static int __init w83877f_wdt_init(void)
394 394
395 return 0; 395 return 0;
396 396
397err_out_miscdev: 397err_out_reboot:
398 misc_deregister(&wdt_miscdev); 398 unregister_reboot_notifier(&wdt_notifier);
399err_out_region2: 399err_out_region2:
400 release_region(WDT_PING,1); 400 release_region(WDT_PING,1);
401err_out_region1: 401err_out_region1:
diff --git a/drivers/watchdog/w83977f_wdt.c b/drivers/watchdog/w83977f_wdt.c
index b475529d2475..b209bcd7f789 100644
--- a/drivers/watchdog/w83977f_wdt.c
+++ b/drivers/watchdog/w83977f_wdt.c
@@ -494,20 +494,20 @@ static int __init w83977f_wdt_init(void)
494 goto err_out; 494 goto err_out;
495 } 495 }
496 496
497 rc = misc_register(&wdt_miscdev); 497 rc = register_reboot_notifier(&wdt_notifier);
498 if (rc) 498 if (rc)
499 { 499 {
500 printk(KERN_ERR PFX "cannot register miscdev on minor=%d (err=%d)\n", 500 printk(KERN_ERR PFX "cannot register reboot notifier (err=%d)\n",
501 wdt_miscdev.minor, rc); 501 rc);
502 goto err_out_region; 502 goto err_out_region;
503 } 503 }
504 504
505 rc = register_reboot_notifier(&wdt_notifier); 505 rc = misc_register(&wdt_miscdev);
506 if (rc) 506 if (rc)
507 { 507 {
508 printk(KERN_ERR PFX "cannot register reboot notifier (err=%d)\n", 508 printk(KERN_ERR PFX "cannot register miscdev on minor=%d (err=%d)\n",
509 rc); 509 wdt_miscdev.minor, rc);
510 goto err_out_miscdev; 510 goto err_out_reboot;
511 } 511 }
512 512
513 printk(KERN_INFO PFX "initialized. timeout=%d sec (nowayout=%d testmode=%d)\n", 513 printk(KERN_INFO PFX "initialized. timeout=%d sec (nowayout=%d testmode=%d)\n",
@@ -515,8 +515,8 @@ static int __init w83977f_wdt_init(void)
515 515
516 return 0; 516 return 0;
517 517
518err_out_miscdev: 518err_out_reboot:
519 misc_deregister(&wdt_miscdev); 519 unregister_reboot_notifier(&wdt_notifier);
520err_out_region: 520err_out_region:
521 release_region(IO_INDEX_PORT,2); 521 release_region(IO_INDEX_PORT,2);
522err_out: 522err_out:
diff --git a/drivers/watchdog/wdt.c b/drivers/watchdog/wdt.c
index 53d0bb410df8..756fb15fdce7 100644
--- a/drivers/watchdog/wdt.c
+++ b/drivers/watchdog/wdt.c
@@ -70,6 +70,8 @@ MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default=" _
70static int io=0x240; 70static int io=0x240;
71static int irq=11; 71static int irq=11;
72 72
73static DEFINE_SPINLOCK(wdt_lock);
74
73module_param(io, int, 0); 75module_param(io, int, 0);
74MODULE_PARM_DESC(io, "WDT io port (default=0x240)"); 76MODULE_PARM_DESC(io, "WDT io port (default=0x240)");
75module_param(irq, int, 0); 77module_param(irq, int, 0);
@@ -109,6 +111,8 @@ static void wdt_ctr_load(int ctr, int val)
109 111
110static int wdt_start(void) 112static int wdt_start(void)
111{ 113{
114 unsigned long flags;
115 spin_lock_irqsave(&wdt_lock, flags);
112 inb_p(WDT_DC); /* Disable watchdog */ 116 inb_p(WDT_DC); /* Disable watchdog */
113 wdt_ctr_mode(0,3); /* Program CTR0 for Mode 3: Square Wave Generator */ 117 wdt_ctr_mode(0,3); /* Program CTR0 for Mode 3: Square Wave Generator */
114 wdt_ctr_mode(1,2); /* Program CTR1 for Mode 2: Rate Generator */ 118 wdt_ctr_mode(1,2); /* Program CTR1 for Mode 2: Rate Generator */
@@ -117,6 +121,7 @@ static int wdt_start(void)
117 wdt_ctr_load(1,wd_heartbeat); /* Heartbeat */ 121 wdt_ctr_load(1,wd_heartbeat); /* Heartbeat */
118 wdt_ctr_load(2,65535); /* Length of reset pulse */ 122 wdt_ctr_load(2,65535); /* Length of reset pulse */
119 outb_p(0, WDT_DC); /* Enable watchdog */ 123 outb_p(0, WDT_DC); /* Enable watchdog */
124 spin_unlock_irqrestore(&wdt_lock, flags);
120 return 0; 125 return 0;
121} 126}
122 127
@@ -128,9 +133,12 @@ static int wdt_start(void)
128 133
129static int wdt_stop (void) 134static int wdt_stop (void)
130{ 135{
136 unsigned long flags;
137 spin_lock_irqsave(&wdt_lock, flags);
131 /* Turn the card off */ 138 /* Turn the card off */
132 inb_p(WDT_DC); /* Disable watchdog */ 139 inb_p(WDT_DC); /* Disable watchdog */
133 wdt_ctr_load(2,0); /* 0 length reset pulses now */ 140 wdt_ctr_load(2,0); /* 0 length reset pulses now */
141 spin_unlock_irqrestore(&wdt_lock, flags);
134 return 0; 142 return 0;
135} 143}
136 144
@@ -143,11 +151,14 @@ static int wdt_stop (void)
143 151
144static int wdt_ping(void) 152static int wdt_ping(void)
145{ 153{
154 unsigned long flags;
155 spin_lock_irqsave(&wdt_lock, flags);
146 /* Write a watchdog value */ 156 /* Write a watchdog value */
147 inb_p(WDT_DC); /* Disable watchdog */ 157 inb_p(WDT_DC); /* Disable watchdog */
148 wdt_ctr_mode(1,2); /* Re-Program CTR1 for Mode 2: Rate Generator */ 158 wdt_ctr_mode(1,2); /* Re-Program CTR1 for Mode 2: Rate Generator */
149 wdt_ctr_load(1,wd_heartbeat); /* Heartbeat */ 159 wdt_ctr_load(1,wd_heartbeat); /* Heartbeat */
150 outb_p(0, WDT_DC); /* Enable watchdog */ 160 outb_p(0, WDT_DC); /* Enable watchdog */
161 spin_unlock_irqrestore(&wdt_lock, flags);
151 return 0; 162 return 0;
152} 163}
153 164
@@ -182,7 +193,12 @@ static int wdt_set_heartbeat(int t)
182 193
183static int wdt_get_status(int *status) 194static int wdt_get_status(int *status)
184{ 195{
185 unsigned char new_status=inb_p(WDT_SR); 196 unsigned char new_status;
197 unsigned long flags;
198
199 spin_lock_irqsave(&wdt_lock, flags);
200 new_status = inb_p(WDT_SR);
201 spin_unlock_irqrestore(&wdt_lock, flags);
186 202
187 *status=0; 203 *status=0;
188 if (new_status & WDC_SR_ISOI0) 204 if (new_status & WDC_SR_ISOI0)
@@ -214,8 +230,12 @@ static int wdt_get_status(int *status)
214 230
215static int wdt_get_temperature(int *temperature) 231static int wdt_get_temperature(int *temperature)
216{ 232{
217 unsigned short c=inb_p(WDT_RT); 233 unsigned short c;
234 unsigned long flags;
218 235
236 spin_lock_irqsave(&wdt_lock, flags);
237 c = inb_p(WDT_RT);
238 spin_unlock_irqrestore(&wdt_lock, flags);
219 *temperature = (c * 11 / 15) + 7; 239 *temperature = (c * 11 / 15) + 7;
220 return 0; 240 return 0;
221} 241}
@@ -237,7 +257,10 @@ static irqreturn_t wdt_interrupt(int irq, void *dev_id)
237 * Read the status register see what is up and 257 * Read the status register see what is up and
238 * then printk it. 258 * then printk it.
239 */ 259 */
240 unsigned char status=inb_p(WDT_SR); 260 unsigned char status;
261
262 spin_lock(&wdt_lock);
263 status = inb_p(WDT_SR);
241 264
242 printk(KERN_CRIT "WDT status %d\n", status); 265 printk(KERN_CRIT "WDT status %d\n", status);
243 266
@@ -265,6 +288,7 @@ static irqreturn_t wdt_interrupt(int irq, void *dev_id)
265 printk(KERN_CRIT "Reset in 5ms.\n"); 288 printk(KERN_CRIT "Reset in 5ms.\n");
266#endif 289#endif
267 } 290 }
291 spin_unlock(&wdt_lock);
268 return IRQ_HANDLED; 292 return IRQ_HANDLED;
269} 293}
270 294
diff --git a/drivers/watchdog/wdt977.c b/drivers/watchdog/wdt977.c
index 9b7f6b6edef6..fb4b876c9fda 100644
--- a/drivers/watchdog/wdt977.c
+++ b/drivers/watchdog/wdt977.c
@@ -470,20 +470,20 @@ static int __init wd977_init(void)
470 } 470 }
471 } 471 }
472 472
473 rc = misc_register(&wdt977_miscdev); 473 rc = register_reboot_notifier(&wdt977_notifier);
474 if (rc) 474 if (rc)
475 { 475 {
476 printk(KERN_ERR PFX "cannot register miscdev on minor=%d (err=%d)\n", 476 printk(KERN_ERR PFX "cannot register reboot notifier (err=%d)\n",
477 wdt977_miscdev.minor, rc); 477 rc);
478 goto err_out_region; 478 goto err_out_region;
479 } 479 }
480 480
481 rc = register_reboot_notifier(&wdt977_notifier); 481 rc = misc_register(&wdt977_miscdev);
482 if (rc) 482 if (rc)
483 { 483 {
484 printk(KERN_ERR PFX "cannot register reboot notifier (err=%d)\n", 484 printk(KERN_ERR PFX "cannot register miscdev on minor=%d (err=%d)\n",
485 rc); 485 wdt977_miscdev.minor, rc);
486 goto err_out_miscdev; 486 goto err_out_reboot;
487 } 487 }
488 488
489 printk(KERN_INFO PFX "initialized. timeout=%d sec (nowayout=%d, testmode=%i)\n", 489 printk(KERN_INFO PFX "initialized. timeout=%d sec (nowayout=%d, testmode=%i)\n",
@@ -491,8 +491,8 @@ static int __init wd977_init(void)
491 491
492 return 0; 492 return 0;
493 493
494err_out_miscdev: 494err_out_reboot:
495 misc_deregister(&wdt977_miscdev); 495 unregister_reboot_notifier(&wdt977_notifier);
496err_out_region: 496err_out_region:
497 if (!machine_is_netwinder()) 497 if (!machine_is_netwinder())
498 release_region(IO_INDEX_PORT,2); 498 release_region(IO_INDEX_PORT,2);