summaryrefslogtreecommitdiffstats
path: root/drivers/hwmon/asus_atk0110.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/hwmon/asus_atk0110.c')
-rw-r--r--drivers/hwmon/asus_atk0110.c191
1 files changed, 191 insertions, 0 deletions
diff --git a/drivers/hwmon/asus_atk0110.c b/drivers/hwmon/asus_atk0110.c
index 11739819badd..6811346c1c62 100644
--- a/drivers/hwmon/asus_atk0110.c
+++ b/drivers/hwmon/asus_atk0110.c
@@ -5,6 +5,7 @@
* See COPYING in the top level directory of the kernel tree.
*/
+#include <linux/debugfs.h>
#include <linux/kernel.h>
#include <linux/hwmon.h>
#include <linux/list.h>
@@ -101,6 +102,11 @@ struct atk_data {
int temperature_count;
int fan_count;
struct list_head sensor_list;
+
+ struct {
+ struct dentry *root;
+ u32 id;
+ } debugfs;
};
@@ -624,6 +630,187 @@ static int atk_read_value(struct atk_sensor_data *sensor, u64 *value)
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;
+
+ 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,
+};
+
+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;
@@ -1180,6 +1367,8 @@ static int atk_add(struct acpi_device *device)
if (err)
goto cleanup;
+ atk_debugfs_init(data);
+
device->driver_data = data;
return 0;
cleanup:
@@ -1198,6 +1387,8 @@ static int atk_remove(struct acpi_device *device, int type)
device->driver_data = NULL;
+ atk_debugfs_cleanup(data);
+
atk_remove_files(data);
atk_free_sensors(data);
hwmon_device_unregister(data->hwmon_dev);