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