1
0
Fork 0
alistair23-linux/drivers/platform/x86/eeepc-wmi.c

246 lines
6.3 KiB
C
Raw Normal View History

// SPDX-License-Identifier: GPL-2.0-or-later
/*
* Eee PC WMI hotkey driver
*
* Copyright(C) 2010 Intel Corporation.
* Copyright(C) 2010-2011 Corentin Chary <corentin.chary@gmail.com>
*
* Portions based on wistron_btns.c:
* Copyright (C) 2005 Miloslav Trmac <mitr@volny.cz>
* Copyright (C) 2005 Bernhard Rosenkraenzer <bero@arklinux.org>
* Copyright (C) 2005 Dmitry Torokhov <dtor@mail.ru>
*/
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/init.h>
#include <linux/input.h>
#include <linux/input/sparse-keymap.h>
#include <linux/dmi.h>
#include <linux/fb.h>
ACPI: Clean up inclusions of ACPI header files Replace direct inclusions of <acpi/acpi.h>, <acpi/acpi_bus.h> and <acpi/acpi_drivers.h>, which are incorrect, with <linux/acpi.h> inclusions and remove some inclusions of those files that aren't necessary. First of all, <acpi/acpi.h>, <acpi/acpi_bus.h> and <acpi/acpi_drivers.h> should not be included directly from any files that are built for CONFIG_ACPI unset, because that generally leads to build warnings about undefined symbols in !CONFIG_ACPI builds. For CONFIG_ACPI set, <linux/acpi.h> includes those files and for CONFIG_ACPI unset it provides stub ACPI symbols to be used in that case. Second, there are ordering dependencies between those files that always have to be met. Namely, it is required that <acpi/acpi_bus.h> be included prior to <acpi/acpi_drivers.h> so that the acpi_pci_root declarations the latter depends on are always there. And <acpi/acpi.h> which provides basic ACPICA type declarations should always be included prior to any other ACPI headers in CONFIG_ACPI builds. That also is taken care of including <linux/acpi.h> as appropriate. Signed-off-by: Lv Zheng <lv.zheng@intel.com> Cc: Greg Kroah-Hartman <gregkh@linuxfoundation.org> Cc: Matthew Garrett <mjg59@srcf.ucam.org> Cc: Tony Luck <tony.luck@intel.com> Cc: "H. Peter Anvin" <hpa@zytor.com> Acked-by: Bjorn Helgaas <bhelgaas@google.com> (drivers/pci stuff) Acked-by: Konrad Rzeszutek Wilk <konrad.wilk@oracle.com> (Xen stuff) Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
2013-12-02 17:49:16 -07:00
#include <linux/acpi.h>
#include "asus-wmi.h"
#define EEEPC_WMI_FILE "eeepc-wmi"
MODULE_AUTHOR("Corentin Chary <corentin.chary@gmail.com>");
MODULE_DESCRIPTION("Eee PC WMI Hotkey Driver");
MODULE_LICENSE("GPL");
#define EEEPC_ACPI_HID "ASUS010" /* old _HID used in eeepc-laptop */
#define EEEPC_WMI_EVENT_GUID "ABBC0F72-8EA1-11D1-00A0-C90629100000"
MODULE_ALIAS("wmi:"EEEPC_WMI_EVENT_GUID);
static bool hotplug_wireless;
module_param(hotplug_wireless, bool, 0444);
MODULE_PARM_DESC(hotplug_wireless,
"Enable hotplug for wireless device. "
"If your laptop needs that, please report to "
"acpi4asus-user@lists.sourceforge.net.");
/* Values for T101MT "Home" key */
#define HOME_PRESS 0xe4
#define HOME_HOLD 0xea
#define HOME_RELEASE 0xe5
static const struct key_entry eeepc_wmi_keymap[] = {
{ KE_KEY, ASUS_WMI_BRN_DOWN, { KEY_BRIGHTNESSDOWN } },
{ KE_KEY, ASUS_WMI_BRN_UP, { KEY_BRIGHTNESSUP } },
/* Sleep already handled via generic ACPI code */
{ KE_KEY, 0x30, { KEY_VOLUMEUP } },
{ KE_KEY, 0x31, { KEY_VOLUMEDOWN } },
{ KE_KEY, 0x32, { KEY_MUTE } },
{ KE_KEY, 0x5c, { KEY_F15 } }, /* Power Gear key */
{ KE_KEY, 0x5d, { KEY_WLAN } },
{ KE_KEY, 0x6b, { KEY_TOUCHPAD_TOGGLE } }, /* Toggle Touchpad */
{ KE_KEY, 0x82, { KEY_CAMERA } },
{ KE_KEY, 0x83, { KEY_CAMERA_ZOOMIN } },
{ KE_KEY, 0x88, { KEY_WLAN } },
{ KE_KEY, 0xbd, { KEY_CAMERA } },
{ KE_KEY, 0xcc, { KEY_SWITCHVIDEOMODE } },
{ KE_KEY, 0xe0, { KEY_PROG1 } }, /* Task Manager */
{ KE_KEY, 0xe1, { KEY_F14 } }, /* Change Resolution */
{ KE_KEY, HOME_PRESS, { KEY_CONFIG } }, /* Home/Express gate key */
{ KE_KEY, 0xe8, { KEY_SCREENLOCK } },
{ KE_KEY, 0xe9, { KEY_DISPLAYTOGGLE } },
{ KE_KEY, 0xeb, { KEY_CAMERA_ZOOMOUT } },
{ KE_KEY, 0xec, { KEY_CAMERA_UP } },
{ KE_KEY, 0xed, { KEY_CAMERA_DOWN } },
{ KE_KEY, 0xee, { KEY_CAMERA_LEFT } },
{ KE_KEY, 0xef, { KEY_CAMERA_RIGHT } },
{ KE_KEY, 0xf3, { KEY_MENU } },
{ KE_KEY, 0xf5, { KEY_HOMEPAGE } },
{ KE_KEY, 0xf6, { KEY_ESC } },
{ KE_END, 0},
};
static struct quirk_entry quirk_asus_unknown = {
};
static struct quirk_entry quirk_asus_1000h = {
.hotplug_wireless = true,
};
static struct quirk_entry quirk_asus_et2012_type1 = {
.store_backlight_power = true,
};
static struct quirk_entry quirk_asus_et2012_type3 = {
.scalar_panel_brightness = true,
.store_backlight_power = true,
};
static struct quirk_entry quirk_asus_x101ch = {
/* We need this when ACPI function doesn't do this well */
.wmi_backlight_power = true,
};
static struct quirk_entry *quirks;
static void et2012_quirks(void)
{
const struct dmi_device *dev = NULL;
char oemstring[30];
while ((dev = dmi_find_device(DMI_DEV_TYPE_OEM_STRING, NULL, dev))) {
if (sscanf(dev->name, "AEMS%24c", oemstring) == 1) {
if (oemstring[18] == '1')
quirks = &quirk_asus_et2012_type1;
else if (oemstring[18] == '3')
quirks = &quirk_asus_et2012_type3;
break;
}
}
}
static int dmi_matched(const struct dmi_system_id *dmi)
{
char *model;
quirks = dmi->driver_data;
model = (char *)dmi->matches[1].substr;
if (unlikely(strncmp(model, "ET2012", 6) == 0))
et2012_quirks();
return 1;
}
static const struct dmi_system_id asus_quirks[] = {
{
.callback = dmi_matched,
.ident = "ASUSTeK Computer INC. 1000H",
.matches = {
DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK Computer INC."),
DMI_MATCH(DMI_PRODUCT_NAME, "1000H"),
},
.driver_data = &quirk_asus_1000h,
},
{
.callback = dmi_matched,
.ident = "ASUSTeK Computer INC. ET2012E/I",
.matches = {
DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK Computer INC."),
DMI_MATCH(DMI_PRODUCT_NAME, "ET2012"),
},
.driver_data = &quirk_asus_unknown,
},
{
.callback = dmi_matched,
.ident = "ASUSTeK Computer INC. X101CH",
.matches = {
DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."),
DMI_MATCH(DMI_PRODUCT_NAME, "X101CH"),
},
.driver_data = &quirk_asus_x101ch,
},
{
.callback = dmi_matched,
.ident = "ASUSTeK Computer INC. 1015CX",
.matches = {
DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."),
DMI_MATCH(DMI_PRODUCT_NAME, "1015CX"),
},
.driver_data = &quirk_asus_x101ch,
},
{},
};
static void eeepc_wmi_key_filter(struct asus_wmi_driver *asus_wmi, int *code,
unsigned int *value, bool *autorelease)
{
switch (*code) {
case HOME_PRESS:
*value = 1;
*autorelease = 0;
break;
case HOME_HOLD:
*code = ASUS_WMI_KEY_IGNORE;
break;
case HOME_RELEASE:
*code = HOME_PRESS;
*value = 0;
*autorelease = 0;
break;
}
}
static int eeepc_wmi_probe(struct platform_device *pdev)
{
if (acpi_dev_found(EEEPC_ACPI_HID)) {
pr_warn("Found legacy ATKD device (%s)\n", EEEPC_ACPI_HID);
pr_warn("WMI device present, but legacy ATKD device is also "
"present and enabled\n");
pr_warn("You probably booted with acpi_osi=\"Linux\" or "
"acpi_osi=\"!Windows 2009\"\n");
pr_warn("Can't load eeepc-wmi, use default acpi_osi "
"(preferred) or eeepc-laptop\n");
return -EBUSY;
}
return 0;
}
static void eeepc_wmi_quirks(struct asus_wmi_driver *driver)
{
quirks = &quirk_asus_unknown;
quirks->hotplug_wireless = hotplug_wireless;
dmi_check_system(asus_quirks);
driver->quirks = quirks;
driver->quirks->wapf = -1;
driver->panel_power = FB_BLANK_UNBLANK;
}
static struct asus_wmi_driver asus_wmi_driver = {
.name = EEEPC_WMI_FILE,
.owner = THIS_MODULE,
.event_guid = EEEPC_WMI_EVENT_GUID,
.keymap = eeepc_wmi_keymap,
.input_name = "Eee PC WMI hotkeys",
.input_phys = EEEPC_WMI_FILE "/input0",
.key_filter = eeepc_wmi_key_filter,
.probe = eeepc_wmi_probe,
.detect_quirks = eeepc_wmi_quirks,
};
static int __init eeepc_wmi_init(void)
{
return asus_wmi_register_driver(&asus_wmi_driver);
}
static void __exit eeepc_wmi_exit(void)
{
asus_wmi_unregister_driver(&asus_wmi_driver);
}
module_init(eeepc_wmi_init);
module_exit(eeepc_wmi_exit);