2005-02-24 06:16:31

by Dmitry Torokhov

[permalink] [raw]
Subject: [PATCH 0/5] I8K driver facelift

Hi,

here are some changes that freshen I8K driver (Dell Inspiron/Latitude
platform driver). The patches have been tested on Inspiron 8100.

i8k-lindent.patch
- pass the driver through Lindent to comply with CondingStyle requirements
(4 spaces vs. TAB indentation)

i8k-use-dmi.patch
- use standard DMI handling functions instead of homemade ones. The driver
now requires DMI data to match list of supported models - this way driver
can be safely enabled without fear of it poking into SMM code on wrong
box. DMI checks can be ignored with i8k.ignore_dmi option.

i8k-seqfile.patch
- switch proc handlig code to seq_file instead of having custom read
function splitting output to fit into user's buffer.

i8k-cleanup.patch
- use module_{init|exit} instead of old-style module intialization code,
some formatting changes.

i8k-sysfs.patch
- make i8k a platform device and export temperatiure and both fan states
as sysfs attributes. Wringing into fan1_state and fan2_state attributes
allows switching fans on and off without need for special utility.

Please consider for inclusion.

Thanks!

--
Dmitry


2005-02-24 06:16:25

by Dmitry Torokhov

[permalink] [raw]
Subject: [PATCH 1/5] I8K - pass though Lindent

===================================================================

I8K: pass through Lindent to change 4 spaces identation to TABs

Signed-off-by: Dmitry Torokhov <[email protected]>


i8k.c | 954 +++++++++++++++++++++++++++++++++---------------------------------
1 files changed, 477 insertions(+), 477 deletions(-)

Index: dtor/drivers/char/i8k.c
===================================================================
--- dtor.orig/drivers/char/i8k.c
+++ dtor/drivers/char/i8k.c
@@ -55,14 +55,14 @@
#define DELL_SIGNATURE "Dell Computer"

static char *supported_models[] = {
- "Inspiron",
- "Latitude",
- NULL
+ "Inspiron",
+ "Latitude",
+ NULL
};

static char system_vendor[48] = "?";
-static char product_name [48] = "?";
-static char bios_version [4] = "?";
+static char product_name[48] = "?";
+static char bios_version[4] = "?";
static char serial_number[16] = "?";

MODULE_AUTHOR("Massimo Dal Zotto ([email protected])");
@@ -86,64 +86,63 @@ static int i8k_ioctl(struct inode *, str
unsigned long);

static struct file_operations i8k_fops = {
- .read = i8k_read,
- .ioctl = i8k_ioctl,
+ .read = i8k_read,
+ .ioctl = i8k_ioctl,
};

typedef struct {
- unsigned int eax;
- unsigned int ebx __attribute__ ((packed));
- unsigned int ecx __attribute__ ((packed));
- unsigned int edx __attribute__ ((packed));
- unsigned int esi __attribute__ ((packed));
- unsigned int edi __attribute__ ((packed));
+ unsigned int eax;
+ unsigned int ebx __attribute__ ((packed));
+ unsigned int ecx __attribute__ ((packed));
+ unsigned int edx __attribute__ ((packed));
+ unsigned int esi __attribute__ ((packed));
+ unsigned int edi __attribute__ ((packed));
} SMMRegisters;

typedef struct {
- u8 type;
- u8 length;
- u16 handle;
+ u8 type;
+ u8 length;
+ u16 handle;
} DMIHeader;

/*
* Call the System Management Mode BIOS. Code provided by Jonathan Buzzard.
*/
-static int i8k_smm(SMMRegisters *regs)
+static int i8k_smm(SMMRegisters * regs)
{
- int rc;
- int eax = regs->eax;
+ int rc;
+ int eax = regs->eax;

- asm("pushl %%eax\n\t" \
- "movl 0(%%eax),%%edx\n\t" \
- "push %%edx\n\t" \
- "movl 4(%%eax),%%ebx\n\t" \
- "movl 8(%%eax),%%ecx\n\t" \
- "movl 12(%%eax),%%edx\n\t" \
- "movl 16(%%eax),%%esi\n\t" \
- "movl 20(%%eax),%%edi\n\t" \
- "popl %%eax\n\t" \
- "out %%al,$0xb2\n\t" \
- "out %%al,$0x84\n\t" \
- "xchgl %%eax,(%%esp)\n\t"
- "movl %%ebx,4(%%eax)\n\t" \
- "movl %%ecx,8(%%eax)\n\t" \
- "movl %%edx,12(%%eax)\n\t" \
- "movl %%esi,16(%%eax)\n\t" \
- "movl %%edi,20(%%eax)\n\t" \
- "popl %%edx\n\t" \
- "movl %%edx,0(%%eax)\n\t" \
- "lahf\n\t" \
- "shrl $8,%%eax\n\t" \
- "andl $1,%%eax\n" \
- : "=a" (rc)
- : "a" (regs)
- : "%ebx", "%ecx", "%edx", "%esi", "%edi", "memory");
-
- if ((rc != 0) || ((regs->eax & 0xffff) == 0xffff) || (regs->eax == eax)) {
- return -EINVAL;
- }
+ asm("pushl %%eax\n\t"
+ "movl 0(%%eax),%%edx\n\t"
+ "push %%edx\n\t"
+ "movl 4(%%eax),%%ebx\n\t"
+ "movl 8(%%eax),%%ecx\n\t"
+ "movl 12(%%eax),%%edx\n\t"
+ "movl 16(%%eax),%%esi\n\t"
+ "movl 20(%%eax),%%edi\n\t"
+ "popl %%eax\n\t"
+ "out %%al,$0xb2\n\t"
+ "out %%al,$0x84\n\t"
+ "xchgl %%eax,(%%esp)\n\t"
+ "movl %%ebx,4(%%eax)\n\t"
+ "movl %%ecx,8(%%eax)\n\t"
+ "movl %%edx,12(%%eax)\n\t"
+ "movl %%esi,16(%%eax)\n\t"
+ "movl %%edi,20(%%eax)\n\t"
+ "popl %%edx\n\t"
+ "movl %%edx,0(%%eax)\n\t"
+ "lahf\n\t"
+ "shrl $8,%%eax\n\t"
+ "andl $1,%%eax\n":"=a"(rc)
+ : "a"(regs)
+ : "%ebx", "%ecx", "%edx", "%esi", "%edi", "memory");

- return 0;
+ if ((rc != 0) || ((regs->eax & 0xffff) == 0xffff) || (regs->eax == eax)) {
+ return -EINVAL;
+ }
+
+ return 0;
}

/*
@@ -152,15 +151,15 @@ static int i8k_smm(SMMRegisters *regs)
*/
static int i8k_get_bios_version(void)
{
- SMMRegisters regs = { 0, 0, 0, 0, 0, 0 };
- int rc;
+ SMMRegisters regs = { 0, 0, 0, 0, 0, 0 };
+ int rc;

- regs.eax = I8K_SMM_BIOS_VERSION;
- if ((rc=i8k_smm(&regs)) < 0) {
- return rc;
- }
+ regs.eax = I8K_SMM_BIOS_VERSION;
+ if ((rc = i8k_smm(&regs)) < 0) {
+ return rc;
+ }

- return regs.eax;
+ return regs.eax;
}

/*
@@ -168,8 +167,8 @@ static int i8k_get_bios_version(void)
*/
static int i8k_get_serial_number(unsigned char *buff)
{
- strlcpy(buff, serial_number, sizeof(serial_number));
- return 0;
+ strlcpy(buff, serial_number, sizeof(serial_number));
+ return 0;
}

/*
@@ -177,24 +176,24 @@ static int i8k_get_serial_number(unsigne
*/
static int i8k_get_fn_status(void)
{
- SMMRegisters regs = { 0, 0, 0, 0, 0, 0 };
- int rc;
+ SMMRegisters regs = { 0, 0, 0, 0, 0, 0 };
+ int rc;

- regs.eax = I8K_SMM_FN_STATUS;
- if ((rc=i8k_smm(&regs)) < 0) {
- return rc;
- }
-
- switch ((regs.eax >> I8K_FN_SHIFT) & I8K_FN_MASK) {
- case I8K_FN_UP:
- return I8K_VOL_UP;
- case I8K_FN_DOWN:
- return I8K_VOL_DOWN;
- case I8K_FN_MUTE:
- return I8K_VOL_MUTE;
- default:
- return 0;
- }
+ regs.eax = I8K_SMM_FN_STATUS;
+ if ((rc = i8k_smm(&regs)) < 0) {
+ return rc;
+ }
+
+ switch ((regs.eax >> I8K_FN_SHIFT) & I8K_FN_MASK) {
+ case I8K_FN_UP:
+ return I8K_VOL_UP;
+ case I8K_FN_DOWN:
+ return I8K_VOL_DOWN;
+ case I8K_FN_MUTE:
+ return I8K_VOL_MUTE;
+ default:
+ return 0;
+ }
}

/*
@@ -202,20 +201,20 @@ static int i8k_get_fn_status(void)
*/
static int i8k_get_power_status(void)
{
- SMMRegisters regs = { 0, 0, 0, 0, 0, 0 };
- int rc;
+ SMMRegisters regs = { 0, 0, 0, 0, 0, 0 };
+ int rc;
+
+ regs.eax = I8K_SMM_POWER_STATUS;
+ if ((rc = i8k_smm(&regs)) < 0) {
+ return rc;
+ }

- regs.eax = I8K_SMM_POWER_STATUS;
- if ((rc=i8k_smm(&regs)) < 0) {
- return rc;
- }
-
- switch (regs.eax & 0xff) {
- case I8K_POWER_AC:
- return I8K_AC;
- default:
- return I8K_BATTERY;
- }
+ switch (regs.eax & 0xff) {
+ case I8K_POWER_AC:
+ return I8K_AC;
+ default:
+ return I8K_BATTERY;
+ }
}

/*
@@ -223,16 +222,16 @@ static int i8k_get_power_status(void)
*/
static int i8k_get_fan_status(int fan)
{
- SMMRegisters regs = { 0, 0, 0, 0, 0, 0 };
- int rc;
+ SMMRegisters regs = { 0, 0, 0, 0, 0, 0 };
+ int rc;

- regs.eax = I8K_SMM_GET_FAN;
- regs.ebx = fan & 0xff;
- if ((rc=i8k_smm(&regs)) < 0) {
- return rc;
- }
+ regs.eax = I8K_SMM_GET_FAN;
+ regs.ebx = fan & 0xff;
+ if ((rc = i8k_smm(&regs)) < 0) {
+ return rc;
+ }

- return (regs.eax & 0xff);
+ return (regs.eax & 0xff);
}

/*
@@ -240,16 +239,16 @@ static int i8k_get_fan_status(int fan)
*/
static int i8k_get_fan_speed(int fan)
{
- SMMRegisters regs = { 0, 0, 0, 0, 0, 0 };
- int rc;
+ SMMRegisters regs = { 0, 0, 0, 0, 0, 0 };
+ int rc;

- regs.eax = I8K_SMM_GET_SPEED;
- regs.ebx = fan & 0xff;
- if ((rc=i8k_smm(&regs)) < 0) {
- return rc;
- }
+ regs.eax = I8K_SMM_GET_SPEED;
+ regs.ebx = fan & 0xff;
+ if ((rc = i8k_smm(&regs)) < 0) {
+ return rc;
+ }

- return (regs.eax & 0xffff) * I8K_FAN_MULT;
+ return (regs.eax & 0xffff) * I8K_FAN_MULT;
}

/*
@@ -257,18 +256,18 @@ static int i8k_get_fan_speed(int fan)
*/
static int i8k_set_fan(int fan, int speed)
{
- SMMRegisters regs = { 0, 0, 0, 0, 0, 0 };
- int rc;
+ SMMRegisters regs = { 0, 0, 0, 0, 0, 0 };
+ int rc;

- speed = (speed < 0) ? 0 : ((speed > I8K_FAN_MAX) ? I8K_FAN_MAX : speed);
+ speed = (speed < 0) ? 0 : ((speed > I8K_FAN_MAX) ? I8K_FAN_MAX : speed);

- regs.eax = I8K_SMM_SET_FAN;
- regs.ebx = (fan & 0xff) | (speed << 8);
- if ((rc=i8k_smm(&regs)) < 0) {
- return rc;
- }
+ regs.eax = I8K_SMM_SET_FAN;
+ regs.ebx = (fan & 0xff) | (speed << 8);
+ if ((rc = i8k_smm(&regs)) < 0) {
+ return rc;
+ }

- return (i8k_get_fan_status(fan));
+ return (i8k_get_fan_status(fan));
}

/*
@@ -276,143 +275,143 @@ static int i8k_set_fan(int fan, int spee
*/
static int i8k_get_cpu_temp(void)
{
- SMMRegisters regs = { 0, 0, 0, 0, 0, 0 };
- int rc;
- int temp;
+ SMMRegisters regs = { 0, 0, 0, 0, 0, 0 };
+ int rc;
+ int temp;

#ifdef I8K_TEMPERATURE_BUG
- static int prev = 0;
+ static int prev = 0;
#endif

- regs.eax = I8K_SMM_GET_TEMP;
- if ((rc=i8k_smm(&regs)) < 0) {
- return rc;
- }
- temp = regs.eax & 0xff;
+ regs.eax = I8K_SMM_GET_TEMP;
+ if ((rc = i8k_smm(&regs)) < 0) {
+ return rc;
+ }
+ temp = regs.eax & 0xff;

#ifdef I8K_TEMPERATURE_BUG
- /*
- * Sometimes the temperature sensor returns 0x99, which is out of range.
- * In this case we return (once) the previous cached value. For example:
- # 1003655137 00000058 00005a4b
- # 1003655138 00000099 00003a80 <--- 0x99 = 153 degrees
- # 1003655139 00000054 00005c52
- */
- if (temp > I8K_MAX_TEMP) {
- temp = prev;
- prev = I8K_MAX_TEMP;
- } else {
- prev = temp;
- }
+ /*
+ * Sometimes the temperature sensor returns 0x99, which is out of range.
+ * In this case we return (once) the previous cached value. For example:
+ # 1003655137 00000058 00005a4b
+ # 1003655138 00000099 00003a80 <--- 0x99 = 153 degrees
+ # 1003655139 00000054 00005c52
+ */
+ if (temp > I8K_MAX_TEMP) {
+ temp = prev;
+ prev = I8K_MAX_TEMP;
+ } else {
+ prev = temp;
+ }
#endif

- return temp;
+ return temp;
}

static int i8k_get_dell_signature(void)
{
- SMMRegisters regs = { 0, 0, 0, 0, 0, 0 };
- int rc;
+ SMMRegisters regs = { 0, 0, 0, 0, 0, 0 };
+ int rc;

- regs.eax = I8K_SMM_GET_DELL_SIG;
- if ((rc=i8k_smm(&regs)) < 0) {
- return rc;
- }
+ regs.eax = I8K_SMM_GET_DELL_SIG;
+ if ((rc = i8k_smm(&regs)) < 0) {
+ return rc;
+ }

- if ((regs.eax == 1145651527) && (regs.edx == 1145392204)) {
- return 0;
- } else {
- return -1;
- }
+ if ((regs.eax == 1145651527) && (regs.edx == 1145392204)) {
+ return 0;
+ } else {
+ return -1;
+ }
}

