static void pcwd_isa_shutdown(struct device *dev, unsigned int id) { if (debug >= DEBUG) pr_debug("pcwd_isa_shutdown id=%d\n", id); pcwd_stop(); }
static int __devexit pcwd_isa_remove(struct device *dev, unsigned int id) { if (debug >= DEBUG) printk(KERN_DEBUG PFX "pcwd_isa_remove id=%d\n", id); if (!pcwd_private.io_addr) return 1; /* Disable the board */ if (!nowayout) pcwd_stop(); /* Deregister */ misc_deregister(&pcwd_miscdev); if (pcwd_private.supports_temp) misc_deregister(&temp_miscdev); release_region(pcwd_private.io_addr, (pcwd_private.revision == PCWD_REVISION_A) ? 2 : 4); pcwd_private.io_addr = 0x0000; cards_found--; return 0; }
static int __devinit pcwd_isa_probe(struct device *dev, unsigned int id) { int ret; if (debug >= DEBUG) printk(KERN_DEBUG PFX "pcwd_isa_probe id=%d\n", id); cards_found++; if (cards_found == 1) printk(KERN_INFO PFX "v%s Ken Hollis ([email protected])\n", WATCHDOG_VERSION); if (cards_found > 1) { printk(KERN_ERR PFX "This driver only supports 1 device\n"); return -ENODEV; } if (pcwd_ioports[id] == 0x0000) { printk(KERN_ERR PFX "No I/O-Address for card detected\n"); return -ENODEV; } pcwd_private.io_addr = pcwd_ioports[id]; spin_lock_init(&pcwd_private.io_lock); /* Check card's revision */ pcwd_private.revision = get_revision(); if (!request_region(pcwd_private.io_addr, (pcwd_private.revision == PCWD_REVISION_A) ? 2 : 4, "PCWD")) { printk(KERN_ERR PFX "I/O address 0x%04x already in use\n", pcwd_private.io_addr); ret = -EIO; goto error_request_region; } /* Initial variables */ pcwd_private.supports_temp = 0; temp_panic = 0; pcwd_private.boot_status = 0x0000; /* get the boot_status */ pcwd_get_status(&pcwd_private.boot_status); /* clear the "card caused reboot" flag */ pcwd_clear_status(); setup_timer(&pcwd_private.timer, pcwd_timer_ping, 0); /* Disable the board */ pcwd_stop(); /* Check whether or not the card supports the temperature device */ pcwd_check_temperature_support(); /* Show info about the card itself */ pcwd_show_card_info(); /* If heartbeat = 0 then we use the heartbeat from the dip-switches */ if (heartbeat == 0) heartbeat = heartbeat_tbl[(pcwd_get_option_switches() & 0x07)]; /* Check that the heartbeat value is within it's range; if not reset to the default */ if (pcwd_set_heartbeat(heartbeat)) { pcwd_set_heartbeat(WATCHDOG_HEARTBEAT); printk(KERN_INFO PFX "heartbeat value must be 2 <= heartbeat <= 7200, using %d\n", WATCHDOG_HEARTBEAT); } if (pcwd_private.supports_temp) { ret = misc_register(&temp_miscdev); if (ret) { printk(KERN_ERR PFX "cannot register miscdev on minor=%d (err=%d)\n", TEMP_MINOR, ret); goto error_misc_register_temp; } } ret = misc_register(&pcwd_miscdev); if (ret) { printk(KERN_ERR PFX "cannot register miscdev on minor=%d (err=%d)\n", WATCHDOG_MINOR, ret); goto error_misc_register_watchdog; } printk(KERN_INFO PFX "initialized. heartbeat=%d sec (nowayout=%d)\n", heartbeat, nowayout); return 0; error_misc_register_watchdog: if (pcwd_private.supports_temp) misc_deregister(&temp_miscdev); error_misc_register_temp: release_region(pcwd_private.io_addr, (pcwd_private.revision == PCWD_REVISION_A) ? 2 : 4); error_request_region: pcwd_private.io_addr = 0x0000; cards_found--; return ret; }
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; }