diff options
Diffstat (limited to 'drivers/char/tlclk.c')
| -rw-r--r-- | drivers/char/tlclk.c | 43 |
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 */ | |||
| 186 | static void switchover_timeout(unsigned long data); | 186 | static void switchover_timeout(unsigned long data); |
| 187 | static struct timer_list switchover_timer = | 187 | static struct timer_list switchover_timer = |
| 188 | TIMER_INITIALIZER(switchover_timeout , 0, 0); | 188 | TIMER_INITIALIZER(switchover_timeout , 0, 0); |
| 189 | static unsigned long tlclk_timer_data; | ||
| 189 | 190 | ||
| 190 | static struct tlclk_alarms *alarm_events; | 191 | static struct tlclk_alarms *alarm_events; |
| 191 | 192 | ||
| @@ -197,10 +198,19 @@ static irqreturn_t tlclk_interrupt(int irq, void *dev_id); | |||
| 197 | 198 | ||
| 198 | static DECLARE_WAIT_QUEUE_HEAD(wq); | 199 | static DECLARE_WAIT_QUEUE_HEAD(wq); |
| 199 | 200 | ||
| 201 | static unsigned long useflags; | ||
| 202 | static DEFINE_MUTEX(tlclk_mutex); | ||
| 203 | |||
| 200 | static int tlclk_open(struct inode *inode, struct file *filp) | 204 | static 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) | |||
| 221 | static int tlclk_release(struct inode *inode, struct file *filp) | 231 | static 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 | ||
| 244 | static 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 | |||
| 250 | static const struct file_operations tlclk_fops = { | 261 | static 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 | ||
| 840 | static void switchover_timeout(unsigned long data) | 850 | static 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); |
