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