OSDN Git Service

acer-wmi-update
authorMarek Vasut <marex@denx.de>
Mon, 28 May 2012 00:36:35 +0000 (02:36 +0200)
committerChih-Wei Huang <cwhuang@linux.org.tw>
Sat, 7 Jul 2012 06:33:40 +0000 (14:33 +0800)
drivers/platform/x86/acer-wmi.c

index 2080b22..514764d 100644 (file)
 #include <linux/input.h>
 #include <linux/input/sparse-keymap.h>
 
+#include <linux/delay.h>
+
 #include <acpi/acpi_drivers.h>
+#include <acpi/video.h>
 
 MODULE_AUTHOR("Carlos Corbacho");
 MODULE_DESCRIPTION("Acer Laptop WMI Extras Driver");
@@ -94,23 +97,31 @@ MODULE_ALIAS("wmi:676AA15E-6A47-4D9F-A2CC-1E6D18D14026");
 
 enum acer_wmi_event_ids {
        WMID_HOTKEY_EVENT = 0x1,
+       WMID_ACCEL_EVENT = 0x5,
 };
 
 static const struct key_entry acer_wmi_keymap[] = {
        {KE_KEY, 0x01, {KEY_WLAN} },     /* WiFi */
        {KE_KEY, 0x03, {KEY_WLAN} },     /* WiFi */
+       {KE_KEY, 0x04, {KEY_WLAN} },     /* WiFi */
        {KE_KEY, 0x12, {KEY_BLUETOOTH} },       /* BT */
        {KE_KEY, 0x21, {KEY_PROG1} },    /* Backup */
        {KE_KEY, 0x22, {KEY_PROG2} },    /* Arcade */
        {KE_KEY, 0x23, {KEY_PROG3} },    /* P_Key */
        {KE_KEY, 0x24, {KEY_PROG4} },    /* Social networking_Key */
+       {KE_KEY, 0x29, {KEY_PROG3} },    /* P_Key for TM8372 */
        {KE_IGNORE, 0x41, {KEY_MUTE} },
        {KE_IGNORE, 0x42, {KEY_PREVIOUSSONG} },
+       {KE_IGNORE, 0x4d, {KEY_PREVIOUSSONG} },
        {KE_IGNORE, 0x43, {KEY_NEXTSONG} },
+       {KE_IGNORE, 0x4e, {KEY_NEXTSONG} },
        {KE_IGNORE, 0x44, {KEY_PLAYPAUSE} },
+       {KE_IGNORE, 0x4f, {KEY_PLAYPAUSE} },
        {KE_IGNORE, 0x45, {KEY_STOP} },
+       {KE_IGNORE, 0x50, {KEY_STOP} },
        {KE_IGNORE, 0x48, {KEY_VOLUMEUP} },
        {KE_IGNORE, 0x49, {KEY_VOLUMEDOWN} },
+       {KE_IGNORE, 0x4a, {KEY_VOLUMEDOWN} },
        {KE_IGNORE, 0x61, {KEY_SWITCHVIDEOMODE} },
        {KE_IGNORE, 0x62, {KEY_BRIGHTNESSUP} },
        {KE_IGNORE, 0x63, {KEY_BRIGHTNESSDOWN} },
@@ -122,6 +133,7 @@ static const struct key_entry acer_wmi_keymap[] = {
 };
 
 static struct input_dev *acer_wmi_input_dev;
+static struct input_dev *acer_wmi_accel_dev;
 
 struct event_return_value {
        u8 function;
@@ -152,7 +164,14 @@ struct lm_return_value {
        u16 reserved;
 } __attribute__((packed));
 
-struct wmid3_gds_input_param { /* Get Device Status input parameter */
+struct wmid3_gds_set_input_param {     /* Set Device Status input parameter */
+       u8 function_num;        /* Function Number */
+       u8 hotkey_number;       /* Hotkey Number */
+       u16 devices;            /* Set Device */
+       u8 volume_value;        /* Volume Value */
+} __attribute__((packed));
+
+struct wmid3_gds_get_input_param {     /* Get Device Status input parameter */
        u8 function_num;        /* Function Number */
        u8 hotkey_number;       /* Hotkey Number */
        u16 devices;            /* Get Device */
@@ -170,6 +189,11 @@ struct hotkey_function_type_aa {
        u8 length;
        u16 handle;
        u16 commun_func_bitmap;
+       u16 application_func_bitmap;
+       u16 media_func_bitmap;
+       u16 display_func_bitmap;
+       u16 others_func_bitmap;
+       u8 commun_fn_key_number;
 } __attribute__((packed));
 
 /*
@@ -180,6 +204,8 @@ struct hotkey_function_type_aa {
 #define ACER_CAP_BLUETOOTH             (1<<2)
 #define ACER_CAP_BRIGHTNESS            (1<<3)
 #define ACER_CAP_THREEG                        (1<<4)
+#define ACER_CAP_ACCEL                 (1<<5)
+#define ACER_CAP_ALS                   (1<<6)
 #define ACER_CAP_ANY                   (0xFFFFFFFF)
 
 /*
@@ -189,6 +215,7 @@ enum interface_flags {
        ACER_AMW0,
        ACER_AMW0_V2,
        ACER_WMID,
+       ACER_WMID_v2,
 };
 
 #define ACER_DEFAULT_WIRELESS  0
@@ -204,6 +231,8 @@ static int threeg = -1;
 static int force_series;
 static bool ec_raw_mode;
 static bool has_type_aa;
+static u16 commun_func_bitmap;
+static u8 commun_fn_key_number;
 
 module_param(mailled, int, 0444);
 module_param(brightness, int, 0444);
@@ -465,6 +494,15 @@ static struct dmi_system_id acer_quirks[] = {
        },
        {
                .callback = dmi_matched,
+               .ident = "Lenovo Ideapad S205 (Brazos)",
+               .matches = {
+                       DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"),
+                       DMI_MATCH(DMI_PRODUCT_NAME, "Brazos"),
+               },
+               .driver_data = &quirk_lenovo_ideapad_s205,
+       },
+       {
+               .callback = dmi_matched,
                .ident = "Lenovo 3000 N200",
                .matches = {
                        DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"),
@@ -475,6 +513,25 @@ static struct dmi_system_id acer_quirks[] = {
        {}
 };
 
+static int video_set_backlight_video_vendor(const struct dmi_system_id *d)
+{
+       interface->capability &= ~ACER_CAP_BRIGHTNESS;
+       pr_info("Brightness must be controlled by generic video driver\n");
+       return 0;
+}
+
+static const struct dmi_system_id video_vendor_dmi_table[] = {
+       {
+               .callback = video_set_backlight_video_vendor,
+               .ident = "Acer TravelMate 4750",
+               .matches = {
+                       DMI_MATCH(DMI_BOARD_VENDOR, "Acer"),
+                       DMI_MATCH(DMI_PRODUCT_NAME, "TravelMate 4750"),
+               },
+       },
+       {}
+};
+
 /* Find which quirks are needed for a particular vendor/ model pair */
 static void find_quirks(void)
 {
@@ -533,8 +590,7 @@ struct acpi_buffer *result)
        return status;
 }
 
-static acpi_status AMW0_get_u32(u32 *value, u32 cap,
-struct wmi_interface *iface)
+static acpi_status AMW0_get_u32(u32 *value, u32 cap)
 {
        int err;
        u8 result;
@@ -604,7 +660,7 @@ struct wmi_interface *iface)
        return AE_OK;
 }
 
-static acpi_status AMW0_set_u32(u32 value, u32 cap, struct wmi_interface *iface)
+static acpi_status AMW0_set_u32(u32 value, u32 cap)
 {
        struct wmab_args args;
 
@@ -825,8 +881,7 @@ WMI_execute_u32(u32 method_id, u32 in, u32 *out)
        return status;
 }
 
-static acpi_status WMID_get_u32(u32 *value, u32 cap,
-struct wmi_interface *iface)
+static acpi_status WMID_get_u32(u32 *value, u32 cap)
 {
        acpi_status status;
        u8 tmp;
@@ -862,7 +917,7 @@ struct wmi_interface *iface)
        return status;
 }
 
-static acpi_status WMID_set_u32(u32 value, u32 cap, struct wmi_interface *iface)
+static acpi_status WMID_set_u32(u32 value, u32 cap)
 {
        u32 method_id = 0;
        char param;
@@ -905,6 +960,181 @@ static acpi_status WMID_set_u32(u32 value, u32 cap, struct wmi_interface *iface)
        return WMI_execute_u32(method_id, (u32)value, NULL);
 }
 
+static acpi_status wmid3_get_device_status(u32 *value, u16 device)
+{
+       struct wmid3_gds_return_value return_value;
+       acpi_status status;
+       union acpi_object *obj;
+       struct wmid3_gds_get_input_param params = {
+               .function_num = 0x1,
+               .hotkey_number = commun_fn_key_number,
+               .devices = device,
+       };
+       struct acpi_buffer input = {
+               sizeof(struct wmid3_gds_get_input_param),
+               &params
+       };
+       struct acpi_buffer output = { ACPI_ALLOCATE_BUFFER, NULL };
+
+       status = wmi_evaluate_method(WMID_GUID3, 0, 0x2, &input, &output);
+       if (ACPI_FAILURE(status))
+               return status;
+
+       obj = output.pointer;
+
+       if (!obj)
+               return AE_ERROR;
+       else if (obj->type != ACPI_TYPE_BUFFER) {
+               kfree(obj);
+               return AE_ERROR;
+       }
+       if (obj->buffer.length != 8) {
+               pr_warn("Unknown buffer length %d\n", obj->buffer.length);
+               kfree(obj);
+               return AE_ERROR;
+       }
+
+       return_value = *((struct wmid3_gds_return_value *)obj->buffer.pointer);
+       kfree(obj);
+
+       if (return_value.error_code || return_value.ec_return_value)
+               pr_warn("Get 0x%x Device Status failed: 0x%x - 0x%x\n",
+                       device,
+                       return_value.error_code,
+                       return_value.ec_return_value);
+       else
+               *value = !!(return_value.devices & device);
+
+       return status;
+}
+
+static acpi_status wmid_v2_get_u32(u32 *value, u32 cap)
+{
+       u16 device;
+
+       switch (cap) {
+       case ACER_CAP_WIRELESS:
+               device = ACER_WMID3_GDS_WIRELESS;
+               break;
+       case ACER_CAP_BLUETOOTH:
+               device = ACER_WMID3_GDS_BLUETOOTH;
+               break;
+       case ACER_CAP_THREEG:
+               device = ACER_WMID3_GDS_THREEG;
+               break;
+       default:
+               return AE_ERROR;
+       }
+       return wmid3_get_device_status(value, device);
+}
+
+static acpi_status wmid3_set_device_status(u32 value, u16 device)
+{
+       struct wmid3_gds_return_value return_value;
+       acpi_status status;
+       union acpi_object *obj;
+       u16 devices;
+       struct wmid3_gds_get_input_param get_params = {
+               .function_num = 0x1,
+               .hotkey_number = commun_fn_key_number,
+               .devices = commun_func_bitmap,
+       };
+       struct acpi_buffer get_input = {
+               sizeof(struct wmid3_gds_get_input_param),
+               &get_params
+       };
+       struct wmid3_gds_set_input_param set_params = {
+               .function_num = 0x2,
+               .hotkey_number = commun_fn_key_number,
+               .devices = commun_func_bitmap,
+       };
+       struct acpi_buffer set_input = {
+               sizeof(struct wmid3_gds_set_input_param),
+               &set_params
+       };
+       struct acpi_buffer output = { ACPI_ALLOCATE_BUFFER, NULL };
+       struct acpi_buffer output2 = { ACPI_ALLOCATE_BUFFER, NULL };
+
+       status = wmi_evaluate_method(WMID_GUID3, 0, 0x2, &get_input, &output);
+       if (ACPI_FAILURE(status))
+               return status;
+
+       obj = output.pointer;
+
+       if (!obj)
+               return AE_ERROR;
+       else if (obj->type != ACPI_TYPE_BUFFER) {
+               kfree(obj);
+               return AE_ERROR;
+       }
+       if (obj->buffer.length != 8) {
+               pr_warn("Unknown buffer length %d\n", obj->buffer.length);
+               kfree(obj);
+               return AE_ERROR;
+       }
+
+       return_value = *((struct wmid3_gds_return_value *)obj->buffer.pointer);
+       kfree(obj);
+
+       if (return_value.error_code || return_value.ec_return_value) {
+               pr_warn("Get Current Device Status failed: 0x%x - 0x%x\n",
+                       return_value.error_code,
+                       return_value.ec_return_value);
+               return status;
+       }
+
+       devices = return_value.devices;
+       set_params.devices = (value) ? (devices | device) : (devices & ~device);
+
+       status = wmi_evaluate_method(WMID_GUID3, 0, 0x1, &set_input, &output2);
+       if (ACPI_FAILURE(status))
+               return status;
+
+       obj = output2.pointer;
+
+       if (!obj)
+               return AE_ERROR;
+       else if (obj->type != ACPI_TYPE_BUFFER) {
+               kfree(obj);
+               return AE_ERROR;
+       }
+       if (obj->buffer.length != 4) {
+               pr_warn("Unknown buffer length %d\n", obj->buffer.length);
+               kfree(obj);
+               return AE_ERROR;
+       }
+
+       return_value = *((struct wmid3_gds_return_value *)obj->buffer.pointer);
+       kfree(obj);
+
+       if (return_value.error_code || return_value.ec_return_value)
+               pr_warn("Set Device Status failed: 0x%x - 0x%x\n",
+                       return_value.error_code,
+                       return_value.ec_return_value);
+
+       return status;
+}
+
+static acpi_status wmid_v2_set_u32(u32 value, u32 cap)
+{
+       u16 device;
+
+       switch (cap) {
+       case ACER_CAP_WIRELESS:
+               device = ACER_WMID3_GDS_WIRELESS;
+               break;
+       case ACER_CAP_BLUETOOTH:
+               device = ACER_WMID3_GDS_BLUETOOTH;
+               break;
+       case ACER_CAP_THREEG:
+               device = ACER_WMID3_GDS_THREEG;
+               break;
+       default:
+               return AE_ERROR;
+       }
+       return wmid3_set_device_status(value, device);
+}
+
 static void type_aa_dmi_decode(const struct dmi_header *header, void *dummy)
 {
        struct hotkey_function_type_aa *type_aa;
@@ -918,6 +1148,7 @@ static void type_aa_dmi_decode(const struct dmi_header *header, void *dummy)
 
        pr_info("Function bitmap for Communication Button: 0x%x\n",
                type_aa->commun_func_bitmap);
+       commun_func_bitmap = type_aa->commun_func_bitmap;
 
        if (type_aa->commun_func_bitmap & ACER_WMID3_GDS_WIRELESS)
                interface->capability |= ACER_CAP_WIRELESS;
@@ -925,6 +1156,8 @@ static void type_aa_dmi_decode(const struct dmi_header *header, void *dummy)
                interface->capability |= ACER_CAP_THREEG;
        if (type_aa->commun_func_bitmap & ACER_WMID3_GDS_BLUETOOTH)
                interface->capability |= ACER_CAP_BLUETOOTH;
+
+       commun_fn_key_number = type_aa->commun_fn_key_number;
 }
 
 static acpi_status WMID_set_capabilities(void)
@@ -950,17 +1183,13 @@ static acpi_status WMID_set_capabilities(void)
                return AE_ERROR;
        }
 
