This source file includes following definitions.
- open_io_config
- close_io_config
- select_io_device
- write_io_cr
- read_io_cr
- gpio_bit12
- gpio_bit13
- wdt_timer_units
- wdt_timeout_value
- wdt_timer_conf
- wdt_timer_ctrl
- wb_smsc_wdt_initialize
- wb_smsc_wdt_shutdown
- wb_smsc_wdt_set_timeout
- wb_smsc_wdt_get_timeout
- wb_smsc_wdt_disable
- wb_smsc_wdt_enable
- wb_smsc_wdt_reset_timer
- wb_smsc_wdt_status
- wb_smsc_wdt_open
- wb_smsc_wdt_release
- wb_smsc_wdt_write
- wb_smsc_wdt_ioctl
- wb_smsc_wdt_notify_sys
- wb_smsc_wdt_init
- wb_smsc_wdt_exit
   1 
   2 
   3 
   4 
   5 
   6 
   7 
   8 
   9 
  10 
  11 
  12 
  13 
  14 
  15 
  16 
  17 
  18 
  19 
  20 
  21 
  22 
  23 
  24 
  25 
  26 
  27 
  28 
  29 
  30 
  31 
  32 
  33 
  34 
  35 
  36 
  37 
  38 
  39 
  40 
  41 
  42 #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
  43 
  44 #include <linux/module.h>
  45 #include <linux/moduleparam.h>
  46 #include <linux/types.h>
  47 #include <linux/miscdevice.h>
  48 #include <linux/watchdog.h>
  49 #include <linux/delay.h>
  50 #include <linux/fs.h>
  51 #include <linux/ioport.h>
  52 #include <linux/notifier.h>
  53 #include <linux/reboot.h>
  54 #include <linux/init.h>
  55 #include <linux/spinlock.h>
  56 #include <linux/io.h>
  57 #include <linux/uaccess.h>
  58 
  59 
  60 
  61 
  62 #define SMSC_SUPPORT_MINUTES
  63 #undef SMSC_SUPPORT_MINUTES
  64 
  65 #define MAX_TIMEOUT     255
  66 
  67 #define UNIT_SECOND     0
  68 #define UNIT_MINUTE     1
  69 
  70 #define VERSION         "1.1"
  71 
  72 #define IOPORT          0x3F0
  73 #define IOPORT_SIZE     2
  74 #define IODEV_NO        8
  75 
  76 static int unit = UNIT_SECOND;  
  77 static int timeout = 60;        
  78 static unsigned long timer_enabled;   
  79 
  80 static char expect_close;       
  81 
  82 static DEFINE_SPINLOCK(io_lock);
  83 
  84 static bool nowayout = WATCHDOG_NOWAYOUT;
  85 
  86 
  87 
  88 
  89 
  90 static inline void open_io_config(void)
  91 {
  92         outb(0x55, IOPORT);
  93         mdelay(1);
  94         outb(0x55, IOPORT);
  95 }
  96 
  97 
  98 static inline void close_io_config(void)
  99 {
 100         outb(0xAA, IOPORT);
 101 }
 102 
 103 
 104 static inline void select_io_device(unsigned char devno)
 105 {
 106         outb(0x07, IOPORT);
 107         outb(devno, IOPORT+1);
 108 }
 109 
 110 
 111 static inline void write_io_cr(unsigned char reg, unsigned char data)
 112 {
 113         outb(reg, IOPORT);
 114         outb(data, IOPORT+1);
 115 }
 116 
 117 
 118 static inline char read_io_cr(unsigned char reg)
 119 {
 120         outb(reg, IOPORT);
 121         return inb(IOPORT+1);
 122 }
 123 
 124 
 125 
 126 static inline void gpio_bit12(unsigned char reg)
 127 {
 128         
 129 
 130 
 131 
 132 
 133 
 134 
 135 
 136 
 137         write_io_cr(0xE2, reg);
 138 }
 139 
 140 static inline void gpio_bit13(unsigned char reg)
 141 {
 142         
 143 
 144 
 145 
 146 
 147 
 148 
 149 
 150         write_io_cr(0xE3, reg);
 151 }
 152 
 153 static inline void wdt_timer_units(unsigned char new_units)
 154 {
 155         
 156 
 157 
 158 
 159 
 160         write_io_cr(0xF1, new_units);
 161 }
 162 
 163 static inline void wdt_timeout_value(unsigned char new_timeout)
 164 {
 165         
 166 
 167 
 168         write_io_cr(0xF2, new_timeout);
 169 }
 170 
 171 static inline void wdt_timer_conf(unsigned char conf)
 172 {
 173         
 174 
 175 
 176 
 177 
 178 
 179 
 180 
 181 
 182 
 183 
 184         write_io_cr(0xF3, conf);
 185 }
 186 
 187 static inline void wdt_timer_ctrl(unsigned char reg)
 188 {
 189         
 190 
 191 
 192 
 193 
 194 
 195 
 196 
 197 
 198 
 199 
 200 
 201 
 202 
 203 
 204 
 205 
 206         write_io_cr(0xF4, reg);
 207 }
 208 
 209 
 210 
 211 
 212 
 213 static void wb_smsc_wdt_initialize(void)
 214 {
 215         unsigned char old;
 216 
 217         spin_lock(&io_lock);
 218         open_io_config();
 219         select_io_device(IODEV_NO);
 220 
 221         
 222         gpio_bit13(0x08);  
 223         gpio_bit12(0x0A);  
 224 
 225         
 226         wdt_timeout_value(0);
 227 
 228         
 229         wdt_timer_ctrl(0x00);
 230 
 231         
 232         wdt_timer_conf(0x00);
 233 
 234         
 235         old = read_io_cr(0xF1) & 0x7F;
 236         if (unit == UNIT_SECOND)
 237                 old |= 0x80;    
 238 
 239         
 240         wdt_timer_units(old);
 241 
 242         close_io_config();
 243         spin_unlock(&io_lock);
 244 }
 245 
 246 
 247 
 248 static void wb_smsc_wdt_shutdown(void)
 249 {
 250         spin_lock(&io_lock);
 251         open_io_config();
 252         select_io_device(IODEV_NO);
 253 
 254         
 255         gpio_bit13(0x09);
 256         gpio_bit12(0x09);
 257 
 258         
 259         wdt_timer_conf(0x00);
 260 
 261         
 262         wdt_timer_ctrl(0x00);
 263 
 264         
 265         wdt_timeout_value(0x00);
 266 
 267         close_io_config();
 268         spin_unlock(&io_lock);
 269 }
 270 
 271 
 272 
 273 static void wb_smsc_wdt_set_timeout(unsigned char new_timeout)
 274 {
 275         spin_lock(&io_lock);
 276         open_io_config();
 277         select_io_device(IODEV_NO);
 278 
 279         
 280         wdt_timer_ctrl((new_timeout == 0) ? 0x00 : 0x02);
 281 
 282         
 283         wdt_timeout_value(new_timeout);
 284 
 285         close_io_config();
 286         spin_unlock(&io_lock);
 287 }
 288 
 289 
 290 
 291 static unsigned char wb_smsc_wdt_get_timeout(void)
 292 {
 293         unsigned char set_timeout;
 294 
 295         spin_lock(&io_lock);
 296         open_io_config();
 297         select_io_device(IODEV_NO);
 298         set_timeout = read_io_cr(0xF2);
 299         close_io_config();
 300         spin_unlock(&io_lock);
 301 
 302         return set_timeout;
 303 }
 304 
 305 
 306 
 307 static void wb_smsc_wdt_disable(void)
 308 {
 309         
 310         wb_smsc_wdt_set_timeout(0);
 311 }
 312 
 313 
 314 
 315 static void wb_smsc_wdt_enable(void)
 316 {
 317         
 318         wb_smsc_wdt_set_timeout(timeout);
 319 }
 320 
 321 
 322 
 323 static void wb_smsc_wdt_reset_timer(void)
 324 {
 325         spin_lock(&io_lock);
 326         open_io_config();
 327         select_io_device(IODEV_NO);
 328 
 329         
 330         wdt_timeout_value(timeout);
 331         wdt_timer_conf(0x08);
 332 
 333         close_io_config();
 334         spin_unlock(&io_lock);
 335 }
 336 
 337 
 338 
 339 static int wb_smsc_wdt_status(void)
 340 {
 341         return (wb_smsc_wdt_get_timeout() == 0) ? 0 : WDIOF_KEEPALIVEPING;
 342 }
 343 
 344 
 345 
 346 
 347 
 348 
 349 static int wb_smsc_wdt_open(struct inode *inode, struct file *file)
 350 {
 351         
 352 
 353         if (test_and_set_bit(0, &timer_enabled))
 354                 return -EBUSY;
 355 
 356         if (nowayout)
 357                 __module_get(THIS_MODULE);
 358 
 359         
 360         wb_smsc_wdt_enable();
 361 
 362         pr_info("Watchdog enabled. Timeout set to %d %s\n",
 363                 timeout, (unit == UNIT_SECOND) ? "second(s)" : "minute(s)");
 364 
 365         return stream_open(inode, file);
 366 }
 367 
 368 
 369 
 370 static int wb_smsc_wdt_release(struct inode *inode, struct file *file)
 371 {
 372         
 373 
 374         if (expect_close == 42) {
 375                 wb_smsc_wdt_disable();
 376                 pr_info("Watchdog disabled, sleeping again...\n");
 377         } else {
 378                 pr_crit("Unexpected close, not stopping watchdog!\n");
 379                 wb_smsc_wdt_reset_timer();
 380         }
 381 
 382         clear_bit(0, &timer_enabled);
 383         expect_close = 0;
 384         return 0;
 385 }
 386 
 387 
 388 
 389 static ssize_t wb_smsc_wdt_write(struct file *file, const char __user *data,
 390                                  size_t len, loff_t *ppos)
 391 {
 392         
 393         if (len) {
 394                 if (!nowayout) {
 395                         size_t i;
 396 
 397                         
 398                         expect_close = 0;
 399 
 400                         
 401 
 402                         for (i = 0; i != len; i++) {
 403                                 char c;
 404                                 if (get_user(c, data + i))
 405                                         return -EFAULT;
 406                                 if (c == 'V')
 407                                         expect_close = 42;
 408                         }
 409                 }
 410 
 411                 
 412                 wb_smsc_wdt_reset_timer();
 413         }
 414         return len;
 415 }
 416 
 417 
 418 
 419 static long wb_smsc_wdt_ioctl(struct file *file,
 420                                         unsigned int cmd, unsigned long arg)
 421 {
 422         int new_timeout;
 423 
 424         union {
 425                 struct watchdog_info __user *ident;
 426                 int __user *i;
 427         } uarg;
 428 
 429         static const struct watchdog_info ident = {
 430                 .options =              WDIOF_KEEPALIVEPING |
 431                                         WDIOF_SETTIMEOUT |
 432                                         WDIOF_MAGICCLOSE,
 433                 .firmware_version =     0,
 434                 .identity =             "SMsC 37B787 Watchdog",
 435         };
 436 
 437         uarg.i = (int __user *)arg;
 438 
 439         switch (cmd) {
 440         case WDIOC_GETSUPPORT:
 441                 return copy_to_user(uarg.ident, &ident, sizeof(ident))
 442                                                                 ? -EFAULT : 0;
 443         case WDIOC_GETSTATUS:
 444                 return put_user(wb_smsc_wdt_status(), uarg.i);
 445         case WDIOC_GETBOOTSTATUS:
 446                 return put_user(0, uarg.i);
 447         case WDIOC_SETOPTIONS:
 448         {
 449                 int options, retval = -EINVAL;
 450 
 451                 if (get_user(options, uarg.i))
 452                         return -EFAULT;
 453 
 454                 if (options & WDIOS_DISABLECARD) {
 455                         wb_smsc_wdt_disable();
 456                         retval = 0;
 457                 }
 458                 if (options & WDIOS_ENABLECARD) {
 459                         wb_smsc_wdt_enable();
 460                         retval = 0;
 461                 }
 462                 return retval;
 463         }
 464         case WDIOC_KEEPALIVE:
 465                 wb_smsc_wdt_reset_timer();
 466                 return 0;
 467         case WDIOC_SETTIMEOUT:
 468                 if (get_user(new_timeout, uarg.i))
 469                         return -EFAULT;
 470                 
 471                 if (unit == UNIT_MINUTE)
 472                         new_timeout /= 60;
 473                 if (new_timeout < 0 || new_timeout > MAX_TIMEOUT)
 474                         return -EINVAL;
 475                 timeout = new_timeout;
 476                 wb_smsc_wdt_set_timeout(timeout);
 477                 
 478         case WDIOC_GETTIMEOUT:
 479                 new_timeout = timeout;
 480                 if (unit == UNIT_MINUTE)
 481                         new_timeout *= 60;
 482                 return put_user(new_timeout, uarg.i);
 483         default:
 484                 return -ENOTTY;
 485         }
 486 }
 487 
 488 
 489 
 490 static int wb_smsc_wdt_notify_sys(struct notifier_block *this,
 491                                         unsigned long code, void *unused)
 492 {
 493         if (code == SYS_DOWN || code == SYS_HALT) {
 494                 
 495                 timeout = 0;
 496                 wb_smsc_wdt_disable();
 497         }
 498         return NOTIFY_DONE;
 499 }
 500 
 501 
 502 
 503 static const struct file_operations wb_smsc_wdt_fops = {
 504         .owner    = THIS_MODULE,
 505         .llseek         = no_llseek,
 506         .write          = wb_smsc_wdt_write,
 507         .unlocked_ioctl = wb_smsc_wdt_ioctl,
 508         .open           = wb_smsc_wdt_open,
 509         .release        = wb_smsc_wdt_release,
 510 };
 511 
 512 static struct notifier_block wb_smsc_wdt_notifier = {
 513         .notifier_call  = wb_smsc_wdt_notify_sys,
 514 };
 515 
 516 static struct miscdevice wb_smsc_wdt_miscdev = {
 517         .minor          = WATCHDOG_MINOR,
 518         .name           = "watchdog",
 519         .fops           = &wb_smsc_wdt_fops,
 520 };
 521 
 522 
 523 
 524 
 525 
 526 static int __init wb_smsc_wdt_init(void)
 527 {
 528         int ret;
 529 
 530         pr_info("SMsC 37B787 watchdog component driver "
 531                 VERSION " initialising...\n");
 532 
 533         if (!request_region(IOPORT, IOPORT_SIZE, "SMsC 37B787 watchdog")) {
 534                 pr_err("Unable to register IO port %#x\n", IOPORT);
 535                 ret = -EBUSY;
 536                 goto out_pnp;
 537         }
 538 
 539         
 540         if (timeout > MAX_TIMEOUT)
 541                 timeout = MAX_TIMEOUT;
 542 
 543         
 544         wb_smsc_wdt_initialize();
 545 
 546         ret = register_reboot_notifier(&wb_smsc_wdt_notifier);
 547         if (ret) {
 548                 pr_err("Unable to register reboot notifier err = %d\n", ret);
 549                 goto out_io;
 550         }
 551 
 552         ret = misc_register(&wb_smsc_wdt_miscdev);
 553         if (ret) {
 554                 pr_err("Unable to register miscdev on minor %d\n",
 555                        WATCHDOG_MINOR);
 556                 goto out_rbt;
 557         }
 558 
 559         
 560         pr_info("Timeout set to %d %s\n",
 561                 timeout, (unit == UNIT_SECOND) ? "second(s)" : "minute(s)");
 562         pr_info("Watchdog initialized and sleeping (nowayout=%d)...\n",
 563                 nowayout);
 564 out_clean:
 565         return ret;
 566 
 567 out_rbt:
 568         unregister_reboot_notifier(&wb_smsc_wdt_notifier);
 569 
 570 out_io:
 571         release_region(IOPORT, IOPORT_SIZE);
 572 
 573 out_pnp:
 574         goto out_clean;
 575 }
 576 
 577 
 578 
 579 static void __exit wb_smsc_wdt_exit(void)
 580 {
 581         
 582         if (!nowayout) {
 583                 wb_smsc_wdt_shutdown();
 584                 pr_info("Watchdog disabled\n");
 585         }
 586 
 587         misc_deregister(&wb_smsc_wdt_miscdev);
 588         unregister_reboot_notifier(&wb_smsc_wdt_notifier);
 589         release_region(IOPORT, IOPORT_SIZE);
 590 
 591         pr_info("SMsC 37B787 watchdog component driver removed\n");
 592 }
 593 
 594 module_init(wb_smsc_wdt_init);
 595 module_exit(wb_smsc_wdt_exit);
 596 
 597 MODULE_AUTHOR("Sven Anders <anders@anduras.de>");
 598 MODULE_DESCRIPTION("Driver for SMsC 37B787 watchdog component (Version "
 599                                                                 VERSION ")");
 600 MODULE_LICENSE("GPL");
 601 
 602 #ifdef SMSC_SUPPORT_MINUTES
 603 module_param(unit, int, 0);
 604 MODULE_PARM_DESC(unit,
 605                 "set unit to use, 0=seconds or 1=minutes, default is 0");
 606 #endif
 607 
 608 module_param(timeout, int, 0);
 609 MODULE_PARM_DESC(timeout, "range is 1-255 units, default is 60");
 610 
 611 module_param(nowayout, bool, 0);
 612 MODULE_PARM_DESC(nowayout,
 613                 "Watchdog cannot be stopped once started (default="
 614                                 __MODULE_STRING(WATCHDOG_NOWAYOUT) ")");