1b1fb60d7SThomas Gleixner // SPDX-License-Identifier: GPL-2.0-only 25fc14680SDmitry Torokhov /* 35fc14680SDmitry Torokhov * Wistron laptop button driver 45fc14680SDmitry Torokhov * Copyright (C) 2005 Miloslav Trmac <mitr@volny.cz> 584b256a6SBernhard Rosenkraenzer * Copyright (C) 2005 Bernhard Rosenkraenzer <bero@arklinux.org> 6a5b0cc80SDmitry Torokhov * Copyright (C) 2005 Dmitry Torokhov <dtor@mail.ru> 75fc14680SDmitry Torokhov */ 853d5ed62SMatthew Wilcox #include <linux/io.h> 95fc14680SDmitry Torokhov #include <linux/dmi.h> 105fc14680SDmitry Torokhov #include <linux/init.h> 114a767ec3SDmitry Torokhov #include <linux/input.h> 12e97af4cbSDmitry Torokhov #include <linux/input/sparse-keymap.h> 135fc14680SDmitry Torokhov #include <linux/interrupt.h> 14a4da16d3SEric Piel #include <linux/jiffies.h> 155fc14680SDmitry Torokhov #include <linux/kernel.h> 165fc14680SDmitry Torokhov #include <linux/mc146818rtc.h> 175fc14680SDmitry Torokhov #include <linux/module.h> 185fc14680SDmitry Torokhov #include <linux/preempt.h> 195fc14680SDmitry Torokhov #include <linux/string.h> 205a0e3ad6STejun Heo #include <linux/slab.h> 215fc14680SDmitry Torokhov #include <linux/types.h> 22a5b0cc80SDmitry Torokhov #include <linux/platform_device.h> 23389679d8SEric Piel #include <linux/leds.h> 245fc14680SDmitry Torokhov 25c2554c91SDmitry Torokhov /* How often we poll keys - msecs */ 26c2554c91SDmitry Torokhov #define POLL_INTERVAL_DEFAULT 500 /* when idle */ 27c2554c91SDmitry Torokhov #define POLL_INTERVAL_BURST 100 /* when a key was recently pressed */ 285fc14680SDmitry Torokhov 2984b256a6SBernhard Rosenkraenzer /* BIOS subsystem IDs */ 3084b256a6SBernhard Rosenkraenzer #define WIFI 0x35 3184b256a6SBernhard Rosenkraenzer #define BLUETOOTH 0x34 32389679d8SEric Piel #define MAIL_LED 0x31 3384b256a6SBernhard Rosenkraenzer 345fc14680SDmitry Torokhov MODULE_AUTHOR("Miloslav Trmac <mitr@volny.cz>"); 355fc14680SDmitry Torokhov MODULE_DESCRIPTION("Wistron laptop button driver"); 365fc14680SDmitry Torokhov MODULE_LICENSE("GPL v2"); 375fc14680SDmitry Torokhov 3890ab5ee9SRusty Russell static bool force; /* = 0; */ 395fc14680SDmitry Torokhov module_param(force, bool, 0); 405fc14680SDmitry Torokhov MODULE_PARM_DESC(force, "Load even if computer is not in database"); 415fc14680SDmitry Torokhov 425fc14680SDmitry Torokhov static char *keymap_name; /* = NULL; */ 435fc14680SDmitry Torokhov module_param_named(keymap, keymap_name, charp, 0); 447b0a4cd7SEric Piel MODULE_PARM_DESC(keymap, "Keymap name, if it can't be autodetected [generic, 1557/MS2141]"); 455fc14680SDmitry Torokhov 46a5b0cc80SDmitry Torokhov static struct platform_device *wistron_device; 47a5b0cc80SDmitry Torokhov 485fc14680SDmitry Torokhov /* BIOS interface implementation */ 495fc14680SDmitry Torokhov 505fc14680SDmitry Torokhov static void __iomem *bios_entry_point; /* BIOS routine entry point */ 515fc14680SDmitry Torokhov static void __iomem *bios_code_map_base; 525fc14680SDmitry Torokhov static void __iomem *bios_data_map_base; 535fc14680SDmitry Torokhov 545fc14680SDmitry Torokhov static u8 cmos_address; 555fc14680SDmitry Torokhov 565fc14680SDmitry Torokhov struct regs { 575fc14680SDmitry Torokhov u32 eax, ebx, ecx; 585fc14680SDmitry Torokhov }; 595fc14680SDmitry Torokhov 605fc14680SDmitry Torokhov static void call_bios(struct regs *regs) 615fc14680SDmitry Torokhov { 625fc14680SDmitry Torokhov unsigned long flags; 635fc14680SDmitry Torokhov 645fc14680SDmitry Torokhov preempt_disable(); 655fc14680SDmitry Torokhov local_irq_save(flags); 665fc14680SDmitry Torokhov asm volatile ("pushl %%ebp;" 675fc14680SDmitry Torokhov "movl %7, %%ebp;" 685fc14680SDmitry Torokhov "call *%6;" 695fc14680SDmitry Torokhov "popl %%ebp" 705fc14680SDmitry Torokhov : "=a" (regs->eax), "=b" (regs->ebx), "=c" (regs->ecx) 715fc14680SDmitry Torokhov : "0" (regs->eax), "1" (regs->ebx), "2" (regs->ecx), 725fc14680SDmitry Torokhov "m" (bios_entry_point), "m" (bios_data_map_base) 735fc14680SDmitry Torokhov : "edx", "edi", "esi", "memory"); 745fc14680SDmitry Torokhov local_irq_restore(flags); 755fc14680SDmitry Torokhov preempt_enable(); 765fc14680SDmitry Torokhov } 775fc14680SDmitry Torokhov 78c28c3583SMiloslav Trmac static ssize_t __init locate_wistron_bios(void __iomem *base) 795fc14680SDmitry Torokhov { 80c7948989SAndrew Morton static unsigned char __initdata signature[] = 815fc14680SDmitry Torokhov { 0x42, 0x21, 0x55, 0x30 }; 82c28c3583SMiloslav Trmac ssize_t offset; 835fc14680SDmitry Torokhov 845fc14680SDmitry Torokhov for (offset = 0; offset < 0x10000; offset += 0x10) { 855fc14680SDmitry Torokhov if (check_signature(base + offset, signature, 865fc14680SDmitry Torokhov sizeof(signature)) != 0) 875fc14680SDmitry Torokhov return offset; 885fc14680SDmitry Torokhov } 895fc14680SDmitry Torokhov return -1; 905fc14680SDmitry Torokhov } 915fc14680SDmitry Torokhov 925fc14680SDmitry Torokhov static int __init map_bios(void) 935fc14680SDmitry Torokhov { 945fc14680SDmitry Torokhov void __iomem *base; 95c28c3583SMiloslav Trmac ssize_t offset; 965fc14680SDmitry Torokhov u32 entry_point; 975fc14680SDmitry Torokhov 985fc14680SDmitry Torokhov base = ioremap(0xF0000, 0x10000); /* Can't fail */ 995fc14680SDmitry Torokhov offset = locate_wistron_bios(base); 1005fc14680SDmitry Torokhov if (offset < 0) { 1015fc14680SDmitry Torokhov printk(KERN_ERR "wistron_btns: BIOS entry point not found\n"); 1025fc14680SDmitry Torokhov iounmap(base); 1035fc14680SDmitry Torokhov return -ENODEV; 1045fc14680SDmitry Torokhov } 1055fc14680SDmitry Torokhov 1065fc14680SDmitry Torokhov entry_point = readl(base + offset + 5); 1075fc14680SDmitry Torokhov printk(KERN_DEBUG 1085fc14680SDmitry Torokhov "wistron_btns: BIOS signature found at %p, entry point %08X\n", 1095fc14680SDmitry Torokhov base + offset, entry_point); 1105fc14680SDmitry Torokhov 1115fc14680SDmitry Torokhov if (entry_point >= 0xF0000) { 1125fc14680SDmitry Torokhov bios_code_map_base = base; 1135fc14680SDmitry Torokhov bios_entry_point = bios_code_map_base + (entry_point & 0xFFFF); 1145fc14680SDmitry Torokhov } else { 1155fc14680SDmitry Torokhov iounmap(base); 1165fc14680SDmitry Torokhov bios_code_map_base = ioremap(entry_point & ~0x3FFF, 0x4000); 1175fc14680SDmitry Torokhov if (bios_code_map_base == NULL) { 1185fc14680SDmitry Torokhov printk(KERN_ERR 1195fc14680SDmitry Torokhov "wistron_btns: Can't map BIOS code at %08X\n", 1205fc14680SDmitry Torokhov entry_point & ~0x3FFF); 1215fc14680SDmitry Torokhov goto err; 1225fc14680SDmitry Torokhov } 1235fc14680SDmitry Torokhov bios_entry_point = bios_code_map_base + (entry_point & 0x3FFF); 1245fc14680SDmitry Torokhov } 1255fc14680SDmitry Torokhov /* The Windows driver maps 0x10000 bytes, we keep only one page... */ 1265fc14680SDmitry Torokhov bios_data_map_base = ioremap(0x400, 0xc00); 1275fc14680SDmitry Torokhov if (bios_data_map_base == NULL) { 1285fc14680SDmitry Torokhov printk(KERN_ERR "wistron_btns: Can't map BIOS data\n"); 1295fc14680SDmitry Torokhov goto err_code; 1305fc14680SDmitry Torokhov } 1315fc14680SDmitry Torokhov return 0; 1325fc14680SDmitry Torokhov 1335fc14680SDmitry Torokhov err_code: 1345fc14680SDmitry Torokhov iounmap(bios_code_map_base); 1355fc14680SDmitry Torokhov err: 1365fc14680SDmitry Torokhov return -ENOMEM; 1375fc14680SDmitry Torokhov } 1385fc14680SDmitry Torokhov 13922a397e2SDmitry Torokhov static inline void unmap_bios(void) 1405fc14680SDmitry Torokhov { 1415fc14680SDmitry Torokhov iounmap(bios_code_map_base); 1425fc14680SDmitry Torokhov iounmap(bios_data_map_base); 1435fc14680SDmitry Torokhov } 1445fc14680SDmitry Torokhov 1455fc14680SDmitry Torokhov /* BIOS calls */ 1465fc14680SDmitry Torokhov 1475fc14680SDmitry Torokhov static u16 bios_pop_queue(void) 1485fc14680SDmitry Torokhov { 1495fc14680SDmitry Torokhov struct regs regs; 1505fc14680SDmitry Torokhov 1515fc14680SDmitry Torokhov memset(®s, 0, sizeof (regs)); 1525fc14680SDmitry Torokhov regs.eax = 0x9610; 1535fc14680SDmitry Torokhov regs.ebx = 0x061C; 1545fc14680SDmitry Torokhov regs.ecx = 0x0000; 1555fc14680SDmitry Torokhov call_bios(®s); 1565fc14680SDmitry Torokhov 1575fc14680SDmitry Torokhov return regs.eax; 1585fc14680SDmitry Torokhov } 1595fc14680SDmitry Torokhov 1605298cc4cSBill Pemberton static void bios_attach(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 = 0x012E; 1675fc14680SDmitry Torokhov call_bios(®s); 1685fc14680SDmitry Torokhov } 1695fc14680SDmitry Torokhov 17022a397e2SDmitry Torokhov static void bios_detach(void) 1715fc14680SDmitry Torokhov { 1725fc14680SDmitry Torokhov struct regs regs; 1735fc14680SDmitry Torokhov 1745fc14680SDmitry Torokhov memset(®s, 0, sizeof (regs)); 1755fc14680SDmitry Torokhov regs.eax = 0x9610; 1765fc14680SDmitry Torokhov regs.ebx = 0x002E; 1775fc14680SDmitry Torokhov call_bios(®s); 1785fc14680SDmitry Torokhov } 1795fc14680SDmitry Torokhov 1805298cc4cSBill Pemberton static u8 bios_get_cmos_address(void) 1815fc14680SDmitry Torokhov { 1825fc14680SDmitry Torokhov struct regs regs; 1835fc14680SDmitry Torokhov 1845fc14680SDmitry Torokhov memset(®s, 0, sizeof (regs)); 1855fc14680SDmitry Torokhov regs.eax = 0x9610; 1865fc14680SDmitry Torokhov regs.ebx = 0x051C; 1875fc14680SDmitry Torokhov call_bios(®s); 1885fc14680SDmitry Torokhov 1895fc14680SDmitry Torokhov return regs.ecx; 1905fc14680SDmitry Torokhov } 1915fc14680SDmitry Torokhov 1925298cc4cSBill Pemberton static u16 bios_get_default_setting(u8 subsys) 1935fc14680SDmitry Torokhov { 1945fc14680SDmitry Torokhov struct regs regs; 1955fc14680SDmitry Torokhov 1965fc14680SDmitry Torokhov memset(®s, 0, sizeof (regs)); 1975fc14680SDmitry Torokhov regs.eax = 0x9610; 19884b256a6SBernhard Rosenkraenzer regs.ebx = 0x0200 | subsys; 1995fc14680SDmitry Torokhov call_bios(®s); 2005fc14680SDmitry Torokhov 2015fc14680SDmitry Torokhov return regs.eax; 2025fc14680SDmitry Torokhov } 2035fc14680SDmitry Torokhov 20484b256a6SBernhard Rosenkraenzer static void bios_set_state(u8 subsys, int enable) 2055fc14680SDmitry Torokhov { 2065fc14680SDmitry Torokhov struct regs regs; 2075fc14680SDmitry Torokhov 2085fc14680SDmitry Torokhov memset(®s, 0, sizeof (regs)); 2095fc14680SDmitry Torokhov regs.eax = 0x9610; 21084b256a6SBernhard Rosenkraenzer regs.ebx = (enable ? 0x0100 : 0x0000) | subsys; 2115fc14680SDmitry Torokhov call_bios(®s); 2125fc14680SDmitry Torokhov } 2135fc14680SDmitry Torokhov 2145fc14680SDmitry Torokhov /* Hardware database */ 2155fc14680SDmitry Torokhov 216e97af4cbSDmitry Torokhov #define KE_WIFI (KE_LAST + 1) 217e97af4cbSDmitry Torokhov #define KE_BLUETOOTH (KE_LAST + 2) 2186480e2a2SEric Piel 2196480e2a2SEric Piel #define FE_MAIL_LED 0x01 2206480e2a2SEric Piel #define FE_WIFI_LED 0x02 2216480e2a2SEric Piel #define FE_UNTESTED 0x80 2225fc14680SDmitry Torokhov 223d63219a1SDmitry Torokhov static struct key_entry *keymap; /* = NULL; Current key map */ 22467dbe83aSDmitry Torokhov static bool have_wifi; 22567dbe83aSDmitry Torokhov static bool have_bluetooth; 22667dbe83aSDmitry Torokhov static int leds_present; /* bitmask of leds present */ 2275fc14680SDmitry Torokhov 2281855256cSJeff Garzik static int __init dmi_matched(const struct dmi_system_id *dmi) 2295fc14680SDmitry Torokhov { 2305fc14680SDmitry Torokhov const struct key_entry *key; 2315fc14680SDmitry Torokhov 2325fc14680SDmitry Torokhov keymap = dmi->driver_data; 2335fc14680SDmitry Torokhov for (key = keymap; key->type != KE_END; key++) { 234cde45f19SReiner Herrmann if (key->type == KE_WIFI) 23567dbe83aSDmitry Torokhov have_wifi = true; 236cde45f19SReiner Herrmann else if (key->type == KE_BLUETOOTH) 23767dbe83aSDmitry Torokhov have_bluetooth = true; 2385fc14680SDmitry Torokhov } 23967dbe83aSDmitry Torokhov leds_present = key->code & (FE_MAIL_LED | FE_WIFI_LED); 240389679d8SEric Piel 2415fc14680SDmitry Torokhov return 1; 2425fc14680SDmitry Torokhov } 2435fc14680SDmitry Torokhov 24455d29c98SEric Piel static struct key_entry keymap_empty[] __initdata = { 2455fc14680SDmitry Torokhov { KE_END, 0 } 2465fc14680SDmitry Torokhov }; 2475fc14680SDmitry Torokhov 24855d29c98SEric Piel static struct key_entry keymap_fs_amilo_pro_v2000[] __initdata = { 2496480e2a2SEric Piel { KE_KEY, 0x01, {KEY_HELP} }, 2506480e2a2SEric Piel { KE_KEY, 0x11, {KEY_PROG1} }, 2516480e2a2SEric Piel { KE_KEY, 0x12, {KEY_PROG2} }, 2526480e2a2SEric Piel { KE_WIFI, 0x30 }, 2536480e2a2SEric Piel { KE_KEY, 0x31, {KEY_MAIL} }, 2546480e2a2SEric Piel { KE_KEY, 0x36, {KEY_WWW} }, 2555fc14680SDmitry Torokhov { KE_END, 0 } 2565fc14680SDmitry Torokhov }; 2575fc14680SDmitry Torokhov 25834a7c48cSRemi Herilier static struct key_entry keymap_fs_amilo_pro_v3505[] __initdata = { 25934a7c48cSRemi Herilier { KE_KEY, 0x01, {KEY_HELP} }, /* Fn+F1 */ 26034a7c48cSRemi Herilier { KE_KEY, 0x06, {KEY_DISPLAYTOGGLE} }, /* Fn+F4 */ 26134a7c48cSRemi Herilier { KE_BLUETOOTH, 0x30 }, /* Fn+F10 */ 26234a7c48cSRemi Herilier { KE_KEY, 0x31, {KEY_MAIL} }, /* mail button */ 26334a7c48cSRemi Herilier { KE_KEY, 0x36, {KEY_WWW} }, /* www button */ 26425985edcSLucas De Marchi { KE_WIFI, 0x78 }, /* satellite dish button */ 26534a7c48cSRemi Herilier { KE_END, 0 } 26634a7c48cSRemi Herilier }; 26734a7c48cSRemi Herilier 26811601a82SJakub Bogusz static struct key_entry keymap_fs_amilo_pro_v8210[] __initdata = { 26911601a82SJakub Bogusz { KE_KEY, 0x01, {KEY_HELP} }, /* Fn+F1 */ 27011601a82SJakub Bogusz { KE_KEY, 0x06, {KEY_DISPLAYTOGGLE} }, /* Fn+F4 */ 27111601a82SJakub Bogusz { KE_BLUETOOTH, 0x30 }, /* Fn+F10 */ 27211601a82SJakub Bogusz { KE_KEY, 0x31, {KEY_MAIL} }, /* mail button */ 27311601a82SJakub Bogusz { KE_KEY, 0x36, {KEY_WWW} }, /* www button */ 27411601a82SJakub Bogusz { KE_WIFI, 0x78 }, /* satelite dish button */ 27511601a82SJakub Bogusz { KE_END, FE_WIFI_LED } 27611601a82SJakub Bogusz }; 27711601a82SJakub Bogusz 27855d29c98SEric Piel static struct key_entry keymap_fujitsu_n3510[] __initdata = { 2796480e2a2SEric Piel { KE_KEY, 0x11, {KEY_PROG1} }, 2806480e2a2SEric Piel { KE_KEY, 0x12, {KEY_PROG2} }, 2816480e2a2SEric Piel { KE_KEY, 0x36, {KEY_WWW} }, 2826480e2a2SEric Piel { KE_KEY, 0x31, {KEY_MAIL} }, 2836480e2a2SEric Piel { KE_KEY, 0x71, {KEY_STOPCD} }, 2846480e2a2SEric Piel { KE_KEY, 0x72, {KEY_PLAYPAUSE} }, 2856480e2a2SEric Piel { KE_KEY, 0x74, {KEY_REWIND} }, 2866480e2a2SEric Piel { KE_KEY, 0x78, {KEY_FORWARD} }, 287e2aa507aSJohn Reed Riley { KE_END, 0 } 288e2aa507aSJohn Reed Riley }; 289e2aa507aSJohn Reed Riley 29055d29c98SEric Piel static struct key_entry keymap_wistron_ms2111[] __initdata = { 2916480e2a2SEric Piel { KE_KEY, 0x11, {KEY_PROG1} }, 2926480e2a2SEric Piel { KE_KEY, 0x12, {KEY_PROG2} }, 2936480e2a2SEric Piel { KE_KEY, 0x13, {KEY_PROG3} }, 2946480e2a2SEric Piel { KE_KEY, 0x31, {KEY_MAIL} }, 2956480e2a2SEric Piel { KE_KEY, 0x36, {KEY_WWW} }, 2966480e2a2SEric Piel { KE_END, FE_MAIL_LED } 2976480e2a2SEric Piel }; 2986480e2a2SEric Piel 29955d29c98SEric Piel static struct key_entry keymap_wistron_md40100[] __initdata = { 3006480e2a2SEric Piel { KE_KEY, 0x01, {KEY_HELP} }, 3016480e2a2SEric Piel { KE_KEY, 0x02, {KEY_CONFIG} }, 3026480e2a2SEric Piel { KE_KEY, 0x31, {KEY_MAIL} }, 3036480e2a2SEric Piel { KE_KEY, 0x36, {KEY_WWW} }, 3046480e2a2SEric Piel { KE_KEY, 0x37, {KEY_DISPLAYTOGGLE} }, /* Display on/off */ 3056480e2a2SEric Piel { KE_END, FE_MAIL_LED | FE_WIFI_LED | FE_UNTESTED } 3069000195bSFrank de Lange }; 3079000195bSFrank de Lange 30855d29c98SEric Piel static struct key_entry keymap_wistron_ms2141[] __initdata = { 3096480e2a2SEric Piel { KE_KEY, 0x11, {KEY_PROG1} }, 3106480e2a2SEric Piel { KE_KEY, 0x12, {KEY_PROG2} }, 3116480e2a2SEric Piel { KE_WIFI, 0x30 }, 3126480e2a2SEric Piel { KE_KEY, 0x22, {KEY_REWIND} }, 3136480e2a2SEric Piel { KE_KEY, 0x23, {KEY_FORWARD} }, 3146480e2a2SEric Piel { KE_KEY, 0x24, {KEY_PLAYPAUSE} }, 3156480e2a2SEric Piel { KE_KEY, 0x25, {KEY_STOPCD} }, 3166480e2a2SEric Piel { KE_KEY, 0x31, {KEY_MAIL} }, 3176480e2a2SEric Piel { KE_KEY, 0x36, {KEY_WWW} }, 3185fc14680SDmitry Torokhov { KE_END, 0 } 3195fc14680SDmitry Torokhov }; 3205fc14680SDmitry Torokhov 32155d29c98SEric Piel static struct key_entry keymap_acer_aspire_1500[] __initdata = { 3226480e2a2SEric Piel { KE_KEY, 0x01, {KEY_HELP} }, 3236480e2a2SEric Piel { KE_KEY, 0x03, {KEY_POWER} }, 3246480e2a2SEric Piel { KE_KEY, 0x11, {KEY_PROG1} }, 3256480e2a2SEric Piel { KE_KEY, 0x12, {KEY_PROG2} }, 3266480e2a2SEric Piel { KE_WIFI, 0x30 }, 3276480e2a2SEric Piel { KE_KEY, 0x31, {KEY_MAIL} }, 3286480e2a2SEric Piel { KE_KEY, 0x36, {KEY_WWW} }, 3296480e2a2SEric Piel { KE_KEY, 0x49, {KEY_CONFIG} }, 3306480e2a2SEric Piel { KE_BLUETOOTH, 0x44 }, 3316480e2a2SEric Piel { KE_END, FE_UNTESTED } 3326480e2a2SEric Piel }; 3336480e2a2SEric Piel 33455d29c98SEric Piel static struct key_entry keymap_acer_aspire_1600[] __initdata = { 3356480e2a2SEric Piel { KE_KEY, 0x01, {KEY_HELP} }, 3366480e2a2SEric Piel { KE_KEY, 0x03, {KEY_POWER} }, 3376480e2a2SEric Piel { KE_KEY, 0x08, {KEY_MUTE} }, 3386480e2a2SEric Piel { KE_KEY, 0x11, {KEY_PROG1} }, 3396480e2a2SEric Piel { KE_KEY, 0x12, {KEY_PROG2} }, 3406480e2a2SEric Piel { KE_KEY, 0x13, {KEY_PROG3} }, 3416480e2a2SEric Piel { KE_KEY, 0x31, {KEY_MAIL} }, 3426480e2a2SEric Piel { KE_KEY, 0x36, {KEY_WWW} }, 3436480e2a2SEric Piel { KE_KEY, 0x49, {KEY_CONFIG} }, 3446480e2a2SEric Piel { KE_WIFI, 0x30 }, 3456480e2a2SEric Piel { KE_BLUETOOTH, 0x44 }, 3466480e2a2SEric Piel { KE_END, FE_MAIL_LED | FE_UNTESTED } 3476480e2a2SEric Piel }; 3486480e2a2SEric Piel 3496480e2a2SEric Piel /* 3020 has been tested */ 35055d29c98SEric Piel static struct key_entry keymap_acer_aspire_5020[] __initdata = { 3516480e2a2SEric Piel { KE_KEY, 0x01, {KEY_HELP} }, 3526480e2a2SEric Piel { KE_KEY, 0x03, {KEY_POWER} }, 3536480e2a2SEric Piel { KE_KEY, 0x05, {KEY_SWITCHVIDEOMODE} }, /* Display selection */ 3546480e2a2SEric Piel { KE_KEY, 0x11, {KEY_PROG1} }, 3556480e2a2SEric Piel { KE_KEY, 0x12, {KEY_PROG2} }, 3566480e2a2SEric Piel { KE_KEY, 0x31, {KEY_MAIL} }, 3576480e2a2SEric Piel { KE_KEY, 0x36, {KEY_WWW} }, 3586480e2a2SEric Piel { KE_KEY, 0x6a, {KEY_CONFIG} }, 3596480e2a2SEric Piel { KE_WIFI, 0x30 }, 3606480e2a2SEric Piel { KE_BLUETOOTH, 0x44 }, 3616480e2a2SEric Piel { KE_END, FE_MAIL_LED | FE_UNTESTED } 3626480e2a2SEric Piel }; 3636480e2a2SEric Piel 36455d29c98SEric Piel static struct key_entry keymap_acer_travelmate_2410[] __initdata = { 3656480e2a2SEric Piel { KE_KEY, 0x01, {KEY_HELP} }, 3666480e2a2SEric Piel { KE_KEY, 0x6d, {KEY_POWER} }, 3676480e2a2SEric Piel { KE_KEY, 0x11, {KEY_PROG1} }, 3686480e2a2SEric Piel { KE_KEY, 0x12, {KEY_PROG2} }, 3696480e2a2SEric Piel { KE_KEY, 0x31, {KEY_MAIL} }, 3706480e2a2SEric Piel { KE_KEY, 0x36, {KEY_WWW} }, 3716480e2a2SEric Piel { KE_KEY, 0x6a, {KEY_CONFIG} }, 3726480e2a2SEric Piel { KE_WIFI, 0x30 }, 3736480e2a2SEric Piel { KE_BLUETOOTH, 0x44 }, 3746480e2a2SEric Piel { KE_END, FE_MAIL_LED | FE_UNTESTED } 3756480e2a2SEric Piel }; 3766480e2a2SEric Piel 37755d29c98SEric Piel static struct key_entry keymap_acer_travelmate_110[] __initdata = { 3786480e2a2SEric Piel { KE_KEY, 0x01, {KEY_HELP} }, 3796480e2a2SEric Piel { KE_KEY, 0x02, {KEY_CONFIG} }, 3806480e2a2SEric Piel { KE_KEY, 0x03, {KEY_POWER} }, 3816480e2a2SEric Piel { KE_KEY, 0x08, {KEY_MUTE} }, 3826480e2a2SEric Piel { KE_KEY, 0x11, {KEY_PROG1} }, 3836480e2a2SEric Piel { KE_KEY, 0x12, {KEY_PROG2} }, 3846480e2a2SEric Piel { KE_KEY, 0x20, {KEY_VOLUMEUP} }, 3856480e2a2SEric Piel { KE_KEY, 0x21, {KEY_VOLUMEDOWN} }, 3866480e2a2SEric Piel { KE_KEY, 0x31, {KEY_MAIL} }, 3876480e2a2SEric Piel { KE_KEY, 0x36, {KEY_WWW} }, 3886480e2a2SEric Piel { KE_SW, 0x4a, {.sw = {SW_LID, 1}} }, /* lid close */ 3896480e2a2SEric Piel { KE_SW, 0x4b, {.sw = {SW_LID, 0}} }, /* lid open */ 3906480e2a2SEric Piel { KE_WIFI, 0x30 }, 3916480e2a2SEric Piel { KE_END, FE_MAIL_LED | FE_UNTESTED } 3926480e2a2SEric Piel }; 3936480e2a2SEric Piel 39455d29c98SEric Piel static struct key_entry keymap_acer_travelmate_300[] __initdata = { 3956480e2a2SEric Piel { KE_KEY, 0x01, {KEY_HELP} }, 3966480e2a2SEric Piel { KE_KEY, 0x02, {KEY_CONFIG} }, 3976480e2a2SEric Piel { KE_KEY, 0x03, {KEY_POWER} }, 3986480e2a2SEric Piel { KE_KEY, 0x08, {KEY_MUTE} }, 3996480e2a2SEric Piel { KE_KEY, 0x11, {KEY_PROG1} }, 4006480e2a2SEric Piel { KE_KEY, 0x12, {KEY_PROG2} }, 4016480e2a2SEric Piel { KE_KEY, 0x20, {KEY_VOLUMEUP} }, 4026480e2a2SEric Piel { KE_KEY, 0x21, {KEY_VOLUMEDOWN} }, 4036480e2a2SEric Piel { KE_KEY, 0x31, {KEY_MAIL} }, 4046480e2a2SEric Piel { KE_KEY, 0x36, {KEY_WWW} }, 4056480e2a2SEric Piel { KE_WIFI, 0x30 }, 4066480e2a2SEric Piel { KE_BLUETOOTH, 0x44 }, 4076480e2a2SEric Piel { KE_END, FE_MAIL_LED | FE_UNTESTED } 4086480e2a2SEric Piel }; 4096480e2a2SEric Piel 41055d29c98SEric Piel static struct key_entry keymap_acer_travelmate_380[] __initdata = { 4116480e2a2SEric Piel { KE_KEY, 0x01, {KEY_HELP} }, 4126480e2a2SEric Piel { KE_KEY, 0x02, {KEY_CONFIG} }, 4136480e2a2SEric Piel { KE_KEY, 0x03, {KEY_POWER} }, /* not 370 */ 4146480e2a2SEric Piel { KE_KEY, 0x11, {KEY_PROG1} }, 4156480e2a2SEric Piel { KE_KEY, 0x12, {KEY_PROG2} }, 4166480e2a2SEric Piel { KE_KEY, 0x13, {KEY_PROG3} }, 4176480e2a2SEric Piel { KE_KEY, 0x31, {KEY_MAIL} }, 4186480e2a2SEric Piel { KE_KEY, 0x36, {KEY_WWW} }, 4196480e2a2SEric Piel { KE_WIFI, 0x30 }, 4206480e2a2SEric Piel { KE_END, FE_MAIL_LED | FE_UNTESTED } 4216480e2a2SEric Piel }; 4226480e2a2SEric Piel 4236480e2a2SEric Piel /* unusual map */ 42455d29c98SEric Piel static struct key_entry keymap_acer_travelmate_220[] __initdata = { 4256480e2a2SEric Piel { KE_KEY, 0x01, {KEY_HELP} }, 4266480e2a2SEric Piel { KE_KEY, 0x02, {KEY_CONFIG} }, 4276480e2a2SEric Piel { KE_KEY, 0x11, {KEY_MAIL} }, 4286480e2a2SEric Piel { KE_KEY, 0x12, {KEY_WWW} }, 4296480e2a2SEric Piel { KE_KEY, 0x13, {KEY_PROG2} }, 4306480e2a2SEric Piel { KE_KEY, 0x31, {KEY_PROG1} }, 4316480e2a2SEric Piel { KE_END, FE_WIFI_LED | FE_UNTESTED } 4326480e2a2SEric Piel }; 4336480e2a2SEric Piel 43455d29c98SEric Piel static struct key_entry keymap_acer_travelmate_230[] __initdata = { 4356480e2a2SEric Piel { KE_KEY, 0x01, {KEY_HELP} }, 4366480e2a2SEric Piel { KE_KEY, 0x02, {KEY_CONFIG} }, 4376480e2a2SEric Piel { KE_KEY, 0x11, {KEY_PROG1} }, 4386480e2a2SEric Piel { KE_KEY, 0x12, {KEY_PROG2} }, 4396480e2a2SEric Piel { KE_KEY, 0x31, {KEY_MAIL} }, 4406480e2a2SEric Piel { KE_KEY, 0x36, {KEY_WWW} }, 4416480e2a2SEric Piel { KE_END, FE_WIFI_LED | FE_UNTESTED } 44284b256a6SBernhard Rosenkraenzer }; 44384b256a6SBernhard Rosenkraenzer 44455d29c98SEric Piel static struct key_entry keymap_acer_travelmate_240[] __initdata = { 4456480e2a2SEric Piel { KE_KEY, 0x01, {KEY_HELP} }, 4466480e2a2SEric Piel { KE_KEY, 0x02, {KEY_CONFIG} }, 4476480e2a2SEric Piel { KE_KEY, 0x03, {KEY_POWER} }, 4486480e2a2SEric Piel { KE_KEY, 0x08, {KEY_MUTE} }, 4496480e2a2SEric Piel { KE_KEY, 0x31, {KEY_MAIL} }, 4506480e2a2SEric Piel { KE_KEY, 0x36, {KEY_WWW} }, 4516480e2a2SEric Piel { KE_KEY, 0x11, {KEY_PROG1} }, 4526480e2a2SEric Piel { KE_KEY, 0x12, {KEY_PROG2} }, 4536480e2a2SEric Piel { KE_BLUETOOTH, 0x44 }, 4546480e2a2SEric Piel { KE_WIFI, 0x30 }, 4556480e2a2SEric Piel { KE_END, FE_UNTESTED } 4566480e2a2SEric Piel }; 4576480e2a2SEric Piel 45855d29c98SEric Piel static struct key_entry keymap_acer_travelmate_350[] __initdata = { 4596480e2a2SEric Piel { KE_KEY, 0x01, {KEY_HELP} }, 4606480e2a2SEric Piel { KE_KEY, 0x02, {KEY_CONFIG} }, 4616480e2a2SEric Piel { KE_KEY, 0x11, {KEY_PROG1} }, 4626480e2a2SEric Piel { KE_KEY, 0x12, {KEY_PROG2} }, 4636480e2a2SEric Piel { KE_KEY, 0x13, {KEY_MAIL} }, 4646480e2a2SEric Piel { KE_KEY, 0x14, {KEY_PROG3} }, 4656480e2a2SEric Piel { KE_KEY, 0x15, {KEY_WWW} }, 4666480e2a2SEric Piel { KE_END, FE_MAIL_LED | FE_WIFI_LED | FE_UNTESTED } 4676480e2a2SEric Piel }; 4686480e2a2SEric Piel 46955d29c98SEric Piel static struct key_entry keymap_acer_travelmate_360[] __initdata = { 4706480e2a2SEric Piel { KE_KEY, 0x01, {KEY_HELP} }, 4716480e2a2SEric Piel { KE_KEY, 0x02, {KEY_CONFIG} }, 4726480e2a2SEric Piel { KE_KEY, 0x11, {KEY_PROG1} }, 4736480e2a2SEric Piel { KE_KEY, 0x12, {KEY_PROG2} }, 4746480e2a2SEric Piel { KE_KEY, 0x13, {KEY_MAIL} }, 4756480e2a2SEric Piel { KE_KEY, 0x14, {KEY_PROG3} }, 4766480e2a2SEric Piel { KE_KEY, 0x15, {KEY_WWW} }, 4776480e2a2SEric Piel { KE_KEY, 0x40, {KEY_WLAN} }, 4786480e2a2SEric Piel { KE_END, FE_WIFI_LED | FE_UNTESTED } /* no mail led */ 47974a89c96SAshutosh Naik }; 48074a89c96SAshutosh Naik 481bc413c95SEric Piel /* Wifi subsystem only activates the led. Therefore we need to pass 482bc413c95SEric Piel * wifi event as a normal key, then userspace can really change the wifi state. 483bc413c95SEric Piel * TODO we need to export led state to userspace (wifi and mail) */ 48455d29c98SEric Piel static struct key_entry keymap_acer_travelmate_610[] __initdata = { 4856480e2a2SEric Piel { KE_KEY, 0x01, {KEY_HELP} }, 4866480e2a2SEric Piel { KE_KEY, 0x02, {KEY_CONFIG} }, 4876480e2a2SEric Piel { KE_KEY, 0x11, {KEY_PROG1} }, 488fd013ce8SEric Piel { KE_KEY, 0x12, {KEY_PROG2} }, 4896480e2a2SEric Piel { KE_KEY, 0x13, {KEY_PROG3} }, 4906480e2a2SEric Piel { KE_KEY, 0x14, {KEY_MAIL} }, 4916480e2a2SEric Piel { KE_KEY, 0x15, {KEY_WWW} }, 4926480e2a2SEric Piel { KE_KEY, 0x40, {KEY_WLAN} }, 4936480e2a2SEric Piel { KE_END, FE_MAIL_LED | FE_WIFI_LED } 4946480e2a2SEric Piel }; 4956480e2a2SEric Piel 49655d29c98SEric Piel static struct key_entry keymap_acer_travelmate_630[] __initdata = { 4976480e2a2SEric Piel { KE_KEY, 0x01, {KEY_HELP} }, 4986480e2a2SEric Piel { KE_KEY, 0x02, {KEY_CONFIG} }, 4996480e2a2SEric Piel { KE_KEY, 0x03, {KEY_POWER} }, 5006480e2a2SEric Piel { KE_KEY, 0x08, {KEY_MUTE} }, /* not 620 */ 5016480e2a2SEric Piel { KE_KEY, 0x11, {KEY_PROG1} }, 5026480e2a2SEric Piel { KE_KEY, 0x12, {KEY_PROG2} }, 5036480e2a2SEric Piel { KE_KEY, 0x13, {KEY_PROG3} }, 5046480e2a2SEric Piel { KE_KEY, 0x20, {KEY_VOLUMEUP} }, 5056480e2a2SEric Piel { KE_KEY, 0x21, {KEY_VOLUMEDOWN} }, 5066480e2a2SEric Piel { KE_KEY, 0x31, {KEY_MAIL} }, 5076480e2a2SEric Piel { KE_KEY, 0x36, {KEY_WWW} }, 5086480e2a2SEric Piel { KE_WIFI, 0x30 }, 5096480e2a2SEric Piel { KE_END, FE_MAIL_LED | FE_UNTESTED } 510bc413c95SEric Piel }; 511bc413c95SEric Piel 51255d29c98SEric Piel static struct key_entry keymap_aopen_1559as[] __initdata = { 5136480e2a2SEric Piel { KE_KEY, 0x01, {KEY_HELP} }, 5146480e2a2SEric Piel { KE_KEY, 0x06, {KEY_PROG3} }, 5156480e2a2SEric Piel { KE_KEY, 0x11, {KEY_PROG1} }, 5166480e2a2SEric Piel { KE_KEY, 0x12, {KEY_PROG2} }, 5176480e2a2SEric Piel { KE_WIFI, 0x30 }, 5186480e2a2SEric Piel { KE_KEY, 0x31, {KEY_MAIL} }, 5196480e2a2SEric Piel { KE_KEY, 0x36, {KEY_WWW} }, 5209000195bSFrank de Lange { KE_END, 0 }, 521e107b8eeSmasc@theaterzentrum.at }; 522e107b8eeSmasc@theaterzentrum.at 52355d29c98SEric Piel static struct key_entry keymap_fs_amilo_d88x0[] __initdata = { 5246480e2a2SEric Piel { KE_KEY, 0x01, {KEY_HELP} }, 5256480e2a2SEric Piel { KE_KEY, 0x08, {KEY_MUTE} }, 5266480e2a2SEric Piel { KE_KEY, 0x31, {KEY_MAIL} }, 5276480e2a2SEric Piel { KE_KEY, 0x36, {KEY_WWW} }, 5286480e2a2SEric Piel { KE_KEY, 0x11, {KEY_PROG1} }, 5296480e2a2SEric Piel { KE_KEY, 0x12, {KEY_PROG2} }, 5306480e2a2SEric Piel { KE_KEY, 0x13, {KEY_PROG3} }, 5316480e2a2SEric Piel { KE_END, FE_MAIL_LED | FE_WIFI_LED | FE_UNTESTED } 5326480e2a2SEric Piel }; 5336480e2a2SEric Piel 53455d29c98SEric Piel static struct key_entry keymap_wistron_md2900[] __initdata = { 5356480e2a2SEric Piel { KE_KEY, 0x01, {KEY_HELP} }, 5366480e2a2SEric Piel { KE_KEY, 0x02, {KEY_CONFIG} }, 5376480e2a2SEric Piel { KE_KEY, 0x11, {KEY_PROG1} }, 5386480e2a2SEric Piel { KE_KEY, 0x12, {KEY_PROG2} }, 5396480e2a2SEric Piel { KE_KEY, 0x31, {KEY_MAIL} }, 5406480e2a2SEric Piel { KE_KEY, 0x36, {KEY_WWW} }, 5416480e2a2SEric Piel { KE_WIFI, 0x30 }, 5426480e2a2SEric Piel { KE_END, FE_MAIL_LED | FE_UNTESTED } 5436480e2a2SEric Piel }; 5446480e2a2SEric Piel 54555d29c98SEric Piel static struct key_entry keymap_wistron_md96500[] __initdata = { 5466480e2a2SEric Piel { KE_KEY, 0x01, {KEY_HELP} }, 5476480e2a2SEric Piel { KE_KEY, 0x02, {KEY_CONFIG} }, 5486480e2a2SEric Piel { KE_KEY, 0x05, {KEY_SWITCHVIDEOMODE} }, /* Display selection */ 5496480e2a2SEric Piel { KE_KEY, 0x06, {KEY_DISPLAYTOGGLE} }, /* Display on/off */ 5506480e2a2SEric Piel { KE_KEY, 0x08, {KEY_MUTE} }, 5516480e2a2SEric Piel { KE_KEY, 0x11, {KEY_PROG1} }, 5526480e2a2SEric Piel { KE_KEY, 0x12, {KEY_PROG2} }, 5536480e2a2SEric Piel { KE_KEY, 0x20, {KEY_VOLUMEUP} }, 5546480e2a2SEric Piel { KE_KEY, 0x21, {KEY_VOLUMEDOWN} }, 5556480e2a2SEric Piel { KE_KEY, 0x22, {KEY_REWIND} }, 5566480e2a2SEric Piel { KE_KEY, 0x23, {KEY_FORWARD} }, 5576480e2a2SEric Piel { KE_KEY, 0x24, {KEY_PLAYPAUSE} }, 5586480e2a2SEric Piel { KE_KEY, 0x25, {KEY_STOPCD} }, 5596480e2a2SEric Piel { KE_KEY, 0x31, {KEY_MAIL} }, 5606480e2a2SEric Piel { KE_KEY, 0x36, {KEY_WWW} }, 5616480e2a2SEric Piel { KE_WIFI, 0x30 }, 5626480e2a2SEric Piel { KE_BLUETOOTH, 0x44 }, 56353e88754SStefan Lippers-Hollmann { KE_END, 0 } 5645809d537SMichael Leun }; 5655809d537SMichael Leun 56655d29c98SEric Piel static struct key_entry keymap_wistron_generic[] __initdata = { 5677b0a4cd7SEric Piel { KE_KEY, 0x01, {KEY_HELP} }, 5687b0a4cd7SEric Piel { KE_KEY, 0x02, {KEY_CONFIG} }, 5697b0a4cd7SEric Piel { KE_KEY, 0x03, {KEY_POWER} }, 5707b0a4cd7SEric Piel { KE_KEY, 0x05, {KEY_SWITCHVIDEOMODE} }, /* Display selection */ 5717b0a4cd7SEric Piel { KE_KEY, 0x06, {KEY_DISPLAYTOGGLE} }, /* Display on/off */ 5727b0a4cd7SEric Piel { KE_KEY, 0x08, {KEY_MUTE} }, 5737b0a4cd7SEric Piel { KE_KEY, 0x11, {KEY_PROG1} }, 5747b0a4cd7SEric Piel { KE_KEY, 0x12, {KEY_PROG2} }, 5757b0a4cd7SEric Piel { KE_KEY, 0x13, {KEY_PROG3} }, 5767b0a4cd7SEric Piel { KE_KEY, 0x14, {KEY_MAIL} }, 5777b0a4cd7SEric Piel { KE_KEY, 0x15, {KEY_WWW} }, 5787b0a4cd7SEric Piel { KE_KEY, 0x20, {KEY_VOLUMEUP} }, 5797b0a4cd7SEric Piel { KE_KEY, 0x21, {KEY_VOLUMEDOWN} }, 5807b0a4cd7SEric Piel { KE_KEY, 0x22, {KEY_REWIND} }, 5817b0a4cd7SEric Piel { KE_KEY, 0x23, {KEY_FORWARD} }, 5827b0a4cd7SEric Piel { KE_KEY, 0x24, {KEY_PLAYPAUSE} }, 5837b0a4cd7SEric Piel { KE_KEY, 0x25, {KEY_STOPCD} }, 5847b0a4cd7SEric Piel { KE_KEY, 0x31, {KEY_MAIL} }, 5857b0a4cd7SEric Piel { KE_KEY, 0x36, {KEY_WWW} }, 5867b0a4cd7SEric Piel { KE_KEY, 0x37, {KEY_DISPLAYTOGGLE} }, /* Display on/off */ 5877b0a4cd7SEric Piel { KE_KEY, 0x40, {KEY_WLAN} }, 5887b0a4cd7SEric Piel { KE_KEY, 0x49, {KEY_CONFIG} }, 5897b0a4cd7SEric Piel { KE_SW, 0x4a, {.sw = {SW_LID, 1}} }, /* lid close */ 5907b0a4cd7SEric Piel { KE_SW, 0x4b, {.sw = {SW_LID, 0}} }, /* lid open */ 5917b0a4cd7SEric Piel { KE_KEY, 0x6a, {KEY_CONFIG} }, 5927b0a4cd7SEric Piel { KE_KEY, 0x6d, {KEY_POWER} }, 5937b0a4cd7SEric Piel { KE_KEY, 0x71, {KEY_STOPCD} }, 5947b0a4cd7SEric Piel { KE_KEY, 0x72, {KEY_PLAYPAUSE} }, 5957b0a4cd7SEric Piel { KE_KEY, 0x74, {KEY_REWIND} }, 5967b0a4cd7SEric Piel { KE_KEY, 0x78, {KEY_FORWARD} }, 5977b0a4cd7SEric Piel { KE_WIFI, 0x30 }, 5987b0a4cd7SEric Piel { KE_BLUETOOTH, 0x44 }, 5997b0a4cd7SEric Piel { KE_END, 0 } 6007b0a4cd7SEric Piel }; 6017b0a4cd7SEric Piel 60285927b0dSDmitry Torokhov static struct key_entry keymap_aopen_1557[] __initdata = { 60385927b0dSDmitry Torokhov { KE_KEY, 0x01, {KEY_HELP} }, 60485927b0dSDmitry Torokhov { KE_KEY, 0x11, {KEY_PROG1} }, 60585927b0dSDmitry Torokhov { KE_KEY, 0x12, {KEY_PROG2} }, 60685927b0dSDmitry Torokhov { KE_WIFI, 0x30 }, 60785927b0dSDmitry Torokhov { KE_KEY, 0x22, {KEY_REWIND} }, 60885927b0dSDmitry Torokhov { KE_KEY, 0x23, {KEY_FORWARD} }, 60985927b0dSDmitry Torokhov { KE_KEY, 0x24, {KEY_PLAYPAUSE} }, 61085927b0dSDmitry Torokhov { KE_KEY, 0x25, {KEY_STOPCD} }, 61185927b0dSDmitry Torokhov { KE_KEY, 0x31, {KEY_MAIL} }, 61285927b0dSDmitry Torokhov { KE_KEY, 0x36, {KEY_WWW} }, 61385927b0dSDmitry Torokhov { KE_END, 0 } 61485927b0dSDmitry Torokhov }; 61585927b0dSDmitry Torokhov 61619493478STJ static struct key_entry keymap_prestigio[] __initdata = { 61719493478STJ { KE_KEY, 0x11, {KEY_PROG1} }, 61819493478STJ { KE_KEY, 0x12, {KEY_PROG2} }, 61919493478STJ { KE_WIFI, 0x30 }, 62019493478STJ { KE_KEY, 0x22, {KEY_REWIND} }, 62119493478STJ { KE_KEY, 0x23, {KEY_FORWARD} }, 62219493478STJ { KE_KEY, 0x24, {KEY_PLAYPAUSE} }, 62319493478STJ { KE_KEY, 0x25, {KEY_STOPCD} }, 62419493478STJ { KE_KEY, 0x31, {KEY_MAIL} }, 62519493478STJ { KE_KEY, 0x36, {KEY_WWW} }, 62619493478STJ { KE_END, 0 } 62719493478STJ }; 62819493478STJ 62919493478STJ 6305fc14680SDmitry Torokhov /* 6315fc14680SDmitry Torokhov * If your machine is not here (which is currently rather likely), please send 6325fc14680SDmitry Torokhov * a list of buttons and their key codes (reported when loading this module 6335fc14680SDmitry Torokhov * with force=1) and the output of dmidecode to $MODULE_AUTHOR. 6345fc14680SDmitry Torokhov */ 63598f6e5d1SSachin Kamat static const struct dmi_system_id dmi_ids[] __initconst = { 6365fc14680SDmitry Torokhov { 637a9b0d0e5SDmitry Torokhov /* Fujitsu-Siemens Amilo Pro V2000 */ 6385fc14680SDmitry Torokhov .callback = dmi_matched, 6395fc14680SDmitry Torokhov .matches = { 6405fc14680SDmitry Torokhov DMI_MATCH(DMI_SYS_VENDOR, "FUJITSU SIEMENS"), 6415fc14680SDmitry Torokhov DMI_MATCH(DMI_PRODUCT_NAME, "AMILO Pro V2000"), 6425fc14680SDmitry Torokhov }, 6435fc14680SDmitry Torokhov .driver_data = keymap_fs_amilo_pro_v2000 6445fc14680SDmitry Torokhov }, 64584b256a6SBernhard Rosenkraenzer { 646a9b0d0e5SDmitry Torokhov /* Fujitsu-Siemens Amilo Pro Edition V3505 */ 64784b256a6SBernhard Rosenkraenzer .callback = dmi_matched, 64834a7c48cSRemi Herilier .matches = { 64934a7c48cSRemi Herilier DMI_MATCH(DMI_SYS_VENDOR, "FUJITSU SIEMENS"), 65034a7c48cSRemi Herilier DMI_MATCH(DMI_PRODUCT_NAME, "AMILO Pro Edition V3505"), 65134a7c48cSRemi Herilier }, 65234a7c48cSRemi Herilier .driver_data = keymap_fs_amilo_pro_v3505 65334a7c48cSRemi Herilier }, 65434a7c48cSRemi Herilier { 65511601a82SJakub Bogusz /* Fujitsu-Siemens Amilo Pro Edition V8210 */ 65611601a82SJakub Bogusz .callback = dmi_matched, 65711601a82SJakub Bogusz .matches = { 65811601a82SJakub Bogusz DMI_MATCH(DMI_SYS_VENDOR, "FUJITSU SIEMENS"), 65911601a82SJakub Bogusz DMI_MATCH(DMI_PRODUCT_NAME, "AMILO Pro Series V8210"), 66011601a82SJakub Bogusz }, 66111601a82SJakub Bogusz .driver_data = keymap_fs_amilo_pro_v8210 66211601a82SJakub Bogusz }, 66311601a82SJakub Bogusz { 664a9b0d0e5SDmitry Torokhov /* Fujitsu-Siemens Amilo M7400 */ 66534a7c48cSRemi Herilier .callback = dmi_matched, 6668a1b1708SStefan Rompf .matches = { 6678a1b1708SStefan Rompf DMI_MATCH(DMI_SYS_VENDOR, "FUJITSU SIEMENS"), 6688a1b1708SStefan Rompf DMI_MATCH(DMI_PRODUCT_NAME, "AMILO M "), 6698a1b1708SStefan Rompf }, 6708a1b1708SStefan Rompf .driver_data = keymap_fs_amilo_pro_v2000 6718a1b1708SStefan Rompf }, 6728a1b1708SStefan Rompf { 673a9b0d0e5SDmitry Torokhov /* Maxdata Pro 7000 DX */ 6748a1b1708SStefan Rompf .callback = dmi_matched, 675e705cee4SGiuseppe Mazzotta .matches = { 676e705cee4SGiuseppe Mazzotta DMI_MATCH(DMI_SYS_VENDOR, "MAXDATA"), 677e705cee4SGiuseppe Mazzotta DMI_MATCH(DMI_PRODUCT_NAME, "Pro 7000"), 678e705cee4SGiuseppe Mazzotta }, 679e705cee4SGiuseppe Mazzotta .driver_data = keymap_fs_amilo_pro_v2000 680e705cee4SGiuseppe Mazzotta }, 681e705cee4SGiuseppe Mazzotta { 682a9b0d0e5SDmitry Torokhov /* Fujitsu N3510 */ 683e705cee4SGiuseppe Mazzotta .callback = dmi_matched, 684e2aa507aSJohn Reed Riley .matches = { 685e2aa507aSJohn Reed Riley DMI_MATCH(DMI_SYS_VENDOR, "FUJITSU"), 686e2aa507aSJohn Reed Riley DMI_MATCH(DMI_PRODUCT_NAME, "N3510"), 687e2aa507aSJohn Reed Riley }, 688e2aa507aSJohn Reed Riley .driver_data = keymap_fujitsu_n3510 689e2aa507aSJohn Reed Riley }, 690e2aa507aSJohn Reed Riley { 691a9b0d0e5SDmitry Torokhov /* Acer Aspire 1500 */ 692e2aa507aSJohn Reed Riley .callback = dmi_matched, 69384b256a6SBernhard Rosenkraenzer .matches = { 69484b256a6SBernhard Rosenkraenzer DMI_MATCH(DMI_SYS_VENDOR, "Acer"), 69584b256a6SBernhard Rosenkraenzer DMI_MATCH(DMI_PRODUCT_NAME, "Aspire 1500"), 69684b256a6SBernhard Rosenkraenzer }, 69784b256a6SBernhard Rosenkraenzer .driver_data = keymap_acer_aspire_1500 69884b256a6SBernhard Rosenkraenzer }, 69974a89c96SAshutosh Naik { 700a9b0d0e5SDmitry Torokhov /* Acer Aspire 1600 */ 70174a89c96SAshutosh Naik .callback = dmi_matched, 7026480e2a2SEric Piel .matches = { 7036480e2a2SEric Piel DMI_MATCH(DMI_SYS_VENDOR, "Acer"), 7046480e2a2SEric Piel DMI_MATCH(DMI_PRODUCT_NAME, "Aspire 1600"), 7056480e2a2SEric Piel }, 7066480e2a2SEric Piel .driver_data = keymap_acer_aspire_1600 7076480e2a2SEric Piel }, 7086480e2a2SEric Piel { 709a9b0d0e5SDmitry Torokhov /* Acer Aspire 3020 */ 7106480e2a2SEric Piel .callback = dmi_matched, 7116480e2a2SEric Piel .matches = { 7126480e2a2SEric Piel DMI_MATCH(DMI_SYS_VENDOR, "Acer"), 7136480e2a2SEric Piel DMI_MATCH(DMI_PRODUCT_NAME, "Aspire 3020"), 7146480e2a2SEric Piel }, 7156480e2a2SEric Piel .driver_data = keymap_acer_aspire_5020 7166480e2a2SEric Piel }, 7176480e2a2SEric Piel { 718a9b0d0e5SDmitry Torokhov /* Acer Aspire 5020 */ 7196480e2a2SEric Piel .callback = dmi_matched, 7206480e2a2SEric Piel .matches = { 7216480e2a2SEric Piel DMI_MATCH(DMI_SYS_VENDOR, "Acer"), 7226480e2a2SEric Piel DMI_MATCH(DMI_PRODUCT_NAME, "Aspire 5020"), 7236480e2a2SEric Piel }, 7246480e2a2SEric Piel .driver_data = keymap_acer_aspire_5020 7256480e2a2SEric Piel }, 7266480e2a2SEric Piel { 727a9b0d0e5SDmitry Torokhov /* Acer TravelMate 2100 */ 7286480e2a2SEric Piel .callback = dmi_matched, 7296480e2a2SEric Piel .matches = { 7306480e2a2SEric Piel DMI_MATCH(DMI_SYS_VENDOR, "Acer"), 7316480e2a2SEric Piel DMI_MATCH(DMI_PRODUCT_NAME, "TravelMate 2100"), 7326480e2a2SEric Piel }, 7336480e2a2SEric Piel .driver_data = keymap_acer_aspire_5020 7346480e2a2SEric Piel }, 7356480e2a2SEric Piel { 736a9b0d0e5SDmitry Torokhov /* Acer TravelMate 2410 */ 7376480e2a2SEric Piel .callback = dmi_matched, 7386480e2a2SEric Piel .matches = { 7396480e2a2SEric Piel DMI_MATCH(DMI_SYS_VENDOR, "Acer"), 7406480e2a2SEric Piel DMI_MATCH(DMI_PRODUCT_NAME, "TravelMate 2410"), 7416480e2a2SEric Piel }, 7426480e2a2SEric Piel .driver_data = keymap_acer_travelmate_2410 7436480e2a2SEric Piel }, 7446480e2a2SEric Piel { 745a9b0d0e5SDmitry Torokhov /* Acer TravelMate C300 */ 7466480e2a2SEric Piel .callback = dmi_matched, 7476480e2a2SEric Piel .matches = { 7486480e2a2SEric Piel DMI_MATCH(DMI_SYS_VENDOR, "Acer"), 7496480e2a2SEric Piel DMI_MATCH(DMI_PRODUCT_NAME, "TravelMate C300"), 7506480e2a2SEric Piel }, 7516480e2a2SEric Piel .driver_data = keymap_acer_travelmate_300 7526480e2a2SEric Piel }, 7536480e2a2SEric Piel { 754a9b0d0e5SDmitry Torokhov /* Acer TravelMate C100 */ 7556480e2a2SEric Piel .callback = dmi_matched, 7566480e2a2SEric Piel .matches = { 7576480e2a2SEric Piel DMI_MATCH(DMI_SYS_VENDOR, "Acer"), 7586480e2a2SEric Piel DMI_MATCH(DMI_PRODUCT_NAME, "TravelMate C100"), 7596480e2a2SEric Piel }, 7606480e2a2SEric Piel .driver_data = keymap_acer_travelmate_300 7616480e2a2SEric Piel }, 7626480e2a2SEric Piel { 763a9b0d0e5SDmitry Torokhov /* Acer TravelMate C110 */ 7646480e2a2SEric Piel .callback = dmi_matched, 7656480e2a2SEric Piel .matches = { 7666480e2a2SEric Piel DMI_MATCH(DMI_SYS_VENDOR, "Acer"), 7676480e2a2SEric Piel DMI_MATCH(DMI_PRODUCT_NAME, "TravelMate C110"), 7686480e2a2SEric Piel }, 7696480e2a2SEric Piel .driver_data = keymap_acer_travelmate_110 7706480e2a2SEric Piel }, 7716480e2a2SEric Piel { 772a9b0d0e5SDmitry Torokhov /* Acer TravelMate 380 */ 7736480e2a2SEric Piel .callback = dmi_matched, 7746480e2a2SEric Piel .matches = { 7756480e2a2SEric Piel DMI_MATCH(DMI_SYS_VENDOR, "Acer"), 7766480e2a2SEric Piel DMI_MATCH(DMI_PRODUCT_NAME, "TravelMate 380"), 7776480e2a2SEric Piel }, 7786480e2a2SEric Piel .driver_data = keymap_acer_travelmate_380 7796480e2a2SEric Piel }, 7806480e2a2SEric Piel { 781a9b0d0e5SDmitry Torokhov /* Acer TravelMate 370 */ 7826480e2a2SEric Piel .callback = dmi_matched, 7836480e2a2SEric Piel .matches = { 7846480e2a2SEric Piel DMI_MATCH(DMI_SYS_VENDOR, "Acer"), 7856480e2a2SEric Piel DMI_MATCH(DMI_PRODUCT_NAME, "TravelMate 370"), 7866480e2a2SEric Piel }, 7876480e2a2SEric Piel .driver_data = keymap_acer_travelmate_380 /* keyboard minus 1 key */ 7886480e2a2SEric Piel }, 7896480e2a2SEric Piel { 790a9b0d0e5SDmitry Torokhov /* Acer TravelMate 220 */ 7916480e2a2SEric Piel .callback = dmi_matched, 7926480e2a2SEric Piel .matches = { 7936480e2a2SEric Piel DMI_MATCH(DMI_SYS_VENDOR, "Acer"), 7946480e2a2SEric Piel DMI_MATCH(DMI_PRODUCT_NAME, "TravelMate 220"), 7956480e2a2SEric Piel }, 7966480e2a2SEric Piel .driver_data = keymap_acer_travelmate_220 7976480e2a2SEric Piel }, 7986480e2a2SEric Piel { 799a9b0d0e5SDmitry Torokhov /* Acer TravelMate 260 */ 8006480e2a2SEric Piel .callback = dmi_matched, 8016480e2a2SEric Piel .matches = { 8026480e2a2SEric Piel DMI_MATCH(DMI_SYS_VENDOR, "Acer"), 8036480e2a2SEric Piel DMI_MATCH(DMI_PRODUCT_NAME, "TravelMate 260"), 8046480e2a2SEric Piel }, 8056480e2a2SEric Piel .driver_data = keymap_acer_travelmate_220 8066480e2a2SEric Piel }, 8076480e2a2SEric Piel { 808a9b0d0e5SDmitry Torokhov /* Acer TravelMate 230 */ 8096480e2a2SEric Piel .callback = dmi_matched, 8106480e2a2SEric Piel .matches = { 8116480e2a2SEric Piel DMI_MATCH(DMI_SYS_VENDOR, "Acer"), 8126480e2a2SEric Piel DMI_MATCH(DMI_PRODUCT_NAME, "TravelMate 230"), 8136480e2a2SEric Piel /* acerhk looks for "TravelMate F4..." ?! */ 8146480e2a2SEric Piel }, 8156480e2a2SEric Piel .driver_data = keymap_acer_travelmate_230 8166480e2a2SEric Piel }, 8176480e2a2SEric Piel { 818a9b0d0e5SDmitry Torokhov /* Acer TravelMate 280 */ 8196480e2a2SEric Piel .callback = dmi_matched, 8206480e2a2SEric Piel .matches = { 8216480e2a2SEric Piel DMI_MATCH(DMI_SYS_VENDOR, "Acer"), 8226480e2a2SEric Piel DMI_MATCH(DMI_PRODUCT_NAME, "TravelMate 280"), 8236480e2a2SEric Piel }, 8246480e2a2SEric Piel .driver_data = keymap_acer_travelmate_230 8256480e2a2SEric Piel }, 8266480e2a2SEric Piel { 827a9b0d0e5SDmitry Torokhov /* Acer TravelMate 240 */ 8286480e2a2SEric Piel .callback = dmi_matched, 82974a89c96SAshutosh Naik .matches = { 83074a89c96SAshutosh Naik DMI_MATCH(DMI_SYS_VENDOR, "Acer"), 83174a89c96SAshutosh Naik DMI_MATCH(DMI_PRODUCT_NAME, "TravelMate 240"), 83274a89c96SAshutosh Naik }, 83374a89c96SAshutosh Naik .driver_data = keymap_acer_travelmate_240 83474a89c96SAshutosh Naik }, 835e107b8eeSmasc@theaterzentrum.at { 836a9b0d0e5SDmitry Torokhov /* Acer TravelMate 250 */ 837bb088590SAshutosh Naik .callback = dmi_matched, 8386480e2a2SEric Piel .matches = { 8396480e2a2SEric Piel DMI_MATCH(DMI_SYS_VENDOR, "Acer"), 8406480e2a2SEric Piel DMI_MATCH(DMI_PRODUCT_NAME, "TravelMate 250"), 8416480e2a2SEric Piel }, 8426480e2a2SEric Piel .driver_data = keymap_acer_travelmate_240 8436480e2a2SEric Piel }, 8446480e2a2SEric Piel { 845a9b0d0e5SDmitry Torokhov /* Acer TravelMate 2424NWXCi */ 8466480e2a2SEric Piel .callback = dmi_matched, 847bb088590SAshutosh Naik .matches = { 848bb088590SAshutosh Naik DMI_MATCH(DMI_SYS_VENDOR, "Acer"), 849bb088590SAshutosh Naik DMI_MATCH(DMI_PRODUCT_NAME, "TravelMate 2420"), 850bb088590SAshutosh Naik }, 851bb088590SAshutosh Naik .driver_data = keymap_acer_travelmate_240 852bb088590SAshutosh Naik }, 853bb088590SAshutosh Naik { 854a9b0d0e5SDmitry Torokhov /* Acer TravelMate 350 */ 855e107b8eeSmasc@theaterzentrum.at .callback = dmi_matched, 8566480e2a2SEric Piel .matches = { 8576480e2a2SEric Piel DMI_MATCH(DMI_SYS_VENDOR, "Acer"), 8586480e2a2SEric Piel DMI_MATCH(DMI_PRODUCT_NAME, "TravelMate 350"), 8596480e2a2SEric Piel }, 8606480e2a2SEric Piel .driver_data = keymap_acer_travelmate_350 8616480e2a2SEric Piel }, 8626480e2a2SEric Piel { 863a9b0d0e5SDmitry Torokhov /* Acer TravelMate 360 */ 8646480e2a2SEric Piel .callback = dmi_matched, 8656480e2a2SEric Piel .matches = { 8666480e2a2SEric Piel DMI_MATCH(DMI_SYS_VENDOR, "Acer"), 8676480e2a2SEric Piel DMI_MATCH(DMI_PRODUCT_NAME, "TravelMate 360"), 8686480e2a2SEric Piel }, 8696480e2a2SEric Piel .driver_data = keymap_acer_travelmate_360 8706480e2a2SEric Piel }, 8716480e2a2SEric Piel { 872a9b0d0e5SDmitry Torokhov /* Acer TravelMate 610 */ 8736480e2a2SEric Piel .callback = dmi_matched, 874bc413c95SEric Piel .matches = { 875bc413c95SEric Piel DMI_MATCH(DMI_SYS_VENDOR, "ACER"), 876bc413c95SEric Piel DMI_MATCH(DMI_PRODUCT_NAME, "TravelMate 610"), 877bc413c95SEric Piel }, 878bc413c95SEric Piel .driver_data = keymap_acer_travelmate_610 879bc413c95SEric Piel }, 880bc413c95SEric Piel { 881a9b0d0e5SDmitry Torokhov /* Acer TravelMate 620 */ 882bc413c95SEric Piel .callback = dmi_matched, 8836480e2a2SEric Piel .matches = { 8846480e2a2SEric Piel DMI_MATCH(DMI_SYS_VENDOR, "Acer"), 8856480e2a2SEric Piel DMI_MATCH(DMI_PRODUCT_NAME, "TravelMate 620"), 8866480e2a2SEric Piel }, 8876480e2a2SEric Piel .driver_data = keymap_acer_travelmate_630 8886480e2a2SEric Piel }, 8896480e2a2SEric Piel { 890a9b0d0e5SDmitry Torokhov /* Acer TravelMate 630 */ 8916480e2a2SEric Piel .callback = dmi_matched, 8926480e2a2SEric Piel .matches = { 8936480e2a2SEric Piel DMI_MATCH(DMI_SYS_VENDOR, "Acer"), 8946480e2a2SEric Piel DMI_MATCH(DMI_PRODUCT_NAME, "TravelMate 630"), 8956480e2a2SEric Piel }, 8966480e2a2SEric Piel .driver_data = keymap_acer_travelmate_630 8976480e2a2SEric Piel }, 8986480e2a2SEric Piel { 899a9b0d0e5SDmitry Torokhov /* AOpen 1559AS */ 9006480e2a2SEric Piel .callback = dmi_matched, 901e107b8eeSmasc@theaterzentrum.at .matches = { 902e107b8eeSmasc@theaterzentrum.at DMI_MATCH(DMI_PRODUCT_NAME, "E2U"), 903e107b8eeSmasc@theaterzentrum.at DMI_MATCH(DMI_BOARD_NAME, "E2U"), 904e107b8eeSmasc@theaterzentrum.at }, 905e107b8eeSmasc@theaterzentrum.at .driver_data = keymap_aopen_1559as 906e107b8eeSmasc@theaterzentrum.at }, 9079000195bSFrank de Lange { 908a9b0d0e5SDmitry Torokhov /* Medion MD 9783 */ 9099000195bSFrank de Lange .callback = dmi_matched, 9109000195bSFrank de Lange .matches = { 9119000195bSFrank de Lange DMI_MATCH(DMI_SYS_VENDOR, "MEDIONNB"), 9129000195bSFrank de Lange DMI_MATCH(DMI_PRODUCT_NAME, "MD 9783"), 9139000195bSFrank de Lange }, 9149000195bSFrank de Lange .driver_data = keymap_wistron_ms2111 9159000195bSFrank de Lange }, 9165809d537SMichael Leun { 917a9b0d0e5SDmitry Torokhov /* Medion MD 40100 */ 9185809d537SMichael Leun .callback = dmi_matched, 9196480e2a2SEric Piel .matches = { 9206480e2a2SEric Piel DMI_MATCH(DMI_SYS_VENDOR, "MEDIONNB"), 9216480e2a2SEric Piel DMI_MATCH(DMI_PRODUCT_NAME, "WID2000"), 9226480e2a2SEric Piel }, 9236480e2a2SEric Piel .driver_data = keymap_wistron_md40100 9246480e2a2SEric Piel }, 9256480e2a2SEric Piel { 926a9b0d0e5SDmitry Torokhov /* Medion MD 2900 */ 9276480e2a2SEric Piel .callback = dmi_matched, 9286480e2a2SEric Piel .matches = { 9296480e2a2SEric Piel DMI_MATCH(DMI_SYS_VENDOR, "MEDIONNB"), 9306480e2a2SEric Piel DMI_MATCH(DMI_PRODUCT_NAME, "WIM 2000"), 9316480e2a2SEric Piel }, 9326480e2a2SEric Piel .driver_data = keymap_wistron_md2900 9336480e2a2SEric Piel }, 9346480e2a2SEric Piel { 935a9b0d0e5SDmitry Torokhov /* Medion MD 42200 */ 9366480e2a2SEric Piel .callback = dmi_matched, 9373bfb0a7eSSebastian Frei .matches = { 9383bfb0a7eSSebastian Frei DMI_MATCH(DMI_SYS_VENDOR, "Medion"), 9393bfb0a7eSSebastian Frei DMI_MATCH(DMI_PRODUCT_NAME, "WIM 2030"), 9403bfb0a7eSSebastian Frei }, 9413bfb0a7eSSebastian Frei .driver_data = keymap_fs_amilo_pro_v2000 9423bfb0a7eSSebastian Frei }, 9433bfb0a7eSSebastian Frei { 944a9b0d0e5SDmitry Torokhov /* Medion MD 96500 */ 9453bfb0a7eSSebastian Frei .callback = dmi_matched, 9466480e2a2SEric Piel .matches = { 9476480e2a2SEric Piel DMI_MATCH(DMI_SYS_VENDOR, "MEDIONPC"), 9486480e2a2SEric Piel DMI_MATCH(DMI_PRODUCT_NAME, "WIM 2040"), 9496480e2a2SEric Piel }, 9506480e2a2SEric Piel .driver_data = keymap_wistron_md96500 9516480e2a2SEric Piel }, 9526480e2a2SEric Piel { 953a9b0d0e5SDmitry Torokhov /* Medion MD 95400 */ 9546480e2a2SEric Piel .callback = dmi_matched, 9556480e2a2SEric Piel .matches = { 9566480e2a2SEric Piel DMI_MATCH(DMI_SYS_VENDOR, "MEDIONPC"), 9576480e2a2SEric Piel DMI_MATCH(DMI_PRODUCT_NAME, "WIM 2050"), 9586480e2a2SEric Piel }, 9596480e2a2SEric Piel .driver_data = keymap_wistron_md96500 9606480e2a2SEric Piel }, 9616480e2a2SEric Piel { 962a9b0d0e5SDmitry Torokhov /* Fujitsu Siemens Amilo D7820 */ 9636480e2a2SEric Piel .callback = dmi_matched, 9646480e2a2SEric Piel .matches = { 9656480e2a2SEric Piel DMI_MATCH(DMI_SYS_VENDOR, "FUJITSU SIEMENS"), /* not sure */ 9666480e2a2SEric Piel DMI_MATCH(DMI_PRODUCT_NAME, "Amilo D"), 9676480e2a2SEric Piel }, 9686480e2a2SEric Piel .driver_data = keymap_fs_amilo_d88x0 9696480e2a2SEric Piel }, 9706480e2a2SEric Piel { 971a9b0d0e5SDmitry Torokhov /* Fujitsu Siemens Amilo D88x0 */ 9726480e2a2SEric Piel .callback = dmi_matched, 9735809d537SMichael Leun .matches = { 9745809d537SMichael Leun DMI_MATCH(DMI_SYS_VENDOR, "FUJITSU SIEMENS"), 9755809d537SMichael Leun DMI_MATCH(DMI_PRODUCT_NAME, "AMILO D"), 9765809d537SMichael Leun }, 9775809d537SMichael Leun .driver_data = keymap_fs_amilo_d88x0 9785809d537SMichael Leun }, 97981f0a91eSAl Viro { NULL, } 9805fc14680SDmitry Torokhov }; 981ac67be92SStefan Lippers-Hollmann MODULE_DEVICE_TABLE(dmi, dmi_ids); 9825fc14680SDmitry Torokhov 98355d29c98SEric Piel /* Copy the good keymap, as the original ones are free'd */ 98455d29c98SEric Piel static int __init copy_keymap(void) 98555d29c98SEric Piel { 98655d29c98SEric Piel const struct key_entry *key; 98755d29c98SEric Piel struct key_entry *new_keymap; 98855d29c98SEric Piel unsigned int length = 1; 98955d29c98SEric Piel 99055d29c98SEric Piel for (key = keymap; key->type != KE_END; key++) 99155d29c98SEric Piel length++; 99255d29c98SEric Piel 993f8300ab8SJulia Lawall new_keymap = kmemdup(keymap, length * sizeof(struct key_entry), 994f8300ab8SJulia Lawall GFP_KERNEL); 99555d29c98SEric Piel if (!new_keymap) 99655d29c98SEric Piel return -ENOMEM; 99755d29c98SEric Piel 99855d29c98SEric Piel keymap = new_keymap; 99955d29c98SEric Piel 100055d29c98SEric Piel return 0; 100155d29c98SEric Piel } 100255d29c98SEric Piel 10035fc14680SDmitry Torokhov static int __init select_keymap(void) 10045fc14680SDmitry Torokhov { 10057b0a4cd7SEric Piel dmi_check_system(dmi_ids); 10065fc14680SDmitry Torokhov if (keymap_name != NULL) { 10075fc14680SDmitry Torokhov if (strcmp (keymap_name, "1557/MS2141") == 0) 10085fc14680SDmitry Torokhov keymap = keymap_wistron_ms2141; 100985927b0dSDmitry Torokhov else if (strcmp (keymap_name, "aopen1557") == 0) 101085927b0dSDmitry Torokhov keymap = keymap_aopen_1557; 101119493478STJ else if (strcmp (keymap_name, "prestigio") == 0) 101219493478STJ keymap = keymap_prestigio; 10137b0a4cd7SEric Piel else if (strcmp (keymap_name, "generic") == 0) 10147b0a4cd7SEric Piel keymap = keymap_wistron_generic; 10155fc14680SDmitry Torokhov else { 10165fc14680SDmitry Torokhov printk(KERN_ERR "wistron_btns: Keymap unknown\n"); 10175fc14680SDmitry Torokhov return -EINVAL; 10185fc14680SDmitry Torokhov } 10195fc14680SDmitry Torokhov } 10205fc14680SDmitry Torokhov if (keymap == NULL) { 10215fc14680SDmitry Torokhov if (!force) { 10225fc14680SDmitry Torokhov printk(KERN_ERR "wistron_btns: System unknown\n"); 10235fc14680SDmitry Torokhov return -ENODEV; 10245fc14680SDmitry Torokhov } 10255fc14680SDmitry Torokhov keymap = keymap_empty; 10265fc14680SDmitry Torokhov } 102755d29c98SEric Piel 102855d29c98SEric Piel return copy_keymap(); 10295fc14680SDmitry Torokhov } 10305fc14680SDmitry Torokhov 10315fc14680SDmitry Torokhov /* Input layer interface */ 10325fc14680SDmitry Torokhov 10334a767ec3SDmitry Torokhov static struct input_dev *wistron_idev; 1034c2554c91SDmitry Torokhov static unsigned long jiffies_last_press; 103567dbe83aSDmitry Torokhov static bool wifi_enabled; 103667dbe83aSDmitry Torokhov static bool bluetooth_enabled; 10375fc14680SDmitry Torokhov 1038389679d8SEric Piel /* led management */ 1039389679d8SEric Piel static void wistron_mail_led_set(struct led_classdev *led_cdev, 1040389679d8SEric Piel enum led_brightness value) 1041389679d8SEric Piel { 1042389679d8SEric Piel bios_set_state(MAIL_LED, (value != LED_OFF) ? 1 : 0); 1043389679d8SEric Piel } 1044389679d8SEric Piel 1045389679d8SEric Piel /* same as setting up wifi card, but for laptops on which the led is managed */ 1046389679d8SEric Piel static void wistron_wifi_led_set(struct led_classdev *led_cdev, 1047389679d8SEric Piel enum led_brightness value) 1048389679d8SEric Piel { 1049389679d8SEric Piel bios_set_state(WIFI, (value != LED_OFF) ? 1 : 0); 1050389679d8SEric Piel } 1051389679d8SEric Piel 1052389679d8SEric Piel static struct led_classdev wistron_mail_led = { 10536c152beeSRichard Purdie .name = "wistron:green:mail", 1054389679d8SEric Piel .brightness_set = wistron_mail_led_set, 1055389679d8SEric Piel }; 1056389679d8SEric Piel 1057389679d8SEric Piel static struct led_classdev wistron_wifi_led = { 10586c152beeSRichard Purdie .name = "wistron:red:wifi", 1059389679d8SEric Piel .brightness_set = wistron_wifi_led_set, 1060389679d8SEric Piel }; 1061389679d8SEric Piel 10625298cc4cSBill Pemberton static void wistron_led_init(struct device *parent) 1063389679d8SEric Piel { 106467dbe83aSDmitry Torokhov if (leds_present & FE_WIFI_LED) { 1065389679d8SEric Piel u16 wifi = bios_get_default_setting(WIFI); 1066389679d8SEric Piel if (wifi & 1) { 1067389679d8SEric Piel wistron_wifi_led.brightness = (wifi & 2) ? LED_FULL : LED_OFF; 1068389679d8SEric Piel if (led_classdev_register(parent, &wistron_wifi_led)) 106967dbe83aSDmitry Torokhov leds_present &= ~FE_WIFI_LED; 1070389679d8SEric Piel else 1071389679d8SEric Piel bios_set_state(WIFI, wistron_wifi_led.brightness); 1072389679d8SEric Piel 1073389679d8SEric Piel } else 107467dbe83aSDmitry Torokhov leds_present &= ~FE_WIFI_LED; 1075389679d8SEric Piel } 1076389679d8SEric Piel 107767dbe83aSDmitry Torokhov if (leds_present & FE_MAIL_LED) { 1078389679d8SEric Piel /* bios_get_default_setting(MAIL) always retuns 0, so just turn the led off */ 1079389679d8SEric Piel wistron_mail_led.brightness = LED_OFF; 1080389679d8SEric Piel if (led_classdev_register(parent, &wistron_mail_led)) 108167dbe83aSDmitry Torokhov leds_present &= ~FE_MAIL_LED; 1082389679d8SEric Piel else 1083389679d8SEric Piel bios_set_state(MAIL_LED, wistron_mail_led.brightness); 1084389679d8SEric Piel } 1085389679d8SEric Piel } 1086389679d8SEric Piel 1087e2619cf7SBill Pemberton static void wistron_led_remove(void) 1088389679d8SEric Piel { 108967dbe83aSDmitry Torokhov if (leds_present & FE_MAIL_LED) 1090389679d8SEric Piel led_classdev_unregister(&wistron_mail_led); 1091389679d8SEric Piel 109267dbe83aSDmitry Torokhov if (leds_present & FE_WIFI_LED) 1093389679d8SEric Piel led_classdev_unregister(&wistron_wifi_led); 1094389679d8SEric Piel } 1095389679d8SEric Piel 1096389679d8SEric Piel static inline void wistron_led_suspend(void) 1097389679d8SEric Piel { 109867dbe83aSDmitry Torokhov if (leds_present & FE_MAIL_LED) 1099389679d8SEric Piel led_classdev_suspend(&wistron_mail_led); 1100389679d8SEric Piel 110167dbe83aSDmitry Torokhov if (leds_present & FE_WIFI_LED) 1102389679d8SEric Piel led_classdev_suspend(&wistron_wifi_led); 1103389679d8SEric Piel } 1104389679d8SEric Piel 1105389679d8SEric Piel static inline void wistron_led_resume(void) 1106389679d8SEric Piel { 110767dbe83aSDmitry Torokhov if (leds_present & FE_MAIL_LED) 1108389679d8SEric Piel led_classdev_resume(&wistron_mail_led); 1109389679d8SEric Piel 111067dbe83aSDmitry Torokhov if (leds_present & FE_WIFI_LED) 1111389679d8SEric Piel led_classdev_resume(&wistron_wifi_led); 1112389679d8SEric Piel } 1113389679d8SEric Piel 11145fc14680SDmitry Torokhov static void handle_key(u8 code) 11155fc14680SDmitry Torokhov { 1116e97af4cbSDmitry Torokhov const struct key_entry *key = 11174a767ec3SDmitry Torokhov sparse_keymap_entry_from_scancode(wistron_idev, code); 11185fc14680SDmitry Torokhov 1119d63219a1SDmitry Torokhov if (key) { 11205fc14680SDmitry Torokhov switch (key->type) { 11215fc14680SDmitry Torokhov case KE_WIFI: 11225fc14680SDmitry Torokhov if (have_wifi) { 11235fc14680SDmitry Torokhov wifi_enabled = !wifi_enabled; 112484b256a6SBernhard Rosenkraenzer bios_set_state(WIFI, wifi_enabled); 112584b256a6SBernhard Rosenkraenzer } 112684b256a6SBernhard Rosenkraenzer break; 112784b256a6SBernhard Rosenkraenzer 112884b256a6SBernhard Rosenkraenzer case KE_BLUETOOTH: 112984b256a6SBernhard Rosenkraenzer if (have_bluetooth) { 113084b256a6SBernhard Rosenkraenzer bluetooth_enabled = !bluetooth_enabled; 113184b256a6SBernhard Rosenkraenzer bios_set_state(BLUETOOTH, bluetooth_enabled); 11325fc14680SDmitry Torokhov } 11335fc14680SDmitry Torokhov break; 11345fc14680SDmitry Torokhov 11355fc14680SDmitry Torokhov default: 11364a767ec3SDmitry Torokhov sparse_keymap_report_entry(wistron_idev, key, 1, true); 1137e97af4cbSDmitry Torokhov break; 11385fc14680SDmitry Torokhov } 1139c2554c91SDmitry Torokhov jiffies_last_press = jiffies; 11404a767ec3SDmitry Torokhov } else { 1141d63219a1SDmitry Torokhov printk(KERN_NOTICE 1142d63219a1SDmitry Torokhov "wistron_btns: Unknown key code %02X\n", code); 11435fc14680SDmitry Torokhov } 11444a767ec3SDmitry Torokhov } 11455fc14680SDmitry Torokhov 1146c2554c91SDmitry Torokhov static void poll_bios(bool discard) 11475fc14680SDmitry Torokhov { 11485fc14680SDmitry Torokhov u8 qlen; 11495fc14680SDmitry Torokhov u16 val; 11505fc14680SDmitry Torokhov 11515fc14680SDmitry Torokhov for (;;) { 11525fc14680SDmitry Torokhov qlen = CMOS_READ(cmos_address); 11535fc14680SDmitry Torokhov if (qlen == 0) 11545fc14680SDmitry Torokhov break; 11555fc14680SDmitry Torokhov val = bios_pop_queue(); 1156c2554c91SDmitry Torokhov if (val != 0 && !discard) 11575fc14680SDmitry Torokhov handle_key((u8)val); 1158a4da16d3SEric Piel } 11595fc14680SDmitry Torokhov } 11605fc14680SDmitry Torokhov 11614a767ec3SDmitry Torokhov static int wistron_flush(struct input_dev *dev) 1162c2554c91SDmitry Torokhov { 1163c2554c91SDmitry Torokhov /* Flush stale event queue */ 1164c2554c91SDmitry Torokhov poll_bios(true); 11654a767ec3SDmitry Torokhov 11664a767ec3SDmitry Torokhov return 0; 11675fc14680SDmitry Torokhov } 11685fc14680SDmitry Torokhov 11694a767ec3SDmitry Torokhov static void wistron_poll(struct input_dev *dev) 1170c2554c91SDmitry Torokhov { 1171c2554c91SDmitry Torokhov poll_bios(false); 1172c2554c91SDmitry Torokhov 1173c2554c91SDmitry Torokhov /* Increase poll frequency if user is currently pressing keys (< 2s ago) */ 1174c2554c91SDmitry Torokhov if (time_before(jiffies, jiffies_last_press + 2 * HZ)) 11754a767ec3SDmitry Torokhov input_set_poll_interval(dev, POLL_INTERVAL_BURST); 1176c2554c91SDmitry Torokhov else 11774a767ec3SDmitry Torokhov input_set_poll_interval(dev, POLL_INTERVAL_DEFAULT); 1178c2554c91SDmitry Torokhov } 1179c2554c91SDmitry Torokhov 11805298cc4cSBill Pemberton static int wistron_setup_keymap(struct input_dev *dev, 1181e97af4cbSDmitry Torokhov struct key_entry *entry) 1182d63219a1SDmitry Torokhov { 1183e97af4cbSDmitry Torokhov switch (entry->type) { 1184d63219a1SDmitry Torokhov 1185e97af4cbSDmitry Torokhov /* if wifi or bluetooth are not available, create normal keys */ 1186e97af4cbSDmitry Torokhov case KE_WIFI: 1187e97af4cbSDmitry Torokhov if (!have_wifi) { 1188e97af4cbSDmitry Torokhov entry->type = KE_KEY; 1189e97af4cbSDmitry Torokhov entry->keycode = KEY_WLAN; 1190e97af4cbSDmitry Torokhov } 1191e97af4cbSDmitry Torokhov break; 1192e97af4cbSDmitry Torokhov 1193e97af4cbSDmitry Torokhov case KE_BLUETOOTH: 1194e97af4cbSDmitry Torokhov if (!have_bluetooth) { 1195e97af4cbSDmitry Torokhov entry->type = KE_KEY; 1196e97af4cbSDmitry Torokhov entry->keycode = KEY_BLUETOOTH; 1197e97af4cbSDmitry Torokhov } 1198e97af4cbSDmitry Torokhov break; 1199e97af4cbSDmitry Torokhov 1200e97af4cbSDmitry Torokhov case KE_END: 1201e97af4cbSDmitry Torokhov if (entry->code & FE_UNTESTED) 1202e97af4cbSDmitry Torokhov printk(KERN_WARNING "Untested laptop multimedia keys, " 1203e97af4cbSDmitry Torokhov "please report success or failure to " 1204e97af4cbSDmitry Torokhov "eric.piel@tremplin-utc.net\n"); 1205e97af4cbSDmitry Torokhov break; 1206e97af4cbSDmitry Torokhov } 1207e97af4cbSDmitry Torokhov 1208d63219a1SDmitry Torokhov return 0; 1209d63219a1SDmitry Torokhov } 1210d63219a1SDmitry Torokhov 12115298cc4cSBill Pemberton static int setup_input_dev(void) 1212c2554c91SDmitry Torokhov { 1213c2554c91SDmitry Torokhov int error; 1214c2554c91SDmitry Torokhov 12154a767ec3SDmitry Torokhov wistron_idev = input_allocate_device(); 1216c2554c91SDmitry Torokhov if (!wistron_idev) 1217c2554c91SDmitry Torokhov return -ENOMEM; 1218c2554c91SDmitry Torokhov 12194a767ec3SDmitry Torokhov wistron_idev->name = "Wistron laptop buttons"; 12204a767ec3SDmitry Torokhov wistron_idev->phys = "wistron/input0"; 12214a767ec3SDmitry Torokhov wistron_idev->id.bustype = BUS_HOST; 12224a767ec3SDmitry Torokhov wistron_idev->dev.parent = &wistron_device->dev; 12234a767ec3SDmitry Torokhov 1224b0aba1e6SSamu Onkalo wistron_idev->open = wistron_flush; 1225c2554c91SDmitry Torokhov 12264a767ec3SDmitry Torokhov error = sparse_keymap_setup(wistron_idev, keymap, wistron_setup_keymap); 1227e97af4cbSDmitry Torokhov if (error) 1228e97af4cbSDmitry Torokhov goto err_free_dev; 1229c2554c91SDmitry Torokhov 12304a767ec3SDmitry Torokhov error = input_setup_polling(wistron_idev, wistron_poll); 12314a767ec3SDmitry Torokhov if (error) 12324a767ec3SDmitry Torokhov goto err_free_dev; 12334a767ec3SDmitry Torokhov 12344a767ec3SDmitry Torokhov input_set_poll_interval(wistron_idev, POLL_INTERVAL_DEFAULT); 12354a767ec3SDmitry Torokhov 12364a767ec3SDmitry Torokhov error = input_register_device(wistron_idev); 1237e97af4cbSDmitry Torokhov if (error) 1238fc2a6e50SDmitry Torokhov goto err_free_dev; 1239c2554c91SDmitry Torokhov 1240c2554c91SDmitry Torokhov return 0; 1241e97af4cbSDmitry Torokhov 1242e97af4cbSDmitry Torokhov err_free_dev: 12434a767ec3SDmitry Torokhov input_free_device(wistron_idev); 1244e97af4cbSDmitry Torokhov return error; 1245c2554c91SDmitry Torokhov } 1246c2554c91SDmitry Torokhov 1247c2554c91SDmitry Torokhov /* Driver core */ 1248c2554c91SDmitry Torokhov 12495298cc4cSBill Pemberton static int wistron_probe(struct platform_device *dev) 1250e7c3aad5SDmitry Torokhov { 1251c2554c91SDmitry Torokhov int err; 1252e7c3aad5SDmitry Torokhov 1253e7c3aad5SDmitry Torokhov bios_attach(); 1254e7c3aad5SDmitry Torokhov cmos_address = bios_get_cmos_address(); 1255e7c3aad5SDmitry Torokhov 1256e7c3aad5SDmitry Torokhov if (have_wifi) { 1257e7c3aad5SDmitry Torokhov u16 wifi = bios_get_default_setting(WIFI); 1258e7c3aad5SDmitry Torokhov if (wifi & 1) 125967dbe83aSDmitry Torokhov wifi_enabled = wifi & 2; 1260e7c3aad5SDmitry Torokhov else 1261e7c3aad5SDmitry Torokhov have_wifi = 0; 1262e7c3aad5SDmitry Torokhov 1263e7c3aad5SDmitry Torokhov if (have_wifi) 1264e7c3aad5SDmitry Torokhov bios_set_state(WIFI, wifi_enabled); 1265e7c3aad5SDmitry Torokhov } 1266e7c3aad5SDmitry Torokhov 1267e7c3aad5SDmitry Torokhov if (have_bluetooth) { 1268e7c3aad5SDmitry Torokhov u16 bt = bios_get_default_setting(BLUETOOTH); 1269e7c3aad5SDmitry Torokhov if (bt & 1) 127067dbe83aSDmitry Torokhov bluetooth_enabled = bt & 2; 1271e7c3aad5SDmitry Torokhov else 127267dbe83aSDmitry Torokhov have_bluetooth = false; 1273e7c3aad5SDmitry Torokhov 1274e7c3aad5SDmitry Torokhov if (have_bluetooth) 1275e7c3aad5SDmitry Torokhov bios_set_state(BLUETOOTH, bluetooth_enabled); 1276e7c3aad5SDmitry Torokhov } 1277e7c3aad5SDmitry Torokhov 1278389679d8SEric Piel wistron_led_init(&dev->dev); 127967dbe83aSDmitry Torokhov 1280c2554c91SDmitry Torokhov err = setup_input_dev(); 1281c2554c91SDmitry Torokhov if (err) { 1282c2554c91SDmitry Torokhov bios_detach(); 1283c2554c91SDmitry Torokhov return err; 1284c2554c91SDmitry Torokhov } 1285e7c3aad5SDmitry Torokhov 1286e7c3aad5SDmitry Torokhov return 0; 1287e7c3aad5SDmitry Torokhov } 1288e7c3aad5SDmitry Torokhov 1289e2619cf7SBill Pemberton static int wistron_remove(struct platform_device *dev) 1290e7c3aad5SDmitry Torokhov { 1291389679d8SEric Piel wistron_led_remove(); 12924a767ec3SDmitry Torokhov input_unregister_device(wistron_idev); 1293e7c3aad5SDmitry Torokhov bios_detach(); 1294e7c3aad5SDmitry Torokhov 1295e7c3aad5SDmitry Torokhov return 0; 1296e7c3aad5SDmitry Torokhov } 1297e7c3aad5SDmitry Torokhov 1298e7c3aad5SDmitry Torokhov #ifdef CONFIG_PM 129967dbe83aSDmitry Torokhov static int wistron_suspend(struct device *dev) 1300a5b0cc80SDmitry Torokhov { 1301e753b650SMiloslav Trmac if (have_wifi) 1302e753b650SMiloslav Trmac bios_set_state(WIFI, 0); 1303e753b650SMiloslav Trmac 1304e753b650SMiloslav Trmac if (have_bluetooth) 1305e753b650SMiloslav Trmac bios_set_state(BLUETOOTH, 0); 1306e753b650SMiloslav Trmac 1307389679d8SEric Piel wistron_led_suspend(); 130867dbe83aSDmitry Torokhov 1309a5b0cc80SDmitry Torokhov return 0; 1310a5b0cc80SDmitry Torokhov } 1311a5b0cc80SDmitry Torokhov 131267dbe83aSDmitry Torokhov static int wistron_resume(struct device *dev) 1313a5b0cc80SDmitry Torokhov { 1314a5b0cc80SDmitry Torokhov if (have_wifi) 1315a5b0cc80SDmitry Torokhov bios_set_state(WIFI, wifi_enabled); 1316a5b0cc80SDmitry Torokhov 1317a5b0cc80SDmitry Torokhov if (have_bluetooth) 1318a5b0cc80SDmitry Torokhov bios_set_state(BLUETOOTH, bluetooth_enabled); 1319a5b0cc80SDmitry Torokhov 1320389679d8SEric Piel wistron_led_resume(); 132167dbe83aSDmitry Torokhov 1322c2554c91SDmitry Torokhov poll_bios(true); 1323a5b0cc80SDmitry Torokhov 1324a5b0cc80SDmitry Torokhov return 0; 1325a5b0cc80SDmitry Torokhov } 132667dbe83aSDmitry Torokhov 132767dbe83aSDmitry Torokhov static const struct dev_pm_ops wistron_pm_ops = { 132867dbe83aSDmitry Torokhov .suspend = wistron_suspend, 132967dbe83aSDmitry Torokhov .resume = wistron_resume, 133067dbe83aSDmitry Torokhov .poweroff = wistron_suspend, 133167dbe83aSDmitry Torokhov .restore = wistron_resume, 133267dbe83aSDmitry Torokhov }; 1333e7c3aad5SDmitry Torokhov #endif 1334a5b0cc80SDmitry Torokhov 1335a5b0cc80SDmitry Torokhov static struct platform_driver wistron_driver = { 1336a5b0cc80SDmitry Torokhov .driver = { 1337a5b0cc80SDmitry Torokhov .name = "wistron-bios", 1338e97006aeSRakib Mullick #ifdef CONFIG_PM 133967dbe83aSDmitry Torokhov .pm = &wistron_pm_ops, 134067dbe83aSDmitry Torokhov #endif 1341a5b0cc80SDmitry Torokhov }, 1342e7c3aad5SDmitry Torokhov .probe = wistron_probe, 13431cb0aa88SBill Pemberton .remove = wistron_remove, 1344a5b0cc80SDmitry Torokhov }; 1345a5b0cc80SDmitry Torokhov 13465fc14680SDmitry Torokhov static int __init wb_module_init(void) 13475fc14680SDmitry Torokhov { 13485fc14680SDmitry Torokhov int err; 13495fc14680SDmitry Torokhov 13505fc14680SDmitry Torokhov err = select_keymap(); 13515fc14680SDmitry Torokhov if (err) 13525fc14680SDmitry Torokhov return err; 135322a397e2SDmitry Torokhov 13545fc14680SDmitry Torokhov err = map_bios(); 13555fc14680SDmitry Torokhov if (err) 13561fcb8bb6SAxel Lin goto err_free_keymap; 135722a397e2SDmitry Torokhov 1358a5b0cc80SDmitry Torokhov err = platform_driver_register(&wistron_driver); 1359a5b0cc80SDmitry Torokhov if (err) 1360e7c3aad5SDmitry Torokhov goto err_unmap_bios; 1361a5b0cc80SDmitry Torokhov 1362e7c3aad5SDmitry Torokhov wistron_device = platform_device_alloc("wistron-bios", -1); 1363e7c3aad5SDmitry Torokhov if (!wistron_device) { 1364e7c3aad5SDmitry Torokhov err = -ENOMEM; 1365a5b0cc80SDmitry Torokhov goto err_unregister_driver; 1366a5b0cc80SDmitry Torokhov } 1367a5b0cc80SDmitry Torokhov 1368e7c3aad5SDmitry Torokhov err = platform_device_add(wistron_device); 1369a5b0cc80SDmitry Torokhov if (err) 1370e7c3aad5SDmitry Torokhov goto err_free_device; 13715fc14680SDmitry Torokhov 13725fc14680SDmitry Torokhov return 0; 1373a5b0cc80SDmitry Torokhov 1374e7c3aad5SDmitry Torokhov err_free_device: 1375e7c3aad5SDmitry Torokhov platform_device_put(wistron_device); 1376a5b0cc80SDmitry Torokhov err_unregister_driver: 1377a5b0cc80SDmitry Torokhov platform_driver_unregister(&wistron_driver); 1378e7c3aad5SDmitry Torokhov err_unmap_bios: 1379a5b0cc80SDmitry Torokhov unmap_bios(); 13801fcb8bb6SAxel Lin err_free_keymap: 13811fcb8bb6SAxel Lin kfree(keymap); 1382a5b0cc80SDmitry Torokhov 1383a5b0cc80SDmitry Torokhov return err; 13845fc14680SDmitry Torokhov } 13855fc14680SDmitry Torokhov 13865fc14680SDmitry Torokhov static void __exit wb_module_exit(void) 13875fc14680SDmitry Torokhov { 1388a5b0cc80SDmitry Torokhov platform_device_unregister(wistron_device); 1389a5b0cc80SDmitry Torokhov platform_driver_unregister(&wistron_driver); 13905fc14680SDmitry Torokhov unmap_bios(); 139155d29c98SEric Piel kfree(keymap); 13925fc14680SDmitry Torokhov } 13935fc14680SDmitry Torokhov 13945fc14680SDmitry Torokhov module_init(wb_module_init); 13955fc14680SDmitry Torokhov module_exit(wb_module_exit); 1396