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
0032
0033
0034
0035
0036
0037
0038
0039
0040
0041
0042 #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
0043
0044 #include <linux/module.h>
0045 #include <linux/moduleparam.h>
0046 #include <linux/types.h>
0047 #include <linux/miscdevice.h>
0048 #include <linux/watchdog.h>
0049 #include <linux/delay.h>
0050 #include <linux/fs.h>
0051 #include <linux/ioport.h>
0052 #include <linux/notifier.h>
0053 #include <linux/reboot.h>
0054 #include <linux/init.h>
0055 #include <linux/spinlock.h>
0056 #include <linux/io.h>
0057 #include <linux/uaccess.h>
0058
0059
0060
0061
0062 #define SMSC_SUPPORT_MINUTES
0063 #undef SMSC_SUPPORT_MINUTES
0064
0065 #define MAX_TIMEOUT 255
0066
0067 #define UNIT_SECOND 0
0068 #define UNIT_MINUTE 1
0069
0070 #define VERSION "1.1"
0071
0072 #define IOPORT 0x3F0
0073 #define IOPORT_SIZE 2
0074 #define IODEV_NO 8
0075
0076 static int unit = UNIT_SECOND;
0077 static int timeout = 60;
0078 static unsigned long timer_enabled;
0079
0080 static char expect_close;
0081
0082 static DEFINE_SPINLOCK(io_lock);
0083
0084 static bool nowayout = WATCHDOG_NOWAYOUT;
0085
0086
0087
0088
0089
0090 static inline void open_io_config(void)
0091 {
0092 outb(0x55, IOPORT);
0093 mdelay(1);
0094 outb(0x55, IOPORT);
0095 }
0096
0097
0098 static inline void close_io_config(void)
0099 {
0100 outb(0xAA, IOPORT);
0101 }
0102
0103
0104 static inline void select_io_device(unsigned char devno)
0105 {
0106 outb(0x07, IOPORT);
0107 outb(devno, IOPORT+1);
0108 }
0109
0110
0111 static inline void write_io_cr(unsigned char reg, unsigned char data)
0112 {
0113 outb(reg, IOPORT);
0114 outb(data, IOPORT+1);
0115 }
0116
0117
0118 static inline char read_io_cr(unsigned char reg)
0119 {
0120 outb(reg, IOPORT);
0121 return inb(IOPORT+1);
0122 }
0123
0124
0125
0126 static inline void gpio_bit12(unsigned char reg)
0127 {
0128
0129
0130
0131
0132
0133
0134
0135
0136
0137 write_io_cr(0xE2, reg);
0138 }
0139
0140 static inline void gpio_bit13(unsigned char reg)
0141 {
0142
0143
0144
0145
0146
0147
0148
0149
0150 write_io_cr(0xE3, reg);
0151 }
0152
0153 static inline void wdt_timer_units(unsigned char new_units)
0154 {
0155
0156
0157
0158
0159
0160 write_io_cr(0xF1, new_units);
0161 }
0162
0163 static inline void wdt_timeout_value(unsigned char new_timeout)
0164 {
0165
0166
0167
0168 write_io_cr(0xF2, new_timeout);
0169 }
0170
0171 static inline void wdt_timer_conf(unsigned char conf)
0172 {
0173
0174
0175
0176
0177
0178
0179
0180
0181
0182
0183
0184 write_io_cr(0xF3, conf);
0185 }
0186
0187 static inline void wdt_timer_ctrl(unsigned char reg)
0188 {
0189
0190
0191
0192
0193
0194
0195
0196
0197
0198
0199
0200
0201
0202
0203
0204
0205
0206 write_io_cr(0xF4, reg);
0207 }
0208
0209
0210
0211
0212
0213 static void wb_smsc_wdt_initialize(void)
0214 {
0215 unsigned char old;
0216
0217 spin_lock(&io_lock);
0218 open_io_config();
0219 select_io_device(IODEV_NO);
0220
0221
0222 gpio_bit13(0x08);
0223 gpio_bit12(0x0A);
0224
0225
0226 wdt_timeout_value(0);
0227
0228
0229 wdt_timer_ctrl(0x00);
0230
0231
0232 wdt_timer_conf(0x00);
0233
0234
0235 old = read_io_cr(0xF1) & 0x7F;
0236 if (unit == UNIT_SECOND)
0237 old |= 0x80;
0238
0239
0240 wdt_timer_units(old);
0241
0242 close_io_config();
0243 spin_unlock(&io_lock);
0244 }
0245
0246
0247
0248 static void wb_smsc_wdt_shutdown(void)
0249 {
0250 spin_lock(&io_lock);
0251 open_io_config();
0252 select_io_device(IODEV_NO);
0253
0254
0255 gpio_bit13(0x09);
0256 gpio_bit12(0x09);
0257
0258
0259 wdt_timer_conf(0x00);
0260
0261
0262 wdt_timer_ctrl(0x00);
0263
0264
0265 wdt_timeout_value(0x00);
0266
0267 close_io_config();
0268 spin_unlock(&io_lock);
0269 }
0270
0271
0272
0273 static void wb_smsc_wdt_set_timeout(unsigned char new_timeout)
0274 {
0275 spin_lock(&io_lock);
0276 open_io_config();
0277 select_io_device(IODEV_NO);
0278
0279
0280 wdt_timer_ctrl((new_timeout == 0) ? 0x00 : 0x02);
0281
0282
0283 wdt_timeout_value(new_timeout);
0284
0285 close_io_config();
0286 spin_unlock(&io_lock);
0287 }
0288
0289
0290
0291 static unsigned char wb_smsc_wdt_get_timeout(void)
0292 {
0293 unsigned char set_timeout;
0294
0295 spin_lock(&io_lock);
0296 open_io_config();
0297 select_io_device(IODEV_NO);
0298 set_timeout = read_io_cr(0xF2);
0299 close_io_config();
0300 spin_unlock(&io_lock);
0301
0302 return set_timeout;
0303 }
0304
0305
0306
0307 static void wb_smsc_wdt_disable(void)
0308 {
0309
0310 wb_smsc_wdt_set_timeout(0);
0311 }
0312
0313
0314
0315 static void wb_smsc_wdt_enable(void)
0316 {
0317
0318 wb_smsc_wdt_set_timeout(timeout);
0319 }
0320
0321
0322
0323 static void wb_smsc_wdt_reset_timer(void)
0324 {
0325 spin_lock(&io_lock);
0326 open_io_config();
0327 select_io_device(IODEV_NO);
0328
0329
0330 wdt_timeout_value(timeout);
0331 wdt_timer_conf(0x08);
0332
0333 close_io_config();
0334 spin_unlock(&io_lock);
0335 }
0336
0337
0338
0339 static int wb_smsc_wdt_status(void)
0340 {
0341 return (wb_smsc_wdt_get_timeout() == 0) ? 0 : WDIOF_KEEPALIVEPING;
0342 }
0343
0344
0345
0346
0347
0348
0349 static int wb_smsc_wdt_open(struct inode *inode, struct file *file)
0350 {
0351
0352
0353 if (test_and_set_bit(0, &timer_enabled))
0354 return -EBUSY;
0355
0356 if (nowayout)
0357 __module_get(THIS_MODULE);
0358
0359
0360 wb_smsc_wdt_enable();
0361
0362 pr_info("Watchdog enabled. Timeout set to %d %s\n",
0363 timeout, (unit == UNIT_SECOND) ? "second(s)" : "minute(s)");
0364
0365 return stream_open(inode, file);
0366 }
0367
0368
0369
0370 static int wb_smsc_wdt_release(struct inode *inode, struct file *file)
0371 {
0372
0373
0374 if (expect_close == 42) {
0375 wb_smsc_wdt_disable();
0376 pr_info("Watchdog disabled, sleeping again...\n");
0377 } else {
0378 pr_crit("Unexpected close, not stopping watchdog!\n");
0379 wb_smsc_wdt_reset_timer();
0380 }
0381
0382 clear_bit(0, &timer_enabled);
0383 expect_close = 0;
0384 return 0;
0385 }
0386
0387
0388
0389 static ssize_t wb_smsc_wdt_write(struct file *file, const char __user *data,
0390 size_t len, loff_t *ppos)
0391 {
0392
0393 if (len) {
0394 if (!nowayout) {
0395 size_t i;
0396
0397
0398 expect_close = 0;
0399
0400
0401
0402 for (i = 0; i != len; i++) {
0403 char c;
0404 if (get_user(c, data + i))
0405 return -EFAULT;
0406 if (c == 'V')
0407 expect_close = 42;
0408 }
0409 }
0410
0411
0412 wb_smsc_wdt_reset_timer();
0413 }
0414 return len;
0415 }
0416
0417
0418
0419 static long wb_smsc_wdt_ioctl(struct file *file,
0420 unsigned int cmd, unsigned long arg)
0421 {
0422 int new_timeout;
0423
0424 union {
0425 struct watchdog_info __user *ident;
0426 int __user *i;
0427 } uarg;
0428
0429 static const struct watchdog_info ident = {
0430 .options = WDIOF_KEEPALIVEPING |
0431 WDIOF_SETTIMEOUT |
0432 WDIOF_MAGICCLOSE,
0433 .firmware_version = 0,
0434 .identity = "SMsC 37B787 Watchdog",
0435 };
0436
0437 uarg.i = (int __user *)arg;
0438
0439 switch (cmd) {
0440 case WDIOC_GETSUPPORT:
0441 return copy_to_user(uarg.ident, &ident, sizeof(ident))
0442 ? -EFAULT : 0;
0443 case WDIOC_GETSTATUS:
0444 return put_user(wb_smsc_wdt_status(), uarg.i);
0445 case WDIOC_GETBOOTSTATUS:
0446 return put_user(0, uarg.i);
0447 case WDIOC_SETOPTIONS:
0448 {
0449 int options, retval = -EINVAL;
0450
0451 if (get_user(options, uarg.i))
0452 return -EFAULT;
0453
0454 if (options & WDIOS_DISABLECARD) {
0455 wb_smsc_wdt_disable();
0456 retval = 0;
0457 }
0458 if (options & WDIOS_ENABLECARD) {
0459 wb_smsc_wdt_enable();
0460 retval = 0;
0461 }
0462 return retval;
0463 }
0464 case WDIOC_KEEPALIVE:
0465 wb_smsc_wdt_reset_timer();
0466 return 0;
0467 case WDIOC_SETTIMEOUT:
0468 if (get_user(new_timeout, uarg.i))
0469 return -EFAULT;
0470
0471 if (unit == UNIT_MINUTE)
0472 new_timeout /= 60;
0473 if (new_timeout < 0 || new_timeout > MAX_TIMEOUT)
0474 return -EINVAL;
0475 timeout = new_timeout;
0476 wb_smsc_wdt_set_timeout(timeout);
0477 fallthrough;
0478 case WDIOC_GETTIMEOUT:
0479 new_timeout = timeout;
0480 if (unit == UNIT_MINUTE)
0481 new_timeout *= 60;
0482 return put_user(new_timeout, uarg.i);
0483 default:
0484 return -ENOTTY;
0485 }
0486 }
0487
0488
0489
0490 static int wb_smsc_wdt_notify_sys(struct notifier_block *this,
0491 unsigned long code, void *unused)
0492 {
0493 if (code == SYS_DOWN || code == SYS_HALT) {
0494
0495 timeout = 0;
0496 wb_smsc_wdt_disable();
0497 }
0498 return NOTIFY_DONE;
0499 }
0500
0501
0502
0503 static const struct file_operations wb_smsc_wdt_fops = {
0504 .owner = THIS_MODULE,
0505 .llseek = no_llseek,
0506 .write = wb_smsc_wdt_write,
0507 .unlocked_ioctl = wb_smsc_wdt_ioctl,
0508 .compat_ioctl = compat_ptr_ioctl,
0509 .open = wb_smsc_wdt_open,
0510 .release = wb_smsc_wdt_release,
0511 };
0512
0513 static struct notifier_block wb_smsc_wdt_notifier = {
0514 .notifier_call = wb_smsc_wdt_notify_sys,
0515 };
0516
0517 static struct miscdevice wb_smsc_wdt_miscdev = {
0518 .minor = WATCHDOG_MINOR,
0519 .name = "watchdog",
0520 .fops = &wb_smsc_wdt_fops,
0521 };
0522
0523
0524
0525
0526
0527 static int __init wb_smsc_wdt_init(void)
0528 {
0529 int ret;
0530
0531 pr_info("SMsC 37B787 watchdog component driver "
0532 VERSION " initialising...\n");
0533
0534 if (!request_region(IOPORT, IOPORT_SIZE, "SMsC 37B787 watchdog")) {
0535 pr_err("Unable to register IO port %#x\n", IOPORT);
0536 ret = -EBUSY;
0537 goto out_pnp;
0538 }
0539
0540
0541 if (timeout > MAX_TIMEOUT)
0542 timeout = MAX_TIMEOUT;
0543
0544
0545 wb_smsc_wdt_initialize();
0546
0547 ret = register_reboot_notifier(&wb_smsc_wdt_notifier);
0548 if (ret) {
0549 pr_err("Unable to register reboot notifier err = %d\n", ret);
0550 goto out_io;
0551 }
0552
0553 ret = misc_register(&wb_smsc_wdt_miscdev);
0554 if (ret) {
0555 pr_err("Unable to register miscdev on minor %d\n",
0556 WATCHDOG_MINOR);
0557 goto out_rbt;
0558 }
0559
0560
0561 pr_info("Timeout set to %d %s\n",
0562 timeout, (unit == UNIT_SECOND) ? "second(s)" : "minute(s)");
0563 pr_info("Watchdog initialized and sleeping (nowayout=%d)...\n",
0564 nowayout);
0565 out_clean:
0566 return ret;
0567
0568 out_rbt:
0569 unregister_reboot_notifier(&wb_smsc_wdt_notifier);
0570
0571 out_io:
0572 release_region(IOPORT, IOPORT_SIZE);
0573
0574 out_pnp:
0575 goto out_clean;
0576 }
0577
0578
0579
0580 static void __exit wb_smsc_wdt_exit(void)
0581 {
0582
0583 if (!nowayout) {
0584 wb_smsc_wdt_shutdown();
0585 pr_info("Watchdog disabled\n");
0586 }
0587
0588 misc_deregister(&wb_smsc_wdt_miscdev);
0589 unregister_reboot_notifier(&wb_smsc_wdt_notifier);
0590 release_region(IOPORT, IOPORT_SIZE);
0591
0592 pr_info("SMsC 37B787 watchdog component driver removed\n");
0593 }
0594
0595 module_init(wb_smsc_wdt_init);
0596 module_exit(wb_smsc_wdt_exit);
0597
0598 MODULE_AUTHOR("Sven Anders <anders@anduras.de>");
0599 MODULE_DESCRIPTION("Driver for SMsC 37B787 watchdog component (Version "
0600 VERSION ")");
0601 MODULE_LICENSE("GPL");
0602
0603 #ifdef SMSC_SUPPORT_MINUTES
0604 module_param(unit, int, 0);
0605 MODULE_PARM_DESC(unit,
0606 "set unit to use, 0=seconds or 1=minutes, default is 0");
0607 #endif
0608
0609 module_param(timeout, int, 0);
0610 MODULE_PARM_DESC(timeout, "range is 1-255 units, default is 60");
0611
0612 module_param(nowayout, bool, 0);
0613 MODULE_PARM_DESC(nowayout,
0614 "Watchdog cannot be stopped once started (default="
0615 __MODULE_STRING(WATCHDOG_NOWAYOUT) ")");