···73#include <asm/io.h> /* For inb/outb/... */7475/* Module and version information */76-#define WD_VER "1.16 (06/12/2004)"77#define PFX "pcwd: "7879/*···133/* internal variables */134static atomic_t open_allowed = ATOMIC_INIT(1);135static char expect_close;136-static struct timer_list timer;137-static unsigned long next_heartbeat;138static int temp_panic;139-static int revision; /* The card's revision */140-static int supports_temp; /* Wether or not the card has a temperature device */141-static int command_mode; /* Wether or not the card is in command mode */142-static int initial_status; /* The card's boot status */143-static int current_readport; /* The cards I/O address */144-static spinlock_t io_lock;0000145146/* module parameters */147#define WATCHDOG_HEARTBEAT 60 /* 60 sec default heartbeat */···167168 /* The WCMD bit must be 1 and the command is only 4 bits in size */169 control_status = (cmd & 0x0F) | 0x80;170- outb_p(control_status, current_readport + 2);171 udelay(ISA_COMMAND_TIMEOUT);172173- port0 = inb_p(current_readport);174 for (i = 0; i < 25; ++i) {175 last_port0 = port0;176- port0 = inb_p(current_readport);177178 if (port0 == last_port0)179 break; /* Data is stable */···189 int i, found=0, count=0;190191 /* Set the card into command mode */192- spin_lock(&io_lock);193 while ((!found) && (count < 3)) {194 i = send_isa_command(CMD_ISA_IDLE);195···197 found = 1;198 else if (i == 0xF3) {199 /* Card does not like what we've done to it */200- outb_p(0x00, current_readport + 2);201 udelay(1200); /* Spec says wait 1ms */202- outb_p(0x00, current_readport + 2);203 udelay(ISA_COMMAND_TIMEOUT);204 }205 count++;206 }207- spin_unlock(&io_lock);208- command_mode = found;209210 return(found);211}···213static void unset_command_mode(void)214{215 /* Set the card into normal mode */216- spin_lock(&io_lock);217- outb_p(0x00, current_readport + 2);218 udelay(ISA_COMMAND_TIMEOUT);219- spin_unlock(&io_lock);220221- command_mode = 0;222}223224static void pcwd_timer_ping(unsigned long data)···227228 /* If we got a heartbeat pulse within the WDT_INTERVAL229 * we agree to ping the WDT */230- if(time_before(jiffies, next_heartbeat)) {231 /* Ping the watchdog */232- spin_lock(&io_lock);233- if (revision == PCWD_REVISION_A) {234 /* Rev A cards are reset by setting the WD_WDRST bit in register 1 */235- wdrst_stat = inb_p(current_readport);236 wdrst_stat &= 0x0F;237 wdrst_stat |= WD_WDRST;238239- outb_p(wdrst_stat, current_readport + 1);240 } else {241 /* Re-trigger watchdog by writing to port 0 */242- outb_p(0x00, current_readport);243 }244245 /* Re-set the timer interval */246- mod_timer(&timer, jiffies + WDT_INTERVAL);247248- spin_unlock(&io_lock);249 } else {250 printk(KERN_WARNING PFX "Heartbeat lost! Will not ping the watchdog\n");251 }···255{256 int stat_reg;257258- next_heartbeat = jiffies + (heartbeat * HZ);259260 /* Start the timer */261- mod_timer(&timer, jiffies + WDT_INTERVAL);262263 /* Enable the port */264- if (revision == PCWD_REVISION_C) {265- spin_lock(&io_lock);266- outb_p(0x00, current_readport + 3);267 udelay(ISA_COMMAND_TIMEOUT);268- stat_reg = inb_p(current_readport + 2);269- spin_unlock(&io_lock);270 if (stat_reg & 0x10) {271 printk(KERN_INFO PFX "Could not start watchdog\n");272 return -EIO;···280 int stat_reg;281282 /* Stop the timer */283- del_timer(&timer);284285 /* Disable the board */286- if (revision == PCWD_REVISION_C) {287- spin_lock(&io_lock);288- outb_p(0xA5, current_readport + 3);289 udelay(ISA_COMMAND_TIMEOUT);290- outb_p(0xA5, current_readport + 3);291 udelay(ISA_COMMAND_TIMEOUT);292- stat_reg = inb_p(current_readport + 2);293- spin_unlock(&io_lock);294 if ((stat_reg & 0x10) == 0) {295 printk(KERN_INFO PFX "Could not stop watchdog\n");296 return -EIO;···302static int pcwd_keepalive(void)303{304 /* user land ping */305- next_heartbeat = jiffies + (heartbeat * HZ);306 return 0;307}308···320 int card_status;321322 *status=0;323- spin_lock(&io_lock);324- if (revision == PCWD_REVISION_A)325 /* Rev A cards return status information from326 * the base register, which is used for the327 * temperature in other cards. */328- card_status = inb(current_readport);329 else {330 /* Rev C cards return card status in the base331 * address + 1 register. And use different bits332 * to indicate a card initiated reset, and an333 * over-temperature condition. And the reboot334 * status can be reset. */335- card_status = inb(current_readport + 1);336 }337- spin_unlock(&io_lock);338339- if (revision == PCWD_REVISION_A) {340 if (card_status & WD_WDRST)341 *status |= WDIOF_CARDRESET;342···365366static int pcwd_clear_status(void)367{368- if (revision == PCWD_REVISION_C) {369- spin_lock(&io_lock);370- outb_p(0x00, current_readport + 1); /* clear reset status */371- spin_unlock(&io_lock);372 }373 return 0;374}···376static int pcwd_get_temperature(int *temperature)377{378 /* check that port 0 gives temperature info and no command results */379- if (command_mode)380 return -1;381382 *temperature = 0;383- if (!supports_temp)384 return -ENODEV;385386 /*387 * Convert celsius to fahrenheit, since this was388 * the decided 'standard' for this return value.389 */390- spin_lock(&io_lock);391- *temperature = ((inb(current_readport)) * 9 / 5) + 32;392- spin_unlock(&io_lock);393394 return 0;395}···430 return put_user(status, argp);431432 case WDIOC_GETBOOTSTATUS:433- return put_user(initial_status, argp);434435 case WDIOC_GETTEMP:436 if (pcwd_get_temperature(&temperature))···439 return put_user(temperature, argp);440441 case WDIOC_SETOPTIONS:442- if (revision == PCWD_REVISION_C)443 {444 if(copy_from_user(&rv, argp, sizeof(int)))445 return -EFAULT;···555556static int pcwd_temp_open(struct inode *inode, struct file *file)557{558- if (!supports_temp)559 return -ENODEV;560561 return nonseekable_open(inode, file);···623624static inline void get_support(void)625{626- if (inb(current_readport) != 0xF0)627- supports_temp = 1;628}629630static inline int get_revision(void)631{632 int r = PCWD_REVISION_C;633634- spin_lock(&io_lock);635 /* REV A cards use only 2 io ports; test636 * presumes a floating bus reads as 0xff. */637- if ((inb(current_readport + 2) == 0xFF) ||638- (inb(current_readport + 3) == 0xFF))639 r=PCWD_REVISION_A;640- spin_unlock(&io_lock);641642 return r;643}···697 printk(KERN_ERR PFX "No I/O-Address for card detected\n");698 return -ENODEV;699 }700- current_readport = base_addr;701702 /* Check card's revision */703- revision = get_revision();704705- if (!request_region(current_readport, (revision == PCWD_REVISION_A) ? 2 : 4, "PCWD")) {706 printk(KERN_ERR PFX "I/O address 0x%04x already in use\n",707- current_readport);708- current_readport = 0x0000;709 return -EIO;710 }711712 /* Initial variables */713- supports_temp = 0;714 temp_panic = 0;715- initial_status = 0x0000;716717 /* get the boot_status */718- pcwd_get_status(&initial_status);719720 /* clear the "card caused reboot" flag */721 pcwd_clear_status();722723- init_timer(&timer);724- timer.function = pcwd_timer_ping;725- timer.data = 0;726727 /* Disable the board */728 pcwd_stop();···731 get_support();732733 /* Get some extra info from the hardware (in command/debug/diag mode) */734- if (revision == PCWD_REVISION_A)735- printk(KERN_INFO PFX "ISA-PC Watchdog (REV.A) detected at port 0x%04x\n", current_readport);736- else if (revision == PCWD_REVISION_C) {737 firmware = get_firmware();738 printk(KERN_INFO PFX "ISA-PC Watchdog (REV.C) detected at port 0x%04x (Firmware version: %s)\n",739- current_readport, firmware);740 kfree(firmware);741 option_switches = get_option_switches();742 printk(KERN_INFO PFX "Option switches (0x%02x): Temperature Reset Enable=%s, Power On Delay=%s\n",···752 } else {753 /* Should NEVER happen, unless get_revision() fails. */754 printk(KERN_INFO PFX "Unable to get revision\n");755- release_region(current_readport, (revision == PCWD_REVISION_A) ? 2 : 4);756- current_readport = 0x0000;757 return -1;758 }759760- if (supports_temp)761 printk(KERN_INFO PFX "Temperature Option Detected\n");762763- if (initial_status & WDIOF_CARDRESET)764 printk(KERN_INFO PFX "Previous reboot was caused by the card\n");765766- if (initial_status & WDIOF_OVERHEAT) {767 printk(KERN_EMERG PFX "Card senses a CPU Overheat. Panicking!\n");768 printk(KERN_EMERG PFX "CPU Overheat\n");769 }770771- if (initial_status == 0)772 printk(KERN_INFO PFX "No previous trip detected - Cold boot or reset\n");773774 /* Check that the heartbeat value is within it's range ; if not reset to the default */···782 if (ret) {783 printk(KERN_ERR PFX "cannot register reboot notifier (err=%d)\n",784 ret);785- release_region(current_readport, (revision == PCWD_REVISION_A) ? 2 : 4);786- current_readport = 0x0000;787 return ret;788 }789790- if (supports_temp) {791 ret = misc_register(&temp_miscdev);792 if (ret) {793 printk(KERN_ERR PFX "cannot register miscdev on minor=%d (err=%d)\n",794 TEMP_MINOR, ret);795 unregister_reboot_notifier(&pcwd_notifier);796- release_region(current_readport, (revision == PCWD_REVISION_A) ? 2 : 4);797- current_readport = 0x0000;798 return ret;799 }800 }···803 if (ret) {804 printk(KERN_ERR PFX "cannot register miscdev on minor=%d (err=%d)\n",805 WATCHDOG_MINOR, ret);806- if (supports_temp)807 misc_deregister(&temp_miscdev);808 unregister_reboot_notifier(&pcwd_notifier);809- release_region(current_readport, (revision == PCWD_REVISION_A) ? 2 : 4);810- current_readport = 0x0000;811 return ret;812 }813···825826 /* Deregister */827 misc_deregister(&pcwd_miscdev);828- if (supports_temp)829 misc_deregister(&temp_miscdev);830 unregister_reboot_notifier(&pcwd_notifier);831- release_region(current_readport, (revision == PCWD_REVISION_A) ? 2 : 4);832- current_readport = 0x0000;833 cards_found--;834}835···893{894 int i, found = 0;895896- spin_lock_init(&io_lock);897898 for (i = 0; pcwd_ioports[i] != 0; i++) {899 if (pcwd_checkcard(pcwd_ioports[i])) {···912913static void __exit pcwd_cleanup_module(void)914{915- if (current_readport)916 pcwatchdog_exit();917 return;918}
···73#include <asm/io.h> /* For inb/outb/... */7475/* Module and version information */76+#define WD_VER "1.16 (03/01/2006)"77#define PFX "pcwd: "7879/*···133/* internal variables */134static atomic_t open_allowed = ATOMIC_INIT(1);135static char expect_close;00136static int temp_panic;137+static struct { /* this is private data for each ISA-PC watchdog card */138+ int revision; /* The card's revision */139+ int supports_temp; /* Wether or not the card has a temperature device */140+ int command_mode; /* Wether or not the card is in command mode */141+ int boot_status; /* The card's boot status */142+ int io_addr; /* The cards I/O address */143+ spinlock_t io_lock; /* the lock for io operations */144+ struct timer_list timer; /* The timer that pings the watchdog */145+ unsigned long next_heartbeat; /* the next_heartbeat for the timer */146+} pcwd_private;147148/* module parameters */149#define WATCHDOG_HEARTBEAT 60 /* 60 sec default heartbeat */···165166 /* The WCMD bit must be 1 and the command is only 4 bits in size */167 control_status = (cmd & 0x0F) | 0x80;168+ outb_p(control_status, pcwd_private.io_addr + 2);169 udelay(ISA_COMMAND_TIMEOUT);170171+ port0 = inb_p(pcwd_private.io_addr);172 for (i = 0; i < 25; ++i) {173 last_port0 = port0;174+ port0 = inb_p(pcwd_private.io_addr);175176 if (port0 == last_port0)177 break; /* Data is stable */···187 int i, found=0, count=0;188189 /* Set the card into command mode */190+ spin_lock(&pcwd_private.io_lock);191 while ((!found) && (count < 3)) {192 i = send_isa_command(CMD_ISA_IDLE);193···195 found = 1;196 else if (i == 0xF3) {197 /* Card does not like what we've done to it */198+ outb_p(0x00, pcwd_private.io_addr + 2);199 udelay(1200); /* Spec says wait 1ms */200+ outb_p(0x00, pcwd_private.io_addr + 2);201 udelay(ISA_COMMAND_TIMEOUT);202 }203 count++;204 }205+ spin_unlock(&pcwd_private.io_lock);206+ pcwd_private.command_mode = found;207208 return(found);209}···211static void unset_command_mode(void)212{213 /* Set the card into normal mode */214+ spin_lock(&pcwd_private.io_lock);215+ outb_p(0x00, pcwd_private.io_addr + 2);216 udelay(ISA_COMMAND_TIMEOUT);217+ spin_unlock(&pcwd_private.io_lock);218219+ pcwd_private.command_mode = 0;220}221222static void pcwd_timer_ping(unsigned long data)···225226 /* If we got a heartbeat pulse within the WDT_INTERVAL227 * we agree to ping the WDT */228+ if(time_before(jiffies, pcwd_private.next_heartbeat)) {229 /* Ping the watchdog */230+ spin_lock(&pcwd_private.io_lock);231+ if (pcwd_private.revision == PCWD_REVISION_A) {232 /* Rev A cards are reset by setting the WD_WDRST bit in register 1 */233+ wdrst_stat = inb_p(pcwd_private.io_addr);234 wdrst_stat &= 0x0F;235 wdrst_stat |= WD_WDRST;236237+ outb_p(wdrst_stat, pcwd_private.io_addr + 1);238 } else {239 /* Re-trigger watchdog by writing to port 0 */240+ outb_p(0x00, pcwd_private.io_addr);241 }242243 /* Re-set the timer interval */244+ mod_timer(&pcwd_private.timer, jiffies + WDT_INTERVAL);245246+ spin_unlock(&pcwd_private.io_lock);247 } else {248 printk(KERN_WARNING PFX "Heartbeat lost! Will not ping the watchdog\n");249 }···253{254 int stat_reg;255256+ pcwd_private.next_heartbeat = jiffies + (heartbeat * HZ);257258 /* Start the timer */259+ mod_timer(&pcwd_private.timer, jiffies + WDT_INTERVAL);260261 /* Enable the port */262+ if (pcwd_private.revision == PCWD_REVISION_C) {263+ spin_lock(&pcwd_private.io_lock);264+ outb_p(0x00, pcwd_private.io_addr + 3);265 udelay(ISA_COMMAND_TIMEOUT);266+ stat_reg = inb_p(pcwd_private.io_addr + 2);267+ spin_unlock(&pcwd_private.io_lock);268 if (stat_reg & 0x10) {269 printk(KERN_INFO PFX "Could not start watchdog\n");270 return -EIO;···278 int stat_reg;279280 /* Stop the timer */281+ del_timer(&pcwd_private.timer);282283 /* Disable the board */284+ if (pcwd_private.revision == PCWD_REVISION_C) {285+ spin_lock(&pcwd_private.io_lock);286+ outb_p(0xA5, pcwd_private.io_addr + 3);287 udelay(ISA_COMMAND_TIMEOUT);288+ outb_p(0xA5, pcwd_private.io_addr + 3);289 udelay(ISA_COMMAND_TIMEOUT);290+ stat_reg = inb_p(pcwd_private.io_addr + 2);291+ spin_unlock(&pcwd_private.io_lock);292 if ((stat_reg & 0x10) == 0) {293 printk(KERN_INFO PFX "Could not stop watchdog\n");294 return -EIO;···300static int pcwd_keepalive(void)301{302 /* user land ping */303+ pcwd_private.next_heartbeat = jiffies + (heartbeat * HZ);304 return 0;305}306···318 int card_status;319320 *status=0;321+ spin_lock(&pcwd_private.io_lock);322+ if (pcwd_private.revision == PCWD_REVISION_A)323 /* Rev A cards return status information from324 * the base register, which is used for the325 * temperature in other cards. */326+ card_status = inb(pcwd_private.io_addr);327 else {328 /* Rev C cards return card status in the base329 * address + 1 register. And use different bits330 * to indicate a card initiated reset, and an331 * over-temperature condition. And the reboot332 * status can be reset. */333+ card_status = inb(pcwd_private.io_addr + 1);334 }335+ spin_unlock(&pcwd_private.io_lock);336337+ if (pcwd_private.revision == PCWD_REVISION_A) {338 if (card_status & WD_WDRST)339 *status |= WDIOF_CARDRESET;340···363364static int pcwd_clear_status(void)365{366+ if (pcwd_private.revision == PCWD_REVISION_C) {367+ spin_lock(&pcwd_private.io_lock);368+ outb_p(0x00, pcwd_private.io_addr + 1); /* clear reset status */369+ spin_unlock(&pcwd_private.io_lock);370 }371 return 0;372}···374static int pcwd_get_temperature(int *temperature)375{376 /* check that port 0 gives temperature info and no command results */377+ if (pcwd_private.command_mode)378 return -1;379380 *temperature = 0;381+ if (!pcwd_private.supports_temp)382 return -ENODEV;383384 /*385 * Convert celsius to fahrenheit, since this was386 * the decided 'standard' for this return value.387 */388+ spin_lock(&pcwd_private.io_lock);389+ *temperature = ((inb(pcwd_private.io_addr)) * 9 / 5) + 32;390+ spin_unlock(&pcwd_private.io_lock);391392 return 0;393}···428 return put_user(status, argp);429430 case WDIOC_GETBOOTSTATUS:431+ return put_user(pcwd_private.boot_status, argp);432433 case WDIOC_GETTEMP:434 if (pcwd_get_temperature(&temperature))···437 return put_user(temperature, argp);438439 case WDIOC_SETOPTIONS:440+ if (pcwd_private.revision == PCWD_REVISION_C)441 {442 if(copy_from_user(&rv, argp, sizeof(int)))443 return -EFAULT;···553554static int pcwd_temp_open(struct inode *inode, struct file *file)555{556+ if (!pcwd_private.supports_temp)557 return -ENODEV;558559 return nonseekable_open(inode, file);···621622static inline void get_support(void)623{624+ if (inb(pcwd_private.io_addr) != 0xF0)625+ pcwd_private.supports_temp = 1;626}627628static inline int get_revision(void)629{630 int r = PCWD_REVISION_C;631632+ spin_lock(&pcwd_private.io_lock);633 /* REV A cards use only 2 io ports; test634 * presumes a floating bus reads as 0xff. */635+ if ((inb(pcwd_private.io_addr + 2) == 0xFF) ||636+ (inb(pcwd_private.io_addr + 3) == 0xFF))637 r=PCWD_REVISION_A;638+ spin_unlock(&pcwd_private.io_lock);639640 return r;641}···695 printk(KERN_ERR PFX "No I/O-Address for card detected\n");696 return -ENODEV;697 }698+ pcwd_private.io_addr = base_addr;699700 /* Check card's revision */701+ pcwd_private.revision = get_revision();702703+ if (!request_region(pcwd_private.io_addr, (pcwd_private.revision == PCWD_REVISION_A) ? 2 : 4, "PCWD")) {704 printk(KERN_ERR PFX "I/O address 0x%04x already in use\n",705+ pcwd_private.io_addr);706+ pcwd_private.io_addr = 0x0000;707 return -EIO;708 }709710 /* Initial variables */711+ pcwd_private.supports_temp = 0;712 temp_panic = 0;713+ pcwd_private.boot_status = 0x0000;714715 /* get the boot_status */716+ pcwd_get_status(&pcwd_private.boot_status);717718 /* clear the "card caused reboot" flag */719 pcwd_clear_status();720721+ init_timer(&pcwd_private.timer);722+ pcwd_private.timer.function = pcwd_timer_ping;723+ pcwd_private.timer.data = 0;724725 /* Disable the board */726 pcwd_stop();···729 get_support();730731 /* Get some extra info from the hardware (in command/debug/diag mode) */732+ if (pcwd_private.revision == PCWD_REVISION_A)733+ printk(KERN_INFO PFX "ISA-PC Watchdog (REV.A) detected at port 0x%04x\n", pcwd_private.io_addr);734+ else if (pcwd_private.revision == PCWD_REVISION_C) {735 firmware = get_firmware();736 printk(KERN_INFO PFX "ISA-PC Watchdog (REV.C) detected at port 0x%04x (Firmware version: %s)\n",737+ pcwd_private.io_addr, firmware);738 kfree(firmware);739 option_switches = get_option_switches();740 printk(KERN_INFO PFX "Option switches (0x%02x): Temperature Reset Enable=%s, Power On Delay=%s\n",···750 } else {751 /* Should NEVER happen, unless get_revision() fails. */752 printk(KERN_INFO PFX "Unable to get revision\n");753+ release_region(pcwd_private.io_addr, (pcwd_private.revision == PCWD_REVISION_A) ? 2 : 4);754+ pcwd_private.io_addr = 0x0000;755 return -1;756 }757758+ if (pcwd_private.supports_temp)759 printk(KERN_INFO PFX "Temperature Option Detected\n");760761+ if (pcwd_private.boot_status & WDIOF_CARDRESET)762 printk(KERN_INFO PFX "Previous reboot was caused by the card\n");763764+ if (pcwd_private.boot_status & WDIOF_OVERHEAT) {765 printk(KERN_EMERG PFX "Card senses a CPU Overheat. Panicking!\n");766 printk(KERN_EMERG PFX "CPU Overheat\n");767 }768769+ if (pcwd_private.boot_status == 0)770 printk(KERN_INFO PFX "No previous trip detected - Cold boot or reset\n");771772 /* Check that the heartbeat value is within it's range ; if not reset to the default */···780 if (ret) {781 printk(KERN_ERR PFX "cannot register reboot notifier (err=%d)\n",782 ret);783+ release_region(pcwd_private.io_addr, (pcwd_private.revision == PCWD_REVISION_A) ? 2 : 4);784+ pcwd_private.io_addr = 0x0000;785 return ret;786 }787788+ if (pcwd_private.supports_temp) {789 ret = misc_register(&temp_miscdev);790 if (ret) {791 printk(KERN_ERR PFX "cannot register miscdev on minor=%d (err=%d)\n",792 TEMP_MINOR, ret);793 unregister_reboot_notifier(&pcwd_notifier);794+ release_region(pcwd_private.io_addr, (pcwd_private.revision == PCWD_REVISION_A) ? 2 : 4);795+ pcwd_private.io_addr = 0x0000;796 return ret;797 }798 }···801 if (ret) {802 printk(KERN_ERR PFX "cannot register miscdev on minor=%d (err=%d)\n",803 WATCHDOG_MINOR, ret);804+ if (pcwd_private.supports_temp)805 misc_deregister(&temp_miscdev);806 unregister_reboot_notifier(&pcwd_notifier);807+ release_region(pcwd_private.io_addr, (pcwd_private.revision == PCWD_REVISION_A) ? 2 : 4);808+ pcwd_private.io_addr = 0x0000;809 return ret;810 }811···823824 /* Deregister */825 misc_deregister(&pcwd_miscdev);826+ if (pcwd_private.supports_temp)827 misc_deregister(&temp_miscdev);828 unregister_reboot_notifier(&pcwd_notifier);829+ release_region(pcwd_private.io_addr, (pcwd_private.revision == PCWD_REVISION_A) ? 2 : 4);830+ pcwd_private.io_addr = 0x0000;831 cards_found--;832}833···891{892 int i, found = 0;893894+ spin_lock_init(&pcwd_private.io_lock);895896 for (i = 0; pcwd_ioports[i] != 0; i++) {897 if (pcwd_checkcard(pcwd_ioports[i])) {···910911static void __exit pcwd_cleanup_module(void)912{913+ if (pcwd_private.io_addr)914 pcwatchdog_exit();915 return;916}