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