pcwd.c
上传用户:jlfgdled
上传日期:2013-04-10
资源大小:33168k
文件大小:23k
源码类别:

Linux/Unix编程

开发平台:

Unix_Linux

  1. /*
  2.  * PC Watchdog Driver
  3.  * by Ken Hollis (khollis@bitgate.com)
  4.  *
  5.  * Permission granted from Simon Machell (73244.1270@compuserve.com)
  6.  * Written for the Linux Kernel, and GPLed by Ken Hollis
  7.  *
  8.  * 960107 Added request_region routines, modulized the whole thing.
  9.  * 960108 Fixed end-of-file pointer (Thanks to Dan Hollis), added
  10.  * WD_TIMEOUT define.
  11.  * 960216 Added eof marker on the file, and changed verbose messages.
  12.  * 960716 Made functional and cosmetic changes to the source for
  13.  * inclusion in Linux 2.0.x kernels, thanks to Alan Cox.
  14.  * 960717 Removed read/seek routines, replaced with ioctl.  Also, added
  15.  * check_region command due to Alan's suggestion.
  16.  * 960821 Made changes to compile in newer 2.0.x kernels.  Added
  17.  * "cold reboot sense" entry.
  18.  * 960825 Made a few changes to code, deleted some defines and made
  19.  * typedefs to replace them.  Made heartbeat reset only available
  20.  * via ioctl, and removed the write routine.
  21.  * 960828 Added new items for PC Watchdog Rev.C card.
  22.  * 960829 Changed around all of the IOCTLs, added new features,
  23.  * added watchdog disable/re-enable routines.  Added firmware
  24.  * version reporting.  Added read routine for temperature.
  25.  * Removed some extra defines, added an autodetect Revision
  26.  * routine.
  27.  * 961006       Revised some documentation, fixed some cosmetic bugs.  Made
  28.  *              drivers to panic the system if it's overheating at bootup.
  29.  * 961118 Changed some verbiage on some of the output, tidied up
  30.  * code bits, and added compatibility to 2.1.x.
  31.  * 970912       Enabled board on open and disable on close.
  32.  * 971107 Took account of recent VFS changes (broke read).
  33.  * 971210       Disable board on initialisation in case board already ticking.
  34.  * 971222       Changed open/close for temperature handling
  35.  *              Michael Meskes <meskes@debian.org>.
  36.  * 980112       Used minor numbers from include/linux/miscdevice.h
  37.  * 990403       Clear reset status after reading control status register in 
  38.  *              pcwd_showprevstate(). [Marc Boucher <marc@mbsi.ca>]
  39.  * 990605 Made changes to code to support Firmware 1.22a, added
  40.  * fairly useless proc entry.
  41.  * 990610 removed said useless proc code for the merge <alan>
  42.  * 000403 Removed last traces of proc code. <davej>
  43.  * 011214 Added nowayout module option to override CONFIG_WATCHDOG_NOWAYOUT <Matt_Domsch@dell.com>
  44.  * 020210       Backported 2.5 open_allowed changes, and got rid of a useless
  45.  *              variable <rob@osinvestor.com>
  46.  *              Added timeout module option to override default
  47.  * 020306 Support the PCI version [Lindsay Harris <lindsay@bluegum.com>]
  48.  */
  49. /*
  50.  *  A bells and whistles driver is available from http://www.pcwd.de/
  51.  */
  52. #include <linux/module.h>
  53. #include <linux/types.h>
  54. #include <linux/delay.h>
  55. #include <linux/miscdevice.h>
  56. #include <linux/watchdog.h>
  57. #include <linux/init.h>
  58. #include <asm/uaccess.h>
  59. #include <asm/io.h>
  60. #include <linux/notifier.h>
  61. #include <linux/reboot.h>
  62. #include <linux/pci.h>
  63. #define WD_VER                  "1.13 (03/06/2002)"
  64. /*  Stuff for the PCI version  */
  65. #ifndef PCI_VENDOR_ID_QUICKLOGIC
  66. #define PCI_VENDOR_ID_QUICKLOGIC 0x11e3
  67. #endif
  68. #ifndef PCI_DEVICE_ID_BERKSHIRE
  69. #define PCI_DEVICE_ID_BERKSHIRE 0x5030
  70. #endif
  71. /*
  72.  * It should be noted that PCWD_REV_B was removed because A and B
  73.  * are essentially the same types of card, with the exception that B
  74.  * has temperature reporting.  Since I didn't receive a Rev.B card,
  75.  * the Rev.B card is not supported.  (It's a good thing too, as they
  76.  * are no longer in production.)
  77.  */
  78. #define PCWD_REV_A 0
  79. #define PCWD_REV_C 1
  80. #define PCWD_REV_PCI 2
  81. static int timeout_val;
  82. static int timeout = 2;
  83. static int expect_close = 0;
  84. MODULE_PARM (timeout, "i");
  85. MODULE_PARM_DESC (timeout, "Watchdog timeout in seconds (default=2)");
  86. #ifdef CONFIG_WATCHDOG_NOWAYOUT
  87. static int nowayout = 1;
  88. #else
  89. static int nowayout = 0;
  90. #endif
  91. MODULE_PARM (nowayout, "i");
  92. MODULE_PARM_DESC (nowayout,
  93.   "Watchdog cannot be stopped once started (default=CONFIG_WATCHDOG_NOWAYOUT)");
  94. /*
  95.  * These are the defines for the PC Watchdog card, revision A.
  96.  */
  97. #define WD_WDRST                0x01 /* Previously reset state */
  98. #define WD_T110                 0x02 /* Temperature overheat sense */
  99. #define WD_HRTBT                0x04 /* Heartbeat sense */
  100. #define WD_RLY2                 0x08 /* External relay triggered */
  101. #define WD_SRLY2                0x80 /* Software external relay triggered */
  102. /*
  103.  *  Differences between cards regarding how they perform some operations
  104.  *  are handled by an array of structs, with per card functions for the
  105.  *  incompatible operations.  It's all defined here.
  106.  */
  107. /*  ENABLE/DISABLE the card  */
  108. typedef int (*fn_enable) (int); /* Enable/disable card */
  109. static int pcwd_enable_card (int enable); /* Actually works */
  110. static int pcwd_enable_nop (int enable); /* NOP - REV A cannot */
  111. /* Obtain firmware version, if possible */
  112. #define PCWD_FIRMWARE_BSZ 16 /* Version buffer size */
  113. typedef void (*fn_firmware) (char *bp);
  114. static void pcwd_firmware_ver_none (char *bp); /* REV A can't do it */
  115. static void pcwd_firmware_ver_revc (char *bp); /* REV C boards can */
  116. static void pcwd_firmware_ver_pci (char *bp); /* PCI boards can too */
  117. /*  Tickle the watchdog timer */
  118. typedef void (*fn_tickle) (void);
  119. static void pcwd_tickle_reva (void); /* Rev A only */
  120. static void pcwd_tickle (void); /* Rev C, PCI */
  121. /*  Determine reboot and temperature status */
  122. typedef int (*fn_status) (int reset_boot);
  123. static int pcwd_get_stat_reva (int reset_boot);
  124. static int pcwd_get_stat (int reset_boot);
  125. /*  Per card type specifications */
  126. typedef struct {
  127. fn_tickle wd_tickle; /* Reset the watchdog */
  128. fn_enable enable_card; /* Enable/disable card, if possible */
  129. fn_firmware firmware_ver; /* Get firmware version, if possible */
  130. fn_status wd_status; /* Card reset and/or over temp */
  131. int io_size; /* I/O space used */
  132. const char *name; /* Nice name to display */
  133. } PCWD_CARD_INFO;
  134. /* Per card information, indexed by card version ID */
  135. static PCWD_CARD_INFO pcwd_card_info[] = {
  136. {
  137.  pcwd_tickle_reva,
  138.  pcwd_enable_nop,
  139.  pcwd_firmware_ver_none,
  140.  pcwd_get_stat_reva,
  141.  2,
  142.  "Berkshire Products PC Watchdog (REV A)",
  143.  },
  144. {
  145.  pcwd_tickle,
  146.  pcwd_enable_card,
  147.  pcwd_firmware_ver_revc,
  148.  pcwd_get_stat,
  149.  4,
  150.  "Berkshire Products PC Watchdog (REV C)",
  151.  },
  152. {
  153.  pcwd_tickle,
  154.  pcwd_enable_card,
  155.  pcwd_firmware_ver_pci,
  156.  pcwd_get_stat,
  157.  8,
  158.  "Berkshire Products PC Watchdog (PCI)",
  159.  },
  160. };
  161. /*  Overall driver information, including per card pointer */
  162. static struct {
  163. PCWD_CARD_INFO *card_info; /* Points to one of the above */
  164. atomic_t open_allowed; /* Watchdog is single open */
  165. int flags; /* Defined below */
  166. int boot_status; /* Card status at boot time */
  167. int io_addr; /* Card's base address */
  168. } pcwd_info = {
  169. NULL, ATOMIC_INIT (1), 0, 0, 0};
  170. /*  Bits allocated in flags above. */
  171. #define PCWD_HAS_TEMP 0x0001 /* Set when thermometer available */
  172. #define PCWD_PCI_REG 0x0002 /* Set if PCI register code worked */
  173. #define PCWD_TEMP_PANIC 0x0004 /* Panic when over temperature */
  174. static spinlock_t io_lock;
  175. /* D E T E R M I N E   C A R D   S T A T U S   F U N C T I O N S  */
  176. /*   Rev A cards return status information from the base register,
  177.  * which is used for the temperature in other cards.  */
  178. static int
  179. pcwd_get_stat_reva (int reset_boot)
  180. {
  181. int retval;
  182. int status;
  183. spin_lock (&io_lock);
  184. status = inb_p (pcwd_info.io_addr);
  185. spin_unlock (&io_lock);
  186. /* Transform the card register to the ioctl bits we use internally */
  187. retval = WDIOF_MAGICCLOSE;
  188. if (status & WD_WDRST)
  189. retval |= WDIOF_CARDRESET;
  190. if (status & WD_T110)
  191. retval |= WDIOF_OVERHEAT;
  192. return retval;
  193. }
  194. /*
  195.  *  Rev C and PCI cards return card status in the base address + 1 register.
  196.  *  And use different bits to indicate a card initiated reset, and
  197.  *  an over-temperature condition.  And the reboot status can be reset.
  198.  */
  199. static int
  200. pcwd_get_stat (int reset_boot)
  201. {
  202. int retval;
  203. int status;
  204. spin_lock (&io_lock);
  205. status = inb_p (pcwd_info.io_addr + 1);
  206. if (reset_boot) {
  207. /*  NOTE:  the REV C card clears the "card caused reboot"
  208.  * flag when writing ANY value to this port.  However,
  209.  * the PCI card requires writing a 1 to bit 0.  */
  210. outb_p (0x01, pcwd_info.io_addr + 1);
  211. }
  212. spin_unlock (&io_lock);
  213. retval = 0;
  214. if (status & 0x01)
  215. retval |= WDIOF_CARDRESET;
  216. if (status & 0x04)
  217. retval |= WDIOF_OVERHEAT;
  218. return retval;
  219. }
  220. /*  W A T C H D O G   T I M E R   R E S E T   F U N C T I O N S   */
  221. /*  Rev A cards are reset by setting a specific bit in register 1.  */
  222. static void
  223. pcwd_tickle_reva (void)
  224. {
  225. int wdrst_stat;
  226. spin_lock (&io_lock);
  227. wdrst_stat = inb_p (pcwd_info.io_addr);
  228. wdrst_stat = (wdrst_stat & 0x0F) | WD_WDRST;
  229. outb_p (wdrst_stat, pcwd_info.io_addr + 1);
  230. spin_unlock (&io_lock);
  231. return;
  232. }
  233. /*  Other cards are reset by writing anything to the base register.  */
  234. static void
  235. pcwd_tickle (void)
  236. {
  237. spin_lock (&io_lock);
  238. outb_p (0x42, pcwd_info.io_addr);
  239. spin_unlock (&io_lock);
  240. return;
  241. }
  242. static int
  243. pcwd_ioctl (struct inode *inode, struct file *file,
  244.     unsigned int cmd, unsigned long arg)
  245. {
  246. int rv;
  247. int retval;
  248. static struct watchdog_info ident = {
  249. WDIOF_OVERHEAT | WDIOF_CARDRESET,
  250. 1,
  251. "PCWD"
  252. };
  253. switch (cmd) {
  254. case WDIOC_GETSUPPORT:
  255. rv = copy_to_user ((void *) arg, &ident, sizeof (ident));
  256. return rv ? -EFAULT : 0;
  257. case WDIOC_GETSTATUS:
  258. rv = pcwd_info.card_info->wd_status (0);
  259. if (rv & WDIOF_OVERHEAT) {
  260. if (pcwd_info.flags & PCWD_TEMP_PANIC)
  261. panic ("pcwd: Temperature overheat trip!n");
  262. }
  263. if (put_user (rv, (int *) arg))
  264. return -EFAULT;
  265. return 0;
  266. case WDIOC_GETBOOTSTATUS:
  267. rv = pcwd_info.boot_status;
  268. if (put_user (rv, (int *) arg))
  269. return -EFAULT;
  270. return 0;
  271. case WDIOC_GETTEMP:
  272. rv = 0;
  273. if (pcwd_info.flags & PCWD_HAS_TEMP) {
  274. spin_lock (&io_lock);
  275. rv = inb_p (pcwd_info.io_addr);
  276. spin_unlock (&io_lock);
  277. }
  278. if (put_user (rv, (int *) arg))
  279. return -EFAULT;
  280. return 0;
  281. case WDIOC_SETOPTIONS:
  282. if (copy_from_user (&rv, (int *) arg, sizeof (int)))
  283. return -EFAULT;
  284. retval = -EINVAL;
  285. if (rv & WDIOS_DISABLECARD) {
  286. if (!pcwd_info.card_info->enable_card (0)) {
  287. printk (KERN_EMERG
  288. "pcwd: Could not disable cardn");
  289. return -EIO;
  290. }
  291. retval = 0;
  292. }
  293. if (rv & WDIOS_ENABLECARD) {
  294. if (!pcwd_info.card_info->enable_card (1)) {
  295. printk (KERN_EMERG
  296. "pcwd: Could not enable cardn");
  297. return -EIO;
  298. }
  299. retval = 0;
  300. }
  301. if (rv & WDIOS_TEMPPANIC) {
  302. pcwd_info.flags |= PCWD_TEMP_PANIC;
  303. retval = 0;
  304. }
  305. return retval;
  306. case WDIOC_KEEPALIVE:
  307. pcwd_info.card_info->wd_tickle ();
  308. return 0;
  309. default:
  310. return -ENOTTY;
  311. }
  312. return 0;
  313. }
  314. /*   Write:  only for the watchdog device (thermometer is read-only).  */
  315. static ssize_t
  316. pcwd_write (struct file *file, const char *buf, size_t len, loff_t * ppos)
  317. {
  318. /*  Can't seek (pwrite) on this device  */
  319. if (ppos != &file->f_pos)
  320. return -ESPIPE;
  321. if (len) {
  322. if (!nowayout) {
  323. size_t i;
  324. /* In case it was set long ago */
  325. expect_close = 0;
  326. for (i = 0; i != len; i++) {
  327. char c;
  328. if (get_user(c, buf + i))
  329. return -EFAULT;
  330. if (c == 'V')
  331. expect_close = 1;
  332. }
  333. }
  334. pcwd_info.card_info->wd_tickle ();
  335. return 1;
  336. }
  337. return 0;
  338. }
  339. static int
  340. pcwd_open (struct inode *ino, struct file *filep)
  341. {
  342. switch (MINOR (ino->i_rdev)) {
  343. case WATCHDOG_MINOR:
  344. if (!atomic_dec_and_test (&pcwd_info.open_allowed)) {
  345. atomic_inc (&pcwd_info.open_allowed);
  346. return -EBUSY;
  347. }
  348. /*  Enable the card  */
  349. pcwd_info.card_info->enable_card (1);
  350. pcwd_info.card_info->wd_tickle ();
  351. return 0;
  352. case TEMP_MINOR:
  353. if (pcwd_info.flags & PCWD_HAS_TEMP) {
  354. return 0;
  355. }
  356. return -ENODEV;
  357. default:
  358. return -ENODEV;
  359. }
  360. }
  361. /* Read:  applies only to the thermometer (watchdog is write only).  */
  362. static ssize_t
  363. pcwd_read (struct file *file, char *buf, size_t count, loff_t * ppos)
  364. {
  365. unsigned short c;
  366. unsigned char cp;
  367. /*  Can't seek (pread) on this device  */
  368. if (ppos != &file->f_pos)
  369. return -ESPIPE;
  370. /*
  371.  * Convert celsius to fahrenheit, since this was
  372.  * the decided 'standard' for this return value.
  373.  */
  374. spin_lock (&io_lock);
  375. c = inb_p (pcwd_info.io_addr);
  376. spin_unlock (&io_lock);
  377. cp = (c * 9 / 5) + 32;
  378. if (copy_to_user (buf, &cp, 1))
  379. return -EFAULT;
  380. return 1;
  381. }
  382. static int
  383. pcwd_close (struct inode *ino, struct file *filep)
  384. {
  385. switch (MINOR (ino->i_rdev)) {
  386. case WATCHDOG_MINOR:
  387. if (expect_close)
  388. pcwd_info.card_info->enable_card (0);
  389. atomic_inc (&pcwd_info.open_allowed);
  390. break;
  391. case TEMP_MINOR:
  392. break;
  393. }
  394. return 0;
  395. }
  396. /*
  397.  *  System is shutting down, so disable the card.  Otherwise the timeout
  398.  * may expire during shutdown.  Of course, this means a hang during
  399.  * shutdown will not be reset, but somebody is probably nearby and will
  400.  * notice.  The alternative is to have the shutdown aborted when the
  401.  * watchdog expires and hits reset.
  402.  */
  403. static int
  404. pcwd_notify_sys (struct notifier_block *this, unsigned long code, void *unused)
  405. {
  406. if (code == SYS_DOWN || code == SYS_HALT) {
  407. /*
  408.  *  If initialisation is still in progress, the device pointer
  409.  * may not be valid, so check, just to make sure.
  410.  */
  411. if (pcwd_info.card_info)
  412. pcwd_info.card_info->enable_card (0);
  413. }
  414. return NOTIFY_DONE;
  415. }
  416. /*  C A R D   E N A B L E / D I S A B L E   F U N C T I O N S  */
  417. /*  Enable/disable the card, not REV A.  The two writes are required by card */
  418. static int
  419. pcwd_enable_card (int enable)
  420. {
  421. int stat_reg;
  422. spin_lock (&io_lock);
  423. if (enable) {
  424. outb_p (0x00, pcwd_info.io_addr + 3);
  425. } else {
  426. outb_p (0xA5, pcwd_info.io_addr + 3);
  427. outb_p (0xA5, pcwd_info.io_addr + 3);
  428. }
  429. stat_reg = inb_p (pcwd_info.io_addr + 2);
  430. spin_unlock (&io_lock);
  431. stat_reg &= 0x10; /* "disabled when set" bit */
  432. if (enable) {
  433. stat_reg ^= 0x10;
  434. }
  435. return stat_reg;
  436. }
  437. static int
  438. pcwd_enable_nop (int enable)
  439. {
  440. return 0;
  441. }
  442. static void __init
  443. set_card_type (int is_pci)
  444. {
  445. if (is_pci) {
  446. pcwd_info.card_info = &pcwd_card_info[PCWD_REV_PCI];
  447. pcwd_info.flags |= PCWD_PCI_REG;
  448. } else {
  449. pcwd_info.card_info = &pcwd_card_info[PCWD_REV_C];
  450. /* REV A cards use only 2 io ports; test
  451.  * presumes a floating bus reads as 0xff.  */
  452. if ((inb (pcwd_info.io_addr + 2) == 0xFF) ||
  453.     (inb (pcwd_info.io_addr + 3) == 0xFF)) {
  454. pcwd_info.card_info = &pcwd_card_info[PCWD_REV_A];
  455. }
  456. }
  457. return;
  458. }
  459. /* G E T    F I R M W A R E   V E R S I O N   F U N C T I O N S    */
  460. /* REV A can't do it */
  461. static void __init
  462. pcwd_firmware_ver_none (char *bp)
  463. {
  464. strncpy (bp, "<unavailable>", PCWD_FIRMWARE_BSZ);
  465. return;
  466. }
  467. /* PCI boards can too */
  468. static void __init
  469. pcwd_firmware_ver_pci (char *bp)
  470. {
  471. int count;
  472. /* Write the 'Get Firmware Version' command to port 6 and wait */
  473. outb (0x08, pcwd_info.io_addr + 6);
  474. /* Card sets bit 0x40 (WRSP) bit in port 2.  Can take 10ms! */
  475. for (count = 0; count < 15; ++count) {
  476. mdelay (1); /* Board responds slowly */
  477. if (inb (pcwd_info.io_addr + 2) & 0x40) {
  478. /* Board says data now valid */
  479. snprintf (bp, PCWD_FIRMWARE_BSZ, "%u.%u",
  480.   inb (pcwd_info.io_addr + 5),
  481.   inb (pcwd_info.io_addr + 4));
  482. return;
  483. }
  484. }
  485. strncpy (bp, "<card no answer>", PCWD_FIRMWARE_BSZ);
  486. return;
  487. }
  488. /*
  489.  *   REV C boards read diagnostic (including firmware version) data
  490.  * from the register 0.  To do this, the card is put into diagnostic
  491.  * mode, then the command is submitted and data read from register 0.
  492.  * NOTE:  the onboard processor writes 4 bits at a time to the register,
  493.  * so it's necessary to wait for the data to stabilise before
  494.  * accepting it.
  495.  */
  496. static int __init
  497. send_command (int cmd)
  498. {
  499. int ii;
  500. int reg0, last_reg0; /* Double read for stabilising */
  501. outb (cmd, pcwd_info.io_addr + 2);
  502. /*
  503.  *    The following delay need only be 200 microseconds according
  504.  *  to the spec I have.  But my card seems slower, as waiting
  505.  *  250 microseconds returns valid data, but NOT from this
  506.  *  command.  The 1000 value may be excessive, but is reliable.
  507.  */
  508. mdelay (1);
  509. reg0 = inb (pcwd_info.io_addr);
  510. for (ii = 0; ii < 25; ++ii) {
  511. last_reg0 = reg0;
  512. reg0 = inb (pcwd_info.io_addr);
  513. if (reg0 == last_reg0)
  514. break; /* Data is stable */
  515. udelay (250);
  516. }
  517. return reg0;
  518. }
  519. /*  REV C board function to retrieve firmware version */
  520. static void __init
  521. pcwd_firmware_ver_revc (char *bp)
  522. {
  523. int i, found = 0, count = 0;
  524. /*  Set the card into debug mode to find firmware version */
  525. outb_p (0x00, pcwd_info.io_addr + 2); /* Spec says to do this */
  526. udelay (500);
  527. while ((count < 3) && (!found)) {
  528. i = send_command (0x80);
  529. if (i == 0x00) {
  530. found = 1;
  531. break;
  532. } else if (i == 0xF3) {
  533. /* Card does not like what we've done to it */
  534. outb_p (0x00, pcwd_info.io_addr + 2);
  535. udelay (1200); /* Spec says wait 1ms */
  536. outb_p (0x00, pcwd_info.io_addr + 2);
  537. udelay (500);
  538. }
  539. count++;
  540. }
  541. if (found) {
  542. *bp++ = send_command (0x81);
  543. *bp++ = '.';
  544. *bp++ = send_command (0x82);
  545. *bp++ = send_command (0x83);
  546. *bp++ = send_command (0x84);
  547. *bp++ = '';
  548. /* Out of debug mode */
  549. outb (0x00, pcwd_info.io_addr + 2);
  550. } else
  551. strncpy (bp, "<err - no go>", PCWD_FIRMWARE_BSZ);
  552. return;
  553. }
  554. /*   Initialisation function called ONLY from the PCI layer.  */
  555. static int __init
  556. pcwd_init_one (struct pci_dev *dev, const struct pci_device_id *ent)
  557. {
  558. static int devices = 0;
  559. ++devices;
  560. if (devices > 1) {
  561. printk (KERN_ERR "pcwd: Driver supports only ONE devicen");
  562. return -ENODEV;
  563. }
  564. pcwd_info.io_addr = pci_resource_start (dev, 0);
  565. if (pcwd_info.io_addr == 0 || pci_enable_device (dev))
  566. return -ENODEV;
  567. return 0;
  568. }
  569. static struct pci_device_id pcwd_pci_tbl[] __initdata = {
  570. {PCI_VENDOR_ID_QUICKLOGIC, PCI_DEVICE_ID_BERKSHIRE,
  571.  PCI_ANY_ID, PCI_ANY_ID,},
  572. {0}, /* End of list */
  573. };
  574. MODULE_DEVICE_TABLE (pci, pcwd_pci_tbl);
  575. static struct pci_driver pcwd_driver = {
  576. name:"pcwd",
  577. id_table:pcwd_pci_tbl,
  578. probe:pcwd_init_one,
  579. };
  580. static struct file_operations pcwd_fops = {
  581. owner:THIS_MODULE,
  582. write:pcwd_write,
  583. ioctl:pcwd_ioctl,
  584. open:pcwd_open,
  585. release:pcwd_close,
  586. };
  587. static struct miscdevice pcwd_miscdev = {
  588. WATCHDOG_MINOR,
  589. "watchdog",
  590. &pcwd_fops
  591. };
  592. static struct file_operations pcwd_temp_fops = {
  593. owner:THIS_MODULE,
  594. read:pcwd_read,
  595. open:pcwd_open,
  596. release:pcwd_close,
  597. };
  598. static struct miscdevice temp_miscdev = {
  599. TEMP_MINOR,
  600. "temperature",
  601. &pcwd_temp_fops
  602. };
  603. /* Need to know about shutdown to kill the timer - may reset during shutdown! */
  604.     static struct notifier_block pcwd_notifier =
  605. {
  606. pcwd_notify_sys,
  607. NULL,
  608. 0,
  609. };
  610. /*
  611.  *   The ISA cards have a heartbeat bit in one of the registers, which
  612.  *  register is card dependent.  The heartbeat bit is monitored, and if
  613.  *  found, is considered proof that a Berkshire card has been found.
  614.  *  The initial rate is once per second at board start up, then twice
  615.  *  per second for normal operation.
  616.  */
  617. static int __init
  618. check_isa_card (int base_addr)
  619. {
  620. int reg0, last_reg0; /* Reg 0, in case it's REV A */
  621. int reg1, last_reg1; /* Register 1 for REV C cards */
  622. int ii;
  623. int retval;
  624. /* As suggested by Alan Cox - this is a safety measure. */
  625. if (!request_region (base_addr, 4, "pcwd-isa")) {
  626. printk (KERN_INFO "pcwd: Port 0x%x unavailablen", base_addr);
  627. return 0;
  628. }
  629. retval = 0;
  630. reg0 = inb_p (base_addr); /* For REV A boards */
  631. reg1 = inb (base_addr + 1); /* For REV C boards */
  632. if (reg0 != 0xff || reg1 != 0xff) {
  633. /* Not an 'ff' from a floating bus, so must be a card! */
  634. for (ii = 0; ii < timeout_val; ++ii) {
  635. set_current_state (TASK_INTERRUPTIBLE);
  636. schedule_timeout (HZ / 2);
  637. last_reg0 = reg0;
  638. last_reg1 = reg1;
  639. reg0 = inb_p (base_addr);
  640. reg1 = inb (base_addr + 1);
  641. /* Has either hearbeat bit changed?  */
  642. if ((reg0 ^ last_reg0) & WD_HRTBT ||
  643.     (reg1 ^ last_reg1) & 0x02) {
  644. retval = 1;
  645. break;
  646. }
  647. }
  648. }
  649. release_region (base_addr, 4);
  650. return retval;
  651. }
  652. static int __init
  653. pcwd_card_init (void)
  654. {
  655. int retval;
  656. char fvbuf[PCWD_FIRMWARE_BSZ];
  657. pcwd_info.card_info->firmware_ver (fvbuf);
  658. printk (KERN_INFO "pcwd: %s at port 0x%03x (Firmware: %s)n",
  659. pcwd_info.card_info->name, pcwd_info.io_addr, fvbuf);
  660. /* Returns 0xf0 in temperature register if no thermometer */
  661. if (inb (pcwd_info.io_addr) != 0xF0) {
  662. pcwd_info.flags |= PCWD_HAS_TEMP;
  663. printk (KERN_INFO "pcwd: Temperature option detectedn");
  664. }
  665. if (nowayout)
  666. printk (KERN_INFO
  667. "pcwd: Watchdog cannot be stopped once startedn");
  668. /* Record the power up status of "card did reset" and/or temp trip */
  669. pcwd_info.boot_status = pcwd_info.card_info->wd_status (1);
  670. if (pcwd_info.boot_status & WDIOF_CARDRESET)
  671. printk (KERN_INFO
  672. "pcwd: Previous reboot was caused by the cardn");
  673. if (pcwd_info.boot_status & WDIOF_OVERHEAT) {
  674. printk (KERN_EMERG
  675. "pcwd: Card senses a CPU Overheat.  Panicking!n");
  676. panic ("pcwd: CPU Overheatn");
  677. }
  678. if (pcwd_info.boot_status == 0)
  679. printk (KERN_INFO "pcwd: Cold boot sensen");
  680. pcwd_info.card_info->enable_card (0);
  681. retval = 0;
  682. if (!request_region (pcwd_info.io_addr,
  683.      pcwd_info.card_info->io_size,
  684.      pcwd_info.card_info->name)) {
  685. printk (KERN_ERR "pcwd: I/0 %d is not freen",
  686. pcwd_info.io_addr);
  687. return retval;
  688. }
  689. retval = misc_register (&pcwd_miscdev);
  690. if (retval) {
  691. release_region (pcwd_info.io_addr,
  692. pcwd_info.card_info->io_size);
  693. printk (KERN_ERR "pcwd: can't misc_register on minor %dn",
  694. WATCHDOG_MINOR);
  695. return retval;
  696. }
  697. if (pcwd_info.flags & PCWD_HAS_TEMP) {
  698. if (misc_register (&temp_miscdev)) {
  699. printk (KERN_ERR
  700. "pwcd: can't misc_register thermometer - disabling itn");
  701. pcwd_info.flags &= ~PCWD_HAS_TEMP;
  702. }
  703. }
  704. retval = register_reboot_notifier (&pcwd_notifier);
  705. if (retval) {
  706. if (pcwd_info.flags & PCWD_HAS_TEMP)
  707. misc_deregister (&temp_miscdev);
  708. misc_deregister (&pcwd_miscdev);
  709. release_region (pcwd_info.io_addr,
  710. pcwd_info.card_info->io_size);
  711. }
  712. return retval;
  713. }
  714. static int __init
  715. pcwatchdog_init (void)
  716. {
  717. int i, found = 0;
  718. /*
  719.  * ISA card auto-probe addresses available.  Last one is only
  720.  * available on REV C cards.
  721.  */
  722. static int pcwd_ioports[] = { 0x270, 0x350, 0x370 };
  723. #define PCWD_NUM_ADDR (sizeof(pcwd_ioports)/sizeof(pcwd_ioports[0]))
  724. timeout_val = timeout * 2;
  725. spin_lock_init (&io_lock);
  726. printk (KERN_INFO "pcwd: v%s Ken Hollis (kenji@bitgate.com)n", WD_VER);
  727. if (pci_register_driver (&pcwd_driver) > 0) {
  728. found = 1;
  729. set_card_type (1); /* Set to PCI card model */
  730. } else {
  731. /* No PCI entry, try the ISA addresses.  */
  732. for (i = 0; i < PCWD_NUM_ADDR; i++) {
  733. if (check_isa_card (pcwd_ioports[i])) {
  734. found = 1;
  735. pcwd_info.io_addr = pcwd_ioports[i];
  736. set_card_type (0);
  737. break;
  738. }
  739. }
  740. }
  741. if (!found) {
  742. printk (KERN_INFO
  743. "pcwd: No card detected, or port not availablen");
  744. return -EIO;
  745. }
  746. return pcwd_card_init ();
  747. }
  748. static void __exit
  749. pcwatchdog_exit (void)
  750. {
  751. unregister_reboot_notifier (&pcwd_notifier);
  752. misc_deregister (&pcwd_miscdev);
  753. if (!nowayout)
  754. pcwd_info.card_info->enable_card (0);
  755. if (pcwd_info.flags & PCWD_HAS_TEMP)
  756. misc_deregister (&temp_miscdev);
  757. release_region (pcwd_info.io_addr, pcwd_info.card_info->io_size);
  758. if (pcwd_info.flags & PCWD_PCI_REG)
  759. pci_unregister_driver (&pcwd_driver);
  760. return;
  761. }
  762. module_init (pcwatchdog_init);
  763. module_exit (pcwatchdog_exit);
  764. MODULE_LICENSE ("GPL");
  765. EXPORT_NO_SYMBOLS;