aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--drivers/char/tlclk.c43
1 files changed, 28 insertions, 15 deletions
diff --git a/drivers/char/tlclk.c b/drivers/char/tlclk.c
index 448d5083c381..4fac2bdf6215 100644
--- a/drivers/char/tlclk.c
+++ b/drivers/char/tlclk.c
@@ -186,6 +186,7 @@ static int got_event; /* if events processing have been done */
186static void switchover_timeout(unsigned long data); 186static void switchover_timeout(unsigned long data);
187static struct timer_list switchover_timer = 187static struct timer_list switchover_timer =
188 TIMER_INITIALIZER(switchover_timeout , 0, 0); 188 TIMER_INITIALIZER(switchover_timeout , 0, 0);
189static unsigned long tlclk_timer_data;
189 190
190static struct tlclk_alarms *alarm_events; 191static struct tlclk_alarms *alarm_events;
191 192
@@ -197,10 +198,19 @@ static irqreturn_t tlclk_interrupt(int irq, void *dev_id);
197 198
198static DECLARE_WAIT_QUEUE_HEAD(wq); 199static DECLARE_WAIT_QUEUE_HEAD(wq);
199 200
201static unsigned long useflags;
202static DEFINE_MUTEX(tlclk_mutex);
203
200static int tlclk_open(struct inode *inode, struct file *filp) 204static int tlclk_open(struct inode *inode, struct file *filp)
201{ 205{
202 int result; 206 int result;
203 207
208 if (test_and_set_bit(0, &useflags))
209 return -EBUSY;
210 /* this legacy device is always one per system and it doesn't
211 * know how to handle multiple concurrent clients.
212 */
213
204 /* Make sure there is no interrupt pending while 214 /* Make sure there is no interrupt pending while
205 * initialising interrupt handler */ 215 * initialising interrupt handler */
206 inb(TLCLK_REG6); 216 inb(TLCLK_REG6);
@@ -221,6 +231,7 @@ static int tlclk_open(struct inode *inode, struct file *filp)
221static int tlclk_release(struct inode *inode, struct file *filp) 231static int tlclk_release(struct inode *inode, struct file *filp)
222{ 232{
223 free_irq(telclk_interrupt, tlclk_interrupt); 233 free_irq(telclk_interrupt, tlclk_interrupt);
234 clear_bit(0, &useflags);
224 235
225 return 0; 236 return 0;
226} 237}
@@ -230,26 +241,25 @@ static ssize_t tlclk_read(struct file *filp, char __user *buf, size_t count,
230{ 241{
231 if (count < sizeof(struct tlclk_alarms)) 242 if (count < sizeof(struct tlclk_alarms))
232 return -EIO; 243 return -EIO;
244 if (mutex_lock_interruptible(&tlclk_mutex))
245 return -EINTR;
246
233 247
234 wait_event_interruptible(wq, got_event); 248 wait_event_interruptible(wq, got_event);
235 if (copy_to_user(buf, alarm_events, sizeof(struct tlclk_alarms))) 249 if (copy_to_user(buf, alarm_events, sizeof(struct tlclk_alarms))) {
250 mutex_unlock(&tlclk_mutex);
236 return -EFAULT; 251 return -EFAULT;
252 }
237 253
238 memset(alarm_events, 0, sizeof(struct tlclk_alarms)); 254 memset(alarm_events, 0, sizeof(struct tlclk_alarms));
239 got_event = 0; 255 got_event = 0;
240 256
257 mutex_unlock(&tlclk_mutex);
241 return sizeof(struct tlclk_alarms); 258 return sizeof(struct tlclk_alarms);
242} 259}
243 260
244static ssize_t tlclk_write(struct file *filp, const char __user *buf, size_t count,
245 loff_t *f_pos)
246{
247 return 0;
248}
249
250static const struct file_operations tlclk_fops = { 261static const struct file_operations tlclk_fops = {
251 .read = tlclk_read, 262 .read = tlclk_read,
252 .write = tlclk_write,
253 .open = tlclk_open, 263 .open = tlclk_open,
254 .release = tlclk_release, 264 .release = tlclk_release,
255 265
@@ -540,7 +550,7 @@ static ssize_t store_select_amcb1_transmit_clock(struct device *d,
540 SET_PORT_BITS(TLCLK_REG3, 0xf8, 0x7); 550 SET_PORT_BITS(TLCLK_REG3, 0xf8, 0x7);
541 switch (val) { 551 switch (val) {
542 case CLK_8_592MHz: 552 case CLK_8_592MHz:
543 SET_PORT_BITS(TLCLK_REG0, 0xfc, 1); 553 SET_PORT_BITS(TLCLK_REG0, 0xfc, 2);
544 break; 554 break;
545 case CLK_11_184MHz: 555 case CLK_11_184MHz:
546 SET_PORT_BITS(TLCLK_REG0, 0xfc, 0); 556 SET_PORT_BITS(TLCLK_REG0, 0xfc, 0);
@@ -549,7 +559,7 @@ static ssize_t store_select_amcb1_transmit_clock(struct device *d,
549 SET_PORT_BITS(TLCLK_REG0, 0xfc, 3); 559 SET_PORT_BITS(TLCLK_REG0, 0xfc, 3);
550 break; 560 break;
551 case CLK_44_736MHz: 561 case CLK_44_736MHz:
552 SET_PORT_BITS(TLCLK_REG0, 0xfc, 2); 562 SET_PORT_BITS(TLCLK_REG0, 0xfc, 1);
553 break; 563 break;
554 } 564 }
555 } else 565 } else
@@ -839,11 +849,13 @@ static void __exit tlclk_cleanup(void)
839 849
840static void switchover_timeout(unsigned long data) 850static void switchover_timeout(unsigned long data)
841{ 851{
842 if ((data & 1)) { 852 unsigned long flags = *(unsigned long *) data;
843 if ((inb(TLCLK_REG1) & 0x08) != (data & 0x08)) 853
854 if ((flags & 1)) {
855 if ((inb(TLCLK_REG1) & 0x08) != (flags & 0x08))
844 alarm_events->switchover_primary++; 856 alarm_events->switchover_primary++;
845 } else { 857 } else {
846 if ((inb(TLCLK_REG1) & 0x08) != (data & 0x08)) 858 if ((inb(TLCLK_REG1) & 0x08) != (flags & 0x08))
847 alarm_events->switchover_secondary++; 859 alarm_events->switchover_secondary++;
848 } 860 }
849 861
@@ -901,8 +913,9 @@ static irqreturn_t tlclk_interrupt(int irq, void *dev_id)
901 913
902 /* TIMEOUT in ~10ms */ 914 /* TIMEOUT in ~10ms */
903 switchover_timer.expires = jiffies + msecs_to_jiffies(10); 915 switchover_timer.expires = jiffies + msecs_to_jiffies(10);
904 switchover_timer.data = inb(TLCLK_REG1); 916 tlclk_timer_data = inb(TLCLK_REG1);
905 add_timer(&switchover_timer); 917 switchover_timer.data = (unsigned long) &tlclk_timer_data;
918 mod_timer(&switchover_timer, switchover_timer.expires);
906 } else { 919 } else {
907 got_event = 1; 920 got_event = 1;
908 wake_up(&wq); 921 wake_up(&wq);