aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorCalin A. Culianu <calin@ajvar.org>2006-01-14 16:20:46 -0500
committerLinus Torvalds <torvalds@g5.osdl.org>2006-01-14 21:27:07 -0500
commiteed6565f70ce3fc958e5a3483c48fc4a8e111bdc (patch)
tree43f3bb533401eff6197f8a0beebf690fc0b4feac
parentee7be5de357b8ff69afc8c39648b336cd917218a (diff)
[PATCH] Watchdog: Winsystems EPX-C3 SBC
This is a 2.6 patch that adds support for the watchdog timer built into the EPX-C3 single board computer manufactured by Winsystems, Inc. Driver details: This is for x86 only. This watchdog is pretty basic and simple. It is only configurable via jumpers on the SBC, and it only has either a 1.5s or 200s interval. The watchdog can either be auto-configured to start as soon as the machine powers up (bad idea for the 1.5s interval!) or it can be enabled and disabled by writing to io port 0x1ee. Petting the watchdog involves writing any value to io port 0x1ef. The only unfortunate thing about this watchdog (and it is not at all uncommmon in watchdogs that linux supports) is that it is not a PCI or ISA-PNP device and as such it isn't at all probeable. Either the watchdog exists as 2 bytes at 0x1ee, or it doesn't. Thus, using this driver on a machine that doesn't have that watchdog can potentially hang/crash the system, etc. So only use this driver if you in fact are on a Winsystems EPX-C3 SBC. Anyway this driver fits into the already-existing watchdog framework quite nicely and I already tested it on my EPX-C3 and it works like a charm. Signed-off-by: Calin A. Culianu <calin@ajvar.org> Signed-off-by: Andrew Morton <akpm@osdl.org> Signed-off-by: Linus Torvalds <torvalds@osdl.org>
-rw-r--r--drivers/char/watchdog/Kconfig22
-rw-r--r--drivers/char/watchdog/Makefile1
-rw-r--r--drivers/char/watchdog/sbc_epx_c3.c216
3 files changed, 239 insertions, 0 deletions
diff --git a/drivers/char/watchdog/Kconfig b/drivers/char/watchdog/Kconfig
index a6544790af60..f68aaa60fa8f 100644
--- a/drivers/char/watchdog/Kconfig
+++ b/drivers/char/watchdog/Kconfig
@@ -395,6 +395,28 @@ config MACHZ_WDT
395 To compile this driver as a module, choose M here: the 395 To compile this driver as a module, choose M here: the
396 module will be called machzwd. 396 module will be called machzwd.
397 397
398config SBC_EPX_C3_WATCHDOG
399 tristate "Winsystems SBC EPX-C3 watchdog"
400 depends on WATCHDOG && X86
401 ---help---
402 This is the driver for the built-in watchdog timer on the EPX-C3
403 Single-board computer made by Winsystems, Inc.
404
405 *Note*: This hardware watchdog is not probeable and thus there
406 is no way to know if writing to its IO address will corrupt
407 your system or have any real effect. The only way to be sure
408 that this driver does what you want is to make sure you
409 are runnning it on an EPX-C3 from Winsystems with the watchdog
410 timer at IO address 0x1ee and 0x1ef. It will write to both those
411 IO ports. Basically, the assumption is made that if you compile
412 this driver into your kernel and/or load it as a module, that you
413 know what you are doing and that you are in fact running on an
414 EPX-C3 board!
415
416 To compile this driver as a module, choose M here: the
417 module will be called sbc_epx_c3.
418
419
398# PowerPC Architecture 420# PowerPC Architecture
399 421
400config 8xx_WDT 422config 8xx_WDT
diff --git a/drivers/char/watchdog/Makefile b/drivers/char/watchdog/Makefile
index cfd0a3987710..4fa2ca8e943c 100644
--- a/drivers/char/watchdog/Makefile
+++ b/drivers/char/watchdog/Makefile
@@ -52,6 +52,7 @@ obj-$(CONFIG_W83627HF_WDT) += w83627hf_wdt.o
52obj-$(CONFIG_W83877F_WDT) += w83877f_wdt.o 52obj-$(CONFIG_W83877F_WDT) += w83877f_wdt.o
53obj-$(CONFIG_W83977F_WDT) += w83977f_wdt.o 53obj-$(CONFIG_W83977F_WDT) += w83977f_wdt.o
54obj-$(CONFIG_MACHZ_WDT) += machzwd.o 54obj-$(CONFIG_MACHZ_WDT) += machzwd.o
55obj-$(CONFIG_SBC_EPX_C3_WATCHDOG) += sbc_epx_c3.o
55 56
56# PowerPC Architecture 57# PowerPC Architecture
57obj-$(CONFIG_8xx_WDT) += mpc8xx_wdt.o 58obj-$(CONFIG_8xx_WDT) += mpc8xx_wdt.o
diff --git a/drivers/char/watchdog/sbc_epx_c3.c b/drivers/char/watchdog/sbc_epx_c3.c
new file mode 100644
index 000000000000..951764614ebf
--- /dev/null
+++ b/drivers/char/watchdog/sbc_epx_c3.c
@@ -0,0 +1,216 @@
1/*
2 * SBC EPX C3 0.1 A Hardware Watchdog Device for the Winsystems EPX-C3
3 * single board computer
4 *
5 * (c) Copyright 2006 Calin A. Culianu <calin@ajvar.org>, All Rights
6 * Reserved.
7 *
8 * This program is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU General Public License
10 * as published by the Free Software Foundation; either version
11 * 2 of the License, or (at your option) any later version.
12 *
13 * based on softdog.c by Alan Cox <alan@redhat.com>
14 */
15
16#include <linux/module.h>
17#include <linux/moduleparam.h>
18#include <linux/config.h>
19#include <linux/types.h>
20#include <linux/kernel.h>
21#include <linux/fs.h>
22#include <linux/mm.h>
23#include <linux/miscdevice.h>
24#include <linux/watchdog.h>
25#include <linux/notifier.h>
26#include <linux/reboot.h>
27#include <linux/init.h>
28#include <asm/uaccess.h>
29#include <asm/io.h>
30
31#define PFX "epx_c3: "
32static int epx_c3_alive;
33
34#define WATCHDOG_TIMEOUT 1 /* 1 sec default timeout */
35
36static int nowayout = WATCHDOG_NOWAYOUT;
37module_param(nowayout, int, 0);
38MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default=CONFIG_WATCHDOG_NOWAYOUT)");
39
40#define EPXC3_WATCHDOG_CTL_REG 0x1ee /* write 1 to enable, 0 to disable */
41#define EPXC3_WATCHDOG_PET_REG 0x1ef /* write anything to pet once enabled */
42
43static void epx_c3_start(void)
44{
45 outb(1, EPXC3_WATCHDOG_CTL_REG);
46}
47
48static void epx_c3_stop(void)
49{
50
51 outb(0, EPXC3_WATCHDOG_CTL_REG);
52
53 printk(KERN_INFO PFX "Stopped watchdog timer.\n");
54}
55
56static void epx_c3_pet(void)
57{
58 outb(1, EPXC3_WATCHDOG_PET_REG);
59}
60
61/*
62 * Allow only one person to hold it open
63 */
64static int epx_c3_open(struct inode *inode, struct file *file)
65{
66 if (epx_c3_alive)
67 return -EBUSY;
68
69 if (nowayout)
70 __module_get(THIS_MODULE);
71
72 /* Activate timer */
73 epx_c3_start();
74 epx_c3_pet();
75
76 epx_c3_alive = 1;
77 printk(KERN_INFO "Started watchdog timer.\n");
78
79 return nonseekable_open(inode, file);
80}
81
82static int epx_c3_release(struct inode *inode, struct file *file)
83{
84 /* Shut off the timer.
85 * Lock it in if it's a module and we defined ...NOWAYOUT */
86 if (!nowayout)
87 epx_c3_stop(); /* Turn the WDT off */
88
89 epx_c3_alive = 0;
90
91 return 0;
92}
93
94static ssize_t epx_c3_write(struct file *file, const char *data,
95 size_t len, loff_t *ppos)
96{
97 /* Refresh the timer. */
98 if (len)
99 epx_c3_pet();
100 return len;
101}
102
103static int epx_c3_ioctl(struct inode *inode, struct file *file,
104 unsigned int cmd, unsigned long arg)
105{
106 int options, retval = -EINVAL;
107 static struct watchdog_info ident = {
108 .options = WDIOF_KEEPALIVEPING |
109 WDIOF_MAGICCLOSE,
110 .firmware_version = 0,
111 .identity = "Winsystems EPX-C3 H/W Watchdog",
112 };
113
114 switch (cmd) {
115 case WDIOC_GETSUPPORT:
116 if (copy_to_user((struct watchdog_info *)arg,
117 &ident, sizeof(ident)))
118 return -EFAULT;
119 return 0;
120 case WDIOC_GETSTATUS:
121 case WDIOC_GETBOOTSTATUS:
122 return put_user(0,(int *)arg);
123 case WDIOC_KEEPALIVE:
124 epx_c3_pet();
125 return 0;
126 case WDIOC_GETTIMEOUT:
127 return put_user(WATCHDOG_TIMEOUT,(int *)arg);
128 case WDIOC_SETOPTIONS: {
129 if (get_user(options, (int *)arg))
130 return -EFAULT;
131
132 if (options & WDIOS_DISABLECARD) {
133 epx_c3_stop();
134 retval = 0;
135 }
136
137 if (options & WDIOS_ENABLECARD) {
138 epx_c3_start();
139 retval = 0;
140 }
141
142 return retval;
143 }
144 default:
145 return -ENOIOCTLCMD;
146 }
147}
148
149static int epx_c3_notify_sys(struct notifier_block *this, unsigned long code,
150 void *unused)
151{
152 if (code == SYS_DOWN || code == SYS_HALT)
153 epx_c3_stop(); /* Turn the WDT off */
154
155 return NOTIFY_DONE;
156}
157
158static struct file_operations epx_c3_fops = {
159 .owner = THIS_MODULE,
160 .llseek = no_llseek,
161 .write = epx_c3_write,
162 .ioctl = epx_c3_ioctl,
163 .open = epx_c3_open,
164 .release = epx_c3_release,
165};
166
167static struct miscdevice epx_c3_miscdev = {
168 .minor = WATCHDOG_MINOR,
169 .name = "watchdog",
170 .fops = &epx_c3_fops,
171};
172
173static struct notifier_block epx_c3_notifier = {
174 .notifier_call = epx_c3_notify_sys,
175};
176
177static const char banner[] __initdata =
178 KERN_INFO PFX "Hardware Watchdog Timer for Winsystems EPX-C3 SBC: 0.1\n";
179
180static int __init watchdog_init(void)
181{
182 int ret;
183
184 ret = register_reboot_notifier(&epx_c3_notifier);
185 if (ret) {
186 printk(KERN_ERR PFX "cannot register reboot notifier "
187 "(err=%d)\n", ret);
188 return ret;
189 }
190
191 ret = misc_register(&epx_c3_miscdev);
192 if (ret) {
193 printk(KERN_ERR PFX "cannot register miscdev on minor=%d "
194 "(err=%d)\n", WATCHDOG_MINOR, ret);
195 unregister_reboot_notifier(&epx_c3_notifier);
196 return ret;
197 }
198
199 printk(banner);
200
201 return 0;
202}
203
204static void __exit watchdog_exit(void)
205{
206 misc_deregister(&epx_c3_miscdev);
207 unregister_reboot_notifier(&epx_c3_notifier);
208}
209
210module_init(watchdog_init);
211module_exit(watchdog_exit);
212
213MODULE_AUTHOR("Calin A. Culianu <calin@ajvar.org>");
214MODULE_DESCRIPTION("Hardware Watchdog Device for Winsystems EPX-C3 SBC. Note that there is no way to probe for this device -- so only use it if you are *sure* you are runnning on this specific SBC system from Winsystems! It writes to IO ports 0x1ee and 0x1ef!");
215MODULE_LICENSE("GPL");
216MODULE_ALIAS_MISCDEV(WATCHDOG_MINOR);