aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/input/serio/i8042.c
diff options
context:
space:
mode:
authorDmitry Torokhov <dmitry.torokhov@gmail.com>2009-09-16 04:06:43 -0400
committerDmitry Torokhov <dmitry.torokhov@gmail.com>2009-09-18 02:23:45 -0400
commit181d683d752c432635eda0f182ee71548c1f1820 (patch)
tree1fa397811ea6bcc73001fe1ab5b53525f2b88f74 /drivers/input/serio/i8042.c
parent0cb583fd2862f19ea88b02eb307d11c09e51e2f8 (diff)
Input: libps2 - additional locking for i8042 ports
The serio ports on i8042 are not completely isolated; while we provide enough locking to ensure proper serialization when accessing control and data registers AUX and KBD ports can still have an effect on each other on PS/2 protocol level. The most prominent effect is that issuing a command for the device connected to one port may cause abort of the command currently executing by the device connected to another port. Since i8042 nor serio subsystem are not aware of the details of the PS/2 protocol (length of the commands and their replies and so on) the locking should be done on libps2 level by adding special handling when we see that we are dealing with serio port on i8042. Signed-off-by: Dmitry Torokhov <dtor@mail.ru>
Diffstat (limited to 'drivers/input/serio/i8042.c')
-rw-r--r--drivers/input/serio/i8042.c41
1 files changed, 41 insertions, 0 deletions
diff --git a/drivers/input/serio/i8042.c b/drivers/input/serio/i8042.c
index eb3ff94af58c..bc56e52b945f 100644
--- a/drivers/input/serio/i8042.c
+++ b/drivers/input/serio/i8042.c
@@ -87,8 +87,22 @@ static bool i8042_bypass_aux_irq_test;
87 87
88#include "i8042.h" 88#include "i8042.h"
89 89
90/*
91 * i8042_lock protects serialization between i8042_command and
92 * the interrupt handler.
93 */
90static DEFINE_SPINLOCK(i8042_lock); 94static DEFINE_SPINLOCK(i8042_lock);
91 95
96/*
97 * Writers to AUX and KBD ports as well as users issuing i8042_command
98 * directly should acquire i8042_mutex (by means of calling
99 * i8042_lock_chip() and i8042_unlock_ship() helpers) to ensure that
100 * they do not disturb each other (unfortunately in many i8042
101 * implementations write to one of the ports will immediately abort
102 * command that is being processed by another port).
103 */
104static DEFINE_MUTEX(i8042_mutex);
105
92struct i8042_port { 106struct i8042_port {
93 struct serio *serio; 107 struct serio *serio;
94 int irq; 108 int irq;
@@ -113,6 +127,18 @@ static struct platform_device *i8042_platform_device;
113 127
114static irqreturn_t i8042_interrupt(int irq, void *dev_id); 128static irqreturn_t i8042_interrupt(int irq, void *dev_id);
115 129
130void i8042_lock_chip(void)
131{
132 mutex_lock(&i8042_mutex);
133}
134EXPORT_SYMBOL(i8042_lock_chip);
135
136void i8042_unlock_chip(void)
137{
138 mutex_unlock(&i8042_mutex);
139}
140EXPORT_SYMBOL(i8042_unlock_chip);
141
116/* 142/*
117 * The i8042_wait_read() and i8042_wait_write functions wait for the i8042 to 143 * The i8042_wait_read() and i8042_wait_write functions wait for the i8042 to
118 * be ready for reading values from it / writing values to it. 144 * be ready for reading values from it / writing values to it.
@@ -1161,6 +1187,21 @@ static void __devexit i8042_unregister_ports(void)
1161 } 1187 }
1162} 1188}
1163 1189
1190/*
1191 * Checks whether port belongs to i8042 controller.
1192 */
1193bool i8042_check_port_owner(const struct serio *port)
1194{
1195 int i;
1196
1197 for (i = 0; i < I8042_NUM_PORTS; i++)
1198 if (i8042_ports[i].serio == port)
1199 return true;
1200
1201 return false;
1202}
1203EXPORT_SYMBOL(i8042_check_port_owner);
1204
1164static void i8042_free_irqs(void) 1205static void i8042_free_irqs(void)
1165{ 1206{
1166 if (i8042_aux_irq_registered) 1207 if (i8042_aux_irq_registered)