diff options
Diffstat (limited to 'drivers/platform/x86/hp-wmi.c')
-rw-r--r-- | drivers/platform/x86/hp-wmi.c | 185 |
1 files changed, 101 insertions, 84 deletions
diff --git a/drivers/platform/x86/hp-wmi.c b/drivers/platform/x86/hp-wmi.c index 50d9019de2b..4ac2311c00a 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,61 +150,64 @@ 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); |
155 | } | ||
156 | 154 | ||
157 | static int hp_wmi_wifi_set(void *data, enum rfkill_state state) | 155 | if (ret < 0) |
158 | { | 156 | return ret; |
159 | if (state) | 157 | |
160 | return hp_wmi_perform_query(HPWMI_WIRELESS_QUERY, 1, 0x101); | 158 | return ret & 0x1; |
161 | else | ||
162 | return hp_wmi_perform_query(HPWMI_WIRELESS_QUERY, 1, 0x100); | ||
163 | } | 159 | } |
164 | 160 | ||
165 | static int hp_wmi_bluetooth_set(void *data, enum rfkill_state state) | 161 | static int hp_wmi_tablet_state(void) |
166 | { | 162 | { |
167 | if (state) | 163 | int ret = hp_wmi_perform_query(HPWMI_HARDWARE_QUERY, 0, 0); |
168 | return hp_wmi_perform_query(HPWMI_WIRELESS_QUERY, 1, 0x202); | 164 | |
169 | else | 165 | if (ret < 0) |
170 | return hp_wmi_perform_query(HPWMI_WIRELESS_QUERY, 1, 0x200); | 166 | return ret; |
167 | |||
168 | return (ret & 0x4) ? 1 : 0; | ||
171 | } | 169 | } |
172 | 170 | ||
173 | static int hp_wmi_wwan_set(void *data, enum rfkill_state state) | 171 | static int hp_wmi_set_block(void *data, bool blocked) |
174 | { | 172 | { |
175 | if (state) | 173 | unsigned long b = (unsigned long) data; |
176 | return hp_wmi_perform_query(HPWMI_WIRELESS_QUERY, 1, 0x404); | 174 | int query = BIT(b + 8) | ((!!blocked) << b); |
177 | else | 175 | |
178 | return hp_wmi_perform_query(HPWMI_WIRELESS_QUERY, 1, 0x400); | 176 | return hp_wmi_perform_query(HPWMI_WIRELESS_QUERY, 1, query); |
179 | } | 177 | } |
180 | 178 | ||
181 | static int hp_wmi_wifi_state(void) | 179 | static const struct rfkill_ops hp_wmi_rfkill_ops = { |
180 | .set_block = hp_wmi_set_block, | ||
181 | }; | ||
182 | |||
183 | static bool hp_wmi_wifi_state(void) | ||
182 | { | 184 | { |
183 | int wireless = hp_wmi_perform_query(HPWMI_WIRELESS_QUERY, 0, 0); | 185 | int wireless = hp_wmi_perform_query(HPWMI_WIRELESS_QUERY, 0, 0); |
184 | 186 | ||
185 | if (wireless & 0x100) | 187 | if (wireless & 0x100) |
186 | return RFKILL_STATE_UNBLOCKED; | 188 | return false; |
187 | else | 189 | else |
188 | return RFKILL_STATE_SOFT_BLOCKED; | 190 | return true; |
189 | } | 191 | } |
190 | 192 | ||
191 | static int hp_wmi_bluetooth_state(void) | 193 | static bool hp_wmi_bluetooth_state(void) |
192 | { | 194 | { |
193 | int wireless = hp_wmi_perform_query(HPWMI_WIRELESS_QUERY, 0, 0); | 195 | int wireless = hp_wmi_perform_query(HPWMI_WIRELESS_QUERY, 0, 0); |
194 | 196 | ||
195 | if (wireless & 0x10000) | 197 | if (wireless & 0x10000) |
196 | return RFKILL_STATE_UNBLOCKED; | 198 | return false; |
197 | else | 199 | else |
198 | return RFKILL_STATE_SOFT_BLOCKED; | 200 | return true; |
199 | } | 201 | } |
200 | 202 | ||
201 | static int hp_wmi_wwan_state(void) | 203 | static bool hp_wmi_wwan_state(void) |
202 | { | 204 | { |
203 | int wireless = hp_wmi_perform_query(HPWMI_WIRELESS_QUERY, 0, 0); | 205 | int wireless = hp_wmi_perform_query(HPWMI_WIRELESS_QUERY, 0, 0); |
204 | 206 | ||
205 | if (wireless & 0x1000000) | 207 | if (wireless & 0x1000000) |
206 | return RFKILL_STATE_UNBLOCKED; | 208 | return false; |
207 | else | 209 | else |
208 | return RFKILL_STATE_SOFT_BLOCKED; | 210 | return true; |
209 | } | 211 | } |
210 | 212 | ||
211 | static ssize_t show_display(struct device *dev, struct device_attribute *attr, | 213 | static ssize_t show_display(struct device *dev, struct device_attribute *attr, |
@@ -244,6 +246,15 @@ static ssize_t show_dock(struct device *dev, struct device_attribute *attr, | |||
244 | return sprintf(buf, "%d\n", value); | 246 | return sprintf(buf, "%d\n", value); |
245 | } | 247 | } |
246 | 248 | ||
249 | static ssize_t show_tablet(struct device *dev, struct device_attribute *attr, | ||
250 | char *buf) | ||
251 | { | ||
252 | int value = hp_wmi_tablet_state(); | ||
253 | if (value < 0) | ||
254 | return -EINVAL; | ||
255 | return sprintf(buf, "%d\n", value); | ||
256 | } | ||
257 | |||
247 | static ssize_t set_als(struct device *dev, struct device_attribute *attr, | 258 | static ssize_t set_als(struct device *dev, struct device_attribute *attr, |
248 | const char *buf, size_t count) | 259 | const char *buf, size_t count) |
249 | { | 260 | { |
@@ -256,6 +267,7 @@ static DEVICE_ATTR(display, S_IRUGO, show_display, NULL); | |||
256 | static DEVICE_ATTR(hddtemp, S_IRUGO, show_hddtemp, NULL); | 267 | static DEVICE_ATTR(hddtemp, S_IRUGO, show_hddtemp, NULL); |
257 | static DEVICE_ATTR(als, S_IRUGO | S_IWUSR, show_als, set_als); | 268 | static DEVICE_ATTR(als, S_IRUGO | S_IWUSR, show_als, set_als); |
258 | static DEVICE_ATTR(dock, S_IRUGO, show_dock, NULL); | 269 | static DEVICE_ATTR(dock, S_IRUGO, show_dock, NULL); |
270 | static DEVICE_ATTR(tablet, S_IRUGO, show_tablet, NULL); | ||
259 | 271 | ||
260 | static struct key_entry *hp_wmi_get_entry_by_scancode(int code) | 272 | static struct key_entry *hp_wmi_get_entry_by_scancode(int code) |
261 | { | 273 | { |
@@ -338,23 +350,23 @@ static void hp_wmi_notify(u32 value, void *context) | |||
338 | key->keycode, 0); | 350 | key->keycode, 0); |
339 | input_sync(hp_wmi_input_dev); | 351 | input_sync(hp_wmi_input_dev); |
340 | break; | 352 | 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 | } | 353 | } |
354 | } else if (eventcode == 0x1) { | ||
355 | input_report_switch(hp_wmi_input_dev, SW_DOCK, | ||
356 | hp_wmi_dock_state()); | ||
357 | input_report_switch(hp_wmi_input_dev, SW_TABLET_MODE, | ||
358 | hp_wmi_tablet_state()); | ||
359 | input_sync(hp_wmi_input_dev); | ||
348 | } else if (eventcode == 0x5) { | 360 | } else if (eventcode == 0x5) { |
349 | if (wifi_rfkill) | 361 | if (wifi_rfkill) |
350 | rfkill_force_state(wifi_rfkill, | 362 | rfkill_set_sw_state(wifi_rfkill, |
351 | hp_wmi_wifi_state()); | 363 | hp_wmi_wifi_state()); |
352 | if (bluetooth_rfkill) | 364 | if (bluetooth_rfkill) |
353 | rfkill_force_state(bluetooth_rfkill, | 365 | rfkill_set_sw_state(bluetooth_rfkill, |
354 | hp_wmi_bluetooth_state()); | 366 | hp_wmi_bluetooth_state()); |
355 | if (wwan_rfkill) | 367 | if (wwan_rfkill) |
356 | rfkill_force_state(wwan_rfkill, | 368 | rfkill_set_sw_state(wwan_rfkill, |
357 | hp_wmi_wwan_state()); | 369 | hp_wmi_wwan_state()); |
358 | } else | 370 | } else |
359 | printk(KERN_INFO "HP WMI: Unknown key pressed - %x\n", | 371 | printk(KERN_INFO "HP WMI: Unknown key pressed - %x\n", |
360 | eventcode); | 372 | eventcode); |
@@ -381,18 +393,19 @@ static int __init hp_wmi_input_setup(void) | |||
381 | set_bit(EV_KEY, hp_wmi_input_dev->evbit); | 393 | set_bit(EV_KEY, hp_wmi_input_dev->evbit); |
382 | set_bit(key->keycode, hp_wmi_input_dev->keybit); | 394 | set_bit(key->keycode, hp_wmi_input_dev->keybit); |
383 | break; | 395 | 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 | } | 396 | } |
394 | } | 397 | } |
395 | 398 | ||
399 | set_bit(EV_SW, hp_wmi_input_dev->evbit); | ||
400 | set_bit(SW_DOCK, hp_wmi_input_dev->swbit); | ||
401 | set_bit(SW_TABLET_MODE, hp_wmi_input_dev->swbit); | ||
402 | |||
403 | /* Set initial hardware state */ | ||
404 | input_report_switch(hp_wmi_input_dev, SW_DOCK, hp_wmi_dock_state()); | ||
405 | input_report_switch(hp_wmi_input_dev, SW_TABLET_MODE, | ||
406 | hp_wmi_tablet_state()); | ||
407 | input_sync(hp_wmi_input_dev); | ||
408 | |||
396 | err = input_register_device(hp_wmi_input_dev); | 409 | err = input_register_device(hp_wmi_input_dev); |
397 | 410 | ||
398 | if (err) { | 411 | if (err) { |
@@ -409,6 +422,7 @@ static void cleanup_sysfs(struct platform_device *device) | |||
409 | device_remove_file(&device->dev, &dev_attr_hddtemp); | 422 | device_remove_file(&device->dev, &dev_attr_hddtemp); |
410 | device_remove_file(&device->dev, &dev_attr_als); | 423 | device_remove_file(&device->dev, &dev_attr_als); |
411 | device_remove_file(&device->dev, &dev_attr_dock); | 424 | device_remove_file(&device->dev, &dev_attr_dock); |
425 | device_remove_file(&device->dev, &dev_attr_tablet); | ||
412 | } | 426 | } |
413 | 427 | ||
414 | static int __init hp_wmi_bios_setup(struct platform_device *device) | 428 | static int __init hp_wmi_bios_setup(struct platform_device *device) |
@@ -428,36 +442,35 @@ static int __init hp_wmi_bios_setup(struct platform_device *device) | |||
428 | err = device_create_file(&device->dev, &dev_attr_dock); | 442 | err = device_create_file(&device->dev, &dev_attr_dock); |
429 | if (err) | 443 | if (err) |
430 | goto add_sysfs_error; | 444 | goto add_sysfs_error; |
445 | err = device_create_file(&device->dev, &dev_attr_tablet); | ||
446 | if (err) | ||
447 | goto add_sysfs_error; | ||
431 | 448 | ||
432 | if (wireless & 0x1) { | 449 | if (wireless & 0x1) { |
433 | wifi_rfkill = rfkill_allocate(&device->dev, RFKILL_TYPE_WLAN); | 450 | wifi_rfkill = rfkill_alloc("hp-wifi", &device->dev, |
434 | wifi_rfkill->name = "hp-wifi"; | 451 | RFKILL_TYPE_WLAN, |
435 | wifi_rfkill->state = hp_wmi_wifi_state(); | 452 | &hp_wmi_rfkill_ops, |
436 | wifi_rfkill->toggle_radio = hp_wmi_wifi_set; | 453 | (void *) 0); |
437 | wifi_rfkill->user_claim_unsupported = 1; | ||
438 | err = rfkill_register(wifi_rfkill); | 454 | err = rfkill_register(wifi_rfkill); |
439 | if (err) | 455 | if (err) |
440 | goto add_sysfs_error; | 456 | goto register_wifi_error; |
441 | } | 457 | } |
442 | 458 | ||
443 | if (wireless & 0x2) { | 459 | if (wireless & 0x2) { |
444 | bluetooth_rfkill = rfkill_allocate(&device->dev, | 460 | bluetooth_rfkill = rfkill_alloc("hp-bluetooth", &device->dev, |
445 | RFKILL_TYPE_BLUETOOTH); | 461 | RFKILL_TYPE_BLUETOOTH, |
446 | bluetooth_rfkill->name = "hp-bluetooth"; | 462 | &hp_wmi_rfkill_ops, |
447 | bluetooth_rfkill->state = hp_wmi_bluetooth_state(); | 463 | (void *) 1); |
448 | bluetooth_rfkill->toggle_radio = hp_wmi_bluetooth_set; | ||
449 | bluetooth_rfkill->user_claim_unsupported = 1; | ||
450 | err = rfkill_register(bluetooth_rfkill); | 464 | err = rfkill_register(bluetooth_rfkill); |
451 | if (err) | 465 | if (err) |
452 | goto register_bluetooth_error; | 466 | goto register_bluetooth_error; |
453 | } | 467 | } |
454 | 468 | ||
455 | if (wireless & 0x4) { | 469 | if (wireless & 0x4) { |
456 | wwan_rfkill = rfkill_allocate(&device->dev, RFKILL_TYPE_WWAN); | 470 | wwan_rfkill = rfkill_alloc("hp-wwan", &device->dev, |
457 | wwan_rfkill->name = "hp-wwan"; | 471 | RFKILL_TYPE_WWAN, |
458 | wwan_rfkill->state = hp_wmi_wwan_state(); | 472 | &hp_wmi_rfkill_ops, |
459 | wwan_rfkill->toggle_radio = hp_wmi_wwan_set; | 473 | (void *) 2); |
460 | wwan_rfkill->user_claim_unsupported = 1; | ||
461 | err = rfkill_register(wwan_rfkill); | 474 | err = rfkill_register(wwan_rfkill); |
462 | if (err) | 475 | if (err) |
463 | goto register_wwan_err; | 476 | goto register_wwan_err; |
@@ -465,11 +478,15 @@ static int __init hp_wmi_bios_setup(struct platform_device *device) | |||
465 | 478 | ||
466 | return 0; | 479 | return 0; |
467 | register_wwan_err: | 480 | register_wwan_err: |
481 | rfkill_destroy(wwan_rfkill); | ||
468 | if (bluetooth_rfkill) | 482 | if (bluetooth_rfkill) |
469 | rfkill_unregister(bluetooth_rfkill); | 483 | rfkill_unregister(bluetooth_rfkill); |
470 | register_bluetooth_error: | 484 | register_bluetooth_error: |
485 | rfkill_destroy(bluetooth_rfkill); | ||
471 | if (wifi_rfkill) | 486 | if (wifi_rfkill) |
472 | rfkill_unregister(wifi_rfkill); | 487 | rfkill_unregister(wifi_rfkill); |
488 | register_wifi_error: | ||
489 | rfkill_destroy(wifi_rfkill); | ||
473 | add_sysfs_error: | 490 | add_sysfs_error: |
474 | cleanup_sysfs(device); | 491 | cleanup_sysfs(device); |
475 | return err; | 492 | return err; |
@@ -479,35 +496,35 @@ static int __exit hp_wmi_bios_remove(struct platform_device *device) | |||
479 | { | 496 | { |
480 | cleanup_sysfs(device); | 497 | cleanup_sysfs(device); |
481 | 498 | ||
482 | if (wifi_rfkill) | 499 | if (wifi_rfkill) { |
483 | rfkill_unregister(wifi_rfkill); | 500 | rfkill_unregister(wifi_rfkill); |
484 | if (bluetooth_rfkill) | 501 | rfkill_destroy(wifi_rfkill); |
502 | } | ||
503 | if (bluetooth_rfkill) { | ||
485 | rfkill_unregister(bluetooth_rfkill); | 504 | rfkill_unregister(bluetooth_rfkill); |
486 | if (wwan_rfkill) | 505 | rfkill_destroy(wifi_rfkill); |
506 | } | ||
507 | if (wwan_rfkill) { | ||
487 | rfkill_unregister(wwan_rfkill); | 508 | rfkill_unregister(wwan_rfkill); |
509 | rfkill_destroy(wwan_rfkill); | ||
510 | } | ||
488 | 511 | ||
489 | return 0; | 512 | return 0; |
490 | } | 513 | } |
491 | 514 | ||
492 | static int hp_wmi_resume_handler(struct platform_device *device) | 515 | static int hp_wmi_resume_handler(struct platform_device *device) |
493 | { | 516 | { |
494 | struct key_entry *key; | ||
495 | |||
496 | /* | 517 | /* |
497 | * Docking state may have changed while suspended, so trigger | 518 | * Hardware state may have changed while suspended, so trigger |
498 | * an input event for the current state. As this is a switch, | 519 | * input events for the current state. As this is a switch, |
499 | * the input layer will only actually pass it on if the state | 520 | * the input layer will only actually pass it on if the state |
500 | * changed. | 521 | * changed. |
501 | */ | 522 | */ |
502 | for (key = hp_wmi_keymap; key->type != KE_END; key++) { | 523 | |
503 | switch (key->type) { | 524 | input_report_switch(hp_wmi_input_dev, SW_DOCK, hp_wmi_dock_state()); |
504 | case KE_SW: | 525 | input_report_switch(hp_wmi_input_dev, SW_TABLET_MODE, |
505 | input_report_switch(hp_wmi_input_dev, key->keycode, | 526 | hp_wmi_tablet_state()); |
506 | hp_wmi_dock_state()); | 527 | input_sync(hp_wmi_input_dev); |
507 | input_sync(hp_wmi_input_dev); | ||
508 | break; | ||
509 | } | ||
510 | } | ||
511 | 528 | ||
512 | return 0; | 529 | return 0; |
513 | } | 530 | } |