fschmd.c
来自「linux 内核源代码」· C语言 代码 · 共 779 行 · 第 1/2 页
C
779 行
static ssize_t store_pwm_auto_point1_pwm(struct device *dev, struct device_attribute *devattr, const char *buf, size_t count){ int index = to_sensor_dev_attr(devattr)->index; struct fschmd_data *data = dev_get_drvdata(dev); unsigned long v = simple_strtoul(buf, NULL, 10); /* register: 0 = allow turning off, 1-255 = 50-100% */ if (v) { v = SENSORS_LIMIT(v, 128, 255); v = (v - 128) * 2 + 1; } mutex_lock(&data->update_lock); i2c_smbus_write_byte_data(&data->client, FSCHMD_REG_FAN_MIN[data->kind][index], v); data->fan_min[index] = v; mutex_unlock(&data->update_lock); return count;}/* The FSC hwmon family has the ability to force an attached alert led to flash from software, we export this as an alert_led sysfs attr */static ssize_t show_alert_led(struct device *dev, struct device_attribute *devattr, char *buf){ struct fschmd_data *data = fschmd_update_device(dev); if (data->global_control & FSCHMD_CONTROL_ALERT_LED_MASK) return sprintf(buf, "1\n"); else return sprintf(buf, "0\n");}static ssize_t store_alert_led(struct device *dev, struct device_attribute *devattr, const char *buf, size_t count){ u8 reg; struct fschmd_data *data = dev_get_drvdata(dev); unsigned long v = simple_strtoul(buf, NULL, 10); mutex_lock(&data->update_lock); reg = i2c_smbus_read_byte_data(&data->client, FSCHMD_REG_CONTROL); if (v) reg |= FSCHMD_CONTROL_ALERT_LED_MASK; else reg &= ~FSCHMD_CONTROL_ALERT_LED_MASK; i2c_smbus_write_byte_data(&data->client, FSCHMD_REG_CONTROL, reg); data->global_control = reg; mutex_unlock(&data->update_lock); return count;}static struct sensor_device_attribute fschmd_attr[] = { SENSOR_ATTR(in0_input, 0444, show_in_value, NULL, 0), SENSOR_ATTR(in1_input, 0444, show_in_value, NULL, 1), SENSOR_ATTR(in2_input, 0444, show_in_value, NULL, 2), SENSOR_ATTR(alert_led, 0644, show_alert_led, store_alert_led, 0),};static struct sensor_device_attribute fschmd_temp_attr[] = { SENSOR_ATTR(temp1_input, 0444, show_temp_value, NULL, 0), SENSOR_ATTR(temp1_max, 0644, show_temp_max, store_temp_max, 0), SENSOR_ATTR(temp1_fault, 0444, show_temp_fault, NULL, 0), SENSOR_ATTR(temp1_alarm, 0444, show_temp_alarm, NULL, 0), SENSOR_ATTR(temp2_input, 0444, show_temp_value, NULL, 1), SENSOR_ATTR(temp2_max, 0644, show_temp_max, store_temp_max, 1), SENSOR_ATTR(temp2_fault, 0444, show_temp_fault, NULL, 1), SENSOR_ATTR(temp2_alarm, 0444, show_temp_alarm, NULL, 1), SENSOR_ATTR(temp3_input, 0444, show_temp_value, NULL, 2), SENSOR_ATTR(temp3_max, 0644, show_temp_max, store_temp_max, 2), SENSOR_ATTR(temp3_fault, 0444, show_temp_fault, NULL, 2), SENSOR_ATTR(temp3_alarm, 0444, show_temp_alarm, NULL, 2), SENSOR_ATTR(temp4_input, 0444, show_temp_value, NULL, 3), SENSOR_ATTR(temp4_max, 0644, show_temp_max, store_temp_max, 3), SENSOR_ATTR(temp4_fault, 0444, show_temp_fault, NULL, 3), SENSOR_ATTR(temp4_alarm, 0444, show_temp_alarm, NULL, 3), SENSOR_ATTR(temp5_input, 0444, show_temp_value, NULL, 4), SENSOR_ATTR(temp5_max, 0644, show_temp_max, store_temp_max, 4), SENSOR_ATTR(temp5_fault, 0444, show_temp_fault, NULL, 4), SENSOR_ATTR(temp5_alarm, 0444, show_temp_alarm, NULL, 4),};static struct sensor_device_attribute fschmd_fan_attr[] = { SENSOR_ATTR(fan1_input, 0444, show_fan_value, NULL, 0), SENSOR_ATTR(fan1_div, 0644, show_fan_div, store_fan_div, 0), SENSOR_ATTR(fan1_alarm, 0444, show_fan_alarm, NULL, 0), SENSOR_ATTR(fan1_fault, 0444, show_fan_fault, NULL, 0), SENSOR_ATTR(pwm1_auto_point1_pwm, 0644, show_pwm_auto_point1_pwm, store_pwm_auto_point1_pwm, 0), SENSOR_ATTR(fan2_input, 0444, show_fan_value, NULL, 1), SENSOR_ATTR(fan2_div, 0644, show_fan_div, store_fan_div, 1), SENSOR_ATTR(fan2_alarm, 0444, show_fan_alarm, NULL, 1), SENSOR_ATTR(fan2_fault, 0444, show_fan_fault, NULL, 1), SENSOR_ATTR(pwm2_auto_point1_pwm, 0644, show_pwm_auto_point1_pwm, store_pwm_auto_point1_pwm, 1), SENSOR_ATTR(fan3_input, 0444, show_fan_value, NULL, 2), SENSOR_ATTR(fan3_div, 0644, show_fan_div, store_fan_div, 2), SENSOR_ATTR(fan3_alarm, 0444, show_fan_alarm, NULL, 2), SENSOR_ATTR(fan3_fault, 0444, show_fan_fault, NULL, 2), SENSOR_ATTR(pwm3_auto_point1_pwm, 0644, show_pwm_auto_point1_pwm, store_pwm_auto_point1_pwm, 2), SENSOR_ATTR(fan4_input, 0444, show_fan_value, NULL, 3), SENSOR_ATTR(fan4_div, 0644, show_fan_div, store_fan_div, 3), SENSOR_ATTR(fan4_alarm, 0444, show_fan_alarm, NULL, 3), SENSOR_ATTR(fan4_fault, 0444, show_fan_fault, NULL, 3), SENSOR_ATTR(pwm4_auto_point1_pwm, 0644, show_pwm_auto_point1_pwm, store_pwm_auto_point1_pwm, 3), SENSOR_ATTR(fan5_input, 0444, show_fan_value, NULL, 4), SENSOR_ATTR(fan5_div, 0644, show_fan_div, store_fan_div, 4), SENSOR_ATTR(fan5_alarm, 0444, show_fan_alarm, NULL, 4), SENSOR_ATTR(fan5_fault, 0444, show_fan_fault, NULL, 4), SENSOR_ATTR(pwm5_auto_point1_pwm, 0644, show_pwm_auto_point1_pwm, store_pwm_auto_point1_pwm, 4), SENSOR_ATTR(fan6_input, 0444, show_fan_value, NULL, 5), SENSOR_ATTR(fan6_div, 0644, show_fan_div, store_fan_div, 5), SENSOR_ATTR(fan6_alarm, 0444, show_fan_alarm, NULL, 5), SENSOR_ATTR(fan6_fault, 0444, show_fan_fault, NULL, 5), SENSOR_ATTR(pwm6_auto_point1_pwm, 0644, show_pwm_auto_point1_pwm, store_pwm_auto_point1_pwm, 5),};/* * Real code */static int fschmd_detect(struct i2c_adapter *adapter, int address, int kind){ struct i2c_client *client; struct fschmd_data *data; u8 revision; const char * const names[5] = { "Poseidon", "Hermes", "Scylla", "Heracles", "Heimdall" }; const char * const client_names[5] = { "fscpos", "fscher", "fscscy", "fschrc", "fschmd" }; int i, err = 0; if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA)) return 0; /* OK. For now, we presume we have a valid client. We now create the * client structure, even though we cannot fill it completely yet. * But it allows us to access i2c_smbus_read_byte_data. */ if (!(data = kzalloc(sizeof(struct fschmd_data), GFP_KERNEL))) return -ENOMEM; client = &data->client; i2c_set_clientdata(client, data); client->addr = address; client->adapter = adapter; client->driver = &fschmd_driver; mutex_init(&data->update_lock); /* Detect & Identify the chip */ if (kind <= 0) { char id[4]; id[0] = i2c_smbus_read_byte_data(client, FSCHMD_REG_IDENT_0); id[1] = i2c_smbus_read_byte_data(client, FSCHMD_REG_IDENT_1); id[2] = i2c_smbus_read_byte_data(client, FSCHMD_REG_IDENT_2); id[3] = '\0'; if (!strcmp(id, "PEG")) kind = fscpos; else if (!strcmp(id, "HER")) kind = fscher; else if (!strcmp(id, "SCY")) kind = fscscy; else if (!strcmp(id, "HRC")) kind = fschrc; else if (!strcmp(id, "HMD")) kind = fschmd; else goto exit_free; } if (kind == fscpos) { /* The Poseidon has hardwired temp limits, fill these in for the alarm resetting code */ data->temp_max[0] = 70 + 128; data->temp_max[1] = 50 + 128; data->temp_max[2] = 50 + 128; } /* i2c kind goes from 1-5, we want from 0-4 to address arrays */ data->kind = kind - 1; strlcpy(client->name, client_names[data->kind], I2C_NAME_SIZE); /* Tell the I2C layer a new client has arrived */ if ((err = i2c_attach_client(client))) goto exit_free; for (i = 0; i < ARRAY_SIZE(fschmd_attr); i++) { err = device_create_file(&client->dev, &fschmd_attr[i].dev_attr); if (err) goto exit_detach; } for (i = 0; i < (FSCHMD_NO_TEMP_SENSORS[data->kind] * 4); i++) { /* Poseidon doesn't have TEMP_LIMIT registers */ if (kind == fscpos && fschmd_temp_attr[i].dev_attr.show == show_temp_max) continue; err = device_create_file(&client->dev, &fschmd_temp_attr[i].dev_attr); if (err) goto exit_detach; } for (i = 0; i < (FSCHMD_NO_FAN_SENSORS[data->kind] * 5); i++) { /* Poseidon doesn't have a FAN_MIN register for its 3rd fan */ if (kind == fscpos && !strcmp(fschmd_fan_attr[i].dev_attr.attr.name, "pwm3_auto_point1_pwm")) continue; err = device_create_file(&client->dev, &fschmd_fan_attr[i].dev_attr); if (err) goto exit_detach; } data->hwmon_dev = hwmon_device_register(&client->dev); if (IS_ERR(data->hwmon_dev)) { err = PTR_ERR(data->hwmon_dev); data->hwmon_dev = NULL; goto exit_detach; } revision = i2c_smbus_read_byte_data(client, FSCHMD_REG_REVISION); printk(KERN_INFO FSCHMD_NAME ": Detected FSC %s chip, revision: %d\n", names[data->kind], (int) revision); return 0;exit_detach: fschmd_detach_client(client); /* will also free data for us */ return err;exit_free: kfree(data); return err;}static int fschmd_attach_adapter(struct i2c_adapter *adapter){ if (!(adapter->class & I2C_CLASS_HWMON)) return 0; return i2c_probe(adapter, &addr_data, fschmd_detect);}static int fschmd_detach_client(struct i2c_client *client){ struct fschmd_data *data = i2c_get_clientdata(client); int i, err; /* Check if registered in case we're called from fschmd_detect to cleanup after an error */ if (data->hwmon_dev) hwmon_device_unregister(data->hwmon_dev); for (i = 0; i < ARRAY_SIZE(fschmd_attr); i++) device_remove_file(&client->dev, &fschmd_attr[i].dev_attr); for (i = 0; i < (FSCHMD_NO_TEMP_SENSORS[data->kind] * 4); i++) device_remove_file(&client->dev, &fschmd_temp_attr[i].dev_attr); for (i = 0; i < (FSCHMD_NO_FAN_SENSORS[data->kind] * 5); i++) device_remove_file(&client->dev, &fschmd_fan_attr[i].dev_attr); if ((err = i2c_detach_client(client))) return err; kfree(data); return 0;}static struct fschmd_data *fschmd_update_device(struct device *dev){ struct i2c_client *client = to_i2c_client(dev); struct fschmd_data *data = i2c_get_clientdata(client); int i; mutex_lock(&data->update_lock); if (time_after(jiffies, data->last_updated + 2 * HZ) || !data->valid) { for (i = 0; i < FSCHMD_NO_TEMP_SENSORS[data->kind]; i++) { data->temp_act[i] = i2c_smbus_read_byte_data(client, FSCHMD_REG_TEMP_ACT[data->kind][i]); data->temp_status[i] = i2c_smbus_read_byte_data(client, FSCHMD_REG_TEMP_STATE[data->kind][i]); /* The fscpos doesn't have TEMP_LIMIT registers */ if (FSCHMD_REG_TEMP_LIMIT[data->kind][i]) data->temp_max[i] = i2c_smbus_read_byte_data( client, FSCHMD_REG_TEMP_LIMIT[data->kind][i]); /* reset alarm if the alarm condition is gone, the chip doesn't do this itself */ if ((data->temp_status[i] & FSCHMD_TEMP_ALARM_MASK) == FSCHMD_TEMP_ALARM_MASK && data->temp_act[i] < data->temp_max[i]) i2c_smbus_write_byte_data(client, FSCHMD_REG_TEMP_STATE[data->kind][i], FSCHMD_TEMP_ALERT_MASK); } for (i = 0; i < FSCHMD_NO_FAN_SENSORS[data->kind]; i++) { data->fan_act[i] = i2c_smbus_read_byte_data(client, FSCHMD_REG_FAN_ACT[data->kind][i]); data->fan_status[i] = i2c_smbus_read_byte_data(client, FSCHMD_REG_FAN_STATE[data->kind][i]); data->fan_ripple[i] = i2c_smbus_read_byte_data(client, FSCHMD_REG_FAN_RIPPLE[data->kind][i]); /* The fscpos third fan doesn't have a fan_min */ if (FSCHMD_REG_FAN_MIN[data->kind][i]) data->fan_min[i] = i2c_smbus_read_byte_data( client, FSCHMD_REG_FAN_MIN[data->kind][i]); /* reset fan status if speed is back to > 0 */ if ((data->fan_status[i] & FSCHMD_FAN_ALARM_MASK) && data->fan_act[i]) i2c_smbus_write_byte_data(client, FSCHMD_REG_FAN_STATE[data->kind][i], FSCHMD_FAN_ALARM_MASK); } for (i = 0; i < 3; i++) data->volt[i] = i2c_smbus_read_byte_data(client, FSCHMD_REG_VOLT[i]); data->global_control = i2c_smbus_read_byte_data(client, FSCHMD_REG_CONTROL); /* To be implemented in the future data->watchdog[0] = i2c_smbus_read_byte_data(client, FSCHMD_REG_WDOG_PRESET); data->watchdog[1] = i2c_smbus_read_byte_data(client, FSCHMD_REG_WDOG_STATE); data->watchdog[2] = i2c_smbus_read_byte_data(client, FSCHMD_REG_WDOG_CONTROL); */ data->last_updated = jiffies; data->valid = 1; } mutex_unlock(&data->update_lock); return data;}static int __init fschmd_init(void){ return i2c_add_driver(&fschmd_driver);}static void __exit fschmd_exit(void){ i2c_del_driver(&fschmd_driver);}MODULE_AUTHOR("Hans de Goede <j.w.r.degoede@hhs.nl>");MODULE_DESCRIPTION("FSC Poseidon, Hermes, Scylla, Heracles and " "Heimdall driver");MODULE_LICENSE("GPL");module_init(fschmd_init);module_exit(fschmd_exit);
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?