Merge /pub/scm/linux/kernel/git/torvalds/linux-2.6
[linux-2.6] / drivers / char / watchdog / pcwd.c
1 /*
2  * PC Watchdog Driver
3  * by Ken Hollis (khollis@bitgate.com)
4  *
5  * Permission granted from Simon Machell (73244.1270@compuserve.com)
6  * Written for the Linux Kernel, and GPLed by Ken Hollis
7  *
8  * 960107       Added request_region routines, modulized the whole thing.
9  * 960108       Fixed end-of-file pointer (Thanks to Dan Hollis), added
10  *              WD_TIMEOUT define.
11  * 960216       Added eof marker on the file, and changed verbose messages.
12  * 960716       Made functional and cosmetic changes to the source for
13  *              inclusion in Linux 2.0.x kernels, thanks to Alan Cox.
14  * 960717       Removed read/seek routines, replaced with ioctl.  Also, added
15  *              check_region command due to Alan's suggestion.
16  * 960821       Made changes to compile in newer 2.0.x kernels.  Added
17  *              "cold reboot sense" entry.
18  * 960825       Made a few changes to code, deleted some defines and made
19  *              typedefs to replace them.  Made heartbeat reset only available
20  *              via ioctl, and removed the write routine.
21  * 960828       Added new items for PC Watchdog Rev.C card.
22  * 960829       Changed around all of the IOCTLs, added new features,
23  *              added watchdog disable/re-enable routines.  Added firmware
24  *              version reporting.  Added read routine for temperature.
25  *              Removed some extra defines, added an autodetect Revision
26  *              routine.
27  * 961006       Revised some documentation, fixed some cosmetic bugs.  Made
28  *              drivers to panic the system if it's overheating at bootup.
29  * 961118       Changed some verbiage on some of the output, tidied up
30  *              code bits, and added compatibility to 2.1.x.
31  * 970912       Enabled board on open and disable on close.
32  * 971107       Took account of recent VFS changes (broke read).
33  * 971210       Disable board on initialisation in case board already ticking.
34  * 971222       Changed open/close for temperature handling
35  *              Michael Meskes <meskes@debian.org>.
36  * 980112       Used minor numbers from include/linux/miscdevice.h
37  * 990403       Clear reset status after reading control status register in
38  *              pcwd_showprevstate(). [Marc Boucher <marc@mbsi.ca>]
39  * 990605       Made changes to code to support Firmware 1.22a, added
40  *              fairly useless proc entry.
41  * 990610       removed said useless proc code for the merge <alan>
42  * 000403       Removed last traces of proc code. <davej>
43  * 011214       Added nowayout module option to override CONFIG_WATCHDOG_NOWAYOUT <Matt_Domsch@dell.com>
44  *              Added timeout module option to override default
45  */
46
47 /*
48  *      A bells and whistles driver is available from http://www.pcwd.de/
49  *      More info available at http://www.berkprod.com/ or http://www.pcwatchdog.com/
50  */
51
52 #include <linux/module.h>
53 #include <linux/moduleparam.h>
54 #include <linux/types.h>
55 #include <linux/timer.h>
56 #include <linux/jiffies.h>
57 #include <linux/config.h>
58 #include <linux/wait.h>
59 #include <linux/slab.h>
60 #include <linux/ioport.h>
61 #include <linux/delay.h>
62 #include <linux/fs.h>
63 #include <linux/miscdevice.h>
64 #include <linux/watchdog.h>
65 #include <linux/notifier.h>
66 #include <linux/init.h>
67 #include <linux/spinlock.h>
68 #include <linux/reboot.h>
69
70 #include <asm/uaccess.h>
71 #include <asm/io.h>
72
73 #define WD_VER                  "1.16 (06/12/2004)"
74 #define PFX                     "pcwd: "
75
76 /*
77  * It should be noted that PCWD_REVISION_B was removed because A and B
78  * are essentially the same types of card, with the exception that B
79  * has temperature reporting.  Since I didn't receive a Rev.B card,
80  * the Rev.B card is not supported.  (It's a good thing too, as they
81  * are no longer in production.)
82  */
83 #define PCWD_REVISION_A         1
84 #define PCWD_REVISION_C         2
85
86 /*
87  * These are the defines that describe the control status bits for the
88  * PC Watchdog card, revision A.
89  */
90 #define WD_WDRST                0x01    /* Previously reset state */
91 #define WD_T110                 0x02    /* Temperature overheat sense */
92 #define WD_HRTBT                0x04    /* Heartbeat sense */
93 #define WD_RLY2                 0x08    /* External relay triggered */
94 #define WD_SRLY2                0x80    /* Software external relay triggered */
95
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 */
101 #define WD_REVC_HRBT            0x02    /* Watchdog Heartbeat */
102 #define WD_REVC_TTRP            0x04    /* Temperature Trip status */
103
104 /* max. time we give an ISA watchdog card to process a command */
105 /* 500ms for each 4 bit response (according to spec.) */
106 #define ISA_COMMAND_TIMEOUT     1000
107
108 /* Watchdog's internal commands */
109 #define CMD_ISA_IDLE                    0x00
110 #define CMD_ISA_VERSION_INTEGER         0x01
111 #define CMD_ISA_VERSION_TENTH           0x02
112 #define CMD_ISA_VERSION_HUNDRETH        0x03
113 #define CMD_ISA_VERSION_MINOR           0x04
114 #define CMD_ISA_SWITCH_SETTINGS         0x05
115 #define CMD_ISA_DELAY_TIME_2SECS        0x0A
116 #define CMD_ISA_DELAY_TIME_4SECS        0x0B
117 #define CMD_ISA_DELAY_TIME_8SECS        0x0C
118
119 /*
120  * We are using an kernel timer to do the pinging of the watchdog
121  * every ~500ms. We try to set the internal heartbeat of the
122  * watchdog to 2 ms.
123  */
124
125 #define WDT_INTERVAL (HZ/2+1)
126
127 /* We can only use 1 card due to the /dev/watchdog restriction */
128 static int cards_found;
129
130 /* internal variables */
131 static atomic_t open_allowed = ATOMIC_INIT(1);
132 static char expect_close;
133 static struct timer_list timer;
134 static unsigned long next_heartbeat;
135 static int temp_panic;
136 static int revision;                    /* The card's revision */
137 static int supports_temp;               /* Wether or not the card has a temperature device */
138 static int command_mode;                /* Wether or not the card is in command mode */
139 static int initial_status;              /* The card's boot status */
140 static int current_readport;            /* The cards I/O address */
141 static spinlock_t io_lock;
142
143 /* module parameters */
144 #define WATCHDOG_HEARTBEAT 60           /* 60 sec default heartbeat */
145 static int heartbeat = WATCHDOG_HEARTBEAT;
146 module_param(heartbeat, int, 0);
147 MODULE_PARM_DESC(heartbeat, "Watchdog heartbeat in seconds. (2<=heartbeat<=7200, default=" __MODULE_STRING(WATCHDOG_HEARTBEAT) ")");
148
149 static int nowayout = WATCHDOG_NOWAYOUT;
150 module_param(nowayout, int, 0);
151 MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default=CONFIG_WATCHDOG_NOWAYOUT)");
152
153 /*
154  *      Internal functions
155  */
156
157 static int send_isa_command(int cmd)
158 {
159         int i;
160         int control_status;
161         int port0, last_port0;  /* Double read for stabilising */
162
163         /* The WCMD bit must be 1 and the command is only 4 bits in size */
164         control_status = (cmd & 0x0F) | 0x80;
165         outb_p(control_status, current_readport + 2);
166         udelay(ISA_COMMAND_TIMEOUT);
167
168         port0 = inb_p(current_readport);
169         for (i = 0; i < 25; ++i) {
170                 last_port0 = port0;
171                 port0 = inb_p(current_readport);
172
173                 if (port0 == last_port0)
174                         break;  /* Data is stable */
175
176                 udelay (250);
177         }
178
179         return port0;
180 }
181
182 static int set_command_mode(void)
183 {
184         int i, found=0, count=0;
185
186         /* Set the card into command mode */
187         spin_lock(&io_lock);
188         while ((!found) && (count < 3)) {
189                 i = send_isa_command(CMD_ISA_IDLE);
190
191                 if (i == 0x00)
192                         found = 1;
193                 else if (i == 0xF3) {
194                         /* Card does not like what we've done to it */
195                         outb_p(0x00, current_readport + 2);
196                         udelay(1200);   /* Spec says wait 1ms */
197                         outb_p(0x00, current_readport + 2);
198                         udelay(ISA_COMMAND_TIMEOUT);
199                 }
200                 count++;
201         }
202         spin_unlock(&io_lock);
203         command_mode = found;
204
205         return(found);
206 }
207
208 static void unset_command_mode(void)
209 {
210         /* Set the card into normal mode */
211         spin_lock(&io_lock);
212         outb_p(0x00, current_readport + 2);
213         udelay(ISA_COMMAND_TIMEOUT);
214         spin_unlock(&io_lock);
215
216         command_mode = 0;
217 }
218
219 static void pcwd_timer_ping(unsigned long data)
220 {
221         int wdrst_stat;
222
223         /* If we got a heartbeat pulse within the WDT_INTERVAL
224          * we agree to ping the WDT */
225         if(time_before(jiffies, next_heartbeat)) {
226                 /* Ping the watchdog */
227                 spin_lock(&io_lock);
228                 if (revision == PCWD_REVISION_A) {
229                         /*  Rev A cards are reset by setting the WD_WDRST bit in register 1 */
230                         wdrst_stat = inb_p(current_readport);
231                         wdrst_stat &= 0x0F;
232                         wdrst_stat |= WD_WDRST;
233
234                         outb_p(wdrst_stat, current_readport + 1);
235                 } else {
236                         /* Re-trigger watchdog by writing to port 0 */
237                         outb_p(0x00, current_readport);
238                 }
239
240                 /* Re-set the timer interval */
241                 mod_timer(&timer, jiffies + WDT_INTERVAL);
242
243                 spin_unlock(&io_lock);
244         } else {
245                 printk(KERN_WARNING PFX "Heartbeat lost! Will not ping the watchdog\n");
246         }
247 }
248
249 static int pcwd_start(void)
250 {
251         int stat_reg;
252
253         next_heartbeat = jiffies + (heartbeat * HZ);
254
255         /* Start the timer */
256         mod_timer(&timer, jiffies + WDT_INTERVAL);
257
258         /* Enable the port */
259         if (revision == PCWD_REVISION_C) {
260                 spin_lock(&io_lock);
261                 outb_p(0x00, current_readport + 3);
262                 udelay(ISA_COMMAND_TIMEOUT);
263                 stat_reg = inb_p(current_readport + 2);
264                 spin_unlock(&io_lock);
265                 if (stat_reg & 0x10) {
266                         printk(KERN_INFO PFX "Could not start watchdog\n");
267                         return -EIO;
268                 }
269         }
270         return 0;
271 }
272
273 static int pcwd_stop(void)
274 {
275         int stat_reg;
276
277         /* Stop the timer */
278         del_timer(&timer);
279
280         /*  Disable the board  */
281         if (revision == PCWD_REVISION_C) {
282                 spin_lock(&io_lock);
283                 outb_p(0xA5, current_readport + 3);
284                 udelay(ISA_COMMAND_TIMEOUT);
285                 outb_p(0xA5, current_readport + 3);
286                 udelay(ISA_COMMAND_TIMEOUT);
287                 stat_reg = inb_p(current_readport + 2);
288                 spin_unlock(&io_lock);
289                 if ((stat_reg & 0x10) == 0) {
290                         printk(KERN_INFO PFX "Could not stop watchdog\n");
291                         return -EIO;
292                 }
293         }
294         return 0;
295 }
296
297 static int pcwd_keepalive(void)
298 {
299         /* user land ping */
300         next_heartbeat = jiffies + (heartbeat * HZ);
301         return 0;
302 }
303
304 static int pcwd_set_heartbeat(int t)
305 {
306         if ((t < 2) || (t > 7200)) /* arbitrary upper limit */
307                 return -EINVAL;
308
309         heartbeat = t;
310         return 0;
311 }
312
313 static int pcwd_get_status(int *status)
314 {
315         int card_status;
316
317         *status=0;
318         spin_lock(&io_lock);
319         if (revision == PCWD_REVISION_A)
320                 /* Rev A cards return status information from
321                  * the base register, which is used for the
322                  * temperature in other cards. */
323                 card_status = inb(current_readport);
324         else {
325                 /* Rev C cards return card status in the base
326                  * address + 1 register. And use different bits
327                  * to indicate a card initiated reset, and an
328                  * over-temperature condition. And the reboot
329                  * status can be reset. */
330                 card_status = inb(current_readport + 1);
331         }
332         spin_unlock(&io_lock);
333
334         if (revision == PCWD_REVISION_A) {
335                 if (card_status & WD_WDRST)
336                         *status |= WDIOF_CARDRESET;
337
338                 if (card_status & WD_T110) {
339                         *status |= WDIOF_OVERHEAT;
340                         if (temp_panic) {
341                                 printk (KERN_INFO PFX "Temperature overheat trip!\n");
342                                 kernel_power_off();
343                         }
344                 }
345         } else {
346                 if (card_status & WD_REVC_WTRP)
347                         *status |= WDIOF_CARDRESET;
348
349                 if (card_status & WD_REVC_TTRP) {
350                         *status |= WDIOF_OVERHEAT;
351                         if (temp_panic) {
352                                 printk (KERN_INFO PFX "Temperature overheat trip!\n");
353                                 kernel_power_off();
354                         }
355                 }
356         }
357
358         return 0;
359 }
360
361 static int pcwd_clear_status(void)
362 {
363         if (revision == PCWD_REVISION_C) {
364                 spin_lock(&io_lock);
365                 outb_p(0x00, current_readport + 1); /* clear reset status */
366                 spin_unlock(&io_lock);
367         }
368         return 0;
369 }
370
371 static int pcwd_get_temperature(int *temperature)
372 {
373         /* check that port 0 gives temperature info and no command results */
374         if (command_mode)
375                 return -1;
376
377         *temperature = 0;
378         if (!supports_temp)
379                 return -ENODEV;
380
381         /*
382          * Convert celsius to fahrenheit, since this was
383          * the decided 'standard' for this return value.
384          */
385         spin_lock(&io_lock);
386         *temperature = ((inb(current_readport)) * 9 / 5) + 32;
387         spin_unlock(&io_lock);
388
389         return 0;
390 }
391
392 /*
393  *      /dev/watchdog handling
394  */
395
396 static int pcwd_ioctl(struct inode *inode, struct file *file,
397                       unsigned int cmd, unsigned long arg)
398 {
399         int rv;
400         int status;
401         int temperature;
402         int new_heartbeat;
403         int __user *argp = (int __user *)arg;
404         static struct watchdog_info ident = {
405                 .options =              WDIOF_OVERHEAT |
406                                         WDIOF_CARDRESET |
407                                         WDIOF_KEEPALIVEPING |
408                                         WDIOF_SETTIMEOUT |
409                                         WDIOF_MAGICCLOSE,
410                 .firmware_version =     1,
411                 .identity =             "PCWD",
412         };
413
414         switch(cmd) {
415         default:
416                 return -ENOIOCTLCMD;
417
418         case WDIOC_GETSUPPORT:
419                 if(copy_to_user(argp, &ident, sizeof(ident)))
420                         return -EFAULT;
421                 return 0;
422
423         case WDIOC_GETSTATUS:
424                 pcwd_get_status(&status);
425                 return put_user(status, argp);
426
427         case WDIOC_GETBOOTSTATUS:
428                 return put_user(initial_status, argp);
429
430         case WDIOC_GETTEMP:
431                 if (pcwd_get_temperature(&temperature))
432                         return -EFAULT;
433
434                 return put_user(temperature, argp);
435
436         case WDIOC_SETOPTIONS:
437                 if (revision == PCWD_REVISION_C)
438                 {
439                         if(copy_from_user(&rv, argp, sizeof(int)))
440                                 return -EFAULT;
441
442                         if (rv & WDIOS_DISABLECARD)
443                         {
444                                 return pcwd_stop();
445                         }
446
447                         if (rv & WDIOS_ENABLECARD)
448                         {
449                                 return pcwd_start();
450                         }
451
452                         if (rv & WDIOS_TEMPPANIC)
453                         {
454                                 temp_panic = 1;
455                         }
456                 }
457                 return -EINVAL;
458
459         case WDIOC_KEEPALIVE:
460                 pcwd_keepalive();
461                 return 0;
462
463         case WDIOC_SETTIMEOUT:
464                 if (get_user(new_heartbeat, argp))
465                         return -EFAULT;
466
467                 if (pcwd_set_heartbeat(new_heartbeat))
468                         return -EINVAL;
469
470                 pcwd_keepalive();
471                 /* Fall */
472
473         case WDIOC_GETTIMEOUT:
474                 return put_user(heartbeat, argp);
475         }
476
477         return 0;
478 }
479
480 static ssize_t pcwd_write(struct file *file, const char __user *buf, size_t len,
481                           loff_t *ppos)
482 {
483         if (len) {
484                 if (!nowayout) {
485                         size_t i;
486
487                         /* In case it was set long ago */
488                         expect_close = 0;
489
490                         for (i = 0; i != len; i++) {
491                                 char c;
492
493                                 if (get_user(c, buf + i))
494                                         return -EFAULT;
495                                 if (c == 'V')
496                                         expect_close = 42;
497                         }
498                 }
499                 pcwd_keepalive();
500         }
501         return len;
502 }
503
504 static int pcwd_open(struct inode *inode, struct file *file)
505 {
506         if (!atomic_dec_and_test(&open_allowed) ) {
507                 atomic_inc( &open_allowed );
508                 return -EBUSY;
509         }
510
511         if (nowayout)
512                 __module_get(THIS_MODULE);
513
514         /* Activate */
515         pcwd_start();
516         pcwd_keepalive();
517         return nonseekable_open(inode, file);
518 }
519
520 static int pcwd_close(struct inode *inode, struct file *file)
521 {
522         if (expect_close == 42) {
523                 pcwd_stop();
524         } else {
525                 printk(KERN_CRIT PFX "Unexpected close, not stopping watchdog!\n");
526                 pcwd_keepalive();
527         }
528         expect_close = 0;
529         atomic_inc( &open_allowed );
530         return 0;
531 }
532
533 /*
534  *      /dev/temperature handling
535  */
536
537 static ssize_t pcwd_temp_read(struct file *file, char __user *buf, size_t count,
538                          loff_t *ppos)
539 {
540         int temperature;
541
542         if (pcwd_get_temperature(&temperature))
543                 return -EFAULT;
544
545         if (copy_to_user(buf, &temperature, 1))
546                 return -EFAULT;
547
548         return 1;
549 }
550
551 static int pcwd_temp_open(struct inode *inode, struct file *file)
552 {
553         if (!supports_temp)
554                 return -ENODEV;
555
556         return nonseekable_open(inode, file);
557 }
558
559 static int pcwd_temp_close(struct inode *inode, struct file *file)
560 {
561         return 0;
562 }
563
564 /*
565  *      Notify system
566  */
567
568 static int pcwd_notify_sys(struct notifier_block *this, unsigned long code, void *unused)
569 {
570         if (code==SYS_DOWN || code==SYS_HALT) {
571                 /* Turn the WDT off */
572                 pcwd_stop();
573         }
574
575         return NOTIFY_DONE;
576 }
577
578 /*
579  *      Kernel Interfaces
580  */
581
582 static struct file_operations pcwd_fops = {
583         .owner          = THIS_MODULE,
584         .llseek         = no_llseek,
585         .write          = pcwd_write,
586         .ioctl          = pcwd_ioctl,
587         .open           = pcwd_open,
588         .release        = pcwd_close,
589 };
590
591 static struct miscdevice pcwd_miscdev = {
592         .minor =        WATCHDOG_MINOR,
593         .name =         "watchdog",
594         .fops =         &pcwd_fops,
595 };
596
597 static struct file_operations pcwd_temp_fops = {
598         .owner          = THIS_MODULE,
599         .llseek         = no_llseek,
600         .read           = pcwd_temp_read,
601         .open           = pcwd_temp_open,
602         .release        = pcwd_temp_close,
603 };
604
605 static struct miscdevice temp_miscdev = {
606         .minor =        TEMP_MINOR,
607         .name =         "temperature",
608         .fops =         &pcwd_temp_fops,
609 };
610
611 static struct notifier_block pcwd_notifier = {
612         .notifier_call =        pcwd_notify_sys,
613 };
614
615 /*
616  *      Init & exit routines
617  */
618
619 static inline void get_support(void)
620 {
621         if (inb(current_readport) != 0xF0)
622                 supports_temp = 1;
623 }
624
625 static inline int get_revision(void)
626 {
627         int r = PCWD_REVISION_C;
628
629         spin_lock(&io_lock);
630         /* REV A cards use only 2 io ports; test
631          * presumes a floating bus reads as 0xff. */
632         if ((inb(current_readport + 2) == 0xFF) ||
633             (inb(current_readport + 3) == 0xFF))
634                 r=PCWD_REVISION_A;
635         spin_unlock(&io_lock);
636
637         return r;
638 }
639
640 static 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
663 static 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
676 static int __devinit pcwatchdog_init(int base_addr)
677 {
678         int ret;
679         char *firmware;
680         int option_switches;
681
682         cards_found++;
683         if (cards_found == 1)
684                 printk(KERN_INFO PFX "v%s Ken Hollis (kenji@bitgate.com)\n", WD_VER);
685
686         if (cards_found > 1) {
687                 printk(KERN_ERR PFX "This driver only supports 1 device\n");
688                 return -ENODEV;
689         }
690
691         if (base_addr == 0x0000) {
692                 printk(KERN_ERR PFX "No I/O-Address for card detected\n");
693                 return -ENODEV;
694         }
695         current_readport = base_addr;
696
697         /* Check card's revision */
698         revision = get_revision();
699
700         if (!request_region(current_readport, (revision == PCWD_REVISION_A) ? 2 : 4, "PCWD")) {
701                 printk(KERN_ERR PFX "I/O address 0x%04x already in use\n",
702                         current_readport);
703                 current_readport = 0x0000;
704                 return -EIO;
705         }
706
707         /* Initial variables */
708         supports_temp = 0;
709         temp_panic = 0;
710         initial_status = 0x0000;
711
712         /* get the boot_status */
713         pcwd_get_status(&initial_status);
714
715         /* clear the "card caused reboot" flag */
716         pcwd_clear_status();
717
718         init_timer(&timer);
719         timer.function = pcwd_timer_ping;
720         timer.data = 0;
721
722         /*  Disable the board  */
723         pcwd_stop();
724
725         /*  Check whether or not the card supports the temperature device */
726         get_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
755         if (supports_temp)
756                 printk(KERN_INFO PFX "Temperature Option Detected\n");
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
769         /* Check that the heartbeat value is within it's range ; if not reset to the default */
770         if (pcwd_set_heartbeat(heartbeat)) {
771                 pcwd_set_heartbeat(WATCHDOG_HEARTBEAT);
772                 printk(KERN_INFO PFX "heartbeat value must be 2<=heartbeat<=7200, using %d\n",
773                         WATCHDOG_HEARTBEAT);
774         }
775
776         ret = register_reboot_notifier(&pcwd_notifier);
777         if (ret) {
778                 printk(KERN_ERR PFX "cannot register reboot notifier (err=%d)\n",
779                         ret);
780                 release_region(current_readport, (revision == PCWD_REVISION_A) ? 2 : 4);
781                 current_readport = 0x0000;
782                 return ret;
783         }
784
785         if (supports_temp) {
786                 ret = misc_register(&temp_miscdev);
787                 if (ret) {
788                         printk(KERN_ERR PFX "cannot register miscdev on minor=%d (err=%d)\n",
789                                 TEMP_MINOR, ret);
790                         unregister_reboot_notifier(&pcwd_notifier);
791                         release_region(current_readport, (revision == PCWD_REVISION_A) ? 2 : 4);
792                         current_readport = 0x0000;
793                         return ret;
794                 }
795         }
796
797         ret = misc_register(&pcwd_miscdev);
798         if (ret) {
799                 printk(KERN_ERR PFX "cannot register miscdev on minor=%d (err=%d)\n",
800                         WATCHDOG_MINOR, ret);
801                 if (supports_temp)
802                         misc_deregister(&temp_miscdev);
803                 unregister_reboot_notifier(&pcwd_notifier);
804                 release_region(current_readport, (revision == PCWD_REVISION_A) ? 2 : 4);
805                 current_readport = 0x0000;
806                 return ret;
807         }
808
809         printk(KERN_INFO PFX "initialized. heartbeat=%d sec (nowayout=%d)\n",
810                 heartbeat, nowayout);
811
812         return 0;
813 }
814
815 static void __devexit pcwatchdog_exit(void)
816 {
817         /*  Disable the board  */
818         if (!nowayout)
819                 pcwd_stop();
820
821         /* Deregister */
822         misc_deregister(&pcwd_miscdev);
823         if (supports_temp)
824                 misc_deregister(&temp_miscdev);
825         unregister_reboot_notifier(&pcwd_notifier);
826         release_region(current_readport, (revision == PCWD_REVISION_A) ? 2 : 4);
827         current_readport = 0x0000;
828 }
829
830 /*
831  *  The ISA cards have a heartbeat bit in one of the registers, which
832  *  register is card dependent.  The heartbeat bit is monitored, and if
833  *  found, is considered proof that a Berkshire card has been found.
834  *  The initial rate is once per second at board start up, then twice
835  *  per second for normal operation.
836  */
837 static int __init pcwd_checkcard(int base_addr)
838 {
839         int port0, last_port0;  /* Reg 0, in case it's REV A */
840         int port1, last_port1;  /* Register 1 for REV C cards */
841         int i;
842         int retval;
843
844         if (!request_region (base_addr, 4, "PCWD")) {
845                 printk (KERN_INFO PFX "Port 0x%04x unavailable\n", base_addr);
846                 return 0;
847         }
848
849         retval = 0;
850
851         port0 = inb_p(base_addr);       /* For REV A boards */
852         port1 = inb_p(base_addr + 1);   /* For REV C boards */
853         if (port0 != 0xff || port1 != 0xff) {
854                 /* Not an 'ff' from a floating bus, so must be a card! */
855                 for (i = 0; i < 4; ++i) {
856
857                         msleep(500);
858
859                         last_port0 = port0;
860                         last_port1 = port1;
861
862                         port0 = inb_p(base_addr);
863                         port1 = inb_p(base_addr + 1);
864
865                         /* Has either hearbeat bit changed?  */
866                         if ((port0 ^ last_port0) & WD_HRTBT ||
867                             (port1 ^ last_port1) & WD_REVC_HRBT) {
868                                 retval = 1;
869                                 break;
870                         }
871                 }
872         }
873         release_region (base_addr, 4);
874
875         return retval;
876 }
877
878 /*
879  * These are the auto-probe addresses available.
880  *
881  * Revision A only uses ports 0x270 and 0x370.  Revision C introduced 0x350.
882  * Revision A has an address range of 2 addresses, while Revision C has 4.
883  */
884 static int pcwd_ioports[] = { 0x270, 0x350, 0x370, 0x000 };
885
886 static int __init pcwd_init_module(void)
887 {
888         int i, found = 0;
889
890         spin_lock_init(&io_lock);
891
892         for (i = 0; pcwd_ioports[i] != 0; i++) {
893                 if (pcwd_checkcard(pcwd_ioports[i])) {
894                         if (!(pcwatchdog_init(pcwd_ioports[i])))
895                                 found++;
896                 }
897         }
898
899         if (!found) {
900                 printk (KERN_INFO PFX "No card detected, or port not available\n");
901                 return -ENODEV;
902         }
903
904         return 0;
905 }
906
907 static void __exit pcwd_cleanup_module(void)
908 {
909         if (current_readport)
910                 pcwatchdog_exit();
911         return;
912 }
913
914 module_init(pcwd_init_module);
915 module_exit(pcwd_cleanup_module);
916
917 MODULE_AUTHOR("Ken Hollis <kenji@bitgate.com>");
918 MODULE_DESCRIPTION("Berkshire ISA-PC Watchdog driver");
919 MODULE_LICENSE("GPL");
920 MODULE_ALIAS_MISCDEV(WATCHDOG_MINOR);
921 MODULE_ALIAS_MISCDEV(TEMP_MINOR);