diff options
Diffstat (limited to 'drivers/watchdog/w83697hf_wdt.c')
-rw-r--r-- | drivers/watchdog/w83697hf_wdt.c | 148 |
1 files changed, 73 insertions, 75 deletions
diff --git a/drivers/watchdog/w83697hf_wdt.c b/drivers/watchdog/w83697hf_wdt.c index 528b882420b6..06ddd38675bd 100644 --- a/drivers/watchdog/w83697hf_wdt.c +++ b/drivers/watchdog/w83697hf_wdt.c | |||
@@ -36,9 +36,9 @@ | |||
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 <linux/io.h> | ||
40 | #include <linux/uaccess.h> | ||
39 | 41 | ||
40 | #include <asm/io.h> | ||
41 | #include <asm/uaccess.h> | ||
42 | #include <asm/system.h> | 42 | #include <asm/system.h> |
43 | 43 | ||
44 | #define WATCHDOG_NAME "w83697hf/hg WDT" | 44 | #define WATCHDOG_NAME "w83697hf/hg WDT" |
@@ -53,37 +53,43 @@ static DEFINE_SPINLOCK(io_lock); | |||
53 | /* You must set this - there is no sane way to probe for this board. */ | 53 | /* You must set this - there is no sane way to probe for this board. */ |
54 | static int wdt_io = 0x2e; | 54 | static int wdt_io = 0x2e; |
55 | module_param(wdt_io, int, 0); | 55 | module_param(wdt_io, int, 0); |
56 | MODULE_PARM_DESC(wdt_io, "w83697hf/hg WDT io port (default 0x2e, 0 = autodetect)"); | 56 | MODULE_PARM_DESC(wdt_io, |
57 | "w83697hf/hg WDT io port (default 0x2e, 0 = autodetect)"); | ||
57 | 58 | ||
58 | static int timeout = WATCHDOG_TIMEOUT; /* in seconds */ | 59 | static int timeout = WATCHDOG_TIMEOUT; /* in seconds */ |
59 | module_param(timeout, int, 0); | 60 | module_param(timeout, int, 0); |
60 | MODULE_PARM_DESC(timeout, "Watchdog timeout in seconds. 1<= timeout <=255 (default=" __MODULE_STRING(WATCHDOG_TIMEOUT) ")"); | 61 | MODULE_PARM_DESC(timeout, |
62 | "Watchdog timeout in seconds. 1<= timeout <=255 (default=" | ||
63 | __MODULE_STRING(WATCHDOG_TIMEOUT) ")"); | ||
61 | 64 | ||
62 | static int nowayout = WATCHDOG_NOWAYOUT; | 65 | static int nowayout = WATCHDOG_NOWAYOUT; |
63 | module_param(nowayout, int, 0); | 66 | module_param(nowayout, int, 0); |
64 | MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default=" __MODULE_STRING(WATCHDOG_NOWAYOUT) ")"); | 67 | MODULE_PARM_DESC(nowayout, |
68 | "Watchdog cannot be stopped once started (default=" | ||
69 | __MODULE_STRING(WATCHDOG_NOWAYOUT) ")"); | ||
65 | 70 | ||
66 | static int early_disable = WATCHDOG_EARLY_DISABLE; | 71 | static int early_disable = WATCHDOG_EARLY_DISABLE; |
67 | module_param(early_disable, int, 0); | 72 | module_param(early_disable, int, 0); |
68 | MODULE_PARM_DESC(early_disable, "Watchdog gets disabled at boot time (default=" __MODULE_STRING(WATCHDOG_EARLY_DISABLE) ")"); | 73 | MODULE_PARM_DESC(early_disable, |
74 | "Watchdog gets disabled at boot time (default=" | ||
75 | __MODULE_STRING(WATCHDOG_EARLY_DISABLE) ")"); | ||
69 | 76 | ||
70 | /* | 77 | /* |
71 | * Kernel methods. | 78 | * Kernel methods. |
72 | */ | 79 | */ |
73 | 80 | ||
74 | #define W83697HF_EFER (wdt_io+0) /* Extended Function Enable Register */ | 81 | #define W83697HF_EFER (wdt_io + 0) /* Extended Function Enable Register */ |
75 | #define W83697HF_EFIR (wdt_io+0) /* Extended Function Index Register (same as EFER) */ | 82 | #define W83697HF_EFIR (wdt_io + 0) /* Extended Function Index Register |
76 | #define W83697HF_EFDR (wdt_io+1) /* Extended Function Data Register */ | 83 | (same as EFER) */ |
84 | #define W83697HF_EFDR (wdt_io + 1) /* Extended Function Data Register */ | ||
77 | 85 | ||
78 | static inline void | 86 | static inline void w83697hf_unlock(void) |
79 | w83697hf_unlock(void) | ||
80 | { | 87 | { |
81 | outb_p(0x87, W83697HF_EFER); /* Enter extended function mode */ | 88 | outb_p(0x87, W83697HF_EFER); /* Enter extended function mode */ |
82 | outb_p(0x87, W83697HF_EFER); /* Again according to manual */ | 89 | outb_p(0x87, W83697HF_EFER); /* Again according to manual */ |
83 | } | 90 | } |
84 | 91 | ||
85 | static inline void | 92 | static inline void w83697hf_lock(void) |
86 | w83697hf_lock(void) | ||
87 | { | 93 | { |
88 | outb_p(0xAA, W83697HF_EFER); /* Leave extended function mode */ | 94 | outb_p(0xAA, W83697HF_EFER); /* Leave extended function mode */ |
89 | } | 95 | } |
@@ -93,41 +99,36 @@ w83697hf_lock(void) | |||
93 | * w83697hf_write_timeout() must be called with the device unlocked. | 99 | * w83697hf_write_timeout() must be called with the device unlocked. |
94 | */ | 100 | */ |
95 | 101 | ||
96 | static unsigned char | 102 | static unsigned char w83697hf_get_reg(unsigned char reg) |
97 | w83697hf_get_reg(unsigned char reg) | ||
98 | { | 103 | { |
99 | outb_p(reg, W83697HF_EFIR); | 104 | outb_p(reg, W83697HF_EFIR); |
100 | return inb_p(W83697HF_EFDR); | 105 | return inb_p(W83697HF_EFDR); |
101 | } | 106 | } |
102 | 107 | ||
103 | static void | 108 | static void w83697hf_set_reg(unsigned char reg, unsigned char data) |
104 | w83697hf_set_reg(unsigned char reg, unsigned char data) | ||
105 | { | 109 | { |
106 | outb_p(reg, W83697HF_EFIR); | 110 | outb_p(reg, W83697HF_EFIR); |
107 | outb_p(data, W83697HF_EFDR); | 111 | outb_p(data, W83697HF_EFDR); |
108 | } | 112 | } |
109 | 113 | ||
110 | static void | 114 | static void w83697hf_write_timeout(int timeout) |
111 | w83697hf_write_timeout(int timeout) | ||
112 | { | 115 | { |
113 | w83697hf_set_reg(0xF4, timeout); /* Write Timeout counter to CRF4 */ | 116 | /* Write Timeout counter to CRF4 */ |
117 | w83697hf_set_reg(0xF4, timeout); | ||
114 | } | 118 | } |
115 | 119 | ||
116 | static void | 120 | static void w83697hf_select_wdt(void) |
117 | w83697hf_select_wdt(void) | ||
118 | { | 121 | { |
119 | w83697hf_unlock(); | 122 | w83697hf_unlock(); |
120 | w83697hf_set_reg(0x07, 0x08); /* Switch to logic device 8 (GPIO2) */ | 123 | w83697hf_set_reg(0x07, 0x08); /* Switch to logic device 8 (GPIO2) */ |
121 | } | 124 | } |
122 | 125 | ||
123 | static inline void | 126 | static inline void w83697hf_deselect_wdt(void) |
124 | w83697hf_deselect_wdt(void) | ||
125 | { | 127 | { |
126 | w83697hf_lock(); | 128 | w83697hf_lock(); |
127 | } | 129 | } |
128 | 130 | ||
129 | static void | 131 | static void w83697hf_init(void) |
130 | w83697hf_init(void) | ||
131 | { | 132 | { |
132 | unsigned char bbuf; | 133 | unsigned char bbuf; |
133 | 134 | ||
@@ -136,7 +137,9 @@ w83697hf_init(void) | |||
136 | bbuf = w83697hf_get_reg(0x29); | 137 | bbuf = w83697hf_get_reg(0x29); |
137 | bbuf &= ~0x60; | 138 | bbuf &= ~0x60; |
138 | bbuf |= 0x20; | 139 | bbuf |= 0x20; |
139 | w83697hf_set_reg(0x29, bbuf); /* Set pin 119 to WDTO# mode (= CR29, WDT0) */ | 140 | |
141 | /* Set pin 119 to WDTO# mode (= CR29, WDT0) */ | ||
142 | w83697hf_set_reg(0x29, bbuf); | ||
140 | 143 | ||
141 | bbuf = w83697hf_get_reg(0xF3); | 144 | bbuf = w83697hf_get_reg(0xF3); |
142 | bbuf &= ~0x04; | 145 | bbuf &= ~0x04; |
@@ -145,8 +148,7 @@ w83697hf_init(void) | |||
145 | w83697hf_deselect_wdt(); | 148 | w83697hf_deselect_wdt(); |
146 | } | 149 | } |
147 | 150 | ||
148 | static void | 151 | static void wdt_ping(void) |
149 | wdt_ping(void) | ||
150 | { | 152 | { |
151 | spin_lock(&io_lock); | 153 | spin_lock(&io_lock); |
152 | w83697hf_select_wdt(); | 154 | w83697hf_select_wdt(); |
@@ -157,8 +159,7 @@ wdt_ping(void) | |||
157 | spin_unlock(&io_lock); | 159 | spin_unlock(&io_lock); |
158 | } | 160 | } |
159 | 161 | ||
160 | static void | 162 | static void wdt_enable(void) |
161 | wdt_enable(void) | ||
162 | { | 163 | { |
163 | spin_lock(&io_lock); | 164 | spin_lock(&io_lock); |
164 | w83697hf_select_wdt(); | 165 | w83697hf_select_wdt(); |
@@ -170,8 +171,7 @@ wdt_enable(void) | |||
170 | spin_unlock(&io_lock); | 171 | spin_unlock(&io_lock); |
171 | } | 172 | } |
172 | 173 | ||
173 | static void | 174 | static void wdt_disable(void) |
174 | wdt_disable(void) | ||
175 | { | 175 | { |
176 | spin_lock(&io_lock); | 176 | spin_lock(&io_lock); |
177 | w83697hf_select_wdt(); | 177 | w83697hf_select_wdt(); |
@@ -183,8 +183,7 @@ wdt_disable(void) | |||
183 | spin_unlock(&io_lock); | 183 | spin_unlock(&io_lock); |
184 | } | 184 | } |
185 | 185 | ||
186 | static unsigned char | 186 | static unsigned char wdt_running(void) |
187 | wdt_running(void) | ||
188 | { | 187 | { |
189 | unsigned char t; | 188 | unsigned char t; |
190 | 189 | ||
@@ -199,18 +198,17 @@ wdt_running(void) | |||
199 | return t; | 198 | return t; |
200 | } | 199 | } |
201 | 200 | ||
202 | static int | 201 | static int wdt_set_heartbeat(int t) |
203 | wdt_set_heartbeat(int t) | ||
204 | { | 202 | { |
205 | if ((t < 1) || (t > 255)) | 203 | if (t < 1 || t > 255) |
206 | return -EINVAL; | 204 | return -EINVAL; |
207 | 205 | ||
208 | timeout = t; | 206 | timeout = t; |
209 | return 0; | 207 | return 0; |
210 | } | 208 | } |
211 | 209 | ||
212 | static ssize_t | 210 | static ssize_t wdt_write(struct file *file, const char __user *buf, |
213 | wdt_write(struct file *file, const char __user *buf, size_t count, loff_t *ppos) | 211 | size_t count, loff_t *ppos) |
214 | { | 212 | { |
215 | if (count) { | 213 | if (count) { |
216 | if (!nowayout) { | 214 | if (!nowayout) { |
@@ -231,15 +229,14 @@ wdt_write(struct file *file, const char __user *buf, size_t count, loff_t *ppos) | |||
231 | return count; | 229 | return count; |
232 | } | 230 | } |
233 | 231 | ||
234 | static int | 232 | static long wdt_ioctl(struct file *file, unsigned int cmd, unsigned long arg) |
235 | wdt_ioctl(struct inode *inode, struct file *file, unsigned int cmd, | ||
236 | unsigned long arg) | ||
237 | { | 233 | { |
238 | void __user *argp = (void __user *)arg; | 234 | void __user *argp = (void __user *)arg; |
239 | int __user *p = argp; | 235 | int __user *p = argp; |
240 | int new_timeout; | 236 | int new_timeout; |
241 | static struct watchdog_info ident = { | 237 | static const struct watchdog_info ident = { |
242 | .options = WDIOF_KEEPALIVEPING | WDIOF_SETTIMEOUT | WDIOF_MAGICCLOSE, | 238 | .options = WDIOF_KEEPALIVEPING | WDIOF_SETTIMEOUT |
239 | | WDIOF_MAGICCLOSE, | ||
243 | .firmware_version = 1, | 240 | .firmware_version = 1, |
244 | .identity = "W83697HF WDT", | 241 | .identity = "W83697HF WDT", |
245 | }; | 242 | }; |
@@ -295,8 +292,7 @@ wdt_ioctl(struct inode *inode, struct file *file, unsigned int cmd, | |||
295 | return 0; | 292 | return 0; |
296 | } | 293 | } |
297 | 294 | ||
298 | static int | 295 | static int wdt_open(struct inode *inode, struct file *file) |
299 | wdt_open(struct inode *inode, struct file *file) | ||
300 | { | 296 | { |
301 | if (test_and_set_bit(0, &wdt_is_open)) | 297 | if (test_and_set_bit(0, &wdt_is_open)) |
302 | return -EBUSY; | 298 | return -EBUSY; |
@@ -308,13 +304,13 @@ wdt_open(struct inode *inode, struct file *file) | |||
308 | return nonseekable_open(inode, file); | 304 | return nonseekable_open(inode, file); |
309 | } | 305 | } |
310 | 306 | ||
311 | static int | 307 | static int wdt_close(struct inode *inode, struct file *file) |
312 | wdt_close(struct inode *inode, struct file *file) | ||
313 | { | 308 | { |
314 | if (expect_close == 42) { | 309 | if (expect_close == 42) |
315 | wdt_disable(); | 310 | wdt_disable(); |
316 | } else { | 311 | else { |
317 | printk (KERN_CRIT PFX "Unexpected close, not stopping watchdog!\n"); | 312 | printk(KERN_CRIT PFX |
313 | "Unexpected close, not stopping watchdog!\n"); | ||
318 | wdt_ping(); | 314 | wdt_ping(); |
319 | } | 315 | } |
320 | expect_close = 0; | 316 | expect_close = 0; |
@@ -326,8 +322,7 @@ wdt_close(struct inode *inode, struct file *file) | |||
326 | * Notifier for system down | 322 | * Notifier for system down |
327 | */ | 323 | */ |
328 | 324 | ||
329 | static int | 325 | static int wdt_notify_sys(struct notifier_block *this, unsigned long code, |
330 | wdt_notify_sys(struct notifier_block *this, unsigned long code, | ||
331 | void *unused) | 326 | void *unused) |
332 | { | 327 | { |
333 | if (code == SYS_DOWN || code == SYS_HALT) { | 328 | if (code == SYS_DOWN || code == SYS_HALT) { |
@@ -345,7 +340,7 @@ static const struct file_operations wdt_fops = { | |||
345 | .owner = THIS_MODULE, | 340 | .owner = THIS_MODULE, |
346 | .llseek = no_llseek, | 341 | .llseek = no_llseek, |
347 | .write = wdt_write, | 342 | .write = wdt_write, |
348 | .ioctl = wdt_ioctl, | 343 | .unlocked_ioctl = wdt_ioctl, |
349 | .open = wdt_open, | 344 | .open = wdt_open, |
350 | .release = wdt_close, | 345 | .release = wdt_close, |
351 | }; | 346 | }; |
@@ -365,36 +360,38 @@ static struct notifier_block wdt_notifier = { | |||
365 | .notifier_call = wdt_notify_sys, | 360 | .notifier_call = wdt_notify_sys, |
366 | }; | 361 | }; |
367 | 362 | ||
368 | static int | 363 | static int w83697hf_check_wdt(void) |
369 | w83697hf_check_wdt(void) | ||
370 | { | 364 | { |
371 | if (!request_region(wdt_io, 2, WATCHDOG_NAME)) { | 365 | if (!request_region(wdt_io, 2, WATCHDOG_NAME)) { |
372 | printk (KERN_ERR PFX "I/O address 0x%x already in use\n", wdt_io); | 366 | printk(KERN_ERR PFX |
367 | "I/O address 0x%x already in use\n", wdt_io); | ||
373 | return -EIO; | 368 | return -EIO; |
374 | } | 369 | } |
375 | 370 | ||
376 | printk (KERN_DEBUG PFX "Looking for watchdog at address 0x%x\n", wdt_io); | 371 | printk(KERN_DEBUG PFX |
372 | "Looking for watchdog at address 0x%x\n", wdt_io); | ||
377 | w83697hf_unlock(); | 373 | w83697hf_unlock(); |
378 | if (w83697hf_get_reg(0x20) == 0x60) { | 374 | if (w83697hf_get_reg(0x20) == 0x60) { |
379 | printk (KERN_INFO PFX "watchdog found at address 0x%x\n", wdt_io); | 375 | printk(KERN_INFO PFX |
376 | "watchdog found at address 0x%x\n", wdt_io); | ||
380 | w83697hf_lock(); | 377 | w83697hf_lock(); |
381 | return 0; | 378 | return 0; |
382 | } | 379 | } |
383 | w83697hf_lock(); /* Reprotect in case it was a compatible device */ | 380 | /* Reprotect in case it was a compatible device */ |
381 | w83697hf_lock(); | ||
384 | 382 | ||
385 | printk (KERN_INFO PFX "watchdog not found at address 0x%x\n", wdt_io); | 383 | printk(KERN_INFO PFX "watchdog not found at address 0x%x\n", wdt_io); |
386 | release_region(wdt_io, 2); | 384 | release_region(wdt_io, 2); |
387 | return -EIO; | 385 | return -EIO; |
388 | } | 386 | } |
389 | 387 | ||
390 | static int w83697hf_ioports[] = { 0x2e, 0x4e, 0x00 }; | 388 | static int w83697hf_ioports[] = { 0x2e, 0x4e, 0x00 }; |
391 | 389 | ||
392 | static int __init | 390 | static int __init wdt_init(void) |
393 | wdt_init(void) | ||
394 | { | 391 | { |
395 | int ret, i, found = 0; | 392 | int ret, i, found = 0; |
396 | 393 | ||
397 | printk (KERN_INFO PFX "WDT driver for W83697HF/HG initializing\n"); | 394 | printk(KERN_INFO PFX "WDT driver for W83697HF/HG initializing\n"); |
398 | 395 | ||
399 | if (wdt_io == 0) { | 396 | if (wdt_io == 0) { |
400 | /* we will autodetect the W83697HF/HG watchdog */ | 397 | /* we will autodetect the W83697HF/HG watchdog */ |
@@ -409,7 +406,7 @@ wdt_init(void) | |||
409 | } | 406 | } |
410 | 407 | ||
411 | if (!found) { | 408 | if (!found) { |
412 | printk (KERN_ERR PFX "No W83697HF/HG could be found\n"); | 409 | printk(KERN_ERR PFX "No W83697HF/HG could be found\n"); |
413 | ret = -EIO; | 410 | ret = -EIO; |
414 | goto out; | 411 | goto out; |
415 | } | 412 | } |
@@ -423,25 +420,27 @@ wdt_init(void) | |||
423 | 420 | ||
424 | if (wdt_set_heartbeat(timeout)) { | 421 | if (wdt_set_heartbeat(timeout)) { |
425 | wdt_set_heartbeat(WATCHDOG_TIMEOUT); | 422 | wdt_set_heartbeat(WATCHDOG_TIMEOUT); |
426 | printk (KERN_INFO PFX "timeout value must be 1<=timeout<=255, using %d\n", | 423 | printk(KERN_INFO PFX |
427 | WATCHDOG_TIMEOUT); | 424 | "timeout value must be 1 <= timeout <= 255, using %d\n", |
425 | WATCHDOG_TIMEOUT); | ||
428 | } | 426 | } |
429 | 427 | ||
430 | ret = register_reboot_notifier(&wdt_notifier); | 428 | ret = register_reboot_notifier(&wdt_notifier); |
431 | if (ret != 0) { | 429 | if (ret != 0) { |
432 | printk (KERN_ERR PFX "cannot register reboot notifier (err=%d)\n", | 430 | printk(KERN_ERR PFX |
433 | ret); | 431 | "cannot register reboot notifier (err=%d)\n", ret); |
434 | goto unreg_regions; | 432 | goto unreg_regions; |
435 | } | 433 | } |
436 | 434 | ||
437 | ret = misc_register(&wdt_miscdev); | 435 | ret = misc_register(&wdt_miscdev); |
438 | if (ret != 0) { | 436 | if (ret != 0) { |
439 | printk (KERN_ERR PFX "cannot register miscdev on minor=%d (err=%d)\n", | 437 | printk(KERN_ERR PFX |
440 | WATCHDOG_MINOR, ret); | 438 | "cannot register miscdev on minor=%d (err=%d)\n", |
439 | WATCHDOG_MINOR, ret); | ||
441 | goto unreg_reboot; | 440 | goto unreg_reboot; |
442 | } | 441 | } |
443 | 442 | ||
444 | printk (KERN_INFO PFX "initialized. timeout=%d sec (nowayout=%d)\n", | 443 | printk(KERN_INFO PFX "initialized. timeout=%d sec (nowayout=%d)\n", |
445 | timeout, nowayout); | 444 | timeout, nowayout); |
446 | 445 | ||
447 | out: | 446 | out: |
@@ -453,8 +452,7 @@ unreg_regions: | |||
453 | goto out; | 452 | goto out; |
454 | } | 453 | } |
455 | 454 | ||
456 | static void __exit | 455 | static void __exit wdt_exit(void) |
457 | wdt_exit(void) | ||
458 | { | 456 | { |
459 | misc_deregister(&wdt_miscdev); | 457 | misc_deregister(&wdt_miscdev); |
460 | unregister_reboot_notifier(&wdt_notifier); | 458 | unregister_reboot_notifier(&wdt_notifier); |