All of lore.kernel.org
 help / color / mirror / Atom feed
* Re: [lm-sensors] Asus atk0110 driver
@ 2008-06-18 21:26 Luca Tettamanti
  2008-06-19  7:16 ` Jean Delvare
                   ` (6 more replies)
  0 siblings, 7 replies; 8+ messages in thread
From: Luca Tettamanti @ 2008-06-18 21:26 UTC (permalink / raw)
  To: lm-sensors

[-- Attachment #1: Type: text/plain, Size: 3882 bytes --]

Il Mon, Jun 16, 2008 at 09:32:27AM +0200, Jean Delvare ha scritto: 
> Hi Luca,
> 
> On Mon, 2 Jun 2008 01:25:30 +0200, Luca Tettamanti wrote:
> > Hi Thomas,
> > I'm attaching a new version of my driver; I've done some refactoring &
> > cleanup and I should I've addresses all the comments from the last time.
> > 
> > A few reminders:
> > - asus_acpi claims the same ID, so the two are exclusive (but should be ok
> >   since notebooks doesn't have the ACPI hw monitoring stuff)
> > - the driver is read only, i.e. it's not possible to control fan speed
> >   (and other overclocking stuff) though the hw is capable of doing it
> > - I exported a few ACPI functions: acpi_ns_map_handle_to_node,
> >   acpi_ns_convert_entry_to_handle and acpi_ns_get_node for inspecting
> >   ACPI methods and ensure that all the expected stuff is there;
> >   acpi_evaluate_object_typed since it's very handy to let it do the
> >   check on the returned data instead of open-coding it all over the
> >   driver
> 
> Apparently your post was not archived on acpi4asus-user. Can you please
> post your driver again, on the lm-sensors list this time? I'd like it
> to be archived publicly so that we can point users to it and it doesn't
> get lost.

Sure. This is the patch for in-kernel ACPI (diff against vanilla
952f4a0a, somewhere after 2.6.26-rc6):

diff --git a/drivers/acpi/namespace/nsutils.c b/drivers/acpi/namespace/nsutils.c
index 64c0398..56e806b 100644
--- a/drivers/acpi/namespace/nsutils.c
+++ b/drivers/acpi/namespace/nsutils.c
@@ -700,6 +700,7 @@ struct acpi_namespace_node *acpi_ns_map_handle_to_node(acpi_handle handle)
 
 	return (ACPI_CAST_PTR(struct acpi_namespace_node, handle));
 }
+EXPORT_SYMBOL(acpi_ns_map_handle_to_node);
 
 /*******************************************************************************
  *
@@ -736,6 +737,7 @@ acpi_handle acpi_ns_convert_entry_to_handle(struct acpi_namespace_node *node)
 	return ((acpi_handle) Node);
 ------------------------------------------------------*/
 }
+EXPORT_SYMBOL(acpi_ns_convert_entry_to_handle);
 
 /*******************************************************************************
  *
@@ -875,6 +877,7 @@ acpi_ns_get_node(struct acpi_namespace_node *prefix_node,
 	ACPI_FREE(internal_path);
 	return_ACPI_STATUS(status);
 }
+EXPORT_SYMBOL(acpi_ns_get_node);
 
 /*******************************************************************************
  *
diff --git a/drivers/acpi/namespace/nsxfeval.c b/drivers/acpi/namespace/nsxfeval.c
index a8d5491..141f9e3 100644
--- a/drivers/acpi/namespace/nsxfeval.c
+++ b/drivers/acpi/namespace/nsxfeval.c
@@ -48,7 +48,7 @@
 
 #define _COMPONENT          ACPI_NAMESPACE
 ACPI_MODULE_NAME("nsxfeval")
-#ifdef ACPI_FUTURE_USAGE
+
 /*******************************************************************************
  *
  * FUNCTION:    acpi_evaluate_object_typed
@@ -141,7 +141,7 @@ acpi_evaluate_object_typed(acpi_handle handle,
 }
 
 ACPI_EXPORT_SYMBOL(acpi_evaluate_object_typed)
-#endif				/*  ACPI_FUTURE_USAGE  */
+
 /*******************************************************************************
  *
  * FUNCTION:    acpi_evaluate_object
diff --git a/include/acpi/acpixf.h b/include/acpi/acpixf.h
index 2c3806e..76372a0 100644
--- a/include/acpi/acpixf.h
+++ b/include/acpi/acpixf.h
@@ -169,14 +169,12 @@ acpi_evaluate_object(acpi_handle object,
 		     struct acpi_object_list *parameter_objects,
 		     struct acpi_buffer *return_object_buffer);
 
-#ifdef ACPI_FUTURE_USAGE
 acpi_status
 acpi_evaluate_object_typed(acpi_handle object,
 			   acpi_string pathname,
 			   struct acpi_object_list *external_params,
 			   struct acpi_buffer *return_buffer,
 			   acpi_object_type return_type);
-#endif
 
 acpi_status
 acpi_get_object_info(acpi_handle handle, struct acpi_buffer *return_buffer);


The source of the driver is attached (text/plain).

Luca
-- 
Not an editor command: Wq

[-- Attachment #2: atk.c --]
[-- Type: text/plain, Size: 28789 bytes --]

/*
 * Copyright (C) 2007 Luca Tettamanti <kronos.it@gmail.com>
 * See COPYING in the top level directory of the kernel tree.
 */

#define DEBUG

#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/hwmon.h>

#include <acpi/acpi.h>
#include <acpi/acnamesp.h>
#include <acpi/acpi_drivers.h>
#include <acpi/acpi_bus.h>


#define ATK_HID "ATK0110"
#define ATK_DRV "atk-hwmon"
#define ASOC "_SB.PCI0.SBRG.ASOC"

struct atk_data {
	struct device *dev;
	acpi_handle atk_handle;
	struct acpi_device *acpi_dev;

	acpi_handle rtmp_handle;
	acpi_handle rvlt_handle;
	acpi_handle rfan_handle;
} atk_data;


typedef ssize_t (*sysfs_show_func)(struct device *dev,
			struct device_attribute *attr, char *buf);

typedef ssize_t (*sysfs_store_func)(struct device *dev,
			struct device_attribute *attr, const char *buf,
			size_t count);


static void atk_init_attribute(struct device_attribute *attr, char *name,
		mode_t mode, sysfs_show_func show, sysfs_store_func store)
{
	attr->attr.name = name;
	attr->attr.mode = mode;
	attr->show = show;
	attr->store = store;
}

#define ATTR_NAME_SIZE 16 /* Worst case is "tempN_input" */

enum atk_pack_value_id {
	ATK_PACK_VALUE_MIN = 2,
	ATK_PACK_VALUE_MAX = 3,
};

static int atk_pack_read(char *name, int pack_id,
		enum atk_pack_value_id value_id, unsigned long *out)
{
	struct acpi_buffer ret;
	union acpi_object *id;
	union acpi_object *pack;
	union acpi_object *obj;
	union acpi_object *val;
	acpi_status status;
	int err = 0;
	int i;

	ret.length = ACPI_ALLOCATE_BUFFER;

	status = acpi_evaluate_object_typed(atk_data.atk_handle, name, NULL,
			&ret, ACPI_TYPE_PACKAGE);
	if (status != AE_OK) {
		dev_warn(&atk_data.acpi_dev->dev, "%s: ACPI exception: %s\n",
				__func__, acpi_format_exception(status));
		return -EIO;
	}

	obj = ret.pointer;

	err = -ENOENT;
	for (i = 1; i < obj->package.count; i++) {
		pack = &obj->package.elements[i];
		id = &pack->package.elements[0];
		val = &pack->package.elements[value_id];

		if (pack_id == id->integer.value) {
			*out = val->integer.value;
			err = 0;
			break;
		}
	}

	ACPI_FREE(ret.pointer);

	return err;
}

struct atk_temp {
	struct device_attribute label_attr;
	struct device_attribute input_attr;
	struct device_attribute max_attr;
	struct device_attribute crit_attr;
	char label_attr_name[ATTR_NAME_SIZE];
	char input_attr_name[ATTR_NAME_SIZE];
	char max_attr_name[ATTR_NAME_SIZE];
	char crit_attr_name[ATTR_NAME_SIZE];
	u64 id;
	char *acpi_name;
};

