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