0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
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"
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
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
0056 { KE_KEY, 0x30, { KEY_VOLUMEUP } },
0057 { KE_KEY, 0x31, { KEY_VOLUMEDOWN } },
0058 { KE_KEY, 0x32, { KEY_MUTE } },
0059 { KE_KEY, 0x5c, { KEY_F15 } },
0060 { KE_KEY, 0x5d, { KEY_WLAN } },
0061 { KE_KEY, 0x6b, { KEY_TOUCHPAD_TOGGLE } },
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 } },
0068 { KE_KEY, 0xe1, { KEY_F14 } },
0069 { KE_KEY, HOME_PRESS, { KEY_CONFIG } },
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
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);