linux/drivers/watchdog/it87_wdt.c
<<
>>
Prefs
   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
 135static  unsigned int base, gpact, ciract;
 136static  unsigned long wdt_status;
 137static  DEFINE_SPINLOCK(spinlock);
 138
 139static  int nogameport = DEFAULT_NOGAMEPORT;
 140static  int exclusive  = DEFAULT_EXCLUSIVE;
 141static  int timeout    = DEFAULT_TIMEOUT;
 142static  int testmode   = DEFAULT_TESTMODE;
 143static  int nowayout   = DEFAULT_NOWAYOUT;
 144
 145module_param(nogameport, int, 0);
 146MODULE_PARM_DESC(nogameport, "Forbid the activation of game port, default="
 147                __MODULE_STRING(DEFAULT_NOGAMEPORT));
 148module_param(exclusive, int, 0);
 149MODULE_PARM_DESC(exclusive, "Watchdog exclusive device open, default="
 150                __MODULE_STRING(DEFAULT_EXCLUSIVE));
 151module_param(timeout, int, 0);
 152MODULE_PARM_DESC(timeout, "Watchdog timeout in seconds, default="
 153                __MODULE_STRING(DEFAULT_TIMEOUT));
 154module_param(testmode, int, 0);
 155MODULE_PARM_DESC(testmode, "Watchdog test mode (1 = no reboot), default="
 156                __MODULE_STRING(DEFAULT_TESTMODE));
 157module_param(nowayout, int, 0);
 158MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started, default="
 159                __MODULE_STRING(WATCHDOG_NOWAYOUT));
 160
 161/* Superio Chip */
 162
 163static inline void superio_enter(void)
 164{
 165        outb(0x87, REG);
 166        outb(0x01, REG);
 167        outb(0x55, REG);
 168        outb(0x55, REG);
 169}
 170
 171static inline void superio_exit(void)
 172{
 173        outb(0x02, REG);
 174        outb(0x02, VAL);
 175}
 176
 177static inline void superio_select(int ldn)
 178{
 179        outb(LDNREG, REG);
 180        outb(ldn, VAL);
 181}
 182
 183static inline int superio_inb(int reg)
 184{
 185        outb(reg, REG);
 186        return inb(VAL);
 187}
 188
 189static inline void superio_outb(int val, int reg)
 190{
 191        outb(reg, REG);
 192        outb(val, VAL);
 193}
 194
 195static 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
 205static 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
 215static 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
 225static 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
 248static 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
 275static 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
 311static 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
 348static 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
 373static 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
 402static 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
 424static 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
 442static 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
 502static 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
 510static 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
 519static struct miscdevice wdt_miscdev = {
 520        .minor          = WATCHDOG_MINOR,
 521        .name           = "watchdog",
 522        .fops           = &wdt_fops,
 523};
 524
 525static struct notifier_block wdt_notifier = {
 526        .notifier_call = wdt_notify_sys,
 527};
 528
 529static 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
 666err_out_reboot:
 667        unregister_reboot_notifier(&wdt_notifier);
 668err_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        }
 678err_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
 691static 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
 719module_init(it87_wdt_init);
 720module_exit(it87_wdt_exit);
 721
 722MODULE_AUTHOR("Oliver Schuster");
 723MODULE_DESCRIPTION("Hardware Watchdog Device Driver for IT87xx EC-LPC I/O");
 724MODULE_LICENSE("GPL");
 725MODULE_ALIAS_MISCDEV(WATCHDOG_MINOR);
 726