Skip to content

Commit

Permalink
[WATCHDOG] pcwd.c: Port to the new device driver model
Browse files Browse the repository at this point in the history
Port the pcwd.c driver to the new device driver model.
Since this is an ISA card, I used Rene Herman's new isa bus type.
This made the probing for the card very "easy".

Signed-off-by: Wim Van Sebroeck <wim@iguana.be>
  • Loading branch information
Wim Van Sebroeck committed May 5, 2007
1 parent 9f7afa6 commit 5aa1505
Showing 1 changed file with 120 additions and 122 deletions.
242 changes: 120 additions & 122 deletions drivers/char/watchdog/pcwd.c
Original file line number Diff line number Diff line change
Expand Up @@ -59,19 +59,19 @@
#include <linux/jiffies.h> /* For jiffies stuff */
#include <linux/miscdevice.h> /* For MODULE_ALIAS_MISCDEV(WATCHDOG_MINOR) */
#include <linux/watchdog.h> /* For the watchdog specific items */
#include <linux/notifier.h> /* For notifier support */
#include <linux/reboot.h> /* For reboot_notifier stuff */
#include <linux/reboot.h> /* For kernel_power_off() */
#include <linux/init.h> /* For __init/__exit/... */
#include <linux/fs.h> /* For file operations */
#include <linux/isa.h> /* For isa devices */
#include <linux/ioport.h> /* For io-port access */
#include <linux/spinlock.h> /* For spin_lock/spin_unlock/... */

#include <asm/uaccess.h> /* For copy_to_user/put_user/... */
#include <asm/io.h> /* For inb/outb/... */

/* Module and version information */
#define WATCHDOG_VERSION "1.18"
#define WATCHDOG_DATE "21 Jan 2007"
#define WATCHDOG_VERSION "1.20"
#define WATCHDOG_DATE "18 Feb 2007"
#define WATCHDOG_DRIVER_NAME "ISA-PC Watchdog"
#define WATCHDOG_NAME "pcwd"
#define PFX WATCHDOG_NAME ": "
Expand All @@ -88,6 +88,15 @@
#define PCWD_REVISION_A 1
#define PCWD_REVISION_C 2

/*
* These are the auto-probe addresses available.
*
* Revision A only uses ports 0x270 and 0x370. Revision C introduced 0x350.
* Revision A has an address range of 2 addresses, while Revision C has 4.
*/
#define PCWD_ISA_NR_CARDS 3
static int pcwd_ioports[] = { 0x270, 0x350, 0x370, 0x000 };

/*
* These are the defines that describe the control status bits for the
* PCI-PC Watchdog card.
Expand Down Expand Up @@ -485,7 +494,7 @@ static int pcwd_get_status(int *status)
if (control_status & WD_T110) {
*status |= WDIOF_OVERHEAT;
if (temp_panic) {
printk (KERN_INFO PFX "Temperature overheat trip!\n");
printk(KERN_INFO PFX "Temperature overheat trip!\n");
kernel_power_off();
/* or should we just do a: panic(PFX "Temperature overheat trip!\n"); */
}
Expand All @@ -497,7 +506,7 @@ static int pcwd_get_status(int *status)
if (control_status & WD_REVC_TTRP) {
*status |= WDIOF_OVERHEAT;
if (temp_panic) {
printk (KERN_INFO PFX "Temperature overheat trip!\n");
printk(KERN_INFO PFX "Temperature overheat trip!\n");
kernel_power_off();
/* or should we just do a: panic(PFX "Temperature overheat trip!\n"); */
}
Expand Down Expand Up @@ -733,20 +742,6 @@ static int pcwd_temp_close(struct inode *inode, struct file *file)
return 0;
}

/*
* Notify system
*/

static int pcwd_notify_sys(struct notifier_block *this, unsigned long code, void *unused)
{
if (code==SYS_DOWN || code==SYS_HALT) {
/* Turn the WDT off */
pcwd_stop();
}

return NOTIFY_DONE;
}

/*
* Kernel Interfaces
*/
Expand Down Expand Up @@ -780,10 +775,6 @@ static struct miscdevice temp_miscdev = {
.fops = &pcwd_temp_fops,
};

static struct notifier_block pcwd_notifier = {
.notifier_call = pcwd_notify_sys,
};

/*
* Init & exit routines
*/
Expand All @@ -803,10 +794,67 @@ static inline int get_revision(void)
return r;
}

