ftp://ftp.kernel.org/pub/linux/kernel/v2.6/linux-2.6.6.tar.bz2
[linux-2.6.git] / 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 (03/27/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 #ifdef CONFIG_WATCHDOG_NOWAYOUT
150 static int nowayout = 1;
151 #else
152 static int nowayout = 0;
153 #endif
154
155 module_param(nowayout, int, 0);
156 MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default=CONFIG_WATCHDOG_NOWAYOUT)");
157
158 /*
159  *      Internal functions
160  */
161
162 static int send_isa_command(int cmd)
163 {
164         int i;
165         int control_status;
166         int port0, last_port0;  /* Double read for stabilising */
167
168         /* The WCMD bit must be 1 and the command is only 4 bits in size */
169         control_status = (cmd & 0x0F) | 0x80;
170         outb_p(control_status, current_readport + 2);
171         udelay(ISA_COMMAND_TIMEOUT);
172
173         port0 = inb_p(current_readport);
174         for (i = 0; i < 25; ++i) {
175                 last_port0 = port0;
176                 port0 = inb_p(current_readport);
177
178                 if (port0 == last_port0)
179                         break;  /* Data is stable */
180
181                 udelay (250);
182         }
183
184         return port0;
185 }
186
187 static int set_command_mode(void)
188 {
189         int i, found=0, count=0;
190
191         /* Set the card into command mode */
192         spin_lock(&io_lock);
193         while ((!found) && (count < 3)) {
194                 i = send_isa_command(CMD_ISA_IDLE);
195
196                 if (i == 0x00)
197                         found = 1;
198                 else if (i == 0xF3) {
199                         /* Card does not like what we've done to it */
200                         outb_p(0x00, current_readport + 2);
201                         udelay(1200);   /* Spec says wait 1ms */
202                         outb_p(0x00, current_readport + 2);
203                         udelay(ISA_COMMAND_TIMEOUT);
204                 }
205                 count++;
206         }
207         spin_unlock(&io_lock);
208         command_mode = found;
209
210         return(found);
211 }
212
213 static void unset_command_mode(void)
214 {
215         /* Set the card into normal mode */
216         spin_lock(&io_lock);
217         outb_p(0x00, current_readport + 2);
218         udelay(ISA_COMMAND_TIMEOUT);
219         spin_unlock(&io_lock);
220
221         command_mode = 0;
222 }
223
224 static void pcwd_timer_ping(unsigned long data)
225 {
226         int wdrst_stat;
227
228         /* If we got a heartbeat pulse within the WDT_INTERVAL
229          * we agree to ping the WDT */
230         if(time_before(jiffies, next_heartbeat)) {
231                 /* Ping the watchdog */
232                 spin_lock(&io_lock);
233                 if (revision == PCWD_REVISION_A) {
234                         /*  Rev A cards are reset by setting the WD_WDRST bit in register 1 */
235                         wdrst_stat = inb_p(current_readport);
236                         wdrst_stat &= 0x0F;
237                         wdrst_stat |= WD_WDRST;
238
239                         outb_p(wdrst_stat, current_readport + 1);
240                 } else {
241                         /* Re-trigger watchdog by writing to port 0 */
242                         outb_p(0x00, current_readport);
243                 }
244
245                 /* Re-set the timer interval */
246                 mod_timer(&timer, jiffies + WDT_INTERVAL);
247
248                 spin_unlock(&io_lock);
249         } else {
250                 printk(KERN_WARNING PFX "Heartbeat lost! Will not ping the watchdog\n");
251         }
252 }
253
254 static int pcwd_start(void)
255 {
256         int stat_reg;
257
258         next_heartbeat = jiffies + (heartbeat * HZ);
259
260         /* Start the timer */
261         mod_timer(&timer, jiffies + WDT_INTERVAL);
262
263         /* Enable the port */
264         if (revision == PCWD_REVISION_C) {
265                 spin_lock(&io_lock);
266                 outb_p(0x00, current_readport + 3);
267                 udelay(ISA_COMMAND_TIMEOUT);
268                 stat_reg = inb_p(current_readport + 2);
269                 spin_unlock(&io_lock);
270                 if (stat_reg & 0x10) {
271                         printk(KERN_INFO PFX "Could not start watchdog\n");
272                         return -EIO;
273                 }
274         }
275         return 0;
276 }
277
278 static int pcwd_stop(void)
279 {
280         int stat_reg;
281
282         /* Stop the timer */
283         del_timer(&timer);
284
285         /*  Disable the board  */
286         if (revision == PCWD_REVISION_C) {
287                 spin_lock(&io_lock);
288                 outb_p(0xA5, current_readport + 3);
289                 udelay(ISA_COMMAND_TIMEOUT);
290                 outb_p(0xA5, current_readport + 3);
291                 udelay(ISA_COMMAND_TIMEOUT);
292                 stat_reg = inb_p(current_readport + 2);
293                 spin_unlock(&io_lock);
294                 if ((stat_reg & 0x10) == 0) {
295                         printk(KERN_INFO PFX "Could not stop watchdog\n");
296                         return -EIO;
297                 }
298         }
299         return 0;
300 }
301
302 static void pcwd_keepalive(void)
303 {
304         /* user land ping */
305         next_heartbeat = jiffies + (heartbeat * HZ);
306 }
307
308 static int pcwd_set_heartbeat(int t)
309 {
310         if ((t < 2) || (t > 7200)) /* arbitrary upper limit */
311                 return -EINVAL;
312
313         heartbeat = t;
314         return 0;
315 }
316
317 static int pcwd_get_status(int *status)
318 {
319         int card_status;
320
321         *status=0;
322         spin_lock(&io_lock);
323         if (revision == PCWD_REVISION_A)
324                 /* Rev A cards return status information from
325                  * the base register, which is used for the
326                  * temperature in other cards. */
327                 card_status = inb(current_readport);
328         else {
329                 /* Rev C cards return card status in the base
330                  * address + 1 register. And use different bits
331                  * to indicate a card initiated reset, and an
332                  * over-temperature condition. And the reboot
333                  * status can be reset. */
334                 card_status = inb(current_readport + 1);
335         }
336         spin_unlock(&io_lock);
337
338         if (revision == PCWD_REVISION_A) {
339                 if (card_status & WD_WDRST)
340                         *status |= WDIOF_CARDRESET;
341
342                 if (card_status & WD_T110) {
343                         *status |= WDIOF_OVERHEAT;
344                         if (temp_panic) {
345                                 printk (KERN_INFO PFX "Temperature overheat trip!\n");
346                                 machine_power_off();
347                         }
348                 }
349         } else {
350                 if (card_status & WD_REVC_WTRP)
351                         *status |= WDIOF_CARDRESET;
352
353                 if (card_status & WD_REVC_TTRP) {
354                         *status |= WDIOF_OVERHEAT;
355                         if (temp_panic) {
356                                 printk (KERN_INFO PFX "Temperature overheat trip!\n");
357                                 machine_power_off();
358                         }
359                 }
360         }
361
362         return 0;
363 }
364
365 static int pcwd_clear_status(void)
366 {
367         if (revision == PCWD_REVISION_C) {
368                 spin_lock(&io_lock);
369                 outb_p(0x00, current_readport + 1); /* clear reset status */
370                 spin_unlock(&io_lock);
371         }
372         return 0;
373 }
374
375 static int pcwd_get_temperature(int *temperature)
376 {
377         /* check that port 0 gives temperature info and no command results */
378         if (command_mode)
379                 return -1;
380
381         *temperature = 0;
382         if (!supports_temp)
383                 return -ENODEV;
384
385         /*
386          * Convert celsius to fahrenheit, since this was
387          * the decided 'standard' for this return value.
388          */
389         spin_lock(&io_lock);
390         *temperature = ((inb(current_readport)) * 9 / 5) + 32;
391         spin_unlock(&io_lock);
392
393         return 0;
394 }
395
396 /*
397  *      /dev/watchdog handling
398  */
399
400 static int pcwd_ioctl(struct inode *inode, struct file *file,
401                       unsigned int cmd, unsigned long arg)
402 {
403         int rv;
404         int status;
405         int temperature;
406         int new_heartbeat;
407         static struct watchdog_info ident = {
408                 .options =              WDIOF_OVERHEAT |
409                                         WDIOF_CARDRESET |
410                                         WDIOF_KEEPALIVEPING |
411                                         WDIOF_SETTIMEOUT |
412                                         WDIOF_MAGICCLOSE,
413                 .firmware_version =     1,
414                 .identity =             "PCWD",
415         };
416
417         switch(cmd) {
418         default:
419                 return -ENOIOCTLCMD;
420
421         case WDIOC_GETSUPPORT:
422                 if(copy_to_user((void*)arg, &ident, sizeof(ident)))
423                         return -EFAULT;
424                 return 0;
425
426         case WDIOC_GETSTATUS:
427                 pcwd_get_status(&status);
428                 return put_user(status, (int *) arg);
429
430         case WDIOC_GETBOOTSTATUS:
431                 return put_user(initial_status, (int *) arg);
432
433         case WDIOC_GETTEMP:
434                 if (pcwd_get_temperature(&temperature))
435                         return -EFAULT;
436
437                 return put_user(temperature, (int *) arg);
438
439         case WDIOC_SETOPTIONS:
440                 if (revision == PCWD_REVISION_C)
441                 {
442                         if(copy_from_user(&rv, (int*) arg, sizeof(int)))
443                                 return -EFAULT;
444
445                         if (rv & WDIOS_DISABLECARD)
446                         {
447                                 return pcwd_stop();
448                         }
449
450                         if (rv & WDIOS_ENABLECARD)
451                         {
452                                 return pcwd_start();
453                         }
454
455                         if (rv & WDIOS_TEMPPANIC)
456                         {
457                                 temp_panic = 1;
458                         }
459                 }
460                 return -EINVAL;
461
462         case WDIOC_KEEPALIVE:
463                 pcwd_keepalive();
464                 return 0;
465
466         case WDIOC_SETTIMEOUT:
467                 if (get_user(new_heartbeat, (int *) arg))
468                         return -EFAULT;
469
470                 if (pcwd_set_heartbeat(new_heartbeat))
471                         return -EINVAL;
472
473                 pcwd_keepalive();
474                 /* Fall */
475
476         case WDIOC_GETTIMEOUT:
477                 return put_user(heartbeat, (int *)arg);
478         }
479
480         return 0;
481 }
482
483 static ssize_t pcwd_write(struct file *file, const char *buf, size_t len,
484                           loff_t *ppos)
485 {
486         /*  Can't seek (pwrite) on this device  */
487         if (ppos != &file->f_pos)
488                 return -ESPIPE;
489
490         if (len) {
491                 if (!nowayout) {
492                         size_t i;
493
494                         /* In case it was set long ago */
495                         expect_close = 0;
496
497                         for (i = 0; i != len; i++) {
498                                 char c;
499
500                                 if (get_user(c, buf + i))
501                                         return -EFAULT;
502                                 if (c == 'V')
503                                         expect_close = 42;
504                         }
505                 }
506                 pcwd_keepalive();
507         }
508         return len;
509 }
510
511 static int pcwd_open(struct inode *inode, struct file *file)
512 {
513         if (!atomic_dec_and_test(&open_allowed) ) {
514                 atomic_inc( &open_allowed );
515                 return -EBUSY;
516         }
517
518         if (nowayout)
519                 __module_get(THIS_MODULE);
520
521         /* Activate */
522         pcwd_start();
523         pcwd_keepalive();
524         return(0);
525 }
526
527 static int pcwd_close(struct inode *inode, struct file *file)
528 {
529         if (expect_close == 42) {
530                 pcwd_stop();
531                 atomic_inc( &open_allowed );
532         } else {
533                 printk(KERN_CRIT PFX "Unexpected close, not stopping watchdog!\n");
534                 pcwd_keepalive();
535         }
536         expect_close = 0;
537         return 0;
538 }
539
540 /*
541  *      /dev/temperature handling
542  */
543
544 static ssize_t pcwd_temp_read(struct file *file, char *buf, size_t count,
545                          loff_t *ppos)
546 {
547         int temperature;
548
549         /* Can't seek (pread) on this device */
550         if (ppos != &file->f_pos)
551                 return -ESPIPE;
552
553         if (pcwd_get_temperature(&temperature))
554                 return -EFAULT;
555
556         if (copy_to_user(buf, &temperature, 1))
557                 return -EFAULT;
558
559         return 1;
560 }
561
562 static int pcwd_temp_open(struct inode *inode, struct file *file)
563 {
564         if (!supports_temp)
565                 return -ENODEV;
566
567         return 0;
568 }
569
570 static int pcwd_temp_close(struct inode *inode, struct file *file)
571 {
572         return 0;
573 }
574
575 /*
576  *      Notify system
577  */
578
579 static int pcwd_notify_sys(struct notifier_block *this, unsigned long code, void *unused)
580 {
581         if (code==SYS_DOWN || code==SYS_HALT) {
582                 /* Turn the WDT off */
583                 pcwd_stop();
584         }
585
586         return NOTIFY_DONE;
587 }
588
589 /*
590  *      Kernel Interfaces
591  */
592
593 static struct file_operations pcwd_fops = {
594         .owner          = THIS_MODULE,
595         .llseek         = no_llseek,
596         .write          = pcwd_write,
597         .ioctl          = pcwd_ioctl,
598         .open           = pcwd_open,
599         .release        = pcwd_close,
600 };
601
602 static struct miscdevice pcwd_miscdev = {
603         .minor =        WATCHDOG_MINOR,
604         .name =         "watchdog",
605         .fops =         &pcwd_fops,
606 };
607
608 static struct file_operations pcwd_temp_fops = {
609         .owner          = THIS_MODULE,
610         .llseek         = no_llseek,
611         .read           = pcwd_temp_read,
612         .open           = pcwd_temp_open,
613         .release        = pcwd_temp_close,
614 };
615
616 static struct miscdevice temp_miscdev = {
617         .minor =        TEMP_MINOR,
618         .name =         "temperature",
619         .fops =         &pcwd_temp_fops,
620 };
621
622 static struct notifier_block pcwd_notifier = {
623         .notifier_call =        pcwd_notify_sys,
624 };
625
626 /*
627  *      Init & exit routines
628  */
629
630 static inline void get_support(void)
631 {
632         if (inb(current_readport) != 0xF0)
633                 supports_temp = 1;
634 }
635
636 static inline int get_revision(void)
637 {
638         int r = PCWD_REVISION_C;
639
640         spin_lock(&io_lock);
641         /* REV A cards use only 2 io ports; test
642          * presumes a floating bus reads as 0xff. */
643         if ((inb(current_readport + 2) == 0xFF) ||
644             (inb(current_readport + 3) == 0xFF))
645                 r=PCWD_REVISION_A;
646         spin_unlock(&io_lock);
647
648         return r;
649 }
650
651 static inline char *get_firmware(void)
652 {
653         int one, ten, hund, minor;
654         char *ret;
655
656         ret = kmalloc(6, GFP_KERNEL);
657         if(ret == NULL)
658                 return NULL;
659
660         if (set_command_mode()) {
661                 one = send_isa_command(CMD_ISA_VERSION_INTEGER);
662                 ten = send_isa_command(CMD_ISA_VERSION_TENTH);
663                 hund = send_isa_command(CMD_ISA_VERSION_HUNDRETH);
664                 minor = send_isa_command(CMD_ISA_VERSION_MINOR);
665                 sprintf(ret, "%c.%c%c%c", one, ten, hund, minor);
666         }
667         else
668                 sprintf(ret, "ERROR");
669
670         unset_command_mode();
671         return(ret);
672 }
673
674 static inline int get_option_switches(void)
675 {
676         int rv=0;
677
678         if (set_command_mode()) {
679                 /* Get switch settings */
680                 rv = send_isa_command(CMD_ISA_SWITCH_SETTINGS);
681         }
682
683         unset_command_mode();
684         return(rv);
685 }
686
687 static int __devinit pcwatchdog_init(int base_addr)
688 {
689         int ret;
690         char *firmware;
691         int option_switches;
692
693         cards_found++;
694         if (cards_found == 1)
695                 printk(KERN_INFO PFX "v%s Ken Hollis (kenji@bitgate.com)\n", WD_VER);
696
697         if (cards_found > 1) {
698                 printk(KERN_ERR PFX "This driver only supports 1 device\n");
699                 return -ENODEV;
700         }
701
702         if (base_addr == 0x0000) {
703                 printk(KERN_ERR PFX "No I/O-Address for card detected\n");
704                 return -ENODEV;
705         }
706         current_readport = base_addr;
707
708         /* Check card's revision */
709         revision = get_revision();
710
711         if (!request_region(current_readport, (revision == PCWD_REVISION_A) ? 2 : 4, "PCWD")) {
712                 printk(KERN_ERR PFX "I/O address 0x%04x already in use\n",
713                         current_readport);
714                 current_readport = 0x0000;
715                 return -EIO;
716         }
717
718         /* Initial variables */
719         supports_temp = 0;
720         temp_panic = 0;
721         initial_status = 0x0000;
722
723         /* get the boot_status */
724         pcwd_get_status(&initial_status);
725
726         /* clear the "card caused reboot" flag */
727         pcwd_clear_status();
728
729         init_timer(&timer);
730         timer.function = pcwd_timer_ping;
731         timer.data = 0;
732
733         /*  Disable the board  */
734         pcwd_stop();
735
736         /*  Check whether or not the card supports the temperature device */
737         get_support();
738
739         /* Get some extra info from the hardware (in command/debug/diag mode) */
740         if (revision == PCWD_REVISION_A)
741                 printk(KERN_INFO PFX "ISA-PC Watchdog (REV.A) detected at port 0x%04x\n", current_readport);
742         else if (revision == PCWD_REVISION_C) {
743                 firmware = get_firmware();
744                 printk(KERN_INFO PFX "ISA-PC Watchdog (REV.C) detected at port 0x%04x (Firmware version: %s)\n",
745                         current_readport, firmware);
746                 kfree(firmware);
747                 option_switches = get_option_switches();
748                 printk(KERN_INFO PFX "Option switches (0x%02x): Temperature Reset Enable=%s, Power On Delay=%s\n",
749                         option_switches,
750                         ((option_switches & 0x10) ? "ON" : "OFF"),
751                         ((option_switches & 0x08) ? "ON" : "OFF"));
752
753                 /* Reprogram internal heartbeat to 2 seconds */
754                 if (set_command_mode()) {
755                         send_isa_command(CMD_ISA_DELAY_TIME_2SECS);
756                         unset_command_mode();
757                 }
758         } else {
759                 /* Should NEVER happen, unless get_revision() fails. */
760                 printk(KERN_INFO PFX "Unable to get revision\n");
761                 release_region(current_readport, (revision == PCWD_REVISION_A) ? 2 : 4);
762                 current_readport = 0x0000;
763                 return -1;
764         }
765
766         if (supports_temp)
767                 printk(KERN_INFO PFX "Temperature Option Detected\n");
768
769         if (initial_status & WDIOF_CARDRESET)
770                 printk(KERN_INFO PFX "Previous reboot was caused by the card\n");
771
772         if (initial_status & WDIOF_OVERHEAT) {
773                 printk(KERN_EMERG PFX "Card senses a CPU Overheat. Panicking!\n");
774                 printk(KERN_EMERG PFX "CPU Overheat\n");
775         }
776
777         if (initial_status == 0)
778                 printk(KERN_INFO PFX "No previous trip detected - Cold boot or reset\n");
779
780         /* Check that the heartbeat value is within it's range ; if not reset to the default */
781         if (pcwd_set_heartbeat(heartbeat)) {
782                 pcwd_set_heartbeat(WATCHDOG_HEARTBEAT);
783                 printk(KERN_INFO PFX "heartbeat value must be 2<=heartbeat<=7200, using %d\n",
784                         WATCHDOG_HEARTBEAT);
785         }
786
787         ret = register_reboot_notifier(&pcwd_notifier);
788         if (ret) {
789                 printk(KERN_ERR PFX "cannot register reboot notifier (err=%d)\n",
790                         ret);
791                 release_region(current_readport, (revision == PCWD_REVISION_A) ? 2 : 4);
792                 current_readport = 0x0000;
793                 return ret;
794         }
795
796         if (supports_temp) {
797                 ret = misc_register(&temp_miscdev);
798                 if (ret) {
799                         printk(KERN_ERR PFX "cannot register miscdev on minor=%d (err=%d)\n",
800                                 TEMP_MINOR, ret);
801                         unregister_reboot_notifier(&pcwd_notifier);
802                         release_region(current_readport, (revision == PCWD_REVISION_A) ? 2 : 4);
803                         current_readport = 0x0000;
804                         return ret;
805                 }
806         }
807
808         ret = misc_register(&pcwd_miscdev);
809         if (ret) {
810                 printk(KERN_ERR PFX "cannot register miscdev on minor=%d (err=%d)\n",
811                         WATCHDOG_MINOR, ret);
812                 if (supports_temp)
813                         misc_deregister(&temp_miscdev);
814                 unregister_reboot_notifier(&pcwd_notifier);
815                 release_region(current_readport, (revision == PCWD_REVISION_A) ? 2 : 4);
816                 current_readport = 0x0000;
817                 return ret;
818         }
819
820         printk(KERN_INFO PFX "initialized. heartbeat=%d sec (nowayout=%d)\n",
821                 heartbeat, nowayout);
822
823         return 0;
824 }
825
826 static void __devexit pcwatchdog_exit(void)
827 {
828         /*  Disable the board  */
829         if (!nowayout)
830                 pcwd_stop();
831
832         /* Deregister */
833         misc_deregister(&pcwd_miscdev);
834         if (supports_temp)
835                 misc_deregister(&temp_miscdev);
836         unregister_reboot_notifier(&pcwd_notifier);
837         release_region(current_readport, (revision == PCWD_REVISION_A) ? 2 : 4);
838         current_readport = 0x0000;
839 }
840
841 /*
842  *  The ISA cards have a heartbeat bit in one of the registers, which
843  *  register is card dependent.  The heartbeat bit is monitored, and if
844  *  found, is considered proof that a Berkshire card has been found.
845  *  The initial rate is once per second at board start up, then twice
846  *  per second for normal operation.
847  */
848 static int __init pcwd_checkcard(int base_addr)
849 {
850         int port0, last_port0;  /* Reg 0, in case it's REV A */
851         int port1, last_port1;  /* Register 1 for REV C cards */
852         int i;
853         int retval;
854
855         if (!request_region (base_addr, 4, "PCWD")) {
856                 printk (KERN_INFO PFX "Port 0x%04x unavailable\n", base_addr);
857                 return 0;
858         }
859
860         retval = 0;
861
862         port0 = inb_p(base_addr);       /* For REV A boards */
863         port1 = inb_p(base_addr + 1);   /* For REV C boards */
864         if (port0 != 0xff || port1 != 0xff) {
865                 /* Not an 'ff' from a floating bus, so must be a card! */
866                 for (i = 0; i < 4; ++i) {
867
868                         set_current_state(TASK_INTERRUPTIBLE);
869                         schedule_timeout(HZ / 2);
870
871                         last_port0 = port0;
872                         last_port1 = port1;
873
874                         port0 = inb_p(base_addr);
875                         port1 = inb_p(base_addr + 1);
876
877                         /* Has either hearbeat bit changed?  */
878                         if ((port0 ^ last_port0) & WD_HRTBT ||
879                             (port1 ^ last_port1) & WD_REVC_HRBT) {
880                                 retval = 1;
881                                 break;
882                         }
883                 }
884         }
885         release_region (base_addr, 4);
886
887         return retval;
888 }
889
890 /*
891  * These are the auto-probe addresses available.
892  *
893  * Revision A only uses ports 0x270 and 0x370.  Revision C introduced 0x350.
894  * Revision A has an address range of 2 addresses, while Revision C has 4.
895  */
896 static int pcwd_ioports[] = { 0x270, 0x350, 0x370, 0x000 };
897
898 static int __init pcwd_init_module(void)
899 {
900         int i, found = 0;
901
902         spin_lock_init(&io_lock);
903
904         for (i = 0; pcwd_ioports[i] != 0; i++) {
905                 if (pcwd_checkcard(pcwd_ioports[i])) {
906                         if (!(pcwatchdog_init(pcwd_ioports[i])))
907                                 found++;
908                 }
909         }
910
911         if (!found) {
912                 printk (KERN_INFO PFX "No card detected, or port not available\n");
913                 return -ENODEV;
914         }
915
916         return 0;
917 }
918
919 static void __exit pcwd_cleanup_module(void)
920 {
921         if (current_readport)
922                 pcwatchdog_exit();
923         return;
924 }
925
926 module_init(pcwd_init_module);
927 module_exit(pcwd_cleanup_module);
928
929 MODULE_AUTHOR("Ken Hollis <kenji@bitgate.com>");
930 MODULE_DESCRIPTION("Berkshire ISA-PC Watchdog driver");
931 MODULE_LICENSE("GPL");
932 MODULE_ALIAS_MISCDEV(WATCHDOG_MINOR);
933 MODULE_ALIAS_MISCDEV(TEMP_MINOR);