xref: /linux/drivers/platform/x86/asus-nb-wmi.c (revision b889fcf63cb62e7fdb7816565e28f44dbe4a76a5)
1 /*
2  * Asus Notebooks WMI hotkey driver
3  *
4  * Copyright(C) 2010 Corentin Chary <corentin.chary@gmail.com>
5  *
6  *  This program is free software; you can redistribute it and/or modify
7  *  it under the terms of the GNU General Public License as published by
8  *  the Free Software Foundation; either version 2 of the License, or
9  *  (at your option) any later version.
10  *
11  *  This program is distributed in the hope that it will be useful,
12  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
13  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  *  GNU General Public License for more details.
15  *
16  *  You should have received a copy of the GNU General Public License
17  *  along with this program; if not, write to the Free Software
18  *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
19  */
20 
21 #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
22 
23 #include <linux/kernel.h>
24 #include <linux/module.h>
25 #include <linux/init.h>
26 #include <linux/input.h>
27 #include <linux/input/sparse-keymap.h>
28 #include <linux/fb.h>
29 #include <linux/dmi.h>
30 
31 #include "asus-wmi.h"
32 
33 #define	ASUS_NB_WMI_FILE	"asus-nb-wmi"
34 
35 MODULE_AUTHOR("Corentin Chary <corentin.chary@gmail.com>");
36 MODULE_DESCRIPTION("Asus Notebooks WMI Hotkey Driver");
37 MODULE_LICENSE("GPL");
38 
39 #define ASUS_NB_WMI_EVENT_GUID	"0B3CBB35-E3C2-45ED-91C2-4C5A6D195D1C"
40 
41 MODULE_ALIAS("wmi:"ASUS_NB_WMI_EVENT_GUID);
42 
43 /*
44  * WAPF defines the behavior of the Fn+Fx wlan key
45  * The significance of values is yet to be found, but
46  * most of the time:
47  * Bit | Bluetooth | WLAN
48  *  0  | Hardware  | Hardware
49  *  1  | Hardware  | Software
50  *  4  | Software  | Software
51  */
52 static int wapf = -1;
53 module_param(wapf, uint, 0444);
54 MODULE_PARM_DESC(wapf, "WAPF value");
55 
56 static struct quirk_entry *quirks;
57 
58 static struct quirk_entry quirk_asus_unknown = {
59 	.wapf = 0,
60 };
61 
62 static struct quirk_entry quirk_asus_x401u = {
63 	.wapf = 4,
64 };
65 
66 static int dmi_matched(const struct dmi_system_id *dmi)
67 {
68 	quirks = dmi->driver_data;
69 	return 1;
70 }
71 
72 static struct dmi_system_id asus_quirks[] = {
73 	{
74 		.callback = dmi_matched,
75 		.ident = "ASUSTeK COMPUTER INC. X401U",
76 		.matches = {
77 			DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."),
78 			DMI_MATCH(DMI_PRODUCT_NAME, "X401U"),
79 		},
80 		.driver_data = &quirk_asus_x401u,
81 	},
82 	{
83 		.callback = dmi_matched,
84 		.ident = "ASUSTeK COMPUTER INC. X401A1",
85 		.matches = {
86 			DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."),
87 			DMI_MATCH(DMI_PRODUCT_NAME, "X401A1"),
88 		},
89 		.driver_data = &quirk_asus_x401u,
90 	},
91 	{
92 		.callback = dmi_matched,
93 		.ident = "ASUSTeK COMPUTER INC. X501U",
94 		.matches = {
95 			DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."),
96 			DMI_MATCH(DMI_PRODUCT_NAME, "X501U"),
97 		},
98 		.driver_data = &quirk_asus_x401u,
99 	},
100 	{
101 		.callback = dmi_matched,
102 		.ident = "ASUSTeK COMPUTER INC. X501A1",
103 		.matches = {
104 			DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."),
105 			DMI_MATCH(DMI_PRODUCT_NAME, "X501A1"),
106 		},
107 		.driver_data = &quirk_asus_x401u,
108 	},
109 	{
110 		.callback = dmi_matched,
111 		.ident = "ASUSTeK COMPUTER INC. X55A",
112 		.matches = {
113 			DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."),
114 			DMI_MATCH(DMI_PRODUCT_NAME, "X55A"),
115 		},
116 		.driver_data = &quirk_asus_x401u,
117 	},
118 	{
119 		.callback = dmi_matched,
120 		.ident = "ASUSTeK COMPUTER INC. X55C",
121 		.matches = {
122 			DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."),
123 			DMI_MATCH(DMI_PRODUCT_NAME, "X55C"),
124 		},
125 		.driver_data = &quirk_asus_x401u,
126 	},
127 	{
128 		.callback = dmi_matched,
129 		.ident = "ASUSTeK COMPUTER INC. X55U",
130 		.matches = {
131 			DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."),
132 			DMI_MATCH(DMI_PRODUCT_NAME, "X55U"),
133 		},
134 		.driver_data = &quirk_asus_x401u,
135 	},
136 	{
137 		.callback = dmi_matched,
138 		.ident = "ASUSTeK COMPUTER INC. X55VD",
139 		.matches = {
140 			DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."),
141 			DMI_MATCH(DMI_PRODUCT_NAME, "X55VD"),
142 		},
143 		.driver_data = &quirk_asus_x401u,
144 	},
145 	{},
146 };
147 
148 static void asus_nb_wmi_quirks(struct asus_wmi_driver *driver)
149 {
150 	quirks = &quirk_asus_unknown;
151 	dmi_check_system(asus_quirks);
152 
153 	driver->quirks = quirks;
154 	driver->panel_power = FB_BLANK_UNBLANK;
155 
156 	/* overwrite the wapf setting if the wapf paramater is specified */
157 	if (wapf != -1)
158 		quirks->wapf = wapf;
159 	else
160 		wapf = quirks->wapf;
161 }
162 
163 static const struct key_entry asus_nb_wmi_keymap[] = {
164 	{ KE_KEY, 0x30, { KEY_VOLUMEUP } },
165 	{ KE_KEY, 0x31, { KEY_VOLUMEDOWN } },
166 	{ KE_KEY, 0x32, { KEY_MUTE } },
167 	{ KE_KEY, 0x33, { KEY_DISPLAYTOGGLE } }, /* LCD on */
168 	{ KE_KEY, 0x34, { KEY_DISPLAY_OFF } }, /* LCD off */
169 	{ KE_KEY, 0x40, { KEY_PREVIOUSSONG } },
170 	{ KE_KEY, 0x41, { KEY_NEXTSONG } },
171 	{ KE_KEY, 0x43, { KEY_STOPCD } },
172 	{ KE_KEY, 0x45, { KEY_PLAYPAUSE } },
173 	{ KE_KEY, 0x4c, { KEY_MEDIA } },
174 	{ KE_KEY, 0x50, { KEY_EMAIL } },
175 	{ KE_KEY, 0x51, { KEY_WWW } },
176 	{ KE_KEY, 0x55, { KEY_CALC } },
177 	{ KE_IGNORE, 0x57, },  /* Battery mode */
178 	{ KE_IGNORE, 0x58, },  /* AC mode */
179 	{ KE_KEY, 0x5C, { KEY_F15 } },  /* Power Gear key */
180 	{ KE_KEY, 0x5D, { KEY_WLAN } }, /* Wireless console Toggle */
181 	{ KE_KEY, 0x5E, { KEY_WLAN } }, /* Wireless console Enable */
182 	{ KE_KEY, 0x5F, { KEY_WLAN } }, /* Wireless console Disable */
183 	{ KE_KEY, 0x60, { KEY_SWITCHVIDEOMODE } },
184 	{ KE_KEY, 0x61, { KEY_SWITCHVIDEOMODE } },
185 	{ KE_KEY, 0x62, { KEY_SWITCHVIDEOMODE } },
186 	{ KE_KEY, 0x63, { KEY_SWITCHVIDEOMODE } },
187 	{ KE_KEY, 0x6B, { KEY_TOUCHPAD_TOGGLE } },
188 	{ KE_KEY, 0x7D, { KEY_BLUETOOTH } },
189 	{ KE_KEY, 0x7E, { KEY_BLUETOOTH } },
190 	{ KE_KEY, 0x82, { KEY_CAMERA } },
191 	{ KE_KEY, 0x88, { KEY_RFKILL  } },
192 	{ KE_KEY, 0x8A, { KEY_PROG1 } },
193 	{ KE_KEY, 0x95, { KEY_MEDIA } },
194 	{ KE_KEY, 0x99, { KEY_PHONE } },
195 	{ KE_KEY, 0xA0, { KEY_SWITCHVIDEOMODE } }, /* SDSP HDMI only */
196 	{ KE_KEY, 0xA1, { KEY_SWITCHVIDEOMODE } }, /* SDSP LCD + HDMI */
197 	{ KE_KEY, 0xA2, { KEY_SWITCHVIDEOMODE } }, /* SDSP CRT + HDMI */
198 	{ KE_KEY, 0xA3, { KEY_SWITCHVIDEOMODE } }, /* SDSP TV + HDMI */
199 	{ KE_KEY, 0xb5, { KEY_CALC } },
200 	{ KE_KEY, 0xc4, { KEY_KBDILLUMUP } },
201 	{ KE_KEY, 0xc5, { KEY_KBDILLUMDOWN } },
202 	{ KE_END, 0},
203 };
204 
205 static struct asus_wmi_driver asus_nb_wmi_driver = {
206 	.name = ASUS_NB_WMI_FILE,
207 	.owner = THIS_MODULE,
208 	.event_guid = ASUS_NB_WMI_EVENT_GUID,
209 	.keymap = asus_nb_wmi_keymap,
210 	.input_name = "Asus WMI hotkeys",
211 	.input_phys = ASUS_NB_WMI_FILE "/input0",
212 	.detect_quirks = asus_nb_wmi_quirks,
213 };
214 
215 
216 static int __init asus_nb_wmi_init(void)
217 {
218 	return asus_wmi_register_driver(&asus_nb_wmi_driver);
219 }
220 
221 static void __exit asus_nb_wmi_exit(void)
222 {
223 	asus_wmi_unregister_driver(&asus_nb_wmi_driver);
224 }
225 
226 module_init(asus_nb_wmi_init);
227 module_exit(asus_nb_wmi_exit);
228