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

asus-nb-wmi.c (16991B)


      1// SPDX-License-Identifier: GPL-2.0-or-later
      2/*
      3 * Asus Notebooks WMI hotkey driver
      4 *
      5 * Copyright(C) 2010 Corentin Chary <corentin.chary@gmail.com>
      6 */
      7
      8#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
      9
     10#include <linux/kernel.h>
     11#include <linux/module.h>
     12#include <linux/init.h>
     13#include <linux/input.h>
     14#include <linux/input/sparse-keymap.h>
     15#include <linux/fb.h>
     16#include <linux/dmi.h>
     17#include <linux/i8042.h>
     18
     19#include "asus-wmi.h"
     20
     21#define	ASUS_NB_WMI_FILE	"asus-nb-wmi"
     22
     23MODULE_AUTHOR("Corentin Chary <corentin.chary@gmail.com>");
     24MODULE_DESCRIPTION("Asus Notebooks WMI Hotkey Driver");
     25MODULE_LICENSE("GPL");
     26
     27#define ASUS_NB_WMI_EVENT_GUID	"0B3CBB35-E3C2-45ED-91C2-4C5A6D195D1C"
     28
     29MODULE_ALIAS("wmi:"ASUS_NB_WMI_EVENT_GUID);
     30
     31/*
     32 * WAPF defines the behavior of the Fn+Fx wlan key
     33 * The significance of values is yet to be found, but
     34 * most of the time:
     35 * Bit | Bluetooth | WLAN
     36 *  0  | Hardware  | Hardware
     37 *  1  | Hardware  | Software
     38 *  4  | Software  | Software
     39 */
     40static int wapf = -1;
     41module_param(wapf, uint, 0444);
     42MODULE_PARM_DESC(wapf, "WAPF value");
     43
     44static int tablet_mode_sw = -1;
     45module_param(tablet_mode_sw, uint, 0444);
     46MODULE_PARM_DESC(tablet_mode_sw, "Tablet mode detect: -1:auto 0:disable 1:kbd-dock 2:lid-flip");
     47
     48static struct quirk_entry *quirks;
     49
     50static bool asus_q500a_i8042_filter(unsigned char data, unsigned char str,
     51			      struct serio *port)
     52{
     53	static bool extended;
     54	bool ret = false;
     55
     56	if (str & I8042_STR_AUXDATA)
     57		return false;
     58
     59	if (unlikely(data == 0xe1)) {
     60		extended = true;
     61		ret = true;
     62	} else if (unlikely(extended)) {
     63		extended = false;
     64		ret = true;
     65	}
     66
     67	return ret;
     68}
     69
     70static struct quirk_entry quirk_asus_unknown = {
     71	.wapf = 0,
     72	.wmi_backlight_set_devstate = true,
     73};
     74
     75static struct quirk_entry quirk_asus_q500a = {
     76	.i8042_filter = asus_q500a_i8042_filter,
     77	.wmi_backlight_set_devstate = true,
     78};
     79
     80/*
     81 * For those machines that need software to control bt/wifi status
     82 * and can't adjust brightness through ACPI interface
     83 * and have duplicate events(ACPI and WMI) for display toggle
     84 */
     85static struct quirk_entry quirk_asus_x55u = {
     86	.wapf = 4,
     87	.wmi_backlight_power = true,
     88	.wmi_backlight_set_devstate = true,
     89	.no_display_toggle = true,
     90};
     91
     92static struct quirk_entry quirk_asus_wapf4 = {
     93	.wapf = 4,
     94	.wmi_backlight_set_devstate = true,
     95};
     96
     97static struct quirk_entry quirk_asus_x200ca = {
     98	.wapf = 2,
     99	.wmi_backlight_set_devstate = true,
    100};
    101
    102static struct quirk_entry quirk_asus_ux303ub = {
    103	.wmi_backlight_native = true,
    104	.wmi_backlight_set_devstate = true,
    105};
    106
    107static struct quirk_entry quirk_asus_x550lb = {
    108	.wmi_backlight_set_devstate = true,
    109	.xusb2pr = 0x01D9,
    110};
    111
    112static struct quirk_entry quirk_asus_forceals = {
    113	.wmi_backlight_set_devstate = true,
    114	.wmi_force_als_set = true,
    115};
    116
    117static struct quirk_entry quirk_asus_use_kbd_dock_devid = {
    118	.use_kbd_dock_devid = true,
    119};
    120
    121static struct quirk_entry quirk_asus_use_lid_flip_devid = {
    122	.wmi_backlight_set_devstate = true,
    123	.use_lid_flip_devid = true,
    124};
    125
    126static int dmi_matched(const struct dmi_system_id *dmi)
    127{
    128	pr_info("Identified laptop model '%s'\n", dmi->ident);
    129	quirks = dmi->driver_data;
    130	return 1;
    131}
    132
    133static const struct dmi_system_id asus_quirks[] = {
    134	{
    135		.callback = dmi_matched,
    136		.ident = "ASUSTeK COMPUTER INC. Q500A",
    137		.matches = {
    138			DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."),
    139			DMI_MATCH(DMI_PRODUCT_NAME, "Q500A"),
    140		},
    141		.driver_data = &quirk_asus_q500a,
    142	},
    143	{
    144		.callback = dmi_matched,
    145		.ident = "ASUSTeK COMPUTER INC. U32U",
    146		.matches = {
    147			DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK Computer Inc."),
    148			DMI_MATCH(DMI_PRODUCT_NAME, "U32U"),
    149		},
    150		/*
    151		 * Note this machine has a Brazos APU, and most Brazos Asus
    152		 * machines need quirk_asus_x55u / wmi_backlight_power but
    153		 * here acpi-video seems to work fine for backlight control.
    154		 */
    155		.driver_data = &quirk_asus_wapf4,
    156	},
    157	{
    158		.callback = dmi_matched,
    159		.ident = "ASUSTeK COMPUTER INC. X302UA",
    160		.matches = {
    161			DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."),
    162			DMI_MATCH(DMI_PRODUCT_NAME, "X302UA"),
    163		},
    164		.driver_data = &quirk_asus_wapf4,
    165	},
    166	{
    167		.callback = dmi_matched,
    168		.ident = "ASUSTeK COMPUTER INC. X401U",
    169		.matches = {
    170			DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."),
    171			DMI_MATCH(DMI_PRODUCT_NAME, "X401U"),
    172		},
    173		.driver_data = &quirk_asus_x55u,
    174	},
    175	{
    176		.callback = dmi_matched,
    177		.ident = "ASUSTeK COMPUTER INC. X401A",
    178		.matches = {
    179			DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."),
    180			DMI_MATCH(DMI_PRODUCT_NAME, "X401A"),
    181		},
    182		.driver_data = &quirk_asus_wapf4,
    183	},
    184	{
    185		.callback = dmi_matched,
    186		.ident = "ASUSTeK COMPUTER INC. X401A1",
    187		.matches = {
    188			DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."),
    189			DMI_MATCH(DMI_PRODUCT_NAME, "X401A1"),
    190		},
    191		.driver_data = &quirk_asus_wapf4,
    192	},
    193	{
    194		.callback = dmi_matched,
    195		.ident = "ASUSTeK COMPUTER INC. X45U",
    196		.matches = {
    197			DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."),
    198			DMI_MATCH(DMI_PRODUCT_NAME, "X45U"),
    199		},
    200		.driver_data = &quirk_asus_wapf4,
    201	},
    202	{
    203		.callback = dmi_matched,
    204		.ident = "ASUSTeK COMPUTER INC. X456UA",
    205		.matches = {
    206			DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."),
    207			DMI_MATCH(DMI_PRODUCT_NAME, "X456UA"),
    208		},
    209		.driver_data = &quirk_asus_wapf4,
    210	},
    211	{
    212		.callback = dmi_matched,
    213		.ident = "ASUSTeK COMPUTER INC. X456UF",
    214		.matches = {
    215			DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."),
    216			DMI_MATCH(DMI_PRODUCT_NAME, "X456UF"),
    217		},
    218		.driver_data = &quirk_asus_wapf4,
    219	},
    220	{
    221		.callback = dmi_matched,
    222		.ident = "ASUSTeK COMPUTER INC. X501U",
    223		.matches = {
    224			DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."),
    225			DMI_MATCH(DMI_PRODUCT_NAME, "X501U"),
    226		},
    227		.driver_data = &quirk_asus_x55u,
    228	},
    229	{
    230		.callback = dmi_matched,
    231		.ident = "ASUSTeK COMPUTER INC. X501A",
    232		.matches = {
    233			DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."),
    234			DMI_MATCH(DMI_PRODUCT_NAME, "X501A"),
    235		},
    236		.driver_data = &quirk_asus_wapf4,
    237	},
    238	{
    239		.callback = dmi_matched,
    240		.ident = "ASUSTeK COMPUTER INC. X501A1",
    241		.matches = {
    242			DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."),
    243			DMI_MATCH(DMI_PRODUCT_NAME, "X501A1"),
    244		},
    245		.driver_data = &quirk_asus_wapf4,
    246	},
    247	{
    248		.callback = dmi_matched,
    249		.ident = "ASUSTeK COMPUTER INC. X550CA",
    250		.matches = {
    251			DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."),
    252			DMI_MATCH(DMI_PRODUCT_NAME, "X550CA"),
    253		},
    254		.driver_data = &quirk_asus_wapf4,
    255	},
    256	{
    257		.callback = dmi_matched,
    258		.ident = "ASUSTeK COMPUTER INC. X550CC",
    259		.matches = {
    260			DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."),
    261			DMI_MATCH(DMI_PRODUCT_NAME, "X550CC"),
    262		},
    263		.driver_data = &quirk_asus_wapf4,
    264	},
    265	{
    266		.callback = dmi_matched,
    267		.ident = "ASUSTeK COMPUTER INC. X550CL",
    268		.matches = {
    269			DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."),
    270			DMI_MATCH(DMI_PRODUCT_NAME, "X550CL"),
    271		},
    272		.driver_data = &quirk_asus_wapf4,
    273	},
    274	{
    275		.callback = dmi_matched,
    276		.ident = "ASUSTeK COMPUTER INC. X550VB",
    277		.matches = {
    278			DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."),
    279			DMI_MATCH(DMI_PRODUCT_NAME, "X550VB"),
    280		},
    281		.driver_data = &quirk_asus_wapf4,
    282	},
    283	{
    284		.callback = dmi_matched,
    285		.ident = "ASUSTeK COMPUTER INC. X551CA",
    286		.matches = {
    287			DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."),
    288			DMI_MATCH(DMI_PRODUCT_NAME, "X551CA"),
    289		},
    290		.driver_data = &quirk_asus_wapf4,
    291	},
    292	{
    293		.callback = dmi_matched,
    294		.ident = "ASUSTeK COMPUTER INC. X55A",
    295		.matches = {
    296			DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."),
    297			DMI_MATCH(DMI_PRODUCT_NAME, "X55A"),
    298		},
    299		.driver_data = &quirk_asus_wapf4,
    300	},
    301	{
    302		.callback = dmi_matched,
    303		.ident = "ASUSTeK COMPUTER INC. X55C",
    304		.matches = {
    305			DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."),
    306			DMI_MATCH(DMI_PRODUCT_NAME, "X55C"),
    307		},
    308		.driver_data = &quirk_asus_wapf4,
    309	},
    310	{
    311		.callback = dmi_matched,
    312		.ident = "ASUSTeK COMPUTER INC. X55U",
    313		.matches = {
    314			DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."),
    315			DMI_MATCH(DMI_PRODUCT_NAME, "X55U"),
    316		},
    317		.driver_data = &quirk_asus_x55u,
    318	},
    319	{
    320		.callback = dmi_matched,
    321		.ident = "ASUSTeK COMPUTER INC. X55VD",
    322		.matches = {
    323			DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."),
    324			DMI_MATCH(DMI_PRODUCT_NAME, "X55VD"),
    325		},
    326		.driver_data = &quirk_asus_wapf4,
    327	},
    328	{
    329		.callback = dmi_matched,
    330		.ident = "ASUSTeK COMPUTER INC. X75A",
    331		.matches = {
    332			DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."),
    333			DMI_MATCH(DMI_PRODUCT_NAME, "X75A"),
    334		},
    335		.driver_data = &quirk_asus_wapf4,
    336	},
    337	{
    338		.callback = dmi_matched,
    339		.ident = "ASUSTeK COMPUTER INC. X75VBP",
    340		.matches = {
    341			DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."),
    342			DMI_MATCH(DMI_PRODUCT_NAME, "X75VBP"),
    343		},
    344		.driver_data = &quirk_asus_wapf4,
    345	},
    346	{
    347		.callback = dmi_matched,
    348		.ident = "ASUSTeK COMPUTER INC. X75VD",
    349		.matches = {
    350			DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."),
    351			DMI_MATCH(DMI_PRODUCT_NAME, "X75VD"),
    352		},
    353		.driver_data = &quirk_asus_wapf4,
    354	},
    355	{
    356		.callback = dmi_matched,
    357		.ident = "ASUSTeK COMPUTER INC. 1015E",
    358		.matches = {
    359			DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."),
    360			DMI_MATCH(DMI_PRODUCT_NAME, "1015E"),
    361		},
    362		.driver_data = &quirk_asus_wapf4,
    363	},
    364	{
    365		.callback = dmi_matched,
    366		.ident = "ASUSTeK COMPUTER INC. 1015U",
    367		.matches = {
    368			DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."),
    369			DMI_MATCH(DMI_PRODUCT_NAME, "1015U"),
    370		},
    371		.driver_data = &quirk_asus_wapf4,
    372	},
    373	{
    374		.callback = dmi_matched,
    375		.ident = "ASUSTeK COMPUTER INC. X200CA",
    376		.matches = {
    377			DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."),
    378			DMI_MATCH(DMI_PRODUCT_NAME, "X200CA"),
    379		},
    380		.driver_data = &quirk_asus_x200ca,
    381	},
    382	{
    383		.callback = dmi_matched,
    384		.ident = "ASUSTeK COMPUTER INC. UX303UB",
    385		.matches = {
    386			DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."),
    387			DMI_MATCH(DMI_PRODUCT_NAME, "UX303UB"),
    388		},
    389		.driver_data = &quirk_asus_ux303ub,
    390	},
    391	{
    392		.callback = dmi_matched,
    393		.ident = "ASUSTeK COMPUTER INC. UX330UAK",
    394		.matches = {
    395			DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."),
    396			DMI_MATCH(DMI_PRODUCT_NAME, "UX330UAK"),
    397		},
    398		.driver_data = &quirk_asus_forceals,
    399	},
    400	{
    401		.callback = dmi_matched,
    402		.ident = "ASUSTeK COMPUTER INC. X550LB",
    403		.matches = {
    404			DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."),
    405			DMI_MATCH(DMI_PRODUCT_NAME, "X550LB"),
    406		},
    407		.driver_data = &quirk_asus_x550lb,
    408	},
    409	{
    410		.callback = dmi_matched,
    411		.ident = "ASUSTeK COMPUTER INC. UX430UQ",
    412		.matches = {
    413			DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."),
    414			DMI_MATCH(DMI_PRODUCT_NAME, "UX430UQ"),
    415		},
    416		.driver_data = &quirk_asus_forceals,
    417	},
    418	{
    419		.callback = dmi_matched,
    420		.ident = "ASUSTeK COMPUTER INC. UX430UNR",
    421		.matches = {
    422			DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."),
    423			DMI_MATCH(DMI_PRODUCT_NAME, "UX430UNR"),
    424		},
    425		.driver_data = &quirk_asus_forceals,
    426	},
    427	{
    428		.callback = dmi_matched,
    429		.ident = "Asus Transformer T100TA / T100HA / T100CHI",
    430		.matches = {
    431			DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."),
    432			/* Match *T100* */
    433			DMI_MATCH(DMI_PRODUCT_NAME, "T100"),
    434		},
    435		.driver_data = &quirk_asus_use_kbd_dock_devid,
    436	},
    437	{
    438		.callback = dmi_matched,
    439		.ident = "Asus Transformer T101HA",
    440		.matches = {
    441			DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."),
    442			DMI_MATCH(DMI_PRODUCT_NAME, "T101HA"),
    443		},
    444		.driver_data = &quirk_asus_use_kbd_dock_devid,
    445	},
    446	{
    447		.callback = dmi_matched,
    448		.ident = "Asus Transformer T200TA",
    449		.matches = {
    450			DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."),
    451			DMI_MATCH(DMI_PRODUCT_NAME, "T200TA"),
    452		},
    453		.driver_data = &quirk_asus_use_kbd_dock_devid,
    454	},
    455	{
    456		.callback = dmi_matched,
    457		.ident = "ASUS ZenBook Flip UX360",
    458		.matches = {
    459			DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."),
    460			/* Match UX360* */
    461			DMI_MATCH(DMI_PRODUCT_NAME, "UX360"),
    462		},
    463		.driver_data = &quirk_asus_use_lid_flip_devid,
    464	},
    465	{
    466		.callback = dmi_matched,
    467		.ident = "ASUS TP200s / E205SA",
    468		.matches = {
    469			DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."),
    470			DMI_MATCH(DMI_PRODUCT_NAME, "E205SA"),
    471		},
    472		.driver_data = &quirk_asus_use_lid_flip_devid,
    473	},
    474	{},
    475};
    476
    477static void asus_nb_wmi_quirks(struct asus_wmi_driver *driver)
    478{
    479	int ret;
    480
    481	quirks = &quirk_asus_unknown;
    482	dmi_check_system(asus_quirks);
    483
    484	driver->quirks = quirks;
    485	driver->panel_power = FB_BLANK_UNBLANK;
    486
    487	/* overwrite the wapf setting if the wapf paramater is specified */
    488	if (wapf != -1)
    489		quirks->wapf = wapf;
    490	else
    491		wapf = quirks->wapf;
    492
    493	switch (tablet_mode_sw) {
    494	case 0:
    495		quirks->use_kbd_dock_devid = false;
    496		quirks->use_lid_flip_devid = false;
    497		break;
    498	case 1:
    499		quirks->use_kbd_dock_devid = true;
    500		quirks->use_lid_flip_devid = false;
    501		break;
    502	case 2:
    503		quirks->use_kbd_dock_devid = false;
    504		quirks->use_lid_flip_devid = true;
    505		break;
    506	}
    507
    508	if (quirks->i8042_filter) {
    509		ret = i8042_install_filter(quirks->i8042_filter);
    510		if (ret) {
    511			pr_warn("Unable to install key filter\n");
    512			return;
    513		}
    514		pr_info("Using i8042 filter function for receiving events\n");
    515	}
    516}
    517
    518static const struct key_entry asus_nb_wmi_keymap[] = {
    519	{ KE_KEY, ASUS_WMI_BRN_DOWN, { KEY_BRIGHTNESSDOWN } },
    520	{ KE_KEY, ASUS_WMI_BRN_UP, { KEY_BRIGHTNESSUP } },
    521	{ KE_KEY, 0x30, { KEY_VOLUMEUP } },
    522	{ KE_KEY, 0x31, { KEY_VOLUMEDOWN } },
    523	{ KE_KEY, 0x32, { KEY_MUTE } },
    524	{ KE_KEY, 0x35, { KEY_SCREENLOCK } },
    525	{ KE_KEY, 0x40, { KEY_PREVIOUSSONG } },
    526	{ KE_KEY, 0x41, { KEY_NEXTSONG } },
    527	{ KE_KEY, 0x43, { KEY_STOPCD } }, /* Stop/Eject */
    528	{ KE_KEY, 0x45, { KEY_PLAYPAUSE } },
    529	{ KE_KEY, 0x4c, { KEY_MEDIA } }, /* WMP Key */
    530	{ KE_KEY, 0x50, { KEY_EMAIL } },
    531	{ KE_KEY, 0x51, { KEY_WWW } },
    532	{ KE_KEY, 0x55, { KEY_CALC } },
    533	{ KE_IGNORE, 0x57, },  /* Battery mode */
    534	{ KE_IGNORE, 0x58, },  /* AC mode */
    535	{ KE_KEY, 0x5C, { KEY_F15 } },  /* Power Gear key */
    536	{ KE_KEY, 0x5D, { KEY_WLAN } }, /* Wireless console Toggle */
    537	{ KE_KEY, 0x5E, { KEY_WLAN } }, /* Wireless console Enable */
    538	{ KE_KEY, 0x5F, { KEY_WLAN } }, /* Wireless console Disable */
    539	{ KE_KEY, 0x60, { KEY_TOUCHPAD_ON } },
    540	{ KE_KEY, 0x61, { KEY_SWITCHVIDEOMODE } }, /* SDSP LCD only */
    541	{ KE_KEY, 0x62, { KEY_SWITCHVIDEOMODE } }, /* SDSP CRT only */
    542	{ KE_KEY, 0x63, { KEY_SWITCHVIDEOMODE } }, /* SDSP LCD + CRT */
    543	{ KE_KEY, 0x64, { KEY_SWITCHVIDEOMODE } }, /* SDSP TV */
    544	{ KE_KEY, 0x65, { KEY_SWITCHVIDEOMODE } }, /* SDSP LCD + TV */
    545	{ KE_KEY, 0x66, { KEY_SWITCHVIDEOMODE } }, /* SDSP CRT + TV */
    546	{ KE_KEY, 0x67, { KEY_SWITCHVIDEOMODE } }, /* SDSP LCD + CRT + TV */
    547	{ KE_KEY, 0x6B, { KEY_TOUCHPAD_TOGGLE } },
    548	{ KE_IGNORE, 0x6E, },  /* Low Battery notification */
    549	{ KE_KEY, 0x71, { KEY_F13 } }, /* General-purpose button */
    550	{ KE_IGNORE, 0x79, },  /* Charger type dectection notification */
    551	{ KE_KEY, 0x7a, { KEY_ALS_TOGGLE } }, /* Ambient Light Sensor Toggle */
    552	{ KE_KEY, 0x7c, { KEY_MICMUTE } },
    553	{ KE_KEY, 0x7D, { KEY_BLUETOOTH } }, /* Bluetooth Enable */
    554	{ KE_KEY, 0x7E, { KEY_BLUETOOTH } }, /* Bluetooth Disable */
    555	{ KE_KEY, 0x82, { KEY_CAMERA } },
    556	{ KE_KEY, 0x86, { KEY_PROG1 } }, /* MyASUS Key */
    557	{ KE_KEY, 0x88, { KEY_RFKILL  } }, /* Radio Toggle Key */
    558	{ KE_KEY, 0x8A, { KEY_PROG1 } }, /* Color enhancement mode */
    559	{ KE_KEY, 0x8C, { KEY_SWITCHVIDEOMODE } }, /* SDSP DVI only */
    560	{ KE_KEY, 0x8D, { KEY_SWITCHVIDEOMODE } }, /* SDSP LCD + DVI */
    561	{ KE_KEY, 0x8E, { KEY_SWITCHVIDEOMODE } }, /* SDSP CRT + DVI */
    562	{ KE_KEY, 0x8F, { KEY_SWITCHVIDEOMODE } }, /* SDSP TV + DVI */
    563	{ KE_KEY, 0x90, { KEY_SWITCHVIDEOMODE } }, /* SDSP LCD + CRT + DVI */
    564	{ KE_KEY, 0x91, { KEY_SWITCHVIDEOMODE } }, /* SDSP LCD + TV + DVI */
    565	{ KE_KEY, 0x92, { KEY_SWITCHVIDEOMODE } }, /* SDSP CRT + TV + DVI */
    566	{ KE_KEY, 0x93, { KEY_SWITCHVIDEOMODE } }, /* SDSP LCD + CRT + TV + DVI */
    567	{ KE_KEY, 0x95, { KEY_MEDIA } },
    568	{ KE_KEY, 0x99, { KEY_PHONE } }, /* Conflicts with fan mode switch */
    569	{ KE_KEY, 0xA0, { KEY_SWITCHVIDEOMODE } }, /* SDSP HDMI only */
    570	{ KE_KEY, 0xA1, { KEY_SWITCHVIDEOMODE } }, /* SDSP LCD + HDMI */
    571	{ KE_KEY, 0xA2, { KEY_SWITCHVIDEOMODE } }, /* SDSP CRT + HDMI */
    572	{ KE_KEY, 0xA3, { KEY_SWITCHVIDEOMODE } }, /* SDSP TV + HDMI */
    573	{ KE_KEY, 0xA4, { KEY_SWITCHVIDEOMODE } }, /* SDSP LCD + CRT + HDMI */
    574	{ KE_KEY, 0xA5, { KEY_SWITCHVIDEOMODE } }, /* SDSP LCD + TV + HDMI */
    575	{ KE_KEY, 0xA6, { KEY_SWITCHVIDEOMODE } }, /* SDSP CRT + TV + HDMI */
    576	{ KE_KEY, 0xA7, { KEY_SWITCHVIDEOMODE } }, /* SDSP LCD + CRT + TV + HDMI */
    577	{ KE_KEY, 0xB5, { KEY_CALC } },
    578	{ KE_KEY, 0xC4, { KEY_KBDILLUMUP } },
    579	{ KE_KEY, 0xC5, { KEY_KBDILLUMDOWN } },
    580	{ KE_IGNORE, 0xC6, },  /* Ambient Light Sensor notification */
    581	{ KE_KEY, 0xFA, { KEY_PROG2 } },           /* Lid flip action */
    582	{ KE_END, 0},
    583};
    584
    585static struct asus_wmi_driver asus_nb_wmi_driver = {
    586	.name = ASUS_NB_WMI_FILE,
    587	.owner = THIS_MODULE,
    588	.event_guid = ASUS_NB_WMI_EVENT_GUID,
    589	.keymap = asus_nb_wmi_keymap,
    590	.input_name = "Asus WMI hotkeys",
    591	.input_phys = ASUS_NB_WMI_FILE "/input0",
    592	.detect_quirks = asus_nb_wmi_quirks,
    593};
    594
    595
    596static int __init asus_nb_wmi_init(void)
    597{
    598	return asus_wmi_register_driver(&asus_nb_wmi_driver);
    599}
    600
    601static void __exit asus_nb_wmi_exit(void)
    602{
    603	asus_wmi_unregister_driver(&asus_nb_wmi_driver);
    604}
    605
    606module_init(asus_nb_wmi_init);
    607module_exit(asus_nb_wmi_exit);