11da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 21da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * National Semiconductor PC87307/PC97307 (ala SC1200) WDT driver 31da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * (c) Copyright 2002 Zwane Mwaikambo <zwane@commfireservices.com>, 41da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * All Rights Reserved. 51da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Based on wdt.c and wdt977.c by Alan Cox and Woody Suwalski respectively. 61da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 71da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * This program is free software; you can redistribute it and/or 81da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * modify it under the terms of the GNU General Public License 91da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * as published by the Free Software Foundation; either version 101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 2 of the License, or (at your option) any later version. 111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * The author(s) of this software shall not be held liable for damages 131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * of any nature resulting due to the use of this software. This 141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * software is provided AS-IS with no warranties. 151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Changelog: 171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 20020220 Zwane Mwaikambo Code based on datasheet, no hardware. 18103a1d5c57fac3623613b130b104f5b03367b31cAlan Cox * 20020221 Zwane Mwaikambo Cleanups as suggested by Jeff Garzik 19103a1d5c57fac3623613b130b104f5b03367b31cAlan Cox * and Alan Cox. 201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 20020222 Zwane Mwaikambo Added probing. 211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 20020225 Zwane Mwaikambo Added ISAPNP support. 221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 20020412 Rob Radez Broke out start/stop functions 23103a1d5c57fac3623613b130b104f5b03367b31cAlan Cox * <rob@osinvestor.com> Return proper status instead of 24103a1d5c57fac3623613b130b104f5b03367b31cAlan Cox * temperature warning 25103a1d5c57fac3623613b130b104f5b03367b31cAlan Cox * Add WDIOC_GETBOOTSTATUS and 26103a1d5c57fac3623613b130b104f5b03367b31cAlan Cox * WDIOC_SETOPTIONS ioctls 271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Fix CONFIG_WATCHDOG_NOWAYOUT 28103a1d5c57fac3623613b130b104f5b03367b31cAlan Cox * 20020530 Joel Becker Add Matt Domsch's nowayout module 29103a1d5c57fac3623613b130b104f5b03367b31cAlan Cox * option 301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 20030116 Adam Belay Updated to the latest pnp code 311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3427c766aaacb265d625dc634bf7903f7f9fd0c697Joe Perches#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt 3527c766aaacb265d625dc634bf7903f7f9fd0c697Joe Perches 361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/module.h> 371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/moduleparam.h> 381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/miscdevice.h> 391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/watchdog.h> 401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/ioport.h> 411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/spinlock.h> 421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/notifier.h> 431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/reboot.h> 441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/init.h> 451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/pnp.h> 461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/fs.h> 476188e10d38b8d7244ee7776d5f1f88c837b4b93fMatthew Wilcox#include <linux/semaphore.h> 48103a1d5c57fac3623613b130b104f5b03367b31cAlan Cox#include <linux/io.h> 49103a1d5c57fac3623613b130b104f5b03367b31cAlan Cox#include <linux/uaccess.h> 501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define SC1200_MODULE_VER "build 20020303" 521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define SC1200_MODULE_NAME "sc1200wdt" 531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define MAX_TIMEOUT 255 /* 255 minutes */ 551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define PMIR (io) /* Power Management Index Register */ 561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define PMDR (io+1) /* Power Management Data Register */ 571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* Data Register indexes */ 591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define FER1 0x00 /* Function enable register 1 */ 601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define FER2 0x01 /* Function enable register 2 */ 611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define PMC1 0x02 /* Power Management Ctrl 1 */ 621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define PMC2 0x03 /* Power Management Ctrl 2 */ 631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define PMC3 0x04 /* Power Management Ctrl 3 */ 641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define WDTO 0x05 /* Watchdog timeout register */ 651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define WDCF 0x06 /* Watchdog config register */ 661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define WDST 0x07 /* Watchdog status register */ 671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* WDCF bitfields - which devices assert WDO */ 691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define KBC_IRQ 0x01 /* Keyboard Controller */ 701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define MSE_IRQ 0x02 /* Mouse */ 711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define UART1_IRQ 0x03 /* Serial0 */ 721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define UART2_IRQ 0x04 /* Serial1 */ 731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 5 -7 are reserved */ 741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int timeout = 1; 761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int io = -1; 771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int io_len = 2; /* for non plug and play */ 78103a1d5c57fac3623613b130b104f5b03367b31cAlan Coxstatic unsigned long open_flag; 791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic char expect_close; 80c7dfd0cca300c5dc49213cf1c78c77393600410dAlexey Dobriyanstatic DEFINE_SPINLOCK(sc1200wdt_lock); /* io port access serialisation */ 811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#if defined CONFIG_PNP 831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int isapnp = 1; 841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic struct pnp_dev *wdt_dev; 851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsmodule_param(isapnp, int, 0); 87103a1d5c57fac3623613b130b104f5b03367b31cAlan CoxMODULE_PARM_DESC(isapnp, 88103a1d5c57fac3623613b130b104f5b03367b31cAlan Cox "When set to 0 driver ISA PnP support will be disabled"); 891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif 901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsmodule_param(io, int, 0); 921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsMODULE_PARM_DESC(io, "io port"); 931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsmodule_param(timeout, int, 0); 941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsMODULE_PARM_DESC(timeout, "range is 0-255 minutes, default is 1"); 951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 9686a1e1896c2710402e29a875d8d830244274244dWim Van Sebroeckstatic bool nowayout = WATCHDOG_NOWAYOUT; 9786a1e1896c2710402e29a875d8d830244274244dWim Van Sebroeckmodule_param(nowayout, bool, 0); 98103a1d5c57fac3623613b130b104f5b03367b31cAlan CoxMODULE_PARM_DESC(nowayout, 99103a1d5c57fac3623613b130b104f5b03367b31cAlan Cox "Watchdog cannot be stopped once started (default=" 100103a1d5c57fac3623613b130b104f5b03367b31cAlan Cox __MODULE_STRING(WATCHDOG_NOWAYOUT) ")"); 1011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* Read from Data Register */ 105103a1d5c57fac3623613b130b104f5b03367b31cAlan Coxstatic inline void __sc1200wdt_read_data(unsigned char index, 106103a1d5c57fac3623613b130b104f5b03367b31cAlan Cox unsigned char *data) 1071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 1081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds outb_p(index, PMIR); 1091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *data = inb(PMDR); 1101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 1111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 112103a1d5c57fac3623613b130b104f5b03367b31cAlan Coxstatic void sc1200wdt_read_data(unsigned char index, unsigned char *data) 113103a1d5c57fac3623613b130b104f5b03367b31cAlan Cox{ 114103a1d5c57fac3623613b130b104f5b03367b31cAlan Cox spin_lock(&sc1200wdt_lock); 115103a1d5c57fac3623613b130b104f5b03367b31cAlan Cox __sc1200wdt_read_data(index, data); 116103a1d5c57fac3623613b130b104f5b03367b31cAlan Cox spin_unlock(&sc1200wdt_lock); 117103a1d5c57fac3623613b130b104f5b03367b31cAlan Cox} 1181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* Write to Data Register */ 120103a1d5c57fac3623613b130b104f5b03367b31cAlan Coxstatic inline void __sc1200wdt_write_data(unsigned char index, 121103a1d5c57fac3623613b130b104f5b03367b31cAlan Cox unsigned char data) 1221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 1231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds outb_p(index, PMIR); 1241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds outb(data, PMDR); 125103a1d5c57fac3623613b130b104f5b03367b31cAlan Cox} 126103a1d5c57fac3623613b130b104f5b03367b31cAlan Cox 127103a1d5c57fac3623613b130b104f5b03367b31cAlan Coxstatic inline void sc1200wdt_write_data(unsigned char index, 128103a1d5c57fac3623613b130b104f5b03367b31cAlan Cox unsigned char data) 129103a1d5c57fac3623613b130b104f5b03367b31cAlan Cox{ 130103a1d5c57fac3623613b130b104f5b03367b31cAlan Cox spin_lock(&sc1200wdt_lock); 131103a1d5c57fac3623613b130b104f5b03367b31cAlan Cox __sc1200wdt_write_data(index, data); 1321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds spin_unlock(&sc1200wdt_lock); 1331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 1341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void sc1200wdt_start(void) 1371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 1381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned char reg; 139103a1d5c57fac3623613b130b104f5b03367b31cAlan Cox spin_lock(&sc1200wdt_lock); 1401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 141103a1d5c57fac3623613b130b104f5b03367b31cAlan Cox __sc1200wdt_read_data(WDCF, ®); 1421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* assert WDO when any of the following interrupts are triggered too */ 1431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds reg |= (KBC_IRQ | MSE_IRQ | UART1_IRQ | UART2_IRQ); 144103a1d5c57fac3623613b130b104f5b03367b31cAlan Cox __sc1200wdt_write_data(WDCF, reg); 1451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* set the timeout and get the ball rolling */ 146103a1d5c57fac3623613b130b104f5b03367b31cAlan Cox __sc1200wdt_write_data(WDTO, timeout); 1471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 148103a1d5c57fac3623613b130b104f5b03367b31cAlan Cox spin_unlock(&sc1200wdt_lock); 149103a1d5c57fac3623613b130b104f5b03367b31cAlan Cox} 1501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void sc1200wdt_stop(void) 1521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 1531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds sc1200wdt_write_data(WDTO, 0); 1541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 1551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* This returns the status of the WDO signal, inactive high. */ 1571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic inline int sc1200wdt_status(void) 1581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 1591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned char ret; 1601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds sc1200wdt_read_data(WDST, &ret); 1621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* If the bit is inactive, the watchdog is enabled, so return 1631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * KEEPALIVEPING which is a bit of a kludge because there's nothing 1641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * else for enabled/disabled status 1651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 166103a1d5c57fac3623613b130b104f5b03367b31cAlan Cox return (ret & 0x01) ? 0 : WDIOF_KEEPALIVEPING; 1671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 1681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int sc1200wdt_open(struct inode *inode, struct file *file) 1701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 1711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* allow one at a time */ 172103a1d5c57fac3623613b130b104f5b03367b31cAlan Cox if (test_and_set_bit(0, &open_flag)) 1731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -EBUSY; 1741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (timeout > MAX_TIMEOUT) 1761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds timeout = MAX_TIMEOUT; 1771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds sc1200wdt_start(); 17927c766aaacb265d625dc634bf7903f7f9fd0c697Joe Perches pr_info("Watchdog enabled, timeout = %d min(s)", timeout); 1801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1816abe78bf195c633f67f6349e3d09b2bcd5d32a79Wim Van Sebroeck return nonseekable_open(inode, file); 1821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 1831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 185103a1d5c57fac3623613b130b104f5b03367b31cAlan Coxstatic long sc1200wdt_ioctl(struct file *file, unsigned int cmd, 186103a1d5c57fac3623613b130b104f5b03367b31cAlan Cox unsigned long arg) 1871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 1881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int new_timeout; 1891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds void __user *argp = (void __user *)arg; 1901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int __user *p = argp; 191103a1d5c57fac3623613b130b104f5b03367b31cAlan Cox static const struct watchdog_info ident = { 192103a1d5c57fac3623613b130b104f5b03367b31cAlan Cox .options = WDIOF_KEEPALIVEPING | WDIOF_SETTIMEOUT | 193103a1d5c57fac3623613b130b104f5b03367b31cAlan Cox WDIOF_MAGICCLOSE, 1941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .firmware_version = 0, 1951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .identity = "PC87307/PC97307", 1961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds }; 1971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds switch (cmd) { 199103a1d5c57fac3623613b130b104f5b03367b31cAlan Cox case WDIOC_GETSUPPORT: 200e04ab958727a4b314df3e40036d72d9348835d0cWim Van Sebroeck if (copy_to_user(argp, &ident, sizeof(ident))) 201103a1d5c57fac3623613b130b104f5b03367b31cAlan Cox return -EFAULT; 202103a1d5c57fac3623613b130b104f5b03367b31cAlan Cox return 0; 2031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 204103a1d5c57fac3623613b130b104f5b03367b31cAlan Cox case WDIOC_GETSTATUS: 205103a1d5c57fac3623613b130b104f5b03367b31cAlan Cox return put_user(sc1200wdt_status(), p); 2061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 207103a1d5c57fac3623613b130b104f5b03367b31cAlan Cox case WDIOC_GETBOOTSTATUS: 208103a1d5c57fac3623613b130b104f5b03367b31cAlan Cox return put_user(0, p); 2091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 210103a1d5c57fac3623613b130b104f5b03367b31cAlan Cox case WDIOC_SETOPTIONS: 211103a1d5c57fac3623613b130b104f5b03367b31cAlan Cox { 212103a1d5c57fac3623613b130b104f5b03367b31cAlan Cox int options, retval = -EINVAL; 2131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 214103a1d5c57fac3623613b130b104f5b03367b31cAlan Cox if (get_user(options, p)) 215103a1d5c57fac3623613b130b104f5b03367b31cAlan Cox return -EFAULT; 2161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 217103a1d5c57fac3623613b130b104f5b03367b31cAlan Cox if (options & WDIOS_DISABLECARD) { 218103a1d5c57fac3623613b130b104f5b03367b31cAlan Cox sc1200wdt_stop(); 219103a1d5c57fac3623613b130b104f5b03367b31cAlan Cox retval = 0; 220103a1d5c57fac3623613b130b104f5b03367b31cAlan Cox } 2211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 222103a1d5c57fac3623613b130b104f5b03367b31cAlan Cox if (options & WDIOS_ENABLECARD) { 223103a1d5c57fac3623613b130b104f5b03367b31cAlan Cox sc1200wdt_start(); 224103a1d5c57fac3623613b130b104f5b03367b31cAlan Cox retval = 0; 2251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 226103a1d5c57fac3623613b130b104f5b03367b31cAlan Cox 227103a1d5c57fac3623613b130b104f5b03367b31cAlan Cox return retval; 228103a1d5c57fac3623613b130b104f5b03367b31cAlan Cox } 2290c06090c9472db0525cb6fe229c3bea33bbbbb3cWim Van Sebroeck case WDIOC_KEEPALIVE: 2300c06090c9472db0525cb6fe229c3bea33bbbbb3cWim Van Sebroeck sc1200wdt_write_data(WDTO, timeout); 2310c06090c9472db0525cb6fe229c3bea33bbbbb3cWim Van Sebroeck return 0; 2320c06090c9472db0525cb6fe229c3bea33bbbbb3cWim Van Sebroeck 2330c06090c9472db0525cb6fe229c3bea33bbbbb3cWim Van Sebroeck case WDIOC_SETTIMEOUT: 2340c06090c9472db0525cb6fe229c3bea33bbbbb3cWim Van Sebroeck if (get_user(new_timeout, p)) 2350c06090c9472db0525cb6fe229c3bea33bbbbb3cWim Van Sebroeck return -EFAULT; 2360c06090c9472db0525cb6fe229c3bea33bbbbb3cWim Van Sebroeck /* the API states this is given in secs */ 2370c06090c9472db0525cb6fe229c3bea33bbbbb3cWim Van Sebroeck new_timeout /= 60; 2380c06090c9472db0525cb6fe229c3bea33bbbbb3cWim Van Sebroeck if (new_timeout < 0 || new_timeout > MAX_TIMEOUT) 2390c06090c9472db0525cb6fe229c3bea33bbbbb3cWim Van Sebroeck return -EINVAL; 2400c06090c9472db0525cb6fe229c3bea33bbbbb3cWim Van Sebroeck timeout = new_timeout; 2410c06090c9472db0525cb6fe229c3bea33bbbbb3cWim Van Sebroeck sc1200wdt_write_data(WDTO, timeout); 2420c06090c9472db0525cb6fe229c3bea33bbbbb3cWim Van Sebroeck /* fall through and return the new timeout */ 2430c06090c9472db0525cb6fe229c3bea33bbbbb3cWim Van Sebroeck 2440c06090c9472db0525cb6fe229c3bea33bbbbb3cWim Van Sebroeck case WDIOC_GETTIMEOUT: 2450c06090c9472db0525cb6fe229c3bea33bbbbb3cWim Van Sebroeck return put_user(timeout * 60, p); 2460c06090c9472db0525cb6fe229c3bea33bbbbb3cWim Van Sebroeck 247103a1d5c57fac3623613b130b104f5b03367b31cAlan Cox default: 248103a1d5c57fac3623613b130b104f5b03367b31cAlan Cox return -ENOTTY; 2491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 2501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 2511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int sc1200wdt_release(struct inode *inode, struct file *file) 2541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 2551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (expect_close == 42) { 2561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds sc1200wdt_stop(); 25727c766aaacb265d625dc634bf7903f7f9fd0c697Joe Perches pr_info("Watchdog disabled\n"); 2581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } else { 2591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds sc1200wdt_write_data(WDTO, timeout); 26027c766aaacb265d625dc634bf7903f7f9fd0c697Joe Perches pr_crit("Unexpected close!, timeout = %d min(s)\n", timeout); 2611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 262103a1d5c57fac3623613b130b104f5b03367b31cAlan Cox clear_bit(0, &open_flag); 2631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds expect_close = 0; 2641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 0; 2661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 2671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 269103a1d5c57fac3623613b130b104f5b03367b31cAlan Coxstatic ssize_t sc1200wdt_write(struct file *file, const char __user *data, 270103a1d5c57fac3623613b130b104f5b03367b31cAlan Cox size_t len, loff_t *ppos) 2711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 2721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (len) { 2731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!nowayout) { 2741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds size_t i; 2751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds expect_close = 0; 2771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds for (i = 0; i != len; i++) { 2791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds char c; 2801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2817944d3a5a70ee5c1904ed1e8b1d71ff0af2854d9Wim Van Sebroeck if (get_user(c, data + i)) 2821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -EFAULT; 2831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (c == 'V') 2841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds expect_close = 42; 2851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 2861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 2871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds sc1200wdt_write_data(WDTO, timeout); 2891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return len; 2901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 2911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 0; 2931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 2941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 296103a1d5c57fac3623613b130b104f5b03367b31cAlan Coxstatic int sc1200wdt_notify_sys(struct notifier_block *this, 297103a1d5c57fac3623613b130b104f5b03367b31cAlan Cox unsigned long code, void *unused) 2981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 2991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (code == SYS_DOWN || code == SYS_HALT) 3001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds sc1200wdt_stop(); 3011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return NOTIFY_DONE; 3031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 3041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 306103a1d5c57fac3623613b130b104f5b03367b31cAlan Coxstatic struct notifier_block sc1200wdt_notifier = { 3071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .notifier_call = sc1200wdt_notify_sys, 3081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}; 3091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 310103a1d5c57fac3623613b130b104f5b03367b31cAlan Coxstatic const struct file_operations sc1200wdt_fops = { 3111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .owner = THIS_MODULE, 3121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .llseek = no_llseek, 3131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .write = sc1200wdt_write, 314103a1d5c57fac3623613b130b104f5b03367b31cAlan Cox .unlocked_ioctl = sc1200wdt_ioctl, 3151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .open = sc1200wdt_open, 3161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .release = sc1200wdt_release, 3171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}; 3181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 319103a1d5c57fac3623613b130b104f5b03367b31cAlan Coxstatic struct miscdevice sc1200wdt_miscdev = { 3201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .minor = WATCHDOG_MINOR, 3211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .name = "watchdog", 3221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .fops = &sc1200wdt_fops, 3231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}; 3241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int __init sc1200wdt_probe(void) 3271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 3281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* The probe works by reading the PMC3 register's default value of 0x0e 3291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * there is one caveat, if the device disables the parallel port or any 3301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * of the UARTs we won't be able to detect it. 331103a1d5c57fac3623613b130b104f5b03367b31cAlan Cox * NB. This could be done with accuracy by reading the SID registers, 332103a1d5c57fac3623613b130b104f5b03367b31cAlan Cox * but we don't have access to those io regions. 3331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 3341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned char reg; 3361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds sc1200wdt_read_data(PMC3, ®); 338103a1d5c57fac3623613b130b104f5b03367b31cAlan Cox reg &= 0x0f; /* we don't want the UART busy bits */ 3391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return (reg == 0x0e) ? 0 : -ENODEV; 3401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 3411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#if defined CONFIG_PNP 3441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic struct pnp_device_id scl200wdt_pnp_devices[] = { 3461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* National Semiconductor PC87307/PC97307 watchdog component */ 3471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds {.id = "NSC0800", .driver_data = 0}, 3481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds {.id = ""}, 3491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}; 3501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 351103a1d5c57fac3623613b130b104f5b03367b31cAlan Coxstatic int scl200wdt_pnp_probe(struct pnp_dev *dev, 352103a1d5c57fac3623613b130b104f5b03367b31cAlan Cox const struct pnp_device_id *dev_id) 3531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 3541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* this driver only supports one card at a time */ 3551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (wdt_dev || !isapnp) 3561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -EBUSY; 3571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds wdt_dev = dev; 3591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds io = pnp_port_start(wdt_dev, 0); 3601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds io_len = pnp_port_len(wdt_dev, 0); 3611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!request_region(io, io_len, SC1200_MODULE_NAME)) { 36327c766aaacb265d625dc634bf7903f7f9fd0c697Joe Perches pr_err("Unable to register IO port %#x\n", io); 3641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -EBUSY; 3651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 3661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 36727c766aaacb265d625dc634bf7903f7f9fd0c697Joe Perches pr_info("PnP device found at io port %#x/%d\n", io, io_len); 3681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 0; 3691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 3701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 371103a1d5c57fac3623613b130b104f5b03367b31cAlan Coxstatic void scl200wdt_pnp_remove(struct pnp_dev *dev) 3721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 373103a1d5c57fac3623613b130b104f5b03367b31cAlan Cox if (wdt_dev) { 3741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds release_region(io, io_len); 3751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds wdt_dev = NULL; 3761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 3771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 3781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic struct pnp_driver scl200wdt_pnp_driver = { 3801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .name = "scl200wdt", 3811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .id_table = scl200wdt_pnp_devices, 3821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .probe = scl200wdt_pnp_probe, 3831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .remove = scl200wdt_pnp_remove, 3841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}; 3851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif /* CONFIG_PNP */ 3871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int __init sc1200wdt_init(void) 3901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 3911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int ret; 3921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 39327c766aaacb265d625dc634bf7903f7f9fd0c697Joe Perches pr_info("%s\n", SC1200_MODULE_VER); 3941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#if defined CONFIG_PNP 3961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (isapnp) { 3971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ret = pnp_register_driver(&scl200wdt_pnp_driver); 3981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (ret) 3991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto out_clean; 4001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 4011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif 4021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (io == -1) { 40427c766aaacb265d625dc634bf7903f7f9fd0c697Joe Perches pr_err("io parameter must be specified\n"); 4051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ret = -EINVAL; 406150ed8ed63b96d7f93ef7e6081797aa0df2b1abdAkinobu Mita goto out_pnp; 4071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 4081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#if defined CONFIG_PNP 4101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* now that the user has specified an IO port and we haven't detected 4111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * any devices, disable pnp support */ 4121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds isapnp = 0; 4131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds pnp_unregister_driver(&scl200wdt_pnp_driver); 4141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif 4151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!request_region(io, io_len, SC1200_MODULE_NAME)) { 41727c766aaacb265d625dc634bf7903f7f9fd0c697Joe Perches pr_err("Unable to register IO port %#x\n", io); 4181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ret = -EBUSY; 419150ed8ed63b96d7f93ef7e6081797aa0df2b1abdAkinobu Mita goto out_pnp; 4201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 4211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ret = sc1200wdt_probe(); 4231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (ret) 4241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto out_io; 4251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ret = register_reboot_notifier(&sc1200wdt_notifier); 4271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (ret) { 42827c766aaacb265d625dc634bf7903f7f9fd0c697Joe Perches pr_err("Unable to register reboot notifier err = %d\n", ret); 4291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto out_io; 4301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 4311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ret = misc_register(&sc1200wdt_miscdev); 4331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (ret) { 43427c766aaacb265d625dc634bf7903f7f9fd0c697Joe Perches pr_err("Unable to register miscdev on minor %d\n", 43527c766aaacb265d625dc634bf7903f7f9fd0c697Joe Perches WATCHDOG_MINOR); 4361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto out_rbt; 4371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 4381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* ret = 0 */ 4401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsout_clean: 4421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return ret; 4431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsout_rbt: 4451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unregister_reboot_notifier(&sc1200wdt_notifier); 4461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsout_io: 4481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds release_region(io, io_len); 4491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 450150ed8ed63b96d7f93ef7e6081797aa0df2b1abdAkinobu Mitaout_pnp: 451150ed8ed63b96d7f93ef7e6081797aa0df2b1abdAkinobu Mita#if defined CONFIG_PNP 452150ed8ed63b96d7f93ef7e6081797aa0df2b1abdAkinobu Mita if (isapnp) 453150ed8ed63b96d7f93ef7e6081797aa0df2b1abdAkinobu Mita pnp_unregister_driver(&scl200wdt_pnp_driver); 454150ed8ed63b96d7f93ef7e6081797aa0df2b1abdAkinobu Mita#endif 4551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto out_clean; 4561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 4571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void __exit sc1200wdt_exit(void) 4601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 4611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds misc_deregister(&sc1200wdt_miscdev); 4621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unregister_reboot_notifier(&sc1200wdt_notifier); 4631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#if defined CONFIG_PNP 465103a1d5c57fac3623613b130b104f5b03367b31cAlan Cox if (isapnp) 4661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds pnp_unregister_driver(&scl200wdt_pnp_driver); 4671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds else 4681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif 4691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds release_region(io, io_len); 4701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 4711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsmodule_init(sc1200wdt_init); 4731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsmodule_exit(sc1200wdt_exit); 4741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsMODULE_AUTHOR("Zwane Mwaikambo <zwane@commfireservices.com>"); 476143a2e54bf53216674eada16e8953f48b159e08aWim Van SebroeckMODULE_DESCRIPTION( 477143a2e54bf53216674eada16e8953f48b159e08aWim Van Sebroeck "Driver for National Semiconductor PC87307/PC97307 watchdog component"); 4781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsMODULE_LICENSE("GPL"); 4791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsMODULE_ALIAS_MISCDEV(WATCHDOG_MINOR); 480