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 <file:Documentation/watchdog.txt>
- in the kernel source.
-
- The watchdog is usually used together with the watchdog daemon
- which is available from
- <ftp://ibiblio.org/pub/Linux/system/daemons/watchdog/>. 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
- <file:Documentation/modules.txt>. 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 <file:Documentation/modules.txt>. 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 <file:Documentation/modules.txt>. 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 <file:Documentation/pcwd-watchdog.txt>. The PC
- watchdog cards can be ordered from <http://www.berkprod.com/>.
-
- 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 <file:Documentation/modules.txt>.
-
- 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 <file:Documentation/modules.txt>. 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 <http://www.eurotech.it/>.
-
-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=<n>" where <n> 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
- <file:Documentation/modules.txt>. 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 <file:Documentation/modules.txt>. 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 <file:Documentation/modules.txt>. 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 <file:Documentation/modules.txt>.
-
-endmenu
+source "drivers/char/watchdog/Kconfig"
config DS1620
tristate "NetWinder thermometer support"
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_WATCHDOGS) += 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
+++ /dev/null
-/*
- * Acquire Single Board Computer Watchdog Timer driver for Linux 2.1.x
- *
- * Based on wdt.c. Original copyright messages:
- *
- * (c) Copyright 1996 Alan Cox <alan@redhat.com>, 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 <alan@redhat.com>
- *
- * 14-Dec-2001 Matt Domsch <Matt_Domsch@dell.com>
- * Added nowayout module option to override CONFIG_WATCHDOG_NOWAYOUT
- * Can't add timeout - driver doesn't allow changing value
- */
-
-#include <linux/config.h>
-#include <linux/module.h>
-#include <linux/version.h>
-#include <linux/types.h>
-#include <linux/errno.h>
-#include <linux/kernel.h>
-#include <linux/sched.h>
-#include <linux/miscdevice.h>
-#include <linux/watchdog.h>
-#include <linux/slab.h>
-#include <linux/ioport.h>
-#include <linux/fcntl.h>
-#include <asm/io.h>
-#include <asm/uaccess.h>
-#include <asm/system.h>
-#include <linux/notifier.h>
-#include <linux/reboot.h>
-#include <linux/init.h>
-#include <linux/spinlock.h>
-#include <linux/smp_lock.h>
-
-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");
+++ /dev/null
-/*
- * Advantech Single Board Computer WDT driver for Linux 2.4.x
- *
- * (c) Copyright 2000-2001 Marek Michalkiewicz <marekm@linux.org.pl>
- *
- * Based on acquirewdt.c which is based on wdt.c.
- * Original copyright messages:
- *
- * (c) Copyright 1996 Alan Cox <alan@redhat.com>, 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 <alan@redhat.com>
- *
- * 14-Dec-2001 Matt Domsch <Matt_Domsch@dell.com>
- * Added nowayout module option to override CONFIG_WATCHDOG_NOWAYOUT
- * Added timeout module option to override default
- */
-
-#include <linux/config.h>
-#include <linux/module.h>
-#include <linux/version.h>
-#include <linux/types.h>
-#include <linux/errno.h>
-#include <linux/kernel.h>
-#include <linux/sched.h>
-#include <linux/miscdevice.h>
-#include <linux/watchdog.h>
-#include <linux/slab.h>
-#include <linux/ioport.h>
-#include <linux/fcntl.h>
-#include <asm/io.h>
-#include <asm/uaccess.h>
-#include <asm/system.h>
-#include <linux/notifier.h>
-#include <linux/reboot.h>
-#include <linux/init.h>
-#include <linux/spinlock.h>
-#include <linux/smp_lock.h>
-
-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 */
-
+++ /dev/null
-/*
- * Eurotech CPU-1220/1410 on board WDT driver for Linux 2.4.x
- *
- * (c) Copyright 2001 Ascensit <support@ascensit.com>
- * (c) Copyright 2001 Rodolfo Giometti <giometti@ascensit.com>
- *
- * Based on wdt.c.
- * Original copyright messages:
- *
- * (c) Copyright 1996-1997 Alan Cox <alan@redhat.com>, 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 <alan@lxorguk.ukuu.org.uk>*
- *
- * 14-Dec-2001 Matt Domsch <Matt_Domsch@dell.com>
- * Added nowayout module option to override CONFIG_WATCHDOG_NOWAYOUT
- * Added timeout module option to override default
- */
-
-#include <linux/config.h>
-#include <linux/interrupt.h>
-#include <linux/module.h>
-#include <linux/version.h>
-#include <linux/types.h>
-#include <linux/errno.h>
-#include <linux/kernel.h>
-#include <linux/miscdevice.h>
-#include <linux/watchdog.h>
-#include <linux/slab.h>
-#include <linux/ioport.h>
-#include <linux/fcntl.h>
-#include <linux/notifier.h>
-#include <linux/reboot.h>
-#include <linux/init.h>
-#include <linux/spinlock.h>
-
-#include <asm/io.h>
-#include <asm/uaccess.h>
-#include <asm/system.h>
-
-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");
+++ /dev/null
-/*
- * i810-tco 0.05: TCO timer driver for i8xx chipsets
- *
- * (c) Copyright 2000 kernel concepts <nils@kernelconcepts.de>, 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 <nils@kernelconcepts.de>
- * developed for
- * Jentro AG, Haar/Munich (Germany)
- *
- * TCO timer driver for i8xx chipsets
- * based on softdog.c by Alan Cox <alan@redhat.com>
- *
- * 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 <Matt_Domsch@dell.com>
- * 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 <rob@osinvestor.com>, 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 <linux/module.h>
-#include <linux/types.h>
-#include <linux/kernel.h>
-#include <linux/fs.h>
-#include <linux/mm.h>
-#include <linux/miscdevice.h>
-#include <linux/watchdog.h>
-#include <linux/reboot.h>
-#include <linux/init.h>
-#include <linux/pci.h>
-#include <linux/ioport.h>
-#include <asm/uaccess.h>
-#include <asm/io.h>
-#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<n<64. Default is 30 seconds */
-
-static unsigned int ACPIBASE;
-static spinlock_t tco_lock; /* Guards the hardware */
-
-static int i810_margin = TIMER_MARGIN; /* steps of 0.6sec */
-
-MODULE_PARM(i810_margin, "i");
-MODULE_PARM_DESC(i810_margin, "i810-tco timeout in steps of 0.6sec, 3<n<64. Default = 50 (30 seconds)");
-
-#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)");
-
-
-/*
- * Timer active flag
- */
-
-static unsigned long timer_alive;
-static char tco_expect_close;
-
-/*
- * Some TCO specific functions
- */
-
-
-/*
- * Start the timer countdown
- */
-static int tco_timer_start (void)
-{
- unsigned char val;
-
- spin_lock(&tco_lock);
- val = inb (TCO1_CNT + 1);
- val &= 0xf7;
- outb (val, TCO1_CNT + 1);
- val = inb (TCO1_CNT + 1);
- spin_unlock(&tco_lock);
-
- if (val & 0x08)
- return -1;
- return 0;
-}
-
-/*
- * Stop the timer countdown
- */
-static int tco_timer_stop (void)
-{
- unsigned char val;
-
- spin_lock(&tco_lock);
- val = inb (TCO1_CNT + 1);
- val |= 0x08;
- outb (val, TCO1_CNT + 1);
- val = inb (TCO1_CNT + 1);
- spin_unlock(&tco_lock);
-
- if ((val & 0x08) == 0)
- return -1;
- return 0;
-}
-
-/*
- * Set the timer reload value
- */
-static int tco_timer_settimer (unsigned char tmrval)
-{
- unsigned char val;
-
- /* from the specs: */
- /* "Values of 0h-3h are ignored and should not be attempted" */
- if (tmrval > 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");
+++ /dev/null
-/*
- * IB700 Single Board Computer WDT driver for Linux 2.4.x
- *
- * (c) Copyright 2001 Charles Howes <chowes@vsol.net>
- *
- * Based on advantechwdt.c which is based on acquirewdt.c which
- * is based on wdt.c.
- *
- * (c) Copyright 2000-2001 Marek Michalkiewicz <marekm@linux.org.pl>
- *
- * Based on acquirewdt.c which is based on wdt.c.
- * Original copyright messages:
- *
- * (c) Copyright 1996 Alan Cox <alan@redhat.com>, 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 <alan@redhat.com>
- *
- * 14-Dec-2001 Matt Domsch <Matt_Domsch@dell.com>
- * Added nowayout module option to override CONFIG_WATCHDOG_NOWAYOUT
- * Added timeout module option to override default
- *
- */
-
-#include <linux/config.h>
-#include <linux/module.h>
-#include <linux/version.h>
-#include <linux/types.h>
-#include <linux/errno.h>
-#include <linux/kernel.h>
-#include <linux/sched.h>
-#include <linux/miscdevice.h>
-#include <linux/watchdog.h>
-#include <linux/slab.h>
-#include <linux/ioport.h>
-#include <linux/fcntl.h>
-#include <asm/io.h>
-#include <asm/uaccess.h>
-#include <asm/system.h>
-#include <linux/notifier.h>
-#include <linux/reboot.h>
-#include <linux/init.h>
-#include <linux/spinlock.h>
-#include <linux/smp_lock.h>
-
-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 <chowes@vsol.net>");
-MODULE_DESCRIPTION("IB700 SBC watchdog driver");
-MODULE_LICENSE("GPL");
-
-/* end of ib700wdt.c */
+++ /dev/null
-/*
- * 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 <fuganti@conectiva.com.br>
- *
- * 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 <Matt_Domsch@dell.com>
- * Added nowayout module option to override CONFIG_WATCHDOG_NOWAYOUT
- */
-
-#include <linux/config.h>
-#include <linux/module.h>
-#include <linux/version.h>
-#include <linux/types.h>
-#include <linux/errno.h>
-#include <linux/kernel.h>
-#include <linux/timer.h>
-#include <linux/jiffies.h>
-#include <linux/miscdevice.h>
-#include <linux/watchdog.h>
-#include <linux/slab.h>
-#include <linux/ioport.h>
-#include <linux/fcntl.h>
-#include <linux/smp_lock.h>
-#include <asm/io.h>
-#include <asm/uaccess.h>
-#include <asm/system.h>
-#include <linux/notifier.h>
-#include <linux/reboot.h>
-#include <linux/init.h>
-
-
-/* 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 <fuganti@conectiva.com.br>");
-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);
+++ /dev/null
-/*
- * MixCom Watchdog: A Simple Hardware Watchdog Device
- * Based on Softdog driver by Alan Cox and PC Watchdog driver by Ken Hollis
- *
- * Author: Gergely Madarasz <gorgo@itc.hu>
- *
- * Copyright (c) 1999 ITConsult-Pro Co. <info@itc.hu>
- *
- * 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 <Matt_Domsch@dell.com>
- * - added nowayout module option to override CONFIG_WATCHDOG_NOWAYOUT
- *
- */
-
-#define VERSION "0.5"
-
-#include <linux/module.h>
-#include <linux/config.h>
-#include <linux/types.h>
-#include <linux/kernel.h>
-#include <linux/fs.h>
-#include <linux/mm.h>
-#include <linux/miscdevice.h>
-#include <linux/ioport.h>
-#include <linux/watchdog.h>
-#include <linux/reboot.h>
-#include <linux/init.h>
-#include <linux/smp_lock.h>
-#include <asm/uaccess.h>
-#include <asm/io.h>
-
-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");
+++ /dev/null
-/*
- * 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 <meskes@debian.org>.
- * 980112 Used minor numbers from include/linux/miscdevice.h
- * 990403 Clear reset status after reading control status register in
- * pcwd_showprevstate(). [Marc Boucher <marc@mbsi.ca>]
- * 990605 Made changes to code to support Firmware 1.22a, added
- * fairly useless proc entry.
- * 990610 removed said useless proc code for the merge <alan>
- * 000403 Removed last traces of proc code. <davej>
- */
-
-#include <linux/module.h>
-
-#include <linux/types.h>
-#include <linux/errno.h>
-#include <linux/sched.h>
-#include <linux/tty.h>
-#include <linux/timer.h>
-#include <linux/config.h>
-#include <linux/kernel.h>
-#include <linux/wait.h>
-#include <linux/string.h>
-#include <linux/slab.h>
-#include <linux/ioport.h>
-#include <linux/delay.h>
-#include <linux/miscdevice.h>
-#include <linux/fs.h>
-#include <linux/mm.h>
-#include <linux/watchdog.h>
-#include <linux/init.h>
-#include <linux/proc_fs.h>
-#include <linux/spinlock.h>
-#include <linux/smp_lock.h>
-
-#include <asm/uaccess.h>
-#include <asm/io.h>
-
-/*
- * 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");
-
+++ /dev/null
-/*
- * 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 <jakob@ostenfeld.dk>
- *
- * 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 <linux/module.h>
-#include <linux/version.h>
-#include <linux/types.h>
-#include <linux/errno.h>
-#include <linux/kernel.h>
-#include <linux/timer.h>
-#include <linux/jiffies.h>
-#include <linux/miscdevice.h>
-#include <linux/watchdog.h>
-#include <linux/slab.h>
-#include <linux/ioport.h>
-#include <linux/fcntl.h>
-#include <linux/smp_lock.h>
-#include <asm/io.h>
-#include <asm/uaccess.h>
-#include <asm/system.h>
-#include <linux/notifier.h>
-#include <linux/reboot.h>
-#include <linux/init.h>
-
-#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");
+++ /dev/null
-/* linux/drivers/char/scx200_wdt.c
-
- National Semiconductor SCx200 Watchdog support
-
- Copyright (c) 2001,2002 Christer Weinigel <wingel@nano-system.com>
-
- Som code taken from:
- National Semiconductor PC87307/PC97307 (ala SC1200) WDT driver
- (c) Copyright 2002 Zwane Mwaikambo <zwane@commfireservices.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.
-
- 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 <linux/config.h>
-#include <linux/module.h>
-#include <linux/errno.h>
-#include <linux/kernel.h>
-#include <linux/init.h>
-#include <linux/miscdevice.h>
-#include <linux/watchdog.h>
-#include <linux/notifier.h>
-#include <linux/reboot.h>
-#include <linux/pci.h>
-#include <asm/uaccess.h>
-#include <asm/io.h>
-
-#include <linux/scx200.h>
-
-#define NAME "scx200_wdt"
-
-MODULE_AUTHOR("Christer Weinigel <wingel@nano-system.com>");
-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:
-*/
+++ /dev/null
-/*
- * drivers/char/shwdt.c
- *
- * Watchdog driver for integrated watchdog in the SuperH 3/4 processors.
- *
- * Copyright (C) 2001 Paul Mundt <lethal@chaoticdreams.org>
- *
- * 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 <Matt_Domsch@dell.com>
- * Added nowayout module option to override CONFIG_WATCHDOG_NOWAYOUT
- */
-#include <linux/config.h>
-#include <linux/module.h>
-#include <linux/init.h>
-#include <linux/kernel.h>
-#include <linux/types.h>
-#include <linux/miscdevice.h>
-#include <linux/watchdog.h>
-#include <linux/reboot.h>
-#include <linux/notifier.h>
-#include <linux/ioport.h>
-
-#include <asm/io.h>
-#include <asm/uaccess.h>
-
-#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 <lethal@chaoticdreams.org>");
-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);
-
+++ /dev/null
-/*
- * SoftDog 0.06: A Software Watchdog Device
- *
- * (c) Copyright 1996 Alan Cox <alan@redhat.com>, 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 <alan@lxorguk.ukuu.org.uk>
- *
- * Software only watchdog driver. Unlike its big brother the WDT501P
- * driver this won't always recover a failed machine.
- *
- * 03/96: Angelo Haritsis <ah@doc.ic.ac.uk> :
- * 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 <Matt_Domsch@dell.com>
- * Added nowayout module option to override CONFIG_WATCHDOG_NOWAYOUT
- * Didn't add timeout option, as soft_margin option already exists.
- */
-
-#include <linux/module.h>
-#include <linux/config.h>
-#include <linux/types.h>
-#include <linux/kernel.h>
-#include <linux/fs.h>
-#include <linux/mm.h>
-#include <linux/miscdevice.h>
-#include <linux/watchdog.h>
-#include <linux/reboot.h>
-#include <linux/smp_lock.h>
-#include <linux/init.h>
-#include <asm/uaccess.h>
-
-#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);
+++ /dev/null
-/*
- * W83877F Computer Watchdog Timer driver for Linux 2.4.x
- *
- * Based on acquirewdt.c by Alan Cox,
- * and sbc60xxwdt.c by Jakob Oestergaard <jakob@ostenfeld.dk>
- *
- * 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 <linuxdrivers@oro.net>
- *
- * 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 <linux/module.h>
-#include <linux/version.h>
-#include <linux/types.h>
-#include <linux/errno.h>
-#include <linux/kernel.h>
-#include <linux/timer.h>
-#include <linux/jiffies.h>
-#include <linux/miscdevice.h>
-#include <linux/watchdog.h>
-#include <linux/slab.h>
-#include <linux/ioport.h>
-#include <linux/fcntl.h>
-#include <linux/smp_lock.h>
-#include <asm/io.h>
-#include <asm/uaccess.h>
-#include <asm/system.h>
-#include <linux/notifier.h>
-#include <linux/reboot.h>
-#include <linux/init.h>
-
-#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;
--- /dev/null
+#
+# 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 <file:Documentation/watchdog.txt>
+ in the kernel source.
+
+ The watchdog is usually used together with the watchdog daemon
+ which is available from
+ <ftp://ibiblio.org/pub/Linux/system/daemons/watchdog/>. 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
+ <file:Documentation/modules.txt>. 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 <file:Documentation/modules.txt>. 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 <file:Documentation/modules.txt>. 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 <file:Documentation/pcwd-watchdog.txt>. The PC
+ watchdog cards can be ordered from <http://www.berkprod.com/>.
+
+ 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 <file:Documentation/modules.txt>.
+
+ 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 <file:Documentation/modules.txt>. 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 <http://www.eurotech.it/>.
+
+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=<n>" where <n> 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
+ <file:Documentation/modules.txt>. 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 <file:Documentation/modules.txt>. 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 <file:Documentation/modules.txt>. 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 <file:Documentation/modules.txt>.
+
+endmenu
--- /dev/null
+#
+# 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.
+
+watchdog-$(CONFIG_PCWATCHDOG) += pcwd.o
+watchdog-$(CONFIG_ACQUIRE_WDT) += acquirewdt.o
+watchdog-$(CONFIG_ADVANTECH_WDT) += advantechwdt.o
+watchdog-$(CONFIG_IB700_WDT) += ib700wdt.o
+watchdog-$(CONFIG_MIXCOMWD) += mixcomwd.o
+watchdog-$(CONFIG_SCx200_WDT) += scx200_wdt.o
+watchdog-$(CONFIG_60XX_WDT) += sbc60xxwdt.o
+watchdog-$(CONFIG_WDT) += wdt.o
+watchdog-$(CONFIG_WDTPCI) += wdt_pci.o
+watchdog-$(CONFIG_21285_WATCHDOG) += wdt285.o
+watchdog-$(CONFIG_977_WATCHDOG) += wdt977.o
+watchdog-$(CONFIG_I810_TCO) += i810-tco.o
+watchdog-$(CONFIG_MACHZ_WDT) += machzwd.o
+watchdog-$(CONFIG_SH_WDT) += shwdt.o
+watchdog-$(CONFIG_EUROTECH_WDT) += eurotechwdt.o
+watchdog-$(CONFIG_SOFT_WATCHDOG) += softdog.o
+
+include $(TOPDIR)/Rules.make
--- /dev/null
+/*
+ * Acquire Single Board Computer Watchdog Timer driver for Linux 2.1.x
+ *
+ * Based on wdt.c. Original copyright messages:
+ *
+ * (c) Copyright 1996 Alan Cox <alan@redhat.com>, 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 <alan@redhat.com>
+ *
+ * 14-Dec-2001 Matt Domsch <Matt_Domsch@dell.com>
+ * Added nowayout module option to override CONFIG_WATCHDOG_NOWAYOUT
+ * Can't add timeout - driver doesn't allow changing value
+ */
+
+#include <linux/config.h>
+#include <linux/module.h>
+#include <linux/version.h>
+#include <linux/types.h>
+#include <linux/errno.h>
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/miscdevice.h>
+#include <linux/watchdog.h>
+#include <linux/slab.h>
+#include <linux/ioport.h>
+#include <linux/fcntl.h>
+#include <asm/io.h>
+#include <asm/uaccess.h>
+#include <asm/system.h>
+#include <linux/notifier.h>
+#include <linux/reboot.h>
+#include <linux/init.h>
+#include <linux/spinlock.h>
+#include <linux/smp_lock.h>
+
+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");
--- /dev/null
+/*
+ * Advantech Single Board Computer WDT driver for Linux 2.4.x
+ *
+ * (c) Copyright 2000-2001 Marek Michalkiewicz <marekm@linux.org.pl>
+ *
+ * Based on acquirewdt.c which is based on wdt.c.
+ * Original copyright messages:
+ *
+ * (c) Copyright 1996 Alan Cox <alan@redhat.com>, 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 <alan@redhat.com>
+ *
+ * 14-Dec-2001 Matt Domsch <Matt_Domsch@dell.com>
+ * Added nowayout module option to override CONFIG_WATCHDOG_NOWAYOUT
+ * Added timeout module option to override default
+ */
+
+#include <linux/config.h>
+#include <linux/module.h>
+#include <linux/version.h>
+#include <linux/types.h>
+#include <linux/errno.h>
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/miscdevice.h>
+#include <linux/watchdog.h>
+#include <linux/slab.h>
+#include <linux/ioport.h>
+#include <linux/fcntl.h>
+#include <asm/io.h>
+#include <asm/uaccess.h>
+#include <asm/system.h>
+#include <linux/notifier.h>
+#include <linux/reboot.h>
+#include <linux/init.h>
+#include <linux/spinlock.h>
+#include <linux/smp_lock.h>
+
+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 */
+
--- /dev/null
+/*
+ * Eurotech CPU-1220/1410 on board WDT driver for Linux 2.4.x
+ *
+ * (c) Copyright 2001 Ascensit <support@ascensit.com>
+ * (c) Copyright 2001 Rodolfo Giometti <giometti@ascensit.com>
+ *
+ * Based on wdt.c.
+ * Original copyright messages:
+ *
+ * (c) Copyright 1996-1997 Alan Cox <alan@redhat.com>, 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 <alan@lxorguk.ukuu.org.uk>*
+ *
+ * 14-Dec-2001 Matt Domsch <Matt_Domsch@dell.com>
+ * Added nowayout module option to override CONFIG_WATCHDOG_NOWAYOUT
+ * Added timeout module option to override default
+ */
+
+#include <linux/config.h>
+#include <linux/interrupt.h>
+#include <linux/module.h>
+#include <linux/version.h>
+#include <linux/types.h>
+#include <linux/errno.h>
+#include <linux/kernel.h>
+#include <linux/miscdevice.h>
+#include <linux/watchdog.h>
+#include <linux/slab.h>
+#include <linux/ioport.h>
+#include <linux/fcntl.h>
+#include <linux/notifier.h>
+#include <linux/reboot.h>
+#include <linux/init.h>
+#include <linux/spinlock.h>
+
+#include <asm/io.h>
+#include <asm/uaccess.h>
+#include <asm/system.h>
+
+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");
--- /dev/null
+/*
+ * i810-tco 0.05: TCO timer driver for i8xx chipsets
+ *
+ * (c) Copyright 2000 kernel concepts <nils@kernelconcepts.de>, 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 <nils@kernelconcepts.de>
+ * developed for
+ * Jentro AG, Haar/Munich (Germany)
+ *
+ * TCO timer driver for i8xx chipsets
+ * based on softdog.c by Alan Cox <alan@redhat.com>
+ *
+ * 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 <Matt_Domsch@dell.com>
+ * 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 <rob@osinvestor.com>, 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 <linux/module.h>
+#include <linux/types.h>
+#include <linux/kernel.h>
+#include <linux/fs.h>
+#include <linux/mm.h>
+#include <linux/miscdevice.h>
+#include <linux/watchdog.h>
+#include <linux/reboot.h>
+#include <linux/init.h>
+#include <linux/pci.h>
+#include <linux/ioport.h>
+#include <asm/uaccess.h>
+#include <asm/io.h>
+#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<n<64. Default is 30 seconds */
+
+static unsigned int ACPIBASE;
+static spinlock_t tco_lock; /* Guards the hardware */
+
+static int i810_margin = TIMER_MARGIN; /* steps of 0.6sec */
+
+MODULE_PARM(i810_margin, "i");
+MODULE_PARM_DESC(i810_margin, "i810-tco timeout in steps of 0.6sec, 3<n<64. Default = 50 (30 seconds)");
+
+#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)");
+
+
+/*
+ * Timer active flag
+ */
+
+static unsigned long timer_alive;
+static char tco_expect_close;
+
+/*
+ * Some TCO specific functions
+ */
+
+
+/*
+ * Start the timer countdown
+ */
+static int tco_timer_start (void)
+{
+ unsigned char val;
+
+ spin_lock(&tco_lock);
+ val = inb (TCO1_CNT + 1);
+ val &= 0xf7;
+ outb (val, TCO1_CNT + 1);
+ val = inb (TCO1_CNT + 1);
+ spin_unlock(&tco_lock);
+
+ if (val & 0x08)
+ return -1;
+ return 0;
+}
+
+/*
+ * Stop the timer countdown
+ */
+static int tco_timer_stop (void)
+{
+ unsigned char val;
+
+ spin_lock(&tco_lock);
+ val = inb (TCO1_CNT + 1);
+ val |= 0x08;
+ outb (val, TCO1_CNT + 1);
+ val = inb (TCO1_CNT + 1);
+ spin_unlock(&tco_lock);
+
+ if ((val & 0x08) == 0)
+ return -1;
+ return 0;
+}
+
+/*
+ * Set the timer reload value
+ */
+static int tco_timer_settimer (unsigned char tmrval)
+{
+ unsigned char val;
+
+ /* from the specs: */
+ /* "Values of 0h-3h are ignored and should not be attempted" */
+ if (tmrval > 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");
--- /dev/null
+/*
+ * IB700 Single Board Computer WDT driver for Linux 2.4.x
+ *
+ * (c) Copyright 2001 Charles Howes <chowes@vsol.net>
+ *
+ * Based on advantechwdt.c which is based on acquirewdt.c which
+ * is based on wdt.c.
+ *
+ * (c) Copyright 2000-2001 Marek Michalkiewicz <marekm@linux.org.pl>
+ *
+ * Based on acquirewdt.c which is based on wdt.c.
+ * Original copyright messages:
+ *
+ * (c) Copyright 1996 Alan Cox <alan@redhat.com>, 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 <alan@redhat.com>
+ *
+ * 14-Dec-2001 Matt Domsch <Matt_Domsch@dell.com>
+ * Added nowayout module option to override CONFIG_WATCHDOG_NOWAYOUT
+ * Added timeout module option to override default
+ *
+ */
+
+#include <linux/config.h>
+#include <linux/module.h>
+#include <linux/version.h>
+#include <linux/types.h>
+#include <linux/errno.h>
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/miscdevice.h>
+#include <linux/watchdog.h>
+#include <linux/slab.h>
+#include <linux/ioport.h>
+#include <linux/fcntl.h>
+#include <asm/io.h>
+#include <asm/uaccess.h>
+#include <asm/system.h>
+#include <linux/notifier.h>
+#include <linux/reboot.h>
+#include <linux/init.h>
+#include <linux/spinlock.h>
+#include <linux/smp_lock.h>
+
+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 <chowes@vsol.net>");
+MODULE_DESCRIPTION("IB700 SBC watchdog driver");
+MODULE_LICENSE("GPL");
+
+/* end of ib700wdt.c */
--- /dev/null
+/*
+ * 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 <fuganti@conectiva.com.br>
+ *
+ * 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 <Matt_Domsch@dell.com>
+ * Added nowayout module option to override CONFIG_WATCHDOG_NOWAYOUT
+ */
+
+#include <linux/config.h>
+#include <linux/module.h>
+#include <linux/version.h>
+#include <linux/types.h>
+#include <linux/errno.h>
+#include <linux/kernel.h>
+#include <linux/timer.h>
+#include <linux/jiffies.h>
+#include <linux/miscdevice.h>
+#include <linux/watchdog.h>
+#include <linux/slab.h>
+#include <linux/ioport.h>
+#include <linux/fcntl.h>
+#include <linux/smp_lock.h>
+#include <asm/io.h>
+#include <asm/uaccess.h>
+#include <asm/system.h>
+#include <linux/notifier.h>
+#include <linux/reboot.h>
+#include <linux/init.h>
+
+
+/* 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 <fuganti@conectiva.com.br>");
+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);
--- /dev/null
+/*
+ * MixCom Watchdog: A Simple Hardware Watchdog Device
+ * Based on Softdog driver by Alan Cox and PC Watchdog driver by Ken Hollis
+ *
+ * Author: Gergely Madarasz <gorgo@itc.hu>
+ *
+ * Copyright (c) 1999 ITConsult-Pro Co. <info@itc.hu>
+ *
+ * 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 <Matt_Domsch@dell.com>
+ * - added nowayout module option to override CONFIG_WATCHDOG_NOWAYOUT
+ *
+ */
+
+#define VERSION "0.5"
+
+#include <linux/module.h>
+#include <linux/config.h>
+#include <linux/types.h>
+#include <linux/kernel.h>
+#include <linux/fs.h>
+#include <linux/mm.h>
+#include <linux/miscdevice.h>
+#include <linux/ioport.h>
+#include <linux/watchdog.h>
+#include <linux/reboot.h>
+#include <linux/init.h>
+#include <linux/smp_lock.h>
+#include <asm/uaccess.h>
+#include <asm/io.h>
+
+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");
--- /dev/null
+/*
+ * 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 <meskes@debian.org>.
+ * 980112 Used minor numbers from include/linux/miscdevice.h
+ * 990403 Clear reset status after reading control status register in
+ * pcwd_showprevstate(). [Marc Boucher <marc@mbsi.ca>]
+ * 990605 Made changes to code to support Firmware 1.22a, added
+ * fairly useless proc entry.
+ * 990610 removed said useless proc code for the merge <alan>
+ * 000403 Removed last traces of proc code. <davej>
+ */
+
+#include <linux/module.h>
+
+#include <linux/types.h>
+#include <linux/errno.h>
+#include <linux/sched.h>
+#include <linux/tty.h>
+#include <linux/timer.h>
+#include <linux/config.h>
+#include <linux/kernel.h>
+#include <linux/wait.h>
+#include <linux/string.h>
+#include <linux/slab.h>
+#include <linux/ioport.h>
+#include <linux/delay.h>
+#include <linux/miscdevice.h>
+#include <linux/fs.h>
+#include <linux/mm.h>
+#include <linux/watchdog.h>
+#include <linux/init.h>
+#include <linux/proc_fs.h>
+#include <linux/spinlock.h>
+#include <linux/smp_lock.h>
+
+#include <asm/uaccess.h>
+#include <asm/io.h>
+
+/*
+ * 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");
+
--- /dev/null
+/*
+ * 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 <jakob@ostenfeld.dk>
+ *
+ * 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 <linux/module.h>
+#include <linux/version.h>
+#include <linux/types.h>
+#include <linux/errno.h>
+#include <linux/kernel.h>
+#include <linux/timer.h>
+#include <linux/jiffies.h>
+#include <linux/miscdevice.h>
+#include <linux/watchdog.h>
+#include <linux/slab.h>
+#include <linux/ioport.h>
+#include <linux/fcntl.h>
+#include <linux/smp_lock.h>
+#include <asm/io.h>
+#include <asm/uaccess.h>
+#include <asm/system.h>
+#include <linux/notifier.h>
+#include <linux/reboot.h>
+#include <linux/init.h>
+
+#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");
--- /dev/null
+/* linux/drivers/char/scx200_wdt.c
+
+ National Semiconductor SCx200 Watchdog support
+
+ Copyright (c) 2001,2002 Christer Weinigel <wingel@nano-system.com>
+
+ Som code taken from:
+ National Semiconductor PC87307/PC97307 (ala SC1200) WDT driver
+ (c) Copyright 2002 Zwane Mwaikambo <zwane@commfireservices.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.
+
+ 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 <linux/config.h>
+#include <linux/module.h>
+#include <linux/errno.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/miscdevice.h>
+#include <linux/watchdog.h>
+#include <linux/notifier.h>
+#include <linux/reboot.h>
+#include <linux/pci.h>
+#include <asm/uaccess.h>
+#include <asm/io.h>
+
+#include <linux/scx200.h>
+
+#define NAME "scx200_wdt"
+
+MODULE_AUTHOR("Christer Weinigel <wingel@nano-system.com>");
+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:
+*/
--- /dev/null
+/*
+ * drivers/char/shwdt.c
+ *
+ * Watchdog driver for integrated watchdog in the SuperH 3/4 processors.
+ *
+ * Copyright (C) 2001 Paul Mundt <lethal@chaoticdreams.org>
+ *
+ * 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 <Matt_Domsch@dell.com>
+ * Added nowayout module option to override CONFIG_WATCHDOG_NOWAYOUT
+ */
+#include <linux/config.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/types.h>
+#include <linux/miscdevice.h>
+#include <linux/watchdog.h>
+#include <linux/reboot.h>
+#include <linux/notifier.h>
+#include <linux/ioport.h>
+
+#include <asm/io.h>
+#include <asm/uaccess.h>
+
+#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 <lethal@chaoticdreams.org>");
+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);
+
--- /dev/null
+/*
+ * SoftDog 0.06: A Software Watchdog Device
+ *
+ * (c) Copyright 1996 Alan Cox <alan@redhat.com>, 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 <alan@lxorguk.ukuu.org.uk>
+ *
+ * Software only watchdog driver. Unlike its big brother the WDT501P
+ * driver this won't always recover a failed machine.
+ *
+ * 03/96: Angelo Haritsis <ah@doc.ic.ac.uk> :
+ * 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 <Matt_Domsch@dell.com>
+ * Added nowayout module option to override CONFIG_WATCHDOG_NOWAYOUT
+ * Didn't add timeout option, as soft_margin option already exists.
+ */
+
+#include <linux/module.h>
+#include <linux/config.h>
+#include <linux/types.h>
+#include <linux/kernel.h>
+#include <linux/fs.h>
+#include <linux/mm.h>
+#include <linux/miscdevice.h>
+#include <linux/watchdog.h>
+#include <linux/reboot.h>
+#include <linux/smp_lock.h>
+#include <linux/init.h>
+#include <asm/uaccess.h>
+
+#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);
--- /dev/null
+/*
+ * W83877F Computer Watchdog Timer driver for Linux 2.4.x
+ *
+ * Based on acquirewdt.c by Alan Cox,
+ * and sbc60xxwdt.c by Jakob Oestergaard <jakob@ostenfeld.dk>
+ *
+ * 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 <linuxdrivers@oro.net>
+ *
+ * 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 <linux/module.h>
+#include <linux/version.h>
+#include <linux/types.h>
+#include <linux/errno.h>
+#include <linux/kernel.h>
+#include <linux/timer.h>
+#include <linux/jiffies.h>
+#include <linux/miscdevice.h>
+#include <linux/watchdog.h>
+#include <linux/slab.h>
+#include <linux/ioport.h>
+#include <linux/fcntl.h>
+#include <linux/smp_lock.h>
+#include <asm/io.h>
+#include <asm/uaccess.h>
+#include <asm/system.h>
+#include <linux/notifier.h>
+#include <linux/reboot.h>
+#include <linux/init.h>
+
+#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;
--- /dev/null
+/*
+ * Industrial Computer Source WDT500/501 driver for Linux 2.1.x
+ *
+ * (c) Copyright 1996-1997 Alan Cox <alan@redhat.com>, 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 <alan@lxorguk.ukuu.org.uk>
+ *
+ * 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 <linux/config.h>
+#include <linux/interrupt.h>
+#include <linux/module.h>
+#include <linux/version.h>
+#include <linux/types.h>
+#include <linux/errno.h>
+#include <linux/kernel.h>
+#include <linux/miscdevice.h>
+#include <linux/watchdog.h>
+#include "wd501p.h"
+#include <linux/slab.h>
+#include <linux/ioport.h>
+#include <linux/fcntl.h>
+#include <linux/notifier.h>
+#include <linux/reboot.h>
+#include <linux/init.h>
+
+#include <asm/io.h>
+#include <asm/uaccess.h>
+#include <asm/system.h>
+
+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");
--- /dev/null
+/*
+ * Intel 21285 watchdog driver
+ * Copyright (c) Phil Blundell <pb@nexus.co.uk>, 1998
+ *
+ * based on
+ *
+ * SoftDog 0.05: A Software Watchdog Device
+ *
+ * (c) Copyright 1996 Alan Cox <alan@redhat.com>, 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 <linux/module.h>
+#include <linux/types.h>
+#include <linux/kernel.h>
+#include <linux/fs.h>
+#include <linux/mm.h>
+#include <linux/miscdevice.h>
+#include <linux/watchdog.h>
+#include <linux/reboot.h>
+#include <linux/init.h>
+#include <linux/interrupt.h>
+#include <linux/smp_lock.h>
+
+#include <asm/irq.h>
+#include <asm/uaccess.h>
+#include <asm/hardware.h>
+#include <asm/mach-types.h>
+#include <asm/hardware/dec21285.h>
+
+/*
+ * 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 <pb@nexus.co.uk>");
+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);
--- /dev/null
+/*
+ * Wdt977 0.02: A Watchdog Device for Netwinder W83977AF chip
+ *
+ * (c) Copyright 1998 Rebel.com (Woody Suwalski <woody@netwinder.org>)
+ *
+ * -----------------------
+ *
+ * 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 <Matt_Domsch@dell.com>
+ * 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 <linux/module.h>
+#include <linux/config.h>
+#include <linux/types.h>
+#include <linux/kernel.h>
+#include <linux/fs.h>
+#include <linux/miscdevice.h>
+#include <linux/init.h>
+#include <linux/smp_lock.h>
+#include <linux/watchdog.h>
+
+#include <asm/io.h>
+#include <asm/system.h>
+#include <asm/mach-types.h>
+#include <asm/uaccess.h>
+
+#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");
--- /dev/null
+/*
+ * Industrial Computer Source WDT500/501 driver for Linux 2.1.x
+ *
+ * (c) Copyright 1996-1997 Alan Cox <alan@redhat.com>, 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 <alan@lxorguk.ukuu.org.uk>
+ *
+ * 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 <linux/config.h>
+#include <linux/interrupt.h>
+#include <linux/module.h>
+#include <linux/version.h>
+#include <linux/types.h>
+#include <linux/errno.h>
+#include <linux/kernel.h>
+#include <linux/miscdevice.h>
+#include <linux/watchdog.h>
+#include <linux/slab.h>
+#include <linux/ioport.h>
+#include <linux/fcntl.h>
+#include <linux/notifier.h>
+#include <linux/reboot.h>
+#include <linux/init.h>
+#include <linux/pci.h>
+
+#include <asm/io.h>
+#include <asm/uaccess.h>
+#include <asm/system.h>
+
+#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");
+++ /dev/null
-/*
- * Industrial Computer Source WDT500/501 driver for Linux 2.1.x
- *
- * (c) Copyright 1996-1997 Alan Cox <alan@redhat.com>, 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 <alan@lxorguk.ukuu.org.uk>
- *
- * 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 <linux/config.h>
-#include <linux/interrupt.h>
-#include <linux/module.h>
-#include <linux/version.h>
-#include <linux/types.h>
-#include <linux/errno.h>
-#include <linux/kernel.h>
-#include <linux/miscdevice.h>
-#include <linux/watchdog.h>
-#include "wd501p.h"
-#include <linux/slab.h>
-#include <linux/ioport.h>
-#include <linux/fcntl.h>
-#include <linux/notifier.h>
-#include <linux/reboot.h>
-#include <linux/init.h>
-
-#include <asm/io.h>
-#include <asm/uaccess.h>
-#include <asm/system.h>
-
-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");
+++ /dev/null
-/*
- * Intel 21285 watchdog driver
- * Copyright (c) Phil Blundell <pb@nexus.co.uk>, 1998
- *
- * based on
- *
- * SoftDog 0.05: A Software Watchdog Device
- *
- * (c) Copyright 1996 Alan Cox <alan@redhat.com>, 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 <linux/module.h>
-#include <linux/types.h>
-#include <linux/kernel.h>
-#include <linux/fs.h>
-#include <linux/mm.h>
-#include <linux/miscdevice.h>
-#include <linux/watchdog.h>
-#include <linux/reboot.h>
-#include <linux/init.h>
-#include <linux/interrupt.h>
-#include <linux/smp_lock.h>
-
-#include <asm/irq.h>
-#include <asm/uaccess.h>
-#include <asm/hardware.h>
-#include <asm/mach-types.h>
-#include <asm/hardware/dec21285.h>
-
-/*
- * 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 <pb@nexus.co.uk>");
-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);
+++ /dev/null
-/*
- * Wdt977 0.02: A Watchdog Device for Netwinder W83977AF chip
- *
- * (c) Copyright 1998 Rebel.com (Woody Suwalski <woody@netwinder.org>)
- *
- * -----------------------
- *
- * 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 <Matt_Domsch@dell.com>
- * 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 <linux/module.h>
-#include <linux/config.h>
-#include <linux/types.h>
-#include <linux/kernel.h>
-#include <linux/fs.h>
-#include <linux/miscdevice.h>
-#include <linux/init.h>
-#include <linux/smp_lock.h>
-#include <linux/watchdog.h>
-
-#include <asm/io.h>
-#include <asm/system.h>
-#include <asm/mach-types.h>
-#include <asm/uaccess.h>
-
-#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");
+++ /dev/null
-/*
- * Industrial Computer Source WDT500/501 driver for Linux 2.1.x
- *
- * (c) Copyright 1996-1997 Alan Cox <alan@redhat.com>, 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 <alan@lxorguk.ukuu.org.uk>
- *
- * 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 <linux/config.h>
-#include <linux/interrupt.h>
-#include <linux/module.h>
-#include <linux/version.h>
-#include <linux/types.h>
-#include <linux/errno.h>
-#include <linux/kernel.h>
-#include <linux/miscdevice.h>
-#include <linux/watchdog.h>
-#include <linux/slab.h>
-#include <linux/ioport.h>
-#include <linux/fcntl.h>
-#include <linux/notifier.h>
-#include <linux/reboot.h>
-#include <linux/init.h>
-#include <linux/pci.h>
-
-#include <asm/io.h>
-#include <asm/uaccess.h>
-#include <asm/system.h>
-
-#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");