diff options
Diffstat (limited to 'drivers/watchdog/wafer5823wdt.c')
-rw-r--r-- | drivers/watchdog/wafer5823wdt.c | 132 |
1 files changed, 71 insertions, 61 deletions
diff --git a/drivers/watchdog/wafer5823wdt.c b/drivers/watchdog/wafer5823wdt.c index 9e368091f799..68377ae171ff 100644 --- a/drivers/watchdog/wafer5823wdt.c +++ b/drivers/watchdog/wafer5823wdt.c | |||
@@ -1,11 +1,11 @@ | |||
1 | /* | 1 | /* |
2 | * ICP Wafer 5823 Single Board Computer WDT driver | 2 | * ICP Wafer 5823 Single Board Computer WDT driver |
3 | * http://www.icpamerica.com/wafer_5823.php | 3 | * http://www.icpamerica.com/wafer_5823.php |
4 | * May also work on other similar models | 4 | * May also work on other similar models |
5 | * | 5 | * |
6 | * (c) Copyright 2002 Justin Cormack <justin@street-vision.com> | 6 | * (c) Copyright 2002 Justin Cormack <justin@street-vision.com> |
7 | * | 7 | * |
8 | * Release 0.02 | 8 | * Release 0.02 |
9 | * | 9 | * |
10 | * Based on advantechwdt.c which is based on wdt.c. | 10 | * Based on advantechwdt.c which is based on wdt.c. |
11 | * Original copyright messages: | 11 | * Original copyright messages: |
@@ -36,8 +36,8 @@ | |||
36 | #include <linux/reboot.h> | 36 | #include <linux/reboot.h> |
37 | #include <linux/init.h> | 37 | #include <linux/init.h> |
38 | #include <linux/spinlock.h> | 38 | #include <linux/spinlock.h> |
39 | #include <asm/io.h> | 39 | #include <linux/io.h> |
40 | #include <asm/uaccess.h> | 40 | #include <linux/uaccess.h> |
41 | 41 | ||
42 | #define WATCHDOG_NAME "Wafer 5823 WDT" | 42 | #define WATCHDOG_NAME "Wafer 5823 WDT" |
43 | #define PFX WATCHDOG_NAME ": " | 43 | #define PFX WATCHDOG_NAME ": " |
@@ -50,10 +50,10 @@ static DEFINE_SPINLOCK(wafwdt_lock); | |||
50 | /* | 50 | /* |
51 | * You must set these - there is no sane way to probe for this board. | 51 | * You must set these - there is no sane way to probe for this board. |
52 | * | 52 | * |
53 | * To enable, write the timeout value in seconds (1 to 255) to I/O | 53 | * To enable, write the timeout value in seconds (1 to 255) to I/O |
54 | * port WDT_START, then read the port to start the watchdog. To pat | 54 | * port WDT_START, then read the port to start the watchdog. To pat |
55 | * the dog, read port WDT_STOP to stop the timer, then read WDT_START | 55 | * the dog, read port WDT_STOP to stop the timer, then read WDT_START |
56 | * to restart it again. | 56 | * to restart it again. |
57 | */ | 57 | */ |
58 | 58 | ||
59 | static int wdt_stop = 0x843; | 59 | static int wdt_stop = 0x843; |
@@ -61,11 +61,15 @@ static int wdt_start = 0x443; | |||
61 | 61 | ||
62 | static int timeout = WD_TIMO; /* in seconds */ | 62 | static int timeout = WD_TIMO; /* in seconds */ |
63 | module_param(timeout, int, 0); | 63 | module_param(timeout, int, 0); |
64 | MODULE_PARM_DESC(timeout, "Watchdog timeout in seconds. 1<= timeout <=255, default=" __MODULE_STRING(WD_TIMO) "."); | 64 | MODULE_PARM_DESC(timeout, |
65 | "Watchdog timeout in seconds. 1 <= timeout <= 255, default=" | ||
66 | __MODULE_STRING(WD_TIMO) "."); | ||
65 | 67 | ||
66 | static int nowayout = WATCHDOG_NOWAYOUT; | 68 | static int nowayout = WATCHDOG_NOWAYOUT; |
67 | module_param(nowayout, int, 0); | 69 | module_param(nowayout, int, 0); |
68 | MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default=" __MODULE_STRING(WATCHDOG_NOWAYOUT) ")"); | 70 | MODULE_PARM_DESC(nowayout, |
71 | "Watchdog cannot be stopped once started (default=" | ||
72 | __MODULE_STRING(WATCHDOG_NOWAYOUT) ")"); | ||
69 | 73 | ||
70 | static void wafwdt_ping(void) | 74 | static void wafwdt_ping(void) |
71 | { | 75 | { |
@@ -83,14 +87,14 @@ static void wafwdt_start(void) | |||
83 | inb_p(wdt_start); | 87 | inb_p(wdt_start); |
84 | } | 88 | } |
85 | 89 | ||
86 | static void | 90 | static void wafwdt_stop(void) |
87 | wafwdt_stop(void) | ||
88 | { | 91 | { |
89 | /* stop watchdog */ | 92 | /* stop watchdog */ |
90 | inb_p(wdt_stop); | 93 | inb_p(wdt_stop); |
91 | } | 94 | } |
92 | 95 | ||
93 | static ssize_t wafwdt_write(struct file *file, const char __user *buf, size_t count, loff_t * ppos) | 96 | static ssize_t wafwdt_write(struct file *file, const char __user *buf, |
97 | size_t count, loff_t *ppos) | ||
94 | { | 98 | { |
95 | /* See if we got the magic character 'V' and reload the timer */ | 99 | /* See if we got the magic character 'V' and reload the timer */ |
96 | if (count) { | 100 | if (count) { |
@@ -100,7 +104,8 @@ static ssize_t wafwdt_write(struct file *file, const char __user *buf, size_t co | |||
100 | /* In case it was set long ago */ | 104 | /* In case it was set long ago */ |
101 | expect_close = 0; | 105 | expect_close = 0; |
102 | 106 | ||
103 | /* scan to see whether or not we got the magic character */ | 107 | /* scan to see whether or not we got the magic |
108 | character */ | ||
104 | for (i = 0; i != count; i++) { | 109 | for (i = 0; i != count; i++) { |
105 | char c; | 110 | char c; |
106 | if (get_user(c, buf + i)) | 111 | if (get_user(c, buf + i)) |
@@ -109,27 +114,29 @@ static ssize_t wafwdt_write(struct file *file, const char __user *buf, size_t co | |||
109 | expect_close = 42; | 114 | expect_close = 42; |
110 | } | 115 | } |
111 | } | 116 | } |
112 | /* Well, anyhow someone wrote to us, we should return that favour */ | 117 | /* Well, anyhow someone wrote to us, we should |
118 | return that favour */ | ||
113 | wafwdt_ping(); | 119 | wafwdt_ping(); |
114 | } | 120 | } |
115 | return count; | 121 | return count; |
116 | } | 122 | } |
117 | 123 | ||
118 | static int wafwdt_ioctl(struct inode *inode, struct file *file, unsigned int cmd, | 124 | static long wafwdt_ioctl(struct file *file, unsigned int cmd, |
119 | unsigned long arg) | 125 | unsigned long arg) |
120 | { | 126 | { |
121 | int new_timeout; | 127 | int new_timeout; |
122 | void __user *argp = (void __user *)arg; | 128 | void __user *argp = (void __user *)arg; |
123 | int __user *p = argp; | 129 | int __user *p = argp; |
124 | static struct watchdog_info ident = { | 130 | static const struct watchdog_info ident = { |
125 | .options = WDIOF_KEEPALIVEPING | WDIOF_SETTIMEOUT | WDIOF_MAGICCLOSE, | 131 | .options = WDIOF_KEEPALIVEPING | WDIOF_SETTIMEOUT | |
132 | WDIOF_MAGICCLOSE, | ||
126 | .firmware_version = 1, | 133 | .firmware_version = 1, |
127 | .identity = "Wafer 5823 WDT", | 134 | .identity = "Wafer 5823 WDT", |
128 | }; | 135 | }; |
129 | 136 | ||
130 | switch (cmd) { | 137 | switch (cmd) { |
131 | case WDIOC_GETSUPPORT: | 138 | case WDIOC_GETSUPPORT: |
132 | if (copy_to_user(argp, &ident, sizeof (ident))) | 139 | if (copy_to_user(argp, &ident, sizeof(ident))) |
133 | return -EFAULT; | 140 | return -EFAULT; |
134 | break; | 141 | break; |
135 | 142 | ||
@@ -137,22 +144,6 @@ static int wafwdt_ioctl(struct inode *inode, struct file *file, unsigned int cmd | |||
137 | case WDIOC_GETBOOTSTATUS: | 144 | case WDIOC_GETBOOTSTATUS: |
138 | return put_user(0, p); | 145 | return put_user(0, p); |
139 | 146 | ||
140 | case WDIOC_KEEPALIVE: | ||
141 | wafwdt_ping(); | ||
142 | break; | ||
143 | |||
144 | case WDIOC_SETTIMEOUT: | ||
145 | if (get_user(new_timeout, p)) | ||
146 | return -EFAULT; | ||
147 | if ((new_timeout < 1) || (new_timeout > 255)) | ||
148 | return -EINVAL; | ||
149 | timeout = new_timeout; | ||
150 | wafwdt_stop(); | ||
151 | wafwdt_start(); | ||
152 | /* Fall */ | ||
153 | case WDIOC_GETTIMEOUT: | ||
154 | return put_user(timeout, p); | ||
155 | |||
156 | case WDIOC_SETOPTIONS: | 147 | case WDIOC_SETOPTIONS: |
157 | { | 148 | { |
158 | int options, retval = -EINVAL; | 149 | int options, retval = -EINVAL; |
@@ -173,6 +164,22 @@ static int wafwdt_ioctl(struct inode *inode, struct file *file, unsigned int cmd | |||
173 | return retval; | 164 | return retval; |
174 | } | 165 | } |
175 | 166 | ||
167 | case WDIOC_KEEPALIVE: | ||
168 | wafwdt_ping(); | ||
169 | break; | ||
170 | |||
171 | case WDIOC_SETTIMEOUT: | ||
172 | if (get_user(new_timeout, p)) | ||
173 | return -EFAULT; | ||
174 | if ((new_timeout < 1) || (new_timeout > 255)) | ||
175 | return -EINVAL; | ||
176 | timeout = new_timeout; | ||
177 | wafwdt_stop(); | ||
178 | wafwdt_start(); | ||
179 | /* Fall */ | ||
180 | case WDIOC_GETTIMEOUT: | ||
181 | return put_user(timeout, p); | ||
182 | |||
176 | default: | 183 | default: |
177 | return -ENOTTY; | 184 | return -ENOTTY; |
178 | } | 185 | } |
@@ -191,13 +198,13 @@ static int wafwdt_open(struct inode *inode, struct file *file) | |||
191 | return nonseekable_open(inode, file); | 198 | return nonseekable_open(inode, file); |
192 | } | 199 | } |
193 | 200 | ||
194 | static int | 201 | static int wafwdt_close(struct inode *inode, struct file *file) |
195 | wafwdt_close(struct inode *inode, struct file *file) | ||
196 | { | 202 | { |
197 | if (expect_close == 42) { | 203 | if (expect_close == 42) |
198 | wafwdt_stop(); | 204 | wafwdt_stop(); |
199 | } else { | 205 | else { |
200 | printk(KERN_CRIT PFX "WDT device closed unexpectedly. WDT will not stop!\n"); | 206 | printk(KERN_CRIT PFX |
207 | "WDT device closed unexpectedly. WDT will not stop!\n"); | ||
201 | wafwdt_ping(); | 208 | wafwdt_ping(); |
202 | } | 209 | } |
203 | clear_bit(0, &wafwdt_is_open); | 210 | clear_bit(0, &wafwdt_is_open); |
@@ -209,12 +216,11 @@ wafwdt_close(struct inode *inode, struct file *file) | |||
209 | * Notifier for system down | 216 | * Notifier for system down |
210 | */ | 217 | */ |
211 | 218 | ||
212 | static int wafwdt_notify_sys(struct notifier_block *this, unsigned long code, void *unused) | 219 | static int wafwdt_notify_sys(struct notifier_block *this, unsigned long code, |
220 | void *unused) | ||
213 | { | 221 | { |
214 | if (code == SYS_DOWN || code == SYS_HALT) { | 222 | if (code == SYS_DOWN || code == SYS_HALT) |
215 | /* Turn the WDT off */ | ||
216 | wafwdt_stop(); | 223 | wafwdt_stop(); |
217 | } | ||
218 | return NOTIFY_DONE; | 224 | return NOTIFY_DONE; |
219 | } | 225 | } |
220 | 226 | ||
@@ -226,7 +232,7 @@ static const struct file_operations wafwdt_fops = { | |||
226 | .owner = THIS_MODULE, | 232 | .owner = THIS_MODULE, |
227 | .llseek = no_llseek, | 233 | .llseek = no_llseek, |
228 | .write = wafwdt_write, | 234 | .write = wafwdt_write, |
229 | .ioctl = wafwdt_ioctl, | 235 | .unlocked_ioctl = wafwdt_ioctl, |
230 | .open = wafwdt_open, | 236 | .open = wafwdt_open, |
231 | .release = wafwdt_close, | 237 | .release = wafwdt_close, |
232 | }; | 238 | }; |
@@ -250,25 +256,28 @@ static int __init wafwdt_init(void) | |||
250 | { | 256 | { |
251 | int ret; | 257 | int ret; |
252 | 258 | ||
253 | printk(KERN_INFO "WDT driver for Wafer 5823 single board computer initialising.\n"); | 259 | printk(KERN_INFO |
260 | "WDT driver for Wafer 5823 single board computer initialising.\n"); | ||
254 | 261 | ||
255 | if (timeout < 1 || timeout > 255) { | 262 | if (timeout < 1 || timeout > 255) { |
256 | timeout = WD_TIMO; | 263 | timeout = WD_TIMO; |
257 | printk (KERN_INFO PFX "timeout value must be 1<=x<=255, using %d\n", | 264 | printk(KERN_INFO PFX |
258 | timeout); | 265 | "timeout value must be 1 <= x <= 255, using %d\n", |
266 | timeout); | ||
259 | } | 267 | } |
260 | 268 | ||
261 | if (wdt_stop != wdt_start) { | 269 | if (wdt_stop != wdt_start) { |
262 | if(!request_region(wdt_stop, 1, "Wafer 5823 WDT")) { | 270 | if (!request_region(wdt_stop, 1, "Wafer 5823 WDT")) { |
263 | printk (KERN_ERR PFX "I/O address 0x%04x already in use\n", | 271 | printk(KERN_ERR PFX |
264 | wdt_stop); | 272 | "I/O address 0x%04x already in use\n", |
273 | wdt_stop); | ||
265 | ret = -EIO; | 274 | ret = -EIO; |
266 | goto error; | 275 | goto error; |
267 | } | 276 | } |
268 | } | 277 | } |
269 | 278 | ||
270 | if(!request_region(wdt_start, 1, "Wafer 5823 WDT")) { | 279 | if (!request_region(wdt_start, 1, "Wafer 5823 WDT")) { |
271 | printk (KERN_ERR PFX "I/O address 0x%04x already in use\n", | 280 | printk(KERN_ERR PFX "I/O address 0x%04x already in use\n", |
272 | wdt_start); | 281 | wdt_start); |
273 | ret = -EIO; | 282 | ret = -EIO; |
274 | goto error2; | 283 | goto error2; |
@@ -276,19 +285,20 @@ static int __init wafwdt_init(void) | |||
276 | 285 | ||
277 | ret = register_reboot_notifier(&wafwdt_notifier); | 286 | ret = register_reboot_notifier(&wafwdt_notifier); |
278 | if (ret != 0) { | 287 | if (ret != 0) { |
279 | printk (KERN_ERR PFX "cannot register reboot notifier (err=%d)\n", | 288 | printk(KERN_ERR PFX |
280 | ret); | 289 | "cannot register reboot notifier (err=%d)\n", ret); |
281 | goto error3; | 290 | goto error3; |
282 | } | 291 | } |
283 | 292 | ||
284 | ret = misc_register(&wafwdt_miscdev); | 293 | ret = misc_register(&wafwdt_miscdev); |
285 | if (ret != 0) { | 294 | if (ret != 0) { |
286 | printk (KERN_ERR PFX "cannot register miscdev on minor=%d (err=%d)\n", | 295 | printk(KERN_ERR PFX |
287 | WATCHDOG_MINOR, ret); | 296 | "cannot register miscdev on minor=%d (err=%d)\n", |
297 | WATCHDOG_MINOR, ret); | ||
288 | goto error4; | 298 | goto error4; |
289 | } | 299 | } |
290 | 300 | ||
291 | printk (KERN_INFO PFX "initialized. timeout=%d sec (nowayout=%d)\n", | 301 | printk(KERN_INFO PFX "initialized. timeout=%d sec (nowayout=%d)\n", |
292 | timeout, nowayout); | 302 | timeout, nowayout); |
293 | 303 | ||
294 | return ret; | 304 | return ret; |
@@ -307,7 +317,7 @@ static void __exit wafwdt_exit(void) | |||
307 | { | 317 | { |
308 | misc_deregister(&wafwdt_miscdev); | 318 | misc_deregister(&wafwdt_miscdev); |
309 | unregister_reboot_notifier(&wafwdt_notifier); | 319 | unregister_reboot_notifier(&wafwdt_notifier); |
310 | if(wdt_stop != wdt_start) | 320 | if (wdt_stop != wdt_start) |
311 | release_region(wdt_stop, 1); | 321 | release_region(wdt_stop, 1); |
312 | release_region(wdt_start, 1); | 322 | release_region(wdt_start, 1); |
313 | } | 323 | } |