struct atk_temp_list {
	int count;
	struct atk_temp temp[];
};

#define input_to_atk_temp(attr) \
	container_of(attr, struct atk_temp, input_attr)

static ssize_t atk_temp_input_show(struct device *dev,
		struct device_attribute *attr, char *buf)
{
	struct atk_temp *a = input_to_atk_temp(attr);
	unsigned long temp;
	struct acpi_object_list params;
	union acpi_object id;
	acpi_status status;
	ssize_t count;

	id.type = ACPI_TYPE_INTEGER;
	id.integer.value = a->id;

	params.count = 1;
	params.pointer = &id;

	status = acpi_evaluate_integer(atk_data.rtmp_handle, NULL, &params, &temp);
	if (status != AE_OK) {
		dev_warn(dev, "%s: ACPI exception: %s\n", __func__,
				acpi_format_exception(status));
		return -EIO;
	}

	/* ACPI returns decidegree */
	count = sprintf(buf, "%lu\n", temp * 100);

	return count;
}

#define label_to_atk_temp(attr) \
	container_of(attr, struct atk_temp, label_attr)

static ssize_t atk_temp_label_show(struct device *dev,
		struct device_attribute *attr, char *buf)
{
	struct atk_temp *a = label_to_atk_temp(attr);

	return sprintf(buf, "%s\n", a->acpi_name);
}

#define max_to_atk_temp(attr) \
	container_of(attr, struct atk_temp, max_attr)

static ssize_t atk_temp_max_show(struct device *dev,
		struct device_attribute *attr, char *buf)
{
	struct atk_temp *a = max_to_atk_temp(attr);
	unsigned long temp;

	/* Yes, this is correct... tmax is the first value */
	if (atk_pack_read("TSIF", a->id, ATK_PACK_VALUE_MIN, &temp))
		return -EIO;

	return sprintf(buf, "%ld\n", temp * 100);
}

#define crit_to_atk_temp(attr) \
	container_of(attr, struct atk_temp, crit_attr)

static ssize_t atk_temp_crit_show(struct device *dev,
		struct device_attribute *attr, char *buf)
{
	struct atk_temp *a = crit_to_atk_temp(attr);
	unsigned long temp;

	if (atk_pack_read("TSIF", a->id, ATK_PACK_VALUE_MAX, &temp))
		return -EIO;

	return sprintf(buf, "%ld\n", temp * 100);
}

struct atk_voltage {
	struct device_attribute input_attr;
	struct device_attribute label_attr;
	struct device_attribute min_attr;
	struct device_attribute max_attr;
	char label_attr_name[ATTR_NAME_SIZE];
	char input_attr_name[ATTR_NAME_SIZE];
	char min_attr_name[ATTR_NAME_SIZE];
	char max_attr_name[ATTR_NAME_SIZE];
	u64 id;
	char const *acpi_name;
};

struct atk_voltage_list {
	int count;
	struct atk_voltage voltage[];
};

#define label_to_atk_voltage(attr) \
	container_of(attr, struct atk_voltage, label_attr)

static ssize_t atk_voltage_label_show(struct device *dev,
		struct device_attribute *attr, char *buf)
{
	struct atk_voltage *a = label_to_atk_voltage(attr);

	return sprintf(buf, "%s\n", a->acpi_name);
}

#define input_to_atk_voltage(attr) \
	container_of(attr, struct atk_voltage, input_attr)

static ssize_t atk_voltage_input_show(struct device *dev,
		struct device_attribute *attr, char *buf)
{
	struct atk_voltage *a = input_to_atk_voltage(attr);
	unsigned long voltage;
	struct acpi_object_list params;
	union acpi_object id;
	acpi_status status;

	id.type = ACPI_TYPE_INTEGER;
	id.integer.value = a->id;

	params.count = 1;
	params.pointer = &id;

	status = acpi_evaluate_integer(atk_data.rvlt_handle, NULL, &params, &voltage);
	if (status != AE_OK) {
		dev_warn(dev, "%s: ACPI exception: %s\n", __func__,
				acpi_format_exception(status));
		return -EIO;
	}

	return sprintf(buf, "%lu\n", voltage);
}

#define max_to_atk_voltage(attr) \
	container_of(attr, struct atk_voltage, max_attr)

static ssize_t atk_voltage_max_show(struct device *dev,
		struct device_attribute *attr, char *buf)
{
	struct atk_voltage *a = max_to_atk_voltage(attr);
	unsigned long volt;

	if (atk_pack_read("VSIF", a->id, ATK_PACK_VALUE_MAX, &volt))
		return -EIO;

	return sprintf(buf, "%lu\n", volt);
}

#define min_to_atk_voltage(attr) \
	container_of(attr, struct atk_voltage, min_attr)

static ssize_t atk_voltage_min_show(struct device *dev,
		struct device_attribute *attr, char *buf)
{
	struct atk_voltage *a = min_to_atk_voltage(attr);
	unsigned long volt;

	if (atk_pack_read("VSIF", a->id, ATK_PACK_VALUE_MIN, &volt))
		return -EIO;

	return sprintf(buf, "%lu\n", volt);
}

struct atk_fan {
	struct device_attribute input_attr;
	struct device_attribute label_attr;
	struct device_attribute min_attr;
	struct device_attribute max_attr;
	char input_attr_name[ATTR_NAME_SIZE];
	char label_attr_name[ATTR_NAME_SIZE];
	char min_attr_name[ATTR_NAME_SIZE];
	char max_attr_name[ATTR_NAME_SIZE];
	u64 id;
	char const *acpi_name;
};

struct atk_fan_list {
	int count;
	struct atk_fan fan[];
};

#define input_to_atk_fan(attr) \
	container_of(attr, struct atk_fan, input_attr)

static ssize_t atk_fan_input_show(struct device *dev,
		struct device_attribute *attr, char *buf)
{
	struct atk_fan *a = input_to_atk_fan(attr);
	unsigned long rotation;
	struct acpi_object_list params;
	union acpi_object id;
	acpi_status status;

	id.type = ACPI_TYPE_INTEGER;
	id.integer.value = a->id;

	params.count = 1;
	params.pointer = &id;

	status = acpi_evaluate_integer(atk_data.rfan_handle, NULL, &params, &rotation);
	if (status != AE_OK) {
		dev_warn(dev, "%s: ACPI exception: %s\n", __func__,
				acpi_format_exception(status));
		return -EIO;
	}

	return sprintf(buf, "%lu\n", rotation);
}

#define label_to_atk_fan(attr) \
	container_of(attr, struct atk_fan, label_attr)

static ssize_t atk_fan_label_show(struct device *dev,
		struct device_attribute *attr, char *buf)
{
	struct atk_fan *a = label_to_atk_fan(attr);

	return sprintf(buf, "%s\n", a->acpi_name);
}

#define min_to_atk_fan(attr) \
	container_of(attr, struct atk_fan, min_attr)

static ssize_t atk_fan_min_show(struct device *dev,
		struct device_attribute *attr, char *buf)
{
	struct atk_fan *a = min_to_atk_fan(attr);
	unsigned long rot;
	int err;

	err = atk_pack_read("FSIF", a->id, ATK_PACK_VALUE_MIN, &rot);
	if (err)
		return err;

	return sprintf(buf, "%ld\n", rot);
}

#define max_to_atk_fan(attr) \
	container_of(attr, struct atk_fan, max_attr)

static ssize_t atk_fan_max_show(struct device *dev,
		struct device_attribute *attr, char *buf)
{
	struct atk_fan *a = max_to_atk_fan(attr);
	unsigned long rot;

	if (atk_pack_read("FSIF", a->id, ATK_PACK_VALUE_MAX, &rot))
		return -EIO;

	return sprintf(buf, "%ld\n", rot);;
}

static ssize_t atk_name_show(struct device *dev,
		struct device_attribute *attr, char *buf)
{
	return sprintf(buf, "atk0110-0\n");
}

static struct device_attribute atk_name_attr = __ATTR(name, 0444, atk_name_show, NULL);

