Commit e1fee94f346387739e683b31815ab54dc0a30bd6

Authored by Oliver Schuster
Committed by Wim Van Sebroeck
1 parent 3fa8749e58

[WATCHDOG] add watchdog driver IT8716 IT8726 IT8712J/K

Add it87xx watchdog driver
IT8716 IT8718 IT8726 IT8712-J IT8712-K

Signed-off-by: Oliver Schuster <olivers137@aol.com>
Signed-off-by: Wim Van Sebroeck <wim@iguana.be>

Showing 3 changed files with 738 additions and 0 deletions Side-by-side Diff

drivers/watchdog/Kconfig
... ... @@ -416,6 +416,18 @@
416 416 To compile this driver as a module, choose M here: the
417 417 module will be called it8712f_wdt.
418 418  
  419 +config IT87_WDT
  420 + tristate "IT87 Watchdog Timer"
  421 + depends on X86 && EXPERIMENTAL
  422 + ---help---
  423 + This is the driver for the hardware watchdog on the ITE IT8716,
  424 + IT8718, IT8726, IT8712(Version J,K) Super I/O chips. This watchdog
  425 + simply watches your kernel to make sure it doesn't freeze, and if
  426 + it does, it reboots your computer after a certain amount of time.
  427 +
  428 + To compile this driver as a module, choose M here: the module will
  429 + be called it87_wdt.
  430 +
419 431 config HP_WATCHDOG
420 432 tristate "HP Proliant iLO 2 Hardware Watchdog Timer"
421 433 depends on X86
drivers/watchdog/Makefile
... ... @@ -71,6 +71,7 @@
71 71 obj-$(CONFIG_ITCO_WDT) += iTCO_vendor_support.o
72 72 endif
73 73 obj-$(CONFIG_IT8712F_WDT) += it8712f_wdt.o
  74 +obj-$(CONFIG_IT87_WDT) += it87_wdt.o
