0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012
0013
0014
0015
0016
0017
0018
0019
0020
0021
0022
0023
0024
0025
0026
0027
0028
0029
0030
0031 #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
0032
0033 #include <linux/interrupt.h>
0034 #include <linux/module.h>
0035 #include <linux/moduleparam.h>
0036 #include <linux/types.h>
0037 #include <linux/miscdevice.h>
0038 #include <linux/watchdog.h>
0039 #include <linux/fs.h>
0040 #include <linux/ioport.h>
0041 #include <linux/notifier.h>
0042 #include <linux/reboot.h>
0043 #include <linux/init.h>
0044 #include <linux/io.h>
0045 #include <linux/uaccess.h>
0046
0047 #include "wd501p.h"
0048
0049 static unsigned long wdt_is_open;
0050 static char expect_close;
0051
0052
0053
0054
0055
0056 #define WD_TIMO 60
0057
0058 static int heartbeat = WD_TIMO;
0059 static int wd_heartbeat;
0060 module_param(heartbeat, int, 0);
0061 MODULE_PARM_DESC(heartbeat,
0062 "Watchdog heartbeat in seconds. (0 < heartbeat < 65536, default="
0063 __MODULE_STRING(WD_TIMO) ")");
0064
0065 static bool nowayout = WATCHDOG_NOWAYOUT;
0066 module_param(nowayout, bool, 0);
0067 MODULE_PARM_DESC(nowayout,
0068 "Watchdog cannot be stopped once started (default="
0069 __MODULE_STRING(WATCHDOG_NOWAYOUT) ")");
0070
0071
0072 static int io = 0x240;
0073 static int irq = 11;
0074
0075 static DEFINE_SPINLOCK(wdt_lock);
0076
0077 module_param_hw(io, int, ioport, 0);
0078 MODULE_PARM_DESC(io, "WDT io port (default=0x240)");
0079 module_param_hw(irq, int, irq, 0);
0080 MODULE_PARM_DESC(irq, "WDT irq (default=11)");
0081
0082
0083 static int tachometer;
0084 module_param(tachometer, int, 0);
0085 MODULE_PARM_DESC(tachometer,
0086 "WDT501-P Fan Tachometer support (0=disable, default=0)");
0087
0088 static int type = 500;
0089 module_param(type, int, 0);
0090 MODULE_PARM_DESC(type,
0091 "WDT501-P Card type (500 or 501, default=500)");
0092
0093
0094
0095
0096
0097 static void wdt_ctr_mode(int ctr, int mode)
0098 {
0099 ctr <<= 6;
0100 ctr |= 0x30;
0101 ctr |= (mode << 1);
0102 outb_p(ctr, WDT_CR);
0103 }
0104
0105 static void wdt_ctr_load(int ctr, int val)
0106 {
0107 outb_p(val&0xFF, WDT_COUNT0+ctr);
0108 outb_p(val>>8, WDT_COUNT0+ctr);
0109 }
0110
0111
0112
0113
0114
0115
0116
0117 static int wdt_start(void)
0118 {
0119 unsigned long flags;
0120 spin_lock_irqsave(&wdt_lock, flags);
0121 inb_p(WDT_DC);
0122 wdt_ctr_mode(0, 3);
0123
0124 wdt_ctr_mode(1, 2);
0125
0126 wdt_ctr_mode(2, 0);
0127
0128 wdt_ctr_load(0, 8948);
0129 wdt_ctr_load(1, wd_heartbeat);
0130 wdt_ctr_load(2, 65535);
0131 outb_p(0, WDT_DC);
0132 spin_unlock_irqrestore(&wdt_lock, flags);
0133 return 0;
0134 }
0135
0136
0137
0138
0139
0140
0141
0142 static int wdt_stop(void)
0143 {
0144 unsigned long flags;
0145 spin_lock_irqsave(&wdt_lock, flags);
0146
0147 inb_p(WDT_DC);
0148 wdt_ctr_load(2, 0);
0149 spin_unlock_irqrestore(&wdt_lock, flags);
0150 return 0;
0151 }
0152
0153
0154
0155
0156
0157
0158
0159
0160 static void wdt_ping(void)
0161 {
0162 unsigned long flags;
0163 spin_lock_irqsave(&wdt_lock, flags);
0164
0165 inb_p(WDT_DC);
0166 wdt_ctr_mode(1, 2);
0167
0168 wdt_ctr_load(1, wd_heartbeat);
0169 outb_p(0, WDT_DC);
0170 spin_unlock_irqrestore(&wdt_lock, flags);
0171 }
0172
0173
0174
0175
0176
0177
0178
0179
0180
0181
0182 static int wdt_set_heartbeat(int t)
0183 {
0184 if (t < 1 || t > 65535)
0185 return -EINVAL;
0186
0187 heartbeat = t;
0188 wd_heartbeat = t * 100;
0189 return 0;
0190 }
0191
0192
0193
0194
0195
0196
0197
0198
0199
0200
0201
0202 static int wdt_get_status(void)
0203 {
0204 unsigned char new_status;
0205 int status = 0;
0206 unsigned long flags;
0207
0208 spin_lock_irqsave(&wdt_lock, flags);
0209 new_status = inb_p(WDT_SR);
0210 spin_unlock_irqrestore(&wdt_lock, flags);
0211
0212 if (new_status & WDC_SR_ISOI0)
0213 status |= WDIOF_EXTERN1;
0214 if (new_status & WDC_SR_ISII1)
0215 status |= WDIOF_EXTERN2;
0216 if (type == 501) {
0217 if (!(new_status & WDC_SR_TGOOD))
0218 status |= WDIOF_OVERHEAT;
0219 if (!(new_status & WDC_SR_PSUOVER))
0220 status |= WDIOF_POWEROVER;
0221 if (!(new_status & WDC_SR_PSUUNDR))
0222 status |= WDIOF_POWERUNDER;
0223 if (tachometer) {
0224 if (!(new_status & WDC_SR_FANGOOD))
0225 status |= WDIOF_FANFAULT;
0226 }
0227 }
0228 return status;
0229 }
0230
0231
0232
0233
0234
0235
0236
0237
0238 static int wdt_get_temperature(void)
0239 {
0240 unsigned short c;
0241 unsigned long flags;
0242
0243 spin_lock_irqsave(&wdt_lock, flags);
0244 c = inb_p(WDT_RT);
0245 spin_unlock_irqrestore(&wdt_lock, flags);
0246 return (c * 11 / 15) + 7;
0247 }
0248
0249 static void wdt_decode_501(int status)
0250 {
0251 if (!(status & WDC_SR_TGOOD))
0252 pr_crit("Overheat alarm (%d)\n", inb_p(WDT_RT));
0253 if (!(status & WDC_SR_PSUOVER))
0254 pr_crit("PSU over voltage\n");
0255 if (!(status & WDC_SR_PSUUNDR))
0256 pr_crit("PSU under voltage\n");
0257 }
0258
0259
0260
0261
0262
0263
0264
0265
0266
0267
0268
0269 static irqreturn_t wdt_interrupt(int irq, void *dev_id)
0270 {
0271
0272
0273
0274
0275 unsigned char status;
0276
0277 spin_lock(&wdt_lock);
0278 status = inb_p(WDT_SR);
0279
0280 pr_crit("WDT status %d\n", status);
0281
0282 if (type == 501) {
0283 wdt_decode_501(status);
0284 if (tachometer) {
0285 if (!(status & WDC_SR_FANGOOD))
0286 pr_crit("Possible fan fault\n");
0287 }
0288 }
0289 if (!(status & WDC_SR_WCCR)) {
0290 #ifdef SOFTWARE_REBOOT
0291 #ifdef ONLY_TESTING
0292 pr_crit("Would Reboot\n");
0293 #else
0294 pr_crit("Initiating system reboot\n");
0295 emergency_restart();
0296 #endif
0297 #else
0298 pr_crit("Reset in 5ms\n");
0299 #endif
0300 }
0301 spin_unlock(&wdt_lock);
0302 return IRQ_HANDLED;
0303 }
0304
0305
0306
0307
0308
0309
0310
0311
0312
0313
0314
0315
0316
0317 static ssize_t wdt_write(struct file *file, const char __user *buf,
0318 size_t count, loff_t *ppos)
0319 {
0320 if (count) {
0321 if (!nowayout) {
0322 size_t i;
0323
0324
0325 expect_close = 0;
0326
0327 for (i = 0; i != count; i++) {
0328 char c;
0329 if (get_user(c, buf + i))
0330 return -EFAULT;
0331 if (c == 'V')
0332 expect_close = 42;
0333 }
0334 }
0335 wdt_ping();
0336 }
0337 return count;
0338 }
0339
0340
0341
0342
0343
0344
0345
0346
0347
0348
0349
0350
0351 static long wdt_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
0352 {
0353 void __user *argp = (void __user *)arg;
0354 int __user *p = argp;
0355 int new_heartbeat;
0356 int status;
0357
0358 struct watchdog_info ident = {
0359 .options = WDIOF_SETTIMEOUT|
0360 WDIOF_MAGICCLOSE|
0361 WDIOF_KEEPALIVEPING,
0362 .firmware_version = 1,
0363 .identity = "WDT500/501",
0364 };
0365
0366
0367 ident.options |= (WDIOF_EXTERN1|WDIOF_EXTERN2);
0368 if (type == 501) {
0369 ident.options |= (WDIOF_OVERHEAT|WDIOF_POWERUNDER|
0370 WDIOF_POWEROVER);
0371 if (tachometer)
0372 ident.options |= WDIOF_FANFAULT;
0373 }
0374
0375 switch (cmd) {
0376 case WDIOC_GETSUPPORT:
0377 return copy_to_user(argp, &ident, sizeof(ident)) ? -EFAULT : 0;
0378 case WDIOC_GETSTATUS:
0379 status = wdt_get_status();
0380 return put_user(status, p);
0381 case WDIOC_GETBOOTSTATUS:
0382 return put_user(0, p);
0383 case WDIOC_KEEPALIVE:
0384 wdt_ping();
0385 return 0;
0386 case WDIOC_SETTIMEOUT:
0387 if (get_user(new_heartbeat, p))
0388 return -EFAULT;
0389 if (wdt_set_heartbeat(new_heartbeat))
0390 return -EINVAL;
0391 wdt_ping();
0392 fallthrough;
0393 case WDIOC_GETTIMEOUT:
0394 return put_user(heartbeat, p);
0395 default:
0396 return -ENOTTY;
0397 }
0398 }
0399
0400
0401
0402
0403
0404
0405
0406
0407
0408
0409
0410
0411
0412 static int wdt_open(struct inode *inode, struct file *file)
0413 {
0414 if (test_and_set_bit(0, &wdt_is_open))
0415 return -EBUSY;
0416
0417
0418
0419 wdt_start();
0420 return stream_open(inode, file);
0421 }
0422
0423
0424
0425
0426
0427
0428
0429
0430
0431
0432
0433
0434
0435 static int wdt_release(struct inode *inode, struct file *file)
0436 {
0437 if (expect_close == 42) {
0438 wdt_stop();
0439 clear_bit(0, &wdt_is_open);
0440 } else {
0441 pr_crit("WDT device closed unexpectedly. WDT will not stop!\n");
0442 wdt_ping();
0443 }
0444 expect_close = 0;
0445 return 0;
0446 }
0447
0448
0449
0450
0451
0452
0453
0454
0455
0456
0457
0458
0459 static ssize_t wdt_temp_read(struct file *file, char __user *buf,
0460 size_t count, loff_t *ptr)
0461 {
0462 int temperature = wdt_get_temperature();
0463
0464 if (copy_to_user(buf, &temperature, 1))
0465 return -EFAULT;
0466
0467 return 1;
0468 }
0469
0470
0471
0472
0473
0474
0475
0476
0477
0478 static int wdt_temp_open(struct inode *inode, struct file *file)
0479 {
0480 return stream_open(inode, file);
0481 }
0482
0483
0484
0485
0486
0487
0488
0489
0490
0491 static int wdt_temp_release(struct inode *inode, struct file *file)
0492 {
0493 return 0;
0494 }
0495
0496
0497
0498
0499
0500
0501
0502
0503
0504
0505
0506
0507
0508 static int wdt_notify_sys(struct notifier_block *this, unsigned long code,
0509 void *unused)
0510 {
0511 if (code == SYS_DOWN || code == SYS_HALT)
0512 wdt_stop();
0513 return NOTIFY_DONE;
0514 }
0515
0516
0517
0518
0519
0520
0521 static const struct file_operations wdt_fops = {
0522 .owner = THIS_MODULE,
0523 .llseek = no_llseek,
0524 .write = wdt_write,
0525 .unlocked_ioctl = wdt_ioctl,
0526 .compat_ioctl = compat_ptr_ioctl,
0527 .open = wdt_open,
0528 .release = wdt_release,
0529 };
0530
0531 static struct miscdevice wdt_miscdev = {
0532 .minor = WATCHDOG_MINOR,
0533 .name = "watchdog",
0534 .fops = &wdt_fops,
0535 };
0536
0537 static const struct file_operations wdt_temp_fops = {
0538 .owner = THIS_MODULE,
0539 .llseek = no_llseek,
0540 .read = wdt_temp_read,
0541 .open = wdt_temp_open,
0542 .release = wdt_temp_release,
0543 };
0544
0545 static struct miscdevice temp_miscdev = {
0546 .minor = TEMP_MINOR,
0547 .name = "temperature",
0548 .fops = &wdt_temp_fops,
0549 };
0550
0551
0552
0553
0554
0555
0556 static struct notifier_block wdt_notifier = {
0557 .notifier_call = wdt_notify_sys,
0558 };
0559
0560
0561
0562
0563
0564
0565
0566
0567
0568
0569
0570 static void __exit wdt_exit(void)
0571 {
0572 misc_deregister(&wdt_miscdev);
0573 if (type == 501)
0574 misc_deregister(&temp_miscdev);
0575 unregister_reboot_notifier(&wdt_notifier);
0576 free_irq(irq, NULL);
0577 release_region(io, 8);
0578 }
0579
0580
0581
0582
0583
0584
0585
0586
0587
0588 static int __init wdt_init(void)
0589 {
0590 int ret;
0591
0592 if (type != 500 && type != 501) {
0593 pr_err("unknown card type '%d'\n", type);
0594 return -ENODEV;
0595 }
0596
0597
0598
0599 if (wdt_set_heartbeat(heartbeat)) {
0600 wdt_set_heartbeat(WD_TIMO);
0601 pr_info("heartbeat value must be 0 < heartbeat < 65536, using %d\n",
0602 WD_TIMO);
0603 }
0604
0605 if (!request_region(io, 8, "wdt501p")) {
0606 pr_err("I/O address 0x%04x already in use\n", io);
0607 ret = -EBUSY;
0608 goto out;
0609 }
0610
0611 ret = request_irq(irq, wdt_interrupt, 0, "wdt501p", NULL);
0612 if (ret) {
0613 pr_err("IRQ %d is not free\n", irq);
0614 goto outreg;
0615 }
0616
0617 ret = register_reboot_notifier(&wdt_notifier);
0618 if (ret) {
0619 pr_err("cannot register reboot notifier (err=%d)\n", ret);
0620 goto outirq;
0621 }
0622
0623 if (type == 501) {
0624 ret = misc_register(&temp_miscdev);
0625 if (ret) {
0626 pr_err("cannot register miscdev on minor=%d (err=%d)\n",
0627 TEMP_MINOR, ret);
0628 goto outrbt;
0629 }
0630 }
0631
0632 ret = misc_register(&wdt_miscdev);
0633 if (ret) {
0634 pr_err("cannot register miscdev on minor=%d (err=%d)\n",
0635 WATCHDOG_MINOR, ret);
0636 goto outmisc;
0637 }
0638
0639 pr_info("WDT500/501-P driver 0.10 at 0x%04x (Interrupt %d). heartbeat=%d sec (nowayout=%d)\n",
0640 io, irq, heartbeat, nowayout);
0641 if (type == 501)
0642 pr_info("Fan Tachometer is %s\n",
0643 tachometer ? "Enabled" : "Disabled");
0644 return 0;
0645
0646 outmisc:
0647 if (type == 501)
0648 misc_deregister(&temp_miscdev);
0649 outrbt:
0650 unregister_reboot_notifier(&wdt_notifier);
0651 outirq:
0652 free_irq(irq, NULL);
0653 outreg:
0654 release_region(io, 8);
0655 out:
0656 return ret;
0657 }
0658
0659 module_init(wdt_init);
0660 module_exit(wdt_exit);
0661
0662 MODULE_AUTHOR("Alan Cox");
0663 MODULE_DESCRIPTION("Driver for ISA ICS watchdog cards (WDT500/501)");
0664 MODULE_LICENSE("GPL");