1485ae77dc7f484563707557ccf8c5d228980619fSven Anders/* 2485ae77dc7f484563707557ccf8c5d228980619fSven Anders * SMsC 37B787 Watchdog Timer driver for Linux 2.6.x.x 3485ae77dc7f484563707557ccf8c5d228980619fSven Anders * 429fa0586de4fe518f122a915b8c6e92d12e8ca7fAlan Cox * Based on acquirewdt.c by Alan Cox <alan@lxorguk.ukuu.org.uk> 5143a2e54bf53216674eada16e8953f48b159e08aWim Van Sebroeck * and some other existing drivers 6485ae77dc7f484563707557ccf8c5d228980619fSven Anders * 7485ae77dc7f484563707557ccf8c5d228980619fSven Anders * This program is free software; you can redistribute it and/or 8485ae77dc7f484563707557ccf8c5d228980619fSven Anders * modify it under the terms of the GNU General Public License 9485ae77dc7f484563707557ccf8c5d228980619fSven Anders * as published by the Free Software Foundation; either version 10485ae77dc7f484563707557ccf8c5d228980619fSven Anders * 2 of the License, or (at your option) any later version. 118386c8cfb2131b2a9caae3db6bf94292bbbe1cafWim Van Sebroeck * 12485ae77dc7f484563707557ccf8c5d228980619fSven Anders * The authors do NOT admit liability nor provide warranty for 13485ae77dc7f484563707557ccf8c5d228980619fSven Anders * any of this software. This material is provided "AS-IS" in 14143a2e54bf53216674eada16e8953f48b159e08aWim Van Sebroeck * the hope that it may be useful for others. 15485ae77dc7f484563707557ccf8c5d228980619fSven Anders * 16485ae77dc7f484563707557ccf8c5d228980619fSven Anders * (C) Copyright 2003-2006 Sven Anders <anders@anduras.de> 17485ae77dc7f484563707557ccf8c5d228980619fSven Anders * 18485ae77dc7f484563707557ccf8c5d228980619fSven Anders * History: 19485ae77dc7f484563707557ccf8c5d228980619fSven Anders * 2003 - Created version 1.0 for Linux 2.4.x. 20485ae77dc7f484563707557ccf8c5d228980619fSven Anders * 2006 - Ported to Linux 2.6, added nowayout and MAGICCLOSE 21598467938dd8bcdcd4d88e9102c609f4caa9d9efAlan Cox * features. Released version 1.1 22485ae77dc7f484563707557ccf8c5d228980619fSven Anders * 23485ae77dc7f484563707557ccf8c5d228980619fSven Anders * Theory of operation: 24485ae77dc7f484563707557ccf8c5d228980619fSven Anders * 25143a2e54bf53216674eada16e8953f48b159e08aWim Van Sebroeck * A Watchdog Timer (WDT) is a hardware circuit that can 26143a2e54bf53216674eada16e8953f48b159e08aWim Van Sebroeck * reset the computer system in case of a software fault. 27143a2e54bf53216674eada16e8953f48b159e08aWim Van Sebroeck * You probably knew that already. 28485ae77dc7f484563707557ccf8c5d228980619fSven Anders * 29143a2e54bf53216674eada16e8953f48b159e08aWim Van Sebroeck * Usually a userspace daemon will notify the kernel WDT driver 30143a2e54bf53216674eada16e8953f48b159e08aWim Van Sebroeck * via the /dev/watchdog special device file that userspace is 31143a2e54bf53216674eada16e8953f48b159e08aWim Van Sebroeck * still alive, at regular intervals. When such a notification 32143a2e54bf53216674eada16e8953f48b159e08aWim Van Sebroeck * occurs, the driver will usually tell the hardware watchdog 33143a2e54bf53216674eada16e8953f48b159e08aWim Van Sebroeck * that everything is in order, and that the watchdog should wait 34143a2e54bf53216674eada16e8953f48b159e08aWim Van Sebroeck * for yet another little while to reset the system. 35143a2e54bf53216674eada16e8953f48b159e08aWim Van Sebroeck * If userspace fails (RAM error, kernel bug, whatever), the 36143a2e54bf53216674eada16e8953f48b159e08aWim Van Sebroeck * notifications cease to occur, and the hardware watchdog will 37143a2e54bf53216674eada16e8953f48b159e08aWim Van Sebroeck * reset the system (causing a reboot) after the timeout occurs. 38485ae77dc7f484563707557ccf8c5d228980619fSven Anders * 39485ae77dc7f484563707557ccf8c5d228980619fSven Anders * Create device with: 40485ae77dc7f484563707557ccf8c5d228980619fSven Anders * mknod /dev/watchdog c 10 130 41485ae77dc7f484563707557ccf8c5d228980619fSven Anders * 42485ae77dc7f484563707557ccf8c5d228980619fSven Anders * For an example userspace keep-alive daemon, see: 43395cf9691d72173d8cdaa613c5f0255f993af94bPaul Bolle * Documentation/watchdog/wdt.txt 44485ae77dc7f484563707557ccf8c5d228980619fSven Anders */ 45485ae77dc7f484563707557ccf8c5d228980619fSven Anders 4627c766aaacb265d625dc634bf7903f7f9fd0c697Joe Perches#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt 4727c766aaacb265d625dc634bf7903f7f9fd0c697Joe Perches 48485ae77dc7f484563707557ccf8c5d228980619fSven Anders#include <linux/module.h> 49485ae77dc7f484563707557ccf8c5d228980619fSven Anders#include <linux/moduleparam.h> 50485ae77dc7f484563707557ccf8c5d228980619fSven Anders#include <linux/types.h> 51485ae77dc7f484563707557ccf8c5d228980619fSven Anders#include <linux/miscdevice.h> 52485ae77dc7f484563707557ccf8c5d228980619fSven Anders#include <linux/watchdog.h> 53485ae77dc7f484563707557ccf8c5d228980619fSven Anders#include <linux/delay.h> 54485ae77dc7f484563707557ccf8c5d228980619fSven Anders#include <linux/fs.h> 55485ae77dc7f484563707557ccf8c5d228980619fSven Anders#include <linux/ioport.h> 56485ae77dc7f484563707557ccf8c5d228980619fSven Anders#include <linux/notifier.h> 57485ae77dc7f484563707557ccf8c5d228980619fSven Anders#include <linux/reboot.h> 58485ae77dc7f484563707557ccf8c5d228980619fSven Anders#include <linux/init.h> 59aa1fd4d7c3b131026bf156da40fdf94bcbd705aaWim Van Sebroeck#include <linux/spinlock.h> 60598467938dd8bcdcd4d88e9102c609f4caa9d9efAlan Cox#include <linux/io.h> 61598467938dd8bcdcd4d88e9102c609f4caa9d9efAlan Cox#include <linux/uaccess.h> 62485ae77dc7f484563707557ccf8c5d228980619fSven Anders 63485ae77dc7f484563707557ccf8c5d228980619fSven Anders 64485ae77dc7f484563707557ccf8c5d228980619fSven Anders/* enable support for minutes as units? */ 65485ae77dc7f484563707557ccf8c5d228980619fSven Anders/* (does not always work correctly, so disabled by default!) */ 66485ae77dc7f484563707557ccf8c5d228980619fSven Anders#define SMSC_SUPPORT_MINUTES 67485ae77dc7f484563707557ccf8c5d228980619fSven Anders#undef SMSC_SUPPORT_MINUTES 68485ae77dc7f484563707557ccf8c5d228980619fSven Anders 69485ae77dc7f484563707557ccf8c5d228980619fSven Anders#define MAX_TIMEOUT 255 70485ae77dc7f484563707557ccf8c5d228980619fSven Anders 71485ae77dc7f484563707557ccf8c5d228980619fSven Anders#define UNIT_SECOND 0 72485ae77dc7f484563707557ccf8c5d228980619fSven Anders#define UNIT_MINUTE 1 73485ae77dc7f484563707557ccf8c5d228980619fSven Anders 74598467938dd8bcdcd4d88e9102c609f4caa9d9efAlan Cox#define VERSION "1.1" 75485ae77dc7f484563707557ccf8c5d228980619fSven Anders 76598467938dd8bcdcd4d88e9102c609f4caa9d9efAlan Cox#define IOPORT 0x3F0 77485ae77dc7f484563707557ccf8c5d228980619fSven Anders#define IOPORT_SIZE 2 78598467938dd8bcdcd4d88e9102c609f4caa9d9efAlan Cox#define IODEV_NO 8 79485ae77dc7f484563707557ccf8c5d228980619fSven Anders 80598467938dd8bcdcd4d88e9102c609f4caa9d9efAlan Coxstatic int unit = UNIT_SECOND; /* timer's unit */ 81598467938dd8bcdcd4d88e9102c609f4caa9d9efAlan Coxstatic int timeout = 60; /* timeout value: default is 60 "units" */ 82598467938dd8bcdcd4d88e9102c609f4caa9d9efAlan Coxstatic unsigned long timer_enabled; /* is the timer enabled? */ 83485ae77dc7f484563707557ccf8c5d228980619fSven Anders 84485ae77dc7f484563707557ccf8c5d228980619fSven Andersstatic char expect_close; /* is the close expected? */ 85485ae77dc7f484563707557ccf8c5d228980619fSven Anders 86c7dfd0cca300c5dc49213cf1c78c77393600410dAlexey Dobriyanstatic DEFINE_SPINLOCK(io_lock);/* to guard the watchdog from io races */ 87aa1fd4d7c3b131026bf156da40fdf94bcbd705aaWim Van Sebroeck 8886a1e1896c2710402e29a875d8d830244274244dWim Van Sebroeckstatic bool nowayout = WATCHDOG_NOWAYOUT; 89485ae77dc7f484563707557ccf8c5d228980619fSven Anders 90485ae77dc7f484563707557ccf8c5d228980619fSven Anders/* -- Low level function ----------------------------------------*/ 91485ae77dc7f484563707557ccf8c5d228980619fSven Anders 92485ae77dc7f484563707557ccf8c5d228980619fSven Anders/* unlock the IO chip */ 93485ae77dc7f484563707557ccf8c5d228980619fSven Anders 94485ae77dc7f484563707557ccf8c5d228980619fSven Andersstatic inline void open_io_config(void) 95485ae77dc7f484563707557ccf8c5d228980619fSven Anders{ 96598467938dd8bcdcd4d88e9102c609f4caa9d9efAlan Cox outb(0x55, IOPORT); 97485ae77dc7f484563707557ccf8c5d228980619fSven Anders mdelay(1); 98598467938dd8bcdcd4d88e9102c609f4caa9d9efAlan Cox outb(0x55, IOPORT); 99485ae77dc7f484563707557ccf8c5d228980619fSven Anders} 100485ae77dc7f484563707557ccf8c5d228980619fSven Anders 101485ae77dc7f484563707557ccf8c5d228980619fSven Anders/* lock the IO chip */ 102485ae77dc7f484563707557ccf8c5d228980619fSven Andersstatic inline void close_io_config(void) 103485ae77dc7f484563707557ccf8c5d228980619fSven Anders{ 104598467938dd8bcdcd4d88e9102c609f4caa9d9efAlan Cox outb(0xAA, IOPORT); 105485ae77dc7f484563707557ccf8c5d228980619fSven Anders} 106485ae77dc7f484563707557ccf8c5d228980619fSven Anders 107485ae77dc7f484563707557ccf8c5d228980619fSven Anders/* select the IO device */ 108485ae77dc7f484563707557ccf8c5d228980619fSven Andersstatic inline void select_io_device(unsigned char devno) 109485ae77dc7f484563707557ccf8c5d228980619fSven Anders{ 110598467938dd8bcdcd4d88e9102c609f4caa9d9efAlan Cox outb(0x07, IOPORT); 111598467938dd8bcdcd4d88e9102c609f4caa9d9efAlan Cox outb(devno, IOPORT+1); 112485ae77dc7f484563707557ccf8c5d228980619fSven Anders} 113485ae77dc7f484563707557ccf8c5d228980619fSven Anders 114485ae77dc7f484563707557ccf8c5d228980619fSven Anders/* write to the control register */ 115485ae77dc7f484563707557ccf8c5d228980619fSven Andersstatic inline void write_io_cr(unsigned char reg, unsigned char data) 116485ae77dc7f484563707557ccf8c5d228980619fSven Anders{ 117598467938dd8bcdcd4d88e9102c609f4caa9d9efAlan Cox outb(reg, IOPORT); 118598467938dd8bcdcd4d88e9102c609f4caa9d9efAlan Cox outb(data, IOPORT+1); 119485ae77dc7f484563707557ccf8c5d228980619fSven Anders} 120485ae77dc7f484563707557ccf8c5d228980619fSven Anders 121485ae77dc7f484563707557ccf8c5d228980619fSven Anders/* read from the control register */ 122485ae77dc7f484563707557ccf8c5d228980619fSven Andersstatic inline char read_io_cr(unsigned char reg) 123485ae77dc7f484563707557ccf8c5d228980619fSven Anders{ 124598467938dd8bcdcd4d88e9102c609f4caa9d9efAlan Cox outb(reg, IOPORT); 125598467938dd8bcdcd4d88e9102c609f4caa9d9efAlan Cox return inb(IOPORT+1); 126485ae77dc7f484563707557ccf8c5d228980619fSven Anders} 127485ae77dc7f484563707557ccf8c5d228980619fSven Anders 128485ae77dc7f484563707557ccf8c5d228980619fSven Anders/* -- Medium level functions ------------------------------------*/ 129485ae77dc7f484563707557ccf8c5d228980619fSven Anders 130485ae77dc7f484563707557ccf8c5d228980619fSven Andersstatic inline void gpio_bit12(unsigned char reg) 131485ae77dc7f484563707557ccf8c5d228980619fSven Anders{ 132598467938dd8bcdcd4d88e9102c609f4caa9d9efAlan Cox /* -- General Purpose I/O Bit 1.2 -- 133598467938dd8bcdcd4d88e9102c609f4caa9d9efAlan Cox * Bit 0, In/Out: 0 = Output, 1 = Input 134598467938dd8bcdcd4d88e9102c609f4caa9d9efAlan Cox * Bit 1, Polarity: 0 = No Invert, 1 = Invert 135598467938dd8bcdcd4d88e9102c609f4caa9d9efAlan Cox * Bit 2, Group Enable Intr.: 0 = Disable, 1 = Enable 136598467938dd8bcdcd4d88e9102c609f4caa9d9efAlan Cox * Bit 3/4, Function select: 00 = GPI/O, 01 = WDT, 10 = P17, 137598467938dd8bcdcd4d88e9102c609f4caa9d9efAlan Cox * 11 = Either Edge Triggered Intr. 2 138598467938dd8bcdcd4d88e9102c609f4caa9d9efAlan Cox * Bit 5/6 (Reserved) 139598467938dd8bcdcd4d88e9102c609f4caa9d9efAlan Cox * Bit 7, Output Type: 0 = Push Pull Bit, 1 = Open Drain 140598467938dd8bcdcd4d88e9102c609f4caa9d9efAlan Cox */ 141598467938dd8bcdcd4d88e9102c609f4caa9d9efAlan Cox write_io_cr(0xE2, reg); 142485ae77dc7f484563707557ccf8c5d228980619fSven Anders} 143485ae77dc7f484563707557ccf8c5d228980619fSven Anders 144485ae77dc7f484563707557ccf8c5d228980619fSven Andersstatic inline void gpio_bit13(unsigned char reg) 145485ae77dc7f484563707557ccf8c5d228980619fSven Anders{ 146598467938dd8bcdcd4d88e9102c609f4caa9d9efAlan Cox /* -- General Purpose I/O Bit 1.3 -- 147598467938dd8bcdcd4d88e9102c609f4caa9d9efAlan Cox * Bit 0, In/Out: 0 = Output, 1 = Input 148598467938dd8bcdcd4d88e9102c609f4caa9d9efAlan Cox * Bit 1, Polarity: 0 = No Invert, 1 = Invert 149598467938dd8bcdcd4d88e9102c609f4caa9d9efAlan Cox * Bit 2, Group Enable Intr.: 0 = Disable, 1 = Enable 150598467938dd8bcdcd4d88e9102c609f4caa9d9efAlan Cox * Bit 3, Function select: 0 = GPI/O, 1 = LED 151598467938dd8bcdcd4d88e9102c609f4caa9d9efAlan Cox * Bit 4-6 (Reserved) 152598467938dd8bcdcd4d88e9102c609f4caa9d9efAlan Cox * Bit 7, Output Type: 0 = Push Pull Bit, 1 = Open Drain 153598467938dd8bcdcd4d88e9102c609f4caa9d9efAlan Cox */ 154598467938dd8bcdcd4d88e9102c609f4caa9d9efAlan Cox write_io_cr(0xE3, reg); 155485ae77dc7f484563707557ccf8c5d228980619fSven Anders} 156485ae77dc7f484563707557ccf8c5d228980619fSven Anders 157485ae77dc7f484563707557ccf8c5d228980619fSven Andersstatic inline void wdt_timer_units(unsigned char new_units) 158485ae77dc7f484563707557ccf8c5d228980619fSven Anders{ 159598467938dd8bcdcd4d88e9102c609f4caa9d9efAlan Cox /* -- Watchdog timer units -- 160598467938dd8bcdcd4d88e9102c609f4caa9d9efAlan Cox * Bit 0-6 (Reserved) 161598467938dd8bcdcd4d88e9102c609f4caa9d9efAlan Cox * Bit 7, WDT Time-out Value Units Select 162598467938dd8bcdcd4d88e9102c609f4caa9d9efAlan Cox * (0 = Minutes, 1 = Seconds) 163598467938dd8bcdcd4d88e9102c609f4caa9d9efAlan Cox */ 164598467938dd8bcdcd4d88e9102c609f4caa9d9efAlan Cox write_io_cr(0xF1, new_units); 165485ae77dc7f484563707557ccf8c5d228980619fSven Anders} 166485ae77dc7f484563707557ccf8c5d228980619fSven Anders 167485ae77dc7f484563707557ccf8c5d228980619fSven Andersstatic inline void wdt_timeout_value(unsigned char new_timeout) 168485ae77dc7f484563707557ccf8c5d228980619fSven Anders{ 169598467938dd8bcdcd4d88e9102c609f4caa9d9efAlan Cox /* -- Watchdog Timer Time-out Value -- 170598467938dd8bcdcd4d88e9102c609f4caa9d9efAlan Cox * Bit 0-7 Binary coded units (0=Disabled, 1..255) 171598467938dd8bcdcd4d88e9102c609f4caa9d9efAlan Cox */ 172598467938dd8bcdcd4d88e9102c609f4caa9d9efAlan Cox write_io_cr(0xF2, new_timeout); 173485ae77dc7f484563707557ccf8c5d228980619fSven Anders} 174485ae77dc7f484563707557ccf8c5d228980619fSven Anders 175485ae77dc7f484563707557ccf8c5d228980619fSven Andersstatic inline void wdt_timer_conf(unsigned char conf) 176485ae77dc7f484563707557ccf8c5d228980619fSven Anders{ 177598467938dd8bcdcd4d88e9102c609f4caa9d9efAlan Cox /* -- Watchdog timer configuration -- 178598467938dd8bcdcd4d88e9102c609f4caa9d9efAlan Cox * Bit 0 Joystick enable: 0* = No Reset, 1 = Reset WDT upon 179598467938dd8bcdcd4d88e9102c609f4caa9d9efAlan Cox * Gameport I/O 180598467938dd8bcdcd4d88e9102c609f4caa9d9efAlan Cox * Bit 1 Keyboard enable: 0* = No Reset, 1 = Reset WDT upon KBD Intr. 181598467938dd8bcdcd4d88e9102c609f4caa9d9efAlan Cox * Bit 2 Mouse enable: 0* = No Reset, 1 = Reset WDT upon Mouse Intr 182598467938dd8bcdcd4d88e9102c609f4caa9d9efAlan Cox * Bit 3 Reset the timer 183598467938dd8bcdcd4d88e9102c609f4caa9d9efAlan Cox * (Wrong in SMsC documentation? Given as: PowerLED Timout 184598467938dd8bcdcd4d88e9102c609f4caa9d9efAlan Cox * Enabled) 185598467938dd8bcdcd4d88e9102c609f4caa9d9efAlan Cox * Bit 4-7 WDT Interrupt Mapping: (0000* = Disabled, 186598467938dd8bcdcd4d88e9102c609f4caa9d9efAlan Cox * 0001=IRQ1, 0010=(Invalid), 0011=IRQ3 to 1111=IRQ15) 187598467938dd8bcdcd4d88e9102c609f4caa9d9efAlan Cox */ 188598467938dd8bcdcd4d88e9102c609f4caa9d9efAlan Cox write_io_cr(0xF3, conf); 189485ae77dc7f484563707557ccf8c5d228980619fSven Anders} 190485ae77dc7f484563707557ccf8c5d228980619fSven Anders 191485ae77dc7f484563707557ccf8c5d228980619fSven Andersstatic inline void wdt_timer_ctrl(unsigned char reg) 192485ae77dc7f484563707557ccf8c5d228980619fSven Anders{ 193598467938dd8bcdcd4d88e9102c609f4caa9d9efAlan Cox /* -- Watchdog timer control -- 19425985edcedea6396277003854657b5f3cb31a628Lucas De Marchi * Bit 0 Status Bit: 0 = Timer counting, 1 = Timeout occurred 195598467938dd8bcdcd4d88e9102c609f4caa9d9efAlan Cox * Bit 1 Power LED Toggle: 0 = Disable Toggle, 1 = Toggle at 1 Hz 196598467938dd8bcdcd4d88e9102c609f4caa9d9efAlan Cox * Bit 2 Force Timeout: 1 = Forces WD timeout event (self-cleaning) 197598467938dd8bcdcd4d88e9102c609f4caa9d9efAlan Cox * Bit 3 P20 Force Timeout enabled: 198598467938dd8bcdcd4d88e9102c609f4caa9d9efAlan Cox * 0 = P20 activity does not generate the WD timeout event 199598467938dd8bcdcd4d88e9102c609f4caa9d9efAlan Cox * 1 = P20 Allows rising edge of P20, from the keyboard 200598467938dd8bcdcd4d88e9102c609f4caa9d9efAlan Cox * controller, to force the WD timeout event. 201598467938dd8bcdcd4d88e9102c609f4caa9d9efAlan Cox * Bit 4 (Reserved) 202598467938dd8bcdcd4d88e9102c609f4caa9d9efAlan Cox * -- Soft power management -- 203598467938dd8bcdcd4d88e9102c609f4caa9d9efAlan Cox * Bit 5 Stop Counter: 1 = Stop software power down counter 204598467938dd8bcdcd4d88e9102c609f4caa9d9efAlan Cox * set via register 0xB8, (self-cleaning) 205598467938dd8bcdcd4d88e9102c609f4caa9d9efAlan Cox * (Upon read: 0 = Counter running, 1 = Counter stopped) 206598467938dd8bcdcd4d88e9102c609f4caa9d9efAlan Cox * Bit 6 Restart Counter: 1 = Restart software power down counter 207598467938dd8bcdcd4d88e9102c609f4caa9d9efAlan Cox * set via register 0xB8, (self-cleaning) 208598467938dd8bcdcd4d88e9102c609f4caa9d9efAlan Cox * Bit 7 SPOFF: 1 = Force software power down (self-cleaning) 209598467938dd8bcdcd4d88e9102c609f4caa9d9efAlan Cox */ 210598467938dd8bcdcd4d88e9102c609f4caa9d9efAlan Cox write_io_cr(0xF4, reg); 211485ae77dc7f484563707557ccf8c5d228980619fSven Anders} 212485ae77dc7f484563707557ccf8c5d228980619fSven Anders 213485ae77dc7f484563707557ccf8c5d228980619fSven Anders/* -- Higher level functions ------------------------------------*/ 214485ae77dc7f484563707557ccf8c5d228980619fSven Anders 215485ae77dc7f484563707557ccf8c5d228980619fSven Anders/* initialize watchdog */ 216485ae77dc7f484563707557ccf8c5d228980619fSven Anders 217485ae77dc7f484563707557ccf8c5d228980619fSven Andersstatic void wb_smsc_wdt_initialize(void) 218485ae77dc7f484563707557ccf8c5d228980619fSven Anders{ 219598467938dd8bcdcd4d88e9102c609f4caa9d9efAlan Cox unsigned char old; 220485ae77dc7f484563707557ccf8c5d228980619fSven Anders 221aa1fd4d7c3b131026bf156da40fdf94bcbd705aaWim Van Sebroeck spin_lock(&io_lock); 222598467938dd8bcdcd4d88e9102c609f4caa9d9efAlan Cox open_io_config(); 223598467938dd8bcdcd4d88e9102c609f4caa9d9efAlan Cox select_io_device(IODEV_NO); 224485ae77dc7f484563707557ccf8c5d228980619fSven Anders 225598467938dd8bcdcd4d88e9102c609f4caa9d9efAlan Cox /* enable the watchdog */ 226598467938dd8bcdcd4d88e9102c609f4caa9d9efAlan Cox gpio_bit13(0x08); /* Select pin 80 = LED not GPIO */ 227598467938dd8bcdcd4d88e9102c609f4caa9d9efAlan Cox gpio_bit12(0x0A); /* Set pin 79 = WDT not 228598467938dd8bcdcd4d88e9102c609f4caa9d9efAlan Cox GPIO/Output/Polarity=Invert */ 229598467938dd8bcdcd4d88e9102c609f4caa9d9efAlan Cox /* disable the timeout */ 230598467938dd8bcdcd4d88e9102c609f4caa9d9efAlan Cox wdt_timeout_value(0); 231485ae77dc7f484563707557ccf8c5d228980619fSven Anders 232598467938dd8bcdcd4d88e9102c609f4caa9d9efAlan Cox /* reset control register */ 233598467938dd8bcdcd4d88e9102c609f4caa9d9efAlan Cox wdt_timer_ctrl(0x00); 234485ae77dc7f484563707557ccf8c5d228980619fSven Anders 235598467938dd8bcdcd4d88e9102c609f4caa9d9efAlan Cox /* reset configuration register */ 236485ae77dc7f484563707557ccf8c5d228980619fSven Anders wdt_timer_conf(0x00); 237485ae77dc7f484563707557ccf8c5d228980619fSven Anders 238598467938dd8bcdcd4d88e9102c609f4caa9d9efAlan Cox /* read old (timer units) register */ 239598467938dd8bcdcd4d88e9102c609f4caa9d9efAlan Cox old = read_io_cr(0xF1) & 0x7F; 240598467938dd8bcdcd4d88e9102c609f4caa9d9efAlan Cox if (unit == UNIT_SECOND) 241598467938dd8bcdcd4d88e9102c609f4caa9d9efAlan Cox old |= 0x80; /* set to seconds */ 242485ae77dc7f484563707557ccf8c5d228980619fSven Anders 243598467938dd8bcdcd4d88e9102c609f4caa9d9efAlan Cox /* set the watchdog timer units */ 244598467938dd8bcdcd4d88e9102c609f4caa9d9efAlan Cox wdt_timer_units(old); 245485ae77dc7f484563707557ccf8c5d228980619fSven Anders 246598467938dd8bcdcd4d88e9102c609f4caa9d9efAlan Cox close_io_config(); 247aa1fd4d7c3b131026bf156da40fdf94bcbd705aaWim Van Sebroeck spin_unlock(&io_lock); 248485ae77dc7f484563707557ccf8c5d228980619fSven Anders} 249485ae77dc7f484563707557ccf8c5d228980619fSven Anders 250485ae77dc7f484563707557ccf8c5d228980619fSven Anders/* shutdown the watchdog */ 251485ae77dc7f484563707557ccf8c5d228980619fSven Anders 252485ae77dc7f484563707557ccf8c5d228980619fSven Andersstatic void wb_smsc_wdt_shutdown(void) 253485ae77dc7f484563707557ccf8c5d228980619fSven Anders{ 254aa1fd4d7c3b131026bf156da40fdf94bcbd705aaWim Van Sebroeck spin_lock(&io_lock); 255598467938dd8bcdcd4d88e9102c609f4caa9d9efAlan Cox open_io_config(); 256598467938dd8bcdcd4d88e9102c609f4caa9d9efAlan Cox select_io_device(IODEV_NO); 257485ae77dc7f484563707557ccf8c5d228980619fSven Anders 258598467938dd8bcdcd4d88e9102c609f4caa9d9efAlan Cox /* disable the watchdog */ 259598467938dd8bcdcd4d88e9102c609f4caa9d9efAlan Cox gpio_bit13(0x09); 260598467938dd8bcdcd4d88e9102c609f4caa9d9efAlan Cox gpio_bit12(0x09); 261485ae77dc7f484563707557ccf8c5d228980619fSven Anders 262598467938dd8bcdcd4d88e9102c609f4caa9d9efAlan Cox /* reset watchdog config register */ 263485ae77dc7f484563707557ccf8c5d228980619fSven Anders wdt_timer_conf(0x00); 264485ae77dc7f484563707557ccf8c5d228980619fSven Anders 265598467938dd8bcdcd4d88e9102c609f4caa9d9efAlan Cox /* reset watchdog control register */ 266598467938dd8bcdcd4d88e9102c609f4caa9d9efAlan Cox wdt_timer_ctrl(0x00); 267485ae77dc7f484563707557ccf8c5d228980619fSven Anders 268598467938dd8bcdcd4d88e9102c609f4caa9d9efAlan Cox /* disable timeout */ 269598467938dd8bcdcd4d88e9102c609f4caa9d9efAlan Cox wdt_timeout_value(0x00); 270485ae77dc7f484563707557ccf8c5d228980619fSven Anders 271598467938dd8bcdcd4d88e9102c609f4caa9d9efAlan Cox close_io_config(); 272aa1fd4d7c3b131026bf156da40fdf94bcbd705aaWim Van Sebroeck spin_unlock(&io_lock); 273485ae77dc7f484563707557ccf8c5d228980619fSven Anders} 274485ae77dc7f484563707557ccf8c5d228980619fSven Anders 275485ae77dc7f484563707557ccf8c5d228980619fSven Anders/* set timeout => enable watchdog */ 276485ae77dc7f484563707557ccf8c5d228980619fSven Anders 277485ae77dc7f484563707557ccf8c5d228980619fSven Andersstatic void wb_smsc_wdt_set_timeout(unsigned char new_timeout) 278485ae77dc7f484563707557ccf8c5d228980619fSven Anders{ 279aa1fd4d7c3b131026bf156da40fdf94bcbd705aaWim Van Sebroeck spin_lock(&io_lock); 280598467938dd8bcdcd4d88e9102c609f4caa9d9efAlan Cox open_io_config(); 281598467938dd8bcdcd4d88e9102c609f4caa9d9efAlan Cox select_io_device(IODEV_NO); 282485ae77dc7f484563707557ccf8c5d228980619fSven Anders 283598467938dd8bcdcd4d88e9102c609f4caa9d9efAlan Cox /* set Power LED to blink, if we enable the timeout */ 284598467938dd8bcdcd4d88e9102c609f4caa9d9efAlan Cox wdt_timer_ctrl((new_timeout == 0) ? 0x00 : 0x02); 285485ae77dc7f484563707557ccf8c5d228980619fSven Anders 286598467938dd8bcdcd4d88e9102c609f4caa9d9efAlan Cox /* set timeout value */ 287598467938dd8bcdcd4d88e9102c609f4caa9d9efAlan Cox wdt_timeout_value(new_timeout); 288485ae77dc7f484563707557ccf8c5d228980619fSven Anders 289598467938dd8bcdcd4d88e9102c609f4caa9d9efAlan Cox close_io_config(); 290aa1fd4d7c3b131026bf156da40fdf94bcbd705aaWim Van Sebroeck spin_unlock(&io_lock); 291485ae77dc7f484563707557ccf8c5d228980619fSven Anders} 292485ae77dc7f484563707557ccf8c5d228980619fSven Anders 293485ae77dc7f484563707557ccf8c5d228980619fSven Anders/* get timeout */ 294485ae77dc7f484563707557ccf8c5d228980619fSven Anders 295485ae77dc7f484563707557ccf8c5d228980619fSven Andersstatic unsigned char wb_smsc_wdt_get_timeout(void) 296485ae77dc7f484563707557ccf8c5d228980619fSven Anders{ 297598467938dd8bcdcd4d88e9102c609f4caa9d9efAlan Cox unsigned char set_timeout; 298485ae77dc7f484563707557ccf8c5d228980619fSven Anders 299aa1fd4d7c3b131026bf156da40fdf94bcbd705aaWim Van Sebroeck spin_lock(&io_lock); 300598467938dd8bcdcd4d88e9102c609f4caa9d9efAlan Cox open_io_config(); 301598467938dd8bcdcd4d88e9102c609f4caa9d9efAlan Cox select_io_device(IODEV_NO); 302598467938dd8bcdcd4d88e9102c609f4caa9d9efAlan Cox set_timeout = read_io_cr(0xF2); 303598467938dd8bcdcd4d88e9102c609f4caa9d9efAlan Cox close_io_config(); 304aa1fd4d7c3b131026bf156da40fdf94bcbd705aaWim Van Sebroeck spin_unlock(&io_lock); 305485ae77dc7f484563707557ccf8c5d228980619fSven Anders 306598467938dd8bcdcd4d88e9102c609f4caa9d9efAlan Cox return set_timeout; 307485ae77dc7f484563707557ccf8c5d228980619fSven Anders} 308485ae77dc7f484563707557ccf8c5d228980619fSven Anders 309485ae77dc7f484563707557ccf8c5d228980619fSven Anders/* disable watchdog */ 310485ae77dc7f484563707557ccf8c5d228980619fSven Anders 311485ae77dc7f484563707557ccf8c5d228980619fSven Andersstatic void wb_smsc_wdt_disable(void) 312485ae77dc7f484563707557ccf8c5d228980619fSven Anders{ 313598467938dd8bcdcd4d88e9102c609f4caa9d9efAlan Cox /* set the timeout to 0 to disable the watchdog */ 314598467938dd8bcdcd4d88e9102c609f4caa9d9efAlan Cox wb_smsc_wdt_set_timeout(0); 315485ae77dc7f484563707557ccf8c5d228980619fSven Anders} 316485ae77dc7f484563707557ccf8c5d228980619fSven Anders 317485ae77dc7f484563707557ccf8c5d228980619fSven Anders/* enable watchdog by setting the current timeout */ 318485ae77dc7f484563707557ccf8c5d228980619fSven Anders 319485ae77dc7f484563707557ccf8c5d228980619fSven Andersstatic void wb_smsc_wdt_enable(void) 320485ae77dc7f484563707557ccf8c5d228980619fSven Anders{ 321598467938dd8bcdcd4d88e9102c609f4caa9d9efAlan Cox /* set the current timeout... */ 322598467938dd8bcdcd4d88e9102c609f4caa9d9efAlan Cox wb_smsc_wdt_set_timeout(timeout); 323485ae77dc7f484563707557ccf8c5d228980619fSven Anders} 324485ae77dc7f484563707557ccf8c5d228980619fSven Anders 325485ae77dc7f484563707557ccf8c5d228980619fSven Anders/* reset the timer */ 326485ae77dc7f484563707557ccf8c5d228980619fSven Anders 327485ae77dc7f484563707557ccf8c5d228980619fSven Andersstatic void wb_smsc_wdt_reset_timer(void) 328485ae77dc7f484563707557ccf8c5d228980619fSven Anders{ 329aa1fd4d7c3b131026bf156da40fdf94bcbd705aaWim Van Sebroeck spin_lock(&io_lock); 330598467938dd8bcdcd4d88e9102c609f4caa9d9efAlan Cox open_io_config(); 331598467938dd8bcdcd4d88e9102c609f4caa9d9efAlan Cox select_io_device(IODEV_NO); 332485ae77dc7f484563707557ccf8c5d228980619fSven Anders 333598467938dd8bcdcd4d88e9102c609f4caa9d9efAlan Cox /* reset the timer */ 334485ae77dc7f484563707557ccf8c5d228980619fSven Anders wdt_timeout_value(timeout); 335485ae77dc7f484563707557ccf8c5d228980619fSven Anders wdt_timer_conf(0x08); 336485ae77dc7f484563707557ccf8c5d228980619fSven Anders 337598467938dd8bcdcd4d88e9102c609f4caa9d9efAlan Cox close_io_config(); 338aa1fd4d7c3b131026bf156da40fdf94bcbd705aaWim Van Sebroeck spin_unlock(&io_lock); 339485ae77dc7f484563707557ccf8c5d228980619fSven Anders} 340485ae77dc7f484563707557ccf8c5d228980619fSven Anders 341485ae77dc7f484563707557ccf8c5d228980619fSven Anders/* return, if the watchdog is enabled (timeout is set...) */ 342485ae77dc7f484563707557ccf8c5d228980619fSven Anders 343485ae77dc7f484563707557ccf8c5d228980619fSven Andersstatic int wb_smsc_wdt_status(void) 344485ae77dc7f484563707557ccf8c5d228980619fSven Anders{ 345485ae77dc7f484563707557ccf8c5d228980619fSven Anders return (wb_smsc_wdt_get_timeout() == 0) ? 0 : WDIOF_KEEPALIVEPING; 346485ae77dc7f484563707557ccf8c5d228980619fSven Anders} 347485ae77dc7f484563707557ccf8c5d228980619fSven Anders 348485ae77dc7f484563707557ccf8c5d228980619fSven Anders 349485ae77dc7f484563707557ccf8c5d228980619fSven Anders/* -- File operations -------------------------------------------*/ 350485ae77dc7f484563707557ccf8c5d228980619fSven Anders 351485ae77dc7f484563707557ccf8c5d228980619fSven Anders/* open => enable watchdog and set initial timeout */ 352485ae77dc7f484563707557ccf8c5d228980619fSven Anders 353485ae77dc7f484563707557ccf8c5d228980619fSven Andersstatic int wb_smsc_wdt_open(struct inode *inode, struct file *file) 354485ae77dc7f484563707557ccf8c5d228980619fSven Anders{ 355485ae77dc7f484563707557ccf8c5d228980619fSven Anders /* /dev/watchdog can only be opened once */ 356485ae77dc7f484563707557ccf8c5d228980619fSven Anders 357aa1fd4d7c3b131026bf156da40fdf94bcbd705aaWim Van Sebroeck if (test_and_set_bit(0, &timer_enabled)) 358485ae77dc7f484563707557ccf8c5d228980619fSven Anders return -EBUSY; 359485ae77dc7f484563707557ccf8c5d228980619fSven Anders 360485ae77dc7f484563707557ccf8c5d228980619fSven Anders if (nowayout) 361485ae77dc7f484563707557ccf8c5d228980619fSven Anders __module_get(THIS_MODULE); 362485ae77dc7f484563707557ccf8c5d228980619fSven Anders 363485ae77dc7f484563707557ccf8c5d228980619fSven Anders /* Reload and activate timer */ 364485ae77dc7f484563707557ccf8c5d228980619fSven Anders wb_smsc_wdt_enable(); 365485ae77dc7f484563707557ccf8c5d228980619fSven Anders 36627c766aaacb265d625dc634bf7903f7f9fd0c697Joe Perches pr_info("Watchdog enabled. Timeout set to %d %s\n", 367598467938dd8bcdcd4d88e9102c609f4caa9d9efAlan Cox timeout, (unit == UNIT_SECOND) ? "second(s)" : "minute(s)"); 368485ae77dc7f484563707557ccf8c5d228980619fSven Anders 369485ae77dc7f484563707557ccf8c5d228980619fSven Anders return nonseekable_open(inode, file); 370485ae77dc7f484563707557ccf8c5d228980619fSven Anders} 371485ae77dc7f484563707557ccf8c5d228980619fSven Anders 372485ae77dc7f484563707557ccf8c5d228980619fSven Anders/* close => shut off the timer */ 373485ae77dc7f484563707557ccf8c5d228980619fSven Anders 374485ae77dc7f484563707557ccf8c5d228980619fSven Andersstatic int wb_smsc_wdt_release(struct inode *inode, struct file *file) 375485ae77dc7f484563707557ccf8c5d228980619fSven Anders{ 376485ae77dc7f484563707557ccf8c5d228980619fSven Anders /* Shut off the timer. */ 377485ae77dc7f484563707557ccf8c5d228980619fSven Anders 378485ae77dc7f484563707557ccf8c5d228980619fSven Anders if (expect_close == 42) { 379598467938dd8bcdcd4d88e9102c609f4caa9d9efAlan Cox wb_smsc_wdt_disable(); 38027c766aaacb265d625dc634bf7903f7f9fd0c697Joe Perches pr_info("Watchdog disabled, sleeping again...\n"); 381485ae77dc7f484563707557ccf8c5d228980619fSven Anders } else { 38227c766aaacb265d625dc634bf7903f7f9fd0c697Joe Perches pr_crit("Unexpected close, not stopping watchdog!\n"); 383485ae77dc7f484563707557ccf8c5d228980619fSven Anders wb_smsc_wdt_reset_timer(); 384485ae77dc7f484563707557ccf8c5d228980619fSven Anders } 385485ae77dc7f484563707557ccf8c5d228980619fSven Anders 386aa1fd4d7c3b131026bf156da40fdf94bcbd705aaWim Van Sebroeck clear_bit(0, &timer_enabled); 387485ae77dc7f484563707557ccf8c5d228980619fSven Anders expect_close = 0; 388485ae77dc7f484563707557ccf8c5d228980619fSven Anders return 0; 389485ae77dc7f484563707557ccf8c5d228980619fSven Anders} 390485ae77dc7f484563707557ccf8c5d228980619fSven Anders 391485ae77dc7f484563707557ccf8c5d228980619fSven Anders/* write => update the timer to keep the machine alive */ 392485ae77dc7f484563707557ccf8c5d228980619fSven Anders 393485ae77dc7f484563707557ccf8c5d228980619fSven Andersstatic ssize_t wb_smsc_wdt_write(struct file *file, const char __user *data, 394485ae77dc7f484563707557ccf8c5d228980619fSven Anders size_t len, loff_t *ppos) 395485ae77dc7f484563707557ccf8c5d228980619fSven Anders{ 396485ae77dc7f484563707557ccf8c5d228980619fSven Anders /* See if we got the magic character 'V' and reload the timer */ 397485ae77dc7f484563707557ccf8c5d228980619fSven Anders if (len) { 398485ae77dc7f484563707557ccf8c5d228980619fSven Anders if (!nowayout) { 399485ae77dc7f484563707557ccf8c5d228980619fSven Anders size_t i; 400485ae77dc7f484563707557ccf8c5d228980619fSven Anders 401485ae77dc7f484563707557ccf8c5d228980619fSven Anders /* reset expect flag */ 402485ae77dc7f484563707557ccf8c5d228980619fSven Anders expect_close = 0; 403485ae77dc7f484563707557ccf8c5d228980619fSven Anders 404598467938dd8bcdcd4d88e9102c609f4caa9d9efAlan Cox /* scan to see whether or not we got the 405598467938dd8bcdcd4d88e9102c609f4caa9d9efAlan Cox magic character */ 406485ae77dc7f484563707557ccf8c5d228980619fSven Anders for (i = 0; i != len; i++) { 407485ae77dc7f484563707557ccf8c5d228980619fSven Anders char c; 4087944d3a5a70ee5c1904ed1e8b1d71ff0af2854d9Wim Van Sebroeck if (get_user(c, data + i)) 409485ae77dc7f484563707557ccf8c5d228980619fSven Anders return -EFAULT; 410485ae77dc7f484563707557ccf8c5d228980619fSven Anders if (c == 'V') 411485ae77dc7f484563707557ccf8c5d228980619fSven Anders expect_close = 42; 412485ae77dc7f484563707557ccf8c5d228980619fSven Anders } 413485ae77dc7f484563707557ccf8c5d228980619fSven Anders } 414485ae77dc7f484563707557ccf8c5d228980619fSven Anders 415485ae77dc7f484563707557ccf8c5d228980619fSven Anders /* someone wrote to us, we should reload the timer */ 416485ae77dc7f484563707557ccf8c5d228980619fSven Anders wb_smsc_wdt_reset_timer(); 417485ae77dc7f484563707557ccf8c5d228980619fSven Anders } 418485ae77dc7f484563707557ccf8c5d228980619fSven Anders return len; 419485ae77dc7f484563707557ccf8c5d228980619fSven Anders} 420485ae77dc7f484563707557ccf8c5d228980619fSven Anders 421485ae77dc7f484563707557ccf8c5d228980619fSven Anders/* ioctl => control interface */ 422485ae77dc7f484563707557ccf8c5d228980619fSven Anders 423598467938dd8bcdcd4d88e9102c609f4caa9d9efAlan Coxstatic long wb_smsc_wdt_ioctl(struct file *file, 424598467938dd8bcdcd4d88e9102c609f4caa9d9efAlan Cox unsigned int cmd, unsigned long arg) 425485ae77dc7f484563707557ccf8c5d228980619fSven Anders{ 426485ae77dc7f484563707557ccf8c5d228980619fSven Anders int new_timeout; 427485ae77dc7f484563707557ccf8c5d228980619fSven Anders 428485ae77dc7f484563707557ccf8c5d228980619fSven Anders union { 429485ae77dc7f484563707557ccf8c5d228980619fSven Anders struct watchdog_info __user *ident; 430485ae77dc7f484563707557ccf8c5d228980619fSven Anders int __user *i; 431485ae77dc7f484563707557ccf8c5d228980619fSven Anders } uarg; 432485ae77dc7f484563707557ccf8c5d228980619fSven Anders 433598467938dd8bcdcd4d88e9102c609f4caa9d9efAlan Cox static const struct watchdog_info ident = { 4345f3b27569fc0286a51f8d0655c7fb4f5b36aea65Wim Van Sebroeck .options = WDIOF_KEEPALIVEPING | 435598467938dd8bcdcd4d88e9102c609f4caa9d9efAlan Cox WDIOF_SETTIMEOUT | 436485ae77dc7f484563707557ccf8c5d228980619fSven Anders WDIOF_MAGICCLOSE, 437485ae77dc7f484563707557ccf8c5d228980619fSven Anders .firmware_version = 0, 4385f3b27569fc0286a51f8d0655c7fb4f5b36aea65Wim Van Sebroeck .identity = "SMsC 37B787 Watchdog", 439485ae77dc7f484563707557ccf8c5d228980619fSven Anders }; 440485ae77dc7f484563707557ccf8c5d228980619fSven Anders 441485ae77dc7f484563707557ccf8c5d228980619fSven Anders uarg.i = (int __user *)arg; 442485ae77dc7f484563707557ccf8c5d228980619fSven Anders 443485ae77dc7f484563707557ccf8c5d228980619fSven Anders switch (cmd) { 444598467938dd8bcdcd4d88e9102c609f4caa9d9efAlan Cox case WDIOC_GETSUPPORT: 445598467938dd8bcdcd4d88e9102c609f4caa9d9efAlan Cox return copy_to_user(uarg.ident, &ident, sizeof(ident)) 446598467938dd8bcdcd4d88e9102c609f4caa9d9efAlan Cox ? -EFAULT : 0; 447598467938dd8bcdcd4d88e9102c609f4caa9d9efAlan Cox case WDIOC_GETSTATUS: 448598467938dd8bcdcd4d88e9102c609f4caa9d9efAlan Cox return put_user(wb_smsc_wdt_status(), uarg.i); 449598467938dd8bcdcd4d88e9102c609f4caa9d9efAlan Cox case WDIOC_GETBOOTSTATUS: 450598467938dd8bcdcd4d88e9102c609f4caa9d9efAlan Cox return put_user(0, uarg.i); 4510c06090c9472db0525cb6fe229c3bea33bbbbb3cWim Van Sebroeck case WDIOC_SETOPTIONS: 4520c06090c9472db0525cb6fe229c3bea33bbbbb3cWim Van Sebroeck { 4530c06090c9472db0525cb6fe229c3bea33bbbbb3cWim Van Sebroeck int options, retval = -EINVAL; 4540c06090c9472db0525cb6fe229c3bea33bbbbb3cWim Van Sebroeck 4550c06090c9472db0525cb6fe229c3bea33bbbbb3cWim Van Sebroeck if (get_user(options, uarg.i)) 4560c06090c9472db0525cb6fe229c3bea33bbbbb3cWim Van Sebroeck return -EFAULT; 4570c06090c9472db0525cb6fe229c3bea33bbbbb3cWim Van Sebroeck 4580c06090c9472db0525cb6fe229c3bea33bbbbb3cWim Van Sebroeck if (options & WDIOS_DISABLECARD) { 4590c06090c9472db0525cb6fe229c3bea33bbbbb3cWim Van Sebroeck wb_smsc_wdt_disable(); 4600c06090c9472db0525cb6fe229c3bea33bbbbb3cWim Van Sebroeck retval = 0; 4610c06090c9472db0525cb6fe229c3bea33bbbbb3cWim Van Sebroeck } 4620c06090c9472db0525cb6fe229c3bea33bbbbb3cWim Van Sebroeck if (options & WDIOS_ENABLECARD) { 4630c06090c9472db0525cb6fe229c3bea33bbbbb3cWim Van Sebroeck wb_smsc_wdt_enable(); 4640c06090c9472db0525cb6fe229c3bea33bbbbb3cWim Van Sebroeck retval = 0; 4650c06090c9472db0525cb6fe229c3bea33bbbbb3cWim Van Sebroeck } 4660c06090c9472db0525cb6fe229c3bea33bbbbb3cWim Van Sebroeck return retval; 4670c06090c9472db0525cb6fe229c3bea33bbbbb3cWim Van Sebroeck } 468598467938dd8bcdcd4d88e9102c609f4caa9d9efAlan Cox case WDIOC_KEEPALIVE: 469598467938dd8bcdcd4d88e9102c609f4caa9d9efAlan Cox wb_smsc_wdt_reset_timer(); 470598467938dd8bcdcd4d88e9102c609f4caa9d9efAlan Cox return 0; 471598467938dd8bcdcd4d88e9102c609f4caa9d9efAlan Cox case WDIOC_SETTIMEOUT: 472598467938dd8bcdcd4d88e9102c609f4caa9d9efAlan Cox if (get_user(new_timeout, uarg.i)) 473598467938dd8bcdcd4d88e9102c609f4caa9d9efAlan Cox return -EFAULT; 474598467938dd8bcdcd4d88e9102c609f4caa9d9efAlan Cox /* the API states this is given in secs */ 475598467938dd8bcdcd4d88e9102c609f4caa9d9efAlan Cox if (unit == UNIT_MINUTE) 476598467938dd8bcdcd4d88e9102c609f4caa9d9efAlan Cox new_timeout /= 60; 477598467938dd8bcdcd4d88e9102c609f4caa9d9efAlan Cox if (new_timeout < 0 || new_timeout > MAX_TIMEOUT) 478598467938dd8bcdcd4d88e9102c609f4caa9d9efAlan Cox return -EINVAL; 479598467938dd8bcdcd4d88e9102c609f4caa9d9efAlan Cox timeout = new_timeout; 480598467938dd8bcdcd4d88e9102c609f4caa9d9efAlan Cox wb_smsc_wdt_set_timeout(timeout); 481598467938dd8bcdcd4d88e9102c609f4caa9d9efAlan Cox /* fall through and return the new timeout... */ 482598467938dd8bcdcd4d88e9102c609f4caa9d9efAlan Cox case WDIOC_GETTIMEOUT: 483598467938dd8bcdcd4d88e9102c609f4caa9d9efAlan Cox new_timeout = timeout; 484598467938dd8bcdcd4d88e9102c609f4caa9d9efAlan Cox if (unit == UNIT_MINUTE) 485143a2e54bf53216674eada16e8953f48b159e08aWim Van Sebroeck new_timeout *= 60; 486598467938dd8bcdcd4d88e9102c609f4caa9d9efAlan Cox return put_user(new_timeout, uarg.i); 487598467938dd8bcdcd4d88e9102c609f4caa9d9efAlan Cox default: 488598467938dd8bcdcd4d88e9102c609f4caa9d9efAlan Cox return -ENOTTY; 489485ae77dc7f484563707557ccf8c5d228980619fSven Anders } 490485ae77dc7f484563707557ccf8c5d228980619fSven Anders} 491485ae77dc7f484563707557ccf8c5d228980619fSven Anders 492485ae77dc7f484563707557ccf8c5d228980619fSven Anders/* -- Notifier funtions -----------------------------------------*/ 493485ae77dc7f484563707557ccf8c5d228980619fSven Anders 494598467938dd8bcdcd4d88e9102c609f4caa9d9efAlan Coxstatic int wb_smsc_wdt_notify_sys(struct notifier_block *this, 495598467938dd8bcdcd4d88e9102c609f4caa9d9efAlan Cox unsigned long code, void *unused) 496485ae77dc7f484563707557ccf8c5d228980619fSven Anders{ 497598467938dd8bcdcd4d88e9102c609f4caa9d9efAlan Cox if (code == SYS_DOWN || code == SYS_HALT) { 498598467938dd8bcdcd4d88e9102c609f4caa9d9efAlan Cox /* set timeout to 0, to avoid possible race-condition */ 499598467938dd8bcdcd4d88e9102c609f4caa9d9efAlan Cox timeout = 0; 500485ae77dc7f484563707557ccf8c5d228980619fSven Anders wb_smsc_wdt_disable(); 501485ae77dc7f484563707557ccf8c5d228980619fSven Anders } 502485ae77dc7f484563707557ccf8c5d228980619fSven Anders return NOTIFY_DONE; 503485ae77dc7f484563707557ccf8c5d228980619fSven Anders} 504485ae77dc7f484563707557ccf8c5d228980619fSven Anders 505485ae77dc7f484563707557ccf8c5d228980619fSven Anders/* -- Module's structures ---------------------------------------*/ 506485ae77dc7f484563707557ccf8c5d228980619fSven Anders 507598467938dd8bcdcd4d88e9102c609f4caa9d9efAlan Coxstatic const struct file_operations wb_smsc_wdt_fops = { 508598467938dd8bcdcd4d88e9102c609f4caa9d9efAlan Cox .owner = THIS_MODULE, 509485ae77dc7f484563707557ccf8c5d228980619fSven Anders .llseek = no_llseek, 510485ae77dc7f484563707557ccf8c5d228980619fSven Anders .write = wb_smsc_wdt_write, 511598467938dd8bcdcd4d88e9102c609f4caa9d9efAlan Cox .unlocked_ioctl = wb_smsc_wdt_ioctl, 512485ae77dc7f484563707557ccf8c5d228980619fSven Anders .open = wb_smsc_wdt_open, 513aa1fd4d7c3b131026bf156da40fdf94bcbd705aaWim Van Sebroeck .release = wb_smsc_wdt_release, 514485ae77dc7f484563707557ccf8c5d228980619fSven Anders}; 515485ae77dc7f484563707557ccf8c5d228980619fSven Anders 516598467938dd8bcdcd4d88e9102c609f4caa9d9efAlan Coxstatic struct notifier_block wb_smsc_wdt_notifier = { 517aa1fd4d7c3b131026bf156da40fdf94bcbd705aaWim Van Sebroeck .notifier_call = wb_smsc_wdt_notify_sys, 518485ae77dc7f484563707557ccf8c5d228980619fSven Anders}; 519485ae77dc7f484563707557ccf8c5d228980619fSven Anders 520598467938dd8bcdcd4d88e9102c609f4caa9d9efAlan Coxstatic struct miscdevice wb_smsc_wdt_miscdev = { 521485ae77dc7f484563707557ccf8c5d228980619fSven Anders .minor = WATCHDOG_MINOR, 522485ae77dc7f484563707557ccf8c5d228980619fSven Anders .name = "watchdog", 523485ae77dc7f484563707557ccf8c5d228980619fSven Anders .fops = &wb_smsc_wdt_fops, 524485ae77dc7f484563707557ccf8c5d228980619fSven Anders}; 525485ae77dc7f484563707557ccf8c5d228980619fSven Anders 526485ae77dc7f484563707557ccf8c5d228980619fSven Anders/* -- Module init functions -------------------------------------*/ 527485ae77dc7f484563707557ccf8c5d228980619fSven Anders 528485ae77dc7f484563707557ccf8c5d228980619fSven Anders/* module's "constructor" */ 529485ae77dc7f484563707557ccf8c5d228980619fSven Anders 530485ae77dc7f484563707557ccf8c5d228980619fSven Andersstatic int __init wb_smsc_wdt_init(void) 531485ae77dc7f484563707557ccf8c5d228980619fSven Anders{ 532485ae77dc7f484563707557ccf8c5d228980619fSven Anders int ret; 533485ae77dc7f484563707557ccf8c5d228980619fSven Anders 53427c766aaacb265d625dc634bf7903f7f9fd0c697Joe Perches pr_info("SMsC 37B787 watchdog component driver " 53527c766aaacb265d625dc634bf7903f7f9fd0c697Joe Perches VERSION " initialising...\n"); 536485ae77dc7f484563707557ccf8c5d228980619fSven Anders 537485ae77dc7f484563707557ccf8c5d228980619fSven Anders if (!request_region(IOPORT, IOPORT_SIZE, "SMsC 37B787 watchdog")) { 53827c766aaacb265d625dc634bf7903f7f9fd0c697Joe Perches pr_err("Unable to register IO port %#x\n", IOPORT); 539485ae77dc7f484563707557ccf8c5d228980619fSven Anders ret = -EBUSY; 540485ae77dc7f484563707557ccf8c5d228980619fSven Anders goto out_pnp; 541485ae77dc7f484563707557ccf8c5d228980619fSven Anders } 542485ae77dc7f484563707557ccf8c5d228980619fSven Anders 543598467938dd8bcdcd4d88e9102c609f4caa9d9efAlan Cox /* set new maximum, if it's too big */ 544598467938dd8bcdcd4d88e9102c609f4caa9d9efAlan Cox if (timeout > MAX_TIMEOUT) 545598467938dd8bcdcd4d88e9102c609f4caa9d9efAlan Cox timeout = MAX_TIMEOUT; 546aa1fd4d7c3b131026bf156da40fdf94bcbd705aaWim Van Sebroeck 547598467938dd8bcdcd4d88e9102c609f4caa9d9efAlan Cox /* init the watchdog timer */ 548598467938dd8bcdcd4d88e9102c609f4caa9d9efAlan Cox wb_smsc_wdt_initialize(); 549aa1fd4d7c3b131026bf156da40fdf94bcbd705aaWim Van Sebroeck 550485ae77dc7f484563707557ccf8c5d228980619fSven Anders ret = register_reboot_notifier(&wb_smsc_wdt_notifier); 551485ae77dc7f484563707557ccf8c5d228980619fSven Anders if (ret) { 55227c766aaacb265d625dc634bf7903f7f9fd0c697Joe Perches pr_err("Unable to register reboot notifier err = %d\n", ret); 553485ae77dc7f484563707557ccf8c5d228980619fSven Anders goto out_io; 554485ae77dc7f484563707557ccf8c5d228980619fSven Anders } 555485ae77dc7f484563707557ccf8c5d228980619fSven Anders 556485ae77dc7f484563707557ccf8c5d228980619fSven Anders ret = misc_register(&wb_smsc_wdt_miscdev); 557485ae77dc7f484563707557ccf8c5d228980619fSven Anders if (ret) { 55827c766aaacb265d625dc634bf7903f7f9fd0c697Joe Perches pr_err("Unable to register miscdev on minor %d\n", 55927c766aaacb265d625dc634bf7903f7f9fd0c697Joe Perches WATCHDOG_MINOR); 560485ae77dc7f484563707557ccf8c5d228980619fSven Anders goto out_rbt; 561485ae77dc7f484563707557ccf8c5d228980619fSven Anders } 562485ae77dc7f484563707557ccf8c5d228980619fSven Anders 563598467938dd8bcdcd4d88e9102c609f4caa9d9efAlan Cox /* output info */ 56427c766aaacb265d625dc634bf7903f7f9fd0c697Joe Perches pr_info("Timeout set to %d %s\n", 565598467938dd8bcdcd4d88e9102c609f4caa9d9efAlan Cox timeout, (unit == UNIT_SECOND) ? "second(s)" : "minute(s)"); 56627c766aaacb265d625dc634bf7903f7f9fd0c697Joe Perches pr_info("Watchdog initialized and sleeping (nowayout=%d)...\n", 56727c766aaacb265d625dc634bf7903f7f9fd0c697Joe Perches nowayout); 568485ae77dc7f484563707557ccf8c5d228980619fSven Andersout_clean: 569485ae77dc7f484563707557ccf8c5d228980619fSven Anders return ret; 570485ae77dc7f484563707557ccf8c5d228980619fSven Anders 571485ae77dc7f484563707557ccf8c5d228980619fSven Andersout_rbt: 572485ae77dc7f484563707557ccf8c5d228980619fSven Anders unregister_reboot_notifier(&wb_smsc_wdt_notifier); 573485ae77dc7f484563707557ccf8c5d228980619fSven Anders 574485ae77dc7f484563707557ccf8c5d228980619fSven Andersout_io: 575485ae77dc7f484563707557ccf8c5d228980619fSven Anders release_region(IOPORT, IOPORT_SIZE); 576485ae77dc7f484563707557ccf8c5d228980619fSven Anders 577485ae77dc7f484563707557ccf8c5d228980619fSven Andersout_pnp: 578485ae77dc7f484563707557ccf8c5d228980619fSven Anders goto out_clean; 5798386c8cfb2131b2a9caae3db6bf94292bbbe1cafWim Van Sebroeck} 580485ae77dc7f484563707557ccf8c5d228980619fSven Anders 581485ae77dc7f484563707557ccf8c5d228980619fSven Anders/* module's "destructor" */ 582485ae77dc7f484563707557ccf8c5d228980619fSven Anders 583485ae77dc7f484563707557ccf8c5d228980619fSven Andersstatic void __exit wb_smsc_wdt_exit(void) 584485ae77dc7f484563707557ccf8c5d228980619fSven Anders{ 585485ae77dc7f484563707557ccf8c5d228980619fSven Anders /* Stop the timer before we leave */ 586598467938dd8bcdcd4d88e9102c609f4caa9d9efAlan Cox if (!nowayout) { 587485ae77dc7f484563707557ccf8c5d228980619fSven Anders wb_smsc_wdt_shutdown(); 58827c766aaacb265d625dc634bf7903f7f9fd0c697Joe Perches pr_info("Watchdog disabled\n"); 589485ae77dc7f484563707557ccf8c5d228980619fSven Anders } 590485ae77dc7f484563707557ccf8c5d228980619fSven Anders 591485ae77dc7f484563707557ccf8c5d228980619fSven Anders misc_deregister(&wb_smsc_wdt_miscdev); 592485ae77dc7f484563707557ccf8c5d228980619fSven Anders unregister_reboot_notifier(&wb_smsc_wdt_notifier); 593485ae77dc7f484563707557ccf8c5d228980619fSven Anders release_region(IOPORT, IOPORT_SIZE); 594485ae77dc7f484563707557ccf8c5d228980619fSven Anders 59527c766aaacb265d625dc634bf7903f7f9fd0c697Joe Perches pr_info("SMsC 37B787 watchdog component driver removed\n"); 596485ae77dc7f484563707557ccf8c5d228980619fSven Anders} 597485ae77dc7f484563707557ccf8c5d228980619fSven Anders 598485ae77dc7f484563707557ccf8c5d228980619fSven Andersmodule_init(wb_smsc_wdt_init); 599485ae77dc7f484563707557ccf8c5d228980619fSven Andersmodule_exit(wb_smsc_wdt_exit); 600485ae77dc7f484563707557ccf8c5d228980619fSven Anders 601485ae77dc7f484563707557ccf8c5d228980619fSven AndersMODULE_AUTHOR("Sven Anders <anders@anduras.de>"); 602598467938dd8bcdcd4d88e9102c609f4caa9d9efAlan CoxMODULE_DESCRIPTION("Driver for SMsC 37B787 watchdog component (Version " 603598467938dd8bcdcd4d88e9102c609f4caa9d9efAlan Cox VERSION ")"); 604485ae77dc7f484563707557ccf8c5d228980619fSven AndersMODULE_LICENSE("GPL"); 605485ae77dc7f484563707557ccf8c5d228980619fSven Anders 606485ae77dc7f484563707557ccf8c5d228980619fSven AndersMODULE_ALIAS_MISCDEV(WATCHDOG_MINOR); 607485ae77dc7f484563707557ccf8c5d228980619fSven Anders 608485ae77dc7f484563707557ccf8c5d228980619fSven Anders#ifdef SMSC_SUPPORT_MINUTES 609485ae77dc7f484563707557ccf8c5d228980619fSven Andersmodule_param(unit, int, 0); 610598467938dd8bcdcd4d88e9102c609f4caa9d9efAlan CoxMODULE_PARM_DESC(unit, 611598467938dd8bcdcd4d88e9102c609f4caa9d9efAlan Cox "set unit to use, 0=seconds or 1=minutes, default is 0"); 612485ae77dc7f484563707557ccf8c5d228980619fSven Anders#endif 613485ae77dc7f484563707557ccf8c5d228980619fSven Anders 614aa1fd4d7c3b131026bf156da40fdf94bcbd705aaWim Van Sebroeckmodule_param(timeout, int, 0); 615485ae77dc7f484563707557ccf8c5d228980619fSven AndersMODULE_PARM_DESC(timeout, "range is 1-255 units, default is 60"); 616485ae77dc7f484563707557ccf8c5d228980619fSven Anders 61786a1e1896c2710402e29a875d8d830244274244dWim Van Sebroeckmodule_param(nowayout, bool, 0); 618598467938dd8bcdcd4d88e9102c609f4caa9d9efAlan CoxMODULE_PARM_DESC(nowayout, 619598467938dd8bcdcd4d88e9102c609f4caa9d9efAlan Cox "Watchdog cannot be stopped once started (default=" 620598467938dd8bcdcd4d88e9102c609f4caa9d9efAlan Cox __MODULE_STRING(WATCHDOG_NOWAYOUT) ")"); 621