aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/hwmon/asus_atk0110.c
diff options
context:
space:
mode:
authorLuca Tettamanti <kronos.it@gmail.com>2010-01-10 14:52:33 -0500
committerJean Delvare <khali@linux-fr.org>2010-01-10 14:52:33 -0500
commit7e5eab1128a05b99b8c81c01ff6515a3ca25e5aa (patch)
treea39f3f6bce1e38b434ffdf371eae2eb56c0ecfcd /drivers/hwmon/asus_atk0110.c
parent8ba406be53713efdd705666e2178cfe486fcfb27 (diff)
hwmon: (asus_atk0110) Add debugfs interface
Expose the raw GGRP/GITM interface via debugfs. The hwmon interface is reverse engineered and the driver tends to break on newer boards... Using this interface it's possible to poke directly at the ACPI methods without the need to recompile, reducing the guesswork and the round trips needed to support a new revision of the interface. Signed-off-by: Luca Tettamanti <kronos.it@gmail.com> Signed-off-by: Jean Delvare <khali@linux-fr.org>
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 @@
5 * See COPYING in the top level directory of the kernel tree. 5 * See COPYING in the top level directory of the kernel tree.
6 */ 6 */
7 7
8#include <linux/debugfs.h>
8#include <linux/kernel.h> 9#include <linux/kernel.h>
9#include <linux/hwmon.h> 10#include <linux/hwmon.h>
10#include <linux/list.h> 11#include <linux/list.h>
@@ -101,6 +102,11 @@ struct atk_data {
101 int temperature_count; 102 int temperature_count;
102 int fan_count; 103 int fan_count;
103 struct list_head sensor_list; 104 struct list_head sensor_list;
105
106 struct {
107 struct dentry *root;
108 u32 id;
109 } debugfs;
104}; 110};
105 111
106 112
@@ -624,6 +630,187 @@ static int atk_read_value(struct atk_sensor_data *sensor, u64 *value)
624 return err; 630 return err;
625} 631}
626 632
633#ifdef CONFIG_DEBUG_FS
634static int atk_debugfs_gitm_get(void *p, u64 *val)
635{
636 struct atk_data *data = p;
637 union acpi_object *ret;
638 struct atk_acpi_ret_buffer *buf;
639 int err = 0;
640
641 if (!data->read_handle)
642 return -ENODEV;
643
644 if (!data->debugfs.id)
645 return -EINVAL;
646
647 ret = atk_gitm(data, data->debugfs.id);
648 if (IS_ERR(ret))
649 return PTR_ERR(ret);
650
651 buf = (struct atk_acpi_ret_buffer *)ret->buffer.pointer;
652 if (buf->flags)
653 *val = buf->value;
654 else
655 err = -EIO;
656
657 return err;
658}
659
660DEFINE_SIMPLE_ATTRIBUTE(atk_debugfs_gitm,
661 atk_debugfs_gitm_get,
662 NULL,
663 "0x%08llx\n")
664
665static int atk_acpi_print(char *buf, size_t sz, union acpi_object *obj)
666{
667 int ret = 0;
668
669 switch (obj->type) {
670 case ACPI_TYPE_INTEGER:
671 ret = snprintf(buf, sz, "0x%08llx\n", obj->integer.value);
672 break;
673 case ACPI_TYPE_STRING:
674 ret = snprintf(buf, sz, "%s\n", obj->string.pointer);
675 break;
676 }
677
678 return ret;
679}
680
681static void atk_pack_print(char *buf, size_t sz, union acpi_object *pack)
682{
683 int ret;
684 int i;
685
686 for (i = 0; i < pack->package.count; i++) {
687 union acpi_object *obj = &pack->package.elements[i];
688
689 ret = atk_acpi_print(buf, sz, obj);
690 if (ret >= sz)
691 break;
692 buf += ret;
693 sz -= ret;
694 }
695}
696
697static int atk_debugfs_ggrp_open(struct inode *inode, struct file *file)
698{
699 struct atk_data *data = inode->i_private;
700 char *buf = NULL;
701 union acpi_object *ret;
702 u8 cls;
703 int i;
704
705 if (!data->enumerate_handle)
706 return -ENODEV;
707 if (!data->debugfs.id)
708 return -EINVAL;
709
710 cls = (data->debugfs.id & 0xff000000) >> 24;
711 ret = atk_ggrp(data, cls);
712 if (IS_ERR(ret))
713 return PTR_ERR(ret);
714
715 for (i = 0; i < ret->package.count; i++) {
716 union acpi_object *pack = &ret->package.elements[i];
717 union acpi_object *id;
718
719 if (pack->type != ACPI_TYPE_PACKAGE)
720 continue;
721 if (!pack->package.count)
722 continue;
723 id = &pack->package.elements[0];
724 if (id->integer.value == data->debugfs.id) {
725 /* Print the package */
726 buf = kzalloc(512, GFP_KERNEL);
727 if (!buf) {
728 ACPI_FREE(ret);
729 return -ENOMEM;
730 }
731 atk_pack_print(buf, 512, pack);
732 break;
733 }
734 }
735 ACPI_FREE(ret);
736
737 if (!buf)
738 return -EINVAL;
739
740 file->private_data = buf;
741
742 return nonseekable_open(inode, file);
743}
744
745static ssize_t atk_debugfs_ggrp_read(struct file *file, char __user *buf,
746 size_t count, loff_t *pos)
747{
748 char *str = file->private_data;
749 size_t len = strlen(str);
750
751 return simple_read_from_buffer(buf, count, pos, str, len);
752}
753
754static int atk_debugfs_ggrp_release(struct inode *inode, struct file *file)
755{
756 kfree(file->private_data);
757 return 0;
758}
759
760static const struct file_operations atk_debugfs_ggrp_fops = {
761 .read = atk_debugfs_ggrp_read,
762 .open = atk_debugfs_ggrp_open,
763 .release = atk_debugfs_ggrp_release,
764};
765
766static void atk_debugfs_init(struct atk_data *data)
767{
768 struct dentry *d;
769 struct dentry *f;
770
771 data->debugfs.id = 0;
772
773 d = debugfs_create_dir("asus_atk0110", NULL);
774 if (!d || IS_ERR(d))
775 return;
776
777 f = debugfs_create_x32("id", S_IRUSR | S_IWUSR, d, &data->debugfs.id);
778 if (!f || IS_ERR(f))
779 goto cleanup;
780
781 f = debugfs_create_file("gitm", S_IRUSR, d, data,
782 &atk_debugfs_gitm);
783 if (!f || IS_ERR(f))
784 goto cleanup;
785
786 f = debugfs_create_file("ggrp", S_IRUSR, d, data,
787 &atk_debugfs_ggrp_fops);
788 if (!f || IS_ERR(f))
789 goto cleanup;
790
791 data->debugfs.root = d;
792
793 return;
794cleanup:
795 debugfs_remove_recursive(d);
796}
797
798static void atk_debugfs_cleanup(struct atk_data *data)
799{
800 debugfs_remove_recursive(data->debugfs.root);
801}
802
803#else /* CONFIG_DEBUG_FS */
804
805static void atk_debugfs_init(struct atk_data *data)
806{
807}
808
809static void atk_debugfs_cleanup(struct atk_data *data)
810{
811}
812#endif
813
627static int atk_add_sensor(struct atk_data *data, union acpi_object *obj) 814static int atk_add_sensor(struct atk_data *data, union acpi_object *obj)
628{ 815{
629 struct device *dev = &data->acpi_dev->dev; 816 struct device *dev = &data->acpi_dev->dev;
@@ -1180,6 +1367,8 @@ static int atk_add(struct acpi_device *device)
1180 if (err) 1367 if (err)
1181 goto cleanup; 1368 goto cleanup;
1182 1369
1370 atk_debugfs_init(data);
1371
1183 device->driver_data = data; 1372 device->driver_data = data;
1184 return 0; 1373 return 0;
1185cleanup: 1374cleanup:
@@ -1198,6 +1387,8 @@ static int atk_remove(struct acpi_device *device, int type)
1198 1387
1199 device->driver_data = NULL; 1388 device->driver_data = NULL;
1200 1389
1390 atk_debugfs_cleanup(data);
1391
1201 atk_remove_files(data); 1392 atk_remove_files(data);
1202 atk_free_sensors(data); 1393 atk_free_sensors(data);
1203 hwmon_device_unregister(data->hwmon_dev); 1394 hwmon_device_unregister(data->hwmon_dev);