static int wdtpci_start(void) { unsigned long flags; spin_lock_irqsave(&wdtpci_lock, flags); /* * "pet" the watchdog, as Access says. * This resets the clock outputs. */ inb_p(WDT_DC); /* Disable watchdog */ wdtpci_ctr_mode(2,0); /* Program CTR2 for Mode 0: Pulse on Terminal Count */ outb_p(0, WDT_DC); /* Enable watchdog */ inb_p(WDT_DC); /* Disable watchdog */ outb_p(0, WDT_CLOCK); /* 2.0833MHz clock */ inb_p(WDT_BUZZER); /* disable */ inb_p(WDT_OPTONOTRST); /* disable */ inb_p(WDT_OPTORST); /* disable */ inb_p(WDT_PROGOUT); /* disable */ wdtpci_ctr_mode(0,3); /* Program CTR0 for Mode 3: Square Wave Generator */ wdtpci_ctr_mode(1,2); /* Program CTR1 for Mode 2: Rate Generator */ wdtpci_ctr_mode(2,1); /* Program CTR2 for Mode 1: Retriggerable One-Shot */ wdtpci_ctr_load(0,20833); /* count at 100Hz */ wdtpci_ctr_load(1,wd_heartbeat);/* Heartbeat */ /* DO NOT LOAD CTR2 on PCI card! -- JPN */ outb_p(0, WDT_DC); /* Enable watchdog */ spin_unlock_irqrestore(&wdtpci_lock, flags); return 0; }
static int wdtpci_stop (void) { unsigned long flags; /* Turn the card off */ spin_lock_irqsave(&wdtpci_lock, flags); inb_p(WDT_DC); /* Disable watchdog */ wdtpci_ctr_load(2,0); /* 0 length reset pulses now */ spin_unlock_irqrestore(&wdtpci_lock, flags); return 0; }
static void wdtpci_ping(void) { unsigned long flags; /* Write a watchdog value */ spin_lock_irqsave(&wdtpci_lock, flags); inb_p(WDT_DC); wdtpci_ctr_mode(1,2); wdtpci_ctr_load(1,wd_margin); /* Timeout */ outb_p(0, WDT_DC); spin_unlock_irqrestore(&wdtpci_lock, flags); }
static int wdtpci_ping(void) { unsigned long flags; /* Write a watchdog value */ spin_lock_irqsave(&wdtpci_lock, flags); inb_p(WDT_DC); /* Disable watchdog */ wdtpci_ctr_mode(1,2); /* Re-Program CTR1 for Mode 2: Rate Generator */ wdtpci_ctr_load(1,wd_heartbeat);/* Heartbeat */ outb_p(0, WDT_DC); /* Enable watchdog */ spin_unlock_irqrestore(&wdtpci_lock, flags); return 0; }
static int wdtpci_release(struct inode *inode, struct file *file) { if (iminor(inode)==WATCHDOG_MINOR) { unsigned long flags; if (expect_close) { spin_lock_irqsave(&wdtpci_lock, flags); inb_p(WDT_DC); /* Disable counters */ wdtpci_ctr_load(2,0); /* 0 length reset pulses now */ spin_unlock_irqrestore(&wdtpci_lock, flags); } else { printk(KERN_CRIT PFX "Unexpected close, not stopping timer!"); wdtpci_ping(); } up(&open_sem); } return 0; }
static int wdtpci_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg) { int new_margin; static struct watchdog_info ident = { .options = WDIOF_OVERHEAT | WDIOF_POWERUNDER | WDIOF_POWEROVER | WDIOF_EXTERN1 | WDIOF_EXTERN2 | WDIOF_FANFAULT | WDIOF_SETTIMEOUT|WDIOF_MAGICCLOSE, .firmware_version = 1, .identity = "WDT500/501PCI", }; ident.options&=WDT_OPTION_MASK; /* Mask down to the card we have */ switch(cmd) { default: return -ENOTTY; case WDIOC_GETSUPPORT: return copy_to_user((struct watchdog_info *)arg, &ident, sizeof(ident))?-EFAULT:0; case WDIOC_GETSTATUS: return put_user(wdtpci_status(),(int *)arg); case WDIOC_GETBOOTSTATUS: return put_user(0, (int *)arg); case WDIOC_KEEPALIVE: wdtpci_ping(); return 0; case WDIOC_SETTIMEOUT: if (get_user(new_margin, (int *)arg)) return -EFAULT; /* Arbitrary, can't find the card's limits */ new_margin *= 100; if ((new_margin < 0) || (new_margin > WD_TIMO_MAX)) return -EINVAL; wd_margin = new_margin; wdtpci_ping(); /* Fall */ case WDIOC_GETTIMEOUT: return put_user(wd_margin / 100, (int *)arg); } } /** * wdtpci_open: * @inode: inode of device * @file: file handle to device * * One of our two misc devices has been opened. The watchdog device is * single open and on opening we load the counters. Counter zero is a * 100Hz cascade, into counter 1 which downcounts to reboot. When the * counter triggers counter 2 downcounts the length of the reset pulse * which set set to be as long as possible. */ static int wdtpci_open(struct inode *inode, struct file *file) { unsigned long flags; switch(iminor(inode)) { case WATCHDOG_MINOR: if (down_trylock(&open_sem)) return -EBUSY; if (nowayout) { __module_get(THIS_MODULE); } /* * Activate */ spin_lock_irqsave(&wdtpci_lock, flags); inb_p(WDT_DC); /* Disable */ /* * "pet" the watchdog, as Access says. * This resets the clock outputs. */ wdtpci_ctr_mode(2,0); outb_p(0, WDT_DC); inb_p(WDT_DC); outb_p(0, WDT_CLOCK); /* 2.0833MHz clock */ inb_p(WDT_BUZZER); /* disable */ inb_p(WDT_OPTONOTRST); /* disable */ inb_p(WDT_OPTORST); /* disable */ inb_p(WDT_PROGOUT); /* disable */ wdtpci_ctr_mode(0,3); wdtpci_ctr_mode(1,2); wdtpci_ctr_mode(2,1); wdtpci_ctr_load(0,20833); /* count at 100Hz */ wdtpci_ctr_load(1,wd_margin);/* Timeout 60 seconds */ /* DO NOT LOAD CTR2 on PCI card! -- JPN */ outb_p(0, WDT_DC); /* Enable */ spin_unlock_irqrestore(&wdtpci_lock, flags); return 0; case TEMP_MINOR: return 0; default: return -ENODEV; } }