diff options
Diffstat (limited to 'ANDROID_3.4.5/drivers/hwmon/asus_atk0110.c')
-rw-r--r-- | ANDROID_3.4.5/drivers/hwmon/asus_atk0110.c | 1463 |
1 files changed, 0 insertions, 1463 deletions
diff --git a/ANDROID_3.4.5/drivers/hwmon/asus_atk0110.c b/ANDROID_3.4.5/drivers/hwmon/asus_atk0110.c deleted file mode 100644 index 351d1f45..00000000 --- a/ANDROID_3.4.5/drivers/hwmon/asus_atk0110.c +++ /dev/null @@ -1,1463 +0,0 @@ -/* - * Copyright (C) 2007-2009 Luca Tettamanti <kronos.it@gmail.com> - * - * This file is released under the GPLv2 - * See COPYING in the top level directory of the kernel tree. - */ - -#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt - -#include <linux/debugfs.h> -#include <linux/kernel.h> -#include <linux/hwmon.h> -#include <linux/list.h> -#include <linux/module.h> -#include <linux/slab.h> -#include <linux/dmi.h> - -#include <acpi/acpi.h> -#include <acpi/acpixf.h> -#include <acpi/acpi_drivers.h> -#include <acpi/acpi_bus.h> - - -#define ATK_HID "ATK0110" - -static bool new_if; -module_param(new_if, bool, 0); -MODULE_PARM_DESC(new_if, "Override detection heuristic and force the use of the new ATK0110 interface"); - -static const struct dmi_system_id __initconst atk_force_new_if[] = { - { - /* Old interface has broken MCH temp monitoring */ - .ident = "Asus Sabertooth X58", - .matches = { - DMI_MATCH(DMI_BOARD_NAME, "SABERTOOTH X58") - } - }, - { } -}; - -/* - * Minimum time between readings, enforced in order to avoid - * hogging the CPU. - */ -#define CACHE_TIME HZ - -#define BOARD_ID "MBIF" -#define METHOD_ENUMERATE "GGRP" -#define METHOD_READ "GITM" -#define METHOD_WRITE "SITM" -#define METHOD_OLD_READ_TMP "RTMP" -#define METHOD_OLD_READ_VLT "RVLT" -#define METHOD_OLD_READ_FAN "RFAN" -#define METHOD_OLD_ENUM_TMP "TSIF" -#define METHOD_OLD_ENUM_VLT "VSIF" -#define METHOD_OLD_ENUM_FAN "FSIF" - -#define ATK_MUX_HWMON 0x00000006ULL -#define ATK_MUX_MGMT 0x00000011ULL - -#define ATK_CLASS_MASK 0xff000000ULL -#define ATK_CLASS_FREQ_CTL 0x03000000ULL -#define ATK_CLASS_FAN_CTL 0x04000000ULL -#define ATK_CLASS_HWMON 0x06000000ULL -#define ATK_CLASS_MGMT 0x11000000ULL - -#define ATK_TYPE_MASK 0x00ff0000ULL -#define HWMON_TYPE_VOLT 0x00020000ULL -#define HWMON_TYPE_TEMP 0x00030000ULL -#define HWMON_TYPE_FAN 0x00040000ULL - -#define ATK_ELEMENT_ID_MASK 0x0000ffffULL - -#define ATK_EC_ID 0x11060004ULL - -enum atk_pack_member { - HWMON_PACK_FLAGS, - HWMON_PACK_NAME, - HWMON_PACK_LIMIT1, - HWMON_PACK_LIMIT2, - HWMON_PACK_ENABLE -}; - -/* New package format */ -#define _HWMON_NEW_PACK_SIZE 7 -#define _HWMON_NEW_PACK_FLAGS 0 -#define _HWMON_NEW_PACK_NAME 1 -#define _HWMON_NEW_PACK_UNK1 2 -#define _HWMON_NEW_PACK_UNK2 3 -#define _HWMON_NEW_PACK_LIMIT1 4 -#define _HWMON_NEW_PACK_LIMIT2 5 -#define _HWMON_NEW_PACK_ENABLE 6 - -/* Old package format */ -#define _HWMON_OLD_PACK_SIZE 5 -#define _HWMON_OLD_PACK_FLAGS 0 -#define _HWMON_OLD_PACK_NAME 1 -#define _HWMON_OLD_PACK_LIMIT1 2 -#define _HWMON_OLD_PACK_LIMIT2 3 -#define _HWMON_OLD_PACK_ENABLE 4 - - -struct atk_data { - struct device *hwmon_dev; - acpi_handle atk_handle; - struct acpi_device *acpi_dev; - - bool old_interface; - - /* old interface */ - acpi_handle rtmp_handle; - acpi_handle rvlt_handle; - acpi_handle rfan_handle; - /* new inteface */ - acpi_handle enumerate_handle; - acpi_handle read_handle; - acpi_handle write_handle; - - bool disable_ec; - - int voltage_count; - int temperature_count; - int fan_count; - struct list_head sensor_list; - - struct { - struct dentry *root; - u32 id; - } debugfs; -}; - - -typedef ssize_t (*sysfs_show_func)(struct device *dev, - struct device_attribute *attr, char *buf); - -static const struct acpi_device_id atk_ids[] = { - {ATK_HID, 0}, - {"", 0}, -}; -MODULE_DEVICE_TABLE(acpi, atk_ids); - -#define ATTR_NAME_SIZE 16 /* Worst case is "tempN_input" */ - -struct atk_sensor_data { - struct list_head list; - struct atk_data *data; - struct device_attribute label_attr; - struct device_attribute input_attr; - struct device_attribute limit1_attr; - struct device_attribute limit2_attr; - char label_attr_name[ATTR_NAME_SIZE]; - char input_attr_name[ATTR_NAME_SIZE]; - char limit1_attr_name[ATTR_NAME_SIZE]; - char limit2_attr_name[ATTR_NAME_SIZE]; - u64 id; - u64 type; - u64 limit1; - u64 limit2; - u64 cached_value; - unsigned long last_updated; /* in jiffies */ - bool is_valid; - char const *acpi_name; -}; - -/* - * Return buffer format: - * [0-3] "value" is valid flag - * [4-7] value - * [8- ] unknown stuff on newer mobos - */ -struct atk_acpi_ret_buffer { - u32 flags; - u32 value; - u8 data[]; -}; - -/* Input buffer used for GITM and SITM methods */ -struct atk_acpi_input_buf { - u32 id; - u32 param1; - u32 param2; -}; - -static int atk_add(struct acpi_device *device); -static int atk_remove(struct acpi_device *device, int type); -static void atk_print_sensor(struct atk_data *data, union acpi_object *obj); -static int atk_read_value(struct atk_sensor_data *sensor, u64 *value); -static void atk_free_sensors(struct atk_data *data); - -static struct acpi_driver atk_driver = { - .name = ATK_HID, - .class = "hwmon", - .ids = atk_ids, - .ops = { - .add = atk_add, - .remove = atk_remove, - }, -}; - -#define input_to_atk_sensor(attr) \ - container_of(attr, struct atk_sensor_data, input_attr) - -#define label_to_atk_sensor(attr) \ - container_of(attr, struct atk_sensor_data, label_attr) - -#define limit1_to_atk_sensor(attr) \ - container_of(attr, struct atk_sensor_data, limit1_attr) - -#define limit2_to_atk_sensor(attr) \ - container_of(attr, struct atk_sensor_data, limit2_attr) - -static ssize_t atk_input_show(struct device *dev, - struct device_attribute *attr, char *buf) -{ - struct atk_sensor_data *s = input_to_atk_sensor(attr); - u64 value; - int err; - - err = atk_read_value(s, &value); - if (err) - return err; - - if (s->type == HWMON_TYPE_TEMP) - /* ACPI returns decidegree */ - value *= 100; - - return sprintf(buf, "%llu\n", value); -} - -static ssize_t atk_label_show(struct device *dev, - struct device_attribute *attr, char *buf) -{ - struct atk_sensor_data *s = label_to_atk_sensor(attr); - - return sprintf(buf, "%s\n", s->acpi_name); -} - -static ssize_t atk_limit1_show(struct device *dev, - struct device_attribute *attr, char *buf) -{ - struct atk_sensor_data *s = limit1_to_atk_sensor(attr); - u64 value = s->limit1; - - if (s->type == HWMON_TYPE_TEMP) - value *= 100; - - return sprintf(buf, "%lld\n", value); -} - -static ssize_t atk_limit2_show(struct device *dev, - struct device_attribute *attr, char *buf) -{ - struct atk_sensor_data *s = limit2_to_atk_sensor(attr); - u64 value = s->limit2; - - if (s->type == HWMON_TYPE_TEMP) - value *= 100; - - return sprintf(buf, "%lld\n", value); -} - -static ssize_t atk_name_show(struct device *dev, - struct device_attribute *attr, char *buf) -{ - return sprintf(buf, "atk0110\n"); -} -static struct device_attribute atk_name_attr = - __ATTR(name, 0444, atk_name_show, NULL); - -static void atk_init_attribute(struct device_attribute *attr, char *name, - sysfs_show_func show) -{ - sysfs_attr_init(&attr->attr); - attr->attr.name = name; - attr->attr.mode = 0444; - attr->show = show; - attr->store = NULL; -} - - -static union acpi_object *atk_get_pack_member(struct atk_data *data, - union acpi_object *pack, - enum atk_pack_member m) -{ - bool old_if = data->old_interface; - int offset; - - switch (m) { - case HWMON_PACK_FLAGS: - offset = old_if ? _HWMON_OLD_PACK_FLAGS : _HWMON_NEW_PACK_FLAGS; - break; - case HWMON_PACK_NAME: - offset = old_if ? _HWMON_OLD_PACK_NAME : _HWMON_NEW_PACK_NAME; - break; - case HWMON_PACK_LIMIT1: - offset = old_if ? _HWMON_OLD_PACK_LIMIT1 : - _HWMON_NEW_PACK_LIMIT1; - break; - case HWMON_PACK_LIMIT2: - offset = old_if ? _HWMON_OLD_PACK_LIMIT2 : - _HWMON_NEW_PACK_LIMIT2; - break; - case HWMON_PACK_ENABLE: - offset = old_if ? _HWMON_OLD_PACK_ENABLE : - _HWMON_NEW_PACK_ENABLE; - break; - default: - return NULL; - } - - return &pack->package.elements[offset]; -} - - -/* - * New package format is: - * - flag (int) - * class - used for de-muxing the request to the correct GITn - * type (volt, temp, fan) - * sensor id | - * sensor id - used for de-muxing the request _inside_ the GITn - * - name (str) - * - unknown (int) - * - unknown (int) - * - limit1 (int) - * - limit2 (int) - * - enable (int) - * - * The old package has the same format but it's missing the two unknown fields. - */ -static int validate_hwmon_pack(struct atk_data *data, union acpi_object *obj) -{ - struct device *dev = &data->acpi_dev->dev; - union acpi_object *tmp; - bool old_if = data->old_interface; - int const expected_size = old_if ? _HWMON_OLD_PACK_SIZE : - _HWMON_NEW_PACK_SIZE; - - if (obj->type != ACPI_TYPE_PACKAGE) { - dev_warn(dev, "Invalid type: %d\n", obj->type); - return -EINVAL; - } - - if (obj->package.count != expected_size) { - dev_warn(dev, "Invalid package size: %d, expected: %d\n", - obj->package.count, expected_size); - return -EINVAL; - } - - tmp = atk_get_pack_member(data, obj, HWMON_PACK_FLAGS); - if (tmp->type != ACPI_TYPE_INTEGER) { - dev_warn(dev, "Invalid type (flag): %d\n", tmp->type); - return -EINVAL; - } - - tmp = atk_get_pack_member(data, obj, HWMON_PACK_NAME); - if (tmp->type != ACPI_TYPE_STRING) { - dev_warn(dev, "Invalid type (name): %d\n", tmp->type); - return -EINVAL; - } - - /* Don't check... we don't know what they're useful for anyway */ -#if 0 - tmp = &obj->package.elements[HWMON_PACK_UNK1]; - if (tmp->type != ACPI_TYPE_INTEGER) { - dev_warn(dev, "Invalid type (unk1): %d\n", tmp->type); - return -EINVAL; - } - - tmp = &obj->package.elements[HWMON_PACK_UNK2]; - if (tmp->type != ACPI_TYPE_INTEGER) { - dev_warn(dev, "Invalid type (unk2): %d\n", tmp->type); - return -EINVAL; - } -#endif - - tmp = atk_get_pack_member(data, obj, HWMON_PACK_LIMIT1); - if (tmp->type != ACPI_TYPE_INTEGER) { - dev_warn(dev, "Invalid type (limit1): %d\n", tmp->type); - return -EINVAL; - } - - tmp = atk_get_pack_member(data, obj, HWMON_PACK_LIMIT2); - if (tmp->type != ACPI_TYPE_INTEGER) { - dev_warn(dev, "Invalid type (limit2): %d\n", tmp->type); - return -EINVAL; - } - - tmp = atk_get_pack_member(data, obj, HWMON_PACK_ENABLE); - if (tmp->type != ACPI_TYPE_INTEGER) { - dev_warn(dev, "Invalid type (enable): %d\n", tmp->type); - return -EINVAL; - } - - atk_print_sensor(data, obj); - - return 0; -} - -#ifdef DEBUG -static char const *atk_sensor_type(union acpi_object *flags) -{ - u64 type = flags->integer.value & ATK_TYPE_MASK; - char const *what; - - switch (type) { - case HWMON_TYPE_VOLT: - what = "voltage"; - break; - case HWMON_TYPE_TEMP: - what = "temperature"; - break; - case HWMON_TYPE_FAN: - what = "fan"; - break; - default: - what = "unknown"; - break; - } - - return what; -} -#endif - -static void atk_print_sensor(struct atk_data *data, union acpi_object *obj) -{ -#ifdef DEBUG - struct device *dev = &data->acpi_dev->dev; - union acpi_object *flags; - union acpi_object *name; - union acpi_object *limit1; - union acpi_object *limit2; - union acpi_object *enable; - char const *what; - - flags = atk_get_pack_member(data, obj, HWMON_PACK_FLAGS); - name = atk_get_pack_member(data, obj, HWMON_PACK_NAME); - limit1 = atk_get_pack_member(data, obj, HWMON_PACK_LIMIT1); - limit2 = atk_get_pack_member(data, obj, HWMON_PACK_LIMIT2); - enable = atk_get_pack_member(data, obj, HWMON_PACK_ENABLE); - - what = atk_sensor_type(flags); - - dev_dbg(dev, "%s: %#llx %s [%llu-%llu] %s\n", what, - flags->integer.value, - name->string.pointer, - limit1->integer.value, limit2->integer.value, - enable->integer.value ? "enabled" : "disabled"); -#endif -} - -static int atk_read_value_old(struct atk_sensor_data *sensor, u64 *value) -{ - struct atk_data *data = sensor->data; - struct device *dev = &data->acpi_dev->dev; - struct acpi_object_list params; - union acpi_object id; - acpi_status status; - acpi_handle method; - - switch (sensor->type) { - case HWMON_TYPE_VOLT: - method = data->rvlt_handle; - break; - case HWMON_TYPE_TEMP: - method = data->rtmp_handle; - break; - case HWMON_TYPE_FAN: - method = data->rfan_handle; - break; - default: - return -EINVAL; - } - - id.type = ACPI_TYPE_INTEGER; - id.integer.value = sensor->id; - - params.count = 1; - params.pointer = &id; - - status = acpi_evaluate_integer(method, NULL, ¶ms, value); - if (status != AE_OK) { - dev_warn(dev, "%s: ACPI exception: %s\n", __func__, - acpi_format_exception(status)); - return -EIO; - } - - return 0; -} - -static union acpi_object *atk_ggrp(struct atk_data *data, u16 mux) -{ - struct device *dev = &data->acpi_dev->dev; - struct acpi_buffer buf; - acpi_status ret; - struct acpi_object_list params; - union acpi_object id; - union acpi_object *pack; - - id.type = ACPI_TYPE_INTEGER; - id.integer.value = mux; - params.count = 1; - params.pointer = &id; - - buf.length = ACPI_ALLOCATE_BUFFER; - ret = acpi_evaluate_object(data->enumerate_handle, NULL, ¶ms, &buf); - if (ret != AE_OK) { - dev_err(dev, "GGRP[%#x] ACPI exception: %s\n", mux, - acpi_format_exception(ret)); - return ERR_PTR(-EIO); - } - pack = buf.pointer; - if (pack->type != ACPI_TYPE_PACKAGE) { - /* Execution was successful, but the id was not found */ - ACPI_FREE(pack); - return ERR_PTR(-ENOENT); - } - - if (pack->package.count < 1) { - dev_err(dev, "GGRP[%#x] package is too small\n", mux); - ACPI_FREE(pack); - return ERR_PTR(-EIO); - } - return pack; -} - -static union acpi_object *atk_gitm(struct atk_data *data, u64 id) -{ - struct device *dev = &data->acpi_dev->dev; - struct atk_acpi_input_buf buf; - union acpi_object tmp; - struct acpi_object_list params; - struct acpi_buffer ret; - union acpi_object *obj; - acpi_status status; - - buf.id = id; - buf.param1 = 0; - buf.param2 = 0; - - tmp.type = ACPI_TYPE_BUFFER; - tmp.buffer.pointer = (u8 *)&buf; - tmp.buffer.length = sizeof(buf); - - params.count = 1; - params.pointer = (void *)&tmp; - - ret.length = ACPI_ALLOCATE_BUFFER; - status = acpi_evaluate_object_typed(data->read_handle, NULL, ¶ms, - &ret, ACPI_TYPE_BUFFER); - if (status != AE_OK) { - dev_warn(dev, "GITM[%#llx] ACPI exception: %s\n", id, - acpi_format_exception(status)); - return ERR_PTR(-EIO); - } - obj = ret.pointer; - - /* Sanity check */ - if (obj->buffer.length < 8) { - dev_warn(dev, "Unexpected ASBF length: %u\n", - obj->buffer.length); - ACPI_FREE(obj); - return ERR_PTR(-EIO); - } - return obj; -} - -static union acpi_object *atk_sitm(struct atk_data *data, - struct atk_acpi_input_buf *buf) -{ - struct device *dev = &data->acpi_dev->dev; - struct acpi_object_list params; - union acpi_object tmp; - struct acpi_buffer ret; - union acpi_object *obj; - acpi_status status; - - tmp.type = ACPI_TYPE_BUFFER; - tmp.buffer.pointer = (u8 *)buf; - tmp.buffer.length = sizeof(*buf); - - params.count = 1; - params.pointer = &tmp; - - ret.length = ACPI_ALLOCATE_BUFFER; - status = acpi_evaluate_object_typed(data->write_handle, NULL, ¶ms, - &ret, ACPI_TYPE_BUFFER); - if (status != AE_OK) { - dev_warn(dev, "SITM[%#x] ACPI exception: %s\n", buf->id, - acpi_format_exception(status)); - return ERR_PTR(-EIO); - } - obj = ret.pointer; - - /* Sanity check */ - if (obj->buffer.length < 8) { - dev_warn(dev, "Unexpected ASBF length: %u\n", - obj->buffer.length); - ACPI_FREE(obj); - return ERR_PTR(-EIO); - } - return obj; -} - -static int atk_read_value_new(struct atk_sensor_data *sensor, u64 *value) -{ - struct atk_data *data = sensor->data; - struct device *dev = &data->acpi_dev->dev; - union acpi_object *obj; - struct atk_acpi_ret_buffer *buf; - int err = 0; - - obj = atk_gitm(data, sensor->id); - if (IS_ERR(obj)) - return PTR_ERR(obj); - - buf = (struct atk_acpi_ret_buffer *)obj->buffer.pointer; - if (buf->flags == 0) { - /* - * The reading is not valid, possible causes: - * - sensor failure - * - enumeration was FUBAR (and we didn't notice) - */ - dev_warn(dev, "Read failed, sensor = %#llx\n", sensor->id); - err = -EIO; - goto out; - } - - *value = buf->value; -out: - ACPI_FREE(obj); - return err; -} - -static int atk_read_value(struct atk_sensor_data *sensor, u64 *value) -{ - int err; - - if (!sensor->is_valid || - time_after(jiffies, sensor->last_updated + CACHE_TIME)) { - if (sensor->data->old_interface) - err = atk_read_value_old(sensor, value); - else - err = atk_read_value_new(sensor, value); - - sensor->is_valid = true; - sensor->last_updated = jiffies; - sensor->cached_value = *value; - } else { - *value = sensor->cached_value; - err = 0; - } - - return err; -} - -#ifdef CONFIG_DEBUG_FS -static int atk_debugfs_gitm_get(void *p, u64 *val) -{ - struct atk_data *data = p; - union acpi_object *ret; - struct atk_acpi_ret_buffer *buf; - int err = 0; - - if (!data->read_handle) - return -ENODEV; - - if (!data->debugfs.id) - return -EINVAL; - - ret = atk_gitm(data, data->debugfs.id); - if (IS_ERR(ret)) - return PTR_ERR(ret); - - buf = (struct atk_acpi_ret_buffer *)ret->buffer.pointer; - if (buf->flags) - *val = buf->value; - else - err = -EIO; - - ACPI_FREE(ret); - return err; -} - -DEFINE_SIMPLE_ATTRIBUTE(atk_debugfs_gitm, - atk_debugfs_gitm_get, - NULL, - "0x%08llx\n") - -static int atk_acpi_print(char *buf, size_t sz, union acpi_object *obj) -{ - int ret = 0; - - switch (obj->type) { - case ACPI_TYPE_INTEGER: - ret = snprintf(buf, sz, "0x%08llx\n", obj->integer.value); - break; - case ACPI_TYPE_STRING: - ret = snprintf(buf, sz, "%s\n", obj->string.pointer); - break; - } - - return ret; -} - -static void atk_pack_print(char *buf, size_t sz, union acpi_object *pack) -{ - int ret; - int i; - - for (i = 0; i < pack->package.count; i++) { - union acpi_object *obj = &pack->package.elements[i]; - - ret = atk_acpi_print(buf, sz, obj); - if (ret >= sz) - break; - buf += ret; - sz -= ret; - } -} - -static int atk_debugfs_ggrp_open(struct inode *inode, struct file *file) -{ - struct atk_data *data = inode->i_private; - char *buf = NULL; - union acpi_object *ret; - u8 cls; - int i; - - if (!data->enumerate_handle) - return -ENODEV; - if (!data->debugfs.id) - return -EINVAL; - - cls = (data->debugfs.id & 0xff000000) >> 24; - ret = atk_ggrp(data, cls); - if (IS_ERR(ret)) - return PTR_ERR(ret); - - for (i = 0; i < ret->package.count; i++) { - union acpi_object *pack = &ret->package.elements[i]; - union acpi_object *id; - - if (pack->type != ACPI_TYPE_PACKAGE) - continue; - if (!pack->package.count) - continue; - id = &pack->package.elements[0]; - if (id->integer.value == data->debugfs.id) { - /* Print the package */ - buf = kzalloc(512, GFP_KERNEL); - if (!buf) { - ACPI_FREE(ret); - return -ENOMEM; - } - atk_pack_print(buf, 512, pack); - break; - } - } - ACPI_FREE(ret); - - if (!buf) - return -EINVAL; - - file->private_data = buf; - - return nonseekable_open(inode, file); -} - -static ssize_t atk_debugfs_ggrp_read(struct file *file, char __user *buf, - size_t count, loff_t *pos) -{ - char *str = file->private_data; - size_t len = strlen(str); - - return simple_read_from_buffer(buf, count, pos, str, len); -} - -static int atk_debugfs_ggrp_release(struct inode *inode, struct file *file) -{ - kfree(file->private_data); - return 0; -} - -static const struct file_operations atk_debugfs_ggrp_fops = { - .read = atk_debugfs_ggrp_read, - .open = atk_debugfs_ggrp_open, - .release = atk_debugfs_ggrp_release, - .llseek = no_llseek, -}; - -static void atk_debugfs_init(struct atk_data *data) -{ - struct dentry *d; - struct dentry *f; - - data->debugfs.id = 0; - - d = debugfs_create_dir("asus_atk0110", NULL); - if (!d || IS_ERR(d)) - return; - - f = debugfs_create_x32("id", S_IRUSR | S_IWUSR, d, &data->debugfs.id); - if (!f || IS_ERR(f)) - goto cleanup; - - f = debugfs_create_file("gitm", S_IRUSR, d, data, - &atk_debugfs_gitm); - if (!f || IS_ERR(f)) - goto cleanup; - - f = debugfs_create_file("ggrp", S_IRUSR, d, data, - &atk_debugfs_ggrp_fops); - if (!f || IS_ERR(f)) - goto cleanup; - - data->debugfs.root = d; - - return; -cleanup: - debugfs_remove_recursive(d); -} - -static void atk_debugfs_cleanup(struct atk_data *data) -{ - debugfs_remove_recursive(data->debugfs.root); -} - -#else /* CONFIG_DEBUG_FS */ - -static void atk_debugfs_init(struct atk_data *data) -{ -} - -static void atk_debugfs_cleanup(struct atk_data *data) -{ -} -#endif - -static int atk_add_sensor(struct atk_data *data, union acpi_object *obj) -{ - struct device *dev = &data->acpi_dev->dev; - union acpi_object *flags; - union acpi_object *name; - union acpi_object *limit1; - union acpi_object *limit2; - union acpi_object *enable; - struct atk_sensor_data *sensor; - char const *base_name; - char const *limit1_name; - char const *limit2_name; - u64 type; - int err; - int *num; - int start; - - if (obj->type != ACPI_TYPE_PACKAGE) { - /* wft is this? */ - dev_warn(dev, "Unknown type for ACPI object: (%d)\n", - obj->type); - return -EINVAL; - } - - err = validate_hwmon_pack(data, obj); - if (err) - return err; - - /* Ok, we have a valid hwmon package */ - type = atk_get_pack_member(data, obj, HWMON_PACK_FLAGS)->integer.value - & ATK_TYPE_MASK; - - switch (type) { - case HWMON_TYPE_VOLT: - base_name = "in"; - limit1_name = "min"; - limit2_name = "max"; - num = &data->voltage_count; - start = 0; - break; - case HWMON_TYPE_TEMP: - base_name = "temp"; - limit1_name = "max"; - limit2_name = "crit"; - num = &data->temperature_count; - start = 1; - break; - case HWMON_TYPE_FAN: - base_name = "fan"; - limit1_name = "min"; - limit2_name = "max"; - num = &data->fan_count; - start = 1; - break; - default: - dev_warn(dev, "Unknown sensor type: %#llx\n", type); - return -EINVAL; - } - - enable = atk_get_pack_member(data, obj, HWMON_PACK_ENABLE); - if (!enable->integer.value) - /* sensor is disabled */ - return 0; - - flags = atk_get_pack_member(data, obj, HWMON_PACK_FLAGS); - name = atk_get_pack_member(data, obj, HWMON_PACK_NAME); - limit1 = atk_get_pack_member(data, obj, HWMON_PACK_LIMIT1); - limit2 = atk_get_pack_member(data, obj, HWMON_PACK_LIMIT2); - - sensor = kzalloc(sizeof(*sensor), GFP_KERNEL); - if (!sensor) - return -ENOMEM; - - sensor->acpi_name = kstrdup(name->string.pointer, GFP_KERNEL); - if (!sensor->acpi_name) { - err = -ENOMEM; - goto out; - } - - INIT_LIST_HEAD(&sensor->list); - sensor->type = type; - sensor->data = data; - sensor->id = flags->integer.value; - sensor->limit1 = limit1->integer.value; - if (data->old_interface) - sensor->limit2 = limit2->integer.value; - else - /* The upper limit is expressed as delta from lower limit */ - sensor->limit2 = sensor->limit1 + limit2->integer.value; - - snprintf(sensor->input_attr_name, ATTR_NAME_SIZE, - "%s%d_input", base_name, start + *num); - atk_init_attribute(&sensor->input_attr, - sensor->input_attr_name, - atk_input_show); - - snprintf(sensor->label_attr_name, ATTR_NAME_SIZE, - "%s%d_label", base_name, start + *num); - atk_init_attribute(&sensor->label_attr, - sensor->label_attr_name, - atk_label_show); - - snprintf(sensor->limit1_attr_name, ATTR_NAME_SIZE, - "%s%d_%s", base_name, start + *num, limit1_name); - atk_init_attribute(&sensor->limit1_attr, - sensor->limit1_attr_name, - atk_limit1_show); - - snprintf(sensor->limit2_attr_name, ATTR_NAME_SIZE, - "%s%d_%s", base_name, start + *num, limit2_name); - atk_init_attribute(&sensor->limit2_attr, - sensor->limit2_attr_name, - atk_limit2_show); - - list_add(&sensor->list, &data->sensor_list); - (*num)++; - - return 1; -out: - kfree(sensor->acpi_name); - kfree(sensor); - return err; -} - -static int atk_enumerate_old_hwmon(struct atk_data *data) -{ - struct device *dev = &data->acpi_dev->dev; - struct acpi_buffer buf; - union acpi_object *pack; - acpi_status status; - int i, ret; - int count = 0; - - /* Voltages */ - buf.length = ACPI_ALLOCATE_BUFFER; - status = acpi_evaluate_object_typed(data->atk_handle, - METHOD_OLD_ENUM_VLT, NULL, &buf, ACPI_TYPE_PACKAGE); - if (status != AE_OK) { - dev_warn(dev, METHOD_OLD_ENUM_VLT ": ACPI exception: %s\n", - acpi_format_exception(status)); - - return -ENODEV; - } - - pack = buf.pointer; - for (i = 1; i < pack->package.count; i++) { - union acpi_object *obj = &pack->package.elements[i]; - - ret = atk_add_sensor(data, obj); - if (ret > 0) - count++; - } - ACPI_FREE(buf.pointer); - - /* Temperatures */ - buf.length = ACPI_ALLOCATE_BUFFER; - status = acpi_evaluate_object_typed(data->atk_handle, - METHOD_OLD_ENUM_TMP, NULL, &buf, ACPI_TYPE_PACKAGE); - if (status != AE_OK) { - dev_warn(dev, METHOD_OLD_ENUM_TMP ": ACPI exception: %s\n", - acpi_format_exception(status)); - - ret = -ENODEV; - goto cleanup; - } - - pack = buf.pointer; - for (i = 1; i < pack->package.count; i++) { - union acpi_object *obj = &pack->package.elements[i]; - - ret = atk_add_sensor(data, obj); - if (ret > 0) - count++; - } - ACPI_FREE(buf.pointer); - - /* Fans */ - buf.length = ACPI_ALLOCATE_BUFFER; - status = acpi_evaluate_object_typed(data->atk_handle, - METHOD_OLD_ENUM_FAN, NULL, &buf, ACPI_TYPE_PACKAGE); - if (status != AE_OK) { - dev_warn(dev, METHOD_OLD_ENUM_FAN ": ACPI exception: %s\n", - acpi_format_exception(status)); - - ret = -ENODEV; - goto cleanup; - } - - pack = buf.pointer; - for (i = 1; i < pack->package.count; i++) { - union acpi_object *obj = &pack->package.elements[i]; - - ret = atk_add_sensor(data, obj); - if (ret > 0) - count++; - } - ACPI_FREE(buf.pointer); - - return count; -cleanup: - atk_free_sensors(data); - return ret; -} - -static int atk_ec_present(struct atk_data *data) -{ - struct device *dev = &data->acpi_dev->dev; - union acpi_object *pack; - union acpi_object *ec; - int ret; - int i; - - pack = atk_ggrp(data, ATK_MUX_MGMT); - if (IS_ERR(pack)) { - if (PTR_ERR(pack) == -ENOENT) { - /* The MGMT class does not exists - that's ok */ - dev_dbg(dev, "Class %#llx not found\n", ATK_MUX_MGMT); - return 0; - } - return PTR_ERR(pack); - } - - /* Search the EC */ - ec = NULL; - for (i = 0; i < pack->package.count; i++) { - union acpi_object *obj = &pack->package.elements[i]; - union acpi_object *id; - - if (obj->type != ACPI_TYPE_PACKAGE) - continue; - - id = &obj->package.elements[0]; - if (id->type != ACPI_TYPE_INTEGER) - continue; - - if (id->integer.value == ATK_EC_ID) { - ec = obj; - break; - } - } - - ret = (ec != NULL); - if (!ret) - /* The system has no EC */ - dev_dbg(dev, "EC not found\n"); - - ACPI_FREE(pack); - return ret; -} - -static int atk_ec_enabled(struct atk_data *data) -{ - struct device *dev = &data->acpi_dev->dev; - union acpi_object *obj; - struct atk_acpi_ret_buffer *buf; - int err; - - obj = atk_gitm(data, ATK_EC_ID); - if (IS_ERR(obj)) { - dev_err(dev, "Unable to query EC status\n"); - return PTR_ERR(obj); - } - buf = (struct atk_acpi_ret_buffer *)obj->buffer.pointer; - - if (buf->flags == 0) { - dev_err(dev, "Unable to query EC status\n"); - err = -EIO; - } else { - err = (buf->value != 0); - dev_dbg(dev, "EC is %sabled\n", - err ? "en" : "dis"); - } - - ACPI_FREE(obj); - return err; -} - -static int atk_ec_ctl(struct atk_data *data, int enable) -{ - struct device *dev = &data->acpi_dev->dev; - union acpi_object *obj; - struct atk_acpi_input_buf sitm; - struct atk_acpi_ret_buffer *ec_ret; - int err = 0; - - sitm.id = ATK_EC_ID; - sitm.param1 = enable; - sitm.param2 = 0; - - obj = atk_sitm(data, &sitm); - if (IS_ERR(obj)) { - dev_err(dev, "Failed to %sable the EC\n", - enable ? "en" : "dis"); - return PTR_ERR(obj); - } - ec_ret = (struct atk_acpi_ret_buffer *)obj->buffer.pointer; - if (ec_ret->flags == 0) { - dev_err(dev, "Failed to %sable the EC\n", - enable ? "en" : "dis"); - err = -EIO; - } else { - dev_info(dev, "EC %sabled\n", - enable ? "en" : "dis"); - } - - ACPI_FREE(obj); - return err; -} - -static int atk_enumerate_new_hwmon(struct atk_data *data) -{ - struct device *dev = &data->acpi_dev->dev; - union acpi_object *pack; - int err; - int i; - - err = atk_ec_present(data); - if (err < 0) - return err; - if (err) { - err = atk_ec_enabled(data); - if (err < 0) - return err; - /* If the EC was disabled we will disable it again on unload */ - data->disable_ec = err; - - err = atk_ec_ctl(data, 1); - if (err) { - data->disable_ec = false; - return err; - } - } - - dev_dbg(dev, "Enumerating hwmon sensors\n"); - - pack = atk_ggrp(data, ATK_MUX_HWMON); - if (IS_ERR(pack)) - return PTR_ERR(pack); - - for (i = 0; i < pack->package.count; i++) { - union acpi_object *obj = &pack->package.elements[i]; - - atk_add_sensor(data, obj); - } - - err = data->voltage_count + data->temperature_count + data->fan_count; - - ACPI_FREE(pack); - return err; -} - -static int atk_create_files(struct atk_data *data) -{ - struct atk_sensor_data *s; - int err; - - list_for_each_entry(s, &data->sensor_list, list) { - err = device_create_file(data->hwmon_dev, &s->input_attr); - if (err) - return err; - err = device_create_file(data->hwmon_dev, &s->label_attr); - if (err) - return err; - err = device_create_file(data->hwmon_dev, &s->limit1_attr); - if (err) - return err; - err = device_create_file(data->hwmon_dev, &s->limit2_attr); - if (err) - return err; - } - - err = device_create_file(data->hwmon_dev, &atk_name_attr); - - return err; -} - -static void atk_remove_files(struct atk_data *data) -{ - struct atk_sensor_data *s; - - list_for_each_entry(s, &data->sensor_list, list) { - device_remove_file(data->hwmon_dev, &s->input_attr); - device_remove_file(data->hwmon_dev, &s->label_attr); - device_remove_file(data->hwmon_dev, &s->limit1_attr); - device_remove_file(data->hwmon_dev, &s->limit2_attr); - } - device_remove_file(data->hwmon_dev, &atk_name_attr); -} - -static void atk_free_sensors(struct atk_data *data) -{ - struct list_head *head = &data->sensor_list; - struct atk_sensor_data *s, *tmp; - - list_for_each_entry_safe(s, tmp, head, list) { - kfree(s->acpi_name); - kfree(s); - } -} - -static int atk_register_hwmon(struct atk_data *data) -{ - struct device *dev = &data->acpi_dev->dev; - int err; - - dev_dbg(dev, "registering hwmon device\n"); - data->hwmon_dev = hwmon_device_register(dev); - if (IS_ERR(data->hwmon_dev)) - return PTR_ERR(data->hwmon_dev); - - dev_dbg(dev, "populating sysfs directory\n"); - err = atk_create_files(data); - if (err) - goto remove; - - return 0; -remove: - /* Cleanup the registered files */ - atk_remove_files(data); - hwmon_device_unregister(data->hwmon_dev); - return err; -} - -static int atk_probe_if(struct atk_data *data) -{ - struct device *dev = &data->acpi_dev->dev; - acpi_handle ret; - acpi_status status; - int err = 0; - - /* RTMP: read temperature */ - status = acpi_get_handle(data->atk_handle, METHOD_OLD_READ_TMP, &ret); - if (ACPI_SUCCESS(status)) - data->rtmp_handle = ret; - else - dev_dbg(dev, "method " METHOD_OLD_READ_TMP " not found: %s\n", - acpi_format_exception(status)); - - /* RVLT: read voltage */ - status = acpi_get_handle(data->atk_handle, METHOD_OLD_READ_VLT, &ret); - if (ACPI_SUCCESS(status)) - data->rvlt_handle = ret; - else - dev_dbg(dev, "method " METHOD_OLD_READ_VLT " not found: %s\n", - acpi_format_exception(status)); - - /* RFAN: read fan status */ - status = acpi_get_handle(data->atk_handle, METHOD_OLD_READ_FAN, &ret); - if (ACPI_SUCCESS(status)) - data->rfan_handle = ret; - else - dev_dbg(dev, "method " METHOD_OLD_READ_FAN " not found: %s\n", - acpi_format_exception(status)); - - /* Enumeration */ - status = acpi_get_handle(data->atk_handle, METHOD_ENUMERATE, &ret); - if (ACPI_SUCCESS(status)) - data->enumerate_handle = ret; - else - dev_dbg(dev, "method " METHOD_ENUMERATE " not found: %s\n", - acpi_format_exception(status)); - - /* De-multiplexer (read) */ - status = acpi_get_handle(data->atk_handle, METHOD_READ, &ret); - if (ACPI_SUCCESS(status)) - data->read_handle = ret; - else - dev_dbg(dev, "method " METHOD_READ " not found: %s\n", - acpi_format_exception(status)); - - /* De-multiplexer (write) */ - status = acpi_get_handle(data->atk_handle, METHOD_WRITE, &ret); - if (ACPI_SUCCESS(status)) - data->write_handle = ret; - else - dev_dbg(dev, "method " METHOD_WRITE " not found: %s\n", - acpi_format_exception(status)); - - /* - * Check for hwmon methods: first check "old" style methods; note that - * both may be present: in this case we stick to the old interface; - * analysis of multiple DSDTs indicates that when both interfaces - * are present the new one (GGRP/GITM) is not functional. - */ - if (new_if) - dev_info(dev, "Overriding interface detection\n"); - if (data->rtmp_handle && - data->rvlt_handle && data->rfan_handle && !new_if) - data->old_interface = true; - else if (data->enumerate_handle && data->read_handle && - data->write_handle) - data->old_interface = false; - else - err = -ENODEV; - - return err; -} - -static int atk_add(struct acpi_device *device) -{ - acpi_status ret; - int err; - struct acpi_buffer buf; - union acpi_object *obj; - struct atk_data *data; - - dev_dbg(&device->dev, "adding...\n"); - - data = kzalloc(sizeof(*data), GFP_KERNEL); - if (!data) - return -ENOMEM; - - data->acpi_dev = device; - data->atk_handle = device->handle; - INIT_LIST_HEAD(&data->sensor_list); - data->disable_ec = false; - - buf.length = ACPI_ALLOCATE_BUFFER; - ret = acpi_evaluate_object_typed(data->atk_handle, BOARD_ID, NULL, - &buf, ACPI_TYPE_PACKAGE); - if (ret != AE_OK) { - dev_dbg(&device->dev, "atk: method MBIF not found\n"); - } else { - obj = buf.pointer; - if (obj->package.count >= 2) { - union acpi_object *id = &obj->package.elements[1]; - if (id->type == ACPI_TYPE_STRING) - dev_dbg(&device->dev, "board ID = %s\n", - id->string.pointer); - } - ACPI_FREE(buf.pointer); - } - - err = atk_probe_if(data); - if (err) { - dev_err(&device->dev, "No usable hwmon interface detected\n"); - goto out; - } - - if (data->old_interface) { - dev_dbg(&device->dev, "Using old hwmon interface\n"); - err = atk_enumerate_old_hwmon(data); - } else { - dev_dbg(&device->dev, "Using new hwmon interface\n"); - err = atk_enumerate_new_hwmon(data); - } - if (err < 0) - goto out; - if (err == 0) { - dev_info(&device->dev, - "No usable sensor detected, bailing out\n"); - err = -ENODEV; - goto out; - } - - err = atk_register_hwmon(data); - if (err) - goto cleanup; - - atk_debugfs_init(data); - - device->driver_data = data; - return 0; -cleanup: - atk_free_sensors(data); -out: - if (data->disable_ec) - atk_ec_ctl(data, 0); - kfree(data); - return err; -} - -static int atk_remove(struct acpi_device *device, int type) -{ - struct atk_data *data = device->driver_data; - dev_dbg(&device->dev, "removing...\n"); - - device->driver_data = NULL; - - atk_debugfs_cleanup(data); - - atk_remove_files(data); - atk_free_sensors(data); - hwmon_device_unregister(data->hwmon_dev); - - if (data->disable_ec) { - if (atk_ec_ctl(data, 0)) - dev_err(&device->dev, "Failed to disable EC\n"); - } - - kfree(data); - - return 0; -} - -static int __init atk0110_init(void) -{ - int ret; - - /* Make sure it's safe to access the device through ACPI */ - if (!acpi_resources_are_enforced()) { - pr_err("Resources not safely usable due to acpi_enforce_resources kernel parameter\n"); - return -EBUSY; - } - - if (dmi_check_system(atk_force_new_if)) - new_if = true; - - ret = acpi_bus_register_driver(&atk_driver); - if (ret) - pr_info("acpi_bus_register_driver failed: %d\n", ret); - - return ret; -} - -static void __exit atk0110_exit(void) -{ - acpi_bus_unregister_driver(&atk_driver); -} - -module_init(atk0110_init); -module_exit(atk0110_exit); - -MODULE_LICENSE("GPL"); |