Linux-2.6.12-rc2

Initial git repository build. I'm not bothering with the full history,
even though we have it. We can create a separate "historical" git
archive of that later if we want to, and in the meantime it's about
3.2GB when imported into git - space that would just make the early
git days unnecessarily complicated, when we don't have a lot of good
infrastructure for it.

Let it rip!
diff --git a/drivers/char/watchdog/Kconfig b/drivers/char/watchdog/Kconfig
new file mode 100644
index 0000000..06a31da
--- /dev/null
+++ b/drivers/char/watchdog/Kconfig
@@ -0,0 +1,549 @@
+#
+# Watchdog 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/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.
+
+#
+# General Watchdog drivers
+#
+
+comment "Watchdog Device Drivers"
+	depends on WATCHDOG
+
+# Architecture Independant
+
+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.
+
+	  To compile this driver as a module, choose M here: the
+	  module will be called softdog.
+
+# ARM Architecture
+
+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.
+
+	  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.
+
+	  Not sure? It's safe to say N.
+
+config IXP4XX_WATCHDOG
+	tristate "IXP4xx Watchdog"
+	depends on WATCHDOG && ARCH_IXP4XX
+	help
+	  Say Y here if to include support for the watchdog timer
+	  in the Intel IXP4xx network processors. This driver can
+	  be built as a module by choosing M. The module will
+	  be called ixp4xx_wdt.
+
+	  Note: The internal IXP4xx watchdog does a soft CPU reset
+	  which doesn't reset any peripherals. There are circumstances
+	  where the watchdog will fail to reset the board correctly
+	  (e.g., if the boot ROM is in an unreadable state).
+
+	  Say N if you are unsure.
+
+config IXP2000_WATCHDOG
+	tristate "IXP2000 Watchdog"
+	depends on WATCHDOG && ARCH_IXP2000
+	help
+	  Say Y here if to include support for the watchdog timer
+	  in the Intel IXP2000(2400, 2800, 2850) network processors.
+	  This driver can be built as a module by choosing M. The module
+	  will be called ixp2000_wdt.
+
+	  Say N if you are unsure.
+
+config S3C2410_WATCHDOG
+	tristate "S3C2410 Watchdog"
+	depends on WATCHDOG && ARCH_S3C2410
+	help
+	  Watchdog timer block in the Samsung S3C2410 chips. This will
+	  reboot the system when the timer expires with the watchdog
+	  enabled.
+
+	  The driver is limited by the speed of the system's PCLK
+	  signal, so with reasonbaly fast systems (PCLK around 50-66MHz)
+	  then watchdog intervals of over approximately 20seconds are
+	  unavailable.
+
+	  The driver can be built as a module by choosing M, and will
+	  be called s3c2410_wdt
+
+config SA1100_WATCHDOG
+	tristate "SA1100/PXA2xx watchdog"
+	depends on WATCHDOG && ( ARCH_SA1100 || ARCH_PXA )
+	help
+	  Watchdog timer embedded into SA11x0 and PXA2xx chips. This will
+	  reboot your system when timeout is reached.
+
+	  NOTE: once enabled, this timer cannot be disabled.
+
+	  To compile this driver as a module, choose M here: the
+	  module will be called sa1100_wdt.
+
+# X86 (i386 + ia64 + x86_64) Architecture
+
+config ACQUIRE_WDT
+	tristate "Acquire SBC Watchdog Timer"
+	depends on WATCHDOG && X86
+	---help---
+	  This is the driver for the hardware watchdog on Single Board
+	  Computers 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.
+
+	  To compile this driver as a module, choose M here: the
+	  module will be called acquirewdt.
+
+	  Most people will say N.
+
+config ADVANTECH_WDT
+	tristate "Advantech SBC Watchdog Timer"
+	depends on WATCHDOG && X86
+	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. More information can be found at
+	  <http://www.advantech.com.tw/products/>
+
+config ALIM1535_WDT
+	tristate "ALi M1535 PMU Watchdog Timer"
+	depends on WATCHDOG && X86 && PCI
+	---help---
+	  This is the driver for the hardware watchdog on the ALi M1535 PMU.
+
+	  To compile this driver as a module, choose M here: the
+	  module will be called alim1535_wdt.
+
+	  Most people will say N.
+
+config ALIM7101_WDT
+	tristate "ALi M7101 PMU Computer Watchdog"
+	depends on WATCHDOG && X86 && PCI
+	help
+	  This is the driver for the hardware watchdog on the ALi M7101 PMU
+	  as used in the x86 Cobalt servers.
+
+	  To compile this driver as a module, choose M here: the
+	  module will be called alim7101_wdt.
+
+	  Most people will say N.
+
+config SC520_WDT
+	tristate "AMD Elan SC520 processor Watchdog"
+	depends on WATCHDOG && X86
+	help
+	  This is the driver for the hardware watchdog built in to the
+	  AMD "Elan" SC520 microcomputer commonly used in embedded systems.
+	  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.
+
+	  You can compile this driver directly into the kernel, or use
+	  it as a module.  The module will be called sc520_wdt.
+
+config EUROTECH_WDT
+	tristate "Eurotech CPU-1220/1410 Watchdog Timer"
+	depends on WATCHDOG && X86
+	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 && X86
+	---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.
+
+	  To compile this driver as a module, choose M here: the
+	  module will be called ib700wdt.
+
+	  Most people will say N.
+
+config WAFER_WDT
+	tristate "ICP Wafer 5823 Single Board Computer Watchdog"
+	depends on WATCHDOG && X86
+	help
+	  This is a driver for the hardware watchdog on the ICP Wafer 5823
+	  Single Board Computer (and probably other similar models).
+
+	  To compile this driver as a module, choose M here: the
+	  module will be called wafer5823wdt.
+
+config I8XX_TCO
+	tristate "Intel i8xx TCO Timer/Watchdog"
+	depends on WATCHDOG && (X86 || IA64) && PCI
+	---help---
+	  Hardware driver for the TCO timer built into the Intel 82801
+	  I/O Controller Hub 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
+	  with the "heartbeat" parameter.
+
+	  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
+	  "failed to reset NO_REBOOT flag, reboot disabled by hardware".
+
+	  To compile this driver as a module, choose M here: the
+	  module will be called i8xx_tco.
+
+config SC1200_WDT
+	tristate "National Semiconductor PC87307/PC97307 (ala SC1200) Watchdog"
+	depends on WATCHDOG && X86
+	help
+	  This is a driver for National Semiconductor PC87307/PC97307 hardware
+	  watchdog cards as found on the SC1200. This watchdog is mainly used
+	  for power management purposes and can be used to power down the device
+	  during inactivity periods (includes interrupt activity monitoring).
+
+	  To compile this driver as a module, choose M here: the
+	  module will be called sc1200wdt.
+
+	  Most people will say N.
+
+config SCx200_WDT
+	tristate "National Semiconductor SCx200 Watchdog"
+	depends on WATCHDOG && SCx200 && PCI
+	help
+	  Enable the built-in watchdog timer support on the National
+	  Semiconductor SCx200 processors.
+
+	  If compiled as a module, it will be called scx200_wdt.
+
+config 60XX_WDT
+	tristate "SBC-60XX Watchdog Timer"
+	depends on WATCHDOG && X86
+	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.
+
+config CPU5_WDT
+	tristate "SMA CPU5 Watchdog"
+	depends on WATCHDOG && X86
+	---help---
+	  TBD.
+	  To compile this driver as a module, choose M here: the
+	  module will be called cpu5wdt.
+
+config W83627HF_WDT
+	tristate "W83627HF Watchdog Timer"
+	depends on WATCHDOG && X86
+	---help---
+	  This is the driver for the hardware watchdog on the W83627HF chipset
+	  as used in Advantech PC-9578 and Tyan S2721-533 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.
+
+	  To compile this driver as a module, choose M here: the
+	  module will be called w83627hf_wdt.
+
+	  Most people will say N.
+
+config W83877F_WDT
+	tristate "W83877F (EMACS) Watchdog Timer"
+	depends on WATCHDOG && X86
+	---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.
+
+	  To compile this driver as a module, choose M here: the
+	  module will be called w83877f_wdt.
+
+	  Most people will say N.
+
+config MACHZ_WDT
+	tristate "ZF MachZ Watchdog"
+	depends on WATCHDOG && X86
+	---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.
+
+	  To compile this driver as a module, choose M here: the
+	  module will be called machzwd.
+
+# PowerPC Architecture
+
+config 8xx_WDT
+	tristate "MPC8xx Watchdog Timer"
+	depends on WATCHDOG && 8xx
+
+# MIPS Architecture
+
+config INDYDOG
+	tristate "Indy/I2 Hardware Watchdog"
+	depends on WATCHDOG && SGI_IP22
+	help
+	  Hardwaredriver for the Indy's/I2's watchdog. This is a
+	  watchdog timer that will reboot the machine after a 60 second
+	  timer expired and no process has written to /dev/watchdog during
+	  that time.
+
+# S390 Architecture
+
+config ZVM_WATCHDOG
+	tristate "z/VM Watchdog Timer"
+	depends on WATCHDOG && ARCH_S390
+	help
+	  IBM s/390 and zSeries machines running under z/VM 5.1 or later
+	  provide a virtual watchdog timer to their guest that cause a
+	  user define Control Program command to be executed after a
+	  timeout.
+
+	  To compile this driver as a module, choose M here. The module
+	  will be called vmwatchdog.
+
+# SUPERH Architecture
+
+config SH_WDT
+	tristate "SuperH Watchdog"
+	depends on WATCHDOG && SUPERH
+	help
+	  This driver adds watchdog support for the integrated watchdog in the
+	  SuperH processors. If you have one of these processors and wish
+	  to have watchdog support enabled, say Y, otherwise say N.
+
+	  As a side note, saying Y here will automatically boost HZ to 1000
+	  so that the timer has a chance to clear the overflow counter. On
+	  slower systems (such as the SH-2 and SH-3) this will likely yield
+	  some performance issues. As such, the WDT should be avoided here
+	  unless it is absolutely necessary.
+
+	  To compile this driver as a module, choose M here: the
+	  module will be called shwdt.
+
+# SPARC64 Architecture
+
+config WATCHDOG_CP1XXX
+	tristate "CP1XXX Hardware Watchdog support"
+	depends on WATCHDOG && SPARC64 && PCI
+	---help---
+	  This is the driver for the hardware watchdog timers present on
+	  Sun Microsystems CompactPCI models CP1400 and CP1500.
+
+	  To compile this driver as a module, choose M here: the
+	  module will be called cpwatchdog.
+
+	  If you do not have a CompactPCI model CP1400 or CP1500, or
+	  another UltraSPARC-IIi-cEngine boardset with hardware watchdog,
+	  you should say N to this option.
+
+config WATCHDOG_RIO
+	tristate "RIO Hardware Watchdog support"
+	depends on WATCHDOG && SPARC64 && PCI
+	help
+	  Say Y here to support the hardware watchdog capability on Sun RIO
+	  machines.  The watchdog timeout period is normally one minute but
+	  can be changed with a boot-time parameter.
+
+#
+# ISA-based Watchdog Cards
+#
+
+comment "ISA-based Watchdog Cards"
+	depends on WATCHDOG && ISA
+
+config PCWATCHDOG
+	tristate "Berkshire Products ISA-PC Watchdog"
+	depends on WATCHDOG && ISA
+	---help---
+	  This is the driver for the Berkshire Products ISA-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/watchdog/pcwd-watchdog.txt>. The PC
+	  watchdog cards can be ordered from <http://www.berkprod.com/>.
+
+	  To compile this driver as a module, choose M here: the
+	  module will be called pcwd.
+
+	  Most people will say N.
+
+config MIXCOMWD
+	tristate "Mixcom Watchdog"
+	depends on WATCHDOG && ISA
+	---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.
+
+	  To compile this driver as a module, choose M here: the
+	  module will be called mixcomwd.
+
+	  Most people will say N.
+
+config WDT
+	tristate "WDT Watchdog timer"
+	depends on WATCHDOG && ISA
+	---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 that
+	  is needed (you can do this via the io and irq parameters)
+
+	  To compile this driver as a module, choose M here: the
+	  module will be called wdt.
+
+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.
+
+	  If you want to enable the Fan Tachometer on the WDT501P, then you
+	  can do this via the tachometer parameter. Only do this if you have a
+	  fan tachometer actually set up.
+
+#
+# PCI-based Watchdog Cards
+#
+
+comment "PCI-based Watchdog Cards"
+	depends on WATCHDOG && PCI
+
+config PCIPCWATCHDOG
+	tristate "Berkshire Products PCI-PC Watchdog"
+	depends on WATCHDOG && PCI
+	---help---
+	  This is the driver for the Berkshire Products PCI-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. The card can also monitor the internal temperature of the PC.
+	  More info is available at <http://www.berkprod.com/pci_pc_watchdog.htm>.
+
+	  To compile this driver as a module, choose M here: the
+	  module will be called pcwd_pci.
+
+	  Most people will say N.
+
+config WDTPCI
+	tristate "PCI-WDT500/501 Watchdog timer"
+	depends on WATCHDOG && PCI
+	---help---
+	  If you have a PCI-WDT500/501 watchdog board, say Y here, otherwise N.
+
+	  To compile this driver as a module, choose M here: the
+	  module will be called wdt_pci.
+
+config WDT_501_PCI
+	bool "PCI-WDT501 features"
+	depends on WDTPCI
+	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 PCI-WDT501 watchdog board
+	  installed.
+
+	  If you want to enable the Fan Tachometer on the PCI-WDT501, then you
+	  can do this via the tachometer parameter. Only do this if you have a
+	  fan tachometer actually set up.
+
+#
+# USB-based Watchdog Cards
+#
+
+comment "USB-based Watchdog Cards"
+	depends on WATCHDOG && USB
+
+config USBPCWATCHDOG
+	tristate "Berkshire Products USB-PC Watchdog"
+	depends on WATCHDOG && USB
+	---help---
+	  This is the driver for the Berkshire Products USB-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. The card can also monitor the internal temperature of the PC.
+	  More info is available at <http://www.berkprod.com/usb_pc_watchdog.htm>.
+
+	  To compile this driver as a module, choose M here: the
+	  module will be called pcwd_usb.
+
+	  Most people will say N.
+
+endmenu
diff --git a/drivers/char/watchdog/Makefile b/drivers/char/watchdog/Makefile
new file mode 100644
index 0000000..1cd27ef
--- /dev/null
+++ b/drivers/char/watchdog/Makefile
@@ -0,0 +1,42 @@
+#
+# Makefile for the WatchDog device drivers.
+#
+
+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_I8XX_TCO) += i8xx_tco.o
+obj-$(CONFIG_MACHZ_WDT) += machzwd.o
+obj-$(CONFIG_SH_WDT) += shwdt.o
+obj-$(CONFIG_S3C2410_WATCHDOG) += s3c2410_wdt.o
+obj-$(CONFIG_SA1100_WATCHDOG) += sa1100_wdt.o
+obj-$(CONFIG_EUROTECH_WDT) += eurotechwdt.o
+obj-$(CONFIG_W83877F_WDT) += w83877f_wdt.o
+obj-$(CONFIG_W83627HF_WDT) += w83627hf_wdt.o
+obj-$(CONFIG_SC520_WDT) += sc520_wdt.o
+obj-$(CONFIG_ALIM7101_WDT) += alim7101_wdt.o
+obj-$(CONFIG_ALIM1535_WDT) += alim1535_wdt.o
+obj-$(CONFIG_SC1200_WDT) += sc1200wdt.o
+obj-$(CONFIG_WAFER_WDT) += wafer5823wdt.o
+obj-$(CONFIG_CPU5_WDT) += cpu5wdt.o
+obj-$(CONFIG_INDYDOG) += indydog.o
+obj-$(CONFIG_PCIPCWATCHDOG) += pcwd_pci.o
+obj-$(CONFIG_USBPCWATCHDOG) += pcwd_usb.o
+obj-$(CONFIG_IXP4XX_WATCHDOG) += ixp4xx_wdt.o
+obj-$(CONFIG_IXP2000_WATCHDOG) += ixp2000_wdt.o
+obj-$(CONFIG_8xx_WDT) += mpc8xx_wdt.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_SOFT_WATCHDOG) += softdog.o
diff --git a/drivers/char/watchdog/acquirewdt.c b/drivers/char/watchdog/acquirewdt.c
new file mode 100644
index 0000000..8f30212
--- /dev/null
+++ b/drivers/char/watchdog/acquirewdt.c
@@ -0,0 +1,332 @@
+/*
+ *	Acquire Single Board Computer Watchdog Timer driver
+ *
+ *      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
+ */
+
+/*
+ *	Theory of Operation:
+ *		The Watch-Dog Timer is provided to ensure that standalone
+ *		Systems can always recover from catastrophic conditions that
+ *		caused the CPU to crash. This condition may have occured by
+ *		external EMI or a software bug. When the CPU stops working
+ *		correctly, hardware on the board will either perform a hardware
+ *		reset (cold boot) or a non-maskable interrupt (NMI) to bring the
+ *		system back to a known state.
+ *
+ *		The Watch-Dog Timer is controlled by two I/O Ports.
+ *		  443 hex	- Read	- Enable or refresh the Watch-Dog Timer
+ *		  043 hex	- Read	- Disable the Watch-Dog Timer
+ *
+ *		To enable the Watch-Dog Timer, a read from I/O port 443h must
+ *		be performed. This will enable and activate the countdown timer
+ *		which will eventually time out and either reset the CPU or cause
+ *		an NMI depending on the setting of a jumper. To ensure that this
+ *		reset condition does not occur, the Watch-Dog Timer must be
+ *		periodically refreshed by reading the same I/O port 443h.
+ *		The Watch-Dog Timer is disabled by reading I/O port 043h.
+ *
+ *		The Watch-Dog Timer Time-Out Period is set via jumpers.
+ *		It can be 1, 2, 10, 20, 110 or 220 seconds.
+ */
+
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/types.h>
+#include <linux/miscdevice.h>
+#include <linux/watchdog.h>
+#include <linux/fs.h>
+#include <linux/ioport.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>
+
+#define WATCHDOG_NAME "Acquire WDT"
+#define PFX WATCHDOG_NAME ": "
+#define WATCHDOG_HEARTBEAT 0	/* There is no way to see what the correct time-out period is */
+
+static unsigned long acq_is_open;
+static char expect_close;
+
+/*
+ *	You must set these - there is no sane way to probe for this board.
+ */
+
+static int wdt_stop = 0x43;
+module_param(wdt_stop, int, 0);
+MODULE_PARM_DESC(wdt_stop, "Acquire WDT 'stop' io port (default 0x43)");
+
+static int wdt_start = 0x443;
+module_param(wdt_start, int, 0);
+MODULE_PARM_DESC(wdt_start, "Acquire WDT 'start' io port (default 0x443)");
+
+#ifdef CONFIG_WATCHDOG_NOWAYOUT
+static int nowayout = 1;
+#else
+static int nowayout = 0;
+#endif
+
+module_param(nowayout, int, 0);
+MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default=CONFIG_WATCHDOG_NOWAYOUT)");
+
+/*
+ *	Kernel methods.
+ */
+
+static void acq_keepalive(void)
+{
+	/* Write a watchdog value */
+	inb_p(wdt_start);
+}
+
+static void acq_stop(void)
+{
+	/* Turn the card off */
+	inb_p(wdt_stop);
+}
+
+/*
+ *	/dev/watchdog handling.
+ */
+
+static ssize_t acq_write(struct file *file, const char __user *buf, size_t count, loff_t *ppos)
+{
+	/* See if we got the magic character 'V' and reload the timer */
+	if(count) {
+		if (!nowayout) {
+			size_t i;
+
+			/* note: just in case someone wrote the magic character
+			 * five months ago... */
+			expect_close = 0;
+
+			/* scan to see whether or not we got the magic character */
+			for (i = 0; i != count; i++) {
+				char c;
+				if (get_user(c, buf + i))
+					return -EFAULT;
+				if (c == 'V')
+					expect_close = 42;
+			}
+		}
+
+		/* Well, anyhow someone wrote to us, we should return that favour */
+		acq_keepalive();
+	}
+	return count;
+}
+
+static int acq_ioctl(struct inode *inode, struct file *file, unsigned int cmd,
+	unsigned long arg)
+{
+	int options, retval = -EINVAL;
+	void __user *argp = (void __user *)arg;
+	int __user *p = argp;
+	static struct watchdog_info ident =
+	{
+		.options = WDIOF_KEEPALIVEPING | WDIOF_MAGICCLOSE,
+		.firmware_version = 1,
+		.identity = "Acquire WDT",
+	};
+
+	switch(cmd)
+	{
+	case WDIOC_GETSUPPORT:
+	  return copy_to_user(argp, &ident, sizeof(ident)) ? -EFAULT : 0;
+
+	case WDIOC_GETSTATUS:
+	case WDIOC_GETBOOTSTATUS:
+	  return put_user(0, p);
+
+	case WDIOC_KEEPALIVE:
+	  acq_keepalive();
+	  return 0;
+
+	case WDIOC_GETTIMEOUT:
+	  return put_user(WATCHDOG_HEARTBEAT, p);
+
+	case WDIOC_SETOPTIONS:
+	{
+	    if (get_user(options, p))
+	      return -EFAULT;
+
+	    if (options & WDIOS_DISABLECARD)
+	    {
+	      acq_stop();
+	      retval = 0;
+	    }
+
+	    if (options & WDIOS_ENABLECARD)
+	    {
+	      acq_keepalive();
+	      retval = 0;
+	    }
+
+	    return retval;
+	}
+
+	default:
+	  return -ENOIOCTLCMD;
+	}
+}
+
+static int acq_open(struct inode *inode, struct file *file)
+{
+	if (test_and_set_bit(0, &acq_is_open))
+		return -EBUSY;
+
+	if (nowayout)
+		__module_get(THIS_MODULE);
+
+	/* Activate */
+	acq_keepalive();
+	return nonseekable_open(inode, file);
+}
+
+static int acq_close(struct inode *inode, struct file *file)
+{
+	if (expect_close == 42) {
+		acq_stop();
+	} else {
+		printk(KERN_CRIT PFX "Unexpected close, not stopping watchdog!\n");
+		acq_keepalive();
+	}
+	clear_bit(0, &acq_is_open);
+	expect_close = 0;
+	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 WDT off */
+		acq_stop();
+	}
+	return NOTIFY_DONE;
+}
+
+/*
+ *	Kernel Interfaces
+ */
+
+static struct file_operations acq_fops = {
+	.owner		= THIS_MODULE,
+	.llseek		= no_llseek,
+	.write		= acq_write,
+	.ioctl		= acq_ioctl,
+	.open		= acq_open,
+	.release	= acq_close,
+};
+
+static struct miscdevice acq_miscdev=
+{
+	.minor = WATCHDOG_MINOR,
+	.name = "watchdog",
+	.fops = &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 =
+{
+	.notifier_call = acq_notify_sys,
+};
+
+static int __init acq_init(void)
+{
+	int ret;
+
+	printk(KERN_INFO "WDT driver for Acquire single board computer initialising.\n");
+
+	if (wdt_stop != wdt_start) {
+		if (!request_region(wdt_stop, 1, WATCHDOG_NAME)) {
+			printk (KERN_ERR PFX "I/O address 0x%04x already in use\n",
+				wdt_stop);
+			ret = -EIO;
+			goto out;
+		}
+	}
+
+	if (!request_region(wdt_start, 1, WATCHDOG_NAME)) {
+		printk (KERN_ERR PFX "I/O address 0x%04x already in use\n",
+			wdt_start);
+		ret = -EIO;
+		goto unreg_stop;
+	}
+
+	ret = register_reboot_notifier(&acq_notifier);
+	if (ret != 0) {
+		printk (KERN_ERR PFX "cannot register reboot notifier (err=%d)\n",
+			ret);
+		goto unreg_regions;
+	}
+
+	ret = misc_register(&acq_miscdev);
+	if (ret != 0) {
+		printk (KERN_ERR PFX "cannot register miscdev on minor=%d (err=%d)\n",
+			WATCHDOG_MINOR, ret);
+		goto unreg_reboot;
+	}
+
+	printk (KERN_INFO PFX "initialized. (nowayout=%d)\n",
+		nowayout);
+
+	return 0;
+
+unreg_reboot:
+	unregister_reboot_notifier(&acq_notifier);
+unreg_regions:
+	release_region(wdt_start, 1);
+unreg_stop:
+	if (wdt_stop != wdt_start)
+		release_region(wdt_stop, 1);
+out:
+	return ret;
+}
+
+static void __exit acq_exit(void)
+{
+	misc_deregister(&acq_miscdev);
+	unregister_reboot_notifier(&acq_notifier);
+	if(wdt_stop != wdt_start)
+		release_region(wdt_stop,1);
+	release_region(wdt_start,1);
+}
+
+module_init(acq_init);
+module_exit(acq_exit);
+
+MODULE_AUTHOR("David Woodhouse");
+MODULE_DESCRIPTION("Acquire Inc. Single Board Computer Watchdog Timer driver");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS_MISCDEV(WATCHDOG_MINOR);
diff --git a/drivers/char/watchdog/advantechwdt.c b/drivers/char/watchdog/advantechwdt.c
new file mode 100644
index 0000000..ea73c83
--- /dev/null
+++ b/drivers/char/watchdog/advantechwdt.c
@@ -0,0 +1,333 @@
+/*
+ *	Advantech Single Board Computer WDT driver
+ *
+ *	(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
+ *
+ *	16-Oct-2002 Rob Radez <rob@osinvestor.com>
+ *	    Clean up ioctls, clean up init + exit, add expect close support,
+ *	    add wdt_start and wdt_stop as parameters.
+ */
+
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/types.h>
+#include <linux/miscdevice.h>
+#include <linux/watchdog.h>
+#include <linux/fs.h>
+#include <linux/ioport.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>
+
+#define WATCHDOG_NAME "Advantech WDT"
+#define PFX WATCHDOG_NAME ": "
+#define WATCHDOG_TIMEOUT 60		/* 60 sec default timeout */
+
+static unsigned long advwdt_is_open;
+static char adv_expect_close;
+
+/*
+ *	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!)
+ */
+
+static int wdt_stop = 0x443;
+module_param(wdt_stop, int, 0);
+MODULE_PARM_DESC(wdt_stop, "Advantech WDT 'stop' io port (default 0x443)");
+
+static int wdt_start = 0x443;
+module_param(wdt_start, int, 0);
+MODULE_PARM_DESC(wdt_start, "Advantech WDT 'start' io port (default 0x443)");
+
+static int timeout = WATCHDOG_TIMEOUT;	/* in seconds */
+module_param(timeout, int, 0);
+MODULE_PARM_DESC(timeout, "Watchdog timeout in seconds. 1<= timeout <=63, default=" __MODULE_STRING(WATCHDOG_TIMEOUT) ".");
+
+#ifdef CONFIG_WATCHDOG_NOWAYOUT
+static int nowayout = 1;
+#else
+static int nowayout = 0;
+#endif
+
+module_param(nowayout, int, 0);
+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 void
+advwdt_disable(void)
+{
+	inb_p(wdt_stop);
+}
+
+static ssize_t
+advwdt_write(struct file *file, const char __user *buf, size_t count, loff_t *ppos)
+{
+	if (count) {
+		if (!nowayout) {
+			size_t i;
+
+			adv_expect_close = 0;
+
+			for (i = 0; i != count; i++) {
+				char c;
+				if (get_user(c, buf+i))
+					return -EFAULT;
+				if (c == 'V')
+					adv_expect_close = 42;
+			}
+		}
+		advwdt_ping();
+	}
+	return count;
+}
+
+static int
+advwdt_ioctl(struct inode *inode, struct file *file, unsigned int cmd,
+	  unsigned long arg)
+{
+	int new_timeout;
+	void __user *argp = (void __user *)arg;
+	int __user *p = argp;
+	static struct watchdog_info ident = {
+		.options = WDIOF_KEEPALIVEPING | WDIOF_SETTIMEOUT | WDIOF_MAGICCLOSE,
+		.firmware_version = 1,
+		.identity = "Advantech WDT",
+	};
+
+	switch (cmd) {
+	case WDIOC_GETSUPPORT:
+	  if (copy_to_user(argp, &ident, sizeof(ident)))
+	    return -EFAULT;
+	  break;
+
+	case WDIOC_GETSTATUS:
+	case WDIOC_GETBOOTSTATUS:
+	  return put_user(0, p);
+
+	case WDIOC_KEEPALIVE:
+	  advwdt_ping();
+	  break;
+
+	case WDIOC_SETTIMEOUT:
+	  if (get_user(new_timeout, p))
+		  return -EFAULT;
+	  if ((new_timeout < 1) || (new_timeout > 63))
+		  return -EINVAL;
+	  timeout = new_timeout;
+	  advwdt_ping();
+	  /* Fall */
+
+	case WDIOC_GETTIMEOUT:
+	  return put_user(timeout, p);
+
+	case WDIOC_SETOPTIONS:
+	{
+	  int options, retval = -EINVAL;
+
+	  if (get_user(options, p))
+	    return -EFAULT;
+
+	  if (options & WDIOS_DISABLECARD) {
+	    advwdt_disable();
+	    retval = 0;
+	  }
+
+	  if (options & WDIOS_ENABLECARD) {
+	    advwdt_ping();
+	    retval = 0;
+	  }
+
+	  return retval;
+	}
+
+	default:
+	  return -ENOIOCTLCMD;
+	}
+	return 0;
+}
+
+static int
+advwdt_open(struct inode *inode, struct file *file)
+{
+	if (test_and_set_bit(0, &advwdt_is_open))
+		return -EBUSY;
+	/*
+	 *	Activate
+	 */
+
+	advwdt_ping();
+	return nonseekable_open(inode, file);
+}
+
+static int
+advwdt_close(struct inode *inode, struct file *file)
+{
+	if (adv_expect_close == 42) {
+		advwdt_disable();
+	} else {
+		printk(KERN_CRIT PFX "Unexpected close, not stopping watchdog!\n");
+		advwdt_ping();
+	}
+	clear_bit(0, &advwdt_is_open);
+	adv_expect_close = 0;
+	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 */
+		advwdt_disable();
+	}
+	return NOTIFY_DONE;
+}
+
+/*
+ *	Kernel Interfaces
+ */
+
+static struct file_operations advwdt_fops = {
+	.owner		= THIS_MODULE,
+	.llseek		= no_llseek,
+	.write		= advwdt_write,
+	.ioctl		= advwdt_ioctl,
+	.open		= advwdt_open,
+	.release	= advwdt_close,
+};
+
+static struct miscdevice advwdt_miscdev = {
+	.minor = WATCHDOG_MINOR,
+	.name = "watchdog",
+	.fops = &advwdt_fops,
+};
+
+/*
+ *	The WDT needs to learn about soft shutdowns in order to
+ *	turn the timebomb registers off.
+ */
+
+static struct notifier_block advwdt_notifier = {
+	.notifier_call = advwdt_notify_sys,
+};
+
+static int __init
+advwdt_init(void)
+{
+	int ret;
+
+	printk(KERN_INFO "WDT driver for Advantech single board computer initialising.\n");
+
+	if (timeout < 1 || timeout > 63) {
+		timeout = WATCHDOG_TIMEOUT;
+		printk (KERN_INFO PFX "timeout value must be 1<=x<=63, using %d\n",
+			timeout);
+	}
+
+	if (wdt_stop != wdt_start) {
+		if (!request_region(wdt_stop, 1, WATCHDOG_NAME)) {
+			printk (KERN_ERR PFX "I/O address 0x%04x already in use\n",
+				wdt_stop);
+			ret = -EIO;
+			goto out;
+		}
+	}
+
+	if (!request_region(wdt_start, 1, WATCHDOG_NAME)) {
+		printk (KERN_ERR PFX "I/O address 0x%04x already in use\n",
+			wdt_start);
+		ret = -EIO;
+		goto unreg_stop;
+	}
+
+	ret = register_reboot_notifier(&advwdt_notifier);
+	if (ret != 0) {
+		printk (KERN_ERR PFX "cannot register reboot notifier (err=%d)\n",
+			ret);
+		goto unreg_regions;
+	}
+
+	ret = misc_register(&advwdt_miscdev);
+	if (ret != 0) {
+		printk (KERN_ERR PFX "cannot register miscdev on minor=%d (err=%d)\n",
+			WATCHDOG_MINOR, ret);
+		goto unreg_reboot;
+	}
+
+	printk (KERN_INFO PFX "initialized. timeout=%d sec (nowayout=%d)\n",
+		timeout, nowayout);
+
+out:
+	return ret;
+unreg_reboot:
+	unregister_reboot_notifier(&advwdt_notifier);
+unreg_regions:
+	release_region(wdt_start, 1);
+unreg_stop:
+	if (wdt_stop != wdt_start)
+		release_region(wdt_stop, 1);
+	goto out;
+}
+
+static void __exit
+advwdt_exit(void)
+{
+	misc_deregister(&advwdt_miscdev);
+	unregister_reboot_notifier(&advwdt_notifier);
+	if(wdt_stop != wdt_start)
+		release_region(wdt_stop,1);
+	release_region(wdt_start,1);
+}
+
+module_init(advwdt_init);
+module_exit(advwdt_exit);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Marek Michalkiewicz <marekm@linux.org.pl>");
+MODULE_DESCRIPTION("Advantech Single Board Computer WDT driver");
+MODULE_ALIAS_MISCDEV(WATCHDOG_MINOR);
diff --git a/drivers/char/watchdog/alim1535_wdt.c b/drivers/char/watchdog/alim1535_wdt.c
new file mode 100644
index 0000000..35dcbf8
--- /dev/null
+++ b/drivers/char/watchdog/alim1535_wdt.c
@@ -0,0 +1,463 @@
+/*
+ *	Watchdog for the 7101 PMU version found in the ALi M1535 chipsets
+ *
+ *	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/moduleparam.h>
+#include <linux/types.h>
+#include <linux/miscdevice.h>
+#include <linux/watchdog.h>
+#include <linux/ioport.h>
+#include <linux/notifier.h>
+#include <linux/reboot.h>
+#include <linux/init.h>
+#include <linux/fs.h>
+#include <linux/pci.h>
+
+#include <asm/uaccess.h>
+#include <asm/io.h>
+
+#define WATCHDOG_NAME "ALi_M1535"
+#define PFX WATCHDOG_NAME ": "
+#define WATCHDOG_TIMEOUT 60	/* 60 sec default timeout */
+
+/* internal variables */
+static unsigned long ali_is_open;
+static char ali_expect_release;
+static struct pci_dev *ali_pci;
+static u32 ali_timeout_bits;	/* stores the computed timeout */
+static spinlock_t ali_lock;	/* Guards the hardware */
+
+/* module parameters */
+static int timeout = WATCHDOG_TIMEOUT;
+module_param(timeout, int, 0);
+MODULE_PARM_DESC(timeout, "Watchdog timeout in seconds. (0<timeout<18000, default=" __MODULE_STRING(WATCHDOG_TIMEOUT) ")");
+
+#ifdef CONFIG_WATCHDOG_NOWAYOUT
+static int nowayout = 1;
+#else
+static int nowayout = 0;
+#endif
+
+module_param(nowayout, int, 0);
+MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default=CONFIG_WATCHDOG_NOWAYOUT)");
+
+/*
+ *	ali_start	-	start watchdog countdown
+ *
+ *	Starts the timer running providing the timer has a counter
+ *	configuration set.
+ */
+
+static void ali_start(void)
+{
+	u32 val;
+
+	spin_lock(&ali_lock);
+
+	pci_read_config_dword(ali_pci, 0xCC, &val);
+	val &= ~0x3F;	/* Mask count */
+	val |= (1<<25) | ali_timeout_bits;
+	pci_write_config_dword(ali_pci, 0xCC, val);
+
+	spin_unlock(&ali_lock);
+}
+
+/*
+ *	ali_stop	-	stop the timer countdown
+ *
+ *	Stop the ALi watchdog countdown
+ */
+
+static void ali_stop(void)
+{
+	u32 val;
+
+	spin_lock(&ali_lock);
+
+	pci_read_config_dword(ali_pci, 0xCC, &val);
+	val &= ~0x3F;	/* Mask count to zero (disabled) */
+	val &= ~(1<<25);/* and for safety mask the reset enable */
+	pci_write_config_dword(ali_pci, 0xCC, val);
+
+	spin_unlock(&ali_lock);
+}
+
+/*
+ *	ali_keepalive	-	send a keepalive to the watchdog
+ *
+ *      Send a keepalive to the timer (actually we restart the timer).
+ */
+
+static void ali_keepalive(void)
+{
+	ali_start();
+}
+
+/*
+ *	ali_settimer	-	compute the timer reload value
+ *	@t: time in seconds
+ *
+ *	Computes the timeout values needed
+ */
+
+static int ali_settimer(int t)
+{
+	if(t < 0)
+		return -EINVAL;
+	else if(t < 60)
+		ali_timeout_bits = t|(1<<6);
+	else if(t < 3600)
+		ali_timeout_bits = (t/60)|(1<<7);
+	else if(t < 18000)
+		ali_timeout_bits = (t/300)|(1<<6)|(1<<7);
+	else return -EINVAL;
+
+	timeout = t;
+	return 0;
+}
+
+/*
+ *	/dev/watchdog handling
+ */
+
+/*
+ *	ali_write	-	writes to ALi watchdog
+ *	@file: file from VFS
+ *	@data: user address of data
+ *	@len: length of data
+ *	@ppos: pointer to the file offset
+ *
+ *	Handle a write to the ALi watchdog. Writing to the file pings
+ *	the watchdog and resets it. Writing the magic 'V' sequence allows
+ *	the next close to turn off the watchdog.
+ */
+
+static ssize_t ali_write(struct file *file, const char __user *data,
+			      size_t len, loff_t * ppos)
+{
+	/* See if we got the magic character 'V' and reload the timer */
+	if (len) {
+		if (!nowayout) {
+			size_t i;
+
+			/* note: just in case someone wrote the magic character
+			 * five months ago... */
+			ali_expect_release = 0;
+
+			/* scan to see whether or not we got the magic character */
+			for (i = 0; i != len; i++) {
+				char c;
+				if(get_user(c, data+i))
+					return -EFAULT;
+				if (c == 'V')
+					ali_expect_release = 42;
+			}
+		}
+
+		/* someone wrote to us, we should reload the timer */
+		ali_start();
+	}
+	return len;
+}
+
+/*
+ *	ali_ioctl	-	handle watchdog ioctls
+ *	@inode: VFS inode
+ *	@file: VFS file pointer
+ *	@cmd: ioctl number
+ *	@arg: arguments to the ioctl
+ *
+ *	Handle the watchdog ioctls supported by the ALi driver. Really
+ *	we want an extension to enable irq ack monitoring and the like
+ */
+
+static int ali_ioctl(struct inode *inode, struct file *file,
+			  unsigned int cmd, unsigned long arg)
+{
+	void __user *argp = (void __user *)arg;
+	int __user *p = argp;
+	static struct watchdog_info ident = {
+		.options =		WDIOF_KEEPALIVEPING |
+					WDIOF_SETTIMEOUT |
+					WDIOF_MAGICCLOSE,
+		.firmware_version =	0,
+		.identity =		"ALi M1535 WatchDog Timer",
+	};
+
+	switch (cmd) {
+		case WDIOC_GETSUPPORT:
+			return copy_to_user(argp, &ident,
+				sizeof (ident)) ? -EFAULT : 0;
+
+		case WDIOC_GETSTATUS:
+		case WDIOC_GETBOOTSTATUS:
+			return put_user(0, p);
+
+		case WDIOC_KEEPALIVE:
+			ali_keepalive();
+			return 0;
+
+		case WDIOC_SETOPTIONS:
+		{
+			int new_options, retval = -EINVAL;
+
+			if (get_user (new_options, p))
+				return -EFAULT;
+
+			if (new_options & WDIOS_DISABLECARD) {
+				ali_stop();
+				retval = 0;
+			}
+
+			if (new_options & WDIOS_ENABLECARD) {
+				ali_start();
+				retval = 0;
+			}
+
+			return retval;
+		}
+
+		case WDIOC_SETTIMEOUT:
+		{
+			int new_timeout;
+
+			if (get_user(new_timeout, p))
+				return -EFAULT;
+
+			if (ali_settimer(new_timeout))
+			    return -EINVAL;
+
+			ali_keepalive();
+			/* Fall */
+		}
+
+		case WDIOC_GETTIMEOUT:
+			return put_user(timeout, p);
+
+		default:
+			return -ENOIOCTLCMD;
+	}
+}
+
+/*
+ *	ali_open	-	handle open of ali watchdog
+ *	@inode: inode from VFS
+ *	@file: file from VFS
+ *
+ *	Open the ALi watchdog device. Ensure only one person opens it
+ *	at a time. Also start the watchdog running.
+ */
+
+static int ali_open(struct inode *inode, struct file *file)
+{
+	/* /dev/watchdog can only be opened once */
+	if (test_and_set_bit(0, &ali_is_open))
+		return -EBUSY;
+
+	/* Activate */
+	ali_start();
+	return nonseekable_open(inode, file);
+}
+
+/*
+ *	ali_release	-	close an ALi watchdog
+ *	@inode: inode from VFS
+ *	@file: file from VFS
+ *
+ *	Close the ALi watchdog device. Actual shutdown of the timer
+ *	only occurs if the magic sequence has been set.
+ */
+
+static int ali_release(struct inode *inode, struct file *file)
+{
+	/*
+	 *      Shut off the timer.
+	 */
+	if (ali_expect_release == 42) {
+		ali_stop();
+	} else {
+		printk(KERN_CRIT PFX "Unexpected close, not stopping watchdog!\n");
+		ali_keepalive();
+	}
+	clear_bit(0, &ali_is_open);
+	ali_expect_release = 0;
+	return 0;
+}
+
+/*
+ *	ali_notify_sys	-	System down notifier
+ *
+ *	Notifier for system down
+ */
+
+
+static int ali_notify_sys(struct notifier_block *this, unsigned long code, void *unused)
+{
+	if (code==SYS_DOWN || code==SYS_HALT) {
+		/* Turn the WDT off */
+		ali_stop();
+	}
+
+	return NOTIFY_DONE;
+}
+
+/*
+ *	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 ali_pci_tbl[] = {
+	{ PCI_VENDOR_ID_AL, 1535, PCI_ANY_ID, PCI_ANY_ID,},
+	{ 0, },
+};
+MODULE_DEVICE_TABLE(pci, ali_pci_tbl);
+
+/*
+ *	ali_find_watchdog	-	find a 1535 and 7101
+ *
+ *	Scans the PCI hardware for a 1535 series bridge and matching 7101
+ *	watchdog device. This may be overtight but it is better to be safe
+ */
+
+static int __init ali_find_watchdog(void)
+{
+	struct pci_dev *pdev;
+	u32 wdog;
+
+	/* Check for a 1535 series bridge */
+	pdev = pci_find_device(PCI_VENDOR_ID_AL, 0x1535, NULL);
+	if(pdev == NULL)
+		return -ENODEV;
+
+	/* Check for the a 7101 PMU */
+	pdev = pci_find_device(PCI_VENDOR_ID_AL, 0x7101, NULL);
+	if(pdev == NULL)
+		return -ENODEV;
+
+	if(pci_enable_device(pdev))
+		return -EIO;
+
+	ali_pci = pdev;
+
+	/*
+	 *	Initialize the timer bits
+	 */
+	pci_read_config_dword(pdev, 0xCC, &wdog);
+
+	wdog &= ~0x3F;		/* Timer bits */
+	wdog &= ~((1<<27)|(1<<26)|(1<<25)|(1<<24));	/* Issued events */
+	wdog &= ~((1<<16)|(1<<13)|(1<<12)|(1<<11)|(1<<10)|(1<<9));	/* No monitor bits */
+
+	pci_write_config_dword(pdev, 0xCC, wdog);
+
+	return 0;
+}
+
+/*
+ *	Kernel Interfaces
+ */
+
+static struct file_operations ali_fops = {
+	.owner =	THIS_MODULE,
+	.llseek =	no_llseek,
+	.write =	ali_write,
+	.ioctl =	ali_ioctl,
+	.open =		ali_open,
+	.release =	ali_release,
+};
+
+static struct miscdevice ali_miscdev = {
+	.minor =	WATCHDOG_MINOR,
+	.name =		"watchdog",
+	.fops =		&ali_fops,
+};
+
+static struct notifier_block ali_notifier = {
+	.notifier_call =	ali_notify_sys,
+};
+
+/*
+ *	watchdog_init	-	module initialiser
+ *
+ *	Scan for a suitable watchdog and if so initialize it. Return an error
+ *	if we cannot, the error causes the module to unload
+ */
+
+static int __init watchdog_init(void)
+{
+	int ret;
+
+	spin_lock_init(&ali_lock);
+
+	/* Check whether or not the hardware watchdog is there */
+	if (ali_find_watchdog() != 0) {
+		return -ENODEV;
+	}
+
+	/* Check that the timeout value is within it's range ; if not reset to the default */
+	if (timeout < 1 || timeout >= 18000) {
+		timeout = WATCHDOG_TIMEOUT;
+		printk(KERN_INFO PFX "timeout value must be 0<timeout<18000, using %d\n",
+			timeout);
+	}
+
+	/* Calculate the watchdog's timeout */
+	ali_settimer(timeout);
+
+	ret = misc_register(&ali_miscdev);
+	if (ret != 0) {
+		printk(KERN_ERR PFX "cannot register miscdev on minor=%d (err=%d)\n",
+			WATCHDOG_MINOR, ret);
+		goto out;
+	}
+
+	ret = register_reboot_notifier(&ali_notifier);
+	if (ret != 0) {
+		printk(KERN_ERR PFX "cannot register reboot notifier (err=%d)\n",
+			ret);
+		goto unreg_miscdev;
+	}
+
+	printk(KERN_INFO PFX "initialized. timeout=%d sec (nowayout=%d)\n",
+		timeout, nowayout);
+
+out:
+	return ret;
+unreg_miscdev:
+	misc_deregister(&ali_miscdev);
+	goto out;
+}
+
+/*
+ *	watchdog_exit	-	module de-initialiser
+ *
+ *	Called while unloading a successfully installed watchdog module.
+ */
+
+static void __exit watchdog_exit(void)
+{
+	/* Stop the timer before we leave */
+	ali_stop();
+
+	/* Deregister */
+	unregister_reboot_notifier(&ali_notifier);
+	misc_deregister(&ali_miscdev);
+}
+
+module_init(watchdog_init);
+module_exit(watchdog_exit);
+
+MODULE_AUTHOR("Alan Cox");
+MODULE_DESCRIPTION("ALi M1535 PMU Watchdog Timer driver");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS_MISCDEV(WATCHDOG_MINOR);
diff --git a/drivers/char/watchdog/alim7101_wdt.c b/drivers/char/watchdog/alim7101_wdt.c
new file mode 100644
index 0000000..90c091d
--- /dev/null
+++ b/drivers/char/watchdog/alim7101_wdt.c
@@ -0,0 +1,421 @@
+/*
+ *	ALi M7101 PMU Computer Watchdog Timer driver
+ *
+ *	Based on w83877f_wdt.c by Scott Jennings <linuxdrivers@oro.net>
+ *	and the Cobalt kernel WDT timer driver by Tim Hockin
+ *	                                      <thockin@cobaltnet.com>
+ *
+ *	(c)2002 Steve Hill <steve@navaho.co.uk>
+ *
+ *  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.
+ *
+ *  Additions:
+ *   Aug 23, 2004 - Added use_gpio module parameter for use on revision a1d PMUs
+ *                  found on very old cobalt hardware.
+ *                  -- Mike Waychison <michael.waychison@sun.com>
+ */
+
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/types.h>
+#include <linux/timer.h>
+#include <linux/miscdevice.h>
+#include <linux/watchdog.h>
+#include <linux/ioport.h>
+#include <linux/notifier.h>
+#include <linux/reboot.h>
+#include <linux/init.h>
+#include <linux/fs.h>
+#include <linux/pci.h>
+
+#include <asm/io.h>
+#include <asm/uaccess.h>
+#include <asm/system.h>
+
+#define OUR_NAME "alim7101_wdt"
+#define PFX OUR_NAME ": "
+
+#define WDT_ENABLE 0x9C
+#define WDT_DISABLE 0x8C
+
+#define ALI_7101_WDT    0x92
+#define ALI_7101_GPIO   0x7D
+#define ALI_7101_GPIO_O 0x7E
+#define ALI_WDT_ARM     0x01
+
+/*
+ * We're going to use a 1 second timeout.
+ * 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 WATCHDOG_TIMEOUT 30            /* 30 sec default timeout */
+static int timeout = WATCHDOG_TIMEOUT; /* in seconds, will be multiplied by HZ to get seconds to wait for a ping */
+module_param(timeout, int, 0);
+MODULE_PARM_DESC(timeout, "Watchdog timeout in seconds. (1<=timeout<=3600, default=" __MODULE_STRING(WATCHDOG_TIMEOUT) ")");
+
+static int use_gpio = 0; /* Use the pic (for a1d revision alim7101) */
+module_param(use_gpio, int, 0);
+MODULE_PARM_DESC(use_gpio, "Use the gpio watchdog.  (required by old cobalt boards)");
+
+static void wdt_timer_ping(unsigned long);
+static struct timer_list timer;
+static unsigned long next_heartbeat;
+static unsigned long wdt_is_open;
+static char wdt_expect_close;
+static struct pci_dev *alim7101_pmu;
+
+#ifdef CONFIG_WATCHDOG_NOWAYOUT
+static int nowayout = 1;
+#else
+static int nowayout = 0;
+#endif
+
+module_param(nowayout, int, 0);
+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
+	 */
+	char	tmp;
+
+	if(time_before(jiffies, next_heartbeat))
+	{
+		/* Ping the WDT (this is actually a disarm/arm sequence) */
+		pci_read_config_byte(alim7101_pmu, 0x92, &tmp);
+		pci_write_config_byte(alim7101_pmu, ALI_7101_WDT, (tmp & ~ALI_WDT_ARM));
+		pci_write_config_byte(alim7101_pmu, ALI_7101_WDT, (tmp | ALI_WDT_ARM));
+		if (use_gpio) {
+			pci_read_config_byte(alim7101_pmu, ALI_7101_GPIO_O, &tmp);
+			pci_write_config_byte(alim7101_pmu, ALI_7101_GPIO_O, tmp
+					| 0x20);
+			pci_write_config_byte(alim7101_pmu, ALI_7101_GPIO_O, tmp
+					& ~0x20);
+		}
+	} else {
+		printk(KERN_WARNING PFX "Heartbeat lost! Will not ping the watchdog\n");
+	}
+	/* Re-set the timer interval */
+	timer.expires = jiffies + WDT_INTERVAL;
+	add_timer(&timer);
+}
+
+/*
+ * Utility routines
+ */
+
+static void wdt_change(int writeval)
+{
+	char	tmp;
+
+	pci_read_config_byte(alim7101_pmu, ALI_7101_WDT, &tmp);
+	if (writeval == WDT_ENABLE) {
+		pci_write_config_byte(alim7101_pmu, ALI_7101_WDT, (tmp | ALI_WDT_ARM));
+		if (use_gpio) {
+			pci_read_config_byte(alim7101_pmu, ALI_7101_GPIO_O, &tmp);
+			pci_write_config_byte(alim7101_pmu, ALI_7101_GPIO_O, tmp & ~0x20);
+		}
+
+	} else {
+		pci_write_config_byte(alim7101_pmu, ALI_7101_WDT, (tmp & ~ALI_WDT_ARM));
+		if (use_gpio) {
+			pci_read_config_byte(alim7101_pmu, ALI_7101_GPIO_O, &tmp);
+			pci_write_config_byte(alim7101_pmu, ALI_7101_GPIO_O, tmp | 0x20);
+		}
+	}
+}
+
+static void wdt_startup(void)
+{
+	next_heartbeat = jiffies + (timeout * HZ);
+
+	/* We must enable before we kick off the timer in case the timer
+	   occurs as we ping it */
+
+	wdt_change(WDT_ENABLE);
+
+	/* Start the timer */
+	timer.expires = jiffies + WDT_INTERVAL;
+	add_timer(&timer);
+
+
+	printk(KERN_INFO PFX "Watchdog timer is now enabled.\n");
+}
+
+static void wdt_turnoff(void)
+{
+	/* Stop the timer */
+	del_timer_sync(&timer);
+	wdt_change(WDT_DISABLE);
+	printk(KERN_INFO PFX "Watchdog timer is now disabled...\n");
+}
+
+static void wdt_keepalive(void)
+{
+	/* user land ping */
+	next_heartbeat = jiffies + (timeout * HZ);
+}
+
+/*
+ * /dev/watchdog handling
+ */
+
+static ssize_t fop_write(struct file * file, const char __user * buf, size_t count, loff_t * ppos)
+{
+	/* See if we got the magic character 'V' and reload the timer */
+	if(count) {
+		if (!nowayout) {
+			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 = 42;
+			}
+		}
+		/* someone wrote to us, we should restart timer */
+		wdt_keepalive();
+	}
+	return count;
+}
+
+static int fop_open(struct inode * inode, struct file * file)
+{
+	/* 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 nonseekable_open(inode, file);
+}
+
+static int fop_close(struct inode * inode, struct file * file)
+{
+	if(wdt_expect_close == 42)
+		wdt_turnoff();
+	else {
+		/* wim: shouldn't there be a: del_timer(&timer); */
+		printk(KERN_CRIT PFX "device file closed unexpectedly. Will not stop the WDT!\n");
+	}
+	clear_bit(0, &wdt_is_open);
+	wdt_expect_close = 0;
+	return 0;
+}
+
+static int fop_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg)
+{
+	void __user *argp = (void __user *)arg;
+	int __user *p = argp;
+	static struct watchdog_info ident =
+	{
+		.options = WDIOF_KEEPALIVEPING | WDIOF_SETTIMEOUT | WDIOF_MAGICCLOSE,
+		.firmware_version = 1,
+		.identity = "ALiM7101",
+	};
+
+	switch(cmd)
+	{
+		case WDIOC_GETSUPPORT:
+			return copy_to_user(argp, &ident, sizeof(ident))?-EFAULT:0;
+		case WDIOC_GETSTATUS:
+		case WDIOC_GETBOOTSTATUS:
+			return put_user(0, p);
+		case WDIOC_KEEPALIVE:
+			wdt_keepalive();
+			return 0;
+		case WDIOC_SETOPTIONS:
+		{
+			int new_options, retval = -EINVAL;
+
+			if(get_user(new_options, p))
+				return -EFAULT;
+
+			if(new_options & WDIOS_DISABLECARD) {
+				wdt_turnoff();
+				retval = 0;
+			}
+
+			if(new_options & WDIOS_ENABLECARD) {
+				wdt_startup();
+				retval = 0;
+			}
+
+			return retval;
+		}
+		case WDIOC_SETTIMEOUT:
+		{
+			int new_timeout;
+
+			if(get_user(new_timeout, p))
+				return -EFAULT;
+
+			if(new_timeout < 1 || new_timeout > 3600) /* arbitrary upper limit */
+				return -EINVAL;
+
+			timeout = new_timeout;
+			wdt_keepalive();
+			/* Fall through */
+		}
+		case WDIOC_GETTIMEOUT:
+			return put_user(timeout, p);
+		default:
+			return -ENOIOCTLCMD;
+	}
+}
+
+static struct file_operations wdt_fops = {
+	.owner=		THIS_MODULE,
+	.llseek=	no_llseek,
+	.write=		fop_write,
+	.open=		fop_open,
+	.release=	fop_close,
+	.ioctl=		fop_ioctl,
+};
+
+static struct miscdevice wdt_miscdev = {
+	.minor=WATCHDOG_MINOR,
+	.name="watchdog",
+	.fops=&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();
+
+	if (code==SYS_RESTART) {
+		/*
+		 * Cobalt devices have no way of rebooting themselves other than
+		 * getting the watchdog to pull reset, so we restart the watchdog on
+		 * reboot with no heartbeat
+		 */
+		wdt_change(WDT_ENABLE);
+		printk(KERN_INFO PFX "Watchdog timer is now enabled with no heartbeat - should reboot in ~1 second.\n");
+	}
+	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=
+{
+	.notifier_call = wdt_notify_sys,
+};
+
+static void __exit alim7101_wdt_unload(void)
+{
+	wdt_turnoff();
+	/* Deregister */
+	misc_deregister(&wdt_miscdev);
+	unregister_reboot_notifier(&wdt_notifier);
+}
+
+static int __init alim7101_wdt_init(void)
+{
+	int rc = -EBUSY;
+	struct pci_dev *ali1543_south;
+	char tmp;
+
+	printk(KERN_INFO PFX "Steve Hill <steve@navaho.co.uk>.\n");
+	alim7101_pmu = pci_find_device(PCI_VENDOR_ID_AL, PCI_DEVICE_ID_AL_M7101,NULL);
+	if (!alim7101_pmu) {
+		printk(KERN_INFO PFX "ALi M7101 PMU not present - WDT not set\n");
+		return -EBUSY;
+	}
+
+	/* Set the WDT in the PMU to 1 second */
+	pci_write_config_byte(alim7101_pmu, ALI_7101_WDT, 0x02);
+
+	ali1543_south = pci_find_device(PCI_VENDOR_ID_AL, PCI_DEVICE_ID_AL_M1533, NULL);
+	if (!ali1543_south) {
+		printk(KERN_INFO PFX "ALi 1543 South-Bridge not present - WDT not set\n");
+		return -EBUSY;
+	}
+	pci_read_config_byte(ali1543_south, 0x5e, &tmp);
+	if ((tmp & 0x1e) == 0x00) {
+		if (!use_gpio) {
+			printk(KERN_INFO PFX "Detected old alim7101 revision 'a1d'.  If this is a cobalt board, set the 'use_gpio' module parameter.\n");
+			return -EBUSY;
+		} 
+		nowayout = 1;
+	} else if ((tmp & 0x1e) != 0x12 && (tmp & 0x1e) != 0x00) {
+		printk(KERN_INFO PFX "ALi 1543 South-Bridge does not have the correct revision number (???1001?) - WDT not set\n");
+		return -EBUSY;
+	}
+
+	if(timeout < 1 || timeout > 3600) /* arbitrary upper limit */
+	{
+		timeout = WATCHDOG_TIMEOUT;
+		printk(KERN_INFO PFX "timeout value must be 1<=x<=3600, using %d\n",
+			timeout);
+	}
+
+	init_timer(&timer);
+	timer.function = wdt_timer_ping;
+	timer.data = 1;
+
+	rc = misc_register(&wdt_miscdev);
+	if (rc) {
+		printk(KERN_ERR PFX "cannot register miscdev on minor=%d (err=%d)\n",
+			wdt_miscdev.minor, rc);
+		goto err_out;
+	}
+
+	rc = register_reboot_notifier(&wdt_notifier);
+	if (rc) {
+		printk(KERN_ERR PFX "cannot register reboot notifier (err=%d)\n",
+			rc);
+		goto err_out_miscdev;
+	}
+
+	if (nowayout) {
+		__module_get(THIS_MODULE);
+	}
+
+	printk(KERN_INFO PFX "WDT driver for ALi M7101 initialised. timeout=%d sec (nowayout=%d)\n",
+		timeout, nowayout);
+	return 0;
+
+err_out_miscdev:
+	misc_deregister(&wdt_miscdev);
+err_out:
+	return rc;
+}
+
+module_init(alim7101_wdt_init);
+module_exit(alim7101_wdt_unload);
+
+MODULE_AUTHOR("Steve Hill");
+MODULE_DESCRIPTION("ALi M7101 PMU Computer Watchdog Timer driver");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS_MISCDEV(WATCHDOG_MINOR);
diff --git a/drivers/char/watchdog/cpu5wdt.c b/drivers/char/watchdog/cpu5wdt.c
new file mode 100644
index 0000000..2865dac
--- /dev/null
+++ b/drivers/char/watchdog/cpu5wdt.c
@@ -0,0 +1,303 @@
+/*
+ * sma cpu5 watchdog driver
+ *
+ * Copyright (C) 2003 Heiko Ronsdorf <hero@ihg.uni-duisburg.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.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/types.h>
+#include <linux/errno.h>
+#include <linux/miscdevice.h>
+#include <linux/fs.h>
+#include <linux/init.h>
+#include <linux/ioport.h>
+#include <linux/timer.h>
+#include <asm/io.h>
+#include <asm/uaccess.h>
+
+#include <linux/watchdog.h>
+
+/* adjustable parameters */
+
+static int verbose = 0;
+static int port = 0x91;
+static int ticks = 10000;
+
+#define PFX			"cpu5wdt: "
+
+#define CPU5WDT_EXTENT          0x0A
+
+#define CPU5WDT_STATUS_REG      0x00
+#define CPU5WDT_TIME_A_REG      0x02
+#define CPU5WDT_TIME_B_REG      0x03
+#define CPU5WDT_MODE_REG        0x04
+#define CPU5WDT_TRIGGER_REG     0x07
+#define CPU5WDT_ENABLE_REG      0x08
+#define CPU5WDT_RESET_REG       0x09
+
+#define CPU5WDT_INTERVAL	(HZ/10+1)
+
+/* some device data */
+
+static struct {
+	struct semaphore stop;
+	volatile int running;
+	struct timer_list timer;
+	volatile int queue;
+	int default_ticks;
+	unsigned long inuse;
+} cpu5wdt_device;
+
+/* generic helper functions */
+
+static void cpu5wdt_trigger(unsigned long unused)
+{
+	if ( verbose > 2 )
+		printk(KERN_DEBUG PFX "trigger at %i ticks\n", ticks);
+
+	if( cpu5wdt_device.running )
+		ticks--;
+
+	/* keep watchdog alive */
+	outb(1, port + CPU5WDT_TRIGGER_REG);
+
+	/* requeue?? */
+	if( cpu5wdt_device.queue && ticks ) {
+		cpu5wdt_device.timer.expires = jiffies + CPU5WDT_INTERVAL;
+		add_timer(&cpu5wdt_device.timer);
+	}
+	else {
+		/* ticks doesn't matter anyway */
+		up(&cpu5wdt_device.stop);
+	}
+
+}
+
+static void cpu5wdt_reset(void)
+{
+	ticks = cpu5wdt_device.default_ticks;
+
+	if ( verbose )
+		printk(KERN_DEBUG PFX "reset (%i ticks)\n", (int) ticks);
+
+}
+
+static void cpu5wdt_start(void)
+{
+	if ( !cpu5wdt_device.queue ) {
+		cpu5wdt_device.queue = 1;
+		outb(0, port + CPU5WDT_TIME_A_REG);
+		outb(0, port + CPU5WDT_TIME_B_REG);
+		outb(1, port + CPU5WDT_MODE_REG);
+		outb(0, port + CPU5WDT_RESET_REG);
+		outb(0, port + CPU5WDT_ENABLE_REG);
+		cpu5wdt_device.timer.expires = jiffies + CPU5WDT_INTERVAL;
+		add_timer(&cpu5wdt_device.timer);
+	}
+	/* if process dies, counter is not decremented */
+	cpu5wdt_device.running++;
+}
+
+static int cpu5wdt_stop(void)
+{
+	if ( cpu5wdt_device.running )
+		cpu5wdt_device.running = 0;
+
+	ticks = cpu5wdt_device.default_ticks;
+
+	if ( verbose )
+		printk(KERN_CRIT PFX "stop not possible\n");
+
+	return -EIO;
+}
+
+/* filesystem operations */
+
+static int cpu5wdt_open(struct inode *inode, struct file *file)
+{
+	if ( test_and_set_bit(0, &cpu5wdt_device.inuse) )
+		return -EBUSY;
+
+	return nonseekable_open(inode, file);
+}
+
+static int cpu5wdt_release(struct inode *inode, struct file *file)
+{
+	clear_bit(0, &cpu5wdt_device.inuse);
+	return 0;
+}
+
+static int cpu5wdt_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg)
+{
+	void __user *argp = (void __user *)arg;
+	unsigned int value;
+	static struct watchdog_info ident =
+	{
+		.options = WDIOF_CARDRESET,
+		.identity = "CPU5 WDT",
+	};
+
+	switch(cmd) {
+		case WDIOC_KEEPALIVE:
+			cpu5wdt_reset();
+			break;
+		case WDIOC_GETSTATUS:
+			value = inb(port + CPU5WDT_STATUS_REG);
+			value = (value >> 2) & 1;
+			if ( copy_to_user(argp, &value, sizeof(int)) )
+				return -EFAULT;
+			break;
+		case WDIOC_GETSUPPORT:
+			if ( copy_to_user(argp, &ident, sizeof(ident)) )
+				return -EFAULT;
+			break;
+		case WDIOC_SETOPTIONS:
+			if ( copy_from_user(&value, argp, sizeof(int)) )
+				return -EFAULT;
+			switch(value) {
+				case WDIOS_ENABLECARD:
+					cpu5wdt_start();
+					break;
+				case WDIOS_DISABLECARD:
+					return cpu5wdt_stop();
+				default:
+					return -EINVAL;
+			}
+			break;
+		default:
+    			return -ENOIOCTLCMD;
+	}
+	return 0;
+}
+
+static ssize_t cpu5wdt_write(struct file *file, const char __user *buf, size_t count, loff_t *ppos)
+{
+	if ( !count )
+		return -EIO;
+
+	cpu5wdt_reset();
+
+	return count;
+}
+
+static struct file_operations cpu5wdt_fops = {
+	.owner		= THIS_MODULE,
+	.llseek		= no_llseek,
+	.ioctl		= cpu5wdt_ioctl,
+	.open		= cpu5wdt_open,
+	.write		= cpu5wdt_write,
+	.release	= cpu5wdt_release,
+};
+
+static struct miscdevice cpu5wdt_misc = {
+	.minor	= WATCHDOG_MINOR,
+	.name	= "watchdog",
+	.fops	= &cpu5wdt_fops,
+};
+
+/* init/exit function */
+
+static int __devinit cpu5wdt_init(void)
+{
+	unsigned int val;
+	int err;
+
+	if ( verbose )
+		printk(KERN_DEBUG PFX "port=0x%x, verbose=%i\n", port, verbose);
+
+	if ( (err = misc_register(&cpu5wdt_misc)) < 0 ) {
+		printk(KERN_ERR PFX "misc_register failed\n");
+		goto no_misc;
+	}
+
+	if ( !request_region(port, CPU5WDT_EXTENT, PFX) ) {
+		printk(KERN_ERR PFX "request_region failed\n");
+		err = -EBUSY;
+		goto no_port;
+	}
+
+	/* watchdog reboot? */
+	val = inb(port + CPU5WDT_STATUS_REG);
+	val = (val >> 2) & 1;
+	if ( !val )
+		printk(KERN_INFO PFX "sorry, was my fault\n");
+
+	init_MUTEX_LOCKED(&cpu5wdt_device.stop);
+	cpu5wdt_device.queue = 0;
+
+	clear_bit(0, &cpu5wdt_device.inuse);
+
+	init_timer(&cpu5wdt_device.timer);
+	cpu5wdt_device.timer.function = cpu5wdt_trigger;
+	cpu5wdt_device.timer.data = 0;
+
+	cpu5wdt_device.default_ticks = ticks;
+
+	printk(KERN_INFO PFX "init success\n");
+
+	return 0;
+
+no_port:
+	misc_deregister(&cpu5wdt_misc);
+no_misc:
+	return err;
+}
+
+static int __devinit cpu5wdt_init_module(void)
+{
+	return cpu5wdt_init();
+}
+
+static void __devexit cpu5wdt_exit(void)
+{
+	if ( cpu5wdt_device.queue ) {
+		cpu5wdt_device.queue = 0;
+		down(&cpu5wdt_device.stop);
+	}
+
+	misc_deregister(&cpu5wdt_misc);
+
+	release_region(port, CPU5WDT_EXTENT);
+
+}
+
+static void __devexit cpu5wdt_exit_module(void)
+{
+	cpu5wdt_exit();
+}
+
+/* module entry points */
+
+module_init(cpu5wdt_init_module);
+module_exit(cpu5wdt_exit_module);
+
+MODULE_AUTHOR("Heiko Ronsdorf <hero@ihg.uni-duisburg.de>");
+MODULE_DESCRIPTION("sma cpu5 watchdog driver");
+MODULE_SUPPORTED_DEVICE("sma cpu5 watchdog");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS_MISCDEV(WATCHDOG_MINOR);
+
+module_param(port, int, 0);
+MODULE_PARM_DESC(port, "base address of watchdog card, default is 0x91");
+
+module_param(verbose, int, 0);
+MODULE_PARM_DESC(verbose, "be verbose, default is 0 (no)");
+
+module_param(ticks, int, 0);
+MODULE_PARM_DESC(ticks, "count down ticks, default is 10000");
diff --git a/drivers/char/watchdog/eurotechwdt.c b/drivers/char/watchdog/eurotechwdt.c
new file mode 100644
index 0000000..d10e554
--- /dev/null
+++ b/drivers/char/watchdog/eurotechwdt.c
@@ -0,0 +1,474 @@
+/*
+ *	Eurotech CPU-1220/1410 on board WDT driver
+ *
+ *	(c) Copyright 2001 Ascensit <support@ascensit.com>
+ *	(c) Copyright 2001 Rodolfo Giometti <giometti@ascensit.com>
+ *	(c) Copyright 2002 Rob Radez <rob@osinvestor.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>*
+ */
+
+/* Changelog:
+ *
+ * 2002/04/25 - Rob Radez
+ *	clean up #includes
+ *	clean up locking
+ *	make __setup param unique
+ *	proper options in watchdog_info
+ *	add WDIOC_GETSTATUS and WDIOC_SETOPTIONS ioctls
+ *	add expect_close support
+ *
+ * 2001 - Rodolfo Giometti
+ *	Initial release
+ *
+ * 2002.05.30 - Joel Becker <joel.becker@oracle.com>
+ * 	Added Matt Domsch's nowayout module option.
+ */
+
+#include <linux/config.h>
+#include <linux/interrupt.h>
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/types.h>
+#include <linux/miscdevice.h>
+#include <linux/watchdog.h>
+#include <linux/fs.h>
+#include <linux/ioport.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 eurwdt_is_open;
+static int eurwdt_timeout;
+static char eur_expect_close;
+
+/*
+ * You must set these - there is no sane way to probe for this board.
+ * You can use eurwdt=x,y to set these now.
+ */
+
+static int io = 0x3f0;
+static int irq = 10;
+static char *ev = "int";
+
+#define WDT_TIMEOUT		60                /* 1 minute */
+
+#ifdef CONFIG_WATCHDOG_NOWAYOUT
+static int nowayout = 1;
+#else
+static int nowayout = 0;
+#endif
+
+module_param(nowayout, int, 0);
+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
+
+
+module_param(io, int, 0);
+MODULE_PARM_DESC(io, "Eurotech WDT io port (default=0x3f0)");
+module_param(irq, int, 0);
+MODULE_PARM_DESC(irq, "Eurotech WDT irq (default=10)");
+module_param(ev, charp, 0);
+MODULE_PARM_DESC(ev, "Eurotech WDT event type (default is `int')");
+
+
+/*
+ * Programming support
+ */
+
+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.
+ */
+
+static irqreturn_t 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
+	return IRQ_HANDLED;
+}
+
+
+/**
+ * eurwdt_ping:
+ *
+ * Reload counter one with the watchdog timeout.
+ */
+
+static void eurwdt_ping(void)
+{
+	/* Write the watchdog default value */
+	eurwdt_set_timeout(eurwdt_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 __user *buf,
+size_t count, loff_t *ppos)
+{
+	if (count) 	{
+		if (!nowayout) {
+			size_t i;
+
+			eur_expect_close = 0;
+
+			for (i = 0; i != count; i++) {
+				char c;
+				if(get_user(c, buf+i))
+					return -EFAULT;
+				if (c == 'V')
+					eur_expect_close = 42;
+			}
+		}
+		eurwdt_ping();	/* the default timeout */
+	}
+
+	return count;
+}
+
+/**
+ * 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)
+{
+	void __user *argp = (void __user *)arg;
+	int __user *p = argp;
+	static struct watchdog_info ident = {
+		.options	  = WDIOF_KEEPALIVEPING | WDIOF_SETTIMEOUT | WDIOF_MAGICCLOSE,
+		.firmware_version = 1,
+		.identity	  = "WDT Eurotech CPU-1220/1410",
+	};
+
+	int time;
+	int options, retval = -EINVAL;
+
+	switch(cmd) {
+	default:
+		return -ENOIOCTLCMD;
+
+	case WDIOC_GETSUPPORT:
+		return copy_to_user(argp, &ident, sizeof(ident)) ? -EFAULT : 0;
+
+	case WDIOC_GETSTATUS:
+	case WDIOC_GETBOOTSTATUS:
+		return put_user(0, p);
+
+	case WDIOC_KEEPALIVE:
+		eurwdt_ping();
+		return 0;
+
+	case WDIOC_SETTIMEOUT:
+		if (copy_from_user(&time, p, sizeof(int)))
+			return -EFAULT;
+
+		/* Sanity check */
+		if (time < 0 || time > 255)
+			return -EINVAL;
+
+		eurwdt_timeout = time;
+		eurwdt_set_timeout(time);
+		/* Fall */
+
+	case WDIOC_GETTIMEOUT:
+		return put_user(eurwdt_timeout, p);
+
+	case WDIOC_SETOPTIONS:
+		if (get_user(options, p))
+			return -EFAULT;
+		if (options & WDIOS_DISABLECARD) {
+			eurwdt_disable_timer();
+			retval = 0;
+		}
+		if (options & WDIOS_ENABLECARD) {
+			eurwdt_activate_timer();
+			eurwdt_ping();
+			retval = 0;
+		}
+		return retval;
+	}
+}
+
+/**
+ * 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)
+{
+	if (test_and_set_bit(0, &eurwdt_is_open))
+		return -EBUSY;
+	eurwdt_timeout = WDT_TIMEOUT;	/* initial timeout */
+	/* Activate the WDT */
+	eurwdt_activate_timer();
+	return nonseekable_open(inode, file);
+}
+
+/**
+ * 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 (eur_expect_close == 42) {
+		eurwdt_disable_timer();
+	} else {
+		printk(KERN_CRIT "eurwdt: Unexpected close, not stopping watchdog!\n");
+		eurwdt_ping();
+	}
+	clear_bit(0, &eurwdt_is_open);
+	eur_expect_close = 0;
+	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;
+
+	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"));
+
+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");
+MODULE_ALIAS_MISCDEV(WATCHDOG_MINOR);
diff --git a/drivers/char/watchdog/i8xx_tco.c b/drivers/char/watchdog/i8xx_tco.c
new file mode 100644
index 0000000..c337978
--- /dev/null
+++ b/drivers/char/watchdog/i8xx_tco.c
@@ -0,0 +1,535 @@
+/*
+ *	i8xx_tco 0.07:	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  (ICH)    : document number 290655-003, 290677-014,
+ *	82801AB  (ICHO)   : document number 290655-003, 290677-014,
+ *	82801BA  (ICH2)   : document number 290687-002, 298242-027,
+ *	82801BAM (ICH2-M) : document number 290687-002, 298242-027,
+ *	82801CA  (ICH3-S) : document number 290733-003, 290739-013,
+ *	82801CAM (ICH3-M) : document number 290716-001, 290718-007,
+ *	82801DB  (ICH4)   : document number 290744-001, 290745-020,
+ *	82801DBM (ICH4-M) : document number 252337-001, 252663-005,
+ *	82801E   (C-ICH)  : document number 273599-001, 273645-002,
+ *	82801EB  (ICH5)   : document number 252516-001, 252517-003,
+ *	82801ER  (ICH5R)  : document number 252516-001, 252517-003,
+ *	82801FB  (ICH6)   : document number 301473-002, 301474-007,
+ *	82801FR  (ICH6R)  : document number 301473-002, 301474-007,
+ *	82801FBM (ICH6-M) : document number 301473-002, 301474-007,
+ *	82801FW  (ICH6W)  : document number 301473-001, 301474-007,
+ *	82801FRW (ICH6RW) : document number 301473-001, 301474-007
+ *
+ *  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,
+ *	     added support for 82801EB and 8280ER chipset,
+ *	     general cleanup.
+ *  20030921 Wim Van Sebroeck <wim@iguana.be>
+ *	0.06 change i810_margin to heartbeat, use module_param,
+ *	     added notify system support, renamed module to i8xx_tco.
+ *  20050128 Wim Van Sebroeck <wim@iguana.be>
+ *	0.07 Added support for the ICH4-M, ICH6, ICH6R, ICH6-M, ICH6W and ICH6RW
+ *	     chipsets. Also added support for the "undocumented" ICH7 chipset.
+ */
+
+/*
+ *	Includes, defines, variables, module parameters, ...
+ */
+
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/types.h>
+#include <linux/miscdevice.h>
+#include <linux/watchdog.h>
+#include <linux/notifier.h>
+#include <linux/reboot.h>
+#include <linux/init.h>
+#include <linux/fs.h>
+#include <linux/pci.h>
+#include <linux/ioport.h>
+
+#include <asm/uaccess.h>
+#include <asm/io.h>
+
+#include "i8xx_tco.h"
+
+/* Module and version information */
+#define TCO_VERSION "0.07"
+#define TCO_MODULE_NAME "i8xx TCO timer"
+#define TCO_DRIVER_NAME   TCO_MODULE_NAME ", v" TCO_VERSION
+#define PFX TCO_MODULE_NAME ": "
+
+/* internal variables */
+static unsigned int ACPIBASE;
+static spinlock_t tco_lock;	/* Guards the hardware */
+static unsigned long timer_alive;
+static char tco_expect_close;
+static struct pci_dev *i8xx_tco_pci;
+
+/* module parameters */
+#define WATCHDOG_HEARTBEAT 30	/* 30 sec default heartbeat (2<heartbeat<39) */
+static int heartbeat = WATCHDOG_HEARTBEAT;  /* in seconds */
+module_param(heartbeat, int, 0);
+MODULE_PARM_DESC(heartbeat, "Watchdog heartbeat in seconds. (2<heartbeat<39, default=" __MODULE_STRING(WATCHDOG_HEARTBEAT) ")");
+
+#ifdef CONFIG_WATCHDOG_NOWAYOUT
+static int nowayout = 1;
+#else
+static int nowayout = 0;
+#endif
+
+module_param(nowayout, int, 0);
+MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default=CONFIG_WATCHDOG_NOWAYOUT)");
+
+/*
+ * Some TCO specific functions
+ */
+
+static inline unsigned char seconds_to_ticks(int seconds)
+{
+	/* the internal timer is stored as ticks which decrement
+	 * every 0.6 seconds */
+	return (seconds * 10) / 6;
+}
+
+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;
+}
+
+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;
+}
+
+static int tco_timer_keepalive (void)
+{
+	spin_lock(&tco_lock);
+	outb (0x01, TCO1_RLD);
+	spin_unlock(&tco_lock);
+	return 0;
+}
+
+static int tco_timer_set_heartbeat (int t)
+{
+	unsigned char val;
+	unsigned char tmrval;
+
+	tmrval = seconds_to_ticks(t);
+	/* from the specs: */
+	/* "Values of 0h-3h are ignored and should not be attempted" */
+	if (tmrval > 0x3f || tmrval < 0x04)
+		return -EINVAL;
+
+	/* Write new heartbeat to watchdog */
+	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 -EINVAL;
+
+	heartbeat = t;
+	return 0;
+}
+
+/*
+ *	/dev/watchdog handling
+ */
+
+static int i8xx_tco_open (struct inode *inode, struct file *file)
+{
+	/* /dev/watchdog can only be opened once */
+	if (test_and_set_bit(0, &timer_alive))
+		return -EBUSY;
+
+	/*
+	 *      Reload and activate timer
+	 */
+	tco_timer_keepalive ();
+	tco_timer_start ();
+	return nonseekable_open(inode, file);
+}
+
+static int i8xx_tco_release (struct inode *inode, struct file *file)
+{
+	/*
+	 *      Shut off the timer.
+	 */
+	if (tco_expect_close == 42) {
+		tco_timer_stop ();
+	} else {
+		printk(KERN_CRIT PFX "Unexpected close, not stopping watchdog!\n");
+		tco_timer_keepalive ();
+	}
+	clear_bit(0, &timer_alive);
+	tco_expect_close = 0;
+	return 0;
+}
+
+static ssize_t i8xx_tco_write (struct file *file, const char __user *data,
+			      size_t len, loff_t * ppos)
+{
+	/* See if we got the magic character 'V' and reload the timer */
+	if (len) {
+		if (!nowayout) {
+			size_t i;
+
+			/* note: just in case someone wrote the magic character
+			 * five months ago... */
+			tco_expect_close = 0;
+
+			/* scan to see whether or not we got the magic character */
+			for (i = 0; i != len; i++) {
+				char 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_keepalive ();
+	}
+	return len;
+}
+
+static int i8xx_tco_ioctl (struct inode *inode, struct file *file,
+			  unsigned int cmd, unsigned long arg)
+{
+	int new_options, retval = -EINVAL;
+	int new_heartbeat;
+	void __user *argp = (void __user *)arg;
+	int __user *p = argp;
+	static struct watchdog_info ident = {
+		.options =		WDIOF_SETTIMEOUT |
+					WDIOF_KEEPALIVEPING |
+					WDIOF_MAGICCLOSE,
+		.firmware_version =	0,
+		.identity =		TCO_MODULE_NAME,
+	};
+
+	switch (cmd) {
+		case WDIOC_GETSUPPORT:
+			return copy_to_user(argp, &ident,
+				sizeof (ident)) ? -EFAULT : 0;
+
+		case WDIOC_GETSTATUS:
+		case WDIOC_GETBOOTSTATUS:
+			return put_user (0, p);
+
+		case WDIOC_KEEPALIVE:
+			tco_timer_keepalive ();
+			return 0;
+
+		case WDIOC_SETOPTIONS:
+		{
+			if (get_user (new_options, p))
+				return -EFAULT;
+
+			if (new_options & WDIOS_DISABLECARD) {
+				tco_timer_stop ();
+				retval = 0;
+			}
+
+			if (new_options & WDIOS_ENABLECARD) {
+				tco_timer_keepalive ();
+				tco_timer_start ();
+				retval = 0;
+			}
+
+			return retval;
+		}
+
+		case WDIOC_SETTIMEOUT:
+		{
+			if (get_user(new_heartbeat, p))
+				return -EFAULT;
+
+			if (tco_timer_set_heartbeat(new_heartbeat))
+			    return -EINVAL;
+
+			tco_timer_keepalive ();
+			/* Fall */
+		}
+
+		case WDIOC_GETTIMEOUT:
+			return put_user(heartbeat, p);
+
+		default:
+			return -ENOIOCTLCMD;
+	}
+}
+
+/*
+ *	Notify system
+ */
+
+static int i8xx_tco_notify_sys (struct notifier_block *this, unsigned long code, void *unused)
+{
+	if (code==SYS_DOWN || code==SYS_HALT) {
+		/* Turn the WDT off */
+		tco_timer_stop ();
+	}
+
+	return NOTIFY_DONE;
+}
+
+/*
+ *	Kernel Interfaces
+ */
+
+static struct file_operations i8xx_tco_fops = {
+	.owner =	THIS_MODULE,
+	.llseek =	no_llseek,
+	.write =	i8xx_tco_write,
+	.ioctl =	i8xx_tco_ioctl,
+	.open =		i8xx_tco_open,
+	.release =	i8xx_tco_release,
+};
+
+static struct miscdevice i8xx_tco_miscdev = {
+	.minor =	WATCHDOG_MINOR,
+	.name =		"watchdog",
+	.fops =		&i8xx_tco_fops,
+};
+
+static struct notifier_block i8xx_tco_notifier = {
+	.notifier_call =	i8xx_tco_notify_sys,
+};
+
+/*
+ * 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 i8xx_tco_pci_tbl[] = {
+	{ 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_82801DB_12,	PCI_ANY_ID, PCI_ANY_ID, },
+	{ PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801E_0,	PCI_ANY_ID, PCI_ANY_ID, },
+	{ PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801EB_0,	PCI_ANY_ID, PCI_ANY_ID, },
+	{ PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ICH6_0,	PCI_ANY_ID, PCI_ANY_ID, },
+	{ PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ICH6_1,	PCI_ANY_ID, PCI_ANY_ID, },
+	{ PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ICH6_2,	PCI_ANY_ID, PCI_ANY_ID, },
+	{ PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ICH7_0,	PCI_ANY_ID, PCI_ANY_ID, },
+	{ PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ICH7_1,	PCI_ANY_ID, PCI_ANY_ID, },
+	{ 0, },			/* End of list */
+};
+MODULE_DEVICE_TABLE (pci, i8xx_tco_pci_tbl);
+
+/*
+ *	Init & exit routines
+ */
+
+static unsigned char __init i8xx_tco_getdevice (void)
+{
+	struct pci_dev *dev = NULL;
+	u8 val1, val2;
+	u16 badr;
+	/*
+	 *      Find the PCI device
+	 */
+
+	while ((dev = pci_find_device(PCI_ANY_ID, PCI_ANY_ID, dev)) != NULL) {
+		if (pci_match_device(i8xx_tco_pci_tbl, dev)) {
+			i8xx_tco_pci = dev;
+			break;
+		}
+	}
+
+	if (i8xx_tco_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 (i8xx_tco_pci, 0x40, &val1);
+		pci_read_config_byte (i8xx_tco_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 PFX "failed to get TCOBASE address\n");
+			return 0;
+		}
+		/*
+		 * Check chipset's NO_REBOOT bit
+		 */
+		pci_read_config_byte (i8xx_tco_pci, 0xd4, &val1);
+		if (val1 & 0x02) {
+			val1 &= 0xfd;
+			pci_write_config_byte (i8xx_tco_pci, 0xd4, val1);
+			pci_read_config_byte (i8xx_tco_pci, 0xd4, &val1);
+			if (val1 & 0x02) {
+				printk (KERN_ERR PFX "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 */
+		if (!request_region (SMI_EN + 1, 1, "i8xx TCO")) {
+			printk (KERN_ERR PFX "I/O address 0x%04x already in use\n",
+				SMI_EN + 1);
+			return 0;
+		}
+		val1 = inb (SMI_EN + 1);
+		val1 &= 0xdf;
+		outb (val1, SMI_EN + 1);
+		release_region (SMI_EN + 1, 1);
+		return 1;
+	}
+	return 0;
+}
+
+static int __init watchdog_init (void)
+{
+	int ret;
+
+	spin_lock_init(&tco_lock);
+
+	/* Check whether or not the hardware watchdog is there */
+	if (!i8xx_tco_getdevice () || i8xx_tco_pci == NULL)
+		return -ENODEV;
+
+	if (!request_region (TCOBASE, 0x10, "i8xx TCO")) {
+		printk (KERN_ERR PFX "I/O address 0x%04x already in use\n",
+			TCOBASE);
+		ret = -EIO;
+		goto out;
+	}
+
+	/* Clear out the (probably old) status */
+	outb (0, TCO1_STS);
+	outb (3, TCO2_STS);
+
+	/* Check that the heartbeat value is within it's range ; if not reset to the default */
+	if (tco_timer_set_heartbeat (heartbeat)) {
+		heartbeat = WATCHDOG_HEARTBEAT;
+		tco_timer_set_heartbeat (heartbeat);
+		printk(KERN_INFO PFX "heartbeat value must be 2<heartbeat<39, using %d\n",
+			heartbeat);
+	}
+
+	ret = register_reboot_notifier(&i8xx_tco_notifier);
+	if (ret != 0) {
+		printk(KERN_ERR PFX "cannot register reboot notifier (err=%d)\n",
+			ret);
+		goto unreg_region;
+	}
+
+	ret = misc_register(&i8xx_tco_miscdev);
+	if (ret != 0) {
+		printk(KERN_ERR PFX "cannot register miscdev on minor=%d (err=%d)\n",
+			WATCHDOG_MINOR, ret);
+		goto unreg_notifier;
+	}
+
+	tco_timer_stop ();
+
+	printk (KERN_INFO PFX "initialized (0x%04x). heartbeat=%d sec (nowayout=%d)\n",
+		TCOBASE, heartbeat, nowayout);
+
+	return 0;
+
+unreg_notifier:
+	unregister_reboot_notifier(&i8xx_tco_notifier);
+unreg_region:
+	release_region (TCOBASE, 0x10);
+out:
+	return ret;
+}
+
+static void __exit watchdog_cleanup (void)
+{
+	u8 val;
+
+	/* Stop the timer before we leave */
+	if (!nowayout)
+		tco_timer_stop ();
+
+	/* Set the NO_REBOOT bit to prevent later reboots, just for sure */
+	pci_read_config_byte (i8xx_tco_pci, 0xd4, &val);
+	val |= 0x02;
+	pci_write_config_byte (i8xx_tco_pci, 0xd4, val);
+
+	/* Deregister */
+	misc_deregister (&i8xx_tco_miscdev);
+	unregister_reboot_notifier(&i8xx_tco_notifier);
+	release_region (TCOBASE, 0x10);
+}
+
+module_init(watchdog_init);
+module_exit(watchdog_cleanup);
+
+MODULE_AUTHOR("Nils Faerber");
+MODULE_DESCRIPTION("TCO timer driver for i8xx chipsets");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS_MISCDEV(WATCHDOG_MINOR);
diff --git a/drivers/char/watchdog/i8xx_tco.h b/drivers/char/watchdog/i8xx_tco.h
new file mode 100644
index 0000000..cc14eb8
--- /dev/null
+++ b/drivers/char/watchdog/i8xx_tco.h
@@ -0,0 +1,42 @@
+/*
+ *	i8xx_tco:	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>
+ *
+ *	For history and the complete list of supported I/O Controller Hub's
+ *	see i8xx_tco.c
+ */
+
+
+/*
+ * Some address definitions for the TCO
+ */
+
+#define	TCOBASE		ACPIBASE + 0x60	/* TCO base address		*/
+#define TCO1_RLD	TCOBASE + 0x00	/* TCO Timer Reload and Current Value */
+#define TCO1_TMR	TCOBASE + 0x01	/* TCO Timer Initial Value	*/
+#define	TCO1_DAT_IN	TCOBASE + 0x02	/* TCO Data In Register		*/
+#define	TCO1_DAT_OUT	TCOBASE + 0x03	/* TCO Data Out Register	*/
+#define	TCO1_STS	TCOBASE + 0x04	/* TCO1 Status Register		*/
+#define	TCO2_STS	TCOBASE + 0x06	/* TCO2 Status Register		*/
+#define TCO1_CNT	TCOBASE + 0x08	/* TCO1 Control Register	*/
+#define TCO2_CNT	TCOBASE + 0x0a	/* TCO2 Control Register	*/
+
+#define	SMI_EN		ACPIBASE + 0x30	/* SMI Control and Enable Register */
diff --git a/drivers/char/watchdog/ib700wdt.c b/drivers/char/watchdog/ib700wdt.c
new file mode 100644
index 0000000..d974f16
--- /dev/null
+++ b/drivers/char/watchdog/ib700wdt.c
@@ -0,0 +1,352 @@
+/*
+ *	IB700 Single Board Computer WDT driver
+ *
+ *	(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/types.h>
+#include <linux/miscdevice.h>
+#include <linux/watchdog.h>
+#include <linux/ioport.h>
+#include <linux/notifier.h>
+#include <linux/fs.h>
+#include <linux/reboot.h>
+#include <linux/init.h>
+#include <linux/spinlock.h>
+#include <linux/moduleparam.h>
+
+#include <asm/io.h>
+#include <asm/uaccess.h>
+#include <asm/system.h>
+
+static unsigned long ibwdt_is_open;
+static spinlock_t ibwdt_lock;
+static char expect_close;
+
+#define PFX "ib700wdt: "
+
+/*
+ *
+ * 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
+ *
+ */
+
+static int wd_times[] = {
+	30,	/* 0x0 */
+	28,	/* 0x1 */
+	26,	/* 0x2 */
+	24,	/* 0x3 */
+	22,	/* 0x4 */
+	20,	/* 0x5 */
+	18,	/* 0x6 */
+	16,	/* 0x7 */
+	14,	/* 0x8 */
+	12,	/* 0x9 */
+	10,	/* 0xA */
+	8,	/* 0xB */
+	6,	/* 0xC */
+	4,	/* 0xD */
+	2,	/* 0xE */
+	0,	/* 0xF */
+};
+
+#define WDT_STOP 0x441
+#define WDT_START 0x443
+
+/* Default timeout */
+#define WD_TIMO 0		/* 30 seconds +/- 20%, from table */
+
+static int wd_margin = WD_TIMO;
+
+#ifdef CONFIG_WATCHDOG_NOWAYOUT
+static int nowayout = 1;
+#else
+static int nowayout = 0;
+#endif
+
+module_param(nowayout, int, 0);
+MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default=CONFIG_WATCHDOG_NOWAYOUT)");
+
+
+/*
+ *	Kernel methods.
+ */
+
+static void
+ibwdt_ping(void)
+{
+	/* Write a watchdog value */
+	outb_p(wd_margin, WDT_START);
+}
+
+static ssize_t
+ibwdt_write(struct file *file, const char __user *buf, size_t count, loff_t *ppos)
+{
+	if (count) {
+		if (!nowayout) {
+			size_t i;
+
+			/* In case it was set long ago */
+			expect_close = 0;
+
+			for (i = 0; i != count; i++) {
+				char c;
+				if (get_user(c, buf + i))
+					return -EFAULT;
+				if (c == 'V')
+					expect_close = 42;
+			}
+		}
+		ibwdt_ping();
+	}
+	return count;
+}
+
+static int
+ibwdt_ioctl(struct inode *inode, struct file *file, unsigned int cmd,
+	  unsigned long arg)
+{
+	int i, new_margin;
+	void __user *argp = (void __user *)arg;
+	int __user *p = argp;
+
+	static struct watchdog_info ident = {
+		.options = WDIOF_KEEPALIVEPING | WDIOF_SETTIMEOUT | WDIOF_MAGICCLOSE,
+		.firmware_version = 1,
+		.identity = "IB700 WDT",
+	};
+
+	switch (cmd) {
+	case WDIOC_GETSUPPORT:
+	  if (copy_to_user(argp, &ident, sizeof(ident)))
+	    return -EFAULT;
+	  break;
+
+	case WDIOC_GETSTATUS:
+	  return put_user(0, p);
+
+	case WDIOC_KEEPALIVE:
+	  ibwdt_ping();
+	  break;
+
+	case WDIOC_SETTIMEOUT:
+	  if (get_user(new_margin, p))
+		  return -EFAULT;
+	  if ((new_margin < 0) || (new_margin > 30))
+		  return -EINVAL;
+	  for (i = 0x0F; i > -1; i--)
+		  if (wd_times[i] > new_margin)
+			  break;
+	  wd_margin = i;
+	  ibwdt_ping();
+	  /* Fall */
+
+	case WDIOC_GETTIMEOUT:
+	  return put_user(wd_times[wd_margin], p);
+	  break;
+
+	default:
+	  return -ENOIOCTLCMD;
+	}
+	return 0;
+}
+
+static int
+ibwdt_open(struct inode *inode, struct file *file)
+{
+	spin_lock(&ibwdt_lock);
+	if (test_and_set_bit(0, &ibwdt_is_open)) {
+		spin_unlock(&ibwdt_lock);
+		return -EBUSY;
+	}
+	if (nowayout)
+		__module_get(THIS_MODULE);
+
+	/* Activate */
+	ibwdt_ping();
+	spin_unlock(&ibwdt_lock);
+	return nonseekable_open(inode, file);
+}
+
+static int
+ibwdt_close(struct inode *inode, struct file *file)
+{
+	spin_lock(&ibwdt_lock);
+	if (expect_close == 42)
+		outb_p(0, WDT_STOP);
+	else
+		printk(KERN_CRIT PFX "WDT device closed unexpectedly.  WDT will not stop!\n");
+
+	clear_bit(0, &ibwdt_is_open);
+	expect_close = 0;
+	spin_unlock(&ibwdt_lock);
+	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(0, WDT_STOP);
+	}
+	return NOTIFY_DONE;
+}
+
+/*
+ *	Kernel Interfaces
+ */
+
+static struct file_operations ibwdt_fops = {
+	.owner		= THIS_MODULE,
+	.llseek		= no_llseek,
+	.write		= ibwdt_write,
+	.ioctl		= ibwdt_ioctl,
+	.open		= ibwdt_open,
+	.release	= ibwdt_close,
+};
+
+static struct miscdevice ibwdt_miscdev = {
+	.minor = WATCHDOG_MINOR,
+	.name = "watchdog",
+	.fops = &ibwdt_fops,
+};
+
+/*
+ *	The WDT needs to learn about soft shutdowns in order to
+ *	turn the timebomb registers off.
+ */
+
+static struct notifier_block ibwdt_notifier = {
+	.notifier_call = ibwdt_notify_sys,
+};
+
+static int __init ibwdt_init(void)
+{
+	int res;
+
+	printk(KERN_INFO PFX "WDT driver for IB700 single board computer initialising.\n");
+
+	spin_lock_init(&ibwdt_lock);
+	res = misc_register(&ibwdt_miscdev);
+	if (res) {
+		printk (KERN_ERR PFX "failed to register misc device\n");
+		goto out_nomisc;
+	}
+
+#if WDT_START != WDT_STOP
+	if (!request_region(WDT_STOP, 1, "IB700 WDT")) {
+		printk (KERN_ERR PFX "STOP method I/O %X is not available.\n", WDT_STOP);
+		res = -EIO;
+		goto out_nostopreg;
+	}
+#endif
+
+	if (!request_region(WDT_START, 1, "IB700 WDT")) {
+		printk (KERN_ERR PFX "START method I/O %X is not available.\n", WDT_START);
+		res = -EIO;
+		goto out_nostartreg;
+	}
+	res = register_reboot_notifier(&ibwdt_notifier);
+	if (res) {
+		printk (KERN_ERR PFX "Failed to register reboot notifier.\n");
+		goto out_noreboot;
+	}
+	return 0;
+
+out_noreboot:
+	release_region(WDT_START, 1);
+out_nostartreg:
+#if WDT_START != WDT_STOP
+	release_region(WDT_STOP, 1);
+#endif
+out_nostopreg:
+	misc_deregister(&ibwdt_miscdev);
+out_nomisc:
+	return res;
+}
+
+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");
+MODULE_ALIAS_MISCDEV(WATCHDOG_MINOR);
+
+/* end of ib700wdt.c */
diff --git a/drivers/char/watchdog/indydog.c b/drivers/char/watchdog/indydog.c
new file mode 100644
index 0000000..6af2c79
--- /dev/null
+++ b/drivers/char/watchdog/indydog.c
@@ -0,0 +1,221 @@
+/*
+ *	IndyDog	0.3	A Hardware Watchdog Device for SGI IP22
+ *
+ *	(c) Copyright 2002 Guido Guenther <agx@sigxcpu.org>, 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.
+ *
+ *	based on softdog.c by Alan Cox <alan@redhat.com>
+ */
+
+#include <linux/module.h>
+#include <linux/moduleparam.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/notifier.h>
+#include <linux/reboot.h>
+#include <linux/init.h>
+#include <asm/uaccess.h>
+#include <asm/sgi/mc.h>
+
+#define PFX "indydog: "
+static int indydog_alive;
+
+#ifdef CONFIG_WATCHDOG_NOWAYOUT
+static int nowayout = 1;
+#else
+static int nowayout = 0;
+#endif
+
+#define WATCHDOG_TIMEOUT 30		/* 30 sec default timeout */
+
+module_param(nowayout, int, 0);
+MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default=CONFIG_WATCHDOG_NOWAYOUT)");
+
+static void indydog_start(void)
+{
+	u32 mc_ctrl0 = sgimc->cpuctrl0;
+
+	mc_ctrl0 = sgimc->cpuctrl0 | SGIMC_CCTRL0_WDOG;
+	sgimc->cpuctrl0 = mc_ctrl0;
+}
+
+static void indydog_stop(void)
+{
+	u32 mc_ctrl0 = sgimc->cpuctrl0;
+
+	mc_ctrl0 &= ~SGIMC_CCTRL0_WDOG;
+	sgimc->cpuctrl0 = mc_ctrl0;
+
+	printk(KERN_INFO PFX "Stopped watchdog timer.\n");
+}
+
+static void indydog_ping(void)
+{
+	sgimc->watchdogt = 0;
+}
+
+/*
+ *	Allow only one person to hold it open
+ */
+static int indydog_open(struct inode *inode, struct file *file)
+{
+	if (indydog_alive)
+		return -EBUSY;
+
+	if (nowayout)
+		__module_get(THIS_MODULE);
+
+	/* Activate timer */
+	indydog_start();
+	indydog_ping();
+
+	indydog_alive = 1;
+	printk(KERN_INFO "Started watchdog timer.\n");
+
+	return nonseekable_open(inode, file);
+}
+
+static int indydog_release(struct inode *inode, struct file *file)
+{
+	/* Shut off the timer.
+	 * Lock it in if it's a module and we defined ...NOWAYOUT */
+	if (!nowayout)
+		indydog_stop();		/* Turn the WDT off */
+
+	indydog_alive = 0;
+
+	return 0;
+}
+
+static ssize_t indydog_write(struct file *file, const char *data, size_t len, loff_t *ppos)
+{
+	/* Refresh the timer. */
+	if (len) {
+		indydog_ping();
+	}
+	return len;
+}
+
+static int indydog_ioctl(struct inode *inode, struct file *file,
+	unsigned int cmd, unsigned long arg)
+{
+	int options, retval = -EINVAL;
+	static struct watchdog_info ident = {
+		.options		= WDIOF_KEEPALIVEPING |
+					  WDIOF_MAGICCLOSE,
+		.firmware_version	= 0,
+		.identity		= "Hardware Watchdog for SGI IP22",
+	};
+
+	switch (cmd) {
+		default:
+			return -ENOIOCTLCMD;
+		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:
+			indydog_ping();
+			return 0;
+		case WDIOC_GETTIMEOUT:
+			return put_user(WATCHDOG_TIMEOUT,(int *)arg);
+		case WDIOC_SETOPTIONS:
+		{
+			if (get_user(options, (int *)arg))
+				return -EFAULT;
+
+			if (options & WDIOS_DISABLECARD) {
+				indydog_stop();
+				retval = 0;
+			}
+
+			if (options & WDIOS_ENABLECARD) {
+				indydog_start();
+				retval = 0;
+			}
+
+			return retval;
+		}
+	}
+}
+
+static int indydog_notify_sys(struct notifier_block *this, unsigned long code, void *unused)
+{
+	if (code == SYS_DOWN || code == SYS_HALT)
+		indydog_stop();		/* Turn the WDT off */
+
+	return NOTIFY_DONE;
+}
+
+static struct file_operations indydog_fops = {
+	.owner		= THIS_MODULE,
+	.llseek		= no_llseek,
+	.write		= indydog_write,
+	.ioctl		= indydog_ioctl,
+	.open		= indydog_open,
+	.release	= indydog_release,
+};
+
+static struct miscdevice indydog_miscdev = {
+	.minor		= WATCHDOG_MINOR,
+	.name		= "watchdog",
+	.fops		= &indydog_fops,
+};
+
+static struct notifier_block indydog_notifier = {
+	.notifier_call = indydog_notify_sys,
+};
+
+static char banner[] __initdata =
+	KERN_INFO PFX "Hardware Watchdog Timer for SGI IP22: 0.3\n";
+
+static int __init watchdog_init(void)
+{
+	int ret;
+
+	ret = register_reboot_notifier(&indydog_notifier);
+	if (ret) {
+		printk(KERN_ERR PFX "cannot register reboot notifier (err=%d)\n",
+			ret);
+		return ret;
+	}
+
+	ret = misc_register(&indydog_miscdev);
+	if (ret) {
+		printk(KERN_ERR PFX "cannot register miscdev on minor=%d (err=%d)\n",
+			WATCHDOG_MINOR, ret);
+		unregister_reboot_notifier(&indydog_notifier);
+		return ret;
+	}
+
+	printk(banner);
+
+	return 0;
+}
+
+static void __exit watchdog_exit(void)
+{
+	misc_deregister(&indydog_miscdev);
+	unregister_reboot_notifier(&indydog_notifier);
+}
+
+module_init(watchdog_init);
+module_exit(watchdog_exit);
+
+MODULE_AUTHOR("Guido Guenther <agx@sigxcpu.org>");
+MODULE_DESCRIPTION("Hardware Watchdog Device for SGI IP22");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS_MISCDEV(WATCHDOG_MINOR);
diff --git a/drivers/char/watchdog/ixp2000_wdt.c b/drivers/char/watchdog/ixp2000_wdt.c
new file mode 100644
index 0000000..ab659d3
--- /dev/null
+++ b/drivers/char/watchdog/ixp2000_wdt.c
@@ -0,0 +1,219 @@
+/*
+ * drivers/watchdog/ixp2000_wdt.c
+ *
+ * Watchdog driver for Intel IXP2000 network processors
+ *
+ * Adapted from the IXP4xx watchdog driver by Lennert Buytenhek.
+ * The original version carries these notices:
+ *
+ * Author: Deepak Saxena <dsaxena@plexity.net>
+ *
+ * Copyright 2004 (c) MontaVista, Software, Inc.
+ * Based on sa1100 driver, Copyright (C) 2000 Oleg Drokin <green@crimea.edu>
+ *
+ * This file is licensed under  the terms of the GNU General Public
+ * License version 2. This program is licensed "as is" without any
+ * warranty of any kind, whether express or implied.
+ */
+
+#include <linux/config.h>
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/types.h>
+#include <linux/kernel.h>
+#include <linux/fs.h>
+#include <linux/miscdevice.h>
+#include <linux/watchdog.h>
+#include <linux/init.h>
+#include <linux/bitops.h>
+
+#include <asm/hardware.h>
+#include <asm/uaccess.h>
+
+#ifdef CONFIG_WATCHDOG_NOWAYOUT
+static int nowayout = 1;
+#else
+static int nowayout = 0;
+#endif
+static unsigned int heartbeat = 60;	/* (secs) Default is 1 minute */
+static unsigned long wdt_status;
+
+#define	WDT_IN_USE		0
+#define	WDT_OK_TO_CLOSE		1
+
+static unsigned long wdt_tick_rate;
+
+static void
+wdt_enable(void)
+{
+	ixp2000_reg_write(IXP2000_RESET0, *(IXP2000_RESET0) | WDT_RESET_ENABLE);
+	ixp2000_reg_write(IXP2000_TWDE, WDT_ENABLE);
+	ixp2000_reg_write(IXP2000_T4_CLD, heartbeat * wdt_tick_rate);
+	ixp2000_reg_write(IXP2000_T4_CTL, TIMER_DIVIDER_256 | TIMER_ENABLE);
+}
+
+static void
+wdt_disable(void)
+{
+	ixp2000_reg_write(IXP2000_T4_CTL, 0);
+}
+
+static void
+wdt_keepalive(void)
+{
+	ixp2000_reg_write(IXP2000_T4_CLD, heartbeat * wdt_tick_rate);
+}
+
+static int
+ixp2000_wdt_open(struct inode *inode, struct file *file)
+{
+	if (test_and_set_bit(WDT_IN_USE, &wdt_status))
+		return -EBUSY;
+
+	clear_bit(WDT_OK_TO_CLOSE, &wdt_status);
+
+	wdt_enable();
+
+	return nonseekable_open(inode, file);
+}
+
+static ssize_t
+ixp2000_wdt_write(struct file *file, const char *data, size_t len, loff_t *ppos)
+{
+	if (len) {
+		if (!nowayout) {
+			size_t i;
+
+			clear_bit(WDT_OK_TO_CLOSE, &wdt_status);
+
+			for (i = 0; i != len; i++) {
+				char c;
+
+				if (get_user(c, data + i))
+					return -EFAULT;
+				if (c == 'V')
+					set_bit(WDT_OK_TO_CLOSE, &wdt_status);
+			}
+		}
+		wdt_keepalive();
+	}
+
+	return len;
+}
+
+
+static struct watchdog_info ident = {
+	.options	= WDIOF_MAGICCLOSE | WDIOF_SETTIMEOUT |
+				WDIOF_KEEPALIVEPING,
+	.identity	= "IXP2000 Watchdog",
+};
+
+static int
+ixp2000_wdt_ioctl(struct inode *inode, struct file *file, unsigned int cmd,
+			unsigned long arg)
+{
+	int ret = -ENOIOCTLCMD;
+	int time;
+
+	switch (cmd) {
+	case WDIOC_GETSUPPORT:
+		ret = copy_to_user((struct watchdog_info *)arg, &ident,
+				   sizeof(ident)) ? -EFAULT : 0;
+		break;
+
+	case WDIOC_GETSTATUS:
+		ret = put_user(0, (int *)arg);
+		break;
+
+	case WDIOC_GETBOOTSTATUS:
+		ret = put_user(0, (int *)arg);
+		break;
+
+	case WDIOC_SETTIMEOUT:
+		ret = get_user(time, (int *)arg);
+		if (ret)
+			break;
+
+		if (time <= 0 || time > 60) {
+			ret = -EINVAL;
+			break;
+		}
+
+		heartbeat = time;
+		wdt_keepalive();
+		/* Fall through */
+
+	case WDIOC_GETTIMEOUT:
+		ret = put_user(heartbeat, (int *)arg);
+		break;
+
+	case WDIOC_KEEPALIVE:
+		wdt_enable();
+		ret = 0;
+		break;
+	}
+
+	return ret;
+}
+
+static int
+ixp2000_wdt_release(struct inode *inode, struct file *file)
+{
+	if (test_bit(WDT_OK_TO_CLOSE, &wdt_status)) {
+		wdt_disable();
+	} else {
+		printk(KERN_CRIT "WATCHDOG: Device closed unexpectdly - "
+					"timer will not stop\n");
+	}
+
+	clear_bit(WDT_IN_USE, &wdt_status);
+	clear_bit(WDT_OK_TO_CLOSE, &wdt_status);
+
+	return 0;
+}
+
+
+static struct file_operations ixp2000_wdt_fops =
+{
+	.owner		= THIS_MODULE,
+	.llseek		= no_llseek,
+	.write		= ixp2000_wdt_write,
+	.ioctl		= ixp2000_wdt_ioctl,
+	.open		= ixp2000_wdt_open,
+	.release	= ixp2000_wdt_release,
+};
+
+static struct miscdevice ixp2000_wdt_miscdev =
+{
+	.minor		= WATCHDOG_MINOR,
+	.name		= "IXP2000 Watchdog",
+	.fops		= &ixp2000_wdt_fops,
+};
+
+static int __init ixp2000_wdt_init(void)
+{
+	wdt_tick_rate = (*IXP2000_T1_CLD * HZ)/ 256;;
+
+	return misc_register(&ixp2000_wdt_miscdev);
+}
+
+static void __exit ixp2000_wdt_exit(void)
+{
+	misc_deregister(&ixp2000_wdt_miscdev);
+}
+
+module_init(ixp2000_wdt_init);
+module_exit(ixp2000_wdt_exit);
+
+MODULE_AUTHOR("Deepak Saxena <dsaxena@plexity.net">);
+MODULE_DESCRIPTION("IXP2000 Network Processor Watchdog");
+
+module_param(heartbeat, int, 0);
+MODULE_PARM_DESC(heartbeat, "Watchdog heartbeat in seconds (default 60s)");
+
+module_param(nowayout, int, 0);
+MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started");
+
+MODULE_LICENSE("GPL");
+MODULE_ALIAS_MISCDEV(WATCHDOG_MINOR);
+
diff --git a/drivers/char/watchdog/ixp4xx_wdt.c b/drivers/char/watchdog/ixp4xx_wdt.c
new file mode 100644
index 0000000..82396e0
--- /dev/null
+++ b/drivers/char/watchdog/ixp4xx_wdt.c
@@ -0,0 +1,230 @@
+/*
+ * drivers/watchdog/ixp4xx_wdt.c
+ *
+ * Watchdog driver for Intel IXP4xx network processors
+ *
+ * Author: Deepak Saxena <dsaxena@plexity.net>
+ *
+ * Copyright 2004 (c) MontaVista, Software, Inc.
+ * Based on sa1100 driver, Copyright (C) 2000 Oleg Drokin <green@crimea.edu>
+ *
+ * This file is licensed under  the terms of the GNU General Public
+ * License version 2. This program is licensed "as is" without any
+ * warranty of any kind, whether express or implied.
+ */
+
+#include <linux/config.h>
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/types.h>
+#include <linux/kernel.h>
+#include <linux/fs.h>
+#include <linux/miscdevice.h>
+#include <linux/watchdog.h>
+#include <linux/init.h>
+#include <linux/bitops.h>
+
+#include <asm/hardware.h>
+#include <asm/uaccess.h>
+
+#ifdef CONFIG_WATCHDOG_NOWAYOUT
+static int nowayout = 1;
+#else
+static int nowayout = 0;
+#endif
+static int heartbeat = 60;	/* (secs) Default is 1 minute */
+static unsigned long wdt_status;
+static unsigned long boot_status;
+
+#define WDT_TICK_RATE (IXP4XX_PERIPHERAL_BUS_CLOCK * 1000000UL)
+
+#define	WDT_IN_USE		0
+#define	WDT_OK_TO_CLOSE		1
+
+static void
+wdt_enable(void)
+{
+	*IXP4XX_OSWK = IXP4XX_WDT_KEY;
+	*IXP4XX_OSWE = 0;
+	*IXP4XX_OSWT = WDT_TICK_RATE * heartbeat;
+	*IXP4XX_OSWE = IXP4XX_WDT_COUNT_ENABLE | IXP4XX_WDT_RESET_ENABLE;
+	*IXP4XX_OSWK = 0;
+}
+
+static void
+wdt_disable(void)
+{
+	*IXP4XX_OSWK = IXP4XX_WDT_KEY;
+	*IXP4XX_OSWE = 0;
+	*IXP4XX_OSWK = 0;
+}
+
+static int
+ixp4xx_wdt_open(struct inode *inode, struct file *file)
+{
+	if (test_and_set_bit(WDT_IN_USE, &wdt_status))
+		return -EBUSY;
+
+	clear_bit(WDT_OK_TO_CLOSE, &wdt_status);
+
+	wdt_enable();
+
+	return nonseekable_open(inode, file);
+}
+
+static ssize_t
+ixp4xx_wdt_write(struct file *file, const char *data, size_t len, loff_t *ppos)
+{
+	if (len) {
+		if (!nowayout) {
+			size_t i;
+
+			clear_bit(WDT_OK_TO_CLOSE, &wdt_status);
+
+			for (i = 0; i != len; i++) {
+				char c;
+
+				if (get_user(c, data + i))
+					return -EFAULT;
+				if (c == 'V')
+					set_bit(WDT_OK_TO_CLOSE, &wdt_status);
+			}
+		}
+		wdt_enable();
+	}
+
+	return len;
+}
+
+static struct watchdog_info ident = {
+	.options	= WDIOF_CARDRESET | WDIOF_MAGICCLOSE |
+			  WDIOF_SETTIMEOUT | WDIOF_KEEPALIVEPING,
+	.identity	= "IXP4xx Watchdog",
+};
+
+
+static int
+ixp4xx_wdt_ioctl(struct inode *inode, struct file *file, unsigned int cmd,
+			unsigned long arg)
+{
+	int ret = -ENOIOCTLCMD;
+	int time;
+
+	switch (cmd) {
+	case WDIOC_GETSUPPORT:
+		ret = copy_to_user((struct watchdog_info *)arg, &ident,
+				   sizeof(ident)) ? -EFAULT : 0;
+		break;
+
+	case WDIOC_GETSTATUS:
+		ret = put_user(0, (int *)arg);
+		break;
+
+	case WDIOC_GETBOOTSTATUS:
+		ret = put_user(boot_status, (int *)arg);
+		break;
+
+	case WDIOC_SETTIMEOUT:
+		ret = get_user(time, (int *)arg);
+		if (ret)
+			break;
+
+		if (time <= 0 || time > 60) {
+			ret = -EINVAL;
+			break;
+		}
+
+		heartbeat = time;
+		wdt_enable();
+		/* Fall through */
+
+	case WDIOC_GETTIMEOUT:
+		ret = put_user(heartbeat, (int *)arg);
+		break;
+
+	case WDIOC_KEEPALIVE:
+		wdt_enable();
+		ret = 0;
+		break;
+	}
+	return ret;
+}
+
+static int
+ixp4xx_wdt_release(struct inode *inode, struct file *file)
+{
+	if (test_bit(WDT_OK_TO_CLOSE, &wdt_status)) {
+		wdt_disable();
+	} else {
+		printk(KERN_CRIT "WATCHDOG: Device closed unexpectdly - "
+					"timer will not stop\n");
+	}
+
+	clear_bit(WDT_IN_USE, &wdt_status);
+	clear_bit(WDT_OK_TO_CLOSE, &wdt_status);
+
+	return 0;
+}
+
+
+static struct file_operations ixp4xx_wdt_fops =
+{
+	.owner		= THIS_MODULE,
+	.llseek		= no_llseek,
+	.write		= ixp4xx_wdt_write,
+	.ioctl		= ixp4xx_wdt_ioctl,
+	.open		= ixp4xx_wdt_open,
+	.release	= ixp4xx_wdt_release,
+};
+
+static struct miscdevice ixp4xx_wdt_miscdev =
+{
+	.minor		= WATCHDOG_MINOR,
+	.name		= "IXP4xx Watchdog",
+	.fops		= &ixp4xx_wdt_fops,
+};
+
+static int __init ixp4xx_wdt_init(void)
+{
+	int ret;
+	unsigned long processor_id;
+
+	asm("mrc p15, 0, %0, cr0, cr0, 0;" : "=r"(processor_id) :);
+	if (!(processor_id & 0xf)) {
+		printk("IXP4XXX Watchdog: Rev. A0 CPU detected - "
+			"watchdog disabled\n");
+
+		return -ENODEV;
+	}
+
+	ret = misc_register(&ixp4xx_wdt_miscdev);
+	if (ret == 0)
+		printk("IXP4xx Watchdog Timer: heartbeat %d sec\n", heartbeat);
+
+	boot_status = (*IXP4XX_OSST & IXP4XX_OSST_TIMER_WARM_RESET) ?
+			WDIOF_CARDRESET : 0;
+
+	return ret;
+}
+
+static void __exit ixp4xx_wdt_exit(void)
+{
+	misc_deregister(&ixp4xx_wdt_miscdev);
+}
+
+
+module_init(ixp4xx_wdt_init);
+module_exit(ixp4xx_wdt_exit);
+
+MODULE_AUTHOR("Deepak Saxena <dsaxena@plexity.net>");
+MODULE_DESCRIPTION("IXP4xx Network Processor Watchdog");
+
+module_param(heartbeat, int, 0);
+MODULE_PARM_DESC(heartbeat, "Watchdog heartbeat in seconds (default 60s)");
+
+module_param(nowayout, int, 0);
+MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started");
+
+MODULE_LICENSE("GPL");
+MODULE_ALIAS_MISCDEV(WATCHDOG_MINOR);
+
diff --git a/drivers/char/watchdog/machzwd.c b/drivers/char/watchdog/machzwd.c
new file mode 100644
index 0000000..9da395f
--- /dev/null
+++ b/drivers/char/watchdog/machzwd.c
@@ -0,0 +1,501 @@
+/*
+ *  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/moduleparam.h>
+#include <linux/types.h>
+#include <linux/timer.h>
+#include <linux/jiffies.h>
+#include <linux/miscdevice.h>
+#include <linux/watchdog.h>
+#include <linux/fs.h>
+#include <linux/ioport.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>
+
+/* 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);
+}
+
+
+MODULE_AUTHOR("Fernando Fuganti <fuganti@conectiva.com.br>");
+MODULE_DESCRIPTION("MachZ ZF-Logic Watchdog driver");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS_MISCDEV(WATCHDOG_MINOR);
+
+#ifdef CONFIG_WATCHDOG_NOWAYOUT
+static int nowayout = 1;
+#else
+static int nowayout = 0;
+#endif
+
+module_param(nowayout, int, 0);
+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 | WDIOF_MAGICCLOSE,
+	.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;
+module_param(action, int, 0);
+MODULE_PARM_DESC(action, "after watchdog resets, generate: 0 = RESET(*)  1 = SMI  2 = NMI  3 = SCI");
+
+static int zf_action = GEN_RESET;
+static unsigned long zf_is_open;
+static char zf_expect_close;
+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 ":%s:%d: " format, __FUNCTION__, __LINE__ , ## args)
+#endif
+
+
+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 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 __user *buf, size_t count,
+								loff_t *ppos)
+{
+	/* 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 = 42;
+					dprintk("zf_expect_close = 42\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 count;
+}
+
+static int zf_ioctl(struct inode *inode, struct file *file, unsigned int cmd,
+	unsigned long arg)
+{
+	void __user *argp = (void __user *)arg;
+	int __user *p = argp;
+	switch(cmd){
+		case WDIOC_GETSUPPORT:
+			if (copy_to_user(argp, &zf_info, sizeof(zf_info)))
+				return -EFAULT;
+			break;
+
+		case WDIOC_GETSTATUS:
+			return put_user(0, p);
+
+		case WDIOC_KEEPALIVE:
+			zf_ping(0);
+			break;
+
+		default:
+			return -ENOIOCTLCMD;
+	}
+
+	return 0;
+}
+
+static int zf_open(struct inode *inode, struct file *file)
+{
+	spin_lock(&zf_lock);
+	if(test_and_set_bit(0, &zf_is_open)) {
+		spin_unlock(&zf_lock);
+		return -EBUSY;
+	}
+
+	if (nowayout)
+		__module_get(THIS_MODULE);
+
+	spin_unlock(&zf_lock);
+
+	zf_timer_on();
+
+	return nonseekable_open(inode, file);
+}
+
+static int zf_close(struct inode *inode, struct file *file)
+{
+	if(zf_expect_close == 42){
+		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);
+	clear_bit(0, &zf_is_open);
+	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,
+	.llseek         = no_llseek,
+	.write          = zf_write,
+	.ioctl          = zf_ioctl,
+	.open           = zf_open,
+	.release        = zf_close,
+};
+
+static struct miscdevice zf_miscdev = {
+	.minor = WATCHDOG_MINOR,
+	.name = "watchdog",
+	.fops = &zf_fops,
+};
+ 
+
+/*
+ * The device needs to learn about soft shutdowns in order to
+ * turn the timebomb registers off.
+ */
+static struct notifier_block zf_notifier = {
+	.notifier_call = zf_notify_sys,
+};
+
+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;
+}
+
+
+static void __exit zf_exit(void)
+{
+	zf_timer_off();
+
+	misc_deregister(&zf_miscdev);
+	unregister_reboot_notifier(&zf_notifier);
+	release_region(ZF_IOBASE, 3);
+}
+
+module_init(zf_init);
+module_exit(zf_exit);
diff --git a/drivers/char/watchdog/mixcomwd.c b/drivers/char/watchdog/mixcomwd.c
new file mode 100644
index 0000000..3143e4a
--- /dev/null
+++ b/drivers/char/watchdog/mixcomwd.c
@@ -0,0 +1,306 @@
+/*
+ * 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/moduleparam.h>
+#include <linux/config.h>
+#include <linux/types.h>
+#include <linux/miscdevice.h>
+#include <linux/ioport.h>
+#include <linux/watchdog.h>
+#include <linux/fs.h>
+#include <linux/reboot.h>
+#include <linux/init.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 unsigned 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);
+static char expect_close;
+
+#ifdef CONFIG_WATCHDOG_NOWAYOUT
+static int nowayout = 1;
+#else
+static int nowayout = 0;
+#endif
+
+module_param(nowayout, int, 0);
+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) {
+		/*
+		 * fops_get() code via open() has already done
+		 * a try_module_get() so it is safe to do the
+		 * __module_get().
+		 */
+		__module_get(THIS_MODULE);
+	} else {
+		if(mixcomwd_timer_alive) {
+			del_timer(&mixcomwd_timer);
+			mixcomwd_timer_alive=0;
+		}
+	}
+	return nonseekable_open(inode, file);
+}
+
+static int mixcomwd_release(struct inode *inode, struct file *file)
+{
+	if (expect_close == 42) {
+		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);
+	} else {
+		printk(KERN_CRIT "mixcomwd: WDT device closed unexpectedly.  WDT will not stop!\n");
+	}
+
+	clear_bit(0,&mixcomwd_opened);
+	expect_close=0;
+	return 0;
+}
+
+
+static ssize_t mixcomwd_write(struct file *file, const char __user *data, size_t len, loff_t *ppos)
+{
+	if(len)
+	{
+		if (!nowayout) {
+			size_t i;
+
+			/* In case it was set long ago */
+			expect_close = 0;
+
+			for (i = 0; i != len; i++) {
+				char c;
+				if (get_user(c, data + i))
+					return -EFAULT;
+				if (c == 'V')
+					expect_close = 42;
+			}
+		}
+		mixcomwd_ping();
+	}
+	return len;
+}
+
+static int mixcomwd_ioctl(struct inode *inode, struct file *file,
+	unsigned int cmd, unsigned long arg)
+{
+	void __user *argp = (void __user *)arg;
+	int __user *p = argp;
+	int status;
+	static struct watchdog_info ident = {
+		.options = WDIOF_KEEPALIVEPING | WDIOF_MAGICCLOSE,
+		.firmware_version = 1,
+		.identity = "MixCOM watchdog",
+	};
+
+	switch(cmd)
+	{
+		case WDIOC_GETSTATUS:
+			status=mixcomwd_opened;
+			if (!nowayout) {
+				status|=mixcomwd_timer_alive;
+			}
+			if (copy_to_user(p, &status, sizeof(int))) {
+				return -EFAULT;
+			}
+			break;
+		case WDIOC_GETSUPPORT:
+			if (copy_to_user(argp, &ident, sizeof(ident))) {
+				return -EFAULT;
+			}
+			break;
+		case WDIOC_KEEPALIVE:
+			mixcomwd_ping();
+			break;
+		default:
+			return -ENOIOCTLCMD;
+	}
+	return 0;
+}
+
+static struct file_operations mixcomwd_fops=
+{
+	.owner		= THIS_MODULE,
+	.llseek		= no_llseek,
+	.write		= mixcomwd_write,
+	.ioctl		= mixcomwd_ioctl,
+	.open		= mixcomwd_open,
+	.release	= mixcomwd_release,
+};
+
+static struct miscdevice mixcomwd_miscdev=
+{
+	.minor	= WATCHDOG_MINOR,
+	.name	= "watchdog",
+	.fops	= &mixcomwd_fops,
+};
+
+static int __init mixcomwd_checkcard(int port)
+{
+	int id;
+
+	port += MIXCOM_WATCHDOG_OFFSET;
+	if (!request_region(port, 1, "MixCOM watchdog")) {
+		return 0;
+	}
+
+	id=inb_p(port) & 0x3f;
+	if(id!=MIXCOM_ID) {
+		release_region(port, 1);
+		return 0;
+	}
+	return port;
+}
+
+static int __init flashcom_checkcard(int port)
+{
+	int id;
+
+	port += FLASHCOM_WATCHDOG_OFFSET;
+	if (!request_region(port, 1, "MixCOM watchdog")) {
+		return 0;
+	}
+
+	id=inb_p(port);
+ 	if(id!=FLASHCOM_ID) {
+		release_region(port, 1);
+		return 0;
+	}
+ 	return port;
+ }
+
+static int __init mixcomwd_init(void)
+{
+	int i;
+	int ret;
+	int found=0;
+
+	for (i = 0; !found && mixcomwd_ioports[i] != 0; i++) {
+		watchdog_port = mixcomwd_checkcard(mixcomwd_ioports[i]);
+		if (watchdog_port) {
+			found = 1;
+		}
+	}
+
+	/* The FlashCOM card can be set up at 0x300 -> 0x378, in 0x8 jumps */
+	for (i = 0x300; !found && i < 0x380; i+=0x8) {
+		watchdog_port = flashcom_checkcard(i);
+		if (watchdog_port) {
+			found = 1;
+		}
+	}
+
+	if (!found) {
+		printk("mixcomwd: No card detected, or port not available.\n");
+		return -ENODEV;
+	}
+
+	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_AUTHOR("Gergely Madarasz <gorgo@itc.hu>");
+MODULE_DESCRIPTION("MixCom Watchdog driver");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS_MISCDEV(WATCHDOG_MINOR);
diff --git a/drivers/char/watchdog/mpc8xx_wdt.c b/drivers/char/watchdog/mpc8xx_wdt.c
new file mode 100644
index 0000000..56d62ba
--- /dev/null
+++ b/drivers/char/watchdog/mpc8xx_wdt.c
@@ -0,0 +1,164 @@
+/*
+ * mpc8xx_wdt.c - MPC8xx watchdog userspace interface
+ *
+ * Author: Florian Schirmer <jolt@tuxbox.org>
+ *
+ * 2002 (c) Florian Schirmer <jolt@tuxbox.org> This file is licensed under
+ * the terms of the GNU General Public License version 2. This program
+ * is licensed "as is" without any warranty of any kind, whether express
+ * or implied.
+ */
+
+#include <linux/config.h>
+#include <linux/fs.h>
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/miscdevice.h>
+#include <linux/module.h>
+#include <linux/watchdog.h>
+#include <asm/8xx_immap.h>
+#include <asm/uaccess.h>
+#include <syslib/m8xx_wdt.h>
+
+static unsigned long wdt_opened;
+static int wdt_status;
+
+static void mpc8xx_wdt_handler_disable(void)
+{
+	volatile immap_t *imap = (volatile immap_t *)IMAP_ADDR;
+
+	imap->im_sit.sit_piscr &= ~(PISCR_PIE | PISCR_PTE);
+
+	printk(KERN_NOTICE "mpc8xx_wdt: keep-alive handler deactivated\n");
+}
+
+static void mpc8xx_wdt_handler_enable(void)
+{
+	volatile immap_t *imap = (volatile immap_t *)IMAP_ADDR;
+
+	imap->im_sit.sit_piscr |= PISCR_PIE | PISCR_PTE;
+
+	printk(KERN_NOTICE "mpc8xx_wdt: keep-alive handler activated\n");
+}
+
+static int mpc8xx_wdt_open(struct inode *inode, struct file *file)
+{
+	if (test_and_set_bit(0, &wdt_opened))
+		return -EBUSY;
+
+	m8xx_wdt_reset();
+	mpc8xx_wdt_handler_disable();
+
+	return 0;
+}
+
+static int mpc8xx_wdt_release(struct inode *inode, struct file *file)
+{
+	m8xx_wdt_reset();
+
+#if !defined(CONFIG_WATCHDOG_NOWAYOUT)
+	mpc8xx_wdt_handler_enable();
+#endif
+
+	clear_bit(0, &wdt_opened);
+
+	return 0;
+}
+
+static ssize_t mpc8xx_wdt_write(struct file *file, const char *data, size_t len,
+				loff_t * ppos)
+{
+	if (ppos != &file->f_pos)
+		return -ESPIPE;
+
+	if (len)
+		m8xx_wdt_reset();
+
+	return len;
+}
+
+static int mpc8xx_wdt_ioctl(struct inode *inode, struct file *file,
+			    unsigned int cmd, unsigned long arg)
+{
+	int timeout;
+	static struct watchdog_info info = {
+		.options = WDIOF_KEEPALIVEPING,
+		.firmware_version = 0,
+		.identity = "MPC8xx watchdog",
+	};
+
+	switch (cmd) {
+	case WDIOC_GETSUPPORT:
+		if (copy_to_user((void *)arg, &info, sizeof(info)))
+			return -EFAULT;
+		break;
+
+	case WDIOC_GETSTATUS:
+	case WDIOC_GETBOOTSTATUS:
+		if (put_user(wdt_status, (int *)arg))
+			return -EFAULT;
+		wdt_status &= ~WDIOF_KEEPALIVEPING;
+		break;
+
+	case WDIOC_GETTEMP:
+		return -EOPNOTSUPP;
+
+	case WDIOC_SETOPTIONS:
+		return -EOPNOTSUPP;
+
+	case WDIOC_KEEPALIVE:
+		m8xx_wdt_reset();
+		wdt_status |= WDIOF_KEEPALIVEPING;
+		break;
+
+	case WDIOC_SETTIMEOUT:
+		return -EOPNOTSUPP;
+
+	case WDIOC_GETTIMEOUT:
+		timeout = m8xx_wdt_get_timeout();
+		if (put_user(timeout, (int *)arg))
+			return -EFAULT;
+		break;
+
+	default:
+		return -ENOIOCTLCMD;
+	}
+
+	return 0;
+}
+
+static struct file_operations mpc8xx_wdt_fops = {
+	.owner = THIS_MODULE,
+	.llseek = no_llseek,
+	.write = mpc8xx_wdt_write,
+	.ioctl = mpc8xx_wdt_ioctl,
+	.open = mpc8xx_wdt_open,
+	.release = mpc8xx_wdt_release,
+};
+
+static struct miscdevice mpc8xx_wdt_miscdev = {
+	.minor = WATCHDOG_MINOR,
+	.name = "watchdog",
+	.fops = &mpc8xx_wdt_fops,
+};
+
+static int __init mpc8xx_wdt_init(void)
+{
+	return misc_register(&mpc8xx_wdt_miscdev);
+}
+
+static void __exit mpc8xx_wdt_exit(void)
+{
+	misc_deregister(&mpc8xx_wdt_miscdev);
+
+	m8xx_wdt_reset();
+	mpc8xx_wdt_handler_enable();
+}
+
+module_init(mpc8xx_wdt_init);
+module_exit(mpc8xx_wdt_exit);
+
+MODULE_AUTHOR("Florian Schirmer <jolt@tuxbox.org>");
+MODULE_DESCRIPTION("MPC8xx watchdog driver");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS_MISCDEV(WATCHDOG_MINOR);
diff --git a/drivers/char/watchdog/pcwd.c b/drivers/char/watchdog/pcwd.c
new file mode 100644
index 0000000..592dca1
--- /dev/null
+++ b/drivers/char/watchdog/pcwd.c
@@ -0,0 +1,926 @@
+/*
+ * 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>
+ * 011214	Added nowayout module option to override CONFIG_WATCHDOG_NOWAYOUT <Matt_Domsch@dell.com>
+ *              Added timeout module option to override default
+ */
+
+/*
+ *	A bells and whistles driver is available from http://www.pcwd.de/
+ *	More info available at http://www.berkprod.com/ or http://www.pcwatchdog.com/
+ */
+
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/types.h>
+#include <linux/timer.h>
+#include <linux/jiffies.h>
+#include <linux/config.h>
+#include <linux/wait.h>
+#include <linux/slab.h>
+#include <linux/ioport.h>
+#include <linux/delay.h>
+#include <linux/fs.h>
+#include <linux/miscdevice.h>
+#include <linux/watchdog.h>
+#include <linux/notifier.h>
+#include <linux/init.h>
+#include <linux/spinlock.h>
+#include <linux/reboot.h>
+
+#include <asm/uaccess.h>
+#include <asm/io.h>
+
+#define WD_VER                  "1.16 (06/12/2004)"
+#define PFX			"pcwd: "
+
+/*
+ * 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
+
+/*
+ * These are the defines that describe the control status bits 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 */
+
+/*
+ * These are the defines that describe the control status bits for the
+ * PC Watchdog card, revision C.
+ */
+#define WD_REVC_WTRP            0x01	/* Watchdog Trip status */
+#define WD_REVC_HRBT            0x02	/* Watchdog Heartbeat */
+#define WD_REVC_TTRP            0x04	/* Temperature Trip status */
+
+/* max. time we give an ISA watchdog card to process a command */
+/* 500ms for each 4 bit response (according to spec.) */
+#define ISA_COMMAND_TIMEOUT     1000
+
+/* Watchdog's internal commands */
+#define CMD_ISA_IDLE                    0x00
+#define CMD_ISA_VERSION_INTEGER         0x01
+#define CMD_ISA_VERSION_TENTH           0x02
+#define CMD_ISA_VERSION_HUNDRETH        0x03
+#define CMD_ISA_VERSION_MINOR           0x04
+#define CMD_ISA_SWITCH_SETTINGS         0x05
+#define CMD_ISA_DELAY_TIME_2SECS        0x0A
+#define CMD_ISA_DELAY_TIME_4SECS        0x0B
+#define CMD_ISA_DELAY_TIME_8SECS        0x0C
+
+/*
+ * We are using an kernel timer to do the pinging of the watchdog
+ * every ~500ms. We try to set the internal heartbeat of the
+ * watchdog to 2 ms.
+ */
+
+#define WDT_INTERVAL (HZ/2+1)
+
+/* We can only use 1 card due to the /dev/watchdog restriction */
+static int cards_found;
+
+/* internal variables */
+static atomic_t open_allowed = ATOMIC_INIT(1);
+static char expect_close;
+static struct timer_list timer;
+static unsigned long next_heartbeat;
+static int temp_panic;
+static int revision;			/* The card's revision */
+static int supports_temp;		/* Wether or not the card has a temperature device */
+static int command_mode;		/* Wether or not the card is in command mode */
+static int initial_status;		/* The card's boot status */
+static int current_readport;		/* The cards I/O address */
+static spinlock_t io_lock;
+
+/* module parameters */
+#define WATCHDOG_HEARTBEAT 60		/* 60 sec default heartbeat */
+static int heartbeat = WATCHDOG_HEARTBEAT;
+module_param(heartbeat, int, 0);
+MODULE_PARM_DESC(heartbeat, "Watchdog heartbeat in seconds. (2<=heartbeat<=7200, default=" __MODULE_STRING(WATCHDOG_HEARTBEAT) ")");
+
+#ifdef CONFIG_WATCHDOG_NOWAYOUT
+static int nowayout = 1;
+#else
+static int nowayout = 0;
+#endif
+
+module_param(nowayout, int, 0);
+MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default=CONFIG_WATCHDOG_NOWAYOUT)");
+
+/*
+ *	Internal functions
+ */
+
+static int send_isa_command(int cmd)
+{
+	int i;
+	int control_status;
+	int port0, last_port0;	/* Double read for stabilising */
+
+	/* The WCMD bit must be 1 and the command is only 4 bits in size */
+	control_status = (cmd & 0x0F) | 0x80;
+	outb_p(control_status, current_readport + 2);
+	udelay(ISA_COMMAND_TIMEOUT);
+
+	port0 = inb_p(current_readport);
+	for (i = 0; i < 25; ++i) {
+		last_port0 = port0;
+		port0 = inb_p(current_readport);
+
+		if (port0 == last_port0)
+			break;	/* Data is stable */
+
+		udelay (250);
+	}
+
+	return port0;
+}
+
+static int set_command_mode(void)
+{
+	int i, found=0, count=0;
+
+	/* Set the card into command mode */
+	spin_lock(&io_lock);
+	while ((!found) && (count < 3)) {
+		i = send_isa_command(CMD_ISA_IDLE);
+
+		if (i == 0x00)
+			found = 1;
+		else if (i == 0xF3) {
+			/* Card does not like what we've done to it */
+			outb_p(0x00, current_readport + 2);
+			udelay(1200);	/* Spec says wait 1ms */
+			outb_p(0x00, current_readport + 2);
+			udelay(ISA_COMMAND_TIMEOUT);
+		}
+		count++;
+	}
+	spin_unlock(&io_lock);
+	command_mode = found;
+
+	return(found);
+}
+
+static void unset_command_mode(void)
+{
+	/* Set the card into normal mode */
+	spin_lock(&io_lock);
+	outb_p(0x00, current_readport + 2);
+	udelay(ISA_COMMAND_TIMEOUT);
+	spin_unlock(&io_lock);
+
+	command_mode = 0;
+}
+
+static void pcwd_timer_ping(unsigned long data)
+{
+	int wdrst_stat;
+
+	/* If we got a heartbeat pulse within the WDT_INTERVAL
+	 * we agree to ping the WDT */
+	if(time_before(jiffies, next_heartbeat)) {
+		/* Ping the watchdog */
+		spin_lock(&io_lock);
+		if (revision == PCWD_REVISION_A) {
+			/*  Rev A cards are reset by setting the WD_WDRST bit in register 1 */
+			wdrst_stat = inb_p(current_readport);
+			wdrst_stat &= 0x0F;
+			wdrst_stat |= WD_WDRST;
+
+			outb_p(wdrst_stat, current_readport + 1);
+		} else {
+			/* Re-trigger watchdog by writing to port 0 */
+			outb_p(0x00, current_readport);
+		}
+
+		/* Re-set the timer interval */
+		mod_timer(&timer, jiffies + WDT_INTERVAL);
+
+		spin_unlock(&io_lock);
+	} else {
+		printk(KERN_WARNING PFX "Heartbeat lost! Will not ping the watchdog\n");
+	}
+}
+
+static int pcwd_start(void)
+{
+	int stat_reg;
+
+	next_heartbeat = jiffies + (heartbeat * HZ);
+
+	/* Start the timer */
+	mod_timer(&timer, jiffies + WDT_INTERVAL);
+
+	/* Enable the port */
+	if (revision == PCWD_REVISION_C) {
+		spin_lock(&io_lock);
+		outb_p(0x00, current_readport + 3);
+		udelay(ISA_COMMAND_TIMEOUT);
+		stat_reg = inb_p(current_readport + 2);
+		spin_unlock(&io_lock);
+		if (stat_reg & 0x10) {
+			printk(KERN_INFO PFX "Could not start watchdog\n");
+			return -EIO;
+		}
+	}
+	return 0;
+}
+
+static int pcwd_stop(void)
+{
+	int stat_reg;
+
+	/* Stop the timer */
+	del_timer(&timer);
+
+	/*  Disable the board  */
+	if (revision == PCWD_REVISION_C) {
+		spin_lock(&io_lock);
+		outb_p(0xA5, current_readport + 3);
+		udelay(ISA_COMMAND_TIMEOUT);
+		outb_p(0xA5, current_readport + 3);
+		udelay(ISA_COMMAND_TIMEOUT);
+		stat_reg = inb_p(current_readport + 2);
+		spin_unlock(&io_lock);
+		if ((stat_reg & 0x10) == 0) {
+			printk(KERN_INFO PFX "Could not stop watchdog\n");
+			return -EIO;
+		}
+	}
+	return 0;
+}
+
+static int pcwd_keepalive(void)
+{
+	/* user land ping */
+	next_heartbeat = jiffies + (heartbeat * HZ);
+	return 0;
+}
+
+static int pcwd_set_heartbeat(int t)
+{
+	if ((t < 2) || (t > 7200)) /* arbitrary upper limit */
+		return -EINVAL;
+
+	heartbeat = t;
+	return 0;
+}
+
+static int pcwd_get_status(int *status)
+{
+	int card_status;
+
+	*status=0;
+	spin_lock(&io_lock);
+	if (revision == PCWD_REVISION_A)
+		/* Rev A cards return status information from
+		 * the base register, which is used for the
+		 * temperature in other cards. */
+		card_status = inb(current_readport);
+	else {
+		/* Rev C cards return card status in the base
+		 * address + 1 register. And use different bits
+		 * to indicate a card initiated reset, and an
+		 * over-temperature condition. And the reboot
+		 * status can be reset. */
+		card_status = inb(current_readport + 1);
+	}
+	spin_unlock(&io_lock);
+
+	if (revision == PCWD_REVISION_A) {
+		if (card_status & WD_WDRST)
+			*status |= WDIOF_CARDRESET;
+
+		if (card_status & WD_T110) {
+			*status |= WDIOF_OVERHEAT;
+			if (temp_panic) {
+				printk (KERN_INFO PFX "Temperature overheat trip!\n");
+				machine_power_off();
+			}
+		}
+	} else {
+		if (card_status & WD_REVC_WTRP)
+			*status |= WDIOF_CARDRESET;
+
+		if (card_status & WD_REVC_TTRP) {
+			*status |= WDIOF_OVERHEAT;
+			if (temp_panic) {
+				printk (KERN_INFO PFX "Temperature overheat trip!\n");
+				machine_power_off();
+			}
+		}
+	}
+
+	return 0;
+}
+
+static int pcwd_clear_status(void)
+{
+	if (revision == PCWD_REVISION_C) {
+		spin_lock(&io_lock);
+		outb_p(0x00, current_readport + 1); /* clear reset status */
+		spin_unlock(&io_lock);
+	}
+	return 0;
+}
+
+static int pcwd_get_temperature(int *temperature)
+{
+	/* check that port 0 gives temperature info and no command results */
+	if (command_mode)
+		return -1;
+
+	*temperature = 0;
+	if (!supports_temp)
+		return -ENODEV;
+
+	/*
+	 * Convert celsius to fahrenheit, since this was
+	 * the decided 'standard' for this return value.
+	 */
+	spin_lock(&io_lock);
+	*temperature = ((inb(current_readport)) * 9 / 5) + 32;
+	spin_unlock(&io_lock);
+
+	return 0;
+}
+
+/*
+ *	/dev/watchdog handling
+ */
+
+static int pcwd_ioctl(struct inode *inode, struct file *file,
+		      unsigned int cmd, unsigned long arg)
+{
+	int rv;
+	int status;
+	int temperature;
+	int new_heartbeat;
+	int __user *argp = (int __user *)arg;
+	static struct watchdog_info ident = {
+		.options =		WDIOF_OVERHEAT |
+					WDIOF_CARDRESET |
+					WDIOF_KEEPALIVEPING |
+					WDIOF_SETTIMEOUT |
+					WDIOF_MAGICCLOSE,
+		.firmware_version =	1,
+		.identity =		"PCWD",
+	};
+
+	switch(cmd) {
+	default:
+		return -ENOIOCTLCMD;
+
+	case WDIOC_GETSUPPORT:
+		if(copy_to_user(argp, &ident, sizeof(ident)))
+			return -EFAULT;
+		return 0;
+
+	case WDIOC_GETSTATUS:
+		pcwd_get_status(&status);
+		return put_user(status, argp);
+
+	case WDIOC_GETBOOTSTATUS:
+		return put_user(initial_status, argp);
+
+	case WDIOC_GETTEMP:
+		if (pcwd_get_temperature(&temperature))
+			return -EFAULT;
+
+		return put_user(temperature, argp);
+
+	case WDIOC_SETOPTIONS:
+		if (revision == PCWD_REVISION_C)
+		{
+			if(copy_from_user(&rv, argp, sizeof(int)))
+				return -EFAULT;
+
+			if (rv & WDIOS_DISABLECARD)
+			{
+				return pcwd_stop();
+			}
+
+			if (rv & WDIOS_ENABLECARD)
+			{
+				return pcwd_start();
+			}
+
+			if (rv & WDIOS_TEMPPANIC)
+			{
+				temp_panic = 1;
+			}
+		}
+		return -EINVAL;
+
+	case WDIOC_KEEPALIVE:
+		pcwd_keepalive();
+		return 0;
+
+	case WDIOC_SETTIMEOUT:
+		if (get_user(new_heartbeat, argp))
+			return -EFAULT;
+
+		if (pcwd_set_heartbeat(new_heartbeat))
+			return -EINVAL;
+
+		pcwd_keepalive();
+		/* Fall */
+
+	case WDIOC_GETTIMEOUT:
+		return put_user(heartbeat, argp);
+	}
+
+	return 0;
+}
+
+static ssize_t pcwd_write(struct file *file, const char __user *buf, size_t len,
+			  loff_t *ppos)
+{
+	if (len) {
+		if (!nowayout) {
+			size_t i;
+
+			/* In case it was set long ago */
+			expect_close = 0;
+
+			for (i = 0; i != len; i++) {
+				char c;
+
+				if (get_user(c, buf + i))
+					return -EFAULT;
+				if (c == 'V')
+					expect_close = 42;
+			}
+		}
+		pcwd_keepalive();
+	}
+	return len;
+}
+
+static int pcwd_open(struct inode *inode, struct file *file)
+{
+	if (!atomic_dec_and_test(&open_allowed) ) {
+		atomic_inc( &open_allowed );
+		return -EBUSY;
+	}
+
+	if (nowayout)
+		__module_get(THIS_MODULE);
+
+	/* Activate */
+	pcwd_start();
+	pcwd_keepalive();
+	return nonseekable_open(inode, file);
+}
+
+static int pcwd_close(struct inode *inode, struct file *file)
+{
+	if (expect_close == 42) {
+		pcwd_stop();
+	} else {
+		printk(KERN_CRIT PFX "Unexpected close, not stopping watchdog!\n");
+		pcwd_keepalive();
+	}
+	expect_close = 0;
+	atomic_inc( &open_allowed );
+	return 0;
+}
+
+/*
+ *	/dev/temperature handling
+ */
+
+static ssize_t pcwd_temp_read(struct file *file, char __user *buf, size_t count,
+			 loff_t *ppos)
+{
+	int temperature;
+
+	if (pcwd_get_temperature(&temperature))
+		return -EFAULT;
+
+	if (copy_to_user(buf, &temperature, 1))
+		return -EFAULT;
+
+	return 1;
+}
+
+static int pcwd_temp_open(struct inode *inode, struct file *file)
+{
+	if (!supports_temp)
+		return -ENODEV;
+
+	return nonseekable_open(inode, file);
+}
+
+static int pcwd_temp_close(struct inode *inode, struct file *file)
+{
+	return 0;
+}
+
+/*
+ *	Notify system
+ */
+
+static int pcwd_notify_sys(struct notifier_block *this, unsigned long code, void *unused)
+{
+	if (code==SYS_DOWN || code==SYS_HALT) {
+		/* Turn the WDT off */
+		pcwd_stop();
+	}
+
+	return NOTIFY_DONE;
+}
+
+/*
+ *	Kernel Interfaces
+ */
+
+static struct file_operations pcwd_fops = {
+	.owner		= THIS_MODULE,
+	.llseek		= no_llseek,
+	.write		= pcwd_write,
+	.ioctl		= pcwd_ioctl,
+	.open		= pcwd_open,
+	.release	= pcwd_close,
+};
+
+static struct miscdevice pcwd_miscdev = {
+	.minor =	WATCHDOG_MINOR,
+	.name =		"watchdog",
+	.fops =		&pcwd_fops,
+};
+
+static struct file_operations pcwd_temp_fops = {
+	.owner		= THIS_MODULE,
+	.llseek		= no_llseek,
+	.read		= pcwd_temp_read,
+	.open		= pcwd_temp_open,
+	.release	= pcwd_temp_close,
+};
+
+static struct miscdevice temp_miscdev = {
+	.minor =	TEMP_MINOR,
+	.name =		"temperature",
+	.fops =		&pcwd_temp_fops,
+};
+
+static struct notifier_block pcwd_notifier = {
+	.notifier_call =	pcwd_notify_sys,
+};
+
+/*
+ *	Init & exit routines
+ */
+
+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);
+	/* REV A cards use only 2 io ports; test
+	 * presumes a floating bus reads as 0xff. */
+	if ((inb(current_readport + 2) == 0xFF) ||
+	    (inb(current_readport + 3) == 0xFF))
+		r=PCWD_REVISION_A;
+	spin_unlock(&io_lock);
+
+	return r;
+}
+
+static inline char *get_firmware(void)
+{
+	int one, ten, hund, minor;
+	char *ret;
+
+	ret = kmalloc(6, GFP_KERNEL);
+	if(ret == NULL)
+		return NULL;
+
+	if (set_command_mode()) {
+		one = send_isa_command(CMD_ISA_VERSION_INTEGER);
+		ten = send_isa_command(CMD_ISA_VERSION_TENTH);
+		hund = send_isa_command(CMD_ISA_VERSION_HUNDRETH);
+		minor = send_isa_command(CMD_ISA_VERSION_MINOR);
+		sprintf(ret, "%c.%c%c%c", one, ten, hund, minor);
+	}
+	else
+		sprintf(ret, "ERROR");
+
+	unset_command_mode();
+	return(ret);
+}
+
+static inline int get_option_switches(void)
+{
+	int rv=0;
+
+	if (set_command_mode()) {
+		/* Get switch settings */
+		rv = send_isa_command(CMD_ISA_SWITCH_SETTINGS);
+	}
+
+	unset_command_mode();
+	return(rv);
+}
+
+static int __devinit pcwatchdog_init(int base_addr)
+{
+	int ret;
+	char *firmware;
+	int option_switches;
+
+	cards_found++;
+	if (cards_found == 1)
+		printk(KERN_INFO PFX "v%s Ken Hollis (kenji@bitgate.com)\n", WD_VER);
+
+	if (cards_found > 1) {
+		printk(KERN_ERR PFX "This driver only supports 1 device\n");
+		return -ENODEV;
+	}
+
+	if (base_addr == 0x0000) {
+		printk(KERN_ERR PFX "No I/O-Address for card detected\n");
+		return -ENODEV;
+	}
+	current_readport = base_addr;
+
+	/* Check card's revision */
+	revision = get_revision();
+
+	if (!request_region(current_readport, (revision == PCWD_REVISION_A) ? 2 : 4, "PCWD")) {
+		printk(KERN_ERR PFX "I/O address 0x%04x already in use\n",
+			current_readport);
+		current_readport = 0x0000;
+		return -EIO;
+	}
+
+	/* Initial variables */
+	supports_temp = 0;
+	temp_panic = 0;
+	initial_status = 0x0000;
+
+	/* get the boot_status */
+	pcwd_get_status(&initial_status);
+
+	/* clear the "card caused reboot" flag */
+	pcwd_clear_status();
+
+	init_timer(&timer);
+	timer.function = pcwd_timer_ping;
+	timer.data = 0;
+
+	/*  Disable the board  */
+	pcwd_stop();
+
+	/*  Check whether or not the card supports the temperature device */
+	get_support();
+
+	/* Get some extra info from the hardware (in command/debug/diag mode) */
+	if (revision == PCWD_REVISION_A)
+		printk(KERN_INFO PFX "ISA-PC Watchdog (REV.A) detected at port 0x%04x\n", current_readport);
+	else if (revision == PCWD_REVISION_C) {
+		firmware = get_firmware();
+		printk(KERN_INFO PFX "ISA-PC Watchdog (REV.C) detected at port 0x%04x (Firmware version: %s)\n",
+			current_readport, firmware);
+		kfree(firmware);
+		option_switches = get_option_switches();
+		printk(KERN_INFO PFX "Option switches (0x%02x): Temperature Reset Enable=%s, Power On Delay=%s\n",
+			option_switches,
+			((option_switches & 0x10) ? "ON" : "OFF"),
+			((option_switches & 0x08) ? "ON" : "OFF"));
+
+		/* Reprogram internal heartbeat to 2 seconds */
+		if (set_command_mode()) {
+			send_isa_command(CMD_ISA_DELAY_TIME_2SECS);
+			unset_command_mode();
+		}
+	} else {
+		/* Should NEVER happen, unless get_revision() fails. */
+		printk(KERN_INFO PFX "Unable to get revision\n");
+		release_region(current_readport, (revision == PCWD_REVISION_A) ? 2 : 4);
+		current_readport = 0x0000;
+		return -1;
+	}
+
+	if (supports_temp)
+		printk(KERN_INFO PFX "Temperature Option Detected\n");
+
+	if (initial_status & WDIOF_CARDRESET)
+		printk(KERN_INFO PFX "Previous reboot was caused by the card\n");
+
+	if (initial_status & WDIOF_OVERHEAT) {
+		printk(KERN_EMERG PFX "Card senses a CPU Overheat. Panicking!\n");
+		printk(KERN_EMERG PFX "CPU Overheat\n");
+	}
+
+	if (initial_status == 0)
+		printk(KERN_INFO PFX "No previous trip detected - Cold boot or reset\n");
+
+	/* Check that the heartbeat value is within it's range ; if not reset to the default */
+        if (pcwd_set_heartbeat(heartbeat)) {
+                pcwd_set_heartbeat(WATCHDOG_HEARTBEAT);
+                printk(KERN_INFO PFX "heartbeat value must be 2<=heartbeat<=7200, using %d\n",
+                        WATCHDOG_HEARTBEAT);
+	}
+
+	ret = register_reboot_notifier(&pcwd_notifier);
+	if (ret) {
+		printk(KERN_ERR PFX "cannot register reboot notifier (err=%d)\n",
+			ret);
+		release_region(current_readport, (revision == PCWD_REVISION_A) ? 2 : 4);
+		current_readport = 0x0000;
+		return ret;
+	}
+
+	if (supports_temp) {
+		ret = misc_register(&temp_miscdev);
+		if (ret) {
+			printk(KERN_ERR PFX "cannot register miscdev on minor=%d (err=%d)\n",
+				TEMP_MINOR, ret);
+			unregister_reboot_notifier(&pcwd_notifier);
+			release_region(current_readport, (revision == PCWD_REVISION_A) ? 2 : 4);
+			current_readport = 0x0000;
+			return ret;
+		}
+	}
+
+	ret = misc_register(&pcwd_miscdev);
+	if (ret) {
+		printk(KERN_ERR PFX "cannot register miscdev on minor=%d (err=%d)\n",
+			WATCHDOG_MINOR, ret);
+		if (supports_temp)
+			misc_deregister(&temp_miscdev);
+		unregister_reboot_notifier(&pcwd_notifier);
+		release_region(current_readport, (revision == PCWD_REVISION_A) ? 2 : 4);
+		current_readport = 0x0000;
+		return ret;
+	}
+
+	printk(KERN_INFO PFX "initialized. heartbeat=%d sec (nowayout=%d)\n",
+		heartbeat, nowayout);
+
+	return 0;
+}
+
+static void __devexit pcwatchdog_exit(void)
+{
+	/*  Disable the board  */
+	if (!nowayout)
+		pcwd_stop();
+
+	/* Deregister */
+	misc_deregister(&pcwd_miscdev);
+	if (supports_temp)
+		misc_deregister(&temp_miscdev);
+	unregister_reboot_notifier(&pcwd_notifier);
+	release_region(current_readport, (revision == PCWD_REVISION_A) ? 2 : 4);
+	current_readport = 0x0000;
+}
+
+/*
+ *  The ISA cards have a heartbeat bit in one of the registers, which
+ *  register is card dependent.  The heartbeat bit is monitored, and if
+ *  found, is considered proof that a Berkshire card has been found.
+ *  The initial rate is once per second at board start up, then twice
+ *  per second for normal operation.
+ */
+static int __init pcwd_checkcard(int base_addr)
+{
+	int port0, last_port0;	/* Reg 0, in case it's REV A */
+	int port1, last_port1;	/* Register 1 for REV C cards */
+	int i;
+	int retval;
+
+	if (!request_region (base_addr, 4, "PCWD")) {
+		printk (KERN_INFO PFX "Port 0x%04x unavailable\n", base_addr);
+		return 0;
+	}
+
+	retval = 0;
+
+	port0 = inb_p(base_addr);	/* For REV A boards */
+	port1 = inb_p(base_addr + 1);	/* For REV C boards */
+	if (port0 != 0xff || port1 != 0xff) {
+		/* Not an 'ff' from a floating bus, so must be a card! */
+		for (i = 0; i < 4; ++i) {
+
+			msleep(500);
+
+			last_port0 = port0;
+			last_port1 = port1;
+
+			port0 = inb_p(base_addr);
+			port1 = inb_p(base_addr + 1);
+
+			/* Has either hearbeat bit changed?  */
+			if ((port0 ^ last_port0) & WD_HRTBT ||
+			    (port1 ^ last_port1) & WD_REVC_HRBT) {
+				retval = 1;
+				break;
+			}
+		}
+	}
+	release_region (base_addr, 4);
+
+	return retval;
+}
+
+/*
+ * 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 4.
+ */
+static int pcwd_ioports[] = { 0x270, 0x350, 0x370, 0x000 };
+
+static int __init pcwd_init_module(void)
+{
+	int i, found = 0;
+
+	spin_lock_init(&io_lock);
+
+	for (i = 0; pcwd_ioports[i] != 0; i++) {
+		if (pcwd_checkcard(pcwd_ioports[i])) {
+			if (!(pcwatchdog_init(pcwd_ioports[i])))
+				found++;
+		}
+	}
+
+	if (!found) {
+		printk (KERN_INFO PFX "No card detected, or port not available\n");
+		return -ENODEV;
+	}
+
+	return 0;
+}
+
+static void __exit pcwd_cleanup_module(void)
+{
+	if (current_readport)
+		pcwatchdog_exit();
+	return;
+}
+
+module_init(pcwd_init_module);
+module_exit(pcwd_cleanup_module);
+
+MODULE_AUTHOR("Ken Hollis <kenji@bitgate.com>");
+MODULE_DESCRIPTION("Berkshire ISA-PC Watchdog driver");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS_MISCDEV(WATCHDOG_MINOR);
+MODULE_ALIAS_MISCDEV(TEMP_MINOR);
diff --git a/drivers/char/watchdog/pcwd_pci.c b/drivers/char/watchdog/pcwd_pci.c
new file mode 100644
index 0000000..8ce0666
--- /dev/null
+++ b/drivers/char/watchdog/pcwd_pci.c
@@ -0,0 +1,677 @@
+/*
+ *	Berkshire PCI-PC Watchdog Card Driver
+ *
+ *	(c) Copyright 2003 Wim Van Sebroeck <wim@iguana.be>.
+ *
+ *	Based on source code of the following authors:
+ *	  Ken Hollis <kenji@bitgate.com>,
+ *	  Lindsay Harris <lindsay@bluegum.com>,
+ *	  Alan Cox <alan@redhat.com>,
+ *	  Matt Domsch <Matt_Domsch@dell.com>,
+ *	  Rob Radez <rob@osinvestor.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 Wim Van Sebroeck nor Iguana vzw. admit liability nor
+ *	provide warranty for any of this software. This material is
+ *	provided "AS-IS" and at no charge.
+ */
+
+/*
+ *	A bells and whistles driver is available from http://www.pcwd.de/
+ *	More info available at http://www.berkprod.com/ or http://www.pcwatchdog.com/
+ */
+
+/*
+ *	Includes, defines, variables, module parameters, ...
+ */
+
+#include <linux/config.h>
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/types.h>
+#include <linux/delay.h>
+#include <linux/miscdevice.h>
+#include <linux/watchdog.h>
+#include <linux/notifier.h>
+#include <linux/reboot.h>
+#include <linux/init.h>
+#include <linux/fs.h>
+#include <linux/pci.h>
+#include <linux/ioport.h>
+#include <linux/spinlock.h>
+
+#include <asm/uaccess.h>
+#include <asm/io.h>
+
+/* Module and version information */
+#define WATCHDOG_VERSION "1.01"
+#define WATCHDOG_DATE "15 Mar 2005"
+#define WATCHDOG_DRIVER_NAME "PCI-PC Watchdog"
+#define WATCHDOG_NAME "pcwd_pci"
+#define PFX WATCHDOG_NAME ": "
+#define DRIVER_VERSION WATCHDOG_DRIVER_NAME " driver, v" WATCHDOG_VERSION " (" WATCHDOG_DATE ")\n"
+
+/* Stuff for the PCI ID's  */
+#ifndef PCI_VENDOR_ID_QUICKLOGIC
+#define PCI_VENDOR_ID_QUICKLOGIC    0x11e3
+#endif
+
+#ifndef PCI_DEVICE_ID_WATCHDOG_PCIPCWD
+#define PCI_DEVICE_ID_WATCHDOG_PCIPCWD 0x5030
+#endif
+
+/*
+ * These are the defines that describe the control status bits for the
+ * PCI-PC Watchdog card.
+ */
+#define WD_PCI_WTRP             0x01	/* Watchdog Trip status */
+#define WD_PCI_HRBT             0x02	/* Watchdog Heartbeat */
+#define WD_PCI_TTRP             0x04	/* Temperature Trip status */
+
+/* according to documentation max. time to process a command for the pci
+ * watchdog card is 100 ms, so we give it 150 ms to do it's job */
+#define PCI_COMMAND_TIMEOUT	150
+
+/* Watchdog's internal commands */
+#define CMD_GET_STATUS			0x04
+#define CMD_GET_FIRMWARE_VERSION	0x08
+#define CMD_READ_WATCHDOG_TIMEOUT	0x18
+#define CMD_WRITE_WATCHDOG_TIMEOUT	0x19
+
+/* We can only use 1 card due to the /dev/watchdog restriction */
+static int cards_found;
+
+/* internal variables */
+static int temp_panic;
+static unsigned long is_active;
+static char expect_release;
+static struct {
+	int supports_temp;	/* Wether or not the card has a temperature device */
+	int boot_status;	/* The card's boot status */
+	unsigned long io_addr;	/* The cards I/O address */
+	spinlock_t io_lock;
+	struct pci_dev *pdev;
+} pcipcwd_private;
+
+/* module parameters */
+#define WATCHDOG_HEARTBEAT 2	/* 2 sec default heartbeat */
+static int heartbeat = WATCHDOG_HEARTBEAT;
+module_param(heartbeat, int, 0);
+MODULE_PARM_DESC(heartbeat, "Watchdog heartbeat in seconds. (0<heartbeat<65536, default=" __MODULE_STRING(WATCHDOG_HEARTBEAT) ")");
+
+#ifdef CONFIG_WATCHDOG_NOWAYOUT
+static int nowayout = 1;
+#else
+static int nowayout = 0;
+#endif
+
+module_param(nowayout, int, 0);
+MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default=CONFIG_WATCHDOG_NOWAYOUT)");
+
+/*
+ *	Internal functions
+ */
+
+static int send_command(int cmd, int *msb, int *lsb)
+{
+	int got_response, count;
+
+	spin_lock(&pcipcwd_private.io_lock);
+	/* If a command requires data it should be written first.
+	 * Data for commands with 8 bits of data should be written to port 4.
+	 * Commands with 16 bits of data, should be written as LSB to port 4
+	 * and MSB to port 5.
+	 * After the required data has been written then write the command to
+	 * port 6. */
+	outb_p(*lsb, pcipcwd_private.io_addr + 4);
+	outb_p(*msb, pcipcwd_private.io_addr + 5);
+	outb_p(cmd, pcipcwd_private.io_addr + 6);
+
+	/* wait till the pci card processed the command, signaled by
+	 * the WRSP bit in port 2 and give it a max. timeout of
+	 * PCI_COMMAND_TIMEOUT to process */
+	got_response = inb_p(pcipcwd_private.io_addr + 2) & 0x40;
+	for (count = 0; (count < PCI_COMMAND_TIMEOUT) && (!got_response); count++) {
+		mdelay(1);
+		got_response = inb_p(pcipcwd_private.io_addr + 2) & 0x40;
+	}
+
+	if (got_response) {
+		/* read back response */
+		*lsb = inb_p(pcipcwd_private.io_addr + 4);
+		*msb = inb_p(pcipcwd_private.io_addr + 5);
+
+		/* clear WRSP bit */
+		inb_p(pcipcwd_private.io_addr + 6);
+	}
+	spin_unlock(&pcipcwd_private.io_lock);
+
+	return got_response;
+}
+
+static int pcipcwd_start(void)
+{
+	int stat_reg;
+
+	spin_lock(&pcipcwd_private.io_lock);
+	outb_p(0x00, pcipcwd_private.io_addr + 3);
+	udelay(1000);
+
+	stat_reg = inb_p(pcipcwd_private.io_addr + 2);
+	spin_unlock(&pcipcwd_private.io_lock);
+
+	if (stat_reg & 0x10) {
+		printk(KERN_ERR PFX "Card timer not enabled\n");
+		return -1;
+	}
+
+	return 0;
+}
+
+static int pcipcwd_stop(void)
+{
+	int stat_reg;
+
+	spin_lock(&pcipcwd_private.io_lock);
+	outb_p(0xA5, pcipcwd_private.io_addr + 3);
+	udelay(1000);
+
+	outb_p(0xA5, pcipcwd_private.io_addr + 3);
+	udelay(1000);
+
+	stat_reg = inb_p(pcipcwd_private.io_addr + 2);
+	spin_unlock(&pcipcwd_private.io_lock);
+
+	if (!(stat_reg & 0x10)) {
+		printk(KERN_ERR PFX "Card did not acknowledge disable attempt\n");
+		return -1;
+	}
+
+	return 0;
+}
+
+static int pcipcwd_keepalive(void)
+{
+	/* Re-trigger watchdog by writing to port 0 */
+	outb_p(0x42, pcipcwd_private.io_addr);
+	return 0;
+}
+
+static int pcipcwd_set_heartbeat(int t)
+{
+	int t_msb = t / 256;
+	int t_lsb = t % 256;
+
+	if ((t < 0x0001) || (t > 0xFFFF))
+		return -EINVAL;
+
+	/* Write new heartbeat to watchdog */
+	send_command(CMD_WRITE_WATCHDOG_TIMEOUT, &t_msb, &t_lsb);
+
+	heartbeat = t;
+	return 0;
+}
+
+static int pcipcwd_get_status(int *status)
+{
+	int new_status;
+
+	*status=0;
+	new_status = inb_p(pcipcwd_private.io_addr + 1);
+	if (new_status & WD_PCI_WTRP)
+		*status |= WDIOF_CARDRESET;
+	if (new_status & WD_PCI_TTRP) {
+		*status |= WDIOF_OVERHEAT;
+		if (temp_panic)
+			panic(PFX "Temperature overheat trip!\n");
+	}
+
+	return 0;
+}
+
+static int pcipcwd_clear_status(void)
+{
+	outb_p(0x01, pcipcwd_private.io_addr + 1);
+	return 0;
+}
+
+static int pcipcwd_get_temperature(int *temperature)
+{
+	*temperature = 0;
+	if (!pcipcwd_private.supports_temp)
+		return -ENODEV;
+
+	/*
+	 * Convert celsius to fahrenheit, since this was
+	 * the decided 'standard' for this return value.
+	 */
+	*temperature = ((inb_p(pcipcwd_private.io_addr)) * 9 / 5) + 32;
+
+	return 0;
+}
+
+/*
+ *	/dev/watchdog handling
+ */
+
+static ssize_t pcipcwd_write(struct file *file, const char __user *data,
+			      size_t len, loff_t *ppos)
+{
+	/* See if we got the magic character 'V' and reload the timer */
+	if (len) {
+		if (!nowayout) {
+			size_t i;
+
+			/* note: just in case someone wrote the magic character
+			 * five months ago... */
+			expect_release = 0;
+
+			/* scan to see whether or not we got the magic character */
+			for (i = 0; i != len; i++) {
+				char c;
+				if(get_user(c, data+i))
+					return -EFAULT;
+				if (c == 'V')
+					expect_release = 42;
+			}
+		}
+
+		/* someone wrote to us, we should reload the timer */
+		pcipcwd_keepalive();
+	}
+	return len;
+}
+
+static int pcipcwd_ioctl(struct inode *inode, struct file *file,
+			  unsigned int cmd, unsigned long arg)
+{
+	void __user *argp = (void __user *)arg;
+	int __user *p = argp;
+	static struct watchdog_info ident = {
+		.options =		WDIOF_OVERHEAT |
+					WDIOF_CARDRESET |
+					WDIOF_KEEPALIVEPING |
+					WDIOF_SETTIMEOUT |
+					WDIOF_MAGICCLOSE,
+		.firmware_version =	1,
+		.identity =		WATCHDOG_DRIVER_NAME,
+	};
+
+	switch (cmd) {
+		case WDIOC_GETSUPPORT:
+			return copy_to_user(argp, &ident,
+				sizeof (ident)) ? -EFAULT : 0;
+
+		case WDIOC_GETSTATUS:
+		{
+			int status;
+
+			pcipcwd_get_status(&status);
+
+			return put_user(status, p);
+		}
+
+		case WDIOC_GETBOOTSTATUS:
+			return put_user(pcipcwd_private.boot_status, p);
+
+		case WDIOC_GETTEMP:
+		{
+			int temperature;
+
+			if (pcipcwd_get_temperature(&temperature))
+				return -EFAULT;
+
+			return put_user(temperature, p);
+		}
+
+		case WDIOC_KEEPALIVE:
+			pcipcwd_keepalive();
+			return 0;
+
+		case WDIOC_SETOPTIONS:
+		{
+			int new_options, retval = -EINVAL;
+
+			if (get_user (new_options, p))
+				return -EFAULT;
+
+			if (new_options & WDIOS_DISABLECARD) {
+				pcipcwd_stop();
+				retval = 0;
+			}
+
+			if (new_options & WDIOS_ENABLECARD) {
+				pcipcwd_start();
+				retval = 0;
+			}
+
+			if (new_options & WDIOS_TEMPPANIC) {
+				temp_panic = 1;
+				retval = 0;
+			}
+
+			return retval;
+		}
+
+		case WDIOC_SETTIMEOUT:
+		{
+			int new_heartbeat;
+
+			if (get_user(new_heartbeat, p))
+				return -EFAULT;
+
+			if (pcipcwd_set_heartbeat(new_heartbeat))
+			    return -EINVAL;
+
+			pcipcwd_keepalive();
+			/* Fall */
+		}
+
+		case WDIOC_GETTIMEOUT:
+			return put_user(heartbeat, p);
+
+		default:
+			return -ENOIOCTLCMD;
+	}
+}
+
+static int pcipcwd_open(struct inode *inode, struct file *file)
+{
+	/* /dev/watchdog can only be opened once */
+	if (test_and_set_bit(0, &is_active))
+		return -EBUSY;
+
+	/* Activate */
+	pcipcwd_start();
+	pcipcwd_keepalive();
+	return nonseekable_open(inode, file);
+}
+
+static int pcipcwd_release(struct inode *inode, struct file *file)
+{
+	/*
+	 *      Shut off the timer.
+	 */
+	if (expect_release == 42) {
+		pcipcwd_stop();
+	} else {
+		printk(KERN_CRIT PFX "Unexpected close, not stopping watchdog!\n");
+		pcipcwd_keepalive();
+	}
+	expect_release = 0;
+	clear_bit(0, &is_active);
+	return 0;
+}
+
+/*
+ *	/dev/temperature handling
+ */
+
+static ssize_t pcipcwd_temp_read(struct file *file, char __user *data,
+				size_t len, loff_t *ppos)
+{
+	int temperature;
+
+	if (pcipcwd_get_temperature(&temperature))
+		return -EFAULT;
+
+	if (copy_to_user (data, &temperature, 1))
+		return -EFAULT;
+
+	return 1;
+}
+
+static int pcipcwd_temp_open(struct inode *inode, struct file *file)
+{
+	if (!pcipcwd_private.supports_temp)
+		return -ENODEV;
+
+	return nonseekable_open(inode, file);
+}
+
+static int pcipcwd_temp_release(struct inode *inode, struct file *file)
+{
+	return 0;
+}
+
+/*
+ *	Notify system
+ */
+
+static int pcipcwd_notify_sys(struct notifier_block *this, unsigned long code, void *unused)
+{
+	if (code==SYS_DOWN || code==SYS_HALT) {
+		/* Turn the WDT off */
+		pcipcwd_stop();
+	}
+
+	return NOTIFY_DONE;
+}
+
+/*
+ *	Kernel Interfaces
+ */
+
+static struct file_operations pcipcwd_fops = {
+	.owner =	THIS_MODULE,
+	.llseek =	no_llseek,
+	.write =	pcipcwd_write,
+	.ioctl =	pcipcwd_ioctl,
+	.open =		pcipcwd_open,
+	.release =	pcipcwd_release,
+};
+
+static struct miscdevice pcipcwd_miscdev = {
+	.minor =	WATCHDOG_MINOR,
+	.name =		"watchdog",
+	.fops =		&pcipcwd_fops,
+};
+
+static struct file_operations pcipcwd_temp_fops = {
+	.owner =	THIS_MODULE,
+	.llseek =	no_llseek,
+	.read =		pcipcwd_temp_read,
+	.open =		pcipcwd_temp_open,
+	.release =	pcipcwd_temp_release,
+};
+
+static struct miscdevice pcipcwd_temp_miscdev = {
+	.minor =	TEMP_MINOR,
+	.name =		"temperature",
+	.fops =		&pcipcwd_temp_fops,
+};
+
+static struct notifier_block pcipcwd_notifier = {
+	.notifier_call =	pcipcwd_notify_sys,
+};
+
+/*
+ *	Init & exit routines
+ */
+
+static inline void check_temperature_support(void)
+{
+	if (inb_p(pcipcwd_private.io_addr) != 0xF0)
+		pcipcwd_private.supports_temp = 1;
+}
+
+static int __devinit pcipcwd_card_init(struct pci_dev *pdev,
+		const struct pci_device_id *ent)
+{
+	int ret = -EIO;
+	int got_fw_rev, fw_rev_major, fw_rev_minor;
+	char fw_ver_str[20];
+	char option_switches;
+
+	cards_found++;
+	if (cards_found == 1)
+		printk(KERN_INFO PFX DRIVER_VERSION);
+
+	if (cards_found > 1) {
+		printk(KERN_ERR PFX "This driver only supports 1 device\n");
+		return -ENODEV;
+	}
+
+	if (pci_enable_device(pdev)) {
+		printk(KERN_ERR PFX "Not possible to enable PCI Device\n");
+		return -ENODEV;
+	}
+
+	if (pci_resource_start(pdev, 0) == 0x0000) {
+		printk(KERN_ERR PFX "No I/O-Address for card detected\n");
+		ret = -ENODEV;
+		goto err_out_disable_device;
+	}
+
+	pcipcwd_private.pdev = pdev;
+	pcipcwd_private.io_addr = pci_resource_start(pdev, 0);
+
+	if (pci_request_regions(pdev, WATCHDOG_NAME)) {
+		printk(KERN_ERR PFX "I/O address 0x%04x already in use\n",
+			(int) pcipcwd_private.io_addr);
+		ret = -EIO;
+		goto err_out_disable_device;
+	}
+
+	/* get the boot_status */
+	pcipcwd_get_status(&pcipcwd_private.boot_status);
+
+	/* clear the "card caused reboot" flag */
+	pcipcwd_clear_status();
+
+	/* disable card */
+	pcipcwd_stop();
+
+	/* Check whether or not the card supports the temperature device */
+	check_temperature_support();
+
+	/* Get the Firmware Version */
+	got_fw_rev = send_command(CMD_GET_FIRMWARE_VERSION, &fw_rev_major, &fw_rev_minor);
+	if (got_fw_rev) {
+		sprintf(fw_ver_str, "%u.%02u", fw_rev_major, fw_rev_minor);
+	} else {
+		sprintf(fw_ver_str, "<card no answer>");
+	}
+
+	/* Get switch settings */
+	option_switches = inb_p(pcipcwd_private.io_addr + 3);
+
+	printk(KERN_INFO PFX "Found card at port 0x%04x (Firmware: %s) %s temp option\n",
+		(int) pcipcwd_private.io_addr, fw_ver_str,
+		(pcipcwd_private.supports_temp ? "with" : "without"));
+
+	printk(KERN_INFO PFX "Option switches (0x%02x): Temperature Reset Enable=%s, Power On Delay=%s\n",
+		option_switches,
+		((option_switches & 0x10) ? "ON" : "OFF"),
+		((option_switches & 0x08) ? "ON" : "OFF"));
+
+	if (pcipcwd_private.boot_status & WDIOF_CARDRESET)
+		printk(KERN_INFO PFX "Previous reset was caused by the Watchdog card\n");
+
+	if (pcipcwd_private.boot_status & WDIOF_OVERHEAT)
+		printk(KERN_INFO PFX "Card sensed a CPU Overheat\n");
+
+	if (pcipcwd_private.boot_status == 0)
+		printk(KERN_INFO PFX "No previous trip detected - Cold boot or reset\n");
+
+	/* Check that the heartbeat value is within it's range ; if not reset to the default */
+	if (pcipcwd_set_heartbeat(heartbeat)) {
+		pcipcwd_set_heartbeat(WATCHDOG_HEARTBEAT);
+		printk(KERN_INFO PFX "heartbeat value must be 0<heartbeat<65536, using %d\n",
+			WATCHDOG_HEARTBEAT);
+	}
+
+	ret = register_reboot_notifier(&pcipcwd_notifier);
+	if (ret != 0) {
+		printk(KERN_ERR PFX "cannot register reboot notifier (err=%d)\n",
+			ret);
+		goto err_out_release_region;
+	}
+
+	if (pcipcwd_private.supports_temp) {
+		ret = misc_register(&pcipcwd_temp_miscdev);
+		if (ret != 0) {
+			printk(KERN_ERR PFX "cannot register miscdev on minor=%d (err=%d)\n",
+				TEMP_MINOR, ret);
+			goto err_out_unregister_reboot;
+		}
+	}
+
+	ret = misc_register(&pcipcwd_miscdev);
+	if (ret != 0) {
+		printk(KERN_ERR PFX "cannot register miscdev on minor=%d (err=%d)\n",
+			WATCHDOG_MINOR, ret);
+		goto err_out_misc_deregister;
+	}
+
+	printk(KERN_INFO PFX "initialized. heartbeat=%d sec (nowayout=%d)\n",
+		heartbeat, nowayout);
+
+	return 0;
+
+err_out_misc_deregister:
+	if (pcipcwd_private.supports_temp)
+		misc_deregister(&pcipcwd_temp_miscdev);
+err_out_unregister_reboot:
+	unregister_reboot_notifier(&pcipcwd_notifier);
+err_out_release_region:
+	pci_release_regions(pdev);
+err_out_disable_device:
+	pci_disable_device(pdev);
+	return ret;
+}
+
+static void __devexit pcipcwd_card_exit(struct pci_dev *pdev)
+{
+	/* Stop the timer before we leave */
+	if (!nowayout)
+		pcipcwd_stop();
+
+	/* Deregister */
+	misc_deregister(&pcipcwd_miscdev);
+	if (pcipcwd_private.supports_temp)
+		misc_deregister(&pcipcwd_temp_miscdev);
+	unregister_reboot_notifier(&pcipcwd_notifier);
+	pci_release_regions(pdev);
+	pci_disable_device(pdev);
+	cards_found--;
+}
+
+static struct pci_device_id pcipcwd_pci_tbl[] = {
+	{ PCI_VENDOR_ID_QUICKLOGIC, PCI_DEVICE_ID_WATCHDOG_PCIPCWD,
+		PCI_ANY_ID, PCI_ANY_ID, },
+	{ 0 },			/* End of list */
+};
+MODULE_DEVICE_TABLE(pci, pcipcwd_pci_tbl);
+
+static struct pci_driver pcipcwd_driver = {
+	.name		= WATCHDOG_NAME,
+	.id_table	= pcipcwd_pci_tbl,
+	.probe		= pcipcwd_card_init,
+	.remove		= __devexit_p(pcipcwd_card_exit),
+};
+
+static int __init pcipcwd_init_module(void)
+{
+	spin_lock_init (&pcipcwd_private.io_lock);
+
+	return pci_register_driver(&pcipcwd_driver);
+}
+
+static void __exit pcipcwd_cleanup_module(void)
+{
+	pci_unregister_driver(&pcipcwd_driver);
+}
+
+module_init(pcipcwd_init_module);
+module_exit(pcipcwd_cleanup_module);
+
+MODULE_AUTHOR("Wim Van Sebroeck <wim@iguana.be>");
+MODULE_DESCRIPTION("Berkshire PCI-PC Watchdog driver");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS_MISCDEV(WATCHDOG_MINOR);
+MODULE_ALIAS_MISCDEV(TEMP_MINOR);
diff --git a/drivers/char/watchdog/pcwd_usb.c b/drivers/char/watchdog/pcwd_usb.c
new file mode 100644
index 0000000..1127201
--- /dev/null
+++ b/drivers/char/watchdog/pcwd_usb.c
@@ -0,0 +1,796 @@
+/*
+ *	Berkshire USB-PC Watchdog Card Driver
+ *
+ *	(c) Copyright 2004 Wim Van Sebroeck <wim@iguana.be>.
+ *
+ *	Based on source code of the following authors:
+ *	  Ken Hollis <kenji@bitgate.com>,
+ *	  Alan Cox <alan@redhat.com>,
+ *	  Matt Domsch <Matt_Domsch@dell.com>,
+ *	  Rob Radez <rob@osinvestor.com>,
+ *	  Greg Kroah-Hartman <greg@kroah.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 Wim Van Sebroeck nor Iguana vzw. admit liability nor
+ *	provide warranty for any of this software. This material is
+ *	provided "AS-IS" and at no charge.
+ *
+ *	Thanks also to Simon Machell at Berkshire Products Inc. for
+ *	providing the test hardware. More info is available at
+ *	http://www.berkprod.com/ or http://www.pcwatchdog.com/
+ */
+
+#include <linux/config.h>
+#include <linux/kernel.h>
+#include <linux/errno.h>
+#include <linux/init.h>
+#include <linux/slab.h>
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/types.h>
+#include <linux/delay.h>
+#include <linux/miscdevice.h>
+#include <linux/watchdog.h>
+#include <linux/notifier.h>
+#include <linux/reboot.h>
+#include <linux/fs.h>
+#include <linux/smp_lock.h>
+#include <linux/completion.h>
+#include <asm/uaccess.h>
+#include <linux/usb.h>
+
+
+#ifdef CONFIG_USB_DEBUG
+	static int debug = 1;
+#else
+	static int debug;
+#endif
+
+/* Use our own dbg macro */
+#undef dbg
+#define dbg(format, arg...) do { if (debug) printk(KERN_DEBUG PFX format "\n" , ## arg); } while (0)
+
+
+/* Module and Version Information */
+#define DRIVER_VERSION "1.01"
+#define DRIVER_DATE "15 Mar 2005"
+#define DRIVER_AUTHOR "Wim Van Sebroeck <wim@iguana.be>"
+#define DRIVER_DESC "Berkshire USB-PC Watchdog driver"
+#define DRIVER_LICENSE "GPL"
+#define DRIVER_NAME "pcwd_usb"
+#define PFX DRIVER_NAME ": "
+
+MODULE_AUTHOR(DRIVER_AUTHOR);
+MODULE_DESCRIPTION(DRIVER_DESC);
+MODULE_LICENSE(DRIVER_LICENSE);
+MODULE_ALIAS_MISCDEV(WATCHDOG_MINOR);
+MODULE_ALIAS_MISCDEV(TEMP_MINOR);
+
+/* Module Parameters */
+module_param(debug, int, 0);
+MODULE_PARM_DESC(debug, "Debug enabled or not");
+
+#define WATCHDOG_HEARTBEAT 2	/* 2 sec default heartbeat */
+static int heartbeat = WATCHDOG_HEARTBEAT;
+module_param(heartbeat, int, 0);
+MODULE_PARM_DESC(heartbeat, "Watchdog heartbeat in seconds. (0<heartbeat<65536, default=" __MODULE_STRING(WATCHDOG_HEARTBEAT) ")");
+
+#ifdef CONFIG_WATCHDOG_NOWAYOUT
+static int nowayout = 1;
+#else
+static int nowayout = 0;
+#endif
+
+module_param(nowayout, int, 0);
+MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default=CONFIG_WATCHDOG_NOWAYOUT)");
+
+/* The vendor and product id's for the USB-PC Watchdog card */
+#define USB_PCWD_VENDOR_ID	0x0c98
+#define USB_PCWD_PRODUCT_ID	0x1140
+
+/* table of devices that work with this driver */
+static struct usb_device_id usb_pcwd_table [] = {
+	{ USB_DEVICE(USB_PCWD_VENDOR_ID, USB_PCWD_PRODUCT_ID) },
+	{ }					/* Terminating entry */
+};
+MODULE_DEVICE_TABLE (usb, usb_pcwd_table);
+
+/* according to documentation max. time to process a command for the USB
+ * watchdog card is 100 or 200 ms, so we give it 250 ms to do it's job */
+#define USB_COMMAND_TIMEOUT	250
+
+/* Watchdog's internal commands */
+#define CMD_READ_TEMP			0x02	/* Read Temperature; Re-trigger Watchdog */
+#define CMD_TRIGGER			CMD_READ_TEMP
+#define CMD_GET_STATUS			0x04	/* Get Status Information */
+#define CMD_GET_FIRMWARE_VERSION	0x08	/* Get Firmware Version */
+#define CMD_GET_DIP_SWITCH_SETTINGS	0x0c	/* Get Dip Switch Settings */
+#define CMD_READ_WATCHDOG_TIMEOUT	0x18	/* Read Current Watchdog Time */
+#define CMD_WRITE_WATCHDOG_TIMEOUT	0x19	/* Write Current Watchdog Time */
+#define CMD_ENABLE_WATCHDOG		0x30	/* Enable / Disable Watchdog */
+#define CMD_DISABLE_WATCHDOG		CMD_ENABLE_WATCHDOG
+
+/* Some defines that I like to be somewhere else like include/linux/usb_hid.h */
+#define HID_REQ_SET_REPORT		0x09
+#define HID_DT_REPORT			(USB_TYPE_CLASS | 0x02)
+
+/* We can only use 1 card due to the /dev/watchdog restriction */
+static int cards_found;
+
+/* some internal variables */
+static unsigned long is_active;
+static char expect_release;
+
+/* Structure to hold all of our device specific stuff */
+struct usb_pcwd_private {
+	struct usb_device *	udev;			/* save off the usb device pointer */
+	struct usb_interface *	interface;		/* the interface for this device */
+
+	unsigned int		interface_number;	/* the interface number used for cmd's */
+
+	unsigned char *		intr_buffer;		/* the buffer to intr data */
+	dma_addr_t		intr_dma;		/* the dma address for the intr buffer */
+	size_t			intr_size;		/* the size of the intr buffer */
+	struct urb *		intr_urb;		/* the urb used for the intr pipe */
+
+	unsigned char		cmd_command;		/* The command that is reported back */
+	unsigned char		cmd_data_msb;		/* The data MSB that is reported back */
+	unsigned char		cmd_data_lsb;		/* The data LSB that is reported back */
+	atomic_t		cmd_received;		/* true if we received a report after a command */
+
+	int			exists;			/* Wether or not the device exists */
+	struct semaphore	sem;			/* locks this structure */
+};
+static struct usb_pcwd_private *usb_pcwd_device;
+
+/* prevent races between open() and disconnect() */
+static DECLARE_MUTEX (disconnect_sem);
+
+/* local function prototypes */
+static int usb_pcwd_probe	(struct usb_interface *interface, const struct usb_device_id *id);
+static void usb_pcwd_disconnect	(struct usb_interface *interface);
+
+/* usb specific object needed to register this driver with the usb subsystem */
+static struct usb_driver usb_pcwd_driver = {
+	.owner =	THIS_MODULE,
+	.name =		DRIVER_NAME,
+	.probe =	usb_pcwd_probe,
+	.disconnect =	usb_pcwd_disconnect,
+	.id_table =	usb_pcwd_table,
+};
+
+
+static void usb_pcwd_intr_done(struct urb *urb, struct pt_regs *regs)
+{
+	struct usb_pcwd_private *usb_pcwd = (struct usb_pcwd_private *)urb->context;
+	unsigned char *data = usb_pcwd->intr_buffer;
+	int retval;
+
+	switch (urb->status) {
+	case 0:			/* success */
+		break;
+	case -ECONNRESET:	/* unlink */
+	case -ENOENT:
+	case -ESHUTDOWN:
+		/* this urb is terminated, clean up */
+		dbg("%s - urb shutting down with status: %d", __FUNCTION__, urb->status);
+		return;
+	/* -EPIPE:  should clear the halt */
+	default:		/* error */
+		dbg("%s - nonzero urb status received: %d", __FUNCTION__, urb->status);
+		goto resubmit;
+	}
+
+	dbg("received following data cmd=0x%02x msb=0x%02x lsb=0x%02x",
+		data[0], data[1], data[2]);
+
+	usb_pcwd->cmd_command  = data[0];
+	usb_pcwd->cmd_data_msb = data[1];
+	usb_pcwd->cmd_data_lsb = data[2];
+
+	/* notify anyone waiting that the cmd has finished */
+	atomic_set (&usb_pcwd->cmd_received, 1);
+
+resubmit:
+	retval = usb_submit_urb (urb, GFP_ATOMIC);
+	if (retval)
+		printk(KERN_ERR PFX "can't resubmit intr, usb_submit_urb failed with result %d\n",
+			retval);
+}
+
+static int usb_pcwd_send_command(struct usb_pcwd_private *usb_pcwd, unsigned char cmd,
+	unsigned char *msb, unsigned char *lsb)
+{
+	int got_response, count;
+	unsigned char buf[6];
+
+	/* We will not send any commands if the USB PCWD device does not exist */
+	if ((!usb_pcwd) || (!usb_pcwd->exists))
+		return -1;
+
+	/* The USB PC Watchdog uses a 6 byte report format. The board currently uses
+	 * only 3 of the six bytes of the report. */
+	buf[0] = cmd;			/* Byte 0 = CMD */
+	buf[1] = *msb;			/* Byte 1 = Data MSB */
+	buf[2] = *lsb;			/* Byte 2 = Data LSB */
+	buf[3] = buf[4] = buf[5] = 0;	/* All other bytes not used */
+
+	dbg("sending following data cmd=0x%02x msb=0x%02x lsb=0x%02x",
+		buf[0], buf[1], buf[2]);
+
+	atomic_set (&usb_pcwd->cmd_received, 0);
+
+	if (usb_control_msg(usb_pcwd->udev, usb_sndctrlpipe(usb_pcwd->udev, 0),
+			HID_REQ_SET_REPORT, HID_DT_REPORT,
+			0x0200, usb_pcwd->interface_number, buf, sizeof(buf),
+			USB_COMMAND_TIMEOUT) != sizeof(buf)) {
+		dbg("usb_pcwd_send_command: error in usb_control_msg for cmd 0x%x 0x%x 0x%x\n", cmd, *msb, *lsb);
+	}
+	/* wait till the usb card processed the command,
+	 * with a max. timeout of USB_COMMAND_TIMEOUT */
+	got_response = 0;
+	for (count = 0; (count < USB_COMMAND_TIMEOUT) && (!got_response); count++) {
+		mdelay(1);
+		if (atomic_read (&usb_pcwd->cmd_received))
+			got_response = 1;
+	}
+
+	if ((got_response) && (cmd == usb_pcwd->cmd_command)) {
+		/* read back response */
+		*msb = usb_pcwd->cmd_data_msb;
+		*lsb = usb_pcwd->cmd_data_lsb;
+	}
+
+	return got_response;
+}
+
+static int usb_pcwd_start(struct usb_pcwd_private *usb_pcwd)
+{
+	unsigned char msb = 0x00;
+	unsigned char lsb = 0x00;
+	int retval;
+
+	/* Enable Watchdog */
+	retval = usb_pcwd_send_command(usb_pcwd, CMD_ENABLE_WATCHDOG, &msb, &lsb);
+
+	if ((retval == 0) || (lsb == 0)) {
+		printk(KERN_ERR PFX "Card did not acknowledge enable attempt\n");
+		return -1;
+	}
+
+	return 0;
+}
+
+static int usb_pcwd_stop(struct usb_pcwd_private *usb_pcwd)
+{
+	unsigned char msb = 0xA5;
+	unsigned char lsb = 0xC3;
+	int retval;
+
+	/* Disable Watchdog */
+	retval = usb_pcwd_send_command(usb_pcwd, CMD_DISABLE_WATCHDOG, &msb, &lsb);
+
+	if ((retval == 0) || (lsb != 0)) {
+		printk(KERN_ERR PFX "Card did not acknowledge disable attempt\n");
+		return -1;
+	}
+
+	return 0;
+}
+
+static int usb_pcwd_keepalive(struct usb_pcwd_private *usb_pcwd)
+{
+	unsigned char dummy;
+
+	/* Re-trigger Watchdog */
+	usb_pcwd_send_command(usb_pcwd, CMD_TRIGGER, &dummy, &dummy);
+
+	return 0;
+}
+
+static int usb_pcwd_set_heartbeat(struct usb_pcwd_private *usb_pcwd, int t)
+{
+	unsigned char msb = t / 256;
+	unsigned char lsb = t % 256;
+
+	if ((t < 0x0001) || (t > 0xFFFF))
+		return -EINVAL;
+
+	/* Write new heartbeat to watchdog */
+	usb_pcwd_send_command(usb_pcwd, CMD_WRITE_WATCHDOG_TIMEOUT, &msb, &lsb);
+
+	heartbeat = t;
+	return 0;
+}
+
+static int usb_pcwd_get_temperature(struct usb_pcwd_private *usb_pcwd, int *temperature)
+{
+	unsigned char msb, lsb;
+
+	usb_pcwd_send_command(usb_pcwd, CMD_READ_TEMP, &msb, &lsb);
+
+	/*
+	 * Convert celsius to fahrenheit, since this was
+	 * the decided 'standard' for this return value.
+	 */
+	*temperature = (lsb * 9 / 5) + 32;
+
+	return 0;
+}
+
+/*
+ *	/dev/watchdog handling
+ */
+
+static ssize_t usb_pcwd_write(struct file *file, const char __user *data,
+			      size_t len, loff_t *ppos)
+{
+	/* See if we got the magic character 'V' and reload the timer */
+	if (len) {
+		if (!nowayout) {
+			size_t i;
+
+			/* note: just in case someone wrote the magic character
+			 * five months ago... */
+			expect_release = 0;
+
+			/* scan to see whether or not we got the magic character */
+			for (i = 0; i != len; i++) {
+				char c;
+				if(get_user(c, data+i))
+					return -EFAULT;
+				if (c == 'V')
+					expect_release = 42;
+			}
+		}
+
+		/* someone wrote to us, we should reload the timer */
+		usb_pcwd_keepalive(usb_pcwd_device);
+	}
+	return len;
+}
+
+static int usb_pcwd_ioctl(struct inode *inode, struct file *file,
+			  unsigned int cmd, unsigned long arg)
+{
+	void __user *argp = (void __user *)arg;
+	int __user *p = argp;
+	static struct watchdog_info ident = {
+		.options =		WDIOF_KEEPALIVEPING |
+					WDIOF_SETTIMEOUT |
+					WDIOF_MAGICCLOSE,
+		.firmware_version =	1,
+		.identity =		DRIVER_NAME,
+	};
+
+	switch (cmd) {
+		case WDIOC_GETSUPPORT:
+			return copy_to_user(argp, &ident,
+				sizeof (ident)) ? -EFAULT : 0;
+
+		case WDIOC_GETSTATUS:
+		case WDIOC_GETBOOTSTATUS:
+			return put_user(0, p);
+
+		case WDIOC_GETTEMP:
+		{
+			int temperature;
+
+			if (usb_pcwd_get_temperature(usb_pcwd_device, &temperature))
+				return -EFAULT;
+
+			return put_user(temperature, p);
+		}
+
+		case WDIOC_KEEPALIVE:
+			usb_pcwd_keepalive(usb_pcwd_device);
+			return 0;
+
+		case WDIOC_SETOPTIONS:
+		{
+			int new_options, retval = -EINVAL;
+
+			if (get_user (new_options, p))
+				return -EFAULT;
+
+			if (new_options & WDIOS_DISABLECARD) {
+				usb_pcwd_stop(usb_pcwd_device);
+				retval = 0;
+			}
+
+			if (new_options & WDIOS_ENABLECARD) {
+				usb_pcwd_start(usb_pcwd_device);
+				retval = 0;
+			}
+
+			return retval;
+		}
+
+		case WDIOC_SETTIMEOUT:
+		{
+			int new_heartbeat;
+
+			if (get_user(new_heartbeat, p))
+				return -EFAULT;
+
+			if (usb_pcwd_set_heartbeat(usb_pcwd_device, new_heartbeat))
+			    return -EINVAL;
+
+			usb_pcwd_keepalive(usb_pcwd_device);
+			/* Fall */
+		}
+
+		case WDIOC_GETTIMEOUT:
+			return put_user(heartbeat, p);
+
+		default:
+			return -ENOIOCTLCMD;
+	}
+}
+
+static int usb_pcwd_open(struct inode *inode, struct file *file)
+{
+	/* /dev/watchdog can only be opened once */
+	if (test_and_set_bit(0, &is_active))
+		return -EBUSY;
+
+	/* Activate */
+	usb_pcwd_start(usb_pcwd_device);
+	usb_pcwd_keepalive(usb_pcwd_device);
+	return nonseekable_open(inode, file);
+}
+
+static int usb_pcwd_release(struct inode *inode, struct file *file)
+{
+	/*
+	 *      Shut off the timer.
+	 */
+	if (expect_release == 42) {
+		usb_pcwd_stop(usb_pcwd_device);
+	} else {
+		printk(KERN_CRIT PFX "Unexpected close, not stopping watchdog!\n");
+		usb_pcwd_keepalive(usb_pcwd_device);
+	}
+	expect_release = 0;
+	clear_bit(0, &is_active);
+	return 0;
+}
+
+/*
+ *	/dev/temperature handling
+ */
+
+static ssize_t usb_pcwd_temperature_read(struct file *file, char __user *data,
+				size_t len, loff_t *ppos)
+{
+	int temperature;
+
+	if (usb_pcwd_get_temperature(usb_pcwd_device, &temperature))
+		return -EFAULT;
+
+	if (copy_to_user(data, &temperature, 1))
+		return -EFAULT;
+
+	return 1;
+}
+
+static int usb_pcwd_temperature_open(struct inode *inode, struct file *file)
+{
+	return nonseekable_open(inode, file);
+}
+
+static int usb_pcwd_temperature_release(struct inode *inode, struct file *file)
+{
+	return 0;
+}
+
+/*
+ *	Notify system
+ */
+
+static int usb_pcwd_notify_sys(struct notifier_block *this, unsigned long code, void *unused)
+{
+	if (code==SYS_DOWN || code==SYS_HALT) {
+		/* Turn the WDT off */
+		usb_pcwd_stop(usb_pcwd_device);
+	}
+
+	return NOTIFY_DONE;
+}
+
+/*
+ *	Kernel Interfaces
+ */
+
+static struct file_operations usb_pcwd_fops = {
+	.owner =	THIS_MODULE,
+	.llseek =	no_llseek,
+	.write =	usb_pcwd_write,
+	.ioctl =	usb_pcwd_ioctl,
+	.open =		usb_pcwd_open,
+	.release =	usb_pcwd_release,
+};
+
+static struct miscdevice usb_pcwd_miscdev = {
+	.minor =	WATCHDOG_MINOR,
+	.name =		"watchdog",
+	.fops =		&usb_pcwd_fops,
+};
+
+static struct file_operations usb_pcwd_temperature_fops = {
+	.owner =	THIS_MODULE,
+	.llseek =	no_llseek,
+	.read =		usb_pcwd_temperature_read,
+	.open =		usb_pcwd_temperature_open,
+	.release =	usb_pcwd_temperature_release,
+};
+
+static struct miscdevice usb_pcwd_temperature_miscdev = {
+	.minor =	TEMP_MINOR,
+	.name =		"temperature",
+	.fops =		&usb_pcwd_temperature_fops,
+};
+
+static struct notifier_block usb_pcwd_notifier = {
+	.notifier_call =	usb_pcwd_notify_sys,
+};
+
+/**
+ *	usb_pcwd_delete
+ */
+static inline void usb_pcwd_delete (struct usb_pcwd_private *usb_pcwd)
+{
+	if (usb_pcwd->intr_urb != NULL)
+		usb_free_urb (usb_pcwd->intr_urb);
+	if (usb_pcwd->intr_buffer != NULL)
+		usb_buffer_free(usb_pcwd->udev, usb_pcwd->intr_size,
+				usb_pcwd->intr_buffer, usb_pcwd->intr_dma);
+	kfree (usb_pcwd);
+}
+
+/**
+ *	usb_pcwd_probe
+ *
+ *	Called by the usb core when a new device is connected that it thinks
+ *	this driver might be interested in.
+ */
+static int usb_pcwd_probe(struct usb_interface *interface, const struct usb_device_id *id)
+{
+	struct usb_device *udev = interface_to_usbdev(interface);
+	struct usb_host_interface *iface_desc;
+	struct usb_endpoint_descriptor *endpoint;
+	struct usb_pcwd_private *usb_pcwd = NULL;
+	int pipe, maxp;
+	int retval = -ENOMEM;
+	int got_fw_rev;
+	unsigned char fw_rev_major, fw_rev_minor;
+	char fw_ver_str[20];
+	unsigned char option_switches, dummy;
+
+	cards_found++;
+	if (cards_found > 1) {
+		printk(KERN_ERR PFX "This driver only supports 1 device\n");
+		return -ENODEV;
+	}
+
+	/* get the active interface descriptor */
+	iface_desc = interface->cur_altsetting;
+
+	/* check out that we have a HID device */
+	if (!(iface_desc->desc.bInterfaceClass == USB_CLASS_HID)) {
+		printk(KERN_ERR PFX "The device isn't a Human Interface Device\n");
+		return -ENODEV;
+	}
+
+	/* check out the endpoint: it has to be Interrupt & IN */
+	endpoint = &iface_desc->endpoint[0].desc;
+
+	if (!((endpoint->bEndpointAddress & USB_DIR_IN) &&
+	     ((endpoint->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK)
+				== USB_ENDPOINT_XFER_INT))) {
+		/* we didn't find a Interrupt endpoint with direction IN */
+		printk(KERN_ERR PFX "Couldn't find an INTR & IN endpoint\n");
+		return -ENODEV;
+	}
+
+	/* get a handle to the interrupt data pipe */
+	pipe = usb_rcvintpipe(udev, endpoint->bEndpointAddress);
+	maxp = usb_maxpacket(udev, pipe, usb_pipeout(pipe));
+
+	/* allocate memory for our device and initialize it */
+	usb_pcwd = kmalloc (sizeof(struct usb_pcwd_private), GFP_KERNEL);
+	if (usb_pcwd == NULL) {
+		printk(KERN_ERR PFX "Out of memory\n");
+		goto error;
+	}
+	memset (usb_pcwd, 0x00, sizeof (*usb_pcwd));
+
+	usb_pcwd_device = usb_pcwd;
+
+	init_MUTEX (&usb_pcwd->sem);
+	usb_pcwd->udev = udev;
+	usb_pcwd->interface = interface;
+	usb_pcwd->interface_number = iface_desc->desc.bInterfaceNumber;
+	usb_pcwd->intr_size = (le16_to_cpu(endpoint->wMaxPacketSize) > 8 ? le16_to_cpu(endpoint->wMaxPacketSize) : 8);
+
+	/* set up the memory buffer's */
+	if (!(usb_pcwd->intr_buffer = usb_buffer_alloc(udev, usb_pcwd->intr_size, SLAB_ATOMIC, &usb_pcwd->intr_dma))) {
+		printk(KERN_ERR PFX "Out of memory\n");
+		goto error;
+	}
+
+	/* allocate the urb's */
+	usb_pcwd->intr_urb = usb_alloc_urb(0, GFP_KERNEL);
+	if (!usb_pcwd->intr_urb) {
+		printk(KERN_ERR PFX "Out of memory\n");
+		goto error;
+	}
+
+	/* initialise the intr urb's */
+	usb_fill_int_urb(usb_pcwd->intr_urb, udev, pipe,
+			usb_pcwd->intr_buffer, usb_pcwd->intr_size,
+			usb_pcwd_intr_done, usb_pcwd, endpoint->bInterval);
+	usb_pcwd->intr_urb->transfer_dma = usb_pcwd->intr_dma;
+	usb_pcwd->intr_urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;
+
+	/* register our interrupt URB with the USB system */
+	if (usb_submit_urb(usb_pcwd->intr_urb, GFP_KERNEL)) {
+		printk(KERN_ERR PFX "Problem registering interrupt URB\n");
+		retval = -EIO; /* failure */
+		goto error;
+	}
+
+	/* The device exists and can be communicated with */
+	usb_pcwd->exists = 1;
+
+	/* disable card */
+	usb_pcwd_stop(usb_pcwd);
+
+	/* Get the Firmware Version */
+	got_fw_rev = usb_pcwd_send_command(usb_pcwd, CMD_GET_FIRMWARE_VERSION, &fw_rev_major, &fw_rev_minor);
+	if (got_fw_rev) {
+		sprintf(fw_ver_str, "%u.%02u", fw_rev_major, fw_rev_minor);
+	} else {
+		sprintf(fw_ver_str, "<card no answer>");
+	}
+
+	printk(KERN_INFO PFX "Found card (Firmware: %s) with temp option\n",
+		fw_ver_str);
+
+	/* Get switch settings */
+	usb_pcwd_send_command(usb_pcwd, CMD_GET_DIP_SWITCH_SETTINGS, &dummy, &option_switches);
+
+	printk(KERN_INFO PFX "Option switches (0x%02x): Temperature Reset Enable=%s, Power On Delay=%s\n",
+		option_switches,
+		((option_switches & 0x10) ? "ON" : "OFF"),
+		((option_switches & 0x08) ? "ON" : "OFF"));
+
+	/* Check that the heartbeat value is within it's range ; if not reset to the default */
+	if (usb_pcwd_set_heartbeat(usb_pcwd, heartbeat)) {
+		usb_pcwd_set_heartbeat(usb_pcwd, WATCHDOG_HEARTBEAT);
+		printk(KERN_INFO PFX "heartbeat value must be 0<heartbeat<65536, using %d\n",
+			WATCHDOG_HEARTBEAT);
+	}
+
+	retval = register_reboot_notifier(&usb_pcwd_notifier);
+	if (retval != 0) {
+		printk(KERN_ERR PFX "cannot register reboot notifier (err=%d)\n",
+			retval);
+		goto error;
+	}
+
+	retval = misc_register(&usb_pcwd_temperature_miscdev);
+	if (retval != 0) {
+		printk(KERN_ERR PFX "cannot register miscdev on minor=%d (err=%d)\n",
+			TEMP_MINOR, retval);
+		goto err_out_unregister_reboot;
+	}
+
+	retval = misc_register(&usb_pcwd_miscdev);
+	if (retval != 0) {
+		printk(KERN_ERR PFX "cannot register miscdev on minor=%d (err=%d)\n",
+			WATCHDOG_MINOR, retval);
+		goto err_out_misc_deregister;
+	}
+
+	/* we can register the device now, as it is ready */
+	usb_set_intfdata (interface, usb_pcwd);
+
+	printk(KERN_INFO PFX "initialized. heartbeat=%d sec (nowayout=%d)\n",
+		heartbeat, nowayout);
+
+	return 0;
+
+err_out_misc_deregister:
+	misc_deregister(&usb_pcwd_temperature_miscdev);
+err_out_unregister_reboot:
+	unregister_reboot_notifier(&usb_pcwd_notifier);
+error:
+	usb_pcwd_delete (usb_pcwd);
+	usb_pcwd_device = NULL;
+	return retval;
+}
+
+
+/**
+ *	usb_pcwd_disconnect
+ *
+ *	Called by the usb core when the device is removed from the system.
+ *
+ *	This routine guarantees that the driver will not submit any more urbs
+ *	by clearing dev->udev.
+ */
+static void usb_pcwd_disconnect(struct usb_interface *interface)
+{
+	struct usb_pcwd_private *usb_pcwd;
+
+	/* prevent races with open() */
+	down (&disconnect_sem);
+
+	usb_pcwd = usb_get_intfdata (interface);
+	usb_set_intfdata (interface, NULL);
+
+	down (&usb_pcwd->sem);
+
+	/* Stop the timer before we leave */
+	if (!nowayout)
+		usb_pcwd_stop(usb_pcwd);
+
+	/* We should now stop communicating with the USB PCWD device */
+	usb_pcwd->exists = 0;
+
+	/* Deregister */
+	misc_deregister(&usb_pcwd_miscdev);
+	misc_deregister(&usb_pcwd_temperature_miscdev);
+	unregister_reboot_notifier(&usb_pcwd_notifier);
+
+	up (&usb_pcwd->sem);
+
+	/* Delete the USB PCWD device */
+	usb_pcwd_delete(usb_pcwd);
+
+	cards_found--;
+
+	up (&disconnect_sem);
+
+	printk(KERN_INFO PFX "USB PC Watchdog disconnected\n");
+}
+
+
+
+/**
+ *	usb_pcwd_init
+ */
+static int __init usb_pcwd_init(void)
+{
+	int result;
+
+	/* register this driver with the USB subsystem */
+	result = usb_register(&usb_pcwd_driver);
+	if (result) {
+		printk(KERN_ERR PFX "usb_register failed. Error number %d\n",
+		    result);
+		return result;
+	}
+
+	printk(KERN_INFO PFX DRIVER_DESC " v" DRIVER_VERSION " (" DRIVER_DATE ")\n");
+	return 0;
+}
+
+
+/**
+ *	usb_pcwd_exit
+ */
+static void __exit usb_pcwd_exit(void)
+{
+	/* deregister this driver with the USB subsystem */
+	usb_deregister(&usb_pcwd_driver);
+}
+
+
+module_init (usb_pcwd_init);
+module_exit (usb_pcwd_exit);
diff --git a/drivers/char/watchdog/s3c2410_wdt.c b/drivers/char/watchdog/s3c2410_wdt.c
new file mode 100644
index 0000000..1699d2c
--- /dev/null
+++ b/drivers/char/watchdog/s3c2410_wdt.c
@@ -0,0 +1,516 @@
+/* linux/drivers/char/watchdog/s3c2410_wdt.c
+ *
+ * Copyright (c) 2004 Simtec Electronics
+ *	Ben Dooks <ben@simtec.co.uk>
+ *
+ * S3C2410 Watchdog Timer Support
+ *
+ * Based on, softdog.c by Alan Cox,
+ *     (c) Copyright 1996 Alan Cox <alan@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.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ * Changelog:
+ *	05-Oct-2004	BJD	Added semaphore init to stop crashes on open
+ *				Fixed tmr_count / wdt_count confusion
+ *				Added configurable debug
+ *
+ *	11-Jan-2004	BJD	Fixed divide-by-2 in timeout code
+ *
+ *	10-Mar-2005	LCVR	Changed S3C2410_VA to S3C24XX_VA
+*/
+
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/config.h>
+#include <linux/types.h>
+#include <linux/timer.h>
+#include <linux/miscdevice.h>
+#include <linux/watchdog.h>
+#include <linux/fs.h>
+#include <linux/notifier.h>
+#include <linux/reboot.h>
+#include <linux/init.h>
+#include <linux/device.h>
+#include <linux/interrupt.h>
+
+#include <asm/uaccess.h>
+#include <asm/io.h>
+
+#include <asm/arch/map.h>
+#include <asm/hardware/clock.h>
+
+#undef S3C24XX_VA_WATCHDOG
+#define S3C24XX_VA_WATCHDOG (0)
+
+#include <asm/arch/regs-watchdog.h>
+
+#define PFX "s3c2410-wdt: "
+
+#define CONFIG_S3C2410_WATCHDOG_ATBOOT		(0)
+#define CONFIG_S3C2410_WATCHDOG_DEFAULT_TIME	(15)
+
+#ifdef CONFIG_WATCHDOG_NOWAYOUT
+static int nowayout = 1;
+#else
+static int nowayout = 0;
+#endif
+
+static int tmr_margin	= CONFIG_S3C2410_WATCHDOG_DEFAULT_TIME;
+static int tmr_atboot	= CONFIG_S3C2410_WATCHDOG_ATBOOT;
+static int soft_noboot	= 0;
+static int debug	= 0;
+
+module_param(tmr_margin,  int, 0);
+module_param(tmr_atboot,  int, 0);
+module_param(nowayout,    int, 0);
+module_param(soft_noboot, int, 0);
+module_param(debug,	  int, 0);
+
+MODULE_PARM_DESC(tmr_margin, "Watchdog tmr_margin in seconds. default=" __MODULE_STRING(CONFIG_S3C2410_WATCHDOG_DEFAULT_TIME) ")");
+
+MODULE_PARM_DESC(tmr_atboot, "Watchdog is started at boot time if set to 1, default=" __MODULE_STRING(CONFIG_S3C2410_WATCHDOG_ATBOOT));
+
+MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default=CONFIG_WATCHDOG_NOWAYOUT)");
+
+MODULE_PARM_DESC(soft_noboot, "Watchdog action, set to 1 to ignore reboots, 0 to reboot (default depends on ONLY_TESTING)");
+
+MODULE_PARM_DESC(debug, "Watchdog debug, set to >1 for debug, (default 0)");
+
+
+typedef enum close_state {
+	CLOSE_STATE_NOT,
+	CLOSE_STATE_ALLOW=0x4021
+} close_state_t;
+
+static DECLARE_MUTEX(open_lock);
+
+static struct resource	*wdt_mem;
+static struct resource	*wdt_irq;
+static struct clk	*wdt_clock;
+static void __iomem	*wdt_base;
+static unsigned int	 wdt_count;
+static close_state_t	 allow_close;
+
+/* watchdog control routines */
+
+#define DBG(msg...) do { \
+	if (debug) \
+		printk(KERN_INFO msg); \
+	} while(0)
+
+/* functions */
+
+static int s3c2410wdt_keepalive(void)
+{
+	writel(wdt_count, wdt_base + S3C2410_WTCNT);
+	return 0;
+}
+
+static int s3c2410wdt_stop(void)
+{
+	unsigned long wtcon;
+
+	wtcon = readl(wdt_base + S3C2410_WTCON);
+	wtcon &= ~(S3C2410_WTCON_ENABLE | S3C2410_WTCON_RSTEN);
+	writel(wtcon, wdt_base + S3C2410_WTCON);
+
+	return 0;
+}
+
+static int s3c2410wdt_start(void)
+{
+	unsigned long wtcon;
+
+	s3c2410wdt_stop();
+
+	wtcon = readl(wdt_base + S3C2410_WTCON);
+	wtcon |= S3C2410_WTCON_ENABLE | S3C2410_WTCON_DIV128;
+
+	if (soft_noboot) {
+		wtcon |= S3C2410_WTCON_INTEN;
+		wtcon &= ~S3C2410_WTCON_RSTEN;
+	} else {
+		wtcon &= ~S3C2410_WTCON_INTEN;
+		wtcon |= S3C2410_WTCON_RSTEN;
+	}
+
+	DBG("%s: wdt_count=0x%08x, wtcon=%08lx\n",
+	    __FUNCTION__, wdt_count, wtcon);
+
+	writel(wdt_count, wdt_base + S3C2410_WTDAT);
+	writel(wdt_count, wdt_base + S3C2410_WTCNT);
+	writel(wtcon, wdt_base + S3C2410_WTCON);
+
+	return 0;
+}
+
+static int s3c2410wdt_set_heartbeat(int timeout)
+{
+	unsigned int freq = clk_get_rate(wdt_clock);
+	unsigned int count;
+	unsigned int divisor = 1;
+	unsigned long wtcon;
+
+	if (timeout < 1)
+		return -EINVAL;
+
+	freq /= 128;
+	count = timeout * freq;
+
+	DBG("%s: count=%d, timeout=%d, freq=%d\n",
+	    __FUNCTION__, count, timeout, freq);
+
+	/* if the count is bigger than the watchdog register,
+	   then work out what we need to do (and if) we can
+	   actually make this value
+	*/
+
+	if (count >= 0x10000) {
+		for (divisor = 1; divisor <= 0x100; divisor++) {
+			if ((count / divisor) < 0x10000)
+				break;
+		}
+
+		if ((count / divisor) >= 0x10000) {
+			printk(KERN_ERR PFX "timeout %d too big\n", timeout);
+			return -EINVAL;
+		}
+	}
+
+	tmr_margin = timeout;
+
+	DBG("%s: timeout=%d, divisor=%d, count=%d (%08x)\n",
+	    __FUNCTION__, timeout, divisor, count, count/divisor);
+
+	count /= divisor;
+	wdt_count = count;
+
+	/* update the pre-scaler */
+	wtcon = readl(wdt_base + S3C2410_WTCON);
+	wtcon &= ~S3C2410_WTCON_PRESCALE_MASK;
+	wtcon |= S3C2410_WTCON_PRESCALE(divisor-1);
+
+	writel(count, wdt_base + S3C2410_WTDAT);
+	writel(wtcon, wdt_base + S3C2410_WTCON);
+
+	return 0;
+}
+
+/*
+ *	/dev/watchdog handling
+ */
+
+static int s3c2410wdt_open(struct inode *inode, struct file *file)
+{
+	if(down_trylock(&open_lock))
+		return -EBUSY;
+
+	if (nowayout) {
+		__module_get(THIS_MODULE);
+	} else {
+		allow_close = CLOSE_STATE_ALLOW;
+	}
+
+	/* start the timer */
+	s3c2410wdt_start();
+	return nonseekable_open(inode, file);
+}
+
+static int s3c2410wdt_release(struct inode *inode, struct file *file)
+{
+	/*
+	 *	Shut off the timer.
+	 * 	Lock it in if it's a module and we set nowayout
+	 */
+	if (allow_close == CLOSE_STATE_ALLOW) {
+		s3c2410wdt_stop();
+	} else {
+		printk(KERN_CRIT PFX "Unexpected close, not stopping watchdog!\n");
+		s3c2410wdt_keepalive();
+	}
+
+	allow_close = CLOSE_STATE_NOT;
+	up(&open_lock);
+	return 0;
+}
+
+static ssize_t s3c2410wdt_write(struct file *file, const char __user *data,
+				size_t len, loff_t *ppos)
+{
+	/*
+	 *	Refresh the timer.
+	 */
+	if(len) {
+		if (!nowayout) {
+			size_t i;
+
+			/* In case it was set long ago */
+			allow_close = CLOSE_STATE_NOT;
+
+			for (i = 0; i != len; i++) {
+				char c;
+
+				if (get_user(c, data + i))
+					return -EFAULT;
+				if (c == 'V')
+					allow_close = CLOSE_STATE_ALLOW;
+			}
+		}
+
+		s3c2410wdt_keepalive();
+	}
+	return len;
+}
+
+#define OPTIONS WDIOF_SETTIMEOUT | WDIOF_KEEPALIVEPING | WDIOF_MAGICCLOSE
+
+static struct watchdog_info s3c2410_wdt_ident = {
+	.options          =     OPTIONS,
+	.firmware_version =	0,
+	.identity         =	"S3C2410 Watchdog",
+};
+
+
+static int s3c2410wdt_ioctl(struct inode *inode, struct file *file,
+	unsigned int cmd, unsigned long arg)
+{
+	void __user *argp = (void __user *)arg;
+	int __user *p = argp;
+	int new_margin;
+
+	switch (cmd) {
+		default:
+			return -ENOIOCTLCMD;
+
+		case WDIOC_GETSUPPORT:
+			return copy_to_user(argp, &s3c2410_wdt_ident,
+				sizeof(s3c2410_wdt_ident)) ? -EFAULT : 0;
+
+		case WDIOC_GETSTATUS:
+		case WDIOC_GETBOOTSTATUS:
+			return put_user(0, p);
+
+		case WDIOC_KEEPALIVE:
+			s3c2410wdt_keepalive();
+			return 0;
+
+		case WDIOC_SETTIMEOUT:
+			if (get_user(new_margin, p))
+				return -EFAULT;
+
+			if (s3c2410wdt_set_heartbeat(new_margin))
+				return -EINVAL;
+
+			s3c2410wdt_keepalive();
+			return put_user(tmr_margin, p);
+
+		case WDIOC_GETTIMEOUT:
+			return put_user(tmr_margin, p);
+	}
+}
+
+/*
+ *	Notifier for system down
+ */
+
+static int s3c2410wdt_notify_sys(struct notifier_block *this, unsigned long code,
+			      void *unused)
+{
+	if(code==SYS_DOWN || code==SYS_HALT) {
+		/* Turn the WDT off */
+		s3c2410wdt_stop();
+	}
+	return NOTIFY_DONE;
+}
+
+/* kernel interface */
+
+static struct file_operations s3c2410wdt_fops = {
+	.owner		= THIS_MODULE,
+	.llseek		= no_llseek,
+	.write		= s3c2410wdt_write,
+	.ioctl		= s3c2410wdt_ioctl,
+	.open		= s3c2410wdt_open,
+	.release	= s3c2410wdt_release,
+};
+
+static struct miscdevice s3c2410wdt_miscdev = {
+	.minor		= WATCHDOG_MINOR,
+	.name		= "watchdog",
+	.fops		= &s3c2410wdt_fops,
+};
+
+static struct notifier_block s3c2410wdt_notifier = {
+	.notifier_call	= s3c2410wdt_notify_sys,
+};
+
+/* interrupt handler code */
+
+static irqreturn_t s3c2410wdt_irq(int irqno, void *param,
+				  struct pt_regs *regs)
+{
+	printk(KERN_INFO PFX "Watchdog timer expired!\n");
+
+	s3c2410wdt_keepalive();
+	return IRQ_HANDLED;
+}
+/* device interface */
+
+static int s3c2410wdt_probe(struct device *dev)
+{
+	struct platform_device *pdev = to_platform_device(dev);
+	struct resource *res;
+	int started = 0;
+	int ret;
+	int size;
+
+	DBG("%s: probe=%p, device=%p\n", __FUNCTION__, pdev, dev);
+
+	/* get the memory region for the watchdog timer */
+
+	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	if (res == NULL) {
+		printk(KERN_INFO PFX "failed to get memory region resouce\n");
+		return -ENOENT;
+	}
+
+	size = (res->end-res->start)+1;
+	wdt_mem = request_mem_region(res->start, size, pdev->name);
+	if (wdt_mem == NULL) {
+		printk(KERN_INFO PFX "failed to get memory region\n");
+		return -ENOENT;
+	}
+
+	wdt_base = ioremap(res->start, size);
+	if (wdt_base == 0) {
+		printk(KERN_INFO PFX "failed to ioremap() region\n");
+		return -EINVAL;
+	}
+
+	DBG("probe: mapped wdt_base=%p\n", wdt_base);
+
+	res = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
+	if (res == NULL) {
+		printk(KERN_INFO PFX "failed to get irq resource\n");
+		return -ENOENT;
+	}
+
+	ret = request_irq(res->start, s3c2410wdt_irq, 0, pdev->name, dev);
+	if (ret != 0) {
+		printk(KERN_INFO PFX "failed to install irq (%d)\n", ret);
+		return ret;
+	}
+
+	wdt_clock = clk_get(dev, "watchdog");
+	if (wdt_clock == NULL) {
+		printk(KERN_INFO PFX "failed to find watchdog clock source\n");
+		return -ENOENT;
+	}
+
+	clk_use(wdt_clock);
+	clk_enable(wdt_clock);
+
+	/* see if we can actually set the requested timer margin, and if
+	 * not, try the default value */
+
+	if (s3c2410wdt_set_heartbeat(tmr_margin)) {
+		started = s3c2410wdt_set_heartbeat(CONFIG_S3C2410_WATCHDOG_DEFAULT_TIME);
+
+		if (started == 0) {
+			printk(KERN_INFO PFX "tmr_margin value out of range, default %d used\n",
+			       CONFIG_S3C2410_WATCHDOG_DEFAULT_TIME);
+		} else {
+			printk(KERN_INFO PFX "default timer value is out of range, cannot start\n");
+		}
+	}
+
+	ret = register_reboot_notifier(&s3c2410wdt_notifier);
+	if (ret) {
+		printk (KERN_ERR PFX "cannot register reboot notifier (%d)\n",
+			ret);
+		return ret;
+	}
+
+	ret = misc_register(&s3c2410wdt_miscdev);
+	if (ret) {
+		printk (KERN_ERR PFX "cannot register miscdev on minor=%d (%d)\n",
+			WATCHDOG_MINOR, ret);
+		unregister_reboot_notifier(&s3c2410wdt_notifier);
+		return ret;
+	}
+
+	if (tmr_atboot && started == 0) {
+		printk(KERN_INFO PFX "Starting Watchdog Timer\n");
+		s3c2410wdt_start();
+	}
+
+	return 0;
+}
+
+static int s3c2410wdt_remove(struct device *dev)
+{
+	if (wdt_mem != NULL) {
+		release_resource(wdt_mem);
+		kfree(wdt_mem);
+		wdt_mem = NULL;
+	}
+
+	if (wdt_irq != NULL) {
+		free_irq(wdt_irq->start, dev);
+		wdt_irq = NULL;
+	}
+
+	if (wdt_clock != NULL) {
+		clk_disable(wdt_clock);
+		clk_unuse(wdt_clock);
+		clk_put(wdt_clock);
+		wdt_clock = NULL;
+	}
+
+	misc_deregister(&s3c2410wdt_miscdev);
+	return 0;
+}
+
+static struct device_driver s3c2410wdt_driver = {
+	.name		= "s3c2410-wdt",
+	.bus		= &platform_bus_type,
+	.probe		= s3c2410wdt_probe,
+	.remove		= s3c2410wdt_remove,
+};
+
+
+
+static char banner[] __initdata = KERN_INFO "S3C2410 Watchdog Timer, (c) 2004 Simtec Electronics\n";
+
+static int __init watchdog_init(void)
+{
+	printk(banner);
+	return driver_register(&s3c2410wdt_driver);
+}
+
+static void __exit watchdog_exit(void)
+{
+	driver_unregister(&s3c2410wdt_driver);
+	unregister_reboot_notifier(&s3c2410wdt_notifier);
+}
+
+module_init(watchdog_init);
+module_exit(watchdog_exit);
+
+MODULE_AUTHOR("Ben Dooks <ben@simtec.co.uk>");
+MODULE_DESCRIPTION("S3C2410 Watchdog Device Driver");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS_MISCDEV(WATCHDOG_MINOR);
diff --git a/drivers/char/watchdog/sa1100_wdt.c b/drivers/char/watchdog/sa1100_wdt.c
new file mode 100644
index 0000000..34e8f7b
--- /dev/null
+++ b/drivers/char/watchdog/sa1100_wdt.c
@@ -0,0 +1,223 @@
+/*
+ *	Watchdog driver for the SA11x0/PXA2xx
+ *
+ *      (c) Copyright 2000 Oleg Drokin <green@crimea.edu>
+ *          Based on SoftDog driver by Alan Cox <alan@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 Oleg Drokin nor iXcelerator.com admit liability nor provide
+ *	warranty for any of this software. This material is provided
+ *	"AS-IS" and at no charge.
+ *
+ *	(c) Copyright 2000           Oleg Drokin <green@crimea.edu>
+ *
+ *      27/11/2000 Initial release
+ */
+#include <linux/config.h>
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/types.h>
+#include <linux/kernel.h>
+#include <linux/fs.h>
+#include <linux/miscdevice.h>
+#include <linux/watchdog.h>
+#include <linux/init.h>
+
+#ifdef CONFIG_ARCH_PXA
+#include <asm/arch/pxa-regs.h>
+#endif
+
+#include <asm/hardware.h>
+#include <asm/bitops.h>
+#include <asm/uaccess.h>
+
+#define OSCR_FREQ		CLOCK_TICK_RATE
+#define SA1100_CLOSE_MAGIC	(0x5afc4453)
+
+static unsigned long sa1100wdt_users;
+static int expect_close;
+static int pre_margin;
+static int boot_status;
+#ifdef CONFIG_WATCHDOG_NOWAYOUT
+static int nowayout = 1;
+#else
+static int nowayout = 0;
+#endif
+
+/*
+ *	Allow only one person to hold it open
+ */
+static int sa1100dog_open(struct inode *inode, struct file *file)
+{
+	nonseekable_open(inode, file);
+	if (test_and_set_bit(1,&sa1100wdt_users))
+		return -EBUSY;
+
+	/* Activate SA1100 Watchdog timer */
+	OSMR3 = OSCR + pre_margin;
+	OSSR = OSSR_M3;
+	OWER = OWER_WME;
+	OIER |= OIER_E3;
+	return 0;
+}
+
+/*
+ *	Shut off the timer.
+ * 	Lock it in if it's a module and we defined ...NOWAYOUT
+ *	Oddly, the watchdog can only be enabled, but we can turn off
+ *	the interrupt, which appears to prevent the watchdog timing out.
+ */
+static int sa1100dog_release(struct inode *inode, struct file *file)
+{
+	OSMR3 = OSCR + pre_margin;
+
+	if (expect_close == SA1100_CLOSE_MAGIC) {
+		OIER &= ~OIER_E3;
+	} else {
+		printk(KERN_CRIT "WATCHDOG: WDT device closed unexpectedly.  WDT will not stop!\n");
+	}
+
+	clear_bit(1, &sa1100wdt_users);
+	expect_close = 0;
+
+	return 0;
+}
+
+static ssize_t sa1100dog_write(struct file *file, const char *data, size_t len, loff_t *ppos)
+{
+	if (len) {
+		if (!nowayout) {
+			size_t i;
+
+			expect_close = 0;
+
+			for (i = 0; i != len; i++) {
+				char c;
+
+				if (get_user(c, data + i))
+					return -EFAULT;
+				if (c == 'V')
+					expect_close = SA1100_CLOSE_MAGIC;
+			}
+		}
+		/* Refresh OSMR3 timer. */
+		OSMR3 = OSCR + pre_margin;
+	}
+
+	return len;
+}
+
+static struct watchdog_info ident = {
+	.options	= WDIOF_CARDRESET | WDIOF_MAGICCLOSE |
+			  WDIOF_SETTIMEOUT | WDIOF_KEEPALIVEPING,
+	.identity	= "SA1100 Watchdog",
+};
+
+static int sa1100dog_ioctl(struct inode *inode, struct file *file,
+	unsigned int cmd, unsigned long arg)
+{
+	int ret = -ENOIOCTLCMD;
+	int time;
+
+	switch (cmd) {
+	case WDIOC_GETSUPPORT:
+		ret = copy_to_user((struct watchdog_info *)arg, &ident,
+				   sizeof(ident)) ? -EFAULT : 0;
+		break;
+
+	case WDIOC_GETSTATUS:
+		ret = put_user(0, (int *)arg);
+		break;
+
+	case WDIOC_GETBOOTSTATUS:
+		ret = put_user(boot_status, (int *)arg);
+		break;
+
+	case WDIOC_SETTIMEOUT:
+		ret = get_user(time, (int *)arg);
+		if (ret)
+			break;
+
+		if (time <= 0 || time > 255) {
+			ret = -EINVAL;
+			break;
+		}
+
+		pre_margin = OSCR_FREQ * time;
+		OSMR3 = OSCR + pre_margin;
+		/*fall through*/
+
+	case WDIOC_GETTIMEOUT:
+		ret = put_user(pre_margin / OSCR_FREQ, (int *)arg);
+		break;
+
+	case WDIOC_KEEPALIVE:
+		OSMR3 = OSCR + pre_margin;
+		ret = 0;
+		break;
+	}
+	return ret;
+}
+
+static struct file_operations sa1100dog_fops =
+{
+	.owner		= THIS_MODULE,
+	.llseek		= no_llseek,
+	.write		= sa1100dog_write,
+	.ioctl		= sa1100dog_ioctl,
+	.open		= sa1100dog_open,
+	.release	= sa1100dog_release,
+};
+
+static struct miscdevice sa1100dog_miscdev =
+{
+	.minor		= WATCHDOG_MINOR,
+	.name		= "SA1100/PXA2xx watchdog",
+	.fops		= &sa1100dog_fops,
+};
+
+static int margin __initdata = 60;		/* (secs) Default is 1 minute */
+
+static int __init sa1100dog_init(void)
+{
+	int ret;
+
+	/*
+	 * Read the reset status, and save it for later.  If
+	 * we suspend, RCSR will be cleared, and the watchdog
+	 * reset reason will be lost.
+	 */
+	boot_status = (RCSR & RCSR_WDR) ? WDIOF_CARDRESET : 0;
+	pre_margin = OSCR_FREQ * margin;
+
+	ret = misc_register(&sa1100dog_miscdev);
+	if (ret == 0)
+		printk("SA1100/PXA2xx Watchdog Timer: timer margin %d sec\n",
+		       margin);
+
+	return ret;
+}
+
+static void __exit sa1100dog_exit(void)
+{
+	misc_deregister(&sa1100dog_miscdev);
+}
+
+module_init(sa1100dog_init);
+module_exit(sa1100dog_exit);
+
+MODULE_AUTHOR("Oleg Drokin <green@crimea.edu>");
+MODULE_DESCRIPTION("SA1100/PXA2xx Watchdog");
+
+module_param(margin, int, 0);
+MODULE_PARM_DESC(margin, "Watchdog margin in seconds (default 60s)");
+
+module_param(nowayout, int, 0);
+MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started");
+
+MODULE_LICENSE("GPL");
+MODULE_ALIAS_MISCDEV(WATCHDOG_MINOR);
diff --git a/drivers/char/watchdog/sbc60xxwdt.c b/drivers/char/watchdog/sbc60xxwdt.c
new file mode 100644
index 0000000..d7de988
--- /dev/null
+++ b/drivers/char/watchdog/sbc60xxwdt.c
@@ -0,0 +1,413 @@
+/*
+ *	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@unthought.net>
+ *
+ *           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
+ *           12/4 - 2002      [rob@osinvestor.com] eliminate fop_read
+ *                            fix possible wdt_is_open race
+ *                            add CONFIG_WATCHDOG_NOWAYOUT support
+ *                            remove lock_kernel/unlock_kernel pairs
+ *                            added KERN_* to printk's
+ *                            got rid of extraneous comments
+ *                            changed watchdog_info to correctly reflect what the driver offers
+ *                            added WDIOC_GETSTATUS, WDIOC_GETBOOTSTATUS, WDIOC_SETTIMEOUT,
+ *                            WDIOC_GETTIMEOUT, and WDIOC_SETOPTIONS ioctls
+ *           09/8 - 2003      [wim@iguana.be] cleanup of trailing spaces
+ *                            use module_param
+ *                            made timeout (the emulated heartbeat) a module_param
+ *                            made the keepalive ping an internal subroutine
+ *                            made wdt_stop and wdt_start module params
+ *                            added extra printk's for startup problems
+ *                            added MODULE_AUTHOR and MODULE_DESCRIPTION info
+ *
+ *
+ *  This WDT driver is different from the other Linux WDT
+ *  drivers in the following 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.
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/types.h>
+#include <linux/timer.h>
+#include <linux/jiffies.h>
+#include <linux/miscdevice.h>
+#include <linux/watchdog.h>
+#include <linux/fs.h>
+#include <linux/ioport.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>
+
+#define OUR_NAME "sbc60xxwdt"
+#define PFX OUR_NAME ": "
+
+/*
+ * You must set these - The driver cannot probe for the settings
+ */
+
+static int wdt_stop = 0x45;
+module_param(wdt_stop, int, 0);
+MODULE_PARM_DESC(wdt_stop, "SBC60xx WDT 'stop' io port (default 0x45)");
+
+static int wdt_start = 0x443;
+module_param(wdt_start, int, 0);
+MODULE_PARM_DESC(wdt_start, "SBC60xx WDT 'start' io port (default 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 30 seconds.
+ * If the daemon pulses us every 25 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 WATCHDOG_TIMEOUT 30		/* 30 sec default timeout */
+static int timeout = WATCHDOG_TIMEOUT;	/* in seconds, will be multiplied by HZ to get seconds to wait for a ping */
+module_param(timeout, int, 0);
+MODULE_PARM_DESC(timeout, "Watchdog timeout in seconds. (1<=timeout<=3600, default=" __MODULE_STRING(WATCHDOG_TIMEOUT) ")");
+
+#ifdef CONFIG_WATCHDOG_NOWAYOUT
+static int nowayout = 1;
+#else
+static int nowayout = 0;
+#endif
+
+module_param(nowayout, int, 0);
+MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default=CONFIG_WATCHDOG_NOWAYOUT)");
+
+static void wdt_timer_ping(unsigned long);
+static struct timer_list timer;
+static unsigned long next_heartbeat;
+static unsigned long wdt_is_open;
+static char wdt_expect_close;
+
+/*
+ *	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(KERN_WARNING PFX "Heartbeat lost! Will not ping the watchdog\n");
+	}
+}
+
+/*
+ * Utility routines
+ */
+
+static void wdt_startup(void)
+{
+	next_heartbeat = jiffies + (timeout * HZ);
+
+	/* Start the timer */
+	timer.expires = jiffies + WDT_INTERVAL;
+	add_timer(&timer);
+	printk(KERN_INFO PFX "Watchdog timer is now enabled.\n");
+}
+
+static void wdt_turnoff(void)
+{
+	/* Stop the timer */
+	del_timer(&timer);
+	inb_p(wdt_stop);
+	printk(KERN_INFO PFX "Watchdog timer is now disabled...\n");
+}
+
+static void wdt_keepalive(void)
+{
+	/* user land ping */
+	next_heartbeat = jiffies + (timeout * HZ);
+}
+
+/*
+ * /dev/watchdog handling
+ */
+
+static ssize_t fop_write(struct file * file, const char __user * buf, size_t count, loff_t * ppos)
+{
+	/* See if we got the magic character 'V' and reload the timer */
+	if(count)
+	{
+		if (!nowayout)
+		{
+			size_t ofs;
+
+			/* note: just in case someone wrote the magic character
+			 * five months ago... */
+			wdt_expect_close = 0;
+
+			/* scan to see whether or not we got the magic character */
+			for(ofs = 0; ofs != count; ofs++)
+			{
+				char c;
+				if(get_user(c, buf+ofs))
+					return -EFAULT;
+				if(c == 'V')
+					wdt_expect_close = 42;
+			}
+		}
+
+		/* Well, anyhow someone wrote to us, we should return that favour */
+		wdt_keepalive();
+	}
+	return count;
+}
+
+static int fop_open(struct inode * inode, struct file * file)
+{
+	nonseekable_open(inode, file);
+
+	/* Just in case we're already talking to someone... */
+	if(test_and_set_bit(0, &wdt_is_open))
+		return -EBUSY;
+
+	if (nowayout)
+		__module_get(THIS_MODULE);
+
+	/* Good, fire up the show */
+	wdt_startup();
+	return 0;
+}
+
+static int fop_close(struct inode * inode, struct file * file)
+{
+	if(wdt_expect_close == 42)
+		wdt_turnoff();
+	else {
+		del_timer(&timer);
+		printk(KERN_CRIT PFX "device file closed unexpectedly. Will not stop the WDT!\n");
+	}
+	clear_bit(0, &wdt_is_open);
+	wdt_expect_close = 0;
+	return 0;
+}
+
+static int fop_ioctl(struct inode *inode, struct file *file, unsigned int cmd,
+	unsigned long arg)
+{
+	void __user *argp = (void __user *)arg;
+	int __user *p = argp;
+	static struct watchdog_info ident=
+	{
+		.options = WDIOF_KEEPALIVEPING | WDIOF_SETTIMEOUT | WDIOF_MAGICCLOSE,
+		.firmware_version = 1,
+		.identity = "SBC60xx",
+	};
+
+	switch(cmd)
+	{
+		default:
+			return -ENOIOCTLCMD;
+		case WDIOC_GETSUPPORT:
+			return copy_to_user(argp, &ident, sizeof(ident))?-EFAULT:0;
+		case WDIOC_GETSTATUS:
+		case WDIOC_GETBOOTSTATUS:
+			return put_user(0, p);
+		case WDIOC_KEEPALIVE:
+			wdt_keepalive();
+			return 0;
+		case WDIOC_SETOPTIONS:
+		{
+			int new_options, retval = -EINVAL;
+
+			if(get_user(new_options, p))
+				return -EFAULT;
+
+			if(new_options & WDIOS_DISABLECARD) {
+				wdt_turnoff();
+				retval = 0;
+			}
+
+			if(new_options & WDIOS_ENABLECARD) {
+				wdt_startup();
+				retval = 0;
+			}
+
+			return retval;
+		}
+		case WDIOC_SETTIMEOUT:
+		{
+			int new_timeout;
+
+			if(get_user(new_timeout, p))
+				return -EFAULT;
+
+			if(new_timeout < 1 || new_timeout > 3600) /* arbitrary upper limit */
+				return -EINVAL;
+
+			timeout = new_timeout;
+			wdt_keepalive();
+			/* Fall through */
+		}
+		case WDIOC_GETTIMEOUT:
+			return put_user(timeout, p);
+	}
+}
+
+static struct file_operations wdt_fops = {
+	.owner		= THIS_MODULE,
+	.llseek		= no_llseek,
+	.write		= fop_write,
+	.open		= fop_open,
+	.release	= fop_close,
+	.ioctl		= fop_ioctl,
+};
+
+static struct miscdevice wdt_miscdev = {
+	.minor = WATCHDOG_MINOR,
+	.name = "watchdog",
+	.fops = &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=
+{
+	.notifier_call = wdt_notify_sys,
+};
+
+static void __exit sbc60xxwdt_unload(void)
+{
+	wdt_turnoff();
+
+	/* Deregister */
+	misc_deregister(&wdt_miscdev);
+
+	unregister_reboot_notifier(&wdt_notifier);
+	if ((wdt_stop != 0x45) && (wdt_stop != wdt_start))
+		release_region(wdt_stop,1);
+	release_region(wdt_start,1);
+}
+
+static int __init sbc60xxwdt_init(void)
+{
+	int rc = -EBUSY;
+
+	if(timeout < 1 || timeout > 3600) /* arbitrary upper limit */
+	{
+		timeout = WATCHDOG_TIMEOUT;
+		printk(KERN_INFO PFX "timeout value must be 1<=x<=3600, using %d\n",
+			timeout);
+ 	}
+
+	if (!request_region(wdt_start, 1, "SBC 60XX WDT"))
+	{
+		printk(KERN_ERR PFX "I/O address 0x%04x already in use\n",
+			wdt_start);
+		rc = -EIO;
+		goto err_out;
+	}
+
+	/* We cannot reserve 0x45 - the kernel already has! */
+	if ((wdt_stop != 0x45) && (wdt_stop != wdt_start))
+	{
+		if (!request_region(wdt_stop, 1, "SBC 60XX WDT"))
+		{
+			printk(KERN_ERR PFX "I/O address 0x%04x already in use\n",
+				wdt_stop);
+			rc = -EIO;
+			goto err_out_region1;
+		}
+	}
+
+	init_timer(&timer);
+	timer.function = wdt_timer_ping;
+	timer.data = 0;
+
+	rc = misc_register(&wdt_miscdev);
+	if (rc)
+	{
+		printk(KERN_ERR PFX "cannot register miscdev on minor=%d (err=%d)\n",
+			wdt_miscdev.minor, rc);
+		goto err_out_region2;
+	}
+
+	rc = register_reboot_notifier(&wdt_notifier);
+	if (rc)
+	{
+		printk(KERN_ERR PFX "cannot register reboot notifier (err=%d)\n",
+			rc);
+		goto err_out_miscdev;
+	}
+
+	printk(KERN_INFO PFX "WDT driver for 60XX single board computer initialised. timeout=%d sec (nowayout=%d)\n",
+		timeout, nowayout);
+
+	return 0;
+
+err_out_miscdev:
+	misc_deregister(&wdt_miscdev);
+err_out_region2:
+	if ((wdt_stop != 0x45) && (wdt_stop != wdt_start))
+		release_region(wdt_stop,1);
+err_out_region1:
+	release_region(wdt_start,1);
+err_out:
+	return rc;
+}
+
+module_init(sbc60xxwdt_init);
+module_exit(sbc60xxwdt_unload);
+
+MODULE_AUTHOR("Jakob Oestergaard <jakob@unthought.net>");
+MODULE_DESCRIPTION("60xx Single Board Computer Watchdog Timer driver");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS_MISCDEV(WATCHDOG_MINOR);
diff --git a/drivers/char/watchdog/sc1200wdt.c b/drivers/char/watchdog/sc1200wdt.c
new file mode 100644
index 0000000..24401e8
--- /dev/null
+++ b/drivers/char/watchdog/sc1200wdt.c
@@ -0,0 +1,467 @@
+/*
+ *	National Semiconductor PC87307/PC97307 (ala SC1200) WDT driver
+ *	(c) Copyright 2002 Zwane Mwaikambo <zwane@commfireservices.com>,
+ *			All Rights Reserved.
+ *	Based on wdt.c and wdt977.c by Alan Cox and Woody Suwalski respectively.
+ *
+ *	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.
+ *
+ *	Changelog:
+ *	20020220 Zwane Mwaikambo	Code based on datasheet, no hardware.
+ *	20020221 Zwane Mwaikambo	Cleanups as suggested by Jeff Garzik and Alan Cox.
+ *	20020222 Zwane Mwaikambo	Added probing.
+ *	20020225 Zwane Mwaikambo	Added ISAPNP support.
+ *	20020412 Rob Radez		Broke out start/stop functions
+ *		 <rob@osinvestor.com>	Return proper status instead of temperature warning
+ *					Add WDIOC_GETBOOTSTATUS and WDIOC_SETOPTIONS ioctls
+ *					Fix CONFIG_WATCHDOG_NOWAYOUT
+ *	20020530 Joel Becker		Add Matt Domsch's nowayout module option
+ *	20030116 Adam Belay		Updated to the latest pnp code
+ *
+ */
+
+#include <linux/config.h>
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/miscdevice.h>
+#include <linux/watchdog.h>
+#include <linux/ioport.h>
+#include <linux/spinlock.h>
+#include <linux/notifier.h>
+#include <linux/reboot.h>
+#include <linux/init.h>
+#include <linux/pnp.h>
+#include <linux/fs.h>
+#include <linux/pci.h>
+
+#include <asm/semaphore.h>
+#include <asm/io.h>
+#include <asm/uaccess.h>
+
+#define SC1200_MODULE_VER	"build 20020303"
+#define SC1200_MODULE_NAME	"sc1200wdt"
+#define PFX			SC1200_MODULE_NAME ": "
+
+#define	MAX_TIMEOUT	255	/* 255 minutes */
+#define PMIR		(io)	/* Power Management Index Register */
+#define PMDR		(io+1)	/* Power Management Data Register */
+
+/* Data Register indexes */
+#define FER1		0x00	/* Function enable register 1 */
+#define FER2		0x01	/* Function enable register 2 */
+#define PMC1		0x02	/* Power Management Ctrl 1 */
+#define PMC2		0x03	/* Power Management Ctrl 2 */
+#define PMC3		0x04	/* Power Management Ctrl 3 */
+#define WDTO		0x05	/* Watchdog timeout register */
+#define	WDCF		0x06	/* Watchdog config register */
+#define WDST		0x07	/* Watchdog status register */
+
+/* WDCF bitfields - which devices assert WDO */
+#define KBC_IRQ		0x01	/* Keyboard Controller */
+#define MSE_IRQ		0x02	/* Mouse */
+#define UART1_IRQ	0x03	/* Serial0 */
+#define UART2_IRQ	0x04	/* Serial1 */
+/* 5 -7 are reserved */
+
+static char banner[] __initdata = KERN_INFO PFX SC1200_MODULE_VER;
+static int timeout = 1;
+static int io = -1;
+static int io_len = 2;		/* for non plug and play */
+static struct semaphore open_sem;
+static char expect_close;
+static spinlock_t sc1200wdt_lock;	/* io port access serialisation */
+
+#if defined CONFIG_PNP
+static int isapnp = 1;
+static struct pnp_dev *wdt_dev;
+
+module_param(isapnp, int, 0);
+MODULE_PARM_DESC(isapnp, "When set to 0 driver ISA PnP support will be disabled");
+#endif
+
+module_param(io, int, 0);
+MODULE_PARM_DESC(io, "io port");
+module_param(timeout, int, 0);
+MODULE_PARM_DESC(timeout, "range is 0-255 minutes, default is 1");
+
+#ifdef CONFIG_WATCHDOG_NOWAYOUT
+static int nowayout = 1;
+#else
+static int nowayout = 0;
+#endif
+
+module_param(nowayout, int, 0);
+MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default=CONFIG_WATCHDOG_NOWAYOUT)");
+
+
+
+/* Read from Data Register */
+static inline void sc1200wdt_read_data(unsigned char index, unsigned char *data)
+{
+	spin_lock(&sc1200wdt_lock);
+	outb_p(index, PMIR);
+	*data = inb(PMDR);
+	spin_unlock(&sc1200wdt_lock);
+}
+
+
+/* Write to Data Register */
+static inline void sc1200wdt_write_data(unsigned char index, unsigned char data)
+{
+	spin_lock(&sc1200wdt_lock);
+	outb_p(index, PMIR);
+	outb(data, PMDR);
+	spin_unlock(&sc1200wdt_lock);
+}
+
+
+static void sc1200wdt_start(void)
+{
+	unsigned char reg;
+
+	sc1200wdt_read_data(WDCF, &reg);
+	/* assert WDO when any of the following interrupts are triggered too */
+	reg |= (KBC_IRQ | MSE_IRQ | UART1_IRQ | UART2_IRQ);
+	sc1200wdt_write_data(WDCF, reg);
+	/* set the timeout and get the ball rolling */
+	sc1200wdt_write_data(WDTO, timeout);
+}
+
+
+static void sc1200wdt_stop(void)
+{
+	sc1200wdt_write_data(WDTO, 0);
+}
+
+
+/* This returns the status of the WDO signal, inactive high. */
+static inline int sc1200wdt_status(void)
+{
+	unsigned char ret;
+
+	sc1200wdt_read_data(WDST, &ret);
+	/* If the bit is inactive, the watchdog is enabled, so return
+	 * KEEPALIVEPING which is a bit of a kludge because there's nothing
+	 * else for enabled/disabled status
+	 */
+	return (ret & 0x01) ? 0 : WDIOF_KEEPALIVEPING;	/* bits 1 - 7 are undefined */
+}
+
+
+static int sc1200wdt_open(struct inode *inode, struct file *file)
+{
+	nonseekable_open(inode, file);
+
+	/* allow one at a time */
+	if (down_trylock(&open_sem))
+		return -EBUSY;
+
+	if (timeout > MAX_TIMEOUT)
+		timeout = MAX_TIMEOUT;
+
+	sc1200wdt_start();
+	printk(KERN_INFO PFX "Watchdog enabled, timeout = %d min(s)", timeout);
+
+	return 0;
+}
+
+
+static int sc1200wdt_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg)
+{
+	int new_timeout;
+	void __user *argp = (void __user *)arg;
+	int __user *p = argp;
+	static struct watchdog_info ident = {
+		.options = WDIOF_KEEPALIVEPING | WDIOF_SETTIMEOUT | WDIOF_MAGICCLOSE,
+		.firmware_version = 0,
+		.identity = "PC87307/PC97307",
+	};
+
+	switch (cmd) {
+		default:
+			return -ENOIOCTLCMD;	/* Keep Pavel Machek amused ;) */
+
+		case WDIOC_GETSUPPORT:
+			if (copy_to_user(argp, &ident, sizeof ident))
+				return -EFAULT;
+			return 0;
+
+		case WDIOC_GETSTATUS:
+			return put_user(sc1200wdt_status(), p);
+
+		case WDIOC_GETBOOTSTATUS:
+			return put_user(0, p);
+
+		case WDIOC_KEEPALIVE:
+			sc1200wdt_write_data(WDTO, timeout);
+			return 0;
+
+		case WDIOC_SETTIMEOUT:
+			if (get_user(new_timeout, p))
+				return -EFAULT;
+
+			/* the API states this is given in secs */
+			new_timeout /= 60;
+			if (new_timeout < 0 || new_timeout > MAX_TIMEOUT)
+				return -EINVAL;
+
+			timeout = new_timeout;
+			sc1200wdt_write_data(WDTO, timeout);
+			/* fall through and return the new timeout */
+
+		case WDIOC_GETTIMEOUT:
+			return put_user(timeout * 60, p);
+
+		case WDIOC_SETOPTIONS:
+		{
+			int options, retval = -EINVAL;
+
+			if (get_user(options, p))
+				return -EFAULT;
+
+			if (options & WDIOS_DISABLECARD) {
+				sc1200wdt_stop();
+				retval = 0;
+			}
+
+			if (options & WDIOS_ENABLECARD) {
+				sc1200wdt_start();
+				retval = 0;
+			}
+
+			return retval;
+		}
+	}
+}
+
+
+static int sc1200wdt_release(struct inode *inode, struct file *file)
+{
+	if (expect_close == 42) {
+		sc1200wdt_stop();
+		printk(KERN_INFO PFX "Watchdog disabled\n");
+	} else {
+		sc1200wdt_write_data(WDTO, timeout);
+		printk(KERN_CRIT PFX "Unexpected close!, timeout = %d min(s)\n", timeout);
+	}
+	up(&open_sem);
+	expect_close = 0;
+
+	return 0;
+}
+
+
+static ssize_t sc1200wdt_write(struct file *file, const char __user *data, size_t len, loff_t *ppos)
+{
+	if (len) {
+		if (!nowayout) {
+			size_t i;
+
+			expect_close = 0;
+
+			for (i = 0; i != len; i++) {
+				char c;
+
+				if (get_user(c, data+i))
+					return -EFAULT;
+				if (c == 'V')
+					expect_close = 42;
+			}
+		}
+
+		sc1200wdt_write_data(WDTO, timeout);
+		return len;
+	}
+
+	return 0;
+}
+
+
+static int sc1200wdt_notify_sys(struct notifier_block *this, unsigned long code, void *unused)
+{
+	if (code == SYS_DOWN || code == SYS_HALT)
+		sc1200wdt_stop();
+
+	return NOTIFY_DONE;
+}
+
+
+static struct notifier_block sc1200wdt_notifier =
+{
+	.notifier_call =	sc1200wdt_notify_sys,
+};
+
+static struct file_operations sc1200wdt_fops =
+{
+	.owner		= THIS_MODULE,
+	.llseek		= no_llseek,
+	.write		= sc1200wdt_write,
+	.ioctl		= sc1200wdt_ioctl,
+	.open		= sc1200wdt_open,
+	.release	= sc1200wdt_release,
+};
+
+static struct miscdevice sc1200wdt_miscdev =
+{
+	.minor		= WATCHDOG_MINOR,
+	.name		= "watchdog",
+	.fops		= &sc1200wdt_fops,
+};
+
+
+static int __init sc1200wdt_probe(void)
+{
+	/* The probe works by reading the PMC3 register's default value of 0x0e
+	 * there is one caveat, if the device disables the parallel port or any
+	 * of the UARTs we won't be able to detect it.
+	 * Nb. This could be done with accuracy by reading the SID registers, but
+	 * we don't have access to those io regions.
+	 */
+
+	unsigned char reg;
+
+	sc1200wdt_read_data(PMC3, &reg);
+	reg &= 0x0f;				/* we don't want the UART busy bits */
+	return (reg == 0x0e) ? 0 : -ENODEV;
+}
+
+
+#if defined CONFIG_PNP
+
+static struct pnp_device_id scl200wdt_pnp_devices[] = {
+	/* National Semiconductor PC87307/PC97307 watchdog component */
+	{.id = "NSC0800", .driver_data = 0},
+	{.id = ""},
+};
+
+static int scl200wdt_pnp_probe(struct pnp_dev * dev, const struct pnp_device_id *dev_id)
+{
+	/* this driver only supports one card at a time */
+	if (wdt_dev || !isapnp)
+		return -EBUSY;
+
+	wdt_dev = dev;
+	io = pnp_port_start(wdt_dev, 0);
+	io_len = pnp_port_len(wdt_dev, 0);
+
+	if (!request_region(io, io_len, SC1200_MODULE_NAME)) {
+		printk(KERN_ERR PFX "Unable to register IO port %#x\n", io);
+		return -EBUSY;
+	}
+
+	printk(KERN_INFO "scl200wdt: PnP device found at io port %#x/%d\n", io, io_len);
+	return 0;
+}
+
+static void scl200wdt_pnp_remove(struct pnp_dev * dev)
+{
+	if (wdt_dev){
+		release_region(io, io_len);
+		wdt_dev = NULL;
+	}
+}
+
+static struct pnp_driver scl200wdt_pnp_driver = {
+	.name		= "scl200wdt",
+	.id_table	= scl200wdt_pnp_devices,
+	.probe		= scl200wdt_pnp_probe,
+	.remove		= scl200wdt_pnp_remove,
+};
+
+#endif /* CONFIG_PNP */
+
+
+static int __init sc1200wdt_init(void)
+{
+	int ret;
+
+	printk(banner);
+
+	spin_lock_init(&sc1200wdt_lock);
+	sema_init(&open_sem, 1);
+
+#if defined CONFIG_PNP
+	if (isapnp) {
+		ret = pnp_register_driver(&scl200wdt_pnp_driver);
+		if (ret)
+			goto out_clean;
+	}
+#endif
+
+	if (io == -1) {
+		printk(KERN_ERR PFX "io parameter must be specified\n");
+		ret = -EINVAL;
+		goto out_clean;
+	}
+
+#if defined CONFIG_PNP
+	/* now that the user has specified an IO port and we haven't detected
+	 * any devices, disable pnp support */
+	isapnp = 0;
+	pnp_unregister_driver(&scl200wdt_pnp_driver);
+#endif
+
+	if (!request_region(io, io_len, SC1200_MODULE_NAME)) {
+		printk(KERN_ERR PFX "Unable to register IO port %#x\n", io);
+		ret = -EBUSY;
+		goto out_clean;
+	}
+
+	ret = sc1200wdt_probe();
+	if (ret)
+		goto out_io;
+
+	ret = register_reboot_notifier(&sc1200wdt_notifier);
+	if (ret) {
+		printk(KERN_ERR PFX "Unable to register reboot notifier err = %d\n", ret);
+		goto out_io;
+	}
+
+	ret = misc_register(&sc1200wdt_miscdev);
+	if (ret) {
+		printk(KERN_ERR PFX "Unable to register miscdev on minor %d\n", WATCHDOG_MINOR);
+		goto out_rbt;
+	}
+
+	/* ret = 0 */
+
+out_clean:
+	return ret;
+
+out_rbt:
+	unregister_reboot_notifier(&sc1200wdt_notifier);
+
+out_io:
+	release_region(io, io_len);
+
+	goto out_clean;
+}
+
+
+static void __exit sc1200wdt_exit(void)
+{
+	misc_deregister(&sc1200wdt_miscdev);
+	unregister_reboot_notifier(&sc1200wdt_notifier);
+
+#if defined CONFIG_PNP
+	if(isapnp)
+		pnp_unregister_driver(&scl200wdt_pnp_driver);
+	else
+#endif
+	release_region(io, io_len);
+}
+
+module_init(sc1200wdt_init);
+module_exit(sc1200wdt_exit);
+
+MODULE_AUTHOR("Zwane Mwaikambo <zwane@commfireservices.com>");
+MODULE_DESCRIPTION("Driver for National Semiconductor PC87307/PC97307 watchdog component");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS_MISCDEV(WATCHDOG_MINOR);
diff --git a/drivers/char/watchdog/sc520_wdt.c b/drivers/char/watchdog/sc520_wdt.c
new file mode 100644
index 0000000..f6d143e
--- /dev/null
+++ b/drivers/char/watchdog/sc520_wdt.c
@@ -0,0 +1,447 @@
+/*
+ *	AMD Elan SC520 processor Watchdog Timer driver
+ *
+ *      Based on acquirewdt.c by Alan Cox,
+ *           and sbc60xxwdt.c by Jakob Oestergaard <jakob@unthought.net>
+ *
+ *	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>
+ *           9/27 - 2001      [Initial release]
+ *
+ *	Additional fixes Alan Cox
+ *	-	Fixed formatting
+ *	-	Removed debug printks
+ *	-	Fixed SMP built kernel deadlock
+ *	-	Switched to private locks not lock_kernel
+ *	-	Used ioremap/writew/readw
+ *	-	Added NOWAYOUT support
+ *	4/12 - 2002 Changes by Rob Radez <rob@osinvestor.com>
+ *	-	Change comments
+ *	-	Eliminate fop_llseek
+ *	-	Change CONFIG_WATCHDOG_NOWAYOUT semantics
+ *	-	Add KERN_* tags to printks
+ *	-	fix possible wdt_is_open race
+ *	-	Report proper capabilities in watchdog_info
+ *	-	Add WDIOC_{GETSTATUS, GETBOOTSTATUS, SETTIMEOUT,
+ *		GETTIMEOUT, SETOPTIONS} ioctls
+ *	09/8 - 2003 Changes by Wim Van Sebroeck <wim@iguana.be>
+ *	-	cleanup of trailing spaces
+ *	-	added extra printk's for startup problems
+ *	-	use module_param
+ *	-	made timeout (the emulated heartbeat) a module_param
+ *	-	made the keepalive ping an internal subroutine
+ *	3/27 - 2004 Changes by Sean Young <sean@mess.org>
+ *	-	set MMCR_BASE to 0xfffef000
+ *	-	CBAR does not need to be read
+ *	-	removed debugging printks
+ *
+ *  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.
+ *
+ *  This driver uses memory mapped IO, and spinlock.
+ */
+
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/types.h>
+#include <linux/timer.h>
+#include <linux/miscdevice.h>
+#include <linux/watchdog.h>
+#include <linux/fs.h>
+#include <linux/ioport.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>
+
+#define OUR_NAME "sc520_wdt"
+#define PFX OUR_NAME ": "
+
+/*
+ * The AMD Elan SC520 timeout value is 492us times a power of 2 (0-7)
+ *
+ *   0: 492us    2: 1.01s    4: 4.03s   6: 16.22s
+ *   1: 503ms    3: 2.01s    5: 8.05s   7: 32.21s
+ *
+ * We will program the SC520 watchdog for a timeout of 2.01s.
+ * 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 WATCHDOG_TIMEOUT 30		/* 30 sec default timeout */
+static int timeout = WATCHDOG_TIMEOUT;	/* in seconds, will be multiplied by HZ to get seconds to wait for a ping */
+module_param(timeout, int, 0);
+MODULE_PARM_DESC(timeout, "Watchdog timeout in seconds. (1<=timeout<=3600, default=" __MODULE_STRING(WATCHDOG_TIMEOUT) ")");
+
+#ifdef CONFIG_WATCHDOG_NOWAYOUT
+static int nowayout = 1;
+#else
+static int nowayout = 0;
+#endif
+
+module_param(nowayout, int, 0);
+MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default=CONFIG_WATCHDOG_NOWAYOUT)");
+
+/*
+ * AMD Elan SC520 - Watchdog Timer Registers
+ */
+#define MMCR_BASE	0xfffef000	/* The default base address */
+#define OFFS_WDTMRCTL	0xCB0	/* Watchdog Timer Control Register */
+
+/* WDT Control Register bit definitions */
+#define WDT_EXP_SEL_01	0x0001	/* [01] Time-out = 496 us (with 33 Mhz clk). */
+#define WDT_EXP_SEL_02	0x0002	/* [02] Time-out = 508 ms (with 33 Mhz clk). */
+#define WDT_EXP_SEL_03	0x0004	/* [03] Time-out = 1.02 s (with 33 Mhz clk). */
+#define WDT_EXP_SEL_04	0x0008	/* [04] Time-out = 2.03 s (with 33 Mhz clk). */
+#define WDT_EXP_SEL_05	0x0010	/* [05] Time-out = 4.07 s (with 33 Mhz clk). */
+#define WDT_EXP_SEL_06	0x0020	/* [06] Time-out = 8.13 s (with 33 Mhz clk). */
+#define WDT_EXP_SEL_07	0x0040	/* [07] Time-out = 16.27s (with 33 Mhz clk). */
+#define WDT_EXP_SEL_08	0x0080	/* [08] Time-out = 32.54s (with 33 Mhz clk). */
+#define WDT_IRQ_FLG	0x1000	/* [12] Interrupt Request Flag */
+#define WDT_WRST_ENB	0x4000	/* [14] Watchdog Timer Reset Enable */
+#define WDT_ENB		0x8000	/* [15] Watchdog Timer Enable */
+
+static __u16 __iomem *wdtmrctl;
+
+static void wdt_timer_ping(unsigned long);
+static struct timer_list timer;
+static unsigned long next_heartbeat;
+static unsigned long wdt_is_open;
+static char 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);
+		writew(0xAAAA, wdtmrctl);
+		writew(0x5555, wdtmrctl);
+		spin_unlock(&wdt_spinlock);
+
+		/* Re-set the timer interval */
+		timer.expires = jiffies + WDT_INTERVAL;
+		add_timer(&timer);
+	} else {
+		printk(KERN_WARNING PFX "Heartbeat lost! Will not ping the watchdog\n");
+	}
+}
+
+/*
+ *	Utility routines
+ */
+
+static void wdt_config(int writeval)
+{
+	__u16 dummy;
+	unsigned long flags;
+
+	/* buy some time (ping) */
+	spin_lock_irqsave(&wdt_spinlock, flags);
+	dummy=readw(wdtmrctl);	/* ensure write synchronization */
+	writew(0xAAAA, wdtmrctl);
+	writew(0x5555, wdtmrctl);
+	/* unlock WDT = make WDT configuration register writable one time */
+	writew(0x3333, wdtmrctl);
+	writew(0xCCCC, wdtmrctl);
+	/* write WDT configuration register */
+	writew(writeval, wdtmrctl);
+	spin_unlock_irqrestore(&wdt_spinlock, flags);
+}
+
+static int wdt_startup(void)
+{
+	next_heartbeat = jiffies + (timeout * HZ);
+
+	/* Start the timer */
+	timer.expires = jiffies + WDT_INTERVAL;
+	add_timer(&timer);
+
+	/* Start the watchdog */
+	wdt_config(WDT_ENB | WDT_WRST_ENB | WDT_EXP_SEL_04);
+
+	printk(KERN_INFO PFX "Watchdog timer is now enabled.\n");
+	return 0;
+}
+
+static int wdt_turnoff(void)
+{
+	/* Stop the timer */
+	del_timer(&timer);
+
+	/* Stop the watchdog */
+	wdt_config(0);
+
+	printk(KERN_INFO PFX "Watchdog timer is now disabled...\n");
+	return 0;
+}
+
+static int wdt_keepalive(void)
+{
+	/* user land ping */
+	next_heartbeat = jiffies + (timeout * HZ);
+	return 0;
+}
+
+static int wdt_set_heartbeat(int t)
+{
+	if ((t < 1) || (t > 3600))	/* arbitrary upper limit */
+		return -EINVAL;
+
+	timeout = t;
+	return 0;
+}
+
+/*
+ *	/dev/watchdog handling
+ */
+
+static ssize_t fop_write(struct file * file, const char __user * buf, size_t count, loff_t * ppos)
+{
+	/* See if we got the magic character 'V' and reload the timer */
+	if(count) {
+		if (!nowayout) {
+			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 = 42;
+			}
+		}
+
+		/* Well, anyhow someone wrote to us, we should return that favour */
+		wdt_keepalive();
+	}
+	return count;
+}
+
+static int fop_open(struct inode * inode, struct file * file)
+{
+	nonseekable_open(inode, file);
+
+	/* Just in case we're already talking to someone... */
+	if(test_and_set_bit(0, &wdt_is_open))
+		return -EBUSY;
+	if (nowayout)
+		__module_get(THIS_MODULE);
+
+	/* Good, fire up the show */
+	wdt_startup();
+	return 0;
+}
+
+static int fop_close(struct inode * inode, struct file * file)
+{
+	if(wdt_expect_close == 42) {
+		wdt_turnoff();
+	} else {
+		printk(KERN_CRIT PFX "Unexpected close, not stopping watchdog!\n");
+		wdt_keepalive();
+	}
+	clear_bit(0, &wdt_is_open);
+	wdt_expect_close = 0;
+	return 0;
+}
+
+static int fop_ioctl(struct inode *inode, struct file *file, unsigned int cmd,
+	unsigned long arg)
+{
+	void __user *argp = (void __user *)arg;
+	int __user *p = argp;
+	static struct watchdog_info ident = {
+		.options = WDIOF_KEEPALIVEPING | WDIOF_SETTIMEOUT | WDIOF_MAGICCLOSE,
+		.firmware_version = 1,
+		.identity = "SC520",
+	};
+
+	switch(cmd)
+	{
+		default:
+			return -ENOIOCTLCMD;
+		case WDIOC_GETSUPPORT:
+			return copy_to_user(argp, &ident, sizeof(ident))?-EFAULT:0;
+		case WDIOC_GETSTATUS:
+		case WDIOC_GETBOOTSTATUS:
+			return put_user(0, p);
+		case WDIOC_KEEPALIVE:
+			wdt_keepalive();
+			return 0;
+		case WDIOC_SETOPTIONS:
+		{
+			int new_options, retval = -EINVAL;
+
+			if(get_user(new_options, p))
+				return -EFAULT;
+
+			if(new_options & WDIOS_DISABLECARD) {
+				wdt_turnoff();
+				retval = 0;
+			}
+
+			if(new_options & WDIOS_ENABLECARD) {
+				wdt_startup();
+				retval = 0;
+			}
+
+			return retval;
+		}
+		case WDIOC_SETTIMEOUT:
+		{
+			int new_timeout;
+
+			if(get_user(new_timeout, p))
+				return -EFAULT;
+
+			if(wdt_set_heartbeat(new_timeout))
+				return -EINVAL;
+
+			wdt_keepalive();
+			/* Fall through */
+		}
+		case WDIOC_GETTIMEOUT:
+			return put_user(timeout, p);
+	}
+}
+
+static struct file_operations wdt_fops = {
+	.owner		= THIS_MODULE,
+	.llseek		= no_llseek,
+	.write		= fop_write,
+	.open		= fop_open,
+	.release	= fop_close,
+	.ioctl		= fop_ioctl,
+};
+
+static struct miscdevice wdt_miscdev = {
+	.minor	= WATCHDOG_MINOR,
+	.name	= "watchdog",
+	.fops	= &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 = {
+	.notifier_call = wdt_notify_sys,
+};
+
+static void __exit sc520_wdt_unload(void)
+{
+	if (!nowayout)
+		wdt_turnoff();
+
+	/* Deregister */
+	misc_deregister(&wdt_miscdev);
+	unregister_reboot_notifier(&wdt_notifier);
+	iounmap(wdtmrctl);
+}
+
+static int __init sc520_wdt_init(void)
+{
+	int rc = -EBUSY;
+
+	spin_lock_init(&wdt_spinlock);
+
+	init_timer(&timer);
+	timer.function = wdt_timer_ping;
+	timer.data = 0;
+
+	/* Check that the timeout value is within it's range ; if not reset to the default */
+	if (wdt_set_heartbeat(timeout)) {
+		wdt_set_heartbeat(WATCHDOG_TIMEOUT);
+		printk(KERN_INFO PFX "timeout value must be 1<=timeout<=3600, using %d\n",
+			WATCHDOG_TIMEOUT);
+	}
+
+	wdtmrctl = ioremap((unsigned long)(MMCR_BASE + OFFS_WDTMRCTL), 2);
+	if (!wdtmrctl) {
+		printk(KERN_ERR PFX "Unable to remap memory\n");
+		rc = -ENOMEM;
+		goto err_out_region2;
+	}
+
+	rc = register_reboot_notifier(&wdt_notifier);
+	if (rc) {
+		printk(KERN_ERR PFX "cannot register reboot notifier (err=%d)\n",
+			rc);
+		goto err_out_ioremap;
+	}
+
+	rc = misc_register(&wdt_miscdev);
+	if (rc) {
+		printk(KERN_ERR PFX "cannot register miscdev on minor=%d (err=%d)\n",
+			WATCHDOG_MINOR, rc);
+		goto err_out_notifier;
+	}
+
+	printk(KERN_INFO PFX "WDT driver for SC520 initialised. timeout=%d sec (nowayout=%d)\n",
+		timeout,nowayout);
+
+	return 0;
+
+err_out_notifier:
+	unregister_reboot_notifier(&wdt_notifier);
+err_out_ioremap:
+	iounmap(wdtmrctl);
+err_out_region2:
+	return rc;
+}
+
+module_init(sc520_wdt_init);
+module_exit(sc520_wdt_unload);
+
+MODULE_AUTHOR("Scott and Bill Jennings");
+MODULE_DESCRIPTION("Driver for watchdog timer in AMD \"Elan\" SC520 uProcessor");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS_MISCDEV(WATCHDOG_MINOR);
diff --git a/drivers/char/watchdog/scx200_wdt.c b/drivers/char/watchdog/scx200_wdt.c
new file mode 100644
index 0000000..b569670
--- /dev/null
+++ b/drivers/char/watchdog/scx200_wdt.c
@@ -0,0 +1,274 @@
+/* drivers/char/watchdog/scx200_wdt.c
+
+   National Semiconductor SCx200 Watchdog support
+
+   Copyright (c) 2001,2002 Christer Weinigel <wingel@nano-system.com>
+
+   Some 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/moduleparam.h>
+#include <linux/init.h>
+#include <linux/miscdevice.h>
+#include <linux/watchdog.h>
+#include <linux/notifier.h>
+#include <linux/reboot.h>
+#include <linux/fs.h>
+#include <linux/pci.h>
+#include <linux/scx200.h>
+
+#include <asm/uaccess.h>
+#include <asm/io.h>
+
+#define NAME "scx200_wdt"
+
+MODULE_AUTHOR("Christer Weinigel <wingel@nano-system.com>");
+MODULE_DESCRIPTION("NatSemi SCx200 Watchdog Driver");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS_MISCDEV(WATCHDOG_MINOR);
+
+#ifndef CONFIG_WATCHDOG_NOWAYOUT
+#define CONFIG_WATCHDOG_NOWAYOUT 0
+#endif
+
+static int margin = 60;		/* in seconds */
+module_param(margin, int, 0);
+MODULE_PARM_DESC(margin, "Watchdog margin in seconds");
+
+static int nowayout = CONFIG_WATCHDOG_NOWAYOUT;
+module_param(nowayout, int, 0);
+MODULE_PARM_DESC(nowayout, "Disable watchdog shutdown on close");
+
+static u16 wdto_restart;
+static struct semaphore open_semaphore;
+static char 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();
+
+	return nonseekable_open(inode, file);
+}
+
+static int scx200_wdt_release(struct inode *inode, struct file *file)
+{
+	if (expect_close != 42) {
+		printk(KERN_WARNING NAME ": watchdog device closed unexpectedly, will not disable the watchdog timer\n");
+	} else if (!nowayout) {
+		scx200_wdt_disable();
+	}
+	expect_close = 0;
+	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 __user *data,
+				     size_t len, loff_t *ppos)
+{
+	/* 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 = 42;
+		}
+
+		return len;
+	}
+
+	return 0;
+}
+
+static int scx200_wdt_ioctl(struct inode *inode, struct file *file,
+	unsigned int cmd, unsigned long arg)
+{
+	void __user *argp = (void __user *)arg;
+	int __user *p = argp;
+	static struct watchdog_info ident = {
+		.identity = "NatSemi SCx200 Watchdog",
+		.firmware_version = 1,
+		.options = (WDIOF_SETTIMEOUT | WDIOF_KEEPALIVEPING),
+	};
+	int new_margin;
+
+	switch (cmd) {
+	default:
+		return -ENOIOCTLCMD;
+	case WDIOC_GETSUPPORT:
+		if(copy_to_user(argp, &ident, sizeof(ident)))
+			return -EFAULT;
+		return 0;
+	case WDIOC_GETSTATUS:
+	case WDIOC_GETBOOTSTATUS:
+		if (put_user(0, p))
+			return -EFAULT;
+		return 0;
+	case WDIOC_KEEPALIVE:
+		scx200_wdt_ping();
+		return 0;
+	case WDIOC_SETTIMEOUT:
+		if (get_user(new_margin, p))
+			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, p))
+			return -EFAULT;
+		return 0;
+	}
+}
+
+static struct file_operations scx200_wdt_fops = {
+	.owner	 = THIS_MODULE,
+	.llseek	 = no_llseek,
+	.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");
+
+	/* check that we have found the configuration block */
+	if (!scx200_cb_present())
+		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) {
+		release_region(scx200_cb_base + SCx200_WDT_OFFSET,
+				SCx200_WDT_SIZE);
+		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);
+		release_region(scx200_cb_base + SCx200_WDT_OFFSET,
+				SCx200_WDT_SIZE);
+		return r;
+	}
+
+	return 0;
+}
+
+static void __exit scx200_wdt_cleanup(void)
+{
+	unregister_reboot_notifier(&scx200_wdt_notifier);
+	misc_deregister(&scx200_wdt_miscdev);
+	release_region(scx200_cb_base + SCx200_WDT_OFFSET,
+		       SCx200_WDT_SIZE);
+}
+
+module_init(scx200_wdt_init);
+module_exit(scx200_wdt_cleanup);
+
+/*
+    Local variables:
+        compile-command: "make -k -C ../.. SUBDIRS=drivers/char modules"
+        c-basic-offset: 8
+    End:
+*/
diff --git a/drivers/char/watchdog/shwdt.c b/drivers/char/watchdog/shwdt.c
new file mode 100644
index 0000000..3bc9272
--- /dev/null
+++ b/drivers/char/watchdog/shwdt.c
@@ -0,0 +1,452 @@
+/*
+ * drivers/char/watchdog/shwdt.c
+ *
+ * Watchdog driver for integrated watchdog in the SuperH processors.
+ *
+ * Copyright (C) 2001, 2002, 2003 Paul Mundt <lethal@linux-sh.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-Apr-2002 Rob Radez <rob@osinvestor.com>
+ *     Added expect close support, made emulated timeout runtime changeable
+ *     general cleanups, add some ioctls
+ */
+#include <linux/config.h>
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/init.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 <linux/fs.h>
+
+#include <asm/io.h>
+#include <asm/uaccess.h>
+#include <asm/watchdog.h>
+
+#define PFX "shwdt: "
+
+/*
+ * Default clock division ratio is 5.25 msecs. For an additional table of
+ * values, consult the asm-sh/watchdog.h. Overload this at module load
+ * time.
+ *
+ * In order for this to work reliably we need to have HZ set to 1000 or
+ * something quite higher than 100 (or we need a proper high-res timer
+ * implementation that will deal with this properly), otherwise the 10ms
+ * resolution of a jiffy is enough to trigger the overflow. For things like
+ * the SH-4 and SH-5, this isn't necessarily that big of a problem, though
+ * for the SH-2 and SH-3, this isn't recommended unless the WDT is absolutely
+ * necssary.
+ *
+ * As a result of this timing problem, the only modes that are particularly
+ * feasible are the 4096 and the 2048 divisors, which yeild 5.25 and 2.62ms
+ * overflow periods respectively.
+ *
+ * Also, since we can't really expect userspace to be responsive enough
+ * before the overflow happens, we maintain two seperate timers .. One in
+ * the kernel for clearing out WOVF every 2ms or so (again, this depends on
+ * HZ == 1000), and another for monitoring userspace writes to the WDT device.
+ *
+ * As such, we currently use a configurable heartbeat interval which defaults
+ * to 30s. In this case, the userspace daemon is only responsible for periodic
+ * writes to the device before the next heartbeat is scheduled. If the daemon
+ * misses its deadline, the kernel timer will allow the WDT to overflow.
+ */
+static int clock_division_ratio = WTCSR_CKS_4096;
+
+#define next_ping_period(cks)	msecs_to_jiffies(cks - 4)
+
+static unsigned long shwdt_is_open;
+static struct watchdog_info sh_wdt_info;
+static char shwdt_expect_close;
+static struct timer_list timer;
+static unsigned long next_heartbeat;
+
+#define WATCHDOG_HEARTBEAT 30			/* 30 sec default heartbeat */
+static int heartbeat = WATCHDOG_HEARTBEAT;	/* in seconds */
+
+#ifdef CONFIG_WATCHDOG_NOWAYOUT
+static int nowayout = 1;
+#else
+static int nowayout = 0;
+#endif
+
+/**
+ * 	sh_wdt_start - Start the Watchdog
+ *
+ * 	Starts the watchdog.
+ */
+static void sh_wdt_start(void)
+{
+	__u8 csr;
+
+	next_heartbeat = jiffies + (heartbeat * HZ);
+	mod_timer(&timer, next_ping_period(clock_division_ratio));
+
+	csr = sh_wdt_read_csr();
+	csr |= WTCSR_WT | clock_division_ratio;
+	sh_wdt_write_csr(csr);
+
+	sh_wdt_write_cnt(0);
+
+	/*
+	 * These processors have a bit of an inconsistent initialization
+	 * process.. starting with SH-3, RSTS was moved to WTCSR, and the
+	 * RSTCSR register was removed.
+	 *
+	 * On the SH-2 however, in addition with bits being in different
+	 * locations, we must deal with RSTCSR outright..
+	 */
+	csr = sh_wdt_read_csr();
+	csr |= WTCSR_TME;
+	csr &= ~WTCSR_RSTS;
+	sh_wdt_write_csr(csr);
+
+#ifdef CONFIG_CPU_SH2
+	/*
+	 * Whoever came up with the RSTCSR semantics must've been smoking
+	 * some of the good stuff, since in addition to the WTCSR/WTCNT write
+	 * brain-damage, it's managed to fuck things up one step further..
+	 *
+	 * If we need to clear the WOVF bit, the upper byte has to be 0xa5..
+	 * but if we want to touch RSTE or RSTS, the upper byte has to be
+	 * 0x5a..
+	 */
+	csr = sh_wdt_read_rstcsr();
+	csr &= ~RSTCSR_RSTS;
+	sh_wdt_write_rstcsr(csr);
+#endif
+}
+
+/**
+ * 	sh_wdt_stop - Stop the Watchdog
+ *
+ * 	Stops the watchdog.
+ */
+static void sh_wdt_stop(void)
+{
+	__u8 csr;
+
+	del_timer(&timer);
+
+	csr = sh_wdt_read_csr();
+	csr &= ~WTCSR_TME;
+	sh_wdt_write_csr(csr);
+}
+
+/**
+ * 	sh_wdt_keepalive - Keep the Userspace Watchdog Alive
+ *
+ * 	The Userspace watchdog got a KeepAlive: schedule the next heartbeat.
+ */
+static void sh_wdt_keepalive(void)
+{
+	next_heartbeat = jiffies + (heartbeat * HZ);
+}
+
+/**
+ * 	sh_wdt_set_heartbeat - Set the Userspace Watchdog heartbeat
+ *
+ * 	Set the Userspace Watchdog heartbeat
+ */
+static int sh_wdt_set_heartbeat(int t)
+{
+	if ((t < 1) || (t > 3600)) /* arbitrary upper limit */
+		return -EINVAL;
+
+	heartbeat = t;
+	return 0;
+}
+
+/**
+ * 	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)) {
+		__u8 csr;
+
+		csr = sh_wdt_read_csr();
+		csr &= ~WTCSR_IOVF;
+		sh_wdt_write_csr(csr);
+
+		sh_wdt_write_cnt(0);
+
+		mod_timer(&timer, next_ping_period(clock_division_ratio));
+	} else {
+		printk(KERN_WARNING PFX "Heartbeat lost! Will not ping the watchdog\n");
+	}
+}
+
+/**
+ * 	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)
+{
+	if (test_and_set_bit(0, &shwdt_is_open))
+		return -EBUSY;
+	if (nowayout)
+		__module_get(THIS_MODULE);
+
+	sh_wdt_start();
+
+	return nonseekable_open(inode, file);
+}
+
+/**
+ * 	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 (shwdt_expect_close == 42) {
+		sh_wdt_stop();
+	} else {
+		printk(KERN_CRIT PFX "Unexpected close, not stopping watchdog!\n");
+		sh_wdt_keepalive();
+	}
+
+	clear_bit(0, &shwdt_is_open);
+	shwdt_expect_close = 0;
+
+	return 0;
+}
+
+/**
+ * 	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)
+{
+	if (count) {
+		if (!nowayout) {
+			size_t i;
+
+			shwdt_expect_close = 0;
+
+			for (i = 0; i != count; i++) {
+				char c;
+				if (get_user(c, buf + i))
+					return -EFAULT;
+				if (c == 'V')
+					shwdt_expect_close = 42;
+			}
+		}
+		sh_wdt_keepalive();
+	}
+
+	return count;
+}
+
+/**
+ * 	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)
+{
+	int new_heartbeat;
+	int options, retval = -EINVAL;
+
+	switch (cmd) {
+		case WDIOC_GETSUPPORT:
+			return copy_to_user((struct watchdog_info *)arg,
+					  &sh_wdt_info,
+					  sizeof(sh_wdt_info)) ? -EFAULT : 0;
+		case WDIOC_GETSTATUS:
+		case WDIOC_GETBOOTSTATUS:
+			return put_user(0, (int *)arg);
+		case WDIOC_KEEPALIVE:
+			sh_wdt_keepalive();
+			return 0;
+		case WDIOC_SETTIMEOUT:
+			if (get_user(new_heartbeat, (int *)arg))
+				return -EFAULT;
+
+			if (sh_wdt_set_heartbeat(new_heartbeat))
+				return -EINVAL;
+
+			sh_wdt_keepalive();
+			/* Fall */
+		case WDIOC_GETTIMEOUT:
+			return put_user(heartbeat, (int *)arg);
+		case WDIOC_SETOPTIONS:
+			if (get_user(options, (int *)arg))
+				return -EFAULT;
+
+			if (options & WDIOS_DISABLECARD) {
+				sh_wdt_stop();
+				retval = 0;
+			}
+
+			if (options & WDIOS_ENABLECARD) {
+				sh_wdt_start();
+				retval = 0;
+			}
+
+			return retval;
+		default:
+			return -ENOIOCTLCMD;
+	}
+
+	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,
+	.llseek		= no_llseek,
+	.write		= sh_wdt_write,
+	.ioctl		= sh_wdt_ioctl,
+	.open		= sh_wdt_open,
+	.release	= sh_wdt_close,
+};
+
+static struct watchdog_info sh_wdt_info = {
+	.options		= WDIOF_KEEPALIVEPING | WDIOF_SETTIMEOUT | WDIOF_MAGICCLOSE,
+	.firmware_version	= 1,
+	.identity		= "SH WDT",
+};
+
+static struct notifier_block sh_wdt_notifier = {
+	.notifier_call		= sh_wdt_notify_sys,
+};
+
+static struct miscdevice sh_wdt_miscdev = {
+	.minor		= WATCHDOG_MINOR,
+	.name		= "watchdog",
+	.fops		= &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)
+{
+	int rc;
+
+	if ((clock_division_ratio < 0x5) || (clock_division_ratio > 0x7)) {
+		clock_division_ratio = WTCSR_CKS_4096;
+		printk(KERN_INFO PFX "clock_division_ratio value must be 0x5<=x<=0x7, using %d\n",
+			clock_division_ratio);
+	}
+
+	if (sh_wdt_set_heartbeat(heartbeat))
+	{
+		heartbeat = WATCHDOG_HEARTBEAT;
+		printk(KERN_INFO PFX "heartbeat value must be 1<=x<=3600, using %d\n",
+			heartbeat);
+	}
+
+	init_timer(&timer);
+	timer.function = sh_wdt_ping;
+	timer.data = 0;
+
+	rc = register_reboot_notifier(&sh_wdt_notifier);
+	if (rc) {
+		printk(KERN_ERR PFX "Can't register reboot notifier (err=%d)\n", rc);
+		return rc;
+	}
+
+	rc = misc_register(&sh_wdt_miscdev);
+	if (rc) {
+		printk(KERN_ERR PFX "Can't register miscdev on minor=%d (err=%d)\n",
+			sh_wdt_miscdev.minor, rc);
+		unregister_reboot_notifier(&sh_wdt_notifier);
+		return rc;
+	}
+
+	printk(KERN_INFO PFX "initialized. heartbeat=%d sec (nowayout=%d)\n",
+		heartbeat, nowayout);
+
+	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)
+{
+	misc_deregister(&sh_wdt_miscdev);
+	unregister_reboot_notifier(&sh_wdt_notifier);
+}
+
+MODULE_AUTHOR("Paul Mundt <lethal@linux-sh.org>");
+MODULE_DESCRIPTION("SuperH watchdog driver");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS_MISCDEV(WATCHDOG_MINOR);
+
+module_param(clock_division_ratio, int, 0);
+MODULE_PARM_DESC(clock_division_ratio, "Clock division ratio. Valid ranges are from 0x5 (1.31ms) to 0x7 (5.25ms). Defaults to 0x7.");
+
+module_param(heartbeat, int, 0);
+MODULE_PARM_DESC(heartbeat, "Watchdog heartbeat in seconds. (1<=heartbeat<=3600, default=" __MODULE_STRING(WATCHDOG_HEARTBEAT) ")");
+
+module_param(nowayout, int, 0);
+MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default=CONFIG_WATCHDOG_NOWAYOUT)");
+
+module_init(sh_wdt_init);
+module_exit(sh_wdt_exit);
+
diff --git a/drivers/char/watchdog/softdog.c b/drivers/char/watchdog/softdog.c
new file mode 100644
index 0000000..11790349
--- /dev/null
+++ b/drivers/char/watchdog/softdog.c
@@ -0,0 +1,309 @@
+/*
+ *	SoftDog	0.07:	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
+ *
+ *  20011127 Joel Becker (jlbec@evilplan.org>
+ *	Added soft_noboot; Allows testing the softdog trigger without
+ *	requiring a recompile.
+ *	Added WDIOC_GETTIMEOUT and WDIOC_SETTIMOUT.
+ *
+ *  20020530 Joel Becker <joel.becker@oracle.com>
+ *  	Added Matt Domsch's nowayout module option.
+ */
+
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/config.h>
+#include <linux/types.h>
+#include <linux/timer.h>
+#include <linux/miscdevice.h>
+#include <linux/watchdog.h>
+#include <linux/fs.h>
+#include <linux/notifier.h>
+#include <linux/reboot.h>
+#include <linux/init.h>
+#include <asm/uaccess.h>
+
+#define PFX "SoftDog: "
+
+#define TIMER_MARGIN	60		/* Default is 60 seconds */
+static int soft_margin = TIMER_MARGIN;	/* in seconds */
+module_param(soft_margin, int, 0);
+MODULE_PARM_DESC(soft_margin, "Watchdog soft_margin in seconds. (0<soft_margin<65536, default=" __MODULE_STRING(TIMER_MARGIN) ")");
+
+#ifdef CONFIG_WATCHDOG_NOWAYOUT
+static int nowayout = 1;
+#else
+static int nowayout = 0;
+#endif
+
+module_param(nowayout, int, 0);
+MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default=CONFIG_WATCHDOG_NOWAYOUT)");
+
+#ifdef ONLY_TESTING
+static int soft_noboot = 1;
+#else
+static int soft_noboot = 0;
+#endif  /* ONLY_TESTING */
+
+module_param(soft_noboot, int, 0);
+MODULE_PARM_DESC(soft_noboot, "Softdog action, set to 1 to ignore reboots, 0 to reboot (default depends on ONLY_TESTING)");
+
+/*
+ *	Our timer
+ */
+
+static void watchdog_fire(unsigned long);
+
+static struct timer_list watchdog_ticktock =
+		TIMER_INITIALIZER(watchdog_fire, 0, 0);
+static unsigned long timer_alive;
+static char expect_close;
+
+
+/*
+ *	If the timer expires..
+ */
+
+static void watchdog_fire(unsigned long data)
+{
+	if (soft_noboot)
+		printk(KERN_CRIT PFX "Triggered - Reboot ignored.\n");
+	else
+	{
+		printk(KERN_CRIT PFX "Initiating system reboot.\n");
+		machine_restart(NULL);
+		printk(KERN_CRIT PFX "Reboot didn't ?????\n");
+	}
+}
+
+/*
+ *	Softdog operations
+ */
+
+static int softdog_keepalive(void)
+{
+	mod_timer(&watchdog_ticktock, jiffies+(soft_margin*HZ));
+	return 0;
+}
+
+static int softdog_stop(void)
+{
+	del_timer(&watchdog_ticktock);
+	return 0;
+}
+
+static int softdog_set_heartbeat(int t)
+{
+	if ((t < 0x0001) || (t > 0xFFFF))
+		return -EINVAL;
+
+	soft_margin = t;
+	return 0;
+}
+
+/*
+ *	/dev/watchdog handling
+ */
+
+static int softdog_open(struct inode *inode, struct file *file)
+{
+	if(test_and_set_bit(0, &timer_alive))
+		return -EBUSY;
+	if (nowayout)
+		__module_get(THIS_MODULE);
+	/*
+	 *	Activate timer
+	 */
+	softdog_keepalive();
+	return nonseekable_open(inode, file);
+}
+
+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 (expect_close == 42) {
+		softdog_stop();
+	} else {
+		printk(KERN_CRIT PFX "Unexpected close, not stopping watchdog!\n");
+		softdog_keepalive();
+	}
+	clear_bit(0, &timer_alive);
+	expect_close = 0;
+	return 0;
+}
+
+static ssize_t softdog_write(struct file *file, const char __user *data, size_t len, loff_t *ppos)
+{
+	/*
+	 *	Refresh the timer.
+	 */
+	if(len) {
+		if (!nowayout) {
+			size_t i;
+
+			/* In case it was set long ago */
+			expect_close = 0;
+
+			for (i = 0; i != len; i++) {
+				char c;
+
+				if (get_user(c, data + i))
+					return -EFAULT;
+				if (c == 'V')
+					expect_close = 42;
+			}
+		}
+		softdog_keepalive();
+	}
+	return len;
+}
+
+static int softdog_ioctl(struct inode *inode, struct file *file,
+	unsigned int cmd, unsigned long arg)
+{
+	void __user *argp = (void __user *)arg;
+	int __user *p = argp;
+	int new_margin;
+	static struct watchdog_info ident = {
+		.options =		WDIOF_SETTIMEOUT |
+					WDIOF_KEEPALIVEPING |
+					WDIOF_MAGICCLOSE,
+		.firmware_version =	0,
+		.identity =		"Software Watchdog",
+	};
+	switch (cmd) {
+		default:
+			return -ENOIOCTLCMD;
+		case WDIOC_GETSUPPORT:
+			return copy_to_user(argp, &ident,
+				sizeof(ident)) ? -EFAULT : 0;
+		case WDIOC_GETSTATUS:
+		case WDIOC_GETBOOTSTATUS:
+			return put_user(0, p);
+		case WDIOC_KEEPALIVE:
+			softdog_keepalive();
+			return 0;
+		case WDIOC_SETTIMEOUT:
+			if (get_user(new_margin, p))
+				return -EFAULT;
+			if (softdog_set_heartbeat(new_margin))
+				return -EINVAL;
+			softdog_keepalive();
+			/* Fall */
+		case WDIOC_GETTIMEOUT:
+			return put_user(soft_margin, p);
+	}
+}
+
+/*
+ *	Notifier for system down
+ */
+
+static int softdog_notify_sys(struct notifier_block *this, unsigned long code,
+	void *unused)
+{
+	if(code==SYS_DOWN || code==SYS_HALT) {
+		/* Turn the WDT off */
+		softdog_stop();
+	}
+	return NOTIFY_DONE;
+}
+
+/*
+ *	Kernel Interfaces
+ */
+
+static struct file_operations softdog_fops = {
+	.owner		= THIS_MODULE,
+	.llseek		= no_llseek,
+	.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 struct notifier_block softdog_notifier = {
+	.notifier_call	= softdog_notify_sys,
+};
+
+static char banner[] __initdata = KERN_INFO "Software Watchdog Timer: 0.07 initialized. soft_noboot=%d soft_margin=%d sec (nowayout= %d)\n";
+
+static int __init watchdog_init(void)
+{
+	int ret;
+
+	/* Check that the soft_margin value is within it's range ; if not reset to the default */
+	if (softdog_set_heartbeat(soft_margin)) {
+		softdog_set_heartbeat(TIMER_MARGIN);
+		printk(KERN_INFO PFX "soft_margin value must be 0<soft_margin<65536, using %d\n",
+			TIMER_MARGIN);
+	}
+
+	ret = register_reboot_notifier(&softdog_notifier);
+	if (ret) {
+		printk (KERN_ERR PFX "cannot register reboot notifier (err=%d)\n",
+			ret);
+		return ret;
+	}
+
+	ret = misc_register(&softdog_miscdev);
+	if (ret) {
+		printk (KERN_ERR PFX "cannot register miscdev on minor=%d (err=%d)\n",
+			WATCHDOG_MINOR, ret);
+		unregister_reboot_notifier(&softdog_notifier);
+		return ret;
+	}
+
+	printk(banner, soft_noboot, soft_margin, nowayout);
+
+	return 0;
+}
+
+static void __exit watchdog_exit(void)
+{
+	misc_deregister(&softdog_miscdev);
+	unregister_reboot_notifier(&softdog_notifier);
+}
+
+module_init(watchdog_init);
+module_exit(watchdog_exit);
+
+MODULE_AUTHOR("Alan Cox");
+MODULE_DESCRIPTION("Software Watchdog Device Driver");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS_MISCDEV(WATCHDOG_MINOR);
diff --git a/drivers/char/watchdog/w83627hf_wdt.c b/drivers/char/watchdog/w83627hf_wdt.c
new file mode 100644
index 0000000..813c970
--- /dev/null
+++ b/drivers/char/watchdog/w83627hf_wdt.c
@@ -0,0 +1,362 @@
+/*
+ *	w83627hf WDT driver
+ *
+ *	(c) Copyright 2003 Pádraig Brady <P@draigBrady.com>
+ *
+ *	Based on advantechwdt.c which is based on wdt.c.
+ *	Original copyright messages:
+ *
+ *	(c) Copyright 2000-2001 Marek Michalkiewicz <marekm@linux.org.pl>
+ *
+ *	(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>
+ */
+
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/types.h>
+#include <linux/miscdevice.h>
+#include <linux/watchdog.h>
+#include <linux/fs.h>
+#include <linux/ioport.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>
+
+#define WATCHDOG_NAME "w83627hf WDT"
+#define PFX WATCHDOG_NAME ": "
+#define WATCHDOG_TIMEOUT 60		/* 60 sec default timeout */
+
+static unsigned long wdt_is_open;
+static char expect_close;
+
+/* You must set this - there is no sane way to probe for this board. */
+static int wdt_io = 0x2E;
+module_param(wdt_io, int, 0);
+MODULE_PARM_DESC(wdt_io, "w83627hf WDT io port (default 0x2E)");
+
+static int timeout = WATCHDOG_TIMEOUT;	/* in seconds */
+module_param(timeout, int, 0);
+MODULE_PARM_DESC(timeout, "Watchdog timeout in seconds. 1<= timeout <=63, default=" __MODULE_STRING(WATCHDOG_TIMEOUT) ".");
+
+#ifdef CONFIG_WATCHDOG_NOWAYOUT
+static int nowayout = 1;
+#else
+static int nowayout = 0;
+#endif
+
+module_param(nowayout, int, 0);
+MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default=CONFIG_WATCHDOG_NOWAYOUT)");
+
+/*
+ *	Kernel methods.
+ */
+
+#define WDT_EFER (wdt_io+0)   /* Extended Function Enable Registers */
+#define WDT_EFIR (wdt_io+0)   /* Extended Function Index Register (same as EFER) */
+#define WDT_EFDR (WDT_EFIR+1) /* Extended Function Data Register */
+
+static void
+w83627hf_select_wd_register(void)
+{
+	outb_p(0x87, WDT_EFER); /* Enter extended function mode */
+	outb_p(0x87, WDT_EFER); /* Again according to manual */
+
+	outb_p(0x07, WDT_EFER); /* point to logical device number reg */
+	outb_p(0x08, WDT_EFDR); /* select logical device 8 (GPIO2) */
+	outb_p(0x30, WDT_EFER); /* select CR30 */
+	outb_p(0x01, WDT_EFDR); /* set bit 0 to activate GPIO2 */
+}
+
+static void
+w83627hf_unselect_wd_register(void)
+{
+	outb_p(0xAA, WDT_EFER); /* Leave extended function mode */
+}
+
+/* tyan motherboards seem to set F5 to 0x4C ?
+ * So explicitly init to appropriate value. */
+static void
+w83627hf_init(void)
+{
+	unsigned char t;
+
+	w83627hf_select_wd_register();
+
+	outb_p(0xF5, WDT_EFER); /* Select CRF5 */
+	t=inb_p(WDT_EFDR);      /* read CRF5 */
+	t&=~0x0C;               /* set second mode & disable keyboard turning off watchdog */
+	outb_p(t, WDT_EFDR);    /* Write back to CRF5 */
+
+	w83627hf_unselect_wd_register();
+}
+
+static void
+wdt_ctrl(int timeout)
+{
+	w83627hf_select_wd_register();
+
+	outb_p(0xF6, WDT_EFER);    /* Select CRF6 */
+	outb_p(timeout, WDT_EFDR); /* Write Timeout counter to CRF6 */
+
+	w83627hf_unselect_wd_register();
+}
+
+static int
+wdt_ping(void)
+{
+	wdt_ctrl(timeout);
+	return 0;
+}
+
+static int
+wdt_disable(void)
+{
+	wdt_ctrl(0);
+	return 0;
+}
+
+static int
+wdt_set_heartbeat(int t)
+{
+	if ((t < 1) || (t > 63))
+		return -EINVAL;
+
+	timeout = t;
+	return 0;
+}
+
+static ssize_t
+wdt_write(struct file *file, const char __user *buf, size_t count, loff_t *ppos)
+{
+	if (count) {
+		if (!nowayout) {
+			size_t i;
+
+			expect_close = 0;
+
+			for (i = 0; i != count; i++) {
+				char c;
+				if (get_user(c, buf+i))
+					return -EFAULT;
+				if (c == 'V')
+					expect_close = 42;
+			}
+		}
+		wdt_ping();
+	}
+	return count;
+}
+
+static int
+wdt_ioctl(struct inode *inode, struct file *file, unsigned int cmd,
+	  unsigned long arg)
+{
+	void __user *argp = (void __user *)arg;
+	int __user *p = argp;
+	int new_timeout;
+	static struct watchdog_info ident = {
+		.options = WDIOF_KEEPALIVEPING | WDIOF_SETTIMEOUT | WDIOF_MAGICCLOSE,
+		.firmware_version = 1,
+		.identity = "W83627HF WDT",
+	};
+
+	switch (cmd) {
+	case WDIOC_GETSUPPORT:
+	  if (copy_to_user(argp, &ident, sizeof(ident)))
+	    return -EFAULT;
+	  break;
+
+	case WDIOC_GETSTATUS:
+	case WDIOC_GETBOOTSTATUS:
+	  return put_user(0, p);
+
+	case WDIOC_KEEPALIVE:
+	  wdt_ping();
+	  break;
+
+	case WDIOC_SETTIMEOUT:
+	  if (get_user(new_timeout, p))
+		  return -EFAULT;
+	  if (wdt_set_heartbeat(new_timeout))
+		  return -EINVAL;
+	  wdt_ping();
+	  /* Fall */
+
+	case WDIOC_GETTIMEOUT:
+	  return put_user(timeout, p);
+
+	case WDIOC_SETOPTIONS:
+	{
+	  int options, retval = -EINVAL;
+
+	  if (get_user(options, p))
+	    return -EFAULT;
+
+	  if (options & WDIOS_DISABLECARD) {
+	    wdt_disable();
+	    retval = 0;
+	  }
+
+	  if (options & WDIOS_ENABLECARD) {
+	    wdt_ping();
+	    retval = 0;
+	  }
+
+	  return retval;
+	}
+
+	default:
+	  return -ENOIOCTLCMD;
+	}
+	return 0;
+}
+
+static int
+wdt_open(struct inode *inode, struct file *file)
+{
+	if (test_and_set_bit(0, &wdt_is_open))
+		return -EBUSY;
+	/*
+	 *	Activate
+	 */
+
+	wdt_ping();
+	return nonseekable_open(inode, file);
+}
+
+static int
+wdt_close(struct inode *inode, struct file *file)
+{
+	if (expect_close == 42) {
+		wdt_disable();
+	} else {
+		printk(KERN_CRIT PFX "Unexpected close, not stopping watchdog!\n");
+		wdt_ping();
+	}
+	expect_close = 0;
+	clear_bit(0, &wdt_is_open);
+	return 0;
+}
+
+/*
+ *	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) {
+		/* Turn the WDT off */
+		wdt_disable();
+	}
+	return NOTIFY_DONE;
+}
+
+/*
+ *	Kernel Interfaces
+ */
+
+static struct file_operations wdt_fops = {
+	.owner		= THIS_MODULE,
+	.llseek		= no_llseek,
+	.write		= wdt_write,
+	.ioctl		= wdt_ioctl,
+	.open		= wdt_open,
+	.release	= wdt_close,
+};
+
+static struct miscdevice wdt_miscdev = {
+	.minor = WATCHDOG_MINOR,
+	.name = "watchdog",
+	.fops = &wdt_fops,
+};
+
+/*
+ *	The WDT needs to learn about soft shutdowns in order to
+ *	turn the timebomb registers off.
+ */
+
+static struct notifier_block wdt_notifier = {
+	.notifier_call = wdt_notify_sys,
+};
+
+static int __init
+wdt_init(void)
+{
+	int ret;
+
+	printk(KERN_INFO "WDT driver for the Winbond(TM) W83627HF Super I/O chip initialising.\n");
+
+	if (wdt_set_heartbeat(timeout)) {
+		wdt_set_heartbeat(WATCHDOG_TIMEOUT);
+		printk (KERN_INFO PFX "timeout value must be 1<=timeout<=63, using %d\n",
+			WATCHDOG_TIMEOUT);
+	}
+
+	if (!request_region(wdt_io, 1, WATCHDOG_NAME)) {
+		printk (KERN_ERR PFX "I/O address 0x%04x already in use\n",
+			wdt_io);
+		ret = -EIO;
+		goto out;
+	}
+
+	w83627hf_init();
+
+	ret = register_reboot_notifier(&wdt_notifier);
+	if (ret != 0) {
+		printk (KERN_ERR PFX "cannot register reboot notifier (err=%d)\n",
+			ret);
+		goto unreg_regions;
+	}
+
+	ret = misc_register(&wdt_miscdev);
+	if (ret != 0) {
+		printk (KERN_ERR PFX "cannot register miscdev on minor=%d (err=%d)\n",
+			WATCHDOG_MINOR, ret);
+		goto unreg_reboot;
+	}
+
+	printk (KERN_INFO PFX "initialized. timeout=%d sec (nowayout=%d)\n",
+		timeout, nowayout);
+
+out:
+	return ret;
+unreg_reboot:
+	unregister_reboot_notifier(&wdt_notifier);
+unreg_regions:
+	release_region(wdt_io, 1);
+	goto out;
+}
+
+static void __exit
+wdt_exit(void)
+{
+	misc_deregister(&wdt_miscdev);
+	unregister_reboot_notifier(&wdt_notifier);
+	release_region(wdt_io,1);
+}
+
+module_init(wdt_init);
+module_exit(wdt_exit);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Pádraig Brady <P@draigBrady.com>");
+MODULE_DESCRIPTION("w38627hf WDT driver");
+MODULE_ALIAS_MISCDEV(WATCHDOG_MINOR);
diff --git a/drivers/char/watchdog/w83877f_wdt.c b/drivers/char/watchdog/w83877f_wdt.c
new file mode 100644
index 0000000..bccbd4d
--- /dev/null
+++ b/drivers/char/watchdog/w83877f_wdt.c
@@ -0,0 +1,426 @@
+/*
+ *	W83877F Computer Watchdog Timer driver
+ *
+ *      Based on acquirewdt.c by Alan Cox,
+ *           and sbc60xxwdt.c by Jakob Oestergaard <jakob@unthought.net>
+ *
+ *	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
+ *           4/12 - 2002      [rob@osinvestor.com] Eliminate extra comments
+ *                            Eliminate fop_read
+ *                            Eliminate extra spin_unlock
+ *                            Added KERN_* tags to printks
+ *                            add CONFIG_WATCHDOG_NOWAYOUT support
+ *                            fix possible wdt_is_open race
+ *                            changed watchdog_info to correctly reflect what the driver offers
+ *                            added WDIOC_GETSTATUS, WDIOC_GETBOOTSTATUS, WDIOC_SETTIMEOUT,
+ *                            WDIOC_GETTIMEOUT, and WDIOC_SETOPTIONS ioctls
+ *           09/8 - 2003      [wim@iguana.be] cleanup of trailing spaces
+ *                            added extra printk's for startup problems
+ *                            use module_param
+ *                            made timeout (the emulated heartbeat) a module_param
+ *                            made the keepalive ping an internal subroutine
+ *
+ *  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/moduleparam.h>
+#include <linux/types.h>
+#include <linux/timer.h>
+#include <linux/jiffies.h>
+#include <linux/miscdevice.h>
+#include <linux/watchdog.h>
+#include <linux/fs.h>
+#include <linux/ioport.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>
+
+#define OUR_NAME "w83877f_wdt"
+#define PFX OUR_NAME ": "
+
+#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 WATCHDOG_TIMEOUT 30            /* 30 sec default timeout */
+static int timeout = WATCHDOG_TIMEOUT; /* in seconds, will be multiplied by HZ to get seconds to wait for a ping */
+module_param(timeout, int, 0);
+MODULE_PARM_DESC(timeout, "Watchdog timeout in seconds. (1<=timeout<=3600, default=" __MODULE_STRING(WATCHDOG_TIMEOUT) ")");
+
+
+#ifdef CONFIG_WATCHDOG_NOWAYOUT
+static int nowayout = 1;
+#else
+static int nowayout = 0;
+#endif
+
+module_param(nowayout, int, 0);
+MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default=CONFIG_WATCHDOG_NOWAYOUT)");
+
+static void wdt_timer_ping(unsigned long);
+static struct timer_list timer;
+static unsigned long next_heartbeat;
+static unsigned long wdt_is_open;
+static char 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(KERN_WARNING PFX "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 + (timeout * HZ);
+
+	/* Start the timer */
+	timer.expires = jiffies + WDT_INTERVAL;
+	add_timer(&timer);
+
+	wdt_change(WDT_ENABLE);
+
+	printk(KERN_INFO PFX "Watchdog timer is now enabled.\n");
+}
+
+static void wdt_turnoff(void)
+{
+	/* Stop the timer */
+	del_timer(&timer);
+
+	wdt_change(WDT_DISABLE);
+
+	printk(KERN_INFO PFX "Watchdog timer is now disabled...\n");
+}
+
+static void wdt_keepalive(void)
+{
+	/* user land ping */
+	next_heartbeat = jiffies + (timeout * HZ);
+}
+
+/*
+ * /dev/watchdog handling
+ */
+
+static ssize_t fop_write(struct file * file, const char __user * buf, size_t count, loff_t * ppos)
+{
+	/* See if we got the magic character 'V' and reload the timer */
+	if(count)
+	{
+		if (!nowayout)
+		{
+			size_t ofs;
+
+			/* note: just in case someone wrote the magic character
+			 * five months ago... */
+			wdt_expect_close = 0;
+
+			/* scan to see whether or not we got the magic character */
+			for(ofs = 0; ofs != count; ofs++)
+			{
+				char c;
+				if (get_user(c, buf + ofs))
+					return -EFAULT;
+				if (c == 'V')
+					wdt_expect_close = 42;
+			}
+		}
+
+		/* someone wrote to us, we should restart timer */
+		wdt_keepalive();
+	}
+	return count;
+}
+
+static int fop_open(struct inode * inode, struct file * file)
+{
+	/* 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 nonseekable_open(inode, file);
+}
+
+static int fop_close(struct inode * inode, struct file * file)
+{
+	if(wdt_expect_close == 42)
+		wdt_turnoff();
+	else {
+		del_timer(&timer);
+		printk(KERN_CRIT PFX "device file closed unexpectedly. Will not stop the WDT!\n");
+	}
+	clear_bit(0, &wdt_is_open);
+	wdt_expect_close = 0;
+	return 0;
+}
+
+static int fop_ioctl(struct inode *inode, struct file *file, unsigned int cmd,
+	unsigned long arg)
+{
+	void __user *argp = (void __user *)arg;
+	int __user *p = argp;
+	static struct watchdog_info ident=
+	{
+		.options = WDIOF_KEEPALIVEPING | WDIOF_SETTIMEOUT | WDIOF_MAGICCLOSE,
+		.firmware_version = 1,
+		.identity = "W83877F",
+	};
+
+	switch(cmd)
+	{
+		default:
+			return -ENOIOCTLCMD;
+		case WDIOC_GETSUPPORT:
+			return copy_to_user(argp, &ident, sizeof(ident))?-EFAULT:0;
+		case WDIOC_GETSTATUS:
+		case WDIOC_GETBOOTSTATUS:
+			return put_user(0, p);
+		case WDIOC_KEEPALIVE:
+			wdt_keepalive();
+			return 0;
+		case WDIOC_SETOPTIONS:
+		{
+			int new_options, retval = -EINVAL;
+
+			if(get_user(new_options, p))
+				return -EFAULT;
+
+			if(new_options & WDIOS_DISABLECARD) {
+				wdt_turnoff();
+				retval = 0;
+			}
+
+			if(new_options & WDIOS_ENABLECARD) {
+				wdt_startup();
+				retval = 0;
+			}
+
+			return retval;
+		}
+		case WDIOC_SETTIMEOUT:
+		{
+			int new_timeout;
+
+			if(get_user(new_timeout, p))
+				return -EFAULT;
+
+			if(new_timeout < 1 || new_timeout > 3600) /* arbitrary upper limit */
+				return -EINVAL;
+
+			timeout = new_timeout;
+			wdt_keepalive();
+			/* Fall through */
+		}
+		case WDIOC_GETTIMEOUT:
+			return put_user(timeout, p);
+	}
+}
+
+static struct file_operations wdt_fops = {
+	.owner		= THIS_MODULE,
+	.llseek		= no_llseek,
+	.write		= fop_write,
+	.open		= fop_open,
+	.release	= fop_close,
+	.ioctl		= fop_ioctl,
+};
+
+static struct miscdevice wdt_miscdev = {
+	.minor	= WATCHDOG_MINOR,
+	.name	= "watchdog",
+	.fops	= &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=
+{
+	.notifier_call = wdt_notify_sys,
+};
+
+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(timeout < 1 || timeout > 3600) /* arbitrary upper limit */
+	{
+		timeout = WATCHDOG_TIMEOUT;
+		printk(KERN_INFO PFX "timeout value must be 1<=x<=3600, using %d\n",
+			timeout);
+	}
+
+	if (!request_region(ENABLE_W83877F_PORT, 2, "W83877F WDT"))
+	{
+		printk(KERN_ERR PFX "I/O address 0x%04x already in use\n",
+			ENABLE_W83877F_PORT);
+		rc = -EIO;
+		goto err_out;
+	}
+
+	if (!request_region(WDT_PING, 1, "W8387FF WDT"))
+	{
+		printk(KERN_ERR PFX "I/O address 0x%04x already in use\n",
+			WDT_PING);
+		rc = -EIO;
+		goto err_out_region1;
+	}
+
+	init_timer(&timer);
+	timer.function = wdt_timer_ping;
+	timer.data = 0;
+
+	rc = misc_register(&wdt_miscdev);
+	if (rc)
+	{
+		printk(KERN_ERR PFX "cannot register miscdev on minor=%d (err=%d)\n",
+			wdt_miscdev.minor, rc);
+		goto err_out_region2;
+	}
+
+	rc = register_reboot_notifier(&wdt_notifier);
+	if (rc)
+	{
+		printk(KERN_ERR PFX "cannot register reboot notifier (err=%d)\n",
+			rc);
+		goto err_out_miscdev;
+	}
+
+	printk(KERN_INFO PFX "WDT driver for W83877F initialised. timeout=%d sec (nowayout=%d)\n",
+		timeout, nowayout);
+
+	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");
+MODULE_ALIAS_MISCDEV(WATCHDOG_MINOR);
diff --git a/drivers/char/watchdog/wafer5823wdt.c b/drivers/char/watchdog/wafer5823wdt.c
new file mode 100644
index 0000000..abb0bea
--- /dev/null
+++ b/drivers/char/watchdog/wafer5823wdt.c
@@ -0,0 +1,330 @@
+/*
+ *	ICP Wafer 5823 Single Board Computer WDT driver
+ *      http://www.icpamerica.com/wafer_5823.php
+ *      May also work on other similar models
+ *
+ *	(c) Copyright 2002 Justin Cormack <justin@street-vision.com>
+ *
+ *      Release 0.02
+ *
+ *	Based on advantechwdt.c which is 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>
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/miscdevice.h>
+#include <linux/watchdog.h>
+#include <linux/fs.h>
+#include <linux/ioport.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>
+
+#define WATCHDOG_NAME "Wafer 5823 WDT"
+#define PFX WATCHDOG_NAME ": "
+#define WD_TIMO 60			/* 60 sec default timeout */
+
+static unsigned long wafwdt_is_open;
+static char expect_close;
+static spinlock_t wafwdt_lock;
+
+/*
+ *	You must set these - there is no sane way to probe for this board.
+ *
+ *      To enable, write the timeout value in seconds (1 to 255) to I/O
+ *      port WDT_START, then read the port to start the watchdog. To pat
+ *      the dog, read port WDT_STOP to stop the timer, then read WDT_START
+ *      to restart it again.
+ */
+
+static int wdt_stop = 0x843;
+static int wdt_start = 0x443;
+
+static int timeout = WD_TIMO;  /* in seconds */
+module_param(timeout, int, 0);
+MODULE_PARM_DESC(timeout, "Watchdog timeout in seconds. 1<= timeout <=255, default=" __MODULE_STRING(WD_TIMO) ".");
+
+#ifdef CONFIG_WATCHDOG_NOWAYOUT
+static int nowayout = 1;
+#else
+static int nowayout = 0;
+#endif
+
+module_param(nowayout, int, 0);
+MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default=CONFIG_WATCHDOG_NOWAYOUT)");
+
+static void wafwdt_ping(void)
+{
+	/* pat watchdog */
+	spin_lock(&wafwdt_lock);
+	inb_p(wdt_stop);
+	inb_p(wdt_start);
+	spin_unlock(&wafwdt_lock);
+}
+
+static void wafwdt_start(void)
+{
+	/* start up watchdog */
+	outb_p(timeout, wdt_start);
+	inb_p(wdt_start);
+}
+
+static void
+wafwdt_stop(void)
+{
+	/* stop watchdog */
+	inb_p(wdt_stop);
+}
+
+static ssize_t wafwdt_write(struct file *file, const char __user *buf, size_t count, loff_t * ppos)
+{
+	/* See if we got the magic character 'V' and reload the timer */
+	if (count) {
+		if (!nowayout) {
+			size_t i;
+
+			/* In case it was set long ago */
+			expect_close = 0;
+
+			/* scan to see whether or not we got the magic character */
+			for (i = 0; i != count; i++) {
+				char c;
+				if (get_user(c, buf + i))
+					return -EFAULT;
+				if (c == 'V')
+					expect_close = 42;
+			}
+		}
+		/* Well, anyhow someone wrote to us, we should return that favour */
+		wafwdt_ping();
+	}
+	return count;
+}
+
+static int wafwdt_ioctl(struct inode *inode, struct file *file, unsigned int cmd,
+	     unsigned long arg)
+{
+	int new_timeout;
+	void __user *argp = (void __user *)arg;
+	int __user *p = argp;
+	static struct watchdog_info ident = {
+		.options = WDIOF_KEEPALIVEPING | WDIOF_SETTIMEOUT | WDIOF_MAGICCLOSE,
+		.firmware_version = 1,
+		.identity = "Wafer 5823 WDT",
+	};
+
+	switch (cmd) {
+	case WDIOC_GETSUPPORT:
+		if (copy_to_user(argp, &ident, sizeof (ident)))
+			return -EFAULT;
+		break;
+
+	case WDIOC_GETSTATUS:
+	case WDIOC_GETBOOTSTATUS:
+		return put_user(0, p);
+
+	case WDIOC_KEEPALIVE:
+		wafwdt_ping();
+		break;
+
+	case WDIOC_SETTIMEOUT:
+		if (get_user(new_timeout, p))
+			return -EFAULT;
+		if ((new_timeout < 1) || (new_timeout > 255))
+			return -EINVAL;
+		timeout = new_timeout;
+		wafwdt_stop();
+		wafwdt_start();
+		/* Fall */
+	case WDIOC_GETTIMEOUT:
+		return put_user(timeout, p);
+
+	case WDIOC_SETOPTIONS:
+	{
+		int options, retval = -EINVAL;
+
+		if (get_user(options, p))
+			return -EFAULT;
+
+		if (options & WDIOS_DISABLECARD) {
+			wafwdt_start();
+			retval = 0;
+		}
+
+		if (options & WDIOS_ENABLECARD) {
+			wafwdt_stop();
+			retval = 0;
+		}
+
+		return retval;
+	}
+
+	default:
+		return -ENOIOCTLCMD;
+	}
+	return 0;
+}
+
+static int wafwdt_open(struct inode *inode, struct file *file)
+{
+	if (test_and_set_bit(0, &wafwdt_is_open))
+		return -EBUSY;
+
+	/*
+	 *      Activate
+	 */
+	wafwdt_start();
+	return nonseekable_open(inode, file);
+}
+
+static int
+wafwdt_close(struct inode *inode, struct file *file)
+{
+	if (expect_close == 42) {
+		wafwdt_stop();
+	} else {
+		printk(KERN_CRIT PFX "WDT device closed unexpectedly.  WDT will not stop!\n");
+		wafwdt_ping();
+	}
+	clear_bit(0, &wafwdt_is_open);
+	expect_close = 0;
+	return 0;
+}
+
+/*
+ *	Notifier for system down
+ */
+
+static int wafwdt_notify_sys(struct notifier_block *this, unsigned long code, void *unused)
+{
+	if (code == SYS_DOWN || code == SYS_HALT) {
+		/* Turn the WDT off */
+		wafwdt_stop();
+	}
+	return NOTIFY_DONE;
+}
+
+/*
+ *	Kernel Interfaces
+ */
+
+static struct file_operations wafwdt_fops = {
+	.owner		= THIS_MODULE,
+	.llseek		= no_llseek,
+	.write		= wafwdt_write,
+	.ioctl		= wafwdt_ioctl,
+	.open		= wafwdt_open,
+	.release	= wafwdt_close,
+};
+
+static struct miscdevice wafwdt_miscdev = {
+	.minor	= WATCHDOG_MINOR,
+	.name	= "watchdog",
+	.fops	= &wafwdt_fops,
+};
+
+/*
+ *	The WDT needs to learn about soft shutdowns in order to
+ *	turn the timebomb registers off.
+ */
+
+static struct notifier_block wafwdt_notifier = {
+	.notifier_call = wafwdt_notify_sys,
+};
+
+static int __init wafwdt_init(void)
+{
+	int ret;
+
+	printk(KERN_INFO "WDT driver for Wafer 5823 single board computer initialising.\n");
+
+	spin_lock_init(&wafwdt_lock);
+
+	if (timeout < 1 || timeout > 255) {
+		timeout = WD_TIMO;
+		printk (KERN_INFO PFX "timeout value must be 1<=x<=255, using %d\n",
+			timeout);
+	}
+
+	if (wdt_stop != wdt_start) {
+		if(!request_region(wdt_stop, 1, "Wafer 5823 WDT")) {
+			printk (KERN_ERR PFX "I/O address 0x%04x already in use\n",
+			wdt_stop);
+			ret = -EIO;
+			goto error;
+		}
+	}
+
+	if(!request_region(wdt_start, 1, "Wafer 5823 WDT")) {
+		printk (KERN_ERR PFX "I/O address 0x%04x already in use\n",
+			wdt_start);
+		ret = -EIO;
+		goto error2;
+	}
+
+	ret = register_reboot_notifier(&wafwdt_notifier);
+	if (ret != 0) {
+		printk (KERN_ERR PFX "cannot register reboot notifier (err=%d)\n",
+			ret);
+		goto error3;
+	}
+
+	ret = misc_register(&wafwdt_miscdev);
+	if (ret != 0) {
+		printk (KERN_ERR PFX "cannot register miscdev on minor=%d (err=%d)\n",
+			WATCHDOG_MINOR, ret);
+		goto error4;
+	}
+
+	printk (KERN_INFO PFX "initialized. timeout=%d sec (nowayout=%d)\n",
+		timeout, nowayout);
+
+	return ret;
+error4:
+	unregister_reboot_notifier(&wafwdt_notifier);
+error3:
+	release_region(wdt_start, 1);
+error2:
+	if (wdt_stop != wdt_start)
+		release_region(wdt_stop, 1);
+error:
+	return ret;
+}
+
+static void __exit wafwdt_exit(void)
+{
+	misc_deregister(&wafwdt_miscdev);
+	unregister_reboot_notifier(&wafwdt_notifier);
+	if(wdt_stop != wdt_start)
+		release_region(wdt_stop, 1);
+	release_region(wdt_start, 1);
+}
+
+module_init(wafwdt_init);
+module_exit(wafwdt_exit);
+
+MODULE_AUTHOR("Justin Cormack");
+MODULE_DESCRIPTION("ICP Wafer 5823 Single Board Computer WDT driver");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS_MISCDEV(WATCHDOG_MINOR);
+
+/* end of wafer5823wdt.c */
diff --git a/drivers/char/watchdog/wd501p.h b/drivers/char/watchdog/wd501p.h
new file mode 100644
index 0000000..84e60eb
--- /dev/null
+++ b/drivers/char/watchdog/wd501p.h
@@ -0,0 +1,52 @@
+/*
+ *	Industrial Computer Source WDT500/501 driver
+ *
+ *	(c) Copyright 1995	CymruNET Ltd
+ *				Innovation Centre
+ *				Singleton Park
+ *				Swansea
+ *				Wales
+ *				UK
+ *				SA2 8PP
+ *
+ *	http://www.cymru.net
+ *
+ *	This driver is provided under the GNU General Public License, incorporated
+ *	herein by reference. The driver is provided without warranty or 
+ *	support.
+ *
+ *	Release 0.04.
+ *
+ */
+
+#include <linux/config.h>
+
+#define WDT_COUNT0		(io+0)
+#define WDT_COUNT1		(io+1)
+#define WDT_COUNT2		(io+2)
+#define WDT_CR			(io+3)
+#define WDT_SR			(io+4)	/* Start buzzer on PCI write */
+#define WDT_RT			(io+5)	/* Stop buzzer on PCI write */
+#define WDT_BUZZER		(io+6)	/* PCI only: rd=disable, wr=enable */
+#define WDT_DC			(io+7)
+
+/* The following are only on the PCI card, they're outside of I/O space on
+ * the ISA card: */
+#define WDT_CLOCK		(io+12)	/* COUNT2: rd=16.67MHz, wr=2.0833MHz */
+/* inverted opto isolated reset output: */
+#define WDT_OPTONOTRST		(io+13)	/* wr=enable, rd=disable */
+/* opto isolated reset output: */
+#define WDT_OPTORST		(io+14)	/* wr=enable, rd=disable */
+/* programmable outputs: */
+#define WDT_PROGOUT		(io+15)	/* wr=enable, rd=disable */
+
+								/* FAN 501 500 */
+#define WDC_SR_WCCR		1	/* Active low */	/*  X   X   X  */
+#define WDC_SR_TGOOD		2				/*  X   X   -  */
+#define WDC_SR_ISOI0		4				/*  X   X   X  */
+#define WDC_SR_ISII1		8				/*  X   X   X  */
+#define WDC_SR_FANGOOD		16				/*  X   -   -  */
+#define WDC_SR_PSUOVER		32	/* Active low */	/*  X   X   -  */
+#define WDC_SR_PSUUNDR		64	/* Active low */	/*  X   X   -  */
+#define WDC_SR_IRQ		128	/* Active low */	/*  X   X   X  */
+
diff --git a/drivers/char/watchdog/wdt.c b/drivers/char/watchdog/wdt.c
new file mode 100644
index 0000000..5684aa3
--- /dev/null
+++ b/drivers/char/watchdog/wdt.c
@@ -0,0 +1,647 @@
+/*
+ *	Industrial Computer Source WDT500/501 driver
+ *
+ *	(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.10.
+ *
+ *	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
+ *		Joel Becker	:	Added WDIOC_GET/SETTIMEOUT
+ *		Matt Domsch	:	Added nowayout module option
+ */
+
+#include <linux/config.h>
+#include <linux/interrupt.h>
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/types.h>
+#include <linux/miscdevice.h>
+#include <linux/watchdog.h>
+#include <linux/fs.h>
+#include <linux/ioport.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>
+#include "wd501p.h"
+
+static unsigned long wdt_is_open;
+static char expect_close;
+
+/*
+ *	Module parameters
+ */
+
+#define WD_TIMO 60			/* Default heartbeat = 60 seconds */
+
+static int heartbeat = WD_TIMO;
+static int wd_heartbeat;
+module_param(heartbeat, int, 0);
+MODULE_PARM_DESC(heartbeat, "Watchdog heartbeat in seconds. (0<heartbeat<65536, default=" __MODULE_STRING(WD_TIMO) ")");
+
+#ifdef CONFIG_WATCHDOG_NOWAYOUT
+static int nowayout = 1;
+#else
+static int nowayout = 0;
+#endif
+
+module_param(nowayout, int, 0);
+MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default=CONFIG_WATCHDOG_NOWAYOUT)");
+
+/* You must set these - there is no sane way to probe for this board. */
+static int io=0x240;
+static int irq=11;
+
+module_param(io, int, 0);
+MODULE_PARM_DESC(io, "WDT io port (default=0x240)");
+module_param(irq, int, 0);
+MODULE_PARM_DESC(irq, "WDT irq (default=11)");
+
+#ifdef CONFIG_WDT_501
+/* Support for the Fan Tachometer on the WDT501-P */
+static int tachometer;
+
+module_param(tachometer, int, 0);
+MODULE_PARM_DESC(tachometer, "WDT501-P Fan Tachometer support (0=disable, default=0)");
+#endif /* CONFIG_WDT_501 */
+
+/*
+ *	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);
+}
+
+/**
+ *	wdt_start:
+ *
+ *	Start the watchdog driver.
+ */
+
+static int wdt_start(void)
+{
+	inb_p(WDT_DC);			/* Disable watchdog */
+	wdt_ctr_mode(0,3);		/* Program CTR0 for Mode 3: Square Wave Generator */
+	wdt_ctr_mode(1,2);		/* Program CTR1 for Mode 2: Rate Generator */
+	wdt_ctr_mode(2,0);		/* Program CTR2 for Mode 0: Pulse on Terminal Count */
+	wdt_ctr_load(0, 8948);		/* Count at 100Hz */
+	wdt_ctr_load(1,wd_heartbeat);	/* Heartbeat */
+	wdt_ctr_load(2,65535);		/* Length of reset pulse */
+	outb_p(0, WDT_DC);		/* Enable watchdog */
+	return 0;
+}
+
+/**
+ *	wdt_stop:
+ *
+ *	Stop the watchdog driver.
+ */
+
+static int wdt_stop (void)
+{
+	/* Turn the card off */
+	inb_p(WDT_DC);			/* Disable watchdog */
+	wdt_ctr_load(2,0);		/* 0 length reset pulses now */
+	return 0;
+}
+
+/**
+ *	wdt_ping:
+ *
+ *	Reload counter one with the watchdog heartbeat. We don't bother reloading
+ *	the cascade counter.
+ */
+
+static int wdt_ping(void)
+{
+	/* Write a watchdog value */
+	inb_p(WDT_DC);			/* Disable watchdog */
+	wdt_ctr_mode(1,2);		/* Re-Program CTR1 for Mode 2: Rate Generator */
+	wdt_ctr_load(1,wd_heartbeat);	/* Heartbeat */
+	outb_p(0, WDT_DC);		/* Enable watchdog */
+	return 0;
+}
+
+/**
+ *	wdt_set_heartbeat:
+ *	@t:		the new heartbeat value that needs to be set.
+ *
+ *	Set a new heartbeat value for the watchdog device. If the heartbeat value is
+ *	incorrect we keep the old value and return -EINVAL. If successfull we
+ *	return 0.
+ */
+static int wdt_set_heartbeat(int t)
+{
+	if ((t < 1) || (t > 65535))
+		return -EINVAL;
+
+	heartbeat = t;
+	wd_heartbeat = t * 100;
+	return 0;
+}
+
+/**
+ *	wdt_get_status:
+ *	@status:		the new 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_get_status(int *status)
+{
+	unsigned char new_status=inb_p(WDT_SR);
+
+	*status=0;
+	if (new_status & WDC_SR_ISOI0)
+		*status |= WDIOF_EXTERN1;
+	if (new_status & WDC_SR_ISII1)
+		*status |= WDIOF_EXTERN2;
+#ifdef CONFIG_WDT_501
+	if (!(new_status & WDC_SR_TGOOD))
+		*status |= WDIOF_OVERHEAT;
+	if (!(new_status & WDC_SR_PSUOVER))
+		*status |= WDIOF_POWEROVER;
+	if (!(new_status & WDC_SR_PSUUNDR))
+		*status |= WDIOF_POWERUNDER;
+	if (tachometer) {
+		if (!(new_status & WDC_SR_FANGOOD))
+			*status |= WDIOF_FANFAULT;
+	}
+#endif /* CONFIG_WDT_501 */
+	return 0;
+}
+
+#ifdef CONFIG_WDT_501
+/**
+ *	wdt_get_temperature:
+ *
+ *	Reports the temperature in degrees Fahrenheit. The API is in
+ *	farenheit. It was designed by an imperial measurement luddite.
+ */
+
+static int wdt_get_temperature(int *temperature)
+{
+	unsigned short c=inb_p(WDT_RT);
+
+	*temperature = (c * 11 / 15) + 7;
+	return 0;
+}
+#endif /* CONFIG_WDT_501 */
+
+/**
+ *	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 occurring.
+ */
+
+static irqreturn_t 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);
+
+	printk(KERN_CRIT "WDT status %d\n", status);
+
+#ifdef CONFIG_WDT_501
+	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 (tachometer) {
+		if (!(status & WDC_SR_FANGOOD))
+			printk(KERN_CRIT "Possible fan fault.\n");
+	}
+#endif /* CONFIG_WDT_501 */
+	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
+	return IRQ_HANDLED;
+}
+
+
+/**
+ *	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 __user *buf, size_t count, loff_t *ppos)
+{
+	if(count) {
+		if (!nowayout) {
+			size_t i;
+
+			/* In case it was set long ago */
+			expect_close = 0;
+
+			for (i = 0; i != count; i++) {
+				char c;
+				if (get_user(c, buf + i))
+					return -EFAULT;
+				if (c == 'V')
+					expect_close = 42;
+			}
+		}
+		wdt_ping();
+	}
+	return count;
+}
+
+/**
+ *	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)
+{
+	void __user *argp = (void __user *)arg;
+	int __user *p = argp;
+	int new_heartbeat;
+	int status;
+
+	static struct watchdog_info ident = {
+		.options =		WDIOF_SETTIMEOUT|
+					WDIOF_MAGICCLOSE|
+					WDIOF_KEEPALIVEPING,
+		.firmware_version =	1,
+		.identity =		"WDT500/501",
+	};
+
+	/* Add options according to the card we have */
+	ident.options |= (WDIOF_EXTERN1|WDIOF_EXTERN2);
+#ifdef CONFIG_WDT_501
+	ident.options |= (WDIOF_OVERHEAT|WDIOF_POWERUNDER|WDIOF_POWEROVER);
+	if (tachometer)
+		ident.options |= WDIOF_FANFAULT;
+#endif /* CONFIG_WDT_501 */
+
+	switch(cmd)
+	{
+		default:
+			return -ENOIOCTLCMD;
+		case WDIOC_GETSUPPORT:
+			return copy_to_user(argp, &ident, sizeof(ident))?-EFAULT:0;
+
+		case WDIOC_GETSTATUS:
+			wdt_get_status(&status);
+			return put_user(status, p);
+		case WDIOC_GETBOOTSTATUS:
+			return put_user(0, p);
+		case WDIOC_KEEPALIVE:
+			wdt_ping();
+			return 0;
+		case WDIOC_SETTIMEOUT:
+			if (get_user(new_heartbeat, p))
+				return -EFAULT;
+
+			if (wdt_set_heartbeat(new_heartbeat))
+				return -EINVAL;
+
+			wdt_ping();
+			/* Fall */
+		case WDIOC_GETTIMEOUT:
+			return put_user(heartbeat, p);
+	}
+}
+
+/**
+ *	wdt_open:
+ *	@inode: inode of device
+ *	@file: file handle to device
+ *
+ *	The watchdog device 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)
+{
+	if(test_and_set_bit(0, &wdt_is_open))
+		return -EBUSY;
+	/*
+	 *	Activate
+	 */
+	wdt_start();
+	return nonseekable_open(inode, file);
+}
+
+/**
+ *	wdt_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 wdt_release(struct inode *inode, struct file *file)
+{
+	if (expect_close == 42) {
+		wdt_stop();
+		clear_bit(0, &wdt_is_open);
+	} else {
+		printk(KERN_CRIT "wdt: WDT device closed unexpectedly.  WDT will not stop!\n");
+		wdt_ping();
+	}
+	expect_close = 0;
+	return 0;
+}
+
+#ifdef CONFIG_WDT_501
+/**
+ *	wdt_temp_read:
+ *	@file: file handle to the watchdog board
+ *	@buf: buffer to write 1 byte into
+ *	@count: length of buffer
+ *	@ptr: offset (no seek allowed)
+ *
+ *	Temp_read reports the temperature in degrees Fahrenheit. The API is in
+ *	farenheit. It was designed by an imperial measurement luddite.
+ */
+
+static ssize_t wdt_temp_read(struct file *file, char __user *buf, size_t count, loff_t *ptr)
+{
+	int temperature;
+
+	if (wdt_get_temperature(&temperature))
+		return -EFAULT;
+
+	if (copy_to_user (buf, &temperature, 1))
+		return -EFAULT;
+
+	return 1;
+}
+
+/**
+ *	wdt_temp_open:
+ *	@inode: inode of device
+ *	@file: file handle to device
+ *
+ *	The temperature device has been opened.
+ */
+
+static int wdt_temp_open(struct inode *inode, struct file *file)
+{
+	return nonseekable_open(inode, file);
+}
+
+/**
+ *	wdt_temp_release:
+ *	@inode: inode to board
+ *	@file: file handle to board
+ *
+ *	The temperature device has been closed.
+ */
+
+static int wdt_temp_release(struct inode *inode, struct file *file)
+{
+	return 0;
+}
+#endif /* CONFIG_WDT_501 */
+
+/**
+ *	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 */
+		wdt_stop();
+	}
+	return NOTIFY_DONE;
+}
+
+/*
+ *	Kernel Interfaces
+ */
+
+
+static struct file_operations wdt_fops = {
+	.owner		= THIS_MODULE,
+	.llseek		= no_llseek,
+	.write		= wdt_write,
+	.ioctl		= wdt_ioctl,
+	.open		= wdt_open,
+	.release	= wdt_release,
+};
+
+static struct miscdevice wdt_miscdev = {
+	.minor	= WATCHDOG_MINOR,
+	.name	= "watchdog",
+	.fops	= &wdt_fops,
+};
+
+#ifdef CONFIG_WDT_501
+static struct file_operations wdt_temp_fops = {
+	.owner		= THIS_MODULE,
+	.llseek		= no_llseek,
+	.read		= wdt_temp_read,
+	.open		= wdt_temp_open,
+	.release	= wdt_temp_release,
+};
+
+static struct miscdevice temp_miscdev = {
+	.minor	= TEMP_MINOR,
+	.name	= "temperature",
+	.fops	= &wdt_temp_fops,
+};
+#endif /* CONFIG_WDT_501 */
+
+/*
+ *	The WDT card needs to learn about soft shutdowns in order to
+ *	turn the timebomb registers off.
+ */
+
+static struct notifier_block wdt_notifier = {
+	.notifier_call = wdt_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 wdt_exit(void)
+{
+	misc_deregister(&wdt_miscdev);
+#ifdef CONFIG_WDT_501
+	misc_deregister(&temp_miscdev);
+#endif /* CONFIG_WDT_501 */
+	unregister_reboot_notifier(&wdt_notifier);
+	free_irq(irq, NULL);
+	release_region(io,8);
+}
+
+/**
+ * 	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;
+
+	/* Check that the heartbeat value is within it's range ; if not reset to the default */
+	if (wdt_set_heartbeat(heartbeat)) {
+		wdt_set_heartbeat(WD_TIMO);
+		printk(KERN_INFO "wdt: heartbeat value must be 0<heartbeat<65536, using %d\n",
+			WD_TIMO);
+	}
+
+	if (!request_region(io, 8, "wdt501p")) {
+		printk(KERN_ERR "wdt: I/O address 0x%04x already in use\n", io);
+		ret = -EBUSY;
+		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 outreg;
+	}
+
+	ret = register_reboot_notifier(&wdt_notifier);
+	if(ret) {
+		printk(KERN_ERR "wdt: cannot register reboot notifier (err=%d)\n", ret);
+		goto outirq;
+	}
+
+#ifdef CONFIG_WDT_501
+	ret = misc_register(&temp_miscdev);
+	if (ret) {
+		printk(KERN_ERR "wdt: cannot register miscdev on minor=%d (err=%d)\n",
+			TEMP_MINOR, ret);
+		goto outrbt;
+	}
+#endif /* CONFIG_WDT_501 */
+
+	ret = misc_register(&wdt_miscdev);
+	if (ret) {
+		printk(KERN_ERR "wdt: cannot register miscdev on minor=%d (err=%d)\n",
+			WATCHDOG_MINOR, ret);
+		goto outmisc;
+	}
+
+	ret = 0;
+	printk(KERN_INFO "WDT500/501-P driver 0.10 at 0x%04x (Interrupt %d). heartbeat=%d sec (nowayout=%d)\n",
+		io, irq, heartbeat, nowayout);
+#ifdef CONFIG_WDT_501
+	printk(KERN_INFO "wdt: Fan Tachometer is %s\n", (tachometer ? "Enabled" : "Disabled"));
+#endif /* CONFIG_WDT_501 */
+
+out:
+	return ret;
+
+outmisc:
+#ifdef CONFIG_WDT_501
+	misc_deregister(&temp_miscdev);
+outrbt:
+#endif /* CONFIG_WDT_501 */
+	unregister_reboot_notifier(&wdt_notifier);
+outirq:
+	free_irq(irq, NULL);
+outreg:
+	release_region(io,8);
+	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_ALIAS_MISCDEV(WATCHDOG_MINOR);
+MODULE_ALIAS_MISCDEV(TEMP_MINOR);
+MODULE_LICENSE("GPL");
diff --git a/drivers/char/watchdog/wdt285.c b/drivers/char/watchdog/wdt285.c
new file mode 100644
index 0000000..52825a1
--- /dev/null
+++ b/drivers/char/watchdog/wdt285.c
@@ -0,0 +1,229 @@
+/*
+ *	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/moduleparam.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 <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
+
+static unsigned int soft_margin = 60;		/* in seconds */
+static unsigned int reload;
+static unsigned long 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
+
+/*
+ *	Refresh the timer.
+ */
+static void watchdog_ping(void)
+{
+	*CSR_TIMER4_LOAD = reload;
+}
+
+/*
+ *	Allow only one person to hold it open
+ */
+static int watchdog_open(struct inode *inode, struct file *file)
+{
+	int ret;
+
+	if (*CSR_SA110_CNTL & (1 << 13))
+		return -EBUSY;
+
+	if (test_and_set_bit(1, &timer_alive))
+		return -EBUSY;
+
+	reload = soft_margin * (mem_fclk_21285 / 256);
+
+	*CSR_TIMER4_CLR = 0;
+	watchdog_ping();
+	*CSR_TIMER4_CNTL = TIMER_CNTL_ENABLE | TIMER_CNTL_AUTORELOAD
+		| TIMER_CNTL_DIV256;
+
+#ifdef ONLY_TESTING
+	ret = request_irq(IRQ_TIMER4, watchdog_fire, 0, "watchdog", NULL);
+	if (ret) {
+		*CSR_TIMER4_CNTL = 0;
+		clear_bit(1, &timer_alive);
+	}
+#else
+	/*
+	 * Setting this bit is irreversible; once enabled, there is
+	 * no way to disable the watchdog.
+	 */
+	*CSR_SA110_CNTL |= 1 << 13;
+
+	ret = 0;
+#endif
+	nonseekable_open(inode, file);
+	return ret;
+}
+
+/*
+ *	Shut off the timer.
+ *	Note: if we really have enabled the watchdog, there
+ *	is no way to turn off.
+ */
+static int watchdog_release(struct inode *inode, struct file *file)
+{
+#ifdef ONLY_TESTING
+	free_irq(IRQ_TIMER4, NULL);
+	clear_bit(1, &timer_alive);
+#endif
+	return 0;
+}
+
+static ssize_t
+watchdog_write(struct file *file, const char *data, size_t len, loff_t *ppos)
+{
+	/*
+	 *	Refresh the timer.
+	 */
+	if (len)
+		watchdog_ping();
+
+	return len;
+}
+
+static struct watchdog_info ident = {
+	.options	= WDIOF_SETTIMEOUT,
+	.identity	= "Footbridge Watchdog",
+};
+
+static int
+watchdog_ioctl(struct inode *inode, struct file *file, unsigned int cmd,
+	       unsigned long arg)
+{
+	unsigned int new_margin;
+	int ret = -ENOIOCTLCMD;
+
+	switch(cmd) {
+	case WDIOC_GETSUPPORT:
+		ret = 0;
+		if (copy_to_user((void *)arg, &ident, sizeof(ident)))
+			ret = -EFAULT;
+		break;
+
+	case WDIOC_GETSTATUS:
+	case WDIOC_GETBOOTSTATUS:
+		ret = put_user(0,(int *)arg);
+		break;
+
+	case WDIOC_KEEPALIVE:
+		watchdog_ping();
+		ret = 0;
+		break;
+
+	case WDIOC_SETTIMEOUT:
+		ret = get_user(new_margin, (int *)arg);
+		if (ret)
+			break;
+
+		/* Arbitrary, can't find the card's limits */
+		if (new_margin < 0 || new_margin > 60) {
+			ret = -EINVAL;
+			break;
+		}
+
+		soft_margin = new_margin;
+		reload = soft_margin * (mem_fclk_21285 / 256);
+		watchdog_ping();
+		/* Fall */
+	case WDIOC_GETTIMEOUT:
+		ret = put_user(soft_margin, (int *)arg);
+		break;
+	}
+	return ret;
+}
+
+static struct file_operations watchdog_fops = {
+	.owner		= THIS_MODULE,
+	.llseek		= no_llseek,
+	.write		= watchdog_write,
+	.ioctl		= watchdog_ioctl,
+	.open		= watchdog_open,
+	.release	= watchdog_release,
+};
+
+static struct miscdevice watchdog_miscdev = {
+	.minor		= WATCHDOG_MINOR,
+	.name		= "watchdog",
+	.fops		= &watchdog_fops,
+};
+
+static int __init footbridge_watchdog_init(void)
+{
+	int retval;
+
+	if (machine_is_netwinder())
+		return -ENODEV;
+
+	retval = misc_register(&watchdog_miscdev);
+	if (retval < 0)
+		return retval;
+
+	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("Footbridge watchdog driver");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS_MISCDEV(WATCHDOG_MINOR);
+
+module_param(soft_margin, int, 0);
+MODULE_PARM_DESC(soft_margin,"Watchdog timeout in seconds");
+
+module_init(footbridge_watchdog_init);
+module_exit(footbridge_watchdog_exit);
diff --git a/drivers/char/watchdog/wdt977.c b/drivers/char/watchdog/wdt977.c
new file mode 100644
index 0000000..072e9b2
--- /dev/null
+++ b/drivers/char/watchdog/wdt977.c
@@ -0,0 +1,459 @@
+/*
+ *	Wdt977	0.03:	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.
+ *      07-Jul-2003 Daniele Bellucci: Audit return code of misc_register in
+ *                                    nwwatchdog_init.
+ */
+
+#include <linux/module.h>
+#include <linux/moduleparam.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/watchdog.h>
+#include <linux/notifier.h>
+#include <linux/reboot.h>
+
+#include <asm/io.h>
+#include <asm/system.h>
+#include <asm/mach-types.h>
+#include <asm/uaccess.h>
+
+#define PFX "Wdt977: "
+#define WATCHDOG_MINOR	130
+
+#define	DEFAULT_TIMEOUT	60			/* default timeout in seconds */
+
+static	int timeout = DEFAULT_TIMEOUT;
+static	int timeoutM;				/* timeout in minutes */
+static	unsigned long timer_alive;
+static	int testmode;
+static	char expect_close;
+
+module_param(timeout, int, 0);
+MODULE_PARM_DESC(timeout,"Watchdog timeout in seconds (60..15300), default=" __MODULE_STRING(DEFAULT_TIMEOUT) ")");
+module_param(testmode, int, 0);
+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_param(nowayout, int, 0);
+MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default=CONFIG_WATCHDOG_NOWAYOUT)");
+
+/*
+ * Start the watchdog
+ */
+
+static int wdt977_start(void)
+{
+	/* 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);
+
+	printk(KERN_INFO PFX "activated.\n");
+
+	return 0;
+}
+
+/*
+ * Stop the watchdog
+ */
+
+static int wdt977_stop(void)
+{
+	/* 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);
+
+	printk(KERN_INFO PFX "shutdown.\n");
+
+	return 0;
+}
+
+/*
+ * Send a keepalive ping to the watchdog
+ * This is done by simply re-writing the timeout to reg. 0xF2
+ */
+
+static int wdt977_keepalive(void)
+{
+	/* 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;
+}
+
+/*
+ * Set the watchdog timeout value
+ */
+
+static int wdt977_set_timeout(int t)
+{
+	int tmrval;
+
+	/* convert seconds to minutes, rounding up */
+	tmrval = (t + 59) / 60;
+
+	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...
+		 */
+		tmrval += tmrval;
+	}
+
+	if ((tmrval < 1) || (tmrval > 255))
+		return -EINVAL;
+
+	/* timeout is the timeout in seconds, timeoutM is the timeout in minutes) */
+	timeout = t;
+	timeoutM = tmrval;
+	return 0;
+}
+
+/*
+ * Get the watchdog status
+ */
+
+static int wdt977_get_status(int *status)
+{
+	int new_status;
+
+	*status=0;
+
+	/* 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);
+	new_status = inb(0x371);
+
+	/* lock the SuperIO chip */
+	outb(0xAA,0x370);
+
+	if (new_status & 1)
+		*status |= WDIOF_CARDRESET;
+
+	return 0;
+}
+
+
+/*
+ *	/dev/watchdog handling
+ */
+
+static int wdt977_open(struct inode *inode, struct file *file)
+{
+	/* If the watchdog is alive we don't need to start it again */
+	if( test_and_set_bit(0,&timer_alive) )
+		return -EBUSY;
+
+	if (nowayout)
+		__module_get(THIS_MODULE);
+
+	wdt977_start();
+	return nonseekable_open(inode, file);
+}
+
+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 (expect_close == 42)
+	{
+		wdt977_stop();
+		clear_bit(0,&timer_alive);
+	} else {
+		printk(KERN_CRIT PFX "Unexpected close, not stopping watchdog!\n");
+		wdt977_keepalive();
+	}
+	expect_close = 0;
+	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 __user *buf,
+			    size_t count, loff_t *ppos)
+{
+	if (count) {
+		if (!nowayout) {
+			size_t i;
+
+			/* In case it was set long ago */
+			expect_close = 0;
+
+			for (i = 0; i != count; i++) {
+				char c;
+				if (get_user(c, buf + i))
+					return -EFAULT;
+				if (c == 'V')
+					expect_close = 42;
+			}
+		}
+
+		wdt977_keepalive();
+	}
+	return count;
+}
+
+/*
+ *      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 struct watchdog_info ident = {
+	.options =		WDIOF_SETTIMEOUT |
+				WDIOF_MAGICCLOSE |
+				WDIOF_KEEPALIVEPING,
+	.firmware_version =	1,
+	.identity =		"Winbond 83977",
+};
+
+static int wdt977_ioctl(struct inode *inode, struct file *file,
+	unsigned int cmd, unsigned long arg)
+{
+	int status;
+	int new_options, retval = -EINVAL;
+	int new_timeout;
+	union {
+		struct watchdog_info __user *ident;
+		int __user *i;
+	} uarg;
+
+	uarg.i = (int __user *)arg;
+
+	switch(cmd)
+	{
+	default:
+		return -ENOIOCTLCMD;
+
+	case WDIOC_GETSUPPORT:
+		return copy_to_user(uarg.ident, &ident,
+			sizeof(ident)) ? -EFAULT : 0;
+
+	case WDIOC_GETSTATUS:
+		wdt977_get_status(&status);
+		return put_user(status, uarg.i);
+
+	case WDIOC_GETBOOTSTATUS:
+		return put_user(0, uarg.i);
+
+	case WDIOC_KEEPALIVE:
+		wdt977_keepalive();
+		return 0;
+
+	case WDIOC_SETOPTIONS:
+		if (get_user (new_options, uarg.i))
+			return -EFAULT;
+
+		if (new_options & WDIOS_DISABLECARD) {
+			wdt977_stop();
+			retval = 0;
+		}
+
+		if (new_options & WDIOS_ENABLECARD) {
+			wdt977_start();
+			retval = 0;
+		}
+
+		return retval;
+
+	case WDIOC_SETTIMEOUT:
+		if (get_user(new_timeout, uarg.i))
+			return -EFAULT;
+
+		if (wdt977_set_timeout(new_timeout))
+		    return -EINVAL;
+
+		wdt977_keepalive();
+		/* Fall */
+
+	case WDIOC_GETTIMEOUT:
+		return put_user(timeout, uarg.i);
+
+	}
+}
+
+static int wdt977_notify_sys(struct notifier_block *this, unsigned long code,
+	void *unused)
+{
+	if(code==SYS_DOWN || code==SYS_HALT)
+		wdt977_stop();
+	return NOTIFY_DONE;
+}
+
+static struct file_operations wdt977_fops=
+{
+	.owner		= THIS_MODULE,
+	.llseek		= no_llseek,
+	.write		= wdt977_write,
+	.ioctl		= wdt977_ioctl,
+	.open		= wdt977_open,
+	.release	= wdt977_release,
+};
+
+static struct miscdevice wdt977_miscdev=
+{
+	.minor		= WATCHDOG_MINOR,
+	.name		= "watchdog",
+	.fops		= &wdt977_fops,
+};
+
+static struct notifier_block wdt977_notifier = {
+	.notifier_call = wdt977_notify_sys,
+};
+
+static int __init nwwatchdog_init(void)
+{
+	int retval;
+	if (!machine_is_netwinder())
+		return -ENODEV;
+
+	/* Check that the timeout value is within it's range ; if not reset to the default */
+	if (wdt977_set_timeout(timeout)) {
+		wdt977_set_timeout(DEFAULT_TIMEOUT);
+		printk(KERN_INFO PFX "timeout value must be 60<timeout<15300, using %d\n",
+			DEFAULT_TIMEOUT);
+	}
+
+	retval = register_reboot_notifier(&wdt977_notifier);
+	if (retval) {
+		printk(KERN_ERR PFX "cannot register reboot notifier (err=%d)\n",
+			retval);
+		return retval;
+	}
+
+	retval = misc_register(&wdt977_miscdev);
+	if (retval) {
+		printk(KERN_ERR PFX "cannot register miscdev on minor=%d (err=%d)\n",
+			WATCHDOG_MINOR, retval);
+		unregister_reboot_notifier(&wdt977_notifier);
+		return retval;
+	}
+
+	printk(KERN_INFO PFX "initialized. timeout=%d sec (nowayout=%d, testmode = %i)\n",
+		timeout, nowayout, testmode);
+
+	return 0;
+}
+
+static void __exit nwwatchdog_exit(void)
+{
+	misc_deregister(&wdt977_miscdev);
+	unregister_reboot_notifier(&wdt977_notifier);
+}
+
+module_init(nwwatchdog_init);
+module_exit(nwwatchdog_exit);
+
+MODULE_AUTHOR("Woody Suwalski <woody@netwinder.org>");
+MODULE_DESCRIPTION("W83977AF Watchdog driver");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS_MISCDEV(WATCHDOG_MINOR);
diff --git a/drivers/char/watchdog/wdt_pci.c b/drivers/char/watchdog/wdt_pci.c
new file mode 100644
index 0000000..7651ded
--- /dev/null
+++ b/drivers/char/watchdog/wdt_pci.c
@@ -0,0 +1,763 @@
+/*
+ *	Industrial Computer Source PCI-WDT500/501 driver
+ *
+ *	(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.10.
+ *
+ *	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
+ *		Joel Becker 	:	Added WDIOC_GET/SETTIMEOUT
+ *		Zwane Mwaikambo	:	Magic char closing, locking changes, cleanups
+ *		Matt Domsch	:	nowayout module option
+ */
+
+#include <linux/config.h>
+#include <linux/interrupt.h>
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/types.h>
+#include <linux/miscdevice.h>
+#include <linux/watchdog.h>
+#include <linux/ioport.h>
+#include <linux/notifier.h>
+#include <linux/reboot.h>
+#include <linux/init.h>
+#include <linux/fs.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
+
+/* We can only use 1 card due to the /dev/watchdog restriction */
+static int dev_count;
+
+static struct semaphore open_sem;
+static spinlock_t wdtpci_lock;
+static char expect_close;
+
+static int io;
+static int irq;
+
+/* Default timeout */
+#define WD_TIMO 60			/* Default heartbeat = 60 seconds */
+
+static int heartbeat = WD_TIMO;
+static int wd_heartbeat;
+module_param(heartbeat, int, 0);
+MODULE_PARM_DESC(heartbeat, "Watchdog heartbeat in seconds. (0<heartbeat<65536, default=" __MODULE_STRING(WD_TIMO) ")");
+
+#ifdef CONFIG_WATCHDOG_NOWAYOUT
+static int nowayout = 1;
+#else
+static int nowayout = 0;
+#endif
+
+module_param(nowayout, int, 0);
+MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default=CONFIG_WATCHDOG_NOWAYOUT)");
+
+#ifdef CONFIG_WDT_501_PCI
+/* Support for the Fan Tachometer on the PCI-WDT501 */
+static int tachometer;
+
+module_param(tachometer, int, 0);
+MODULE_PARM_DESC(tachometer, "PCI-WDT501 Fan Tachometer support (0=disable, default=0)");
+#endif /* CONFIG_WDT_501_PCI */
+
+/*
+ *	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);
+}
+
+/**
+ *	wdtpci_start:
+ *
+ *	Start the watchdog driver.
+ */
+
+static int wdtpci_start(void)
+{
+	unsigned long flags;
+
+	spin_lock_irqsave(&wdtpci_lock, flags);
+
+	/*
+	 * "pet" the watchdog, as Access says.
+	 * This resets the clock outputs.
+	 */
+	inb_p(WDT_DC);			/* Disable watchdog */
+	wdtpci_ctr_mode(2,0);		/* Program CTR2 for Mode 0: Pulse on Terminal Count */
+	outb_p(0, WDT_DC);		/* Enable watchdog */
+
+	inb_p(WDT_DC);			/* Disable watchdog */
+	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);		/* Program CTR0 for Mode 3: Square Wave Generator */
+	wdtpci_ctr_mode(1,2);		/* Program CTR1 for Mode 2: Rate Generator */
+	wdtpci_ctr_mode(2,1);		/* Program CTR2 for Mode 1: Retriggerable One-Shot */
+	wdtpci_ctr_load(0,20833);	/* count at 100Hz */
+	wdtpci_ctr_load(1,wd_heartbeat);/* Heartbeat */
+	/* DO NOT LOAD CTR2 on PCI card! -- JPN */
+	outb_p(0, WDT_DC);		/* Enable watchdog */
+
+	spin_unlock_irqrestore(&wdtpci_lock, flags);
+	return 0;
+}
+
+/**
+ *	wdtpci_stop:
+ *
+ *	Stop the watchdog driver.
+ */
+
+static int wdtpci_stop (void)
+{
+	unsigned long flags;
+
+	/* Turn the card off */
+	spin_lock_irqsave(&wdtpci_lock, flags);
+	inb_p(WDT_DC);			/* Disable watchdog */
+	wdtpci_ctr_load(2,0);		/* 0 length reset pulses now */
+	spin_unlock_irqrestore(&wdtpci_lock, flags);
+	return 0;
+}
+
+/**
+ *	wdtpci_ping:
+ *
+ *	Reload counter one with the watchdog heartbeat. We don't bother reloading
+ *	the cascade counter.
+ */
+
+static int wdtpci_ping(void)
+{
+	unsigned long flags;
+
+	/* Write a watchdog value */
+	spin_lock_irqsave(&wdtpci_lock, flags);
+	inb_p(WDT_DC);			/* Disable watchdog */
+	wdtpci_ctr_mode(1,2);		/* Re-Program CTR1 for Mode 2: Rate Generator */
+	wdtpci_ctr_load(1,wd_heartbeat);/* Heartbeat */
+	outb_p(0, WDT_DC);		/* Enable watchdog */
+	spin_unlock_irqrestore(&wdtpci_lock, flags);
+	return 0;
+}
+
+/**
+ *	wdtpci_set_heartbeat:
+ *	@t:		the new heartbeat value that needs to be set.
+ *
+ *	Set a new heartbeat value for the watchdog device. If the heartbeat value is
+ *	incorrect we keep the old value and return -EINVAL. If successfull we
+ *	return 0.
+ */
+static int wdtpci_set_heartbeat(int t)
+{
+	/* Arbitrary, can't find the card's limits */
+	if ((t < 1) || (t > 65535))
+		return -EINVAL;
+
+	heartbeat = t;
+	wd_heartbeat = t * 100;
+	return 0;
+}
+
+/**
+ *	wdtpci_get_status:
+ *	@status:		the new 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_get_status(int *status)
+{
+	unsigned char new_status=inb_p(WDT_SR);
+
+	*status=0;
+	if (new_status & WDC_SR_ISOI0)
+		*status |= WDIOF_EXTERN1;
+	if (new_status & WDC_SR_ISII1)
+		*status |= WDIOF_EXTERN2;
+#ifdef CONFIG_WDT_501_PCI
+	if (!(new_status & WDC_SR_TGOOD))
+		*status |= WDIOF_OVERHEAT;
+	if (!(new_status & WDC_SR_PSUOVER))
+		*status |= WDIOF_POWEROVER;
+	if (!(new_status & WDC_SR_PSUUNDR))
+		*status |= WDIOF_POWERUNDER;
+	if (tachometer) {
+		if (!(new_status & WDC_SR_FANGOOD))
+			*status |= WDIOF_FANFAULT;
+	}
+#endif /* CONFIG_WDT_501_PCI */
+	return 0;
+}
+
+#ifdef CONFIG_WDT_501_PCI
+/**
+ *	wdtpci_get_temperature:
+ *
+ *	Reports the temperature in degrees Fahrenheit. The API is in
+ *	farenheit. It was designed by an imperial measurement luddite.
+ */
+
+static int wdtpci_get_temperature(int *temperature)
+{
+	unsigned short c=inb_p(WDT_RT);
+
+	*temperature = (c * 11 / 15) + 7;
+	return 0;
+}
+#endif /* CONFIG_WDT_501_PCI */
+
+/**
+ *	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 occurring.
+ */
+
+static irqreturn_t 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);
+
+	printk(KERN_CRIT PFX "status %d\n", status);
+
+#ifdef CONFIG_WDT_501_PCI
+	if (!(status & WDC_SR_TGOOD))
+ 		printk(KERN_CRIT PFX "Overheat alarm.(%d)\n",inb_p(WDT_RT));
+	if (!(status & WDC_SR_PSUOVER))
+ 		printk(KERN_CRIT PFX "PSU over voltage.\n");
+	if (!(status & WDC_SR_PSUUNDR))
+ 		printk(KERN_CRIT PFX "PSU under voltage.\n");
+	if (tachometer) {
+		if (!(status & WDC_SR_FANGOOD))
+			printk(KERN_CRIT PFX "Possible fan fault.\n");
+	}
+#endif /* CONFIG_WDT_501_PCI */
+	if (!(status&WDC_SR_WCCR))
+#ifdef SOFTWARE_REBOOT
+#ifdef ONLY_TESTING
+		printk(KERN_CRIT PFX "Would Reboot.\n");
+#else
+		printk(KERN_CRIT PFX "Initiating system reboot.\n");
+		machine_restart(NULL);
+#endif
+#else
+		printk(KERN_CRIT PFX "Reset in 5ms.\n");
+#endif
+	return IRQ_HANDLED;
+}
+
+
+/**
+ *	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 __user *buf, size_t count, loff_t *ppos)
+{
+	if (count) {
+		if (!nowayout) {
+			size_t i;
+
+			expect_close = 0;
+
+			for (i = 0; i != count; i++) {
+				char c;
+				if(get_user(c, buf+i))
+					return -EFAULT;
+				if (c == 'V')
+					expect_close = 42;
+			}
+		}
+		wdtpci_ping();
+	}
+
+	return count;
+}
+
+/**
+ *	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)
+{
+	int new_heartbeat;
+	int status;
+	void __user *argp = (void __user *)arg;
+	int __user *p = argp;
+
+	static struct watchdog_info ident = {
+		.options =		WDIOF_SETTIMEOUT|
+					WDIOF_MAGICCLOSE|
+					WDIOF_KEEPALIVEPING,
+		.firmware_version =	1,
+		.identity =		"PCI-WDT500/501",
+	};
+
+	/* Add options according to the card we have */
+	ident.options |= (WDIOF_EXTERN1|WDIOF_EXTERN2);
+#ifdef CONFIG_WDT_501_PCI
+	ident.options |= (WDIOF_OVERHEAT|WDIOF_POWERUNDER|WDIOF_POWEROVER);
+	if (tachometer)
+		ident.options |= WDIOF_FANFAULT;
+#endif /* CONFIG_WDT_501_PCI */
+
+	switch(cmd)
+	{
+		default:
+			return -ENOIOCTLCMD;
+		case WDIOC_GETSUPPORT:
+			return copy_to_user(argp, &ident, sizeof(ident))?-EFAULT:0;
+
+		case WDIOC_GETSTATUS:
+			wdtpci_get_status(&status);
+			return put_user(status, p);
+		case WDIOC_GETBOOTSTATUS:
+			return put_user(0, p);
+		case WDIOC_KEEPALIVE:
+			wdtpci_ping();
+			return 0;
+		case WDIOC_SETTIMEOUT:
+			if (get_user(new_heartbeat, p))
+				return -EFAULT;
+
+			if (wdtpci_set_heartbeat(new_heartbeat))
+				return -EINVAL;
+
+			wdtpci_ping();
+			/* Fall */
+		case WDIOC_GETTIMEOUT:
+			return put_user(heartbeat, p);
+	}
+}
+
+/**
+ *	wdtpci_open:
+ *	@inode: inode of device
+ *	@file: file handle to device
+ *
+ *	The watchdog device 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)
+{
+	if (down_trylock(&open_sem))
+		return -EBUSY;
+
+	if (nowayout) {
+		__module_get(THIS_MODULE);
+	}
+	/*
+	 *	Activate
+	 */
+	wdtpci_start();
+	return nonseekable_open(inode, file);
+}
+
+/**
+ *	wdtpci_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 wdtpci_release(struct inode *inode, struct file *file)
+{
+	if (expect_close == 42) {
+		wdtpci_stop();
+	} else {
+		printk(KERN_CRIT PFX "Unexpected close, not stopping timer!");
+		wdtpci_ping();
+	}
+	expect_close = 0;
+	up(&open_sem);
+	return 0;
+}
+
+#ifdef CONFIG_WDT_501_PCI
+/**
+ *	wdtpci_temp_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_temp_read(struct file *file, char __user *buf, size_t count, loff_t *ptr)
+{
+	int temperature;
+
+	if (wdtpci_get_temperature(&temperature))
+		return -EFAULT;
+
+	if (copy_to_user (buf, &temperature, 1))
+		return -EFAULT;
+
+	return 1;
+}
+
+/**
+ *	wdtpci_temp_open:
+ *	@inode: inode of device
+ *	@file: file handle to device
+ *
+ *	The temperature device has been opened.
+ */
+
+static int wdtpci_temp_open(struct inode *inode, struct file *file)
+{
+	return nonseekable_open(inode, file);
+}
+
+/**
+ *	wdtpci_temp_release:
+ *	@inode: inode to board
+ *	@file: file handle to board
+ *
+ *	The temperature device has been closed.
+ */
+
+static int wdtpci_temp_release(struct inode *inode, struct file *file)
+{
+	return 0;
+}
+#endif /* CONFIG_WDT_501_PCI */
+
+/**
+ *	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 */
+		wdtpci_stop();
+	}
+	return NOTIFY_DONE;
+}
+
+/*
+ *	Kernel Interfaces
+ */
+
+
+static struct file_operations wdtpci_fops = {
+	.owner		= THIS_MODULE,
+	.llseek		= no_llseek,
+	.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_PCI
+static struct file_operations wdtpci_temp_fops = {
+	.owner		= THIS_MODULE,
+	.llseek		= no_llseek,
+	.read		= wdtpci_temp_read,
+	.open		= wdtpci_temp_open,
+	.release	= wdtpci_temp_release,
+};
+
+static struct miscdevice temp_miscdev = {
+	.minor	= TEMP_MINOR,
+	.name	= "temperature",
+	.fops	= &wdtpci_temp_fops,
+};
+#endif /* CONFIG_WDT_501_PCI */
+
+/*
+ *	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 __devinit wdtpci_init_one (struct pci_dev *dev,
+				   const struct pci_device_id *ent)
+{
+	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)) {
+		printk (KERN_ERR PFX "Not possible to enable PCI Device\n");
+		return -ENODEV;
+	}
+
+	if (pci_resource_start (dev, 2) == 0x0000) {
+		printk (KERN_ERR PFX "No I/O-Address for card detected\n");
+		ret = -ENODEV;
+		goto out_pci;
+	}
+
+	sema_init(&open_sem, 1);
+	spin_lock_init(&wdtpci_lock);
+
+	irq = dev->irq;
+	io = pci_resource_start (dev, 2);
+
+	if (request_region (io, 16, "wdt_pci") == NULL) {
+		printk (KERN_ERR PFX "I/O address 0x%04x already in use\n", io);
+		goto out_pci;
+	}
+
+	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;
+	}
+
+	printk ("PCI-WDT500/501 (PCI-WDG-CSM) driver 0.10 at 0x%04x (Interrupt %d)\n",
+		io, irq);
+
+	/* Check that the heartbeat value is within it's range ; if not reset to the default */
+	if (wdtpci_set_heartbeat(heartbeat)) {
+		wdtpci_set_heartbeat(WD_TIMO);
+		printk(KERN_INFO PFX "heartbeat value must be 0<heartbeat<65536, using %d\n",
+			WD_TIMO);
+	}
+
+	ret = register_reboot_notifier (&wdtpci_notifier);
+	if (ret) {
+		printk (KERN_ERR PFX "cannot register reboot notifier (err=%d)\n", ret);
+		goto out_irq;
+	}
+
+#ifdef CONFIG_WDT_501_PCI
+	ret = misc_register (&temp_miscdev);
+	if (ret) {
+		printk (KERN_ERR PFX "cannot register miscdev on minor=%d (err=%d)\n",
+			TEMP_MINOR, ret);
+		goto out_rbt;
+	}
+#endif /* CONFIG_WDT_501_PCI */
+
+	ret = misc_register (&wdtpci_miscdev);
+	if (ret) {
+		printk (KERN_ERR PFX "cannot register miscdev on minor=%d (err=%d)\n",
+			WATCHDOG_MINOR, ret);
+		goto out_misc;
+	}
+
+	printk(KERN_INFO PFX "initialized. heartbeat=%d sec (nowayout=%d)\n",
+		heartbeat, nowayout);
+#ifdef CONFIG_WDT_501_PCI
+	printk(KERN_INFO "wdt: Fan Tachometer is %s\n", (tachometer ? "Enabled" : "Disabled"));
+#endif /* CONFIG_WDT_501_PCI */
+
+	ret = 0;
+out:
+	return ret;
+
+out_misc:
+#ifdef CONFIG_WDT_501_PCI
+	misc_deregister(&temp_miscdev);
+out_rbt:
+#endif /* CONFIG_WDT_501_PCI */
+	unregister_reboot_notifier(&wdtpci_notifier);
+out_irq:
+	free_irq(irq, &wdtpci_miscdev);
+out_reg:
+	release_region (io, 16);
+out_pci:
+	pci_disable_device(dev);
+	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 */
+	misc_deregister(&wdtpci_miscdev);
+#ifdef CONFIG_WDT_501_PCI
+	misc_deregister(&temp_miscdev);
+#endif /* CONFIG_WDT_501_PCI */
+	unregister_reboot_notifier(&wdtpci_notifier);
+	free_irq(irq, &wdtpci_miscdev);
+	release_region(io, 16);
+	pci_disable_device(pdev);
+	dev_count--;
+}
+
+
+static struct pci_device_id wdtpci_pci_tbl[] = {
+	{
+		.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 xx 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)
+{
+	return pci_register_driver (&wdtpci_driver);
+}
+
+
+module_init(wdtpci_init);
+module_exit(wdtpci_cleanup);
+
+MODULE_AUTHOR("JP Nollmann, Alan Cox");
+MODULE_DESCRIPTION("Driver for the ICS PCI-WDT500/501 watchdog cards");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS_MISCDEV(WATCHDOG_MINOR);
+MODULE_ALIAS_MISCDEV(TEMP_MINOR);