linux/drivers/platform/x86/acer-wmi.c
<<
>>
Prefs
   1/*
   2 *  Acer WMI Laptop Extras
   3 *
   4 *  Copyright (C) 2007-2009     Carlos Corbacho <carlos@strangeworlds.co.uk>
   5 *
   6 *  Based on acer_acpi:
   7 *    Copyright (C) 2005-2007   E.M. Smith
   8 *    Copyright (C) 2007-2008   Carlos Corbacho <cathectic@gmail.com>
   9 *
  10 *  This program is free software; you can redistribute it and/or modify
  11 *  it under the terms of the GNU General Public License as published by
  12 *  the Free Software Foundation; either version 2 of the License, or
  13 *  (at your option) any later version.
  14 *
  15 *  This program is distributed in the hope that it will be useful,
  16 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
  17 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  18 *  GNU General Public License for more details.
  19 *
  20 *  You should have received a copy of the GNU General Public License
  21 *  along with this program; if not, write to the Free Software
  22 *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
  23 */
  24
  25#include <linux/kernel.h>
  26#include <linux/module.h>
  27#include <linux/init.h>
  28#include <linux/types.h>
  29#include <linux/dmi.h>
  30#include <linux/fb.h>
  31#include <linux/backlight.h>
  32#include <linux/leds.h>
  33#include <linux/platform_device.h>
  34#include <linux/acpi.h>
  35#include <linux/i8042.h>
  36#include <linux/rfkill.h>
  37#include <linux/workqueue.h>
  38#include <linux/debugfs.h>
  39#include <linux/slab.h>
  40#include <linux/input.h>
  41#include <linux/input/sparse-keymap.h>
  42#include <linux/dmi.h>
  43
  44#include <acpi/acpi_drivers.h>
  45
  46MODULE_AUTHOR("Carlos Corbacho");
  47MODULE_DESCRIPTION("Acer Laptop WMI Extras Driver");
  48MODULE_LICENSE("GPL");
  49
  50#define ACER_LOGPREFIX "acer-wmi: "
  51#define ACER_ERR KERN_ERR ACER_LOGPREFIX
  52#define ACER_NOTICE KERN_NOTICE ACER_LOGPREFIX
  53#define ACER_INFO KERN_INFO ACER_LOGPREFIX
  54#define ACER_WARNING KERN_WARNING ACER_LOGPREFIX
  55
  56/*
  57 * Magic Number
  58 * Meaning is unknown - this number is required for writing to ACPI for AMW0
  59 * (it's also used in acerhk when directly accessing the BIOS)
  60 */
  61#define ACER_AMW0_WRITE 0x9610
  62
  63/*
  64 * Bit masks for the AMW0 interface
  65 */
  66#define ACER_AMW0_WIRELESS_MASK  0x35
  67#define ACER_AMW0_BLUETOOTH_MASK 0x34
  68#define ACER_AMW0_MAILLED_MASK   0x31
  69
  70/*
  71 * Method IDs for WMID interface
  72 */
  73#define ACER_WMID_GET_WIRELESS_METHODID         1
  74#define ACER_WMID_GET_BLUETOOTH_METHODID        2
  75#define ACER_WMID_GET_BRIGHTNESS_METHODID       3
  76#define ACER_WMID_SET_WIRELESS_METHODID         4
  77#define ACER_WMID_SET_BLUETOOTH_METHODID        5
  78#define ACER_WMID_SET_BRIGHTNESS_METHODID       6
  79#define ACER_WMID_GET_THREEG_METHODID           10
  80#define ACER_WMID_SET_THREEG_METHODID           11
  81
  82/*
  83 * Acer ACPI method GUIDs
  84 */
  85#define AMW0_GUID1              "67C3371D-95A3-4C37-BB61-DD47B491DAAB"
  86#define AMW0_GUID2              "431F16ED-0C2B-444C-B267-27DEB140CF9C"
  87#define WMID_GUID1              "6AF4F258-B401-42FD-BE91-3D4AC2D7C0D3"
  88#define WMID_GUID2              "95764E09-FB56-4e83-B31A-37761F60994A"
  89#define WMID_GUID3              "61EF69EA-865C-4BC3-A502-A0DEBA0CB531"
  90
  91/*
  92 * Acer ACPI event GUIDs
  93 */
  94#define ACERWMID_EVENT_GUID "676AA15E-6A47-4D9F-A2CC-1E6D18D14026"
  95
  96MODULE_ALIAS("wmi:67C3371D-95A3-4C37-BB61-DD47B491DAAB");
  97MODULE_ALIAS("wmi:6AF4F258-B401-42fd-BE91-3D4AC2D7C0D3");
  98MODULE_ALIAS("wmi:676AA15E-6A47-4D9F-A2CC-1E6D18D14026");
  99
 100enum acer_wmi_event_ids {
 101        WMID_HOTKEY_EVENT = 0x1,
 102};
 103
 104static const struct key_entry acer_wmi_keymap[] = {
 105        {KE_KEY, 0x01, {KEY_WLAN} },     /* WiFi */
 106        {KE_KEY, 0x12, {KEY_BLUETOOTH} },       /* BT */
 107        {KE_KEY, 0x21, {KEY_PROG1} },    /* Backup */
 108        {KE_KEY, 0x22, {KEY_PROG2} },    /* Arcade */
 109        {KE_KEY, 0x23, {KEY_PROG3} },    /* P_Key */
 110        {KE_KEY, 0x24, {KEY_PROG4} },    /* Social networking_Key */
 111        {KE_KEY, 0x64, {KEY_SWITCHVIDEOMODE} }, /* Display Switch */
 112        {KE_KEY, 0x82, {KEY_F22} },      /* Touch Pad On/Off */
 113        {KE_END, 0}
 114};
 115
 116static struct input_dev *acer_wmi_input_dev;
 117
 118struct event_return_value {
 119        u8 function;
 120        u8 key_num;
 121        u16 device_state;
 122        u32 reserved;
 123} __attribute__((packed));
 124
 125/*
 126 * GUID3 Get Device Status device flags
 127 */
 128#define ACER_WMID3_GDS_WIRELESS         (1<<0)  /* WiFi */
 129#define ACER_WMID3_GDS_THREEG           (1<<6)  /* 3G */
 130#define ACER_WMID3_GDS_BLUETOOTH        (1<<11) /* BT */
 131
 132struct lm_input_params {
 133        u8 function_num;        /* Function Number */
 134        u16 commun_devices;     /* Communication type devices default status */
 135        u16 devices;            /* Other type devices default status */
 136        u8 lm_status;           /* Launch Manager Status */
 137        u16 reserved;
 138} __attribute__((packed));
 139
 140struct lm_return_value {
 141        u8 error_code;          /* Error Code */
 142        u8 ec_return_value;     /* EC Return Value */
 143        u16 reserved;
 144} __attribute__((packed));
 145
 146struct wmid3_gds_input_param {  /* Get Device Status input parameter */
 147        u8 function_num;        /* Function Number */
 148        u8 hotkey_number;       /* Hotkey Number */
 149        u16 devices;            /* Get Device */
 150} __attribute__((packed));
 151
 152struct wmid3_gds_return_value { /* Get Device Status return value*/
 153        u8 error_code;          /* Error Code */
 154        u8 ec_return_value;     /* EC Return Value */
 155        u16 devices;            /* Current Device Status */
 156        u32 reserved;
 157} __attribute__((packed));
 158
 159struct hotkey_function_type_aa {
 160        u8 type;
 161        u8 length;
 162        u16 handle;
 163        u16 commun_func_bitmap;
 164} __attribute__((packed));
 165
 166/*
 167 * Interface capability flags
 168 */
 169#define ACER_CAP_MAILLED                (1<<0)
 170#define ACER_CAP_WIRELESS               (1<<1)
 171#define ACER_CAP_BLUETOOTH              (1<<2)
 172#define ACER_CAP_BRIGHTNESS             (1<<3)
 173#define ACER_CAP_THREEG                 (1<<4)
 174#define ACER_CAP_ANY                    (0xFFFFFFFF)
 175
 176/*
 177 * Interface type flags
 178 */
 179enum interface_flags {
 180        ACER_AMW0,
 181        ACER_AMW0_V2,
 182        ACER_WMID,
 183};
 184
 185#define ACER_DEFAULT_WIRELESS  0
 186#define ACER_DEFAULT_BLUETOOTH 0
 187#define ACER_DEFAULT_MAILLED   0
 188#define ACER_DEFAULT_THREEG    0
 189
 190static int max_brightness = 0xF;
 191
 192static int mailled = -1;
 193static int brightness = -1;
 194static int threeg = -1;
 195static int force_series;
 196static bool ec_raw_mode;
 197static bool has_type_aa;
 198
 199module_param(mailled, int, 0444);
 200module_param(brightness, int, 0444);
 201module_param(threeg, int, 0444);
 202module_param(force_series, int, 0444);
 203module_param(ec_raw_mode, bool, 0444);
 204MODULE_PARM_DESC(mailled, "Set initial state of Mail LED");
 205MODULE_PARM_DESC(brightness, "Set initial LCD backlight brightness");
 206MODULE_PARM_DESC(threeg, "Set initial state of 3G hardware");
 207MODULE_PARM_DESC(force_series, "Force a different laptop series");
 208MODULE_PARM_DESC(ec_raw_mode, "Enable EC raw mode");
 209
 210struct acer_data {
 211        int mailled;
 212        int threeg;
 213        int brightness;
 214};
 215
 216struct acer_debug {
 217        struct dentry *root;
 218        struct dentry *devices;
 219        u32 wmid_devices;
 220};
 221
 222static struct rfkill *wireless_rfkill;
 223static struct rfkill *bluetooth_rfkill;
 224static struct rfkill *threeg_rfkill;
 225
 226/* Each low-level interface must define at least some of the following */
 227struct wmi_interface {
 228        /* The WMI device type */
 229        u32 type;
 230
 231        /* The capabilities this interface provides */
 232        u32 capability;
 233
 234        /* Private data for the current interface */
 235        struct acer_data data;
 236
 237        /* debugfs entries associated with this interface */
 238        struct acer_debug debug;
 239};
 240
 241/* The static interface pointer, points to the currently detected interface */
 242static struct wmi_interface *interface;
 243
 244/*
 245 * Embedded Controller quirks
 246 * Some laptops require us to directly access the EC to either enable or query
 247 * features that are not available through WMI.
 248 */
 249
 250struct quirk_entry {
 251        u8 wireless;
 252        u8 mailled;
 253        s8 brightness;
 254        u8 bluetooth;
 255};
 256
 257static struct quirk_entry *quirks;
 258
 259static void set_quirks(void)
 260{
 261        if (!interface)
 262                return;
 263
 264        if (quirks->mailled)
 265                interface->capability |= ACER_CAP_MAILLED;
 266
 267        if (quirks->brightness)
 268                interface->capability |= ACER_CAP_BRIGHTNESS;
 269}
 270
 271static int dmi_matched(const struct dmi_system_id *dmi)
 272{
 273        quirks = dmi->driver_data;
 274        return 1;
 275}
 276
 277static struct quirk_entry quirk_unknown = {
 278};
 279
 280static struct quirk_entry quirk_acer_aspire_1520 = {
 281        .brightness = -1,
 282};
 283
 284static struct quirk_entry quirk_acer_travelmate_2490 = {
 285        .mailled = 1,
 286};
 287
 288/* This AMW0 laptop has no bluetooth */
 289static struct quirk_entry quirk_medion_md_98300 = {
 290        .wireless = 1,
 291};
 292
 293static struct quirk_entry quirk_fujitsu_amilo_li_1718 = {
 294        .wireless = 2,
 295};
 296
 297/* The Aspire One has a dummy ACPI-WMI interface - disable it */
 298static struct dmi_system_id __devinitdata acer_blacklist[] = {
 299        {
 300                .ident = "Acer Aspire One (SSD)",
 301                .matches = {
 302                        DMI_MATCH(DMI_SYS_VENDOR, "Acer"),
 303                        DMI_MATCH(DMI_PRODUCT_NAME, "AOA110"),
 304                },
 305        },
 306        {
 307                .ident = "Acer Aspire One (HDD)",
 308                .matches = {
 309                        DMI_MATCH(DMI_SYS_VENDOR, "Acer"),
 310                        DMI_MATCH(DMI_PRODUCT_NAME, "AOA150"),
 311                },
 312        },
 313        {}
 314};
 315
 316static struct dmi_system_id acer_quirks[] = {
 317        {
 318                .callback = dmi_matched,
 319                .ident = "Acer Aspire 1360",
 320                .matches = {
 321                        DMI_MATCH(DMI_SYS_VENDOR, "Acer"),
 322                        DMI_MATCH(DMI_PRODUCT_NAME, "Aspire 1360"),
 323                },
 324                .driver_data = &quirk_acer_aspire_1520,
 325        },
 326        {
 327                .callback = dmi_matched,
 328                .ident = "Acer Aspire 1520",
 329                .matches = {
 330                        DMI_MATCH(DMI_SYS_VENDOR, "Acer"),
 331                        DMI_MATCH(DMI_PRODUCT_NAME, "Aspire 1520"),
 332                },
 333                .driver_data = &quirk_acer_aspire_1520,
 334        },
 335        {
 336                .callback = dmi_matched,
 337                .ident = "Acer Aspire 3100",
 338                .matches = {
 339                        DMI_MATCH(DMI_SYS_VENDOR, "Acer"),
 340                        DMI_MATCH(DMI_PRODUCT_NAME, "Aspire 3100"),
 341                },
 342                .driver_data = &quirk_acer_travelmate_2490,
 343        },
 344        {
 345                .callback = dmi_matched,
 346                .ident = "Acer Aspire 3610",
 347                .matches = {
 348                        DMI_MATCH(DMI_SYS_VENDOR, "Acer"),
 349                        DMI_MATCH(DMI_PRODUCT_NAME, "Aspire 3610"),
 350                },
 351                .driver_data = &quirk_acer_travelmate_2490,
 352        },
 353        {
 354                .callback = dmi_matched,
 355                .ident = "Acer Aspire 5100",
 356                .matches = {
 357                        DMI_MATCH(DMI_SYS_VENDOR, "Acer"),
 358                        DMI_MATCH(DMI_PRODUCT_NAME, "Aspire 5100"),
 359                },
 360                .driver_data = &quirk_acer_travelmate_2490,
 361        },
 362        {
 363                .callback = dmi_matched,
 364                .ident = "Acer Aspire 5610",
 365                .matches = {
 366                        DMI_MATCH(DMI_SYS_VENDOR, "Acer"),
 367                        DMI_MATCH(DMI_PRODUCT_NAME, "Aspire 5610"),
 368                },
 369                .driver_data = &quirk_acer_travelmate_2490,
 370        },
 371        {
 372                .callback = dmi_matched,
 373                .ident = "Acer Aspire 5630",
 374                .matches = {
 375                        DMI_MATCH(DMI_SYS_VENDOR, "Acer"),
 376                        DMI_MATCH(DMI_PRODUCT_NAME, "Aspire 5630"),
 377                },
 378                .driver_data = &quirk_acer_travelmate_2490,
 379        },
 380        {
 381                .callback = dmi_matched,
 382                .ident = "Acer Aspire 5650",
 383                .matches = {
 384                        DMI_MATCH(DMI_SYS_VENDOR, "Acer"),
 385                        DMI_MATCH(DMI_PRODUCT_NAME, "Aspire 5650"),
 386                },
 387                .driver_data = &quirk_acer_travelmate_2490,
 388        },
 389        {
 390                .callback = dmi_matched,
 391                .ident = "Acer Aspire 5680",
 392                .matches = {
 393                        DMI_MATCH(DMI_SYS_VENDOR, "Acer"),
 394                        DMI_MATCH(DMI_PRODUCT_NAME, "Aspire 5680"),
 395                },
 396                .driver_data = &quirk_acer_travelmate_2490,
 397        },
 398        {
 399                .callback = dmi_matched,
 400                .ident = "Acer Aspire 9110",
 401                .matches = {
 402                        DMI_MATCH(DMI_SYS_VENDOR, "Acer"),
 403                        DMI_MATCH(DMI_PRODUCT_NAME, "Aspire 9110"),
 404                },
 405                .driver_data = &quirk_acer_travelmate_2490,
 406        },
 407        {
 408                .callback = dmi_matched,
 409                .ident = "Acer TravelMate 2490",
 410                .matches = {
 411                        DMI_MATCH(DMI_SYS_VENDOR, "Acer"),
 412                        DMI_MATCH(DMI_PRODUCT_NAME, "TravelMate 2490"),
 413                },
 414                .driver_data = &quirk_acer_travelmate_2490,
 415        },
 416        {
 417                .callback = dmi_matched,
 418                .ident = "Acer TravelMate 4200",
 419                .matches = {
 420                        DMI_MATCH(DMI_SYS_VENDOR, "Acer"),
 421                        DMI_MATCH(DMI_PRODUCT_NAME, "TravelMate 4200"),
 422                },
 423                .driver_data = &quirk_acer_travelmate_2490,
 424        },
 425        {
 426                .callback = dmi_matched,
 427                .ident = "Fujitsu Siemens Amilo Li 1718",
 428                .matches = {
 429                        DMI_MATCH(DMI_SYS_VENDOR, "FUJITSU SIEMENS"),
 430                        DMI_MATCH(DMI_PRODUCT_NAME, "AMILO Li 1718"),
 431                },
 432                .driver_data = &quirk_fujitsu_amilo_li_1718,
 433        },
 434        {
 435                .callback = dmi_matched,
 436                .ident = "Medion MD 98300",
 437                .matches = {
 438                        DMI_MATCH(DMI_SYS_VENDOR, "MEDION"),
 439                        DMI_MATCH(DMI_PRODUCT_NAME, "WAM2030"),
 440                },
 441                .driver_data = &quirk_medion_md_98300,
 442        },
 443        {}
 444};
 445
 446/* Find which quirks are needed for a particular vendor/ model pair */
 447static void find_quirks(void)
 448{
 449        if (!force_series) {
 450                dmi_check_system(acer_quirks);
 451        } else if (force_series == 2490) {
 452                quirks = &quirk_acer_travelmate_2490;
 453        }
 454
 455        if (quirks == NULL)
 456                quirks = &quirk_unknown;
 457
 458        set_quirks();
 459}
 460
 461/*
 462 * General interface convenience methods
 463 */
 464
 465static bool has_cap(u32 cap)
 466{
 467        if ((interface->capability & cap) != 0)
 468                return 1;
 469
 470        return 0;
 471}
 472
 473/*
 474 * AMW0 (V1) interface
 475 */
 476struct wmab_args {
 477        u32 eax;
 478        u32 ebx;
 479        u32 ecx;
 480        u32 edx;
 481};
 482
 483struct wmab_ret {
 484        u32 eax;
 485        u32 ebx;
 486        u32 ecx;
 487        u32 edx;
 488        u32 eex;
 489};
 490
 491static acpi_status wmab_execute(struct wmab_args *regbuf,
 492struct acpi_buffer *result)
 493{
 494        struct acpi_buffer input;
 495        acpi_status status;
 496        input.length = sizeof(struct wmab_args);
 497        input.pointer = (u8 *)regbuf;
 498
 499        status = wmi_evaluate_method(AMW0_GUID1, 1, 1, &input, result);
 500
 501        return status;
 502}
 503
 504static acpi_status AMW0_get_u32(u32 *value, u32 cap,
 505struct wmi_interface *iface)
 506{
 507        int err;
 508        u8 result;
 509
 510        switch (cap) {
 511        case ACER_CAP_MAILLED:
 512                switch (quirks->mailled) {
 513                default:
 514                        err = ec_read(0xA, &result);
 515                        if (err)
 516                                return AE_ERROR;
 517                        *value = (result >> 7) & 0x1;
 518                        return AE_OK;
 519                }
 520                break;
 521        case ACER_CAP_WIRELESS:
 522                switch (quirks->wireless) {
 523                case 1:
 524                        err = ec_read(0x7B, &result);
 525                        if (err)
 526                                return AE_ERROR;
 527                        *value = result & 0x1;
 528                        return AE_OK;
 529                case 2:
 530                        err = ec_read(0x71, &result);
 531                        if (err)
 532                                return AE_ERROR;
 533                        *value = result & 0x1;
 534                        return AE_OK;
 535                default:
 536                        err = ec_read(0xA, &result);
 537                        if (err)
 538                                return AE_ERROR;
 539                        *value = (result >> 2) & 0x1;
 540                        return AE_OK;
 541                }
 542                break;
 543        case ACER_CAP_BLUETOOTH:
 544                switch (quirks->bluetooth) {
 545                default:
 546                        err = ec_read(0xA, &result);
 547                        if (err)
 548                                return AE_ERROR;
 549                        *value = (result >> 4) & 0x1;
 550                        return AE_OK;
 551                }
 552                break;
 553        case ACER_CAP_BRIGHTNESS:
 554                switch (quirks->brightness) {
 555                default:
 556                        err = ec_read(0x83, &result);
 557                        if (err)
 558                                return AE_ERROR;
 559                        *value = result;
 560                        return AE_OK;
 561                }
 562                break;
 563        default:
 564                return AE_ERROR;
 565        }
 566        return AE_OK;
 567}
 568
 569static acpi_status AMW0_set_u32(u32 value, u32 cap, struct wmi_interface *iface)
 570{
 571        struct wmab_args args;
 572
 573        args.eax = ACER_AMW0_WRITE;
 574        args.ebx = value ? (1<<8) : 0;
 575        args.ecx = args.edx = 0;
 576
 577        switch (cap) {
 578        case ACER_CAP_MAILLED:
 579                if (value > 1)
 580                        return AE_BAD_PARAMETER;
 581                args.ebx |= ACER_AMW0_MAILLED_MASK;
 582                break;
 583        case ACER_CAP_WIRELESS:
 584                if (value > 1)
 585                        return AE_BAD_PARAMETER;
 586                args.ebx |= ACER_AMW0_WIRELESS_MASK;
 587                break;
 588        case ACER_CAP_BLUETOOTH:
 589                if (value > 1)
 590                        return AE_BAD_PARAMETER;
 591                args.ebx |= ACER_AMW0_BLUETOOTH_MASK;
 592                break;
 593        case ACER_CAP_BRIGHTNESS:
 594                if (value > max_brightness)
 595                        return AE_BAD_PARAMETER;
 596                switch (quirks->brightness) {
 597                default:
 598                        return ec_write(0x83, value);
 599                        break;
 600                }
 601        default:
 602                return AE_ERROR;
 603        }
 604
 605        /* Actually do the set */
 606        return wmab_execute(&args, NULL);
 607}
 608
 609static acpi_status AMW0_find_mailled(void)
 610{
 611        struct wmab_args args;
 612        struct wmab_ret ret;
 613        acpi_status status = AE_OK;
 614        struct acpi_buffer out = { ACPI_ALLOCATE_BUFFER, NULL };
 615        union acpi_object *obj;
 616
 617        args.eax = 0x86;
 618        args.ebx = args.ecx = args.edx = 0;
 619
 620        status = wmab_execute(&args, &out);
 621        if (ACPI_FAILURE(status))
 622                return status;
 623
 624        obj = (union acpi_object *) out.pointer;
 625        if (obj && obj->type == ACPI_TYPE_BUFFER &&
 626        obj->buffer.length == sizeof(struct wmab_ret)) {
 627                ret = *((struct wmab_ret *) obj->buffer.pointer);
 628        } else {
 629                kfree(out.pointer);
 630                return AE_ERROR;
 631        }
 632
 633        if (ret.eex & 0x1)
 634                interface->capability |= ACER_CAP_MAILLED;
 635
 636        kfree(out.pointer);
 637
 638        return AE_OK;
 639}
 640
 641static acpi_status AMW0_set_capabilities(void)
 642{
 643        struct wmab_args args;
 644        struct wmab_ret ret;
 645        acpi_status status;
 646        struct acpi_buffer out = { ACPI_ALLOCATE_BUFFER, NULL };
 647        union acpi_object *obj;
 648
 649        /*
 650         * On laptops with this strange GUID (non Acer), normal probing doesn't
 651         * work.
 652         */
 653        if (wmi_has_guid(AMW0_GUID2)) {
 654                interface->capability |= ACER_CAP_WIRELESS;
 655                return AE_OK;
 656        }
 657
 658        args.eax = ACER_AMW0_WRITE;
 659        args.ecx = args.edx = 0;
 660
 661        args.ebx = 0xa2 << 8;
 662        args.ebx |= ACER_AMW0_WIRELESS_MASK;
 663
 664        status = wmab_execute(&args, &out);
 665        if (ACPI_FAILURE(status))
 666                return status;
 667
 668        obj = out.pointer;
 669        if (obj && obj->type == ACPI_TYPE_BUFFER &&
 670        obj->buffer.length == sizeof(struct wmab_ret)) {
 671                ret = *((struct wmab_ret *) obj->buffer.pointer);
 672        } else {
 673                status = AE_ERROR;
 674                goto out;
 675        }
 676
 677        if (ret.eax & 0x1)
 678                interface->capability |= ACER_CAP_WIRELESS;
 679
 680        args.ebx = 2 << 8;
 681        args.ebx |= ACER_AMW0_BLUETOOTH_MASK;
 682
 683        /*
 684         * It's ok to use existing buffer for next wmab_execute call.
 685         * But we need to kfree(out.pointer) if next wmab_execute fail.
 686         */
 687        status = wmab_execute(&args, &out);
 688        if (ACPI_FAILURE(status))
 689                goto out;
 690
 691        obj = (union acpi_object *) out.pointer;
 692        if (obj && obj->type == ACPI_TYPE_BUFFER
 693        && obj->buffer.length == sizeof(struct wmab_ret)) {
 694                ret = *((struct wmab_ret *) obj->buffer.pointer);
 695        } else {
 696                status = AE_ERROR;
 697                goto out;
 698        }
 699
 700        if (ret.eax & 0x1)
 701                interface->capability |= ACER_CAP_BLUETOOTH;
 702
 703        /*
 704         * This appears to be safe to enable, since all Wistron based laptops
 705         * appear to use the same EC register for brightness, even if they
 706         * differ for wireless, etc
 707         */
 708        if (quirks->brightness >= 0)
 709                interface->capability |= ACER_CAP_BRIGHTNESS;
 710
 711        status = AE_OK;
 712out:
 713        kfree(out.pointer);
 714        return status;
 715}
 716
 717static struct wmi_interface AMW0_interface = {
 718        .type = ACER_AMW0,
 719};
 720
 721static struct wmi_interface AMW0_V2_interface = {
 722        .type = ACER_AMW0_V2,
 723};
 724
 725/*
 726 * New interface (The WMID interface)
 727 */
 728static acpi_status
 729WMI_execute_u32(u32 method_id, u32 in, u32 *out)
 730{
 731        struct acpi_buffer input = { (acpi_size) sizeof(u32), (void *)(&in) };
 732        struct acpi_buffer result = { ACPI_ALLOCATE_BUFFER, NULL };
 733        union acpi_object *obj;
 734        u32 tmp;
 735        acpi_status status;
 736
 737        status = wmi_evaluate_method(WMID_GUID1, 1, method_id, &input, &result);
 738
 739        if (ACPI_FAILURE(status))
 740                return status;
 741
 742        obj = (union acpi_object *) result.pointer;
 743        if (obj && obj->type == ACPI_TYPE_BUFFER &&
 744                obj->buffer.length == sizeof(u32)) {
 745                tmp = *((u32 *) obj->buffer.pointer);
 746        } else {
 747                tmp = 0;
 748        }
 749
 750        if (out)
 751                *out = tmp;
 752
 753        kfree(result.pointer);
 754
 755        return status;
 756}
 757
 758static acpi_status WMID_get_u32(u32 *value, u32 cap,
 759struct wmi_interface *iface)
 760{
 761        acpi_status status;
 762        u8 tmp;
 763        u32 result, method_id = 0;
 764
 765        switch (cap) {
 766        case ACER_CAP_WIRELESS:
 767                method_id = ACER_WMID_GET_WIRELESS_METHODID;
 768                break;
 769        case ACER_CAP_BLUETOOTH:
 770                method_id = ACER_WMID_GET_BLUETOOTH_METHODID;
 771                break;
 772        case ACER_CAP_BRIGHTNESS:
 773                method_id = ACER_WMID_GET_BRIGHTNESS_METHODID;
 774                break;
 775        case ACER_CAP_THREEG:
 776                method_id = ACER_WMID_GET_THREEG_METHODID;
 777                break;
 778        case ACER_CAP_MAILLED:
 779                if (quirks->mailled == 1) {
 780                        ec_read(0x9f, &tmp);
 781                        *value = tmp & 0x1;
 782                        return 0;
 783                }
 784        default:
 785                return AE_ERROR;
 786        }
 787        status = WMI_execute_u32(method_id, 0, &result);
 788
 789        if (ACPI_SUCCESS(status))
 790                *value = (u8)result;
 791
 792        return status;
 793}
 794
 795static acpi_status WMID_set_u32(u32 value, u32 cap, struct wmi_interface *iface)
 796{
 797        u32 method_id = 0;
 798        char param;
 799
 800        switch (cap) {
 801        case ACER_CAP_BRIGHTNESS:
 802                if (value > max_brightness)
 803                        return AE_BAD_PARAMETER;
 804                method_id = ACER_WMID_SET_BRIGHTNESS_METHODID;
 805                break;
 806        case ACER_CAP_WIRELESS:
 807                if (value > 1)
 808                        return AE_BAD_PARAMETER;
 809                method_id = ACER_WMID_SET_WIRELESS_METHODID;
 810                break;
 811        case ACER_CAP_BLUETOOTH:
 812                if (value > 1)
 813                        return AE_BAD_PARAMETER;
 814                method_id = ACER_WMID_SET_BLUETOOTH_METHODID;
 815                break;
 816        case ACER_CAP_THREEG:
 817                if (value > 1)
 818                        return AE_BAD_PARAMETER;
 819                method_id = ACER_WMID_SET_THREEG_METHODID;
 820                break;
 821        case ACER_CAP_MAILLED:
 822                if (value > 1)
 823                        return AE_BAD_PARAMETER;
 824                if (quirks->mailled == 1) {
 825                        param = value ? 0x92 : 0x93;
 826                        i8042_lock_chip();
 827                        i8042_command(&param, 0x1059);
 828                        i8042_unlock_chip();
 829                        return 0;
 830                }
 831                break;
 832        default:
 833                return AE_ERROR;
 834        }
 835        return WMI_execute_u32(method_id, (u32)value, NULL);
 836}
 837
 838static void type_aa_dmi_decode(const struct dmi_header *header, void *dummy)
 839{
 840        struct hotkey_function_type_aa *type_aa;
 841
 842        /* We are looking for OEM-specific Type AAh */
 843        if (header->type != 0xAA)
 844                return;
 845
 846        has_type_aa = true;
 847        type_aa = (struct hotkey_function_type_aa *) header;
 848
 849        printk(ACER_INFO "Function bitmap for Communication Button: 0x%x\n",
 850                type_aa->commun_func_bitmap);
 851
 852        if (type_aa->commun_func_bitmap & ACER_WMID3_GDS_WIRELESS)
 853                interface->capability |= ACER_CAP_WIRELESS;
 854        if (type_aa->commun_func_bitmap & ACER_WMID3_GDS_THREEG)
 855                interface->capability |= ACER_CAP_THREEG;
 856        if (type_aa->commun_func_bitmap & ACER_WMID3_GDS_BLUETOOTH)
 857                interface->capability |= ACER_CAP_BLUETOOTH;
 858}
 859
 860static acpi_status WMID_set_capabilities(void)
 861{
 862        struct acpi_buffer out = {ACPI_ALLOCATE_BUFFER, NULL};
 863        union acpi_object *obj;
 864        acpi_status status;
 865        u32 devices;
 866
 867        status = wmi_query_block(WMID_GUID2, 1, &out);
 868        if (ACPI_FAILURE(status))
 869                return status;
 870
 871        obj = (union acpi_object *) out.pointer;
 872        if (obj && obj->type == ACPI_TYPE_BUFFER &&
 873                obj->buffer.length == sizeof(u32)) {
 874                devices = *((u32 *) obj->buffer.pointer);
 875        } else {
 876                kfree(out.pointer);
 877                return AE_ERROR;
 878        }
 879
 880        dmi_walk(type_aa_dmi_decode, NULL);
 881        if (!has_type_aa) {
 882                interface->capability |= ACER_CAP_WIRELESS;
 883                interface->capability |= ACER_CAP_THREEG;
 884                if (devices & 0x10)
 885                        interface->capability |= ACER_CAP_BLUETOOTH;
 886        }
 887
 888        /* WMID always provides brightness methods */
 889        interface->capability |= ACER_CAP_BRIGHTNESS;
 890
 891        if (!(devices & 0x20))
 892                max_brightness = 0x9;
 893
 894        kfree(out.pointer);
 895        return status;
 896}
 897
 898static struct wmi_interface wmid_interface = {
 899        .type = ACER_WMID,
 900};
 901
 902/*
 903 * Generic Device (interface-independent)
 904 */
 905
 906static acpi_status get_u32(u32 *value, u32 cap)
 907{
 908        acpi_status status = AE_ERROR;
 909
 910        switch (interface->type) {
 911        case ACER_AMW0:
 912                status = AMW0_get_u32(value, cap, interface);
 913                break;
 914        case ACER_AMW0_V2:
 915                if (cap == ACER_CAP_MAILLED) {
 916                        status = AMW0_get_u32(value, cap, interface);
 917                        break;
 918                }
 919        case ACER_WMID:
 920                status = WMID_get_u32(value, cap, interface);
 921                break;
 922        }
 923
 924        return status;
 925}
 926
 927static acpi_status set_u32(u32 value, u32 cap)
 928{
 929        acpi_status status;
 930
 931        if (interface->capability & cap) {
 932                switch (interface->type) {
 933                case ACER_AMW0:
 934                        return AMW0_set_u32(value, cap, interface);
 935                case ACER_AMW0_V2:
 936                        if (cap == ACER_CAP_MAILLED)
 937                                return AMW0_set_u32(value, cap, interface);
 938
 939                        /*
 940                         * On some models, some WMID methods don't toggle
 941                         * properly. For those cases, we want to run the AMW0
 942                         * method afterwards to be certain we've really toggled
 943                         * the device state.
 944                         */
 945                        if (cap == ACER_CAP_WIRELESS ||
 946                                cap == ACER_CAP_BLUETOOTH) {
 947                                status = WMID_set_u32(value, cap, interface);
 948                                if (ACPI_FAILURE(status))
 949                                        return status;
 950
 951                                return AMW0_set_u32(value, cap, interface);
 952                        }
 953                case ACER_WMID:
 954                        return WMID_set_u32(value, cap, interface);
 955                default:
 956                        return AE_BAD_PARAMETER;
 957                }
 958        }
 959        return AE_BAD_PARAMETER;
 960}
 961
 962static void __init acer_commandline_init(void)
 963{
 964        /*
 965         * These will all fail silently if the value given is invalid, or the
 966         * capability isn't available on the given interface
 967         */
 968        set_u32(mailled, ACER_CAP_MAILLED);
 969        if (!has_type_aa)
 970                set_u32(threeg, ACER_CAP_THREEG);
 971        set_u32(brightness, ACER_CAP_BRIGHTNESS);
 972}
 973
 974/*
 975 * LED device (Mail LED only, no other LEDs known yet)
 976 */
 977static void mail_led_set(struct led_classdev *led_cdev,
 978enum led_brightness value)
 979{
 980        set_u32(value, ACER_CAP_MAILLED);
 981}
 982
 983static struct led_classdev mail_led = {
 984        .name = "acer-wmi::mail",
 985        .brightness_set = mail_led_set,
 986};
 987
 988static int __devinit acer_led_init(struct device *dev)
 989{
 990        return led_classdev_register(dev, &mail_led);
 991}
 992
 993static void acer_led_exit(void)
 994{
 995        led_classdev_unregister(&mail_led);
 996}
 997
 998/*
 999 * Backlight device
1000 */
1001static struct backlight_device *acer_backlight_device;
1002
1003static int read_brightness(struct backlight_device *bd)
1004{
1005        u32 value;
1006        get_u32(&value, ACER_CAP_BRIGHTNESS);
1007        return value;
1008}
1009
1010static int update_bl_status(struct backlight_device *bd)
1011{
1012        int intensity = bd->props.brightness;
1013
1014        if (bd->props.power != FB_BLANK_UNBLANK)
1015                intensity = 0;
1016        if (bd->props.fb_blank != FB_BLANK_UNBLANK)
1017                intensity = 0;
1018
1019        set_u32(intensity, ACER_CAP_BRIGHTNESS);
1020
1021        return 0;
1022}
1023
1024static const struct backlight_ops acer_bl_ops = {
1025        .get_brightness = read_brightness,
1026        .update_status = update_bl_status,
1027};
1028
1029static int __devinit acer_backlight_init(struct device *dev)
1030{
1031        struct backlight_properties props;
1032        struct backlight_device *bd;
1033
1034        memset(&props, 0, sizeof(struct backlight_properties));
1035        props.max_brightness = max_brightness;
1036        bd = backlight_device_register("acer-wmi", dev, NULL, &acer_bl_ops,
1037                                       &props);
1038        if (IS_ERR(bd)) {
1039                printk(ACER_ERR "Could not register Acer backlight device\n");
1040                acer_backlight_device = NULL;
1041                return PTR_ERR(bd);
1042        }
1043
1044        acer_backlight_device = bd;
1045
1046        bd->props.power = FB_BLANK_UNBLANK;
1047        bd->props.brightness = read_brightness(bd);
1048        backlight_update_status(bd);
1049        return 0;
1050}
1051
1052static void acer_backlight_exit(void)
1053{
1054        backlight_device_unregister(acer_backlight_device);
1055}
1056
1057static acpi_status wmid3_get_device_status(u32 *value, u16 device)
1058{
1059        struct wmid3_gds_return_value return_value;
1060        acpi_status status;
1061        union acpi_object *obj;
1062        struct wmid3_gds_input_param params = {
1063                .function_num = 0x1,
1064                .hotkey_number = 0x01,
1065                .devices = device,
1066        };
1067        struct acpi_buffer input = {
1068                sizeof(struct wmid3_gds_input_param),
1069                &params
1070        };
1071        struct acpi_buffer output = { ACPI_ALLOCATE_BUFFER, NULL };
1072
1073        status = wmi_evaluate_method(WMID_GUID3, 0, 0x2, &input, &output);
1074        if (ACPI_FAILURE(status))
1075                return status;
1076
1077        obj = output.pointer;
1078
1079        if (!obj)
1080                return AE_ERROR;
1081        else if (obj->type != ACPI_TYPE_BUFFER) {
1082                kfree(obj);
1083                return AE_ERROR;
1084        }
1085        if (obj->buffer.length != 8) {
1086                printk(ACER_WARNING "Unknown buffer length %d\n",
1087                        obj->buffer.length);
1088                kfree(obj);
1089                return AE_ERROR;
1090        }
1091
1092        return_value = *((struct wmid3_gds_return_value *)obj->buffer.pointer);
1093        kfree(obj);
1094
1095        if (return_value.error_code || return_value.ec_return_value)
1096                printk(ACER_WARNING "Get Device Status failed: "
1097                        "0x%x - 0x%x\n", return_value.error_code,
1098                        return_value.ec_return_value);
1099        else
1100                *value = !!(return_value.devices & device);
1101
1102        return status;
1103}
1104
1105static acpi_status get_device_status(u32 *value, u32 cap)
1106{
1107        if (wmi_has_guid(WMID_GUID3)) {
1108                u16 device;
1109
1110                switch (cap) {
1111                case ACER_CAP_WIRELESS:
1112                        device = ACER_WMID3_GDS_WIRELESS;
1113                        break;
1114                case ACER_CAP_BLUETOOTH:
1115                        device = ACER_WMID3_GDS_BLUETOOTH;
1116                        break;
1117                case ACER_CAP_THREEG:
1118                        device = ACER_WMID3_GDS_THREEG;
1119                        break;
1120                default:
1121                        return AE_ERROR;
1122                }
1123                return wmid3_get_device_status(value, device);
1124
1125        } else {
1126                return get_u32(value, cap);
1127        }
1128}
1129
1130/*
1131 * Rfkill devices
1132 */
1133static void acer_rfkill_update(struct work_struct *ignored);
1134static DECLARE_DELAYED_WORK(acer_rfkill_work, acer_rfkill_update);
1135static void acer_rfkill_update(struct work_struct *ignored)
1136{
1137        u32 state;
1138        acpi_status status;
1139
1140        status = get_u32(&state, ACER_CAP_WIRELESS);
1141        if (ACPI_SUCCESS(status))
1142                rfkill_set_sw_state(wireless_rfkill, !state);
1143
1144        if (has_cap(ACER_CAP_BLUETOOTH)) {
1145                status = get_u32(&state, ACER_CAP_BLUETOOTH);
1146                if (ACPI_SUCCESS(status))
1147                        rfkill_set_sw_state(bluetooth_rfkill, !state);
1148        }
1149
1150        if (has_cap(ACER_CAP_THREEG) && wmi_has_guid(WMID_GUID3)) {
1151                status = wmid3_get_device_status(&state,
1152                                ACER_WMID3_GDS_THREEG);
1153                if (ACPI_SUCCESS(status))
1154                        rfkill_set_sw_state(threeg_rfkill, !state);
1155        }
1156
1157        schedule_delayed_work(&acer_rfkill_work, round_jiffies_relative(HZ));
1158}
1159
1160static int acer_rfkill_set(void *data, bool blocked)
1161{
1162        acpi_status status;
1163        u32 cap = (unsigned long)data;
1164        status = set_u32(!blocked, cap);
1165        if (ACPI_FAILURE(status))
1166                return -ENODEV;
1167        return 0;
1168}
1169
1170static const struct rfkill_ops acer_rfkill_ops = {
1171        .set_block = acer_rfkill_set,
1172};
1173
1174static struct rfkill *acer_rfkill_register(struct device *dev,
1175                                           enum rfkill_type type,
1176                                           char *name, u32 cap)
1177{
1178        int err;
1179        struct rfkill *rfkill_dev;
1180        u32 state;
1181        acpi_status status;
1182
1183        rfkill_dev = rfkill_alloc(name, dev, type,
1184                                  &acer_rfkill_ops,
1185                                  (void *)(unsigned long)cap);
1186        if (!rfkill_dev)
1187                return ERR_PTR(-ENOMEM);
1188
1189        status = get_device_status(&state, cap);
1190        if (ACPI_SUCCESS(status))
1191                rfkill_init_sw_state(rfkill_dev, !state);
1192
1193        err = rfkill_register(rfkill_dev);
1194        if (err) {
1195                rfkill_destroy(rfkill_dev);
1196                return ERR_PTR(err);
1197        }
1198        return rfkill_dev;
1199}
1200
1201static int acer_rfkill_init(struct device *dev)
1202{
1203        wireless_rfkill = acer_rfkill_register(dev, RFKILL_TYPE_WLAN,
1204                "acer-wireless", ACER_CAP_WIRELESS);
1205        if (IS_ERR(wireless_rfkill))
1206                return PTR_ERR(wireless_rfkill);
1207
1208        if (has_cap(ACER_CAP_BLUETOOTH)) {
1209                bluetooth_rfkill = acer_rfkill_register(dev,
1210                        RFKILL_TYPE_BLUETOOTH, "acer-bluetooth",
1211                        ACER_CAP_BLUETOOTH);
1212                if (IS_ERR(bluetooth_rfkill)) {
1213                        rfkill_unregister(wireless_rfkill);
1214                        rfkill_destroy(wireless_rfkill);
1215                        return PTR_ERR(bluetooth_rfkill);
1216                }
1217        }
1218
1219        if (has_cap(ACER_CAP_THREEG)) {
1220                threeg_rfkill = acer_rfkill_register(dev,
1221                        RFKILL_TYPE_WWAN, "acer-threeg",
1222                        ACER_CAP_THREEG);
1223                if (IS_ERR(threeg_rfkill)) {
1224                        rfkill_unregister(wireless_rfkill);
1225                        rfkill_destroy(wireless_rfkill);
1226                        rfkill_unregister(bluetooth_rfkill);
1227                        rfkill_destroy(bluetooth_rfkill);
1228                        return PTR_ERR(threeg_rfkill);
1229                }
1230        }
1231
1232        schedule_delayed_work(&acer_rfkill_work, round_jiffies_relative(HZ));
1233
1234        return 0;
1235}
1236
1237static void acer_rfkill_exit(void)
1238{
1239        cancel_delayed_work_sync(&acer_rfkill_work);
1240
1241        rfkill_unregister(wireless_rfkill);
1242        rfkill_destroy(wireless_rfkill);
1243
1244        if (has_cap(ACER_CAP_BLUETOOTH)) {
1245                rfkill_unregister(bluetooth_rfkill);
1246                rfkill_destroy(bluetooth_rfkill);
1247        }
1248
1249        if (has_cap(ACER_CAP_THREEG)) {
1250                rfkill_unregister(threeg_rfkill);
1251                rfkill_destroy(threeg_rfkill);
1252        }
1253        return;
1254}
1255
1256/*
1257 * sysfs interface
1258 */
1259static ssize_t show_bool_threeg(struct device *dev,
1260        struct device_attribute *attr, char *buf)
1261{
1262        u32 result; \
1263        acpi_status status;
1264        if (wmi_has_guid(WMID_GUID3))
1265                status = wmid3_get_device_status(&result,
1266                                ACER_WMID3_GDS_THREEG);
1267        else
1268                status = get_u32(&result, ACER_CAP_THREEG);
1269        if (ACPI_SUCCESS(status))
1270                return sprintf(buf, "%u\n", result);
1271        return sprintf(buf, "Read error\n");
1272}
1273
1274static ssize_t set_bool_threeg(struct device *dev,
1275        struct device_attribute *attr, const char *buf, size_t count)
1276{
1277        u32 tmp = simple_strtoul(buf, NULL, 10);
1278        acpi_status status = set_u32(tmp, ACER_CAP_THREEG);
1279                if (ACPI_FAILURE(status))
1280                        return -EINVAL;
1281        return count;
1282}
1283static DEVICE_ATTR(threeg, S_IRUGO | S_IWUSR, show_bool_threeg,
1284        set_bool_threeg);
1285
1286static ssize_t show_interface(struct device *dev, struct device_attribute *attr,
1287        char *buf)
1288{
1289        switch (interface->type) {
1290        case ACER_AMW0:
1291                return sprintf(buf, "AMW0\n");
1292        case ACER_AMW0_V2:
1293                return sprintf(buf, "AMW0 v2\n");
1294        case ACER_WMID:
1295                return sprintf(buf, "WMID\n");
1296        default:
1297                return sprintf(buf, "Error!\n");
1298        }
1299}
1300
1301static DEVICE_ATTR(interface, S_IRUGO, show_interface, NULL);
1302
1303static void acer_wmi_notify(u32 value, void *context)
1304{
1305        struct acpi_buffer response = { ACPI_ALLOCATE_BUFFER, NULL };
1306        union acpi_object *obj;
1307        struct event_return_value return_value;
1308        acpi_status status;
1309
1310        status = wmi_get_event_data(value, &response);
1311        if (status != AE_OK) {
1312                printk(ACER_WARNING "bad event status 0x%x\n", status);
1313                return;
1314        }
1315
1316        obj = (union acpi_object *)response.pointer;
1317
1318        if (!obj)
1319                return;
1320        if (obj->type != ACPI_TYPE_BUFFER) {
1321                printk(ACER_WARNING "Unknown response received %d\n",
1322                        obj->type);
1323                kfree(obj);
1324                return;
1325        }
1326        if (obj->buffer.length != 8) {
1327                printk(ACER_WARNING "Unknown buffer length %d\n",
1328                        obj->buffer.length);
1329                kfree(obj);
1330                return;
1331        }
1332
1333        return_value = *((struct event_return_value *)obj->buffer.pointer);
1334        kfree(obj);
1335
1336        switch (return_value.function) {
1337        case WMID_HOTKEY_EVENT:
1338                if (!sparse_keymap_report_event(acer_wmi_input_dev,
1339                                return_value.key_num, 1, true))
1340                        printk(ACER_WARNING "Unknown key number - 0x%x\n",
1341                                return_value.key_num);
1342                break;
1343        default:
1344                printk(ACER_WARNING "Unknown function number - %d - %d\n",
1345                        return_value.function, return_value.key_num);
1346                break;
1347        }
1348}
1349
1350static acpi_status
1351wmid3_set_lm_mode(struct lm_input_params *params,
1352                  struct lm_return_value *return_value)
1353{
1354        acpi_status status;
1355        union acpi_object *obj;
1356
1357        struct acpi_buffer input = { sizeof(struct lm_input_params), params };
1358        struct acpi_buffer output = { ACPI_ALLOCATE_BUFFER, NULL };
1359
1360        status = wmi_evaluate_method(WMID_GUID3, 0, 0x1, &input, &output);
1361        if (ACPI_FAILURE(status))
1362                return status;
1363
1364        obj = output.pointer;
1365
1366        if (!obj)
1367                return AE_ERROR;
1368        else if (obj->type != ACPI_TYPE_BUFFER) {
1369                kfree(obj);
1370                return AE_ERROR;
1371        }
1372        if (obj->buffer.length != 4) {
1373                printk(ACER_WARNING "Unknown buffer length %d\n",
1374                       obj->buffer.length);
1375                kfree(obj);
1376                return AE_ERROR;
1377        }
1378
1379        *return_value = *((struct lm_return_value *)obj->buffer.pointer);
1380        kfree(obj);
1381
1382        return status;
1383}
1384
1385static int acer_wmi_enable_ec_raw(void)
1386{
1387        struct lm_return_value return_value;
1388        acpi_status status;
1389        struct lm_input_params params = {
1390                .function_num = 0x1,
1391                .commun_devices = 0xFFFF,
1392                .devices = 0xFFFF,
1393                .lm_status = 0x00,            /* Launch Manager Deactive */
1394        };
1395
1396        status = wmid3_set_lm_mode(&params, &return_value);
1397
1398        if (return_value.error_code || return_value.ec_return_value)
1399                printk(ACER_WARNING "Enabling EC raw mode failed: "
1400                       "0x%x - 0x%x\n", return_value.error_code,
1401                       return_value.ec_return_value);
1402        else
1403                printk(ACER_INFO "Enabled EC raw mode");
1404
1405        return status;
1406}
1407
1408static int acer_wmi_enable_lm(void)
1409{
1410        struct lm_return_value return_value;
1411        acpi_status status;
1412        struct lm_input_params params = {
1413                .function_num = 0x1,
1414                .commun_devices = 0xFFFF,
1415                .devices = 0xFFFF,
1416                .lm_status = 0x01,            /* Launch Manager Active */
1417        };
1418
1419        status = wmid3_set_lm_mode(&params, &return_value);
1420
1421        if (return_value.error_code || return_value.ec_return_value)
1422                printk(ACER_WARNING "Enabling Launch Manager failed: "
1423                       "0x%x - 0x%x\n", return_value.error_code,
1424                       return_value.ec_return_value);
1425
1426        return status;
1427}
1428
1429static int __init acer_wmi_input_setup(void)
1430{
1431        acpi_status status;
1432        int err;
1433
1434        acer_wmi_input_dev = input_allocate_device();
1435        if (!acer_wmi_input_dev)
1436                return -ENOMEM;
1437
1438        acer_wmi_input_dev->name = "Acer WMI hotkeys";
1439        acer_wmi_input_dev->phys = "wmi/input0";
1440        acer_wmi_input_dev->id.bustype = BUS_HOST;
1441
1442        err = sparse_keymap_setup(acer_wmi_input_dev, acer_wmi_keymap, NULL);
1443        if (err)
1444                goto err_free_dev;
1445
1446        status = wmi_install_notify_handler(ACERWMID_EVENT_GUID,
1447                                                acer_wmi_notify, NULL);
1448        if (ACPI_FAILURE(status)) {
1449                err = -EIO;
1450                goto err_free_keymap;
1451        }
1452
1453        err = input_register_device(acer_wmi_input_dev);
1454        if (err)
1455                goto err_uninstall_notifier;
1456
1457        return 0;
1458
1459err_uninstall_notifier:
1460        wmi_remove_notify_handler(ACERWMID_EVENT_GUID);
1461err_free_keymap:
1462        sparse_keymap_free(acer_wmi_input_dev);
1463err_free_dev:
1464        input_free_device(acer_wmi_input_dev);
1465        return err;
1466}
1467
1468static void acer_wmi_input_destroy(void)
1469{
1470        wmi_remove_notify_handler(ACERWMID_EVENT_GUID);
1471        sparse_keymap_free(acer_wmi_input_dev);
1472        input_unregister_device(acer_wmi_input_dev);
1473}
1474
1475/*
1476 * debugfs functions
1477 */
1478static u32 get_wmid_devices(void)
1479{
1480        struct acpi_buffer out = {ACPI_ALLOCATE_BUFFER, NULL};
1481        union acpi_object *obj;
1482        acpi_status status;
1483        u32 devices = 0;
1484
1485        status = wmi_query_block(WMID_GUID2, 1, &out);
1486        if (ACPI_FAILURE(status))
1487                return 0;
1488
1489        obj = (union acpi_object *) out.pointer;
1490        if (obj && obj->type == ACPI_TYPE_BUFFER &&
1491                obj->buffer.length == sizeof(u32)) {
1492                devices = *((u32 *) obj->buffer.pointer);
1493        }
1494
1495        kfree(out.pointer);
1496        return devices;
1497}
1498
1499/*
1500 * Platform device
1501 */
1502static int __devinit acer_platform_probe(struct platform_device *device)
1503{
1504        int err;
1505
1506        if (has_cap(ACER_CAP_MAILLED)) {
1507                err = acer_led_init(&device->dev);
1508                if (err)
1509                        goto error_mailled;
1510        }
1511
1512        if (has_cap(ACER_CAP_BRIGHTNESS)) {
1513                err = acer_backlight_init(&device->dev);
1514                if (err)
1515                        goto error_brightness;
1516        }
1517
1518        err = acer_rfkill_init(&device->dev);
1519        if (err)
1520                goto error_rfkill;
1521
1522        return err;
1523
1524error_rfkill:
1525        if (has_cap(ACER_CAP_BRIGHTNESS))
1526                acer_backlight_exit();
1527error_brightness:
1528        if (has_cap(ACER_CAP_MAILLED))
1529                acer_led_exit();
1530error_mailled:
1531        return err;
1532}
1533
1534static int acer_platform_remove(struct platform_device *device)
1535{
1536        if (has_cap(ACER_CAP_MAILLED))
1537                acer_led_exit();
1538        if (has_cap(ACER_CAP_BRIGHTNESS))
1539                acer_backlight_exit();
1540
1541        acer_rfkill_exit();
1542        return 0;
1543}
1544
1545static int acer_platform_suspend(struct platform_device *dev,
1546pm_message_t state)
1547{
1548        u32 value;
1549        struct acer_data *data = &interface->data;
1550
1551        if (!data)
1552                return -ENOMEM;
1553
1554        if (has_cap(ACER_CAP_MAILLED)) {
1555                get_u32(&value, ACER_CAP_MAILLED);
1556                data->mailled = value;
1557        }
1558
1559        if (has_cap(ACER_CAP_BRIGHTNESS)) {
1560                get_u32(&value, ACER_CAP_BRIGHTNESS);
1561                data->brightness = value;
1562        }
1563
1564        return 0;
1565}
1566
1567static int acer_platform_resume(struct platform_device *device)
1568{
1569        struct acer_data *data = &interface->data;
1570
1571        if (!data)
1572                return -ENOMEM;
1573
1574        if (has_cap(ACER_CAP_MAILLED))
1575                set_u32(data->mailled, ACER_CAP_MAILLED);
1576
1577        if (has_cap(ACER_CAP_BRIGHTNESS))
1578                set_u32(data->brightness, ACER_CAP_BRIGHTNESS);
1579
1580        return 0;
1581}
1582
1583static struct platform_driver acer_platform_driver = {
1584        .driver = {
1585                .name = "acer-wmi",
1586                .owner = THIS_MODULE,
1587        },
1588        .probe = acer_platform_probe,
1589        .remove = acer_platform_remove,
1590        .suspend = acer_platform_suspend,
1591        .resume = acer_platform_resume,
1592};
1593
1594static struct platform_device *acer_platform_device;
1595
1596static int remove_sysfs(struct platform_device *device)
1597{
1598        if (has_cap(ACER_CAP_THREEG))
1599                device_remove_file(&device->dev, &dev_attr_threeg);
1600
1601        device_remove_file(&device->dev, &dev_attr_interface);
1602
1603        return 0;
1604}
1605
1606static int create_sysfs(void)
1607{
1608        int retval = -ENOMEM;
1609
1610        if (has_cap(ACER_CAP_THREEG)) {
1611                retval = device_create_file(&acer_platform_device->dev,
1612                        &dev_attr_threeg);
1613                if (retval)
1614                        goto error_sysfs;
1615        }
1616
1617        retval = device_create_file(&acer_platform_device->dev,
1618                &dev_attr_interface);
1619        if (retval)
1620                goto error_sysfs;
1621
1622        return 0;
1623
1624error_sysfs:
1625                remove_sysfs(acer_platform_device);
1626        return retval;
1627}
1628
1629static void remove_debugfs(void)
1630{
1631        debugfs_remove(interface->debug.devices);
1632        debugfs_remove(interface->debug.root);
1633}
1634
1635static int create_debugfs(void)
1636{
1637        interface->debug.root = debugfs_create_dir("acer-wmi", NULL);
1638        if (!interface->debug.root) {
1639                printk(ACER_ERR "Failed to create debugfs directory");
1640                return -ENOMEM;
1641        }
1642
1643        interface->debug.devices = debugfs_create_u32("devices", S_IRUGO,
1644                                        interface->debug.root,
1645                                        &interface->debug.wmid_devices);
1646        if (!interface->debug.devices)
1647                goto error_debugfs;
1648
1649        return 0;
1650
1651error_debugfs:
1652        remove_debugfs();
1653        return -ENOMEM;
1654}
1655
1656static int __init acer_wmi_init(void)
1657{
1658        int err;
1659
1660        printk(ACER_INFO "Acer Laptop ACPI-WMI Extras\n");
1661
1662        if (dmi_check_system(acer_blacklist)) {
1663                printk(ACER_INFO "Blacklisted hardware detected - "
1664                                "not loading\n");
1665                return -ENODEV;
1666        }
1667
1668        find_quirks();
1669
1670        /*
1671         * Detect which ACPI-WMI interface we're using.
1672         */
1673        if (wmi_has_guid(AMW0_GUID1) && wmi_has_guid(WMID_GUID1))
1674                interface = &AMW0_V2_interface;
1675
1676        if (!wmi_has_guid(AMW0_GUID1) && wmi_has_guid(WMID_GUID1))
1677                interface = &wmid_interface;
1678
1679        if (wmi_has_guid(WMID_GUID2) && interface) {
1680                if (ACPI_FAILURE(WMID_set_capabilities())) {
1681                        printk(ACER_ERR "Unable to detect available WMID "
1682                                        "devices\n");
1683                        return -ENODEV;
1684                }
1685        } else if (!wmi_has_guid(WMID_GUID2) && interface) {
1686                printk(ACER_ERR "No WMID device detection method found\n");
1687                return -ENODEV;
1688        }
1689
1690        if (wmi_has_guid(AMW0_GUID1) && !wmi_has_guid(WMID_GUID1)) {
1691                interface = &AMW0_interface;
1692
1693                if (ACPI_FAILURE(AMW0_set_capabilities())) {
1694                        printk(ACER_ERR "Unable to detect available AMW0 "
1695                                        "devices\n");
1696                        return -ENODEV;
1697                }
1698        }
1699
1700        if (wmi_has_guid(AMW0_GUID1))
1701                AMW0_find_mailled();
1702
1703        if (!interface) {
1704                printk(ACER_INFO "No or unsupported WMI interface, unable to "
1705                                "load\n");
1706                return -ENODEV;
1707        }
1708
1709        set_quirks();
1710
1711        if (acpi_video_backlight_support() && has_cap(ACER_CAP_BRIGHTNESS)) {
1712                interface->capability &= ~ACER_CAP_BRIGHTNESS;
1713                printk(ACER_INFO "Brightness must be controlled by "
1714                       "generic video driver\n");
1715        }
1716
1717        if (wmi_has_guid(WMID_GUID3)) {
1718                if (ec_raw_mode) {
1719                        if (ACPI_FAILURE(acer_wmi_enable_ec_raw())) {
1720                                printk(ACER_ERR "Cannot enable EC raw mode\n");
1721                                return -ENODEV;
1722                        }
1723                } else if (ACPI_FAILURE(acer_wmi_enable_lm())) {
1724                        printk(ACER_ERR "Cannot enable Launch Manager mode\n");
1725                        return -ENODEV;
1726                }
1727        } else if (ec_raw_mode) {
1728                printk(ACER_INFO "No WMID EC raw mode enable method\n");
1729        }
1730
1731        if (wmi_has_guid(ACERWMID_EVENT_GUID)) {
1732                err = acer_wmi_input_setup();
1733                if (err)
1734                        return err;
1735        }
1736
1737        err = platform_driver_register(&acer_platform_driver);
1738        if (err) {
1739                printk(ACER_ERR "Unable to register platform driver.\n");
1740                goto error_platform_register;
1741        }
1742
1743        acer_platform_device = platform_device_alloc("acer-wmi", -1);
1744        if (!acer_platform_device) {
1745                err = -ENOMEM;
1746                goto error_device_alloc;
1747        }
1748
1749        err = platform_device_add(acer_platform_device);
1750        if (err)
1751                goto error_device_add;
1752
1753        err = create_sysfs();
1754        if (err)
1755                goto error_create_sys;
1756
1757        if (wmi_has_guid(WMID_GUID2)) {
1758                interface->debug.wmid_devices = get_wmid_devices();
1759                err = create_debugfs();
1760                if (err)
1761                        goto error_create_debugfs;
1762        }
1763
1764        /* Override any initial settings with values from the commandline */
1765        acer_commandline_init();
1766
1767        return 0;
1768
1769error_create_debugfs:
1770        remove_sysfs(acer_platform_device);
1771error_create_sys:
1772        platform_device_del(acer_platform_device);
1773error_device_add:
1774        platform_device_put(acer_platform_device);
1775error_device_alloc:
1776        platform_driver_unregister(&acer_platform_driver);
1777error_platform_register:
1778        if (wmi_has_guid(ACERWMID_EVENT_GUID))
1779                acer_wmi_input_destroy();
1780
1781        return err;
1782}
1783
1784static void __exit acer_wmi_exit(void)
1785{
1786        if (wmi_has_guid(ACERWMID_EVENT_GUID))
1787                acer_wmi_input_destroy();
1788
1789        remove_sysfs(acer_platform_device);
1790        remove_debugfs();
1791        platform_device_unregister(acer_platform_device);
1792        platform_driver_unregister(&acer_platform_driver);
1793
1794        printk(ACER_INFO "Acer Laptop WMI Extras unloaded\n");
1795        return;
1796}
1797
1798module_init(acer_wmi_init);
1799module_exit(acer_wmi_exit);
1800