struct atk_temp_list *temp_list;
struct atk_voltage_list *voltage_list;
struct atk_fan_list *fan_list;

static int atk_add(struct acpi_device *device);
static int atk_remove(struct acpi_device *device, int type);

static const struct acpi_device_id atk_ids[] = {
	{ATK_HID, 0},
	{"", 0},
};
MODULE_DEVICE_TABLE(acpi, atk_ids);

static struct acpi_driver atk_driver = {
	.name	= ATK_HID,
	.class	= "hwmon",
	.ids	= atk_ids,
	.ops	= {
		.add	= atk_add,
		.remove	= atk_remove,
	},
};

static int atk_create_files(struct device *dev)
{
	int i;
	int ret;

	/* Temperatures */
	for (i = 0; i < temp_list->count; i++) {
		ret = device_create_file(dev, &temp_list->temp[i].input_attr);
		if (ret)
			return ret;
		ret = device_create_file(dev, &temp_list->temp[i].label_attr);
		if (ret)
			return ret;
		ret = device_create_file(dev, &temp_list->temp[i].max_attr);
		if (ret)
			return ret;
		ret = device_create_file(dev, &temp_list->temp[i].crit_attr);
		if (ret)
			return ret;
	}

	/* Voltages */
	for (i = 0; i < voltage_list->count; i++) {
		ret = device_create_file(dev, &voltage_list->voltage[i].input_attr);
		if (ret)
			return ret;
		ret = device_create_file(dev, &voltage_list->voltage[i].label_attr);
		if (ret)
			return ret;
		ret = device_create_file(dev, &voltage_list->voltage[i].min_attr);
		if (ret)
			return ret;
		ret = device_create_file(dev, &voltage_list->voltage[i].max_attr);
		if (ret)
			return ret;
	}

	/* Fans */
	for (i = 0; i < fan_list->count; i++) {
		ret = device_create_file(dev, &fan_list->fan[i].input_attr);
		if (ret)
			return ret;
		ret = device_create_file(dev, &fan_list->fan[i].label_attr);
		if (ret)
			return ret;
		ret = device_create_file(dev, &fan_list->fan[i].min_attr);
		if (ret)
			return ret;
		ret = device_create_file(dev, &fan_list->fan[i].max_attr);
		if (ret)
			return ret;
	}

	ret = device_create_file(dev, &atk_name_attr);

	return ret;
}

static void atk_remove_files(struct device *dev)
{
	int i;

	/* Temperatures */
	if (temp_list) {
		for (i = 0; i < temp_list->count; i++) {
			device_remove_file(dev, &temp_list->temp[i].input_attr);
			device_remove_file(dev, &temp_list->temp[i].label_attr);
			kfree(temp_list->temp[i].acpi_name);
			device_remove_file(dev, &temp_list->temp[i].max_attr);
			device_remove_file(dev, &temp_list->temp[i].crit_attr);
		}
	}
	kfree(temp_list);
	temp_list = NULL;

	/* Voltages */
	if (voltage_list) {
		for (i = 0; i < voltage_list->count; i++) {
			device_remove_file(dev, &voltage_list->voltage[i].input_attr);
			device_remove_file(dev, &voltage_list->voltage[i].label_attr);
			kfree(voltage_list->voltage[i].acpi_name);
			device_remove_file(dev, &voltage_list->voltage[i].min_attr);
			device_remove_file(dev, &voltage_list->voltage[i].max_attr);
		}
	}
	kfree(voltage_list);
	voltage_list = NULL;

	/* Fans */
	if (fan_list) {
		for (i = 0; i < fan_list->count; i++) {
			device_remove_file(dev, &fan_list->fan[i].input_attr);
			device_remove_file(dev, &fan_list->fan[i].label_attr);
			kfree(fan_list->fan[i].acpi_name);
			device_remove_file(dev, &fan_list->fan[i].min_attr);
			device_remove_file(dev, &fan_list->fan[i].max_attr);
		}
	}
	kfree(fan_list);
	voltage_list = NULL;

	device_remove_file(dev, &atk_name_attr);
}

static int atk_check_package(struct device *dev, char const *fn, int i,
		union acpi_object *pack)
{
	union acpi_object *obj;

	/* Expected format:
	 *
	 * ACPI_TYPE_INTEGER (id)
	 * ACPI_TYPE_STRING (name)
	 * ACPI_TYPE_INTEGER (min or max)
	 * ACPI_TYPE_INTEGER (max or crit)
	 * ACPI_TYPE_INTEGER (enable)
	 */

	obj = &pack->package.elements[0];
	if (obj->type != ACPI_TYPE_INTEGER) {
		dev_warn(dev, "%s: object %d, int expected (id), got: %d\n",
				fn, i, obj->type);
		return -EINVAL;
	}

	obj = &pack->package.elements[1];
	if (obj->type != ACPI_TYPE_STRING) {
		dev_warn(dev, "%s: object %d, string expected, got: %d\n",
				fn, i, obj->type);
		return -EINVAL;
	}

	obj = &pack->package.elements[2];
	if (obj->type != ACPI_TYPE_INTEGER) {
		dev_warn(dev, "%s: object %d, int expected (l1), got: %d\n",
				fn, i, obj->type);
		return -EINVAL;
	}

	obj = &pack->package.elements[3];
	if (obj->type != ACPI_TYPE_INTEGER) {
		dev_warn(dev, "%s: object %d, int expected (l2), got: %d\n",
				fn, i, obj->type);
		return -EINVAL;
	}

	obj = &pack->package.elements[4];
	if (obj->type != ACPI_TYPE_INTEGER) {
		dev_warn(dev, "%s: object %d, int expected (en), got: %d\n",
				fn, i, obj->type);
		return -EINVAL;
	}

	return 0;
}

