15fc14680SDmitry Torokhov /*
25fc14680SDmitry Torokhov  * Wistron laptop button driver
35fc14680SDmitry Torokhov  * Copyright (C) 2005 Miloslav Trmac <mitr@volny.cz>
484b256a6SBernhard Rosenkraenzer  * Copyright (C) 2005 Bernhard Rosenkraenzer <bero@arklinux.org>
5a5b0cc80SDmitry Torokhov  * Copyright (C) 2005 Dmitry Torokhov <dtor@mail.ru>
65fc14680SDmitry Torokhov  *
75fc14680SDmitry Torokhov  * You can redistribute and/or modify this program under the terms of the
85fc14680SDmitry Torokhov  * GNU General Public License version 2 as published by the Free Software
95fc14680SDmitry Torokhov  * Foundation.
105fc14680SDmitry Torokhov  *
115fc14680SDmitry Torokhov  * This program is distributed in the hope that it will be useful, but
125fc14680SDmitry Torokhov  * WITHOUT ANY WARRANTY; without even the implied warranty of
135fc14680SDmitry Torokhov  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General
145fc14680SDmitry Torokhov  * Public License for more details.
155fc14680SDmitry Torokhov  *
165fc14680SDmitry Torokhov  * You should have received a copy of the GNU General Public License along
175fc14680SDmitry Torokhov  * with this program; if not, write to the Free Software Foundation, Inc.,
185fc14680SDmitry Torokhov  * 59 Temple Place Suite 330, Boston, MA 02111-1307, USA.
195fc14680SDmitry Torokhov  */
2053d5ed62SMatthew Wilcox #include <linux/io.h>
215fc14680SDmitry Torokhov #include <linux/dmi.h>
225fc14680SDmitry Torokhov #include <linux/init.h>
23c2554c91SDmitry Torokhov #include <linux/input-polldev.h>
245fc14680SDmitry Torokhov #include <linux/interrupt.h>
25a4da16d3SEric Piel #include <linux/jiffies.h>
265fc14680SDmitry Torokhov #include <linux/kernel.h>
275fc14680SDmitry Torokhov #include <linux/mc146818rtc.h>
285fc14680SDmitry Torokhov #include <linux/module.h>
295fc14680SDmitry Torokhov #include <linux/preempt.h>
305fc14680SDmitry Torokhov #include <linux/string.h>
315fc14680SDmitry Torokhov #include <linux/types.h>
32a5b0cc80SDmitry Torokhov #include <linux/platform_device.h>
33389679d8SEric Piel #include <linux/leds.h>
345fc14680SDmitry Torokhov 
35c2554c91SDmitry Torokhov /* How often we poll keys - msecs */
36c2554c91SDmitry Torokhov #define POLL_INTERVAL_DEFAULT	500 /* when idle */
37c2554c91SDmitry Torokhov #define POLL_INTERVAL_BURST	100 /* when a key was recently pressed */
385fc14680SDmitry Torokhov 
3984b256a6SBernhard Rosenkraenzer /* BIOS subsystem IDs */
4084b256a6SBernhard Rosenkraenzer #define WIFI		0x35
4184b256a6SBernhard Rosenkraenzer #define BLUETOOTH	0x34
42389679d8SEric Piel #define MAIL_LED	0x31
4384b256a6SBernhard Rosenkraenzer 
445fc14680SDmitry Torokhov MODULE_AUTHOR("Miloslav Trmac <mitr@volny.cz>");
455fc14680SDmitry Torokhov MODULE_DESCRIPTION("Wistron laptop button driver");
465fc14680SDmitry Torokhov MODULE_LICENSE("GPL v2");
47389679d8SEric Piel MODULE_VERSION("0.3");
485fc14680SDmitry Torokhov 
495fc14680SDmitry Torokhov static int force; /* = 0; */
505fc14680SDmitry Torokhov module_param(force, bool, 0);
515fc14680SDmitry Torokhov MODULE_PARM_DESC(force, "Load even if computer is not in database");
525fc14680SDmitry Torokhov 
535fc14680SDmitry Torokhov static char *keymap_name; /* = NULL; */
545fc14680SDmitry Torokhov module_param_named(keymap, keymap_name, charp, 0);
557b0a4cd7SEric Piel MODULE_PARM_DESC(keymap, "Keymap name, if it can't be autodetected [generic, 1557/MS2141]");
565fc14680SDmitry Torokhov 
57a5b0cc80SDmitry Torokhov static struct platform_device *wistron_device;
58a5b0cc80SDmitry Torokhov 
595fc14680SDmitry Torokhov  /* BIOS interface implementation */
605fc14680SDmitry Torokhov 
615fc14680SDmitry Torokhov static void __iomem *bios_entry_point; /* BIOS routine entry point */
625fc14680SDmitry Torokhov static void __iomem *bios_code_map_base;
635fc14680SDmitry Torokhov static void __iomem *bios_data_map_base;
645fc14680SDmitry Torokhov 
655fc14680SDmitry Torokhov static u8 cmos_address;
665fc14680SDmitry Torokhov 
675fc14680SDmitry Torokhov struct regs {
685fc14680SDmitry Torokhov 	u32 eax, ebx, ecx;
695fc14680SDmitry Torokhov };
705fc14680SDmitry Torokhov 
715fc14680SDmitry Torokhov static void call_bios(struct regs *regs)
725fc14680SDmitry Torokhov {
735fc14680SDmitry Torokhov 	unsigned long flags;
745fc14680SDmitry Torokhov 
755fc14680SDmitry Torokhov 	preempt_disable();
765fc14680SDmitry Torokhov 	local_irq_save(flags);
775fc14680SDmitry Torokhov 	asm volatile ("pushl %%ebp;"
785fc14680SDmitry Torokhov 		      "movl %7, %%ebp;"
795fc14680SDmitry Torokhov 		      "call *%6;"
805fc14680SDmitry Torokhov 		      "popl %%ebp"
815fc14680SDmitry Torokhov 		      : "=a" (regs->eax), "=b" (regs->ebx), "=c" (regs->ecx)
825fc14680SDmitry Torokhov 		      : "0" (regs->eax), "1" (regs->ebx), "2" (regs->ecx),
835fc14680SDmitry Torokhov 			"m" (bios_entry_point), "m" (bios_data_map_base)
845fc14680SDmitry Torokhov 		      : "edx", "edi", "esi", "memory");
855fc14680SDmitry Torokhov 	local_irq_restore(flags);
865fc14680SDmitry Torokhov 	preempt_enable();
875fc14680SDmitry Torokhov }
885fc14680SDmitry Torokhov 
89c28c3583SMiloslav Trmac static ssize_t __init locate_wistron_bios(void __iomem *base)
905fc14680SDmitry Torokhov {
91c7948989SAndrew Morton 	static unsigned char __initdata signature[] =
925fc14680SDmitry Torokhov 		{ 0x42, 0x21, 0x55, 0x30 };
93c28c3583SMiloslav Trmac 	ssize_t offset;
945fc14680SDmitry Torokhov 
955fc14680SDmitry Torokhov 	for (offset = 0; offset < 0x10000; offset += 0x10) {
965fc14680SDmitry Torokhov 		if (check_signature(base + offset, signature,
975fc14680SDmitry Torokhov 				    sizeof(signature)) != 0)
985fc14680SDmitry Torokhov 			return offset;
995fc14680SDmitry Torokhov 	}
1005fc14680SDmitry Torokhov 	return -1;
1015fc14680SDmitry Torokhov }
1025fc14680SDmitry Torokhov 
1035fc14680SDmitry Torokhov static int __init map_bios(void)
1045fc14680SDmitry Torokhov {
1055fc14680SDmitry Torokhov 	void __iomem *base;
106c28c3583SMiloslav Trmac 	ssize_t offset;
1075fc14680SDmitry Torokhov 	u32 entry_point;
1085fc14680SDmitry Torokhov 
1095fc14680SDmitry Torokhov 	base = ioremap(0xF0000, 0x10000); /* Can't fail */
1105fc14680SDmitry Torokhov 	offset = locate_wistron_bios(base);
1115fc14680SDmitry Torokhov 	if (offset < 0) {
1125fc14680SDmitry Torokhov 		printk(KERN_ERR "wistron_btns: BIOS entry point not found\n");
1135fc14680SDmitry Torokhov 		iounmap(base);
1145fc14680SDmitry Torokhov 		return -ENODEV;
1155fc14680SDmitry Torokhov 	}
1165fc14680SDmitry Torokhov 
1175fc14680SDmitry Torokhov 	entry_point = readl(base + offset + 5);
1185fc14680SDmitry Torokhov 	printk(KERN_DEBUG
1195fc14680SDmitry Torokhov 		"wistron_btns: BIOS signature found at %p, entry point %08X\n",
1205fc14680SDmitry Torokhov 		base + offset, entry_point);
1215fc14680SDmitry Torokhov 
1225fc14680SDmitry Torokhov 	if (entry_point >= 0xF0000) {
1235fc14680SDmitry Torokhov 		bios_code_map_base = base;
1245fc14680SDmitry Torokhov 		bios_entry_point = bios_code_map_base + (entry_point & 0xFFFF);
1255fc14680SDmitry Torokhov 	} else {
1265fc14680SDmitry Torokhov 		iounmap(base);
1275fc14680SDmitry Torokhov 		bios_code_map_base = ioremap(entry_point & ~0x3FFF, 0x4000);
1285fc14680SDmitry Torokhov 		if (bios_code_map_base == NULL) {
1295fc14680SDmitry Torokhov 			printk(KERN_ERR
1305fc14680SDmitry Torokhov 				"wistron_btns: Can't map BIOS code at %08X\n",
1315fc14680SDmitry Torokhov 				entry_point & ~0x3FFF);
1325fc14680SDmitry Torokhov 			goto err;
1335fc14680SDmitry Torokhov 		}
1345fc14680SDmitry Torokhov 		bios_entry_point = bios_code_map_base + (entry_point & 0x3FFF);
1355fc14680SDmitry Torokhov 	}
1365fc14680SDmitry Torokhov 	/* The Windows driver maps 0x10000 bytes, we keep only one page... */
1375fc14680SDmitry Torokhov 	bios_data_map_base = ioremap(0x400, 0xc00);
1385fc14680SDmitry Torokhov 	if (bios_data_map_base == NULL) {
1395fc14680SDmitry Torokhov 		printk(KERN_ERR "wistron_btns: Can't map BIOS data\n");
1405fc14680SDmitry Torokhov 		goto err_code;
1415fc14680SDmitry Torokhov 	}
1425fc14680SDmitry Torokhov 	return 0;
1435fc14680SDmitry Torokhov 
1445fc14680SDmitry Torokhov err_code:
1455fc14680SDmitry Torokhov 	iounmap(bios_code_map_base);
1465fc14680SDmitry Torokhov err:
1475fc14680SDmitry Torokhov 	return -ENOMEM;
1485fc14680SDmitry Torokhov }
1495fc14680SDmitry Torokhov 
15022a397e2SDmitry Torokhov static inline void unmap_bios(void)
1515fc14680SDmitry Torokhov {
1525fc14680SDmitry Torokhov 	iounmap(bios_code_map_base);
1535fc14680SDmitry Torokhov 	iounmap(bios_data_map_base);
1545fc14680SDmitry Torokhov }
1555fc14680SDmitry Torokhov 
1565fc14680SDmitry Torokhov  /* BIOS calls */
1575fc14680SDmitry Torokhov 
1585fc14680SDmitry Torokhov static u16 bios_pop_queue(void)
1595fc14680SDmitry Torokhov {
1605fc14680SDmitry Torokhov 	struct regs regs;
1615fc14680SDmitry Torokhov 
1625fc14680SDmitry Torokhov 	memset(&regs, 0, sizeof (regs));
1635fc14680SDmitry Torokhov 	regs.eax = 0x9610;
1645fc14680SDmitry Torokhov 	regs.ebx = 0x061C;
1655fc14680SDmitry Torokhov 	regs.ecx = 0x0000;
1665fc14680SDmitry Torokhov 	call_bios(&regs);
1675fc14680SDmitry Torokhov 
1685fc14680SDmitry Torokhov 	return regs.eax;
1695fc14680SDmitry Torokhov }
1705fc14680SDmitry Torokhov 
171e7c3aad5SDmitry Torokhov static void __devinit bios_attach(void)
1725fc14680SDmitry Torokhov {
1735fc14680SDmitry Torokhov 	struct regs regs;
1745fc14680SDmitry Torokhov 
1755fc14680SDmitry Torokhov 	memset(&regs, 0, sizeof (regs));
1765fc14680SDmitry Torokhov 	regs.eax = 0x9610;
1775fc14680SDmitry Torokhov 	regs.ebx = 0x012E;
1785fc14680SDmitry Torokhov 	call_bios(&regs);
1795fc14680SDmitry Torokhov }
1805fc14680SDmitry Torokhov 
18122a397e2SDmitry Torokhov static void bios_detach(void)
1825fc14680SDmitry Torokhov {
1835fc14680SDmitry Torokhov 	struct regs regs;
1845fc14680SDmitry Torokhov 
1855fc14680SDmitry Torokhov 	memset(&regs, 0, sizeof (regs));
1865fc14680SDmitry Torokhov 	regs.eax = 0x9610;
1875fc14680SDmitry Torokhov 	regs.ebx = 0x002E;
1885fc14680SDmitry Torokhov 	call_bios(&regs);
1895fc14680SDmitry Torokhov }
1905fc14680SDmitry Torokhov 
191e7c3aad5SDmitry Torokhov static u8 __devinit bios_get_cmos_address(void)
1925fc14680SDmitry Torokhov {
1935fc14680SDmitry Torokhov 	struct regs regs;
1945fc14680SDmitry Torokhov 
1955fc14680SDmitry Torokhov 	memset(&regs, 0, sizeof (regs));
1965fc14680SDmitry Torokhov 	regs.eax = 0x9610;
1975fc14680SDmitry Torokhov 	regs.ebx = 0x051C;
1985fc14680SDmitry Torokhov 	call_bios(&regs);
1995fc14680SDmitry Torokhov 
2005fc14680SDmitry Torokhov 	return regs.ecx;
2015fc14680SDmitry Torokhov }
2025fc14680SDmitry Torokhov 
203e7c3aad5SDmitry Torokhov static u16 __devinit bios_get_default_setting(u8 subsys)
2045fc14680SDmitry Torokhov {
2055fc14680SDmitry Torokhov 	struct regs regs;
2065fc14680SDmitry Torokhov 
2075fc14680SDmitry Torokhov 	memset(&regs, 0, sizeof (regs));
2085fc14680SDmitry Torokhov 	regs.eax = 0x9610;
20984b256a6SBernhard Rosenkraenzer 	regs.ebx = 0x0200 | subsys;
2105fc14680SDmitry Torokhov 	call_bios(&regs);
2115fc14680SDmitry Torokhov 
2125fc14680SDmitry Torokhov 	return regs.eax;
2135fc14680SDmitry Torokhov }
2145fc14680SDmitry Torokhov 
21584b256a6SBernhard Rosenkraenzer static void bios_set_state(u8 subsys, int enable)
2165fc14680SDmitry Torokhov {
2175fc14680SDmitry Torokhov 	struct regs regs;
2185fc14680SDmitry Torokhov 
2195fc14680SDmitry Torokhov 	memset(&regs, 0, sizeof (regs));
2205fc14680SDmitry Torokhov 	regs.eax = 0x9610;
22184b256a6SBernhard Rosenkraenzer 	regs.ebx = (enable ? 0x0100 : 0x0000) | subsys;
2225fc14680SDmitry Torokhov 	call_bios(&regs);
2235fc14680SDmitry Torokhov }
2245fc14680SDmitry Torokhov 
2255fc14680SDmitry Torokhov /* Hardware database */
2265fc14680SDmitry Torokhov 
2275fc14680SDmitry Torokhov struct key_entry {
2285fc14680SDmitry Torokhov 	char type;		/* See KE_* below */
2295fc14680SDmitry Torokhov 	u8 code;
2306480e2a2SEric Piel 	union {
2316480e2a2SEric Piel 		u16 keycode;		/* For KE_KEY */
2326480e2a2SEric Piel 		struct {		/* For KE_SW */
2336480e2a2SEric Piel 			u8 code;
2346480e2a2SEric Piel 			u8 value;
2356480e2a2SEric Piel 		} sw;
2366480e2a2SEric Piel 	};
2375fc14680SDmitry Torokhov };
2385fc14680SDmitry Torokhov 
2396480e2a2SEric Piel enum { KE_END, KE_KEY, KE_SW, KE_WIFI, KE_BLUETOOTH };
2406480e2a2SEric Piel 
2416480e2a2SEric Piel #define FE_MAIL_LED 0x01
2426480e2a2SEric Piel #define FE_WIFI_LED 0x02
2436480e2a2SEric Piel #define FE_UNTESTED 0x80
2445fc14680SDmitry Torokhov 
245d63219a1SDmitry Torokhov static struct key_entry *keymap; /* = NULL; Current key map */
24667dbe83aSDmitry Torokhov static bool have_wifi;
24767dbe83aSDmitry Torokhov static bool have_bluetooth;
24867dbe83aSDmitry Torokhov static int leds_present;	/* bitmask of leds present */
2495fc14680SDmitry Torokhov 
2501855256cSJeff Garzik static int __init dmi_matched(const struct dmi_system_id *dmi)
2515fc14680SDmitry Torokhov {
2525fc14680SDmitry Torokhov 	const struct key_entry *key;
2535fc14680SDmitry Torokhov 
2545fc14680SDmitry Torokhov 	keymap = dmi->driver_data;
2555fc14680SDmitry Torokhov 	for (key = keymap; key->type != KE_END; key++) {
256cde45f19SReiner Herrmann 		if (key->type == KE_WIFI)
25767dbe83aSDmitry Torokhov 			have_wifi = true;
258cde45f19SReiner Herrmann 		else if (key->type == KE_BLUETOOTH)
25967dbe83aSDmitry Torokhov 			have_bluetooth = true;
2605fc14680SDmitry Torokhov 	}
26167dbe83aSDmitry Torokhov 	leds_present = key->code & (FE_MAIL_LED | FE_WIFI_LED);
262389679d8SEric Piel 
2635fc14680SDmitry Torokhov 	return 1;
2645fc14680SDmitry Torokhov }
2655fc14680SDmitry Torokhov 
26655d29c98SEric Piel static struct key_entry keymap_empty[] __initdata = {
2675fc14680SDmitry Torokhov 	{ KE_END, 0 }
2685fc14680SDmitry Torokhov };
2695fc14680SDmitry Torokhov 
27055d29c98SEric Piel static struct key_entry keymap_fs_amilo_pro_v2000[] __initdata = {
2716480e2a2SEric Piel 	{ KE_KEY,  0x01, {KEY_HELP} },
2726480e2a2SEric Piel 	{ KE_KEY,  0x11, {KEY_PROG1} },
2736480e2a2SEric Piel 	{ KE_KEY,  0x12, {KEY_PROG2} },
2746480e2a2SEric Piel 	{ KE_WIFI, 0x30 },
2756480e2a2SEric Piel 	{ KE_KEY,  0x31, {KEY_MAIL} },
2766480e2a2SEric Piel 	{ KE_KEY,  0x36, {KEY_WWW} },
2775fc14680SDmitry Torokhov 	{ KE_END,  0 }
2785fc14680SDmitry Torokhov };
2795fc14680SDmitry Torokhov 
28034a7c48cSRemi Herilier static struct key_entry keymap_fs_amilo_pro_v3505[] __initdata = {
28134a7c48cSRemi Herilier 	{ KE_KEY,       0x01, {KEY_HELP} },          /* Fn+F1 */
28234a7c48cSRemi Herilier 	{ KE_KEY,       0x06, {KEY_DISPLAYTOGGLE} }, /* Fn+F4 */
28334a7c48cSRemi Herilier 	{ KE_BLUETOOTH, 0x30 },                      /* Fn+F10 */
28434a7c48cSRemi Herilier 	{ KE_KEY,       0x31, {KEY_MAIL} },          /* mail button */
28534a7c48cSRemi Herilier 	{ KE_KEY,       0x36, {KEY_WWW} },           /* www button */
28634a7c48cSRemi Herilier 	{ KE_WIFI,      0x78 },                      /* satelite dish button */
28734a7c48cSRemi Herilier 	{ KE_END,       0 }
28834a7c48cSRemi Herilier };
28934a7c48cSRemi Herilier 
29055d29c98SEric Piel static struct key_entry keymap_fujitsu_n3510[] __initdata = {
2916480e2a2SEric Piel 	{ KE_KEY, 0x11, {KEY_PROG1} },
2926480e2a2SEric Piel 	{ KE_KEY, 0x12, {KEY_PROG2} },
2936480e2a2SEric Piel 	{ KE_KEY, 0x36, {KEY_WWW} },
2946480e2a2SEric Piel 	{ KE_KEY, 0x31, {KEY_MAIL} },
2956480e2a2SEric Piel 	{ KE_KEY, 0x71, {KEY_STOPCD} },
2966480e2a2SEric Piel 	{ KE_KEY, 0x72, {KEY_PLAYPAUSE} },
2976480e2a2SEric Piel 	{ KE_KEY, 0x74, {KEY_REWIND} },
2986480e2a2SEric Piel 	{ KE_KEY, 0x78, {KEY_FORWARD} },
299e2aa507aSJohn Reed Riley 	{ KE_END, 0 }
300e2aa507aSJohn Reed Riley };
301e2aa507aSJohn Reed Riley 
30255d29c98SEric Piel static struct key_entry keymap_wistron_ms2111[] __initdata = {
3036480e2a2SEric Piel 	{ KE_KEY,  0x11, {KEY_PROG1} },
3046480e2a2SEric Piel 	{ KE_KEY,  0x12, {KEY_PROG2} },
3056480e2a2SEric Piel 	{ KE_KEY,  0x13, {KEY_PROG3} },
3066480e2a2SEric Piel 	{ KE_KEY,  0x31, {KEY_MAIL} },
3076480e2a2SEric Piel 	{ KE_KEY,  0x36, {KEY_WWW} },
3086480e2a2SEric Piel 	{ KE_END, FE_MAIL_LED }
3096480e2a2SEric Piel };
3106480e2a2SEric Piel 
31155d29c98SEric Piel static struct key_entry keymap_wistron_md40100[] __initdata = {
3126480e2a2SEric Piel 	{ KE_KEY, 0x01, {KEY_HELP} },
3136480e2a2SEric Piel 	{ KE_KEY, 0x02, {KEY_CONFIG} },
3146480e2a2SEric Piel 	{ KE_KEY, 0x31, {KEY_MAIL} },
3156480e2a2SEric Piel 	{ KE_KEY, 0x36, {KEY_WWW} },
3166480e2a2SEric Piel 	{ KE_KEY, 0x37, {KEY_DISPLAYTOGGLE} }, /* Display on/off */
3176480e2a2SEric Piel 	{ KE_END, FE_MAIL_LED | FE_WIFI_LED | FE_UNTESTED }
3189000195bSFrank de Lange };
3199000195bSFrank de Lange 
32055d29c98SEric Piel static struct key_entry keymap_wistron_ms2141[] __initdata = {
3216480e2a2SEric Piel 	{ KE_KEY,  0x11, {KEY_PROG1} },
3226480e2a2SEric Piel 	{ KE_KEY,  0x12, {KEY_PROG2} },
3236480e2a2SEric Piel 	{ KE_WIFI, 0x30 },
3246480e2a2SEric Piel 	{ KE_KEY,  0x22, {KEY_REWIND} },
3256480e2a2SEric Piel 	{ KE_KEY,  0x23, {KEY_FORWARD} },
3266480e2a2SEric Piel 	{ KE_KEY,  0x24, {KEY_PLAYPAUSE} },
3276480e2a2SEric Piel 	{ KE_KEY,  0x25, {KEY_STOPCD} },
3286480e2a2SEric Piel 	{ KE_KEY,  0x31, {KEY_MAIL} },
3296480e2a2SEric Piel 	{ KE_KEY,  0x36, {KEY_WWW} },
3305fc14680SDmitry Torokhov 	{ KE_END,  0 }
3315fc14680SDmitry Torokhov };
3325fc14680SDmitry Torokhov 
33355d29c98SEric Piel static struct key_entry keymap_acer_aspire_1500[] __initdata = {
3346480e2a2SEric Piel 	{ KE_KEY, 0x01, {KEY_HELP} },
3356480e2a2SEric Piel 	{ KE_KEY, 0x03, {KEY_POWER} },
3366480e2a2SEric Piel 	{ KE_KEY, 0x11, {KEY_PROG1} },
3376480e2a2SEric Piel 	{ KE_KEY, 0x12, {KEY_PROG2} },
3386480e2a2SEric Piel 	{ KE_WIFI, 0x30 },
3396480e2a2SEric Piel 	{ KE_KEY, 0x31, {KEY_MAIL} },
3406480e2a2SEric Piel 	{ KE_KEY, 0x36, {KEY_WWW} },
3416480e2a2SEric Piel 	{ KE_KEY, 0x49, {KEY_CONFIG} },
3426480e2a2SEric Piel 	{ KE_BLUETOOTH, 0x44 },
3436480e2a2SEric Piel 	{ KE_END, FE_UNTESTED }
3446480e2a2SEric Piel };
3456480e2a2SEric Piel 
34655d29c98SEric Piel static struct key_entry keymap_acer_aspire_1600[] __initdata = {
3476480e2a2SEric Piel 	{ KE_KEY, 0x01, {KEY_HELP} },
3486480e2a2SEric Piel 	{ KE_KEY, 0x03, {KEY_POWER} },
3496480e2a2SEric Piel 	{ KE_KEY, 0x08, {KEY_MUTE} },
3506480e2a2SEric Piel 	{ KE_KEY, 0x11, {KEY_PROG1} },
3516480e2a2SEric Piel 	{ KE_KEY, 0x12, {KEY_PROG2} },
3526480e2a2SEric Piel 	{ KE_KEY, 0x13, {KEY_PROG3} },
3536480e2a2SEric Piel 	{ KE_KEY, 0x31, {KEY_MAIL} },
3546480e2a2SEric Piel 	{ KE_KEY, 0x36, {KEY_WWW} },
3556480e2a2SEric Piel 	{ KE_KEY, 0x49, {KEY_CONFIG} },
3566480e2a2SEric Piel 	{ KE_WIFI, 0x30 },
3576480e2a2SEric Piel 	{ KE_BLUETOOTH, 0x44 },
3586480e2a2SEric Piel 	{ KE_END, FE_MAIL_LED | FE_UNTESTED }
3596480e2a2SEric Piel };
3606480e2a2SEric Piel 
3616480e2a2SEric Piel /* 3020 has been tested */
36255d29c98SEric Piel static struct key_entry keymap_acer_aspire_5020[] __initdata = {
3636480e2a2SEric Piel 	{ KE_KEY, 0x01, {KEY_HELP} },
3646480e2a2SEric Piel 	{ KE_KEY, 0x03, {KEY_POWER} },
3656480e2a2SEric Piel 	{ KE_KEY, 0x05, {KEY_SWITCHVIDEOMODE} }, /* Display selection */
3666480e2a2SEric Piel 	{ KE_KEY, 0x11, {KEY_PROG1} },
3676480e2a2SEric Piel 	{ KE_KEY, 0x12, {KEY_PROG2} },
3686480e2a2SEric Piel 	{ KE_KEY, 0x31, {KEY_MAIL} },
3696480e2a2SEric Piel 	{ KE_KEY, 0x36, {KEY_WWW} },
3706480e2a2SEric Piel 	{ KE_KEY, 0x6a, {KEY_CONFIG} },
3716480e2a2SEric Piel 	{ KE_WIFI, 0x30 },
3726480e2a2SEric Piel 	{ KE_BLUETOOTH, 0x44 },
3736480e2a2SEric Piel 	{ KE_END, FE_MAIL_LED | FE_UNTESTED }
3746480e2a2SEric Piel };
3756480e2a2SEric Piel 
37655d29c98SEric Piel static struct key_entry keymap_acer_travelmate_2410[] __initdata = {
3776480e2a2SEric Piel 	{ KE_KEY, 0x01, {KEY_HELP} },
3786480e2a2SEric Piel 	{ KE_KEY, 0x6d, {KEY_POWER} },
3796480e2a2SEric Piel 	{ KE_KEY, 0x11, {KEY_PROG1} },
3806480e2a2SEric Piel 	{ KE_KEY, 0x12, {KEY_PROG2} },
3816480e2a2SEric Piel 	{ KE_KEY, 0x31, {KEY_MAIL} },
3826480e2a2SEric Piel 	{ KE_KEY, 0x36, {KEY_WWW} },
3836480e2a2SEric Piel 	{ KE_KEY, 0x6a, {KEY_CONFIG} },
3846480e2a2SEric Piel 	{ KE_WIFI, 0x30 },
3856480e2a2SEric Piel 	{ KE_BLUETOOTH, 0x44 },
3866480e2a2SEric Piel 	{ KE_END, FE_MAIL_LED | FE_UNTESTED }
3876480e2a2SEric Piel };
3886480e2a2SEric Piel 
38955d29c98SEric Piel static struct key_entry keymap_acer_travelmate_110[] __initdata = {
3906480e2a2SEric Piel 	{ KE_KEY, 0x01, {KEY_HELP} },
3916480e2a2SEric Piel 	{ KE_KEY, 0x02, {KEY_CONFIG} },
3926480e2a2SEric Piel 	{ KE_KEY, 0x03, {KEY_POWER} },
3936480e2a2SEric Piel 	{ KE_KEY, 0x08, {KEY_MUTE} },
3946480e2a2SEric Piel 	{ KE_KEY, 0x11, {KEY_PROG1} },
3956480e2a2SEric Piel 	{ KE_KEY, 0x12, {KEY_PROG2} },
3966480e2a2SEric Piel 	{ KE_KEY, 0x20, {KEY_VOLUMEUP} },
3976480e2a2SEric Piel 	{ KE_KEY, 0x21, {KEY_VOLUMEDOWN} },
3986480e2a2SEric Piel 	{ KE_KEY, 0x31, {KEY_MAIL} },
3996480e2a2SEric Piel 	{ KE_KEY, 0x36, {KEY_WWW} },
4006480e2a2SEric Piel 	{ KE_SW, 0x4a, {.sw = {SW_LID, 1}} }, /* lid close */
4016480e2a2SEric Piel 	{ KE_SW, 0x4b, {.sw = {SW_LID, 0}} }, /* lid open */
4026480e2a2SEric Piel 	{ KE_WIFI, 0x30 },
4036480e2a2SEric Piel 	{ KE_END, FE_MAIL_LED | FE_UNTESTED }
4046480e2a2SEric Piel };
4056480e2a2SEric Piel 
40655d29c98SEric Piel static struct key_entry keymap_acer_travelmate_300[] __initdata = {
4076480e2a2SEric Piel 	{ KE_KEY, 0x01, {KEY_HELP} },
4086480e2a2SEric Piel 	{ KE_KEY, 0x02, {KEY_CONFIG} },
4096480e2a2SEric Piel 	{ KE_KEY, 0x03, {KEY_POWER} },
4106480e2a2SEric Piel 	{ KE_KEY, 0x08, {KEY_MUTE} },
4116480e2a2SEric Piel 	{ KE_KEY, 0x11, {KEY_PROG1} },
4126480e2a2SEric Piel 	{ KE_KEY, 0x12, {KEY_PROG2} },
4136480e2a2SEric Piel 	{ KE_KEY, 0x20, {KEY_VOLUMEUP} },
4146480e2a2SEric Piel 	{ KE_KEY, 0x21, {KEY_VOLUMEDOWN} },
4156480e2a2SEric Piel 	{ KE_KEY, 0x31, {KEY_MAIL} },
4166480e2a2SEric Piel 	{ KE_KEY, 0x36, {KEY_WWW} },
4176480e2a2SEric Piel 	{ KE_WIFI, 0x30 },
4186480e2a2SEric Piel 	{ KE_BLUETOOTH, 0x44 },
4196480e2a2SEric Piel 	{ KE_END, FE_MAIL_LED | FE_UNTESTED }
4206480e2a2SEric Piel };
4216480e2a2SEric Piel 
42255d29c98SEric Piel static struct key_entry keymap_acer_travelmate_380[] __initdata = {
4236480e2a2SEric Piel 	{ KE_KEY, 0x01, {KEY_HELP} },
4246480e2a2SEric Piel 	{ KE_KEY, 0x02, {KEY_CONFIG} },
4256480e2a2SEric Piel 	{ KE_KEY, 0x03, {KEY_POWER} }, /* not 370 */
4266480e2a2SEric Piel 	{ KE_KEY, 0x11, {KEY_PROG1} },
4276480e2a2SEric Piel 	{ KE_KEY, 0x12, {KEY_PROG2} },
4286480e2a2SEric Piel 	{ KE_KEY, 0x13, {KEY_PROG3} },
4296480e2a2SEric Piel 	{ KE_KEY, 0x31, {KEY_MAIL} },
4306480e2a2SEric Piel 	{ KE_KEY, 0x36, {KEY_WWW} },
4316480e2a2SEric Piel 	{ KE_WIFI, 0x30 },
4326480e2a2SEric Piel 	{ KE_END, FE_MAIL_LED | FE_UNTESTED }
4336480e2a2SEric Piel };
4346480e2a2SEric Piel 
4356480e2a2SEric Piel /* unusual map */
43655d29c98SEric Piel static struct key_entry keymap_acer_travelmate_220[] __initdata = {
4376480e2a2SEric Piel 	{ KE_KEY, 0x01, {KEY_HELP} },
4386480e2a2SEric Piel 	{ KE_KEY, 0x02, {KEY_CONFIG} },
4396480e2a2SEric Piel 	{ KE_KEY, 0x11, {KEY_MAIL} },
4406480e2a2SEric Piel 	{ KE_KEY, 0x12, {KEY_WWW} },
4416480e2a2SEric Piel 	{ KE_KEY, 0x13, {KEY_PROG2} },
4426480e2a2SEric Piel 	{ KE_KEY, 0x31, {KEY_PROG1} },
4436480e2a2SEric Piel 	{ KE_END, FE_WIFI_LED | FE_UNTESTED }
4446480e2a2SEric Piel };
4456480e2a2SEric Piel 
44655d29c98SEric Piel static struct key_entry keymap_acer_travelmate_230[] __initdata = {
4476480e2a2SEric Piel 	{ KE_KEY, 0x01, {KEY_HELP} },
4486480e2a2SEric Piel 	{ KE_KEY, 0x02, {KEY_CONFIG} },
4496480e2a2SEric Piel 	{ KE_KEY, 0x11, {KEY_PROG1} },
4506480e2a2SEric Piel 	{ KE_KEY, 0x12, {KEY_PROG2} },
4516480e2a2SEric Piel 	{ KE_KEY, 0x31, {KEY_MAIL} },
4526480e2a2SEric Piel 	{ KE_KEY, 0x36, {KEY_WWW} },
4536480e2a2SEric Piel 	{ KE_END, FE_WIFI_LED | FE_UNTESTED }
45484b256a6SBernhard Rosenkraenzer };
45584b256a6SBernhard Rosenkraenzer 
45655d29c98SEric Piel static struct key_entry keymap_acer_travelmate_240[] __initdata = {
4576480e2a2SEric Piel 	{ KE_KEY, 0x01, {KEY_HELP} },
4586480e2a2SEric Piel 	{ KE_KEY, 0x02, {KEY_CONFIG} },
4596480e2a2SEric Piel 	{ KE_KEY, 0x03, {KEY_POWER} },
4606480e2a2SEric Piel 	{ KE_KEY, 0x08, {KEY_MUTE} },
4616480e2a2SEric Piel 	{ KE_KEY, 0x31, {KEY_MAIL} },
4626480e2a2SEric Piel 	{ KE_KEY, 0x36, {KEY_WWW} },
4636480e2a2SEric Piel 	{ KE_KEY, 0x11, {KEY_PROG1} },
4646480e2a2SEric Piel 	{ KE_KEY, 0x12, {KEY_PROG2} },
4656480e2a2SEric Piel 	{ KE_BLUETOOTH, 0x44 },
4666480e2a2SEric Piel 	{ KE_WIFI, 0x30 },
4676480e2a2SEric Piel 	{ KE_END, FE_UNTESTED }
4686480e2a2SEric Piel };
4696480e2a2SEric Piel 
47055d29c98SEric Piel static struct key_entry keymap_acer_travelmate_350[] __initdata = {
4716480e2a2SEric Piel 	{ KE_KEY, 0x01, {KEY_HELP} },
4726480e2a2SEric Piel 	{ KE_KEY, 0x02, {KEY_CONFIG} },
4736480e2a2SEric Piel 	{ KE_KEY, 0x11, {KEY_PROG1} },
4746480e2a2SEric Piel 	{ KE_KEY, 0x12, {KEY_PROG2} },
4756480e2a2SEric Piel 	{ KE_KEY, 0x13, {KEY_MAIL} },
4766480e2a2SEric Piel 	{ KE_KEY, 0x14, {KEY_PROG3} },
4776480e2a2SEric Piel 	{ KE_KEY, 0x15, {KEY_WWW} },
4786480e2a2SEric Piel 	{ KE_END, FE_MAIL_LED | FE_WIFI_LED | FE_UNTESTED }
4796480e2a2SEric Piel };
4806480e2a2SEric Piel 
48155d29c98SEric Piel static struct key_entry keymap_acer_travelmate_360[] __initdata = {
4826480e2a2SEric Piel 	{ KE_KEY, 0x01, {KEY_HELP} },
4836480e2a2SEric Piel 	{ KE_KEY, 0x02, {KEY_CONFIG} },
4846480e2a2SEric Piel 	{ KE_KEY, 0x11, {KEY_PROG1} },
4856480e2a2SEric Piel 	{ KE_KEY, 0x12, {KEY_PROG2} },
4866480e2a2SEric Piel 	{ KE_KEY, 0x13, {KEY_MAIL} },
4876480e2a2SEric Piel 	{ KE_KEY, 0x14, {KEY_PROG3} },
4886480e2a2SEric Piel 	{ KE_KEY, 0x15, {KEY_WWW} },
4896480e2a2SEric Piel 	{ KE_KEY, 0x40, {KEY_WLAN} },
4906480e2a2SEric Piel 	{ KE_END, FE_WIFI_LED | FE_UNTESTED } /* no mail led */
49174a89c96SAshutosh Naik };
49274a89c96SAshutosh Naik 
493bc413c95SEric Piel /* Wifi subsystem only activates the led. Therefore we need to pass
494bc413c95SEric Piel  * wifi event as a normal key, then userspace can really change the wifi state.
495bc413c95SEric Piel  * TODO we need to export led state to userspace (wifi and mail) */
49655d29c98SEric Piel static struct key_entry keymap_acer_travelmate_610[] __initdata = {
4976480e2a2SEric Piel 	{ KE_KEY, 0x01, {KEY_HELP} },
4986480e2a2SEric Piel 	{ KE_KEY, 0x02, {KEY_CONFIG} },
4996480e2a2SEric Piel 	{ KE_KEY, 0x11, {KEY_PROG1} },
500fd013ce8SEric Piel 	{ KE_KEY, 0x12, {KEY_PROG2} },
5016480e2a2SEric Piel 	{ KE_KEY, 0x13, {KEY_PROG3} },
5026480e2a2SEric Piel 	{ KE_KEY, 0x14, {KEY_MAIL} },
5036480e2a2SEric Piel 	{ KE_KEY, 0x15, {KEY_WWW} },
5046480e2a2SEric Piel 	{ KE_KEY, 0x40, {KEY_WLAN} },
5056480e2a2SEric Piel 	{ KE_END, FE_MAIL_LED | FE_WIFI_LED }
5066480e2a2SEric Piel };
5076480e2a2SEric Piel 
50855d29c98SEric Piel static struct key_entry keymap_acer_travelmate_630[] __initdata = {
5096480e2a2SEric Piel 	{ KE_KEY, 0x01, {KEY_HELP} },
5106480e2a2SEric Piel 	{ KE_KEY, 0x02, {KEY_CONFIG} },
5116480e2a2SEric Piel 	{ KE_KEY, 0x03, {KEY_POWER} },
5126480e2a2SEric Piel 	{ KE_KEY, 0x08, {KEY_MUTE} }, /* not 620 */
5136480e2a2SEric Piel 	{ KE_KEY, 0x11, {KEY_PROG1} },
5146480e2a2SEric Piel 	{ KE_KEY, 0x12, {KEY_PROG2} },
5156480e2a2SEric Piel 	{ KE_KEY, 0x13, {KEY_PROG3} },
5166480e2a2SEric Piel 	{ KE_KEY, 0x20, {KEY_VOLUMEUP} },
5176480e2a2SEric Piel 	{ KE_KEY, 0x21, {KEY_VOLUMEDOWN} },
5186480e2a2SEric Piel 	{ KE_KEY, 0x31, {KEY_MAIL} },
5196480e2a2SEric Piel 	{ KE_KEY, 0x36, {KEY_WWW} },
5206480e2a2SEric Piel 	{ KE_WIFI, 0x30 },
5216480e2a2SEric Piel 	{ KE_END, FE_MAIL_LED | FE_UNTESTED }
522bc413c95SEric Piel };
523bc413c95SEric Piel 
52455d29c98SEric Piel static struct key_entry keymap_aopen_1559as[] __initdata = {
5256480e2a2SEric Piel 	{ KE_KEY,  0x01, {KEY_HELP} },
5266480e2a2SEric Piel 	{ KE_KEY,  0x06, {KEY_PROG3} },
5276480e2a2SEric Piel 	{ KE_KEY,  0x11, {KEY_PROG1} },
5286480e2a2SEric Piel 	{ KE_KEY,  0x12, {KEY_PROG2} },
5296480e2a2SEric Piel 	{ KE_WIFI, 0x30 },
5306480e2a2SEric Piel 	{ KE_KEY,  0x31, {KEY_MAIL} },
5316480e2a2SEric Piel 	{ KE_KEY,  0x36, {KEY_WWW} },
5329000195bSFrank de Lange 	{ KE_END,  0 },
533e107b8eeSmasc@theaterzentrum.at };
534e107b8eeSmasc@theaterzentrum.at 
53555d29c98SEric Piel static struct key_entry keymap_fs_amilo_d88x0[] __initdata = {
5366480e2a2SEric Piel 	{ KE_KEY, 0x01, {KEY_HELP} },
5376480e2a2SEric Piel 	{ KE_KEY, 0x08, {KEY_MUTE} },
5386480e2a2SEric Piel 	{ KE_KEY, 0x31, {KEY_MAIL} },
5396480e2a2SEric Piel 	{ KE_KEY, 0x36, {KEY_WWW} },
5406480e2a2SEric Piel 	{ KE_KEY, 0x11, {KEY_PROG1} },
5416480e2a2SEric Piel 	{ KE_KEY, 0x12, {KEY_PROG2} },
5426480e2a2SEric Piel 	{ KE_KEY, 0x13, {KEY_PROG3} },
5436480e2a2SEric Piel 	{ KE_END, FE_MAIL_LED | FE_WIFI_LED | FE_UNTESTED }
5446480e2a2SEric Piel };
5456480e2a2SEric Piel 
54655d29c98SEric Piel static struct key_entry keymap_wistron_md2900[] __initdata = {
5476480e2a2SEric Piel 	{ KE_KEY, 0x01, {KEY_HELP} },
5486480e2a2SEric Piel 	{ KE_KEY, 0x02, {KEY_CONFIG} },
5496480e2a2SEric Piel 	{ KE_KEY, 0x11, {KEY_PROG1} },
5506480e2a2SEric Piel 	{ KE_KEY, 0x12, {KEY_PROG2} },
5516480e2a2SEric Piel 	{ KE_KEY, 0x31, {KEY_MAIL} },
5526480e2a2SEric Piel 	{ KE_KEY, 0x36, {KEY_WWW} },
5536480e2a2SEric Piel 	{ KE_WIFI, 0x30 },
5546480e2a2SEric Piel 	{ KE_END, FE_MAIL_LED | FE_UNTESTED }
5556480e2a2SEric Piel };
5566480e2a2SEric Piel 
55755d29c98SEric Piel static struct key_entry keymap_wistron_md96500[] __initdata = {
5586480e2a2SEric Piel 	{ KE_KEY, 0x01, {KEY_HELP} },
5596480e2a2SEric Piel 	{ KE_KEY, 0x02, {KEY_CONFIG} },
5606480e2a2SEric Piel 	{ KE_KEY, 0x05, {KEY_SWITCHVIDEOMODE} }, /* Display selection */
5616480e2a2SEric Piel 	{ KE_KEY, 0x06, {KEY_DISPLAYTOGGLE} }, /* Display on/off */
5626480e2a2SEric Piel 	{ KE_KEY, 0x08, {KEY_MUTE} },
5636480e2a2SEric Piel 	{ KE_KEY, 0x11, {KEY_PROG1} },
5646480e2a2SEric Piel 	{ KE_KEY, 0x12, {KEY_PROG2} },
5656480e2a2SEric Piel 	{ KE_KEY, 0x20, {KEY_VOLUMEUP} },
5666480e2a2SEric Piel 	{ KE_KEY, 0x21, {KEY_VOLUMEDOWN} },
5676480e2a2SEric Piel 	{ KE_KEY, 0x22, {KEY_REWIND} },
5686480e2a2SEric Piel 	{ KE_KEY, 0x23, {KEY_FORWARD} },
5696480e2a2SEric Piel 	{ KE_KEY, 0x24, {KEY_PLAYPAUSE} },
5706480e2a2SEric Piel 	{ KE_KEY, 0x25, {KEY_STOPCD} },
5716480e2a2SEric Piel 	{ KE_KEY, 0x31, {KEY_MAIL} },
5726480e2a2SEric Piel 	{ KE_KEY, 0x36, {KEY_WWW} },
5736480e2a2SEric Piel 	{ KE_WIFI, 0x30 },
5746480e2a2SEric Piel 	{ KE_BLUETOOTH, 0x44 },
5756480e2a2SEric Piel 	{ KE_END, FE_UNTESTED }
5765809d537SMichael Leun };
5775809d537SMichael Leun 
57855d29c98SEric Piel static struct key_entry keymap_wistron_generic[] __initdata = {
5797b0a4cd7SEric Piel 	{ KE_KEY, 0x01, {KEY_HELP} },
5807b0a4cd7SEric Piel 	{ KE_KEY, 0x02, {KEY_CONFIG} },
5817b0a4cd7SEric Piel 	{ KE_KEY, 0x03, {KEY_POWER} },
5827b0a4cd7SEric Piel 	{ KE_KEY, 0x05, {KEY_SWITCHVIDEOMODE} }, /* Display selection */
5837b0a4cd7SEric Piel 	{ KE_KEY, 0x06, {KEY_DISPLAYTOGGLE} }, /* Display on/off */
5847b0a4cd7SEric Piel 	{ KE_KEY, 0x08, {KEY_MUTE} },
5857b0a4cd7SEric Piel 	{ KE_KEY, 0x11, {KEY_PROG1} },
5867b0a4cd7SEric Piel 	{ KE_KEY, 0x12, {KEY_PROG2} },
5877b0a4cd7SEric Piel 	{ KE_KEY, 0x13, {KEY_PROG3} },
5887b0a4cd7SEric Piel 	{ KE_KEY, 0x14, {KEY_MAIL} },
5897b0a4cd7SEric Piel 	{ KE_KEY, 0x15, {KEY_WWW} },
5907b0a4cd7SEric Piel 	{ KE_KEY, 0x20, {KEY_VOLUMEUP} },
5917b0a4cd7SEric Piel 	{ KE_KEY, 0x21, {KEY_VOLUMEDOWN} },
5927b0a4cd7SEric Piel 	{ KE_KEY, 0x22, {KEY_REWIND} },
5937b0a4cd7SEric Piel 	{ KE_KEY, 0x23, {KEY_FORWARD} },
5947b0a4cd7SEric Piel 	{ KE_KEY, 0x24, {KEY_PLAYPAUSE} },
5957b0a4cd7SEric Piel 	{ KE_KEY, 0x25, {KEY_STOPCD} },
5967b0a4cd7SEric Piel 	{ KE_KEY, 0x31, {KEY_MAIL} },
5977b0a4cd7SEric Piel 	{ KE_KEY, 0x36, {KEY_WWW} },
5987b0a4cd7SEric Piel 	{ KE_KEY, 0x37, {KEY_DISPLAYTOGGLE} }, /* Display on/off */
5997b0a4cd7SEric Piel 	{ KE_KEY, 0x40, {KEY_WLAN} },
6007b0a4cd7SEric Piel 	{ KE_KEY, 0x49, {KEY_CONFIG} },
6017b0a4cd7SEric Piel 	{ KE_SW, 0x4a, {.sw = {SW_LID, 1}} }, /* lid close */
6027b0a4cd7SEric Piel 	{ KE_SW, 0x4b, {.sw = {SW_LID, 0}} }, /* lid open */
6037b0a4cd7SEric Piel 	{ KE_KEY, 0x6a, {KEY_CONFIG} },
6047b0a4cd7SEric Piel 	{ KE_KEY, 0x6d, {KEY_POWER} },
6057b0a4cd7SEric Piel 	{ KE_KEY, 0x71, {KEY_STOPCD} },
6067b0a4cd7SEric Piel 	{ KE_KEY, 0x72, {KEY_PLAYPAUSE} },
6077b0a4cd7SEric Piel 	{ KE_KEY, 0x74, {KEY_REWIND} },
6087b0a4cd7SEric Piel 	{ KE_KEY, 0x78, {KEY_FORWARD} },
6097b0a4cd7SEric Piel 	{ KE_WIFI, 0x30 },
6107b0a4cd7SEric Piel 	{ KE_BLUETOOTH, 0x44 },
6117b0a4cd7SEric Piel 	{ KE_END, 0 }
6127b0a4cd7SEric Piel };
6137b0a4cd7SEric Piel 
61485927b0dSDmitry Torokhov static struct key_entry keymap_aopen_1557[] __initdata = {
61585927b0dSDmitry Torokhov 	{ KE_KEY,  0x01, {KEY_HELP} },
61685927b0dSDmitry Torokhov 	{ KE_KEY,  0x11, {KEY_PROG1} },
61785927b0dSDmitry Torokhov 	{ KE_KEY,  0x12, {KEY_PROG2} },
61885927b0dSDmitry Torokhov 	{ KE_WIFI, 0x30 },
61985927b0dSDmitry Torokhov 	{ KE_KEY,  0x22, {KEY_REWIND} },
62085927b0dSDmitry Torokhov 	{ KE_KEY,  0x23, {KEY_FORWARD} },
62185927b0dSDmitry Torokhov 	{ KE_KEY,  0x24, {KEY_PLAYPAUSE} },
62285927b0dSDmitry Torokhov 	{ KE_KEY,  0x25, {KEY_STOPCD} },
62385927b0dSDmitry Torokhov 	{ KE_KEY,  0x31, {KEY_MAIL} },
62485927b0dSDmitry Torokhov 	{ KE_KEY,  0x36, {KEY_WWW} },
62585927b0dSDmitry Torokhov 	{ KE_END,  0 }
62685927b0dSDmitry Torokhov };
62785927b0dSDmitry Torokhov 
62819493478STJ static struct key_entry keymap_prestigio[] __initdata = {
62919493478STJ 	{ KE_KEY,  0x11, {KEY_PROG1} },
63019493478STJ 	{ KE_KEY,  0x12, {KEY_PROG2} },
63119493478STJ 	{ KE_WIFI, 0x30 },
63219493478STJ 	{ KE_KEY,  0x22, {KEY_REWIND} },
63319493478STJ 	{ KE_KEY,  0x23, {KEY_FORWARD} },
63419493478STJ 	{ KE_KEY,  0x24, {KEY_PLAYPAUSE} },
63519493478STJ 	{ KE_KEY,  0x25, {KEY_STOPCD} },
63619493478STJ 	{ KE_KEY,  0x31, {KEY_MAIL} },
63719493478STJ 	{ KE_KEY,  0x36, {KEY_WWW} },
63819493478STJ 	{ KE_END,  0 }
63919493478STJ };
64019493478STJ 
64119493478STJ 
6425fc14680SDmitry Torokhov /*
6435fc14680SDmitry Torokhov  * If your machine is not here (which is currently rather likely), please send
6445fc14680SDmitry Torokhov  * a list of buttons and their key codes (reported when loading this module
6455fc14680SDmitry Torokhov  * with force=1) and the output of dmidecode to $MODULE_AUTHOR.
6465fc14680SDmitry Torokhov  */
647c7948989SAndrew Morton static struct dmi_system_id dmi_ids[] __initdata = {
6485fc14680SDmitry Torokhov 	{
6495fc14680SDmitry Torokhov 		.callback = dmi_matched,
6505fc14680SDmitry Torokhov 		.ident = "Fujitsu-Siemens Amilo Pro V2000",
6515fc14680SDmitry Torokhov 		.matches = {
6525fc14680SDmitry Torokhov 			DMI_MATCH(DMI_SYS_VENDOR, "FUJITSU SIEMENS"),
6535fc14680SDmitry Torokhov 			DMI_MATCH(DMI_PRODUCT_NAME, "AMILO Pro V2000"),
6545fc14680SDmitry Torokhov 		},
6555fc14680SDmitry Torokhov 		.driver_data = keymap_fs_amilo_pro_v2000
6565fc14680SDmitry Torokhov 	},
65784b256a6SBernhard Rosenkraenzer 	{
65884b256a6SBernhard Rosenkraenzer 		.callback = dmi_matched,
65934a7c48cSRemi Herilier 		.ident = "Fujitsu-Siemens Amilo Pro Edition V3505",
66034a7c48cSRemi Herilier 		.matches = {
66134a7c48cSRemi Herilier 			DMI_MATCH(DMI_SYS_VENDOR, "FUJITSU SIEMENS"),
66234a7c48cSRemi Herilier 			DMI_MATCH(DMI_PRODUCT_NAME, "AMILO Pro Edition V3505"),
66334a7c48cSRemi Herilier 		},
66434a7c48cSRemi Herilier 		.driver_data = keymap_fs_amilo_pro_v3505
66534a7c48cSRemi Herilier 	},
66634a7c48cSRemi Herilier 	{
66734a7c48cSRemi Herilier 		.callback = dmi_matched,
6688a1b1708SStefan Rompf 		.ident = "Fujitsu-Siemens Amilo M7400",
6698a1b1708SStefan Rompf 		.matches = {
6708a1b1708SStefan Rompf 			DMI_MATCH(DMI_SYS_VENDOR, "FUJITSU SIEMENS"),
6718a1b1708SStefan Rompf 			DMI_MATCH(DMI_PRODUCT_NAME, "AMILO M        "),
6728a1b1708SStefan Rompf 		},
6738a1b1708SStefan Rompf 		.driver_data = keymap_fs_amilo_pro_v2000
6748a1b1708SStefan Rompf 	},
6758a1b1708SStefan Rompf 	{
6768a1b1708SStefan Rompf 		.callback = dmi_matched,
677e705cee4SGiuseppe Mazzotta 		.ident = "Maxdata Pro 7000 DX",
678e705cee4SGiuseppe Mazzotta 		.matches = {
679e705cee4SGiuseppe Mazzotta 			DMI_MATCH(DMI_SYS_VENDOR, "MAXDATA"),
680e705cee4SGiuseppe Mazzotta 			DMI_MATCH(DMI_PRODUCT_NAME, "Pro 7000"),
681e705cee4SGiuseppe Mazzotta 		},
682e705cee4SGiuseppe Mazzotta 		.driver_data = keymap_fs_amilo_pro_v2000
683e705cee4SGiuseppe Mazzotta 	},
684e705cee4SGiuseppe Mazzotta 	{
685e705cee4SGiuseppe Mazzotta 		.callback = dmi_matched,
686e2aa507aSJohn Reed Riley 		.ident = "Fujitsu N3510",
687e2aa507aSJohn Reed Riley 		.matches = {
688e2aa507aSJohn Reed Riley 			DMI_MATCH(DMI_SYS_VENDOR, "FUJITSU"),
689e2aa507aSJohn Reed Riley 			DMI_MATCH(DMI_PRODUCT_NAME, "N3510"),
690e2aa507aSJohn Reed Riley 		},
691e2aa507aSJohn Reed Riley 		.driver_data = keymap_fujitsu_n3510
692e2aa507aSJohn Reed Riley 	},
693e2aa507aSJohn Reed Riley 	{
694e2aa507aSJohn Reed Riley 		.callback = dmi_matched,
69584b256a6SBernhard Rosenkraenzer 		.ident = "Acer Aspire 1500",
69684b256a6SBernhard Rosenkraenzer 		.matches = {
69784b256a6SBernhard Rosenkraenzer 			DMI_MATCH(DMI_SYS_VENDOR, "Acer"),
69884b256a6SBernhard Rosenkraenzer 			DMI_MATCH(DMI_PRODUCT_NAME, "Aspire 1500"),
69984b256a6SBernhard Rosenkraenzer 		},
70084b256a6SBernhard Rosenkraenzer 		.driver_data = keymap_acer_aspire_1500
70184b256a6SBernhard Rosenkraenzer 	},
70274a89c96SAshutosh Naik 	{
70374a89c96SAshutosh Naik 		.callback = dmi_matched,
7046480e2a2SEric Piel 		.ident = "Acer Aspire 1600",
7056480e2a2SEric Piel 		.matches = {
7066480e2a2SEric Piel 			DMI_MATCH(DMI_SYS_VENDOR, "Acer"),
7076480e2a2SEric Piel 			DMI_MATCH(DMI_PRODUCT_NAME, "Aspire 1600"),
7086480e2a2SEric Piel 		},
7096480e2a2SEric Piel 		.driver_data = keymap_acer_aspire_1600
7106480e2a2SEric Piel 	},
7116480e2a2SEric Piel 	{
7126480e2a2SEric Piel 		.callback = dmi_matched,
7136480e2a2SEric Piel 		.ident = "Acer Aspire 3020",
7146480e2a2SEric Piel 		.matches = {
7156480e2a2SEric Piel 			DMI_MATCH(DMI_SYS_VENDOR, "Acer"),
7166480e2a2SEric Piel 			DMI_MATCH(DMI_PRODUCT_NAME, "Aspire 3020"),
7176480e2a2SEric Piel 		},
7186480e2a2SEric Piel 		.driver_data = keymap_acer_aspire_5020
7196480e2a2SEric Piel 	},
7206480e2a2SEric Piel 	{
7216480e2a2SEric Piel 		.callback = dmi_matched,
7226480e2a2SEric Piel 		.ident = "Acer Aspire 5020",
7236480e2a2SEric Piel 		.matches = {
7246480e2a2SEric Piel 			DMI_MATCH(DMI_SYS_VENDOR, "Acer"),
7256480e2a2SEric Piel 			DMI_MATCH(DMI_PRODUCT_NAME, "Aspire 5020"),
7266480e2a2SEric Piel 		},
7276480e2a2SEric Piel 		.driver_data = keymap_acer_aspire_5020
7286480e2a2SEric Piel 	},
7296480e2a2SEric Piel 	{
7306480e2a2SEric Piel 		.callback = dmi_matched,
7316480e2a2SEric Piel 		.ident = "Acer TravelMate 2100",
7326480e2a2SEric Piel 		.matches = {
7336480e2a2SEric Piel 			DMI_MATCH(DMI_SYS_VENDOR, "Acer"),
7346480e2a2SEric Piel 			DMI_MATCH(DMI_PRODUCT_NAME, "TravelMate 2100"),
7356480e2a2SEric Piel 		},
7366480e2a2SEric Piel 		.driver_data = keymap_acer_aspire_5020
7376480e2a2SEric Piel 	},
7386480e2a2SEric Piel 	{
7396480e2a2SEric Piel 		.callback = dmi_matched,
7406480e2a2SEric Piel 		.ident = "Acer TravelMate 2410",
7416480e2a2SEric Piel 		.matches = {
7426480e2a2SEric Piel 			DMI_MATCH(DMI_SYS_VENDOR, "Acer"),
7436480e2a2SEric Piel 			DMI_MATCH(DMI_PRODUCT_NAME, "TravelMate 2410"),
7446480e2a2SEric Piel 		},
7456480e2a2SEric Piel 		.driver_data = keymap_acer_travelmate_2410
7466480e2a2SEric Piel 	},
7476480e2a2SEric Piel 	{
7486480e2a2SEric Piel 		.callback = dmi_matched,
7496480e2a2SEric Piel 		.ident = "Acer TravelMate C300",
7506480e2a2SEric Piel 		.matches = {
7516480e2a2SEric Piel 			DMI_MATCH(DMI_SYS_VENDOR, "Acer"),
7526480e2a2SEric Piel 			DMI_MATCH(DMI_PRODUCT_NAME, "TravelMate C300"),
7536480e2a2SEric Piel 		},
7546480e2a2SEric Piel 		.driver_data = keymap_acer_travelmate_300
7556480e2a2SEric Piel 	},
7566480e2a2SEric Piel 	{
7576480e2a2SEric Piel 		.callback = dmi_matched,
7586480e2a2SEric Piel 		.ident = "Acer TravelMate C100",
7596480e2a2SEric Piel 		.matches = {
7606480e2a2SEric Piel 			DMI_MATCH(DMI_SYS_VENDOR, "Acer"),
7616480e2a2SEric Piel 			DMI_MATCH(DMI_PRODUCT_NAME, "TravelMate C100"),
7626480e2a2SEric Piel 		},
7636480e2a2SEric Piel 		.driver_data = keymap_acer_travelmate_300
7646480e2a2SEric Piel 	},
7656480e2a2SEric Piel 	{
7666480e2a2SEric Piel 		.callback = dmi_matched,
7676480e2a2SEric Piel 		.ident = "Acer TravelMate C110",
7686480e2a2SEric Piel 		.matches = {
7696480e2a2SEric Piel 			DMI_MATCH(DMI_SYS_VENDOR, "Acer"),
7706480e2a2SEric Piel 			DMI_MATCH(DMI_PRODUCT_NAME, "TravelMate C110"),
7716480e2a2SEric Piel 		},
7726480e2a2SEric Piel 		.driver_data = keymap_acer_travelmate_110
7736480e2a2SEric Piel 	},
7746480e2a2SEric Piel 	{
7756480e2a2SEric Piel 		.callback = dmi_matched,
7766480e2a2SEric Piel 		.ident = "Acer TravelMate 380",
7776480e2a2SEric Piel 		.matches = {
7786480e2a2SEric Piel 			DMI_MATCH(DMI_SYS_VENDOR, "Acer"),
7796480e2a2SEric Piel 			DMI_MATCH(DMI_PRODUCT_NAME, "TravelMate 380"),
7806480e2a2SEric Piel 		},
7816480e2a2SEric Piel 		.driver_data = keymap_acer_travelmate_380
7826480e2a2SEric Piel 	},
7836480e2a2SEric Piel 	{
7846480e2a2SEric Piel 		.callback = dmi_matched,
7856480e2a2SEric Piel 		.ident = "Acer TravelMate 370",
7866480e2a2SEric Piel 		.matches = {
7876480e2a2SEric Piel 			DMI_MATCH(DMI_SYS_VENDOR, "Acer"),
7886480e2a2SEric Piel 			DMI_MATCH(DMI_PRODUCT_NAME, "TravelMate 370"),
7896480e2a2SEric Piel 		},
7906480e2a2SEric Piel 		.driver_data = keymap_acer_travelmate_380 /* keyboard minus 1 key */
7916480e2a2SEric Piel 	},
7926480e2a2SEric Piel 	{
7936480e2a2SEric Piel 		.callback = dmi_matched,
7946480e2a2SEric Piel 		.ident = "Acer TravelMate 220",
7956480e2a2SEric Piel 		.matches = {
7966480e2a2SEric Piel 			DMI_MATCH(DMI_SYS_VENDOR, "Acer"),
7976480e2a2SEric Piel 			DMI_MATCH(DMI_PRODUCT_NAME, "TravelMate 220"),
7986480e2a2SEric Piel 		},
7996480e2a2SEric Piel 		.driver_data = keymap_acer_travelmate_220
8006480e2a2SEric Piel 	},
8016480e2a2SEric Piel 	{
8026480e2a2SEric Piel 		.callback = dmi_matched,
8036480e2a2SEric Piel 		.ident = "Acer TravelMate 260",
8046480e2a2SEric Piel 		.matches = {
8056480e2a2SEric Piel 			DMI_MATCH(DMI_SYS_VENDOR, "Acer"),
8066480e2a2SEric Piel 			DMI_MATCH(DMI_PRODUCT_NAME, "TravelMate 260"),
8076480e2a2SEric Piel 		},
8086480e2a2SEric Piel 		.driver_data = keymap_acer_travelmate_220
8096480e2a2SEric Piel 	},
8106480e2a2SEric Piel 	{
8116480e2a2SEric Piel 		.callback = dmi_matched,
8126480e2a2SEric Piel 		.ident = "Acer TravelMate 230",
8136480e2a2SEric Piel 		.matches = {
8146480e2a2SEric Piel 			DMI_MATCH(DMI_SYS_VENDOR, "Acer"),
8156480e2a2SEric Piel 			DMI_MATCH(DMI_PRODUCT_NAME, "TravelMate 230"),
8166480e2a2SEric Piel 			/* acerhk looks for "TravelMate F4..." ?! */
8176480e2a2SEric Piel 		},
8186480e2a2SEric Piel 		.driver_data = keymap_acer_travelmate_230
8196480e2a2SEric Piel 	},
8206480e2a2SEric Piel 	{
8216480e2a2SEric Piel 		.callback = dmi_matched,
8226480e2a2SEric Piel 		.ident = "Acer TravelMate 280",
8236480e2a2SEric Piel 		.matches = {
8246480e2a2SEric Piel 			DMI_MATCH(DMI_SYS_VENDOR, "Acer"),
8256480e2a2SEric Piel 			DMI_MATCH(DMI_PRODUCT_NAME, "TravelMate 280"),
8266480e2a2SEric Piel 		},
8276480e2a2SEric Piel 		.driver_data = keymap_acer_travelmate_230
8286480e2a2SEric Piel 	},
8296480e2a2SEric Piel 	{
8306480e2a2SEric Piel 		.callback = dmi_matched,
83174a89c96SAshutosh Naik 		.ident = "Acer TravelMate 240",
83274a89c96SAshutosh Naik 		.matches = {
83374a89c96SAshutosh Naik 			DMI_MATCH(DMI_SYS_VENDOR, "Acer"),
83474a89c96SAshutosh Naik 			DMI_MATCH(DMI_PRODUCT_NAME, "TravelMate 240"),
83574a89c96SAshutosh Naik 		},
83674a89c96SAshutosh Naik 		.driver_data = keymap_acer_travelmate_240
83774a89c96SAshutosh Naik 	},
838e107b8eeSmasc@theaterzentrum.at 	{
839bb088590SAshutosh Naik 		.callback = dmi_matched,
8406480e2a2SEric Piel 		.ident = "Acer TravelMate 250",
8416480e2a2SEric Piel 		.matches = {
8426480e2a2SEric Piel 			DMI_MATCH(DMI_SYS_VENDOR, "Acer"),
8436480e2a2SEric Piel 			DMI_MATCH(DMI_PRODUCT_NAME, "TravelMate 250"),
8446480e2a2SEric Piel 		},
8456480e2a2SEric Piel 		.driver_data = keymap_acer_travelmate_240
8466480e2a2SEric Piel 	},
8476480e2a2SEric Piel 	{
8486480e2a2SEric Piel 		.callback = dmi_matched,
849bb088590SAshutosh Naik 		.ident = "Acer TravelMate 2424NWXCi",
850bb088590SAshutosh Naik 		.matches = {
851bb088590SAshutosh Naik 			DMI_MATCH(DMI_SYS_VENDOR, "Acer"),
852bb088590SAshutosh Naik 			DMI_MATCH(DMI_PRODUCT_NAME, "TravelMate 2420"),
853bb088590SAshutosh Naik 		},
854bb088590SAshutosh Naik 		.driver_data = keymap_acer_travelmate_240
855bb088590SAshutosh Naik 	},
856bb088590SAshutosh Naik 	{
857e107b8eeSmasc@theaterzentrum.at 		.callback = dmi_matched,
8586480e2a2SEric Piel 		.ident = "Acer TravelMate 350",
8596480e2a2SEric Piel 		.matches = {
8606480e2a2SEric Piel 			DMI_MATCH(DMI_SYS_VENDOR, "Acer"),
8616480e2a2SEric Piel 			DMI_MATCH(DMI_PRODUCT_NAME, "TravelMate 350"),
8626480e2a2SEric Piel 		},
8636480e2a2SEric Piel 		.driver_data = keymap_acer_travelmate_350
8646480e2a2SEric Piel 	},
8656480e2a2SEric Piel 	{
8666480e2a2SEric Piel 		.callback = dmi_matched,
8676480e2a2SEric Piel 		.ident = "Acer TravelMate 360",
8686480e2a2SEric Piel 		.matches = {
8696480e2a2SEric Piel 			DMI_MATCH(DMI_SYS_VENDOR, "Acer"),
8706480e2a2SEric Piel 			DMI_MATCH(DMI_PRODUCT_NAME, "TravelMate 360"),
8716480e2a2SEric Piel 		},
8726480e2a2SEric Piel 		.driver_data = keymap_acer_travelmate_360
8736480e2a2SEric Piel 	},
8746480e2a2SEric Piel 	{
8756480e2a2SEric Piel 		.callback = dmi_matched,
876bc413c95SEric Piel 		.ident = "Acer TravelMate 610",
877bc413c95SEric Piel 		.matches = {
878bc413c95SEric Piel 			DMI_MATCH(DMI_SYS_VENDOR, "ACER"),
879bc413c95SEric Piel 			DMI_MATCH(DMI_PRODUCT_NAME, "TravelMate 610"),
880bc413c95SEric Piel 		},
881bc413c95SEric Piel 		.driver_data = keymap_acer_travelmate_610
882bc413c95SEric Piel 	},
883bc413c95SEric Piel 	{
884bc413c95SEric Piel 		.callback = dmi_matched,
8856480e2a2SEric Piel 		.ident = "Acer TravelMate 620",
8866480e2a2SEric Piel 		.matches = {
8876480e2a2SEric Piel 			DMI_MATCH(DMI_SYS_VENDOR, "Acer"),
8886480e2a2SEric Piel 			DMI_MATCH(DMI_PRODUCT_NAME, "TravelMate 620"),
8896480e2a2SEric Piel 		},
8906480e2a2SEric Piel 		.driver_data = keymap_acer_travelmate_630
8916480e2a2SEric Piel 	},
8926480e2a2SEric Piel 	{
8936480e2a2SEric Piel 		.callback = dmi_matched,
8946480e2a2SEric Piel 		.ident = "Acer TravelMate 630",
8956480e2a2SEric Piel 		.matches = {
8966480e2a2SEric Piel 			DMI_MATCH(DMI_SYS_VENDOR, "Acer"),
8976480e2a2SEric Piel 			DMI_MATCH(DMI_PRODUCT_NAME, "TravelMate 630"),
8986480e2a2SEric Piel 		},
8996480e2a2SEric Piel 		.driver_data = keymap_acer_travelmate_630
9006480e2a2SEric Piel 	},
9016480e2a2SEric Piel 	{
9026480e2a2SEric Piel 		.callback = dmi_matched,
903e107b8eeSmasc@theaterzentrum.at 		.ident = "AOpen 1559AS",
904e107b8eeSmasc@theaterzentrum.at 		.matches = {
905e107b8eeSmasc@theaterzentrum.at 			DMI_MATCH(DMI_PRODUCT_NAME, "E2U"),
906e107b8eeSmasc@theaterzentrum.at 			DMI_MATCH(DMI_BOARD_NAME, "E2U"),
907e107b8eeSmasc@theaterzentrum.at 		},
908e107b8eeSmasc@theaterzentrum.at 		.driver_data = keymap_aopen_1559as
909e107b8eeSmasc@theaterzentrum.at 	},
9109000195bSFrank de Lange 	{
9119000195bSFrank de Lange 		.callback = dmi_matched,
9129000195bSFrank de Lange 		.ident = "Medion MD 9783",
9139000195bSFrank de Lange 		.matches = {
9149000195bSFrank de Lange 			DMI_MATCH(DMI_SYS_VENDOR, "MEDIONNB"),
9159000195bSFrank de Lange 			DMI_MATCH(DMI_PRODUCT_NAME, "MD 9783"),
9169000195bSFrank de Lange 		},
9179000195bSFrank de Lange 		.driver_data = keymap_wistron_ms2111
9189000195bSFrank de Lange 	},
9195809d537SMichael Leun 	{
9205809d537SMichael Leun 		.callback = dmi_matched,
9216480e2a2SEric Piel 		.ident = "Medion MD 40100",
9226480e2a2SEric Piel 		.matches = {
9236480e2a2SEric Piel 			DMI_MATCH(DMI_SYS_VENDOR, "MEDIONNB"),
9246480e2a2SEric Piel 			DMI_MATCH(DMI_PRODUCT_NAME, "WID2000"),
9256480e2a2SEric Piel 		},
9266480e2a2SEric Piel 		.driver_data = keymap_wistron_md40100
9276480e2a2SEric Piel 	},
9286480e2a2SEric Piel 	{
9296480e2a2SEric Piel 		.callback = dmi_matched,
9306480e2a2SEric Piel 		.ident = "Medion MD 2900",
9316480e2a2SEric Piel 		.matches = {
9326480e2a2SEric Piel 			DMI_MATCH(DMI_SYS_VENDOR, "MEDIONNB"),
9336480e2a2SEric Piel 			DMI_MATCH(DMI_PRODUCT_NAME, "WIM 2000"),
9346480e2a2SEric Piel 		},
9356480e2a2SEric Piel 		.driver_data = keymap_wistron_md2900
9366480e2a2SEric Piel 	},
9376480e2a2SEric Piel 	{
9386480e2a2SEric Piel 		.callback = dmi_matched,
9393bfb0a7eSSebastian Frei 		.ident = "Medion MD 42200",
9403bfb0a7eSSebastian Frei 		.matches = {
9413bfb0a7eSSebastian Frei 			DMI_MATCH(DMI_SYS_VENDOR, "Medion"),
9423bfb0a7eSSebastian Frei 			DMI_MATCH(DMI_PRODUCT_NAME, "WIM 2030"),
9433bfb0a7eSSebastian Frei 		},
9443bfb0a7eSSebastian Frei 		.driver_data = keymap_fs_amilo_pro_v2000
9453bfb0a7eSSebastian Frei 	},
9463bfb0a7eSSebastian Frei 	{
9473bfb0a7eSSebastian Frei 		.callback = dmi_matched,
9486480e2a2SEric Piel 		.ident = "Medion MD 96500",
9496480e2a2SEric Piel 		.matches = {
9506480e2a2SEric Piel 			DMI_MATCH(DMI_SYS_VENDOR, "MEDIONPC"),
9516480e2a2SEric Piel 			DMI_MATCH(DMI_PRODUCT_NAME, "WIM 2040"),
9526480e2a2SEric Piel 		},
9536480e2a2SEric Piel 		.driver_data = keymap_wistron_md96500
9546480e2a2SEric Piel 	},
9556480e2a2SEric Piel 	{
9566480e2a2SEric Piel 		.callback = dmi_matched,
9576480e2a2SEric Piel 		.ident = "Medion MD 95400",
9586480e2a2SEric Piel 		.matches = {
9596480e2a2SEric Piel 			DMI_MATCH(DMI_SYS_VENDOR, "MEDIONPC"),
9606480e2a2SEric Piel 			DMI_MATCH(DMI_PRODUCT_NAME, "WIM 2050"),
9616480e2a2SEric Piel 		},
9626480e2a2SEric Piel 		.driver_data = keymap_wistron_md96500
9636480e2a2SEric Piel 	},
9646480e2a2SEric Piel 	{
9656480e2a2SEric Piel 		.callback = dmi_matched,
9666480e2a2SEric Piel 		.ident = "Fujitsu Siemens Amilo D7820",
9676480e2a2SEric Piel 		.matches = {
9686480e2a2SEric Piel 			DMI_MATCH(DMI_SYS_VENDOR, "FUJITSU SIEMENS"), /* not sure */
9696480e2a2SEric Piel 			DMI_MATCH(DMI_PRODUCT_NAME, "Amilo D"),
9706480e2a2SEric Piel 		},
9716480e2a2SEric Piel 		.driver_data = keymap_fs_amilo_d88x0
9726480e2a2SEric Piel 	},
9736480e2a2SEric Piel 	{
9746480e2a2SEric Piel 		.callback = dmi_matched,
9755809d537SMichael Leun 		.ident = "Fujitsu Siemens Amilo D88x0",
9765809d537SMichael Leun 		.matches = {
9775809d537SMichael Leun 			DMI_MATCH(DMI_SYS_VENDOR, "FUJITSU SIEMENS"),
9785809d537SMichael Leun 			DMI_MATCH(DMI_PRODUCT_NAME, "AMILO D"),
9795809d537SMichael Leun 		},
9805809d537SMichael Leun 		.driver_data = keymap_fs_amilo_d88x0
9815809d537SMichael Leun 	},
98281f0a91eSAl Viro 	{ NULL, }
9835fc14680SDmitry Torokhov };
9845fc14680SDmitry Torokhov 
98555d29c98SEric Piel /* Copy the good keymap, as the original ones are free'd */
98655d29c98SEric Piel static int __init copy_keymap(void)
98755d29c98SEric Piel {
98855d29c98SEric Piel 	const struct key_entry *key;
98955d29c98SEric Piel 	struct key_entry *new_keymap;
99055d29c98SEric Piel 	unsigned int length = 1;
99155d29c98SEric Piel 
99255d29c98SEric Piel 	for (key = keymap; key->type != KE_END; key++)
99355d29c98SEric Piel 		length++;
99455d29c98SEric Piel 
99555d29c98SEric Piel 	new_keymap = kmalloc(length * sizeof(struct key_entry), GFP_KERNEL);
99655d29c98SEric Piel 	if (!new_keymap)
99755d29c98SEric Piel 		return -ENOMEM;
99855d29c98SEric Piel 
99955d29c98SEric Piel 	memcpy(new_keymap, keymap, length * sizeof(struct key_entry));
100055d29c98SEric Piel 	keymap = new_keymap;
100155d29c98SEric Piel 
100255d29c98SEric Piel 	return 0;
100355d29c98SEric Piel }
100455d29c98SEric Piel 
10055fc14680SDmitry Torokhov static int __init select_keymap(void)
10065fc14680SDmitry Torokhov {
10077b0a4cd7SEric Piel 	dmi_check_system(dmi_ids);
10085fc14680SDmitry Torokhov 	if (keymap_name != NULL) {
10095fc14680SDmitry Torokhov 		if (strcmp (keymap_name, "1557/MS2141") == 0)
10105fc14680SDmitry Torokhov 			keymap = keymap_wistron_ms2141;
101185927b0dSDmitry Torokhov 		else if (strcmp (keymap_name, "aopen1557") == 0)
101285927b0dSDmitry Torokhov 			keymap = keymap_aopen_1557;
101319493478STJ 		else if (strcmp (keymap_name, "prestigio") == 0)
101419493478STJ 			keymap = keymap_prestigio;
10157b0a4cd7SEric Piel 		else if (strcmp (keymap_name, "generic") == 0)
10167b0a4cd7SEric Piel 			keymap = keymap_wistron_generic;
10175fc14680SDmitry Torokhov 		else {
10185fc14680SDmitry Torokhov 			printk(KERN_ERR "wistron_btns: Keymap unknown\n");
10195fc14680SDmitry Torokhov 			return -EINVAL;
10205fc14680SDmitry Torokhov 		}
10215fc14680SDmitry Torokhov 	}
10225fc14680SDmitry Torokhov 	if (keymap == NULL) {
10235fc14680SDmitry Torokhov 		if (!force) {
10245fc14680SDmitry Torokhov 			printk(KERN_ERR "wistron_btns: System unknown\n");
10255fc14680SDmitry Torokhov 			return -ENODEV;
10265fc14680SDmitry Torokhov 		}
10275fc14680SDmitry Torokhov 		keymap = keymap_empty;
10285fc14680SDmitry Torokhov 	}
102955d29c98SEric Piel 
103055d29c98SEric Piel 	return copy_keymap();
10315fc14680SDmitry Torokhov }
10325fc14680SDmitry Torokhov 
10335fc14680SDmitry Torokhov  /* Input layer interface */
10345fc14680SDmitry Torokhov 
1035c2554c91SDmitry Torokhov static struct input_polled_dev *wistron_idev;
1036c2554c91SDmitry Torokhov static unsigned long jiffies_last_press;
103767dbe83aSDmitry Torokhov static bool wifi_enabled;
103867dbe83aSDmitry Torokhov static bool bluetooth_enabled;
10395fc14680SDmitry Torokhov 
1040c2554c91SDmitry Torokhov static void report_key(struct input_dev *dev, unsigned int keycode)
10415fc14680SDmitry Torokhov {
1042c2554c91SDmitry Torokhov 	input_report_key(dev, keycode, 1);
1043c2554c91SDmitry Torokhov 	input_sync(dev);
1044c2554c91SDmitry Torokhov 	input_report_key(dev, keycode, 0);
1045c2554c91SDmitry Torokhov 	input_sync(dev);
10465fc14680SDmitry Torokhov }
10475fc14680SDmitry Torokhov 
1048c2554c91SDmitry Torokhov static void report_switch(struct input_dev *dev, unsigned int code, int value)
10495fc14680SDmitry Torokhov {
1050c2554c91SDmitry Torokhov 	input_report_switch(dev, code, value);
1051c2554c91SDmitry Torokhov 	input_sync(dev);
10526480e2a2SEric Piel }
10536480e2a2SEric Piel 
1054389679d8SEric Piel 
1055389679d8SEric Piel  /* led management */
1056389679d8SEric Piel static void wistron_mail_led_set(struct led_classdev *led_cdev,
1057389679d8SEric Piel 				enum led_brightness value)
1058389679d8SEric Piel {
1059389679d8SEric Piel 	bios_set_state(MAIL_LED, (value != LED_OFF) ? 1 : 0);
1060389679d8SEric Piel }
1061389679d8SEric Piel 
1062389679d8SEric Piel /* same as setting up wifi card, but for laptops on which the led is managed */
1063389679d8SEric Piel static void wistron_wifi_led_set(struct led_classdev *led_cdev,
1064389679d8SEric Piel 				enum led_brightness value)
1065389679d8SEric Piel {
1066389679d8SEric Piel 	bios_set_state(WIFI, (value != LED_OFF) ? 1 : 0);
1067389679d8SEric Piel }
1068389679d8SEric Piel 
1069389679d8SEric Piel static struct led_classdev wistron_mail_led = {
10706c152beeSRichard Purdie 	.name			= "wistron:green:mail",
1071389679d8SEric Piel 	.brightness_set		= wistron_mail_led_set,
1072389679d8SEric Piel };
1073389679d8SEric Piel 
1074389679d8SEric Piel static struct led_classdev wistron_wifi_led = {
10756c152beeSRichard Purdie 	.name			= "wistron:red:wifi",
1076389679d8SEric Piel 	.brightness_set		= wistron_wifi_led_set,
1077389679d8SEric Piel };
1078389679d8SEric Piel 
1079389679d8SEric Piel static void __devinit wistron_led_init(struct device *parent)
1080389679d8SEric Piel {
108167dbe83aSDmitry Torokhov 	if (leds_present & FE_WIFI_LED) {
1082389679d8SEric Piel 		u16 wifi = bios_get_default_setting(WIFI);
1083389679d8SEric Piel 		if (wifi & 1) {
1084389679d8SEric Piel 			wistron_wifi_led.brightness = (wifi & 2) ? LED_FULL : LED_OFF;
1085389679d8SEric Piel 			if (led_classdev_register(parent, &wistron_wifi_led))
108667dbe83aSDmitry Torokhov 				leds_present &= ~FE_WIFI_LED;
1087389679d8SEric Piel 			else
1088389679d8SEric Piel 				bios_set_state(WIFI, wistron_wifi_led.brightness);
1089389679d8SEric Piel 
1090389679d8SEric Piel 		} else
109167dbe83aSDmitry Torokhov 			leds_present &= ~FE_WIFI_LED;
1092389679d8SEric Piel 	}
1093389679d8SEric Piel 
109467dbe83aSDmitry Torokhov 	if (leds_present & FE_MAIL_LED) {
1095389679d8SEric Piel 		/* bios_get_default_setting(MAIL) always retuns 0, so just turn the led off */
1096389679d8SEric Piel 		wistron_mail_led.brightness = LED_OFF;
1097389679d8SEric Piel 		if (led_classdev_register(parent, &wistron_mail_led))
109867dbe83aSDmitry Torokhov 			leds_present &= ~FE_MAIL_LED;
1099389679d8SEric Piel 		else
1100389679d8SEric Piel 			bios_set_state(MAIL_LED, wistron_mail_led.brightness);
1101389679d8SEric Piel 	}
1102389679d8SEric Piel }
1103389679d8SEric Piel 
1104389679d8SEric Piel static void __devexit wistron_led_remove(void)
1105389679d8SEric Piel {
110667dbe83aSDmitry Torokhov 	if (leds_present & FE_MAIL_LED)
1107389679d8SEric Piel 		led_classdev_unregister(&wistron_mail_led);
1108389679d8SEric Piel 
110967dbe83aSDmitry Torokhov 	if (leds_present & FE_WIFI_LED)
1110389679d8SEric Piel 		led_classdev_unregister(&wistron_wifi_led);
1111389679d8SEric Piel }
1112389679d8SEric Piel 
1113389679d8SEric Piel static inline void wistron_led_suspend(void)
1114389679d8SEric Piel {
111567dbe83aSDmitry Torokhov 	if (leds_present & FE_MAIL_LED)
1116389679d8SEric Piel 		led_classdev_suspend(&wistron_mail_led);
1117389679d8SEric Piel 
111867dbe83aSDmitry Torokhov 	if (leds_present & FE_WIFI_LED)
1119389679d8SEric Piel 		led_classdev_suspend(&wistron_wifi_led);
1120389679d8SEric Piel }
1121389679d8SEric Piel 
1122389679d8SEric Piel static inline void wistron_led_resume(void)
1123389679d8SEric Piel {
112467dbe83aSDmitry Torokhov 	if (leds_present & FE_MAIL_LED)
1125389679d8SEric Piel 		led_classdev_resume(&wistron_mail_led);
1126389679d8SEric Piel 
112767dbe83aSDmitry Torokhov 	if (leds_present & FE_WIFI_LED)
1128389679d8SEric Piel 		led_classdev_resume(&wistron_wifi_led);
1129389679d8SEric Piel }
1130389679d8SEric Piel 
1131d63219a1SDmitry Torokhov static struct key_entry *wistron_get_entry_by_scancode(int code)
1132d63219a1SDmitry Torokhov {
1133d63219a1SDmitry Torokhov 	struct key_entry *key;
1134d63219a1SDmitry Torokhov 
1135d63219a1SDmitry Torokhov 	for (key = keymap; key->type != KE_END; key++)
1136d63219a1SDmitry Torokhov 		if (code == key->code)
1137d63219a1SDmitry Torokhov 			return key;
1138d63219a1SDmitry Torokhov 
1139d63219a1SDmitry Torokhov 	return NULL;
1140d63219a1SDmitry Torokhov }
1141d63219a1SDmitry Torokhov 
1142d63219a1SDmitry Torokhov static struct key_entry *wistron_get_entry_by_keycode(int keycode)
1143d63219a1SDmitry Torokhov {
1144d63219a1SDmitry Torokhov 	struct key_entry *key;
1145d63219a1SDmitry Torokhov 
1146d63219a1SDmitry Torokhov 	for (key = keymap; key->type != KE_END; key++)
1147d63219a1SDmitry Torokhov 		if (key->type == KE_KEY && keycode == key->keycode)
1148d63219a1SDmitry Torokhov 			return key;
1149d63219a1SDmitry Torokhov 
1150d63219a1SDmitry Torokhov 	return NULL;
1151d63219a1SDmitry Torokhov }
1152d63219a1SDmitry Torokhov 
11535fc14680SDmitry Torokhov static void handle_key(u8 code)
11545fc14680SDmitry Torokhov {
1155d63219a1SDmitry Torokhov 	const struct key_entry *key = wistron_get_entry_by_scancode(code);
11565fc14680SDmitry Torokhov 
1157d63219a1SDmitry Torokhov 	if (key) {
11585fc14680SDmitry Torokhov 		switch (key->type) {
11595fc14680SDmitry Torokhov 		case KE_KEY:
1160c2554c91SDmitry Torokhov 			report_key(wistron_idev->input, key->keycode);
11615fc14680SDmitry Torokhov 			break;
11625fc14680SDmitry Torokhov 
11636480e2a2SEric Piel 		case KE_SW:
1164c2554c91SDmitry Torokhov 			report_switch(wistron_idev->input,
1165c2554c91SDmitry Torokhov 				      key->sw.code, key->sw.value);
11666480e2a2SEric Piel 			break;
11676480e2a2SEric Piel 
11685fc14680SDmitry Torokhov 		case KE_WIFI:
11695fc14680SDmitry Torokhov 			if (have_wifi) {
11705fc14680SDmitry Torokhov 				wifi_enabled = !wifi_enabled;
117184b256a6SBernhard Rosenkraenzer 				bios_set_state(WIFI, wifi_enabled);
117284b256a6SBernhard Rosenkraenzer 			}
117384b256a6SBernhard Rosenkraenzer 			break;
117484b256a6SBernhard Rosenkraenzer 
117584b256a6SBernhard Rosenkraenzer 		case KE_BLUETOOTH:
117684b256a6SBernhard Rosenkraenzer 			if (have_bluetooth) {
117784b256a6SBernhard Rosenkraenzer 				bluetooth_enabled = !bluetooth_enabled;
117884b256a6SBernhard Rosenkraenzer 				bios_set_state(BLUETOOTH, bluetooth_enabled);
11795fc14680SDmitry Torokhov 			}
11805fc14680SDmitry Torokhov 			break;
11815fc14680SDmitry Torokhov 
11825fc14680SDmitry Torokhov 		default:
11835fc14680SDmitry Torokhov 			BUG();
11845fc14680SDmitry Torokhov 		}
1185c2554c91SDmitry Torokhov 		jiffies_last_press = jiffies;
1186d63219a1SDmitry Torokhov 	} else
1187d63219a1SDmitry Torokhov 		printk(KERN_NOTICE
1188d63219a1SDmitry Torokhov 			"wistron_btns: Unknown key code %02X\n", code);
11895fc14680SDmitry Torokhov }
11905fc14680SDmitry Torokhov 
1191c2554c91SDmitry Torokhov static void poll_bios(bool discard)
11925fc14680SDmitry Torokhov {
11935fc14680SDmitry Torokhov 	u8 qlen;
11945fc14680SDmitry Torokhov 	u16 val;
11955fc14680SDmitry Torokhov 
11965fc14680SDmitry Torokhov 	for (;;) {
11975fc14680SDmitry Torokhov 		qlen = CMOS_READ(cmos_address);
11985fc14680SDmitry Torokhov 		if (qlen == 0)
11995fc14680SDmitry Torokhov 			break;
12005fc14680SDmitry Torokhov 		val = bios_pop_queue();
1201c2554c91SDmitry Torokhov 		if (val != 0 && !discard)
12025fc14680SDmitry Torokhov 			handle_key((u8)val);
1203a4da16d3SEric Piel 	}
12045fc14680SDmitry Torokhov }
12055fc14680SDmitry Torokhov 
1206c2554c91SDmitry Torokhov static void wistron_flush(struct input_polled_dev *dev)
1207c2554c91SDmitry Torokhov {
1208c2554c91SDmitry Torokhov 	/* Flush stale event queue */
1209c2554c91SDmitry Torokhov 	poll_bios(true);
12105fc14680SDmitry Torokhov }
12115fc14680SDmitry Torokhov 
1212c2554c91SDmitry Torokhov static void wistron_poll(struct input_polled_dev *dev)
1213c2554c91SDmitry Torokhov {
1214c2554c91SDmitry Torokhov 	poll_bios(false);
1215c2554c91SDmitry Torokhov 
1216c2554c91SDmitry Torokhov 	/* Increase poll frequency if user is currently pressing keys (< 2s ago) */
1217c2554c91SDmitry Torokhov 	if (time_before(jiffies, jiffies_last_press + 2 * HZ))
1218c2554c91SDmitry Torokhov 		dev->poll_interval = POLL_INTERVAL_BURST;
1219c2554c91SDmitry Torokhov 	else
1220c2554c91SDmitry Torokhov 		dev->poll_interval = POLL_INTERVAL_DEFAULT;
1221c2554c91SDmitry Torokhov }
1222c2554c91SDmitry Torokhov 
1223d63219a1SDmitry Torokhov static int wistron_getkeycode(struct input_dev *dev, int scancode, int *keycode)
1224d63219a1SDmitry Torokhov {
1225d63219a1SDmitry Torokhov 	const struct key_entry *key = wistron_get_entry_by_scancode(scancode);
1226d63219a1SDmitry Torokhov 
1227d63219a1SDmitry Torokhov 	if (key && key->type == KE_KEY) {
1228d63219a1SDmitry Torokhov 		*keycode = key->keycode;
1229d63219a1SDmitry Torokhov 		return 0;
1230d63219a1SDmitry Torokhov 	}
1231d63219a1SDmitry Torokhov 
1232d63219a1SDmitry Torokhov 	return -EINVAL;
1233d63219a1SDmitry Torokhov }
1234d63219a1SDmitry Torokhov 
1235d63219a1SDmitry Torokhov static int wistron_setkeycode(struct input_dev *dev, int scancode, int keycode)
1236d63219a1SDmitry Torokhov {
1237d63219a1SDmitry Torokhov 	struct key_entry *key;
1238d63219a1SDmitry Torokhov 	int old_keycode;
1239d63219a1SDmitry Torokhov 
1240d63219a1SDmitry Torokhov 	if (keycode < 0 || keycode > KEY_MAX)
1241d63219a1SDmitry Torokhov 		return -EINVAL;
1242d63219a1SDmitry Torokhov 
1243d63219a1SDmitry Torokhov 	key = wistron_get_entry_by_scancode(scancode);
1244d63219a1SDmitry Torokhov 	if (key && key->type == KE_KEY) {
1245d63219a1SDmitry Torokhov 		old_keycode = key->keycode;
1246d63219a1SDmitry Torokhov 		key->keycode = keycode;
1247d63219a1SDmitry Torokhov 		set_bit(keycode, dev->keybit);
1248d63219a1SDmitry Torokhov 		if (!wistron_get_entry_by_keycode(old_keycode))
1249d63219a1SDmitry Torokhov 			clear_bit(old_keycode, dev->keybit);
1250d63219a1SDmitry Torokhov 		return 0;
1251d63219a1SDmitry Torokhov 	}
1252d63219a1SDmitry Torokhov 
1253d63219a1SDmitry Torokhov 	return -EINVAL;
1254d63219a1SDmitry Torokhov }
1255d63219a1SDmitry Torokhov 
1256c2554c91SDmitry Torokhov static int __devinit setup_input_dev(void)
1257c2554c91SDmitry Torokhov {
1258a8944037SÉric Piel 	struct key_entry *key;
1259c2554c91SDmitry Torokhov 	struct input_dev *input_dev;
1260c2554c91SDmitry Torokhov 	int error;
1261c2554c91SDmitry Torokhov 
1262c2554c91SDmitry Torokhov 	wistron_idev = input_allocate_polled_device();
1263c2554c91SDmitry Torokhov 	if (!wistron_idev)
1264c2554c91SDmitry Torokhov 		return -ENOMEM;
1265c2554c91SDmitry Torokhov 
1266c2554c91SDmitry Torokhov 	wistron_idev->flush = wistron_flush;
1267c2554c91SDmitry Torokhov 	wistron_idev->poll = wistron_poll;
1268c2554c91SDmitry Torokhov 	wistron_idev->poll_interval = POLL_INTERVAL_DEFAULT;
1269c2554c91SDmitry Torokhov 
1270c2554c91SDmitry Torokhov 	input_dev = wistron_idev->input;
1271c2554c91SDmitry Torokhov 	input_dev->name = "Wistron laptop buttons";
1272c2554c91SDmitry Torokhov 	input_dev->phys = "wistron/input0";
1273c2554c91SDmitry Torokhov 	input_dev->id.bustype = BUS_HOST;
1274d63219a1SDmitry Torokhov 	input_dev->dev.parent = &wistron_device->dev;
1275d63219a1SDmitry Torokhov 
1276d63219a1SDmitry Torokhov 	input_dev->getkeycode = wistron_getkeycode;
1277d63219a1SDmitry Torokhov 	input_dev->setkeycode = wistron_setkeycode;
1278c2554c91SDmitry Torokhov 
1279c2554c91SDmitry Torokhov 	for (key = keymap; key->type != KE_END; key++) {
1280c2554c91SDmitry Torokhov 		switch (key->type) {
1281c2554c91SDmitry Torokhov 			case KE_KEY:
1282c2554c91SDmitry Torokhov 				set_bit(EV_KEY, input_dev->evbit);
1283c2554c91SDmitry Torokhov 				set_bit(key->keycode, input_dev->keybit);
1284c2554c91SDmitry Torokhov 				break;
1285c2554c91SDmitry Torokhov 
1286c2554c91SDmitry Torokhov 			case KE_SW:
1287c2554c91SDmitry Torokhov 				set_bit(EV_SW, input_dev->evbit);
1288c2554c91SDmitry Torokhov 				set_bit(key->sw.code, input_dev->swbit);
1289c2554c91SDmitry Torokhov 				break;
1290c2554c91SDmitry Torokhov 
1291a8944037SÉric Piel 			/* if wifi or bluetooth are not available, create normal keys */
1292a8944037SÉric Piel 			case KE_WIFI:
1293a8944037SÉric Piel 				if (!have_wifi) {
1294a8944037SÉric Piel 					key->type = KE_KEY;
1295a8944037SÉric Piel 					key->keycode = KEY_WLAN;
1296a8944037SÉric Piel 					key--;
1297a8944037SÉric Piel 				}
1298a8944037SÉric Piel 				break;
1299a8944037SÉric Piel 
1300a8944037SÉric Piel 			case KE_BLUETOOTH:
1301a8944037SÉric Piel 				if (!have_bluetooth) {
1302a8944037SÉric Piel 					key->type = KE_KEY;
1303a8944037SÉric Piel 					key->keycode = KEY_BLUETOOTH;
1304a8944037SÉric Piel 					key--;
1305a8944037SÉric Piel 				}
1306a8944037SÉric Piel 				break;
1307a8944037SÉric Piel 
1308c2554c91SDmitry Torokhov 			default:
1309c2554c91SDmitry Torokhov 				break;
1310c2554c91SDmitry Torokhov 		}
1311c2554c91SDmitry Torokhov 	}
1312c2554c91SDmitry Torokhov 
1313c2554c91SDmitry Torokhov 	/* reads information flags on KE_END */
1314c2554c91SDmitry Torokhov 	if (key->code & FE_UNTESTED)
1315c2554c91SDmitry Torokhov 		printk(KERN_WARNING "Untested laptop multimedia keys, "
1316c2554c91SDmitry Torokhov 			"please report success or failure to eric.piel"
1317c2554c91SDmitry Torokhov 			"@tremplin-utc.net\n");
1318c2554c91SDmitry Torokhov 
1319c2554c91SDmitry Torokhov 	error = input_register_polled_device(wistron_idev);
1320c2554c91SDmitry Torokhov 	if (error) {
1321c2554c91SDmitry Torokhov 		input_free_polled_device(wistron_idev);
1322c2554c91SDmitry Torokhov 		return error;
1323c2554c91SDmitry Torokhov 	}
1324c2554c91SDmitry Torokhov 
1325c2554c91SDmitry Torokhov 	return 0;
1326c2554c91SDmitry Torokhov }
1327c2554c91SDmitry Torokhov 
1328c2554c91SDmitry Torokhov /* Driver core */
1329c2554c91SDmitry Torokhov 
1330e7c3aad5SDmitry Torokhov static int __devinit wistron_probe(struct platform_device *dev)
1331e7c3aad5SDmitry Torokhov {
1332c2554c91SDmitry Torokhov 	int err;
1333e7c3aad5SDmitry Torokhov 
1334e7c3aad5SDmitry Torokhov 	bios_attach();
1335e7c3aad5SDmitry Torokhov 	cmos_address = bios_get_cmos_address();
1336e7c3aad5SDmitry Torokhov 
1337e7c3aad5SDmitry Torokhov 	if (have_wifi) {
1338e7c3aad5SDmitry Torokhov 		u16 wifi = bios_get_default_setting(WIFI);
1339e7c3aad5SDmitry Torokhov 		if (wifi & 1)
134067dbe83aSDmitry Torokhov 			wifi_enabled = wifi & 2;
1341e7c3aad5SDmitry Torokhov 		else
1342e7c3aad5SDmitry Torokhov 			have_wifi = 0;
1343e7c3aad5SDmitry Torokhov 
1344e7c3aad5SDmitry Torokhov 		if (have_wifi)
1345e7c3aad5SDmitry Torokhov 			bios_set_state(WIFI, wifi_enabled);
1346e7c3aad5SDmitry Torokhov 	}
1347e7c3aad5SDmitry Torokhov 
1348e7c3aad5SDmitry Torokhov 	if (have_bluetooth) {
1349e7c3aad5SDmitry Torokhov 		u16 bt = bios_get_default_setting(BLUETOOTH);
1350e7c3aad5SDmitry Torokhov 		if (bt & 1)
135167dbe83aSDmitry Torokhov 			bluetooth_enabled = bt & 2;
1352e7c3aad5SDmitry Torokhov 		else
135367dbe83aSDmitry Torokhov 			have_bluetooth = false;
1354e7c3aad5SDmitry Torokhov 
1355e7c3aad5SDmitry Torokhov 		if (have_bluetooth)
1356e7c3aad5SDmitry Torokhov 			bios_set_state(BLUETOOTH, bluetooth_enabled);
1357e7c3aad5SDmitry Torokhov 	}
1358e7c3aad5SDmitry Torokhov 
1359389679d8SEric Piel 	wistron_led_init(&dev->dev);
136067dbe83aSDmitry Torokhov 
1361c2554c91SDmitry Torokhov 	err = setup_input_dev();
1362c2554c91SDmitry Torokhov 	if (err) {
1363c2554c91SDmitry Torokhov 		bios_detach();
1364c2554c91SDmitry Torokhov 		return err;
1365c2554c91SDmitry Torokhov 	}
1366e7c3aad5SDmitry Torokhov 
1367e7c3aad5SDmitry Torokhov 	return 0;
1368e7c3aad5SDmitry Torokhov }
1369e7c3aad5SDmitry Torokhov 
1370e7c3aad5SDmitry Torokhov static int __devexit wistron_remove(struct platform_device *dev)
1371e7c3aad5SDmitry Torokhov {
1372389679d8SEric Piel 	wistron_led_remove();
1373c2554c91SDmitry Torokhov 	input_unregister_polled_device(wistron_idev);
1374c2554c91SDmitry Torokhov 	input_free_polled_device(wistron_idev);
1375e7c3aad5SDmitry Torokhov 	bios_detach();
1376e7c3aad5SDmitry Torokhov 
1377e7c3aad5SDmitry Torokhov 	return 0;
1378e7c3aad5SDmitry Torokhov }
1379e7c3aad5SDmitry Torokhov 
1380e7c3aad5SDmitry Torokhov #ifdef CONFIG_PM
138167dbe83aSDmitry Torokhov static int wistron_suspend(struct device *dev)
1382a5b0cc80SDmitry Torokhov {
1383e753b650SMiloslav Trmac 	if (have_wifi)
1384e753b650SMiloslav Trmac 		bios_set_state(WIFI, 0);
1385e753b650SMiloslav Trmac 
1386e753b650SMiloslav Trmac 	if (have_bluetooth)
1387e753b650SMiloslav Trmac 		bios_set_state(BLUETOOTH, 0);
1388e753b650SMiloslav Trmac 
1389389679d8SEric Piel 	wistron_led_suspend();
139067dbe83aSDmitry Torokhov 
1391a5b0cc80SDmitry Torokhov 	return 0;
1392a5b0cc80SDmitry Torokhov }
1393a5b0cc80SDmitry Torokhov 
139467dbe83aSDmitry Torokhov static int wistron_resume(struct device *dev)
1395a5b0cc80SDmitry Torokhov {
1396a5b0cc80SDmitry Torokhov 	if (have_wifi)
1397a5b0cc80SDmitry Torokhov 		bios_set_state(WIFI, wifi_enabled);
1398a5b0cc80SDmitry Torokhov 
1399a5b0cc80SDmitry Torokhov 	if (have_bluetooth)
1400a5b0cc80SDmitry Torokhov 		bios_set_state(BLUETOOTH, bluetooth_enabled);
1401a5b0cc80SDmitry Torokhov 
1402389679d8SEric Piel 	wistron_led_resume();
140367dbe83aSDmitry Torokhov 
1404c2554c91SDmitry Torokhov 	poll_bios(true);
1405a5b0cc80SDmitry Torokhov 
1406a5b0cc80SDmitry Torokhov 	return 0;
1407a5b0cc80SDmitry Torokhov }
140867dbe83aSDmitry Torokhov 
140967dbe83aSDmitry Torokhov static const struct dev_pm_ops wistron_pm_ops = {
141067dbe83aSDmitry Torokhov 	.suspend	= wistron_suspend,
141167dbe83aSDmitry Torokhov 	.resume		= wistron_resume,
141267dbe83aSDmitry Torokhov 	.poweroff	= wistron_suspend,
141367dbe83aSDmitry Torokhov 	.restore	= wistron_resume,
141467dbe83aSDmitry Torokhov };
1415e7c3aad5SDmitry Torokhov #endif
1416a5b0cc80SDmitry Torokhov 
1417a5b0cc80SDmitry Torokhov static struct platform_driver wistron_driver = {
1418a5b0cc80SDmitry Torokhov 	.driver		= {
1419a5b0cc80SDmitry Torokhov 		.name	= "wistron-bios",
1420e7c3aad5SDmitry Torokhov 		.owner	= THIS_MODULE,
142167dbe83aSDmitry Torokhov #if CONFIG_PM
142267dbe83aSDmitry Torokhov 		.pm	= &wistron_pm_ops,
142367dbe83aSDmitry Torokhov #endif
1424a5b0cc80SDmitry Torokhov 	},
1425e7c3aad5SDmitry Torokhov 	.probe		= wistron_probe,
1426e7c3aad5SDmitry Torokhov 	.remove		= __devexit_p(wistron_remove),
1427a5b0cc80SDmitry Torokhov };
1428a5b0cc80SDmitry Torokhov 
14295fc14680SDmitry Torokhov static int __init wb_module_init(void)
14305fc14680SDmitry Torokhov {
14315fc14680SDmitry Torokhov 	int err;
14325fc14680SDmitry Torokhov 
14335fc14680SDmitry Torokhov 	err = select_keymap();
14345fc14680SDmitry Torokhov 	if (err)
14355fc14680SDmitry Torokhov 		return err;
143622a397e2SDmitry Torokhov 
14375fc14680SDmitry Torokhov 	err = map_bios();
14385fc14680SDmitry Torokhov 	if (err)
14395fc14680SDmitry Torokhov 		return err;
144022a397e2SDmitry Torokhov 
1441a5b0cc80SDmitry Torokhov 	err = platform_driver_register(&wistron_driver);
1442a5b0cc80SDmitry Torokhov 	if (err)
1443e7c3aad5SDmitry Torokhov 		goto err_unmap_bios;
1444a5b0cc80SDmitry Torokhov 
1445e7c3aad5SDmitry Torokhov 	wistron_device = platform_device_alloc("wistron-bios", -1);
1446e7c3aad5SDmitry Torokhov 	if (!wistron_device) {
1447e7c3aad5SDmitry Torokhov 		err = -ENOMEM;
1448a5b0cc80SDmitry Torokhov 		goto err_unregister_driver;
1449a5b0cc80SDmitry Torokhov 	}
1450a5b0cc80SDmitry Torokhov 
1451e7c3aad5SDmitry Torokhov 	err = platform_device_add(wistron_device);
1452a5b0cc80SDmitry Torokhov 	if (err)
1453e7c3aad5SDmitry Torokhov 		goto err_free_device;
14545fc14680SDmitry Torokhov 
14555fc14680SDmitry Torokhov 	return 0;
1456a5b0cc80SDmitry Torokhov 
1457e7c3aad5SDmitry Torokhov  err_free_device:
1458e7c3aad5SDmitry Torokhov 	platform_device_put(wistron_device);
1459a5b0cc80SDmitry Torokhov  err_unregister_driver:
1460a5b0cc80SDmitry Torokhov 	platform_driver_unregister(&wistron_driver);
1461e7c3aad5SDmitry Torokhov  err_unmap_bios:
1462a5b0cc80SDmitry Torokhov 	unmap_bios();
1463a5b0cc80SDmitry Torokhov 
1464a5b0cc80SDmitry Torokhov 	return err;
14655fc14680SDmitry Torokhov }
14665fc14680SDmitry Torokhov 
14675fc14680SDmitry Torokhov static void __exit wb_module_exit(void)
14685fc14680SDmitry Torokhov {
1469a5b0cc80SDmitry Torokhov 	platform_device_unregister(wistron_device);
1470a5b0cc80SDmitry Torokhov 	platform_driver_unregister(&wistron_driver);
14715fc14680SDmitry Torokhov 	unmap_bios();
147255d29c98SEric Piel 	kfree(keymap);
14735fc14680SDmitry Torokhov }
14745fc14680SDmitry Torokhov 
14755fc14680SDmitry Torokhov module_init(wb_module_init);
14765fc14680SDmitry Torokhov module_exit(wb_module_exit);
1477