static int __devinit pcwatchdog_init(int base_addr)
/*
* The ISA cards have a heartbeat bit in one of the registers, which
* register is card dependent. The heartbeat bit is monitored, and if
* found, is considered proof that a Berkshire card has been found.
* The initial rate is once per second at board start up, then twice
* per second for normal operation.
*/
static int __devinit pcwd_isa_match(struct device *dev, unsigned int id)
{
int base_addr=pcwd_ioports[id];
int port0, last_port0; /* Reg 0, in case it's REV A */
int port1, last_port1; /* Register 1 for REV C cards */
int i;
int retval;

if (debug >= DEBUG)
printk(KERN_DEBUG PFX "pcwd_isa_match id=%d\n",
id);

if (!request_region (base_addr, 4, "PCWD")) {
printk(KERN_INFO PFX "Port 0x%04x unavailable\n", base_addr);
return 0;
}

retval = 0;

port0 = inb_p(base_addr); /* For REV A boards */
port1 = inb_p(base_addr + 1); /* For REV C boards */
if (port0 != 0xff || port1 != 0xff) {
/* Not an 'ff' from a floating bus, so must be a card! */
for (i = 0; i < 4; ++i) {

msleep(500);

last_port0 = port0;
last_port1 = port1;

port0 = inb_p(base_addr);
port1 = inb_p(base_addr + 1);

/* Has either hearbeat bit changed? */
if ((port0 ^ last_port0) & WD_HRTBT ||
(port1 ^ last_port1) & WD_REVC_HRBT) {
retval = 1;
break;
}
}
}
release_region (base_addr, 4);

return retval;
}

static int __devinit pcwd_isa_probe(struct device *dev, unsigned int id)
{
int ret;

if (debug >= DEBUG)
printk(KERN_DEBUG PFX "pcwd_isa_probe id=%d\n",
id);

cards_found++;
if (cards_found == 1)
printk(KERN_INFO PFX "v%s Ken Hollis (kenji@bitgate.com)\n", WD_VER);
Expand All @@ -816,20 +864,22 @@ static int __devinit pcwatchdog_init(int base_addr)
return -ENODEV;
}

if (base_addr == 0x0000) {
if (pcwd_ioports[id] == 0x0000) {
printk(KERN_ERR PFX "No I/O-Address for card detected\n");
return -ENODEV;
}
pcwd_private.io_addr = base_addr;
pcwd_private.io_addr = pcwd_ioports[id];

spin_lock_init(&pcwd_private.io_lock);

/* Check card's revision */
pcwd_private.revision = get_revision();

if (!request_region(pcwd_private.io_addr, (pcwd_private.revision == PCWD_REVISION_A) ? 2 : 4, "PCWD")) {
printk(KERN_ERR PFX "I/O address 0x%04x already in use\n",
pcwd_private.io_addr);
pcwd_private.io_addr = 0x0000;
return -EIO;
ret=-EIO;
goto error_request_region;
}

/* Initial variables */
Expand Down Expand Up @@ -865,47 +915,47 @@ static int __devinit pcwatchdog_init(int base_addr)
WATCHDOG_HEARTBEAT);
}

ret = register_reboot_notifier(&pcwd_notifier);
if (ret) {
printk(KERN_ERR PFX "cannot register reboot notifier (err=%d)\n",
ret);
release_region(pcwd_private.io_addr, (pcwd_private.revision == PCWD_REVISION_A) ? 2 : 4);
pcwd_private.io_addr = 0x0000;
return ret;
}

if (pcwd_private.supports_temp) {
ret = misc_register(&temp_miscdev);
if (ret) {
printk(KERN_ERR PFX "cannot register miscdev on minor=%d (err=%d)\n",
TEMP_MINOR, ret);
unregister_reboot_notifier(&pcwd_notifier);
release_region(pcwd_private.io_addr, (pcwd_private.revision == PCWD_REVISION_A) ? 2 : 4);
pcwd_private.io_addr = 0x0000;
return ret;
goto error_misc_register_temp;
}
}

ret = misc_register(&pcwd_miscdev);
if (ret) {
printk(KERN_ERR PFX "cannot register miscdev on minor=%d (err=%d)\n",
WATCHDOG_MINOR, ret);
if (pcwd_private.supports_temp)
misc_deregister(&temp_miscdev);
unregister_reboot_notifier(&pcwd_notifier);
release_region(pcwd_private.io_addr, (pcwd_private.revision == PCWD_REVISION_A) ? 2 : 4);
pcwd_private.io_addr = 0x0000;
return ret;
goto error_misc_register_watchdog;
}

printk(KERN_INFO PFX "initialized. heartbeat=%d sec (nowayout=%d)\n",
heartbeat, nowayout);

return 0;

error_misc_register_watchdog:
if (pcwd_private.supports_temp)
misc_deregister(&temp_miscdev);
error_misc_register_temp:
release_region(pcwd_private.io_addr, (pcwd_private.revision == PCWD_REVISION_A) ? 2 : 4);
error_request_region:
pcwd_private.io_addr = 0x0000;
cards_found--;
return ret;
}

