From: Bjorn Helgaas Input: Add ACPI-based i8042 keyboard and aux controller enumeration; can be disabled by passing i8042.noacpi as a boot parameter. Original code by Bjorn Helgaas Signed-off-by: Dmitry Torokhov Signed-off-by: Andrew Morton --- 25-akpm/Documentation/kernel-parameters.txt | 2 25-akpm/drivers/input/serio/i8042-io.h | 51 ---- 25-akpm/drivers/input/serio/i8042-x86ia64io.h | 272 ++++++++++++++++++++++++++ 25-akpm/drivers/input/serio/i8042.c | 6 25-akpm/drivers/input/serio/i8042.h | 2 5 files changed, 289 insertions(+), 44 deletions(-) diff -puN Documentation/kernel-parameters.txt~allow-i8042-register-location-override-2 Documentation/kernel-parameters.txt --- 25/Documentation/kernel-parameters.txt~allow-i8042-register-location-override-2 2004-09-03 22:40:22.644430240 -0700 +++ 25-akpm/Documentation/kernel-parameters.txt 2004-09-03 22:40:22.654428720 -0700 @@ -478,6 +478,8 @@ running once the system is up. i8042.dumbkbd [HW] Pretend that controlled can only read data from keyboard and can not control its state (Don't attempt to blink the leds) + i8042.noacpi [HW] Don't use ACPI to discover KBD/AUX controller + settings i8042.noaux [HW] Don't check for auxiliary (== mouse) port i8042.nomux [HW] Don't check presence of an active multiplexing controller diff -puN drivers/input/serio/i8042.c~allow-i8042-register-location-override-2 drivers/input/serio/i8042.c --- 25/drivers/input/serio/i8042.c~allow-i8042-register-location-override-2 2004-09-03 22:40:22.646429936 -0700 +++ 25-akpm/drivers/input/serio/i8042.c 2004-09-03 22:40:22.658428112 -0700 @@ -58,6 +58,12 @@ static unsigned int i8042_noloop; module_param_named(noloop, i8042_noloop, bool, 0); MODULE_PARM_DESC(dumbkbd, "Disable the AUX Loopback command while probing for the AUX port"); +#ifdef CONFIG_ACPI +static int i8042_noacpi; +module_param_named(noacpi, i8042_noacpi, bool, 0); +MODULE_PARM_DESC(noacpi, "Do not use ACPI to detect controller settings"); +#endif + __obsolete_setup("i8042_noaux"); __obsolete_setup("i8042_nomux"); __obsolete_setup("i8042_unlock"); diff -puN drivers/input/serio/i8042.h~allow-i8042-register-location-override-2 drivers/input/serio/i8042.h --- 25/drivers/input/serio/i8042.h~allow-i8042-register-location-override-2 2004-09-03 22:40:22.647429784 -0700 +++ 25-akpm/drivers/input/serio/i8042.h 2004-09-03 22:40:22.658428112 -0700 @@ -23,6 +23,8 @@ #include "i8042-ppcio.h" #elif defined(CONFIG_SPARC32) || defined(CONFIG_SPARC64) #include "i8042-sparcio.h" +#elif defined(CONFIG_X86) || defined(CONFIG_IA64) +#include "i8042-x86ia64io.h" #else #include "i8042-io.h" #endif diff -puN drivers/input/serio/i8042-io.h~allow-i8042-register-location-override-2 drivers/input/serio/i8042-io.h --- 25/drivers/input/serio/i8042-io.h~allow-i8042-register-location-override-2 2004-09-03 22:40:22.649429480 -0700 +++ 25-akpm/drivers/input/serio/i8042-io.h 2004-09-03 22:40:22.655428568 -0700 @@ -3,7 +3,7 @@ /* * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 as published by + * under the terms of the GNU General Public License version 2 as published by * the Free Software Foundation. */ @@ -22,9 +22,6 @@ #ifdef __alpha__ # define I8042_KBD_IRQ 1 # define I8042_AUX_IRQ (RTC_PORT(0) == 0x170 ? 9 : 12) /* Jensen is special */ -#elif defined(__ia64__) -# define I8042_KBD_IRQ isa_irq_to_vector(1) -# define I8042_AUX_IRQ isa_irq_to_vector(12) #elif defined(__arm__) /* defined in include/asm-arm/arch-xxx/irqs.h */ #include @@ -39,8 +36,8 @@ * Register numbers. */ -#define I8042_COMMAND_REG 0x64 -#define I8042_STATUS_REG 0x64 +#define I8042_COMMAND_REG 0x64 +#define I8042_STATUS_REG 0x64 #define I8042_DATA_REG 0x60 static inline int i8042_read_data(void) @@ -56,66 +53,32 @@ static inline int i8042_read_status(void static inline void i8042_write_data(int val) { outb(val, I8042_DATA_REG); - return; } static inline void i8042_write_command(int val) { outb(val, I8042_COMMAND_REG); - return; } -#if defined(__i386__) - -#include - -static struct dmi_system_id __initdata i8042_dmi_table[] = { - { - .ident = "Compaq Proliant 8500", - .matches = { - DMI_MATCH(DMI_SYS_VENDOR, "Compaq"), - DMI_MATCH(DMI_PRODUCT_NAME , "ProLiant"), - DMI_MATCH(DMI_PRODUCT_VERSION, "8500"), - }, - }, - { - .ident = "Compaq Proliant DL760", - .matches = { - DMI_MATCH(DMI_SYS_VENDOR, "Compaq"), - DMI_MATCH(DMI_PRODUCT_NAME , "ProLiant"), - DMI_MATCH(DMI_PRODUCT_VERSION, "DL760"), - }, - }, - { } -}; -#endif - static inline int i8042_platform_init(void) { /* - * On ix86 platforms touching the i8042 data register region can do really - * bad things. Because of this the region is always reserved on ix86 boxes. + * On some platforms touching the i8042 data register region can do really + * bad things. Because of this the region is always reserved on such boxes. */ -#if !defined(__i386__) && !defined(__sh__) && !defined(__alpha__) && !defined(__x86_64__) && !defined(__mips__) +#if !defined(__sh__) && !defined(__alpha__) && !defined(__mips__) if (!request_region(I8042_DATA_REG, 16, "i8042")) return -1; #endif -#if !defined(__i386__) && !defined(__x86_64__) i8042_reset = 1; -#endif - -#if defined(__i386__) - if (dmi_check_system(i8042_dmi_table)) - i8042_noloop = 1; -#endif return 0; } static inline void i8042_platform_exit(void) { -#if !defined(__i386__) && !defined(__sh__) && !defined(__alpha__) && !defined(__x86_64__) +#if !defined(__sh__) && !defined(__alpha__) release_region(I8042_DATA_REG, 16); #endif } diff -puN /dev/null drivers/input/serio/i8042-x86ia64io.h --- /dev/null 2003-09-15 06:40:47.000000000 -0700 +++ 25-akpm/drivers/input/serio/i8042-x86ia64io.h 2004-09-03 22:40:22.656428416 -0700 @@ -0,0 +1,272 @@ +#ifndef _I8042_X86IA64IO_H +#define _I8042_X86IA64IO_H + +/* + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 as published by + * the Free Software Foundation. + */ + +/* + * Names. + */ + +#define I8042_KBD_PHYS_DESC "isa0060/serio0" +#define I8042_AUX_PHYS_DESC "isa0060/serio1" +#define I8042_MUX_PHYS_DESC "isa0060/serio%d" + +/* + * IRQs. + */ + +#if defined(__ia64__) +# define I8042_MAP_IRQ(x) isa_irq_to_vector((x)) +#else +# define I8042_MAP_IRQ(x) (x) +#endif + +#define I8042_KBD_IRQ i8042_kbd_irq +#define I8042_AUX_IRQ i8042_aux_irq + +static int i8042_kbd_irq = I8042_MAP_IRQ(1); +static int i8042_aux_irq = I8042_MAP_IRQ(12); + +/* + * Register numbers. + */ + +#define I8042_COMMAND_REG i8042_command_reg +#define I8042_STATUS_REG i8042_command_reg +#define I8042_DATA_REG i8042_data_reg + +static int i8042_command_reg = 0x64; +static int i8042_data_reg = 0x60; + + +static inline int i8042_read_data(void) +{ + return inb(I8042_DATA_REG); +} + +static inline int i8042_read_status(void) +{ + return inb(I8042_STATUS_REG); +} + +static inline void i8042_write_data(int val) +{ + outb(val, I8042_DATA_REG); +} + +static inline void i8042_write_command(int val) +{ + outb(val, I8042_COMMAND_REG); +} + +#if defined(__i386__) + +#include + +static struct dmi_system_id __initdata i8042_dmi_table[] = { + { + .ident = "Compaq Proliant 8500", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "Compaq"), + DMI_MATCH(DMI_PRODUCT_NAME , "ProLiant"), + DMI_MATCH(DMI_PRODUCT_VERSION, "8500"), + }, + }, + { + .ident = "Compaq Proliant DL760", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "Compaq"), + DMI_MATCH(DMI_PRODUCT_NAME , "ProLiant"), + DMI_MATCH(DMI_PRODUCT_VERSION, "DL760"), + }, + }, + { } +}; +#endif + +#ifdef CONFIG_ACPI +#include +#include + +struct i8042_acpi_resources { + unsigned int port1; + unsigned int port2; + unsigned int irq; +}; + +static int i8042_acpi_kbd_registered; +static int i8042_acpi_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_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_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_acpi_kbd_add(struct acpi_device *device) +{ + struct i8042_acpi_resources kbd_res; + acpi_status status; + + 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; + + printk("i8042: ACPI %s [%s] at I/O 0x%x, 0x%x, irq %d\n", + acpi_device_name(device), acpi_device_bid(device), + kbd_res.port1, kbd_res.port2, kbd_res.irq); + + i8042_data_reg = kbd_res.port1; + i8042_command_reg = kbd_res.port2; + i8042_kbd_irq = kbd_res.irq; + + return 0; +} + +static int i8042_acpi_aux_add(struct acpi_device *device) +{ + struct i8042_acpi_resources aux_res; + acpi_status status; + + 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; + + printk("i8042: ACPI %s [%s] at irq %d\n", + acpi_device_name(device), acpi_device_bid(device), aux_res.irq); + + i8042_aux_irq = aux_res.irq; + + return 0; +} + +static struct acpi_driver i8042_acpi_kbd_driver = { + .name = "i8042", + .ids = "PNP0303", + .ops = { + .add = i8042_acpi_kbd_add, + }, +}; + +static struct acpi_driver i8042_acpi_aux_driver = { + .name = "i8042", + .ids = "PNP0F13", + .ops = { + .add = i8042_acpi_aux_add, + }, +}; + +static int i8042_acpi_init(void) +{ + int result; + + if (i8042_noacpi) { + printk("i8042: ACPI detection disabled\n"); + return 0; + } + + result = acpi_bus_register_driver(&i8042_acpi_kbd_driver); + if (result < 0) + return result; + + if (result == 0) { + acpi_bus_unregister_driver(&i8042_acpi_kbd_driver); + return -ENODEV; + } + 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) + i8042_noaux = 1; + + return 0; +} + +static void i8042_acpi_exit(void) +{ + if (i8042_acpi_kbd_registered) + acpi_bus_unregister_driver(&i8042_acpi_kbd_driver); + + if (i8042_acpi_aux_registered) + acpi_bus_unregister_driver(&i8042_acpi_aux_driver); +} +#endif + +static inline int i8042_platform_init(void) +{ +/* + * On ix86 platforms touching the i8042 data register region can do really + * bad things. Because of this the region is always reserved on ix86 boxes. + * + * if (!request_region(I8042_DATA_REG, 16, "i8042")) + * return -1; + */ + +#ifdef CONFIG_ACPI + if (i8042_acpi_init()) + return -1; +#endif + +#if defined(__ia64__) + i8042_reset = 1; +#endif + +#if defined(__i386__) + if (dmi_check_system(i8042_dmi_table)) + i8042_noloop = 1; +#endif + + return 0; +} + +static inline void i8042_platform_exit(void) +{ +#ifdef CONFIG_ACPI + i8042_acpi_exit(); +#endif +} + +#endif /* _I8042_X86IA64IO_H */ _