Simplification of /proc files functions in chip drivers

I moved a large part of the proc and sysctl call-back functions into
sensors.c. The result saved about 100 lines in lm78.c; it now uses only
2 pages according to lsmod, instead of 3! Also, other modules can use
the same functions, saving coding efforts and keeping them small.

I also fixed a fan_div display error.

Expect more code to be moved to sensors.c: I am writing lm75.c, and
most things which are in both modules (and so probably general purpose)
will be moved to sensors.c.


git-svn-id: http://lm-sensors.org/svn/lm-sensors/trunk@28 7894878c-1315-0410-8ee3-d5d059ff63e0
This commit is contained in:
Frodo Looijaard committed 1998-12-03 23:15:17 +00:00
1 parent 0aa9e734d0
commit 857a44f757
6 files changed
+594 -584

No files matched your search

+147 -284
View File
@@ -33,7 +33,7 @@
#include "i2c.h"
#include "compat.h"
/* Many LM78 constants needed below */
/* Many LM78 constants specified below */
/* Length of ISA address segment */
#define LM78_EXTENT 8
@@ -81,7 +81,7 @@ static int lm78_in_conv[7] = {10000, 10000, 10000, 16892, 38000,
(val)>=0x06?0:205-(val)*5)
#define ALARMS_FROM_REG(val) (val)
#define DIV_FROM_REG(val) (1 >> (val))
#define DIV_FROM_REG(val) (1 << (val))
#define DIV_TO_REG(val) ((val)==8?3:(val)==4?2:(val)==1?0:1)
/* Initial limits */
@@ -203,27 +203,19 @@ static int lm78_write_value(struct i2c_client *client, u8 register, u8 value);
static void lm78_update_client(struct i2c_client *client);
static void lm78_init_client(struct i2c_client *client);
static int lm78_sysctl (ctl_table *table, int *name, int nlen, void *oldval,
size_t *oldlenp, void *newval, size_t newlen,
void **context);
static int lm78_proc (ctl_table *ctl, int write, struct file * filp,
void *buffer, size_t *lenp);
static void write_in(struct i2c_client *client, int nr, int nrels,
long *results);
static void read_in(struct i2c_client *client, int nr, long *results);
static void write_fan(struct i2c_client *client, int nr, int nrels,
long *results);
static void read_fan(struct i2c_client *client, int nr, long *results);
static void write_temp(struct i2c_client *client, int nrels, long *results);
static void read_temp(struct i2c_client *client, long *results);
static void read_vid(struct i2c_client *client, long *results);
static void read_alarms(struct i2c_client *client, long *results);
static void write_fan_div(struct i2c_client *client, int nrels, long *results);
static void read_fan_div(struct i2c_client *client, long *results);
void lm78_in(struct i2c_client *client, int operation, int ctl_name,
int *nrels_mag, long *results);
void lm78_fan(struct i2c_client *client, int operation, int ctl_name,
int *nrels_mag, long *results);
void lm78_temp(struct i2c_client *client, int operation, int ctl_name,
int *nrels_mag, long *results);
void lm78_vid(struct i2c_client *client, int operation, int ctl_name,
int *nrels_mag, long *results);
void lm78_alarms(struct i2c_client *client, int operation, int ctl_name,
int *nrels_mag, long *results);
void lm78_fan_div(struct i2c_client *client, int operation, int ctl_name,
int *nrels_mag, long *results);
/* I choose here for semi-static LM78 allocation. Complete dynamic
allocation could also be used; the code needed for this would probably
@@ -254,20 +246,34 @@ static int lm78_initialized = 0;
is done through one of the 'extra' fields which are initialized
when a new copy is allocated. */
static ctl_table lm78_dir_table_template[] = {
{ LM78_SYSCTL_IN0, "in0", NULL, 0, 0644, NULL, &lm78_proc, &lm78_sysctl },
{ LM78_SYSCTL_IN1, "in1", NULL, 0, 0644, NULL, &lm78_proc, &lm78_sysctl },
{ LM78_SYSCTL_IN2, "in2", NULL, 0, 0644, NULL, &lm78_proc, &lm78_sysctl },
{ LM78_SYSCTL_IN3, "in3", NULL, 0, 0644, NULL, &lm78_proc, &lm78_sysctl },
{ LM78_SYSCTL_IN4, "in4", NULL, 0, 0644, NULL, &lm78_proc, &lm78_sysctl },
{ LM78_SYSCTL_IN5, "in5", NULL, 0, 0644, NULL, &lm78_proc, &lm78_sysctl },
{ LM78_SYSCTL_IN6, "in6", NULL, 0, 0644, NULL, &lm78_proc, &lm78_sysctl },
{ LM78_SYSCTL_FAN1, "fan1", NULL, 0, 0644, NULL, &lm78_proc, &lm78_sysctl },
{ LM78_SYSCTL_FAN2, "fan2", NULL, 0, 0644, NULL, &lm78_proc, &lm78_sysctl },
{ LM78_SYSCTL_FAN3, "fan3", NULL, 0, 0644, NULL, &lm78_proc, &lm78_sysctl },
{ LM78_SYSCTL_TEMP, "temp", NULL, 0, 0644, NULL, &lm78_proc, &lm78_sysctl },
{ LM78_SYSCTL_VID, "vid", NULL, 0, 0644, NULL, &lm78_proc, &lm78_sysctl },
{ LM78_SYSCTL_FAN_DIV, "fan_div", NULL, 0, 0644, NULL, &lm78_proc, &lm78_sysctl },
{ LM78_SYSCTL_ALARMS, "alarms", NULL, 0, 0644, NULL, &lm78_proc, &lm78_sysctl },
{ LM78_SYSCTL_IN0, "in0", NULL, 0, 0644, NULL, &sensors_proc_real,
&sensors_sysctl_real, NULL, &lm78_in },
{ LM78_SYSCTL_IN1, "in1", NULL, 0, 0644, NULL, &sensors_proc_real,
&sensors_sysctl_real, NULL, &lm78_in },
{ LM78_SYSCTL_IN2, "in2", NULL, 0, 0644, NULL, &sensors_proc_real,
&sensors_sysctl_real, NULL, &lm78_in },
{ LM78_SYSCTL_IN3, "in3", NULL, 0, 0644, NULL, &sensors_proc_real,
&sensors_sysctl_real, NULL, &lm78_in },
{ LM78_SYSCTL_IN4, "in4", NULL, 0, 0644, NULL, &sensors_proc_real,
&sensors_sysctl_real, NULL, &lm78_in },
{ LM78_SYSCTL_IN5, "in5", NULL, 0, 0644, NULL, &sensors_proc_real,
&sensors_sysctl_real, NULL, &lm78_in },
{ LM78_SYSCTL_IN6, "in6", NULL, 0, 0644, NULL, &sensors_proc_real,
&sensors_sysctl_real, NULL, &lm78_in },
{ LM78_SYSCTL_FAN1, "fan1", NULL, 0, 0644, NULL, &sensors_proc_real,
&sensors_sysctl_real, NULL, &lm78_fan },
{ LM78_SYSCTL_FAN2, "fan2", NULL, 0, 0644, NULL, &sensors_proc_real,
&sensors_sysctl_real, NULL, &lm78_fan },
{ LM78_SYSCTL_FAN3, "fan3", NULL, 0, 0644, NULL, &sensors_proc_real,
&sensors_sysctl_real, NULL, &lm78_fan },
{ LM78_SYSCTL_TEMP, "temp", NULL, 0, 0644, NULL, &sensors_proc_real,
&sensors_sysctl_real, NULL, &lm78_temp },
{ LM78_SYSCTL_VID, "vid", NULL, 0, 0644, NULL, &sensors_proc_real,
&sensors_sysctl_real, NULL, &lm78_vid },
{ LM78_SYSCTL_FAN_DIV, "fan_div", NULL, 0, 0644, NULL, &sensors_proc_real,
&sensors_sysctl_real, NULL, &lm78_fan_div },
{ LM78_SYSCTL_ALARMS, "alarms", NULL, 0, 0644, NULL, &sensors_proc_real,
&sensors_sysctl_real, NULL, &lm78_alarms },
{ 0 }
};
@@ -699,281 +705,138 @@ void lm78_update_client(struct i2c_client *client)
up(&data->update_lock);
}
/* This function is called when /proc/sys/dev/lm78-???/... is accessed */
int lm78_proc (ctl_table *ctl, int write, struct file * filp,
void *buffer, size_t *lenp)
/* The next few functions are the call-back functions of the /proc/sys and
sysctl files. Which function is used is defined in the ctl_table in
the extra1 field.
Each function must return the magnitude (power of 10 to divide the date
with) if it is called with operation==SENSORS_PROC_REAL_INFO. It must
put a maximum of *nrels elements in results reflecting the data of this
file, and set *nrels to the number it actually put in it, if operation==
SENSORS_PROC_REAL_READ. Finally, it must get upto *nrels elements from
results and write them to the chip, if operations==SENSORS_PROC_REAL_WRITE.
Note that on SENSORS_PROC_REAL_READ, I do not check whether results is
large enough (by checking the incoming value of *nrels). This is not very
good practice, but as long as you put less than about 5 values in results,
you can assume it is large enough. */
void lm78_in(struct i2c_client *client, int operation, int ctl_name,
int *nrels_mag, long *results)
{
int nrels,mag;
long results[7];
struct i2c_client *client = ctl -> extra1;
struct lm78_data *data = client->data;
int nr = ctl_name - LM78_SYSCTL_IN0;
/* If buffer is size 0, or we try to read when not at the start, we
return nothing. Note that I think writing when not at the start
does not work either, but anyway, this is straight from the kernel
sources. */
if (!*lenp || (filp->f_pos && !write)) {
*lenp = 0;
return 0;
}
/* How many numbers are found within these files, and how to scale them? */
switch (ctl->ctl_name) {
case LM78_SYSCTL_IN0: case LM78_SYSCTL_IN1: case LM78_SYSCTL_IN2:
case LM78_SYSCTL_IN3: case LM78_SYSCTL_IN4: case LM78_SYSCTL_IN5:
case LM78_SYSCTL_IN6:
nrels=3;
mag=2;
break;
case LM78_SYSCTL_TEMP:
nrels=3;
mag=1;
break;
case LM78_SYSCTL_FAN_DIV:
nrels=3;
mag=0;
break;
case LM78_SYSCTL_FAN1: case LM78_SYSCTL_FAN2: case LM78_SYSCTL_FAN3:
nrels=2;
mag=0;
break;
case LM78_SYSCTL_VID:
nrels=1;
mag=2;
break;
case LM78_SYSCTL_ALARMS:
nrels=1;
mag=0;
break;
default: /* Should never be called */
return -EINVAL;
}
/* OK, try writing stuff. */
if (write) {
sensors_parse_reals(&nrels,buffer,*lenp,results,mag);
if (nrels == 0)
return 0;
switch (ctl->ctl_name) {
case LM78_SYSCTL_IN0: write_in(client,0,nrels,results); break;
case LM78_SYSCTL_IN1: write_in(client,1,nrels,results); break;
case LM78_SYSCTL_IN2: write_in(client,2,nrels,results); break;
case LM78_SYSCTL_IN3: write_in(client,3,nrels,results); break;
case LM78_SYSCTL_IN4: write_in(client,4,nrels,results); break;
case LM78_SYSCTL_IN5: write_in(client,5,nrels,results); break;
case LM78_SYSCTL_IN6: write_in(client,6,nrels,results); break;
case LM78_SYSCTL_FAN1: write_fan(client,1,nrels,results); break;
case LM78_SYSCTL_FAN2: write_fan(client,2,nrels,results); break;
case LM78_SYSCTL_FAN3: write_fan(client,3,nrels,results); break;
case LM78_SYSCTL_FAN_DIV: write_fan_div(client,nrels,results);break;
case LM78_SYSCTL_TEMP: write_temp(client,nrels,results);break;
case LM78_SYSCTL_VID: case LM78_SYSCTL_ALARMS: break;
default: /* Should never be called */ *lenp=0; return -EINVAL; break;
}
filp->f_pos += *lenp;
return 0;
} else { /* read */
/* Update all values in LM_Sensor_Data */
lm78_update_client((struct i2c_client *) (ctl->extra1));
/* Read the values to print into results */
switch (ctl->ctl_name) {
case LM78_SYSCTL_IN0: read_in(client,0,results);break;
case LM78_SYSCTL_IN1: read_in(client,1,results);break;
case LM78_SYSCTL_IN2: read_in(client,2,results);break;
case LM78_SYSCTL_IN3: read_in(client,3,results);break;
case LM78_SYSCTL_IN4: read_in(client,4,results);break;
case LM78_SYSCTL_IN5: read_in(client,5,results);break;
case LM78_SYSCTL_IN6: read_in(client,6,results);break;
case LM78_SYSCTL_FAN1: read_fan(client,1,results);break;
case LM78_SYSCTL_FAN2: read_fan(client,2,results);break;
case LM78_SYSCTL_FAN3: read_fan(client,3,results);break;
case LM78_SYSCTL_TEMP: read_temp(client,results);break;
case LM78_SYSCTL_FAN_DIV: read_fan_div(client,results);break;
case LM78_SYSCTL_VID: read_vid(client,results);break;
case LM78_SYSCTL_ALARMS: read_alarms(client,results);break;
default: /* Should never be called */ return -EINVAL;
}
/* OK, print it now */
sensors_write_reals(nrels,buffer,lenp,results,mag);
filp->f_pos += *lenp;
return 0;
}
}
/* This function is called when a sysctl on a lm78 file is done */
int lm78_sysctl (ctl_table *table, int *name, int nlen, void *oldval,
size_t *oldlenp, void *newval, size_t newlen,
void **context)
{
long results[7];
int nrels,oldlen;
struct i2c_client *client = table -> extra1;
/* How many numbers are found within these files, and how to scale them? */
switch (table->ctl_name) {
case LM78_SYSCTL_IN0: case LM78_SYSCTL_IN1: case LM78_SYSCTL_IN2:
case LM78_SYSCTL_IN3: case LM78_SYSCTL_IN4: case LM78_SYSCTL_IN5:
case LM78_SYSCTL_IN6: case LM78_SYSCTL_TEMP:
case LM78_SYSCTL_FAN_DIV:
nrels=3;
break;
case LM78_SYSCTL_FAN1: case LM78_SYSCTL_FAN2: case LM78_SYSCTL_FAN3:
nrels=2;
break;
case LM78_SYSCTL_VID: case LM78_SYSCTL_ALARMS:
nrels=1;
break;
default: /* Should never be called */
return -EINVAL;
}
/* Check if we need to output the old values */
if (oldval && oldlenp && ! get_user_data(oldlen,oldlenp) && oldlen) {
/* Update all values in LM_Sensor_Data */
lm78_update_client((struct i2c_client *) (table->extra1));
switch (table->ctl_name) {
case LM78_SYSCTL_IN0: read_in(client,0,results);break;
case LM78_SYSCTL_IN1: read_in(client,1,results);break;
case LM78_SYSCTL_IN2: read_in(client,2,results);break;
case LM78_SYSCTL_IN3: read_in(client,3,results);break;
case LM78_SYSCTL_IN4: read_in(client,4,results);break;
case LM78_SYSCTL_IN5: read_in(client,5,results);break;
case LM78_SYSCTL_IN6: read_in(client,6,results);break;
case LM78_SYSCTL_FAN1: read_fan(client,1,results);break;
case LM78_SYSCTL_FAN2: read_fan(client,2,results);break;
case LM78_SYSCTL_FAN3: read_fan(client,3,results);break;
case LM78_SYSCTL_TEMP: read_temp(client,results);break;
case LM78_SYSCTL_FAN_DIV: read_fan_div(client,results);break;
case LM78_SYSCTL_VID: read_vid(client,results);break;
case LM78_SYSCTL_ALARMS: read_alarms(client,results);break;
default: /* Should never be called */ return -EINVAL;
}
/* Note the rounding factor! */
if (nrels * sizeof(long) < oldlen)
oldlen = nrels * sizeof(long);
oldlen = (oldlen / sizeof(long)) * sizeof(long);
copy_to_user(oldval,results,oldlen);
put_user(oldlen,oldlenp);
}
/* Check to see whether we need to read the new values */
if (newval && newlen) {
if (nrels * sizeof(long) < newlen)
newlen = nrels * sizeof(long);
nrels = newlen / sizeof(long);
newlen = (newlen / sizeof(long)) * sizeof(long);
copy_from_user(results,newval,newlen);
switch (table->ctl_name) {
case LM78_SYSCTL_IN0: write_in(client,0,nrels,results); break;
case LM78_SYSCTL_IN1: write_in(client,1,nrels,results); break;
case LM78_SYSCTL_IN2: write_in(client,2,nrels,results); break;
case LM78_SYSCTL_IN3: write_in(client,3,nrels,results); break;
case LM78_SYSCTL_IN4: write_in(client,4,nrels,results); break;
case LM78_SYSCTL_IN5: write_in(client,5,nrels,results); break;
case LM78_SYSCTL_IN6: write_in(client,6,nrels,results); break;
case LM78_SYSCTL_FAN1: write_fan(client,1,nrels,results); break;
case LM78_SYSCTL_FAN2: write_fan(client,2,nrels,results); break;
case LM78_SYSCTL_FAN3: write_fan(client,3,nrels,results); break;
case LM78_SYSCTL_TEMP: write_temp(client,nrels,results); break;
case LM78_SYSCTL_FAN_DIV: write_fan_div(client,nrels,results);break;
case LM78_SYSCTL_VID: case LM78_SYSCTL_ALARMS: break;
default: /* Should never be called */ return -EINVAL; break;
if (operation == SENSORS_PROC_REAL_INFO)
*nrels_mag = 2;
else if (operation == SENSORS_PROC_REAL_READ) {
lm78_update_client(client);
results[0] = IN_FROM_REG(data->in_min[nr],nr);
results[1] = IN_FROM_REG(data->in_max[nr],nr);
results[2] = IN_FROM_REG(data->in[nr],nr);
*nrels_mag = 3;
} else if (operation == SENSORS_PROC_REAL_WRITE) {
if (*nrels_mag >= 1) {
data->in_min[nr] = IN_TO_REG(results[0],nr);
lm78_write_value(client,LM78_REG_IN_MIN(nr),data->in_min[nr]);
}
if (*nrels_mag >= 2) {
data->in_max[nr] = IN_TO_REG(results[1],nr);
lm78_write_value(client,LM78_REG_IN_MAX(nr),data->in_max[nr]);
}
}
return 1; /* We have done all the work */
}
void write_in(struct i2c_client *client, int nr, int nrels, long *results)
void lm78_fan(struct i2c_client *client, int operation, int ctl_name,
int *nrels_mag, long *results)
{
struct lm78_data *data = client->data;
if (nrels >= 1) {
data->in_min[nr] = IN_TO_REG(results[0],nr);
lm78_write_value(client,LM78_REG_IN_MIN(nr),data->in_min[nr]);
}
if (nrels >= 2) {
data->in_max[nr] = IN_TO_REG(results[1],nr);
lm78_write_value(client,LM78_REG_IN_MAX(nr),data->in_max[nr]);
int nr = ctl_name - LM78_SYSCTL_FAN1 + 1;
if (operation == SENSORS_PROC_REAL_INFO)
*nrels_mag = 0;
else if (operation == SENSORS_PROC_REAL_READ) {
lm78_update_client(client);
results[0] = FAN_FROM_REG(data->fan_min[nr-1]);
results[1] = FAN_FROM_REG(data->fan[nr-1]);
*nrels_mag = 2;
} else if (operation == SENSORS_PROC_REAL_WRITE) {
if (*nrels_mag >= 1) {
data->fan_min[nr-1] = FAN_TO_REG(results[0]);
lm78_write_value(client,LM78_REG_FAN_MIN(nr),data->fan_min[nr-1]);
}
}
}
void read_in(struct i2c_client *client, int nr, long *results)
{
struct lm78_data *data = client->data;
results[0] = IN_FROM_REG(data->in_min[nr],nr);
results[1] = IN_FROM_REG(data->in_max[nr],nr);
results[2] = IN_FROM_REG(data->in[nr],nr);
}
void write_fan(struct i2c_client *client, int nr, int nrels, long *results)
void lm78_temp(struct i2c_client *client, int operation, int ctl_name,
int *nrels_mag, long *results)
{
struct lm78_data *data = client->data;
if (nrels >= 1) {
data->fan_min[nr-1] = FAN_TO_REG(results[0]);
lm78_write_value(client,LM78_REG_FAN_MIN(nr),data->fan_min[nr-1]);
if (operation == SENSORS_PROC_REAL_INFO)
*nrels_mag = 1;
else if (operation == SENSORS_PROC_REAL_READ) {
lm78_update_client(client);
results[0] = TEMP_FROM_REG(data->temp_over);
results[1] = TEMP_FROM_REG(data->temp_hyst);
results[2] = TEMP_FROM_REG(data->temp);
*nrels_mag = 3;
} else if (operation == SENSORS_PROC_REAL_WRITE) {
if (*nrels_mag >= 1) {
data->temp_over = TEMP_TO_REG(results[0]);
lm78_write_value(client,LM78_REG_TEMP_OVER,data->temp_over);
}
if (*nrels_mag >= 2) {
data->temp_hyst = TEMP_TO_REG(results[1]);
lm78_write_value(client,LM78_REG_TEMP_HYST,data->temp_hyst);
}
}
}
void read_fan(struct i2c_client *client, int nr, long *results)
void lm78_vid(struct i2c_client *client, int operation, int ctl_name,
int *nrels_mag, long *results)
{
struct lm78_data *data = client->data;
results[0] = FAN_FROM_REG(data->fan_min[nr-1]);
results[1] = FAN_FROM_REG(data->fan[nr-1]);
}
void write_temp(struct i2c_client *client, int nrels, long *results)
{
struct lm78_data *data = client->data;
if (nrels >= 1) {
data->temp_over = TEMP_TO_REG(results[0]);
lm78_write_value(client,LM78_REG_TEMP_OVER,data->temp_over);
}
if (nrels >= 2) {
data->temp_hyst = TEMP_TO_REG(results[1]);
lm78_write_value(client,LM78_REG_TEMP_HYST,data->temp_hyst);
if (operation == SENSORS_PROC_REAL_INFO)
*nrels_mag = 0;
else if (operation == SENSORS_PROC_REAL_READ) {
lm78_update_client(client);
results[0] = VID_FROM_REG(data->vid);
*nrels_mag = 1;
}
}
void read_temp(struct i2c_client *client, long *results)
void lm78_alarms(struct i2c_client *client, int operation, int ctl_name,
int *nrels_mag, long *results)
{
struct lm78_data *data = client->data;
results[0] = TEMP_FROM_REG(data->temp_over);
results[1] = TEMP_FROM_REG(data->temp_hyst);
results[2] = TEMP_FROM_REG(data->temp);
if (operation == SENSORS_PROC_REAL_INFO)
*nrels_mag = 0;
else if (operation == SENSORS_PROC_REAL_READ) {
lm78_update_client(client);
results[0] = ALARMS_FROM_REG(data->alarms);
*nrels_mag = 1;
}
}
void read_vid(struct i2c_client *client, long *results)
void lm78_fan_div(struct i2c_client *client, int operation, int ctl_name,
int *nrels_mag, long *results)
{
struct lm78_data *data = client->data;
results[0] = VID_FROM_REG(data->vid);
}
void read_alarms(struct i2c_client *client, long *results)
{
struct lm78_data *data = client->data;
results[0] = ALARMS_FROM_REG(data->alarms);
}
void read_fan_div(struct i2c_client *client, long *results)
{
struct lm78_data *data = client->data;
results[0] = DIV_FROM_REG(data->fan_div[0]);
results[1] = DIV_FROM_REG(data->fan_div[1]);
results[2] = 2;
}
void write_fan_div(struct i2c_client *client, int nrels, long *results)
{
struct lm78_data *data = client->data;
if (nrels >= 2)
data->fan_div[1] = DIV_TO_REG(results[1]);
if (nrels >= 1) {
data->fan_div[0] = DIV_TO_REG(results[0]);
lm78_write_value(client,LM78_REG_VID_FANDIV,
(data->fan_div[0] >> 4) | (data->fan_div[1] >> 6));
if (operation == SENSORS_PROC_REAL_INFO)
*nrels_mag = 0;
else if (operation == SENSORS_PROC_REAL_READ) {
lm78_update_client(client);
results[0] = DIV_FROM_REG(data->fan_div[0]);
results[1] = DIV_FROM_REG(data->fan_div[1]);
results[2] = 2;
*nrels_mag = 3;
} else if (operation == SENSORS_PROC_REAL_WRITE) {
if (*nrels_mag >= 2)
data->fan_div[1] = DIV_TO_REG(results[1]);
if (*nrels_mag >= 1) {
data->fan_div[0] = DIV_TO_REG(results[0]);
lm78_write_value(client,LM78_REG_VID_FANDIV,
(data->fan_div[0] >> 4) | (data->fan_div[1] >> 6));
}
}
}
@@ -1012,7 +875,7 @@ int lm78_cleanup(void)
#ifdef MODULE
MODULE_AUTHOR("Frodo Looijaard <frodol@dds.nl>");
MODULE_DESCRIPTION("LM78 driver");
MODULE_DESCRIPTION("LM78, LM78-J and LM79 driver");
int init_module(void)
{
+44 -4
View File
@@ -23,13 +23,53 @@
#include <linux/sysctl.h>
#ifdef __KERNEL__
/* The type of callback functions used in sensors_{proc,sysctl}_real */
typedef void (*sensors_real_callback) (struct i2c_client *client,
int operation, int ctl_name,
int *nrels_mag, long *results);
/* Values for the operation field in the above function type */
#define SENSORS_PROC_REAL_INFO 1
#define SENSORS_PROC_REAL_READ 2
#define SENSORS_PROC_REAL_WRITE 3
/* These funcion reads or writes a 'real' value (encoded by the combination
of an integer and a magnitude, the last is the power of ten the value
should be divided with) to a /proc/sys directory. To use these functions,
you must (before registering the ctl_table) set the extra2 field to the
client, and the extra1 field to a function of the form:
void func(struct i2c_client *client, int operation, int ctl_name,
int *nrels_mag, long *results)
This last function can be called for three values of operation. If
operation equals SENSORS_PROC_REAL_INFO, the magnitude should be returned
in nrels_mag. If operation equals SENSORS_PROC_REAL_READ, values should
be read into results. nrels_mag should return the number of elements
read; the maximum number is put in it on entry. Finally, if operation
equals SENSORS_PROC_REAL_WRITE, the values in results should be
written to the chip. nrels_mag contains on entry the number of elements
found.
In all cases, client points to the client we wish to interact with,
and ctl_name is the SYSCTL id of the file we are accessing. */
extern int sensors_sysctl_real (ctl_table *table, int *name, int nlen,
void *oldval, size_t *oldlenp, void *newval,
size_t newlen, void **context);
extern int sensors_proc_real(ctl_table *ctl, int write, struct file * filp,
void *buffer, size_t *lenp);
/* These rather complex functions must be called when you want to add or
delete an entry in /proc/sys/dev/sensors/chips (not yet implemented). It
also creates a new directory within /proc/sys/dev/sensors/.
ctl_template should be a template of the newly created directory. It is
copied in memory. The extra2 field of each file is set to point to client.
If any driver wants subdirectories within the newly created directory,
these functions must be updated! */
extern int sensors_register_entry(struct i2c_client *client,
const char *prefix, ctl_table *ctl_template);
extern void sensors_deregister_entry(int id);
extern void sensors_parse_reals(int *nrels, void *buffer, int bufsize,
long *results, int magnitude);
extern void sensors_write_reals(int nrels,void *buffer,int *bufsize,
long *results, int magnitude);
#endif /* def __KERNEL__ */
+106 -4
View File
@@ -28,15 +28,19 @@
#include "isa.h"
#include "sensors.h"
#ifdef MODULE
extern int init_module(void);
extern int cleanup_module(void);
#endif /* MODULE */
int sensors_register_entry(struct i2c_client *client ,const char *prefix,
ctl_table *ctl_template);
static int sensors_create_name(char **name, const char *prefix,
struct i2c_adapter * adapter, int addr);
static void sensors_parse_reals(int *nrels, void *buffer, int bufsize,
long *results, int magnitude);
static void sensors_write_reals(int nrels,void *buffer,int *bufsize,
long *results, int magnitude);
static int sensors_init(void);
static int sensors_cleanup(void);
@@ -77,7 +81,7 @@ int sensors_create_name(char **name, const char *prefix,
to /proc/sys/dev/sensors/chips (not yet implemented). It also creates
a new directory within /proc/sys/dev/sensors/.
ctl_template should be a template of the newly created directory. It is
copied in memory. The extra1 field of each file is set to point to client.
copied in memory. The extra2 field of each file is set to point to client.
If any driver wants subdirectories within the newly created directory,
this function must be updated! */
int sensors_register_entry(struct i2c_client *client ,const char *prefix,
@@ -121,7 +125,7 @@ int sensors_register_entry(struct i2c_client *client ,const char *prefix,
new_table[4].ctl_name = id;
memcpy(new_table+6,ctl_template,(len-6) * sizeof(ctl_table));
for (i = 6; i < len; i++)
new_table[i].extra1 = client;
new_table[i].extra2 = client;
if (! (new_header = register_sysctl_table(new_table,0))) {
kfree(new_table);
@@ -147,6 +151,104 @@ void sensors_deregister_entry(int id)
}
}
/* This funcion reads or writes a 'real' value (encoded by the combination
of an integer and a magnitude, the last is the power of ten the value
should be divided with) to a /proc/sys directory. To use this function,
you must (before registering the ctl_table) set the extra2 field to the
client, and the extra1 field to a function of the form:
void func(struct i2c_client *client, int operation, int ctl_name,
int *nrels_mag, long *results)
This function can be called for three values of operation. If operation
equals SENSORS_PROC_REAL_INFO, the magnitude should be returned in
nrels_mag. If operation equals SENSORS_PROC_REAL_READ, values should
be read into results. nrels_mag should return the number of elements
read; the maximum number is put in it on entry. Finally, if operation
equals SENSORS_PROC_REAL_WRITE, the values in results should be
written to the chip. nrels_mag contains on entry the number of elements
found.
In all cases, client points to the client we wish to interact with,
and ctl_name is the SYSCTL id of the file we are accessing. */
int sensors_proc_real(ctl_table *ctl, int write, struct file * filp,
void *buffer, size_t *lenp)
{
#define MAX_RESULTS 20
int mag,nrels=MAX_RESULTS;
long results[MAX_RESULTS];
sensors_real_callback callback = ctl -> extra1;
struct i2c_client *client = ctl -> extra2;
/* If buffer is size 0, or we try to read when not at the start, we
return nothing. Note that I think writing when not at the start
does not work either, but anyway, this is straight from the kernel
sources. */
if (!*lenp || (filp->f_pos && !write)) {
*lenp = 0;
return 0;
}
/* Get the magnitude */
callback(client,SENSORS_PROC_REAL_INFO,ctl->ctl_name,&mag,NULL);
if (write) {
/* Read the complete input into results, converting to longs */
sensors_parse_reals(&nrels,buffer,*lenp,results,mag);
if (! nrels)
return 0;
/* Now feed this information back to the client */
callback(client,SENSORS_PROC_REAL_WRITE,ctl->ctl_name,&nrels,results);
filp->f_pos += *lenp;
return 0;
} else { /* read */
/* Get the information from the client into results */
callback(client,SENSORS_PROC_REAL_READ,ctl->ctl_name,&nrels,results);
/* And write them to buffer, converting to reals */
sensors_write_reals(nrels,buffer,lenp,results,mag);
sensors_write_reals(nrels,buffer,lenp,results,mag);
filp->f_pos += *lenp;
return 0;
}
}
/* This function is equivalent to sensors_proc_real, only it interacts with
the sysctl(2) syscall, and returns no reals, but integers */
int sensors_sysctl_real (ctl_table *table, int *name, int nlen, void *oldval,
size_t *oldlenp, void *newval, size_t newlen,
void **context)
{
long results[MAX_RESULTS];
int oldlen,nrels=MAX_RESULTS;
sensors_real_callback callback = table -> extra1;
struct i2c_client *client = table -> extra2;
/* Check if we need to output the old values */
if (oldval && oldlenp && ! get_user_data(oldlen,oldlenp) && oldlen) {
callback(client,SENSORS_PROC_REAL_READ,table->ctl_name,&nrels,results);
/* Note the rounding factor! */
if (nrels * sizeof(long) < oldlen)
oldlen = nrels * sizeof(long);
oldlen = (oldlen / sizeof(long)) * sizeof(long);
copy_to_user(oldval,results,oldlen);
put_user(oldlen,oldlenp);
}
if (newval && newlen) {
/* Note the rounding factor! */
newlen -= newlen % sizeof(long);
nrels = newlen / sizeof(long);
copy_from_user(results,newval,newlen);
/* Get the new values back to the client */
callback(client,SENSORS_PROC_REAL_WRITE,table->ctl_name,&nrels,results);
}
return 0;
}
/* nrels contains initially the maximum number of elements which can be
put in results, and finally the number of elements actually put there.
A magnitude of 1 will multiply everything with 10; etc.