74 75 obj-$(CONFIG_HP_WATCHDOG) += hpwdt.o
75 76 obj-$(CONFIG_SC1200_WDT) += sc1200wdt.o
76 77 obj-$(CONFIG_SCx200_WDT) += scx200_wdt.o
drivers/watchdog/it87_wdt.c
  1 +/*
  2 + * Watchdog Timer Driver
  3 + * for ITE IT87xx Environment Control - Low Pin Count Input / Output
  4 + *
  5 + * (c) Copyright 2007 Oliver Schuster <olivers137@aol.com>
  6 + *
  7 + * Based on softdog.c by Alan Cox,
  8 + * 83977f_wdt.c by Jose Goncalves,
  9 + * it87.c by Chris Gauthron, Jean Delvare
  10 + *
  11 + * Data-sheets: Publicly available at the ITE website
  12 + * http://www.ite.com.tw/
  13 + *
  14 + * Support of the watchdog timers, which are available on
  15 + * IT8716, IT8718, IT8726 and IT8712 (J,K version).
  16 + *
  17 + * This program is free software; you can redistribute it and/or
  18 + * modify it under the terms of the GNU General Public License
  19 + * as published by the Free Software Foundation; either version
  20 + * 2 of the License, or (at your option) any later version.
  21 + *
  22 + * This program is distributed in the hope that it will be useful,
  23 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
  24 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  25 + * GNU General Public License for more details.
  26 + *
  27 + * You should have received a copy of the GNU General Public License
  28 + * along with this program; if not, write to the Free Software
  29 + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  30 + */
  31 +
  32 +#include <linux/module.h>
  33 +#include <linux/moduleparam.h>
  34 +#include <linux/types.h>
  35 +#include <linux/kernel.h>
  36 +#include <linux/fs.h>
  37 +#include <linux/miscdevice.h>
  38 +#include <linux/init.h>
  39 +#include <linux/ioport.h>
  40 +#include <linux/watchdog.h>
  41 +#include <linux/notifier.h>
  42 +#include <linux/reboot.h>
  43 +#include <linux/uaccess.h>
  44 +#include <linux/io.h>
  45 +
  46 +#include <asm/system.h>
  47 +
  48 +#define WATCHDOG_VERSION "1.12"
  49 +#define WATCHDOG_NAME "IT87 WDT"
  50 +#define PFX WATCHDOG_NAME ": "
  51 +#define DRIVER_VERSION WATCHDOG_NAME " driver, v" WATCHDOG_VERSION "\n"
  52 +#define WD_MAGIC 'V'
  53 +
  54 +/* Defaults for Module Parameter */
  55 +#define DEFAULT_NOGAMEPORT 0
  56 +#define DEFAULT_EXCLUSIVE 1
  57 +#define DEFAULT_TIMEOUT 60
  58 +#define DEFAULT_TESTMODE 0
  59 +#define DEFAULT_NOWAYOUT WATCHDOG_NOWAYOUT
  60 +
  61 +/* IO Ports */
  62 +#define REG 0x2e
  63 +#define VAL 0x2f
  64 +
  65 +/* Logical device Numbers LDN */
  66 +#define GPIO 0x07
  67 +#define GAMEPORT 0x09
  68 +#define CIR 0x0a
  69 +
  70 +/* Configuration Registers and Functions */
  71 +#define LDNREG 0x07
  72 +#define CHIPID 0x20
  73 +#define CHIPREV 0x22
  74 +#define ACTREG 0x30
  75 +#define BASEREG 0x60
  76 +
  77 +/* Chip Id numbers */
  78 +#define NO_DEV_ID 0xffff
  79 +#define IT8705_ID 0x8705
  80 +#define IT8712_ID 0x8712
  81 +#define IT8716_ID 0x8716
  82 +#define IT8718_ID 0x8718
  83 +#define IT8726_ID 0x8726 /* the data sheet suggest wrongly 0x8716 */
  84 +
  85 +/* GPIO Configuration Registers LDN=0x07 */
  86 +#define WDTCTRL 0x71
  87 +#define WDTCFG 0x72
  88 +#define WDTVALLSB 0x73
  89 +#define WDTVALMSB 0x74
  90 +
  91 +/* GPIO Bits WDTCTRL */
  92 +#define WDT_CIRINT 0x80
  93 +#define WDT_MOUSEINT 0x40
  94 +#define WDT_KYBINT 0x20
  95 +#define WDT_GAMEPORT 0x10 /* not it8718 */
  96 +#define WDT_FORCE 0x02
  97 +#define WDT_ZERO 0x01
  98 +
  99 +/* GPIO Bits WDTCFG */
  100 +#define WDT_TOV1 0x80
  101 +#define WDT_KRST 0x40
  102 +#define WDT_TOVE 0x20
  103 +#define WDT_PWROK 0x10
  104 +#define WDT_INT_MASK 0x0f
  105 +
  106 +/* CIR Configuration Register LDN=0x0a */
  107 +#define CIR_ILS 0x70
  108 +
  109 +/* The default Base address is not always available, we use this */
  110 +#define CIR_BASE 0x0208
  111 +
  112 +/* CIR Controller */
  113 +#define CIR_DR(b) (b)
  114 +#define CIR_IER(b) (b + 1)
  115 +#define CIR_RCR(b) (b + 2)
  116 +#define CIR_TCR1(b) (b + 3)
  117 +#define CIR_TCR2(b) (b + 4)
  118 +#define CIR_TSR(b) (b + 5)
  119 +#define CIR_RSR(b) (b + 6)
  120 +#define CIR_BDLR(b) (b + 5)
  121 +#define CIR_BDHR(b) (b + 6)
  122 +#define CIR_IIR(b) (b + 7)
  123 +
  124 +/* Default Base address of Game port */
  125 +#define GP_BASE_DEFAULT 0x0201
  126 +
  127 +/* wdt_status */
  128 +#define WDTS_TIMER_RUN 0
  129 +#define WDTS_DEV_OPEN 1
  130 +#define WDTS_KEEPALIVE 2
  131 +#define WDTS_LOCKED 3
  132 +#define WDTS_USE_GP 4
  133 +#define WDTS_EXPECTED 5
  134 +
  135 +static unsigned int base, gpact, ciract;
  136 +static unsigned long wdt_status;
  137 +static DEFINE_SPINLOCK(spinlock);
  138 +
  139 +static int nogameport = DEFAULT_NOGAMEPORT;
  140 +static int exclusive = DEFAULT_EXCLUSIVE;
  141 +static int timeout = DEFAULT_TIMEOUT;
  142 +static int testmode = DEFAULT_TESTMODE;
  143 +static int nowayout = DEFAULT_NOWAYOUT;
  144 +
  145 +module_param(nogameport, int, 0);
  146 +MODULE_PARM_DESC(nogameport, "Forbid the activation of game port, default="
  147 + __MODULE_STRING(DEFAULT_NOGAMEPORT));
  148 +module_param(exclusive, int, 0);
  149 +MODULE_PARM_DESC(exclusive, "Watchdog exclusive device open, default="
  150 + __MODULE_STRING(DEFAULT_EXCLUSIVE));
  151 +module_param(timeout, int, 0);
  152 +MODULE_PARM_DESC(timeout, "Watchdog timeout in seconds, default="
  153 + __MODULE_STRING(DEFAULT_TIMEOUT));
  154 +module_param(testmode, int, 0);
  155 +MODULE_PARM_DESC(testmode, "Watchdog test mode (1 = no reboot), default="
  156 + __MODULE_STRING(DEFAULT_TESTMODE));
  157 +module_param(nowayout, int, 0);
  158 +MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started, default="
  159 + __MODULE_STRING(WATCHDOG_NOWAYOUT));
  160 +
  161 +/* Superio Chip */
  162 +
  163 +static inline void superio_enter(void)
  164 +{
  165 + outb(0x87, REG);
  166 + outb(0x01, REG);
  167 + outb(0x55, REG);
  168 + outb(0x55, REG);
  169 +}
  170 +
  171 +static inline void superio_exit(void)
  172 +{
  173 + outb(0x02, REG);
  174 + outb(0x02, VAL);
  175 +}
  176 +
  177 +static inline void superio_select(int ldn)
  178 +{
  179 + outb(LDNREG, REG);
  180 + outb(ldn, VAL);
  181 +}
  182 +
  183 +static inline int superio_inb(int reg)
  184 +{
  185 + outb(reg, REG);
  186 + return inb(VAL);
  187 +}
  188 +
  189 +static inline void superio_outb(int val, int reg)
  190 +{
  191 + outb(reg, REG);
  192 + outb(val, VAL);
  193 +}
  194 +
  195 +static inline int superio_inw(int reg)
  196 +{
  197 + int val;
  198 + outb(reg++, REG);
  199 + val = inb(VAL) << 8;
  200 + outb(reg, REG);
  201 + val |= inb(VAL);
  202 + return val;
  203 +}
  204 +
  205 +static inline void superio_outw(int val, int reg)
  206 +{
  207 + outb(reg++, REG);
  208 + outb(val >> 8, VAL);
  209 + outb(reg, REG);
  210 + outb(val, VAL);
  211 +}
  212 +
  213 +/* watchdog timer handling */
  214 +
  215 +static void wdt_keepalive(void)
  216 +{
  217 + if (test_bit(WDTS_USE_GP, &wdt_status))
  218 + inb(base);
  219 + else
  220 + /* The timer reloads with around 5 msec delay */
  221 + outb(0x55, CIR_DR(base));
  222 + set_bit(WDTS_KEEPALIVE, &wdt_status);
  223 +}
  224 +
  225 +static void wdt_start(void)
  226 +{
  227 + unsigned long flags;
  228 +
  229 + spin_lock_irqsave(&spinlock, flags);
  230 + superio_enter();
  231 +
  232 + superio_select(GPIO);
  233 + if (test_bit(WDTS_USE_GP, &wdt_status))
  234 + superio_outb(WDT_GAMEPORT, WDTCTRL);
  235 + else
  236 + superio_outb(WDT_CIRINT, WDTCTRL);
  237 + if (!testmode)
  238 + superio_outb(WDT_TOV1 | WDT_KRST | WDT_PWROK, WDTCFG);
  239 + else
  240 + superio_outb(WDT_TOV1, WDTCFG);
  241 + superio_outb(timeout>>8, WDTVALMSB);
  242 + superio_outb(timeout, WDTVALLSB);
  243 +
  244 + superio_exit();
  245 + spin_unlock_irqrestore(&spinlock, flags);
  246 +}
  247 +
  248 +static void wdt_stop(void)
  249 +{
  250 + unsigned long flags;
  251 +
  252 + spin_lock_irqsave(&spinlock, flags);
  253 + superio_enter();
  254 +
  255 + superio_select(GPIO);
  256 + superio_outb(0x00, WDTCTRL);
  257 + superio_outb(WDT_TOV1, WDTCFG);
  258 + superio_outb(0x00, WDTVALMSB);
  259 + superio_outb(0x00, WDTVALLSB);
  260 +
  261 + superio_exit();
  262 + spin_unlock_irqrestore(&spinlock, flags);
  263 +}
  264 +
  265 +/**
  266 + * wdt_set_timeout - set a new timeout value with watchdog ioctl
  267 + * @t: timeout value in seconds
  268 + *
  269 + * The hardware device has a 16 bit watchdog timer, thus the
  270 + * timeout time ranges between 1 and 65535 seconds.
  271 + *
  272 + * Used within WDIOC_SETTIMEOUT watchdog device ioctl.
  273 + */
  274 +
  275 +static int wdt_set_timeout(int t)
  276 +{
  277 + unsigned long flags;
  278 +
  279 + if (t < 1 || t > 65535)
  280 + return -EINVAL;
  281 +
  282 + timeout = t;
  283 +
  284 + spin_lock_irqsave(&spinlock, flags);
  285 + if (test_bit(WDTS_TIMER_RUN, &wdt_status)) {
  286 + superio_enter();
  287 +
  288 + superio_select(GPIO);
  289 + superio_outb(t>>8, WDTVALMSB);
  290 + superio_outb(t, WDTVALLSB);
  291 +
  292 + superio_exit();
  293 + }
  294 + spin_unlock_irqrestore(&spinlock, flags);
  295 + return 0;
  296 +}
  297 +
  298 +/**
  299 + * wdt_get_status - determines the status supported by watchdog ioctl
  300 + * @status: status returned to user space
  301 + *
  302 + * The status bit of the device does not allow to distinguish
  303 + * between a regular system reset and a watchdog forced reset.
  304 + * But, in test mode it is useful, so it is supported through
  305 + * WDIOC_GETSTATUS watchdog ioctl. Additionally the driver
  306 + * reports the keepalive signal and the acception of the magic.
  307 + *
  308 + * Used within WDIOC_GETSTATUS watchdog device ioctl.
  309 + */
  310 +
  311 +static int wdt_get_status(int *status)
  312 +{
  313 + unsigned long flags;
  314 +
  315 + *status = 0;
  316 + if (testmode) {
  317 + spin_lock_irqsave(&spinlock, flags);
  318 + superio_enter();
  319 + superio_select(GPIO);
  320 + if (superio_inb(WDTCTRL) & WDT_ZERO) {
  321 + superio_outb(0x00, WDTCTRL);
  322 + clear_bit(WDTS_TIMER_RUN, &wdt_status);
  323 + *status |= WDIOF_CARDRESET;
  324 + }
  325 +
  326 + superio_exit();
  327 + spin_unlock_irqrestore(&spinlock, flags);
  328 + }
  329 + if (test_and_clear_bit(WDTS_KEEPALIVE, &wdt_status))
  330 + *status |= WDIOF_KEEPALIVEPING;
  331 + if (test_bit(WDTS_EXPECTED, &wdt_status))
  332 + *status |= WDIOF_MAGICCLOSE;
  333 + return 0;
  334 +}
  335 +
  336 +/* /dev/watchdog handling */
  337 +
  338 +/**
  339 + * wdt_open - watchdog file_operations .open
  340 + * @inode: inode of the device
  341 + * @file: file handle to the device
  342 + *
  343 + * The watchdog timer starts by opening the device.
  344 + *
  345 + * Used within the file operation of the watchdog device.
  346 + */
  347 +
  348 +static int wdt_open(struct inode *inode, struct file *file)
  349 +{
  350 + if (exclusive && test_and_set_bit(WDTS_DEV_OPEN, &wdt_status))
  351 + return -EBUSY;
  352 + if (!test_and_set_bit(WDTS_TIMER_RUN, &wdt_status)) {
  353 + if (nowayout && !test_and_set_bit(WDTS_LOCKED, &wdt_status))
  354 + __module_get(THIS_MODULE);
  355 + wdt_start();
  356 + }
  357 + return nonseekable_open(inode, file);
  358 +}
  359 +
  360 +/**
  361 + * wdt_release - watchdog file_operations .release
  362 + * @inode: inode of the device
  363 + * @file: file handle to the device
  364 + *
  365 + * Closing the watchdog device either stops the watchdog timer
  366 + * or in the case, that nowayout is set or the magic character
  367 + * wasn't written, a critical warning about an running watchdog
  368 + * timer is given.
  369 + *
  370 + * Used within the file operation of the watchdog device.
  371 + */
  372 +
  373 +static int wdt_release(struct inode *inode, struct file *file)
  374 +{
  375 + if (test_bit(WDTS_TIMER_RUN, &wdt_status)) {
  376 + if (test_and_clear_bit(WDTS_EXPECTED, &wdt_status)) {
  377 + wdt_stop();
  378 + clear_bit(WDTS_TIMER_RUN, &wdt_status);
  379 + } else {
  380 + wdt_keepalive();
  381 + printk(KERN_CRIT PFX
  382 + "unexpected close, not stopping watchdog!\n");
  383 + }
  384 + }
  385 + clear_bit(WDTS_DEV_OPEN, &wdt_status);
  386 + return 0;
  387 +}
  388 +
  389 +/**
  390 + * wdt_write - watchdog file_operations .write
  391 + * @file: file handle to the watchdog
  392 + * @buf: buffer to write
  393 + * @count: count of bytes
  394 + * @ppos: pointer to the position to write. No seeks allowed
  395 + *
  396 + * A write to a watchdog device is defined as a keepalive signal. Any
  397 + * write of data will do, as we don't define content meaning.
  398 + *
  399 + * Used within the file operation of the watchdog device.
  400 + */
  401 +
  402 +static ssize_t wdt_write(struct file *file, const char __user *buf,
  403 + size_t count, loff_t *ppos)
  404 +{
  405 + if (count) {
  406 + clear_bit(WDTS_EXPECTED, &wdt_status);
  407 + wdt_keepalive();
  408 + }
  409 + if (!nowayout) {
  410 + size_t ofs;
  411 +
  412 + /* note: just in case someone wrote the magic character long ago */
  413 + for (ofs = 0; ofs != count; ofs++) {
  414 + char c;
  415 + if (get_user(c, buf + ofs))
  416 + return -EFAULT;
  417 + if (c == WD_MAGIC)
  418 + set_bit(WDTS_EXPECTED, &wdt_status);
  419 + }
  420 + }
  421 + return count;
  422 +}
  423 +
  424 +static struct watchdog_info ident = {
  425 + .options = WDIOF_SETTIMEOUT | WDIOF_MAGICCLOSE | WDIOF_KEEPALIVEPING,
  426 + .firmware_version = 1,
  427 + .identity = WATCHDOG_NAME,
  428 +};
  429 +
  430 +/**
  431 + * wdt_ioctl - watchdog file_operations .unlocked_ioctl
  432 + * @file: file handle to the device
  433 + * @cmd: watchdog command
  434 + * @arg: argument pointer
  435 + *
  436 + * The watchdog API defines a common set of functions for all watchdogs
  437 + * according to their available features.
  438 + *
  439 + * Used within the file operation of the watchdog device.
  440 + */
  441 +
  442 +static long wdt_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
  443 +{
  444 + int rc = 0, status, new_options, new_timeout;
  445 + union {
  446 + struct watchdog_info __user *ident;
  447 + int __user *i;
  448 + } uarg;
  449 +
  450 + uarg.i = (int __user *)arg;
  451 +
  452 + switch (cmd) {
  453 + case WDIOC_GETSUPPORT:
  454 + return copy_to_user(uarg.ident,
  455 + &ident, sizeof(ident)) ? -EFAULT : 0;
  456 +
  457 + case WDIOC_GETSTATUS:
  458 + wdt_get_status(&status);
  459 + return put_user(status, uarg.i);
  460 +
  461 + case WDIOC_GETBOOTSTATUS:
  462 + return put_user(0, uarg.i);
  463 +
  464 + case WDIOC_KEEPALIVE:
  465 + wdt_keepalive();
  466 + return 0;
  467 +
  468 + case WDIOC_SETOPTIONS:
  469 + if (get_user(new_options, uarg.i))
  470 + return -EFAULT;
  471 +
  472 + switch (new_options) {
  473 + case WDIOS_DISABLECARD:
  474 + if (test_bit(WDTS_TIMER_RUN, &wdt_status))
  475 + wdt_stop();
  476 + clear_bit(WDTS_TIMER_RUN, &wdt_status);
  477 + return 0;
  478 +
  479 + case WDIOS_ENABLECARD:
  480 + if (!test_and_set_bit(WDTS_TIMER_RUN, &wdt_status))
  481 + wdt_start();
  482 + return 0;
  483 +
  484 + default:
  485 + return -EFAULT;
  486 + }
  487 +
  488 + case WDIOC_SETTIMEOUT:
  489 + if (get_user(new_timeout, uarg.i))
  490 + return -EFAULT;
  491 + rc = wdt_set_timeout(new_timeout);
  492 + case WDIOC_GETTIMEOUT:
  493 + if (put_user(timeout, uarg.i))
  494 + return -EFAULT;
  495 + return rc;
  496 +
  497 + default:
  498 + return -ENOTTY;
  499 + }
  500 +}
  501 +
  502 +static int wdt_notify_sys(struct notifier_block *this, unsigned long code,
  503 + void *unused)
  504 +{
  505 + if (code == SYS_DOWN || code == SYS_HALT)
  506 + wdt_stop();
  507 + return NOTIFY_DONE;
  508 +}
  509 +
  510 +static const struct file_operations wdt_fops = {
  511 + .owner = THIS_MODULE,
  512 + .llseek = no_llseek,
  513 + .write = wdt_write,
  514 + .unlocked_ioctl = wdt_ioctl,
  515 + .open = wdt_open,
  516 + .release = wdt_release,
  517 +};
  518 +
  519 +static struct miscdevice wdt_miscdev = {
  520 + .minor = WATCHDOG_MINOR,
  521 + .name = "watchdog",
  522 + .fops = &wdt_fops,
  523 +};
  524 +
  525 +static struct notifier_block wdt_notifier = {
  526 + .notifier_call = wdt_notify_sys,
  527 +};
  528 +
  529 +static int __init it87_wdt_init(void)
  530 +{
  531 + int rc = 0;
  532 + u16 chip_type;
  533 + u8 chip_rev;
  534 + unsigned long flags;
  535 +
  536 + spin_lock_irqsave(&spinlock, flags);
  537 + superio_enter();
  538 + chip_type = superio_inw(CHIPID);
  539 + chip_rev = superio_inb(CHIPREV) & 0x0f;
  540 + superio_exit();
  541 + spin_unlock_irqrestore(&spinlock, flags);
  542 +
  543 + switch (chip_type) {
  544 + case IT8716_ID:
  545 + case IT8718_ID:
  546 + case IT8726_ID:
  547 + break;
  548 + case IT8712_ID:
  549 + if (chip_rev > 7)
  550 + break;
  551 + case IT8705_ID:
  552 + printk(KERN_ERR PFX
  553 + "Unsupported Chip found, Chip %04x Revision %02x\n",
  554 + chip_type, chip_rev);
  555 + return -ENODEV;
  556 + case NO_DEV_ID:
  557 + printk(KERN_ERR PFX "no device\n");
  558 + return -ENODEV;
  559 + default:
  560 + printk(KERN_ERR PFX
  561 + "Unknown Chip found, Chip %04x Revision %04x\n",
  562 + chip_type, chip_rev);
  563 + return -ENODEV;
  564 + }
  565 +
  566 + spin_lock_irqsave(&spinlock, flags);
  567 + superio_enter();
  568 +
  569 + superio_select(GPIO);
  570 + superio_outb(WDT_TOV1, WDTCFG);
  571 + superio_outb(0x00, WDTCTRL);
  572 +
  573 + /* First try to get Gameport support */
  574 + if (chip_type != IT8718_ID && !nogameport) {
  575 + superio_select(GAMEPORT);
  576 + base = superio_inw(BASEREG);
  577 + if (!base) {
  578 + base = GP_BASE_DEFAULT;
  579 + superio_outw(base, BASEREG);
  580 + }
  581 + gpact = superio_inb(ACTREG);
  582 + superio_outb(0x01, ACTREG);
  583 + superio_exit();
  584 + spin_unlock_irqrestore(&spinlock, flags);
  585 + if (request_region(base, 1, WATCHDOG_NAME))
  586 + set_bit(WDTS_USE_GP, &wdt_status);
  587 + else
  588 + rc = -EIO;
  589 + } else {
  590 + superio_exit();
  591 + spin_unlock_irqrestore(&spinlock, flags);
  592 + }
  593 +
  594 + /* If we haven't Gameport support, try to get CIR support */
  595 + if (!test_bit(WDTS_USE_GP, &wdt_status)) {
  596 + if (!request_region(CIR_BASE, 8, WATCHDOG_NAME)) {
  597 + if (rc == -EIO)
  598 + printk(KERN_ERR PFX
  599 + "I/O Address 0x%04x and 0x%04x"
  600 + " already in use\n", base, CIR_BASE);
  601 + else
  602 + printk(KERN_ERR PFX
  603 + "I/O Address 0x%04x already in use\n",
  604 + CIR_BASE);
  605 + rc = -EIO;
  606 + goto err_out;
  607 + }
  608 + base = CIR_BASE;
  609 + spin_lock_irqsave(&spinlock, flags);
  610 + superio_enter();
  611 +
  612 + superio_select(CIR);
  613 + superio_outw(base, BASEREG);
  614 + superio_outb(0x00, CIR_ILS);
  615 + ciract = superio_inb(ACTREG);
  616 + superio_outb(0x01, ACTREG);
  617 + if (rc == -EIO) {
  618 + superio_select(GAMEPORT);
  619 + superio_outb(gpact, ACTREG);
  620 + }
  621 +
  622 + superio_exit();
  623 + spin_unlock_irqrestore(&spinlock, flags);
  624 + }
  625 +
  626 + if (timeout < 1 || timeout > 65535) {
  627 + timeout = DEFAULT_TIMEOUT;
  628 + printk(KERN_WARNING PFX
  629 + "Timeout value out of range, use default %d sec\n",
  630 + DEFAULT_TIMEOUT);
  631 + }
  632 +
  633 + rc = register_reboot_notifier(&wdt_notifier);
  634 + if (rc) {
  635 + printk(KERN_ERR PFX
  636 + "Cannot register reboot notifier (err=%d)\n", rc);
  637 + goto err_out_region;
  638 + }
  639 +
  640 + rc = misc_register(&wdt_miscdev);
  641 + if (rc) {
  642 + printk(KERN_ERR PFX
  643 + "Cannot register miscdev on minor=%d (err=%d)\n",
  644 + wdt_miscdev.minor, rc);
  645 + goto err_out_reboot;
  646 + }
  647 +
  648 + /* Initialize CIR to use it as keepalive source */
  649 + if (!test_bit(WDTS_USE_GP, &wdt_status)) {
  650 + outb(0x00, CIR_RCR(base));
  651 + outb(0xc0, CIR_TCR1(base));
  652 + outb(0x5c, CIR_TCR2(base));
  653 + outb(0x10, CIR_IER(base));
  654 + outb(0x00, CIR_BDHR(base));
  655 + outb(0x01, CIR_BDLR(base));
  656 + outb(0x09, CIR_IER(base));
  657 + }
  658 +
  659 + printk(KERN_INFO PFX "Chip it%04x revision %d initialized. "
  660 + "timeout=%d sec (nowayout=%d testmode=%d exclusive=%d "
  661 + "nogameport=%d)\n", chip_type, chip_rev, timeout,
  662 + nowayout, testmode, exclusive, nogameport);
  663 +
  664 + return 0;
  665 +
  666 +err_out_reboot:
  667 + unregister_reboot_notifier(&wdt_notifier);
  668 +err_out_region:
  669 + release_region(base, test_bit(WDTS_USE_GP, &wdt_status) ? 1 : 8);
  670 + if (!test_bit(WDTS_USE_GP, &wdt_status)) {
  671 + spin_lock_irqsave(&spinlock, flags);
  672 + superio_enter();
  673 + superio_select(CIR);
  674 + superio_outb(ciract, ACTREG);
  675 + superio_exit();
  676 + spin_unlock_irqrestore(&spinlock, flags);
  677 + }
  678 +err_out:
  679 + if (chip_type != IT8718_ID && !nogameport) {
  680 + spin_lock_irqsave(&spinlock, flags);
  681 + superio_enter();
  682 + superio_select(GAMEPORT);
  683 + superio_outb(gpact, ACTREG);
  684 + superio_exit();
  685 + spin_unlock_irqrestore(&spinlock, flags);
  686 + }
  687 +
  688 + return rc;
  689 +}
  690 +
  691 +static void __exit it87_wdt_exit(void)
  692 +{
  693 + unsigned long flags;
  694 + int nolock;
  695 +
  696 + nolock = !spin_trylock_irqsave(&spinlock, flags);
  697 + superio_enter();
  698 + superio_select(GPIO);
  699 + superio_outb(0x00, WDTCTRL);
  700 + superio_outb(0x00, WDTCFG);
  701 + superio_outb(0x00, WDTVALMSB);
  702 + superio_outb(0x00, WDTVALLSB);
  703 + if (test_bit(WDTS_USE_GP, &wdt_status)) {
  704 + superio_select(GAMEPORT);
  705 + superio_outb(gpact, ACTREG);
  706 + } else {
  707 + superio_select(CIR);
  708 + superio_outb(ciract, ACTREG);
  709 + }
  710 + superio_exit();
  711 + if (!nolock)
  712 + spin_unlock_irqrestore(&spinlock, flags);
  713 +
  714 + misc_deregister(&wdt_miscdev);
  715 + unregister_reboot_notifier(&wdt_notifier);
  716 + release_region(base, test_bit(WDTS_USE_GP, &wdt_status) ? 1 : 8);
  717 +}
  718 +
  719 +module_init(it87_wdt_init);
  720 +module_exit(it87_wdt_exit);
  721 +
  722 +MODULE_AUTHOR("Oliver Schuster");
  723 +MODULE_DESCRIPTION("Hardware Watchdog Device Driver for IT87xx EC-LPC I/O");
  724 +MODULE_LICENSE("GPL");
  725 +MODULE_ALIAS_MISCDEV(WATCHDOG_MINOR);