-       dmi_walk(type_aa_dmi_decode, NULL);
-       if (!has_type_aa) {
+       pr_info("Function bitmap for Communication Device: 0x%x\n", devices);
+       if (devices & 0x07)
                interface->capability |= ACER_CAP_WIRELESS;
-               if (devices & 0x40)
-                       interface->capability |= ACER_CAP_THREEG;
-               if (devices & 0x10)
-                       interface->capability |= ACER_CAP_BLUETOOTH;
-       }
-
-       /* WMID always provides brightness methods */
-       interface->capability |= ACER_CAP_BRIGHTNESS;
+       if (devices & 0x40)
+               interface->capability |= ACER_CAP_THREEG;
+       if (devices & 0x10)
+               interface->capability |= ACER_CAP_BLUETOOTH;
 
        if (!(devices & 0x20))
                max_brightness = 0x9;
@@ -973,6 +1202,10 @@ static struct wmi_interface wmid_interface = {
        .type = ACER_WMID,
 };
 
+static struct wmi_interface wmid_v2_interface = {
+       .type = ACER_WMID_v2,
+};
+
 /*
  * Generic Device (interface-independent)
  */
@@ -983,15 +1216,23 @@ static acpi_status get_u32(u32 *value, u32 cap)
 
        switch (interface->type) {
        case ACER_AMW0:
-               status = AMW0_get_u32(value, cap, interface);
+               status = AMW0_get_u32(value, cap);
                break;
        case ACER_AMW0_V2:
                if (cap == ACER_CAP_MAILLED) {
-                       status = AMW0_get_u32(value, cap, interface);
+                       status = AMW0_get_u32(value, cap);
                        break;
                }
        case ACER_WMID:
-               status = WMID_get_u32(value, cap, interface);
+               status = WMID_get_u32(value, cap);
+               break;
+       case ACER_WMID_v2:
+               if (cap & (ACER_CAP_WIRELESS |
+                          ACER_CAP_BLUETOOTH |
+                          ACER_CAP_THREEG))
+                       status = wmid_v2_get_u32(value, cap);
+               else if (wmi_has_guid(WMID_GUID2))
+                       status = WMID_get_u32(value, cap);
                break;
        }
 
