aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/platform/x86/hp-wmi.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/platform/x86/hp-wmi.c')
-rw-r--r--drivers/platform/x86/hp-wmi.c502
1 files changed, 330 insertions, 172 deletions
diff --git a/drivers/platform/x86/hp-wmi.c b/drivers/platform/x86/hp-wmi.c
index c1741142a4cb..e2faa3cbb792 100644
--- a/drivers/platform/x86/hp-wmi.c
+++ b/drivers/platform/x86/hp-wmi.c
@@ -2,6 +2,7 @@
2 * HP WMI hotkeys 2 * HP WMI hotkeys
3 * 3 *
4 * Copyright (C) 2008 Red Hat <mjg@redhat.com> 4 * Copyright (C) 2008 Red Hat <mjg@redhat.com>
5 * Copyright (C) 2010, 2011 Anssi Hannula <anssi.hannula@iki.fi>
5 * 6 *
6 * Portions based on wistron_btns.c: 7 * Portions based on wistron_btns.c:
7 * Copyright (C) 2005 Miloslav Trmac <mitr@volny.cz> 8 * Copyright (C) 2005 Miloslav Trmac <mitr@volny.cz>
@@ -23,12 +24,15 @@
23 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 24 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
24 */ 25 */
25 26
27#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
28
26#include <linux/kernel.h> 29#include <linux/kernel.h>
27#include <linux/module.h> 30#include <linux/module.h>
28#include <linux/init.h> 31#include <linux/init.h>
29#include <linux/slab.h> 32#include <linux/slab.h>
30#include <linux/types.h> 33#include <linux/types.h>
31#include <linux/input.h> 34#include <linux/input.h>
35#include <linux/input/sparse-keymap.h>
32#include <linux/platform_device.h> 36#include <linux/platform_device.h>
33#include <linux/acpi.h> 37#include <linux/acpi.h>
34#include <linux/rfkill.h> 38#include <linux/rfkill.h>
@@ -50,9 +54,7 @@ MODULE_ALIAS("wmi:5FB7F034-2C63-45e9-BE91-3D44E2C707E4");
50#define HPWMI_HARDWARE_QUERY 0x4 54#define HPWMI_HARDWARE_QUERY 0x4
51#define HPWMI_WIRELESS_QUERY 0x5 55#define HPWMI_WIRELESS_QUERY 0x5
52#define HPWMI_HOTKEY_QUERY 0xc 56#define HPWMI_HOTKEY_QUERY 0xc
53 57#define HPWMI_WIRELESS2_QUERY 0x1b
54#define PREFIX "HP WMI: "
55#define UNIMP "Unimplemented "
56 58
57enum hp_wmi_radio { 59enum hp_wmi_radio {
58 HPWMI_WIFI = 0, 60 HPWMI_WIFI = 0,
@@ -85,27 +87,58 @@ struct bios_args {
85struct bios_return { 87struct bios_return {
86 u32 sigpass; 88 u32 sigpass;
87 u32 return_code; 89 u32 return_code;
88 u32 value;
89}; 90};
90 91
91struct key_entry { 92enum hp_return_value {
92 char type; /* See KE_* below */ 93 HPWMI_RET_WRONG_SIGNATURE = 0x02,
93 u16 code; 94 HPWMI_RET_UNKNOWN_COMMAND = 0x03,
94 u16 keycode; 95 HPWMI_RET_UNKNOWN_CMDTYPE = 0x04,
96 HPWMI_RET_INVALID_PARAMETERS = 0x05,
97};
98
99enum hp_wireless2_bits {
100 HPWMI_POWER_STATE = 0x01,
101 HPWMI_POWER_SOFT = 0x02,
102 HPWMI_POWER_BIOS = 0x04,
103 HPWMI_POWER_HARD = 0x08,
95}; 104};
96 105
97enum { KE_KEY, KE_END }; 106#define IS_HWBLOCKED(x) ((x & (HPWMI_POWER_BIOS | HPWMI_POWER_HARD)) \
98 107 != (HPWMI_POWER_BIOS | HPWMI_POWER_HARD))
99static struct key_entry hp_wmi_keymap[] = { 108#define IS_SWBLOCKED(x) !(x & HPWMI_POWER_SOFT)
100 {KE_KEY, 0x02, KEY_BRIGHTNESSUP}, 109
101 {KE_KEY, 0x03, KEY_BRIGHTNESSDOWN}, 110struct bios_rfkill2_device_state {
102 {KE_KEY, 0x20e6, KEY_PROG1}, 111 u8 radio_type;
103 {KE_KEY, 0x20e8, KEY_MEDIA}, 112 u8 bus_type;
104 {KE_KEY, 0x2142, KEY_MEDIA}, 113 u16 vendor_id;
105 {KE_KEY, 0x213b, KEY_INFO}, 114 u16 product_id;
106 {KE_KEY, 0x2169, KEY_DIRECTION}, 115 u16 subsys_vendor_id;
107 {KE_KEY, 0x231b, KEY_HELP}, 116 u16 subsys_product_id;
108 {KE_END, 0} 117 u8 rfkill_id;
118 u8 power;
119 u8 unknown[4];
120};
121
122/* 7 devices fit into the 128 byte buffer */
123#define HPWMI_MAX_RFKILL2_DEVICES 7
124
125struct bios_rfkill2_state {
126 u8 unknown[7];
127 u8 count;
128 u8 pad[8];
129 struct bios_rfkill2_device_state device[HPWMI_MAX_RFKILL2_DEVICES];
130};
131
132static const struct key_entry hp_wmi_keymap[] = {
133 { KE_KEY, 0x02, { KEY_BRIGHTNESSUP } },
134 { KE_KEY, 0x03, { KEY_BRIGHTNESSDOWN } },
135 { KE_KEY, 0x20e6, { KEY_PROG1 } },
136 { KE_KEY, 0x20e8, { KEY_MEDIA } },
137 { KE_KEY, 0x2142, { KEY_MEDIA } },
138 { KE_KEY, 0x213b, { KEY_INFO } },
139 { KE_KEY, 0x2169, { KEY_DIRECTION } },
140 { KE_KEY, 0x231b, { KEY_HELP } },
141 { KE_END, 0 }
109}; 142};
110 143
111static struct input_dev *hp_wmi_input_dev; 144static struct input_dev *hp_wmi_input_dev;
@@ -115,6 +148,15 @@ static struct rfkill *wifi_rfkill;
115static struct rfkill *bluetooth_rfkill; 148static struct rfkill *bluetooth_rfkill;
116static struct rfkill *wwan_rfkill; 149static struct rfkill *wwan_rfkill;
117 150
151struct rfkill2_device {
152 u8 id;
153 int num;
154 struct rfkill *rfkill;
155};
156
157static int rfkill2_count;
158static struct rfkill2_device rfkill2[HPWMI_MAX_RFKILL2_DEVICES];
159
118static const struct dev_pm_ops hp_wmi_pm_ops = { 160static const struct dev_pm_ops hp_wmi_pm_ops = {
119 .resume = hp_wmi_resume_handler, 161 .resume = hp_wmi_resume_handler,
120 .restore = hp_wmi_resume_handler, 162 .restore = hp_wmi_resume_handler,
@@ -136,7 +178,8 @@ static struct platform_driver hp_wmi_driver = {
136 * query: The commandtype -> What should be queried 178 * query: The commandtype -> What should be queried
137 * write: The command -> 0 read, 1 write, 3 ODM specific 179 * write: The command -> 0 read, 1 write, 3 ODM specific
138 * buffer: Buffer used as input and/or output 180 * buffer: Buffer used as input and/or output
139 * buffersize: Size of buffer 181 * insize: Size of input buffer
182 * outsize: Size of output buffer
140 * 183 *
141 * returns zero on success 184 * returns zero on success
142 * an HP WMI query specific error code (which is positive) 185 * an HP WMI query specific error code (which is positive)
@@ -147,25 +190,30 @@ static struct platform_driver hp_wmi_driver = {
147 * size. E.g. Battery info query (0x7) is defined to have 1 byte input 190 * size. E.g. Battery info query (0x7) is defined to have 1 byte input
148 * and 128 byte output. The caller would do: 191 * and 128 byte output. The caller would do:
149 * buffer = kzalloc(128, GFP_KERNEL); 192 * buffer = kzalloc(128, GFP_KERNEL);
150 * ret = hp_wmi_perform_query(0x7, 0, buffer, 128) 193 * ret = hp_wmi_perform_query(0x7, 0, buffer, 1, 128)
151 */ 194 */
152static int hp_wmi_perform_query(int query, int write, u32 *buffer, 195static int hp_wmi_perform_query(int query, int write, void *buffer,
153 int buffersize) 196 int insize, int outsize)
154{ 197{
155 struct bios_return bios_return; 198 struct bios_return *bios_return;
156 acpi_status status; 199 int actual_outsize;
157 union acpi_object *obj; 200 union acpi_object *obj;
158 struct bios_args args = { 201 struct bios_args args = {
159 .signature = 0x55434553, 202 .signature = 0x55434553,
160 .command = write ? 0x2 : 0x1, 203 .command = write ? 0x2 : 0x1,
161 .commandtype = query, 204 .commandtype = query,
162 .datasize = buffersize, 205 .datasize = insize,
163 .data = *buffer, 206 .data = 0,
164 }; 207 };
165 struct acpi_buffer input = { sizeof(struct bios_args), &args }; 208 struct acpi_buffer input = { sizeof(struct bios_args), &args };
166 struct acpi_buffer output = { ACPI_ALLOCATE_BUFFER, NULL }; 209 struct acpi_buffer output = { ACPI_ALLOCATE_BUFFER, NULL };
210 u32 rc;
211
212 if (WARN_ON(insize > sizeof(args.data)))
213 return -EINVAL;
214 memcpy(&args.data, buffer, insize);
167 215
168 status = wmi_evaluate_method(HPWMI_BIOS_GUID, 0, 0x3, &input, &output); 216 wmi_evaluate_method(HPWMI_BIOS_GUID, 0, 0x3, &input, &output);
169 217
170 obj = output.pointer; 218 obj = output.pointer;
171 219
@@ -176,9 +224,26 @@ static int hp_wmi_perform_query(int query, int write, u32 *buffer,
176 return -EINVAL; 224 return -EINVAL;
177 } 225 }
178 226
179 bios_return = *((struct bios_return *)obj->buffer.pointer); 227 bios_return = (struct bios_return *)obj->buffer.pointer;
228 rc = bios_return->return_code;
229
230 if (rc) {
231 if (rc != HPWMI_RET_UNKNOWN_CMDTYPE)
232 pr_warn("query 0x%x returned error 0x%x\n", query, rc);
233 kfree(obj);
234 return rc;
235 }
236
237 if (!outsize) {
238 /* ignore output data */
239 kfree(obj);
240 return 0;
241 }
180 242
181 memcpy(buffer, &bios_return.value, sizeof(bios_return.value)); 243 actual_outsize = min(outsize, (int)(obj->buffer.length - sizeof(*bios_return)));
244 memcpy(buffer, obj->buffer.pointer + sizeof(*bios_return), actual_outsize);
245 memset(buffer + actual_outsize, 0, outsize - actual_outsize);
246 kfree(obj);
182 return 0; 247 return 0;
183} 248}
184 249
@@ -186,7 +251,7 @@ static int hp_wmi_display_state(void)
186{ 251{
187 int state = 0; 252 int state = 0;
188 int ret = hp_wmi_perform_query(HPWMI_DISPLAY_QUERY, 0, &state, 253 int ret = hp_wmi_perform_query(HPWMI_DISPLAY_QUERY, 0, &state,
189 sizeof(state)); 254 sizeof(state), sizeof(state));
190 if (ret) 255 if (ret)
191 return -EINVAL; 256 return -EINVAL;
192 return state; 257 return state;
@@ -196,7 +261,7 @@ static int hp_wmi_hddtemp_state(void)
196{ 261{
197 int state = 0; 262 int state = 0;
198 int ret = hp_wmi_perform_query(HPWMI_HDDTEMP_QUERY, 0, &state, 263 int ret = hp_wmi_perform_query(HPWMI_HDDTEMP_QUERY, 0, &state,
199 sizeof(state)); 264 sizeof(state), sizeof(state));
200 if (ret) 265 if (ret)
201 return -EINVAL; 266 return -EINVAL;
202 return state; 267 return state;
@@ -206,7 +271,7 @@ static int hp_wmi_als_state(void)
206{ 271{
207 int state = 0; 272 int state = 0;
208 int ret = hp_wmi_perform_query(HPWMI_ALS_QUERY, 0, &state, 273 int ret = hp_wmi_perform_query(HPWMI_ALS_QUERY, 0, &state,
209 sizeof(state)); 274 sizeof(state), sizeof(state));
210 if (ret) 275 if (ret)
211 return -EINVAL; 276 return -EINVAL;
212 return state; 277 return state;
@@ -216,7 +281,7 @@ static int hp_wmi_dock_state(void)
216{ 281{
217 int state = 0; 282 int state = 0;
218 int ret = hp_wmi_perform_query(HPWMI_HARDWARE_QUERY, 0, &state, 283 int ret = hp_wmi_perform_query(HPWMI_HARDWARE_QUERY, 0, &state,
219 sizeof(state)); 284 sizeof(state), sizeof(state));
220 285
221 if (ret) 286 if (ret)
222 return -EINVAL; 287 return -EINVAL;
@@ -228,7 +293,7 @@ static int hp_wmi_tablet_state(void)
228{ 293{
229 int state = 0; 294 int state = 0;
230 int ret = hp_wmi_perform_query(HPWMI_HARDWARE_QUERY, 0, &state, 295 int ret = hp_wmi_perform_query(HPWMI_HARDWARE_QUERY, 0, &state,
231 sizeof(state)); 296 sizeof(state), sizeof(state));
232 if (ret) 297 if (ret)
233 return ret; 298 return ret;
234 299
@@ -242,7 +307,7 @@ static int hp_wmi_set_block(void *data, bool blocked)
242 int ret; 307 int ret;
243 308
244 ret = hp_wmi_perform_query(HPWMI_WIRELESS_QUERY, 1, 309 ret = hp_wmi_perform_query(HPWMI_WIRELESS_QUERY, 1,
245 &query, sizeof(query)); 310 &query, sizeof(query), 0);
246 if (ret) 311 if (ret)
247 return -EINVAL; 312 return -EINVAL;
248 return 0; 313 return 0;
@@ -257,7 +322,8 @@ static bool hp_wmi_get_sw_state(enum hp_wmi_radio r)
257 int wireless = 0; 322 int wireless = 0;
258 int mask; 323 int mask;
259 hp_wmi_perform_query(HPWMI_WIRELESS_QUERY, 0, 324 hp_wmi_perform_query(HPWMI_WIRELESS_QUERY, 0,
260 &wireless, sizeof(wireless)); 325 &wireless, sizeof(wireless),
326 sizeof(wireless));
261 /* TBD: Pass error */ 327 /* TBD: Pass error */
262 328
263 mask = 0x200 << (r * 8); 329 mask = 0x200 << (r * 8);
@@ -273,7 +339,8 @@ static bool hp_wmi_get_hw_state(enum hp_wmi_radio r)
273 int wireless = 0; 339 int wireless = 0;
274 int mask; 340 int mask;
275 hp_wmi_perform_query(HPWMI_WIRELESS_QUERY, 0, 341 hp_wmi_perform_query(HPWMI_WIRELESS_QUERY, 0,
276 &wireless, sizeof(wireless)); 342 &wireless, sizeof(wireless),
343 sizeof(wireless));
277 /* TBD: Pass error */ 344 /* TBD: Pass error */
278 345
279 mask = 0x800 << (r * 8); 346 mask = 0x800 << (r * 8);
@@ -284,6 +351,50 @@ static bool hp_wmi_get_hw_state(enum hp_wmi_radio r)
284 return true; 351 return true;
285} 352}
286 353
354static int hp_wmi_rfkill2_set_block(void *data, bool blocked)
355{
356 int rfkill_id = (int)(long)data;
357 char buffer[4] = { 0x01, 0x00, rfkill_id, !blocked };
358
359 if (hp_wmi_perform_query(HPWMI_WIRELESS2_QUERY, 1,
360 buffer, sizeof(buffer), 0))
361 return -EINVAL;
362 return 0;
363}
364
365static const struct rfkill_ops hp_wmi_rfkill2_ops = {
366 .set_block = hp_wmi_rfkill2_set_block,
367};
368
369static int hp_wmi_rfkill2_refresh(void)
370{
371 int err, i;
372 struct bios_rfkill2_state state;
373
374 err = hp_wmi_perform_query(HPWMI_WIRELESS2_QUERY, 0, &state,
375 0, sizeof(state));
376 if (err)
377 return err;
378
379 for (i = 0; i < rfkill2_count; i++) {
380 int num = rfkill2[i].num;
381 struct bios_rfkill2_device_state *devstate;
382 devstate = &state.device[num];
383
384 if (num >= state.count ||
385 devstate->rfkill_id != rfkill2[i].id) {
386 pr_warn("power configuration of the wireless devices unexpectedly changed\n");
387 continue;
388 }
389
390 rfkill_set_states(rfkill2[i].rfkill,
391 IS_SWBLOCKED(devstate->power),
392 IS_HWBLOCKED(devstate->power));
393 }
394
395 return 0;
396}
397
287static ssize_t show_display(struct device *dev, struct device_attribute *attr, 398static ssize_t show_display(struct device *dev, struct device_attribute *attr,
288 char *buf) 399 char *buf)
289{ 400{
@@ -334,7 +445,7 @@ static ssize_t set_als(struct device *dev, struct device_attribute *attr,
334{ 445{
335 u32 tmp = simple_strtoul(buf, NULL, 10); 446 u32 tmp = simple_strtoul(buf, NULL, 10);
336 int ret = hp_wmi_perform_query(HPWMI_ALS_QUERY, 1, &tmp, 447 int ret = hp_wmi_perform_query(HPWMI_ALS_QUERY, 1, &tmp,
337 sizeof(tmp)); 448 sizeof(tmp), sizeof(tmp));
338 if (ret) 449 if (ret)
339 return -EINVAL; 450 return -EINVAL;
340 451
@@ -347,64 +458,9 @@ static DEVICE_ATTR(als, S_IRUGO | S_IWUSR, show_als, set_als);
347static DEVICE_ATTR(dock, S_IRUGO, show_dock, NULL); 458static DEVICE_ATTR(dock, S_IRUGO, show_dock, NULL);
348static DEVICE_ATTR(tablet, S_IRUGO, show_tablet, NULL); 459static DEVICE_ATTR(tablet, S_IRUGO, show_tablet, NULL);
349 460
350static struct key_entry *hp_wmi_get_entry_by_scancode(unsigned int code)
351{
352 struct key_entry *key;
353
354 for (key = hp_wmi_keymap; key->type != KE_END; key++)
355 if (code == key->code)
356 return key;
357
358 return NULL;
359}
360
361static struct key_entry *hp_wmi_get_entry_by_keycode(unsigned int keycode)
362{
363 struct key_entry *key;
364
365 for (key = hp_wmi_keymap; key->type != KE_END; key++)
366 if (key->type == KE_KEY && keycode == key->keycode)
367 return key;
368
369 return NULL;
370}
371
372static int hp_wmi_getkeycode(struct input_dev *dev,
373 unsigned int scancode, unsigned int *keycode)
374{
375 struct key_entry *key = hp_wmi_get_entry_by_scancode(scancode);
376
377 if (key && key->type == KE_KEY) {
378 *keycode = key->keycode;
379 return 0;
380 }
381
382 return -EINVAL;
383}
384
385static int hp_wmi_setkeycode(struct input_dev *dev,
386 unsigned int scancode, unsigned int keycode)
387{
388 struct key_entry *key;
389 unsigned int old_keycode;
390
391 key = hp_wmi_get_entry_by_scancode(scancode);
392 if (key && key->type == KE_KEY) {
393 old_keycode = key->keycode;
394 key->keycode = keycode;
395 set_bit(keycode, dev->keybit);
396 if (!hp_wmi_get_entry_by_keycode(old_keycode))
397 clear_bit(old_keycode, dev->keybit);
398 return 0;
399 }
400
401 return -EINVAL;
402}
403
404static void hp_wmi_notify(u32 value, void *context) 461static void hp_wmi_notify(u32 value, void *context)
405{ 462{
406 struct acpi_buffer response = { ACPI_ALLOCATE_BUFFER, NULL }; 463 struct acpi_buffer response = { ACPI_ALLOCATE_BUFFER, NULL };
407 static struct key_entry *key;
408 union acpi_object *obj; 464 union acpi_object *obj;
409 u32 event_id, event_data; 465 u32 event_id, event_data;
410 int key_code = 0, ret; 466 int key_code = 0, ret;
@@ -413,7 +469,7 @@ static void hp_wmi_notify(u32 value, void *context)
413 469
414 status = wmi_get_event_data(value, &response); 470 status = wmi_get_event_data(value, &response);
415 if (status != AE_OK) { 471 if (status != AE_OK) {
416 printk(KERN_INFO PREFIX "bad event status 0x%x\n", status); 472 pr_info("bad event status 0x%x\n", status);
417 return; 473 return;
418 } 474 }
419 475
@@ -422,8 +478,7 @@ static void hp_wmi_notify(u32 value, void *context)
422 if (!obj) 478 if (!obj)
423 return; 479 return;
424 if (obj->type != ACPI_TYPE_BUFFER) { 480 if (obj->type != ACPI_TYPE_BUFFER) {
425 printk(KERN_INFO "hp-wmi: Unknown response received %d\n", 481 pr_info("Unknown response received %d\n", obj->type);
426 obj->type);
427 kfree(obj); 482 kfree(obj);
428 return; 483 return;
429 } 484 }
@@ -440,8 +495,7 @@ static void hp_wmi_notify(u32 value, void *context)
440 event_id = *location; 495 event_id = *location;
441 event_data = *(location + 2); 496 event_data = *(location + 2);
442 } else { 497 } else {
443 printk(KERN_INFO "hp-wmi: Unknown buffer length %d\n", 498 pr_info("Unknown buffer length %d\n", obj->buffer.length);
444 obj->buffer.length);
445 kfree(obj); 499 kfree(obj);
446 return; 500 return;
447 } 501 }
@@ -462,26 +516,21 @@ static void hp_wmi_notify(u32 value, void *context)
462 case HPWMI_BEZEL_BUTTON: 516 case HPWMI_BEZEL_BUTTON:
463 ret = hp_wmi_perform_query(HPWMI_HOTKEY_QUERY, 0, 517 ret = hp_wmi_perform_query(HPWMI_HOTKEY_QUERY, 0,
464 &key_code, 518 &key_code,
519 sizeof(key_code),
465 sizeof(key_code)); 520 sizeof(key_code));
466 if (ret) 521 if (ret)
467 break; 522 break;
468 key = hp_wmi_get_entry_by_scancode(key_code); 523
469 if (key) { 524 if (!sparse_keymap_report_event(hp_wmi_input_dev,
470 switch (key->type) { 525 key_code, 1, true))
471 case KE_KEY: 526 pr_info("Unknown key code - 0x%x\n", key_code);
472 input_report_key(hp_wmi_input_dev,
473 key->keycode, 1);
474 input_sync(hp_wmi_input_dev);
475 input_report_key(hp_wmi_input_dev,
476 key->keycode, 0);
477 input_sync(hp_wmi_input_dev);
478 break;
479 }
480 } else
481 printk(KERN_INFO PREFIX "Unknown key code - 0x%x\n",
482 key_code);
483 break; 527 break;
484 case HPWMI_WIRELESS: 528 case HPWMI_WIRELESS:
529 if (rfkill2_count) {
530 hp_wmi_rfkill2_refresh();
531 break;
532 }
533
485 if (wifi_rfkill) 534 if (wifi_rfkill)
486 rfkill_set_states(wifi_rfkill, 535 rfkill_set_states(wifi_rfkill,
487 hp_wmi_get_sw_state(HPWMI_WIFI), 536 hp_wmi_get_sw_state(HPWMI_WIFI),
@@ -496,21 +545,19 @@ static void hp_wmi_notify(u32 value, void *context)
496 hp_wmi_get_hw_state(HPWMI_WWAN)); 545 hp_wmi_get_hw_state(HPWMI_WWAN));
497 break; 546 break;
498 case HPWMI_CPU_BATTERY_THROTTLE: 547 case HPWMI_CPU_BATTERY_THROTTLE:
499 printk(KERN_INFO PREFIX UNIMP "CPU throttle because of 3 Cell" 548 pr_info("Unimplemented CPU throttle because of 3 Cell battery event detected\n");
500 " battery event detected\n");
501 break; 549 break;
502 case HPWMI_LOCK_SWITCH: 550 case HPWMI_LOCK_SWITCH:
503 break; 551 break;
504 default: 552 default:
505 printk(KERN_INFO PREFIX "Unknown event_id - %d - 0x%x\n", 553 pr_info("Unknown event_id - %d - 0x%x\n", event_id, event_data);
506 event_id, event_data);
507 break; 554 break;
508 } 555 }
509} 556}
510 557
511static int __init hp_wmi_input_setup(void) 558static int __init hp_wmi_input_setup(void)
512{ 559{
513 struct key_entry *key; 560 acpi_status status;
514 int err; 561 int err;
515 562
516 hp_wmi_input_dev = input_allocate_device(); 563 hp_wmi_input_dev = input_allocate_device();
@@ -520,21 +567,14 @@ static int __init hp_wmi_input_setup(void)
520 hp_wmi_input_dev->name = "HP WMI hotkeys"; 567 hp_wmi_input_dev->name = "HP WMI hotkeys";
521 hp_wmi_input_dev->phys = "wmi/input0"; 568 hp_wmi_input_dev->phys = "wmi/input0";
522 hp_wmi_input_dev->id.bustype = BUS_HOST; 569 hp_wmi_input_dev->id.bustype = BUS_HOST;
523 hp_wmi_input_dev->getkeycode = hp_wmi_getkeycode;
524 hp_wmi_input_dev->setkeycode = hp_wmi_setkeycode;
525
526 for (key = hp_wmi_keymap; key->type != KE_END; key++) {
527 switch (key->type) {
528 case KE_KEY:
529 set_bit(EV_KEY, hp_wmi_input_dev->evbit);
530 set_bit(key->keycode, hp_wmi_input_dev->keybit);
531 break;
532 }
533 }
534 570
535 set_bit(EV_SW, hp_wmi_input_dev->evbit); 571 __set_bit(EV_SW, hp_wmi_input_dev->evbit);
536 set_bit(SW_DOCK, hp_wmi_input_dev->swbit); 572 __set_bit(SW_DOCK, hp_wmi_input_dev->swbit);
537 set_bit(SW_TABLET_MODE, hp_wmi_input_dev->swbit); 573 __set_bit(SW_TABLET_MODE, hp_wmi_input_dev->swbit);
574
575 err = sparse_keymap_setup(hp_wmi_input_dev, hp_wmi_keymap, NULL);
576 if (err)
577 goto err_free_dev;
538 578
539 /* Set initial hardware state */ 579 /* Set initial hardware state */
540 input_report_switch(hp_wmi_input_dev, SW_DOCK, hp_wmi_dock_state()); 580 input_report_switch(hp_wmi_input_dev, SW_DOCK, hp_wmi_dock_state());
@@ -542,14 +582,32 @@ static int __init hp_wmi_input_setup(void)
542 hp_wmi_tablet_state()); 582 hp_wmi_tablet_state());
543 input_sync(hp_wmi_input_dev); 583 input_sync(hp_wmi_input_dev);
544 584
545 err = input_register_device(hp_wmi_input_dev); 585 status = wmi_install_notify_handler(HPWMI_EVENT_GUID, hp_wmi_notify, NULL);
546 586 if (ACPI_FAILURE(status)) {
547 if (err) { 587 err = -EIO;
548 input_free_device(hp_wmi_input_dev); 588 goto err_free_keymap;
549 return err;
550 } 589 }
551 590
591 err = input_register_device(hp_wmi_input_dev);
592 if (err)
593 goto err_uninstall_notifier;
594
552 return 0; 595 return 0;
596
597 err_uninstall_notifier:
598 wmi_remove_notify_handler(HPWMI_EVENT_GUID);
599 err_free_keymap:
600 sparse_keymap_free(hp_wmi_input_dev);
601 err_free_dev:
602 input_free_device(hp_wmi_input_dev);
603 return err;
604}
605
606static void hp_wmi_input_destroy(void)
607{
608 wmi_remove_notify_handler(HPWMI_EVENT_GUID);
609 sparse_keymap_free(hp_wmi_input_dev);
610 input_unregister_device(hp_wmi_input_dev);
553} 611}
554 612
555static void cleanup_sysfs(struct platform_device *device) 613static void cleanup_sysfs(struct platform_device *device)
@@ -561,32 +619,16 @@ static void cleanup_sysfs(struct platform_device *device)
561 device_remove_file(&device->dev, &dev_attr_tablet); 619 device_remove_file(&device->dev, &dev_attr_tablet);
562} 620}
563 621
564static int __devinit hp_wmi_bios_setup(struct platform_device *device) 622static int __devinit hp_wmi_rfkill_setup(struct platform_device *device)
565{ 623{
566 int err; 624 int err;
567 int wireless = 0; 625 int wireless = 0;
568 626
569 err = hp_wmi_perform_query(HPWMI_WIRELESS_QUERY, 0, &wireless, 627 err = hp_wmi_perform_query(HPWMI_WIRELESS_QUERY, 0, &wireless,
570 sizeof(wireless)); 628 sizeof(wireless), sizeof(wireless));
571 if (err) 629 if (err)
572 return err; 630 return err;
573 631
574 err = device_create_file(&device->dev, &dev_attr_display);
575 if (err)
576 goto add_sysfs_error;
577 err = device_create_file(&device->dev, &dev_attr_hddtemp);
578 if (err)
579 goto add_sysfs_error;
580 err = device_create_file(&device->dev, &dev_attr_als);
581 if (err)
582 goto add_sysfs_error;
583 err = device_create_file(&device->dev, &dev_attr_dock);
584 if (err)
585 goto add_sysfs_error;
586 err = device_create_file(&device->dev, &dev_attr_tablet);
587 if (err)
588 goto add_sysfs_error;
589
590 if (wireless & 0x1) { 632 if (wireless & 0x1) {
591 wifi_rfkill = rfkill_alloc("hp-wifi", &device->dev, 633 wifi_rfkill = rfkill_alloc("hp-wifi", &device->dev,
592 RFKILL_TYPE_WLAN, 634 RFKILL_TYPE_WLAN,
@@ -632,14 +674,130 @@ static int __devinit hp_wmi_bios_setup(struct platform_device *device)
632 return 0; 674 return 0;
633register_wwan_err: 675register_wwan_err:
634 rfkill_destroy(wwan_rfkill); 676 rfkill_destroy(wwan_rfkill);
677 wwan_rfkill = NULL;
635 if (bluetooth_rfkill) 678 if (bluetooth_rfkill)
636 rfkill_unregister(bluetooth_rfkill); 679 rfkill_unregister(bluetooth_rfkill);
637register_bluetooth_error: 680register_bluetooth_error:
638 rfkill_destroy(bluetooth_rfkill); 681 rfkill_destroy(bluetooth_rfkill);
682 bluetooth_rfkill = NULL;
639 if (wifi_rfkill) 683 if (wifi_rfkill)
640 rfkill_unregister(wifi_rfkill); 684 rfkill_unregister(wifi_rfkill);
641register_wifi_error: 685register_wifi_error:
642 rfkill_destroy(wifi_rfkill); 686 rfkill_destroy(wifi_rfkill);
687 wifi_rfkill = NULL;
688 return err;
689}
690
691static int __devinit hp_wmi_rfkill2_setup(struct platform_device *device)
692{
693 int err, i;
694 struct bios_rfkill2_state state;
695 err = hp_wmi_perform_query(HPWMI_WIRELESS2_QUERY, 0, &state,
696 0, sizeof(state));
697 if (err)
698 return err;
699
700 if (state.count > HPWMI_MAX_RFKILL2_DEVICES) {
701 pr_warn("unable to parse 0x1b query output\n");
702 return -EINVAL;
703 }
704
705 for (i = 0; i < state.count; i++) {
706 struct rfkill *rfkill;
707 enum rfkill_type type;
708 char *name;
709 switch (state.device[i].radio_type) {
710 case HPWMI_WIFI:
711 type = RFKILL_TYPE_WLAN;
712 name = "hp-wifi";
713 break;
714 case HPWMI_BLUETOOTH:
715 type = RFKILL_TYPE_BLUETOOTH;
716 name = "hp-bluetooth";
717 break;
718 case HPWMI_WWAN:
719 type = RFKILL_TYPE_WWAN;
720 name = "hp-wwan";
721 break;
722 default:
723 pr_warn("unknown device type 0x%x\n",
724 state.device[i].radio_type);
725 continue;
726 }
727
728 if (!state.device[i].vendor_id) {
729 pr_warn("zero device %d while %d reported\n",
730 i, state.count);
731 continue;
732 }
733
734 rfkill = rfkill_alloc(name, &device->dev, type,
735 &hp_wmi_rfkill2_ops, (void *)(long)i);
736 if (!rfkill) {
737 err = -ENOMEM;
738 goto fail;
739 }
740
741 rfkill2[rfkill2_count].id = state.device[i].rfkill_id;
742 rfkill2[rfkill2_count].num = i;
743 rfkill2[rfkill2_count].rfkill = rfkill;
744
745 rfkill_init_sw_state(rfkill,
746 IS_SWBLOCKED(state.device[i].power));
747 rfkill_set_hw_state(rfkill,
748 IS_HWBLOCKED(state.device[i].power));
749
750 if (!(state.device[i].power & HPWMI_POWER_BIOS))
751 pr_info("device %s blocked by BIOS\n", name);
752
753 err = rfkill_register(rfkill);
754 if (err) {
755 rfkill_destroy(rfkill);
756 goto fail;
757 }
758
759 rfkill2_count++;
760 }
761
762 return 0;
763fail:
764 for (; rfkill2_count > 0; rfkill2_count--) {
765 rfkill_unregister(rfkill2[rfkill2_count - 1].rfkill);
766 rfkill_destroy(rfkill2[rfkill2_count - 1].rfkill);
767 }
768 return err;
769}
770
771static int __devinit hp_wmi_bios_setup(struct platform_device *device)
772{
773 int err;
774
775 /* clear detected rfkill devices */
776 wifi_rfkill = NULL;
777 bluetooth_rfkill = NULL;
778 wwan_rfkill = NULL;
779 rfkill2_count = 0;
780
781 if (hp_wmi_rfkill_setup(device))
782 hp_wmi_rfkill2_setup(device);
783
784 err = device_create_file(&device->dev, &dev_attr_display);
785 if (err)
786 goto add_sysfs_error;
787 err = device_create_file(&device->dev, &dev_attr_hddtemp);
788 if (err)
789 goto add_sysfs_error;
790 err = device_create_file(&device->dev, &dev_attr_als);
791 if (err)
792 goto add_sysfs_error;
793 err = device_create_file(&device->dev, &dev_attr_dock);
794 if (err)
795 goto add_sysfs_error;
796 err = device_create_file(&device->dev, &dev_attr_tablet);
797 if (err)
798 goto add_sysfs_error;
799 return 0;
800
643add_sysfs_error: 801add_sysfs_error:
644 cleanup_sysfs(device); 802 cleanup_sysfs(device);
645 return err; 803 return err;
@@ -647,8 +805,14 @@ add_sysfs_error:
647 805
648static int __exit hp_wmi_bios_remove(struct platform_device *device) 806static int __exit hp_wmi_bios_remove(struct platform_device *device)
649{ 807{
808 int i;
650 cleanup_sysfs(device); 809 cleanup_sysfs(device);
651 810
811 for (i = 0; i < rfkill2_count; i++) {
812 rfkill_unregister(rfkill2[i].rfkill);
813 rfkill_destroy(rfkill2[i].rfkill);
814 }
815
652 if (wifi_rfkill) { 816 if (wifi_rfkill) {
653 rfkill_unregister(wifi_rfkill); 817 rfkill_unregister(wifi_rfkill);
654 rfkill_destroy(wifi_rfkill); 818 rfkill_destroy(wifi_rfkill);
@@ -681,6 +845,9 @@ static int hp_wmi_resume_handler(struct device *device)
681 input_sync(hp_wmi_input_dev); 845 input_sync(hp_wmi_input_dev);
682 } 846 }
683 847
848 if (rfkill2_count)
849 hp_wmi_rfkill2_refresh();
850
684 if (wifi_rfkill) 851 if (wifi_rfkill)
685 rfkill_set_states(wifi_rfkill, 852 rfkill_set_states(wifi_rfkill,
686 hp_wmi_get_sw_state(HPWMI_WIFI), 853 hp_wmi_get_sw_state(HPWMI_WIFI),
@@ -704,15 +871,9 @@ static int __init hp_wmi_init(void)
704 int bios_capable = wmi_has_guid(HPWMI_BIOS_GUID); 871 int bios_capable = wmi_has_guid(HPWMI_BIOS_GUID);
705 872
706 if (event_capable) { 873 if (event_capable) {
707 err = wmi_install_notify_handler(HPWMI_EVENT_GUID,
708 hp_wmi_notify, NULL);
709 if (ACPI_FAILURE(err))
710 return -EINVAL;
711 err = hp_wmi_input_setup(); 874 err = hp_wmi_input_setup();
712 if (err) { 875 if (err)
713 wmi_remove_notify_handler(HPWMI_EVENT_GUID);
714 return err; 876 return err;
715 }
716 } 877 }
717 878
718 if (bios_capable) { 879 if (bios_capable) {
@@ -739,20 +900,17 @@ err_device_add:
739err_device_alloc: 900err_device_alloc:
740 platform_driver_unregister(&hp_wmi_driver); 901 platform_driver_unregister(&hp_wmi_driver);
741err_driver_reg: 902err_driver_reg:
742 if (wmi_has_guid(HPWMI_EVENT_GUID)) { 903 if (event_capable)
743 input_unregister_device(hp_wmi_input_dev); 904 hp_wmi_input_destroy();
744 wmi_remove_notify_handler(HPWMI_EVENT_GUID);
745 }
746 905
747 return err; 906 return err;
748} 907}
749 908
750static void __exit hp_wmi_exit(void) 909static void __exit hp_wmi_exit(void)
751{ 910{
752 if (wmi_has_guid(HPWMI_EVENT_GUID)) { 911 if (wmi_has_guid(HPWMI_EVENT_GUID))
753 wmi_remove_notify_handler(HPWMI_EVENT_GUID); 912 hp_wmi_input_destroy();
754 input_unregister_device(hp_wmi_input_dev); 913
755 }
756 if (hp_wmi_platform_dev) { 914 if (hp_wmi_platform_dev) {
757 platform_device_unregister(hp_wmi_platform_dev); 915 platform_device_unregister(hp_wmi_platform_dev);
758 platform_driver_unregister(&hp_wmi_driver); 916 platform_driver_unregister(&hp_wmi_driver);