diff options
Diffstat (limited to 'drivers/watchdog/pcwd.c')
-rw-r--r-- | drivers/watchdog/pcwd.c | 191 |
1 files changed, 106 insertions, 85 deletions
diff --git a/drivers/watchdog/pcwd.c b/drivers/watchdog/pcwd.c index 7b41434fac8c..3b0ddc7fcf3f 100644 --- a/drivers/watchdog/pcwd.c +++ b/drivers/watchdog/pcwd.c | |||
@@ -40,13 +40,15 @@ | |||
40 | * fairly useless proc entry. | 40 | * fairly useless proc entry. |
41 | * 990610 removed said useless proc code for the merge <alan> | 41 | * 990610 removed said useless proc code for the merge <alan> |
42 | * 000403 Removed last traces of proc code. <davej> | 42 | * 000403 Removed last traces of proc code. <davej> |
43 | * 011214 Added nowayout module option to override CONFIG_WATCHDOG_NOWAYOUT <Matt_Domsch@dell.com> | 43 | * 011214 Added nowayout module option to override |
44 | * CONFIG_WATCHDOG_NOWAYOUT <Matt_Domsch@dell.com> | ||
44 | * Added timeout module option to override default | 45 | * Added timeout module option to override default |
45 | */ | 46 | */ |
46 | 47 | ||
47 | /* | 48 | /* |
48 | * A bells and whistles driver is available from http://www.pcwd.de/ | 49 | * A bells and whistles driver is available from http://www.pcwd.de/ |
49 | * More info available at http://www.berkprod.com/ or http://www.pcwatchdog.com/ | 50 | * More info available at http://www.berkprod.com/ or |
51 | * http://www.pcwatchdog.com/ | ||
50 | */ | 52 | */ |
51 | 53 | ||
52 | #include <linux/module.h> /* For module specific items */ | 54 | #include <linux/module.h> /* For module specific items */ |
@@ -65,9 +67,8 @@ | |||
65 | #include <linux/isa.h> /* For isa devices */ | 67 | #include <linux/isa.h> /* For isa devices */ |
66 | #include <linux/ioport.h> /* For io-port access */ | 68 | #include <linux/ioport.h> /* For io-port access */ |
67 | #include <linux/spinlock.h> /* For spin_lock/spin_unlock/... */ | 69 | #include <linux/spinlock.h> /* For spin_lock/spin_unlock/... */ |
68 | 70 | #include <linux/uaccess.h> /* For copy_to_user/put_user/... */ | |
69 | #include <asm/uaccess.h> /* For copy_to_user/put_user/... */ | 71 | #include <linux/io.h> /* For inb/outb/... */ |
70 | #include <asm/io.h> /* For inb/outb/... */ | ||
71 | 72 | ||
72 | /* Module and version information */ | 73 | /* Module and version information */ |
73 | #define WATCHDOG_VERSION "1.20" | 74 | #define WATCHDOG_VERSION "1.20" |
@@ -111,14 +112,16 @@ static int pcwd_ioports[] = { 0x270, 0x350, 0x370, 0x000 }; | |||
111 | #define WD_REVC_WTRP 0x01 /* Watchdog Trip status */ | 112 | #define WD_REVC_WTRP 0x01 /* Watchdog Trip status */ |
112 | #define WD_REVC_HRBT 0x02 /* Watchdog Heartbeat */ | 113 | #define WD_REVC_HRBT 0x02 /* Watchdog Heartbeat */ |
113 | #define WD_REVC_TTRP 0x04 /* Temperature Trip status */ | 114 | #define WD_REVC_TTRP 0x04 /* Temperature Trip status */ |
114 | #define WD_REVC_RL2A 0x08 /* Relay 2 activated by on-board processor */ | 115 | #define WD_REVC_RL2A 0x08 /* Relay 2 activated by |
116 | on-board processor */ | ||
115 | #define WD_REVC_RL1A 0x10 /* Relay 1 active */ | 117 | #define WD_REVC_RL1A 0x10 /* Relay 1 active */ |
116 | #define WD_REVC_R2DS 0x40 /* Relay 2 disable */ | 118 | #define WD_REVC_R2DS 0x40 /* Relay 2 disable */ |
117 | #define WD_REVC_RLY2 0x80 /* Relay 2 activated? */ | 119 | #define WD_REVC_RLY2 0x80 /* Relay 2 activated? */ |
118 | /* Port 2 : Control Status #2 */ | 120 | /* Port 2 : Control Status #2 */ |
119 | #define WD_WDIS 0x10 /* Watchdog Disabled */ | 121 | #define WD_WDIS 0x10 /* Watchdog Disabled */ |
120 | #define WD_ENTP 0x20 /* Watchdog Enable Temperature Trip */ | 122 | #define WD_ENTP 0x20 /* Watchdog Enable Temperature Trip */ |
121 | #define WD_SSEL 0x40 /* Watchdog Switch Select (1:SW1 <-> 0:SW2) */ | 123 | #define WD_SSEL 0x40 /* Watchdog Switch Select |
124 | (1:SW1 <-> 0:SW2) */ | ||
122 | #define WD_WCMD 0x80 /* Watchdog Command Mode */ | 125 | #define WD_WCMD 0x80 /* Watchdog Command Mode */ |
123 | 126 | ||
124 | /* max. time we give an ISA watchdog card to process a command */ | 127 | /* max. time we give an ISA watchdog card to process a command */ |
@@ -142,7 +145,7 @@ static int pcwd_ioports[] = { 0x270, 0x350, 0x370, 0x000 }; | |||
142 | #define CMD_ISA_RESET_RELAYS 0x0D | 145 | #define CMD_ISA_RESET_RELAYS 0x0D |
143 | 146 | ||
144 | /* Watchdog's Dip Switch heartbeat values */ | 147 | /* Watchdog's Dip Switch heartbeat values */ |
145 | static const int heartbeat_tbl [] = { | 148 | static const int heartbeat_tbl[] = { |
146 | 20, /* OFF-OFF-OFF = 20 Sec */ | 149 | 20, /* OFF-OFF-OFF = 20 Sec */ |
147 | 40, /* OFF-OFF-ON = 40 Sec */ | 150 | 40, /* OFF-OFF-ON = 40 Sec */ |
148 | 60, /* OFF-ON-OFF = 1 Min */ | 151 | 60, /* OFF-ON-OFF = 1 Min */ |
@@ -168,11 +171,15 @@ static int cards_found; | |||
168 | static atomic_t open_allowed = ATOMIC_INIT(1); | 171 | static atomic_t open_allowed = ATOMIC_INIT(1); |
169 | static char expect_close; | 172 | static char expect_close; |
170 | static int temp_panic; | 173 | static int temp_panic; |
171 | static struct { /* this is private data for each ISA-PC watchdog card */ | 174 | |
175 | /* this is private data for each ISA-PC watchdog card */ | ||
176 | static struct { | ||
172 | char fw_ver_str[6]; /* The cards firmware version */ | 177 | char fw_ver_str[6]; /* The cards firmware version */ |
173 | int revision; /* The card's revision */ | 178 | int revision; /* The card's revision */ |
174 | int supports_temp; /* Wether or not the card has a temperature device */ | 179 | int supports_temp; /* Whether or not the card has |
175 | int command_mode; /* Wether or not the card is in command mode */ | 180 | a temperature device */ |
181 | int command_mode; /* Whether or not the card is in | ||
182 | command mode */ | ||
176 | int boot_status; /* The card's boot status */ | 183 | int boot_status; /* The card's boot status */ |
177 | int io_addr; /* The cards I/O address */ | 184 | int io_addr; /* The cards I/O address */ |
178 | spinlock_t io_lock; /* the lock for io operations */ | 185 | spinlock_t io_lock; /* the lock for io operations */ |
@@ -186,16 +193,20 @@ static struct { /* this is private data for each ISA-PC watchdog card */ | |||
186 | #define DEBUG 2 /* print fancy stuff too */ | 193 | #define DEBUG 2 /* print fancy stuff too */ |
187 | static int debug = QUIET; | 194 | static int debug = QUIET; |
188 | module_param(debug, int, 0); | 195 | module_param(debug, int, 0); |
189 | MODULE_PARM_DESC(debug, "Debug level: 0=Quiet, 1=Verbose, 2=Debug (default=0)"); | 196 | MODULE_PARM_DESC(debug, |
197 | "Debug level: 0=Quiet, 1=Verbose, 2=Debug (default=0)"); | ||
190 | 198 | ||
191 | #define WATCHDOG_HEARTBEAT 0 /* default heartbeat = delay-time from dip-switches */ | 199 | /* default heartbeat = delay-time from dip-switches */ |
200 | #define WATCHDOG_HEARTBEAT 0 | ||
192 | static int heartbeat = WATCHDOG_HEARTBEAT; | 201 | static int heartbeat = WATCHDOG_HEARTBEAT; |
193 | module_param(heartbeat, int, 0); | 202 | module_param(heartbeat, int, 0); |
194 | MODULE_PARM_DESC(heartbeat, "Watchdog heartbeat in seconds. (2<=heartbeat<=7200 or 0=delay-time from dip-switches, default=" __MODULE_STRING(WATCHDOG_HEARTBEAT) ")"); | 203 | MODULE_PARM_DESC(heartbeat, "Watchdog heartbeat in seconds. (2 <= heartbeat <= 7200 or 0=delay-time from dip-switches, default=" __MODULE_STRING(WATCHDOG_HEARTBEAT) ")"); |
195 | 204 | ||
196 | static int nowayout = WATCHDOG_NOWAYOUT; | 205 | static int nowayout = WATCHDOG_NOWAYOUT; |
197 | module_param(nowayout, int, 0); | 206 | module_param(nowayout, int, 0); |
198 | MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default=" __MODULE_STRING(WATCHDOG_NOWAYOUT) ")"); | 207 | MODULE_PARM_DESC(nowayout, |
208 | "Watchdog cannot be stopped once started (default=" | ||
209 | __MODULE_STRING(WATCHDOG_NOWAYOUT) ")"); | ||
199 | 210 | ||
200 | /* | 211 | /* |
201 | * Internal functions | 212 | * Internal functions |
@@ -224,7 +235,7 @@ static int send_isa_command(int cmd) | |||
224 | if (port0 == last_port0) | 235 | if (port0 == last_port0) |
225 | break; /* Data is stable */ | 236 | break; /* Data is stable */ |
226 | 237 | ||
227 | udelay (250); | 238 | udelay(250); |
228 | } | 239 | } |
229 | 240 | ||
230 | if (debug >= DEBUG) | 241 | if (debug >= DEBUG) |
@@ -236,7 +247,7 @@ static int send_isa_command(int cmd) | |||
236 | 247 | ||
237 | static int set_command_mode(void) | 248 | static int set_command_mode(void) |
238 | { | 249 | { |
239 | int i, found=0, count=0; | 250 | int i, found = 0, count = 0; |
240 | 251 | ||
241 | /* Set the card into command mode */ | 252 | /* Set the card into command mode */ |
242 | spin_lock(&pcwd_private.io_lock); | 253 | spin_lock(&pcwd_private.io_lock); |
@@ -261,7 +272,7 @@ static int set_command_mode(void) | |||
261 | printk(KERN_DEBUG PFX "command_mode=%d\n", | 272 | printk(KERN_DEBUG PFX "command_mode=%d\n", |
262 | pcwd_private.command_mode); | 273 | pcwd_private.command_mode); |
263 | 274 | ||
264 | return(found); | 275 | return found; |
265 | } | 276 | } |
266 | 277 | ||
267 | static void unset_command_mode(void) | 278 | static void unset_command_mode(void) |
@@ -296,7 +307,8 @@ static inline void pcwd_get_firmware(void) | |||
296 | ten = send_isa_command(CMD_ISA_VERSION_TENTH); | 307 | ten = send_isa_command(CMD_ISA_VERSION_TENTH); |
297 | hund = send_isa_command(CMD_ISA_VERSION_HUNDRETH); | 308 | hund = send_isa_command(CMD_ISA_VERSION_HUNDRETH); |
298 | minor = send_isa_command(CMD_ISA_VERSION_MINOR); | 309 | minor = send_isa_command(CMD_ISA_VERSION_MINOR); |
299 | sprintf(pcwd_private.fw_ver_str, "%c.%c%c%c", one, ten, hund, minor); | 310 | sprintf(pcwd_private.fw_ver_str, "%c.%c%c%c", |
311 | one, ten, hund, minor); | ||
300 | } | 312 | } |
301 | unset_command_mode(); | 313 | unset_command_mode(); |
302 | 314 | ||
@@ -305,7 +317,7 @@ static inline void pcwd_get_firmware(void) | |||
305 | 317 | ||
306 | static inline int pcwd_get_option_switches(void) | 318 | static inline int pcwd_get_option_switches(void) |
307 | { | 319 | { |
308 | int option_switches=0; | 320 | int option_switches = 0; |
309 | 321 | ||
310 | if (set_command_mode()) { | 322 | if (set_command_mode()) { |
311 | /* Get switch settings */ | 323 | /* Get switch settings */ |
@@ -313,7 +325,7 @@ static inline int pcwd_get_option_switches(void) | |||
313 | } | 325 | } |
314 | 326 | ||
315 | unset_command_mode(); | 327 | unset_command_mode(); |
316 | return(option_switches); | 328 | return option_switches; |
317 | } | 329 | } |
318 | 330 | ||
319 | static void pcwd_show_card_info(void) | 331 | static void pcwd_show_card_info(void) |
@@ -322,7 +334,9 @@ static void pcwd_show_card_info(void) | |||
322 | 334 | ||
323 | /* Get some extra info from the hardware (in command/debug/diag mode) */ | 335 | /* Get some extra info from the hardware (in command/debug/diag mode) */ |
324 | if (pcwd_private.revision == PCWD_REVISION_A) | 336 | if (pcwd_private.revision == PCWD_REVISION_A) |
325 | printk(KERN_INFO PFX "ISA-PC Watchdog (REV.A) detected at port 0x%04x\n", pcwd_private.io_addr); | 337 | printk(KERN_INFO PFX |
338 | "ISA-PC Watchdog (REV.A) detected at port 0x%04x\n", | ||
339 | pcwd_private.io_addr); | ||
326 | else if (pcwd_private.revision == PCWD_REVISION_C) { | 340 | else if (pcwd_private.revision == PCWD_REVISION_C) { |
327 | pcwd_get_firmware(); | 341 | pcwd_get_firmware(); |
328 | printk(KERN_INFO PFX "ISA-PC Watchdog (REV.C) detected at port 0x%04x (Firmware version: %s)\n", | 342 | printk(KERN_INFO PFX "ISA-PC Watchdog (REV.C) detected at port 0x%04x (Firmware version: %s)\n", |
@@ -347,12 +361,15 @@ static void pcwd_show_card_info(void) | |||
347 | printk(KERN_INFO PFX "Previous reboot was caused by the card\n"); | 361 | printk(KERN_INFO PFX "Previous reboot was caused by the card\n"); |
348 | 362 | ||
349 | if (pcwd_private.boot_status & WDIOF_OVERHEAT) { | 363 | if (pcwd_private.boot_status & WDIOF_OVERHEAT) { |
350 | printk(KERN_EMERG PFX "Card senses a CPU Overheat. Panicking!\n"); | 364 | printk(KERN_EMERG PFX |
351 | printk(KERN_EMERG PFX "CPU Overheat\n"); | 365 | "Card senses a CPU Overheat. Panicking!\n"); |
366 | printk(KERN_EMERG PFX | ||
367 | "CPU Overheat\n"); | ||
352 | } | 368 | } |
353 | 369 | ||
354 | if (pcwd_private.boot_status == 0) | 370 | if (pcwd_private.boot_status == 0) |
355 | printk(KERN_INFO PFX "No previous trip detected - Cold boot or reset\n"); | 371 | printk(KERN_INFO PFX |
372 | "No previous trip detected - Cold boot or reset\n"); | ||
356 | } | 373 | } |
357 | 374 | ||
358 | static void pcwd_timer_ping(unsigned long data) | 375 | static void pcwd_timer_ping(unsigned long data) |
@@ -361,11 +378,12 @@ static void pcwd_timer_ping(unsigned long data) | |||
361 | 378 | ||
362 | /* If we got a heartbeat pulse within the WDT_INTERVAL | 379 | /* If we got a heartbeat pulse within the WDT_INTERVAL |
363 | * we agree to ping the WDT */ | 380 | * we agree to ping the WDT */ |
364 | if(time_before(jiffies, pcwd_private.next_heartbeat)) { | 381 | if (time_before(jiffies, pcwd_private.next_heartbeat)) { |
365 | /* Ping the watchdog */ | 382 | /* Ping the watchdog */ |
366 | spin_lock(&pcwd_private.io_lock); | 383 | spin_lock(&pcwd_private.io_lock); |
367 | if (pcwd_private.revision == PCWD_REVISION_A) { | 384 | if (pcwd_private.revision == PCWD_REVISION_A) { |
368 | /* Rev A cards are reset by setting the WD_WDRST bit in register 1 */ | 385 | /* Rev A cards are reset by setting the |
386 | WD_WDRST bit in register 1 */ | ||
369 | wdrst_stat = inb_p(pcwd_private.io_addr); | 387 | wdrst_stat = inb_p(pcwd_private.io_addr); |
370 | wdrst_stat &= 0x0F; | 388 | wdrst_stat &= 0x0F; |
371 | wdrst_stat |= WD_WDRST; | 389 | wdrst_stat |= WD_WDRST; |
@@ -381,7 +399,8 @@ static void pcwd_timer_ping(unsigned long data) | |||
381 | 399 | ||
382 | spin_unlock(&pcwd_private.io_lock); | 400 | spin_unlock(&pcwd_private.io_lock); |
383 | } else { | 401 | } else { |
384 | printk(KERN_WARNING PFX "Heartbeat lost! Will not ping the watchdog\n"); | 402 | printk(KERN_WARNING PFX |
403 | "Heartbeat lost! Will not ping the watchdog\n"); | ||
385 | } | 404 | } |
386 | } | 405 | } |
387 | 406 | ||
@@ -454,7 +473,7 @@ static int pcwd_keepalive(void) | |||
454 | 473 | ||
455 | static int pcwd_set_heartbeat(int t) | 474 | static int pcwd_set_heartbeat(int t) |
456 | { | 475 | { |
457 | if ((t < 2) || (t > 7200)) /* arbitrary upper limit */ | 476 | if (t < 2 || t > 7200) /* arbitrary upper limit */ |
458 | return -EINVAL; | 477 | return -EINVAL; |
459 | 478 | ||
460 | heartbeat = t; | 479 | heartbeat = t; |
@@ -470,7 +489,7 @@ static int pcwd_get_status(int *status) | |||
470 | { | 489 | { |
471 | int control_status; | 490 | int control_status; |
472 | 491 | ||
473 | *status=0; | 492 | *status = 0; |
474 | spin_lock(&pcwd_private.io_lock); | 493 | spin_lock(&pcwd_private.io_lock); |
475 | if (pcwd_private.revision == PCWD_REVISION_A) | 494 | if (pcwd_private.revision == PCWD_REVISION_A) |
476 | /* Rev A cards return status information from | 495 | /* Rev A cards return status information from |
@@ -494,9 +513,9 @@ static int pcwd_get_status(int *status) | |||
494 | if (control_status & WD_T110) { | 513 | if (control_status & WD_T110) { |
495 | *status |= WDIOF_OVERHEAT; | 514 | *status |= WDIOF_OVERHEAT; |
496 | if (temp_panic) { | 515 | if (temp_panic) { |
497 | printk(KERN_INFO PFX "Temperature overheat trip!\n"); | 516 | printk(KERN_INFO PFX |
517 | "Temperature overheat trip!\n"); | ||
498 | kernel_power_off(); | 518 | kernel_power_off(); |
499 | /* or should we just do a: panic(PFX "Temperature overheat trip!\n"); */ | ||
500 | } | 519 | } |
501 | } | 520 | } |
502 | } else { | 521 | } else { |
@@ -506,9 +525,9 @@ static int pcwd_get_status(int *status) | |||
506 | if (control_status & WD_REVC_TTRP) { | 525 | if (control_status & WD_REVC_TTRP) { |
507 | *status |= WDIOF_OVERHEAT; | 526 | *status |= WDIOF_OVERHEAT; |
508 | if (temp_panic) { | 527 | if (temp_panic) { |
509 | printk(KERN_INFO PFX "Temperature overheat trip!\n"); | 528 | printk(KERN_INFO PFX |
529 | "Temperature overheat trip!\n"); | ||
510 | kernel_power_off(); | 530 | kernel_power_off(); |
511 | /* or should we just do a: panic(PFX "Temperature overheat trip!\n"); */ | ||
512 | } | 531 | } |
513 | } | 532 | } |
514 | } | 533 | } |
@@ -524,18 +543,21 @@ static int pcwd_clear_status(void) | |||
524 | spin_lock(&pcwd_private.io_lock); | 543 | spin_lock(&pcwd_private.io_lock); |
525 | 544 | ||
526 | if (debug >= VERBOSE) | 545 | if (debug >= VERBOSE) |
527 | printk(KERN_INFO PFX "clearing watchdog trip status\n"); | 546 | printk(KERN_INFO PFX |
547 | "clearing watchdog trip status\n"); | ||
528 | 548 | ||
529 | control_status = inb_p(pcwd_private.io_addr + 1); | 549 | control_status = inb_p(pcwd_private.io_addr + 1); |
530 | 550 | ||
531 | if (debug >= DEBUG) { | 551 | if (debug >= DEBUG) { |
532 | printk(KERN_DEBUG PFX "status was: 0x%02x\n", control_status); | 552 | printk(KERN_DEBUG PFX "status was: 0x%02x\n", |
553 | control_status); | ||
533 | printk(KERN_DEBUG PFX "sending: 0x%02x\n", | 554 | printk(KERN_DEBUG PFX "sending: 0x%02x\n", |
534 | (control_status & WD_REVC_R2DS)); | 555 | (control_status & WD_REVC_R2DS)); |
535 | } | 556 | } |
536 | 557 | ||
537 | /* clear reset status & Keep Relay 2 disable state as it is */ | 558 | /* clear reset status & Keep Relay 2 disable state as it is */ |
538 | outb_p((control_status & WD_REVC_R2DS), pcwd_private.io_addr + 1); | 559 | outb_p((control_status & WD_REVC_R2DS), |
560 | pcwd_private.io_addr + 1); | ||
539 | 561 | ||
540 | spin_unlock(&pcwd_private.io_lock); | 562 | spin_unlock(&pcwd_private.io_lock); |
541 | } | 563 | } |
@@ -572,8 +594,7 @@ static int pcwd_get_temperature(int *temperature) | |||
572 | * /dev/watchdog handling | 594 | * /dev/watchdog handling |
573 | */ | 595 | */ |
574 | 596 | ||
575 | static int pcwd_ioctl(struct inode *inode, struct file *file, | 597 | static long pcwd_ioctl(struct file *file, unsigned int cmd, unsigned long arg) |
576 | unsigned int cmd, unsigned long arg) | ||
577 | { | 598 | { |
578 | int rv; | 599 | int rv; |
579 | int status; | 600 | int status; |
@@ -590,12 +611,9 @@ static int pcwd_ioctl(struct inode *inode, struct file *file, | |||
590 | .identity = "PCWD", | 611 | .identity = "PCWD", |
591 | }; | 612 | }; |
592 | 613 | ||
593 | switch(cmd) { | 614 | switch (cmd) { |
594 | default: | ||
595 | return -ENOTTY; | ||
596 | |||
597 | case WDIOC_GETSUPPORT: | 615 | case WDIOC_GETSUPPORT: |
598 | if(copy_to_user(argp, &ident, sizeof(ident))) | 616 | if (copy_to_user(argp, &ident, sizeof(ident))) |
599 | return -EFAULT; | 617 | return -EFAULT; |
600 | return 0; | 618 | return 0; |
601 | 619 | ||
@@ -613,25 +631,22 @@ static int pcwd_ioctl(struct inode *inode, struct file *file, | |||
613 | return put_user(temperature, argp); | 631 | return put_user(temperature, argp); |
614 | 632 | ||
615 | case WDIOC_SETOPTIONS: | 633 | case WDIOC_SETOPTIONS: |
616 | if (pcwd_private.revision == PCWD_REVISION_C) | 634 | if (pcwd_private.revision == PCWD_REVISION_C) { |
617 | { | 635 | if (get_user(rv, argp)) |
618 | if(copy_from_user(&rv, argp, sizeof(int))) | ||
619 | return -EFAULT; | 636 | return -EFAULT; |
620 | 637 | ||
621 | if (rv & WDIOS_DISABLECARD) | 638 | if (rv & WDIOS_DISABLECARD) { |
622 | { | 639 | status = pcwd_stop(); |
623 | return pcwd_stop(); | 640 | if (status < 0) |
641 | return status; | ||
624 | } | 642 | } |
625 | 643 | if (rv & WDIOS_ENABLECARD) { | |
626 | if (rv & WDIOS_ENABLECARD) | 644 | status = pcwd_start(); |
627 | { | 645 | if (status < 0) |
628 | return pcwd_start(); | 646 | return status; |
629 | } | 647 | } |
630 | |||
631 | if (rv & WDIOS_TEMPPANIC) | 648 | if (rv & WDIOS_TEMPPANIC) |
632 | { | ||
633 | temp_panic = 1; | 649 | temp_panic = 1; |
634 | } | ||
635 | } | 650 | } |
636 | return -EINVAL; | 651 | return -EINVAL; |
637 | 652 | ||
@@ -651,6 +666,9 @@ static int pcwd_ioctl(struct inode *inode, struct file *file, | |||
651 | 666 | ||
652 | case WDIOC_GETTIMEOUT: | 667 | case WDIOC_GETTIMEOUT: |
653 | return put_user(heartbeat, argp); | 668 | return put_user(heartbeat, argp); |
669 | |||
670 | default: | ||
671 | return -ENOTTY; | ||
654 | } | 672 | } |
655 | 673 | ||
656 | return 0; | 674 | return 0; |
@@ -682,16 +700,10 @@ static ssize_t pcwd_write(struct file *file, const char __user *buf, size_t len, | |||
682 | 700 | ||
683 | static int pcwd_open(struct inode *inode, struct file *file) | 701 | static int pcwd_open(struct inode *inode, struct file *file) |
684 | { | 702 | { |
685 | if (!atomic_dec_and_test(&open_allowed) ) { | 703 | if (test_and_set_bit(0, &open_allowed)) |
686 | if (debug >= VERBOSE) | ||
687 | printk(KERN_ERR PFX "Attempt to open already opened device.\n"); | ||
688 | atomic_inc( &open_allowed ); | ||
689 | return -EBUSY; | 704 | return -EBUSY; |
690 | } | ||
691 | |||
692 | if (nowayout) | 705 | if (nowayout) |
693 | __module_get(THIS_MODULE); | 706 | __module_get(THIS_MODULE); |
694 | |||
695 | /* Activate */ | 707 | /* Activate */ |
696 | pcwd_start(); | 708 | pcwd_start(); |
697 | pcwd_keepalive(); | 709 | pcwd_keepalive(); |
@@ -700,14 +712,15 @@ static int pcwd_open(struct inode *inode, struct file *file) | |||
700 | 712 | ||
701 | static int pcwd_close(struct inode *inode, struct file *file) | 713 | static int pcwd_close(struct inode *inode, struct file *file) |
702 | { | 714 | { |
703 | if (expect_close == 42) { | 715 | if (expect_close == 42) |
704 | pcwd_stop(); | 716 | pcwd_stop(); |
705 | } else { | 717 | else { |
706 | printk(KERN_CRIT PFX "Unexpected close, not stopping watchdog!\n"); | 718 | printk(KERN_CRIT PFX |
719 | "Unexpected close, not stopping watchdog!\n"); | ||
707 | pcwd_keepalive(); | 720 | pcwd_keepalive(); |
708 | } | 721 | } |
709 | expect_close = 0; | 722 | expect_close = 0; |
710 | atomic_inc( &open_allowed ); | 723 | clear_bit(0, &open_allowed); |
711 | return 0; | 724 | return 0; |
712 | } | 725 | } |
713 | 726 | ||
@@ -750,7 +763,7 @@ static const struct file_operations pcwd_fops = { | |||
750 | .owner = THIS_MODULE, | 763 | .owner = THIS_MODULE, |
751 | .llseek = no_llseek, | 764 | .llseek = no_llseek, |
752 | .write = pcwd_write, | 765 | .write = pcwd_write, |
753 | .ioctl = pcwd_ioctl, | 766 | .unlocked_ioctl = pcwd_ioctl, |
754 | .open = pcwd_open, | 767 | .open = pcwd_open, |
755 | .release = pcwd_close, | 768 | .release = pcwd_close, |
756 | }; | 769 | }; |
@@ -788,7 +801,7 @@ static inline int get_revision(void) | |||
788 | * presumes a floating bus reads as 0xff. */ | 801 | * presumes a floating bus reads as 0xff. */ |
789 | if ((inb(pcwd_private.io_addr + 2) == 0xFF) || | 802 | if ((inb(pcwd_private.io_addr + 2) == 0xFF) || |
790 | (inb(pcwd_private.io_addr + 3) == 0xFF)) | 803 | (inb(pcwd_private.io_addr + 3) == 0xFF)) |
791 | r=PCWD_REVISION_A; | 804 | r = PCWD_REVISION_A; |
792 | spin_unlock(&pcwd_private.io_lock); | 805 | spin_unlock(&pcwd_private.io_lock); |
793 | 806 | ||
794 | return r; | 807 | return r; |
@@ -803,7 +816,7 @@ static inline int get_revision(void) | |||
803 | */ | 816 | */ |
804 | static int __devinit pcwd_isa_match(struct device *dev, unsigned int id) | 817 | static int __devinit pcwd_isa_match(struct device *dev, unsigned int id) |
805 | { | 818 | { |
806 | int base_addr=pcwd_ioports[id]; | 819 | int base_addr = pcwd_ioports[id]; |
807 | int port0, last_port0; /* Reg 0, in case it's REV A */ | 820 | int port0, last_port0; /* Reg 0, in case it's REV A */ |
808 | int port1, last_port1; /* Register 1 for REV C cards */ | 821 | int port1, last_port1; /* Register 1 for REV C cards */ |
809 | int i; | 822 | int i; |
@@ -813,7 +826,7 @@ static int __devinit pcwd_isa_match(struct device *dev, unsigned int id) | |||
813 | printk(KERN_DEBUG PFX "pcwd_isa_match id=%d\n", | 826 | printk(KERN_DEBUG PFX "pcwd_isa_match id=%d\n", |
814 | id); | 827 | id); |
815 | 828 | ||
816 | if (!request_region (base_addr, 4, "PCWD")) { | 829 | if (!request_region(base_addr, 4, "PCWD")) { |
817 | printk(KERN_INFO PFX "Port 0x%04x unavailable\n", base_addr); | 830 | printk(KERN_INFO PFX "Port 0x%04x unavailable\n", base_addr); |
818 | return 0; | 831 | return 0; |
819 | } | 832 | } |
@@ -842,7 +855,7 @@ static int __devinit pcwd_isa_match(struct device *dev, unsigned int id) | |||
842 | } | 855 | } |
843 | } | 856 | } |
844 | } | 857 | } |
845 | release_region (base_addr, 4); | 858 | release_region(base_addr, 4); |
846 | 859 | ||
847 | return retval; | 860 | return retval; |
848 | } | 861 | } |
@@ -857,7 +870,8 @@ static int __devinit pcwd_isa_probe(struct device *dev, unsigned int id) | |||
857 | 870 | ||
858 | cards_found++; | 871 | cards_found++; |
859 | if (cards_found == 1) | 872 | if (cards_found == 1) |
860 | printk(KERN_INFO PFX "v%s Ken Hollis (kenji@bitgate.com)\n", WD_VER); | 873 | printk(KERN_INFO PFX "v%s Ken Hollis (kenji@bitgate.com)\n", |
874 | WD_VER); | ||
861 | 875 | ||
862 | if (cards_found > 1) { | 876 | if (cards_found > 1) { |
863 | printk(KERN_ERR PFX "This driver only supports 1 device\n"); | 877 | printk(KERN_ERR PFX "This driver only supports 1 device\n"); |
@@ -875,10 +889,11 @@ static int __devinit pcwd_isa_probe(struct device *dev, unsigned int id) | |||
875 | /* Check card's revision */ | 889 | /* Check card's revision */ |
876 | pcwd_private.revision = get_revision(); | 890 | pcwd_private.revision = get_revision(); |
877 | 891 | ||
878 | if (!request_region(pcwd_private.io_addr, (pcwd_private.revision == PCWD_REVISION_A) ? 2 : 4, "PCWD")) { | 892 | if (!request_region(pcwd_private.io_addr, |
893 | (pcwd_private.revision == PCWD_REVISION_A) ? 2 : 4, "PCWD")) { | ||
879 | printk(KERN_ERR PFX "I/O address 0x%04x already in use\n", | 894 | printk(KERN_ERR PFX "I/O address 0x%04x already in use\n", |
880 | pcwd_private.io_addr); | 895 | pcwd_private.io_addr); |
881 | ret=-EIO; | 896 | ret = -EIO; |
882 | goto error_request_region; | 897 | goto error_request_region; |
883 | } | 898 | } |
884 | 899 | ||
@@ -908,26 +923,30 @@ static int __devinit pcwd_isa_probe(struct device *dev, unsigned int id) | |||
908 | if (heartbeat == 0) | 923 | if (heartbeat == 0) |
909 | heartbeat = heartbeat_tbl[(pcwd_get_option_switches() & 0x07)]; | 924 | heartbeat = heartbeat_tbl[(pcwd_get_option_switches() & 0x07)]; |
910 | 925 | ||
911 | /* Check that the heartbeat value is within it's range ; if not reset to the default */ | 926 | /* Check that the heartbeat value is within it's range; |
927 | if not reset to the default */ | ||
912 | if (pcwd_set_heartbeat(heartbeat)) { | 928 | if (pcwd_set_heartbeat(heartbeat)) { |
913 | pcwd_set_heartbeat(WATCHDOG_HEARTBEAT); | 929 | pcwd_set_heartbeat(WATCHDOG_HEARTBEAT); |
914 | printk(KERN_INFO PFX "heartbeat value must be 2<=heartbeat<=7200, using %d\n", | 930 | printk(KERN_INFO PFX |
915 | WATCHDOG_HEARTBEAT); | 931 | "heartbeat value must be 2 <= heartbeat <= 7200, using %d\n", |
932 | WATCHDOG_HEARTBEAT); | ||
916 | } | 933 | } |
917 | 934 | ||
918 | if (pcwd_private.supports_temp) { | 935 | if (pcwd_private.supports_temp) { |
919 | ret = misc_register(&temp_miscdev); | 936 | ret = misc_register(&temp_miscdev); |
920 | if (ret) { | 937 | if (ret) { |
921 | printk(KERN_ERR PFX "cannot register miscdev on minor=%d (err=%d)\n", | 938 | printk(KERN_ERR PFX |
922 | TEMP_MINOR, ret); | 939 | "cannot register miscdev on minor=%d (err=%d)\n", |
940 | TEMP_MINOR, ret); | ||
923 | goto error_misc_register_temp; | 941 | goto error_misc_register_temp; |
924 | } | 942 | } |
925 | } | 943 | } |
926 | 944 | ||
927 | ret = misc_register(&pcwd_miscdev); | 945 | ret = misc_register(&pcwd_miscdev); |
928 | if (ret) { | 946 | if (ret) { |
929 | printk(KERN_ERR PFX "cannot register miscdev on minor=%d (err=%d)\n", | 947 | printk(KERN_ERR PFX |
930 | WATCHDOG_MINOR, ret); | 948 | "cannot register miscdev on minor=%d (err=%d)\n", |
949 | WATCHDOG_MINOR, ret); | ||
931 | goto error_misc_register_watchdog; | 950 | goto error_misc_register_watchdog; |
932 | } | 951 | } |
933 | 952 | ||
@@ -940,7 +959,8 @@ error_misc_register_watchdog: | |||
940 | if (pcwd_private.supports_temp) | 959 | if (pcwd_private.supports_temp) |
941 | misc_deregister(&temp_miscdev); | 960 | misc_deregister(&temp_miscdev); |
942 | error_misc_register_temp: | 961 | error_misc_register_temp: |
943 | release_region(pcwd_private.io_addr, (pcwd_private.revision == PCWD_REVISION_A) ? 2 : 4); | 962 | release_region(pcwd_private.io_addr, |
963 | (pcwd_private.revision == PCWD_REVISION_A) ? 2 : 4); | ||
944 | error_request_region: | 964 | error_request_region: |
945 | pcwd_private.io_addr = 0x0000; | 965 | pcwd_private.io_addr = 0x0000; |
946 | cards_found--; | 966 | cards_found--; |
@@ -964,7 +984,8 @@ static int __devexit pcwd_isa_remove(struct device *dev, unsigned int id) | |||
964 | misc_deregister(&pcwd_miscdev); | 984 | misc_deregister(&pcwd_miscdev); |
965 | if (pcwd_private.supports_temp) | 985 | if (pcwd_private.supports_temp) |
966 | misc_deregister(&temp_miscdev); | 986 | misc_deregister(&temp_miscdev); |
967 | release_region(pcwd_private.io_addr, (pcwd_private.revision == PCWD_REVISION_A) ? 2 : 4); | 987 | release_region(pcwd_private.io_addr, |
988 | (pcwd_private.revision == PCWD_REVISION_A) ? 2 : 4); | ||
968 | pcwd_private.io_addr = 0x0000; | 989 | pcwd_private.io_addr = 0x0000; |
969 | cards_found--; | 990 | cards_found--; |
970 | 991 | ||