summaryrefslogtreecommitdiffstats
path: root/drivers/sbus/char/pcikbd.c
diff options
context:
space:
mode:
authorRalf Baechle <ralf@linux-mips.org>2000-04-28 01:09:25 +0000
committerRalf Baechle <ralf@linux-mips.org>2000-04-28 01:09:25 +0000
commitb9ba7aeb165cffecdffb60aec8c3fa8d590d9ca9 (patch)
tree42d07b0c7246ae2536a702e7c5de9e2732341116 /drivers/sbus/char/pcikbd.c
parent7406b0a326f2d70ade2671c37d1beef62249db97 (diff)
Merge with 2.3.99-pre6.
Diffstat (limited to 'drivers/sbus/char/pcikbd.c')
-rw-r--r--drivers/sbus/char/pcikbd.c215
1 files changed, 115 insertions, 100 deletions
diff --git a/drivers/sbus/char/pcikbd.c b/drivers/sbus/char/pcikbd.c
index 76b83eacb..d0e88d087 100644
--- a/drivers/sbus/char/pcikbd.c
+++ b/drivers/sbus/char/pcikbd.c
@@ -1,4 +1,4 @@
-/* $Id: pcikbd.c,v 1.44 2000/02/11 04:49:13 davem Exp $
+/* $Id: pcikbd.c,v 1.45 2000/04/24 06:10:19 davem Exp $
* pcikbd.c: Ultra/AX PC keyboard support.
*
* Copyright (C) 1997 Eddie C. Dost (ecd@skynet.be)
@@ -23,6 +23,7 @@
#include <linux/kbd_ll.h>
#include <linux/kbd_kern.h>
#include <linux/delay.h>
+#include <linux/spinlock.h>
#include <linux/init.h>
#include <asm/ebus.h>
@@ -59,6 +60,8 @@ static volatile unsigned char reply_expected = 0;
static volatile unsigned char acknowledge = 0;
static volatile unsigned char resend = 0;
+static spinlock_t pcikbd_lock = SPIN_LOCK_UNLOCKED;
+
unsigned char pckbd_read_mask = KBD_STAT_OBF;
extern int pcikbd_init(void);
@@ -71,26 +74,18 @@ extern unsigned char pci_getledstate(void);
#define pcikbd_inb(x) inb(x)
#define pcikbd_outb(v,x) outb(v,x)
-#if 0 /* deadwood */
-static __inline__ unsigned char pcikbd_inb(unsigned long port)
-{
- return inb(port);
-}
-
-static __inline__ void pcikbd_outb(unsigned char val, unsigned long port)
-{
- outb(val, port);
-}
-#endif
-
-static inline void kb_wait(void)
+/* Wait for keyboard controller input buffer to drain.
+ * Must be invoked under the pcikbd_lock.
+ */
+static void kb_wait(void)
{
- unsigned long start = jiffies;
+ unsigned long timeout = 250;
do {
if(!(pcikbd_inb(pcikbd_iobase + KBD_STATUS_REG) & KBD_STAT_IBF))
return;
- } while (jiffies - start < KBC_TIMEOUT);
+ mdelay(1);
+ } while (--timeout);
}
/*
@@ -312,8 +307,11 @@ char pcikbd_unexpected_up(unsigned char keycode)
static void
pcikbd_interrupt(int irq, void *dev_id, struct pt_regs *regs)
{
+ unsigned long flags;
unsigned char status;
+ spin_lock_irqsave(&pcikbd_lock, flags);
+
kbd_pt_regs = regs;
status = pcikbd_inb(pcikbd_iobase + KBD_STATUS_REG);
do {
@@ -327,27 +325,45 @@ pcikbd_interrupt(int irq, void *dev_id, struct pt_regs *regs)
status = pcikbd_inb(pcikbd_iobase + KBD_STATUS_REG);
} while(status & KBD_STAT_OBF);
tasklet_schedule(&keyboard_tasklet);
+
+ spin_unlock_irqrestore(&pcikbd_lock, flags);
}
static int send_data(unsigned char data)
{
int retries = 3;
- unsigned long start;
+ unsigned long flags;
+
+ spin_lock_irqsave(&pcikbd_lock, flags);
do {
+ unsigned long timeout = 1000;
+
kb_wait();
- acknowledge = resend = 0;
+
+ acknowledge = 0;
+ resend = 0;
reply_expected = 1;
+
pcikbd_outb(data, pcikbd_iobase + KBD_DATA_REG);
- start = jiffies;
do {
- if(acknowledge)
- return 1;
- if(jiffies - start >= KBD_TIMEOUT)
- return 0;
- } while(!resend);
- } while(retries-- > 0);
+ if (acknowledge)
+ goto out_ack;
+ if (resend)
+ break;
+ mdelay(1);
+ } while (--timeout);
+ if (timeout == 0)
+ goto out_timeout;
+ } while (retries-- > 0);
+
+out_timeout:
+ spin_unlock_irqrestore(&pcikbd_lock, flags);
return 0;
+
+out_ack:
+ spin_unlock_irqrestore(&pcikbd_lock, flags);
+ return 1;
}
void pcikbd_leds(unsigned char leds)
@@ -360,17 +376,23 @@ void pcikbd_leds(unsigned char leds)
static int __init pcikbd_wait_for_input(void)
{
int status, data;
- unsigned long start = jiffies;
+ unsigned long timeout = 1000;
do {
+ mdelay(1);
+
status = pcikbd_inb(pcikbd_iobase + KBD_STATUS_REG);
- if(!(status & KBD_STAT_OBF))
+ if (!(status & KBD_STAT_OBF))
continue;
+
data = pcikbd_inb(pcikbd_iobase + KBD_DATA_REG);
- if(status & (KBD_STAT_GTO | KBD_STAT_PERR))
+ if (status & (KBD_STAT_GTO | KBD_STAT_PERR))
continue;
+
return (data & 0xff);
- } while(jiffies - start < KBD_INIT_TIMEOUT);
+
+ } while (--timeout > 0);
+
return -1;
}
@@ -573,27 +595,12 @@ struct aux_queue {
};
static struct aux_queue *queue;
-static int aux_ready = 0;
static int aux_count = 0;
static int aux_present = 0;
#define pcimouse_inb(x) inb(x)
#define pcimouse_outb(v,x) outb(v,x)
-#if 0
-
-static __inline__ unsigned char pcimouse_inb(unsigned long port)
-{
- return inb(port);
-}
-
-static __inline__ void pcimouse_outb(unsigned char val, unsigned long port)
-{
- outb(val, port);
-}
-
-#endif
-
/*
* Shared subroutines
*/
@@ -603,11 +610,11 @@ static unsigned int get_from_queue(void)
unsigned int result;
unsigned long flags;
- save_flags(flags);
- cli();
+ spin_lock_irqsave(&pcikbd_lock, flags);
result = queue->buf[queue->tail];
queue->tail = (queue->tail + 1) & (AUX_BUF_SIZE-1);
- restore_flags(flags);
+ spin_unlock_irqrestore(&pcikbd_lock, flags);
+
return result;
}
@@ -645,17 +652,17 @@ static int aux_fasync(int fd, struct file *filp, int on)
static int poll_aux_status(void)
{
- int retries=0;
+ int retries = 0;
while ((pcimouse_inb(pcimouse_iobase + KBD_STATUS_REG) &
(KBD_STAT_IBF | KBD_STAT_OBF)) && retries < MAX_RETRIES) {
if ((pcimouse_inb(pcimouse_iobase + KBD_STATUS_REG) & AUX_STAT_OBF)
== AUX_STAT_OBF)
pcimouse_inb(pcimouse_iobase + KBD_DATA_REG);
- current->state = TASK_INTERRUPTIBLE;
- schedule_timeout((5*HZ + 99) / 100);
+ mdelay(5);
retries++;
}
+
return (retries < MAX_RETRIES);
}
@@ -699,51 +706,38 @@ static void aux_write_cmd(int val)
}
/*
- * AUX handler critical section start and end.
- *
- * Only one process can be in the critical section and all keyboard sends are
- * deferred as long as we're inside. This is necessary as we may sleep when
- * waiting for the keyboard controller and other processes / BH's can
- * preempt us. Please note that the input buffer must be flushed when
- * aux_end_atomic() is called and the interrupt is no longer enabled as not
- * doing so might cause the keyboard driver to ignore all incoming keystrokes.
- */
-
-static DECLARE_MUTEX(aux_sema4);
-
-static inline void aux_start_atomic(void)
-{
- down(&aux_sema4);
- tasklet_disable_nosync(&keyboard_tasklet);
- tasklet_unlock_wait(&keyboard_tasklet);
-}
-
-static inline void aux_end_atomic(void)
-{
- tasklet_enable(&keyboard_tasklet);
- up(&aux_sema4);
-}
-
-/*
* Interrupt from the auxiliary device: a character
* is waiting in the keyboard/aux controller.
*/
void pcimouse_interrupt(int irq, void *dev_id, struct pt_regs *regs)
{
- int head = queue->head;
- int maxhead = (queue->tail-1) & (AUX_BUF_SIZE-1);
+ unsigned long flags;
+ int head, maxhead;
+ unsigned char val;
+
+ spin_lock_irqsave(&pcikbd_lock, flags);
- if ((pcimouse_inb(pcimouse_iobase + KBD_STATUS_REG) & AUX_STAT_OBF) != AUX_STAT_OBF)
+ head = queue->head;
+ maxhead = (queue->tail - 1) & (AUX_BUF_SIZE - 1);
+
+ if ((pcimouse_inb(pcimouse_iobase + KBD_STATUS_REG) & AUX_STAT_OBF) !=
+ AUX_STAT_OBF) {
+ spin_unlock_irqrestore(&pcikbd_lock, flags);
return;
+ }
- add_mouse_randomness(queue->buf[head] = pcimouse_inb(pcimouse_iobase + KBD_DATA_REG));
+ val = pcimouse_inb(pcimouse_iobase + KBD_DATA_REG);
+ queue->buf[head] = val;
+ add_mouse_randomness(val);
if (head != maxhead) {
head++;
- head &= AUX_BUF_SIZE-1;
+ head &= AUX_BUF_SIZE - 1;
}
queue->head = head;
- aux_ready = 1;
+
+ spin_unlock_irqrestore(&pcikbd_lock, flags);
+
if (queue->fasync)
kill_fasync(queue->fasync, SIGIO, POLL_IN);
wake_up_interruptible(&queue->proc_list);
@@ -751,10 +745,13 @@ void pcimouse_interrupt(int irq, void *dev_id, struct pt_regs *regs)
static int aux_release(struct inode * inode, struct file * file)
{
+ unsigned long flags;
+
aux_fasync(-1, file, 0);
if (--aux_count)
return 0;
- aux_start_atomic();
+
+ spin_lock_irqsave(&pcikbd_lock, flags);
/* Disable controller ints */
aux_write_cmd(AUX_INTS_OFF);
@@ -763,7 +760,8 @@ static int aux_release(struct inode * inode, struct file * file)
/* Disable Aux device */
pcimouse_outb(KBD_CCMD_MOUSE_DISABLE, pcimouse_iobase + KBD_CNTL_REG);
poll_aux_status();
- aux_end_atomic();
+
+ spin_unlock_irqrestore(&pcikbd_lock, flags);
MOD_DEC_USE_COUNT;
return 0;
@@ -776,17 +774,19 @@ static int aux_release(struct inode * inode, struct file * file)
static int aux_open(struct inode * inode, struct file * file)
{
+ unsigned long flags;
+
if (!aux_present)
return -ENODEV;
- aux_start_atomic();
- if (aux_count++) {
- aux_end_atomic();
+ if (aux_count++)
return 0;
- }
- if (!poll_aux_status()) { /* FIXME: Race condition */
+
+ spin_lock_irqsave(&pcikbd_lock, flags);
+
+ if (!poll_aux_status()) {
aux_count--;
- aux_end_atomic();
+ spin_unlock_irqrestore(&pcikbd_lock, flags);
return -EBUSY;
}
queue->head = queue->tail = 0; /* Flush input queue */
@@ -798,9 +798,10 @@ static int aux_open(struct inode * inode, struct file * file)
aux_write_dev(AUX_ENABLE_DEV); /* Enable aux device */
aux_write_cmd(AUX_INTS_ON); /* Enable controller ints */
poll_aux_status();
- aux_end_atomic();
- aux_ready = 0;
+ spin_unlock_irqrestore(&pcikbd_lock, flags);
+
+
return 0;
}
@@ -812,23 +813,35 @@ static ssize_t aux_write(struct file * file, const char * buffer,
size_t count, loff_t *ppos)
{
ssize_t retval = 0;
+ unsigned long flags;
if (count) {
ssize_t written = 0;
- aux_start_atomic();
+ spin_lock_irqsave(&pcikbd_lock, flags);
+
do {
char c;
+
+ spin_unlock_irqrestore(&pcikbd_lock, flags);
+
+ get_user(c, buffer++);
+
+ spin_lock_irqsave(&pcikbd_lock, flags);
+
if (!poll_aux_status())
break;
- pcimouse_outb(KBD_CCMD_WRITE_MOUSE, pcimouse_iobase + KBD_CNTL_REG);
+ pcimouse_outb(KBD_CCMD_WRITE_MOUSE,
+ pcimouse_iobase + KBD_CNTL_REG);
if (!poll_aux_status())
break;
- get_user(c, buffer++);
+
pcimouse_outb(c, pcimouse_iobase + KBD_DATA_REG);
written++;
} while (--count);
- aux_end_atomic();
+
+ spin_unlock_irqrestore(&pcikbd_lock, flags);
+
retval = -EIO;
if (written) {
retval = written;
@@ -872,7 +885,6 @@ repeat:
put_user(c, buffer++);
i--;
}
- aux_ready = !queue_empty();
if (count-i) {
file->f_dentry->d_inode->i_atime = CURRENT_TIME;
return count-i;
@@ -885,7 +897,7 @@ repeat:
static unsigned int aux_poll(struct file *file, poll_table * wait)
{
poll_wait(file, &queue->proc_list, wait);
- if (aux_ready)
+ if (!queue_empty())
return POLLIN | POLLRDNORM;
return 0;
}
@@ -972,7 +984,9 @@ found:
pckbd_read_mask = AUX_STAT_OBF;
misc_register(&psaux_mouse);
- aux_start_atomic();
+
+ spin_lock_irq(&pcikbd_lock);
+
pcimouse_outb(KBD_CCMD_MOUSE_ENABLE, pcimouse_iobase + KBD_CNTL_REG);
aux_write_ack(AUX_RESET);
aux_write_ack(AUX_SET_SAMPLE);
@@ -987,7 +1001,8 @@ found:
poll_aux_status();
pcimouse_outb(AUX_INTS_OFF, pcimouse_iobase + KBD_DATA_REG);
poll_aux_status();
- aux_end_atomic();
+
+ spin_unlock_irq(&pcikbd_lock);
return 0;