static int atk_enumerate_temp(struct acpi_buffer *temp_buf)
{
	struct atk_temp_list *tmp;
	union acpi_object *pack;
	union acpi_object *obj;
	struct device *dev = &atk_data.acpi_dev->dev;
	int i, ret;
	int next;

	/* Result must be a package */
	pack = temp_buf->pointer;

	if (pack->package.count < 1) {
		dev_dbg(dev, "%s: temp package is too small: %d\n", __func__,
				pack->package.count);
		return -EINVAL;
	}

	/* First field is the number of available readings */
	obj = &pack->package.elements[0];
	if (obj->type != ACPI_TYPE_INTEGER) {
		dev_dbg(dev, "%s: temp package: invalid type for "
				"element 0: %d\n", __func__, obj->type);
		return -EINVAL;
	}

	/* The count may differ in case one or more sensors are disabled */
	if (pack->package.count != obj->integer.value + 1) {
		dev_dbg(dev, "%s: temperature count (%llu) differs "
				"from package count (%u)\n", __func__,
				obj->integer.value, pack->package.count);
	}

	tmp = kzalloc(sizeof(*tmp) + sizeof(*tmp->temp) * obj->integer.value, GFP_KERNEL);
	if (!tmp)
		return -ENOMEM;

	tmp->count = obj->integer.value;
	next = 0;
	for (i = 0; i < pack->package.count - 1; i++) {
		union acpi_object *temp_pack;
		union acpi_object *name;
		union acpi_object *tmax;
		union acpi_object *tcrit;
		union acpi_object *acpi_id;
		union acpi_object *enable;

		temp_pack = &pack->package.elements[i + 1];

		/* object should be a temperature package */
		if (temp_pack->type != ACPI_TYPE_PACKAGE) {
			dev_warn(dev, "%s: invalid type for element %d: %d\n",
					__func__, i, temp_pack->type);
			ret = -EINVAL;
			goto cleanup;
		}

		/* Temperature package:
		 * byte buffer?
		 *   [3]: used by GITM/SITM to locate correct GITx/SITx,
		 *        method, same as the other package (GPID)
		 *   [2]: same as the other package, seems unused in
		 *        GITM/STIM
		 *   [1]: type?
		 *        1: cpu freq?
		 *        2: voltage
		 *        3: temperature
		 *        4: fan
		 *        7: Q-FAN (alarm?)
		 *        8: NOS
		 *   [0]: used by GITx/SITx for demux; selects the
		 *        value stored in ASB1 (PRM0)
		 * description
		 * max
		 * critical
		 * enable
		 */

		if (temp_pack->package.count != 5) {
			dev_dbg(dev, "%s: invalid package count "
					"for object %d: %u\n", __func__,
					i + 1, temp_pack->package.count);
			ret = -EINVAL;
			goto cleanup;
		}

		if (atk_check_package(dev, __func__, i, temp_pack)) {
			ret = -EINVAL;
			goto cleanup;
		}

		acpi_id = &temp_pack->package.elements[0];
		name = &temp_pack->package.elements[1];
		tmax = &temp_pack->package.elements[2];
		tcrit = &temp_pack->package.elements[3];
		enable = &temp_pack->package.elements[4];

		dev_dbg(dev, "temp %d: %#llx %s [%llu-%llu] %s\n", next,
				acpi_id->integer.value,
				name->string.pointer,
				tmax->integer.value, tcrit->integer.value,
				enable->integer.value ? "enabled" : "disabled");

		if (!enable->integer.value) {
			tmp->count--;
			continue;
		}

		tmp->temp[next].id = acpi_id->integer.value;

		snprintf(tmp->temp[next].input_attr_name, ATTR_NAME_SIZE,
				"temp%d_input", next + 1);
		atk_init_attribute(&tmp->temp[next].input_attr,
				tmp->temp[next].input_attr_name,
				0444, atk_temp_input_show, NULL);

		tmp->temp[next].acpi_name = kstrdup(name->string.pointer, GFP_KERNEL);
		snprintf(tmp->temp[next].label_attr_name, ATTR_NAME_SIZE,
				"temp%d_label", next + 1);
		atk_init_attribute(&tmp->temp[next].label_attr,
				tmp->temp[next].label_attr_name,
				0444, atk_temp_label_show, NULL);

		snprintf(tmp->temp[next].max_attr_name, ATTR_NAME_SIZE,
				"temp%d_max", next + 1);
		atk_init_attribute(&tmp->temp[next].max_attr,
				tmp->temp[next].max_attr_name,
				0444, atk_temp_max_show, NULL);

		snprintf(tmp->temp[next].crit_attr_name, ATTR_NAME_SIZE,
				"temp%d_crit", next + 1);
		atk_init_attribute(&tmp->temp[next].crit_attr,
				tmp->temp[next].crit_attr_name,
				0444, atk_temp_crit_show, NULL);

		next++;
	}

	temp_list = tmp;

	return 0;
cleanup:
	for (i = 0; i < tmp->count; i++)
		kfree(tmp->temp[i].acpi_name);
	kfree(tmp);

	return ret;
}

static int atk_enumerate_voltage(struct acpi_buffer *vlt_buf)
{
	struct device *dev = &atk_data.acpi_dev->dev;
	union acpi_object *pack;
	union acpi_object *obj;
	struct atk_voltage_list *vlt;
	int ret, i;
	int next;

	pack = vlt_buf->pointer;

	/* At least one element is expected */
	if (pack->package.count < 1) {
		dev_warn(dev, "%s: voltage pack is too small: %d\n", __func__,
				pack->package.count);
		return -EINVAL;
	}

	/* First field is the number of available readings */
	obj = &pack->package.elements[0];
	if (obj->type != ACPI_TYPE_INTEGER) {
		dev_warn(dev, "%s: voltage pack: invalid type for element 0: %d\n",
				__func__, obj->type);
	}

	/* The count may differ in case one or more sensors are disabled */
	if (obj->integer.value + 1 != pack->package.count) {
		dev_warn(dev, "%s: invalid voltage count %llu (should be %d)\n",
			__func__, obj->integer.value, pack->package.count - 1);
	}

	vlt = kzalloc(sizeof(*vlt) + sizeof(*vlt->voltage) * obj->integer.value, GFP_KERNEL);
	if (!vlt)
		return -ENOMEM;

	vlt->count = obj->integer.value;
	next = 0;
	for (i = 0; i < pack->package.count - 1; i++) {
		union acpi_object *voltage_pack;
		union acpi_object *name;
		union acpi_object *vmax;
		union acpi_object *vmin;
		union acpi_object *acpi_id;
		union acpi_object *enable;

		voltage_pack = &pack->package.elements[i + 1];

		/*  voltage package */
		if (voltage_pack->type != ACPI_TYPE_PACKAGE) {
			dev_warn(dev, "%s: invalid type for element %d: %d\n",
					__func__, i, voltage_pack->type);
			ret = -EINVAL;
			goto cleanup;
		}

		/* Package:
		 * id
		 * description
		 * min
		 * max
		 * enable
		 */

		if (voltage_pack->package.count != 5) {
			dev_warn(dev, "%s: invalid package for object %d: %d\n",
				__func__, i, voltage_pack->package.count);
			ret = -EINVAL;
			goto cleanup;
		}

		if (atk_check_package(dev, __func__, i, voltage_pack)) {
			ret = -EINVAL;
			goto cleanup;
		}

		acpi_id = &voltage_pack->package.elements[0];
		name = &voltage_pack->package.elements[1];
		vmin = &voltage_pack->package.elements[2];
		vmax = &voltage_pack->package.elements[3];
		enable = &voltage_pack->package.elements[4];

		dev_dbg(dev, "voltage %d: %#llx %s [%llu-%llu] %s\n", next,
				acpi_id->integer.value,
				name->string.pointer, vmin->integer.value,
				vmax->integer.value,
				enable->integer.value ? "enabled" : "disbaled");

		if (!enable->integer.value) {
			vlt->count--;
			continue;
		}

		vlt->voltage[next].id = acpi_id->integer.value;
		vlt->voltage[next].acpi_name = kstrdup(name->string.pointer, GFP_KERNEL);

		snprintf(vlt->voltage[next].input_attr_name, ATTR_NAME_SIZE,
				"in%d_input", next);
		atk_init_attribute(&vlt->voltage[next].input_attr,
				vlt->voltage[next].input_attr_name,
				0444, atk_voltage_input_show, NULL);

		snprintf(vlt->voltage[next].label_attr_name, ATTR_NAME_SIZE,
				"in%d_label", next);
		atk_init_attribute(&vlt->voltage[next].label_attr,
				vlt->voltage[next].label_attr_name,
				0444, atk_voltage_label_show, NULL);

		snprintf(vlt->voltage[next].max_attr_name, ATTR_NAME_SIZE,
				"in%d_max", next);
		atk_init_attribute(&vlt->voltage[next].max_attr,
				vlt->voltage[next].max_attr_name,
				0444, atk_voltage_max_show, NULL);

		snprintf(vlt->voltage[next].min_attr_name, ATTR_NAME_SIZE,
				"in%d_min", next);
		atk_init_attribute(&vlt->voltage[next].min_attr,
				vlt->voltage[next].min_attr_name,
				0444, atk_voltage_min_show, NULL);

		next++;
	}

	voltage_list = vlt;

	return 0;

cleanup:
	for (i = 0; i < vlt->count; i++)
		kfree(vlt->voltage[i].acpi_name);
	kfree(vlt);

	return ret;
}