@@ -1005,10 +1246,10 @@ static acpi_status set_u32(u32 value, u32 cap)
        if (interface->capability & cap) {
                switch (interface->type) {
                case ACER_AMW0:
-                       return AMW0_set_u32(value, cap, interface);
+                       return AMW0_set_u32(value, cap);
                case ACER_AMW0_V2:
                        if (cap == ACER_CAP_MAILLED)
-                               return AMW0_set_u32(value, cap, interface);
+                               return AMW0_set_u32(value, cap);
 
                        /*
                         * On some models, some WMID methods don't toggle
@@ -1018,14 +1259,21 @@ static acpi_status set_u32(u32 value, u32 cap)
                         */
                        if (cap == ACER_CAP_WIRELESS ||
                                cap == ACER_CAP_BLUETOOTH) {
-                               status = WMID_set_u32(value, cap, interface);
+                               status = WMID_set_u32(value, cap);
                                if (ACPI_FAILURE(status))
                                        return status;
 
-                               return AMW0_set_u32(value, cap, interface);
+                               return AMW0_set_u32(value, cap);
                        }
                case ACER_WMID:
-                       return WMID_set_u32(value, cap, interface);
+                       return WMID_set_u32(value, cap);
+               case ACER_WMID_v2:
+                       if (cap & (ACER_CAP_WIRELESS |
+                                  ACER_CAP_BLUETOOTH |
+                                  ACER_CAP_THREEG))
+                               return wmid_v2_set_u32(value, cap);
+                       else if (wmi_has_guid(WMID_GUID2))
+                               return WMID_set_u32(value, cap);
                default:
                        return AE_BAD_PARAMETER;
                }
@@ -1132,184 +1380,129 @@ static void acer_backlight_exit(void)
        backlight_device_unregister(acer_backlight_device);
 }
 
