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