Gitweb:     
http://git.kernel.org/git/?p=linux/kernel/git/torvalds/linux-2.6.git;a=commit;h=7845cd791d87b9d5e6171452143dbef15aba00dc
Commit:     7845cd791d87b9d5e6171452143dbef15aba00dc
Parent:     67b671bceb4a8340a30929e9642620d99ed5ad76
Author:     Hans de Goede <[EMAIL PROTECTED]>
AuthorDate: Thu Dec 20 16:42:59 2007 +0100
Committer:  Mark M. Hoffman <[EMAIL PROTECTED]>
CommitDate: Thu Feb 7 20:39:42 2008 -0500

    hwmon: (fschmd) Read voltage scaling factors from BIOS DMI
    
    This patch adds support to the fschmd driver for reading the voltage scaling
    factors from BIOS DMI tables, as specified in the Siemens datasheet.
    
    Signed-off-by: Hans de Goede <[EMAIL PROTECTED]>
    Acked-by: Jean Delvare <[EMAIL PROTECTED]>
    Signed-off-by: Mark M. Hoffman <[EMAIL PROTECTED]>
---
 drivers/hwmon/fschmd.c |   90 ++++++++++++++++++++++++++++++++++++++++++++++-
 1 files changed, 88 insertions(+), 2 deletions(-)

diff --git a/drivers/hwmon/fschmd.c b/drivers/hwmon/fschmd.c
index d427ea5..b7c9eef 100644
--- a/drivers/hwmon/fschmd.c
+++ b/drivers/hwmon/fschmd.c
@@ -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 };
@@ -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);
-
To unsubscribe from this list: send the line "unsubscribe git-commits-head" in
the body of a message to [EMAIL PROTECTED]
More majordomo info at  http://vger.kernel.org/majordomo-info.html

Reply via email to