-static acpi_status wmid3_get_device_status(u32 *value, u16 device)
+/*
+ * Ambient light sensor device
+ */
+static acpi_handle alsd_handle;
+static uint32_t alsd_value;
+static struct work_struct acer_alsd_work;
+
+static int acer_als_init(void)
 {
-       struct wmid3_gds_return_value return_value;
+       union acpi_object in_obj;
+       struct acpi_object_list params;
+       struct acpi_buffer out;
+       union acpi_object out_obj;
        acpi_status status;
-       union acpi_object *obj;
-       struct wmid3_gds_input_param params = {
-               .function_num = 0x1,
-               .hotkey_number = 0x01,
-               .devices = device,
-       };
-       struct acpi_buffer input = {
-               sizeof(struct wmid3_gds_input_param),
-               &params
-       };
-       struct acpi_buffer output = { ACPI_ALLOCATE_BUFFER, NULL };
 
-       status = wmi_evaluate_method(WMID_GUID3, 0, 0x2, &input, &output);
+       status = acpi_evaluate_object(alsd_handle, "_INI", NULL, NULL);
        if (ACPI_FAILURE(status))
-               return status;
-
-       obj = output.pointer;
+               return -1;
 
-       if (!obj)
-               return AE_ERROR;
-       else if (obj->type != ACPI_TYPE_BUFFER) {
-               kfree(obj);
-               return AE_ERROR;
-       }
-       if (obj->buffer.length != 8) {
-               pr_warn("Unknown buffer length %d\n", obj->buffer.length);
-               kfree(obj);
-               return AE_ERROR;
-       }
-
-       return_value = *((struct wmid3_gds_return_value *)obj->buffer.pointer);
-       kfree(obj);
-
-       if (return_value.error_code || return_value.ec_return_value)
-               pr_warn("Get Device Status failed: 0x%x - 0x%x\n",
-                       return_value.error_code,
-                       return_value.ec_return_value);
-       else
-               *value = !!(return_value.devices & device);
-
-       return status;
-}
-
-static acpi_status get_device_status(u32 *value, u32 cap)
-{
-       if (wmi_has_guid(WMID_GUID3)) {
-               u16 device;
+       params.count = 1;
+       params.pointer = &in_obj;
+       in_obj.type = ACPI_TYPE_INTEGER;
+       /*
+        * Unknown argument of both GLOV and GUPV, set to 5.
+        * GLOV - G? Lower Value ?
+        * GUPV - G? Upper Value ?
+        */
+       in_obj.integer.value = 5;
+       out.length = sizeof(out_obj);
+       out.pointer = &out_obj;
 
-               switch (cap) {
-               case ACER_CAP_WIRELESS:
-                       device = ACER_WMID3_GDS_WIRELESS;
-                       break;
-               case ACER_CAP_BLUETOOTH:
-                       device = ACER_WMID3_GDS_BLUETOOTH;
-                       break;
-               case ACER_CAP_THREEG:
-                       device = ACER_WMID3_GDS_THREEG;
-                       break;
-               default:
-                       return AE_ERROR;
-               }
-               return wmid3_get_device_status(value, device);
+       acpi_evaluate_object(alsd_handle, "GLOV", &params, &out);
+       acpi_evaluate_object(alsd_handle, "GUPV", &params, &out);
 
-       } else {
-               return get_u32(value, cap);
-       }
+       return 0;
 }
 
