aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/char/watchdog/advantechwdt.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/char/watchdog/advantechwdt.c')
-rw-r--r--drivers/char/watchdog/advantechwdt.c142
1 files changed, 88 insertions, 54 deletions
diff --git a/drivers/char/watchdog/advantechwdt.c b/drivers/char/watchdog/advantechwdt.c
index 9d732769ba01..8121cc247343 100644
--- a/drivers/char/watchdog/advantechwdt.c
+++ b/drivers/char/watchdog/advantechwdt.c
@@ -35,18 +35,19 @@
35#include <linux/watchdog.h> 35#include <linux/watchdog.h>
36#include <linux/fs.h> 36#include <linux/fs.h>
37#include <linux/ioport.h> 37#include <linux/ioport.h>
38#include <linux/notifier.h> 38#include <linux/platform_device.h>
39#include <linux/reboot.h>
40#include <linux/init.h> 39#include <linux/init.h>
41 40
42#include <asm/io.h> 41#include <asm/io.h>
43#include <asm/uaccess.h> 42#include <asm/uaccess.h>
44#include <asm/system.h> 43#include <asm/system.h>
45 44
45#define DRV_NAME "advantechwdt"
46#define PFX DRV_NAME ": "
46#define WATCHDOG_NAME "Advantech WDT" 47#define WATCHDOG_NAME "Advantech WDT"
47#define PFX WATCHDOG_NAME ": "
48#define WATCHDOG_TIMEOUT 60 /* 60 sec default timeout */ 48#define WATCHDOG_TIMEOUT 60 /* 60 sec default timeout */
49 49
50static struct platform_device *advwdt_platform_device; /* the watchdog platform device */
50static unsigned long advwdt_is_open; 51static unsigned long advwdt_is_open;
51static char adv_expect_close; 52static char adv_expect_close;
52 53
@@ -75,10 +76,10 @@ MODULE_PARM_DESC(timeout, "Watchdog timeout in seconds. 1<= timeout <=63, defaul
75 76
76static int nowayout = WATCHDOG_NOWAYOUT; 77static int nowayout = WATCHDOG_NOWAYOUT;
77module_param(nowayout, int, 0); 78module_param(nowayout, int, 0);
78MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default=CONFIG_WATCHDOG_NOWAYOUT)"); 79MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default=" __MODULE_STRING(WATCHDOG_NOWAYOUT) ")");
79 80
80/* 81/*
81 * Kernel methods. 82 * Watchdog Operations
82 */ 83 */
83 84
84static void 85static void
@@ -94,6 +95,20 @@ advwdt_disable(void)
94 inb_p(wdt_stop); 95 inb_p(wdt_stop);
95} 96}
96 97
98static int
99advwdt_set_heartbeat(int t)
100{
101 if ((t < 1) || (t > 63))
102 return -EINVAL;
103
104 timeout = t;
105 return 0;
106}
107
108/*
109 * /dev/watchdog handling
110 */
111
97static ssize_t 112static ssize_t
98advwdt_write(struct file *file, const char __user *buf, size_t count, loff_t *ppos) 113advwdt_write(struct file *file, const char __user *buf, size_t count, loff_t *ppos)
99{ 114{
@@ -126,7 +141,7 @@ advwdt_ioctl(struct inode *inode, struct file *file, unsigned int cmd,
126 static struct watchdog_info ident = { 141 static struct watchdog_info ident = {
127 .options = WDIOF_KEEPALIVEPING | WDIOF_SETTIMEOUT | WDIOF_MAGICCLOSE, 142 .options = WDIOF_KEEPALIVEPING | WDIOF_SETTIMEOUT | WDIOF_MAGICCLOSE,
128 .firmware_version = 1, 143 .firmware_version = 1,
129 .identity = "Advantech WDT", 144 .identity = WATCHDOG_NAME,
130 }; 145 };
131 146
132 switch (cmd) { 147 switch (cmd) {
@@ -146,9 +161,8 @@ advwdt_ioctl(struct inode *inode, struct file *file, unsigned int cmd,
146 case WDIOC_SETTIMEOUT: 161 case WDIOC_SETTIMEOUT:
147 if (get_user(new_timeout, p)) 162 if (get_user(new_timeout, p))
148 return -EFAULT; 163 return -EFAULT;
149 if ((new_timeout < 1) || (new_timeout > 63)) 164 if (advwdt_set_heartbeat(new_timeout))
150 return -EINVAL; 165 return -EINVAL;
151 timeout = new_timeout;
152 advwdt_ping(); 166 advwdt_ping();
153 /* Fall */ 167 /* Fall */
154 168
@@ -209,21 +223,6 @@ advwdt_close(struct inode *inode, struct file *file)
209} 223}
210 224
211/* 225/*
212 * Notifier for system down
213 */
214
215static int
216advwdt_notify_sys(struct notifier_block *this, unsigned long code,
217 void *unused)
218{
219 if (code == SYS_DOWN || code == SYS_HALT) {
220 /* Turn the WDT off */
221 advwdt_disable();
222 }
223 return NOTIFY_DONE;
224}
225
226/*
227 * Kernel Interfaces 226 * Kernel Interfaces
228 */ 227 */
229 228
@@ -237,33 +236,20 @@ static const struct file_operations advwdt_fops = {
237}; 236};
238 237
239static struct miscdevice advwdt_miscdev = { 238static struct miscdevice advwdt_miscdev = {
240 .minor = WATCHDOG_MINOR, 239 .minor = WATCHDOG_MINOR,
241 .name = "watchdog", 240 .name = "watchdog",
242 .fops = &advwdt_fops, 241 .fops = &advwdt_fops,
243}; 242};
244 243
245/* 244/*
246 * The WDT needs to learn about soft shutdowns in order to 245 * Init & exit routines
247 * turn the timebomb registers off.
248 */ 246 */
249 247
250static struct notifier_block advwdt_notifier = { 248static int __devinit
251 .notifier_call = advwdt_notify_sys, 249advwdt_probe(struct platform_device *dev)
252};
253
254static int __init
255advwdt_init(void)
256{ 250{
257 int ret; 251 int ret;
258 252
259 printk(KERN_INFO "WDT driver for Advantech single board computer initialising.\n");
260
261 if (timeout < 1 || timeout > 63) {
262 timeout = WATCHDOG_TIMEOUT;
263 printk (KERN_INFO PFX "timeout value must be 1<=x<=63, using %d\n",
264 timeout);
265 }
266
267 if (wdt_stop != wdt_start) { 253 if (wdt_stop != wdt_start) {
268 if (!request_region(wdt_stop, 1, WATCHDOG_NAME)) { 254 if (!request_region(wdt_stop, 1, WATCHDOG_NAME)) {
269 printk (KERN_ERR PFX "I/O address 0x%04x already in use\n", 255 printk (KERN_ERR PFX "I/O address 0x%04x already in use\n",
@@ -280,18 +266,18 @@ advwdt_init(void)
280 goto unreg_stop; 266 goto unreg_stop;
281 } 267 }
282 268
283 ret = register_reboot_notifier(&advwdt_notifier); 269 /* Check that the heartbeat value is within it's range ; if not reset to the default */
284 if (ret != 0) { 270 if (advwdt_set_heartbeat(timeout)) {
285 printk (KERN_ERR PFX "cannot register reboot notifier (err=%d)\n", 271 advwdt_set_heartbeat(WATCHDOG_TIMEOUT);
286 ret); 272 printk (KERN_INFO PFX "timeout value must be 1<=x<=63, using %d\n",
287 goto unreg_regions; 273 timeout);
288 } 274 }
289 275
290 ret = misc_register(&advwdt_miscdev); 276 ret = misc_register(&advwdt_miscdev);
291 if (ret != 0) { 277 if (ret != 0) {
292 printk (KERN_ERR PFX "cannot register miscdev on minor=%d (err=%d)\n", 278 printk (KERN_ERR PFX "cannot register miscdev on minor=%d (err=%d)\n",
293 WATCHDOG_MINOR, ret); 279 WATCHDOG_MINOR, ret);
294 goto unreg_reboot; 280 goto unreg_regions;
295 } 281 }
296 282
297 printk (KERN_INFO PFX "initialized. timeout=%d sec (nowayout=%d)\n", 283 printk (KERN_INFO PFX "initialized. timeout=%d sec (nowayout=%d)\n",
@@ -299,8 +285,6 @@ advwdt_init(void)
299 285
300out: 286out:
301 return ret; 287 return ret;
302unreg_reboot:
303 unregister_reboot_notifier(&advwdt_notifier);
304unreg_regions: 288unreg_regions:
305 release_region(wdt_start, 1); 289 release_region(wdt_start, 1);
306unreg_stop: 290unreg_stop:
@@ -309,14 +293,64 @@ unreg_stop:
309 goto out; 293 goto out;
310} 294}
311 295
312static void __exit 296static int __devexit
313advwdt_exit(void) 297advwdt_remove(struct platform_device *dev)
314{ 298{
315 misc_deregister(&advwdt_miscdev); 299 misc_deregister(&advwdt_miscdev);
316 unregister_reboot_notifier(&advwdt_notifier); 300 release_region(wdt_start,1);
317 if(wdt_stop != wdt_start) 301 if(wdt_stop != wdt_start)
318 release_region(wdt_stop,1); 302 release_region(wdt_stop,1);
319 release_region(wdt_start,1); 303
304 return 0;
305}
306
307static void
308advwdt_shutdown(struct platform_device *dev)
309{
310 /* Turn the WDT off if we have a soft shutdown */
311 advwdt_disable();
312}
313
314static struct platform_driver advwdt_driver = {
315 .probe = advwdt_probe,
316 .remove = __devexit_p(advwdt_remove),
317 .shutdown = advwdt_shutdown,
318 .driver = {
319 .owner = THIS_MODULE,
320 .name = DRV_NAME,
321 },
322};
323
324static int __init
325advwdt_init(void)
326{
327 int err;
328
329 printk(KERN_INFO "WDT driver for Advantech single board computer initialising.\n");
330
331 err = platform_driver_register(&advwdt_driver);
332 if (err)
333 return err;
334
335 advwdt_platform_device = platform_device_register_simple(DRV_NAME, -1, NULL, 0);
336 if (IS_ERR(advwdt_platform_device)) {
337 err = PTR_ERR(advwdt_platform_device);
338 goto unreg_platform_driver;
339 }
340
341 return 0;
342
343unreg_platform_driver:
344 platform_driver_unregister(&advwdt_driver);
345 return err;
346}
347
348static void __exit
349advwdt_exit(void)
350{
351 platform_device_unregister(advwdt_platform_device);
352 platform_driver_unregister(&advwdt_driver);
353 printk(KERN_INFO PFX "Watchdog Module Unloaded.\n");
320} 354}
321 355
322module_init(advwdt_init); 356module_init(advwdt_init);