X-Git-Url: https://err.no/cgi-bin/gitweb.cgi?a=blobdiff_plain;f=drivers%2Fhwmon%2Ffschmd.c;h=bd89d270a5ed2b7fcfcd6eac5ede75c397b6cb9b;hb=6afe6828b19b4567768264831d101026cb5510ff;hp=63a4df0580db78f44fb030056336b699155508a4;hpb=541010e4b8921cd781ff02ae68028501457045b6;p=linux-2.6 diff --git a/drivers/hwmon/fschmd.c b/drivers/hwmon/fschmd.c index 63a4df0580..bd89d270a5 100644 --- a/drivers/hwmon/fschmd.c +++ b/drivers/hwmon/fschmd.c @@ -41,9 +41,10 @@ #include #include #include +#include /* Addresses to scan */ -static unsigned short normal_i2c[] = { 0x73, I2C_CLIENT_END }; +static const unsigned short normal_i2c[] = { 0x73, I2C_CLIENT_END }; /* Insmod parameters */ I2C_CLIENT_INSMOD_5(fscpos, fscher, fscscy, fschrc, fschmd); @@ -133,7 +134,7 @@ static const u8 FSCHMD_REG_TEMP_STATE[5][5] = { { 0x71, 0x81, 0x91 }, /* her */ { 0x71, 0xd1, 0x81, 0x91 }, /* scy */ { 0x71, 0x81, 0x91 }, /* hrc */ - { 0x71, 0x81, 0x91, 0xd1, 0xe1 }, /* hmd */ + { 0x71, 0x81, 0x91, 0xd1, 0xe1 }, /* hmd */ }; /* temperature high limit registers, FSC does not document these. Proven to be @@ -146,7 +147,7 @@ static const u8 FSCHMD_REG_TEMP_LIMIT[5][5] = { { 0x76, 0x86, 0x96 }, /* her */ { 0x76, 0xd6, 0x86, 0x96 }, /* scy */ { 0x76, 0x86, 0x96 }, /* hrc */ - { 0x76, 0x86, 0x96, 0xd6, 0xe6 }, /* hmd */ + { 0x76, 0x86, 0x96, 0xd6, 0xe6 }, /* hmd */ }; /* These were found through experimenting with an fscher, currently they are @@ -210,6 +211,13 @@ struct fschmd_data { u8 fan_ripple[6]; /* divider for rps */ }; +/* Global variables to hold information read from special DMI tables, which are + available on FSC machines with an fscher or later chip. */ +static int dmi_mult[3] = { 490, 200, 100 }; +static int dmi_offset[3] = { 0, 0, 0 }; +static int dmi_vref = -1; + + /* * Sysfs attr show / store functions */ @@ -221,8 +229,13 @@ static ssize_t show_in_value(struct device *dev, int index = to_sensor_dev_attr(devattr)->index; struct fschmd_data *data = fschmd_update_device(dev); - return sprintf(buf, "%d\n", (data->volt[index] * - max_reading[index] + 128) / 255); + /* fscher / fschrc - 1 as data->kind is an array index, not a chips */ + if (data->kind == (fscher - 1) || data->kind >= (fschrc - 1)) + return sprintf(buf, "%d\n", (data->volt[index] * dmi_vref * + dmi_mult[index]) / 255 + dmi_offset[index]); + else + return sprintf(buf, "%d\n", (data->volt[index] * + max_reading[index] + 128) / 255); } @@ -525,6 +538,68 @@ static struct sensor_device_attribute fschmd_fan_attr[] = { * Real code */ +/* DMI decode routine to read voltage scaling factors from special DMI tables, + which are available on FSC machines with an fscher or later chip. */ +static void fschmd_dmi_decode(const struct dmi_header *header) +{ + int i, mult[3] = { 0 }, offset[3] = { 0 }, vref = 0, found = 0; + + /* dmi code ugliness, we get passed the address of the contents of + a complete DMI record, but in the form of a dmi_header pointer, in + reality this address holds header->length bytes of which the header + are the first 4 bytes */ + u8 *dmi_data = (u8 *)header; + + /* We are looking for OEM-specific type 185 */ + if (header->type != 185) + return; + + /* we are looking for what Siemens calls "subtype" 19, the subtype + is stored in byte 5 of the dmi block */ + if (header->length < 5 || dmi_data[4] != 19) + return; + + /* After the subtype comes 1 unknown byte and then blocks of 5 bytes, + consisting of what Siemens calls an "Entity" number, followed by + 2 16-bit words in LSB first order */ + for (i = 6; (i + 4) < header->length; i += 5) { + /* entity 1 - 3: voltage multiplier and offset */ + if (dmi_data[i] >= 1 && dmi_data[i] <= 3) { + /* Our in sensors order and the DMI order differ */ + const int shuffle[3] = { 1, 0, 2 }; + int in = shuffle[dmi_data[i] - 1]; + + /* Check for twice the same entity */ + if (found & (1 << in)) + return; + + mult[in] = dmi_data[i + 1] | (dmi_data[i + 2] << 8); + offset[in] = dmi_data[i + 3] | (dmi_data[i + 4] << 8); + + found |= 1 << in; + } + + /* entity 7: reference voltage */ + if (dmi_data[i] == 7) { + /* Check for twice the same entity */ + if (found & 0x08) + return; + + vref = dmi_data[i + 1] | (dmi_data[i + 2] << 8); + + found |= 0x08; + } + } + + if (found == 0x0F) { + for (i = 0; i < 3; i++) { + dmi_mult[i] = mult[i] * 10; + dmi_offset[i] = offset[i] * 10; + } + dmi_vref = vref; + } +} + static int fschmd_detect(struct i2c_adapter *adapter, int address, int kind) { struct i2c_client *client; @@ -586,6 +661,17 @@ static int fschmd_detect(struct i2c_adapter *adapter, int address, int kind) data->temp_max[2] = 50 + 128; } + /* Read the special DMI table for fscher and newer chips */ + if (kind == fscher || kind >= fschrc) { + dmi_walk(fschmd_dmi_decode); + if (dmi_vref == -1) { + printk(KERN_WARNING FSCHMD_NAME + ": Couldn't get voltage scaling factors from " + "BIOS DMI table, using builtin defaults\n"); + dmi_vref = 33; + } + } + /* i2c kind goes from 1-5, we want from 0-4 to address arrays */ data->kind = kind - 1; strlcpy(client->name, client_names[data->kind], I2C_NAME_SIZE);