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

[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
...@@ -186,6 +186,7 @@ static int got_event; /* if events processing have been done */ ...@@ -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); ...@@ -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) ...@@ -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, ...@@ -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, ...@@ -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, ...@@ -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) ...@@ -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) ...@@ -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);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment