Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit d14bccaa authored by Alan Cox's avatar Alan Cox Committed by Wim Van Sebroeck
Browse files

[WATCHDOG 42/57] sc1200_wdt: clean up, fix locking and use unlocked_ioctl



Review and switch to unlocked_ioctl

Signed-off-by: default avatarAlan Cox <alan@redhat.com>
Signed-off-by: default avatarWim Van Sebroeck <wim@iguana.be>
parent df3c9de3
Loading
Loading
Loading
Loading
+114 −89
Original line number Original line Diff line number Diff line
@@ -15,14 +15,18 @@
 *
 *
 *	Changelog:
 *	Changelog:
 *	20020220 Zwane Mwaikambo	Code based on datasheet, no hardware.
 *	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.
 *	20020222 Zwane Mwaikambo	Added probing.
 *	20020225 Zwane Mwaikambo	Added ISAPNP support.
 *	20020225 Zwane Mwaikambo	Added ISAPNP support.
 *	20020412 Rob Radez		Broke out start/stop functions
 *	20020412 Rob Radez		Broke out start/stop functions
 *		 <rob@osinvestor.com>	Return proper status instead of temperature warning
 *		 <rob@osinvestor.com>	Return proper status instead of
 *					Add WDIOC_GETBOOTSTATUS and WDIOC_SETOPTIONS ioctls
 *					temperature warning
 *					Add WDIOC_GETBOOTSTATUS and
 *					WDIOC_SETOPTIONS ioctls
 *					Fix CONFIG_WATCHDOG_NOWAYOUT
 *					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
 *	20030116 Adam Belay		Updated to the latest pnp code
 *
 *
 */
 */
@@ -39,9 +43,8 @@
#include <linux/pnp.h>
#include <linux/pnp.h>
#include <linux/fs.h>
#include <linux/fs.h>
#include <linux/semaphore.h>
#include <linux/semaphore.h>

#include <linux/io.h>
#include <asm/io.h>
#include <linux/uaccess.h>
#include <asm/uaccess.h>


#define SC1200_MODULE_VER	"build 20020303"
#define SC1200_MODULE_VER	"build 20020303"
#define SC1200_MODULE_NAME	"sc1200wdt"
#define SC1200_MODULE_NAME	"sc1200wdt"
@@ -72,7 +75,7 @@ static char banner[] __initdata = KERN_INFO PFX SC1200_MODULE_VER;
static int timeout = 1;
static int timeout = 1;
static int io = -1;
static int io = -1;
static int io_len = 2;		/* for non plug and play */
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 char expect_close;
static DEFINE_SPINLOCK(sc1200wdt_lock);	/* io port access serialisation */
static DEFINE_SPINLOCK(sc1200wdt_lock);	/* io port access serialisation */


@@ -81,7 +84,8 @@ static int isapnp = 1;
static struct pnp_dev *wdt_dev;
static struct pnp_dev *wdt_dev;


module_param(isapnp, int, 0);
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
#endif


module_param(io, int, 0);
module_param(io, int, 0);
@@ -91,26 +95,40 @@ MODULE_PARM_DESC(timeout, "range is 0-255 minutes, default is 1");


static int nowayout = WATCHDOG_NOWAYOUT;
static int nowayout = WATCHDOG_NOWAYOUT;
module_param(nowayout, int, 0);
module_param(nowayout, int, 0);
MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default=" __MODULE_STRING(WATCHDOG_NOWAYOUT) ")");
MODULE_PARM_DESC(nowayout,
	"Watchdog cannot be stopped once started (default="
				__MODULE_STRING(WATCHDOG_NOWAYOUT) ")");






/* Read from Data Register */
/* 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);
	outb_p(index, PMIR);
	*data = inb(PMDR);
	*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 */
/* 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_p(index, PMIR);
	outb(data, PMDR);
	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);
	spin_unlock(&sc1200wdt_lock);
}
}


@@ -118,13 +136,16 @@ static inline void sc1200wdt_write_data(unsigned char index, unsigned char data)
static void sc1200wdt_start(void)
static void sc1200wdt_start(void)
{
{
	unsigned char reg;
	unsigned char reg;
	spin_lock(&sc1200wdt_lock);


	sc1200wdt_read_data(WDCF, &reg);
	__sc1200wdt_read_data(WDCF, &reg);
	/* assert WDO when any of the following interrupts are triggered too */
	/* assert WDO when any of the following interrupts are triggered too */
	reg |= (KBC_IRQ | MSE_IRQ | UART1_IRQ | UART2_IRQ);
	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 */
	/* set the timeout and get the ball rolling */
	sc1200wdt_write_data(WDTO, timeout);
	__sc1200wdt_write_data(WDTO, timeout);

	spin_unlock(&sc1200wdt_lock);
}
}




