aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--drivers/platform/x86/Kconfig10
-rw-r--r--drivers/platform/x86/Makefile1
-rw-r--r--drivers/platform/x86/msi-wmi.c369
3 files changed, 380 insertions, 0 deletions
diff --git a/drivers/platform/x86/Kconfig b/drivers/platform/x86/Kconfig
index 55ca39dea42e..98ec6bd9226e 100644
--- a/drivers/platform/x86/Kconfig
+++ b/drivers/platform/x86/Kconfig
@@ -365,6 +365,16 @@ config ACPI_WMI
365 It is safe to enable this driver even if your DSDT doesn't define 365 It is safe to enable this driver even if your DSDT doesn't define
366 any ACPI-WMI devices. 366 any ACPI-WMI devices.
367 367
368config MSI_WMI
369 tristate "MSI WMI extras"
370 depends on ACPI_WMI
371 depends on INPUT
372 help
373 Say Y here if you want to support WMI-based hotkeys on MSI laptops.
374
375 To compile this driver as a module, choose M here: the module will
376 be called msi-wmi.
377
368config ACPI_ASUS 378config ACPI_ASUS
369 tristate "ASUS/Medion Laptop Extras (DEPRECATED)" 379 tristate "ASUS/Medion Laptop Extras (DEPRECATED)"
370 depends on ACPI 380 depends on ACPI
diff --git a/drivers/platform/x86/Makefile b/drivers/platform/x86/Makefile
index d1c16210a512..13aa37310f33 100644
--- a/drivers/platform/x86/Makefile
+++ b/drivers/platform/x86/Makefile
@@ -18,6 +18,7 @@ obj-$(CONFIG_FUJITSU_LAPTOP) += fujitsu-laptop.o
18obj-$(CONFIG_PANASONIC_LAPTOP) += panasonic-laptop.o 18obj-$(CONFIG_PANASONIC_LAPTOP) += panasonic-laptop.o
19obj-$(CONFIG_INTEL_MENLOW) += intel_menlow.o 19obj-$(CONFIG_INTEL_MENLOW) += intel_menlow.o
20obj-$(CONFIG_ACPI_WMI) += wmi.o 20obj-$(CONFIG_ACPI_WMI) += wmi.o
21obj-$(CONFIG_MSI_WMI) += msi-wmi.o
21obj-$(CONFIG_ACPI_ASUS) += asus_acpi.o 22obj-$(CONFIG_ACPI_ASUS) += asus_acpi.o
22obj-$(CONFIG_TOPSTAR_LAPTOP) += topstar-laptop.o 23obj-$(CONFIG_TOPSTAR_LAPTOP) += topstar-laptop.o
23obj-$(CONFIG_ACPI_TOSHIBA) += toshiba_acpi.o 24obj-$(CONFIG_ACPI_TOSHIBA) += toshiba_acpi.o
diff --git a/drivers/platform/x86/msi-wmi.c b/drivers/platform/x86/msi-wmi.c
new file mode 100644
index 000000000000..7e0dab659752
--- /dev/null
+++ b/drivers/platform/x86/msi-wmi.c
@@ -0,0 +1,369 @@
1/*
2 * MSI WMI hotkeys
3 *
4 * Copyright (C) 2009 Novell <trenn@suse.de>
5 *
6 * Most stuff taken over from hp-wmi
7 *
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 2 of the License, or
11 * (at your option) any later version.
12 *
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
17 *
18 * You should have received a copy of the GNU General Public License
19 * along with this program; if not, write to the Free Software
20 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
21 */
22
23
24
25#include <linux/kernel.h>
26#include <linux/module.h>
27#include <linux/init.h>
28#include <linux/types.h>
29#include <linux/input.h>
30#include <acpi/acpi_drivers.h>
31#include <linux/acpi.h>
32#include <linux/string.h>
33#include <linux/hrtimer.h>
34#include <linux/backlight.h>
35
36MODULE_AUTHOR("Thomas Renninger <trenn@suse.de>");
37MODULE_DESCRIPTION("MSI laptop WMI hotkeys driver");
38MODULE_LICENSE("GPL");
39
40static int debug;
41module_param(debug, int, 0);
42MODULE_PARM_DESC(debug, "Set this to 1 to let the driver be more verbose");
43
44MODULE_ALIAS("wmi:551A1F84-FBDD-4125-91DB-3EA8F44F1D45");
45MODULE_ALIAS("wmi:B6F3EEF2-3D2F-49DC-9DE3-85BCE18C62F2");
46
47/* Temporary workaround until the WMI sysfs interface goes in
48 { "svn", DMI_SYS_VENDOR },
49 { "pn", DMI_PRODUCT_NAME },
50 { "pvr", DMI_PRODUCT_VERSION },
51 { "rvn", DMI_BOARD_VENDOR },
52 { "rn", DMI_BOARD_NAME },
53*/
54
55MODULE_ALIAS("dmi:*:svnMICRO-STARINTERNATIONAL*:pnMS-6638:*");
56
57#define DRV_NAME "msi-wmi"
58#define DRV_PFX DRV_NAME ": "
59
60#define MSIWMI_BIOS_GUID "551A1F84-FBDD-4125-91DB-3EA8F44F1D45"
61#define MSIWMI_EVENT_GUID "B6F3EEF2-3D2F-49DC-9DE3-85BCE18C62F2"
62
63#define dprintk(msg...) do { \
64 if (debug) \
65 printk(KERN_INFO DRV_PFX msg); \
66 } while (0)
67
68struct key_entry {
69 char type; /* See KE_* below */
70 u16 code;
71 u16 keycode;
72 int instance;
73 ktime_t last_pressed;
74};
75
76/*
77 * KE_KEY the only used key type, but keep this, others might also
78 * show up in the future. Compare with hp-wmi.c
79 */
80enum { KE_KEY, KE_END };
81
82static struct key_entry msi_wmi_keymap[] = {
83 { KE_KEY, 0xd0, KEY_BRIGHTNESSUP, 0, {0, } },
84 { KE_KEY, 0xd1, KEY_BRIGHTNESSDOWN, 1, {0, } },
85 { KE_KEY, 0xd2, KEY_VOLUMEUP, 2, {0, } },
86 { KE_KEY, 0xd3, KEY_VOLUMEDOWN, 3, {0, } },
87 { KE_END, 0}
88};
89
90struct backlight_device *backlight;
91
92static int backlight_map[] = { 0x00, 0x33, 0x66, 0x99, 0xCC, 0xFF };
93
94static struct input_dev *msi_wmi_input_dev;
95
96static int msi_wmi_query_block(int instance, int *ret)
97{
98 acpi_status status;
99 union acpi_object *obj;
100
101 struct acpi_buffer output = { ACPI_ALLOCATE_BUFFER, NULL };
102
103 status = wmi_query_block(MSIWMI_BIOS_GUID, instance, &output);
104
105 obj = output.pointer;
106
107 if (!obj || obj->type != ACPI_TYPE_INTEGER) {
108 if (obj) {
109 printk(KERN_ERR DRV_PFX "query block returned object "
110 "type: %d - buffer length:%d\n", obj->type,
111 obj->type == ACPI_TYPE_BUFFER ?
112 obj->buffer.length : 0);
113 }
114 kfree(obj);
115 return -EINVAL;
116 }
117 *ret = obj->integer.value;
118 kfree(obj);
119 return 0;
120}
121
122static int msi_wmi_set_block(int instance, int value)
123{
124 acpi_status status;
125
126 struct acpi_buffer input = { sizeof(int), &value };
127
128 dprintk("Going to set block of instance: %d - value: %d\n",
129 instance, value);
130
131 status = wmi_set_block(MSIWMI_BIOS_GUID, instance, &input);
132
133 return ACPI_SUCCESS(status) ? 0 : 1;
134}
135
136static int bl_get(struct backlight_device *bd)
137{
138 int level, err, ret = 0;
139
140 /* Instance 1 is "get backlight", cmp with DSDT */
141 err = msi_wmi_query_block(1, &ret);
142 if (err)
143 printk(KERN_ERR DRV_PFX "Could not query backlight: %d\n", err);
144 dprintk("Get: Query block returned: %d\n", ret);
145 for (level = 0; level < ARRAY_SIZE(backlight_map); level++) {
146 if (backlight_map[level] == ret) {
147 dprintk("Current backlight level: 0x%X - index: %d\n",
148 backlight_map[level], level);
149 break;
150 }
151 }
152 if (level == ARRAY_SIZE(backlight_map)) {
153 printk(KERN_ERR DRV_PFX "get: Invalid brightness value: 0x%X\n",
154 ret);
155 return -EINVAL;
156 }
157 return level;
158}
159
160static int bl_set_status(struct backlight_device *bd)
161{
162 int bright = bd->props.brightness;
163 if (bright >= ARRAY_SIZE(backlight_map) || bright < 0)