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