@@ -144,14 +165,15 @@ static inline int sc1200wdt_status(void)
	 * KEEPALIVEPING which is a bit of a kludge because there's nothing
	 * KEEPALIVEPING which is a bit of a kludge because there's nothing
	 * else for enabled/disabled status
	 * else for enabled/disabled status
	 */
	 */
	return (ret & 0x01) ? 0 : WDIOF_KEEPALIVEPING;	/* bits 1 - 7 are undefined */
	return (ret & 0x01) ? 0 : WDIOF_KEEPALIVEPING;
	/* bits 1 - 7 are undefined */
}
}




static int sc1200wdt_open(struct inode *inode, struct file *file)
static int sc1200wdt_open(struct inode *inode, struct file *file)
{
{
	/* allow one at a time */
	/* allow one at a time */
	if (down_trylock(&open_sem))
	if (test_and_set_bit(0, &open_flag))
		return -EBUSY;
		return -EBUSY;


	if (timeout > MAX_TIMEOUT)
	if (timeout > MAX_TIMEOUT)
@@ -164,20 +186,20 @@ static int sc1200wdt_open(struct inode *inode, struct file *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;
	int new_timeout;
	void __user *argp = (void __user *)arg;
	void __user *argp = (void __user *)arg;
	int __user *p = argp;
	int __user *p = argp;
	static struct watchdog_info ident = {
	static const struct watchdog_info ident = {
		.options = WDIOF_KEEPALIVEPING | WDIOF_SETTIMEOUT | WDIOF_MAGICCLOSE,
		.options = WDIOF_KEEPALIVEPING | WDIOF_SETTIMEOUT |
							WDIOF_MAGICCLOSE,
		.firmware_version = 0,
		.firmware_version = 0,
		.identity = "PC87307/PC97307",
		.identity = "PC87307/PC97307",
	};
	};


	switch (cmd) {
	switch (cmd) {
		default:
			return -ENOTTY;


	case WDIOC_GETSUPPORT:
	case WDIOC_GETSUPPORT:
		if (copy_to_user(argp, &ident, sizeof ident))
		if (copy_to_user(argp, &ident, sizeof ident))
@@ -197,12 +219,10 @@ static int sc1200wdt_ioctl(struct inode *inode, struct file *file, unsigned int
	case WDIOC_SETTIMEOUT:
	case WDIOC_SETTIMEOUT:
		if (get_user(new_timeout, p))
		if (get_user(new_timeout, p))
			return -EFAULT;
			return -EFAULT;

		/* the API states this is given in secs */
		/* the API states this is given in secs */
		new_timeout /= 60;
		new_timeout /= 60;
		if (new_timeout < 0 || new_timeout > MAX_TIMEOUT)
		if (new_timeout < 0 || new_timeout > MAX_TIMEOUT)
			return -EINVAL;
			return -EINVAL;

		timeout = new_timeout;
		timeout = new_timeout;
		sc1200wdt_write_data(WDTO, timeout);
		sc1200wdt_write_data(WDTO, timeout);
		/* fall through and return the new timeout */
		/* fall through and return the new timeout */
@@ -229,6 +249,8 @@ static int sc1200wdt_ioctl(struct inode *inode, struct file *file, unsigned int


		return retval;
		return retval;
	}
	}
	default:
		return -ENOTTY;
	}
	}
}
}


@@ -240,16 +262,18 @@ static int sc1200wdt_release(struct inode *inode, struct file *file)
		printk(KERN_INFO PFX "Watchdog disabled\n");
		printk(KERN_INFO PFX "Watchdog disabled\n");
	} else {
	} else {
		sc1200wdt_write_data(WDTO, timeout);
		sc1200wdt_write_data(WDTO, timeout);
		printk(KERN_CRIT PFX "Unexpected close!, timeout = %d min(s)\n", timeout);
		printk(KERN_CRIT PFX
			"Unexpected close!, timeout = %d min(s)\n", timeout);
	}
	}
	up(&open_sem);
	clear_bit(0, &open_flag);
	expect_close = 0;
	expect_close = 0;


	return 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 (len) {
		if (!nowayout) {
		if (!nowayout) {
@@ -275,7 +299,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)
	if (code == SYS_DOWN || code == SYS_HALT)
		sc1200wdt_stop();
		sc1200wdt_stop();
@@ -284,23 +309,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,
	.notifier_call =	sc1200wdt_notify_sys,
};
};


