📄 pcwd.c
字号:
static voidpcwd_get_fw_string(void){ if (revision == PCWD_PCI) { int firmware_revision; firmware_revision = send_command_ret16(0x08, 0, 0); pcwd_fw_rev_major = firmware_revision / 256; pcwd_fw_rev_minor = firmware_revision % 256; sprintf(pcwd_fw_string, "%u.%02u", pcwd_fw_rev_major, pcwd_fw_rev_minor); } else { if (pcwd_set_diag() == ENABLED) { int one, ten, hund, minor; one = send_diag_command(0x81); ten = send_diag_command(0x82); hund = send_diag_command(0x83); minor = send_diag_command(0x84); sprintf(pcwd_fw_string, "%c.%c%c%c", one, ten, hund, minor); } else { sprintf(pcwd_fw_string, "ERROR"); } }}static voidpcwd_show_card_stats(void){ switch (revision) { case PCWD_REVISION_A: printk(KERN_INFO "pcwd: PC Watchdog Card at 0x%x: REV.A %s temp option.\n", (int) card_ioport, (supports_temp ? "with" : "without")); break; case PCWD_REVISION_C: printk(KERN_INFO "pcwd: PC Watchdog Card at 0x%x: REV.C (Firmware: %s) %s temp option.\n", (int) card_ioport, pcwd_fw_string, (supports_temp ? "with" : "without")); break; case PCWD_PCI: printk(KERN_INFO "pcwd: PCI PC Watchdog Card at 0x%x: (Firmware: %s) %s temp option.\n", (int) card_ioport, pcwd_fw_string, (supports_temp ? "with" : "without")); break; default: printk(KERN_ERR "pcwd: Unknown or unsupported card or revision.\n"); } pcwd_get_trip_status(); if (initial_status & 0x01) printk(KERN_INFO "pcwd: Previous reset was caused by the Watchdog card.\n"); if (initial_status & 0x04) printk(KERN_INFO "pcwd: Card sensed a CPU Overheat.\n"); if (!(initial_status & 0x01)) printk(KERN_INFO "pcwd: No previous trip detected - Cold boot or reset.\n");}static voidpcwd_ping(void){ if (revision == PCWD_PCI) { spin_lock(&pcwd_io_lock); outb_p(0xfc, card_ioport); /* send out any data */ spin_unlock(&pcwd_io_lock); } else { int wdrst_stat; spin_lock(&pcwd_io_lock); wdrst_stat = inb_p(card_ioport); wdrst_stat &= 0x0F; wdrst_stat |= 0x01; /* Previously reset state */ if (revision == PCWD_REVISION_A) outb_p(wdrst_stat, card_ioport + 1); else outb_p(wdrst_stat, card_ioport); spin_unlock(&pcwd_io_lock); } if (card_status == ENABLED) ping_counter++;}/* The file operation functions for user access to /dev/watchdog */static intpcwd_open(struct inode *inode, struct file *file){ switch (MINOR(inode->i_rdev)) { case WATCHDOG_MINOR: spin_lock(&pcwd_lock); if (in_use) { spin_unlock(&pcwd_lock); printk(KERN_ERR "pcwd: Attempt to open already opened device.\n"); return -EBUSY; } MOD_INC_USE_COUNT; in_use++; spin_unlock(&pcwd_lock); return 0; case TEMP_MINOR: MOD_INC_USE_COUNT; return 0; default: return -ENODEV; }}static intpcwd_release(struct inode *inode, struct file *file){ lock_kernel(); MOD_DEC_USE_COUNT; if (MINOR(inode->i_rdev) == WATCHDOG_MINOR) { spin_lock(&pcwd_lock); if (!nowayout) pcwd_disable_card(); in_use--; spin_unlock(&pcwd_lock); } unlock_kernel(); return 0;}/*static long longpcwd_llseek(struct file *file, long long offset, int origin){ return -ESPIPE;}*/static ssize_tpcwd_read(struct file *file, char *buf, size_t len, loff_t * ppos){ unsigned short temp; temp = pcwd_get_temperature(); /* Can't seek (pread) on this device */ if (ppos != &file->f_pos) return -ESPIPE; switch (MINOR(file->f_dentry->d_inode->i_rdev)) { case TEMP_MINOR: case WATCHDOG_MINOR: if (copy_to_user(buf, &temp, 1)) return -EFAULT; return 0; default: return -EINVAL; }}static ssize_tpcwd_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) { pcwd_ping(); return 1; } return 0;}static intpcwd_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg){ int rv; int retval; static struct watchdog_info ident = { WDIOF_OVERHEAT | WDIOF_CARDRESET, 1, "PCWD" }; switch (cmd) { case WDIOC_GETSUPPORT: rv = copy_to_user((void *) arg, &ident, sizeof (ident)); return rv ? -EFAULT : 0; case WDIOC_GETSTATUS: if (initial_status & WDIOF_OVERHEAT) { if (pcwd_temp_panic == ENABLED) panic("pcwd: Temperature overheat trip!\n"); } if (put_user(initial_status, (int *) arg)) return -EFAULT; return 0; case WDIOC_GETBOOTSTATUS: if (put_user(initial_status, (int *) arg)) return -EFAULT; return 0; case WDIOC_GETTEMP: rv = 0; if (supports_temp) rv = pcwd_get_temperature(); if (put_user(rv, (int *) arg)) return -EFAULT; return 0; case WDIOC_SETOPTIONS: if (copy_from_user(&rv, (int *) arg, sizeof (int))) return -EFAULT; retval = -EINVAL; if (rv & WDIOS_DISABLECARD) { if (!pcwd_disable_card()) return -EIO; retval = 0; } if (rv & WDIOS_ENABLECARD) { if (!pcwd_enable_card()) return -EIO; retval = 0; } if (rv & WDIOS_TEMPPANIC) { pcwd_temp_panic = ENABLED; retval = 0; } return retval; case WDIOC_KEEPALIVE: pcwd_ping(); return 0; default: return -ENOTTY; }}#ifdef CONFIG_PROC_FSstatic intpcwd_set_relay(char *sub_command){ char *new_sub_command = sub_command; int i; while (*sub_command == ' ') sub_command++; if (sub_command == new_sub_command) { printk("relay value: %d\n", send_command_ret8(0x50, 0, 0)); return 0; } i = send_command_ret8(0x50, 0, 0); // read the relays if (strcmp(sub_command, "1on") == 0) { i = send_command_ret8(0x51, 0, (i | 1) & (0xff - 4)); if (pcwd_verbose >= VERBOSE) printk(KERN_INFO "pcwd: relay 1on\n"); } else if (strcmp(sub_command, "1off") == 0) { i = send_command_ret8(0x51, 0, (i | 4) & (0xff - 1)); if (pcwd_verbose >= VERBOSE) printk(KERN_INFO "pcwd: relay 1off\n"); } else if (strcmp(sub_command, "2on") == 0) { i = send_command_ret8(0x51, 0, (i | 2) & (0xff - 8)); if (pcwd_verbose >= VERBOSE) printk(KERN_INFO "pcwd: relay 2on\n"); } else if (strcmp(sub_command, "2off") == 0) { i = send_command_ret8(0x51, 0, (i | 8) & (0xff - 2)); if (pcwd_verbose >= VERBOSE) printk(KERN_INFO "pcwd: relay 2off\n"); } else if (strcmp(sub_command, "1invert") == 0) { if (pcwd_verbose >= DEBUG) { printk(KERN_DEBUG "pcwd: before: 0x%02x\n", i); printk(KERN_DEBUG "pcwd: sending: 0x%02x\n", i | 0x10); } i = send_command_ret8(0x51, 0, i | 0x10); if (pcwd_verbose >= DEBUG) { i = send_command_ret8(0x50, 0, 0); // read the relays printk(KERN_DEBUG "pcwd: after: 0x%02x\n", i); } if (pcwd_verbose >= VERBOSE) printk(KERN_INFO "pcwd: relay 1invert\n"); } else if (strcmp(sub_command, "1noinvert") == 0) { if (pcwd_verbose >= DEBUG) { printk(KERN_DEBUG "pcwd: before: 0x%02x\n", i); printk(KERN_DEBUG "pcwd: sending: 0x%02x\n", i & (0xff - 0x10)); } i = send_command_ret8(0x51, 0, i & (0xff - 0x10)); if (pcwd_verbose >= DEBUG) { i = send_command_ret8(0x50, 0, 0); // read the relays printk(KERN_DEBUG "pcwd: after: 0x%2x\n", i); } if (pcwd_verbose >= VERBOSE) printk(KERN_INFO "pcwd: relay 1noinvert\n"); } else if (strcmp(sub_command, "1nvinvert") == 0) { if (pcwd_verbose >= DEBUG) { printk(KERN_DEBUG "pcwd: before: 0x%02x\n", i); printk(KERN_DEBUG "pcwd: sending: 0x%02x\n", i | 0x80); } i = send_command_ret8(0x51, 0, i | 0x80); if (pcwd_verbose >= DEBUG) { i = send_command_ret8(0x50, 0, 0); // read the relays printk(KERN_DEBUG "pcwd: after: 0x%02x\n", i); } if (pcwd_verbose >= VERBOSE) printk(KERN_INFO "pcwd: relay 1nvinvert\n"); } else if (strcmp(sub_command, "1nvnoinvert") == 0) { if (pcwd_verbose >= DEBUG) { printk(KERN_DEBUG "pcwd: before: 0x%02x\n", i); printk(KERN_DEBUG "pcwd: sending: 0x%02x\n", i & (0xff - 0x80)); } i = send_command_ret8(0x51, 0, i & (0xff - 0x80)); if (pcwd_verbose >= DEBUG) { i = send_command_ret8(0x50, 0, 0); // read the relays printk(KERN_DEBUG "pcwd: after: 0x%02x\n", i); } if (pcwd_verbose >= VERBOSE) printk(KERN_INFO "pcwd: relay 1nvnoinvert\n"); } else if (strcmp(sub_command, "2notemp") == 0) { outb_p(0x40, card_ioport + 1); if (pcwd_verbose >= VERBOSE) printk(KERN_INFO "pcwd: relay 2notemp\n"); pcwd_get_relay2_mode(); } else if (strcmp(sub_command, "2temp") == 0) { outb_p(0x00, card_ioport + 1); if (pcwd_verbose >= VERBOSE) printk(KERN_INFO "pcwd: relay 2temp\n"); pcwd_get_relay2_mode(); } else { printk(KERN_ERR "pcwd: illegal relay argument '%s', should be 1on, 1off, 2on, 2off, 1invert, 1noinvert, 1nvinvert, 1nvnoinvert, 2temp or 2notemp\n", sub_command); return 1; } return 0;}static intpcwd_set_dio(char *sub_command){ char *new_sub_command = sub_command; int i; while (*sub_command == ' ') sub_command++; if (sub_command == new_sub_command) { printk("dio value: %d\n", (inb(card_ioport + 7) / 16) & 15); return 0; } i = simple_strtoul(sub_command, NULL, 0); if ((i >= 0) && (i < 16)) { outb_p(i, card_ioport + 7); if (pcwd_verbose >= VERBOSE) printk(KERN_INFO "pcwd: dio %d\n", i); } else { printk(KERN_ERR "pcwd: illegal dio argument '%s', should be a number between 0 and 15\n", sub_command); return 1; } return 0;}static intpcwd_set_nv_timeout_pci(char *sub_command){ char *new_sub_command = sub_command; int i; while (*sub_command == ' ') sub_command++; if (sub_command == new_sub_command) { printk("nvtimeout value: %d\n", send_command_ret16(0x1C, 0, 0)); return 0; } i = simple_strtoul(sub_command, NULL, 0); if (i == 0) printk("returning to default DIP switch settings.\n"); if ((i >= 0) && (i <= 0xffff)) { send_command(0x1D, i / 256, i % 256); if (pcwd_verbose >= VERBOSE) printk(KERN_INFO "pcwd: nvtimeout %d\n", i); } else { printk(KERN_ERR "pcwd: illegal nvtimeout argument '%s', should be a number between 0 and 65535\n", sub_command); return 1; } return 0;}static intpcwd_set_timeout_pci(char *sub_command){ char *new_sub_command = sub_command; int i; while (*sub_command == ' ') sub_command++; if (sub_command == new_sub_command) { printk("timeout value: %d\n", send_command_ret16(0x18, 0, 0)); return 0; } i = simple_strtoul(sub_command, NULL, 0); if ((i >= 0) && (i <= 0xffff)) { send_command(0x19, i / 256, i % 256); if (pcwd_verbose >= VERBOSE) printk(KERN_INFO "pcwd: timeout %d\n", i); } else { printk(KERN_ERR "pcwd: illegal timeout argument '%s', should be a number between 0 and 65535\n", sub_command); return 1; } return 0;}static intpcwd_set_timeout(char *sub_command){ char *new_sub_command = sub_command; while (*sub_command == ' ') sub_command++; if (sub_command == new_sub_command) { printk(KERN_ERR "pcwd: illegal timeout argument '%s', should be 2, 4 or 8\n", sub_command); return 1; } /* FIXME: show new timeouts also in proc */ if (strcmp(sub_command, "2") == 0) { if (send_diag_command(0x8A) == 0x8A) { if (pcwd_verbose >= VERBOSE) printk(KERN_INFO "pcwd: timeout 2s\n"); return 0; } } else if (strcmp(sub_command, "4") == 0) { if (send_diag_command(0x8B) == 0x8b) { if (pcwd_verbose >= VERBOSE) printk(KERN_INFO "pcwd: timeout 4s\n"); return 0; } } else if (strcmp(sub_command, "8") == 0) { if (send_diag_command(0x8C) == 0x8C) { if (pcwd_verbose >= VERBOSE) printk(KERN_INFO "pcwd: timeout 8s\n"); return 0; } } else { printk(KERN_ERR "pcwd: illegal timeout argument '%s', should be 2, 4 or 8\n", sub_command); return 1; } return 0;}static intpcwd_set_nv_arm_pci(char *sub_command){ char *new_sub_command = sub_command; int i; while (*sub_command == ' ') sub_command++; if (sub_command == new_sub_command) { printk("nvarm value: %d\n", send_command_ret16(0x14, 0, 0)); return 0; } i = simple_strtoul(sub_command, NULL, 0); if ((i >= 0) && (i <= 0xffff)) { send_command(0x15, i / 256, i % 256); if (pcwd_verbose >= VERBOSE) printk(KERN_INFO "pcwd: nvarm %d\n", i); } else { printk(KERN_ERR "pcwd: illegal nvarm argument '%s', should be a number between 0 and 65535\n", sub_command); return 1; } return 0;}static intpcwd_set_arm_pci(char *sub_command){ char *new_sub_command = sub_command; int i; while (*sub_command == ' ') sub_command++; if (sub_command == new_sub_command) { printk("arm value: %d\n", send_command_ret16(0x10, 0, 0)); return 0; } i = simple_strtoul(sub_command, NULL, 0); if ((i >= 0) && (i <= 0xffff)) { if (send_command_ret8(0x11, i / 256, i % 256) == 0) { printk(KERN_INFO "pcwd: arm failed, board already armed!\n"); return 1; } if (pcwd_verbose >= VERBOSE) printk(KERN_INFO "pcwd: arm %d\n", i); } else { printk(KERN_ERR "pcwd: illegal arm argument '%s', should be a number between 0 and 65535\n", sub_command); return 1; } return 0;}static intpcwd_set_arm(char *sub_command){ char *new_sub_command = sub_command; int i = 0; while (*sub_command == ' ') sub_command++; if (sub_command == new_sub_command) { printk(KERN_ERR "pcwd: illegal arm argument '%s', should be 0, 30 or 60\n", sub_command); return 1; } pcwd_set_diag(); if ((strcmp(sub_command, "0") == 0) || (strcmp(sub_command, "immediately") == 0)) { if ((i = send_diag_command(0x87)) == 0x87) { if (pcwd_verbose >= VERBOSE) printk(KERN_INFO "pcwd: arm immediately\n"); return 0; } } else if (strcmp(sub_command, "30") == 0) { if ((i = send_diag_command(0x88)) == 0x88) { if (pcwd_verbose >= VERBOSE) printk(KERN_INFO "pcwd: arm after 30s more\n"); return 0; } } else if (strcmp(sub_command, "60") == 0) { if ((i = send_diag_command(0x89)) != 0x89) { if (pcwd_verbose >= VERBOSE) printk(KERN_INFO "pcwd: arm after 60s more\n"); return 0; } } else { printk(KERN_ERR "pcwd: illegal arm argument '%s', should be 0, 30 or 60\n", sub_command); return 1; } if (i == 0xF5) printk(KERN_INFO "pcwd: already armed\n"); return 0;}static intpcwd_set_tempoffset_pci(char *sub_command){ char *new_sub_command = sub_command; int i; while (*sub_command == ' ') sub_command++; if (sub_command == new_sub_command) { printk("tempoffset value: %d\n", (inb(card_ioport + 2) & 15)); return 0; } i = simple_strtoul(sub_command, NULL, 0); if ((i >= 0) && (i < 16)) { outb_p(i, card_ioport + 2); if (pcwd_verbose >= VERBOSE) printk(KERN_INFO "pcwd: tempoffset %d\n", i); } else { printk(KERN_ERR "pcwd: illegal tempoffset argument '%s', should be a number between 0 and 15\n", sub_command); return 1; } return 0;}static voidpcwd_user_help(void)
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -