11da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* drivers/char/watchdog/scx200_wdt.c 21da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 31da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds National Semiconductor SCx200 Watchdog support 41da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 51da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds Copyright (c) 2001,2002 Christer Weinigel <wingel@nano-system.com> 61da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 71da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds Some code taken from: 81da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds National Semiconductor PC87307/PC97307 (ala SC1200) WDT driver 91da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds (c) Copyright 2002 Zwane Mwaikambo <zwane@commfireservices.com> 101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds This program is free software; you can redistribute it and/or 121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds modify it under the terms of the GNU General Public License as 131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds published by the Free Software Foundation; either version 2 of the 141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds License, or (at your option) any later version. 151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds The author(s) of this software shall not be held liable for damages 171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds of any nature resulting due to the use of this software. This 181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds software is provided AS-IS with no warranties. */ 191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2027c766aaacb265d625dc634bf7903f7f9fd0c697Joe Perches#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt 2127c766aaacb265d625dc634bf7903f7f9fd0c697Joe Perches 221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/module.h> 231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/moduleparam.h> 241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/init.h> 251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/miscdevice.h> 261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/watchdog.h> 271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/notifier.h> 281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/reboot.h> 291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/fs.h> 306473d160b4aba8023bcf38519a5989694dfd51a7Jean Delvare#include <linux/ioport.h> 311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/scx200.h> 329b748ed03cabf533a815e5ffc50108a21c98e40cAlan Cox#include <linux/uaccess.h> 339b748ed03cabf533a815e5ffc50108a21c98e40cAlan Cox#include <linux/io.h> 341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3527c766aaacb265d625dc634bf7903f7f9fd0c697Joe Perches#define DEBUG 361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsMODULE_AUTHOR("Christer Weinigel <wingel@nano-system.com>"); 381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsMODULE_DESCRIPTION("NatSemi SCx200 Watchdog Driver"); 391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsMODULE_LICENSE("GPL"); 401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int margin = 60; /* in seconds */ 421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsmodule_param(margin, int, 0); 431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsMODULE_PARM_DESC(margin, "Watchdog margin in seconds"); 441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4586a1e1896c2710402e29a875d8d830244274244dWim Van Sebroeckstatic bool nowayout = WATCHDOG_NOWAYOUT; 4686a1e1896c2710402e29a875d8d830244274244dWim Van Sebroeckmodule_param(nowayout, bool, 0); 471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsMODULE_PARM_DESC(nowayout, "Disable watchdog shutdown on close"); 481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic u16 wdto_restart; 501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic char expect_close; 519b748ed03cabf533a815e5ffc50108a21c98e40cAlan Coxstatic unsigned long open_lock; 529b748ed03cabf533a815e5ffc50108a21c98e40cAlan Coxstatic DEFINE_SPINLOCK(scx_lock); 531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* Bits of the WDCNFG register */ 551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define W_ENABLE 0x00fa /* Enable watchdog */ 561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define W_DISABLE 0x0000 /* Disable watchdog */ 571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* The scaling factor for the timer, this depends on the value of W_ENABLE */ 591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define W_SCALE (32768/1024) 601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void scx200_wdt_ping(void) 621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 639b748ed03cabf533a815e5ffc50108a21c98e40cAlan Cox spin_lock(&scx_lock); 641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds outw(wdto_restart, scx200_cb_base + SCx200_WDT_WDTO); 659b748ed03cabf533a815e5ffc50108a21c98e40cAlan Cox spin_unlock(&scx_lock); 661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void scx200_wdt_update_margin(void) 691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 7027c766aaacb265d625dc634bf7903f7f9fd0c697Joe Perches pr_info("timer margin %d seconds\n", margin); 711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds wdto_restart = margin * W_SCALE; 721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void scx200_wdt_enable(void) 751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 7627c766aaacb265d625dc634bf7903f7f9fd0c697Joe Perches pr_debug("enabling watchdog timer, wdto_restart = %d\n", wdto_restart); 771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 789b748ed03cabf533a815e5ffc50108a21c98e40cAlan Cox spin_lock(&scx_lock); 791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds outw(0, scx200_cb_base + SCx200_WDT_WDTO); 801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds outb(SCx200_WDT_WDSTS_WDOVF, scx200_cb_base + SCx200_WDT_WDSTS); 811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds outw(W_ENABLE, scx200_cb_base + SCx200_WDT_WDCNFG); 829b748ed03cabf533a815e5ffc50108a21c98e40cAlan Cox spin_unlock(&scx_lock); 831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds scx200_wdt_ping(); 851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void scx200_wdt_disable(void) 881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 8927c766aaacb265d625dc634bf7903f7f9fd0c697Joe Perches pr_debug("disabling watchdog timer\n"); 901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 919b748ed03cabf533a815e5ffc50108a21c98e40cAlan Cox spin_lock(&scx_lock); 921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds outw(0, scx200_cb_base + SCx200_WDT_WDTO); 931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds outb(SCx200_WDT_WDSTS_WDOVF, scx200_cb_base + SCx200_WDT_WDSTS); 941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds outw(W_DISABLE, scx200_cb_base + SCx200_WDT_WDCNFG); 959b748ed03cabf533a815e5ffc50108a21c98e40cAlan Cox spin_unlock(&scx_lock); 961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int scx200_wdt_open(struct inode *inode, struct file *file) 991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 1001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* only allow one at a time */ 1019b748ed03cabf533a815e5ffc50108a21c98e40cAlan Cox if (test_and_set_bit(0, &open_lock)) 1021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -EBUSY; 1031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds scx200_wdt_enable(); 1041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return nonseekable_open(inode, file); 1061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 1071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int scx200_wdt_release(struct inode *inode, struct file *file) 1091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 1109b748ed03cabf533a815e5ffc50108a21c98e40cAlan Cox if (expect_close != 42) 11127c766aaacb265d625dc634bf7903f7f9fd0c697Joe Perches pr_warn("watchdog device closed unexpectedly, will not disable the watchdog timer\n"); 1129b748ed03cabf533a815e5ffc50108a21c98e40cAlan Cox else if (!nowayout) 1131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds scx200_wdt_disable(); 1141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds expect_close = 0; 1159b748ed03cabf533a815e5ffc50108a21c98e40cAlan Cox clear_bit(0, &open_lock); 1161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 0; 1181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 1191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int scx200_wdt_notify_sys(struct notifier_block *this, 1211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned long code, void *unused) 1221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 1231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (code == SYS_HALT || code == SYS_POWER_OFF) 1241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!nowayout) 1251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds scx200_wdt_disable(); 1261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return NOTIFY_DONE; 1281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 1291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1309b748ed03cabf533a815e5ffc50108a21c98e40cAlan Coxstatic struct notifier_block scx200_wdt_notifier = { 1311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .notifier_call = scx200_wdt_notify_sys, 1321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}; 1331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic ssize_t scx200_wdt_write(struct file *file, const char __user *data, 1351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds size_t len, loff_t *ppos) 1361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 1371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* check for a magic close character */ 1389b748ed03cabf533a815e5ffc50108a21c98e40cAlan Cox if (len) { 1391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds size_t i; 1401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds scx200_wdt_ping(); 1421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds expect_close = 0; 1441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds for (i = 0; i < len; ++i) { 1451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds char c; 1467944d3a5a70ee5c1904ed1e8b1d71ff0af2854d9Wim Van Sebroeck if (get_user(c, data + i)) 1471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -EFAULT; 1481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (c == 'V') 1491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds expect_close = 42; 1501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 1511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return len; 1531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 1541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 0; 1561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 1571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1589b748ed03cabf533a815e5ffc50108a21c98e40cAlan Coxstatic long scx200_wdt_ioctl(struct file *file, unsigned int cmd, 1599b748ed03cabf533a815e5ffc50108a21c98e40cAlan Cox unsigned long arg) 1601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 1611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds void __user *argp = (void __user *)arg; 1621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int __user *p = argp; 1639b748ed03cabf533a815e5ffc50108a21c98e40cAlan Cox static const struct watchdog_info ident = { 1641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .identity = "NatSemi SCx200 Watchdog", 1651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .firmware_version = 1, 166e73a780272a46e897bd94a4870fd6b6a8655d2d4Wim Van Sebroeck .options = WDIOF_SETTIMEOUT | WDIOF_KEEPALIVEPING | 167e73a780272a46e897bd94a4870fd6b6a8655d2d4Wim Van Sebroeck WDIOF_MAGICCLOSE, 1681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds }; 1691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int new_margin; 1701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds switch (cmd) { 1721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case WDIOC_GETSUPPORT: 1739b748ed03cabf533a815e5ffc50108a21c98e40cAlan Cox if (copy_to_user(argp, &ident, sizeof(ident))) 1741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -EFAULT; 1751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 0; 1761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case WDIOC_GETSTATUS: 1771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case WDIOC_GETBOOTSTATUS: 1781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (put_user(0, p)) 1791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -EFAULT; 1801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 0; 1811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case WDIOC_KEEPALIVE: 1821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds scx200_wdt_ping(); 1831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 0; 1841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case WDIOC_SETTIMEOUT: 1851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (get_user(new_margin, p)) 1861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -EFAULT; 1871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (new_margin < 1) 1881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -EINVAL; 1891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds margin = new_margin; 1901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds scx200_wdt_update_margin(); 1911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds scx200_wdt_ping(); 1921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case WDIOC_GETTIMEOUT: 1931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (put_user(margin, p)) 1941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -EFAULT; 1951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 0; 1960c06090c9472db0525cb6fe229c3bea33bbbbb3cWim Van Sebroeck default: 1970c06090c9472db0525cb6fe229c3bea33bbbbb3cWim Van Sebroeck return -ENOTTY; 1981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 1991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 2001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 20162322d2554d2f9680c8ace7bbf1f97d8fa84ad1aArjan van de Venstatic const struct file_operations scx200_wdt_fops = { 2029b748ed03cabf533a815e5ffc50108a21c98e40cAlan Cox .owner = THIS_MODULE, 2039b748ed03cabf533a815e5ffc50108a21c98e40cAlan Cox .llseek = no_llseek, 2049b748ed03cabf533a815e5ffc50108a21c98e40cAlan Cox .write = scx200_wdt_write, 2059b748ed03cabf533a815e5ffc50108a21c98e40cAlan Cox .unlocked_ioctl = scx200_wdt_ioctl, 2069b748ed03cabf533a815e5ffc50108a21c98e40cAlan Cox .open = scx200_wdt_open, 2071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .release = scx200_wdt_release, 2081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}; 2091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic struct miscdevice scx200_wdt_miscdev = { 2111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .minor = WATCHDOG_MINOR, 2129b748ed03cabf533a815e5ffc50108a21c98e40cAlan Cox .name = "watchdog", 2139b748ed03cabf533a815e5ffc50108a21c98e40cAlan Cox .fops = &scx200_wdt_fops, 2141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}; 2151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int __init scx200_wdt_init(void) 2171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 2181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int r; 2191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 22027c766aaacb265d625dc634bf7903f7f9fd0c697Joe Perches pr_debug("NatSemi SCx200 Watchdog Driver\n"); 2211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* check that we have found the configuration block */ 2231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!scx200_cb_present()) 2241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -ENODEV; 2251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!request_region(scx200_cb_base + SCx200_WDT_OFFSET, 2271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds SCx200_WDT_SIZE, 2281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds "NatSemi SCx200 Watchdog")) { 22927c766aaacb265d625dc634bf7903f7f9fd0c697Joe Perches pr_warn("watchdog I/O region busy\n"); 2301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -EBUSY; 2311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 2321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds scx200_wdt_update_margin(); 2341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds scx200_wdt_disable(); 2351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 236c6cb13aead3a3cf5bd3e2cfa945602d5cd7825cdWim Van Sebroeck r = register_reboot_notifier(&scx200_wdt_notifier); 2371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (r) { 23827c766aaacb265d625dc634bf7903f7f9fd0c697Joe Perches pr_err("unable to register reboot notifier\n"); 2391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds release_region(scx200_cb_base + SCx200_WDT_OFFSET, 2401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds SCx200_WDT_SIZE); 2411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return r; 2421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 2431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 244c6cb13aead3a3cf5bd3e2cfa945602d5cd7825cdWim Van Sebroeck r = misc_register(&scx200_wdt_miscdev); 2451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (r) { 246c6cb13aead3a3cf5bd3e2cfa945602d5cd7825cdWim Van Sebroeck unregister_reboot_notifier(&scx200_wdt_notifier); 2471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds release_region(scx200_cb_base + SCx200_WDT_OFFSET, 2481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds SCx200_WDT_SIZE); 2491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return r; 2501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 2511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 0; 2531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 2541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void __exit scx200_wdt_cleanup(void) 2561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 2571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds misc_deregister(&scx200_wdt_miscdev); 258c6cb13aead3a3cf5bd3e2cfa945602d5cd7825cdWim Van Sebroeck unregister_reboot_notifier(&scx200_wdt_notifier); 2591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds release_region(scx200_cb_base + SCx200_WDT_OFFSET, 2601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds SCx200_WDT_SIZE); 2611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 2621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsmodule_init(scx200_wdt_init); 2641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsmodule_exit(scx200_wdt_cleanup); 2651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 2671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds Local variables: 2689b748ed03cabf533a815e5ffc50108a21c98e40cAlan Cox compile-command: "make -k -C ../.. SUBDIRS=drivers/char modules" 2699b748ed03cabf533a815e5ffc50108a21c98e40cAlan Cox c-basic-offset: 8 2701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds End: 2711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds*/ 272