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.9-rc1 1042 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; 160 161struct rfkill2_device { 162 u8 id; 163 int num; 164 struct rfkill *rfkill; 165}; 166 167static int rfkill2_count; 168static struct rfkill2_device rfkill2[HPWMI_MAX_RFKILL2_DEVICES]; 169 170/* 171 * hp_wmi_perform_query 172 * 173 * query: The commandtype -> What should be queried 174 * write: The command -> 0 read, 1 write, 3 ODM specific 175 * buffer: Buffer used as input and/or output 176 * insize: Size of input buffer 177 * outsize: Size of output buffer 178 * 179 * returns zero on success 180 * an HP WMI query specific error code (which is positive) 181 * -EINVAL if the query was not successful at all 182 * -EINVAL if the output buffer size exceeds buffersize 183 * 184 * Note: The buffersize must at least be the maximum of the input and output 185 * size. E.g. Battery info query (0x7) is defined to have 1 byte input 186 * and 128 byte output. The caller would do: 187 * buffer = kzalloc(128, GFP_KERNEL); 188 * ret = hp_wmi_perform_query(0x7, 0, buffer, 1, 128) 189 */ 190static int hp_wmi_perform_query(int query, int write, void *buffer, 191 int insize, int outsize) 192{ 193 struct bios_return *bios_return; 194 int actual_outsize; 195 union acpi_object *obj; 196 struct bios_args args = { 197 .signature = 0x55434553, 198 .command = write ? 0x2 : 0x1, 199 .commandtype = query, 200 .datasize = insize, 201 .data = 0, 202 }; 203 struct acpi_buffer input = { sizeof(struct bios_args), &args }; 204 struct acpi_buffer output = { ACPI_ALLOCATE_BUFFER, NULL }; 205 u32 rc; 206 207 if (WARN_ON(insize > sizeof(args.data))) 208 return -EINVAL; 209 memcpy(&args.data, buffer, insize); 210 211 wmi_evaluate_method(HPWMI_BIOS_GUID, 0, 0x3, &input, &output); 212 213 obj = output.pointer; 214 215 if (!obj) 216 return -EINVAL; 217 else if (obj->type != ACPI_TYPE_BUFFER) { 218 kfree(obj); 219 return -EINVAL; 220 } 221 222 bios_return = (struct bios_return *)obj->buffer.pointer; 223 rc = bios_return->return_code; 224 225 if (rc) { 226 if (rc != HPWMI_RET_UNKNOWN_CMDTYPE) 227 pr_warn("query 0x%x returned error 0x%x\n", query, rc); 228 kfree(obj); 229 return rc; 230 } 231 232 if (!outsize) { 233 /* ignore output data */ 234 kfree(obj); 235 return 0; 236 } 237 238 actual_outsize = min(outsize, (int)(obj->buffer.length - sizeof(*bios_return))); 239 memcpy(buffer, obj->buffer.pointer + sizeof(*bios_return), actual_outsize); 240 memset(buffer + actual_outsize, 0, outsize - actual_outsize); 241 kfree(obj); 242 return 0; 243} 244 245static int hp_wmi_display_state(void) 246{ 247 int state = 0; 248 int ret = hp_wmi_perform_query(HPWMI_DISPLAY_QUERY, 0, &state, 249 sizeof(state), sizeof(state)); 250 if (ret) 251 return -EINVAL; 252 return state; 253} 254 255static int hp_wmi_hddtemp_state(void) 256{ 257 int state = 0; 258 int ret = hp_wmi_perform_query(HPWMI_HDDTEMP_QUERY, 0, &state, 259 sizeof(state), sizeof(state)); 260 if (ret) 261 return -EINVAL; 262 return state; 263} 264 265static int hp_wmi_als_state(void) 266{ 267 int state = 0; 268 int ret = hp_wmi_perform_query(HPWMI_ALS_QUERY, 0, &state, 269 sizeof(state), sizeof(state)); 270 if (ret) 271 return -EINVAL; 272 return state; 273} 274 275static int hp_wmi_dock_state(void) 276{ 277 int state = 0; 278 int ret = hp_wmi_perform_query(HPWMI_HARDWARE_QUERY, 0, &state, 279 sizeof(state), sizeof(state)); 280 281 if (ret) 282 return -EINVAL; 283 284 return state & 0x1; 285} 286 287static int hp_wmi_tablet_state(void) 288{ 289 int state = 0; 290 int ret = hp_wmi_perform_query(HPWMI_HARDWARE_QUERY, 0, &state, 291 sizeof(state), sizeof(state)); 292 if (ret) 293 return ret; 294 295 return (state & 0x4) ? 1 : 0; 296} 297 298static int __init hp_wmi_bios_2008_later(void) 299{ 300 int state = 0; 301 int ret = hp_wmi_perform_query(HPWMI_FEATURE_QUERY, 0, &state, 302 sizeof(state), sizeof(state)); 303 if (!ret) 304 return 1; 305 306 return (ret == HPWMI_RET_UNKNOWN_CMDTYPE) ? 0 : -ENXIO; 307} 308 309static int __init hp_wmi_bios_2009_later(void) 310{ 311 int state = 0; 312 int ret = hp_wmi_perform_query(HPWMI_FEATURE2_QUERY, 0, &state, 313 sizeof(state), sizeof(state)); 314 if (!ret) 315 return 1; 316 317 return (ret == HPWMI_RET_UNKNOWN_CMDTYPE) ? 0 : -ENXIO; 318} 319 320static int __init hp_wmi_enable_hotkeys(void) 321{ 322 int value = 0x6e; 323 int ret = hp_wmi_perform_query(HPWMI_BIOS_QUERY, 1, &value, 324 sizeof(value), 0); 325 if (ret) 326 return -EINVAL; 327 return 0; 328} 329 330static int hp_wmi_set_block(void *data, bool blocked) 331{ 332 enum hp_wmi_radio r = (enum hp_wmi_radio) data; 333 int query = BIT(r + 8) | ((!blocked) << r); 334 int ret; 335 336 ret = hp_wmi_perform_query(HPWMI_WIRELESS_QUERY, 1, 337 &query, sizeof(query), 0); 338 if (ret) 339 return -EINVAL; 340 return 0; 341} 342 343static const struct rfkill_ops hp_wmi_rfkill_ops = { 344 .set_block = hp_wmi_set_block, 345}; 346 347static bool hp_wmi_get_sw_state(enum hp_wmi_radio r) 348{ 349 int wireless = 0; 350 int mask; 351 hp_wmi_perform_query(HPWMI_WIRELESS_QUERY, 0, 352 &wireless, sizeof(wireless), 353 sizeof(wireless)); 354 /* TBD: Pass error */ 355 356 mask = 0x200 << (r * 8); 357 358 if (wireless & mask) 359 return false; 360 else 361 return true; 362} 363 364static bool hp_wmi_get_hw_state(enum hp_wmi_radio r) 365{ 366 int wireless = 0; 367 int mask; 368 hp_wmi_perform_query(HPWMI_WIRELESS_QUERY, 0, 369 &wireless, sizeof(wireless), 370 sizeof(wireless)); 371 /* TBD: Pass error */ 372 373 mask = 0x800 << (r * 8); 374 375 if (wireless & mask) 376 return false; 377 else 378 return true; 379} 380 381static int hp_wmi_rfkill2_set_block(void *data, bool blocked) 382{ 383 int rfkill_id = (int)(long)data; 384 char buffer[4] = { 0x01, 0x00, rfkill_id, !blocked }; 385 386 if (hp_wmi_perform_query(HPWMI_WIRELESS2_QUERY, 1, 387 buffer, sizeof(buffer), 0)) 388 return -EINVAL; 389 return 0; 390} 391 392static const struct rfkill_ops hp_wmi_rfkill2_ops = { 393 .set_block = hp_wmi_rfkill2_set_block, 394}; 395 396static int hp_wmi_rfkill2_refresh(void) 397{ 398 int err, i; 399 struct bios_rfkill2_state state; 400 401 err = hp_wmi_perform_query(HPWMI_WIRELESS2_QUERY, 0, &state, 402 0, sizeof(state)); 403 if (err) 404 return err; 405 406 for (i = 0; i < rfkill2_count; i++) { 407 int num = rfkill2[i].num; 408 struct bios_rfkill2_device_state *devstate; 409 devstate = &state.device[num]; 410 411 if (num >= state.count || 412 devstate->rfkill_id != rfkill2[i].id) { 413 pr_warn("power configuration of the wireless devices unexpectedly changed\n"); 414 continue; 415 } 416 417 rfkill_set_states(rfkill2[i].rfkill, 418 IS_SWBLOCKED(devstate->power), 419 IS_HWBLOCKED(devstate->power)); 420 } 421 422 return 0; 423} 424 425static int hp_wmi_post_code_state(void) 426{ 427 int state = 0; 428 int ret = hp_wmi_perform_query(HPWMI_POSTCODEERROR_QUERY, 0, &state, 429 sizeof(state), sizeof(state)); 430 if (ret) 431 return -EINVAL; 432 return state; 433} 434 435static ssize_t show_display(struct device *dev, struct device_attribute *attr, 436 char *buf) 437{ 438 int value = hp_wmi_display_state(); 439 if (value < 0) 440 return -EINVAL; 441 return sprintf(buf, "%d\n", value); 442} 443 444static ssize_t show_hddtemp(struct device *dev, struct device_attribute *attr, 445 char *buf) 446{ 447 int value = hp_wmi_hddtemp_state(); 448 if (value < 0) 449 return -EINVAL; 450 return sprintf(buf, "%d\n", value); 451} 452 453static ssize_t show_als(struct device *dev, struct device_attribute *attr, 454 char *buf) 455{ 456 int value = hp_wmi_als_state(); 457 if (value < 0) 458 return -EINVAL; 459 return sprintf(buf, "%d\n", value); 460} 461 462static ssize_t show_dock(struct device *dev, struct device_attribute *attr, 463 char *buf) 464{ 465 int value = hp_wmi_dock_state(); 466 if (value < 0) 467 return -EINVAL; 468 return sprintf(buf, "%d\n", value); 469} 470 471static ssize_t show_tablet(struct device *dev, struct device_attribute *attr, 472 char *buf) 473{ 474 int value = hp_wmi_tablet_state(); 475 if (value < 0) 476 return -EINVAL; 477 return sprintf(buf, "%d\n", value); 478} 479 480static ssize_t show_postcode(struct device *dev, struct device_attribute *attr, 481 char *buf) 482{ 483 /* Get the POST error code of previous boot failure. */ 484 int value = hp_wmi_post_code_state(); 485 if (value < 0) 486 return -EINVAL; 487 return sprintf(buf, "0x%x\n", value); 488} 489 490static ssize_t set_als(struct device *dev, struct device_attribute *attr, 491 const char *buf, size_t count) 492{ 493 u32 tmp = simple_strtoul(buf, NULL, 10); 494 int ret = hp_wmi_perform_query(HPWMI_ALS_QUERY, 1, &tmp, 495 sizeof(tmp), sizeof(tmp)); 496 if (ret) 497 return -EINVAL; 498 499 return count; 500} 501 502static ssize_t set_postcode(struct device *dev, struct device_attribute *attr, 503 const char *buf, size_t count) 504{ 505 int ret; 506 u32 tmp; 507 long unsigned int tmp2; 508 509 ret = kstrtoul(buf, 10, &tmp2); 510 if (ret || tmp2 != 1) 511 return -EINVAL; 512 513 /* Clear the POST error code. It is kept until until cleared. */ 514 tmp = (u32) tmp2; 515 ret = hp_wmi_perform_query(HPWMI_POSTCODEERROR_QUERY, 1, &tmp, 516 sizeof(tmp), sizeof(tmp)); 517 if (ret) 518 return -EINVAL; 519 520 return count; 521} 522 523static DEVICE_ATTR(display, S_IRUGO, show_display, NULL); 524static DEVICE_ATTR(hddtemp, S_IRUGO, show_hddtemp, NULL); 525static DEVICE_ATTR(als, S_IRUGO | S_IWUSR, show_als, set_als); 526static DEVICE_ATTR(dock, S_IRUGO, show_dock, NULL); 527static DEVICE_ATTR(tablet, S_IRUGO, show_tablet, NULL); 528static DEVICE_ATTR(postcode, S_IRUGO | S_IWUSR, show_postcode, set_postcode); 529 530static void hp_wmi_notify(u32 value, void *context) 531{ 532 struct acpi_buffer response = { ACPI_ALLOCATE_BUFFER, NULL }; 533 union acpi_object *obj; 534 u32 event_id, event_data; 535 int key_code = 0, ret; 536 u32 *location; 537 acpi_status status; 538 539 status = wmi_get_event_data(value, &response); 540 if (status != AE_OK) { 541 pr_info("bad event status 0x%x\n", status); 542 return; 543 } 544 545 obj = (union acpi_object *)response.pointer; 546 547 if (!obj) 548 return; 549 if (obj->type != ACPI_TYPE_BUFFER) { 550 pr_info("Unknown response received %d\n", obj->type); 551 kfree(obj); 552 return; 553 } 554 555 /* 556 * Depending on ACPI version the concatenation of id and event data 557 * inside _WED function will result in a 8 or 16 byte buffer. 558 */ 559 location = (u32 *)obj->buffer.pointer; 560 if (obj->buffer.length == 8) { 561 event_id = *location; 562 event_data = *(location + 1); 563 } else if (obj->buffer.length == 16) { 564 event_id = *location; 565 event_data = *(location + 2); 566 } else { 567 pr_info("Unknown buffer length %d\n", obj->buffer.length); 568 kfree(obj); 569 return; 570 } 571 kfree(obj); 572 573 switch (event_id) { 574 case HPWMI_DOCK_EVENT: 575 input_report_switch(hp_wmi_input_dev, SW_DOCK, 576 hp_wmi_dock_state()); 577 input_report_switch(hp_wmi_input_dev, SW_TABLET_MODE, 578 hp_wmi_tablet_state()); 579 input_sync(hp_wmi_input_dev); 580 break; 581 case HPWMI_PARK_HDD: 582 break; 583 case HPWMI_SMART_ADAPTER: 584 break; 585 case HPWMI_BEZEL_BUTTON: 586 ret = hp_wmi_perform_query(HPWMI_HOTKEY_QUERY, 0, 587 &key_code, 588 sizeof(key_code), 589 sizeof(key_code)); 590 if (ret) 591 break; 592 593 if (!sparse_keymap_report_event(hp_wmi_input_dev, 594 key_code, 1, true)) 595 pr_info("Unknown key code - 0x%x\n", key_code); 596 break; 597 case HPWMI_WIRELESS: 598 if (rfkill2_count) { 599 hp_wmi_rfkill2_refresh(); 600 break; 601 } 602 603 if (wifi_rfkill) 604 rfkill_set_states(wifi_rfkill, 605 hp_wmi_get_sw_state(HPWMI_WIFI), 606 hp_wmi_get_hw_state(HPWMI_WIFI)); 607 if (bluetooth_rfkill) 608 rfkill_set_states(bluetooth_rfkill, 609 hp_wmi_get_sw_state(HPWMI_BLUETOOTH), 610 hp_wmi_get_hw_state(HPWMI_BLUETOOTH)); 611 if (wwan_rfkill) 612 rfkill_set_states(wwan_rfkill, 613 hp_wmi_get_sw_state(HPWMI_WWAN), 614 hp_wmi_get_hw_state(HPWMI_WWAN)); 615 break; 616 case HPWMI_CPU_BATTERY_THROTTLE: 617 pr_info("Unimplemented CPU throttle because of 3 Cell battery event detected\n"); 618 break; 619 case HPWMI_LOCK_SWITCH: 620 break; 621 case HPWMI_LID_SWITCH: 622 break; 623 case HPWMI_SCREEN_ROTATION: 624 break; 625 case HPWMI_COOLSENSE_SYSTEM_MOBILE: 626 break; 627 case HPWMI_COOLSENSE_SYSTEM_HOT: 628 break; 629 case HPWMI_PROXIMITY_SENSOR: 630 break; 631 case HPWMI_BACKLIT_KB_BRIGHTNESS: 632 break; 633 case HPWMI_PEAKSHIFT_PERIOD: 634 break; 635 case HPWMI_BATTERY_CHARGE_PERIOD: 636 break; 637 default: 638 pr_info("Unknown event_id - %d - 0x%x\n", event_id, event_data); 639 break; 640 } 641} 642 643static int __init hp_wmi_input_setup(void) 644{ 645 acpi_status status; 646 int err; 647 648 hp_wmi_input_dev = input_allocate_device(); 649 if (!hp_wmi_input_dev) 650 return -ENOMEM; 651 652 hp_wmi_input_dev->name = "HP WMI hotkeys"; 653 hp_wmi_input_dev->phys = "wmi/input0"; 654 hp_wmi_input_dev->id.bustype = BUS_HOST; 655 656 __set_bit(EV_SW, hp_wmi_input_dev->evbit); 657 __set_bit(SW_DOCK, hp_wmi_input_dev->swbit); 658 __set_bit(SW_TABLET_MODE, hp_wmi_input_dev->swbit); 659 660 err = sparse_keymap_setup(hp_wmi_input_dev, hp_wmi_keymap, NULL); 661 if (err) 662 goto err_free_dev; 663 664 /* Set initial hardware state */ 665 input_report_switch(hp_wmi_input_dev, SW_DOCK, hp_wmi_dock_state()); 666 input_report_switch(hp_wmi_input_dev, SW_TABLET_MODE, 667 hp_wmi_tablet_state()); 668 input_sync(hp_wmi_input_dev); 669 670 if (!hp_wmi_bios_2009_later() && hp_wmi_bios_2008_later()) 671 hp_wmi_enable_hotkeys(); 672 673 status = wmi_install_notify_handler(HPWMI_EVENT_GUID, hp_wmi_notify, NULL); 674 if (ACPI_FAILURE(status)) { 675 err = -EIO; 676 goto err_free_keymap; 677 } 678 679 err = input_register_device(hp_wmi_input_dev); 680 if (err) 681 goto err_uninstall_notifier; 682 683 return 0; 684 685 err_uninstall_notifier: 686 wmi_remove_notify_handler(HPWMI_EVENT_GUID); 687 err_free_keymap: 688 sparse_keymap_free(hp_wmi_input_dev); 689 err_free_dev: 690 input_free_device(hp_wmi_input_dev); 691 return err; 692} 693 694static void hp_wmi_input_destroy(void) 695{ 696 wmi_remove_notify_handler(HPWMI_EVENT_GUID); 697 sparse_keymap_free(hp_wmi_input_dev); 698 input_unregister_device(hp_wmi_input_dev); 699} 700 701static void cleanup_sysfs(struct platform_device *device) 702{ 703 device_remove_file(&device->dev, &dev_attr_display); 704 device_remove_file(&device->dev, &dev_attr_hddtemp); 705 device_remove_file(&device->dev, &dev_attr_als); 706 device_remove_file(&device->dev, &dev_attr_dock); 707 device_remove_file(&device->dev, &dev_attr_tablet); 708 device_remove_file(&device->dev, &dev_attr_postcode); 709} 710 711static int __init hp_wmi_rfkill_setup(struct platform_device *device) 712{ 713 int err; 714 int wireless = 0; 715 716 err = hp_wmi_perform_query(HPWMI_WIRELESS_QUERY, 0, &wireless, 717 sizeof(wireless), sizeof(wireless)); 718 if (err) 719 return err; 720 721 err = hp_wmi_perform_query(HPWMI_WIRELESS_QUERY, 1, &wireless, 722 sizeof(wireless), 0); 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_bluetooth_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_wwan_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 return 0; 779 780register_wwan_error: 781 rfkill_destroy(wwan_rfkill); 782 wwan_rfkill = NULL; 783 if (bluetooth_rfkill) 784 rfkill_unregister(bluetooth_rfkill); 785register_bluetooth_error: 786 rfkill_destroy(bluetooth_rfkill); 787 bluetooth_rfkill = NULL; 788 if (wifi_rfkill) 789 rfkill_unregister(wifi_rfkill); 790register_wifi_error: 791 rfkill_destroy(wifi_rfkill); 792 wifi_rfkill = NULL; 793 return err; 794} 795 796static int __init hp_wmi_rfkill2_setup(struct platform_device *device) 797{ 798 int err, i; 799 struct bios_rfkill2_state state; 800 err = hp_wmi_perform_query(HPWMI_WIRELESS2_QUERY, 0, &state, 801 0, sizeof(state)); 802 if (err) 803 return err; 804 805 if (state.count > HPWMI_MAX_RFKILL2_DEVICES) { 806 pr_warn("unable to parse 0x1b query output\n"); 807 return -EINVAL; 808 } 809 810 for (i = 0; i < state.count; i++) { 811 struct rfkill *rfkill; 812 enum rfkill_type type; 813 char *name; 814 switch (state.device[i].radio_type) { 815 case HPWMI_WIFI: 816 type = RFKILL_TYPE_WLAN; 817 name = "hp-wifi"; 818 break; 819 case HPWMI_BLUETOOTH: 820 type = RFKILL_TYPE_BLUETOOTH; 821 name = "hp-bluetooth"; 822 break; 823 case HPWMI_WWAN: 824 type = RFKILL_TYPE_WWAN; 825 name = "hp-wwan"; 826 break; 827 case HPWMI_GPS: 828 type = RFKILL_TYPE_GPS; 829 name = "hp-gps"; 830 break; 831 default: 832 pr_warn("unknown device type 0x%x\n", 833 state.device[i].radio_type); 834 continue; 835 } 836 837 if (!state.device[i].vendor_id) { 838 pr_warn("zero device %d while %d reported\n", 839 i, state.count); 840 continue; 841 } 842 843 rfkill = rfkill_alloc(name, &device->dev, type, 844 &hp_wmi_rfkill2_ops, (void *)(long)i); 845 if (!rfkill) { 846 err = -ENOMEM; 847 goto fail; 848 } 849 850 rfkill2[rfkill2_count].id = state.device[i].rfkill_id; 851 rfkill2[rfkill2_count].num = i; 852 rfkill2[rfkill2_count].rfkill = rfkill; 853 854 rfkill_init_sw_state(rfkill, 855 IS_SWBLOCKED(state.device[i].power)); 856 rfkill_set_hw_state(rfkill, 857 IS_HWBLOCKED(state.device[i].power)); 858 859 if (!(state.device[i].power & HPWMI_POWER_BIOS)) 860 pr_info("device %s blocked by BIOS\n", name); 861 862 err = rfkill_register(rfkill); 863 if (err) { 864 rfkill_destroy(rfkill); 865 goto fail; 866 } 867 868 rfkill2_count++; 869 } 870 871 return 0; 872fail: 873 for (; rfkill2_count > 0; rfkill2_count--) { 874 rfkill_unregister(rfkill2[rfkill2_count - 1].rfkill); 875 rfkill_destroy(rfkill2[rfkill2_count - 1].rfkill); 876 } 877 return err; 878} 879 880static int __init hp_wmi_bios_setup(struct platform_device *device) 881{ 882 int err; 883 884 /* clear detected rfkill devices */ 885 wifi_rfkill = NULL; 886 bluetooth_rfkill = NULL; 887 wwan_rfkill = NULL; 888 rfkill2_count = 0; 889 890 if (hp_wmi_rfkill_setup(device)) 891 hp_wmi_rfkill2_setup(device); 892 893 err = device_create_file(&device->dev, &dev_attr_display); 894 if (err) 895 goto add_sysfs_error; 896 err = device_create_file(&device->dev, &dev_attr_hddtemp); 897 if (err) 898 goto add_sysfs_error; 899 err = device_create_file(&device->dev, &dev_attr_als); 900 if (err) 901 goto add_sysfs_error; 902 err = device_create_file(&device->dev, &dev_attr_dock); 903 if (err) 904 goto add_sysfs_error; 905 err = device_create_file(&device->dev, &dev_attr_tablet); 906 if (err) 907 goto add_sysfs_error; 908 err = device_create_file(&device->dev, &dev_attr_postcode); 909 if (err) 910 goto add_sysfs_error; 911 return 0; 912 913add_sysfs_error: 914 cleanup_sysfs(device); 915 return err; 916} 917 918static int __exit hp_wmi_bios_remove(struct platform_device *device) 919{ 920 int i; 921 cleanup_sysfs(device); 922 923 for (i = 0; i < rfkill2_count; i++) { 924 rfkill_unregister(rfkill2[i].rfkill); 925 rfkill_destroy(rfkill2[i].rfkill); 926 } 927 928 if (wifi_rfkill) { 929 rfkill_unregister(wifi_rfkill); 930 rfkill_destroy(wifi_rfkill); 931 } 932 if (bluetooth_rfkill) { 933 rfkill_unregister(bluetooth_rfkill); 934 rfkill_destroy(bluetooth_rfkill); 935 } 936 if (wwan_rfkill) { 937 rfkill_unregister(wwan_rfkill); 938 rfkill_destroy(wwan_rfkill); 939 } 940 941 return 0; 942} 943 944static int hp_wmi_resume_handler(struct device *device) 945{ 946 /* 947 * Hardware state may have changed while suspended, so trigger 948 * input events for the current state. As this is a switch, 949 * the input layer will only actually pass it on if the state 950 * changed. 951 */ 952 if (hp_wmi_input_dev) { 953 input_report_switch(hp_wmi_input_dev, SW_DOCK, 954 hp_wmi_dock_state()); 955 input_report_switch(hp_wmi_input_dev, SW_TABLET_MODE, 956 hp_wmi_tablet_state()); 957 input_sync(hp_wmi_input_dev); 958 } 959 960 if (rfkill2_count) 961 hp_wmi_rfkill2_refresh(); 962 963 if (wifi_rfkill) 964 rfkill_set_states(wifi_rfkill, 965 hp_wmi_get_sw_state(HPWMI_WIFI), 966 hp_wmi_get_hw_state(HPWMI_WIFI)); 967 if (bluetooth_rfkill) 968 rfkill_set_states(bluetooth_rfkill, 969 hp_wmi_get_sw_state(HPWMI_BLUETOOTH), 970 hp_wmi_get_hw_state(HPWMI_BLUETOOTH)); 971 if (wwan_rfkill) 972 rfkill_set_states(wwan_rfkill, 973 hp_wmi_get_sw_state(HPWMI_WWAN), 974 hp_wmi_get_hw_state(HPWMI_WWAN)); 975 976 return 0; 977} 978 979static const struct dev_pm_ops hp_wmi_pm_ops = { 980 .resume = hp_wmi_resume_handler, 981 .restore = hp_wmi_resume_handler, 982}; 983 984static struct platform_driver hp_wmi_driver = { 985 .driver = { 986 .name = "hp-wmi", 987 .pm = &hp_wmi_pm_ops, 988 }, 989 .remove = __exit_p(hp_wmi_bios_remove), 990}; 991 992static int __init hp_wmi_init(void) 993{ 994 int err; 995 int event_capable = wmi_has_guid(HPWMI_EVENT_GUID); 996 int bios_capable = wmi_has_guid(HPWMI_BIOS_GUID); 997 998 if (!bios_capable && !event_capable) 999 return -ENODEV; 1000 1001 if (event_capable) { 1002 err = hp_wmi_input_setup(); 1003 if (err) 1004 return err; 1005 } 1006 1007 if (bios_capable) { 1008 hp_wmi_platform_dev = 1009 platform_device_register_simple("hp-wmi", -1, NULL, 0); 1010 if (IS_ERR(hp_wmi_platform_dev)) { 1011 err = PTR_ERR(hp_wmi_platform_dev); 1012 goto err_destroy_input; 1013 } 1014 1015 err = platform_driver_probe(&hp_wmi_driver, hp_wmi_bios_setup); 1016 if (err) 1017 goto err_unregister_device; 1018 } 1019 1020 return 0; 1021 1022err_unregister_device: 1023 platform_device_unregister(hp_wmi_platform_dev); 1024err_destroy_input: 1025 if (event_capable) 1026 hp_wmi_input_destroy(); 1027 1028 return err; 1029} 1030module_init(hp_wmi_init); 1031 1032static void __exit hp_wmi_exit(void) 1033{ 1034 if (wmi_has_guid(HPWMI_EVENT_GUID)) 1035 hp_wmi_input_destroy(); 1036 1037 if (hp_wmi_platform_dev) { 1038 platform_device_unregister(hp_wmi_platform_dev); 1039 platform_driver_unregister(&hp_wmi_driver); 1040 } 1041} 1042module_exit(hp_wmi_exit);