patch-2.1.48 linux/drivers/char/psaux.c
Next file: linux/drivers/char/sysrq.c
Previous file: linux/drivers/char/pc_keyb.h
Back to the patch index
Back to the overall index
- Lines: 187
- Date:
Thu Jul 31 13:09:17 1997
- Orig file:
v2.1.47/linux/drivers/char/psaux.c
- Orig date:
Thu Jul 17 10:06:04 1997
diff -u --recursive --new-file v2.1.47/linux/drivers/char/psaux.c linux/drivers/char/psaux.c
@@ -53,6 +53,7 @@
#include <asm/io.h>
#include <asm/uaccess.h>
#include <asm/system.h>
+#include <asm/semaphore.h>
#include <linux/config.h>
@@ -141,19 +142,7 @@
schedule();
retries++;
}
- return !(retries==MAX_RETRIES);
-}
-
-static int poll_aux_status_nosleep(void)
-{
- int retries = 0;
-
- while ((inb(KBD_STATUS_REG) & (KBD_STAT_IBF | KBD_STAT_OBF)) && retries < 1000000) {
- if ((inb_p(KBD_STATUS_REG) & AUX_STAT_OBF) == AUX_STAT_OBF)
- inb_p(KBD_DATA_REG);
- retries++;
- }
- return !(retries == 1000000);
+ return (retries < MAX_RETRIES);
}
/*
@@ -173,18 +162,10 @@
*/
#ifdef INITIALIZE_DEVICE
-__initfunc(static void aux_write_dev_nosleep(int val))
-{
- poll_aux_status_nosleep();
- outb_p(KBD_CCMD_WRITE_MOUSE, KBD_CNTL_REG);
- poll_aux_status_nosleep();
- outb_p(val, KBD_DATA_REG);
-}
-
__initfunc(static int aux_write_ack(int val))
{
- aux_write_dev_nosleep(val);
- poll_aux_status_nosleep();
+ aux_write_dev(val);
+ poll_aux_status();
if ((inb(KBD_STATUS_REG) & AUX_STAT_OBF) == AUX_STAT_OBF)
{
@@ -207,6 +188,31 @@
}
/*
+ * 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 struct semaphore aux_sema4 = MUTEX;
+
+static inline void aux_start_atomic(void)
+{
+ down(&aux_sema4);
+ disable_bh(KEYBOARD_BH);
+}
+
+static inline void aux_end_atomic(void)
+{
+ enable_bh(KEYBOARD_BH);
+ up(&aux_sema4);
+}
+
+/*
* Interrupt from the auxiliary device: a character
* is waiting in the keyboard/aux controller.
*/
@@ -236,14 +242,12 @@
fasync_aux(inode, file, 0);
if (--aux_count)
return 0;
- /* disable kbd bh to avoid mixing of cmd bytes */
- disable_bh(KEYBOARD_BH);
+ aux_start_atomic();
aux_write_cmd(AUX_INTS_OFF); /* Disable controller ints */
poll_aux_status();
outb_p(KBD_CCMD_MOUSE_DISABLE, KBD_CNTL_REG); /* Disable Aux device */
poll_aux_status();
- /* reenable kbd bh */
- enable_bh(KEYBOARD_BH);
+ aux_end_atomic();
#ifdef CONFIG_MCA
free_irq(AUX_IRQ, inode);
#else
@@ -262,10 +266,14 @@
{
if (!aux_present)
return -ENODEV;
- if (aux_count++)
+ aux_start_atomic();
+ if (aux_count++) {
+ aux_end_atomic();
return 0;
- if (!poll_aux_status()) {
+ }
+ if (!poll_aux_status()) { /* FIXME: Race condition */
aux_count--;
+ aux_end_atomic();
return -EBUSY;
}
queue->head = queue->tail = 0; /* Flush input queue */
@@ -275,18 +283,16 @@
if (request_irq(AUX_IRQ, aux_interrupt, 0, "PS/2 Mouse", NULL)) {
#endif
aux_count--;
+ aux_end_atomic();
return -EBUSY;
}
MOD_INC_USE_COUNT;
- /* disable kbd bh to avoid mixing of cmd bytes */
- disable_bh(KEYBOARD_BH);
poll_aux_status();
outb_p(KBD_CCMD_MOUSE_ENABLE, KBD_CNTL_REG); /* Enable Aux */
aux_write_dev(AUX_ENABLE_DEV); /* Enable aux device */
aux_write_cmd(AUX_INTS_ON); /* Enable controller ints */
poll_aux_status();
- /* reenable kbd bh */
- enable_bh(KEYBOARD_BH);
+ aux_end_atomic();
aux_ready = 0;
return 0;
@@ -304,9 +310,7 @@
if (count) {
int written = 0;
- /* disable kbd bh to avoid mixing of cmd bytes */
- disable_bh(KEYBOARD_BH);
-
+ aux_start_atomic();
do {
char c;
if (!poll_aux_status())
@@ -318,8 +322,7 @@
outb_p(c, KBD_DATA_REG);
written++;
} while (--count);
- /* reenable kbd bh */
- enable_bh(KEYBOARD_BH);
+ aux_end_atomic();
retval = -EIO;
if (written) {
retval = written;
@@ -618,6 +621,7 @@
queue->head = queue->tail = 0;
queue->proc_list = NULL;
if (!qp_found) {
+ aux_start_atomic();
#ifdef INITIALIZE_DEVICE
outb_p(KBD_CCMD_MOUSE_ENABLE, KBD_CNTL_REG); /* Enable Aux */
aux_write_ack(AUX_SET_SAMPLE);
@@ -625,13 +629,15 @@
aux_write_ack(AUX_SET_RES);
aux_write_ack(3); /* 8 counts per mm */
aux_write_ack(AUX_SET_SCALE21); /* 2:1 scaling */
- poll_aux_status_nosleep();
+ poll_aux_status();
#endif /* INITIALIZE_DEVICE */
outb_p(KBD_CCMD_MOUSE_DISABLE, KBD_CNTL_REG); /* Disable Aux device */
- poll_aux_status_nosleep();
- outb_p(KBD_CCMD_WRITE_MODE, KBD_CNTL_REG);
- poll_aux_status_nosleep();
- outb_p(AUX_INTS_OFF, KBD_DATA_REG);
+ poll_aux_status();
+ outb_p(KBD_CCMD_WRITE_MODE, KBD_CNTL_REG); /* Disable controller interrupts */
+ poll_aux_status();
+ outb_p(AUX_INTS_OFF, KBD_DATA_REG);
+ poll_aux_status();
+ aux_end_atomic();
}
return 0;
}
FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen, slshen@lbl.gov