]> git.karo-electronics.de Git - linux-beck.git/blob - drivers/watchdog/pcwd.c
Merge tag 'xtensa-next-20160320' of git://github.com/czankel/xtensa-linux
[linux-beck.git] / drivers / watchdog / pcwd.c
1 /*
2  * PC Watchdog Driver
3  * by Ken Hollis (khollis@bitgate.com)
4  *
5  * Permission granted from Simon Machell (smachell@berkprod.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
44  *              CONFIG_WATCHDOG_NOWAYOUT <Matt_Domsch@dell.com>
45  *              Added timeout module option to override default
46  */
47
48 /*
49  *      A bells and whistles driver is available from http://www.pcwd.de/
50  *      More info available at http://www.berkprod.com/ or
51  *      http://www.pcwatchdog.com/
52  */
53
54 #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
55
56 #include <linux/module.h>       /* For module specific items */
57 #include <linux/moduleparam.h>  /* For new moduleparam's */
58 #include <linux/types.h>        /* For standard types (like size_t) */
59 #include <linux/errno.h>        /* For the -ENODEV/... values */
60 #include <linux/kernel.h>       /* For printk/panic/... */
61 #include <linux/delay.h>        /* For mdelay function */
62 #include <linux/timer.h>        /* For timer related operations */
63 #include <linux/jiffies.h>      /* For jiffies stuff */
64 #include <linux/miscdevice.h>   /* For struct miscdevice */
65 #include <linux/watchdog.h>     /* For the watchdog specific items */
66 #include <linux/reboot.h>       /* For kernel_power_off() */
67 #include <linux/init.h>         /* For __init/__exit/... */
68 #include <linux/fs.h>           /* For file operations */
69 #include <linux/isa.h>          /* For isa devices */
70 #include <linux/ioport.h>       /* For io-port access */
71 #include <linux/spinlock.h>     /* For spin_lock/spin_unlock/... */
72 #include <linux/uaccess.h>      /* For copy_to_user/put_user/... */
73 #include <linux/io.h>           /* For inb/outb/... */
74
75 /* Module and version information */
76 #define WATCHDOG_VERSION "1.20"
77 #define WATCHDOG_DATE "18 Feb 2007"
78 #define WATCHDOG_DRIVER_NAME "ISA-PC Watchdog"
79 #define WATCHDOG_NAME "pcwd"
80 #define DRIVER_VERSION WATCHDOG_DRIVER_NAME " driver, v" WATCHDOG_VERSION "\n"
81
82 /*
83  * It should be noted that PCWD_REVISION_B was removed because A and B
84  * are essentially the same types of card, with the exception that B
85  * has temperature reporting.  Since I didn't receive a Rev.B card,
86  * the Rev.B card is not supported.  (It's a good thing too, as they
87  * are no longer in production.)
88  */
89 #define PCWD_REVISION_A         1
90 #define PCWD_REVISION_C         2
91
92 /*
93  * These are the auto-probe addresses available.
94  *
95  * Revision A only uses ports 0x270 and 0x370.  Revision C introduced 0x350.
96  * Revision A has an address range of 2 addresses, while Revision C has 4.
97  */
98 #define PCWD_ISA_NR_CARDS       3
99 static int pcwd_ioports[] = { 0x270, 0x350, 0x370, 0x000 };
100
101 /*
102  * These are the defines that describe the control status bits for the
103  * PCI-PC Watchdog card.
104 */
105 /* Port 1 : Control Status #1 for the PC Watchdog card, revision A. */
106 #define WD_WDRST                0x01    /* Previously reset state */
107 #define WD_T110                 0x02    /* Temperature overheat sense */
108 #define WD_HRTBT                0x04    /* Heartbeat sense */
109 #define WD_RLY2                 0x08    /* External relay triggered */
110 #define WD_SRLY2                0x80    /* Software external relay triggered */
111 /* Port 1 : Control Status #1 for the PC Watchdog card, revision C. */
112 #define WD_REVC_WTRP            0x01    /* Watchdog Trip status */
113 #define WD_REVC_HRBT            0x02    /* Watchdog Heartbeat */
114 #define WD_REVC_TTRP            0x04    /* Temperature Trip status */
115 #define WD_REVC_RL2A            0x08    /* Relay 2 activated by
116                                                         on-board processor */
117 #define WD_REVC_RL1A            0x10    /* Relay 1 active */
118 #define WD_REVC_R2DS            0x40    /* Relay 2 disable */
119 #define WD_REVC_RLY2            0x80    /* Relay 2 activated? */
120 /* Port 2 : Control Status #2 */
121 #define WD_WDIS                 0x10    /* Watchdog Disabled */
122 #define WD_ENTP                 0x20    /* Watchdog Enable Temperature Trip */
123 #define WD_SSEL                 0x40    /* Watchdog Switch Select
124                                                         (1:SW1 <-> 0:SW2) */
125 #define WD_WCMD                 0x80    /* Watchdog Command Mode */
126
127 /* max. time we give an ISA watchdog card to process a command */
128 /* 500ms for each 4 bit response (according to spec.) */
129 #define ISA_COMMAND_TIMEOUT     1000
130
131 /* Watchdog's internal commands */
132 #define CMD_ISA_IDLE                    0x00
133 #define CMD_ISA_VERSION_INTEGER         0x01
134 #define CMD_ISA_VERSION_TENTH           0x02
135 #define CMD_ISA_VERSION_HUNDRETH        0x03
136 #define CMD_ISA_VERSION_MINOR           0x04
137 #define CMD_ISA_SWITCH_SETTINGS         0x05
138 #define CMD_ISA_RESET_PC                0x06
139 #define CMD_ISA_ARM_0                   0x07
140 #define CMD_ISA_ARM_30                  0x08
141 #define CMD_ISA_ARM_60                  0x09
142 #define CMD_ISA_DELAY_TIME_2SECS        0x0A
143 #define CMD_ISA_DELAY_TIME_4SECS        0x0B
144 #define CMD_ISA_DELAY_TIME_8SECS        0x0C
145 #define CMD_ISA_RESET_RELAYS            0x0D
146
147 /* Watchdog's Dip Switch heartbeat values */
148 static const int heartbeat_tbl[] = {
149         20,     /* OFF-OFF-OFF  = 20 Sec  */
150         40,     /* OFF-OFF-ON   = 40 Sec  */
151         60,     /* OFF-ON-OFF   =  1 Min  */
152         300,    /* OFF-ON-ON    =  5 Min  */
153         600,    /* ON-OFF-OFF   = 10 Min  */
154         1800,   /* ON-OFF-ON    = 30 Min  */
155         3600,   /* ON-ON-OFF    =  1 Hour */
156         7200,   /* ON-ON-ON     =  2 hour */
157 };
158
159 /*
160  * We are using an kernel timer to do the pinging of the watchdog
161  * every ~500ms. We try to set the internal heartbeat of the
162  * watchdog to 2 ms.
163  */
164
165 #define WDT_INTERVAL (HZ/2+1)
166
167 /* We can only use 1 card due to the /dev/watchdog restriction */
168 static int cards_found;
169
170 /* internal variables */
171 static unsigned long open_allowed;
172 static char expect_close;
173 static int temp_panic;
174
175 /* this is private data for each ISA-PC watchdog card */
176 static struct {
177         char fw_ver_str[6];             /* The cards firmware version */
178         int revision;                   /* The card's revision */
179         int supports_temp;              /* Whether or not the card has
180                                                 a temperature device */
181         int command_mode;               /* Whether or not the card is in
182                                                 command mode */
183         int boot_status;                /* The card's boot status */
184         int io_addr;                    /* The cards I/O address */
185         spinlock_t io_lock;             /* the lock for io operations */
186         struct timer_list timer;        /* The timer that pings the watchdog */
187         unsigned long next_heartbeat;   /* the next_heartbeat for the timer */
188 } pcwd_private;
189
190 /* module parameters */
191 #define QUIET   0       /* Default */
192 #define VERBOSE 1       /* Verbose */
193 #define DEBUG   2       /* print fancy stuff too */
194 static int debug = QUIET;
195 module_param(debug, int, 0);
196 MODULE_PARM_DESC(debug,
197                 "Debug level: 0=Quiet, 1=Verbose, 2=Debug (default=0)");
198
199 /* default heartbeat = delay-time from dip-switches */
200 #define WATCHDOG_HEARTBEAT 0
201 static int heartbeat = WATCHDOG_HEARTBEAT;
202 module_param(heartbeat, int, 0);
203 MODULE_PARM_DESC(heartbeat, "Watchdog heartbeat in seconds. "
204         "(2 <= heartbeat <= 7200 or 0=delay-time from dip-switches, default="
205                                 __MODULE_STRING(WATCHDOG_HEARTBEAT) ")");
206
207 static bool nowayout = WATCHDOG_NOWAYOUT;
208 module_param(nowayout, bool, 0);
209 MODULE_PARM_DESC(nowayout,
210                 "Watchdog cannot be stopped once started (default="
211                                 __MODULE_STRING(WATCHDOG_NOWAYOUT) ")");
212
213 /*
214  *      Internal functions
215  */
216
217 static int send_isa_command(int cmd)
218 {
219         int i;
220         int control_status;
221         int port0, last_port0;  /* Double read for stabilising */
222
223         if (debug >= DEBUG)
224                 pr_debug("sending following data cmd=0x%02x\n", cmd);
225
226         /* The WCMD bit must be 1 and the command is only 4 bits in size */
227         control_status = (cmd & 0x0F) | WD_WCMD;
228         outb_p(control_status, pcwd_private.io_addr + 2);
229         udelay(ISA_COMMAND_TIMEOUT);
230
231         port0 = inb_p(pcwd_private.io_addr);
232         for (i = 0; i < 25; ++i) {
233                 last_port0 = port0;
234                 port0 = inb_p(pcwd_private.io_addr);
235
236                 if (port0 == last_port0)
237                         break;  /* Data is stable */
238
239                 udelay(250);
240         }
241
242         if (debug >= DEBUG)
243                 pr_debug("received following data for cmd=0x%02x: port0=0x%02x last_port0=0x%02x\n",
244                          cmd, port0, last_port0);
245
246         return port0;
247 }
248
249 static int set_command_mode(void)
250 {
251         int i, found = 0, count = 0;
252
253         /* Set the card into command mode */
254         spin_lock(&pcwd_private.io_lock);
255         while ((!found) && (count < 3)) {
256                 i = send_isa_command(CMD_ISA_IDLE);
257
258                 if (i == 0x00)
259                         found = 1;
260                 else if (i == 0xF3) {
261                         /* Card does not like what we've done to it */
262                         outb_p(0x00, pcwd_private.io_addr + 2);
263                         udelay(1200);   /* Spec says wait 1ms */
264                         outb_p(0x00, pcwd_private.io_addr + 2);
265                         udelay(ISA_COMMAND_TIMEOUT);
266                 }
267                 count++;
268         }
269         spin_unlock(&pcwd_private.io_lock);
270         pcwd_private.command_mode = found;
271
272         if (debug >= DEBUG)
273                 pr_debug("command_mode=%d\n", pcwd_private.command_mode);
274
275         return found;
276 }
277
278 static void unset_command_mode(void)
279 {
280         /* Set the card into normal mode */
281         spin_lock(&pcwd_private.io_lock);
282         outb_p(0x00, pcwd_private.io_addr + 2);
283         udelay(ISA_COMMAND_TIMEOUT);
284         spin_unlock(&pcwd_private.io_lock);
285
286         pcwd_private.command_mode = 0;
287
288         if (debug >= DEBUG)
289                 pr_debug("command_mode=%d\n", pcwd_private.command_mode);
290 }
291
292 static inline void pcwd_check_temperature_support(void)
293 {
294         if (inb(pcwd_private.io_addr) != 0xF0)
295                 pcwd_private.supports_temp = 1;
296 }
297
298 static inline void pcwd_get_firmware(void)
299 {
300         int one, ten, hund, minor;
301
302         strcpy(pcwd_private.fw_ver_str, "ERROR");
303
304         if (set_command_mode()) {
305                 one = send_isa_command(CMD_ISA_VERSION_INTEGER);
306                 ten = send_isa_command(CMD_ISA_VERSION_TENTH);
307                 hund = send_isa_command(CMD_ISA_VERSION_HUNDRETH);
308                 minor = send_isa_command(CMD_ISA_VERSION_MINOR);
309                 sprintf(pcwd_private.fw_ver_str, "%c.%c%c%c",
310                                         one, ten, hund, minor);
311         }
312         unset_command_mode();
313
314         return;
315 }
316
317 static inline int pcwd_get_option_switches(void)
318 {
319         int option_switches = 0;
320
321         if (set_command_mode()) {
322                 /* Get switch settings */
323                 option_switches = send_isa_command(CMD_ISA_SWITCH_SETTINGS);
324         }
325
326         unset_command_mode();
327         return option_switches;
328 }
329
330 static void pcwd_show_card_info(void)
331 {
332         int option_switches;
333
334         /* Get some extra info from the hardware (in command/debug/diag mode) */
335         if (pcwd_private.revision == PCWD_REVISION_A)
336                 pr_info("ISA-PC Watchdog (REV.A) detected at port 0x%04x\n",
337                         pcwd_private.io_addr);
338         else if (pcwd_private.revision == PCWD_REVISION_C) {
339                 pcwd_get_firmware();
340                 pr_info("ISA-PC Watchdog (REV.C) detected at port 0x%04x (Firmware version: %s)\n",
341                         pcwd_private.io_addr, pcwd_private.fw_ver_str);
342                 option_switches = pcwd_get_option_switches();
343                 pr_info("Option switches (0x%02x): Temperature Reset Enable=%s, Power On Delay=%s\n",
344                         option_switches,
345                         ((option_switches & 0x10) ? "ON" : "OFF"),
346                         ((option_switches & 0x08) ? "ON" : "OFF"));
347
348                 /* Reprogram internal heartbeat to 2 seconds */
349                 if (set_command_mode()) {
350                         send_isa_command(CMD_ISA_DELAY_TIME_2SECS);
351                         unset_command_mode();
352                 }
353         }
354
355         if (pcwd_private.supports_temp)
356                 pr_info("Temperature Option Detected\n");
357
358         if (pcwd_private.boot_status & WDIOF_CARDRESET)
359                 pr_info("Previous reboot was caused by the card\n");
360
361         if (pcwd_private.boot_status & WDIOF_OVERHEAT) {
362                 pr_emerg("Card senses a CPU Overheat. Panicking!\n");
363                 pr_emerg("CPU Overheat\n");
364         }
365
366         if (pcwd_private.boot_status == 0)
367                 pr_info("No previous trip detected - Cold boot or reset\n");
368 }
369
370 static void pcwd_timer_ping(unsigned long data)
371 {
372         int wdrst_stat;
373
374         /* If we got a heartbeat pulse within the WDT_INTERVAL
375          * we agree to ping the WDT */
376         if (time_before(jiffies, pcwd_private.next_heartbeat)) {
377                 /* Ping the watchdog */
378                 spin_lock(&pcwd_private.io_lock);
379                 if (pcwd_private.revision == PCWD_REVISION_A) {
380                         /*  Rev A cards are reset by setting the
381                             WD_WDRST bit in register 1 */
382                         wdrst_stat = inb_p(pcwd_private.io_addr);
383                         wdrst_stat &= 0x0F;
384                         wdrst_stat |= WD_WDRST;
385
386                         outb_p(wdrst_stat, pcwd_private.io_addr + 1);
387                 } else {
388                         /* Re-trigger watchdog by writing to port 0 */
389                         outb_p(0x00, pcwd_private.io_addr);
390                 }
391
392                 /* Re-set the timer interval */
393                 mod_timer(&pcwd_private.timer, jiffies + WDT_INTERVAL);
394
395                 spin_unlock(&pcwd_private.io_lock);
396         } else {
397                 pr_warn("Heartbeat lost! Will not ping the watchdog\n");
398         }
399 }
400
401 static int pcwd_start(void)
402 {
403         int stat_reg;
404
405         pcwd_private.next_heartbeat = jiffies + (heartbeat * HZ);
406
407         /* Start the timer */
408         mod_timer(&pcwd_private.timer, jiffies + WDT_INTERVAL);
409
410         /* Enable the port */
411         if (pcwd_private.revision == PCWD_REVISION_C) {
412                 spin_lock(&pcwd_private.io_lock);
413                 outb_p(0x00, pcwd_private.io_addr + 3);
414                 udelay(ISA_COMMAND_TIMEOUT);
415                 stat_reg = inb_p(pcwd_private.io_addr + 2);
416                 spin_unlock(&pcwd_private.io_lock);
417                 if (stat_reg & WD_WDIS) {
418                         pr_info("Could not start watchdog\n");
419                         return -EIO;
420                 }
421         }
422
423         if (debug >= VERBOSE)
424                 pr_debug("Watchdog started\n");
425
426         return 0;
427 }
428
429 static int pcwd_stop(void)
430 {
431         int stat_reg;
432
433         /* Stop the timer */
434         del_timer(&pcwd_private.timer);
435
436         /*  Disable the board  */
437         if (pcwd_private.revision == PCWD_REVISION_C) {
438                 spin_lock(&pcwd_private.io_lock);
439                 outb_p(0xA5, pcwd_private.io_addr + 3);
440                 udelay(ISA_COMMAND_TIMEOUT);
441                 outb_p(0xA5, pcwd_private.io_addr + 3);
442                 udelay(ISA_COMMAND_TIMEOUT);
443                 stat_reg = inb_p(pcwd_private.io_addr + 2);
444                 spin_unlock(&pcwd_private.io_lock);
445                 if ((stat_reg & WD_WDIS) == 0) {
446                         pr_info("Could not stop watchdog\n");
447                         return -EIO;
448                 }
449         }
450
451         if (debug >= VERBOSE)
452                 pr_debug("Watchdog stopped\n");
453
454         return 0;
455 }
456
457 static int pcwd_keepalive(void)
458 {
459         /* user land ping */
460         pcwd_private.next_heartbeat = jiffies + (heartbeat * HZ);
461
462         if (debug >= DEBUG)
463                 pr_debug("Watchdog keepalive signal send\n");
464
465         return 0;
466 }
467
468 static int pcwd_set_heartbeat(int t)
469 {
470         if (t < 2 || t > 7200) /* arbitrary upper limit */
471                 return -EINVAL;
472
473         heartbeat = t;
474
475         if (debug >= VERBOSE)
476                 pr_debug("New heartbeat: %d\n", heartbeat);
477
478         return 0;
479 }
480
481 static int pcwd_get_status(int *status)
482 {
483         int control_status;
484
485         *status = 0;
486         spin_lock(&pcwd_private.io_lock);
487         if (pcwd_private.revision == PCWD_REVISION_A)
488                 /* Rev A cards return status information from
489                  * the base register, which is used for the
490                  * temperature in other cards. */
491                 control_status = inb(pcwd_private.io_addr);
492         else {
493                 /* Rev C cards return card status in the base
494                  * address + 1 register. And use different bits
495                  * to indicate a card initiated reset, and an
496                  * over-temperature condition. And the reboot
497                  * status can be reset. */
498                 control_status = inb(pcwd_private.io_addr + 1);
499         }
500         spin_unlock(&pcwd_private.io_lock);
501
502         if (pcwd_private.revision == PCWD_REVISION_A) {
503                 if (control_status & WD_WDRST)
504                         *status |= WDIOF_CARDRESET;
505
506                 if (control_status & WD_T110) {
507                         *status |= WDIOF_OVERHEAT;
508                         if (temp_panic) {
509                                 pr_info("Temperature overheat trip!\n");
510                                 kernel_power_off();
511                         }
512                 }
513         } else {
514                 if (control_status & WD_REVC_WTRP)
515                         *status |= WDIOF_CARDRESET;
516
517                 if (control_status & WD_REVC_TTRP) {
518                         *status |= WDIOF_OVERHEAT;
519                         if (temp_panic) {
520                                 pr_info("Temperature overheat trip!\n");
521                                 kernel_power_off();
522                         }
523                 }
524         }
525
526         return 0;
527 }
528
529 static int pcwd_clear_status(void)
530 {
531         int control_status;
532
533         if (pcwd_private.revision == PCWD_REVISION_C) {
534                 spin_lock(&pcwd_private.io_lock);
535
536                 if (debug >= VERBOSE)
537                         pr_info("clearing watchdog trip status\n");
538
539                 control_status = inb_p(pcwd_private.io_addr + 1);
540
541                 if (debug >= DEBUG) {
542                         pr_debug("status was: 0x%02x\n", control_status);
543                         pr_debug("sending: 0x%02x\n",
544                                  (control_status & WD_REVC_R2DS));
545                 }
546
547                 /* clear reset status & Keep Relay 2 disable state as it is */
548                 outb_p((control_status & WD_REVC_R2DS),
549                                                 pcwd_private.io_addr + 1);
550
551                 spin_unlock(&pcwd_private.io_lock);
552         }
553         return 0;
554 }
555
556 static int pcwd_get_temperature(int *temperature)
557 {
558         /* check that port 0 gives temperature info and no command results */
559         if (pcwd_private.command_mode)
560                 return -1;
561
562         *temperature = 0;
563         if (!pcwd_private.supports_temp)
564                 return -ENODEV;
565
566         /*
567          * Convert celsius to fahrenheit, since this was
568          * the decided 'standard' for this return value.
569          */
570         spin_lock(&pcwd_private.io_lock);
571         *temperature = ((inb(pcwd_private.io_addr)) * 9 / 5) + 32;
572         spin_unlock(&pcwd_private.io_lock);
573
574         if (debug >= DEBUG) {
575                 pr_debug("temperature is: %d F\n", *temperature);
576         }
577
578         return 0;
579 }
580
581 /*
582  *      /dev/watchdog handling
583  */
584
585 static long pcwd_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
586 {
587         int rv;
588         int status;
589         int temperature;
590         int new_heartbeat;
591         int __user *argp = (int __user *)arg;
592         static const struct watchdog_info ident = {
593                 .options =              WDIOF_OVERHEAT |
594                                         WDIOF_CARDRESET |
595                                         WDIOF_KEEPALIVEPING |
596                                         WDIOF_SETTIMEOUT |
597                                         WDIOF_MAGICCLOSE,
598                 .firmware_version =     1,
599                 .identity =             "PCWD",
600         };
601
602         switch (cmd) {
603         case WDIOC_GETSUPPORT:
604                 if (copy_to_user(argp, &ident, sizeof(ident)))
605                         return -EFAULT;
606                 return 0;
607
608         case WDIOC_GETSTATUS:
609                 pcwd_get_status(&status);
610                 return put_user(status, argp);
611
612         case WDIOC_GETBOOTSTATUS:
613                 return put_user(pcwd_private.boot_status, argp);
614
615         case WDIOC_GETTEMP:
616                 if (pcwd_get_temperature(&temperature))
617                         return -EFAULT;
618
619                 return put_user(temperature, argp);
620
621         case WDIOC_SETOPTIONS:
622                 if (pcwd_private.revision == PCWD_REVISION_C) {
623                         if (get_user(rv, argp))
624                                 return -EFAULT;
625
626                         if (rv & WDIOS_DISABLECARD) {
627                                 status = pcwd_stop();
628                                 if (status < 0)
629                                         return status;
630                         }
631                         if (rv & WDIOS_ENABLECARD) {
632                                 status = pcwd_start();
633                                 if (status < 0)
634                                         return status;
635                         }
636                         if (rv & WDIOS_TEMPPANIC)
637                                 temp_panic = 1;
638                 }
639                 return -EINVAL;
640
641         case WDIOC_KEEPALIVE:
642                 pcwd_keepalive();
643                 return 0;
644
645         case WDIOC_SETTIMEOUT:
646                 if (get_user(new_heartbeat, argp))
647                         return -EFAULT;
648
649                 if (pcwd_set_heartbeat(new_heartbeat))
650                         return -EINVAL;
651
652                 pcwd_keepalive();
653                 /* Fall */
654
655         case WDIOC_GETTIMEOUT:
656                 return put_user(heartbeat, argp);
657
658         default:
659                 return -ENOTTY;
660         }
661
662         return 0;
663 }
664
665 static ssize_t pcwd_write(struct file *file, const char __user *buf, size_t len,
666                           loff_t *ppos)
667 {
668         if (len) {
669                 if (!nowayout) {
670                         size_t i;
671
672                         /* In case it was set long ago */
673                         expect_close = 0;
674
675                         for (i = 0; i != len; i++) {
676                                 char c;
677
678                                 if (get_user(c, buf + i))
679                                         return -EFAULT;
680                                 if (c == 'V')
681                                         expect_close = 42;
682                         }
683                 }
684                 pcwd_keepalive();
685         }
686         return len;
687 }
688
689 static int pcwd_open(struct inode *inode, struct file *file)
690 {
691         if (test_and_set_bit(0, &open_allowed))
692                 return -EBUSY;
693         if (nowayout)
694                 __module_get(THIS_MODULE);
695         /* Activate */
696         pcwd_start();
697         pcwd_keepalive();
698         return nonseekable_open(inode, file);
699 }
700
701 static int pcwd_close(struct inode *inode, struct file *file)
702 {
703         if (expect_close == 42)
704                 pcwd_stop();
705         else {
706                 pr_crit("Unexpected close, not stopping watchdog!\n");
707                 pcwd_keepalive();
708         }
709         expect_close = 0;
710         clear_bit(0, &open_allowed);
711         return 0;
712 }
713
714 /*
715  *      /dev/temperature handling
716  */
717
718 static ssize_t pcwd_temp_read(struct file *file, char __user *buf, size_t count,
719                          loff_t *ppos)
720 {
721         int temperature;
722
723         if (pcwd_get_temperature(&temperature))
724                 return -EFAULT;
725
726         if (copy_to_user(buf, &temperature, 1))
727                 return -EFAULT;
728
729         return 1;
730 }
731
732 static int pcwd_temp_open(struct inode *inode, struct file *file)
733 {
734         if (!pcwd_private.supports_temp)
735                 return -ENODEV;
736
737         return nonseekable_open(inode, file);
738 }
739
740 static int pcwd_temp_close(struct inode *inode, struct file *file)
741 {
742         return 0;
743 }
744
745 /*
746  *      Kernel Interfaces
747  */
748
749 static const struct file_operations pcwd_fops = {
750         .owner          = THIS_MODULE,
751         .llseek         = no_llseek,
752         .write          = pcwd_write,
753         .unlocked_ioctl = pcwd_ioctl,
754         .open           = pcwd_open,
755         .release        = pcwd_close,
756 };
757
758 static struct miscdevice pcwd_miscdev = {
759         .minor =        WATCHDOG_MINOR,
760         .name =         "watchdog",
761         .fops =         &pcwd_fops,
762 };
763
764 static const struct file_operations pcwd_temp_fops = {
765         .owner          = THIS_MODULE,
766         .llseek         = no_llseek,
767         .read           = pcwd_temp_read,
768         .open           = pcwd_temp_open,
769         .release        = pcwd_temp_close,
770 };
771
772 static struct miscdevice temp_miscdev = {
773         .minor =        TEMP_MINOR,
774         .name =         "temperature",
775         .fops =         &pcwd_temp_fops,
776 };
777
778 /*
779  *      Init & exit routines
780  */
781
782 static inline int get_revision(void)
783 {
784         int r = PCWD_REVISION_C;
785
786         spin_lock(&pcwd_private.io_lock);
787         /* REV A cards use only 2 io ports; test
788          * presumes a floating bus reads as 0xff. */
789         if ((inb(pcwd_private.io_addr + 2) == 0xFF) ||
790             (inb(pcwd_private.io_addr + 3) == 0xFF))
791                 r = PCWD_REVISION_A;
792         spin_unlock(&pcwd_private.io_lock);
793
794         return r;
795 }
796
797 /*
798  *  The ISA cards have a heartbeat bit in one of the registers, which
799  *  register is card dependent.  The heartbeat bit is monitored, and if
800  *  found, is considered proof that a Berkshire card has been found.
801  *  The initial rate is once per second at board start up, then twice
802  *  per second for normal operation.
803  */
804 static int pcwd_isa_match(struct device *dev, unsigned int id)
805 {
806         int base_addr = pcwd_ioports[id];
807         int port0, last_port0;  /* Reg 0, in case it's REV A */
808         int port1, last_port1;  /* Register 1 for REV C cards */
809         int i;
810         int retval;
811
812         if (debug >= DEBUG)
813                 pr_debug("pcwd_isa_match id=%d\n", id);
814
815         if (!request_region(base_addr, 4, "PCWD")) {
816                 pr_info("Port 0x%04x unavailable\n", base_addr);
817                 return 0;
818         }
819
820         retval = 0;
821
822         port0 = inb_p(base_addr);       /* For REV A boards */
823         port1 = inb_p(base_addr + 1);   /* For REV C boards */
824         if (port0 != 0xff || port1 != 0xff) {
825                 /* Not an 'ff' from a floating bus, so must be a card! */
826                 for (i = 0; i < 4; ++i) {
827
828                         msleep(500);
829
830                         last_port0 = port0;
831                         last_port1 = port1;
832
833                         port0 = inb_p(base_addr);
834                         port1 = inb_p(base_addr + 1);
835
836                         /* Has either hearbeat bit changed?  */
837                         if ((port0 ^ last_port0) & WD_HRTBT ||
838                             (port1 ^ last_port1) & WD_REVC_HRBT) {
839                                 retval = 1;
840                                 break;
841                         }
842                 }
843         }
844         release_region(base_addr, 4);
845
846         return retval;
847 }
848
849 static int pcwd_isa_probe(struct device *dev, unsigned int id)
850 {
851         int ret;
852
853         if (debug >= DEBUG)
854                 pr_debug("pcwd_isa_probe id=%d\n", id);
855
856         cards_found++;
857         if (cards_found == 1)
858                 pr_info("v%s Ken Hollis (kenji@bitgate.com)\n",
859                                                         WATCHDOG_VERSION);
860
861         if (cards_found > 1) {
862                 pr_err("This driver only supports 1 device\n");
863                 return -ENODEV;
864         }
865
866         if (pcwd_ioports[id] == 0x0000) {
867                 pr_err("No I/O-Address for card detected\n");
868                 return -ENODEV;
869         }
870         pcwd_private.io_addr = pcwd_ioports[id];
871
872         spin_lock_init(&pcwd_private.io_lock);
873
874         /* Check card's revision */
875         pcwd_private.revision = get_revision();
876
877         if (!request_region(pcwd_private.io_addr,
878                 (pcwd_private.revision == PCWD_REVISION_A) ? 2 : 4, "PCWD")) {
879                 pr_err("I/O address 0x%04x already in use\n",
880                        pcwd_private.io_addr);
881                 ret = -EIO;
882                 goto error_request_region;
883         }
884
885         /* Initial variables */
886         pcwd_private.supports_temp = 0;
887         temp_panic = 0;
888         pcwd_private.boot_status = 0x0000;
889
890         /* get the boot_status */
891         pcwd_get_status(&pcwd_private.boot_status);
892
893         /* clear the "card caused reboot" flag */
894         pcwd_clear_status();
895
896         setup_timer(&pcwd_private.timer, pcwd_timer_ping, 0);
897
898         /*  Disable the board  */
899         pcwd_stop();
900
901         /*  Check whether or not the card supports the temperature device */
902         pcwd_check_temperature_support();
903
904         /* Show info about the card itself */
905         pcwd_show_card_info();
906
907         /* If heartbeat = 0 then we use the heartbeat from the dip-switches */
908         if (heartbeat == 0)
909                 heartbeat = heartbeat_tbl[(pcwd_get_option_switches() & 0x07)];
910
911         /* Check that the heartbeat value is within it's range;
912            if not reset to the default */
913         if (pcwd_set_heartbeat(heartbeat)) {
914                 pcwd_set_heartbeat(WATCHDOG_HEARTBEAT);
915                 pr_info("heartbeat value must be 2 <= heartbeat <= 7200, using %d\n",
916                         WATCHDOG_HEARTBEAT);
917         }
918
919         if (pcwd_private.supports_temp) {
920                 ret = misc_register(&temp_miscdev);
921                 if (ret) {
922                         pr_err("cannot register miscdev on minor=%d (err=%d)\n",
923                                TEMP_MINOR, ret);
924                         goto error_misc_register_temp;
925                 }
926         }
927
928         ret = misc_register(&pcwd_miscdev);
929         if (ret) {
930                 pr_err("cannot register miscdev on minor=%d (err=%d)\n",
931                        WATCHDOG_MINOR, ret);
932                 goto error_misc_register_watchdog;
933         }
934
935         pr_info("initialized. heartbeat=%d sec (nowayout=%d)\n",
936                 heartbeat, nowayout);
937
938         return 0;
939
940 error_misc_register_watchdog:
941         if (pcwd_private.supports_temp)
942                 misc_deregister(&temp_miscdev);
943 error_misc_register_temp:
944         release_region(pcwd_private.io_addr,
945                         (pcwd_private.revision == PCWD_REVISION_A) ? 2 : 4);
946 error_request_region:
947         pcwd_private.io_addr = 0x0000;
948         cards_found--;
949         return ret;
950 }
951
952 static int pcwd_isa_remove(struct device *dev, unsigned int id)
953 {
954         if (debug >= DEBUG)
955                 pr_debug("pcwd_isa_remove id=%d\n", id);
956
957         if (!pcwd_private.io_addr)
958                 return 1;
959
960         /*  Disable the board  */
961         if (!nowayout)
962                 pcwd_stop();
963
964         /* Deregister */
965         misc_deregister(&pcwd_miscdev);
966         if (pcwd_private.supports_temp)
967                 misc_deregister(&temp_miscdev);
968         release_region(pcwd_private.io_addr,
969                         (pcwd_private.revision == PCWD_REVISION_A) ? 2 : 4);
970         pcwd_private.io_addr = 0x0000;
971         cards_found--;
972
973         return 0;
974 }
975
976 static void pcwd_isa_shutdown(struct device *dev, unsigned int id)
977 {
978         if (debug >= DEBUG)
979                 pr_debug("pcwd_isa_shutdown id=%d\n", id);
980
981         pcwd_stop();
982 }
983
984 static struct isa_driver pcwd_isa_driver = {
985         .match          = pcwd_isa_match,
986         .probe          = pcwd_isa_probe,
987         .remove         = pcwd_isa_remove,
988         .shutdown       = pcwd_isa_shutdown,
989         .driver         = {
990                 .owner  = THIS_MODULE,
991                 .name   = WATCHDOG_NAME,
992         },
993 };
994
995 static int __init pcwd_init_module(void)
996 {
997         return isa_register_driver(&pcwd_isa_driver, PCWD_ISA_NR_CARDS);
998 }
999
1000 static void __exit pcwd_cleanup_module(void)
1001 {
1002         isa_unregister_driver(&pcwd_isa_driver);
1003         pr_info("Watchdog Module Unloaded\n");
1004 }
1005
1006 module_init(pcwd_init_module);
1007 module_exit(pcwd_cleanup_module);
1008
1009 MODULE_AUTHOR("Ken Hollis <kenji@bitgate.com>, "
1010                 "Wim Van Sebroeck <wim@iguana.be>");
1011 MODULE_DESCRIPTION("Berkshire ISA-PC Watchdog driver");
1012 MODULE_VERSION(WATCHDOG_VERSION);
1013 MODULE_LICENSE("GPL");