Skip to content

Commit

Permalink
---
Browse files Browse the repository at this point in the history
yaml
---
r: 84519
b: refs/heads/master
c: 7845cd7
h: refs/heads/master
i:
  84517: 498cba6
  84515: dcb224f
  84511: a4a8b5a
v: v3
  • Loading branch information
Hans de Goede authored and Mark M. Hoffman committed Feb 8, 2008
1 parent 5c91d8a commit d63fd77
Show file tree
Hide file tree
Showing 2 changed files with 89 additions and 3 deletions.
2 changes: 1 addition & 1 deletion [refs]
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
---
refs/heads/master: 67b671bceb4a8340a30929e9642620d99ed5ad76
refs/heads/master: 7845cd791d87b9d5e6171452143dbef15aba00dc
90 changes: 88 additions & 2 deletions trunk/drivers/hwmon/fschmd.c
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@
#include <linux/err.h>
#include <linux/mutex.h>
#include <linux/sysfs.h>
#include <linux/dmi.h>

/* Addresses to scan */
static unsigned short normal_i2c[] = { 0x73, I2C_CLIENT_END };
Expand Down Expand Up @@ -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
*/
Expand All @@ -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);
}


Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -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);
Expand Down

0 comments on commit d63fd77

Please sign in to comment.