📄 pcwd_pci.c
字号:
/* * /dev/watchdog handling */static ssize_t pcipcwd_write(struct file *file, const char __user *data, size_t len, loff_t *ppos){ /* See if we got the magic character 'V' and reload the timer */ if (len) { if (!nowayout) { size_t i; /* note: just in case someone wrote the magic character * five months ago... */ expect_release = 0; /* scan to see whether or not we got the magic character */ for (i = 0; i != len; i++) { char c; if(get_user(c, data+i)) return -EFAULT; if (c == 'V') expect_release = 42; } } /* someone wrote to us, we should reload the timer */ pcipcwd_keepalive(); } return len;}static int pcipcwd_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg){ void __user *argp = (void __user *)arg; int __user *p = argp; static struct watchdog_info ident = { .options = WDIOF_OVERHEAT | WDIOF_CARDRESET | WDIOF_KEEPALIVEPING | WDIOF_SETTIMEOUT | WDIOF_MAGICCLOSE, .firmware_version = 1, .identity = WATCHDOG_DRIVER_NAME, }; switch (cmd) { case WDIOC_GETSUPPORT: return copy_to_user(argp, &ident, sizeof (ident)) ? -EFAULT : 0; case WDIOC_GETSTATUS: { int status; pcipcwd_get_status(&status); return put_user(status, p); } case WDIOC_GETBOOTSTATUS: return put_user(pcipcwd_private.boot_status, p); case WDIOC_GETTEMP: { int temperature; if (pcipcwd_get_temperature(&temperature)) return -EFAULT; return put_user(temperature, p); } case WDIOC_KEEPALIVE: pcipcwd_keepalive(); return 0; case WDIOC_SETOPTIONS: { int new_options, retval = -EINVAL; if (get_user (new_options, p)) return -EFAULT; if (new_options & WDIOS_DISABLECARD) { if (pcipcwd_stop()) return -EIO; retval = 0; } if (new_options & WDIOS_ENABLECARD) { if (pcipcwd_start()) return -EIO; retval = 0; } if (new_options & WDIOS_TEMPPANIC) { temp_panic = 1; retval = 0; } return retval; } case WDIOC_SETTIMEOUT: { int new_heartbeat; if (get_user(new_heartbeat, p)) return -EFAULT; if (pcipcwd_set_heartbeat(new_heartbeat)) return -EINVAL; pcipcwd_keepalive(); /* Fall */ } case WDIOC_GETTIMEOUT: return put_user(heartbeat, p); default: return -ENOIOCTLCMD; }}static int pcipcwd_open(struct inode *inode, struct file *file){ /* /dev/watchdog can only be opened once */ if (test_and_set_bit(0, &is_active)) { if (debug >= VERBOSE) printk(KERN_ERR PFX "Attempt to open already opened device.\n"); return -EBUSY; } /* Activate */ pcipcwd_start(); pcipcwd_keepalive(); return nonseekable_open(inode, file);}static int pcipcwd_release(struct inode *inode, struct file *file){ /* * Shut off the timer. */ if (expect_release == 42) { pcipcwd_stop(); } else { printk(KERN_CRIT PFX "Unexpected close, not stopping watchdog!\n"); pcipcwd_keepalive(); } expect_release = 0; clear_bit(0, &is_active); return 0;}/* * /dev/temperature handling */static ssize_t pcipcwd_temp_read(struct file *file, char __user *data, size_t len, loff_t *ppos){ int temperature; if (pcipcwd_get_temperature(&temperature)) return -EFAULT; if (copy_to_user (data, &temperature, 1)) return -EFAULT; return 1;}static int pcipcwd_temp_open(struct inode *inode, struct file *file){ if (!pcipcwd_private.supports_temp) return -ENODEV; return nonseekable_open(inode, file);}static int pcipcwd_temp_release(struct inode *inode, struct file *file){ return 0;}/* * Notify system */static int pcipcwd_notify_sys(struct notifier_block *this, unsigned long code, void *unused){ if (code==SYS_DOWN || code==SYS_HALT) { /* Turn the WDT off */ pcipcwd_stop(); } return NOTIFY_DONE;}/* * Kernel Interfaces */static struct file_operations pcipcwd_fops = { .owner = THIS_MODULE, .llseek = no_llseek, .write = pcipcwd_write, .ioctl = pcipcwd_ioctl, .open = pcipcwd_open, .release = pcipcwd_release,};static struct miscdevice pcipcwd_miscdev = { .minor = WATCHDOG_MINOR, .name = "watchdog", .fops = &pcipcwd_fops,};static struct file_operations pcipcwd_temp_fops = { .owner = THIS_MODULE, .llseek = no_llseek, .read = pcipcwd_temp_read, .open = pcipcwd_temp_open, .release = pcipcwd_temp_release,};static struct miscdevice pcipcwd_temp_miscdev = { .minor = TEMP_MINOR, .name = "temperature", .fops = &pcipcwd_temp_fops,};static struct notifier_block pcipcwd_notifier = { .notifier_call = pcipcwd_notify_sys,};/* * Init & exit routines */static int __devinit pcipcwd_card_init(struct pci_dev *pdev, const struct pci_device_id *ent){ int ret = -EIO; cards_found++; if (cards_found == 1) printk(KERN_INFO PFX DRIVER_VERSION); if (cards_found > 1) { printk(KERN_ERR PFX "This driver only supports 1 device\n"); return -ENODEV; } if (pci_enable_device(pdev)) { printk(KERN_ERR PFX "Not possible to enable PCI Device\n"); return -ENODEV; } if (pci_resource_start(pdev, 0) == 0x0000) { printk(KERN_ERR PFX "No I/O-Address for card detected\n"); ret = -ENODEV; goto err_out_disable_device; } pcipcwd_private.pdev = pdev; pcipcwd_private.io_addr = pci_resource_start(pdev, 0); if (pci_request_regions(pdev, WATCHDOG_NAME)) { printk(KERN_ERR PFX "I/O address 0x%04x already in use\n", (int) pcipcwd_private.io_addr); ret = -EIO; goto err_out_disable_device; } /* get the boot_status */ pcipcwd_get_status(&pcipcwd_private.boot_status); /* clear the "card caused reboot" flag */ pcipcwd_clear_status(); /* disable card */ pcipcwd_stop(); /* Check whether or not the card supports the temperature device */ pcipcwd_check_temperature_support(); /* Show info about the card itself */ pcipcwd_show_card_info(); /* Check that the heartbeat value is within it's range ; if not reset to the default */ if (pcipcwd_set_heartbeat(heartbeat)) { pcipcwd_set_heartbeat(WATCHDOG_HEARTBEAT); printk(KERN_INFO PFX "heartbeat value must be 0<heartbeat<65536, using %d\n", WATCHDOG_HEARTBEAT); } ret = register_reboot_notifier(&pcipcwd_notifier); if (ret != 0) { printk(KERN_ERR PFX "cannot register reboot notifier (err=%d)\n", ret); goto err_out_release_region; } if (pcipcwd_private.supports_temp) { ret = misc_register(&pcipcwd_temp_miscdev); if (ret != 0) { printk(KERN_ERR PFX "cannot register miscdev on minor=%d (err=%d)\n", TEMP_MINOR, ret); goto err_out_unregister_reboot; } } ret = misc_register(&pcipcwd_miscdev); if (ret != 0) { printk(KERN_ERR PFX "cannot register miscdev on minor=%d (err=%d)\n", WATCHDOG_MINOR, ret); goto err_out_misc_deregister; } printk(KERN_INFO PFX "initialized. heartbeat=%d sec (nowayout=%d)\n", heartbeat, nowayout); return 0;err_out_misc_deregister: if (pcipcwd_private.supports_temp) misc_deregister(&pcipcwd_temp_miscdev);err_out_unregister_reboot: unregister_reboot_notifier(&pcipcwd_notifier);err_out_release_region: pci_release_regions(pdev);err_out_disable_device: pci_disable_device(pdev); return ret;}static void __devexit pcipcwd_card_exit(struct pci_dev *pdev){ /* Stop the timer before we leave */ if (!nowayout) pcipcwd_stop(); /* Deregister */ misc_deregister(&pcipcwd_miscdev); if (pcipcwd_private.supports_temp) misc_deregister(&pcipcwd_temp_miscdev); unregister_reboot_notifier(&pcipcwd_notifier); pci_release_regions(pdev); pci_disable_device(pdev); cards_found--;}static struct pci_device_id pcipcwd_pci_tbl[] = { { PCI_VENDOR_ID_QUICKLOGIC, PCI_DEVICE_ID_WATCHDOG_PCIPCWD, PCI_ANY_ID, PCI_ANY_ID, }, { 0 }, /* End of list */};MODULE_DEVICE_TABLE(pci, pcipcwd_pci_tbl);static struct pci_driver pcipcwd_driver = { .name = WATCHDOG_NAME, .id_table = pcipcwd_pci_tbl, .probe = pcipcwd_card_init, .remove = __devexit_p(pcipcwd_card_exit),};static int __init pcipcwd_init_module(void){ spin_lock_init(&pcipcwd_private.io_lock); return pci_register_driver(&pcipcwd_driver);}static void __exit pcipcwd_cleanup_module(void){ pci_unregister_driver(&pcipcwd_driver);}module_init(pcipcwd_init_module);module_exit(pcipcwd_cleanup_module);MODULE_AUTHOR("Wim Van Sebroeck <wim@iguana.be>");MODULE_DESCRIPTION("Berkshire PCI-PC Watchdog driver");MODULE_LICENSE("GPL");MODULE_ALIAS_MISCDEV(WATCHDOG_MINOR);MODULE_ALIAS_MISCDEV(TEMP_MINOR);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -