diff options
Diffstat (limited to 'drivers/watchdog/advantechwdt.c')
-rw-r--r-- | drivers/watchdog/advantechwdt.c | 162 |
1 files changed, 76 insertions, 86 deletions
diff --git a/drivers/watchdog/advantechwdt.c b/drivers/watchdog/advantechwdt.c index 8121cc247343..a5110f93a755 100644 --- a/drivers/watchdog/advantechwdt.c +++ b/drivers/watchdog/advantechwdt.c | |||
@@ -37,9 +37,9 @@ | |||
37 | #include <linux/ioport.h> | 37 | #include <linux/ioport.h> |
38 | #include <linux/platform_device.h> | 38 | #include <linux/platform_device.h> |
39 | #include <linux/init.h> | 39 | #include <linux/init.h> |
40 | #include <linux/io.h> | ||
41 | #include <linux/uaccess.h> | ||
40 | 42 | ||
41 | #include <asm/io.h> | ||
42 | #include <asm/uaccess.h> | ||
43 | #include <asm/system.h> | 43 | #include <asm/system.h> |
44 | 44 | ||
45 | #define DRV_NAME "advantechwdt" | 45 | #define DRV_NAME "advantechwdt" |
@@ -47,7 +47,8 @@ | |||
47 | #define WATCHDOG_NAME "Advantech WDT" | 47 | #define WATCHDOG_NAME "Advantech WDT" |
48 | #define WATCHDOG_TIMEOUT 60 /* 60 sec default timeout */ | 48 | #define WATCHDOG_TIMEOUT 60 /* 60 sec default timeout */ |
49 | 49 | ||
50 | static struct platform_device *advwdt_platform_device; /* the watchdog platform device */ | 50 | /* the watchdog platform device */ |
51 | static struct platform_device *advwdt_platform_device; | ||
51 | static unsigned long advwdt_is_open; | 52 | static unsigned long advwdt_is_open; |
52 | static char adv_expect_close; | 53 | static char adv_expect_close; |
53 | 54 | ||
@@ -72,35 +73,35 @@ MODULE_PARM_DESC(wdt_start, "Advantech WDT 'start' io port (default 0x443)"); | |||
72 | 73 | ||
73 | static int timeout = WATCHDOG_TIMEOUT; /* in seconds */ | 74 | static int timeout = WATCHDOG_TIMEOUT; /* in seconds */ |
74 | module_param(timeout, int, 0); | 75 | module_param(timeout, int, 0); |
75 | MODULE_PARM_DESC(timeout, "Watchdog timeout in seconds. 1<= timeout <=63, default=" __MODULE_STRING(WATCHDOG_TIMEOUT) "."); | 76 | MODULE_PARM_DESC(timeout, |
77 | "Watchdog timeout in seconds. 1<= timeout <=63, default=" | ||
78 | __MODULE_STRING(WATCHDOG_TIMEOUT) "."); | ||
76 | 79 | ||
77 | static int nowayout = WATCHDOG_NOWAYOUT; | 80 | static int nowayout = WATCHDOG_NOWAYOUT; |
78 | module_param(nowayout, int, 0); | 81 | module_param(nowayout, int, 0); |
79 | MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default=" __MODULE_STRING(WATCHDOG_NOWAYOUT) ")"); | 82 | MODULE_PARM_DESC(nowayout, |
83 | "Watchdog cannot be stopped once started (default=" | ||
84 | __MODULE_STRING(WATCHDOG_NOWAYOUT) ")"); | ||
80 | 85 | ||
81 | /* | 86 | /* |
82 | * Watchdog Operations | 87 | * Watchdog Operations |
83 | */ | 88 | */ |
84 | 89 | ||
85 | static void | 90 | static void advwdt_ping(void) |
86 | advwdt_ping(void) | ||
87 | { | 91 | { |
88 | /* Write a watchdog value */ | 92 | /* Write a watchdog value */ |
89 | outb_p(timeout, wdt_start); | 93 | outb_p(timeout, wdt_start); |
90 | } | 94 | } |
91 | 95 | ||
92 | static void | 96 | static void advwdt_disable(void) |
93 | advwdt_disable(void) | ||
94 | { | 97 | { |
95 | inb_p(wdt_stop); | 98 | inb_p(wdt_stop); |
96 | } | 99 | } |
97 | 100 | ||
98 | static int | 101 | static int advwdt_set_heartbeat(int t) |
99 | advwdt_set_heartbeat(int t) | ||
100 | { | 102 | { |
101 | if ((t < 1) || (t > 63)) | 103 | if (t < 1 || t > 63) |
102 | return -EINVAL; | 104 | return -EINVAL; |
103 | |||
104 | timeout = t; | 105 | timeout = t; |
105 | return 0; | 106 | return 0; |
106 | } | 107 | } |
@@ -109,8 +110,8 @@ advwdt_set_heartbeat(int t) | |||
109 | * /dev/watchdog handling | 110 | * /dev/watchdog handling |
110 | */ | 111 | */ |
111 | 112 | ||
112 | static ssize_t | 113 | static ssize_t advwdt_write(struct file *file, const char __user *buf, |
113 | advwdt_write(struct file *file, const char __user *buf, size_t count, loff_t *ppos) | 114 | size_t count, loff_t *ppos) |
114 | { | 115 | { |
115 | if (count) { | 116 | if (count) { |
116 | if (!nowayout) { | 117 | if (!nowayout) { |
@@ -120,7 +121,7 @@ advwdt_write(struct file *file, const char __user *buf, size_t count, loff_t *pp | |||
120 | 121 | ||
121 | for (i = 0; i != count; i++) { | 122 | for (i = 0; i != count; i++) { |
122 | char c; | 123 | char c; |
123 | if (get_user(c, buf+i)) | 124 | if (get_user(c, buf + i)) |
124 | return -EFAULT; | 125 | return -EFAULT; |
125 | if (c == 'V') | 126 | if (c == 'V') |
126 | adv_expect_close = 42; | 127 | adv_expect_close = 42; |
@@ -131,9 +132,7 @@ advwdt_write(struct file *file, const char __user *buf, size_t count, loff_t *pp | |||
131 | return count; | 132 | return count; |
132 | } | 133 | } |
133 | 134 | ||
134 | static int | 135 | static long advwdt_ioctl(struct file *file, unsigned int cmd, unsigned long arg) |
135 | advwdt_ioctl(struct inode *inode, struct file *file, unsigned int cmd, | ||
136 | unsigned long arg) | ||
137 | { | 136 | { |
138 | int new_timeout; | 137 | int new_timeout; |
139 | void __user *argp = (void __user *)arg; | 138 | void __user *argp = (void __user *)arg; |
@@ -146,57 +145,50 @@ advwdt_ioctl(struct inode *inode, struct file *file, unsigned int cmd, | |||
146 | 145 | ||
147 | switch (cmd) { | 146 | switch (cmd) { |
148 | case WDIOC_GETSUPPORT: | 147 | case WDIOC_GETSUPPORT: |
149 | if (copy_to_user(argp, &ident, sizeof(ident))) | 148 | if (copy_to_user(argp, &ident, sizeof(ident))) |
150 | return -EFAULT; | 149 | return -EFAULT; |
151 | break; | 150 | break; |
152 | 151 | ||
153 | case WDIOC_GETSTATUS: | 152 | case WDIOC_GETSTATUS: |
154 | case WDIOC_GETBOOTSTATUS: | 153 | case WDIOC_GETBOOTSTATUS: |
155 | return put_user(0, p); | 154 | return put_user(0, p); |
156 | |||
157 | case WDIOC_KEEPALIVE: | ||
158 | advwdt_ping(); | ||
159 | break; | ||
160 | |||
161 | case WDIOC_SETTIMEOUT: | ||
162 | if (get_user(new_timeout, p)) | ||
163 | return -EFAULT; | ||
164 | if (advwdt_set_heartbeat(new_timeout)) | ||
165 | return -EINVAL; | ||
166 | advwdt_ping(); | ||
167 | /* Fall */ | ||
168 | |||
169 | case WDIOC_GETTIMEOUT: | ||
170 | return put_user(timeout, p); | ||
171 | 155 | ||
172 | case WDIOC_SETOPTIONS: | 156 | case WDIOC_SETOPTIONS: |
173 | { | 157 | { |
174 | int options, retval = -EINVAL; | 158 | int options, retval = -EINVAL; |
175 | |||
176 | if (get_user(options, p)) | ||
177 | return -EFAULT; | ||
178 | |||
179 | if (options & WDIOS_DISABLECARD) { | ||
180 | advwdt_disable(); | ||
181 | retval = 0; | ||
182 | } | ||
183 | 159 | ||
184 | if (options & WDIOS_ENABLECARD) { | 160 | if (get_user(options, p)) |
185 | advwdt_ping(); | 161 | return -EFAULT; |
186 | retval = 0; | 162 | if (options & WDIOS_DISABLECARD) { |
187 | } | 163 | advwdt_disable(); |
188 | 164 | retval = 0; | |
189 | return retval; | 165 | } |
166 | if (options & WDIOS_ENABLECARD) { | ||
167 | advwdt_ping(); | ||
168 | retval = 0; | ||
169 | } | ||
170 | return retval; | ||
190 | } | 171 | } |
172 | case WDIOC_KEEPALIVE: | ||
173 | advwdt_ping(); | ||
174 | break; | ||
191 | 175 | ||
176 | case WDIOC_SETTIMEOUT: | ||
177 | if (get_user(new_timeout, p)) | ||
178 | return -EFAULT; | ||
179 | if (advwdt_set_heartbeat(new_timeout)) | ||
180 | return -EINVAL; | ||
181 | advwdt_ping(); | ||
182 | /* Fall */ | ||
183 | case WDIOC_GETTIMEOUT: | ||
184 | return put_user(timeout, p); | ||
192 | default: | 185 | default: |
193 | return -ENOTTY; | 186 | return -ENOTTY; |
194 | } | 187 | } |
195 | return 0; | 188 | return 0; |
196 | } | 189 | } |
197 | 190 | ||
198 | static int | 191 | static int advwdt_open(struct inode *inode, struct file *file) |
199 | advwdt_open(struct inode *inode, struct file *file) | ||
200 | { | 192 | { |
201 | if (test_and_set_bit(0, &advwdt_is_open)) | 193 | if (test_and_set_bit(0, &advwdt_is_open)) |
202 | return -EBUSY; | 194 | return -EBUSY; |
@@ -208,13 +200,13 @@ advwdt_open(struct inode *inode, struct file *file) | |||
208 | return nonseekable_open(inode, file); | 200 | return nonseekable_open(inode, file); |
209 | } | 201 | } |
210 | 202 | ||
211 | static int | 203 | static int advwdt_close(struct inode *inode, struct file *file) |
212 | advwdt_close(struct inode *inode, struct file *file) | ||
213 | { | 204 | { |
214 | if (adv_expect_close == 42) { | 205 | if (adv_expect_close == 42) { |
215 | advwdt_disable(); | 206 | advwdt_disable(); |
216 | } else { | 207 | } else { |
217 | printk(KERN_CRIT PFX "Unexpected close, not stopping watchdog!\n"); | 208 | printk(KERN_CRIT PFX |
209 | "Unexpected close, not stopping watchdog!\n"); | ||
218 | advwdt_ping(); | 210 | advwdt_ping(); |
219 | } | 211 | } |
220 | clear_bit(0, &advwdt_is_open); | 212 | clear_bit(0, &advwdt_is_open); |
@@ -230,7 +222,7 @@ static const struct file_operations advwdt_fops = { | |||
230 | .owner = THIS_MODULE, | 222 | .owner = THIS_MODULE, |
231 | .llseek = no_llseek, | 223 | .llseek = no_llseek, |
232 | .write = advwdt_write, | 224 | .write = advwdt_write, |
233 | .ioctl = advwdt_ioctl, | 225 | .unlocked_ioctl = advwdt_ioctl, |
234 | .open = advwdt_open, | 226 | .open = advwdt_open, |
235 | .release = advwdt_close, | 227 | .release = advwdt_close, |
236 | }; | 228 | }; |
@@ -245,23 +237,24 @@ static struct miscdevice advwdt_miscdev = { | |||
245 | * Init & exit routines | 237 | * Init & exit routines |
246 | */ | 238 | */ |
247 | 239 | ||
248 | static int __devinit | 240 | static int __devinit advwdt_probe(struct platform_device *dev) |
249 | advwdt_probe(struct platform_device *dev) | ||
250 | { | 241 | { |
251 | int ret; | 242 | int ret; |
252 | 243 | ||
253 | if (wdt_stop != wdt_start) { | 244 | if (wdt_stop != wdt_start) { |
254 | if (!request_region(wdt_stop, 1, WATCHDOG_NAME)) { | 245 | if (!request_region(wdt_stop, 1, WATCHDOG_NAME)) { |
255 | printk (KERN_ERR PFX "I/O address 0x%04x already in use\n", | 246 | printk(KERN_ERR PFX |
256 | wdt_stop); | 247 | "I/O address 0x%04x already in use\n", |
248 | wdt_stop); | ||
257 | ret = -EIO; | 249 | ret = -EIO; |
258 | goto out; | 250 | goto out; |
259 | } | 251 | } |
260 | } | 252 | } |
261 | 253 | ||
262 | if (!request_region(wdt_start, 1, WATCHDOG_NAME)) { | 254 | if (!request_region(wdt_start, 1, WATCHDOG_NAME)) { |
263 | printk (KERN_ERR PFX "I/O address 0x%04x already in use\n", | 255 | printk(KERN_ERR PFX |
264 | wdt_start); | 256 | "I/O address 0x%04x already in use\n", |
257 | wdt_start); | ||
265 | ret = -EIO; | 258 | ret = -EIO; |
266 | goto unreg_stop; | 259 | goto unreg_stop; |
267 | } | 260 | } |
@@ -269,20 +262,19 @@ advwdt_probe(struct platform_device *dev) | |||
269 | /* Check that the heartbeat value is within it's range ; if not reset to the default */ | 262 | /* Check that the heartbeat value is within it's range ; if not reset to the default */ |
270 | if (advwdt_set_heartbeat(timeout)) { | 263 | if (advwdt_set_heartbeat(timeout)) { |
271 | advwdt_set_heartbeat(WATCHDOG_TIMEOUT); | 264 | advwdt_set_heartbeat(WATCHDOG_TIMEOUT); |
272 | printk (KERN_INFO PFX "timeout value must be 1<=x<=63, using %d\n", | 265 | printk(KERN_INFO PFX |
273 | timeout); | 266 | "timeout value must be 1<=x<=63, using %d\n", timeout); |
274 | } | 267 | } |
275 | 268 | ||
276 | ret = misc_register(&advwdt_miscdev); | 269 | ret = misc_register(&advwdt_miscdev); |
277 | if (ret != 0) { | 270 | if (ret != 0) { |
278 | printk (KERN_ERR PFX "cannot register miscdev on minor=%d (err=%d)\n", | 271 | printk(KERN_ERR PFX |
279 | WATCHDOG_MINOR, ret); | 272 | "cannot register miscdev on minor=%d (err=%d)\n", |
273 | WATCHDOG_MINOR, ret); | ||
280 | goto unreg_regions; | 274 | goto unreg_regions; |
281 | } | 275 | } |
282 | 276 | printk(KERN_INFO PFX "initialized. timeout=%d sec (nowayout=%d)\n", | |
283 | printk (KERN_INFO PFX "initialized. timeout=%d sec (nowayout=%d)\n", | ||
284 | timeout, nowayout); | 277 | timeout, nowayout); |
285 | |||
286 | out: | 278 | out: |
287 | return ret; | 279 | return ret; |
288 | unreg_regions: | 280 | unreg_regions: |
@@ -293,19 +285,17 @@ unreg_stop: | |||
293 | goto out; | 285 | goto out; |
294 | } | 286 | } |
295 | 287 | ||
296 | static int __devexit | 288 | static int __devexit advwdt_remove(struct platform_device *dev) |
297 | advwdt_remove(struct platform_device *dev) | ||
298 | { | 289 | { |
299 | misc_deregister(&advwdt_miscdev); | 290 | misc_deregister(&advwdt_miscdev); |
300 | release_region(wdt_start,1); | 291 | release_region(wdt_start, 1); |
301 | if(wdt_stop != wdt_start) | 292 | if (wdt_stop != wdt_start) |
302 | release_region(wdt_stop,1); | 293 | release_region(wdt_stop, 1); |
303 | 294 | ||
304 | return 0; | 295 | return 0; |
305 | } | 296 | } |
306 | 297 | ||
307 | static void | 298 | static void advwdt_shutdown(struct platform_device *dev) |
308 | advwdt_shutdown(struct platform_device *dev) | ||
309 | { | 299 | { |
310 | /* Turn the WDT off if we have a soft shutdown */ | 300 | /* Turn the WDT off if we have a soft shutdown */ |
311 | advwdt_disable(); | 301 | advwdt_disable(); |
@@ -321,18 +311,19 @@ static struct platform_driver advwdt_driver = { | |||
321 | }, | 311 | }, |
322 | }; | 312 | }; |
323 | 313 | ||
324 | static int __init | 314 | static int __init advwdt_init(void) |
325 | advwdt_init(void) | ||
326 | { | 315 | { |
327 | int err; | 316 | int err; |
328 | 317 | ||
329 | printk(KERN_INFO "WDT driver for Advantech single board computer initialising.\n"); | 318 | printk(KERN_INFO |
319 | "WDT driver for Advantech single board computer initialising.\n"); | ||
330 | 320 | ||
331 | err = platform_driver_register(&advwdt_driver); | 321 | err = platform_driver_register(&advwdt_driver); |
332 | if (err) | 322 | if (err) |
333 | return err; | 323 | return err; |
334 | 324 | ||
335 | advwdt_platform_device = platform_device_register_simple(DRV_NAME, -1, NULL, 0); | 325 | advwdt_platform_device = platform_device_register_simple(DRV_NAME, |
326 | -1, NULL, 0); | ||
336 | if (IS_ERR(advwdt_platform_device)) { | 327 | if (IS_ERR(advwdt_platform_device)) { |
337 | err = PTR_ERR(advwdt_platform_device); | 328 | err = PTR_ERR(advwdt_platform_device); |
338 | goto unreg_platform_driver; | 329 | goto unreg_platform_driver; |
@@ -345,8 +336,7 @@ unreg_platform_driver: | |||
345 | return err; | 336 | return err; |
346 | } | 337 | } |
347 | 338 | ||
348 | static void __exit | 339 | static void __exit advwdt_exit(void) |
349 | advwdt_exit(void) | ||
350 | { | 340 | { |
351 | platform_device_unregister(advwdt_platform_device); | 341 | platform_device_unregister(advwdt_platform_device); |
352 | platform_driver_unregister(&advwdt_driver); | 342 | platform_driver_unregister(&advwdt_driver); |