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