Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

at v3.5-rc3 775 lines 18 kB view raw
1/* 2 * Watchdog Timer Driver 3 * for ITE IT87xx Environment Control - Low Pin Count Input / Output 4 * 5 * (c) Copyright 2007 Oliver Schuster <olivers137@aol.com> 6 * 7 * Based on softdog.c by Alan Cox, 8 * 83977f_wdt.c by Jose Goncalves, 9 * it87.c by Chris Gauthron, Jean Delvare 10 * 11 * Data-sheets: Publicly available at the ITE website 12 * http://www.ite.com.tw/ 13 * 14 * Support of the watchdog timers, which are available on 15 * IT8702, IT8712, IT8716, IT8718, IT8720, IT8721, IT8726 16 * and IT8728. 17 * 18 * This program is free software; you can redistribute it and/or 19 * modify it under the terms of the GNU General Public License 20 * as published by the Free Software Foundation; either version 21 * 2 of the License, or (at your option) any later version. 22 * 23 * This program is distributed in the hope that it will be useful, 24 * but WITHOUT ANY WARRANTY; without even the implied warranty of 25 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 26 * GNU General Public License for more details. 27 * 28 * You should have received a copy of the GNU General Public License 29 * along with this program; if not, write to the Free Software 30 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. 31 */ 32 33#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt 34 35#include <linux/module.h> 36#include <linux/moduleparam.h> 37#include <linux/types.h> 38#include <linux/kernel.h> 39#include <linux/fs.h> 40#include <linux/miscdevice.h> 41#include <linux/init.h> 42#include <linux/ioport.h> 43#include <linux/watchdog.h> 44#include <linux/notifier.h> 45#include <linux/reboot.h> 46#include <linux/uaccess.h> 47#include <linux/io.h> 48 49 50#define WATCHDOG_VERSION "1.14" 51#define WATCHDOG_NAME "IT87 WDT" 52#define DRIVER_VERSION WATCHDOG_NAME " driver, v" WATCHDOG_VERSION "\n" 53#define WD_MAGIC 'V' 54 55/* Defaults for Module Parameter */ 56#define DEFAULT_NOGAMEPORT 0 57#define DEFAULT_EXCLUSIVE 1 58#define DEFAULT_TIMEOUT 60 59#define DEFAULT_TESTMODE 0 60#define DEFAULT_NOWAYOUT WATCHDOG_NOWAYOUT 61 62/* IO Ports */ 63#define REG 0x2e 64#define VAL 0x2f 65 66/* Logical device Numbers LDN */ 67#define GPIO 0x07 68#define GAMEPORT 0x09 69#define CIR 0x0a 70 71/* Configuration Registers and Functions */ 72#define LDNREG 0x07 73#define CHIPID 0x20 74#define CHIPREV 0x22 75#define ACTREG 0x30 76#define BASEREG 0x60 77 78/* Chip Id numbers */ 79#define NO_DEV_ID 0xffff 80#define IT8702_ID 0x8702 81#define IT8705_ID 0x8705 82#define IT8712_ID 0x8712 83#define IT8716_ID 0x8716 84#define IT8718_ID 0x8718 85#define IT8720_ID 0x8720 86#define IT8721_ID 0x8721 87#define IT8726_ID 0x8726 /* the data sheet suggest wrongly 0x8716 */ 88#define IT8728_ID 0x8728 89 90/* GPIO Configuration Registers LDN=0x07 */ 91#define WDTCTRL 0x71 92#define WDTCFG 0x72 93#define WDTVALLSB 0x73 94#define WDTVALMSB 0x74 95 96/* GPIO Bits WDTCTRL */ 97#define WDT_CIRINT 0x80 98#define WDT_MOUSEINT 0x40 99#define WDT_KYBINT 0x20 100#define WDT_GAMEPORT 0x10 /* not in it8718, it8720, it8721, it8728 */ 101#define WDT_FORCE 0x02 102#define WDT_ZERO 0x01 103 104/* GPIO Bits WDTCFG */ 105#define WDT_TOV1 0x80 106#define WDT_KRST 0x40 107#define WDT_TOVE 0x20 108#define WDT_PWROK 0x10 /* not in it8721 */ 109#define WDT_INT_MASK 0x0f 110 111/* CIR Configuration Register LDN=0x0a */ 112#define CIR_ILS 0x70 113 114/* The default Base address is not always available, we use this */ 115#define CIR_BASE 0x0208 116 117/* CIR Controller */ 118#define CIR_DR(b) (b) 119#define CIR_IER(b) (b + 1) 120#define CIR_RCR(b) (b + 2) 121#define CIR_TCR1(b) (b + 3) 122#define CIR_TCR2(b) (b + 4) 123#define CIR_TSR(b) (b + 5) 124#define CIR_RSR(b) (b + 6) 125#define CIR_BDLR(b) (b + 5) 126#define CIR_BDHR(b) (b + 6) 127#define CIR_IIR(b) (b + 7) 128 129/* Default Base address of Game port */ 130#define GP_BASE_DEFAULT 0x0201 131 132/* wdt_status */ 133#define WDTS_TIMER_RUN 0 134#define WDTS_DEV_OPEN 1 135#define WDTS_KEEPALIVE 2 136#define WDTS_LOCKED 3 137#define WDTS_USE_GP 4 138#define WDTS_EXPECTED 5 139 140static unsigned int base, gpact, ciract, max_units, chip_type; 141static unsigned long wdt_status; 142 143static int nogameport = DEFAULT_NOGAMEPORT; 144static int exclusive = DEFAULT_EXCLUSIVE; 145static int timeout = DEFAULT_TIMEOUT; 146static int testmode = DEFAULT_TESTMODE; 147static bool nowayout = DEFAULT_NOWAYOUT; 148 149module_param(nogameport, int, 0); 150MODULE_PARM_DESC(nogameport, "Forbid the activation of game port, default=" 151 __MODULE_STRING(DEFAULT_NOGAMEPORT)); 152module_param(exclusive, int, 0); 153MODULE_PARM_DESC(exclusive, "Watchdog exclusive device open, default=" 154 __MODULE_STRING(DEFAULT_EXCLUSIVE)); 155module_param(timeout, int, 0); 156MODULE_PARM_DESC(timeout, "Watchdog timeout in seconds, default=" 157 __MODULE_STRING(DEFAULT_TIMEOUT)); 158module_param(testmode, int, 0); 159MODULE_PARM_DESC(testmode, "Watchdog test mode (1 = no reboot), default=" 160 __MODULE_STRING(DEFAULT_TESTMODE)); 161module_param(nowayout, bool, 0); 162MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started, default=" 163 __MODULE_STRING(WATCHDOG_NOWAYOUT)); 164 165/* Superio Chip */ 166 167static inline int superio_enter(void) 168{ 169 /* 170 * Try to reserve REG and REG + 1 for exclusive access. 171 */ 172 if (!request_muxed_region(REG, 2, WATCHDOG_NAME)) 173 return -EBUSY; 174 175 outb(0x87, REG); 176 outb(0x01, REG); 177 outb(0x55, REG); 178 outb(0x55, REG); 179 return 0; 180} 181 182static inline void superio_exit(void) 183{ 184 outb(0x02, REG); 185 outb(0x02, VAL); 186 release_region(REG, 2); 187} 188 189static inline void superio_select(int ldn) 190{ 191 outb(LDNREG, REG); 192 outb(ldn, VAL); 193} 194 195static inline int superio_inb(int reg) 196{ 197 outb(reg, REG); 198 return inb(VAL); 199} 200 201static inline void superio_outb(int val, int reg) 202{ 203 outb(reg, REG); 204 outb(val, VAL); 205} 206 207static inline int superio_inw(int reg) 208{ 209 int val; 210 outb(reg++, REG); 211 val = inb(VAL) << 8; 212 outb(reg, REG); 213 val |= inb(VAL); 214 return val; 215} 216 217static inline void superio_outw(int val, int reg) 218{ 219 outb(reg++, REG); 220 outb(val >> 8, VAL); 221 outb(reg, REG); 222 outb(val, VAL); 223} 224 225/* Internal function, should be called after superio_select(GPIO) */ 226static void wdt_update_timeout(void) 227{ 228 unsigned char cfg = WDT_KRST; 229 int tm = timeout; 230 231 if (testmode) 232 cfg = 0; 233 234 if (tm <= max_units) 235 cfg |= WDT_TOV1; 236 else 237 tm /= 60; 238 239 if (chip_type != IT8721_ID) 240 cfg |= WDT_PWROK; 241 242 superio_outb(cfg, WDTCFG); 243 superio_outb(tm, WDTVALLSB); 244 if (max_units > 255) 245 superio_outb(tm>>8, WDTVALMSB); 246} 247 248static int wdt_round_time(int t) 249{ 250 t += 59; 251 t -= t % 60; 252 return t; 253} 254 255/* watchdog timer handling */ 256 257static void wdt_keepalive(void) 258{ 259 if (test_bit(WDTS_USE_GP, &wdt_status)) 260 inb(base); 261 else 262 /* The timer reloads with around 5 msec delay */ 263 outb(0x55, CIR_DR(base)); 264 set_bit(WDTS_KEEPALIVE, &wdt_status); 265} 266 267static int wdt_start(void) 268{ 269 int ret = superio_enter(); 270 if (ret) 271 return ret; 272 273 superio_select(GPIO); 274 if (test_bit(WDTS_USE_GP, &wdt_status)) 275 superio_outb(WDT_GAMEPORT, WDTCTRL); 276 else 277 superio_outb(WDT_CIRINT, WDTCTRL); 278 wdt_update_timeout(); 279 280 superio_exit(); 281 282 return 0; 283} 284 285static int wdt_stop(void) 286{ 287 int ret = superio_enter(); 288 if (ret) 289 return ret; 290 291 superio_select(GPIO); 292 superio_outb(0x00, WDTCTRL); 293 superio_outb(WDT_TOV1, WDTCFG); 294 superio_outb(0x00, WDTVALLSB); 295 if (max_units > 255) 296 superio_outb(0x00, WDTVALMSB); 297 298 superio_exit(); 299 return 0; 300} 301 302/** 303 * wdt_set_timeout - set a new timeout value with watchdog ioctl 304 * @t: timeout value in seconds 305 * 306 * The hardware device has a 8 or 16 bit watchdog timer (depends on 307 * chip version) that can be configured to count seconds or minutes. 308 * 309 * Used within WDIOC_SETTIMEOUT watchdog device ioctl. 310 */ 311 312static int wdt_set_timeout(int t) 313{ 314 if (t < 1 || t > max_units * 60) 315 return -EINVAL; 316 317 if (t > max_units) 318 timeout = wdt_round_time(t); 319 else 320 timeout = t; 321 322 if (test_bit(WDTS_TIMER_RUN, &wdt_status)) { 323 int ret = superio_enter(); 324 if (ret) 325 return ret; 326 327 superio_select(GPIO); 328 wdt_update_timeout(); 329 superio_exit(); 330 } 331 return 0; 332} 333 334/** 335 * wdt_get_status - determines the status supported by watchdog ioctl 336 * @status: status returned to user space 337 * 338 * The status bit of the device does not allow to distinguish 339 * between a regular system reset and a watchdog forced reset. 340 * But, in test mode it is useful, so it is supported through 341 * WDIOC_GETSTATUS watchdog ioctl. Additionally the driver 342 * reports the keepalive signal and the acception of the magic. 343 * 344 * Used within WDIOC_GETSTATUS watchdog device ioctl. 345 */ 346 347static int wdt_get_status(int *status) 348{ 349 *status = 0; 350 if (testmode) { 351 int ret = superio_enter(); 352 if (ret) 353 return ret; 354 355 superio_select(GPIO); 356 if (superio_inb(WDTCTRL) & WDT_ZERO) { 357 superio_outb(0x00, WDTCTRL); 358 clear_bit(WDTS_TIMER_RUN, &wdt_status); 359 *status |= WDIOF_CARDRESET; 360 } 361 362 superio_exit(); 363 } 364 if (test_and_clear_bit(WDTS_KEEPALIVE, &wdt_status)) 365 *status |= WDIOF_KEEPALIVEPING; 366 if (test_bit(WDTS_EXPECTED, &wdt_status)) 367 *status |= WDIOF_MAGICCLOSE; 368 return 0; 369} 370 371/* /dev/watchdog handling */ 372 373/** 374 * wdt_open - watchdog file_operations .open 375 * @inode: inode of the device 376 * @file: file handle to the device 377 * 378 * The watchdog timer starts by opening the device. 379 * 380 * Used within the file operation of the watchdog device. 381 */ 382 383static int wdt_open(struct inode *inode, struct file *file) 384{ 385 if (exclusive && test_and_set_bit(WDTS_DEV_OPEN, &wdt_status)) 386 return -EBUSY; 387 if (!test_and_set_bit(WDTS_TIMER_RUN, &wdt_status)) { 388 int ret; 389 if (nowayout && !test_and_set_bit(WDTS_LOCKED, &wdt_status)) 390 __module_get(THIS_MODULE); 391 392 ret = wdt_start(); 393 if (ret) { 394 clear_bit(WDTS_LOCKED, &wdt_status); 395 clear_bit(WDTS_TIMER_RUN, &wdt_status); 396 clear_bit(WDTS_DEV_OPEN, &wdt_status); 397 return ret; 398 } 399 } 400 return nonseekable_open(inode, file); 401} 402 403/** 404 * wdt_release - watchdog file_operations .release 405 * @inode: inode of the device 406 * @file: file handle to the device 407 * 408 * Closing the watchdog device either stops the watchdog timer 409 * or in the case, that nowayout is set or the magic character 410 * wasn't written, a critical warning about an running watchdog 411 * timer is given. 412 * 413 * Used within the file operation of the watchdog device. 414 */ 415 416static int wdt_release(struct inode *inode, struct file *file) 417{ 418 if (test_bit(WDTS_TIMER_RUN, &wdt_status)) { 419 if (test_and_clear_bit(WDTS_EXPECTED, &wdt_status)) { 420 int ret = wdt_stop(); 421 if (ret) { 422 /* 423 * Stop failed. Just keep the watchdog alive 424 * and hope nothing bad happens. 425 */ 426 set_bit(WDTS_EXPECTED, &wdt_status); 427 wdt_keepalive(); 428 return ret; 429 } 430 clear_bit(WDTS_TIMER_RUN, &wdt_status); 431 } else { 432 wdt_keepalive(); 433 pr_crit("unexpected close, not stopping watchdog!\n"); 434 } 435 } 436 clear_bit(WDTS_DEV_OPEN, &wdt_status); 437 return 0; 438} 439 440/** 441 * wdt_write - watchdog file_operations .write 442 * @file: file handle to the watchdog 443 * @buf: buffer to write 444 * @count: count of bytes 445 * @ppos: pointer to the position to write. No seeks allowed 446 * 447 * A write to a watchdog device is defined as a keepalive signal. Any 448 * write of data will do, as we don't define content meaning. 449 * 450 * Used within the file operation of the watchdog device. 451 */ 452 453static ssize_t wdt_write(struct file *file, const char __user *buf, 454 size_t count, loff_t *ppos) 455{ 456 if (count) { 457 clear_bit(WDTS_EXPECTED, &wdt_status); 458 wdt_keepalive(); 459 } 460 if (!nowayout) { 461 size_t ofs; 462 463 /* note: just in case someone wrote the magic character long ago */ 464 for (ofs = 0; ofs != count; ofs++) { 465 char c; 466 if (get_user(c, buf + ofs)) 467 return -EFAULT; 468 if (c == WD_MAGIC) 469 set_bit(WDTS_EXPECTED, &wdt_status); 470 } 471 } 472 return count; 473} 474 475static const struct watchdog_info ident = { 476 .options = WDIOF_SETTIMEOUT | WDIOF_MAGICCLOSE | WDIOF_KEEPALIVEPING, 477 .firmware_version = 1, 478 .identity = WATCHDOG_NAME, 479}; 480 481/** 482 * wdt_ioctl - watchdog file_operations .unlocked_ioctl 483 * @file: file handle to the device 484 * @cmd: watchdog command 485 * @arg: argument pointer 486 * 487 * The watchdog API defines a common set of functions for all watchdogs 488 * according to their available features. 489 * 490 * Used within the file operation of the watchdog device. 491 */ 492 493static long wdt_ioctl(struct file *file, unsigned int cmd, unsigned long arg) 494{ 495 int rc = 0, status, new_options, new_timeout; 496 union { 497 struct watchdog_info __user *ident; 498 int __user *i; 499 } uarg; 500 501 uarg.i = (int __user *)arg; 502 503 switch (cmd) { 504 case WDIOC_GETSUPPORT: 505 return copy_to_user(uarg.ident, 506 &ident, sizeof(ident)) ? -EFAULT : 0; 507 508 case WDIOC_GETSTATUS: 509 rc = wdt_get_status(&status); 510 if (rc) 511 return rc; 512 return put_user(status, uarg.i); 513 514 case WDIOC_GETBOOTSTATUS: 515 return put_user(0, uarg.i); 516 517 case WDIOC_KEEPALIVE: 518 wdt_keepalive(); 519 return 0; 520 521 case WDIOC_SETOPTIONS: 522 if (get_user(new_options, uarg.i)) 523 return -EFAULT; 524 525 switch (new_options) { 526 case WDIOS_DISABLECARD: 527 if (test_bit(WDTS_TIMER_RUN, &wdt_status)) { 528 rc = wdt_stop(); 529 if (rc) 530 return rc; 531 } 532 clear_bit(WDTS_TIMER_RUN, &wdt_status); 533 return 0; 534 535 case WDIOS_ENABLECARD: 536 if (!test_and_set_bit(WDTS_TIMER_RUN, &wdt_status)) { 537 rc = wdt_start(); 538 if (rc) { 539 clear_bit(WDTS_TIMER_RUN, &wdt_status); 540 return rc; 541 } 542 } 543 return 0; 544 545 default: 546 return -EFAULT; 547 } 548 549 case WDIOC_SETTIMEOUT: 550 if (get_user(new_timeout, uarg.i)) 551 return -EFAULT; 552 rc = wdt_set_timeout(new_timeout); 553 case WDIOC_GETTIMEOUT: 554 if (put_user(timeout, uarg.i)) 555 return -EFAULT; 556 return rc; 557 558 default: 559 return -ENOTTY; 560 } 561} 562 563static int wdt_notify_sys(struct notifier_block *this, unsigned long code, 564 void *unused) 565{ 566 if (code == SYS_DOWN || code == SYS_HALT) 567 wdt_stop(); 568 return NOTIFY_DONE; 569} 570 571static const struct file_operations wdt_fops = { 572 .owner = THIS_MODULE, 573 .llseek = no_llseek, 574 .write = wdt_write, 575 .unlocked_ioctl = wdt_ioctl, 576 .open = wdt_open, 577 .release = wdt_release, 578}; 579 580static struct miscdevice wdt_miscdev = { 581 .minor = WATCHDOG_MINOR, 582 .name = "watchdog", 583 .fops = &wdt_fops, 584}; 585 586static struct notifier_block wdt_notifier = { 587 .notifier_call = wdt_notify_sys, 588}; 589 590static int __init it87_wdt_init(void) 591{ 592 int rc = 0; 593 int try_gameport = !nogameport; 594 u8 chip_rev; 595 int gp_rreq_fail = 0; 596 597 wdt_status = 0; 598 599 rc = superio_enter(); 600 if (rc) 601 return rc; 602 603 chip_type = superio_inw(CHIPID); 604 chip_rev = superio_inb(CHIPREV) & 0x0f; 605 superio_exit(); 606 607 switch (chip_type) { 608 case IT8702_ID: 609 max_units = 255; 610 break; 611 case IT8712_ID: 612 max_units = (chip_rev < 8) ? 255 : 65535; 613 break; 614 case IT8716_ID: 615 case IT8726_ID: 616 max_units = 65535; 617 break; 618 case IT8718_ID: 619 case IT8720_ID: 620 case IT8721_ID: 621 case IT8728_ID: 622 max_units = 65535; 623 try_gameport = 0; 624 break; 625 case IT8705_ID: 626 pr_err("Unsupported Chip found, Chip %04x Revision %02x\n", 627 chip_type, chip_rev); 628 return -ENODEV; 629 case NO_DEV_ID: 630 pr_err("no device\n"); 631 return -ENODEV; 632 default: 633 pr_err("Unknown Chip found, Chip %04x Revision %04x\n", 634 chip_type, chip_rev); 635 return -ENODEV; 636 } 637 638 rc = superio_enter(); 639 if (rc) 640 return rc; 641 642 superio_select(GPIO); 643 superio_outb(WDT_TOV1, WDTCFG); 644 superio_outb(0x00, WDTCTRL); 645 646 /* First try to get Gameport support */ 647 if (try_gameport) { 648 superio_select(GAMEPORT); 649 base = superio_inw(BASEREG); 650 if (!base) { 651 base = GP_BASE_DEFAULT; 652 superio_outw(base, BASEREG); 653 } 654 gpact = superio_inb(ACTREG); 655 superio_outb(0x01, ACTREG); 656 if (request_region(base, 1, WATCHDOG_NAME)) 657 set_bit(WDTS_USE_GP, &wdt_status); 658 else 659 gp_rreq_fail = 1; 660 } 661 662 /* If we haven't Gameport support, try to get CIR support */ 663 if (!test_bit(WDTS_USE_GP, &wdt_status)) { 664 if (!request_region(CIR_BASE, 8, WATCHDOG_NAME)) { 665 if (gp_rreq_fail) 666 pr_err("I/O Address 0x%04x and 0x%04x already in use\n", 667 base, CIR_BASE); 668 else 669 pr_err("I/O Address 0x%04x already in use\n", 670 CIR_BASE); 671 rc = -EIO; 672 goto err_out; 673 } 674 base = CIR_BASE; 675 676 superio_select(CIR); 677 superio_outw(base, BASEREG); 678 superio_outb(0x00, CIR_ILS); 679 ciract = superio_inb(ACTREG); 680 superio_outb(0x01, ACTREG); 681 if (gp_rreq_fail) { 682 superio_select(GAMEPORT); 683 superio_outb(gpact, ACTREG); 684 } 685 } 686 687 if (timeout < 1 || timeout > max_units * 60) { 688 timeout = DEFAULT_TIMEOUT; 689 pr_warn("Timeout value out of range, use default %d sec\n", 690 DEFAULT_TIMEOUT); 691 } 692 693 if (timeout > max_units) 694 timeout = wdt_round_time(timeout); 695 696 rc = register_reboot_notifier(&wdt_notifier); 697 if (rc) { 698 pr_err("Cannot register reboot notifier (err=%d)\n", rc); 699 goto err_out_region; 700 } 701 702 rc = misc_register(&wdt_miscdev); 703 if (rc) { 704 pr_err("Cannot register miscdev on minor=%d (err=%d)\n", 705 wdt_miscdev.minor, rc); 706 goto err_out_reboot; 707 } 708 709 /* Initialize CIR to use it as keepalive source */ 710 if (!test_bit(WDTS_USE_GP, &wdt_status)) { 711 outb(0x00, CIR_RCR(base)); 712 outb(0xc0, CIR_TCR1(base)); 713 outb(0x5c, CIR_TCR2(base)); 714 outb(0x10, CIR_IER(base)); 715 outb(0x00, CIR_BDHR(base)); 716 outb(0x01, CIR_BDLR(base)); 717 outb(0x09, CIR_IER(base)); 718 } 719 720 pr_info("Chip IT%04x revision %d initialized. timeout=%d sec (nowayout=%d testmode=%d exclusive=%d nogameport=%d)\n", 721 chip_type, chip_rev, timeout, 722 nowayout, testmode, exclusive, nogameport); 723 724 superio_exit(); 725 return 0; 726 727err_out_reboot: 728 unregister_reboot_notifier(&wdt_notifier); 729err_out_region: 730 release_region(base, test_bit(WDTS_USE_GP, &wdt_status) ? 1 : 8); 731 if (!test_bit(WDTS_USE_GP, &wdt_status)) { 732 superio_select(CIR); 733 superio_outb(ciract, ACTREG); 734 } 735err_out: 736 if (try_gameport) { 737 superio_select(GAMEPORT); 738 superio_outb(gpact, ACTREG); 739 } 740 741 superio_exit(); 742 return rc; 743} 744 745static void __exit it87_wdt_exit(void) 746{ 747 if (superio_enter() == 0) { 748 superio_select(GPIO); 749 superio_outb(0x00, WDTCTRL); 750 superio_outb(0x00, WDTCFG); 751 superio_outb(0x00, WDTVALLSB); 752 if (max_units > 255) 753 superio_outb(0x00, WDTVALMSB); 754 if (test_bit(WDTS_USE_GP, &wdt_status)) { 755 superio_select(GAMEPORT); 756 superio_outb(gpact, ACTREG); 757 } else { 758 superio_select(CIR); 759 superio_outb(ciract, ACTREG); 760 } 761 superio_exit(); 762 } 763 764 misc_deregister(&wdt_miscdev); 765 unregister_reboot_notifier(&wdt_notifier); 766 release_region(base, test_bit(WDTS_USE_GP, &wdt_status) ? 1 : 8); 767} 768 769module_init(it87_wdt_init); 770module_exit(it87_wdt_exit); 771 772MODULE_AUTHOR("Oliver Schuster"); 773MODULE_DESCRIPTION("Hardware Watchdog Device Driver for IT87xx EC-LPC I/O"); 774MODULE_LICENSE("GPL"); 775MODULE_ALIAS_MISCDEV(WATCHDOG_MINOR);