-static acpi_status wmid3_set_device_status(u32 value, u16 device)
+static void acer_als_work(struct work_struct *w)
 {
-       struct wmid3_gds_return_value return_value;
        acpi_status status;
-       union acpi_object *obj;
-       u16 devices;
-       struct wmid3_gds_input_param params = {
-               .function_num = 0x1,
-               .hotkey_number = 0x01,
-               .devices = ACER_WMID3_GDS_WIRELESS |
-                               ACER_WMID3_GDS_THREEG |
-                               ACER_WMID3_GDS_WIMAX |
-                               ACER_WMID3_GDS_BLUETOOTH,
-       };
-       struct acpi_buffer input = {
-               sizeof(struct wmid3_gds_input_param),
-               &params
-       };
-       struct acpi_buffer output = { ACPI_ALLOCATE_BUFFER, NULL };
-       struct acpi_buffer output2 = { ACPI_ALLOCATE_BUFFER, NULL };
+       struct acpi_buffer output;
+       union acpi_object out_obj;
 
-       status = wmi_evaluate_method(WMID_GUID3, 0, 0x2, &input, &output);
+       status = acpi_evaluate_object(alsd_handle, "S3WK", NULL, NULL);
        if (ACPI_FAILURE(status))
-               return status;
+               return;
 
-       obj = output.pointer;
+       output.length = sizeof(out_obj);
+       output.pointer = &out_obj;
+       status = acpi_evaluate_object(alsd_handle, "_ALI", NULL, &output);
+       if (ACPI_FAILURE(status))
+               return;
 
-       if (!obj)
-               return AE_ERROR;
-       else if (obj->type != ACPI_TYPE_BUFFER) {
-               kfree(obj);
-               return AE_ERROR;
-       }
-       if (obj->buffer.length != 8) {
-               pr_warning("Unknown buffer length %d\n", obj->buffer.length);
-               kfree(obj);
-               return AE_ERROR;
-       }
+       alsd_value = (u32)out_obj.integer.value;
+       input_report_abs(acer_wmi_accel_dev, ABS_MISC, alsd_value);
+       input_sync(acer_wmi_accel_dev);
 
-       return_value = *((struct wmid3_gds_return_value *)obj->buffer.pointer);
-       kfree(obj);
+       mdelay(1000);
 
-       if (return_value.error_code || return_value.ec_return_value) {
-               pr_warning("Get Current Device Status failed: "
-                       "0x%x - 0x%x\n", return_value.error_code,
-                       return_value.ec_return_value);
-               return status;
-       }
+       schedule_work(w);
+}
 
