static long pcwd_ioctl(struct file *file, unsigned int cmd, unsigned long arg) { int rv; int status; int temperature; int new_heartbeat; int __user *argp = (int __user *)arg; static const struct watchdog_info ident = { .options = WDIOF_OVERHEAT | WDIOF_CARDRESET | WDIOF_KEEPALIVEPING | WDIOF_SETTIMEOUT | WDIOF_MAGICCLOSE, .firmware_version = 1, .identity = "PCWD", }; switch (cmd) { case WDIOC_GETSUPPORT: if (copy_to_user(argp, &ident, sizeof(ident))) return -EFAULT; return 0; case WDIOC_GETSTATUS: pcwd_get_status(&status); return put_user(status, argp); case WDIOC_GETBOOTSTATUS: return put_user(pcwd_private.boot_status, argp); case WDIOC_GETTEMP: if (pcwd_get_temperature(&temperature)) return -EFAULT; return put_user(temperature, argp); case WDIOC_SETOPTIONS: if (pcwd_private.revision == PCWD_REVISION_C) { if (get_user(rv, argp)) return -EFAULT; if (rv & WDIOS_DISABLECARD) { status = pcwd_stop(); if (status < 0) return status; } if (rv & WDIOS_ENABLECARD) { status = pcwd_start(); if (status < 0) return status; } if (rv & WDIOS_TEMPPANIC) temp_panic = 1; } return -EINVAL; case WDIOC_KEEPALIVE: pcwd_keepalive(); return 0; case WDIOC_SETTIMEOUT: if (get_user(new_heartbeat, argp)) return -EFAULT; if (pcwd_set_heartbeat(new_heartbeat)) return -EINVAL; pcwd_keepalive(); /* Fall */ case WDIOC_GETTIMEOUT: return put_user(heartbeat, argp); default: return -ENOTTY; } return 0; } static ssize_t pcwd_write(struct file *file, const char __user *buf, size_t len, loff_t *ppos) { if (len) { if (!nowayout) { size_t i; /* In case it was set long ago */ expect_close = 0; for (i = 0; i != len; i++) { char c; if (get_user(c, buf + i)) return -EFAULT; if (c == 'V') expect_close = 42; } } pcwd_keepalive(); } return len; } static int pcwd_open(struct inode *inode, struct file *file) { if (test_and_set_bit(0, &open_allowed)) return -EBUSY; if (nowayout) __module_get(THIS_MODULE); /* Activate */ pcwd_start(); pcwd_keepalive(); return nonseekable_open(inode, file); } static int pcwd_close(struct inode *inode, struct file *file) { if (expect_close == 42) pcwd_stop(); else { printk(KERN_CRIT PFX "Unexpected close, not stopping watchdog!\n"); pcwd_keepalive(); } expect_close = 0; clear_bit(0, &open_allowed); return 0; } /* * /dev/temperature handling */ static ssize_t pcwd_temp_read(struct file *file, char __user *buf, size_t count, loff_t *ppos) { int temperature; if (pcwd_get_temperature(&temperature)) return -EFAULT; if (copy_to_user(buf, &temperature, 1)) return -EFAULT; return 1; }
static int pcwd_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg) { int rv; int status; int temperature; int new_heartbeat; static struct watchdog_info ident = { .options = WDIOF_OVERHEAT | WDIOF_CARDRESET | WDIOF_KEEPALIVEPING | WDIOF_SETTIMEOUT | WDIOF_MAGICCLOSE, .firmware_version = 1, .identity = "PCWD", }; switch(cmd) { default: return -ENOIOCTLCMD; case WDIOC_GETSUPPORT: if(copy_to_user((void*)arg, &ident, sizeof(ident))) return -EFAULT; return 0; case WDIOC_GETSTATUS: pcwd_get_status(&status); return put_user(status, (int *) arg); case WDIOC_GETBOOTSTATUS: return put_user(initial_status, (int *) arg); case WDIOC_GETTEMP: if (pcwd_get_temperature(&temperature)) return -EFAULT; return put_user(temperature, (int *) arg); case WDIOC_SETOPTIONS: if (revision == PCWD_REVISION_C) { if(copy_from_user(&rv, (int*) arg, sizeof(int))) return -EFAULT; if (rv & WDIOS_DISABLECARD) { return pcwd_stop(); } if (rv & WDIOS_ENABLECARD) { return pcwd_start(); } if (rv & WDIOS_TEMPPANIC) { temp_panic = 1; } } return -EINVAL; case WDIOC_KEEPALIVE: pcwd_keepalive(); return 0; case WDIOC_SETTIMEOUT: if (get_user(new_heartbeat, (int *) arg)) return -EFAULT; if (pcwd_set_heartbeat(new_heartbeat)) return -EINVAL; pcwd_keepalive(); /* Fall */ case WDIOC_GETTIMEOUT: return put_user(heartbeat, (int *)arg); } return 0; } static ssize_t pcwd_write(struct file *file, const char *buf, size_t len, loff_t *ppos) { /* Can't seek (pwrite) on this device */ if (ppos != &file->f_pos) return -ESPIPE; if (len) { if (!nowayout) { size_t i; /* In case it was set long ago */ expect_close = 0; for (i = 0; i != len; i++) { char c; if (get_user(c, buf + i)) return -EFAULT; if (c == 'V') expect_close = 42; } } pcwd_keepalive(); } return len; } static int pcwd_open(struct inode *inode, struct file *file) { if (!atomic_dec_and_test(&open_allowed) ) { atomic_inc( &open_allowed ); return -EBUSY; } if (nowayout) __module_get(THIS_MODULE); /* Activate */ pcwd_start(); pcwd_keepalive(); return(0); } static int pcwd_close(struct inode *inode, struct file *file) { if (expect_close == 42) { pcwd_stop(); atomic_inc( &open_allowed ); } else { printk(KERN_CRIT PFX "Unexpected close, not stopping watchdog!\n"); pcwd_keepalive(); } expect_close = 0; return 0; } /* * /dev/temperature handling */ static ssize_t pcwd_temp_read(struct file *file, char *buf, size_t count, loff_t *ppos) { int temperature; /* Can't seek (pread) on this device */ if (ppos != &file->f_pos) return -ESPIPE; if (pcwd_get_temperature(&temperature)) return -EFAULT; if (copy_to_user(buf, &temperature, 1)) return -EFAULT; return 1; }