diff options
author | Linus Torvalds <torvalds@g5.osdl.org> | 2006-04-02 16:01:11 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@g5.osdl.org> | 2006-04-02 16:01:11 -0400 |
commit | 7f344f0aa7d4ec0e4c1c676329aff1353f90fb38 (patch) | |
tree | 955347ebf22af5f7479ea9b01e8e8f14c2c426c0 /drivers/char | |
parent | 63589ed0785ffc715777a54ccb96cdfaea9edbc0 (diff) | |
parent | 853807fb500a9442d88646b7be92bfa51334f8e8 (diff) |
Merge master.kernel.org:/pub/scm/linux/kernel/git/wim/linux-2.6-watchdog
* master.kernel.org:/pub/scm/linux/kernel/git/wim/linux-2.6-watchdog:
[WATCHDOG] at91_wdt.c - Atmel AT91RM9200 watchdog driver
[WATCHDOG] pcwd_usb.c: fix a NULL pointer dereference
[WATCHDOG] pcwd.c sprintf/strcpy fix
[WATCHDOG] pcwd.c general clean-up after patches
[WATCHDOG] pcwd.c add debug info
[WATCHDOG] pcwd.c pcwd_cleanup_module patch
[WATCHDOG] pcwd.c firmware-info patch
[WATCHDOG] pcwd.c control status patch
Diffstat (limited to 'drivers/char')
-rw-r--r-- | drivers/char/watchdog/Kconfig | 7 | ||||
-rw-r--r-- | drivers/char/watchdog/Makefile | 1 | ||||
-rw-r--r-- | drivers/char/watchdog/at91_wdt.c | 228 | ||||
-rw-r--r-- | drivers/char/watchdog/pcwd.c | 137 | ||||
-rw-r--r-- | drivers/char/watchdog/pcwd_usb.c | 3 |
5 files changed, 340 insertions, 36 deletions
diff --git a/drivers/char/watchdog/Kconfig b/drivers/char/watchdog/Kconfig index 16e99db2e12d..d53f664a4dd8 100644 --- a/drivers/char/watchdog/Kconfig +++ b/drivers/char/watchdog/Kconfig | |||
@@ -60,6 +60,13 @@ config SOFT_WATCHDOG | |||
60 | 60 | ||
61 | # ARM Architecture | 61 | # ARM Architecture |
62 | 62 | ||
63 | config AT91_WATCHDOG | ||
64 | tristate "AT91RM9200 watchdog" | ||
65 | depends on WATCHDOG && ARCH_AT91RM9200 | ||
66 | help | ||
67 | Watchdog timer embedded into AT91RM9200 chips. This will reboot your | ||
68 | system when the timeout is reached. | ||
69 | |||
63 | config 21285_WATCHDOG | 70 | config 21285_WATCHDOG |
64 | tristate "DC21285 watchdog" | 71 | tristate "DC21285 watchdog" |
65 | depends on WATCHDOG && FOOTBRIDGE | 72 | depends on WATCHDOG && FOOTBRIDGE |
diff --git a/drivers/char/watchdog/Makefile b/drivers/char/watchdog/Makefile index d6f27fde9905..6ab77b61a643 100644 --- a/drivers/char/watchdog/Makefile +++ b/drivers/char/watchdog/Makefile | |||
@@ -23,6 +23,7 @@ obj-$(CONFIG_WDTPCI) += wdt_pci.o | |||
23 | obj-$(CONFIG_USBPCWATCHDOG) += pcwd_usb.o | 23 | obj-$(CONFIG_USBPCWATCHDOG) += pcwd_usb.o |
24 | 24 | ||
25 | # ARM Architecture | 25 | # ARM Architecture |
26 | obj-$(CONFIG_AT91_WATCHDOG) += at91_wdt.o | ||
26 | obj-$(CONFIG_21285_WATCHDOG) += wdt285.o | 27 | obj-$(CONFIG_21285_WATCHDOG) += wdt285.o |
27 | obj-$(CONFIG_977_WATCHDOG) += wdt977.o | 28 | obj-$(CONFIG_977_WATCHDOG) += wdt977.o |
28 | obj-$(CONFIG_IXP2000_WATCHDOG) += ixp2000_wdt.o | 29 | obj-$(CONFIG_IXP2000_WATCHDOG) += ixp2000_wdt.o |
diff --git a/drivers/char/watchdog/at91_wdt.c b/drivers/char/watchdog/at91_wdt.c new file mode 100644 index 000000000000..ac83bc4b019a --- /dev/null +++ b/drivers/char/watchdog/at91_wdt.c | |||
@@ -0,0 +1,228 @@ | |||
1 | /* | ||
2 | * Watchdog driver for Atmel AT91RM9200 (Thunder) | ||
3 | * | ||
4 | * Copyright (C) 2003 SAN People (Pty) Ltd | ||
5 | * | ||
6 | * This program is free software; you can redistribute it and/or | ||
7 | * modify it under the terms of the GNU General Public License | ||
8 | * as published by the Free Software Foundation; either version | ||
9 | * 2 of the License, or (at your option) any later version. | ||
10 | */ | ||
11 | |||
12 | #include <linux/config.h> | ||
13 | #include <linux/errno.h> | ||
14 | #include <linux/fs.h> | ||
15 | #include <linux/init.h> | ||
16 | #include <linux/kernel.h> | ||
17 | #include <linux/miscdevice.h> | ||
18 | #include <linux/module.h> | ||
19 | #include <linux/moduleparam.h> | ||
20 | #include <linux/types.h> | ||
21 | #include <linux/watchdog.h> | ||
22 | #include <asm/bitops.h> | ||
23 | #include <asm/uaccess.h> | ||
24 | |||
25 | |||
26 | #define WDT_DEFAULT_TIME 5 /* 5 seconds */ | ||
27 | #define WDT_MAX_TIME 256 /* 256 seconds */ | ||
28 | |||
29 | static int wdt_time = WDT_DEFAULT_TIME; | ||
30 | static int nowayout = WATCHDOG_NOWAYOUT; | ||
31 | |||
32 | module_param(wdt_time, int, 0); | ||
33 | MODULE_PARM_DESC(wdt_time, "Watchdog time in seconds. (default="__MODULE_STRING(WDT_DEFAULT_TIME) ")"); | ||
34 | |||
35 | module_param(nowayout, int, 0); | ||
36 | MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default=" __MODULE_STRING(WATCHDOG_NOWAYOUT) ")"); | ||
37 | |||
38 | |||
39 | static unsigned long at91wdt_busy; | ||
40 | |||
41 | /* ......................................................................... */ | ||
42 | |||
43 | /* | ||
44 | * Disable the watchdog. | ||
45 | */ | ||
46 | static void inline at91_wdt_stop(void) | ||
47 | { | ||
48 | at91_sys_write(AT91_ST_WDMR, AT91_ST_EXTEN); | ||
49 | } | ||
50 | |||
51 | /* | ||
52 | * Enable and reset the watchdog. | ||
53 | */ | ||
54 | static void inline at91_wdt_start(void) | ||
55 | { | ||
56 | at91_sys_write(AT91_ST_WDMR, AT91_ST_EXTEN | AT91_ST_RSTEN | (((65536 * wdt_time) >> 8) & AT91_ST_WDV)); | ||
57 | at91_sys_write(AT91_ST_CR, AT91_ST_WDRST); | ||
58 | } | ||
59 | |||
60 | /* | ||
61 | * Reload the watchdog timer. (ie, pat the watchdog) | ||
62 | */ | ||
63 | static void inline at91_wdt_reload(void) | ||
64 | { | ||
65 | at91_sys_write(AT91_ST_CR, AT91_ST_WDRST); | ||
66 | } | ||
67 | |||
68 | /* ......................................................................... */ | ||
69 | |||
70 | /* | ||
71 | * Watchdog device is opened, and watchdog starts running. | ||
72 | */ | ||
73 | static int at91_wdt_open(struct inode *inode, struct file *file) | ||
74 | { | ||
75 | if (test_and_set_bit(0, &at91wdt_busy)) | ||
76 | return -EBUSY; | ||
77 | |||
78 | at91_wdt_start(); | ||
79 | return nonseekable_open(inode, file); | ||
80 | } | ||
81 | |||
82 | /* | ||
83 | * Close the watchdog device. | ||
84 | * If CONFIG_WATCHDOG_NOWAYOUT is NOT defined then the watchdog is also | ||
85 | * disabled. | ||
86 | */ | ||
87 | static int at91_wdt_close(struct inode *inode, struct file *file) | ||
88 | { | ||
89 | if (!nowayout) | ||
90 | at91_wdt_stop(); /* Disable the watchdog when file is closed */ | ||
91 | |||
92 | clear_bit(0, &at91wdt_busy); | ||
93 | return 0; | ||
94 | } | ||
95 | |||
96 | /* | ||
97 | * Change the watchdog time interval. | ||
98 | */ | ||
99 | static int at91_wdt_settimeout(int new_time) | ||
100 | { | ||
101 | /* | ||
102 | * All counting occurs at SLOW_CLOCK / 128 = 0.256 Hz | ||
103 | * | ||
104 | * Since WDV is a 16-bit counter, the maximum period is | ||
105 | * 65536 / 0.256 = 256 seconds. | ||
106 | */ | ||
107 | if ((new_time <= 0) || (new_time > WDT_MAX_TIME)) | ||
108 | return -EINVAL; | ||
109 | |||
110 | /* Set new watchdog time. It will be used when at91_wdt_start() is called. */ | ||
111 | wdt_time = new_time; | ||
112 | return 0; | ||
113 | } | ||
114 | |||
115 | static struct watchdog_info at91_wdt_info = { | ||
116 | .identity = "at91 watchdog", | ||
117 | .options = WDIOF_SETTIMEOUT | WDIOF_KEEPALIVEPING, | ||
118 | }; | ||
119 | |||
120 | /* | ||
121 | * Handle commands from user-space. | ||
122 | */ | ||
123 | static int at91_wdt_ioctl(struct inode *inode, struct file *file, | ||
124 | unsigned int cmd, unsigned long arg) | ||
125 | { | ||
126 | void __user *argp = (void __user *)arg; | ||
127 | int __user *p = argp; | ||
128 | int new_value; | ||
129 | |||
130 | switch(cmd) { | ||
131 | case WDIOC_KEEPALIVE: | ||
132 | at91_wdt_reload(); /* pat the watchdog */ | ||
133 | return 0; | ||
134 | |||
135 | case WDIOC_GETSUPPORT: | ||
136 | return copy_to_user(argp, &at91_wdt_info, sizeof(at91_wdt_info)) ? -EFAULT : 0; | ||
137 | |||
138 | case WDIOC_SETTIMEOUT: | ||
139 | if (get_user(new_value, p)) | ||
140 | return -EFAULT; | ||
141 | |||
142 | if (at91_wdt_settimeout(new_value)) | ||
143 | return -EINVAL; | ||
144 | |||
145 | /* Enable new time value */ | ||
146 | at91_wdt_start(); | ||
147 | |||
148 | /* Return current value */ | ||
149 | return put_user(wdt_time, p); | ||
150 | |||
151 | case WDIOC_GETTIMEOUT: | ||
152 | return put_user(wdt_time, p); | ||
153 | |||
154 | case WDIOC_GETSTATUS: | ||
155 | case WDIOC_GETBOOTSTATUS: | ||
156 | return put_user(0, p); | ||
157 | |||
158 | case WDIOC_SETOPTIONS: | ||
159 | if (get_user(new_value, p)) | ||
160 | return -EFAULT; | ||
161 | |||
162 | if (new_value & WDIOS_DISABLECARD) | ||
163 | at91_wdt_stop(); | ||
164 | if (new_value & WDIOS_ENABLECARD) | ||
165 | at91_wdt_start(); | ||
166 | return 0; | ||
167 | |||
168 | default: | ||
169 | return -ENOIOCTLCMD; | ||
170 | } | ||
171 | } | ||
172 | |||
173 | /* | ||
174 | * Pat the watchdog whenever device is written to. | ||
175 | */ | ||
176 | static ssize_t at91_wdt_write(struct file *file, const char *data, size_t len, loff_t *ppos) | ||
177 | { | ||
178 | at91_wdt_reload(); /* pat the watchdog */ | ||
179 | return len; | ||
180 | } | ||
181 | |||
182 | /* ......................................................................... */ | ||
183 | |||
184 | static struct file_operations at91wdt_fops = { | ||
185 | .owner = THIS_MODULE, | ||
186 | .llseek = no_llseek, | ||
187 | .ioctl = at91_wdt_ioctl, | ||
188 | .open = at91_wdt_open, | ||
189 | .release = at91_wdt_close, | ||
190 | .write = at91_wdt_write, | ||
191 | }; | ||
192 | |||
193 | static struct miscdevice at91wdt_miscdev = { | ||
194 | .minor = WATCHDOG_MINOR, | ||
195 | .name = "watchdog", | ||
196 | .fops = &at91wdt_fops, | ||
197 | }; | ||
198 | |||
199 | static int __init at91_wdt_init(void) | ||
200 | { | ||
201 | int res; | ||
202 | |||
203 | /* Check that the heartbeat value is within range; if not reset to the default */ | ||
204 | if (at91_wdt_settimeout(wdt_time)) { | ||
205 | at91_wdt_settimeout(WDT_DEFAULT_TIME); | ||
206 | printk(KERN_INFO "at91_wdt: wdt_time value must be 1 <= wdt_time <= 256, using %d\n", wdt_time); | ||
207 | } | ||
208 | |||
209 | res = misc_register(&at91wdt_miscdev); | ||
210 | if (res) | ||
211 | return res; | ||
212 | |||
213 | printk("AT91 Watchdog Timer enabled (%d seconds, nowayout=%d)\n", wdt_time, nowayout); | ||
214 | return 0; | ||
215 | } | ||
216 | |||
217 | static void __exit at91_wdt_exit(void) | ||
218 | { | ||
219 | misc_deregister(&at91wdt_miscdev); | ||
220 | } | ||
221 | |||
222 | module_init(at91_wdt_init); | ||
223 | module_exit(at91_wdt_exit); | ||
224 | |||
225 | MODULE_AUTHOR("Andrew Victor"); | ||
226 | MODULE_DESCRIPTION("Watchdog driver for Atmel AT91RM9200"); | ||
227 | MODULE_LICENSE("GPL"); | ||
228 | MODULE_ALIAS_MISCDEV(WATCHDOG_MINOR); | ||
diff --git a/drivers/char/watchdog/pcwd.c b/drivers/char/watchdog/pcwd.c index 8d6b249ad66b..6d44ca68312d 100644 --- a/drivers/char/watchdog/pcwd.c +++ b/drivers/char/watchdog/pcwd.c | |||
@@ -66,15 +66,13 @@ | |||
66 | #include <linux/fs.h> /* For file operations */ | 66 | #include <linux/fs.h> /* For file operations */ |
67 | #include <linux/ioport.h> /* For io-port access */ | 67 | #include <linux/ioport.h> /* For io-port access */ |
68 | #include <linux/spinlock.h> /* For spin_lock/spin_unlock/... */ | 68 | #include <linux/spinlock.h> /* For spin_lock/spin_unlock/... */ |
69 | #include <linux/sched.h> /* TASK_INTERRUPTIBLE, set_current_state() and friends */ | ||
70 | #include <linux/slab.h> /* For kmalloc */ | ||
71 | 69 | ||
72 | #include <asm/uaccess.h> /* For copy_to_user/put_user/... */ | 70 | #include <asm/uaccess.h> /* For copy_to_user/put_user/... */ |
73 | #include <asm/io.h> /* For inb/outb/... */ | 71 | #include <asm/io.h> /* For inb/outb/... */ |
74 | 72 | ||
75 | /* Module and version information */ | 73 | /* Module and version information */ |
76 | #define WATCHDOG_VERSION "1.16" | 74 | #define WATCHDOG_VERSION "1.17" |
77 | #define WATCHDOG_DATE "03 Jan 2006" | 75 | #define WATCHDOG_DATE "12 Feb 2006" |
78 | #define WATCHDOG_DRIVER_NAME "ISA-PC Watchdog" | 76 | #define WATCHDOG_DRIVER_NAME "ISA-PC Watchdog" |
79 | #define WATCHDOG_NAME "pcwd" | 77 | #define WATCHDOG_NAME "pcwd" |
80 | #define PFX WATCHDOG_NAME ": " | 78 | #define PFX WATCHDOG_NAME ": " |
@@ -96,15 +94,19 @@ | |||
96 | * PCI-PC Watchdog card. | 94 | * PCI-PC Watchdog card. |
97 | */ | 95 | */ |
98 | /* Port 1 : Control Status #1 for the PC Watchdog card, revision A. */ | 96 | /* Port 1 : Control Status #1 for the PC Watchdog card, revision A. */ |
99 | #define WD_WDRST 0x01 /* Previously reset state */ | 97 | #define WD_WDRST 0x01 /* Previously reset state */ |
100 | #define WD_T110 0x02 /* Temperature overheat sense */ | 98 | #define WD_T110 0x02 /* Temperature overheat sense */ |
101 | #define WD_HRTBT 0x04 /* Heartbeat sense */ | 99 | #define WD_HRTBT 0x04 /* Heartbeat sense */ |
102 | #define WD_RLY2 0x08 /* External relay triggered */ | 100 | #define WD_RLY2 0x08 /* External relay triggered */ |
103 | #define WD_SRLY2 0x80 /* Software external relay triggered */ | 101 | #define WD_SRLY2 0x80 /* Software external relay triggered */ |
104 | /* Port 1 : Control Status #1 for the PC Watchdog card, revision C. */ | 102 | /* Port 1 : Control Status #1 for the PC Watchdog card, revision C. */ |
105 | #define WD_REVC_WTRP 0x01 /* Watchdog Trip status */ | 103 | #define WD_REVC_WTRP 0x01 /* Watchdog Trip status */ |
106 | #define WD_REVC_HRBT 0x02 /* Watchdog Heartbeat */ | 104 | #define WD_REVC_HRBT 0x02 /* Watchdog Heartbeat */ |
107 | #define WD_REVC_TTRP 0x04 /* Temperature Trip status */ | 105 | #define WD_REVC_TTRP 0x04 /* Temperature Trip status */ |
106 | #define WD_REVC_RL2A 0x08 /* Relay 2 activated by on-board processor */ | ||
107 | #define WD_REVC_RL1A 0x10 /* Relay 1 active */ | ||
108 | #define WD_REVC_R2DS 0x40 /* Relay 2 disable */ | ||
109 | #define WD_REVC_RLY2 0x80 /* Relay 2 activated? */ | ||
108 | /* Port 2 : Control Status #2 */ | 110 | /* Port 2 : Control Status #2 */ |
109 | #define WD_WDIS 0x10 /* Watchdog Disabled */ | 111 | #define WD_WDIS 0x10 /* Watchdog Disabled */ |
110 | #define WD_ENTP 0x20 /* Watchdog Enable Temperature Trip */ | 112 | #define WD_ENTP 0x20 /* Watchdog Enable Temperature Trip */ |
@@ -122,9 +124,14 @@ | |||
122 | #define CMD_ISA_VERSION_HUNDRETH 0x03 | 124 | #define CMD_ISA_VERSION_HUNDRETH 0x03 |
123 | #define CMD_ISA_VERSION_MINOR 0x04 | 125 | #define CMD_ISA_VERSION_MINOR 0x04 |
124 | #define CMD_ISA_SWITCH_SETTINGS 0x05 | 126 | #define CMD_ISA_SWITCH_SETTINGS 0x05 |
127 | #define CMD_ISA_RESET_PC 0x06 | ||
128 | #define CMD_ISA_ARM_0 0x07 | ||
129 | #define CMD_ISA_ARM_30 0x08 | ||
130 | #define CMD_ISA_ARM_60 0x09 | ||
125 | #define CMD_ISA_DELAY_TIME_2SECS 0x0A | 131 | #define CMD_ISA_DELAY_TIME_2SECS 0x0A |
126 | #define CMD_ISA_DELAY_TIME_4SECS 0x0B | 132 | #define CMD_ISA_DELAY_TIME_4SECS 0x0B |
127 | #define CMD_ISA_DELAY_TIME_8SECS 0x0C | 133 | #define CMD_ISA_DELAY_TIME_8SECS 0x0C |
134 | #define CMD_ISA_RESET_RELAYS 0x0D | ||
128 | 135 | ||
129 | /* | 136 | /* |
130 | * We are using an kernel timer to do the pinging of the watchdog | 137 | * We are using an kernel timer to do the pinging of the watchdog |
@@ -142,6 +149,7 @@ static atomic_t open_allowed = ATOMIC_INIT(1); | |||
142 | static char expect_close; | 149 | static char expect_close; |
143 | static int temp_panic; | 150 | static int temp_panic; |
144 | static struct { /* this is private data for each ISA-PC watchdog card */ | 151 | static struct { /* this is private data for each ISA-PC watchdog card */ |
152 | char fw_ver_str[6]; /* The cards firmware version */ | ||
145 | int revision; /* The card's revision */ | 153 | int revision; /* The card's revision */ |
146 | int supports_temp; /* Wether or not the card has a temperature device */ | 154 | int supports_temp; /* Wether or not the card has a temperature device */ |
147 | int command_mode; /* Wether or not the card is in command mode */ | 155 | int command_mode; /* Wether or not the card is in command mode */ |
@@ -153,6 +161,13 @@ static struct { /* this is private data for each ISA-PC watchdog card */ | |||
153 | } pcwd_private; | 161 | } pcwd_private; |
154 | 162 | ||
155 | /* module parameters */ | 163 | /* module parameters */ |
164 | #define QUIET 0 /* Default */ | ||
165 | #define VERBOSE 1 /* Verbose */ | ||
166 | #define DEBUG 2 /* print fancy stuff too */ | ||
167 | static int debug = QUIET; | ||
168 | module_param(debug, int, 0); | ||
169 | MODULE_PARM_DESC(debug, "Debug level: 0=Quiet, 1=Verbose, 2=Debug (default=0)"); | ||
170 | |||
156 | #define WATCHDOG_HEARTBEAT 60 /* 60 sec default heartbeat */ | 171 | #define WATCHDOG_HEARTBEAT 60 /* 60 sec default heartbeat */ |
157 | static int heartbeat = WATCHDOG_HEARTBEAT; | 172 | static int heartbeat = WATCHDOG_HEARTBEAT; |
158 | module_param(heartbeat, int, 0); | 173 | module_param(heartbeat, int, 0); |
@@ -172,6 +187,10 @@ static int send_isa_command(int cmd) | |||
172 | int control_status; | 187 | int control_status; |
173 | int port0, last_port0; /* Double read for stabilising */ | 188 | int port0, last_port0; /* Double read for stabilising */ |
174 | 189 | ||
190 | if (debug >= DEBUG) | ||
191 | printk(KERN_DEBUG PFX "sending following data cmd=0x%02x\n", | ||
192 | cmd); | ||
193 | |||
175 | /* The WCMD bit must be 1 and the command is only 4 bits in size */ | 194 | /* The WCMD bit must be 1 and the command is only 4 bits in size */ |
176 | control_status = (cmd & 0x0F) | WD_WCMD; | 195 | control_status = (cmd & 0x0F) | WD_WCMD; |
177 | outb_p(control_status, pcwd_private.io_addr + 2); | 196 | outb_p(control_status, pcwd_private.io_addr + 2); |
@@ -188,6 +207,10 @@ static int send_isa_command(int cmd) | |||
188 | udelay (250); | 207 | udelay (250); |
189 | } | 208 | } |
190 | 209 | ||
210 | if (debug >= DEBUG) | ||
211 | printk(KERN_DEBUG PFX "received following data for cmd=0x%02x: port0=0x%02x last_port0=0x%02x\n", | ||
212 | cmd, port0, last_port0); | ||
213 | |||
191 | return port0; | 214 | return port0; |
192 | } | 215 | } |
193 | 216 | ||
@@ -214,6 +237,10 @@ static int set_command_mode(void) | |||
214 | spin_unlock(&pcwd_private.io_lock); | 237 | spin_unlock(&pcwd_private.io_lock); |
215 | pcwd_private.command_mode = found; | 238 | pcwd_private.command_mode = found; |
216 | 239 | ||
240 | if (debug >= DEBUG) | ||
241 | printk(KERN_DEBUG PFX "command_mode=%d\n", | ||
242 | pcwd_private.command_mode); | ||
243 | |||
217 | return(found); | 244 | return(found); |
218 | } | 245 | } |
219 | 246 | ||
@@ -226,6 +253,10 @@ static void unset_command_mode(void) | |||
226 | spin_unlock(&pcwd_private.io_lock); | 253 | spin_unlock(&pcwd_private.io_lock); |
227 | 254 | ||
228 | pcwd_private.command_mode = 0; | 255 | pcwd_private.command_mode = 0; |
256 | |||
257 | if (debug >= DEBUG) | ||
258 | printk(KERN_DEBUG PFX "command_mode=%d\n", | ||
259 | pcwd_private.command_mode); | ||
229 | } | 260 | } |
230 | 261 | ||
231 | static inline void pcwd_check_temperature_support(void) | 262 | static inline void pcwd_check_temperature_support(void) |
@@ -234,27 +265,22 @@ static inline void pcwd_check_temperature_support(void) | |||
234 | pcwd_private.supports_temp = 1; | 265 | pcwd_private.supports_temp = 1; |
235 | } | 266 | } |
236 | 267 | ||
237 | static inline char *get_firmware(void) | 268 | static inline void pcwd_get_firmware(void) |
238 | { | 269 | { |
239 | int one, ten, hund, minor; | 270 | int one, ten, hund, minor; |
240 | char *ret; | ||
241 | 271 | ||
242 | ret = kmalloc(6, GFP_KERNEL); | 272 | strcpy(pcwd_private.fw_ver_str, "ERROR"); |
243 | if(ret == NULL) | ||
244 | return NULL; | ||
245 | 273 | ||
246 | if (set_command_mode()) { | 274 | if (set_command_mode()) { |
247 | one = send_isa_command(CMD_ISA_VERSION_INTEGER); | 275 | one = send_isa_command(CMD_ISA_VERSION_INTEGER); |
248 | ten = send_isa_command(CMD_ISA_VERSION_TENTH); | 276 | ten = send_isa_command(CMD_ISA_VERSION_TENTH); |
249 | hund = send_isa_command(CMD_ISA_VERSION_HUNDRETH); | 277 | hund = send_isa_command(CMD_ISA_VERSION_HUNDRETH); |
250 | minor = send_isa_command(CMD_ISA_VERSION_MINOR); | 278 | minor = send_isa_command(CMD_ISA_VERSION_MINOR); |
251 | sprintf(ret, "%c.%c%c%c", one, ten, hund, minor); | 279 | sprintf(pcwd_private.fw_ver_str, "%c.%c%c%c", one, ten, hund, minor); |
252 | } | 280 | } |
253 | else | ||
254 | sprintf(ret, "ERROR"); | ||
255 | |||
256 | unset_command_mode(); | 281 | unset_command_mode(); |
257 | return(ret); | 282 | |
283 | return; | ||
258 | } | 284 | } |
259 | 285 | ||
260 | static inline int pcwd_get_option_switches(void) | 286 | static inline int pcwd_get_option_switches(void) |
@@ -272,17 +298,15 @@ static inline int pcwd_get_option_switches(void) | |||
272 | 298 | ||
273 | static void pcwd_show_card_info(void) | 299 | static void pcwd_show_card_info(void) |
274 | { | 300 | { |
275 | char *firmware; | ||
276 | int option_switches; | 301 | int option_switches; |
277 | 302 | ||
278 | /* Get some extra info from the hardware (in command/debug/diag mode) */ | 303 | /* Get some extra info from the hardware (in command/debug/diag mode) */ |
279 | if (pcwd_private.revision == PCWD_REVISION_A) | 304 | if (pcwd_private.revision == PCWD_REVISION_A) |
280 | printk(KERN_INFO PFX "ISA-PC Watchdog (REV.A) detected at port 0x%04x\n", pcwd_private.io_addr); | 305 | printk(KERN_INFO PFX "ISA-PC Watchdog (REV.A) detected at port 0x%04x\n", pcwd_private.io_addr); |
281 | else if (pcwd_private.revision == PCWD_REVISION_C) { | 306 | else if (pcwd_private.revision == PCWD_REVISION_C) { |
282 | firmware = get_firmware(); | 307 | pcwd_get_firmware(); |
283 | printk(KERN_INFO PFX "ISA-PC Watchdog (REV.C) detected at port 0x%04x (Firmware version: %s)\n", | 308 | printk(KERN_INFO PFX "ISA-PC Watchdog (REV.C) detected at port 0x%04x (Firmware version: %s)\n", |
284 | pcwd_private.io_addr, firmware); | 309 | pcwd_private.io_addr, pcwd_private.fw_ver_str); |
285 | kfree(firmware); | ||
286 | option_switches = pcwd_get_option_switches(); | 310 | option_switches = pcwd_get_option_switches(); |
287 | printk(KERN_INFO PFX "Option switches (0x%02x): Temperature Reset Enable=%s, Power On Delay=%s\n", | 311 | printk(KERN_INFO PFX "Option switches (0x%02x): Temperature Reset Enable=%s, Power On Delay=%s\n", |
288 | option_switches, | 312 | option_switches, |
@@ -362,6 +386,10 @@ static int pcwd_start(void) | |||
362 | return -EIO; | 386 | return -EIO; |
363 | } | 387 | } |
364 | } | 388 | } |
389 | |||
390 | if (debug >= VERBOSE) | ||
391 | printk(KERN_DEBUG PFX "Watchdog started\n"); | ||
392 | |||
365 | return 0; | 393 | return 0; |
366 | } | 394 | } |
367 | 395 | ||
@@ -386,6 +414,10 @@ static int pcwd_stop(void) | |||
386 | return -EIO; | 414 | return -EIO; |
387 | } | 415 | } |
388 | } | 416 | } |
417 | |||
418 | if (debug >= VERBOSE) | ||
419 | printk(KERN_DEBUG PFX "Watchdog stopped\n"); | ||
420 | |||
389 | return 0; | 421 | return 0; |
390 | } | 422 | } |
391 | 423 | ||
@@ -393,6 +425,10 @@ static int pcwd_keepalive(void) | |||
393 | { | 425 | { |
394 | /* user land ping */ | 426 | /* user land ping */ |
395 | pcwd_private.next_heartbeat = jiffies + (heartbeat * HZ); | 427 | pcwd_private.next_heartbeat = jiffies + (heartbeat * HZ); |
428 | |||
429 | if (debug >= DEBUG) | ||
430 | printk(KERN_DEBUG PFX "Watchdog keepalive signal send\n"); | ||
431 | |||
396 | return 0; | 432 | return 0; |
397 | } | 433 | } |
398 | 434 | ||
@@ -402,12 +438,17 @@ static int pcwd_set_heartbeat(int t) | |||
402 | return -EINVAL; | 438 | return -EINVAL; |
403 | 439 | ||
404 | heartbeat = t; | 440 | heartbeat = t; |
441 | |||
442 | if (debug >= VERBOSE) | ||
443 | printk(KERN_DEBUG PFX "New heartbeat: %d\n", | ||
444 | heartbeat); | ||
445 | |||
405 | return 0; | 446 | return 0; |
406 | } | 447 | } |
407 | 448 | ||
408 | static int pcwd_get_status(int *status) | 449 | static int pcwd_get_status(int *status) |
409 | { | 450 | { |
410 | int card_status; | 451 | int control_status; |
411 | 452 | ||
412 | *status=0; | 453 | *status=0; |
413 | spin_lock(&pcwd_private.io_lock); | 454 | spin_lock(&pcwd_private.io_lock); |
@@ -415,37 +456,39 @@ static int pcwd_get_status(int *status) | |||
415 | /* Rev A cards return status information from | 456 | /* Rev A cards return status information from |
416 | * the base register, which is used for the | 457 | * the base register, which is used for the |
417 | * temperature in other cards. */ | 458 | * temperature in other cards. */ |
418 | card_status = inb(pcwd_private.io_addr); | 459 | control_status = inb(pcwd_private.io_addr); |
419 | else { | 460 | else { |
420 | /* Rev C cards return card status in the base | 461 | /* Rev C cards return card status in the base |
421 | * address + 1 register. And use different bits | 462 | * address + 1 register. And use different bits |
422 | * to indicate a card initiated reset, and an | 463 | * to indicate a card initiated reset, and an |
423 | * over-temperature condition. And the reboot | 464 | * over-temperature condition. And the reboot |
424 | * status can be reset. */ | 465 | * status can be reset. */ |
425 | card_status = inb(pcwd_private.io_addr + 1); | 466 | control_status = inb(pcwd_private.io_addr + 1); |
426 | } | 467 | } |
427 | spin_unlock(&pcwd_private.io_lock); | 468 | spin_unlock(&pcwd_private.io_lock); |
428 | 469 | ||
429 | if (pcwd_private.revision == PCWD_REVISION_A) { | 470 | if (pcwd_private.revision == PCWD_REVISION_A) { |
430 | if (card_status & WD_WDRST) | 471 | if (control_status & WD_WDRST) |
431 | *status |= WDIOF_CARDRESET; | 472 | *status |= WDIOF_CARDRESET; |
432 | 473 | ||
433 | if (card_status & WD_T110) { | 474 | if (control_status & WD_T110) { |
434 | *status |= WDIOF_OVERHEAT; | 475 | *status |= WDIOF_OVERHEAT; |
435 | if (temp_panic) { | 476 | if (temp_panic) { |
436 | printk (KERN_INFO PFX "Temperature overheat trip!\n"); | 477 | printk (KERN_INFO PFX "Temperature overheat trip!\n"); |
437 | kernel_power_off(); | 478 | kernel_power_off(); |
479 | /* or should we just do a: panic(PFX "Temperature overheat trip!\n"); */ | ||
438 | } | 480 | } |
439 | } | 481 | } |
440 | } else { | 482 | } else { |
441 | if (card_status & WD_REVC_WTRP) | 483 | if (control_status & WD_REVC_WTRP) |
442 | *status |= WDIOF_CARDRESET; | 484 | *status |= WDIOF_CARDRESET; |
443 | 485 | ||
444 | if (card_status & WD_REVC_TTRP) { | 486 | if (control_status & WD_REVC_TTRP) { |
445 | *status |= WDIOF_OVERHEAT; | 487 | *status |= WDIOF_OVERHEAT; |
446 | if (temp_panic) { | 488 | if (temp_panic) { |
447 | printk (KERN_INFO PFX "Temperature overheat trip!\n"); | 489 | printk (KERN_INFO PFX "Temperature overheat trip!\n"); |
448 | kernel_power_off(); | 490 | kernel_power_off(); |
491 | /* or should we just do a: panic(PFX "Temperature overheat trip!\n"); */ | ||
449 | } | 492 | } |
450 | } | 493 | } |
451 | } | 494 | } |
@@ -455,9 +498,25 @@ static int pcwd_get_status(int *status) | |||
455 | 498 | ||
456 | static int pcwd_clear_status(void) | 499 | static int pcwd_clear_status(void) |
457 | { | 500 | { |
501 | int control_status; | ||
502 | |||
458 | if (pcwd_private.revision == PCWD_REVISION_C) { | 503 | if (pcwd_private.revision == PCWD_REVISION_C) { |
459 | spin_lock(&pcwd_private.io_lock); | 504 | spin_lock(&pcwd_private.io_lock); |
460 | outb_p(0x00, pcwd_private.io_addr + 1); /* clear reset status */ | 505 | |
506 | if (debug >= VERBOSE) | ||
507 | printk(KERN_INFO PFX "clearing watchdog trip status\n"); | ||
508 | |||
509 | control_status = inb_p(pcwd_private.io_addr + 1); | ||
510 | |||
511 | if (debug >= DEBUG) { | ||
512 | printk(KERN_DEBUG PFX "status was: 0x%02x\n", control_status); | ||
513 | printk(KERN_DEBUG PFX "sending: 0x%02x\n", | ||
514 | (control_status & WD_REVC_R2DS)); | ||
515 | } | ||
516 | |||
517 | /* clear reset status & Keep Relay 2 disable state as it is */ | ||
518 | outb_p((control_status & WD_REVC_R2DS), pcwd_private.io_addr + 1); | ||
519 | |||
461 | spin_unlock(&pcwd_private.io_lock); | 520 | spin_unlock(&pcwd_private.io_lock); |
462 | } | 521 | } |
463 | return 0; | 522 | return 0; |
@@ -481,6 +540,11 @@ static int pcwd_get_temperature(int *temperature) | |||
481 | *temperature = ((inb(pcwd_private.io_addr)) * 9 / 5) + 32; | 540 | *temperature = ((inb(pcwd_private.io_addr)) * 9 / 5) + 32; |
482 | spin_unlock(&pcwd_private.io_lock); | 541 | spin_unlock(&pcwd_private.io_lock); |
483 | 542 | ||
543 | if (debug >= DEBUG) { | ||
544 | printk(KERN_DEBUG PFX "temperature is: %d F\n", | ||
545 | *temperature); | ||
546 | } | ||
547 | |||
484 | return 0; | 548 | return 0; |
485 | } | 549 | } |
486 | 550 | ||
@@ -599,6 +663,8 @@ static ssize_t pcwd_write(struct file *file, const char __user *buf, size_t len, | |||
599 | static int pcwd_open(struct inode *inode, struct file *file) | 663 | static int pcwd_open(struct inode *inode, struct file *file) |
600 | { | 664 | { |
601 | if (!atomic_dec_and_test(&open_allowed) ) { | 665 | if (!atomic_dec_and_test(&open_allowed) ) { |
666 | if (debug >= VERBOSE) | ||
667 | printk(KERN_ERR PFX "Attempt to open already opened device.\n"); | ||
602 | atomic_inc( &open_allowed ); | 668 | atomic_inc( &open_allowed ); |
603 | return -EBUSY; | 669 | return -EBUSY; |
604 | } | 670 | } |
@@ -922,7 +988,8 @@ static void __exit pcwd_cleanup_module(void) | |||
922 | { | 988 | { |
923 | if (pcwd_private.io_addr) | 989 | if (pcwd_private.io_addr) |
924 | pcwatchdog_exit(); | 990 | pcwatchdog_exit(); |
925 | return; | 991 | |
992 | printk(KERN_INFO PFX "Watchdog Module Unloaded.\n"); | ||
926 | } | 993 | } |
927 | 994 | ||
928 | module_init(pcwd_init_module); | 995 | module_init(pcwd_init_module); |
diff --git a/drivers/char/watchdog/pcwd_usb.c b/drivers/char/watchdog/pcwd_usb.c index 2700c5c45b8a..3fdfda9324fa 100644 --- a/drivers/char/watchdog/pcwd_usb.c +++ b/drivers/char/watchdog/pcwd_usb.c | |||
@@ -705,7 +705,8 @@ err_out_misc_deregister: | |||
705 | err_out_unregister_reboot: | 705 | err_out_unregister_reboot: |
706 | unregister_reboot_notifier(&usb_pcwd_notifier); | 706 | unregister_reboot_notifier(&usb_pcwd_notifier); |
707 | error: | 707 | error: |
708 | usb_pcwd_delete (usb_pcwd); | 708 | if (usb_pcwd) |
709 | usb_pcwd_delete(usb_pcwd); | ||
709 | usb_pcwd_device = NULL; | 710 | usb_pcwd_device = NULL; |
710 | return retval; | 711 | return retval; |
711 | } | 712 | } |