-       devices = return_value.devices;
-       params.function_num = 0x2;
-       params.hotkey_number = 0x01;
-       params.devices = (value) ? (devices | device) : (devices & ~device);
+static ssize_t acer_als_show(struct device *dev, struct device_attribute *attr,
+                       char *buf)
+{
+       return sprintf(buf, "%d\n", alsd_value);
+}
 
-       status = wmi_evaluate_method(WMID_GUID3, 0, 0x1, &input, &output2);
-       if (ACPI_FAILURE(status))
-               return status;
+static DEVICE_ATTR(ls_switch, S_IRUGO, acer_als_show, NULL);
 
-       obj = output2.pointer;
+/*
+ * Accelerometer device
+ */
+static acpi_handle gsensor_handle;
 
-       if (!obj)
-               return AE_ERROR;
-       else if (obj->type != ACPI_TYPE_BUFFER) {
-               kfree(obj);
-               return AE_ERROR;
-       }
-       if (obj->buffer.length != 4) {
-               pr_warning("Unknown buffer length %d\n", obj->buffer.length);
-               kfree(obj);
-               return AE_ERROR;
-       }
+static int acer_gsensor_init(void)
+{
+       acpi_status status;
+       struct acpi_buffer output;
+       union acpi_object out_obj;
 
-       return_value = *((struct wmid3_gds_return_value *)obj->buffer.pointer);
-       kfree(obj);
+       output.length = sizeof(out_obj);
+       output.pointer = &out_obj;
+       status = acpi_evaluate_object(gsensor_handle, "_INI", NULL, &output);
+       if (ACPI_FAILURE(status))
+               return -1;
 
-       if (return_value.error_code || return_value.ec_return_value)
-               pr_warning("Set Device Status failed: "
-                       "0x%x - 0x%x\n", return_value.error_code,
-                       return_value.ec_return_value);
+       return 0;
+}
 
-       return status;
+static int acer_gsensor_open(struct input_dev *input)
+{
+       return acer_gsensor_init();
 }
 
