1/* 2 * Wdt977 0.02: A Watchdog Device for Netwinder W83977AF chip 3 * 4 * (c) Copyright 1998 Rebel.com (Woody Suwalski <woody@netwinder.org>) 5 * 6 * ----------------------- 7 * 8 * This program is free software; you can redistribute it and/or 9 * modify it under the terms of the GNU General Public License 10 * as published by the Free Software Foundation; either version 11 * 2 of the License, or (at your option) any later version. 12 * 13 * ----------------------- 14 * 14-Dec-2001 Matt Domsch <Matt_Domsch@dell.com> 15 * Added nowayout module option to override CONFIG_WATCHDOG_NOWAYOUT 16 */ 17 18#include <linux/module.h> 19#include <linux/config.h> 20#include <linux/types.h> 21#include <linux/kernel.h> 22#include <linux/fs.h> 23#include <linux/miscdevice.h> 24#include <linux/init.h> 25#include <linux/smp_lock.h> 26 27#include <asm/io.h> 28#include <asm/system.h> 29#include <asm/mach-types.h> 30 31#define WATCHDOG_MINOR 130 32 33static int timeout = 3; 34static int timer_alive; 35static int testmode; 36static int expect_close = 0; 37 38#ifdef CONFIG_WATCHDOG_NOWAYOUT 39static int nowayout = 1; 40#else 41static int nowayout = 0; 42#endif 43 44MODULE_PARM(nowayout,"i"); 45MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default=CONFIG_WATCHDOG_NOWAYOUT)"); 46 47 48/* 49 * Allow only one person to hold it open 50 */ 51 52static int wdt977_open(struct inode *inode, struct file *file) 53{ 54 if(timer_alive) 55 return -EBUSY; 56 if (nowayout) { 57 MOD_INC_USE_COUNT; 58 } 59 timer_alive++; 60 61 //max timeout value = 255 minutes (0xFF). Write 0 to disable WatchDog. 62 if (timeout>255) 63 timeout = 255; 64 65 printk(KERN_INFO "Watchdog: active, current timeout %d min.\n",timeout); 66 67 // unlock the SuperIO chip 68 outb(0x87,0x370); 69 outb(0x87,0x370); 70 71 //select device Aux2 (device=8) and set watchdog regs F2, F3 and F4 72 //F2 has the timeout in minutes 73 //F3 could be set to the POWER LED blink (with GP17 set to PowerLed) 74 // at timeout, and to reset timer on kbd/mouse activity (not now) 75 //F4 is used to just clear the TIMEOUT'ed state (bit 0) 76 77 outb(0x07,0x370); 78 outb(0x08,0x371); 79 outb(0xF2,0x370); 80 outb(timeout,0x371); 81 outb(0xF3,0x370); 82 outb(0x00,0x371); //another setting is 0E for kbd/mouse/LED 83 outb(0xF4,0x370); 84 outb(0x00,0x371); 85 86 //at last select device Aux1 (dev=7) and set GP16 as a watchdog output 87 if (!testmode) 88 { 89 outb(0x07,0x370); 90 outb(0x07,0x371); 91 outb(0xE6,0x370); 92 outb(0x08,0x371); 93 } 94 95 // lock the SuperIO chip 96 outb(0xAA,0x370); 97 98 return 0; 99} 100 101static int wdt977_release(struct inode *inode, struct file *file) 102{ 103 /* 104 * Shut off the timer. 105 * Lock it in if it's a module and we set nowayout 106 */ 107 lock_kernel(); 108 if (expect_close) { 109 110 // unlock the SuperIO chip 111 outb(0x87,0x370); 112 outb(0x87,0x370); 113 114 //select device Aux2 (device=8) and set watchdog regs F2,F3 and F4 115 //F3 is reset to its default state 116 //F4 can clear the TIMEOUT'ed state (bit 0) - back to default 117 //We can not use GP17 as a PowerLed, as we use its usage as a RedLed 118 119 outb(0x07,0x370); 120 outb(0x08,0x371); 121 outb(0xF2,0x370); 122 outb(0xFF,0x371); 123 outb(0xF3,0x370); 124 outb(0x00,0x371); 125 outb(0xF4,0x370); 126 outb(0x00,0x371); 127 outb(0xF2,0x370); 128 outb(0x00,0x371); 129 130 //at last select device Aux1 (dev=7) and set GP16 as a watchdog output 131 outb(0x07,0x370); 132 outb(0x07,0x371); 133 outb(0xE6,0x370); 134 outb(0x08,0x371); 135 136 // lock the SuperIO chip 137 outb(0xAA,0x370); 138 printk(KERN_INFO "Watchdog: shutdown.\n"); 139 } else { 140 printk(KERN_CRIT "WDT device closed unexpectedly. WDT will not stop!\n"); 141 } 142 143 timer_alive=0; 144 unlock_kernel(); 145 146 return 0; 147} 148 149static ssize_t wdt977_write(struct file *file, const char *data, size_t len, loff_t *ppos) 150{ 151 if (!nowayout) { 152 size_t i; 153 154 /* In case it was set long ago */ 155 expect_close = 0; 156 157 for (i = 0; i != len; i++) { 158 char c; 159 if (get_user(c, data + i)) 160 return -EFAULT; 161 if (c == 'V') 162 expect_close = 1; 163 } 164 } 165 166 //max timeout value = 255 minutes (0xFF). Write 0 to disable WatchDog. 167 if (timeout>255) 168 timeout = 255; 169 170 /* 171 * Refresh the timer. 172 */ 173 174 //we have a hw bug somewhere, so each 977 minute is actually only 30sec 175 //as such limit the max timeout to half of max of 255 minutes... 176// if (timeout>126) 177// timeout = 126; 178 179 // unlock the SuperIO chip 180 outb(0x87,0x370); 181 outb(0x87,0x370); 182 183 //select device Aux2 (device=8) and kicks watchdog reg F2 184 //F2 has the timeout in minutes 185 186 outb(0x07,0x370); 187 outb(0x08,0x371); 188 outb(0xF2,0x370); 189 outb(timeout,0x371); 190 191 // lock the SuperIO chip 192 outb(0xAA,0x370); 193 194 return 1; 195} 196 197static struct file_operations wdt977_fops= 198{ 199 owner: THIS_MODULE, 200 write: wdt977_write, 201 open: wdt977_open, 202 release: wdt977_release, 203}; 204 205static struct miscdevice wdt977_miscdev= 206{ 207 WATCHDOG_MINOR, 208 "watchdog", 209 &wdt977_fops 210}; 211 212static int __init nwwatchdog_init(void) 213{ 214 if (!machine_is_netwinder()) 215 return -ENODEV; 216 217 misc_register(&wdt977_miscdev); 218 printk(KERN_INFO "NetWinder Watchdog sleeping.\n"); 219 return 0; 220} 221 222static void __exit nwwatchdog_exit(void) 223{ 224 misc_deregister(&wdt977_miscdev); 225} 226 227EXPORT_NO_SYMBOLS; 228 229module_init(nwwatchdog_init); 230module_exit(nwwatchdog_exit); 231 232MODULE_LICENSE("GPL"); 233