3 * by Ken Hollis (khollis@bitgate.com)
5 * Permission granted from Simon Machell (73244.1270@compuserve.com)
6 * Written for the Linux Kernel, and GPLed by Ken Hollis
8 * 960107 Added request_region routines, modulized the whole thing.
9 * 960108 Fixed end-of-file pointer (Thanks to Dan Hollis), added
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
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 * 020210 Backported 2.5 open_allowed changes, and got rid of a useless
45 * variable <rob@osinvestor.com>
46 * Added timeout module option to override default
47 * 020306 Support the PCI version [Lindsay Harris <lindsay@bluegum.com>]
51 * A bells and whistles driver is available from http://www.pcwd.de/
53 #include <linux/module.h>
55 #include <linux/types.h>
56 #include <linux/delay.h>
57 #include <linux/miscdevice.h>
58 #include <linux/watchdog.h>
59 #include <linux/init.h>
61 #include <asm/uaccess.h>
64 #include <linux/notifier.h>
65 #include <linux/reboot.h>
66 #include <linux/pci.h>
68 #define WD_VER "1.13 (03/06/2002)"
70 /* Stuff for the PCI version */
71 #ifndef PCI_VENDOR_ID_QUICKLOGIC
72 #define PCI_VENDOR_ID_QUICKLOGIC 0x11e3
74 #ifndef PCI_DEVICE_ID_BERKSHIRE
75 #define PCI_DEVICE_ID_BERKSHIRE 0x5030
79 * It should be noted that PCWD_REV_B was removed because A and B
80 * are essentially the same types of card, with the exception that B
81 * has temperature reporting. Since I didn't receive a Rev.B card,
82 * the Rev.B card is not supported. (It's a good thing too, as they
83 * are no longer in production.)
87 #define PCWD_REV_PCI 2
89 static int timeout_val;
90 static int timeout = 2;
91 static int expect_close = 0;
93 MODULE_PARM (timeout, "i");
94 MODULE_PARM_DESC (timeout, "Watchdog timeout in seconds (default=2)");
96 #ifdef CONFIG_WATCHDOG_NOWAYOUT
97 static int nowayout = 1;
99 static int nowayout = 0;
102 MODULE_PARM (nowayout, "i");
103 MODULE_PARM_DESC (nowayout,
104 "Watchdog cannot be stopped once started (default=CONFIG_WATCHDOG_NOWAYOUT)");
107 * These are the defines for the PC Watchdog card, revision A.
109 #define WD_WDRST 0x01 /* Previously reset state */
110 #define WD_T110 0x02 /* Temperature overheat sense */
111 #define WD_HRTBT 0x04 /* Heartbeat sense */
112 #define WD_RLY2 0x08 /* External relay triggered */
113 #define WD_SRLY2 0x80 /* Software external relay triggered */
116 * Differences between cards regarding how they perform some operations
117 * are handled by an array of structs, with per card functions for the
118 * incompatible operations. It's all defined here.
121 /* ENABLE/DISABLE the card */
122 typedef int (*fn_enable) (int); /* Enable/disable card */
124 static int pcwd_enable_card (int enable); /* Actually works */
125 static int pcwd_enable_nop (int enable); /* NOP - REV A cannot */
127 /* Obtain firmware version, if possible */
128 #define PCWD_FIRMWARE_BSZ 16 /* Version buffer size */
129 typedef void (*fn_firmware) (char *bp);
131 static void pcwd_firmware_ver_none (char *bp); /* REV A can't do it */
132 static void pcwd_firmware_ver_revc (char *bp); /* REV C boards can */
133 static void pcwd_firmware_ver_pci (char *bp); /* PCI boards can too */
135 /* Tickle the watchdog timer */
136 typedef void (*fn_tickle) (void);
138 static void pcwd_tickle_reva (void); /* Rev A only */
139 static void pcwd_tickle (void); /* Rev C, PCI */
141 /* Determine reboot and temperature status */
142 typedef int (*fn_status) (int reset_boot);
144 static int pcwd_get_stat_reva (int reset_boot);
145 static int pcwd_get_stat (int reset_boot);
147 /* Per card type specifications */
149 fn_tickle wd_tickle; /* Reset the watchdog */
150 fn_enable enable_card; /* Enable/disable card, if possible */
151 fn_firmware firmware_ver; /* Get firmware version, if possible */
152 fn_status wd_status; /* Card reset and/or over temp */
153 int io_size; /* I/O space used */
154 const char *name; /* Nice name to display */
157 /* Per card information, indexed by card version ID */
158 static PCWD_CARD_INFO pcwd_card_info[] = {
162 pcwd_firmware_ver_none,
165 "Berkshire Products PC Watchdog (REV A)",
170 pcwd_firmware_ver_revc,
173 "Berkshire Products PC Watchdog (REV C)",
178 pcwd_firmware_ver_pci,
181 "Berkshire Products PC Watchdog (PCI)",
185 /* Overall driver information, including per card pointer */
187 PCWD_CARD_INFO *card_info; /* Points to one of the above */
188 atomic_t open_allowed; /* Watchdog is single open */
189 int flags; /* Defined below */
190 int boot_status; /* Card status at boot time */
191 int io_addr; /* Card's base address */
193 NULL, ATOMIC_INIT (1), 0, 0, 0};
195 /* Bits allocated in flags above. */
196 #define PCWD_HAS_TEMP 0x0001 /* Set when thermometer available */
197 #define PCWD_PCI_REG 0x0002 /* Set if PCI register code worked */
198 #define PCWD_TEMP_PANIC 0x0004 /* Panic when over temperature */
200 static spinlock_t io_lock;
202 /* D E T E R M I N E C A R D S T A T U S F U N C T I O N S */
203 /* Rev A cards return status information from the base register,
204 * which is used for the temperature in other cards. */
207 pcwd_get_stat_reva (int reset_boot)
212 spin_lock (&io_lock);
213 status = inb_p (pcwd_info.io_addr);
214 spin_unlock (&io_lock);
216 /* Transform the card register to the ioctl bits we use internally */
217 retval = WDIOF_MAGICCLOSE;
218 if (status & WD_WDRST)
219 retval |= WDIOF_CARDRESET;
220 if (status & WD_T110)
221 retval |= WDIOF_OVERHEAT;
227 * Rev C and PCI cards return card status in the base address + 1 register.
228 * And use different bits to indicate a card initiated reset, and
229 * an over-temperature condition. And the reboot status can be reset.
233 pcwd_get_stat (int reset_boot)
238 spin_lock (&io_lock);
239 status = inb_p (pcwd_info.io_addr + 1);
241 /* NOTE: the REV C card clears the "card caused reboot"
242 * flag when writing ANY value to this port. However,
243 * the PCI card requires writing a 1 to bit 0. */
244 outb_p (0x01, pcwd_info.io_addr + 1);
246 spin_unlock (&io_lock);
250 retval |= WDIOF_CARDRESET;
252 retval |= WDIOF_OVERHEAT;
257 /* W A T C H D O G T I M E R R E S E T F U N C T I O N S */
258 /* Rev A cards are reset by setting a specific bit in register 1. */
261 pcwd_tickle_reva (void)
265 spin_lock (&io_lock);
266 wdrst_stat = inb_p (pcwd_info.io_addr);
267 wdrst_stat = (wdrst_stat & 0x0F) | WD_WDRST;
269 outb_p (wdrst_stat, pcwd_info.io_addr + 1);
270 spin_unlock (&io_lock);
275 /* Other cards are reset by writing anything to the base register. */
280 spin_lock (&io_lock);
281 outb_p (0x42, pcwd_info.io_addr);
282 spin_unlock (&io_lock);
288 pcwd_ioctl (struct inode *inode, struct file *file,
289 unsigned int cmd, unsigned long arg)
294 static struct watchdog_info ident = {
295 WDIOF_OVERHEAT | WDIOF_CARDRESET,
301 case WDIOC_GETSUPPORT:
302 rv = copy_to_user ((void *) arg, &ident, sizeof (ident));
303 return rv ? -EFAULT : 0;
305 case WDIOC_GETSTATUS:
306 rv = pcwd_info.card_info->wd_status (0);
308 if (rv & WDIOF_OVERHEAT) {
309 if (pcwd_info.flags & PCWD_TEMP_PANIC)
310 panic ("pcwd: Temperature overheat trip!\n");
313 if (put_user (rv, (int *) arg))
317 case WDIOC_GETBOOTSTATUS:
318 rv = pcwd_info.boot_status;
320 if (put_user (rv, (int *) arg))
326 if (pcwd_info.flags & PCWD_HAS_TEMP) {
327 spin_lock (&io_lock);
328 rv = inb_p (pcwd_info.io_addr);
329 spin_unlock (&io_lock);
331 if (put_user (rv, (int *) arg))
335 case WDIOC_SETOPTIONS:
336 if (copy_from_user (&rv, (int *) arg, sizeof (int)))
341 if (rv & WDIOS_DISABLECARD) {
342 if (!pcwd_info.card_info->enable_card (0)) {
344 "pcwd: Could not disable card\n");
351 if (rv & WDIOS_ENABLECARD) {
352 if (!pcwd_info.card_info->enable_card (1)) {
354 "pcwd: Could not enable card\n");
360 if (rv & WDIOS_TEMPPANIC) {
361 pcwd_info.flags |= PCWD_TEMP_PANIC;
368 case WDIOC_KEEPALIVE:
369 pcwd_info.card_info->wd_tickle ();
379 /* Write: only for the watchdog device (thermometer is read-only). */
382 pcwd_write (struct file *file, const char *buf, size_t len, loff_t * ppos)
384 /* Can't seek (pwrite) on this device */
385 if (ppos != &file->f_pos)
392 /* In case it was set long ago */
395 for (i = 0; i != len; i++) {
397 if (get_user(c, buf + i))
403 pcwd_info.card_info->wd_tickle ();
410 pcwd_open (struct inode *ino, struct file *filep)
412 switch (MINOR (ino->i_rdev)) {
414 if (!atomic_dec_and_test (&pcwd_info.open_allowed)) {
415 atomic_inc (&pcwd_info.open_allowed);
419 /* Enable the card */
420 pcwd_info.card_info->enable_card (1);
421 pcwd_info.card_info->wd_tickle ();
426 if (pcwd_info.flags & PCWD_HAS_TEMP) {
436 /* Read: applies only to the thermometer (watchdog is write only). */
438 pcwd_read (struct file *file, char *buf, size_t count, loff_t * ppos)
443 /* Can't seek (pread) on this device */
444 if (ppos != &file->f_pos)
448 * Convert celsius to fahrenheit, since this was
449 * the decided 'standard' for this return value.
452 spin_lock (&io_lock);
453 c = inb_p (pcwd_info.io_addr);
454 spin_unlock (&io_lock);
456 cp = (c * 9 / 5) + 32;
457 if (copy_to_user (buf, &cp, 1))
464 pcwd_close (struct inode *ino, struct file *filep)
466 switch (MINOR (ino->i_rdev)) {
469 pcwd_info.card_info->enable_card (0);
471 atomic_inc (&pcwd_info.open_allowed);
481 * System is shutting down, so disable the card. Otherwise the timeout
482 * may expire during shutdown. Of course, this means a hang during
483 * shutdown will not be reset, but somebody is probably nearby and will
484 * notice. The alternative is to have the shutdown aborted when the
485 * watchdog expires and hits reset.
489 pcwd_notify_sys (struct notifier_block *this, unsigned long code, void *unused)
491 if (code == SYS_DOWN || code == SYS_HALT) {
493 * If initialisation is still in progress, the device pointer
494 * may not be valid, so check, just to make sure.
497 if (pcwd_info.card_info)
498 pcwd_info.card_info->enable_card (0);
504 /* C A R D E N A B L E / D I S A B L E F U N C T I O N S */
505 /* Enable/disable the card, not REV A. The two writes are required by card */
508 pcwd_enable_card (int enable)
512 spin_lock (&io_lock);
514 outb_p (0x00, pcwd_info.io_addr + 3);
516 outb_p (0xA5, pcwd_info.io_addr + 3);
517 outb_p (0xA5, pcwd_info.io_addr + 3);
519 stat_reg = inb_p (pcwd_info.io_addr + 2);
520 spin_unlock (&io_lock);
522 stat_reg &= 0x10; /* "disabled when set" bit */
531 pcwd_enable_nop (int enable)
537 set_card_type (int is_pci)
541 pcwd_info.card_info = &pcwd_card_info[PCWD_REV_PCI];
542 pcwd_info.flags |= PCWD_PCI_REG;
544 pcwd_info.card_info = &pcwd_card_info[PCWD_REV_C];
546 /* REV A cards use only 2 io ports; test
547 * presumes a floating bus reads as 0xff. */
548 if ((inb (pcwd_info.io_addr + 2) == 0xFF) ||
549 (inb (pcwd_info.io_addr + 3) == 0xFF)) {
550 pcwd_info.card_info = &pcwd_card_info[PCWD_REV_A];
557 /* G E T F I R M W A R E V E R S I O N F U N C T I O N S */
558 /* REV A can't do it */
560 pcwd_firmware_ver_none (char *bp)
562 strncpy (bp, "<unavailable>", PCWD_FIRMWARE_BSZ);
567 /* PCI boards can too */
569 pcwd_firmware_ver_pci (char *bp)
573 /* Write the 'Get Firmware Version' command to port 6 and wait */
574 outb (0x08, pcwd_info.io_addr + 6);
576 /* Card sets bit 0x40 (WRSP) bit in port 2. Can take 10ms! */
577 for (count = 0; count < 15; ++count) {
578 mdelay (1); /* Board responds slowly */
580 if (inb (pcwd_info.io_addr + 2) & 0x40) {
581 /* Board says data now valid */
583 snprintf (bp, PCWD_FIRMWARE_BSZ, "%u.%u",
584 inb (pcwd_info.io_addr + 5),
585 inb (pcwd_info.io_addr + 4));
590 strncpy (bp, "<card no answer>", PCWD_FIRMWARE_BSZ);
596 * REV C boards read diagnostic (including firmware version) data
597 * from the register 0. To do this, the card is put into diagnostic
598 * mode, then the command is submitted and data read from register 0.
599 * NOTE: the onboard processor writes 4 bits at a time to the register,
600 * so it's necessary to wait for the data to stabilise before
605 send_command (int cmd)
609 int reg0, last_reg0; /* Double read for stabilising */
611 outb (cmd, pcwd_info.io_addr + 2);
613 * The following delay need only be 200 microseconds according
614 * to the spec I have. But my card seems slower, as waiting
615 * 250 microseconds returns valid data, but NOT from this
616 * command. The 1000 value may be excessive, but is reliable.
620 reg0 = inb (pcwd_info.io_addr);
621 for (ii = 0; ii < 25; ++ii) {
623 reg0 = inb (pcwd_info.io_addr);
625 if (reg0 == last_reg0)
626 break; /* Data is stable */
634 /* REV C board function to retrieve firmware version */
636 pcwd_firmware_ver_revc (char *bp)
638 int i, found = 0, count = 0;
640 /* Set the card into debug mode to find firmware version */
641 outb_p (0x00, pcwd_info.io_addr + 2); /* Spec says to do this */
644 while ((count < 3) && (!found)) {
645 i = send_command (0x80);
650 } else if (i == 0xF3) {
651 /* Card does not like what we've done to it */
652 outb_p (0x00, pcwd_info.io_addr + 2);
653 udelay (1200); /* Spec says wait 1ms */
654 outb_p (0x00, pcwd_info.io_addr + 2);
662 *bp++ = send_command (0x81);
664 *bp++ = send_command (0x82);
665 *bp++ = send_command (0x83);
666 *bp++ = send_command (0x84);
669 /* Out of debug mode */
670 outb (0x00, pcwd_info.io_addr + 2);
672 strncpy (bp, "<err - no go>", PCWD_FIRMWARE_BSZ);
677 /* Initialisation function called ONLY from the PCI layer. */
680 pcwd_init_one (struct pci_dev *dev, const struct pci_device_id *ent)
682 static int devices = 0;
686 printk (KERN_ERR "pcwd: Driver supports only ONE device\n");
691 pcwd_info.io_addr = pci_resource_start (dev, 0);
693 if (pcwd_info.io_addr == 0 || pci_enable_device (dev))
699 static struct pci_device_id pcwd_pci_tbl[] __initdata = {
700 {PCI_VENDOR_ID_QUICKLOGIC, PCI_DEVICE_ID_BERKSHIRE,
701 PCI_ANY_ID, PCI_ANY_ID,},
702 {0}, /* End of list */
705 MODULE_DEVICE_TABLE (pci, pcwd_pci_tbl);
707 static struct pci_driver pcwd_driver = {
709 id_table:pcwd_pci_tbl,
713 static struct file_operations pcwd_fops = {
721 static struct miscdevice pcwd_miscdev = {
727 static struct file_operations pcwd_temp_fops = {
734 static struct miscdevice temp_miscdev = {
740 /* Need to know about shutdown to kill the timer - may reset during shutdown! */
741 static struct notifier_block pcwd_notifier =
749 * The ISA cards have a heartbeat bit in one of the registers, which
750 * register is card dependent. The heartbeat bit is monitored, and if
751 * found, is considered proof that a Berkshire card has been found.
752 * The initial rate is once per second at board start up, then twice
753 * per second for normal operation.
756 check_isa_card (int base_addr)
758 int reg0, last_reg0; /* Reg 0, in case it's REV A */
759 int reg1, last_reg1; /* Register 1 for REV C cards */
763 /* As suggested by Alan Cox - this is a safety measure. */
764 if (!request_region (base_addr, 4, "pcwd-isa")) {
765 printk (KERN_INFO "pcwd: Port 0x%x unavailable\n", base_addr);
771 reg0 = inb_p (base_addr); /* For REV A boards */
772 reg1 = inb (base_addr + 1); /* For REV C boards */
773 if (reg0 != 0xff || reg1 != 0xff) {
774 /* Not an 'ff' from a floating bus, so must be a card! */
775 for (ii = 0; ii < timeout_val; ++ii) {
777 set_current_state (TASK_INTERRUPTIBLE);
778 schedule_timeout (HZ / 2);
783 reg0 = inb_p (base_addr);
784 reg1 = inb (base_addr + 1);
786 /* Has either hearbeat bit changed? */
787 if ((reg0 ^ last_reg0) & WD_HRTBT ||
788 (reg1 ^ last_reg1) & 0x02) {
795 release_region (base_addr, 4);
801 pcwd_card_init (void)
804 char fvbuf[PCWD_FIRMWARE_BSZ];
806 pcwd_info.card_info->firmware_ver (fvbuf);
808 printk (KERN_INFO "pcwd: %s at port 0x%03x (Firmware: %s)\n",
809 pcwd_info.card_info->name, pcwd_info.io_addr, fvbuf);
811 /* Returns 0xf0 in temperature register if no thermometer */
812 if (inb (pcwd_info.io_addr) != 0xF0) {
813 pcwd_info.flags |= PCWD_HAS_TEMP;
814 printk (KERN_INFO "pcwd: Temperature option detected\n");
819 "pcwd: Watchdog cannot be stopped once started\n");
821 /* Record the power up status of "card did reset" and/or temp trip */
822 pcwd_info.boot_status = pcwd_info.card_info->wd_status (1);
824 if (pcwd_info.boot_status & WDIOF_CARDRESET)
826 "pcwd: Previous reboot was caused by the card\n");
828 if (pcwd_info.boot_status & WDIOF_OVERHEAT) {
830 "pcwd: Card senses a CPU Overheat. Panicking!\n");
831 panic ("pcwd: CPU Overheat\n");
834 if (pcwd_info.boot_status == 0)
835 printk (KERN_INFO "pcwd: Cold boot sense\n");
837 pcwd_info.card_info->enable_card (0);
840 if (!request_region (pcwd_info.io_addr,
841 pcwd_info.card_info->io_size,
842 pcwd_info.card_info->name)) {
843 printk (KERN_ERR "pcwd: I/0 %d is not free\n",
849 retval = misc_register (&pcwd_miscdev);
851 release_region (pcwd_info.io_addr,
852 pcwd_info.card_info->io_size);
853 printk (KERN_ERR "pcwd: can't misc_register on minor %d\n",
858 if (pcwd_info.flags & PCWD_HAS_TEMP) {
859 if (misc_register (&temp_miscdev)) {
861 "pwcd: can't misc_register thermometer - disabling it\n");
862 pcwd_info.flags &= ~PCWD_HAS_TEMP;
866 retval = register_reboot_notifier (&pcwd_notifier);
868 if (pcwd_info.flags & PCWD_HAS_TEMP)
869 misc_deregister (&temp_miscdev);
870 misc_deregister (&pcwd_miscdev);
871 release_region (pcwd_info.io_addr,
872 pcwd_info.card_info->io_size);
879 pcwatchdog_init (void)
883 * ISA card auto-probe addresses available. Last one is only
884 * available on REV C cards.
886 static int pcwd_ioports[] = { 0x270, 0x350, 0x370 };
887 #define PCWD_NUM_ADDR (sizeof(pcwd_ioports)/sizeof(pcwd_ioports[0]))
889 timeout_val = timeout * 2;
891 spin_lock_init (&io_lock);
893 printk (KERN_INFO "pcwd: v%s Ken Hollis (kenji@bitgate.com)\n", WD_VER);
895 if (pci_register_driver (&pcwd_driver) > 0) {
897 set_card_type (1); /* Set to PCI card model */
899 /* No PCI entry, try the ISA addresses. */
900 for (i = 0; i < PCWD_NUM_ADDR; i++) {
902 if (check_isa_card (pcwd_ioports[i])) {
905 pcwd_info.io_addr = pcwd_ioports[i];
915 "pcwd: No card detected, or port not available\n");
919 return pcwd_card_init ();
923 pcwatchdog_exit (void)
925 unregister_reboot_notifier (&pcwd_notifier);
926 misc_deregister (&pcwd_miscdev);
929 pcwd_info.card_info->enable_card (0);
931 if (pcwd_info.flags & PCWD_HAS_TEMP)
932 misc_deregister (&temp_miscdev);
934 release_region (pcwd_info.io_addr, pcwd_info.card_info->io_size);
936 if (pcwd_info.flags & PCWD_PCI_REG)
937 pci_unregister_driver (&pcwd_driver);
942 module_init (pcwatchdog_init);
943 module_exit (pcwatchdog_exit);
945 MODULE_LICENSE ("GPL");