aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--drivers/watchdog/sc1200wdt.c203
1 files changed, 114 insertions, 89 deletions
diff --git a/drivers/watchdog/sc1200wdt.c b/drivers/watchdog/sc1200wdt.c
index 35cddff7020f..7e5c9cc97dee 100644
--- a/drivers/watchdog/sc1200wdt.c
+++ b/drivers/watchdog/sc1200wdt.c
@@ -15,14 +15,18 @@
15 * 15 *
16 * Changelog: 16 * Changelog:
17 * 20020220 Zwane Mwaikambo Code based on datasheet, no hardware. 17 * 20020220 Zwane Mwaikambo Code based on datasheet, no hardware.
18 * 20020221 Zwane Mwaikambo Cleanups as suggested by Jeff Garzik and Alan Cox. 18 * 20020221 Zwane Mwaikambo Cleanups as suggested by Jeff Garzik
19 * and Alan Cox.
19 * 20020222 Zwane Mwaikambo Added probing. 20 * 20020222 Zwane Mwaikambo Added probing.
20 * 20020225 Zwane Mwaikambo Added ISAPNP support. 21 * 20020225 Zwane Mwaikambo Added ISAPNP support.
21 * 20020412 Rob Radez Broke out start/stop functions 22 * 20020412 Rob Radez Broke out start/stop functions
22 * <rob@osinvestor.com> Return proper status instead of temperature warning 23 * <rob@osinvestor.com> Return proper status instead of
23 * Add WDIOC_GETBOOTSTATUS and WDIOC_SETOPTIONS ioctls 24 * temperature warning
25 * Add WDIOC_GETBOOTSTATUS and
26 * WDIOC_SETOPTIONS ioctls
24 * Fix CONFIG_WATCHDOG_NOWAYOUT 27 * Fix CONFIG_WATCHDOG_NOWAYOUT
25 * 20020530 Joel Becker Add Matt Domsch's nowayout module option 28 * 20020530 Joel Becker Add Matt Domsch's nowayout module
29 * option
26 * 20030116 Adam Belay Updated to the latest pnp code 30 * 20030116 Adam Belay Updated to the latest pnp code
27 * 31 *
28 */ 32 */
@@ -39,9 +43,8 @@
39#include <linux/pnp.h> 43#include <linux/pnp.h>
40#include <linux/fs.h> 44#include <linux/fs.h>
41#include <linux/semaphore.h> 45#include <linux/semaphore.h>
42 46#include <linux/io.h>
43#include <asm/io.h> 47#include <linux/uaccess.h>
44#include <asm/uaccess.h>
45 48
46#define SC1200_MODULE_VER "build 20020303" 49#define SC1200_MODULE_VER "build 20020303"
47#define SC1200_MODULE_NAME "sc1200wdt" 50#define SC1200_MODULE_NAME "sc1200wdt"
@@ -72,7 +75,7 @@ static char banner[] __initdata = KERN_INFO PFX SC1200_MODULE_VER;
72static int timeout = 1; 75static int timeout = 1;
73static int io = -1; 76static int io = -1;
74static int io_len = 2; /* for non plug and play */ 77static int io_len = 2; /* for non plug and play */
75static struct semaphore open_sem; 78static unsigned long open_flag;
76static char expect_close; 79static char expect_close;
77static DEFINE_SPINLOCK(sc1200wdt_lock); /* io port access serialisation */ 80static DEFINE_SPINLOCK(sc1200wdt_lock); /* io port access serialisation */
78 81
@@ -81,7 +84,8 @@ static int isapnp = 1;
81static struct pnp_dev *wdt_dev; 84static struct pnp_dev *wdt_dev;
82 85
83module_param(isapnp, int, 0); 86module_param(isapnp, int, 0);
84MODULE_PARM_DESC(isapnp, "When set to 0 driver ISA PnP support will be disabled"); 87MODULE_PARM_DESC(isapnp,
88 "When set to 0 driver ISA PnP support will be disabled");
85#endif 89#endif
86 90
87module_param(io, int, 0); 91module_param(io, int, 0);
@@ -91,26 +95,40 @@ MODULE_PARM_DESC(timeout, "range is 0-255 minutes, default is 1");
91 95
92static int nowayout = WATCHDOG_NOWAYOUT; 96static int nowayout = WATCHDOG_NOWAYOUT;
93module_param(nowayout, int, 0); 97module_param(nowayout, int, 0);
94MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default=" __MODULE_STRING(WATCHDOG_NOWAYOUT) ")"); 98MODULE_PARM_DESC(nowayout,
99 "Watchdog cannot be stopped once started (default="
100 __MODULE_STRING(WATCHDOG_NOWAYOUT) ")");
95 101
96 102
97 103
98/* Read from Data Register */ 104/* Read from Data Register */
99static inline void sc1200wdt_read_data(unsigned char index, unsigned char *data) 105static inline void __sc1200wdt_read_data(unsigned char index,
106 unsigned char *data)
100{ 107{
101 spin_lock(&sc1200wdt_lock);
102 outb_p(index, PMIR); 108 outb_p(index, PMIR);
103 *data = inb(PMDR); 109 *data = inb(PMDR);
104 spin_unlock(&sc1200wdt_lock);
105} 110}
106 111
112static void sc1200wdt_read_data(unsigned char index, unsigned char *data)
113{
114 spin_lock(&sc1200wdt_lock);
115 __sc1200wdt_read_data(index, data);
116 spin_unlock(&sc1200wdt_lock);
117}
107 118
108/* Write to Data Register */ 119/* Write to Data Register */
109static inline void sc1200wdt_write_data(unsigned char index, unsigned char data) 120static inline void __sc1200wdt_write_data(unsigned char index,
121 unsigned char data)
110{ 122{
111 spin_lock(&sc1200wdt_lock);
112 outb_p(index, PMIR); 123 outb_p(index, PMIR);
113 outb(data, PMDR); 124 outb(data, PMDR);
125}
126
127static inline void sc1200wdt_write_data(unsigned char index,
128 unsigned char data)
129{
130 spin_lock(&sc1200wdt_lock);
131 __sc1200wdt_write_data(index, data);
114 spin_unlock(&sc1200wdt_lock); 132 spin_unlock(&sc1200wdt_lock);
115} 133}
116 134
@@ -118,13 +136,16 @@ static inline void sc1200wdt_write_data(unsigned char index, unsigned char data)
118static void sc1200wdt_start(void) 136static void sc1200wdt_start(void)
119{ 137{
120 unsigned char reg; 138 unsigned char reg;
139 spin_lock(&sc1200wdt_lock);
121 140
122 sc1200wdt_read_data(WDCF, &reg); 141 __sc1200wdt_read_data(WDCF, &reg);
123 /* assert WDO when any of the following interrupts are triggered too */ 142 /* assert WDO when any of the following interrupts are triggered too */
124 reg |= (KBC_IRQ | MSE_IRQ | UART1_IRQ | UART2_IRQ); 143 reg |= (KBC_IRQ | MSE_IRQ | UART1_IRQ | UART2_IRQ);
125 sc1200wdt_write_data(WDCF, reg); 144 __sc1200wdt_write_data(WDCF, reg);
126 /* set the timeout and get the ball rolling */ 145 /* set the timeout and get the ball rolling */
127 sc1200wdt_write_data(WDTO, timeout); 146 __sc1200wdt_write_data(WDTO, timeout);
147
148 spin_unlock(&sc1200wdt_lock);
128} 149}
129 150
130 151
@@ -144,14 +165,15 @@ static inline int sc1200wdt_status(void)
144 * KEEPALIVEPING which is a bit of a kludge because there's nothing 165 * KEEPALIVEPING which is a bit of a kludge because there's nothing
145 * else for enabled/disabled status 166 * else for enabled/disabled status
146 */ 167 */
147 return (ret & 0x01) ? 0 : WDIOF_KEEPALIVEPING; /* bits 1 - 7 are undefined */ 168 return (ret & 0x01) ? 0 : WDIOF_KEEPALIVEPING;
169 /* bits 1 - 7 are undefined */
148} 170}
149 171
150 172
151static int sc1200wdt_open(struct inode *inode, struct file *file) 173static int sc1200wdt_open(struct inode *inode, struct file *file)
152{ 174{
153 /* allow one at a time */ 175 /* allow one at a time */
154 if (down_trylock(&open_sem)) 176 if (test_and_set_bit(0, &open_flag))
155 return -EBUSY; 177 return -EBUSY;
156 178
157 if (timeout > MAX_TIMEOUT) 179 if (timeout > MAX_TIMEOUT)
@@ -164,71 +186,71 @@ static int sc1200wdt_open(struct inode *inode, struct file *file)
164} 186}
165 187
166 188
167static int sc1200wdt_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg) 189static long sc1200wdt_ioctl(struct file *file, unsigned int cmd,
190 unsigned long arg)
168{ 191{
169 int new_timeout; 192 int new_timeout;
170 void __user *argp = (void __user *)arg; 193 void __user *argp = (void __user *)arg;
171 int __user *p = argp; 194 int __user *p = argp;
172 static struct watchdog_info ident = { 195 static const struct watchdog_info ident = {
173 .options = WDIOF_KEEPALIVEPING | WDIOF_SETTIMEOUT | WDIOF_MAGICCLOSE, 196 .options = WDIOF_KEEPALIVEPING | WDIOF_SETTIMEOUT |
197 WDIOF_MAGICCLOSE,
174 .firmware_version = 0, 198 .firmware_version = 0,
175 .identity = "PC87307/PC97307", 199 .identity = "PC87307/PC97307",
176 }; 200 };
177 201
178 switch (cmd) { 202 switch (cmd) {
179 default:
180 return -ENOTTY;
181
182 case WDIOC_GETSUPPORT:
183 if (copy_to_user(argp, &ident, sizeof ident))
184 return -EFAULT;
185 return 0;
186 203
187 case WDIOC_GETSTATUS: 204 case WDIOC_GETSUPPORT:
188 return put_user(sc1200wdt_status(), p); 205 if (copy_to_user(argp, &ident, sizeof ident))
206 return -EFAULT;
207 return 0;
189 208
190 case WDIOC_GETBOOTSTATUS: 209 case WDIOC_GETSTATUS:
191 return put_user(0, p); 210 return put_user(sc1200wdt_status(), p);
192 211
193 case WDIOC_KEEPALIVE: 212 case WDIOC_GETBOOTSTATUS:
194 sc1200wdt_write_data(WDTO, timeout); 213 return put_user(0, p);
195 return 0;
196 214
197 case WDIOC_SETTIMEOUT: 215 case WDIOC_KEEPALIVE:
198 if (get_user(new_timeout, p)) 216 sc1200wdt_write_data(WDTO, timeout);
199 return -EFAULT; 217 return 0;
200 218
201 /* the API states this is given in secs */ 219 case WDIOC_SETTIMEOUT:
202 new_timeout /= 60; 220 if (get_user(new_timeout, p))
203 if (new_timeout < 0 || new_timeout > MAX_TIMEOUT) 221 return -EFAULT;
204 return -EINVAL; 222 /* the API states this is given in secs */
205 223 new_timeout /= 60;
206 timeout = new_timeout; 224 if (new_timeout < 0 || new_timeout > MAX_TIMEOUT)
207 sc1200wdt_write_data(WDTO, timeout); 225 return -EINVAL;
208 /* fall through and return the new timeout */ 226 timeout = new_timeout;
209 227 sc1200wdt_write_data(WDTO, timeout);
210 case WDIOC_GETTIMEOUT: 228 /* fall through and return the new timeout */
211 return put_user(timeout * 60, p);
212 229
213 case WDIOC_SETOPTIONS: 230 case WDIOC_GETTIMEOUT:
214 { 231 return put_user(timeout * 60, p);
215 int options, retval = -EINVAL;
216 232
217 if (get_user(options, p)) 233 case WDIOC_SETOPTIONS:
218 return -EFAULT; 234 {
235 int options, retval = -EINVAL;
219 236
220 if (options & WDIOS_DISABLECARD) { 237 if (get_user(options, p))
221 sc1200wdt_stop(); 238 return -EFAULT;
222 retval = 0;
223 }
224 239
225 if (options & WDIOS_ENABLECARD) { 240 if (options & WDIOS_DISABLECARD) {
226 sc1200wdt_start(); 241 sc1200wdt_stop();
227 retval = 0; 242 retval = 0;
228 } 243 }
229 244
230 return retval; 245 if (options & WDIOS_ENABLECARD) {
246 sc1200wdt_start();
247 retval = 0;
231 } 248 }
249
250 return retval;
251 }
252 default:
253 return -ENOTTY;
232 } 254 }
233} 255}
234 256
@@ -240,16 +262,18 @@ static int sc1200wdt_release(struct inode *inode, struct file *file)
240 printk(KERN_INFO PFX "Watchdog disabled\n"); 262 printk(KERN_INFO PFX "Watchdog disabled\n");
241 } else { 263 } else {
242 sc1200wdt_write_data(WDTO, timeout); 264 sc1200wdt_write_data(WDTO, timeout);
243 printk(KERN_CRIT PFX "Unexpected close!, timeout = %d min(s)\n", timeout); 265 printk(KERN_CRIT PFX
266 "Unexpected close!, timeout = %d min(s)\n", timeout);
244 } 267 }
245 up(&open_sem); 268 clear_bit(0, &open_flag);
246 expect_close = 0; 269 expect_close = 0;
247 270
248 return 0; 271 return 0;
249} 272}
250 273
251 274
252static ssize_t sc1200wdt_write(struct file *file, const char __user *data, size_t len, loff_t *ppos) 275static ssize_t sc1200wdt_write(struct file *file, const char __user *data,
276 size_t len, loff_t *ppos)
253{ 277{
254 if (len) { 278 if (len) {
255 if (!nowayout) { 279 if (!nowayout) {
@@ -275,7 +299,8 @@ static ssize_t sc1200wdt_write(struct file *file, const char __user *data, size_
275} 299}
276 300
277 301
278static int sc1200wdt_notify_sys(struct notifier_block *this, unsigned long code, void *unused) 302static int sc1200wdt_notify_sys(struct notifier_block *this,
303 unsigned long code, void *unused)
279{ 304{
280 if (code == SYS_DOWN || code == SYS_HALT) 305 if (code == SYS_DOWN || code == SYS_HALT)
281 sc1200wdt_stop(); 306 sc1200wdt_stop();
@@ -284,23 +309,20 @@ static int sc1200wdt_notify_sys(struct notifier_block *this, unsigned long code,
284} 309}
285 310
286 311
287static struct notifier_block sc1200wdt_notifier = 312static struct notifier_block sc1200wdt_notifier = {
288{
289 .notifier_call = sc1200wdt_notify_sys, 313 .notifier_call = sc1200wdt_notify_sys,
290}; 314};
291 315
292static const struct file_operations sc1200wdt_fops = 316static const struct file_operations sc1200wdt_fops = {
293{
294 .owner = THIS_MODULE, 317 .owner = THIS_MODULE,
295 .llseek = no_llseek, 318 .llseek = no_llseek,
296 .write = sc1200wdt_write, 319 .write = sc1200wdt_write,
297 .ioctl = sc1200wdt_ioctl, 320 .unlocked_ioctl = sc1200wdt_ioctl,
298 .open = sc1200wdt_open, 321 .open = sc1200wdt_open,
299 .release = sc1200wdt_release, 322 .release = sc1200wdt_release,
300}; 323};
301 324
302static struct miscdevice sc1200wdt_miscdev = 325static struct miscdevice sc1200wdt_miscdev = {
303{
304 .minor = WATCHDOG_MINOR, 326 .minor = WATCHDOG_MINOR,
305 .name = "watchdog", 327 .name = "watchdog",
306 .fops = &sc1200wdt_fops, 328 .fops = &sc1200wdt_fops,
@@ -312,14 +334,14 @@ static int __init sc1200wdt_probe(void)
312 /* The probe works by reading the PMC3 register's default value of 0x0e 334 /* The probe works by reading the PMC3 register's default value of 0x0e
313 * there is one caveat, if the device disables the parallel port or any 335 * there is one caveat, if the device disables the parallel port or any
314 * of the UARTs we won't be able to detect it. 336 * of the UARTs we won't be able to detect it.
315 * Nb. This could be done with accuracy by reading the SID registers, but 337 * NB. This could be done with accuracy by reading the SID registers,
316 * we don't have access to those io regions. 338 * but we don't have access to those io regions.
317 */ 339 */
318 340
319 unsigned char reg; 341 unsigned char reg;
320 342
321 sc1200wdt_read_data(PMC3, &reg); 343 sc1200wdt_read_data(PMC3, &reg);
322 reg &= 0x0f; /* we don't want the UART busy bits */ 344 reg &= 0x0f; /* we don't want the UART busy bits */
323 return (reg == 0x0e) ? 0 : -ENODEV; 345 return (reg == 0x0e) ? 0 : -ENODEV;
324} 346}
325 347
@@ -332,7 +354,8 @@ static struct pnp_device_id scl200wdt_pnp_devices[] = {
332 {.id = ""}, 354 {.id = ""},
333}; 355};
334 356
335static int scl200wdt_pnp_probe(struct pnp_dev * dev, const struct pnp_device_id *dev_id) 357static int scl200wdt_pnp_probe(struct pnp_dev *dev,
358 const struct pnp_device_id *dev_id)
336{ 359{
337 /* this driver only supports one card at a time */ 360 /* this driver only supports one card at a time */
338 if (wdt_dev || !isapnp) 361 if (wdt_dev || !isapnp)
@@ -347,13 +370,14 @@ static int scl200wdt_pnp_probe(struct pnp_dev * dev, const struct pnp_device_id
347 return -EBUSY; 370 return -EBUSY;
348 } 371 }
349 372
350 printk(KERN_INFO "scl200wdt: PnP device found at io port %#x/%d\n", io, io_len); 373 printk(KERN_INFO "scl200wdt: PnP device found at io port %#x/%d\n",
374 io, io_len);
351 return 0; 375 return 0;
352} 376}
353 377
354static void scl200wdt_pnp_remove(struct pnp_dev * dev) 378static void scl200wdt_pnp_remove(struct pnp_dev *dev)
355{ 379{
356 if (wdt_dev){ 380 if (wdt_dev) {
357 release_region(io, io_len); 381 release_region(io, io_len);
358 wdt_dev = NULL; 382 wdt_dev = NULL;
359 } 383 }
@@ -375,8 +399,6 @@ static int __init sc1200wdt_init(void)
375 399
376 printk("%s\n", banner); 400 printk("%s\n", banner);
377 401
378 sema_init(&open_sem, 1);
379
380#if defined CONFIG_PNP 402#if defined CONFIG_PNP
381 if (isapnp) { 403 if (isapnp) {
382 ret = pnp_register_driver(&scl200wdt_pnp_driver); 404 ret = pnp_register_driver(&scl200wdt_pnp_driver);
@@ -410,13 +432,16 @@ static int __init sc1200wdt_init(void)
410 432
411 ret = register_reboot_notifier(&sc1200wdt_notifier); 433 ret = register_reboot_notifier(&sc1200wdt_notifier);
412 if (ret) { 434 if (ret) {
413 printk(KERN_ERR PFX "Unable to register reboot notifier err = %d\n", ret); 435 printk(KERN_ERR PFX
436 "Unable to register reboot notifier err = %d\n", ret);
414 goto out_io; 437 goto out_io;
415 } 438 }
416 439
417 ret = misc_register(&sc1200wdt_miscdev); 440 ret = misc_register(&sc1200wdt_miscdev);
418 if (ret) { 441 if (ret) {
419 printk(KERN_ERR PFX "Unable to register miscdev on minor %d\n", WATCHDOG_MINOR); 442 printk(KERN_ERR PFX
443 "Unable to register miscdev on minor %d\n",
444 WATCHDOG_MINOR);
420 goto out_rbt; 445 goto out_rbt;
421 } 446 }
422 447
@@ -446,7 +471,7 @@ static void __exit sc1200wdt_exit(void)
446 unregister_reboot_notifier(&sc1200wdt_notifier); 471 unregister_reboot_notifier(&sc1200wdt_notifier);
447 472
448#if defined CONFIG_PNP 473#if defined CONFIG_PNP
449 if(isapnp) 474 if (isapnp)
450 pnp_unregister_driver(&scl200wdt_pnp_driver); 475 pnp_unregister_driver(&scl200wdt_pnp_driver);
451 else 476 else
452#endif 477#endif