it87_wdt.c revision dfb0b8eae1f78c7d0cf7c8abe6c84ff8cefde50e
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 15dfb0b8eae1f78c7d0cf7c8abe6c84ff8cefde50eOndrej Zajicek * IT8702, IT8712, IT8716, IT8718, IT8720 and IT8726. 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 48ee3e96583e42dcb4bd406ce4e5f824bd5bb80013Ondrej Zajicek#define WATCHDOG_VERSION "1.13" 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 79dfb0b8eae1f78c7d0cf7c8abe6c84ff8cefde50eOndrej Zajicek#define IT8702_ID 0x8702 80e1fee94f346387739e683b31815ab54dc0a30bd6Oliver Schuster#define IT8705_ID 0x8705 81e1fee94f346387739e683b31815ab54dc0a30bd6Oliver Schuster#define IT8712_ID 0x8712 82e1fee94f346387739e683b31815ab54dc0a30bd6Oliver Schuster#define IT8716_ID 0x8716 83e1fee94f346387739e683b31815ab54dc0a30bd6Oliver Schuster#define IT8718_ID 0x8718 84ee3e96583e42dcb4bd406ce4e5f824bd5bb80013Ondrej Zajicek#define IT8720_ID 0x8720 85e1fee94f346387739e683b31815ab54dc0a30bd6Oliver Schuster#define IT8726_ID 0x8726 /* the data sheet suggest wrongly 0x8716 */ 86e1fee94f346387739e683b31815ab54dc0a30bd6Oliver Schuster 87e1fee94f346387739e683b31815ab54dc0a30bd6Oliver Schuster/* GPIO Configuration Registers LDN=0x07 */ 88e1fee94f346387739e683b31815ab54dc0a30bd6Oliver Schuster#define WDTCTRL 0x71 89e1fee94f346387739e683b31815ab54dc0a30bd6Oliver Schuster#define WDTCFG 0x72 90e1fee94f346387739e683b31815ab54dc0a30bd6Oliver Schuster#define WDTVALLSB 0x73 91e1fee94f346387739e683b31815ab54dc0a30bd6Oliver Schuster#define WDTVALMSB 0x74 92e1fee94f346387739e683b31815ab54dc0a30bd6Oliver Schuster 93e1fee94f346387739e683b31815ab54dc0a30bd6Oliver Schuster/* GPIO Bits WDTCTRL */ 94e1fee94f346387739e683b31815ab54dc0a30bd6Oliver Schuster#define WDT_CIRINT 0x80 95e1fee94f346387739e683b31815ab54dc0a30bd6Oliver Schuster#define WDT_MOUSEINT 0x40 96e1fee94f346387739e683b31815ab54dc0a30bd6Oliver Schuster#define WDT_KYBINT 0x20 97ee3e96583e42dcb4bd406ce4e5f824bd5bb80013Ondrej Zajicek#define WDT_GAMEPORT 0x10 /* not in it8718, it8720 */ 98e1fee94f346387739e683b31815ab54dc0a30bd6Oliver Schuster#define WDT_FORCE 0x02 99e1fee94f346387739e683b31815ab54dc0a30bd6Oliver Schuster#define WDT_ZERO 0x01 100e1fee94f346387739e683b31815ab54dc0a30bd6Oliver Schuster 101e1fee94f346387739e683b31815ab54dc0a30bd6Oliver Schuster/* GPIO Bits WDTCFG */ 102e1fee94f346387739e683b31815ab54dc0a30bd6Oliver Schuster#define WDT_TOV1 0x80 103e1fee94f346387739e683b31815ab54dc0a30bd6Oliver Schuster#define WDT_KRST 0x40 104e1fee94f346387739e683b31815ab54dc0a30bd6Oliver Schuster#define WDT_TOVE 0x20 105e1fee94f346387739e683b31815ab54dc0a30bd6Oliver Schuster#define WDT_PWROK 0x10 106e1fee94f346387739e683b31815ab54dc0a30bd6Oliver Schuster#define WDT_INT_MASK 0x0f 107e1fee94f346387739e683b31815ab54dc0a30bd6Oliver Schuster 108e1fee94f346387739e683b31815ab54dc0a30bd6Oliver Schuster/* CIR Configuration Register LDN=0x0a */ 109e1fee94f346387739e683b31815ab54dc0a30bd6Oliver Schuster#define CIR_ILS 0x70 110e1fee94f346387739e683b31815ab54dc0a30bd6Oliver Schuster 111e1fee94f346387739e683b31815ab54dc0a30bd6Oliver Schuster/* The default Base address is not always available, we use this */ 112e1fee94f346387739e683b31815ab54dc0a30bd6Oliver Schuster#define CIR_BASE 0x0208 113e1fee94f346387739e683b31815ab54dc0a30bd6Oliver Schuster 114e1fee94f346387739e683b31815ab54dc0a30bd6Oliver Schuster/* CIR Controller */ 115e1fee94f346387739e683b31815ab54dc0a30bd6Oliver Schuster#define CIR_DR(b) (b) 116e1fee94f346387739e683b31815ab54dc0a30bd6Oliver Schuster#define CIR_IER(b) (b + 1) 117e1fee94f346387739e683b31815ab54dc0a30bd6Oliver Schuster#define CIR_RCR(b) (b + 2) 118e1fee94f346387739e683b31815ab54dc0a30bd6Oliver Schuster#define CIR_TCR1(b) (b + 3) 119e1fee94f346387739e683b31815ab54dc0a30bd6Oliver Schuster#define CIR_TCR2(b) (b + 4) 120e1fee94f346387739e683b31815ab54dc0a30bd6Oliver Schuster#define CIR_TSR(b) (b + 5) 121e1fee94f346387739e683b31815ab54dc0a30bd6Oliver Schuster#define CIR_RSR(b) (b + 6) 122e1fee94f346387739e683b31815ab54dc0a30bd6Oliver Schuster#define CIR_BDLR(b) (b + 5) 123e1fee94f346387739e683b31815ab54dc0a30bd6Oliver Schuster#define CIR_BDHR(b) (b + 6) 124e1fee94f346387739e683b31815ab54dc0a30bd6Oliver Schuster#define CIR_IIR(b) (b + 7) 125e1fee94f346387739e683b31815ab54dc0a30bd6Oliver Schuster 126e1fee94f346387739e683b31815ab54dc0a30bd6Oliver Schuster/* Default Base address of Game port */ 127e1fee94f346387739e683b31815ab54dc0a30bd6Oliver Schuster#define GP_BASE_DEFAULT 0x0201 128e1fee94f346387739e683b31815ab54dc0a30bd6Oliver Schuster 129e1fee94f346387739e683b31815ab54dc0a30bd6Oliver Schuster/* wdt_status */ 130e1fee94f346387739e683b31815ab54dc0a30bd6Oliver Schuster#define WDTS_TIMER_RUN 0 131e1fee94f346387739e683b31815ab54dc0a30bd6Oliver Schuster#define WDTS_DEV_OPEN 1 132e1fee94f346387739e683b31815ab54dc0a30bd6Oliver Schuster#define WDTS_KEEPALIVE 2 133e1fee94f346387739e683b31815ab54dc0a30bd6Oliver Schuster#define WDTS_LOCKED 3 134e1fee94f346387739e683b31815ab54dc0a30bd6Oliver Schuster#define WDTS_USE_GP 4 135e1fee94f346387739e683b31815ab54dc0a30bd6Oliver Schuster#define WDTS_EXPECTED 5 136e1fee94f346387739e683b31815ab54dc0a30bd6Oliver Schuster 137dfb0b8eae1f78c7d0cf7c8abe6c84ff8cefde50eOndrej Zajicekstatic unsigned int base, gpact, ciract, max_units; 138e1fee94f346387739e683b31815ab54dc0a30bd6Oliver Schusterstatic unsigned long wdt_status; 139e1fee94f346387739e683b31815ab54dc0a30bd6Oliver Schusterstatic DEFINE_SPINLOCK(spinlock); 140e1fee94f346387739e683b31815ab54dc0a30bd6Oliver Schuster 141e1fee94f346387739e683b31815ab54dc0a30bd6Oliver Schusterstatic int nogameport = DEFAULT_NOGAMEPORT; 142e1fee94f346387739e683b31815ab54dc0a30bd6Oliver Schusterstatic int exclusive = DEFAULT_EXCLUSIVE; 143e1fee94f346387739e683b31815ab54dc0a30bd6Oliver Schusterstatic int timeout = DEFAULT_TIMEOUT; 144e1fee94f346387739e683b31815ab54dc0a30bd6Oliver Schusterstatic int testmode = DEFAULT_TESTMODE; 145e1fee94f346387739e683b31815ab54dc0a30bd6Oliver Schusterstatic int nowayout = DEFAULT_NOWAYOUT; 146e1fee94f346387739e683b31815ab54dc0a30bd6Oliver Schuster 147e1fee94f346387739e683b31815ab54dc0a30bd6Oliver Schustermodule_param(nogameport, int, 0); 148e1fee94f346387739e683b31815ab54dc0a30bd6Oliver SchusterMODULE_PARM_DESC(nogameport, "Forbid the activation of game port, default=" 149e1fee94f346387739e683b31815ab54dc0a30bd6Oliver Schuster __MODULE_STRING(DEFAULT_NOGAMEPORT)); 150e1fee94f346387739e683b31815ab54dc0a30bd6Oliver Schustermodule_param(exclusive, int, 0); 151e1fee94f346387739e683b31815ab54dc0a30bd6Oliver SchusterMODULE_PARM_DESC(exclusive, "Watchdog exclusive device open, default=" 152e1fee94f346387739e683b31815ab54dc0a30bd6Oliver Schuster __MODULE_STRING(DEFAULT_EXCLUSIVE)); 153e1fee94f346387739e683b31815ab54dc0a30bd6Oliver Schustermodule_param(timeout, int, 0); 154e1fee94f346387739e683b31815ab54dc0a30bd6Oliver SchusterMODULE_PARM_DESC(timeout, "Watchdog timeout in seconds, default=" 155e1fee94f346387739e683b31815ab54dc0a30bd6Oliver Schuster __MODULE_STRING(DEFAULT_TIMEOUT)); 156e1fee94f346387739e683b31815ab54dc0a30bd6Oliver Schustermodule_param(testmode, int, 0); 157e1fee94f346387739e683b31815ab54dc0a30bd6Oliver SchusterMODULE_PARM_DESC(testmode, "Watchdog test mode (1 = no reboot), default=" 158e1fee94f346387739e683b31815ab54dc0a30bd6Oliver Schuster __MODULE_STRING(DEFAULT_TESTMODE)); 159e1fee94f346387739e683b31815ab54dc0a30bd6Oliver Schustermodule_param(nowayout, int, 0); 160e1fee94f346387739e683b31815ab54dc0a30bd6Oliver SchusterMODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started, default=" 161e1fee94f346387739e683b31815ab54dc0a30bd6Oliver Schuster __MODULE_STRING(WATCHDOG_NOWAYOUT)); 162e1fee94f346387739e683b31815ab54dc0a30bd6Oliver Schuster 163e1fee94f346387739e683b31815ab54dc0a30bd6Oliver Schuster/* Superio Chip */ 164e1fee94f346387739e683b31815ab54dc0a30bd6Oliver Schuster 165e1fee94f346387739e683b31815ab54dc0a30bd6Oliver Schusterstatic inline void superio_enter(void) 166e1fee94f346387739e683b31815ab54dc0a30bd6Oliver Schuster{ 167e1fee94f346387739e683b31815ab54dc0a30bd6Oliver Schuster outb(0x87, REG); 168e1fee94f346387739e683b31815ab54dc0a30bd6Oliver Schuster outb(0x01, REG); 169e1fee94f346387739e683b31815ab54dc0a30bd6Oliver Schuster outb(0x55, REG); 170e1fee94f346387739e683b31815ab54dc0a30bd6Oliver Schuster outb(0x55, REG); 171e1fee94f346387739e683b31815ab54dc0a30bd6Oliver Schuster} 172e1fee94f346387739e683b31815ab54dc0a30bd6Oliver Schuster 173e1fee94f346387739e683b31815ab54dc0a30bd6Oliver Schusterstatic inline void superio_exit(void) 174e1fee94f346387739e683b31815ab54dc0a30bd6Oliver Schuster{ 175e1fee94f346387739e683b31815ab54dc0a30bd6Oliver Schuster outb(0x02, REG); 176e1fee94f346387739e683b31815ab54dc0a30bd6Oliver Schuster outb(0x02, VAL); 177e1fee94f346387739e683b31815ab54dc0a30bd6Oliver Schuster} 178e1fee94f346387739e683b31815ab54dc0a30bd6Oliver Schuster 179e1fee94f346387739e683b31815ab54dc0a30bd6Oliver Schusterstatic inline void superio_select(int ldn) 180e1fee94f346387739e683b31815ab54dc0a30bd6Oliver Schuster{ 181e1fee94f346387739e683b31815ab54dc0a30bd6Oliver Schuster outb(LDNREG, REG); 182e1fee94f346387739e683b31815ab54dc0a30bd6Oliver Schuster outb(ldn, VAL); 183e1fee94f346387739e683b31815ab54dc0a30bd6Oliver Schuster} 184e1fee94f346387739e683b31815ab54dc0a30bd6Oliver Schuster 185e1fee94f346387739e683b31815ab54dc0a30bd6Oliver Schusterstatic inline int superio_inb(int reg) 186e1fee94f346387739e683b31815ab54dc0a30bd6Oliver Schuster{ 187e1fee94f346387739e683b31815ab54dc0a30bd6Oliver Schuster outb(reg, REG); 188e1fee94f346387739e683b31815ab54dc0a30bd6Oliver Schuster return inb(VAL); 189e1fee94f346387739e683b31815ab54dc0a30bd6Oliver Schuster} 190e1fee94f346387739e683b31815ab54dc0a30bd6Oliver Schuster 191e1fee94f346387739e683b31815ab54dc0a30bd6Oliver Schusterstatic inline void superio_outb(int val, int reg) 192e1fee94f346387739e683b31815ab54dc0a30bd6Oliver Schuster{ 193143a2e54bf53216674eada16e8953f48b159e08aWim Van Sebroeck outb(reg, REG); 194143a2e54bf53216674eada16e8953f48b159e08aWim Van Sebroeck outb(val, VAL); 195e1fee94f346387739e683b31815ab54dc0a30bd6Oliver Schuster} 196e1fee94f346387739e683b31815ab54dc0a30bd6Oliver Schuster 197e1fee94f346387739e683b31815ab54dc0a30bd6Oliver Schusterstatic inline int superio_inw(int reg) 198e1fee94f346387739e683b31815ab54dc0a30bd6Oliver Schuster{ 199e1fee94f346387739e683b31815ab54dc0a30bd6Oliver Schuster int val; 200e1fee94f346387739e683b31815ab54dc0a30bd6Oliver Schuster outb(reg++, REG); 201e1fee94f346387739e683b31815ab54dc0a30bd6Oliver Schuster val = inb(VAL) << 8; 202e1fee94f346387739e683b31815ab54dc0a30bd6Oliver Schuster outb(reg, REG); 203e1fee94f346387739e683b31815ab54dc0a30bd6Oliver Schuster val |= inb(VAL); 204e1fee94f346387739e683b31815ab54dc0a30bd6Oliver Schuster return val; 205e1fee94f346387739e683b31815ab54dc0a30bd6Oliver Schuster} 206e1fee94f346387739e683b31815ab54dc0a30bd6Oliver Schuster 207e1fee94f346387739e683b31815ab54dc0a30bd6Oliver Schusterstatic inline void superio_outw(int val, int reg) 208e1fee94f346387739e683b31815ab54dc0a30bd6Oliver Schuster{ 209143a2e54bf53216674eada16e8953f48b159e08aWim Van Sebroeck outb(reg++, REG); 210143a2e54bf53216674eada16e8953f48b159e08aWim Van Sebroeck outb(val >> 8, VAL); 211143a2e54bf53216674eada16e8953f48b159e08aWim Van Sebroeck outb(reg, REG); 212143a2e54bf53216674eada16e8953f48b159e08aWim Van Sebroeck outb(val, VAL); 213e1fee94f346387739e683b31815ab54dc0a30bd6Oliver Schuster} 214e1fee94f346387739e683b31815ab54dc0a30bd6Oliver Schuster 215dfb0b8eae1f78c7d0cf7c8abe6c84ff8cefde50eOndrej Zajicek/* Internal function, should be called after superio_select(GPIO) */ 216dfb0b8eae1f78c7d0cf7c8abe6c84ff8cefde50eOndrej Zajicekstatic void wdt_update_timeout(void) 217dfb0b8eae1f78c7d0cf7c8abe6c84ff8cefde50eOndrej Zajicek{ 218dfb0b8eae1f78c7d0cf7c8abe6c84ff8cefde50eOndrej Zajicek unsigned char cfg = WDT_KRST | WDT_PWROK; 219dfb0b8eae1f78c7d0cf7c8abe6c84ff8cefde50eOndrej Zajicek int tm = timeout; 220dfb0b8eae1f78c7d0cf7c8abe6c84ff8cefde50eOndrej Zajicek 221dfb0b8eae1f78c7d0cf7c8abe6c84ff8cefde50eOndrej Zajicek if (testmode) 222dfb0b8eae1f78c7d0cf7c8abe6c84ff8cefde50eOndrej Zajicek cfg = 0; 223dfb0b8eae1f78c7d0cf7c8abe6c84ff8cefde50eOndrej Zajicek 224dfb0b8eae1f78c7d0cf7c8abe6c84ff8cefde50eOndrej Zajicek if (tm <= max_units) 225dfb0b8eae1f78c7d0cf7c8abe6c84ff8cefde50eOndrej Zajicek cfg |= WDT_TOV1; 226dfb0b8eae1f78c7d0cf7c8abe6c84ff8cefde50eOndrej Zajicek else 227dfb0b8eae1f78c7d0cf7c8abe6c84ff8cefde50eOndrej Zajicek tm /= 60; 228dfb0b8eae1f78c7d0cf7c8abe6c84ff8cefde50eOndrej Zajicek 229dfb0b8eae1f78c7d0cf7c8abe6c84ff8cefde50eOndrej Zajicek superio_outb(cfg, WDTCFG); 230dfb0b8eae1f78c7d0cf7c8abe6c84ff8cefde50eOndrej Zajicek superio_outb(tm, WDTVALLSB); 231dfb0b8eae1f78c7d0cf7c8abe6c84ff8cefde50eOndrej Zajicek if (max_units > 255) 232dfb0b8eae1f78c7d0cf7c8abe6c84ff8cefde50eOndrej Zajicek superio_outb(tm>>8, WDTVALMSB); 233dfb0b8eae1f78c7d0cf7c8abe6c84ff8cefde50eOndrej Zajicek} 234dfb0b8eae1f78c7d0cf7c8abe6c84ff8cefde50eOndrej Zajicek 235dfb0b8eae1f78c7d0cf7c8abe6c84ff8cefde50eOndrej Zajicekstatic int wdt_round_time(int t) 236dfb0b8eae1f78c7d0cf7c8abe6c84ff8cefde50eOndrej Zajicek{ 237dfb0b8eae1f78c7d0cf7c8abe6c84ff8cefde50eOndrej Zajicek t += 59; 238dfb0b8eae1f78c7d0cf7c8abe6c84ff8cefde50eOndrej Zajicek t -= t % 60; 239dfb0b8eae1f78c7d0cf7c8abe6c84ff8cefde50eOndrej Zajicek return t; 240dfb0b8eae1f78c7d0cf7c8abe6c84ff8cefde50eOndrej Zajicek} 241dfb0b8eae1f78c7d0cf7c8abe6c84ff8cefde50eOndrej Zajicek 242e1fee94f346387739e683b31815ab54dc0a30bd6Oliver Schuster/* watchdog timer handling */ 243e1fee94f346387739e683b31815ab54dc0a30bd6Oliver Schuster 244e1fee94f346387739e683b31815ab54dc0a30bd6Oliver Schusterstatic void wdt_keepalive(void) 245e1fee94f346387739e683b31815ab54dc0a30bd6Oliver Schuster{ 246e1fee94f346387739e683b31815ab54dc0a30bd6Oliver Schuster if (test_bit(WDTS_USE_GP, &wdt_status)) 247e1fee94f346387739e683b31815ab54dc0a30bd6Oliver Schuster inb(base); 248e1fee94f346387739e683b31815ab54dc0a30bd6Oliver Schuster else 249e1fee94f346387739e683b31815ab54dc0a30bd6Oliver Schuster /* The timer reloads with around 5 msec delay */ 250e1fee94f346387739e683b31815ab54dc0a30bd6Oliver Schuster outb(0x55, CIR_DR(base)); 251e1fee94f346387739e683b31815ab54dc0a30bd6Oliver Schuster set_bit(WDTS_KEEPALIVE, &wdt_status); 252e1fee94f346387739e683b31815ab54dc0a30bd6Oliver Schuster} 253e1fee94f346387739e683b31815ab54dc0a30bd6Oliver Schuster 254e1fee94f346387739e683b31815ab54dc0a30bd6Oliver Schusterstatic void wdt_start(void) 255e1fee94f346387739e683b31815ab54dc0a30bd6Oliver Schuster{ 256e1fee94f346387739e683b31815ab54dc0a30bd6Oliver Schuster unsigned long flags; 257e1fee94f346387739e683b31815ab54dc0a30bd6Oliver Schuster 258e1fee94f346387739e683b31815ab54dc0a30bd6Oliver Schuster spin_lock_irqsave(&spinlock, flags); 259e1fee94f346387739e683b31815ab54dc0a30bd6Oliver Schuster superio_enter(); 260e1fee94f346387739e683b31815ab54dc0a30bd6Oliver Schuster 261e1fee94f346387739e683b31815ab54dc0a30bd6Oliver Schuster superio_select(GPIO); 262e1fee94f346387739e683b31815ab54dc0a30bd6Oliver Schuster if (test_bit(WDTS_USE_GP, &wdt_status)) 263e1fee94f346387739e683b31815ab54dc0a30bd6Oliver Schuster superio_outb(WDT_GAMEPORT, WDTCTRL); 264e1fee94f346387739e683b31815ab54dc0a30bd6Oliver Schuster else 265e1fee94f346387739e683b31815ab54dc0a30bd6Oliver Schuster superio_outb(WDT_CIRINT, WDTCTRL); 266dfb0b8eae1f78c7d0cf7c8abe6c84ff8cefde50eOndrej Zajicek wdt_update_timeout(); 267e1fee94f346387739e683b31815ab54dc0a30bd6Oliver Schuster 268e1fee94f346387739e683b31815ab54dc0a30bd6Oliver Schuster superio_exit(); 269e1fee94f346387739e683b31815ab54dc0a30bd6Oliver Schuster spin_unlock_irqrestore(&spinlock, flags); 270e1fee94f346387739e683b31815ab54dc0a30bd6Oliver Schuster} 271e1fee94f346387739e683b31815ab54dc0a30bd6Oliver Schuster 272e1fee94f346387739e683b31815ab54dc0a30bd6Oliver Schusterstatic void wdt_stop(void) 273e1fee94f346387739e683b31815ab54dc0a30bd6Oliver Schuster{ 274e1fee94f346387739e683b31815ab54dc0a30bd6Oliver Schuster unsigned long flags; 275e1fee94f346387739e683b31815ab54dc0a30bd6Oliver Schuster 276e1fee94f346387739e683b31815ab54dc0a30bd6Oliver Schuster spin_lock_irqsave(&spinlock, flags); 277e1fee94f346387739e683b31815ab54dc0a30bd6Oliver Schuster superio_enter(); 278e1fee94f346387739e683b31815ab54dc0a30bd6Oliver Schuster 279e1fee94f346387739e683b31815ab54dc0a30bd6Oliver Schuster superio_select(GPIO); 280e1fee94f346387739e683b31815ab54dc0a30bd6Oliver Schuster superio_outb(0x00, WDTCTRL); 281e1fee94f346387739e683b31815ab54dc0a30bd6Oliver Schuster superio_outb(WDT_TOV1, WDTCFG); 282e1fee94f346387739e683b31815ab54dc0a30bd6Oliver Schuster superio_outb(0x00, WDTVALLSB); 283dfb0b8eae1f78c7d0cf7c8abe6c84ff8cefde50eOndrej Zajicek if (max_units > 255) 284dfb0b8eae1f78c7d0cf7c8abe6c84ff8cefde50eOndrej Zajicek superio_outb(0x00, WDTVALMSB); 285e1fee94f346387739e683b31815ab54dc0a30bd6Oliver Schuster 286e1fee94f346387739e683b31815ab54dc0a30bd6Oliver Schuster superio_exit(); 287e1fee94f346387739e683b31815ab54dc0a30bd6Oliver Schuster spin_unlock_irqrestore(&spinlock, flags); 288e1fee94f346387739e683b31815ab54dc0a30bd6Oliver Schuster} 289e1fee94f346387739e683b31815ab54dc0a30bd6Oliver Schuster 290e1fee94f346387739e683b31815ab54dc0a30bd6Oliver Schuster/** 291e1fee94f346387739e683b31815ab54dc0a30bd6Oliver Schuster * wdt_set_timeout - set a new timeout value with watchdog ioctl 292e1fee94f346387739e683b31815ab54dc0a30bd6Oliver Schuster * @t: timeout value in seconds 293e1fee94f346387739e683b31815ab54dc0a30bd6Oliver Schuster * 294dfb0b8eae1f78c7d0cf7c8abe6c84ff8cefde50eOndrej Zajicek * The hardware device has a 8 or 16 bit watchdog timer (depends on 295dfb0b8eae1f78c7d0cf7c8abe6c84ff8cefde50eOndrej Zajicek * chip version) that can be configured to count seconds or minutes. 296e1fee94f346387739e683b31815ab54dc0a30bd6Oliver Schuster * 297e1fee94f346387739e683b31815ab54dc0a30bd6Oliver Schuster * Used within WDIOC_SETTIMEOUT watchdog device ioctl. 298e1fee94f346387739e683b31815ab54dc0a30bd6Oliver Schuster */ 299e1fee94f346387739e683b31815ab54dc0a30bd6Oliver Schuster 300e1fee94f346387739e683b31815ab54dc0a30bd6Oliver Schusterstatic int wdt_set_timeout(int t) 301e1fee94f346387739e683b31815ab54dc0a30bd6Oliver Schuster{ 302e1fee94f346387739e683b31815ab54dc0a30bd6Oliver Schuster unsigned long flags; 303e1fee94f346387739e683b31815ab54dc0a30bd6Oliver Schuster 304dfb0b8eae1f78c7d0cf7c8abe6c84ff8cefde50eOndrej Zajicek if (t < 1 || t > max_units * 60) 305e1fee94f346387739e683b31815ab54dc0a30bd6Oliver Schuster return -EINVAL; 306e1fee94f346387739e683b31815ab54dc0a30bd6Oliver Schuster 307dfb0b8eae1f78c7d0cf7c8abe6c84ff8cefde50eOndrej Zajicek if (t > max_units) 308dfb0b8eae1f78c7d0cf7c8abe6c84ff8cefde50eOndrej Zajicek timeout = wdt_round_time(t); 309dfb0b8eae1f78c7d0cf7c8abe6c84ff8cefde50eOndrej Zajicek else 310dfb0b8eae1f78c7d0cf7c8abe6c84ff8cefde50eOndrej Zajicek timeout = t; 311e1fee94f346387739e683b31815ab54dc0a30bd6Oliver Schuster 312e1fee94f346387739e683b31815ab54dc0a30bd6Oliver Schuster spin_lock_irqsave(&spinlock, flags); 313e1fee94f346387739e683b31815ab54dc0a30bd6Oliver Schuster if (test_bit(WDTS_TIMER_RUN, &wdt_status)) { 314e1fee94f346387739e683b31815ab54dc0a30bd6Oliver Schuster superio_enter(); 315e1fee94f346387739e683b31815ab54dc0a30bd6Oliver Schuster superio_select(GPIO); 316dfb0b8eae1f78c7d0cf7c8abe6c84ff8cefde50eOndrej Zajicek wdt_update_timeout(); 317e1fee94f346387739e683b31815ab54dc0a30bd6Oliver Schuster superio_exit(); 318e1fee94f346387739e683b31815ab54dc0a30bd6Oliver Schuster } 319e1fee94f346387739e683b31815ab54dc0a30bd6Oliver Schuster spin_unlock_irqrestore(&spinlock, flags); 320e1fee94f346387739e683b31815ab54dc0a30bd6Oliver Schuster return 0; 321e1fee94f346387739e683b31815ab54dc0a30bd6Oliver Schuster} 322e1fee94f346387739e683b31815ab54dc0a30bd6Oliver Schuster 323e1fee94f346387739e683b31815ab54dc0a30bd6Oliver Schuster/** 324e1fee94f346387739e683b31815ab54dc0a30bd6Oliver Schuster * wdt_get_status - determines the status supported by watchdog ioctl 325e1fee94f346387739e683b31815ab54dc0a30bd6Oliver Schuster * @status: status returned to user space 326e1fee94f346387739e683b31815ab54dc0a30bd6Oliver Schuster * 327e1fee94f346387739e683b31815ab54dc0a30bd6Oliver Schuster * The status bit of the device does not allow to distinguish 328e1fee94f346387739e683b31815ab54dc0a30bd6Oliver Schuster * between a regular system reset and a watchdog forced reset. 329e1fee94f346387739e683b31815ab54dc0a30bd6Oliver Schuster * But, in test mode it is useful, so it is supported through 330e1fee94f346387739e683b31815ab54dc0a30bd6Oliver Schuster * WDIOC_GETSTATUS watchdog ioctl. Additionally the driver 331e1fee94f346387739e683b31815ab54dc0a30bd6Oliver Schuster * reports the keepalive signal and the acception of the magic. 332e1fee94f346387739e683b31815ab54dc0a30bd6Oliver Schuster * 333e1fee94f346387739e683b31815ab54dc0a30bd6Oliver Schuster * Used within WDIOC_GETSTATUS watchdog device ioctl. 334e1fee94f346387739e683b31815ab54dc0a30bd6Oliver Schuster */ 335e1fee94f346387739e683b31815ab54dc0a30bd6Oliver Schuster 336e1fee94f346387739e683b31815ab54dc0a30bd6Oliver Schusterstatic int wdt_get_status(int *status) 337e1fee94f346387739e683b31815ab54dc0a30bd6Oliver Schuster{ 338e1fee94f346387739e683b31815ab54dc0a30bd6Oliver Schuster unsigned long flags; 339e1fee94f346387739e683b31815ab54dc0a30bd6Oliver Schuster 340e1fee94f346387739e683b31815ab54dc0a30bd6Oliver Schuster *status = 0; 341e1fee94f346387739e683b31815ab54dc0a30bd6Oliver Schuster if (testmode) { 342e1fee94f346387739e683b31815ab54dc0a30bd6Oliver Schuster spin_lock_irqsave(&spinlock, flags); 343e1fee94f346387739e683b31815ab54dc0a30bd6Oliver Schuster superio_enter(); 344e1fee94f346387739e683b31815ab54dc0a30bd6Oliver Schuster superio_select(GPIO); 345e1fee94f346387739e683b31815ab54dc0a30bd6Oliver Schuster if (superio_inb(WDTCTRL) & WDT_ZERO) { 346e1fee94f346387739e683b31815ab54dc0a30bd6Oliver Schuster superio_outb(0x00, WDTCTRL); 347e1fee94f346387739e683b31815ab54dc0a30bd6Oliver Schuster clear_bit(WDTS_TIMER_RUN, &wdt_status); 348e1fee94f346387739e683b31815ab54dc0a30bd6Oliver Schuster *status |= WDIOF_CARDRESET; 349e1fee94f346387739e683b31815ab54dc0a30bd6Oliver Schuster } 350e1fee94f346387739e683b31815ab54dc0a30bd6Oliver Schuster 351e1fee94f346387739e683b31815ab54dc0a30bd6Oliver Schuster superio_exit(); 352e1fee94f346387739e683b31815ab54dc0a30bd6Oliver Schuster spin_unlock_irqrestore(&spinlock, flags); 353e1fee94f346387739e683b31815ab54dc0a30bd6Oliver Schuster } 354e1fee94f346387739e683b31815ab54dc0a30bd6Oliver Schuster if (test_and_clear_bit(WDTS_KEEPALIVE, &wdt_status)) 355e1fee94f346387739e683b31815ab54dc0a30bd6Oliver Schuster *status |= WDIOF_KEEPALIVEPING; 356e1fee94f346387739e683b31815ab54dc0a30bd6Oliver Schuster if (test_bit(WDTS_EXPECTED, &wdt_status)) 357e1fee94f346387739e683b31815ab54dc0a30bd6Oliver Schuster *status |= WDIOF_MAGICCLOSE; 358e1fee94f346387739e683b31815ab54dc0a30bd6Oliver Schuster return 0; 359e1fee94f346387739e683b31815ab54dc0a30bd6Oliver Schuster} 360e1fee94f346387739e683b31815ab54dc0a30bd6Oliver Schuster 361e1fee94f346387739e683b31815ab54dc0a30bd6Oliver Schuster/* /dev/watchdog handling */ 362e1fee94f346387739e683b31815ab54dc0a30bd6Oliver Schuster 363e1fee94f346387739e683b31815ab54dc0a30bd6Oliver Schuster/** 364e1fee94f346387739e683b31815ab54dc0a30bd6Oliver Schuster * wdt_open - watchdog file_operations .open 365e1fee94f346387739e683b31815ab54dc0a30bd6Oliver Schuster * @inode: inode of the device 366e1fee94f346387739e683b31815ab54dc0a30bd6Oliver Schuster * @file: file handle to the device 367e1fee94f346387739e683b31815ab54dc0a30bd6Oliver Schuster * 368e1fee94f346387739e683b31815ab54dc0a30bd6Oliver Schuster * The watchdog timer starts by opening the device. 369e1fee94f346387739e683b31815ab54dc0a30bd6Oliver Schuster * 370e1fee94f346387739e683b31815ab54dc0a30bd6Oliver Schuster * Used within the file operation of the watchdog device. 371e1fee94f346387739e683b31815ab54dc0a30bd6Oliver Schuster */ 372e1fee94f346387739e683b31815ab54dc0a30bd6Oliver Schuster 373e1fee94f346387739e683b31815ab54dc0a30bd6Oliver Schusterstatic int wdt_open(struct inode *inode, struct file *file) 374e1fee94f346387739e683b31815ab54dc0a30bd6Oliver Schuster{ 375e1fee94f346387739e683b31815ab54dc0a30bd6Oliver Schuster if (exclusive && test_and_set_bit(WDTS_DEV_OPEN, &wdt_status)) 376e1fee94f346387739e683b31815ab54dc0a30bd6Oliver Schuster return -EBUSY; 377e1fee94f346387739e683b31815ab54dc0a30bd6Oliver Schuster if (!test_and_set_bit(WDTS_TIMER_RUN, &wdt_status)) { 378e1fee94f346387739e683b31815ab54dc0a30bd6Oliver Schuster if (nowayout && !test_and_set_bit(WDTS_LOCKED, &wdt_status)) 379e1fee94f346387739e683b31815ab54dc0a30bd6Oliver Schuster __module_get(THIS_MODULE); 380e1fee94f346387739e683b31815ab54dc0a30bd6Oliver Schuster wdt_start(); 381e1fee94f346387739e683b31815ab54dc0a30bd6Oliver Schuster } 382e1fee94f346387739e683b31815ab54dc0a30bd6Oliver Schuster return nonseekable_open(inode, file); 383e1fee94f346387739e683b31815ab54dc0a30bd6Oliver Schuster} 384e1fee94f346387739e683b31815ab54dc0a30bd6Oliver Schuster 385e1fee94f346387739e683b31815ab54dc0a30bd6Oliver Schuster/** 386e1fee94f346387739e683b31815ab54dc0a30bd6Oliver Schuster * wdt_release - watchdog file_operations .release 387e1fee94f346387739e683b31815ab54dc0a30bd6Oliver Schuster * @inode: inode of the device 388e1fee94f346387739e683b31815ab54dc0a30bd6Oliver Schuster * @file: file handle to the device 389e1fee94f346387739e683b31815ab54dc0a30bd6Oliver Schuster * 390e1fee94f346387739e683b31815ab54dc0a30bd6Oliver Schuster * Closing the watchdog device either stops the watchdog timer 391e1fee94f346387739e683b31815ab54dc0a30bd6Oliver Schuster * or in the case, that nowayout is set or the magic character 392e1fee94f346387739e683b31815ab54dc0a30bd6Oliver Schuster * wasn't written, a critical warning about an running watchdog 393e1fee94f346387739e683b31815ab54dc0a30bd6Oliver Schuster * timer is given. 394e1fee94f346387739e683b31815ab54dc0a30bd6Oliver Schuster * 395e1fee94f346387739e683b31815ab54dc0a30bd6Oliver Schuster * Used within the file operation of the watchdog device. 396e1fee94f346387739e683b31815ab54dc0a30bd6Oliver Schuster */ 397e1fee94f346387739e683b31815ab54dc0a30bd6Oliver Schuster 398e1fee94f346387739e683b31815ab54dc0a30bd6Oliver Schusterstatic int wdt_release(struct inode *inode, struct file *file) 399e1fee94f346387739e683b31815ab54dc0a30bd6Oliver Schuster{ 400e1fee94f346387739e683b31815ab54dc0a30bd6Oliver Schuster if (test_bit(WDTS_TIMER_RUN, &wdt_status)) { 401e1fee94f346387739e683b31815ab54dc0a30bd6Oliver Schuster if (test_and_clear_bit(WDTS_EXPECTED, &wdt_status)) { 402e1fee94f346387739e683b31815ab54dc0a30bd6Oliver Schuster wdt_stop(); 403e1fee94f346387739e683b31815ab54dc0a30bd6Oliver Schuster clear_bit(WDTS_TIMER_RUN, &wdt_status); 404e1fee94f346387739e683b31815ab54dc0a30bd6Oliver Schuster } else { 405e1fee94f346387739e683b31815ab54dc0a30bd6Oliver Schuster wdt_keepalive(); 406e1fee94f346387739e683b31815ab54dc0a30bd6Oliver Schuster printk(KERN_CRIT PFX 407e1fee94f346387739e683b31815ab54dc0a30bd6Oliver Schuster "unexpected close, not stopping watchdog!\n"); 408e1fee94f346387739e683b31815ab54dc0a30bd6Oliver Schuster } 409e1fee94f346387739e683b31815ab54dc0a30bd6Oliver Schuster } 410e1fee94f346387739e683b31815ab54dc0a30bd6Oliver Schuster clear_bit(WDTS_DEV_OPEN, &wdt_status); 411e1fee94f346387739e683b31815ab54dc0a30bd6Oliver Schuster return 0; 412e1fee94f346387739e683b31815ab54dc0a30bd6Oliver Schuster} 413e1fee94f346387739e683b31815ab54dc0a30bd6Oliver Schuster 414e1fee94f346387739e683b31815ab54dc0a30bd6Oliver Schuster/** 415e1fee94f346387739e683b31815ab54dc0a30bd6Oliver Schuster * wdt_write - watchdog file_operations .write 416e1fee94f346387739e683b31815ab54dc0a30bd6Oliver Schuster * @file: file handle to the watchdog 417e1fee94f346387739e683b31815ab54dc0a30bd6Oliver Schuster * @buf: buffer to write 418e1fee94f346387739e683b31815ab54dc0a30bd6Oliver Schuster * @count: count of bytes 419e1fee94f346387739e683b31815ab54dc0a30bd6Oliver Schuster * @ppos: pointer to the position to write. No seeks allowed 420e1fee94f346387739e683b31815ab54dc0a30bd6Oliver Schuster * 421e1fee94f346387739e683b31815ab54dc0a30bd6Oliver Schuster * A write to a watchdog device is defined as a keepalive signal. Any 422e1fee94f346387739e683b31815ab54dc0a30bd6Oliver Schuster * write of data will do, as we don't define content meaning. 423e1fee94f346387739e683b31815ab54dc0a30bd6Oliver Schuster * 424e1fee94f346387739e683b31815ab54dc0a30bd6Oliver Schuster * Used within the file operation of the watchdog device. 425e1fee94f346387739e683b31815ab54dc0a30bd6Oliver Schuster */ 426e1fee94f346387739e683b31815ab54dc0a30bd6Oliver Schuster 427e1fee94f346387739e683b31815ab54dc0a30bd6Oliver Schusterstatic ssize_t wdt_write(struct file *file, const char __user *buf, 428e1fee94f346387739e683b31815ab54dc0a30bd6Oliver Schuster size_t count, loff_t *ppos) 429e1fee94f346387739e683b31815ab54dc0a30bd6Oliver Schuster{ 430e1fee94f346387739e683b31815ab54dc0a30bd6Oliver Schuster if (count) { 431e1fee94f346387739e683b31815ab54dc0a30bd6Oliver Schuster clear_bit(WDTS_EXPECTED, &wdt_status); 432e1fee94f346387739e683b31815ab54dc0a30bd6Oliver Schuster wdt_keepalive(); 433e1fee94f346387739e683b31815ab54dc0a30bd6Oliver Schuster } 434e1fee94f346387739e683b31815ab54dc0a30bd6Oliver Schuster if (!nowayout) { 435e1fee94f346387739e683b31815ab54dc0a30bd6Oliver Schuster size_t ofs; 436e1fee94f346387739e683b31815ab54dc0a30bd6Oliver Schuster 437e1fee94f346387739e683b31815ab54dc0a30bd6Oliver Schuster /* note: just in case someone wrote the magic character long ago */ 438e1fee94f346387739e683b31815ab54dc0a30bd6Oliver Schuster for (ofs = 0; ofs != count; ofs++) { 439e1fee94f346387739e683b31815ab54dc0a30bd6Oliver Schuster char c; 440e1fee94f346387739e683b31815ab54dc0a30bd6Oliver Schuster if (get_user(c, buf + ofs)) 441e1fee94f346387739e683b31815ab54dc0a30bd6Oliver Schuster return -EFAULT; 442e1fee94f346387739e683b31815ab54dc0a30bd6Oliver Schuster if (c == WD_MAGIC) 443e1fee94f346387739e683b31815ab54dc0a30bd6Oliver Schuster set_bit(WDTS_EXPECTED, &wdt_status); 444e1fee94f346387739e683b31815ab54dc0a30bd6Oliver Schuster } 445e1fee94f346387739e683b31815ab54dc0a30bd6Oliver Schuster } 446e1fee94f346387739e683b31815ab54dc0a30bd6Oliver Schuster return count; 447e1fee94f346387739e683b31815ab54dc0a30bd6Oliver Schuster} 448e1fee94f346387739e683b31815ab54dc0a30bd6Oliver Schuster 44942747d712de56cf2087b702d2ad90af114c53138Wim Van Sebroeckstatic const struct watchdog_info ident = { 450e1fee94f346387739e683b31815ab54dc0a30bd6Oliver Schuster .options = WDIOF_SETTIMEOUT | WDIOF_MAGICCLOSE | WDIOF_KEEPALIVEPING, 451e1fee94f346387739e683b31815ab54dc0a30bd6Oliver Schuster .firmware_version = 1, 452e1fee94f346387739e683b31815ab54dc0a30bd6Oliver Schuster .identity = WATCHDOG_NAME, 453e1fee94f346387739e683b31815ab54dc0a30bd6Oliver Schuster}; 454e1fee94f346387739e683b31815ab54dc0a30bd6Oliver Schuster 455e1fee94f346387739e683b31815ab54dc0a30bd6Oliver Schuster/** 456e1fee94f346387739e683b31815ab54dc0a30bd6Oliver Schuster * wdt_ioctl - watchdog file_operations .unlocked_ioctl 457e1fee94f346387739e683b31815ab54dc0a30bd6Oliver Schuster * @file: file handle to the device 458e1fee94f346387739e683b31815ab54dc0a30bd6Oliver Schuster * @cmd: watchdog command 459e1fee94f346387739e683b31815ab54dc0a30bd6Oliver Schuster * @arg: argument pointer 460e1fee94f346387739e683b31815ab54dc0a30bd6Oliver Schuster * 461e1fee94f346387739e683b31815ab54dc0a30bd6Oliver Schuster * The watchdog API defines a common set of functions for all watchdogs 462e1fee94f346387739e683b31815ab54dc0a30bd6Oliver Schuster * according to their available features. 463e1fee94f346387739e683b31815ab54dc0a30bd6Oliver Schuster * 464e1fee94f346387739e683b31815ab54dc0a30bd6Oliver Schuster * Used within the file operation of the watchdog device. 465e1fee94f346387739e683b31815ab54dc0a30bd6Oliver Schuster */ 466e1fee94f346387739e683b31815ab54dc0a30bd6Oliver Schuster 467e1fee94f346387739e683b31815ab54dc0a30bd6Oliver Schusterstatic long wdt_ioctl(struct file *file, unsigned int cmd, unsigned long arg) 468e1fee94f346387739e683b31815ab54dc0a30bd6Oliver Schuster{ 469e1fee94f346387739e683b31815ab54dc0a30bd6Oliver Schuster int rc = 0, status, new_options, new_timeout; 470e1fee94f346387739e683b31815ab54dc0a30bd6Oliver Schuster union { 471e1fee94f346387739e683b31815ab54dc0a30bd6Oliver Schuster struct watchdog_info __user *ident; 472e1fee94f346387739e683b31815ab54dc0a30bd6Oliver Schuster int __user *i; 473e1fee94f346387739e683b31815ab54dc0a30bd6Oliver Schuster } uarg; 474e1fee94f346387739e683b31815ab54dc0a30bd6Oliver Schuster 475e1fee94f346387739e683b31815ab54dc0a30bd6Oliver Schuster uarg.i = (int __user *)arg; 476e1fee94f346387739e683b31815ab54dc0a30bd6Oliver Schuster 477e1fee94f346387739e683b31815ab54dc0a30bd6Oliver Schuster switch (cmd) { 478e1fee94f346387739e683b31815ab54dc0a30bd6Oliver Schuster case WDIOC_GETSUPPORT: 479e1fee94f346387739e683b31815ab54dc0a30bd6Oliver Schuster return copy_to_user(uarg.ident, 480e1fee94f346387739e683b31815ab54dc0a30bd6Oliver Schuster &ident, sizeof(ident)) ? -EFAULT : 0; 481e1fee94f346387739e683b31815ab54dc0a30bd6Oliver Schuster 482e1fee94f346387739e683b31815ab54dc0a30bd6Oliver Schuster case WDIOC_GETSTATUS: 483e1fee94f346387739e683b31815ab54dc0a30bd6Oliver Schuster wdt_get_status(&status); 484e1fee94f346387739e683b31815ab54dc0a30bd6Oliver Schuster return put_user(status, uarg.i); 485e1fee94f346387739e683b31815ab54dc0a30bd6Oliver Schuster 486e1fee94f346387739e683b31815ab54dc0a30bd6Oliver Schuster case WDIOC_GETBOOTSTATUS: 487e1fee94f346387739e683b31815ab54dc0a30bd6Oliver Schuster return put_user(0, uarg.i); 488e1fee94f346387739e683b31815ab54dc0a30bd6Oliver Schuster 489e1fee94f346387739e683b31815ab54dc0a30bd6Oliver Schuster case WDIOC_KEEPALIVE: 490e1fee94f346387739e683b31815ab54dc0a30bd6Oliver Schuster wdt_keepalive(); 491e1fee94f346387739e683b31815ab54dc0a30bd6Oliver Schuster return 0; 492e1fee94f346387739e683b31815ab54dc0a30bd6Oliver Schuster 493e1fee94f346387739e683b31815ab54dc0a30bd6Oliver Schuster case WDIOC_SETOPTIONS: 494e1fee94f346387739e683b31815ab54dc0a30bd6Oliver Schuster if (get_user(new_options, uarg.i)) 495e1fee94f346387739e683b31815ab54dc0a30bd6Oliver Schuster return -EFAULT; 496e1fee94f346387739e683b31815ab54dc0a30bd6Oliver Schuster 497e1fee94f346387739e683b31815ab54dc0a30bd6Oliver Schuster switch (new_options) { 498e1fee94f346387739e683b31815ab54dc0a30bd6Oliver Schuster case WDIOS_DISABLECARD: 499e1fee94f346387739e683b31815ab54dc0a30bd6Oliver Schuster if (test_bit(WDTS_TIMER_RUN, &wdt_status)) 500e1fee94f346387739e683b31815ab54dc0a30bd6Oliver Schuster wdt_stop(); 501e1fee94f346387739e683b31815ab54dc0a30bd6Oliver Schuster clear_bit(WDTS_TIMER_RUN, &wdt_status); 502e1fee94f346387739e683b31815ab54dc0a30bd6Oliver Schuster return 0; 503e1fee94f346387739e683b31815ab54dc0a30bd6Oliver Schuster 504e1fee94f346387739e683b31815ab54dc0a30bd6Oliver Schuster case WDIOS_ENABLECARD: 505e1fee94f346387739e683b31815ab54dc0a30bd6Oliver Schuster if (!test_and_set_bit(WDTS_TIMER_RUN, &wdt_status)) 506e1fee94f346387739e683b31815ab54dc0a30bd6Oliver Schuster wdt_start(); 507e1fee94f346387739e683b31815ab54dc0a30bd6Oliver Schuster return 0; 508e1fee94f346387739e683b31815ab54dc0a30bd6Oliver Schuster 509e1fee94f346387739e683b31815ab54dc0a30bd6Oliver Schuster default: 510e1fee94f346387739e683b31815ab54dc0a30bd6Oliver Schuster return -EFAULT; 511e1fee94f346387739e683b31815ab54dc0a30bd6Oliver Schuster } 512e1fee94f346387739e683b31815ab54dc0a30bd6Oliver Schuster 513e1fee94f346387739e683b31815ab54dc0a30bd6Oliver Schuster case WDIOC_SETTIMEOUT: 514e1fee94f346387739e683b31815ab54dc0a30bd6Oliver Schuster if (get_user(new_timeout, uarg.i)) 515e1fee94f346387739e683b31815ab54dc0a30bd6Oliver Schuster return -EFAULT; 516e1fee94f346387739e683b31815ab54dc0a30bd6Oliver Schuster rc = wdt_set_timeout(new_timeout); 517e1fee94f346387739e683b31815ab54dc0a30bd6Oliver Schuster case WDIOC_GETTIMEOUT: 518e1fee94f346387739e683b31815ab54dc0a30bd6Oliver Schuster if (put_user(timeout, uarg.i)) 519e1fee94f346387739e683b31815ab54dc0a30bd6Oliver Schuster return -EFAULT; 520e1fee94f346387739e683b31815ab54dc0a30bd6Oliver Schuster return rc; 521e1fee94f346387739e683b31815ab54dc0a30bd6Oliver Schuster 522e1fee94f346387739e683b31815ab54dc0a30bd6Oliver Schuster default: 523e1fee94f346387739e683b31815ab54dc0a30bd6Oliver Schuster return -ENOTTY; 524e1fee94f346387739e683b31815ab54dc0a30bd6Oliver Schuster } 525e1fee94f346387739e683b31815ab54dc0a30bd6Oliver Schuster} 526e1fee94f346387739e683b31815ab54dc0a30bd6Oliver Schuster 527e1fee94f346387739e683b31815ab54dc0a30bd6Oliver Schusterstatic int wdt_notify_sys(struct notifier_block *this, unsigned long code, 528e1fee94f346387739e683b31815ab54dc0a30bd6Oliver Schuster void *unused) 529e1fee94f346387739e683b31815ab54dc0a30bd6Oliver Schuster{ 530e1fee94f346387739e683b31815ab54dc0a30bd6Oliver Schuster if (code == SYS_DOWN || code == SYS_HALT) 531e1fee94f346387739e683b31815ab54dc0a30bd6Oliver Schuster wdt_stop(); 532e1fee94f346387739e683b31815ab54dc0a30bd6Oliver Schuster return NOTIFY_DONE; 533e1fee94f346387739e683b31815ab54dc0a30bd6Oliver Schuster} 534e1fee94f346387739e683b31815ab54dc0a30bd6Oliver Schuster 535e1fee94f346387739e683b31815ab54dc0a30bd6Oliver Schusterstatic const struct file_operations wdt_fops = { 536e1fee94f346387739e683b31815ab54dc0a30bd6Oliver Schuster .owner = THIS_MODULE, 537e1fee94f346387739e683b31815ab54dc0a30bd6Oliver Schuster .llseek = no_llseek, 538e1fee94f346387739e683b31815ab54dc0a30bd6Oliver Schuster .write = wdt_write, 539e1fee94f346387739e683b31815ab54dc0a30bd6Oliver Schuster .unlocked_ioctl = wdt_ioctl, 540e1fee94f346387739e683b31815ab54dc0a30bd6Oliver Schuster .open = wdt_open, 541e1fee94f346387739e683b31815ab54dc0a30bd6Oliver Schuster .release = wdt_release, 542e1fee94f346387739e683b31815ab54dc0a30bd6Oliver Schuster}; 543e1fee94f346387739e683b31815ab54dc0a30bd6Oliver Schuster 544e1fee94f346387739e683b31815ab54dc0a30bd6Oliver Schusterstatic struct miscdevice wdt_miscdev = { 545e1fee94f346387739e683b31815ab54dc0a30bd6Oliver Schuster .minor = WATCHDOG_MINOR, 546e1fee94f346387739e683b31815ab54dc0a30bd6Oliver Schuster .name = "watchdog", 547e1fee94f346387739e683b31815ab54dc0a30bd6Oliver Schuster .fops = &wdt_fops, 548e1fee94f346387739e683b31815ab54dc0a30bd6Oliver Schuster}; 549e1fee94f346387739e683b31815ab54dc0a30bd6Oliver Schuster 550e1fee94f346387739e683b31815ab54dc0a30bd6Oliver Schusterstatic struct notifier_block wdt_notifier = { 551e1fee94f346387739e683b31815ab54dc0a30bd6Oliver Schuster .notifier_call = wdt_notify_sys, 552e1fee94f346387739e683b31815ab54dc0a30bd6Oliver Schuster}; 553e1fee94f346387739e683b31815ab54dc0a30bd6Oliver Schuster 554e1fee94f346387739e683b31815ab54dc0a30bd6Oliver Schusterstatic int __init it87_wdt_init(void) 555e1fee94f346387739e683b31815ab54dc0a30bd6Oliver Schuster{ 556e1fee94f346387739e683b31815ab54dc0a30bd6Oliver Schuster int rc = 0; 557ee3e96583e42dcb4bd406ce4e5f824bd5bb80013Ondrej Zajicek int try_gameport = !nogameport; 558e1fee94f346387739e683b31815ab54dc0a30bd6Oliver Schuster u16 chip_type; 559e1fee94f346387739e683b31815ab54dc0a30bd6Oliver Schuster u8 chip_rev; 560e1fee94f346387739e683b31815ab54dc0a30bd6Oliver Schuster unsigned long flags; 561e1fee94f346387739e683b31815ab54dc0a30bd6Oliver Schuster 562dfb0b8eae1f78c7d0cf7c8abe6c84ff8cefde50eOndrej Zajicek wdt_status = 0; 563dfb0b8eae1f78c7d0cf7c8abe6c84ff8cefde50eOndrej Zajicek 564e1fee94f346387739e683b31815ab54dc0a30bd6Oliver Schuster spin_lock_irqsave(&spinlock, flags); 565e1fee94f346387739e683b31815ab54dc0a30bd6Oliver Schuster superio_enter(); 566e1fee94f346387739e683b31815ab54dc0a30bd6Oliver Schuster chip_type = superio_inw(CHIPID); 567e1fee94f346387739e683b31815ab54dc0a30bd6Oliver Schuster chip_rev = superio_inb(CHIPREV) & 0x0f; 568e1fee94f346387739e683b31815ab54dc0a30bd6Oliver Schuster superio_exit(); 569e1fee94f346387739e683b31815ab54dc0a30bd6Oliver Schuster spin_unlock_irqrestore(&spinlock, flags); 570e1fee94f346387739e683b31815ab54dc0a30bd6Oliver Schuster 571e1fee94f346387739e683b31815ab54dc0a30bd6Oliver Schuster switch (chip_type) { 572dfb0b8eae1f78c7d0cf7c8abe6c84ff8cefde50eOndrej Zajicek case IT8702_ID: 573dfb0b8eae1f78c7d0cf7c8abe6c84ff8cefde50eOndrej Zajicek max_units = 255; 574dfb0b8eae1f78c7d0cf7c8abe6c84ff8cefde50eOndrej Zajicek break; 575dfb0b8eae1f78c7d0cf7c8abe6c84ff8cefde50eOndrej Zajicek case IT8712_ID: 576dfb0b8eae1f78c7d0cf7c8abe6c84ff8cefde50eOndrej Zajicek max_units = (chip_rev < 8) ? 255 : 65535; 577dfb0b8eae1f78c7d0cf7c8abe6c84ff8cefde50eOndrej Zajicek break; 578e1fee94f346387739e683b31815ab54dc0a30bd6Oliver Schuster case IT8716_ID: 579e1fee94f346387739e683b31815ab54dc0a30bd6Oliver Schuster case IT8726_ID: 580dfb0b8eae1f78c7d0cf7c8abe6c84ff8cefde50eOndrej Zajicek max_units = 65535; 581e1fee94f346387739e683b31815ab54dc0a30bd6Oliver Schuster break; 582ee3e96583e42dcb4bd406ce4e5f824bd5bb80013Ondrej Zajicek case IT8718_ID: 583ee3e96583e42dcb4bd406ce4e5f824bd5bb80013Ondrej Zajicek case IT8720_ID: 584dfb0b8eae1f78c7d0cf7c8abe6c84ff8cefde50eOndrej Zajicek max_units = 65535; 585ee3e96583e42dcb4bd406ce4e5f824bd5bb80013Ondrej Zajicek try_gameport = 0; 586ee3e96583e42dcb4bd406ce4e5f824bd5bb80013Ondrej Zajicek break; 587e1fee94f346387739e683b31815ab54dc0a30bd6Oliver Schuster case IT8705_ID: 588e1fee94f346387739e683b31815ab54dc0a30bd6Oliver Schuster printk(KERN_ERR PFX 589e1fee94f346387739e683b31815ab54dc0a30bd6Oliver Schuster "Unsupported Chip found, Chip %04x Revision %02x\n", 590e1fee94f346387739e683b31815ab54dc0a30bd6Oliver Schuster chip_type, chip_rev); 591e1fee94f346387739e683b31815ab54dc0a30bd6Oliver Schuster return -ENODEV; 592e1fee94f346387739e683b31815ab54dc0a30bd6Oliver Schuster case NO_DEV_ID: 593e1fee94f346387739e683b31815ab54dc0a30bd6Oliver Schuster printk(KERN_ERR PFX "no device\n"); 594e1fee94f346387739e683b31815ab54dc0a30bd6Oliver Schuster return -ENODEV; 595e1fee94f346387739e683b31815ab54dc0a30bd6Oliver Schuster default: 596e1fee94f346387739e683b31815ab54dc0a30bd6Oliver Schuster printk(KERN_ERR PFX 597e1fee94f346387739e683b31815ab54dc0a30bd6Oliver Schuster "Unknown Chip found, Chip %04x Revision %04x\n", 598e1fee94f346387739e683b31815ab54dc0a30bd6Oliver Schuster chip_type, chip_rev); 599e1fee94f346387739e683b31815ab54dc0a30bd6Oliver Schuster return -ENODEV; 600e1fee94f346387739e683b31815ab54dc0a30bd6Oliver Schuster } 601e1fee94f346387739e683b31815ab54dc0a30bd6Oliver Schuster 602e1fee94f346387739e683b31815ab54dc0a30bd6Oliver Schuster spin_lock_irqsave(&spinlock, flags); 603e1fee94f346387739e683b31815ab54dc0a30bd6Oliver Schuster superio_enter(); 604e1fee94f346387739e683b31815ab54dc0a30bd6Oliver Schuster 605e1fee94f346387739e683b31815ab54dc0a30bd6Oliver Schuster superio_select(GPIO); 606e1fee94f346387739e683b31815ab54dc0a30bd6Oliver Schuster superio_outb(WDT_TOV1, WDTCFG); 607e1fee94f346387739e683b31815ab54dc0a30bd6Oliver Schuster superio_outb(0x00, WDTCTRL); 608e1fee94f346387739e683b31815ab54dc0a30bd6Oliver Schuster 609e1fee94f346387739e683b31815ab54dc0a30bd6Oliver Schuster /* First try to get Gameport support */ 610ee3e96583e42dcb4bd406ce4e5f824bd5bb80013Ondrej Zajicek if (try_gameport) { 611e1fee94f346387739e683b31815ab54dc0a30bd6Oliver Schuster superio_select(GAMEPORT); 612e1fee94f346387739e683b31815ab54dc0a30bd6Oliver Schuster base = superio_inw(BASEREG); 613e1fee94f346387739e683b31815ab54dc0a30bd6Oliver Schuster if (!base) { 614e1fee94f346387739e683b31815ab54dc0a30bd6Oliver Schuster base = GP_BASE_DEFAULT; 615e1fee94f346387739e683b31815ab54dc0a30bd6Oliver Schuster superio_outw(base, BASEREG); 616e1fee94f346387739e683b31815ab54dc0a30bd6Oliver Schuster } 617e1fee94f346387739e683b31815ab54dc0a30bd6Oliver Schuster gpact = superio_inb(ACTREG); 618e1fee94f346387739e683b31815ab54dc0a30bd6Oliver Schuster superio_outb(0x01, ACTREG); 619e1fee94f346387739e683b31815ab54dc0a30bd6Oliver Schuster superio_exit(); 620e1fee94f346387739e683b31815ab54dc0a30bd6Oliver Schuster spin_unlock_irqrestore(&spinlock, flags); 621e1fee94f346387739e683b31815ab54dc0a30bd6Oliver Schuster if (request_region(base, 1, WATCHDOG_NAME)) 622e1fee94f346387739e683b31815ab54dc0a30bd6Oliver Schuster set_bit(WDTS_USE_GP, &wdt_status); 623e1fee94f346387739e683b31815ab54dc0a30bd6Oliver Schuster else 624e1fee94f346387739e683b31815ab54dc0a30bd6Oliver Schuster rc = -EIO; 625e1fee94f346387739e683b31815ab54dc0a30bd6Oliver Schuster } else { 626e1fee94f346387739e683b31815ab54dc0a30bd6Oliver Schuster superio_exit(); 627e1fee94f346387739e683b31815ab54dc0a30bd6Oliver Schuster spin_unlock_irqrestore(&spinlock, flags); 628e1fee94f346387739e683b31815ab54dc0a30bd6Oliver Schuster } 629e1fee94f346387739e683b31815ab54dc0a30bd6Oliver Schuster 630e1fee94f346387739e683b31815ab54dc0a30bd6Oliver Schuster /* If we haven't Gameport support, try to get CIR support */ 631e1fee94f346387739e683b31815ab54dc0a30bd6Oliver Schuster if (!test_bit(WDTS_USE_GP, &wdt_status)) { 632e1fee94f346387739e683b31815ab54dc0a30bd6Oliver Schuster if (!request_region(CIR_BASE, 8, WATCHDOG_NAME)) { 633e1fee94f346387739e683b31815ab54dc0a30bd6Oliver Schuster if (rc == -EIO) 634e1fee94f346387739e683b31815ab54dc0a30bd6Oliver Schuster printk(KERN_ERR PFX 635e1fee94f346387739e683b31815ab54dc0a30bd6Oliver Schuster "I/O Address 0x%04x and 0x%04x" 636e1fee94f346387739e683b31815ab54dc0a30bd6Oliver Schuster " already in use\n", base, CIR_BASE); 637e1fee94f346387739e683b31815ab54dc0a30bd6Oliver Schuster else 638e1fee94f346387739e683b31815ab54dc0a30bd6Oliver Schuster printk(KERN_ERR PFX 639e1fee94f346387739e683b31815ab54dc0a30bd6Oliver Schuster "I/O Address 0x%04x already in use\n", 640e1fee94f346387739e683b31815ab54dc0a30bd6Oliver Schuster CIR_BASE); 641e1fee94f346387739e683b31815ab54dc0a30bd6Oliver Schuster rc = -EIO; 642e1fee94f346387739e683b31815ab54dc0a30bd6Oliver Schuster goto err_out; 643e1fee94f346387739e683b31815ab54dc0a30bd6Oliver Schuster } 644e1fee94f346387739e683b31815ab54dc0a30bd6Oliver Schuster base = CIR_BASE; 645e1fee94f346387739e683b31815ab54dc0a30bd6Oliver Schuster spin_lock_irqsave(&spinlock, flags); 646e1fee94f346387739e683b31815ab54dc0a30bd6Oliver Schuster superio_enter(); 647e1fee94f346387739e683b31815ab54dc0a30bd6Oliver Schuster 648e1fee94f346387739e683b31815ab54dc0a30bd6Oliver Schuster superio_select(CIR); 649e1fee94f346387739e683b31815ab54dc0a30bd6Oliver Schuster superio_outw(base, BASEREG); 650e1fee94f346387739e683b31815ab54dc0a30bd6Oliver Schuster superio_outb(0x00, CIR_ILS); 651e1fee94f346387739e683b31815ab54dc0a30bd6Oliver Schuster ciract = superio_inb(ACTREG); 652e1fee94f346387739e683b31815ab54dc0a30bd6Oliver Schuster superio_outb(0x01, ACTREG); 653e1fee94f346387739e683b31815ab54dc0a30bd6Oliver Schuster if (rc == -EIO) { 654e1fee94f346387739e683b31815ab54dc0a30bd6Oliver Schuster superio_select(GAMEPORT); 655e1fee94f346387739e683b31815ab54dc0a30bd6Oliver Schuster superio_outb(gpact, ACTREG); 656e1fee94f346387739e683b31815ab54dc0a30bd6Oliver Schuster } 657e1fee94f346387739e683b31815ab54dc0a30bd6Oliver Schuster 658e1fee94f346387739e683b31815ab54dc0a30bd6Oliver Schuster superio_exit(); 659e1fee94f346387739e683b31815ab54dc0a30bd6Oliver Schuster spin_unlock_irqrestore(&spinlock, flags); 660e1fee94f346387739e683b31815ab54dc0a30bd6Oliver Schuster } 661e1fee94f346387739e683b31815ab54dc0a30bd6Oliver Schuster 662dfb0b8eae1f78c7d0cf7c8abe6c84ff8cefde50eOndrej Zajicek if (timeout < 1 || timeout > max_units * 60) { 663e1fee94f346387739e683b31815ab54dc0a30bd6Oliver Schuster timeout = DEFAULT_TIMEOUT; 664e1fee94f346387739e683b31815ab54dc0a30bd6Oliver Schuster printk(KERN_WARNING PFX 665e1fee94f346387739e683b31815ab54dc0a30bd6Oliver Schuster "Timeout value out of range, use default %d sec\n", 666e1fee94f346387739e683b31815ab54dc0a30bd6Oliver Schuster DEFAULT_TIMEOUT); 667e1fee94f346387739e683b31815ab54dc0a30bd6Oliver Schuster } 668e1fee94f346387739e683b31815ab54dc0a30bd6Oliver Schuster 669dfb0b8eae1f78c7d0cf7c8abe6c84ff8cefde50eOndrej Zajicek if (timeout > max_units) 670dfb0b8eae1f78c7d0cf7c8abe6c84ff8cefde50eOndrej Zajicek timeout = wdt_round_time(timeout); 671dfb0b8eae1f78c7d0cf7c8abe6c84ff8cefde50eOndrej Zajicek 672e1fee94f346387739e683b31815ab54dc0a30bd6Oliver Schuster rc = register_reboot_notifier(&wdt_notifier); 673e1fee94f346387739e683b31815ab54dc0a30bd6Oliver Schuster if (rc) { 674e1fee94f346387739e683b31815ab54dc0a30bd6Oliver Schuster printk(KERN_ERR PFX 675e1fee94f346387739e683b31815ab54dc0a30bd6Oliver Schuster "Cannot register reboot notifier (err=%d)\n", rc); 676e1fee94f346387739e683b31815ab54dc0a30bd6Oliver Schuster goto err_out_region; 677e1fee94f346387739e683b31815ab54dc0a30bd6Oliver Schuster } 678e1fee94f346387739e683b31815ab54dc0a30bd6Oliver Schuster 679e1fee94f346387739e683b31815ab54dc0a30bd6Oliver Schuster rc = misc_register(&wdt_miscdev); 680e1fee94f346387739e683b31815ab54dc0a30bd6Oliver Schuster if (rc) { 681e1fee94f346387739e683b31815ab54dc0a30bd6Oliver Schuster printk(KERN_ERR PFX 682e1fee94f346387739e683b31815ab54dc0a30bd6Oliver Schuster "Cannot register miscdev on minor=%d (err=%d)\n", 683e1fee94f346387739e683b31815ab54dc0a30bd6Oliver Schuster wdt_miscdev.minor, rc); 684e1fee94f346387739e683b31815ab54dc0a30bd6Oliver Schuster goto err_out_reboot; 685e1fee94f346387739e683b31815ab54dc0a30bd6Oliver Schuster } 686e1fee94f346387739e683b31815ab54dc0a30bd6Oliver Schuster 687e1fee94f346387739e683b31815ab54dc0a30bd6Oliver Schuster /* Initialize CIR to use it as keepalive source */ 688e1fee94f346387739e683b31815ab54dc0a30bd6Oliver Schuster if (!test_bit(WDTS_USE_GP, &wdt_status)) { 689e1fee94f346387739e683b31815ab54dc0a30bd6Oliver Schuster outb(0x00, CIR_RCR(base)); 690e1fee94f346387739e683b31815ab54dc0a30bd6Oliver Schuster outb(0xc0, CIR_TCR1(base)); 691e1fee94f346387739e683b31815ab54dc0a30bd6Oliver Schuster outb(0x5c, CIR_TCR2(base)); 692e1fee94f346387739e683b31815ab54dc0a30bd6Oliver Schuster outb(0x10, CIR_IER(base)); 693e1fee94f346387739e683b31815ab54dc0a30bd6Oliver Schuster outb(0x00, CIR_BDHR(base)); 694e1fee94f346387739e683b31815ab54dc0a30bd6Oliver Schuster outb(0x01, CIR_BDLR(base)); 695e1fee94f346387739e683b31815ab54dc0a30bd6Oliver Schuster outb(0x09, CIR_IER(base)); 696e1fee94f346387739e683b31815ab54dc0a30bd6Oliver Schuster } 697e1fee94f346387739e683b31815ab54dc0a30bd6Oliver Schuster 698dfb0b8eae1f78c7d0cf7c8abe6c84ff8cefde50eOndrej Zajicek printk(KERN_INFO PFX "Chip IT%04x revision %d initialized. " 699e1fee94f346387739e683b31815ab54dc0a30bd6Oliver Schuster "timeout=%d sec (nowayout=%d testmode=%d exclusive=%d " 700e1fee94f346387739e683b31815ab54dc0a30bd6Oliver Schuster "nogameport=%d)\n", chip_type, chip_rev, timeout, 701e1fee94f346387739e683b31815ab54dc0a30bd6Oliver Schuster nowayout, testmode, exclusive, nogameport); 702e1fee94f346387739e683b31815ab54dc0a30bd6Oliver Schuster 703e1fee94f346387739e683b31815ab54dc0a30bd6Oliver Schuster return 0; 704e1fee94f346387739e683b31815ab54dc0a30bd6Oliver Schuster 705e1fee94f346387739e683b31815ab54dc0a30bd6Oliver Schustererr_out_reboot: 706e1fee94f346387739e683b31815ab54dc0a30bd6Oliver Schuster unregister_reboot_notifier(&wdt_notifier); 707e1fee94f346387739e683b31815ab54dc0a30bd6Oliver Schustererr_out_region: 708e1fee94f346387739e683b31815ab54dc0a30bd6Oliver Schuster release_region(base, test_bit(WDTS_USE_GP, &wdt_status) ? 1 : 8); 709e1fee94f346387739e683b31815ab54dc0a30bd6Oliver Schuster if (!test_bit(WDTS_USE_GP, &wdt_status)) { 710e1fee94f346387739e683b31815ab54dc0a30bd6Oliver Schuster spin_lock_irqsave(&spinlock, flags); 711e1fee94f346387739e683b31815ab54dc0a30bd6Oliver Schuster superio_enter(); 712e1fee94f346387739e683b31815ab54dc0a30bd6Oliver Schuster superio_select(CIR); 713e1fee94f346387739e683b31815ab54dc0a30bd6Oliver Schuster superio_outb(ciract, ACTREG); 714e1fee94f346387739e683b31815ab54dc0a30bd6Oliver Schuster superio_exit(); 715e1fee94f346387739e683b31815ab54dc0a30bd6Oliver Schuster spin_unlock_irqrestore(&spinlock, flags); 716e1fee94f346387739e683b31815ab54dc0a30bd6Oliver Schuster } 717e1fee94f346387739e683b31815ab54dc0a30bd6Oliver Schustererr_out: 718ee3e96583e42dcb4bd406ce4e5f824bd5bb80013Ondrej Zajicek if (try_gameport) { 719e1fee94f346387739e683b31815ab54dc0a30bd6Oliver Schuster spin_lock_irqsave(&spinlock, flags); 720e1fee94f346387739e683b31815ab54dc0a30bd6Oliver Schuster superio_enter(); 721e1fee94f346387739e683b31815ab54dc0a30bd6Oliver Schuster superio_select(GAMEPORT); 722e1fee94f346387739e683b31815ab54dc0a30bd6Oliver Schuster superio_outb(gpact, ACTREG); 723e1fee94f346387739e683b31815ab54dc0a30bd6Oliver Schuster superio_exit(); 724e1fee94f346387739e683b31815ab54dc0a30bd6Oliver Schuster spin_unlock_irqrestore(&spinlock, flags); 725e1fee94f346387739e683b31815ab54dc0a30bd6Oliver Schuster } 726e1fee94f346387739e683b31815ab54dc0a30bd6Oliver Schuster 727e1fee94f346387739e683b31815ab54dc0a30bd6Oliver Schuster return rc; 728e1fee94f346387739e683b31815ab54dc0a30bd6Oliver Schuster} 729e1fee94f346387739e683b31815ab54dc0a30bd6Oliver Schuster 730e1fee94f346387739e683b31815ab54dc0a30bd6Oliver Schusterstatic void __exit it87_wdt_exit(void) 731e1fee94f346387739e683b31815ab54dc0a30bd6Oliver Schuster{ 732e1fee94f346387739e683b31815ab54dc0a30bd6Oliver Schuster unsigned long flags; 733e1fee94f346387739e683b31815ab54dc0a30bd6Oliver Schuster int nolock; 734e1fee94f346387739e683b31815ab54dc0a30bd6Oliver Schuster 735e1fee94f346387739e683b31815ab54dc0a30bd6Oliver Schuster nolock = !spin_trylock_irqsave(&spinlock, flags); 736e1fee94f346387739e683b31815ab54dc0a30bd6Oliver Schuster superio_enter(); 737e1fee94f346387739e683b31815ab54dc0a30bd6Oliver Schuster superio_select(GPIO); 738e1fee94f346387739e683b31815ab54dc0a30bd6Oliver Schuster superio_outb(0x00, WDTCTRL); 739e1fee94f346387739e683b31815ab54dc0a30bd6Oliver Schuster superio_outb(0x00, WDTCFG); 740e1fee94f346387739e683b31815ab54dc0a30bd6Oliver Schuster superio_outb(0x00, WDTVALLSB); 741dfb0b8eae1f78c7d0cf7c8abe6c84ff8cefde50eOndrej Zajicek if (max_units > 255) 742dfb0b8eae1f78c7d0cf7c8abe6c84ff8cefde50eOndrej Zajicek superio_outb(0x00, WDTVALMSB); 743e1fee94f346387739e683b31815ab54dc0a30bd6Oliver Schuster if (test_bit(WDTS_USE_GP, &wdt_status)) { 744e1fee94f346387739e683b31815ab54dc0a30bd6Oliver Schuster superio_select(GAMEPORT); 745e1fee94f346387739e683b31815ab54dc0a30bd6Oliver Schuster superio_outb(gpact, ACTREG); 746e1fee94f346387739e683b31815ab54dc0a30bd6Oliver Schuster } else { 747e1fee94f346387739e683b31815ab54dc0a30bd6Oliver Schuster superio_select(CIR); 748e1fee94f346387739e683b31815ab54dc0a30bd6Oliver Schuster superio_outb(ciract, ACTREG); 749e1fee94f346387739e683b31815ab54dc0a30bd6Oliver Schuster } 750e1fee94f346387739e683b31815ab54dc0a30bd6Oliver Schuster superio_exit(); 751e1fee94f346387739e683b31815ab54dc0a30bd6Oliver Schuster if (!nolock) 752e1fee94f346387739e683b31815ab54dc0a30bd6Oliver Schuster spin_unlock_irqrestore(&spinlock, flags); 753e1fee94f346387739e683b31815ab54dc0a30bd6Oliver Schuster 754e1fee94f346387739e683b31815ab54dc0a30bd6Oliver Schuster misc_deregister(&wdt_miscdev); 755e1fee94f346387739e683b31815ab54dc0a30bd6Oliver Schuster unregister_reboot_notifier(&wdt_notifier); 756e1fee94f346387739e683b31815ab54dc0a30bd6Oliver Schuster release_region(base, test_bit(WDTS_USE_GP, &wdt_status) ? 1 : 8); 757e1fee94f346387739e683b31815ab54dc0a30bd6Oliver Schuster} 758e1fee94f346387739e683b31815ab54dc0a30bd6Oliver Schuster 759e1fee94f346387739e683b31815ab54dc0a30bd6Oliver Schustermodule_init(it87_wdt_init); 760e1fee94f346387739e683b31815ab54dc0a30bd6Oliver Schustermodule_exit(it87_wdt_exit); 761e1fee94f346387739e683b31815ab54dc0a30bd6Oliver Schuster 762e1fee94f346387739e683b31815ab54dc0a30bd6Oliver SchusterMODULE_AUTHOR("Oliver Schuster"); 763e1fee94f346387739e683b31815ab54dc0a30bd6Oliver SchusterMODULE_DESCRIPTION("Hardware Watchdog Device Driver for IT87xx EC-LPC I/O"); 764e1fee94f346387739e683b31815ab54dc0a30bd6Oliver SchusterMODULE_LICENSE("GPL"); 765e1fee94f346387739e683b31815ab54dc0a30bd6Oliver SchusterMODULE_ALIAS_MISCDEV(WATCHDOG_MINOR); 766