acer-wmi: schedule threeg and interface sysfs for feature removal
[linux-2.6.git] / drivers / platform / x86 / acer-wmi.c
index 4821911..089db86 100644 (file)
@@ -135,6 +135,7 @@ struct event_return_value {
  */
 #define ACER_WMID3_GDS_WIRELESS                (1<<0)  /* WiFi */
 #define ACER_WMID3_GDS_THREEG          (1<<6)  /* 3G */
+#define ACER_WMID3_GDS_WIMAX           (1<<7)  /* WiMAX */
 #define ACER_WMID3_GDS_BLUETOOTH       (1<<11) /* BT */
 
 struct lm_input_params {
@@ -753,6 +754,8 @@ WMI_execute_u32(u32 method_id, u32 in, u32 *out)
                (obj->buffer.length == sizeof(u32) ||
                obj->buffer.length == sizeof(u64))) {
                tmp = *((u32 *) obj->buffer.pointer);
+       } else if (obj->type == ACPI_TYPE_INTEGER) {
+               tmp = (u32) obj->integer.value;
        } else {
                tmp = 0;
        }
@@ -883,6 +886,8 @@ static acpi_status WMID_set_capabilities(void)
                (obj->buffer.length == sizeof(u32) ||
                obj->buffer.length == sizeof(u64))) {
                devices = *((u32 *) obj->buffer.pointer);
+       } else if (obj->type == ACPI_TYPE_INTEGER) {
+               devices = (u32) obj->integer.value;
        } else {
                kfree(out.pointer);
                return AE_ERROR;
@@ -1142,6 +1147,114 @@ static acpi_status get_device_status(u32 *value, u32 cap)
        }
 }
 
+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_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 };
+
+       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_warning("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_warning("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;
+       params.function_num = 0x2;
+       params.hotkey_number = 0x01;
+       params.devices = (value) ? (devices | device) : (devices & ~device);
+
+       status = wmi_evaluate_method(WMID_GUID3, 0, 0x1, &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_warning("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_warning("Set Device Status failed: "
+                       "0x%x - 0x%x\n", return_value.error_code,
+                       return_value.ec_return_value);
+
+       return status;
+}
+
+static acpi_status set_device_status(u32 value, u32 cap)
+{
+       if (wmi_has_guid(WMID_GUID3)) {
+               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);
+
+       } else {
+               return set_u32(value, cap);
+       }
+}
+
 /*
  * Rfkill devices
  */
@@ -1178,7 +1291,7 @@ static int acer_rfkill_set(void *data, bool blocked)
        u32 cap = (unsigned long)data;
 
        if (rfkill_inited) {
-               status = set_u32(!blocked, cap);
+               status = set_device_status(!blocked, cap);
                if (ACPI_FAILURE(status))
                        return -ENODEV;
        }
@@ -1287,6 +1400,9 @@ static ssize_t show_bool_threeg(struct device *dev,
 {
        u32 result; \
        acpi_status status;
+
+       pr_info("This threeg sysfs will be removed in 2012"
+               " - used by: %s\n", current->comm);
        if (wmi_has_guid(WMID_GUID3))
                status = wmid3_get_device_status(&result,
                                ACER_WMID3_GDS_THREEG);
@@ -1302,8 +1418,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,
@@ -1312,6 +1430,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");
@@ -1332,6 +1452,8 @@ static void acer_wmi_notify(u32 value, void *context)
        union acpi_object *obj;
        struct event_return_value return_value;
        acpi_status status;
+       u16 device_state;
+       const struct key_entry *key;
 
        status = wmi_get_event_data(value, &response);
        if (status != AE_OK) {
@@ -1359,23 +1481,32 @@ static void acer_wmi_notify(u32 value, void *context)
 
        switch (return_value.function) {
        case WMID_HOTKEY_EVENT:
-               if (return_value.device_state) {
-                       u16 device_state = return_value.device_state;
-                       pr_debug("device state: 0x%x\n", device_state);
-                       if (has_cap(ACER_CAP_WIRELESS))
-                               rfkill_set_sw_state(wireless_rfkill,
-                               !(device_state & ACER_WMID3_GDS_WIRELESS));
-                       if (has_cap(ACER_CAP_BLUETOOTH))
-                               rfkill_set_sw_state(bluetooth_rfkill,
-                               !(device_state & ACER_WMID3_GDS_BLUETOOTH));
-                       if (has_cap(ACER_CAP_THREEG))
-                               rfkill_set_sw_state(threeg_rfkill,
-                               !(device_state & ACER_WMID3_GDS_THREEG));
-               }
-               if (!sparse_keymap_report_event(acer_wmi_input_dev,
-                               return_value.key_num, 1, true))
+               device_state = return_value.device_state;
+               pr_debug("device state: 0x%x\n", device_state);
+
+               key = sparse_keymap_entry_from_scancode(acer_wmi_input_dev,
+                                                       return_value.key_num);
+               if (!key) {
                        pr_warn("Unknown key number - 0x%x\n",
                                return_value.key_num);
+               } else {
+                       switch (key->keycode) {
+                       case KEY_WLAN:
+                       case KEY_BLUETOOTH:
+                               if (has_cap(ACER_CAP_WIRELESS))
+                                       rfkill_set_sw_state(wireless_rfkill,
+                                               !(device_state & ACER_WMID3_GDS_WIRELESS));
+                               if (has_cap(ACER_CAP_THREEG))
+                                       rfkill_set_sw_state(threeg_rfkill,
+                                               !(device_state & ACER_WMID3_GDS_THREEG));
+                               if (has_cap(ACER_CAP_BLUETOOTH))
+                                       rfkill_set_sw_state(bluetooth_rfkill,
+                                               !(device_state & ACER_WMID3_GDS_BLUETOOTH));
+                               break;
+                       }
+                       sparse_keymap_report_entry(acer_wmi_input_dev, key,
+                                                  1, true);
+               }
                break;
        default:
                pr_warn("Unknown function number - %d - %d\n",
@@ -1527,6 +1658,8 @@ static u32 get_wmid_devices(void)
                (obj->buffer.length == sizeof(u32) ||
                obj->buffer.length == sizeof(u64))) {
                devices = *((u32 *) obj->buffer.pointer);
+       } else if (obj->type == ACPI_TYPE_INTEGER) {
+               devices = (u32) obj->integer.value;
        }
 
        kfree(out.pointer);