Blame view
drivers/watchdog/i6300esb.c
12.9 KB
cc90ef0f9 [WATCHDOG] i6300e... |
1 |
/* |
abda5c8bd [WATCHDOG] i6300.... |
2 |
* i6300esb: Watchdog timer driver for Intel 6300ESB chipset |
cc90ef0f9 [WATCHDOG] i6300e... |
3 4 |
* * (c) Copyright 2004 Google Inc. |
96de0e252 Convert files to ... |
5 |
* (c) Copyright 2005 David Härdeman <david@2gen.com> |
cc90ef0f9 [WATCHDOG] i6300e... |
6 7 8 9 10 11 |
* * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version * 2 of the License, or (at your option) any later version. * |
7944d3a5a [WATCHDOG] more c... |
12 |
* based on i810-tco.c which is in turn based on softdog.c |
cc90ef0f9 [WATCHDOG] i6300e... |
13 |
* |
7944d3a5a [WATCHDOG] more c... |
14 15 |
* The timer is implemented in the following I/O controller hubs: * (See the intel documentation on http://developer.intel.com.) |
0426fd0d8 [WATCHDOG] i6300e... |
16 |
* 6300ESB chip : document number 300641-004 |
cc90ef0f9 [WATCHDOG] i6300e... |
17 18 19 20 |
* * 2004YYZZ Ross Biro * Initial version 0.01 * 2004YYZZ Ross Biro |
7944d3a5a [WATCHDOG] more c... |
21 |
* Version 0.02 |
96de0e252 Convert files to ... |
22 |
* 20050210 David Härdeman <david@2gen.com> |
7944d3a5a [WATCHDOG] more c... |
23 |
* Ported driver to kernel 2.6 |
cc90ef0f9 [WATCHDOG] i6300e... |
24 25 26 27 28 29 30 31 32 33 34 35 36 |
*/ /* * Includes, defines, variables, module parameters, ... */ #include <linux/module.h> #include <linux/types.h> #include <linux/kernel.h> #include <linux/fs.h> #include <linux/mm.h> #include <linux/miscdevice.h> #include <linux/watchdog.h> |
cc90ef0f9 [WATCHDOG] i6300e... |
37 38 39 |
#include <linux/init.h> #include <linux/pci.h> #include <linux/ioport.h> |
0829291ea [WATCHDOG 13/57] ... |
40 41 |
#include <linux/uaccess.h> #include <linux/io.h> |
cc90ef0f9 [WATCHDOG] i6300e... |
42 |
|
cc90ef0f9 [WATCHDOG] i6300e... |
43 |
/* Module and version information */ |
2786095a5 [WATCHDOG] i6300e... |
44 |
#define ESB_VERSION "0.05" |
cc90ef0f9 [WATCHDOG] i6300e... |
45 46 47 |
#define ESB_MODULE_NAME "i6300ESB timer" #define ESB_DRIVER_NAME ESB_MODULE_NAME ", v" ESB_VERSION #define PFX ESB_MODULE_NAME ": " |
abda5c8bd [WATCHDOG] i6300.... |
48 49 50 51 52 |
/* PCI configuration registers */ #define ESB_CONFIG_REG 0x60 /* Config register */ #define ESB_LOCK_REG 0x68 /* WDT lock register */ /* Memory mapped registers */ |
bd4e6c18a [WATCHDOG] i6300e... |
53 54 55 56 |
#define ESB_TIMER1_REG (BASEADDR + 0x00)/* Timer1 value after each reset */ #define ESB_TIMER2_REG (BASEADDR + 0x04)/* Timer2 value after each reset */ #define ESB_GINTSR_REG (BASEADDR + 0x08)/* General Interrupt Status Register */ #define ESB_RELOAD_REG (BASEADDR + 0x0c)/* Reload register */ |
abda5c8bd [WATCHDOG] i6300.... |
57 58 |
/* Lock register bits */ |
0829291ea [WATCHDOG 13/57] ... |
59 60 61 |
#define ESB_WDT_FUNC (0x01 << 2) /* Watchdog functionality */ #define ESB_WDT_ENABLE (0x01 << 1) /* Enable WDT */ #define ESB_WDT_LOCK (0x01 << 0) /* Lock (nowayout) */ |
abda5c8bd [WATCHDOG] i6300.... |
62 63 |
/* Config register bits */ |
0829291ea [WATCHDOG 13/57] ... |
64 65 |
#define ESB_WDT_REBOOT (0x01 << 5) /* Enable reboot on timeout */ #define ESB_WDT_FREQ (0x01 << 2) /* Decrement frequency */ |
39f3be72c [WATCHDOG] i6300e... |
66 |
#define ESB_WDT_INTTYPE (0x03 << 0) /* Interrupt type on timer1 timeout */ |
abda5c8bd [WATCHDOG] i6300.... |
67 68 |
/* Reload register bits */ |
31838d9da [WATCHDOG] i6300e... |
69 |
#define ESB_WDT_TIMEOUT (0x01 << 9) /* Watchdog timed out */ |
0829291ea [WATCHDOG 13/57] ... |
70 |
#define ESB_WDT_RELOAD (0x01 << 8) /* prevent timeout */ |
abda5c8bd [WATCHDOG] i6300.... |
71 72 73 74 |
/* Magic constants */ #define ESB_UNLOCK1 0x80 /* Step 1 to unlock reset registers */ #define ESB_UNLOCK2 0x86 /* Step 2 to unlock reset registers */ |
cc90ef0f9 [WATCHDOG] i6300e... |
75 76 |
/* internal variables */ static void __iomem *BASEADDR; |
c7dfd0cca [WATCHDOG] spin_l... |
77 |
static DEFINE_SPINLOCK(esb_lock); /* Guards the hardware */ |
cc90ef0f9 [WATCHDOG] i6300e... |
78 79 80 81 |
static unsigned long timer_alive; static struct pci_dev *esb_pci; static unsigned short triggered; /* The status of the watchdog upon boot */ static char esb_expect_close; |
2786095a5 [WATCHDOG] i6300e... |
82 83 84 |
/* We can only use 1 card due to the /dev/watchdog restriction */ static int cards_found; |
0426fd0d8 [WATCHDOG] i6300e... |
85 |
|
cc90ef0f9 [WATCHDOG] i6300e... |
86 |
/* module parameters */ |
0829291ea [WATCHDOG 13/57] ... |
87 88 |
/* 30 sec default heartbeat (1 < heartbeat < 2*1023) */ #define WATCHDOG_HEARTBEAT 30 |
cc90ef0f9 [WATCHDOG] i6300e... |
89 90 |
static int heartbeat = WATCHDOG_HEARTBEAT; /* in seconds */ module_param(heartbeat, int, 0); |
0829291ea [WATCHDOG 13/57] ... |
91 92 93 |
MODULE_PARM_DESC(heartbeat, "Watchdog heartbeat in seconds. (1<heartbeat<2046, default=" __MODULE_STRING(WATCHDOG_HEARTBEAT) ")"); |
cc90ef0f9 [WATCHDOG] i6300e... |
94 |
|
811f99916 [WATCHDOG] i6300e... |
95 |
static int nowayout = WATCHDOG_NOWAYOUT; |
cc90ef0f9 [WATCHDOG] i6300e... |
96 |
module_param(nowayout, int, 0); |
0829291ea [WATCHDOG 13/57] ... |
97 98 99 |
MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default=" __MODULE_STRING(WATCHDOG_NOWAYOUT) ")"); |
cc90ef0f9 [WATCHDOG] i6300e... |
100 101 102 103 104 105 106 107 108 109 110 |
/* * Some i6300ESB specific functions */ /* * Prepare for reloading the timer by unlocking the proper registers. * This is performed by first writing 0x80 followed by 0x86 to the * reload register. After this the appropriate registers can be written * to once before they need to be unlocked again. */ |
7944d3a5a [WATCHDOG] more c... |
111 112 |
static inline void esb_unlock_registers(void) { |
39f3be72c [WATCHDOG] i6300e... |
113 114 |
writew(ESB_UNLOCK1, ESB_RELOAD_REG); writew(ESB_UNLOCK2, ESB_RELOAD_REG); |
cc90ef0f9 [WATCHDOG] i6300e... |
115 |
} |
3b9d49eea [WATCHDOG] i6300e... |
116 |
static int esb_timer_start(void) |
cc90ef0f9 [WATCHDOG] i6300e... |
117 118 |
{ u8 val; |
3b9d49eea [WATCHDOG] i6300e... |
119 120 121 |
spin_lock(&esb_lock); esb_unlock_registers(); writew(ESB_WDT_RELOAD, ESB_RELOAD_REG); |
cc90ef0f9 [WATCHDOG] i6300e... |
122 |
/* Enable or Enable + Lock? */ |
fc8a9d830 [WATCHDOG] i6300e... |
123 |
val = ESB_WDT_ENABLE | (nowayout ? ESB_WDT_LOCK : 0x00); |
0829291ea [WATCHDOG 13/57] ... |
124 |
pci_write_config_byte(esb_pci, ESB_LOCK_REG, val); |
3b9d49eea [WATCHDOG] i6300e... |
125 126 |
spin_unlock(&esb_lock); return 0; |
cc90ef0f9 [WATCHDOG] i6300e... |
127 128 129 130 131 132 133 134 135 |
} static int esb_timer_stop(void) { u8 val; spin_lock(&esb_lock); /* First, reset timers as suggested by the docs */ esb_unlock_registers(); |
ce2f50b4a [WATCHDOG] i6300e... |
136 |
writew(ESB_WDT_RELOAD, ESB_RELOAD_REG); |
cc90ef0f9 [WATCHDOG] i6300e... |
137 138 139 140 141 142 |
/* Then disable the WDT */ pci_write_config_byte(esb_pci, ESB_LOCK_REG, 0x0); pci_read_config_byte(esb_pci, ESB_LOCK_REG, &val); spin_unlock(&esb_lock); /* Returns 0 if the timer was disabled, non-zero otherwise */ |
fc8a9d830 [WATCHDOG] i6300e... |
143 |
return val & ESB_WDT_ENABLE; |
cc90ef0f9 [WATCHDOG] i6300e... |
144 145 146 147 148 149 |
} static void esb_timer_keepalive(void) { spin_lock(&esb_lock); esb_unlock_registers(); |
ce2f50b4a [WATCHDOG] i6300e... |
150 |
writew(ESB_WDT_RELOAD, ESB_RELOAD_REG); |
0829291ea [WATCHDOG 13/57] ... |
151 |
/* FIXME: Do we need to flush anything here? */ |
cc90ef0f9 [WATCHDOG] i6300e... |
152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 |
spin_unlock(&esb_lock); } static int esb_timer_set_heartbeat(int time) { u32 val; if (time < 0x1 || time > (2 * 0x03ff)) return -EINVAL; spin_lock(&esb_lock); /* We shift by 9, so if we are passed a value of 1 sec, * val will be 1 << 9 = 512, then write that to two * timers => 2 * 512 = 1024 (which is decremented at 1KHz) */ val = time << 9; /* Write timer 1 */ esb_unlock_registers(); writel(val, ESB_TIMER1_REG); /* Write timer 2 */ esb_unlock_registers(); |
7944d3a5a [WATCHDOG] more c... |
176 |
writel(val, ESB_TIMER2_REG); |
cc90ef0f9 [WATCHDOG] i6300e... |
177 |
|
0829291ea [WATCHDOG 13/57] ... |
178 |
/* Reload */ |
cc90ef0f9 [WATCHDOG] i6300e... |
179 |
esb_unlock_registers(); |
ce2f50b4a [WATCHDOG] i6300e... |
180 |
writew(ESB_WDT_RELOAD, ESB_RELOAD_REG); |
cc90ef0f9 [WATCHDOG] i6300e... |
181 182 183 184 185 186 187 188 |
/* FIXME: Do we need to flush everything out? */ /* Done */ heartbeat = time; spin_unlock(&esb_lock); return 0; } |
cc90ef0f9 [WATCHDOG] i6300e... |
189 |
/* |
7944d3a5a [WATCHDOG] more c... |
190 |
* /dev/watchdog handling |
cc90ef0f9 [WATCHDOG] i6300e... |
191 |
*/ |
0829291ea [WATCHDOG 13/57] ... |
192 |
static int esb_open(struct inode *inode, struct file *file) |
cc90ef0f9 [WATCHDOG] i6300e... |
193 |
{ |
0829291ea [WATCHDOG 13/57] ... |
194 195 196 |
/* /dev/watchdog can only be opened once */ if (test_and_set_bit(0, &timer_alive)) return -EBUSY; |
cc90ef0f9 [WATCHDOG] i6300e... |
197 |
|
0829291ea [WATCHDOG 13/57] ... |
198 |
/* Reload and activate timer */ |
0829291ea [WATCHDOG 13/57] ... |
199 |
esb_timer_start(); |
cc90ef0f9 [WATCHDOG] i6300e... |
200 201 202 |
return nonseekable_open(inode, file); } |
0829291ea [WATCHDOG 13/57] ... |
203 |
static int esb_release(struct inode *inode, struct file *file) |
cc90ef0f9 [WATCHDOG] i6300e... |
204 |
{ |
0829291ea [WATCHDOG 13/57] ... |
205 206 207 208 209 210 211 212 213 214 215 216 |
/* Shut off the timer. */ if (esb_expect_close == 42) esb_timer_stop(); else { printk(KERN_CRIT PFX "Unexpected close, not stopping watchdog! "); esb_timer_keepalive(); } clear_bit(0, &timer_alive); esb_expect_close = 0; return 0; |
cc90ef0f9 [WATCHDOG] i6300e... |
217 |
} |
0829291ea [WATCHDOG 13/57] ... |
218 219 |
static ssize_t esb_write(struct file *file, const char __user *data, size_t len, loff_t *ppos) |
cc90ef0f9 [WATCHDOG] i6300e... |
220 221 |
{ /* See if we got the magic character 'V' and reload the timer */ |
0829291ea [WATCHDOG 13/57] ... |
222 |
if (len) { |
cc90ef0f9 [WATCHDOG] i6300e... |
223 224 225 226 227 228 |
if (!nowayout) { size_t i; /* note: just in case someone wrote the magic character * five months ago... */ esb_expect_close = 0; |
143a2e54b [WATCHDOG] More c... |
229 230 |
/* scan to see whether or not we got the * magic character */ |
cc90ef0f9 [WATCHDOG] i6300e... |
231 232 |
for (i = 0; i != len; i++) { char c; |
7944d3a5a [WATCHDOG] more c... |
233 |
if (get_user(c, data + i)) |
cc90ef0f9 [WATCHDOG] i6300e... |
234 235 236 237 238 239 240 |
return -EFAULT; if (c == 'V') esb_expect_close = 42; } } /* someone wrote to us, we should reload the timer */ |
0829291ea [WATCHDOG 13/57] ... |
241 |
esb_timer_keepalive(); |
cc90ef0f9 [WATCHDOG] i6300e... |
242 243 244 |
} return len; } |
0829291ea [WATCHDOG 13/57] ... |
245 |
static long esb_ioctl(struct file *file, unsigned int cmd, unsigned long arg) |
cc90ef0f9 [WATCHDOG] i6300e... |
246 247 248 249 250 |
{ int new_options, retval = -EINVAL; int new_heartbeat; void __user *argp = (void __user *)arg; int __user *p = argp; |
42747d712 [WATCHDOG] watchd... |
251 |
static const struct watchdog_info ident = { |
7944d3a5a [WATCHDOG] more c... |
252 |
.options = WDIOF_SETTIMEOUT | |
cc90ef0f9 [WATCHDOG] i6300e... |
253 254 |
WDIOF_KEEPALIVEPING | WDIOF_MAGICCLOSE, |
7944d3a5a [WATCHDOG] more c... |
255 256 |
.firmware_version = 0, .identity = ESB_MODULE_NAME, |
cc90ef0f9 [WATCHDOG] i6300e... |
257 258 259 |
}; switch (cmd) { |
0829291ea [WATCHDOG 13/57] ... |
260 261 262 |
case WDIOC_GETSUPPORT: return copy_to_user(argp, &ident, sizeof(ident)) ? -EFAULT : 0; |
cc90ef0f9 [WATCHDOG] i6300e... |
263 |
|
0829291ea [WATCHDOG 13/57] ... |
264 |
case WDIOC_GETSTATUS: |
31838d9da [WATCHDOG] i6300e... |
265 |
return put_user(0, p); |
cc90ef0f9 [WATCHDOG] i6300e... |
266 |
|
0829291ea [WATCHDOG 13/57] ... |
267 268 |
case WDIOC_GETBOOTSTATUS: return put_user(triggered, p); |
cc90ef0f9 [WATCHDOG] i6300e... |
269 |
|
0829291ea [WATCHDOG 13/57] ... |
270 271 272 273 |
case WDIOC_SETOPTIONS: { if (get_user(new_options, p)) return -EFAULT; |
cc90ef0f9 [WATCHDOG] i6300e... |
274 |
|
0829291ea [WATCHDOG 13/57] ... |
275 276 277 278 |
if (new_options & WDIOS_DISABLECARD) { esb_timer_stop(); retval = 0; } |
cc90ef0f9 [WATCHDOG] i6300e... |
279 |
|
0829291ea [WATCHDOG 13/57] ... |
280 |
if (new_options & WDIOS_ENABLECARD) { |
0829291ea [WATCHDOG 13/57] ... |
281 282 283 284 285 |
esb_timer_start(); retval = 0; } return retval; } |
0c06090c9 [WATCHDOG] Coding... |
286 287 288 |
case WDIOC_KEEPALIVE: esb_timer_keepalive(); return 0; |
0829291ea [WATCHDOG 13/57] ... |
289 290 291 292 293 294 295 296 297 298 299 300 301 302 |
case WDIOC_SETTIMEOUT: { if (get_user(new_heartbeat, p)) return -EFAULT; if (esb_timer_set_heartbeat(new_heartbeat)) return -EINVAL; esb_timer_keepalive(); /* Fall */ } case WDIOC_GETTIMEOUT: return put_user(heartbeat, p); default: return -ENOTTY; } |
cc90ef0f9 [WATCHDOG] i6300e... |
303 304 305 |
} /* |
cc90ef0f9 [WATCHDOG] i6300e... |
306 307 |
* Kernel Interfaces */ |
62322d255 [PATCH] make more... |
308 |
static const struct file_operations esb_fops = { |
0829291ea [WATCHDOG 13/57] ... |
309 310 311 312 313 314 |
.owner = THIS_MODULE, .llseek = no_llseek, .write = esb_write, .unlocked_ioctl = esb_ioctl, .open = esb_open, .release = esb_release, |
cc90ef0f9 [WATCHDOG] i6300e... |
315 316 317 |
}; static struct miscdevice esb_miscdev = { |
0829291ea [WATCHDOG 13/57] ... |
318 319 320 |
.minor = WATCHDOG_MINOR, .name = "watchdog", .fops = &esb_fops, |
cc90ef0f9 [WATCHDOG] i6300e... |
321 |
}; |
cc90ef0f9 [WATCHDOG] i6300e... |
322 323 |
/* * Data for PCI driver interface |
cc90ef0f9 [WATCHDOG] i6300e... |
324 |
*/ |
4562f5394 watchdog: convert... |
325 |
static DEFINE_PCI_DEVICE_TABLE(esb_pci_tbl) = { |
0829291ea [WATCHDOG 13/57] ... |
326 327 |
{ PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ESB_9), }, { 0, }, /* End of list */ |
cc90ef0f9 [WATCHDOG] i6300e... |
328 |
}; |
0829291ea [WATCHDOG 13/57] ... |
329 |
MODULE_DEVICE_TABLE(pci, esb_pci_tbl); |
cc90ef0f9 [WATCHDOG] i6300e... |
330 331 332 333 |
/* * Init & exit routines */ |
2786095a5 [WATCHDOG] i6300e... |
334 |
static unsigned char __devinit esb_getdevice(struct pci_dev *pdev) |
cc90ef0f9 [WATCHDOG] i6300e... |
335 |
{ |
2786095a5 [WATCHDOG] i6300e... |
336 |
if (pci_enable_device(pdev)) { |
fc8a9d830 [WATCHDOG] i6300e... |
337 338 339 340 |
printk(KERN_ERR PFX "failed to enable device "); goto err_devput; } |
cc90ef0f9 [WATCHDOG] i6300e... |
341 |
|
2786095a5 [WATCHDOG] i6300e... |
342 |
if (pci_request_region(pdev, 0, ESB_MODULE_NAME)) { |
fc8a9d830 [WATCHDOG] i6300e... |
343 344 345 346 |
printk(KERN_ERR PFX "failed to request region "); goto err_disable; } |
cc90ef0f9 [WATCHDOG] i6300e... |
347 |
|
2786095a5 [WATCHDOG] i6300e... |
348 |
BASEADDR = pci_ioremap_bar(pdev, 0); |
fc8a9d830 [WATCHDOG] i6300e... |
349 350 351 352 353 354 355 356 |
if (BASEADDR == NULL) { /* Something's wrong here, BASEADDR has to be set */ printk(KERN_ERR PFX "failed to get BASEADDR "); goto err_release; } /* Done */ |
2786095a5 [WATCHDOG] i6300e... |
357 |
esb_pci = pdev; |
fc8a9d830 [WATCHDOG] i6300e... |
358 |
return 1; |
cc90ef0f9 [WATCHDOG] i6300e... |
359 360 |
err_release: |
2786095a5 [WATCHDOG] i6300e... |
361 |
pci_release_region(pdev, 0); |
cc90ef0f9 [WATCHDOG] i6300e... |
362 |
err_disable: |
2786095a5 [WATCHDOG] i6300e... |
363 |
pci_disable_device(pdev); |
811f99916 [WATCHDOG] i6300e... |
364 |
err_devput: |
cc90ef0f9 [WATCHDOG] i6300e... |
365 366 |
return 0; } |
fc8a9d830 [WATCHDOG] i6300e... |
367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 |
static void __devinit esb_initdevice(void) { u8 val1; u16 val2; /* * Config register: * Bit 5 : 0 = Enable WDT_OUTPUT * Bit 2 : 0 = set the timer frequency to the PCI clock * divided by 2^15 (approx 1KHz). * Bits 1:0 : 11 = WDT_INT_TYPE Disabled. * The watchdog has two timers, it can be setup so that the * expiry of timer1 results in an interrupt and the expiry of * timer2 results in a reboot. We set it to not generate * any interrupts as there is not much we can do with it * right now. */ pci_write_config_word(esb_pci, ESB_CONFIG_REG, 0x0003); /* Check that the WDT isn't already locked */ pci_read_config_byte(esb_pci, ESB_LOCK_REG, &val1); if (val1 & ESB_WDT_LOCK) printk(KERN_WARNING PFX "nowayout already set "); /* Set the timer to watchdog mode and disable it for now */ pci_write_config_byte(esb_pci, ESB_LOCK_REG, 0x00); /* Check if the watchdog was previously triggered */ esb_unlock_registers(); val2 = readw(ESB_RELOAD_REG); if (val2 & ESB_WDT_TIMEOUT) triggered = WDIOF_CARDRESET; /* Reset WDT_TIMEOUT flag and timers */ esb_unlock_registers(); writew((ESB_WDT_TIMEOUT | ESB_WDT_RELOAD), ESB_RELOAD_REG); /* And set the correct timeout value */ esb_timer_set_heartbeat(heartbeat); } |
2786095a5 [WATCHDOG] i6300e... |
408 409 |
static int __devinit esb_probe(struct pci_dev *pdev, const struct pci_device_id *ent) |
cc90ef0f9 [WATCHDOG] i6300e... |
410 |
{ |
0829291ea [WATCHDOG 13/57] ... |
411 |
int ret; |
2786095a5 [WATCHDOG] i6300e... |
412 413 414 415 416 417 418 419 420 421 422 |
cards_found++; if (cards_found == 1) printk(KERN_INFO PFX "Intel 6300ESB WatchDog Timer Driver v%s ", ESB_VERSION); if (cards_found > 1) { printk(KERN_ERR PFX "This driver only supports 1 device "); return -ENODEV; } |
0829291ea [WATCHDOG 13/57] ... |
423 |
/* Check whether or not the hardware watchdog is there */ |
2786095a5 [WATCHDOG] i6300e... |
424 |
if (!esb_getdevice(pdev) || esb_pci == NULL) |
0829291ea [WATCHDOG 13/57] ... |
425 426 427 428 |
return -ENODEV; /* Check that the heartbeat value is within it's range; if not reset to the default */ |
fc8a9d830 [WATCHDOG] i6300e... |
429 430 |
if (heartbeat < 0x1 || heartbeat > 2 * 0x03ff) { heartbeat = WATCHDOG_HEARTBEAT; |
0829291ea [WATCHDOG 13/57] ... |
431 432 433 434 435 |
printk(KERN_INFO PFX "heartbeat value must be 1<heartbeat<2046, using %d ", heartbeat); } |
cc90ef0f9 [WATCHDOG] i6300e... |
436 |
|
fc8a9d830 [WATCHDOG] i6300e... |
437 438 439 440 |
/* Initialize the watchdog and make sure it does not run */ esb_initdevice(); /* Register the watchdog so that userspace has access to it */ |
0829291ea [WATCHDOG 13/57] ... |
441 442 443 444 445 446 |
ret = misc_register(&esb_miscdev); if (ret != 0) { printk(KERN_ERR PFX "cannot register miscdev on minor=%d (err=%d) ", WATCHDOG_MINOR, ret); |
0426fd0d8 [WATCHDOG] i6300e... |
447 |
goto err_unmap; |
0829291ea [WATCHDOG 13/57] ... |
448 |
} |
0829291ea [WATCHDOG 13/57] ... |
449 450 451 452 453 |
printk(KERN_INFO PFX "initialized (0x%p). heartbeat=%d sec (nowayout=%d) ", BASEADDR, heartbeat, nowayout); return 0; |
cc90ef0f9 [WATCHDOG] i6300e... |
454 |
|
cc90ef0f9 [WATCHDOG] i6300e... |
455 456 |
err_unmap: iounmap(BASEADDR); |
cc90ef0f9 [WATCHDOG] i6300e... |
457 |
pci_release_region(esb_pci, 0); |
cc90ef0f9 [WATCHDOG] i6300e... |
458 |
pci_disable_device(esb_pci); |
2786095a5 [WATCHDOG] i6300e... |
459 |
esb_pci = NULL; |
0829291ea [WATCHDOG 13/57] ... |
460 |
return ret; |
cc90ef0f9 [WATCHDOG] i6300e... |
461 |
} |
2786095a5 [WATCHDOG] i6300e... |
462 |
static void __devexit esb_remove(struct pci_dev *pdev) |
cc90ef0f9 [WATCHDOG] i6300e... |
463 464 465 |
{ /* Stop the timer before we leave */ if (!nowayout) |
0829291ea [WATCHDOG 13/57] ... |
466 |
esb_timer_stop(); |
cc90ef0f9 [WATCHDOG] i6300e... |
467 468 469 |
/* Deregister */ misc_deregister(&esb_miscdev); |
cc90ef0f9 [WATCHDOG] i6300e... |
470 471 472 |
iounmap(BASEADDR); pci_release_region(esb_pci, 0); pci_disable_device(esb_pci); |
2786095a5 [WATCHDOG] i6300e... |
473 |
esb_pci = NULL; |
0426fd0d8 [WATCHDOG] i6300e... |
474 |
} |
2786095a5 [WATCHDOG] i6300e... |
475 |
static void esb_shutdown(struct pci_dev *pdev) |
0426fd0d8 [WATCHDOG] i6300e... |
476 477 478 |
{ esb_timer_stop(); } |
2786095a5 [WATCHDOG] i6300e... |
479 480 481 |
static struct pci_driver esb_driver = { .name = ESB_MODULE_NAME, .id_table = esb_pci_tbl, |
0426fd0d8 [WATCHDOG] i6300e... |
482 483 484 |
.probe = esb_probe, .remove = __devexit_p(esb_remove), .shutdown = esb_shutdown, |
0426fd0d8 [WATCHDOG] i6300e... |
485 486 487 488 |
}; static int __init watchdog_init(void) { |
2786095a5 [WATCHDOG] i6300e... |
489 |
return pci_register_driver(&esb_driver); |
0426fd0d8 [WATCHDOG] i6300e... |
490 491 492 493 |
} static void __exit watchdog_cleanup(void) { |
2786095a5 [WATCHDOG] i6300e... |
494 |
pci_unregister_driver(&esb_driver); |
0426fd0d8 [WATCHDOG] i6300e... |
495 496 |
printk(KERN_INFO PFX "Watchdog Module Unloaded. "); |
cc90ef0f9 [WATCHDOG] i6300e... |
497 498 499 500 |
} module_init(watchdog_init); module_exit(watchdog_cleanup); |
96de0e252 Convert files to ... |
501 |
MODULE_AUTHOR("Ross Biro and David Härdeman"); |
cc90ef0f9 [WATCHDOG] i6300e... |
502 503 504 |
MODULE_DESCRIPTION("Watchdog driver for Intel 6300ESB chipsets"); MODULE_LICENSE("GPL"); MODULE_ALIAS_MISCDEV(WATCHDOG_MINOR); |