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