static const struct file_operations sc1200wdt_fops =
static const struct file_operations sc1200wdt_fops = {
{
	.owner		= THIS_MODULE,
	.owner		= THIS_MODULE,
	.llseek		= no_llseek,
	.llseek		= no_llseek,
	.write		= sc1200wdt_write,
	.write		= sc1200wdt_write,
	.ioctl		= sc1200wdt_ioctl,
	.unlocked_ioctl = sc1200wdt_ioctl,
	.open		= sc1200wdt_open,
	.open		= sc1200wdt_open,
	.release	= sc1200wdt_release,
	.release	= sc1200wdt_release,
};
};


static struct miscdevice sc1200wdt_miscdev =
static struct miscdevice sc1200wdt_miscdev = {
{
	.minor		= WATCHDOG_MINOR,
	.minor		= WATCHDOG_MINOR,
	.name		= "watchdog",
	.name		= "watchdog",
	.fops		= &sc1200wdt_fops,
	.fops		= &sc1200wdt_fops,
@@ -312,8 +334,8 @@ static int __init sc1200wdt_probe(void)
	/* The probe works by reading the PMC3 register's default value of 0x0e
	/* 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
	 * there is one caveat, if the device disables the parallel port or any
	 * of the UARTs we won't be able to detect it.
	 * of the UARTs we won't be able to detect it.
	 * Nb. This could be done with accuracy by reading the SID registers, but
	 * NB. This could be done with accuracy by reading the SID registers,
	 * we don't have access to those io regions.
	 * but we don't have access to those io regions.
	 */
	 */


	unsigned char reg;
	unsigned char reg;
@@ -332,7 +354,8 @@ static struct pnp_device_id scl200wdt_pnp_devices[] = {
	{.id = ""},
	{.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 */
	/* this driver only supports one card at a time */
	if (wdt_dev || !isapnp)
	if (wdt_dev || !isapnp)
@@ -347,7 +370,8 @@ static int scl200wdt_pnp_probe(struct pnp_dev * dev, const struct pnp_device_id
		return -EBUSY;
		return -EBUSY;
	}
	}


	printk(KERN_INFO "scl200wdt: PnP device found at io port %#x/%d\n", io, io_len);
	printk(KERN_INFO "scl200wdt: PnP device found at io port %#x/%d\n",
								io, io_len);
	return 0;
	return 0;
}
}


@@ -375,8 +399,6 @@ static int __init sc1200wdt_init(void)


	printk("%s\n", banner);
	printk("%s\n", banner);


	sema_init(&open_sem, 1);

#if defined CONFIG_PNP
#if defined CONFIG_PNP
	if (isapnp) {
	if (isapnp) {
		ret = pnp_register_driver(&scl200wdt_pnp_driver);
		ret = pnp_register_driver(&scl200wdt_pnp_driver);
@@ -410,13 +432,16 @@ static int __init sc1200wdt_init(void)


	ret = register_reboot_notifier(&sc1200wdt_notifier);
	ret = register_reboot_notifier(&sc1200wdt_notifier);
	if (ret) {
	if (ret) {
		printk(KERN_ERR PFX "Unable to register reboot notifier err = %d\n", ret);
		printk(KERN_ERR PFX
			"Unable to register reboot notifier err = %d\n", ret);
		goto out_io;
		goto out_io;
	}
	}


	ret = misc_register(&sc1200wdt_miscdev);
	ret = misc_register(&sc1200wdt_miscdev);
	if (ret) {
	if (ret) {
		printk(KERN_ERR PFX "Unable to register miscdev on minor %d\n", WATCHDOG_MINOR);
		printk(KERN_ERR PFX
			"Unable to register miscdev on minor %d\n",
							WATCHDOG_MINOR);
		goto out_rbt;
		goto out_rbt;
	}
	}