Il Wed, Sep 16, 2009 at 11:28:39PM -0600, Robert Hancock ha scritto: > Just built a new system with an Asus P7P55D PRO motherboard. The > ATK0110 driver doesn't seem to be able to retrieve any hardware > monitoring parameters successfully, sensors gives: > > atk0110-acpi-0 > Adapter: ACPI interface > ERROR: Can't get value of subfeature in0_input: I/O error > Vcore Voltage: +0.00 V (min = +0.80 V, max = +1.60 V) > ERROR: Can't get value of subfeature in1_input: I/O error > +3.3V Voltage: +0.00 V (min = +2.97 V, max = +3.63 V) > ERROR: Can't get value of subfeature in2_input: I/O error > +5V Voltage: +0.00 V (min = +4.50 V, max = +5.50 V) > > etc. and dmesg spits out a bunch of these: > > ATK0110 ATK0110:00: atk_read_value_new: ACPI exception: AE_BUFFER_OVERFLOW > > I'm guessing this board uses a different format than what the driver > is expecting. I'm attaching the gzipped decompiled DSDT from the > board, hopefully it's useful to somebody.. Please try the following patch, it should detect the proper buffer size. diff --git a/drivers/hwmon/asus_atk0110.c b/drivers/hwmon/asus_atk0110.c index fe4fa29..4f6f5ec 100644 --- a/drivers/hwmon/asus_atk0110.c +++ b/drivers/hwmon/asus_atk0110.c @@ -75,6 +75,13 @@ enum atk_pack_member { #define _HWMON_OLD_PACK_ENABLE 4 +struct atk_acpi_out_buffer { + union acpi_object buf; + u32 flags; + u32 value; + u8 data[]; +}; + struct atk_data { struct device *hwmon_dev; acpi_handle atk_handle; @@ -94,6 +101,10 @@ struct atk_data { int temperature_count; int fan_count; struct list_head sensor_list; + + struct atk_acpi_out_buffer *buffer; + size_t buffer_size; + struct mutex buffer_lock; }; @@ -129,11 +140,6 @@ struct atk_sensor_data { char const *acpi_name; }; -struct atk_acpi_buffer_u64 { - union acpi_object buf; - u64 value; -}; - 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); @@ -446,8 +452,9 @@ static int atk_read_value_new(struct atk_sensor_data *sensor, u64 *value) struct acpi_object_list params; struct acpi_buffer ret; union acpi_object id; - struct atk_acpi_buffer_u64 tmp; + union acpi_object buf; acpi_status status; + int err = 0; id.type = ACPI_TYPE_INTEGER; id.integer.value = sensor->id; @@ -455,36 +462,35 @@ static int atk_read_value_new(struct atk_sensor_data *sensor, u64 *value) params.count = 1; params.pointer = &id; - tmp.buf.type = ACPI_TYPE_BUFFER; - tmp.buf.buffer.pointer = (u8 *)&tmp.value; - tmp.buf.buffer.length = sizeof(u64); - ret.length = sizeof(tmp); - ret.pointer = &tmp; + mutex_lock(&data->buffer_lock); + + ret.length = data->buffer_size; + ret.pointer = &buf; status = acpi_evaluate_object_typed(data->read_handle, NULL, ¶ms, &ret, ACPI_TYPE_BUFFER); if (status != AE_OK) { dev_warn(dev, "%s: ACPI exception: %s\n", __func__, acpi_format_exception(status)); - return -EIO; + err = -EIO; + goto out; } - /* Return buffer format: - * [0-3] "value" is valid flag - * [4-7] value - */ - if (!(tmp.value & 0xffffffff)) { + if (!data->buffer->flags) { /* The reading is not valid, possible causes: * - sensor failure * - enumeration was FUBAR (and we didn't notice) */ - dev_info(dev, "Failure: %#llx\n", tmp.value); - return -EIO; + dev_info(dev, "Failure: %#x\n", data->buffer->flags); + + err = -EIO; + goto out; } - *value = (tmp.value & 0xffffffff00000000ULL) >> 32; - - return 0; + *value = data->buffer->value; +out: + mutex_unlock(&data->buffer_lock); + return err; } static int atk_read_value(struct atk_sensor_data *sensor, u64 *value) @@ -721,11 +727,40 @@ static int atk_enumerate_new_hwmon(struct atk_data *data) struct acpi_object_list params; union acpi_object id; union acpi_object *pack; + union acpi_object *asbf; int err; int i; dev_dbg(dev, "Enumerating hwmon sensors\n"); + /* Probe ASBF */ + buf.length = ACPI_ALLOCATE_BUFFER; + ret = acpi_evaluate_object_typed(data->atk_handle, "ASBF", NULL, &buf, + ACPI_TYPE_BUFFER); + if (ret != AE_OK) { + dev_warn(dev, "Failed to evaluate ASBF: %s\n", + acpi_format_exception(ret)); + return -ENODEV; + } + asbf = buf.pointer; + data->buffer_size = asbf->buffer.length; + ACPI_FREE(buf.pointer); + buf.pointer = NULL; + + dev_dbg(dev, "ASBF buffer size: %zu\n", data->buffer_size); + /* Sanity check */ + if (data->buffer_size < 8 || data->buffer_size > 512) { + dev_warn(dev, "Invalid ASBF buffer size: %zu\n", + data->buffer_size); + return -EINVAL; + } + data->buffer_size += sizeof(union acpi_object); + + data->buffer = kzalloc(data->buffer_size, GFP_KERNEL); + if (!data->buffer) + return -ENOMEM; + mutex_init(&data->buffer_lock); + id.type = ACPI_TYPE_INTEGER; id.integer.value = ATK_MUX_HWMON; params.count = 1; @@ -737,7 +772,8 @@ static int atk_enumerate_new_hwmon(struct atk_data *data) if (ret != AE_OK) { dev_warn(dev, METHOD_ENUMERATE ": ACPI exception: %s\n", acpi_format_exception(ret)); - return -ENODEV; + err = -ENODEV; + goto out; } /* Result must be a package */ @@ -759,6 +795,8 @@ static int atk_enumerate_new_hwmon(struct atk_data *data) err = data->voltage_count + data->temperature_count + data->fan_count; out: + if (err < 0) + kfree(data->buffer); ACPI_FREE(buf.pointer); return err; } @@ -988,6 +1026,7 @@ static int atk_remove(struct acpi_device *device, int type) atk_free_sensors(data); hwmon_device_unregister(data->hwmon_dev); + kfree(data->buffer); kfree(data); return 0; Luca -- "La vita potrebbe non avere alcun significato. Oppure, ancora peggio, potrebbe averne uno che disapprovo". -- Ashleigh Brilliant -- To unsubscribe from this list: send the line "unsubscribe linux-acpi" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html