cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

wistron_btns.c (34700B)


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