diff options
author | Alan Cox <alan@redhat.com> | 2008-08-04 12:55:35 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2008-08-04 20:12:07 -0400 |
commit | 9f2d1f0da766f84fdb96c9bd79ed0f97036635cb (patch) | |
tree | 398d413ab236da55522fe091be55d9e4ba798660 | |
parent | 41dc8b72e37c514f7332cbc3f3dd864910c2a1fa (diff) |
wdt: Cleanup and sort out locking and inb_p
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Alan Cox <alan@redhat.com>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
-rw-r--r-- | drivers/watchdog/wdt.c | 176 | ||||
-rw-r--r-- | drivers/watchdog/wdt_pci.c | 300 |
2 files changed, 265 insertions, 211 deletions
diff --git a/drivers/watchdog/wdt.c b/drivers/watchdog/wdt.c index 756fb15fdce7..53a6b18bcb9a 100644 --- a/drivers/watchdog/wdt.c +++ b/drivers/watchdog/wdt.c | |||
@@ -24,9 +24,10 @@ | |||
24 | * Matt Crocker). | 24 | * Matt Crocker). |
25 | * Alan Cox : Added wdt= boot option | 25 | * Alan Cox : Added wdt= boot option |
26 | * Alan Cox : Cleaned up copy/user stuff | 26 | * Alan Cox : Cleaned up copy/user stuff |
27 | * Tim Hockin : Added insmod parameters, comment cleanup | 27 | * Tim Hockin : Added insmod parameters, comment |
28 | * Parameterized timeout | 28 | * cleanup, parameterized timeout |
29 | * Tigran Aivazian : Restructured wdt_init() to handle failures | 29 | * Tigran Aivazian : Restructured wdt_init() to handle |
30 | * failures | ||
30 | * Joel Becker : Added WDIOC_GET/SETTIMEOUT | 31 | * Joel Becker : Added WDIOC_GET/SETTIMEOUT |
31 | * Matt Domsch : Added nowayout module option | 32 | * Matt Domsch : Added nowayout module option |
32 | */ | 33 | */ |
@@ -42,9 +43,9 @@ | |||
42 | #include <linux/notifier.h> | 43 | #include <linux/notifier.h> |
43 | #include <linux/reboot.h> | 44 | #include <linux/reboot.h> |
44 | #include <linux/init.h> | 45 | #include <linux/init.h> |
46 | #include <linux/io.h> | ||
47 | #include <linux/uaccess.h> | ||
45 | 48 | ||
46 | #include <asm/io.h> | ||
47 | #include <asm/uaccess.h> | ||
48 | #include <asm/system.h> | 49 | #include <asm/system.h> |
49 | #include "wd501p.h" | 50 | #include "wd501p.h" |
50 | 51 | ||
@@ -60,15 +61,19 @@ static char expect_close; | |||
60 | static int heartbeat = WD_TIMO; | 61 | static int heartbeat = WD_TIMO; |
61 | static int wd_heartbeat; | 62 | static int wd_heartbeat; |
62 | module_param(heartbeat, int, 0); | 63 | module_param(heartbeat, int, 0); |
63 | MODULE_PARM_DESC(heartbeat, "Watchdog heartbeat in seconds. (0<heartbeat<65536, default=" __MODULE_STRING(WD_TIMO) ")"); | 64 | MODULE_PARM_DESC(heartbeat, |
65 | "Watchdog heartbeat in seconds. (0 < heartbeat < 65536, default=" | ||
66 | __MODULE_STRING(WD_TIMO) ")"); | ||
64 | 67 | ||
65 | static int nowayout = WATCHDOG_NOWAYOUT; | 68 | static int nowayout = WATCHDOG_NOWAYOUT; |
66 | module_param(nowayout, int, 0); | 69 | module_param(nowayout, int, 0); |
67 | 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) ")"); | ||
68 | 73 | ||
69 | /* You must set these - there is no sane way to probe for this board. */ | 74 | /* You must set these - there is no sane way to probe for this board. */ |
70 | static int io=0x240; | 75 | static int io = 0x240; |
71 | static int irq=11; | 76 | static int irq = 11; |
72 | 77 | ||
73 | static DEFINE_SPINLOCK(wdt_lock); | 78 | static DEFINE_SPINLOCK(wdt_lock); |
74 | 79 | ||
@@ -82,7 +87,8 @@ MODULE_PARM_DESC(irq, "WDT irq (default=11)"); | |||
82 | static int tachometer; | 87 | static int tachometer; |
83 | 88 | ||
84 | module_param(tachometer, int, 0); | 89 | module_param(tachometer, int, 0); |
85 | MODULE_PARM_DESC(tachometer, "WDT501-P Fan Tachometer support (0=disable, default=0)"); | 90 | MODULE_PARM_DESC(tachometer, |
91 | "WDT501-P Fan Tachometer support (0=disable, default=0)"); | ||
86 | #endif /* CONFIG_WDT_501 */ | 92 | #endif /* CONFIG_WDT_501 */ |
87 | 93 | ||
88 | /* | 94 | /* |
@@ -91,9 +97,9 @@ MODULE_PARM_DESC(tachometer, "WDT501-P Fan Tachometer support (0=disable, defaul | |||
91 | 97 | ||
92 | static void wdt_ctr_mode(int ctr, int mode) | 98 | static void wdt_ctr_mode(int ctr, int mode) |
93 | { | 99 | { |
94 | ctr<<=6; | 100 | ctr <<= 6; |
95 | ctr|=0x30; | 101 | ctr |= 0x30; |
96 | ctr|=(mode<<1); | 102 | ctr |= (mode << 1); |
97 | outb_p(ctr, WDT_CR); | 103 | outb_p(ctr, WDT_CR); |
98 | } | 104 | } |
99 | 105 | ||
@@ -114,12 +120,15 @@ static int wdt_start(void) | |||
114 | unsigned long flags; | 120 | unsigned long flags; |
115 | spin_lock_irqsave(&wdt_lock, flags); | 121 | spin_lock_irqsave(&wdt_lock, flags); |
116 | inb_p(WDT_DC); /* Disable watchdog */ | 122 | inb_p(WDT_DC); /* Disable watchdog */ |
117 | wdt_ctr_mode(0,3); /* Program CTR0 for Mode 3: Square Wave Generator */ | 123 | wdt_ctr_mode(0, 3); /* Program CTR0 for Mode 3: |
118 | wdt_ctr_mode(1,2); /* Program CTR1 for Mode 2: Rate Generator */ | 124 | Square Wave Generator */ |
119 | wdt_ctr_mode(2,0); /* Program CTR2 for Mode 0: Pulse on Terminal Count */ | 125 | wdt_ctr_mode(1, 2); /* Program CTR1 for Mode 2: |
126 | Rate Generator */ | ||
127 | wdt_ctr_mode(2, 0); /* Program CTR2 for Mode 0: | ||
128 | Pulse on Terminal Count */ | ||
120 | wdt_ctr_load(0, 8948); /* Count at 100Hz */ | 129 | wdt_ctr_load(0, 8948); /* Count at 100Hz */ |
121 | wdt_ctr_load(1,wd_heartbeat); /* Heartbeat */ | 130 | wdt_ctr_load(1, wd_heartbeat); /* Heartbeat */ |
122 | wdt_ctr_load(2,65535); /* Length of reset pulse */ | 131 | wdt_ctr_load(2, 65535); /* Length of reset pulse */ |
123 | outb_p(0, WDT_DC); /* Enable watchdog */ | 132 | outb_p(0, WDT_DC); /* Enable watchdog */ |
124 | spin_unlock_irqrestore(&wdt_lock, flags); | 133 | spin_unlock_irqrestore(&wdt_lock, flags); |
125 | return 0; | 134 | return 0; |
@@ -131,13 +140,13 @@ static int wdt_start(void) | |||
131 | * Stop the watchdog driver. | 140 | * Stop the watchdog driver. |
132 | */ | 141 | */ |
133 | 142 | ||
134 | static int wdt_stop (void) | 143 | static int wdt_stop(void) |
135 | { | 144 | { |
136 | unsigned long flags; | 145 | unsigned long flags; |
137 | spin_lock_irqsave(&wdt_lock, flags); | 146 | spin_lock_irqsave(&wdt_lock, flags); |
138 | /* Turn the card off */ | 147 | /* Turn the card off */ |
139 | inb_p(WDT_DC); /* Disable watchdog */ | 148 | inb_p(WDT_DC); /* Disable watchdog */ |
140 | wdt_ctr_load(2,0); /* 0 length reset pulses now */ | 149 | wdt_ctr_load(2, 0); /* 0 length reset pulses now */ |
141 | spin_unlock_irqrestore(&wdt_lock, flags); | 150 | spin_unlock_irqrestore(&wdt_lock, flags); |
142 | return 0; | 151 | return 0; |
143 | } | 152 | } |
@@ -145,8 +154,8 @@ static int wdt_stop (void) | |||
145 | /** | 154 | /** |
146 | * wdt_ping: | 155 | * wdt_ping: |
147 | * | 156 | * |
148 | * Reload counter one with the watchdog heartbeat. We don't bother reloading | 157 | * Reload counter one with the watchdog heartbeat. We don't bother |
149 | * the cascade counter. | 158 | * reloading the cascade counter. |
150 | */ | 159 | */ |
151 | 160 | ||
152 | static int wdt_ping(void) | 161 | static int wdt_ping(void) |
@@ -155,8 +164,9 @@ static int wdt_ping(void) | |||
155 | spin_lock_irqsave(&wdt_lock, flags); | 164 | spin_lock_irqsave(&wdt_lock, flags); |
156 | /* Write a watchdog value */ | 165 | /* Write a watchdog value */ |
157 | inb_p(WDT_DC); /* Disable watchdog */ | 166 | inb_p(WDT_DC); /* Disable watchdog */ |
158 | wdt_ctr_mode(1,2); /* Re-Program CTR1 for Mode 2: Rate Generator */ | 167 | wdt_ctr_mode(1, 2); /* Re-Program CTR1 for Mode 2: |
159 | wdt_ctr_load(1,wd_heartbeat); /* Heartbeat */ | 168 | Rate Generator */ |
169 | wdt_ctr_load(1, wd_heartbeat); /* Heartbeat */ | ||
160 | outb_p(0, WDT_DC); /* Enable watchdog */ | 170 | outb_p(0, WDT_DC); /* Enable watchdog */ |
161 | spin_unlock_irqrestore(&wdt_lock, flags); | 171 | spin_unlock_irqrestore(&wdt_lock, flags); |
162 | return 0; | 172 | return 0; |
@@ -166,13 +176,14 @@ static int wdt_ping(void) | |||
166 | * wdt_set_heartbeat: | 176 | * wdt_set_heartbeat: |
167 | * @t: the new heartbeat value that needs to be set. | 177 | * @t: the new heartbeat value that needs to be set. |
168 | * | 178 | * |
169 | * Set a new heartbeat value for the watchdog device. If the heartbeat value is | 179 | * Set a new heartbeat value for the watchdog device. If the heartbeat |
170 | * incorrect we keep the old value and return -EINVAL. If successfull we | 180 | * value is incorrect we keep the old value and return -EINVAL. If |
171 | * return 0. | 181 | * successful we return 0. |
172 | */ | 182 | */ |
183 | |||
173 | static int wdt_set_heartbeat(int t) | 184 | static int wdt_set_heartbeat(int t) |
174 | { | 185 | { |
175 | if ((t < 1) || (t > 65535)) | 186 | if (t < 1 || t > 65535) |
176 | return -EINVAL; | 187 | return -EINVAL; |
177 | 188 | ||
178 | heartbeat = t; | 189 | heartbeat = t; |
@@ -200,7 +211,7 @@ static int wdt_get_status(int *status) | |||
200 | new_status = inb_p(WDT_SR); | 211 | new_status = inb_p(WDT_SR); |
201 | spin_unlock_irqrestore(&wdt_lock, flags); | 212 | spin_unlock_irqrestore(&wdt_lock, flags); |
202 | 213 | ||
203 | *status=0; | 214 | *status = 0; |
204 | if (new_status & WDC_SR_ISOI0) | 215 | if (new_status & WDC_SR_ISOI0) |
205 | *status |= WDIOF_EXTERN1; | 216 | *status |= WDIOF_EXTERN1; |
206 | if (new_status & WDC_SR_ISII1) | 217 | if (new_status & WDC_SR_ISII1) |
@@ -266,7 +277,7 @@ static irqreturn_t wdt_interrupt(int irq, void *dev_id) | |||
266 | 277 | ||
267 | #ifdef CONFIG_WDT_501 | 278 | #ifdef CONFIG_WDT_501 |
268 | if (!(status & WDC_SR_TGOOD)) | 279 | if (!(status & WDC_SR_TGOOD)) |
269 | printk(KERN_CRIT "Overheat alarm.(%d)\n",inb_p(WDT_RT)); | 280 | printk(KERN_CRIT "Overheat alarm.(%d)\n", inb_p(WDT_RT)); |
270 | if (!(status & WDC_SR_PSUOVER)) | 281 | if (!(status & WDC_SR_PSUOVER)) |
271 | printk(KERN_CRIT "PSU over voltage.\n"); | 282 | printk(KERN_CRIT "PSU over voltage.\n"); |
272 | if (!(status & WDC_SR_PSUUNDR)) | 283 | if (!(status & WDC_SR_PSUUNDR)) |
@@ -304,9 +315,10 @@ static irqreturn_t wdt_interrupt(int irq, void *dev_id) | |||
304 | * write of data will do, as we we don't define content meaning. | 315 | * write of data will do, as we we don't define content meaning. |
305 | */ | 316 | */ |
306 | 317 | ||
307 | static ssize_t wdt_write(struct file *file, const char __user *buf, size_t count, loff_t *ppos) | 318 | static ssize_t wdt_write(struct file *file, const char __user *buf, |
319 | size_t count, loff_t *ppos) | ||
308 | { | 320 | { |
309 | if(count) { | 321 | if (count) { |
310 | if (!nowayout) { | 322 | if (!nowayout) { |
311 | size_t i; | 323 | size_t i; |
312 | 324 | ||
@@ -328,7 +340,6 @@ static ssize_t wdt_write(struct file *file, const char __user *buf, size_t count | |||
328 | 340 | ||
329 | /** | 341 | /** |
330 | * wdt_ioctl: | 342 | * wdt_ioctl: |
331 | * @inode: inode of the device | ||
332 | * @file: file handle to the device | 343 | * @file: file handle to the device |
333 | * @cmd: watchdog command | 344 | * @cmd: watchdog command |
334 | * @arg: argument pointer | 345 | * @arg: argument pointer |
@@ -338,8 +349,7 @@ static ssize_t wdt_write(struct file *file, const char __user *buf, size_t count | |||
338 | * querying capabilities and current status. | 349 | * querying capabilities and current status. |
339 | */ | 350 | */ |
340 | 351 | ||
341 | static int wdt_ioctl(struct inode *inode, struct file *file, unsigned int cmd, | 352 | static long wdt_ioctl(struct file *file, unsigned int cmd, unsigned long arg) |
342 | unsigned long arg) | ||
343 | { | 353 | { |
344 | void __user *argp = (void __user *)arg; | 354 | void __user *argp = (void __user *)arg; |
345 | int __user *p = argp; | 355 | int __user *p = argp; |
@@ -362,32 +372,28 @@ static int wdt_ioctl(struct inode *inode, struct file *file, unsigned int cmd, | |||
362 | ident.options |= WDIOF_FANFAULT; | 372 | ident.options |= WDIOF_FANFAULT; |
363 | #endif /* CONFIG_WDT_501 */ | 373 | #endif /* CONFIG_WDT_501 */ |
364 | 374 | ||
365 | switch(cmd) | 375 | switch (cmd) { |
366 | { | 376 | default: |
367 | default: | 377 | return -ENOTTY; |
368 | return -ENOTTY; | 378 | case WDIOC_GETSUPPORT: |
369 | case WDIOC_GETSUPPORT: | 379 | return copy_to_user(argp, &ident, sizeof(ident)) ? -EFAULT : 0; |
370 | return copy_to_user(argp, &ident, sizeof(ident))?-EFAULT:0; | 380 | case WDIOC_GETSTATUS: |
371 | 381 | wdt_get_status(&status); | |
372 | case WDIOC_GETSTATUS: | 382 | return put_user(status, p); |
373 | wdt_get_status(&status); | 383 | case WDIOC_GETBOOTSTATUS: |
374 | return put_user(status, p); | 384 | return put_user(0, p); |
375 | case WDIOC_GETBOOTSTATUS: | 385 | case WDIOC_KEEPALIVE: |
376 | return put_user(0, p); | 386 | wdt_ping(); |
377 | case WDIOC_KEEPALIVE: | 387 | return 0; |
378 | wdt_ping(); | 388 | case WDIOC_SETTIMEOUT: |
379 | return 0; | 389 | if (get_user(new_heartbeat, p)) |
380 | case WDIOC_SETTIMEOUT: | 390 | return -EFAULT; |
381 | if (get_user(new_heartbeat, p)) | 391 | if (wdt_set_heartbeat(new_heartbeat)) |
382 | return -EFAULT; | 392 | return -EINVAL; |
383 | 393 | wdt_ping(); | |
384 | if (wdt_set_heartbeat(new_heartbeat)) | 394 | /* Fall */ |
385 | return -EINVAL; | 395 | case WDIOC_GETTIMEOUT: |
386 | 396 | return put_user(heartbeat, p); | |
387 | wdt_ping(); | ||
388 | /* Fall */ | ||
389 | case WDIOC_GETTIMEOUT: | ||
390 | return put_user(heartbeat, p); | ||
391 | } | 397 | } |
392 | } | 398 | } |
393 | 399 | ||
@@ -405,7 +411,7 @@ static int wdt_ioctl(struct inode *inode, struct file *file, unsigned int cmd, | |||
405 | 411 | ||
406 | static int wdt_open(struct inode *inode, struct file *file) | 412 | static int wdt_open(struct inode *inode, struct file *file) |
407 | { | 413 | { |
408 | if(test_and_set_bit(0, &wdt_is_open)) | 414 | if (test_and_set_bit(0, &wdt_is_open)) |
409 | return -EBUSY; | 415 | return -EBUSY; |
410 | /* | 416 | /* |
411 | * Activate | 417 | * Activate |
@@ -432,7 +438,8 @@ static int wdt_release(struct inode *inode, struct file *file) | |||
432 | wdt_stop(); | 438 | wdt_stop(); |
433 | clear_bit(0, &wdt_is_open); | 439 | clear_bit(0, &wdt_is_open); |
434 | } else { | 440 | } else { |
435 | printk(KERN_CRIT "wdt: WDT device closed unexpectedly. WDT will not stop!\n"); | 441 | printk(KERN_CRIT |
442 | "wdt: WDT device closed unexpectedly. WDT will not stop!\n"); | ||
436 | wdt_ping(); | 443 | wdt_ping(); |
437 | } | 444 | } |
438 | expect_close = 0; | 445 | expect_close = 0; |
@@ -451,14 +458,15 @@ static int wdt_release(struct inode *inode, struct file *file) | |||
451 | * farenheit. It was designed by an imperial measurement luddite. | 458 | * farenheit. It was designed by an imperial measurement luddite. |
452 | */ | 459 | */ |
453 | 460 | ||
454 | static ssize_t wdt_temp_read(struct file *file, char __user *buf, size_t count, loff_t *ptr) | 461 | static ssize_t wdt_temp_read(struct file *file, char __user *buf, |
462 | size_t count, loff_t *ptr) | ||
455 | { | 463 | { |
456 | int temperature; | 464 | int temperature; |
457 | 465 | ||
458 | if (wdt_get_temperature(&temperature)) | 466 | if (wdt_get_temperature(&temperature)) |
459 | return -EFAULT; | 467 | return -EFAULT; |
460 | 468 | ||
461 | if (copy_to_user (buf, &temperature, 1)) | 469 | if (copy_to_user(buf, &temperature, 1)) |
462 | return -EFAULT; | 470 | return -EFAULT; |
463 | 471 | ||
464 | return 1; | 472 | return 1; |
@@ -506,10 +514,8 @@ static int wdt_temp_release(struct inode *inode, struct file *file) | |||
506 | static int wdt_notify_sys(struct notifier_block *this, unsigned long code, | 514 | static int wdt_notify_sys(struct notifier_block *this, unsigned long code, |
507 | void *unused) | 515 | void *unused) |
508 | { | 516 | { |
509 | if(code==SYS_DOWN || code==SYS_HALT) { | 517 | if (code == SYS_DOWN || code == SYS_HALT) |
510 | /* Turn the card off */ | ||
511 | wdt_stop(); | 518 | wdt_stop(); |
512 | } | ||
513 | return NOTIFY_DONE; | 519 | return NOTIFY_DONE; |
514 | } | 520 | } |
515 | 521 | ||
@@ -522,7 +528,7 @@ static const struct file_operations wdt_fops = { | |||
522 | .owner = THIS_MODULE, | 528 | .owner = THIS_MODULE, |
523 | .llseek = no_llseek, | 529 | .llseek = no_llseek, |
524 | .write = wdt_write, | 530 | .write = wdt_write, |
525 | .ioctl = wdt_ioctl, | 531 | .unlocked_ioctl = wdt_ioctl, |
526 | .open = wdt_open, | 532 | .open = wdt_open, |
527 | .release = wdt_release, | 533 | .release = wdt_release, |
528 | }; | 534 | }; |
@@ -576,7 +582,7 @@ static void __exit wdt_exit(void) | |||
576 | #endif /* CONFIG_WDT_501 */ | 582 | #endif /* CONFIG_WDT_501 */ |
577 | unregister_reboot_notifier(&wdt_notifier); | 583 | unregister_reboot_notifier(&wdt_notifier); |
578 | free_irq(irq, NULL); | 584 | free_irq(irq, NULL); |
579 | release_region(io,8); | 585 | release_region(io, 8); |
580 | } | 586 | } |
581 | 587 | ||
582 | /** | 588 | /** |
@@ -591,44 +597,49 @@ static int __init wdt_init(void) | |||
591 | { | 597 | { |
592 | int ret; | 598 | int ret; |
593 | 599 | ||
594 | /* Check that the heartbeat value is within it's range ; if not reset to the default */ | 600 | /* Check that the heartbeat value is within it's range; |
601 | if not reset to the default */ | ||
595 | if (wdt_set_heartbeat(heartbeat)) { | 602 | if (wdt_set_heartbeat(heartbeat)) { |
596 | wdt_set_heartbeat(WD_TIMO); | 603 | wdt_set_heartbeat(WD_TIMO); |
597 | printk(KERN_INFO "wdt: heartbeat value must be 0<heartbeat<65536, using %d\n", | 604 | printk(KERN_INFO "wdt: heartbeat value must be 0 < heartbeat < 65536, using %d\n", |
598 | WD_TIMO); | 605 | WD_TIMO); |
599 | } | 606 | } |
600 | 607 | ||
601 | if (!request_region(io, 8, "wdt501p")) { | 608 | if (!request_region(io, 8, "wdt501p")) { |
602 | printk(KERN_ERR "wdt: I/O address 0x%04x already in use\n", io); | 609 | printk(KERN_ERR |
610 | "wdt: I/O address 0x%04x already in use\n", io); | ||
603 | ret = -EBUSY; | 611 | ret = -EBUSY; |
604 | goto out; | 612 | goto out; |
605 | } | 613 | } |
606 | 614 | ||
607 | ret = request_irq(irq, wdt_interrupt, IRQF_DISABLED, "wdt501p", NULL); | 615 | ret = request_irq(irq, wdt_interrupt, IRQF_DISABLED, "wdt501p", NULL); |
608 | if(ret) { | 616 | if (ret) { |
609 | printk(KERN_ERR "wdt: IRQ %d is not free.\n", irq); | 617 | printk(KERN_ERR "wdt: IRQ %d is not free.\n", irq); |
610 | goto outreg; | 618 | goto outreg; |
611 | } | 619 | } |
612 | 620 | ||
613 | ret = register_reboot_notifier(&wdt_notifier); | 621 | ret = register_reboot_notifier(&wdt_notifier); |
614 | if(ret) { | 622 | if (ret) { |
615 | printk(KERN_ERR "wdt: cannot register reboot notifier (err=%d)\n", ret); | 623 | printk(KERN_ERR |
624 | "wdt: cannot register reboot notifier (err=%d)\n", ret); | ||
616 | goto outirq; | 625 | goto outirq; |
617 | } | 626 | } |
618 | 627 | ||
619 | #ifdef CONFIG_WDT_501 | 628 | #ifdef CONFIG_WDT_501 |
620 | ret = misc_register(&temp_miscdev); | 629 | ret = misc_register(&temp_miscdev); |
621 | if (ret) { | 630 | if (ret) { |
622 | printk(KERN_ERR "wdt: cannot register miscdev on minor=%d (err=%d)\n", | 631 | printk(KERN_ERR |
623 | TEMP_MINOR, ret); | 632 | "wdt: cannot register miscdev on minor=%d (err=%d)\n", |
633 | TEMP_MINOR, ret); | ||
624 | goto outrbt; | 634 | goto outrbt; |
625 | } | 635 | } |
626 | #endif /* CONFIG_WDT_501 */ | 636 | #endif /* CONFIG_WDT_501 */ |
627 | 637 | ||
628 | ret = misc_register(&wdt_miscdev); | 638 | ret = misc_register(&wdt_miscdev); |
629 | if (ret) { | 639 | if (ret) { |
630 | printk(KERN_ERR "wdt: cannot register miscdev on minor=%d (err=%d)\n", | 640 | printk(KERN_ERR |
631 | WATCHDOG_MINOR, ret); | 641 | "wdt: cannot register miscdev on minor=%d (err=%d)\n", |
642 | WATCHDOG_MINOR, ret); | ||
632 | goto outmisc; | 643 | goto outmisc; |
633 | } | 644 | } |
634 | 645 | ||
@@ -636,7 +647,8 @@ static int __init wdt_init(void) | |||
636 | printk(KERN_INFO "WDT500/501-P driver 0.10 at 0x%04x (Interrupt %d). heartbeat=%d sec (nowayout=%d)\n", | 647 | printk(KERN_INFO "WDT500/501-P driver 0.10 at 0x%04x (Interrupt %d). heartbeat=%d sec (nowayout=%d)\n", |
637 | io, irq, heartbeat, nowayout); | 648 | io, irq, heartbeat, nowayout); |
638 | #ifdef CONFIG_WDT_501 | 649 | #ifdef CONFIG_WDT_501 |
639 | printk(KERN_INFO "wdt: Fan Tachometer is %s\n", (tachometer ? "Enabled" : "Disabled")); | 650 | printk(KERN_INFO "wdt: Fan Tachometer is %s\n", |
651 | (tachometer ? "Enabled" : "Disabled")); | ||
640 | #endif /* CONFIG_WDT_501 */ | 652 | #endif /* CONFIG_WDT_501 */ |
641 | 653 | ||
642 | out: | 654 | out: |
@@ -651,7 +663,7 @@ outrbt: | |||
651 | outirq: | 663 | outirq: |
652 | free_irq(irq, NULL); | 664 | free_irq(irq, NULL); |
653 | outreg: | 665 | outreg: |
654 | release_region(io,8); | 666 | release_region(io, 8); |
655 | goto out; | 667 | goto out; |
656 | } | 668 | } |
657 | 669 | ||
diff --git a/drivers/watchdog/wdt_pci.c b/drivers/watchdog/wdt_pci.c index 1355608683e4..078f37f80383 100644 --- a/drivers/watchdog/wdt_pci.c +++ b/drivers/watchdog/wdt_pci.c | |||
@@ -29,9 +29,11 @@ | |||
29 | * JP Nollmann : Added support for PCI wdt501p | 29 | * JP Nollmann : Added support for PCI wdt501p |
30 | * Alan Cox : Split ISA and PCI cards into two drivers | 30 | * Alan Cox : Split ISA and PCI cards into two drivers |
31 | * Jeff Garzik : PCI cleanups | 31 | * Jeff Garzik : PCI cleanups |
32 | * Tigran Aivazian : Restructured wdtpci_init_one() to handle failures | 32 | * Tigran Aivazian : Restructured wdtpci_init_one() to handle |
33 | * failures | ||
33 | * Joel Becker : Added WDIOC_GET/SETTIMEOUT | 34 | * Joel Becker : Added WDIOC_GET/SETTIMEOUT |
34 | * Zwane Mwaikambo : Magic char closing, locking changes, cleanups | 35 | * Zwane Mwaikambo : Magic char closing, locking changes, |
36 | * cleanups | ||
35 | * Matt Domsch : nowayout module option | 37 | * Matt Domsch : nowayout module option |
36 | */ | 38 | */ |
37 | 39 | ||
@@ -47,9 +49,9 @@ | |||
47 | #include <linux/init.h> | 49 | #include <linux/init.h> |
48 | #include <linux/fs.h> | 50 | #include <linux/fs.h> |
49 | #include <linux/pci.h> | 51 | #include <linux/pci.h> |
52 | #include <linux/io.h> | ||
53 | #include <linux/uaccess.h> | ||
50 | 54 | ||
51 | #include <asm/io.h> | ||
52 | #include <asm/uaccess.h> | ||
53 | #include <asm/system.h> | 55 | #include <asm/system.h> |
54 | 56 | ||
55 | #define WDT_IS_PCI | 57 | #define WDT_IS_PCI |
@@ -73,7 +75,7 @@ | |||
73 | /* We can only use 1 card due to the /dev/watchdog restriction */ | 75 | /* We can only use 1 card due to the /dev/watchdog restriction */ |
74 | static int dev_count; | 76 | static int dev_count; |
75 | 77 | ||
76 | static struct semaphore open_sem; | 78 | static unsigned long open_lock; |
77 | static DEFINE_SPINLOCK(wdtpci_lock); | 79 | static DEFINE_SPINLOCK(wdtpci_lock); |
78 | static char expect_close; | 80 | static char expect_close; |
79 | 81 | ||
@@ -86,18 +88,23 @@ static int irq; | |||
86 | static int heartbeat = WD_TIMO; | 88 | static int heartbeat = WD_TIMO; |
87 | static int wd_heartbeat; | 89 | static int wd_heartbeat; |
88 | module_param(heartbeat, int, 0); | 90 | module_param(heartbeat, int, 0); |
89 | MODULE_PARM_DESC(heartbeat, "Watchdog heartbeat in seconds. (0<heartbeat<65536, default=" __MODULE_STRING(WD_TIMO) ")"); | 91 | MODULE_PARM_DESC(heartbeat, |
92 | "Watchdog heartbeat in seconds. (0<heartbeat<65536, default=" | ||
93 | __MODULE_STRING(WD_TIMO) ")"); | ||
90 | 94 | ||
91 | static int nowayout = WATCHDOG_NOWAYOUT; | 95 | static int nowayout = WATCHDOG_NOWAYOUT; |
92 | module_param(nowayout, int, 0); | 96 | module_param(nowayout, int, 0); |
93 | MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default=" __MODULE_STRING(WATCHDOG_NOWAYOUT) ")"); | 97 | MODULE_PARM_DESC(nowayout, |
98 | "Watchdog cannot be stopped once started (default=" | ||
99 | __MODULE_STRING(WATCHDOG_NOWAYOUT) ")"); | ||
94 | 100 | ||
95 | #ifdef CONFIG_WDT_501_PCI | 101 | #ifdef CONFIG_WDT_501_PCI |
96 | /* Support for the Fan Tachometer on the PCI-WDT501 */ | 102 | /* Support for the Fan Tachometer on the PCI-WDT501 */ |
97 | static int tachometer; | 103 | static int tachometer; |
98 | 104 | ||
99 | module_param(tachometer, int, 0); | 105 | module_param(tachometer, int, 0); |
100 | MODULE_PARM_DESC(tachometer, "PCI-WDT501 Fan Tachometer support (0=disable, default=0)"); | 106 | MODULE_PARM_DESC(tachometer, |
107 | "PCI-WDT501 Fan Tachometer support (0=disable, default=0)"); | ||
101 | #endif /* CONFIG_WDT_501_PCI */ | 108 | #endif /* CONFIG_WDT_501_PCI */ |
102 | 109 | ||
103 | /* | 110 | /* |
@@ -106,16 +113,19 @@ MODULE_PARM_DESC(tachometer, "PCI-WDT501 Fan Tachometer support (0=disable, defa | |||
106 | 113 | ||
107 | static void wdtpci_ctr_mode(int ctr, int mode) | 114 | static void wdtpci_ctr_mode(int ctr, int mode) |
108 | { | 115 | { |
109 | ctr<<=6; | 116 | ctr <<= 6; |
110 | ctr|=0x30; | 117 | ctr |= 0x30; |
111 | ctr|=(mode<<1); | 118 | ctr |= (mode << 1); |
112 | outb_p(ctr, WDT_CR); | 119 | outb(ctr, WDT_CR); |
120 | udelay(8); | ||
113 | } | 121 | } |
114 | 122 | ||
115 | static void wdtpci_ctr_load(int ctr, int val) | 123 | static void wdtpci_ctr_load(int ctr, int val) |
116 | { | 124 | { |
117 | outb_p(val&0xFF, WDT_COUNT0+ctr); | 125 | outb(val & 0xFF, WDT_COUNT0 + ctr); |
118 | outb_p(val>>8, WDT_COUNT0+ctr); | 126 | udelay(8); |
127 | outb(val >> 8, WDT_COUNT0 + ctr); | ||
128 | udelay(8); | ||
119 | } | 129 | } |
120 | 130 | ||
121 | /** | 131 | /** |
@@ -134,23 +144,35 @@ static int wdtpci_start(void) | |||
134 | * "pet" the watchdog, as Access says. | 144 | * "pet" the watchdog, as Access says. |
135 | * This resets the clock outputs. | 145 | * This resets the clock outputs. |
136 | */ | 146 | */ |
137 | inb_p(WDT_DC); /* Disable watchdog */ | 147 | inb(WDT_DC); /* Disable watchdog */ |
138 | wdtpci_ctr_mode(2,0); /* Program CTR2 for Mode 0: Pulse on Terminal Count */ | 148 | udelay(8); |
139 | outb_p(0, WDT_DC); /* Enable watchdog */ | 149 | wdtpci_ctr_mode(2, 0); /* Program CTR2 for Mode 0: |
140 | 150 | Pulse on Terminal Count */ | |
141 | inb_p(WDT_DC); /* Disable watchdog */ | 151 | outb(0, WDT_DC); /* Enable watchdog */ |
142 | outb_p(0, WDT_CLOCK); /* 2.0833MHz clock */ | 152 | udelay(8); |
143 | inb_p(WDT_BUZZER); /* disable */ | 153 | inb(WDT_DC); /* Disable watchdog */ |
144 | inb_p(WDT_OPTONOTRST); /* disable */ | 154 | udelay(8); |
145 | inb_p(WDT_OPTORST); /* disable */ | 155 | outb(0, WDT_CLOCK); /* 2.0833MHz clock */ |
146 | inb_p(WDT_PROGOUT); /* disable */ | 156 | udelay(8); |
147 | wdtpci_ctr_mode(0,3); /* Program CTR0 for Mode 3: Square Wave Generator */ | 157 | inb(WDT_BUZZER); /* disable */ |
148 | wdtpci_ctr_mode(1,2); /* Program CTR1 for Mode 2: Rate Generator */ | 158 | udelay(8); |
149 | wdtpci_ctr_mode(2,1); /* Program CTR2 for Mode 1: Retriggerable One-Shot */ | 159 | inb(WDT_OPTONOTRST); /* disable */ |
150 | wdtpci_ctr_load(0,20833); /* count at 100Hz */ | 160 | udelay(8); |
151 | wdtpci_ctr_load(1,wd_heartbeat);/* Heartbeat */ | 161 | inb(WDT_OPTORST); /* disable */ |
162 | udelay(8); | ||
163 | inb(WDT_PROGOUT); /* disable */ | ||
164 | udelay(8); | ||
165 | wdtpci_ctr_mode(0, 3); /* Program CTR0 for Mode 3: | ||
166 | Square Wave Generator */ | ||
167 | wdtpci_ctr_mode(1, 2); /* Program CTR1 for Mode 2: | ||
168 | Rate Generator */ | ||
169 | wdtpci_ctr_mode(2, 1); /* Program CTR2 for Mode 1: | ||
170 | Retriggerable One-Shot */ | ||
171 | wdtpci_ctr_load(0, 20833); /* count at 100Hz */ | ||
172 | wdtpci_ctr_load(1, wd_heartbeat);/* Heartbeat */ | ||
152 | /* DO NOT LOAD CTR2 on PCI card! -- JPN */ | 173 | /* DO NOT LOAD CTR2 on PCI card! -- JPN */ |
153 | outb_p(0, WDT_DC); /* Enable watchdog */ | 174 | outb(0, WDT_DC); /* Enable watchdog */ |
175 | udelay(8); | ||
154 | 176 | ||
155 | spin_unlock_irqrestore(&wdtpci_lock, flags); | 177 | spin_unlock_irqrestore(&wdtpci_lock, flags); |
156 | return 0; | 178 | return 0; |
@@ -162,14 +184,15 @@ static int wdtpci_start(void) | |||
162 | * Stop the watchdog driver. | 184 | * Stop the watchdog driver. |
163 | */ | 185 | */ |
164 | 186 | ||
165 | static int wdtpci_stop (void) | 187 | static int wdtpci_stop(void) |
166 | { | 188 | { |
167 | unsigned long flags; | 189 | unsigned long flags; |
168 | 190 | ||
169 | /* Turn the card off */ | 191 | /* Turn the card off */ |
170 | spin_lock_irqsave(&wdtpci_lock, flags); | 192 | spin_lock_irqsave(&wdtpci_lock, flags); |
171 | inb_p(WDT_DC); /* Disable watchdog */ | 193 | inb(WDT_DC); /* Disable watchdog */ |
172 | wdtpci_ctr_load(2,0); /* 0 length reset pulses now */ | 194 | udelay(8); |
195 | wdtpci_ctr_load(2, 0); /* 0 length reset pulses now */ | ||
173 | spin_unlock_irqrestore(&wdtpci_lock, flags); | 196 | spin_unlock_irqrestore(&wdtpci_lock, flags); |
174 | return 0; | 197 | return 0; |
175 | } | 198 | } |
@@ -177,20 +200,23 @@ static int wdtpci_stop (void) | |||
177 | /** | 200 | /** |
178 | * wdtpci_ping: | 201 | * wdtpci_ping: |
179 | * | 202 | * |
180 | * Reload counter one with the watchdog heartbeat. We don't bother reloading | 203 | * Reload counter one with the watchdog heartbeat. We don't bother |
181 | * the cascade counter. | 204 | * reloading the cascade counter. |
182 | */ | 205 | */ |
183 | 206 | ||
184 | static int wdtpci_ping(void) | 207 | static int wdtpci_ping(void) |
185 | { | 208 | { |
186 | unsigned long flags; | 209 | unsigned long flags; |
187 | 210 | ||
188 | /* Write a watchdog value */ | ||
189 | spin_lock_irqsave(&wdtpci_lock, flags); | 211 | spin_lock_irqsave(&wdtpci_lock, flags); |
190 | inb_p(WDT_DC); /* Disable watchdog */ | 212 | /* Write a watchdog value */ |
191 | wdtpci_ctr_mode(1,2); /* Re-Program CTR1 for Mode 2: Rate Generator */ | 213 | inb(WDT_DC); /* Disable watchdog */ |
192 | wdtpci_ctr_load(1,wd_heartbeat);/* Heartbeat */ | 214 | udelay(8); |
193 | outb_p(0, WDT_DC); /* Enable watchdog */ | 215 | wdtpci_ctr_mode(1, 2); /* Re-Program CTR1 for Mode 2: |
216 | Rate Generator */ | ||
217 | wdtpci_ctr_load(1, wd_heartbeat);/* Heartbeat */ | ||
218 | outb(0, WDT_DC); /* Enable watchdog */ | ||
219 | udelay(8); | ||
194 | spin_unlock_irqrestore(&wdtpci_lock, flags); | 220 | spin_unlock_irqrestore(&wdtpci_lock, flags); |
195 | return 0; | 221 | return 0; |
196 | } | 222 | } |
@@ -199,14 +225,14 @@ static int wdtpci_ping(void) | |||
199 | * wdtpci_set_heartbeat: | 225 | * wdtpci_set_heartbeat: |
200 | * @t: the new heartbeat value that needs to be set. | 226 | * @t: the new heartbeat value that needs to be set. |
201 | * | 227 | * |
202 | * Set a new heartbeat value for the watchdog device. If the heartbeat value is | 228 | * Set a new heartbeat value for the watchdog device. If the heartbeat |
203 | * incorrect we keep the old value and return -EINVAL. If successfull we | 229 | * value is incorrect we keep the old value and return -EINVAL. |
204 | * return 0. | 230 | * If successful we return 0. |
205 | */ | 231 | */ |
206 | static int wdtpci_set_heartbeat(int t) | 232 | static int wdtpci_set_heartbeat(int t) |
207 | { | 233 | { |
208 | /* Arbitrary, can't find the card's limits */ | 234 | /* Arbitrary, can't find the card's limits */ |
209 | if ((t < 1) || (t > 65535)) | 235 | if (t < 1 || t > 65535) |
210 | return -EINVAL; | 236 | return -EINVAL; |
211 | 237 | ||
212 | heartbeat = t; | 238 | heartbeat = t; |
@@ -227,9 +253,14 @@ static int wdtpci_set_heartbeat(int t) | |||
227 | 253 | ||
228 | static int wdtpci_get_status(int *status) | 254 | static int wdtpci_get_status(int *status) |
229 | { | 255 | { |
230 | unsigned char new_status=inb_p(WDT_SR); | 256 | unsigned char new_status; |
257 | unsigned long flags; | ||
258 | |||
259 | spin_lock_irqsave(&wdtpci_lock, flags); | ||
260 | new_status = inb(WDT_SR); | ||
261 | spin_unlock_irqrestore(&wdtpci_lock, flags); | ||
231 | 262 | ||
232 | *status=0; | 263 | *status = 0; |
233 | if (new_status & WDC_SR_ISOI0) | 264 | if (new_status & WDC_SR_ISOI0) |
234 | *status |= WDIOF_EXTERN1; | 265 | *status |= WDIOF_EXTERN1; |
235 | if (new_status & WDC_SR_ISII1) | 266 | if (new_status & WDC_SR_ISII1) |
@@ -259,8 +290,12 @@ static int wdtpci_get_status(int *status) | |||
259 | 290 | ||
260 | static int wdtpci_get_temperature(int *temperature) | 291 | static int wdtpci_get_temperature(int *temperature) |
261 | { | 292 | { |
262 | unsigned short c=inb_p(WDT_RT); | 293 | unsigned short c; |
263 | 294 | unsigned long flags; | |
295 | spin_lock_irqsave(&wdtpci_lock, flags); | ||
296 | c = inb(WDT_RT); | ||
297 | udelay(8); | ||
298 | spin_unlock_irqrestore(&wdtpci_lock, flags); | ||
264 | *temperature = (c * 11 / 15) + 7; | 299 | *temperature = (c * 11 / 15) + 7; |
265 | return 0; | 300 | return 0; |
266 | } | 301 | } |
@@ -282,17 +317,25 @@ static irqreturn_t wdtpci_interrupt(int irq, void *dev_id) | |||
282 | * Read the status register see what is up and | 317 | * Read the status register see what is up and |
283 | * then printk it. | 318 | * then printk it. |
284 | */ | 319 | */ |
285 | unsigned char status=inb_p(WDT_SR); | 320 | unsigned char status; |
321 | |||
322 | spin_lock(&wdtpci_lock); | ||
323 | |||
324 | status = inb(WDT_SR); | ||
325 | udelay(8); | ||
286 | 326 | ||
287 | printk(KERN_CRIT PFX "status %d\n", status); | 327 | printk(KERN_CRIT PFX "status %d\n", status); |
288 | 328 | ||
289 | #ifdef CONFIG_WDT_501_PCI | 329 | #ifdef CONFIG_WDT_501_PCI |
290 | if (!(status & WDC_SR_TGOOD)) | 330 | if (!(status & WDC_SR_TGOOD)) { |
291 | printk(KERN_CRIT PFX "Overheat alarm.(%d)\n",inb_p(WDT_RT)); | 331 | u8 alarm = inb(WDT_RT); |
332 | printk(KERN_CRIT PFX "Overheat alarm.(%d)\n", alarm); | ||
333 | udelay(8); | ||
334 | } | ||
292 | if (!(status & WDC_SR_PSUOVER)) | 335 | if (!(status & WDC_SR_PSUOVER)) |
293 | printk(KERN_CRIT PFX "PSU over voltage.\n"); | 336 | printk(KERN_CRIT PFX "PSU over voltage.\n"); |
294 | if (!(status & WDC_SR_PSUUNDR)) | 337 | if (!(status & WDC_SR_PSUUNDR)) |
295 | printk(KERN_CRIT PFX "PSU under voltage.\n"); | 338 | printk(KERN_CRIT PFX "PSU under voltage.\n"); |
296 | if (tachometer) { | 339 | if (tachometer) { |
297 | if (!(status & WDC_SR_FANGOOD)) | 340 | if (!(status & WDC_SR_FANGOOD)) |
298 | printk(KERN_CRIT PFX "Possible fan fault.\n"); | 341 | printk(KERN_CRIT PFX "Possible fan fault.\n"); |
@@ -310,6 +353,7 @@ static irqreturn_t wdtpci_interrupt(int irq, void *dev_id) | |||
310 | printk(KERN_CRIT PFX "Reset in 5ms.\n"); | 353 | printk(KERN_CRIT PFX "Reset in 5ms.\n"); |
311 | #endif | 354 | #endif |
312 | } | 355 | } |
356 | spin_unlock(&wdtpci_lock); | ||
313 | return IRQ_HANDLED; | 357 | return IRQ_HANDLED; |
314 | } | 358 | } |
315 | 359 | ||
@@ -325,7 +369,8 @@ static irqreturn_t wdtpci_interrupt(int irq, void *dev_id) | |||
325 | * write of data will do, as we we don't define content meaning. | 369 | * write of data will do, as we we don't define content meaning. |
326 | */ | 370 | */ |
327 | 371 | ||
328 | static ssize_t wdtpci_write(struct file *file, const char __user *buf, size_t count, loff_t *ppos) | 372 | static ssize_t wdtpci_write(struct file *file, const char __user *buf, |
373 | size_t count, loff_t *ppos) | ||
329 | { | 374 | { |
330 | if (count) { | 375 | if (count) { |
331 | if (!nowayout) { | 376 | if (!nowayout) { |
@@ -335,7 +380,7 @@ static ssize_t wdtpci_write(struct file *file, const char __user *buf, size_t co | |||
335 | 380 | ||
336 | for (i = 0; i != count; i++) { | 381 | for (i = 0; i != count; i++) { |
337 | char c; | 382 | char c; |
338 | if(get_user(c, buf+i)) | 383 | if (get_user(c, buf+i)) |
339 | return -EFAULT; | 384 | return -EFAULT; |
340 | if (c == 'V') | 385 | if (c == 'V') |
341 | expect_close = 42; | 386 | expect_close = 42; |
@@ -343,13 +388,11 @@ static ssize_t wdtpci_write(struct file *file, const char __user *buf, size_t co | |||
343 | } | 388 | } |
344 | wdtpci_ping(); | 389 | wdtpci_ping(); |
345 | } | 390 | } |
346 | |||
347 | return count; | 391 | return count; |
348 | } | 392 | } |
349 | 393 | ||
350 | /** | 394 | /** |
351 | * wdtpci_ioctl: | 395 | * wdtpci_ioctl: |
352 | * @inode: inode of the device | ||
353 | * @file: file handle to the device | 396 | * @file: file handle to the device |
354 | * @cmd: watchdog command | 397 | * @cmd: watchdog command |
355 | * @arg: argument pointer | 398 | * @arg: argument pointer |
@@ -359,8 +402,8 @@ static ssize_t wdtpci_write(struct file *file, const char __user *buf, size_t co | |||
359 | * querying capabilities and current status. | 402 | * querying capabilities and current status. |
360 | */ | 403 | */ |
361 | 404 | ||
362 | static int wdtpci_ioctl(struct inode *inode, struct file *file, unsigned int cmd, | 405 | static long wdtpci_ioctl(struct file *file, unsigned int cmd, |
363 | unsigned long arg) | 406 | unsigned long arg) |
364 | { | 407 | { |
365 | int new_heartbeat; | 408 | int new_heartbeat; |
366 | int status; | 409 | int status; |
@@ -383,33 +426,29 @@ static int wdtpci_ioctl(struct inode *inode, struct file *file, unsigned int cmd | |||
383 | ident.options |= WDIOF_FANFAULT; | 426 | ident.options |= WDIOF_FANFAULT; |
384 | #endif /* CONFIG_WDT_501_PCI */ | 427 | #endif /* CONFIG_WDT_501_PCI */ |
385 | 428 | ||
386 | switch(cmd) | 429 | switch (cmd) { |
387 | { | 430 | default: |
388 | default: | 431 | return -ENOTTY; |
389 | return -ENOTTY; | 432 | case WDIOC_GETSUPPORT: |
390 | case WDIOC_GETSUPPORT: | 433 | return copy_to_user(argp, &ident, sizeof(ident)) ? -EFAULT : 0; |
391 | return copy_to_user(argp, &ident, sizeof(ident))?-EFAULT:0; | 434 | case WDIOC_GETSTATUS: |
392 | 435 | wdtpci_get_status(&status); | |
393 | case WDIOC_GETSTATUS: | 436 | return put_user(status, p); |
394 | wdtpci_get_status(&status); | 437 | case WDIOC_GETBOOTSTATUS: |
395 | return put_user(status, p); | 438 | return put_user(0, p); |
396 | case WDIOC_GETBOOTSTATUS: | 439 | case WDIOC_KEEPALIVE: |
397 | return put_user(0, p); | 440 | wdtpci_ping(); |
398 | case WDIOC_KEEPALIVE: | 441 | return 0; |
399 | wdtpci_ping(); | 442 | case WDIOC_SETTIMEOUT: |
400 | return 0; | 443 | if (get_user(new_heartbeat, p)) |
401 | case WDIOC_SETTIMEOUT: | 444 | return -EFAULT; |
402 | if (get_user(new_heartbeat, p)) | 445 | if (wdtpci_set_heartbeat(new_heartbeat)) |
403 | return -EFAULT; | 446 | return -EINVAL; |
404 | 447 | wdtpci_ping(); | |
405 | if (wdtpci_set_heartbeat(new_heartbeat)) | 448 | /* Fall */ |
406 | return -EINVAL; | 449 | case WDIOC_GETTIMEOUT: |
407 | 450 | return put_user(heartbeat, p); | |
408 | wdtpci_ping(); | 451 | } |
409 | /* Fall */ | ||
410 | case WDIOC_GETTIMEOUT: | ||
411 | return put_user(heartbeat, p); | ||
412 | } | ||
413 | } | 452 | } |
414 | 453 | ||
415 | /** | 454 | /** |
@@ -426,12 +465,11 @@ static int wdtpci_ioctl(struct inode *inode, struct file *file, unsigned int cmd | |||
426 | 465 | ||
427 | static int wdtpci_open(struct inode *inode, struct file *file) | 466 | static int wdtpci_open(struct inode *inode, struct file *file) |
428 | { | 467 | { |
429 | if (down_trylock(&open_sem)) | 468 | if (test_and_set_bit(0, &open_lock)) |
430 | return -EBUSY; | 469 | return -EBUSY; |
431 | 470 | ||
432 | if (nowayout) { | 471 | if (nowayout) |
433 | __module_get(THIS_MODULE); | 472 | __module_get(THIS_MODULE); |
434 | } | ||
435 | /* | 473 | /* |
436 | * Activate | 474 | * Activate |
437 | */ | 475 | */ |
@@ -460,7 +498,7 @@ static int wdtpci_release(struct inode *inode, struct file *file) | |||
460 | wdtpci_ping(); | 498 | wdtpci_ping(); |
461 | } | 499 | } |
462 | expect_close = 0; | 500 | expect_close = 0; |
463 | up(&open_sem); | 501 | clear_bit(0, &open_lock); |
464 | return 0; | 502 | return 0; |
465 | } | 503 | } |
466 | 504 | ||
@@ -476,14 +514,15 @@ static int wdtpci_release(struct inode *inode, struct file *file) | |||
476 | * fahrenheit. It was designed by an imperial measurement luddite. | 514 | * fahrenheit. It was designed by an imperial measurement luddite. |
477 | */ | 515 | */ |
478 | 516 | ||
479 | static ssize_t wdtpci_temp_read(struct file *file, char __user *buf, size_t count, loff_t *ptr) | 517 | static ssize_t wdtpci_temp_read(struct file *file, char __user *buf, |
518 | size_t count, loff_t *ptr) | ||
480 | { | 519 | { |
481 | int temperature; | 520 | int temperature; |
482 | 521 | ||
483 | if (wdtpci_get_temperature(&temperature)) | 522 | if (wdtpci_get_temperature(&temperature)) |
484 | return -EFAULT; | 523 | return -EFAULT; |
485 | 524 | ||
486 | if (copy_to_user (buf, &temperature, 1)) | 525 | if (copy_to_user(buf, &temperature, 1)) |
487 | return -EFAULT; | 526 | return -EFAULT; |
488 | 527 | ||
489 | return 1; | 528 | return 1; |
@@ -529,12 +568,10 @@ static int wdtpci_temp_release(struct inode *inode, struct file *file) | |||
529 | */ | 568 | */ |
530 | 569 | ||
531 | static int wdtpci_notify_sys(struct notifier_block *this, unsigned long code, | 570 | static int wdtpci_notify_sys(struct notifier_block *this, unsigned long code, |
532 | void *unused) | 571 | void *unused) |
533 | { | 572 | { |
534 | if (code==SYS_DOWN || code==SYS_HALT) { | 573 | if (code == SYS_DOWN || code == SYS_HALT) |
535 | /* Turn the card off */ | ||
536 | wdtpci_stop(); | 574 | wdtpci_stop(); |
537 | } | ||
538 | return NOTIFY_DONE; | 575 | return NOTIFY_DONE; |
539 | } | 576 | } |
540 | 577 | ||
@@ -547,7 +584,7 @@ static const struct file_operations wdtpci_fops = { | |||
547 | .owner = THIS_MODULE, | 584 | .owner = THIS_MODULE, |
548 | .llseek = no_llseek, | 585 | .llseek = no_llseek, |
549 | .write = wdtpci_write, | 586 | .write = wdtpci_write, |
550 | .ioctl = wdtpci_ioctl, | 587 | .unlocked_ioctl = wdtpci_ioctl, |
551 | .open = wdtpci_open, | 588 | .open = wdtpci_open, |
552 | .release = wdtpci_release, | 589 | .release = wdtpci_release, |
553 | }; | 590 | }; |
@@ -584,80 +621,85 @@ static struct notifier_block wdtpci_notifier = { | |||
584 | }; | 621 | }; |
585 | 622 | ||
586 | 623 | ||
587 | static int __devinit wdtpci_init_one (struct pci_dev *dev, | 624 | static int __devinit wdtpci_init_one(struct pci_dev *dev, |
588 | const struct pci_device_id *ent) | 625 | const struct pci_device_id *ent) |
589 | { | 626 | { |
590 | int ret = -EIO; | 627 | int ret = -EIO; |
591 | 628 | ||
592 | dev_count++; | 629 | dev_count++; |
593 | if (dev_count > 1) { | 630 | if (dev_count > 1) { |
594 | printk (KERN_ERR PFX "this driver only supports 1 device\n"); | 631 | printk(KERN_ERR PFX "This driver only supports one device\n"); |
595 | return -ENODEV; | 632 | return -ENODEV; |
596 | } | 633 | } |
597 | 634 | ||
598 | if (pci_enable_device (dev)) { | 635 | if (pci_enable_device(dev)) { |
599 | printk (KERN_ERR PFX "Not possible to enable PCI Device\n"); | 636 | printk(KERN_ERR PFX "Not possible to enable PCI Device\n"); |
600 | return -ENODEV; | 637 | return -ENODEV; |
601 | } | 638 | } |
602 | 639 | ||
603 | if (pci_resource_start (dev, 2) == 0x0000) { | 640 | if (pci_resource_start(dev, 2) == 0x0000) { |
604 | printk (KERN_ERR PFX "No I/O-Address for card detected\n"); | 641 | printk(KERN_ERR PFX "No I/O-Address for card detected\n"); |
605 | ret = -ENODEV; | 642 | ret = -ENODEV; |
606 | goto out_pci; | 643 | goto out_pci; |
607 | } | 644 | } |
608 | 645 | ||
609 | sema_init(&open_sem, 1); | ||
610 | |||
611 | irq = dev->irq; | 646 | irq = dev->irq; |
612 | io = pci_resource_start (dev, 2); | 647 | io = pci_resource_start(dev, 2); |
613 | 648 | ||
614 | if (request_region (io, 16, "wdt_pci") == NULL) { | 649 | if (request_region(io, 16, "wdt_pci") == NULL) { |
615 | printk (KERN_ERR PFX "I/O address 0x%04x already in use\n", io); | 650 | printk(KERN_ERR PFX "I/O address 0x%04x already in use\n", io); |
616 | goto out_pci; | 651 | goto out_pci; |
617 | } | 652 | } |
618 | 653 | ||
619 | if (request_irq (irq, wdtpci_interrupt, IRQF_DISABLED | IRQF_SHARED, | 654 | if (request_irq(irq, wdtpci_interrupt, IRQF_DISABLED | IRQF_SHARED, |
620 | "wdt_pci", &wdtpci_miscdev)) { | 655 | "wdt_pci", &wdtpci_miscdev)) { |
621 | printk (KERN_ERR PFX "IRQ %d is not free\n", irq); | 656 | printk(KERN_ERR PFX "IRQ %d is not free\n", irq); |
622 | goto out_reg; | 657 | goto out_reg; |
623 | } | 658 | } |
624 | 659 | ||
625 | printk ("PCI-WDT500/501 (PCI-WDG-CSM) driver 0.10 at 0x%04x (Interrupt %d)\n", | 660 | printk(KERN_INFO |
626 | io, irq); | 661 | "PCI-WDT500/501 (PCI-WDG-CSM) driver 0.10 at 0x%04x (Interrupt %d)\n", |
662 | io, irq); | ||
627 | 663 | ||
628 | /* Check that the heartbeat value is within it's range ; if not reset to the default */ | 664 | /* Check that the heartbeat value is within its range; |
665 | if not reset to the default */ | ||
629 | if (wdtpci_set_heartbeat(heartbeat)) { | 666 | if (wdtpci_set_heartbeat(heartbeat)) { |
630 | wdtpci_set_heartbeat(WD_TIMO); | 667 | wdtpci_set_heartbeat(WD_TIMO); |
631 | printk(KERN_INFO PFX "heartbeat value must be 0<heartbeat<65536, using %d\n", | 668 | printk(KERN_INFO PFX |
632 | WD_TIMO); | 669 | "heartbeat value must be 0 < heartbeat < 65536, using %d\n", |
670 | WD_TIMO); | ||
633 | } | 671 | } |
634 | 672 | ||
635 | ret = register_reboot_notifier (&wdtpci_notifier); | 673 | ret = register_reboot_notifier(&wdtpci_notifier); |
636 | if (ret) { | 674 | if (ret) { |
637 | printk (KERN_ERR PFX "cannot register reboot notifier (err=%d)\n", ret); | 675 | printk(KERN_ERR PFX |
676 | "cannot register reboot notifier (err=%d)\n", ret); | ||
638 | goto out_irq; | 677 | goto out_irq; |
639 | } | 678 | } |
640 | 679 | ||
641 | #ifdef CONFIG_WDT_501_PCI | 680 | #ifdef CONFIG_WDT_501_PCI |
642 | ret = misc_register (&temp_miscdev); | 681 | ret = misc_register(&temp_miscdev); |
643 | if (ret) { | 682 | if (ret) { |
644 | printk (KERN_ERR PFX "cannot register miscdev on minor=%d (err=%d)\n", | 683 | printk(KERN_ERR PFX |
645 | TEMP_MINOR, ret); | 684 | "cannot register miscdev on minor=%d (err=%d)\n", |
685 | TEMP_MINOR, ret); | ||
646 | goto out_rbt; | 686 | goto out_rbt; |
647 | } | 687 | } |
648 | #endif /* CONFIG_WDT_501_PCI */ | 688 | #endif /* CONFIG_WDT_501_PCI */ |
649 | 689 | ||
650 | ret = misc_register (&wdtpci_miscdev); | 690 | ret = misc_register(&wdtpci_miscdev); |
651 | if (ret) { | 691 | if (ret) { |
652 | printk (KERN_ERR PFX "cannot register miscdev on minor=%d (err=%d)\n", | 692 | printk(KERN_ERR PFX |
653 | WATCHDOG_MINOR, ret); | 693 | "cannot register miscdev on minor=%d (err=%d)\n", |
694 | WATCHDOG_MINOR, ret); | ||
654 | goto out_misc; | 695 | goto out_misc; |
655 | } | 696 | } |
656 | 697 | ||
657 | printk(KERN_INFO PFX "initialized. heartbeat=%d sec (nowayout=%d)\n", | 698 | printk(KERN_INFO PFX "initialized. heartbeat=%d sec (nowayout=%d)\n", |
658 | heartbeat, nowayout); | 699 | heartbeat, nowayout); |
659 | #ifdef CONFIG_WDT_501_PCI | 700 | #ifdef CONFIG_WDT_501_PCI |
660 | printk(KERN_INFO "wdt: Fan Tachometer is %s\n", (tachometer ? "Enabled" : "Disabled")); | 701 | printk(KERN_INFO "wdt: Fan Tachometer is %s\n", |
702 | (tachometer ? "Enabled" : "Disabled")); | ||
661 | #endif /* CONFIG_WDT_501_PCI */ | 703 | #endif /* CONFIG_WDT_501_PCI */ |
662 | 704 | ||
663 | ret = 0; | 705 | ret = 0; |
@@ -673,14 +715,14 @@ out_rbt: | |||
673 | out_irq: | 715 | out_irq: |
674 | free_irq(irq, &wdtpci_miscdev); | 716 | free_irq(irq, &wdtpci_miscdev); |
675 | out_reg: | 717 | out_reg: |
676 | release_region (io, 16); | 718 | release_region(io, 16); |
677 | out_pci: | 719 | out_pci: |
678 | pci_disable_device(dev); | 720 | pci_disable_device(dev); |
679 | goto out; | 721 | goto out; |
680 | } | 722 | } |
681 | 723 | ||
682 | 724 | ||
683 | static void __devexit wdtpci_remove_one (struct pci_dev *pdev) | 725 | static void __devexit wdtpci_remove_one(struct pci_dev *pdev) |
684 | { | 726 | { |
685 | /* here we assume only one device will ever have | 727 | /* here we assume only one device will ever have |
686 | * been picked up and registered by probe function */ | 728 | * been picked up and registered by probe function */ |
@@ -728,7 +770,7 @@ static struct pci_driver wdtpci_driver = { | |||
728 | 770 | ||
729 | static void __exit wdtpci_cleanup(void) | 771 | static void __exit wdtpci_cleanup(void) |
730 | { | 772 | { |
731 | pci_unregister_driver (&wdtpci_driver); | 773 | pci_unregister_driver(&wdtpci_driver); |
732 | } | 774 | } |
733 | 775 | ||
734 | 776 | ||
@@ -742,7 +784,7 @@ static void __exit wdtpci_cleanup(void) | |||
742 | 784 | ||
743 | static int __init wdtpci_init(void) | 785 | static int __init wdtpci_init(void) |
744 | { | 786 | { |
745 | return pci_register_driver (&wdtpci_driver); | 787 | return pci_register_driver(&wdtpci_driver); |
746 | } | 788 | } |
747 | 789 | ||
748 | 790 | ||