📄 via686a.c
字号:
u16 twoBits = val & 3; /* no interpolation for these */ if (twoBits == 0 || eightBits == 255) return TEMP_FROM_REG(eightBits); /* do some linear interpolation */ return (tempLUT[eightBits] * (4 - twoBits) + tempLUT[eightBits + 1] * twoBits) * 25;}#define ALARMS_FROM_REG(val) (val)#define DIV_FROM_REG(val) (1 << (val))#define DIV_TO_REG(val) ((val)==8?3:(val)==4?2:(val)==1?0:1)/* For the VIA686A, we need to keep some data in memory. The structure is dynamically allocated, at the same time when a new via686a client is allocated. */struct via686a_data { struct i2c_client client; struct semaphore update_lock; char valid; /* !=0 if following fields are valid */ unsigned long last_updated; /* In jiffies */ u8 in[5]; /* Register value */ u8 in_max[5]; /* Register value */ u8 in_min[5]; /* Register value */ u8 fan[2]; /* Register value */ u8 fan_min[2]; /* Register value */ u16 temp[3]; /* Register value 10 bit */ u8 temp_over[3]; /* Register value */ u8 temp_hyst[3]; /* Register value */ u8 fan_div[2]; /* Register encoding, shifted right */ u16 alarms; /* Register encoding, combined */};static struct pci_dev *s_bridge; /* pointer to the (only) via686a */static int via686a_attach_adapter(struct i2c_adapter *adapter);static int via686a_detect(struct i2c_adapter *adapter, int address, int kind);static int via686a_detach_client(struct i2c_client *client);static inline int via686a_read_value(struct i2c_client *client, u8 reg){ return (inb_p(client->addr + reg));}static inline void via686a_write_value(struct i2c_client *client, u8 reg, u8 value){ outb_p(value, client->addr + reg);}static struct via686a_data *via686a_update_device(struct device *dev);static void via686a_init_client(struct i2c_client *client);/* following are the sysfs callback functions *//* 7 voltage sensors */static ssize_t show_in(struct device *dev, char *buf, int nr) { struct via686a_data *data = via686a_update_device(dev); return sprintf(buf, "%ld\n", IN_FROM_REG(data->in[nr], nr));}static ssize_t show_in_min(struct device *dev, char *buf, int nr) { struct via686a_data *data = via686a_update_device(dev); return sprintf(buf, "%ld\n", IN_FROM_REG(data->in_min[nr], nr));}static ssize_t show_in_max(struct device *dev, char *buf, int nr) { struct via686a_data *data = via686a_update_device(dev); return sprintf(buf, "%ld\n", IN_FROM_REG(data->in_max[nr], nr));}static ssize_t set_in_min(struct device *dev, const char *buf, size_t count, int nr) { struct i2c_client *client = to_i2c_client(dev); struct via686a_data *data = i2c_get_clientdata(client); unsigned long val = simple_strtoul(buf, NULL, 10); data->in_min[nr] = IN_TO_REG(val,nr); via686a_write_value(client, VIA686A_REG_IN_MIN(nr), data->in_min[nr]); return count;}static ssize_t set_in_max(struct device *dev, const char *buf, size_t count, int nr) { struct i2c_client *client = to_i2c_client(dev); struct via686a_data *data = i2c_get_clientdata(client); unsigned long val = simple_strtoul(buf, NULL, 10); data->in_max[nr] = IN_TO_REG(val,nr); via686a_write_value(client, VIA686A_REG_IN_MAX(nr), data->in_max[nr]); return count;}#define show_in_offset(offset) \static ssize_t \ show_in##offset (struct device *dev, char *buf) \{ \ return show_in(dev, buf, 0x##offset); \} \static ssize_t \ show_in##offset##_min (struct device *dev, char *buf) \{ \ return show_in_min(dev, buf, 0x##offset); \} \static ssize_t \ show_in##offset##_max (struct device *dev, char *buf) \{ \ return show_in_max(dev, buf, 0x##offset); \} \static ssize_t set_in##offset##_min (struct device *dev, \ const char *buf, size_t count) \{ \ return set_in_min(dev, buf, count, 0x##offset); \} \static ssize_t set_in##offset##_max (struct device *dev, \ const char *buf, size_t count) \{ \ return set_in_max(dev, buf, count, 0x##offset); \} \static DEVICE_ATTR(in##offset##_input, S_IRUGO, show_in##offset, NULL);\static DEVICE_ATTR(in##offset##_min, S_IRUGO | S_IWUSR, \ show_in##offset##_min, set_in##offset##_min); \static DEVICE_ATTR(in##offset##_max, S_IRUGO | S_IWUSR, \ show_in##offset##_max, set_in##offset##_max);show_in_offset(0);show_in_offset(1);show_in_offset(2);show_in_offset(3);show_in_offset(4);/* 3 temperatures */static ssize_t show_temp(struct device *dev, char *buf, int nr) { struct via686a_data *data = via686a_update_device(dev); return sprintf(buf, "%ld\n", TEMP_FROM_REG10(data->temp[nr]));}static ssize_t show_temp_over(struct device *dev, char *buf, int nr) { struct via686a_data *data = via686a_update_device(dev); return sprintf(buf, "%ld\n", TEMP_FROM_REG(data->temp_over[nr]));}static ssize_t show_temp_hyst(struct device *dev, char *buf, int nr) { struct via686a_data *data = via686a_update_device(dev); return sprintf(buf, "%ld\n", TEMP_FROM_REG(data->temp_hyst[nr]));}static ssize_t set_temp_over(struct device *dev, const char *buf, size_t count, int nr) { struct i2c_client *client = to_i2c_client(dev); struct via686a_data *data = i2c_get_clientdata(client); int val = simple_strtol(buf, NULL, 10); data->temp_over[nr] = TEMP_TO_REG(val); via686a_write_value(client, VIA686A_REG_TEMP_OVER(nr), data->temp_over[nr]); return count;}static ssize_t set_temp_hyst(struct device *dev, const char *buf, size_t count, int nr) { struct i2c_client *client = to_i2c_client(dev); struct via686a_data *data = i2c_get_clientdata(client); int val = simple_strtol(buf, NULL, 10); data->temp_hyst[nr] = TEMP_TO_REG(val); via686a_write_value(client, VIA686A_REG_TEMP_HYST(nr), data->temp_hyst[nr]); return count;}#define show_temp_offset(offset) \static ssize_t show_temp_##offset (struct device *dev, char *buf) \{ \ return show_temp(dev, buf, 0x##offset - 1); \} \static ssize_t \show_temp_##offset##_over (struct device *dev, char *buf) \{ \ return show_temp_over(dev, buf, 0x##offset - 1); \} \static ssize_t \show_temp_##offset##_hyst (struct device *dev, char *buf) \{ \ return show_temp_hyst(dev, buf, 0x##offset - 1); \} \static ssize_t set_temp_##offset##_over (struct device *dev, \ const char *buf, size_t count) \{ \ return set_temp_over(dev, buf, count, 0x##offset - 1); \} \static ssize_t set_temp_##offset##_hyst (struct device *dev, \ const char *buf, size_t count) \{ \ return set_temp_hyst(dev, buf, count, 0x##offset - 1); \} \static DEVICE_ATTR(temp##offset##_input, S_IRUGO, show_temp_##offset, NULL);\static DEVICE_ATTR(temp##offset##_max, S_IRUGO | S_IWUSR, \ show_temp_##offset##_over, set_temp_##offset##_over); \static DEVICE_ATTR(temp##offset##_max_hyst, S_IRUGO | S_IWUSR, \ show_temp_##offset##_hyst, set_temp_##offset##_hyst); show_temp_offset(1);show_temp_offset(2);show_temp_offset(3);/* 2 Fans */static ssize_t show_fan(struct device *dev, char *buf, int nr) { struct via686a_data *data = via686a_update_device(dev); return sprintf(buf,"%d\n", FAN_FROM_REG(data->fan[nr], DIV_FROM_REG(data->fan_div[nr])) );}static ssize_t show_fan_min(struct device *dev, char *buf, int nr) { struct via686a_data *data = via686a_update_device(dev); return sprintf(buf,"%d\n", FAN_FROM_REG(data->fan_min[nr], DIV_FROM_REG(data->fan_div[nr])) );}static ssize_t show_fan_div(struct device *dev, char *buf, int nr) { struct via686a_data *data = via686a_update_device(dev); return sprintf(buf,"%d\n", DIV_FROM_REG(data->fan_div[nr]) );}static ssize_t set_fan_min(struct device *dev, const char *buf, size_t count, int nr) { struct i2c_client *client = to_i2c_client(dev); struct via686a_data *data = i2c_get_clientdata(client); int val = simple_strtol(buf, NULL, 10); data->fan_min[nr] = FAN_TO_REG(val, DIV_FROM_REG(data->fan_div[nr])); via686a_write_value(client, VIA686A_REG_FAN_MIN(nr+1), data->fan_min[nr]); return count;}static ssize_t set_fan_div(struct device *dev, const char *buf, size_t count, int nr) { struct i2c_client *client = to_i2c_client(dev); struct via686a_data *data = i2c_get_clientdata(client); int val = simple_strtol(buf, NULL, 10); int old = via686a_read_value(client, VIA686A_REG_FANDIV); data->fan_div[nr] = DIV_TO_REG(val); old = (old & 0x0f) | (data->fan_div[1] << 6) | (data->fan_div[0] << 4); via686a_write_value(client, VIA686A_REG_FANDIV, old); return count;}#define show_fan_offset(offset) \static ssize_t show_fan_##offset (struct device *dev, char *buf) \{ \ return show_fan(dev, buf, 0x##offset - 1); \} \static ssize_t show_fan_##offset##_min (struct device *dev, char *buf) \{ \ return show_fan_min(dev, buf, 0x##offset - 1); \} \static ssize_t show_fan_##offset##_div (struct device *dev, char *buf) \{ \ return show_fan_div(dev, buf, 0x##offset - 1); \} \static ssize_t set_fan_##offset##_min (struct device *dev, \ const char *buf, size_t count) \{ \ return set_fan_min(dev, buf, count, 0x##offset - 1); \} \static ssize_t set_fan_##offset##_div (struct device *dev, \ const char *buf, size_t count) \{ \ return set_fan_div(dev, buf, count, 0x##offset - 1); \} \static DEVICE_ATTR(fan##offset##_input, S_IRUGO, show_fan_##offset, NULL);\static DEVICE_ATTR(fan##offset##_min, S_IRUGO | S_IWUSR, \ show_fan_##offset##_min, set_fan_##offset##_min); \static DEVICE_ATTR(fan##offset##_div, S_IRUGO | S_IWUSR, \ show_fan_##offset##_div, set_fan_##offset##_div);show_fan_offset(1);show_fan_offset(2);/* Alarms */static ssize_t show_alarms(struct device *dev, char *buf) { struct via686a_data *data = via686a_update_device(dev); return sprintf(buf,"%d\n", ALARMS_FROM_REG(data->alarms));}static DEVICE_ATTR(alarms, S_IRUGO | S_IWUSR, show_alarms, NULL);/* The driver. I choose to use type i2c_driver, as at is identical to both smbus_driver and isa_driver, and clients could be of either kind */static struct i2c_driver via686a_driver = { .owner = THIS_MODULE, .name = "via686a", .id = I2C_DRIVERID_VIA686A, .flags = I2C_DF_NOTIFY, .attach_adapter = via686a_attach_adapter, .detach_client = via686a_detach_client,};
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -