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
call_bios(struct regs * regs)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
locate_wistron_bios(void __iomem * base)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
map_bios(void)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
unmap_bios(void)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
bios_pop_queue(void)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
bios_attach(void)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
bios_detach(void)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
bios_get_cmos_address(void)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
bios_get_default_setting(u8 subsys)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
bios_set_state(u8 subsys,int enable)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
dmi_matched(const struct dmi_system_id * dmi)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 */
copy_keymap(void)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
993*b7ffc98aSShen Lichuan new_keymap = kmemdup_array(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
select_keymap(void)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 */
wistron_mail_led_set(struct led_classdev * led_cdev,enum led_brightness value)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 */
wistron_wifi_led_set(struct led_classdev * led_cdev,enum led_brightness value)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
wistron_led_init(struct device * parent)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) {
1078dab2214fSWangYuli /* bios_get_default_setting(MAIL) always returns 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
wistron_led_remove(void)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
wistron_led_suspend(void)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
wistron_led_resume(void)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
handle_key(u8 code)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
poll_bios(bool discard)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
wistron_flush(struct input_dev * dev)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
wistron_poll(struct input_dev * dev)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
wistron_setup_keymap(struct input_dev * dev,struct key_entry * entry)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
setup_input_dev(void)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
wistron_probe(struct platform_device * dev)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
wistron_remove(struct platform_device * dev)1289ad437160SUwe Kleine-König static void 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
wistron_suspend(struct device * dev)129667dbe83aSDmitry Torokhov static int wistron_suspend(struct device *dev)
1297a5b0cc80SDmitry Torokhov {
1298e753b650SMiloslav Trmac if (have_wifi)
1299e753b650SMiloslav Trmac bios_set_state(WIFI, 0);
1300e753b650SMiloslav Trmac
1301e753b650SMiloslav Trmac if (have_bluetooth)
1302e753b650SMiloslav Trmac bios_set_state(BLUETOOTH, 0);
1303e753b650SMiloslav Trmac
1304389679d8SEric Piel wistron_led_suspend();
130567dbe83aSDmitry Torokhov
1306a5b0cc80SDmitry Torokhov return 0;
1307a5b0cc80SDmitry Torokhov }
1308a5b0cc80SDmitry Torokhov
wistron_resume(struct device * dev)130967dbe83aSDmitry Torokhov static int wistron_resume(struct device *dev)
1310a5b0cc80SDmitry Torokhov {
1311a5b0cc80SDmitry Torokhov if (have_wifi)
1312a5b0cc80SDmitry Torokhov bios_set_state(WIFI, wifi_enabled);
1313a5b0cc80SDmitry Torokhov
1314a5b0cc80SDmitry Torokhov if (have_bluetooth)
1315a5b0cc80SDmitry Torokhov bios_set_state(BLUETOOTH, bluetooth_enabled);
1316a5b0cc80SDmitry Torokhov
1317389679d8SEric Piel wistron_led_resume();
131867dbe83aSDmitry Torokhov
1319c2554c91SDmitry Torokhov poll_bios(true);
1320a5b0cc80SDmitry Torokhov
1321a5b0cc80SDmitry Torokhov return 0;
1322a5b0cc80SDmitry Torokhov }
132367dbe83aSDmitry Torokhov
132467dbe83aSDmitry Torokhov static const struct dev_pm_ops wistron_pm_ops = {
132567dbe83aSDmitry Torokhov .suspend = wistron_suspend,
132667dbe83aSDmitry Torokhov .resume = wistron_resume,
132767dbe83aSDmitry Torokhov .poweroff = wistron_suspend,
132867dbe83aSDmitry Torokhov .restore = wistron_resume,
132967dbe83aSDmitry Torokhov };
1330a5b0cc80SDmitry Torokhov
1331a5b0cc80SDmitry Torokhov static struct platform_driver wistron_driver = {
1332a5b0cc80SDmitry Torokhov .driver = {
1333a5b0cc80SDmitry Torokhov .name = "wistron-bios",
133447e79d31SJonathan Cameron .pm = pm_sleep_ptr(&wistron_pm_ops),
1335a5b0cc80SDmitry Torokhov },
1336e7c3aad5SDmitry Torokhov .probe = wistron_probe,
1337ad437160SUwe Kleine-König .remove_new = wistron_remove,
1338a5b0cc80SDmitry Torokhov };
1339a5b0cc80SDmitry Torokhov
wb_module_init(void)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
wb_module_exit(void)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