···5050#include <asm/io.h> /* For inb/outb/... */51515252/* Module and version information */5353-#define WATCHDOG_VERSION "1.01"5454-#define WATCHDOG_DATE "02 Sep 2005"5353+#define WATCHDOG_VERSION "1.02"5454+#define WATCHDOG_DATE "03 Sep 2005"5555#define WATCHDOG_DRIVER_NAME "PCI-PC Watchdog"5656#define WATCHDOG_NAME "pcwd_pci"5757#define PFX WATCHDOG_NAME ": "···7070 * These are the defines that describe the control status bits for the7171 * PCI-PC Watchdog card.7272 */7373-#define WD_PCI_WTRP 0x01 /* Watchdog Trip status */7474-#define WD_PCI_HRBT 0x02 /* Watchdog Heartbeat */7575-#define WD_PCI_TTRP 0x04 /* Temperature Trip status */7373+/* Port 1 : Control Status #1 */7474+#define WD_PCI_WTRP 0x01 /* Watchdog Trip status */7575+#define WD_PCI_HRBT 0x02 /* Watchdog Heartbeat */7676+#define WD_PCI_TTRP 0x04 /* Temperature Trip status */7777+#define WD_PCI_RL2A 0x08 /* Relay 2 Active */7878+#define WD_PCI_RL1A 0x10 /* Relay 1 Active */7979+#define WD_PCI_R2DS 0x40 /* Relay 2 Disable Temperature-trip/reset */8080+#define WD_PCI_RLY2 0x80 /* Activate Relay 2 on the board */8181+/* Port 2 : Control Status #2 */8282+#define WD_PCI_WDIS 0x10 /* Watchdog Disable */8383+#define WD_PCI_ENTP 0x20 /* Enable Temperature Trip Reset */8484+#define WD_PCI_WRSP 0x40 /* Watchdog wrote response */8585+#define WD_PCI_PCMD 0x80 /* PC has sent command */76867787/* according to documentation max. time to process a command for the pci7888 * watchdog card is 100 ms, so we give it 150 ms to do it's job */7989#define PCI_COMMAND_TIMEOUT 15080908191/* Watchdog's internal commands */8282-#define CMD_GET_STATUS 0x048383-#define CMD_GET_FIRMWARE_VERSION 0x088484-#define CMD_READ_WATCHDOG_TIMEOUT 0x188585-#define CMD_WRITE_WATCHDOG_TIMEOUT 0x199292+#define CMD_GET_STATUS 0x049393+#define CMD_GET_FIRMWARE_VERSION 0x089494+#define CMD_READ_WATCHDOG_TIMEOUT 0x189595+#define CMD_WRITE_WATCHDOG_TIMEOUT 0x199696+#define CMD_GET_CLEAR_RESET_COUNT 0x8486978798/* We can only use 1 card due to the /dev/watchdog restriction */8899static int cards_found;···10291static int temp_panic;10392static unsigned long is_active;10493static char expect_release;105105-static struct {106106- int supports_temp; /* Wether or not the card has a temperature device */107107- int boot_status; /* The card's boot status */108108- unsigned long io_addr; /* The cards I/O address */109109- spinlock_t io_lock;110110- struct pci_dev *pdev;9494+static struct { /* this is private data for each PCI-PC watchdog card */9595+ int supports_temp; /* Wether or not the card has a temperature device */9696+ int boot_status; /* The card's boot status */9797+ unsigned long io_addr; /* The cards I/O address */9898+ spinlock_t io_lock; /* the lock for io operations */9999+ struct pci_dev *pdev; /* the PCI-device */111100} pcipcwd_private;112101113102/* module parameters */103103+#define QUIET 0 /* Default */104104+#define VERBOSE 1 /* Verbose */105105+#define DEBUG 2 /* print fancy stuff too */106106+static int debug = QUIET;107107+module_param(debug, int, 0);108108+MODULE_PARM_DESC(debug, "Debug level: 0=Quiet, 1=Verbose, 2=Debug (default=0)");109109+114110#define WATCHDOG_HEARTBEAT 2 /* 2 sec default heartbeat */115111static int heartbeat = WATCHDOG_HEARTBEAT;116112module_param(heartbeat, int, 0);···135117{136118 int got_response, count;137119120120+ if (debug >= DEBUG)121121+ printk(KERN_DEBUG PFX "sending following data cmd=0x%02x msb=0x%02x lsb=0x%02x\n",122122+ cmd, *msb, *lsb);123123+138124 spin_lock(&pcipcwd_private.io_lock);139125 /* If a command requires data it should be written first.140126 * Data for commands with 8 bits of data should be written to port 4.···153131 /* wait till the pci card processed the command, signaled by154132 * the WRSP bit in port 2 and give it a max. timeout of155133 * PCI_COMMAND_TIMEOUT to process */156156- got_response = inb_p(pcipcwd_private.io_addr + 2) & 0x40;134134+ got_response = inb_p(pcipcwd_private.io_addr + 2) & WD_PCI_WRSP;157135 for (count = 0; (count < PCI_COMMAND_TIMEOUT) && (!got_response); count++) {158136 mdelay(1);159159- got_response = inb_p(pcipcwd_private.io_addr + 2) & 0x40;137137+ got_response = inb_p(pcipcwd_private.io_addr + 2) & WD_PCI_WRSP;138138+ }139139+140140+ if (debug >= DEBUG) {141141+ if (got_response) {142142+ printk(KERN_DEBUG PFX "time to process command was: %d ms\n",143143+ count);144144+ } else {145145+ printk(KERN_DEBUG PFX "card did not respond on command!\n");146146+ }160147 }161148162149 if (got_response) {···175144176145 /* clear WRSP bit */177146 inb_p(pcipcwd_private.io_addr + 6);147147+148148+ if (debug >= DEBUG)149149+ printk(KERN_DEBUG PFX "received following data for cmd=0x%02x: msb=0x%02x lsb=0x%02x\n",150150+ cmd, *msb, *lsb);178151 }152152+179153 spin_unlock(&pcipcwd_private.io_lock);180154181155 return got_response;156156+}157157+158158+static inline void pcipcwd_check_temperature_support(void)159159+{160160+ if (inb_p(pcipcwd_private.io_addr) != 0xF0)161161+ pcipcwd_private.supports_temp = 1;162162+}163163+164164+static int pcipcwd_get_option_switches(void)165165+{166166+ int option_switches;167167+168168+ option_switches = inb_p(pcipcwd_private.io_addr + 3);169169+ return option_switches;170170+}171171+172172+static void pcipcwd_show_card_info(void)173173+{174174+ int got_fw_rev, fw_rev_major, fw_rev_minor;175175+ char fw_ver_str[20]; /* The cards firmware version */176176+ int option_switches;177177+178178+ got_fw_rev = send_command(CMD_GET_FIRMWARE_VERSION, &fw_rev_major, &fw_rev_minor);179179+ if (got_fw_rev) {180180+ sprintf(fw_ver_str, "%u.%02u", fw_rev_major, fw_rev_minor);181181+ } else {182182+ sprintf(fw_ver_str, "<card no answer>");183183+ }184184+185185+ /* Get switch settings */186186+ option_switches = pcipcwd_get_option_switches();187187+188188+ printk(KERN_INFO PFX "Found card at port 0x%04x (Firmware: %s) %s temp option\n",189189+ (int) pcipcwd_private.io_addr, fw_ver_str,190190+ (pcipcwd_private.supports_temp ? "with" : "without"));191191+192192+ printk(KERN_INFO PFX "Option switches (0x%02x): Temperature Reset Enable=%s, Power On Delay=%s\n",193193+ option_switches,194194+ ((option_switches & 0x10) ? "ON" : "OFF"),195195+ ((option_switches & 0x08) ? "ON" : "OFF"));196196+197197+ if (pcipcwd_private.boot_status & WDIOF_CARDRESET)198198+ printk(KERN_INFO PFX "Previous reset was caused by the Watchdog card\n");199199+200200+ if (pcipcwd_private.boot_status & WDIOF_OVERHEAT)201201+ printk(KERN_INFO PFX "Card sensed a CPU Overheat\n");202202+203203+ if (pcipcwd_private.boot_status == 0)204204+ printk(KERN_INFO PFX "No previous trip detected - Cold boot or reset\n");182205}183206184207static int pcipcwd_start(void)···246161 stat_reg = inb_p(pcipcwd_private.io_addr + 2);247162 spin_unlock(&pcipcwd_private.io_lock);248163249249- if (stat_reg & 0x10) {164164+ if (stat_reg & WD_PCI_WDIS) {250165 printk(KERN_ERR PFX "Card timer not enabled\n");251166 return -1;252167 }168168+169169+ if (debug >= VERBOSE)170170+ printk(KERN_DEBUG PFX "Watchdog started\n");253171254172 return 0;255173}···271183 stat_reg = inb_p(pcipcwd_private.io_addr + 2);272184 spin_unlock(&pcipcwd_private.io_lock);273185274274- if (!(stat_reg & 0x10)) {186186+ if (!(stat_reg & WD_PCI_WDIS)) {275187 printk(KERN_ERR PFX "Card did not acknowledge disable attempt\n");276188 return -1;277189 }190190+191191+ if (debug >= VERBOSE)192192+ printk(KERN_DEBUG PFX "Watchdog stopped\n");278193279194 return 0;280195}···285194static int pcipcwd_keepalive(void)286195{287196 /* Re-trigger watchdog by writing to port 0 */288288- outb_p(0x42, pcipcwd_private.io_addr);197197+ outb_p(0x42, pcipcwd_private.io_addr); /* send out any data */198198+199199+ if (debug >= DEBUG)200200+ printk(KERN_DEBUG PFX "Watchdog keepalive signal send\n");201201+289202 return 0;290203}291204···305210 send_command(CMD_WRITE_WATCHDOG_TIMEOUT, &t_msb, &t_lsb);306211307212 heartbeat = t;213213+ if (debug >= VERBOSE)214214+ printk(KERN_DEBUG PFX "New heartbeat: %d\n",215215+ heartbeat);216216+308217 return 0;309218}310219311220static int pcipcwd_get_status(int *status)312221{313313- int new_status;222222+ int control_status;314223315224 *status=0;316316- new_status = inb_p(pcipcwd_private.io_addr + 1);317317- if (new_status & WD_PCI_WTRP)225225+ control_status = inb_p(pcipcwd_private.io_addr + 1);226226+ if (control_status & WD_PCI_WTRP)318227 *status |= WDIOF_CARDRESET;319319- if (new_status & WD_PCI_TTRP) {228228+ if (control_status & WD_PCI_TTRP) {320229 *status |= WDIOF_OVERHEAT;321230 if (temp_panic)322231 panic(PFX "Temperature overheat trip!\n");323232 }233233+234234+ if (debug >= DEBUG)235235+ printk(KERN_DEBUG PFX "Control Status #1: 0x%02x\n",236236+ control_status);324237325238 return 0;326239}327240328241static int pcipcwd_clear_status(void)329242{330330- outb_p(0x01, pcipcwd_private.io_addr + 1);243243+ int control_status;244244+ int msb;245245+ int reset_counter;246246+247247+ if (debug >= VERBOSE)248248+ printk(KERN_INFO PFX "clearing watchdog trip status & LED\n");249249+250250+ control_status = inb_p(pcipcwd_private.io_addr + 1);251251+252252+ if (debug >= DEBUG) {253253+ printk(KERN_DEBUG PFX "status was: 0x%02x\n", control_status);254254+ printk(KERN_DEBUG PFX "sending: 0x%02x\n",255255+ (control_status & WD_PCI_R2DS) | WD_PCI_WTRP);256256+ }257257+258258+ /* clear trip status & LED and keep mode of relay 2 */259259+ outb_p((control_status & WD_PCI_R2DS) | WD_PCI_WTRP, pcipcwd_private.io_addr + 1);260260+261261+ /* clear reset counter */262262+ msb=0;263263+ reset_counter=0xff;264264+ send_command(CMD_GET_CLEAR_RESET_COUNT, &msb, &reset_counter);265265+266266+ if (debug >= DEBUG) {267267+ printk(KERN_DEBUG PFX "reset count was: 0x%02x\n",268268+ reset_counter);269269+ }270270+331271 return 0;332272}333273···372242 if (!pcipcwd_private.supports_temp)373243 return -ENODEV;374244245245+ *temperature = inb_p(pcipcwd_private.io_addr);246246+375247 /*376248 * Convert celsius to fahrenheit, since this was377249 * the decided 'standard' for this return value.378250 */379379- *temperature = ((inb_p(pcipcwd_private.io_addr)) * 9 / 5) + 32;251251+ *temperature = (*temperature * 9 / 5) + 32;252252+253253+ if (debug >= DEBUG) {254254+ printk(KERN_DEBUG PFX "temperature is: %d F\n",255255+ *temperature);256256+ }380257381258 return 0;382259}···393256 */394257395258static ssize_t pcipcwd_write(struct file *file, const char __user *data,396396- size_t len, loff_t *ppos)259259+ size_t len, loff_t *ppos)397260{398261 /* See if we got the magic character 'V' and reload the timer */399262 if (len) {···518381static int pcipcwd_open(struct inode *inode, struct file *file)519382{520383 /* /dev/watchdog can only be opened once */521521- if (test_and_set_bit(0, &is_active))384384+ if (test_and_set_bit(0, &is_active)) {385385+ if (debug >= VERBOSE)386386+ printk(KERN_ERR PFX "Attempt to open already opened device.\n");522387 return -EBUSY;388388+ }523389524390 /* Activate */525391 pcipcwd_start();···632492 * Init & exit routines633493 */634494635635-static inline void check_temperature_support(void)636636-{637637- if (inb_p(pcipcwd_private.io_addr) != 0xF0)638638- pcipcwd_private.supports_temp = 1;639639-}640640-641495static int __devinit pcipcwd_card_init(struct pci_dev *pdev,642496 const struct pci_device_id *ent)643497{644498 int ret = -EIO;645645- int got_fw_rev, fw_rev_major, fw_rev_minor;646646- char fw_ver_str[20];647647- char option_switches;648499649500 cards_found++;650501 if (cards_found == 1)···677546 pcipcwd_stop();678547679548 /* Check whether or not the card supports the temperature device */680680- check_temperature_support();549549+ pcipcwd_check_temperature_support();681550682682- /* Get the Firmware Version */683683- got_fw_rev = send_command(CMD_GET_FIRMWARE_VERSION, &fw_rev_major, &fw_rev_minor);684684- if (got_fw_rev) {685685- sprintf(fw_ver_str, "%u.%02u", fw_rev_major, fw_rev_minor);686686- } else {687687- sprintf(fw_ver_str, "<card no answer>");688688- }689689-690690- /* Get switch settings */691691- option_switches = inb_p(pcipcwd_private.io_addr + 3);692692-693693- printk(KERN_INFO PFX "Found card at port 0x%04x (Firmware: %s) %s temp option\n",694694- (int) pcipcwd_private.io_addr, fw_ver_str,695695- (pcipcwd_private.supports_temp ? "with" : "without"));696696-697697- printk(KERN_INFO PFX "Option switches (0x%02x): Temperature Reset Enable=%s, Power On Delay=%s\n",698698- option_switches,699699- ((option_switches & 0x10) ? "ON" : "OFF"),700700- ((option_switches & 0x08) ? "ON" : "OFF"));701701-702702- if (pcipcwd_private.boot_status & WDIOF_CARDRESET)703703- printk(KERN_INFO PFX "Previous reset was caused by the Watchdog card\n");704704-705705- if (pcipcwd_private.boot_status & WDIOF_OVERHEAT)706706- printk(KERN_INFO PFX "Card sensed a CPU Overheat\n");707707-708708- if (pcipcwd_private.boot_status == 0)709709- printk(KERN_INFO PFX "No previous trip detected - Cold boot or reset\n");551551+ /* Show info about the card itself */552552+ pcipcwd_show_card_info();710553711554 /* Check that the heartbeat value is within it's range ; if not reset to the default */712555 if (pcipcwd_set_heartbeat(heartbeat)) {···761656762657static int __init pcipcwd_init_module(void)763658{764764- spin_lock_init (&pcipcwd_private.io_lock);659659+ spin_lock_init(&pcipcwd_private.io_lock);765660766661 return pci_register_driver(&pcipcwd_driver);767662}