Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

at v4.3 1073 lines 26 kB view raw
1/* 2 * HP WMI hotkeys 3 * 4 * Copyright (C) 2008 Red Hat <mjg@redhat.com> 5 * Copyright (C) 2010, 2011 Anssi Hannula <anssi.hannula@iki.fi> 6 * 7 * Portions based on wistron_btns.c: 8 * Copyright (C) 2005 Miloslav Trmac <mitr@volny.cz> 9 * Copyright (C) 2005 Bernhard Rosenkraenzer <bero@arklinux.org> 10 * Copyright (C) 2005 Dmitry Torokhov <dtor@mail.ru> 11 * 12 * This program is free software; you can redistribute it and/or modify 13 * it under the terms of the GNU General Public License as published by 14 * the Free Software Foundation; either version 2 of the License, or 15 * (at your option) any later version. 16 * 17 * This program is distributed in the hope that it will be useful, 18 * but WITHOUT ANY WARRANTY; without even the implied warranty of 19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 20 * GNU General Public License for more details. 21 * 22 * You should have received a copy of the GNU General Public License 23 * along with this program; if not, write to the Free Software 24 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 25 */ 26 27#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt 28 29#include <linux/kernel.h> 30#include <linux/module.h> 31#include <linux/init.h> 32#include <linux/slab.h> 33#include <linux/types.h> 34#include <linux/input.h> 35#include <linux/input/sparse-keymap.h> 36#include <linux/platform_device.h> 37#include <linux/acpi.h> 38#include <linux/rfkill.h> 39#include <linux/string.h> 40 41MODULE_AUTHOR("Matthew Garrett <mjg59@srcf.ucam.org>"); 42MODULE_DESCRIPTION("HP laptop WMI hotkeys driver"); 43MODULE_LICENSE("GPL"); 44 45MODULE_ALIAS("wmi:95F24279-4D7B-4334-9387-ACCDC67EF61C"); 46MODULE_ALIAS("wmi:5FB7F034-2C63-45e9-BE91-3D44E2C707E4"); 47 48#define HPWMI_EVENT_GUID "95F24279-4D7B-4334-9387-ACCDC67EF61C" 49#define HPWMI_BIOS_GUID "5FB7F034-2C63-45e9-BE91-3D44E2C707E4" 50 51#define HPWMI_DISPLAY_QUERY 0x1 52#define HPWMI_HDDTEMP_QUERY 0x2 53#define HPWMI_ALS_QUERY 0x3 54#define HPWMI_HARDWARE_QUERY 0x4 55#define HPWMI_WIRELESS_QUERY 0x5 56#define HPWMI_BIOS_QUERY 0x9 57#define HPWMI_FEATURE_QUERY 0xb 58#define HPWMI_HOTKEY_QUERY 0xc 59#define HPWMI_FEATURE2_QUERY 0xd 60#define HPWMI_WIRELESS2_QUERY 0x1b 61#define HPWMI_POSTCODEERROR_QUERY 0x2a 62 63enum hp_wmi_radio { 64 HPWMI_WIFI = 0, 65 HPWMI_BLUETOOTH = 1, 66 HPWMI_WWAN = 2, 67 HPWMI_GPS = 3, 68}; 69 70enum hp_wmi_event_ids { 71 HPWMI_DOCK_EVENT = 1, 72 HPWMI_PARK_HDD = 2, 73 HPWMI_SMART_ADAPTER = 3, 74 HPWMI_BEZEL_BUTTON = 4, 75 HPWMI_WIRELESS = 5, 76 HPWMI_CPU_BATTERY_THROTTLE = 6, 77 HPWMI_LOCK_SWITCH = 7, 78 HPWMI_LID_SWITCH = 8, 79 HPWMI_SCREEN_ROTATION = 9, 80 HPWMI_COOLSENSE_SYSTEM_MOBILE = 0x0A, 81 HPWMI_COOLSENSE_SYSTEM_HOT = 0x0B, 82 HPWMI_PROXIMITY_SENSOR = 0x0C, 83 HPWMI_BACKLIT_KB_BRIGHTNESS = 0x0D, 84 HPWMI_PEAKSHIFT_PERIOD = 0x0F, 85 HPWMI_BATTERY_CHARGE_PERIOD = 0x10, 86}; 87 88struct bios_args { 89 u32 signature; 90 u32 command; 91 u32 commandtype; 92 u32 datasize; 93 u32 data; 94}; 95 96struct bios_return { 97 u32 sigpass; 98 u32 return_code; 99}; 100 101enum hp_return_value { 102 HPWMI_RET_WRONG_SIGNATURE = 0x02, 103 HPWMI_RET_UNKNOWN_COMMAND = 0x03, 104 HPWMI_RET_UNKNOWN_CMDTYPE = 0x04, 105 HPWMI_RET_INVALID_PARAMETERS = 0x05, 106}; 107 108enum hp_wireless2_bits { 109 HPWMI_POWER_STATE = 0x01, 110 HPWMI_POWER_SOFT = 0x02, 111 HPWMI_POWER_BIOS = 0x04, 112 HPWMI_POWER_HARD = 0x08, 113}; 114 115#define IS_HWBLOCKED(x) ((x & (HPWMI_POWER_BIOS | HPWMI_POWER_HARD)) \ 116 != (HPWMI_POWER_BIOS | HPWMI_POWER_HARD)) 117#define IS_SWBLOCKED(x) !(x & HPWMI_POWER_SOFT) 118 119struct bios_rfkill2_device_state { 120 u8 radio_type; 121 u8 bus_type; 122 u16 vendor_id; 123 u16 product_id; 124 u16 subsys_vendor_id; 125 u16 subsys_product_id; 126 u8 rfkill_id; 127 u8 power; 128 u8 unknown[4]; 129}; 130 131/* 7 devices fit into the 128 byte buffer */ 132#define HPWMI_MAX_RFKILL2_DEVICES 7 133 134struct bios_rfkill2_state { 135 u8 unknown[7]; 136 u8 count; 137 u8 pad[8]; 138 struct bios_rfkill2_device_state device[HPWMI_MAX_RFKILL2_DEVICES]; 139}; 140 141static const struct key_entry hp_wmi_keymap[] = { 142 { KE_KEY, 0x02, { KEY_BRIGHTNESSUP } }, 143 { KE_KEY, 0x03, { KEY_BRIGHTNESSDOWN } }, 144 { KE_KEY, 0x20e6, { KEY_PROG1 } }, 145 { KE_KEY, 0x20e8, { KEY_MEDIA } }, 146 { KE_KEY, 0x2142, { KEY_MEDIA } }, 147 { KE_KEY, 0x213b, { KEY_INFO } }, 148 { KE_KEY, 0x2169, { KEY_ROTATE_DISPLAY } }, 149 { KE_KEY, 0x216a, { KEY_SETUP } }, 150 { KE_KEY, 0x231b, { KEY_HELP } }, 151 { KE_END, 0 } 152}; 153 154static struct input_dev *hp_wmi_input_dev; 155static struct platform_device *hp_wmi_platform_dev; 156 157static struct rfkill *wifi_rfkill; 158static struct rfkill *bluetooth_rfkill; 159static struct rfkill *wwan_rfkill; 160static struct rfkill *gps_rfkill; 161 162struct rfkill2_device { 163 u8 id; 164 int num; 165 struct rfkill *rfkill; 166}; 167 168static int rfkill2_count; 169static struct rfkill2_device rfkill2[HPWMI_MAX_RFKILL2_DEVICES]; 170 171/* 172 * hp_wmi_perform_query 173 * 174 * query: The commandtype -> What should be queried 175 * write: The command -> 0 read, 1 write, 3 ODM specific 176 * buffer: Buffer used as input and/or output 177 * insize: Size of input buffer 178 * outsize: Size of output buffer 179 * 180 * returns zero on success 181 * an HP WMI query specific error code (which is positive) 182 * -EINVAL if the query was not successful at all 183 * -EINVAL if the output buffer size exceeds buffersize 184 * 185 * Note: The buffersize must at least be the maximum of the input and output 186 * size. E.g. Battery info query (0x7) is defined to have 1 byte input 187 * and 128 byte output. The caller would do: 188 * buffer = kzalloc(128, GFP_KERNEL); 189 * ret = hp_wmi_perform_query(0x7, 0, buffer, 1, 128) 190 */ 191static int hp_wmi_perform_query(int query, int write, void *buffer, 192 int insize, int outsize) 193{ 194 struct bios_return *bios_return; 195 int actual_outsize; 196 union acpi_object *obj; 197 struct bios_args args = { 198 .signature = 0x55434553, 199 .command = write ? 0x2 : 0x1, 200 .commandtype = query, 201 .datasize = insize, 202 .data = 0, 203 }; 204 struct acpi_buffer input = { sizeof(struct bios_args), &args }; 205 struct acpi_buffer output = { ACPI_ALLOCATE_BUFFER, NULL }; 206 u32 rc; 207 208 if (WARN_ON(insize > sizeof(args.data))) 209 return -EINVAL; 210 memcpy(&args.data, buffer, insize); 211 212 wmi_evaluate_method(HPWMI_BIOS_GUID, 0, 0x3, &input, &output); 213 214 obj = output.pointer; 215 216 if (!obj) 217 return -EINVAL; 218 else if (obj->type != ACPI_TYPE_BUFFER) { 219 kfree(obj); 220 return -EINVAL; 221 } 222 223 bios_return = (struct bios_return *)obj->buffer.pointer; 224 rc = bios_return->return_code; 225 226 if (rc) { 227 if (rc != HPWMI_RET_UNKNOWN_CMDTYPE) 228 pr_warn("query 0x%x returned error 0x%x\n", query, rc); 229 kfree(obj); 230 return rc; 231 } 232 233 if (!outsize) { 234 /* ignore output data */ 235 kfree(obj); 236 return 0; 237 } 238 239 actual_outsize = min(outsize, (int)(obj->buffer.length - sizeof(*bios_return))); 240 memcpy(buffer, obj->buffer.pointer + sizeof(*bios_return), actual_outsize); 241 memset(buffer + actual_outsize, 0, outsize - actual_outsize); 242 kfree(obj); 243 return 0; 244} 245 246static int hp_wmi_display_state(void) 247{ 248 int state = 0; 249 int ret = hp_wmi_perform_query(HPWMI_DISPLAY_QUERY, 0, &state, 250 sizeof(state), sizeof(state)); 251 if (ret) 252 return -EINVAL; 253 return state; 254} 255 256static int hp_wmi_hddtemp_state(void) 257{ 258 int state = 0; 259 int ret = hp_wmi_perform_query(HPWMI_HDDTEMP_QUERY, 0, &state, 260 sizeof(state), sizeof(state)); 261 if (ret) 262 return -EINVAL; 263 return state; 264} 265 266static int hp_wmi_als_state(void) 267{ 268 int state = 0; 269 int ret = hp_wmi_perform_query(HPWMI_ALS_QUERY, 0, &state, 270 sizeof(state), sizeof(state)); 271 if (ret) 272 return -EINVAL; 273 return state; 274} 275 276static int hp_wmi_dock_state(void) 277{ 278 int state = 0; 279 int ret = hp_wmi_perform_query(HPWMI_HARDWARE_QUERY, 0, &state, 280 sizeof(state), sizeof(state)); 281 282 if (ret) 283 return -EINVAL; 284 285 return state & 0x1; 286} 287 288static int hp_wmi_tablet_state(void) 289{ 290 int state = 0; 291 int ret = hp_wmi_perform_query(HPWMI_HARDWARE_QUERY, 0, &state, 292 sizeof(state), sizeof(state)); 293 if (ret) 294 return ret; 295 296 return (state & 0x4) ? 1 : 0; 297} 298 299static int __init hp_wmi_bios_2008_later(void) 300{ 301 int state = 0; 302 int ret = hp_wmi_perform_query(HPWMI_FEATURE_QUERY, 0, &state, 303 sizeof(state), sizeof(state)); 304 if (!ret) 305 return 1; 306 307 return (ret == HPWMI_RET_UNKNOWN_CMDTYPE) ? 0 : -ENXIO; 308} 309 310static int __init hp_wmi_bios_2009_later(void) 311{ 312 int state = 0; 313 int ret = hp_wmi_perform_query(HPWMI_FEATURE2_QUERY, 0, &state, 314 sizeof(state), sizeof(state)); 315 if (!ret) 316 return 1; 317 318 return (ret == HPWMI_RET_UNKNOWN_CMDTYPE) ? 0 : -ENXIO; 319} 320 321static int __init hp_wmi_enable_hotkeys(void) 322{ 323 int value = 0x6e; 324 int ret = hp_wmi_perform_query(HPWMI_BIOS_QUERY, 1, &value, 325 sizeof(value), 0); 326 if (ret) 327 return -EINVAL; 328 return 0; 329} 330 331static int hp_wmi_set_block(void *data, bool blocked) 332{ 333 enum hp_wmi_radio r = (enum hp_wmi_radio) data; 334 int query = BIT(r + 8) | ((!blocked) << r); 335 int ret; 336 337 ret = hp_wmi_perform_query(HPWMI_WIRELESS_QUERY, 1, 338 &query, sizeof(query), 0); 339 if (ret) 340 return -EINVAL; 341 return 0; 342} 343 344static const struct rfkill_ops hp_wmi_rfkill_ops = { 345 .set_block = hp_wmi_set_block, 346}; 347 348static bool hp_wmi_get_sw_state(enum hp_wmi_radio r) 349{ 350 int wireless = 0; 351 int mask; 352 hp_wmi_perform_query(HPWMI_WIRELESS_QUERY, 0, 353 &wireless, sizeof(wireless), 354 sizeof(wireless)); 355 /* TBD: Pass error */ 356 357 mask = 0x200 << (r * 8); 358 359 if (wireless & mask) 360 return false; 361 else 362 return true; 363} 364 365static bool hp_wmi_get_hw_state(enum hp_wmi_radio r) 366{ 367 int wireless = 0; 368 int mask; 369 hp_wmi_perform_query(HPWMI_WIRELESS_QUERY, 0, 370 &wireless, sizeof(wireless), 371 sizeof(wireless)); 372 /* TBD: Pass error */ 373 374 mask = 0x800 << (r * 8); 375 376 if (wireless & mask) 377 return false; 378 else 379 return true; 380} 381 382static int hp_wmi_rfkill2_set_block(void *data, bool blocked) 383{ 384 int rfkill_id = (int)(long)data; 385 char buffer[4] = { 0x01, 0x00, rfkill_id, !blocked }; 386 387 if (hp_wmi_perform_query(HPWMI_WIRELESS2_QUERY, 1, 388 buffer, sizeof(buffer), 0)) 389 return -EINVAL; 390 return 0; 391} 392 393static const struct rfkill_ops hp_wmi_rfkill2_ops = { 394 .set_block = hp_wmi_rfkill2_set_block, 395}; 396 397static int hp_wmi_rfkill2_refresh(void) 398{ 399 int err, i; 400 struct bios_rfkill2_state state; 401 402 err = hp_wmi_perform_query(HPWMI_WIRELESS2_QUERY, 0, &state, 403 0, sizeof(state)); 404 if (err) 405 return err; 406 407 for (i = 0; i < rfkill2_count; i++) { 408 int num = rfkill2[i].num; 409 struct bios_rfkill2_device_state *devstate; 410 devstate = &state.device[num]; 411 412 if (num >= state.count || 413 devstate->rfkill_id != rfkill2[i].id) { 414 pr_warn("power configuration of the wireless devices unexpectedly changed\n"); 415 continue; 416 } 417 418 rfkill_set_states(rfkill2[i].rfkill, 419 IS_SWBLOCKED(devstate->power), 420 IS_HWBLOCKED(devstate->power)); 421 } 422 423 return 0; 424} 425 426static int hp_wmi_post_code_state(void) 427{ 428 int state = 0; 429 int ret = hp_wmi_perform_query(HPWMI_POSTCODEERROR_QUERY, 0, &state, 430 sizeof(state), sizeof(state)); 431 if (ret) 432 return -EINVAL; 433 return state; 434} 435 436static ssize_t show_display(struct device *dev, struct device_attribute *attr, 437 char *buf) 438{ 439 int value = hp_wmi_display_state(); 440 if (value < 0) 441 return -EINVAL; 442 return sprintf(buf, "%d\n", value); 443} 444 445static ssize_t show_hddtemp(struct device *dev, struct device_attribute *attr, 446 char *buf) 447{ 448 int value = hp_wmi_hddtemp_state(); 449 if (value < 0) 450 return -EINVAL; 451 return sprintf(buf, "%d\n", value); 452} 453 454static ssize_t show_als(struct device *dev, struct device_attribute *attr, 455 char *buf) 456{ 457 int value = hp_wmi_als_state(); 458 if (value < 0) 459 return -EINVAL; 460 return sprintf(buf, "%d\n", value); 461} 462 463static ssize_t show_dock(struct device *dev, struct device_attribute *attr, 464 char *buf) 465{ 466 int value = hp_wmi_dock_state(); 467 if (value < 0) 468 return -EINVAL; 469 return sprintf(buf, "%d\n", value); 470} 471 472static ssize_t show_tablet(struct device *dev, struct device_attribute *attr, 473 char *buf) 474{ 475 int value = hp_wmi_tablet_state(); 476 if (value < 0) 477 return -EINVAL; 478 return sprintf(buf, "%d\n", value); 479} 480 481static ssize_t show_postcode(struct device *dev, struct device_attribute *attr, 482 char *buf) 483{ 484 /* Get the POST error code of previous boot failure. */ 485 int value = hp_wmi_post_code_state(); 486 if (value < 0) 487 return -EINVAL; 488 return sprintf(buf, "0x%x\n", value); 489} 490 491static ssize_t set_als(struct device *dev, struct device_attribute *attr, 492 const char *buf, size_t count) 493{ 494 u32 tmp = simple_strtoul(buf, NULL, 10); 495 int ret = hp_wmi_perform_query(HPWMI_ALS_QUERY, 1, &tmp, 496 sizeof(tmp), sizeof(tmp)); 497 if (ret) 498 return -EINVAL; 499 500 return count; 501} 502 503static ssize_t set_postcode(struct device *dev, struct device_attribute *attr, 504 const char *buf, size_t count) 505{ 506 int ret; 507 u32 tmp; 508 long unsigned int tmp2; 509 510 ret = kstrtoul(buf, 10, &tmp2); 511 if (ret || tmp2 != 1) 512 return -EINVAL; 513 514 /* Clear the POST error code. It is kept until until cleared. */ 515 tmp = (u32) tmp2; 516 ret = hp_wmi_perform_query(HPWMI_POSTCODEERROR_QUERY, 1, &tmp, 517 sizeof(tmp), sizeof(tmp)); 518 if (ret) 519 return -EINVAL; 520 521 return count; 522} 523 524static DEVICE_ATTR(display, S_IRUGO, show_display, NULL); 525static DEVICE_ATTR(hddtemp, S_IRUGO, show_hddtemp, NULL); 526static DEVICE_ATTR(als, S_IRUGO | S_IWUSR, show_als, set_als); 527static DEVICE_ATTR(dock, S_IRUGO, show_dock, NULL); 528static DEVICE_ATTR(tablet, S_IRUGO, show_tablet, NULL); 529static DEVICE_ATTR(postcode, S_IRUGO | S_IWUSR, show_postcode, set_postcode); 530 531static void hp_wmi_notify(u32 value, void *context) 532{ 533 struct acpi_buffer response = { ACPI_ALLOCATE_BUFFER, NULL }; 534 union acpi_object *obj; 535 u32 event_id, event_data; 536 int key_code = 0, ret; 537 u32 *location; 538 acpi_status status; 539 540 status = wmi_get_event_data(value, &response); 541 if (status != AE_OK) { 542 pr_info("bad event status 0x%x\n", status); 543 return; 544 } 545 546 obj = (union acpi_object *)response.pointer; 547 548 if (!obj) 549 return; 550 if (obj->type != ACPI_TYPE_BUFFER) { 551 pr_info("Unknown response received %d\n", obj->type); 552 kfree(obj); 553 return; 554 } 555 556 /* 557 * Depending on ACPI version the concatenation of id and event data 558 * inside _WED function will result in a 8 or 16 byte buffer. 559 */ 560 location = (u32 *)obj->buffer.pointer; 561 if (obj->buffer.length == 8) { 562 event_id = *location; 563 event_data = *(location + 1); 564 } else if (obj->buffer.length == 16) { 565 event_id = *location; 566 event_data = *(location + 2); 567 } else { 568 pr_info("Unknown buffer length %d\n", obj->buffer.length); 569 kfree(obj); 570 return; 571 } 572 kfree(obj); 573 574 switch (event_id) { 575 case HPWMI_DOCK_EVENT: 576 input_report_switch(hp_wmi_input_dev, SW_DOCK, 577 hp_wmi_dock_state()); 578 input_report_switch(hp_wmi_input_dev, SW_TABLET_MODE, 579 hp_wmi_tablet_state()); 580 input_sync(hp_wmi_input_dev); 581 break; 582 case HPWMI_PARK_HDD: 583 break; 584 case HPWMI_SMART_ADAPTER: 585 break; 586 case HPWMI_BEZEL_BUTTON: 587 ret = hp_wmi_perform_query(HPWMI_HOTKEY_QUERY, 0, 588 &key_code, 589 sizeof(key_code), 590 sizeof(key_code)); 591 if (ret) 592 break; 593 594 if (!sparse_keymap_report_event(hp_wmi_input_dev, 595 key_code, 1, true)) 596 pr_info("Unknown key code - 0x%x\n", key_code); 597 break; 598 case HPWMI_WIRELESS: 599 if (rfkill2_count) { 600 hp_wmi_rfkill2_refresh(); 601 break; 602 } 603 604 if (wifi_rfkill) 605 rfkill_set_states(wifi_rfkill, 606 hp_wmi_get_sw_state(HPWMI_WIFI), 607 hp_wmi_get_hw_state(HPWMI_WIFI)); 608 if (bluetooth_rfkill) 609 rfkill_set_states(bluetooth_rfkill, 610 hp_wmi_get_sw_state(HPWMI_BLUETOOTH), 611 hp_wmi_get_hw_state(HPWMI_BLUETOOTH)); 612 if (wwan_rfkill) 613 rfkill_set_states(wwan_rfkill, 614 hp_wmi_get_sw_state(HPWMI_WWAN), 615 hp_wmi_get_hw_state(HPWMI_WWAN)); 616 if (gps_rfkill) 617 rfkill_set_states(gps_rfkill, 618 hp_wmi_get_sw_state(HPWMI_GPS), 619 hp_wmi_get_hw_state(HPWMI_GPS)); 620 break; 621 case HPWMI_CPU_BATTERY_THROTTLE: 622 pr_info("Unimplemented CPU throttle because of 3 Cell battery event detected\n"); 623 break; 624 case HPWMI_LOCK_SWITCH: 625 break; 626 case HPWMI_LID_SWITCH: 627 break; 628 case HPWMI_SCREEN_ROTATION: 629 break; 630 case HPWMI_COOLSENSE_SYSTEM_MOBILE: 631 break; 632 case HPWMI_COOLSENSE_SYSTEM_HOT: 633 break; 634 case HPWMI_PROXIMITY_SENSOR: 635 break; 636 case HPWMI_BACKLIT_KB_BRIGHTNESS: 637 break; 638 case HPWMI_PEAKSHIFT_PERIOD: 639 break; 640 case HPWMI_BATTERY_CHARGE_PERIOD: 641 break; 642 default: 643 pr_info("Unknown event_id - %d - 0x%x\n", event_id, event_data); 644 break; 645 } 646} 647 648static int __init hp_wmi_input_setup(void) 649{ 650 acpi_status status; 651 int err; 652 653 hp_wmi_input_dev = input_allocate_device(); 654 if (!hp_wmi_input_dev) 655 return -ENOMEM; 656 657 hp_wmi_input_dev->name = "HP WMI hotkeys"; 658 hp_wmi_input_dev->phys = "wmi/input0"; 659 hp_wmi_input_dev->id.bustype = BUS_HOST; 660 661 __set_bit(EV_SW, hp_wmi_input_dev->evbit); 662 __set_bit(SW_DOCK, hp_wmi_input_dev->swbit); 663 __set_bit(SW_TABLET_MODE, hp_wmi_input_dev->swbit); 664 665 err = sparse_keymap_setup(hp_wmi_input_dev, hp_wmi_keymap, NULL); 666 if (err) 667 goto err_free_dev; 668 669 /* Set initial hardware state */ 670 input_report_switch(hp_wmi_input_dev, SW_DOCK, hp_wmi_dock_state()); 671 input_report_switch(hp_wmi_input_dev, SW_TABLET_MODE, 672 hp_wmi_tablet_state()); 673 input_sync(hp_wmi_input_dev); 674 675 if (!hp_wmi_bios_2009_later() && hp_wmi_bios_2008_later()) 676 hp_wmi_enable_hotkeys(); 677 678 status = wmi_install_notify_handler(HPWMI_EVENT_GUID, hp_wmi_notify, NULL); 679 if (ACPI_FAILURE(status)) { 680 err = -EIO; 681 goto err_free_keymap; 682 } 683 684 err = input_register_device(hp_wmi_input_dev); 685 if (err) 686 goto err_uninstall_notifier; 687 688 return 0; 689 690 err_uninstall_notifier: 691 wmi_remove_notify_handler(HPWMI_EVENT_GUID); 692 err_free_keymap: 693 sparse_keymap_free(hp_wmi_input_dev); 694 err_free_dev: 695 input_free_device(hp_wmi_input_dev); 696 return err; 697} 698 699static void hp_wmi_input_destroy(void) 700{ 701 wmi_remove_notify_handler(HPWMI_EVENT_GUID); 702 sparse_keymap_free(hp_wmi_input_dev); 703 input_unregister_device(hp_wmi_input_dev); 704} 705 706static void cleanup_sysfs(struct platform_device *device) 707{ 708 device_remove_file(&device->dev, &dev_attr_display); 709 device_remove_file(&device->dev, &dev_attr_hddtemp); 710 device_remove_file(&device->dev, &dev_attr_als); 711 device_remove_file(&device->dev, &dev_attr_dock); 712 device_remove_file(&device->dev, &dev_attr_tablet); 713 device_remove_file(&device->dev, &dev_attr_postcode); 714} 715 716static int __init hp_wmi_rfkill_setup(struct platform_device *device) 717{ 718 int err; 719 int wireless = 0; 720 721 err = hp_wmi_perform_query(HPWMI_WIRELESS_QUERY, 0, &wireless, 722 sizeof(wireless), sizeof(wireless)); 723 if (err) 724 return err; 725 726 if (wireless & 0x1) { 727 wifi_rfkill = rfkill_alloc("hp-wifi", &device->dev, 728 RFKILL_TYPE_WLAN, 729 &hp_wmi_rfkill_ops, 730 (void *) HPWMI_WIFI); 731 if (!wifi_rfkill) 732 return -ENOMEM; 733 rfkill_init_sw_state(wifi_rfkill, 734 hp_wmi_get_sw_state(HPWMI_WIFI)); 735 rfkill_set_hw_state(wifi_rfkill, 736 hp_wmi_get_hw_state(HPWMI_WIFI)); 737 err = rfkill_register(wifi_rfkill); 738 if (err) 739 goto register_wifi_error; 740 } 741 742 if (wireless & 0x2) { 743 bluetooth_rfkill = rfkill_alloc("hp-bluetooth", &device->dev, 744 RFKILL_TYPE_BLUETOOTH, 745 &hp_wmi_rfkill_ops, 746 (void *) HPWMI_BLUETOOTH); 747 if (!bluetooth_rfkill) { 748 err = -ENOMEM; 749 goto register_wifi_error; 750 } 751 rfkill_init_sw_state(bluetooth_rfkill, 752 hp_wmi_get_sw_state(HPWMI_BLUETOOTH)); 753 rfkill_set_hw_state(bluetooth_rfkill, 754 hp_wmi_get_hw_state(HPWMI_BLUETOOTH)); 755 err = rfkill_register(bluetooth_rfkill); 756 if (err) 757 goto register_bluetooth_error; 758 } 759 760 if (wireless & 0x4) { 761 wwan_rfkill = rfkill_alloc("hp-wwan", &device->dev, 762 RFKILL_TYPE_WWAN, 763 &hp_wmi_rfkill_ops, 764 (void *) HPWMI_WWAN); 765 if (!wwan_rfkill) { 766 err = -ENOMEM; 767 goto register_bluetooth_error; 768 } 769 rfkill_init_sw_state(wwan_rfkill, 770 hp_wmi_get_sw_state(HPWMI_WWAN)); 771 rfkill_set_hw_state(wwan_rfkill, 772 hp_wmi_get_hw_state(HPWMI_WWAN)); 773 err = rfkill_register(wwan_rfkill); 774 if (err) 775 goto register_wwan_error; 776 } 777 778 if (wireless & 0x8) { 779 gps_rfkill = rfkill_alloc("hp-gps", &device->dev, 780 RFKILL_TYPE_GPS, 781 &hp_wmi_rfkill_ops, 782 (void *) HPWMI_GPS); 783 if (!gps_rfkill) { 784 err = -ENOMEM; 785 goto register_wwan_error; 786 } 787 rfkill_init_sw_state(gps_rfkill, 788 hp_wmi_get_sw_state(HPWMI_GPS)); 789 rfkill_set_hw_state(gps_rfkill, 790 hp_wmi_get_hw_state(HPWMI_GPS)); 791 err = rfkill_register(gps_rfkill); 792 if (err) 793 goto register_gps_error; 794 } 795 796 return 0; 797register_gps_error: 798 rfkill_destroy(gps_rfkill); 799 gps_rfkill = NULL; 800 if (bluetooth_rfkill) 801 rfkill_unregister(bluetooth_rfkill); 802register_wwan_error: 803 rfkill_destroy(wwan_rfkill); 804 wwan_rfkill = NULL; 805 if (gps_rfkill) 806 rfkill_unregister(gps_rfkill); 807register_bluetooth_error: 808 rfkill_destroy(bluetooth_rfkill); 809 bluetooth_rfkill = NULL; 810 if (wifi_rfkill) 811 rfkill_unregister(wifi_rfkill); 812register_wifi_error: 813 rfkill_destroy(wifi_rfkill); 814 wifi_rfkill = NULL; 815 return err; 816} 817 818static int __init hp_wmi_rfkill2_setup(struct platform_device *device) 819{ 820 int err, i; 821 struct bios_rfkill2_state state; 822 err = hp_wmi_perform_query(HPWMI_WIRELESS2_QUERY, 0, &state, 823 0, sizeof(state)); 824 if (err) 825 return err; 826 827 if (state.count > HPWMI_MAX_RFKILL2_DEVICES) { 828 pr_warn("unable to parse 0x1b query output\n"); 829 return -EINVAL; 830 } 831 832 for (i = 0; i < state.count; i++) { 833 struct rfkill *rfkill; 834 enum rfkill_type type; 835 char *name; 836 switch (state.device[i].radio_type) { 837 case HPWMI_WIFI: 838 type = RFKILL_TYPE_WLAN; 839 name = "hp-wifi"; 840 break; 841 case HPWMI_BLUETOOTH: 842 type = RFKILL_TYPE_BLUETOOTH; 843 name = "hp-bluetooth"; 844 break; 845 case HPWMI_WWAN: 846 type = RFKILL_TYPE_WWAN; 847 name = "hp-wwan"; 848 break; 849 case HPWMI_GPS: 850 type = RFKILL_TYPE_GPS; 851 name = "hp-gps"; 852 break; 853 default: 854 pr_warn("unknown device type 0x%x\n", 855 state.device[i].radio_type); 856 continue; 857 } 858 859 if (!state.device[i].vendor_id) { 860 pr_warn("zero device %d while %d reported\n", 861 i, state.count); 862 continue; 863 } 864 865 rfkill = rfkill_alloc(name, &device->dev, type, 866 &hp_wmi_rfkill2_ops, (void *)(long)i); 867 if (!rfkill) { 868 err = -ENOMEM; 869 goto fail; 870 } 871 872 rfkill2[rfkill2_count].id = state.device[i].rfkill_id; 873 rfkill2[rfkill2_count].num = i; 874 rfkill2[rfkill2_count].rfkill = rfkill; 875 876 rfkill_init_sw_state(rfkill, 877 IS_SWBLOCKED(state.device[i].power)); 878 rfkill_set_hw_state(rfkill, 879 IS_HWBLOCKED(state.device[i].power)); 880 881 if (!(state.device[i].power & HPWMI_POWER_BIOS)) 882 pr_info("device %s blocked by BIOS\n", name); 883 884 err = rfkill_register(rfkill); 885 if (err) { 886 rfkill_destroy(rfkill); 887 goto fail; 888 } 889 890 rfkill2_count++; 891 } 892 893 return 0; 894fail: 895 for (; rfkill2_count > 0; rfkill2_count--) { 896 rfkill_unregister(rfkill2[rfkill2_count - 1].rfkill); 897 rfkill_destroy(rfkill2[rfkill2_count - 1].rfkill); 898 } 899 return err; 900} 901 902static int __init hp_wmi_bios_setup(struct platform_device *device) 903{ 904 int err; 905 906 /* clear detected rfkill devices */ 907 wifi_rfkill = NULL; 908 bluetooth_rfkill = NULL; 909 wwan_rfkill = NULL; 910 gps_rfkill = NULL; 911 rfkill2_count = 0; 912 913 if (hp_wmi_bios_2009_later() || hp_wmi_rfkill_setup(device)) 914 hp_wmi_rfkill2_setup(device); 915 916 err = device_create_file(&device->dev, &dev_attr_display); 917 if (err) 918 goto add_sysfs_error; 919 err = device_create_file(&device->dev, &dev_attr_hddtemp); 920 if (err) 921 goto add_sysfs_error; 922 err = device_create_file(&device->dev, &dev_attr_als); 923 if (err) 924 goto add_sysfs_error; 925 err = device_create_file(&device->dev, &dev_attr_dock); 926 if (err) 927 goto add_sysfs_error; 928 err = device_create_file(&device->dev, &dev_attr_tablet); 929 if (err) 930 goto add_sysfs_error; 931 err = device_create_file(&device->dev, &dev_attr_postcode); 932 if (err) 933 goto add_sysfs_error; 934 return 0; 935 936add_sysfs_error: 937 cleanup_sysfs(device); 938 return err; 939} 940 941static int __exit hp_wmi_bios_remove(struct platform_device *device) 942{ 943 int i; 944 cleanup_sysfs(device); 945 946 for (i = 0; i < rfkill2_count; i++) { 947 rfkill_unregister(rfkill2[i].rfkill); 948 rfkill_destroy(rfkill2[i].rfkill); 949 } 950 951 if (wifi_rfkill) { 952 rfkill_unregister(wifi_rfkill); 953 rfkill_destroy(wifi_rfkill); 954 } 955 if (bluetooth_rfkill) { 956 rfkill_unregister(bluetooth_rfkill); 957 rfkill_destroy(bluetooth_rfkill); 958 } 959 if (wwan_rfkill) { 960 rfkill_unregister(wwan_rfkill); 961 rfkill_destroy(wwan_rfkill); 962 } 963 if (gps_rfkill) { 964 rfkill_unregister(gps_rfkill); 965 rfkill_destroy(gps_rfkill); 966 } 967 968 return 0; 969} 970 971static int hp_wmi_resume_handler(struct device *device) 972{ 973 /* 974 * Hardware state may have changed while suspended, so trigger 975 * input events for the current state. As this is a switch, 976 * the input layer will only actually pass it on if the state 977 * changed. 978 */ 979 if (hp_wmi_input_dev) { 980 input_report_switch(hp_wmi_input_dev, SW_DOCK, 981 hp_wmi_dock_state()); 982 input_report_switch(hp_wmi_input_dev, SW_TABLET_MODE, 983 hp_wmi_tablet_state()); 984 input_sync(hp_wmi_input_dev); 985 } 986 987 if (rfkill2_count) 988 hp_wmi_rfkill2_refresh(); 989 990 if (wifi_rfkill) 991 rfkill_set_states(wifi_rfkill, 992 hp_wmi_get_sw_state(HPWMI_WIFI), 993 hp_wmi_get_hw_state(HPWMI_WIFI)); 994 if (bluetooth_rfkill) 995 rfkill_set_states(bluetooth_rfkill, 996 hp_wmi_get_sw_state(HPWMI_BLUETOOTH), 997 hp_wmi_get_hw_state(HPWMI_BLUETOOTH)); 998 if (wwan_rfkill) 999 rfkill_set_states(wwan_rfkill, 1000 hp_wmi_get_sw_state(HPWMI_WWAN), 1001 hp_wmi_get_hw_state(HPWMI_WWAN)); 1002 if (gps_rfkill) 1003 rfkill_set_states(gps_rfkill, 1004 hp_wmi_get_sw_state(HPWMI_GPS), 1005 hp_wmi_get_hw_state(HPWMI_GPS)); 1006 1007 return 0; 1008} 1009 1010static const struct dev_pm_ops hp_wmi_pm_ops = { 1011 .resume = hp_wmi_resume_handler, 1012 .restore = hp_wmi_resume_handler, 1013}; 1014 1015static struct platform_driver hp_wmi_driver = { 1016 .driver = { 1017 .name = "hp-wmi", 1018 .pm = &hp_wmi_pm_ops, 1019 }, 1020 .remove = __exit_p(hp_wmi_bios_remove), 1021}; 1022 1023static int __init hp_wmi_init(void) 1024{ 1025 int err; 1026 int event_capable = wmi_has_guid(HPWMI_EVENT_GUID); 1027 int bios_capable = wmi_has_guid(HPWMI_BIOS_GUID); 1028 1029 if (!bios_capable && !event_capable) 1030 return -ENODEV; 1031 1032 if (event_capable) { 1033 err = hp_wmi_input_setup(); 1034 if (err) 1035 return err; 1036 } 1037 1038 if (bios_capable) { 1039 hp_wmi_platform_dev = 1040 platform_device_register_simple("hp-wmi", -1, NULL, 0); 1041 if (IS_ERR(hp_wmi_platform_dev)) { 1042 err = PTR_ERR(hp_wmi_platform_dev); 1043 goto err_destroy_input; 1044 } 1045 1046 err = platform_driver_probe(&hp_wmi_driver, hp_wmi_bios_setup); 1047 if (err) 1048 goto err_unregister_device; 1049 } 1050 1051 return 0; 1052 1053err_unregister_device: 1054 platform_device_unregister(hp_wmi_platform_dev); 1055err_destroy_input: 1056 if (event_capable) 1057 hp_wmi_input_destroy(); 1058 1059 return err; 1060} 1061module_init(hp_wmi_init); 1062 1063static void __exit hp_wmi_exit(void) 1064{ 1065 if (wmi_has_guid(HPWMI_EVENT_GUID)) 1066 hp_wmi_input_destroy(); 1067 1068 if (hp_wmi_platform_dev) { 1069 platform_device_unregister(hp_wmi_platform_dev); 1070 platform_driver_unregister(&hp_wmi_driver); 1071 } 1072} 1073module_exit(hp_wmi_exit);