-static acpi_status set_device_status(u32 value, u32 cap)
+static int acer_gsensor_event(void)
 {
-       if (wmi_has_guid(WMID_GUID3)) {
-               u16 device;
+       acpi_status status;
+       struct acpi_buffer output;
+       union acpi_object out_obj[5];
 
-               switch (cap) {
-               case ACER_CAP_WIRELESS:
-                       device = ACER_WMID3_GDS_WIRELESS;
-                       break;
-               case ACER_CAP_BLUETOOTH:
-                       device = ACER_WMID3_GDS_BLUETOOTH;
-                       break;
-               case ACER_CAP_THREEG:
-                       device = ACER_WMID3_GDS_THREEG;
-                       break;
-               default:
-                       return AE_ERROR;
-               }
-               return wmid3_set_device_status(value, device);
+       if (!has_cap(ACER_CAP_ACCEL))
+               return -1;
 
-       } else {
-               return set_u32(value, cap);
-       }
+       output.length = sizeof(out_obj);
+       output.pointer = out_obj;
+
+       status = acpi_evaluate_object(gsensor_handle, "RDVL", NULL, &output);
+       if (ACPI_FAILURE(status))
+               return -1;
+
+       if (out_obj->package.count != 4)
+               return -1;
+
+       input_report_abs(acer_wmi_accel_dev, ABS_X,
+               (s16)out_obj->package.elements[0].integer.value);
+       input_report_abs(acer_wmi_accel_dev, ABS_Y,
+               (s16)out_obj->package.elements[1].integer.value);
+       input_report_abs(acer_wmi_accel_dev, ABS_Z,
+               (s16)out_obj->package.elements[2].integer.value);
+       input_sync(acer_wmi_accel_dev);
+
+       return 0;
 }
 
 /*
@@ -1339,8 +1532,7 @@ static void acer_rfkill_update(struct work_struct *ignored)
        }
 
        if (has_cap(ACER_CAP_THREEG) && wmi_has_guid(WMID_GUID3)) {
-               status = wmid3_get_device_status(&state,
-                               ACER_WMID3_GDS_THREEG);
+               status = get_u32(&state, ACER_WMID3_GDS_THREEG);
                if (ACPI_SUCCESS(status))
                        rfkill_set_sw_state(threeg_rfkill, !state);
        }
@@ -1354,7 +1546,7 @@ static int acer_rfkill_set(void *data, bool blocked)
        u32 cap = (unsigned long)data;
 
        if (rfkill_inited) {
-               status = set_device_status(!blocked, cap);
+               status = set_u32(!blocked, cap);
                if (ACPI_FAILURE(status))
                        return -ENODEV;
        }
@@ -1381,7 +1573,7 @@ static struct rfkill *acer_rfkill_register(struct device *dev,
        if (!rfkill_dev)
                return ERR_PTR(-ENOMEM);
 
-       status = get_device_status(&state, cap);
+       status = get_u32(&state, cap);
 
        err = rfkill_register(rfkill_dev);
        if (err) {
@@ -1482,11 +1674,10 @@ static ssize_t show_bool_threeg(struct device *dev,
 {
        u32 result; \
        acpi_status status;
-       if (wmi_has_guid(WMID_GUID3))
-               status = wmid3_get_device_status(&result,
-                               ACER_WMID3_GDS_THREEG);
-       else
-               status = get_u32(&result, ACER_CAP_THREEG);
+
+       pr_info("This threeg sysfs will be removed in 2012 - used by: %s\n",
+               current->comm);
+       status = get_u32(&result, ACER_CAP_THREEG);
        if (ACPI_SUCCESS(status))
                return sprintf(buf, "%u\n", result);
        return sprintf(buf, "Read error\n");
@@ -1497,8 +1688,10 @@ static ssize_t set_bool_threeg(struct device *dev,
 {
        u32 tmp = simple_strtoul(buf, NULL, 10);
        acpi_status status = set_u32(tmp, ACER_CAP_THREEG);
-               if (ACPI_FAILURE(status))
-                       return -EINVAL;
+       pr_info("This threeg sysfs will be removed in 2012 - used by: %s\n",
+               current->comm);
+       if (ACPI_FAILURE(status))
+               return -EINVAL;
        return count;
 }
 static DEVICE_ATTR(threeg, S_IRUGO | S_IWUSR, show_bool_threeg,
@@ -1507,6 +1700,8 @@ static DEVICE_ATTR(threeg, S_IRUGO | S_IWUSR, show_bool_threeg,
 static ssize_t show_interface(struct device *dev, struct device_attribute *attr,
        char *buf)
 {
+       pr_info("This interface sysfs will be removed in 2012 - used by: %s\n",
+               current->comm);
        switch (interface->type) {
        case ACER_AMW0:
                return sprintf(buf, "AMW0\n");
@@ -1514,6 +1709,8 @@ static ssize_t show_interface(struct device *dev, struct device_attribute *attr,
                return sprintf(buf, "AMW0 v2\n");
        case ACER_WMID:
                return sprintf(buf, "WMID\n");
+       case ACER_WMID_v2:
+               return sprintf(buf, "WMID v2\n");
        default:
                return sprintf(buf, "Error!\n");
        }
@@ -1583,6 +1780,9 @@ static void acer_wmi_notify(u32 value, void *context)
                                                   1, true);
                }
                break;
+       case WMID_ACCEL_EVENT:
+               acer_gsensor_event();
+               break;
        default:
                pr_warn("Unknown function number - %d - %d\n",
                        return_value.function, return_value.key_num);
@@ -1668,6 +1868,98 @@ static int acer_wmi_enable_lm(void)
        return status;
 }
 
+static acpi_status __init acer_wmi_get_handle_cb(acpi_handle ah, u32 level,
+                                               void *ctx, void **retval)
+{
+       *(acpi_handle *)retval = ah;
+       return AE_OK;
+}
+
+static int __init acer_wmi_get_handle(const char *name, const char *prop,
+                                       acpi_handle *ah)
+{
+       acpi_status status;
+       acpi_handle handle;
+
+       BUG_ON(!name || !ah);
+
+       handle = 0;
+       status = acpi_get_devices(prop, acer_wmi_get_handle_cb,
+                                       (void *)name, &handle);
+
+       if (ACPI_SUCCESS(status)) {
+               *ah = handle;
+               return 0;
+       } else {
+               return -ENODEV;
+       }
+}
+
+static int __init acer_wmi_accel_setup(void)
+{
+       int err;
+
+       err = acer_wmi_get_handle("SENR", "BST0001", &gsensor_handle);
+       if (err)
+               return err;
+
+       interface->capability |= ACER_CAP_ACCEL;
+
+       acer_wmi_accel_dev = input_allocate_device();
+       if (!acer_wmi_accel_dev)
+               return -ENOMEM;
+
+       acer_wmi_accel_dev->open = acer_gsensor_open;
+
+       acer_wmi_accel_dev->name = "Acer BMA150 accelerometer";
+       acer_wmi_accel_dev->phys = "wmi/input1";
+       acer_wmi_accel_dev->id.bustype = BUS_HOST;
+       acer_wmi_accel_dev->evbit[0] = BIT_MASK(EV_ABS);
+       input_set_abs_params(acer_wmi_accel_dev, ABS_X, -16384, 16384, 0, 0);
+       input_set_abs_params(acer_wmi_accel_dev, ABS_Y, -16384, 16384, 0, 0);
+       input_set_abs_params(acer_wmi_accel_dev, ABS_Z, -16384, 16384, 0, 0);
+       input_set_abs_params(acer_wmi_accel_dev, ABS_MISC, 0, 65536, 0, 0);
+
+       err = input_register_device(acer_wmi_accel_dev);
+       if (err)
+               goto err_free_dev;
+
+       return 0;
+
+err_free_dev:
+       input_free_device(acer_wmi_accel_dev);
+       return err;
+}
+
+static int __init acer_wmi_alsd_setup(void)
+{
+       int err;
+
+       err = acer_wmi_get_handle("ALSD", "ACPI0008", &alsd_handle);
+       if (err)
+               return err;
+
+       interface->capability |= ACER_CAP_ALS;
+
+       acer_als_init();
+
+       INIT_WORK(&acer_alsd_work, acer_als_work);
+       schedule_work(&acer_alsd_work);
+
+       return 0;
+}
+
+static void acer_wmi_accel_destroy(void)
+{
+       input_unregister_device(acer_wmi_accel_dev);
+       input_free_device(acer_wmi_accel_dev);
+}
+
+static void acer_wmi_als_destroy(void)
+{
+       cancel_work_sync(&acer_alsd_work);
+}
+
 static int __init acer_wmi_input_setup(void)
 {
        acpi_status status;
@@ -1823,6 +2115,12 @@ static int acer_platform_resume(struct platform_device *device)
        if (has_cap(ACER_CAP_BRIGHTNESS))
                set_u32(data->brightness, ACER_CAP_BRIGHTNESS);
 
+       if (has_cap(ACER_CAP_ACCEL))
+               acer_gsensor_init();
+
+       if (has_cap(ACER_CAP_ALS))
+               acer_als_init();
+
        return 0;
 }
 
@@ -1855,6 +2153,8 @@ static int remove_sysfs(struct platform_device *device)
 {
        if (has_cap(ACER_CAP_THREEG))
                device_remove_file(&device->dev, &dev_attr_threeg);
+       if (has_cap(ACER_CAP_ALS))
+               device_remove_file(&device->dev, &dev_attr_ls_switch);
 
        device_remove_file(&device->dev, &dev_attr_interface);
 
@@ -1872,6 +2172,13 @@ static int create_sysfs(void)
                        goto error_sysfs;
        }
 
+       if (has_cap(ACER_CAP_ALS)) {
+               retval = device_create_file(&acer_platform_device->dev,
+                       &dev_attr_ls_switch);
+               if (retval)
+                       goto error_sysfs;
+       }
+
        retval = device_create_file(&acer_platform_device->dev,
                &dev_attr_interface);
        if (retval)
@@ -1933,12 +2240,20 @@ static int __init acer_wmi_init(void)
        if (!wmi_has_guid(AMW0_GUID1) && wmi_has_guid(WMID_GUID1))
                interface = &wmid_interface;
 
+       if (wmi_has_guid(WMID_GUID3))
+               interface = &wmid_v2_interface;
+
+       if (interface)
+               dmi_walk(type_aa_dmi_decode, NULL);
+
        if (wmi_has_guid(WMID_GUID2) && interface) {
-               if (ACPI_FAILURE(WMID_set_capabilities())) {
+               if (!has_type_aa && ACPI_FAILURE(WMID_set_capabilities())) {
                        pr_err("Unable to detect available WMID devices\n");
                        return -ENODEV;
                }
-       } else if (!wmi_has_guid(WMID_GUID2) && interface) {
+               /* WMID always provides brightness methods */
+               interface->capability |= ACER_CAP_BRIGHTNESS;
+       } else if (!wmi_has_guid(WMID_GUID2) && interface && !has_type_aa) {
                pr_err("No WMID device detection method found\n");
                return -ENODEV;
        }
