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> 23c2554c91SDmitry Torokhov #include <linux/input-polldev.h> 24e97af4cbSDmitry Torokhov #include <linux/input/sparse-keymap.h> 255fc14680SDmitry Torokhov #include <linux/interrupt.h> 26a4da16d3SEric Piel #include <linux/jiffies.h> 275fc14680SDmitry Torokhov #include <linux/kernel.h> 285fc14680SDmitry Torokhov #include <linux/mc146818rtc.h> 295fc14680SDmitry Torokhov #include <linux/module.h> 305fc14680SDmitry Torokhov #include <linux/preempt.h> 315fc14680SDmitry Torokhov #include <linux/string.h> 325a0e3ad6STejun Heo #include <linux/slab.h> 335fc14680SDmitry Torokhov #include <linux/types.h> 34a5b0cc80SDmitry Torokhov #include <linux/platform_device.h> 35389679d8SEric Piel #include <linux/leds.h> 365fc14680SDmitry Torokhov 37c2554c91SDmitry Torokhov /* How often we poll keys - msecs */ 38c2554c91SDmitry Torokhov #define POLL_INTERVAL_DEFAULT 500 /* when idle */ 39c2554c91SDmitry Torokhov #define POLL_INTERVAL_BURST 100 /* when a key was recently pressed */ 405fc14680SDmitry Torokhov 4184b256a6SBernhard Rosenkraenzer /* BIOS subsystem IDs */ 4284b256a6SBernhard Rosenkraenzer #define WIFI 0x35 4384b256a6SBernhard Rosenkraenzer #define BLUETOOTH 0x34 44389679d8SEric Piel #define MAIL_LED 0x31 4584b256a6SBernhard Rosenkraenzer 465fc14680SDmitry Torokhov MODULE_AUTHOR("Miloslav Trmac <mitr@volny.cz>"); 475fc14680SDmitry Torokhov MODULE_DESCRIPTION("Wistron laptop button driver"); 485fc14680SDmitry Torokhov MODULE_LICENSE("GPL v2"); 49389679d8SEric Piel MODULE_VERSION("0.3"); 505fc14680SDmitry Torokhov 5190ab5ee9SRusty Russell static bool force; /* = 0; */ 525fc14680SDmitry Torokhov module_param(force, bool, 0); 535fc14680SDmitry Torokhov MODULE_PARM_DESC(force, "Load even if computer is not in database"); 545fc14680SDmitry Torokhov 555fc14680SDmitry Torokhov static char *keymap_name; /* = NULL; */ 565fc14680SDmitry Torokhov module_param_named(keymap, keymap_name, charp, 0); 577b0a4cd7SEric Piel MODULE_PARM_DESC(keymap, "Keymap name, if it can't be autodetected [generic, 1557/MS2141]"); 585fc14680SDmitry Torokhov 59a5b0cc80SDmitry Torokhov static struct platform_device *wistron_device; 60a5b0cc80SDmitry Torokhov 615fc14680SDmitry Torokhov /* BIOS interface implementation */ 625fc14680SDmitry Torokhov 635fc14680SDmitry Torokhov static void __iomem *bios_entry_point; /* BIOS routine entry point */ 645fc14680SDmitry Torokhov static void __iomem *bios_code_map_base; 655fc14680SDmitry Torokhov static void __iomem *bios_data_map_base; 665fc14680SDmitry Torokhov 675fc14680SDmitry Torokhov static u8 cmos_address; 685fc14680SDmitry Torokhov 695fc14680SDmitry Torokhov struct regs { 705fc14680SDmitry Torokhov u32 eax, ebx, ecx; 715fc14680SDmitry Torokhov }; 725fc14680SDmitry Torokhov 735fc14680SDmitry Torokhov static void call_bios(struct regs *regs) 745fc14680SDmitry Torokhov { 755fc14680SDmitry Torokhov unsigned long flags; 765fc14680SDmitry Torokhov 775fc14680SDmitry Torokhov preempt_disable(); 785fc14680SDmitry Torokhov local_irq_save(flags); 795fc14680SDmitry Torokhov asm volatile ("pushl %%ebp;" 805fc14680SDmitry Torokhov "movl %7, %%ebp;" 815fc14680SDmitry Torokhov "call *%6;" 825fc14680SDmitry Torokhov "popl %%ebp" 835fc14680SDmitry Torokhov : "=a" (regs->eax), "=b" (regs->ebx), "=c" (regs->ecx) 845fc14680SDmitry Torokhov : "0" (regs->eax), "1" (regs->ebx), "2" (regs->ecx), 855fc14680SDmitry Torokhov "m" (bios_entry_point), "m" (bios_data_map_base) 865fc14680SDmitry Torokhov : "edx", "edi", "esi", "memory"); 875fc14680SDmitry Torokhov local_irq_restore(flags); 885fc14680SDmitry Torokhov preempt_enable(); 895fc14680SDmitry Torokhov } 905fc14680SDmitry Torokhov 91c28c3583SMiloslav Trmac static ssize_t __init locate_wistron_bios(void __iomem *base) 925fc14680SDmitry Torokhov { 93c7948989SAndrew Morton static unsigned char __initdata signature[] = 945fc14680SDmitry Torokhov { 0x42, 0x21, 0x55, 0x30 }; 95c28c3583SMiloslav Trmac ssize_t offset; 965fc14680SDmitry Torokhov 975fc14680SDmitry Torokhov for (offset = 0; offset < 0x10000; offset += 0x10) { 985fc14680SDmitry Torokhov if (check_signature(base + offset, signature, 995fc14680SDmitry Torokhov sizeof(signature)) != 0) 1005fc14680SDmitry Torokhov return offset; 1015fc14680SDmitry Torokhov } 1025fc14680SDmitry Torokhov return -1; 1035fc14680SDmitry Torokhov } 1045fc14680SDmitry Torokhov 1055fc14680SDmitry Torokhov static int __init map_bios(void) 1065fc14680SDmitry Torokhov { 1075fc14680SDmitry Torokhov void __iomem *base; 108c28c3583SMiloslav Trmac ssize_t offset; 1095fc14680SDmitry Torokhov u32 entry_point; 1105fc14680SDmitry Torokhov 1115fc14680SDmitry Torokhov base = ioremap(0xF0000, 0x10000); /* Can't fail */ 1125fc14680SDmitry Torokhov offset = locate_wistron_bios(base); 1135fc14680SDmitry Torokhov if (offset < 0) { 1145fc14680SDmitry Torokhov printk(KERN_ERR "wistron_btns: BIOS entry point not found\n"); 1155fc14680SDmitry Torokhov iounmap(base); 1165fc14680SDmitry Torokhov return -ENODEV; 1175fc14680SDmitry Torokhov } 1185fc14680SDmitry Torokhov 1195fc14680SDmitry Torokhov entry_point = readl(base + offset + 5); 1205fc14680SDmitry Torokhov printk(KERN_DEBUG 1215fc14680SDmitry Torokhov "wistron_btns: BIOS signature found at %p, entry point %08X\n", 1225fc14680SDmitry Torokhov base + offset, entry_point); 1235fc14680SDmitry Torokhov 1245fc14680SDmitry Torokhov if (entry_point >= 0xF0000) { 1255fc14680SDmitry Torokhov bios_code_map_base = base; 1265fc14680SDmitry Torokhov bios_entry_point = bios_code_map_base + (entry_point & 0xFFFF); 1275fc14680SDmitry Torokhov } else { 1285fc14680SDmitry Torokhov iounmap(base); 1295fc14680SDmitry Torokhov bios_code_map_base = ioremap(entry_point & ~0x3FFF, 0x4000); 1305fc14680SDmitry Torokhov if (bios_code_map_base == NULL) { 1315fc14680SDmitry Torokhov printk(KERN_ERR 1325fc14680SDmitry Torokhov "wistron_btns: Can't map BIOS code at %08X\n", 1335fc14680SDmitry Torokhov entry_point & ~0x3FFF); 1345fc14680SDmitry Torokhov goto err; 1355fc14680SDmitry Torokhov } 1365fc14680SDmitry Torokhov bios_entry_point = bios_code_map_base + (entry_point & 0x3FFF); 1375fc14680SDmitry Torokhov } 1385fc14680SDmitry Torokhov /* The Windows driver maps 0x10000 bytes, we keep only one page... */ 1395fc14680SDmitry Torokhov bios_data_map_base = ioremap(0x400, 0xc00); 1405fc14680SDmitry Torokhov if (bios_data_map_base == NULL) { 1415fc14680SDmitry Torokhov printk(KERN_ERR "wistron_btns: Can't map BIOS data\n"); 1425fc14680SDmitry Torokhov goto err_code; 1435fc14680SDmitry Torokhov } 1445fc14680SDmitry Torokhov return 0; 1455fc14680SDmitry Torokhov 1465fc14680SDmitry Torokhov err_code: 1475fc14680SDmitry Torokhov iounmap(bios_code_map_base); 1485fc14680SDmitry Torokhov err: 1495fc14680SDmitry Torokhov return -ENOMEM; 1505fc14680SDmitry Torokhov } 1515fc14680SDmitry Torokhov 15222a397e2SDmitry Torokhov static inline void unmap_bios(void) 1535fc14680SDmitry Torokhov { 1545fc14680SDmitry Torokhov iounmap(bios_code_map_base); 1555fc14680SDmitry Torokhov iounmap(bios_data_map_base); 1565fc14680SDmitry Torokhov } 1575fc14680SDmitry Torokhov 1585fc14680SDmitry Torokhov /* BIOS calls */ 1595fc14680SDmitry Torokhov 1605fc14680SDmitry Torokhov static u16 bios_pop_queue(void) 1615fc14680SDmitry Torokhov { 1625fc14680SDmitry Torokhov struct regs regs; 1635fc14680SDmitry Torokhov 1645fc14680SDmitry Torokhov memset(®s, 0, sizeof (regs)); 1655fc14680SDmitry Torokhov regs.eax = 0x9610; 1665fc14680SDmitry Torokhov regs.ebx = 0x061C; 1675fc14680SDmitry Torokhov regs.ecx = 0x0000; 1685fc14680SDmitry Torokhov call_bios(®s); 1695fc14680SDmitry Torokhov 1705fc14680SDmitry Torokhov return regs.eax; 1715fc14680SDmitry Torokhov } 1725fc14680SDmitry Torokhov 173e7c3aad5SDmitry Torokhov static void __devinit bios_attach(void) 1745fc14680SDmitry Torokhov { 1755fc14680SDmitry Torokhov struct regs regs; 1765fc14680SDmitry Torokhov 1775fc14680SDmitry Torokhov memset(®s, 0, sizeof (regs)); 1785fc14680SDmitry Torokhov regs.eax = 0x9610; 1795fc14680SDmitry Torokhov regs.ebx = 0x012E; 1805fc14680SDmitry Torokhov call_bios(®s); 1815fc14680SDmitry Torokhov } 1825fc14680SDmitry Torokhov 18322a397e2SDmitry Torokhov static void bios_detach(void) 1845fc14680SDmitry Torokhov { 1855fc14680SDmitry Torokhov struct regs regs; 1865fc14680SDmitry Torokhov 1875fc14680SDmitry Torokhov memset(®s, 0, sizeof (regs)); 1885fc14680SDmitry Torokhov regs.eax = 0x9610; 1895fc14680SDmitry Torokhov regs.ebx = 0x002E; 1905fc14680SDmitry Torokhov call_bios(®s); 1915fc14680SDmitry Torokhov } 1925fc14680SDmitry Torokhov 193e7c3aad5SDmitry Torokhov static u8 __devinit bios_get_cmos_address(void) 1945fc14680SDmitry Torokhov { 1955fc14680SDmitry Torokhov struct regs regs; 1965fc14680SDmitry Torokhov 1975fc14680SDmitry Torokhov memset(®s, 0, sizeof (regs)); 1985fc14680SDmitry Torokhov regs.eax = 0x9610; 1995fc14680SDmitry Torokhov regs.ebx = 0x051C; 2005fc14680SDmitry Torokhov call_bios(®s); 2015fc14680SDmitry Torokhov 2025fc14680SDmitry Torokhov return regs.ecx; 2035fc14680SDmitry Torokhov } 2045fc14680SDmitry Torokhov 205e7c3aad5SDmitry Torokhov static u16 __devinit bios_get_default_setting(u8 subsys) 2065fc14680SDmitry Torokhov { 2075fc14680SDmitry Torokhov struct regs regs; 2085fc14680SDmitry Torokhov 2095fc14680SDmitry Torokhov memset(®s, 0, sizeof (regs)); 2105fc14680SDmitry Torokhov regs.eax = 0x9610; 21184b256a6SBernhard Rosenkraenzer regs.ebx = 0x0200 | subsys; 2125fc14680SDmitry Torokhov call_bios(®s); 2135fc14680SDmitry Torokhov 2145fc14680SDmitry Torokhov return regs.eax; 2155fc14680SDmitry Torokhov } 2165fc14680SDmitry Torokhov 21784b256a6SBernhard Rosenkraenzer static void bios_set_state(u8 subsys, int enable) 2185fc14680SDmitry Torokhov { 2195fc14680SDmitry Torokhov struct regs regs; 2205fc14680SDmitry Torokhov 2215fc14680SDmitry Torokhov memset(®s, 0, sizeof (regs)); 2225fc14680SDmitry Torokhov regs.eax = 0x9610; 22384b256a6SBernhard Rosenkraenzer regs.ebx = (enable ? 0x0100 : 0x0000) | subsys; 2245fc14680SDmitry Torokhov call_bios(®s); 2255fc14680SDmitry Torokhov } 2265fc14680SDmitry Torokhov 2275fc14680SDmitry Torokhov /* Hardware database */ 2285fc14680SDmitry Torokhov 229e97af4cbSDmitry Torokhov #define KE_WIFI (KE_LAST + 1) 230e97af4cbSDmitry Torokhov #define KE_BLUETOOTH (KE_LAST + 2) 2316480e2a2SEric Piel 2326480e2a2SEric Piel #define FE_MAIL_LED 0x01 2336480e2a2SEric Piel #define FE_WIFI_LED 0x02 2346480e2a2SEric Piel #define FE_UNTESTED 0x80 2355fc14680SDmitry Torokhov 236d63219a1SDmitry Torokhov static struct key_entry *keymap; /* = NULL; Current key map */ 23767dbe83aSDmitry Torokhov static bool have_wifi; 23867dbe83aSDmitry Torokhov static bool have_bluetooth; 23967dbe83aSDmitry Torokhov static int leds_present; /* bitmask of leds present */ 2405fc14680SDmitry Torokhov 2411855256cSJeff Garzik static int __init dmi_matched(const struct dmi_system_id *dmi) 2425fc14680SDmitry Torokhov { 2435fc14680SDmitry Torokhov const struct key_entry *key; 2445fc14680SDmitry Torokhov 2455fc14680SDmitry Torokhov keymap = dmi->driver_data; 2465fc14680SDmitry Torokhov for (key = keymap; key->type != KE_END; key++) { 247cde45f19SReiner Herrmann if (key->type == KE_WIFI) 24867dbe83aSDmitry Torokhov have_wifi = true; 249cde45f19SReiner Herrmann else if (key->type == KE_BLUETOOTH) 25067dbe83aSDmitry Torokhov have_bluetooth = true; 2515fc14680SDmitry Torokhov } 25267dbe83aSDmitry Torokhov leds_present = key->code & (FE_MAIL_LED | FE_WIFI_LED); 253389679d8SEric Piel 2545fc14680SDmitry Torokhov return 1; 2555fc14680SDmitry Torokhov } 2565fc14680SDmitry Torokhov 25755d29c98SEric Piel static struct key_entry keymap_empty[] __initdata = { 2585fc14680SDmitry Torokhov { KE_END, 0 } 2595fc14680SDmitry Torokhov }; 2605fc14680SDmitry Torokhov 26155d29c98SEric Piel static struct key_entry keymap_fs_amilo_pro_v2000[] __initdata = { 2626480e2a2SEric Piel { KE_KEY, 0x01, {KEY_HELP} }, 2636480e2a2SEric Piel { KE_KEY, 0x11, {KEY_PROG1} }, 2646480e2a2SEric Piel { KE_KEY, 0x12, {KEY_PROG2} }, 2656480e2a2SEric Piel { KE_WIFI, 0x30 }, 2666480e2a2SEric Piel { KE_KEY, 0x31, {KEY_MAIL} }, 2676480e2a2SEric Piel { KE_KEY, 0x36, {KEY_WWW} }, 2685fc14680SDmitry Torokhov { KE_END, 0 } 2695fc14680SDmitry Torokhov }; 2705fc14680SDmitry Torokhov 27134a7c48cSRemi Herilier static struct key_entry keymap_fs_amilo_pro_v3505[] __initdata = { 27234a7c48cSRemi Herilier { KE_KEY, 0x01, {KEY_HELP} }, /* Fn+F1 */ 27334a7c48cSRemi Herilier { KE_KEY, 0x06, {KEY_DISPLAYTOGGLE} }, /* Fn+F4 */ 27434a7c48cSRemi Herilier { KE_BLUETOOTH, 0x30 }, /* Fn+F10 */ 27534a7c48cSRemi Herilier { KE_KEY, 0x31, {KEY_MAIL} }, /* mail button */ 27634a7c48cSRemi Herilier { KE_KEY, 0x36, {KEY_WWW} }, /* www button */ 27725985edcSLucas De Marchi { KE_WIFI, 0x78 }, /* satellite dish button */ 27834a7c48cSRemi Herilier { KE_END, 0 } 27934a7c48cSRemi Herilier }; 28034a7c48cSRemi Herilier 28155d29c98SEric Piel static struct key_entry keymap_fujitsu_n3510[] __initdata = { 2826480e2a2SEric Piel { KE_KEY, 0x11, {KEY_PROG1} }, 2836480e2a2SEric Piel { KE_KEY, 0x12, {KEY_PROG2} }, 2846480e2a2SEric Piel { KE_KEY, 0x36, {KEY_WWW} }, 2856480e2a2SEric Piel { KE_KEY, 0x31, {KEY_MAIL} }, 2866480e2a2SEric Piel { KE_KEY, 0x71, {KEY_STOPCD} }, 2876480e2a2SEric Piel { KE_KEY, 0x72, {KEY_PLAYPAUSE} }, 2886480e2a2SEric Piel { KE_KEY, 0x74, {KEY_REWIND} }, 2896480e2a2SEric Piel { KE_KEY, 0x78, {KEY_FORWARD} }, 290e2aa507aSJohn Reed Riley { KE_END, 0 } 291e2aa507aSJohn Reed Riley }; 292e2aa507aSJohn Reed Riley 29355d29c98SEric Piel static struct key_entry keymap_wistron_ms2111[] __initdata = { 2946480e2a2SEric Piel { KE_KEY, 0x11, {KEY_PROG1} }, 2956480e2a2SEric Piel { KE_KEY, 0x12, {KEY_PROG2} }, 2966480e2a2SEric Piel { KE_KEY, 0x13, {KEY_PROG3} }, 2976480e2a2SEric Piel { KE_KEY, 0x31, {KEY_MAIL} }, 2986480e2a2SEric Piel { KE_KEY, 0x36, {KEY_WWW} }, 2996480e2a2SEric Piel { KE_END, FE_MAIL_LED } 3006480e2a2SEric Piel }; 3016480e2a2SEric Piel 30255d29c98SEric Piel static struct key_entry keymap_wistron_md40100[] __initdata = { 3036480e2a2SEric Piel { KE_KEY, 0x01, {KEY_HELP} }, 3046480e2a2SEric Piel { KE_KEY, 0x02, {KEY_CONFIG} }, 3056480e2a2SEric Piel { KE_KEY, 0x31, {KEY_MAIL} }, 3066480e2a2SEric Piel { KE_KEY, 0x36, {KEY_WWW} }, 3076480e2a2SEric Piel { KE_KEY, 0x37, {KEY_DISPLAYTOGGLE} }, /* Display on/off */ 3086480e2a2SEric Piel { KE_END, FE_MAIL_LED | FE_WIFI_LED | FE_UNTESTED } 3099000195bSFrank de Lange }; 3109000195bSFrank de Lange 31155d29c98SEric Piel static struct key_entry keymap_wistron_ms2141[] __initdata = { 3126480e2a2SEric Piel { KE_KEY, 0x11, {KEY_PROG1} }, 3136480e2a2SEric Piel { KE_KEY, 0x12, {KEY_PROG2} }, 3146480e2a2SEric Piel { KE_WIFI, 0x30 }, 3156480e2a2SEric Piel { KE_KEY, 0x22, {KEY_REWIND} }, 3166480e2a2SEric Piel { KE_KEY, 0x23, {KEY_FORWARD} }, 3176480e2a2SEric Piel { KE_KEY, 0x24, {KEY_PLAYPAUSE} }, 3186480e2a2SEric Piel { KE_KEY, 0x25, {KEY_STOPCD} }, 3196480e2a2SEric Piel { KE_KEY, 0x31, {KEY_MAIL} }, 3206480e2a2SEric Piel { KE_KEY, 0x36, {KEY_WWW} }, 3215fc14680SDmitry Torokhov { KE_END, 0 } 3225fc14680SDmitry Torokhov }; 3235fc14680SDmitry Torokhov 32455d29c98SEric Piel static struct key_entry keymap_acer_aspire_1500[] __initdata = { 3256480e2a2SEric Piel { KE_KEY, 0x01, {KEY_HELP} }, 3266480e2a2SEric Piel { KE_KEY, 0x03, {KEY_POWER} }, 3276480e2a2SEric Piel { KE_KEY, 0x11, {KEY_PROG1} }, 3286480e2a2SEric Piel { KE_KEY, 0x12, {KEY_PROG2} }, 3296480e2a2SEric Piel { KE_WIFI, 0x30 }, 3306480e2a2SEric Piel { KE_KEY, 0x31, {KEY_MAIL} }, 3316480e2a2SEric Piel { KE_KEY, 0x36, {KEY_WWW} }, 3326480e2a2SEric Piel { KE_KEY, 0x49, {KEY_CONFIG} }, 3336480e2a2SEric Piel { KE_BLUETOOTH, 0x44 }, 3346480e2a2SEric Piel { KE_END, FE_UNTESTED } 3356480e2a2SEric Piel }; 3366480e2a2SEric Piel 33755d29c98SEric Piel static struct key_entry keymap_acer_aspire_1600[] __initdata = { 3386480e2a2SEric Piel { KE_KEY, 0x01, {KEY_HELP} }, 3396480e2a2SEric Piel { KE_KEY, 0x03, {KEY_POWER} }, 3406480e2a2SEric Piel { KE_KEY, 0x08, {KEY_MUTE} }, 3416480e2a2SEric Piel { KE_KEY, 0x11, {KEY_PROG1} }, 3426480e2a2SEric Piel { KE_KEY, 0x12, {KEY_PROG2} }, 3436480e2a2SEric Piel { KE_KEY, 0x13, {KEY_PROG3} }, 3446480e2a2SEric Piel { KE_KEY, 0x31, {KEY_MAIL} }, 3456480e2a2SEric Piel { KE_KEY, 0x36, {KEY_WWW} }, 3466480e2a2SEric Piel { KE_KEY, 0x49, {KEY_CONFIG} }, 3476480e2a2SEric Piel { KE_WIFI, 0x30 }, 3486480e2a2SEric Piel { KE_BLUETOOTH, 0x44 }, 3496480e2a2SEric Piel { KE_END, FE_MAIL_LED | FE_UNTESTED } 3506480e2a2SEric Piel }; 3516480e2a2SEric Piel 3526480e2a2SEric Piel /* 3020 has been tested */ 35355d29c98SEric Piel static struct key_entry keymap_acer_aspire_5020[] __initdata = { 3546480e2a2SEric Piel { KE_KEY, 0x01, {KEY_HELP} }, 3556480e2a2SEric Piel { KE_KEY, 0x03, {KEY_POWER} }, 3566480e2a2SEric Piel { KE_KEY, 0x05, {KEY_SWITCHVIDEOMODE} }, /* Display selection */ 3576480e2a2SEric Piel { KE_KEY, 0x11, {KEY_PROG1} }, 3586480e2a2SEric Piel { KE_KEY, 0x12, {KEY_PROG2} }, 3596480e2a2SEric Piel { KE_KEY, 0x31, {KEY_MAIL} }, 3606480e2a2SEric Piel { KE_KEY, 0x36, {KEY_WWW} }, 3616480e2a2SEric Piel { KE_KEY, 0x6a, {KEY_CONFIG} }, 3626480e2a2SEric Piel { KE_WIFI, 0x30 }, 3636480e2a2SEric Piel { KE_BLUETOOTH, 0x44 }, 3646480e2a2SEric Piel { KE_END, FE_MAIL_LED | FE_UNTESTED } 3656480e2a2SEric Piel }; 3666480e2a2SEric Piel 36755d29c98SEric Piel static struct key_entry keymap_acer_travelmate_2410[] __initdata = { 3686480e2a2SEric Piel { KE_KEY, 0x01, {KEY_HELP} }, 3696480e2a2SEric Piel { KE_KEY, 0x6d, {KEY_POWER} }, 3706480e2a2SEric Piel { KE_KEY, 0x11, {KEY_PROG1} }, 3716480e2a2SEric Piel { KE_KEY, 0x12, {KEY_PROG2} }, 3726480e2a2SEric Piel { KE_KEY, 0x31, {KEY_MAIL} }, 3736480e2a2SEric Piel { KE_KEY, 0x36, {KEY_WWW} }, 3746480e2a2SEric Piel { KE_KEY, 0x6a, {KEY_CONFIG} }, 3756480e2a2SEric Piel { KE_WIFI, 0x30 }, 3766480e2a2SEric Piel { KE_BLUETOOTH, 0x44 }, 3776480e2a2SEric Piel { KE_END, FE_MAIL_LED | FE_UNTESTED } 3786480e2a2SEric Piel }; 3796480e2a2SEric Piel 38055d29c98SEric Piel static struct key_entry keymap_acer_travelmate_110[] __initdata = { 3816480e2a2SEric Piel { KE_KEY, 0x01, {KEY_HELP} }, 3826480e2a2SEric Piel { KE_KEY, 0x02, {KEY_CONFIG} }, 3836480e2a2SEric Piel { KE_KEY, 0x03, {KEY_POWER} }, 3846480e2a2SEric Piel { KE_KEY, 0x08, {KEY_MUTE} }, 3856480e2a2SEric Piel { KE_KEY, 0x11, {KEY_PROG1} }, 3866480e2a2SEric Piel { KE_KEY, 0x12, {KEY_PROG2} }, 3876480e2a2SEric Piel { KE_KEY, 0x20, {KEY_VOLUMEUP} }, 3886480e2a2SEric Piel { KE_KEY, 0x21, {KEY_VOLUMEDOWN} }, 3896480e2a2SEric Piel { KE_KEY, 0x31, {KEY_MAIL} }, 3906480e2a2SEric Piel { KE_KEY, 0x36, {KEY_WWW} }, 3916480e2a2SEric Piel { KE_SW, 0x4a, {.sw = {SW_LID, 1}} }, /* lid close */ 3926480e2a2SEric Piel { KE_SW, 0x4b, {.sw = {SW_LID, 0}} }, /* lid open */ 3936480e2a2SEric Piel { KE_WIFI, 0x30 }, 3946480e2a2SEric Piel { KE_END, FE_MAIL_LED | FE_UNTESTED } 3956480e2a2SEric Piel }; 3966480e2a2SEric Piel 39755d29c98SEric Piel static struct key_entry keymap_acer_travelmate_300[] __initdata = { 3986480e2a2SEric Piel { KE_KEY, 0x01, {KEY_HELP} }, 3996480e2a2SEric Piel { KE_KEY, 0x02, {KEY_CONFIG} }, 4006480e2a2SEric Piel { KE_KEY, 0x03, {KEY_POWER} }, 4016480e2a2SEric Piel { KE_KEY, 0x08, {KEY_MUTE} }, 4026480e2a2SEric Piel { KE_KEY, 0x11, {KEY_PROG1} }, 4036480e2a2SEric Piel { KE_KEY, 0x12, {KEY_PROG2} }, 4046480e2a2SEric Piel { KE_KEY, 0x20, {KEY_VOLUMEUP} }, 4056480e2a2SEric Piel { KE_KEY, 0x21, {KEY_VOLUMEDOWN} }, 4066480e2a2SEric Piel { KE_KEY, 0x31, {KEY_MAIL} }, 4076480e2a2SEric Piel { KE_KEY, 0x36, {KEY_WWW} }, 4086480e2a2SEric Piel { KE_WIFI, 0x30 }, 4096480e2a2SEric Piel { KE_BLUETOOTH, 0x44 }, 4106480e2a2SEric Piel { KE_END, FE_MAIL_LED | FE_UNTESTED } 4116480e2a2SEric Piel }; 4126480e2a2SEric Piel 41355d29c98SEric Piel static struct key_entry keymap_acer_travelmate_380[] __initdata = { 4146480e2a2SEric Piel { KE_KEY, 0x01, {KEY_HELP} }, 4156480e2a2SEric Piel { KE_KEY, 0x02, {KEY_CONFIG} }, 4166480e2a2SEric Piel { KE_KEY, 0x03, {KEY_POWER} }, /* not 370 */ 4176480e2a2SEric Piel { KE_KEY, 0x11, {KEY_PROG1} }, 4186480e2a2SEric Piel { KE_KEY, 0x12, {KEY_PROG2} }, 4196480e2a2SEric Piel { KE_KEY, 0x13, {KEY_PROG3} }, 4206480e2a2SEric Piel { KE_KEY, 0x31, {KEY_MAIL} }, 4216480e2a2SEric Piel { KE_KEY, 0x36, {KEY_WWW} }, 4226480e2a2SEric Piel { KE_WIFI, 0x30 }, 4236480e2a2SEric Piel { KE_END, FE_MAIL_LED | FE_UNTESTED } 4246480e2a2SEric Piel }; 4256480e2a2SEric Piel 4266480e2a2SEric Piel /* unusual map */ 42755d29c98SEric Piel static struct key_entry keymap_acer_travelmate_220[] __initdata = { 4286480e2a2SEric Piel { KE_KEY, 0x01, {KEY_HELP} }, 4296480e2a2SEric Piel { KE_KEY, 0x02, {KEY_CONFIG} }, 4306480e2a2SEric Piel { KE_KEY, 0x11, {KEY_MAIL} }, 4316480e2a2SEric Piel { KE_KEY, 0x12, {KEY_WWW} }, 4326480e2a2SEric Piel { KE_KEY, 0x13, {KEY_PROG2} }, 4336480e2a2SEric Piel { KE_KEY, 0x31, {KEY_PROG1} }, 4346480e2a2SEric Piel { KE_END, FE_WIFI_LED | FE_UNTESTED } 4356480e2a2SEric Piel }; 4366480e2a2SEric Piel 43755d29c98SEric Piel static struct key_entry keymap_acer_travelmate_230[] __initdata = { 4386480e2a2SEric Piel { KE_KEY, 0x01, {KEY_HELP} }, 4396480e2a2SEric Piel { KE_KEY, 0x02, {KEY_CONFIG} }, 4406480e2a2SEric Piel { KE_KEY, 0x11, {KEY_PROG1} }, 4416480e2a2SEric Piel { KE_KEY, 0x12, {KEY_PROG2} }, 4426480e2a2SEric Piel { KE_KEY, 0x31, {KEY_MAIL} }, 4436480e2a2SEric Piel { KE_KEY, 0x36, {KEY_WWW} }, 4446480e2a2SEric Piel { KE_END, FE_WIFI_LED | FE_UNTESTED } 44584b256a6SBernhard Rosenkraenzer }; 44684b256a6SBernhard Rosenkraenzer 44755d29c98SEric Piel static struct key_entry keymap_acer_travelmate_240[] __initdata = { 4486480e2a2SEric Piel { KE_KEY, 0x01, {KEY_HELP} }, 4496480e2a2SEric Piel { KE_KEY, 0x02, {KEY_CONFIG} }, 4506480e2a2SEric Piel { KE_KEY, 0x03, {KEY_POWER} }, 4516480e2a2SEric Piel { KE_KEY, 0x08, {KEY_MUTE} }, 4526480e2a2SEric Piel { KE_KEY, 0x31, {KEY_MAIL} }, 4536480e2a2SEric Piel { KE_KEY, 0x36, {KEY_WWW} }, 4546480e2a2SEric Piel { KE_KEY, 0x11, {KEY_PROG1} }, 4556480e2a2SEric Piel { KE_KEY, 0x12, {KEY_PROG2} }, 4566480e2a2SEric Piel { KE_BLUETOOTH, 0x44 }, 4576480e2a2SEric Piel { KE_WIFI, 0x30 }, 4586480e2a2SEric Piel { KE_END, FE_UNTESTED } 4596480e2a2SEric Piel }; 4606480e2a2SEric Piel 46155d29c98SEric Piel static struct key_entry keymap_acer_travelmate_350[] __initdata = { 4626480e2a2SEric Piel { KE_KEY, 0x01, {KEY_HELP} }, 4636480e2a2SEric Piel { KE_KEY, 0x02, {KEY_CONFIG} }, 4646480e2a2SEric Piel { KE_KEY, 0x11, {KEY_PROG1} }, 4656480e2a2SEric Piel { KE_KEY, 0x12, {KEY_PROG2} }, 4666480e2a2SEric Piel { KE_KEY, 0x13, {KEY_MAIL} }, 4676480e2a2SEric Piel { KE_KEY, 0x14, {KEY_PROG3} }, 4686480e2a2SEric Piel { KE_KEY, 0x15, {KEY_WWW} }, 4696480e2a2SEric Piel { KE_END, FE_MAIL_LED | FE_WIFI_LED | FE_UNTESTED } 4706480e2a2SEric Piel }; 4716480e2a2SEric Piel 47255d29c98SEric Piel static struct key_entry keymap_acer_travelmate_360[] __initdata = { 4736480e2a2SEric Piel { KE_KEY, 0x01, {KEY_HELP} }, 4746480e2a2SEric Piel { KE_KEY, 0x02, {KEY_CONFIG} }, 4756480e2a2SEric Piel { KE_KEY, 0x11, {KEY_PROG1} }, 4766480e2a2SEric Piel { KE_KEY, 0x12, {KEY_PROG2} }, 4776480e2a2SEric Piel { KE_KEY, 0x13, {KEY_MAIL} }, 4786480e2a2SEric Piel { KE_KEY, 0x14, {KEY_PROG3} }, 4796480e2a2SEric Piel { KE_KEY, 0x15, {KEY_WWW} }, 4806480e2a2SEric Piel { KE_KEY, 0x40, {KEY_WLAN} }, 4816480e2a2SEric Piel { KE_END, FE_WIFI_LED | FE_UNTESTED } /* no mail led */ 48274a89c96SAshutosh Naik }; 48374a89c96SAshutosh Naik 484bc413c95SEric Piel /* Wifi subsystem only activates the led. Therefore we need to pass 485bc413c95SEric Piel * wifi event as a normal key, then userspace can really change the wifi state. 486bc413c95SEric Piel * TODO we need to export led state to userspace (wifi and mail) */ 48755d29c98SEric Piel static struct key_entry keymap_acer_travelmate_610[] __initdata = { 4886480e2a2SEric Piel { KE_KEY, 0x01, {KEY_HELP} }, 4896480e2a2SEric Piel { KE_KEY, 0x02, {KEY_CONFIG} }, 4906480e2a2SEric Piel { KE_KEY, 0x11, {KEY_PROG1} }, 491fd013ce8SEric Piel { KE_KEY, 0x12, {KEY_PROG2} }, 4926480e2a2SEric Piel { KE_KEY, 0x13, {KEY_PROG3} }, 4936480e2a2SEric Piel { KE_KEY, 0x14, {KEY_MAIL} }, 4946480e2a2SEric Piel { KE_KEY, 0x15, {KEY_WWW} }, 4956480e2a2SEric Piel { KE_KEY, 0x40, {KEY_WLAN} }, 4966480e2a2SEric Piel { KE_END, FE_MAIL_LED | FE_WIFI_LED } 4976480e2a2SEric Piel }; 4986480e2a2SEric Piel 49955d29c98SEric Piel static struct key_entry keymap_acer_travelmate_630[] __initdata = { 5006480e2a2SEric Piel { KE_KEY, 0x01, {KEY_HELP} }, 5016480e2a2SEric Piel { KE_KEY, 0x02, {KEY_CONFIG} }, 5026480e2a2SEric Piel { KE_KEY, 0x03, {KEY_POWER} }, 5036480e2a2SEric Piel { KE_KEY, 0x08, {KEY_MUTE} }, /* not 620 */ 5046480e2a2SEric Piel { KE_KEY, 0x11, {KEY_PROG1} }, 5056480e2a2SEric Piel { KE_KEY, 0x12, {KEY_PROG2} }, 5066480e2a2SEric Piel { KE_KEY, 0x13, {KEY_PROG3} }, 5076480e2a2SEric Piel { KE_KEY, 0x20, {KEY_VOLUMEUP} }, 5086480e2a2SEric Piel { KE_KEY, 0x21, {KEY_VOLUMEDOWN} }, 5096480e2a2SEric Piel { KE_KEY, 0x31, {KEY_MAIL} }, 5106480e2a2SEric Piel { KE_KEY, 0x36, {KEY_WWW} }, 5116480e2a2SEric Piel { KE_WIFI, 0x30 }, 5126480e2a2SEric Piel { KE_END, FE_MAIL_LED | FE_UNTESTED } 513bc413c95SEric Piel }; 514bc413c95SEric Piel 51555d29c98SEric Piel static struct key_entry keymap_aopen_1559as[] __initdata = { 5166480e2a2SEric Piel { KE_KEY, 0x01, {KEY_HELP} }, 5176480e2a2SEric Piel { KE_KEY, 0x06, {KEY_PROG3} }, 5186480e2a2SEric Piel { KE_KEY, 0x11, {KEY_PROG1} }, 5196480e2a2SEric Piel { KE_KEY, 0x12, {KEY_PROG2} }, 5206480e2a2SEric Piel { KE_WIFI, 0x30 }, 5216480e2a2SEric Piel { KE_KEY, 0x31, {KEY_MAIL} }, 5226480e2a2SEric Piel { KE_KEY, 0x36, {KEY_WWW} }, 5239000195bSFrank de Lange { KE_END, 0 }, 524e107b8eeSmasc@theaterzentrum.at }; 525e107b8eeSmasc@theaterzentrum.at 52655d29c98SEric Piel static struct key_entry keymap_fs_amilo_d88x0[] __initdata = { 5276480e2a2SEric Piel { KE_KEY, 0x01, {KEY_HELP} }, 5286480e2a2SEric Piel { KE_KEY, 0x08, {KEY_MUTE} }, 5296480e2a2SEric Piel { KE_KEY, 0x31, {KEY_MAIL} }, 5306480e2a2SEric Piel { KE_KEY, 0x36, {KEY_WWW} }, 5316480e2a2SEric Piel { KE_KEY, 0x11, {KEY_PROG1} }, 5326480e2a2SEric Piel { KE_KEY, 0x12, {KEY_PROG2} }, 5336480e2a2SEric Piel { KE_KEY, 0x13, {KEY_PROG3} }, 5346480e2a2SEric Piel { KE_END, FE_MAIL_LED | FE_WIFI_LED | FE_UNTESTED } 5356480e2a2SEric Piel }; 5366480e2a2SEric Piel 53755d29c98SEric Piel static struct key_entry keymap_wistron_md2900[] __initdata = { 5386480e2a2SEric Piel { KE_KEY, 0x01, {KEY_HELP} }, 5396480e2a2SEric Piel { KE_KEY, 0x02, {KEY_CONFIG} }, 5406480e2a2SEric Piel { KE_KEY, 0x11, {KEY_PROG1} }, 5416480e2a2SEric Piel { KE_KEY, 0x12, {KEY_PROG2} }, 5426480e2a2SEric Piel { KE_KEY, 0x31, {KEY_MAIL} }, 5436480e2a2SEric Piel { KE_KEY, 0x36, {KEY_WWW} }, 5446480e2a2SEric Piel { KE_WIFI, 0x30 }, 5456480e2a2SEric Piel { KE_END, FE_MAIL_LED | FE_UNTESTED } 5466480e2a2SEric Piel }; 5476480e2a2SEric Piel 54855d29c98SEric Piel static struct key_entry keymap_wistron_md96500[] __initdata = { 5496480e2a2SEric Piel { KE_KEY, 0x01, {KEY_HELP} }, 5506480e2a2SEric Piel { KE_KEY, 0x02, {KEY_CONFIG} }, 5516480e2a2SEric Piel { KE_KEY, 0x05, {KEY_SWITCHVIDEOMODE} }, /* Display selection */ 5526480e2a2SEric Piel { KE_KEY, 0x06, {KEY_DISPLAYTOGGLE} }, /* Display on/off */ 5536480e2a2SEric Piel { KE_KEY, 0x08, {KEY_MUTE} }, 5546480e2a2SEric Piel { KE_KEY, 0x11, {KEY_PROG1} }, 5556480e2a2SEric Piel { KE_KEY, 0x12, {KEY_PROG2} }, 5566480e2a2SEric Piel { KE_KEY, 0x20, {KEY_VOLUMEUP} }, 5576480e2a2SEric Piel { KE_KEY, 0x21, {KEY_VOLUMEDOWN} }, 5586480e2a2SEric Piel { KE_KEY, 0x22, {KEY_REWIND} }, 5596480e2a2SEric Piel { KE_KEY, 0x23, {KEY_FORWARD} }, 5606480e2a2SEric Piel { KE_KEY, 0x24, {KEY_PLAYPAUSE} }, 5616480e2a2SEric Piel { KE_KEY, 0x25, {KEY_STOPCD} }, 5626480e2a2SEric Piel { KE_KEY, 0x31, {KEY_MAIL} }, 5636480e2a2SEric Piel { KE_KEY, 0x36, {KEY_WWW} }, 5646480e2a2SEric Piel { KE_WIFI, 0x30 }, 5656480e2a2SEric Piel { KE_BLUETOOTH, 0x44 }, 5666480e2a2SEric Piel { KE_END, FE_UNTESTED } 5675809d537SMichael Leun }; 5685809d537SMichael Leun 56955d29c98SEric Piel static struct key_entry keymap_wistron_generic[] __initdata = { 5707b0a4cd7SEric Piel { KE_KEY, 0x01, {KEY_HELP} }, 5717b0a4cd7SEric Piel { KE_KEY, 0x02, {KEY_CONFIG} }, 5727b0a4cd7SEric Piel { KE_KEY, 0x03, {KEY_POWER} }, 5737b0a4cd7SEric Piel { KE_KEY, 0x05, {KEY_SWITCHVIDEOMODE} }, /* Display selection */ 5747b0a4cd7SEric Piel { KE_KEY, 0x06, {KEY_DISPLAYTOGGLE} }, /* Display on/off */ 5757b0a4cd7SEric Piel { KE_KEY, 0x08, {KEY_MUTE} }, 5767b0a4cd7SEric Piel { KE_KEY, 0x11, {KEY_PROG1} }, 5777b0a4cd7SEric Piel { KE_KEY, 0x12, {KEY_PROG2} }, 5787b0a4cd7SEric Piel { KE_KEY, 0x13, {KEY_PROG3} }, 5797b0a4cd7SEric Piel { KE_KEY, 0x14, {KEY_MAIL} }, 5807b0a4cd7SEric Piel { KE_KEY, 0x15, {KEY_WWW} }, 5817b0a4cd7SEric Piel { KE_KEY, 0x20, {KEY_VOLUMEUP} }, 5827b0a4cd7SEric Piel { KE_KEY, 0x21, {KEY_VOLUMEDOWN} }, 5837b0a4cd7SEric Piel { KE_KEY, 0x22, {KEY_REWIND} }, 5847b0a4cd7SEric Piel { KE_KEY, 0x23, {KEY_FORWARD} }, 5857b0a4cd7SEric Piel { KE_KEY, 0x24, {KEY_PLAYPAUSE} }, 5867b0a4cd7SEric Piel { KE_KEY, 0x25, {KEY_STOPCD} }, 5877b0a4cd7SEric Piel { KE_KEY, 0x31, {KEY_MAIL} }, 5887b0a4cd7SEric Piel { KE_KEY, 0x36, {KEY_WWW} }, 5897b0a4cd7SEric Piel { KE_KEY, 0x37, {KEY_DISPLAYTOGGLE} }, /* Display on/off */ 5907b0a4cd7SEric Piel { KE_KEY, 0x40, {KEY_WLAN} }, 5917b0a4cd7SEric Piel { KE_KEY, 0x49, {KEY_CONFIG} }, 5927b0a4cd7SEric Piel { KE_SW, 0x4a, {.sw = {SW_LID, 1}} }, /* lid close */ 5937b0a4cd7SEric Piel { KE_SW, 0x4b, {.sw = {SW_LID, 0}} }, /* lid open */ 5947b0a4cd7SEric Piel { KE_KEY, 0x6a, {KEY_CONFIG} }, 5957b0a4cd7SEric Piel { KE_KEY, 0x6d, {KEY_POWER} }, 5967b0a4cd7SEric Piel { KE_KEY, 0x71, {KEY_STOPCD} }, 5977b0a4cd7SEric Piel { KE_KEY, 0x72, {KEY_PLAYPAUSE} }, 5987b0a4cd7SEric Piel { KE_KEY, 0x74, {KEY_REWIND} }, 5997b0a4cd7SEric Piel { KE_KEY, 0x78, {KEY_FORWARD} }, 6007b0a4cd7SEric Piel { KE_WIFI, 0x30 }, 6017b0a4cd7SEric Piel { KE_BLUETOOTH, 0x44 }, 6027b0a4cd7SEric Piel { KE_END, 0 } 6037b0a4cd7SEric Piel }; 6047b0a4cd7SEric Piel 60585927b0dSDmitry Torokhov static struct key_entry keymap_aopen_1557[] __initdata = { 60685927b0dSDmitry Torokhov { KE_KEY, 0x01, {KEY_HELP} }, 60785927b0dSDmitry Torokhov { KE_KEY, 0x11, {KEY_PROG1} }, 60885927b0dSDmitry Torokhov { KE_KEY, 0x12, {KEY_PROG2} }, 60985927b0dSDmitry Torokhov { KE_WIFI, 0x30 }, 61085927b0dSDmitry Torokhov { KE_KEY, 0x22, {KEY_REWIND} }, 61185927b0dSDmitry Torokhov { KE_KEY, 0x23, {KEY_FORWARD} }, 61285927b0dSDmitry Torokhov { KE_KEY, 0x24, {KEY_PLAYPAUSE} }, 61385927b0dSDmitry Torokhov { KE_KEY, 0x25, {KEY_STOPCD} }, 61485927b0dSDmitry Torokhov { KE_KEY, 0x31, {KEY_MAIL} }, 61585927b0dSDmitry Torokhov { KE_KEY, 0x36, {KEY_WWW} }, 61685927b0dSDmitry Torokhov { KE_END, 0 } 61785927b0dSDmitry Torokhov }; 61885927b0dSDmitry Torokhov 61919493478STJ static struct key_entry keymap_prestigio[] __initdata = { 62019493478STJ { KE_KEY, 0x11, {KEY_PROG1} }, 62119493478STJ { KE_KEY, 0x12, {KEY_PROG2} }, 62219493478STJ { KE_WIFI, 0x30 }, 62319493478STJ { KE_KEY, 0x22, {KEY_REWIND} }, 62419493478STJ { KE_KEY, 0x23, {KEY_FORWARD} }, 62519493478STJ { KE_KEY, 0x24, {KEY_PLAYPAUSE} }, 62619493478STJ { KE_KEY, 0x25, {KEY_STOPCD} }, 62719493478STJ { KE_KEY, 0x31, {KEY_MAIL} }, 62819493478STJ { KE_KEY, 0x36, {KEY_WWW} }, 62919493478STJ { KE_END, 0 } 63019493478STJ }; 63119493478STJ 63219493478STJ 6335fc14680SDmitry Torokhov /* 6345fc14680SDmitry Torokhov * If your machine is not here (which is currently rather likely), please send 6355fc14680SDmitry Torokhov * a list of buttons and their key codes (reported when loading this module 6365fc14680SDmitry Torokhov * with force=1) and the output of dmidecode to $MODULE_AUTHOR. 6375fc14680SDmitry Torokhov */ 638a9b0d0e5SDmitry Torokhov static const struct dmi_system_id __initconst dmi_ids[] = { 6395fc14680SDmitry Torokhov { 640a9b0d0e5SDmitry Torokhov /* Fujitsu-Siemens Amilo Pro V2000 */ 6415fc14680SDmitry Torokhov .callback = dmi_matched, 6425fc14680SDmitry Torokhov .matches = { 6435fc14680SDmitry Torokhov DMI_MATCH(DMI_SYS_VENDOR, "FUJITSU SIEMENS"), 6445fc14680SDmitry Torokhov DMI_MATCH(DMI_PRODUCT_NAME, "AMILO Pro V2000"), 6455fc14680SDmitry Torokhov }, 6465fc14680SDmitry Torokhov .driver_data = keymap_fs_amilo_pro_v2000 6475fc14680SDmitry Torokhov }, 64884b256a6SBernhard Rosenkraenzer { 649a9b0d0e5SDmitry Torokhov /* Fujitsu-Siemens Amilo Pro Edition V3505 */ 65084b256a6SBernhard Rosenkraenzer .callback = dmi_matched, 65134a7c48cSRemi Herilier .matches = { 65234a7c48cSRemi Herilier DMI_MATCH(DMI_SYS_VENDOR, "FUJITSU SIEMENS"), 65334a7c48cSRemi Herilier DMI_MATCH(DMI_PRODUCT_NAME, "AMILO Pro Edition V3505"), 65434a7c48cSRemi Herilier }, 65534a7c48cSRemi Herilier .driver_data = keymap_fs_amilo_pro_v3505 65634a7c48cSRemi Herilier }, 65734a7c48cSRemi Herilier { 658a9b0d0e5SDmitry Torokhov /* Fujitsu-Siemens Amilo M7400 */ 65934a7c48cSRemi Herilier .callback = dmi_matched, 6608a1b1708SStefan Rompf .matches = { 6618a1b1708SStefan Rompf DMI_MATCH(DMI_SYS_VENDOR, "FUJITSU SIEMENS"), 6628a1b1708SStefan Rompf DMI_MATCH(DMI_PRODUCT_NAME, "AMILO M "), 6638a1b1708SStefan Rompf }, 6648a1b1708SStefan Rompf .driver_data = keymap_fs_amilo_pro_v2000 6658a1b1708SStefan Rompf }, 6668a1b1708SStefan Rompf { 667a9b0d0e5SDmitry Torokhov /* Maxdata Pro 7000 DX */ 6688a1b1708SStefan Rompf .callback = dmi_matched, 669e705cee4SGiuseppe Mazzotta .matches = { 670e705cee4SGiuseppe Mazzotta DMI_MATCH(DMI_SYS_VENDOR, "MAXDATA"), 671e705cee4SGiuseppe Mazzotta DMI_MATCH(DMI_PRODUCT_NAME, "Pro 7000"), 672e705cee4SGiuseppe Mazzotta }, 673e705cee4SGiuseppe Mazzotta .driver_data = keymap_fs_amilo_pro_v2000 674e705cee4SGiuseppe Mazzotta }, 675e705cee4SGiuseppe Mazzotta { 676a9b0d0e5SDmitry Torokhov /* Fujitsu N3510 */ 677e705cee4SGiuseppe Mazzotta .callback = dmi_matched, 678e2aa507aSJohn Reed Riley .matches = { 679e2aa507aSJohn Reed Riley DMI_MATCH(DMI_SYS_VENDOR, "FUJITSU"), 680e2aa507aSJohn Reed Riley DMI_MATCH(DMI_PRODUCT_NAME, "N3510"), 681e2aa507aSJohn Reed Riley }, 682e2aa507aSJohn Reed Riley .driver_data = keymap_fujitsu_n3510 683e2aa507aSJohn Reed Riley }, 684e2aa507aSJohn Reed Riley { 685a9b0d0e5SDmitry Torokhov /* Acer Aspire 1500 */ 686e2aa507aSJohn Reed Riley .callback = dmi_matched, 68784b256a6SBernhard Rosenkraenzer .matches = { 68884b256a6SBernhard Rosenkraenzer DMI_MATCH(DMI_SYS_VENDOR, "Acer"), 68984b256a6SBernhard Rosenkraenzer DMI_MATCH(DMI_PRODUCT_NAME, "Aspire 1500"), 69084b256a6SBernhard Rosenkraenzer }, 69184b256a6SBernhard Rosenkraenzer .driver_data = keymap_acer_aspire_1500 69284b256a6SBernhard Rosenkraenzer }, 69374a89c96SAshutosh Naik { 694a9b0d0e5SDmitry Torokhov /* Acer Aspire 1600 */ 69574a89c96SAshutosh Naik .callback = dmi_matched, 6966480e2a2SEric Piel .matches = { 6976480e2a2SEric Piel DMI_MATCH(DMI_SYS_VENDOR, "Acer"), 6986480e2a2SEric Piel DMI_MATCH(DMI_PRODUCT_NAME, "Aspire 1600"), 6996480e2a2SEric Piel }, 7006480e2a2SEric Piel .driver_data = keymap_acer_aspire_1600 7016480e2a2SEric Piel }, 7026480e2a2SEric Piel { 703a9b0d0e5SDmitry Torokhov /* Acer Aspire 3020 */ 7046480e2a2SEric Piel .callback = dmi_matched, 7056480e2a2SEric Piel .matches = { 7066480e2a2SEric Piel DMI_MATCH(DMI_SYS_VENDOR, "Acer"), 7076480e2a2SEric Piel DMI_MATCH(DMI_PRODUCT_NAME, "Aspire 3020"), 7086480e2a2SEric Piel }, 7096480e2a2SEric Piel .driver_data = keymap_acer_aspire_5020 7106480e2a2SEric Piel }, 7116480e2a2SEric Piel { 712a9b0d0e5SDmitry Torokhov /* Acer Aspire 5020 */ 7136480e2a2SEric Piel .callback = dmi_matched, 7146480e2a2SEric Piel .matches = { 7156480e2a2SEric Piel DMI_MATCH(DMI_SYS_VENDOR, "Acer"), 7166480e2a2SEric Piel DMI_MATCH(DMI_PRODUCT_NAME, "Aspire 5020"), 7176480e2a2SEric Piel }, 7186480e2a2SEric Piel .driver_data = keymap_acer_aspire_5020 7196480e2a2SEric Piel }, 7206480e2a2SEric Piel { 721a9b0d0e5SDmitry Torokhov /* Acer TravelMate 2100 */ 7226480e2a2SEric Piel .callback = dmi_matched, 7236480e2a2SEric Piel .matches = { 7246480e2a2SEric Piel DMI_MATCH(DMI_SYS_VENDOR, "Acer"), 7256480e2a2SEric Piel DMI_MATCH(DMI_PRODUCT_NAME, "TravelMate 2100"), 7266480e2a2SEric Piel }, 7276480e2a2SEric Piel .driver_data = keymap_acer_aspire_5020 7286480e2a2SEric Piel }, 7296480e2a2SEric Piel { 730a9b0d0e5SDmitry Torokhov /* Acer TravelMate 2410 */ 7316480e2a2SEric Piel .callback = dmi_matched, 7326480e2a2SEric Piel .matches = { 7336480e2a2SEric Piel DMI_MATCH(DMI_SYS_VENDOR, "Acer"), 7346480e2a2SEric Piel DMI_MATCH(DMI_PRODUCT_NAME, "TravelMate 2410"), 7356480e2a2SEric Piel }, 7366480e2a2SEric Piel .driver_data = keymap_acer_travelmate_2410 7376480e2a2SEric Piel }, 7386480e2a2SEric Piel { 739a9b0d0e5SDmitry Torokhov /* Acer TravelMate C300 */ 7406480e2a2SEric Piel .callback = dmi_matched, 7416480e2a2SEric Piel .matches = { 7426480e2a2SEric Piel DMI_MATCH(DMI_SYS_VENDOR, "Acer"), 7436480e2a2SEric Piel DMI_MATCH(DMI_PRODUCT_NAME, "TravelMate C300"), 7446480e2a2SEric Piel }, 7456480e2a2SEric Piel .driver_data = keymap_acer_travelmate_300 7466480e2a2SEric Piel }, 7476480e2a2SEric Piel { 748a9b0d0e5SDmitry Torokhov /* Acer TravelMate C100 */ 7496480e2a2SEric Piel .callback = dmi_matched, 7506480e2a2SEric Piel .matches = { 7516480e2a2SEric Piel DMI_MATCH(DMI_SYS_VENDOR, "Acer"), 7526480e2a2SEric Piel DMI_MATCH(DMI_PRODUCT_NAME, "TravelMate C100"), 7536480e2a2SEric Piel }, 7546480e2a2SEric Piel .driver_data = keymap_acer_travelmate_300 7556480e2a2SEric Piel }, 7566480e2a2SEric Piel { 757a9b0d0e5SDmitry Torokhov /* Acer TravelMate C110 */ 7586480e2a2SEric Piel .callback = dmi_matched, 7596480e2a2SEric Piel .matches = { 7606480e2a2SEric Piel DMI_MATCH(DMI_SYS_VENDOR, "Acer"), 7616480e2a2SEric Piel DMI_MATCH(DMI_PRODUCT_NAME, "TravelMate C110"), 7626480e2a2SEric Piel }, 7636480e2a2SEric Piel .driver_data = keymap_acer_travelmate_110 7646480e2a2SEric Piel }, 7656480e2a2SEric Piel { 766a9b0d0e5SDmitry Torokhov /* Acer TravelMate 380 */ 7676480e2a2SEric Piel .callback = dmi_matched, 7686480e2a2SEric Piel .matches = { 7696480e2a2SEric Piel DMI_MATCH(DMI_SYS_VENDOR, "Acer"), 7706480e2a2SEric Piel DMI_MATCH(DMI_PRODUCT_NAME, "TravelMate 380"), 7716480e2a2SEric Piel }, 7726480e2a2SEric Piel .driver_data = keymap_acer_travelmate_380 7736480e2a2SEric Piel }, 7746480e2a2SEric Piel { 775a9b0d0e5SDmitry Torokhov /* Acer TravelMate 370 */ 7766480e2a2SEric Piel .callback = dmi_matched, 7776480e2a2SEric Piel .matches = { 7786480e2a2SEric Piel DMI_MATCH(DMI_SYS_VENDOR, "Acer"), 7796480e2a2SEric Piel DMI_MATCH(DMI_PRODUCT_NAME, "TravelMate 370"), 7806480e2a2SEric Piel }, 7816480e2a2SEric Piel .driver_data = keymap_acer_travelmate_380 /* keyboard minus 1 key */ 7826480e2a2SEric Piel }, 7836480e2a2SEric Piel { 784a9b0d0e5SDmitry Torokhov /* Acer TravelMate 220 */ 7856480e2a2SEric Piel .callback = dmi_matched, 7866480e2a2SEric Piel .matches = { 7876480e2a2SEric Piel DMI_MATCH(DMI_SYS_VENDOR, "Acer"), 7886480e2a2SEric Piel DMI_MATCH(DMI_PRODUCT_NAME, "TravelMate 220"), 7896480e2a2SEric Piel }, 7906480e2a2SEric Piel .driver_data = keymap_acer_travelmate_220 7916480e2a2SEric Piel }, 7926480e2a2SEric Piel { 793a9b0d0e5SDmitry Torokhov /* Acer TravelMate 260 */ 7946480e2a2SEric Piel .callback = dmi_matched, 7956480e2a2SEric Piel .matches = { 7966480e2a2SEric Piel DMI_MATCH(DMI_SYS_VENDOR, "Acer"), 7976480e2a2SEric Piel DMI_MATCH(DMI_PRODUCT_NAME, "TravelMate 260"), 7986480e2a2SEric Piel }, 7996480e2a2SEric Piel .driver_data = keymap_acer_travelmate_220 8006480e2a2SEric Piel }, 8016480e2a2SEric Piel { 802a9b0d0e5SDmitry Torokhov /* Acer TravelMate 230 */ 8036480e2a2SEric Piel .callback = dmi_matched, 8046480e2a2SEric Piel .matches = { 8056480e2a2SEric Piel DMI_MATCH(DMI_SYS_VENDOR, "Acer"), 8066480e2a2SEric Piel DMI_MATCH(DMI_PRODUCT_NAME, "TravelMate 230"), 8076480e2a2SEric Piel /* acerhk looks for "TravelMate F4..." ?! */ 8086480e2a2SEric Piel }, 8096480e2a2SEric Piel .driver_data = keymap_acer_travelmate_230 8106480e2a2SEric Piel }, 8116480e2a2SEric Piel { 812a9b0d0e5SDmitry Torokhov /* Acer TravelMate 280 */ 8136480e2a2SEric Piel .callback = dmi_matched, 8146480e2a2SEric Piel .matches = { 8156480e2a2SEric Piel DMI_MATCH(DMI_SYS_VENDOR, "Acer"), 8166480e2a2SEric Piel DMI_MATCH(DMI_PRODUCT_NAME, "TravelMate 280"), 8176480e2a2SEric Piel }, 8186480e2a2SEric Piel .driver_data = keymap_acer_travelmate_230 8196480e2a2SEric Piel }, 8206480e2a2SEric Piel { 821a9b0d0e5SDmitry Torokhov /* Acer TravelMate 240 */ 8226480e2a2SEric Piel .callback = dmi_matched, 82374a89c96SAshutosh Naik .matches = { 82474a89c96SAshutosh Naik DMI_MATCH(DMI_SYS_VENDOR, "Acer"), 82574a89c96SAshutosh Naik DMI_MATCH(DMI_PRODUCT_NAME, "TravelMate 240"), 82674a89c96SAshutosh Naik }, 82774a89c96SAshutosh Naik .driver_data = keymap_acer_travelmate_240 82874a89c96SAshutosh Naik }, 829e107b8eeSmasc@theaterzentrum.at { 830a9b0d0e5SDmitry Torokhov /* Acer TravelMate 250 */ 831bb088590SAshutosh Naik .callback = dmi_matched, 8326480e2a2SEric Piel .matches = { 8336480e2a2SEric Piel DMI_MATCH(DMI_SYS_VENDOR, "Acer"), 8346480e2a2SEric Piel DMI_MATCH(DMI_PRODUCT_NAME, "TravelMate 250"), 8356480e2a2SEric Piel }, 8366480e2a2SEric Piel .driver_data = keymap_acer_travelmate_240 8376480e2a2SEric Piel }, 8386480e2a2SEric Piel { 839a9b0d0e5SDmitry Torokhov /* Acer TravelMate 2424NWXCi */ 8406480e2a2SEric Piel .callback = dmi_matched, 841bb088590SAshutosh Naik .matches = { 842bb088590SAshutosh Naik DMI_MATCH(DMI_SYS_VENDOR, "Acer"), 843bb088590SAshutosh Naik DMI_MATCH(DMI_PRODUCT_NAME, "TravelMate 2420"), 844bb088590SAshutosh Naik }, 845bb088590SAshutosh Naik .driver_data = keymap_acer_travelmate_240 846bb088590SAshutosh Naik }, 847bb088590SAshutosh Naik { 848a9b0d0e5SDmitry Torokhov /* Acer TravelMate 350 */ 849e107b8eeSmasc@theaterzentrum.at .callback = dmi_matched, 8506480e2a2SEric Piel .matches = { 8516480e2a2SEric Piel DMI_MATCH(DMI_SYS_VENDOR, "Acer"), 8526480e2a2SEric Piel DMI_MATCH(DMI_PRODUCT_NAME, "TravelMate 350"), 8536480e2a2SEric Piel }, 8546480e2a2SEric Piel .driver_data = keymap_acer_travelmate_350 8556480e2a2SEric Piel }, 8566480e2a2SEric Piel { 857a9b0d0e5SDmitry Torokhov /* Acer TravelMate 360 */ 8586480e2a2SEric Piel .callback = dmi_matched, 8596480e2a2SEric Piel .matches = { 8606480e2a2SEric Piel DMI_MATCH(DMI_SYS_VENDOR, "Acer"), 8616480e2a2SEric Piel DMI_MATCH(DMI_PRODUCT_NAME, "TravelMate 360"), 8626480e2a2SEric Piel }, 8636480e2a2SEric Piel .driver_data = keymap_acer_travelmate_360 8646480e2a2SEric Piel }, 8656480e2a2SEric Piel { 866a9b0d0e5SDmitry Torokhov /* Acer TravelMate 610 */ 8676480e2a2SEric Piel .callback = dmi_matched, 868bc413c95SEric Piel .matches = { 869bc413c95SEric Piel DMI_MATCH(DMI_SYS_VENDOR, "ACER"), 870bc413c95SEric Piel DMI_MATCH(DMI_PRODUCT_NAME, "TravelMate 610"), 871bc413c95SEric Piel }, 872bc413c95SEric Piel .driver_data = keymap_acer_travelmate_610 873bc413c95SEric Piel }, 874bc413c95SEric Piel { 875a9b0d0e5SDmitry Torokhov /* Acer TravelMate 620 */ 876bc413c95SEric Piel .callback = dmi_matched, 8776480e2a2SEric Piel .matches = { 8786480e2a2SEric Piel DMI_MATCH(DMI_SYS_VENDOR, "Acer"), 8796480e2a2SEric Piel DMI_MATCH(DMI_PRODUCT_NAME, "TravelMate 620"), 8806480e2a2SEric Piel }, 8816480e2a2SEric Piel .driver_data = keymap_acer_travelmate_630 8826480e2a2SEric Piel }, 8836480e2a2SEric Piel { 884a9b0d0e5SDmitry Torokhov /* Acer TravelMate 630 */ 8856480e2a2SEric Piel .callback = dmi_matched, 8866480e2a2SEric Piel .matches = { 8876480e2a2SEric Piel DMI_MATCH(DMI_SYS_VENDOR, "Acer"), 8886480e2a2SEric Piel DMI_MATCH(DMI_PRODUCT_NAME, "TravelMate 630"), 8896480e2a2SEric Piel }, 8906480e2a2SEric Piel .driver_data = keymap_acer_travelmate_630 8916480e2a2SEric Piel }, 8926480e2a2SEric Piel { 893a9b0d0e5SDmitry Torokhov /* AOpen 1559AS */ 8946480e2a2SEric Piel .callback = dmi_matched, 895e107b8eeSmasc@theaterzentrum.at .matches = { 896e107b8eeSmasc@theaterzentrum.at DMI_MATCH(DMI_PRODUCT_NAME, "E2U"), 897e107b8eeSmasc@theaterzentrum.at DMI_MATCH(DMI_BOARD_NAME, "E2U"), 898e107b8eeSmasc@theaterzentrum.at }, 899e107b8eeSmasc@theaterzentrum.at .driver_data = keymap_aopen_1559as 900e107b8eeSmasc@theaterzentrum.at }, 9019000195bSFrank de Lange { 902a9b0d0e5SDmitry Torokhov /* Medion MD 9783 */ 9039000195bSFrank de Lange .callback = dmi_matched, 9049000195bSFrank de Lange .matches = { 9059000195bSFrank de Lange DMI_MATCH(DMI_SYS_VENDOR, "MEDIONNB"), 9069000195bSFrank de Lange DMI_MATCH(DMI_PRODUCT_NAME, "MD 9783"), 9079000195bSFrank de Lange }, 9089000195bSFrank de Lange .driver_data = keymap_wistron_ms2111 9099000195bSFrank de Lange }, 9105809d537SMichael Leun { 911a9b0d0e5SDmitry Torokhov /* Medion MD 40100 */ 9125809d537SMichael Leun .callback = dmi_matched, 9136480e2a2SEric Piel .matches = { 9146480e2a2SEric Piel DMI_MATCH(DMI_SYS_VENDOR, "MEDIONNB"), 9156480e2a2SEric Piel DMI_MATCH(DMI_PRODUCT_NAME, "WID2000"), 9166480e2a2SEric Piel }, 9176480e2a2SEric Piel .driver_data = keymap_wistron_md40100 9186480e2a2SEric Piel }, 9196480e2a2SEric Piel { 920a9b0d0e5SDmitry Torokhov /* Medion MD 2900 */ 9216480e2a2SEric Piel .callback = dmi_matched, 9226480e2a2SEric Piel .matches = { 9236480e2a2SEric Piel DMI_MATCH(DMI_SYS_VENDOR, "MEDIONNB"), 9246480e2a2SEric Piel DMI_MATCH(DMI_PRODUCT_NAME, "WIM 2000"), 9256480e2a2SEric Piel }, 9266480e2a2SEric Piel .driver_data = keymap_wistron_md2900 9276480e2a2SEric Piel }, 9286480e2a2SEric Piel { 929a9b0d0e5SDmitry Torokhov /* Medion MD 42200 */ 9306480e2a2SEric Piel .callback = dmi_matched, 9313bfb0a7eSSebastian Frei .matches = { 9323bfb0a7eSSebastian Frei DMI_MATCH(DMI_SYS_VENDOR, "Medion"), 9333bfb0a7eSSebastian Frei DMI_MATCH(DMI_PRODUCT_NAME, "WIM 2030"), 9343bfb0a7eSSebastian Frei }, 9353bfb0a7eSSebastian Frei .driver_data = keymap_fs_amilo_pro_v2000 9363bfb0a7eSSebastian Frei }, 9373bfb0a7eSSebastian Frei { 938a9b0d0e5SDmitry Torokhov /* Medion MD 96500 */ 9393bfb0a7eSSebastian Frei .callback = dmi_matched, 9406480e2a2SEric Piel .matches = { 9416480e2a2SEric Piel DMI_MATCH(DMI_SYS_VENDOR, "MEDIONPC"), 9426480e2a2SEric Piel DMI_MATCH(DMI_PRODUCT_NAME, "WIM 2040"), 9436480e2a2SEric Piel }, 9446480e2a2SEric Piel .driver_data = keymap_wistron_md96500 9456480e2a2SEric Piel }, 9466480e2a2SEric Piel { 947a9b0d0e5SDmitry Torokhov /* Medion MD 95400 */ 9486480e2a2SEric Piel .callback = dmi_matched, 9496480e2a2SEric Piel .matches = { 9506480e2a2SEric Piel DMI_MATCH(DMI_SYS_VENDOR, "MEDIONPC"), 9516480e2a2SEric Piel DMI_MATCH(DMI_PRODUCT_NAME, "WIM 2050"), 9526480e2a2SEric Piel }, 9536480e2a2SEric Piel .driver_data = keymap_wistron_md96500 9546480e2a2SEric Piel }, 9556480e2a2SEric Piel { 956a9b0d0e5SDmitry Torokhov /* Fujitsu Siemens Amilo D7820 */ 9576480e2a2SEric Piel .callback = dmi_matched, 9586480e2a2SEric Piel .matches = { 9596480e2a2SEric Piel DMI_MATCH(DMI_SYS_VENDOR, "FUJITSU SIEMENS"), /* not sure */ 9606480e2a2SEric Piel DMI_MATCH(DMI_PRODUCT_NAME, "Amilo D"), 9616480e2a2SEric Piel }, 9626480e2a2SEric Piel .driver_data = keymap_fs_amilo_d88x0 9636480e2a2SEric Piel }, 9646480e2a2SEric Piel { 965a9b0d0e5SDmitry Torokhov /* Fujitsu Siemens Amilo D88x0 */ 9666480e2a2SEric Piel .callback = dmi_matched, 9675809d537SMichael Leun .matches = { 9685809d537SMichael Leun DMI_MATCH(DMI_SYS_VENDOR, "FUJITSU SIEMENS"), 9695809d537SMichael Leun DMI_MATCH(DMI_PRODUCT_NAME, "AMILO D"), 9705809d537SMichael Leun }, 9715809d537SMichael Leun .driver_data = keymap_fs_amilo_d88x0 9725809d537SMichael Leun }, 97381f0a91eSAl Viro { NULL, } 9745fc14680SDmitry Torokhov }; 9755fc14680SDmitry Torokhov 97655d29c98SEric Piel /* Copy the good keymap, as the original ones are free'd */ 97755d29c98SEric Piel static int __init copy_keymap(void) 97855d29c98SEric Piel { 97955d29c98SEric Piel const struct key_entry *key; 98055d29c98SEric Piel struct key_entry *new_keymap; 98155d29c98SEric Piel unsigned int length = 1; 98255d29c98SEric Piel 98355d29c98SEric Piel for (key = keymap; key->type != KE_END; key++) 98455d29c98SEric Piel length++; 98555d29c98SEric Piel 986f8300ab8SJulia Lawall new_keymap = kmemdup(keymap, length * sizeof(struct key_entry), 987f8300ab8SJulia Lawall GFP_KERNEL); 98855d29c98SEric Piel if (!new_keymap) 98955d29c98SEric Piel return -ENOMEM; 99055d29c98SEric Piel 99155d29c98SEric Piel keymap = new_keymap; 99255d29c98SEric Piel 99355d29c98SEric Piel return 0; 99455d29c98SEric Piel } 99555d29c98SEric Piel 9965fc14680SDmitry Torokhov static int __init select_keymap(void) 9975fc14680SDmitry Torokhov { 9987b0a4cd7SEric Piel dmi_check_system(dmi_ids); 9995fc14680SDmitry Torokhov if (keymap_name != NULL) { 10005fc14680SDmitry Torokhov if (strcmp (keymap_name, "1557/MS2141") == 0) 10015fc14680SDmitry Torokhov keymap = keymap_wistron_ms2141; 100285927b0dSDmitry Torokhov else if (strcmp (keymap_name, "aopen1557") == 0) 100385927b0dSDmitry Torokhov keymap = keymap_aopen_1557; 100419493478STJ else if (strcmp (keymap_name, "prestigio") == 0) 100519493478STJ keymap = keymap_prestigio; 10067b0a4cd7SEric Piel else if (strcmp (keymap_name, "generic") == 0) 10077b0a4cd7SEric Piel keymap = keymap_wistron_generic; 10085fc14680SDmitry Torokhov else { 10095fc14680SDmitry Torokhov printk(KERN_ERR "wistron_btns: Keymap unknown\n"); 10105fc14680SDmitry Torokhov return -EINVAL; 10115fc14680SDmitry Torokhov } 10125fc14680SDmitry Torokhov } 10135fc14680SDmitry Torokhov if (keymap == NULL) { 10145fc14680SDmitry Torokhov if (!force) { 10155fc14680SDmitry Torokhov printk(KERN_ERR "wistron_btns: System unknown\n"); 10165fc14680SDmitry Torokhov return -ENODEV; 10175fc14680SDmitry Torokhov } 10185fc14680SDmitry Torokhov keymap = keymap_empty; 10195fc14680SDmitry Torokhov } 102055d29c98SEric Piel 102155d29c98SEric Piel return copy_keymap(); 10225fc14680SDmitry Torokhov } 10235fc14680SDmitry Torokhov 10245fc14680SDmitry Torokhov /* Input layer interface */ 10255fc14680SDmitry Torokhov 1026c2554c91SDmitry Torokhov static struct input_polled_dev *wistron_idev; 1027c2554c91SDmitry Torokhov static unsigned long jiffies_last_press; 102867dbe83aSDmitry Torokhov static bool wifi_enabled; 102967dbe83aSDmitry Torokhov static bool bluetooth_enabled; 10305fc14680SDmitry Torokhov 1031389679d8SEric Piel /* led management */ 1032389679d8SEric Piel static void wistron_mail_led_set(struct led_classdev *led_cdev, 1033389679d8SEric Piel enum led_brightness value) 1034389679d8SEric Piel { 1035389679d8SEric Piel bios_set_state(MAIL_LED, (value != LED_OFF) ? 1 : 0); 1036389679d8SEric Piel } 1037389679d8SEric Piel 1038389679d8SEric Piel /* same as setting up wifi card, but for laptops on which the led is managed */ 1039389679d8SEric Piel static void wistron_wifi_led_set(struct led_classdev *led_cdev, 1040389679d8SEric Piel enum led_brightness value) 1041389679d8SEric Piel { 1042389679d8SEric Piel bios_set_state(WIFI, (value != LED_OFF) ? 1 : 0); 1043389679d8SEric Piel } 1044389679d8SEric Piel 1045389679d8SEric Piel static struct led_classdev wistron_mail_led = { 10466c152beeSRichard Purdie .name = "wistron:green:mail", 1047389679d8SEric Piel .brightness_set = wistron_mail_led_set, 1048389679d8SEric Piel }; 1049389679d8SEric Piel 1050389679d8SEric Piel static struct led_classdev wistron_wifi_led = { 10516c152beeSRichard Purdie .name = "wistron:red:wifi", 1052389679d8SEric Piel .brightness_set = wistron_wifi_led_set, 1053389679d8SEric Piel }; 1054389679d8SEric Piel 1055389679d8SEric Piel static void __devinit wistron_led_init(struct device *parent) 1056389679d8SEric Piel { 105767dbe83aSDmitry Torokhov if (leds_present & FE_WIFI_LED) { 1058389679d8SEric Piel u16 wifi = bios_get_default_setting(WIFI); 1059389679d8SEric Piel if (wifi & 1) { 1060389679d8SEric Piel wistron_wifi_led.brightness = (wifi & 2) ? LED_FULL : LED_OFF; 1061389679d8SEric Piel if (led_classdev_register(parent, &wistron_wifi_led)) 106267dbe83aSDmitry Torokhov leds_present &= ~FE_WIFI_LED; 1063389679d8SEric Piel else 1064389679d8SEric Piel bios_set_state(WIFI, wistron_wifi_led.brightness); 1065389679d8SEric Piel 1066389679d8SEric Piel } else 106767dbe83aSDmitry Torokhov leds_present &= ~FE_WIFI_LED; 1068389679d8SEric Piel } 1069389679d8SEric Piel 107067dbe83aSDmitry Torokhov if (leds_present & FE_MAIL_LED) { 1071389679d8SEric Piel /* bios_get_default_setting(MAIL) always retuns 0, so just turn the led off */ 1072389679d8SEric Piel wistron_mail_led.brightness = LED_OFF; 1073389679d8SEric Piel if (led_classdev_register(parent, &wistron_mail_led)) 107467dbe83aSDmitry Torokhov leds_present &= ~FE_MAIL_LED; 1075389679d8SEric Piel else 1076389679d8SEric Piel bios_set_state(MAIL_LED, wistron_mail_led.brightness); 1077389679d8SEric Piel } 1078389679d8SEric Piel } 1079389679d8SEric Piel 1080389679d8SEric Piel static void __devexit wistron_led_remove(void) 1081389679d8SEric Piel { 108267dbe83aSDmitry Torokhov if (leds_present & FE_MAIL_LED) 1083389679d8SEric Piel led_classdev_unregister(&wistron_mail_led); 1084389679d8SEric Piel 108567dbe83aSDmitry Torokhov if (leds_present & FE_WIFI_LED) 1086389679d8SEric Piel led_classdev_unregister(&wistron_wifi_led); 1087389679d8SEric Piel } 1088389679d8SEric Piel 1089389679d8SEric Piel static inline void wistron_led_suspend(void) 1090389679d8SEric Piel { 109167dbe83aSDmitry Torokhov if (leds_present & FE_MAIL_LED) 1092389679d8SEric Piel led_classdev_suspend(&wistron_mail_led); 1093389679d8SEric Piel 109467dbe83aSDmitry Torokhov if (leds_present & FE_WIFI_LED) 1095389679d8SEric Piel led_classdev_suspend(&wistron_wifi_led); 1096389679d8SEric Piel } 1097389679d8SEric Piel 1098389679d8SEric Piel static inline void wistron_led_resume(void) 1099389679d8SEric Piel { 110067dbe83aSDmitry Torokhov if (leds_present & FE_MAIL_LED) 1101389679d8SEric Piel led_classdev_resume(&wistron_mail_led); 1102389679d8SEric Piel 110367dbe83aSDmitry Torokhov if (leds_present & FE_WIFI_LED) 1104389679d8SEric Piel led_classdev_resume(&wistron_wifi_led); 1105389679d8SEric Piel } 1106389679d8SEric Piel 11075fc14680SDmitry Torokhov static void handle_key(u8 code) 11085fc14680SDmitry Torokhov { 1109e97af4cbSDmitry Torokhov const struct key_entry *key = 1110e97af4cbSDmitry Torokhov sparse_keymap_entry_from_scancode(wistron_idev->input, code); 11115fc14680SDmitry Torokhov 1112d63219a1SDmitry Torokhov if (key) { 11135fc14680SDmitry Torokhov switch (key->type) { 11145fc14680SDmitry Torokhov case KE_WIFI: 11155fc14680SDmitry Torokhov if (have_wifi) { 11165fc14680SDmitry Torokhov wifi_enabled = !wifi_enabled; 111784b256a6SBernhard Rosenkraenzer bios_set_state(WIFI, wifi_enabled); 111884b256a6SBernhard Rosenkraenzer } 111984b256a6SBernhard Rosenkraenzer break; 112084b256a6SBernhard Rosenkraenzer 112184b256a6SBernhard Rosenkraenzer case KE_BLUETOOTH: 112284b256a6SBernhard Rosenkraenzer if (have_bluetooth) { 112384b256a6SBernhard Rosenkraenzer bluetooth_enabled = !bluetooth_enabled; 112484b256a6SBernhard Rosenkraenzer bios_set_state(BLUETOOTH, bluetooth_enabled); 11255fc14680SDmitry Torokhov } 11265fc14680SDmitry Torokhov break; 11275fc14680SDmitry Torokhov 11285fc14680SDmitry Torokhov default: 1129e97af4cbSDmitry Torokhov sparse_keymap_report_entry(wistron_idev->input, 1130e97af4cbSDmitry Torokhov key, 1, true); 1131e97af4cbSDmitry Torokhov break; 11325fc14680SDmitry Torokhov } 1133c2554c91SDmitry Torokhov jiffies_last_press = jiffies; 1134d63219a1SDmitry Torokhov } else 1135d63219a1SDmitry Torokhov printk(KERN_NOTICE 1136d63219a1SDmitry Torokhov "wistron_btns: Unknown key code %02X\n", code); 11375fc14680SDmitry Torokhov } 11385fc14680SDmitry Torokhov 1139c2554c91SDmitry Torokhov static void poll_bios(bool discard) 11405fc14680SDmitry Torokhov { 11415fc14680SDmitry Torokhov u8 qlen; 11425fc14680SDmitry Torokhov u16 val; 11435fc14680SDmitry Torokhov 11445fc14680SDmitry Torokhov for (;;) { 11455fc14680SDmitry Torokhov qlen = CMOS_READ(cmos_address); 11465fc14680SDmitry Torokhov if (qlen == 0) 11475fc14680SDmitry Torokhov break; 11485fc14680SDmitry Torokhov val = bios_pop_queue(); 1149c2554c91SDmitry Torokhov if (val != 0 && !discard) 11505fc14680SDmitry Torokhov handle_key((u8)val); 1151a4da16d3SEric Piel } 11525fc14680SDmitry Torokhov } 11535fc14680SDmitry Torokhov 1154c2554c91SDmitry Torokhov static void wistron_flush(struct input_polled_dev *dev) 1155c2554c91SDmitry Torokhov { 1156c2554c91SDmitry Torokhov /* Flush stale event queue */ 1157c2554c91SDmitry Torokhov poll_bios(true); 11585fc14680SDmitry Torokhov } 11595fc14680SDmitry Torokhov 1160c2554c91SDmitry Torokhov static void wistron_poll(struct input_polled_dev *dev) 1161c2554c91SDmitry Torokhov { 1162c2554c91SDmitry Torokhov poll_bios(false); 1163c2554c91SDmitry Torokhov 1164c2554c91SDmitry Torokhov /* Increase poll frequency if user is currently pressing keys (< 2s ago) */ 1165c2554c91SDmitry Torokhov if (time_before(jiffies, jiffies_last_press + 2 * HZ)) 1166c2554c91SDmitry Torokhov dev->poll_interval = POLL_INTERVAL_BURST; 1167c2554c91SDmitry Torokhov else 1168c2554c91SDmitry Torokhov dev->poll_interval = POLL_INTERVAL_DEFAULT; 1169c2554c91SDmitry Torokhov } 1170c2554c91SDmitry Torokhov 1171e97af4cbSDmitry Torokhov static int __devinit wistron_setup_keymap(struct input_dev *dev, 1172e97af4cbSDmitry Torokhov struct key_entry *entry) 1173d63219a1SDmitry Torokhov { 1174e97af4cbSDmitry Torokhov switch (entry->type) { 1175d63219a1SDmitry Torokhov 1176e97af4cbSDmitry Torokhov /* if wifi or bluetooth are not available, create normal keys */ 1177e97af4cbSDmitry Torokhov case KE_WIFI: 1178e97af4cbSDmitry Torokhov if (!have_wifi) { 1179e97af4cbSDmitry Torokhov entry->type = KE_KEY; 1180e97af4cbSDmitry Torokhov entry->keycode = KEY_WLAN; 1181e97af4cbSDmitry Torokhov } 1182e97af4cbSDmitry Torokhov break; 1183e97af4cbSDmitry Torokhov 1184e97af4cbSDmitry Torokhov case KE_BLUETOOTH: 1185e97af4cbSDmitry Torokhov if (!have_bluetooth) { 1186e97af4cbSDmitry Torokhov entry->type = KE_KEY; 1187e97af4cbSDmitry Torokhov entry->keycode = KEY_BLUETOOTH; 1188e97af4cbSDmitry Torokhov } 1189e97af4cbSDmitry Torokhov break; 1190e97af4cbSDmitry Torokhov 1191e97af4cbSDmitry Torokhov case KE_END: 1192e97af4cbSDmitry Torokhov if (entry->code & FE_UNTESTED) 1193e97af4cbSDmitry Torokhov printk(KERN_WARNING "Untested laptop multimedia keys, " 1194e97af4cbSDmitry Torokhov "please report success or failure to " 1195e97af4cbSDmitry Torokhov "eric.piel@tremplin-utc.net\n"); 1196e97af4cbSDmitry Torokhov break; 1197e97af4cbSDmitry Torokhov } 1198e97af4cbSDmitry Torokhov 1199d63219a1SDmitry Torokhov return 0; 1200d63219a1SDmitry Torokhov } 1201d63219a1SDmitry Torokhov 1202c2554c91SDmitry Torokhov static int __devinit setup_input_dev(void) 1203c2554c91SDmitry Torokhov { 1204c2554c91SDmitry Torokhov struct input_dev *input_dev; 1205c2554c91SDmitry Torokhov int error; 1206c2554c91SDmitry Torokhov 1207c2554c91SDmitry Torokhov wistron_idev = input_allocate_polled_device(); 1208c2554c91SDmitry Torokhov if (!wistron_idev) 1209c2554c91SDmitry Torokhov return -ENOMEM; 1210c2554c91SDmitry Torokhov 1211b0aba1e6SSamu Onkalo wistron_idev->open = wistron_flush; 1212c2554c91SDmitry Torokhov wistron_idev->poll = wistron_poll; 1213c2554c91SDmitry Torokhov wistron_idev->poll_interval = POLL_INTERVAL_DEFAULT; 1214c2554c91SDmitry Torokhov 1215c2554c91SDmitry Torokhov input_dev = wistron_idev->input; 1216c2554c91SDmitry Torokhov input_dev->name = "Wistron laptop buttons"; 1217c2554c91SDmitry Torokhov input_dev->phys = "wistron/input0"; 1218c2554c91SDmitry Torokhov input_dev->id.bustype = BUS_HOST; 1219d63219a1SDmitry Torokhov input_dev->dev.parent = &wistron_device->dev; 1220d63219a1SDmitry Torokhov 1221e97af4cbSDmitry Torokhov error = sparse_keymap_setup(input_dev, keymap, wistron_setup_keymap); 1222e97af4cbSDmitry Torokhov if (error) 1223e97af4cbSDmitry Torokhov goto err_free_dev; 1224c2554c91SDmitry Torokhov 1225c2554c91SDmitry Torokhov error = input_register_polled_device(wistron_idev); 1226e97af4cbSDmitry Torokhov if (error) 1227e97af4cbSDmitry Torokhov goto err_free_keymap; 1228c2554c91SDmitry Torokhov 1229c2554c91SDmitry Torokhov return 0; 1230e97af4cbSDmitry Torokhov 1231e97af4cbSDmitry Torokhov err_free_keymap: 1232e97af4cbSDmitry Torokhov sparse_keymap_free(input_dev); 1233e97af4cbSDmitry Torokhov err_free_dev: 1234e97af4cbSDmitry Torokhov input_free_polled_device(wistron_idev); 1235e97af4cbSDmitry Torokhov return error; 1236c2554c91SDmitry Torokhov } 1237c2554c91SDmitry Torokhov 1238c2554c91SDmitry Torokhov /* Driver core */ 1239c2554c91SDmitry Torokhov 1240e7c3aad5SDmitry Torokhov static int __devinit wistron_probe(struct platform_device *dev) 1241e7c3aad5SDmitry Torokhov { 1242c2554c91SDmitry Torokhov int err; 1243e7c3aad5SDmitry Torokhov 1244e7c3aad5SDmitry Torokhov bios_attach(); 1245e7c3aad5SDmitry Torokhov cmos_address = bios_get_cmos_address(); 1246e7c3aad5SDmitry Torokhov 1247e7c3aad5SDmitry Torokhov if (have_wifi) { 1248e7c3aad5SDmitry Torokhov u16 wifi = bios_get_default_setting(WIFI); 1249e7c3aad5SDmitry Torokhov if (wifi & 1) 125067dbe83aSDmitry Torokhov wifi_enabled = wifi & 2; 1251e7c3aad5SDmitry Torokhov else 1252e7c3aad5SDmitry Torokhov have_wifi = 0; 1253e7c3aad5SDmitry Torokhov 1254e7c3aad5SDmitry Torokhov if (have_wifi) 1255e7c3aad5SDmitry Torokhov bios_set_state(WIFI, wifi_enabled); 1256e7c3aad5SDmitry Torokhov } 1257e7c3aad5SDmitry Torokhov 1258e7c3aad5SDmitry Torokhov if (have_bluetooth) { 1259e7c3aad5SDmitry Torokhov u16 bt = bios_get_default_setting(BLUETOOTH); 1260e7c3aad5SDmitry Torokhov if (bt & 1) 126167dbe83aSDmitry Torokhov bluetooth_enabled = bt & 2; 1262e7c3aad5SDmitry Torokhov else 126367dbe83aSDmitry Torokhov have_bluetooth = false; 1264e7c3aad5SDmitry Torokhov 1265e7c3aad5SDmitry Torokhov if (have_bluetooth) 1266e7c3aad5SDmitry Torokhov bios_set_state(BLUETOOTH, bluetooth_enabled); 1267e7c3aad5SDmitry Torokhov } 1268e7c3aad5SDmitry Torokhov 1269389679d8SEric Piel wistron_led_init(&dev->dev); 127067dbe83aSDmitry Torokhov 1271c2554c91SDmitry Torokhov err = setup_input_dev(); 1272c2554c91SDmitry Torokhov if (err) { 1273c2554c91SDmitry Torokhov bios_detach(); 1274c2554c91SDmitry Torokhov return err; 1275c2554c91SDmitry Torokhov } 1276e7c3aad5SDmitry Torokhov 1277e7c3aad5SDmitry Torokhov return 0; 1278e7c3aad5SDmitry Torokhov } 1279e7c3aad5SDmitry Torokhov 1280e7c3aad5SDmitry Torokhov static int __devexit wistron_remove(struct platform_device *dev) 1281e7c3aad5SDmitry Torokhov { 1282389679d8SEric Piel wistron_led_remove(); 1283c2554c91SDmitry Torokhov input_unregister_polled_device(wistron_idev); 1284e97af4cbSDmitry Torokhov sparse_keymap_free(wistron_idev->input); 1285c2554c91SDmitry Torokhov input_free_polled_device(wistron_idev); 1286e7c3aad5SDmitry Torokhov bios_detach(); 1287e7c3aad5SDmitry Torokhov 1288e7c3aad5SDmitry Torokhov return 0; 1289e7c3aad5SDmitry Torokhov } 1290e7c3aad5SDmitry Torokhov 1291e7c3aad5SDmitry Torokhov #ifdef CONFIG_PM 129267dbe83aSDmitry Torokhov static int wistron_suspend(struct device *dev) 1293a5b0cc80SDmitry Torokhov { 1294e753b650SMiloslav Trmac if (have_wifi) 1295e753b650SMiloslav Trmac bios_set_state(WIFI, 0); 1296e753b650SMiloslav Trmac 1297e753b650SMiloslav Trmac if (have_bluetooth) 1298e753b650SMiloslav Trmac bios_set_state(BLUETOOTH, 0); 1299e753b650SMiloslav Trmac 1300389679d8SEric Piel wistron_led_suspend(); 130167dbe83aSDmitry Torokhov 1302a5b0cc80SDmitry Torokhov return 0; 1303a5b0cc80SDmitry Torokhov } 1304a5b0cc80SDmitry Torokhov 130567dbe83aSDmitry Torokhov static int wistron_resume(struct device *dev) 1306a5b0cc80SDmitry Torokhov { 1307a5b0cc80SDmitry Torokhov if (have_wifi) 1308a5b0cc80SDmitry Torokhov bios_set_state(WIFI, wifi_enabled); 1309a5b0cc80SDmitry Torokhov 1310a5b0cc80SDmitry Torokhov if (have_bluetooth) 1311a5b0cc80SDmitry Torokhov bios_set_state(BLUETOOTH, bluetooth_enabled); 1312a5b0cc80SDmitry Torokhov 1313389679d8SEric Piel wistron_led_resume(); 131467dbe83aSDmitry Torokhov 1315c2554c91SDmitry Torokhov poll_bios(true); 1316a5b0cc80SDmitry Torokhov 1317a5b0cc80SDmitry Torokhov return 0; 1318a5b0cc80SDmitry Torokhov } 131967dbe83aSDmitry Torokhov 132067dbe83aSDmitry Torokhov static const struct dev_pm_ops wistron_pm_ops = { 132167dbe83aSDmitry Torokhov .suspend = wistron_suspend, 132267dbe83aSDmitry Torokhov .resume = wistron_resume, 132367dbe83aSDmitry Torokhov .poweroff = wistron_suspend, 132467dbe83aSDmitry Torokhov .restore = wistron_resume, 132567dbe83aSDmitry Torokhov }; 1326e7c3aad5SDmitry Torokhov #endif 1327a5b0cc80SDmitry Torokhov 1328a5b0cc80SDmitry Torokhov static struct platform_driver wistron_driver = { 1329a5b0cc80SDmitry Torokhov .driver = { 1330a5b0cc80SDmitry Torokhov .name = "wistron-bios", 1331e7c3aad5SDmitry Torokhov .owner = THIS_MODULE, 1332e97006aeSRakib Mullick #ifdef CONFIG_PM 133367dbe83aSDmitry Torokhov .pm = &wistron_pm_ops, 133467dbe83aSDmitry Torokhov #endif 1335a5b0cc80SDmitry Torokhov }, 1336e7c3aad5SDmitry Torokhov .probe = wistron_probe, 1337e7c3aad5SDmitry Torokhov .remove = __devexit_p(wistron_remove), 1338a5b0cc80SDmitry Torokhov }; 1339a5b0cc80SDmitry Torokhov 13405fc14680SDmitry Torokhov static int __init wb_module_init(void) 13415fc14680SDmitry Torokhov { 13425fc14680SDmitry Torokhov int err; 13435fc14680SDmitry Torokhov 13445fc14680SDmitry Torokhov err = select_keymap(); 13455fc14680SDmitry Torokhov if (err) 13465fc14680SDmitry Torokhov return err; 134722a397e2SDmitry Torokhov 13485fc14680SDmitry Torokhov err = map_bios(); 13495fc14680SDmitry Torokhov if (err) 13501fcb8bb6SAxel Lin goto err_free_keymap; 135122a397e2SDmitry Torokhov 1352a5b0cc80SDmitry Torokhov err = platform_driver_register(&wistron_driver); 1353a5b0cc80SDmitry Torokhov if (err) 1354e7c3aad5SDmitry Torokhov goto err_unmap_bios; 1355a5b0cc80SDmitry Torokhov 1356e7c3aad5SDmitry Torokhov wistron_device = platform_device_alloc("wistron-bios", -1); 1357e7c3aad5SDmitry Torokhov if (!wistron_device) { 1358e7c3aad5SDmitry Torokhov err = -ENOMEM; 1359a5b0cc80SDmitry Torokhov goto err_unregister_driver; 1360a5b0cc80SDmitry Torokhov } 1361a5b0cc80SDmitry Torokhov 1362e7c3aad5SDmitry Torokhov err = platform_device_add(wistron_device); 1363a5b0cc80SDmitry Torokhov if (err) 1364e7c3aad5SDmitry Torokhov goto err_free_device; 13655fc14680SDmitry Torokhov 13665fc14680SDmitry Torokhov return 0; 1367a5b0cc80SDmitry Torokhov 1368e7c3aad5SDmitry Torokhov err_free_device: 1369e7c3aad5SDmitry Torokhov platform_device_put(wistron_device); 1370a5b0cc80SDmitry Torokhov err_unregister_driver: 1371a5b0cc80SDmitry Torokhov platform_driver_unregister(&wistron_driver); 1372e7c3aad5SDmitry Torokhov err_unmap_bios: 1373a5b0cc80SDmitry Torokhov unmap_bios(); 13741fcb8bb6SAxel Lin err_free_keymap: 13751fcb8bb6SAxel Lin kfree(keymap); 1376a5b0cc80SDmitry Torokhov 1377a5b0cc80SDmitry Torokhov return err; 13785fc14680SDmitry Torokhov } 13795fc14680SDmitry Torokhov 13805fc14680SDmitry Torokhov static void __exit wb_module_exit(void) 13815fc14680SDmitry Torokhov { 1382a5b0cc80SDmitry Torokhov platform_device_unregister(wistron_device); 1383a5b0cc80SDmitry Torokhov platform_driver_unregister(&wistron_driver); 13845fc14680SDmitry Torokhov unmap_bios(); 138555d29c98SEric Piel kfree(keymap); 13865fc14680SDmitry Torokhov } 13875fc14680SDmitry Torokhov 13885fc14680SDmitry Torokhov module_init(wb_module_init); 13895fc14680SDmitry Torokhov module_exit(wb_module_exit); 1390