static ssize_t ibwdt_write(struct file *file, const char __user *buf, size_t count, loff_t *ppos) { if (count) { if (!nowayout) { size_t i; /* In case it was set long ago */ expect_close = 0; for (i = 0; i != count; i++) { char c; if (get_user(c, buf + i)) return -EFAULT; if (c == 'V') expect_close = 42; } } ibwdt_ping(); } return count; }
static long ibwdt_ioctl(struct file *file, unsigned int cmd, unsigned long arg) { int new_margin; void __user *argp = (void __user *)arg; int __user *p = argp; static const struct watchdog_info ident = { .options = WDIOF_KEEPALIVEPING | WDIOF_SETTIMEOUT | WDIOF_MAGICCLOSE, .firmware_version = 1, .identity = "IB700 WDT", }; switch (cmd) { case WDIOC_GETSUPPORT: if (copy_to_user(argp, &ident, sizeof(ident))) return -EFAULT; break; case WDIOC_GETSTATUS: case WDIOC_GETBOOTSTATUS: return put_user(0, p); case WDIOC_SETOPTIONS: { int options, retval = -EINVAL; if (get_user(options, p)) return -EFAULT; if (options & WDIOS_DISABLECARD) { ibwdt_disable(); retval = 0; } if (options & WDIOS_ENABLECARD) { ibwdt_ping(); retval = 0; } return retval; } case WDIOC_KEEPALIVE: ibwdt_ping(); break; case WDIOC_SETTIMEOUT: if (get_user(new_margin, p)) return -EFAULT; if (ibwdt_set_heartbeat(new_margin)) return -EINVAL; ibwdt_ping(); /* Fall */ case WDIOC_GETTIMEOUT: return put_user(timeout, p); default: return -ENOTTY; } return 0; } static int ibwdt_open(struct inode *inode, struct file *file) { if (test_and_set_bit(0, &ibwdt_is_open)) return -EBUSY; if (nowayout) __module_get(THIS_MODULE); /* Activate */ ibwdt_ping(); return nonseekable_open(inode, file); } static int ibwdt_close(struct inode *inode, struct file *file) { if (expect_close == 42) { ibwdt_disable(); } else { pr_crit("WDT device closed unexpectedly. WDT will not stop!\n"); ibwdt_ping(); } clear_bit(0, &ibwdt_is_open); expect_close = 0; return 0; } /* * Kernel Interfaces */ static const struct file_operations ibwdt_fops = { .owner = THIS_MODULE, .llseek = no_llseek, .write = ibwdt_write, .unlocked_ioctl = ibwdt_ioctl, .open = ibwdt_open, .release = ibwdt_close, }; static struct miscdevice ibwdt_miscdev = { .minor = WATCHDOG_MINOR, .name = "watchdog", .fops = &ibwdt_fops, }; /* * Init & exit routines */ static int ibwdt_probe(struct platform_device *dev) { int res; #if WDT_START != WDT_STOP if (!request_region(WDT_STOP, 1, "IB700 WDT")) { pr_err("STOP method I/O %X is not available\n", WDT_STOP); res = -EIO; goto out_nostopreg; } #endif if (!request_region(WDT_START, 1, "IB700 WDT")) { pr_err("START method I/O %X is not available\n", WDT_START); res = -EIO; goto out_nostartreg; } /* Check that the heartbeat value is within it's range ; * if not reset to the default */ if (ibwdt_set_heartbeat(timeout)) { ibwdt_set_heartbeat(WATCHDOG_TIMEOUT); pr_info("timeout value must be 0<=x<=30, using %d\n", timeout); } res = misc_register(&ibwdt_miscdev); if (res) { pr_err("failed to register misc device\n"); goto out_nomisc; } return 0; out_nomisc: release_region(WDT_START, 1); out_nostartreg: #if WDT_START != WDT_STOP release_region(WDT_STOP, 1); #endif out_nostopreg: return res; } static int ibwdt_remove(struct platform_device *dev) { misc_deregister(&ibwdt_miscdev); release_region(WDT_START, 1); #if WDT_START != WDT_STOP release_region(WDT_STOP, 1); #endif return 0; }
static int ibwdt_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg) { int i, new_margin; void __user *argp = (void __user *)arg; int __user *p = argp; static struct watchdog_info ident = { .options = WDIOF_KEEPALIVEPING | WDIOF_SETTIMEOUT | WDIOF_MAGICCLOSE, .firmware_version = 1, .identity = "IB700 WDT", }; switch (cmd) { case WDIOC_GETSUPPORT: if (copy_to_user(argp, &ident, sizeof(ident))) return -EFAULT; break; case WDIOC_GETSTATUS: return put_user(0, p); case WDIOC_KEEPALIVE: ibwdt_ping(); break; case WDIOC_SETTIMEOUT: if (get_user(new_margin, p)) return -EFAULT; if ((new_margin < 0) || (new_margin > 30)) return -EINVAL; for (i = 0x0F; i > -1; i--) if (wd_times[i] > new_margin) break; wd_margin = i; ibwdt_ping(); /* Fall */ case WDIOC_GETTIMEOUT: return put_user(wd_times[wd_margin], p); break; default: return -ENOIOCTLCMD; } return 0; } static int ibwdt_open(struct inode *inode, struct file *file) { spin_lock(&ibwdt_lock); if (test_and_set_bit(0, &ibwdt_is_open)) { spin_unlock(&ibwdt_lock); return -EBUSY; } if (nowayout) __module_get(THIS_MODULE); /* Activate */ ibwdt_ping(); spin_unlock(&ibwdt_lock); return nonseekable_open(inode, file); }