@@ -1962,10 +2277,14 @@ static int __init acer_wmi_init(void)
 
        set_quirks();
 
-       if (acpi_video_backlight_support() && has_cap(ACER_CAP_BRIGHTNESS)) {
-               interface->capability &= ~ACER_CAP_BRIGHTNESS;
-               pr_info("Brightness must be controlled by "
-                      "generic video driver\n");
+       if (acpi_video_backlight_support()) {
+               if (dmi_check_system(video_vendor_dmi_table)) {
+                       acpi_video_unregister();
+               } else {
+                       interface->capability &= ~ACER_CAP_BRIGHTNESS;
+                       pr_info("Brightness must be controlled by "
+                               "acpi video driver\n");
+               }
        }
 
        if (wmi_has_guid(WMID_GUID3)) {
@@ -1988,9 +2307,12 @@ static int __init acer_wmi_init(void)
                        return err;
        }
 
+       acer_wmi_accel_setup();
+       acer_wmi_alsd_setup();
+
        err = platform_driver_register(&acer_platform_driver);
        if (err) {
-               pr_err("Unable to register platform driver.\n");
+               pr_err("Unable to register platform driver\n");
                goto error_platform_register;
        }
 
@@ -2031,6 +2353,10 @@ error_device_alloc:
 error_platform_register:
        if (wmi_has_guid(ACERWMID_EVENT_GUID))
                acer_wmi_input_destroy();
+       if (has_cap(ACER_CAP_ACCEL))
+               acer_wmi_accel_destroy();
+       if (has_cap(ACER_CAP_ALS))
+               acer_wmi_als_destroy();
 
        return err;
 }
@@ -2040,6 +2366,12 @@ static void __exit acer_wmi_exit(void)
        if (wmi_has_guid(ACERWMID_EVENT_GUID))
                acer_wmi_input_destroy();
 
+       if (has_cap(ACER_CAP_ACCEL))
+               acer_wmi_accel_destroy();
+
+       if (has_cap(ACER_CAP_ALS))
+               acer_wmi_als_destroy();
+
        remove_sysfs(acer_platform_device);
        remove_debugfs();
        platform_device_unregister(acer_platform_device);