fscher.c

来自「linux 内核源代码」· C语言 代码 · 共 691 行 · 第 1/2 页

C
691
字号
	data->hwmon_dev = hwmon_device_register(&new_client->dev);	if (IS_ERR(data->hwmon_dev)) {		err = PTR_ERR(data->hwmon_dev);		goto exit_remove_files;	}	return 0;exit_remove_files:	sysfs_remove_group(&new_client->dev.kobj, &fscher_group);exit_detach:	i2c_detach_client(new_client);exit_free:	kfree(data);exit:	return err;}static int fscher_detach_client(struct i2c_client *client){	struct fscher_data *data = i2c_get_clientdata(client);	int err;	hwmon_device_unregister(data->hwmon_dev);	sysfs_remove_group(&client->dev.kobj, &fscher_group);	if ((err = i2c_detach_client(client)))		return err;	kfree(data);	return 0;}static int fscher_read_value(struct i2c_client *client, u8 reg){	dev_dbg(&client->dev, "read reg 0x%02x\n", reg);	return i2c_smbus_read_byte_data(client, reg);}static int fscher_write_value(struct i2c_client *client, u8 reg, u8 value){	dev_dbg(&client->dev, "write reg 0x%02x, val 0x%02x\n",		reg, value);	return i2c_smbus_write_byte_data(client, reg, value);}/* Called when we have found a new FSC Hermes. */static void fscher_init_client(struct i2c_client *client){	struct fscher_data *data = i2c_get_clientdata(client);	/* Read revision from chip */	data->revision =  fscher_read_value(client, FSCHER_REG_REVISION);}static struct fscher_data *fscher_update_device(struct device *dev){	struct i2c_client *client = to_i2c_client(dev);	struct fscher_data *data = i2c_get_clientdata(client);	mutex_lock(&data->update_lock);	if (time_after(jiffies, data->last_updated + 2 * HZ) || !data->valid) {		dev_dbg(&client->dev, "Starting fscher update\n");		data->temp_act[0] = fscher_read_value(client, FSCHER_REG_TEMP0_ACT);		data->temp_act[1] = fscher_read_value(client, FSCHER_REG_TEMP1_ACT);		data->temp_act[2] = fscher_read_value(client, FSCHER_REG_TEMP2_ACT);		data->temp_status[0] = fscher_read_value(client, FSCHER_REG_TEMP0_STATE);		data->temp_status[1] = fscher_read_value(client, FSCHER_REG_TEMP1_STATE);		data->temp_status[2] = fscher_read_value(client, FSCHER_REG_TEMP2_STATE);		data->volt[0] = fscher_read_value(client, FSCHER_REG_VOLT_12);		data->volt[1] = fscher_read_value(client, FSCHER_REG_VOLT_5);		data->volt[2] = fscher_read_value(client, FSCHER_REG_VOLT_BATT);		data->fan_act[0] = fscher_read_value(client, FSCHER_REG_FAN0_ACT);		data->fan_act[1] = fscher_read_value(client, FSCHER_REG_FAN1_ACT);		data->fan_act[2] = fscher_read_value(client, FSCHER_REG_FAN2_ACT);		data->fan_status[0] = fscher_read_value(client, FSCHER_REG_FAN0_STATE);		data->fan_status[1] = fscher_read_value(client, FSCHER_REG_FAN1_STATE);		data->fan_status[2] = fscher_read_value(client, FSCHER_REG_FAN2_STATE);		data->fan_min[0] = fscher_read_value(client, FSCHER_REG_FAN0_MIN);		data->fan_min[1] = fscher_read_value(client, FSCHER_REG_FAN1_MIN);		data->fan_min[2] = fscher_read_value(client, FSCHER_REG_FAN2_MIN);		data->fan_ripple[0] = fscher_read_value(client, FSCHER_REG_FAN0_RIPPLE);		data->fan_ripple[1] = fscher_read_value(client, FSCHER_REG_FAN1_RIPPLE);		data->fan_ripple[2] = fscher_read_value(client, FSCHER_REG_FAN2_RIPPLE);		data->watchdog[0] = fscher_read_value(client, FSCHER_REG_WDOG_PRESET);		data->watchdog[1] = fscher_read_value(client, FSCHER_REG_WDOG_STATE);		data->watchdog[2] = fscher_read_value(client, FSCHER_REG_WDOG_CONTROL);		data->global_event = fscher_read_value(client, FSCHER_REG_EVENT_STATE);		data->global_control = fscher_read_value(client,							FSCHER_REG_CONTROL);		data->last_updated = jiffies;		data->valid = 1;                 	}	mutex_unlock(&data->update_lock);	return data;}#define FAN_INDEX_FROM_NUM(nr)	((nr) - 1)static ssize_t set_fan_status(struct i2c_client *client, struct fscher_data *data,			      const char *buf, size_t count, int nr, int reg){	/* bits 0..1, 3..7 reserved => mask with 0x04 */  	unsigned long v = simple_strtoul(buf, NULL, 10) & 0x04;		mutex_lock(&data->update_lock);	data->fan_status[FAN_INDEX_FROM_NUM(nr)] &= ~v;	fscher_write_value(client, reg, v);	mutex_unlock(&data->update_lock);	return count;}static ssize_t show_fan_status(struct fscher_data *data, char *buf, int nr){	/* bits 0..1, 3..7 reserved => mask with 0x04 */  	return sprintf(buf, "%u\n", data->fan_status[FAN_INDEX_FROM_NUM(nr)] & 0x04);}static ssize_t set_pwm(struct i2c_client *client, struct fscher_data *data,		       const char *buf, size_t count, int nr, int reg){	unsigned long v = simple_strtoul(buf, NULL, 10);	mutex_lock(&data->update_lock);	data->fan_min[FAN_INDEX_FROM_NUM(nr)] = v > 0xff ? 0xff : v;	fscher_write_value(client, reg, data->fan_min[FAN_INDEX_FROM_NUM(nr)]);	mutex_unlock(&data->update_lock);	return count;}static ssize_t show_pwm(struct fscher_data *data, char *buf, int nr){	return sprintf(buf, "%u\n", data->fan_min[FAN_INDEX_FROM_NUM(nr)]);}static ssize_t set_fan_div(struct i2c_client *client, struct fscher_data *data,			   const char *buf, size_t count, int nr, int reg){	/* supported values: 2, 4, 8 */	unsigned long v = simple_strtoul(buf, NULL, 10);	switch (v) {	case 2: v = 1; break;	case 4: v = 2; break;	case 8: v = 3; break;	default:		dev_err(&client->dev, "fan_div value %ld not "			 "supported. Choose one of 2, 4 or 8!\n", v);		return -EINVAL;	}	mutex_lock(&data->update_lock);	/* bits 2..7 reserved => mask with 0x03 */	data->fan_ripple[FAN_INDEX_FROM_NUM(nr)] &= ~0x03;	data->fan_ripple[FAN_INDEX_FROM_NUM(nr)] |= v;	fscher_write_value(client, reg, data->fan_ripple[FAN_INDEX_FROM_NUM(nr)]);	mutex_unlock(&data->update_lock);	return count;}static ssize_t show_fan_div(struct fscher_data *data, char *buf, int nr){	/* bits 2..7 reserved => mask with 0x03 */  	return sprintf(buf, "%u\n", 1 << (data->fan_ripple[FAN_INDEX_FROM_NUM(nr)] & 0x03));}#define RPM_FROM_REG(val)	(val*60)static ssize_t show_fan_input (struct fscher_data *data, char *buf, int nr){	return sprintf(buf, "%u\n", RPM_FROM_REG(data->fan_act[FAN_INDEX_FROM_NUM(nr)]));}#define TEMP_INDEX_FROM_NUM(nr)		((nr) - 1)static ssize_t set_temp_status(struct i2c_client *client, struct fscher_data *data,			       const char *buf, size_t count, int nr, int reg){	/* bits 2..7 reserved, 0 read only => mask with 0x02 */  	unsigned long v = simple_strtoul(buf, NULL, 10) & 0x02;	mutex_lock(&data->update_lock);	data->temp_status[TEMP_INDEX_FROM_NUM(nr)] &= ~v;	fscher_write_value(client, reg, v);	mutex_unlock(&data->update_lock);	return count;}static ssize_t show_temp_status(struct fscher_data *data, char *buf, int nr){	/* bits 2..7 reserved => mask with 0x03 */	return sprintf(buf, "%u\n", data->temp_status[TEMP_INDEX_FROM_NUM(nr)] & 0x03);}#define TEMP_FROM_REG(val)	(((val) - 128) * 1000)static ssize_t show_temp_input(struct fscher_data *data, char *buf, int nr){	return sprintf(buf, "%d\n", TEMP_FROM_REG(data->temp_act[TEMP_INDEX_FROM_NUM(nr)]));}/* * The final conversion is specified in sensors.conf, as it depends on * mainboard specific values. We export the registers contents as * pseudo-hundredths-of-Volts (range 0V - 2.55V). Not that it makes much * sense per se, but it minimizes the conversions count and keeps the * values within a usual range. */#define VOLT_FROM_REG(val)	((val) * 10)static ssize_t show_in_input(struct fscher_data *data, char *buf, int nr){	return sprintf(buf, "%u\n", VOLT_FROM_REG(data->volt[nr]));}static ssize_t show_revision(struct fscher_data *data, char *buf, int nr){	return sprintf(buf, "%u\n", data->revision);}static ssize_t show_alarms(struct fscher_data *data, char *buf, int nr){	/* bits 2, 5..6 reserved => mask with 0x9b */	return sprintf(buf, "%u\n", data->global_event & 0x9b);}static ssize_t set_control(struct i2c_client *client, struct fscher_data *data,			   const char *buf, size_t count, int nr, int reg){	/* bits 1..7 reserved => mask with 0x01 */  	unsigned long v = simple_strtoul(buf, NULL, 10) & 0x01;	mutex_lock(&data->update_lock);	data->global_control = v;	fscher_write_value(client, reg, v);	mutex_unlock(&data->update_lock);	return count;}static ssize_t show_control(struct fscher_data *data, char *buf, int nr){	/* bits 1..7 reserved => mask with 0x01 */	return sprintf(buf, "%u\n", data->global_control & 0x01);}static ssize_t set_watchdog_control(struct i2c_client *client, struct				    fscher_data *data, const char *buf, size_t count,				    int nr, int reg){	/* bits 0..3 reserved => mask with 0xf0 */  	unsigned long v = simple_strtoul(buf, NULL, 10) & 0xf0;	mutex_lock(&data->update_lock);	data->watchdog[2] &= ~0xf0;	data->watchdog[2] |= v;	fscher_write_value(client, reg, data->watchdog[2]);	mutex_unlock(&data->update_lock);	return count;}static ssize_t show_watchdog_control(struct fscher_data *data, char *buf, int nr){	/* bits 0..3 reserved, bit 5 write only => mask with 0xd0 */	return sprintf(buf, "%u\n", data->watchdog[2] & 0xd0);}static ssize_t set_watchdog_status(struct i2c_client *client, struct fscher_data *data,				   const char *buf, size_t count, int nr, int reg){	/* bits 0, 2..7 reserved => mask with 0x02 */  	unsigned long v = simple_strtoul(buf, NULL, 10) & 0x02;	mutex_lock(&data->update_lock);	data->watchdog[1] &= ~v;	fscher_write_value(client, reg, v);	mutex_unlock(&data->update_lock);	return count;}static ssize_t show_watchdog_status(struct fscher_data *data, char *buf, int nr){	/* bits 0, 2..7 reserved => mask with 0x02 */	return sprintf(buf, "%u\n", data->watchdog[1] & 0x02);}static ssize_t set_watchdog_preset(struct i2c_client *client, struct fscher_data *data,				   const char *buf, size_t count, int nr, int reg){	unsigned long v = simple_strtoul(buf, NULL, 10) & 0xff;		mutex_lock(&data->update_lock);	data->watchdog[0] = v;	fscher_write_value(client, reg, data->watchdog[0]);	mutex_unlock(&data->update_lock);	return count;}static ssize_t show_watchdog_preset(struct fscher_data *data, char *buf, int nr){	return sprintf(buf, "%u\n", data->watchdog[0]);}static int __init sensors_fscher_init(void){	return i2c_add_driver(&fscher_driver);}static void __exit sensors_fscher_exit(void){	i2c_del_driver(&fscher_driver);}MODULE_AUTHOR("Reinhard Nissl <rnissl@gmx.de>");MODULE_DESCRIPTION("FSC Hermes driver");MODULE_LICENSE("GPL");module_init(sensors_fscher_init);module_exit(sensors_fscher_exit);

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?