0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012
0013
0014
0015
0016
0017
0018
0019
0020
0021
0022 #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
0023
0024 #include <linux/module.h>
0025 #include <linux/moduleparam.h>
0026 #include <linux/types.h>
0027 #include <linux/kernel.h>
0028 #include <linux/fs.h>
0029 #include <linux/miscdevice.h>
0030 #include <linux/init.h>
0031 #include <linux/ioport.h>
0032 #include <linux/watchdog.h>
0033 #include <linux/notifier.h>
0034 #include <linux/reboot.h>
0035 #include <linux/io.h>
0036 #include <linux/uaccess.h>
0037
0038 #include <asm/mach-types.h>
0039
0040 #define WATCHDOG_VERSION "0.04"
0041 #define WATCHDOG_NAME "Wdt977"
0042
0043 #define IO_INDEX_PORT 0x370
0044 #define IO_DATA_PORT (IO_INDEX_PORT + 1)
0045
0046 #define UNLOCK_DATA 0x87
0047 #define LOCK_DATA 0xAA
0048 #define DEVICE_REGISTER 0x07
0049
0050
0051 #define DEFAULT_TIMEOUT 60
0052
0053 static int timeout = DEFAULT_TIMEOUT;
0054 static int timeoutM;
0055 static unsigned long timer_alive;
0056 static int testmode;
0057 static char expect_close;
0058 static DEFINE_SPINLOCK(spinlock);
0059
0060 module_param(timeout, int, 0);
0061 MODULE_PARM_DESC(timeout, "Watchdog timeout in seconds (60..15300, default="
0062 __MODULE_STRING(DEFAULT_TIMEOUT) ")");
0063 module_param(testmode, int, 0);
0064 MODULE_PARM_DESC(testmode, "Watchdog testmode (1 = no reboot), default=0");
0065
0066 static bool nowayout = WATCHDOG_NOWAYOUT;
0067 module_param(nowayout, bool, 0);
0068 MODULE_PARM_DESC(nowayout,
0069 "Watchdog cannot be stopped once started (default="
0070 __MODULE_STRING(WATCHDOG_NOWAYOUT) ")");
0071
0072
0073
0074
0075
0076 static int wdt977_start(void)
0077 {
0078 unsigned long flags;
0079
0080 spin_lock_irqsave(&spinlock, flags);
0081
0082
0083 outb_p(UNLOCK_DATA, IO_INDEX_PORT);
0084 outb_p(UNLOCK_DATA, IO_INDEX_PORT);
0085
0086
0087
0088
0089
0090
0091
0092 outb_p(DEVICE_REGISTER, IO_INDEX_PORT);
0093 outb_p(0x08, IO_DATA_PORT);
0094 outb_p(0xF2, IO_INDEX_PORT);
0095 outb_p(timeoutM, IO_DATA_PORT);
0096 outb_p(0xF3, IO_INDEX_PORT);
0097 outb_p(0x00, IO_DATA_PORT);
0098
0099 outb_p(0xF4, IO_INDEX_PORT);
0100 outb_p(0x00, IO_DATA_PORT);
0101
0102
0103
0104
0105
0106 if (!testmode) {
0107 outb_p(DEVICE_REGISTER, IO_INDEX_PORT);
0108 outb_p(0x07, IO_DATA_PORT);
0109 outb_p(0xE6, IO_INDEX_PORT);
0110 outb_p(0x08, IO_DATA_PORT);
0111 }
0112
0113
0114 outb_p(LOCK_DATA, IO_INDEX_PORT);
0115
0116 spin_unlock_irqrestore(&spinlock, flags);
0117 pr_info("activated\n");
0118
0119 return 0;
0120 }
0121
0122
0123
0124
0125
0126 static int wdt977_stop(void)
0127 {
0128 unsigned long flags;
0129 spin_lock_irqsave(&spinlock, flags);
0130
0131
0132 outb_p(UNLOCK_DATA, IO_INDEX_PORT);
0133 outb_p(UNLOCK_DATA, IO_INDEX_PORT);
0134
0135
0136
0137
0138
0139
0140 outb_p(DEVICE_REGISTER, IO_INDEX_PORT);
0141 outb_p(0x08, IO_DATA_PORT);
0142 outb_p(0xF2, IO_INDEX_PORT);
0143 outb_p(0xFF, IO_DATA_PORT);
0144 outb_p(0xF3, IO_INDEX_PORT);
0145 outb_p(0x00, IO_DATA_PORT);
0146 outb_p(0xF4, IO_INDEX_PORT);
0147 outb_p(0x00, IO_DATA_PORT);
0148 outb_p(0xF2, IO_INDEX_PORT);
0149 outb_p(0x00, IO_DATA_PORT);
0150
0151
0152
0153 outb_p(DEVICE_REGISTER, IO_INDEX_PORT);
0154 outb_p(0x07, IO_DATA_PORT);
0155 outb_p(0xE6, IO_INDEX_PORT);
0156 outb_p(0x08, IO_DATA_PORT);
0157
0158
0159 outb_p(LOCK_DATA, IO_INDEX_PORT);
0160
0161 spin_unlock_irqrestore(&spinlock, flags);
0162 pr_info("shutdown\n");
0163
0164 return 0;
0165 }
0166
0167
0168
0169
0170
0171
0172 static int wdt977_keepalive(void)
0173 {
0174 unsigned long flags;
0175 spin_lock_irqsave(&spinlock, flags);
0176
0177
0178 outb_p(UNLOCK_DATA, IO_INDEX_PORT);
0179 outb_p(UNLOCK_DATA, IO_INDEX_PORT);
0180
0181
0182
0183 outb_p(DEVICE_REGISTER, IO_INDEX_PORT);
0184 outb_p(0x08, IO_DATA_PORT);
0185 outb_p(0xF2, IO_INDEX_PORT);
0186 outb_p(timeoutM, IO_DATA_PORT);
0187
0188
0189 outb_p(LOCK_DATA, IO_INDEX_PORT);
0190 spin_unlock_irqrestore(&spinlock, flags);
0191
0192 return 0;
0193 }
0194
0195
0196
0197
0198
0199 static int wdt977_set_timeout(int t)
0200 {
0201 int tmrval;
0202
0203
0204 tmrval = (t + 59) / 60;
0205
0206 if (machine_is_netwinder()) {
0207
0208
0209
0210
0211 tmrval += tmrval;
0212 }
0213
0214 if (tmrval < 1 || tmrval > 255)
0215 return -EINVAL;
0216
0217
0218
0219 timeout = t;
0220 timeoutM = tmrval;
0221 return 0;
0222 }
0223
0224
0225
0226
0227
0228 static int wdt977_get_status(int *status)
0229 {
0230 int new_status;
0231 unsigned long flags;
0232
0233 spin_lock_irqsave(&spinlock, flags);
0234
0235
0236 outb_p(UNLOCK_DATA, IO_INDEX_PORT);
0237 outb_p(UNLOCK_DATA, IO_INDEX_PORT);
0238
0239
0240 outb_p(DEVICE_REGISTER, IO_INDEX_PORT);
0241 outb_p(0x08, IO_DATA_PORT);
0242 outb_p(0xF4, IO_INDEX_PORT);
0243 new_status = inb_p(IO_DATA_PORT);
0244
0245
0246 outb_p(LOCK_DATA, IO_INDEX_PORT);
0247
0248 spin_unlock_irqrestore(&spinlock, flags);
0249
0250 *status = 0;
0251 if (new_status & 1)
0252 *status |= WDIOF_CARDRESET;
0253
0254 return 0;
0255 }
0256
0257
0258
0259
0260
0261
0262 static int wdt977_open(struct inode *inode, struct file *file)
0263 {
0264
0265 if (test_and_set_bit(0, &timer_alive))
0266 return -EBUSY;
0267
0268 if (nowayout)
0269 __module_get(THIS_MODULE);
0270
0271 wdt977_start();
0272 return stream_open(inode, file);
0273 }
0274
0275 static int wdt977_release(struct inode *inode, struct file *file)
0276 {
0277
0278
0279
0280
0281 if (expect_close == 42) {
0282 wdt977_stop();
0283 clear_bit(0, &timer_alive);
0284 } else {
0285 wdt977_keepalive();
0286 pr_crit("Unexpected close, not stopping watchdog!\n");
0287 }
0288 expect_close = 0;
0289 return 0;
0290 }
0291
0292
0293
0294
0295
0296
0297
0298
0299
0300
0301
0302
0303
0304 static ssize_t wdt977_write(struct file *file, const char __user *buf,
0305 size_t count, loff_t *ppos)
0306 {
0307 if (count) {
0308 if (!nowayout) {
0309 size_t i;
0310
0311
0312 expect_close = 0;
0313
0314 for (i = 0; i != count; i++) {
0315 char c;
0316 if (get_user(c, buf + i))
0317 return -EFAULT;
0318 if (c == 'V')
0319 expect_close = 42;
0320 }
0321 }
0322
0323
0324 wdt977_keepalive();
0325 }
0326 return count;
0327 }
0328
0329 static const struct watchdog_info ident = {
0330 .options = WDIOF_SETTIMEOUT |
0331 WDIOF_MAGICCLOSE |
0332 WDIOF_KEEPALIVEPING,
0333 .firmware_version = 1,
0334 .identity = WATCHDOG_NAME,
0335 };
0336
0337
0338
0339
0340
0341
0342
0343
0344
0345
0346
0347
0348 static long wdt977_ioctl(struct file *file, unsigned int cmd,
0349 unsigned long arg)
0350 {
0351 int status;
0352 int new_options, retval = -EINVAL;
0353 int new_timeout;
0354 union {
0355 struct watchdog_info __user *ident;
0356 int __user *i;
0357 } uarg;
0358
0359 uarg.i = (int __user *)arg;
0360
0361 switch (cmd) {
0362 case WDIOC_GETSUPPORT:
0363 return copy_to_user(uarg.ident, &ident,
0364 sizeof(ident)) ? -EFAULT : 0;
0365
0366 case WDIOC_GETSTATUS:
0367 wdt977_get_status(&status);
0368 return put_user(status, uarg.i);
0369
0370 case WDIOC_GETBOOTSTATUS:
0371 return put_user(0, uarg.i);
0372
0373 case WDIOC_SETOPTIONS:
0374 if (get_user(new_options, uarg.i))
0375 return -EFAULT;
0376
0377 if (new_options & WDIOS_DISABLECARD) {
0378 wdt977_stop();
0379 retval = 0;
0380 }
0381
0382 if (new_options & WDIOS_ENABLECARD) {
0383 wdt977_start();
0384 retval = 0;
0385 }
0386
0387 return retval;
0388
0389 case WDIOC_KEEPALIVE:
0390 wdt977_keepalive();
0391 return 0;
0392
0393 case WDIOC_SETTIMEOUT:
0394 if (get_user(new_timeout, uarg.i))
0395 return -EFAULT;
0396
0397 if (wdt977_set_timeout(new_timeout))
0398 return -EINVAL;
0399
0400 wdt977_keepalive();
0401 fallthrough;
0402
0403 case WDIOC_GETTIMEOUT:
0404 return put_user(timeout, uarg.i);
0405
0406 default:
0407 return -ENOTTY;
0408
0409 }
0410 }
0411
0412 static int wdt977_notify_sys(struct notifier_block *this, unsigned long code,
0413 void *unused)
0414 {
0415 if (code == SYS_DOWN || code == SYS_HALT)
0416 wdt977_stop();
0417 return NOTIFY_DONE;
0418 }
0419
0420 static const struct file_operations wdt977_fops = {
0421 .owner = THIS_MODULE,
0422 .llseek = no_llseek,
0423 .write = wdt977_write,
0424 .unlocked_ioctl = wdt977_ioctl,
0425 .compat_ioctl = compat_ptr_ioctl,
0426 .open = wdt977_open,
0427 .release = wdt977_release,
0428 };
0429
0430 static struct miscdevice wdt977_miscdev = {
0431 .minor = WATCHDOG_MINOR,
0432 .name = "watchdog",
0433 .fops = &wdt977_fops,
0434 };
0435
0436 static struct notifier_block wdt977_notifier = {
0437 .notifier_call = wdt977_notify_sys,
0438 };
0439
0440 static int __init wd977_init(void)
0441 {
0442 int rc;
0443
0444 pr_info("driver v%s\n", WATCHDOG_VERSION);
0445
0446
0447
0448 if (wdt977_set_timeout(timeout)) {
0449 wdt977_set_timeout(DEFAULT_TIMEOUT);
0450 pr_info("timeout value must be 60 < timeout < 15300, using %d\n",
0451 DEFAULT_TIMEOUT);
0452 }
0453
0454
0455
0456
0457 if (!machine_is_netwinder()) {
0458 if (!request_region(IO_INDEX_PORT, 2, WATCHDOG_NAME)) {
0459 pr_err("I/O address 0x%04x already in use\n",
0460 IO_INDEX_PORT);
0461 rc = -EIO;
0462 goto err_out;
0463 }
0464 }
0465
0466 rc = register_reboot_notifier(&wdt977_notifier);
0467 if (rc) {
0468 pr_err("cannot register reboot notifier (err=%d)\n", rc);
0469 goto err_out_region;
0470 }
0471
0472 rc = misc_register(&wdt977_miscdev);
0473 if (rc) {
0474 pr_err("cannot register miscdev on minor=%d (err=%d)\n",
0475 wdt977_miscdev.minor, rc);
0476 goto err_out_reboot;
0477 }
0478
0479 pr_info("initialized. timeout=%d sec (nowayout=%d, testmode=%i)\n",
0480 timeout, nowayout, testmode);
0481
0482 return 0;
0483
0484 err_out_reboot:
0485 unregister_reboot_notifier(&wdt977_notifier);
0486 err_out_region:
0487 if (!machine_is_netwinder())
0488 release_region(IO_INDEX_PORT, 2);
0489 err_out:
0490 return rc;
0491 }
0492
0493 static void __exit wd977_exit(void)
0494 {
0495 wdt977_stop();
0496 misc_deregister(&wdt977_miscdev);
0497 unregister_reboot_notifier(&wdt977_notifier);
0498 release_region(IO_INDEX_PORT, 2);
0499 }
0500
0501 module_init(wd977_init);
0502 module_exit(wd977_exit);
0503
0504 MODULE_AUTHOR("Woody Suwalski <woodys@xandros.com>");
0505 MODULE_DESCRIPTION("W83977AF Watchdog driver");
0506 MODULE_LICENSE("GPL");