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