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