diff options
-rw-r--r-- | drivers/platform/x86/hp-wmi.c | 87 |
1 files changed, 55 insertions, 32 deletions
diff --git a/drivers/platform/x86/hp-wmi.c b/drivers/platform/x86/hp-wmi.c index 50d9019de2be..46a7a6e8ed91 100644 --- a/drivers/platform/x86/hp-wmi.c +++ b/drivers/platform/x86/hp-wmi.c | |||
@@ -47,7 +47,7 @@ MODULE_ALIAS("wmi:5FB7F034-2C63-45e9-BE91-3D44E2C707E4"); | |||
47 | #define HPWMI_DISPLAY_QUERY 0x1 | 47 | #define HPWMI_DISPLAY_QUERY 0x1 |
48 | #define HPWMI_HDDTEMP_QUERY 0x2 | 48 | #define HPWMI_HDDTEMP_QUERY 0x2 |
49 | #define HPWMI_ALS_QUERY 0x3 | 49 | #define HPWMI_ALS_QUERY 0x3 |
50 | #define HPWMI_DOCK_QUERY 0x4 | 50 | #define HPWMI_HARDWARE_QUERY 0x4 |
51 | #define HPWMI_WIRELESS_QUERY 0x5 | 51 | #define HPWMI_WIRELESS_QUERY 0x5 |
52 | #define HPWMI_HOTKEY_QUERY 0xc | 52 | #define HPWMI_HOTKEY_QUERY 0xc |
53 | 53 | ||
@@ -75,10 +75,9 @@ struct key_entry { | |||
75 | u16 keycode; | 75 | u16 keycode; |
76 | }; | 76 | }; |
77 | 77 | ||
78 | enum { KE_KEY, KE_SW, KE_END }; | 78 | enum { KE_KEY, KE_END }; |
79 | 79 | ||
80 | static struct key_entry hp_wmi_keymap[] = { | 80 | static struct key_entry hp_wmi_keymap[] = { |
81 | {KE_SW, 0x01, SW_DOCK}, | ||
82 | {KE_KEY, 0x02, KEY_BRIGHTNESSUP}, | 81 | {KE_KEY, 0x02, KEY_BRIGHTNESSUP}, |
83 | {KE_KEY, 0x03, KEY_BRIGHTNESSDOWN}, | 82 | {KE_KEY, 0x03, KEY_BRIGHTNESSDOWN}, |
84 | {KE_KEY, 0x20e6, KEY_PROG1}, | 83 | {KE_KEY, 0x20e6, KEY_PROG1}, |
@@ -151,7 +150,22 @@ static int hp_wmi_als_state(void) | |||
151 | 150 | ||
152 | static int hp_wmi_dock_state(void) | 151 | static int hp_wmi_dock_state(void) |
153 | { | 152 | { |
154 | return hp_wmi_perform_query(HPWMI_DOCK_QUERY, 0, 0); | 153 | int ret = hp_wmi_perform_query(HPWMI_HARDWARE_QUERY, 0, 0); |
154 | |||
155 | if (ret < 0) | ||
156 | return ret; | ||
157 | |||
158 | return ret & 0x1; | ||
159 | } | ||
160 | |||
161 | static int hp_wmi_tablet_state(void) | ||
162 | { | ||
163 | int ret = hp_wmi_perform_query(HPWMI_HARDWARE_QUERY, 0, 0); | ||
164 | |||
165 | if (ret < 0) | ||
166 | return ret; | ||
167 | |||
168 | return (ret & 0x4) ? 1 : 0; | ||
155 | } | 169 | } |
156 | 170 | ||
157 | static int hp_wmi_wifi_set(void *data, enum rfkill_state state) | 171 | static int hp_wmi_wifi_set(void *data, enum rfkill_state state) |
@@ -244,6 +258,15 @@ static ssize_t show_dock(struct device *dev, struct device_attribute *attr, | |||
244 | return sprintf(buf, "%d\n", value); | 258 | return sprintf(buf, "%d\n", value); |
245 | } | 259 | } |
246 | 260 | ||
261 | static ssize_t show_tablet(struct device *dev, struct device_attribute *attr, | ||
262 | char *buf) | ||
263 | { | ||
264 | int value = hp_wmi_tablet_state(); | ||
265 | if (value < 0) | ||
266 | return -EINVAL; | ||
267 | return sprintf(buf, "%d\n", value); | ||
268 | } | ||
269 | |||
247 | static ssize_t set_als(struct device *dev, struct device_attribute *attr, | 270 | static ssize_t set_als(struct device *dev, struct device_attribute *attr, |
248 | const char *buf, size_t count) | 271 | const char *buf, size_t count) |
249 | { | 272 | { |
@@ -256,6 +279,7 @@ static DEVICE_ATTR(display, S_IRUGO, show_display, NULL); | |||
256 | static DEVICE_ATTR(hddtemp, S_IRUGO, show_hddtemp, NULL); | 279 | static DEVICE_ATTR(hddtemp, S_IRUGO, show_hddtemp, NULL); |
257 | static DEVICE_ATTR(als, S_IRUGO | S_IWUSR, show_als, set_als); | 280 | static DEVICE_ATTR(als, S_IRUGO | S_IWUSR, show_als, set_als); |
258 | static DEVICE_ATTR(dock, S_IRUGO, show_dock, NULL); | 281 | static DEVICE_ATTR(dock, S_IRUGO, show_dock, NULL); |
282 | static DEVICE_ATTR(tablet, S_IRUGO, show_tablet, NULL); | ||
259 | 283 | ||
260 | static struct key_entry *hp_wmi_get_entry_by_scancode(int code) | 284 | static struct key_entry *hp_wmi_get_entry_by_scancode(int code) |
261 | { | 285 | { |
@@ -338,13 +362,13 @@ static void hp_wmi_notify(u32 value, void *context) | |||
338 | key->keycode, 0); | 362 | key->keycode, 0); |
339 | input_sync(hp_wmi_input_dev); | 363 | input_sync(hp_wmi_input_dev); |
340 | break; | 364 | break; |
341 | case KE_SW: | ||
342 | input_report_switch(hp_wmi_input_dev, | ||
343 | key->keycode, | ||
344 | hp_wmi_dock_state()); | ||
345 | input_sync(hp_wmi_input_dev); | ||
346 | break; | ||
347 | } | 365 | } |
366 | } else if (eventcode == 0x1) { | ||
367 | input_report_switch(hp_wmi_input_dev, SW_DOCK, | ||
368 | hp_wmi_dock_state()); | ||
369 | input_report_switch(hp_wmi_input_dev, SW_TABLET_MODE, | ||
370 | hp_wmi_tablet_state()); | ||
371 | input_sync(hp_wmi_input_dev); | ||
348 | } else if (eventcode == 0x5) { | 372 | } else if (eventcode == 0x5) { |
349 | if (wifi_rfkill) | 373 | if (wifi_rfkill) |
350 | rfkill_force_state(wifi_rfkill, | 374 | rfkill_force_state(wifi_rfkill, |
@@ -381,18 +405,19 @@ static int __init hp_wmi_input_setup(void) | |||
381 | set_bit(EV_KEY, hp_wmi_input_dev->evbit); | 405 | set_bit(EV_KEY, hp_wmi_input_dev->evbit); |
382 | set_bit(key->keycode, hp_wmi_input_dev->keybit); | 406 | set_bit(key->keycode, hp_wmi_input_dev->keybit); |
383 | break; | 407 | break; |
384 | case KE_SW: | ||
385 | set_bit(EV_SW, hp_wmi_input_dev->evbit); | ||
386 | set_bit(key->keycode, hp_wmi_input_dev->swbit); | ||
387 | |||
388 | /* Set initial dock state */ | ||
389 | input_report_switch(hp_wmi_input_dev, key->keycode, | ||
390 | hp_wmi_dock_state()); | ||
391 | input_sync(hp_wmi_input_dev); | ||
392 | break; | ||
393 | } | 408 | } |
394 | } | 409 | } |
395 | 410 | ||
411 | set_bit(EV_SW, hp_wmi_input_dev->evbit); | ||
412 | set_bit(SW_DOCK, hp_wmi_input_dev->swbit); | ||
413 | set_bit(SW_TABLET_MODE, hp_wmi_input_dev->swbit); | ||
414 | |||
415 | /* Set initial hardware state */ | ||
416 | input_report_switch(hp_wmi_input_dev, SW_DOCK, hp_wmi_dock_state()); | ||
417 | input_report_switch(hp_wmi_input_dev, SW_TABLET_MODE, | ||
418 | hp_wmi_tablet_state()); | ||
419 | input_sync(hp_wmi_input_dev); | ||
420 | |||
396 | err = input_register_device(hp_wmi_input_dev); | 421 | err = input_register_device(hp_wmi_input_dev); |
397 | 422 | ||
398 | if (err) { | 423 | if (err) { |
@@ -409,6 +434,7 @@ static void cleanup_sysfs(struct platform_device *device) | |||
409 | device_remove_file(&device->dev, &dev_attr_hddtemp); | 434 | device_remove_file(&device->dev, &dev_attr_hddtemp); |
410 | device_remove_file(&device->dev, &dev_attr_als); | 435 | device_remove_file(&device->dev, &dev_attr_als); |
411 | device_remove_file(&device->dev, &dev_attr_dock); | 436 | device_remove_file(&device->dev, &dev_attr_dock); |
437 | device_remove_file(&device->dev, &dev_attr_tablet); | ||
412 | } | 438 | } |
413 | 439 | ||
414 | static int __init hp_wmi_bios_setup(struct platform_device *device) | 440 | static int __init hp_wmi_bios_setup(struct platform_device *device) |
@@ -428,6 +454,9 @@ static int __init hp_wmi_bios_setup(struct platform_device *device) | |||
428 | err = device_create_file(&device->dev, &dev_attr_dock); | 454 | err = device_create_file(&device->dev, &dev_attr_dock); |
429 | if (err) | 455 | if (err) |
430 | goto add_sysfs_error; | 456 | goto add_sysfs_error; |
457 | err = device_create_file(&device->dev, &dev_attr_tablet); | ||
458 | if (err) | ||
459 | goto add_sysfs_error; | ||
431 | 460 | ||
432 | if (wireless & 0x1) { | 461 | if (wireless & 0x1) { |
433 | wifi_rfkill = rfkill_allocate(&device->dev, RFKILL_TYPE_WLAN); | 462 | wifi_rfkill = rfkill_allocate(&device->dev, RFKILL_TYPE_WLAN); |
@@ -491,23 +520,17 @@ static int __exit hp_wmi_bios_remove(struct platform_device *device) | |||
491 | 520 | ||
492 | static int hp_wmi_resume_handler(struct platform_device *device) | 521 | static int hp_wmi_resume_handler(struct platform_device *device) |
493 | { | 522 | { |
494 | struct key_entry *key; | ||
495 | |||
496 | /* | 523 | /* |
497 | * Docking state may have changed while suspended, so trigger | 524 | * Hardware state may have changed while suspended, so trigger |
498 | * an input event for the current state. As this is a switch, | 525 | * input events for the current state. As this is a switch, |
499 | * the input layer will only actually pass it on if the state | 526 | * the input layer will only actually pass it on if the state |
500 | * changed. | 527 | * changed. |
501 | */ | 528 | */ |
502 | for (key = hp_wmi_keymap; key->type != KE_END; key++) { | 529 | |
503 | switch (key->type) { | 530 | input_report_switch(hp_wmi_input_dev, SW_DOCK, hp_wmi_dock_state()); |
504 | case KE_SW: | 531 | input_report_switch(hp_wmi_input_dev, SW_TABLET_MODE, |
505 | input_report_switch(hp_wmi_input_dev, key->keycode, | 532 | hp_wmi_tablet_state()); |
506 | hp_wmi_dock_state()); | 533 | input_sync(hp_wmi_input_dev); |
507 | input_sync(hp_wmi_input_dev); | ||
508 | break; | ||
509 | } | ||
510 | } | ||
511 | 534 | ||
512 | return 0; | 535 | return 0; |
513 | } | 536 | } |