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

Commit 79603a35 authored by Mark Gross's avatar Mark Gross Committed by Linus Torvalds
Browse files

[PATCH] tlclk: bug fix + misc fixes



The following patch fixes a few problems with the tlclk driver.
* bug in the select_amcb1_transmit_clock
* racy read sys call
* racy open sys call
* use of add_timer where mod_timer would be better
* change to the timer data parameter use

Signed-off-by: default avatarMark Gross <mark.gross@intel.com>
Signed-off-by: default avatarAndrew Morton <akpm@osdl.org>
Signed-off-by: default avatarLinus Torvalds <torvalds@linux-foundation.org>
parent cda9205d
Loading
Loading
Loading
Loading
+28 −15
Original line number Original line Diff line number Diff line
@@ -186,6 +186,7 @@ static int got_event; /* if events processing have been done */
static void switchover_timeout(unsigned long data);
static void switchover_timeout(unsigned long data);
static struct timer_list switchover_timer =
static struct timer_list switchover_timer =
	TIMER_INITIALIZER(switchover_timeout , 0, 0);
	TIMER_INITIALIZER(switchover_timeout , 0, 0);
static unsigned long tlclk_timer_data;


static struct tlclk_alarms *alarm_events;
static struct tlclk_alarms *alarm_events;


@@ -197,10 +198,19 @@ static irqreturn_t tlclk_interrupt(int irq, void *dev_id);


static DECLARE_WAIT_QUEUE_HEAD(wq);
static DECLARE_WAIT_QUEUE_HEAD(wq);


static unsigned long useflags;
static DEFINE_MUTEX(tlclk_mutex);

static int tlclk_open(struct inode *inode, struct file *filp)
static int tlclk_open(struct inode *inode, struct file *filp)
{
{
	int result;
	int result;


	if (test_and_set_bit(0, &useflags))
		return -EBUSY;
		/* this legacy device is always one per system and it doesn't
		 * know how to handle multiple concurrent clients.
		 */

	/* Make sure there is no interrupt pending while
	/* Make sure there is no interrupt pending while
	 * initialising interrupt handler */
	 * initialising interrupt handler */
	inb(TLCLK_REG6);
	inb(TLCLK_REG6);
@@ -221,6 +231,7 @@ static int tlclk_open(struct inode *inode, struct file *filp)
static int tlclk_release(struct inode *inode, struct file *filp)
static int tlclk_release(struct inode *inode, struct file *filp)
{
{
	free_irq(telclk_interrupt, tlclk_interrupt);
	free_irq(telclk_interrupt, tlclk_interrupt);
	clear_bit(0, &useflags);


	return 0;
	return 0;
}
}
@@ -230,26 +241,25 @@ static ssize_t tlclk_read(struct file *filp, char __user *buf, size_t count,
{
{
	if (count < sizeof(struct tlclk_alarms))
	if (count < sizeof(struct tlclk_alarms))
		return -EIO;
		return -EIO;
	if (mutex_lock_interruptible(&tlclk_mutex))
		return -EINTR;



	wait_event_interruptible(wq, got_event);
	wait_event_interruptible(wq, got_event);
	if (copy_to_user(buf, alarm_events, sizeof(struct tlclk_alarms)))
	if (copy_to_user(buf, alarm_events, sizeof(struct tlclk_alarms))) {
		mutex_unlock(&tlclk_mutex);
		return -EFAULT;
		return -EFAULT;
	}


	memset(alarm_events, 0, sizeof(struct tlclk_alarms));
	memset(alarm_events, 0, sizeof(struct tlclk_alarms));
	got_event = 0;
	got_event = 0;


	mutex_unlock(&tlclk_mutex);
	return  sizeof(struct tlclk_alarms);
	return  sizeof(struct tlclk_alarms);
}
}


static ssize_t tlclk_write(struct file *filp, const char __user *buf, size_t count,
	    loff_t *f_pos)
{
	return 0;
}

static const struct file_operations tlclk_fops = {
static const struct file_operations tlclk_fops = {
	.read = tlclk_read,
	.read = tlclk_read,
	.write = tlclk_write,
	.open = tlclk_open,
	.open = tlclk_open,
	.release = tlclk_release,
	.release = tlclk_release,


@@ -540,7 +550,7 @@ static ssize_t store_select_amcb1_transmit_clock(struct device *d,
			SET_PORT_BITS(TLCLK_REG3, 0xf8, 0x7);
			SET_PORT_BITS(TLCLK_REG3, 0xf8, 0x7);
			switch (val) {
			switch (val) {
			case CLK_8_592MHz:
			case CLK_8_592MHz:
				SET_PORT_BITS(TLCLK_REG0, 0xfc, 1);
				SET_PORT_BITS(TLCLK_REG0, 0xfc, 2);
				break;
				break;
			case CLK_11_184MHz:
			case CLK_11_184MHz:
				SET_PORT_BITS(TLCLK_REG0, 0xfc, 0);
				SET_PORT_BITS(TLCLK_REG0, 0xfc, 0);
@@ -549,7 +559,7 @@ static ssize_t store_select_amcb1_transmit_clock(struct device *d,
				SET_PORT_BITS(TLCLK_REG0, 0xfc, 3);
				SET_PORT_BITS(TLCLK_REG0, 0xfc, 3);
				break;
				break;
			case CLK_44_736MHz:
			case CLK_44_736MHz:
				SET_PORT_BITS(TLCLK_REG0, 0xfc, 2);
				SET_PORT_BITS(TLCLK_REG0, 0xfc, 1);
				break;
				break;
			}
			}
		} else
		} else
@@ -839,11 +849,13 @@ static void __exit tlclk_cleanup(void)


static void switchover_timeout(unsigned long data)
static void switchover_timeout(unsigned long data)
{
{
	if ((data & 1)) {
	unsigned long flags = *(unsigned long *) data;
		if ((inb(TLCLK_REG1) & 0x08) != (data & 0x08))

	if ((flags & 1)) {
		if ((inb(TLCLK_REG1) & 0x08) != (flags & 0x08))
			alarm_events->switchover_primary++;
			alarm_events->switchover_primary++;
	} else {
	} else {
		if ((inb(TLCLK_REG1) & 0x08) != (data & 0x08))
		if ((inb(TLCLK_REG1) & 0x08) != (flags & 0x08))
			alarm_events->switchover_secondary++;
			alarm_events->switchover_secondary++;
	}
	}


@@ -901,8 +913,9 @@ static irqreturn_t tlclk_interrupt(int irq, void *dev_id)


		/* TIMEOUT in ~10ms */
		/* TIMEOUT in ~10ms */
		switchover_timer.expires = jiffies + msecs_to_jiffies(10);
		switchover_timer.expires = jiffies + msecs_to_jiffies(10);
		switchover_timer.data = inb(TLCLK_REG1);
		tlclk_timer_data = inb(TLCLK_REG1);
		add_timer(&switchover_timer);
		switchover_timer.data = (unsigned long) &tlclk_timer_data;
		mod_timer(&switchover_timer, switchover_timer.expires);
	} else {
	} else {
		got_event = 1;
		got_event = 1;
		wake_up(&wq);
		wake_up(&wq);