summaryrefslogtreecommitdiff
path: root/drivers/input/serio
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/input/serio')
-rw-r--r--drivers/input/serio/hp_sdc.c24
-rw-r--r--drivers/input/serio/i8042-x86ia64io.h28
-rw-r--r--drivers/input/serio/i8042.c37
-rw-r--r--drivers/input/serio/sa1111ps2.c2
4 files changed, 81 insertions, 10 deletions
diff --git a/drivers/input/serio/hp_sdc.c b/drivers/input/serio/hp_sdc.c
index bfe4924..1c9410d 100644
--- a/drivers/input/serio/hp_sdc.c
+++ b/drivers/input/serio/hp_sdc.c
@@ -819,6 +819,7 @@ static const struct parisc_device_id hp_sdc_tbl[] = {
MODULE_DEVICE_TABLE(parisc, hp_sdc_tbl);
static int __init hp_sdc_init_hppa(struct parisc_device *d);
+static struct delayed_work moduleloader_work;
static struct parisc_driver hp_sdc_driver = {
.name = "hp_sdc",
@@ -930,8 +931,15 @@ static int __init hp_sdc_init(void)
#if defined(__hppa__)
+static void request_module_delayed(struct work_struct *work)
+{
+ request_module("hp_sdc_mlc");
+}
+
static int __init hp_sdc_init_hppa(struct parisc_device *d)
{
+ int ret;
+
if (!d)
return 1;
if (hp_sdc.dev != NULL)
@@ -944,13 +952,26 @@ static int __init hp_sdc_init_hppa(struct parisc_device *d)
hp_sdc.data_io = d->hpa.start + 0x800;
hp_sdc.status_io = d->hpa.start + 0x801;
- return hp_sdc_init();
+ INIT_DELAYED_WORK(&moduleloader_work, request_module_delayed);
+
+ ret = hp_sdc_init();
+ /* after sucessfull initialization give SDC some time to settle
+ * and then load the hp_sdc_mlc upper layer driver */
+ if (!ret)
+ schedule_delayed_work(&moduleloader_work,
+ msecs_to_jiffies(2000));
+
+ return ret;
}
#endif /* __hppa__ */
static void hp_sdc_exit(void)
{
+ /* do nothing if we don't have a SDC */
+ if (!hp_sdc.dev)
+ return;
+
write_lock_irq(&hp_sdc.lock);
/* Turn off all maskable "sub-function" irq's. */
@@ -969,6 +990,7 @@ static void hp_sdc_exit(void)
tasklet_kill(&hp_sdc.task);
#if defined(__hppa__)
+ cancel_delayed_work_sync(&moduleloader_work);
if (unregister_parisc_driver(&hp_sdc_driver))
printk(KERN_WARNING PREFIX "Error unregistering HP SDC");
#endif
diff --git a/drivers/input/serio/i8042-x86ia64io.h b/drivers/input/serio/i8042-x86ia64io.h
index 83ed2d5..fb8a3cd 100644
--- a/drivers/input/serio/i8042-x86ia64io.h
+++ b/drivers/input/serio/i8042-x86ia64io.h
@@ -377,6 +377,24 @@ static struct dmi_system_id __initdata i8042_dmi_nomux_table[] = {
{ }
};
+static struct dmi_system_id __initdata i8042_dmi_reset_table[] = {
+ {
+ .ident = "MSI Wind U-100",
+ .matches = {
+ DMI_MATCH(DMI_BOARD_NAME, "U-100"),
+ DMI_MATCH(DMI_BOARD_VENDOR, "MICRO-STAR INTERNATIONAL CO., LTD"),
+ },
+ },
+ {
+ .ident = "LG Electronics X110",
+ .matches = {
+ DMI_MATCH(DMI_BOARD_NAME, "X110"),
+ DMI_MATCH(DMI_BOARD_VENDOR, "LG Electronics Inc."),
+ },
+ },
+ { }
+};
+
#ifdef CONFIG_PNP
static struct dmi_system_id __initdata i8042_dmi_nopnp_table[] = {
{
@@ -386,6 +404,13 @@ static struct dmi_system_id __initdata i8042_dmi_nopnp_table[] = {
DMI_MATCH(DMI_BOARD_VENDOR, "Intel Corporation"),
},
},
+ {
+ .ident = "MSI Wind U-100",
+ .matches = {
+ DMI_MATCH(DMI_BOARD_NAME, "U-100"),
+ DMI_MATCH(DMI_BOARD_VENDOR, "MICRO-STAR INTERNATIONAL CO., LTD"),
+ },
+ },
{ }
};
#endif
@@ -698,6 +723,9 @@ static int __init i8042_platform_init(void)
#endif
#ifdef CONFIG_X86
+ if (dmi_check_system(i8042_dmi_reset_table))
+ i8042_reset = 1;
+
if (dmi_check_system(i8042_dmi_noloop_table))
i8042_noloop = 1;
diff --git a/drivers/input/serio/i8042.c b/drivers/input/serio/i8042.c
index 170f71e..3cffb70 100644
--- a/drivers/input/serio/i8042.c
+++ b/drivers/input/serio/i8042.c
@@ -712,22 +712,43 @@ static int i8042_controller_check(void)
static int i8042_controller_selftest(void)
{
unsigned char param;
+ int i = 0;
if (!i8042_reset)
return 0;
- if (i8042_command(&param, I8042_CMD_CTL_TEST)) {
- printk(KERN_ERR "i8042.c: i8042 controller self test timeout.\n");
- return -ENODEV;
- }
+ /*
+ * We try this 5 times; on some really fragile systems this does not
+ * take the first time...
+ */
+ do {
+
+ if (i8042_command(&param, I8042_CMD_CTL_TEST)) {
+ printk(KERN_ERR "i8042.c: i8042 controller self test timeout.\n");
+ return -ENODEV;
+ }
+
+ if (param == I8042_RET_CTL_TEST)
+ return 0;
- if (param != I8042_RET_CTL_TEST) {
printk(KERN_ERR "i8042.c: i8042 controller selftest failed. (%#x != %#x)\n",
- param, I8042_RET_CTL_TEST);
- return -EIO;
- }
+ param, I8042_RET_CTL_TEST);
+ msleep(50);
+ } while (i++ < 5);
+#ifdef CONFIG_X86
+ /*
+ * On x86, we don't fail entire i8042 initialization if controller
+ * reset fails in hopes that keyboard port will still be functional
+ * and user will still get a working keyboard. This is especially
+ * important on netbooks. On other arches we trust hardware more.
+ */
+ printk(KERN_INFO
+ "i8042: giving up on controller selftest, continuing anyway...\n");
return 0;
+#else
+ return -EIO;
+#endif
}
/*
diff --git a/drivers/input/serio/sa1111ps2.c b/drivers/input/serio/sa1111ps2.c
index 57953c0..f412c69 100644
--- a/drivers/input/serio/sa1111ps2.c
+++ b/drivers/input/serio/sa1111ps2.c
@@ -77,7 +77,7 @@ static irqreturn_t ps2_txint(int irq, void *dev_id)
spin_lock(&ps2if->lock);
status = sa1111_readl(ps2if->base + SA1111_PS2STAT);
if (ps2if->head == ps2if->tail) {
- disable_irq(irq);
+ disable_irq_nosync(irq);
/* done */
} else if (status & PS2STAT_TXE) {
sa1111_writel(ps2if->buf[ps2if->tail], ps2if->base + SA1111_PS2DATA);