static void __devexit pcwatchdog_exit(void)
static int __devexit pcwd_isa_remove(struct device *dev, unsigned int id)
{
if (debug >= DEBUG)
printk(KERN_DEBUG PFX "pcwd_isa_remove id=%d\n",
id);

if (!pcwd_private.io_addr)
return 1;

/* Disable the board */
if (!nowayout)
pcwd_stop();
Expand All @@ -914,102 +964,50 @@ static void __devexit pcwatchdog_exit(void)
misc_deregister(&pcwd_miscdev);
if (pcwd_private.supports_temp)
misc_deregister(&temp_miscdev);
unregister_reboot_notifier(&pcwd_notifier);
release_region(pcwd_private.io_addr, (pcwd_private.revision == PCWD_REVISION_A) ? 2 : 4);
pcwd_private.io_addr = 0x0000;
cards_found--;

return 0;
}

/*
* The ISA cards have a heartbeat bit in one of the registers, which
* register is card dependent. The heartbeat bit is monitored, and if
* found, is considered proof that a Berkshire card has been found.
* The initial rate is once per second at board start up, then twice
* per second for normal operation.
*/
static int __init pcwd_checkcard(int base_addr)
static void pcwd_isa_shutdown(struct device *dev, unsigned int id)
{
int port0, last_port0; /* Reg 0, in case it's REV A */
int port1, last_port1; /* Register 1 for REV C cards */
int i;
int retval;

if (!request_region (base_addr, 4, "PCWD")) {
printk (KERN_INFO PFX "Port 0x%04x unavailable\n", base_addr);
return 0;
}

retval = 0;

port0 = inb_p(base_addr); /* For REV A boards */
port1 = inb_p(base_addr + 1); /* For REV C boards */
if (port0 != 0xff || port1 != 0xff) {
/* Not an 'ff' from a floating bus, so must be a card! */
for (i = 0; i < 4; ++i) {

msleep(500);

last_port0 = port0;
last_port1 = port1;

port0 = inb_p(base_addr);
port1 = inb_p(base_addr + 1);

/* Has either hearbeat bit changed? */
if ((port0 ^ last_port0) & WD_HRTBT ||
(port1 ^ last_port1) & WD_REVC_HRBT) {
retval = 1;
break;
}
}
}
release_region (base_addr, 4);
if (debug >= DEBUG)
printk(KERN_DEBUG PFX "pcwd_isa_shutdown id=%d\n",
id);

return retval;
pcwd_stop();
}

/*
* These are the auto-probe addresses available.
*
* Revision A only uses ports 0x270 and 0x370. Revision C introduced 0x350.
* Revision A has an address range of 2 addresses, while Revision C has 4.
*/
static int pcwd_ioports[] = { 0x270, 0x350, 0x370, 0x000 };
static struct isa_driver pcwd_isa_driver = {
.match = pcwd_isa_match,
.probe = pcwd_isa_probe,
.remove = __devexit_p(pcwd_isa_remove),
.shutdown = pcwd_isa_shutdown,
.driver = {
.owner = THIS_MODULE,
.name = WATCHDOG_NAME,
},
};

static int __init pcwd_init_module(void)
{
int i, found = 0;

spin_lock_init(&pcwd_private.io_lock);

for (i = 0; pcwd_ioports[i] != 0; i++) {
if (pcwd_checkcard(pcwd_ioports[i])) {
if (!(pcwatchdog_init(pcwd_ioports[i])))
found++;
}
}

if (!found) {
printk (KERN_INFO PFX "No card detected, or port not available\n");
return -ENODEV;
}

return 0;
return isa_register_driver(&pcwd_isa_driver, PCWD_ISA_NR_CARDS);
}

static void __exit pcwd_cleanup_module(void)
{
if (pcwd_private.io_addr)
pcwatchdog_exit();

isa_unregister_driver(&pcwd_isa_driver);
printk(KERN_INFO PFX "Watchdog Module Unloaded.\n");
}

module_init(pcwd_init_module);
module_exit(pcwd_cleanup_module);

MODULE_AUTHOR("Ken Hollis <kenji@bitgate.com>");
MODULE_AUTHOR("Ken Hollis <kenji@bitgate.com>, Wim Van Sebroeck <wim@iguana.be>");
MODULE_DESCRIPTION("Berkshire ISA-PC Watchdog driver");
MODULE_VERSION(WATCHDOG_VERSION);
MODULE_LICENSE("GPL");
MODULE_ALIAS_MISCDEV(WATCHDOG_MINOR);
MODULE_ALIAS_MISCDEV(TEMP_MINOR);

0 comments on commit 5aa1505

Please sign in to comment.