diff options
Diffstat (limited to 'drivers/watchdog/sc1200wdt.c')
| -rw-r--r-- | drivers/watchdog/sc1200wdt.c | 231 |
1 files changed, 124 insertions, 107 deletions
diff --git a/drivers/watchdog/sc1200wdt.c b/drivers/watchdog/sc1200wdt.c index 35cddff7020..131193a7acd 100644 --- a/drivers/watchdog/sc1200wdt.c +++ b/drivers/watchdog/sc1200wdt.c @@ -15,18 +15,24 @@ * * Changelog: * 20020220 Zwane Mwaikambo Code based on datasheet, no hardware. - * 20020221 Zwane Mwaikambo Cleanups as suggested by Jeff Garzik and Alan Cox. + * 20020221 Zwane Mwaikambo Cleanups as suggested by Jeff Garzik + * and Alan Cox. * 20020222 Zwane Mwaikambo Added probing. * 20020225 Zwane Mwaikambo Added ISAPNP support. * 20020412 Rob Radez Broke out start/stop functions - * <rob@osinvestor.com> Return proper status instead of temperature warning - * Add WDIOC_GETBOOTSTATUS and WDIOC_SETOPTIONS ioctls + * <rob@osinvestor.com> Return proper status instead of + * temperature warning + * Add WDIOC_GETBOOTSTATUS and + * WDIOC_SETOPTIONS ioctls * Fix CONFIG_WATCHDOG_NOWAYOUT - * 20020530 Joel Becker Add Matt Domsch's nowayout module option + * 20020530 Joel Becker Add Matt Domsch's nowayout module + * option * 20030116 Adam Belay Updated to the latest pnp code * */ +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt + #include <linux/module.h> #include <linux/moduleparam.h> #include <linux/miscdevice.h> @@ -39,13 +45,11 @@ #include <linux/pnp.h> #include <linux/fs.h> #include <linux/semaphore.h> - -#include <asm/io.h> -#include <asm/uaccess.h> +#include <linux/io.h> +#include <linux/uaccess.h> #define SC1200_MODULE_VER "build 20020303" #define SC1200_MODULE_NAME "sc1200wdt" -#define PFX SC1200_MODULE_NAME ": " #define MAX_TIMEOUT 255 /* 255 minutes */ #define PMIR (io) /* Power Management Index Register */ @@ -68,11 +72,10 @@ #define UART2_IRQ 0x04 /* Serial1 */ /* 5 -7 are reserved */ -static char banner[] __initdata = KERN_INFO PFX SC1200_MODULE_VER; static int timeout = 1; static int io = -1; static int io_len = 2; /* for non plug and play */ -static struct semaphore open_sem; +static unsigned long open_flag; static char expect_close; static DEFINE_SPINLOCK(sc1200wdt_lock); /* io port access serialisation */ @@ -81,7 +84,8 @@ static int isapnp = 1; static struct pnp_dev *wdt_dev; module_param(isapnp, int, 0); -MODULE_PARM_DESC(isapnp, "When set to 0 driver ISA PnP support will be disabled"); +MODULE_PARM_DESC(isapnp, + "When set to 0 driver ISA PnP support will be disabled"); #endif module_param(io, int, 0); @@ -89,28 +93,42 @@ MODULE_PARM_DESC(io, "io port"); module_param(timeout, int, 0); MODULE_PARM_DESC(timeout, "range is 0-255 minutes, default is 1"); -static int nowayout = WATCHDOG_NOWAYOUT; -module_param(nowayout, int, 0); -MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default=" __MODULE_STRING(WATCHDOG_NOWAYOUT) ")"); +static bool nowayout = WATCHDOG_NOWAYOUT; +module_param(nowayout, bool, 0); +MODULE_PARM_DESC(nowayout, + "Watchdog cannot be stopped once started (default=" + __MODULE_STRING(WATCHDOG_NOWAYOUT) ")"); /* Read from Data Register */ -static inline void sc1200wdt_read_data(unsigned char index, unsigned char *data) +static inline void __sc1200wdt_read_data(unsigned char index, + unsigned char *data) { - spin_lock(&sc1200wdt_lock); outb_p(index, PMIR); *data = inb(PMDR); - spin_unlock(&sc1200wdt_lock); } +static void sc1200wdt_read_data(unsigned char index, unsigned char *data) +{ + spin_lock(&sc1200wdt_lock); + __sc1200wdt_read_data(index, data); + spin_unlock(&sc1200wdt_lock); +} /* Write to Data Register */ -static inline void sc1200wdt_write_data(unsigned char index, unsigned char data) +static inline void __sc1200wdt_write_data(unsigned char index, + unsigned char data) { - spin_lock(&sc1200wdt_lock); outb_p(index, PMIR); outb(data, PMDR); +} + +static inline void sc1200wdt_write_data(unsigned char index, + unsigned char data) +{ + spin_lock(&sc1200wdt_lock); + __sc1200wdt_write_data(index, data); spin_unlock(&sc1200wdt_lock); } @@ -118,22 +136,23 @@ static inline void sc1200wdt_write_data(unsigned char index, unsigned char data) static void sc1200wdt_start(void) { unsigned char reg; + spin_lock(&sc1200wdt_lock); - sc1200wdt_read_data(WDCF, ®); + __sc1200wdt_read_data(WDCF, ®); /* assert WDO when any of the following interrupts are triggered too */ reg |= (KBC_IRQ | MSE_IRQ | UART1_IRQ | UART2_IRQ); - sc1200wdt_write_data(WDCF, reg); + __sc1200wdt_write_data(WDCF, reg); /* set the timeout and get the ball rolling */ - sc1200wdt_write_data(WDTO, timeout); -} + __sc1200wdt_write_data(WDTO, timeout); + spin_unlock(&sc1200wdt_lock); +} static void sc1200wdt_stop(void) { sc1200wdt_write_data(WDTO, 0); } - /* This returns the status of the WDO signal, inactive high. */ static inline int sc1200wdt_status(void) { @@ -144,91 +163,89 @@ static inline int sc1200wdt_status(void) * KEEPALIVEPING which is a bit of a kludge because there's nothing * else for enabled/disabled status */ - return (ret & 0x01) ? 0 : WDIOF_KEEPALIVEPING; /* bits 1 - 7 are undefined */ + return (ret & 0x01) ? 0 : WDIOF_KEEPALIVEPING; } - static int sc1200wdt_open(struct inode *inode, struct file *file) { /* allow one at a time */ - if (down_trylock(&open_sem)) + if (test_and_set_bit(0, &open_flag)) return -EBUSY; if (timeout > MAX_TIMEOUT) timeout = MAX_TIMEOUT; sc1200wdt_start(); - printk(KERN_INFO PFX "Watchdog enabled, timeout = %d min(s)", timeout); + pr_info("Watchdog enabled, timeout = %d min(s)", timeout); return nonseekable_open(inode, file); } -static int sc1200wdt_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg) +static long sc1200wdt_ioctl(struct file *file, unsigned int cmd, + unsigned long arg) { int new_timeout; void __user *argp = (void __user *)arg; int __user *p = argp; - static struct watchdog_info ident = { - .options = WDIOF_KEEPALIVEPING | WDIOF_SETTIMEOUT | WDIOF_MAGICCLOSE, + static const struct watchdog_info ident = { + .options = WDIOF_KEEPALIVEPING | WDIOF_SETTIMEOUT | + WDIOF_MAGICCLOSE, .firmware_version = 0, .identity = "PC87307/PC97307", }; switch (cmd) { - default: - return -ENOTTY; + case WDIOC_GETSUPPORT: + if (copy_to_user(argp, &ident, sizeof(ident))) + return -EFAULT; + return 0; - case WDIOC_GETSUPPORT: - if (copy_to_user(argp, &ident, sizeof ident)) - return -EFAULT; - return 0; + case WDIOC_GETSTATUS: + return put_user(sc1200wdt_status(), p); - case WDIOC_GETSTATUS: - return put_user(sc1200wdt_status(), p); + case WDIOC_GETBOOTSTATUS: + return put_user(0, p); - case WDIOC_GETBOOTSTATUS: - return put_user(0, p); + case WDIOC_SETOPTIONS: + { + int options, retval = -EINVAL; - case WDIOC_KEEPALIVE: - sc1200wdt_write_data(WDTO, timeout); - return 0; + if (get_user(options, p)) + return -EFAULT; - case WDIOC_SETTIMEOUT: - if (get_user(new_timeout, p)) - return -EFAULT; - - /* the API states this is given in secs */ - new_timeout /= 60; - if (new_timeout < 0 || new_timeout > MAX_TIMEOUT) - return -EINVAL; - - timeout = new_timeout; - sc1200wdt_write_data(WDTO, timeout); - /* fall through and return the new timeout */ - - case WDIOC_GETTIMEOUT: - return put_user(timeout * 60, p); + if (options & WDIOS_DISABLECARD) { + sc1200wdt_stop(); + retval = 0; + } - case WDIOC_SETOPTIONS: - { - int options, retval = -EINVAL; + if (options & WDIOS_ENABLECARD) { + sc1200wdt_start(); + retval = 0; + } - if (get_user(options, p)) - return -EFAULT; + return retval; + } + case WDIOC_KEEPALIVE: + sc1200wdt_write_data(WDTO, timeout); + return 0; + + case WDIOC_SETTIMEOUT: + if (get_user(new_timeout, p)) + return -EFAULT; + /* the API states this is given in secs */ + new_timeout /= 60; + if (new_timeout < 0 || new_timeout > MAX_TIMEOUT) + return -EINVAL; + timeout = new_timeout; + sc1200wdt_write_data(WDTO, timeout); + /* fall through and return the new timeout */ - if (options & WDIOS_DISABLECARD) { - sc1200wdt_stop(); - retval = 0; - } + case WDIOC_GETTIMEOUT: + return put_user(timeout * 60, p); - if (options & WDIOS_ENABLECARD) { - sc1200wdt_start(); - retval = 0; - } - - return retval; - } + default: + return -ENOTTY; } } @@ -237,19 +254,20 @@ static int sc1200wdt_release(struct inode *inode, struct file *file) { if (expect_close == 42) { sc1200wdt_stop(); - printk(KERN_INFO PFX "Watchdog disabled\n"); + pr_info("Watchdog disabled\n"); } else { sc1200wdt_write_data(WDTO, timeout); - printk(KERN_CRIT PFX "Unexpected close!, timeout = %d min(s)\n", timeout); + pr_crit("Unexpected close!, timeout = %d min(s)\n", timeout); } - up(&open_sem); + clear_bit(0, &open_flag); expect_close = 0; return 0; } -static ssize_t sc1200wdt_write(struct file *file, const char __user *data, size_t len, loff_t *ppos) +static ssize_t sc1200wdt_write(struct file *file, const char __user *data, + size_t len, loff_t *ppos) { if (len) { if (!nowayout) { @@ -260,7 +278,7 @@ static ssize_t sc1200wdt_write(struct file *file, const char __user *data, size_ for (i = 0; i != len; i++) { char c; - if (get_user(c, data+i)) + if (get_user(c, data + i)) return -EFAULT; if (c == 'V') expect_close = 42; @@ -275,7 +293,8 @@ static ssize_t sc1200wdt_write(struct file *file, const char __user *data, size_ } -static int sc1200wdt_notify_sys(struct notifier_block *this, unsigned long code, void *unused) +static int sc1200wdt_notify_sys(struct notifier_block *this, + unsigned long code, void *unused) { if (code == SYS_DOWN || code == SYS_HALT) sc1200wdt_stop(); @@ -284,23 +303,20 @@ static int sc1200wdt_notify_sys(struct notifier_block *this, unsigned long code, } -static struct notifier_block sc1200wdt_notifier = -{ +static struct notifier_block sc1200wdt_notifier = { .notifier_call = sc1200wdt_notify_sys, }; -static const struct file_operations sc1200wdt_fops = -{ +static const struct file_operations sc1200wdt_fops = { .owner = THIS_MODULE, .llseek = no_llseek, .write = sc1200wdt_write, - .ioctl = sc1200wdt_ioctl, + .unlocked_ioctl = sc1200wdt_ioctl, .open = sc1200wdt_open, .release = sc1200wdt_release, }; -static struct miscdevice sc1200wdt_miscdev = -{ +static struct miscdevice sc1200wdt_miscdev = { .minor = WATCHDOG_MINOR, .name = "watchdog", .fops = &sc1200wdt_fops, @@ -312,14 +328,14 @@ static int __init sc1200wdt_probe(void) /* The probe works by reading the PMC3 register's default value of 0x0e * there is one caveat, if the device disables the parallel port or any * of the UARTs we won't be able to detect it. - * Nb. This could be done with accuracy by reading the SID registers, but - * we don't have access to those io regions. + * NB. This could be done with accuracy by reading the SID registers, + * but we don't have access to those io regions. */ unsigned char reg; sc1200wdt_read_data(PMC3, ®); - reg &= 0x0f; /* we don't want the UART busy bits */ + reg &= 0x0f; /* we don't want the UART busy bits */ return (reg == 0x0e) ? 0 : -ENODEV; } @@ -332,7 +348,8 @@ static struct pnp_device_id scl200wdt_pnp_devices[] = { {.id = ""}, }; -static int scl200wdt_pnp_probe(struct pnp_dev * dev, const struct pnp_device_id *dev_id) +static int scl200wdt_pnp_probe(struct pnp_dev *dev, + const struct pnp_device_id *dev_id) { /* this driver only supports one card at a time */ if (wdt_dev || !isapnp) @@ -343,17 +360,17 @@ static int scl200wdt_pnp_probe(struct pnp_dev * dev, const struct pnp_device_id io_len = pnp_port_len(wdt_dev, 0); if (!request_region(io, io_len, SC1200_MODULE_NAME)) { - printk(KERN_ERR PFX "Unable to register IO port %#x\n", io); + pr_err("Unable to register IO port %#x\n", io); return -EBUSY; } - printk(KERN_INFO "scl200wdt: PnP device found at io port %#x/%d\n", io, io_len); + pr_info("PnP device found at io port %#x/%d\n", io, io_len); return 0; } -static void scl200wdt_pnp_remove(struct pnp_dev * dev) +static void scl200wdt_pnp_remove(struct pnp_dev *dev) { - if (wdt_dev){ + if (wdt_dev) { release_region(io, io_len); wdt_dev = NULL; } @@ -373,9 +390,7 @@ static int __init sc1200wdt_init(void) { int ret; - printk("%s\n", banner); - - sema_init(&open_sem, 1); + pr_info("%s\n", SC1200_MODULE_VER); #if defined CONFIG_PNP if (isapnp) { @@ -386,7 +401,7 @@ static int __init sc1200wdt_init(void) #endif if (io == -1) { - printk(KERN_ERR PFX "io parameter must be specified\n"); + pr_err("io parameter must be specified\n"); ret = -EINVAL; goto out_pnp; } @@ -394,12 +409,13 @@ static int __init sc1200wdt_init(void) #if defined CONFIG_PNP /* now that the user has specified an IO port and we haven't detected * any devices, disable pnp support */ + if (isapnp) + pnp_unregister_driver(&scl200wdt_pnp_driver); isapnp = 0; - pnp_unregister_driver(&scl200wdt_pnp_driver); #endif if (!request_region(io, io_len, SC1200_MODULE_NAME)) { - printk(KERN_ERR PFX "Unable to register IO port %#x\n", io); + pr_err("Unable to register IO port %#x\n", io); ret = -EBUSY; goto out_pnp; } @@ -410,13 +426,14 @@ static int __init sc1200wdt_init(void) ret = register_reboot_notifier(&sc1200wdt_notifier); if (ret) { - printk(KERN_ERR PFX "Unable to register reboot notifier err = %d\n", ret); + pr_err("Unable to register reboot notifier err = %d\n", ret); goto out_io; } ret = misc_register(&sc1200wdt_miscdev); if (ret) { - printk(KERN_ERR PFX "Unable to register miscdev on minor %d\n", WATCHDOG_MINOR); + pr_err("Unable to register miscdev on minor %d\n", + WATCHDOG_MINOR); goto out_rbt; } @@ -446,7 +463,7 @@ static void __exit sc1200wdt_exit(void) unregister_reboot_notifier(&sc1200wdt_notifier); #if defined CONFIG_PNP - if(isapnp) + if (isapnp) pnp_unregister_driver(&scl200wdt_pnp_driver); else #endif @@ -457,6 +474,6 @@ module_init(sc1200wdt_init); module_exit(sc1200wdt_exit); MODULE_AUTHOR("Zwane Mwaikambo <zwane@commfireservices.com>"); -MODULE_DESCRIPTION("Driver for National Semiconductor PC87307/PC97307 watchdog component"); +MODULE_DESCRIPTION( + "Driver for National Semiconductor PC87307/PC97307 watchdog component"); MODULE_LICENSE("GPL"); -MODULE_ALIAS_MISCDEV(WATCHDOG_MINOR); |
