Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-or-later
0002 /*
0003  * Eee PC WMI hotkey driver
0004  *
0005  * Copyright(C) 2010 Intel Corporation.
0006  * Copyright(C) 2010-2011 Corentin Chary <corentin.chary@gmail.com>
0007  *
0008  * Portions based on wistron_btns.c:
0009  * Copyright (C) 2005 Miloslav Trmac <mitr@volny.cz>
0010  * Copyright (C) 2005 Bernhard Rosenkraenzer <bero@arklinux.org>
0011  * Copyright (C) 2005 Dmitry Torokhov <dtor@mail.ru>
0012  */
0013 
0014 #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
0015 
0016 #include <linux/kernel.h>
0017 #include <linux/module.h>
0018 #include <linux/init.h>
0019 #include <linux/input.h>
0020 #include <linux/input/sparse-keymap.h>
0021 #include <linux/dmi.h>
0022 #include <linux/fb.h>
0023 #include <linux/acpi.h>
0024 
0025 #include "asus-wmi.h"
0026 
0027 #define EEEPC_WMI_FILE  "eeepc-wmi"
0028 
0029 MODULE_AUTHOR("Corentin Chary <corentin.chary@gmail.com>");
0030 MODULE_DESCRIPTION("Eee PC WMI Hotkey Driver");
0031 MODULE_LICENSE("GPL");
0032 
0033 #define EEEPC_ACPI_HID      "ASUS010" /* old _HID used in eeepc-laptop */
0034 
0035 #define EEEPC_WMI_EVENT_GUID    "ABBC0F72-8EA1-11D1-00A0-C90629100000"
0036 
0037 MODULE_ALIAS("wmi:"EEEPC_WMI_EVENT_GUID);
0038 
0039 static bool hotplug_wireless;
0040 
0041 module_param(hotplug_wireless, bool, 0444);
0042 MODULE_PARM_DESC(hotplug_wireless,
0043          "Enable hotplug for wireless device. "
0044          "If your laptop needs that, please report to "
0045          "acpi4asus-user@lists.sourceforge.net.");
0046 
0047 /* Values for T101MT "Home" key */
0048 #define HOME_PRESS  0xe4
0049 #define HOME_HOLD   0xea
0050 #define HOME_RELEASE    0xe5
0051 
0052 static const struct key_entry eeepc_wmi_keymap[] = {
0053     { KE_KEY, ASUS_WMI_BRN_DOWN, { KEY_BRIGHTNESSDOWN } },
0054     { KE_KEY, ASUS_WMI_BRN_UP, { KEY_BRIGHTNESSUP } },
0055     /* Sleep already handled via generic ACPI code */
0056     { KE_KEY, 0x30, { KEY_VOLUMEUP } },
0057     { KE_KEY, 0x31, { KEY_VOLUMEDOWN } },
0058     { KE_KEY, 0x32, { KEY_MUTE } },
0059     { KE_KEY, 0x5c, { KEY_F15 } }, /* Power Gear key */
0060     { KE_KEY, 0x5d, { KEY_WLAN } },
0061     { KE_KEY, 0x6b, { KEY_TOUCHPAD_TOGGLE } }, /* Toggle Touchpad */
0062     { KE_KEY, 0x82, { KEY_CAMERA } },
0063     { KE_KEY, 0x83, { KEY_CAMERA_ZOOMIN } },
0064     { KE_KEY, 0x88, { KEY_WLAN } },
0065     { KE_KEY, 0xbd, { KEY_CAMERA } },
0066     { KE_KEY, 0xcc, { KEY_SWITCHVIDEOMODE } },
0067     { KE_KEY, 0xe0, { KEY_PROG1 } }, /* Task Manager */
0068     { KE_KEY, 0xe1, { KEY_F14 } }, /* Change Resolution */
0069     { KE_KEY, HOME_PRESS, { KEY_CONFIG } }, /* Home/Express gate key */
0070     { KE_KEY, 0xe8, { KEY_SCREENLOCK } },
0071     { KE_KEY, 0xe9, { KEY_DISPLAYTOGGLE } },
0072     { KE_KEY, 0xeb, { KEY_CAMERA_ZOOMOUT } },
0073     { KE_KEY, 0xec, { KEY_CAMERA_UP } },
0074     { KE_KEY, 0xed, { KEY_CAMERA_DOWN } },
0075     { KE_KEY, 0xee, { KEY_CAMERA_LEFT } },
0076     { KE_KEY, 0xef, { KEY_CAMERA_RIGHT } },
0077     { KE_KEY, 0xf3, { KEY_MENU } },
0078     { KE_KEY, 0xf5, { KEY_HOMEPAGE } },
0079     { KE_KEY, 0xf6, { KEY_ESC } },
0080     { KE_END, 0},
0081 };
0082 
0083 static struct quirk_entry quirk_asus_unknown = {
0084 };
0085 
0086 static struct quirk_entry quirk_asus_1000h = {
0087     .hotplug_wireless = true,
0088 };
0089 
0090 static struct quirk_entry quirk_asus_et2012_type1 = {
0091     .store_backlight_power = true,
0092 };
0093 
0094 static struct quirk_entry quirk_asus_et2012_type3 = {
0095     .scalar_panel_brightness = true,
0096     .store_backlight_power = true,
0097 };
0098 
0099 static struct quirk_entry quirk_asus_x101ch = {
0100     /* We need this when ACPI function doesn't do this well */
0101     .wmi_backlight_power = true,
0102 };
0103 
0104 static struct quirk_entry *quirks;
0105 
0106 static void et2012_quirks(void)
0107 {
0108     const struct dmi_device *dev = NULL;
0109     char oemstring[30];
0110 
0111     while ((dev = dmi_find_device(DMI_DEV_TYPE_OEM_STRING, NULL, dev))) {
0112         if (sscanf(dev->name, "AEMS%24c", oemstring) == 1) {
0113             if (oemstring[18] == '1')
0114                 quirks = &quirk_asus_et2012_type1;
0115             else if (oemstring[18] == '3')
0116                 quirks = &quirk_asus_et2012_type3;
0117             break;
0118         }
0119     }
0120 }
0121 
0122 static int dmi_matched(const struct dmi_system_id *dmi)
0123 {
0124     char *model;
0125 
0126     quirks = dmi->driver_data;
0127 
0128     model = (char *)dmi->matches[1].substr;
0129     if (unlikely(strncmp(model, "ET2012", 6) == 0))
0130         et2012_quirks();
0131 
0132     return 1;
0133 }
0134 
0135 static const struct dmi_system_id asus_quirks[] = {
0136     {
0137         .callback = dmi_matched,
0138         .ident = "ASUSTeK Computer INC. 1000H",
0139         .matches = {
0140             DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK Computer INC."),
0141             DMI_MATCH(DMI_PRODUCT_NAME, "1000H"),
0142         },
0143         .driver_data = &quirk_asus_1000h,
0144     },
0145     {
0146         .callback = dmi_matched,
0147         .ident = "ASUSTeK Computer INC. ET2012E/I",
0148         .matches = {
0149             DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK Computer INC."),
0150             DMI_MATCH(DMI_PRODUCT_NAME, "ET2012"),
0151         },
0152         .driver_data = &quirk_asus_unknown,
0153     },
0154     {
0155         .callback = dmi_matched,
0156         .ident = "ASUSTeK Computer INC. X101CH",
0157         .matches = {
0158             DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."),
0159             DMI_MATCH(DMI_PRODUCT_NAME, "X101CH"),
0160         },
0161         .driver_data = &quirk_asus_x101ch,
0162     },
0163     {
0164         .callback = dmi_matched,
0165         .ident = "ASUSTeK Computer INC. 1015CX",
0166         .matches = {
0167             DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."),
0168             DMI_MATCH(DMI_PRODUCT_NAME, "1015CX"),
0169         },
0170         .driver_data = &quirk_asus_x101ch,
0171     },
0172     {},
0173 };
0174 
0175 static void eeepc_wmi_key_filter(struct asus_wmi_driver *asus_wmi, int *code,
0176                  unsigned int *value, bool *autorelease)
0177 {
0178     switch (*code) {
0179     case HOME_PRESS:
0180         *value = 1;
0181         *autorelease = 0;
0182         break;
0183     case HOME_HOLD:
0184         *code = ASUS_WMI_KEY_IGNORE;
0185         break;
0186     case HOME_RELEASE:
0187         *code = HOME_PRESS;
0188         *value = 0;
0189         *autorelease = 0;
0190         break;
0191     }
0192 }
0193 
0194 static int eeepc_wmi_probe(struct platform_device *pdev)
0195 {
0196     if (acpi_dev_found(EEEPC_ACPI_HID)) {
0197         pr_warn("Found legacy ATKD device (%s)\n", EEEPC_ACPI_HID);
0198         pr_warn("WMI device present, but legacy ATKD device is also "
0199             "present and enabled\n");
0200         pr_warn("You probably booted with acpi_osi=\"Linux\" or "
0201             "acpi_osi=\"!Windows 2009\"\n");
0202         pr_warn("Can't load eeepc-wmi, use default acpi_osi "
0203             "(preferred) or eeepc-laptop\n");
0204         return -EBUSY;
0205     }
0206     return 0;
0207 }
0208 
0209 static void eeepc_wmi_quirks(struct asus_wmi_driver *driver)
0210 {
0211     quirks = &quirk_asus_unknown;
0212     quirks->hotplug_wireless = hotplug_wireless;
0213 
0214     dmi_check_system(asus_quirks);
0215 
0216     driver->quirks = quirks;
0217     driver->quirks->wapf = -1;
0218     driver->panel_power = FB_BLANK_UNBLANK;
0219 }
0220 
0221 static struct asus_wmi_driver asus_wmi_driver = {
0222     .name = EEEPC_WMI_FILE,
0223     .owner = THIS_MODULE,
0224     .event_guid = EEEPC_WMI_EVENT_GUID,
0225     .keymap = eeepc_wmi_keymap,
0226     .input_name = "Eee PC WMI hotkeys",
0227     .input_phys = EEEPC_WMI_FILE "/input0",
0228     .key_filter = eeepc_wmi_key_filter,
0229     .probe = eeepc_wmi_probe,
0230     .detect_quirks = eeepc_wmi_quirks,
0231 };
0232 
0233 
0234 static int __init eeepc_wmi_init(void)
0235 {
0236     return asus_wmi_register_driver(&asus_wmi_driver);
0237 }
0238 
0239 static void __exit eeepc_wmi_exit(void)
0240 {
0241     asus_wmi_unregister_driver(&asus_wmi_driver);
0242 }
0243 
0244 module_init(eeepc_wmi_init);
0245 module_exit(eeepc_wmi_exit);