static int atk_enumerate_fan(struct acpi_buffer *fan_buf)
{
	struct device *dev = &atk_data.acpi_dev->dev;
	union acpi_object *pack;
	union acpi_object *obj;
	struct atk_fan_list *fan;
	int ret, i;
	int count, next;

	pack = fan_buf->pointer;

	if (pack->package.count < 1) {
		dev_warn(dev, "%s: fan package is too small: %d\n",
				__func__, pack->package.count);
		return -EINVAL;
	}

	obj = &pack->package.elements[0];
	if (obj->type != ACPI_TYPE_INTEGER) {
		dev_warn(dev, "%s: fan package: invalid type for element 0: %d\n",
				__func__, obj->type);
		return -EINVAL;
	}

	/* Don't fail, it's not fatal */
	if (obj->integer.value + 1 != pack->package.count) {
		dev_dbg(dev, "%s: invalid fan count? %llu (should be %d)\n",
			__func__, obj->integer.value, pack->package.count - 1);
	}

	count = pack->package.count - 1;

	fan = kzalloc(sizeof(*fan) + sizeof(*fan->fan) * count, GFP_KERNEL);
	if (!fan)
		return -ENOMEM;

	fan->count = count;
	next = 0;
	for (i = 0; i < pack->package.count - 1; i++) {
		union acpi_object *fan_pack;
		union acpi_object *acpi_id;
		union acpi_object *name;
		union acpi_object *fmin;
		union acpi_object *fmax;
		union acpi_object *enable;

		/* fan package */
		fan_pack = &pack->package.elements[i + 1];

		if (fan_pack->type != ACPI_TYPE_PACKAGE) {
			dev_warn(dev, "%s: invalid type type for element %d: %d\n",
					__func__, i + 1, fan_pack->type);
			ret = -EINVAL;
			goto cleanup;
		}

		/* Fan package:
		 * id (usual stuff)
		 * description
		 * min
		 * max
		 * enable bit (disabled = 0, enabled otherwise)
		 */

		if (fan_pack->package.count != 5) {
			dev_warn(dev, "%s: invalid package len for object %d: %d\n",
				__func__, i + 1, fan_pack->package.count);
			ret = -EINVAL;
			goto cleanup;
		}

		if (atk_check_package(dev, __func__, i, fan_pack)) {
			ret = -EINVAL;
			goto cleanup;
		}

		acpi_id = &fan_pack->package.elements[0];
		name = &fan_pack->package.elements[1];
		fmin = &fan_pack->package.elements[2];
		fmax = &fan_pack->package.elements[3];
		enable = &fan_pack->package.elements[4];

		dev_dbg(dev, "fan %d: %#llx %s [%llu-%llu] %s\n", i,
				acpi_id->integer.value, name->string.pointer,
				fmin->integer.value, fmax->integer.value,
				enable->integer.value ? "enabled" : "disabled");

		if (!enable->integer.value) {
			fan->count--;
			continue;
		}

		fan->fan[next].id = acpi_id->integer.value;
		fan->fan[next].acpi_name = kstrdup(name->string.pointer, GFP_KERNEL);

		snprintf(fan->fan[next].input_attr_name, ATTR_NAME_SIZE,
				"fan%d_input", next + 1);
		atk_init_attribute(&fan->fan[next].input_attr,
				fan->fan[next].input_attr_name,
				0444, atk_fan_input_show, NULL);

		snprintf(fan->fan[next].label_attr_name, ATTR_NAME_SIZE,
				"fan%d_label", next + 1);
		atk_init_attribute(&fan->fan[next].label_attr,
				fan->fan[next].label_attr_name,
				0444, atk_fan_label_show, NULL);

		snprintf(fan->fan[next].min_attr_name, ATTR_NAME_SIZE,
				"fan%d_min", next + 1);
		atk_init_attribute(&fan->fan[next].min_attr,
				fan->fan[next].min_attr_name,
				0444, atk_fan_min_show, NULL);

		snprintf(fan->fan[next].max_attr_name, ATTR_NAME_SIZE,
				"fan%d_max", next + 1);
		atk_init_attribute(&fan->fan[next].max_attr,
				fan->fan[next].max_attr_name,
				0444, atk_fan_max_show, NULL);

		next++;
	}

	fan_list = fan;

	return 0;
cleanup:
	for (i = 0; i < fan->count; i++)
		kfree(fan->fan[i].acpi_name);
	kfree(fan);

	return ret;
}

static int atk_add(struct acpi_device *device)
{
	acpi_status ret;
	int err, i;
	struct acpi_buffer buf;
	union acpi_object *obj;
	struct acpi_namespace_node *search_ns;
	struct acpi_namespace_node *ns;

	dev_dbg(&device->dev, "atk: adding...\n");

	atk_data.acpi_dev = device;
	atk_data.atk_handle = device->handle;

	buf.length = ACPI_ALLOCATE_BUFFER;
	ret = acpi_evaluate_object_typed(atk_data.atk_handle, "MBIF", NULL,
			&buf, ACPI_TYPE_PACKAGE);
	if (ret != AE_OK) {
		dev_dbg(&device->dev, "atk: method MBIF not found\n");
		return -ENODEV;
	}

	obj = buf.pointer;
	if (obj->package.count >= 2 &&
			obj->package.elements[1].type == ACPI_TYPE_STRING) {
		dev_dbg(&device->dev, "board ID = %s\n",
				obj->package.elements[1].string.pointer);
	}
	ACPI_FREE(buf.pointer);

	/* Check for hwmon methods */
	search_ns = acpi_ns_map_handle_to_node(device->handle);
	if (!search_ns)
		return -ENODEV;

	/* RTMP: read temperature */
	ret = acpi_ns_get_node(search_ns, "RTMP", ACPI_NS_NO_UPSEARCH, &ns);
	if (ret != AE_OK) {
		dev_dbg(&device->dev, "method RTMP not found\n");
		return -ENODEV;
	}
	atk_data.rtmp_handle = acpi_ns_convert_entry_to_handle(ns);

	/* RVLT: read voltage */
	ret = acpi_ns_get_node(search_ns, "RVLT", ACPI_NS_NO_UPSEARCH, &ns);
	if (ret != AE_OK) {
		dev_dbg(&device->dev, "method RVLT not found\n");
		return -ENODEV;
	}
	atk_data.rvlt_handle = acpi_ns_convert_entry_to_handle(ns);

	/* RFAN: read fan status */
	ret = acpi_ns_get_node(search_ns, "RFAN", ACPI_NS_NO_UPSEARCH, &ns);
	if (ret != AE_OK) {
		dev_dbg(&device->dev, "method RFAN not found\n");
		return -ENODEV;
	}
	atk_data.rfan_handle = acpi_ns_convert_entry_to_handle(ns);

	/* Enumerate temp data - TSIF */
	buf.length = ACPI_ALLOCATE_BUFFER;
	ret = acpi_evaluate_object_typed(atk_data.atk_handle, "TSIF", NULL,
			&buf, ACPI_TYPE_PACKAGE);
	if (ret != AE_OK) {
		dev_warn(&device->dev, "TSIF: ACPI exception: %s\n",
				acpi_format_exception(ret));
		return -ENODEV;
	}

	err = atk_enumerate_temp(&buf);
	ACPI_FREE(buf.pointer);
	if (err)
		return err;

	/* Enumerate voltage data - VSIF */
	buf.length = ACPI_ALLOCATE_BUFFER;
	ret = acpi_evaluate_object_typed(atk_data.atk_handle, "VSIF", NULL,
			&buf, ACPI_TYPE_PACKAGE);
	if (ret != AE_OK) {
		dev_warn(&device->dev, "VSIF: ACPI exception: %s\n",
				acpi_format_exception(ret));

		err = -ENODEV;
		goto cleanup;
	}

	err = atk_enumerate_voltage(&buf);
	ACPI_FREE(buf.pointer);
	if (err)
		goto cleanup;

	/* Enumerate fan data - FSIF */
	buf.length = ACPI_ALLOCATE_BUFFER;
	ret = acpi_evaluate_object_typed(atk_data.atk_handle, "FSIF", NULL,
			&buf, ACPI_TYPE_PACKAGE);
	if (ret != AE_OK) {
		dev_warn(&device->dev, "TSIF: ACPI exception: %s\n",
				acpi_format_exception(ret));

		err = -ENODEV;
		goto cleanup;
	}

	err = atk_enumerate_fan(&buf);
	ACPI_FREE(buf.pointer);
	if (err)
		goto cleanup;

	dev_dbg(&atk_data.acpi_dev->dev, "registering hwmon device\n");
	atk_data.dev = hwmon_device_register(&atk_data.acpi_dev->dev);
	if (IS_ERR(atk_data.dev)) {
		err = PTR_ERR(atk_data.dev);
		goto cleanup;
	}

	dev_dbg(&atk_data.acpi_dev->dev, "populating sysfs directory\n");
	err = atk_create_files(&atk_data.acpi_dev->dev);
	if (err)
		goto remove;

	acpi_driver_data(device) = &atk_data;

	return 0;
remove:
	atk_remove_files(&atk_data.acpi_dev->dev);
	hwmon_device_unregister(atk_data.dev);

	return err;
cleanup:
	if (temp_list) {
		for (i = 0; i < temp_list->count; i++)
			kfree(temp_list->temp[i].acpi_name);
	}
	kfree(temp_list);

	if (voltage_list) {
		for (i = 0; i < voltage_list->count; i++)
			kfree(voltage_list->voltage[i].acpi_name);
	}
	kfree(voltage_list);

	if (fan_list) {
		for (i = 0; i < fan_list->count; i++)
			kfree(fan_list->fan[i].acpi_name);
	}
	kfree(fan_list);

	temp_list = NULL;
	voltage_list = NULL;
	fan_list = NULL;

	return err;
}

