This source file includes following definitions.
- ibwdt_ping
 
- ibwdt_disable
 
- ibwdt_set_heartbeat
 
- ibwdt_write
 
- ibwdt_ioctl
 
- ibwdt_open
 
- ibwdt_close
 
- ibwdt_probe
 
- ibwdt_remove
 
- ibwdt_shutdown
 
- ibwdt_init
 
- ibwdt_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 #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
  31 
  32 #include <linux/module.h>
  33 #include <linux/types.h>
  34 #include <linux/miscdevice.h>
  35 #include <linux/watchdog.h>
  36 #include <linux/ioport.h>
  37 #include <linux/fs.h>
  38 #include <linux/init.h>
  39 #include <linux/spinlock.h>
  40 #include <linux/moduleparam.h>
  41 #include <linux/platform_device.h>
  42 #include <linux/io.h>
  43 #include <linux/uaccess.h>
  44 
  45 
  46 static struct platform_device *ibwdt_platform_device;
  47 static unsigned long ibwdt_is_open;
  48 static DEFINE_SPINLOCK(ibwdt_lock);
  49 static char expect_close;
  50 
  51 
  52 #define DRV_NAME "ib700wdt"
  53 
  54 
  55 
  56 
  57 
  58 
  59 
  60 
  61 
  62 
  63 
  64 
  65 
  66 
  67 
  68 
  69 
  70 
  71 
  72 
  73 
  74 
  75 
  76 
  77 
  78 
  79 
  80 
  81 
  82 
  83 
  84 
  85 
  86 
  87 
  88 
  89 
  90 #define WDT_STOP 0x441
  91 #define WDT_START 0x443
  92 
  93 
  94 #define WATCHDOG_TIMEOUT 30             
  95 static int timeout = WATCHDOG_TIMEOUT;  
  96 module_param(timeout, int, 0);
  97 MODULE_PARM_DESC(timeout,
  98         "Watchdog timeout in seconds. 0<= timeout <=30, default="
  99                 __MODULE_STRING(WATCHDOG_TIMEOUT) ".");
 100 
 101 static bool nowayout = WATCHDOG_NOWAYOUT;
 102 module_param(nowayout, bool, 0);
 103 MODULE_PARM_DESC(nowayout,
 104                 "Watchdog cannot be stopped once started (default="
 105                                 __MODULE_STRING(WATCHDOG_NOWAYOUT) ")");
 106 
 107 
 108 
 109 
 110 
 111 
 112 static void ibwdt_ping(void)
 113 {
 114         int wd_margin = 15 - ((timeout + 1) / 2);
 115 
 116         spin_lock(&ibwdt_lock);
 117 
 118         
 119         outb_p(wd_margin, WDT_START);
 120 
 121         spin_unlock(&ibwdt_lock);
 122 }
 123 
 124 static void ibwdt_disable(void)
 125 {
 126         spin_lock(&ibwdt_lock);
 127         outb_p(0, WDT_STOP);
 128         spin_unlock(&ibwdt_lock);
 129 }
 130 
 131 static int ibwdt_set_heartbeat(int t)
 132 {
 133         if (t < 0 || t > 30)
 134                 return -EINVAL;
 135 
 136         timeout = t;
 137         return 0;
 138 }
 139 
 140 
 141 
 142 
 143 
 144 static ssize_t ibwdt_write(struct file *file, const char __user *buf,
 145                                                 size_t count, loff_t *ppos)
 146 {
 147         if (count) {
 148                 if (!nowayout) {
 149                         size_t i;
 150 
 151                         
 152                         expect_close = 0;
 153 
 154                         for (i = 0; i != count; i++) {
 155                                 char c;
 156                                 if (get_user(c, buf + i))
 157                                         return -EFAULT;
 158                                 if (c == 'V')
 159                                         expect_close = 42;
 160                         }
 161                 }
 162                 ibwdt_ping();
 163         }
 164         return count;
 165 }
 166 
 167 static long ibwdt_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
 168 {
 169         int new_margin;
 170         void __user *argp = (void __user *)arg;
 171         int __user *p = argp;
 172 
 173         static const struct watchdog_info ident = {
 174                 .options = WDIOF_KEEPALIVEPING | WDIOF_SETTIMEOUT
 175                                                         | WDIOF_MAGICCLOSE,
 176                 .firmware_version = 1,
 177                 .identity = "IB700 WDT",
 178         };
 179 
 180         switch (cmd) {
 181         case WDIOC_GETSUPPORT:
 182                 if (copy_to_user(argp, &ident, sizeof(ident)))
 183                         return -EFAULT;
 184                 break;
 185 
 186         case WDIOC_GETSTATUS:
 187         case WDIOC_GETBOOTSTATUS:
 188                 return put_user(0, p);
 189 
 190         case WDIOC_SETOPTIONS:
 191         {
 192                 int options, retval = -EINVAL;
 193 
 194                 if (get_user(options, p))
 195                         return -EFAULT;
 196 
 197                 if (options & WDIOS_DISABLECARD) {
 198                         ibwdt_disable();
 199                         retval = 0;
 200                 }
 201                 if (options & WDIOS_ENABLECARD) {
 202                         ibwdt_ping();
 203                         retval = 0;
 204                 }
 205                 return retval;
 206         }
 207         case WDIOC_KEEPALIVE:
 208                 ibwdt_ping();
 209                 break;
 210 
 211         case WDIOC_SETTIMEOUT:
 212                 if (get_user(new_margin, p))
 213                         return -EFAULT;
 214                 if (ibwdt_set_heartbeat(new_margin))
 215                         return -EINVAL;
 216                 ibwdt_ping();
 217                 
 218 
 219         case WDIOC_GETTIMEOUT:
 220                 return put_user(timeout, p);
 221 
 222         default:
 223                 return -ENOTTY;
 224         }
 225         return 0;
 226 }
 227 
 228 static int ibwdt_open(struct inode *inode, struct file *file)
 229 {
 230         if (test_and_set_bit(0, &ibwdt_is_open))
 231                 return -EBUSY;
 232         if (nowayout)
 233                 __module_get(THIS_MODULE);
 234 
 235         
 236         ibwdt_ping();
 237         return stream_open(inode, file);
 238 }
 239 
 240 static int ibwdt_close(struct inode *inode, struct file *file)
 241 {
 242         if (expect_close == 42) {
 243                 ibwdt_disable();
 244         } else {
 245                 pr_crit("WDT device closed unexpectedly.  WDT will not stop!\n");
 246                 ibwdt_ping();
 247         }
 248         clear_bit(0, &ibwdt_is_open);
 249         expect_close = 0;
 250         return 0;
 251 }
 252 
 253 
 254 
 255 
 256 
 257 static const struct file_operations ibwdt_fops = {
 258         .owner          = THIS_MODULE,
 259         .llseek         = no_llseek,
 260         .write          = ibwdt_write,
 261         .unlocked_ioctl = ibwdt_ioctl,
 262         .open           = ibwdt_open,
 263         .release        = ibwdt_close,
 264 };
 265 
 266 static struct miscdevice ibwdt_miscdev = {
 267         .minor = WATCHDOG_MINOR,
 268         .name = "watchdog",
 269         .fops = &ibwdt_fops,
 270 };
 271 
 272 
 273 
 274 
 275 
 276 static int __init ibwdt_probe(struct platform_device *dev)
 277 {
 278         int res;
 279 
 280 #if WDT_START != WDT_STOP
 281         if (!request_region(WDT_STOP, 1, "IB700 WDT")) {
 282                 pr_err("STOP method I/O %X is not available\n", WDT_STOP);
 283                 res = -EIO;
 284                 goto out_nostopreg;
 285         }
 286 #endif
 287 
 288         if (!request_region(WDT_START, 1, "IB700 WDT")) {
 289                 pr_err("START method I/O %X is not available\n", WDT_START);
 290                 res = -EIO;
 291                 goto out_nostartreg;
 292         }
 293 
 294         
 295 
 296         if (ibwdt_set_heartbeat(timeout)) {
 297                 ibwdt_set_heartbeat(WATCHDOG_TIMEOUT);
 298                 pr_info("timeout value must be 0<=x<=30, using %d\n", timeout);
 299         }
 300 
 301         res = misc_register(&ibwdt_miscdev);
 302         if (res) {
 303                 pr_err("failed to register misc device\n");
 304                 goto out_nomisc;
 305         }
 306         return 0;
 307 
 308 out_nomisc:
 309         release_region(WDT_START, 1);
 310 out_nostartreg:
 311 #if WDT_START != WDT_STOP
 312         release_region(WDT_STOP, 1);
 313 #endif
 314 out_nostopreg:
 315         return res;
 316 }
 317 
 318 static int ibwdt_remove(struct platform_device *dev)
 319 {
 320         misc_deregister(&ibwdt_miscdev);
 321         release_region(WDT_START, 1);
 322 #if WDT_START != WDT_STOP
 323         release_region(WDT_STOP, 1);
 324 #endif
 325         return 0;
 326 }
 327 
 328 static void ibwdt_shutdown(struct platform_device *dev)
 329 {
 330         
 331         ibwdt_disable();
 332 }
 333 
 334 static struct platform_driver ibwdt_driver = {
 335         .remove         = ibwdt_remove,
 336         .shutdown       = ibwdt_shutdown,
 337         .driver         = {
 338                 .name   = DRV_NAME,
 339         },
 340 };
 341 
 342 static int __init ibwdt_init(void)
 343 {
 344         int err;
 345 
 346         pr_info("WDT driver for IB700 single board computer initialising\n");
 347 
 348         ibwdt_platform_device = platform_device_register_simple(DRV_NAME,
 349                                                                 -1, NULL, 0);
 350         if (IS_ERR(ibwdt_platform_device))
 351                 return PTR_ERR(ibwdt_platform_device);
 352 
 353         err = platform_driver_probe(&ibwdt_driver, ibwdt_probe);
 354         if (err)
 355                 goto unreg_platform_device;
 356 
 357         return 0;
 358 
 359 unreg_platform_device:
 360         platform_device_unregister(ibwdt_platform_device);
 361         return err;
 362 }
 363 
 364 static void __exit ibwdt_exit(void)
 365 {
 366         platform_device_unregister(ibwdt_platform_device);
 367         platform_driver_unregister(&ibwdt_driver);
 368         pr_info("Watchdog Module Unloaded\n");
 369 }
 370 
 371 module_init(ibwdt_init);
 372 module_exit(ibwdt_exit);
 373 
 374 MODULE_AUTHOR("Charles Howes <chowes@vsol.net>");
 375 MODULE_DESCRIPTION("IB700 SBC watchdog driver");
 376 MODULE_LICENSE("GPL");
 377 
 378