15fc14680SDmitry Torokhov /* 25fc14680SDmitry Torokhov * Wistron laptop button driver 35fc14680SDmitry Torokhov * Copyright (C) 2005 Miloslav Trmac <mitr@volny.cz> 484b256a6SBernhard Rosenkraenzer * Copyright (C) 2005 Bernhard Rosenkraenzer <bero@arklinux.org> 5a5b0cc80SDmitry Torokhov * Copyright (C) 2005 Dmitry Torokhov <dtor@mail.ru> 65fc14680SDmitry Torokhov * 75fc14680SDmitry Torokhov * You can redistribute and/or modify this program under the terms of the 85fc14680SDmitry Torokhov * GNU General Public License version 2 as published by the Free Software 95fc14680SDmitry Torokhov * Foundation. 105fc14680SDmitry Torokhov * 115fc14680SDmitry Torokhov * This program is distributed in the hope that it will be useful, but 125fc14680SDmitry Torokhov * WITHOUT ANY WARRANTY; without even the implied warranty of 135fc14680SDmitry Torokhov * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General 145fc14680SDmitry Torokhov * Public License for more details. 155fc14680SDmitry Torokhov * 165fc14680SDmitry Torokhov * You should have received a copy of the GNU General Public License along 175fc14680SDmitry Torokhov * with this program; if not, write to the Free Software Foundation, Inc., 185fc14680SDmitry Torokhov * 59 Temple Place Suite 330, Boston, MA 02111-1307, USA. 195fc14680SDmitry Torokhov */ 2053d5ed62SMatthew Wilcox #include <linux/io.h> 215fc14680SDmitry Torokhov #include <linux/dmi.h> 225fc14680SDmitry Torokhov #include <linux/init.h> 235fc14680SDmitry Torokhov #include <linux/input.h> 245fc14680SDmitry Torokhov #include <linux/interrupt.h> 255fc14680SDmitry Torokhov #include <linux/kernel.h> 265fc14680SDmitry Torokhov #include <linux/mc146818rtc.h> 275fc14680SDmitry Torokhov #include <linux/module.h> 285fc14680SDmitry Torokhov #include <linux/preempt.h> 295fc14680SDmitry Torokhov #include <linux/string.h> 305fc14680SDmitry Torokhov #include <linux/timer.h> 315fc14680SDmitry Torokhov #include <linux/types.h> 32a5b0cc80SDmitry Torokhov #include <linux/platform_device.h> 335fc14680SDmitry Torokhov 345fc14680SDmitry Torokhov /* 355fc14680SDmitry Torokhov * Number of attempts to read data from queue per poll; 365fc14680SDmitry Torokhov * the queue can hold up to 31 entries 375fc14680SDmitry Torokhov */ 385fc14680SDmitry Torokhov #define MAX_POLL_ITERATIONS 64 395fc14680SDmitry Torokhov 405fc14680SDmitry Torokhov #define POLL_FREQUENCY 10 /* Number of polls per second */ 415fc14680SDmitry Torokhov 425fc14680SDmitry Torokhov #if POLL_FREQUENCY > HZ 435fc14680SDmitry Torokhov #error "POLL_FREQUENCY too high" 445fc14680SDmitry Torokhov #endif 455fc14680SDmitry Torokhov 4684b256a6SBernhard Rosenkraenzer /* BIOS subsystem IDs */ 4784b256a6SBernhard Rosenkraenzer #define WIFI 0x35 4884b256a6SBernhard Rosenkraenzer #define BLUETOOTH 0x34 4984b256a6SBernhard Rosenkraenzer 505fc14680SDmitry Torokhov MODULE_AUTHOR("Miloslav Trmac <mitr@volny.cz>"); 515fc14680SDmitry Torokhov MODULE_DESCRIPTION("Wistron laptop button driver"); 525fc14680SDmitry Torokhov MODULE_LICENSE("GPL v2"); 5355d29c98SEric Piel MODULE_VERSION("0.2"); 545fc14680SDmitry Torokhov 555fc14680SDmitry Torokhov static int force; /* = 0; */ 565fc14680SDmitry Torokhov module_param(force, bool, 0); 575fc14680SDmitry Torokhov MODULE_PARM_DESC(force, "Load even if computer is not in database"); 585fc14680SDmitry Torokhov 595fc14680SDmitry Torokhov static char *keymap_name; /* = NULL; */ 605fc14680SDmitry Torokhov module_param_named(keymap, keymap_name, charp, 0); 617b0a4cd7SEric Piel MODULE_PARM_DESC(keymap, "Keymap name, if it can't be autodetected [generic, 1557/MS2141]"); 625fc14680SDmitry Torokhov 63a5b0cc80SDmitry Torokhov static struct platform_device *wistron_device; 64a5b0cc80SDmitry Torokhov 655fc14680SDmitry Torokhov /* BIOS interface implementation */ 665fc14680SDmitry Torokhov 675fc14680SDmitry Torokhov static void __iomem *bios_entry_point; /* BIOS routine entry point */ 685fc14680SDmitry Torokhov static void __iomem *bios_code_map_base; 695fc14680SDmitry Torokhov static void __iomem *bios_data_map_base; 705fc14680SDmitry Torokhov 715fc14680SDmitry Torokhov static u8 cmos_address; 725fc14680SDmitry Torokhov 735fc14680SDmitry Torokhov struct regs { 745fc14680SDmitry Torokhov u32 eax, ebx, ecx; 755fc14680SDmitry Torokhov }; 765fc14680SDmitry Torokhov 775fc14680SDmitry Torokhov static void call_bios(struct regs *regs) 785fc14680SDmitry Torokhov { 795fc14680SDmitry Torokhov unsigned long flags; 805fc14680SDmitry Torokhov 815fc14680SDmitry Torokhov preempt_disable(); 825fc14680SDmitry Torokhov local_irq_save(flags); 835fc14680SDmitry Torokhov asm volatile ("pushl %%ebp;" 845fc14680SDmitry Torokhov "movl %7, %%ebp;" 855fc14680SDmitry Torokhov "call *%6;" 865fc14680SDmitry Torokhov "popl %%ebp" 875fc14680SDmitry Torokhov : "=a" (regs->eax), "=b" (regs->ebx), "=c" (regs->ecx) 885fc14680SDmitry Torokhov : "0" (regs->eax), "1" (regs->ebx), "2" (regs->ecx), 895fc14680SDmitry Torokhov "m" (bios_entry_point), "m" (bios_data_map_base) 905fc14680SDmitry Torokhov : "edx", "edi", "esi", "memory"); 915fc14680SDmitry Torokhov local_irq_restore(flags); 925fc14680SDmitry Torokhov preempt_enable(); 935fc14680SDmitry Torokhov } 945fc14680SDmitry Torokhov 95c28c3583SMiloslav Trmac static ssize_t __init locate_wistron_bios(void __iomem *base) 965fc14680SDmitry Torokhov { 97c7948989SAndrew Morton static unsigned char __initdata signature[] = 985fc14680SDmitry Torokhov { 0x42, 0x21, 0x55, 0x30 }; 99c28c3583SMiloslav Trmac ssize_t offset; 1005fc14680SDmitry Torokhov 1015fc14680SDmitry Torokhov for (offset = 0; offset < 0x10000; offset += 0x10) { 1025fc14680SDmitry Torokhov if (check_signature(base + offset, signature, 1035fc14680SDmitry Torokhov sizeof(signature)) != 0) 1045fc14680SDmitry Torokhov return offset; 1055fc14680SDmitry Torokhov } 1065fc14680SDmitry Torokhov return -1; 1075fc14680SDmitry Torokhov } 1085fc14680SDmitry Torokhov 1095fc14680SDmitry Torokhov static int __init map_bios(void) 1105fc14680SDmitry Torokhov { 1115fc14680SDmitry Torokhov void __iomem *base; 112c28c3583SMiloslav Trmac ssize_t offset; 1135fc14680SDmitry Torokhov u32 entry_point; 1145fc14680SDmitry Torokhov 1155fc14680SDmitry Torokhov base = ioremap(0xF0000, 0x10000); /* Can't fail */ 1165fc14680SDmitry Torokhov offset = locate_wistron_bios(base); 1175fc14680SDmitry Torokhov if (offset < 0) { 1185fc14680SDmitry Torokhov printk(KERN_ERR "wistron_btns: BIOS entry point not found\n"); 1195fc14680SDmitry Torokhov iounmap(base); 1205fc14680SDmitry Torokhov return -ENODEV; 1215fc14680SDmitry Torokhov } 1225fc14680SDmitry Torokhov 1235fc14680SDmitry Torokhov entry_point = readl(base + offset + 5); 1245fc14680SDmitry Torokhov printk(KERN_DEBUG 1255fc14680SDmitry Torokhov "wistron_btns: BIOS signature found at %p, entry point %08X\n", 1265fc14680SDmitry Torokhov base + offset, entry_point); 1275fc14680SDmitry Torokhov 1285fc14680SDmitry Torokhov if (entry_point >= 0xF0000) { 1295fc14680SDmitry Torokhov bios_code_map_base = base; 1305fc14680SDmitry Torokhov bios_entry_point = bios_code_map_base + (entry_point & 0xFFFF); 1315fc14680SDmitry Torokhov } else { 1325fc14680SDmitry Torokhov iounmap(base); 1335fc14680SDmitry Torokhov bios_code_map_base = ioremap(entry_point & ~0x3FFF, 0x4000); 1345fc14680SDmitry Torokhov if (bios_code_map_base == NULL) { 1355fc14680SDmitry Torokhov printk(KERN_ERR 1365fc14680SDmitry Torokhov "wistron_btns: Can't map BIOS code at %08X\n", 1375fc14680SDmitry Torokhov entry_point & ~0x3FFF); 1385fc14680SDmitry Torokhov goto err; 1395fc14680SDmitry Torokhov } 1405fc14680SDmitry Torokhov bios_entry_point = bios_code_map_base + (entry_point & 0x3FFF); 1415fc14680SDmitry Torokhov } 1425fc14680SDmitry Torokhov /* The Windows driver maps 0x10000 bytes, we keep only one page... */ 1435fc14680SDmitry Torokhov bios_data_map_base = ioremap(0x400, 0xc00); 1445fc14680SDmitry Torokhov if (bios_data_map_base == NULL) { 1455fc14680SDmitry Torokhov printk(KERN_ERR "wistron_btns: Can't map BIOS data\n"); 1465fc14680SDmitry Torokhov goto err_code; 1475fc14680SDmitry Torokhov } 1485fc14680SDmitry Torokhov return 0; 1495fc14680SDmitry Torokhov 1505fc14680SDmitry Torokhov err_code: 1515fc14680SDmitry Torokhov iounmap(bios_code_map_base); 1525fc14680SDmitry Torokhov err: 1535fc14680SDmitry Torokhov return -ENOMEM; 1545fc14680SDmitry Torokhov } 1555fc14680SDmitry Torokhov 15622a397e2SDmitry Torokhov static inline void unmap_bios(void) 1575fc14680SDmitry Torokhov { 1585fc14680SDmitry Torokhov iounmap(bios_code_map_base); 1595fc14680SDmitry Torokhov iounmap(bios_data_map_base); 1605fc14680SDmitry Torokhov } 1615fc14680SDmitry Torokhov 1625fc14680SDmitry Torokhov /* BIOS calls */ 1635fc14680SDmitry Torokhov 1645fc14680SDmitry Torokhov static u16 bios_pop_queue(void) 1655fc14680SDmitry Torokhov { 1665fc14680SDmitry Torokhov struct regs regs; 1675fc14680SDmitry Torokhov 1685fc14680SDmitry Torokhov memset(®s, 0, sizeof (regs)); 1695fc14680SDmitry Torokhov regs.eax = 0x9610; 1705fc14680SDmitry Torokhov regs.ebx = 0x061C; 1715fc14680SDmitry Torokhov regs.ecx = 0x0000; 1725fc14680SDmitry Torokhov call_bios(®s); 1735fc14680SDmitry Torokhov 1745fc14680SDmitry Torokhov return regs.eax; 1755fc14680SDmitry Torokhov } 1765fc14680SDmitry Torokhov 177e7c3aad5SDmitry Torokhov static void __devinit bios_attach(void) 1785fc14680SDmitry Torokhov { 1795fc14680SDmitry Torokhov struct regs regs; 1805fc14680SDmitry Torokhov 1815fc14680SDmitry Torokhov memset(®s, 0, sizeof (regs)); 1825fc14680SDmitry Torokhov regs.eax = 0x9610; 1835fc14680SDmitry Torokhov regs.ebx = 0x012E; 1845fc14680SDmitry Torokhov call_bios(®s); 1855fc14680SDmitry Torokhov } 1865fc14680SDmitry Torokhov 18722a397e2SDmitry Torokhov static void bios_detach(void) 1885fc14680SDmitry Torokhov { 1895fc14680SDmitry Torokhov struct regs regs; 1905fc14680SDmitry Torokhov 1915fc14680SDmitry Torokhov memset(®s, 0, sizeof (regs)); 1925fc14680SDmitry Torokhov regs.eax = 0x9610; 1935fc14680SDmitry Torokhov regs.ebx = 0x002E; 1945fc14680SDmitry Torokhov call_bios(®s); 1955fc14680SDmitry Torokhov } 1965fc14680SDmitry Torokhov 197e7c3aad5SDmitry Torokhov static u8 __devinit bios_get_cmos_address(void) 1985fc14680SDmitry Torokhov { 1995fc14680SDmitry Torokhov struct regs regs; 2005fc14680SDmitry Torokhov 2015fc14680SDmitry Torokhov memset(®s, 0, sizeof (regs)); 2025fc14680SDmitry Torokhov regs.eax = 0x9610; 2035fc14680SDmitry Torokhov regs.ebx = 0x051C; 2045fc14680SDmitry Torokhov call_bios(®s); 2055fc14680SDmitry Torokhov 2065fc14680SDmitry Torokhov return regs.ecx; 2075fc14680SDmitry Torokhov } 2085fc14680SDmitry Torokhov 209e7c3aad5SDmitry Torokhov static u16 __devinit bios_get_default_setting(u8 subsys) 2105fc14680SDmitry Torokhov { 2115fc14680SDmitry Torokhov struct regs regs; 2125fc14680SDmitry Torokhov 2135fc14680SDmitry Torokhov memset(®s, 0, sizeof (regs)); 2145fc14680SDmitry Torokhov regs.eax = 0x9610; 21584b256a6SBernhard Rosenkraenzer regs.ebx = 0x0200 | subsys; 2165fc14680SDmitry Torokhov call_bios(®s); 2175fc14680SDmitry Torokhov 2185fc14680SDmitry Torokhov return regs.eax; 2195fc14680SDmitry Torokhov } 2205fc14680SDmitry Torokhov 22184b256a6SBernhard Rosenkraenzer static void bios_set_state(u8 subsys, int enable) 2225fc14680SDmitry Torokhov { 2235fc14680SDmitry Torokhov struct regs regs; 2245fc14680SDmitry Torokhov 2255fc14680SDmitry Torokhov memset(®s, 0, sizeof (regs)); 2265fc14680SDmitry Torokhov regs.eax = 0x9610; 22784b256a6SBernhard Rosenkraenzer regs.ebx = (enable ? 0x0100 : 0x0000) | subsys; 2285fc14680SDmitry Torokhov call_bios(®s); 2295fc14680SDmitry Torokhov } 2305fc14680SDmitry Torokhov 2315fc14680SDmitry Torokhov /* Hardware database */ 2325fc14680SDmitry Torokhov 2335fc14680SDmitry Torokhov struct key_entry { 2345fc14680SDmitry Torokhov char type; /* See KE_* below */ 2355fc14680SDmitry Torokhov u8 code; 2366480e2a2SEric Piel union { 2376480e2a2SEric Piel u16 keycode; /* For KE_KEY */ 2386480e2a2SEric Piel struct { /* For KE_SW */ 2396480e2a2SEric Piel u8 code; 2406480e2a2SEric Piel u8 value; 2416480e2a2SEric Piel } sw; 2426480e2a2SEric Piel }; 2435fc14680SDmitry Torokhov }; 2445fc14680SDmitry Torokhov 2456480e2a2SEric Piel enum { KE_END, KE_KEY, KE_SW, KE_WIFI, KE_BLUETOOTH }; 2466480e2a2SEric Piel 2476480e2a2SEric Piel #define FE_MAIL_LED 0x01 2486480e2a2SEric Piel #define FE_WIFI_LED 0x02 2496480e2a2SEric Piel #define FE_UNTESTED 0x80 2505fc14680SDmitry Torokhov 2515fc14680SDmitry Torokhov static const struct key_entry *keymap; /* = NULL; Current key map */ 2525fc14680SDmitry Torokhov static int have_wifi; 25384b256a6SBernhard Rosenkraenzer static int have_bluetooth; 2545fc14680SDmitry Torokhov 2555fc14680SDmitry Torokhov static int __init dmi_matched(struct dmi_system_id *dmi) 2565fc14680SDmitry Torokhov { 2575fc14680SDmitry Torokhov const struct key_entry *key; 2585fc14680SDmitry Torokhov 2595fc14680SDmitry Torokhov keymap = dmi->driver_data; 2605fc14680SDmitry Torokhov for (key = keymap; key->type != KE_END; key++) { 261cde45f19SReiner Herrmann if (key->type == KE_WIFI) 2625fc14680SDmitry Torokhov have_wifi = 1; 263cde45f19SReiner Herrmann else if (key->type == KE_BLUETOOTH) 26484b256a6SBernhard Rosenkraenzer have_bluetooth = 1; 2655fc14680SDmitry Torokhov } 2665fc14680SDmitry Torokhov return 1; 2675fc14680SDmitry Torokhov } 2685fc14680SDmitry Torokhov 26955d29c98SEric Piel static struct key_entry keymap_empty[] __initdata = { 2705fc14680SDmitry Torokhov { KE_END, 0 } 2715fc14680SDmitry Torokhov }; 2725fc14680SDmitry Torokhov 27355d29c98SEric Piel static struct key_entry keymap_fs_amilo_pro_v2000[] __initdata = { 2746480e2a2SEric Piel { KE_KEY, 0x01, {KEY_HELP} }, 2756480e2a2SEric Piel { KE_KEY, 0x11, {KEY_PROG1} }, 2766480e2a2SEric Piel { KE_KEY, 0x12, {KEY_PROG2} }, 2776480e2a2SEric Piel { KE_WIFI, 0x30 }, 2786480e2a2SEric Piel { KE_KEY, 0x31, {KEY_MAIL} }, 2796480e2a2SEric Piel { KE_KEY, 0x36, {KEY_WWW} }, 2805fc14680SDmitry Torokhov { KE_END, 0 } 2815fc14680SDmitry Torokhov }; 2825fc14680SDmitry Torokhov 28355d29c98SEric Piel static struct key_entry keymap_fujitsu_n3510[] __initdata = { 2846480e2a2SEric Piel { KE_KEY, 0x11, {KEY_PROG1} }, 2856480e2a2SEric Piel { KE_KEY, 0x12, {KEY_PROG2} }, 2866480e2a2SEric Piel { KE_KEY, 0x36, {KEY_WWW} }, 2876480e2a2SEric Piel { KE_KEY, 0x31, {KEY_MAIL} }, 2886480e2a2SEric Piel { KE_KEY, 0x71, {KEY_STOPCD} }, 2896480e2a2SEric Piel { KE_KEY, 0x72, {KEY_PLAYPAUSE} }, 2906480e2a2SEric Piel { KE_KEY, 0x74, {KEY_REWIND} }, 2916480e2a2SEric Piel { KE_KEY, 0x78, {KEY_FORWARD} }, 292e2aa507aSJohn Reed Riley { KE_END, 0 } 293e2aa507aSJohn Reed Riley }; 294e2aa507aSJohn Reed Riley 29555d29c98SEric Piel static struct key_entry keymap_wistron_ms2111[] __initdata = { 2966480e2a2SEric Piel { KE_KEY, 0x11, {KEY_PROG1} }, 2976480e2a2SEric Piel { KE_KEY, 0x12, {KEY_PROG2} }, 2986480e2a2SEric Piel { KE_KEY, 0x13, {KEY_PROG3} }, 2996480e2a2SEric Piel { KE_KEY, 0x31, {KEY_MAIL} }, 3006480e2a2SEric Piel { KE_KEY, 0x36, {KEY_WWW} }, 3016480e2a2SEric Piel { KE_END, FE_MAIL_LED } 3026480e2a2SEric Piel }; 3036480e2a2SEric Piel 30455d29c98SEric Piel static struct key_entry keymap_wistron_md40100[] __initdata = { 3056480e2a2SEric Piel { KE_KEY, 0x01, {KEY_HELP} }, 3066480e2a2SEric Piel { KE_KEY, 0x02, {KEY_CONFIG} }, 3076480e2a2SEric Piel { KE_KEY, 0x31, {KEY_MAIL} }, 3086480e2a2SEric Piel { KE_KEY, 0x36, {KEY_WWW} }, 3096480e2a2SEric Piel { KE_KEY, 0x37, {KEY_DISPLAYTOGGLE} }, /* Display on/off */ 3106480e2a2SEric Piel { KE_END, FE_MAIL_LED | FE_WIFI_LED | FE_UNTESTED } 3119000195bSFrank de Lange }; 3129000195bSFrank de Lange 31355d29c98SEric Piel static struct key_entry keymap_wistron_ms2141[] __initdata = { 3146480e2a2SEric Piel { KE_KEY, 0x11, {KEY_PROG1} }, 3156480e2a2SEric Piel { KE_KEY, 0x12, {KEY_PROG2} }, 3166480e2a2SEric Piel { KE_WIFI, 0x30 }, 3176480e2a2SEric Piel { KE_KEY, 0x22, {KEY_REWIND} }, 3186480e2a2SEric Piel { KE_KEY, 0x23, {KEY_FORWARD} }, 3196480e2a2SEric Piel { KE_KEY, 0x24, {KEY_PLAYPAUSE} }, 3206480e2a2SEric Piel { KE_KEY, 0x25, {KEY_STOPCD} }, 3216480e2a2SEric Piel { KE_KEY, 0x31, {KEY_MAIL} }, 3226480e2a2SEric Piel { KE_KEY, 0x36, {KEY_WWW} }, 3235fc14680SDmitry Torokhov { KE_END, 0 } 3245fc14680SDmitry Torokhov }; 3255fc14680SDmitry Torokhov 32655d29c98SEric Piel static struct key_entry keymap_acer_aspire_1500[] __initdata = { 3276480e2a2SEric Piel { KE_KEY, 0x01, {KEY_HELP} }, 3286480e2a2SEric Piel { KE_KEY, 0x03, {KEY_POWER} }, 3296480e2a2SEric Piel { KE_KEY, 0x11, {KEY_PROG1} }, 3306480e2a2SEric Piel { KE_KEY, 0x12, {KEY_PROG2} }, 3316480e2a2SEric Piel { KE_WIFI, 0x30 }, 3326480e2a2SEric Piel { KE_KEY, 0x31, {KEY_MAIL} }, 3336480e2a2SEric Piel { KE_KEY, 0x36, {KEY_WWW} }, 3346480e2a2SEric Piel { KE_KEY, 0x49, {KEY_CONFIG} }, 3356480e2a2SEric Piel { KE_BLUETOOTH, 0x44 }, 3366480e2a2SEric Piel { KE_END, FE_UNTESTED } 3376480e2a2SEric Piel }; 3386480e2a2SEric Piel 33955d29c98SEric Piel static struct key_entry keymap_acer_aspire_1600[] __initdata = { 3406480e2a2SEric Piel { KE_KEY, 0x01, {KEY_HELP} }, 3416480e2a2SEric Piel { KE_KEY, 0x03, {KEY_POWER} }, 3426480e2a2SEric Piel { KE_KEY, 0x08, {KEY_MUTE} }, 3436480e2a2SEric Piel { KE_KEY, 0x11, {KEY_PROG1} }, 3446480e2a2SEric Piel { KE_KEY, 0x12, {KEY_PROG2} }, 3456480e2a2SEric Piel { KE_KEY, 0x13, {KEY_PROG3} }, 3466480e2a2SEric Piel { KE_KEY, 0x31, {KEY_MAIL} }, 3476480e2a2SEric Piel { KE_KEY, 0x36, {KEY_WWW} }, 3486480e2a2SEric Piel { KE_KEY, 0x49, {KEY_CONFIG} }, 3496480e2a2SEric Piel { KE_WIFI, 0x30 }, 3506480e2a2SEric Piel { KE_BLUETOOTH, 0x44 }, 3516480e2a2SEric Piel { KE_END, FE_MAIL_LED | FE_UNTESTED } 3526480e2a2SEric Piel }; 3536480e2a2SEric Piel 3546480e2a2SEric Piel /* 3020 has been tested */ 35555d29c98SEric Piel static struct key_entry keymap_acer_aspire_5020[] __initdata = { 3566480e2a2SEric Piel { KE_KEY, 0x01, {KEY_HELP} }, 3576480e2a2SEric Piel { KE_KEY, 0x03, {KEY_POWER} }, 3586480e2a2SEric Piel { KE_KEY, 0x05, {KEY_SWITCHVIDEOMODE} }, /* Display selection */ 3596480e2a2SEric Piel { KE_KEY, 0x11, {KEY_PROG1} }, 3606480e2a2SEric Piel { KE_KEY, 0x12, {KEY_PROG2} }, 3616480e2a2SEric Piel { KE_KEY, 0x31, {KEY_MAIL} }, 3626480e2a2SEric Piel { KE_KEY, 0x36, {KEY_WWW} }, 3636480e2a2SEric Piel { KE_KEY, 0x6a, {KEY_CONFIG} }, 3646480e2a2SEric Piel { KE_WIFI, 0x30 }, 3656480e2a2SEric Piel { KE_BLUETOOTH, 0x44 }, 3666480e2a2SEric Piel { KE_END, FE_MAIL_LED | FE_UNTESTED } 3676480e2a2SEric Piel }; 3686480e2a2SEric Piel 36955d29c98SEric Piel static struct key_entry keymap_acer_travelmate_2410[] __initdata = { 3706480e2a2SEric Piel { KE_KEY, 0x01, {KEY_HELP} }, 3716480e2a2SEric Piel { KE_KEY, 0x6d, {KEY_POWER} }, 3726480e2a2SEric Piel { KE_KEY, 0x11, {KEY_PROG1} }, 3736480e2a2SEric Piel { KE_KEY, 0x12, {KEY_PROG2} }, 3746480e2a2SEric Piel { KE_KEY, 0x31, {KEY_MAIL} }, 3756480e2a2SEric Piel { KE_KEY, 0x36, {KEY_WWW} }, 3766480e2a2SEric Piel { KE_KEY, 0x6a, {KEY_CONFIG} }, 3776480e2a2SEric Piel { KE_WIFI, 0x30 }, 3786480e2a2SEric Piel { KE_BLUETOOTH, 0x44 }, 3796480e2a2SEric Piel { KE_END, FE_MAIL_LED | FE_UNTESTED } 3806480e2a2SEric Piel }; 3816480e2a2SEric Piel 38255d29c98SEric Piel static struct key_entry keymap_acer_travelmate_110[] __initdata = { 3836480e2a2SEric Piel { KE_KEY, 0x01, {KEY_HELP} }, 3846480e2a2SEric Piel { KE_KEY, 0x02, {KEY_CONFIG} }, 3856480e2a2SEric Piel { KE_KEY, 0x03, {KEY_POWER} }, 3866480e2a2SEric Piel { KE_KEY, 0x08, {KEY_MUTE} }, 3876480e2a2SEric Piel { KE_KEY, 0x11, {KEY_PROG1} }, 3886480e2a2SEric Piel { KE_KEY, 0x12, {KEY_PROG2} }, 3896480e2a2SEric Piel { KE_KEY, 0x20, {KEY_VOLUMEUP} }, 3906480e2a2SEric Piel { KE_KEY, 0x21, {KEY_VOLUMEDOWN} }, 3916480e2a2SEric Piel { KE_KEY, 0x31, {KEY_MAIL} }, 3926480e2a2SEric Piel { KE_KEY, 0x36, {KEY_WWW} }, 3936480e2a2SEric Piel { KE_SW, 0x4a, {.sw = {SW_LID, 1}} }, /* lid close */ 3946480e2a2SEric Piel { KE_SW, 0x4b, {.sw = {SW_LID, 0}} }, /* lid open */ 3956480e2a2SEric Piel { KE_WIFI, 0x30 }, 3966480e2a2SEric Piel { KE_END, FE_MAIL_LED | FE_UNTESTED } 3976480e2a2SEric Piel }; 3986480e2a2SEric Piel 39955d29c98SEric Piel static struct key_entry keymap_acer_travelmate_300[] __initdata = { 4006480e2a2SEric Piel { KE_KEY, 0x01, {KEY_HELP} }, 4016480e2a2SEric Piel { KE_KEY, 0x02, {KEY_CONFIG} }, 4026480e2a2SEric Piel { KE_KEY, 0x03, {KEY_POWER} }, 4036480e2a2SEric Piel { KE_KEY, 0x08, {KEY_MUTE} }, 4046480e2a2SEric Piel { KE_KEY, 0x11, {KEY_PROG1} }, 4056480e2a2SEric Piel { KE_KEY, 0x12, {KEY_PROG2} }, 4066480e2a2SEric Piel { KE_KEY, 0x20, {KEY_VOLUMEUP} }, 4076480e2a2SEric Piel { KE_KEY, 0x21, {KEY_VOLUMEDOWN} }, 4086480e2a2SEric Piel { KE_KEY, 0x31, {KEY_MAIL} }, 4096480e2a2SEric Piel { KE_KEY, 0x36, {KEY_WWW} }, 4106480e2a2SEric Piel { KE_WIFI, 0x30 }, 4116480e2a2SEric Piel { KE_BLUETOOTH, 0x44 }, 4126480e2a2SEric Piel { KE_END, FE_MAIL_LED | FE_UNTESTED } 4136480e2a2SEric Piel }; 4146480e2a2SEric Piel 41555d29c98SEric Piel static struct key_entry keymap_acer_travelmate_380[] __initdata = { 4166480e2a2SEric Piel { KE_KEY, 0x01, {KEY_HELP} }, 4176480e2a2SEric Piel { KE_KEY, 0x02, {KEY_CONFIG} }, 4186480e2a2SEric Piel { KE_KEY, 0x03, {KEY_POWER} }, /* not 370 */ 4196480e2a2SEric Piel { KE_KEY, 0x11, {KEY_PROG1} }, 4206480e2a2SEric Piel { KE_KEY, 0x12, {KEY_PROG2} }, 4216480e2a2SEric Piel { KE_KEY, 0x13, {KEY_PROG3} }, 4226480e2a2SEric Piel { KE_KEY, 0x31, {KEY_MAIL} }, 4236480e2a2SEric Piel { KE_KEY, 0x36, {KEY_WWW} }, 4246480e2a2SEric Piel { KE_WIFI, 0x30 }, 4256480e2a2SEric Piel { KE_END, FE_MAIL_LED | FE_UNTESTED } 4266480e2a2SEric Piel }; 4276480e2a2SEric Piel 4286480e2a2SEric Piel /* unusual map */ 42955d29c98SEric Piel static struct key_entry keymap_acer_travelmate_220[] __initdata = { 4306480e2a2SEric Piel { KE_KEY, 0x01, {KEY_HELP} }, 4316480e2a2SEric Piel { KE_KEY, 0x02, {KEY_CONFIG} }, 4326480e2a2SEric Piel { KE_KEY, 0x11, {KEY_MAIL} }, 4336480e2a2SEric Piel { KE_KEY, 0x12, {KEY_WWW} }, 4346480e2a2SEric Piel { KE_KEY, 0x13, {KEY_PROG2} }, 4356480e2a2SEric Piel { KE_KEY, 0x31, {KEY_PROG1} }, 4366480e2a2SEric Piel { KE_END, FE_WIFI_LED | FE_UNTESTED } 4376480e2a2SEric Piel }; 4386480e2a2SEric Piel 43955d29c98SEric Piel static struct key_entry keymap_acer_travelmate_230[] __initdata = { 4406480e2a2SEric Piel { KE_KEY, 0x01, {KEY_HELP} }, 4416480e2a2SEric Piel { KE_KEY, 0x02, {KEY_CONFIG} }, 4426480e2a2SEric Piel { KE_KEY, 0x11, {KEY_PROG1} }, 4436480e2a2SEric Piel { KE_KEY, 0x12, {KEY_PROG2} }, 4446480e2a2SEric Piel { KE_KEY, 0x31, {KEY_MAIL} }, 4456480e2a2SEric Piel { KE_KEY, 0x36, {KEY_WWW} }, 4466480e2a2SEric Piel { KE_END, FE_WIFI_LED | FE_UNTESTED } 44784b256a6SBernhard Rosenkraenzer }; 44884b256a6SBernhard Rosenkraenzer 44955d29c98SEric Piel static struct key_entry keymap_acer_travelmate_240[] __initdata = { 4506480e2a2SEric Piel { KE_KEY, 0x01, {KEY_HELP} }, 4516480e2a2SEric Piel { KE_KEY, 0x02, {KEY_CONFIG} }, 4526480e2a2SEric Piel { KE_KEY, 0x03, {KEY_POWER} }, 4536480e2a2SEric Piel { KE_KEY, 0x08, {KEY_MUTE} }, 4546480e2a2SEric Piel { KE_KEY, 0x31, {KEY_MAIL} }, 4556480e2a2SEric Piel { KE_KEY, 0x36, {KEY_WWW} }, 4566480e2a2SEric Piel { KE_KEY, 0x11, {KEY_PROG1} }, 4576480e2a2SEric Piel { KE_KEY, 0x12, {KEY_PROG2} }, 4586480e2a2SEric Piel { KE_BLUETOOTH, 0x44 }, 4596480e2a2SEric Piel { KE_WIFI, 0x30 }, 4606480e2a2SEric Piel { KE_END, FE_UNTESTED } 4616480e2a2SEric Piel }; 4626480e2a2SEric Piel 46355d29c98SEric Piel static struct key_entry keymap_acer_travelmate_350[] __initdata = { 4646480e2a2SEric Piel { KE_KEY, 0x01, {KEY_HELP} }, 4656480e2a2SEric Piel { KE_KEY, 0x02, {KEY_CONFIG} }, 4666480e2a2SEric Piel { KE_KEY, 0x11, {KEY_PROG1} }, 4676480e2a2SEric Piel { KE_KEY, 0x12, {KEY_PROG2} }, 4686480e2a2SEric Piel { KE_KEY, 0x13, {KEY_MAIL} }, 4696480e2a2SEric Piel { KE_KEY, 0x14, {KEY_PROG3} }, 4706480e2a2SEric Piel { KE_KEY, 0x15, {KEY_WWW} }, 4716480e2a2SEric Piel { KE_END, FE_MAIL_LED | FE_WIFI_LED | FE_UNTESTED } 4726480e2a2SEric Piel }; 4736480e2a2SEric Piel 47455d29c98SEric Piel static struct key_entry keymap_acer_travelmate_360[] __initdata = { 4756480e2a2SEric Piel { KE_KEY, 0x01, {KEY_HELP} }, 4766480e2a2SEric Piel { KE_KEY, 0x02, {KEY_CONFIG} }, 4776480e2a2SEric Piel { KE_KEY, 0x11, {KEY_PROG1} }, 4786480e2a2SEric Piel { KE_KEY, 0x12, {KEY_PROG2} }, 4796480e2a2SEric Piel { KE_KEY, 0x13, {KEY_MAIL} }, 4806480e2a2SEric Piel { KE_KEY, 0x14, {KEY_PROG3} }, 4816480e2a2SEric Piel { KE_KEY, 0x15, {KEY_WWW} }, 4826480e2a2SEric Piel { KE_KEY, 0x40, {KEY_WLAN} }, 4836480e2a2SEric Piel { KE_END, FE_WIFI_LED | FE_UNTESTED } /* no mail led */ 48474a89c96SAshutosh Naik }; 48574a89c96SAshutosh Naik 486bc413c95SEric Piel /* Wifi subsystem only activates the led. Therefore we need to pass 487bc413c95SEric Piel * wifi event as a normal key, then userspace can really change the wifi state. 488bc413c95SEric Piel * TODO we need to export led state to userspace (wifi and mail) */ 48955d29c98SEric Piel static struct key_entry keymap_acer_travelmate_610[] __initdata = { 4906480e2a2SEric Piel { KE_KEY, 0x01, {KEY_HELP} }, 4916480e2a2SEric Piel { KE_KEY, 0x02, {KEY_CONFIG} }, 4926480e2a2SEric Piel { KE_KEY, 0x11, {KEY_PROG1} }, 493fd013ce8SEric Piel { KE_KEY, 0x12, {KEY_PROG2} }, 4946480e2a2SEric Piel { KE_KEY, 0x13, {KEY_PROG3} }, 4956480e2a2SEric Piel { KE_KEY, 0x14, {KEY_MAIL} }, 4966480e2a2SEric Piel { KE_KEY, 0x15, {KEY_WWW} }, 4976480e2a2SEric Piel { KE_KEY, 0x40, {KEY_WLAN} }, 4986480e2a2SEric Piel { KE_END, FE_MAIL_LED | FE_WIFI_LED } 4996480e2a2SEric Piel }; 5006480e2a2SEric Piel 50155d29c98SEric Piel static struct key_entry keymap_acer_travelmate_630[] __initdata = { 5026480e2a2SEric Piel { KE_KEY, 0x01, {KEY_HELP} }, 5036480e2a2SEric Piel { KE_KEY, 0x02, {KEY_CONFIG} }, 5046480e2a2SEric Piel { KE_KEY, 0x03, {KEY_POWER} }, 5056480e2a2SEric Piel { KE_KEY, 0x08, {KEY_MUTE} }, /* not 620 */ 5066480e2a2SEric Piel { KE_KEY, 0x11, {KEY_PROG1} }, 5076480e2a2SEric Piel { KE_KEY, 0x12, {KEY_PROG2} }, 5086480e2a2SEric Piel { KE_KEY, 0x13, {KEY_PROG3} }, 5096480e2a2SEric Piel { KE_KEY, 0x20, {KEY_VOLUMEUP} }, 5106480e2a2SEric Piel { KE_KEY, 0x21, {KEY_VOLUMEDOWN} }, 5116480e2a2SEric Piel { KE_KEY, 0x31, {KEY_MAIL} }, 5126480e2a2SEric Piel { KE_KEY, 0x36, {KEY_WWW} }, 5136480e2a2SEric Piel { KE_WIFI, 0x30 }, 5146480e2a2SEric Piel { KE_END, FE_MAIL_LED | FE_UNTESTED } 515bc413c95SEric Piel }; 516bc413c95SEric Piel 51755d29c98SEric Piel static struct key_entry keymap_aopen_1559as[] __initdata = { 5186480e2a2SEric Piel { KE_KEY, 0x01, {KEY_HELP} }, 5196480e2a2SEric Piel { KE_KEY, 0x06, {KEY_PROG3} }, 5206480e2a2SEric Piel { KE_KEY, 0x11, {KEY_PROG1} }, 5216480e2a2SEric Piel { KE_KEY, 0x12, {KEY_PROG2} }, 5226480e2a2SEric Piel { KE_WIFI, 0x30 }, 5236480e2a2SEric Piel { KE_KEY, 0x31, {KEY_MAIL} }, 5246480e2a2SEric Piel { KE_KEY, 0x36, {KEY_WWW} }, 5259000195bSFrank de Lange { KE_END, 0 }, 526e107b8eeSmasc@theaterzentrum.at }; 527e107b8eeSmasc@theaterzentrum.at 52855d29c98SEric Piel static struct key_entry keymap_fs_amilo_d88x0[] __initdata = { 5296480e2a2SEric Piel { KE_KEY, 0x01, {KEY_HELP} }, 5306480e2a2SEric Piel { KE_KEY, 0x08, {KEY_MUTE} }, 5316480e2a2SEric Piel { KE_KEY, 0x31, {KEY_MAIL} }, 5326480e2a2SEric Piel { KE_KEY, 0x36, {KEY_WWW} }, 5336480e2a2SEric Piel { KE_KEY, 0x11, {KEY_PROG1} }, 5346480e2a2SEric Piel { KE_KEY, 0x12, {KEY_PROG2} }, 5356480e2a2SEric Piel { KE_KEY, 0x13, {KEY_PROG3} }, 5366480e2a2SEric Piel { KE_END, FE_MAIL_LED | FE_WIFI_LED | FE_UNTESTED } 5376480e2a2SEric Piel }; 5386480e2a2SEric Piel 53955d29c98SEric Piel static struct key_entry keymap_wistron_md2900[] __initdata = { 5406480e2a2SEric Piel { KE_KEY, 0x01, {KEY_HELP} }, 5416480e2a2SEric Piel { KE_KEY, 0x02, {KEY_CONFIG} }, 5426480e2a2SEric Piel { KE_KEY, 0x11, {KEY_PROG1} }, 5436480e2a2SEric Piel { KE_KEY, 0x12, {KEY_PROG2} }, 5446480e2a2SEric Piel { KE_KEY, 0x31, {KEY_MAIL} }, 5456480e2a2SEric Piel { KE_KEY, 0x36, {KEY_WWW} }, 5466480e2a2SEric Piel { KE_WIFI, 0x30 }, 5476480e2a2SEric Piel { KE_END, FE_MAIL_LED | FE_UNTESTED } 5486480e2a2SEric Piel }; 5496480e2a2SEric Piel 55055d29c98SEric Piel static struct key_entry keymap_wistron_md96500[] __initdata = { 5516480e2a2SEric Piel { KE_KEY, 0x01, {KEY_HELP} }, 5526480e2a2SEric Piel { KE_KEY, 0x02, {KEY_CONFIG} }, 5536480e2a2SEric Piel { KE_KEY, 0x05, {KEY_SWITCHVIDEOMODE} }, /* Display selection */ 5546480e2a2SEric Piel { KE_KEY, 0x06, {KEY_DISPLAYTOGGLE} }, /* Display on/off */ 5556480e2a2SEric Piel { KE_KEY, 0x08, {KEY_MUTE} }, 5566480e2a2SEric Piel { KE_KEY, 0x11, {KEY_PROG1} }, 5576480e2a2SEric Piel { KE_KEY, 0x12, {KEY_PROG2} }, 5586480e2a2SEric Piel { KE_KEY, 0x20, {KEY_VOLUMEUP} }, 5596480e2a2SEric Piel { KE_KEY, 0x21, {KEY_VOLUMEDOWN} }, 5606480e2a2SEric Piel { KE_KEY, 0x22, {KEY_REWIND} }, 5616480e2a2SEric Piel { KE_KEY, 0x23, {KEY_FORWARD} }, 5626480e2a2SEric Piel { KE_KEY, 0x24, {KEY_PLAYPAUSE} }, 5636480e2a2SEric Piel { KE_KEY, 0x25, {KEY_STOPCD} }, 5646480e2a2SEric Piel { KE_KEY, 0x31, {KEY_MAIL} }, 5656480e2a2SEric Piel { KE_KEY, 0x36, {KEY_WWW} }, 5666480e2a2SEric Piel { KE_WIFI, 0x30 }, 5676480e2a2SEric Piel { KE_BLUETOOTH, 0x44 }, 5686480e2a2SEric Piel { KE_END, FE_UNTESTED } 5695809d537SMichael Leun }; 5705809d537SMichael Leun 57155d29c98SEric Piel static struct key_entry keymap_wistron_generic[] __initdata = { 5727b0a4cd7SEric Piel { KE_KEY, 0x01, {KEY_HELP} }, 5737b0a4cd7SEric Piel { KE_KEY, 0x02, {KEY_CONFIG} }, 5747b0a4cd7SEric Piel { KE_KEY, 0x03, {KEY_POWER} }, 5757b0a4cd7SEric Piel { KE_KEY, 0x05, {KEY_SWITCHVIDEOMODE} }, /* Display selection */ 5767b0a4cd7SEric Piel { KE_KEY, 0x06, {KEY_DISPLAYTOGGLE} }, /* Display on/off */ 5777b0a4cd7SEric Piel { KE_KEY, 0x08, {KEY_MUTE} }, 5787b0a4cd7SEric Piel { KE_KEY, 0x11, {KEY_PROG1} }, 5797b0a4cd7SEric Piel { KE_KEY, 0x12, {KEY_PROG2} }, 5807b0a4cd7SEric Piel { KE_KEY, 0x13, {KEY_PROG3} }, 5817b0a4cd7SEric Piel { KE_KEY, 0x14, {KEY_MAIL} }, 5827b0a4cd7SEric Piel { KE_KEY, 0x15, {KEY_WWW} }, 5837b0a4cd7SEric Piel { KE_KEY, 0x20, {KEY_VOLUMEUP} }, 5847b0a4cd7SEric Piel { KE_KEY, 0x21, {KEY_VOLUMEDOWN} }, 5857b0a4cd7SEric Piel { KE_KEY, 0x22, {KEY_REWIND} }, 5867b0a4cd7SEric Piel { KE_KEY, 0x23, {KEY_FORWARD} }, 5877b0a4cd7SEric Piel { KE_KEY, 0x24, {KEY_PLAYPAUSE} }, 5887b0a4cd7SEric Piel { KE_KEY, 0x25, {KEY_STOPCD} }, 5897b0a4cd7SEric Piel { KE_KEY, 0x31, {KEY_MAIL} }, 5907b0a4cd7SEric Piel { KE_KEY, 0x36, {KEY_WWW} }, 5917b0a4cd7SEric Piel { KE_KEY, 0x37, {KEY_DISPLAYTOGGLE} }, /* Display on/off */ 5927b0a4cd7SEric Piel { KE_KEY, 0x40, {KEY_WLAN} }, 5937b0a4cd7SEric Piel { KE_KEY, 0x49, {KEY_CONFIG} }, 5947b0a4cd7SEric Piel { KE_SW, 0x4a, {.sw = {SW_LID, 1}} }, /* lid close */ 5957b0a4cd7SEric Piel { KE_SW, 0x4b, {.sw = {SW_LID, 0}} }, /* lid open */ 5967b0a4cd7SEric Piel { KE_KEY, 0x6a, {KEY_CONFIG} }, 5977b0a4cd7SEric Piel { KE_KEY, 0x6d, {KEY_POWER} }, 5987b0a4cd7SEric Piel { KE_KEY, 0x71, {KEY_STOPCD} }, 5997b0a4cd7SEric Piel { KE_KEY, 0x72, {KEY_PLAYPAUSE} }, 6007b0a4cd7SEric Piel { KE_KEY, 0x74, {KEY_REWIND} }, 6017b0a4cd7SEric Piel { KE_KEY, 0x78, {KEY_FORWARD} }, 6027b0a4cd7SEric Piel { KE_WIFI, 0x30 }, 6037b0a4cd7SEric Piel { KE_BLUETOOTH, 0x44 }, 6047b0a4cd7SEric Piel { KE_END, 0 } 6057b0a4cd7SEric Piel }; 6067b0a4cd7SEric Piel 6075fc14680SDmitry Torokhov /* 6085fc14680SDmitry Torokhov * If your machine is not here (which is currently rather likely), please send 6095fc14680SDmitry Torokhov * a list of buttons and their key codes (reported when loading this module 6105fc14680SDmitry Torokhov * with force=1) and the output of dmidecode to $MODULE_AUTHOR. 6115fc14680SDmitry Torokhov */ 612c7948989SAndrew Morton static struct dmi_system_id dmi_ids[] __initdata = { 6135fc14680SDmitry Torokhov { 6145fc14680SDmitry Torokhov .callback = dmi_matched, 6155fc14680SDmitry Torokhov .ident = "Fujitsu-Siemens Amilo Pro V2000", 6165fc14680SDmitry Torokhov .matches = { 6175fc14680SDmitry Torokhov DMI_MATCH(DMI_SYS_VENDOR, "FUJITSU SIEMENS"), 6185fc14680SDmitry Torokhov DMI_MATCH(DMI_PRODUCT_NAME, "AMILO Pro V2000"), 6195fc14680SDmitry Torokhov }, 6205fc14680SDmitry Torokhov .driver_data = keymap_fs_amilo_pro_v2000 6215fc14680SDmitry Torokhov }, 62284b256a6SBernhard Rosenkraenzer { 62384b256a6SBernhard Rosenkraenzer .callback = dmi_matched, 6248a1b1708SStefan Rompf .ident = "Fujitsu-Siemens Amilo M7400", 6258a1b1708SStefan Rompf .matches = { 6268a1b1708SStefan Rompf DMI_MATCH(DMI_SYS_VENDOR, "FUJITSU SIEMENS"), 6278a1b1708SStefan Rompf DMI_MATCH(DMI_PRODUCT_NAME, "AMILO M "), 6288a1b1708SStefan Rompf }, 6298a1b1708SStefan Rompf .driver_data = keymap_fs_amilo_pro_v2000 6308a1b1708SStefan Rompf }, 6318a1b1708SStefan Rompf { 6328a1b1708SStefan Rompf .callback = dmi_matched, 633e2aa507aSJohn Reed Riley .ident = "Fujitsu N3510", 634e2aa507aSJohn Reed Riley .matches = { 635e2aa507aSJohn Reed Riley DMI_MATCH(DMI_SYS_VENDOR, "FUJITSU"), 636e2aa507aSJohn Reed Riley DMI_MATCH(DMI_PRODUCT_NAME, "N3510"), 637e2aa507aSJohn Reed Riley }, 638e2aa507aSJohn Reed Riley .driver_data = keymap_fujitsu_n3510 639e2aa507aSJohn Reed Riley }, 640e2aa507aSJohn Reed Riley { 641e2aa507aSJohn Reed Riley .callback = dmi_matched, 64284b256a6SBernhard Rosenkraenzer .ident = "Acer Aspire 1500", 64384b256a6SBernhard Rosenkraenzer .matches = { 64484b256a6SBernhard Rosenkraenzer DMI_MATCH(DMI_SYS_VENDOR, "Acer"), 64584b256a6SBernhard Rosenkraenzer DMI_MATCH(DMI_PRODUCT_NAME, "Aspire 1500"), 64684b256a6SBernhard Rosenkraenzer }, 64784b256a6SBernhard Rosenkraenzer .driver_data = keymap_acer_aspire_1500 64884b256a6SBernhard Rosenkraenzer }, 64974a89c96SAshutosh Naik { 65074a89c96SAshutosh Naik .callback = dmi_matched, 6516480e2a2SEric Piel .ident = "Acer Aspire 1600", 6526480e2a2SEric Piel .matches = { 6536480e2a2SEric Piel DMI_MATCH(DMI_SYS_VENDOR, "Acer"), 6546480e2a2SEric Piel DMI_MATCH(DMI_PRODUCT_NAME, "Aspire 1600"), 6556480e2a2SEric Piel }, 6566480e2a2SEric Piel .driver_data = keymap_acer_aspire_1600 6576480e2a2SEric Piel }, 6586480e2a2SEric Piel { 6596480e2a2SEric Piel .callback = dmi_matched, 6606480e2a2SEric Piel .ident = "Acer Aspire 3020", 6616480e2a2SEric Piel .matches = { 6626480e2a2SEric Piel DMI_MATCH(DMI_SYS_VENDOR, "Acer"), 6636480e2a2SEric Piel DMI_MATCH(DMI_PRODUCT_NAME, "Aspire 3020"), 6646480e2a2SEric Piel }, 6656480e2a2SEric Piel .driver_data = keymap_acer_aspire_5020 6666480e2a2SEric Piel }, 6676480e2a2SEric Piel { 6686480e2a2SEric Piel .callback = dmi_matched, 6696480e2a2SEric Piel .ident = "Acer Aspire 5020", 6706480e2a2SEric Piel .matches = { 6716480e2a2SEric Piel DMI_MATCH(DMI_SYS_VENDOR, "Acer"), 6726480e2a2SEric Piel DMI_MATCH(DMI_PRODUCT_NAME, "Aspire 5020"), 6736480e2a2SEric Piel }, 6746480e2a2SEric Piel .driver_data = keymap_acer_aspire_5020 6756480e2a2SEric Piel }, 6766480e2a2SEric Piel { 6776480e2a2SEric Piel .callback = dmi_matched, 6786480e2a2SEric Piel .ident = "Acer TravelMate 2100", 6796480e2a2SEric Piel .matches = { 6806480e2a2SEric Piel DMI_MATCH(DMI_SYS_VENDOR, "Acer"), 6816480e2a2SEric Piel DMI_MATCH(DMI_PRODUCT_NAME, "TravelMate 2100"), 6826480e2a2SEric Piel }, 6836480e2a2SEric Piel .driver_data = keymap_acer_aspire_5020 6846480e2a2SEric Piel }, 6856480e2a2SEric Piel { 6866480e2a2SEric Piel .callback = dmi_matched, 6876480e2a2SEric Piel .ident = "Acer TravelMate 2410", 6886480e2a2SEric Piel .matches = { 6896480e2a2SEric Piel DMI_MATCH(DMI_SYS_VENDOR, "Acer"), 6906480e2a2SEric Piel DMI_MATCH(DMI_PRODUCT_NAME, "TravelMate 2410"), 6916480e2a2SEric Piel }, 6926480e2a2SEric Piel .driver_data = keymap_acer_travelmate_2410 6936480e2a2SEric Piel }, 6946480e2a2SEric Piel { 6956480e2a2SEric Piel .callback = dmi_matched, 6966480e2a2SEric Piel .ident = "Acer TravelMate C300", 6976480e2a2SEric Piel .matches = { 6986480e2a2SEric Piel DMI_MATCH(DMI_SYS_VENDOR, "Acer"), 6996480e2a2SEric Piel DMI_MATCH(DMI_PRODUCT_NAME, "TravelMate C300"), 7006480e2a2SEric Piel }, 7016480e2a2SEric Piel .driver_data = keymap_acer_travelmate_300 7026480e2a2SEric Piel }, 7036480e2a2SEric Piel { 7046480e2a2SEric Piel .callback = dmi_matched, 7056480e2a2SEric Piel .ident = "Acer TravelMate C100", 7066480e2a2SEric Piel .matches = { 7076480e2a2SEric Piel DMI_MATCH(DMI_SYS_VENDOR, "Acer"), 7086480e2a2SEric Piel DMI_MATCH(DMI_PRODUCT_NAME, "TravelMate C100"), 7096480e2a2SEric Piel }, 7106480e2a2SEric Piel .driver_data = keymap_acer_travelmate_300 7116480e2a2SEric Piel }, 7126480e2a2SEric Piel { 7136480e2a2SEric Piel .callback = dmi_matched, 7146480e2a2SEric Piel .ident = "Acer TravelMate C110", 7156480e2a2SEric Piel .matches = { 7166480e2a2SEric Piel DMI_MATCH(DMI_SYS_VENDOR, "Acer"), 7176480e2a2SEric Piel DMI_MATCH(DMI_PRODUCT_NAME, "TravelMate C110"), 7186480e2a2SEric Piel }, 7196480e2a2SEric Piel .driver_data = keymap_acer_travelmate_110 7206480e2a2SEric Piel }, 7216480e2a2SEric Piel { 7226480e2a2SEric Piel .callback = dmi_matched, 7236480e2a2SEric Piel .ident = "Acer TravelMate 380", 7246480e2a2SEric Piel .matches = { 7256480e2a2SEric Piel DMI_MATCH(DMI_SYS_VENDOR, "Acer"), 7266480e2a2SEric Piel DMI_MATCH(DMI_PRODUCT_NAME, "TravelMate 380"), 7276480e2a2SEric Piel }, 7286480e2a2SEric Piel .driver_data = keymap_acer_travelmate_380 7296480e2a2SEric Piel }, 7306480e2a2SEric Piel { 7316480e2a2SEric Piel .callback = dmi_matched, 7326480e2a2SEric Piel .ident = "Acer TravelMate 370", 7336480e2a2SEric Piel .matches = { 7346480e2a2SEric Piel DMI_MATCH(DMI_SYS_VENDOR, "Acer"), 7356480e2a2SEric Piel DMI_MATCH(DMI_PRODUCT_NAME, "TravelMate 370"), 7366480e2a2SEric Piel }, 7376480e2a2SEric Piel .driver_data = keymap_acer_travelmate_380 /* keyboard minus 1 key */ 7386480e2a2SEric Piel }, 7396480e2a2SEric Piel { 7406480e2a2SEric Piel .callback = dmi_matched, 7416480e2a2SEric Piel .ident = "Acer TravelMate 220", 7426480e2a2SEric Piel .matches = { 7436480e2a2SEric Piel DMI_MATCH(DMI_SYS_VENDOR, "Acer"), 7446480e2a2SEric Piel DMI_MATCH(DMI_PRODUCT_NAME, "TravelMate 220"), 7456480e2a2SEric Piel }, 7466480e2a2SEric Piel .driver_data = keymap_acer_travelmate_220 7476480e2a2SEric Piel }, 7486480e2a2SEric Piel { 7496480e2a2SEric Piel .callback = dmi_matched, 7506480e2a2SEric Piel .ident = "Acer TravelMate 260", 7516480e2a2SEric Piel .matches = { 7526480e2a2SEric Piel DMI_MATCH(DMI_SYS_VENDOR, "Acer"), 7536480e2a2SEric Piel DMI_MATCH(DMI_PRODUCT_NAME, "TravelMate 260"), 7546480e2a2SEric Piel }, 7556480e2a2SEric Piel .driver_data = keymap_acer_travelmate_220 7566480e2a2SEric Piel }, 7576480e2a2SEric Piel { 7586480e2a2SEric Piel .callback = dmi_matched, 7596480e2a2SEric Piel .ident = "Acer TravelMate 230", 7606480e2a2SEric Piel .matches = { 7616480e2a2SEric Piel DMI_MATCH(DMI_SYS_VENDOR, "Acer"), 7626480e2a2SEric Piel DMI_MATCH(DMI_PRODUCT_NAME, "TravelMate 230"), 7636480e2a2SEric Piel /* acerhk looks for "TravelMate F4..." ?! */ 7646480e2a2SEric Piel }, 7656480e2a2SEric Piel .driver_data = keymap_acer_travelmate_230 7666480e2a2SEric Piel }, 7676480e2a2SEric Piel { 7686480e2a2SEric Piel .callback = dmi_matched, 7696480e2a2SEric Piel .ident = "Acer TravelMate 280", 7706480e2a2SEric Piel .matches = { 7716480e2a2SEric Piel DMI_MATCH(DMI_SYS_VENDOR, "Acer"), 7726480e2a2SEric Piel DMI_MATCH(DMI_PRODUCT_NAME, "TravelMate 280"), 7736480e2a2SEric Piel }, 7746480e2a2SEric Piel .driver_data = keymap_acer_travelmate_230 7756480e2a2SEric Piel }, 7766480e2a2SEric Piel { 7776480e2a2SEric Piel .callback = dmi_matched, 77874a89c96SAshutosh Naik .ident = "Acer TravelMate 240", 77974a89c96SAshutosh Naik .matches = { 78074a89c96SAshutosh Naik DMI_MATCH(DMI_SYS_VENDOR, "Acer"), 78174a89c96SAshutosh Naik DMI_MATCH(DMI_PRODUCT_NAME, "TravelMate 240"), 78274a89c96SAshutosh Naik }, 78374a89c96SAshutosh Naik .driver_data = keymap_acer_travelmate_240 78474a89c96SAshutosh Naik }, 785e107b8eeSmasc@theaterzentrum.at { 786bb088590SAshutosh Naik .callback = dmi_matched, 7876480e2a2SEric Piel .ident = "Acer TravelMate 250", 7886480e2a2SEric Piel .matches = { 7896480e2a2SEric Piel DMI_MATCH(DMI_SYS_VENDOR, "Acer"), 7906480e2a2SEric Piel DMI_MATCH(DMI_PRODUCT_NAME, "TravelMate 250"), 7916480e2a2SEric Piel }, 7926480e2a2SEric Piel .driver_data = keymap_acer_travelmate_240 7936480e2a2SEric Piel }, 7946480e2a2SEric Piel { 7956480e2a2SEric Piel .callback = dmi_matched, 796bb088590SAshutosh Naik .ident = "Acer TravelMate 2424NWXCi", 797bb088590SAshutosh Naik .matches = { 798bb088590SAshutosh Naik DMI_MATCH(DMI_SYS_VENDOR, "Acer"), 799bb088590SAshutosh Naik DMI_MATCH(DMI_PRODUCT_NAME, "TravelMate 2420"), 800bb088590SAshutosh Naik }, 801bb088590SAshutosh Naik .driver_data = keymap_acer_travelmate_240 802bb088590SAshutosh Naik }, 803bb088590SAshutosh Naik { 804e107b8eeSmasc@theaterzentrum.at .callback = dmi_matched, 8056480e2a2SEric Piel .ident = "Acer TravelMate 350", 8066480e2a2SEric Piel .matches = { 8076480e2a2SEric Piel DMI_MATCH(DMI_SYS_VENDOR, "Acer"), 8086480e2a2SEric Piel DMI_MATCH(DMI_PRODUCT_NAME, "TravelMate 350"), 8096480e2a2SEric Piel }, 8106480e2a2SEric Piel .driver_data = keymap_acer_travelmate_350 8116480e2a2SEric Piel }, 8126480e2a2SEric Piel { 8136480e2a2SEric Piel .callback = dmi_matched, 8146480e2a2SEric Piel .ident = "Acer TravelMate 360", 8156480e2a2SEric Piel .matches = { 8166480e2a2SEric Piel DMI_MATCH(DMI_SYS_VENDOR, "Acer"), 8176480e2a2SEric Piel DMI_MATCH(DMI_PRODUCT_NAME, "TravelMate 360"), 8186480e2a2SEric Piel }, 8196480e2a2SEric Piel .driver_data = keymap_acer_travelmate_360 8206480e2a2SEric Piel }, 8216480e2a2SEric Piel { 8226480e2a2SEric Piel .callback = dmi_matched, 823bc413c95SEric Piel .ident = "Acer TravelMate 610", 824bc413c95SEric Piel .matches = { 825bc413c95SEric Piel DMI_MATCH(DMI_SYS_VENDOR, "ACER"), 826bc413c95SEric Piel DMI_MATCH(DMI_PRODUCT_NAME, "TravelMate 610"), 827bc413c95SEric Piel }, 828bc413c95SEric Piel .driver_data = keymap_acer_travelmate_610 829bc413c95SEric Piel }, 830bc413c95SEric Piel { 831bc413c95SEric Piel .callback = dmi_matched, 8326480e2a2SEric Piel .ident = "Acer TravelMate 620", 8336480e2a2SEric Piel .matches = { 8346480e2a2SEric Piel DMI_MATCH(DMI_SYS_VENDOR, "Acer"), 8356480e2a2SEric Piel DMI_MATCH(DMI_PRODUCT_NAME, "TravelMate 620"), 8366480e2a2SEric Piel }, 8376480e2a2SEric Piel .driver_data = keymap_acer_travelmate_630 8386480e2a2SEric Piel }, 8396480e2a2SEric Piel { 8406480e2a2SEric Piel .callback = dmi_matched, 8416480e2a2SEric Piel .ident = "Acer TravelMate 630", 8426480e2a2SEric Piel .matches = { 8436480e2a2SEric Piel DMI_MATCH(DMI_SYS_VENDOR, "Acer"), 8446480e2a2SEric Piel DMI_MATCH(DMI_PRODUCT_NAME, "TravelMate 630"), 8456480e2a2SEric Piel }, 8466480e2a2SEric Piel .driver_data = keymap_acer_travelmate_630 8476480e2a2SEric Piel }, 8486480e2a2SEric Piel { 8496480e2a2SEric Piel .callback = dmi_matched, 850e107b8eeSmasc@theaterzentrum.at .ident = "AOpen 1559AS", 851e107b8eeSmasc@theaterzentrum.at .matches = { 852e107b8eeSmasc@theaterzentrum.at DMI_MATCH(DMI_PRODUCT_NAME, "E2U"), 853e107b8eeSmasc@theaterzentrum.at DMI_MATCH(DMI_BOARD_NAME, "E2U"), 854e107b8eeSmasc@theaterzentrum.at }, 855e107b8eeSmasc@theaterzentrum.at .driver_data = keymap_aopen_1559as 856e107b8eeSmasc@theaterzentrum.at }, 8579000195bSFrank de Lange { 8589000195bSFrank de Lange .callback = dmi_matched, 8599000195bSFrank de Lange .ident = "Medion MD 9783", 8609000195bSFrank de Lange .matches = { 8619000195bSFrank de Lange DMI_MATCH(DMI_SYS_VENDOR, "MEDIONNB"), 8629000195bSFrank de Lange DMI_MATCH(DMI_PRODUCT_NAME, "MD 9783"), 8639000195bSFrank de Lange }, 8649000195bSFrank de Lange .driver_data = keymap_wistron_ms2111 8659000195bSFrank de Lange }, 8665809d537SMichael Leun { 8675809d537SMichael Leun .callback = dmi_matched, 8686480e2a2SEric Piel .ident = "Medion MD 40100", 8696480e2a2SEric Piel .matches = { 8706480e2a2SEric Piel DMI_MATCH(DMI_SYS_VENDOR, "MEDIONNB"), 8716480e2a2SEric Piel DMI_MATCH(DMI_PRODUCT_NAME, "WID2000"), 8726480e2a2SEric Piel }, 8736480e2a2SEric Piel .driver_data = keymap_wistron_md40100 8746480e2a2SEric Piel }, 8756480e2a2SEric Piel { 8766480e2a2SEric Piel .callback = dmi_matched, 8776480e2a2SEric Piel .ident = "Medion MD 2900", 8786480e2a2SEric Piel .matches = { 8796480e2a2SEric Piel DMI_MATCH(DMI_SYS_VENDOR, "MEDIONNB"), 8806480e2a2SEric Piel DMI_MATCH(DMI_PRODUCT_NAME, "WIM 2000"), 8816480e2a2SEric Piel }, 8826480e2a2SEric Piel .driver_data = keymap_wistron_md2900 8836480e2a2SEric Piel }, 8846480e2a2SEric Piel { 8856480e2a2SEric Piel .callback = dmi_matched, 8866480e2a2SEric Piel .ident = "Medion MD 96500", 8876480e2a2SEric Piel .matches = { 8886480e2a2SEric Piel DMI_MATCH(DMI_SYS_VENDOR, "MEDIONPC"), 8896480e2a2SEric Piel DMI_MATCH(DMI_PRODUCT_NAME, "WIM 2040"), 8906480e2a2SEric Piel }, 8916480e2a2SEric Piel .driver_data = keymap_wistron_md96500 8926480e2a2SEric Piel }, 8936480e2a2SEric Piel { 8946480e2a2SEric Piel .callback = dmi_matched, 8956480e2a2SEric Piel .ident = "Medion MD 95400", 8966480e2a2SEric Piel .matches = { 8976480e2a2SEric Piel DMI_MATCH(DMI_SYS_VENDOR, "MEDIONPC"), 8986480e2a2SEric Piel DMI_MATCH(DMI_PRODUCT_NAME, "WIM 2050"), 8996480e2a2SEric Piel }, 9006480e2a2SEric Piel .driver_data = keymap_wistron_md96500 9016480e2a2SEric Piel }, 9026480e2a2SEric Piel { 9036480e2a2SEric Piel .callback = dmi_matched, 9046480e2a2SEric Piel .ident = "Fujitsu Siemens Amilo D7820", 9056480e2a2SEric Piel .matches = { 9066480e2a2SEric Piel DMI_MATCH(DMI_SYS_VENDOR, "FUJITSU SIEMENS"), /* not sure */ 9076480e2a2SEric Piel DMI_MATCH(DMI_PRODUCT_NAME, "Amilo D"), 9086480e2a2SEric Piel }, 9096480e2a2SEric Piel .driver_data = keymap_fs_amilo_d88x0 9106480e2a2SEric Piel }, 9116480e2a2SEric Piel { 9126480e2a2SEric Piel .callback = dmi_matched, 9135809d537SMichael Leun .ident = "Fujitsu Siemens Amilo D88x0", 9145809d537SMichael Leun .matches = { 9155809d537SMichael Leun DMI_MATCH(DMI_SYS_VENDOR, "FUJITSU SIEMENS"), 9165809d537SMichael Leun DMI_MATCH(DMI_PRODUCT_NAME, "AMILO D"), 9175809d537SMichael Leun }, 9185809d537SMichael Leun .driver_data = keymap_fs_amilo_d88x0 9195809d537SMichael Leun }, 92081f0a91eSAl Viro { NULL, } 9215fc14680SDmitry Torokhov }; 9225fc14680SDmitry Torokhov 92355d29c98SEric Piel /* Copy the good keymap, as the original ones are free'd */ 92455d29c98SEric Piel static int __init copy_keymap(void) 92555d29c98SEric Piel { 92655d29c98SEric Piel const struct key_entry *key; 92755d29c98SEric Piel struct key_entry *new_keymap; 92855d29c98SEric Piel unsigned int length = 1; 92955d29c98SEric Piel 93055d29c98SEric Piel for (key = keymap; key->type != KE_END; key++) 93155d29c98SEric Piel length++; 93255d29c98SEric Piel 93355d29c98SEric Piel new_keymap = kmalloc(length * sizeof(struct key_entry), GFP_KERNEL); 93455d29c98SEric Piel if (!new_keymap) 93555d29c98SEric Piel return -ENOMEM; 93655d29c98SEric Piel 93755d29c98SEric Piel memcpy(new_keymap, keymap, length * sizeof(struct key_entry)); 93855d29c98SEric Piel keymap = new_keymap; 93955d29c98SEric Piel 94055d29c98SEric Piel return 0; 94155d29c98SEric Piel } 94255d29c98SEric Piel 9435fc14680SDmitry Torokhov static int __init select_keymap(void) 9445fc14680SDmitry Torokhov { 9457b0a4cd7SEric Piel dmi_check_system(dmi_ids); 9465fc14680SDmitry Torokhov if (keymap_name != NULL) { 9475fc14680SDmitry Torokhov if (strcmp (keymap_name, "1557/MS2141") == 0) 9485fc14680SDmitry Torokhov keymap = keymap_wistron_ms2141; 9497b0a4cd7SEric Piel else if (strcmp (keymap_name, "generic") == 0) 9507b0a4cd7SEric Piel keymap = keymap_wistron_generic; 9515fc14680SDmitry Torokhov else { 9525fc14680SDmitry Torokhov printk(KERN_ERR "wistron_btns: Keymap unknown\n"); 9535fc14680SDmitry Torokhov return -EINVAL; 9545fc14680SDmitry Torokhov } 9555fc14680SDmitry Torokhov } 9565fc14680SDmitry Torokhov if (keymap == NULL) { 9575fc14680SDmitry Torokhov if (!force) { 9585fc14680SDmitry Torokhov printk(KERN_ERR "wistron_btns: System unknown\n"); 9595fc14680SDmitry Torokhov return -ENODEV; 9605fc14680SDmitry Torokhov } 9615fc14680SDmitry Torokhov keymap = keymap_empty; 9625fc14680SDmitry Torokhov } 96355d29c98SEric Piel 96455d29c98SEric Piel return copy_keymap(); 9655fc14680SDmitry Torokhov } 9665fc14680SDmitry Torokhov 9675fc14680SDmitry Torokhov /* Input layer interface */ 9685fc14680SDmitry Torokhov 96922a397e2SDmitry Torokhov static struct input_dev *input_dev; 9705fc14680SDmitry Torokhov 971e7c3aad5SDmitry Torokhov static int __devinit setup_input_dev(void) 9725fc14680SDmitry Torokhov { 9735fc14680SDmitry Torokhov const struct key_entry *key; 97422a397e2SDmitry Torokhov int error; 97522a397e2SDmitry Torokhov 97622a397e2SDmitry Torokhov input_dev = input_allocate_device(); 97722a397e2SDmitry Torokhov if (!input_dev) 97822a397e2SDmitry Torokhov return -ENOMEM; 97922a397e2SDmitry Torokhov 98022a397e2SDmitry Torokhov input_dev->name = "Wistron laptop buttons"; 98122a397e2SDmitry Torokhov input_dev->phys = "wistron/input0"; 98222a397e2SDmitry Torokhov input_dev->id.bustype = BUS_HOST; 983a5b0cc80SDmitry Torokhov input_dev->cdev.dev = &wistron_device->dev; 9845fc14680SDmitry Torokhov 9855fc14680SDmitry Torokhov for (key = keymap; key->type != KE_END; key++) { 9866480e2a2SEric Piel switch (key->type) { 9876480e2a2SEric Piel case KE_KEY: 9886480e2a2SEric Piel set_bit(EV_KEY, input_dev->evbit); 98922a397e2SDmitry Torokhov set_bit(key->keycode, input_dev->keybit); 9906480e2a2SEric Piel break; 9916480e2a2SEric Piel 9926480e2a2SEric Piel case KE_SW: 9936480e2a2SEric Piel set_bit(EV_SW, input_dev->evbit); 9946480e2a2SEric Piel set_bit(key->sw.code, input_dev->swbit); 9956480e2a2SEric Piel break; 9966480e2a2SEric Piel 9976480e2a2SEric Piel default: 9986480e2a2SEric Piel ; 9995fc14680SDmitry Torokhov } 10005fc14680SDmitry Torokhov } 10015fc14680SDmitry Torokhov 10026480e2a2SEric Piel /* reads information flags on KE_END */ 10036480e2a2SEric Piel if (key->code & FE_UNTESTED) 10046480e2a2SEric Piel printk(KERN_WARNING "Untested laptop multimedia keys, " 10056480e2a2SEric Piel "please report success or failure to eric.piel" 10066480e2a2SEric Piel "@tremplin-utc.net\n"); 10076480e2a2SEric Piel 100822a397e2SDmitry Torokhov error = input_register_device(input_dev); 100922a397e2SDmitry Torokhov if (error) { 101022a397e2SDmitry Torokhov input_free_device(input_dev); 101122a397e2SDmitry Torokhov return error; 101222a397e2SDmitry Torokhov } 101322a397e2SDmitry Torokhov 101422a397e2SDmitry Torokhov return 0; 10155fc14680SDmitry Torokhov } 10165fc14680SDmitry Torokhov 10175fc14680SDmitry Torokhov static void report_key(unsigned keycode) 10185fc14680SDmitry Torokhov { 101922a397e2SDmitry Torokhov input_report_key(input_dev, keycode, 1); 102022a397e2SDmitry Torokhov input_sync(input_dev); 102122a397e2SDmitry Torokhov input_report_key(input_dev, keycode, 0); 102222a397e2SDmitry Torokhov input_sync(input_dev); 10235fc14680SDmitry Torokhov } 10245fc14680SDmitry Torokhov 10256480e2a2SEric Piel static void report_switch(unsigned code, int value) 10266480e2a2SEric Piel { 10276480e2a2SEric Piel input_report_switch(input_dev, code, value); 10286480e2a2SEric Piel input_sync(input_dev); 10296480e2a2SEric Piel } 10306480e2a2SEric Piel 10315fc14680SDmitry Torokhov /* Driver core */ 10325fc14680SDmitry Torokhov 10335fc14680SDmitry Torokhov static int wifi_enabled; 103484b256a6SBernhard Rosenkraenzer static int bluetooth_enabled; 10355fc14680SDmitry Torokhov 10365fc14680SDmitry Torokhov static void poll_bios(unsigned long); 10375fc14680SDmitry Torokhov 10385fc14680SDmitry Torokhov static struct timer_list poll_timer = TIMER_INITIALIZER(poll_bios, 0, 0); 10395fc14680SDmitry Torokhov 10405fc14680SDmitry Torokhov static void handle_key(u8 code) 10415fc14680SDmitry Torokhov { 10425fc14680SDmitry Torokhov const struct key_entry *key; 10435fc14680SDmitry Torokhov 10445fc14680SDmitry Torokhov for (key = keymap; key->type != KE_END; key++) { 10455fc14680SDmitry Torokhov if (code == key->code) { 10465fc14680SDmitry Torokhov switch (key->type) { 10475fc14680SDmitry Torokhov case KE_KEY: 10485fc14680SDmitry Torokhov report_key(key->keycode); 10495fc14680SDmitry Torokhov break; 10505fc14680SDmitry Torokhov 10516480e2a2SEric Piel case KE_SW: 10526480e2a2SEric Piel report_switch(key->sw.code, key->sw.value); 10536480e2a2SEric Piel break; 10546480e2a2SEric Piel 10555fc14680SDmitry Torokhov case KE_WIFI: 10565fc14680SDmitry Torokhov if (have_wifi) { 10575fc14680SDmitry Torokhov wifi_enabled = !wifi_enabled; 105884b256a6SBernhard Rosenkraenzer bios_set_state(WIFI, wifi_enabled); 105984b256a6SBernhard Rosenkraenzer } 106084b256a6SBernhard Rosenkraenzer break; 106184b256a6SBernhard Rosenkraenzer 106284b256a6SBernhard Rosenkraenzer case KE_BLUETOOTH: 106384b256a6SBernhard Rosenkraenzer if (have_bluetooth) { 106484b256a6SBernhard Rosenkraenzer bluetooth_enabled = !bluetooth_enabled; 106584b256a6SBernhard Rosenkraenzer bios_set_state(BLUETOOTH, bluetooth_enabled); 10665fc14680SDmitry Torokhov } 10675fc14680SDmitry Torokhov break; 10685fc14680SDmitry Torokhov 10695fc14680SDmitry Torokhov case KE_END: 10706480e2a2SEric Piel break; 10715fc14680SDmitry Torokhov default: 10725fc14680SDmitry Torokhov BUG(); 10735fc14680SDmitry Torokhov } 10745fc14680SDmitry Torokhov return; 10755fc14680SDmitry Torokhov } 10765fc14680SDmitry Torokhov } 10775fc14680SDmitry Torokhov printk(KERN_NOTICE "wistron_btns: Unknown key code %02X\n", code); 10785fc14680SDmitry Torokhov } 10795fc14680SDmitry Torokhov 10805fc14680SDmitry Torokhov static void poll_bios(unsigned long discard) 10815fc14680SDmitry Torokhov { 10825fc14680SDmitry Torokhov u8 qlen; 10835fc14680SDmitry Torokhov u16 val; 10845fc14680SDmitry Torokhov 10855fc14680SDmitry Torokhov for (;;) { 10865fc14680SDmitry Torokhov qlen = CMOS_READ(cmos_address); 10875fc14680SDmitry Torokhov if (qlen == 0) 10885fc14680SDmitry Torokhov break; 10895fc14680SDmitry Torokhov val = bios_pop_queue(); 10905fc14680SDmitry Torokhov if (val != 0 && !discard) 10915fc14680SDmitry Torokhov handle_key((u8)val); 10925fc14680SDmitry Torokhov } 10935fc14680SDmitry Torokhov 10945fc14680SDmitry Torokhov mod_timer(&poll_timer, jiffies + HZ / POLL_FREQUENCY); 10955fc14680SDmitry Torokhov } 10965fc14680SDmitry Torokhov 1097e7c3aad5SDmitry Torokhov static int __devinit wistron_probe(struct platform_device *dev) 1098e7c3aad5SDmitry Torokhov { 1099e7c3aad5SDmitry Torokhov int err = setup_input_dev(); 1100e7c3aad5SDmitry Torokhov if (err) 1101e7c3aad5SDmitry Torokhov return err; 1102e7c3aad5SDmitry Torokhov 1103e7c3aad5SDmitry Torokhov bios_attach(); 1104e7c3aad5SDmitry Torokhov cmos_address = bios_get_cmos_address(); 1105e7c3aad5SDmitry Torokhov 1106e7c3aad5SDmitry Torokhov if (have_wifi) { 1107e7c3aad5SDmitry Torokhov u16 wifi = bios_get_default_setting(WIFI); 1108e7c3aad5SDmitry Torokhov if (wifi & 1) 1109e7c3aad5SDmitry Torokhov wifi_enabled = (wifi & 2) ? 1 : 0; 1110e7c3aad5SDmitry Torokhov else 1111e7c3aad5SDmitry Torokhov have_wifi = 0; 1112e7c3aad5SDmitry Torokhov 1113e7c3aad5SDmitry Torokhov if (have_wifi) 1114e7c3aad5SDmitry Torokhov bios_set_state(WIFI, wifi_enabled); 1115e7c3aad5SDmitry Torokhov } 1116e7c3aad5SDmitry Torokhov 1117e7c3aad5SDmitry Torokhov if (have_bluetooth) { 1118e7c3aad5SDmitry Torokhov u16 bt = bios_get_default_setting(BLUETOOTH); 1119e7c3aad5SDmitry Torokhov if (bt & 1) 1120e7c3aad5SDmitry Torokhov bluetooth_enabled = (bt & 2) ? 1 : 0; 1121e7c3aad5SDmitry Torokhov else 1122e7c3aad5SDmitry Torokhov have_bluetooth = 0; 1123e7c3aad5SDmitry Torokhov 1124e7c3aad5SDmitry Torokhov if (have_bluetooth) 1125e7c3aad5SDmitry Torokhov bios_set_state(BLUETOOTH, bluetooth_enabled); 1126e7c3aad5SDmitry Torokhov } 1127e7c3aad5SDmitry Torokhov 1128e7c3aad5SDmitry Torokhov poll_bios(1); /* Flush stale event queue and arm timer */ 1129e7c3aad5SDmitry Torokhov 1130e7c3aad5SDmitry Torokhov return 0; 1131e7c3aad5SDmitry Torokhov } 1132e7c3aad5SDmitry Torokhov 1133e7c3aad5SDmitry Torokhov static int __devexit wistron_remove(struct platform_device *dev) 1134e7c3aad5SDmitry Torokhov { 1135e7c3aad5SDmitry Torokhov del_timer_sync(&poll_timer); 1136e7c3aad5SDmitry Torokhov input_unregister_device(input_dev); 1137e7c3aad5SDmitry Torokhov bios_detach(); 1138e7c3aad5SDmitry Torokhov 1139e7c3aad5SDmitry Torokhov return 0; 1140e7c3aad5SDmitry Torokhov } 1141e7c3aad5SDmitry Torokhov 1142e7c3aad5SDmitry Torokhov #ifdef CONFIG_PM 1143a5b0cc80SDmitry Torokhov static int wistron_suspend(struct platform_device *dev, pm_message_t state) 1144a5b0cc80SDmitry Torokhov { 1145a5b0cc80SDmitry Torokhov del_timer_sync(&poll_timer); 1146a5b0cc80SDmitry Torokhov 1147e753b650SMiloslav Trmac if (have_wifi) 1148e753b650SMiloslav Trmac bios_set_state(WIFI, 0); 1149e753b650SMiloslav Trmac 1150e753b650SMiloslav Trmac if (have_bluetooth) 1151e753b650SMiloslav Trmac bios_set_state(BLUETOOTH, 0); 1152e753b650SMiloslav Trmac 1153a5b0cc80SDmitry Torokhov return 0; 1154a5b0cc80SDmitry Torokhov } 1155a5b0cc80SDmitry Torokhov 1156a5b0cc80SDmitry Torokhov static int wistron_resume(struct platform_device *dev) 1157a5b0cc80SDmitry Torokhov { 1158a5b0cc80SDmitry Torokhov if (have_wifi) 1159a5b0cc80SDmitry Torokhov bios_set_state(WIFI, wifi_enabled); 1160a5b0cc80SDmitry Torokhov 1161a5b0cc80SDmitry Torokhov if (have_bluetooth) 1162a5b0cc80SDmitry Torokhov bios_set_state(BLUETOOTH, bluetooth_enabled); 1163a5b0cc80SDmitry Torokhov 1164a5b0cc80SDmitry Torokhov poll_bios(1); 1165a5b0cc80SDmitry Torokhov 1166a5b0cc80SDmitry Torokhov return 0; 1167a5b0cc80SDmitry Torokhov } 1168e7c3aad5SDmitry Torokhov #else 1169e7c3aad5SDmitry Torokhov #define wistron_suspend NULL 1170e7c3aad5SDmitry Torokhov #define wistron_resume NULL 1171e7c3aad5SDmitry Torokhov #endif 1172a5b0cc80SDmitry Torokhov 1173a5b0cc80SDmitry Torokhov static struct platform_driver wistron_driver = { 1174a5b0cc80SDmitry Torokhov .driver = { 1175a5b0cc80SDmitry Torokhov .name = "wistron-bios", 1176e7c3aad5SDmitry Torokhov .owner = THIS_MODULE, 1177a5b0cc80SDmitry Torokhov }, 1178e7c3aad5SDmitry Torokhov .probe = wistron_probe, 1179e7c3aad5SDmitry Torokhov .remove = __devexit_p(wistron_remove), 1180e7c3aad5SDmitry Torokhov .suspend = wistron_suspend, 1181e7c3aad5SDmitry Torokhov .resume = wistron_resume, 1182a5b0cc80SDmitry Torokhov }; 1183a5b0cc80SDmitry Torokhov 11845fc14680SDmitry Torokhov static int __init wb_module_init(void) 11855fc14680SDmitry Torokhov { 11865fc14680SDmitry Torokhov int err; 11875fc14680SDmitry Torokhov 11885fc14680SDmitry Torokhov err = select_keymap(); 11895fc14680SDmitry Torokhov if (err) 11905fc14680SDmitry Torokhov return err; 119122a397e2SDmitry Torokhov 11925fc14680SDmitry Torokhov err = map_bios(); 11935fc14680SDmitry Torokhov if (err) 11945fc14680SDmitry Torokhov return err; 119522a397e2SDmitry Torokhov 1196a5b0cc80SDmitry Torokhov err = platform_driver_register(&wistron_driver); 1197a5b0cc80SDmitry Torokhov if (err) 1198e7c3aad5SDmitry Torokhov goto err_unmap_bios; 1199a5b0cc80SDmitry Torokhov 1200e7c3aad5SDmitry Torokhov wistron_device = platform_device_alloc("wistron-bios", -1); 1201e7c3aad5SDmitry Torokhov if (!wistron_device) { 1202e7c3aad5SDmitry Torokhov err = -ENOMEM; 1203a5b0cc80SDmitry Torokhov goto err_unregister_driver; 1204a5b0cc80SDmitry Torokhov } 1205a5b0cc80SDmitry Torokhov 1206e7c3aad5SDmitry Torokhov err = platform_device_add(wistron_device); 1207a5b0cc80SDmitry Torokhov if (err) 1208e7c3aad5SDmitry Torokhov goto err_free_device; 12095fc14680SDmitry Torokhov 12105fc14680SDmitry Torokhov return 0; 1211a5b0cc80SDmitry Torokhov 1212e7c3aad5SDmitry Torokhov err_free_device: 1213e7c3aad5SDmitry Torokhov platform_device_put(wistron_device); 1214a5b0cc80SDmitry Torokhov err_unregister_driver: 1215a5b0cc80SDmitry Torokhov platform_driver_unregister(&wistron_driver); 1216e7c3aad5SDmitry Torokhov err_unmap_bios: 1217a5b0cc80SDmitry Torokhov unmap_bios(); 1218a5b0cc80SDmitry Torokhov 1219a5b0cc80SDmitry Torokhov return err; 12205fc14680SDmitry Torokhov } 12215fc14680SDmitry Torokhov 12225fc14680SDmitry Torokhov static void __exit wb_module_exit(void) 12235fc14680SDmitry Torokhov { 1224a5b0cc80SDmitry Torokhov platform_device_unregister(wistron_device); 1225a5b0cc80SDmitry Torokhov platform_driver_unregister(&wistron_driver); 12265fc14680SDmitry Torokhov unmap_bios(); 122755d29c98SEric Piel kfree(keymap); 12285fc14680SDmitry Torokhov } 12295fc14680SDmitry Torokhov 12305fc14680SDmitry Torokhov module_init(wb_module_init); 12315fc14680SDmitry Torokhov module_exit(wb_module_exit); 1232