static int atk_remove(struct acpi_device *device, int type)
{
	dev_dbg(&device->dev, "removing...\n");

	acpi_driver_data(device) = NULL;

	hwmon_device_unregister(atk_data.dev);
	atk_remove_files(&atk_data.acpi_dev->dev);

	return 0;
}

int atk_init(void)
{
	int ret;

	ret = acpi_bus_register_driver(&atk_driver);
	if (ret)
		pr_info("atk: acpi_bus_register_driver failed: %d\n", ret);

	return ret;
}

void atk_exit(void)
{
	acpi_bus_unregister_driver(&atk_driver);
}

module_init(atk_init);
module_exit(atk_exit);

MODULE_LICENSE("GPL");

[-- Attachment #3: Type: text/plain, Size: 153 bytes --]

_______________________________________________
lm-sensors mailing list
lm-sensors@lm-sensors.org
http://lists.lm-sensors.org/mailman/listinfo/lm-sensors

^ permalink raw reply related	[flat|nested] 8+ messages in thread

* Re: [lm-sensors] Asus atk0110 driver
  2008-06-18 21:26 [lm-sensors] Asus atk0110 driver Luca Tettamanti
@ 2008-06-19  7:16 ` Jean Delvare
  2008-06-22 16:15 ` Gabriel C
                   ` (5 subsequent siblings)
  6 siblings, 0 replies; 8+ messages in thread
From: Jean Delvare @ 2008-06-19  7:16 UTC (permalink / raw)
  To: lm-sensors

On Wed, 18 Jun 2008 23:26:29 +0200, Luca Tettamanti wrote:
> Il Mon, Jun 16, 2008 at 09:32:27AM +0200, Jean Delvare ha scritto: 
> > Apparently your post was not archived on acpi4asus-user. Can you please
> > post your driver again, on the lm-sensors list this time? I'd like it
> > to be archived publicly so that we can point users to it and it doesn't
> > get lost.
> 
> Sure. This is the patch for in-kernel ACPI (diff against vanilla
> 952f4a0a, somewhere after 2.6.26-rc6):
> (...)
> The source of the driver is attached (text/plain).

Thanks Luca. I've added a link to your post on wiki/Devices so that
interested users and developers can find it easily.

-- 
Jean Delvare

_______________________________________________
lm-sensors mailing list
lm-sensors@lm-sensors.org
http://lists.lm-sensors.org/mailman/listinfo/lm-sensors

^ permalink raw reply	[flat|nested] 8+ messages in thread

* Re: [lm-sensors] Asus atk0110 driver
  2008-06-18 21:26 [lm-sensors] Asus atk0110 driver Luca Tettamanti
  2008-06-19  7:16 ` Jean Delvare
@ 2008-06-22 16:15 ` Gabriel C
  2008-06-23  9:06 ` Jean Delvare
                   ` (4 subsequent siblings)
  6 siblings, 0 replies; 8+ messages in thread
From: Gabriel C @ 2008-06-22 16:15 UTC (permalink / raw)
  To: lm-sensors

Jean Delvare wrote:

Hi Jean , Luca ,

> On Wed, 18 Jun 2008 23:26:29 +0200, Luca Tettamanti wrote:
>> Il Mon, Jun 16, 2008 at 09:32:27AM +0200, Jean Delvare ha scritto: 
>>> Apparently your post was not archived on acpi4asus-user. Can you please
>>> post your driver again, on the lm-sensors list this time? I'd like it
>>> to be archived publicly so that we can point users to it and it doesn't
>>> get lost.
>> Sure. This is the patch for in-kernel ACPI (diff against vanilla
>> 952f4a0a, somewhere after 2.6.26-rc6):
>> (...)
>> The source of the driver is attached (text/plain).
> 
> Thanks Luca. I've added a link to your post on wiki/Devices so that
> interested users and developers can find it easily.
> 


I've tested the driver with linux-next on my P5E-VM DO motherboard.

The driver seems to work , the values / data in  /sys/class/hwmon/hwmon0/device/*
seems to be the same like what the BIOS reports.

However how do I get sensors to display the data from atk driver ?
I guess I have to patch lm-sensors ?

Luca what do you think about creating  a proper patch for the driver too and send it over to 
Greg to be included in his linux-staging tree ? I think that way it will get more testing.

Best Regards ,

Gabriel

_______________________________________________
lm-sensors mailing list
lm-sensors@lm-sensors.org
http://lists.lm-sensors.org/mailman/listinfo/lm-sensors

^ permalink raw reply	[flat|nested] 8+ messages in thread

* Re: [lm-sensors] Asus atk0110 driver
  2008-06-18 21:26 [lm-sensors] Asus atk0110 driver Luca Tettamanti
  2008-06-19  7:16 ` Jean Delvare
  2008-06-22 16:15 ` Gabriel C
@ 2008-06-23  9:06 ` Jean Delvare
  2008-06-23 12:41 ` Gabriel C
                   ` (3 subsequent siblings)
  6 siblings, 0 replies; 8+ messages in thread
From: Jean Delvare @ 2008-06-23  9:06 UTC (permalink / raw)
  To: lm-sensors

Hi Gabriel,

On Sun, 22 Jun 2008 18:15:51 +0200, Gabriel C wrote:
> I've tested the driver with linux-next on my P5E-VM DO motherboard.
> 
> The driver seems to work , the values / data in  /sys/class/hwmon/hwmon0/device/*
> seems to be the same like what the BIOS reports.
> 
> However how do I get sensors to display the data from atk driver ?
> I guess I have to patch lm-sensors ?

For lm-sensors 2.10.x, yes, you'd need to patch libsensors and sensors
and virtually every monitoring application out there.

But the preferred solution is to just upgrade to lm-sensors 3.0.x,
which automatically detects the device features, so every new driver is
supported right away.

> Luca what do you think about creating  a proper patch for the driver too and send it over to 
> Greg to be included in his linux-staging tree ? I think that way it will get more testing.

Don't know which Greg you're thinking of? This is an ACPI-based
hardware monitoring driver, so it would go to either the ACPI folks or
(IMHO better) to the hwmon folks (i.e. the lm-sensors list). I agree
that having a proper patch would be nice (but I also want to say that I
will not have the time to review the driver myself.)

-- 
Jean Delvare

_______________________________________________
lm-sensors mailing list
lm-sensors@lm-sensors.org
http://lists.lm-sensors.org/mailman/listinfo/lm-sensors

^ permalink raw reply	[flat|nested] 8+ messages in thread

* Re: [lm-sensors] Asus atk0110 driver
  2008-06-18 21:26 [lm-sensors] Asus atk0110 driver Luca Tettamanti
                   ` (2 preceding siblings ...)
  2008-06-23  9:06 ` Jean Delvare
@ 2008-06-23 12:41 ` Gabriel C
  2008-06-23 13:48 ` Jean Delvare
                   ` (2 subsequent siblings)
  6 siblings, 0 replies; 8+ messages in thread
From: Gabriel C @ 2008-06-23 12:41 UTC (permalink / raw)
  To: lm-sensors

Jean Delvare wrote:

> Hi Gabriel,
> 
> On Sun, 22 Jun 2008 18:15:51 +0200, Gabriel C wrote:
>> I've tested the driver with linux-next on my P5E-VM DO motherboard.
>>
>> The driver seems to work , the values / data in  /sys/class/hwmon/hwmon0/device/*
>> seems to be the same like what the BIOS reports.
>>
>> However how do I get sensors to display the data from atk driver ?
>> I guess I have to patch lm-sensors ?
> 
> For lm-sensors 2.10.x, yes, you'd need to patch libsensors and sensors
> and virtually every monitoring application out there.
> 
> But the preferred solution is to just upgrade to lm-sensors 3.0.x,
> which automatically detects the device features, so every new driver is
> supported right away.


I've tested with 3.0.2 since 2.10* gave only a parse error.
Maybe is a problem with linux-next or something I'm missing in the config file ,
I will retest with linus tree soon.

> 
>> Luca what do you think about creating  a proper patch for the driver too and send it over to 
>> Greg to be included in his linux-staging tree ? I think that way it will get more testing.
> 
> Don't know which Greg you're thinking of? 


Greg Kroah-Hartman

>This is an ACPI-based
> hardware monitoring driver, so it would go to either the ACPI folks or
> (IMHO better) to the hwmon folks (i.e. the lm-sensors list). I agree
> that having a proper patch would be nice (but I also want to say that I
> will not have the time to review the driver myself.)
> 


Yes sure but from what I understand linux-staging[1] tree holds not_yet__really_ready_to_merge
drivers , filesystems and such. I don't think it does matter it is an ACPI driver.

[1] http://lkml.org/lkml/2008/6/10/329


_______________________________________________
lm-sensors mailing list
lm-sensors@lm-sensors.org
http://lists.lm-sensors.org/mailman/listinfo/lm-sensors

^ permalink raw reply	[flat|nested] 8+ messages in thread

* Re: [lm-sensors] Asus atk0110 driver
  2008-06-18 21:26 [lm-sensors] Asus atk0110 driver Luca Tettamanti
                   ` (3 preceding siblings ...)
  2008-06-23 12:41 ` Gabriel C
@ 2008-06-23 13:48 ` Jean Delvare
  2008-06-30 19:58 ` Luca Tettamanti
  2008-06-30 22:20 ` Gabriel C
  6 siblings, 0 replies; 8+ messages in thread
From: Jean Delvare @ 2008-06-23 13:48 UTC (permalink / raw)
  To: lm-sensors

On Mon, 23 Jun 2008 14:41:29 +0200, Gabriel C wrote:
> Jean Delvare wrote:
> > On Sun, 22 Jun 2008 18:15:51 +0200, Gabriel C wrote:
> >> Luca what do you think about creating  a proper patch for the driver too and send it over to 
> >> Greg to be included in his linux-staging tree ? I think that way it will get more testing.
> > 
> > Don't know which Greg you're thinking of? 
> 
> 
> Greg Kroah-Hartman
> 
> >This is an ACPI-based
> > hardware monitoring driver, so it would go to either the ACPI folks or
> > (IMHO better) to the hwmon folks (i.e. the lm-sensors list). I agree
> > that having a proper patch would be nice (but I also want to say that I
> > will not have the time to review the driver myself.)
> > 
> 
> 
> Yes sure but from what I understand linux-staging[1] tree holds not_yet__really_ready_to_merge
> drivers , filesystems and such. I don't think it does matter it is an ACPI driver.
> 
> [1] http://lkml.org/lkml/2008/6/10/329

Ah, I didn't know about this new kernel tree, thanks for the pointer. I
get what you meant now.

-- 
Jean Delvare

_______________________________________________
lm-sensors mailing list
lm-sensors@lm-sensors.org
http://lists.lm-sensors.org/mailman/listinfo/lm-sensors

^ permalink raw reply	[flat|nested] 8+ messages in thread

* Re: [lm-sensors] Asus atk0110 driver
  2008-06-18 21:26 [lm-sensors] Asus atk0110 driver Luca Tettamanti
                   ` (4 preceding siblings ...)
  2008-06-23 13:48 ` Jean Delvare
@ 2008-06-30 19:58 ` Luca Tettamanti
  2008-06-30 22:20 ` Gabriel C
  6 siblings, 0 replies; 8+ messages in thread
From: Luca Tettamanti @ 2008-06-30 19:58 UTC (permalink / raw)
  To: lm-sensors

Il Mon, Jun 23, 2008 at 11:06:01AM +0200, Jean Delvare ha scritto: 
> Hi Gabriel,
> 
> On Sun, 22 Jun 2008 18:15:51 +0200, Gabriel C wrote:
> > I've tested the driver with linux-next on my P5E-VM DO motherboard.
> > 
> > The driver seems to work , the values / data in  /sys/class/hwmon/hwmon0/device/*
> > seems to be the same like what the BIOS reports.
> > 
> > However how do I get sensors to display the data from atk driver ?
> > I guess I have to patch lm-sensors ?
> 
> For lm-sensors 2.10.x, yes, you'd need to patch libsensors and sensors
> and virtually every monitoring application out there.
> 
> But the preferred solution is to just upgrade to lm-sensors 3.0.x,
> which automatically detects the device features, so every new driver is
> supported right away.

Not really, the hwmon device is linked directly to the ACPI node in the
sysfs hierarchy (via subsystem link): lm-sensors just ignores it.

Patch is simple enough though:

---
 Makefile      |    6 +++---
 lib/access.c  |    2 ++
 lib/data.c    |    5 +++++
 lib/sensors.h |    1 +
 lib/sysfs.c   |    5 +++++
 5 files changed, 16 insertions(+), 3 deletions(-)

Index: lib/access.c
=================================--- lib/access.c	(revision 5296)
+++ lib/access.c	(working copy)
@@ -349,6 +349,8 @@
 		return "SPI adapter";
 	case SENSORS_BUS_TYPE_VIRTUAL:
 		return "Virtual device";
+	case SENSORS_BUS_TYPE_ACPI:
+		return "ACPI device";
 	}
 
 	/* bus types with several instances */
Index: lib/sensors.h
=================================--- lib/sensors.h	(revision 5296)
+++ lib/sensors.h	(working copy)
@@ -42,6 +42,7 @@
 #define SENSORS_BUS_TYPE_PCI		2
 #define SENSORS_BUS_TYPE_SPI		3
 #define SENSORS_BUS_TYPE_VIRTUAL	4
+#define SENSORS_BUS_TYPE_ACPI		5
 #define SENSORS_BUS_NR_ANY		(-1)
 #define SENSORS_BUS_NR_IGNORE		(-2)
 
Index: lib/sysfs.c
=================================--- lib/sysfs.c	(revision 5296)
+++ lib/sysfs.c	(working copy)
@@ -579,6 +579,11 @@
 			entry.chip.addr = 0;
 		entry.chip.bus.type = SENSORS_BUS_TYPE_ISA;
 		entry.chip.bus.nr = 0;
+	} else
+	if ((!subsys || !strcmp(subsys, "acpi")) &&
+	    sscanf(dev_name, "%*[a-zA-Z0-9_]:%d", &entry.chip.addr) = 1) {
+		entry.chip.bus.type = SENSORS_BUS_TYPE_ACPI;
+		entry.chip.bus.nr = 0;
 	} else {
 		/* Ignore unknown device */
 		err = 0;
Index: lib/data.c
=================================--- lib/data.c	(revision 5296)
+++ lib/data.c	(working copy)
@@ -111,6 +111,8 @@
 		res->bus.type = SENSORS_BUS_TYPE_SPI;
 	else if (!strncmp(name, "virtual", dash - name))
 		res->bus.type = SENSORS_BUS_TYPE_VIRTUAL;
+	else if (!strncmp(name, "acpi", dash - name))
+		res->bus.type = SENSORS_BUS_TYPE_ACPI;
 	else
 		goto ERROR;
 	name = dash + 1;
@@ -174,6 +176,9 @@
 	case SENSORS_BUS_TYPE_VIRTUAL:
 		return snprintf(str, size, "%s-virtual-%x", chip->prefix,
 				chip->addr);
+	case SENSORS_BUS_TYPE_ACPI:
+		return snprintf(str, size, "%s-acpi-%x", chip->prefix,
+				chip->addr);
 	}
 
 	return -SENSORS_ERR_CHIP_NAME;

