// SPDX-License-Identifier: GPL-2.0-or-later /* * IT8712F "Smart Guardian" Watchdog support * * Copyright (c) 2006-2007 Jorge Boncompte - DTI2 <jorge@dti2.net> * * Based on info and code taken from: * * drivers/char/watchdog/scx200_wdt.c * drivers/hwmon/it87.c * IT8712F EC-LPC I/O Preliminary Specification 0.8.2 * IT8712F EC-LPC I/O Preliminary Specification 0.9.3 * * The author(s) of this software shall not be held liable for damages * of any nature resulting due to the use of this software. This * software is provided AS-IS with no warranties.
*/
#define WDT_RESET_GAME 0x10 /* Reset timer on read or write to game port */ #define WDT_RESET_KBD 0x20 /* Reset timer on keyboard interrupt */ #define WDT_RESET_MOUSE 0x40 /* Reset timer on mouse interrupt */ #define WDT_RESET_CIR 0x80 /* Reset timer on consumer IR interrupt */
#define WDT_UNIT_SEC 0x80 /* If 0 in MINUTES */
#define WDT_OUT_PWROK 0x10 /* Pulse PWROK on timeout */ #define WDT_OUT_KRST 0x40 /* Pulse reset on timeout */
staticint wdt_control_reg = WDT_RESET_GAME;
module_param(wdt_control_reg, int, 0);
MODULE_PARM_DESC(wdt_control_reg, "Value to write to watchdog control " "register. The default WDT_RESET_GAME resets the timer on " "game port reads that this driver generates. You can also " "use KBD, MOUSE or CIR if you have some external way to " "generate those interrupts.");
staticinlinevoid it8712f_wdt_ping(void)
{ if (wdt_control_reg & WDT_RESET_GAME)
inb(address);
}
staticvoid it8712f_wdt_update_margin(void)
{ int config = WDT_OUT_KRST | WDT_OUT_PWROK; int units = margin;
/* Switch to minutes precision if the configured margin * value does not fit within the register width.
*/ if (units <= max_units) {
config |= WDT_UNIT_SEC; /* else UNIT is MINUTES */
pr_info("timer margin %d seconds\n", units);
} else {
units /= 60;
pr_info("timer margin %d minutes\n", units);
}
superio_outb(config, WDT_CONFIG);
switch (cmd) { case WDIOC_GETSUPPORT: if (copy_to_user(argp, &ident, sizeof(ident))) return -EFAULT; return 0; case WDIOC_GETSTATUS:
ret = superio_enter(); if (ret) return ret;
superio_select(LDN_GPIO);
value = it8712f_wdt_get_status();
superio_exit();
return put_user(value, p); case WDIOC_GETBOOTSTATUS: return put_user(0, p); case WDIOC_KEEPALIVE:
it8712f_wdt_ping(); return 0; case WDIOC_SETTIMEOUT: if (get_user(value, p)) return -EFAULT; if (value < 1) return -EINVAL; if (value > (max_units * 60)) return -EINVAL;
margin = value;
ret = superio_enter(); if (ret) return ret;
superio_select(LDN_GPIO);
it8712f_wdt_update_margin();
superio_exit();
it8712f_wdt_ping();
fallthrough; case WDIOC_GETTIMEOUT: if (put_user(margin, p)) return -EFAULT; return 0; default: return -ENOTTY;
}
}
staticint it8712f_wdt_open(struct inode *inode, struct file *file)
{ int ret; /* only allow one at a time */ if (test_and_set_bit(0, &wdt_open)) return -EBUSY;
ret = it8712f_wdt_enable(); if (ret) return ret; return stream_open(inode, file);
}
staticint it8712f_wdt_release(struct inode *inode, struct file *file)
{ if (expect_close != 42) {
pr_warn("watchdog device closed unexpectedly, will not disable the watchdog timer\n");
} elseif (!nowayout) { if (it8712f_wdt_disable())
pr_warn("Watchdog disable failed\n");
}
expect_close = 0;
clear_bit(0, &wdt_open);
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.