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