With the patch applied sensors is able to display all the data:

atk0110-acpi-0
Adapter: ACPI device
Vcore Voltage:      +1.12 V  (min =  +0.85 V, max =  +1.60 V)
 +3.3 Voltage:      +3.31 V  (min =  +2.97 V, max =  +3.63 V)
 +5 Voltage:        +5.12 V  (min =  +4.50 V, max =  +5.50 V)
 +12 Voltage:      +12.41 V  (min = +10.20 V, max = +13.80 V)
CPU FAN Speed:     2860 RPM  (min =  600 RPM)
CHASSIS1 FAN Speed:   0 RPM  (min =  800 RPM)
CHASSIS2 FAN Speed:   0 RPM  (min =  800 RPM)
POWER FAN Speed:      0 RPM  (min =  800 RPM)
CPU Temperature:    +48.5°C  (high = +60.0°C, crit = +95.0°C)
MB Temperature:     +42.0°C  (high = +45.0°C, crit = +95.0°C)

> > Luca what do you think about creating  a proper patch for the driver too and send it over to 
> > Greg to be included in his linux-staging tree ? I think that way it will get more testing.

Will do ;)

Luca
-- 
Sono un mirabile incrocio tra Tarzan e Giacomo Leopardi.
In me convivono tutte le doti intelluttuali di Tarzan e
tutta la prestanza fisica di Giacomo Leopardi.
A. Borsani

