scx200_wdt.c revision e73a780272a46e897bd94a4870fd6b6a8655d2d4
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 201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/module.h> 211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/moduleparam.h> 221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/init.h> 231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/miscdevice.h> 241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/watchdog.h> 251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/notifier.h> 261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/reboot.h> 271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/fs.h> 286473d160b4aba8023bcf38519a5989694dfd51a7Jean Delvare#include <linux/ioport.h> 291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/scx200.h> 309b748ed03cabf533a815e5ffc50108a21c98e40cAlan Cox#include <linux/uaccess.h> 319b748ed03cabf533a815e5ffc50108a21c98e40cAlan Cox#include <linux/io.h> 321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define NAME "scx200_wdt" 341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsMODULE_AUTHOR("Christer Weinigel <wingel@nano-system.com>"); 361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsMODULE_DESCRIPTION("NatSemi SCx200 Watchdog Driver"); 371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsMODULE_LICENSE("GPL"); 381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsMODULE_ALIAS_MISCDEV(WATCHDOG_MINOR); 391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int margin = 60; /* in seconds */ 411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsmodule_param(margin, int, 0); 421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsMODULE_PARM_DESC(margin, "Watchdog margin in seconds"); 431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 444bfdf37830111321e2cd1fe0102dd776ce93194dAndrey Paninstatic int nowayout = WATCHDOG_NOWAYOUT; 451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsmodule_param(nowayout, int, 0); 461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsMODULE_PARM_DESC(nowayout, "Disable watchdog shutdown on close"); 471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic u16 wdto_restart; 491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic char expect_close; 509b748ed03cabf533a815e5ffc50108a21c98e40cAlan Coxstatic unsigned long open_lock; 519b748ed03cabf533a815e5ffc50108a21c98e40cAlan Coxstatic DEFINE_SPINLOCK(scx_lock); 521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* Bits of the WDCNFG register */ 541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define W_ENABLE 0x00fa /* Enable watchdog */ 551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define W_DISABLE 0x0000 /* Disable watchdog */ 561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* The scaling factor for the timer, this depends on the value of W_ENABLE */ 581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define W_SCALE (32768/1024) 591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void scx200_wdt_ping(void) 611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 629b748ed03cabf533a815e5ffc50108a21c98e40cAlan Cox spin_lock(&scx_lock); 631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds outw(wdto_restart, scx200_cb_base + SCx200_WDT_WDTO); 649b748ed03cabf533a815e5ffc50108a21c98e40cAlan Cox spin_unlock(&scx_lock); 651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void scx200_wdt_update_margin(void) 681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds printk(KERN_INFO NAME ": timer margin %d seconds\n", margin); 701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds wdto_restart = margin * W_SCALE; 711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void scx200_wdt_enable(void) 741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds printk(KERN_DEBUG NAME ": enabling watchdog timer, wdto_restart = %d\n", 761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 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{ 891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds printk(KERN_DEBUG NAME ": 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) 111a77dba7e444a6618cbb666d1b42b79842b9c0171Wim Van Sebroeck printk(KERN_WARNING NAME 112a77dba7e444a6618cbb666d1b42b79842b9c0171Wim Van Sebroeck ": watchdog device closed unexpectedly, " 113a77dba7e444a6618cbb666d1b42b79842b9c0171Wim Van Sebroeck "will not disable the watchdog timer\n"); 1149b748ed03cabf533a815e5ffc50108a21c98e40cAlan Cox else if (!nowayout) 1151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds scx200_wdt_disable(); 1161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds expect_close = 0; 1179b748ed03cabf533a815e5ffc50108a21c98e40cAlan Cox clear_bit(0, &open_lock); 1181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 0; 1201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 1211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int scx200_wdt_notify_sys(struct notifier_block *this, 1231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned long code, void *unused) 1241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 1251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (code == SYS_HALT || code == SYS_POWER_OFF) 1261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!nowayout) 1271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds scx200_wdt_disable(); 1281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return NOTIFY_DONE; 1301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 1311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1329b748ed03cabf533a815e5ffc50108a21c98e40cAlan Coxstatic struct notifier_block scx200_wdt_notifier = { 1331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .notifier_call = scx200_wdt_notify_sys, 1341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}; 1351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic ssize_t scx200_wdt_write(struct file *file, const char __user *data, 1371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds size_t len, loff_t *ppos) 1381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 1391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* check for a magic close character */ 1409b748ed03cabf533a815e5ffc50108a21c98e40cAlan Cox if (len) { 1411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds size_t i; 1421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds scx200_wdt_ping(); 1441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds expect_close = 0; 1461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds for (i = 0; i < len; ++i) { 1471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds char c; 1487944d3a5a70ee5c1904ed1e8b1d71ff0af2854d9Wim Van Sebroeck if (get_user(c, data + i)) 1491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -EFAULT; 1501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (c == 'V') 1511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds expect_close = 42; 1521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 1531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return len; 1551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 1561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 0; 1581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 1591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1609b748ed03cabf533a815e5ffc50108a21c98e40cAlan Coxstatic long scx200_wdt_ioctl(struct file *file, unsigned int cmd, 1619b748ed03cabf533a815e5ffc50108a21c98e40cAlan Cox unsigned long arg) 1621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 1631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds void __user *argp = (void __user *)arg; 1641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int __user *p = argp; 1659b748ed03cabf533a815e5ffc50108a21c98e40cAlan Cox static const struct watchdog_info ident = { 1661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .identity = "NatSemi SCx200 Watchdog", 1671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .firmware_version = 1, 168e73a780272a46e897bd94a4870fd6b6a8655d2d4Wim Van Sebroeck .options = WDIOF_SETTIMEOUT | WDIOF_KEEPALIVEPING | 169e73a780272a46e897bd94a4870fd6b6a8655d2d4Wim Van Sebroeck WDIOF_MAGICCLOSE, 1701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds }; 1711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int new_margin; 1721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds switch (cmd) { 1741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case WDIOC_GETSUPPORT: 1759b748ed03cabf533a815e5ffc50108a21c98e40cAlan Cox if (copy_to_user(argp, &ident, sizeof(ident))) 1761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -EFAULT; 1771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 0; 1781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case WDIOC_GETSTATUS: 1791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case WDIOC_GETBOOTSTATUS: 1801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (put_user(0, p)) 1811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -EFAULT; 1821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 0; 1831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case WDIOC_KEEPALIVE: 1841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds scx200_wdt_ping(); 1851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 0; 1861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case WDIOC_SETTIMEOUT: 1871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (get_user(new_margin, p)) 1881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -EFAULT; 1891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (new_margin < 1) 1901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -EINVAL; 1911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds margin = new_margin; 1921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds scx200_wdt_update_margin(); 1931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds scx200_wdt_ping(); 1941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case WDIOC_GETTIMEOUT: 1951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (put_user(margin, p)) 1961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -EFAULT; 1971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 0; 1980c06090c9472db0525cb6fe229c3bea33bbbbb3cWim Van Sebroeck default: 1990c06090c9472db0525cb6fe229c3bea33bbbbb3cWim Van Sebroeck return -ENOTTY; 2001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 2011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 2021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 20362322d2554d2f9680c8ace7bbf1f97d8fa84ad1aArjan van de Venstatic const struct file_operations scx200_wdt_fops = { 2049b748ed03cabf533a815e5ffc50108a21c98e40cAlan Cox .owner = THIS_MODULE, 2059b748ed03cabf533a815e5ffc50108a21c98e40cAlan Cox .llseek = no_llseek, 2069b748ed03cabf533a815e5ffc50108a21c98e40cAlan Cox .write = scx200_wdt_write, 2079b748ed03cabf533a815e5ffc50108a21c98e40cAlan Cox .unlocked_ioctl = scx200_wdt_ioctl, 2089b748ed03cabf533a815e5ffc50108a21c98e40cAlan Cox .open = scx200_wdt_open, 2091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .release = scx200_wdt_release, 2101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}; 2111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic struct miscdevice scx200_wdt_miscdev = { 2131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .minor = WATCHDOG_MINOR, 2149b748ed03cabf533a815e5ffc50108a21c98e40cAlan Cox .name = "watchdog", 2159b748ed03cabf533a815e5ffc50108a21c98e40cAlan Cox .fops = &scx200_wdt_fops, 2161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}; 2171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int __init scx200_wdt_init(void) 2191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 2201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int r; 2211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds printk(KERN_DEBUG NAME ": NatSemi SCx200 Watchdog Driver\n"); 2231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* check that we have found the configuration block */ 2251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!scx200_cb_present()) 2261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -ENODEV; 2271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!request_region(scx200_cb_base + SCx200_WDT_OFFSET, 2291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds SCx200_WDT_SIZE, 2301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds "NatSemi SCx200 Watchdog")) { 2311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds printk(KERN_WARNING NAME ": watchdog I/O region busy\n"); 2321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -EBUSY; 2331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 2341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds scx200_wdt_update_margin(); 2361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds scx200_wdt_disable(); 2371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 238c6cb13aead3a3cf5bd3e2cfa945602d5cd7825cdWim Van Sebroeck r = register_reboot_notifier(&scx200_wdt_notifier); 2391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (r) { 240c6cb13aead3a3cf5bd3e2cfa945602d5cd7825cdWim Van Sebroeck printk(KERN_ERR NAME ": unable to register reboot notifier"); 2411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds release_region(scx200_cb_base + SCx200_WDT_OFFSET, 2421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds SCx200_WDT_SIZE); 2431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return r; 2441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 2451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 246c6cb13aead3a3cf5bd3e2cfa945602d5cd7825cdWim Van Sebroeck r = misc_register(&scx200_wdt_miscdev); 2471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (r) { 248c6cb13aead3a3cf5bd3e2cfa945602d5cd7825cdWim Van Sebroeck unregister_reboot_notifier(&scx200_wdt_notifier); 2491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds release_region(scx200_cb_base + SCx200_WDT_OFFSET, 2501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds SCx200_WDT_SIZE); 2511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return r; 2521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 2531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 0; 2551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 2561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void __exit scx200_wdt_cleanup(void) 2581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 2591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds misc_deregister(&scx200_wdt_miscdev); 260c6cb13aead3a3cf5bd3e2cfa945602d5cd7825cdWim Van Sebroeck unregister_reboot_notifier(&scx200_wdt_notifier); 2611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds release_region(scx200_cb_base + SCx200_WDT_OFFSET, 2621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds SCx200_WDT_SIZE); 2631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 2641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsmodule_init(scx200_wdt_init); 2661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsmodule_exit(scx200_wdt_cleanup); 2671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 2691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds Local variables: 2709b748ed03cabf533a815e5ffc50108a21c98e40cAlan Cox compile-command: "make -k -C ../.. SUBDIRS=drivers/char modules" 2719b748ed03cabf533a815e5ffc50108a21c98e40cAlan Cox c-basic-offset: 8 2721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds End: 2731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds*/ 274