static int i8k_ioctl(struct inode *ip, struct file *fp, unsigned int cmd,
unsigned long arg)
{
- int val;
- int speed;
- unsigned char buff[16];
- int __user *argp = (int __user *)arg;
-
- if (!argp)
- return -EINVAL;
-
- switch (cmd) {
- case I8K_BIOS_VERSION:
- val = i8k_get_bios_version();
- break;
-
- case I8K_MACHINE_ID:
- memset(buff, 0, 16);
- val = i8k_get_serial_number(buff);
- break;
-
- case I8K_FN_STATUS:
- val = i8k_get_fn_status();
- break;
-
- case I8K_POWER_STATUS:
- val = i8k_get_power_status();
- break;
-
- case I8K_GET_TEMP:
- val = i8k_get_cpu_temp();
- break;
-
- case I8K_GET_SPEED:
- if (copy_from_user(&val, argp, sizeof(int))) {
- return -EFAULT;
- }
- val = i8k_get_fan_speed(val);
- break;
-
- case I8K_GET_FAN:
- if (copy_from_user(&val, argp, sizeof(int))) {
- return -EFAULT;
- }
- val = i8k_get_fan_status(val);
- break;
-
- case I8K_SET_FAN:
- if (restricted && !capable(CAP_SYS_ADMIN)) {
- return -EPERM;
- }
- if (copy_from_user(&val, argp, sizeof(int))) {
- return -EFAULT;
- }
- if (copy_from_user(&speed, argp+1, sizeof(int))) {
- return -EFAULT;
- }
- val = i8k_set_fan(val, speed);
- break;
-
- default:
- return -EINVAL;
- }
-
- if (val < 0) {
- return val;
- }
-
- switch (cmd) {
- case I8K_BIOS_VERSION:
- if (copy_to_user(argp, &val, 4)) {
- return -EFAULT;
- }
- break;
- case I8K_MACHINE_ID:
- if (copy_to_user(argp, buff, 16)) {
- return -EFAULT;
- }
- break;
- default:
- if (copy_to_user(argp, &val, sizeof(int))) {
- return -EFAULT;
+ int val;
+ int speed;
+ unsigned char buff[16];
+ int __user *argp = (int __user *)arg;
+
+ if (!argp)
+ return -EINVAL;
+
+ switch (cmd) {
+ case I8K_BIOS_VERSION:
+ val = i8k_get_bios_version();
+ break;
+
+ case I8K_MACHINE_ID:
+ memset(buff, 0, 16);
+ val = i8k_get_serial_number(buff);
+ break;
+
+ case I8K_FN_STATUS:
+ val = i8k_get_fn_status();
+ break;
+
+ case I8K_POWER_STATUS:
+ val = i8k_get_power_status();
+ break;
+
+ case I8K_GET_TEMP:
+ val = i8k_get_cpu_temp();
+ break;
+
+ case I8K_GET_SPEED:
+ if (copy_from_user(&val, argp, sizeof(int))) {
+ return -EFAULT;
+ }
+ val = i8k_get_fan_speed(val);
+ break;
+
+ case I8K_GET_FAN:
+ if (copy_from_user(&val, argp, sizeof(int))) {
+ return -EFAULT;
+ }
+ val = i8k_get_fan_status(val);
+ break;
+
+ case I8K_SET_FAN:
+ if (restricted && !capable(CAP_SYS_ADMIN)) {
+ return -EPERM;
+ }
+ if (copy_from_user(&val, argp, sizeof(int))) {
+ return -EFAULT;
+ }
+ if (copy_from_user(&speed, argp + 1, sizeof(int))) {
+ return -EFAULT;
+ }
+ val = i8k_set_fan(val, speed);
+ break;
+
+ default:
+ return -EINVAL;
}
- break;
- }

- return 0;
+ if (val < 0) {
+ return val;
+ }
+
+ switch (cmd) {
+ case I8K_BIOS_VERSION:
+ if (copy_to_user(argp, &val, 4)) {
+ return -EFAULT;
+ }
+ break;
+ case I8K_MACHINE_ID:
+ if (copy_to_user(argp, buff, 16)) {
+ return -EFAULT;
+ }
+ break;
+ default:
+ if (copy_to_user(argp, &val, sizeof(int))) {
+ return -EFAULT;
+ }
+ break;
+ }
+
+ return 0;
}

/*
@@ -420,90 +419,87 @@ static int i8k_ioctl(struct inode *ip, s
*/
static int i8k_get_info(char *buffer, char **start, off_t fpos, int length)
{
- int n, fn_key, cpu_temp, ac_power;
- int left_fan, right_fan, left_speed, right_speed;
+ int n, fn_key, cpu_temp, ac_power;
+ int left_fan, right_fan, left_speed, right_speed;
+
+ cpu_temp = i8k_get_cpu_temp(); /* 11100 ??s */
+ left_fan = i8k_get_fan_status(I8K_FAN_LEFT); /* 580 ??s */
+ right_fan = i8k_get_fan_status(I8K_FAN_RIGHT); /* 580 ??s */
+ left_speed = i8k_get_fan_speed(I8K_FAN_LEFT); /* 580 ??s */
+ right_speed = i8k_get_fan_speed(I8K_FAN_RIGHT); /* 580 ??s */
+ fn_key = i8k_get_fn_status(); /* 750 ??s */
+ if (power_status) {
+ ac_power = i8k_get_power_status(); /* 14700 ??s */
+ } else {
+ ac_power = -1;
+ }

- cpu_temp = i8k_get_cpu_temp(); /* 11100 ??s */
- left_fan = i8k_get_fan_status(I8K_FAN_LEFT); /* 580 ??s */
- right_fan = i8k_get_fan_status(I8K_FAN_RIGHT); /* 580 ??s */
- left_speed = i8k_get_fan_speed(I8K_FAN_LEFT); /* 580 ??s */
- right_speed = i8k_get_fan_speed(I8K_FAN_RIGHT); /* 580 ??s */
- fn_key = i8k_get_fn_status(); /* 750 ??s */
- if (power_status) {
- ac_power = i8k_get_power_status(); /* 14700 ??s */
- } else {
- ac_power = -1;
- }
-
- /*
- * Info:
- *
- * 1) Format version (this will change if format changes)
- * 2) BIOS version
- * 3) BIOS machine ID
- * 4) Cpu temperature
- * 5) Left fan status
- * 6) Right fan status
- * 7) Left fan speed
- * 8) Right fan speed
- * 9) AC power
- * 10) Fn Key status
- */
- n = sprintf(buffer, "%s %s %s %d %d %d %d %d %d %d\n",
- I8K_PROC_FMT,
- bios_version,
- serial_number,
- cpu_temp,
- left_fan,
- right_fan,
- left_speed,
- right_speed,
- ac_power,
- fn_key);
-
- return n;
+ /*
+ * Info:
+ *
+ * 1) Format version (this will change if format changes)
+ * 2) BIOS version
+ * 3) BIOS machine ID
+ * 4) Cpu temperature
+ * 5) Left fan status
+ * 6) Right fan status
+ * 7) Left fan speed
+ * 8) Right fan speed
+ * 9) AC power
+ * 10) Fn Key status
+ */
+ n = sprintf(buffer, "%s %s %s %d %d %d %d %d %d %d\n",
+ I8K_PROC_FMT,
+ bios_version,
+ serial_number,
+ cpu_temp,
+ left_fan,
+ right_fan, left_speed, right_speed, ac_power, fn_key);
+
+ return n;
}

-static ssize_t i8k_read(struct file *f, char __user *buffer, size_t len, loff_t *fpos)
+static ssize_t i8k_read(struct file *f, char __user * buffer, size_t len,
+ loff_t * fpos)
{
- int n;
- char info[128];
+ int n;
+ char info[128];

- n = i8k_get_info(info, NULL, 0, 128);
- if (n <= 0) {
- return n;
- }
+ n = i8k_get_info(info, NULL, 0, 128);
+ if (n <= 0) {
+ return n;
+ }

- if (*fpos >= n) {
- return 0;
- }
+ if (*fpos >= n) {
+ return 0;
+ }

- if ((*fpos + len) >= n) {
- len = n - *fpos;
- }
+ if ((*fpos + len) >= n) {
+ len = n - *fpos;
+ }

- if (copy_to_user(buffer, info, len) != 0) {
- return -EFAULT;
- }
+ if (copy_to_user(buffer, info, len) != 0) {
+ return -EFAULT;
+ }

- *fpos += len;
- return len;
+ *fpos += len;
+ return len;
}

-static char* __init string_trim(char *s, int size)
+static char *__init string_trim(char *s, int size)
{
- int len;
- char *p;
+ int len;
+ char *p;

- if ((len = strlen(s)) > size) {
- len = size;
- }
+ if ((len = strlen(s)) > size) {
+ len = size;
+ }

- for (p=s+len-1; len && (*p==' '); len--,p--) {
- *p = '\0';
- }
+ for (p = s + len - 1; len && (*p == ' '); len--, p--) {
+ *p = '\0';
+ }

- return s;
+ return s;
}

/* DMI code, stolen from arch/i386/kernel/dmi_scan.c */
@@ -515,111 +511,112 @@ static char* __init string_trim(char *s,
* | |
* +-----------------------+
*/
-static char* __init dmi_string(DMIHeader *dmi, u8 s)
+static char *__init dmi_string(DMIHeader * dmi, u8 s)
{
- u8 *p;
+ u8 *p;

- if (!s) {
- return "";
- }
- s--;
-
- p = (u8 *)dmi + dmi->length;
- while (s > 0) {
- p += strlen(p);
- p++;
+ if (!s) {
+ return "";
+ }
s--;
- }

- return p;
+ p = (u8 *) dmi + dmi->length;
+ while (s > 0) {
+ p += strlen(p);
+ p++;
+ s--;
+ }
+
+ return p;
}

-static void __init dmi_decode(DMIHeader *dmi)
+static void __init dmi_decode(DMIHeader * dmi)
{
- u8 *data = (u8 *) dmi;
- char *p;
+ u8 *data = (u8 *) dmi;
+ char *p;

#ifdef I8K_DEBUG
- int i;
- printk("%08x ", (int)data);
- for (i=0; i<data[1] && i<64; i++) {
- printk("%02x ", data[i]);
- }
- printk("\n");
+ int i;
+ printk("%08x ", (int)data);
+ for (i = 0; i < data[1] && i < 64; i++) {
+ printk("%02x ", data[i]);
+ }
+ printk("\n");
#endif

- switch (dmi->type) {
- case 0: /* BIOS Information */
- p = dmi_string(dmi,data[5]);
- if (*p) {
- strlcpy(bios_version, p, sizeof(bios_version));
- string_trim(bios_version, sizeof(bios_version));
- }
- break;
- case 1: /* System Information */
- p = dmi_string(dmi,data[4]);
- if (*p) {
- strlcpy(system_vendor, p, sizeof(system_vendor));
- string_trim(system_vendor, sizeof(system_vendor));
- }
- p = dmi_string(dmi,data[5]);
- if (*p) {
- strlcpy(product_name, p, sizeof(product_name));
- string_trim(product_name, sizeof(product_name));
- }
- p = dmi_string(dmi,data[7]);
- if (*p) {
- strlcpy(serial_number, p, sizeof(serial_number));
- string_trim(serial_number, sizeof(serial_number));
- }
- break;
- }
-}
-
-static int __init dmi_table(u32 base, int len, int num, void (*fn)(DMIHeader*))
-{
- u8 *buf;
- u8 *data;
- DMIHeader *dmi;
- int i = 1;
+ switch (dmi->type) {
+ case 0: /* BIOS Information */
+ p = dmi_string(dmi, data[5]);
+ if (*p) {
+ strlcpy(bios_version, p, sizeof(bios_version));
+ string_trim(bios_version, sizeof(bios_version));
+ }
+ break;
+ case 1: /* System Information */
+ p = dmi_string(dmi, data[4]);
+ if (*p) {
+ strlcpy(system_vendor, p, sizeof(system_vendor));
+ string_trim(system_vendor, sizeof(system_vendor));
+ }
+ p = dmi_string(dmi, data[5]);
+ if (*p) {
+ strlcpy(product_name, p, sizeof(product_name));
+ string_trim(product_name, sizeof(product_name));
+ }
+ p = dmi_string(dmi, data[7]);
+ if (*p) {
+ strlcpy(serial_number, p, sizeof(serial_number));
+ string_trim(serial_number, sizeof(serial_number));
+ }
+ break;
+ }
+}

- buf = ioremap(base, len);
- if (buf == NULL) {
- return -1;
- }
- data = buf;
+static int __init dmi_table(u32 base, int len, int num,
+ void (*fn) (DMIHeader *))
+{
+ u8 *buf;
+ u8 *data;
+ DMIHeader *dmi;
+ int i = 1;

- /*
- * Stop when we see al the items the table claimed to have
- * or we run off the end of the table (also happens)
- */
- while ((i<num) && ((data-buf) < len)) {
- dmi = (DMIHeader *)data;
- /*
- * Avoid misparsing crud if the length of the last
- * record is crap
- */
- if ((data-buf+dmi->length) >= len) {
- break;
+ buf = ioremap(base, len);
+ if (buf == NULL) {
+ return -1;
}
- fn(dmi);
- data += dmi->length;
+ data = buf;
+
/*
- * Don't go off the end of the data if there is
- * stuff looking like string fill past the end
+ * Stop when we see al the items the table claimed to have
+ * or we run off the end of the table (also happens)
*/
- while (((data-buf) < len) && (*data || data[1])) {
- data++;
+ while ((i < num) && ((data - buf) < len)) {
+ dmi = (DMIHeader *) data;
+ /*
+ * Avoid misparsing crud if the length of the last
+ * record is crap
+ */
+ if ((data - buf + dmi->length) >= len) {
+ break;
+ }
+ fn(dmi);
+ data += dmi->length;
+ /*
+ * Don't go off the end of the data if there is
+ * stuff looking like string fill past the end
+ */
+ while (((data - buf) < len) && (*data || data[1])) {
+ data++;
+ }
+ data += 2;
+ i++;
}
- data += 2;
- i++;
- }
- iounmap(buf);
+ iounmap(buf);

- return 0;
+ return 0;
}

-static int __init dmi_iterate(void (*decode)(DMIHeader *))
+static int __init dmi_iterate(void (*decode) (DMIHeader *))
{
unsigned char buf[20];
void __iomem *p = ioremap(0xe0000, 0x20000), *q;
@@ -629,20 +626,20 @@ static int __init dmi_iterate(void (*dec

for (q = p; q < p + 0x20000; q += 16) {
memcpy_fromio(buf, q, 20);
- if (memcmp(buf, "_DMI_", 5)==0) {
- u16 num = buf[13]<<8 | buf[12];
- u16 len = buf [7]<<8 | buf [6];
- u32 base = buf[11]<<24 | buf[10]<<16 | buf[9]<<8 | buf[8];
+ if (memcmp(buf, "_DMI_", 5) == 0) {
+ u16 num = buf[13] << 8 | buf[12];
+ u16 len = buf[7] << 8 | buf[6];
+ u32 base = buf[11] << 24 | buf[10] << 16 | buf[9] << 8 | buf[8];
#ifdef I8K_DEBUG
printk(KERN_INFO "DMI %d.%d present.\n",
- buf[14]>>4, buf[14]&0x0F);
+ buf[14] >> 4, buf[14] & 0x0F);
printk(KERN_INFO "%d structures occupying %d bytes.\n",
- buf[13]<<8 | buf[12],
- buf [7]<<8 | buf[6]);
+ buf[13] << 8 | buf[12], buf[7] << 8 | buf[6]);
printk(KERN_INFO "DMI table at 0x%08X.\n",
- buf[11]<<24 | buf[10]<<16 | buf[9]<<8 | buf[8]);
+ buf[11] << 24 | buf[10] << 16 | buf[9] << 8 |
+ buf[8]);
#endif
- if (dmi_table(base, len, num, decode)==0) {
+ if (dmi_table(base, len, num, decode) == 0) {
iounmap(p);
return 0;
}
@@ -651,6 +648,7 @@ static int __init dmi_iterate(void (*dec
iounmap(p);
return -1;
}
+
/* end of DMI code */

/*
@@ -658,29 +656,30 @@ static int __init dmi_iterate(void (*dec
*/
static int __init i8k_dmi_probe(void)
{
- char **p;
-
- if (dmi_iterate(dmi_decode) != 0) {
- printk(KERN_INFO "i8k: unable to get DMI information\n");
- return -ENODEV;
- }
+ char **p;

- if (strncmp(system_vendor,DELL_SIGNATURE,strlen(DELL_SIGNATURE)) != 0) {
- printk(KERN_INFO "i8k: not running on a Dell system\n");
- return -ENODEV;
- }
+ if (dmi_iterate(dmi_decode) != 0) {
+ printk(KERN_INFO "i8k: unable to get DMI information\n");
+ return -ENODEV;
+ }

- for (p=supported_models; ; p++) {
- if (!*p) {
- printk(KERN_INFO "i8k: unsupported model: %s\n", product_name);
- return -ENODEV;
+ if (strncmp(system_vendor, DELL_SIGNATURE, strlen(DELL_SIGNATURE)) != 0) {
+ printk(KERN_INFO "i8k: not running on a Dell system\n");
+ return -ENODEV;
}
- if (strncmp(product_name,*p,strlen(*p)) == 0) {
- break;
+
+ for (p = supported_models;; p++) {
+ if (!*p) {
+ printk(KERN_INFO "i8k: unsupported model: %s\n",
+ product_name);
+ return -ENODEV;
+ }
+ if (strncmp(product_name, *p, strlen(*p)) == 0) {
+ break;
+ }
}
- }

- return 0;
+ return 0;
}

/*
@@ -688,59 +687,60 @@ static int __init i8k_dmi_probe(void)
*/
static int __init i8k_probe(void)
{
- char buff[4];
- int version;
- int smm_found = 0;
-
- /*
- * Get DMI information
- */
- if (i8k_dmi_probe() != 0) {
- printk(KERN_INFO "i8k: vendor=%s, model=%s, version=%s\n",
- system_vendor, product_name, bios_version);
- }
-
- /*
- * Get SMM Dell signature
- */
- if (i8k_get_dell_signature() != 0) {
- printk(KERN_INFO "i8k: unable to get SMM Dell signature\n");
- } else {
- smm_found = 1;
- }
-
- /*
- * Get SMM BIOS version.
- */
- version = i8k_get_bios_version();
- if (version <= 0) {
- printk(KERN_INFO "i8k: unable to get SMM BIOS version\n");
- } else {
- smm_found = 1;
- buff[0] = (version >> 16) & 0xff;
- buff[1] = (version >> 8) & 0xff;
- buff[2] = (version) & 0xff;
- buff[3] = '\0';
+ char buff[4];
+ int version;
+ int smm_found = 0;
+
/*
- * If DMI BIOS version is unknown use SMM BIOS version.
+ * Get DMI information
*/
- if (bios_version[0] == '?') {
- strcpy(bios_version, buff);
+ if (i8k_dmi_probe() != 0) {
+ printk(KERN_INFO "i8k: vendor=%s, model=%s, version=%s\n",
+ system_vendor, product_name, bios_version);
}
+
/*
- * Check if the two versions match.
+ * Get SMM Dell signature
*/
- if (strncmp(buff,bios_version,sizeof(bios_version)) != 0) {
- printk(KERN_INFO "i8k: BIOS version mismatch: %s != %s\n",
- buff, bios_version);
+ if (i8k_get_dell_signature() != 0) {
+ printk(KERN_INFO "i8k: unable to get SMM Dell signature\n");
+ } else {
+ smm_found = 1;
}
- }

- if (!smm_found && !force) {
- return -ENODEV;
- }
+ /*
+ * Get SMM BIOS version.
+ */
+ version = i8k_get_bios_version();
+ if (version <= 0) {
+ printk(KERN_INFO "i8k: unable to get SMM BIOS version\n");
+ } else {
+ smm_found = 1;
+ buff[0] = (version >> 16) & 0xff;
+ buff[1] = (version >> 8) & 0xff;
+ buff[2] = (version) & 0xff;
+ buff[3] = '\0';
+ /*
+ * If DMI BIOS version is unknown use SMM BIOS version.
+ */
+ if (bios_version[0] == '?') {
+ strcpy(bios_version, buff);
+ }
+ /*
+ * Check if the two versions match.
+ */
+ if (strncmp(buff, bios_version, sizeof(bios_version)) != 0) {
+ printk(KERN_INFO
+ "i8k: BIOS version mismatch: %s != %s\n", buff,
+ bios_version);
+ }
+ }

- return 0;
+ if (!smm_found && !force) {
+ return -ENODEV;
+ }
+
+ return 0;
}

#ifdef MODULE
@@ -748,40 +748,40 @@ static
#endif
int __init i8k_init(void)
{
- struct proc_dir_entry *proc_i8k;
+ struct proc_dir_entry *proc_i8k;

- /* Are we running on an supported laptop? */
- if (i8k_probe() != 0) {
- return -ENODEV;
- }
-
- /* Register the proc entry */
- proc_i8k = create_proc_info_entry("i8k", 0, NULL, i8k_get_info);
- if (!proc_i8k) {
- return -ENOENT;
- }
- proc_i8k->proc_fops = &i8k_fops;
- proc_i8k->owner = THIS_MODULE;
-
- printk(KERN_INFO
- "Dell laptop SMM driver v%s Massimo Dal Zotto ([email protected])\n",
- I8K_VERSION);
+ /* Are we running on an supported laptop? */
+ if (i8k_probe() != 0) {
+ return -ENODEV;
+ }
+
+ /* Register the proc entry */
+ proc_i8k = create_proc_info_entry("i8k", 0, NULL, i8k_get_info);
+ if (!proc_i8k) {
+ return -ENOENT;
+ }
+ proc_i8k->proc_fops = &i8k_fops;
+ proc_i8k->owner = THIS_MODULE;

- return 0;
+ printk(KERN_INFO
+ "Dell laptop SMM driver v%s Massimo Dal Zotto ([email protected])\n",
+ I8K_VERSION);
+
+ return 0;
}

#ifdef MODULE
int init_module(void)
{
- return i8k_init();
+ return i8k_init();
}

void cleanup_module(void)
{
- /* Remove the proc entry */
- remove_proc_entry("i8k", NULL);
+ /* Remove the proc entry */
+ remove_proc_entry("i8k", NULL);

- printk(KERN_INFO "i8k: module unloaded\n");
+ printk(KERN_INFO "i8k: module unloaded\n");
}
#endif

2005-02-24 06:18:52

by Dmitry Torokhov

[permalink] [raw]
Subject: [PATCH 2/5] I8K - use standard DMI functions

===================================================================

I8K: Change to use stock dmi infrastructure instead of homegrown
parsing code. The driver now requres box's DMI data to match
list of supported models so driver can be safely compiled-in
by default without fear of it poking into random SMM BIOS
code. DMI checks can be ignored with i8k.ignore_dmi option.

Signed-off-by: Dmitry Torokhov <[email protected]>

Documentation/kernel-parameters.txt | 3
arch/i386/kernel/dmi_scan.c | 1
drivers/char/i8k.c | 304 ++++++------------------------------
include/linux/dmi.h | 1
4 files changed, 60 insertions(+), 249 deletions(-)

Index: dtor/arch/i386/kernel/dmi_scan.c
===================================================================
--- dtor.orig/arch/i386/kernel/dmi_scan.c
+++ dtor/arch/i386/kernel/dmi_scan.c
@@ -416,6 +416,7 @@ static void __init dmi_decode(struct dmi
dmi_save_ident(dm, DMI_PRODUCT_VERSION, 6);
dmi_printk(("Serial Number: %s\n",
dmi_string(dm, data[7])));
+ dmi_save_ident(dm, DMI_PRODUCT_SERIAL, 7);
break;
case 2:
dmi_printk(("Board Vendor: %s\n",
Index: dtor/include/linux/dmi.h
===================================================================
--- dtor.orig/include/linux/dmi.h
+++ dtor/include/linux/dmi.h
@@ -9,6 +9,7 @@ enum dmi_field {
DMI_SYS_VENDOR,
DMI_PRODUCT_NAME,
DMI_PRODUCT_VERSION,
+ DMI_PRODUCT_SERIAL,
DMI_BOARD_VENDOR,
DMI_BOARD_NAME,
DMI_BOARD_VERSION,
Index: dtor/drivers/char/i8k.c
===================================================================
--- dtor.orig/drivers/char/i8k.c
+++ dtor/drivers/char/i8k.c
@@ -20,7 +20,7 @@
#include <linux/types.h>
#include <linux/init.h>
#include <linux/proc_fs.h>
-#include <linux/apm_bios.h>
+#include <linux/dmi.h>
#include <asm/uaccess.h>
#include <asm/io.h>

@@ -52,18 +52,7 @@

#define I8K_TEMPERATURE_BUG 1

-#define DELL_SIGNATURE "Dell Computer"
-
-static char *supported_models[] = {
- "Inspiron",
- "Latitude",
- NULL
-};
-
-static char system_vendor[48] = "?";
-static char product_name[48] = "?";
-static char bios_version[4] = "?";
-static char serial_number[16] = "?";
+static char bios_version[4];

MODULE_AUTHOR("Massimo Dal Zotto ([email protected])");
MODULE_DESCRIPTION("Driver for accessing SMM BIOS on Dell laptops");
@@ -73,6 +62,10 @@ static int force;
module_param(force, bool, 0);
MODULE_PARM_DESC(force, "Force loading without checking for supported models");

+static int ignore_dmi;
+module_param(ignore_dmi, bool, 0);
+MODULE_PARM_DESC(ignore_dmi, "Continue probing hardware even if DMI data does not match");
+
static int restricted;
module_param(restricted, bool, 0);
MODULE_PARM_DESC(restricted, "Allow fan control if SYS_ADMIN capability set");
@@ -99,11 +92,10 @@ typedef struct {
unsigned int edi __attribute__ ((packed));
} SMMRegisters;

-typedef struct {
- u8 type;
- u8 length;
- u16 handle;
-} DMIHeader;
+static inline char *i8k_get_dmi_data(int field)
+{
+ return dmi_get_system_info(field) ? : "N/A";
+}

/*
* Call the System Management Mode BIOS. Code provided by Jonathan Buzzard.
@@ -163,15 +155,6 @@ static int i8k_get_bios_version(void)
}

/*
- * Read the machine id.
- */
-static int i8k_get_serial_number(unsigned char *buff)
-{
- strlcpy(buff, serial_number, sizeof(serial_number));
- return 0;
-}
-
-/*
* Read the Fn key status.
*/
static int i8k_get_fn_status(void)
@@ -328,7 +311,7 @@ static int i8k_get_dell_signature(void)
static int i8k_ioctl(struct inode *ip, struct file *fp, unsigned int cmd,
unsigned long arg)
{
- int val;
+ int val = 0;
int speed;
unsigned char buff[16];
int __user *argp = (int __user *)arg;
@@ -343,7 +326,7 @@ static int i8k_ioctl(struct inode *ip, s

case I8K_MACHINE_ID:
memset(buff, 0, 16);
- val = i8k_get_serial_number(buff);
+ strlcpy(buff, i8k_get_dmi_data(DMI_PRODUCT_SERIAL), sizeof(buff));
break;

case I8K_FN_STATUS:
@@ -451,10 +434,10 @@ static int i8k_get_info(char *buffer, ch
n = sprintf(buffer, "%s %s %s %d %d %d %d %d %d %d\n",
I8K_PROC_FMT,
bios_version,
- serial_number,
+ dmi_get_system_info(DMI_PRODUCT_SERIAL) ? : "N/A",
cpu_temp,
- left_fan,
- right_fan, left_speed, right_speed, ac_power, fn_key);
+ left_fan, right_fan, left_speed, right_speed,
+ ac_power, fn_key);

return n;
}
@@ -486,201 +469,23 @@ static ssize_t i8k_read(struct file *f,
return len;
}

-static char *__init string_trim(char *s, int size)
-{
- int len;
- char *p;
-
- if ((len = strlen(s)) > size) {
- len = size;
- }
-
- for (p = s + len - 1; len && (*p == ' '); len--, p--) {
- *p = '\0';
- }
-
- return s;
-}
-
-/* DMI code, stolen from arch/i386/kernel/dmi_scan.c */
-
-/*
- * |<-- dmi->length -->|
- * | |
- * |dmi header s=N | string1,\0, ..., stringN,\0, ..., \0
- * | |
- * +-----------------------+
- */
-static char *__init dmi_string(DMIHeader * dmi, u8 s)
-{
- u8 *p;
-
- if (!s) {
- return "";
- }
- s--;
-
- p = (u8 *) dmi + dmi->length;
- while (s > 0) {
- p += strlen(p);
- p++;
- s--;
- }
-
- return p;
-}
-
-static void __init dmi_decode(DMIHeader * dmi)
-{
- u8 *data = (u8 *) dmi;
- char *p;
-
-#ifdef I8K_DEBUG
- int i;
- printk("%08x ", (int)data);
- for (i = 0; i < data[1] && i < 64; i++) {
- printk("%02x ", data[i]);
- }
- printk("\n");
-#endif
-
- switch (dmi->type) {
- case 0: /* BIOS Information */
- p = dmi_string(dmi, data[5]);
- if (*p) {
- strlcpy(bios_version, p, sizeof(bios_version));
- string_trim(bios_version, sizeof(bios_version));
- }
- break;
- case 1: /* System Information */
- p = dmi_string(dmi, data[4]);
- if (*p) {
- strlcpy(system_vendor, p, sizeof(system_vendor));
- string_trim(system_vendor, sizeof(system_vendor));
- }
- p = dmi_string(dmi, data[5]);
- if (*p) {
- strlcpy(product_name, p, sizeof(product_name));
- string_trim(product_name, sizeof(product_name));
- }
- p = dmi_string(dmi, data[7]);
- if (*p) {
- strlcpy(serial_number, p, sizeof(serial_number));
- string_trim(serial_number, sizeof(serial_number));
- }
- break;
- }
-}
-
-static int __init dmi_table(u32 base, int len, int num,
- void (*fn) (DMIHeader *))
-{
- u8 *buf;
- u8 *data;
- DMIHeader *dmi;
- int i = 1;
-
- buf = ioremap(base, len);
- if (buf == NULL) {
- return -1;
- }
- data = buf;
-
- /*
- * Stop when we see al the items the table claimed to have
- * or we run off the end of the table (also happens)
- */
- while ((i < num) && ((data - buf) < len)) {
- dmi = (DMIHeader *) data;
- /*
- * Avoid misparsing crud if the length of the last
- * record is crap
- */
- if ((data - buf + dmi->length) >= len) {
- break;
- }
- fn(dmi);
- data += dmi->length;
- /*
- * Don't go off the end of the data if there is
- * stuff looking like string fill past the end
- */
- while (((data - buf) < len) && (*data || data[1])) {
- data++;
- }
- data += 2;
- i++;
- }
- iounmap(buf);
-
- return 0;
-}
-
-static int __init dmi_iterate(void (*decode) (DMIHeader *))
-{
- unsigned char buf[20];
- void __iomem *p = ioremap(0xe0000, 0x20000), *q;
-
- if (!p)
- return -1;
-
- for (q = p; q < p + 0x20000; q += 16) {
- memcpy_fromio(buf, q, 20);
- if (memcmp(buf, "_DMI_", 5) == 0) {
- u16 num = buf[13] << 8 | buf[12];
- u16 len = buf[7] << 8 | buf[6];
- u32 base = buf[11] << 24 | buf[10] << 16 | buf[9] << 8 | buf[8];
-#ifdef I8K_DEBUG
- printk(KERN_INFO "DMI %d.%d present.\n",
- buf[14] >> 4, buf[14] & 0x0F);
- printk(KERN_INFO "%d structures occupying %d bytes.\n",
- buf[13] << 8 | buf[12], buf[7] << 8 | buf[6]);
- printk(KERN_INFO "DMI table at 0x%08X.\n",
- buf[11] << 24 | buf[10] << 16 | buf[9] << 8 |
- buf[8]);
-#endif
- if (dmi_table(base, len, num, decode) == 0) {
- iounmap(p);
- return 0;
- }
- }
- }
- iounmap(p);
- return -1;
-}
-
-/* end of DMI code */
-
-/*
- * Get DMI information.
- */
-static int __init i8k_dmi_probe(void)
-{
- char **p;
-
- if (dmi_iterate(dmi_decode) != 0) {
- printk(KERN_INFO "i8k: unable to get DMI information\n");
- return -ENODEV;
- }
-
- if (strncmp(system_vendor, DELL_SIGNATURE, strlen(DELL_SIGNATURE)) != 0) {
- printk(KERN_INFO "i8k: not running on a Dell system\n");
- return -ENODEV;
- }
-
- for (p = supported_models;; p++) {
- if (!*p) {
- printk(KERN_INFO "i8k: unsupported model: %s\n",
- product_name);
- return -ENODEV;
- }
- if (strncmp(product_name, *p, strlen(*p)) == 0) {
- break;
- }
- }
-
- return 0;
-}
+static struct dmi_system_id __initdata i8k_dmi_table[] = {
+ {
+ .ident = "Dell Inspiron",
+ .matches = {
+ DMI_MATCH(DMI_SYS_VENDOR, "Dell Computer"),
+ DMI_MATCH(DMI_PRODUCT_NAME, "Inspiron"),
+ },
+ },
+ {
+ .ident = "Dell Latitude",
+ .matches = {
+ DMI_MATCH(DMI_SYS_VENDOR, "Dell Computer"),
+ DMI_MATCH(DMI_PRODUCT_NAME, "Latitude"),
+ },
+ },
+ { }
+};

/*
* Probe for the presence of a supported laptop.
@@ -689,23 +494,30 @@ static int __init i8k_probe(void)
{
char buff[4];
int version;
- int smm_found = 0;

/*
* Get DMI information
*/
- if (i8k_dmi_probe() != 0) {
+ if (!dmi_check_system(i8k_dmi_table)) {
+ if (!ignore_dmi && !force)
+ return -ENODEV;
+
+ printk(KERN_INFO "i8k: not running on a supported Dell system.\n");
printk(KERN_INFO "i8k: vendor=%s, model=%s, version=%s\n",
- system_vendor, product_name, bios_version);
+ i8k_get_dmi_data(DMI_SYS_VENDOR),
+ i8k_get_dmi_data(DMI_PRODUCT_NAME),
+ i8k_get_dmi_data(DMI_BIOS_VERSION));
}

+ strlcpy(bios_version, i8k_get_dmi_data(DMI_BIOS_VERSION), sizeof(bios_version));
+
/*
* Get SMM Dell signature
*/
if (i8k_get_dell_signature() != 0) {
- printk(KERN_INFO "i8k: unable to get SMM Dell signature\n");
- } else {
- smm_found = 1;
+ printk(KERN_ERR "i8k: unable to get SMM Dell signature\n");
+ if (!force)
+ return -ENODEV;
}

/*
@@ -713,9 +525,10 @@ static int __init i8k_probe(void)
*/
version = i8k_get_bios_version();
if (version <= 0) {
- printk(KERN_INFO "i8k: unable to get SMM BIOS version\n");
+ printk(KERN_ERR "i8k: unable to get SMM BIOS version\n");
+ if (!force)
+ return -ENODEV;
} else {
- smm_found = 1;
buff[0] = (version >> 16) & 0xff;
buff[1] = (version >> 8) & 0xff;
buff[2] = (version) & 0xff;
@@ -723,21 +536,15 @@ static int __init i8k_probe(void)
/*
* If DMI BIOS version is unknown use SMM BIOS version.
*/
- if (bios_version[0] == '?') {
- strcpy(bios_version, buff);
- }
+ if (!dmi_get_system_info(DMI_BIOS_VERSION))
+ strlcpy(bios_version, buff, sizeof(bios_version));
+
/*
* Check if the two versions match.
*/
- if (strncmp(buff, bios_version, sizeof(bios_version)) != 0) {
- printk(KERN_INFO
- "i8k: BIOS version mismatch: %s != %s\n", buff,
- bios_version);
- }
- }
-
- if (!smm_found && !force) {
- return -ENODEV;
+ if (strncmp(buff, bios_version, sizeof(bios_version)) != 0)
+ printk(KERN_WARNING "i8k: BIOS version mismatch: %s != %s\n",
+ buff, bios_version);
}

return 0;
@@ -751,9 +558,8 @@ int __init i8k_init(void)
struct proc_dir_entry *proc_i8k;

/* Are we running on an supported laptop? */
- if (i8k_probe() != 0) {
+ if (i8k_probe())
return -ENODEV;
- }

/* Register the proc entry */
proc_i8k = create_proc_info_entry("i8k", 0, NULL, i8k_get_info);
Index: dtor/Documentation/kernel-parameters.txt
===================================================================
--- dtor.orig/Documentation/kernel-parameters.txt
+++ dtor/Documentation/kernel-parameters.txt
@@ -528,6 +528,9 @@ running once the system is up.

i810= [HW,DRM]

+ i8k.ignore_dmi [HW] Continue probing hardware even if DMI data
+ indicates that the driver is running on unsupported
+ hardware.
i8k.force [HW] Activate i8k driver even if SMM BIOS signature
does not match list of supported models.
i8k.power_status

2005-02-24 06:18:51

by Dmitry Torokhov

[permalink] [raw]
Subject: [PATCH 3/5] I8K - switch to seq_file

===================================================================

I8K: Change proc code to use seq_file.

Signed-off-by: Dmitry Torokhov <[email protected]>


i8k.c | 64 ++++++++++++++++++++++------------------------------------------
1 files changed, 22 insertions(+), 42 deletions(-)

Index: dtor/drivers/char/i8k.c
===================================================================
--- dtor.orig/drivers/char/i8k.c
+++ dtor/drivers/char/i8k.c
@@ -20,13 +20,14 @@
#include <linux/types.h>
#include <linux/init.h>
#include <linux/proc_fs.h>
+#include <linux/seq_file.h>
#include <linux/dmi.h>
#include <asm/uaccess.h>
#include <asm/io.h>

#include <linux/i8k.h>

-#define I8K_VERSION "1.13 14/05/2002"
+#define I8K_VERSION "1.14 21/02/2005"

#define I8K_SMM_FN_STATUS 0x0025
#define I8K_SMM_POWER_STATUS 0x0069
@@ -74,13 +75,16 @@ static int power_status;
module_param(power_status, bool, 0600);
MODULE_PARM_DESC(power_status, "Report power status in /proc/i8k");

-static ssize_t i8k_read(struct file *, char __user *, size_t, loff_t *);
+static int i8k_open_fs(struct inode *inode, struct file *file);
static int i8k_ioctl(struct inode *, struct file *, unsigned int,
unsigned long);

static struct file_operations i8k_fops = {
- .read = i8k_read,
- .ioctl = i8k_ioctl,
+ .open = i8k_open_fs,
+ .read = seq_read,
+ .llseek = seq_lseek,
+ .release = single_release,
+ .ioctl = i8k_ioctl,
};

typedef struct {
@@ -400,9 +404,9 @@ static int i8k_ioctl(struct inode *ip, s
/*
* Print the information for /proc/i8k.
*/
-static int i8k_get_info(char *buffer, char **start, off_t fpos, int length)
+static int i8k_proc_show(struct seq_file *seq, void *offset)
{
- int n, fn_key, cpu_temp, ac_power;
+ int fn_key, cpu_temp, ac_power;
int left_fan, right_fan, left_speed, right_speed;

cpu_temp = i8k_get_cpu_temp(); /* 11100 ??s */
@@ -431,42 +435,18 @@ static int i8k_get_info(char *buffer, ch
* 9) AC power
* 10) Fn Key status
*/
- n = sprintf(buffer, "%s %s %s %d %d %d %d %d %d %d\n",
- I8K_PROC_FMT,
- bios_version,
- dmi_get_system_info(DMI_PRODUCT_SERIAL) ? : "N/A",
- cpu_temp,
- left_fan, right_fan, left_speed, right_speed,
- ac_power, fn_key);
-
- return n;
+ return seq_printf(seq, "%s %s %s %d %d %d %d %d %d %d\n",
+ I8K_PROC_FMT,
+ bios_version,
+ dmi_get_system_info(DMI_PRODUCT_SERIAL) ? : "N/A",
+ cpu_temp,
+ left_fan, right_fan, left_speed, right_speed,
+ ac_power, fn_key);
}

-static ssize_t i8k_read(struct file *f, char __user * buffer, size_t len,
- loff_t * fpos)
+static int i8k_open_fs(struct inode *inode, struct file *file)
{
- int n;
- char info[128];
-
- n = i8k_get_info(info, NULL, 0, 128);
- if (n <= 0) {
- return n;
- }
-
- if (*fpos >= n) {
- return 0;
- }
-
- if ((*fpos + len) >= n) {
- len = n - *fpos;
- }
-
- if (copy_to_user(buffer, info, len) != 0) {
- return -EFAULT;
- }
-
- *fpos += len;
- return len;
+ return single_open(file, i8k_proc_show, NULL);
}

static struct dmi_system_id __initdata i8k_dmi_table[] = {
@@ -562,10 +542,10 @@ int __init i8k_init(void)
return -ENODEV;

/* Register the proc entry */
- proc_i8k = create_proc_info_entry("i8k", 0, NULL, i8k_get_info);
- if (!proc_i8k) {
+ proc_i8k = create_proc_entry("i8k", 0, NULL);
+ if (!proc_i8k)
return -ENOENT;
- }
+
proc_i8k->proc_fops = &i8k_fops;
proc_i8k->owner = THIS_MODULE;

2005-02-24 06:23:44

by Dmitry Torokhov

[permalink] [raw]
Subject: [PATCH 4/5] I8K - switch to module_{init|exit}

===================================================================

I8K: use module_{init|exit} instead of old style #ifdef MODULE
code, some formatting changes.

Signed-off-by: Dmitry Torokhov <[email protected]>


i8k.c | 149 ++++++++++++++++++++---------------------------------------------
misc.c | 4 -
2 files changed, 47 insertions(+), 106 deletions(-)

Index: dtor/drivers/char/misc.c
===================================================================
--- dtor.orig/drivers/char/misc.c
+++ dtor/drivers/char/misc.c
@@ -67,7 +67,6 @@ extern int rtc_DP8570A_init(void);
extern int rtc_MK48T08_init(void);
extern int pmu_device_init(void);
extern int tosh_init(void);
-extern int i8k_init(void);

#ifdef CONFIG_PROC_FS
static void *misc_seq_start(struct seq_file *seq, loff_t *pos)
@@ -317,9 +316,6 @@ static int __init misc_init(void)
#ifdef CONFIG_TOSHIBA
tosh_init();
#endif
-#ifdef CONFIG_I8K
- i8k_init();
-#endif
if (register_chrdev(MISC_MAJOR,"misc",&misc_fops)) {
printk("unable to get major %d for misc devices\n",
MISC_MAJOR);
Index: dtor/drivers/char/i8k.c
===================================================================
--- dtor.orig/drivers/char/i8k.c
+++ dtor/drivers/char/i8k.c
@@ -87,14 +87,14 @@ static struct file_operations i8k_fops =
.ioctl = i8k_ioctl,
};

-typedef struct {
+struct smm_regs {
unsigned int eax;
unsigned int ebx __attribute__ ((packed));
unsigned int ecx __attribute__ ((packed));
unsigned int edx __attribute__ ((packed));
unsigned int esi __attribute__ ((packed));
unsigned int edi __attribute__ ((packed));
-} SMMRegisters;
+};

static inline char *i8k_get_dmi_data(int field)
{
@@ -104,7 +104,7 @@ static inline char *i8k_get_dmi_data(int
/*
* Call the System Management Mode BIOS. Code provided by Jonathan Buzzard.
*/
-static int i8k_smm(SMMRegisters * regs)
+static int i8k_smm(struct smm_regs *regs)
{
int rc;
int eax = regs->eax;
@@ -134,9 +134,8 @@ static int i8k_smm(SMMRegisters * regs)
: "a"(regs)
: "%ebx", "%ecx", "%edx", "%esi", "%edi", "memory");

- if ((rc != 0) || ((regs->eax & 0xffff) == 0xffff) || (regs->eax == eax)) {
+ if (rc != 0 || (regs->eax & 0xffff) == 0xffff || regs->eax == eax)
return -EINVAL;
- }

return 0;
}
@@ -147,15 +146,9 @@ static int i8k_smm(SMMRegisters * regs)
*/
static int i8k_get_bios_version(void)
{
- SMMRegisters regs = { 0, 0, 0, 0, 0, 0 };
- int rc;
-
- regs.eax = I8K_SMM_BIOS_VERSION;
- if ((rc = i8k_smm(&regs)) < 0) {
- return rc;
- }
+ struct smm_regs regs = { .eax = I8K_SMM_BIOS_VERSION, };

- return regs.eax;
+ return i8k_smm(&regs) < 0 ? : regs.eax;
}

/*
@@ -163,13 +156,11 @@ static int i8k_get_bios_version(void)
*/
static int i8k_get_fn_status(void)
{
- SMMRegisters regs = { 0, 0, 0, 0, 0, 0 };
+ struct smm_regs regs = { .eax = I8K_SMM_FN_STATUS, };
int rc;

- regs.eax = I8K_SMM_FN_STATUS;
- if ((rc = i8k_smm(&regs)) < 0) {
+ if ((rc = i8k_smm(&regs)) < 0)
return rc;
- }

switch ((regs.eax >> I8K_FN_SHIFT) & I8K_FN_MASK) {
case I8K_FN_UP:
@@ -188,20 +179,13 @@ static int i8k_get_fn_status(void)
*/
static int i8k_get_power_status(void)
{
- SMMRegisters regs = { 0, 0, 0, 0, 0, 0 };
+ struct smm_regs regs = { .eax = I8K_SMM_POWER_STATUS, };
int rc;

- regs.eax = I8K_SMM_POWER_STATUS;
- if ((rc = i8k_smm(&regs)) < 0) {
+ if ((rc = i8k_smm(&regs)) < 0)
return rc;
- }

- switch (regs.eax & 0xff) {
- case I8K_POWER_AC:
- return I8K_AC;
- default:
- return I8K_BATTERY;
- }
+ return (regs.eax & 0xff) == I8K_POWER_AC ? I8K_AC : I8K_BATTERY;
}

/*
@@ -209,16 +193,10 @@ static int i8k_get_power_status(void)
*/
static int i8k_get_fan_status(int fan)
{
- SMMRegisters regs = { 0, 0, 0, 0, 0, 0 };
- int rc;
+ struct smm_regs regs = { .eax = I8K_SMM_GET_FAN, };

- regs.eax = I8K_SMM_GET_FAN;
regs.ebx = fan & 0xff;
- if ((rc = i8k_smm(&regs)) < 0) {
- return rc;
- }
-
- return (regs.eax & 0xff);
+ return i8k_smm(&regs) < 0 ? : regs.eax & 0xff;
}

/*
@@ -226,16 +204,10 @@ static int i8k_get_fan_status(int fan)
*/
static int i8k_get_fan_speed(int fan)
{
- SMMRegisters regs = { 0, 0, 0, 0, 0, 0 };
- int rc;
+ struct smm_regs regs = { .eax = I8K_SMM_GET_SPEED, };

- regs.eax = I8K_SMM_GET_SPEED;
regs.ebx = fan & 0xff;
- if ((rc = i8k_smm(&regs)) < 0) {
- return rc;
- }
-
- return (regs.eax & 0xffff) * I8K_FAN_MULT;
+ return i8k_smm(&regs) < 0 ? : (regs.eax & 0xffff) * I8K_FAN_MULT;
}

/*
@@ -243,18 +215,12 @@ static int i8k_get_fan_speed(int fan)
*/
static int i8k_set_fan(int fan, int speed)
{
- SMMRegisters regs = { 0, 0, 0, 0, 0, 0 };
- int rc;
+ struct smm_regs regs = { .eax = I8K_SMM_SET_FAN, };

speed = (speed < 0) ? 0 : ((speed > I8K_FAN_MAX) ? I8K_FAN_MAX : speed);
-
- regs.eax = I8K_SMM_SET_FAN;
regs.ebx = (fan & 0xff) | (speed << 8);
- if ((rc = i8k_smm(&regs)) < 0) {
- return rc;
- }

- return (i8k_get_fan_status(fan));
+ return i8k_smm(&regs) < 0 ? : i8k_get_fan_status(fan);
}

/*
@@ -262,18 +228,17 @@ static int i8k_set_fan(int fan, int spee
*/
static int i8k_get_cpu_temp(void)
{
- SMMRegisters regs = { 0, 0, 0, 0, 0, 0 };
+ struct smm_regs regs = { .eax = I8K_SMM_GET_TEMP, };
int rc;
int temp;

#ifdef I8K_TEMPERATURE_BUG
- static int prev = 0;
+ static int prev;
#endif

- regs.eax = I8K_SMM_GET_TEMP;
- if ((rc = i8k_smm(&regs)) < 0) {
+ if ((rc = i8k_smm(&regs)) < 0)
return rc;
- }
+
temp = regs.eax & 0xff;

#ifdef I8K_TEMPERATURE_BUG
@@ -297,19 +262,13 @@ static int i8k_get_cpu_temp(void)

static int i8k_get_dell_signature(void)
{
- SMMRegisters regs = { 0, 0, 0, 0, 0, 0 };
+ struct smm_regs regs = { .eax = I8K_SMM_GET_DELL_SIG, };
int rc;

- regs.eax = I8K_SMM_GET_DELL_SIG;
- if ((rc = i8k_smm(&regs)) < 0) {
+ if ((rc = i8k_smm(&regs)) < 0)
return rc;
- }

- if ((regs.eax == 1145651527) && (regs.edx == 1145392204)) {
- return 0;
- } else {
- return -1;
- }
+ return regs.eax == 1145651527 && regs.edx == 1145392204 ? 0 : -1;
}

static int i8k_ioctl(struct inode *ip, struct file *fp, unsigned int cmd,
@@ -346,29 +305,29 @@ static int i8k_ioctl(struct inode *ip, s
break;

case I8K_GET_SPEED:
- if (copy_from_user(&val, argp, sizeof(int))) {
+ if (copy_from_user(&val, argp, sizeof(int)))
return -EFAULT;
- }
+
val = i8k_get_fan_speed(val);
break;

case I8K_GET_FAN:
- if (copy_from_user(&val, argp, sizeof(int))) {
+ if (copy_from_user(&val, argp, sizeof(int)))
return -EFAULT;
- }
+
val = i8k_get_fan_status(val);
break;

case I8K_SET_FAN:
- if (restricted && !capable(CAP_SYS_ADMIN)) {
+ if (restricted && !capable(CAP_SYS_ADMIN))
return -EPERM;
- }
- if (copy_from_user(&val, argp, sizeof(int))) {
+
+ if (copy_from_user(&val, argp, sizeof(int)))
return -EFAULT;
- }
- if (copy_from_user(&speed, argp + 1, sizeof(int))) {
+
+ if (copy_from_user(&speed, argp + 1, sizeof(int)))
return -EFAULT;
- }
+
val = i8k_set_fan(val, speed);
break;

@@ -376,25 +335,24 @@ static int i8k_ioctl(struct inode *ip, s
return -EINVAL;
}

- if (val < 0) {
+ if (val < 0)
return val;
- }

switch (cmd) {
case I8K_BIOS_VERSION:
- if (copy_to_user(argp, &val, 4)) {
+ if (copy_to_user(argp, &val, 4))
return -EFAULT;
- }
+
break;
case I8K_MACHINE_ID:
- if (copy_to_user(argp, buff, 16)) {
+ if (copy_to_user(argp, buff, 16))
return -EFAULT;
- }
+
break;
default:
- if (copy_to_user(argp, &val, sizeof(int))) {
+ if (copy_to_user(argp, &val, sizeof(int)))
return -EFAULT;
- }
+
break;
}

@@ -415,11 +373,10 @@ static int i8k_proc_show(struct seq_file
left_speed = i8k_get_fan_speed(I8K_FAN_LEFT); /* 580 ??s */
right_speed = i8k_get_fan_speed(I8K_FAN_RIGHT); /* 580 ??s */
fn_key = i8k_get_fn_status(); /* 750 ??s */
- if (power_status) {
+ if (power_status)
ac_power = i8k_get_power_status(); /* 14700 ??s */
- } else {
+ else
ac_power = -1;
- }

/*
* Info:
@@ -530,10 +487,7 @@ static int __init i8k_probe(void)
return 0;
}

-#ifdef MODULE
-static
-#endif
-int __init i8k_init(void)
+static int __init i8k_init(void)
{
struct proc_dir_entry *proc_i8k;

@@ -556,19 +510,10 @@ int __init i8k_init(void)
return 0;
}

-#ifdef MODULE
-int init_module(void)
+static void __exit i8k_exit(void)
{
- return i8k_init();
-}
-
-void cleanup_module(void)
-{
- /* Remove the proc entry */
remove_proc_entry("i8k", NULL);
-
- printk(KERN_INFO "i8k: module unloaded\n");
}
-#endif

-/* end of file */
+module_init(i8k_init);
+module_exit(i8k_exit);

2005-02-24 06:23:40

by Dmitry Torokhov

[permalink] [raw]
Subject: [PATCH 5/5] I8K - convert to platform device (sysfs)



i8k.c | 117 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
1 files changed, 117 insertions(+)

Index: dtor/drivers/char/i8k.c
===================================================================
--- dtor.orig/drivers/char/i8k.c
+++ dtor/drivers/char/i8k.c
@@ -22,6 +22,7 @@
#include <linux/proc_fs.h>
#include <linux/seq_file.h>
#include <linux/dmi.h>
+#include <linux/device.h>
#include <asm/uaccess.h>
#include <asm/io.h>

@@ -87,6 +88,13 @@ static struct file_operations i8k_fops =
.ioctl = i8k_ioctl,
};

+static struct device_driver i8k_driver = {
+ .name = "i8k",
+ .bus = &platform_bus_type,
+};
+
+static struct platform_device *i8k_device;
+
struct smm_regs {
unsigned int eax;
unsigned int ebx __attribute__ ((packed));
@@ -406,6 +414,89 @@ static int i8k_open_fs(struct inode *ino
return single_open(file, i8k_proc_show, NULL);
}

+static ssize_t i8k_sysfs_cpu_temp_show(struct device *dev, char *buf)
+{
+ int temp = i8k_get_cpu_temp();
+
+ return temp < 0 ? -EIO : sprintf(buf, "%d\n", temp);
+}
+
+static ssize_t i8k_sysfs_fan1_show(struct device *dev, char *buf)
+{
+ int status = i8k_get_fan_status(0);
+ return status < 0 ? -EIO : sprintf(buf, "%d\n", status);
+}
+
+static ssize_t i8k_sysfs_fan1_set(struct device *dev, const char *buf, size_t count)
+{
+ unsigned long state;
+ char *rest;
+
+ if (restricted && !capable(CAP_SYS_ADMIN))
+ return -EPERM;
+
+ state = simple_strtoul(buf, &rest, 10);
+ if (*rest || state > I8K_FAN_MAX)
+ return -EINVAL;
+
+ if (i8k_set_fan(0, state) < 0)
+ return -EIO;
+
+ return count;
+}
+
+static ssize_t i8k_sysfs_fan2_show(struct device *dev, char *buf)
+{
+ int status = i8k_get_fan_status(1);
+ return status < 0 ? -EIO : sprintf(buf, "%d\n", status);
+}
+
+static ssize_t i8k_sysfs_fan2_set(struct device *dev, const char *buf, size_t count)
+{
+ unsigned long state;
+ char *rest;
+
+ if (restricted && !capable(CAP_SYS_ADMIN))
+ return -EPERM;
+
+ state = simple_strtoul(buf, &rest, 10);
+ if (*rest || state > I8K_FAN_MAX)
+ return -EINVAL;
+
+ if (i8k_set_fan(1, state) < 0)
+ return -EIO;
+
+ return count;
+}
+
+static ssize_t i8k_sysfs_fan1_speed_show(struct device *dev, char *buf)
+{
+ int speed = i8k_get_fan_speed(0);
+ return speed < 0 ? -EIO : sprintf(buf, "%d\n", speed);
+}
+
+static ssize_t i8k_sysfs_fan2_speed_show(struct device *dev, char *buf)
+{
+ int speed = i8k_get_fan_speed(1);
+ return speed < 0 ? -EIO : sprintf(buf, "%d\n", speed);
+}
+
+static ssize_t i8k_sysfs_power_status_show(struct device *dev, char *buf)
+{
+ int status = power_status ? i8k_get_power_status() : -1;
+ return status < 0 ? -EIO : sprintf(buf, "%d\n", status);
+}
+
+static struct device_attribute i8k_device_attrs[] = {
+ __ATTR(cpu_temp, 0444, i8k_sysfs_cpu_temp_show, NULL),
+ __ATTR(fan1_state, 0644, i8k_sysfs_fan1_show, i8k_sysfs_fan1_set),
+ __ATTR(fan2_state, 0644, i8k_sysfs_fan2_show, i8k_sysfs_fan2_set),
+ __ATTR(fan1_speed, 0444, i8k_sysfs_fan1_speed_show, NULL),
+ __ATTR(fan2_speed, 0444, i8k_sysfs_fan2_speed_show, NULL),
+ __ATTR(power_status, 0444, i8k_sysfs_power_status_show, NULL),
+ __ATTR_NULL
+};
+
static struct dmi_system_id __initdata i8k_dmi_table[] = {
{
.ident = "Dell Inspiron",
@@ -490,6 +581,7 @@ static int __init i8k_probe(void)
static int __init i8k_init(void)
{
struct proc_dir_entry *proc_i8k;
+ int err, i;

/* Are we running on an supported laptop? */
if (i8k_probe())
@@ -503,15 +595,40 @@ static int __init i8k_init(void)
proc_i8k->proc_fops = &i8k_fops;
proc_i8k->owner = THIS_MODULE;

+ err = driver_register(&i8k_driver);
+ if (err)
+ goto fail1;
+
+ i8k_device = platform_device_register_simple("i8k", -1, NULL, 0);
+ if (IS_ERR(i8k_device)) {
+ err = PTR_ERR(i8k_device);
+ goto fail2;
+ }
+
+ for (i = 0; attr_name(i8k_device_attrs[i]); i++) {
+ err = device_create_file(&i8k_device->dev, &i8k_device_attrs[i]);
+ if (err)
+ goto fail3;
+ }
+
printk(KERN_INFO
"Dell laptop SMM driver v%s Massimo Dal Zotto ([email protected])\n",
I8K_VERSION);

return 0;
+
+fail3: while (--i >= 0)
+ device_remove_file(&i8k_device->dev, &i8k_device_attrs[i]);
+ platform_device_unregister(i8k_device);
+fail2: driver_unregister(&i8k_driver);
+fail1: remove_proc_entry("i8k", NULL);
+ return err;
}

static void __exit i8k_exit(void)
{
+ platform_device_unregister(i8k_device);
+ driver_unregister(&i8k_driver);
remove_proc_entry("i8k", NULL);
}

2005-03-13 03:41:44

by Frank Sorenson

[permalink] [raw]
Subject: Re: [PATCH 0/5] I8K driver facelift

-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA1

Dmitry Torokhov wrote:
| Hi,
|
| here are some changes that freshen I8K driver (Dell Inspiron/Latitude
| platform driver). The patches have been tested on Inspiron 8100.
<snip>
| Please consider for inclusion.
|
| Thanks!

These patches look pretty good. A few comments (with a patch--tested on
my Inspiron 9200):

- - The "return i8k_smm(&regs) < 0 ? : regs.eax;" construction is nice and
tidy, but it isn't passing on the return value of the called function,
and is returning TRUE or 1 on failure. This makes it difficult to check
the return value for valid data. Old behavior returned negative, so
I'll return -1.

- - The I8K_VERSION string should probably be changed to something more
unique. The version maintained outside the kernel tree by Massimo Dal
Zotto (http://www.debian.org/~dz/i8k/) is up to 1.25, so 1.14 isn't very
distinguishing. Maybe just use the date? Not sure here...

- - Also, some newer Dell laptops require a different function to get the
Dell signature, so the i8k_get_dell_signature test should check both
(borrowing some code from the out-of-kernel version).

- - Some newer Dell laptops report DMI_SYS_VENDOR as "Dell Inc." rather
than "Dell Computer"

- - Some of the Dell motherboards provide more than 1 temperature sensor.
~ How about a generic i8k_get_temp function, and i8k_get_cpu_temp just
calls that with sensor 0.

- - Also, I've added detection of the number of temperature sensors and
fans at init time. This way, we aren't hardcoded to 1 sensor and 2
fans. I couldn't figure out how to set up the sysfs entries
dynamically, but that probably should happen too.

- - Some boards don't need the I8K_FAN_MULT to get the right fan RPM (I
don't think my fans are rotating at over 90,000 RPM)! I guess we'll
need to address this sometime, but I have not done so.

Patch follows:

Signed-off-by: Frank Sorenson <[email protected]>

- --- 2.6.11-a/drivers/char/i8k.c 2005-03-12 18:47:55.000000000 -0700
+++ 2.6.11-b/drivers/char/i8k.c 2005-03-12 20:29:01.000000000 -0700
@@ -28,7 +28,7 @@

~ #include <linux/i8k.h>

- -#define I8K_VERSION "1.14 21/02/2005"
+#define I8K_VERSION "2005-03-12"

~ #define I8K_SMM_FN_STATUS 0x0025
~ #define I8K_SMM_POWER_STATUS 0x0069
@@ -36,7 +36,8 @@
~ #define I8K_SMM_GET_FAN 0x00a3
~ #define I8K_SMM_GET_SPEED 0x02a3
~ #define I8K_SMM_GET_TEMP 0x10a3
- -#define I8K_SMM_GET_DELL_SIG 0xffa3
+#define I8K_SMM_GET_DELL_SIG1 0xfea3
+#define I8K_SMM_GET_DELL_SIG2 0xffa3
~ #define I8K_SMM_BIOS_VERSION 0x00a6

~ #define I8K_FAN_MULT 30
@@ -55,6 +56,8 @@
~ #define I8K_TEMPERATURE_BUG 1

~ static char bios_version[4];
+static int num_temps = 0;
+static int num_fans = 0;

~ MODULE_AUTHOR("Massimo Dal Zotto ([email protected])");
~ MODULE_DESCRIPTION("Driver for accessing SMM BIOS on Dell laptops");
@@ -201,10 +204,10 @@
~ */
~ static int i8k_get_fan_status(int fan)
~ {
- - struct smm_regs regs = { .eax = I8K_SMM_GET_FAN, };
+ struct smm_regs regs = { .eax = I8K_SMM_GET_FAN, .ebx = (fan & 0xff)};

~ regs.ebx = fan & 0xff;
- - return i8k_smm(&regs) < 0 ? : regs.eax & 0xff;
+ return i8k_smm(&regs) < 0 ? -1 : regs.eax & 0xff;
~ }

~ /*
@@ -215,7 +218,7 @@
~ struct smm_regs regs = { .eax = I8K_SMM_GET_SPEED, };

~ regs.ebx = fan & 0xff;
- - return i8k_smm(&regs) < 0 ? : (regs.eax & 0xffff) * I8K_FAN_MULT;
+ return i8k_smm(&regs) < 0 ? -1 : (regs.eax & 0xffff) * I8K_FAN_MULT;
~ }

~ /*
@@ -228,15 +231,15 @@
~ speed = (speed < 0) ? 0 : ((speed > I8K_FAN_MAX) ? I8K_FAN_MAX : speed);
~ regs.ebx = (fan & 0xff) | (speed << 8);

- - return i8k_smm(&regs) < 0 ? : i8k_get_fan_status(fan);
+ return i8k_smm(&regs) < 0 ? -1 : i8k_get_fan_status(fan);
~ }

~ /*
~ * Read the cpu temperature.
~ */
- -static int i8k_get_cpu_temp(void)
+static int i8k_get_temp(int sensor)
~ {
- - struct smm_regs regs = { .eax = I8K_SMM_GET_TEMP, };
+ struct smm_regs regs = { .eax = I8K_SMM_GET_TEMP, .ebx = sensor };
~ int rc;
~ int temp;

@@ -268,9 +271,14 @@
~ return temp;
~ }

- -static int i8k_get_dell_signature(void)
+static int i8k_get_cpu_temp(void)
+{
+ return i8k_get_temp(0);
+}
+
+static int i8k_get_dell_sig_aux(int fn)
~ {
- - struct smm_regs regs = { .eax = I8K_SMM_GET_DELL_SIG, };
+ struct smm_regs regs = { .eax = fn, };
~ int rc;

~ if ((rc = i8k_smm(&regs)) < 0)
@@ -279,6 +287,17 @@
~ return regs.eax == 1145651527 && regs.edx == 1145392204 ? 0 : -1;
~ }

+static int i8k_get_dell_signature(void)
+{
+ int rc;
+
+ if (((rc=i8k_get_dell_sig_aux(I8K_SMM_GET_DELL_SIG1)) < 0) &&
+ ((rc=i8k_get_dell_sig_aux(I8K_SMM_GET_DELL_SIG2)) < 0)) {
+ return rc;
+ }
+ return 0;
+}
+
~ static int i8k_ioctl(struct inode *ip, struct file *fp, unsigned int cmd,
~ unsigned long arg)
~ {
@@ -506,6 +525,13 @@
~ },
~ },
~ {
+ .ident = "Dell Inspiron",
+ .matches = {
+ DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."),
+ DMI_MATCH(DMI_PRODUCT_NAME, "Inspiron"),
+ },
+ },
+ {
~ .ident = "Dell Latitude",
~ .matches = {
~ DMI_MATCH(DMI_SYS_VENDOR, "Dell Computer"),
@@ -587,6 +613,11 @@
~ if (i8k_probe())
~ return -ENODEV;

+ while (i8k_get_temp(num_temps) >= 0) num_temps ++;
+ printk(KERN_INFO "i8k: found %d temperature sensors\n", num_temps);
+ while (i8k_get_fan_status(num_fans) >= 0) num_fans ++;
+ printk(KERN_INFO "i8k: found %d fans\n", num_fans);
+
~ /* Register the proc entry */
~ proc_i8k = create_proc_entry("i8k", 0, NULL);
~ if (!proc_i8k)



Frank
- --
Frank Sorenson - KD7TZK
Systems Manager, Computer Science Department
Brigham Young University
[email protected]
-----BEGIN PGP SIGNATURE-----
Version: GnuPG v1.2.6 (GNU/Linux)
Comment: Using GnuPG with Thunderbird - http://enigmail.mozdev.org

iD8DBQFCM7ZZaI0dwg4A47wRAok1AKDLYIrMXLphYAeAq98OXYqxk6U1vACfQpld
qczdJm2992BjeQ/iU9RP+k4=
=nNut
-----END PGP SIGNATURE-----

2005-03-13 04:20:22

by Dmitry Torokhov

[permalink] [raw]
Subject: Re: [PATCH 0/5] I8K driver facelift

On Saturday 12 March 2005 22:41, Frank Sorenson wrote:
> Dmitry Torokhov wrote:
> | Hi,
> |
> | here are some changes that freshen I8K driver (Dell Inspiron/Latitude
> | platform driver). The patches have been tested on Inspiron 8100.
> <snip>
> | Please consider for inclusion.
> |
> | Thanks!
>
> These patches look pretty good. ?A few comments (with a patch--tested on
> my Inspiron 9200):
>
> - The "return i8k_smm(&regs) < 0 ? : regs.eax;" construction is nice and
> tidy, but it isn't passing on the return value of the called function,
> and is returning TRUE or 1 on failure. ?This makes it difficult to check
> the return value for valid data. ?Old behavior returned negative, so
> I'll return -1.

Hi,

Actually I am not sure what I was thinkinhg when I wrtote it, the correct
version should be "return i8k_smm(&regs) ? : regs.eax;" since i8k_smm
return 0 on success.

I will think about dynamically adding attributes...

--
Dmitry

2005-03-15 08:12:49

by Valdis Klētnieks

[permalink] [raw]
Subject: Re: [PATCH 0/5] I8K driver facelift

On Sat, 12 Mar 2005 20:41:14 MST, Frank Sorenson said:

> These patches look pretty good. A few comments (with a patch--tested on
> my Inspiron 9200):

I tested your patch on top of Dmitry's on a Dell Latitude C840, seems to work.

> - - Some of the Dell motherboards provide more than 1 temperature sensor.
> ~ How about a generic i8k_get_temp function, and i8k_get_cpu_temp just
> calls that with sensor 0.
>
> - - Also, I've added detection of the number of temperature sensors and
> fans at init time. This way, we aren't hardcoded to 1 sensor and 2
> fans. I couldn't figure out how to set up the sysfs entries
> dynamically, but that probably should happen too.

According to your patch, the C840 has 2 temp sensors. I'll have to figure
out what the second one is (prob either the GPU or the disk drive?)


Attachments:
(No filename) (226.00 B)

2005-03-15 11:00:53

by Giuseppe Bilotta

[permalink] [raw]
Subject: Re: [PATCH 0/5] I8K driver facelift

> According to your patch, the C840 has 2 temp sensors. I'll have to figure
> out what the second one is (prob either the GPU or the disk drive?)

If it runs over 40 C easily it's probably the GPU :)

--
Giuseppe "Oblomov" Bilotta

Can't you see
It all makes perfect sense
Expressed in dollar and cents
Pounds shillings and pence
(Roger Waters)

2005-03-15 17:33:07

by Valdis Klētnieks

[permalink] [raw]
Subject: Re: [PATCH 0/5] I8K driver facelift

On Tue, 15 Mar 2005 11:59:22 +0100, Giuseppe Bilotta said:
> > According to your patch, the C840 has 2 temp sensors. I'll have to figure
> > out what the second one is (prob either the GPU or the disk drive?)
>
> If it runs over 40 C easily it's probably the GPU :)

Well, (a) the next rev of the patch will hopefully provide more access to the
second thermal probe than just detecting its existence (it still doesn't do
the sysfs or whatever magic to make the actual value accessible), and (b) the
probe I *know* about is on the CPU, and runs over 40C easily as well (it's sitting
at 49C right now). Remember we're talking about a laptop here, there's not
a lot of room for a big heat sink in there.. ;)


Attachments:
(No filename) (226.00 B)

2005-03-15 22:36:42

by Frank Sorenson

[permalink] [raw]
Subject: Re: [PATCH 0/5] I8K driver facelift

-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA1

[email protected] wrote:
> Well, (a) the next rev of the patch will hopefully provide more access to the
> second thermal probe than just detecting its existence (it still doesn't do
> the sysfs or whatever magic to make the actual value accessible), and (b) the
> probe I *know* about is on the CPU, and runs over 40C easily as well (it's sitting
> at 49C right now). Remember we're talking about a laptop here, there's not
> a lot of room for a big heat sink in there.. ;)

I've been trying to work out how to do this through dynamic sysfs
attributes, but I have not found a way to create arbitrary attributes
like this. It's not hard to define them at kernel compile time, but
selecting the right number of sensors to compile in seems arbitrary. My
Inspiron 9200 has 4 sensors, and who knows how many next year's model
will have. It just doesn't seem like the Linux Kernel way of doing
things to arbitrarily limit it like this.

I've looked into several ways of creating sysfs attributes, but haven't
found anything that works right/well. One of the most interesting was
in this past LKML thread - http://lkml.org/lkml/2004/8/20/287 If I
could replace the sysfs_attr_show() with my own, I believe that might
work (the attribute is passed into the function, so the name should be
available).

It's odd that it's so easy to compile sysfs attributes into the kernel,
but nobody seems to know how to generate them dynamically.

Thoughts? Suggestions?

Thanks,
Frank
- --
Frank Sorenson - KD7TZK
Systems Manager, Computer Science Department
Brigham Young University
[email protected]
-----BEGIN PGP SIGNATURE-----
Version: GnuPG v1.2.6 (GNU/Linux)
Comment: Using GnuPG with Thunderbird - http://enigmail.mozdev.org

iD8DBQFCN2LeaI0dwg4A47wRAhWEAKC+CcoLmoyvS6RXy7n7gtTnKjPXsACgtCbE
zofgMMEmc5mAzrQKdKwpIMQ=
=xNOU
-----END PGP SIGNATURE-----

2005-03-16 21:49:44

by Frank Sorenson

[permalink] [raw]
Subject: Re: [PATCH 0/5] I8K driver facelift

Okay, I replaced the sysfs_ops with ops of my own, and now all the show
and store functions also accept the name of the attribute as a parameter.
This lets the functions know what attribute is being accessed, and allows
us to create attributes that share show and store functions, so things
don't need to be defined at compile time (I feel slightly evil!).

This patch puts the correct number of temp sensors and fans into sysfs,
and only exposes power_status if enabled by the power_status module
parameter.

This patch applies on top of Dmitry Torokov's patches. Comments welcome!

Thanks,
Frank

Signed-off-by: Frank Sorenson <[email protected]>

--- 2.6.11-a/drivers/char/i8k.c 2005-03-12 18:47:55.000000000 -0700
+++ 2.6.11-b/drivers/char/i8k.c 2005-03-16 14:23:40.000000000 -0700
@@ -23,12 +23,14 @@
#include <linux/seq_file.h>
#include <linux/dmi.h>
#include <linux/device.h>
+#include <linux/sysfs.h>
+#include <linux/kobject.h>
#include <asm/uaccess.h>
#include <asm/io.h>

#include <linux/i8k.h>

-#define I8K_VERSION "1.14 21/02/2005"
+#define I8K_VERSION "2005-03-16"

#define I8K_SMM_FN_STATUS 0x0025
#define I8K_SMM_POWER_STATUS 0x0069
@@ -36,7 +38,8 @@
#define I8K_SMM_GET_FAN 0x00a3
#define I8K_SMM_GET_SPEED 0x02a3
#define I8K_SMM_GET_TEMP 0x10a3
-#define I8K_SMM_GET_DELL_SIG 0xffa3
+#define I8K_SMM_GET_DELL_SIG1 0xfea3
+#define I8K_SMM_GET_DELL_SIG2 0xffa3
#define I8K_SMM_BIOS_VERSION 0x00a6

#define I8K_FAN_MULT 30
@@ -54,7 +57,12 @@

#define I8K_TEMPERATURE_BUG 1

+#define to_dev(d) container_of(d, struct device, kobj)
+#define to_dev_attr(_attr) container_of(_attr,struct device_attribute,attr)
+
static char bios_version[4];
+static int num_temps = 0;
+static int num_fans = 0;

MODULE_AUTHOR("Massimo Dal Zotto ([email protected])");
MODULE_DESCRIPTION("Driver for accessing SMM BIOS on Dell laptops");
@@ -80,6 +88,8 @@
static int i8k_ioctl(struct inode *, struct file *, unsigned int,
unsigned long);

+static struct kobj_type *backup_ktype;
+
static struct file_operations i8k_fops = {
.open = i8k_open_fs,
.read = seq_read,
@@ -94,7 +104,7 @@
};

static struct platform_device *i8k_device;
-
+
struct smm_regs {
unsigned int eax;
unsigned int ebx __attribute__ ((packed));
@@ -156,7 +166,7 @@
{
struct smm_regs regs = { .eax = I8K_SMM_BIOS_VERSION, };

- return i8k_smm(&regs) < 0 ? : regs.eax;
+ return i8k_smm(&regs) ? : regs.eax;
}

/*
@@ -201,10 +211,10 @@
*/
static int i8k_get_fan_status(int fan)
{
- struct smm_regs regs = { .eax = I8K_SMM_GET_FAN, };
+ struct smm_regs regs = { .eax = I8K_SMM_GET_FAN, .ebx = (fan & 0xff)};

regs.ebx = fan & 0xff;
- return i8k_smm(&regs) < 0 ? : regs.eax & 0xff;
+ return i8k_smm(&regs) ? : regs.eax & 0xff;
}

/*
@@ -215,7 +225,7 @@
struct smm_regs regs = { .eax = I8K_SMM_GET_SPEED, };

regs.ebx = fan & 0xff;
- return i8k_smm(&regs) < 0 ? : (regs.eax & 0xffff) * I8K_FAN_MULT;
+ return i8k_smm(&regs) ? : (regs.eax & 0xffff) * I8K_FAN_MULT;
}

/*
@@ -228,15 +238,15 @@
speed = (speed < 0) ? 0 : ((speed > I8K_FAN_MAX) ? I8K_FAN_MAX : speed);
regs.ebx = (fan & 0xff) | (speed << 8);

- return i8k_smm(&regs) < 0 ? : i8k_get_fan_status(fan);
+ return i8k_smm(&regs) ? : i8k_get_fan_status(fan);
}

/*
* Read the cpu temperature.
*/
-static int i8k_get_cpu_temp(void)
+static int i8k_get_temp(int sensor)
{
- struct smm_regs regs = { .eax = I8K_SMM_GET_TEMP, };
+ struct smm_regs regs = { .eax = I8K_SMM_GET_TEMP, .ebx = sensor };
int rc;
int temp;

@@ -268,9 +278,14 @@
return temp;
}

-static int i8k_get_dell_signature(void)
+static int i8k_get_cpu_temp(void)
{
- struct smm_regs regs = { .eax = I8K_SMM_GET_DELL_SIG, };
+ return i8k_get_temp(0);
+}
+
+static int i8k_get_dell_sig_aux(int fn)
+{
+ struct smm_regs regs = { .eax = fn, };
int rc;

if ((rc = i8k_smm(&regs)) < 0)
@@ -279,6 +294,17 @@
return regs.eax == 1145651527 && regs.edx == 1145392204 ? 0 : -1;
}

+static int i8k_get_dell_signature(void)
+{
+ int rc;
+
+ if (((rc=i8k_get_dell_sig_aux(I8K_SMM_GET_DELL_SIG1)) < 0) &&
+ ((rc=i8k_get_dell_sig_aux(I8K_SMM_GET_DELL_SIG2)) < 0)) {
+ return rc;
+ }
+ return 0;
+}
+
static int i8k_ioctl(struct inode *ip, struct file *fp, unsigned int cmd,
unsigned long arg)
{
@@ -414,87 +440,112 @@
return single_open(file, i8k_proc_show, NULL);
}

-static ssize_t i8k_sysfs_cpu_temp_show(struct device *dev, char *buf)
+static ssize_t i8k_sysfs_cpu_temp_show(struct device *dev, char *buf,
+ const char *name)
{
int temp = i8k_get_cpu_temp();

return temp < 0 ? -EIO : sprintf(buf, "%d\n", temp);
}

-static ssize_t i8k_sysfs_fan1_show(struct device *dev, char *buf)
+static ssize_t i8k_sysfs_temp_show(struct device *dev, char *buf,
+ const char *name)
{
- int status = i8k_get_fan_status(0);
- return status < 0 ? -EIO : sprintf(buf, "%d\n", status);
-}
-
-static ssize_t i8k_sysfs_fan1_set(struct device *dev, const char *buf, size_t count)
-{
- unsigned long state;
+ unsigned long temp_num;
+ int temp;
char *rest;

- if (restricted && !capable(CAP_SYS_ADMIN))
- return -EPERM;
-
- state = simple_strtoul(buf, &rest, 10);
- if (*rest || state > I8K_FAN_MAX)
- return -EINVAL;
+ temp_num = simple_strtoul(name + 4, &rest, 10);
+ temp = i8k_get_temp(temp_num - 1);

- if (i8k_set_fan(0, state) < 0)
- return -EIO;
-
- return count;
+ return temp < 0 ? -EIO : sprintf(buf, "%d\n", temp);
}

-static ssize_t i8k_sysfs_fan2_show(struct device *dev, char *buf)
+static ssize_t i8k_sysfs_fan_show(struct device *dev, char *buf,
+ const char *name)
{
- int status = i8k_get_fan_status(1);
+ unsigned long fan_num;
+ int status;
+ char *rest;
+
+ fan_num = simple_strtoul(name + 3, &rest, 10);
+ status = i8k_get_fan_status(fan_num - 1);
return status < 0 ? -EIO : sprintf(buf, "%d\n", status);
}

-static ssize_t i8k_sysfs_fan2_set(struct device *dev, const char *buf, size_t count)
+static ssize_t i8k_sysfs_fan_set(struct device *dev, const char *buf,
+ size_t count, const char *name)
{
+ unsigned long fan_num;
unsigned long state;
char *rest;

if (restricted && !capable(CAP_SYS_ADMIN))
return -EPERM;

+ fan_num = simple_strtoul(name + 3, &rest, 10);
+
state = simple_strtoul(buf, &rest, 10);
if (*rest || state > I8K_FAN_MAX)
return -EINVAL;

- if (i8k_set_fan(1, state) < 0)
+ if (i8k_set_fan(fan_num - 1, state) < 0)
return -EIO;

return count;
}

-static ssize_t i8k_sysfs_fan1_speed_show(struct device *dev, char *buf)
+static ssize_t i8k_sysfs_fan_speed_show(struct device *dev, char *buf,
+ const char *name)
{
- int speed = i8k_get_fan_speed(0);
- return speed < 0 ? -EIO : sprintf(buf, "%d\n", speed);
-}
+ unsigned long fan_num;
+ char *rest;
+ int speed;

-static ssize_t i8k_sysfs_fan2_speed_show(struct device *dev, char *buf)
-{
- int speed = i8k_get_fan_speed(1);
+ fan_num = simple_strtoul(name + 3, &rest, 10);
+ speed = i8k_get_fan_speed(fan_num - 1);
return speed < 0 ? -EIO : sprintf(buf, "%d\n", speed);
}

-static ssize_t i8k_sysfs_power_status_show(struct device *dev, char *buf)
+static ssize_t i8k_sysfs_power_status_show(struct device *dev, char *buf,
+ char *name)
{
int status = power_status ? i8k_get_power_status() : -1;
return status < 0 ? -EIO : sprintf(buf, "%d\n", status);
}

-static struct device_attribute i8k_device_attrs[] = {
- __ATTR(cpu_temp, 0444, i8k_sysfs_cpu_temp_show, NULL),
- __ATTR(fan1_state, 0644, i8k_sysfs_fan1_show, i8k_sysfs_fan1_set),
- __ATTR(fan2_state, 0644, i8k_sysfs_fan2_show, i8k_sysfs_fan2_set),
- __ATTR(fan1_speed, 0444, i8k_sysfs_fan1_speed_show, NULL),
- __ATTR(fan2_speed, 0444, i8k_sysfs_fan2_speed_show, NULL),
- __ATTR(power_status, 0444, i8k_sysfs_power_status_show, NULL),
- __ATTR_NULL
+static ssize_t i8k_sysfs_show(struct kobject *kobj, struct attribute *attr,
+ char * buf)
+{
+ struct device_attribute * dev_attr = to_dev_attr(attr);
+ struct device * dev = to_dev(kobj);
+ int (*func3)(struct device *, char *, char *);
+
+ if (dev_attr->show) {
+ func3 = dev_attr->show;
+ return (*func3)(dev, buf, dev_attr->attr.name);
+ }
+ return -EINVAL;
+}
+
+static ssize_t i8k_sysfs_store(struct kobject *kobj, struct attribute *attr,
+ const char *buf, size_t count)
+{
+ struct device_attribute * dev_attr = to_dev_attr(attr);
+ struct device * dev = to_dev(kobj);
+ int (*func4)(struct device *, const char *, size_t, char *);
+
+ if (dev_attr->store)
+ {
+ func4 = dev_attr->store;
+ return (*func4)(dev, buf, count, dev_attr->attr.name);
+ }
+ return -EINVAL;
+}
+
+static struct sysfs_ops i8k_sysfs_ops = {
+ .show = i8k_sysfs_show,
+ .store = i8k_sysfs_store,
};

static struct dmi_system_id __initdata i8k_dmi_table[] = {
@@ -506,6 +557,13 @@
},
},
{
+ .ident = "Dell Inspiron",
+ .matches = {
+ DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."),
+ DMI_MATCH(DMI_PRODUCT_NAME, "Inspiron"),
+ },
+ },
+ {
.ident = "Dell Latitude",
.matches = {
DMI_MATCH(DMI_SYS_VENDOR, "Dell Computer"),
@@ -578,6 +636,105 @@
return 0;
}

+static int sysfs_add_generic(char *dev_name, int mode, void *show, void *store)
+{
+ char *name;
+ struct device_attribute *attr;
+ int err;
+
+ name = kmalloc(strlen(dev_name) + 1, GFP_KERNEL);
+ if (name == NULL)
+ return -ENOMEM;
+ strncpy(name, dev_name, strlen(dev_name));
+ name[strlen(dev_name)] = '\0';
+ attr = kmalloc(sizeof *attr, GFP_KERNEL);
+ if (attr == NULL)
+ return -ENOMEM;
+ *attr = ((struct device_attribute) {
+ .attr = {
+ .name = name,
+ .mode = mode,
+ },
+ .show = show,
+ .store = store,
+ });
+ err = device_create_file(&i8k_device->dev, attr);
+ if (err)
+ {
+ device_remove_file(&i8k_device->dev, attr);
+ kfree(attr);
+ kfree(name);
+ return -1;
+ }
+ return 0;
+}
+
+static int sysfs_add_temp(int temp_num)
+{
+ char temp_name[30];
+
+ sprintf(temp_name, "temp%d", temp_num + 1);
+ return sysfs_add_generic(temp_name, 0444, i8k_sysfs_temp_show, NULL);
+}
+
+static int sysfs_add_fan(int fan_num)
+{
+ char fan_state_name[30];
+ char fan_speed_name[30];
+
+ sprintf(fan_state_name, "fan%d_state", fan_num + 1);
+ sprintf(fan_speed_name, "fan%d_speed", fan_num + 1);
+
+ sysfs_add_generic(fan_state_name, 0644,
+ i8k_sysfs_fan_show, i8k_sysfs_fan_set);
+ sysfs_add_generic(fan_speed_name, 0444,
+ i8k_sysfs_fan_speed_show, NULL);
+ return 0;
+}
+
+static int i8k_redirect_sysfs_ops(void)
+{
+ struct device *dev;
+ struct kobject *kobj;
+ struct kobj_type *ktype;
+ struct kobj_type *temp_ktype;
+ struct kset *kset;
+
+ dev = &i8k_device->dev;
+ kobj = &dev->kobj;
+ kset = kobj->kset;
+ ktype = kset->ktype;
+
+ temp_ktype = kmalloc(sizeof *temp_ktype, GFP_KERNEL);
+
+ temp_ktype->release = ktype->release;
+ temp_ktype->sysfs_ops = &i8k_sysfs_ops;
+ temp_ktype->default_attrs = ktype->default_attrs;
+
+ backup_ktype = ktype;
+ kset->ktype = temp_ktype;
+
+ return 0;
+}
+
+static int i8k_restore_sysfs_ops(void)
+{
+ struct device *dev;
+ struct kobject *kobj;
+ struct kset *kset;
+ struct kobj_type *temp_ktype;
+
+ dev = &i8k_device->dev;
+ kobj = &dev->kobj;
+ kset = kobj->kset;
+ temp_ktype = kset->ktype;
+
+ kset->ktype = backup_ktype;
+ kfree(temp_ktype);
+
+ return 0;
+}
+
static int __init i8k_init(void)
{
struct proc_dir_entry *proc_i8k;
@@ -587,6 +744,11 @@
if (i8k_probe())
return -ENODEV;

+ while (i8k_get_temp(num_temps) >= 0) num_temps ++;
+ printk(KERN_INFO "i8k: found %d temperature sensors\n", num_temps);
+ while (i8k_get_fan_status(num_fans) >= 0) num_fans ++;
+ printk(KERN_INFO "i8k: found %d fans\n", num_fans);
+
/* Register the proc entry */
proc_i8k = create_proc_entry("i8k", 0, NULL);
if (!proc_i8k)
@@ -605,21 +767,31 @@
goto fail2;
}

- for (i = 0; attr_name(i8k_device_attrs[i]); i++) {
- err = device_create_file(&i8k_device->dev, &i8k_device_attrs[i]);
+ i8k_redirect_sysfs_ops();
+
+ /* register the temp sensors */
+ for (i = 0; i < num_temps; i++) {
+ err = sysfs_add_temp(i);
+ if (err)
+ goto fail2;
+ }
+
+ /* register the fans */
+ for (i = 0; i < num_fans; i++) {
+ err = sysfs_add_fan(i);
if (err)
- goto fail3;
+ goto fail2;
}
+ sysfs_add_generic("cpu_temp", 0444, i8k_sysfs_cpu_temp_show, NULL);
+ if (power_status)
+ sysfs_add_generic("power_status", 0444,
+ i8k_sysfs_power_status_show, NULL);

printk(KERN_INFO
"Dell laptop SMM driver v%s Massimo Dal Zotto ([email protected])\n",
I8K_VERSION);

return 0;
-
-fail3: while (--i >= 0)
- device_remove_file(&i8k_device->dev, &i8k_device_attrs[i]);
- platform_device_unregister(i8k_device);
fail2: driver_unregister(&i8k_driver);
fail1: remove_proc_entry("i8k", NULL);
return err;
@@ -627,6 +799,7 @@

static void __exit i8k_exit(void)
{
+ i8k_restore_sysfs_ops();
platform_device_unregister(i8k_device);
driver_unregister(&i8k_driver);
remove_proc_entry("i8k", NULL);

2005-03-17 06:43:21

by Dmitry Torokhov

[permalink] [raw]
Subject: Re: [PATCH 0/5] I8K driver facelift

On Wednesday 16 March 2005 16:38, Frank Sorenson wrote:
> Okay, I replaced the sysfs_ops with ops of my own, and now all the show
> and store functions also accept the name of the attribute as a parameter.
> This lets the functions know what attribute is being accessed, and allows
> us to create attributes that share show and store functions, so things
> don't need to be defined at compile time (I feel slightly evil!).

Hrm, can we be a little more explicit and not poke in the sysfs guts right
in the driver? What do you think about the patch below athat implements
"attribute arrays"? And I am attaching cumulative i8k patch using these
arrays so they can be tested.

I am CC-ing Greg to see what he thinks about it.

--
Dmitry

===================================================================

sysfs: add support for attribure arrays so it is possible to create
a (variable) number of similar attributes all sharing the
same show and store handlers:

../<attr_name>/0
../<attr_name>/1
...
../<attr_name>/<n>

Signed-off-by: Dmitry Torokhov <[email protected]>

fs/sysfs/Makefile | 2
fs/sysfs/array.c | 167 ++++++++++++++++++++++++++++++++++++++++++++++++++
include/linux/sysfs.h | 20 +++++
3 files changed, 187 insertions(+), 2 deletions(-)

Index: dtor/fs/sysfs/array.c
===================================================================
--- /dev/null
+++ dtor/fs/sysfs/array.c
@@ -0,0 +1,167 @@
+/*
+ * fs/sysfs/array.c - Operations for adding/removing arrays of attributes.
+ *
+ * Copyright (c) 2005 Dmitry Torokhov <[email protected]>
+ *
+ * This file is released under the GPL v2.
+ *
+ */
+
+#include <linux/kobject.h>
+#include <linux/module.h>
+#include <linux/dcache.h>
+#include <linux/err.h>
+#include "sysfs.h"
+
+struct attr_element {
+ struct attribute attr;
+ unsigned int idx;
+ char name[4];
+};
+#define to_attr_element(e) container_of(e, struct attr_element, attr)
+
+struct array_object {
+ const struct attribute_array *array;
+ unsigned int n_elements;
+ struct kobject kobj;
+ struct attr_element elements[0];
+};
+#define to_array_object(obj) container_of(obj, struct array_object, kobj)
+
+static ssize_t
+attr_array_show(struct kobject *kobj, struct attribute *attr, char *buf)
+{
+ struct attr_element *element = to_attr_element(attr);
+ struct array_object *obj = to_array_object(kobj);
+ ssize_t ret = 0;
+
+ if (obj->array->show) {
+ struct kobject *parent = kobject_get(kobj->parent);
+ ret = obj->array->show(parent, element->idx, buf);
+ kobject_put(parent);
+ }
+
+ return ret;
+}
+
+static ssize_t
+attr_array_store(struct kobject *kobj, struct attribute *attr,
+ const char *buf, size_t count)
+{
+ struct attr_element *element = to_attr_element(attr);
+ struct array_object *obj = to_array_object(kobj);
+ ssize_t ret = 0;
+
+ if (obj->array->store) {
+ struct kobject *parent = kobject_get(kobj->parent);
+ ret = obj->array->store(parent, element->idx, buf, count);
+ kobject_put(parent);
+ }
+
+ return ret;
+}
+
+static struct sysfs_ops attr_array_sysfs_ops = {
+ .show = attr_array_show,
+ .store = attr_array_store,
+};
+
+
+static void attr_array_release(struct kobject *kobj)
+{
+ kfree(to_array_object(kobj));
+}
+
+static struct kobj_type ktype_attr_array = {
+ .release = attr_array_release,
+ .sysfs_ops = &attr_array_sysfs_ops,
+};
+
+
+static int create_array_element(struct array_object *obj,
+ unsigned int idx)
+{
+ struct attr_element *element = &obj->elements[idx];
+
+ snprintf(element->name, sizeof(element->name), "%d", idx);
+ element->idx = idx;
+ element->attr = obj->array->attr;
+ element->attr.name = element->name;
+
+ return sysfs_create_file(&obj->kobj, &element->attr);
+}
+
+static inline void remove_array_element(struct array_object *obj,
+ unsigned int idx)
+{
+ sysfs_remove_file(&obj->kobj, &obj->elements[idx].attr);
+}
+
+int sysfs_create_array(struct kobject *kobj,
+ const struct attribute_array *array,
+ unsigned int n_elements)
+{
+ struct array_object *obj;
+ size_t size;
+ unsigned int i;
+ int error;
+
+ BUG_ON(!kobj || !kobj->dentry);
+ BUG_ON(!array->attr.name);
+
+ size = sizeof(struct array_object) +
+ sizeof(struct attr_element) * n_elements;
+
+ obj = kmalloc(size, GFP_KERNEL);
+ if (!obj)
+ return -ENOMEM;
+
+ memset(obj, 0, size);
+ obj->array = array;
+ obj->n_elements = n_elements;
+
+ obj->kobj.ktype = &ktype_attr_array;
+ obj->kobj.parent = kobj;
+ kobject_set_name(&obj->kobj, array->attr.name);
+
+ error = kobject_register(&obj->kobj);
+ if (error)
+ goto fail;
+
+ for (i = 0; i < n_elements; i++) {
+ error = create_array_element(obj, i);
+ if (error) {
+ while (--i)
+ remove_array_element(obj, i);
+ goto fail;
+ }
+ }
+
+ return 0;
+
+ fail:
+ kfree(obj);
+ return error;
+}
+
+void sysfs_remove_array(struct kobject *kobj,
+ const struct attribute_array *array)
+{
+ struct array_object *obj;
+ struct dentry *dir;
+ unsigned int i;
+
+ dir = sysfs_get_dentry(kobj->dentry, array->attr.name);
+
+ if (dir) {
+ obj = to_array_object(to_kobj(dir));
+ for (i = 0; i < obj->n_elements; i++)
+ remove_array_element(obj, i);
+ kobject_unregister(&obj->kobj);
+ }
+
+ dput(dir);
+}
+
+EXPORT_SYMBOL_GPL(sysfs_create_array);
+EXPORT_SYMBOL_GPL(sysfs_remove_array);
Index: dtor/include/linux/sysfs.h
===================================================================
--- dtor.orig/include/linux/sysfs.h
+++ dtor/include/linux/sysfs.h
@@ -26,7 +26,12 @@ struct attribute_group {
struct attribute ** attrs;
};

+struct attribute_array {
+ struct attribute attr;

+ ssize_t (*show)(struct kobject *, unsigned int index, char *);
+ ssize_t (*store)(struct kobject *, unsigned int index, const char *, size_t);
+};

/**
* Use these macros to make defining attributes easier. See include/linux/device.h
@@ -102,7 +107,7 @@ sysfs_update_file(struct kobject *, cons
extern void
sysfs_remove_file(struct kobject *, const struct attribute *);

-extern int
+extern int
sysfs_create_link(struct kobject * kobj, struct kobject * target, char * name);

extern void
@@ -114,6 +119,9 @@ int sysfs_remove_bin_file(struct kobject
int sysfs_create_group(struct kobject *, const struct attribute_group *);
void sysfs_remove_group(struct kobject *, const struct attribute_group *);

+int sysfs_create_array(struct kobject *, const struct attribute_array *, unsigned int);
+void sysfs_remove_array(struct kobject *, const struct attribute_array *);
+
#else /* CONFIG_SYSFS */

static inline int sysfs_create_dir(struct kobject * k)
@@ -177,6 +185,16 @@ static inline void sysfs_remove_group(st
;
}

+static inline int sysfs_create_array(struct kobject * k, const struct attribute_array *a, unsigned int n)
+{
+ return 0;
+}
+
+static inline void sysfs_remove_array(struct kobject * k, const struct attribute_array * a)
+{
+ ;
+}
+
#endif /* CONFIG_SYSFS */

#endif /* _SYSFS_H_ */
Index: dtor/fs/sysfs/Makefile
===================================================================
--- dtor.orig/fs/sysfs/Makefile
+++ dtor/fs/sysfs/Makefile
@@ -3,4 +3,4 @@
#

obj-y := inode.o file.o dir.o symlink.o mount.o bin.o \
- group.o
+ group.o array.o


Attachments:
(No filename) (7.04 kB)
i8k-cumulative.patch (28.82 kB)
Download all attachments

2005-03-17 09:38:18

by Frank Sorenson

[permalink] [raw]
Subject: Re: [PATCH 0/5] I8K driver facelift

-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA1

Dmitry Torokhov wrote:
| Hrm, can we be a little more explicit and not poke in the sysfs guts right
| in the driver? What do you think about the patch below athat implements
| "attribute arrays"? And I am attaching cumulative i8k patch using these
| arrays so they can be tested.
|
| I am CC-ing Greg to see what he thinks about it.

Well, yes. That would probably be the better way to go about it, though
I have to admit I was somewhat pleased with myself that I came up with
something that worked. :)

Your patches work well, with a few minor notes:

1: My Inspiron 9200 (and perhaps others) doesn't seem to respond to the
I8K_SMM_BIOS_VERSION function call, so it fails the check in i8k_probe.
~ The check of i8k_get_bios_version doesn't seem critical, and removing
the return -ENODEV makes it work again for me. That's the current
behavior, so perhaps the printk level should just be changed to
KERN_WARNING rather than KERN_ALERT.

2: To compile 2.6.11 cleanly, I needed two hunks from your original
patch 2 (perhaps you're working from a more up-to-date tree than I am?
If so, these are probably already addressed.):

- --- dtor.orig/arch/i386/kernel/dmi_scan.c
+++ dtor/arch/i386/kernel/dmi_scan.c
@@ -416,6 +416,7 @@ static void __init dmi_decode(struct dmi
~ dmi_save_ident(dm, DMI_PRODUCT_VERSION, 6);
~ dmi_printk(("Serial Number: %s\n",
~ dmi_string(dm, data[7])));
+ dmi_save_ident(dm, DMI_PRODUCT_SERIAL, 7);
~ break;
~ case 2:
~ dmi_printk(("Board Vendor: %s\n",
- --- dtor.orig/include/linux/dmi.h
+++ dtor/include/linux/dmi.h
@@ -9,6 +9,7 @@ enum dmi_field {
~ DMI_SYS_VENDOR,
~ DMI_PRODUCT_NAME,
~ DMI_PRODUCT_VERSION,
+ DMI_PRODUCT_SERIAL,
~ DMI_BOARD_VENDOR,
~ DMI_BOARD_NAME,
~ DMI_BOARD_VERSION,


I also have a question about the structure created using sysfs attribute
arrays. Applying it in this case, I get:
./temp
./temp/3
./temp/2
./temp/1
./temp/0
./fan_speed
./fan_speed/1
./fan_speed/0
./fan_state
./fan_state/1
./fan_state/0

The 'temp' entries make sense, however I'm not sure about the fan_speed
and fan_state entries. From the perspective of how the objects are
ordered, a fan would have 'speed' and 'state' attributes, but a
'fan_state' attribute wouldn't normally have a fan. Maybe something
along these lines would make more sense from that perspective:

./fan/0
./fan/0/speed
./fan/0/state
./fan/1
./fan/1/speed
./fan/1/state

I'm not certain about the best way to do this, so this may just be a
thought. It would certainly be more complex to reorder it, and it
appears usable in its current form.

Frank
- --
Frank Sorenson - KD7TZK
Systems Manager, Computer Science Department
Brigham Young University
[email protected]
-----BEGIN PGP SIGNATURE-----
Version: GnuPG v1.2.6 (GNU/Linux)
Comment: Using GnuPG with Thunderbird - http://enigmail.mozdev.org

iD4DBQFCOU/0aI0dwg4A47wRAjgDAJwLsvd14J/qAmgv7JzkXG2xgAmTGwCY6RUc
Nomk0pwTSfymHtIuF7ylzQ==
=85eA
-----END PGP SIGNATURE-----

2005-03-17 09:46:19

by Frank Sorenson

[permalink] [raw]
Subject: Re: [PATCH 0/5] I8K driver facelift

-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA1

Dmitry Torokhov wrote:
| Hrm, can we be a little more explicit and not poke in the sysfs guts right
| in the driver? What do you think about the patch below athat implements
| "attribute arrays"? And I am attaching cumulative i8k patch using these
| arrays so they can be tested.

Also, with power_status being a module parameter defaulting to 0/off, we
can leave out the device_create_file for the i8k_power_status_attr. No
need to expose it in sysfs if it will always return -EIO.

Frank
- --
Frank Sorenson - KD7TZK
Systems Manager, Computer Science Department
Brigham Young University
[email protected]
-----BEGIN PGP SIGNATURE-----
Version: GnuPG v1.2.6 (GNU/Linux)
Comment: Using GnuPG with Thunderbird - http://enigmail.mozdev.org

iD8DBQFCOVHjaI0dwg4A47wRAgquAJ49qf5qFZX9twSbLetJiliEnES5GwCg41z2
r6AWC22/zAcz54xAIfNQJ4I=
=0BtE
-----END PGP SIGNATURE-----

2005-03-17 14:49:56

by Valdis Klētnieks

[permalink] [raw]
Subject: Re: [PATCH 0/5] I8K driver facelift

On Wed, 16 Mar 2005 14:38:50 MST, Frank Sorenson said:
> Okay, I replaced the sysfs_ops with ops of my own, and now all the show
> and store functions also accept the name of the attribute as a parameter.
> This lets the functions know what attribute is being accessed, and allows
> us to create attributes that share show and store functions, so things
> don't need to be defined at compile time (I feel slightly evil!).
>
> This patch puts the correct number of temp sensors and fans into sysfs,
> and only exposes power_status if enabled by the power_status module
> parameter.

Works for me:

[/sys/bus/platform/drivers/i8k/i8k]2 ls -l
total 0
lrwxrwxrwx 1 root root 0 Mar 17 03:02 bus -> ../../../bus/platform
-r--r--r-- 1 root root 4096 Mar 17 03:02 cpu_temp
-rw-r--r-- 1 root root 4096 Mar 17 03:01 detach_state
lrwxrwxrwx 1 root root 0 Mar 17 03:02 driver -> ../../../bus/platform/drivers/i8k
-r--r--r-- 1 root root 4096 Mar 17 03:02 fan1_speed
-rw-r--r-- 1 root root 4096 Mar 17 03:02 fan1_state
-r--r--r-- 1 root root 4096 Mar 17 03:02 fan2_speed
-rw-r--r-- 1 root root 4096 Mar 17 03:02 fan2_state
drwxr-xr-x 2 root root 0 Mar 17 03:02 power
-r--r--r-- 1 root root 4096 Mar 17 03:02 power_status
-r--r--r-- 1 root root 4096 Mar 17 03:02 temp1
-r--r--r-- 1 root root 4096 Mar 17 03:02 temp2

The valyes of the fan* settings, and cpu_temp match what's reported in /proc/i8k.

temp1 is the same as cpu_temp. temp2 is running about 7C higher and
is still unidentified (though probably the NVidia chip).

I'll give Dmitry's sysfs/array stuff a test tomorrow-ish unless Greg has
comments before then.


Attachments:
(No filename) (226.00 B)

2005-03-17 15:07:19

by Dmitry Torokhov

[permalink] [raw]
Subject: Re: [PATCH 0/5] I8K driver facelift

On Thu, 17 Mar 2005 02:37:56 -0700, Frank Sorenson <[email protected]> wrote:

> 1: My Inspiron 9200 (and perhaps others) doesn't seem to respond to the
> I8K_SMM_BIOS_VERSION function call, so it fails the check in i8k_probe.
> ~ The check of i8k_get_bios_version doesn't seem critical, and removing
> the return -ENODEV makes it work again for me. That's the current
> behavior, so perhaps the printk level should just be changed to
> KERN_WARNING rather than KERN_ALERT.

You are probably right, I shoudl change that.

> 2: To compile 2.6.11 cleanly, I needed two hunks from your original
> patch 2 (perhaps you're working from a more up-to-date tree than I am?
> If so, these are probably already addressed.):
>

Oh, sorry - when I was pereparing cumulative patch I simply missed
this bit. It is still nowhere near the official tree.

>
> The 'temp' entries make sense, however I'm not sure about the fan_speed
> and fan_state entries. From the perspective of how the objects are
> ordered, a fan would have 'speed' and 'state' attributes, but a
> 'fan_state' attribute wouldn't normally have a fan. Maybe something
> along these lines would make more sense from that perspective:
>
> ./fan/0
> ./fan/0/speed
> ./fan/0/state
> ./fan/1
> ./fan/1/speed
> ./fan/1/state
>

Yes, as soon as I did attribute array I realized that something like
attr_array_group would reflect the structure better... We'll see what
can be done.

Thank you for your comments and suggestions!

--
Dmitry

2005-03-21 05:15:27

by Dmitry Torokhov

[permalink] [raw]
Subject: Re: [PATCH 0/5] I8K driver facelift

Hi,

On Thursday 17 March 2005 04:46, Frank Sorenson wrote:
> Dmitry Torokhov wrote:
> | Hrm, can we be a little more explicit and not poke in the sysfs guts right
> | in the driver? What do you think about the patch below athat implements
> | "attribute arrays"? And I am attaching cumulative i8k patch using these
> | arrays so they can be tested.
>
> Also, with power_status being a module parameter defaulting to 0/off, we
> can leave out the device_create_file for the i8k_power_status_attr. No
> need to expose it in sysfs if it will always return -EIO.
>

Since root can toggle power_status through sysfs at runtime (see
/sys/modules/i8k/parameters/power_status) I think it is simplier to have
the file always created.

I have implemented arrays of groups of attributes:

[dtor@core ~]$ ls -R /sys/bus/platform/devices/i8k/fan/
/sys/bus/platform/devices/i8k/fan/:
0 1

/sys/bus/platform/devices/i8k/fan/0:
speed state

/sys/bus/platform/devices/i8k/fan/1:
speed state

Please give it a try when you have time. Thanks!

--
Dmitry


Attachments:
(No filename) (1.02 kB)
attr-array.patch (6.29 kB)
attr-group-array.patch (7.09 kB)
i8k-cumulative.patch (30.61 kB)
Download all attachments

2005-03-21 22:58:15

by Frank Sorenson

[permalink] [raw]
Subject: Re: [PATCH 0/5] I8K driver facelift

-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA1

Dmitry Torokhov wrote:
> I have implemented arrays of groups of attributes:

Works great here. The i8k-cumulative patch claimed to be malformed, but
I merged it in just fine by hand. In arch/i386/kernel/dmi_scan.c, I had
to EXPORT dmi_get_system_info in order to get the i8k module to load.
That may have been a mistake on my end (lots of odd patches in my tree
right now). I'm a little curious to see how many people are going to
find they need the ignore_dmi flag versus working without it.

Everything works great, and it is a big step up from the existing code.
I say lets go with it.

Frank
- --
Frank Sorenson - KD7TZK
Systems Manager, Computer Science Department
Brigham Young University
[email protected]
-----BEGIN PGP SIGNATURE-----
Version: GnuPG v1.2.6 (GNU/Linux)
Comment: Using GnuPG with Thunderbird - http://enigmail.mozdev.org

iD8DBQFCP1B7aI0dwg4A47wRAufNAJ9tJODed2rcndtytGCZbJHr5AQJPgCgqbA1
zWnRrePRdJ/+5K1yu5HM3jg=
=OzaL
-----END PGP SIGNATURE-----

2005-03-22 00:17:53

by Dmitry Torokhov

[permalink] [raw]
Subject: Re: [PATCH 0/5] I8K driver facelift

On Monday 21 March 2005 17:53, Frank Sorenson wrote:
> Dmitry Torokhov wrote:
> > I have implemented arrays of groups of attributes:
>
> Works great here. The i8k-cumulative patch claimed to be malformed, but
> I merged it in just fine by hand. In arch/i386/kernel/dmi_scan.c, I had
> to EXPORT dmi_get_system_info in order to get the i8k module to load.
> That may have been a mistake on my end (lots of odd patches in my tree
> right now).

No, I bet I forgot to export it - I have i8k compiled in and would not
notice missing export.

> I'm a little curious to see how many people are going to
> find they need the ignore_dmi flag versus working without it.

I want this driver to be first of all safe for loading on a random box
so it can be enabled by default.

>
> Everything works great, and it is a big step up from the existing code.
> I say lets go with it.
>

Yep, I will add missing export and forward it to Andrew - it could use
some time in -mm.

Thank you very much for testing it.

--
Dmitry

2005-03-24 07:28:17

by Greg KH

[permalink] [raw]
Subject: Re: [PATCH 0/5] I8K driver facelift

On Thu, Mar 17, 2005 at 03:16:24AM -0500, [email protected] wrote:
> On Wed, 16 Mar 2005 14:38:50 MST, Frank Sorenson said:
> > Okay, I replaced the sysfs_ops with ops of my own, and now all the show
> > and store functions also accept the name of the attribute as a parameter.
> > This lets the functions know what attribute is being accessed, and allows
> > us to create attributes that share show and store functions, so things
> > don't need to be defined at compile time (I feel slightly evil!).
> >
> > This patch puts the correct number of temp sensors and fans into sysfs,
> > and only exposes power_status if enabled by the power_status module
> > parameter.
>
> Works for me:
>
> [/sys/bus/platform/drivers/i8k/i8k]2 ls -l
> total 0
> lrwxrwxrwx 1 root root 0 Mar 17 03:02 bus -> ../../../bus/platform
> -r--r--r-- 1 root root 4096 Mar 17 03:02 cpu_temp
> -rw-r--r-- 1 root root 4096 Mar 17 03:01 detach_state
> lrwxrwxrwx 1 root root 0 Mar 17 03:02 driver -> ../../../bus/platform/drivers/i8k
> -r--r--r-- 1 root root 4096 Mar 17 03:02 fan1_speed
> -rw-r--r-- 1 root root 4096 Mar 17 03:02 fan1_state
> -r--r--r-- 1 root root 4096 Mar 17 03:02 fan2_speed
> -rw-r--r-- 1 root root 4096 Mar 17 03:02 fan2_state
> drwxr-xr-x 2 root root 0 Mar 17 03:02 power
> -r--r--r-- 1 root root 4096 Mar 17 03:02 power_status
> -r--r--r-- 1 root root 4096 Mar 17 03:02 temp1
> -r--r--r-- 1 root root 4096 Mar 17 03:02 temp2
>
> The valyes of the fan* settings, and cpu_temp match what's reported in /proc/i8k.

Please match the same units and filename as the other i2c sensors. See
the documentation in the Documentation/i2c/ directory for what that
standard is, so userspace programs will "just work" with your devices.

thanks,

greg k-h

2005-03-24 07:28:09

by Greg KH

[permalink] [raw]
Subject: Re: [PATCH 0/5] I8K driver facelift

On Thu, Mar 17, 2005 at 01:40:48AM -0500, Dmitry Torokhov wrote:
> On Wednesday 16 March 2005 16:38, Frank Sorenson wrote:
> > Okay, I replaced the sysfs_ops with ops of my own, and now all the show
> > and store functions also accept the name of the attribute as a parameter.
> > This lets the functions know what attribute is being accessed, and allows
> > us to create attributes that share show and store functions, so things
> > don't need to be defined at compile time (I feel slightly evil!).
>
> Hrm, can we be a little more explicit and not poke in the sysfs guts right
> in the driver? What do you think about the patch below athat implements
> "attribute arrays"? And I am attaching cumulative i8k patch using these
> arrays so they can be tested.
>
> I am CC-ing Greg to see what he thinks about it.

Hm, I think it's proably of limited use, right? What other code would
want this (the i2c sensor code doesn't, as it's naming scheme is
different.)

What drivers _do_ want is a way to create attributes on the fly easily,
and be able to have a "private" pointer to determine easier what file
was opened (to allow a single file handler, instead of the current
one-per-attribute type).

thanks,

greg k-h

2005-03-24 07:40:03

by Dmitry Torokhov

[permalink] [raw]
Subject: Re: [PATCH 0/5] I8K driver facelift

On Thursday 24 March 2005 02:25, Greg KH wrote:
> On Thu, Mar 17, 2005 at 01:40:48AM -0500, Dmitry Torokhov wrote:
> > On Wednesday 16 March 2005 16:38, Frank Sorenson wrote:
> > > Okay, I replaced the sysfs_ops with ops of my own, and now all the show
> > > and store functions also accept the name of the attribute as a parameter.
> > > This lets the functions know what attribute is being accessed, and allows
> > > us to create attributes that share show and store functions, so things
> > > don't need to be defined at compile time (I feel slightly evil!).
> >
> > Hrm, can we be a little more explicit and not poke in the sysfs guts right
> > in the driver? What do you think about the patch below athat implements
> > "attribute arrays"? And I am attaching cumulative i8k patch using these
> > arrays so they can be tested.
> >
> > I am CC-ing Greg to see what he thinks about it.
>
> Hm, I think it's proably of limited use, right? What other code would
> want this (the i2c sensor code doesn't, as it's naming scheme is
> different.)
>

Looking at their attributes they would benefit from arrays of goups of
attributes... They have:

temp[1-4]_max
temp[1-3]_min
temp[1-3]_max_hyst

It could be:

temp/<n>/max
min
max_hyst


--
Dmitry

2005-03-24 08:33:11

by Greg KH

[permalink] [raw]
Subject: Re: [PATCH 0/5] I8K driver facelift

On Thu, Mar 24, 2005 at 02:39:32AM -0500, Dmitry Torokhov wrote:
> On Thursday 24 March 2005 02:25, Greg KH wrote:
> > On Thu, Mar 17, 2005 at 01:40:48AM -0500, Dmitry Torokhov wrote:
> > > On Wednesday 16 March 2005 16:38, Frank Sorenson wrote:
> > > > Okay, I replaced the sysfs_ops with ops of my own, and now all the show
> > > > and store functions also accept the name of the attribute as a parameter.
> > > > This lets the functions know what attribute is being accessed, and allows
> > > > us to create attributes that share show and store functions, so things
> > > > don't need to be defined at compile time (I feel slightly evil!).
> > >
> > > Hrm, can we be a little more explicit and not poke in the sysfs guts right
> > > in the driver? What do you think about the patch below athat implements
> > > "attribute arrays"? And I am attaching cumulative i8k patch using these
> > > arrays so they can be tested.
> > >
> > > I am CC-ing Greg to see what he thinks about it.
> >
> > Hm, I think it's proably of limited use, right? What other code would
> > want this (the i2c sensor code doesn't, as it's naming scheme is
> > different.)
> >
>
> Looking at their attributes they would benefit from arrays of goups of
> attributes... They have:
>
> temp[1-4]_max
> temp[1-3]_min
> temp[1-3]_max_hyst
>
> It could be:
>
> temp/<n>/max
> min
> max_hyst
>

Yeah, but then you break the userspace api that tools are already
expecting to see :(

thanks,

greg k-h

2005-03-24 14:44:14

by Dmitry Torokhov

[permalink] [raw]
Subject: Re: [PATCH 0/5] I8K driver facelift

On Thu, 24 Mar 2005 00:00:48 -0800, Greg KH <[email protected]> wrote:
> On Thu, Mar 24, 2005 at 02:39:32AM -0500, Dmitry Torokhov wrote:
> > On Thursday 24 March 2005 02:25, Greg KH wrote:
> > > On Thu, Mar 17, 2005 at 01:40:48AM -0500, Dmitry Torokhov wrote:
> > > > On Wednesday 16 March 2005 16:38, Frank Sorenson wrote:
> > > > > Okay, I replaced the sysfs_ops with ops of my own, and now all the show
> > > > > and store functions also accept the name of the attribute as a parameter.
> > > > > This lets the functions know what attribute is being accessed, and allows
> > > > > us to create attributes that share show and store functions, so things
> > > > > don't need to be defined at compile time (I feel slightly evil!).
> > > >
> > > > Hrm, can we be a little more explicit and not poke in the sysfs guts right
> > > > in the driver? What do you think about the patch below athat implements
> > > > "attribute arrays"? And I am attaching cumulative i8k patch using these
> > > > arrays so they can be tested.
> > > >
> > > > I am CC-ing Greg to see what he thinks about it.
> > >
> > > Hm, I think it's proably of limited use, right? What other code would
> > > want this (the i2c sensor code doesn't, as it's naming scheme is
> > > different.)
> > >
> >
> > Looking at their attributes they would benefit from arrays of goups of
> > attributes... They have:
> > ...
> Yeah, but then you break the userspace api that tools are already
> expecting to see :(
>

Yes, although i2c did change inreface somewhat recently - I remember I
had to upgrade sensor package couple of month ago to get sensors
output, so we have some precedent.

Also, even if i2c decides not to use it it does not mean that at some
point nobody else would use attribute arrays and arrays of groups. I
am willing to bet if these would be available they could be used:

/drivers/macintosh/therm_pm72.c
/drivers/usb/misc/cytherm.c

Attributes with a private pointer passed in would be very useful too.

--
Dmitry

2005-04-13 06:33:39

by Dmitry Torokhov

[permalink] [raw]
Subject: Re: [PATCH 0/5] I8K driver facelift

On Thursday 24 March 2005 02:24, Greg KH wrote:
> On Thu, Mar 17, 2005 at 03:16:24AM -0500, [email protected] wrote:
> > On Wed, 16 Mar 2005 14:38:50 MST, Frank Sorenson said:
> > > Okay, I replaced the sysfs_ops with ops of my own, and now all the show
> > > and store functions also accept the name of the attribute as a parameter.
> > > This lets the functions know what attribute is being accessed, and allows
> > > us to create attributes that share show and store functions, so things
> > > don't need to be defined at compile time (I feel slightly evil!).
> > >
> > > This patch puts the correct number of temp sensors and fans into sysfs,
> > > and only exposes power_status if enabled by the power_status module
> > > parameter.
> >
> > Works for me:
> >
> > [/sys/bus/platform/drivers/i8k/i8k]2 ls -l
> > total 0
> > lrwxrwxrwx 1 root root 0 Mar 17 03:02 bus -> ../../../bus/platform
> > -r--r--r-- 1 root root 4096 Mar 17 03:02 cpu_temp
> > -rw-r--r-- 1 root root 4096 Mar 17 03:01 detach_state
> > lrwxrwxrwx 1 root root 0 Mar 17 03:02 driver -> ../../../bus/platform/drivers/i8k
> > -r--r--r-- 1 root root 4096 Mar 17 03:02 fan1_speed
> > -rw-r--r-- 1 root root 4096 Mar 17 03:02 fan1_state
> > -r--r--r-- 1 root root 4096 Mar 17 03:02 fan2_speed
> > -rw-r--r-- 1 root root 4096 Mar 17 03:02 fan2_state
> > drwxr-xr-x 2 root root 0 Mar 17 03:02 power
> > -r--r--r-- 1 root root 4096 Mar 17 03:02 power_status
> > -r--r--r-- 1 root root 4096 Mar 17 03:02 temp1
> > -r--r--r-- 1 root root 4096 Mar 17 03:02 temp2
> >
> > The valyes of the fan* settings, and cpu_temp match what's reported in /proc/i8k.
>
> Please match the same units and filename as the other i2c sensors. See
> the documentation in the Documentation/i2c/ directory for what that
> standard is, so userspace programs will "just work" with your devices.
>

Greg,

I almost started doing what you just said but then I realized that none of
the programs will "just work" because all of them will look into /sys/bus/i2c
instead of /sys/bus/platform/i8k.

For userspace tools to work transparently we would need something like
/sys/class/sensor/{fan|temp|current}, but it is something I am not ready to do
now - I need to finish input layer first.

So given above I think having private scheme for now is ok. Sooo... Can I get
my attributes goups patch in so I can use it in i8k, please?

Thanks!

--
Dmitry

2005-04-13 08:01:37

by Greg KH

[permalink] [raw]
Subject: Re: [PATCH 0/5] I8K driver facelift

On Wed, Apr 13, 2005 at 01:33:31AM -0500, Dmitry Torokhov wrote:
> On Thursday 24 March 2005 02:24, Greg KH wrote:
> > On Thu, Mar 17, 2005 at 03:16:24AM -0500, [email protected] wrote:
> > > On Wed, 16 Mar 2005 14:38:50 MST, Frank Sorenson said:
> > > > Okay, I replaced the sysfs_ops with ops of my own, and now all the show
> > > > and store functions also accept the name of the attribute as a parameter.
> > > > This lets the functions know what attribute is being accessed, and allows
> > > > us to create attributes that share show and store functions, so things
> > > > don't need to be defined at compile time (I feel slightly evil!).
> > > >
> > > > This patch puts the correct number of temp sensors and fans into sysfs,
> > > > and only exposes power_status if enabled by the power_status module
> > > > parameter.
> > >
> > > Works for me:
> > >
> > > [/sys/bus/platform/drivers/i8k/i8k]2 ls -l
> > > total 0
> > > lrwxrwxrwx 1 root root 0 Mar 17 03:02 bus -> ../../../bus/platform
> > > -r--r--r-- 1 root root 4096 Mar 17 03:02 cpu_temp
> > > -rw-r--r-- 1 root root 4096 Mar 17 03:01 detach_state
> > > lrwxrwxrwx 1 root root 0 Mar 17 03:02 driver -> ../../../bus/platform/drivers/i8k
> > > -r--r--r-- 1 root root 4096 Mar 17 03:02 fan1_speed
> > > -rw-r--r-- 1 root root 4096 Mar 17 03:02 fan1_state
> > > -r--r--r-- 1 root root 4096 Mar 17 03:02 fan2_speed
> > > -rw-r--r-- 1 root root 4096 Mar 17 03:02 fan2_state
> > > drwxr-xr-x 2 root root 0 Mar 17 03:02 power
> > > -r--r--r-- 1 root root 4096 Mar 17 03:02 power_status
> > > -r--r--r-- 1 root root 4096 Mar 17 03:02 temp1
> > > -r--r--r-- 1 root root 4096 Mar 17 03:02 temp2
> > >
> > > The valyes of the fan* settings, and cpu_temp match what's reported in /proc/i8k.
> >
> > Please match the same units and filename as the other i2c sensors. See
> > the documentation in the Documentation/i2c/ directory for what that
> > standard is, so userspace programs will "just work" with your devices.
> >
>
> Greg,
>
> I almost started doing what you just said but then I realized that none of
> the programs will "just work" because all of them will look into /sys/bus/i2c
> instead of /sys/bus/platform/i8k.
>
> For userspace tools to work transparently we would need something like
> /sys/class/sensor/{fan|temp|current}, but it is something I am not ready to do
> now - I need to finish input layer first.

The sensors developers are creating just such a class, see their hwmon
patch in their email archive if you are curious.

> So given above I think having private scheme for now is ok. Sooo... Can I get
> my attributes goups patch in so I can use it in i8k, please?

Ick, no, use the upcoming hwmon stuff instead :)

thanks,

greg k-h