_______________________________________________
lm-sensors mailing list
lm-sensors@lm-sensors.org
http://lists.lm-sensors.org/mailman/listinfo/lm-sensors

^ permalink raw reply	[flat|nested] 8+ messages in thread

* Re: [lm-sensors] Asus atk0110 driver
  2008-06-18 21:26 [lm-sensors] Asus atk0110 driver Luca Tettamanti
                   ` (5 preceding siblings ...)
  2008-06-30 19:58 ` Luca Tettamanti
@ 2008-06-30 22:20 ` Gabriel C
  6 siblings, 0 replies; 8+ messages in thread
From: Gabriel C @ 2008-06-30 22:20 UTC (permalink / raw)
  To: lm-sensors

Luca Tettamanti wrote:

> Il Mon, Jun 23, 2008 at 11:06:01AM +0200, Jean Delvare ha scritto: 
>> Hi Gabriel,
>>
>> On Sun, 22 Jun 2008 18:15:51 +0200, Gabriel C wrote:
>>> I've tested the driver with linux-next on my P5E-VM DO motherboard.
>>>
>>> The driver seems to work , the values / data in  /sys/class/hwmon/hwmon0/device/*
>>> seems to be the same like what the BIOS reports.
>>>
>>> However how do I get sensors to display the data from atk driver ?
>>> I guess I have to patch lm-sensors ?
>> For lm-sensors 2.10.x, yes, you'd need to patch libsensors and sensors
>> and virtually every monitoring application out there.
>>
>> But the preferred solution is to just upgrade to lm-sensors 3.0.x,
>> which automatically detects the device features, so every new driver is
>> supported right away.
> 
> Not really, the hwmon device is linked directly to the ACPI node in the
> sysfs hierarchy (via subsystem link): lm-sensors just ignores it.
> 
> Patch is simple enough though:
> 
> ---
>  Makefile      |    6 +++---
>  lib/access.c  |    2 ++
>  lib/data.c    |    5 +++++
>  lib/sensors.h |    1 +
>  lib/sysfs.c   |    5 +++++
>  5 files changed, 16 insertions(+), 3 deletions(-)
> 
> Index: lib/access.c
> =================================> --- lib/access.c	(revision 5296)
> +++ lib/access.c	(working copy)
> @@ -349,6 +349,8 @@
>  		return "SPI adapter";
>  	case SENSORS_BUS_TYPE_VIRTUAL:
>  		return "Virtual device";
> +	case SENSORS_BUS_TYPE_ACPI:
> +		return "ACPI device";
>  	}
>  
>  	/* bus types with several instances */
> Index: lib/sensors.h
> =================================> --- lib/sensors.h	(revision 5296)
> +++ lib/sensors.h	(working copy)
> @@ -42,6 +42,7 @@
>  #define SENSORS_BUS_TYPE_PCI		2
>  #define SENSORS_BUS_TYPE_SPI		3
>  #define SENSORS_BUS_TYPE_VIRTUAL	4
> +#define SENSORS_BUS_TYPE_ACPI		5
>  #define SENSORS_BUS_NR_ANY		(-1)
>  #define SENSORS_BUS_NR_IGNORE		(-2)
>  
> Index: lib/sysfs.c
> =================================> --- lib/sysfs.c	(revision 5296)
> +++ lib/sysfs.c	(working copy)
> @@ -579,6 +579,11 @@
>  			entry.chip.addr = 0;
>  		entry.chip.bus.type = SENSORS_BUS_TYPE_ISA;
>  		entry.chip.bus.nr = 0;
> +	} else
> +	if ((!subsys || !strcmp(subsys, "acpi")) &&
> +	    sscanf(dev_name, "%*[a-zA-Z0-9_]:%d", &entry.chip.addr) = 1) {
> +		entry.chip.bus.type = SENSORS_BUS_TYPE_ACPI;
> +		entry.chip.bus.nr = 0;
>  	} else {
>  		/* Ignore unknown device */
>  		err = 0;
> Index: lib/data.c
> =================================> --- lib/data.c	(revision 5296)
> +++ lib/data.c	(working copy)
> @@ -111,6 +111,8 @@
>  		res->bus.type = SENSORS_BUS_TYPE_SPI;
>  	else if (!strncmp(name, "virtual", dash - name))
>  		res->bus.type = SENSORS_BUS_TYPE_VIRTUAL;
> +	else if (!strncmp(name, "acpi", dash - name))
> +		res->bus.type = SENSORS_BUS_TYPE_ACPI;
>  	else
>  		goto ERROR;
>  	name = dash + 1;
> @@ -174,6 +176,9 @@
>  	case SENSORS_BUS_TYPE_VIRTUAL:
>  		return snprintf(str, size, "%s-virtual-%x", chip->prefix,
>  				chip->addr);
> +	case SENSORS_BUS_TYPE_ACPI:
> +		return snprintf(str, size, "%s-acpi-%x", chip->prefix,
> +				chip->addr);
>  	}
>  
>  	return -SENSORS_ERR_CHIP_NAME;
> 
> With the patch applied sensors is able to display all the data:
> 
> atk0110-acpi-0
> Adapter: ACPI device
> Vcore Voltage:      +1.12 V  (min =  +0.85 V, max =  +1.60 V)
>  +3.3 Voltage:      +3.31 V  (min =  +2.97 V, max =  +3.63 V)
>  +5 Voltage:        +5.12 V  (min =  +4.50 V, max =  +5.50 V)
>  +12 Voltage:      +12.41 V  (min = +10.20 V, max = +13.80 V)
> CPU FAN Speed:     2860 RPM  (min =  600 RPM)
> CHASSIS1 FAN Speed:   0 RPM  (min =  800 RPM)
> CHASSIS2 FAN Speed:   0 RPM  (min =  800 RPM)
> POWER FAN Speed:      0 RPM  (min =  800 RPM)
> CPU Temperature:    +48.5°C  (high = +60.0°C, crit = +95.0°C)
> MB Temperature:     +42.0°C  (high = +45.0°C, crit = +95.0°C)


Works fine here too , thx Luca :)

> 
>>> Luca what do you think about creating  a proper patch for the driver too and send it over to 
>>> Greg to be included in his linux-staging tree ? I think that way it will get more testing.
> 
> Will do ;)


Thx again :)

> 
> Luca


Gabriel



_______________________________________________
lm-sensors mailing list
lm-sensors@lm-sensors.org
http://lists.lm-sensors.org/mailman/listinfo/lm-sensors

^ permalink raw reply	[flat|nested] 8+ messages in thread

end of thread, other threads:[~2008-06-30 22:20 UTC | newest]

Thread overview: 8+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2008-06-18 21:26 [lm-sensors] Asus atk0110 driver Luca Tettamanti
2008-06-19  7:16 ` Jean Delvare
2008-06-22 16:15 ` Gabriel C
2008-06-23  9:06 ` Jean Delvare
2008-06-23 12:41 ` Gabriel C
2008-06-23 13:48 ` Jean Delvare
2008-06-30 19:58 ` Luca Tettamanti
2008-06-30 22:20 ` Gabriel C

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.