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