linux/drivers/watchdog/f71808e_wdt.c
<<
>>
Prefs
   1/***************************************************************************
   2 *   Copyright (C) 2006 by Hans Edgington <hans@edgington.nl>              *
   3 *   Copyright (C) 2007-2009 Hans de Goede <hdegoede@redhat.com>           *
   4 *   Copyright (C) 2010 Giel van Schijndel <me@mortis.eu>                  *
   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 as published by  *
   8 *   the Free Software Foundation; either version 2 of the License, or     *
   9 *   (at your option) any later version.                                   *
  10 *                                                                         *
  11 *   This program is distributed in the hope that it will be useful,       *
  12 *   but WITHOUT ANY WARRANTY; without even the implied warranty of        *
  13 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *
  14 *   GNU General Public License for more details.                          *
  15 *                                                                         *
  16 *   You should have received a copy of the GNU General Public License     *
  17 *   along with this program; if not, write to the                         *
  18 *   Free Software Foundation, Inc.,                                       *
  19 *   59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.             *
  20 ***************************************************************************/
  21
  22#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
  23
  24#include <linux/err.h>
  25#include <linux/fs.h>
  26#include <linux/init.h>
  27#include <linux/io.h>
  28#include <linux/ioport.h>
  29#include <linux/miscdevice.h>
  30#include <linux/module.h>
  31#include <linux/mutex.h>
  32#include <linux/notifier.h>
  33#include <linux/reboot.h>
  34#include <linux/uaccess.h>
  35#include <linux/watchdog.h>
  36
  37#define DRVNAME "f71808e_wdt"
  38
  39#define SIO_F71808FG_LD_WDT     0x07    /* Watchdog timer logical device */
  40#define SIO_UNLOCK_KEY          0x87    /* Key to enable Super-I/O */
  41#define SIO_LOCK_KEY            0xAA    /* Key to diasble Super-I/O */
  42
  43#define SIO_REG_LDSEL           0x07    /* Logical device select */
  44#define SIO_REG_DEVID           0x20    /* Device ID (2 bytes) */
  45#define SIO_REG_DEVREV          0x22    /* Device revision */
  46#define SIO_REG_MANID           0x23    /* Fintek ID (2 bytes) */
  47#define SIO_REG_ROM_ADDR_SEL    0x27    /* ROM address select */
  48#define SIO_REG_MFUNCT1         0x29    /* Multi function select 1 */
  49#define SIO_REG_MFUNCT2         0x2a    /* Multi function select 2 */
  50#define SIO_REG_MFUNCT3         0x2b    /* Multi function select 3 */
  51#define SIO_REG_ENABLE          0x30    /* Logical device enable */
  52#define SIO_REG_ADDR            0x60    /* Logical device address (2 bytes) */
  53
  54#define SIO_FINTEK_ID           0x1934  /* Manufacturers ID */
  55#define SIO_F71808_ID           0x0901  /* Chipset ID */
  56#define SIO_F71858_ID           0x0507  /* Chipset ID */
  57#define SIO_F71862_ID           0x0601  /* Chipset ID */
  58#define SIO_F71869_ID           0x0814  /* Chipset ID */
  59#define SIO_F71869A_ID          0x1007  /* Chipset ID */
  60#define SIO_F71882_ID           0x0541  /* Chipset ID */
  61#define SIO_F71889_ID           0x0723  /* Chipset ID */
  62
  63#define F71808FG_REG_WDO_CONF           0xf0
  64#define F71808FG_REG_WDT_CONF           0xf5
  65#define F71808FG_REG_WD_TIME            0xf6
  66
  67#define F71808FG_FLAG_WDOUT_EN          7
  68
  69#define F71808FG_FLAG_WDTMOUT_STS       5
  70#define F71808FG_FLAG_WD_EN             5
  71#define F71808FG_FLAG_WD_PULSE          4
  72#define F71808FG_FLAG_WD_UNIT           3
  73
  74/* Default values */
  75#define WATCHDOG_TIMEOUT        60      /* 1 minute default timeout */
  76#define WATCHDOG_MAX_TIMEOUT    (60 * 255)
  77#define WATCHDOG_PULSE_WIDTH    125     /* 125 ms, default pulse width for
  78                                           watchdog signal */
  79#define WATCHDOG_F71862FG_PIN   63      /* default watchdog reset output
  80                                           pin number 63 */
  81
  82static unsigned short force_id;
  83module_param(force_id, ushort, 0);
  84MODULE_PARM_DESC(force_id, "Override the detected device ID");
  85
  86static const int max_timeout = WATCHDOG_MAX_TIMEOUT;
  87static int timeout = WATCHDOG_TIMEOUT;  /* default timeout in seconds */
  88module_param(timeout, int, 0);
  89MODULE_PARM_DESC(timeout,
  90        "Watchdog timeout in seconds. 1<= timeout <="
  91                        __MODULE_STRING(WATCHDOG_MAX_TIMEOUT) " (default="
  92                        __MODULE_STRING(WATCHDOG_TIMEOUT) ")");
  93
  94static unsigned int pulse_width = WATCHDOG_PULSE_WIDTH;
  95module_param(pulse_width, uint, 0);
  96MODULE_PARM_DESC(pulse_width,
  97        "Watchdog signal pulse width. 0(=level), 1 ms, 25 ms, 125 ms or 5000 ms"
  98                        " (default=" __MODULE_STRING(WATCHDOG_PULSE_WIDTH) ")");
  99
 100static unsigned int f71862fg_pin = WATCHDOG_F71862FG_PIN;
 101module_param(f71862fg_pin, uint, 0);
 102MODULE_PARM_DESC(f71862fg_pin,
 103        "Watchdog f71862fg reset output pin configuration. Choose pin 56 or 63"
 104                        " (default=" __MODULE_STRING(WATCHDOG_F71862FG_PIN)")");
 105
 106static bool nowayout = WATCHDOG_NOWAYOUT;
 107module_param(nowayout, bool, 0444);
 108MODULE_PARM_DESC(nowayout, "Disable watchdog shutdown on close");
 109
 110static unsigned int start_withtimeout;
 111module_param(start_withtimeout, uint, 0);
 112MODULE_PARM_DESC(start_withtimeout, "Start watchdog timer on module load with"
 113        " given initial timeout. Zero (default) disables this feature.");
 114
 115enum chips { f71808fg, f71858fg, f71862fg, f71869, f71882fg, f71889fg };
 116
 117static const char *f71808e_names[] = {
 118        "f71808fg",
 119        "f71858fg",
 120        "f71862fg",
 121        "f71869",
 122        "f71882fg",
 123        "f71889fg",
 124};
 125
 126/* Super-I/O Function prototypes */
 127static inline int superio_inb(int base, int reg);
 128static inline int superio_inw(int base, int reg);
 129static inline void superio_outb(int base, int reg, u8 val);
 130static inline void superio_set_bit(int base, int reg, int bit);
 131static inline void superio_clear_bit(int base, int reg, int bit);
 132static inline int superio_enter(int base);
 133static inline void superio_select(int base, int ld);
 134static inline void superio_exit(int base);
 135
 136struct watchdog_data {
 137        unsigned short  sioaddr;
 138        enum chips      type;
 139        unsigned long   opened;
 140        struct mutex    lock;
 141        char            expect_close;
 142        struct watchdog_info ident;
 143
 144        unsigned short  timeout;
 145        u8              timer_val;      /* content for the wd_time register */
 146        char            minutes_mode;
 147        u8              pulse_val;      /* pulse width flag */
 148        char            pulse_mode;     /* enable pulse output mode? */
 149        char            caused_reboot;  /* last reboot was by the watchdog */
 150};
 151
 152static struct watchdog_data watchdog = {
 153        .lock = __MUTEX_INITIALIZER(watchdog.lock),
 154};
 155
 156/* Super I/O functions */
 157static inline int superio_inb(int base, int reg)
 158{
 159        outb(reg, base);
 160        return inb(base + 1);
 161}
 162
 163static int superio_inw(int base, int reg)
 164{
 165        int val;
 166        val  = superio_inb(base, reg) << 8;
 167        val |= superio_inb(base, reg + 1);
 168        return val;
 169}
 170
 171static inline void superio_outb(int base, int reg, u8 val)
 172{
 173        outb(reg, base);
 174        outb(val, base + 1);
 175}
 176
 177static inline void superio_set_bit(int base, int reg, int bit)
 178{
 179        unsigned long val = superio_inb(base, reg);
 180        __set_bit(bit, &val);
 181        superio_outb(base, reg, val);
 182}
 183
 184static inline void superio_clear_bit(int base, int reg, int bit)
 185{
 186        unsigned long val = superio_inb(base, reg);
 187        __clear_bit(bit, &val);
 188        superio_outb(base, reg, val);
 189}
 190
 191static inline int superio_enter(int base)
 192{
 193        /* Don't step on other drivers' I/O space by accident */
 194        if (!request_muxed_region(base, 2, DRVNAME)) {
 195                pr_err("I/O address 0x%04x already in use\n", (int)base);
 196                return -EBUSY;
 197        }
 198
 199        /* according to the datasheet the key must be sent twice! */
 200        outb(SIO_UNLOCK_KEY, base);
 201        outb(SIO_UNLOCK_KEY, base);
 202
 203        return 0;
 204}
 205
 206static inline void superio_select(int base, int ld)
 207{
 208        outb(SIO_REG_LDSEL, base);
 209        outb(ld, base + 1);
 210}
 211
 212static inline void superio_exit(int base)
 213{
 214        outb(SIO_LOCK_KEY, base);
 215        release_region(base, 2);
 216}
 217
 218static int watchdog_set_timeout(int timeout)
 219{
 220        if (timeout <= 0
 221         || timeout >  max_timeout) {
 222                pr_err("watchdog timeout out of range\n");
 223                return -EINVAL;
 224        }
 225
 226        mutex_lock(&watchdog.lock);
 227
 228        watchdog.timeout = timeout;
 229        if (timeout > 0xff) {
 230                watchdog.timer_val = DIV_ROUND_UP(timeout, 60);
 231                watchdog.minutes_mode = true;
 232        } else {
 233                watchdog.timer_val = timeout;
 234                watchdog.minutes_mode = false;
 235        }
 236
 237        mutex_unlock(&watchdog.lock);
 238
 239        return 0;
 240}
 241
 242static int watchdog_set_pulse_width(unsigned int pw)
 243{
 244        int err = 0;
 245
 246        mutex_lock(&watchdog.lock);
 247
 248        if        (pw <=    1) {
 249                watchdog.pulse_val = 0;
 250        } else if (pw <=   25) {
 251                watchdog.pulse_val = 1;
 252        } else if (pw <=  125) {
 253                watchdog.pulse_val = 2;
 254        } else if (pw <= 5000) {
 255                watchdog.pulse_val = 3;
 256        } else {
 257                pr_err("pulse width out of range\n");
 258                err = -EINVAL;
 259                goto exit_unlock;
 260        }
 261
 262        watchdog.pulse_mode = pw;
 263
 264exit_unlock:
 265        mutex_unlock(&watchdog.lock);
 266        return err;
 267}
 268
 269static int watchdog_keepalive(void)
 270{
 271        int err = 0;
 272
 273        mutex_lock(&watchdog.lock);
 274        err = superio_enter(watchdog.sioaddr);
 275        if (err)
 276                goto exit_unlock;
 277        superio_select(watchdog.sioaddr, SIO_F71808FG_LD_WDT);
 278
 279        if (watchdog.minutes_mode)
 280                /* select minutes for timer units */
 281                superio_set_bit(watchdog.sioaddr, F71808FG_REG_WDT_CONF,
 282                                F71808FG_FLAG_WD_UNIT);
 283        else
 284                /* select seconds for timer units */
 285                superio_clear_bit(watchdog.sioaddr, F71808FG_REG_WDT_CONF,
 286                                F71808FG_FLAG_WD_UNIT);
 287
 288        /* Set timer value */
 289        superio_outb(watchdog.sioaddr, F71808FG_REG_WD_TIME,
 290                           watchdog.timer_val);
 291
 292        superio_exit(watchdog.sioaddr);
 293
 294exit_unlock:
 295        mutex_unlock(&watchdog.lock);
 296        return err;
 297}
 298
 299static int f71862fg_pin_configure(unsigned short ioaddr)
 300{
 301        /* When ioaddr is non-zero the calling function has to take care of
 302           mutex handling and superio preparation! */
 303
 304        if (f71862fg_pin == 63) {
 305                if (ioaddr) {
 306                        /* SPI must be disabled first to use this pin! */
 307                        superio_clear_bit(ioaddr, SIO_REG_ROM_ADDR_SEL, 6);
 308                        superio_set_bit(ioaddr, SIO_REG_MFUNCT3, 4);
 309                }
 310        } else if (f71862fg_pin == 56) {
 311                if (ioaddr)
 312                        superio_set_bit(ioaddr, SIO_REG_MFUNCT1, 1);
 313        } else {
 314                pr_err("Invalid argument f71862fg_pin=%d\n", f71862fg_pin);
 315                return -EINVAL;
 316        }
 317        return 0;
 318}
 319
 320static int watchdog_start(void)
 321{
 322        /* Make sure we don't die as soon as the watchdog is enabled below */
 323        int err = watchdog_keepalive();
 324        if (err)
 325                return err;
 326
 327        mutex_lock(&watchdog.lock);
 328        err = superio_enter(watchdog.sioaddr);
 329        if (err)
 330                goto exit_unlock;
 331        superio_select(watchdog.sioaddr, SIO_F71808FG_LD_WDT);
 332
 333        /* Watchdog pin configuration */
 334        switch (watchdog.type) {
 335        case f71808fg:
 336                /* Set pin 21 to GPIO23/WDTRST#, then to WDTRST# */
 337                superio_clear_bit(watchdog.sioaddr, SIO_REG_MFUNCT2, 3);
 338                superio_clear_bit(watchdog.sioaddr, SIO_REG_MFUNCT3, 3);
 339                break;
 340
 341        case f71862fg:
 342                err = f71862fg_pin_configure(watchdog.sioaddr);
 343                if (err)
 344                        goto exit_superio;
 345                break;
 346
 347        case f71869:
 348                /* GPIO14 --> WDTRST# */
 349                superio_clear_bit(watchdog.sioaddr, SIO_REG_MFUNCT1, 4);
 350                break;
 351
 352        case f71882fg:
 353                /* Set pin 56 to WDTRST# */
 354                superio_set_bit(watchdog.sioaddr, SIO_REG_MFUNCT1, 1);
 355                break;
 356
 357        case f71889fg:
 358                /* set pin 40 to WDTRST# */
 359                superio_outb(watchdog.sioaddr, SIO_REG_MFUNCT3,
 360                        superio_inb(watchdog.sioaddr, SIO_REG_MFUNCT3) & 0xcf);
 361                break;
 362
 363        default:
 364                /*
 365                 * 'default' label to shut up the compiler and catch
 366                 * programmer errors
 367                 */
 368                err = -ENODEV;
 369                goto exit_superio;
 370        }
 371
 372        superio_select(watchdog.sioaddr, SIO_F71808FG_LD_WDT);
 373        superio_set_bit(watchdog.sioaddr, SIO_REG_ENABLE, 0);
 374        superio_set_bit(watchdog.sioaddr, F71808FG_REG_WDO_CONF,
 375                        F71808FG_FLAG_WDOUT_EN);
 376
 377        superio_set_bit(watchdog.sioaddr, F71808FG_REG_WDT_CONF,
 378                        F71808FG_FLAG_WD_EN);
 379
 380        if (watchdog.pulse_mode) {
 381                /* Select "pulse" output mode with given duration */
 382                u8 wdt_conf = superio_inb(watchdog.sioaddr,
 383                                F71808FG_REG_WDT_CONF);
 384
 385                /* Set WD_PSWIDTH bits (1:0) */
 386                wdt_conf = (wdt_conf & 0xfc) | (watchdog.pulse_val & 0x03);
 387                /* Set WD_PULSE to "pulse" mode */
 388                wdt_conf |= BIT(F71808FG_FLAG_WD_PULSE);
 389
 390                superio_outb(watchdog.sioaddr, F71808FG_REG_WDT_CONF,
 391                                wdt_conf);
 392        } else {
 393                /* Select "level" output mode */
 394                superio_clear_bit(watchdog.sioaddr, F71808FG_REG_WDT_CONF,
 395                                F71808FG_FLAG_WD_PULSE);
 396        }
 397
 398exit_superio:
 399        superio_exit(watchdog.sioaddr);
 400exit_unlock:
 401        mutex_unlock(&watchdog.lock);
 402
 403        return err;
 404}
 405
 406static int watchdog_stop(void)
 407{
 408        int err = 0;
 409
 410        mutex_lock(&watchdog.lock);
 411        err = superio_enter(watchdog.sioaddr);
 412        if (err)
 413                goto exit_unlock;
 414        superio_select(watchdog.sioaddr, SIO_F71808FG_LD_WDT);
 415
 416        superio_clear_bit(watchdog.sioaddr, F71808FG_REG_WDT_CONF,
 417                        F71808FG_FLAG_WD_EN);
 418
 419        superio_exit(watchdog.sioaddr);
 420
 421exit_unlock:
 422        mutex_unlock(&watchdog.lock);
 423
 424        return err;
 425}
 426
 427static int watchdog_get_status(void)
 428{
 429        int status = 0;
 430
 431        mutex_lock(&watchdog.lock);
 432        status = (watchdog.caused_reboot) ? WDIOF_CARDRESET : 0;
 433        mutex_unlock(&watchdog.lock);
 434
 435        return status;
 436}
 437
 438static bool watchdog_is_running(void)
 439{
 440        /*
 441         * if we fail to determine the watchdog's status assume it to be
 442         * running to be on the safe side
 443         */
 444        bool is_running = true;
 445
 446        mutex_lock(&watchdog.lock);
 447        if (superio_enter(watchdog.sioaddr))
 448                goto exit_unlock;
 449        superio_select(watchdog.sioaddr, SIO_F71808FG_LD_WDT);
 450
 451        is_running = (superio_inb(watchdog.sioaddr, SIO_REG_ENABLE) & BIT(0))
 452                && (superio_inb(watchdog.sioaddr, F71808FG_REG_WDT_CONF)
 453                        & F71808FG_FLAG_WD_EN);
 454
 455        superio_exit(watchdog.sioaddr);
 456
 457exit_unlock:
 458        mutex_unlock(&watchdog.lock);
 459        return is_running;
 460}
 461
 462/* /dev/watchdog api */
 463
 464static int watchdog_open(struct inode *inode, struct file *file)
 465{
 466        int err;
 467
 468        /* If the watchdog is alive we don't need to start it again */
 469        if (test_and_set_bit(0, &watchdog.opened))
 470                return -EBUSY;
 471
 472        err = watchdog_start();
 473        if (err) {
 474                clear_bit(0, &watchdog.opened);
 475                return err;
 476        }
 477
 478        if (nowayout)
 479                __module_get(THIS_MODULE);
 480
 481        watchdog.expect_close = 0;
 482        return nonseekable_open(inode, file);
 483}
 484
 485static int watchdog_release(struct inode *inode, struct file *file)
 486{
 487        clear_bit(0, &watchdog.opened);
 488
 489        if (!watchdog.expect_close) {
 490                watchdog_keepalive();
 491                pr_crit("Unexpected close, not stopping watchdog!\n");
 492        } else if (!nowayout) {
 493                watchdog_stop();
 494        }
 495        return 0;
 496}
 497
 498/*
 499 *      watchdog_write:
 500 *      @file: file handle to the watchdog
 501 *      @buf: buffer to write
 502 *      @count: count of bytes
 503 *      @ppos: pointer to the position to write. No seeks allowed
 504 *
 505 *      A write to a watchdog device is defined as a keepalive signal. Any
 506 *      write of data will do, as we we don't define content meaning.
 507 */
 508
 509static ssize_t watchdog_write(struct file *file, const char __user *buf,
 510                            size_t count, loff_t *ppos)
 511{
 512        if (count) {
 513                if (!nowayout) {
 514                        size_t i;
 515
 516                        /* In case it was set long ago */
 517                        bool expect_close = false;
 518
 519                        for (i = 0; i != count; i++) {
 520                                char c;
 521                                if (get_user(c, buf + i))
 522                                        return -EFAULT;
 523                                expect_close = (c == 'V');
 524                        }
 525
 526                        /* Properly order writes across fork()ed processes */
 527                        mutex_lock(&watchdog.lock);
 528                        watchdog.expect_close = expect_close;
 529                        mutex_unlock(&watchdog.lock);
 530                }
 531
 532                /* someone wrote to us, we should restart timer */
 533                watchdog_keepalive();
 534        }
 535        return count;
 536}
 537
 538/*
 539 *      watchdog_ioctl:
 540 *      @inode: inode of the device
 541 *      @file: file handle to the device
 542 *      @cmd: watchdog command
 543 *      @arg: argument pointer
 544 *
 545 *      The watchdog API defines a common set of functions for all watchdogs
 546 *      according to their available features.
 547 */
 548static long watchdog_ioctl(struct file *file, unsigned int cmd,
 549        unsigned long arg)
 550{
 551        int status;
 552        int new_options;
 553        int new_timeout;
 554        union {
 555                struct watchdog_info __user *ident;
 556                int __user *i;
 557        } uarg;
 558
 559        uarg.i = (int __user *)arg;
 560
 561        switch (cmd) {
 562        case WDIOC_GETSUPPORT:
 563                return copy_to_user(uarg.ident, &watchdog.ident,
 564                        sizeof(watchdog.ident)) ? -EFAULT : 0;
 565
 566        case WDIOC_GETSTATUS:
 567                status = watchdog_get_status();
 568                if (status < 0)
 569                        return status;
 570                return put_user(status, uarg.i);
 571
 572        case WDIOC_GETBOOTSTATUS:
 573                return put_user(0, uarg.i);
 574
 575        case WDIOC_SETOPTIONS:
 576                if (get_user(new_options, uarg.i))
 577                        return -EFAULT;
 578
 579                if (new_options & WDIOS_DISABLECARD)
 580                        watchdog_stop();
 581
 582                if (new_options & WDIOS_ENABLECARD)
 583                        return watchdog_start();
 584
 585
 586        case WDIOC_KEEPALIVE:
 587                watchdog_keepalive();
 588                return 0;
 589
 590        case WDIOC_SETTIMEOUT:
 591                if (get_user(new_timeout, uarg.i))
 592                        return -EFAULT;
 593
 594                if (watchdog_set_timeout(new_timeout))
 595                        return -EINVAL;
 596
 597                watchdog_keepalive();
 598                /* Fall */
 599
 600        case WDIOC_GETTIMEOUT:
 601                return put_user(watchdog.timeout, uarg.i);
 602
 603        default:
 604                return -ENOTTY;
 605
 606        }
 607}
 608
 609static int watchdog_notify_sys(struct notifier_block *this, unsigned long code,
 610        void *unused)
 611{
 612        if (code == SYS_DOWN || code == SYS_HALT)
 613                watchdog_stop();
 614        return NOTIFY_DONE;
 615}
 616
 617static const struct file_operations watchdog_fops = {
 618        .owner          = THIS_MODULE,
 619        .llseek         = no_llseek,
 620        .open           = watchdog_open,
 621        .release        = watchdog_release,
 622        .write          = watchdog_write,
 623        .unlocked_ioctl = watchdog_ioctl,
 624};
 625
 626static struct miscdevice watchdog_miscdev = {
 627        .minor          = WATCHDOG_MINOR,
 628        .name           = "watchdog",
 629        .fops           = &watchdog_fops,
 630};
 631
 632static struct notifier_block watchdog_notifier = {
 633        .notifier_call = watchdog_notify_sys,
 634};
 635
 636static int __init watchdog_init(int sioaddr)
 637{
 638        int wdt_conf, err = 0;
 639
 640        /* No need to lock watchdog.lock here because no entry points
 641         * into the module have been registered yet.
 642         */
 643        watchdog.sioaddr = sioaddr;
 644        watchdog.ident.options = WDIOC_SETTIMEOUT
 645                                | WDIOF_MAGICCLOSE
 646                                | WDIOF_KEEPALIVEPING;
 647
 648        snprintf(watchdog.ident.identity,
 649                sizeof(watchdog.ident.identity), "%s watchdog",
 650                f71808e_names[watchdog.type]);
 651
 652        err = superio_enter(sioaddr);
 653        if (err)
 654                return err;
 655        superio_select(watchdog.sioaddr, SIO_F71808FG_LD_WDT);
 656
 657        wdt_conf = superio_inb(sioaddr, F71808FG_REG_WDT_CONF);
 658        watchdog.caused_reboot = wdt_conf & F71808FG_FLAG_WDTMOUT_STS;
 659
 660        superio_exit(sioaddr);
 661
 662        err = watchdog_set_timeout(timeout);
 663        if (err)
 664                return err;
 665        err = watchdog_set_pulse_width(pulse_width);
 666        if (err)
 667                return err;
 668
 669        err = register_reboot_notifier(&watchdog_notifier);
 670        if (err)
 671                return err;
 672
 673        err = misc_register(&watchdog_miscdev);
 674        if (err) {
 675                pr_err("cannot register miscdev on minor=%d\n",
 676                       watchdog_miscdev.minor);
 677                goto exit_reboot;
 678        }
 679
 680        if (start_withtimeout) {
 681                if (start_withtimeout <= 0
 682                 || start_withtimeout >  max_timeout) {
 683                        pr_err("starting timeout out of range\n");
 684                        err = -EINVAL;
 685                        goto exit_miscdev;
 686                }
 687
 688                err = watchdog_start();
 689                if (err) {
 690                        pr_err("cannot start watchdog timer\n");
 691                        goto exit_miscdev;
 692                }
 693
 694                mutex_lock(&watchdog.lock);
 695                err = superio_enter(sioaddr);
 696                if (err)
 697                        goto exit_unlock;
 698                superio_select(watchdog.sioaddr, SIO_F71808FG_LD_WDT);
 699
 700                if (start_withtimeout > 0xff) {
 701                        /* select minutes for timer units */
 702                        superio_set_bit(sioaddr, F71808FG_REG_WDT_CONF,
 703                                F71808FG_FLAG_WD_UNIT);
 704                        superio_outb(sioaddr, F71808FG_REG_WD_TIME,
 705                                DIV_ROUND_UP(start_withtimeout, 60));
 706                } else {
 707                        /* select seconds for timer units */
 708                        superio_clear_bit(sioaddr, F71808FG_REG_WDT_CONF,
 709                                F71808FG_FLAG_WD_UNIT);
 710                        superio_outb(sioaddr, F71808FG_REG_WD_TIME,
 711                                start_withtimeout);
 712                }
 713
 714                superio_exit(sioaddr);
 715                mutex_unlock(&watchdog.lock);
 716
 717                if (nowayout)
 718                        __module_get(THIS_MODULE);
 719
 720                pr_info("watchdog started with initial timeout of %u sec\n",
 721                        start_withtimeout);
 722        }
 723
 724        return 0;
 725
 726exit_unlock:
 727        mutex_unlock(&watchdog.lock);
 728exit_miscdev:
 729        misc_deregister(&watchdog_miscdev);
 730exit_reboot:
 731        unregister_reboot_notifier(&watchdog_notifier);
 732
 733        return err;
 734}
 735
 736static int __init f71808e_find(int sioaddr)
 737{
 738        u16 devid;
 739        int err = superio_enter(sioaddr);
 740        if (err)
 741                return err;
 742
 743        devid = superio_inw(sioaddr, SIO_REG_MANID);
 744        if (devid != SIO_FINTEK_ID) {
 745                pr_debug("Not a Fintek device\n");
 746                err = -ENODEV;
 747                goto exit;
 748        }
 749
 750        devid = force_id ? force_id : superio_inw(sioaddr, SIO_REG_DEVID);
 751        switch (devid) {
 752        case SIO_F71808_ID:
 753                watchdog.type = f71808fg;
 754                break;
 755        case SIO_F71862_ID:
 756                watchdog.type = f71862fg;
 757                err = f71862fg_pin_configure(0); /* validate module parameter */
 758                break;
 759        case SIO_F71869_ID:
 760        case SIO_F71869A_ID:
 761                watchdog.type = f71869;
 762                break;
 763        case SIO_F71882_ID:
 764                watchdog.type = f71882fg;
 765                break;
 766        case SIO_F71889_ID:
 767                watchdog.type = f71889fg;
 768                break;
 769        case SIO_F71858_ID:
 770                /* Confirmed (by datasheet) not to have a watchdog. */
 771                err = -ENODEV;
 772                goto exit;
 773        default:
 774                pr_info("Unrecognized Fintek device: %04x\n",
 775                        (unsigned int)devid);
 776                err = -ENODEV;
 777                goto exit;
 778        }
 779
 780        pr_info("Found %s watchdog chip, revision %d\n",
 781                f71808e_names[watchdog.type],
 782                (int)superio_inb(sioaddr, SIO_REG_DEVREV));
 783exit:
 784        superio_exit(sioaddr);
 785        return err;
 786}
 787
 788static int __init f71808e_init(void)
 789{
 790        static const unsigned short addrs[] = { 0x2e, 0x4e };
 791        int err = -ENODEV;
 792        int i;
 793
 794        for (i = 0; i < ARRAY_SIZE(addrs); i++) {
 795                err = f71808e_find(addrs[i]);
 796                if (err == 0)
 797                        break;
 798        }
 799        if (i == ARRAY_SIZE(addrs))
 800                return err;
 801
 802        return watchdog_init(addrs[i]);
 803}
 804
 805static void __exit f71808e_exit(void)
 806{
 807        if (watchdog_is_running()) {
 808                pr_warn("Watchdog timer still running, stopping it\n");
 809                watchdog_stop();
 810        }
 811        misc_deregister(&watchdog_miscdev);
 812        unregister_reboot_notifier(&watchdog_notifier);
 813}
 814
 815MODULE_DESCRIPTION("F71808E Watchdog Driver");
 816MODULE_AUTHOR("Giel van Schijndel <me@mortis.eu>");
 817MODULE_LICENSE("GPL");
 818
 819module_init(f71808e_init);
 820module_exit(f71808e_exit);
 821
lxr.linux.no kindly hosted by Redpill Linpro AS, provider of Linux consulting and operations services since 1995.