aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/char/watchdog/pcwd.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/char/watchdog/pcwd.c')
-rw-r--r--drivers/char/watchdog/pcwd.c450
1 files changed, 232 insertions, 218 deletions
diff --git a/drivers/char/watchdog/pcwd.c b/drivers/char/watchdog/pcwd.c
index 37c9e13ad3ac..8d6b249ad66b 100644
--- a/drivers/char/watchdog/pcwd.c
+++ b/drivers/char/watchdog/pcwd.c
@@ -49,29 +49,37 @@
49 * More info available at http://www.berkprod.com/ or http://www.pcwatchdog.com/ 49 * More info available at http://www.berkprod.com/ or http://www.pcwatchdog.com/
50 */ 50 */
51 51
52#include <linux/module.h> 52#include <linux/config.h> /* For CONFIG_WATCHDOG_NOWAYOUT/... */
53#include <linux/moduleparam.h> 53#include <linux/module.h> /* For module specific items */
54#include <linux/types.h> 54#include <linux/moduleparam.h> /* For new moduleparam's */
55#include <linux/timer.h> 55#include <linux/types.h> /* For standard types (like size_t) */
56#include <linux/jiffies.h> 56#include <linux/errno.h> /* For the -ENODEV/... values */
57#include <linux/config.h> 57#include <linux/kernel.h> /* For printk/panic/... */
58#include <linux/wait.h> 58#include <linux/delay.h> /* For mdelay function */
59#include <linux/slab.h> 59#include <linux/timer.h> /* For timer related operations */
60#include <linux/ioport.h> 60#include <linux/jiffies.h> /* For jiffies stuff */
61#include <linux/delay.h> 61#include <linux/miscdevice.h> /* For MODULE_ALIAS_MISCDEV(WATCHDOG_MINOR) */
62#include <linux/fs.h> 62#include <linux/watchdog.h> /* For the watchdog specific items */
63#include <linux/miscdevice.h> 63#include <linux/notifier.h> /* For notifier support */
64#include <linux/watchdog.h> 64#include <linux/reboot.h> /* For reboot_notifier stuff */
65#include <linux/notifier.h> 65#include <linux/init.h> /* For __init/__exit/... */
66#include <linux/init.h> 66#include <linux/fs.h> /* For file operations */
67#include <linux/spinlock.h> 67#include <linux/ioport.h> /* For io-port access */
68#include <linux/reboot.h> 68#include <linux/spinlock.h> /* For spin_lock/spin_unlock/... */
69#include <linux/sched.h> /* TASK_INTERRUPTIBLE, set_current_state() and friends */ 69#include <linux/sched.h> /* TASK_INTERRUPTIBLE, set_current_state() and friends */
70#include <asm/uaccess.h> 70#include <linux/slab.h> /* For kmalloc */
71#include <asm/io.h>
72 71
73#define WD_VER "1.16 (06/12/2004)" 72#include <asm/uaccess.h> /* For copy_to_user/put_user/... */
74#define PFX "pcwd: " 73#include <asm/io.h> /* For inb/outb/... */
74
75/* Module and version information */
76#define WATCHDOG_VERSION "1.16"
77#define WATCHDOG_DATE "03 Jan 2006"
78#define WATCHDOG_DRIVER_NAME "ISA-PC Watchdog"
79#define WATCHDOG_NAME "pcwd"
80#define PFX WATCHDOG_NAME ": "
81#define DRIVER_VERSION WATCHDOG_DRIVER_NAME " driver, v" WATCHDOG_VERSION " (" WATCHDOG_DATE ")\n"
82#define WD_VER WATCHDOG_VERSION " (" WATCHDOG_DATE ")"
75 83
76/* 84/*
77 * It should be noted that PCWD_REVISION_B was removed because A and B 85 * It should be noted that PCWD_REVISION_B was removed because A and B
@@ -85,36 +93,38 @@
85 93
86/* 94/*
87 * These are the defines that describe the control status bits for the 95 * These are the defines that describe the control status bits for the
88 * PC Watchdog card, revision A. 96 * PCI-PC Watchdog card.
89 */ 97*/
98/* Port 1 : Control Status #1 for the PC Watchdog card, revision A. */
90#define WD_WDRST 0x01 /* Previously reset state */ 99#define WD_WDRST 0x01 /* Previously reset state */
91#define WD_T110 0x02 /* Temperature overheat sense */ 100#define WD_T110 0x02 /* Temperature overheat sense */
92#define WD_HRTBT 0x04 /* Heartbeat sense */ 101#define WD_HRTBT 0x04 /* Heartbeat sense */
93#define WD_RLY2 0x08 /* External relay triggered */ 102#define WD_RLY2 0x08 /* External relay triggered */
94#define WD_SRLY2 0x80 /* Software external relay triggered */ 103#define WD_SRLY2 0x80 /* Software external relay triggered */
95 104/* Port 1 : Control Status #1 for the PC Watchdog card, revision C. */
96/*
97 * These are the defines that describe the control status bits for the
98 * PC Watchdog card, revision C.
99 */
100#define WD_REVC_WTRP 0x01 /* Watchdog Trip status */ 105#define WD_REVC_WTRP 0x01 /* Watchdog Trip status */
101#define WD_REVC_HRBT 0x02 /* Watchdog Heartbeat */ 106#define WD_REVC_HRBT 0x02 /* Watchdog Heartbeat */
102#define WD_REVC_TTRP 0x04 /* Temperature Trip status */ 107#define WD_REVC_TTRP 0x04 /* Temperature Trip status */
108/* Port 2 : Control Status #2 */
109#define WD_WDIS 0x10 /* Watchdog Disabled */
110#define WD_ENTP 0x20 /* Watchdog Enable Temperature Trip */
111#define WD_SSEL 0x40 /* Watchdog Switch Select (1:SW1 <-> 0:SW2) */
112#define WD_WCMD 0x80 /* Watchdog Command Mode */
103 113
104/* max. time we give an ISA watchdog card to process a command */ 114/* max. time we give an ISA watchdog card to process a command */
105/* 500ms for each 4 bit response (according to spec.) */ 115/* 500ms for each 4 bit response (according to spec.) */
106#define ISA_COMMAND_TIMEOUT 1000 116#define ISA_COMMAND_TIMEOUT 1000
107 117
108/* Watchdog's internal commands */ 118/* Watchdog's internal commands */
109#define CMD_ISA_IDLE 0x00 119#define CMD_ISA_IDLE 0x00
110#define CMD_ISA_VERSION_INTEGER 0x01 120#define CMD_ISA_VERSION_INTEGER 0x01
111#define CMD_ISA_VERSION_TENTH 0x02 121#define CMD_ISA_VERSION_TENTH 0x02
112#define CMD_ISA_VERSION_HUNDRETH 0x03 122#define CMD_ISA_VERSION_HUNDRETH 0x03
113#define CMD_ISA_VERSION_MINOR 0x04 123#define CMD_ISA_VERSION_MINOR 0x04
114#define CMD_ISA_SWITCH_SETTINGS 0x05 124#define CMD_ISA_SWITCH_SETTINGS 0x05
115#define CMD_ISA_DELAY_TIME_2SECS 0x0A 125#define CMD_ISA_DELAY_TIME_2SECS 0x0A
116#define CMD_ISA_DELAY_TIME_4SECS 0x0B 126#define CMD_ISA_DELAY_TIME_4SECS 0x0B
117#define CMD_ISA_DELAY_TIME_8SECS 0x0C 127#define CMD_ISA_DELAY_TIME_8SECS 0x0C
118 128
119/* 129/*
120 * We are using an kernel timer to do the pinging of the watchdog 130 * We are using an kernel timer to do the pinging of the watchdog
@@ -130,15 +140,17 @@ static int cards_found;
130/* internal variables */ 140/* internal variables */
131static atomic_t open_allowed = ATOMIC_INIT(1); 141static atomic_t open_allowed = ATOMIC_INIT(1);
132static char expect_close; 142static char expect_close;
133static struct timer_list timer;
134static unsigned long next_heartbeat;
135static int temp_panic; 143static int temp_panic;
136static int revision; /* The card's revision */ 144static struct { /* this is private data for each ISA-PC watchdog card */
137static int supports_temp; /* Wether or not the card has a temperature device */ 145 int revision; /* The card's revision */
138static int command_mode; /* Wether or not the card is in command mode */ 146 int supports_temp; /* Wether or not the card has a temperature device */
139static int initial_status; /* The card's boot status */ 147 int command_mode; /* Wether or not the card is in command mode */
140static int current_readport; /* The cards I/O address */ 148 int boot_status; /* The card's boot status */
141static spinlock_t io_lock; 149 int io_addr; /* The cards I/O address */
150 spinlock_t io_lock; /* the lock for io operations */
151 struct timer_list timer; /* The timer that pings the watchdog */
152 unsigned long next_heartbeat; /* the next_heartbeat for the timer */
153} pcwd_private;
142 154
143/* module parameters */ 155/* module parameters */
144#define WATCHDOG_HEARTBEAT 60 /* 60 sec default heartbeat */ 156#define WATCHDOG_HEARTBEAT 60 /* 60 sec default heartbeat */
@@ -161,14 +173,14 @@ static int send_isa_command(int cmd)
161 int port0, last_port0; /* Double read for stabilising */ 173 int port0, last_port0; /* Double read for stabilising */
162 174
163 /* The WCMD bit must be 1 and the command is only 4 bits in size */ 175 /* The WCMD bit must be 1 and the command is only 4 bits in size */
164 control_status = (cmd & 0x0F) | 0x80; 176 control_status = (cmd & 0x0F) | WD_WCMD;
165 outb_p(control_status, current_readport + 2); 177 outb_p(control_status, pcwd_private.io_addr + 2);
166 udelay(ISA_COMMAND_TIMEOUT); 178 udelay(ISA_COMMAND_TIMEOUT);
167 179
168 port0 = inb_p(current_readport); 180 port0 = inb_p(pcwd_private.io_addr);
169 for (i = 0; i < 25; ++i) { 181 for (i = 0; i < 25; ++i) {
170 last_port0 = port0; 182 last_port0 = port0;
171 port0 = inb_p(current_readport); 183 port0 = inb_p(pcwd_private.io_addr);
172 184
173 if (port0 == last_port0) 185 if (port0 == last_port0)
174 break; /* Data is stable */ 186 break; /* Data is stable */
@@ -184,7 +196,7 @@ static int set_command_mode(void)
184 int i, found=0, count=0; 196 int i, found=0, count=0;
185 197
186 /* Set the card into command mode */ 198 /* Set the card into command mode */
187 spin_lock(&io_lock); 199 spin_lock(&pcwd_private.io_lock);
188 while ((!found) && (count < 3)) { 200 while ((!found) && (count < 3)) {
189 i = send_isa_command(CMD_ISA_IDLE); 201 i = send_isa_command(CMD_ISA_IDLE);
190 202
@@ -192,15 +204,15 @@ static int set_command_mode(void)
192 found = 1; 204 found = 1;
193 else if (i == 0xF3) { 205 else if (i == 0xF3) {
194 /* Card does not like what we've done to it */ 206 /* Card does not like what we've done to it */
195 outb_p(0x00, current_readport + 2); 207 outb_p(0x00, pcwd_private.io_addr + 2);
196 udelay(1200); /* Spec says wait 1ms */ 208 udelay(1200); /* Spec says wait 1ms */
197 outb_p(0x00, current_readport + 2); 209 outb_p(0x00, pcwd_private.io_addr + 2);
198 udelay(ISA_COMMAND_TIMEOUT); 210 udelay(ISA_COMMAND_TIMEOUT);
199 } 211 }
200 count++; 212 count++;
201 } 213 }
202 spin_unlock(&io_lock); 214 spin_unlock(&pcwd_private.io_lock);
203 command_mode = found; 215 pcwd_private.command_mode = found;
204 216
205 return(found); 217 return(found);
206} 218}
@@ -208,12 +220,95 @@ static int set_command_mode(void)
208static void unset_command_mode(void) 220static void unset_command_mode(void)
209{ 221{
210 /* Set the card into normal mode */ 222 /* Set the card into normal mode */
211 spin_lock(&io_lock); 223 spin_lock(&pcwd_private.io_lock);
212 outb_p(0x00, current_readport + 2); 224 outb_p(0x00, pcwd_private.io_addr + 2);
213 udelay(ISA_COMMAND_TIMEOUT); 225 udelay(ISA_COMMAND_TIMEOUT);
214 spin_unlock(&io_lock); 226 spin_unlock(&pcwd_private.io_lock);
227
228 pcwd_private.command_mode = 0;
229}
230
231static inline void pcwd_check_temperature_support(void)
232{
233 if (inb(pcwd_private.io_addr) != 0xF0)
234 pcwd_private.supports_temp = 1;
235}
236
237static inline char *get_firmware(void)
238{
239 int one, ten, hund, minor;
240 char *ret;
241
242 ret = kmalloc(6, GFP_KERNEL);
243 if(ret == NULL)
244 return NULL;
245
246 if (set_command_mode()) {
247 one = send_isa_command(CMD_ISA_VERSION_INTEGER);
248 ten = send_isa_command(CMD_ISA_VERSION_TENTH);
249 hund = send_isa_command(CMD_ISA_VERSION_HUNDRETH);
250 minor = send_isa_command(CMD_ISA_VERSION_MINOR);
251 sprintf(ret, "%c.%c%c%c", one, ten, hund, minor);
252 }
253 else
254 sprintf(ret, "ERROR");
255
256 unset_command_mode();
257 return(ret);
258}
259
260static inline int pcwd_get_option_switches(void)
261{
262 int option_switches=0;
263
264 if (set_command_mode()) {
265 /* Get switch settings */
266 option_switches = send_isa_command(CMD_ISA_SWITCH_SETTINGS);
267 }
268
269 unset_command_mode();
270 return(option_switches);
271}
272
273static void pcwd_show_card_info(void)
274{
275 char *firmware;
276 int option_switches;
277
278 /* Get some extra info from the hardware (in command/debug/diag mode) */
279 if (pcwd_private.revision == PCWD_REVISION_A)
280 printk(KERN_INFO PFX "ISA-PC Watchdog (REV.A) detected at port 0x%04x\n", pcwd_private.io_addr);
281 else if (pcwd_private.revision == PCWD_REVISION_C) {
282 firmware = get_firmware();
283 printk(KERN_INFO PFX "ISA-PC Watchdog (REV.C) detected at port 0x%04x (Firmware version: %s)\n",
284 pcwd_private.io_addr, firmware);
285 kfree(firmware);
286 option_switches = pcwd_get_option_switches();
287 printk(KERN_INFO PFX "Option switches (0x%02x): Temperature Reset Enable=%s, Power On Delay=%s\n",
288 option_switches,
289 ((option_switches & 0x10) ? "ON" : "OFF"),
290 ((option_switches & 0x08) ? "ON" : "OFF"));
291
292 /* Reprogram internal heartbeat to 2 seconds */
293 if (set_command_mode()) {
294 send_isa_command(CMD_ISA_DELAY_TIME_2SECS);
295 unset_command_mode();
296 }
297 }
298
299 if (pcwd_private.supports_temp)
300 printk(KERN_INFO PFX "Temperature Option Detected\n");
301
302 if (pcwd_private.boot_status & WDIOF_CARDRESET)
303 printk(KERN_INFO PFX "Previous reboot was caused by the card\n");
304
305 if (pcwd_private.boot_status & WDIOF_OVERHEAT) {
306 printk(KERN_EMERG PFX "Card senses a CPU Overheat. Panicking!\n");
307 printk(KERN_EMERG PFX "CPU Overheat\n");
308 }
215 309
216 command_mode = 0; 310 if (pcwd_private.boot_status == 0)
311 printk(KERN_INFO PFX "No previous trip detected - Cold boot or reset\n");
217} 312}
218 313
219static void pcwd_timer_ping(unsigned long data) 314static void pcwd_timer_ping(unsigned long data)
@@ -222,25 +317,25 @@ static void pcwd_timer_ping(unsigned long data)
222 317
223 /* If we got a heartbeat pulse within the WDT_INTERVAL 318 /* If we got a heartbeat pulse within the WDT_INTERVAL
224 * we agree to ping the WDT */ 319 * we agree to ping the WDT */
225 if(time_before(jiffies, next_heartbeat)) { 320 if(time_before(jiffies, pcwd_private.next_heartbeat)) {
226 /* Ping the watchdog */ 321 /* Ping the watchdog */
227 spin_lock(&io_lock); 322 spin_lock(&pcwd_private.io_lock);
228 if (revision == PCWD_REVISION_A) { 323 if (pcwd_private.revision == PCWD_REVISION_A) {
229 /* Rev A cards are reset by setting the WD_WDRST bit in register 1 */ 324 /* Rev A cards are reset by setting the WD_WDRST bit in register 1 */
230 wdrst_stat = inb_p(current_readport); 325 wdrst_stat = inb_p(pcwd_private.io_addr);
231 wdrst_stat &= 0x0F; 326 wdrst_stat &= 0x0F;
232 wdrst_stat |= WD_WDRST; 327 wdrst_stat |= WD_WDRST;
233 328
234 outb_p(wdrst_stat, current_readport + 1); 329 outb_p(wdrst_stat, pcwd_private.io_addr + 1);
235 } else { 330 } else {
236 /* Re-trigger watchdog by writing to port 0 */ 331 /* Re-trigger watchdog by writing to port 0 */
237 outb_p(0x00, current_readport); 332 outb_p(0x00, pcwd_private.io_addr);
238 } 333 }
239 334
240 /* Re-set the timer interval */ 335 /* Re-set the timer interval */
241 mod_timer(&timer, jiffies + WDT_INTERVAL); 336 mod_timer(&pcwd_private.timer, jiffies + WDT_INTERVAL);
242 337
243 spin_unlock(&io_lock); 338 spin_unlock(&pcwd_private.io_lock);
244 } else { 339 } else {
245 printk(KERN_WARNING PFX "Heartbeat lost! Will not ping the watchdog\n"); 340 printk(KERN_WARNING PFX "Heartbeat lost! Will not ping the watchdog\n");
246 } 341 }
@@ -250,19 +345,19 @@ static int pcwd_start(void)
250{ 345{
251 int stat_reg; 346 int stat_reg;
252 347
253 next_heartbeat = jiffies + (heartbeat * HZ); 348 pcwd_private.next_heartbeat = jiffies + (heartbeat * HZ);
254 349
255 /* Start the timer */ 350 /* Start the timer */
256 mod_timer(&timer, jiffies + WDT_INTERVAL); 351 mod_timer(&pcwd_private.timer, jiffies + WDT_INTERVAL);
257 352
258 /* Enable the port */ 353 /* Enable the port */
259 if (revision == PCWD_REVISION_C) { 354 if (pcwd_private.revision == PCWD_REVISION_C) {
260 spin_lock(&io_lock); 355 spin_lock(&pcwd_private.io_lock);
261 outb_p(0x00, current_readport + 3); 356 outb_p(0x00, pcwd_private.io_addr + 3);
262 udelay(ISA_COMMAND_TIMEOUT); 357 udelay(ISA_COMMAND_TIMEOUT);
263 stat_reg = inb_p(current_readport + 2); 358 stat_reg = inb_p(pcwd_private.io_addr + 2);
264 spin_unlock(&io_lock); 359 spin_unlock(&pcwd_private.io_lock);
265 if (stat_reg & 0x10) { 360 if (stat_reg & WD_WDIS) {
266 printk(KERN_INFO PFX "Could not start watchdog\n"); 361 printk(KERN_INFO PFX "Could not start watchdog\n");
267 return -EIO; 362 return -EIO;
268 } 363 }
@@ -275,18 +370,18 @@ static int pcwd_stop(void)
275 int stat_reg; 370 int stat_reg;
276 371
277 /* Stop the timer */ 372 /* Stop the timer */
278 del_timer(&timer); 373 del_timer(&pcwd_private.timer);
279 374
280 /* Disable the board */ 375 /* Disable the board */
281 if (revision == PCWD_REVISION_C) { 376 if (pcwd_private.revision == PCWD_REVISION_C) {
282 spin_lock(&io_lock); 377 spin_lock(&pcwd_private.io_lock);
283 outb_p(0xA5, current_readport + 3); 378 outb_p(0xA5, pcwd_private.io_addr + 3);
284 udelay(ISA_COMMAND_TIMEOUT); 379 udelay(ISA_COMMAND_TIMEOUT);
285 outb_p(0xA5, current_readport + 3); 380 outb_p(0xA5, pcwd_private.io_addr + 3);
286 udelay(ISA_COMMAND_TIMEOUT); 381 udelay(ISA_COMMAND_TIMEOUT);
287 stat_reg = inb_p(current_readport + 2); 382 stat_reg = inb_p(pcwd_private.io_addr + 2);
288 spin_unlock(&io_lock); 383 spin_unlock(&pcwd_private.io_lock);
289 if ((stat_reg & 0x10) == 0) { 384 if ((stat_reg & WD_WDIS) == 0) {
290 printk(KERN_INFO PFX "Could not stop watchdog\n"); 385 printk(KERN_INFO PFX "Could not stop watchdog\n");
291 return -EIO; 386 return -EIO;
292 } 387 }
@@ -297,7 +392,7 @@ static int pcwd_stop(void)
297static int pcwd_keepalive(void) 392static int pcwd_keepalive(void)
298{ 393{
299 /* user land ping */ 394 /* user land ping */
300 next_heartbeat = jiffies + (heartbeat * HZ); 395 pcwd_private.next_heartbeat = jiffies + (heartbeat * HZ);
301 return 0; 396 return 0;
302} 397}
303 398
@@ -315,23 +410,23 @@ static int pcwd_get_status(int *status)
315 int card_status; 410 int card_status;
316 411
317 *status=0; 412 *status=0;
318 spin_lock(&io_lock); 413 spin_lock(&pcwd_private.io_lock);
319 if (revision == PCWD_REVISION_A) 414 if (pcwd_private.revision == PCWD_REVISION_A)
320 /* Rev A cards return status information from 415 /* Rev A cards return status information from
321 * the base register, which is used for the 416 * the base register, which is used for the
322 * temperature in other cards. */ 417 * temperature in other cards. */
323 card_status = inb(current_readport); 418 card_status = inb(pcwd_private.io_addr);
324 else { 419 else {
325 /* Rev C cards return card status in the base 420 /* Rev C cards return card status in the base
326 * address + 1 register. And use different bits 421 * address + 1 register. And use different bits
327 * to indicate a card initiated reset, and an 422 * to indicate a card initiated reset, and an
328 * over-temperature condition. And the reboot 423 * over-temperature condition. And the reboot
329 * status can be reset. */ 424 * status can be reset. */
330 card_status = inb(current_readport + 1); 425 card_status = inb(pcwd_private.io_addr + 1);
331 } 426 }
332 spin_unlock(&io_lock); 427 spin_unlock(&pcwd_private.io_lock);
333 428
334 if (revision == PCWD_REVISION_A) { 429 if (pcwd_private.revision == PCWD_REVISION_A) {
335 if (card_status & WD_WDRST) 430 if (card_status & WD_WDRST)
336 *status |= WDIOF_CARDRESET; 431 *status |= WDIOF_CARDRESET;
337 432
@@ -360,10 +455,10 @@ static int pcwd_get_status(int *status)
360 455
361static int pcwd_clear_status(void) 456static int pcwd_clear_status(void)
362{ 457{
363 if (revision == PCWD_REVISION_C) { 458 if (pcwd_private.revision == PCWD_REVISION_C) {
364 spin_lock(&io_lock); 459 spin_lock(&pcwd_private.io_lock);
365 outb_p(0x00, current_readport + 1); /* clear reset status */ 460 outb_p(0x00, pcwd_private.io_addr + 1); /* clear reset status */
366 spin_unlock(&io_lock); 461 spin_unlock(&pcwd_private.io_lock);
367 } 462 }
368 return 0; 463 return 0;
369} 464}
@@ -371,20 +466,20 @@ static int pcwd_clear_status(void)
371static int pcwd_get_temperature(int *temperature) 466static int pcwd_get_temperature(int *temperature)
372{ 467{
373 /* check that port 0 gives temperature info and no command results */ 468 /* check that port 0 gives temperature info and no command results */
374 if (command_mode) 469 if (pcwd_private.command_mode)
375 return -1; 470 return -1;
376 471
377 *temperature = 0; 472 *temperature = 0;
378 if (!supports_temp) 473 if (!pcwd_private.supports_temp)
379 return -ENODEV; 474 return -ENODEV;
380 475
381 /* 476 /*
382 * Convert celsius to fahrenheit, since this was 477 * Convert celsius to fahrenheit, since this was
383 * the decided 'standard' for this return value. 478 * the decided 'standard' for this return value.
384 */ 479 */
385 spin_lock(&io_lock); 480 spin_lock(&pcwd_private.io_lock);
386 *temperature = ((inb(current_readport)) * 9 / 5) + 32; 481 *temperature = ((inb(pcwd_private.io_addr)) * 9 / 5) + 32;
387 spin_unlock(&io_lock); 482 spin_unlock(&pcwd_private.io_lock);
388 483
389 return 0; 484 return 0;
390} 485}
@@ -425,7 +520,7 @@ static int pcwd_ioctl(struct inode *inode, struct file *file,
425 return put_user(status, argp); 520 return put_user(status, argp);
426 521
427 case WDIOC_GETBOOTSTATUS: 522 case WDIOC_GETBOOTSTATUS:
428 return put_user(initial_status, argp); 523 return put_user(pcwd_private.boot_status, argp);
429 524
430 case WDIOC_GETTEMP: 525 case WDIOC_GETTEMP:
431 if (pcwd_get_temperature(&temperature)) 526 if (pcwd_get_temperature(&temperature))
@@ -434,7 +529,7 @@ static int pcwd_ioctl(struct inode *inode, struct file *file,
434 return put_user(temperature, argp); 529 return put_user(temperature, argp);
435 530
436 case WDIOC_SETOPTIONS: 531 case WDIOC_SETOPTIONS:
437 if (revision == PCWD_REVISION_C) 532 if (pcwd_private.revision == PCWD_REVISION_C)
438 { 533 {
439 if(copy_from_user(&rv, argp, sizeof(int))) 534 if(copy_from_user(&rv, argp, sizeof(int)))
440 return -EFAULT; 535 return -EFAULT;
@@ -550,7 +645,7 @@ static ssize_t pcwd_temp_read(struct file *file, char __user *buf, size_t count,
550 645
551static int pcwd_temp_open(struct inode *inode, struct file *file) 646static int pcwd_temp_open(struct inode *inode, struct file *file)
552{ 647{
553 if (!supports_temp) 648 if (!pcwd_private.supports_temp)
554 return -ENODEV; 649 return -ENODEV;
555 650
556 return nonseekable_open(inode, file); 651 return nonseekable_open(inode, file);
@@ -616,68 +711,24 @@ static struct notifier_block pcwd_notifier = {
616 * Init & exit routines 711 * Init & exit routines
617 */ 712 */
618 713
619static inline void get_support(void)
620{
621 if (inb(current_readport) != 0xF0)
622 supports_temp = 1;
623}
624
625static inline int get_revision(void) 714static inline int get_revision(void)
626{ 715{
627 int r = PCWD_REVISION_C; 716 int r = PCWD_REVISION_C;
628 717
629 spin_lock(&io_lock); 718 spin_lock(&pcwd_private.io_lock);
630 /* REV A cards use only 2 io ports; test 719 /* REV A cards use only 2 io ports; test
631 * presumes a floating bus reads as 0xff. */ 720 * presumes a floating bus reads as 0xff. */
632 if ((inb(current_readport + 2) == 0xFF) || 721 if ((inb(pcwd_private.io_addr + 2) == 0xFF) ||
633 (inb(current_readport + 3) == 0xFF)) 722 (inb(pcwd_private.io_addr + 3) == 0xFF))
634 r=PCWD_REVISION_A; 723 r=PCWD_REVISION_A;
635 spin_unlock(&io_lock); 724 spin_unlock(&pcwd_private.io_lock);
636 725
637 return r; 726 return r;
638} 727}
639 728
640static inline char *get_firmware(void)
641{
642 int one, ten, hund, minor;
643 char *ret;
644
645 ret = kmalloc(6, GFP_KERNEL);
646 if(ret == NULL)
647 return NULL;
648
649 if (set_command_mode()) {
650 one = send_isa_command(CMD_ISA_VERSION_INTEGER);
651 ten = send_isa_command(CMD_ISA_VERSION_TENTH);
652 hund = send_isa_command(CMD_ISA_VERSION_HUNDRETH);
653 minor = send_isa_command(CMD_ISA_VERSION_MINOR);
654 sprintf(ret, "%c.%c%c%c", one, ten, hund, minor);
655 }
656 else
657 sprintf(ret, "ERROR");
658
659 unset_command_mode();
660 return(ret);
661}
662
663static inline int get_option_switches(void)
664{
665 int rv=0;
666
667 if (set_command_mode()) {
668 /* Get switch settings */
669 rv = send_isa_command(CMD_ISA_SWITCH_SETTINGS);
670 }
671
672 unset_command_mode();
673 return(rv);
674}
675
676static int __devinit pcwatchdog_init(int base_addr) 729static int __devinit pcwatchdog_init(int base_addr)
677{ 730{
678 int ret; 731 int ret;
679 char *firmware;
680 int option_switches;
681 732
682 cards_found++; 733 cards_found++;
683 if (cards_found == 1) 734 if (cards_found == 1)
@@ -692,104 +743,66 @@ static int __devinit pcwatchdog_init(int base_addr)
692 printk(KERN_ERR PFX "No I/O-Address for card detected\n"); 743 printk(KERN_ERR PFX "No I/O-Address for card detected\n");
693 return -ENODEV; 744 return -ENODEV;
694 } 745 }
695 current_readport = base_addr; 746 pcwd_private.io_addr = base_addr;
696 747
697 /* Check card's revision */ 748 /* Check card's revision */
698 revision = get_revision(); 749 pcwd_private.revision = get_revision();
699 750
700 if (!request_region(current_readport, (revision == PCWD_REVISION_A) ? 2 : 4, "PCWD")) { 751 if (!request_region(pcwd_private.io_addr, (pcwd_private.revision == PCWD_REVISION_A) ? 2 : 4, "PCWD")) {
701 printk(KERN_ERR PFX "I/O address 0x%04x already in use\n", 752 printk(KERN_ERR PFX "I/O address 0x%04x already in use\n",
702 current_readport); 753 pcwd_private.io_addr);
703 current_readport = 0x0000; 754 pcwd_private.io_addr = 0x0000;
704 return -EIO; 755 return -EIO;
705 } 756 }
706 757
707 /* Initial variables */ 758 /* Initial variables */
708 supports_temp = 0; 759 pcwd_private.supports_temp = 0;
709 temp_panic = 0; 760 temp_panic = 0;
710 initial_status = 0x0000; 761 pcwd_private.boot_status = 0x0000;
711 762
712 /* get the boot_status */ 763 /* get the boot_status */
713 pcwd_get_status(&initial_status); 764 pcwd_get_status(&pcwd_private.boot_status);
714 765
715 /* clear the "card caused reboot" flag */ 766 /* clear the "card caused reboot" flag */
716 pcwd_clear_status(); 767 pcwd_clear_status();
717 768
718 init_timer(&timer); 769 init_timer(&pcwd_private.timer);
719 timer.function = pcwd_timer_ping; 770 pcwd_private.timer.function = pcwd_timer_ping;
720 timer.data = 0; 771 pcwd_private.timer.data = 0;
721 772
722 /* Disable the board */ 773 /* Disable the board */
723 pcwd_stop(); 774 pcwd_stop();
724 775
725 /* Check whether or not the card supports the temperature device */ 776 /* Check whether or not the card supports the temperature device */
726 get_support(); 777 pcwd_check_temperature_support();
727
728 /* Get some extra info from the hardware (in command/debug/diag mode) */
729 if (revision == PCWD_REVISION_A)
730 printk(KERN_INFO PFX "ISA-PC Watchdog (REV.A) detected at port 0x%04x\n", current_readport);
731 else if (revision == PCWD_REVISION_C) {
732 firmware = get_firmware();
733 printk(KERN_INFO PFX "ISA-PC Watchdog (REV.C) detected at port 0x%04x (Firmware version: %s)\n",
734 current_readport, firmware);
735 kfree(firmware);
736 option_switches = get_option_switches();
737 printk(KERN_INFO PFX "Option switches (0x%02x): Temperature Reset Enable=%s, Power On Delay=%s\n",
738 option_switches,
739 ((option_switches & 0x10) ? "ON" : "OFF"),
740 ((option_switches & 0x08) ? "ON" : "OFF"));
741
742 /* Reprogram internal heartbeat to 2 seconds */
743 if (set_command_mode()) {
744 send_isa_command(CMD_ISA_DELAY_TIME_2SECS);
745 unset_command_mode();
746 }
747 } else {
748 /* Should NEVER happen, unless get_revision() fails. */
749 printk(KERN_INFO PFX "Unable to get revision\n");
750 release_region(current_readport, (revision == PCWD_REVISION_A) ? 2 : 4);
751 current_readport = 0x0000;
752 return -1;
753 }
754 778
755 if (supports_temp) 779 /* Show info about the card itself */
756 printk(KERN_INFO PFX "Temperature Option Detected\n"); 780 pcwd_show_card_info();
757
758 if (initial_status & WDIOF_CARDRESET)
759 printk(KERN_INFO PFX "Previous reboot was caused by the card\n");
760
761 if (initial_status & WDIOF_OVERHEAT) {
762 printk(KERN_EMERG PFX "Card senses a CPU Overheat. Panicking!\n");
763 printk(KERN_EMERG PFX "CPU Overheat\n");
764 }
765
766 if (initial_status == 0)
767 printk(KERN_INFO PFX "No previous trip detected - Cold boot or reset\n");
768 781
769 /* Check that the heartbeat value is within it's range ; if not reset to the default */ 782 /* Check that the heartbeat value is within it's range ; if not reset to the default */
770 if (pcwd_set_heartbeat(heartbeat)) { 783 if (pcwd_set_heartbeat(heartbeat)) {
771 pcwd_set_heartbeat(WATCHDOG_HEARTBEAT); 784 pcwd_set_heartbeat(WATCHDOG_HEARTBEAT);
772 printk(KERN_INFO PFX "heartbeat value must be 2<=heartbeat<=7200, using %d\n", 785 printk(KERN_INFO PFX "heartbeat value must be 2<=heartbeat<=7200, using %d\n",
773 WATCHDOG_HEARTBEAT); 786 WATCHDOG_HEARTBEAT);
774 } 787 }
775 788
776 ret = register_reboot_notifier(&pcwd_notifier); 789 ret = register_reboot_notifier(&pcwd_notifier);
777 if (ret) { 790 if (ret) {
778 printk(KERN_ERR PFX "cannot register reboot notifier (err=%d)\n", 791 printk(KERN_ERR PFX "cannot register reboot notifier (err=%d)\n",
779 ret); 792 ret);
780 release_region(current_readport, (revision == PCWD_REVISION_A) ? 2 : 4); 793 release_region(pcwd_private.io_addr, (pcwd_private.revision == PCWD_REVISION_A) ? 2 : 4);
781 current_readport = 0x0000; 794 pcwd_private.io_addr = 0x0000;
782 return ret; 795 return ret;
783 } 796 }
784 797
785 if (supports_temp) { 798 if (pcwd_private.supports_temp) {
786 ret = misc_register(&temp_miscdev); 799 ret = misc_register(&temp_miscdev);
787 if (ret) { 800 if (ret) {
788 printk(KERN_ERR PFX "cannot register miscdev on minor=%d (err=%d)\n", 801 printk(KERN_ERR PFX "cannot register miscdev on minor=%d (err=%d)\n",
789 TEMP_MINOR, ret); 802 TEMP_MINOR, ret);
790 unregister_reboot_notifier(&pcwd_notifier); 803 unregister_reboot_notifier(&pcwd_notifier);
791 release_region(current_readport, (revision == PCWD_REVISION_A) ? 2 : 4); 804 release_region(pcwd_private.io_addr, (pcwd_private.revision == PCWD_REVISION_A) ? 2 : 4);
792 current_readport = 0x0000; 805 pcwd_private.io_addr = 0x0000;
793 return ret; 806 return ret;
794 } 807 }
795 } 808 }
@@ -798,11 +811,11 @@ static int __devinit pcwatchdog_init(int base_addr)
798 if (ret) { 811 if (ret) {
799 printk(KERN_ERR PFX "cannot register miscdev on minor=%d (err=%d)\n", 812 printk(KERN_ERR PFX "cannot register miscdev on minor=%d (err=%d)\n",
800 WATCHDOG_MINOR, ret); 813 WATCHDOG_MINOR, ret);
801 if (supports_temp) 814 if (pcwd_private.supports_temp)
802 misc_deregister(&temp_miscdev); 815 misc_deregister(&temp_miscdev);
803 unregister_reboot_notifier(&pcwd_notifier); 816 unregister_reboot_notifier(&pcwd_notifier);
804 release_region(current_readport, (revision == PCWD_REVISION_A) ? 2 : 4); 817 release_region(pcwd_private.io_addr, (pcwd_private.revision == PCWD_REVISION_A) ? 2 : 4);
805 current_readport = 0x0000; 818 pcwd_private.io_addr = 0x0000;
806 return ret; 819 return ret;
807 } 820 }
808 821
@@ -820,11 +833,12 @@ static void __devexit pcwatchdog_exit(void)
820 833
821 /* Deregister */ 834 /* Deregister */
822 misc_deregister(&pcwd_miscdev); 835 misc_deregister(&pcwd_miscdev);
823 if (supports_temp) 836 if (pcwd_private.supports_temp)
824 misc_deregister(&temp_miscdev); 837 misc_deregister(&temp_miscdev);
825 unregister_reboot_notifier(&pcwd_notifier); 838 unregister_reboot_notifier(&pcwd_notifier);
826 release_region(current_readport, (revision == PCWD_REVISION_A) ? 2 : 4); 839 release_region(pcwd_private.io_addr, (pcwd_private.revision == PCWD_REVISION_A) ? 2 : 4);
827 current_readport = 0x0000; 840 pcwd_private.io_addr = 0x0000;
841 cards_found--;
828} 842}
829 843
830/* 844/*
@@ -887,7 +901,7 @@ static int __init pcwd_init_module(void)
887{ 901{
888 int i, found = 0; 902 int i, found = 0;
889 903
890 spin_lock_init(&io_lock); 904 spin_lock_init(&pcwd_private.io_lock);
891 905
892 for (i = 0; pcwd_ioports[i] != 0; i++) { 906 for (i = 0; pcwd_ioports[i] != 0; i++) {
893 if (pcwd_checkcard(pcwd_ioports[i])) { 907 if (pcwd_checkcard(pcwd_ioports[i])) {
@@ -906,7 +920,7 @@ static int __init pcwd_init_module(void)
906 920
907static void __exit pcwd_cleanup_module(void) 921static void __exit pcwd_cleanup_module(void)
908{ 922{
909 if (current_readport) 923 if (pcwd_private.io_addr)
910 pcwatchdog_exit(); 924 pcwatchdog_exit();
911 return; 925 return;
912} 926}