Input: i8042 - break load dependency between atkbd/psmouse and i8042
As explained in 1407814240-4275-1-git-send-email-decui@microsoft.com we have a hard load dependency between i8042 and atkbd which prevents keyboard from working on Gen2 Hyper-V VMs. > hyperv_keyboard invokes serio_interrupt(), which needs a valid serio > driver like atkbd.c. atkbd.c depends on libps2.c because it invokes > ps2_command(). libps2.c depends on i8042.c because it invokes > i8042_check_port_owner(). As a result, hyperv_keyboard actually > depends on i8042.c. > > For a Generation 2 Hyper-V VM (meaning no i8042 device emulated), if a > Linux VM (like Arch Linux) happens to configure CONFIG_SERIO_I8042=m > rather than =y, atkbd.ko can't load because i8042.ko can't load(due to > no i8042 device emulated) and finally hyperv_keyboard can't work and > the user can't input: https://bugs.archlinux.org/task/39820 > (Ubuntu/RHEL/SUSE aren't affected since they use CONFIG_SERIO_I8042=y) To break the dependency we move away from using i8042_check_port_owner() and instead allow serio port owner specify a mutex that clients should use to serialize PS/2 command stream. Reported-by: Mark Laws <mdl@60hz.org> Tested-by: Mark Laws <mdl@60hz.org> Cc: stable@vger.kernel.org Signed-off-by: Dmitry Torokhov <dmitry.torokhov@gmail.com>
This commit is contained in:
@@ -1277,6 +1277,7 @@ static int __init i8042_create_kbd_port(void)
|
||||
serio->start = i8042_start;
|
||||
serio->stop = i8042_stop;
|
||||
serio->close = i8042_port_close;
|
||||
serio->ps2_cmd_mutex = &i8042_mutex;
|
||||
serio->port_data = port;
|
||||
serio->dev.parent = &i8042_platform_device->dev;
|
||||
strlcpy(serio->name, "i8042 KBD port", sizeof(serio->name));
|
||||
@@ -1373,21 +1374,6 @@ static void 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)
|
||||
|
@@ -56,19 +56,17 @@ EXPORT_SYMBOL(ps2_sendbyte);
|
||||
|
||||
void ps2_begin_command(struct ps2dev *ps2dev)
|
||||
{
|
||||
mutex_lock(&ps2dev->cmd_mutex);
|
||||
struct mutex *m = ps2dev->serio->ps2_cmd_mutex ?: &ps2dev->cmd_mutex;
|
||||
|
||||
if (i8042_check_port_owner(ps2dev->serio))
|
||||
i8042_lock_chip();
|
||||
mutex_lock(m);
|
||||
}
|
||||
EXPORT_SYMBOL(ps2_begin_command);
|
||||
|
||||
void ps2_end_command(struct ps2dev *ps2dev)
|
||||
{
|
||||
if (i8042_check_port_owner(ps2dev->serio))
|
||||
i8042_unlock_chip();
|
||||
struct mutex *m = ps2dev->serio->ps2_cmd_mutex ?: &ps2dev->cmd_mutex;
|
||||
|
||||
mutex_unlock(&ps2dev->cmd_mutex);
|
||||
mutex_unlock(m);
|
||||
}
|
||||
EXPORT_SYMBOL(ps2_end_command);
|
||||
|
||||
|
Reference in New Issue
Block a user