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