summaryrefslogtreecommitdiffstats
path: root/drivers/input/serio
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/input/serio')
-rw-r--r--drivers/input/serio/Kconfig13
-rw-r--r--drivers/input/serio/i8042.c44
-rw-r--r--drivers/input/serio/libps2.c29
-rw-r--r--drivers/input/serio/serio_raw.c1
-rw-r--r--drivers/input/serio/serport.c1
5 files changed, 78 insertions, 10 deletions
diff --git a/drivers/input/serio/Kconfig b/drivers/input/serio/Kconfig
index c4b3fbd1a80..aa533ceffe3 100644
--- a/drivers/input/serio/Kconfig
+++ b/drivers/input/serio/Kconfig
@@ -4,7 +4,7 @@
config SERIO
tristate "Serial I/O support" if EMBEDDED || !X86
default y
- ---help---
+ help
Say Yes here if you have any input device that uses serial I/O to
communicate with the system. This includes the
* standard AT keyboard and PS/2 mouse *
@@ -22,7 +22,7 @@ config SERIO_I8042
tristate "i8042 PC Keyboard controller" if EMBEDDED || !X86
default y
depends on !PARISC && (!ARM || ARCH_SHARK || FOOTBRIDGE_HOST) && !M68K && !BLACKFIN
- ---help---
+ help
i8042 is the chip over which the standard AT keyboard and PS/2
mouse are connected to the computer. If you use these devices,
you'll need to say Y here.
@@ -35,7 +35,7 @@ config SERIO_I8042
config SERIO_SERPORT
tristate "Serial port line discipline"
default y
- ---help---
+ help
Say Y here if you plan to use an input device (mouse, joystick,
tablet, 6dof) that communicates over the RS232 serial (COM) port.
@@ -49,7 +49,7 @@ config SERIO_SERPORT
config SERIO_CT82C710
tristate "ct82c710 Aux port controller"
depends on X86
- ---help---
+ help
Say Y here if you have a Texas Instruments TravelMate notebook
equipped with the ct82c710 chip and want to use a mouse connected
to the "QuickPort".
@@ -66,7 +66,7 @@ config SERIO_Q40KBD
config SERIO_PARKBD
tristate "Parallel port keyboard adapter"
depends on PARPORT
- ---help---
+ help
Say Y here if you built a simple parallel port adapter to attach
an additional AT keyboard, XT keyboard or PS/2 mouse.
@@ -124,7 +124,7 @@ config HP_SDC
tristate "HP System Device Controller i8042 Support"
depends on (GSC || HP300) && SERIO
default y
- ---help---
+ help
This option enables support for the "System Device
Controller", an i8042 carrying microcode to manage a
few miscellaneous devices on some Hewlett Packard systems.
@@ -168,6 +168,7 @@ config SERIO_MACEPS2
config SERIO_LIBPS2
tristate "PS/2 driver library" if EMBEDDED
+ depends on SERIO_I8042 || SERIO_I8042=n
help
Say Y here if you are using a driver for device connected
to a PS/2 port, such as PS/2 mouse or standard AT keyboard.
diff --git a/drivers/input/serio/i8042.c b/drivers/input/serio/i8042.c
index eb3ff94af58..a31578170cc 100644
--- a/drivers/input/serio/i8042.c
+++ b/drivers/input/serio/i8042.c
@@ -87,8 +87,22 @@ static bool i8042_bypass_aux_irq_test;
#include "i8042.h"
+/*
+ * i8042_lock protects serialization between i8042_command and
+ * the interrupt handler.
+ */
static DEFINE_SPINLOCK(i8042_lock);
+/*
+ * Writers to AUX and KBD ports as well as users issuing i8042_command
+ * directly should acquire i8042_mutex (by means of calling
+ * i8042_lock_chip() and i8042_unlock_ship() helpers) to ensure that
+ * they do not disturb each other (unfortunately in many i8042
+ * implementations write to one of the ports will immediately abort
+ * command that is being processed by another port).
+ */
+static DEFINE_MUTEX(i8042_mutex);
+
struct i8042_port {
struct serio *serio;
int irq;
@@ -113,6 +127,18 @@ static struct platform_device *i8042_platform_device;
static irqreturn_t i8042_interrupt(int irq, void *dev_id);
+void i8042_lock_chip(void)
+{
+ mutex_lock(&i8042_mutex);
+}
+EXPORT_SYMBOL(i8042_lock_chip);
+
+void i8042_unlock_chip(void)
+{
+ mutex_unlock(&i8042_mutex);
+}
+EXPORT_SYMBOL(i8042_unlock_chip);
+
/*
* The i8042_wait_read() and i8042_wait_write functions wait for the i8042 to
* be ready for reading values from it / writing values to it.
@@ -583,6 +609,8 @@ static irqreturn_t __init i8042_aux_test_irq(int irq, void *dev_id)
str = i8042_read_status();
if (str & I8042_STR_OBF) {
data = i8042_read_data();
+ dbg("%02x <- i8042 (aux_test_irq, %s)",
+ data, str & I8042_STR_AUXDATA ? "aux" : "kbd");
if (i8042_irq_being_tested &&
data == 0xa5 && (str & I8042_STR_AUXDATA))
complete(&i8042_aux_irq_delivered);
@@ -724,6 +752,7 @@ static int __init i8042_check_aux(void)
* AUX IRQ was never delivered so we need to flush the controller to
* get rid of the byte we put there; otherwise keyboard may not work.
*/
+ dbg(" -- i8042 (aux irq test timeout)");
i8042_flush();
retval = -1;
}
@@ -1161,6 +1190,21 @@ static void __devexit i8042_unregister_ports(void)
}
}
+/*
+ * Checks whether port belongs to i8042 controller.
+ */
+bool i8042_check_port_owner(const struct serio *port)
+{
+ int i;
+
+ for (i = 0; i < I8042_NUM_PORTS; i++)
+ if (i8042_ports[i].serio == port)
+ return true;
+
+ return false;
+}
+EXPORT_SYMBOL(i8042_check_port_owner);
+
static void i8042_free_irqs(void)
{
if (i8042_aux_irq_registered)
diff --git a/drivers/input/serio/libps2.c b/drivers/input/serio/libps2.c
index 3a95b508bf2..f3876acc3e8 100644
--- a/drivers/input/serio/libps2.c
+++ b/drivers/input/serio/libps2.c
@@ -13,10 +13,12 @@
#include <linux/delay.h>
#include <linux/module.h>
+#include <linux/sched.h>
#include <linux/slab.h>
#include <linux/interrupt.h>
#include <linux/input.h>
#include <linux/serio.h>
+#include <linux/i8042.h>
#include <linux/init.h>
#include <linux/libps2.h>
@@ -54,6 +56,24 @@ int ps2_sendbyte(struct ps2dev *ps2dev, unsigned char byte, int timeout)
}
EXPORT_SYMBOL(ps2_sendbyte);
+void ps2_begin_command(struct ps2dev *ps2dev)
+{
+ mutex_lock(&ps2dev->cmd_mutex);
+
+ if (i8042_check_port_owner(ps2dev->serio))
+ i8042_lock_chip();
+}
+EXPORT_SYMBOL(ps2_begin_command);
+
+void ps2_end_command(struct ps2dev *ps2dev)
+{
+ if (i8042_check_port_owner(ps2dev->serio))
+ i8042_unlock_chip();
+
+ mutex_unlock(&ps2dev->cmd_mutex);
+}
+EXPORT_SYMBOL(ps2_end_command);
+
/*
* ps2_drain() waits for device to transmit requested number of bytes
* and discards them.
@@ -66,7 +86,7 @@ void ps2_drain(struct ps2dev *ps2dev, int maxbytes, int timeout)
maxbytes = sizeof(ps2dev->cmdbuf);
}
- mutex_lock(&ps2dev->cmd_mutex);
+ ps2_begin_command(ps2dev);
serio_pause_rx(ps2dev->serio);
ps2dev->flags = PS2_FLAG_CMD;
@@ -76,7 +96,8 @@ void ps2_drain(struct ps2dev *ps2dev, int maxbytes, int timeout)
wait_event_timeout(ps2dev->wait,
!(ps2dev->flags & PS2_FLAG_CMD),
msecs_to_jiffies(timeout));
- mutex_unlock(&ps2dev->cmd_mutex);
+
+ ps2_end_command(ps2dev);
}
EXPORT_SYMBOL(ps2_drain);
@@ -237,9 +258,9 @@ int ps2_command(struct ps2dev *ps2dev, unsigned char *param, int command)
{
int rc;
- mutex_lock(&ps2dev->cmd_mutex);
+ ps2_begin_command(ps2dev);
rc = __ps2_command(ps2dev, param, command);
- mutex_unlock(&ps2dev->cmd_mutex);
+ ps2_end_command(ps2dev);
return rc;
}
diff --git a/drivers/input/serio/serio_raw.c b/drivers/input/serio/serio_raw.c
index b03009bb746..27fdaaffbb4 100644
--- a/drivers/input/serio/serio_raw.c
+++ b/drivers/input/serio/serio_raw.c
@@ -9,6 +9,7 @@
* the Free Software Foundation.
*/
+#include <linux/sched.h>
#include <linux/slab.h>
#include <linux/smp_lock.h>
#include <linux/poll.h>
diff --git a/drivers/input/serio/serport.c b/drivers/input/serio/serport.c
index b9694b6445d..6d345112bcb 100644
--- a/drivers/input/serio/serport.c
+++ b/drivers/input/serio/serport.c
@@ -15,6 +15,7 @@
#include <asm/uaccess.h>
#include <linux/kernel.h>
+#include <linux/sched.h>
#include <linux/slab.h>
#include <linux/module.h>
#include <linux/init.h>