#include <linux/dmi.h>
-static struct dmi_system_id __initdata i8042_dmi_table[] = {
+static struct dmi_system_id __initdata i8042_dmi_noloop_table[] = {
{
.ident = "Compaq Proliant 8500",
.matches = {
},
{ }
};
+
+/*
+ * Some Fujitsu notebooks are having trouble with touchpads if
+ * active multiplexing mode is activated. Luckily they don't have
+ * external PS/2 ports so we can safely disable it.
+ * ... apparently some Toshibas don't like MUX mode either and
+ * die horrible death on reboot.
+ */
+static struct dmi_system_id __initdata i8042_dmi_nomux_table[] = {
+ {
+ .ident = "Fujitsu Lifebook P7010/P7010D",
+ .matches = {
+ DMI_MATCH(DMI_SYS_VENDOR, "FUJITSU"),
+ DMI_MATCH(DMI_PRODUCT_NAME, "P7010"),
+ },
+ },
+ {
+ .ident = "Fujitsu Lifebook P5020D",
+ .matches = {
+ DMI_MATCH(DMI_SYS_VENDOR, "FUJITSU"),
+ DMI_MATCH(DMI_PRODUCT_NAME, "LifeBook P Series"),
+ },
+ },
+ {
+ .ident = "Fujitsu Lifebook S2000",
+ .matches = {
+ DMI_MATCH(DMI_SYS_VENDOR, "FUJITSU"),
+ DMI_MATCH(DMI_PRODUCT_NAME, "LifeBook S Series"),
+ },
+ },
+ {
+ .ident = "Fujitsu Lifebook S6230",
+ .matches = {
+ DMI_MATCH(DMI_SYS_VENDOR, "FUJITSU"),
+ DMI_MATCH(DMI_PRODUCT_NAME, "LifeBook S6230"),
+ },
+ },
+ {
+ .ident = "Fujitsu T70H",
+ .matches = {
+ DMI_MATCH(DMI_SYS_VENDOR, "FUJITSU"),
+ DMI_MATCH(DMI_PRODUCT_NAME, "FMVLT70H"),
+ },
+ },
+ {
+ .ident = "Toshiba P10",
+ .matches = {
+ DMI_MATCH(DMI_SYS_VENDOR, "TOSHIBA"),
+ DMI_MATCH(DMI_PRODUCT_NAME, "Satellite P10"),
+ },
+ },
+ { }
+};
+
+
+
#endif
-#if defined(__ia64__) && defined(CONFIG_ACPI)
-#include <linux/acpi.h>
-#include <acpi/acpi_bus.h>
-struct i8042_acpi_resources {
- unsigned int port1;
- unsigned int port2;
- unsigned int irq;
-};
+#ifdef CONFIG_PNP
+#include <linux/pnp.h>
-static int i8042_acpi_kbd_registered;
-static int i8042_acpi_aux_registered;
+static int i8042_pnp_kbd_registered;
+static int i8042_pnp_aux_registered;
-static acpi_status i8042_acpi_parse_resource(struct acpi_resource *res, void *data)
-{
- struct i8042_acpi_resources *i8042_res = data;
- struct acpi_resource_io *io;
- struct acpi_resource_fixed_io *fixed_io;
- struct acpi_resource_irq *irq;
- struct acpi_resource_ext_irq *ext_irq;
-
- switch (res->id) {
- case ACPI_RSTYPE_IO:
- io = &res->data.io;
- if (io->range_length) {
- if (!i8042_res->port1)
- i8042_res->port1 = io->min_base_address;
- else
- i8042_res->port2 = io->min_base_address;
- }
- break;
-
- case ACPI_RSTYPE_FIXED_IO:
- fixed_io = &res->data.fixed_io;
- if (fixed_io->range_length) {
- if (!i8042_res->port1)
- i8042_res->port1 = fixed_io->base_address;
- else
- i8042_res->port2 = fixed_io->base_address;
- }
- break;
-
- case ACPI_RSTYPE_IRQ:
- irq = &res->data.irq;
- if (irq->number_of_interrupts > 0)
- i8042_res->irq =
- acpi_register_gsi(irq->interrupts[0],
- irq->edge_level,
- irq->active_high_low);
- break;
-
- case ACPI_RSTYPE_EXT_IRQ:
- ext_irq = &res->data.extended_irq;
- if (ext_irq->number_of_interrupts > 0)
- i8042_res->irq =
- acpi_register_gsi(ext_irq->interrupts[0],
- ext_irq->edge_level,
- ext_irq->active_high_low);
- break;
- }
- return AE_OK;
-}
+static int i8042_pnp_command_reg;
+static int i8042_pnp_data_reg;
+static int i8042_pnp_kbd_irq;
+static int i8042_pnp_aux_irq;
+
+static char i8042_pnp_kbd_name[32];
+static char i8042_pnp_aux_name[32];
-static int i8042_acpi_kbd_add(struct acpi_device *device)
+static int i8042_pnp_kbd_probe(struct pnp_dev *dev, const struct pnp_device_id *did)
{
- struct i8042_acpi_resources kbd_res;
- acpi_status status;
+ if (pnp_port_valid(dev, 0) && pnp_port_len(dev, 0) == 1)
+ i8042_pnp_data_reg = pnp_port_start(dev,0);
- memset(&kbd_res, 0, sizeof(kbd_res));
- status = acpi_walk_resources(device->handle, METHOD_NAME__CRS,
- i8042_acpi_parse_resource, &kbd_res);
- if (ACPI_FAILURE(status))
- return -ENODEV;
+ if (pnp_port_valid(dev, 1) && pnp_port_len(dev, 1) == 1)
+ i8042_pnp_command_reg = pnp_port_start(dev, 1);
+
+ if (pnp_irq_valid(dev,0))
+ i8042_pnp_kbd_irq = pnp_irq(dev, 0);
- if (kbd_res.port1)
- i8042_data_reg = kbd_res.port1;
- else
- printk(KERN_WARNING "ACPI: [%s] has no data port; default is 0x%x\n",
- acpi_device_bid(device), i8042_data_reg);
-
- if (kbd_res.port2)
- i8042_command_reg = kbd_res.port2;
- else
- printk(KERN_WARNING "ACPI: [%s] has no command port; default is 0x%x\n",
- acpi_device_bid(device), i8042_command_reg);
-
- if (kbd_res.irq)
- i8042_kbd_irq = kbd_res.irq;
- else
- printk(KERN_WARNING "ACPI: [%s] has no IRQ; default is %d\n",
- acpi_device_bid(device), i8042_kbd_irq);
-
- strncpy(acpi_device_name(device), "PS/2 Keyboard Controller",
- sizeof(acpi_device_name(device)));
- printk("ACPI: %s [%s] at I/O 0x%x, 0x%x, irq %d\n",
- acpi_device_name(device), acpi_device_bid(device),
- i8042_data_reg, i8042_command_reg, i8042_kbd_irq);
+ strncpy(i8042_pnp_kbd_name, did->id, sizeof(i8042_pnp_kbd_name));
+ if (strlen(pnp_dev_name(dev))) {
+ strncat(i8042_pnp_kbd_name, ":", sizeof(i8042_pnp_kbd_name));
+ strncat(i8042_pnp_kbd_name, pnp_dev_name(dev), sizeof(i8042_pnp_kbd_name));
+ }
return 0;
}
-static int i8042_acpi_aux_add(struct acpi_device *device)
+static int i8042_pnp_aux_probe(struct pnp_dev *dev, const struct pnp_device_id *did)
{
- struct i8042_acpi_resources aux_res;
- acpi_status status;
+ if (pnp_port_valid(dev, 0) && pnp_port_len(dev, 0) == 1)
+ i8042_pnp_data_reg = pnp_port_start(dev,0);
- memset(&aux_res, 0, sizeof(aux_res));
- status = acpi_walk_resources(device->handle, METHOD_NAME__CRS,
- i8042_acpi_parse_resource, &aux_res);
- if (ACPI_FAILURE(status))
- return -ENODEV;
+ if (pnp_port_valid(dev, 1) && pnp_port_len(dev, 1) == 1)
+ i8042_pnp_command_reg = pnp_port_start(dev, 1);
- if (aux_res.irq)
- i8042_aux_irq = aux_res.irq;
- else
- printk(KERN_WARNING "ACPI: [%s] has no IRQ; default is %d\n",
- acpi_device_bid(device), i8042_aux_irq);
+ if (pnp_irq_valid(dev, 0))
+ i8042_pnp_aux_irq = pnp_irq(dev, 0);
- strncpy(acpi_device_name(device), "PS/2 Mouse Controller",
- sizeof(acpi_device_name(device)));
- printk("ACPI: %s [%s] at irq %d\n",
- acpi_device_name(device), acpi_device_bid(device), i8042_aux_irq);
+ strncpy(i8042_pnp_aux_name, did->id, sizeof(i8042_pnp_aux_name));
+ if (strlen(pnp_dev_name(dev))) {
+ strncat(i8042_pnp_aux_name, ":", sizeof(i8042_pnp_aux_name));
+ strncat(i8042_pnp_aux_name, pnp_dev_name(dev), sizeof(i8042_pnp_aux_name));
+ }
return 0;
}
-static struct acpi_driver i8042_acpi_kbd_driver = {
- .name = "i8042",
- .ids = "PNP0303,PNP030B",
- .ops = {
- .add = i8042_acpi_kbd_add,
- },
+static struct pnp_device_id pnp_kbd_devids[] = {
+ { .id = "PNP0303", .driver_data = 0 },
+ { .id = "PNP030b", .driver_data = 0 },
+ { .id = "", },
};
-static struct acpi_driver i8042_acpi_aux_driver = {
- .name = "i8042",
- .ids = "PNP0F03,PNP0F0B,PNP0F0E,PNP0F12,PNP0F13,SYN0801",
- .ops = {
- .add = i8042_acpi_aux_add,
- },
+static struct pnp_driver i8042_pnp_kbd_driver = {
+ .name = "i8042 kbd",
+ .id_table = pnp_kbd_devids,
+ .probe = i8042_pnp_kbd_probe,
};
-static int i8042_acpi_init(void)
+static struct pnp_device_id pnp_aux_devids[] = {
+ { .id = "PNP0f03", .driver_data = 0 },
+ { .id = "PNP0f0b", .driver_data = 0 },
+ { .id = "PNP0f0e", .driver_data = 0 },
+ { .id = "PNP0f12", .driver_data = 0 },
+ { .id = "PNP0f13", .driver_data = 0 },
+ { .id = "PNP0f19", .driver_data = 0 },
+ { .id = "PNP0f1c", .driver_data = 0 },
+ { .id = "SYN0801", .driver_data = 0 },
+ { .id = "", },
+};
+
+static struct pnp_driver i8042_pnp_aux_driver = {
+ .name = "i8042 aux",
+ .id_table = pnp_aux_devids,
+ .probe = i8042_pnp_aux_probe,
+};
+
+static void i8042_pnp_exit(void)
{
- int result;
+ if (i8042_pnp_kbd_registered) {
+ i8042_pnp_kbd_registered = 0;
+ pnp_unregister_driver(&i8042_pnp_kbd_driver);
+ }
+
+ if (i8042_pnp_aux_registered) {
+ i8042_pnp_aux_registered = 0;
+ pnp_unregister_driver(&i8042_pnp_aux_driver);
+ }
+}
- if (acpi_disabled || i8042_noacpi) {
- printk("i8042: ACPI detection disabled\n");
+static int i8042_pnp_init(void)
+{
+ int result_kbd, result_aux;
+
+ if (i8042_nopnp) {
+ printk(KERN_INFO "i8042: PNP detection disabled\n");
return 0;
}
- result = acpi_bus_register_driver(&i8042_acpi_kbd_driver);
- if (result < 0)
- return result;
+ if ((result_kbd = pnp_register_driver(&i8042_pnp_kbd_driver)) >= 0)
+ i8042_pnp_kbd_registered = 1;
+ if ((result_aux = pnp_register_driver(&i8042_pnp_aux_driver)) >= 0)
+ i8042_pnp_aux_registered = 1;
- if (result == 0) {
- acpi_bus_unregister_driver(&i8042_acpi_kbd_driver);
+ if (result_kbd <= 0 && result_aux <= 0) {
+ i8042_pnp_exit();
+#if defined(__ia64__)
return -ENODEV;
+#else
+ printk(KERN_INFO "PNP: No PS/2 controller found. Probing ports directly.\n");
+ return 0;
+#endif
+ }
+
+ if (((i8042_pnp_data_reg & ~0xf) == (i8042_data_reg & ~0xf) &&
+ i8042_pnp_data_reg != i8042_data_reg) || !i8042_pnp_data_reg) {
+ printk(KERN_WARNING "PNP: PS/2 controller has invalid data port %#x; using default %#x\n",
+ i8042_pnp_data_reg, i8042_data_reg);
+ i8042_pnp_data_reg = i8042_data_reg;
+ }
+
+ if (((i8042_pnp_command_reg & ~0xf) == (i8042_command_reg & ~0xf) &&
+ i8042_pnp_command_reg != i8042_command_reg) || !i8042_pnp_command_reg) {
+ printk(KERN_WARNING "PNP: PS/2 controller has invalid command port %#x; using default %#x\n",
+ i8042_pnp_command_reg, i8042_command_reg);
+ i8042_pnp_command_reg = i8042_command_reg;
+ }
+
+ if (!i8042_pnp_kbd_irq) {
+ printk(KERN_WARNING "PNP: PS/2 controller doesn't have KBD irq; using default %#x\n", i8042_kbd_irq);
+ i8042_pnp_kbd_irq = i8042_kbd_irq;
+ }
+
+ if (!i8042_pnp_aux_irq) {
+ printk(KERN_WARNING "PNP: PS/2 controller doesn't have AUX irq; using default %#x\n", i8042_aux_irq);
+ i8042_pnp_aux_irq = i8042_aux_irq;
}
- i8042_acpi_kbd_registered = 1;
- result = acpi_bus_register_driver(&i8042_acpi_aux_driver);
- if (result >= 0)
- i8042_acpi_aux_registered = 1;
- if (result == 0)
+#if defined(__ia64__)
+ if (result_aux <= 0)
i8042_noaux = 1;
+#endif
- return 0;
-}
+ i8042_data_reg = i8042_pnp_data_reg;
+ i8042_command_reg = i8042_pnp_command_reg;
+ i8042_kbd_irq = i8042_pnp_kbd_irq;
+ i8042_aux_irq = i8042_pnp_aux_irq;
-static void i8042_acpi_exit(void)
-{
- if (i8042_acpi_kbd_registered)
- acpi_bus_unregister_driver(&i8042_acpi_kbd_driver);
+ printk(KERN_INFO "PNP: PS/2 Controller [%s%s%s] at %#x,%#x irq %d%s%d\n",
+ i8042_pnp_kbd_name, (result_kbd > 0 && result_aux > 0) ? "," : "", i8042_pnp_aux_name,
+ i8042_data_reg, i8042_command_reg, i8042_kbd_irq,
+ (result_aux > 0) ? "," : "", i8042_aux_irq);
- if (i8042_acpi_aux_registered)
- acpi_bus_unregister_driver(&i8042_acpi_aux_driver);
+ return 0;
}
+
#endif
static inline int i8042_platform_init(void)
i8042_kbd_irq = I8042_MAP_IRQ(1);
i8042_aux_irq = I8042_MAP_IRQ(12);
-#if defined(__ia64__) && defined(CONFIG_ACPI)
- if (i8042_acpi_init())
+#ifdef CONFIG_PNP
+ if (i8042_pnp_init())
return -1;
#endif
#endif
#if defined(__i386__)
- if (dmi_check_system(i8042_dmi_table))
+ if (dmi_check_system(i8042_dmi_noloop_table))
i8042_noloop = 1;
+
+ if (dmi_check_system(i8042_dmi_nomux_table))
+ i8042_nomux = 1;
#endif
return 0;
static inline void i8042_platform_exit(void)
{
-#if defined(__ia64__) && defined(CONFIG_ACPI)
- i8042_acpi_exit();
+#ifdef CONFIG_PNP
+ i8042_pnp_exit();
#endif
}