xref: /OK3568_Linux_fs/kernel/drivers/input/misc/wistron_btns.c (revision 4882a59341e53eb6f0b4789bf948001014eff981)
1*4882a593Smuzhiyun // SPDX-License-Identifier: GPL-2.0-only
2*4882a593Smuzhiyun /*
3*4882a593Smuzhiyun  * Wistron laptop button driver
4*4882a593Smuzhiyun  * Copyright (C) 2005 Miloslav Trmac <mitr@volny.cz>
5*4882a593Smuzhiyun  * Copyright (C) 2005 Bernhard Rosenkraenzer <bero@arklinux.org>
6*4882a593Smuzhiyun  * Copyright (C) 2005 Dmitry Torokhov <dtor@mail.ru>
7*4882a593Smuzhiyun  */
8*4882a593Smuzhiyun #include <linux/io.h>
9*4882a593Smuzhiyun #include <linux/dmi.h>
10*4882a593Smuzhiyun #include <linux/init.h>
11*4882a593Smuzhiyun #include <linux/input.h>
12*4882a593Smuzhiyun #include <linux/input/sparse-keymap.h>
13*4882a593Smuzhiyun #include <linux/interrupt.h>
14*4882a593Smuzhiyun #include <linux/jiffies.h>
15*4882a593Smuzhiyun #include <linux/kernel.h>
16*4882a593Smuzhiyun #include <linux/mc146818rtc.h>
17*4882a593Smuzhiyun #include <linux/module.h>
18*4882a593Smuzhiyun #include <linux/preempt.h>
19*4882a593Smuzhiyun #include <linux/string.h>
20*4882a593Smuzhiyun #include <linux/slab.h>
21*4882a593Smuzhiyun #include <linux/types.h>
22*4882a593Smuzhiyun #include <linux/platform_device.h>
23*4882a593Smuzhiyun #include <linux/leds.h>
24*4882a593Smuzhiyun 
25*4882a593Smuzhiyun /* How often we poll keys - msecs */
26*4882a593Smuzhiyun #define POLL_INTERVAL_DEFAULT	500 /* when idle */
27*4882a593Smuzhiyun #define POLL_INTERVAL_BURST	100 /* when a key was recently pressed */
28*4882a593Smuzhiyun 
29*4882a593Smuzhiyun /* BIOS subsystem IDs */
30*4882a593Smuzhiyun #define WIFI		0x35
31*4882a593Smuzhiyun #define BLUETOOTH	0x34
32*4882a593Smuzhiyun #define MAIL_LED	0x31
33*4882a593Smuzhiyun 
34*4882a593Smuzhiyun MODULE_AUTHOR("Miloslav Trmac <mitr@volny.cz>");
35*4882a593Smuzhiyun MODULE_DESCRIPTION("Wistron laptop button driver");
36*4882a593Smuzhiyun MODULE_LICENSE("GPL v2");
37*4882a593Smuzhiyun 
38*4882a593Smuzhiyun static bool force; /* = 0; */
39*4882a593Smuzhiyun module_param(force, bool, 0);
40*4882a593Smuzhiyun MODULE_PARM_DESC(force, "Load even if computer is not in database");
41*4882a593Smuzhiyun 
42*4882a593Smuzhiyun static char *keymap_name; /* = NULL; */
43*4882a593Smuzhiyun module_param_named(keymap, keymap_name, charp, 0);
44*4882a593Smuzhiyun MODULE_PARM_DESC(keymap, "Keymap name, if it can't be autodetected [generic, 1557/MS2141]");
45*4882a593Smuzhiyun 
46*4882a593Smuzhiyun static struct platform_device *wistron_device;
47*4882a593Smuzhiyun 
48*4882a593Smuzhiyun  /* BIOS interface implementation */
49*4882a593Smuzhiyun 
50*4882a593Smuzhiyun static void __iomem *bios_entry_point; /* BIOS routine entry point */
51*4882a593Smuzhiyun static void __iomem *bios_code_map_base;
52*4882a593Smuzhiyun static void __iomem *bios_data_map_base;
53*4882a593Smuzhiyun 
54*4882a593Smuzhiyun static u8 cmos_address;
55*4882a593Smuzhiyun 
56*4882a593Smuzhiyun struct regs {
57*4882a593Smuzhiyun 	u32 eax, ebx, ecx;
58*4882a593Smuzhiyun };
59*4882a593Smuzhiyun 
call_bios(struct regs * regs)60*4882a593Smuzhiyun static void call_bios(struct regs *regs)
61*4882a593Smuzhiyun {
62*4882a593Smuzhiyun 	unsigned long flags;
63*4882a593Smuzhiyun 
64*4882a593Smuzhiyun 	preempt_disable();
65*4882a593Smuzhiyun 	local_irq_save(flags);
66*4882a593Smuzhiyun 	asm volatile ("pushl %%ebp;"
67*4882a593Smuzhiyun 		      "movl %7, %%ebp;"
68*4882a593Smuzhiyun 		      "call *%6;"
69*4882a593Smuzhiyun 		      "popl %%ebp"
70*4882a593Smuzhiyun 		      : "=a" (regs->eax), "=b" (regs->ebx), "=c" (regs->ecx)
71*4882a593Smuzhiyun 		      : "0" (regs->eax), "1" (regs->ebx), "2" (regs->ecx),
72*4882a593Smuzhiyun 			"m" (bios_entry_point), "m" (bios_data_map_base)
73*4882a593Smuzhiyun 		      : "edx", "edi", "esi", "memory");
74*4882a593Smuzhiyun 	local_irq_restore(flags);
75*4882a593Smuzhiyun 	preempt_enable();
76*4882a593Smuzhiyun }
77*4882a593Smuzhiyun 
locate_wistron_bios(void __iomem * base)78*4882a593Smuzhiyun static ssize_t __init locate_wistron_bios(void __iomem *base)
79*4882a593Smuzhiyun {
80*4882a593Smuzhiyun 	static unsigned char __initdata signature[] =
81*4882a593Smuzhiyun 		{ 0x42, 0x21, 0x55, 0x30 };
82*4882a593Smuzhiyun 	ssize_t offset;
83*4882a593Smuzhiyun 
84*4882a593Smuzhiyun 	for (offset = 0; offset < 0x10000; offset += 0x10) {
85*4882a593Smuzhiyun 		if (check_signature(base + offset, signature,
86*4882a593Smuzhiyun 				    sizeof(signature)) != 0)
87*4882a593Smuzhiyun 			return offset;
88*4882a593Smuzhiyun 	}
89*4882a593Smuzhiyun 	return -1;
90*4882a593Smuzhiyun }
91*4882a593Smuzhiyun 
map_bios(void)92*4882a593Smuzhiyun static int __init map_bios(void)
93*4882a593Smuzhiyun {
94*4882a593Smuzhiyun 	void __iomem *base;
95*4882a593Smuzhiyun 	ssize_t offset;
96*4882a593Smuzhiyun 	u32 entry_point;
97*4882a593Smuzhiyun 
98*4882a593Smuzhiyun 	base = ioremap(0xF0000, 0x10000); /* Can't fail */
99*4882a593Smuzhiyun 	offset = locate_wistron_bios(base);
100*4882a593Smuzhiyun 	if (offset < 0) {
101*4882a593Smuzhiyun 		printk(KERN_ERR "wistron_btns: BIOS entry point not found\n");
102*4882a593Smuzhiyun 		iounmap(base);
103*4882a593Smuzhiyun 		return -ENODEV;
104*4882a593Smuzhiyun 	}
105*4882a593Smuzhiyun 
106*4882a593Smuzhiyun 	entry_point = readl(base + offset + 5);
107*4882a593Smuzhiyun 	printk(KERN_DEBUG
108*4882a593Smuzhiyun 		"wistron_btns: BIOS signature found at %p, entry point %08X\n",
109*4882a593Smuzhiyun 		base + offset, entry_point);
110*4882a593Smuzhiyun 
111*4882a593Smuzhiyun 	if (entry_point >= 0xF0000) {
112*4882a593Smuzhiyun 		bios_code_map_base = base;
113*4882a593Smuzhiyun 		bios_entry_point = bios_code_map_base + (entry_point & 0xFFFF);
114*4882a593Smuzhiyun 	} else {
115*4882a593Smuzhiyun 		iounmap(base);
116*4882a593Smuzhiyun 		bios_code_map_base = ioremap(entry_point & ~0x3FFF, 0x4000);
117*4882a593Smuzhiyun 		if (bios_code_map_base == NULL) {
118*4882a593Smuzhiyun 			printk(KERN_ERR
119*4882a593Smuzhiyun 				"wistron_btns: Can't map BIOS code at %08X\n",
120*4882a593Smuzhiyun 				entry_point & ~0x3FFF);
121*4882a593Smuzhiyun 			goto err;
122*4882a593Smuzhiyun 		}
123*4882a593Smuzhiyun 		bios_entry_point = bios_code_map_base + (entry_point & 0x3FFF);
124*4882a593Smuzhiyun 	}
125*4882a593Smuzhiyun 	/* The Windows driver maps 0x10000 bytes, we keep only one page... */
126*4882a593Smuzhiyun 	bios_data_map_base = ioremap(0x400, 0xc00);
127*4882a593Smuzhiyun 	if (bios_data_map_base == NULL) {
128*4882a593Smuzhiyun 		printk(KERN_ERR "wistron_btns: Can't map BIOS data\n");
129*4882a593Smuzhiyun 		goto err_code;
130*4882a593Smuzhiyun 	}
131*4882a593Smuzhiyun 	return 0;
132*4882a593Smuzhiyun 
133*4882a593Smuzhiyun err_code:
134*4882a593Smuzhiyun 	iounmap(bios_code_map_base);
135*4882a593Smuzhiyun err:
136*4882a593Smuzhiyun 	return -ENOMEM;
137*4882a593Smuzhiyun }
138*4882a593Smuzhiyun 
unmap_bios(void)139*4882a593Smuzhiyun static inline void unmap_bios(void)
140*4882a593Smuzhiyun {
141*4882a593Smuzhiyun 	iounmap(bios_code_map_base);
142*4882a593Smuzhiyun 	iounmap(bios_data_map_base);
143*4882a593Smuzhiyun }
144*4882a593Smuzhiyun 
145*4882a593Smuzhiyun  /* BIOS calls */
146*4882a593Smuzhiyun 
bios_pop_queue(void)147*4882a593Smuzhiyun static u16 bios_pop_queue(void)
148*4882a593Smuzhiyun {
149*4882a593Smuzhiyun 	struct regs regs;
150*4882a593Smuzhiyun 
151*4882a593Smuzhiyun 	memset(&regs, 0, sizeof (regs));
152*4882a593Smuzhiyun 	regs.eax = 0x9610;
153*4882a593Smuzhiyun 	regs.ebx = 0x061C;
154*4882a593Smuzhiyun 	regs.ecx = 0x0000;
155*4882a593Smuzhiyun 	call_bios(&regs);
156*4882a593Smuzhiyun 
157*4882a593Smuzhiyun 	return regs.eax;
158*4882a593Smuzhiyun }
159*4882a593Smuzhiyun 
bios_attach(void)160*4882a593Smuzhiyun static void bios_attach(void)
161*4882a593Smuzhiyun {
162*4882a593Smuzhiyun 	struct regs regs;
163*4882a593Smuzhiyun 
164*4882a593Smuzhiyun 	memset(&regs, 0, sizeof (regs));
165*4882a593Smuzhiyun 	regs.eax = 0x9610;
166*4882a593Smuzhiyun 	regs.ebx = 0x012E;
167*4882a593Smuzhiyun 	call_bios(&regs);
168*4882a593Smuzhiyun }
169*4882a593Smuzhiyun 
bios_detach(void)170*4882a593Smuzhiyun static void bios_detach(void)
171*4882a593Smuzhiyun {
172*4882a593Smuzhiyun 	struct regs regs;
173*4882a593Smuzhiyun 
174*4882a593Smuzhiyun 	memset(&regs, 0, sizeof (regs));
175*4882a593Smuzhiyun 	regs.eax = 0x9610;
176*4882a593Smuzhiyun 	regs.ebx = 0x002E;
177*4882a593Smuzhiyun 	call_bios(&regs);
178*4882a593Smuzhiyun }
179*4882a593Smuzhiyun 
bios_get_cmos_address(void)180*4882a593Smuzhiyun static u8 bios_get_cmos_address(void)
181*4882a593Smuzhiyun {
182*4882a593Smuzhiyun 	struct regs regs;
183*4882a593Smuzhiyun 
184*4882a593Smuzhiyun 	memset(&regs, 0, sizeof (regs));
185*4882a593Smuzhiyun 	regs.eax = 0x9610;
186*4882a593Smuzhiyun 	regs.ebx = 0x051C;
187*4882a593Smuzhiyun 	call_bios(&regs);
188*4882a593Smuzhiyun 
189*4882a593Smuzhiyun 	return regs.ecx;
190*4882a593Smuzhiyun }
191*4882a593Smuzhiyun 
bios_get_default_setting(u8 subsys)192*4882a593Smuzhiyun static u16 bios_get_default_setting(u8 subsys)
193*4882a593Smuzhiyun {
194*4882a593Smuzhiyun 	struct regs regs;
195*4882a593Smuzhiyun 
196*4882a593Smuzhiyun 	memset(&regs, 0, sizeof (regs));
197*4882a593Smuzhiyun 	regs.eax = 0x9610;
198*4882a593Smuzhiyun 	regs.ebx = 0x0200 | subsys;
199*4882a593Smuzhiyun 	call_bios(&regs);
200*4882a593Smuzhiyun 
201*4882a593Smuzhiyun 	return regs.eax;
202*4882a593Smuzhiyun }
203*4882a593Smuzhiyun 
bios_set_state(u8 subsys,int enable)204*4882a593Smuzhiyun static void bios_set_state(u8 subsys, int enable)
205*4882a593Smuzhiyun {
206*4882a593Smuzhiyun 	struct regs regs;
207*4882a593Smuzhiyun 
208*4882a593Smuzhiyun 	memset(&regs, 0, sizeof (regs));
209*4882a593Smuzhiyun 	regs.eax = 0x9610;
210*4882a593Smuzhiyun 	regs.ebx = (enable ? 0x0100 : 0x0000) | subsys;
211*4882a593Smuzhiyun 	call_bios(&regs);
212*4882a593Smuzhiyun }
213*4882a593Smuzhiyun 
214*4882a593Smuzhiyun /* Hardware database */
215*4882a593Smuzhiyun 
216*4882a593Smuzhiyun #define KE_WIFI		(KE_LAST + 1)
217*4882a593Smuzhiyun #define KE_BLUETOOTH	(KE_LAST + 2)
218*4882a593Smuzhiyun 
219*4882a593Smuzhiyun #define FE_MAIL_LED 0x01
220*4882a593Smuzhiyun #define FE_WIFI_LED 0x02
221*4882a593Smuzhiyun #define FE_UNTESTED 0x80
222*4882a593Smuzhiyun 
223*4882a593Smuzhiyun static struct key_entry *keymap; /* = NULL; Current key map */
224*4882a593Smuzhiyun static bool have_wifi;
225*4882a593Smuzhiyun static bool have_bluetooth;
226*4882a593Smuzhiyun static int leds_present;	/* bitmask of leds present */
227*4882a593Smuzhiyun 
dmi_matched(const struct dmi_system_id * dmi)228*4882a593Smuzhiyun static int __init dmi_matched(const struct dmi_system_id *dmi)
229*4882a593Smuzhiyun {
230*4882a593Smuzhiyun 	const struct key_entry *key;
231*4882a593Smuzhiyun 
232*4882a593Smuzhiyun 	keymap = dmi->driver_data;
233*4882a593Smuzhiyun 	for (key = keymap; key->type != KE_END; key++) {
234*4882a593Smuzhiyun 		if (key->type == KE_WIFI)
235*4882a593Smuzhiyun 			have_wifi = true;
236*4882a593Smuzhiyun 		else if (key->type == KE_BLUETOOTH)
237*4882a593Smuzhiyun 			have_bluetooth = true;
238*4882a593Smuzhiyun 	}
239*4882a593Smuzhiyun 	leds_present = key->code & (FE_MAIL_LED | FE_WIFI_LED);
240*4882a593Smuzhiyun 
241*4882a593Smuzhiyun 	return 1;
242*4882a593Smuzhiyun }
243*4882a593Smuzhiyun 
244*4882a593Smuzhiyun static struct key_entry keymap_empty[] __initdata = {
245*4882a593Smuzhiyun 	{ KE_END, 0 }
246*4882a593Smuzhiyun };
247*4882a593Smuzhiyun 
248*4882a593Smuzhiyun static struct key_entry keymap_fs_amilo_pro_v2000[] __initdata = {
249*4882a593Smuzhiyun 	{ KE_KEY,  0x01, {KEY_HELP} },
250*4882a593Smuzhiyun 	{ KE_KEY,  0x11, {KEY_PROG1} },
251*4882a593Smuzhiyun 	{ KE_KEY,  0x12, {KEY_PROG2} },
252*4882a593Smuzhiyun 	{ KE_WIFI, 0x30 },
253*4882a593Smuzhiyun 	{ KE_KEY,  0x31, {KEY_MAIL} },
254*4882a593Smuzhiyun 	{ KE_KEY,  0x36, {KEY_WWW} },
255*4882a593Smuzhiyun 	{ KE_END,  0 }
256*4882a593Smuzhiyun };
257*4882a593Smuzhiyun 
258*4882a593Smuzhiyun static struct key_entry keymap_fs_amilo_pro_v3505[] __initdata = {
259*4882a593Smuzhiyun 	{ KE_KEY,       0x01, {KEY_HELP} },          /* Fn+F1 */
260*4882a593Smuzhiyun 	{ KE_KEY,       0x06, {KEY_DISPLAYTOGGLE} }, /* Fn+F4 */
261*4882a593Smuzhiyun 	{ KE_BLUETOOTH, 0x30 },                      /* Fn+F10 */
262*4882a593Smuzhiyun 	{ KE_KEY,       0x31, {KEY_MAIL} },          /* mail button */
263*4882a593Smuzhiyun 	{ KE_KEY,       0x36, {KEY_WWW} },           /* www button */
264*4882a593Smuzhiyun 	{ KE_WIFI,      0x78 },                      /* satellite dish button */
265*4882a593Smuzhiyun 	{ KE_END,       0 }
266*4882a593Smuzhiyun };
267*4882a593Smuzhiyun 
268*4882a593Smuzhiyun static struct key_entry keymap_fs_amilo_pro_v8210[] __initdata = {
269*4882a593Smuzhiyun 	{ KE_KEY,       0x01, {KEY_HELP} },          /* Fn+F1 */
270*4882a593Smuzhiyun 	{ KE_KEY,       0x06, {KEY_DISPLAYTOGGLE} }, /* Fn+F4 */
271*4882a593Smuzhiyun 	{ KE_BLUETOOTH, 0x30 },                      /* Fn+F10 */
272*4882a593Smuzhiyun 	{ KE_KEY,       0x31, {KEY_MAIL} },          /* mail button */
273*4882a593Smuzhiyun 	{ KE_KEY,       0x36, {KEY_WWW} },           /* www button */
274*4882a593Smuzhiyun 	{ KE_WIFI,      0x78 },                      /* satelite dish button */
275*4882a593Smuzhiyun 	{ KE_END,       FE_WIFI_LED }
276*4882a593Smuzhiyun };
277*4882a593Smuzhiyun 
278*4882a593Smuzhiyun static struct key_entry keymap_fujitsu_n3510[] __initdata = {
279*4882a593Smuzhiyun 	{ KE_KEY, 0x11, {KEY_PROG1} },
280*4882a593Smuzhiyun 	{ KE_KEY, 0x12, {KEY_PROG2} },
281*4882a593Smuzhiyun 	{ KE_KEY, 0x36, {KEY_WWW} },
282*4882a593Smuzhiyun 	{ KE_KEY, 0x31, {KEY_MAIL} },
283*4882a593Smuzhiyun 	{ KE_KEY, 0x71, {KEY_STOPCD} },
284*4882a593Smuzhiyun 	{ KE_KEY, 0x72, {KEY_PLAYPAUSE} },
285*4882a593Smuzhiyun 	{ KE_KEY, 0x74, {KEY_REWIND} },
286*4882a593Smuzhiyun 	{ KE_KEY, 0x78, {KEY_FORWARD} },
287*4882a593Smuzhiyun 	{ KE_END, 0 }
288*4882a593Smuzhiyun };
289*4882a593Smuzhiyun 
290*4882a593Smuzhiyun static struct key_entry keymap_wistron_ms2111[] __initdata = {
291*4882a593Smuzhiyun 	{ KE_KEY,  0x11, {KEY_PROG1} },
292*4882a593Smuzhiyun 	{ KE_KEY,  0x12, {KEY_PROG2} },
293*4882a593Smuzhiyun 	{ KE_KEY,  0x13, {KEY_PROG3} },
294*4882a593Smuzhiyun 	{ KE_KEY,  0x31, {KEY_MAIL} },
295*4882a593Smuzhiyun 	{ KE_KEY,  0x36, {KEY_WWW} },
296*4882a593Smuzhiyun 	{ KE_END, FE_MAIL_LED }
297*4882a593Smuzhiyun };
298*4882a593Smuzhiyun 
299*4882a593Smuzhiyun static struct key_entry keymap_wistron_md40100[] __initdata = {
300*4882a593Smuzhiyun 	{ KE_KEY, 0x01, {KEY_HELP} },
301*4882a593Smuzhiyun 	{ KE_KEY, 0x02, {KEY_CONFIG} },
302*4882a593Smuzhiyun 	{ KE_KEY, 0x31, {KEY_MAIL} },
303*4882a593Smuzhiyun 	{ KE_KEY, 0x36, {KEY_WWW} },
304*4882a593Smuzhiyun 	{ KE_KEY, 0x37, {KEY_DISPLAYTOGGLE} }, /* Display on/off */
305*4882a593Smuzhiyun 	{ KE_END, FE_MAIL_LED | FE_WIFI_LED | FE_UNTESTED }
306*4882a593Smuzhiyun };
307*4882a593Smuzhiyun 
308*4882a593Smuzhiyun static struct key_entry keymap_wistron_ms2141[] __initdata = {
309*4882a593Smuzhiyun 	{ KE_KEY,  0x11, {KEY_PROG1} },
310*4882a593Smuzhiyun 	{ KE_KEY,  0x12, {KEY_PROG2} },
311*4882a593Smuzhiyun 	{ KE_WIFI, 0x30 },
312*4882a593Smuzhiyun 	{ KE_KEY,  0x22, {KEY_REWIND} },
313*4882a593Smuzhiyun 	{ KE_KEY,  0x23, {KEY_FORWARD} },
314*4882a593Smuzhiyun 	{ KE_KEY,  0x24, {KEY_PLAYPAUSE} },
315*4882a593Smuzhiyun 	{ KE_KEY,  0x25, {KEY_STOPCD} },
316*4882a593Smuzhiyun 	{ KE_KEY,  0x31, {KEY_MAIL} },
317*4882a593Smuzhiyun 	{ KE_KEY,  0x36, {KEY_WWW} },
318*4882a593Smuzhiyun 	{ KE_END,  0 }
319*4882a593Smuzhiyun };
320*4882a593Smuzhiyun 
321*4882a593Smuzhiyun static struct key_entry keymap_acer_aspire_1500[] __initdata = {
322*4882a593Smuzhiyun 	{ KE_KEY, 0x01, {KEY_HELP} },
323*4882a593Smuzhiyun 	{ KE_KEY, 0x03, {KEY_POWER} },
324*4882a593Smuzhiyun 	{ KE_KEY, 0x11, {KEY_PROG1} },
325*4882a593Smuzhiyun 	{ KE_KEY, 0x12, {KEY_PROG2} },
326*4882a593Smuzhiyun 	{ KE_WIFI, 0x30 },
327*4882a593Smuzhiyun 	{ KE_KEY, 0x31, {KEY_MAIL} },
328*4882a593Smuzhiyun 	{ KE_KEY, 0x36, {KEY_WWW} },
329*4882a593Smuzhiyun 	{ KE_KEY, 0x49, {KEY_CONFIG} },
330*4882a593Smuzhiyun 	{ KE_BLUETOOTH, 0x44 },
331*4882a593Smuzhiyun 	{ KE_END, FE_UNTESTED }
332*4882a593Smuzhiyun };
333*4882a593Smuzhiyun 
334*4882a593Smuzhiyun static struct key_entry keymap_acer_aspire_1600[] __initdata = {
335*4882a593Smuzhiyun 	{ KE_KEY, 0x01, {KEY_HELP} },
336*4882a593Smuzhiyun 	{ KE_KEY, 0x03, {KEY_POWER} },
337*4882a593Smuzhiyun 	{ KE_KEY, 0x08, {KEY_MUTE} },
338*4882a593Smuzhiyun 	{ KE_KEY, 0x11, {KEY_PROG1} },
339*4882a593Smuzhiyun 	{ KE_KEY, 0x12, {KEY_PROG2} },
340*4882a593Smuzhiyun 	{ KE_KEY, 0x13, {KEY_PROG3} },
341*4882a593Smuzhiyun 	{ KE_KEY, 0x31, {KEY_MAIL} },
342*4882a593Smuzhiyun 	{ KE_KEY, 0x36, {KEY_WWW} },
343*4882a593Smuzhiyun 	{ KE_KEY, 0x49, {KEY_CONFIG} },
344*4882a593Smuzhiyun 	{ KE_WIFI, 0x30 },
345*4882a593Smuzhiyun 	{ KE_BLUETOOTH, 0x44 },
346*4882a593Smuzhiyun 	{ KE_END, FE_MAIL_LED | FE_UNTESTED }
347*4882a593Smuzhiyun };
348*4882a593Smuzhiyun 
349*4882a593Smuzhiyun /* 3020 has been tested */
350*4882a593Smuzhiyun static struct key_entry keymap_acer_aspire_5020[] __initdata = {
351*4882a593Smuzhiyun 	{ KE_KEY, 0x01, {KEY_HELP} },
352*4882a593Smuzhiyun 	{ KE_KEY, 0x03, {KEY_POWER} },
353*4882a593Smuzhiyun 	{ KE_KEY, 0x05, {KEY_SWITCHVIDEOMODE} }, /* Display selection */
354*4882a593Smuzhiyun 	{ KE_KEY, 0x11, {KEY_PROG1} },
355*4882a593Smuzhiyun 	{ KE_KEY, 0x12, {KEY_PROG2} },
356*4882a593Smuzhiyun 	{ KE_KEY, 0x31, {KEY_MAIL} },
357*4882a593Smuzhiyun 	{ KE_KEY, 0x36, {KEY_WWW} },
358*4882a593Smuzhiyun 	{ KE_KEY, 0x6a, {KEY_CONFIG} },
359*4882a593Smuzhiyun 	{ KE_WIFI, 0x30 },
360*4882a593Smuzhiyun 	{ KE_BLUETOOTH, 0x44 },
361*4882a593Smuzhiyun 	{ KE_END, FE_MAIL_LED | FE_UNTESTED }
362*4882a593Smuzhiyun };
363*4882a593Smuzhiyun 
364*4882a593Smuzhiyun static struct key_entry keymap_acer_travelmate_2410[] __initdata = {
365*4882a593Smuzhiyun 	{ KE_KEY, 0x01, {KEY_HELP} },
366*4882a593Smuzhiyun 	{ KE_KEY, 0x6d, {KEY_POWER} },
367*4882a593Smuzhiyun 	{ KE_KEY, 0x11, {KEY_PROG1} },
368*4882a593Smuzhiyun 	{ KE_KEY, 0x12, {KEY_PROG2} },
369*4882a593Smuzhiyun 	{ KE_KEY, 0x31, {KEY_MAIL} },
370*4882a593Smuzhiyun 	{ KE_KEY, 0x36, {KEY_WWW} },
371*4882a593Smuzhiyun 	{ KE_KEY, 0x6a, {KEY_CONFIG} },
372*4882a593Smuzhiyun 	{ KE_WIFI, 0x30 },
373*4882a593Smuzhiyun 	{ KE_BLUETOOTH, 0x44 },
374*4882a593Smuzhiyun 	{ KE_END, FE_MAIL_LED | FE_UNTESTED }
375*4882a593Smuzhiyun };
376*4882a593Smuzhiyun 
377*4882a593Smuzhiyun static struct key_entry keymap_acer_travelmate_110[] __initdata = {
378*4882a593Smuzhiyun 	{ KE_KEY, 0x01, {KEY_HELP} },
379*4882a593Smuzhiyun 	{ KE_KEY, 0x02, {KEY_CONFIG} },
380*4882a593Smuzhiyun 	{ KE_KEY, 0x03, {KEY_POWER} },
381*4882a593Smuzhiyun 	{ KE_KEY, 0x08, {KEY_MUTE} },
382*4882a593Smuzhiyun 	{ KE_KEY, 0x11, {KEY_PROG1} },
383*4882a593Smuzhiyun 	{ KE_KEY, 0x12, {KEY_PROG2} },
384*4882a593Smuzhiyun 	{ KE_KEY, 0x20, {KEY_VOLUMEUP} },
385*4882a593Smuzhiyun 	{ KE_KEY, 0x21, {KEY_VOLUMEDOWN} },
386*4882a593Smuzhiyun 	{ KE_KEY, 0x31, {KEY_MAIL} },
387*4882a593Smuzhiyun 	{ KE_KEY, 0x36, {KEY_WWW} },
388*4882a593Smuzhiyun 	{ KE_SW, 0x4a, {.sw = {SW_LID, 1}} }, /* lid close */
389*4882a593Smuzhiyun 	{ KE_SW, 0x4b, {.sw = {SW_LID, 0}} }, /* lid open */
390*4882a593Smuzhiyun 	{ KE_WIFI, 0x30 },
391*4882a593Smuzhiyun 	{ KE_END, FE_MAIL_LED | FE_UNTESTED }
392*4882a593Smuzhiyun };
393*4882a593Smuzhiyun 
394*4882a593Smuzhiyun static struct key_entry keymap_acer_travelmate_300[] __initdata = {
395*4882a593Smuzhiyun 	{ KE_KEY, 0x01, {KEY_HELP} },
396*4882a593Smuzhiyun 	{ KE_KEY, 0x02, {KEY_CONFIG} },
397*4882a593Smuzhiyun 	{ KE_KEY, 0x03, {KEY_POWER} },
398*4882a593Smuzhiyun 	{ KE_KEY, 0x08, {KEY_MUTE} },
399*4882a593Smuzhiyun 	{ KE_KEY, 0x11, {KEY_PROG1} },
400*4882a593Smuzhiyun 	{ KE_KEY, 0x12, {KEY_PROG2} },
401*4882a593Smuzhiyun 	{ KE_KEY, 0x20, {KEY_VOLUMEUP} },
402*4882a593Smuzhiyun 	{ KE_KEY, 0x21, {KEY_VOLUMEDOWN} },
403*4882a593Smuzhiyun 	{ KE_KEY, 0x31, {KEY_MAIL} },
404*4882a593Smuzhiyun 	{ KE_KEY, 0x36, {KEY_WWW} },
405*4882a593Smuzhiyun 	{ KE_WIFI, 0x30 },
406*4882a593Smuzhiyun 	{ KE_BLUETOOTH, 0x44 },
407*4882a593Smuzhiyun 	{ KE_END, FE_MAIL_LED | FE_UNTESTED }
408*4882a593Smuzhiyun };
409*4882a593Smuzhiyun 
410*4882a593Smuzhiyun static struct key_entry keymap_acer_travelmate_380[] __initdata = {
411*4882a593Smuzhiyun 	{ KE_KEY, 0x01, {KEY_HELP} },
412*4882a593Smuzhiyun 	{ KE_KEY, 0x02, {KEY_CONFIG} },
413*4882a593Smuzhiyun 	{ KE_KEY, 0x03, {KEY_POWER} }, /* not 370 */
414*4882a593Smuzhiyun 	{ KE_KEY, 0x11, {KEY_PROG1} },
415*4882a593Smuzhiyun 	{ KE_KEY, 0x12, {KEY_PROG2} },
416*4882a593Smuzhiyun 	{ KE_KEY, 0x13, {KEY_PROG3} },
417*4882a593Smuzhiyun 	{ KE_KEY, 0x31, {KEY_MAIL} },
418*4882a593Smuzhiyun 	{ KE_KEY, 0x36, {KEY_WWW} },
419*4882a593Smuzhiyun 	{ KE_WIFI, 0x30 },
420*4882a593Smuzhiyun 	{ KE_END, FE_MAIL_LED | FE_UNTESTED }
421*4882a593Smuzhiyun };
422*4882a593Smuzhiyun 
423*4882a593Smuzhiyun /* unusual map */
424*4882a593Smuzhiyun static struct key_entry keymap_acer_travelmate_220[] __initdata = {
425*4882a593Smuzhiyun 	{ KE_KEY, 0x01, {KEY_HELP} },
426*4882a593Smuzhiyun 	{ KE_KEY, 0x02, {KEY_CONFIG} },
427*4882a593Smuzhiyun 	{ KE_KEY, 0x11, {KEY_MAIL} },
428*4882a593Smuzhiyun 	{ KE_KEY, 0x12, {KEY_WWW} },
429*4882a593Smuzhiyun 	{ KE_KEY, 0x13, {KEY_PROG2} },
430*4882a593Smuzhiyun 	{ KE_KEY, 0x31, {KEY_PROG1} },
431*4882a593Smuzhiyun 	{ KE_END, FE_WIFI_LED | FE_UNTESTED }
432*4882a593Smuzhiyun };
433*4882a593Smuzhiyun 
434*4882a593Smuzhiyun static struct key_entry keymap_acer_travelmate_230[] __initdata = {
435*4882a593Smuzhiyun 	{ KE_KEY, 0x01, {KEY_HELP} },
436*4882a593Smuzhiyun 	{ KE_KEY, 0x02, {KEY_CONFIG} },
437*4882a593Smuzhiyun 	{ KE_KEY, 0x11, {KEY_PROG1} },
438*4882a593Smuzhiyun 	{ KE_KEY, 0x12, {KEY_PROG2} },
439*4882a593Smuzhiyun 	{ KE_KEY, 0x31, {KEY_MAIL} },
440*4882a593Smuzhiyun 	{ KE_KEY, 0x36, {KEY_WWW} },
441*4882a593Smuzhiyun 	{ KE_END, FE_WIFI_LED | FE_UNTESTED }
442*4882a593Smuzhiyun };
443*4882a593Smuzhiyun 
444*4882a593Smuzhiyun static struct key_entry keymap_acer_travelmate_240[] __initdata = {
445*4882a593Smuzhiyun 	{ KE_KEY, 0x01, {KEY_HELP} },
446*4882a593Smuzhiyun 	{ KE_KEY, 0x02, {KEY_CONFIG} },
447*4882a593Smuzhiyun 	{ KE_KEY, 0x03, {KEY_POWER} },
448*4882a593Smuzhiyun 	{ KE_KEY, 0x08, {KEY_MUTE} },
449*4882a593Smuzhiyun 	{ KE_KEY, 0x31, {KEY_MAIL} },
450*4882a593Smuzhiyun 	{ KE_KEY, 0x36, {KEY_WWW} },
451*4882a593Smuzhiyun 	{ KE_KEY, 0x11, {KEY_PROG1} },
452*4882a593Smuzhiyun 	{ KE_KEY, 0x12, {KEY_PROG2} },
453*4882a593Smuzhiyun 	{ KE_BLUETOOTH, 0x44 },
454*4882a593Smuzhiyun 	{ KE_WIFI, 0x30 },
455*4882a593Smuzhiyun 	{ KE_END, FE_UNTESTED }
456*4882a593Smuzhiyun };
457*4882a593Smuzhiyun 
458*4882a593Smuzhiyun static struct key_entry keymap_acer_travelmate_350[] __initdata = {
459*4882a593Smuzhiyun 	{ KE_KEY, 0x01, {KEY_HELP} },
460*4882a593Smuzhiyun 	{ KE_KEY, 0x02, {KEY_CONFIG} },
461*4882a593Smuzhiyun 	{ KE_KEY, 0x11, {KEY_PROG1} },
462*4882a593Smuzhiyun 	{ KE_KEY, 0x12, {KEY_PROG2} },
463*4882a593Smuzhiyun 	{ KE_KEY, 0x13, {KEY_MAIL} },
464*4882a593Smuzhiyun 	{ KE_KEY, 0x14, {KEY_PROG3} },
465*4882a593Smuzhiyun 	{ KE_KEY, 0x15, {KEY_WWW} },
466*4882a593Smuzhiyun 	{ KE_END, FE_MAIL_LED | FE_WIFI_LED | FE_UNTESTED }
467*4882a593Smuzhiyun };
468*4882a593Smuzhiyun 
469*4882a593Smuzhiyun static struct key_entry keymap_acer_travelmate_360[] __initdata = {
470*4882a593Smuzhiyun 	{ KE_KEY, 0x01, {KEY_HELP} },
471*4882a593Smuzhiyun 	{ KE_KEY, 0x02, {KEY_CONFIG} },
472*4882a593Smuzhiyun 	{ KE_KEY, 0x11, {KEY_PROG1} },
473*4882a593Smuzhiyun 	{ KE_KEY, 0x12, {KEY_PROG2} },
474*4882a593Smuzhiyun 	{ KE_KEY, 0x13, {KEY_MAIL} },
475*4882a593Smuzhiyun 	{ KE_KEY, 0x14, {KEY_PROG3} },
476*4882a593Smuzhiyun 	{ KE_KEY, 0x15, {KEY_WWW} },
477*4882a593Smuzhiyun 	{ KE_KEY, 0x40, {KEY_WLAN} },
478*4882a593Smuzhiyun 	{ KE_END, FE_WIFI_LED | FE_UNTESTED } /* no mail led */
479*4882a593Smuzhiyun };
480*4882a593Smuzhiyun 
481*4882a593Smuzhiyun /* Wifi subsystem only activates the led. Therefore we need to pass
482*4882a593Smuzhiyun  * wifi event as a normal key, then userspace can really change the wifi state.
483*4882a593Smuzhiyun  * TODO we need to export led state to userspace (wifi and mail) */
484*4882a593Smuzhiyun static struct key_entry keymap_acer_travelmate_610[] __initdata = {
485*4882a593Smuzhiyun 	{ KE_KEY, 0x01, {KEY_HELP} },
486*4882a593Smuzhiyun 	{ KE_KEY, 0x02, {KEY_CONFIG} },
487*4882a593Smuzhiyun 	{ KE_KEY, 0x11, {KEY_PROG1} },
488*4882a593Smuzhiyun 	{ KE_KEY, 0x12, {KEY_PROG2} },
489*4882a593Smuzhiyun 	{ KE_KEY, 0x13, {KEY_PROG3} },
490*4882a593Smuzhiyun 	{ KE_KEY, 0x14, {KEY_MAIL} },
491*4882a593Smuzhiyun 	{ KE_KEY, 0x15, {KEY_WWW} },
492*4882a593Smuzhiyun 	{ KE_KEY, 0x40, {KEY_WLAN} },
493*4882a593Smuzhiyun 	{ KE_END, FE_MAIL_LED | FE_WIFI_LED }
494*4882a593Smuzhiyun };
495*4882a593Smuzhiyun 
496*4882a593Smuzhiyun static struct key_entry keymap_acer_travelmate_630[] __initdata = {
497*4882a593Smuzhiyun 	{ KE_KEY, 0x01, {KEY_HELP} },
498*4882a593Smuzhiyun 	{ KE_KEY, 0x02, {KEY_CONFIG} },
499*4882a593Smuzhiyun 	{ KE_KEY, 0x03, {KEY_POWER} },
500*4882a593Smuzhiyun 	{ KE_KEY, 0x08, {KEY_MUTE} }, /* not 620 */
501*4882a593Smuzhiyun 	{ KE_KEY, 0x11, {KEY_PROG1} },
502*4882a593Smuzhiyun 	{ KE_KEY, 0x12, {KEY_PROG2} },
503*4882a593Smuzhiyun 	{ KE_KEY, 0x13, {KEY_PROG3} },
504*4882a593Smuzhiyun 	{ KE_KEY, 0x20, {KEY_VOLUMEUP} },
505*4882a593Smuzhiyun 	{ KE_KEY, 0x21, {KEY_VOLUMEDOWN} },
506*4882a593Smuzhiyun 	{ KE_KEY, 0x31, {KEY_MAIL} },
507*4882a593Smuzhiyun 	{ KE_KEY, 0x36, {KEY_WWW} },
508*4882a593Smuzhiyun 	{ KE_WIFI, 0x30 },
509*4882a593Smuzhiyun 	{ KE_END, FE_MAIL_LED | FE_UNTESTED }
510*4882a593Smuzhiyun };
511*4882a593Smuzhiyun 
512*4882a593Smuzhiyun static struct key_entry keymap_aopen_1559as[] __initdata = {
513*4882a593Smuzhiyun 	{ KE_KEY,  0x01, {KEY_HELP} },
514*4882a593Smuzhiyun 	{ KE_KEY,  0x06, {KEY_PROG3} },
515*4882a593Smuzhiyun 	{ KE_KEY,  0x11, {KEY_PROG1} },
516*4882a593Smuzhiyun 	{ KE_KEY,  0x12, {KEY_PROG2} },
517*4882a593Smuzhiyun 	{ KE_WIFI, 0x30 },
518*4882a593Smuzhiyun 	{ KE_KEY,  0x31, {KEY_MAIL} },
519*4882a593Smuzhiyun 	{ KE_KEY,  0x36, {KEY_WWW} },
520*4882a593Smuzhiyun 	{ KE_END,  0 },
521*4882a593Smuzhiyun };
522*4882a593Smuzhiyun 
523*4882a593Smuzhiyun static struct key_entry keymap_fs_amilo_d88x0[] __initdata = {
524*4882a593Smuzhiyun 	{ KE_KEY, 0x01, {KEY_HELP} },
525*4882a593Smuzhiyun 	{ KE_KEY, 0x08, {KEY_MUTE} },
526*4882a593Smuzhiyun 	{ KE_KEY, 0x31, {KEY_MAIL} },
527*4882a593Smuzhiyun 	{ KE_KEY, 0x36, {KEY_WWW} },
528*4882a593Smuzhiyun 	{ KE_KEY, 0x11, {KEY_PROG1} },
529*4882a593Smuzhiyun 	{ KE_KEY, 0x12, {KEY_PROG2} },
530*4882a593Smuzhiyun 	{ KE_KEY, 0x13, {KEY_PROG3} },
531*4882a593Smuzhiyun 	{ KE_END, FE_MAIL_LED | FE_WIFI_LED | FE_UNTESTED }
532*4882a593Smuzhiyun };
533*4882a593Smuzhiyun 
534*4882a593Smuzhiyun static struct key_entry keymap_wistron_md2900[] __initdata = {
535*4882a593Smuzhiyun 	{ KE_KEY, 0x01, {KEY_HELP} },
536*4882a593Smuzhiyun 	{ KE_KEY, 0x02, {KEY_CONFIG} },
537*4882a593Smuzhiyun 	{ KE_KEY, 0x11, {KEY_PROG1} },
538*4882a593Smuzhiyun 	{ KE_KEY, 0x12, {KEY_PROG2} },
539*4882a593Smuzhiyun 	{ KE_KEY, 0x31, {KEY_MAIL} },
540*4882a593Smuzhiyun 	{ KE_KEY, 0x36, {KEY_WWW} },
541*4882a593Smuzhiyun 	{ KE_WIFI, 0x30 },
542*4882a593Smuzhiyun 	{ KE_END, FE_MAIL_LED | FE_UNTESTED }
543*4882a593Smuzhiyun };
544*4882a593Smuzhiyun 
545*4882a593Smuzhiyun static struct key_entry keymap_wistron_md96500[] __initdata = {
546*4882a593Smuzhiyun 	{ KE_KEY, 0x01, {KEY_HELP} },
547*4882a593Smuzhiyun 	{ KE_KEY, 0x02, {KEY_CONFIG} },
548*4882a593Smuzhiyun 	{ KE_KEY, 0x05, {KEY_SWITCHVIDEOMODE} }, /* Display selection */
549*4882a593Smuzhiyun 	{ KE_KEY, 0x06, {KEY_DISPLAYTOGGLE} }, /* Display on/off */
550*4882a593Smuzhiyun 	{ KE_KEY, 0x08, {KEY_MUTE} },
551*4882a593Smuzhiyun 	{ KE_KEY, 0x11, {KEY_PROG1} },
552*4882a593Smuzhiyun 	{ KE_KEY, 0x12, {KEY_PROG2} },
553*4882a593Smuzhiyun 	{ KE_KEY, 0x20, {KEY_VOLUMEUP} },
554*4882a593Smuzhiyun 	{ KE_KEY, 0x21, {KEY_VOLUMEDOWN} },
555*4882a593Smuzhiyun 	{ KE_KEY, 0x22, {KEY_REWIND} },
556*4882a593Smuzhiyun 	{ KE_KEY, 0x23, {KEY_FORWARD} },
557*4882a593Smuzhiyun 	{ KE_KEY, 0x24, {KEY_PLAYPAUSE} },
558*4882a593Smuzhiyun 	{ KE_KEY, 0x25, {KEY_STOPCD} },
559*4882a593Smuzhiyun 	{ KE_KEY, 0x31, {KEY_MAIL} },
560*4882a593Smuzhiyun 	{ KE_KEY, 0x36, {KEY_WWW} },
561*4882a593Smuzhiyun 	{ KE_WIFI, 0x30 },
562*4882a593Smuzhiyun 	{ KE_BLUETOOTH, 0x44 },
563*4882a593Smuzhiyun 	{ KE_END, 0 }
564*4882a593Smuzhiyun };
565*4882a593Smuzhiyun 
566*4882a593Smuzhiyun static struct key_entry keymap_wistron_generic[] __initdata = {
567*4882a593Smuzhiyun 	{ KE_KEY, 0x01, {KEY_HELP} },
568*4882a593Smuzhiyun 	{ KE_KEY, 0x02, {KEY_CONFIG} },
569*4882a593Smuzhiyun 	{ KE_KEY, 0x03, {KEY_POWER} },
570*4882a593Smuzhiyun 	{ KE_KEY, 0x05, {KEY_SWITCHVIDEOMODE} }, /* Display selection */
571*4882a593Smuzhiyun 	{ KE_KEY, 0x06, {KEY_DISPLAYTOGGLE} }, /* Display on/off */
572*4882a593Smuzhiyun 	{ KE_KEY, 0x08, {KEY_MUTE} },
573*4882a593Smuzhiyun 	{ KE_KEY, 0x11, {KEY_PROG1} },
574*4882a593Smuzhiyun 	{ KE_KEY, 0x12, {KEY_PROG2} },
575*4882a593Smuzhiyun 	{ KE_KEY, 0x13, {KEY_PROG3} },
576*4882a593Smuzhiyun 	{ KE_KEY, 0x14, {KEY_MAIL} },
577*4882a593Smuzhiyun 	{ KE_KEY, 0x15, {KEY_WWW} },
578*4882a593Smuzhiyun 	{ KE_KEY, 0x20, {KEY_VOLUMEUP} },
579*4882a593Smuzhiyun 	{ KE_KEY, 0x21, {KEY_VOLUMEDOWN} },
580*4882a593Smuzhiyun 	{ KE_KEY, 0x22, {KEY_REWIND} },
581*4882a593Smuzhiyun 	{ KE_KEY, 0x23, {KEY_FORWARD} },
582*4882a593Smuzhiyun 	{ KE_KEY, 0x24, {KEY_PLAYPAUSE} },
583*4882a593Smuzhiyun 	{ KE_KEY, 0x25, {KEY_STOPCD} },
584*4882a593Smuzhiyun 	{ KE_KEY, 0x31, {KEY_MAIL} },
585*4882a593Smuzhiyun 	{ KE_KEY, 0x36, {KEY_WWW} },
586*4882a593Smuzhiyun 	{ KE_KEY, 0x37, {KEY_DISPLAYTOGGLE} }, /* Display on/off */
587*4882a593Smuzhiyun 	{ KE_KEY, 0x40, {KEY_WLAN} },
588*4882a593Smuzhiyun 	{ KE_KEY, 0x49, {KEY_CONFIG} },
589*4882a593Smuzhiyun 	{ KE_SW, 0x4a, {.sw = {SW_LID, 1}} }, /* lid close */
590*4882a593Smuzhiyun 	{ KE_SW, 0x4b, {.sw = {SW_LID, 0}} }, /* lid open */
591*4882a593Smuzhiyun 	{ KE_KEY, 0x6a, {KEY_CONFIG} },
592*4882a593Smuzhiyun 	{ KE_KEY, 0x6d, {KEY_POWER} },
593*4882a593Smuzhiyun 	{ KE_KEY, 0x71, {KEY_STOPCD} },
594*4882a593Smuzhiyun 	{ KE_KEY, 0x72, {KEY_PLAYPAUSE} },
595*4882a593Smuzhiyun 	{ KE_KEY, 0x74, {KEY_REWIND} },
596*4882a593Smuzhiyun 	{ KE_KEY, 0x78, {KEY_FORWARD} },
597*4882a593Smuzhiyun 	{ KE_WIFI, 0x30 },
598*4882a593Smuzhiyun 	{ KE_BLUETOOTH, 0x44 },
599*4882a593Smuzhiyun 	{ KE_END, 0 }
600*4882a593Smuzhiyun };
601*4882a593Smuzhiyun 
602*4882a593Smuzhiyun static struct key_entry keymap_aopen_1557[] __initdata = {
603*4882a593Smuzhiyun 	{ KE_KEY,  0x01, {KEY_HELP} },
604*4882a593Smuzhiyun 	{ KE_KEY,  0x11, {KEY_PROG1} },
605*4882a593Smuzhiyun 	{ KE_KEY,  0x12, {KEY_PROG2} },
606*4882a593Smuzhiyun 	{ KE_WIFI, 0x30 },
607*4882a593Smuzhiyun 	{ KE_KEY,  0x22, {KEY_REWIND} },
608*4882a593Smuzhiyun 	{ KE_KEY,  0x23, {KEY_FORWARD} },
609*4882a593Smuzhiyun 	{ KE_KEY,  0x24, {KEY_PLAYPAUSE} },
610*4882a593Smuzhiyun 	{ KE_KEY,  0x25, {KEY_STOPCD} },
611*4882a593Smuzhiyun 	{ KE_KEY,  0x31, {KEY_MAIL} },
612*4882a593Smuzhiyun 	{ KE_KEY,  0x36, {KEY_WWW} },
613*4882a593Smuzhiyun 	{ KE_END,  0 }
614*4882a593Smuzhiyun };
615*4882a593Smuzhiyun 
616*4882a593Smuzhiyun static struct key_entry keymap_prestigio[] __initdata = {
617*4882a593Smuzhiyun 	{ KE_KEY,  0x11, {KEY_PROG1} },
618*4882a593Smuzhiyun 	{ KE_KEY,  0x12, {KEY_PROG2} },
619*4882a593Smuzhiyun 	{ KE_WIFI, 0x30 },
620*4882a593Smuzhiyun 	{ KE_KEY,  0x22, {KEY_REWIND} },
621*4882a593Smuzhiyun 	{ KE_KEY,  0x23, {KEY_FORWARD} },
622*4882a593Smuzhiyun 	{ KE_KEY,  0x24, {KEY_PLAYPAUSE} },
623*4882a593Smuzhiyun 	{ KE_KEY,  0x25, {KEY_STOPCD} },
624*4882a593Smuzhiyun 	{ KE_KEY,  0x31, {KEY_MAIL} },
625*4882a593Smuzhiyun 	{ KE_KEY,  0x36, {KEY_WWW} },
626*4882a593Smuzhiyun 	{ KE_END,  0 }
627*4882a593Smuzhiyun };
628*4882a593Smuzhiyun 
629*4882a593Smuzhiyun 
630*4882a593Smuzhiyun /*
631*4882a593Smuzhiyun  * If your machine is not here (which is currently rather likely), please send
632*4882a593Smuzhiyun  * a list of buttons and their key codes (reported when loading this module
633*4882a593Smuzhiyun  * with force=1) and the output of dmidecode to $MODULE_AUTHOR.
634*4882a593Smuzhiyun  */
635*4882a593Smuzhiyun static const struct dmi_system_id dmi_ids[] __initconst = {
636*4882a593Smuzhiyun 	{
637*4882a593Smuzhiyun 		/* Fujitsu-Siemens Amilo Pro V2000 */
638*4882a593Smuzhiyun 		.callback = dmi_matched,
639*4882a593Smuzhiyun 		.matches = {
640*4882a593Smuzhiyun 			DMI_MATCH(DMI_SYS_VENDOR, "FUJITSU SIEMENS"),
641*4882a593Smuzhiyun 			DMI_MATCH(DMI_PRODUCT_NAME, "AMILO Pro V2000"),
642*4882a593Smuzhiyun 		},
643*4882a593Smuzhiyun 		.driver_data = keymap_fs_amilo_pro_v2000
644*4882a593Smuzhiyun 	},
645*4882a593Smuzhiyun 	{
646*4882a593Smuzhiyun 		/* Fujitsu-Siemens Amilo Pro Edition V3505 */
647*4882a593Smuzhiyun 		.callback = dmi_matched,
648*4882a593Smuzhiyun 		.matches = {
649*4882a593Smuzhiyun 			DMI_MATCH(DMI_SYS_VENDOR, "FUJITSU SIEMENS"),
650*4882a593Smuzhiyun 			DMI_MATCH(DMI_PRODUCT_NAME, "AMILO Pro Edition V3505"),
651*4882a593Smuzhiyun 		},
652*4882a593Smuzhiyun 		.driver_data = keymap_fs_amilo_pro_v3505
653*4882a593Smuzhiyun 	},
654*4882a593Smuzhiyun 	{
655*4882a593Smuzhiyun 		/* Fujitsu-Siemens Amilo Pro Edition V8210 */
656*4882a593Smuzhiyun 		.callback = dmi_matched,
657*4882a593Smuzhiyun 		.matches = {
658*4882a593Smuzhiyun 			DMI_MATCH(DMI_SYS_VENDOR, "FUJITSU SIEMENS"),
659*4882a593Smuzhiyun 			DMI_MATCH(DMI_PRODUCT_NAME, "AMILO Pro Series V8210"),
660*4882a593Smuzhiyun 		},
661*4882a593Smuzhiyun 		.driver_data = keymap_fs_amilo_pro_v8210
662*4882a593Smuzhiyun 	},
663*4882a593Smuzhiyun 	{
664*4882a593Smuzhiyun 		/* Fujitsu-Siemens Amilo M7400 */
665*4882a593Smuzhiyun 		.callback = dmi_matched,
666*4882a593Smuzhiyun 		.matches = {
667*4882a593Smuzhiyun 			DMI_MATCH(DMI_SYS_VENDOR, "FUJITSU SIEMENS"),
668*4882a593Smuzhiyun 			DMI_MATCH(DMI_PRODUCT_NAME, "AMILO M        "),
669*4882a593Smuzhiyun 		},
670*4882a593Smuzhiyun 		.driver_data = keymap_fs_amilo_pro_v2000
671*4882a593Smuzhiyun 	},
672*4882a593Smuzhiyun 	{
673*4882a593Smuzhiyun 		/* Maxdata Pro 7000 DX */
674*4882a593Smuzhiyun 		.callback = dmi_matched,
675*4882a593Smuzhiyun 		.matches = {
676*4882a593Smuzhiyun 			DMI_MATCH(DMI_SYS_VENDOR, "MAXDATA"),
677*4882a593Smuzhiyun 			DMI_MATCH(DMI_PRODUCT_NAME, "Pro 7000"),
678*4882a593Smuzhiyun 		},
679*4882a593Smuzhiyun 		.driver_data = keymap_fs_amilo_pro_v2000
680*4882a593Smuzhiyun 	},
681*4882a593Smuzhiyun 	{
682*4882a593Smuzhiyun 		/* Fujitsu N3510 */
683*4882a593Smuzhiyun 		.callback = dmi_matched,
684*4882a593Smuzhiyun 		.matches = {
685*4882a593Smuzhiyun 			DMI_MATCH(DMI_SYS_VENDOR, "FUJITSU"),
686*4882a593Smuzhiyun 			DMI_MATCH(DMI_PRODUCT_NAME, "N3510"),
687*4882a593Smuzhiyun 		},
688*4882a593Smuzhiyun 		.driver_data = keymap_fujitsu_n3510
689*4882a593Smuzhiyun 	},
690*4882a593Smuzhiyun 	{
691*4882a593Smuzhiyun 		/* Acer Aspire 1500 */
692*4882a593Smuzhiyun 		.callback = dmi_matched,
693*4882a593Smuzhiyun 		.matches = {
694*4882a593Smuzhiyun 			DMI_MATCH(DMI_SYS_VENDOR, "Acer"),
695*4882a593Smuzhiyun 			DMI_MATCH(DMI_PRODUCT_NAME, "Aspire 1500"),
696*4882a593Smuzhiyun 		},
697*4882a593Smuzhiyun 		.driver_data = keymap_acer_aspire_1500
698*4882a593Smuzhiyun 	},
699*4882a593Smuzhiyun 	{
700*4882a593Smuzhiyun 		/* Acer Aspire 1600 */
701*4882a593Smuzhiyun 		.callback = dmi_matched,
702*4882a593Smuzhiyun 		.matches = {
703*4882a593Smuzhiyun 			DMI_MATCH(DMI_SYS_VENDOR, "Acer"),
704*4882a593Smuzhiyun 			DMI_MATCH(DMI_PRODUCT_NAME, "Aspire 1600"),
705*4882a593Smuzhiyun 		},
706*4882a593Smuzhiyun 		.driver_data = keymap_acer_aspire_1600
707*4882a593Smuzhiyun 	},
708*4882a593Smuzhiyun 	{
709*4882a593Smuzhiyun 		/* Acer Aspire 3020 */
710*4882a593Smuzhiyun 		.callback = dmi_matched,
711*4882a593Smuzhiyun 		.matches = {
712*4882a593Smuzhiyun 			DMI_MATCH(DMI_SYS_VENDOR, "Acer"),
713*4882a593Smuzhiyun 			DMI_MATCH(DMI_PRODUCT_NAME, "Aspire 3020"),
714*4882a593Smuzhiyun 		},
715*4882a593Smuzhiyun 		.driver_data = keymap_acer_aspire_5020
716*4882a593Smuzhiyun 	},
717*4882a593Smuzhiyun 	{
718*4882a593Smuzhiyun 		/* Acer Aspire 5020 */
719*4882a593Smuzhiyun 		.callback = dmi_matched,
720*4882a593Smuzhiyun 		.matches = {
721*4882a593Smuzhiyun 			DMI_MATCH(DMI_SYS_VENDOR, "Acer"),
722*4882a593Smuzhiyun 			DMI_MATCH(DMI_PRODUCT_NAME, "Aspire 5020"),
723*4882a593Smuzhiyun 		},
724*4882a593Smuzhiyun 		.driver_data = keymap_acer_aspire_5020
725*4882a593Smuzhiyun 	},
726*4882a593Smuzhiyun 	{
727*4882a593Smuzhiyun 		/* Acer TravelMate 2100 */
728*4882a593Smuzhiyun 		.callback = dmi_matched,
729*4882a593Smuzhiyun 		.matches = {
730*4882a593Smuzhiyun 			DMI_MATCH(DMI_SYS_VENDOR, "Acer"),
731*4882a593Smuzhiyun 			DMI_MATCH(DMI_PRODUCT_NAME, "TravelMate 2100"),
732*4882a593Smuzhiyun 		},
733*4882a593Smuzhiyun 		.driver_data = keymap_acer_aspire_5020
734*4882a593Smuzhiyun 	},
735*4882a593Smuzhiyun 	{
736*4882a593Smuzhiyun 		/* Acer TravelMate 2410 */
737*4882a593Smuzhiyun 		.callback = dmi_matched,
738*4882a593Smuzhiyun 		.matches = {
739*4882a593Smuzhiyun 			DMI_MATCH(DMI_SYS_VENDOR, "Acer"),
740*4882a593Smuzhiyun 			DMI_MATCH(DMI_PRODUCT_NAME, "TravelMate 2410"),
741*4882a593Smuzhiyun 		},
742*4882a593Smuzhiyun 		.driver_data = keymap_acer_travelmate_2410
743*4882a593Smuzhiyun 	},
744*4882a593Smuzhiyun 	{
745*4882a593Smuzhiyun 		/* Acer TravelMate C300 */
746*4882a593Smuzhiyun 		.callback = dmi_matched,
747*4882a593Smuzhiyun 		.matches = {
748*4882a593Smuzhiyun 			DMI_MATCH(DMI_SYS_VENDOR, "Acer"),
749*4882a593Smuzhiyun 			DMI_MATCH(DMI_PRODUCT_NAME, "TravelMate C300"),
750*4882a593Smuzhiyun 		},
751*4882a593Smuzhiyun 		.driver_data = keymap_acer_travelmate_300
752*4882a593Smuzhiyun 	},
753*4882a593Smuzhiyun 	{
754*4882a593Smuzhiyun 		/* Acer TravelMate C100 */
755*4882a593Smuzhiyun 		.callback = dmi_matched,
756*4882a593Smuzhiyun 		.matches = {
757*4882a593Smuzhiyun 			DMI_MATCH(DMI_SYS_VENDOR, "Acer"),
758*4882a593Smuzhiyun 			DMI_MATCH(DMI_PRODUCT_NAME, "TravelMate C100"),
759*4882a593Smuzhiyun 		},
760*4882a593Smuzhiyun 		.driver_data = keymap_acer_travelmate_300
761*4882a593Smuzhiyun 	},
762*4882a593Smuzhiyun 	{
763*4882a593Smuzhiyun 		/* Acer TravelMate C110 */
764*4882a593Smuzhiyun 		.callback = dmi_matched,
765*4882a593Smuzhiyun 		.matches = {
766*4882a593Smuzhiyun 			DMI_MATCH(DMI_SYS_VENDOR, "Acer"),
767*4882a593Smuzhiyun 			DMI_MATCH(DMI_PRODUCT_NAME, "TravelMate C110"),
768*4882a593Smuzhiyun 		},
769*4882a593Smuzhiyun 		.driver_data = keymap_acer_travelmate_110
770*4882a593Smuzhiyun 	},
771*4882a593Smuzhiyun 	{
772*4882a593Smuzhiyun 		/* Acer TravelMate 380 */
773*4882a593Smuzhiyun 		.callback = dmi_matched,
774*4882a593Smuzhiyun 		.matches = {
775*4882a593Smuzhiyun 			DMI_MATCH(DMI_SYS_VENDOR, "Acer"),
776*4882a593Smuzhiyun 			DMI_MATCH(DMI_PRODUCT_NAME, "TravelMate 380"),
777*4882a593Smuzhiyun 		},
778*4882a593Smuzhiyun 		.driver_data = keymap_acer_travelmate_380
779*4882a593Smuzhiyun 	},
780*4882a593Smuzhiyun 	{
781*4882a593Smuzhiyun 		/* Acer TravelMate 370 */
782*4882a593Smuzhiyun 		.callback = dmi_matched,
783*4882a593Smuzhiyun 		.matches = {
784*4882a593Smuzhiyun 			DMI_MATCH(DMI_SYS_VENDOR, "Acer"),
785*4882a593Smuzhiyun 			DMI_MATCH(DMI_PRODUCT_NAME, "TravelMate 370"),
786*4882a593Smuzhiyun 		},
787*4882a593Smuzhiyun 		.driver_data = keymap_acer_travelmate_380 /* keyboard minus 1 key */
788*4882a593Smuzhiyun 	},
789*4882a593Smuzhiyun 	{
790*4882a593Smuzhiyun 		/* Acer TravelMate 220 */
791*4882a593Smuzhiyun 		.callback = dmi_matched,
792*4882a593Smuzhiyun 		.matches = {
793*4882a593Smuzhiyun 			DMI_MATCH(DMI_SYS_VENDOR, "Acer"),
794*4882a593Smuzhiyun 			DMI_MATCH(DMI_PRODUCT_NAME, "TravelMate 220"),
795*4882a593Smuzhiyun 		},
796*4882a593Smuzhiyun 		.driver_data = keymap_acer_travelmate_220
797*4882a593Smuzhiyun 	},
798*4882a593Smuzhiyun 	{
799*4882a593Smuzhiyun 		/* Acer TravelMate 260 */
800*4882a593Smuzhiyun 		.callback = dmi_matched,
801*4882a593Smuzhiyun 		.matches = {
802*4882a593Smuzhiyun 			DMI_MATCH(DMI_SYS_VENDOR, "Acer"),
803*4882a593Smuzhiyun 			DMI_MATCH(DMI_PRODUCT_NAME, "TravelMate 260"),
804*4882a593Smuzhiyun 		},
805*4882a593Smuzhiyun 		.driver_data = keymap_acer_travelmate_220
806*4882a593Smuzhiyun 	},
807*4882a593Smuzhiyun 	{
808*4882a593Smuzhiyun 		/* Acer TravelMate 230 */
809*4882a593Smuzhiyun 		.callback = dmi_matched,
810*4882a593Smuzhiyun 		.matches = {
811*4882a593Smuzhiyun 			DMI_MATCH(DMI_SYS_VENDOR, "Acer"),
812*4882a593Smuzhiyun 			DMI_MATCH(DMI_PRODUCT_NAME, "TravelMate 230"),
813*4882a593Smuzhiyun 			/* acerhk looks for "TravelMate F4..." ?! */
814*4882a593Smuzhiyun 		},
815*4882a593Smuzhiyun 		.driver_data = keymap_acer_travelmate_230
816*4882a593Smuzhiyun 	},
817*4882a593Smuzhiyun 	{
818*4882a593Smuzhiyun 		/* Acer TravelMate 280 */
819*4882a593Smuzhiyun 		.callback = dmi_matched,
820*4882a593Smuzhiyun 		.matches = {
821*4882a593Smuzhiyun 			DMI_MATCH(DMI_SYS_VENDOR, "Acer"),
822*4882a593Smuzhiyun 			DMI_MATCH(DMI_PRODUCT_NAME, "TravelMate 280"),
823*4882a593Smuzhiyun 		},
824*4882a593Smuzhiyun 		.driver_data = keymap_acer_travelmate_230
825*4882a593Smuzhiyun 	},
826*4882a593Smuzhiyun 	{
827*4882a593Smuzhiyun 		/* Acer TravelMate 240 */
828*4882a593Smuzhiyun 		.callback = dmi_matched,
829*4882a593Smuzhiyun 		.matches = {
830*4882a593Smuzhiyun 			DMI_MATCH(DMI_SYS_VENDOR, "Acer"),
831*4882a593Smuzhiyun 			DMI_MATCH(DMI_PRODUCT_NAME, "TravelMate 240"),
832*4882a593Smuzhiyun 		},
833*4882a593Smuzhiyun 		.driver_data = keymap_acer_travelmate_240
834*4882a593Smuzhiyun 	},
835*4882a593Smuzhiyun 	{
836*4882a593Smuzhiyun 		/* Acer TravelMate 250 */
837*4882a593Smuzhiyun 		.callback = dmi_matched,
838*4882a593Smuzhiyun 		.matches = {
839*4882a593Smuzhiyun 			DMI_MATCH(DMI_SYS_VENDOR, "Acer"),
840*4882a593Smuzhiyun 			DMI_MATCH(DMI_PRODUCT_NAME, "TravelMate 250"),
841*4882a593Smuzhiyun 		},
842*4882a593Smuzhiyun 		.driver_data = keymap_acer_travelmate_240
843*4882a593Smuzhiyun 	},
844*4882a593Smuzhiyun 	{
845*4882a593Smuzhiyun 		/* Acer TravelMate 2424NWXCi */
846*4882a593Smuzhiyun 		.callback = dmi_matched,
847*4882a593Smuzhiyun 		.matches = {
848*4882a593Smuzhiyun 			DMI_MATCH(DMI_SYS_VENDOR, "Acer"),
849*4882a593Smuzhiyun 			DMI_MATCH(DMI_PRODUCT_NAME, "TravelMate 2420"),
850*4882a593Smuzhiyun 		},
851*4882a593Smuzhiyun 		.driver_data = keymap_acer_travelmate_240
852*4882a593Smuzhiyun 	},
853*4882a593Smuzhiyun 	{
854*4882a593Smuzhiyun 		/* Acer TravelMate 350 */
855*4882a593Smuzhiyun 		.callback = dmi_matched,
856*4882a593Smuzhiyun 		.matches = {
857*4882a593Smuzhiyun 			DMI_MATCH(DMI_SYS_VENDOR, "Acer"),
858*4882a593Smuzhiyun 			DMI_MATCH(DMI_PRODUCT_NAME, "TravelMate 350"),
859*4882a593Smuzhiyun 		},
860*4882a593Smuzhiyun 		.driver_data = keymap_acer_travelmate_350
861*4882a593Smuzhiyun 	},
862*4882a593Smuzhiyun 	{
863*4882a593Smuzhiyun 		/* Acer TravelMate 360 */
864*4882a593Smuzhiyun 		.callback = dmi_matched,
865*4882a593Smuzhiyun 		.matches = {
866*4882a593Smuzhiyun 			DMI_MATCH(DMI_SYS_VENDOR, "Acer"),
867*4882a593Smuzhiyun 			DMI_MATCH(DMI_PRODUCT_NAME, "TravelMate 360"),
868*4882a593Smuzhiyun 		},
869*4882a593Smuzhiyun 		.driver_data = keymap_acer_travelmate_360
870*4882a593Smuzhiyun 	},
871*4882a593Smuzhiyun 	{
872*4882a593Smuzhiyun 		/* Acer TravelMate 610 */
873*4882a593Smuzhiyun 		.callback = dmi_matched,
874*4882a593Smuzhiyun 		.matches = {
875*4882a593Smuzhiyun 			DMI_MATCH(DMI_SYS_VENDOR, "ACER"),
876*4882a593Smuzhiyun 			DMI_MATCH(DMI_PRODUCT_NAME, "TravelMate 610"),
877*4882a593Smuzhiyun 		},
878*4882a593Smuzhiyun 		.driver_data = keymap_acer_travelmate_610
879*4882a593Smuzhiyun 	},
880*4882a593Smuzhiyun 	{
881*4882a593Smuzhiyun 		/* Acer TravelMate 620 */
882*4882a593Smuzhiyun 		.callback = dmi_matched,
883*4882a593Smuzhiyun 		.matches = {
884*4882a593Smuzhiyun 			DMI_MATCH(DMI_SYS_VENDOR, "Acer"),
885*4882a593Smuzhiyun 			DMI_MATCH(DMI_PRODUCT_NAME, "TravelMate 620"),
886*4882a593Smuzhiyun 		},
887*4882a593Smuzhiyun 		.driver_data = keymap_acer_travelmate_630
888*4882a593Smuzhiyun 	},
889*4882a593Smuzhiyun 	{
890*4882a593Smuzhiyun 		/* Acer TravelMate 630 */
891*4882a593Smuzhiyun 		.callback = dmi_matched,
892*4882a593Smuzhiyun 		.matches = {
893*4882a593Smuzhiyun 			DMI_MATCH(DMI_SYS_VENDOR, "Acer"),
894*4882a593Smuzhiyun 			DMI_MATCH(DMI_PRODUCT_NAME, "TravelMate 630"),
895*4882a593Smuzhiyun 		},
896*4882a593Smuzhiyun 		.driver_data = keymap_acer_travelmate_630
897*4882a593Smuzhiyun 	},
898*4882a593Smuzhiyun 	{
899*4882a593Smuzhiyun 		/* AOpen 1559AS */
900*4882a593Smuzhiyun 		.callback = dmi_matched,
901*4882a593Smuzhiyun 		.matches = {
902*4882a593Smuzhiyun 			DMI_MATCH(DMI_PRODUCT_NAME, "E2U"),
903*4882a593Smuzhiyun 			DMI_MATCH(DMI_BOARD_NAME, "E2U"),
904*4882a593Smuzhiyun 		},
905*4882a593Smuzhiyun 		.driver_data = keymap_aopen_1559as
906*4882a593Smuzhiyun 	},
907*4882a593Smuzhiyun 	{
908*4882a593Smuzhiyun 		/* Medion MD 9783 */
909*4882a593Smuzhiyun 		.callback = dmi_matched,
910*4882a593Smuzhiyun 		.matches = {
911*4882a593Smuzhiyun 			DMI_MATCH(DMI_SYS_VENDOR, "MEDIONNB"),
912*4882a593Smuzhiyun 			DMI_MATCH(DMI_PRODUCT_NAME, "MD 9783"),
913*4882a593Smuzhiyun 		},
914*4882a593Smuzhiyun 		.driver_data = keymap_wistron_ms2111
915*4882a593Smuzhiyun 	},
916*4882a593Smuzhiyun 	{
917*4882a593Smuzhiyun 		/* Medion MD 40100 */
918*4882a593Smuzhiyun 		.callback = dmi_matched,
919*4882a593Smuzhiyun 		.matches = {
920*4882a593Smuzhiyun 			DMI_MATCH(DMI_SYS_VENDOR, "MEDIONNB"),
921*4882a593Smuzhiyun 			DMI_MATCH(DMI_PRODUCT_NAME, "WID2000"),
922*4882a593Smuzhiyun 		},
923*4882a593Smuzhiyun 		.driver_data = keymap_wistron_md40100
924*4882a593Smuzhiyun 	},
925*4882a593Smuzhiyun 	{
926*4882a593Smuzhiyun 		/* Medion MD 2900 */
927*4882a593Smuzhiyun 		.callback = dmi_matched,
928*4882a593Smuzhiyun 		.matches = {
929*4882a593Smuzhiyun 			DMI_MATCH(DMI_SYS_VENDOR, "MEDIONNB"),
930*4882a593Smuzhiyun 			DMI_MATCH(DMI_PRODUCT_NAME, "WIM 2000"),
931*4882a593Smuzhiyun 		},
932*4882a593Smuzhiyun 		.driver_data = keymap_wistron_md2900
933*4882a593Smuzhiyun 	},
934*4882a593Smuzhiyun 	{
935*4882a593Smuzhiyun 		/* Medion MD 42200 */
936*4882a593Smuzhiyun 		.callback = dmi_matched,
937*4882a593Smuzhiyun 		.matches = {
938*4882a593Smuzhiyun 			DMI_MATCH(DMI_SYS_VENDOR, "Medion"),
939*4882a593Smuzhiyun 			DMI_MATCH(DMI_PRODUCT_NAME, "WIM 2030"),
940*4882a593Smuzhiyun 		},
941*4882a593Smuzhiyun 		.driver_data = keymap_fs_amilo_pro_v2000
942*4882a593Smuzhiyun 	},
943*4882a593Smuzhiyun 	{
944*4882a593Smuzhiyun 		/* Medion MD 96500 */
945*4882a593Smuzhiyun 		.callback = dmi_matched,
946*4882a593Smuzhiyun 		.matches = {
947*4882a593Smuzhiyun 			DMI_MATCH(DMI_SYS_VENDOR, "MEDIONPC"),
948*4882a593Smuzhiyun 			DMI_MATCH(DMI_PRODUCT_NAME, "WIM 2040"),
949*4882a593Smuzhiyun 		},
950*4882a593Smuzhiyun 		.driver_data = keymap_wistron_md96500
951*4882a593Smuzhiyun 	},
952*4882a593Smuzhiyun 	{
953*4882a593Smuzhiyun 		/* Medion MD 95400 */
954*4882a593Smuzhiyun 		.callback = dmi_matched,
955*4882a593Smuzhiyun 		.matches = {
956*4882a593Smuzhiyun 			DMI_MATCH(DMI_SYS_VENDOR, "MEDIONPC"),
957*4882a593Smuzhiyun 			DMI_MATCH(DMI_PRODUCT_NAME, "WIM 2050"),
958*4882a593Smuzhiyun 		},
959*4882a593Smuzhiyun 		.driver_data = keymap_wistron_md96500
960*4882a593Smuzhiyun 	},
961*4882a593Smuzhiyun 	{
962*4882a593Smuzhiyun 		/* Fujitsu Siemens Amilo D7820 */
963*4882a593Smuzhiyun 		.callback = dmi_matched,
964*4882a593Smuzhiyun 		.matches = {
965*4882a593Smuzhiyun 			DMI_MATCH(DMI_SYS_VENDOR, "FUJITSU SIEMENS"), /* not sure */
966*4882a593Smuzhiyun 			DMI_MATCH(DMI_PRODUCT_NAME, "Amilo D"),
967*4882a593Smuzhiyun 		},
968*4882a593Smuzhiyun 		.driver_data = keymap_fs_amilo_d88x0
969*4882a593Smuzhiyun 	},
970*4882a593Smuzhiyun 	{
971*4882a593Smuzhiyun 		/* Fujitsu Siemens Amilo D88x0 */
972*4882a593Smuzhiyun 		.callback = dmi_matched,
973*4882a593Smuzhiyun 		.matches = {
974*4882a593Smuzhiyun 			DMI_MATCH(DMI_SYS_VENDOR, "FUJITSU SIEMENS"),
975*4882a593Smuzhiyun 			DMI_MATCH(DMI_PRODUCT_NAME, "AMILO D"),
976*4882a593Smuzhiyun 		},
977*4882a593Smuzhiyun 		.driver_data = keymap_fs_amilo_d88x0
978*4882a593Smuzhiyun 	},
979*4882a593Smuzhiyun 	{ NULL, }
980*4882a593Smuzhiyun };
981*4882a593Smuzhiyun MODULE_DEVICE_TABLE(dmi, dmi_ids);
982*4882a593Smuzhiyun 
983*4882a593Smuzhiyun /* Copy the good keymap, as the original ones are free'd */
copy_keymap(void)984*4882a593Smuzhiyun static int __init copy_keymap(void)
985*4882a593Smuzhiyun {
986*4882a593Smuzhiyun 	const struct key_entry *key;
987*4882a593Smuzhiyun 	struct key_entry *new_keymap;
988*4882a593Smuzhiyun 	unsigned int length = 1;
989*4882a593Smuzhiyun 
990*4882a593Smuzhiyun 	for (key = keymap; key->type != KE_END; key++)
991*4882a593Smuzhiyun 		length++;
992*4882a593Smuzhiyun 
993*4882a593Smuzhiyun 	new_keymap = kmemdup(keymap, length * sizeof(struct key_entry),
994*4882a593Smuzhiyun 			     GFP_KERNEL);
995*4882a593Smuzhiyun 	if (!new_keymap)
996*4882a593Smuzhiyun 		return -ENOMEM;
997*4882a593Smuzhiyun 
998*4882a593Smuzhiyun 	keymap = new_keymap;
999*4882a593Smuzhiyun 
1000*4882a593Smuzhiyun 	return 0;
1001*4882a593Smuzhiyun }
1002*4882a593Smuzhiyun 
select_keymap(void)1003*4882a593Smuzhiyun static int __init select_keymap(void)
1004*4882a593Smuzhiyun {
1005*4882a593Smuzhiyun 	dmi_check_system(dmi_ids);
1006*4882a593Smuzhiyun 	if (keymap_name != NULL) {
1007*4882a593Smuzhiyun 		if (strcmp (keymap_name, "1557/MS2141") == 0)
1008*4882a593Smuzhiyun 			keymap = keymap_wistron_ms2141;
1009*4882a593Smuzhiyun 		else if (strcmp (keymap_name, "aopen1557") == 0)
1010*4882a593Smuzhiyun 			keymap = keymap_aopen_1557;
1011*4882a593Smuzhiyun 		else if (strcmp (keymap_name, "prestigio") == 0)
1012*4882a593Smuzhiyun 			keymap = keymap_prestigio;
1013*4882a593Smuzhiyun 		else if (strcmp (keymap_name, "generic") == 0)
1014*4882a593Smuzhiyun 			keymap = keymap_wistron_generic;
1015*4882a593Smuzhiyun 		else {
1016*4882a593Smuzhiyun 			printk(KERN_ERR "wistron_btns: Keymap unknown\n");
1017*4882a593Smuzhiyun 			return -EINVAL;
1018*4882a593Smuzhiyun 		}
1019*4882a593Smuzhiyun 	}
1020*4882a593Smuzhiyun 	if (keymap == NULL) {
1021*4882a593Smuzhiyun 		if (!force) {
1022*4882a593Smuzhiyun 			printk(KERN_ERR "wistron_btns: System unknown\n");
1023*4882a593Smuzhiyun 			return -ENODEV;
1024*4882a593Smuzhiyun 		}
1025*4882a593Smuzhiyun 		keymap = keymap_empty;
1026*4882a593Smuzhiyun 	}
1027*4882a593Smuzhiyun 
1028*4882a593Smuzhiyun 	return copy_keymap();
1029*4882a593Smuzhiyun }
1030*4882a593Smuzhiyun 
1031*4882a593Smuzhiyun  /* Input layer interface */
1032*4882a593Smuzhiyun 
1033*4882a593Smuzhiyun static struct input_dev *wistron_idev;
1034*4882a593Smuzhiyun static unsigned long jiffies_last_press;
1035*4882a593Smuzhiyun static bool wifi_enabled;
1036*4882a593Smuzhiyun static bool bluetooth_enabled;
1037*4882a593Smuzhiyun 
1038*4882a593Smuzhiyun  /* led management */
wistron_mail_led_set(struct led_classdev * led_cdev,enum led_brightness value)1039*4882a593Smuzhiyun static void wistron_mail_led_set(struct led_classdev *led_cdev,
1040*4882a593Smuzhiyun 				enum led_brightness value)
1041*4882a593Smuzhiyun {
1042*4882a593Smuzhiyun 	bios_set_state(MAIL_LED, (value != LED_OFF) ? 1 : 0);
1043*4882a593Smuzhiyun }
1044*4882a593Smuzhiyun 
1045*4882a593Smuzhiyun /* 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)1046*4882a593Smuzhiyun static void wistron_wifi_led_set(struct led_classdev *led_cdev,
1047*4882a593Smuzhiyun 				enum led_brightness value)
1048*4882a593Smuzhiyun {
1049*4882a593Smuzhiyun 	bios_set_state(WIFI, (value != LED_OFF) ? 1 : 0);
1050*4882a593Smuzhiyun }
1051*4882a593Smuzhiyun 
1052*4882a593Smuzhiyun static struct led_classdev wistron_mail_led = {
1053*4882a593Smuzhiyun 	.name			= "wistron:green:mail",
1054*4882a593Smuzhiyun 	.brightness_set		= wistron_mail_led_set,
1055*4882a593Smuzhiyun };
1056*4882a593Smuzhiyun 
1057*4882a593Smuzhiyun static struct led_classdev wistron_wifi_led = {
1058*4882a593Smuzhiyun 	.name			= "wistron:red:wifi",
1059*4882a593Smuzhiyun 	.brightness_set		= wistron_wifi_led_set,
1060*4882a593Smuzhiyun };
1061*4882a593Smuzhiyun 
wistron_led_init(struct device * parent)1062*4882a593Smuzhiyun static void wistron_led_init(struct device *parent)
1063*4882a593Smuzhiyun {
1064*4882a593Smuzhiyun 	if (leds_present & FE_WIFI_LED) {
1065*4882a593Smuzhiyun 		u16 wifi = bios_get_default_setting(WIFI);
1066*4882a593Smuzhiyun 		if (wifi & 1) {
1067*4882a593Smuzhiyun 			wistron_wifi_led.brightness = (wifi & 2) ? LED_FULL : LED_OFF;
1068*4882a593Smuzhiyun 			if (led_classdev_register(parent, &wistron_wifi_led))
1069*4882a593Smuzhiyun 				leds_present &= ~FE_WIFI_LED;
1070*4882a593Smuzhiyun 			else
1071*4882a593Smuzhiyun 				bios_set_state(WIFI, wistron_wifi_led.brightness);
1072*4882a593Smuzhiyun 
1073*4882a593Smuzhiyun 		} else
1074*4882a593Smuzhiyun 			leds_present &= ~FE_WIFI_LED;
1075*4882a593Smuzhiyun 	}
1076*4882a593Smuzhiyun 
1077*4882a593Smuzhiyun 	if (leds_present & FE_MAIL_LED) {
1078*4882a593Smuzhiyun 		/* bios_get_default_setting(MAIL) always retuns 0, so just turn the led off */
1079*4882a593Smuzhiyun 		wistron_mail_led.brightness = LED_OFF;
1080*4882a593Smuzhiyun 		if (led_classdev_register(parent, &wistron_mail_led))
1081*4882a593Smuzhiyun 			leds_present &= ~FE_MAIL_LED;
1082*4882a593Smuzhiyun 		else
1083*4882a593Smuzhiyun 			bios_set_state(MAIL_LED, wistron_mail_led.brightness);
1084*4882a593Smuzhiyun 	}
1085*4882a593Smuzhiyun }
1086*4882a593Smuzhiyun 
wistron_led_remove(void)1087*4882a593Smuzhiyun static void wistron_led_remove(void)
1088*4882a593Smuzhiyun {
1089*4882a593Smuzhiyun 	if (leds_present & FE_MAIL_LED)
1090*4882a593Smuzhiyun 		led_classdev_unregister(&wistron_mail_led);
1091*4882a593Smuzhiyun 
1092*4882a593Smuzhiyun 	if (leds_present & FE_WIFI_LED)
1093*4882a593Smuzhiyun 		led_classdev_unregister(&wistron_wifi_led);
1094*4882a593Smuzhiyun }
1095*4882a593Smuzhiyun 
wistron_led_suspend(void)1096*4882a593Smuzhiyun static inline void wistron_led_suspend(void)
1097*4882a593Smuzhiyun {
1098*4882a593Smuzhiyun 	if (leds_present & FE_MAIL_LED)
1099*4882a593Smuzhiyun 		led_classdev_suspend(&wistron_mail_led);
1100*4882a593Smuzhiyun 
1101*4882a593Smuzhiyun 	if (leds_present & FE_WIFI_LED)
1102*4882a593Smuzhiyun 		led_classdev_suspend(&wistron_wifi_led);
1103*4882a593Smuzhiyun }
1104*4882a593Smuzhiyun 
wistron_led_resume(void)1105*4882a593Smuzhiyun static inline void wistron_led_resume(void)
1106*4882a593Smuzhiyun {
1107*4882a593Smuzhiyun 	if (leds_present & FE_MAIL_LED)
1108*4882a593Smuzhiyun 		led_classdev_resume(&wistron_mail_led);
1109*4882a593Smuzhiyun 
1110*4882a593Smuzhiyun 	if (leds_present & FE_WIFI_LED)
1111*4882a593Smuzhiyun 		led_classdev_resume(&wistron_wifi_led);
1112*4882a593Smuzhiyun }
1113*4882a593Smuzhiyun 
handle_key(u8 code)1114*4882a593Smuzhiyun static void handle_key(u8 code)
1115*4882a593Smuzhiyun {
1116*4882a593Smuzhiyun 	const struct key_entry *key =
1117*4882a593Smuzhiyun 		sparse_keymap_entry_from_scancode(wistron_idev, code);
1118*4882a593Smuzhiyun 
1119*4882a593Smuzhiyun 	if (key) {
1120*4882a593Smuzhiyun 		switch (key->type) {
1121*4882a593Smuzhiyun 		case KE_WIFI:
1122*4882a593Smuzhiyun 			if (have_wifi) {
1123*4882a593Smuzhiyun 				wifi_enabled = !wifi_enabled;
1124*4882a593Smuzhiyun 				bios_set_state(WIFI, wifi_enabled);
1125*4882a593Smuzhiyun 			}
1126*4882a593Smuzhiyun 			break;
1127*4882a593Smuzhiyun 
1128*4882a593Smuzhiyun 		case KE_BLUETOOTH:
1129*4882a593Smuzhiyun 			if (have_bluetooth) {
1130*4882a593Smuzhiyun 				bluetooth_enabled = !bluetooth_enabled;
1131*4882a593Smuzhiyun 				bios_set_state(BLUETOOTH, bluetooth_enabled);
1132*4882a593Smuzhiyun 			}
1133*4882a593Smuzhiyun 			break;
1134*4882a593Smuzhiyun 
1135*4882a593Smuzhiyun 		default:
1136*4882a593Smuzhiyun 			sparse_keymap_report_entry(wistron_idev, key, 1, true);
1137*4882a593Smuzhiyun 			break;
1138*4882a593Smuzhiyun 		}
1139*4882a593Smuzhiyun 		jiffies_last_press = jiffies;
1140*4882a593Smuzhiyun 	} else {
1141*4882a593Smuzhiyun 		printk(KERN_NOTICE
1142*4882a593Smuzhiyun 			"wistron_btns: Unknown key code %02X\n", code);
1143*4882a593Smuzhiyun 	}
1144*4882a593Smuzhiyun }
1145*4882a593Smuzhiyun 
poll_bios(bool discard)1146*4882a593Smuzhiyun static void poll_bios(bool discard)
1147*4882a593Smuzhiyun {
1148*4882a593Smuzhiyun 	u8 qlen;
1149*4882a593Smuzhiyun 	u16 val;
1150*4882a593Smuzhiyun 
1151*4882a593Smuzhiyun 	for (;;) {
1152*4882a593Smuzhiyun 		qlen = CMOS_READ(cmos_address);
1153*4882a593Smuzhiyun 		if (qlen == 0)
1154*4882a593Smuzhiyun 			break;
1155*4882a593Smuzhiyun 		val = bios_pop_queue();
1156*4882a593Smuzhiyun 		if (val != 0 && !discard)
1157*4882a593Smuzhiyun 			handle_key((u8)val);
1158*4882a593Smuzhiyun 	}
1159*4882a593Smuzhiyun }
1160*4882a593Smuzhiyun 
wistron_flush(struct input_dev * dev)1161*4882a593Smuzhiyun static int wistron_flush(struct input_dev *dev)
1162*4882a593Smuzhiyun {
1163*4882a593Smuzhiyun 	/* Flush stale event queue */
1164*4882a593Smuzhiyun 	poll_bios(true);
1165*4882a593Smuzhiyun 
1166*4882a593Smuzhiyun 	return 0;
1167*4882a593Smuzhiyun }
1168*4882a593Smuzhiyun 
wistron_poll(struct input_dev * dev)1169*4882a593Smuzhiyun static void wistron_poll(struct input_dev *dev)
1170*4882a593Smuzhiyun {
1171*4882a593Smuzhiyun 	poll_bios(false);
1172*4882a593Smuzhiyun 
1173*4882a593Smuzhiyun 	/* Increase poll frequency if user is currently pressing keys (< 2s ago) */
1174*4882a593Smuzhiyun 	if (time_before(jiffies, jiffies_last_press + 2 * HZ))
1175*4882a593Smuzhiyun 		input_set_poll_interval(dev, POLL_INTERVAL_BURST);
1176*4882a593Smuzhiyun 	else
1177*4882a593Smuzhiyun 		input_set_poll_interval(dev, POLL_INTERVAL_DEFAULT);
1178*4882a593Smuzhiyun }
1179*4882a593Smuzhiyun 
wistron_setup_keymap(struct input_dev * dev,struct key_entry * entry)1180*4882a593Smuzhiyun static int wistron_setup_keymap(struct input_dev *dev,
1181*4882a593Smuzhiyun 					  struct key_entry *entry)
1182*4882a593Smuzhiyun {
1183*4882a593Smuzhiyun 	switch (entry->type) {
1184*4882a593Smuzhiyun 
1185*4882a593Smuzhiyun 	/* if wifi or bluetooth are not available, create normal keys */
1186*4882a593Smuzhiyun 	case KE_WIFI:
1187*4882a593Smuzhiyun 		if (!have_wifi) {
1188*4882a593Smuzhiyun 			entry->type = KE_KEY;
1189*4882a593Smuzhiyun 			entry->keycode = KEY_WLAN;
1190*4882a593Smuzhiyun 		}
1191*4882a593Smuzhiyun 		break;
1192*4882a593Smuzhiyun 
1193*4882a593Smuzhiyun 	case KE_BLUETOOTH:
1194*4882a593Smuzhiyun 		if (!have_bluetooth) {
1195*4882a593Smuzhiyun 			entry->type = KE_KEY;
1196*4882a593Smuzhiyun 			entry->keycode = KEY_BLUETOOTH;
1197*4882a593Smuzhiyun 		}
1198*4882a593Smuzhiyun 		break;
1199*4882a593Smuzhiyun 
1200*4882a593Smuzhiyun 	case KE_END:
1201*4882a593Smuzhiyun 		if (entry->code & FE_UNTESTED)
1202*4882a593Smuzhiyun 			printk(KERN_WARNING "Untested laptop multimedia keys, "
1203*4882a593Smuzhiyun 				"please report success or failure to "
1204*4882a593Smuzhiyun 				"eric.piel@tremplin-utc.net\n");
1205*4882a593Smuzhiyun 		break;
1206*4882a593Smuzhiyun 	}
1207*4882a593Smuzhiyun 
1208*4882a593Smuzhiyun 	return 0;
1209*4882a593Smuzhiyun }
1210*4882a593Smuzhiyun 
setup_input_dev(void)1211*4882a593Smuzhiyun static int setup_input_dev(void)
1212*4882a593Smuzhiyun {
1213*4882a593Smuzhiyun 	int error;
1214*4882a593Smuzhiyun 
1215*4882a593Smuzhiyun 	wistron_idev = input_allocate_device();
1216*4882a593Smuzhiyun 	if (!wistron_idev)
1217*4882a593Smuzhiyun 		return -ENOMEM;
1218*4882a593Smuzhiyun 
1219*4882a593Smuzhiyun 	wistron_idev->name = "Wistron laptop buttons";
1220*4882a593Smuzhiyun 	wistron_idev->phys = "wistron/input0";
1221*4882a593Smuzhiyun 	wistron_idev->id.bustype = BUS_HOST;
1222*4882a593Smuzhiyun 	wistron_idev->dev.parent = &wistron_device->dev;
1223*4882a593Smuzhiyun 
1224*4882a593Smuzhiyun 	wistron_idev->open = wistron_flush;
1225*4882a593Smuzhiyun 
1226*4882a593Smuzhiyun 	error = sparse_keymap_setup(wistron_idev, keymap, wistron_setup_keymap);
1227*4882a593Smuzhiyun 	if (error)
1228*4882a593Smuzhiyun 		goto err_free_dev;
1229*4882a593Smuzhiyun 
1230*4882a593Smuzhiyun 	error = input_setup_polling(wistron_idev, wistron_poll);
1231*4882a593Smuzhiyun 	if (error)
1232*4882a593Smuzhiyun 		goto err_free_dev;
1233*4882a593Smuzhiyun 
1234*4882a593Smuzhiyun 	input_set_poll_interval(wistron_idev, POLL_INTERVAL_DEFAULT);
1235*4882a593Smuzhiyun 
1236*4882a593Smuzhiyun 	error = input_register_device(wistron_idev);
1237*4882a593Smuzhiyun 	if (error)
1238*4882a593Smuzhiyun 		goto err_free_dev;
1239*4882a593Smuzhiyun 
1240*4882a593Smuzhiyun 	return 0;
1241*4882a593Smuzhiyun 
1242*4882a593Smuzhiyun  err_free_dev:
1243*4882a593Smuzhiyun 	input_free_device(wistron_idev);
1244*4882a593Smuzhiyun 	return error;
1245*4882a593Smuzhiyun }
1246*4882a593Smuzhiyun 
1247*4882a593Smuzhiyun /* Driver core */
1248*4882a593Smuzhiyun 
wistron_probe(struct platform_device * dev)1249*4882a593Smuzhiyun static int wistron_probe(struct platform_device *dev)
1250*4882a593Smuzhiyun {
1251*4882a593Smuzhiyun 	int err;
1252*4882a593Smuzhiyun 
1253*4882a593Smuzhiyun 	bios_attach();
1254*4882a593Smuzhiyun 	cmos_address = bios_get_cmos_address();
1255*4882a593Smuzhiyun 
1256*4882a593Smuzhiyun 	if (have_wifi) {
1257*4882a593Smuzhiyun 		u16 wifi = bios_get_default_setting(WIFI);
1258*4882a593Smuzhiyun 		if (wifi & 1)
1259*4882a593Smuzhiyun 			wifi_enabled = wifi & 2;
1260*4882a593Smuzhiyun 		else
1261*4882a593Smuzhiyun 			have_wifi = 0;
1262*4882a593Smuzhiyun 
1263*4882a593Smuzhiyun 		if (have_wifi)
1264*4882a593Smuzhiyun 			bios_set_state(WIFI, wifi_enabled);
1265*4882a593Smuzhiyun 	}
1266*4882a593Smuzhiyun 
1267*4882a593Smuzhiyun 	if (have_bluetooth) {
1268*4882a593Smuzhiyun 		u16 bt = bios_get_default_setting(BLUETOOTH);
1269*4882a593Smuzhiyun 		if (bt & 1)
1270*4882a593Smuzhiyun 			bluetooth_enabled = bt & 2;
1271*4882a593Smuzhiyun 		else
1272*4882a593Smuzhiyun 			have_bluetooth = false;
1273*4882a593Smuzhiyun 
1274*4882a593Smuzhiyun 		if (have_bluetooth)
1275*4882a593Smuzhiyun 			bios_set_state(BLUETOOTH, bluetooth_enabled);
1276*4882a593Smuzhiyun 	}
1277*4882a593Smuzhiyun 
1278*4882a593Smuzhiyun 	wistron_led_init(&dev->dev);
1279*4882a593Smuzhiyun 
1280*4882a593Smuzhiyun 	err = setup_input_dev();
1281*4882a593Smuzhiyun 	if (err) {
1282*4882a593Smuzhiyun 		bios_detach();
1283*4882a593Smuzhiyun 		return err;
1284*4882a593Smuzhiyun 	}
1285*4882a593Smuzhiyun 
1286*4882a593Smuzhiyun 	return 0;
1287*4882a593Smuzhiyun }
1288*4882a593Smuzhiyun 
wistron_remove(struct platform_device * dev)1289*4882a593Smuzhiyun static int wistron_remove(struct platform_device *dev)
1290*4882a593Smuzhiyun {
1291*4882a593Smuzhiyun 	wistron_led_remove();
1292*4882a593Smuzhiyun 	input_unregister_device(wistron_idev);
1293*4882a593Smuzhiyun 	bios_detach();
1294*4882a593Smuzhiyun 
1295*4882a593Smuzhiyun 	return 0;
1296*4882a593Smuzhiyun }
1297*4882a593Smuzhiyun 
1298*4882a593Smuzhiyun #ifdef CONFIG_PM
wistron_suspend(struct device * dev)1299*4882a593Smuzhiyun static int wistron_suspend(struct device *dev)
1300*4882a593Smuzhiyun {
1301*4882a593Smuzhiyun 	if (have_wifi)
1302*4882a593Smuzhiyun 		bios_set_state(WIFI, 0);
1303*4882a593Smuzhiyun 
1304*4882a593Smuzhiyun 	if (have_bluetooth)
1305*4882a593Smuzhiyun 		bios_set_state(BLUETOOTH, 0);
1306*4882a593Smuzhiyun 
1307*4882a593Smuzhiyun 	wistron_led_suspend();
1308*4882a593Smuzhiyun 
1309*4882a593Smuzhiyun 	return 0;
1310*4882a593Smuzhiyun }
1311*4882a593Smuzhiyun 
wistron_resume(struct device * dev)1312*4882a593Smuzhiyun static int wistron_resume(struct device *dev)
1313*4882a593Smuzhiyun {
1314*4882a593Smuzhiyun 	if (have_wifi)
1315*4882a593Smuzhiyun 		bios_set_state(WIFI, wifi_enabled);
1316*4882a593Smuzhiyun 
1317*4882a593Smuzhiyun 	if (have_bluetooth)
1318*4882a593Smuzhiyun 		bios_set_state(BLUETOOTH, bluetooth_enabled);
1319*4882a593Smuzhiyun 
1320*4882a593Smuzhiyun 	wistron_led_resume();
1321*4882a593Smuzhiyun 
1322*4882a593Smuzhiyun 	poll_bios(true);
1323*4882a593Smuzhiyun 
1324*4882a593Smuzhiyun 	return 0;
1325*4882a593Smuzhiyun }
1326*4882a593Smuzhiyun 
1327*4882a593Smuzhiyun static const struct dev_pm_ops wistron_pm_ops = {
1328*4882a593Smuzhiyun 	.suspend	= wistron_suspend,
1329*4882a593Smuzhiyun 	.resume		= wistron_resume,
1330*4882a593Smuzhiyun 	.poweroff	= wistron_suspend,
1331*4882a593Smuzhiyun 	.restore	= wistron_resume,
1332*4882a593Smuzhiyun };
1333*4882a593Smuzhiyun #endif
1334*4882a593Smuzhiyun 
1335*4882a593Smuzhiyun static struct platform_driver wistron_driver = {
1336*4882a593Smuzhiyun 	.driver		= {
1337*4882a593Smuzhiyun 		.name	= "wistron-bios",
1338*4882a593Smuzhiyun #ifdef CONFIG_PM
1339*4882a593Smuzhiyun 		.pm	= &wistron_pm_ops,
1340*4882a593Smuzhiyun #endif
1341*4882a593Smuzhiyun 	},
1342*4882a593Smuzhiyun 	.probe		= wistron_probe,
1343*4882a593Smuzhiyun 	.remove		= wistron_remove,
1344*4882a593Smuzhiyun };
1345*4882a593Smuzhiyun 
wb_module_init(void)1346*4882a593Smuzhiyun static int __init wb_module_init(void)
1347*4882a593Smuzhiyun {
1348*4882a593Smuzhiyun 	int err;
1349*4882a593Smuzhiyun 
1350*4882a593Smuzhiyun 	err = select_keymap();
1351*4882a593Smuzhiyun 	if (err)
1352*4882a593Smuzhiyun 		return err;
1353*4882a593Smuzhiyun 
1354*4882a593Smuzhiyun 	err = map_bios();
1355*4882a593Smuzhiyun 	if (err)
1356*4882a593Smuzhiyun 		goto err_free_keymap;
1357*4882a593Smuzhiyun 
1358*4882a593Smuzhiyun 	err = platform_driver_register(&wistron_driver);
1359*4882a593Smuzhiyun 	if (err)
1360*4882a593Smuzhiyun 		goto err_unmap_bios;
1361*4882a593Smuzhiyun 
1362*4882a593Smuzhiyun 	wistron_device = platform_device_alloc("wistron-bios", -1);
1363*4882a593Smuzhiyun 	if (!wistron_device) {
1364*4882a593Smuzhiyun 		err = -ENOMEM;
1365*4882a593Smuzhiyun 		goto err_unregister_driver;
1366*4882a593Smuzhiyun 	}
1367*4882a593Smuzhiyun 
1368*4882a593Smuzhiyun 	err = platform_device_add(wistron_device);
1369*4882a593Smuzhiyun 	if (err)
1370*4882a593Smuzhiyun 		goto err_free_device;
1371*4882a593Smuzhiyun 
1372*4882a593Smuzhiyun 	return 0;
1373*4882a593Smuzhiyun 
1374*4882a593Smuzhiyun  err_free_device:
1375*4882a593Smuzhiyun 	platform_device_put(wistron_device);
1376*4882a593Smuzhiyun  err_unregister_driver:
1377*4882a593Smuzhiyun 	platform_driver_unregister(&wistron_driver);
1378*4882a593Smuzhiyun  err_unmap_bios:
1379*4882a593Smuzhiyun 	unmap_bios();
1380*4882a593Smuzhiyun  err_free_keymap:
1381*4882a593Smuzhiyun 	kfree(keymap);
1382*4882a593Smuzhiyun 
1383*4882a593Smuzhiyun 	return err;
1384*4882a593Smuzhiyun }
1385*4882a593Smuzhiyun 
wb_module_exit(void)1386*4882a593Smuzhiyun static void __exit wb_module_exit(void)
1387*4882a593Smuzhiyun {
1388*4882a593Smuzhiyun 	platform_device_unregister(wistron_device);
1389*4882a593Smuzhiyun 	platform_driver_unregister(&wistron_driver);
1390*4882a593Smuzhiyun 	unmap_bios();
1391*4882a593Smuzhiyun 	kfree(keymap);
1392*4882a593Smuzhiyun }
1393*4882a593Smuzhiyun 
1394*4882a593Smuzhiyun module_init(wb_module_init);
1395*4882a593Smuzhiyun module_exit(wb_module_exit);
1396