diff -urpN --exclude-from=/home/davej/.exclude bk-linus/drivers/char/Kconfig move-watchdogs/drivers/char/Kconfig --- bk-linus/drivers/char/Kconfig 2002-11-22 11:00:41.000000000 -0100 +++ move-watchdogs/drivers/char/Kconfig 2002-11-22 10:15:39.000000000 -0100 @@ -636,289 +636,7 @@ comment "from the tpqic02-support packag comment "metalab.unc.edu or ftp://titus.cfw.com/pub/Linux/util/" depends on QIC02_TAPE && QIC02_DYNCONF - -menu "Watchdog Cards" - -config WATCHDOG - bool "Watchdog Timer Support" - ---help--- - If you say Y here (and to one of the following options) and create a - character special file /dev/watchdog with major number 10 and minor - number 130 using mknod ("man mknod"), you will get a watchdog, i.e.: - subsequently opening the file and then failing to write to it for - longer than 1 minute will result in rebooting the machine. This - could be useful for a networked machine that needs to come back - online as fast as possible after a lock-up. There's both a watchdog - implementation entirely in software (which can sometimes fail to - reboot the machine) and a driver for hardware watchdog boards, which - are more robust and can also keep track of the temperature inside - your computer. For details, read - in the kernel source. - - The watchdog is usually used together with the watchdog daemon - which is available from - . This daemon can - also monitor NFS connections and can reboot the machine when the process - table is full. - - If unsure, say N. - -config WATCHDOG_NOWAYOUT - bool "Disable watchdog shutdown on close" - depends on WATCHDOG - help - The default watchdog behaviour (which you get if you say N here) is - to stop the timer if the process managing it closes the file - /dev/watchdog. It's always remotely possible that this process might - get killed. If you say Y here, the watchdog cannot be stopped once - it has been started. - -config SOFT_WATCHDOG - tristate "Software watchdog" - depends on WATCHDOG - help - A software monitoring watchdog. This will fail to reboot your system - from some situations that the hardware watchdog will recover - from. Equally it's a lot cheaper to install. - - This driver is also available as a module ( = code which can be - inserted in and removed from the running kernel whenever you want). - If you want to compile it as a module, say M here and read - . The module will be called - softdog.o. - -config WDT - tristate "WDT Watchdog timer" - depends on WATCHDOG - ---help--- - If you have a WDT500P or WDT501P watchdog board, say Y here, - otherwise N. It is not possible to probe for this board, which means - that you have to inform the kernel about the IO port and IRQ using - the "wdt=" kernel option (try "man bootparam" or see the - documentation of your boot loader (lilo or loadlin) about how to - pass options to the kernel at boot time). - - If you want to compile this as a module ( = code which can be - inserted in and removed from the running kernel whenever you want), - say M here and read . The module - will be called wdt.o. - -config WDTPCI - tristate "WDT PCI Watchdog timer" - depends on WATCHDOG - ---help--- - If you have a PCI WDT500/501 watchdog board, say Y here, otherwise - N. It is not possible to probe for this board, which means that you - have to inform the kernel about the IO port and IRQ using the "wdt=" - kernel option (try "man bootparam" or see the documentation of your - boot loader (lilo or loadlin) about how to pass options to the - kernel at boot time). - - If you want to compile this as a module ( = code which can be - inserted in and removed from the running kernel whenever you want), - say M here and read . The module - will be called wdt_pci.o. - -config WDT_501 - bool "WDT501 features" - depends on WDT - help - Saying Y here and creating a character special file /dev/temperature - with major number 10 and minor number 131 ("man mknod") will give - you a thermometer inside your computer: reading from - /dev/temperature yields one byte, the temperature in degrees - Fahrenheit. This works only if you have a WDT501P watchdog board - installed. - -config WDT_501_FAN - bool "Fan Tachometer" - depends on WDT_501 - help - Enable the Fan Tachometer on the WDT501. Only do this if you have a - fan tachometer actually set up. - -config PCWATCHDOG - tristate "Berkshire Products PC Watchdog" - depends on WATCHDOG - ---help--- - This is the driver for the Berkshire Products PC Watchdog card. - This card simply watches your kernel to make sure it doesn't freeze, - and if it does, it reboots your computer after a certain amount of - time. This driver is like the WDT501 driver but for different - hardware. Please read . The PC - watchdog cards can be ordered from . - - This driver is also available as a module ( = code which can be - inserted in and removed from the running kernel whenever you want). - The module is called pcwd.o. If you want to compile it as a module, - say M here and read . - - Most people will say N. - -config ACQUIRE_WDT - tristate "Acquire SBC Watchdog Timer" - depends on WATCHDOG - ---help--- - This is the driver for the hardware watchdog on the PSC-6x86 Single - Board Computer produced by Acquire Inc (and others). This watchdog - simply watches your kernel to make sure it doesn't freeze, and if - it does, it reboots your computer after a certain amount of time. - - This driver is like the WDT501 driver but for different hardware. - This driver is also available as a module ( = code which can be - inserted in and removed from the running kernel whenever you want). - The module is called pscwdt.o. If you want to compile it as a - module, say M here and read . Most - people will say N. - -config ADVANTECH_WDT - tristate "Advantech SBC Watchdog Timer" - depends on WATCHDOG - help - If you are configuring a Linux kernel for the Advantech single-board - computer, say `Y' here to support its built-in watchdog timer - feature. See the help for CONFIG_WATCHDOG for discussion. - -config 21285_WATCHDOG - tristate "DC21285 watchdog" - depends on WATCHDOG && FOOTBRIDGE - help - The Intel Footbridge chip contains a builtin watchdog circuit. Say Y - here if you wish to use this. Alternatively say M to compile the - driver as a module, which will be called wdt285.o. - - This driver does not work on all machines. In particular, early CATS - boards have hardware problems that will cause the machine to simply - lock up if the watchdog fires. - - "If in doubt, leave it out" - say N. - -config 977_WATCHDOG - tristate "NetWinder WB83C977 watchdog" - depends on WATCHDOG && FOOTBRIDGE && ARCH_NETWINDER - help - Say Y here to include support for the WB977 watchdog included in - NetWinder machines. Alternatively say M to compile the driver as - a module, which will be called wdt977.o. - - Not sure? It's safe to say N. - -config EUROTECH_WDT - tristate "Eurotech CPU-1220/1410 Watchdog Timer" - depends on WATCHDOG - help - Enable support for the watchdog timer on the Eurotech CPU-1220 and - CPU-1410 cards. These are PC/104 SBCs. Spec sheets and product - information are at . - -config IB700_WDT - tristate "IB700 SBC Watchdog Timer" - depends on WATCHDOG - ---help--- - This is the driver for the hardware watchdog on the IB700 Single - Board Computer produced by TMC Technology (www.tmc-uk.com). This watchdog - simply watches your kernel to make sure it doesn't freeze, and if - it does, it reboots your computer after a certain amount of time. - - This driver is like the WDT501 driver but for slightly different hardware. - - This driver is also available as a module ( = code which can be - inserted in and removed from the running kernel whenever you want). - The module is called ib700wdt.o. If you want to compile it as a - module, say M here and read Documentation/modules.txt. Most people - will say N. - -config I810_TCO - tristate "Intel i810 TCO timer / Watchdog" - depends on WATCHDOG - ---help--- - Hardware driver for the TCO timer built into the Intel i810 and i815 - chipset family. The TCO (Total Cost of Ownership) timer is a - watchdog timer that will reboot the machine after its second - expiration. The expiration time can be configured by commandline - argument "i810_margin=" where is the counter initial value. - It is decremented every 0.6 secs, the default is 50 which gives a - timeout of 30 seconds and one minute until reset. - - On some motherboards the driver may fail to reset the chipset's - NO_REBOOT flag which prevents the watchdog from rebooting the - machine. If this is the case you will get a kernel message like - "i810tco init: failed to reset NO_REBOOT flag". - - If you want to compile this as a module, say M and read - . The module will be called - i810-tco.o. - -config MIXCOMWD - tristate "Mixcom Watchdog" - depends on WATCHDOG - ---help--- - This is a driver for the Mixcom hardware watchdog cards. This - watchdog simply watches your kernel to make sure it doesn't freeze, - and if it does, it reboots your computer after a certain amount of - time. - - This driver is also available as a module ( = code which can be - inserted in and removed from the running kernel whenever you want). - The module is called mixcomwd.o. If you want to compile it as a - module, say M here and read . Most - people will say N. - -config SCx200_WDT - tristate "NatSemi SCx200 Watchdog" - depends on WATCHDOG - help - Enable the built-in watchdog timer support on the National - Semiconductor SCx200 processors. - - If compiled as a module, it will be called scx200_watchdog.o. - -config 60XX_WDT - tristate "SBC-60XX Watchdog Timer" - depends on WATCHDOG - help - This driver can be used with the watchdog timer found on some - single board computers, namely the 6010 PII based computer. - It may well work with other cards. It reads port 0x443 to enable - and re-set the watchdog timer, and reads port 0x45 to disable - the watchdog. If you have a card that behave in similar ways, - you can probably make this driver work with your card as well. - - You can compile this driver directly into the kernel, or use - it as a module. The module will be called sbc60xxwdt.o. - -config W83877F_WDT - tristate "W83877F (EMACS) Watchdog Timer" - depends on WATCHDOG - ---help--- - This is the driver for the hardware watchdog on the W83877F chipset - as used in EMACS PC-104 motherboards (and likely others). This - watchdog simply watches your kernel to make sure it doesn't freeze, - and if it does, it reboots your computer after a certain amount of - time. - - This driver is also available as a module ( = code which can be - inserted in and removed from the running kernel whenever you want). - The module is called mixcomwd.o. If you want to compile it as a - module, say M here and read . Most - people will say N. - -config MACHZ_WDT - tristate "ZF MachZ Watchdog" - depends on WATCHDOG - ---help--- - If you are using a ZF Micro MachZ processor, say Y here, otherwise - N. This is the driver for the watchdog timer builtin on that - processor using ZF-Logic interface. This watchdog simply watches - your kernel to make sure it doesn't freeze, and if it does, it - reboots your computer after a certain amount of time. - - This driver is also available as a module ( = code which can be - inserted in and removed from the running kernel whenever you want). - The module is called machzwd.o. If you want to compile it as a - module, say M here and read . - -endmenu +source "drivers/char/watchdog/Kconfig" config DS1620 tristate "NetWinder thermometer support" diff -urpN --exclude-from=/home/davej/.exclude bk-linus/drivers/char/Makefile move-watchdogs/drivers/char/Makefile --- bk-linus/drivers/char/Makefile 2002-11-22 11:00:41.000000000 -0100 +++ move-watchdogs/drivers/char/Makefile 2002-11-22 10:53:07.000000000 -0100 @@ -77,32 +77,13 @@ obj-$(CONFIG_NWBUTTON) += nwbutton.o obj-$(CONFIG_NWFLASH) += nwflash.o obj-$(CONFIG_SCx200_GPIO) += scx200_gpio.o -# Only one watchdog can succeed. We probe the hardware watchdog -# drivers first, then the softdog driver. This means if your hardware -# watchdog dies or is 'borrowed' for some reason the software watchdog -# still gives you some cover. - -obj-$(CONFIG_PCWATCHDOG) += pcwd.o -obj-$(CONFIG_ACQUIRE_WDT) += acquirewdt.o -obj-$(CONFIG_ADVANTECH_WDT) += advantechwdt.o -obj-$(CONFIG_IB700_WDT) += ib700wdt.o -obj-$(CONFIG_MIXCOMWD) += mixcomwd.o -obj-$(CONFIG_SCx200_WDT) += scx200_wdt.o -obj-$(CONFIG_60XX_WDT) += sbc60xxwdt.o -obj-$(CONFIG_WDT) += wdt.o -obj-$(CONFIG_WDTPCI) += wdt_pci.o -obj-$(CONFIG_21285_WATCHDOG) += wdt285.o -obj-$(CONFIG_977_WATCHDOG) += wdt977.o -obj-$(CONFIG_I810_TCO) += i810-tco.o -obj-$(CONFIG_MACHZ_WDT) += machzwd.o -obj-$(CONFIG_SH_WDT) += shwdt.o -obj-$(CONFIG_EUROTECH_WDT) += eurotechwdt.o -obj-$(CONFIG_SOFT_WATCHDOG) += softdog.o +obj-$(CONFIG_WATCHDOG) += watchdog/ obj-$(CONFIG_MWAVE) += mwave/ obj-$(CONFIG_AGP) += agp/ obj-$(CONFIG_DRM) += drm/ obj-$(CONFIG_PCMCIA) += pcmcia/ + # Files generated that shall be removed upon make clean clean-files := consolemap_deftbl.c defkeymap.c qtronixmap.c diff -urpN --exclude-from=/home/davej/.exclude bk-linus/drivers/char/acquirewdt.c move-watchdogs/drivers/char/acquirewdt.c --- bk-linus/drivers/char/acquirewdt.c 2002-11-22 11:00:41.000000000 -0100 +++ move-watchdogs/drivers/char/acquirewdt.c 1969-12-31 23:00:00.000000000 -0100 @@ -1,251 +0,0 @@ -/* - * Acquire Single Board Computer Watchdog Timer driver for Linux 2.1.x - * - * Based on wdt.c. Original copyright messages: - * - * (c) Copyright 1996 Alan Cox , All Rights Reserved. - * http://www.redhat.com - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version - * 2 of the License, or (at your option) any later version. - * - * Neither Alan Cox nor CymruNet Ltd. admit liability nor provide - * warranty for any of this software. This material is provided - * "AS-IS" and at no charge. - * - * (c) Copyright 1995 Alan Cox - * - * 14-Dec-2001 Matt Domsch - * Added nowayout module option to override CONFIG_WATCHDOG_NOWAYOUT - * Can't add timeout - driver doesn't allow changing value - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -static int acq_is_open; -static spinlock_t acq_lock; - -/* - * You must set these - there is no sane way to probe for this board. - */ - -#define WDT_STOP 0x43 -#define WDT_START 0x443 - -#ifdef CONFIG_WATCHDOG_NOWAYOUT -static int nowayout = 1; -#else -static int nowayout = 0; -#endif - -MODULE_PARM(nowayout,"i"); -MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default=CONFIG_WATCHDOG_NOWAYOUT)"); - -/* - * Kernel methods. - */ - - -static void acq_ping(void) -{ - /* Write a watchdog value */ - inb_p(WDT_START); -} - -static ssize_t acq_write(struct file *file, const char *buf, size_t count, loff_t *ppos) -{ - /* Can't seek (pwrite) on this device */ - if (ppos != &file->f_pos) - return -ESPIPE; - - if(count) - { - acq_ping(); - return 1; - } - return 0; -} - -static ssize_t acq_read(struct file *file, char *buf, size_t count, loff_t *ppos) -{ - return -EINVAL; -} - - - -static int acq_ioctl(struct inode *inode, struct file *file, unsigned int cmd, - unsigned long arg) -{ - static struct watchdog_info ident= - { - WDIOF_KEEPALIVEPING, 1, "Acquire WDT" - }; - - switch(cmd) - { - case WDIOC_GETSUPPORT: - if (copy_to_user((struct watchdog_info *)arg, &ident, sizeof(ident))) - return -EFAULT; - break; - - case WDIOC_GETSTATUS: - if (copy_to_user((int *)arg, &acq_is_open, sizeof(int))) - return -EFAULT; - break; - - case WDIOC_KEEPALIVE: - acq_ping(); - break; - - default: - return -ENOTTY; - } - return 0; -} - -static int acq_open(struct inode *inode, struct file *file) -{ - switch(minor(inode->i_rdev)) - { - case WATCHDOG_MINOR: - spin_lock(&acq_lock); - if(acq_is_open) - { - spin_unlock(&acq_lock); - return -EBUSY; - } - if (nowayout) { - MOD_INC_USE_COUNT; - } - /* - * Activate - */ - - acq_is_open=1; - inb_p(WDT_START); - spin_unlock(&acq_lock); - return 0; - default: - return -ENODEV; - } -} - -static int acq_close(struct inode *inode, struct file *file) -{ - if(minor(inode->i_rdev)==WATCHDOG_MINOR) - { - spin_lock(&acq_lock); - if (!nowayout) { - inb_p(WDT_STOP); - } - acq_is_open=0; - spin_unlock(&acq_lock); - } - return 0; -} - -/* - * Notifier for system down - */ - -static int acq_notify_sys(struct notifier_block *this, unsigned long code, - void *unused) -{ - if(code==SYS_DOWN || code==SYS_HALT) - { - /* Turn the card off */ - inb_p(WDT_STOP); - } - return NOTIFY_DONE; -} - -/* - * Kernel Interfaces - */ - - -static struct file_operations acq_fops = { - .owner = THIS_MODULE, - .read = acq_read, - .write = acq_write, - .ioctl = acq_ioctl, - .open = acq_open, - .release = acq_close, -}; - -static struct miscdevice acq_miscdev= -{ - WATCHDOG_MINOR, - "watchdog", - &acq_fops -}; - - -/* - * The WDT card needs to learn about soft shutdowns in order to - * turn the timebomb registers off. - */ - -static struct notifier_block acq_notifier= -{ - acq_notify_sys, - NULL, - 0 -}; - -static int __init acq_init(void) -{ - printk("WDT driver for Acquire single board computer initialising.\n"); - - spin_lock_init(&acq_lock); - if (misc_register(&acq_miscdev)) - return -ENODEV; - if (!request_region(WDT_STOP, 1, "Acquire WDT")) - { - misc_deregister(&acq_miscdev); - return -EIO; - } - if (!request_region(WDT_START, 1, "Acquire WDT")) - { - release_region(WDT_STOP, 1); - misc_deregister(&acq_miscdev); - return -EIO; - } - - register_reboot_notifier(&acq_notifier); - return 0; -} - -static void __exit acq_exit(void) -{ - misc_deregister(&acq_miscdev); - unregister_reboot_notifier(&acq_notifier); - release_region(WDT_STOP,1); - release_region(WDT_START,1); -} - -module_init(acq_init); -module_exit(acq_exit); - -MODULE_LICENSE("GPL"); diff -urpN --exclude-from=/home/davej/.exclude bk-linus/drivers/char/advantechwdt.c move-watchdogs/drivers/char/advantechwdt.c --- bk-linus/drivers/char/advantechwdt.c 2002-11-22 11:00:41.000000000 -0100 +++ move-watchdogs/drivers/char/advantechwdt.c 1969-12-31 23:00:00.000000000 -0100 @@ -1,280 +0,0 @@ -/* - * Advantech Single Board Computer WDT driver for Linux 2.4.x - * - * (c) Copyright 2000-2001 Marek Michalkiewicz - * - * Based on acquirewdt.c which is based on wdt.c. - * Original copyright messages: - * - * (c) Copyright 1996 Alan Cox , All Rights Reserved. - * http://www.redhat.com - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version - * 2 of the License, or (at your option) any later version. - * - * Neither Alan Cox nor CymruNet Ltd. admit liability nor provide - * warranty for any of this software. This material is provided - * "AS-IS" and at no charge. - * - * (c) Copyright 1995 Alan Cox - * - * 14-Dec-2001 Matt Domsch - * Added nowayout module option to override CONFIG_WATCHDOG_NOWAYOUT - * Added timeout module option to override default - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -static int advwdt_is_open; -static spinlock_t advwdt_lock; - -/* - * You must set these - there is no sane way to probe for this board. - * - * To enable or restart, write the timeout value in seconds (1 to 63) - * to I/O port WDT_START. To disable, read I/O port WDT_STOP. - * Both are 0x443 for most boards (tested on a PCA-6276VE-00B1), but - * check your manual (at least the PCA-6159 seems to be different - - * the manual says WDT_STOP is 0x43, not 0x443). - * (0x43 is also a write-only control register for the 8254 timer!) - * - * TODO: module parameters to set the I/O port addresses - */ - -#define WDT_STOP 0x443 -#define WDT_START 0x443 - -#define WD_TIMO 60 /* 1 minute */ - -static int timeout = WD_TIMO; /* in seconds */ -MODULE_PARM(timeout,"i"); -MODULE_PARM_DESC(timeout, "Watchdog timeout in seconds (default=60)"); - -#ifdef CONFIG_WATCHDOG_NOWAYOUT -static int nowayout = 1; -#else -static int nowayout = 0; -#endif - -MODULE_PARM(nowayout,"i"); -MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default=CONFIG_WATCHDOG_NOWAYOUT)"); - -/* - * Kernel methods. - */ - -static void -advwdt_ping(void) -{ - /* Write a watchdog value */ - outb_p(timeout, WDT_START); -} - -static ssize_t -advwdt_write(struct file *file, const char *buf, size_t count, loff_t *ppos) -{ - /* Can't seek (pwrite) on this device */ - if (ppos != &file->f_pos) - return -ESPIPE; - - if (count) { - advwdt_ping(); - return 1; - } - return 0; -} - -static ssize_t -advwdt_read(struct file *file, char *buf, size_t count, loff_t *ppos) -{ - return -EINVAL; -} - -static int -advwdt_ioctl(struct inode *inode, struct file *file, unsigned int cmd, - unsigned long arg) -{ - static struct watchdog_info ident = { - WDIOF_KEEPALIVEPING, 1, "Advantech WDT" - }; - - switch (cmd) { - case WDIOC_GETSUPPORT: - if (copy_to_user((struct watchdog_info *)arg, &ident, sizeof(ident))) - return -EFAULT; - break; - - case WDIOC_GETSTATUS: - if (copy_to_user((int *)arg, &advwdt_is_open, sizeof(int))) - return -EFAULT; - break; - - case WDIOC_KEEPALIVE: - advwdt_ping(); - break; - - default: - return -ENOTTY; - } - return 0; -} - -static int -advwdt_open(struct inode *inode, struct file *file) -{ - switch (minor(inode->i_rdev)) { - case WATCHDOG_MINOR: - spin_lock(&advwdt_lock); - if (advwdt_is_open) { - spin_unlock(&advwdt_lock); - return -EBUSY; - } - if (nowayout) { - MOD_INC_USE_COUNT; - } - /* - * Activate - */ - - advwdt_is_open = 1; - advwdt_ping(); - spin_unlock(&advwdt_lock); - return 0; - default: - return -ENODEV; - } -} - -static int -advwdt_close(struct inode *inode, struct file *file) -{ - if (minor(inode->i_rdev) == WATCHDOG_MINOR) { - spin_lock(&advwdt_lock); - if (!nowayout) { - inb_p(WDT_STOP); - } - advwdt_is_open = 0; - spin_unlock(&advwdt_lock); - } - return 0; -} - -/* - * Notifier for system down - */ - -static int -advwdt_notify_sys(struct notifier_block *this, unsigned long code, - void *unused) -{ - if (code == SYS_DOWN || code == SYS_HALT) { - /* Turn the WDT off */ - inb_p(WDT_STOP); - } - return NOTIFY_DONE; -} - -/* - * Kernel Interfaces - */ - -static struct file_operations advwdt_fops = { - .owner = THIS_MODULE, - .read = advwdt_read, - .write = advwdt_write, - .ioctl = advwdt_ioctl, - .open = advwdt_open, - .release = advwdt_close, -}; - -static struct miscdevice advwdt_miscdev = { - WATCHDOG_MINOR, - "watchdog", - &advwdt_fops -}; - -/* - * The WDT needs to learn about soft shutdowns in order to - * turn the timebomb registers off. - */ - -static struct notifier_block advwdt_notifier = { - advwdt_notify_sys, - NULL, - 0 -}; - -static void __init -advwdt_validate_timeout(void) -{ - if (timeout < 1 || timeout > 63) { - timeout = WD_TIMO; - printk(KERN_INFO "advantechwdt: timeout value must be 1 <= x <= 63, using %d\n", timeout); - } -} - -static int __init -advwdt_init(void) -{ - printk("WDT driver for Advantech single board computer initialising.\n"); - - advwdt_validate_timeout(); - spin_lock_init(&advwdt_lock); - if (misc_register(&advwdt_miscdev)) - return -ENODEV; -#if WDT_START != WDT_STOP - if (!request_region(WDT_STOP, 1, "Advantech WDT")) { - misc_deregister(&advwdt_miscdev); - return -EIO; - } -#endif - if (!request_region(WDT_START, 1, "Advantech WDT")) { - misc_deregister(&advwdt_miscdev); -#if WDT_START != WDT_STOP - release_region(WDT_STOP, 1); -#endif - return -EIO; - } - register_reboot_notifier(&advwdt_notifier); - return 0; -} - -static void __exit -advwdt_exit(void) -{ - misc_deregister(&advwdt_miscdev); - unregister_reboot_notifier(&advwdt_notifier); -#if WDT_START != WDT_STOP - release_region(WDT_STOP,1); -#endif - release_region(WDT_START,1); -} - -module_init(advwdt_init); -module_exit(advwdt_exit); - -MODULE_LICENSE("GPL"); - -/* end of advantechwdt.c */ - diff -urpN --exclude-from=/home/davej/.exclude bk-linus/drivers/char/eurotechwdt.c move-watchdogs/drivers/char/eurotechwdt.c --- bk-linus/drivers/char/eurotechwdt.c 2002-11-22 11:00:41.000000000 -0100 +++ move-watchdogs/drivers/char/eurotechwdt.c 1969-12-31 23:00:00.000000000 -0100 @@ -1,501 +0,0 @@ -/* - * Eurotech CPU-1220/1410 on board WDT driver for Linux 2.4.x - * - * (c) Copyright 2001 Ascensit - * (c) Copyright 2001 Rodolfo Giometti - * - * Based on wdt.c. - * Original copyright messages: - * - * (c) Copyright 1996-1997 Alan Cox , All Rights Reserved. - * http://www.redhat.com - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version - * 2 of the License, or (at your option) any later version. - * - * Neither Alan Cox nor CymruNet Ltd. admit liability nor provide - * warranty for any of this software. This material is provided - * "AS-IS" and at no charge. - * - * (c) Copyright 1995 Alan Cox * - * - * 14-Dec-2001 Matt Domsch - * Added nowayout module option to override CONFIG_WATCHDOG_NOWAYOUT - * Added timeout module option to override default - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include - -static int eurwdt_is_open; -static spinlock_t eurwdt_lock; - -/* - * You must set these - there is no sane way to probe for this board. - * You can use wdt=x,y to set these now. - */ - -static int io = 0x3f0; -static int irq = 10; -static char *ev = "int"; - -#define WDT_TIMEOUT 60 /* 1 minute */ -static int timeout = WDT_TIMEOUT; - -MODULE_PARM(timeout,"i"); -MODULE_PARM_DESC(timeout, "Eurotech WDT timeout in seconds (default=60)"); - -#ifdef CONFIG_WATCHDOG_NOWAYOUT -static int nowayout = 1; -#else -static int nowayout = 0; -#endif -MODULE_PARM(nowayout,"i"); -MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default=CONFIG_WATCHDOG_NOWAYOUT)"); - - -/* - * Some symbolic names - */ - -#define WDT_CTRL_REG 0x30 -#define WDT_OUTPIN_CFG 0xe2 - #define WDT_EVENT_INT 0x00 - #define WDT_EVENT_REBOOT 0x08 -#define WDT_UNIT_SEL 0xf1 - #define WDT_UNIT_SECS 0x80 -#define WDT_TIMEOUT_VAL 0xf2 -#define WDT_TIMER_CFG 0xf3 - - -#ifndef MODULE - -/** - * eurwdt_setup: - * @str: command line string - * - * Setup options. The board isn't really probe-able so we have to - * get the user to tell us the configuration. Sane people build it - * modular but the others come here. - */ - -static int __init eurwdt_setup(char *str) -{ - int ints[4]; - - str = get_options (str, ARRAY_SIZE(ints), ints); - - if (ints[0] > 0) { - io = ints[1]; - if (ints[0] > 1) - irq = ints[2]; - } - - return 1; -} - -__setup("wdt=", eurwdt_setup); - -#endif /* !MODULE */ - -MODULE_PARM(io, "i"); -MODULE_PARM_DESC(io, "Eurotech WDT io port (default=0x3f0)"); -MODULE_PARM(irq, "i"); -MODULE_PARM_DESC(irq, "Eurotech WDT irq (default=10)"); -MODULE_PARM(ev, "s"); -MODULE_PARM_DESC(ev, "Eurotech WDT event type (default is `reboot')"); - - -/* - * Programming support - */ - -static void __init eurwdt_validate_timeout(void) -{ - if (timeout < 0 || timeout > 255) { - timeout = WDT_TIMEOUT; - printk(KERN_INFO "eurwdt: timeout must be 0 < x < 255, using %d\n", - timeout); - } -} - -static inline void eurwdt_write_reg(u8 index, u8 data) -{ - outb(index, io); - outb(data, io+1); -} - -static inline void eurwdt_lock_chip(void) -{ - outb(0xaa, io); -} - -static inline void eurwdt_unlock_chip(void) -{ - outb(0x55, io); - eurwdt_write_reg(0x07, 0x08); /* set the logical device */ -} - -static inline void eurwdt_set_timeout(int timeout) -{ - eurwdt_write_reg(WDT_TIMEOUT_VAL, (u8) timeout); -} - -static inline void eurwdt_disable_timer(void) -{ - eurwdt_set_timeout(0); -} - -static void eurwdt_activate_timer(void) -{ - eurwdt_disable_timer(); - eurwdt_write_reg(WDT_CTRL_REG, 0x01); /* activate the WDT */ - eurwdt_write_reg(WDT_OUTPIN_CFG, !strcmp("int", ev) ? - WDT_EVENT_INT : WDT_EVENT_REBOOT); - /* Setting interrupt line */ - if (irq == 2 || irq > 15 || irq < 0) { - printk(KERN_ERR ": invalid irq number\n"); - irq = 0; /* if invalid we disable interrupt */ - } - if (irq == 0) - printk(KERN_INFO ": interrupt disabled\n"); - eurwdt_write_reg(WDT_TIMER_CFG, irq<<4); - - eurwdt_write_reg(WDT_UNIT_SEL, WDT_UNIT_SECS); /* we use seconds */ - eurwdt_set_timeout(0); /* the default timeout */ -} - - -/* - * Kernel methods. - */ - -void eurwdt_interrupt(int irq, void *dev_id, struct pt_regs *regs) -{ - printk(KERN_CRIT "timeout WDT timeout\n"); - -#ifdef ONLY_TESTING - printk(KERN_CRIT "Would Reboot.\n"); -#else - printk(KERN_CRIT "Initiating system reboot.\n"); - machine_restart(NULL); -#endif -} - - -/** - * eurwdt_ping: - * - * Reload counter one with the watchdog timeout. - */ - -static void eurwdt_ping(void) -{ - /* Write the watchdog default value */ - eurwdt_set_timeout(timeout); -} - -/** - * eurwdt_write: - * @file: file handle to the watchdog - * @buf: buffer to write (unused as data does not matter here - * @count: count of bytes - * @ppos: pointer to the position to write. No seeks allowed - * - * A write to a watchdog device is defined as a keepalive signal. Any - * write of data will do, as we we don't define content meaning. - */ - -static ssize_t eurwdt_write(struct file *file, const char *buf, size_t count, -loff_t *ppos) -{ - /* Can't seek (pwrite) on this device */ - if (ppos != &file->f_pos) - return -ESPIPE; - - if (count) { - eurwdt_ping(); /* the default timeout */ - return 1; - } - - return 0; -} - -/** - * eurwdt_ioctl: - * @inode: inode of the device - * @file: file handle to the device - * @cmd: watchdog command - * @arg: argument pointer - * - * The watchdog API defines a common set of functions for all watchdogs - * according to their available features. - */ - -static int eurwdt_ioctl(struct inode *inode, struct file *file, - unsigned int cmd, unsigned long arg) -{ - static struct watchdog_info ident = { - .options = WDIOF_CARDRESET, - .firmware_version = 1, - .identity = "WDT Eurotech CPU-1220/1410", - }; - - int time; - - switch(cmd) { - default: - return -ENOTTY; - - case WDIOC_GETSUPPORT: - return copy_to_user((struct watchdog_info *)arg, &ident, - sizeof(ident)) ? -EFAULT : 0; - - case WDIOC_GETBOOTSTATUS: - return put_user(0, (int *) arg); - - case WDIOC_KEEPALIVE: - eurwdt_ping(); - return 0; - - case WDIOC_SETTIMEOUT: - if (copy_from_user(&time, (int *) arg, sizeof(int))) - return -EFAULT; - - /* Sanity check */ - if (time < 0 || time > 255) - return -EINVAL; - - timeout = time; - eurwdt_set_timeout(time); - return 0; - } -} - -/** - * eurwdt_open: - * @inode: inode of device - * @file: file handle to device - * - * The misc device has been opened. The watchdog device is single - * open and on opening we load the counter. - */ - -static int eurwdt_open(struct inode *inode, struct file *file) -{ - switch (minor(inode->i_rdev)) { - case WATCHDOG_MINOR: - spin_lock(&eurwdt_lock); - if (eurwdt_is_open) { - spin_unlock(&eurwdt_lock); - return -EBUSY; - } - if (nowayout) { - MOD_INC_USE_COUNT; - } - - eurwdt_is_open = 1; - - /* Activate the WDT */ - eurwdt_activate_timer(); - - spin_unlock(&eurwdt_lock); - - MOD_INC_USE_COUNT; - - return 0; - - case TEMP_MINOR: - return 0; - - default: - return -ENODEV; - } -} - -/** - * eurwdt_release: - * @inode: inode to board - * @file: file handle to board - * - * The watchdog has a configurable API. There is a religious dispute - * between people who want their watchdog to be able to shut down and - * those who want to be sure if the watchdog manager dies the machine - * reboots. In the former case we disable the counters, in the latter - * case you have to open it again very soon. - */ - -static int eurwdt_release(struct inode *inode, struct file *file) -{ - if (minor(inode->i_rdev) == WATCHDOG_MINOR) { - if (!nowayout) { - eurwdt_disable_timer(); - } - eurwdt_is_open = 0; - - MOD_DEC_USE_COUNT; - } - - return 0; -} - -/** - * eurwdt_notify_sys: - * @this: our notifier block - * @code: the event being reported - * @unused: unused - * - * Our notifier is called on system shutdowns. We want to turn the card - * off at reboot otherwise the machine will reboot again during memory - * test or worse yet during the following fsck. This would suck, in fact - * trust me - if it happens it does suck. - */ - -static int eurwdt_notify_sys(struct notifier_block *this, unsigned long code, - void *unused) -{ - if (code == SYS_DOWN || code == SYS_HALT) { - /* Turn the card off */ - eurwdt_disable_timer(); - } - - return NOTIFY_DONE; -} - -/* - * Kernel Interfaces - */ - - -static struct file_operations eurwdt_fops = { - .owner = THIS_MODULE, - .llseek = no_llseek, - .write = eurwdt_write, - .ioctl = eurwdt_ioctl, - .open = eurwdt_open, - .release = eurwdt_release, -}; - -static struct miscdevice eurwdt_miscdev = { - .minor = WATCHDOG_MINOR, - .name = "watchdog", - .fops = &eurwdt_fops -}; - -/* - * The WDT card needs to learn about soft shutdowns in order to - * turn the timebomb registers off. - */ - -static struct notifier_block eurwdt_notifier = { - .notifier_call = eurwdt_notify_sys, -}; - -/** - * cleanup_module: - * - * Unload the watchdog. You cannot do this with any file handles open. - * If your watchdog is set to continue ticking on close and you unload - * it, well it keeps ticking. We won't get the interrupt but the board - * will not touch PC memory so all is fine. You just have to load a new - * module in 60 seconds or reboot. - */ - -static void __exit eurwdt_exit(void) -{ - eurwdt_lock_chip(); - - misc_deregister(&eurwdt_miscdev); - - unregister_reboot_notifier(&eurwdt_notifier); - release_region(io, 2); - free_irq(irq, NULL); -} - -/** - * eurwdt_init: - * - * Set up the WDT watchdog board. After grabbing the resources - * we require we need also to unlock the device. - * The open() function will actually kick the board off. - */ - -static int __init eurwdt_init(void) -{ - int ret; - - eurwdt_validate_timeout(); - ret = misc_register(&eurwdt_miscdev); - if (ret) { - printk(KERN_ERR "eurwdt: can't misc_register on minor=%d\n", - WATCHDOG_MINOR); - goto out; - } - - ret = request_irq(irq, eurwdt_interrupt, SA_INTERRUPT, "eurwdt", NULL); - if(ret) { - printk(KERN_ERR "eurwdt: IRQ %d is not free.\n", irq); - goto outmisc; - } - - if (!request_region(io, 2, "eurwdt")) { - printk(KERN_ERR "eurwdt: IO %X is not free.\n", io); - ret = -EBUSY; - goto outirq; - } - - ret = register_reboot_notifier(&eurwdt_notifier); - if (ret) { - printk(KERN_ERR "eurwdt: can't register reboot notifier (err=%d)\n", ret); - goto outreg; - } - - eurwdt_unlock_chip(); - - ret = 0; - printk(KERN_INFO "Eurotech WDT driver 0.01 at %X (Interrupt %d)" - " - timeout event: %s\n", - io, irq, (!strcmp("int", ev) ? "int" : "reboot")); - - spin_lock_init(&eurwdt_lock); - - out: - return ret; - - outreg: - release_region(io, 2); - - outirq: - free_irq(irq, NULL); - - outmisc: - misc_deregister(&eurwdt_miscdev); - goto out; -} - -module_init(eurwdt_init); -module_exit(eurwdt_exit); - -MODULE_AUTHOR("Rodolfo Giometti"); -MODULE_DESCRIPTION("Driver for Eurotech CPU-1220/1410 on board watchdog"); -MODULE_LICENSE("GPL"); diff -urpN --exclude-from=/home/davej/.exclude bk-linus/drivers/char/i810-tco.c move-watchdogs/drivers/char/i810-tco.c --- bk-linus/drivers/char/i810-tco.c 2002-11-22 11:00:43.000000000 -0100 +++ move-watchdogs/drivers/char/i810-tco.c 1969-12-31 23:00:00.000000000 -0100 @@ -1,431 +0,0 @@ -/* - * i810-tco 0.05: TCO timer driver for i8xx chipsets - * - * (c) Copyright 2000 kernel concepts , All Rights Reserved. - * http://www.kernelconcepts.de - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version - * 2 of the License, or (at your option) any later version. - * - * Neither kernel concepts nor Nils Faerber admit liability nor provide - * warranty for any of this software. This material is provided - * "AS-IS" and at no charge. - * - * (c) Copyright 2000 kernel concepts - * developed for - * Jentro AG, Haar/Munich (Germany) - * - * TCO timer driver for i8xx chipsets - * based on softdog.c by Alan Cox - * - * The TCO timer is implemented in the following I/O controller hubs: - * (See the intel documentation on http://developer.intel.com.) - * 82801AA & 82801AB chip : document number 290655-003, 290677-004, - * 82801BA & 82801BAM chip : document number 290687-002, 298242-005, - * 82801CA & 82801CAM chip : document number 290716-001, 290718-001, - * 82801DB & 82801E chip : document number 290744-001, 273599-001 - * - * 20000710 Nils Faerber - * Initial Version 0.01 - * 20000728 Nils Faerber - * 0.02 Fix for SMI_EN->TCO_EN bit, some cleanups - * 20011214 Matt Domsch - * 0.03 Added nowayout module option to override CONFIG_WATCHDOG_NOWAYOUT - * Didn't add timeout option as i810_margin already exists. - * 20020224 Joel Becker, Wim Van Sebroeck - * 0.04 Support for 82801CA(M) chipset, timer margin needs to be > 3, - * add support for WDIOC_SETTIMEOUT and WDIOC_GETTIMEOUT. - * 20020412 Rob Radez , Wim Van Sebroeck - * 0.05 Fix possible timer_alive race, add expect close support, - * clean up ioctls (WDIOC_GETSTATUS, WDIOC_GETBOOTSTATUS and - * WDIOC_SETOPTIONS), made i810tco_getdevice __init, - * removed boot_status, removed tco_timer_read, - * added support for 82801DB and 82801E chipset, general cleanup. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include "i810-tco.h" - - -/* Module and version information */ -#define TCO_VERSION "0.05" -#define TCO_MODULE_NAME "i810 TCO timer" -#define TCO_DRIVER_NAME TCO_MODULE_NAME ", v" TCO_VERSION - -/* Default expire timeout */ -#define TIMER_MARGIN 50 /* steps of 0.6sec, 3 0x3f || tmrval < 0x04) - return -1; - - spin_lock(&tco_lock); - val = inb (TCO1_TMR); - val &= 0xc0; - val |= tmrval; - outb (val, TCO1_TMR); - val = inb (TCO1_TMR); - spin_unlock(&tco_lock); - - if ((val & 0x3f) != tmrval) - return -1; - - return 0; -} - -/* - * Reload (trigger) the timer. Lock is needed so we dont reload it during - * a reprogramming event - */ - -static void tco_timer_reload (void) -{ - spin_lock(&tco_lock); - outb (0x01, TCO1_RLD); - spin_unlock(&tco_lock); -} - -/* - * Allow only one person to hold it open - */ - -static int i810tco_open (struct inode *inode, struct file *file) -{ - if (test_and_set_bit(0, &timer_alive)) - return -EBUSY; - - /* - * Reload and activate timer - */ - tco_timer_reload (); - tco_timer_start (); - return 0; -} - -static int i810tco_release (struct inode *inode, struct file *file) -{ - /* - * Shut off the timer. - */ - if (tco_expect_close == 42 && !nowayout) { - tco_timer_stop (); - } else { - tco_timer_reload (); - printk(KERN_CRIT TCO_MODULE_NAME ": Unexpected close, not stopping watchdog!\n"); - } - clear_bit(0, &timer_alive); - tco_expect_close = 0; - return 0; -} - -static ssize_t i810tco_write (struct file *file, const char *data, - size_t len, loff_t * ppos) -{ - /* Can't seek (pwrite) on this device */ - if (ppos != &file->f_pos) - return -ESPIPE; - - /* See if we got the magic character 'V' and reload the timer */ - if (len) { - size_t i; - - tco_expect_close = 0; - - /* scan to see wether or not we got the magic character */ - for (i = 0; i != len; i++) { - u8 c; - if(get_user(c, data+i)) - return -EFAULT; - if (c == 'V') - tco_expect_close = 42; - } - - /* someone wrote to us, we should reload the timer */ - tco_timer_reload (); - return 1; - } - return 0; -} - -static int i810tco_ioctl (struct inode *inode, struct file *file, - unsigned int cmd, unsigned long arg) -{ - int new_margin, u_margin; - int options, retval = -EINVAL; - - static struct watchdog_info ident = { - .options = WDIOF_SETTIMEOUT | WDIOF_KEEPALIVEPING, - .firmware_version = 0, - .identity = "i810 TCO timer", - }; - switch (cmd) { - default: - return -ENOTTY; - case WDIOC_GETSUPPORT: - if (copy_to_user - ((struct watchdog_info *) arg, &ident, sizeof (ident))) - return -EFAULT; - return 0; - case WDIOC_GETSTATUS: - case WDIOC_GETBOOTSTATUS: - return put_user (0, (int *) arg); - case WDIOC_SETOPTIONS: - if (get_user (options, (int *) arg)) - return -EFAULT; - if (options & WDIOS_DISABLECARD) { - tco_timer_stop (); - retval = 0; - } - if (options & WDIOS_ENABLECARD) { - tco_timer_reload (); - tco_timer_start (); - retval = 0; - } - return retval; - case WDIOC_KEEPALIVE: - tco_timer_reload (); - return 0; - case WDIOC_SETTIMEOUT: - if (get_user (u_margin, (int *) arg)) - return -EFAULT; - new_margin = (u_margin * 10 + 5) / 6; - if ((new_margin < 4) || (new_margin > 63)) - return -EINVAL; - if (tco_timer_settimer ((unsigned char) new_margin)) - return -EINVAL; - i810_margin = new_margin; - tco_timer_reload (); - /* Fall */ - case WDIOC_GETTIMEOUT: - return put_user ((int)(i810_margin * 6 / 10), (int *) arg); - } -} - -/* - * Data for PCI driver interface - * - * This data only exists for exporting the supported - * PCI ids via MODULE_DEVICE_TABLE. We do not actually - * register a pci_driver, because someone else might one day - * want to register another driver on the same PCI id. - */ -static struct pci_device_id i810tco_pci_tbl[] __initdata = { - { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801AA_0, PCI_ANY_ID, PCI_ANY_ID, }, - { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801AB_0, PCI_ANY_ID, PCI_ANY_ID, }, - { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801BA_0, PCI_ANY_ID, PCI_ANY_ID, }, - { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801BA_10, PCI_ANY_ID, PCI_ANY_ID, }, - { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801CA_0, PCI_ANY_ID, PCI_ANY_ID, }, - { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801CA_12, PCI_ANY_ID, PCI_ANY_ID, }, - { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801DB_0, PCI_ANY_ID, PCI_ANY_ID, }, - { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801E_0, PCI_ANY_ID, PCI_ANY_ID, }, - { 0, }, -}; -MODULE_DEVICE_TABLE (pci, i810tco_pci_tbl); - -static struct pci_dev *i810tco_pci; - -static unsigned char __init i810tco_getdevice (void) -{ - struct pci_dev *dev; - u8 val1, val2; - u16 badr; - /* - * Find the PCI device - */ - - pci_for_each_dev(dev) { - if (pci_match_device(i810tco_pci_tbl, dev)) { - i810tco_pci = dev; - break; - } - } - - if (i810tco_pci) { - /* - * Find the ACPI base I/O address which is the base - * for the TCO registers (TCOBASE=ACPIBASE + 0x60) - * ACPIBASE is bits [15:7] from 0x40-0x43 - */ - pci_read_config_byte (i810tco_pci, 0x40, &val1); - pci_read_config_byte (i810tco_pci, 0x41, &val2); - badr = ((val2 << 1) | (val1 >> 7)) << 7; - ACPIBASE = badr; - /* Something's wrong here, ACPIBASE has to be set */ - if (badr == 0x0001 || badr == 0x0000) { - printk (KERN_ERR TCO_MODULE_NAME " init: failed to get TCOBASE address\n"); - return 0; - } - /* - * Check chipset's NO_REBOOT bit - */ - pci_read_config_byte (i810tco_pci, 0xd4, &val1); - if (val1 & 0x02) { - val1 &= 0xfd; - pci_write_config_byte (i810tco_pci, 0xd4, val1); - pci_read_config_byte (i810tco_pci, 0xd4, &val1); - if (val1 & 0x02) { - printk (KERN_ERR TCO_MODULE_NAME " init: failed to reset NO_REBOOT flag, reboot disabled by hardware\n"); - return 0; /* Cannot reset NO_REBOOT bit */ - } - } - /* Set the TCO_EN bit in SMI_EN register */ - val1 = inb (SMI_EN + 1); - val1 &= 0xdf; - outb (val1, SMI_EN + 1); - /* Clear out the (probably old) status */ - outb (0, TCO1_STS); - outb (3, TCO2_STS); - return 1; - } - return 0; -} - -static struct file_operations i810tco_fops = { - .owner = THIS_MODULE, - .write = i810tco_write, - .ioctl = i810tco_ioctl, - .open = i810tco_open, - .release = i810tco_release, -}; - -static struct miscdevice i810tco_miscdev = { - .minor = WATCHDOG_MINOR, - .name = "watchdog", - .fops = &i810tco_fops, -}; - -static int __init watchdog_init (void) -{ - spin_lock_init(&tco_lock); - if (!i810tco_getdevice () || i810tco_pci == NULL) - return -ENODEV; - if (!request_region (TCOBASE, 0x10, "i810 TCO")) { - printk (KERN_ERR TCO_MODULE_NAME - ": I/O address 0x%04x already in use\n", - TCOBASE); - return -EIO; - } - if (misc_register (&i810tco_miscdev) != 0) { - release_region (TCOBASE, 0x10); - printk (KERN_ERR TCO_MODULE_NAME ": cannot register miscdev\n"); - return -EIO; - } - tco_timer_settimer ((unsigned char) i810_margin); - tco_timer_reload (); - - printk (KERN_INFO TCO_DRIVER_NAME - ": timer margin: %d sec (0x%04x) (nowayout=%d)\n", - (int) (i810_margin * 6 / 10), TCOBASE, nowayout); - return 0; -} - -static void __exit watchdog_cleanup (void) -{ - u8 val; - - /* Reset the timer before we leave */ - tco_timer_reload (); - /* Set the NO_REBOOT bit to prevent later reboots, just for sure */ - pci_read_config_byte (i810tco_pci, 0xd4, &val); - val |= 0x02; - pci_write_config_byte (i810tco_pci, 0xd4, val); - release_region (TCOBASE, 0x10); - misc_deregister (&i810tco_miscdev); -} - -module_init(watchdog_init); -module_exit(watchdog_cleanup); - -MODULE_AUTHOR("Nils Faerber"); -MODULE_DESCRIPTION("TCO timer driver for i8xx chipsets"); -MODULE_LICENSE("GPL"); diff -urpN --exclude-from=/home/davej/.exclude bk-linus/drivers/char/ib700wdt.c move-watchdogs/drivers/char/ib700wdt.c --- bk-linus/drivers/char/ib700wdt.c 2002-11-22 11:00:43.000000000 -0100 +++ move-watchdogs/drivers/char/ib700wdt.c 1969-12-31 23:00:00.000000000 -0100 @@ -1,311 +0,0 @@ -/* - * IB700 Single Board Computer WDT driver for Linux 2.4.x - * - * (c) Copyright 2001 Charles Howes - * - * Based on advantechwdt.c which is based on acquirewdt.c which - * is based on wdt.c. - * - * (c) Copyright 2000-2001 Marek Michalkiewicz - * - * Based on acquirewdt.c which is based on wdt.c. - * Original copyright messages: - * - * (c) Copyright 1996 Alan Cox , All Rights Reserved. - * http://www.redhat.com - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version - * 2 of the License, or (at your option) any later version. - * - * Neither Alan Cox nor CymruNet Ltd. admit liability nor provide - * warranty for any of this software. This material is provided - * "AS-IS" and at no charge. - * - * (c) Copyright 1995 Alan Cox - * - * 14-Dec-2001 Matt Domsch - * Added nowayout module option to override CONFIG_WATCHDOG_NOWAYOUT - * Added timeout module option to override default - * - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -static int ibwdt_is_open; -static spinlock_t ibwdt_lock; - -/* - * - * Watchdog Timer Configuration - * - * The function of the watchdog timer is to reset the system - * automatically and is defined at I/O port 0443H. To enable the - * watchdog timer and allow the system to reset, write I/O port 0443H. - * To disable the timer, write I/O port 0441H for the system to stop the - * watchdog function. The timer has a tolerance of 20% for its - * intervals. - * - * The following describes how the timer should be programmed. - * - * Enabling Watchdog: - * MOV AX,000FH (Choose the values from 0 to F) - * MOV DX,0443H - * OUT DX,AX - * - * Disabling Watchdog: - * MOV AX,000FH (Any value is fine.) - * MOV DX,0441H - * OUT DX,AX - * - * Watchdog timer control table: - * Level Value Time/sec | Level Value Time/sec - * 1 F 0 | 9 7 16 - * 2 E 2 | 10 6 18 - * 3 D 4 | 11 5 20 - * 4 C 6 | 12 4 22 - * 5 B 8 | 13 3 24 - * 6 A 10 | 14 2 26 - * 7 9 12 | 15 1 28 - * 8 8 14 | 16 0 30 - * - */ - -#define WDT_STOP 0x441 -#define WDT_START 0x443 - -#define WD_TIMO 0 /* 30 seconds +/- 20%, from table */ - -static int timeout_val = WD_TIMO; /* value in table */ -static int timeout = 30; /* in seconds */ -MODULE_PARM(timeout,"i"); -MODULE_PARM_DESC(timeout, "Watchdog timeout in seconds, 0 < n < 30, must be even (default=30)"); - -#ifdef CONFIG_WATCHDOG_NOWAYOUT -static int nowayout = 1; -#else -static int nowayout = 0; -#endif - -MODULE_PARM(nowayout,"i"); -MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default=CONFIG_WATCHDOG_NOWAYOUT)"); - -/* - * Kernel methods. - */ - -static void __init -ibwdt_validate_timeout(void) -{ - timeout_val = (30 - timeout) / 2; - if (timeout_val < 0 || timeout_val > 0xF) timeout_val = WD_TIMO; -} - -static void -ibwdt_ping(void) -{ - /* Write a watchdog value */ - outb_p(timeout_val, WDT_START); -} - -static ssize_t -ibwdt_write(struct file *file, const char *buf, size_t count, loff_t *ppos) -{ - /* Can't seek (pwrite) on this device */ - if (ppos != &file->f_pos) - return -ESPIPE; - - if (count) { - ibwdt_ping(); - return 1; - } - return 0; -} - -static ssize_t -ibwdt_read(struct file *file, char *buf, size_t count, loff_t *ppos) -{ - return -EINVAL; -} - -static int -ibwdt_ioctl(struct inode *inode, struct file *file, unsigned int cmd, - unsigned long arg) -{ - static struct watchdog_info ident = { - WDIOF_KEEPALIVEPING, 1, "IB700 WDT" - }; - - switch (cmd) { - case WDIOC_GETSUPPORT: - if (copy_to_user((struct watchdog_info *)arg, &ident, sizeof(ident))) - return -EFAULT; - break; - - case WDIOC_GETSTATUS: - if (copy_to_user((int *)arg, &ibwdt_is_open, sizeof(int))) - return -EFAULT; - break; - - case WDIOC_KEEPALIVE: - ibwdt_ping(); - break; - - default: - return -ENOTTY; - } - return 0; -} - -static int -ibwdt_open(struct inode *inode, struct file *file) -{ - switch (minor(inode->i_rdev)) { - case WATCHDOG_MINOR: - spin_lock(&ibwdt_lock); - if (ibwdt_is_open) { - spin_unlock(&ibwdt_lock); - return -EBUSY; - } - if (nowayout) { - MOD_INC_USE_COUNT; - } - /* - * Activate - */ - - ibwdt_is_open = 1; - ibwdt_ping(); - spin_unlock(&ibwdt_lock); - return 0; - default: - return -ENODEV; - } -} - -static int -ibwdt_close(struct inode *inode, struct file *file) -{ - lock_kernel(); - if (minor(inode->i_rdev) == WATCHDOG_MINOR) { - spin_lock(&ibwdt_lock); - if (!nowayout) { - outb_p(timeout_val, WDT_STOP); - } - ibwdt_is_open = 0; - spin_unlock(&ibwdt_lock); - } - unlock_kernel(); - return 0; -} - -/* - * Notifier for system down - */ - -static int -ibwdt_notify_sys(struct notifier_block *this, unsigned long code, - void *unused) -{ - if (code == SYS_DOWN || code == SYS_HALT) { - /* Turn the WDT off */ - outb_p(timeout_val, WDT_STOP); - } - return NOTIFY_DONE; -} - -/* - * Kernel Interfaces - */ - -static struct file_operations ibwdt_fops = { - .owner = THIS_MODULE, - .read = ibwdt_read, - .write = ibwdt_write, - .ioctl = ibwdt_ioctl, - .open = ibwdt_open, - .release = ibwdt_close, -}; - -static struct miscdevice ibwdt_miscdev = { - WATCHDOG_MINOR, - "watchdog", - &ibwdt_fops -}; - -/* - * The WDT needs to learn about soft shutdowns in order to - * turn the timebomb registers off. - */ - -static struct notifier_block ibwdt_notifier = { - ibwdt_notify_sys, - NULL, - 0 -}; - -static int __init -ibwdt_init(void) -{ - printk("WDT driver for IB700 single board computer initialising.\n"); - - ibwdt_validate_timeout(); - spin_lock_init(&ibwdt_lock); - if (misc_register(&ibwdt_miscdev)) - return -ENODEV; -#if WDT_START != WDT_STOP - if (!request_region(WDT_STOP, 1, "IB700 WDT")) { - misc_deregister(&ibwdt_miscdev); - return -EIO; - } -#endif - if (!request_region(WDT_START, 1, "IB700 WDT")) { -#if WDT_START != WDT_STOP - release_region(WDT_STOP, 1); -#endif - misc_deregister(&ibwdt_miscdev); - return -EIO; - } - register_reboot_notifier(&ibwdt_notifier); - return 0; -} - -static void __exit -ibwdt_exit(void) -{ - misc_deregister(&ibwdt_miscdev); - unregister_reboot_notifier(&ibwdt_notifier); -#if WDT_START != WDT_STOP - release_region(WDT_STOP,1); -#endif - release_region(WDT_START,1); -} - -module_init(ibwdt_init); -module_exit(ibwdt_exit); - -MODULE_AUTHOR("Charles Howes "); -MODULE_DESCRIPTION("IB700 SBC watchdog driver"); -MODULE_LICENSE("GPL"); - -/* end of ib700wdt.c */ diff -urpN --exclude-from=/home/davej/.exclude bk-linus/drivers/char/machzwd.c move-watchdogs/drivers/char/machzwd.c --- bk-linus/drivers/char/machzwd.c 2002-11-22 11:00:43.000000000 -0100 +++ move-watchdogs/drivers/char/machzwd.c 1969-12-31 23:00:00.000000000 -0100 @@ -1,557 +0,0 @@ -/* - * MachZ ZF-Logic Watchdog Timer driver for Linux - * - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version - * 2 of the License, or (at your option) any later version. - * - * The author does NOT admit liability nor provide warranty for - * any of this software. This material is provided "AS-IS" in - * the hope that it may be useful for others. - * - * Author: Fernando Fuganti - * - * Based on sbc60xxwdt.c by Jakob Oestergaard - * - * - * We have two timers (wd#1, wd#2) driven by a 32 KHz clock with the - * following periods: - * wd#1 - 2 seconds; - * wd#2 - 7.2 ms; - * After the expiration of wd#1, it can generate a NMI, SCI, SMI, or - * a system RESET and it starts wd#2 that unconditionaly will RESET - * the system when the counter reaches zero. - * - * 14-Dec-2001 Matt Domsch - * Added nowayout module option to override CONFIG_WATCHDOG_NOWAYOUT - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - - -/* ports */ -#define ZF_IOBASE 0x218 -#define INDEX 0x218 -#define DATA_B 0x219 -#define DATA_W 0x21A -#define DATA_D 0x21A - -/* indexes */ /* size */ -#define ZFL_VERSION 0x02 /* 16 */ -#define CONTROL 0x10 /* 16 */ -#define STATUS 0x12 /* 8 */ -#define COUNTER_1 0x0C /* 16 */ -#define COUNTER_2 0x0E /* 8 */ -#define PULSE_LEN 0x0F /* 8 */ - -/* controls */ -#define ENABLE_WD1 0x0001 -#define ENABLE_WD2 0x0002 -#define RESET_WD1 0x0010 -#define RESET_WD2 0x0020 -#define GEN_SCI 0x0100 -#define GEN_NMI 0x0200 -#define GEN_SMI 0x0400 -#define GEN_RESET 0x0800 - - -/* utilities */ - -#define WD1 0 -#define WD2 1 - -#define zf_writew(port, data) { outb(port, INDEX); outw(data, DATA_W); } -#define zf_writeb(port, data) { outb(port, INDEX); outb(data, DATA_B); } -#define zf_get_ZFL_version() zf_readw(ZFL_VERSION) - - -static unsigned short zf_readw(unsigned char port) -{ - outb(port, INDEX); - return inw(DATA_W); -} - -static unsigned short zf_readb(unsigned char port) -{ - outb(port, INDEX); - return inb(DATA_B); -} - - -MODULE_AUTHOR("Fernando Fuganti "); -MODULE_DESCRIPTION("MachZ ZF-Logic Watchdog driver"); -MODULE_LICENSE("GPL"); -MODULE_PARM(action, "i"); -MODULE_PARM_DESC(action, "after watchdog resets, generate: 0 = RESET(*) 1 = SMI 2 = NMI 3 = SCI"); - -#ifdef CONFIG_WATCHDOG_NOWAYOUT -static int nowayout = 1; -#else -static int nowayout = 0; -#endif - -MODULE_PARM(nowayout,"i"); -MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default=CONFIG_WATCHDOG_NOWAYOUT)"); - -#define PFX "machzwd" - -static struct watchdog_info zf_info = { - .options = WDIOF_KEEPALIVEPING, - .firmware_version = 1, - .identity = "ZF-Logic watchdog" -}; - - -/* - * action refers to action taken when watchdog resets - * 0 = GEN_RESET - * 1 = GEN_SMI - * 2 = GEN_NMI - * 3 = GEN_SCI - * defaults to GEN_RESET (0) - */ -static int action = 0; -static int zf_action = GEN_RESET; -static int zf_is_open = 0; -static int zf_expect_close = 0; -static spinlock_t zf_lock; -static spinlock_t zf_port_lock; -static struct timer_list zf_timer; -static unsigned long next_heartbeat = 0; - - -/* timeout for user land heart beat (10 seconds) */ -#define ZF_USER_TIMEO (HZ*10) - -/* timeout for hardware watchdog (~500ms) */ -#define ZF_HW_TIMEO (HZ/2) - -/* number of ticks on WD#1 (driven by a 32KHz clock, 2s) */ -#define ZF_CTIMEOUT 0xffff - -#ifndef ZF_DEBUG -# define dprintk(format, args...) -#else -# define dprintk(format, args...) printk(KERN_DEBUG PFX; ":" __FUNCTION__ ":%d: " format, __LINE__ , ## args) -#endif - - -/* STATUS register functions */ - -static inline unsigned char zf_get_status(void) -{ - return zf_readb(STATUS); -} - -static inline void zf_set_status(unsigned char new) -{ - zf_writeb(STATUS, new); -} - - -/* CONTROL register functions */ - -static inline unsigned short zf_get_control(void) -{ - return zf_readw(CONTROL); -} - -static inline void zf_set_control(unsigned short new) -{ - zf_writew(CONTROL, new); -} - - -/* WD#? counter functions */ -/* - * Just get current counter value - */ - -static inline unsigned short zf_get_timer(unsigned char n) -{ - switch(n){ - case WD1: - return zf_readw(COUNTER_1); - case WD2: - return zf_readb(COUNTER_2); - default: - return 0; - } -} - -/* - * Just set counter value - */ - -static inline void zf_set_timer(unsigned short new, unsigned char n) -{ - switch(n){ - case WD1: - zf_writew(COUNTER_1, new); - case WD2: - zf_writeb(COUNTER_2, new > 0xff ? 0xff : new); - default: - return; - } -} - -/* - * stop hardware timer - */ -static void zf_timer_off(void) -{ - unsigned int ctrl_reg = 0; - unsigned long flags; - - /* stop internal ping */ - del_timer_sync(&zf_timer); - - spin_lock_irqsave(&zf_port_lock, flags); - /* stop watchdog timer */ - ctrl_reg = zf_get_control(); - ctrl_reg |= (ENABLE_WD1|ENABLE_WD2); /* disable wd1 and wd2 */ - ctrl_reg &= ~(ENABLE_WD1|ENABLE_WD2); - zf_set_control(ctrl_reg); - spin_unlock_irqrestore(&zf_port_lock, flags); - - printk(KERN_INFO PFX ": Watchdog timer is now disabled\n"); -} - - -/* - * start hardware timer - */ -static void zf_timer_on(void) -{ - unsigned int ctrl_reg = 0; - unsigned long flags; - - spin_lock_irqsave(&zf_port_lock, flags); - - zf_writeb(PULSE_LEN, 0xff); - - zf_set_timer(ZF_CTIMEOUT, WD1); - - /* user land ping */ - next_heartbeat = jiffies + ZF_USER_TIMEO; - - /* start the timer for internal ping */ - zf_timer.expires = jiffies + ZF_HW_TIMEO; - - add_timer(&zf_timer); - - /* start watchdog timer */ - ctrl_reg = zf_get_control(); - ctrl_reg |= (ENABLE_WD1|zf_action); - zf_set_control(ctrl_reg); - spin_unlock_irqrestore(&zf_port_lock, flags); - - printk(KERN_INFO PFX ": Watchdog timer is now enabled\n"); -} - - -static void zf_ping(unsigned long data) -{ - unsigned int ctrl_reg = 0; - unsigned long flags; - - zf_writeb(COUNTER_2, 0xff); - - if(time_before(jiffies, next_heartbeat)){ - - dprintk("time_before: %ld\n", next_heartbeat - jiffies); - - /* - * reset event is activated by transition from 0 to 1 on - * RESET_WD1 bit and we assume that it is already zero... - */ - - spin_lock_irqsave(&zf_port_lock, flags); - ctrl_reg = zf_get_control(); - ctrl_reg |= RESET_WD1; - zf_set_control(ctrl_reg); - - /* ...and nothing changes until here */ - ctrl_reg &= ~(RESET_WD1); - zf_set_control(ctrl_reg); - spin_unlock_irqrestore(&zf_port_lock, flags); - - zf_timer.expires = jiffies + ZF_HW_TIMEO; - add_timer(&zf_timer); - }else{ - printk(KERN_CRIT PFX ": I will reset your machine\n"); - } -} - -static ssize_t zf_write(struct file *file, const char *buf, size_t count, - loff_t *ppos) -{ - /* Can't seek (pwrite) on this device */ - if (ppos != &file->f_pos) - return -ESPIPE; - - /* See if we got the magic character */ - if(count){ - -/* - * no need to check for close confirmation - * no way to disable watchdog ;) - */ - if (!nowayout) { - size_t ofs; - - /* - * note: just in case someone wrote the magic character - * five months ago... - */ - zf_expect_close = 0; - - /* now scan */ - for(ofs = 0; ofs != count; ofs++){ - char c; - if (get_user(c, buf + ofs)) - return -EFAULT; - if (c == 'V'){ - zf_expect_close = 1; - dprintk("zf_expect_close 1\n"); - } - } - } - /* - * Well, anyhow someone wrote to us, - * we should return that favour - */ - next_heartbeat = jiffies + ZF_USER_TIMEO; - dprintk("user ping at %ld\n", jiffies); - - return 1; - } - - return 0; -} - -static ssize_t zf_read(struct file *file, char *buf, size_t count, - loff_t *ppos) -{ - return -EINVAL; -} - - - -static int zf_ioctl(struct inode *inode, struct file *file, unsigned int cmd, - unsigned long arg) -{ - switch(cmd){ - case WDIOC_GETSUPPORT: - if (copy_to_user((struct watchdog_info *)arg, - &zf_info, sizeof(zf_info))) - return -EFAULT; - break; - - case WDIOC_GETSTATUS: - if (copy_to_user((int *)arg, &zf_is_open, sizeof(int))) - return -EFAULT; - break; - - case WDIOC_KEEPALIVE: - zf_ping(0); - break; - - default: - return -ENOTTY; - } - - return 0; -} - -static int zf_open(struct inode *inode, struct file *file) -{ - switch(minor(inode->i_rdev)){ - case WATCHDOG_MINOR: - spin_lock(&zf_lock); - if(zf_is_open){ - spin_unlock(&zf_lock); - return -EBUSY; - } - - if (nowayout) { - MOD_INC_USE_COUNT; - } - zf_is_open = 1; - - spin_unlock(&zf_lock); - - zf_timer_on(); - - return 0; - default: - return -ENODEV; - } -} - -static int zf_close(struct inode *inode, struct file *file) -{ - if(minor(inode->i_rdev) == WATCHDOG_MINOR){ - - if(zf_expect_close){ - zf_timer_off(); - } else { - del_timer(&zf_timer); - printk(KERN_ERR PFX ": device file closed unexpectedly. Will not stop the WDT!\n"); - } - - spin_lock(&zf_lock); - zf_is_open = 0; - spin_unlock(&zf_lock); - - zf_expect_close = 0; - } - - return 0; -} - -/* - * Notifier for system down - */ - -static int zf_notify_sys(struct notifier_block *this, unsigned long code, - void *unused) -{ - if(code == SYS_DOWN || code == SYS_HALT){ - zf_timer_off(); - } - - return NOTIFY_DONE; -} - - - - -static struct file_operations zf_fops = { - .owner = THIS_MODULE, - .read = zf_read, - .write = zf_write, - .ioctl = zf_ioctl, - .open = zf_open, - .release = zf_close, -}; - -static struct miscdevice zf_miscdev = { - WATCHDOG_MINOR, - "watchdog", - &zf_fops -}; - - -/* - * The device needs to learn about soft shutdowns in order to - * turn the timebomb registers off. - */ -static struct notifier_block zf_notifier = { - zf_notify_sys, - NULL, - 0 -}; - -static void __init zf_show_action(int act) -{ - char *str[] = { "RESET", "SMI", "NMI", "SCI" }; - - printk(KERN_INFO PFX ": Watchdog using action = %s\n", str[act]); -} - -static int __init zf_init(void) -{ - int ret; - - printk(KERN_INFO PFX ": MachZ ZF-Logic Watchdog driver initializing.\n"); - - ret = zf_get_ZFL_version(); - printk("%#x\n", ret); - if((!ret) || (ret != 0xffff)){ - printk(KERN_WARNING PFX ": no ZF-Logic found\n"); - return -ENODEV; - } - - if((action <= 3) && (action >= 0)){ - zf_action = zf_action>>action; - } else - action = 0; - - zf_show_action(action); - - spin_lock_init(&zf_lock); - spin_lock_init(&zf_port_lock); - - ret = misc_register(&zf_miscdev); - if (ret){ - printk(KERN_ERR "can't misc_register on minor=%d\n", - WATCHDOG_MINOR); - goto out; - } - - if(!request_region(ZF_IOBASE, 3, "MachZ ZFL WDT")){ - printk(KERN_ERR "cannot reserve I/O ports at %d\n", - ZF_IOBASE); - ret = -EBUSY; - goto no_region; - } - - ret = register_reboot_notifier(&zf_notifier); - if(ret){ - printk(KERN_ERR "can't register reboot notifier (err=%d)\n", - ret); - goto no_reboot; - } - - zf_set_status(0); - zf_set_control(0); - - /* this is the timer that will do the hard work */ - init_timer(&zf_timer); - zf_timer.function = zf_ping; - zf_timer.data = 0; - - return 0; - -no_reboot: - release_region(ZF_IOBASE, 3); -no_region: - misc_deregister(&zf_miscdev); -out: - return ret; -} - - -void __exit zf_exit(void) -{ - zf_timer_off(); - - misc_deregister(&zf_miscdev); - unregister_reboot_notifier(&zf_notifier); - release_region(ZF_IOBASE, 3); -} - -module_init(zf_init); -module_exit(zf_exit); diff -urpN --exclude-from=/home/davej/.exclude bk-linus/drivers/char/mixcomwd.c move-watchdogs/drivers/char/mixcomwd.c --- bk-linus/drivers/char/mixcomwd.c 2002-11-22 11:00:43.000000000 -0100 +++ move-watchdogs/drivers/char/mixcomwd.c 1969-12-31 23:00:00.000000000 -0100 @@ -1,282 +0,0 @@ -/* - * MixCom Watchdog: A Simple Hardware Watchdog Device - * Based on Softdog driver by Alan Cox and PC Watchdog driver by Ken Hollis - * - * Author: Gergely Madarasz - * - * Copyright (c) 1999 ITConsult-Pro Co. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version - * 2 of the License, or (at your option) any later version. - * - * Version 0.1 (99/04/15): - * - first version - * - * Version 0.2 (99/06/16): - * - added kernel timer watchdog ping after close - * since the hardware does not support watchdog shutdown - * - * Version 0.3 (99/06/21): - * - added WDIOC_GETSTATUS and WDIOC_GETSUPPORT ioctl calls - * - * Version 0.3.1 (99/06/22): - * - allow module removal while internal timer is active, - * print warning about probable reset - * - * Version 0.4 (99/11/15): - * - support for one more type board - * - * Version 0.5 (2001/12/14) Matt Domsch - * - added nowayout module option to override CONFIG_WATCHDOG_NOWAYOUT - * - */ - -#define VERSION "0.5" - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -static int mixcomwd_ioports[] = { 0x180, 0x280, 0x380, 0x000 }; - -#define MIXCOM_WATCHDOG_OFFSET 0xc10 -#define MIXCOM_ID 0x11 -#define FLASHCOM_WATCHDOG_OFFSET 0x4 -#define FLASHCOM_ID 0x18 - -static long mixcomwd_opened; /* long req'd for setbit --RR */ - -static int watchdog_port; -static int mixcomwd_timer_alive; -static struct timer_list mixcomwd_timer = TIMER_INITIALIZER(NULL, 0, 0); - -#ifdef CONFIG_WATCHDOG_NOWAYOUT -static int nowayout = 1; -#else -static int nowayout = 0; -#endif - -MODULE_PARM(nowayout,"i"); -MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default=CONFIG_WATCHDOG_NOWAYOUT)"); - -static void mixcomwd_ping(void) -{ - outb_p(55,watchdog_port); - return; -} - -static void mixcomwd_timerfun(unsigned long d) -{ - mixcomwd_ping(); - - mod_timer(&mixcomwd_timer,jiffies+ 5*HZ); -} - -/* - * Allow only one person to hold it open - */ - -static int mixcomwd_open(struct inode *inode, struct file *file) -{ - if(test_and_set_bit(0,&mixcomwd_opened)) { - return -EBUSY; - } - mixcomwd_ping(); - - if (nowayout) { - MOD_INC_USE_COUNT; - } else { - if(mixcomwd_timer_alive) { - del_timer(&mixcomwd_timer); - mixcomwd_timer_alive=0; - } - } - return 0; -} - -static int mixcomwd_release(struct inode *inode, struct file *file) -{ - - if (!nowayout) { - if(mixcomwd_timer_alive) { - printk(KERN_ERR "mixcomwd: release called while internal timer alive"); - return -EBUSY; - } - init_timer(&mixcomwd_timer); - mixcomwd_timer.expires=jiffies + 5 * HZ; - mixcomwd_timer.function=mixcomwd_timerfun; - mixcomwd_timer.data=0; - mixcomwd_timer_alive=1; - add_timer(&mixcomwd_timer); - } - clear_bit(0,&mixcomwd_opened); - return 0; -} - - -static ssize_t mixcomwd_write(struct file *file, const char *data, size_t len, loff_t *ppos) -{ - if (ppos != &file->f_pos) { - return -ESPIPE; - } - - if(len) - { - mixcomwd_ping(); - return 1; - } - return 0; -} - -static int mixcomwd_ioctl(struct inode *inode, struct file *file, - unsigned int cmd, unsigned long arg) -{ - int status; - static struct watchdog_info ident = { - WDIOF_KEEPALIVEPING, 1, "MixCOM watchdog" - }; - - switch(cmd) - { - case WDIOC_GETSTATUS: - status=mixcomwd_opened; - if (!nowayout) { - status|=mixcomwd_timer_alive; - } - if (copy_to_user((int *)arg, &status, sizeof(int))) { - return -EFAULT; - } - break; - case WDIOC_GETSUPPORT: - if (copy_to_user((struct watchdog_info *)arg, &ident, - sizeof(ident))) { - return -EFAULT; - } - break; - case WDIOC_KEEPALIVE: - mixcomwd_ping(); - break; - default: - return -ENOTTY; - } - return 0; -} - -static struct file_operations mixcomwd_fops= -{ - .owner = THIS_MODULE, - .write = mixcomwd_write, - .ioctl = mixcomwd_ioctl, - .open = mixcomwd_open, - .release = mixcomwd_release, -}; - -static struct miscdevice mixcomwd_miscdev= -{ - WATCHDOG_MINOR, - "watchdog", - &mixcomwd_fops -}; - -static int __init mixcomwd_checkcard(int port) -{ - int id; - - if(check_region(port+MIXCOM_WATCHDOG_OFFSET,1)) { - return 0; - } - - id=inb_p(port + MIXCOM_WATCHDOG_OFFSET) & 0x3f; - if(id!=MIXCOM_ID) { - return 0; - } - return 1; -} - -static int __init flashcom_checkcard(int port) -{ - int id; - - if(check_region(port + FLASHCOM_WATCHDOG_OFFSET,1)) { - return 0; - } - - id=inb_p(port + FLASHCOM_WATCHDOG_OFFSET); - if(id!=FLASHCOM_ID) { - return 0; - } - return 1; - } - -static int __init mixcomwd_init(void) -{ - int i; - int ret; - int found=0; - - for (i = 0; !found && mixcomwd_ioports[i] != 0; i++) { - if (mixcomwd_checkcard(mixcomwd_ioports[i])) { - found = 1; - watchdog_port = mixcomwd_ioports[i] + MIXCOM_WATCHDOG_OFFSET; - } - } - - /* The FlashCOM card can be set up at 0x300 -> 0x378, in 0x8 jumps */ - for (i = 0x300; !found && i < 0x380; i+=0x8) { - if (flashcom_checkcard(i)) { - found = 1; - watchdog_port = i + FLASHCOM_WATCHDOG_OFFSET; - } - } - - if (!found) { - printk("mixcomwd: No card detected, or port not available.\n"); - return -ENODEV; - } - - if (!request_region(watchdog_port,1,"MixCOM watchdog")) - return -EIO; - - ret = misc_register(&mixcomwd_miscdev); - if (ret) - { - release_region(watchdog_port, 1); - return ret; - } - - printk(KERN_INFO "MixCOM watchdog driver v%s, watchdog port at 0x%3x\n",VERSION,watchdog_port); - - return 0; -} - -static void __exit mixcomwd_exit(void) -{ - if (!nowayout) { - if(mixcomwd_timer_alive) { - printk(KERN_WARNING "mixcomwd: I quit now, hardware will" - " probably reboot!\n"); - del_timer(&mixcomwd_timer); - mixcomwd_timer_alive=0; - } - } - release_region(watchdog_port,1); - misc_deregister(&mixcomwd_miscdev); -} - -module_init(mixcomwd_init); -module_exit(mixcomwd_exit); - -MODULE_LICENSE("GPL"); diff -urpN --exclude-from=/home/davej/.exclude bk-linus/drivers/char/pcwd.c move-watchdogs/drivers/char/pcwd.c --- bk-linus/drivers/char/pcwd.c 2002-11-22 11:00:43.000000000 -0100 +++ move-watchdogs/drivers/char/pcwd.c 1969-12-31 23:00:00.000000000 -0100 @@ -1,672 +0,0 @@ -/* - * PC Watchdog Driver - * by Ken Hollis (khollis@bitgate.com) - * - * Permission granted from Simon Machell (73244.1270@compuserve.com) - * Written for the Linux Kernel, and GPLed by Ken Hollis - * - * 960107 Added request_region routines, modulized the whole thing. - * 960108 Fixed end-of-file pointer (Thanks to Dan Hollis), added - * WD_TIMEOUT define. - * 960216 Added eof marker on the file, and changed verbose messages. - * 960716 Made functional and cosmetic changes to the source for - * inclusion in Linux 2.0.x kernels, thanks to Alan Cox. - * 960717 Removed read/seek routines, replaced with ioctl. Also, added - * check_region command due to Alan's suggestion. - * 960821 Made changes to compile in newer 2.0.x kernels. Added - * "cold reboot sense" entry. - * 960825 Made a few changes to code, deleted some defines and made - * typedefs to replace them. Made heartbeat reset only available - * via ioctl, and removed the write routine. - * 960828 Added new items for PC Watchdog Rev.C card. - * 960829 Changed around all of the IOCTLs, added new features, - * added watchdog disable/re-enable routines. Added firmware - * version reporting. Added read routine for temperature. - * Removed some extra defines, added an autodetect Revision - * routine. - * 961006 Revised some documentation, fixed some cosmetic bugs. Made - * drivers to panic the system if it's overheating at bootup. - * 961118 Changed some verbiage on some of the output, tidied up - * code bits, and added compatibility to 2.1.x. - * 970912 Enabled board on open and disable on close. - * 971107 Took account of recent VFS changes (broke read). - * 971210 Disable board on initialisation in case board already ticking. - * 971222 Changed open/close for temperature handling - * Michael Meskes . - * 980112 Used minor numbers from include/linux/miscdevice.h - * 990403 Clear reset status after reading control status register in - * pcwd_showprevstate(). [Marc Boucher ] - * 990605 Made changes to code to support Firmware 1.22a, added - * fairly useless proc entry. - * 990610 removed said useless proc code for the merge - * 000403 Removed last traces of proc code. - */ - -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include - -/* - * These are the auto-probe addresses available. - * - * Revision A only uses ports 0x270 and 0x370. Revision C introduced 0x350. - * Revision A has an address range of 2 addresses, while Revision C has 3. - */ -static int pcwd_ioports[] = { 0x270, 0x350, 0x370, 0x000 }; - -#define WD_VER "1.10 (06/05/99)" - -/* - * It should be noted that PCWD_REVISION_B was removed because A and B - * are essentially the same types of card, with the exception that B - * has temperature reporting. Since I didn't receive a Rev.B card, - * the Rev.B card is not supported. (It's a good thing too, as they - * are no longer in production.) - */ -#define PCWD_REVISION_A 1 -#define PCWD_REVISION_C 2 - -#define WD_TIMEOUT 3 /* 1 1/2 seconds for a timeout */ - -/* - * These are the defines for the PC Watchdog card, revision A. - */ -#define WD_WDRST 0x01 /* Previously reset state */ -#define WD_T110 0x02 /* Temperature overheat sense */ -#define WD_HRTBT 0x04 /* Heartbeat sense */ -#define WD_RLY2 0x08 /* External relay triggered */ -#define WD_SRLY2 0x80 /* Software external relay triggered */ - -static int current_readport, revision, temp_panic; -static atomic_t open_allowed = ATOMIC_INIT(1); -static int initial_status, supports_temp, mode_debug; -static spinlock_t io_lock; - -/* - * PCWD_CHECKCARD - * - * This routine checks the "current_readport" to see if the card lies there. - * If it does, it returns accordingly. - */ -static int __init pcwd_checkcard(void) -{ - int card_dat, prev_card_dat, found = 0, count = 0, done = 0; - - card_dat = 0x00; - prev_card_dat = 0x00; - - prev_card_dat = inb(current_readport); - if (prev_card_dat == 0xFF) - return 0; - - while(count < WD_TIMEOUT) { - - /* Read the raw card data from the port, and strip off the - first 4 bits */ - - card_dat = inb_p(current_readport); - card_dat &= 0x000F; - - /* Sleep 1/2 second (or 500000 microseconds :) */ - - mdelay(500); - done = 0; - - /* If there's a heart beat in both instances, then this means we - found our card. This also means that either the card was - previously reset, or the computer was power-cycled. */ - - if ((card_dat & WD_HRTBT) && (prev_card_dat & WD_HRTBT) && - (!done)) { - found = 1; - done = 1; - break; - } - - /* If the card data is exactly the same as the previous card data, - it's safe to assume that we should check again. The manual says - that the heart beat will change every second (or the bit will - toggle), and this can be used to see if the card is there. If - the card was powered up with a cold boot, then the card will - not start blinking until 2.5 minutes after a reboot, so this - bit will stay at 1. */ - - if ((card_dat == prev_card_dat) && (!done)) { - count++; - done = 1; - } - - /* If the card data is toggling any bits, this means that the heart - beat was detected, or something else about the card is set. */ - - if ((card_dat != prev_card_dat) && (!done)) { - done = 1; - found = 1; - break; - } - - /* Otherwise something else strange happened. */ - - if (!done) - count++; - } - - return((found) ? 1 : 0); -} - -void pcwd_showprevstate(void) -{ - int card_status = 0x0000; - - if (revision == PCWD_REVISION_A) - initial_status = card_status = inb(current_readport); - else { - initial_status = card_status = inb(current_readport + 1); - outb_p(0x00, current_readport + 1); /* clear reset status */ - } - - if (revision == PCWD_REVISION_A) { - if (card_status & WD_WDRST) - printk("pcwd: Previous reboot was caused by the card.\n"); - - if (card_status & WD_T110) { - printk("pcwd: Card senses a CPU Overheat. Panicking!\n"); - panic("pcwd: CPU Overheat.\n"); - } - - if ((!(card_status & WD_WDRST)) && - (!(card_status & WD_T110))) - printk("pcwd: Cold boot sense.\n"); - } else { - if (card_status & 0x01) - printk("pcwd: Previous reboot was caused by the card.\n"); - - if (card_status & 0x04) { - printk("pcwd: Card senses a CPU Overheat. Panicking!\n"); - panic("pcwd: CPU Overheat.\n"); - } - - if ((!(card_status & 0x01)) && - (!(card_status & 0x04))) - printk("pcwd: Cold boot sense.\n"); - } -} - -static void pcwd_send_heartbeat(void) -{ - int wdrst_stat; - - wdrst_stat = inb_p(current_readport); - wdrst_stat &= 0x0F; - - wdrst_stat |= WD_WDRST; - - if (revision == PCWD_REVISION_A) - outb_p(wdrst_stat, current_readport + 1); - else - outb_p(wdrst_stat, current_readport); -} - -static int pcwd_ioctl(struct inode *inode, struct file *file, - unsigned int cmd, unsigned long arg) -{ - int cdat, rv; - static struct watchdog_info ident= - { - WDIOF_OVERHEAT|WDIOF_CARDRESET, - 1, - "PCWD" - }; - - switch(cmd) { - default: - return -ENOTTY; - - case WDIOC_GETSUPPORT: - if(copy_to_user((void*)arg, &ident, sizeof(ident))) - return -EFAULT; - return 0; - - case WDIOC_GETSTATUS: - spin_lock(&io_lock); - if (revision == PCWD_REVISION_A) - cdat = inb(current_readport); - else - cdat = inb(current_readport + 1 ); - spin_unlock(&io_lock); - rv = 0; - - if (revision == PCWD_REVISION_A) - { - if (cdat & WD_WDRST) - rv |= WDIOF_CARDRESET; - - if (cdat & WD_T110) - { - rv |= WDIOF_OVERHEAT; - - if (temp_panic) - panic("pcwd: Temperature overheat trip!\n"); - } - } - else - { - if (cdat & 0x01) - rv |= WDIOF_CARDRESET; - - if (cdat & 0x04) - { - rv |= WDIOF_OVERHEAT; - - if (temp_panic) - panic("pcwd: Temperature overheat trip!\n"); - } - } - - if(put_user(rv, (int *) arg)) - return -EFAULT; - return 0; - - case WDIOC_GETBOOTSTATUS: - rv = 0; - - if (revision == PCWD_REVISION_A) - { - if (initial_status & WD_WDRST) - rv |= WDIOF_CARDRESET; - - if (initial_status & WD_T110) - rv |= WDIOF_OVERHEAT; - } - else - { - if (initial_status & 0x01) - rv |= WDIOF_CARDRESET; - - if (initial_status & 0x04) - rv |= WDIOF_OVERHEAT; - } - - if(put_user(rv, (int *) arg)) - return -EFAULT; - return 0; - - case WDIOC_GETTEMP: - - rv = 0; - if ((supports_temp) && (mode_debug == 0)) - { - spin_lock(&io_lock); - rv = inb(current_readport); - spin_unlock(&io_lock); - if(put_user(rv, (int*) arg)) - return -EFAULT; - } else if(put_user(rv, (int*) arg)) - return -EFAULT; - return 0; - - case WDIOC_SETOPTIONS: - if (revision == PCWD_REVISION_C) - { - if(copy_from_user(&rv, (int*) arg, sizeof(int))) - return -EFAULT; - - if (rv & WDIOS_DISABLECARD) - { - spin_lock(&io_lock); - outb_p(0xA5, current_readport + 3); - outb_p(0xA5, current_readport + 3); - cdat = inb_p(current_readport + 2); - spin_unlock(&io_lock); - if ((cdat & 0x10) == 0) - { - printk("pcwd: Could not disable card.\n"); - return -EIO; - } - - return 0; - } - - if (rv & WDIOS_ENABLECARD) - { - spin_lock(&io_lock); - outb_p(0x00, current_readport + 3); - cdat = inb_p(current_readport + 2); - spin_unlock(&io_lock); - if (cdat & 0x10) - { - printk("pcwd: Could not enable card.\n"); - return -EIO; - } - return 0; - } - - if (rv & WDIOS_TEMPPANIC) - { - temp_panic = 1; - } - } - return -EINVAL; - - case WDIOC_KEEPALIVE: - pcwd_send_heartbeat(); - return 0; - } - - return 0; -} - -static ssize_t pcwd_write(struct file *file, const char *buf, size_t len, - loff_t *ppos) -{ - /* Can't seek (pwrite) on this device */ - if (ppos != &file->f_pos) - return -ESPIPE; - - if (len) - { - pcwd_send_heartbeat(); - return 1; - } - return 0; -} - -static int pcwd_open(struct inode *ino, struct file *filep) -{ - switch (minor(ino->i_rdev)) - { - case WATCHDOG_MINOR: - if ( !atomic_dec_and_test(&open_allowed) ) - { - atomic_inc( &open_allowed ); - return -EBUSY; - } - MOD_INC_USE_COUNT; - /* Enable the port */ - if (revision == PCWD_REVISION_C) - { - spin_lock(&io_lock); - outb_p(0x00, current_readport + 3); - spin_unlock(&io_lock); - } - return(0); - case TEMP_MINOR: - return(0); - default: - return (-ENODEV); - } -} - -static ssize_t pcwd_read(struct file *file, char *buf, size_t count, - loff_t *ppos) -{ - unsigned short c; - unsigned char cp; - - /* Can't seek (pread) on this device */ - if (ppos != &file->f_pos) - return -ESPIPE; - switch(minor(file->f_dentry->d_inode->i_rdev)) - { - case TEMP_MINOR: - /* - * Convert metric to Fahrenheit, since this was - * the decided 'standard' for this return value. - */ - - c = inb(current_readport); - cp = (c * 9 / 5) + 32; - if(copy_to_user(buf, &cp, 1)) - return -EFAULT; - return 1; - default: - return -EINVAL; - } -} - -static int pcwd_close(struct inode *ino, struct file *filep) -{ - if (minor(ino->i_rdev)==WATCHDOG_MINOR) - { -#ifndef CONFIG_WATCHDOG_NOWAYOUT - /* Disable the board */ - if (revision == PCWD_REVISION_C) { - spin_lock(&io_lock); - outb_p(0xA5, current_readport + 3); - outb_p(0xA5, current_readport + 3); - spin_unlock(&io_lock); - } - atomic_inc( &open_allowed ); -#endif - } - return 0; -} - -static inline void get_support(void) -{ - if (inb(current_readport) != 0xF0) - supports_temp = 1; -} - -static inline int get_revision(void) -{ - int r = PCWD_REVISION_C; - - spin_lock(&io_lock); - if ((inb(current_readport + 2) == 0xFF) || - (inb(current_readport + 3) == 0xFF)) - r=PCWD_REVISION_A; - spin_unlock(&io_lock); - - return r; -} - -static int __init send_command(int cmd) -{ - int i; - - outb_p(cmd, current_readport + 2); - mdelay(1); - - i = inb(current_readport); - i = inb(current_readport); - - return(i); -} - -static inline char *get_firmware(void) -{ - int i, found = 0, count = 0, one, ten, hund, minor; - char *ret; - - ret = kmalloc(6, GFP_KERNEL); - if(ret == NULL) - return NULL; - - while((count < 3) && (!found)) { - outb_p(0x80, current_readport + 2); - i = inb(current_readport); - - if (i == 0x00) - found = 1; - else if (i == 0xF3) - outb_p(0x00, current_readport + 2); - - udelay(400L); - count++; - } - - if (found) { - mode_debug = 1; - - one = send_command(0x81); - ten = send_command(0x82); - hund = send_command(0x83); - minor = send_command(0x84); - sprintf(ret, "%c.%c%c%c", one, ten, hund, minor); - } - else - sprintf(ret, "ERROR"); - - return(ret); -} - -static void debug_off(void) -{ - outb_p(0x00, current_readport + 2); - mode_debug = 0; -} - -static struct file_operations pcwd_fops = { - .owner = THIS_MODULE, - .read = pcwd_read, - .write = pcwd_write, - .ioctl = pcwd_ioctl, - .open = pcwd_open, - .release = pcwd_close, -}; - -static struct miscdevice pcwd_miscdev = { - WATCHDOG_MINOR, - "watchdog", - &pcwd_fops -}; - -static struct miscdevice temp_miscdev = { - TEMP_MINOR, - "temperature", - &pcwd_fops -}; - -static int __init pcwatchdog_init(void) -{ - int i, found = 0; - spin_lock_init(&io_lock); - - revision = PCWD_REVISION_A; - - printk("pcwd: v%s Ken Hollis (kenji@bitgate.com)\n", WD_VER); - - /* Initial variables */ - supports_temp = 0; - mode_debug = 0; - temp_panic = 0; - initial_status = 0x0000; - -#ifndef PCWD_BLIND - for (i = 0; pcwd_ioports[i] != 0; i++) { - current_readport = pcwd_ioports[i]; - - if (pcwd_checkcard()) { - found = 1; - break; - } - } - - if (!found) { - printk("pcwd: No card detected, or port not available.\n"); - return(-EIO); - } -#endif - -#ifdef PCWD_BLIND - current_readport = PCWD_BLIND; -#endif - - get_support(); - revision = get_revision(); - - if (revision == PCWD_REVISION_A) - printk("pcwd: PC Watchdog (REV.A) detected at port 0x%03x\n", current_readport); - else if (revision == PCWD_REVISION_C) - printk("pcwd: PC Watchdog (REV.C) detected at port 0x%03x (Firmware version: %s)\n", - current_readport, get_firmware()); - else { - /* Should NEVER happen, unless get_revision() fails. */ - printk("pcwd: Unable to get revision.\n"); - return -1; - } - - if (supports_temp) - printk("pcwd: Temperature Option Detected.\n"); - - debug_off(); - - pcwd_showprevstate(); - - /* Disable the board */ - if (revision == PCWD_REVISION_C) { - outb_p(0xA5, current_readport + 3); - outb_p(0xA5, current_readport + 3); - } - - if (misc_register(&pcwd_miscdev)) - return -ENODEV; - - if (supports_temp) - if (misc_register(&temp_miscdev)) { - misc_deregister(&pcwd_miscdev); - return -ENODEV; - } - - - if (revision == PCWD_REVISION_A) { - if (!request_region(current_readport, 2, "PCWD Rev.A (Berkshire)")) { - misc_deregister(&pcwd_miscdev); - if (supports_temp) - misc_deregister(&pcwd_miscdev); - return -EIO; - } - } - else - if (!request_region(current_readport, 4, "PCWD Rev.C (Berkshire)")) { - misc_deregister(&pcwd_miscdev); - if (supports_temp) - misc_deregister(&pcwd_miscdev); - return -EIO; - } - - return 0; -} - -static void __exit pcwatchdog_exit(void) -{ - misc_deregister(&pcwd_miscdev); - /* Disable the board */ - if (revision == PCWD_REVISION_C) { - outb_p(0xA5, current_readport + 3); - outb_p(0xA5, current_readport + 3); - } - if (supports_temp) - misc_deregister(&temp_miscdev); - - release_region(current_readport, (revision == PCWD_REVISION_A) ? 2 : 4); -} - -module_init(pcwatchdog_init); -module_exit(pcwatchdog_exit); - -MODULE_LICENSE("GPL"); - diff -urpN --exclude-from=/home/davej/.exclude bk-linus/drivers/char/sbc60xxwdt.c move-watchdogs/drivers/char/sbc60xxwdt.c --- bk-linus/drivers/char/sbc60xxwdt.c 2002-11-22 11:00:43.000000000 -0100 +++ move-watchdogs/drivers/char/sbc60xxwdt.c 1969-12-31 23:00:00.000000000 -0100 @@ -1,354 +0,0 @@ -/* - * 60xx Single Board Computer Watchdog Timer driver for Linux 2.2.x - * - * Based on acquirewdt.c by Alan Cox. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version - * 2 of the License, or (at your option) any later version. - * - * The author does NOT admit liability nor provide warranty for - * any of this software. This material is provided "AS-IS" in - * the hope that it may be useful for others. - * - * (c) Copyright 2000 Jakob Oestergaard - * - * 12/4 - 2000 [Initial revision] - * 25/4 - 2000 Added /dev/watchdog support - * 09/5 - 2001 [smj@oro.net] fixed fop_write to "return 1" on success - * - * - * Theory of operation: - * A Watchdog Timer (WDT) is a hardware circuit that can - * reset the computer system in case of a software fault. - * You probably knew that already. - * - * Usually a userspace daemon will notify the kernel WDT driver - * via the /proc/watchdog special device file that userspace is - * still alive, at regular intervals. When such a notification - * occurs, the driver will usually tell the hardware watchdog - * that everything is in order, and that the watchdog should wait - * for yet another little while to reset the system. - * If userspace fails (RAM error, kernel bug, whatever), the - * notifications cease to occur, and the hardware watchdog will - * reset the system (causing a reboot) after the timeout occurs. - * - * This WDT driver is different from the other Linux WDT - * drivers in several ways: - * *) The driver will ping the watchdog by itself, because this - * particular WDT has a very short timeout (one second) and it - * would be insane to count on any userspace daemon always - * getting scheduled within that time frame. - * *) This driver expects the userspace daemon to send a specific - * character code ('V') to /dev/watchdog before closing the - * /dev/watchdog file. If the userspace daemon closes the file - * without sending this special character, the driver will assume - * that the daemon (and userspace in general) died, and will - * stop pinging the WDT without disabling it first. This will - * cause a reboot. - * - * Why `V' ? Well, `V' is the character in ASCII for the value 86, - * and we all know that 86 is _the_ most random number in the universe. - * Therefore it is the letter that has the slightest chance of occuring - * by chance, when the system becomes corrupted. - * - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#define OUR_NAME "sbc60xxwdt" - -/* - * You must set these - The driver cannot probe for the settings - */ - -#define WDT_STOP 0x45 -#define WDT_START 0x443 - -/* - * The 60xx board can use watchdog timeout values from one second - * to several minutes. The default is one second, so if we reset - * the watchdog every ~250ms we should be safe. - */ - -#define WDT_INTERVAL (HZ/4+1) - -/* - * We must not require too good response from the userspace daemon. - * Here we require the userspace daemon to send us a heartbeat - * char to /dev/watchdog every 10 seconds. - * If the daemon pulses us every 5 seconds, we can still afford - * a 5 second scheduling delay on the (high priority) daemon. That - * should be sufficient for a box under any load. - */ - -#define WDT_HEARTBEAT (HZ * 10) - -static void wdt_timer_ping(unsigned long); -static struct timer_list timer; -static unsigned long next_heartbeat; -static int wdt_is_open; -static int wdt_expect_close; - -#ifdef CONFIG_WATCHDOG_NOWAYOUT -static int nowayout = 1; -#else -static int nowayout = 0; -#endif - -MODULE_PARM(nowayout,"i"); -MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default=CONFIG_WATCHDOG_NOWAYOUT)"); - -/* - * Whack the dog - */ - -static void wdt_timer_ping(unsigned long data) -{ - /* If we got a heartbeat pulse within the WDT_US_INTERVAL - * we agree to ping the WDT - */ - if(time_before(jiffies, next_heartbeat)) - { - /* Ping the WDT by reading from WDT_START */ - inb_p(WDT_START); - /* Re-set the timer interval */ - timer.expires = jiffies + WDT_INTERVAL; - add_timer(&timer); - } else { - printk(OUR_NAME ": Heartbeat lost! Will not ping the watchdog\n"); - } -} - -/* - * Utility routines - */ - -static void wdt_startup(void) -{ - next_heartbeat = jiffies + WDT_HEARTBEAT; - - /* Start the timer */ - timer.expires = jiffies + WDT_INTERVAL; - add_timer(&timer); - printk(OUR_NAME ": Watchdog timer is now enabled.\n"); -} - -static void wdt_turnoff(void) -{ - /* Stop the timer */ - del_timer(&timer); - inb_p(WDT_STOP); - printk(OUR_NAME ": Watchdog timer is now disabled...\n"); -} - - -/* - * /dev/watchdog handling - */ - -static ssize_t fop_write(struct file * file, const char * buf, size_t count, loff_t * ppos) -{ - /* We can't seek */ - if(ppos != &file->f_pos) - return -ESPIPE; - - /* See if we got the magic character */ - if(count) - { - size_t ofs; - - /* note: just in case someone wrote the magic character - * five months ago... */ - wdt_expect_close = 0; - - /* now scan */ - for(ofs = 0; ofs != count; ofs++) - { - char c; - if(get_user(c, buf+ofs)) - return -EFAULT; - if(c == 'V') - wdt_expect_close = 1; - } - /* Well, anyhow someone wrote to us, we should return that favour */ - next_heartbeat = jiffies + WDT_HEARTBEAT; - return 1; - } - return 0; -} - -static ssize_t fop_read(struct file * file, char * buf, size_t count, loff_t * ppos) -{ - /* No can do */ - return -EINVAL; -} - -static int fop_open(struct inode * inode, struct file * file) -{ - switch(minor(inode->i_rdev)) - { - case WATCHDOG_MINOR: - /* Just in case we're already talking to someone... */ - if(wdt_is_open) - return -EBUSY; - if (nowayout) { - MOD_INC_USE_COUNT; - } - /* Good, fire up the show */ - wdt_is_open = 1; - wdt_startup(); - return 0; - - default: - return -ENODEV; - } -} - -static int fop_close(struct inode * inode, struct file * file) -{ - if(minor(inode->i_rdev) == WATCHDOG_MINOR) - { - if(wdt_expect_close && !nowayout) - wdt_turnoff(); - else { - del_timer(&timer); - printk(OUR_NAME ": device file closed unexpectedly. Will not stop the WDT!\n"); - } - } - wdt_is_open = 0; - return 0; -} - -static int fop_ioctl(struct inode *inode, struct file *file, unsigned int cmd, - unsigned long arg) -{ - static struct watchdog_info ident= - { - 0, - 1, - "SB60xx" - }; - - switch(cmd) - { - default: - return -ENOTTY; - case WDIOC_GETSUPPORT: - return copy_to_user((struct watchdog_info *)arg, &ident, sizeof(ident))?-EFAULT:0; - case WDIOC_KEEPALIVE: - next_heartbeat = jiffies + WDT_HEARTBEAT; - return 0; - } -} - -static struct file_operations wdt_fops = { - .owner = THIS_MODULE, - .llseek = no_llseek, - .read = fop_read, - .write = fop_write, - .open = fop_open, - .release = fop_close, - .ioctl = fop_ioctl -}; - -static struct miscdevice wdt_miscdev = { - WATCHDOG_MINOR, - "watchdog", - &wdt_fops -}; - -/* - * Notifier for system down - */ - -static int wdt_notify_sys(struct notifier_block *this, unsigned long code, - void *unused) -{ - if(code==SYS_DOWN || code==SYS_HALT) - wdt_turnoff(); - return NOTIFY_DONE; -} - -/* - * The WDT needs to learn about soft shutdowns in order to - * turn the timebomb registers off. - */ - -static struct notifier_block wdt_notifier= -{ - wdt_notify_sys, - 0, - 0 -}; - -static void __exit sbc60xxwdt_unload(void) -{ - wdt_turnoff(); - - /* Deregister */ - misc_deregister(&wdt_miscdev); - - unregister_reboot_notifier(&wdt_notifier); - release_region(WDT_START,1); - release_region(WDT_STOP,1); -} - -static int __init sbc60xxwdt_init(void) -{ - int rc = -EBUSY; - - if (!request_region(WDT_STOP, 1, "SBC 60XX WDT")) - goto err_out; - if (!request_region(WDT_START, 1, "SBC 60XX WDT")) - goto err_out_region1; - - init_timer(&timer); - timer.function = wdt_timer_ping; - timer.data = 0; - - rc = misc_register(&wdt_miscdev); - if (rc) - goto err_out_region2; - - rc = register_reboot_notifier(&wdt_notifier); - if (rc) - goto err_out_miscdev; - - printk(KERN_INFO OUR_NAME ": WDT driver for 60XX single board computer initialised.\n"); - - return 0; - -err_out_miscdev: - misc_deregister(&wdt_miscdev); -err_out_region2: - release_region(WDT_START,1); -err_out_region1: - release_region(WDT_STOP,1); -err_out: - return rc; -} - -module_init(sbc60xxwdt_init); -module_exit(sbc60xxwdt_unload); - -MODULE_LICENSE("GPL"); diff -urpN --exclude-from=/home/davej/.exclude bk-linus/drivers/char/scx200_wdt.c move-watchdogs/drivers/char/scx200_wdt.c --- bk-linus/drivers/char/scx200_wdt.c 2002-11-22 11:00:43.000000000 -0100 +++ move-watchdogs/drivers/char/scx200_wdt.c 1969-12-31 23:00:00.000000000 -0100 @@ -1,277 +0,0 @@ -/* linux/drivers/char/scx200_wdt.c - - National Semiconductor SCx200 Watchdog support - - Copyright (c) 2001,2002 Christer Weinigel - - Som code taken from: - National Semiconductor PC87307/PC97307 (ala SC1200) WDT driver - (c) Copyright 2002 Zwane Mwaikambo - - This program is free software; you can redistribute it and/or - modify it under the terms of the GNU General Public License as - published by the Free Software Foundation; either version 2 of the - License, or (at your option) any later version. - - 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. */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include - -#define NAME "scx200_wdt" - -MODULE_AUTHOR("Christer Weinigel "); -MODULE_DESCRIPTION("NatSemi SCx200 Watchdog Driver"); -MODULE_LICENSE("GPL"); - -#ifndef CONFIG_WATCHDOG_NOWAYOUT -#define CONFIG_WATCHDOG_NOWAYOUT 0 -#endif - -static int margin = 60; /* in seconds */ -MODULE_PARM(margin, "i"); -MODULE_PARM_DESC(margin, "Watchdog margin in seconds"); - -static int nowayout = CONFIG_WATCHDOG_NOWAYOUT; -MODULE_PARM(nowayout, "i"); -MODULE_PARM_DESC(nowayout, "Disable watchdog shutdown on close"); - -static u16 wdto_restart; -static struct semaphore open_semaphore; -static unsigned expect_close; - -/* Bits of the WDCNFG register */ -#define W_ENABLE 0x00fa /* Enable watchdog */ -#define W_DISABLE 0x0000 /* Disable watchdog */ - -/* The scaling factor for the timer, this depends on the value of W_ENABLE */ -#define W_SCALE (32768/1024) - -static void scx200_wdt_ping(void) -{ - outw(wdto_restart, SCx200_CB_BASE + SCx200_WDT_WDTO); -} - -static void scx200_wdt_update_margin(void) -{ - printk(KERN_INFO NAME ": timer margin %d seconds\n", margin); - wdto_restart = margin * W_SCALE; -} - -static void scx200_wdt_enable(void) -{ - printk(KERN_DEBUG NAME ": enabling watchdog timer, wdto_restart = %d\n", - wdto_restart); - - outw(0, SCx200_CB_BASE + SCx200_WDT_WDTO); - outb(SCx200_WDT_WDSTS_WDOVF, SCx200_CB_BASE + SCx200_WDT_WDSTS); - outw(W_ENABLE, SCx200_CB_BASE + SCx200_WDT_WDCNFG); - - scx200_wdt_ping(); -} - -static void scx200_wdt_disable(void) -{ - printk(KERN_DEBUG NAME ": disabling watchdog timer\n"); - - outw(0, SCx200_CB_BASE + SCx200_WDT_WDTO); - outb(SCx200_WDT_WDSTS_WDOVF, SCx200_CB_BASE + SCx200_WDT_WDSTS); - outw(W_DISABLE, SCx200_CB_BASE + SCx200_WDT_WDCNFG); -} - -static int scx200_wdt_open(struct inode *inode, struct file *file) -{ - /* only allow one at a time */ - if (down_trylock(&open_semaphore)) - return -EBUSY; - scx200_wdt_enable(); - expect_close = 0; - - return 0; -} - -static int scx200_wdt_release(struct inode *inode, struct file *file) -{ - if (!expect_close) { - printk(KERN_WARNING NAME ": watchdog device closed unexpectedly, will not disable the watchdog timer\n"); - } else if (!nowayout) { - scx200_wdt_disable(); - } - up(&open_semaphore); - - return 0; -} - -static int scx200_wdt_notify_sys(struct notifier_block *this, - unsigned long code, void *unused) -{ - if (code == SYS_HALT || code == SYS_POWER_OFF) - if (!nowayout) - scx200_wdt_disable(); - - return NOTIFY_DONE; -} - -static struct notifier_block scx200_wdt_notifier = -{ - .notifier_call = scx200_wdt_notify_sys -}; - -static ssize_t scx200_wdt_write(struct file *file, const char *data, - size_t len, loff_t *ppos) -{ - if (ppos != &file->f_pos) - return -ESPIPE; - - /* check for a magic close character */ - if (len) - { - size_t i; - - scx200_wdt_ping(); - - expect_close = 0; - for (i = 0; i < len; ++i) { - char c; - if (get_user(c, data+i)) - return -EFAULT; - if (c == 'V') - expect_close = 1; - } - - return len; - } - - return 0; -} - -static int scx200_wdt_ioctl(struct inode *inode, struct file *file, - unsigned int cmd, unsigned long arg) -{ - static struct watchdog_info ident = { - .identity = "NatSemi SCx200 Watchdog", - .firmware_version = 1, - .options = (WDIOF_SETTIMEOUT | WDIOF_KEEPALIVEPING), - }; - int new_margin; - - switch (cmd) { - default: - return -ENOTTY; - case WDIOC_GETSUPPORT: - if(copy_to_user((struct watchdog_info *)arg, &ident, - sizeof(ident))) - return -EFAULT; - return 0; - case WDIOC_GETSTATUS: - case WDIOC_GETBOOTSTATUS: - if (put_user(0, (int *)arg)) - return -EFAULT; - return 0; - case WDIOC_KEEPALIVE: - scx200_wdt_ping(); - return 0; - case WDIOC_SETTIMEOUT: - if (get_user(new_margin, (int *)arg)) - return -EFAULT; - if (new_margin < 1) - return -EINVAL; - margin = new_margin; - scx200_wdt_update_margin(); - scx200_wdt_ping(); - case WDIOC_GETTIMEOUT: - if (put_user(margin, (int *)arg)) - return -EFAULT; - return 0; - } -} - -static struct file_operations scx200_wdt_fops = { - .owner = THIS_MODULE, - .write = scx200_wdt_write, - .ioctl = scx200_wdt_ioctl, - .open = scx200_wdt_open, - .release = scx200_wdt_release, -}; - -static struct miscdevice scx200_wdt_miscdev = { - .minor = WATCHDOG_MINOR, - .name = NAME, - .fops = &scx200_wdt_fops, -}; - -static int __init scx200_wdt_init(void) -{ - int r; - - printk(KERN_DEBUG NAME ": NatSemi SCx200 Watchdog Driver\n"); - - /* First check that this really is a NatSemi SCx200 CPU */ - if ((pci_find_device(PCI_VENDOR_ID_NS, - PCI_DEVICE_ID_NS_SCx200_BRIDGE, - NULL)) == NULL) - return -ENODEV; - - /* More sanity checks, verify that the configuration block is there */ - if (!scx200_cb_probe(SCx200_CB_BASE)) { - printk(KERN_WARNING NAME ": no configuration block found\n"); - return -ENODEV; - } - - if (!request_region(SCx200_CB_BASE + SCx200_WDT_OFFSET, - SCx200_WDT_SIZE, - "NatSemi SCx200 Watchdog")) { - printk(KERN_WARNING NAME ": watchdog I/O region busy\n"); - return -EBUSY; - } - - scx200_wdt_update_margin(); - scx200_wdt_disable(); - - sema_init(&open_semaphore, 1); - - r = misc_register(&scx200_wdt_miscdev); - if (r) - return r; - - r = register_reboot_notifier(&scx200_wdt_notifier); - if (r) { - printk(KERN_ERR NAME ": unable to register reboot notifier"); - misc_deregister(&scx200_wdt_miscdev); - return r; - } - - return 0; -} - -static void __exit scx200_wdt_cleanup(void) -{ - unregister_reboot_notifier(&scx200_wdt_notifier); - misc_deregister(&scx200_wdt_miscdev); - release_region(SCx200_CB_BASE + SCx200_WDT_OFFSET, - SCx200_WDT_SIZE); -} - -module_init(scx200_wdt_init); -module_exit(scx200_wdt_cleanup); - -/* - Local variables: - compile-command: "make -k -C ../.. SUBDIRS=drivers/char modules" - c-basic-offset: 8 - End: -*/ diff -urpN --exclude-from=/home/davej/.exclude bk-linus/drivers/char/shwdt.c move-watchdogs/drivers/char/shwdt.c --- bk-linus/drivers/char/shwdt.c 2002-11-22 11:00:43.000000000 -0100 +++ move-watchdogs/drivers/char/shwdt.c 1969-12-31 23:00:00.000000000 -0100 @@ -1,417 +0,0 @@ -/* - * drivers/char/shwdt.c - * - * Watchdog driver for integrated watchdog in the SuperH 3/4 processors. - * - * Copyright (C) 2001 Paul Mundt - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation; either version 2 of the License, or (at your - * option) any later version. - * - * 14-Dec-2001 Matt Domsch - * Added nowayout module option to override CONFIG_WATCHDOG_NOWAYOUT - */ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include - -#if defined(CONFIG_CPU_SH4) - #define WTCNT 0xffc00008 - #define WTCSR 0xffc0000c -#elif defined(CONFIG_CPU_SH3) - #define WTCNT 0xffffff84 - #define WTCSR 0xffffff86 -#else - #error "Can't use SH 3/4 watchdog on non-SH 3/4 processor." -#endif - -#define WTCNT_HIGH 0x5a00 -#define WTCSR_HIGH 0xa500 - -#define WTCSR_TME 0x80 -#define WTCSR_WT 0x40 -#define WTCSR_RSTS 0x20 -#define WTCSR_WOVF 0x10 -#define WTCSR_IOVF 0x08 -#define WTCSR_CKS2 0x04 -#define WTCSR_CKS1 0x02 -#define WTCSR_CKS0 0x01 - -/* - * CKS0-2 supports a number of clock division ratios. At the time the watchdog - * is enabled, it defaults to a 41 usec overflow period .. we overload this to - * something a little more reasonable, and really can't deal with anything - * lower than WTCSR_CKS_1024, else we drop back into the usec range. - * - * Clock Division Ratio Overflow Period - * -------------------------------------------- - * 1/32 (initial value) 41 usecs - * 1/64 82 usecs - * 1/128 164 usecs - * 1/256 328 usecs - * 1/512 656 usecs - * 1/1024 1.31 msecs - * 1/2048 2.62 msecs - * 1/4096 5.25 msecs - */ -#define WTCSR_CKS_32 0x00 -#define WTCSR_CKS_64 0x01 -#define WTCSR_CKS_128 0x02 -#define WTCSR_CKS_256 0x03 -#define WTCSR_CKS_512 0x04 -#define WTCSR_CKS_1024 0x05 -#define WTCSR_CKS_2048 0x06 -#define WTCSR_CKS_4096 0x07 - -/* - * Default clock division ratio is 5.25 msecs. Overload this at module load - * time. Any value not in the msec range will default to a timeout of one - * jiffy, which exceeds the usec overflow periods. - */ -static int clock_division_ratio = WTCSR_CKS_4096; - -#define msecs_to_jiffies(msecs) (jiffies + ((HZ * msecs + 999) / 1000)) -#define next_ping_period(cks) msecs_to_jiffies(cks - 4) -#define user_ping_period(cks) (next_ping_period(cks) * 10) - -static unsigned long sh_is_open = 0; -static struct watchdog_info sh_wdt_info; -static struct timer_list timer; -static unsigned long next_heartbeat; - -#ifdef CONFIG_WATCHDOG_NOWAYOUT -static int nowayout = 1; -#else -static int nowayout = 0; -#endif - -MODULE_PARM(nowayout,"i"); -MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default=CONFIG_WATCHDOG_NOWAYOUT)"); - -/** - * sh_wdt_write_cnt - Write to Counter - * - * @val: Value to write - * - * Writes the given value @val to the lower byte of the timer counter. - * The upper byte is set manually on each write. - */ -static void sh_wdt_write_cnt(__u8 val) -{ - ctrl_outw(WTCNT_HIGH | (__u16)val, WTCNT); -} - -/** - * sh_wdt_write_csr - Write to Control/Status Register - * - * @val: Value to write - * - * Writes the given value @val to the lower byte of the control/status - * register. The upper byte is set manually on each write. - */ -static void sh_wdt_write_csr(__u8 val) -{ - ctrl_outw(WTCSR_HIGH | (__u16)val, WTCSR); -} - -/** - * sh_wdt_start - Start the Watchdog - * - * Starts the watchdog. - */ -static void sh_wdt_start(void) -{ - timer.expires = next_ping_period(clock_division_ratio); - next_heartbeat = user_ping_period(clock_division_ratio); - add_timer(&timer); - - sh_wdt_write_csr(WTCSR_WT | WTCSR_CKS_4096); - sh_wdt_write_cnt(0); - sh_wdt_write_csr((ctrl_inb(WTCSR) | WTCSR_TME)); -} - -/** - * sh_wdt_stop - Stop the Watchdog - * - * Stops the watchdog. - */ -static void sh_wdt_stop(void) -{ - del_timer(&timer); - - sh_wdt_write_csr((ctrl_inb(WTCSR) & ~WTCSR_TME)); -} - -/** - * sh_wdt_ping - Ping the Watchdog - * - * @data: Unused - * - * Clears overflow bit, resets timer counter. - */ -static void sh_wdt_ping(unsigned long data) -{ - if (time_before(jiffies, next_heartbeat)) { - sh_wdt_write_csr((ctrl_inb(WTCSR) & ~WTCSR_IOVF)); - sh_wdt_write_cnt(0); - - timer.expires = next_ping_period(clock_division_ratio); - add_timer(&timer); - } -} - -/** - * sh_wdt_open - Open the Device - * - * @inode: inode of device - * @file: file handle of device - * - * Watchdog device is opened and started. - */ -static int sh_wdt_open(struct inode *inode, struct file *file) -{ - switch (minor(inode->i_rdev)) { - case WATCHDOG_MINOR: - if (test_and_set_bit(0, &sh_is_open)) - return -EBUSY; - - if (nowayout) { - MOD_INC_USE_COUNT; - } - - sh_wdt_start(); - - break; - default: - return -ENODEV; - } - - return 0; -} - -/** - * sh_wdt_close - Close the Device - * - * @inode: inode of device - * @file: file handle of device - * - * Watchdog device is closed and stopped. - */ -static int sh_wdt_close(struct inode *inode, struct file *file) -{ - if (minor(inode->i_rdev) == WATCHDOG_MINOR) { - if (!nowayout) { - sh_wdt_stop(); - } - clear_bit(0, &sh_is_open); - } - - return 0; -} - -/** - * sh_wdt_read - Read from Device - * - * @file: file handle of device - * @buf: buffer to write to - * @count: length of buffer - * @ppos: offset - * - * Unsupported. - */ -static ssize_t sh_wdt_read(struct file *file, char *buf, - size_t count, loff_t *ppos) -{ - return -EINVAL; -} - -/** - * sh_wdt_write - Write to Device - * - * @file: file handle of device - * @buf: buffer to write - * @count: length of buffer - * @ppos: offset - * - * Pings the watchdog on write. - */ -static ssize_t sh_wdt_write(struct file *file, const char *buf, - size_t count, loff_t *ppos) -{ - /* Can't seek (pwrite) on this device */ - if (ppos != &file->f_pos) - return -ESPIPE; - - if (count) { - next_heartbeat = user_ping_period(clock_division_ratio); - return 1; - } - - return 0; -} - -/** - * sh_wdt_ioctl - Query Device - * - * @inode: inode of device - * @file: file handle of device - * @cmd: watchdog command - * @arg: argument - * - * Query basic information from the device or ping it, as outlined by the - * watchdog API. - */ -static int sh_wdt_ioctl(struct inode *inode, struct file *file, - unsigned int cmd, unsigned long arg) -{ - switch (cmd) { - case WDIOC_GETSUPPORT: - if (copy_to_user((struct watchdog_info *)arg, - &sh_wdt_info, - sizeof(sh_wdt_info))) { - return -EFAULT; - } - - break; - case WDIOC_GETSTATUS: - if (copy_to_user((int *)arg, - &sh_is_open, - sizeof(int))) { - return -EFAULT; - } - - break; - case WDIOC_KEEPALIVE: - next_heartbeat = user_ping_period(clock_division_ratio); - - break; - default: - return -ENOTTY; - } - - return 0; -} - -/** - * sh_wdt_notify_sys - Notifier Handler - * - * @this: notifier block - * @code: notifier event - * @unused: unused - * - * Handles specific events, such as turning off the watchdog during a - * shutdown event. - */ -static int sh_wdt_notify_sys(struct notifier_block *this, - unsigned long code, void *unused) -{ - if (code == SYS_DOWN || code == SYS_HALT) { - sh_wdt_stop(); - } - - return NOTIFY_DONE; -} - -static struct file_operations sh_wdt_fops = { - .owner = THIS_MODULE, - .read = sh_wdt_read, - .write = sh_wdt_write, - .ioctl = sh_wdt_ioctl, - .open = sh_wdt_open, - .release = sh_wdt_close, -}; - -static struct watchdog_info sh_wdt_info = { - WDIOF_KEEPALIVEPING, - 1, - "SH WDT", -}; - -static struct notifier_block sh_wdt_notifier = { - sh_wdt_notify_sys, - NULL, - 0 -}; - -static struct miscdevice sh_wdt_miscdev = { - WATCHDOG_MINOR, - "watchdog", - &sh_wdt_fops, -}; - -/** - * sh_wdt_init - Initialize module - * - * Registers the device and notifier handler. Actual device - * initialization is handled by sh_wdt_open(). - */ -static int __init sh_wdt_init(void) -{ - if (misc_register(&sh_wdt_miscdev)) { - printk(KERN_ERR "shwdt: Can't register misc device\n"); - return -EINVAL; - } - - if (!request_region(WTCNT, 1, "shwdt")) { - printk(KERN_ERR "shwdt: Can't request WTCNT region\n"); - misc_deregister(&sh_wdt_miscdev); - return -ENXIO; - } - - if (!request_region(WTCSR, 1, "shwdt")) { - printk(KERN_ERR "shwdt: Can't request WTCSR region\n"); - release_region(WTCNT, 1); - misc_deregister(&sh_wdt_miscdev); - return -ENXIO; - } - - if (register_reboot_notifier(&sh_wdt_notifier)) { - printk(KERN_ERR "shwdt: Can't register reboot notifier\n"); - release_region(WTCSR, 1); - release_region(WTCNT, 1); - misc_deregister(&sh_wdt_miscdev); - return -EINVAL; - } - - init_timer(&timer); - timer.function = sh_wdt_ping; - timer.data = 0; - - return 0; -} - -/** - * sh_wdt_exit - Deinitialize module - * - * Unregisters the device and notifier handler. Actual device - * deinitialization is handled by sh_wdt_close(). - */ -static void __exit sh_wdt_exit(void) -{ - unregister_reboot_notifier(&sh_wdt_notifier); - release_region(WTCSR, 1); - release_region(WTCNT, 1); - misc_deregister(&sh_wdt_miscdev); -} - -MODULE_AUTHOR("Paul Mundt "); -MODULE_DESCRIPTION("SH 3/4 watchdog driver"); -MODULE_LICENSE("GPL"); -MODULE_PARM(clock_division_ratio, "i"); -MODULE_PARM_DESC(clock_division_ratio, "Clock division ratio. Valid ranges are from 0x5 (1.31ms) to 0x7 (5.25ms). Defaults to 0x7."); - -module_init(sh_wdt_init); -module_exit(sh_wdt_exit); - diff -urpN --exclude-from=/home/davej/.exclude bk-linus/drivers/char/softdog.c move-watchdogs/drivers/char/softdog.c --- bk-linus/drivers/char/softdog.c 2002-11-22 11:00:43.000000000 -0100 +++ move-watchdogs/drivers/char/softdog.c 1969-12-31 23:00:00.000000000 -0100 @@ -1,196 +0,0 @@ -/* - * SoftDog 0.06: A Software Watchdog Device - * - * (c) Copyright 1996 Alan Cox , All Rights Reserved. - * http://www.redhat.com - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version - * 2 of the License, or (at your option) any later version. - * - * Neither Alan Cox nor CymruNet Ltd. admit liability nor provide - * warranty for any of this software. This material is provided - * "AS-IS" and at no charge. - * - * (c) Copyright 1995 Alan Cox - * - * Software only watchdog driver. Unlike its big brother the WDT501P - * driver this won't always recover a failed machine. - * - * 03/96: Angelo Haritsis : - * Modularised. - * Added soft_margin; use upon insmod to change the timer delay. - * NB: uses same minor as wdt (WATCHDOG_MINOR); we could use separate - * minors. - * - * 19980911 Alan Cox - * Made SMP safe for 2.3.x - * - * 20011214 Matt Domsch - * Added nowayout module option to override CONFIG_WATCHDOG_NOWAYOUT - * Didn't add timeout option, as soft_margin option already exists. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#define TIMER_MARGIN 60 /* (secs) Default is 1 minute */ - -static int soft_margin = TIMER_MARGIN; /* in seconds */ - -MODULE_PARM(soft_margin,"i"); - -#ifdef CONFIG_WATCHDOG_NOWAYOUT -static int nowayout = 1; -#else -static int nowayout = 0; -#endif - -MODULE_PARM(nowayout,"i"); -MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default=CONFIG_WATCHDOG_NOWAYOUT)"); -MODULE_LICENSE("GPL"); - -/* - * Our timer - */ - -static void watchdog_fire(unsigned long); - -static struct timer_list watchdog_ticktock = - TIMER_INITIALIZER(watchdog_fire, 0, 0); -static int timer_alive; - - -/* - * If the timer expires.. - */ - -static void watchdog_fire(unsigned long data) -{ -#ifdef ONLY_TESTING - printk(KERN_CRIT "SOFTDOG: Would Reboot.\n"); -#else - printk(KERN_CRIT "SOFTDOG: Initiating system reboot.\n"); - machine_restart(NULL); - printk("WATCHDOG: Reboot didn't ?????\n"); -#endif -} - -/* - * Allow only one person to hold it open - */ - -static int softdog_open(struct inode *inode, struct file *file) -{ - if(timer_alive) - return -EBUSY; - if (nowayout) { - MOD_INC_USE_COUNT; - } - /* - * Activate timer - */ - mod_timer(&watchdog_ticktock, jiffies+(soft_margin*HZ)); - timer_alive=1; - return 0; -} - -static int softdog_release(struct inode *inode, struct file *file) -{ - /* - * Shut off the timer. - * Lock it in if it's a module and we set nowayout - */ - if(!nowayout) { - del_timer(&watchdog_ticktock); - } - timer_alive=0; - return 0; -} - -static ssize_t softdog_write(struct file *file, const char *data, size_t len, loff_t *ppos) -{ - /* Can't seek (pwrite) on this device */ - if (ppos != &file->f_pos) - return -ESPIPE; - - /* - * Refresh the timer. - */ - if(len) { - mod_timer(&watchdog_ticktock, jiffies+(soft_margin*HZ)); - return 1; - } - return 0; -} - -static int softdog_ioctl(struct inode *inode, struct file *file, - unsigned int cmd, unsigned long arg) -{ - static struct watchdog_info ident = { - identity: "Software Watchdog", - }; - switch (cmd) { - default: - return -ENOTTY; - case WDIOC_GETSUPPORT: - if(copy_to_user((struct watchdog_info *)arg, &ident, sizeof(ident))) - return -EFAULT; - return 0; - case WDIOC_GETSTATUS: - case WDIOC_GETBOOTSTATUS: - return put_user(0,(int *)arg); - case WDIOC_KEEPALIVE: - mod_timer(&watchdog_ticktock, jiffies+(soft_margin*HZ)); - return 0; - } -} - -static struct file_operations softdog_fops = { - owner: THIS_MODULE, - write: softdog_write, - ioctl: softdog_ioctl, - open: softdog_open, - release: softdog_release, -}; - -static struct miscdevice softdog_miscdev = { - minor: WATCHDOG_MINOR, - name: "watchdog", - fops: &softdog_fops, -}; - -static char banner[] __initdata = KERN_INFO "Software Watchdog Timer: 0.06, soft_margin: %d sec, nowayout: %d\n"; - -static int __init watchdog_init(void) -{ - int ret; - - ret = misc_register(&softdog_miscdev); - - if (ret) - return ret; - - printk(banner, soft_margin, nowayout); - - return 0; -} - -static void __exit watchdog_exit(void) -{ - misc_deregister(&softdog_miscdev); -} - -module_init(watchdog_init); -module_exit(watchdog_exit); diff -urpN --exclude-from=/home/davej/.exclude bk-linus/drivers/char/w83877f_wdt.c move-watchdogs/drivers/char/w83877f_wdt.c --- bk-linus/drivers/char/w83877f_wdt.c 2002-11-22 11:00:44.000000000 -0100 +++ move-watchdogs/drivers/char/w83877f_wdt.c 1969-12-31 23:00:00.000000000 -0100 @@ -1,366 +0,0 @@ -/* - * W83877F Computer Watchdog Timer driver for Linux 2.4.x - * - * Based on acquirewdt.c by Alan Cox, - * and sbc60xxwdt.c by Jakob Oestergaard - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version - * 2 of the License, or (at your option) any later version. - * - * The authors do NOT admit liability nor provide warranty for - * any of this software. This material is provided "AS-IS" in - * the hope that it may be useful for others. - * - * (c) Copyright 2001 Scott Jennings - * - * 4/19 - 2001 [Initial revision] - * 9/27 - 2001 Added spinlocking - * - * - * Theory of operation: - * A Watchdog Timer (WDT) is a hardware circuit that can - * reset the computer system in case of a software fault. - * You probably knew that already. - * - * Usually a userspace daemon will notify the kernel WDT driver - * via the /proc/watchdog special device file that userspace is - * still alive, at regular intervals. When such a notification - * occurs, the driver will usually tell the hardware watchdog - * that everything is in order, and that the watchdog should wait - * for yet another little while to reset the system. - * If userspace fails (RAM error, kernel bug, whatever), the - * notifications cease to occur, and the hardware watchdog will - * reset the system (causing a reboot) after the timeout occurs. - * - * This WDT driver is different from most other Linux WDT - * drivers in that the driver will ping the watchdog by itself, - * because this particular WDT has a very short timeout (1.6 - * seconds) and it would be insane to count on any userspace - * daemon always getting scheduled within that time frame. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#define OUR_NAME "w83877f_wdt" - -#define ENABLE_W83877F_PORT 0x3F0 -#define ENABLE_W83877F 0x87 -#define DISABLE_W83877F 0xAA -#define WDT_PING 0x443 -#define WDT_REGISTER 0x14 -#define WDT_ENABLE 0x9C -#define WDT_DISABLE 0x8C - -/* - * The W83877F seems to be fixed at 1.6s timeout (at least on the - * EMACS PC-104 board I'm using). If we reset the watchdog every - * ~250ms we should be safe. */ - -#define WDT_INTERVAL (HZ/4+1) - -/* - * We must not require too good response from the userspace daemon. - * Here we require the userspace daemon to send us a heartbeat - * char to /dev/watchdog every 30 seconds. - */ - -#define WDT_HEARTBEAT (HZ * 30) - -static void wdt_timer_ping(unsigned long); -static struct timer_list timer; -static unsigned long next_heartbeat; -static unsigned long wdt_is_open; -static int wdt_expect_close; -static spinlock_t wdt_spinlock; - -/* - * Whack the dog - */ - -static void wdt_timer_ping(unsigned long data) -{ - /* If we got a heartbeat pulse within the WDT_US_INTERVAL - * we agree to ping the WDT - */ - if(time_before(jiffies, next_heartbeat)) - { - /* Ping the WDT */ - spin_lock(&wdt_spinlock); - - /* Ping the WDT by reading from WDT_PING */ - inb_p(WDT_PING); - - /* Re-set the timer interval */ - timer.expires = jiffies + WDT_INTERVAL; - add_timer(&timer); - - spin_unlock(&wdt_spinlock); - - } else { - printk(OUR_NAME ": Heartbeat lost! Will not ping the watchdog\n"); - } -} - -/* - * Utility routines - */ - -static void wdt_change(int writeval) -{ - unsigned long flags; - spin_lock_irqsave(&wdt_spinlock, flags); - - /* buy some time */ - inb_p(WDT_PING); - - /* make W83877F available */ - outb_p(ENABLE_W83877F, ENABLE_W83877F_PORT); - outb_p(ENABLE_W83877F, ENABLE_W83877F_PORT); - - /* enable watchdog */ - outb_p(WDT_REGISTER, ENABLE_W83877F_PORT); - outb_p(writeval, ENABLE_W83877F_PORT+1); - - /* lock the W8387FF away */ - outb_p(DISABLE_W83877F, ENABLE_W83877F_PORT); - - spin_unlock_irqrestore(&wdt_spinlock, flags); -} - -static void wdt_startup(void) -{ - next_heartbeat = jiffies + WDT_HEARTBEAT; - - /* Start the timer */ - timer.expires = jiffies + WDT_INTERVAL; - add_timer(&timer); - - wdt_change(WDT_ENABLE); - - printk(OUR_NAME ": Watchdog timer is now enabled.\n"); -} - -static void wdt_turnoff(void) -{ - /* Stop the timer */ - del_timer(&timer); - - wdt_change(WDT_DISABLE); - - printk(OUR_NAME ": Watchdog timer is now disabled...\n"); -} - - -/* - * /dev/watchdog handling - */ - -static ssize_t fop_write(struct file * file, const char * buf, size_t count, loff_t * ppos) -{ - /* We can't seek */ - if(ppos != &file->f_pos) - return -ESPIPE; - - /* See if we got the magic character */ - if(count) - { - size_t ofs; - - /* note: just in case someone wrote the magic character - * five months ago... */ - wdt_expect_close = 0; - - /* now scan */ - for(ofs = 0; ofs != count; ofs++) - { - char c; - if (get_user(c, buf + ofs)) - return -EFAULT; - if (c == 'V') - wdt_expect_close = 1; - } - - /* someone wrote to us, we should restart timer */ - next_heartbeat = jiffies + WDT_HEARTBEAT; - return 1; - }; - return 0; -} - -static ssize_t fop_read(struct file * file, char * buf, size_t count, loff_t * ppos) -{ - /* No can do */ - return -EINVAL; -} - -static int fop_open(struct inode * inode, struct file * file) -{ - switch(minor(inode->i_rdev)) - { - case WATCHDOG_MINOR: - /* Just in case we're already talking to someone... */ - if(test_and_set_bit(0, &wdt_is_open)) { - return -EBUSY; - } - /* Good, fire up the show */ - wdt_startup(); - return 0; - - default: - return -ENODEV; - } -} - -static int fop_close(struct inode * inode, struct file * file) -{ - if(minor(inode->i_rdev) == WATCHDOG_MINOR) - { - if(wdt_expect_close) - wdt_turnoff(); - else { - del_timer(&timer); - printk(OUR_NAME ": device file closed unexpectedly. Will not stop the WDT!\n"); - } - } - wdt_is_open = 0; - return 0; -} - -static int fop_ioctl(struct inode *inode, struct file *file, unsigned int cmd, - unsigned long arg) -{ - static struct watchdog_info ident= - { - 0, - 1, - "W83877F" - }; - - switch(cmd) - { - default: - return -ENOIOCTLCMD; - case WDIOC_GETSUPPORT: - return copy_to_user((struct watchdog_info *)arg, &ident, sizeof(ident))?-EFAULT:0; - case WDIOC_KEEPALIVE: - next_heartbeat = jiffies + WDT_HEARTBEAT; - return 0; - } -} - -static struct file_operations wdt_fops = { - .owner = THIS_MODULE, - .llseek = no_llseek, - .read = fop_read, - .write = fop_write, - .open = fop_open, - .release = fop_close, - .ioctl = fop_ioctl -}; - -static struct miscdevice wdt_miscdev = { - WATCHDOG_MINOR, - "watchdog", - &wdt_fops -}; - -/* - * Notifier for system down - */ - -static int wdt_notify_sys(struct notifier_block *this, unsigned long code, - void *unused) -{ - if(code==SYS_DOWN || code==SYS_HALT) - wdt_turnoff(); - return NOTIFY_DONE; -} - -/* - * The WDT needs to learn about soft shutdowns in order to - * turn the timebomb registers off. - */ - -static struct notifier_block wdt_notifier= -{ - wdt_notify_sys, - 0, - 0 -}; - -static void __exit w83877f_wdt_unload(void) -{ - wdt_turnoff(); - - /* Deregister */ - misc_deregister(&wdt_miscdev); - - unregister_reboot_notifier(&wdt_notifier); - release_region(WDT_PING,1); - release_region(ENABLE_W83877F_PORT,2); -} - -static int __init w83877f_wdt_init(void) -{ - int rc = -EBUSY; - - spin_lock_init(&wdt_spinlock); - - if (!request_region(ENABLE_W83877F_PORT, 2, "W83877F WDT")) - goto err_out; - if (!request_region(WDT_PING, 1, "W8387FF WDT")) - goto err_out_region1; - - init_timer(&timer); - timer.function = wdt_timer_ping; - timer.data = 0; - - rc = misc_register(&wdt_miscdev); - if (rc) - goto err_out_region2; - - rc = register_reboot_notifier(&wdt_notifier); - if (rc) - goto err_out_miscdev; - - printk(KERN_INFO OUR_NAME ": WDT driver for W83877F initialised.\n"); - - return 0; - -err_out_miscdev: - misc_deregister(&wdt_miscdev); -err_out_region2: - release_region(WDT_PING,1); -err_out_region1: - release_region(ENABLE_W83877F_PORT,2); -err_out: - return rc; -} - -module_init(w83877f_wdt_init); -module_exit(w83877f_wdt_unload); - -MODULE_AUTHOR("Scott and Bill Jennings"); -MODULE_DESCRIPTION("Driver for watchdog timer in w83877f chip"); -MODULE_LICENSE("GPL"); -EXPORT_NO_SYMBOLS; diff -urpN --exclude-from=/home/davej/.exclude bk-linus/drivers/char/watchdog/Kconfig move-watchdogs/drivers/char/watchdog/Kconfig --- bk-linus/drivers/char/watchdog/Kconfig 1969-12-31 23:00:00.000000000 -0100 +++ move-watchdogs/drivers/char/watchdog/Kconfig 2002-11-22 10:15:41.000000000 -0100 @@ -0,0 +1,286 @@ +# +# Character device configuration +# + +menu "Watchdog Cards" + +config WATCHDOG + bool "Watchdog Timer Support" + ---help--- + If you say Y here (and to one of the following options) and create a + character special file /dev/watchdog with major number 10 and minor + number 130 using mknod ("man mknod"), you will get a watchdog, i.e.: + subsequently opening the file and then failing to write to it for + longer than 1 minute will result in rebooting the machine. This + could be useful for a networked machine that needs to come back + online as fast as possible after a lock-up. There's both a watchdog + implementation entirely in software (which can sometimes fail to + reboot the machine) and a driver for hardware watchdog boards, which + are more robust and can also keep track of the temperature inside + your computer. For details, read + in the kernel source. + + The watchdog is usually used together with the watchdog daemon + which is available from + . This daemon can + also monitor NFS connections and can reboot the machine when the process + table is full. + + If unsure, say N. + +config WATCHDOG_NOWAYOUT + bool "Disable watchdog shutdown on close" + depends on WATCHDOG + help + The default watchdog behaviour (which you get if you say N here) is + to stop the timer if the process managing it closes the file + /dev/watchdog. It's always remotely possible that this process might + get killed. If you say Y here, the watchdog cannot be stopped once + it has been started. + +config SOFT_WATCHDOG + tristate "Software watchdog" + depends on WATCHDOG + help + A software monitoring watchdog. This will fail to reboot your system + from some situations that the hardware watchdog will recover + from. Equally it's a lot cheaper to install. + + This driver is also available as a module ( = code which can be + inserted in and removed from the running kernel whenever you want). + If you want to compile it as a module, say M here and read + . The module will be called + softdog.o. + +config WDT + tristate "WDT Watchdog timer" + depends on WATCHDOG + ---help--- + If you have a WDT500P or WDT501P watchdog board, say Y here, + otherwise N. It is not possible to probe for this board, which means + that you have to inform the kernel about the IO port and IRQ using + the "wdt=" kernel option (try "man bootparam" or see the + documentation of your boot loader (lilo or loadlin) about how to + pass options to the kernel at boot time). + + If you want to compile this as a module ( = code which can be + inserted in and removed from the running kernel whenever you want), + say M here and read . The module + will be called wdt.o. + +config WDTPCI + tristate "WDT PCI Watchdog timer" + depends on WATCHDOG + ---help--- + If you have a PCI WDT500/501 watchdog board, say Y here, otherwise + N. It is not possible to probe for this board, which means that you + have to inform the kernel about the IO port and IRQ using the "wdt=" + kernel option (try "man bootparam" or see the documentation of your + boot loader (lilo or loadlin) about how to pass options to the + kernel at boot time). + + If you want to compile this as a module ( = code which can be + inserted in and removed from the running kernel whenever you want), + say M here and read . The module + will be called wdt_pci.o. + +config WDT_501 + bool "WDT501 features" + depends on WDT + help + Saying Y here and creating a character special file /dev/temperature + with major number 10 and minor number 131 ("man mknod") will give + you a thermometer inside your computer: reading from + /dev/temperature yields one byte, the temperature in degrees + Fahrenheit. This works only if you have a WDT501P watchdog board + installed. + +config WDT_501_FAN + bool "Fan Tachometer" + depends on WDT_501 + help + Enable the Fan Tachometer on the WDT501. Only do this if you have a + fan tachometer actually set up. + +config PCWATCHDOG + tristate "Berkshire Products PC Watchdog" + depends on WATCHDOG + ---help--- + This is the driver for the Berkshire Products PC Watchdog card. + This card simply watches your kernel to make sure it doesn't freeze, + and if it does, it reboots your computer after a certain amount of + time. This driver is like the WDT501 driver but for different + hardware. Please read . The PC + watchdog cards can be ordered from . + + This driver is also available as a module ( = code which can be + inserted in and removed from the running kernel whenever you want). + The module is called pcwd.o. If you want to compile it as a module, + say M here and read . + + Most people will say N. + +config ACQUIRE_WDT + tristate "Acquire SBC Watchdog Timer" + depends on WATCHDOG + ---help--- + This is the driver for the hardware watchdog on the PSC-6x86 Single + Board Computer produced by Acquire Inc (and others). This watchdog + simply watches your kernel to make sure it doesn't freeze, and if + it does, it reboots your computer after a certain amount of time. + + This driver is like the WDT501 driver but for different hardware. + This driver is also available as a module ( = code which can be + inserted in and removed from the running kernel whenever you want). + The module is called pscwdt.o. If you want to compile it as a + module, say M here and read . Most + people will say N. + +config ADVANTECH_WDT + tristate "Advantech SBC Watchdog Timer" + depends on WATCHDOG + help + If you are configuring a Linux kernel for the Advantech single-board + computer, say `Y' here to support its built-in watchdog timer + feature. See the help for CONFIG_WATCHDOG for discussion. + +config 21285_WATCHDOG + tristate "DC21285 watchdog" + depends on WATCHDOG && FOOTBRIDGE + help + The Intel Footbridge chip contains a builtin watchdog circuit. Say Y + here if you wish to use this. Alternatively say M to compile the + driver as a module, which will be called wdt285.o. + + This driver does not work on all machines. In particular, early CATS + boards have hardware problems that will cause the machine to simply + lock up if the watchdog fires. + + "If in doubt, leave it out" - say N. + +config 977_WATCHDOG + tristate "NetWinder WB83C977 watchdog" + depends on WATCHDOG && FOOTBRIDGE && ARCH_NETWINDER + help + Say Y here to include support for the WB977 watchdog included in + NetWinder machines. Alternatively say M to compile the driver as + a module, which will be called wdt977.o. + + Not sure? It's safe to say N. + +config EUROTECH_WDT + tristate "Eurotech CPU-1220/1410 Watchdog Timer" + depends on WATCHDOG + help + Enable support for the watchdog timer on the Eurotech CPU-1220 and + CPU-1410 cards. These are PC/104 SBCs. Spec sheets and product + information are at . + +config IB700_WDT + tristate "IB700 SBC Watchdog Timer" + depends on WATCHDOG + ---help--- + This is the driver for the hardware watchdog on the IB700 Single + Board Computer produced by TMC Technology (www.tmc-uk.com). This watchdog + simply watches your kernel to make sure it doesn't freeze, and if + it does, it reboots your computer after a certain amount of time. + + This driver is like the WDT501 driver but for slightly different hardware. + + This driver is also available as a module ( = code which can be + inserted in and removed from the running kernel whenever you want). + The module is called ib700wdt.o. If you want to compile it as a + module, say M here and read Documentation/modules.txt. Most people + will say N. + +config I810_TCO + tristate "Intel i810 TCO timer / Watchdog" + depends on WATCHDOG + ---help--- + Hardware driver for the TCO timer built into the Intel i810 and i815 + chipset family. The TCO (Total Cost of Ownership) timer is a + watchdog timer that will reboot the machine after its second + expiration. The expiration time can be configured by commandline + argument "i810_margin=" where is the counter initial value. + It is decremented every 0.6 secs, the default is 50 which gives a + timeout of 30 seconds and one minute until reset. + + On some motherboards the driver may fail to reset the chipset's + NO_REBOOT flag which prevents the watchdog from rebooting the + machine. If this is the case you will get a kernel message like + "i810tco init: failed to reset NO_REBOOT flag". + + If you want to compile this as a module, say M and read + . The module will be called + i810-tco.o. + +config MIXCOMWD + tristate "Mixcom Watchdog" + depends on WATCHDOG + ---help--- + This is a driver for the Mixcom hardware watchdog cards. This + watchdog simply watches your kernel to make sure it doesn't freeze, + and if it does, it reboots your computer after a certain amount of + time. + + This driver is also available as a module ( = code which can be + inserted in and removed from the running kernel whenever you want). + The module is called mixcomwd.o. If you want to compile it as a + module, say M here and read . Most + people will say N. + +config SCx200_WDT + tristate "NatSemi SCx200 Watchdog" + depends on WATCHDOG + help + Enable the built-in watchdog timer support on the National + Semiconductor SCx200 processors. + + If compiled as a module, it will be called scx200_watchdog.o. + +config 60XX_WDT + tristate "SBC-60XX Watchdog Timer" + depends on WATCHDOG + help + This driver can be used with the watchdog timer found on some + single board computers, namely the 6010 PII based computer. + It may well work with other cards. It reads port 0x443 to enable + and re-set the watchdog timer, and reads port 0x45 to disable + the watchdog. If you have a card that behave in similar ways, + you can probably make this driver work with your card as well. + + You can compile this driver directly into the kernel, or use + it as a module. The module will be called sbc60xxwdt.o. + +config W83877F_WDT + tristate "W83877F (EMACS) Watchdog Timer" + depends on WATCHDOG + ---help--- + This is the driver for the hardware watchdog on the W83877F chipset + as used in EMACS PC-104 motherboards (and likely others). This + watchdog simply watches your kernel to make sure it doesn't freeze, + and if it does, it reboots your computer after a certain amount of + time. + + This driver is also available as a module ( = code which can be + inserted in and removed from the running kernel whenever you want). + The module is called mixcomwd.o. If you want to compile it as a + module, say M here and read . Most + people will say N. + +config MACHZ_WDT + tristate "ZF MachZ Watchdog" + depends on WATCHDOG + ---help--- + If you are using a ZF Micro MachZ processor, say Y here, otherwise + N. This is the driver for the watchdog timer builtin on that + processor using ZF-Logic interface. This watchdog simply watches + your kernel to make sure it doesn't freeze, and if it does, it + reboots your computer after a certain amount of time. + + This driver is also available as a module ( = code which can be + inserted in and removed from the running kernel whenever you want). + The module is called machzwd.o. If you want to compile it as a + module, say M here and read . + +endmenu diff -urpN --exclude-from=/home/davej/.exclude bk-linus/drivers/char/watchdog/Makefile move-watchdogs/drivers/char/watchdog/Makefile --- bk-linus/drivers/char/watchdog/Makefile 1969-12-31 23:00:00.000000000 -0100 +++ move-watchdogs/drivers/char/watchdog/Makefile 2002-11-22 10:55:01.000000000 -0100 @@ -0,0 +1,27 @@ +# +# Makefile for the kernel character device drivers. +# + +# Only one watchdog can succeed. We probe the hardware watchdog +# drivers first, then the softdog driver. This means if your hardware +# watchdog dies or is 'borrowed' for some reason the software watchdog +# still gives you some cover. + +obj-$(CONFIG_PCWATCHDOG) += pcwd.o +obj-$(CONFIG_ACQUIRE_WDT) += acquirewdt.o +obj-$(CONFIG_ADVANTECH_WDT) += advantechwdt.o +obj-$(CONFIG_IB700_WDT) += ib700wdt.o +obj-$(CONFIG_MIXCOMWD) += mixcomwd.o +obj-$(CONFIG_SCx200_WDT) += scx200_wdt.o +obj-$(CONFIG_60XX_WDT) += sbc60xxwdt.o +obj-$(CONFIG_WDT) += wdt.o +obj-$(CONFIG_WDTPCI) += wdt_pci.o +obj-$(CONFIG_21285_WATCHDOG) += wdt285.o +obj-$(CONFIG_977_WATCHDOG) += wdt977.o +obj-$(CONFIG_I810_TCO) += i810-tco.o +obj-$(CONFIG_MACHZ_WDT) += machzwd.o +obj-$(CONFIG_SH_WDT) += shwdt.o +obj-$(CONFIG_EUROTECH_WDT) += eurotechwdt.o +obj-$(CONFIG_SOFT_WATCHDOG) += softdog.o + +include $(TOPDIR)/Rules.make diff -urpN --exclude-from=/home/davej/.exclude bk-linus/drivers/char/watchdog/acquirewdt.c move-watchdogs/drivers/char/watchdog/acquirewdt.c --- bk-linus/drivers/char/watchdog/acquirewdt.c 1969-12-31 23:00:00.000000000 -0100 +++ move-watchdogs/drivers/char/watchdog/acquirewdt.c 2002-11-22 10:15:41.000000000 -0100 @@ -0,0 +1,251 @@ +/* + * Acquire Single Board Computer Watchdog Timer driver for Linux 2.1.x + * + * Based on wdt.c. Original copyright messages: + * + * (c) Copyright 1996 Alan Cox , All Rights Reserved. + * http://www.redhat.com + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version + * 2 of the License, or (at your option) any later version. + * + * Neither Alan Cox nor CymruNet Ltd. admit liability nor provide + * warranty for any of this software. This material is provided + * "AS-IS" and at no charge. + * + * (c) Copyright 1995 Alan Cox + * + * 14-Dec-2001 Matt Domsch + * Added nowayout module option to override CONFIG_WATCHDOG_NOWAYOUT + * Can't add timeout - driver doesn't allow changing value + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +static int acq_is_open; +static spinlock_t acq_lock; + +/* + * You must set these - there is no sane way to probe for this board. + */ + +#define WDT_STOP 0x43 +#define WDT_START 0x443 + +#ifdef CONFIG_WATCHDOG_NOWAYOUT +static int nowayout = 1; +#else +static int nowayout = 0; +#endif + +MODULE_PARM(nowayout,"i"); +MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default=CONFIG_WATCHDOG_NOWAYOUT)"); + +/* + * Kernel methods. + */ + + +static void acq_ping(void) +{ + /* Write a watchdog value */ + inb_p(WDT_START); +} + +static ssize_t acq_write(struct file *file, const char *buf, size_t count, loff_t *ppos) +{ + /* Can't seek (pwrite) on this device */ + if (ppos != &file->f_pos) + return -ESPIPE; + + if(count) + { + acq_ping(); + return 1; + } + return 0; +} + +static ssize_t acq_read(struct file *file, char *buf, size_t count, loff_t *ppos) +{ + return -EINVAL; +} + + + +static int acq_ioctl(struct inode *inode, struct file *file, unsigned int cmd, + unsigned long arg) +{ + static struct watchdog_info ident= + { + WDIOF_KEEPALIVEPING, 1, "Acquire WDT" + }; + + switch(cmd) + { + case WDIOC_GETSUPPORT: + if (copy_to_user((struct watchdog_info *)arg, &ident, sizeof(ident))) + return -EFAULT; + break; + + case WDIOC_GETSTATUS: + if (copy_to_user((int *)arg, &acq_is_open, sizeof(int))) + return -EFAULT; + break; + + case WDIOC_KEEPALIVE: + acq_ping(); + break; + + default: + return -ENOTTY; + } + return 0; +} + +static int acq_open(struct inode *inode, struct file *file) +{ + switch(minor(inode->i_rdev)) + { + case WATCHDOG_MINOR: + spin_lock(&acq_lock); + if(acq_is_open) + { + spin_unlock(&acq_lock); + return -EBUSY; + } + if (nowayout) { + MOD_INC_USE_COUNT; + } + /* + * Activate + */ + + acq_is_open=1; + inb_p(WDT_START); + spin_unlock(&acq_lock); + return 0; + default: + return -ENODEV; + } +} + +static int acq_close(struct inode *inode, struct file *file) +{ + if(minor(inode->i_rdev)==WATCHDOG_MINOR) + { + spin_lock(&acq_lock); + if (!nowayout) { + inb_p(WDT_STOP); + } + acq_is_open=0; + spin_unlock(&acq_lock); + } + return 0; +} + +/* + * Notifier for system down + */ + +static int acq_notify_sys(struct notifier_block *this, unsigned long code, + void *unused) +{ + if(code==SYS_DOWN || code==SYS_HALT) + { + /* Turn the card off */ + inb_p(WDT_STOP); + } + return NOTIFY_DONE; +} + +/* + * Kernel Interfaces + */ + + +static struct file_operations acq_fops = { + .owner = THIS_MODULE, + .read = acq_read, + .write = acq_write, + .ioctl = acq_ioctl, + .open = acq_open, + .release = acq_close, +}; + +static struct miscdevice acq_miscdev= +{ + WATCHDOG_MINOR, + "watchdog", + &acq_fops +}; + + +/* + * The WDT card needs to learn about soft shutdowns in order to + * turn the timebomb registers off. + */ + +static struct notifier_block acq_notifier= +{ + acq_notify_sys, + NULL, + 0 +}; + +static int __init acq_init(void) +{ + printk("WDT driver for Acquire single board computer initialising.\n"); + + spin_lock_init(&acq_lock); + if (misc_register(&acq_miscdev)) + return -ENODEV; + if (!request_region(WDT_STOP, 1, "Acquire WDT")) + { + misc_deregister(&acq_miscdev); + return -EIO; + } + if (!request_region(WDT_START, 1, "Acquire WDT")) + { + release_region(WDT_STOP, 1); + misc_deregister(&acq_miscdev); + return -EIO; + } + + register_reboot_notifier(&acq_notifier); + return 0; +} + +static void __exit acq_exit(void) +{ + misc_deregister(&acq_miscdev); + unregister_reboot_notifier(&acq_notifier); + release_region(WDT_STOP,1); + release_region(WDT_START,1); +} + +module_init(acq_init); +module_exit(acq_exit); + +MODULE_LICENSE("GPL"); diff -urpN --exclude-from=/home/davej/.exclude bk-linus/drivers/char/watchdog/advantechwdt.c move-watchdogs/drivers/char/watchdog/advantechwdt.c --- bk-linus/drivers/char/watchdog/advantechwdt.c 1969-12-31 23:00:00.000000000 -0100 +++ move-watchdogs/drivers/char/watchdog/advantechwdt.c 2002-11-22 10:15:41.000000000 -0100 @@ -0,0 +1,280 @@ +/* + * Advantech Single Board Computer WDT driver for Linux 2.4.x + * + * (c) Copyright 2000-2001 Marek Michalkiewicz + * + * Based on acquirewdt.c which is based on wdt.c. + * Original copyright messages: + * + * (c) Copyright 1996 Alan Cox , All Rights Reserved. + * http://www.redhat.com + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version + * 2 of the License, or (at your option) any later version. + * + * Neither Alan Cox nor CymruNet Ltd. admit liability nor provide + * warranty for any of this software. This material is provided + * "AS-IS" and at no charge. + * + * (c) Copyright 1995 Alan Cox + * + * 14-Dec-2001 Matt Domsch + * Added nowayout module option to override CONFIG_WATCHDOG_NOWAYOUT + * Added timeout module option to override default + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +static int advwdt_is_open; +static spinlock_t advwdt_lock; + +/* + * You must set these - there is no sane way to probe for this board. + * + * To enable or restart, write the timeout value in seconds (1 to 63) + * to I/O port WDT_START. To disable, read I/O port WDT_STOP. + * Both are 0x443 for most boards (tested on a PCA-6276VE-00B1), but + * check your manual (at least the PCA-6159 seems to be different - + * the manual says WDT_STOP is 0x43, not 0x443). + * (0x43 is also a write-only control register for the 8254 timer!) + * + * TODO: module parameters to set the I/O port addresses + */ + +#define WDT_STOP 0x443 +#define WDT_START 0x443 + +#define WD_TIMO 60 /* 1 minute */ + +static int timeout = WD_TIMO; /* in seconds */ +MODULE_PARM(timeout,"i"); +MODULE_PARM_DESC(timeout, "Watchdog timeout in seconds (default=60)"); + +#ifdef CONFIG_WATCHDOG_NOWAYOUT +static int nowayout = 1; +#else +static int nowayout = 0; +#endif + +MODULE_PARM(nowayout,"i"); +MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default=CONFIG_WATCHDOG_NOWAYOUT)"); + +/* + * Kernel methods. + */ + +static void +advwdt_ping(void) +{ + /* Write a watchdog value */ + outb_p(timeout, WDT_START); +} + +static ssize_t +advwdt_write(struct file *file, const char *buf, size_t count, loff_t *ppos) +{ + /* Can't seek (pwrite) on this device */ + if (ppos != &file->f_pos) + return -ESPIPE; + + if (count) { + advwdt_ping(); + return 1; + } + return 0; +} + +static ssize_t +advwdt_read(struct file *file, char *buf, size_t count, loff_t *ppos) +{ + return -EINVAL; +} + +static int +advwdt_ioctl(struct inode *inode, struct file *file, unsigned int cmd, + unsigned long arg) +{ + static struct watchdog_info ident = { + WDIOF_KEEPALIVEPING, 1, "Advantech WDT" + }; + + switch (cmd) { + case WDIOC_GETSUPPORT: + if (copy_to_user((struct watchdog_info *)arg, &ident, sizeof(ident))) + return -EFAULT; + break; + + case WDIOC_GETSTATUS: + if (copy_to_user((int *)arg, &advwdt_is_open, sizeof(int))) + return -EFAULT; + break; + + case WDIOC_KEEPALIVE: + advwdt_ping(); + break; + + default: + return -ENOTTY; + } + return 0; +} + +static int +advwdt_open(struct inode *inode, struct file *file) +{ + switch (minor(inode->i_rdev)) { + case WATCHDOG_MINOR: + spin_lock(&advwdt_lock); + if (advwdt_is_open) { + spin_unlock(&advwdt_lock); + return -EBUSY; + } + if (nowayout) { + MOD_INC_USE_COUNT; + } + /* + * Activate + */ + + advwdt_is_open = 1; + advwdt_ping(); + spin_unlock(&advwdt_lock); + return 0; + default: + return -ENODEV; + } +} + +static int +advwdt_close(struct inode *inode, struct file *file) +{ + if (minor(inode->i_rdev) == WATCHDOG_MINOR) { + spin_lock(&advwdt_lock); + if (!nowayout) { + inb_p(WDT_STOP); + } + advwdt_is_open = 0; + spin_unlock(&advwdt_lock); + } + return 0; +} + +/* + * Notifier for system down + */ + +static int +advwdt_notify_sys(struct notifier_block *this, unsigned long code, + void *unused) +{ + if (code == SYS_DOWN || code == SYS_HALT) { + /* Turn the WDT off */ + inb_p(WDT_STOP); + } + return NOTIFY_DONE; +} + +/* + * Kernel Interfaces + */ + +static struct file_operations advwdt_fops = { + .owner = THIS_MODULE, + .read = advwdt_read, + .write = advwdt_write, + .ioctl = advwdt_ioctl, + .open = advwdt_open, + .release = advwdt_close, +}; + +static struct miscdevice advwdt_miscdev = { + WATCHDOG_MINOR, + "watchdog", + &advwdt_fops +}; + +/* + * The WDT needs to learn about soft shutdowns in order to + * turn the timebomb registers off. + */ + +static struct notifier_block advwdt_notifier = { + advwdt_notify_sys, + NULL, + 0 +}; + +static void __init +advwdt_validate_timeout(void) +{ + if (timeout < 1 || timeout > 63) { + timeout = WD_TIMO; + printk(KERN_INFO "advantechwdt: timeout value must be 1 <= x <= 63, using %d\n", timeout); + } +} + +static int __init +advwdt_init(void) +{ + printk("WDT driver for Advantech single board computer initialising.\n"); + + advwdt_validate_timeout(); + spin_lock_init(&advwdt_lock); + if (misc_register(&advwdt_miscdev)) + return -ENODEV; +#if WDT_START != WDT_STOP + if (!request_region(WDT_STOP, 1, "Advantech WDT")) { + misc_deregister(&advwdt_miscdev); + return -EIO; + } +#endif + if (!request_region(WDT_START, 1, "Advantech WDT")) { + misc_deregister(&advwdt_miscdev); +#if WDT_START != WDT_STOP + release_region(WDT_STOP, 1); +#endif + return -EIO; + } + register_reboot_notifier(&advwdt_notifier); + return 0; +} + +static void __exit +advwdt_exit(void) +{ + misc_deregister(&advwdt_miscdev); + unregister_reboot_notifier(&advwdt_notifier); +#if WDT_START != WDT_STOP + release_region(WDT_STOP,1); +#endif + release_region(WDT_START,1); +} + +module_init(advwdt_init); +module_exit(advwdt_exit); + +MODULE_LICENSE("GPL"); + +/* end of advantechwdt.c */ + diff -urpN --exclude-from=/home/davej/.exclude bk-linus/drivers/char/watchdog/eurotechwdt.c move-watchdogs/drivers/char/watchdog/eurotechwdt.c --- bk-linus/drivers/char/watchdog/eurotechwdt.c 1969-12-31 23:00:00.000000000 -0100 +++ move-watchdogs/drivers/char/watchdog/eurotechwdt.c 2002-11-22 10:15:41.000000000 -0100 @@ -0,0 +1,501 @@ +/* + * Eurotech CPU-1220/1410 on board WDT driver for Linux 2.4.x + * + * (c) Copyright 2001 Ascensit + * (c) Copyright 2001 Rodolfo Giometti + * + * Based on wdt.c. + * Original copyright messages: + * + * (c) Copyright 1996-1997 Alan Cox , All Rights Reserved. + * http://www.redhat.com + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version + * 2 of the License, or (at your option) any later version. + * + * Neither Alan Cox nor CymruNet Ltd. admit liability nor provide + * warranty for any of this software. This material is provided + * "AS-IS" and at no charge. + * + * (c) Copyright 1995 Alan Cox * + * + * 14-Dec-2001 Matt Domsch + * Added nowayout module option to override CONFIG_WATCHDOG_NOWAYOUT + * Added timeout module option to override default + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +static int eurwdt_is_open; +static spinlock_t eurwdt_lock; + +/* + * You must set these - there is no sane way to probe for this board. + * You can use wdt=x,y to set these now. + */ + +static int io = 0x3f0; +static int irq = 10; +static char *ev = "int"; + +#define WDT_TIMEOUT 60 /* 1 minute */ +static int timeout = WDT_TIMEOUT; + +MODULE_PARM(timeout,"i"); +MODULE_PARM_DESC(timeout, "Eurotech WDT timeout in seconds (default=60)"); + +#ifdef CONFIG_WATCHDOG_NOWAYOUT +static int nowayout = 1; +#else +static int nowayout = 0; +#endif +MODULE_PARM(nowayout,"i"); +MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default=CONFIG_WATCHDOG_NOWAYOUT)"); + + +/* + * Some symbolic names + */ + +#define WDT_CTRL_REG 0x30 +#define WDT_OUTPIN_CFG 0xe2 + #define WDT_EVENT_INT 0x00 + #define WDT_EVENT_REBOOT 0x08 +#define WDT_UNIT_SEL 0xf1 + #define WDT_UNIT_SECS 0x80 +#define WDT_TIMEOUT_VAL 0xf2 +#define WDT_TIMER_CFG 0xf3 + + +#ifndef MODULE + +/** + * eurwdt_setup: + * @str: command line string + * + * Setup options. The board isn't really probe-able so we have to + * get the user to tell us the configuration. Sane people build it + * modular but the others come here. + */ + +static int __init eurwdt_setup(char *str) +{ + int ints[4]; + + str = get_options (str, ARRAY_SIZE(ints), ints); + + if (ints[0] > 0) { + io = ints[1]; + if (ints[0] > 1) + irq = ints[2]; + } + + return 1; +} + +__setup("wdt=", eurwdt_setup); + +#endif /* !MODULE */ + +MODULE_PARM(io, "i"); +MODULE_PARM_DESC(io, "Eurotech WDT io port (default=0x3f0)"); +MODULE_PARM(irq, "i"); +MODULE_PARM_DESC(irq, "Eurotech WDT irq (default=10)"); +MODULE_PARM(ev, "s"); +MODULE_PARM_DESC(ev, "Eurotech WDT event type (default is `reboot')"); + + +/* + * Programming support + */ + +static void __init eurwdt_validate_timeout(void) +{ + if (timeout < 0 || timeout > 255) { + timeout = WDT_TIMEOUT; + printk(KERN_INFO "eurwdt: timeout must be 0 < x < 255, using %d\n", + timeout); + } +} + +static inline void eurwdt_write_reg(u8 index, u8 data) +{ + outb(index, io); + outb(data, io+1); +} + +static inline void eurwdt_lock_chip(void) +{ + outb(0xaa, io); +} + +static inline void eurwdt_unlock_chip(void) +{ + outb(0x55, io); + eurwdt_write_reg(0x07, 0x08); /* set the logical device */ +} + +static inline void eurwdt_set_timeout(int timeout) +{ + eurwdt_write_reg(WDT_TIMEOUT_VAL, (u8) timeout); +} + +static inline void eurwdt_disable_timer(void) +{ + eurwdt_set_timeout(0); +} + +static void eurwdt_activate_timer(void) +{ + eurwdt_disable_timer(); + eurwdt_write_reg(WDT_CTRL_REG, 0x01); /* activate the WDT */ + eurwdt_write_reg(WDT_OUTPIN_CFG, !strcmp("int", ev) ? + WDT_EVENT_INT : WDT_EVENT_REBOOT); + /* Setting interrupt line */ + if (irq == 2 || irq > 15 || irq < 0) { + printk(KERN_ERR ": invalid irq number\n"); + irq = 0; /* if invalid we disable interrupt */ + } + if (irq == 0) + printk(KERN_INFO ": interrupt disabled\n"); + eurwdt_write_reg(WDT_TIMER_CFG, irq<<4); + + eurwdt_write_reg(WDT_UNIT_SEL, WDT_UNIT_SECS); /* we use seconds */ + eurwdt_set_timeout(0); /* the default timeout */ +} + + +/* + * Kernel methods. + */ + +void eurwdt_interrupt(int irq, void *dev_id, struct pt_regs *regs) +{ + printk(KERN_CRIT "timeout WDT timeout\n"); + +#ifdef ONLY_TESTING + printk(KERN_CRIT "Would Reboot.\n"); +#else + printk(KERN_CRIT "Initiating system reboot.\n"); + machine_restart(NULL); +#endif +} + + +/** + * eurwdt_ping: + * + * Reload counter one with the watchdog timeout. + */ + +static void eurwdt_ping(void) +{ + /* Write the watchdog default value */ + eurwdt_set_timeout(timeout); +} + +/** + * eurwdt_write: + * @file: file handle to the watchdog + * @buf: buffer to write (unused as data does not matter here + * @count: count of bytes + * @ppos: pointer to the position to write. No seeks allowed + * + * A write to a watchdog device is defined as a keepalive signal. Any + * write of data will do, as we we don't define content meaning. + */ + +static ssize_t eurwdt_write(struct file *file, const char *buf, size_t count, +loff_t *ppos) +{ + /* Can't seek (pwrite) on this device */ + if (ppos != &file->f_pos) + return -ESPIPE; + + if (count) { + eurwdt_ping(); /* the default timeout */ + return 1; + } + + return 0; +} + +/** + * eurwdt_ioctl: + * @inode: inode of the device + * @file: file handle to the device + * @cmd: watchdog command + * @arg: argument pointer + * + * The watchdog API defines a common set of functions for all watchdogs + * according to their available features. + */ + +static int eurwdt_ioctl(struct inode *inode, struct file *file, + unsigned int cmd, unsigned long arg) +{ + static struct watchdog_info ident = { + .options = WDIOF_CARDRESET, + .firmware_version = 1, + .identity = "WDT Eurotech CPU-1220/1410", + }; + + int time; + + switch(cmd) { + default: + return -ENOTTY; + + case WDIOC_GETSUPPORT: + return copy_to_user((struct watchdog_info *)arg, &ident, + sizeof(ident)) ? -EFAULT : 0; + + case WDIOC_GETBOOTSTATUS: + return put_user(0, (int *) arg); + + case WDIOC_KEEPALIVE: + eurwdt_ping(); + return 0; + + case WDIOC_SETTIMEOUT: + if (copy_from_user(&time, (int *) arg, sizeof(int))) + return -EFAULT; + + /* Sanity check */ + if (time < 0 || time > 255) + return -EINVAL; + + timeout = time; + eurwdt_set_timeout(time); + return 0; + } +} + +/** + * eurwdt_open: + * @inode: inode of device + * @file: file handle to device + * + * The misc device has been opened. The watchdog device is single + * open and on opening we load the counter. + */ + +static int eurwdt_open(struct inode *inode, struct file *file) +{ + switch (minor(inode->i_rdev)) { + case WATCHDOG_MINOR: + spin_lock(&eurwdt_lock); + if (eurwdt_is_open) { + spin_unlock(&eurwdt_lock); + return -EBUSY; + } + if (nowayout) { + MOD_INC_USE_COUNT; + } + + eurwdt_is_open = 1; + + /* Activate the WDT */ + eurwdt_activate_timer(); + + spin_unlock(&eurwdt_lock); + + MOD_INC_USE_COUNT; + + return 0; + + case TEMP_MINOR: + return 0; + + default: + return -ENODEV; + } +} + +/** + * eurwdt_release: + * @inode: inode to board + * @file: file handle to board + * + * The watchdog has a configurable API. There is a religious dispute + * between people who want their watchdog to be able to shut down and + * those who want to be sure if the watchdog manager dies the machine + * reboots. In the former case we disable the counters, in the latter + * case you have to open it again very soon. + */ + +static int eurwdt_release(struct inode *inode, struct file *file) +{ + if (minor(inode->i_rdev) == WATCHDOG_MINOR) { + if (!nowayout) { + eurwdt_disable_timer(); + } + eurwdt_is_open = 0; + + MOD_DEC_USE_COUNT; + } + + return 0; +} + +/** + * eurwdt_notify_sys: + * @this: our notifier block + * @code: the event being reported + * @unused: unused + * + * Our notifier is called on system shutdowns. We want to turn the card + * off at reboot otherwise the machine will reboot again during memory + * test or worse yet during the following fsck. This would suck, in fact + * trust me - if it happens it does suck. + */ + +static int eurwdt_notify_sys(struct notifier_block *this, unsigned long code, + void *unused) +{ + if (code == SYS_DOWN || code == SYS_HALT) { + /* Turn the card off */ + eurwdt_disable_timer(); + } + + return NOTIFY_DONE; +} + +/* + * Kernel Interfaces + */ + + +static struct file_operations eurwdt_fops = { + .owner = THIS_MODULE, + .llseek = no_llseek, + .write = eurwdt_write, + .ioctl = eurwdt_ioctl, + .open = eurwdt_open, + .release = eurwdt_release, +}; + +static struct miscdevice eurwdt_miscdev = { + .minor = WATCHDOG_MINOR, + .name = "watchdog", + .fops = &eurwdt_fops +}; + +/* + * The WDT card needs to learn about soft shutdowns in order to + * turn the timebomb registers off. + */ + +static struct notifier_block eurwdt_notifier = { + .notifier_call = eurwdt_notify_sys, +}; + +/** + * cleanup_module: + * + * Unload the watchdog. You cannot do this with any file handles open. + * If your watchdog is set to continue ticking on close and you unload + * it, well it keeps ticking. We won't get the interrupt but the board + * will not touch PC memory so all is fine. You just have to load a new + * module in 60 seconds or reboot. + */ + +static void __exit eurwdt_exit(void) +{ + eurwdt_lock_chip(); + + misc_deregister(&eurwdt_miscdev); + + unregister_reboot_notifier(&eurwdt_notifier); + release_region(io, 2); + free_irq(irq, NULL); +} + +/** + * eurwdt_init: + * + * Set up the WDT watchdog board. After grabbing the resources + * we require we need also to unlock the device. + * The open() function will actually kick the board off. + */ + +static int __init eurwdt_init(void) +{ + int ret; + + eurwdt_validate_timeout(); + ret = misc_register(&eurwdt_miscdev); + if (ret) { + printk(KERN_ERR "eurwdt: can't misc_register on minor=%d\n", + WATCHDOG_MINOR); + goto out; + } + + ret = request_irq(irq, eurwdt_interrupt, SA_INTERRUPT, "eurwdt", NULL); + if(ret) { + printk(KERN_ERR "eurwdt: IRQ %d is not free.\n", irq); + goto outmisc; + } + + if (!request_region(io, 2, "eurwdt")) { + printk(KERN_ERR "eurwdt: IO %X is not free.\n", io); + ret = -EBUSY; + goto outirq; + } + + ret = register_reboot_notifier(&eurwdt_notifier); + if (ret) { + printk(KERN_ERR "eurwdt: can't register reboot notifier (err=%d)\n", ret); + goto outreg; + } + + eurwdt_unlock_chip(); + + ret = 0; + printk(KERN_INFO "Eurotech WDT driver 0.01 at %X (Interrupt %d)" + " - timeout event: %s\n", + io, irq, (!strcmp("int", ev) ? "int" : "reboot")); + + spin_lock_init(&eurwdt_lock); + + out: + return ret; + + outreg: + release_region(io, 2); + + outirq: + free_irq(irq, NULL); + + outmisc: + misc_deregister(&eurwdt_miscdev); + goto out; +} + +module_init(eurwdt_init); +module_exit(eurwdt_exit); + +MODULE_AUTHOR("Rodolfo Giometti"); +MODULE_DESCRIPTION("Driver for Eurotech CPU-1220/1410 on board watchdog"); +MODULE_LICENSE("GPL"); diff -urpN --exclude-from=/home/davej/.exclude bk-linus/drivers/char/watchdog/i810-tco.c move-watchdogs/drivers/char/watchdog/i810-tco.c --- bk-linus/drivers/char/watchdog/i810-tco.c 1969-12-31 23:00:00.000000000 -0100 +++ move-watchdogs/drivers/char/watchdog/i810-tco.c 2002-11-22 10:15:41.000000000 -0100 @@ -0,0 +1,431 @@ +/* + * i810-tco 0.05: TCO timer driver for i8xx chipsets + * + * (c) Copyright 2000 kernel concepts , All Rights Reserved. + * http://www.kernelconcepts.de + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version + * 2 of the License, or (at your option) any later version. + * + * Neither kernel concepts nor Nils Faerber admit liability nor provide + * warranty for any of this software. This material is provided + * "AS-IS" and at no charge. + * + * (c) Copyright 2000 kernel concepts + * developed for + * Jentro AG, Haar/Munich (Germany) + * + * TCO timer driver for i8xx chipsets + * based on softdog.c by Alan Cox + * + * The TCO timer is implemented in the following I/O controller hubs: + * (See the intel documentation on http://developer.intel.com.) + * 82801AA & 82801AB chip : document number 290655-003, 290677-004, + * 82801BA & 82801BAM chip : document number 290687-002, 298242-005, + * 82801CA & 82801CAM chip : document number 290716-001, 290718-001, + * 82801DB & 82801E chip : document number 290744-001, 273599-001 + * + * 20000710 Nils Faerber + * Initial Version 0.01 + * 20000728 Nils Faerber + * 0.02 Fix for SMI_EN->TCO_EN bit, some cleanups + * 20011214 Matt Domsch + * 0.03 Added nowayout module option to override CONFIG_WATCHDOG_NOWAYOUT + * Didn't add timeout option as i810_margin already exists. + * 20020224 Joel Becker, Wim Van Sebroeck + * 0.04 Support for 82801CA(M) chipset, timer margin needs to be > 3, + * add support for WDIOC_SETTIMEOUT and WDIOC_GETTIMEOUT. + * 20020412 Rob Radez , Wim Van Sebroeck + * 0.05 Fix possible timer_alive race, add expect close support, + * clean up ioctls (WDIOC_GETSTATUS, WDIOC_GETBOOTSTATUS and + * WDIOC_SETOPTIONS), made i810tco_getdevice __init, + * removed boot_status, removed tco_timer_read, + * added support for 82801DB and 82801E chipset, general cleanup. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "i810-tco.h" + + +/* Module and version information */ +#define TCO_VERSION "0.05" +#define TCO_MODULE_NAME "i810 TCO timer" +#define TCO_DRIVER_NAME TCO_MODULE_NAME ", v" TCO_VERSION + +/* Default expire timeout */ +#define TIMER_MARGIN 50 /* steps of 0.6sec, 3 0x3f || tmrval < 0x04) + return -1; + + spin_lock(&tco_lock); + val = inb (TCO1_TMR); + val &= 0xc0; + val |= tmrval; + outb (val, TCO1_TMR); + val = inb (TCO1_TMR); + spin_unlock(&tco_lock); + + if ((val & 0x3f) != tmrval) + return -1; + + return 0; +} + +/* + * Reload (trigger) the timer. Lock is needed so we dont reload it during + * a reprogramming event + */ + +static void tco_timer_reload (void) +{ + spin_lock(&tco_lock); + outb (0x01, TCO1_RLD); + spin_unlock(&tco_lock); +} + +/* + * Allow only one person to hold it open + */ + +static int i810tco_open (struct inode *inode, struct file *file) +{ + if (test_and_set_bit(0, &timer_alive)) + return -EBUSY; + + /* + * Reload and activate timer + */ + tco_timer_reload (); + tco_timer_start (); + return 0; +} + +static int i810tco_release (struct inode *inode, struct file *file) +{ + /* + * Shut off the timer. + */ + if (tco_expect_close == 42 && !nowayout) { + tco_timer_stop (); + } else { + tco_timer_reload (); + printk(KERN_CRIT TCO_MODULE_NAME ": Unexpected close, not stopping watchdog!\n"); + } + clear_bit(0, &timer_alive); + tco_expect_close = 0; + return 0; +} + +static ssize_t i810tco_write (struct file *file, const char *data, + size_t len, loff_t * ppos) +{ + /* Can't seek (pwrite) on this device */ + if (ppos != &file->f_pos) + return -ESPIPE; + + /* See if we got the magic character 'V' and reload the timer */ + if (len) { + size_t i; + + tco_expect_close = 0; + + /* scan to see wether or not we got the magic character */ + for (i = 0; i != len; i++) { + u8 c; + if(get_user(c, data+i)) + return -EFAULT; + if (c == 'V') + tco_expect_close = 42; + } + + /* someone wrote to us, we should reload the timer */ + tco_timer_reload (); + return 1; + } + return 0; +} + +static int i810tco_ioctl (struct inode *inode, struct file *file, + unsigned int cmd, unsigned long arg) +{ + int new_margin, u_margin; + int options, retval = -EINVAL; + + static struct watchdog_info ident = { + .options = WDIOF_SETTIMEOUT | WDIOF_KEEPALIVEPING, + .firmware_version = 0, + .identity = "i810 TCO timer", + }; + switch (cmd) { + default: + return -ENOTTY; + case WDIOC_GETSUPPORT: + if (copy_to_user + ((struct watchdog_info *) arg, &ident, sizeof (ident))) + return -EFAULT; + return 0; + case WDIOC_GETSTATUS: + case WDIOC_GETBOOTSTATUS: + return put_user (0, (int *) arg); + case WDIOC_SETOPTIONS: + if (get_user (options, (int *) arg)) + return -EFAULT; + if (options & WDIOS_DISABLECARD) { + tco_timer_stop (); + retval = 0; + } + if (options & WDIOS_ENABLECARD) { + tco_timer_reload (); + tco_timer_start (); + retval = 0; + } + return retval; + case WDIOC_KEEPALIVE: + tco_timer_reload (); + return 0; + case WDIOC_SETTIMEOUT: + if (get_user (u_margin, (int *) arg)) + return -EFAULT; + new_margin = (u_margin * 10 + 5) / 6; + if ((new_margin < 4) || (new_margin > 63)) + return -EINVAL; + if (tco_timer_settimer ((unsigned char) new_margin)) + return -EINVAL; + i810_margin = new_margin; + tco_timer_reload (); + /* Fall */ + case WDIOC_GETTIMEOUT: + return put_user ((int)(i810_margin * 6 / 10), (int *) arg); + } +} + +/* + * Data for PCI driver interface + * + * This data only exists for exporting the supported + * PCI ids via MODULE_DEVICE_TABLE. We do not actually + * register a pci_driver, because someone else might one day + * want to register another driver on the same PCI id. + */ +static struct pci_device_id i810tco_pci_tbl[] __initdata = { + { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801AA_0, PCI_ANY_ID, PCI_ANY_ID, }, + { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801AB_0, PCI_ANY_ID, PCI_ANY_ID, }, + { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801BA_0, PCI_ANY_ID, PCI_ANY_ID, }, + { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801BA_10, PCI_ANY_ID, PCI_ANY_ID, }, + { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801CA_0, PCI_ANY_ID, PCI_ANY_ID, }, + { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801CA_12, PCI_ANY_ID, PCI_ANY_ID, }, + { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801DB_0, PCI_ANY_ID, PCI_ANY_ID, }, + { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801E_0, PCI_ANY_ID, PCI_ANY_ID, }, + { 0, }, +}; +MODULE_DEVICE_TABLE (pci, i810tco_pci_tbl); + +static struct pci_dev *i810tco_pci; + +static unsigned char __init i810tco_getdevice (void) +{ + struct pci_dev *dev; + u8 val1, val2; + u16 badr; + /* + * Find the PCI device + */ + + pci_for_each_dev(dev) { + if (pci_match_device(i810tco_pci_tbl, dev)) { + i810tco_pci = dev; + break; + } + } + + if (i810tco_pci) { + /* + * Find the ACPI base I/O address which is the base + * for the TCO registers (TCOBASE=ACPIBASE + 0x60) + * ACPIBASE is bits [15:7] from 0x40-0x43 + */ + pci_read_config_byte (i810tco_pci, 0x40, &val1); + pci_read_config_byte (i810tco_pci, 0x41, &val2); + badr = ((val2 << 1) | (val1 >> 7)) << 7; + ACPIBASE = badr; + /* Something's wrong here, ACPIBASE has to be set */ + if (badr == 0x0001 || badr == 0x0000) { + printk (KERN_ERR TCO_MODULE_NAME " init: failed to get TCOBASE address\n"); + return 0; + } + /* + * Check chipset's NO_REBOOT bit + */ + pci_read_config_byte (i810tco_pci, 0xd4, &val1); + if (val1 & 0x02) { + val1 &= 0xfd; + pci_write_config_byte (i810tco_pci, 0xd4, val1); + pci_read_config_byte (i810tco_pci, 0xd4, &val1); + if (val1 & 0x02) { + printk (KERN_ERR TCO_MODULE_NAME " init: failed to reset NO_REBOOT flag, reboot disabled by hardware\n"); + return 0; /* Cannot reset NO_REBOOT bit */ + } + } + /* Set the TCO_EN bit in SMI_EN register */ + val1 = inb (SMI_EN + 1); + val1 &= 0xdf; + outb (val1, SMI_EN + 1); + /* Clear out the (probably old) status */ + outb (0, TCO1_STS); + outb (3, TCO2_STS); + return 1; + } + return 0; +} + +static struct file_operations i810tco_fops = { + .owner = THIS_MODULE, + .write = i810tco_write, + .ioctl = i810tco_ioctl, + .open = i810tco_open, + .release = i810tco_release, +}; + +static struct miscdevice i810tco_miscdev = { + .minor = WATCHDOG_MINOR, + .name = "watchdog", + .fops = &i810tco_fops, +}; + +static int __init watchdog_init (void) +{ + spin_lock_init(&tco_lock); + if (!i810tco_getdevice () || i810tco_pci == NULL) + return -ENODEV; + if (!request_region (TCOBASE, 0x10, "i810 TCO")) { + printk (KERN_ERR TCO_MODULE_NAME + ": I/O address 0x%04x already in use\n", + TCOBASE); + return -EIO; + } + if (misc_register (&i810tco_miscdev) != 0) { + release_region (TCOBASE, 0x10); + printk (KERN_ERR TCO_MODULE_NAME ": cannot register miscdev\n"); + return -EIO; + } + tco_timer_settimer ((unsigned char) i810_margin); + tco_timer_reload (); + + printk (KERN_INFO TCO_DRIVER_NAME + ": timer margin: %d sec (0x%04x) (nowayout=%d)\n", + (int) (i810_margin * 6 / 10), TCOBASE, nowayout); + return 0; +} + +static void __exit watchdog_cleanup (void) +{ + u8 val; + + /* Reset the timer before we leave */ + tco_timer_reload (); + /* Set the NO_REBOOT bit to prevent later reboots, just for sure */ + pci_read_config_byte (i810tco_pci, 0xd4, &val); + val |= 0x02; + pci_write_config_byte (i810tco_pci, 0xd4, val); + release_region (TCOBASE, 0x10); + misc_deregister (&i810tco_miscdev); +} + +module_init(watchdog_init); +module_exit(watchdog_cleanup); + +MODULE_AUTHOR("Nils Faerber"); +MODULE_DESCRIPTION("TCO timer driver for i8xx chipsets"); +MODULE_LICENSE("GPL"); diff -urpN --exclude-from=/home/davej/.exclude bk-linus/drivers/char/watchdog/i810-tco.h move-watchdogs/drivers/char/watchdog/i810-tco.h --- bk-linus/drivers/char/watchdog/i810-tco.h 1969-12-31 23:00:00.000000000 -0100 +++ move-watchdogs/drivers/char/watchdog/i810-tco.h 2002-11-22 10:15:41.000000000 -0100 @@ -0,0 +1,42 @@ +/* + * i810-tco 0.05: TCO timer driver for i8xx chipsets + * + * (c) Copyright 2000 kernel concepts , All Rights Reserved. + * http://www.kernelconcepts.de + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version + * 2 of the License, or (at your option) any later version. + * + * Neither kernel concepts nor Nils Faerber admit liability nor provide + * warranty for any of this software. This material is provided + * "AS-IS" and at no charge. + * + * (c) Copyright 2000 kernel concepts + * developed for + * Jentro AG, Haar/Munich (Germany) + * + * TCO timer driver for i8xx chipsets + * based on softdog.c by Alan Cox + * + * For history and the complete list of supported I/O Controller Hub's + * see i810-tco.c + */ + + +/* + * Some address definitions for the i810 TCO + */ + +#define TCOBASE ACPIBASE + 0x60 /* TCO base address */ +#define TCO1_RLD TCOBASE + 0x00 /* TCO Timer Reload and Current Value */ +#define TCO1_TMR TCOBASE + 0x01 /* TCO Timer Initial Value */ +#define TCO1_DAT_IN TCOBASE + 0x02 /* TCO Data In Register */ +#define TCO1_DAT_OUT TCOBASE + 0x03 /* TCO Data Out Register */ +#define TCO1_STS TCOBASE + 0x04 /* TCO1 Status Register */ +#define TCO2_STS TCOBASE + 0x06 /* TCO2 Status Register */ +#define TCO1_CNT TCOBASE + 0x08 /* TCO1 Control Register */ +#define TCO2_CNT TCOBASE + 0x0a /* TCO2 Control Register */ + +#define SMI_EN ACPIBASE + 0x30 /* SMI Control and Enable Register */ diff -urpN --exclude-from=/home/davej/.exclude bk-linus/drivers/char/watchdog/ib700wdt.c move-watchdogs/drivers/char/watchdog/ib700wdt.c --- bk-linus/drivers/char/watchdog/ib700wdt.c 1969-12-31 23:00:00.000000000 -0100 +++ move-watchdogs/drivers/char/watchdog/ib700wdt.c 2002-11-22 10:15:41.000000000 -0100 @@ -0,0 +1,311 @@ +/* + * IB700 Single Board Computer WDT driver for Linux 2.4.x + * + * (c) Copyright 2001 Charles Howes + * + * Based on advantechwdt.c which is based on acquirewdt.c which + * is based on wdt.c. + * + * (c) Copyright 2000-2001 Marek Michalkiewicz + * + * Based on acquirewdt.c which is based on wdt.c. + * Original copyright messages: + * + * (c) Copyright 1996 Alan Cox , All Rights Reserved. + * http://www.redhat.com + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version + * 2 of the License, or (at your option) any later version. + * + * Neither Alan Cox nor CymruNet Ltd. admit liability nor provide + * warranty for any of this software. This material is provided + * "AS-IS" and at no charge. + * + * (c) Copyright 1995 Alan Cox + * + * 14-Dec-2001 Matt Domsch + * Added nowayout module option to override CONFIG_WATCHDOG_NOWAYOUT + * Added timeout module option to override default + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +static int ibwdt_is_open; +static spinlock_t ibwdt_lock; + +/* + * + * Watchdog Timer Configuration + * + * The function of the watchdog timer is to reset the system + * automatically and is defined at I/O port 0443H. To enable the + * watchdog timer and allow the system to reset, write I/O port 0443H. + * To disable the timer, write I/O port 0441H for the system to stop the + * watchdog function. The timer has a tolerance of 20% for its + * intervals. + * + * The following describes how the timer should be programmed. + * + * Enabling Watchdog: + * MOV AX,000FH (Choose the values from 0 to F) + * MOV DX,0443H + * OUT DX,AX + * + * Disabling Watchdog: + * MOV AX,000FH (Any value is fine.) + * MOV DX,0441H + * OUT DX,AX + * + * Watchdog timer control table: + * Level Value Time/sec | Level Value Time/sec + * 1 F 0 | 9 7 16 + * 2 E 2 | 10 6 18 + * 3 D 4 | 11 5 20 + * 4 C 6 | 12 4 22 + * 5 B 8 | 13 3 24 + * 6 A 10 | 14 2 26 + * 7 9 12 | 15 1 28 + * 8 8 14 | 16 0 30 + * + */ + +#define WDT_STOP 0x441 +#define WDT_START 0x443 + +#define WD_TIMO 0 /* 30 seconds +/- 20%, from table */ + +static int timeout_val = WD_TIMO; /* value in table */ +static int timeout = 30; /* in seconds */ +MODULE_PARM(timeout,"i"); +MODULE_PARM_DESC(timeout, "Watchdog timeout in seconds, 0 < n < 30, must be even (default=30)"); + +#ifdef CONFIG_WATCHDOG_NOWAYOUT +static int nowayout = 1; +#else +static int nowayout = 0; +#endif + +MODULE_PARM(nowayout,"i"); +MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default=CONFIG_WATCHDOG_NOWAYOUT)"); + +/* + * Kernel methods. + */ + +static void __init +ibwdt_validate_timeout(void) +{ + timeout_val = (30 - timeout) / 2; + if (timeout_val < 0 || timeout_val > 0xF) timeout_val = WD_TIMO; +} + +static void +ibwdt_ping(void) +{ + /* Write a watchdog value */ + outb_p(timeout_val, WDT_START); +} + +static ssize_t +ibwdt_write(struct file *file, const char *buf, size_t count, loff_t *ppos) +{ + /* Can't seek (pwrite) on this device */ + if (ppos != &file->f_pos) + return -ESPIPE; + + if (count) { + ibwdt_ping(); + return 1; + } + return 0; +} + +static ssize_t +ibwdt_read(struct file *file, char *buf, size_t count, loff_t *ppos) +{ + return -EINVAL; +} + +static int +ibwdt_ioctl(struct inode *inode, struct file *file, unsigned int cmd, + unsigned long arg) +{ + static struct watchdog_info ident = { + WDIOF_KEEPALIVEPING, 1, "IB700 WDT" + }; + + switch (cmd) { + case WDIOC_GETSUPPORT: + if (copy_to_user((struct watchdog_info *)arg, &ident, sizeof(ident))) + return -EFAULT; + break; + + case WDIOC_GETSTATUS: + if (copy_to_user((int *)arg, &ibwdt_is_open, sizeof(int))) + return -EFAULT; + break; + + case WDIOC_KEEPALIVE: + ibwdt_ping(); + break; + + default: + return -ENOTTY; + } + return 0; +} + +static int +ibwdt_open(struct inode *inode, struct file *file) +{ + switch (minor(inode->i_rdev)) { + case WATCHDOG_MINOR: + spin_lock(&ibwdt_lock); + if (ibwdt_is_open) { + spin_unlock(&ibwdt_lock); + return -EBUSY; + } + if (nowayout) { + MOD_INC_USE_COUNT; + } + /* + * Activate + */ + + ibwdt_is_open = 1; + ibwdt_ping(); + spin_unlock(&ibwdt_lock); + return 0; + default: + return -ENODEV; + } +} + +static int +ibwdt_close(struct inode *inode, struct file *file) +{ + lock_kernel(); + if (minor(inode->i_rdev) == WATCHDOG_MINOR) { + spin_lock(&ibwdt_lock); + if (!nowayout) { + outb_p(timeout_val, WDT_STOP); + } + ibwdt_is_open = 0; + spin_unlock(&ibwdt_lock); + } + unlock_kernel(); + return 0; +} + +/* + * Notifier for system down + */ + +static int +ibwdt_notify_sys(struct notifier_block *this, unsigned long code, + void *unused) +{ + if (code == SYS_DOWN || code == SYS_HALT) { + /* Turn the WDT off */ + outb_p(timeout_val, WDT_STOP); + } + return NOTIFY_DONE; +} + +/* + * Kernel Interfaces + */ + +static struct file_operations ibwdt_fops = { + .owner = THIS_MODULE, + .read = ibwdt_read, + .write = ibwdt_write, + .ioctl = ibwdt_ioctl, + .open = ibwdt_open, + .release = ibwdt_close, +}; + +static struct miscdevice ibwdt_miscdev = { + WATCHDOG_MINOR, + "watchdog", + &ibwdt_fops +}; + +/* + * The WDT needs to learn about soft shutdowns in order to + * turn the timebomb registers off. + */ + +static struct notifier_block ibwdt_notifier = { + ibwdt_notify_sys, + NULL, + 0 +}; + +static int __init +ibwdt_init(void) +{ + printk("WDT driver for IB700 single board computer initialising.\n"); + + ibwdt_validate_timeout(); + spin_lock_init(&ibwdt_lock); + if (misc_register(&ibwdt_miscdev)) + return -ENODEV; +#if WDT_START != WDT_STOP + if (!request_region(WDT_STOP, 1, "IB700 WDT")) { + misc_deregister(&ibwdt_miscdev); + return -EIO; + } +#endif + if (!request_region(WDT_START, 1, "IB700 WDT")) { +#if WDT_START != WDT_STOP + release_region(WDT_STOP, 1); +#endif + misc_deregister(&ibwdt_miscdev); + return -EIO; + } + register_reboot_notifier(&ibwdt_notifier); + return 0; +} + +static void __exit +ibwdt_exit(void) +{ + misc_deregister(&ibwdt_miscdev); + unregister_reboot_notifier(&ibwdt_notifier); +#if WDT_START != WDT_STOP + release_region(WDT_STOP,1); +#endif + release_region(WDT_START,1); +} + +module_init(ibwdt_init); +module_exit(ibwdt_exit); + +MODULE_AUTHOR("Charles Howes "); +MODULE_DESCRIPTION("IB700 SBC watchdog driver"); +MODULE_LICENSE("GPL"); + +/* end of ib700wdt.c */ diff -urpN --exclude-from=/home/davej/.exclude bk-linus/drivers/char/watchdog/machzwd.c move-watchdogs/drivers/char/watchdog/machzwd.c --- bk-linus/drivers/char/watchdog/machzwd.c 1969-12-31 23:00:00.000000000 -0100 +++ move-watchdogs/drivers/char/watchdog/machzwd.c 2002-11-22 10:15:41.000000000 -0100 @@ -0,0 +1,557 @@ +/* + * MachZ ZF-Logic Watchdog Timer driver for Linux + * + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version + * 2 of the License, or (at your option) any later version. + * + * The author does NOT admit liability nor provide warranty for + * any of this software. This material is provided "AS-IS" in + * the hope that it may be useful for others. + * + * Author: Fernando Fuganti + * + * Based on sbc60xxwdt.c by Jakob Oestergaard + * + * + * We have two timers (wd#1, wd#2) driven by a 32 KHz clock with the + * following periods: + * wd#1 - 2 seconds; + * wd#2 - 7.2 ms; + * After the expiration of wd#1, it can generate a NMI, SCI, SMI, or + * a system RESET and it starts wd#2 that unconditionaly will RESET + * the system when the counter reaches zero. + * + * 14-Dec-2001 Matt Domsch + * Added nowayout module option to override CONFIG_WATCHDOG_NOWAYOUT + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + + +/* ports */ +#define ZF_IOBASE 0x218 +#define INDEX 0x218 +#define DATA_B 0x219 +#define DATA_W 0x21A +#define DATA_D 0x21A + +/* indexes */ /* size */ +#define ZFL_VERSION 0x02 /* 16 */ +#define CONTROL 0x10 /* 16 */ +#define STATUS 0x12 /* 8 */ +#define COUNTER_1 0x0C /* 16 */ +#define COUNTER_2 0x0E /* 8 */ +#define PULSE_LEN 0x0F /* 8 */ + +/* controls */ +#define ENABLE_WD1 0x0001 +#define ENABLE_WD2 0x0002 +#define RESET_WD1 0x0010 +#define RESET_WD2 0x0020 +#define GEN_SCI 0x0100 +#define GEN_NMI 0x0200 +#define GEN_SMI 0x0400 +#define GEN_RESET 0x0800 + + +/* utilities */ + +#define WD1 0 +#define WD2 1 + +#define zf_writew(port, data) { outb(port, INDEX); outw(data, DATA_W); } +#define zf_writeb(port, data) { outb(port, INDEX); outb(data, DATA_B); } +#define zf_get_ZFL_version() zf_readw(ZFL_VERSION) + + +static unsigned short zf_readw(unsigned char port) +{ + outb(port, INDEX); + return inw(DATA_W); +} + +static unsigned short zf_readb(unsigned char port) +{ + outb(port, INDEX); + return inb(DATA_B); +} + + +MODULE_AUTHOR("Fernando Fuganti "); +MODULE_DESCRIPTION("MachZ ZF-Logic Watchdog driver"); +MODULE_LICENSE("GPL"); +MODULE_PARM(action, "i"); +MODULE_PARM_DESC(action, "after watchdog resets, generate: 0 = RESET(*) 1 = SMI 2 = NMI 3 = SCI"); + +#ifdef CONFIG_WATCHDOG_NOWAYOUT +static int nowayout = 1; +#else +static int nowayout = 0; +#endif + +MODULE_PARM(nowayout,"i"); +MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default=CONFIG_WATCHDOG_NOWAYOUT)"); + +#define PFX "machzwd" + +static struct watchdog_info zf_info = { + .options = WDIOF_KEEPALIVEPING, + .firmware_version = 1, + .identity = "ZF-Logic watchdog" +}; + + +/* + * action refers to action taken when watchdog resets + * 0 = GEN_RESET + * 1 = GEN_SMI + * 2 = GEN_NMI + * 3 = GEN_SCI + * defaults to GEN_RESET (0) + */ +static int action = 0; +static int zf_action = GEN_RESET; +static int zf_is_open = 0; +static int zf_expect_close = 0; +static spinlock_t zf_lock; +static spinlock_t zf_port_lock; +static struct timer_list zf_timer; +static unsigned long next_heartbeat = 0; + + +/* timeout for user land heart beat (10 seconds) */ +#define ZF_USER_TIMEO (HZ*10) + +/* timeout for hardware watchdog (~500ms) */ +#define ZF_HW_TIMEO (HZ/2) + +/* number of ticks on WD#1 (driven by a 32KHz clock, 2s) */ +#define ZF_CTIMEOUT 0xffff + +#ifndef ZF_DEBUG +# define dprintk(format, args...) +#else +# define dprintk(format, args...) printk(KERN_DEBUG PFX; ":" __FUNCTION__ ":%d: " format, __LINE__ , ## args) +#endif + + +/* STATUS register functions */ + +static inline unsigned char zf_get_status(void) +{ + return zf_readb(STATUS); +} + +static inline void zf_set_status(unsigned char new) +{ + zf_writeb(STATUS, new); +} + + +/* CONTROL register functions */ + +static inline unsigned short zf_get_control(void) +{ + return zf_readw(CONTROL); +} + +static inline void zf_set_control(unsigned short new) +{ + zf_writew(CONTROL, new); +} + + +/* WD#? counter functions */ +/* + * Just get current counter value + */ + +static inline unsigned short zf_get_timer(unsigned char n) +{ + switch(n){ + case WD1: + return zf_readw(COUNTER_1); + case WD2: + return zf_readb(COUNTER_2); + default: + return 0; + } +} + +/* + * Just set counter value + */ + +static inline void zf_set_timer(unsigned short new, unsigned char n) +{ + switch(n){ + case WD1: + zf_writew(COUNTER_1, new); + case WD2: + zf_writeb(COUNTER_2, new > 0xff ? 0xff : new); + default: + return; + } +} + +/* + * stop hardware timer + */ +static void zf_timer_off(void) +{ + unsigned int ctrl_reg = 0; + unsigned long flags; + + /* stop internal ping */ + del_timer_sync(&zf_timer); + + spin_lock_irqsave(&zf_port_lock, flags); + /* stop watchdog timer */ + ctrl_reg = zf_get_control(); + ctrl_reg |= (ENABLE_WD1|ENABLE_WD2); /* disable wd1 and wd2 */ + ctrl_reg &= ~(ENABLE_WD1|ENABLE_WD2); + zf_set_control(ctrl_reg); + spin_unlock_irqrestore(&zf_port_lock, flags); + + printk(KERN_INFO PFX ": Watchdog timer is now disabled\n"); +} + + +/* + * start hardware timer + */ +static void zf_timer_on(void) +{ + unsigned int ctrl_reg = 0; + unsigned long flags; + + spin_lock_irqsave(&zf_port_lock, flags); + + zf_writeb(PULSE_LEN, 0xff); + + zf_set_timer(ZF_CTIMEOUT, WD1); + + /* user land ping */ + next_heartbeat = jiffies + ZF_USER_TIMEO; + + /* start the timer for internal ping */ + zf_timer.expires = jiffies + ZF_HW_TIMEO; + + add_timer(&zf_timer); + + /* start watchdog timer */ + ctrl_reg = zf_get_control(); + ctrl_reg |= (ENABLE_WD1|zf_action); + zf_set_control(ctrl_reg); + spin_unlock_irqrestore(&zf_port_lock, flags); + + printk(KERN_INFO PFX ": Watchdog timer is now enabled\n"); +} + + +static void zf_ping(unsigned long data) +{ + unsigned int ctrl_reg = 0; + unsigned long flags; + + zf_writeb(COUNTER_2, 0xff); + + if(time_before(jiffies, next_heartbeat)){ + + dprintk("time_before: %ld\n", next_heartbeat - jiffies); + + /* + * reset event is activated by transition from 0 to 1 on + * RESET_WD1 bit and we assume that it is already zero... + */ + + spin_lock_irqsave(&zf_port_lock, flags); + ctrl_reg = zf_get_control(); + ctrl_reg |= RESET_WD1; + zf_set_control(ctrl_reg); + + /* ...and nothing changes until here */ + ctrl_reg &= ~(RESET_WD1); + zf_set_control(ctrl_reg); + spin_unlock_irqrestore(&zf_port_lock, flags); + + zf_timer.expires = jiffies + ZF_HW_TIMEO; + add_timer(&zf_timer); + }else{ + printk(KERN_CRIT PFX ": I will reset your machine\n"); + } +} + +static ssize_t zf_write(struct file *file, const char *buf, size_t count, + loff_t *ppos) +{ + /* Can't seek (pwrite) on this device */ + if (ppos != &file->f_pos) + return -ESPIPE; + + /* See if we got the magic character */ + if(count){ + +/* + * no need to check for close confirmation + * no way to disable watchdog ;) + */ + if (!nowayout) { + size_t ofs; + + /* + * note: just in case someone wrote the magic character + * five months ago... + */ + zf_expect_close = 0; + + /* now scan */ + for(ofs = 0; ofs != count; ofs++){ + char c; + if (get_user(c, buf + ofs)) + return -EFAULT; + if (c == 'V'){ + zf_expect_close = 1; + dprintk("zf_expect_close 1\n"); + } + } + } + /* + * Well, anyhow someone wrote to us, + * we should return that favour + */ + next_heartbeat = jiffies + ZF_USER_TIMEO; + dprintk("user ping at %ld\n", jiffies); + + return 1; + } + + return 0; +} + +static ssize_t zf_read(struct file *file, char *buf, size_t count, + loff_t *ppos) +{ + return -EINVAL; +} + + + +static int zf_ioctl(struct inode *inode, struct file *file, unsigned int cmd, + unsigned long arg) +{ + switch(cmd){ + case WDIOC_GETSUPPORT: + if (copy_to_user((struct watchdog_info *)arg, + &zf_info, sizeof(zf_info))) + return -EFAULT; + break; + + case WDIOC_GETSTATUS: + if (copy_to_user((int *)arg, &zf_is_open, sizeof(int))) + return -EFAULT; + break; + + case WDIOC_KEEPALIVE: + zf_ping(0); + break; + + default: + return -ENOTTY; + } + + return 0; +} + +static int zf_open(struct inode *inode, struct file *file) +{ + switch(minor(inode->i_rdev)){ + case WATCHDOG_MINOR: + spin_lock(&zf_lock); + if(zf_is_open){ + spin_unlock(&zf_lock); + return -EBUSY; + } + + if (nowayout) { + MOD_INC_USE_COUNT; + } + zf_is_open = 1; + + spin_unlock(&zf_lock); + + zf_timer_on(); + + return 0; + default: + return -ENODEV; + } +} + +static int zf_close(struct inode *inode, struct file *file) +{ + if(minor(inode->i_rdev) == WATCHDOG_MINOR){ + + if(zf_expect_close){ + zf_timer_off(); + } else { + del_timer(&zf_timer); + printk(KERN_ERR PFX ": device file closed unexpectedly. Will not stop the WDT!\n"); + } + + spin_lock(&zf_lock); + zf_is_open = 0; + spin_unlock(&zf_lock); + + zf_expect_close = 0; + } + + return 0; +} + +/* + * Notifier for system down + */ + +static int zf_notify_sys(struct notifier_block *this, unsigned long code, + void *unused) +{ + if(code == SYS_DOWN || code == SYS_HALT){ + zf_timer_off(); + } + + return NOTIFY_DONE; +} + + + + +static struct file_operations zf_fops = { + .owner = THIS_MODULE, + .read = zf_read, + .write = zf_write, + .ioctl = zf_ioctl, + .open = zf_open, + .release = zf_close, +}; + +static struct miscdevice zf_miscdev = { + WATCHDOG_MINOR, + "watchdog", + &zf_fops +}; + + +/* + * The device needs to learn about soft shutdowns in order to + * turn the timebomb registers off. + */ +static struct notifier_block zf_notifier = { + zf_notify_sys, + NULL, + 0 +}; + +static void __init zf_show_action(int act) +{ + char *str[] = { "RESET", "SMI", "NMI", "SCI" }; + + printk(KERN_INFO PFX ": Watchdog using action = %s\n", str[act]); +} + +static int __init zf_init(void) +{ + int ret; + + printk(KERN_INFO PFX ": MachZ ZF-Logic Watchdog driver initializing.\n"); + + ret = zf_get_ZFL_version(); + printk("%#x\n", ret); + if((!ret) || (ret != 0xffff)){ + printk(KERN_WARNING PFX ": no ZF-Logic found\n"); + return -ENODEV; + } + + if((action <= 3) && (action >= 0)){ + zf_action = zf_action>>action; + } else + action = 0; + + zf_show_action(action); + + spin_lock_init(&zf_lock); + spin_lock_init(&zf_port_lock); + + ret = misc_register(&zf_miscdev); + if (ret){ + printk(KERN_ERR "can't misc_register on minor=%d\n", + WATCHDOG_MINOR); + goto out; + } + + if(!request_region(ZF_IOBASE, 3, "MachZ ZFL WDT")){ + printk(KERN_ERR "cannot reserve I/O ports at %d\n", + ZF_IOBASE); + ret = -EBUSY; + goto no_region; + } + + ret = register_reboot_notifier(&zf_notifier); + if(ret){ + printk(KERN_ERR "can't register reboot notifier (err=%d)\n", + ret); + goto no_reboot; + } + + zf_set_status(0); + zf_set_control(0); + + /* this is the timer that will do the hard work */ + init_timer(&zf_timer); + zf_timer.function = zf_ping; + zf_timer.data = 0; + + return 0; + +no_reboot: + release_region(ZF_IOBASE, 3); +no_region: + misc_deregister(&zf_miscdev); +out: + return ret; +} + + +void __exit zf_exit(void) +{ + zf_timer_off(); + + misc_deregister(&zf_miscdev); + unregister_reboot_notifier(&zf_notifier); + release_region(ZF_IOBASE, 3); +} + +module_init(zf_init); +module_exit(zf_exit); diff -urpN --exclude-from=/home/davej/.exclude bk-linus/drivers/char/watchdog/mixcomwd.c move-watchdogs/drivers/char/watchdog/mixcomwd.c --- bk-linus/drivers/char/watchdog/mixcomwd.c 1969-12-31 23:00:00.000000000 -0100 +++ move-watchdogs/drivers/char/watchdog/mixcomwd.c 2002-11-22 10:15:41.000000000 -0100 @@ -0,0 +1,282 @@ +/* + * MixCom Watchdog: A Simple Hardware Watchdog Device + * Based on Softdog driver by Alan Cox and PC Watchdog driver by Ken Hollis + * + * Author: Gergely Madarasz + * + * Copyright (c) 1999 ITConsult-Pro Co. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version + * 2 of the License, or (at your option) any later version. + * + * Version 0.1 (99/04/15): + * - first version + * + * Version 0.2 (99/06/16): + * - added kernel timer watchdog ping after close + * since the hardware does not support watchdog shutdown + * + * Version 0.3 (99/06/21): + * - added WDIOC_GETSTATUS and WDIOC_GETSUPPORT ioctl calls + * + * Version 0.3.1 (99/06/22): + * - allow module removal while internal timer is active, + * print warning about probable reset + * + * Version 0.4 (99/11/15): + * - support for one more type board + * + * Version 0.5 (2001/12/14) Matt Domsch + * - added nowayout module option to override CONFIG_WATCHDOG_NOWAYOUT + * + */ + +#define VERSION "0.5" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +static int mixcomwd_ioports[] = { 0x180, 0x280, 0x380, 0x000 }; + +#define MIXCOM_WATCHDOG_OFFSET 0xc10 +#define MIXCOM_ID 0x11 +#define FLASHCOM_WATCHDOG_OFFSET 0x4 +#define FLASHCOM_ID 0x18 + +static long mixcomwd_opened; /* long req'd for setbit --RR */ + +static int watchdog_port; +static int mixcomwd_timer_alive; +static struct timer_list mixcomwd_timer = TIMER_INITIALIZER(NULL, 0, 0); + +#ifdef CONFIG_WATCHDOG_NOWAYOUT +static int nowayout = 1; +#else +static int nowayout = 0; +#endif + +MODULE_PARM(nowayout,"i"); +MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default=CONFIG_WATCHDOG_NOWAYOUT)"); + +static void mixcomwd_ping(void) +{ + outb_p(55,watchdog_port); + return; +} + +static void mixcomwd_timerfun(unsigned long d) +{ + mixcomwd_ping(); + + mod_timer(&mixcomwd_timer,jiffies+ 5*HZ); +} + +/* + * Allow only one person to hold it open + */ + +static int mixcomwd_open(struct inode *inode, struct file *file) +{ + if(test_and_set_bit(0,&mixcomwd_opened)) { + return -EBUSY; + } + mixcomwd_ping(); + + if (nowayout) { + MOD_INC_USE_COUNT; + } else { + if(mixcomwd_timer_alive) { + del_timer(&mixcomwd_timer); + mixcomwd_timer_alive=0; + } + } + return 0; +} + +static int mixcomwd_release(struct inode *inode, struct file *file) +{ + + if (!nowayout) { + if(mixcomwd_timer_alive) { + printk(KERN_ERR "mixcomwd: release called while internal timer alive"); + return -EBUSY; + } + init_timer(&mixcomwd_timer); + mixcomwd_timer.expires=jiffies + 5 * HZ; + mixcomwd_timer.function=mixcomwd_timerfun; + mixcomwd_timer.data=0; + mixcomwd_timer_alive=1; + add_timer(&mixcomwd_timer); + } + clear_bit(0,&mixcomwd_opened); + return 0; +} + + +static ssize_t mixcomwd_write(struct file *file, const char *data, size_t len, loff_t *ppos) +{ + if (ppos != &file->f_pos) { + return -ESPIPE; + } + + if(len) + { + mixcomwd_ping(); + return 1; + } + return 0; +} + +static int mixcomwd_ioctl(struct inode *inode, struct file *file, + unsigned int cmd, unsigned long arg) +{ + int status; + static struct watchdog_info ident = { + WDIOF_KEEPALIVEPING, 1, "MixCOM watchdog" + }; + + switch(cmd) + { + case WDIOC_GETSTATUS: + status=mixcomwd_opened; + if (!nowayout) { + status|=mixcomwd_timer_alive; + } + if (copy_to_user((int *)arg, &status, sizeof(int))) { + return -EFAULT; + } + break; + case WDIOC_GETSUPPORT: + if (copy_to_user((struct watchdog_info *)arg, &ident, + sizeof(ident))) { + return -EFAULT; + } + break; + case WDIOC_KEEPALIVE: + mixcomwd_ping(); + break; + default: + return -ENOTTY; + } + return 0; +} + +static struct file_operations mixcomwd_fops= +{ + .owner = THIS_MODULE, + .write = mixcomwd_write, + .ioctl = mixcomwd_ioctl, + .open = mixcomwd_open, + .release = mixcomwd_release, +}; + +static struct miscdevice mixcomwd_miscdev= +{ + WATCHDOG_MINOR, + "watchdog", + &mixcomwd_fops +}; + +static int __init mixcomwd_checkcard(int port) +{ + int id; + + if(check_region(port+MIXCOM_WATCHDOG_OFFSET,1)) { + return 0; + } + + id=inb_p(port + MIXCOM_WATCHDOG_OFFSET) & 0x3f; + if(id!=MIXCOM_ID) { + return 0; + } + return 1; +} + +static int __init flashcom_checkcard(int port) +{ + int id; + + if(check_region(port + FLASHCOM_WATCHDOG_OFFSET,1)) { + return 0; + } + + id=inb_p(port + FLASHCOM_WATCHDOG_OFFSET); + if(id!=FLASHCOM_ID) { + return 0; + } + return 1; + } + +static int __init mixcomwd_init(void) +{ + int i; + int ret; + int found=0; + + for (i = 0; !found && mixcomwd_ioports[i] != 0; i++) { + if (mixcomwd_checkcard(mixcomwd_ioports[i])) { + found = 1; + watchdog_port = mixcomwd_ioports[i] + MIXCOM_WATCHDOG_OFFSET; + } + } + + /* The FlashCOM card can be set up at 0x300 -> 0x378, in 0x8 jumps */ + for (i = 0x300; !found && i < 0x380; i+=0x8) { + if (flashcom_checkcard(i)) { + found = 1; + watchdog_port = i + FLASHCOM_WATCHDOG_OFFSET; + } + } + + if (!found) { + printk("mixcomwd: No card detected, or port not available.\n"); + return -ENODEV; + } + + if (!request_region(watchdog_port,1,"MixCOM watchdog")) + return -EIO; + + ret = misc_register(&mixcomwd_miscdev); + if (ret) + { + release_region(watchdog_port, 1); + return ret; + } + + printk(KERN_INFO "MixCOM watchdog driver v%s, watchdog port at 0x%3x\n",VERSION,watchdog_port); + + return 0; +} + +static void __exit mixcomwd_exit(void) +{ + if (!nowayout) { + if(mixcomwd_timer_alive) { + printk(KERN_WARNING "mixcomwd: I quit now, hardware will" + " probably reboot!\n"); + del_timer(&mixcomwd_timer); + mixcomwd_timer_alive=0; + } + } + release_region(watchdog_port,1); + misc_deregister(&mixcomwd_miscdev); +} + +module_init(mixcomwd_init); +module_exit(mixcomwd_exit); + +MODULE_LICENSE("GPL"); diff -urpN --exclude-from=/home/davej/.exclude bk-linus/drivers/char/watchdog/pcwd.c move-watchdogs/drivers/char/watchdog/pcwd.c --- bk-linus/drivers/char/watchdog/pcwd.c 1969-12-31 23:00:00.000000000 -0100 +++ move-watchdogs/drivers/char/watchdog/pcwd.c 2002-11-22 10:15:41.000000000 -0100 @@ -0,0 +1,672 @@ +/* + * PC Watchdog Driver + * by Ken Hollis (khollis@bitgate.com) + * + * Permission granted from Simon Machell (73244.1270@compuserve.com) + * Written for the Linux Kernel, and GPLed by Ken Hollis + * + * 960107 Added request_region routines, modulized the whole thing. + * 960108 Fixed end-of-file pointer (Thanks to Dan Hollis), added + * WD_TIMEOUT define. + * 960216 Added eof marker on the file, and changed verbose messages. + * 960716 Made functional and cosmetic changes to the source for + * inclusion in Linux 2.0.x kernels, thanks to Alan Cox. + * 960717 Removed read/seek routines, replaced with ioctl. Also, added + * check_region command due to Alan's suggestion. + * 960821 Made changes to compile in newer 2.0.x kernels. Added + * "cold reboot sense" entry. + * 960825 Made a few changes to code, deleted some defines and made + * typedefs to replace them. Made heartbeat reset only available + * via ioctl, and removed the write routine. + * 960828 Added new items for PC Watchdog Rev.C card. + * 960829 Changed around all of the IOCTLs, added new features, + * added watchdog disable/re-enable routines. Added firmware + * version reporting. Added read routine for temperature. + * Removed some extra defines, added an autodetect Revision + * routine. + * 961006 Revised some documentation, fixed some cosmetic bugs. Made + * drivers to panic the system if it's overheating at bootup. + * 961118 Changed some verbiage on some of the output, tidied up + * code bits, and added compatibility to 2.1.x. + * 970912 Enabled board on open and disable on close. + * 971107 Took account of recent VFS changes (broke read). + * 971210 Disable board on initialisation in case board already ticking. + * 971222 Changed open/close for temperature handling + * Michael Meskes . + * 980112 Used minor numbers from include/linux/miscdevice.h + * 990403 Clear reset status after reading control status register in + * pcwd_showprevstate(). [Marc Boucher ] + * 990605 Made changes to code to support Firmware 1.22a, added + * fairly useless proc entry. + * 990610 removed said useless proc code for the merge + * 000403 Removed last traces of proc code. + */ + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +/* + * These are the auto-probe addresses available. + * + * Revision A only uses ports 0x270 and 0x370. Revision C introduced 0x350. + * Revision A has an address range of 2 addresses, while Revision C has 3. + */ +static int pcwd_ioports[] = { 0x270, 0x350, 0x370, 0x000 }; + +#define WD_VER "1.10 (06/05/99)" + +/* + * It should be noted that PCWD_REVISION_B was removed because A and B + * are essentially the same types of card, with the exception that B + * has temperature reporting. Since I didn't receive a Rev.B card, + * the Rev.B card is not supported. (It's a good thing too, as they + * are no longer in production.) + */ +#define PCWD_REVISION_A 1 +#define PCWD_REVISION_C 2 + +#define WD_TIMEOUT 3 /* 1 1/2 seconds for a timeout */ + +/* + * These are the defines for the PC Watchdog card, revision A. + */ +#define WD_WDRST 0x01 /* Previously reset state */ +#define WD_T110 0x02 /* Temperature overheat sense */ +#define WD_HRTBT 0x04 /* Heartbeat sense */ +#define WD_RLY2 0x08 /* External relay triggered */ +#define WD_SRLY2 0x80 /* Software external relay triggered */ + +static int current_readport, revision, temp_panic; +static atomic_t open_allowed = ATOMIC_INIT(1); +static int initial_status, supports_temp, mode_debug; +static spinlock_t io_lock; + +/* + * PCWD_CHECKCARD + * + * This routine checks the "current_readport" to see if the card lies there. + * If it does, it returns accordingly. + */ +static int __init pcwd_checkcard(void) +{ + int card_dat, prev_card_dat, found = 0, count = 0, done = 0; + + card_dat = 0x00; + prev_card_dat = 0x00; + + prev_card_dat = inb(current_readport); + if (prev_card_dat == 0xFF) + return 0; + + while(count < WD_TIMEOUT) { + + /* Read the raw card data from the port, and strip off the + first 4 bits */ + + card_dat = inb_p(current_readport); + card_dat &= 0x000F; + + /* Sleep 1/2 second (or 500000 microseconds :) */ + + mdelay(500); + done = 0; + + /* If there's a heart beat in both instances, then this means we + found our card. This also means that either the card was + previously reset, or the computer was power-cycled. */ + + if ((card_dat & WD_HRTBT) && (prev_card_dat & WD_HRTBT) && + (!done)) { + found = 1; + done = 1; + break; + } + + /* If the card data is exactly the same as the previous card data, + it's safe to assume that we should check again. The manual says + that the heart beat will change every second (or the bit will + toggle), and this can be used to see if the card is there. If + the card was powered up with a cold boot, then the card will + not start blinking until 2.5 minutes after a reboot, so this + bit will stay at 1. */ + + if ((card_dat == prev_card_dat) && (!done)) { + count++; + done = 1; + } + + /* If the card data is toggling any bits, this means that the heart + beat was detected, or something else about the card is set. */ + + if ((card_dat != prev_card_dat) && (!done)) { + done = 1; + found = 1; + break; + } + + /* Otherwise something else strange happened. */ + + if (!done) + count++; + } + + return((found) ? 1 : 0); +} + +void pcwd_showprevstate(void) +{ + int card_status = 0x0000; + + if (revision == PCWD_REVISION_A) + initial_status = card_status = inb(current_readport); + else { + initial_status = card_status = inb(current_readport + 1); + outb_p(0x00, current_readport + 1); /* clear reset status */ + } + + if (revision == PCWD_REVISION_A) { + if (card_status & WD_WDRST) + printk("pcwd: Previous reboot was caused by the card.\n"); + + if (card_status & WD_T110) { + printk("pcwd: Card senses a CPU Overheat. Panicking!\n"); + panic("pcwd: CPU Overheat.\n"); + } + + if ((!(card_status & WD_WDRST)) && + (!(card_status & WD_T110))) + printk("pcwd: Cold boot sense.\n"); + } else { + if (card_status & 0x01) + printk("pcwd: Previous reboot was caused by the card.\n"); + + if (card_status & 0x04) { + printk("pcwd: Card senses a CPU Overheat. Panicking!\n"); + panic("pcwd: CPU Overheat.\n"); + } + + if ((!(card_status & 0x01)) && + (!(card_status & 0x04))) + printk("pcwd: Cold boot sense.\n"); + } +} + +static void pcwd_send_heartbeat(void) +{ + int wdrst_stat; + + wdrst_stat = inb_p(current_readport); + wdrst_stat &= 0x0F; + + wdrst_stat |= WD_WDRST; + + if (revision == PCWD_REVISION_A) + outb_p(wdrst_stat, current_readport + 1); + else + outb_p(wdrst_stat, current_readport); +} + +static int pcwd_ioctl(struct inode *inode, struct file *file, + unsigned int cmd, unsigned long arg) +{ + int cdat, rv; + static struct watchdog_info ident= + { + WDIOF_OVERHEAT|WDIOF_CARDRESET, + 1, + "PCWD" + }; + + switch(cmd) { + default: + return -ENOTTY; + + case WDIOC_GETSUPPORT: + if(copy_to_user((void*)arg, &ident, sizeof(ident))) + return -EFAULT; + return 0; + + case WDIOC_GETSTATUS: + spin_lock(&io_lock); + if (revision == PCWD_REVISION_A) + cdat = inb(current_readport); + else + cdat = inb(current_readport + 1 ); + spin_unlock(&io_lock); + rv = 0; + + if (revision == PCWD_REVISION_A) + { + if (cdat & WD_WDRST) + rv |= WDIOF_CARDRESET; + + if (cdat & WD_T110) + { + rv |= WDIOF_OVERHEAT; + + if (temp_panic) + panic("pcwd: Temperature overheat trip!\n"); + } + } + else + { + if (cdat & 0x01) + rv |= WDIOF_CARDRESET; + + if (cdat & 0x04) + { + rv |= WDIOF_OVERHEAT; + + if (temp_panic) + panic("pcwd: Temperature overheat trip!\n"); + } + } + + if(put_user(rv, (int *) arg)) + return -EFAULT; + return 0; + + case WDIOC_GETBOOTSTATUS: + rv = 0; + + if (revision == PCWD_REVISION_A) + { + if (initial_status & WD_WDRST) + rv |= WDIOF_CARDRESET; + + if (initial_status & WD_T110) + rv |= WDIOF_OVERHEAT; + } + else + { + if (initial_status & 0x01) + rv |= WDIOF_CARDRESET; + + if (initial_status & 0x04) + rv |= WDIOF_OVERHEAT; + } + + if(put_user(rv, (int *) arg)) + return -EFAULT; + return 0; + + case WDIOC_GETTEMP: + + rv = 0; + if ((supports_temp) && (mode_debug == 0)) + { + spin_lock(&io_lock); + rv = inb(current_readport); + spin_unlock(&io_lock); + if(put_user(rv, (int*) arg)) + return -EFAULT; + } else if(put_user(rv, (int*) arg)) + return -EFAULT; + return 0; + + case WDIOC_SETOPTIONS: + if (revision == PCWD_REVISION_C) + { + if(copy_from_user(&rv, (int*) arg, sizeof(int))) + return -EFAULT; + + if (rv & WDIOS_DISABLECARD) + { + spin_lock(&io_lock); + outb_p(0xA5, current_readport + 3); + outb_p(0xA5, current_readport + 3); + cdat = inb_p(current_readport + 2); + spin_unlock(&io_lock); + if ((cdat & 0x10) == 0) + { + printk("pcwd: Could not disable card.\n"); + return -EIO; + } + + return 0; + } + + if (rv & WDIOS_ENABLECARD) + { + spin_lock(&io_lock); + outb_p(0x00, current_readport + 3); + cdat = inb_p(current_readport + 2); + spin_unlock(&io_lock); + if (cdat & 0x10) + { + printk("pcwd: Could not enable card.\n"); + return -EIO; + } + return 0; + } + + if (rv & WDIOS_TEMPPANIC) + { + temp_panic = 1; + } + } + return -EINVAL; + + case WDIOC_KEEPALIVE: + pcwd_send_heartbeat(); + return 0; + } + + return 0; +} + +static ssize_t pcwd_write(struct file *file, const char *buf, size_t len, + loff_t *ppos) +{ + /* Can't seek (pwrite) on this device */ + if (ppos != &file->f_pos) + return -ESPIPE; + + if (len) + { + pcwd_send_heartbeat(); + return 1; + } + return 0; +} + +static int pcwd_open(struct inode *ino, struct file *filep) +{ + switch (minor(ino->i_rdev)) + { + case WATCHDOG_MINOR: + if ( !atomic_dec_and_test(&open_allowed) ) + { + atomic_inc( &open_allowed ); + return -EBUSY; + } + MOD_INC_USE_COUNT; + /* Enable the port */ + if (revision == PCWD_REVISION_C) + { + spin_lock(&io_lock); + outb_p(0x00, current_readport + 3); + spin_unlock(&io_lock); + } + return(0); + case TEMP_MINOR: + return(0); + default: + return (-ENODEV); + } +} + +static ssize_t pcwd_read(struct file *file, char *buf, size_t count, + loff_t *ppos) +{ + unsigned short c; + unsigned char cp; + + /* Can't seek (pread) on this device */ + if (ppos != &file->f_pos) + return -ESPIPE; + switch(minor(file->f_dentry->d_inode->i_rdev)) + { + case TEMP_MINOR: + /* + * Convert metric to Fahrenheit, since this was + * the decided 'standard' for this return value. + */ + + c = inb(current_readport); + cp = (c * 9 / 5) + 32; + if(copy_to_user(buf, &cp, 1)) + return -EFAULT; + return 1; + default: + return -EINVAL; + } +} + +static int pcwd_close(struct inode *ino, struct file *filep) +{ + if (minor(ino->i_rdev)==WATCHDOG_MINOR) + { +#ifndef CONFIG_WATCHDOG_NOWAYOUT + /* Disable the board */ + if (revision == PCWD_REVISION_C) { + spin_lock(&io_lock); + outb_p(0xA5, current_readport + 3); + outb_p(0xA5, current_readport + 3); + spin_unlock(&io_lock); + } + atomic_inc( &open_allowed ); +#endif + } + return 0; +} + +static inline void get_support(void) +{ + if (inb(current_readport) != 0xF0) + supports_temp = 1; +} + +static inline int get_revision(void) +{ + int r = PCWD_REVISION_C; + + spin_lock(&io_lock); + if ((inb(current_readport + 2) == 0xFF) || + (inb(current_readport + 3) == 0xFF)) + r=PCWD_REVISION_A; + spin_unlock(&io_lock); + + return r; +} + +static int __init send_command(int cmd) +{ + int i; + + outb_p(cmd, current_readport + 2); + mdelay(1); + + i = inb(current_readport); + i = inb(current_readport); + + return(i); +} + +static inline char *get_firmware(void) +{ + int i, found = 0, count = 0, one, ten, hund, minor; + char *ret; + + ret = kmalloc(6, GFP_KERNEL); + if(ret == NULL) + return NULL; + + while((count < 3) && (!found)) { + outb_p(0x80, current_readport + 2); + i = inb(current_readport); + + if (i == 0x00) + found = 1; + else if (i == 0xF3) + outb_p(0x00, current_readport + 2); + + udelay(400L); + count++; + } + + if (found) { + mode_debug = 1; + + one = send_command(0x81); + ten = send_command(0x82); + hund = send_command(0x83); + minor = send_command(0x84); + sprintf(ret, "%c.%c%c%c", one, ten, hund, minor); + } + else + sprintf(ret, "ERROR"); + + return(ret); +} + +static void debug_off(void) +{ + outb_p(0x00, current_readport + 2); + mode_debug = 0; +} + +static struct file_operations pcwd_fops = { + .owner = THIS_MODULE, + .read = pcwd_read, + .write = pcwd_write, + .ioctl = pcwd_ioctl, + .open = pcwd_open, + .release = pcwd_close, +}; + +static struct miscdevice pcwd_miscdev = { + WATCHDOG_MINOR, + "watchdog", + &pcwd_fops +}; + +static struct miscdevice temp_miscdev = { + TEMP_MINOR, + "temperature", + &pcwd_fops +}; + +static int __init pcwatchdog_init(void) +{ + int i, found = 0; + spin_lock_init(&io_lock); + + revision = PCWD_REVISION_A; + + printk("pcwd: v%s Ken Hollis (kenji@bitgate.com)\n", WD_VER); + + /* Initial variables */ + supports_temp = 0; + mode_debug = 0; + temp_panic = 0; + initial_status = 0x0000; + +#ifndef PCWD_BLIND + for (i = 0; pcwd_ioports[i] != 0; i++) { + current_readport = pcwd_ioports[i]; + + if (pcwd_checkcard()) { + found = 1; + break; + } + } + + if (!found) { + printk("pcwd: No card detected, or port not available.\n"); + return(-EIO); + } +#endif + +#ifdef PCWD_BLIND + current_readport = PCWD_BLIND; +#endif + + get_support(); + revision = get_revision(); + + if (revision == PCWD_REVISION_A) + printk("pcwd: PC Watchdog (REV.A) detected at port 0x%03x\n", current_readport); + else if (revision == PCWD_REVISION_C) + printk("pcwd: PC Watchdog (REV.C) detected at port 0x%03x (Firmware version: %s)\n", + current_readport, get_firmware()); + else { + /* Should NEVER happen, unless get_revision() fails. */ + printk("pcwd: Unable to get revision.\n"); + return -1; + } + + if (supports_temp) + printk("pcwd: Temperature Option Detected.\n"); + + debug_off(); + + pcwd_showprevstate(); + + /* Disable the board */ + if (revision == PCWD_REVISION_C) { + outb_p(0xA5, current_readport + 3); + outb_p(0xA5, current_readport + 3); + } + + if (misc_register(&pcwd_miscdev)) + return -ENODEV; + + if (supports_temp) + if (misc_register(&temp_miscdev)) { + misc_deregister(&pcwd_miscdev); + return -ENODEV; + } + + + if (revision == PCWD_REVISION_A) { + if (!request_region(current_readport, 2, "PCWD Rev.A (Berkshire)")) { + misc_deregister(&pcwd_miscdev); + if (supports_temp) + misc_deregister(&pcwd_miscdev); + return -EIO; + } + } + else + if (!request_region(current_readport, 4, "PCWD Rev.C (Berkshire)")) { + misc_deregister(&pcwd_miscdev); + if (supports_temp) + misc_deregister(&pcwd_miscdev); + return -EIO; + } + + return 0; +} + +static void __exit pcwatchdog_exit(void) +{ + misc_deregister(&pcwd_miscdev); + /* Disable the board */ + if (revision == PCWD_REVISION_C) { + outb_p(0xA5, current_readport + 3); + outb_p(0xA5, current_readport + 3); + } + if (supports_temp) + misc_deregister(&temp_miscdev); + + release_region(current_readport, (revision == PCWD_REVISION_A) ? 2 : 4); +} + +module_init(pcwatchdog_init); +module_exit(pcwatchdog_exit); + +MODULE_LICENSE("GPL"); + diff -urpN --exclude-from=/home/davej/.exclude bk-linus/drivers/char/watchdog/sbc60xxwdt.c move-watchdogs/drivers/char/watchdog/sbc60xxwdt.c --- bk-linus/drivers/char/watchdog/sbc60xxwdt.c 1969-12-31 23:00:00.000000000 -0100 +++ move-watchdogs/drivers/char/watchdog/sbc60xxwdt.c 2002-11-22 10:15:41.000000000 -0100 @@ -0,0 +1,354 @@ +/* + * 60xx Single Board Computer Watchdog Timer driver for Linux 2.2.x + * + * Based on acquirewdt.c by Alan Cox. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version + * 2 of the License, or (at your option) any later version. + * + * The author does NOT admit liability nor provide warranty for + * any of this software. This material is provided "AS-IS" in + * the hope that it may be useful for others. + * + * (c) Copyright 2000 Jakob Oestergaard + * + * 12/4 - 2000 [Initial revision] + * 25/4 - 2000 Added /dev/watchdog support + * 09/5 - 2001 [smj@oro.net] fixed fop_write to "return 1" on success + * + * + * Theory of operation: + * A Watchdog Timer (WDT) is a hardware circuit that can + * reset the computer system in case of a software fault. + * You probably knew that already. + * + * Usually a userspace daemon will notify the kernel WDT driver + * via the /proc/watchdog special device file that userspace is + * still alive, at regular intervals. When such a notification + * occurs, the driver will usually tell the hardware watchdog + * that everything is in order, and that the watchdog should wait + * for yet another little while to reset the system. + * If userspace fails (RAM error, kernel bug, whatever), the + * notifications cease to occur, and the hardware watchdog will + * reset the system (causing a reboot) after the timeout occurs. + * + * This WDT driver is different from the other Linux WDT + * drivers in several ways: + * *) The driver will ping the watchdog by itself, because this + * particular WDT has a very short timeout (one second) and it + * would be insane to count on any userspace daemon always + * getting scheduled within that time frame. + * *) This driver expects the userspace daemon to send a specific + * character code ('V') to /dev/watchdog before closing the + * /dev/watchdog file. If the userspace daemon closes the file + * without sending this special character, the driver will assume + * that the daemon (and userspace in general) died, and will + * stop pinging the WDT without disabling it first. This will + * cause a reboot. + * + * Why `V' ? Well, `V' is the character in ASCII for the value 86, + * and we all know that 86 is _the_ most random number in the universe. + * Therefore it is the letter that has the slightest chance of occuring + * by chance, when the system becomes corrupted. + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define OUR_NAME "sbc60xxwdt" + +/* + * You must set these - The driver cannot probe for the settings + */ + +#define WDT_STOP 0x45 +#define WDT_START 0x443 + +/* + * The 60xx board can use watchdog timeout values from one second + * to several minutes. The default is one second, so if we reset + * the watchdog every ~250ms we should be safe. + */ + +#define WDT_INTERVAL (HZ/4+1) + +/* + * We must not require too good response from the userspace daemon. + * Here we require the userspace daemon to send us a heartbeat + * char to /dev/watchdog every 10 seconds. + * If the daemon pulses us every 5 seconds, we can still afford + * a 5 second scheduling delay on the (high priority) daemon. That + * should be sufficient for a box under any load. + */ + +#define WDT_HEARTBEAT (HZ * 10) + +static void wdt_timer_ping(unsigned long); +static struct timer_list timer; +static unsigned long next_heartbeat; +static int wdt_is_open; +static int wdt_expect_close; + +#ifdef CONFIG_WATCHDOG_NOWAYOUT +static int nowayout = 1; +#else +static int nowayout = 0; +#endif + +MODULE_PARM(nowayout,"i"); +MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default=CONFIG_WATCHDOG_NOWAYOUT)"); + +/* + * Whack the dog + */ + +static void wdt_timer_ping(unsigned long data) +{ + /* If we got a heartbeat pulse within the WDT_US_INTERVAL + * we agree to ping the WDT + */ + if(time_before(jiffies, next_heartbeat)) + { + /* Ping the WDT by reading from WDT_START */ + inb_p(WDT_START); + /* Re-set the timer interval */ + timer.expires = jiffies + WDT_INTERVAL; + add_timer(&timer); + } else { + printk(OUR_NAME ": Heartbeat lost! Will not ping the watchdog\n"); + } +} + +/* + * Utility routines + */ + +static void wdt_startup(void) +{ + next_heartbeat = jiffies + WDT_HEARTBEAT; + + /* Start the timer */ + timer.expires = jiffies + WDT_INTERVAL; + add_timer(&timer); + printk(OUR_NAME ": Watchdog timer is now enabled.\n"); +} + +static void wdt_turnoff(void) +{ + /* Stop the timer */ + del_timer(&timer); + inb_p(WDT_STOP); + printk(OUR_NAME ": Watchdog timer is now disabled...\n"); +} + + +/* + * /dev/watchdog handling + */ + +static ssize_t fop_write(struct file * file, const char * buf, size_t count, loff_t * ppos) +{ + /* We can't seek */ + if(ppos != &file->f_pos) + return -ESPIPE; + + /* See if we got the magic character */ + if(count) + { + size_t ofs; + + /* note: just in case someone wrote the magic character + * five months ago... */ + wdt_expect_close = 0; + + /* now scan */ + for(ofs = 0; ofs != count; ofs++) + { + char c; + if(get_user(c, buf+ofs)) + return -EFAULT; + if(c == 'V') + wdt_expect_close = 1; + } + /* Well, anyhow someone wrote to us, we should return that favour */ + next_heartbeat = jiffies + WDT_HEARTBEAT; + return 1; + } + return 0; +} + +static ssize_t fop_read(struct file * file, char * buf, size_t count, loff_t * ppos) +{ + /* No can do */ + return -EINVAL; +} + +static int fop_open(struct inode * inode, struct file * file) +{ + switch(minor(inode->i_rdev)) + { + case WATCHDOG_MINOR: + /* Just in case we're already talking to someone... */ + if(wdt_is_open) + return -EBUSY; + if (nowayout) { + MOD_INC_USE_COUNT; + } + /* Good, fire up the show */ + wdt_is_open = 1; + wdt_startup(); + return 0; + + default: + return -ENODEV; + } +} + +static int fop_close(struct inode * inode, struct file * file) +{ + if(minor(inode->i_rdev) == WATCHDOG_MINOR) + { + if(wdt_expect_close && !nowayout) + wdt_turnoff(); + else { + del_timer(&timer); + printk(OUR_NAME ": device file closed unexpectedly. Will not stop the WDT!\n"); + } + } + wdt_is_open = 0; + return 0; +} + +static int fop_ioctl(struct inode *inode, struct file *file, unsigned int cmd, + unsigned long arg) +{ + static struct watchdog_info ident= + { + 0, + 1, + "SB60xx" + }; + + switch(cmd) + { + default: + return -ENOTTY; + case WDIOC_GETSUPPORT: + return copy_to_user((struct watchdog_info *)arg, &ident, sizeof(ident))?-EFAULT:0; + case WDIOC_KEEPALIVE: + next_heartbeat = jiffies + WDT_HEARTBEAT; + return 0; + } +} + +static struct file_operations wdt_fops = { + .owner = THIS_MODULE, + .llseek = no_llseek, + .read = fop_read, + .write = fop_write, + .open = fop_open, + .release = fop_close, + .ioctl = fop_ioctl +}; + +static struct miscdevice wdt_miscdev = { + WATCHDOG_MINOR, + "watchdog", + &wdt_fops +}; + +/* + * Notifier for system down + */ + +static int wdt_notify_sys(struct notifier_block *this, unsigned long code, + void *unused) +{ + if(code==SYS_DOWN || code==SYS_HALT) + wdt_turnoff(); + return NOTIFY_DONE; +} + +/* + * The WDT needs to learn about soft shutdowns in order to + * turn the timebomb registers off. + */ + +static struct notifier_block wdt_notifier= +{ + wdt_notify_sys, + 0, + 0 +}; + +static void __exit sbc60xxwdt_unload(void) +{ + wdt_turnoff(); + + /* Deregister */ + misc_deregister(&wdt_miscdev); + + unregister_reboot_notifier(&wdt_notifier); + release_region(WDT_START,1); + release_region(WDT_STOP,1); +} + +static int __init sbc60xxwdt_init(void) +{ + int rc = -EBUSY; + + if (!request_region(WDT_STOP, 1, "SBC 60XX WDT")) + goto err_out; + if (!request_region(WDT_START, 1, "SBC 60XX WDT")) + goto err_out_region1; + + init_timer(&timer); + timer.function = wdt_timer_ping; + timer.data = 0; + + rc = misc_register(&wdt_miscdev); + if (rc) + goto err_out_region2; + + rc = register_reboot_notifier(&wdt_notifier); + if (rc) + goto err_out_miscdev; + + printk(KERN_INFO OUR_NAME ": WDT driver for 60XX single board computer initialised.\n"); + + return 0; + +err_out_miscdev: + misc_deregister(&wdt_miscdev); +err_out_region2: + release_region(WDT_START,1); +err_out_region1: + release_region(WDT_STOP,1); +err_out: + return rc; +} + +module_init(sbc60xxwdt_init); +module_exit(sbc60xxwdt_unload); + +MODULE_LICENSE("GPL"); diff -urpN --exclude-from=/home/davej/.exclude bk-linus/drivers/char/watchdog/scx200_wdt.c move-watchdogs/drivers/char/watchdog/scx200_wdt.c --- bk-linus/drivers/char/watchdog/scx200_wdt.c 1969-12-31 23:00:00.000000000 -0100 +++ move-watchdogs/drivers/char/watchdog/scx200_wdt.c 2002-11-22 10:15:41.000000000 -0100 @@ -0,0 +1,277 @@ +/* linux/drivers/char/scx200_wdt.c + + National Semiconductor SCx200 Watchdog support + + Copyright (c) 2001,2002 Christer Weinigel + + Som code taken from: + National Semiconductor PC87307/PC97307 (ala SC1200) WDT driver + (c) Copyright 2002 Zwane Mwaikambo + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License as + published by the Free Software Foundation; either version 2 of the + License, or (at your option) any later version. + + 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. */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#define NAME "scx200_wdt" + +MODULE_AUTHOR("Christer Weinigel "); +MODULE_DESCRIPTION("NatSemi SCx200 Watchdog Driver"); +MODULE_LICENSE("GPL"); + +#ifndef CONFIG_WATCHDOG_NOWAYOUT +#define CONFIG_WATCHDOG_NOWAYOUT 0 +#endif + +static int margin = 60; /* in seconds */ +MODULE_PARM(margin, "i"); +MODULE_PARM_DESC(margin, "Watchdog margin in seconds"); + +static int nowayout = CONFIG_WATCHDOG_NOWAYOUT; +MODULE_PARM(nowayout, "i"); +MODULE_PARM_DESC(nowayout, "Disable watchdog shutdown on close"); + +static u16 wdto_restart; +static struct semaphore open_semaphore; +static unsigned expect_close; + +/* Bits of the WDCNFG register */ +#define W_ENABLE 0x00fa /* Enable watchdog */ +#define W_DISABLE 0x0000 /* Disable watchdog */ + +/* The scaling factor for the timer, this depends on the value of W_ENABLE */ +#define W_SCALE (32768/1024) + +static void scx200_wdt_ping(void) +{ + outw(wdto_restart, SCx200_CB_BASE + SCx200_WDT_WDTO); +} + +static void scx200_wdt_update_margin(void) +{ + printk(KERN_INFO NAME ": timer margin %d seconds\n", margin); + wdto_restart = margin * W_SCALE; +} + +static void scx200_wdt_enable(void) +{ + printk(KERN_DEBUG NAME ": enabling watchdog timer, wdto_restart = %d\n", + wdto_restart); + + outw(0, SCx200_CB_BASE + SCx200_WDT_WDTO); + outb(SCx200_WDT_WDSTS_WDOVF, SCx200_CB_BASE + SCx200_WDT_WDSTS); + outw(W_ENABLE, SCx200_CB_BASE + SCx200_WDT_WDCNFG); + + scx200_wdt_ping(); +} + +static void scx200_wdt_disable(void) +{ + printk(KERN_DEBUG NAME ": disabling watchdog timer\n"); + + outw(0, SCx200_CB_BASE + SCx200_WDT_WDTO); + outb(SCx200_WDT_WDSTS_WDOVF, SCx200_CB_BASE + SCx200_WDT_WDSTS); + outw(W_DISABLE, SCx200_CB_BASE + SCx200_WDT_WDCNFG); +} + +static int scx200_wdt_open(struct inode *inode, struct file *file) +{ + /* only allow one at a time */ + if (down_trylock(&open_semaphore)) + return -EBUSY; + scx200_wdt_enable(); + expect_close = 0; + + return 0; +} + +static int scx200_wdt_release(struct inode *inode, struct file *file) +{ + if (!expect_close) { + printk(KERN_WARNING NAME ": watchdog device closed unexpectedly, will not disable the watchdog timer\n"); + } else if (!nowayout) { + scx200_wdt_disable(); + } + up(&open_semaphore); + + return 0; +} + +static int scx200_wdt_notify_sys(struct notifier_block *this, + unsigned long code, void *unused) +{ + if (code == SYS_HALT || code == SYS_POWER_OFF) + if (!nowayout) + scx200_wdt_disable(); + + return NOTIFY_DONE; +} + +static struct notifier_block scx200_wdt_notifier = +{ + .notifier_call = scx200_wdt_notify_sys +}; + +static ssize_t scx200_wdt_write(struct file *file, const char *data, + size_t len, loff_t *ppos) +{ + if (ppos != &file->f_pos) + return -ESPIPE; + + /* check for a magic close character */ + if (len) + { + size_t i; + + scx200_wdt_ping(); + + expect_close = 0; + for (i = 0; i < len; ++i) { + char c; + if (get_user(c, data+i)) + return -EFAULT; + if (c == 'V') + expect_close = 1; + } + + return len; + } + + return 0; +} + +static int scx200_wdt_ioctl(struct inode *inode, struct file *file, + unsigned int cmd, unsigned long arg) +{ + static struct watchdog_info ident = { + .identity = "NatSemi SCx200 Watchdog", + .firmware_version = 1, + .options = (WDIOF_SETTIMEOUT | WDIOF_KEEPALIVEPING), + }; + int new_margin; + + switch (cmd) { + default: + return -ENOTTY; + case WDIOC_GETSUPPORT: + if(copy_to_user((struct watchdog_info *)arg, &ident, + sizeof(ident))) + return -EFAULT; + return 0; + case WDIOC_GETSTATUS: + case WDIOC_GETBOOTSTATUS: + if (put_user(0, (int *)arg)) + return -EFAULT; + return 0; + case WDIOC_KEEPALIVE: + scx200_wdt_ping(); + return 0; + case WDIOC_SETTIMEOUT: + if (get_user(new_margin, (int *)arg)) + return -EFAULT; + if (new_margin < 1) + return -EINVAL; + margin = new_margin; + scx200_wdt_update_margin(); + scx200_wdt_ping(); + case WDIOC_GETTIMEOUT: + if (put_user(margin, (int *)arg)) + return -EFAULT; + return 0; + } +} + +static struct file_operations scx200_wdt_fops = { + .owner = THIS_MODULE, + .write = scx200_wdt_write, + .ioctl = scx200_wdt_ioctl, + .open = scx200_wdt_open, + .release = scx200_wdt_release, +}; + +static struct miscdevice scx200_wdt_miscdev = { + .minor = WATCHDOG_MINOR, + .name = NAME, + .fops = &scx200_wdt_fops, +}; + +static int __init scx200_wdt_init(void) +{ + int r; + + printk(KERN_DEBUG NAME ": NatSemi SCx200 Watchdog Driver\n"); + + /* First check that this really is a NatSemi SCx200 CPU */ + if ((pci_find_device(PCI_VENDOR_ID_NS, + PCI_DEVICE_ID_NS_SCx200_BRIDGE, + NULL)) == NULL) + return -ENODEV; + + /* More sanity checks, verify that the configuration block is there */ + if (!scx200_cb_probe(SCx200_CB_BASE)) { + printk(KERN_WARNING NAME ": no configuration block found\n"); + return -ENODEV; + } + + if (!request_region(SCx200_CB_BASE + SCx200_WDT_OFFSET, + SCx200_WDT_SIZE, + "NatSemi SCx200 Watchdog")) { + printk(KERN_WARNING NAME ": watchdog I/O region busy\n"); + return -EBUSY; + } + + scx200_wdt_update_margin(); + scx200_wdt_disable(); + + sema_init(&open_semaphore, 1); + + r = misc_register(&scx200_wdt_miscdev); + if (r) + return r; + + r = register_reboot_notifier(&scx200_wdt_notifier); + if (r) { + printk(KERN_ERR NAME ": unable to register reboot notifier"); + misc_deregister(&scx200_wdt_miscdev); + return r; + } + + return 0; +} + +static void __exit scx200_wdt_cleanup(void) +{ + unregister_reboot_notifier(&scx200_wdt_notifier); + misc_deregister(&scx200_wdt_miscdev); + release_region(SCx200_CB_BASE + SCx200_WDT_OFFSET, + SCx200_WDT_SIZE); +} + +module_init(scx200_wdt_init); +module_exit(scx200_wdt_cleanup); + +/* + Local variables: + compile-command: "make -k -C ../.. SUBDIRS=drivers/char modules" + c-basic-offset: 8 + End: +*/ diff -urpN --exclude-from=/home/davej/.exclude bk-linus/drivers/char/watchdog/shwdt.c move-watchdogs/drivers/char/watchdog/shwdt.c --- bk-linus/drivers/char/watchdog/shwdt.c 1969-12-31 23:00:00.000000000 -0100 +++ move-watchdogs/drivers/char/watchdog/shwdt.c 2002-11-22 10:15:41.000000000 -0100 @@ -0,0 +1,417 @@ +/* + * drivers/char/shwdt.c + * + * Watchdog driver for integrated watchdog in the SuperH 3/4 processors. + * + * Copyright (C) 2001 Paul Mundt + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + * + * 14-Dec-2001 Matt Domsch + * Added nowayout module option to override CONFIG_WATCHDOG_NOWAYOUT + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#if defined(CONFIG_CPU_SH4) + #define WTCNT 0xffc00008 + #define WTCSR 0xffc0000c +#elif defined(CONFIG_CPU_SH3) + #define WTCNT 0xffffff84 + #define WTCSR 0xffffff86 +#else + #error "Can't use SH 3/4 watchdog on non-SH 3/4 processor." +#endif + +#define WTCNT_HIGH 0x5a00 +#define WTCSR_HIGH 0xa500 + +#define WTCSR_TME 0x80 +#define WTCSR_WT 0x40 +#define WTCSR_RSTS 0x20 +#define WTCSR_WOVF 0x10 +#define WTCSR_IOVF 0x08 +#define WTCSR_CKS2 0x04 +#define WTCSR_CKS1 0x02 +#define WTCSR_CKS0 0x01 + +/* + * CKS0-2 supports a number of clock division ratios. At the time the watchdog + * is enabled, it defaults to a 41 usec overflow period .. we overload this to + * something a little more reasonable, and really can't deal with anything + * lower than WTCSR_CKS_1024, else we drop back into the usec range. + * + * Clock Division Ratio Overflow Period + * -------------------------------------------- + * 1/32 (initial value) 41 usecs + * 1/64 82 usecs + * 1/128 164 usecs + * 1/256 328 usecs + * 1/512 656 usecs + * 1/1024 1.31 msecs + * 1/2048 2.62 msecs + * 1/4096 5.25 msecs + */ +#define WTCSR_CKS_32 0x00 +#define WTCSR_CKS_64 0x01 +#define WTCSR_CKS_128 0x02 +#define WTCSR_CKS_256 0x03 +#define WTCSR_CKS_512 0x04 +#define WTCSR_CKS_1024 0x05 +#define WTCSR_CKS_2048 0x06 +#define WTCSR_CKS_4096 0x07 + +/* + * Default clock division ratio is 5.25 msecs. Overload this at module load + * time. Any value not in the msec range will default to a timeout of one + * jiffy, which exceeds the usec overflow periods. + */ +static int clock_division_ratio = WTCSR_CKS_4096; + +#define msecs_to_jiffies(msecs) (jiffies + ((HZ * msecs + 999) / 1000)) +#define next_ping_period(cks) msecs_to_jiffies(cks - 4) +#define user_ping_period(cks) (next_ping_period(cks) * 10) + +static unsigned long sh_is_open = 0; +static struct watchdog_info sh_wdt_info; +static struct timer_list timer; +static unsigned long next_heartbeat; + +#ifdef CONFIG_WATCHDOG_NOWAYOUT +static int nowayout = 1; +#else +static int nowayout = 0; +#endif + +MODULE_PARM(nowayout,"i"); +MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default=CONFIG_WATCHDOG_NOWAYOUT)"); + +/** + * sh_wdt_write_cnt - Write to Counter + * + * @val: Value to write + * + * Writes the given value @val to the lower byte of the timer counter. + * The upper byte is set manually on each write. + */ +static void sh_wdt_write_cnt(__u8 val) +{ + ctrl_outw(WTCNT_HIGH | (__u16)val, WTCNT); +} + +/** + * sh_wdt_write_csr - Write to Control/Status Register + * + * @val: Value to write + * + * Writes the given value @val to the lower byte of the control/status + * register. The upper byte is set manually on each write. + */ +static void sh_wdt_write_csr(__u8 val) +{ + ctrl_outw(WTCSR_HIGH | (__u16)val, WTCSR); +} + +/** + * sh_wdt_start - Start the Watchdog + * + * Starts the watchdog. + */ +static void sh_wdt_start(void) +{ + timer.expires = next_ping_period(clock_division_ratio); + next_heartbeat = user_ping_period(clock_division_ratio); + add_timer(&timer); + + sh_wdt_write_csr(WTCSR_WT | WTCSR_CKS_4096); + sh_wdt_write_cnt(0); + sh_wdt_write_csr((ctrl_inb(WTCSR) | WTCSR_TME)); +} + +/** + * sh_wdt_stop - Stop the Watchdog + * + * Stops the watchdog. + */ +static void sh_wdt_stop(void) +{ + del_timer(&timer); + + sh_wdt_write_csr((ctrl_inb(WTCSR) & ~WTCSR_TME)); +} + +/** + * sh_wdt_ping - Ping the Watchdog + * + * @data: Unused + * + * Clears overflow bit, resets timer counter. + */ +static void sh_wdt_ping(unsigned long data) +{ + if (time_before(jiffies, next_heartbeat)) { + sh_wdt_write_csr((ctrl_inb(WTCSR) & ~WTCSR_IOVF)); + sh_wdt_write_cnt(0); + + timer.expires = next_ping_period(clock_division_ratio); + add_timer(&timer); + } +} + +/** + * sh_wdt_open - Open the Device + * + * @inode: inode of device + * @file: file handle of device + * + * Watchdog device is opened and started. + */ +static int sh_wdt_open(struct inode *inode, struct file *file) +{ + switch (minor(inode->i_rdev)) { + case WATCHDOG_MINOR: + if (test_and_set_bit(0, &sh_is_open)) + return -EBUSY; + + if (nowayout) { + MOD_INC_USE_COUNT; + } + + sh_wdt_start(); + + break; + default: + return -ENODEV; + } + + return 0; +} + +/** + * sh_wdt_close - Close the Device + * + * @inode: inode of device + * @file: file handle of device + * + * Watchdog device is closed and stopped. + */ +static int sh_wdt_close(struct inode *inode, struct file *file) +{ + if (minor(inode->i_rdev) == WATCHDOG_MINOR) { + if (!nowayout) { + sh_wdt_stop(); + } + clear_bit(0, &sh_is_open); + } + + return 0; +} + +/** + * sh_wdt_read - Read from Device + * + * @file: file handle of device + * @buf: buffer to write to + * @count: length of buffer + * @ppos: offset + * + * Unsupported. + */ +static ssize_t sh_wdt_read(struct file *file, char *buf, + size_t count, loff_t *ppos) +{ + return -EINVAL; +} + +/** + * sh_wdt_write - Write to Device + * + * @file: file handle of device + * @buf: buffer to write + * @count: length of buffer + * @ppos: offset + * + * Pings the watchdog on write. + */ +static ssize_t sh_wdt_write(struct file *file, const char *buf, + size_t count, loff_t *ppos) +{ + /* Can't seek (pwrite) on this device */ + if (ppos != &file->f_pos) + return -ESPIPE; + + if (count) { + next_heartbeat = user_ping_period(clock_division_ratio); + return 1; + } + + return 0; +} + +/** + * sh_wdt_ioctl - Query Device + * + * @inode: inode of device + * @file: file handle of device + * @cmd: watchdog command + * @arg: argument + * + * Query basic information from the device or ping it, as outlined by the + * watchdog API. + */ +static int sh_wdt_ioctl(struct inode *inode, struct file *file, + unsigned int cmd, unsigned long arg) +{ + switch (cmd) { + case WDIOC_GETSUPPORT: + if (copy_to_user((struct watchdog_info *)arg, + &sh_wdt_info, + sizeof(sh_wdt_info))) { + return -EFAULT; + } + + break; + case WDIOC_GETSTATUS: + if (copy_to_user((int *)arg, + &sh_is_open, + sizeof(int))) { + return -EFAULT; + } + + break; + case WDIOC_KEEPALIVE: + next_heartbeat = user_ping_period(clock_division_ratio); + + break; + default: + return -ENOTTY; + } + + return 0; +} + +/** + * sh_wdt_notify_sys - Notifier Handler + * + * @this: notifier block + * @code: notifier event + * @unused: unused + * + * Handles specific events, such as turning off the watchdog during a + * shutdown event. + */ +static int sh_wdt_notify_sys(struct notifier_block *this, + unsigned long code, void *unused) +{ + if (code == SYS_DOWN || code == SYS_HALT) { + sh_wdt_stop(); + } + + return NOTIFY_DONE; +} + +static struct file_operations sh_wdt_fops = { + .owner = THIS_MODULE, + .read = sh_wdt_read, + .write = sh_wdt_write, + .ioctl = sh_wdt_ioctl, + .open = sh_wdt_open, + .release = sh_wdt_close, +}; + +static struct watchdog_info sh_wdt_info = { + WDIOF_KEEPALIVEPING, + 1, + "SH WDT", +}; + +static struct notifier_block sh_wdt_notifier = { + sh_wdt_notify_sys, + NULL, + 0 +}; + +static struct miscdevice sh_wdt_miscdev = { + WATCHDOG_MINOR, + "watchdog", + &sh_wdt_fops, +}; + +/** + * sh_wdt_init - Initialize module + * + * Registers the device and notifier handler. Actual device + * initialization is handled by sh_wdt_open(). + */ +static int __init sh_wdt_init(void) +{ + if (misc_register(&sh_wdt_miscdev)) { + printk(KERN_ERR "shwdt: Can't register misc device\n"); + return -EINVAL; + } + + if (!request_region(WTCNT, 1, "shwdt")) { + printk(KERN_ERR "shwdt: Can't request WTCNT region\n"); + misc_deregister(&sh_wdt_miscdev); + return -ENXIO; + } + + if (!request_region(WTCSR, 1, "shwdt")) { + printk(KERN_ERR "shwdt: Can't request WTCSR region\n"); + release_region(WTCNT, 1); + misc_deregister(&sh_wdt_miscdev); + return -ENXIO; + } + + if (register_reboot_notifier(&sh_wdt_notifier)) { + printk(KERN_ERR "shwdt: Can't register reboot notifier\n"); + release_region(WTCSR, 1); + release_region(WTCNT, 1); + misc_deregister(&sh_wdt_miscdev); + return -EINVAL; + } + + init_timer(&timer); + timer.function = sh_wdt_ping; + timer.data = 0; + + return 0; +} + +/** + * sh_wdt_exit - Deinitialize module + * + * Unregisters the device and notifier handler. Actual device + * deinitialization is handled by sh_wdt_close(). + */ +static void __exit sh_wdt_exit(void) +{ + unregister_reboot_notifier(&sh_wdt_notifier); + release_region(WTCSR, 1); + release_region(WTCNT, 1); + misc_deregister(&sh_wdt_miscdev); +} + +MODULE_AUTHOR("Paul Mundt "); +MODULE_DESCRIPTION("SH 3/4 watchdog driver"); +MODULE_LICENSE("GPL"); +MODULE_PARM(clock_division_ratio, "i"); +MODULE_PARM_DESC(clock_division_ratio, "Clock division ratio. Valid ranges are from 0x5 (1.31ms) to 0x7 (5.25ms). Defaults to 0x7."); + +module_init(sh_wdt_init); +module_exit(sh_wdt_exit); + diff -urpN --exclude-from=/home/davej/.exclude bk-linus/drivers/char/watchdog/softdog.c move-watchdogs/drivers/char/watchdog/softdog.c --- bk-linus/drivers/char/watchdog/softdog.c 1969-12-31 23:00:00.000000000 -0100 +++ move-watchdogs/drivers/char/watchdog/softdog.c 2002-11-22 10:15:41.000000000 -0100 @@ -0,0 +1,196 @@ +/* + * SoftDog 0.06: A Software Watchdog Device + * + * (c) Copyright 1996 Alan Cox , All Rights Reserved. + * http://www.redhat.com + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version + * 2 of the License, or (at your option) any later version. + * + * Neither Alan Cox nor CymruNet Ltd. admit liability nor provide + * warranty for any of this software. This material is provided + * "AS-IS" and at no charge. + * + * (c) Copyright 1995 Alan Cox + * + * Software only watchdog driver. Unlike its big brother the WDT501P + * driver this won't always recover a failed machine. + * + * 03/96: Angelo Haritsis : + * Modularised. + * Added soft_margin; use upon insmod to change the timer delay. + * NB: uses same minor as wdt (WATCHDOG_MINOR); we could use separate + * minors. + * + * 19980911 Alan Cox + * Made SMP safe for 2.3.x + * + * 20011214 Matt Domsch + * Added nowayout module option to override CONFIG_WATCHDOG_NOWAYOUT + * Didn't add timeout option, as soft_margin option already exists. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define TIMER_MARGIN 60 /* (secs) Default is 1 minute */ + +static int soft_margin = TIMER_MARGIN; /* in seconds */ + +MODULE_PARM(soft_margin,"i"); + +#ifdef CONFIG_WATCHDOG_NOWAYOUT +static int nowayout = 1; +#else +static int nowayout = 0; +#endif + +MODULE_PARM(nowayout,"i"); +MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default=CONFIG_WATCHDOG_NOWAYOUT)"); +MODULE_LICENSE("GPL"); + +/* + * Our timer + */ + +static void watchdog_fire(unsigned long); + +static struct timer_list watchdog_ticktock = + TIMER_INITIALIZER(watchdog_fire, 0, 0); +static int timer_alive; + + +/* + * If the timer expires.. + */ + +static void watchdog_fire(unsigned long data) +{ +#ifdef ONLY_TESTING + printk(KERN_CRIT "SOFTDOG: Would Reboot.\n"); +#else + printk(KERN_CRIT "SOFTDOG: Initiating system reboot.\n"); + machine_restart(NULL); + printk("WATCHDOG: Reboot didn't ?????\n"); +#endif +} + +/* + * Allow only one person to hold it open + */ + +static int softdog_open(struct inode *inode, struct file *file) +{ + if(timer_alive) + return -EBUSY; + if (nowayout) { + MOD_INC_USE_COUNT; + } + /* + * Activate timer + */ + mod_timer(&watchdog_ticktock, jiffies+(soft_margin*HZ)); + timer_alive=1; + return 0; +} + +static int softdog_release(struct inode *inode, struct file *file) +{ + /* + * Shut off the timer. + * Lock it in if it's a module and we set nowayout + */ + if(!nowayout) { + del_timer(&watchdog_ticktock); + } + timer_alive=0; + return 0; +} + +static ssize_t softdog_write(struct file *file, const char *data, size_t len, loff_t *ppos) +{ + /* Can't seek (pwrite) on this device */ + if (ppos != &file->f_pos) + return -ESPIPE; + + /* + * Refresh the timer. + */ + if(len) { + mod_timer(&watchdog_ticktock, jiffies+(soft_margin*HZ)); + return 1; + } + return 0; +} + +static int softdog_ioctl(struct inode *inode, struct file *file, + unsigned int cmd, unsigned long arg) +{ + static struct watchdog_info ident = { + identity: "Software Watchdog", + }; + switch (cmd) { + default: + return -ENOTTY; + case WDIOC_GETSUPPORT: + if(copy_to_user((struct watchdog_info *)arg, &ident, sizeof(ident))) + return -EFAULT; + return 0; + case WDIOC_GETSTATUS: + case WDIOC_GETBOOTSTATUS: + return put_user(0,(int *)arg); + case WDIOC_KEEPALIVE: + mod_timer(&watchdog_ticktock, jiffies+(soft_margin*HZ)); + return 0; + } +} + +static struct file_operations softdog_fops = { + owner: THIS_MODULE, + write: softdog_write, + ioctl: softdog_ioctl, + open: softdog_open, + release: softdog_release, +}; + +static struct miscdevice softdog_miscdev = { + minor: WATCHDOG_MINOR, + name: "watchdog", + fops: &softdog_fops, +}; + +static char banner[] __initdata = KERN_INFO "Software Watchdog Timer: 0.06, soft_margin: %d sec, nowayout: %d\n"; + +static int __init watchdog_init(void) +{ + int ret; + + ret = misc_register(&softdog_miscdev); + + if (ret) + return ret; + + printk(banner, soft_margin, nowayout); + + return 0; +} + +static void __exit watchdog_exit(void) +{ + misc_deregister(&softdog_miscdev); +} + +module_init(watchdog_init); +module_exit(watchdog_exit); diff -urpN --exclude-from=/home/davej/.exclude bk-linus/drivers/char/watchdog/w83877f_wdt.c move-watchdogs/drivers/char/watchdog/w83877f_wdt.c --- bk-linus/drivers/char/watchdog/w83877f_wdt.c 1969-12-31 23:00:00.000000000 -0100 +++ move-watchdogs/drivers/char/watchdog/w83877f_wdt.c 2002-11-22 10:15:41.000000000 -0100 @@ -0,0 +1,366 @@ +/* + * W83877F Computer Watchdog Timer driver for Linux 2.4.x + * + * Based on acquirewdt.c by Alan Cox, + * and sbc60xxwdt.c by Jakob Oestergaard + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version + * 2 of the License, or (at your option) any later version. + * + * The authors do NOT admit liability nor provide warranty for + * any of this software. This material is provided "AS-IS" in + * the hope that it may be useful for others. + * + * (c) Copyright 2001 Scott Jennings + * + * 4/19 - 2001 [Initial revision] + * 9/27 - 2001 Added spinlocking + * + * + * Theory of operation: + * A Watchdog Timer (WDT) is a hardware circuit that can + * reset the computer system in case of a software fault. + * You probably knew that already. + * + * Usually a userspace daemon will notify the kernel WDT driver + * via the /proc/watchdog special device file that userspace is + * still alive, at regular intervals. When such a notification + * occurs, the driver will usually tell the hardware watchdog + * that everything is in order, and that the watchdog should wait + * for yet another little while to reset the system. + * If userspace fails (RAM error, kernel bug, whatever), the + * notifications cease to occur, and the hardware watchdog will + * reset the system (causing a reboot) after the timeout occurs. + * + * This WDT driver is different from most other Linux WDT + * drivers in that the driver will ping the watchdog by itself, + * because this particular WDT has a very short timeout (1.6 + * seconds) and it would be insane to count on any userspace + * daemon always getting scheduled within that time frame. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define OUR_NAME "w83877f_wdt" + +#define ENABLE_W83877F_PORT 0x3F0 +#define ENABLE_W83877F 0x87 +#define DISABLE_W83877F 0xAA +#define WDT_PING 0x443 +#define WDT_REGISTER 0x14 +#define WDT_ENABLE 0x9C +#define WDT_DISABLE 0x8C + +/* + * The W83877F seems to be fixed at 1.6s timeout (at least on the + * EMACS PC-104 board I'm using). If we reset the watchdog every + * ~250ms we should be safe. */ + +#define WDT_INTERVAL (HZ/4+1) + +/* + * We must not require too good response from the userspace daemon. + * Here we require the userspace daemon to send us a heartbeat + * char to /dev/watchdog every 30 seconds. + */ + +#define WDT_HEARTBEAT (HZ * 30) + +static void wdt_timer_ping(unsigned long); +static struct timer_list timer; +static unsigned long next_heartbeat; +static unsigned long wdt_is_open; +static int wdt_expect_close; +static spinlock_t wdt_spinlock; + +/* + * Whack the dog + */ + +static void wdt_timer_ping(unsigned long data) +{ + /* If we got a heartbeat pulse within the WDT_US_INTERVAL + * we agree to ping the WDT + */ + if(time_before(jiffies, next_heartbeat)) + { + /* Ping the WDT */ + spin_lock(&wdt_spinlock); + + /* Ping the WDT by reading from WDT_PING */ + inb_p(WDT_PING); + + /* Re-set the timer interval */ + timer.expires = jiffies + WDT_INTERVAL; + add_timer(&timer); + + spin_unlock(&wdt_spinlock); + + } else { + printk(OUR_NAME ": Heartbeat lost! Will not ping the watchdog\n"); + } +} + +/* + * Utility routines + */ + +static void wdt_change(int writeval) +{ + unsigned long flags; + spin_lock_irqsave(&wdt_spinlock, flags); + + /* buy some time */ + inb_p(WDT_PING); + + /* make W83877F available */ + outb_p(ENABLE_W83877F, ENABLE_W83877F_PORT); + outb_p(ENABLE_W83877F, ENABLE_W83877F_PORT); + + /* enable watchdog */ + outb_p(WDT_REGISTER, ENABLE_W83877F_PORT); + outb_p(writeval, ENABLE_W83877F_PORT+1); + + /* lock the W8387FF away */ + outb_p(DISABLE_W83877F, ENABLE_W83877F_PORT); + + spin_unlock_irqrestore(&wdt_spinlock, flags); +} + +static void wdt_startup(void) +{ + next_heartbeat = jiffies + WDT_HEARTBEAT; + + /* Start the timer */ + timer.expires = jiffies + WDT_INTERVAL; + add_timer(&timer); + + wdt_change(WDT_ENABLE); + + printk(OUR_NAME ": Watchdog timer is now enabled.\n"); +} + +static void wdt_turnoff(void) +{ + /* Stop the timer */ + del_timer(&timer); + + wdt_change(WDT_DISABLE); + + printk(OUR_NAME ": Watchdog timer is now disabled...\n"); +} + + +/* + * /dev/watchdog handling + */ + +static ssize_t fop_write(struct file * file, const char * buf, size_t count, loff_t * ppos) +{ + /* We can't seek */ + if(ppos != &file->f_pos) + return -ESPIPE; + + /* See if we got the magic character */ + if(count) + { + size_t ofs; + + /* note: just in case someone wrote the magic character + * five months ago... */ + wdt_expect_close = 0; + + /* now scan */ + for(ofs = 0; ofs != count; ofs++) + { + char c; + if (get_user(c, buf + ofs)) + return -EFAULT; + if (c == 'V') + wdt_expect_close = 1; + } + + /* someone wrote to us, we should restart timer */ + next_heartbeat = jiffies + WDT_HEARTBEAT; + return 1; + }; + return 0; +} + +static ssize_t fop_read(struct file * file, char * buf, size_t count, loff_t * ppos) +{ + /* No can do */ + return -EINVAL; +} + +static int fop_open(struct inode * inode, struct file * file) +{ + switch(minor(inode->i_rdev)) + { + case WATCHDOG_MINOR: + /* Just in case we're already talking to someone... */ + if(test_and_set_bit(0, &wdt_is_open)) { + return -EBUSY; + } + /* Good, fire up the show */ + wdt_startup(); + return 0; + + default: + return -ENODEV; + } +} + +static int fop_close(struct inode * inode, struct file * file) +{ + if(minor(inode->i_rdev) == WATCHDOG_MINOR) + { + if(wdt_expect_close) + wdt_turnoff(); + else { + del_timer(&timer); + printk(OUR_NAME ": device file closed unexpectedly. Will not stop the WDT!\n"); + } + } + wdt_is_open = 0; + return 0; +} + +static int fop_ioctl(struct inode *inode, struct file *file, unsigned int cmd, + unsigned long arg) +{ + static struct watchdog_info ident= + { + 0, + 1, + "W83877F" + }; + + switch(cmd) + { + default: + return -ENOIOCTLCMD; + case WDIOC_GETSUPPORT: + return copy_to_user((struct watchdog_info *)arg, &ident, sizeof(ident))?-EFAULT:0; + case WDIOC_KEEPALIVE: + next_heartbeat = jiffies + WDT_HEARTBEAT; + return 0; + } +} + +static struct file_operations wdt_fops = { + .owner = THIS_MODULE, + .llseek = no_llseek, + .read = fop_read, + .write = fop_write, + .open = fop_open, + .release = fop_close, + .ioctl = fop_ioctl +}; + +static struct miscdevice wdt_miscdev = { + WATCHDOG_MINOR, + "watchdog", + &wdt_fops +}; + +/* + * Notifier for system down + */ + +static int wdt_notify_sys(struct notifier_block *this, unsigned long code, + void *unused) +{ + if(code==SYS_DOWN || code==SYS_HALT) + wdt_turnoff(); + return NOTIFY_DONE; +} + +/* + * The WDT needs to learn about soft shutdowns in order to + * turn the timebomb registers off. + */ + +static struct notifier_block wdt_notifier= +{ + wdt_notify_sys, + 0, + 0 +}; + +static void __exit w83877f_wdt_unload(void) +{ + wdt_turnoff(); + + /* Deregister */ + misc_deregister(&wdt_miscdev); + + unregister_reboot_notifier(&wdt_notifier); + release_region(WDT_PING,1); + release_region(ENABLE_W83877F_PORT,2); +} + +static int __init w83877f_wdt_init(void) +{ + int rc = -EBUSY; + + spin_lock_init(&wdt_spinlock); + + if (!request_region(ENABLE_W83877F_PORT, 2, "W83877F WDT")) + goto err_out; + if (!request_region(WDT_PING, 1, "W8387FF WDT")) + goto err_out_region1; + + init_timer(&timer); + timer.function = wdt_timer_ping; + timer.data = 0; + + rc = misc_register(&wdt_miscdev); + if (rc) + goto err_out_region2; + + rc = register_reboot_notifier(&wdt_notifier); + if (rc) + goto err_out_miscdev; + + printk(KERN_INFO OUR_NAME ": WDT driver for W83877F initialised.\n"); + + return 0; + +err_out_miscdev: + misc_deregister(&wdt_miscdev); +err_out_region2: + release_region(WDT_PING,1); +err_out_region1: + release_region(ENABLE_W83877F_PORT,2); +err_out: + return rc; +} + +module_init(w83877f_wdt_init); +module_exit(w83877f_wdt_unload); + +MODULE_AUTHOR("Scott and Bill Jennings"); +MODULE_DESCRIPTION("Driver for watchdog timer in w83877f chip"); +MODULE_LICENSE("GPL"); +EXPORT_NO_SYMBOLS; diff -urpN --exclude-from=/home/davej/.exclude bk-linus/drivers/char/watchdog/wd501p.h move-watchdogs/drivers/char/watchdog/wd501p.h --- bk-linus/drivers/char/watchdog/wd501p.h 1969-12-31 23:00:00.000000000 -0100 +++ move-watchdogs/drivers/char/watchdog/wd501p.h 2002-11-22 10:28:58.000000000 -0100 @@ -0,0 +1,91 @@ +/* + * Industrial Computer Source WDT500/501 driver for Linux 1.3.x + * + * (c) Copyright 1995 CymruNET Ltd + * Innovation Centre + * Singleton Park + * Swansea + * Wales + * UK + * SA2 8PP + * + * http://www.cymru.net + * + * This driver is provided under the GNU General Public License, incorporated + * herein by reference. The driver is provided without warranty or + * support. + * + * Release 0.04. + * + */ + +#include + +#define WDT_COUNT0 (io+0) +#define WDT_COUNT1 (io+1) +#define WDT_COUNT2 (io+2) +#define WDT_CR (io+3) +#define WDT_SR (io+4) /* Start buzzer on PCI write */ +#define WDT_RT (io+5) /* Stop buzzer on PCI write */ +#define WDT_BUZZER (io+6) /* PCI only: rd=disable, wr=enable */ +#define WDT_DC (io+7) + +/* The following are only on the PCI card, they're outside of I/O space on + * the ISA card: */ +#define WDT_CLOCK (io+12) /* COUNT2: rd=16.67MHz, wr=2.0833MHz */ +/* inverted opto isolated reset output: */ +#define WDT_OPTONOTRST (io+13) /* wr=enable, rd=disable */ +/* opto isolated reset output: */ +#define WDT_OPTORST (io+14) /* wr=enable, rd=disable */ +/* programmable outputs: */ +#define WDT_PROGOUT (io+15) /* wr=enable, rd=disable */ + +#define WDC_SR_WCCR 1 /* Active low */ +#define WDC_SR_TGOOD 2 +#define WDC_SR_ISOI0 4 +#define WDC_SR_ISII1 8 +#define WDC_SR_FANGOOD 16 +#define WDC_SR_PSUOVER 32 /* Active low */ +#define WDC_SR_PSUUNDR 64 /* Active low */ +#define WDC_SR_IRQ 128 /* Active low */ + +#ifndef WDT_IS_PCI + +/* + * Feature Map 1 is the active high inputs not supported on your card. + * Feature Map 2 is the active low inputs not supported on your card. + */ + +#ifdef CONFIG_WDT_501 /* Full board */ + +#ifdef CONFIG_WDT501_FAN /* Full board, Fan has no tachometer */ +#define FEATUREMAP1 0 +#define WDT_OPTION_MASK (WDIOF_OVERHEAT|WDIOF_POWERUNDER|WDIOF_POWEROVER|WDIOF_EXTERN1|WDIOF_EXTERN2|WDIOF_FANFAULT) +#else +#define FEATUREMAP1 WDC_SR_FANGOOD +#define WDT_OPTION_MASK (WDIOF_OVERHEAT|WDIOF_POWERUNDER|WDIOF_POWEROVER|WDIOF_EXTERN1|WDIOF_EXTERN2) +#endif + +#define FEATUREMAP2 0 +#endif + +#ifndef CONFIG_WDT_501 +#define CONFIG_WDT_500 +#endif + +#ifdef CONFIG_WDT_500 /* Minimal board */ +#define FEATUREMAP1 (WDC_SR_TGOOD|WDC_SR_FANGOOD) +#define FEATUREMAP2 (WDC_SR_PSUOVER|WDC_SR_PSUUNDR) +#define WDT_OPTION_MASK (WDIOF_OVERHEAT) +#endif + +#else + +#define FEATUREMAP1 (WDC_SR_TGOOD|WDC_SR_FANGOOD) +#define FEATUREMAP2 (WDC_SR_PSUOVER|WDC_SR_PSUUNDR) +#define WDT_OPTION_MASK (WDIOF_OVERHEAT) +#endif + +#ifndef FEATUREMAP1 +#error "Config option not set" +#endif diff -urpN --exclude-from=/home/davej/.exclude bk-linus/drivers/char/watchdog/wdt.c move-watchdogs/drivers/char/watchdog/wdt.c --- bk-linus/drivers/char/watchdog/wdt.c 1969-12-31 23:00:00.000000000 -0100 +++ move-watchdogs/drivers/char/watchdog/wdt.c 2002-11-22 10:15:41.000000000 -0100 @@ -0,0 +1,565 @@ +/* + * Industrial Computer Source WDT500/501 driver for Linux 2.1.x + * + * (c) Copyright 1996-1997 Alan Cox , All Rights Reserved. + * http://www.redhat.com + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version + * 2 of the License, or (at your option) any later version. + * + * Neither Alan Cox nor CymruNet Ltd. admit liability nor provide + * warranty for any of this software. This material is provided + * "AS-IS" and at no charge. + * + * (c) Copyright 1995 Alan Cox + * + * Release 0.09. + * + * Fixes + * Dave Gregorich : Modularisation and minor bugs + * Alan Cox : Added the watchdog ioctl() stuff + * Alan Cox : Fixed the reboot problem (as noted by + * Matt Crocker). + * Alan Cox : Added wdt= boot option + * Alan Cox : Cleaned up copy/user stuff + * Tim Hockin : Added insmod parameters, comment cleanup + * Parameterized timeout + * Tigran Aivazian : Restructured wdt_init() to handle failures + * Matt Domsch : added nowayout and timeout module options + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "wd501p.h" +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +static unsigned long wdt_is_open; + +/* + * You must set these - there is no sane way to probe for this board. + * You can use wdt=x,y to set these now. + */ + +static int io=0x240; +static int irq=11; + +#define WD_TIMO (100*60) /* 1 minute */ + +static int timeout_val = WD_TIMO; /* value passed to card */ +static int timeout = 60; /* in seconds */ +MODULE_PARM(timeout,"i"); +MODULE_PARM_DESC(timeout, "Watchdog timeout in seconds (default=60)"); + +#ifdef CONFIG_WATCHDOG_NOWAYOUT +static int nowayout = 1; +#else +static int nowayout = 0; +#endif + +MODULE_PARM(nowayout,"i"); +MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default=CONFIG_WATCHDOG_NOWAYOUT)"); + +static void __init +wdt_validate_timeout(void) +{ + timeout_val = timeout * 100; +} + +#ifndef MODULE + +/** + * wdt_setup: + * @str: command line string + * + * Setup options. The board isn't really probe-able so we have to + * get the user to tell us the configuration. Sane people build it + * modular but the others come here. + */ + +static int __init wdt_setup(char *str) +{ + int ints[4]; + + str = get_options (str, ARRAY_SIZE(ints), ints); + + if (ints[0] > 0) + { + io = ints[1]; + if(ints[0] > 1) + irq = ints[2]; + } + + return 1; +} + +__setup("wdt=", wdt_setup); + +#endif /* !MODULE */ + +MODULE_PARM(io, "i"); +MODULE_PARM_DESC(io, "WDT io port (default=0x240)"); +MODULE_PARM(irq, "i"); +MODULE_PARM_DESC(irq, "WDT irq (default=11)"); + +/* + * Programming support + */ + +static void wdt_ctr_mode(int ctr, int mode) +{ + ctr<<=6; + ctr|=0x30; + ctr|=(mode<<1); + outb_p(ctr, WDT_CR); +} + +static void wdt_ctr_load(int ctr, int val) +{ + outb_p(val&0xFF, WDT_COUNT0+ctr); + outb_p(val>>8, WDT_COUNT0+ctr); +} + +/* + * Kernel methods. + */ + + +/** + * wdt_status: + * + * Extract the status information from a WDT watchdog device. There are + * several board variants so we have to know which bits are valid. Some + * bits default to one and some to zero in order to be maximally painful. + * + * we then map the bits onto the status ioctl flags. + */ + +static int wdt_status(void) +{ + /* + * Status register to bit flags + */ + + int flag=0; + unsigned char status=inb_p(WDT_SR); + status|=FEATUREMAP1; + status&=~FEATUREMAP2; + + if(!(status&WDC_SR_TGOOD)) + flag|=WDIOF_OVERHEAT; + if(!(status&WDC_SR_PSUOVER)) + flag|=WDIOF_POWEROVER; + if(!(status&WDC_SR_PSUUNDR)) + flag|=WDIOF_POWERUNDER; + if(!(status&WDC_SR_FANGOOD)) + flag|=WDIOF_FANFAULT; + if(status&WDC_SR_ISOI0) + flag|=WDIOF_EXTERN1; + if(status&WDC_SR_ISII1) + flag|=WDIOF_EXTERN2; + return flag; +} + +/** + * wdt_interrupt: + * @irq: Interrupt number + * @dev_id: Unused as we don't allow multiple devices. + * @regs: Unused. + * + * Handle an interrupt from the board. These are raised when the status + * map changes in what the board considers an interesting way. That means + * a failure condition occuring. + */ + +void wdt_interrupt(int irq, void *dev_id, struct pt_regs *regs) +{ + /* + * Read the status register see what is up and + * then printk it. + */ + + unsigned char status=inb_p(WDT_SR); + + status|=FEATUREMAP1; + status&=~FEATUREMAP2; + + printk(KERN_CRIT "WDT status %d\n", status); + + if(!(status&WDC_SR_TGOOD)) + printk(KERN_CRIT "Overheat alarm.(%d)\n",inb_p(WDT_RT)); + if(!(status&WDC_SR_PSUOVER)) + printk(KERN_CRIT "PSU over voltage.\n"); + if(!(status&WDC_SR_PSUUNDR)) + printk(KERN_CRIT "PSU under voltage.\n"); + if(!(status&WDC_SR_FANGOOD)) + printk(KERN_CRIT "Possible fan fault.\n"); + if(!(status&WDC_SR_WCCR)) +#ifdef SOFTWARE_REBOOT +#ifdef ONLY_TESTING + printk(KERN_CRIT "Would Reboot.\n"); +#else + printk(KERN_CRIT "Initiating system reboot.\n"); + machine_restart(NULL); +#endif +#else + printk(KERN_CRIT "Reset in 5ms.\n"); +#endif +} + + +/** + * wdt_ping: + * + * Reload counter one with the watchdog timeout. We don't bother reloading + * the cascade counter. + */ + +static void wdt_ping(void) +{ + /* Write a watchdog value */ + inb_p(WDT_DC); + wdt_ctr_mode(1,2); + wdt_ctr_load(1,timeout_val); /* Timeout */ + outb_p(0, WDT_DC); +} + +/** + * wdt_write: + * @file: file handle to the watchdog + * @buf: buffer to write (unused as data does not matter here + * @count: count of bytes + * @ppos: pointer to the position to write. No seeks allowed + * + * A write to a watchdog device is defined as a keepalive signal. Any + * write of data will do, as we we don't define content meaning. + */ + +static ssize_t wdt_write(struct file *file, const char *buf, size_t count, loff_t *ppos) +{ + /* Can't seek (pwrite) on this device */ + if (ppos != &file->f_pos) + return -ESPIPE; + + if(count) + { + wdt_ping(); + return 1; + } + return 0; +} + +/** + * wdt_read: + * @file: file handle to the watchdog board + * @buf: buffer to write 1 byte into + * @count: length of buffer + * @ptr: offset (no seek allowed) + * + * Read reports the temperature in degrees Fahrenheit. The API is in + * farenheit. It was designed by an imperial measurement luddite. + */ + +static ssize_t wdt_read(struct file *file, char *buf, size_t count, loff_t *ptr) +{ + unsigned short c=inb_p(WDT_RT); + unsigned char cp; + + /* Can't seek (pread) on this device */ + if (ptr != &file->f_pos) + return -ESPIPE; + + switch(minor(file->f_dentry->d_inode->i_rdev)) + { + case TEMP_MINOR: + c*=11; + c/=15; + cp=c+7; + if(copy_to_user(buf,&cp,1)) + return -EFAULT; + return 1; + default: + return -EINVAL; + } +} + +/** + * wdt_ioctl: + * @inode: inode of the device + * @file: file handle to the device + * @cmd: watchdog command + * @arg: argument pointer + * + * The watchdog API defines a common set of functions for all watchdogs + * according to their available features. We only actually usefully support + * querying capabilities and current status. + */ + +static int wdt_ioctl(struct inode *inode, struct file *file, unsigned int cmd, + unsigned long arg) +{ + static struct watchdog_info ident= + { + WDIOF_OVERHEAT|WDIOF_POWERUNDER|WDIOF_POWEROVER + |WDIOF_EXTERN1|WDIOF_EXTERN2|WDIOF_FANFAULT, + 1, + "WDT500/501" + }; + + ident.options&=WDT_OPTION_MASK; /* Mask down to the card we have */ + switch(cmd) + { + default: + return -ENOTTY; + case WDIOC_GETSUPPORT: + return copy_to_user((struct watchdog_info *)arg, &ident, sizeof(ident))?-EFAULT:0; + + case WDIOC_GETSTATUS: + return put_user(wdt_status(),(int *)arg); + case WDIOC_GETBOOTSTATUS: + return put_user(0, (int *)arg); + case WDIOC_KEEPALIVE: + wdt_ping(); + return 0; + } +} + +/** + * wdt_open: + * @inode: inode of device + * @file: file handle to device + * + * One of our two misc devices has been opened. The watchdog device is + * single open and on opening we load the counters. Counter zero is a + * 100Hz cascade, into counter 1 which downcounts to reboot. When the + * counter triggers counter 2 downcounts the length of the reset pulse + * which set set to be as long as possible. + */ + +static int wdt_open(struct inode *inode, struct file *file) +{ + switch(minor(inode->i_rdev)) + { + case WATCHDOG_MINOR: + if(test_and_set_bit(0, &wdt_is_open)) + return -EBUSY; + if (nowayout) { + MOD_INC_USE_COUNT; + } + /* + * Activate + */ + + inb_p(WDT_DC); /* Disable */ + wdt_ctr_mode(0,3); + wdt_ctr_mode(1,2); + wdt_ctr_mode(2,0); + wdt_ctr_load(0, 8948); /* count at 100Hz */ + wdt_ctr_load(1,timeout_val); /* Timeout */ + wdt_ctr_load(2,65535); + outb_p(0, WDT_DC); /* Enable */ + return 0; + case TEMP_MINOR: + return 0; + default: + return -ENODEV; + } +} + +/** + * wdt_close: + * @inode: inode to board + * @file: file handle to board + * + * The watchdog has a configurable API. There is a religious dispute + * between people who want their watchdog to be able to shut down and + * those who want to be sure if the watchdog manager dies the machine + * reboots. In the former case we disable the counters, in the latter + * case you have to open it again very soon. + */ + +static int wdt_release(struct inode *inode, struct file *file) +{ + if(minor(inode->i_rdev)==WATCHDOG_MINOR) + { + if (!nowayout) { + inb_p(WDT_DC); /* Disable counters */ + wdt_ctr_load(2,0); /* 0 length reset pulses now */ + } + clear_bit(0, &wdt_is_open); + } + return 0; +} + +/** + * notify_sys: + * @this: our notifier block + * @code: the event being reported + * @unused: unused + * + * Our notifier is called on system shutdowns. We want to turn the card + * off at reboot otherwise the machine will reboot again during memory + * test or worse yet during the following fsck. This would suck, in fact + * trust me - if it happens it does suck. + */ + +static int wdt_notify_sys(struct notifier_block *this, unsigned long code, + void *unused) +{ + if(code==SYS_DOWN || code==SYS_HALT) + { + /* Turn the card off */ + inb_p(WDT_DC); + wdt_ctr_load(2,0); + } + return NOTIFY_DONE; +} + +/* + * Kernel Interfaces + */ + + +static struct file_operations wdt_fops = { + .owner = THIS_MODULE, + .llseek = no_llseek, + .read = wdt_read, + .write = wdt_write, + .ioctl = wdt_ioctl, + .open = wdt_open, + .release = wdt_release, +}; + +static struct miscdevice wdt_miscdev= +{ + WATCHDOG_MINOR, + "watchdog", + &wdt_fops +}; + +#ifdef CONFIG_WDT_501 +static struct miscdevice temp_miscdev= +{ + TEMP_MINOR, + "temperature", + &wdt_fops +}; +#endif + +/* + * The WDT card needs to learn about soft shutdowns in order to + * turn the timebomb registers off. + */ + +static struct notifier_block wdt_notifier= +{ + wdt_notify_sys, + NULL, + 0 +}; + +/** + * cleanup_module: + * + * Unload the watchdog. You cannot do this with any file handles open. + * If your watchdog is set to continue ticking on close and you unload + * it, well it keeps ticking. We won't get the interrupt but the board + * will not touch PC memory so all is fine. You just have to load a new + * module in 60 seconds or reboot. + */ + +static void __exit wdt_exit(void) +{ + misc_deregister(&wdt_miscdev); +#ifdef CONFIG_WDT_501 + misc_deregister(&temp_miscdev); +#endif + unregister_reboot_notifier(&wdt_notifier); + release_region(io,8); + free_irq(irq, NULL); +} + +/** + * wdt_init: + * + * Set up the WDT watchdog board. All we have to do is grab the + * resources we require and bitch if anyone beat us to them. + * The open() function will actually kick the board off. + */ + +static int __init wdt_init(void) +{ + int ret; + + wdt_validate_timeout(); + ret = misc_register(&wdt_miscdev); + if (ret) { + printk(KERN_ERR "wdt: can't misc_register on minor=%d\n", WATCHDOG_MINOR); + goto out; + } + ret = request_irq(irq, wdt_interrupt, SA_INTERRUPT, "wdt501p", NULL); + if(ret) { + printk(KERN_ERR "wdt: IRQ %d is not free.\n", irq); + goto outmisc; + } + if (!request_region(io, 8, "wdt501p")) { + printk(KERN_ERR "wdt: IO %X is not free.\n", io); + ret = -EBUSY; + goto outirq; + } + ret = register_reboot_notifier(&wdt_notifier); + if(ret) { + printk(KERN_ERR "wdt: can't register reboot notifier (err=%d)\n", ret); + goto outreg; + } + +#ifdef CONFIG_WDT_501 + ret = misc_register(&temp_miscdev); + if (ret) { + printk(KERN_ERR "wdt: can't misc_register (temp) on minor=%d\n", TEMP_MINOR); + goto outrbt; + } +#endif + + ret = 0; + printk(KERN_INFO "WDT500/501-P driver 0.07 at %X (Interrupt %d)\n", io, irq); +out: + return ret; + +#ifdef CONFIG_WDT_501 +outrbt: + unregister_reboot_notifier(&wdt_notifier); +#endif + +outreg: + release_region(io,8); +outirq: + free_irq(irq, NULL); +outmisc: + misc_deregister(&wdt_miscdev); + goto out; +} + +module_init(wdt_init); +module_exit(wdt_exit); + +MODULE_AUTHOR("Alan Cox"); +MODULE_DESCRIPTION("Driver for ISA ICS watchdog cards (WDT500/501)"); +MODULE_LICENSE("GPL"); diff -urpN --exclude-from=/home/davej/.exclude bk-linus/drivers/char/watchdog/wdt285.c move-watchdogs/drivers/char/watchdog/wdt285.c --- bk-linus/drivers/char/watchdog/wdt285.c 1969-12-31 23:00:00.000000000 -0100 +++ move-watchdogs/drivers/char/watchdog/wdt285.c 2002-11-22 10:15:41.000000000 -0100 @@ -0,0 +1,193 @@ +/* + * Intel 21285 watchdog driver + * Copyright (c) Phil Blundell , 1998 + * + * based on + * + * SoftDog 0.05: A Software Watchdog Device + * + * (c) Copyright 1996 Alan Cox , All Rights Reserved. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version + * 2 of the License, or (at your option) any later version. + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +/* + * Define this to stop the watchdog actually rebooting the machine. + */ +#undef ONLY_TESTING + +#define TIMER_MARGIN 60 /* (secs) Default is 1 minute */ + +#define FCLK (50*1000*1000) /* 50MHz */ + +static int soft_margin = TIMER_MARGIN; /* in seconds */ +static int timer_alive; + +#ifdef ONLY_TESTING +/* + * If the timer expires.. + */ + +static void watchdog_fire(int irq, void *dev_id, struct pt_regs *regs) +{ + printk(KERN_CRIT "Watchdog: Would Reboot.\n"); + *CSR_TIMER4_CNTL = 0; + *CSR_TIMER4_CLR = 0; +} +#endif + +static void watchdog_ping(void) +{ + /* + * Refresh the timer. + */ + *CSR_TIMER4_LOAD = soft_margin * (FCLK / 256); +} + +/* + * Allow only one person to hold it open + */ + +static int watchdog_open(struct inode *inode, struct file *file) +{ + if(timer_alive) + return -EBUSY; + /* + * Ahead watchdog factor ten, Mr Sulu + */ + *CSR_TIMER4_CLR = 0; + watchdog_ping(); + *CSR_TIMER4_CNTL = TIMER_CNTL_ENABLE | TIMER_CNTL_AUTORELOAD + | TIMER_CNTL_DIV256; +#ifdef ONLY_TESTING + request_irq(IRQ_TIMER4, watchdog_fire, 0, "watchdog", NULL); +#else + *CSR_SA110_CNTL |= 1 << 13; + MOD_INC_USE_COUNT; +#endif + timer_alive = 1; + return 0; +} + +static int watchdog_release(struct inode *inode, struct file *file) +{ +#ifdef ONLY_TESTING + free_irq(IRQ_TIMER4, NULL); + timer_alive = 0; +#else + /* + * It's irreversible! + */ +#endif + return 0; +} + +static ssize_t watchdog_write(struct file *file, const char *data, size_t len, loff_t *ppos) +{ + /* Can't seek (pwrite) on this device */ + if (ppos != &file->f_pos) + return -ESPIPE; + + /* + * Refresh the timer. + */ + if(len) + { + watchdog_ping(); + return 1; + } + return 0; +} + +static int watchdog_ioctl(struct inode *inode, struct file *file, + unsigned int cmd, unsigned long arg) +{ + int i; + static struct watchdog_info ident= + { + 0, + 0, + "Footbridge Watchdog" + }; + switch(cmd) + { + default: + return -ENOTTY; + case WDIOC_GETSUPPORT: + if(copy_to_user((struct watchdog_info *)arg, &ident, sizeof(ident))) + return -EFAULT; + return 0; + case WDIOC_GETSTATUS: + case WDIOC_GETBOOTSTATUS: + return put_user(0,(int *)arg); + case WDIOC_KEEPALIVE: + watchdog_ping(); + return 0; + } +} + +static struct file_operations watchdog_fops= +{ + .owner = THIS_MODULE, + .write = watchdog_write, + .ioctl = watchdog_ioctl, + .open = watchdog_open, + .release = watchdog_release, +}; + +static struct miscdevice watchdog_miscdev= +{ + WATCHDOG_MINOR, + "watchdog", + &watchdog_fops +}; + +static int __init footbridge_watchdog_init(void) +{ + if (machine_is_netwinder()) + return -ENODEV; + + misc_register(&watchdog_miscdev); + printk("Footbridge Watchdog Timer: 0.01, timer margin: %d sec\n", + soft_margin); + if (machine_is_cats()) + printk("Warning: Watchdog reset may not work on this machine.\n"); + return 0; +} + +static void __exit footbridge_watchdog_exit(void) +{ + misc_deregister(&watchdog_miscdev); +} + +MODULE_AUTHOR("Phil Blundell "); +MODULE_DESCRIPTION("21285 watchdog driver"); +MODULE_LICENSE("GPL"); + +MODULE_PARM(soft_margin,"i"); +MODULE_PARM_DESC(soft_margin,"Watchdog timeout in seconds"); + +module_init(footbridge_watchdog_init); +module_exit(footbridge_watchdog_exit); diff -urpN --exclude-from=/home/davej/.exclude bk-linus/drivers/char/watchdog/wdt977.c move-watchdogs/drivers/char/watchdog/wdt977.c --- bk-linus/drivers/char/watchdog/wdt977.c 1969-12-31 23:00:00.000000000 -0100 +++ move-watchdogs/drivers/char/watchdog/wdt977.c 2002-11-22 10:15:41.000000000 -0100 @@ -0,0 +1,346 @@ +/* + * Wdt977 0.02: A Watchdog Device for Netwinder W83977AF chip + * + * (c) Copyright 1998 Rebel.com (Woody Suwalski ) + * + * ----------------------- + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version + * 2 of the License, or (at your option) any later version. + * + * ----------------------- + * 14-Dec-2001 Matt Domsch + * Added nowayout module option to override CONFIG_WATCHDOG_NOWAYOUT + * 19-Dec-2001 Woody Suwalski: Netwinder fixes, ioctl interface + * 06-Jan-2002 Woody Suwalski: For compatibility, convert all timeouts + * from minutes to seconds. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#define WATCHDOG_MINOR 130 + +#define DEFAULT_TIMEOUT 1 /* default timeout = 1 minute */ + +static int timeout = DEFAULT_TIMEOUT*60; /* TO in seconds from user */ +static int timeoutM = DEFAULT_TIMEOUT; /* timeout in minutes */ +static unsigned long timer_alive; +static int testmode; + +MODULE_PARM(timeout, "i"); +MODULE_PARM_DESC(timeout,"Watchdog timeout in seconds (60..15300), default=60"); +MODULE_PARM(testmode, "i"); +MODULE_PARM_DESC(testmode,"Watchdog testmode (1 = no reboot), default=0"); + +#ifdef CONFIG_WATCHDOG_NOWAYOUT +static int nowayout = 1; +#else +static int nowayout = 0; +#endif + +MODULE_PARM(nowayout,"i"); +MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default=CONFIG_WATCHDOG_NOWAYOUT)"); + + +/* This is kicking the watchdog by simply re-writing the timeout to reg. 0xF2 */ +int kick_wdog(void) +{ + /* + * Refresh the timer. + */ + + /* unlock the SuperIO chip */ + outb(0x87,0x370); + outb(0x87,0x370); + + /* select device Aux2 (device=8) and kicks watchdog reg F2 */ + /* F2 has the timeout in minutes */ + + outb(0x07,0x370); + outb(0x08,0x371); + outb(0xF2,0x370); + outb(timeoutM,0x371); + + /* lock the SuperIO chip */ + outb(0xAA,0x370); + + return 0; +} + + +/* + * Allow only one person to hold it open + */ + +static int wdt977_open(struct inode *inode, struct file *file) +{ + + if( test_and_set_bit(0,&timer_alive) ) + return -EBUSY; + + /* convert seconds to minutes, rounding up */ + timeoutM = timeout + 59; + timeoutM /= 60; + + if (nowayout) + { + MOD_INC_USE_COUNT; + + /* do not permit disabling the watchdog by writing 0 to reg. 0xF2 */ + if (!timeoutM) timeoutM = DEFAULT_TIMEOUT; + } + + if (machine_is_netwinder()) + { + /* we have a hw bug somewhere, so each 977 minute is actually only 30sec + * this limits the max timeout to half of device max of 255 minutes... + */ + timeoutM += timeoutM; + } + + /* max timeout value = 255 minutes (0xFF). Write 0 to disable WatchDog. */ + if (timeoutM > 255) timeoutM = 255; + + /* convert seconds to minutes */ + printk(KERN_INFO "Wdt977 Watchdog activated: timeout = %d sec, nowayout = %i, testmode = %i.\n", + machine_is_netwinder() ? (timeoutM>>1)*60 : timeoutM*60, + nowayout, testmode); + + /* unlock the SuperIO chip */ + outb(0x87,0x370); + outb(0x87,0x370); + + /* select device Aux2 (device=8) and set watchdog regs F2, F3 and F4 + * F2 has the timeout in minutes + * F3 could be set to the POWER LED blink (with GP17 set to PowerLed) + * at timeout, and to reset timer on kbd/mouse activity (not impl.) + * F4 is used to just clear the TIMEOUT'ed state (bit 0) + */ + outb(0x07,0x370); + outb(0x08,0x371); + outb(0xF2,0x370); + outb(timeoutM,0x371); + outb(0xF3,0x370); + outb(0x00,0x371); /* another setting is 0E for kbd/mouse/LED */ + outb(0xF4,0x370); + outb(0x00,0x371); + + /* at last select device Aux1 (dev=7) and set GP16 as a watchdog output */ + /* in test mode watch the bit 1 on F4 to indicate "triggered" */ + if (!testmode) + { + outb(0x07,0x370); + outb(0x07,0x371); + outb(0xE6,0x370); + outb(0x08,0x371); + } + + /* lock the SuperIO chip */ + outb(0xAA,0x370); + + return 0; +} + +static int wdt977_release(struct inode *inode, struct file *file) +{ + /* + * Shut off the timer. + * Lock it in if it's a module and we set nowayout + */ + if (!nowayout) + { + /* unlock the SuperIO chip */ + outb(0x87,0x370); + outb(0x87,0x370); + + /* select device Aux2 (device=8) and set watchdog regs F2,F3 and F4 + * F3 is reset to its default state + * F4 can clear the TIMEOUT'ed state (bit 0) - back to default + * We can not use GP17 as a PowerLed, as we use its usage as a RedLed + */ + outb(0x07,0x370); + outb(0x08,0x371); + outb(0xF2,0x370); + outb(0xFF,0x371); + outb(0xF3,0x370); + outb(0x00,0x371); + outb(0xF4,0x370); + outb(0x00,0x371); + outb(0xF2,0x370); + outb(0x00,0x371); + + /* at last select device Aux1 (dev=7) and set GP16 as a watchdog output */ + outb(0x07,0x370); + outb(0x07,0x371); + outb(0xE6,0x370); + outb(0x08,0x371); + + /* lock the SuperIO chip */ + outb(0xAA,0x370); + + clear_bit(0,&timer_alive); + + printk(KERN_INFO "Wdt977 Watchdog: shutdown\n"); + } + return 0; +} + + +/* + * wdt977_write: + * @file: file handle to the watchdog + * @buf: buffer to write (unused as data does not matter here + * @count: count of bytes + * @ppos: pointer to the position to write. No seeks allowed + * + * A write to a watchdog device is defined as a keepalive signal. Any + * write of data will do, as we we don't define content meaning. + */ + +static ssize_t wdt977_write(struct file *file, const char *buf, size_t count, loff_t *ppos) +{ + /* Can't seek (pwrite) on this device */ + if (ppos != &file->f_pos) + return -ESPIPE; + + if(count) + { + kick_wdog(); + return 1; + } + return 0; +} + +/* + * wdt977_ioctl: + * @inode: inode of the device + * @file: file handle to the device + * @cmd: watchdog command + * @arg: argument pointer + * + * The watchdog API defines a common set of functions for all watchdogs + * according to their available features. + */ + +static int wdt977_ioctl(struct inode *inode, struct file *file, + unsigned int cmd, unsigned long arg) +{ +static struct watchdog_info ident = { + identity : "Winbond 83977" +}; + +int temp; + + switch(cmd) + { + default: + return -ENOTTY; + + case WDIOC_GETSUPPORT: + return copy_to_user((struct watchdog_info *)arg, &ident, + sizeof(ident)) ? -EFAULT : 0; + + case WDIOC_GETBOOTSTATUS: + return put_user(0, (int *) arg); + + case WDIOC_GETSTATUS: + /* unlock the SuperIO chip */ + outb(0x87,0x370); + outb(0x87,0x370); + + /* select device Aux2 (device=8) and read watchdog reg F4 */ + outb(0x07,0x370); + outb(0x08,0x371); + outb(0xF4,0x370); + temp = inb(0x371); + + /* lock the SuperIO chip */ + outb(0xAA,0x370); + + /* return info if "expired" in test mode */ + return put_user(temp & 1, (int *) arg); + + case WDIOC_KEEPALIVE: + kick_wdog(); + return 0; + + case WDIOC_SETTIMEOUT: + if (copy_from_user(&temp, (int *) arg, sizeof(int))) + return -EFAULT; + + /* convert seconds to minutes, rounding up */ + temp += 59; + temp /= 60; + + /* we have a hw bug somewhere, so each 977 minute is actually only 30sec + * this limits the max timeout to half of device max of 255 minutes... + */ + if (machine_is_netwinder()) + { + temp += temp; + } + + /* Sanity check */ + if (temp < 0 || temp > 255) + return -EINVAL; + + if (!temp && nowayout) + return -EINVAL; + + timeoutM = temp; + kick_wdog(); + return 0; + } +} + + +static struct file_operations wdt977_fops= +{ + .owner = THIS_MODULE, + .write = wdt977_write, + .ioctl = wdt977_ioctl, + .open = wdt977_open, + .release = wdt977_release, +}; + +static struct miscdevice wdt977_miscdev= +{ + WATCHDOG_MINOR, + "watchdog", + &wdt977_fops +}; + +static int __init nwwatchdog_init(void) +{ + if (!machine_is_netwinder()) + return -ENODEV; + + misc_register(&wdt977_miscdev); + printk(KERN_INFO "Wdt977 Watchdog sleeping.\n"); + return 0; +} + +static void __exit nwwatchdog_exit(void) +{ + misc_deregister(&wdt977_miscdev); +} + +module_init(nwwatchdog_init); +module_exit(nwwatchdog_exit); + +MODULE_LICENSE("GPL"); diff -urpN --exclude-from=/home/davej/.exclude bk-linus/drivers/char/watchdog/wdt_pci.c move-watchdogs/drivers/char/watchdog/wdt_pci.c --- bk-linus/drivers/char/watchdog/wdt_pci.c 1969-12-31 23:00:00.000000000 -0100 +++ move-watchdogs/drivers/char/watchdog/wdt_pci.c 2002-11-22 10:15:41.000000000 -0100 @@ -0,0 +1,653 @@ +/* + * Industrial Computer Source WDT500/501 driver for Linux 2.1.x + * + * (c) Copyright 1996-1997 Alan Cox , All Rights Reserved. + * http://www.redhat.com + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version + * 2 of the License, or (at your option) any later version. + * + * Neither Alan Cox nor CymruNet Ltd. admit liability nor provide + * warranty for any of this software. This material is provided + * "AS-IS" and at no charge. + * + * (c) Copyright 1995 Alan Cox + * + * Release 0.09. + * + * Fixes + * Dave Gregorich : Modularisation and minor bugs + * Alan Cox : Added the watchdog ioctl() stuff + * Alan Cox : Fixed the reboot problem (as noted by + * Matt Crocker). + * Alan Cox : Added wdt= boot option + * Alan Cox : Cleaned up copy/user stuff + * Tim Hockin : Added insmod parameters, comment cleanup + * Parameterized timeout + * JP Nollmann : Added support for PCI wdt501p + * Alan Cox : Split ISA and PCI cards into two drivers + * Jeff Garzik : PCI cleanups + * Tigran Aivazian : Restructured wdtpci_init_one() to handle failures + * Matt Domsch : added nowayout and timeout module options + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#define WDT_IS_PCI +#include "wd501p.h" + +#define PFX "wdt_pci: " + +/* + * Until Access I/O gets their application for a PCI vendor ID approved, + * I don't think that it's appropriate to move these constants into the + * regular pci_ids.h file. -- JPN 2000/01/18 + */ + +#ifndef PCI_VENDOR_ID_ACCESSIO +#define PCI_VENDOR_ID_ACCESSIO 0x494f +#endif +#ifndef PCI_DEVICE_ID_WDG_CSM +#define PCI_DEVICE_ID_WDG_CSM 0x22c0 +#endif + +static unsigned long wdt_is_open; + +/* + * You must set these - there is no sane way to probe for this board. + * You can use wdt=x,y to set these now. + */ + +static int io=0x240; +static int irq=11; + +#define WD_TIMO (100*60) /* 1 minute */ + +static int timeout_val = WD_TIMO; /* value passed to card */ +static int timeout = 60; /* in seconds */ +MODULE_PARM(timeout,"i"); +MODULE_PARM_DESC(timeout, "Watchdog timeout in seconds (default=60)"); + +#ifdef CONFIG_WATCHDOG_NOWAYOUT +static int nowayout = 1; +#else +static int nowayout = 0; +#endif + +MODULE_PARM(nowayout,"i"); +MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default=CONFIG_WATCHDOG_NOWAYOUT)"); + +static void __init +wdtpci_validate_timeout(void) +{ + timeout_val = timeout * 100; +} + +#ifndef MODULE + +/** + * wdtpci_setup: + * @str: command line string + * + * Setup options. The board isn't really probe-able so we have to + * get the user to tell us the configuration. Sane people build it + * modular but the others come here. + */ + +static int __init wdtpci_setup(char *str) +{ + int ints[4]; + + str = get_options (str, ARRAY_SIZE(ints), ints); + + if (ints[0] > 0) + { + io = ints[1]; + if(ints[0] > 1) + irq = ints[2]; + } + + return 1; +} + +__setup("wdt=", wdtpci_setup); + +#endif /* !MODULE */ + +/* + * Programming support + */ + +static void wdtpci_ctr_mode(int ctr, int mode) +{ + ctr<<=6; + ctr|=0x30; + ctr|=(mode<<1); + outb_p(ctr, WDT_CR); +} + +static void wdtpci_ctr_load(int ctr, int val) +{ + outb_p(val&0xFF, WDT_COUNT0+ctr); + outb_p(val>>8, WDT_COUNT0+ctr); +} + +/* + * Kernel methods. + */ + + +/** + * wdtpci_status: + * + * Extract the status information from a WDT watchdog device. There are + * several board variants so we have to know which bits are valid. Some + * bits default to one and some to zero in order to be maximally painful. + * + * we then map the bits onto the status ioctl flags. + */ + +static int wdtpci_status(void) +{ + /* + * Status register to bit flags + */ + + int flag=0; + unsigned char status=inb_p(WDT_SR); + status|=FEATUREMAP1; + status&=~FEATUREMAP2; + + if(!(status&WDC_SR_TGOOD)) + flag|=WDIOF_OVERHEAT; + if(!(status&WDC_SR_PSUOVER)) + flag|=WDIOF_POWEROVER; + if(!(status&WDC_SR_PSUUNDR)) + flag|=WDIOF_POWERUNDER; + if(!(status&WDC_SR_FANGOOD)) + flag|=WDIOF_FANFAULT; + if(status&WDC_SR_ISOI0) + flag|=WDIOF_EXTERN1; + if(status&WDC_SR_ISII1) + flag|=WDIOF_EXTERN2; + return flag; +} + +/** + * wdtpci_interrupt: + * @irq: Interrupt number + * @dev_id: Unused as we don't allow multiple devices. + * @regs: Unused. + * + * Handle an interrupt from the board. These are raised when the status + * map changes in what the board considers an interesting way. That means + * a failure condition occuring. + */ + +static void wdtpci_interrupt(int irq, void *dev_id, struct pt_regs *regs) +{ + /* + * Read the status register see what is up and + * then printk it. + */ + + unsigned char status=inb_p(WDT_SR); + + status|=FEATUREMAP1; + status&=~FEATUREMAP2; + + printk(KERN_CRIT "WDT status %d\n", status); + + if(!(status&WDC_SR_TGOOD)) + printk(KERN_CRIT "Overheat alarm.(%d)\n",inb_p(WDT_RT)); + if(!(status&WDC_SR_PSUOVER)) + printk(KERN_CRIT "PSU over voltage.\n"); + if(!(status&WDC_SR_PSUUNDR)) + printk(KERN_CRIT "PSU under voltage.\n"); + if(!(status&WDC_SR_FANGOOD)) + printk(KERN_CRIT "Possible fan fault.\n"); + if(!(status&WDC_SR_WCCR)) +#ifdef SOFTWARE_REBOOT +#ifdef ONLY_TESTING + printk(KERN_CRIT "Would Reboot.\n"); +#else + printk(KERN_CRIT "Initiating system reboot.\n"); + machine_restart(NULL); +#endif +#else + printk(KERN_CRIT "Reset in 5ms.\n"); +#endif +} + + +/** + * wdtpci_ping: + * + * Reload counter one with the watchdog timeout. We don't bother reloading + * the cascade counter. + */ + +static void wdtpci_ping(void) +{ + /* Write a watchdog value */ + inb_p(WDT_DC); + wdtpci_ctr_mode(1,2); + wdtpci_ctr_load(1,timeout_val); /* Timeout */ + outb_p(0, WDT_DC); +} + +/** + * wdtpci_write: + * @file: file handle to the watchdog + * @buf: buffer to write (unused as data does not matter here + * @count: count of bytes + * @ppos: pointer to the position to write. No seeks allowed + * + * A write to a watchdog device is defined as a keepalive signal. Any + * write of data will do, as we we don't define content meaning. + */ + +static ssize_t wdtpci_write(struct file *file, const char *buf, size_t count, loff_t *ppos) +{ + /* Can't seek (pwrite) on this device */ + if (ppos != &file->f_pos) + return -ESPIPE; + + if(count) + { + wdtpci_ping(); + return 1; + } + return 0; +} + +/** + * wdtpci_read: + * @file: file handle to the watchdog board + * @buf: buffer to write 1 byte into + * @count: length of buffer + * @ptr: offset (no seek allowed) + * + * Read reports the temperature in degrees Fahrenheit. The API is in + * fahrenheit. It was designed by an imperial measurement luddite. + */ + +static ssize_t wdtpci_read(struct file *file, char *buf, size_t count, loff_t *ptr) +{ + unsigned short c=inb_p(WDT_RT); + unsigned char cp; + + /* Can't seek (pread) on this device */ + if (ptr != &file->f_pos) + return -ESPIPE; + + switch(minor(file->f_dentry->d_inode->i_rdev)) + { + case TEMP_MINOR: + c*=11; + c/=15; + cp=c+7; + if(copy_to_user(buf,&cp,1)) + return -EFAULT; + return 1; + default: + return -EINVAL; + } +} + +/** + * wdtpci_ioctl: + * @inode: inode of the device + * @file: file handle to the device + * @cmd: watchdog command + * @arg: argument pointer + * + * The watchdog API defines a common set of functions for all watchdogs + * according to their available features. We only actually usefully support + * querying capabilities and current status. + */ + +static int wdtpci_ioctl(struct inode *inode, struct file *file, unsigned int cmd, + unsigned long arg) +{ + static struct watchdog_info ident = { + .options = WDIOF_OVERHEAT | WDIOF_POWERUNDER | + WDIOF_POWEROVER | WDIOF_EXTERN1 | + WDIOF_EXTERN2 | WDIOF_FANFAULT, + .firmware_version = 1, + .identity = "WDT500/501PCI", + }; + + ident.options&=WDT_OPTION_MASK; /* Mask down to the card we have */ + switch(cmd) + { + default: + return -ENOTTY; + case WDIOC_GETSUPPORT: + return copy_to_user((struct watchdog_info *)arg, &ident, sizeof(ident))?-EFAULT:0; + + case WDIOC_GETSTATUS: + return put_user(wdtpci_status(),(int *)arg); + case WDIOC_GETBOOTSTATUS: + return put_user(0, (int *)arg); + case WDIOC_KEEPALIVE: + wdtpci_ping(); + return 0; + } +} + +/** + * wdtpci_open: + * @inode: inode of device + * @file: file handle to device + * + * One of our two misc devices has been opened. The watchdog device is + * single open and on opening we load the counters. Counter zero is a + * 100Hz cascade, into counter 1 which downcounts to reboot. When the + * counter triggers counter 2 downcounts the length of the reset pulse + * which set set to be as long as possible. + */ + +static int wdtpci_open(struct inode *inode, struct file *file) +{ + switch(minor(inode->i_rdev)) + { + case WATCHDOG_MINOR: + if( test_and_set_bit(0,&wdt_is_open) ) + { + return -EBUSY; + } + if (nowayout) { + MOD_INC_USE_COUNT; + } + /* + * Activate + */ + + inb_p(WDT_DC); /* Disable */ + + /* + * "pet" the watchdog, as Access says. + * This resets the clock outputs. + */ + + wdtpci_ctr_mode(2,0); + outb_p(0, WDT_DC); + + inb_p(WDT_DC); + + outb_p(0, WDT_CLOCK); /* 2.0833MHz clock */ + inb_p(WDT_BUZZER); /* disable */ + inb_p(WDT_OPTONOTRST); /* disable */ + inb_p(WDT_OPTORST); /* disable */ + inb_p(WDT_PROGOUT); /* disable */ + wdtpci_ctr_mode(0,3); + wdtpci_ctr_mode(1,2); + wdtpci_ctr_mode(2,1); + wdtpci_ctr_load(0,20833); /* count at 100Hz */ + wdtpci_ctr_load(1,timeout_val); /* Timeout */ + /* DO NOT LOAD CTR2 on PCI card! -- JPN */ + outb_p(0, WDT_DC); /* Enable */ + return 0; + case TEMP_MINOR: + return 0; + default: + return -ENODEV; + } +} + +/** + * wdtpci_close: + * @inode: inode to board + * @file: file handle to board + * + * The watchdog has a configurable API. There is a religious dispute + * between people who want their watchdog to be able to shut down and + * those who want to be sure if the watchdog manager dies the machine + * reboots. In the former case we disable the counters, in the latter + * case you have to open it again very soon. + */ + +static int wdtpci_release(struct inode *inode, struct file *file) +{ + if(minor(inode->i_rdev)==WATCHDOG_MINOR) + { + if (!nowayout) { + inb_p(WDT_DC); /* Disable counters */ + wdtpci_ctr_load(2,0); /* 0 length reset pulses now */ + } + clear_bit(0, &wdt_is_open ); + } + return 0; +} + +/** + * notify_sys: + * @this: our notifier block + * @code: the event being reported + * @unused: unused + * + * Our notifier is called on system shutdowns. We want to turn the card + * off at reboot otherwise the machine will reboot again during memory + * test or worse yet during the following fsck. This would suck, in fact + * trust me - if it happens it does suck. + */ + +static int wdtpci_notify_sys(struct notifier_block *this, unsigned long code, + void *unused) +{ + if(code==SYS_DOWN || code==SYS_HALT) + { + /* Turn the card off */ + inb_p(WDT_DC); + wdtpci_ctr_load(2,0); + } + return NOTIFY_DONE; +} + +/* + * Kernel Interfaces + */ + + +static struct file_operations wdtpci_fops = { + .owner = THIS_MODULE, + .llseek = no_llseek, + .read = wdtpci_read, + .write = wdtpci_write, + .ioctl = wdtpci_ioctl, + .open = wdtpci_open, + .release = wdtpci_release, +}; + +static struct miscdevice wdtpci_miscdev = { + .minor = WATCHDOG_MINOR, + .name = "watchdog", + .fops = &wdtpci_fops, +}; + +#ifdef CONFIG_WDT_501 +static struct miscdevice temp_miscdev = { + .minor = TEMP_MINOR, + .name = "temperature", + .fops = &wdtpci_fops, +}; +#endif + +/* + * The WDT card needs to learn about soft shutdowns in order to + * turn the timebomb registers off. + */ + +static struct notifier_block wdtpci_notifier = { + .notifier_call = wdtpci_notify_sys, +}; + + +static int __init wdtpci_init_one (struct pci_dev *dev, + const struct pci_device_id *ent) +{ + static int dev_count = 0; + int ret = -EIO; + + dev_count++; + if (dev_count > 1) { + printk (KERN_ERR PFX + "this driver only supports 1 device\n"); + return -ENODEV; + } + + if (pci_enable_device (dev)) + goto out; + + irq = dev->irq; + io = pci_resource_start (dev, 2); + printk ("WDT501-P(PCI-WDG-CSM) driver 0.07 at %X " + "(Interrupt %d)\n", io, irq); + + if (request_region (io, 16, "wdt-pci") == NULL) { + printk (KERN_ERR PFX "I/O %d is not free.\n", io); + goto out; + } + + if (request_irq (irq, wdtpci_interrupt, SA_INTERRUPT | SA_SHIRQ, + "wdt-pci", &wdtpci_miscdev)) { + printk (KERN_ERR PFX "IRQ %d is not free.\n", irq); + goto out_reg; + } + + ret = misc_register (&wdtpci_miscdev); + if (ret) { + printk (KERN_ERR PFX "can't misc_register on minor=%d\n", WATCHDOG_MINOR); + goto out_irq; + } + + ret = register_reboot_notifier (&wdtpci_notifier); + if (ret) { + printk (KERN_ERR PFX "can't misc_register on minor=%d\n", WATCHDOG_MINOR); + goto out_misc; + } +#ifdef CONFIG_WDT_501 + ret = misc_register (&temp_miscdev); + if (ret) { + printk (KERN_ERR PFX "can't misc_register (temp) on minor=%d\n", TEMP_MINOR); + goto out_rbt; + } +#endif + + ret = 0; +out: + return ret; + +#ifdef CONFIG_WDT_501 +out_rbt: + unregister_reboot_notifier(&wdtpci_notifier); +#endif +out_misc: + misc_deregister(&wdtpci_miscdev); +out_irq: + free_irq(irq, &wdtpci_miscdev); +out_reg: + release_region (io, 16); + goto out; +} + + +static void __devexit wdtpci_remove_one (struct pci_dev *pdev) +{ + /* here we assume only one device will ever have + * been picked up and registered by probe function */ + unregister_reboot_notifier(&wdtpci_notifier); +#ifdef CONFIG_WDT_501_PCI + misc_deregister(&temp_miscdev); +#endif + misc_deregister(&wdtpci_miscdev); + free_irq(irq, &wdtpci_miscdev); + release_region(io, 16); +} + + +static struct pci_device_id wdtpci_pci_tbl[] __initdata = { + { + .vendor = PCI_VENDOR_ID_ACCESSIO, + .device = PCI_DEVICE_ID_WDG_CSM, + .subvendor = PCI_ANY_ID, + .subdevice = PCI_ANY_ID, + }, + { 0, }, /* terminate list */ +}; +MODULE_DEVICE_TABLE(pci, wdtpci_pci_tbl); + + +static struct pci_driver wdtpci_driver = { + .name = "wdt-pci", + .id_table = wdtpci_pci_tbl, + .probe = wdtpci_init_one, + .remove = __devexit_p(wdtpci_remove_one), +}; + + +/** + * wdtpci_cleanup: + * + * Unload the watchdog. You cannot do this with any file handles open. + * If your watchdog is set to continue ticking on close and you unload + * it, well it keeps ticking. We won't get the interrupt but the board + * will not touch PC memory so all is fine. You just have to load a new + * module in 60 seconds or reboot. + */ + +static void __exit wdtpci_cleanup(void) +{ + pci_unregister_driver (&wdtpci_driver); +} + + +/** + * wdtpci_init: + * + * Set up the WDT watchdog board. All we have to do is grab the + * resources we require and bitch if anyone beat us to them. + * The open() function will actually kick the board off. + */ + +static int __init wdtpci_init(void) +{ + int rc = pci_register_driver (&wdtpci_driver); + + if (rc < 1) + return -ENODEV; + + wdtpci_validate_timeout(); + + return 0; +} + + +module_init(wdtpci_init); +module_exit(wdtpci_cleanup); + +MODULE_AUTHOR("JP Nollmann, Alan Cox"); +MODULE_DESCRIPTION("Driver for the ICS PCI watchdog cards"); +MODULE_LICENSE("GPL"); diff -urpN --exclude-from=/home/davej/.exclude bk-linus/drivers/char/wd501p.h move-watchdogs/drivers/char/wd501p.h --- bk-linus/drivers/char/wd501p.h 2002-11-22 11:00:44.000000000 -0100 +++ move-watchdogs/drivers/char/wd501p.h 1969-12-31 23:00:00.000000000 -0100 @@ -1,91 +0,0 @@ -/* - * Industrial Computer Source WDT500/501 driver for Linux 1.3.x - * - * (c) Copyright 1995 CymruNET Ltd - * Innovation Centre - * Singleton Park - * Swansea - * Wales - * UK - * SA2 8PP - * - * http://www.cymru.net - * - * This driver is provided under the GNU General Public License, incorporated - * herein by reference. The driver is provided without warranty or - * support. - * - * Release 0.04. - * - */ - -#include - -#define WDT_COUNT0 (io+0) -#define WDT_COUNT1 (io+1) -#define WDT_COUNT2 (io+2) -#define WDT_CR (io+3) -#define WDT_SR (io+4) /* Start buzzer on PCI write */ -#define WDT_RT (io+5) /* Stop buzzer on PCI write */ -#define WDT_BUZZER (io+6) /* PCI only: rd=disable, wr=enable */ -#define WDT_DC (io+7) - -/* The following are only on the PCI card, they're outside of I/O space on - * the ISA card: */ -#define WDT_CLOCK (io+12) /* COUNT2: rd=16.67MHz, wr=2.0833MHz */ -/* inverted opto isolated reset output: */ -#define WDT_OPTONOTRST (io+13) /* wr=enable, rd=disable */ -/* opto isolated reset output: */ -#define WDT_OPTORST (io+14) /* wr=enable, rd=disable */ -/* programmable outputs: */ -#define WDT_PROGOUT (io+15) /* wr=enable, rd=disable */ - -#define WDC_SR_WCCR 1 /* Active low */ -#define WDC_SR_TGOOD 2 -#define WDC_SR_ISOI0 4 -#define WDC_SR_ISII1 8 -#define WDC_SR_FANGOOD 16 -#define WDC_SR_PSUOVER 32 /* Active low */ -#define WDC_SR_PSUUNDR 64 /* Active low */ -#define WDC_SR_IRQ 128 /* Active low */ - -#ifndef WDT_IS_PCI - -/* - * Feature Map 1 is the active high inputs not supported on your card. - * Feature Map 2 is the active low inputs not supported on your card. - */ - -#ifdef CONFIG_WDT_501 /* Full board */ - -#ifdef CONFIG_WDT501_FAN /* Full board, Fan has no tachometer */ -#define FEATUREMAP1 0 -#define WDT_OPTION_MASK (WDIOF_OVERHEAT|WDIOF_POWERUNDER|WDIOF_POWEROVER|WDIOF_EXTERN1|WDIOF_EXTERN2|WDIOF_FANFAULT) -#else -#define FEATUREMAP1 WDC_SR_FANGOOD -#define WDT_OPTION_MASK (WDIOF_OVERHEAT|WDIOF_POWERUNDER|WDIOF_POWEROVER|WDIOF_EXTERN1|WDIOF_EXTERN2) -#endif - -#define FEATUREMAP2 0 -#endif - -#ifndef CONFIG_WDT_501 -#define CONFIG_WDT_500 -#endif - -#ifdef CONFIG_WDT_500 /* Minimal board */ -#define FEATUREMAP1 (WDC_SR_TGOOD|WDC_SR_FANGOOD) -#define FEATUREMAP2 (WDC_SR_PSUOVER|WDC_SR_PSUUNDR) -#define WDT_OPTION_MASK (WDIOF_OVERHEAT) -#endif - -#else - -#define FEATUREMAP1 (WDC_SR_TGOOD|WDC_SR_FANGOOD) -#define FEATUREMAP2 (WDC_SR_PSUOVER|WDC_SR_PSUUNDR) -#define WDT_OPTION_MASK (WDIOF_OVERHEAT) -#endif - -#ifndef FEATUREMAP1 -#error "Config option not set" -#endif diff -urpN --exclude-from=/home/davej/.exclude bk-linus/drivers/char/wdt.c move-watchdogs/drivers/char/wdt.c --- bk-linus/drivers/char/wdt.c 2002-11-22 11:00:44.000000000 -0100 +++ move-watchdogs/drivers/char/wdt.c 1969-12-31 23:00:00.000000000 -0100 @@ -1,565 +0,0 @@ -/* - * Industrial Computer Source WDT500/501 driver for Linux 2.1.x - * - * (c) Copyright 1996-1997 Alan Cox , All Rights Reserved. - * http://www.redhat.com - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version - * 2 of the License, or (at your option) any later version. - * - * Neither Alan Cox nor CymruNet Ltd. admit liability nor provide - * warranty for any of this software. This material is provided - * "AS-IS" and at no charge. - * - * (c) Copyright 1995 Alan Cox - * - * Release 0.09. - * - * Fixes - * Dave Gregorich : Modularisation and minor bugs - * Alan Cox : Added the watchdog ioctl() stuff - * Alan Cox : Fixed the reboot problem (as noted by - * Matt Crocker). - * Alan Cox : Added wdt= boot option - * Alan Cox : Cleaned up copy/user stuff - * Tim Hockin : Added insmod parameters, comment cleanup - * Parameterized timeout - * Tigran Aivazian : Restructured wdt_init() to handle failures - * Matt Domsch : added nowayout and timeout module options - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include "wd501p.h" -#include -#include -#include -#include -#include -#include - -#include -#include -#include - -static unsigned long wdt_is_open; - -/* - * You must set these - there is no sane way to probe for this board. - * You can use wdt=x,y to set these now. - */ - -static int io=0x240; -static int irq=11; - -#define WD_TIMO (100*60) /* 1 minute */ - -static int timeout_val = WD_TIMO; /* value passed to card */ -static int timeout = 60; /* in seconds */ -MODULE_PARM(timeout,"i"); -MODULE_PARM_DESC(timeout, "Watchdog timeout in seconds (default=60)"); - -#ifdef CONFIG_WATCHDOG_NOWAYOUT -static int nowayout = 1; -#else -static int nowayout = 0; -#endif - -MODULE_PARM(nowayout,"i"); -MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default=CONFIG_WATCHDOG_NOWAYOUT)"); - -static void __init -wdt_validate_timeout(void) -{ - timeout_val = timeout * 100; -} - -#ifndef MODULE - -/** - * wdt_setup: - * @str: command line string - * - * Setup options. The board isn't really probe-able so we have to - * get the user to tell us the configuration. Sane people build it - * modular but the others come here. - */ - -static int __init wdt_setup(char *str) -{ - int ints[4]; - - str = get_options (str, ARRAY_SIZE(ints), ints); - - if (ints[0] > 0) - { - io = ints[1]; - if(ints[0] > 1) - irq = ints[2]; - } - - return 1; -} - -__setup("wdt=", wdt_setup); - -#endif /* !MODULE */ - -MODULE_PARM(io, "i"); -MODULE_PARM_DESC(io, "WDT io port (default=0x240)"); -MODULE_PARM(irq, "i"); -MODULE_PARM_DESC(irq, "WDT irq (default=11)"); - -/* - * Programming support - */ - -static void wdt_ctr_mode(int ctr, int mode) -{ - ctr<<=6; - ctr|=0x30; - ctr|=(mode<<1); - outb_p(ctr, WDT_CR); -} - -static void wdt_ctr_load(int ctr, int val) -{ - outb_p(val&0xFF, WDT_COUNT0+ctr); - outb_p(val>>8, WDT_COUNT0+ctr); -} - -/* - * Kernel methods. - */ - - -/** - * wdt_status: - * - * Extract the status information from a WDT watchdog device. There are - * several board variants so we have to know which bits are valid. Some - * bits default to one and some to zero in order to be maximally painful. - * - * we then map the bits onto the status ioctl flags. - */ - -static int wdt_status(void) -{ - /* - * Status register to bit flags - */ - - int flag=0; - unsigned char status=inb_p(WDT_SR); - status|=FEATUREMAP1; - status&=~FEATUREMAP2; - - if(!(status&WDC_SR_TGOOD)) - flag|=WDIOF_OVERHEAT; - if(!(status&WDC_SR_PSUOVER)) - flag|=WDIOF_POWEROVER; - if(!(status&WDC_SR_PSUUNDR)) - flag|=WDIOF_POWERUNDER; - if(!(status&WDC_SR_FANGOOD)) - flag|=WDIOF_FANFAULT; - if(status&WDC_SR_ISOI0) - flag|=WDIOF_EXTERN1; - if(status&WDC_SR_ISII1) - flag|=WDIOF_EXTERN2; - return flag; -} - -/** - * wdt_interrupt: - * @irq: Interrupt number - * @dev_id: Unused as we don't allow multiple devices. - * @regs: Unused. - * - * Handle an interrupt from the board. These are raised when the status - * map changes in what the board considers an interesting way. That means - * a failure condition occuring. - */ - -void wdt_interrupt(int irq, void *dev_id, struct pt_regs *regs) -{ - /* - * Read the status register see what is up and - * then printk it. - */ - - unsigned char status=inb_p(WDT_SR); - - status|=FEATUREMAP1; - status&=~FEATUREMAP2; - - printk(KERN_CRIT "WDT status %d\n", status); - - if(!(status&WDC_SR_TGOOD)) - printk(KERN_CRIT "Overheat alarm.(%d)\n",inb_p(WDT_RT)); - if(!(status&WDC_SR_PSUOVER)) - printk(KERN_CRIT "PSU over voltage.\n"); - if(!(status&WDC_SR_PSUUNDR)) - printk(KERN_CRIT "PSU under voltage.\n"); - if(!(status&WDC_SR_FANGOOD)) - printk(KERN_CRIT "Possible fan fault.\n"); - if(!(status&WDC_SR_WCCR)) -#ifdef SOFTWARE_REBOOT -#ifdef ONLY_TESTING - printk(KERN_CRIT "Would Reboot.\n"); -#else - printk(KERN_CRIT "Initiating system reboot.\n"); - machine_restart(NULL); -#endif -#else - printk(KERN_CRIT "Reset in 5ms.\n"); -#endif -} - - -/** - * wdt_ping: - * - * Reload counter one with the watchdog timeout. We don't bother reloading - * the cascade counter. - */ - -static void wdt_ping(void) -{ - /* Write a watchdog value */ - inb_p(WDT_DC); - wdt_ctr_mode(1,2); - wdt_ctr_load(1,timeout_val); /* Timeout */ - outb_p(0, WDT_DC); -} - -/** - * wdt_write: - * @file: file handle to the watchdog - * @buf: buffer to write (unused as data does not matter here - * @count: count of bytes - * @ppos: pointer to the position to write. No seeks allowed - * - * A write to a watchdog device is defined as a keepalive signal. Any - * write of data will do, as we we don't define content meaning. - */ - -static ssize_t wdt_write(struct file *file, const char *buf, size_t count, loff_t *ppos) -{ - /* Can't seek (pwrite) on this device */ - if (ppos != &file->f_pos) - return -ESPIPE; - - if(count) - { - wdt_ping(); - return 1; - } - return 0; -} - -/** - * wdt_read: - * @file: file handle to the watchdog board - * @buf: buffer to write 1 byte into - * @count: length of buffer - * @ptr: offset (no seek allowed) - * - * Read reports the temperature in degrees Fahrenheit. The API is in - * farenheit. It was designed by an imperial measurement luddite. - */ - -static ssize_t wdt_read(struct file *file, char *buf, size_t count, loff_t *ptr) -{ - unsigned short c=inb_p(WDT_RT); - unsigned char cp; - - /* Can't seek (pread) on this device */ - if (ptr != &file->f_pos) - return -ESPIPE; - - switch(minor(file->f_dentry->d_inode->i_rdev)) - { - case TEMP_MINOR: - c*=11; - c/=15; - cp=c+7; - if(copy_to_user(buf,&cp,1)) - return -EFAULT; - return 1; - default: - return -EINVAL; - } -} - -/** - * wdt_ioctl: - * @inode: inode of the device - * @file: file handle to the device - * @cmd: watchdog command - * @arg: argument pointer - * - * The watchdog API defines a common set of functions for all watchdogs - * according to their available features. We only actually usefully support - * querying capabilities and current status. - */ - -static int wdt_ioctl(struct inode *inode, struct file *file, unsigned int cmd, - unsigned long arg) -{ - static struct watchdog_info ident= - { - WDIOF_OVERHEAT|WDIOF_POWERUNDER|WDIOF_POWEROVER - |WDIOF_EXTERN1|WDIOF_EXTERN2|WDIOF_FANFAULT, - 1, - "WDT500/501" - }; - - ident.options&=WDT_OPTION_MASK; /* Mask down to the card we have */ - switch(cmd) - { - default: - return -ENOTTY; - case WDIOC_GETSUPPORT: - return copy_to_user((struct watchdog_info *)arg, &ident, sizeof(ident))?-EFAULT:0; - - case WDIOC_GETSTATUS: - return put_user(wdt_status(),(int *)arg); - case WDIOC_GETBOOTSTATUS: - return put_user(0, (int *)arg); - case WDIOC_KEEPALIVE: - wdt_ping(); - return 0; - } -} - -/** - * wdt_open: - * @inode: inode of device - * @file: file handle to device - * - * One of our two misc devices has been opened. The watchdog device is - * single open and on opening we load the counters. Counter zero is a - * 100Hz cascade, into counter 1 which downcounts to reboot. When the - * counter triggers counter 2 downcounts the length of the reset pulse - * which set set to be as long as possible. - */ - -static int wdt_open(struct inode *inode, struct file *file) -{ - switch(minor(inode->i_rdev)) - { - case WATCHDOG_MINOR: - if(test_and_set_bit(0, &wdt_is_open)) - return -EBUSY; - if (nowayout) { - MOD_INC_USE_COUNT; - } - /* - * Activate - */ - - inb_p(WDT_DC); /* Disable */ - wdt_ctr_mode(0,3); - wdt_ctr_mode(1,2); - wdt_ctr_mode(2,0); - wdt_ctr_load(0, 8948); /* count at 100Hz */ - wdt_ctr_load(1,timeout_val); /* Timeout */ - wdt_ctr_load(2,65535); - outb_p(0, WDT_DC); /* Enable */ - return 0; - case TEMP_MINOR: - return 0; - default: - return -ENODEV; - } -} - -/** - * wdt_close: - * @inode: inode to board - * @file: file handle to board - * - * The watchdog has a configurable API. There is a religious dispute - * between people who want their watchdog to be able to shut down and - * those who want to be sure if the watchdog manager dies the machine - * reboots. In the former case we disable the counters, in the latter - * case you have to open it again very soon. - */ - -static int wdt_release(struct inode *inode, struct file *file) -{ - if(minor(inode->i_rdev)==WATCHDOG_MINOR) - { - if (!nowayout) { - inb_p(WDT_DC); /* Disable counters */ - wdt_ctr_load(2,0); /* 0 length reset pulses now */ - } - clear_bit(0, &wdt_is_open); - } - return 0; -} - -/** - * notify_sys: - * @this: our notifier block - * @code: the event being reported - * @unused: unused - * - * Our notifier is called on system shutdowns. We want to turn the card - * off at reboot otherwise the machine will reboot again during memory - * test or worse yet during the following fsck. This would suck, in fact - * trust me - if it happens it does suck. - */ - -static int wdt_notify_sys(struct notifier_block *this, unsigned long code, - void *unused) -{ - if(code==SYS_DOWN || code==SYS_HALT) - { - /* Turn the card off */ - inb_p(WDT_DC); - wdt_ctr_load(2,0); - } - return NOTIFY_DONE; -} - -/* - * Kernel Interfaces - */ - - -static struct file_operations wdt_fops = { - .owner = THIS_MODULE, - .llseek = no_llseek, - .read = wdt_read, - .write = wdt_write, - .ioctl = wdt_ioctl, - .open = wdt_open, - .release = wdt_release, -}; - -static struct miscdevice wdt_miscdev= -{ - WATCHDOG_MINOR, - "watchdog", - &wdt_fops -}; - -#ifdef CONFIG_WDT_501 -static struct miscdevice temp_miscdev= -{ - TEMP_MINOR, - "temperature", - &wdt_fops -}; -#endif - -/* - * The WDT card needs to learn about soft shutdowns in order to - * turn the timebomb registers off. - */ - -static struct notifier_block wdt_notifier= -{ - wdt_notify_sys, - NULL, - 0 -}; - -/** - * cleanup_module: - * - * Unload the watchdog. You cannot do this with any file handles open. - * If your watchdog is set to continue ticking on close and you unload - * it, well it keeps ticking. We won't get the interrupt but the board - * will not touch PC memory so all is fine. You just have to load a new - * module in 60 seconds or reboot. - */ - -static void __exit wdt_exit(void) -{ - misc_deregister(&wdt_miscdev); -#ifdef CONFIG_WDT_501 - misc_deregister(&temp_miscdev); -#endif - unregister_reboot_notifier(&wdt_notifier); - release_region(io,8); - free_irq(irq, NULL); -} - -/** - * wdt_init: - * - * Set up the WDT watchdog board. All we have to do is grab the - * resources we require and bitch if anyone beat us to them. - * The open() function will actually kick the board off. - */ - -static int __init wdt_init(void) -{ - int ret; - - wdt_validate_timeout(); - ret = misc_register(&wdt_miscdev); - if (ret) { - printk(KERN_ERR "wdt: can't misc_register on minor=%d\n", WATCHDOG_MINOR); - goto out; - } - ret = request_irq(irq, wdt_interrupt, SA_INTERRUPT, "wdt501p", NULL); - if(ret) { - printk(KERN_ERR "wdt: IRQ %d is not free.\n", irq); - goto outmisc; - } - if (!request_region(io, 8, "wdt501p")) { - printk(KERN_ERR "wdt: IO %X is not free.\n", io); - ret = -EBUSY; - goto outirq; - } - ret = register_reboot_notifier(&wdt_notifier); - if(ret) { - printk(KERN_ERR "wdt: can't register reboot notifier (err=%d)\n", ret); - goto outreg; - } - -#ifdef CONFIG_WDT_501 - ret = misc_register(&temp_miscdev); - if (ret) { - printk(KERN_ERR "wdt: can't misc_register (temp) on minor=%d\n", TEMP_MINOR); - goto outrbt; - } -#endif - - ret = 0; - printk(KERN_INFO "WDT500/501-P driver 0.07 at %X (Interrupt %d)\n", io, irq); -out: - return ret; - -#ifdef CONFIG_WDT_501 -outrbt: - unregister_reboot_notifier(&wdt_notifier); -#endif - -outreg: - release_region(io,8); -outirq: - free_irq(irq, NULL); -outmisc: - misc_deregister(&wdt_miscdev); - goto out; -} - -module_init(wdt_init); -module_exit(wdt_exit); - -MODULE_AUTHOR("Alan Cox"); -MODULE_DESCRIPTION("Driver for ISA ICS watchdog cards (WDT500/501)"); -MODULE_LICENSE("GPL"); diff -urpN --exclude-from=/home/davej/.exclude bk-linus/drivers/char/wdt285.c move-watchdogs/drivers/char/wdt285.c --- bk-linus/drivers/char/wdt285.c 2002-11-22 11:00:44.000000000 -0100 +++ move-watchdogs/drivers/char/wdt285.c 1969-12-31 23:00:00.000000000 -0100 @@ -1,193 +0,0 @@ -/* - * Intel 21285 watchdog driver - * Copyright (c) Phil Blundell , 1998 - * - * based on - * - * SoftDog 0.05: A Software Watchdog Device - * - * (c) Copyright 1996 Alan Cox , All Rights Reserved. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version - * 2 of the License, or (at your option) any later version. - * - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include - -/* - * Define this to stop the watchdog actually rebooting the machine. - */ -#undef ONLY_TESTING - -#define TIMER_MARGIN 60 /* (secs) Default is 1 minute */ - -#define FCLK (50*1000*1000) /* 50MHz */ - -static int soft_margin = TIMER_MARGIN; /* in seconds */ -static int timer_alive; - -#ifdef ONLY_TESTING -/* - * If the timer expires.. - */ - -static void watchdog_fire(int irq, void *dev_id, struct pt_regs *regs) -{ - printk(KERN_CRIT "Watchdog: Would Reboot.\n"); - *CSR_TIMER4_CNTL = 0; - *CSR_TIMER4_CLR = 0; -} -#endif - -static void watchdog_ping(void) -{ - /* - * Refresh the timer. - */ - *CSR_TIMER4_LOAD = soft_margin * (FCLK / 256); -} - -/* - * Allow only one person to hold it open - */ - -static int watchdog_open(struct inode *inode, struct file *file) -{ - if(timer_alive) - return -EBUSY; - /* - * Ahead watchdog factor ten, Mr Sulu - */ - *CSR_TIMER4_CLR = 0; - watchdog_ping(); - *CSR_TIMER4_CNTL = TIMER_CNTL_ENABLE | TIMER_CNTL_AUTORELOAD - | TIMER_CNTL_DIV256; -#ifdef ONLY_TESTING - request_irq(IRQ_TIMER4, watchdog_fire, 0, "watchdog", NULL); -#else - *CSR_SA110_CNTL |= 1 << 13; - MOD_INC_USE_COUNT; -#endif - timer_alive = 1; - return 0; -} - -static int watchdog_release(struct inode *inode, struct file *file) -{ -#ifdef ONLY_TESTING - free_irq(IRQ_TIMER4, NULL); - timer_alive = 0; -#else - /* - * It's irreversible! - */ -#endif - return 0; -} - -static ssize_t watchdog_write(struct file *file, const char *data, size_t len, loff_t *ppos) -{ - /* Can't seek (pwrite) on this device */ - if (ppos != &file->f_pos) - return -ESPIPE; - - /* - * Refresh the timer. - */ - if(len) - { - watchdog_ping(); - return 1; - } - return 0; -} - -static int watchdog_ioctl(struct inode *inode, struct file *file, - unsigned int cmd, unsigned long arg) -{ - int i; - static struct watchdog_info ident= - { - 0, - 0, - "Footbridge Watchdog" - }; - switch(cmd) - { - default: - return -ENOTTY; - case WDIOC_GETSUPPORT: - if(copy_to_user((struct watchdog_info *)arg, &ident, sizeof(ident))) - return -EFAULT; - return 0; - case WDIOC_GETSTATUS: - case WDIOC_GETBOOTSTATUS: - return put_user(0,(int *)arg); - case WDIOC_KEEPALIVE: - watchdog_ping(); - return 0; - } -} - -static struct file_operations watchdog_fops= -{ - .owner = THIS_MODULE, - .write = watchdog_write, - .ioctl = watchdog_ioctl, - .open = watchdog_open, - .release = watchdog_release, -}; - -static struct miscdevice watchdog_miscdev= -{ - WATCHDOG_MINOR, - "watchdog", - &watchdog_fops -}; - -static int __init footbridge_watchdog_init(void) -{ - if (machine_is_netwinder()) - return -ENODEV; - - misc_register(&watchdog_miscdev); - printk("Footbridge Watchdog Timer: 0.01, timer margin: %d sec\n", - soft_margin); - if (machine_is_cats()) - printk("Warning: Watchdog reset may not work on this machine.\n"); - return 0; -} - -static void __exit footbridge_watchdog_exit(void) -{ - misc_deregister(&watchdog_miscdev); -} - -MODULE_AUTHOR("Phil Blundell "); -MODULE_DESCRIPTION("21285 watchdog driver"); -MODULE_LICENSE("GPL"); - -MODULE_PARM(soft_margin,"i"); -MODULE_PARM_DESC(soft_margin,"Watchdog timeout in seconds"); - -module_init(footbridge_watchdog_init); -module_exit(footbridge_watchdog_exit); diff -urpN --exclude-from=/home/davej/.exclude bk-linus/drivers/char/wdt977.c move-watchdogs/drivers/char/wdt977.c --- bk-linus/drivers/char/wdt977.c 2002-11-22 11:00:44.000000000 -0100 +++ move-watchdogs/drivers/char/wdt977.c 1969-12-31 23:00:00.000000000 -0100 @@ -1,346 +0,0 @@ -/* - * Wdt977 0.02: A Watchdog Device for Netwinder W83977AF chip - * - * (c) Copyright 1998 Rebel.com (Woody Suwalski ) - * - * ----------------------- - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version - * 2 of the License, or (at your option) any later version. - * - * ----------------------- - * 14-Dec-2001 Matt Domsch - * Added nowayout module option to override CONFIG_WATCHDOG_NOWAYOUT - * 19-Dec-2001 Woody Suwalski: Netwinder fixes, ioctl interface - * 06-Jan-2002 Woody Suwalski: For compatibility, convert all timeouts - * from minutes to seconds. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include - -#define WATCHDOG_MINOR 130 - -#define DEFAULT_TIMEOUT 1 /* default timeout = 1 minute */ - -static int timeout = DEFAULT_TIMEOUT*60; /* TO in seconds from user */ -static int timeoutM = DEFAULT_TIMEOUT; /* timeout in minutes */ -static unsigned long timer_alive; -static int testmode; - -MODULE_PARM(timeout, "i"); -MODULE_PARM_DESC(timeout,"Watchdog timeout in seconds (60..15300), default=60"); -MODULE_PARM(testmode, "i"); -MODULE_PARM_DESC(testmode,"Watchdog testmode (1 = no reboot), default=0"); - -#ifdef CONFIG_WATCHDOG_NOWAYOUT -static int nowayout = 1; -#else -static int nowayout = 0; -#endif - -MODULE_PARM(nowayout,"i"); -MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default=CONFIG_WATCHDOG_NOWAYOUT)"); - - -/* This is kicking the watchdog by simply re-writing the timeout to reg. 0xF2 */ -int kick_wdog(void) -{ - /* - * Refresh the timer. - */ - - /* unlock the SuperIO chip */ - outb(0x87,0x370); - outb(0x87,0x370); - - /* select device Aux2 (device=8) and kicks watchdog reg F2 */ - /* F2 has the timeout in minutes */ - - outb(0x07,0x370); - outb(0x08,0x371); - outb(0xF2,0x370); - outb(timeoutM,0x371); - - /* lock the SuperIO chip */ - outb(0xAA,0x370); - - return 0; -} - - -/* - * Allow only one person to hold it open - */ - -static int wdt977_open(struct inode *inode, struct file *file) -{ - - if( test_and_set_bit(0,&timer_alive) ) - return -EBUSY; - - /* convert seconds to minutes, rounding up */ - timeoutM = timeout + 59; - timeoutM /= 60; - - if (nowayout) - { - MOD_INC_USE_COUNT; - - /* do not permit disabling the watchdog by writing 0 to reg. 0xF2 */ - if (!timeoutM) timeoutM = DEFAULT_TIMEOUT; - } - - if (machine_is_netwinder()) - { - /* we have a hw bug somewhere, so each 977 minute is actually only 30sec - * this limits the max timeout to half of device max of 255 minutes... - */ - timeoutM += timeoutM; - } - - /* max timeout value = 255 minutes (0xFF). Write 0 to disable WatchDog. */ - if (timeoutM > 255) timeoutM = 255; - - /* convert seconds to minutes */ - printk(KERN_INFO "Wdt977 Watchdog activated: timeout = %d sec, nowayout = %i, testmode = %i.\n", - machine_is_netwinder() ? (timeoutM>>1)*60 : timeoutM*60, - nowayout, testmode); - - /* unlock the SuperIO chip */ - outb(0x87,0x370); - outb(0x87,0x370); - - /* select device Aux2 (device=8) and set watchdog regs F2, F3 and F4 - * F2 has the timeout in minutes - * F3 could be set to the POWER LED blink (with GP17 set to PowerLed) - * at timeout, and to reset timer on kbd/mouse activity (not impl.) - * F4 is used to just clear the TIMEOUT'ed state (bit 0) - */ - outb(0x07,0x370); - outb(0x08,0x371); - outb(0xF2,0x370); - outb(timeoutM,0x371); - outb(0xF3,0x370); - outb(0x00,0x371); /* another setting is 0E for kbd/mouse/LED */ - outb(0xF4,0x370); - outb(0x00,0x371); - - /* at last select device Aux1 (dev=7) and set GP16 as a watchdog output */ - /* in test mode watch the bit 1 on F4 to indicate "triggered" */ - if (!testmode) - { - outb(0x07,0x370); - outb(0x07,0x371); - outb(0xE6,0x370); - outb(0x08,0x371); - } - - /* lock the SuperIO chip */ - outb(0xAA,0x370); - - return 0; -} - -static int wdt977_release(struct inode *inode, struct file *file) -{ - /* - * Shut off the timer. - * Lock it in if it's a module and we set nowayout - */ - if (!nowayout) - { - /* unlock the SuperIO chip */ - outb(0x87,0x370); - outb(0x87,0x370); - - /* select device Aux2 (device=8) and set watchdog regs F2,F3 and F4 - * F3 is reset to its default state - * F4 can clear the TIMEOUT'ed state (bit 0) - back to default - * We can not use GP17 as a PowerLed, as we use its usage as a RedLed - */ - outb(0x07,0x370); - outb(0x08,0x371); - outb(0xF2,0x370); - outb(0xFF,0x371); - outb(0xF3,0x370); - outb(0x00,0x371); - outb(0xF4,0x370); - outb(0x00,0x371); - outb(0xF2,0x370); - outb(0x00,0x371); - - /* at last select device Aux1 (dev=7) and set GP16 as a watchdog output */ - outb(0x07,0x370); - outb(0x07,0x371); - outb(0xE6,0x370); - outb(0x08,0x371); - - /* lock the SuperIO chip */ - outb(0xAA,0x370); - - clear_bit(0,&timer_alive); - - printk(KERN_INFO "Wdt977 Watchdog: shutdown\n"); - } - return 0; -} - - -/* - * wdt977_write: - * @file: file handle to the watchdog - * @buf: buffer to write (unused as data does not matter here - * @count: count of bytes - * @ppos: pointer to the position to write. No seeks allowed - * - * A write to a watchdog device is defined as a keepalive signal. Any - * write of data will do, as we we don't define content meaning. - */ - -static ssize_t wdt977_write(struct file *file, const char *buf, size_t count, loff_t *ppos) -{ - /* Can't seek (pwrite) on this device */ - if (ppos != &file->f_pos) - return -ESPIPE; - - if(count) - { - kick_wdog(); - return 1; - } - return 0; -} - -/* - * wdt977_ioctl: - * @inode: inode of the device - * @file: file handle to the device - * @cmd: watchdog command - * @arg: argument pointer - * - * The watchdog API defines a common set of functions for all watchdogs - * according to their available features. - */ - -static int wdt977_ioctl(struct inode *inode, struct file *file, - unsigned int cmd, unsigned long arg) -{ -static struct watchdog_info ident = { - identity : "Winbond 83977" -}; - -int temp; - - switch(cmd) - { - default: - return -ENOTTY; - - case WDIOC_GETSUPPORT: - return copy_to_user((struct watchdog_info *)arg, &ident, - sizeof(ident)) ? -EFAULT : 0; - - case WDIOC_GETBOOTSTATUS: - return put_user(0, (int *) arg); - - case WDIOC_GETSTATUS: - /* unlock the SuperIO chip */ - outb(0x87,0x370); - outb(0x87,0x370); - - /* select device Aux2 (device=8) and read watchdog reg F4 */ - outb(0x07,0x370); - outb(0x08,0x371); - outb(0xF4,0x370); - temp = inb(0x371); - - /* lock the SuperIO chip */ - outb(0xAA,0x370); - - /* return info if "expired" in test mode */ - return put_user(temp & 1, (int *) arg); - - case WDIOC_KEEPALIVE: - kick_wdog(); - return 0; - - case WDIOC_SETTIMEOUT: - if (copy_from_user(&temp, (int *) arg, sizeof(int))) - return -EFAULT; - - /* convert seconds to minutes, rounding up */ - temp += 59; - temp /= 60; - - /* we have a hw bug somewhere, so each 977 minute is actually only 30sec - * this limits the max timeout to half of device max of 255 minutes... - */ - if (machine_is_netwinder()) - { - temp += temp; - } - - /* Sanity check */ - if (temp < 0 || temp > 255) - return -EINVAL; - - if (!temp && nowayout) - return -EINVAL; - - timeoutM = temp; - kick_wdog(); - return 0; - } -} - - -static struct file_operations wdt977_fops= -{ - .owner = THIS_MODULE, - .write = wdt977_write, - .ioctl = wdt977_ioctl, - .open = wdt977_open, - .release = wdt977_release, -}; - -static struct miscdevice wdt977_miscdev= -{ - WATCHDOG_MINOR, - "watchdog", - &wdt977_fops -}; - -static int __init nwwatchdog_init(void) -{ - if (!machine_is_netwinder()) - return -ENODEV; - - misc_register(&wdt977_miscdev); - printk(KERN_INFO "Wdt977 Watchdog sleeping.\n"); - return 0; -} - -static void __exit nwwatchdog_exit(void) -{ - misc_deregister(&wdt977_miscdev); -} - -module_init(nwwatchdog_init); -module_exit(nwwatchdog_exit); - -MODULE_LICENSE("GPL"); diff -urpN --exclude-from=/home/davej/.exclude bk-linus/drivers/char/wdt_pci.c move-watchdogs/drivers/char/wdt_pci.c --- bk-linus/drivers/char/wdt_pci.c 2002-11-22 11:00:44.000000000 -0100 +++ move-watchdogs/drivers/char/wdt_pci.c 1969-12-31 23:00:00.000000000 -0100 @@ -1,653 +0,0 @@ -/* - * Industrial Computer Source WDT500/501 driver for Linux 2.1.x - * - * (c) Copyright 1996-1997 Alan Cox , All Rights Reserved. - * http://www.redhat.com - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version - * 2 of the License, or (at your option) any later version. - * - * Neither Alan Cox nor CymruNet Ltd. admit liability nor provide - * warranty for any of this software. This material is provided - * "AS-IS" and at no charge. - * - * (c) Copyright 1995 Alan Cox - * - * Release 0.09. - * - * Fixes - * Dave Gregorich : Modularisation and minor bugs - * Alan Cox : Added the watchdog ioctl() stuff - * Alan Cox : Fixed the reboot problem (as noted by - * Matt Crocker). - * Alan Cox : Added wdt= boot option - * Alan Cox : Cleaned up copy/user stuff - * Tim Hockin : Added insmod parameters, comment cleanup - * Parameterized timeout - * JP Nollmann : Added support for PCI wdt501p - * Alan Cox : Split ISA and PCI cards into two drivers - * Jeff Garzik : PCI cleanups - * Tigran Aivazian : Restructured wdtpci_init_one() to handle failures - * Matt Domsch : added nowayout and timeout module options - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include - -#define WDT_IS_PCI -#include "wd501p.h" - -#define PFX "wdt_pci: " - -/* - * Until Access I/O gets their application for a PCI vendor ID approved, - * I don't think that it's appropriate to move these constants into the - * regular pci_ids.h file. -- JPN 2000/01/18 - */ - -#ifndef PCI_VENDOR_ID_ACCESSIO -#define PCI_VENDOR_ID_ACCESSIO 0x494f -#endif -#ifndef PCI_DEVICE_ID_WDG_CSM -#define PCI_DEVICE_ID_WDG_CSM 0x22c0 -#endif - -static unsigned long wdt_is_open; - -/* - * You must set these - there is no sane way to probe for this board. - * You can use wdt=x,y to set these now. - */ - -static int io=0x240; -static int irq=11; - -#define WD_TIMO (100*60) /* 1 minute */ - -static int timeout_val = WD_TIMO; /* value passed to card */ -static int timeout = 60; /* in seconds */ -MODULE_PARM(timeout,"i"); -MODULE_PARM_DESC(timeout, "Watchdog timeout in seconds (default=60)"); - -#ifdef CONFIG_WATCHDOG_NOWAYOUT -static int nowayout = 1; -#else -static int nowayout = 0; -#endif - -MODULE_PARM(nowayout,"i"); -MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default=CONFIG_WATCHDOG_NOWAYOUT)"); - -static void __init -wdtpci_validate_timeout(void) -{ - timeout_val = timeout * 100; -} - -#ifndef MODULE - -/** - * wdtpci_setup: - * @str: command line string - * - * Setup options. The board isn't really probe-able so we have to - * get the user to tell us the configuration. Sane people build it - * modular but the others come here. - */ - -static int __init wdtpci_setup(char *str) -{ - int ints[4]; - - str = get_options (str, ARRAY_SIZE(ints), ints); - - if (ints[0] > 0) - { - io = ints[1]; - if(ints[0] > 1) - irq = ints[2]; - } - - return 1; -} - -__setup("wdt=", wdtpci_setup); - -#endif /* !MODULE */ - -/* - * Programming support - */ - -static void wdtpci_ctr_mode(int ctr, int mode) -{ - ctr<<=6; - ctr|=0x30; - ctr|=(mode<<1); - outb_p(ctr, WDT_CR); -} - -static void wdtpci_ctr_load(int ctr, int val) -{ - outb_p(val&0xFF, WDT_COUNT0+ctr); - outb_p(val>>8, WDT_COUNT0+ctr); -} - -/* - * Kernel methods. - */ - - -/** - * wdtpci_status: - * - * Extract the status information from a WDT watchdog device. There are - * several board variants so we have to know which bits are valid. Some - * bits default to one and some to zero in order to be maximally painful. - * - * we then map the bits onto the status ioctl flags. - */ - -static int wdtpci_status(void) -{ - /* - * Status register to bit flags - */ - - int flag=0; - unsigned char status=inb_p(WDT_SR); - status|=FEATUREMAP1; - status&=~FEATUREMAP2; - - if(!(status&WDC_SR_TGOOD)) - flag|=WDIOF_OVERHEAT; - if(!(status&WDC_SR_PSUOVER)) - flag|=WDIOF_POWEROVER; - if(!(status&WDC_SR_PSUUNDR)) - flag|=WDIOF_POWERUNDER; - if(!(status&WDC_SR_FANGOOD)) - flag|=WDIOF_FANFAULT; - if(status&WDC_SR_ISOI0) - flag|=WDIOF_EXTERN1; - if(status&WDC_SR_ISII1) - flag|=WDIOF_EXTERN2; - return flag; -} - -/** - * wdtpci_interrupt: - * @irq: Interrupt number - * @dev_id: Unused as we don't allow multiple devices. - * @regs: Unused. - * - * Handle an interrupt from the board. These are raised when the status - * map changes in what the board considers an interesting way. That means - * a failure condition occuring. - */ - -static void wdtpci_interrupt(int irq, void *dev_id, struct pt_regs *regs) -{ - /* - * Read the status register see what is up and - * then printk it. - */ - - unsigned char status=inb_p(WDT_SR); - - status|=FEATUREMAP1; - status&=~FEATUREMAP2; - - printk(KERN_CRIT "WDT status %d\n", status); - - if(!(status&WDC_SR_TGOOD)) - printk(KERN_CRIT "Overheat alarm.(%d)\n",inb_p(WDT_RT)); - if(!(status&WDC_SR_PSUOVER)) - printk(KERN_CRIT "PSU over voltage.\n"); - if(!(status&WDC_SR_PSUUNDR)) - printk(KERN_CRIT "PSU under voltage.\n"); - if(!(status&WDC_SR_FANGOOD)) - printk(KERN_CRIT "Possible fan fault.\n"); - if(!(status&WDC_SR_WCCR)) -#ifdef SOFTWARE_REBOOT -#ifdef ONLY_TESTING - printk(KERN_CRIT "Would Reboot.\n"); -#else - printk(KERN_CRIT "Initiating system reboot.\n"); - machine_restart(NULL); -#endif -#else - printk(KERN_CRIT "Reset in 5ms.\n"); -#endif -} - - -/** - * wdtpci_ping: - * - * Reload counter one with the watchdog timeout. We don't bother reloading - * the cascade counter. - */ - -static void wdtpci_ping(void) -{ - /* Write a watchdog value */ - inb_p(WDT_DC); - wdtpci_ctr_mode(1,2); - wdtpci_ctr_load(1,timeout_val); /* Timeout */ - outb_p(0, WDT_DC); -} - -/** - * wdtpci_write: - * @file: file handle to the watchdog - * @buf: buffer to write (unused as data does not matter here - * @count: count of bytes - * @ppos: pointer to the position to write. No seeks allowed - * - * A write to a watchdog device is defined as a keepalive signal. Any - * write of data will do, as we we don't define content meaning. - */ - -static ssize_t wdtpci_write(struct file *file, const char *buf, size_t count, loff_t *ppos) -{ - /* Can't seek (pwrite) on this device */ - if (ppos != &file->f_pos) - return -ESPIPE; - - if(count) - { - wdtpci_ping(); - return 1; - } - return 0; -} - -/** - * wdtpci_read: - * @file: file handle to the watchdog board - * @buf: buffer to write 1 byte into - * @count: length of buffer - * @ptr: offset (no seek allowed) - * - * Read reports the temperature in degrees Fahrenheit. The API is in - * fahrenheit. It was designed by an imperial measurement luddite. - */ - -static ssize_t wdtpci_read(struct file *file, char *buf, size_t count, loff_t *ptr) -{ - unsigned short c=inb_p(WDT_RT); - unsigned char cp; - - /* Can't seek (pread) on this device */ - if (ptr != &file->f_pos) - return -ESPIPE; - - switch(minor(file->f_dentry->d_inode->i_rdev)) - { - case TEMP_MINOR: - c*=11; - c/=15; - cp=c+7; - if(copy_to_user(buf,&cp,1)) - return -EFAULT; - return 1; - default: - return -EINVAL; - } -} - -/** - * wdtpci_ioctl: - * @inode: inode of the device - * @file: file handle to the device - * @cmd: watchdog command - * @arg: argument pointer - * - * The watchdog API defines a common set of functions for all watchdogs - * according to their available features. We only actually usefully support - * querying capabilities and current status. - */ - -static int wdtpci_ioctl(struct inode *inode, struct file *file, unsigned int cmd, - unsigned long arg) -{ - static struct watchdog_info ident = { - .options = WDIOF_OVERHEAT | WDIOF_POWERUNDER | - WDIOF_POWEROVER | WDIOF_EXTERN1 | - WDIOF_EXTERN2 | WDIOF_FANFAULT, - .firmware_version = 1, - .identity = "WDT500/501PCI", - }; - - ident.options&=WDT_OPTION_MASK; /* Mask down to the card we have */ - switch(cmd) - { - default: - return -ENOTTY; - case WDIOC_GETSUPPORT: - return copy_to_user((struct watchdog_info *)arg, &ident, sizeof(ident))?-EFAULT:0; - - case WDIOC_GETSTATUS: - return put_user(wdtpci_status(),(int *)arg); - case WDIOC_GETBOOTSTATUS: - return put_user(0, (int *)arg); - case WDIOC_KEEPALIVE: - wdtpci_ping(); - return 0; - } -} - -/** - * wdtpci_open: - * @inode: inode of device - * @file: file handle to device - * - * One of our two misc devices has been opened. The watchdog device is - * single open and on opening we load the counters. Counter zero is a - * 100Hz cascade, into counter 1 which downcounts to reboot. When the - * counter triggers counter 2 downcounts the length of the reset pulse - * which set set to be as long as possible. - */ - -static int wdtpci_open(struct inode *inode, struct file *file) -{ - switch(minor(inode->i_rdev)) - { - case WATCHDOG_MINOR: - if( test_and_set_bit(0,&wdt_is_open) ) - { - return -EBUSY; - } - if (nowayout) { - MOD_INC_USE_COUNT; - } - /* - * Activate - */ - - inb_p(WDT_DC); /* Disable */ - - /* - * "pet" the watchdog, as Access says. - * This resets the clock outputs. - */ - - wdtpci_ctr_mode(2,0); - outb_p(0, WDT_DC); - - inb_p(WDT_DC); - - outb_p(0, WDT_CLOCK); /* 2.0833MHz clock */ - inb_p(WDT_BUZZER); /* disable */ - inb_p(WDT_OPTONOTRST); /* disable */ - inb_p(WDT_OPTORST); /* disable */ - inb_p(WDT_PROGOUT); /* disable */ - wdtpci_ctr_mode(0,3); - wdtpci_ctr_mode(1,2); - wdtpci_ctr_mode(2,1); - wdtpci_ctr_load(0,20833); /* count at 100Hz */ - wdtpci_ctr_load(1,timeout_val); /* Timeout */ - /* DO NOT LOAD CTR2 on PCI card! -- JPN */ - outb_p(0, WDT_DC); /* Enable */ - return 0; - case TEMP_MINOR: - return 0; - default: - return -ENODEV; - } -} - -/** - * wdtpci_close: - * @inode: inode to board - * @file: file handle to board - * - * The watchdog has a configurable API. There is a religious dispute - * between people who want their watchdog to be able to shut down and - * those who want to be sure if the watchdog manager dies the machine - * reboots. In the former case we disable the counters, in the latter - * case you have to open it again very soon. - */ - -static int wdtpci_release(struct inode *inode, struct file *file) -{ - if(minor(inode->i_rdev)==WATCHDOG_MINOR) - { - if (!nowayout) { - inb_p(WDT_DC); /* Disable counters */ - wdtpci_ctr_load(2,0); /* 0 length reset pulses now */ - } - clear_bit(0, &wdt_is_open ); - } - return 0; -} - -/** - * notify_sys: - * @this: our notifier block - * @code: the event being reported - * @unused: unused - * - * Our notifier is called on system shutdowns. We want to turn the card - * off at reboot otherwise the machine will reboot again during memory - * test or worse yet during the following fsck. This would suck, in fact - * trust me - if it happens it does suck. - */ - -static int wdtpci_notify_sys(struct notifier_block *this, unsigned long code, - void *unused) -{ - if(code==SYS_DOWN || code==SYS_HALT) - { - /* Turn the card off */ - inb_p(WDT_DC); - wdtpci_ctr_load(2,0); - } - return NOTIFY_DONE; -} - -/* - * Kernel Interfaces - */ - - -static struct file_operations wdtpci_fops = { - .owner = THIS_MODULE, - .llseek = no_llseek, - .read = wdtpci_read, - .write = wdtpci_write, - .ioctl = wdtpci_ioctl, - .open = wdtpci_open, - .release = wdtpci_release, -}; - -static struct miscdevice wdtpci_miscdev = { - .minor = WATCHDOG_MINOR, - .name = "watchdog", - .fops = &wdtpci_fops, -}; - -#ifdef CONFIG_WDT_501 -static struct miscdevice temp_miscdev = { - .minor = TEMP_MINOR, - .name = "temperature", - .fops = &wdtpci_fops, -}; -#endif - -/* - * The WDT card needs to learn about soft shutdowns in order to - * turn the timebomb registers off. - */ - -static struct notifier_block wdtpci_notifier = { - .notifier_call = wdtpci_notify_sys, -}; - - -static int __init wdtpci_init_one (struct pci_dev *dev, - const struct pci_device_id *ent) -{ - static int dev_count = 0; - int ret = -EIO; - - dev_count++; - if (dev_count > 1) { - printk (KERN_ERR PFX - "this driver only supports 1 device\n"); - return -ENODEV; - } - - if (pci_enable_device (dev)) - goto out; - - irq = dev->irq; - io = pci_resource_start (dev, 2); - printk ("WDT501-P(PCI-WDG-CSM) driver 0.07 at %X " - "(Interrupt %d)\n", io, irq); - - if (request_region (io, 16, "wdt-pci") == NULL) { - printk (KERN_ERR PFX "I/O %d is not free.\n", io); - goto out; - } - - if (request_irq (irq, wdtpci_interrupt, SA_INTERRUPT | SA_SHIRQ, - "wdt-pci", &wdtpci_miscdev)) { - printk (KERN_ERR PFX "IRQ %d is not free.\n", irq); - goto out_reg; - } - - ret = misc_register (&wdtpci_miscdev); - if (ret) { - printk (KERN_ERR PFX "can't misc_register on minor=%d\n", WATCHDOG_MINOR); - goto out_irq; - } - - ret = register_reboot_notifier (&wdtpci_notifier); - if (ret) { - printk (KERN_ERR PFX "can't misc_register on minor=%d\n", WATCHDOG_MINOR); - goto out_misc; - } -#ifdef CONFIG_WDT_501 - ret = misc_register (&temp_miscdev); - if (ret) { - printk (KERN_ERR PFX "can't misc_register (temp) on minor=%d\n", TEMP_MINOR); - goto out_rbt; - } -#endif - - ret = 0; -out: - return ret; - -#ifdef CONFIG_WDT_501 -out_rbt: - unregister_reboot_notifier(&wdtpci_notifier); -#endif -out_misc: - misc_deregister(&wdtpci_miscdev); -out_irq: - free_irq(irq, &wdtpci_miscdev); -out_reg: - release_region (io, 16); - goto out; -} - - -static void __devexit wdtpci_remove_one (struct pci_dev *pdev) -{ - /* here we assume only one device will ever have - * been picked up and registered by probe function */ - unregister_reboot_notifier(&wdtpci_notifier); -#ifdef CONFIG_WDT_501_PCI - misc_deregister(&temp_miscdev); -#endif - misc_deregister(&wdtpci_miscdev); - free_irq(irq, &wdtpci_miscdev); - release_region(io, 16); -} - - -static struct pci_device_id wdtpci_pci_tbl[] __initdata = { - { - .vendor = PCI_VENDOR_ID_ACCESSIO, - .device = PCI_DEVICE_ID_WDG_CSM, - .subvendor = PCI_ANY_ID, - .subdevice = PCI_ANY_ID, - }, - { 0, }, /* terminate list */ -}; -MODULE_DEVICE_TABLE(pci, wdtpci_pci_tbl); - - -static struct pci_driver wdtpci_driver = { - .name = "wdt-pci", - .id_table = wdtpci_pci_tbl, - .probe = wdtpci_init_one, - .remove = __devexit_p(wdtpci_remove_one), -}; - - -/** - * wdtpci_cleanup: - * - * Unload the watchdog. You cannot do this with any file handles open. - * If your watchdog is set to continue ticking on close and you unload - * it, well it keeps ticking. We won't get the interrupt but the board - * will not touch PC memory so all is fine. You just have to load a new - * module in 60 seconds or reboot. - */ - -static void __exit wdtpci_cleanup(void) -{ - pci_unregister_driver (&wdtpci_driver); -} - - -/** - * wdtpci_init: - * - * Set up the WDT watchdog board. All we have to do is grab the - * resources we require and bitch if anyone beat us to them. - * The open() function will actually kick the board off. - */ - -static int __init wdtpci_init(void) -{ - int rc = pci_register_driver (&wdtpci_driver); - - if (rc < 1) - return -ENODEV; - - wdtpci_validate_timeout(); - - return 0; -} - - -module_init(wdtpci_init); -module_exit(wdtpci_cleanup); - -MODULE_AUTHOR("JP Nollmann, Alan Cox"); -MODULE_DESCRIPTION("Driver for the ICS PCI watchdog cards"); -MODULE_LICENSE("GPL");