From 08c79950a047dbaccf05d70a203db2ee75ac3bd8 Mon Sep 17 00:00:00 2001 From: Rudolf Marek Date: Wed, 5 Jul 2006 18:14:31 +0200 Subject: [PATCH 01/39] hwmon: Add fan speed control features to w83627ehf This patch adds long-awaited support for automatic fan modes. Based on the work of Yuan Mu from Winbond, I finished the support with the great help of David Hubbard. Signed-off-by: Yuan Mu Signed-off-by: Rudolf Marek Signed-off-by: David Hubbard Signed-off-by: Jean Delvare Signed-off-by: Greg Kroah-Hartman --- drivers/hwmon/w83627ehf.c | 393 ++++++++++++++++++++++++++++++++++++-- 1 file changed, 382 insertions(+), 11 deletions(-) diff --git a/drivers/hwmon/w83627ehf.c b/drivers/hwmon/w83627ehf.c index b21d6b9d7eac..23824183e02f 100644 --- a/drivers/hwmon/w83627ehf.c +++ b/drivers/hwmon/w83627ehf.c @@ -2,6 +2,8 @@ w83627ehf - Driver for the hardware monitoring functionality of the Winbond W83627EHF Super-I/O chip Copyright (C) 2005 Jean Delvare + Copyright (C) 2006 Yuan Mu , + Rudolf Marek Shamelessly ripped from the w83627hf driver Copyright (C) 2003 Mark Studebaker @@ -29,8 +31,8 @@ Supports the following chips: - Chip #vin #fan #pwm #temp chip_id man_id - w83627ehf 10 5 - 3 0x88 0x5ca3 + Chip #vin #fan #pwm #temp chip_id man_id + w83627ehf 10 5 4 3 0x88,0xa1 0x5ca3 */ #include @@ -145,10 +147,44 @@ static const u16 W83627EHF_REG_TEMP_CONFIG[] = { 0x152, 0x252 }; #define W83627EHF_REG_ALARM2 0x45A #define W83627EHF_REG_ALARM3 0x45B +/* SmartFan registers */ +/* DC or PWM output fan configuration */ +static const u8 W83627EHF_REG_PWM_ENABLE[] = { + 0x04, /* SYS FAN0 output mode and PWM mode */ + 0x04, /* CPU FAN0 output mode and PWM mode */ + 0x12, /* AUX FAN mode */ + 0x62, /* CPU fan1 mode */ +}; + +static const u8 W83627EHF_PWM_MODE_SHIFT[] = { 0, 1, 0, 6 }; +static const u8 W83627EHF_PWM_ENABLE_SHIFT[] = { 2, 4, 1, 4 }; + +/* FAN Duty Cycle, be used to control */ +static const u8 W83627EHF_REG_PWM[] = { 0x01, 0x03, 0x11, 0x61 }; +static const u8 W83627EHF_REG_TARGET[] = { 0x05, 0x06, 0x13, 0x63 }; +static const u8 W83627EHF_REG_TOLERANCE[] = { 0x07, 0x07, 0x14, 0x62 }; + + +/* Advanced Fan control, some values are common for all fans */ +static const u8 W83627EHF_REG_FAN_MIN_OUTPUT[] = { 0x08, 0x09, 0x15, 0x64 }; +static const u8 W83627EHF_REG_FAN_STOP_TIME[] = { 0x0C, 0x0D, 0x17, 0x66 }; + /* * Conversions */ +/* 1 is PWM mode, output in ms */ +static inline unsigned int step_time_from_reg(u8 reg, u8 mode) +{ + return mode ? 100 * reg : 400 * reg; +} + +static inline u8 step_time_to_reg(unsigned int msec, u8 mode) +{ + return SENSORS_LIMIT((mode ? (msec + 50) / 100 : + (msec + 200) / 400), 1, 255); +} + static inline unsigned int fan_from_reg(u8 reg, unsigned int div) { @@ -170,12 +206,12 @@ temp1_from_reg(s8 reg) } static inline s8 -temp1_to_reg(int temp) +temp1_to_reg(int temp, int min, int max) { - if (temp <= -128000) - return -128; - if (temp >= 127000) - return 127; + if (temp <= min) + return min / 1000; + if (temp >= max) + return max / 1000; if (temp < 0) return (temp - 500) / 1000; return (temp + 500) / 1000; @@ -223,6 +259,16 @@ struct w83627ehf_data { s16 temp_max[2]; s16 temp_max_hyst[2]; u32 alarms; + + u8 pwm_mode[4]; /* 0->DC variable voltage, 1->PWM variable duty cycle */ + u8 pwm_enable[4]; /* 1->manual + 2->thermal cruise (also called SmartFan I) */ + u8 pwm[4]; + u8 target_temp[4]; + u8 tolerance[4]; + + u8 fan_min_output[4]; /* minimum fan speed */ + u8 fan_stop_time[4]; }; static inline int is_word_sized(u16 reg) @@ -349,6 +395,7 @@ static struct w83627ehf_data *w83627ehf_update_device(struct device *dev) { struct i2c_client *client = to_i2c_client(dev); struct w83627ehf_data *data = i2c_get_clientdata(client); + int pwmcfg = 0, tolerance = 0; /* shut up the compiler */ int i; mutex_lock(&data->update_lock); @@ -416,6 +463,34 @@ static struct w83627ehf_data *w83627ehf_update_device(struct device *dev) } } + for (i = 0; i < 4; i++) { + /* pwmcfg, tolarance mapped for i=0, i=1 to same reg */ + if (i != 1) { + pwmcfg = w83627ehf_read_value(client, + W83627EHF_REG_PWM_ENABLE[i]); + tolerance = w83627ehf_read_value(client, + W83627EHF_REG_TOLERANCE[i]); + } + data->pwm_mode[i] = + ((pwmcfg >> W83627EHF_PWM_MODE_SHIFT[i]) & 1) + ? 0 : 1; + data->pwm_enable[i] = + ((pwmcfg >> W83627EHF_PWM_ENABLE_SHIFT[i]) + & 3) + 1; + data->pwm[i] = w83627ehf_read_value(client, + W83627EHF_REG_PWM[i]); + data->fan_min_output[i] = w83627ehf_read_value(client, + W83627EHF_REG_FAN_MIN_OUTPUT[i]); + data->fan_stop_time[i] = w83627ehf_read_value(client, + W83627EHF_REG_FAN_STOP_TIME[i]); + data->target_temp[i] = + w83627ehf_read_value(client, + W83627EHF_REG_TARGET[i]) & + (data->pwm_mode[i] == 1 ? 0x7f : 0xff); + data->tolerance[i] = (tolerance >> (i == 1 ? 4 : 0)) + & 0x0f; + } + /* Measured temperatures and limits */ data->temp1 = w83627ehf_read_value(client, W83627EHF_REG_TEMP1); @@ -711,7 +786,7 @@ store_temp1_##reg(struct device *dev, struct device_attribute *attr, \ u32 val = simple_strtoul(buf, NULL, 10); \ \ mutex_lock(&data->update_lock); \ - data->temp1_##reg = temp1_to_reg(val); \ + data->temp1_##reg = temp1_to_reg(val, -128000, 127000); \ w83627ehf_write_value(client, W83627EHF_REG_TEMP1_##REG, \ data->temp1_##reg); \ mutex_unlock(&data->update_lock); \ @@ -777,6 +852,281 @@ static struct sensor_device_attribute sda_temp[] = { SENSOR_ATTR(temp3_alarm, S_IRUGO, show_alarm, NULL, 13), }; +#define show_pwm_reg(reg) \ +static ssize_t show_##reg (struct device *dev, struct device_attribute *attr, \ + char *buf) \ +{ \ + struct w83627ehf_data *data = w83627ehf_update_device(dev); \ + struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr); \ + int nr = sensor_attr->index; \ + return sprintf(buf, "%d\n", data->reg[nr]); \ +} + +show_pwm_reg(pwm_mode) +show_pwm_reg(pwm_enable) +show_pwm_reg(pwm) + +static ssize_t +store_pwm_mode(struct device *dev, struct device_attribute *attr, + const char *buf, size_t count) +{ + struct i2c_client *client = to_i2c_client(dev); + struct w83627ehf_data *data = i2c_get_clientdata(client); + struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr); + int nr = sensor_attr->index; + u32 val = simple_strtoul(buf, NULL, 10); + u16 reg; + + if (val > 1) + return -EINVAL; + mutex_lock(&data->update_lock); + reg = w83627ehf_read_value(client, W83627EHF_REG_PWM_ENABLE[nr]); + data->pwm_mode[nr] = val; + reg &= ~(1 << W83627EHF_PWM_MODE_SHIFT[nr]); + if (!val) + reg |= 1 << W83627EHF_PWM_MODE_SHIFT[nr]; + w83627ehf_write_value(client, W83627EHF_REG_PWM_ENABLE[nr], reg); + mutex_unlock(&data->update_lock); + return count; +} + +static ssize_t +store_pwm(struct device *dev, struct device_attribute *attr, + const char *buf, size_t count) +{ + struct i2c_client *client = to_i2c_client(dev); + struct w83627ehf_data *data = i2c_get_clientdata(client); + struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr); + int nr = sensor_attr->index; + u32 val = SENSORS_LIMIT(simple_strtoul(buf, NULL, 10), 0, 255); + + mutex_lock(&data->update_lock); + data->pwm[nr] = val; + w83627ehf_write_value(client, W83627EHF_REG_PWM[nr], val); + mutex_unlock(&data->update_lock); + return count; +} + +static ssize_t +store_pwm_enable(struct device *dev, struct device_attribute *attr, + const char *buf, size_t count) +{ + struct i2c_client *client = to_i2c_client(dev); + struct w83627ehf_data *data = i2c_get_clientdata(client); + struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr); + int nr = sensor_attr->index; + u32 val = simple_strtoul(buf, NULL, 10); + u16 reg; + + if (!val || (val > 2)) /* only modes 1 and 2 are supported */ + return -EINVAL; + mutex_lock(&data->update_lock); + reg = w83627ehf_read_value(client, W83627EHF_REG_PWM_ENABLE[nr]); + data->pwm_enable[nr] = val; + reg &= ~(0x03 << W83627EHF_PWM_ENABLE_SHIFT[nr]); + reg |= (val - 1) << W83627EHF_PWM_ENABLE_SHIFT[nr]; + w83627ehf_write_value(client, W83627EHF_REG_PWM_ENABLE[nr], reg); + mutex_unlock(&data->update_lock); + return count; +} + + +#define show_tol_temp(reg) \ +static ssize_t show_##reg(struct device *dev, struct device_attribute *attr, \ + char *buf) \ +{ \ + struct w83627ehf_data *data = w83627ehf_update_device(dev); \ + struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr); \ + int nr = sensor_attr->index; \ + return sprintf(buf, "%d\n", temp1_from_reg(data->reg[nr])); \ +} + +show_tol_temp(tolerance) +show_tol_temp(target_temp) + +static ssize_t +store_target_temp(struct device *dev, struct device_attribute *attr, + const char *buf, size_t count) +{ + struct i2c_client *client = to_i2c_client(dev); + struct w83627ehf_data *data = i2c_get_clientdata(client); + struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr); + int nr = sensor_attr->index; + u8 val = temp1_to_reg(simple_strtoul(buf, NULL, 10), 0, 127000); + + mutex_lock(&data->update_lock); + data->target_temp[nr] = val; + w83627ehf_write_value(client, W83627EHF_REG_TARGET[nr], val); + mutex_unlock(&data->update_lock); + return count; +} + +static ssize_t +store_tolerance(struct device *dev, struct device_attribute *attr, + const char *buf, size_t count) +{ + struct i2c_client *client = to_i2c_client(dev); + struct w83627ehf_data *data = i2c_get_clientdata(client); + struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr); + int nr = sensor_attr->index; + u16 reg; + /* Limit the temp to 0C - 15C */ + u8 val = temp1_to_reg(simple_strtoul(buf, NULL, 10), 0, 15000); + + mutex_lock(&data->update_lock); + reg = w83627ehf_read_value(client, W83627EHF_REG_TOLERANCE[nr]); + data->tolerance[nr] = val; + if (nr == 1) + reg = (reg & 0x0f) | (val << 4); + else + reg = (reg & 0xf0) | val; + w83627ehf_write_value(client, W83627EHF_REG_TOLERANCE[nr], reg); + mutex_unlock(&data->update_lock); + return count; +} + +static struct sensor_device_attribute sda_pwm[] = { + SENSOR_ATTR(pwm1, S_IWUSR | S_IRUGO, show_pwm, store_pwm, 0), + SENSOR_ATTR(pwm2, S_IWUSR | S_IRUGO, show_pwm, store_pwm, 1), + SENSOR_ATTR(pwm3, S_IWUSR | S_IRUGO, show_pwm, store_pwm, 2), + SENSOR_ATTR(pwm4, S_IWUSR | S_IRUGO, show_pwm, store_pwm, 3), +}; + +static struct sensor_device_attribute sda_pwm_mode[] = { + SENSOR_ATTR(pwm1_mode, S_IWUSR | S_IRUGO, show_pwm_mode, + store_pwm_mode, 0), + SENSOR_ATTR(pwm2_mode, S_IWUSR | S_IRUGO, show_pwm_mode, + store_pwm_mode, 1), + SENSOR_ATTR(pwm3_mode, S_IWUSR | S_IRUGO, show_pwm_mode, + store_pwm_mode, 2), + SENSOR_ATTR(pwm4_mode, S_IWUSR | S_IRUGO, show_pwm_mode, + store_pwm_mode, 3), +}; + +static struct sensor_device_attribute sda_pwm_enable[] = { + SENSOR_ATTR(pwm1_enable, S_IWUSR | S_IRUGO, show_pwm_enable, + store_pwm_enable, 0), + SENSOR_ATTR(pwm2_enable, S_IWUSR | S_IRUGO, show_pwm_enable, + store_pwm_enable, 1), + SENSOR_ATTR(pwm3_enable, S_IWUSR | S_IRUGO, show_pwm_enable, + store_pwm_enable, 2), + SENSOR_ATTR(pwm4_enable, S_IWUSR | S_IRUGO, show_pwm_enable, + store_pwm_enable, 3), +}; + +static struct sensor_device_attribute sda_target_temp[] = { + SENSOR_ATTR(pwm1_target, S_IWUSR | S_IRUGO, show_target_temp, + store_target_temp, 0), + SENSOR_ATTR(pwm2_target, S_IWUSR | S_IRUGO, show_target_temp, + store_target_temp, 1), + SENSOR_ATTR(pwm3_target, S_IWUSR | S_IRUGO, show_target_temp, + store_target_temp, 2), + SENSOR_ATTR(pwm4_target, S_IWUSR | S_IRUGO, show_target_temp, + store_target_temp, 3), +}; + +static struct sensor_device_attribute sda_tolerance[] = { + SENSOR_ATTR(pwm1_tolerance, S_IWUSR | S_IRUGO, show_tolerance, + store_tolerance, 0), + SENSOR_ATTR(pwm2_tolerance, S_IWUSR | S_IRUGO, show_tolerance, + store_tolerance, 1), + SENSOR_ATTR(pwm3_tolerance, S_IWUSR | S_IRUGO, show_tolerance, + store_tolerance, 2), + SENSOR_ATTR(pwm4_tolerance, S_IWUSR | S_IRUGO, show_tolerance, + store_tolerance, 3), +}; + +static void device_create_file_pwm(struct device *dev, int i) +{ + device_create_file(dev, &sda_pwm[i].dev_attr); + device_create_file(dev, &sda_pwm_mode[i].dev_attr); + device_create_file(dev, &sda_pwm_enable[i].dev_attr); + device_create_file(dev, &sda_target_temp[i].dev_attr); + device_create_file(dev, &sda_tolerance[i].dev_attr); +} + +/* Smart Fan registers */ + +#define fan_functions(reg, REG) \ +static ssize_t show_##reg(struct device *dev, struct device_attribute *attr, \ + char *buf) \ +{ \ + struct w83627ehf_data *data = w83627ehf_update_device(dev); \ + struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr); \ + int nr = sensor_attr->index; \ + return sprintf(buf, "%d\n", data->reg[nr]); \ +}\ +static ssize_t \ +store_##reg(struct device *dev, struct device_attribute *attr, \ + const char *buf, size_t count) \ +{\ + struct i2c_client *client = to_i2c_client(dev); \ + struct w83627ehf_data *data = i2c_get_clientdata(client); \ + struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr); \ + int nr = sensor_attr->index; \ + u32 val = SENSORS_LIMIT(simple_strtoul(buf, NULL, 10), 1, 255); \ + mutex_lock(&data->update_lock); \ + data->reg[nr] = val; \ + w83627ehf_write_value(client, W83627EHF_REG_##REG[nr], val); \ + mutex_unlock(&data->update_lock); \ + return count; \ +} + +fan_functions(fan_min_output, FAN_MIN_OUTPUT) + +#define fan_time_functions(reg, REG) \ +static ssize_t show_##reg(struct device *dev, struct device_attribute *attr, \ + char *buf) \ +{ \ + struct w83627ehf_data *data = w83627ehf_update_device(dev); \ + struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr); \ + int nr = sensor_attr->index; \ + return sprintf(buf, "%d\n", \ + step_time_from_reg(data->reg[nr], data->pwm_mode[nr])); \ +} \ +\ +static ssize_t \ +store_##reg(struct device *dev, struct device_attribute *attr, \ + const char *buf, size_t count) \ +{ \ + struct i2c_client *client = to_i2c_client(dev); \ + struct w83627ehf_data *data = i2c_get_clientdata(client); \ + struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr); \ + int nr = sensor_attr->index; \ + u8 val = step_time_to_reg(simple_strtoul(buf, NULL, 10), \ + data->pwm_mode[nr]); \ + mutex_lock(&data->update_lock); \ + data->reg[nr] = val; \ + w83627ehf_write_value(client, W83627EHF_REG_##REG[nr], val); \ + mutex_unlock(&data->update_lock); \ + return count; \ +} \ + +fan_time_functions(fan_stop_time, FAN_STOP_TIME) + + +static struct sensor_device_attribute sda_sf3_arrays_fan4[] = { + SENSOR_ATTR(pwm4_stop_time, S_IWUSR | S_IRUGO, show_fan_stop_time, + store_fan_stop_time, 3), + SENSOR_ATTR(pwm4_min_output, S_IWUSR | S_IRUGO, show_fan_min_output, + store_fan_min_output, 3), +}; + +static struct sensor_device_attribute sda_sf3_arrays[] = { + SENSOR_ATTR(pwm1_stop_time, S_IWUSR | S_IRUGO, show_fan_stop_time, + store_fan_stop_time, 0), + SENSOR_ATTR(pwm2_stop_time, S_IWUSR | S_IRUGO, show_fan_stop_time, + store_fan_stop_time, 1), + SENSOR_ATTR(pwm3_stop_time, S_IWUSR | S_IRUGO, show_fan_stop_time, + store_fan_stop_time, 2), + SENSOR_ATTR(pwm1_min_output, S_IWUSR | S_IRUGO, show_fan_min_output, + store_fan_min_output, 0), + SENSOR_ATTR(pwm2_min_output, S_IWUSR | S_IRUGO, show_fan_min_output, + store_fan_min_output, 1), + SENSOR_ATTR(pwm3_min_output, S_IWUSR | S_IRUGO, show_fan_min_output, + store_fan_min_output, 2), +}; + /* * Driver and client management */ @@ -810,6 +1160,7 @@ static int w83627ehf_detect(struct i2c_adapter *adapter) struct i2c_client *client; struct w83627ehf_data *data; struct device *dev; + u8 fan4pin, fan5pin; int i, err = 0; if (!request_region(address + REGION_OFFSET, REGION_LENGTH, @@ -848,13 +1199,21 @@ static int w83627ehf_detect(struct i2c_adapter *adapter) data->fan_min[i] = w83627ehf_read_value(client, W83627EHF_REG_FAN_MIN[i]); + /* fan4 and fan5 share some pins with the GPIO and serial flash */ + + superio_enter(); + fan5pin = superio_inb(0x24) & 0x2; + fan4pin = superio_inb(0x29) & 0x6; + superio_exit(); + /* It looks like fan4 and fan5 pins can be alternatively used as fan on/off switches */ + data->has_fan = 0x07; /* fan1, fan2 and fan3 */ i = w83627ehf_read_value(client, W83627EHF_REG_FANDIV1); - if (i & (1 << 2)) + if ((i & (1 << 2)) && (!fan4pin)) data->has_fan |= (1 << 3); - if (i & (1 << 0)) + if ((i & (1 << 0)) && (!fan5pin)) data->has_fan |= (1 << 4); /* Register sysfs hooks */ @@ -864,13 +1223,25 @@ static int w83627ehf_detect(struct i2c_adapter *adapter) goto exit_detach; } + for (i = 0; i < ARRAY_SIZE(sda_sf3_arrays); i++) + device_create_file(dev, &sda_sf3_arrays[i].dev_attr); + + /* if fan4 is enabled create the sf3 files for it */ + if (data->has_fan & (1 << 3)) + for (i = 0; i < ARRAY_SIZE(sda_sf3_arrays_fan4); i++) + device_create_file(dev, &sda_sf3_arrays_fan4[i].dev_attr); + for (i = 0; i < 10; i++) device_create_file_in(dev, i); for (i = 0; i < 5; i++) { - if (data->has_fan & (1 << i)) + if (data->has_fan & (1 << i)) { device_create_file_fan(dev, i); + if (i != 4) /* we have only 4 pwm */ + device_create_file_pwm(dev, i); + } } + for (i = 0; i < ARRAY_SIZE(sda_temp); i++) device_create_file(dev, &sda_temp[i].dev_attr); From 563daaf4047464eef5ffcb46194a99c1a8f2260e Mon Sep 17 00:00:00 2001 From: Rudolf Marek Date: Wed, 5 Jul 2006 18:15:31 +0200 Subject: [PATCH 02/39] hwmon: Documentation update for w83627ehf Add documentation for the w83627ehf hardware monitoring driver. Signed-off-by: Rudolf Marek Signed-off-by: Jean Delvare Signed-off-by: Greg Kroah-Hartman --- Documentation/hwmon/w83627ehf | 85 +++++++++++++++++++++++++++++++++++ 1 file changed, 85 insertions(+) create mode 100644 Documentation/hwmon/w83627ehf diff --git a/Documentation/hwmon/w83627ehf b/Documentation/hwmon/w83627ehf new file mode 100644 index 000000000000..1474e78d5d32 --- /dev/null +++ b/Documentation/hwmon/w83627ehf @@ -0,0 +1,85 @@ +Kernel driver w83627ehf +======================= + +Supported chips: + * Winbond W83627EHF/EHG (ISA access ONLY) + Prefix: 'w83627ehf' + Addresses scanned: ISA address retrieved from Super I/O registers + Datasheet: http://www.winbond-usa.com/products/winbond_products/pdfs/PCIC/W83627EHF_%20W83627EHGb.pdf + +Authors: + Jean Delvare + Yuan Mu + Rudolf Marek + +Description +----------- + +This driver implements support for the Winbond W83627EHF and W83627EHG +super I/O chips. We will refer to them collectively as Winbond chips. + +The chips implement three temperature sensors, five fan rotation +speed sensors, ten analog voltage sensors, alarms with beep warnings (control +unimplemented), and some automatic fan regulation strategies (plus manual +fan control mode). + +Temperatures are measured in degrees Celsius and measurement resolution is 1 +degC for temp1 and 0.5 degC for temp2 and temp3. An alarm is triggered when +the temperature gets higher than high limit; it stays on until the temperature +falls below the Hysteresis value. + +Fan rotation speeds are reported in RPM (rotations per minute). An alarm is +triggered if the rotation speed has dropped below a programmable limit. Fan +readings can be divided by a programmable divider (1, 2, 4, 8, 16, 32, 64 or +128) to give the readings more range or accuracy. The driver sets the most +suitable fan divisor itself. Some fans might not be present because they +share pins with other functions. + +Voltage sensors (also known as IN sensors) report their values in millivolts. +An alarm is triggered if the voltage has crossed a programmable minimum +or maximum limit. + +The driver supports automatic fan control mode known as Thermal Cruise. +In this mode, the chip attempts to keep the measured temperature in a +predefined temperature range. If the temperature goes out of range, fan +is driven slower/faster to reach the predefined range again. + +The mode works for fan1-fan4. Mapping of temperatures to pwm outputs is as +follows: + +temp1 -> pwm1 +temp2 -> pwm2 +temp3 -> pwm3 +prog -> pwm4 (the programmable setting is not supported by the driver) + +/sys files +---------- + +pwm[1-4] - this file stores PWM duty cycle or DC value (fan speed) in range: + 0 (stop) to 255 (full) + +pwm[1-4]_enable - this file controls mode of fan/temperature control: + * 1 Manual Mode, write to pwm file any value 0-255 (full speed) + * 2 Thermal Cruise + +Thermal Cruise mode +------------------- + +If the temperature is in the range defined by: + +pwm[1-4]_target - set target temperature, unit millidegree Celcius + (range 0 - 127000) +pwm[1-4]_tolerance - tolerance, unit millidegree Celcius (range 0 - 15000) + +there are no changes to fan speed. Once the temperature leaves the interval, +fan speed increases (temp is higher) or decreases if lower than desired. +There are defined steps and times, but not exported by the driver yet. + +pwm[1-4]_min_output - minimum fan speed (range 1 - 255), when the temperature + is below defined range. +pwm[1-4]_stop_time - how many milliseconds [ms] must elapse to switch + corresponding fan off. (when the temperature was below + defined range). + +Note: last two functions are influenced by other control bits, not yet exported + by the driver, so a change might not have any effect. From c41bdb526bca5cda5be3de8c112f63c400bf990f Mon Sep 17 00:00:00 2001 From: Alexey Dobriyan Date: Mon, 28 Aug 2006 14:18:14 +0200 Subject: [PATCH 03/39] atxp1: Signed/unsigned char bug fix vid_to_reg() can return -1 and char can be unsigned. Signed-off-by: Alexey Dobriyan Signed-off-by: Jean Delvare Signed-off-by: Greg Kroah-Hartman --- drivers/hwmon/atxp1.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/drivers/hwmon/atxp1.c b/drivers/hwmon/atxp1.c index 728a1e8b9190..ba843f8c4cef 100644 --- a/drivers/hwmon/atxp1.c +++ b/drivers/hwmon/atxp1.c @@ -116,8 +116,7 @@ static ssize_t atxp1_storevcore(struct device *dev, struct device_attribute *att { struct atxp1_data *data; struct i2c_client *client; - char vid; - char cvid; + int vid, cvid; unsigned int vcore; client = to_i2c_client(dev); From b25a10631a81fca33a94d1f1f6960928d8e9ce63 Mon Sep 17 00:00:00 2001 From: Dmitry Torokhov Date: Mon, 28 Aug 2006 14:21:42 +0200 Subject: [PATCH 04/39] hdaps: Handle errors from input_register_device HDAPS: handle errors from input_register_device() Signed-off-by: Dmitry Torokhov Signed-off-by: Jean Delvare Signed-off-by: Greg Kroah-Hartman --- drivers/hwmon/hdaps.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/drivers/hwmon/hdaps.c b/drivers/hwmon/hdaps.c index 42b632889dd8..8e7b5607f5a1 100644 --- a/drivers/hwmon/hdaps.c +++ b/drivers/hwmon/hdaps.c @@ -587,7 +587,9 @@ static int __init hdaps_init(void) input_set_abs_params(hdaps_idev, ABS_Y, -256, 256, HDAPS_INPUT_FUZZ, HDAPS_INPUT_FLAT); - input_register_device(hdaps_idev); + ret = input_register_device(hdaps_idev); + if (ret) + goto out_idev; /* start up our timer for the input device */ init_timer(&hdaps_timer); @@ -598,6 +600,8 @@ static int __init hdaps_init(void) printk(KERN_INFO "hdaps: driver successfully loaded.\n"); return 0; +out_idev: + input_free_device(hdaps_idev); out_group: sysfs_remove_group(&pdev->dev.kobj, &hdaps_attribute_group); out_device: From 0dd7699ec4b27b3662d8980ff7a309cc81276298 Mon Sep 17 00:00:00 2001 From: Jean Delvare Date: Mon, 28 Aug 2006 14:22:34 +0200 Subject: [PATCH 05/39] smsc47m1: dev_warn fix smsc47m1: dev_warn fix We can't use dev_warn on an i2c client before it is attached. Signed-off-by: Jean Delvare Signed-off-by: Greg Kroah-Hartman --- drivers/hwmon/smsc47m1.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/hwmon/smsc47m1.c b/drivers/hwmon/smsc47m1.c index 6c81b843d831..9cd28f2709fc 100644 --- a/drivers/hwmon/smsc47m1.c +++ b/drivers/hwmon/smsc47m1.c @@ -429,7 +429,8 @@ static int smsc47m1_detect(struct i2c_adapter *adapter) pwm2 = (smsc47m1_read_value(new_client, SMSC47M1_REG_PPIN(1)) & 0x05) == 0x04; if (!(fan1 || fan2 || pwm1 || pwm2)) { - dev_warn(&new_client->dev, "Device is not configured, will not use\n"); + dev_warn(&adapter->dev, "Device at 0x%x is not configured, " + "will not use\n", new_client->addr); err = -ENODEV; goto error_free; } From 17d648bf5786ba5b8cbf7cbd5cb18d3d8d2657ca Mon Sep 17 00:00:00 2001 From: Jean Delvare Date: Mon, 28 Aug 2006 14:23:46 +0200 Subject: [PATCH 06/39] it87: Add support for the IT8716F it87: Add support for the IT8716F The IT8716F is a Super-I/O chip with integrated hardware monitoring functions. It is very similar to the IT8712F, so adding support to the it87 driver was pretty straightforward. The most significant change here is that the IT8716F has 16-bit fan speed counters, so the user no more needs to tweak the fan clock dividers to get the best readings. Userspace support is already in lm_sensors SVN (to be soon released as 2.10.1.) Thanks to Stian Oksavik, Olivier Nicolas, Prakash Punnoor and Juergen Kilb for testing the early versions of this patch. Thanks also to ITE for providing datasheets and answering my questions. Signed-off-by: Jean Delvare Signed-off-by: Greg Kroah-Hartman --- Documentation/hwmon/it87 | 40 ++++++--- drivers/hwmon/Kconfig | 4 +- drivers/hwmon/it87.c | 178 +++++++++++++++++++++++++++++++++------ 3 files changed, 185 insertions(+), 37 deletions(-) diff --git a/Documentation/hwmon/it87 b/Documentation/hwmon/it87 index 9555be1ed999..aff680784222 100644 --- a/Documentation/hwmon/it87 +++ b/Documentation/hwmon/it87 @@ -13,6 +13,11 @@ Supported chips: from Super I/O config space (8 I/O ports) Datasheet: Publicly available at the ITE website http://www.ite.com.tw/ + * IT8716F + Prefix: 'it8716' + Addresses scanned: from Super I/O config space (8 I/O ports) + Datasheet: Publicly available at the ITE website + http://www.ite.com.tw/product_info/file/pc/IT8716F_V0.3.ZIP * SiS950 [clone of IT8705F] Prefix: 'it87' Addresses scanned: from Super I/O config space (8 I/O ports) @@ -43,26 +48,39 @@ Module Parameters Description ----------- -This driver implements support for the IT8705F, IT8712F and SiS950 chips. - -This driver also supports IT8712F, which adds SMBus access, and a VID -input, used to report the Vcore voltage of the Pentium processor. -The IT8712F additionally features VID inputs. +This driver implements support for the IT8705F, IT8712F, IT8716F and +SiS950 chips. These chips are 'Super I/O chips', supporting floppy disks, infrared ports, joysticks and other miscellaneous stuff. For hardware monitoring, they include an 'environment controller' with 3 temperature sensors, 3 fan rotation speed sensors, 8 voltage sensors, and associated alarms. +The IT8712F and IT8716F additionally feature VID inputs, used to report +the Vcore voltage of the processor. The early IT8712F have 5 VID pins, +the IT8716F and late IT8712F have 6. They are shared with other functions +though, so the functionality may not be available on a given system. +The driver dumbly assume it is there. + +The IT8716F and later IT8712F revisions have support for 2 additional +fans. They are not yet supported by the driver. + +The IT8716F and late IT8712F and IT8705F also have optional 16-bit +tachometer counters for fans 1 to 3. This is better (no more fan +clock divider mess) but not compatible with the older chips and +revisions. For now, the driver only uses the 16-bit mode on the +IT8716F. + Temperatures are measured in degrees Celsius. An alarm is triggered once when the Overtemperature Shutdown limit is crossed. Fan rotation speeds are reported in RPM (rotations per minute). An alarm is -triggered if the rotation speed has dropped below a programmable limit. Fan -readings can be divided by a programmable divider (1, 2, 4 or 8) to give the -readings more range or accuracy. Not all RPM values can accurately be -represented, so some rounding is done. With a divider of 2, the lowest -representable value is around 2600 RPM. +triggered if the rotation speed has dropped below a programmable limit. When +16-bit tachometer counters aren't used, fan readings can be divided by +a programmable divider (1, 2, 4 or 8) to give the readings more range or +accuracy. With a divider of 2, the lowest representable value is around +2600 RPM. Not all RPM values can accurately be represented, so some rounding +is done. Voltage sensors (also known as IN sensors) report their values in volts. An alarm is triggered if the voltage has crossed a programmable minimum or @@ -71,7 +89,7 @@ zero'; this is important for negative voltage measurements. All voltage inputs can measure voltages between 0 and 4.08 volts, with a resolution of 0.016 volt. The battery voltage in8 does not have limit registers. -The VID lines (IT8712F only) encode the core voltage value: the voltage +The VID lines (IT8712F/IT8716F) encode the core voltage value: the voltage level your processor should work with. This is hardcoded by the mainboard and/or processor itself. It is a value in volts. diff --git a/drivers/hwmon/Kconfig b/drivers/hwmon/Kconfig index 0e31a0c496e8..cefb1adf4534 100644 --- a/drivers/hwmon/Kconfig +++ b/drivers/hwmon/Kconfig @@ -186,8 +186,8 @@ config SENSORS_IT87 select I2C_ISA select HWMON_VID help - If you say yes here you get support for ITE IT87xx sensor chips - and clones: SiS960. + If you say yes here you get support for ITE IT8705F, IT8712F and + IT8716F sensor chips, and the SiS960 clone. This driver can also be built as a module. If so, the module will be called it87. diff --git a/drivers/hwmon/it87.c b/drivers/hwmon/it87.c index b0ee57492228..e7f14e61d6f2 100644 --- a/drivers/hwmon/it87.c +++ b/drivers/hwmon/it87.c @@ -4,6 +4,7 @@ Supports: IT8705F Super I/O chip w/LPC interface IT8712F Super I/O chip w/LPC interface & SMBus + IT8716F Super I/O chip w/LPC interface Sis950 A clone of the IT8705F Copyright (C) 2001 Chris Gauthron @@ -50,7 +51,7 @@ static unsigned short normal_i2c[] = { 0x2d, I2C_CLIENT_END }; static unsigned short isa_address; /* Insmod parameters */ -I2C_CLIENT_INSMOD_2(it87, it8712); +I2C_CLIENT_INSMOD_3(it87, it8712, it8716); #define REG 0x2e /* The register to read/write */ #define DEV 0x07 /* Register: Logical device select */ @@ -101,6 +102,7 @@ superio_exit(void) #define IT8712F_DEVID 0x8712 #define IT8705F_DEVID 0x8705 +#define IT8716F_DEVID 0x8716 #define IT87_ACT_REG 0x30 #define IT87_BASE_REG 0x60 @@ -132,12 +134,18 @@ static u16 chip_type; #define IT87_REG_ALARM3 0x03 #define IT87_REG_VID 0x0a +/* Warning: register 0x0b is used for something completely different in + new chips/revisions. I suspect only 16-bit tachometer mode will work + for these. */ #define IT87_REG_FAN_DIV 0x0b +#define IT87_REG_FAN_16BIT 0x0c /* Monitors: 9 voltage (0 to 7, battery), 3 temp (1 to 3), 3 fan (1 to 3) */ #define IT87_REG_FAN(nr) (0x0d + (nr)) #define IT87_REG_FAN_MIN(nr) (0x10 + (nr)) +#define IT87_REG_FANX(nr) (0x18 + (nr)) +#define IT87_REG_FANX_MIN(nr) (0x1b + (nr)) #define IT87_REG_FAN_MAIN_CTRL 0x13 #define IT87_REG_FAN_CTL 0x14 #define IT87_REG_PWM(nr) (0x15 + (nr)) @@ -169,7 +177,16 @@ static inline u8 FAN_TO_REG(long rpm, int div) 254); } +static inline u16 FAN16_TO_REG(long rpm) +{ + if (rpm == 0) + return 0xffff; + return SENSORS_LIMIT((1350000 + rpm) / (rpm * 2), 1, 0xfffe); +} + #define FAN_FROM_REG(val,div) ((val)==0?-1:(val)==255?0:1350000/((val)*(div))) +/* The divider is fixed to 2 in 16-bit mode */ +#define FAN16_FROM_REG(val) ((val)==0?-1:(val)==0xffff?0:1350000/((val)*2)) #define TEMP_TO_REG(val) (SENSORS_LIMIT(((val)<0?(((val)-500)/1000):\ ((val)+500)/1000),-128,127)) @@ -205,8 +222,8 @@ struct it87_data { u8 in[9]; /* Register value */ u8 in_max[9]; /* Register value */ u8 in_min[9]; /* Register value */ - u8 fan[3]; /* Register value */ - u8 fan_min[3]; /* Register value */ + u16 fan[3]; /* Register values, possibly combined */ + u16 fan_min[3]; /* Register values, possibly combined */ u8 temp[3]; /* Register value */ u8 temp_high[3]; /* Register value */ u8 temp_low[3]; /* Register value */ @@ -657,6 +674,59 @@ show_pwm_offset(1); show_pwm_offset(2); show_pwm_offset(3); +/* A different set of callbacks for 16-bit fans */ +static ssize_t show_fan16(struct device *dev, struct device_attribute *attr, + char *buf) +{ + struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr); + int nr = sensor_attr->index; + struct it87_data *data = it87_update_device(dev); + return sprintf(buf, "%d\n", FAN16_FROM_REG(data->fan[nr])); +} + +static ssize_t show_fan16_min(struct device *dev, struct device_attribute *attr, + char *buf) +{ + struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr); + int nr = sensor_attr->index; + struct it87_data *data = it87_update_device(dev); + return sprintf(buf, "%d\n", FAN16_FROM_REG(data->fan_min[nr])); +} + +static ssize_t set_fan16_min(struct device *dev, struct device_attribute *attr, + const char *buf, size_t count) +{ + struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr); + int nr = sensor_attr->index; + struct i2c_client *client = to_i2c_client(dev); + struct it87_data *data = i2c_get_clientdata(client); + int val = simple_strtol(buf, NULL, 10); + + mutex_lock(&data->update_lock); + data->fan_min[nr] = FAN16_TO_REG(val); + it87_write_value(client, IT87_REG_FAN_MIN(nr), + data->fan_min[nr] & 0xff); + it87_write_value(client, IT87_REG_FANX_MIN(nr), + data->fan_min[nr] >> 8); + mutex_unlock(&data->update_lock); + return count; +} + +/* We want to use the same sysfs file names as 8-bit fans, but we need + different variable names, so we have to use SENSOR_ATTR instead of + SENSOR_DEVICE_ATTR. */ +#define show_fan16_offset(offset) \ +static struct sensor_device_attribute sensor_dev_attr_fan##offset##_input16 \ + = SENSOR_ATTR(fan##offset##_input, S_IRUGO, \ + show_fan16, NULL, offset - 1); \ +static struct sensor_device_attribute sensor_dev_attr_fan##offset##_min16 \ + = SENSOR_ATTR(fan##offset##_min, S_IRUGO | S_IWUSR, \ + show_fan16_min, set_fan16_min, offset - 1) + +show_fan16_offset(1); +show_fan16_offset(2); +show_fan16_offset(3); + /* Alarms */ static ssize_t show_alarms(struct device *dev, struct device_attribute *attr, char *buf) { @@ -721,6 +791,7 @@ static int __init it87_find(unsigned short *address) superio_enter(); chip_type = superio_inw(DEVID); if (chip_type != IT8712F_DEVID + && chip_type != IT8716F_DEVID && chip_type != IT8705F_DEVID) goto exit; @@ -800,8 +871,16 @@ static int it87_detect(struct i2c_adapter *adapter, int address, int kind) i = it87_read_value(new_client, IT87_REG_CHIPID); if (i == 0x90) { kind = it87; - if ((is_isa) && (chip_type == IT8712F_DEVID)) - kind = it8712; + if (is_isa) { + switch (chip_type) { + case IT8712F_DEVID: + kind = it8712; + break; + case IT8716F_DEVID: + kind = it8716; + break; + } + } } else { if (kind == 0) @@ -818,6 +897,8 @@ static int it87_detect(struct i2c_adapter *adapter, int address, int kind) name = "it87"; } else if (kind == it8712) { name = "it8712"; + } else if (kind == it8716) { + name = "it8716"; } /* Fill in the remaining client fields and put it into the global list */ @@ -885,15 +966,41 @@ static int it87_detect(struct i2c_adapter *adapter, int address, int kind) device_create_file(&new_client->dev, &sensor_dev_attr_temp1_type.dev_attr); device_create_file(&new_client->dev, &sensor_dev_attr_temp2_type.dev_attr); device_create_file(&new_client->dev, &sensor_dev_attr_temp3_type.dev_attr); - device_create_file(&new_client->dev, &sensor_dev_attr_fan1_input.dev_attr); - device_create_file(&new_client->dev, &sensor_dev_attr_fan2_input.dev_attr); - device_create_file(&new_client->dev, &sensor_dev_attr_fan3_input.dev_attr); - device_create_file(&new_client->dev, &sensor_dev_attr_fan1_min.dev_attr); - device_create_file(&new_client->dev, &sensor_dev_attr_fan2_min.dev_attr); - device_create_file(&new_client->dev, &sensor_dev_attr_fan3_min.dev_attr); - device_create_file(&new_client->dev, &sensor_dev_attr_fan1_div.dev_attr); - device_create_file(&new_client->dev, &sensor_dev_attr_fan2_div.dev_attr); - device_create_file(&new_client->dev, &sensor_dev_attr_fan3_div.dev_attr); + + if (data->type == it8716) { /* 16-bit tachometers */ + device_create_file(&new_client->dev, + &sensor_dev_attr_fan1_input16.dev_attr); + device_create_file(&new_client->dev, + &sensor_dev_attr_fan2_input16.dev_attr); + device_create_file(&new_client->dev, + &sensor_dev_attr_fan3_input16.dev_attr); + device_create_file(&new_client->dev, + &sensor_dev_attr_fan1_min16.dev_attr); + device_create_file(&new_client->dev, + &sensor_dev_attr_fan2_min16.dev_attr); + device_create_file(&new_client->dev, + &sensor_dev_attr_fan3_min16.dev_attr); + } else { + device_create_file(&new_client->dev, + &sensor_dev_attr_fan1_input.dev_attr); + device_create_file(&new_client->dev, + &sensor_dev_attr_fan2_input.dev_attr); + device_create_file(&new_client->dev, + &sensor_dev_attr_fan3_input.dev_attr); + device_create_file(&new_client->dev, + &sensor_dev_attr_fan1_min.dev_attr); + device_create_file(&new_client->dev, + &sensor_dev_attr_fan2_min.dev_attr); + device_create_file(&new_client->dev, + &sensor_dev_attr_fan3_min.dev_attr); + device_create_file(&new_client->dev, + &sensor_dev_attr_fan1_div.dev_attr); + device_create_file(&new_client->dev, + &sensor_dev_attr_fan2_div.dev_attr); + device_create_file(&new_client->dev, + &sensor_dev_attr_fan3_div.dev_attr); + } + device_create_file(&new_client->dev, &dev_attr_alarms); if (enable_pwm_interface) { device_create_file(&new_client->dev, &sensor_dev_attr_pwm1_enable.dev_attr); @@ -904,7 +1011,7 @@ static int it87_detect(struct i2c_adapter *adapter, int address, int kind) device_create_file(&new_client->dev, &sensor_dev_attr_pwm3.dev_attr); } - if (data->type == it8712) { + if (data->type == it8712 || data->type == it8716) { data->vrm = vid_which_vrm(); device_create_file_vrm(new_client); device_create_file_vid(new_client); @@ -1069,6 +1176,17 @@ static void it87_init_client(struct i2c_client *client, struct it87_data *data) it87_write_value(client, IT87_REG_FAN_MAIN_CTRL, data->fan_main_ctrl); } + /* Set tachometers to 16-bit mode if needed */ + if (data->type == it8716) { + tmp = it87_read_value(client, IT87_REG_FAN_16BIT); + if ((tmp & 0x07) != 0x07) { + dev_dbg(&client->dev, + "Setting fan1-3 to 16-bit mode\n"); + it87_write_value(client, IT87_REG_FAN_16BIT, + tmp | 0x07); + } + } + /* Set current fan mode registers and the default settings for the * other mode registers */ for (i = 0; i < 3; i++) { @@ -1126,10 +1244,17 @@ static struct it87_data *it87_update_device(struct device *dev) data->in_max[8] = 255; for (i = 0; i < 3; i++) { - data->fan[i] = - it87_read_value(client, IT87_REG_FAN(i)); data->fan_min[i] = it87_read_value(client, IT87_REG_FAN_MIN(i)); + data->fan[i] = it87_read_value(client, + IT87_REG_FAN(i)); + /* Add high byte if in 16-bit mode */ + if (data->type == it8716) { + data->fan[i] |= it87_read_value(client, + IT87_REG_FANX(i)) << 8; + data->fan_min[i] |= it87_read_value(client, + IT87_REG_FANX_MIN(i)) << 8; + } } for (i = 0; i < 3; i++) { data->temp[i] = @@ -1140,10 +1265,13 @@ static struct it87_data *it87_update_device(struct device *dev) it87_read_value(client, IT87_REG_TEMP_LOW(i)); } - i = it87_read_value(client, IT87_REG_FAN_DIV); - data->fan_div[0] = i & 0x07; - data->fan_div[1] = (i >> 3) & 0x07; - data->fan_div[2] = (i & 0x40) ? 3 : 1; + /* Newer chips don't have clock dividers */ + if (data->type != it8716) { + i = it87_read_value(client, IT87_REG_FAN_DIV); + data->fan_div[0] = i & 0x07; + data->fan_div[1] = (i >> 3) & 0x07; + data->fan_div[2] = (i & 0x40) ? 3 : 1; + } data->alarms = it87_read_value(client, IT87_REG_ALARM1) | @@ -1153,9 +1281,11 @@ static struct it87_data *it87_update_device(struct device *dev) data->sensor = it87_read_value(client, IT87_REG_TEMP_ENABLE); /* The 8705 does not have VID capability */ - if (data->type == it8712) { + if (data->type == it8712 || data->type == it8716) { data->vid = it87_read_value(client, IT87_REG_VID); - data->vid &= 0x1f; + /* The older IT8712F revisions had only 5 VID pins, + but we assume it is always safe to read 6 bits. */ + data->vid &= 0x3f; } data->last_updated = jiffies; data->valid = 1; @@ -1194,7 +1324,7 @@ static void __exit sm_it87_exit(void) MODULE_AUTHOR("Chris Gauthron "); -MODULE_DESCRIPTION("IT8705F, IT8712F, Sis950 driver"); +MODULE_DESCRIPTION("IT8705F/8712F/8716F, SiS950 driver"); module_param(update_vbat, bool, 0); MODULE_PARM_DESC(update_vbat, "Update vbat if set else return powerup value"); module_param(fix_pwm_polarity, bool, 0); From 9060f8bdd0c40e31d2be388e59f2dbeea55988a2 Mon Sep 17 00:00:00 2001 From: Jean Delvare Date: Mon, 28 Aug 2006 14:24:17 +0200 Subject: [PATCH 07/39] it87: No sysfs files for disabled fans it87: No sysfs files for disabled fans Only create the fan attributes for enabled fan tachometers. Some motherboards have a nice BIOS which only enables the fan inputs which are wired to a fan header on the board. This makes the configuration easier for the user. Signed-off-by: Jean Delvare Signed-off-by: Greg Kroah-Hartman --- drivers/hwmon/it87.c | 83 +++++++++++++++++++++++++++----------------- 1 file changed, 51 insertions(+), 32 deletions(-) diff --git a/drivers/hwmon/it87.c b/drivers/hwmon/it87.c index e7f14e61d6f2..0317e441ca51 100644 --- a/drivers/hwmon/it87.c +++ b/drivers/hwmon/it87.c @@ -222,6 +222,7 @@ struct it87_data { u8 in[9]; /* Register value */ u8 in_max[9]; /* Register value */ u8 in_min[9]; /* Register value */ + u8 has_fan; /* Bitfield, fans enabled */ u16 fan[3]; /* Register values, possibly combined */ u16 fan_min[3]; /* Register values, possibly combined */ u8 temp[3]; /* Register value */ @@ -967,38 +968,51 @@ static int it87_detect(struct i2c_adapter *adapter, int address, int kind) device_create_file(&new_client->dev, &sensor_dev_attr_temp2_type.dev_attr); device_create_file(&new_client->dev, &sensor_dev_attr_temp3_type.dev_attr); + /* Do not create fan files for disabled fans */ if (data->type == it8716) { /* 16-bit tachometers */ - device_create_file(&new_client->dev, - &sensor_dev_attr_fan1_input16.dev_attr); - device_create_file(&new_client->dev, - &sensor_dev_attr_fan2_input16.dev_attr); - device_create_file(&new_client->dev, - &sensor_dev_attr_fan3_input16.dev_attr); - device_create_file(&new_client->dev, - &sensor_dev_attr_fan1_min16.dev_attr); - device_create_file(&new_client->dev, - &sensor_dev_attr_fan2_min16.dev_attr); - device_create_file(&new_client->dev, - &sensor_dev_attr_fan3_min16.dev_attr); + if (data->has_fan & (1 << 0)) { + device_create_file(&new_client->dev, + &sensor_dev_attr_fan1_input16.dev_attr); + device_create_file(&new_client->dev, + &sensor_dev_attr_fan1_min16.dev_attr); + } + if (data->has_fan & (1 << 1)) { + device_create_file(&new_client->dev, + &sensor_dev_attr_fan2_input16.dev_attr); + device_create_file(&new_client->dev, + &sensor_dev_attr_fan2_min16.dev_attr); + } + if (data->has_fan & (1 << 2)) { + device_create_file(&new_client->dev, + &sensor_dev_attr_fan3_input16.dev_attr); + device_create_file(&new_client->dev, + &sensor_dev_attr_fan3_min16.dev_attr); + } } else { - device_create_file(&new_client->dev, - &sensor_dev_attr_fan1_input.dev_attr); - device_create_file(&new_client->dev, - &sensor_dev_attr_fan2_input.dev_attr); - device_create_file(&new_client->dev, - &sensor_dev_attr_fan3_input.dev_attr); - device_create_file(&new_client->dev, - &sensor_dev_attr_fan1_min.dev_attr); - device_create_file(&new_client->dev, - &sensor_dev_attr_fan2_min.dev_attr); - device_create_file(&new_client->dev, - &sensor_dev_attr_fan3_min.dev_attr); - device_create_file(&new_client->dev, - &sensor_dev_attr_fan1_div.dev_attr); - device_create_file(&new_client->dev, - &sensor_dev_attr_fan2_div.dev_attr); - device_create_file(&new_client->dev, - &sensor_dev_attr_fan3_div.dev_attr); + if (data->has_fan & (1 << 0)) { + device_create_file(&new_client->dev, + &sensor_dev_attr_fan1_input.dev_attr); + device_create_file(&new_client->dev, + &sensor_dev_attr_fan1_min.dev_attr); + device_create_file(&new_client->dev, + &sensor_dev_attr_fan1_div.dev_attr); + } + if (data->has_fan & (1 << 1)) { + device_create_file(&new_client->dev, + &sensor_dev_attr_fan2_input.dev_attr); + device_create_file(&new_client->dev, + &sensor_dev_attr_fan2_min.dev_attr); + device_create_file(&new_client->dev, + &sensor_dev_attr_fan2_div.dev_attr); + } + if (data->has_fan & (1 << 2)) { + device_create_file(&new_client->dev, + &sensor_dev_attr_fan3_input.dev_attr); + device_create_file(&new_client->dev, + &sensor_dev_attr_fan3_min.dev_attr); + device_create_file(&new_client->dev, + &sensor_dev_attr_fan3_div.dev_attr); + } } device_create_file(&new_client->dev, &dev_attr_alarms); @@ -1175,11 +1189,12 @@ static void it87_init_client(struct i2c_client *client, struct it87_data *data) data->fan_main_ctrl |= 0x70; it87_write_value(client, IT87_REG_FAN_MAIN_CTRL, data->fan_main_ctrl); } + data->has_fan = (data->fan_main_ctrl >> 4) & 0x07; /* Set tachometers to 16-bit mode if needed */ if (data->type == it8716) { tmp = it87_read_value(client, IT87_REG_FAN_16BIT); - if ((tmp & 0x07) != 0x07) { + if (~tmp & 0x07 & data->has_fan) { dev_dbg(&client->dev, "Setting fan1-3 to 16-bit mode\n"); it87_write_value(client, IT87_REG_FAN_16BIT, @@ -1244,6 +1259,10 @@ static struct it87_data *it87_update_device(struct device *dev) data->in_max[8] = 255; for (i = 0; i < 3; i++) { + /* Skip disabled fans */ + if (!(data->has_fan & (1 << i))) + continue; + data->fan_min[i] = it87_read_value(client, IT87_REG_FAN_MIN(i)); data->fan[i] = it87_read_value(client, @@ -1266,7 +1285,7 @@ static struct it87_data *it87_update_device(struct device *dev) } /* Newer chips don't have clock dividers */ - if (data->type != it8716) { + if ((data->has_fan & 0x07) && data->type != it8716) { i = it87_read_value(client, IT87_REG_FAN_DIV); data->fan_div[0] = i & 0x07; data->fan_div[1] = (i >> 3) & 0x07; From b9e349f710376ef55f200e9fa07e88b4fe2cdf98 Mon Sep 17 00:00:00 2001 From: Jean Delvare Date: Mon, 28 Aug 2006 14:26:22 +0200 Subject: [PATCH 08/39] it87: Prevent overflow on fan clock divider write it87: Prevent overflow on fan clock divider write The highest possible clock divider for fan1 and fan2 is 128. Signed-off-by: Jean Delvare Signed-off-by: Greg Kroah-Hartman --- drivers/hwmon/it87.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/hwmon/it87.c b/drivers/hwmon/it87.c index 0317e441ca51..fc75fcb6bffd 100644 --- a/drivers/hwmon/it87.c +++ b/drivers/hwmon/it87.c @@ -198,7 +198,7 @@ static inline u16 FAN16_TO_REG(long rpm) static int DIV_TO_REG(int val) { int answer = 0; - while ((val >>= 1) != 0) + while (answer < 7 && (val >>= 1)) answer++; return answer; } @@ -563,7 +563,7 @@ static ssize_t set_fan_div(struct device *dev, struct device_attribute *attr, struct i2c_client *client = to_i2c_client(dev); struct it87_data *data = i2c_get_clientdata(client); - int val = simple_strtol(buf, NULL, 10); + unsigned long val = simple_strtoul(buf, NULL, 10); int i, min[3]; u8 old; From 3543a53f6c5b58c233218327f671108590151876 Mon Sep 17 00:00:00 2001 From: Jean Delvare Date: Mon, 28 Aug 2006 14:27:25 +0200 Subject: [PATCH 09/39] it87: in8 has no limit registers it87: in8 has no limit registers Signed-off-by: Jean Delvare Signed-off-by: Greg Kroah-Hartman --- drivers/hwmon/it87.c | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/drivers/hwmon/it87.c b/drivers/hwmon/it87.c index fc75fcb6bffd..bfad8975d1e5 100644 --- a/drivers/hwmon/it87.c +++ b/drivers/hwmon/it87.c @@ -220,8 +220,8 @@ struct it87_data { unsigned long last_updated; /* In jiffies */ u8 in[9]; /* Register value */ - u8 in_max[9]; /* Register value */ - u8 in_min[9]; /* Register value */ + u8 in_max[8]; /* Register value */ + u8 in_min[8]; /* Register value */ u8 has_fan; /* Bitfield, fans enabled */ u16 fan[3]; /* Register values, possibly combined */ u16 fan_min[3]; /* Register values, possibly combined */ @@ -1251,12 +1251,9 @@ static struct it87_data *it87_update_device(struct device *dev) data->in_max[i] = it87_read_value(client, IT87_REG_VIN_MAX(i)); } + /* in8 (battery) has no limit registers */ data->in[8] = it87_read_value(client, IT87_REG_VIN(8)); - /* Temperature sensor doesn't have limit registers, set - to min and max value */ - data->in_min[8] = 0; - data->in_max[8] = 255; for (i = 0; i < 3; i++) { /* Skip disabled fans */ From 8ab4ec3ef45cc2facbe14c733ef7230e7d94fcf2 Mon Sep 17 00:00:00 2001 From: Jean Delvare Date: Mon, 28 Aug 2006 14:35:46 +0200 Subject: [PATCH 10/39] it87: Cleanup set_fan_div it87: Cleanup set_fan_div We only change one fan clock divider at a time, so there is only one fan min which needs to be saved and restored. Signed-off-by: Jean Delvare Signed-off-by: Greg Kroah-Hartman --- drivers/hwmon/it87.c | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/drivers/hwmon/it87.c b/drivers/hwmon/it87.c index bfad8975d1e5..e9ab8a32903b 100644 --- a/drivers/hwmon/it87.c +++ b/drivers/hwmon/it87.c @@ -564,14 +564,14 @@ static ssize_t set_fan_div(struct device *dev, struct device_attribute *attr, struct i2c_client *client = to_i2c_client(dev); struct it87_data *data = i2c_get_clientdata(client); unsigned long val = simple_strtoul(buf, NULL, 10); - int i, min[3]; + int min; u8 old; mutex_lock(&data->update_lock); old = it87_read_value(client, IT87_REG_FAN_DIV); - for (i = 0; i < 3; i++) - min[i] = FAN_FROM_REG(data->fan_min[i], DIV_FROM_REG(data->fan_div[i])); + /* Save fan min limit */ + min = FAN_FROM_REG(data->fan_min[nr], DIV_FROM_REG(data->fan_div[nr])); switch (nr) { case 0: @@ -591,10 +591,10 @@ static ssize_t set_fan_div(struct device *dev, struct device_attribute *attr, val |= 0x1 << 6; it87_write_value(client, IT87_REG_FAN_DIV, val); - for (i = 0; i < 3; i++) { - data->fan_min[i]=FAN_TO_REG(min[i], DIV_FROM_REG(data->fan_div[i])); - it87_write_value(client, IT87_REG_FAN_MIN(i), data->fan_min[i]); - } + /* Restore fan min limit */ + data->fan_min[nr] = FAN_TO_REG(min, DIV_FROM_REG(data->fan_div[nr])); + it87_write_value(client, IT87_REG_FAN_MIN(nr), data->fan_min[nr]); + mutex_unlock(&data->update_lock); return count; } From 87673dd735b8e089b7f2830edd353aa5f5e743ad Mon Sep 17 00:00:00 2001 From: Jean Delvare Date: Mon, 28 Aug 2006 14:37:19 +0200 Subject: [PATCH 11/39] it87: Add support for the IT8718F it87: Add support for the IT8718F The IT8718F is a Super-I/O chip with integrated hardware monitoring functions. It is very similar to the IT8716F, so adding support to the it87 driver was pretty straightforward. The most significant difference is that the IT8718F has up to 8 VID pins, instead of 6 for the older chips. For the IT8718F, the VID value can only be read from Super-I/O space. Userspace support is already in lm_sensors SVN (to be soon released as 2.10.1.) Signed-off-by: Jean Delvare Signed-off-by: Greg Kroah-Hartman --- Documentation/hwmon/it87 | 33 +++++++++++++++------- drivers/hwmon/Kconfig | 4 +-- drivers/hwmon/it87.c | 61 ++++++++++++++++++++++++++++++++-------- 3 files changed, 74 insertions(+), 24 deletions(-) diff --git a/Documentation/hwmon/it87 b/Documentation/hwmon/it87 index aff680784222..a45044e82662 100644 --- a/Documentation/hwmon/it87 +++ b/Documentation/hwmon/it87 @@ -18,6 +18,12 @@ Supported chips: Addresses scanned: from Super I/O config space (8 I/O ports) Datasheet: Publicly available at the ITE website http://www.ite.com.tw/product_info/file/pc/IT8716F_V0.3.ZIP + * IT8718F + Prefix: 'it8718' + Addresses scanned: from Super I/O config space (8 I/O ports) + Datasheet: Publicly available at the ITE website + http://www.ite.com.tw/product_info/file/pc/IT8718F_V0.2.zip + http://www.ite.com.tw/product_info/file/pc/IT8718F_V0%203_(for%20C%20version).zip * SiS950 [clone of IT8705F] Prefix: 'it87' Addresses scanned: from Super I/O config space (8 I/O ports) @@ -48,8 +54,8 @@ Module Parameters Description ----------- -This driver implements support for the IT8705F, IT8712F, IT8716F and -SiS950 chips. +This driver implements support for the IT8705F, IT8712F, IT8716F, +IT8718F and SiS950 chips. These chips are 'Super I/O chips', supporting floppy disks, infrared ports, joysticks and other miscellaneous stuff. For hardware monitoring, they @@ -62,14 +68,21 @@ the IT8716F and late IT8712F have 6. They are shared with other functions though, so the functionality may not be available on a given system. The driver dumbly assume it is there. -The IT8716F and later IT8712F revisions have support for 2 additional -fans. They are not yet supported by the driver. +The IT8718F also features VID inputs (up to 8 pins) but the value is +stored in the Super-I/O configuration space. Due to technical limitations, +this value can currently only be read once at initialization time, so +the driver won't notice and report changes in the VID value. The two +upper VID bits share their pins with voltage inputs (in5 and in6) so you +can't have both on a given board. -The IT8716F and late IT8712F and IT8705F also have optional 16-bit -tachometer counters for fans 1 to 3. This is better (no more fan +The IT8716F, IT8718F and later IT8712F revisions have support for +2 additional fans. They are not yet supported by the driver. + +The IT8716F and IT8718F, and late IT8712F and IT8705F also have optional +16-bit tachometer counters for fans 1 to 3. This is better (no more fan clock divider mess) but not compatible with the older chips and revisions. For now, the driver only uses the 16-bit mode on the -IT8716F. +IT8716F and IT8718F. Temperatures are measured in degrees Celsius. An alarm is triggered once when the Overtemperature Shutdown limit is crossed. @@ -89,9 +102,9 @@ zero'; this is important for negative voltage measurements. All voltage inputs can measure voltages between 0 and 4.08 volts, with a resolution of 0.016 volt. The battery voltage in8 does not have limit registers. -The VID lines (IT8712F/IT8716F) encode the core voltage value: the voltage -level your processor should work with. This is hardcoded by the mainboard -and/or processor itself. It is a value in volts. +The VID lines (IT8712F/IT8716F/IT8718F) encode the core voltage value: +the voltage level your processor should work with. This is hardcoded by +the mainboard and/or processor itself. It is a value in volts. If an alarm triggers, it will remain triggered until the hardware register is read at least once. This means that the cause for the alarm may already diff --git a/drivers/hwmon/Kconfig b/drivers/hwmon/Kconfig index cefb1adf4534..78c237f8fa0a 100644 --- a/drivers/hwmon/Kconfig +++ b/drivers/hwmon/Kconfig @@ -186,8 +186,8 @@ config SENSORS_IT87 select I2C_ISA select HWMON_VID help - If you say yes here you get support for ITE IT8705F, IT8712F and - IT8716F sensor chips, and the SiS960 clone. + If you say yes here you get support for ITE IT8705F, IT8712F, + IT8716F and IT8718F sensor chips, and the SiS960 clone. This driver can also be built as a module. If so, the module will be called it87. diff --git a/drivers/hwmon/it87.c b/drivers/hwmon/it87.c index e9ab8a32903b..956cd553c711 100644 --- a/drivers/hwmon/it87.c +++ b/drivers/hwmon/it87.c @@ -5,6 +5,7 @@ Supports: IT8705F Super I/O chip w/LPC interface IT8712F Super I/O chip w/LPC interface & SMBus IT8716F Super I/O chip w/LPC interface + IT8718F Super I/O chip w/LPC interface Sis950 A clone of the IT8705F Copyright (C) 2001 Chris Gauthron @@ -51,12 +52,13 @@ static unsigned short normal_i2c[] = { 0x2d, I2C_CLIENT_END }; static unsigned short isa_address; /* Insmod parameters */ -I2C_CLIENT_INSMOD_3(it87, it8712, it8716); +I2C_CLIENT_INSMOD_4(it87, it8712, it8716, it8718); #define REG 0x2e /* The register to read/write */ #define DEV 0x07 /* Register: Logical device select */ #define VAL 0x2f /* The value to read/write */ #define PME 0x04 /* The device with the fan registers in it */ +#define GPIO 0x07 /* The device with the IT8718F VID value in it */ #define DEVID 0x20 /* Register: Device ID */ #define DEVREV 0x22 /* Register: Device Revision */ @@ -78,10 +80,10 @@ static int superio_inw(int reg) } static inline void -superio_select(void) +superio_select(int ldn) { outb(DEV, REG); - outb(PME, VAL); + outb(ldn, VAL); } static inline void @@ -100,21 +102,27 @@ superio_exit(void) outb(0x02, VAL); } +/* Logical device 4 registers */ #define IT8712F_DEVID 0x8712 #define IT8705F_DEVID 0x8705 #define IT8716F_DEVID 0x8716 +#define IT8718F_DEVID 0x8718 #define IT87_ACT_REG 0x30 #define IT87_BASE_REG 0x60 +/* Logical device 7 registers (IT8712F and later) */ +#define IT87_SIO_PINX2_REG 0x2c /* Pin selection */ +#define IT87_SIO_VID_REG 0xfc /* VID value */ + /* Update battery voltage after every reading if true */ static int update_vbat; /* Not all BIOSes properly configure the PWM registers */ static int fix_pwm_polarity; -/* Chip Type */ - +/* Values read from Super-I/O config space */ static u16 chip_type; +static u8 vid_value; /* Many IT87 constants specified below */ @@ -133,6 +141,8 @@ static u16 chip_type; #define IT87_REG_ALARM2 0x02 #define IT87_REG_ALARM3 0x03 +/* The IT8718F has the VID value in a different register, in Super-I/O + configuration space. */ #define IT87_REG_VID 0x0a /* Warning: register 0x0b is used for something completely different in new chips/revisions. I suspect only 16-bit tachometer mode will work @@ -793,10 +803,11 @@ static int __init it87_find(unsigned short *address) chip_type = superio_inw(DEVID); if (chip_type != IT8712F_DEVID && chip_type != IT8716F_DEVID + && chip_type != IT8718F_DEVID && chip_type != IT8705F_DEVID) goto exit; - superio_select(); + superio_select(PME); if (!(superio_inb(IT87_ACT_REG) & 0x01)) { pr_info("it87: Device not activated, skipping\n"); goto exit; @@ -812,6 +823,21 @@ static int __init it87_find(unsigned short *address) pr_info("it87: Found IT%04xF chip at 0x%x, revision %d\n", chip_type, *address, superio_inb(DEVREV) & 0x0f); + /* Read GPIO config and VID value from LDN 7 (GPIO) */ + if (chip_type != IT8705F_DEVID) { + int reg; + + superio_select(GPIO); + if (chip_type == it8718) + vid_value = superio_inb(IT87_SIO_VID_REG); + + reg = superio_inb(IT87_SIO_PINX2_REG); + if (reg & (1 << 0)) + pr_info("it87: in3 is VCC (+5V)\n"); + if (reg & (1 << 1)) + pr_info("it87: in7 is VCCH (+5V Stand-By)\n"); + } + exit: superio_exit(); return err; @@ -880,6 +906,9 @@ static int it87_detect(struct i2c_adapter *adapter, int address, int kind) case IT8716F_DEVID: kind = it8716; break; + case IT8718F_DEVID: + kind = it8718; + break; } } } @@ -900,6 +929,8 @@ static int it87_detect(struct i2c_adapter *adapter, int address, int kind) name = "it8712"; } else if (kind == it8716) { name = "it8716"; + } else if (kind == it8718) { + name = "it8718"; } /* Fill in the remaining client fields and put it into the global list */ @@ -969,7 +1000,8 @@ static int it87_detect(struct i2c_adapter *adapter, int address, int kind) device_create_file(&new_client->dev, &sensor_dev_attr_temp3_type.dev_attr); /* Do not create fan files for disabled fans */ - if (data->type == it8716) { /* 16-bit tachometers */ + if (data->type == it8716 || data->type == it8718) { + /* 16-bit tachometers */ if (data->has_fan & (1 << 0)) { device_create_file(&new_client->dev, &sensor_dev_attr_fan1_input16.dev_attr); @@ -989,6 +1021,7 @@ static int it87_detect(struct i2c_adapter *adapter, int address, int kind) &sensor_dev_attr_fan3_min16.dev_attr); } } else { + /* 8-bit tachometers with clock divider */ if (data->has_fan & (1 << 0)) { device_create_file(&new_client->dev, &sensor_dev_attr_fan1_input.dev_attr); @@ -1025,8 +1058,11 @@ static int it87_detect(struct i2c_adapter *adapter, int address, int kind) device_create_file(&new_client->dev, &sensor_dev_attr_pwm3.dev_attr); } - if (data->type == it8712 || data->type == it8716) { + if (data->type == it8712 || data->type == it8716 + || data->type == it8718) { data->vrm = vid_which_vrm(); + /* VID reading from Super-I/O config space if available */ + data->vid = vid_value; device_create_file_vrm(new_client); device_create_file_vid(new_client); } @@ -1192,7 +1228,7 @@ static void it87_init_client(struct i2c_client *client, struct it87_data *data) data->has_fan = (data->fan_main_ctrl >> 4) & 0x07; /* Set tachometers to 16-bit mode if needed */ - if (data->type == it8716) { + if (data->type == it8716 || data->type == it8718) { tmp = it87_read_value(client, IT87_REG_FAN_16BIT); if (~tmp & 0x07 & data->has_fan) { dev_dbg(&client->dev, @@ -1265,7 +1301,7 @@ static struct it87_data *it87_update_device(struct device *dev) data->fan[i] = it87_read_value(client, IT87_REG_FAN(i)); /* Add high byte if in 16-bit mode */ - if (data->type == it8716) { + if (data->type == it8716 || data->type == it8718) { data->fan[i] |= it87_read_value(client, IT87_REG_FANX(i)) << 8; data->fan_min[i] |= it87_read_value(client, @@ -1282,7 +1318,8 @@ static struct it87_data *it87_update_device(struct device *dev) } /* Newer chips don't have clock dividers */ - if ((data->has_fan & 0x07) && data->type != it8716) { + if ((data->has_fan & 0x07) && data->type != it8716 + && data->type != it8718) { i = it87_read_value(client, IT87_REG_FAN_DIV); data->fan_div[0] = i & 0x07; data->fan_div[1] = (i >> 3) & 0x07; @@ -1340,7 +1377,7 @@ static void __exit sm_it87_exit(void) MODULE_AUTHOR("Chris Gauthron "); -MODULE_DESCRIPTION("IT8705F/8712F/8716F, SiS950 driver"); +MODULE_DESCRIPTION("IT8705F/8712F/8716F/8718F, SiS950 driver"); module_param(update_vbat, bool, 0); MODULE_PARM_DESC(update_vbat, "Update vbat if set else return powerup value"); module_param(fix_pwm_polarity, bool, 0); From c5df9b7a7c7600e4365e81f64ea44beb5be8bfa7 Mon Sep 17 00:00:00 2001 From: Jean Delvare Date: Mon, 28 Aug 2006 14:37:54 +0200 Subject: [PATCH 12/39] it87: Overwrite broken default limits it87: Overwrite broken default limits Some IT8716F chips where seen with unreasonable defaults for low voltage and high temperature limits. Overwrite them with sane defaults so as to not generate meaningless alarms. Signed-off-by: Jean Delvare Signed-off-by: Greg Kroah-Hartman --- drivers/hwmon/it87.c | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/drivers/hwmon/it87.c b/drivers/hwmon/it87.c index 956cd553c711..de62f60bcaf1 100644 --- a/drivers/hwmon/it87.c +++ b/drivers/hwmon/it87.c @@ -1202,6 +1202,22 @@ static void it87_init_client(struct i2c_client *client, struct it87_data *data) data->manual_pwm_ctl[i] = 0xff; } + /* Some chips seem to have default value 0xff for all limit + * registers. For low voltage limits it makes no sense and triggers + * alarms, so change to 0 instead. For high temperature limits, it + * means -1 degree C, which surprisingly doesn't trigger an alarm, + * but is still confusing, so change to 127 degrees C. */ + for (i = 0; i < 8; i++) { + tmp = it87_read_value(client, IT87_REG_VIN_MIN(i)); + if (tmp == 0xff) + it87_write_value(client, IT87_REG_VIN_MIN(i), 0); + } + for (i = 0; i < 3; i++) { + tmp = it87_read_value(client, IT87_REG_TEMP_HIGH(i)); + if (tmp == 0xff) + it87_write_value(client, IT87_REG_TEMP_HIGH(i), 127); + } + /* Check if temperature channnels are reset manually or by some reason */ tmp = it87_read_value(client, IT87_REG_TEMP_ENABLE); if ((tmp & 0x3f) == 0) { From b19367c6f438b3a7700aceca21a03396702069ce Mon Sep 17 00:00:00 2001 From: Jean Delvare Date: Mon, 28 Aug 2006 14:39:26 +0200 Subject: [PATCH 13/39] it87: Copyright update it87: Copyright update I think my contributions to the it87 driver over the past two years qualify me as a co-author of this driver. Also drop old comments of dubious usefulness. Signed-off-by: Jean Delvare Signed-off-by: Greg Kroah-Hartman --- Documentation/hwmon/it87 | 4 +++- drivers/hwmon/it87.c | 12 +++--------- 2 files changed, 6 insertions(+), 10 deletions(-) diff --git a/Documentation/hwmon/it87 b/Documentation/hwmon/it87 index a45044e82662..e783fd62e308 100644 --- a/Documentation/hwmon/it87 +++ b/Documentation/hwmon/it87 @@ -29,7 +29,9 @@ Supported chips: Addresses scanned: from Super I/O config space (8 I/O ports) Datasheet: No longer be available -Author: Christophe Gauthron +Authors: + Christophe Gauthron + Jean Delvare Module Parameters diff --git a/drivers/hwmon/it87.c b/drivers/hwmon/it87.c index de62f60bcaf1..af5740d5d70f 100644 --- a/drivers/hwmon/it87.c +++ b/drivers/hwmon/it87.c @@ -9,7 +9,7 @@ Sis950 A clone of the IT8705F Copyright (C) 2001 Chris Gauthron - Largely inspired by lm78.c of the same package + Copyright (C) 2005-2006 Jean Delvare This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -26,13 +26,6 @@ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ -/* - djg@pdp8.net David Gesswein 7/18/01 - Modified to fix bug with not all alarms enabled. - Added ability to read battery voltage and select temperature sensor - type at module load time. -*/ - #include #include #include @@ -1392,7 +1385,8 @@ static void __exit sm_it87_exit(void) } -MODULE_AUTHOR("Chris Gauthron "); +MODULE_AUTHOR("Chris Gauthron , " + "Jean Delvare "); MODULE_DESCRIPTION("IT8705F/8712F/8716F/8718F, SiS950 driver"); module_param(update_vbat, bool, 0); MODULE_PARM_DESC(update_vbat, "Update vbat if set else return powerup value"); From 29fa06c1292f473ae51a84f55c8fe22179bc1080 Mon Sep 17 00:00:00 2001 From: Rudolf Marek Date: Mon, 28 Aug 2006 14:40:17 +0200 Subject: [PATCH 14/39] hwmon: New driver k8temp Add support for the temperature sensor(s) found in AMD K8 CPUs. Signed-off-by: Rudolf Marek Signed-off-by: Jean Delvare Signed-off-by: Greg Kroah-Hartman --- drivers/hwmon/Kconfig | 10 ++ drivers/hwmon/Makefile | 1 + drivers/hwmon/k8temp.c | 292 ++++++++++++++++++++++++++++++++++++++++ include/linux/pci_ids.h | 1 + 4 files changed, 304 insertions(+) create mode 100644 drivers/hwmon/k8temp.c diff --git a/drivers/hwmon/Kconfig b/drivers/hwmon/Kconfig index 78c237f8fa0a..d9f86e9d405b 100644 --- a/drivers/hwmon/Kconfig +++ b/drivers/hwmon/Kconfig @@ -94,6 +94,16 @@ config SENSORS_ADM9240 This driver can also be built as a module. If so, the module will be called adm9240. +config SENSORS_K8TEMP + tristate "AMD K8 processor sensor" + depends on HWMON && X86 && PCI && EXPERIMENTAL + help + If you say yes here you get support for the temperature + sensor(s) inside your AMD K8 CPU. + + This driver can also be built as a module. If so, the module + will be called k8temp. + config SENSORS_ASB100 tristate "Asus ASB100 Bach" depends on HWMON && I2C && EXPERIMENTAL diff --git a/drivers/hwmon/Makefile b/drivers/hwmon/Makefile index 31415843a91a..aab4c1063059 100644 --- a/drivers/hwmon/Makefile +++ b/drivers/hwmon/Makefile @@ -27,6 +27,7 @@ obj-$(CONFIG_SENSORS_GL518SM) += gl518sm.o obj-$(CONFIG_SENSORS_GL520SM) += gl520sm.o obj-$(CONFIG_SENSORS_HDAPS) += hdaps.o obj-$(CONFIG_SENSORS_IT87) += it87.o +obj-$(CONFIG_SENSORS_K8TEMP) += k8temp.o obj-$(CONFIG_SENSORS_LM63) += lm63.o obj-$(CONFIG_SENSORS_LM70) += lm70.o obj-$(CONFIG_SENSORS_LM75) += lm75.o diff --git a/drivers/hwmon/k8temp.c b/drivers/hwmon/k8temp.c new file mode 100644 index 000000000000..50162ffa8832 --- /dev/null +++ b/drivers/hwmon/k8temp.c @@ -0,0 +1,292 @@ +/* + * k8temp.c - Linux kernel module for hardware monitoring + * + * Copyright (C) 2006 Rudolf Marek + * + * Inspired from the w83785 and amd756 drivers. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301 USA. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define TEMP_FROM_REG(val) (((((val) >> 16) & 0xff) - 49) * 1000) +#define REG_TEMP 0xe4 +#define SEL_PLACE 0x40 +#define SEL_CORE 0x04 + +struct k8temp_data { + struct class_device *class_dev; + struct mutex update_lock; + const char *name; + char valid; /* zero until following fields are valid */ + unsigned long last_updated; /* in jiffies */ + + /* registers values */ + u8 sensorsp; /* sensor presence bits - SEL_CORE & SEL_PLACE */ + u32 temp[2][2]; /* core, place */ +}; + +static struct k8temp_data *k8temp_update_device(struct device *dev) +{ + struct k8temp_data *data = dev_get_drvdata(dev); + struct pci_dev *pdev = to_pci_dev(dev); + u8 tmp; + + mutex_lock(&data->update_lock); + + if (!data->valid + || time_after(jiffies, data->last_updated + HZ)) { + pci_read_config_byte(pdev, REG_TEMP, &tmp); + tmp &= ~(SEL_PLACE | SEL_CORE); /* Select sensor 0, core0 */ + pci_write_config_byte(pdev, REG_TEMP, tmp); + pci_read_config_dword(pdev, REG_TEMP, &data->temp[0][0]); + + if (data->sensorsp & SEL_PLACE) { + tmp |= SEL_PLACE; /* Select sensor 1, core0 */ + pci_write_config_byte(pdev, REG_TEMP, tmp); + pci_read_config_dword(pdev, REG_TEMP, + &data->temp[0][1]); + } + + if (data->sensorsp & SEL_CORE) { + tmp &= ~SEL_PLACE; /* Select sensor 0, core1 */ + tmp |= SEL_CORE; + pci_write_config_byte(pdev, REG_TEMP, tmp); + pci_read_config_dword(pdev, REG_TEMP, + &data->temp[1][0]); + + if (data->sensorsp & SEL_PLACE) { + tmp |= SEL_PLACE; /* Select sensor 1, core1 */ + pci_write_config_byte(pdev, REG_TEMP, tmp); + pci_read_config_dword(pdev, REG_TEMP, + &data->temp[1][1]); + } + } + + data->last_updated = jiffies; + data->valid = 1; + } + + mutex_unlock(&data->update_lock); + return data; +} + +/* + * Sysfs stuff + */ + +static ssize_t show_name(struct device *dev, struct device_attribute + *devattr, char *buf) +{ + struct k8temp_data *data = dev_get_drvdata(dev); + + return sprintf(buf, "%s\n", data->name); +} + + +static ssize_t show_temp(struct device *dev, + struct device_attribute *devattr, char *buf) +{ + struct sensor_device_attribute_2 *attr = + to_sensor_dev_attr_2(devattr); + int core = attr->nr; + int place = attr->index; + struct k8temp_data *data = k8temp_update_device(dev); + + return sprintf(buf, "%d\n", + TEMP_FROM_REG(data->temp[core][place])); +} + +/* core, place */ + +static SENSOR_DEVICE_ATTR_2(temp1_input, S_IRUGO, show_temp, NULL, 0, 0); +static SENSOR_DEVICE_ATTR_2(temp2_input, S_IRUGO, show_temp, NULL, 0, 1); +static SENSOR_DEVICE_ATTR_2(temp3_input, S_IRUGO, show_temp, NULL, 1, 0); +static SENSOR_DEVICE_ATTR_2(temp4_input, S_IRUGO, show_temp, NULL, 1, 1); +static DEVICE_ATTR(name, S_IRUGO, show_name, NULL); + +static struct pci_device_id k8temp_ids[] = { + { PCI_DEVICE(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_K8_NB_MISC) }, + { 0 }, +}; + +static int __devinit k8temp_probe(struct pci_dev *pdev, + const struct pci_device_id *id) +{ + int err; + u8 scfg; + u32 temp; + struct k8temp_data *data; + u32 cpuid = cpuid_eax(1); + + /* this feature should be available since SH-C0 core */ + if ((cpuid == 0xf40) || (cpuid == 0xf50) || (cpuid == 0xf51)) { + err = -ENODEV; + goto exit; + } + + if (!(data = kzalloc(sizeof(struct k8temp_data), GFP_KERNEL))) { + err = -ENOMEM; + goto exit; + } + + pci_read_config_byte(pdev, REG_TEMP, &scfg); + scfg &= ~(SEL_PLACE | SEL_CORE); /* Select sensor 0, core0 */ + pci_write_config_byte(pdev, REG_TEMP, scfg); + pci_read_config_byte(pdev, REG_TEMP, &scfg); + + if (scfg & (SEL_PLACE | SEL_CORE)) { + dev_err(&pdev->dev, "Configuration bit(s) stuck at 1!\n"); + err = -ENODEV; + goto exit_free; + } + + scfg |= (SEL_PLACE | SEL_CORE); + pci_write_config_byte(pdev, REG_TEMP, scfg); + + /* now we know if we can change core and/or sensor */ + pci_read_config_byte(pdev, REG_TEMP, &data->sensorsp); + + if (data->sensorsp & SEL_PLACE) { + scfg &= ~SEL_CORE; /* Select sensor 1, core0 */ + pci_write_config_byte(pdev, REG_TEMP, scfg); + pci_read_config_dword(pdev, REG_TEMP, &temp); + scfg |= SEL_CORE; /* prepare for next selection */ + if (!((temp >> 16) & 0xff)) /* if temp is 0 -49C is not likely */ + data->sensorsp &= ~SEL_PLACE; + } + + if (data->sensorsp & SEL_CORE) { + scfg &= ~SEL_PLACE; /* Select sensor 0, core1 */ + pci_write_config_byte(pdev, REG_TEMP, scfg); + pci_read_config_dword(pdev, REG_TEMP, &temp); + if (!((temp >> 16) & 0xff)) /* if temp is 0 -49C is not likely */ + data->sensorsp &= ~SEL_CORE; + } + + data->name = "k8temp"; + mutex_init(&data->update_lock); + dev_set_drvdata(&pdev->dev, data); + + /* Register sysfs hooks */ + err = device_create_file(&pdev->dev, + &sensor_dev_attr_temp1_input.dev_attr); + if (err) + goto exit_remove; + + /* sensor can be changed and reports something */ + if (data->sensorsp & SEL_PLACE) { + err = device_create_file(&pdev->dev, + &sensor_dev_attr_temp2_input.dev_attr); + if (err) + goto exit_remove; + } + + /* core can be changed and reports something */ + if (data->sensorsp & SEL_CORE) { + err = device_create_file(&pdev->dev, + &sensor_dev_attr_temp3_input.dev_attr); + if (err) + goto exit_remove; + if (data->sensorsp & SEL_PLACE) + err = device_create_file(&pdev->dev, + &sensor_dev_attr_temp4_input. + dev_attr); + if (err) + goto exit_remove; + } + + err = device_create_file(&pdev->dev, &dev_attr_name); + if (err) + goto exit_remove; + + data->class_dev = hwmon_device_register(&pdev->dev); + + if (IS_ERR(data->class_dev)) { + err = PTR_ERR(data->class_dev); + goto exit_remove; + } + + return 0; + +exit_remove: + device_remove_file(&pdev->dev, + &sensor_dev_attr_temp1_input.dev_attr); + device_remove_file(&pdev->dev, + &sensor_dev_attr_temp2_input.dev_attr); + device_remove_file(&pdev->dev, + &sensor_dev_attr_temp3_input.dev_attr); + device_remove_file(&pdev->dev, + &sensor_dev_attr_temp4_input.dev_attr); + device_remove_file(&pdev->dev, &dev_attr_name); +exit_free: + dev_set_drvdata(&pdev->dev, NULL); + kfree(data); +exit: + return err; +} + +static void __devexit k8temp_remove(struct pci_dev *pdev) +{ + struct k8temp_data *data = dev_get_drvdata(&pdev->dev); + + hwmon_device_unregister(data->class_dev); + device_remove_file(&pdev->dev, + &sensor_dev_attr_temp1_input.dev_attr); + device_remove_file(&pdev->dev, + &sensor_dev_attr_temp2_input.dev_attr); + device_remove_file(&pdev->dev, + &sensor_dev_attr_temp3_input.dev_attr); + device_remove_file(&pdev->dev, + &sensor_dev_attr_temp4_input.dev_attr); + device_remove_file(&pdev->dev, &dev_attr_name); + dev_set_drvdata(&pdev->dev, NULL); + kfree(data); +} + +static struct pci_driver k8temp_driver = { + .name = "k8temp", + .id_table = k8temp_ids, + .probe = k8temp_probe, + .remove = __devexit_p(k8temp_remove), +}; + +static int __init k8temp_init(void) +{ + return pci_register_driver(&k8temp_driver); +} + +static void __exit k8temp_exit(void) +{ + pci_unregister_driver(&k8temp_driver); +} + +MODULE_AUTHOR("Rudolf Marek "); +MODULE_DESCRIPTION("AMD K8 core temperature monitor"); +MODULE_LICENSE("GPL"); + +module_init(k8temp_init) +module_exit(k8temp_exit) diff --git a/include/linux/pci_ids.h b/include/linux/pci_ids.h index ab032ceafa84..61db1907f06f 100644 --- a/include/linux/pci_ids.h +++ b/include/linux/pci_ids.h @@ -479,6 +479,7 @@ #define PCI_VENDOR_ID_AMD 0x1022 #define PCI_DEVICE_ID_AMD_K8_NB 0x1100 +#define PCI_DEVICE_ID_AMD_K8_NB_MISC 0x1103 #define PCI_DEVICE_ID_AMD_LANCE 0x2000 #define PCI_DEVICE_ID_AMD_LANCE_HOME 0x2001 #define PCI_DEVICE_ID_AMD_SCSI 0x2020 From b17ebc9402040959690b5a2c4e1cfb1e6d4fb206 Mon Sep 17 00:00:00 2001 From: Jean Delvare Date: Mon, 28 Aug 2006 14:41:03 +0200 Subject: [PATCH 15/39] k8temp: Enable automatic loading Let the k8temp driver load automatically. Signed-off-by: Jean Delvare Cc: Rudolf Marek Signed-off-by: Greg Kroah-Hartman --- drivers/hwmon/k8temp.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/hwmon/k8temp.c b/drivers/hwmon/k8temp.c index 50162ffa8832..f58b64ed09e3 100644 --- a/drivers/hwmon/k8temp.c +++ b/drivers/hwmon/k8temp.c @@ -133,6 +133,8 @@ static struct pci_device_id k8temp_ids[] = { { 0 }, }; +MODULE_DEVICE_TABLE(pci, k8temp_ids); + static int __devinit k8temp_probe(struct pci_dev *pdev, const struct pci_device_id *id) { From 360b9ab220aedaf346380fc2344729d9acc3b075 Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Mon, 28 Aug 2006 14:42:24 +0200 Subject: [PATCH 16/39] abituguru: Add suspend/resume support This patch contains rudimentary suspend / resume support for the uguru, this protects the uguru and the driver against suspend / resume cycles, so there is no reason to unload the driver in your suspend / resume scripts. Only include suspend / resume functions when CONFIG_PM is set. Signed-off-by: Hans de Goede Signed-off-by: Jean Delvare Signed-off-by: Greg Kroah-Hartman --- drivers/hwmon/abituguru.c | 30 ++++++++++++++++++++++++++++-- 1 file changed, 28 insertions(+), 2 deletions(-) diff --git a/drivers/hwmon/abituguru.c b/drivers/hwmon/abituguru.c index 35ad1b032726..e5cb0fdab9b1 100644 --- a/drivers/hwmon/abituguru.c +++ b/drivers/hwmon/abituguru.c @@ -1354,13 +1354,39 @@ static struct abituguru_data *abituguru_update_device(struct device *dev) return NULL; } +#ifdef CONFIG_PM +static int abituguru_suspend(struct platform_device *pdev, pm_message_t state) +{ + struct abituguru_data *data = platform_get_drvdata(pdev); + /* make sure all communications with the uguru are done and no new + ones are started */ + mutex_lock(&data->update_lock); + return 0; +} + +static int abituguru_resume(struct platform_device *pdev) +{ + struct abituguru_data *data = platform_get_drvdata(pdev); + /* See if the uGuru is still ready */ + if (inb_p(data->addr + ABIT_UGURU_DATA) != ABIT_UGURU_STATUS_INPUT) + data->uguru_ready = 0; + mutex_unlock(&data->update_lock); + return 0; +} +#else +#define abituguru_suspend NULL +#define abituguru_resume NULL +#endif /* CONFIG_PM */ + static struct platform_driver abituguru_driver = { .driver = { .owner = THIS_MODULE, .name = ABIT_UGURU_NAME, }, - .probe = abituguru_probe, - .remove = __devexit_p(abituguru_remove), + .probe = abituguru_probe, + .remove = __devexit_p(abituguru_remove), + .suspend = abituguru_suspend, + .resume = abituguru_resume, }; static int __init abituguru_detect(void) From ef4c4fdb2809c84c2ed8f037ae7c96cc03992569 Mon Sep 17 00:00:00 2001 From: Rudolf Marek Date: Sun, 24 Sep 2006 20:50:57 +0200 Subject: [PATCH 17/39] k8temp: Add documentation k8temp: Add documentation Add promised documentation for the k8temp driver. Signed-off-by: Rudolf Marek Signed-off-by: Jean Delvare Signed-off-by: Greg Kroah-Hartman --- Documentation/hwmon/k8temp | 52 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 52 insertions(+) create mode 100644 Documentation/hwmon/k8temp diff --git a/Documentation/hwmon/k8temp b/Documentation/hwmon/k8temp new file mode 100644 index 000000000000..bab445ab0f52 --- /dev/null +++ b/Documentation/hwmon/k8temp @@ -0,0 +1,52 @@ +Kernel driver k8temp +==================== + +Supported chips: + * AMD K8 CPU + Prefix: 'k8temp' + Addresses scanned: PCI space + Datasheet: http://www.amd.com/us-en/assets/content_type/white_papers_and_tech_docs/32559.pdf + +Author: Rudolf Marek +Contact: Rudolf Marek + +Description +----------- + +This driver permits reading temperature sensor(s) embedded inside AMD K8 CPUs. +Official documentation says that it works from revision F of K8 core, but +in fact it seems to be implemented for all revisions of K8 except the first +two revisions (SH-B0 and SH-B3). + +There can be up to four temperature sensors inside single CPU. The driver +will auto-detect the sensors and will display only temperatures from +implemented sensors. + +Mapping of /sys files is as follows: + +temp1_input - temperature of Core 0 and "place" 0 +temp2_input - temperature of Core 0 and "place" 1 +temp3_input - temperature of Core 1 and "place" 0 +temp4_input - temperature of Core 1 and "place" 1 + +Temperatures are measured in degrees Celsius and measurement resolution is +1 degree C. It is expected that future CPU will have better resolution. The +temperature is updated once a second. Valid temperatures are from -49 to +206 degrees C. + +Temperature known as TCaseMax was specified for processors up to revision E. +This temperature is defined as temperature between heat-spreader and CPU +case, so the internal CPU temperature supplied by this driver can be higher. +There is no easy way how to measure the temperature which will correlate +with TCaseMax temperature. + +For newer revisions of CPU (rev F, socket AM2) there is a mathematically +computed temperature called TControl, which must be lower than TControlMax. + +The relationship is following: + +temp1_input - TjOffset*2 < TControlMax, + +TjOffset is not yet exported by the driver, TControlMax is usually +70 degrees C. The rule of the thumb -> CPU temperature should not cross +60 degrees C too much. From 51bd56339335fad3643739504523190cd6d3416b Mon Sep 17 00:00:00 2001 From: Jean Delvare Date: Sun, 24 Sep 2006 20:51:37 +0200 Subject: [PATCH 18/39] hwmon: Make a dozen drivers no more experimental hwmon: Make a dozen drivers no more experimental Remove the EXPERIMENTAL tag from a dozen hardware monitoring drivers. They are in the tree for quite a long time, so we would know by now if they were causing trouble. Also make it clearer that the VT8231 is a VIA chip. Signed-off-by: Jean Delvare Signed-off-by: Greg Kroah-Hartman --- drivers/hwmon/Kconfig | 26 +++++++++++++------------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/drivers/hwmon/Kconfig b/drivers/hwmon/Kconfig index d9f86e9d405b..696543ba6a29 100644 --- a/drivers/hwmon/Kconfig +++ b/drivers/hwmon/Kconfig @@ -53,7 +53,7 @@ config SENSORS_ADM1021 config SENSORS_ADM1025 tristate "Analog Devices ADM1025 and compatibles" - depends on HWMON && I2C && EXPERIMENTAL + depends on HWMON && I2C select HWMON_VID help If you say yes here you get support for Analog Devices ADM1025 @@ -131,7 +131,7 @@ config SENSORS_ATXP1 config SENSORS_DS1621 tristate "Dallas Semiconductor DS1621 and DS1625" - depends on HWMON && I2C && EXPERIMENTAL + depends on HWMON && I2C help If you say yes here you get support for Dallas Semiconductor DS1621 and DS1625 sensor chips. @@ -151,7 +151,7 @@ config SENSORS_F71805F config SENSORS_FSCHER tristate "FSC Hermes" - depends on HWMON && I2C && EXPERIMENTAL + depends on HWMON && I2C help If you say yes here you get support for Fujitsu Siemens Computers Hermes sensor chips. @@ -161,7 +161,7 @@ config SENSORS_FSCHER config SENSORS_FSCPOS tristate "FSC Poseidon" - depends on HWMON && I2C && EXPERIMENTAL + depends on HWMON && I2C help If you say yes here you get support for Fujitsu Siemens Computers Poseidon sensor chips. @@ -181,7 +181,7 @@ config SENSORS_GL518SM config SENSORS_GL520SM tristate "Genesys Logic GL520SM" - depends on HWMON && I2C && EXPERIMENTAL + depends on HWMON && I2C select HWMON_VID help If you say yes here you get support for Genesys Logic GL520SM @@ -204,7 +204,7 @@ config SENSORS_IT87 config SENSORS_LM63 tristate "National Semiconductor LM63" - depends on HWMON && I2C && EXPERIMENTAL + depends on HWMON && I2C help If you say yes here you get support for the National Semiconductor LM63 remote diode digital temperature sensor with integrated fan @@ -241,7 +241,7 @@ config SENSORS_LM75 config SENSORS_LM77 tristate "National Semiconductor LM77" - depends on HWMON && I2C && EXPERIMENTAL + depends on HWMON && I2C help If you say yes here you get support for National Semiconductor LM77 sensor chips. @@ -251,7 +251,7 @@ config SENSORS_LM77 config SENSORS_LM78 tristate "National Semiconductor LM78 and compatibles" - depends on HWMON && I2C && EXPERIMENTAL + depends on HWMON && I2C select I2C_ISA select HWMON_VID help @@ -294,7 +294,7 @@ config SENSORS_LM85 config SENSORS_LM87 tristate "National Semiconductor LM87" - depends on HWMON && I2C && EXPERIMENTAL + depends on HWMON && I2C select HWMON_VID help If you say yes here you get support for National Semiconductor LM87 @@ -319,7 +319,7 @@ config SENSORS_LM90 config SENSORS_LM92 tristate "National Semiconductor LM92 and compatibles" - depends on HWMON && I2C && EXPERIMENTAL + depends on HWMON && I2C help If you say yes here you get support for National Semiconductor LM92 and Maxim MAX6635 sensor chips. @@ -329,7 +329,7 @@ config SENSORS_LM92 config SENSORS_MAX1619 tristate "Maxim MAX1619 sensor chip" - depends on HWMON && I2C && EXPERIMENTAL + depends on HWMON && I2C help If you say yes here you get support for MAX1619 sensor chip. @@ -364,7 +364,7 @@ config SENSORS_SIS5595 config SENSORS_SMSC47M1 tristate "SMSC LPC47M10x and compatibles" - depends on HWMON && I2C && EXPERIMENTAL + depends on HWMON && I2C select I2C_ISA help If you say yes here you get support for the integrated fan @@ -418,7 +418,7 @@ config SENSORS_VIA686A will be called via686a. config SENSORS_VT8231 - tristate "VT8231" + tristate "VIA VT8231" depends on HWMON && I2C && PCI && EXPERIMENTAL select HWMON_VID select I2C_ISA From 2d45771e6ea79f56a7d85e448f702f60ef86c228 Mon Sep 17 00:00:00 2001 From: Jean Delvare Date: Sun, 24 Sep 2006 20:52:15 +0200 Subject: [PATCH 19/39] hwmon: Add individual alarm files to 4 drivers hwmon: Add individual alarm files to 4 drivers Add individual sysfs files for all f71805f, lm63, lm83 and lm90 alarm and fault conditions. This is a requirement for the planned chip-independent libsensors. Almost all other hwmon drivers will need the same improvement. Signed-off-by: Jean Delvare Signed-off-by: Greg Kroah-Hartman --- drivers/hwmon/f71805f.c | 46 +++++++++++++++++++++++++++++--------- drivers/hwmon/lm63.c | 33 ++++++++++++++++++++++++++- drivers/hwmon/lm83.c | 49 ++++++++++++++++++++++++++++++++++++++++- drivers/hwmon/lm90.c | 37 ++++++++++++++++++++++++++++++- 4 files changed, 151 insertions(+), 14 deletions(-) diff --git a/drivers/hwmon/f71805f.c b/drivers/hwmon/f71805f.c index fd72440faf76..678bae43716d 100644 --- a/drivers/hwmon/f71805f.c +++ b/drivers/hwmon/f71805f.c @@ -1,7 +1,7 @@ /* * f71805f.c - driver for the Fintek F71805F/FG Super-I/O chip integrated * hardware monitoring features - * Copyright (C) 2005 Jean Delvare + * Copyright (C) 2005-2006 Jean Delvare * * The F71805F/FG is a LPC Super-I/O chip made by Fintek. It integrates * complete hardware monitoring features: voltage, fan and temperature @@ -147,7 +147,7 @@ struct f71805f_data { u8 temp_high[3]; u8 temp_hyst[3]; u8 temp_mode; - u8 alarms[3]; + unsigned long alarms; }; static inline long in_from_reg(u8 reg) @@ -311,10 +311,9 @@ static struct f71805f_data *f71805f_update_device(struct device *dev) data->temp[nr] = f71805f_read8(data, F71805F_REG_TEMP(nr)); } - for (nr = 0; nr < 3; nr++) { - data->alarms[nr] = f71805f_read8(data, - F71805F_REG_STATUS(nr)); - } + data->alarms = f71805f_read8(data, F71805F_REG_STATUS(0)) + + (f71805f_read8(data, F71805F_REG_STATUS(1)) << 8) + + (f71805f_read8(data, F71805F_REG_STATUS(2)) << 16); data->last_updated = jiffies; data->valid = 1; @@ -557,8 +556,7 @@ static ssize_t show_alarms_in(struct device *dev, struct device_attribute { struct f71805f_data *data = f71805f_update_device(dev); - return sprintf(buf, "%d\n", data->alarms[0] | - ((data->alarms[1] & 0x01) << 8)); + return sprintf(buf, "%lu\n", data->alarms & 0x1ff); } static ssize_t show_alarms_fan(struct device *dev, struct device_attribute @@ -566,7 +564,7 @@ static ssize_t show_alarms_fan(struct device *dev, struct device_attribute { struct f71805f_data *data = f71805f_update_device(dev); - return sprintf(buf, "%d\n", data->alarms[2] & 0x07); + return sprintf(buf, "%lu\n", (data->alarms >> 16) & 0x07); } static ssize_t show_alarms_temp(struct device *dev, struct device_attribute @@ -574,7 +572,17 @@ static ssize_t show_alarms_temp(struct device *dev, struct device_attribute { struct f71805f_data *data = f71805f_update_device(dev); - return sprintf(buf, "%d\n", (data->alarms[1] >> 3) & 0x07); + return sprintf(buf, "%lu\n", (data->alarms >> 11) & 0x07); +} + +static ssize_t show_alarm(struct device *dev, struct device_attribute + *devattr, char *buf) +{ + struct f71805f_data *data = f71805f_update_device(dev); + struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); + int bitnr = attr->index; + + return sprintf(buf, "%lu\n", (data->alarms >> bitnr) & 1); } static ssize_t show_name(struct device *dev, struct device_attribute @@ -655,18 +663,34 @@ static struct sensor_device_attribute f71805f_sensor_attr[] = { SENSOR_ATTR(temp3_max_hyst, S_IRUGO | S_IWUSR, show_temp_hyst, set_temp_hyst, 2), SENSOR_ATTR(temp3_type, S_IRUGO, show_temp_type, NULL, 2), + + SENSOR_ATTR(in0_alarm, S_IRUGO, show_alarm, NULL, 0), + SENSOR_ATTR(in1_alarm, S_IRUGO, show_alarm, NULL, 1), + SENSOR_ATTR(in2_alarm, S_IRUGO, show_alarm, NULL, 2), + SENSOR_ATTR(in3_alarm, S_IRUGO, show_alarm, NULL, 3), + SENSOR_ATTR(in4_alarm, S_IRUGO, show_alarm, NULL, 4), + SENSOR_ATTR(in5_alarm, S_IRUGO, show_alarm, NULL, 5), + SENSOR_ATTR(in6_alarm, S_IRUGO, show_alarm, NULL, 6), + SENSOR_ATTR(in7_alarm, S_IRUGO, show_alarm, NULL, 7), + SENSOR_ATTR(in8_alarm, S_IRUGO, show_alarm, NULL, 8), + SENSOR_ATTR(temp1_alarm, S_IRUGO, show_alarm, NULL, 11), + SENSOR_ATTR(temp2_alarm, S_IRUGO, show_alarm, NULL, 12), + SENSOR_ATTR(temp3_alarm, S_IRUGO, show_alarm, NULL, 13), }; static struct sensor_device_attribute f71805f_fan_attr[] = { SENSOR_ATTR(fan1_input, S_IRUGO, show_fan, NULL, 0), SENSOR_ATTR(fan1_min, S_IRUGO | S_IWUSR, show_fan_min, set_fan_min, 0), + SENSOR_ATTR(fan1_alarm, S_IRUGO, show_alarm, NULL, 16), SENSOR_ATTR(fan2_input, S_IRUGO, show_fan, NULL, 1), SENSOR_ATTR(fan2_min, S_IRUGO | S_IWUSR, show_fan_min, set_fan_min, 1), + SENSOR_ATTR(fan2_alarm, S_IRUGO, show_alarm, NULL, 17), SENSOR_ATTR(fan3_input, S_IRUGO, show_fan, NULL, 2), SENSOR_ATTR(fan3_min, S_IRUGO | S_IWUSR, show_fan_min, set_fan_min, 2), + SENSOR_ATTR(fan3_alarm, S_IRUGO, show_alarm, NULL, 18), }; /* @@ -737,7 +761,7 @@ static int __devinit f71805f_probe(struct platform_device *pdev) goto exit_class; } for (i = 0; i < ARRAY_SIZE(f71805f_fan_attr); i++) { - if (!(data->fan_enabled & (1 << (i / 2)))) + if (!(data->fan_enabled & (1 << (i / 3)))) continue; err = device_create_file(&pdev->dev, &f71805f_fan_attr[i].dev_attr); diff --git a/drivers/hwmon/lm63.c b/drivers/hwmon/lm63.c index 071f0fc6adec..00a50bea7cbd 100644 --- a/drivers/hwmon/lm63.c +++ b/drivers/hwmon/lm63.c @@ -1,7 +1,7 @@ /* * lm63.c - driver for the National Semiconductor LM63 temperature sensor * with integrated fan control - * Copyright (C) 2004-2005 Jean Delvare + * Copyright (C) 2004-2006 Jean Delvare * Based on the lm90 driver. * * The LM63 is a sensor chip made by National Semiconductor. It measures @@ -330,6 +330,16 @@ static ssize_t show_alarms(struct device *dev, struct device_attribute *dummy, return sprintf(buf, "%u\n", data->alarms); } +static ssize_t show_alarm(struct device *dev, struct device_attribute *devattr, + char *buf) +{ + struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); + struct lm63_data *data = lm63_update_device(dev); + int bitnr = attr->index; + + return sprintf(buf, "%u\n", (data->alarms >> bitnr) & 1); +} + static SENSOR_DEVICE_ATTR(fan1_input, S_IRUGO, show_fan, NULL, 0); static SENSOR_DEVICE_ATTR(fan1_min, S_IWUSR | S_IRUGO, show_fan, set_fan, 1); @@ -350,6 +360,14 @@ static SENSOR_DEVICE_ATTR(temp2_crit, S_IRUGO, show_temp8, NULL, 2); static DEVICE_ATTR(temp2_crit_hyst, S_IWUSR | S_IRUGO, show_temp2_crit_hyst, set_temp2_crit_hyst); +/* Individual alarm files */ +static SENSOR_DEVICE_ATTR(fan1_min_alarm, S_IRUGO, show_alarm, NULL, 0); +static SENSOR_DEVICE_ATTR(temp2_crit_alarm, S_IRUGO, show_alarm, NULL, 1); +static SENSOR_DEVICE_ATTR(temp2_input_fault, S_IRUGO, show_alarm, NULL, 2); +static SENSOR_DEVICE_ATTR(temp2_min_alarm, S_IRUGO, show_alarm, NULL, 3); +static SENSOR_DEVICE_ATTR(temp2_max_alarm, S_IRUGO, show_alarm, NULL, 4); +static SENSOR_DEVICE_ATTR(temp1_max_alarm, S_IRUGO, show_alarm, NULL, 6); +/* Raw alarm file for compatibility */ static DEVICE_ATTR(alarms, S_IRUGO, show_alarms, NULL); /* @@ -449,6 +467,8 @@ static int lm63_detect(struct i2c_adapter *adapter, int address, int kind) &sensor_dev_attr_fan1_input.dev_attr); device_create_file(&new_client->dev, &sensor_dev_attr_fan1_min.dev_attr); + device_create_file(&new_client->dev, + &sensor_dev_attr_fan1_min_alarm.dev_attr); } device_create_file(&new_client->dev, &dev_attr_pwm1); device_create_file(&new_client->dev, &dev_attr_pwm1_enable); @@ -465,6 +485,17 @@ static int lm63_detect(struct i2c_adapter *adapter, int address, int kind) device_create_file(&new_client->dev, &sensor_dev_attr_temp2_crit.dev_attr); device_create_file(&new_client->dev, &dev_attr_temp2_crit_hyst); + + device_create_file(&new_client->dev, + &sensor_dev_attr_temp2_input_fault.dev_attr); + device_create_file(&new_client->dev, + &sensor_dev_attr_temp2_min_alarm.dev_attr); + device_create_file(&new_client->dev, + &sensor_dev_attr_temp1_max_alarm.dev_attr); + device_create_file(&new_client->dev, + &sensor_dev_attr_temp2_max_alarm.dev_attr); + device_create_file(&new_client->dev, + &sensor_dev_attr_temp2_crit_alarm.dev_attr); device_create_file(&new_client->dev, &dev_attr_alarms); return 0; diff --git a/drivers/hwmon/lm83.c b/drivers/hwmon/lm83.c index 2137d7879df6..ea224891d311 100644 --- a/drivers/hwmon/lm83.c +++ b/drivers/hwmon/lm83.c @@ -1,7 +1,7 @@ /* * lm83.c - Part of lm_sensors, Linux kernel modules for hardware * monitoring - * Copyright (C) 2003-2005 Jean Delvare + * Copyright (C) 2003-2006 Jean Delvare * * Heavily inspired from the lm78, lm75 and adm1021 drivers. The LM83 is * a sensor chip made by National Semiconductor. It reports up to four @@ -191,6 +191,16 @@ static ssize_t show_alarms(struct device *dev, struct device_attribute *dummy, return sprintf(buf, "%d\n", data->alarms); } +static ssize_t show_alarm(struct device *dev, struct device_attribute + *devattr, char *buf) +{ + struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); + struct lm83_data *data = lm83_update_device(dev); + int bitnr = attr->index; + + return sprintf(buf, "%d\n", (data->alarms >> bitnr) & 1); +} + static SENSOR_DEVICE_ATTR(temp1_input, S_IRUGO, show_temp, NULL, 0); static SENSOR_DEVICE_ATTR(temp2_input, S_IRUGO, show_temp, NULL, 1); static SENSOR_DEVICE_ATTR(temp3_input, S_IRUGO, show_temp, NULL, 2); @@ -208,6 +218,20 @@ static SENSOR_DEVICE_ATTR(temp2_crit, S_IRUGO, show_temp, NULL, 8); static SENSOR_DEVICE_ATTR(temp3_crit, S_IWUSR | S_IRUGO, show_temp, set_temp, 8); static SENSOR_DEVICE_ATTR(temp4_crit, S_IRUGO, show_temp, NULL, 8); + +/* Individual alarm files */ +static SENSOR_DEVICE_ATTR(temp1_crit_alarm, S_IRUGO, show_alarm, NULL, 0); +static SENSOR_DEVICE_ATTR(temp3_crit_alarm, S_IRUGO, show_alarm, NULL, 1); +static SENSOR_DEVICE_ATTR(temp3_input_fault, S_IRUGO, show_alarm, NULL, 2); +static SENSOR_DEVICE_ATTR(temp3_max_alarm, S_IRUGO, show_alarm, NULL, 4); +static SENSOR_DEVICE_ATTR(temp1_max_alarm, S_IRUGO, show_alarm, NULL, 6); +static SENSOR_DEVICE_ATTR(temp2_crit_alarm, S_IRUGO, show_alarm, NULL, 8); +static SENSOR_DEVICE_ATTR(temp4_crit_alarm, S_IRUGO, show_alarm, NULL, 9); +static SENSOR_DEVICE_ATTR(temp4_input_fault, S_IRUGO, show_alarm, NULL, 10); +static SENSOR_DEVICE_ATTR(temp4_max_alarm, S_IRUGO, show_alarm, NULL, 12); +static SENSOR_DEVICE_ATTR(temp2_input_fault, S_IRUGO, show_alarm, NULL, 13); +static SENSOR_DEVICE_ATTR(temp2_max_alarm, S_IRUGO, show_alarm, NULL, 15); +/* Raw alarm file for compatibility */ static DEVICE_ATTR(alarms, S_IRUGO, show_alarms, NULL); /* @@ -350,6 +374,16 @@ static int lm83_detect(struct i2c_adapter *adapter, int address, int kind) device_create_file(&new_client->dev, &sensor_dev_attr_temp3_crit.dev_attr); + device_create_file(&new_client->dev, + &sensor_dev_attr_temp3_input_fault.dev_attr); + device_create_file(&new_client->dev, + &sensor_dev_attr_temp1_max_alarm.dev_attr); + device_create_file(&new_client->dev, + &sensor_dev_attr_temp3_max_alarm.dev_attr); + device_create_file(&new_client->dev, + &sensor_dev_attr_temp1_crit_alarm.dev_attr); + device_create_file(&new_client->dev, + &sensor_dev_attr_temp3_crit_alarm.dev_attr); device_create_file(&new_client->dev, &dev_attr_alarms); if (kind == lm83) { @@ -367,6 +401,19 @@ static int lm83_detect(struct i2c_adapter *adapter, int address, int kind) &sensor_dev_attr_temp2_crit.dev_attr); device_create_file(&new_client->dev, &sensor_dev_attr_temp4_crit.dev_attr); + + device_create_file(&new_client->dev, + &sensor_dev_attr_temp2_input_fault.dev_attr); + device_create_file(&new_client->dev, + &sensor_dev_attr_temp4_input_fault.dev_attr); + device_create_file(&new_client->dev, + &sensor_dev_attr_temp2_max_alarm.dev_attr); + device_create_file(&new_client->dev, + &sensor_dev_attr_temp4_max_alarm.dev_attr); + device_create_file(&new_client->dev, + &sensor_dev_attr_temp2_crit_alarm.dev_attr); + device_create_file(&new_client->dev, + &sensor_dev_attr_temp4_crit_alarm.dev_attr); } return 0; diff --git a/drivers/hwmon/lm90.c b/drivers/hwmon/lm90.c index d9eeaf7585bd..77f8e3f7fd49 100644 --- a/drivers/hwmon/lm90.c +++ b/drivers/hwmon/lm90.c @@ -1,7 +1,7 @@ /* * lm90.c - Part of lm_sensors, Linux kernel modules for hardware * monitoring - * Copyright (C) 2003-2005 Jean Delvare + * Copyright (C) 2003-2006 Jean Delvare * * Based on the lm83 driver. The LM90 is a sensor chip made by National * Semiconductor. It reports up to two temperatures (its own plus up to @@ -327,6 +327,16 @@ static ssize_t show_alarms(struct device *dev, struct device_attribute *dummy, return sprintf(buf, "%d\n", data->alarms); } +static ssize_t show_alarm(struct device *dev, struct device_attribute + *devattr, char *buf) +{ + struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); + struct lm90_data *data = lm90_update_device(dev); + int bitnr = attr->index; + + return sprintf(buf, "%d\n", (data->alarms >> bitnr) & 1); +} + static SENSOR_DEVICE_ATTR(temp1_input, S_IRUGO, show_temp8, NULL, 0); static SENSOR_DEVICE_ATTR(temp2_input, S_IRUGO, show_temp11, NULL, 0); static SENSOR_DEVICE_ATTR(temp1_min, S_IWUSR | S_IRUGO, show_temp8, @@ -344,6 +354,16 @@ static SENSOR_DEVICE_ATTR(temp2_crit, S_IWUSR | S_IRUGO, show_temp8, static SENSOR_DEVICE_ATTR(temp1_crit_hyst, S_IWUSR | S_IRUGO, show_temphyst, set_temphyst, 3); static SENSOR_DEVICE_ATTR(temp2_crit_hyst, S_IRUGO, show_temphyst, NULL, 4); + +/* Individual alarm files */ +static SENSOR_DEVICE_ATTR(temp1_crit_alarm, S_IRUGO, show_alarm, NULL, 0); +static SENSOR_DEVICE_ATTR(temp2_crit_alarm, S_IRUGO, show_alarm, NULL, 1); +static SENSOR_DEVICE_ATTR(temp2_input_fault, S_IRUGO, show_alarm, NULL, 2); +static SENSOR_DEVICE_ATTR(temp2_min_alarm, S_IRUGO, show_alarm, NULL, 3); +static SENSOR_DEVICE_ATTR(temp2_max_alarm, S_IRUGO, show_alarm, NULL, 4); +static SENSOR_DEVICE_ATTR(temp1_min_alarm, S_IRUGO, show_alarm, NULL, 5); +static SENSOR_DEVICE_ATTR(temp1_max_alarm, S_IRUGO, show_alarm, NULL, 6); +/* Raw alarm file for compatibility */ static DEVICE_ATTR(alarms, S_IRUGO, show_alarms, NULL); /* pec used for ADM1032 only */ @@ -595,6 +615,21 @@ static int lm90_detect(struct i2c_adapter *adapter, int address, int kind) &sensor_dev_attr_temp1_crit_hyst.dev_attr); device_create_file(&new_client->dev, &sensor_dev_attr_temp2_crit_hyst.dev_attr); + + device_create_file(&new_client->dev, + &sensor_dev_attr_temp2_input_fault.dev_attr); + device_create_file(&new_client->dev, + &sensor_dev_attr_temp1_min_alarm.dev_attr); + device_create_file(&new_client->dev, + &sensor_dev_attr_temp2_min_alarm.dev_attr); + device_create_file(&new_client->dev, + &sensor_dev_attr_temp1_max_alarm.dev_attr); + device_create_file(&new_client->dev, + &sensor_dev_attr_temp2_max_alarm.dev_attr); + device_create_file(&new_client->dev, + &sensor_dev_attr_temp1_crit_alarm.dev_attr); + device_create_file(&new_client->dev, + &sensor_dev_attr_temp2_crit_alarm.dev_attr); device_create_file(&new_client->dev, &dev_attr_alarms); if (new_client->flags & I2C_CLIENT_PEC) From 125751cb833f20c12c7237782b2a4680fd636ed0 Mon Sep 17 00:00:00 2001 From: Charles Spirakis Date: Sun, 24 Sep 2006 20:53:04 +0200 Subject: [PATCH 20/39] w83791d: Documentation update w83791d: Documentation update The alarm bits and the beep enable bits are in different positions in the hardware. Document the problem and leave it to the user-space code to handle the situation. When this driver is updated to the standardized sysfs alarm/beep methodology, this won't be a problem. This is a documentation only change. Signed-off by: Charles Spirakis Signed-off-by: Jean Delvare Signed-off-by: Greg Kroah-Hartman --- Documentation/hwmon/w83791d | 67 ++++++++++++++++++++----------------- drivers/hwmon/w83791d.c | 7 ++-- 2 files changed, 41 insertions(+), 33 deletions(-) diff --git a/Documentation/hwmon/w83791d b/Documentation/hwmon/w83791d index 83a3836289c2..19b2ed739fa1 100644 --- a/Documentation/hwmon/w83791d +++ b/Documentation/hwmon/w83791d @@ -5,7 +5,7 @@ Supported chips: * Winbond W83791D Prefix: 'w83791d' Addresses scanned: I2C 0x2c - 0x2f - Datasheet: http://www.winbond-usa.com/products/winbond_products/pdfs/PCIC/W83791Da.pdf + Datasheet: http://www.winbond-usa.com/products/winbond_products/pdfs/PCIC/W83791D_W83791Gb.pdf Author: Charles Spirakis @@ -20,6 +20,9 @@ Credits: Chunhao Huang , Rudolf Marek +Additional contributors: + Sven Anders + Module Parameters ----------------- @@ -46,7 +49,8 @@ Module Parameters Description ----------- -This driver implements support for the Winbond W83791D chip. +This driver implements support for the Winbond W83791D chip. The W83791G +chip appears to be the same as the W83791D but is lead free. Detection of the chip can sometimes be foiled because it can be in an internal state that allows no clean access (Bank with ID register is not @@ -71,34 +75,36 @@ Voltage sensors (also known as IN sensors) report their values in millivolts. An alarm is triggered if the voltage has crossed a programmable minimum or maximum limit. -Alarms are provided as output from a "realtime status register". The -following bits are defined: +The bit ordering for the alarm "realtime status register" and the +"beep enable registers" are different. -bit - alarm on: -0 - Vcore -1 - VINR0 -2 - +3.3VIN -3 - 5VDD -4 - temp1 -5 - temp2 -6 - fan1 -7 - fan2 -8 - +12VIN -9 - -12VIN -10 - -5VIN -11 - fan3 -12 - chassis -13 - temp3 -14 - VINR1 -15 - reserved -16 - tart1 -17 - tart2 -18 - tart3 -19 - VSB -20 - VBAT -21 - fan4 -22 - fan5 -23 - reserved +in0 (VCORE) : alarms: 0x000001 beep_enable: 0x000001 +in1 (VINR0) : alarms: 0x000002 beep_enable: 0x002000 <== mismatch +in2 (+3.3VIN): alarms: 0x000004 beep_enable: 0x000004 +in3 (5VDD) : alarms: 0x000008 beep_enable: 0x000008 +in4 (+12VIN) : alarms: 0x000100 beep_enable: 0x000100 +in5 (-12VIN) : alarms: 0x000200 beep_enable: 0x000200 +in6 (-5VIN) : alarms: 0x000400 beep_enable: 0x000400 +in7 (VSB) : alarms: 0x080000 beep_enable: 0x010000 <== mismatch +in8 (VBAT) : alarms: 0x100000 beep_enable: 0x020000 <== mismatch +in9 (VINR1) : alarms: 0x004000 beep_enable: 0x004000 +temp1 : alarms: 0x000010 beep_enable: 0x000010 +temp2 : alarms: 0x000020 beep_enable: 0x000020 +temp3 : alarms: 0x002000 beep_enable: 0x000002 <== mismatch +fan1 : alarms: 0x000040 beep_enable: 0x000040 +fan2 : alarms: 0x000080 beep_enable: 0x000080 +fan3 : alarms: 0x000800 beep_enable: 0x000800 +fan4 : alarms: 0x200000 beep_enable: 0x200000 +fan5 : alarms: 0x400000 beep_enable: 0x400000 +tart1 : alarms: 0x010000 beep_enable: 0x040000 <== mismatch +tart2 : alarms: 0x020000 beep_enable: 0x080000 <== mismatch +tart3 : alarms: 0x040000 beep_enable: 0x100000 <== mismatch +case_open : alarms: 0x001000 beep_enable: 0x001000 +user_enable : alarms: -------- beep_enable: 0x800000 + +*** NOTE: It is the responsibility of user-space code to handle the fact +that the beep enable and alarm bits are in different positions when using that +feature of the chip. When an alarm goes off, you can be warned by a beeping signal through your computer speaker. It is possible to enable all beeping globally, or only @@ -109,5 +115,6 @@ often will do no harm, but will return 'old' values. W83791D TODO: --------------- -Provide a patch for per-file alarms as discussed on the mailing list +Provide a patch for per-file alarms and beep enables as defined in the hwmon + documentation (Documentation/hwmon/sysfs-interface) Provide a patch for smart-fan control (still need appropriate motherboard/fans) diff --git a/drivers/hwmon/w83791d.c b/drivers/hwmon/w83791d.c index eec43abd57fb..d965d074cd61 100644 --- a/drivers/hwmon/w83791d.c +++ b/drivers/hwmon/w83791d.c @@ -27,9 +27,9 @@ The w83791d chip appears to be part way between the 83781d and the 83792d. Thus, this file is derived from both the w83792d.c and - w83781d.c files, but its output is more along the lines of the - 83781d (which means there are no changes to the user-mode sensors - program which treats the 83791d as an 83781d). + w83781d.c files. + + The w83791g chip is the same as the w83791d but lead-free. */ #include @@ -1172,6 +1172,7 @@ static struct w83791d_data *w83791d_update_device(struct device *dev) (w83791d_read(client, W83791D_REG_BEEP_CTRL[1]) << 8) + (w83791d_read(client, W83791D_REG_BEEP_CTRL[2]) << 16); + /* Extract global beep enable flag */ data->beep_enable = (data->beep_mask >> GLOBAL_BEEP_ENABLE_SHIFT) & 0x01; From ab41319eab3b5e600873dc77dff7756970424ca6 Mon Sep 17 00:00:00 2001 From: Juerg Haefliger Date: Sun, 24 Sep 2006 20:54:04 +0200 Subject: [PATCH 21/39] hwmon: New driver for the VIA VT1211 hwmon: New driver for the VIA VT1211 This is a new driver for the VIA VT1211 Super-IO chip. It is a rewrite of the existing vt1211 driver (by Mark D. Studebaker and Lars Ekman) which has been around for a while but never made it into the main kernel tree. It is implemented as a platform driver and therefore requires lm_sensors 2.10.1 to function properly. Signed-off-by: Juerg Haefliger Signed-off-by: Jean Delvare Signed-off-by: Greg Kroah-Hartman --- MAINTAINERS | 6 + drivers/hwmon/Kconfig | 11 + drivers/hwmon/Makefile | 1 + drivers/hwmon/vt1211.c | 1355 ++++++++++++++++++++++++++++++++++++++++ 4 files changed, 1373 insertions(+) create mode 100644 drivers/hwmon/vt1211.c diff --git a/MAINTAINERS b/MAINTAINERS index 63673e6513b7..332b220f8a23 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -3309,6 +3309,12 @@ W: http://linuxtv.org T: git kernel.org:/pub/scm/linux/kernel/git/mchehab/v4l-dvb.git S: Maintained +VT1211 HARDWARE MONITOR DRIVER +P: Juerg Haefliger +M: juergh@gmail.com +L: lm-sensors@lm-sensors.org +S: Maintained + VT8231 HARDWARE MONITOR DRIVER P: Roger Lucas M: roger@planbit.co.uk diff --git a/drivers/hwmon/Kconfig b/drivers/hwmon/Kconfig index 696543ba6a29..9b88b25b6edb 100644 --- a/drivers/hwmon/Kconfig +++ b/drivers/hwmon/Kconfig @@ -417,6 +417,17 @@ config SENSORS_VIA686A This driver can also be built as a module. If so, the module will be called via686a. +config SENSORS_VT1211 + tristate "VIA VT1211" + depends on HWMON && EXPERIMENTAL + select HWMON_VID + help + If you say yes here then you get support for hardware monitoring + features of the VIA VT1211 Super-I/O chip. + + This driver can also be built as a module. If so, the module + will be called vt1211. + config SENSORS_VT8231 tristate "VIA VT8231" depends on HWMON && I2C && PCI && EXPERIMENTAL diff --git a/drivers/hwmon/Makefile b/drivers/hwmon/Makefile index aab4c1063059..af01cc64f7d2 100644 --- a/drivers/hwmon/Makefile +++ b/drivers/hwmon/Makefile @@ -46,6 +46,7 @@ obj-$(CONFIG_SENSORS_SMSC47B397)+= smsc47b397.o obj-$(CONFIG_SENSORS_SMSC47M1) += smsc47m1.o obj-$(CONFIG_SENSORS_SMSC47M192)+= smsc47m192.o obj-$(CONFIG_SENSORS_VIA686A) += via686a.o +obj-$(CONFIG_SENSORS_VT1211) += vt1211.o obj-$(CONFIG_SENSORS_VT8231) += vt8231.o obj-$(CONFIG_SENSORS_W83627EHF) += w83627ehf.o obj-$(CONFIG_SENSORS_W83L785TS) += w83l785ts.o diff --git a/drivers/hwmon/vt1211.c b/drivers/hwmon/vt1211.c new file mode 100644 index 000000000000..25cc56003d7a --- /dev/null +++ b/drivers/hwmon/vt1211.c @@ -0,0 +1,1355 @@ +/* + * vt1211.c - driver for the VIA VT1211 Super-I/O chip integrated hardware + * monitoring features + * Copyright (C) 2006 Juerg Haefliger + * + * This driver is based on the driver for kernel 2.4 by Mark D. Studebaker + * and its port to kernel 2.6 by Lars Ekman. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +static int uch_config = -1; +module_param(uch_config, int, 0); +MODULE_PARM_DESC(uch_config, "Initialize the universal channel configuration"); + +static int int_mode = -1; +module_param(int_mode, int, 0); +MODULE_PARM_DESC(int_mode, "Force the temperature interrupt mode"); + +static struct platform_device *pdev; + +#define DRVNAME "vt1211" + +/* --------------------------------------------------------------------- + * Registers + * + * The sensors are defined as follows. + * + * Sensor Voltage Mode Temp Mode Notes (from the datasheet) + * -------- ------------ --------- -------------------------- + * Reading 1 temp1 Intel thermal diode + * Reading 3 temp2 Internal thermal diode + * UCH1/Reading2 in0 temp3 NTC type thermistor + * UCH2 in1 temp4 +2.5V + * UCH3 in2 temp5 VccP + * UCH4 in3 temp6 +5V + * UCH5 in4 temp7 +12V + * 3.3V in5 Internal VDD (+3.3V) + * + * --------------------------------------------------------------------- */ + +/* Voltages (in) numbered 0-5 (ix) */ +#define VT1211_REG_IN(ix) (0x21 + (ix)) +#define VT1211_REG_IN_MIN(ix) ((ix) == 0 ? 0x3e : 0x2a + 2 * (ix)) +#define VT1211_REG_IN_MAX(ix) ((ix) == 0 ? 0x3d : 0x29 + 2 * (ix)) + +/* Temperatures (temp) numbered 0-6 (ix) */ +static u8 regtemp[] = {0x1f, 0x20, 0x21, 0x22, 0x23, 0x24, 0x25}; +static u8 regtempmax[] = {0x39, 0x1d, 0x3d, 0x2b, 0x2d, 0x2f, 0x31}; +static u8 regtemphyst[] = {0x3a, 0x1e, 0x3e, 0x2c, 0x2e, 0x30, 0x32}; + +/* Fans numbered 0-1 (ix) */ +#define VT1211_REG_FAN(ix) (0x29 + (ix)) +#define VT1211_REG_FAN_MIN(ix) (0x3b + (ix)) +#define VT1211_REG_FAN_DIV 0x47 + +/* PWMs numbered 0-1 (ix) */ +/* Auto points numbered 0-3 (ap) */ +#define VT1211_REG_PWM(ix) (0x60 + (ix)) +#define VT1211_REG_PWM_CLK 0x50 +#define VT1211_REG_PWM_CTL 0x51 +#define VT1211_REG_PWM_AUTO_TEMP(ap) (0x55 - (ap)) +#define VT1211_REG_PWM_AUTO_PWM(ix, ap) (0x58 + 2 * (ix) - (ap)) + +/* Miscellaneous registers */ +#define VT1211_REG_CONFIG 0x40 +#define VT1211_REG_ALARM1 0x41 +#define VT1211_REG_ALARM2 0x42 +#define VT1211_REG_VID 0x45 +#define VT1211_REG_UCH_CONFIG 0x4a +#define VT1211_REG_TEMP1_CONFIG 0x4b +#define VT1211_REG_TEMP2_CONFIG 0x4c + +/* In, temp & fan alarm bits */ +static const u8 bitalarmin[] = {11, 0, 1, 3, 8, 2, 9}; +static const u8 bitalarmtemp[] = {4, 15, 11, 0, 1, 3, 8}; +static const u8 bitalarmfan[] = {6, 7}; + +/* --------------------------------------------------------------------- + * Data structures and manipulation thereof + * --------------------------------------------------------------------- */ + +struct vt1211_data { + unsigned short addr; + const char *name; + struct class_device *class_dev; + + struct mutex update_lock; + char valid; /* !=0 if following fields are valid */ + unsigned long last_updated; /* In jiffies */ + + /* Register values */ + u8 in[6]; + u8 in_max[6]; + u8 in_min[6]; + u8 temp[7]; + u8 temp_max[7]; + u8 temp_hyst[7]; + u8 fan[2]; + u8 fan_min[2]; + u8 fan_div[2]; + u8 fan_ctl; + u8 pwm[2]; + u8 pwm_ctl[2]; + u8 pwm_clk; + u8 pwm_auto_temp[4]; + u8 pwm_auto_pwm[2][4]; + u8 vid; /* Read once at init time */ + u8 vrm; + u8 uch_config; /* Read once at init time */ + u16 alarms; +}; + +/* ix = [0-5] */ +#define ISVOLT(ix, uch_config) ((ix) > 4 ? 1 : \ + !(((uch_config) >> ((ix) + 2)) & 1)) + +/* ix = [0-6] */ +#define ISTEMP(ix, uch_config) ((ix) < 2 ? 1 : \ + ((uch_config) >> (ix)) & 1) + +/* in5 (ix = 5) is special. It's the internal 3.3V so it's scaled in the + driver according to the VT1211 BIOS porting guide */ +#define IN_FROM_REG(ix, reg) ((reg) < 3 ? 0 : (ix) == 5 ? \ + (((reg) - 3) * 15882 + 479) / 958 : \ + (((reg) - 3) * 10000 + 479) / 958) +#define IN_TO_REG(ix, val) (SENSORS_LIMIT((ix) == 5 ? \ + ((val) * 958 + 7941) / 15882 + 3 : \ + ((val) * 958 + 5000) / 10000 + 3, 0, 255)) + +/* temp1 (ix = 0) is an intel thermal diode which is scaled in user space. + temp2 (ix = 1) is the internal temp diode so it's scaled in the driver + according to some measurements that I took on an EPIA M10000. + temp3-7 are thermistor based so the driver returns the voltage measured at + the pin (range 0V - 2.2V). */ +#define TEMP_FROM_REG(ix, reg) ((ix) == 0 ? (reg) * 1000 : \ + (ix) == 1 ? (reg) < 51 ? 0 : \ + ((reg) - 51) * 1000 : \ + ((253 - (reg)) * 2200 + 105) / 210) +#define TEMP_TO_REG(ix, val) SENSORS_LIMIT( \ + ((ix) == 0 ? ((val) + 500) / 1000 : \ + (ix) == 1 ? ((val) + 500) / 1000 + 51 : \ + 253 - ((val) * 210 + 1100) / 2200), 0, 255) + +#define DIV_FROM_REG(reg) (1 << (reg)) + +#define RPM_FROM_REG(reg, div) (((reg) == 0) || ((reg) == 255) ? 0 : \ + 1310720 / (reg) / DIV_FROM_REG(div)) +#define RPM_TO_REG(val, div) ((val) == 0 ? 255 : \ + SENSORS_LIMIT((1310720 / (val) / \ + DIV_FROM_REG(div)), 1, 254)) + +/* --------------------------------------------------------------------- + * Super-I/O constants and functions + * --------------------------------------------------------------------- */ + +/* Configuration & data index port registers */ +#define SIO_REG_CIP 0x2e +#define SIO_REG_DIP 0x2f + +/* Configuration registers */ +#define SIO_VT1211_LDN 0x07 /* logical device number */ +#define SIO_VT1211_DEVID 0x20 /* device ID */ +#define SIO_VT1211_DEVREV 0x21 /* device revision */ +#define SIO_VT1211_ACTIVE 0x30 /* HW monitor active */ +#define SIO_VT1211_BADDR 0x60 /* base I/O address */ +#define SIO_VT1211_ID 0x3c /* VT1211 device ID */ + +/* VT1211 logical device numbers */ +#define SIO_VT1211_LDN_HWMON 0x0b /* HW monitor */ + +static inline void superio_outb(int reg, int val) +{ + outb(reg, SIO_REG_CIP); + outb(val, SIO_REG_DIP); +} + +static inline int superio_inb(int reg) +{ + outb(reg, SIO_REG_CIP); + return inb(SIO_REG_DIP); +} + +static inline void superio_select(int ldn) +{ + outb(SIO_VT1211_LDN, SIO_REG_CIP); + outb(ldn, SIO_REG_DIP); +} + +static inline void superio_enter(void) +{ + outb(0x87, SIO_REG_CIP); + outb(0x87, SIO_REG_CIP); +} + +static inline void superio_exit(void) +{ + outb(0xaa, SIO_REG_CIP); +} + +/* --------------------------------------------------------------------- + * Device I/O access + * --------------------------------------------------------------------- */ + +static inline u8 vt1211_read8(struct vt1211_data *data, u8 reg) +{ + return inb(data->addr + reg); +} + +static inline void vt1211_write8(struct vt1211_data *data, u8 reg, u8 val) +{ + outb(val, data->addr + reg); +} + +static struct vt1211_data *vt1211_update_device(struct device *dev) +{ + struct vt1211_data *data = dev_get_drvdata(dev); + int ix, val; + + mutex_lock(&data->update_lock); + + /* registers cache is refreshed after 1 second */ + if (time_after(jiffies, data->last_updated + HZ) || !data->valid) { + /* read VID */ + data->vid = vt1211_read8(data, VT1211_REG_VID) & 0x1f; + + /* voltage (in) registers */ + for (ix = 0; ix < ARRAY_SIZE(data->in); ix++) { + if (ISVOLT(ix, data->uch_config)) { + data->in[ix] = vt1211_read8(data, + VT1211_REG_IN(ix)); + data->in_min[ix] = vt1211_read8(data, + VT1211_REG_IN_MIN(ix)); + data->in_max[ix] = vt1211_read8(data, + VT1211_REG_IN_MAX(ix)); + } + } + + /* temp registers */ + for (ix = 0; ix < ARRAY_SIZE(data->temp); ix++) { + if (ISTEMP(ix, data->uch_config)) { + data->temp[ix] = vt1211_read8(data, + regtemp[ix]); + data->temp_max[ix] = vt1211_read8(data, + regtempmax[ix]); + data->temp_hyst[ix] = vt1211_read8(data, + regtemphyst[ix]); + } + } + + /* fan & pwm registers */ + for (ix = 0; ix < ARRAY_SIZE(data->fan); ix++) { + data->fan[ix] = vt1211_read8(data, + VT1211_REG_FAN(ix)); + data->fan_min[ix] = vt1211_read8(data, + VT1211_REG_FAN_MIN(ix)); + data->pwm[ix] = vt1211_read8(data, + VT1211_REG_PWM(ix)); + } + val = vt1211_read8(data, VT1211_REG_FAN_DIV); + data->fan_div[0] = (val >> 4) & 3; + data->fan_div[1] = (val >> 6) & 3; + data->fan_ctl = val & 0xf; + + val = vt1211_read8(data, VT1211_REG_PWM_CTL); + data->pwm_ctl[0] = val & 0xf; + data->pwm_ctl[1] = (val >> 4) & 0xf; + + data->pwm_clk = vt1211_read8(data, VT1211_REG_PWM_CLK); + + /* pwm & temp auto point registers */ + data->pwm_auto_pwm[0][1] = vt1211_read8(data, + VT1211_REG_PWM_AUTO_PWM(0, 1)); + data->pwm_auto_pwm[0][2] = vt1211_read8(data, + VT1211_REG_PWM_AUTO_PWM(0, 2)); + data->pwm_auto_pwm[1][1] = vt1211_read8(data, + VT1211_REG_PWM_AUTO_PWM(1, 1)); + data->pwm_auto_pwm[1][2] = vt1211_read8(data, + VT1211_REG_PWM_AUTO_PWM(1, 2)); + for (ix = 0; ix < ARRAY_SIZE(data->pwm_auto_temp); ix++) { + data->pwm_auto_temp[ix] = vt1211_read8(data, + VT1211_REG_PWM_AUTO_TEMP(ix)); + } + + /* alarm registers */ + data->alarms = (vt1211_read8(data, VT1211_REG_ALARM2) << 8) | + vt1211_read8(data, VT1211_REG_ALARM1); + + data->last_updated = jiffies; + data->valid = 1; + } + + mutex_unlock(&data->update_lock); + + return data; +} + +/* --------------------------------------------------------------------- + * Voltage sysfs interfaces + * ix = [0-5] + * --------------------------------------------------------------------- */ + +#define SHOW_IN_INPUT 0 +#define SHOW_SET_IN_MIN 1 +#define SHOW_SET_IN_MAX 2 +#define SHOW_IN_ALARM 3 + +static ssize_t show_in(struct device *dev, struct device_attribute *attr, + char *buf) +{ + struct vt1211_data *data = vt1211_update_device(dev); + struct sensor_device_attribute_2 *sensor_attr_2 = + to_sensor_dev_attr_2(attr); + int ix = sensor_attr_2->index; + int fn = sensor_attr_2->nr; + int res; + + switch (fn) { + case SHOW_IN_INPUT: + res = IN_FROM_REG(ix, data->in[ix]); + break; + case SHOW_SET_IN_MIN: + res = IN_FROM_REG(ix, data->in_min[ix]); + break; + case SHOW_SET_IN_MAX: + res = IN_FROM_REG(ix, data->in_max[ix]); + break; + case SHOW_IN_ALARM: + res = (data->alarms >> bitalarmin[ix]) & 1; + break; + default: + res = 0; + dev_dbg(dev, "Unknown attr fetch (%d)\n", fn); + } + + return sprintf(buf, "%d\n", res); +} + +static ssize_t set_in(struct device *dev, struct device_attribute *attr, + const char *buf, size_t count) +{ + struct vt1211_data *data = dev_get_drvdata(dev); + struct sensor_device_attribute_2 *sensor_attr_2 = + to_sensor_dev_attr_2(attr); + int ix = sensor_attr_2->index; + int fn = sensor_attr_2->nr; + long val = simple_strtol(buf, NULL, 10); + + mutex_lock(&data->update_lock); + switch (fn) { + case SHOW_SET_IN_MIN: + data->in_min[ix] = IN_TO_REG(ix, val); + vt1211_write8(data, VT1211_REG_IN_MIN(ix), data->in_min[ix]); + break; + case SHOW_SET_IN_MAX: + data->in_max[ix] = IN_TO_REG(ix, val); + vt1211_write8(data, VT1211_REG_IN_MAX(ix), data->in_max[ix]); + break; + default: + dev_dbg(dev, "Unknown attr fetch (%d)\n", fn); + } + mutex_unlock(&data->update_lock); + + return count; +} + +/* --------------------------------------------------------------------- + * Temperature sysfs interfaces + * ix = [0-6] + * --------------------------------------------------------------------- */ + +#define SHOW_TEMP_INPUT 0 +#define SHOW_SET_TEMP_MAX 1 +#define SHOW_SET_TEMP_MAX_HYST 2 +#define SHOW_TEMP_ALARM 3 + +static ssize_t show_temp(struct device *dev, struct device_attribute *attr, + char *buf) +{ + struct vt1211_data *data = vt1211_update_device(dev); + struct sensor_device_attribute_2 *sensor_attr_2 = + to_sensor_dev_attr_2(attr); + int ix = sensor_attr_2->index; + int fn = sensor_attr_2->nr; + int res; + + switch (fn) { + case SHOW_TEMP_INPUT: + res = TEMP_FROM_REG(ix, data->temp[ix]); + break; + case SHOW_SET_TEMP_MAX: + res = TEMP_FROM_REG(ix, data->temp_max[ix]); + break; + case SHOW_SET_TEMP_MAX_HYST: + res = TEMP_FROM_REG(ix, data->temp_hyst[ix]); + break; + case SHOW_TEMP_ALARM: + res = (data->alarms >> bitalarmtemp[ix]) & 1; + break; + default: + res = 0; + dev_dbg(dev, "Unknown attr fetch (%d)\n", fn); + } + + return sprintf(buf, "%d\n", res); +} + +static ssize_t set_temp(struct device *dev, struct device_attribute *attr, + const char *buf, size_t count) +{ + struct vt1211_data *data = dev_get_drvdata(dev); + struct sensor_device_attribute_2 *sensor_attr_2 = + to_sensor_dev_attr_2(attr); + int ix = sensor_attr_2->index; + int fn = sensor_attr_2->nr; + long val = simple_strtol(buf, NULL, 10); + + mutex_lock(&data->update_lock); + switch (fn) { + case SHOW_SET_TEMP_MAX: + data->temp_max[ix] = TEMP_TO_REG(ix, val); + vt1211_write8(data, regtempmax[ix], + data->temp_max[ix]); + break; + case SHOW_SET_TEMP_MAX_HYST: + data->temp_hyst[ix] = TEMP_TO_REG(ix, val); + vt1211_write8(data, regtemphyst[ix], + data->temp_hyst[ix]); + break; + default: + dev_dbg(dev, "Unknown attr fetch (%d)\n", fn); + } + mutex_unlock(&data->update_lock); + + return count; +} + +/* --------------------------------------------------------------------- + * Fan sysfs interfaces + * ix = [0-1] + * --------------------------------------------------------------------- */ + +#define SHOW_FAN_INPUT 0 +#define SHOW_SET_FAN_MIN 1 +#define SHOW_SET_FAN_DIV 2 +#define SHOW_FAN_ALARM 3 + +static ssize_t show_fan(struct device *dev, struct device_attribute *attr, + char *buf) +{ + struct vt1211_data *data = vt1211_update_device(dev); + struct sensor_device_attribute_2 *sensor_attr_2 = + to_sensor_dev_attr_2(attr); + int ix = sensor_attr_2->index; + int fn = sensor_attr_2->nr; + int res; + + switch (fn) { + case SHOW_FAN_INPUT: + res = RPM_FROM_REG(data->fan[ix], data->fan_div[ix]); + break; + case SHOW_SET_FAN_MIN: + res = RPM_FROM_REG(data->fan_min[ix], data->fan_div[ix]); + break; + case SHOW_SET_FAN_DIV: + res = DIV_FROM_REG(data->fan_div[ix]); + break; + case SHOW_FAN_ALARM: + res = (data->alarms >> bitalarmfan[ix]) & 1; + break; + default: + res = 0; + dev_dbg(dev, "Unknown attr fetch (%d)\n", fn); + } + + return sprintf(buf, "%d\n", res); +} + +static ssize_t set_fan(struct device *dev, struct device_attribute *attr, + const char *buf, size_t count) +{ + struct vt1211_data *data = dev_get_drvdata(dev); + struct sensor_device_attribute_2 *sensor_attr_2 = + to_sensor_dev_attr_2(attr); + int ix = sensor_attr_2->index; + int fn = sensor_attr_2->nr; + long val = simple_strtol(buf, NULL, 10); + int reg; + + mutex_lock(&data->update_lock); + + /* sync the data cache */ + reg = vt1211_read8(data, VT1211_REG_FAN_DIV); + data->fan_div[0] = (reg >> 4) & 3; + data->fan_div[1] = (reg >> 6) & 3; + data->fan_ctl = reg & 0xf; + + switch (fn) { + case SHOW_SET_FAN_MIN: + data->fan_min[ix] = RPM_TO_REG(val, data->fan_div[ix]); + vt1211_write8(data, VT1211_REG_FAN_MIN(ix), + data->fan_min[ix]); + break; + case SHOW_SET_FAN_DIV: + switch (val) { + case 1: data->fan_div[ix] = 0; break; + case 2: data->fan_div[ix] = 1; break; + case 4: data->fan_div[ix] = 2; break; + case 8: data->fan_div[ix] = 3; break; + default: + count = -EINVAL; + dev_warn(dev, "fan div value %ld not " + "supported. Choose one of 1, 2, " + "4, or 8.\n", val); + goto EXIT; + } + vt1211_write8(data, VT1211_REG_FAN_DIV, + ((data->fan_div[1] << 6) | + (data->fan_div[0] << 4) | + data->fan_ctl)); + break; + default: + dev_dbg(dev, "Unknown attr fetch (%d)\n", fn); + } + +EXIT: + mutex_unlock(&data->update_lock); + return count; +} + +/* --------------------------------------------------------------------- + * PWM sysfs interfaces + * ix = [0-1] + * --------------------------------------------------------------------- */ + +#define SHOW_PWM 0 +#define SHOW_SET_PWM_ENABLE 1 +#define SHOW_SET_PWM_FREQ 2 +#define SHOW_SET_PWM_AUTO_CHANNELS_TEMP 3 + +static ssize_t show_pwm(struct device *dev, struct device_attribute *attr, + char *buf) +{ + struct vt1211_data *data = vt1211_update_device(dev); + struct sensor_device_attribute_2 *sensor_attr_2 = + to_sensor_dev_attr_2(attr); + int ix = sensor_attr_2->index; + int fn = sensor_attr_2->nr; + int res; + + switch (fn) { + case SHOW_PWM: + res = data->pwm[ix]; + break; + case SHOW_SET_PWM_ENABLE: + res = ((data->pwm_ctl[ix] >> 3) & 1) ? 2 : 0; + break; + case SHOW_SET_PWM_FREQ: + res = 90000 >> (data->pwm_clk & 7); + break; + case SHOW_SET_PWM_AUTO_CHANNELS_TEMP: + res = (data->pwm_ctl[ix] & 7) + 1; + break; + default: + res = 0; + dev_dbg(dev, "Unknown attr fetch (%d)\n", fn); + } + + return sprintf(buf, "%d\n", res); +} + +static ssize_t set_pwm(struct device *dev, struct device_attribute *attr, + const char *buf, size_t count) +{ + struct vt1211_data *data = dev_get_drvdata(dev); + struct sensor_device_attribute_2 *sensor_attr_2 = + to_sensor_dev_attr_2(attr); + int ix = sensor_attr_2->index; + int fn = sensor_attr_2->nr; + long val = simple_strtol(buf, NULL, 10); + int tmp, reg; + + mutex_lock(&data->update_lock); + + switch (fn) { + case SHOW_SET_PWM_ENABLE: + /* sync the data cache */ + reg = vt1211_read8(data, VT1211_REG_FAN_DIV); + data->fan_div[0] = (reg >> 4) & 3; + data->fan_div[1] = (reg >> 6) & 3; + data->fan_ctl = reg & 0xf; + reg = vt1211_read8(data, VT1211_REG_PWM_CTL); + data->pwm_ctl[0] = reg & 0xf; + data->pwm_ctl[1] = (reg >> 4) & 0xf; + switch (val) { + case 0: + data->pwm_ctl[ix] &= 7; + /* disable SmartGuardian if both PWM outputs are + * disabled */ + if ((data->pwm_ctl[ix ^ 1] & 1) == 0) { + data->fan_ctl &= 0xe; + } + break; + case 2: + data->pwm_ctl[ix] |= 8; + data->fan_ctl |= 1; + break; + default: + count = -EINVAL; + dev_warn(dev, "pwm mode %ld not supported. " + "Choose one of 0 or 2.\n", val); + goto EXIT; + } + vt1211_write8(data, VT1211_REG_PWM_CTL, + ((data->pwm_ctl[1] << 4) | + data->pwm_ctl[0])); + vt1211_write8(data, VT1211_REG_FAN_DIV, + ((data->fan_div[1] << 6) | + (data->fan_div[0] << 4) | + data->fan_ctl)); + break; + case SHOW_SET_PWM_FREQ: + val = 135000 / SENSORS_LIMIT(val, 135000 >> 7, 135000); + /* calculate tmp = log2(val) */ + tmp = 0; + for (val >>= 1; val > 0; val >>= 1) { + tmp++; + } + /* sync the data cache */ + reg = vt1211_read8(data, VT1211_REG_PWM_CLK); + data->pwm_clk = (reg & 0xf8) | tmp; + vt1211_write8(data, VT1211_REG_PWM_CLK, data->pwm_clk); + break; + case SHOW_SET_PWM_AUTO_CHANNELS_TEMP: + if ((val < 1) || (val > 7)) { + count = -EINVAL; + dev_warn(dev, "temp channel %ld not supported. " + "Choose a value between 1 and 7.\n", val); + goto EXIT; + } + if (!ISTEMP(val - 1, data->uch_config)) { + count = -EINVAL; + dev_warn(dev, "temp channel %ld is not available.\n", + val); + goto EXIT; + } + /* sync the data cache */ + reg = vt1211_read8(data, VT1211_REG_PWM_CTL); + data->pwm_ctl[0] = reg & 0xf; + data->pwm_ctl[1] = (reg >> 4) & 0xf; + data->pwm_ctl[ix] = (data->pwm_ctl[ix] & 8) | (val - 1); + vt1211_write8(data, VT1211_REG_PWM_CTL, + ((data->pwm_ctl[1] << 4) | data->pwm_ctl[0])); + break; + default: + dev_dbg(dev, "Unknown attr fetch (%d)\n", fn); + } + +EXIT: + mutex_unlock(&data->update_lock); + return count; +} + +/* --------------------------------------------------------------------- + * PWM auto point definitions + * ix = [0-1] + * ap = [0-3] + * --------------------------------------------------------------------- */ + +/* + * pwm[ix+1]_auto_point[ap+1]_temp mapping table: + * Note that there is only a single set of temp auto points that controls both + * PWM controllers. We still create 2 sets of sysfs files to make it look + * more consistent even though they map to the same registers. + * + * ix ap : description + * ------------------- + * 0 0 : pwm1/2 off temperature (pwm_auto_temp[0]) + * 0 1 : pwm1/2 low speed temperature (pwm_auto_temp[1]) + * 0 2 : pwm1/2 high speed temperature (pwm_auto_temp[2]) + * 0 3 : pwm1/2 full speed temperature (pwm_auto_temp[3]) + * 1 0 : pwm1/2 off temperature (pwm_auto_temp[0]) + * 1 1 : pwm1/2 low speed temperature (pwm_auto_temp[1]) + * 1 2 : pwm1/2 high speed temperature (pwm_auto_temp[2]) + * 1 3 : pwm1/2 full speed temperature (pwm_auto_temp[3]) + */ + +static ssize_t show_pwm_auto_point_temp(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct vt1211_data *data = vt1211_update_device(dev); + struct sensor_device_attribute_2 *sensor_attr_2 = + to_sensor_dev_attr_2(attr); + int ix = sensor_attr_2->index; + int ap = sensor_attr_2->nr; + + return sprintf(buf, "%d\n", TEMP_FROM_REG(data->pwm_ctl[ix] & 7, + data->pwm_auto_temp[ap])); +} + +static ssize_t set_pwm_auto_point_temp(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + struct vt1211_data *data = dev_get_drvdata(dev); + struct sensor_device_attribute_2 *sensor_attr_2 = + to_sensor_dev_attr_2(attr); + int ix = sensor_attr_2->index; + int ap = sensor_attr_2->nr; + long val = simple_strtol(buf, NULL, 10); + int reg; + + mutex_lock(&data->update_lock); + + /* sync the data cache */ + reg = vt1211_read8(data, VT1211_REG_PWM_CTL); + data->pwm_ctl[0] = reg & 0xf; + data->pwm_ctl[1] = (reg >> 4) & 0xf; + + data->pwm_auto_temp[ap] = TEMP_TO_REG(data->pwm_ctl[ix] & 7, val); + vt1211_write8(data, VT1211_REG_PWM_AUTO_TEMP(ap), + data->pwm_auto_temp[ap]); + mutex_unlock(&data->update_lock); + + return count; +} + +/* + * pwm[ix+1]_auto_point[ap+1]_pwm mapping table: + * Note that the PWM auto points 0 & 3 are hard-wired in the VT1211 and can't + * be changed. + * + * ix ap : description + * ------------------- + * 0 0 : pwm1 off (pwm_auto_pwm[0][0], hard-wired to 0) + * 0 1 : pwm1 low speed duty cycle (pwm_auto_pwm[0][1]) + * 0 2 : pwm1 high speed duty cycle (pwm_auto_pwm[0][2]) + * 0 3 : pwm1 full speed (pwm_auto_pwm[0][3], hard-wired to 255) + * 1 0 : pwm2 off (pwm_auto_pwm[1][0], hard-wired to 0) + * 1 1 : pwm2 low speed duty cycle (pwm_auto_pwm[1][1]) + * 1 2 : pwm2 high speed duty cycle (pwm_auto_pwm[1][2]) + * 1 3 : pwm2 full speed (pwm_auto_pwm[1][3], hard-wired to 255) +*/ + +static ssize_t show_pwm_auto_point_pwm(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct vt1211_data *data = vt1211_update_device(dev); + struct sensor_device_attribute_2 *sensor_attr_2 = + to_sensor_dev_attr_2(attr); + int ix = sensor_attr_2->index; + int ap = sensor_attr_2->nr; + + return sprintf(buf, "%d\n", data->pwm_auto_pwm[ix][ap]); +} + +static ssize_t set_pwm_auto_point_pwm(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + struct vt1211_data *data = dev_get_drvdata(dev); + struct sensor_device_attribute_2 *sensor_attr_2 = + to_sensor_dev_attr_2(attr); + int ix = sensor_attr_2->index; + int ap = sensor_attr_2->nr; + long val = simple_strtol(buf, NULL, 10); + + if ((val < 0) || (val > 255)) { + dev_err(dev, "pwm value %ld is out of range. " + "Choose a value between 0 and 255." , val); + return -EINVAL; + } + + mutex_lock(&data->update_lock); + data->pwm_auto_pwm[ix][ap] = val; + vt1211_write8(data, VT1211_REG_PWM_AUTO_PWM(ix, ap), + data->pwm_auto_pwm[ix][ap]); + mutex_unlock(&data->update_lock); + + return count; +} + +/* --------------------------------------------------------------------- + * Miscellaneous sysfs interfaces (VRM, VID, name, and (legacy) alarms) + * --------------------------------------------------------------------- */ + +static ssize_t show_vrm(struct device *dev, struct device_attribute *attr, + char *buf) +{ + struct vt1211_data *data = dev_get_drvdata(dev); + + return sprintf(buf, "%d\n", data->vrm); +} + +static ssize_t set_vrm(struct device *dev, struct device_attribute *attr, + const char *buf, size_t count) +{ + struct vt1211_data *data = dev_get_drvdata(dev); + long val = simple_strtol(buf, NULL, 10); + + data->vrm = val; + + return count; +} + +static ssize_t show_vid(struct device *dev, struct device_attribute *attr, + char *buf) +{ + struct vt1211_data *data = dev_get_drvdata(dev); + + return sprintf(buf, "%d\n", vid_from_reg(data->vid, data->vrm)); +} + +static ssize_t show_name(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct vt1211_data *data = dev_get_drvdata(dev); + + return sprintf(buf, "%s\n", data->name); +} + +static ssize_t show_alarms(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct vt1211_data *data = vt1211_update_device(dev); + + return sprintf(buf, "%d\n", data->alarms); +} + +/* --------------------------------------------------------------------- + * Device attribute structs + * --------------------------------------------------------------------- */ + +#define SENSOR_ATTR_IN_INPUT(ix) \ + SENSOR_ATTR_2(in##ix##_input, S_IRUGO, \ + show_in, NULL, SHOW_IN_INPUT, ix) + +static struct sensor_device_attribute_2 vt1211_sysfs_in_input[] = { + SENSOR_ATTR_IN_INPUT(0), + SENSOR_ATTR_IN_INPUT(1), + SENSOR_ATTR_IN_INPUT(2), + SENSOR_ATTR_IN_INPUT(3), + SENSOR_ATTR_IN_INPUT(4), + SENSOR_ATTR_IN_INPUT(5), +}; + +#define SENSOR_ATTR_IN_MIN(ix) \ + SENSOR_ATTR_2(in##ix##_min, S_IRUGO | S_IWUSR, \ + show_in, set_in, SHOW_SET_IN_MIN, ix) + +static struct sensor_device_attribute_2 vt1211_sysfs_in_min[] = { + SENSOR_ATTR_IN_MIN(0), + SENSOR_ATTR_IN_MIN(1), + SENSOR_ATTR_IN_MIN(2), + SENSOR_ATTR_IN_MIN(3), + SENSOR_ATTR_IN_MIN(4), + SENSOR_ATTR_IN_MIN(5), +}; + +#define SENSOR_ATTR_IN_MAX(ix) \ + SENSOR_ATTR_2(in##ix##_max, S_IRUGO | S_IWUSR, \ + show_in, set_in, SHOW_SET_IN_MAX, ix) + +static struct sensor_device_attribute_2 vt1211_sysfs_in_max[] = { + SENSOR_ATTR_IN_MAX(0), + SENSOR_ATTR_IN_MAX(1), + SENSOR_ATTR_IN_MAX(2), + SENSOR_ATTR_IN_MAX(3), + SENSOR_ATTR_IN_MAX(4), + SENSOR_ATTR_IN_MAX(5), +}; + +#define SENSOR_ATTR_IN_ALARM(ix) \ + SENSOR_ATTR_2(in##ix##_alarm, S_IRUGO, \ + show_in, NULL, SHOW_IN_ALARM, ix) + +static struct sensor_device_attribute_2 vt1211_sysfs_in_alarm[] = { + SENSOR_ATTR_IN_ALARM(0), + SENSOR_ATTR_IN_ALARM(1), + SENSOR_ATTR_IN_ALARM(2), + SENSOR_ATTR_IN_ALARM(3), + SENSOR_ATTR_IN_ALARM(4), + SENSOR_ATTR_IN_ALARM(5), +}; + +#define SENSOR_ATTR_TEMP_INPUT(ix) \ + SENSOR_ATTR_2(temp##ix##_input, S_IRUGO, \ + show_temp, NULL, SHOW_TEMP_INPUT, ix-1) + +static struct sensor_device_attribute_2 vt1211_sysfs_temp_input[] = { + SENSOR_ATTR_TEMP_INPUT(1), + SENSOR_ATTR_TEMP_INPUT(2), + SENSOR_ATTR_TEMP_INPUT(3), + SENSOR_ATTR_TEMP_INPUT(4), + SENSOR_ATTR_TEMP_INPUT(5), + SENSOR_ATTR_TEMP_INPUT(6), + SENSOR_ATTR_TEMP_INPUT(7), +}; + +#define SENSOR_ATTR_TEMP_MAX(ix) \ + SENSOR_ATTR_2(temp##ix##_max, S_IRUGO | S_IWUSR, \ + show_temp, set_temp, SHOW_SET_TEMP_MAX, ix-1) + +static struct sensor_device_attribute_2 vt1211_sysfs_temp_max[] = { + SENSOR_ATTR_TEMP_MAX(1), + SENSOR_ATTR_TEMP_MAX(2), + SENSOR_ATTR_TEMP_MAX(3), + SENSOR_ATTR_TEMP_MAX(4), + SENSOR_ATTR_TEMP_MAX(5), + SENSOR_ATTR_TEMP_MAX(6), + SENSOR_ATTR_TEMP_MAX(7), +}; + +#define SENSOR_ATTR_TEMP_MAX_HYST(ix) \ + SENSOR_ATTR_2(temp##ix##_max_hyst, S_IRUGO | S_IWUSR, \ + show_temp, set_temp, SHOW_SET_TEMP_MAX_HYST, ix-1) + +static struct sensor_device_attribute_2 vt1211_sysfs_temp_max_hyst[] = { + SENSOR_ATTR_TEMP_MAX_HYST(1), + SENSOR_ATTR_TEMP_MAX_HYST(2), + SENSOR_ATTR_TEMP_MAX_HYST(3), + SENSOR_ATTR_TEMP_MAX_HYST(4), + SENSOR_ATTR_TEMP_MAX_HYST(5), + SENSOR_ATTR_TEMP_MAX_HYST(6), + SENSOR_ATTR_TEMP_MAX_HYST(7), +}; + +#define SENSOR_ATTR_TEMP_ALARM(ix) \ + SENSOR_ATTR_2(temp##ix##_alarm, S_IRUGO, \ + show_temp, NULL, SHOW_TEMP_ALARM, ix-1) + +static struct sensor_device_attribute_2 vt1211_sysfs_temp_alarm[] = { + SENSOR_ATTR_TEMP_ALARM(1), + SENSOR_ATTR_TEMP_ALARM(2), + SENSOR_ATTR_TEMP_ALARM(3), + SENSOR_ATTR_TEMP_ALARM(4), + SENSOR_ATTR_TEMP_ALARM(5), + SENSOR_ATTR_TEMP_ALARM(6), + SENSOR_ATTR_TEMP_ALARM(7), +}; + +#define SENSOR_ATTR_FAN(ix) \ + SENSOR_ATTR_2(fan##ix##_input, S_IRUGO, \ + show_fan, NULL, SHOW_FAN_INPUT, ix-1), \ + SENSOR_ATTR_2(fan##ix##_min, S_IRUGO | S_IWUSR, \ + show_fan, set_fan, SHOW_SET_FAN_MIN, ix-1), \ + SENSOR_ATTR_2(fan##ix##_div, S_IRUGO | S_IWUSR, \ + show_fan, set_fan, SHOW_SET_FAN_DIV, ix-1), \ + SENSOR_ATTR_2(fan##ix##_alarm, S_IRUGO, \ + show_fan, NULL, SHOW_FAN_ALARM, ix-1) + +#define SENSOR_ATTR_PWM(ix) \ + SENSOR_ATTR_2(pwm##ix, S_IRUGO, \ + show_pwm, NULL, SHOW_PWM, ix-1), \ + SENSOR_ATTR_2(pwm##ix##_enable, S_IRUGO | S_IWUSR, \ + show_pwm, set_pwm, SHOW_SET_PWM_ENABLE, ix-1), \ + SENSOR_ATTR_2(pwm##ix##_auto_channels_temp, S_IRUGO | S_IWUSR, \ + show_pwm, set_pwm, SHOW_SET_PWM_AUTO_CHANNELS_TEMP, ix-1) + +#define SENSOR_ATTR_PWM_FREQ(ix) \ + SENSOR_ATTR_2(pwm##ix##_freq, S_IRUGO | S_IWUSR, \ + show_pwm, set_pwm, SHOW_SET_PWM_FREQ, ix-1) + +#define SENSOR_ATTR_PWM_FREQ_RO(ix) \ + SENSOR_ATTR_2(pwm##ix##_freq, S_IRUGO, \ + show_pwm, NULL, SHOW_SET_PWM_FREQ, ix-1) + +#define SENSOR_ATTR_PWM_AUTO_POINT_TEMP(ix, ap) \ + SENSOR_ATTR_2(pwm##ix##_auto_point##ap##_temp, S_IRUGO | S_IWUSR, \ + show_pwm_auto_point_temp, set_pwm_auto_point_temp, \ + ap-1, ix-1) + +#define SENSOR_ATTR_PWM_AUTO_POINT_TEMP_RO(ix, ap) \ + SENSOR_ATTR_2(pwm##ix##_auto_point##ap##_temp, S_IRUGO, \ + show_pwm_auto_point_temp, NULL, \ + ap-1, ix-1) + +#define SENSOR_ATTR_PWM_AUTO_POINT_PWM(ix, ap) \ + SENSOR_ATTR_2(pwm##ix##_auto_point##ap##_pwm, S_IRUGO | S_IWUSR, \ + show_pwm_auto_point_pwm, set_pwm_auto_point_pwm, \ + ap-1, ix-1) + +#define SENSOR_ATTR_PWM_AUTO_POINT_PWM_RO(ix, ap) \ + SENSOR_ATTR_2(pwm##ix##_auto_point##ap##_pwm, S_IRUGO, \ + show_pwm_auto_point_pwm, NULL, \ + ap-1, ix-1) + +static struct sensor_device_attribute_2 vt1211_sysfs_fan_pwm[] = { + SENSOR_ATTR_FAN(1), + SENSOR_ATTR_FAN(2), + SENSOR_ATTR_PWM(1), + SENSOR_ATTR_PWM(2), + SENSOR_ATTR_PWM_FREQ(1), + SENSOR_ATTR_PWM_FREQ_RO(2), + SENSOR_ATTR_PWM_AUTO_POINT_TEMP(1, 1), + SENSOR_ATTR_PWM_AUTO_POINT_TEMP(1, 2), + SENSOR_ATTR_PWM_AUTO_POINT_TEMP(1, 3), + SENSOR_ATTR_PWM_AUTO_POINT_TEMP(1, 4), + SENSOR_ATTR_PWM_AUTO_POINT_TEMP_RO(2, 1), + SENSOR_ATTR_PWM_AUTO_POINT_TEMP_RO(2, 2), + SENSOR_ATTR_PWM_AUTO_POINT_TEMP_RO(2, 3), + SENSOR_ATTR_PWM_AUTO_POINT_TEMP_RO(2, 4), + SENSOR_ATTR_PWM_AUTO_POINT_PWM_RO(1, 1), + SENSOR_ATTR_PWM_AUTO_POINT_PWM(1, 2), + SENSOR_ATTR_PWM_AUTO_POINT_PWM(1, 3), + SENSOR_ATTR_PWM_AUTO_POINT_PWM_RO(1, 4), + SENSOR_ATTR_PWM_AUTO_POINT_PWM_RO(2, 1), + SENSOR_ATTR_PWM_AUTO_POINT_PWM(2, 2), + SENSOR_ATTR_PWM_AUTO_POINT_PWM(2, 3), + SENSOR_ATTR_PWM_AUTO_POINT_PWM_RO(2, 4), +}; + +static struct device_attribute vt1211_sysfs_misc[] = { + __ATTR(vrm, S_IRUGO | S_IWUSR, show_vrm, set_vrm), + __ATTR(cpu0_vid, S_IRUGO, show_vid, NULL), + __ATTR(name, S_IRUGO, show_name, NULL), + __ATTR(alarms, S_IRUGO, show_alarms, NULL), +}; + +/* --------------------------------------------------------------------- + * Device registration and initialization + * --------------------------------------------------------------------- */ + +static void __devinit vt1211_init_device(struct vt1211_data *data) +{ + /* set VRM */ + data->vrm = vid_which_vrm(); + + /* Read (and initialize) UCH config */ + data->uch_config = vt1211_read8(data, VT1211_REG_UCH_CONFIG); + if (uch_config > -1) { + data->uch_config = (data->uch_config & 0x83) | + (uch_config << 2); + vt1211_write8(data, VT1211_REG_UCH_CONFIG, data->uch_config); + } + + /* Initialize the interrupt mode (if request at module load time). + * The VT1211 implements 3 different modes for clearing interrupts: + * 0: Clear INT when status register is read. Regenerate INT as long + * as temp stays above hysteresis limit. + * 1: Clear INT when status register is read. DON'T regenerate INT + * until temp falls below hysteresis limit and exceeds hot limit + * again. + * 2: Clear INT when temp falls below max limit. + * + * The driver only allows to force mode 0 since that's the only one + * that makes sense for 'sensors' */ + if (int_mode == 0) { + vt1211_write8(data, VT1211_REG_TEMP1_CONFIG, 0); + vt1211_write8(data, VT1211_REG_TEMP2_CONFIG, 0); + } + + /* Fill in some hard wired values into our data struct */ + data->pwm_auto_pwm[0][3] = 255; + data->pwm_auto_pwm[1][3] = 255; +} + +static void vt1211_remove_sysfs(struct platform_device *pdev) +{ + struct device *dev = &pdev->dev; + int i; + + for (i = 0; i < ARRAY_SIZE(vt1211_sysfs_in_input); i++) { + device_remove_file(dev, + &vt1211_sysfs_in_input[i].dev_attr); + device_remove_file(dev, + &vt1211_sysfs_in_min[i].dev_attr); + device_remove_file(dev, + &vt1211_sysfs_in_max[i].dev_attr); + device_remove_file(dev, + &vt1211_sysfs_in_alarm[i].dev_attr); + } + for (i = 0; i < ARRAY_SIZE(vt1211_sysfs_temp_input); i++) { + device_remove_file(dev, + &vt1211_sysfs_temp_input[i].dev_attr); + device_remove_file(dev, + &vt1211_sysfs_temp_max[i].dev_attr); + device_remove_file(dev, + &vt1211_sysfs_temp_max_hyst[i].dev_attr); + device_remove_file(dev, + &vt1211_sysfs_temp_alarm[i].dev_attr); + } + for (i = 0; i < ARRAY_SIZE(vt1211_sysfs_fan_pwm); i++) { + device_remove_file(dev, + &vt1211_sysfs_fan_pwm[i].dev_attr); + } + for (i = 0; i < ARRAY_SIZE(vt1211_sysfs_misc); i++) { + device_remove_file(dev, &vt1211_sysfs_misc[i]); + } +} + +static int __devinit vt1211_probe(struct platform_device *pdev) +{ + struct device *dev = &pdev->dev; + struct vt1211_data *data; + struct resource *res; + int i, err; + + if (!(data = kzalloc(sizeof(struct vt1211_data), GFP_KERNEL))) { + err = -ENOMEM; + dev_err(dev, "Out of memory\n"); + goto EXIT; + } + + res = platform_get_resource(pdev, IORESOURCE_IO, 0); + data->addr = res->start; + data->name = DRVNAME; + mutex_init(&data->update_lock); + + platform_set_drvdata(pdev, data); + + /* Initialize the VT1211 chip */ + vt1211_init_device(data); + + /* Create sysfs interface files */ + for (i = 0; i < ARRAY_SIZE(vt1211_sysfs_in_input); i++) { + if (ISVOLT(i, data->uch_config)) { + if ((err = device_create_file(dev, + &vt1211_sysfs_in_input[i].dev_attr)) || + (err = device_create_file(dev, + &vt1211_sysfs_in_min[i].dev_attr)) || + (err = device_create_file(dev, + &vt1211_sysfs_in_max[i].dev_attr)) || + (err = device_create_file(dev, + &vt1211_sysfs_in_alarm[i].dev_attr))) { + goto EXIT_DEV_REMOVE; + } + } + } + for (i = 0; i < ARRAY_SIZE(vt1211_sysfs_temp_input); i++) { + if (ISTEMP(i, data->uch_config)) { + if ((err = device_create_file(dev, + &vt1211_sysfs_temp_input[i].dev_attr)) || + (err = device_create_file(dev, + &vt1211_sysfs_temp_max[i].dev_attr)) || + (err = device_create_file(dev, + &vt1211_sysfs_temp_max_hyst[i].dev_attr)) || + (err = device_create_file(dev, + &vt1211_sysfs_temp_alarm[i].dev_attr))) { + goto EXIT_DEV_REMOVE; + } + } + } + for (i = 0; i < ARRAY_SIZE(vt1211_sysfs_fan_pwm); i++) { + err = device_create_file(dev, + &vt1211_sysfs_fan_pwm[i].dev_attr); + if (err) { + goto EXIT_DEV_REMOVE; + } + } + for (i = 0; i < ARRAY_SIZE(vt1211_sysfs_misc); i++) { + err = device_create_file(dev, + &vt1211_sysfs_misc[i]); + if (err) { + goto EXIT_DEV_REMOVE; + } + } + + /* Register device */ + data->class_dev = hwmon_device_register(dev); + if (IS_ERR(data->class_dev)) { + err = PTR_ERR(data->class_dev); + dev_err(dev, "Class registration failed (%d)\n", err); + goto EXIT_DEV_REMOVE_SILENT; + } + + return 0; + +EXIT_DEV_REMOVE: + dev_err(dev, "Sysfs interface creation failed (%d)\n", err); +EXIT_DEV_REMOVE_SILENT: + vt1211_remove_sysfs(pdev); + platform_set_drvdata(pdev, NULL); + kfree(data); +EXIT: + return err; +} + +static int __devexit vt1211_remove(struct platform_device *pdev) +{ + struct vt1211_data *data = platform_get_drvdata(pdev); + + hwmon_device_unregister(data->class_dev); + vt1211_remove_sysfs(pdev); + platform_set_drvdata(pdev, NULL); + kfree(data); + + return 0; +} + +static struct platform_driver vt1211_driver = { + .driver = { + .owner = THIS_MODULE, + .name = DRVNAME, + }, + .probe = vt1211_probe, + .remove = __devexit_p(vt1211_remove), +}; + +static int __init vt1211_device_add(unsigned short address) +{ + struct resource res = { + .start = address, + .end = address + 0x7f, + .flags = IORESOURCE_IO, + }; + int err; + + pdev = platform_device_alloc(DRVNAME, address); + if (!pdev) { + err = -ENOMEM; + printk(KERN_ERR DRVNAME ": Device allocation failed (%d)\n", + err); + goto EXIT; + } + + res.name = pdev->name; + err = platform_device_add_resources(pdev, &res, 1); + if (err) { + printk(KERN_ERR DRVNAME ": Device resource addition failed " + "(%d)\n", err); + goto EXIT_DEV_PUT; + } + + err = platform_device_add(pdev); + if (err) { + printk(KERN_ERR DRVNAME ": Device addition failed (%d)\n", + err); + goto EXIT_DEV_PUT; + } + + return 0; + +EXIT_DEV_PUT: + platform_device_put(pdev); +EXIT: + return err; +} + +static int __init vt1211_find(unsigned short *address) +{ + int err = -ENODEV; + + superio_enter(); + + if (superio_inb(SIO_VT1211_DEVID) != SIO_VT1211_ID) { + goto EXIT; + } + + superio_select(SIO_VT1211_LDN_HWMON); + + if ((superio_inb(SIO_VT1211_ACTIVE) & 1) == 0) { + printk(KERN_WARNING DRVNAME ": HW monitor is disabled, " + "skipping\n"); + goto EXIT; + } + + *address = ((superio_inb(SIO_VT1211_BADDR) << 8) | + (superio_inb(SIO_VT1211_BADDR + 1))) & 0xff00; + if (*address == 0) { + printk(KERN_WARNING DRVNAME ": Base address is not set, " + "skipping\n"); + goto EXIT; + } + + err = 0; + printk(KERN_INFO DRVNAME ": Found VT1211 chip at 0x%04x, " + "revision %u\n", *address, superio_inb(SIO_VT1211_DEVREV)); + +EXIT: + superio_exit(); + return err; +} + +static int __init vt1211_init(void) +{ + int err; + unsigned short address = 0; + + err = vt1211_find(&address); + if (err) { + goto EXIT; + } + + if ((uch_config < -1) || (uch_config > 31)) { + err = -EINVAL; + printk(KERN_WARNING DRVNAME ": Invalid UCH configuration %d. " + "Choose a value between 0 and 31.\n", uch_config); + goto EXIT; + } + + if ((int_mode < -1) || (int_mode > 0)) { + err = -EINVAL; + printk(KERN_WARNING DRVNAME ": Invalid interrupt mode %d. " + "Only mode 0 is supported.\n", int_mode); + goto EXIT; + } + + err = platform_driver_register(&vt1211_driver); + if (err) { + goto EXIT; + } + + /* Sets global pdev as a side effect */ + err = vt1211_device_add(address); + if (err) { + goto EXIT_DRV_UNREGISTER; + } + + return 0; + +EXIT_DRV_UNREGISTER: + platform_driver_unregister(&vt1211_driver); +EXIT: + return err; +} + +static void __exit vt1211_exit(void) +{ + platform_device_unregister(pdev); + platform_driver_unregister(&vt1211_driver); +} + +MODULE_AUTHOR("Juerg Haefliger "); +MODULE_DESCRIPTION("VT1211 sensors"); +MODULE_LICENSE("GPL"); + +module_init(vt1211_init); +module_exit(vt1211_exit); From 61d0b53363256e87aeb79286be2dc8f62a9d429a Mon Sep 17 00:00:00 2001 From: Juerg Haefliger Date: Sun, 24 Sep 2006 20:54:46 +0200 Subject: [PATCH 22/39] vt1211: Add documentation vt1211: Add documentation Add documentation for the new vt1211 hardware monitoring driver. Signed-off-by: Juerg Haefliger Signed-off-by: Jean Delvare Signed-off-by: Greg Kroah-Hartman --- Documentation/hwmon/vt1211 | 188 +++++++++++++++++++++++++++++++++++++ 1 file changed, 188 insertions(+) create mode 100644 Documentation/hwmon/vt1211 diff --git a/Documentation/hwmon/vt1211 b/Documentation/hwmon/vt1211 new file mode 100644 index 000000000000..d6d807138195 --- /dev/null +++ b/Documentation/hwmon/vt1211 @@ -0,0 +1,188 @@ +Kernel driver vt1211 +==================== + +Supported chips: + * VIA VT1211 + Prefix: 'vt1211' + Addresses scanned: none, address read from Super-I/O config space + Datasheet: Provided by VIA upon request and under NDA + +Authors: Juerg Haefliger + +This driver is based on the driver for kernel 2.4 by Mark D. Studebaker and +its port to kernel 2.6 by Lars Ekman. + +Thanks to Joseph Chan and Fiona Gatt from VIA for providing documentation and +technical support. + + +Description +----------- + +The VIA VT1211 Super-I/O chip includes complete hardware monitoring +capabilities. It monitors 2 dedicated temperature sensor inputs (temp1 and +temp2), 1 dedicated voltage (in5) and 2 fans. Additionally, the chip +implements 5 universal input channels (UCH1-5) that can be individually +programmed to either monitor a voltage or a temperature. + +This chip also provides manual and automatic control of fan speeds (according +to the datasheet). The driver only supports automatic control since the manual +mode doesn't seem to work as advertised in the datasheet. In fact I couldn't +get manual mode to work at all! Be aware that automatic mode hasn't been +tested very well (due to the fact that my EPIA M10000 doesn't have the fans +connected to the PWM outputs of the VT1211 :-(). + +The following table shows the relationship between the vt1211 inputs and the +sysfs nodes. + +Sensor Voltage Mode Temp Mode Default Use (from the datasheet) +------ ------------ --------- -------------------------------- +Reading 1 temp1 Intel thermal diode +Reading 3 temp2 Internal thermal diode +UCH1/Reading2 in0 temp3 NTC type thermistor +UCH2 in1 temp4 +2.5V +UCH3 in2 temp5 VccP (processor core) +UCH4 in3 temp6 +5V +UCH5 in4 temp7 +12V ++3.3V in5 Internal VCC (+3.3V) + + +Voltage Monitoring +------------------ + +Voltages are sampled by an 8-bit ADC with a LSB of ~10mV. The supported input +range is thus from 0 to 2.60V. Voltage values outside of this range need +external scaling resistors. This external scaling needs to be compensated for +via compute lines in sensors.conf, like: + +compute inx @*(1+R1/R2), @/(1+R1/R2) + +The board level scaling resistors according to VIA's recommendation are as +follows. And this is of course totally dependent on the actual board +implementation :-) You will have to find documentation for your own +motherboard and edit sensors.conf accordingly. + + Expected +Voltage R1 R2 Divider Raw Value +----------------------------------------------- ++2.5V 2K 10K 1.2 2083 mV +VccP --- --- 1.0 1400 mV (1) ++5V 14K 10K 2.4 2083 mV ++12V 47K 10K 5.7 2105 mV ++3.3V (int) 2K 3.4K 1.588 3300 mV (2) ++3.3V (ext) 6.8K 10K 1.68 1964 mV + +(1) Depending on the CPU (1.4V is for a VIA C3 Nehemiah). +(2) R1 and R2 for 3.3V (int) are internal to the VT1211 chip and the driver + performs the scaling and returns the properly scaled voltage value. + +Each measured voltage has an associated low and high limit which triggers an +alarm when crossed. + + +Temperature Monitoring +---------------------- + +Temperatures are reported in millidegree Celsius. Each measured temperature +has a high limit which triggers an alarm if crossed. There is an associated +hysteresis value with each temperature below which the temperature has to drop +before the alarm is cleared (this is only true for interrupt mode 0). The +interrupt mode can be forced to 0 in case the BIOS doesn't do it +automatically. For that, the parameter int_mode=0 needs to be supplied when +loading the driver module. Be aware that overriding BIOS defaults might cause +some unwanted side effects! + +All temperature channels except temp2 are external. Temp2 is the VT1211 +internal thermal diode and the driver does all the scaling for temp2 and +returns the temperature in millidegree Celsius. For the external channels +temp1 and temp3-temp7, scaling depends on the board implementation and needs +to be performed in userspace via sensors.conf. + +Temp1 is an Intel-type thermal diode which requires the following formula to +convert between sysfs readings and real temperatures: + +compute temp1 (@-Offset)/Gain, (@*Gain)+Offset + +According to the VIA VT1211 BIOS porting guide, the following gain and offset +values should be used: + +Diode Type Offset Gain +---------- ------ ---- +Intel CPU 88.638 0.9528 + 65.000 0.9686 *) +VIA C3 Ezra 83.869 0.9528 +VIA C3 Ezra-T 73.869 0.9528 + +*) This is the formula from the lm_sensors 2.10.0 sensors.conf file. I don't +know where it comes from or how it was derived, it's just listed here for +completeness. + +Temp3-temp7 support NTC thermistors. For these channels, the driver returns +the voltages as seen at the individual pins of UCH1-UCH5. The voltage at the +pin (Vpin) is formed by a voltage divider made of the thermistor (Rth) and a +scaling resistor (Rs): + +Vpin = 2200 * Rth / (Rs + Rth) (2200 is the ADC max limit of 2200 mV) + +The equation for the thermistor is as follows (google it if you want to know +more about it): + +Rth = Ro * exp(B * (1 / T - 1 / To)) (To is 298.15K (25C) and Ro is the + nominal resistance at 25C) + +Mingling the above two equations and assuming Rs = Ro and B = 3435 yields the +following formula for sensors.conf: + +compute tempx 1 / (1 / 298.15 - (` (2200 / @ - 1)) / 3435) - 273.15, + 2200 / (1 + (^ (3435 / 298.15 - 3435 / (273.15 + @)))) + + +Fan Speed Control +----------------- + +The VT1211 provides 2 programmable PWM outputs to control the speeds of 2 +fans. Writing a 2 to any of the two pwm[1-2]_enable sysfs nodes will put the +PWM controller in automatic mode. There is only a single controller that +controls both PWM outputs but each PWM output can be individually enabled and +disabled. + +Each PWM has 4 associated distinct output duty-cycles: full, high, low and +off. Full and off are internally hard-wired to 255 (100%) and 0 (0%), +respectively. High and low can be programmed via +pwm[1-2]_auto_point[2-3]_pwm. Each PWM output can be associated with a +different thermal input but - and here's the weird part - only one set of +thermal thresholds exist that controls both PWMs output duty-cycles. The +thermal thresholds are accessible via pwm[1-2]_auto_point[1-4]_temp. Note +that even though there are 2 sets of 4 auto points each, they map to the same +registers in the VT1211 and programming one set is sufficient (actually only +the first set pwm1_auto_point[1-4]_temp is writable, the second set is +read-only). + +PWM Auto Point PWM Output Duty-Cycle +------------------------------------------------ +pwm[1-2]_auto_point4_pwm full speed duty-cycle (hard-wired to 255) +pwm[1-2]_auto_point3_pwm high speed duty-cycle +pwm[1-2]_auto_point2_pwm low speed duty-cycle +pwm[1-2]_auto_point1_pwm off duty-cycle (hard-wired to 0) + +Temp Auto Point Thermal Threshold +--------------------------------------------- +pwm[1-2]_auto_point4_temp full speed temp +pwm[1-2]_auto_point3_temp high speed temp +pwm[1-2]_auto_point2_temp low speed temp +pwm[1-2]_auto_point1_temp off temp + +Long story short, the controller implements the following algorithm to set the +PWM output duty-cycle based on the input temperature: + +Thermal Threshold Output Duty-Cycle + (Rising Temp) (Falling Temp) +---------------------------------------------------------- + full speed duty-cycle full speed duty-cycle +full speed temp + high speed duty-cycle full speed duty-cycle +high speed temp + low speed duty-cycle high speed duty-cycle +low speed temp + off duty-cycle low speed duty-cycle +off temp From a1fdcb96ee33ba75318476a2a4691147c9f2ad90 Mon Sep 17 00:00:00 2001 From: Juerg Haefliger Date: Sun, 24 Sep 2006 20:55:34 +0200 Subject: [PATCH 23/39] vt1211: Document module parameters vt1211: Document module parameters Add a description of the module parameters to the documentation of the vt1211 driver. Signed-off-by: Juerg Haefliger Signed-off-by: Jean Delvare Signed-off-by: Greg Kroah-Hartman --- Documentation/hwmon/vt1211 | 24 +++++++++++++++++++++--- 1 file changed, 21 insertions(+), 3 deletions(-) diff --git a/Documentation/hwmon/vt1211 b/Documentation/hwmon/vt1211 index d6d807138195..77fa633b97a8 100644 --- a/Documentation/hwmon/vt1211 +++ b/Documentation/hwmon/vt1211 @@ -16,6 +16,26 @@ Thanks to Joseph Chan and Fiona Gatt from VIA for providing documentation and technical support. +Module Parameters +----------------- + +* uch_config: int Override the BIOS default universal channel (UCH) + configuration for channels 1-5. + Legal values are in the range of 0-31. Bit 0 maps to + UCH1, bit 1 maps to UCH2 and so on. Setting a bit to 1 + enables the thermal input of that particular UCH and + setting a bit to 0 enables the voltage input. + +* int_mode: int Override the BIOS default temperature interrupt mode. + The only possible value is 0 which forces interrupt + mode 0. In this mode, any pending interrupt is cleared + when the status register is read but is regenerated as + long as the temperature stays above the hysteresis + limit. + +Be aware that overriding BIOS defaults might cause some unwanted side effects! + + Description ----------- @@ -88,9 +108,7 @@ has a high limit which triggers an alarm if crossed. There is an associated hysteresis value with each temperature below which the temperature has to drop before the alarm is cleared (this is only true for interrupt mode 0). The interrupt mode can be forced to 0 in case the BIOS doesn't do it -automatically. For that, the parameter int_mode=0 needs to be supplied when -loading the driver module. Be aware that overriding BIOS defaults might cause -some unwanted side effects! +automatically. See the 'Module Parameters' section for details. All temperature channels except temp2 are external. Temp2 is the VT1211 internal thermal diode and the driver does all the scaling for temp2 and From c1685f61b0a3110b701d09b84a9f9a3d4e9ef2e2 Mon Sep 17 00:00:00 2001 From: "Mark M. Hoffman" Date: Sun, 24 Sep 2006 20:59:49 +0200 Subject: [PATCH 24/39] hwmon: Fix unchecked return status, batch 1 hwmon: Fix unchecked return status, batch 1 Fix up some hwmon drivers so that they no longer ignore return status from device_create_file(). Signed-off-by: Mark M. Hoffman Signed-off-by: Jean Delvare Signed-off-by: Greg Kroah-Hartman --- drivers/hwmon/asb100.c | 122 ++++++++++--------- drivers/hwmon/lm75.c | 24 +++- drivers/hwmon/lm78.c | 88 ++++++++------ drivers/hwmon/smsc47b397.c | 39 +++--- drivers/hwmon/w83627hf.c | 238 ++++++++++++++++++++++--------------- 5 files changed, 302 insertions(+), 209 deletions(-) diff --git a/drivers/hwmon/asb100.c b/drivers/hwmon/asb100.c index facc1ccb8338..57b1c7b7ac3f 100644 --- a/drivers/hwmon/asb100.c +++ b/drivers/hwmon/asb100.c @@ -298,12 +298,6 @@ sysfs_in(4); sysfs_in(5); sysfs_in(6); -#define device_create_file_in(client, offset) do { \ - device_create_file(&client->dev, &dev_attr_in##offset##_input); \ - device_create_file(&client->dev, &dev_attr_in##offset##_min); \ - device_create_file(&client->dev, &dev_attr_in##offset##_max); \ -} while (0) - /* 3 Fans */ static ssize_t show_fan(struct device *dev, char *buf, int nr) { @@ -421,12 +415,6 @@ sysfs_fan(1); sysfs_fan(2); sysfs_fan(3); -#define device_create_file_fan(client, offset) do { \ - device_create_file(&client->dev, &dev_attr_fan##offset##_input); \ - device_create_file(&client->dev, &dev_attr_fan##offset##_min); \ - device_create_file(&client->dev, &dev_attr_fan##offset##_div); \ -} while (0) - /* 4 Temp. Sensors */ static int sprintf_temp_from_reg(u16 reg, char *buf, int nr) { @@ -515,12 +503,6 @@ sysfs_temp(3); sysfs_temp(4); /* VID */ -#define device_create_file_temp(client, num) do { \ - device_create_file(&client->dev, &dev_attr_temp##num##_input); \ - device_create_file(&client->dev, &dev_attr_temp##num##_max); \ - device_create_file(&client->dev, &dev_attr_temp##num##_max_hyst); \ -} while (0) - static ssize_t show_vid(struct device *dev, struct device_attribute *attr, char *buf) { struct asb100_data *data = asb100_update_device(dev); @@ -528,8 +510,6 @@ static ssize_t show_vid(struct device *dev, struct device_attribute *attr, char } static DEVICE_ATTR(cpu0_vid, S_IRUGO, show_vid, NULL); -#define device_create_file_vid(client) \ -device_create_file(&client->dev, &dev_attr_cpu0_vid) /* VRM */ static ssize_t show_vrm(struct device *dev, struct device_attribute *attr, char *buf) @@ -549,8 +529,6 @@ static ssize_t set_vrm(struct device *dev, struct device_attribute *attr, const /* Alarms */ static DEVICE_ATTR(vrm, S_IRUGO | S_IWUSR, show_vrm, set_vrm); -#define device_create_file_vrm(client) \ -device_create_file(&client->dev, &dev_attr_vrm); static ssize_t show_alarms(struct device *dev, struct device_attribute *attr, char *buf) { @@ -559,8 +537,6 @@ static ssize_t show_alarms(struct device *dev, struct device_attribute *attr, ch } static DEVICE_ATTR(alarms, S_IRUGO, show_alarms, NULL); -#define device_create_file_alarms(client) \ -device_create_file(&client->dev, &dev_attr_alarms) /* 1 PWM */ static ssize_t show_pwm1(struct device *dev, struct device_attribute *attr, char *buf) @@ -607,10 +583,65 @@ static ssize_t set_pwm_enable1(struct device *dev, struct device_attribute *attr static DEVICE_ATTR(pwm1, S_IRUGO | S_IWUSR, show_pwm1, set_pwm1); static DEVICE_ATTR(pwm1_enable, S_IRUGO | S_IWUSR, show_pwm_enable1, set_pwm_enable1); -#define device_create_file_pwm1(client) do { \ - device_create_file(&new_client->dev, &dev_attr_pwm1); \ - device_create_file(&new_client->dev, &dev_attr_pwm1_enable); \ -} while (0) + +static struct attribute *asb100_attributes[] = { + &dev_attr_in0_input.attr, + &dev_attr_in0_min.attr, + &dev_attr_in0_max.attr, + &dev_attr_in1_input.attr, + &dev_attr_in1_min.attr, + &dev_attr_in1_max.attr, + &dev_attr_in2_input.attr, + &dev_attr_in2_min.attr, + &dev_attr_in2_max.attr, + &dev_attr_in3_input.attr, + &dev_attr_in3_min.attr, + &dev_attr_in3_max.attr, + &dev_attr_in4_input.attr, + &dev_attr_in4_min.attr, + &dev_attr_in4_max.attr, + &dev_attr_in5_input.attr, + &dev_attr_in5_min.attr, + &dev_attr_in5_max.attr, + &dev_attr_in6_input.attr, + &dev_attr_in6_min.attr, + &dev_attr_in6_max.attr, + + &dev_attr_fan1_input.attr, + &dev_attr_fan1_min.attr, + &dev_attr_fan1_div.attr, + &dev_attr_fan2_input.attr, + &dev_attr_fan2_min.attr, + &dev_attr_fan2_div.attr, + &dev_attr_fan3_input.attr, + &dev_attr_fan3_min.attr, + &dev_attr_fan3_div.attr, + + &dev_attr_temp1_input.attr, + &dev_attr_temp1_max.attr, + &dev_attr_temp1_max_hyst.attr, + &dev_attr_temp2_input.attr, + &dev_attr_temp2_max.attr, + &dev_attr_temp2_max_hyst.attr, + &dev_attr_temp3_input.attr, + &dev_attr_temp3_max.attr, + &dev_attr_temp3_max_hyst.attr, + &dev_attr_temp4_input.attr, + &dev_attr_temp4_max.attr, + &dev_attr_temp4_max_hyst.attr, + + &dev_attr_cpu0_vid.attr, + &dev_attr_vrm.attr, + &dev_attr_alarms.attr, + &dev_attr_pwm1.attr, + &dev_attr_pwm1_enable.attr, + + NULL +}; + +static const struct attribute_group asb100_group = { + .attrs = asb100_attributes, +}; /* This function is called when: asb100_driver is inserted (when this module is loaded), for each @@ -810,38 +841,19 @@ static int asb100_detect(struct i2c_adapter *adapter, int address, int kind) data->fan_min[2] = asb100_read_value(new_client, ASB100_REG_FAN_MIN(2)); /* Register sysfs hooks */ + if ((err = sysfs_create_group(&new_client->dev.kobj, &asb100_group))) + goto ERROR3; + data->class_dev = hwmon_device_register(&new_client->dev); if (IS_ERR(data->class_dev)) { err = PTR_ERR(data->class_dev); - goto ERROR3; + goto ERROR4; } - device_create_file_in(new_client, 0); - device_create_file_in(new_client, 1); - device_create_file_in(new_client, 2); - device_create_file_in(new_client, 3); - device_create_file_in(new_client, 4); - device_create_file_in(new_client, 5); - device_create_file_in(new_client, 6); - - device_create_file_fan(new_client, 1); - device_create_file_fan(new_client, 2); - device_create_file_fan(new_client, 3); - - device_create_file_temp(new_client, 1); - device_create_file_temp(new_client, 2); - device_create_file_temp(new_client, 3); - device_create_file_temp(new_client, 4); - - device_create_file_vid(new_client); - device_create_file_vrm(new_client); - - device_create_file_alarms(new_client); - - device_create_file_pwm1(new_client); - return 0; +ERROR4: + sysfs_remove_group(&new_client->dev.kobj, &asb100_group); ERROR3: i2c_detach_client(data->lm75[1]); i2c_detach_client(data->lm75[0]); @@ -861,8 +873,10 @@ static int asb100_detach_client(struct i2c_client *client) int err; /* main client */ - if (data) + if (data) { hwmon_device_unregister(data->class_dev); + sysfs_remove_group(&client->dev.kobj, &asb100_group); + } if ((err = i2c_detach_client(client))) return err; diff --git a/drivers/hwmon/lm75.c b/drivers/hwmon/lm75.c index fc25b90ec24a..7c65b8bb6d72 100644 --- a/drivers/hwmon/lm75.c +++ b/drivers/hwmon/lm75.c @@ -112,6 +112,18 @@ static int lm75_attach_adapter(struct i2c_adapter *adapter) return i2c_probe(adapter, &addr_data, lm75_detect); } +static struct attribute *lm75_attributes[] = { + &dev_attr_temp1_input.attr, + &dev_attr_temp1_max.attr, + &dev_attr_temp1_max_hyst.attr, + + NULL +}; + +static const struct attribute_group lm75_group = { + .attrs = lm75_attributes, +}; + /* This function is called by i2c_probe */ static int lm75_detect(struct i2c_adapter *adapter, int address, int kind) { @@ -199,18 +211,19 @@ static int lm75_detect(struct i2c_adapter *adapter, int address, int kind) lm75_init_client(new_client); /* Register sysfs hooks */ + if ((err = sysfs_create_group(&new_client->dev.kobj, &lm75_group))) + goto exit_detach; + data->class_dev = hwmon_device_register(&new_client->dev); if (IS_ERR(data->class_dev)) { err = PTR_ERR(data->class_dev); - goto exit_detach; + goto exit_remove; } - device_create_file(&new_client->dev, &dev_attr_temp1_max); - device_create_file(&new_client->dev, &dev_attr_temp1_max_hyst); - device_create_file(&new_client->dev, &dev_attr_temp1_input); - return 0; +exit_remove: + sysfs_remove_group(&new_client->dev.kobj, &lm75_group); exit_detach: i2c_detach_client(new_client); exit_free: @@ -223,6 +236,7 @@ static int lm75_detach_client(struct i2c_client *client) { struct lm75_data *data = i2c_get_clientdata(client); hwmon_device_unregister(data->class_dev); + sysfs_remove_group(&client->dev.kobj, &lm75_group); i2c_detach_client(client); kfree(data); return 0; diff --git a/drivers/hwmon/lm78.c b/drivers/hwmon/lm78.c index fa1715b9a996..ac1b746df6d0 100644 --- a/drivers/hwmon/lm78.c +++ b/drivers/hwmon/lm78.c @@ -482,6 +482,50 @@ static int lm78_isa_attach_adapter(struct i2c_adapter *adapter) return lm78_detect(adapter, isa_address, -1); } +static struct attribute *lm78_attributes[] = { + &dev_attr_in0_input.attr, + &dev_attr_in0_min.attr, + &dev_attr_in0_max.attr, + &dev_attr_in1_input.attr, + &dev_attr_in1_min.attr, + &dev_attr_in1_max.attr, + &dev_attr_in2_input.attr, + &dev_attr_in2_min.attr, + &dev_attr_in2_max.attr, + &dev_attr_in3_input.attr, + &dev_attr_in3_min.attr, + &dev_attr_in3_max.attr, + &dev_attr_in4_input.attr, + &dev_attr_in4_min.attr, + &dev_attr_in4_max.attr, + &dev_attr_in5_input.attr, + &dev_attr_in5_min.attr, + &dev_attr_in5_max.attr, + &dev_attr_in6_input.attr, + &dev_attr_in6_min.attr, + &dev_attr_in6_max.attr, + &dev_attr_temp1_input.attr, + &dev_attr_temp1_max.attr, + &dev_attr_temp1_max_hyst.attr, + &dev_attr_fan1_input.attr, + &dev_attr_fan1_min.attr, + &dev_attr_fan1_div.attr, + &dev_attr_fan2_input.attr, + &dev_attr_fan2_min.attr, + &dev_attr_fan2_div.attr, + &dev_attr_fan3_input.attr, + &dev_attr_fan3_min.attr, + &dev_attr_fan3_div.attr, + &dev_attr_alarms.attr, + &dev_attr_cpu0_vid.attr, + + NULL +}; + +static const struct attribute_group lm78_group = { + .attrs = lm78_attributes, +}; + /* This function is called by i2c_probe */ static int lm78_detect(struct i2c_adapter *adapter, int address, int kind) { @@ -616,50 +660,19 @@ static int lm78_detect(struct i2c_adapter *adapter, int address, int kind) } /* Register sysfs hooks */ + if ((err = sysfs_create_group(&new_client->dev.kobj, &lm78_group))) + goto ERROR3; + data->class_dev = hwmon_device_register(&new_client->dev); if (IS_ERR(data->class_dev)) { err = PTR_ERR(data->class_dev); - goto ERROR3; + goto ERROR4; } - device_create_file(&new_client->dev, &dev_attr_in0_input); - device_create_file(&new_client->dev, &dev_attr_in0_min); - device_create_file(&new_client->dev, &dev_attr_in0_max); - device_create_file(&new_client->dev, &dev_attr_in1_input); - device_create_file(&new_client->dev, &dev_attr_in1_min); - device_create_file(&new_client->dev, &dev_attr_in1_max); - device_create_file(&new_client->dev, &dev_attr_in2_input); - device_create_file(&new_client->dev, &dev_attr_in2_min); - device_create_file(&new_client->dev, &dev_attr_in2_max); - device_create_file(&new_client->dev, &dev_attr_in3_input); - device_create_file(&new_client->dev, &dev_attr_in3_min); - device_create_file(&new_client->dev, &dev_attr_in3_max); - device_create_file(&new_client->dev, &dev_attr_in4_input); - device_create_file(&new_client->dev, &dev_attr_in4_min); - device_create_file(&new_client->dev, &dev_attr_in4_max); - device_create_file(&new_client->dev, &dev_attr_in5_input); - device_create_file(&new_client->dev, &dev_attr_in5_min); - device_create_file(&new_client->dev, &dev_attr_in5_max); - device_create_file(&new_client->dev, &dev_attr_in6_input); - device_create_file(&new_client->dev, &dev_attr_in6_min); - device_create_file(&new_client->dev, &dev_attr_in6_max); - device_create_file(&new_client->dev, &dev_attr_temp1_input); - device_create_file(&new_client->dev, &dev_attr_temp1_max); - device_create_file(&new_client->dev, &dev_attr_temp1_max_hyst); - device_create_file(&new_client->dev, &dev_attr_fan1_input); - device_create_file(&new_client->dev, &dev_attr_fan1_min); - device_create_file(&new_client->dev, &dev_attr_fan1_div); - device_create_file(&new_client->dev, &dev_attr_fan2_input); - device_create_file(&new_client->dev, &dev_attr_fan2_min); - device_create_file(&new_client->dev, &dev_attr_fan2_div); - device_create_file(&new_client->dev, &dev_attr_fan3_input); - device_create_file(&new_client->dev, &dev_attr_fan3_min); - device_create_file(&new_client->dev, &dev_attr_fan3_div); - device_create_file(&new_client->dev, &dev_attr_alarms); - device_create_file(&new_client->dev, &dev_attr_cpu0_vid); - return 0; +ERROR4: + sysfs_remove_group(&new_client->dev.kobj, &lm78_group); ERROR3: i2c_detach_client(new_client); ERROR2: @@ -677,6 +690,7 @@ static int lm78_detach_client(struct i2c_client *client) int err; hwmon_device_unregister(data->class_dev); + sysfs_remove_group(&client->dev.kobj, &lm78_group); if ((err = i2c_detach_client(client))) return err; diff --git a/drivers/hwmon/smsc47b397.c b/drivers/hwmon/smsc47b397.c index a85869393bab..72b0e2d8650c 100644 --- a/drivers/hwmon/smsc47b397.c +++ b/drivers/hwmon/smsc47b397.c @@ -176,9 +176,6 @@ sysfs_temp(2); sysfs_temp(3); sysfs_temp(4); -#define device_create_file_temp(client, num) \ - device_create_file(&client->dev, &dev_attr_temp##num##_input) - /* FAN: 1 RPM/bit REG: count of 90kHz pulses / revolution */ static int fan_from_reg(u16 reg) @@ -205,8 +202,22 @@ sysfs_fan(2); sysfs_fan(3); sysfs_fan(4); -#define device_create_file_fan(client, num) \ - device_create_file(&client->dev, &dev_attr_fan##num##_input) +static struct attribute *smsc47b397_attributes[] = { + &dev_attr_temp1_input.attr, + &dev_attr_temp2_input.attr, + &dev_attr_temp3_input.attr, + &dev_attr_temp4_input.attr, + &dev_attr_fan1_input.attr, + &dev_attr_fan2_input.attr, + &dev_attr_fan3_input.attr, + &dev_attr_fan4_input.attr, + + NULL +}; + +static const struct attribute_group smsc47b397_group = { + .attrs = smsc47b397_attributes, +}; static int smsc47b397_detach_client(struct i2c_client *client) { @@ -214,6 +225,7 @@ static int smsc47b397_detach_client(struct i2c_client *client) int err; hwmon_device_unregister(data->class_dev); + sysfs_remove_group(&client->dev.kobj, &smsc47b397_group); if ((err = i2c_detach_client(client))) return err; @@ -268,24 +280,19 @@ static int smsc47b397_detect(struct i2c_adapter *adapter) if ((err = i2c_attach_client(new_client))) goto error_free; + if ((err = sysfs_create_group(&new_client->dev.kobj, &smsc47b397_group))) + goto error_detach; + data->class_dev = hwmon_device_register(&new_client->dev); if (IS_ERR(data->class_dev)) { err = PTR_ERR(data->class_dev); - goto error_detach; + goto error_remove; } - device_create_file_temp(new_client, 1); - device_create_file_temp(new_client, 2); - device_create_file_temp(new_client, 3); - device_create_file_temp(new_client, 4); - - device_create_file_fan(new_client, 1); - device_create_file_fan(new_client, 2); - device_create_file_fan(new_client, 3); - device_create_file_fan(new_client, 4); - return 0; +error_remove: + sysfs_remove_group(&new_client->dev.kobj, &smsc47b397_group); error_detach: i2c_detach_client(new_client); error_free: diff --git a/drivers/hwmon/w83627hf.c b/drivers/hwmon/w83627hf.c index 30295028ea99..dfdc29c77123 100644 --- a/drivers/hwmon/w83627hf.c +++ b/drivers/hwmon/w83627hf.c @@ -512,13 +512,6 @@ static DEVICE_ATTR(in0_min, S_IRUGO | S_IWUSR, static DEVICE_ATTR(in0_max, S_IRUGO | S_IWUSR, show_regs_in_max0, store_regs_in_max0); -#define device_create_file_in(client, offset) \ -do { \ -device_create_file(&client->dev, &dev_attr_in##offset##_input); \ -device_create_file(&client->dev, &dev_attr_in##offset##_min); \ -device_create_file(&client->dev, &dev_attr_in##offset##_max); \ -} while (0) - #define show_fan_reg(reg) \ static ssize_t show_##reg (struct device *dev, char *buf, int nr) \ { \ @@ -576,12 +569,6 @@ sysfs_fan_min_offset(2); sysfs_fan_offset(3); sysfs_fan_min_offset(3); -#define device_create_file_fan(client, offset) \ -do { \ -device_create_file(&client->dev, &dev_attr_fan##offset##_input); \ -device_create_file(&client->dev, &dev_attr_fan##offset##_min); \ -} while (0) - #define show_temp_reg(reg) \ static ssize_t show_##reg (struct device *dev, char *buf, int nr) \ { \ @@ -656,13 +643,6 @@ sysfs_temp_offsets(1); sysfs_temp_offsets(2); sysfs_temp_offsets(3); -#define device_create_file_temp(client, offset) \ -do { \ -device_create_file(&client->dev, &dev_attr_temp##offset##_input); \ -device_create_file(&client->dev, &dev_attr_temp##offset##_max); \ -device_create_file(&client->dev, &dev_attr_temp##offset##_max_hyst); \ -} while (0) - static ssize_t show_vid_reg(struct device *dev, struct device_attribute *attr, char *buf) { @@ -670,8 +650,6 @@ show_vid_reg(struct device *dev, struct device_attribute *attr, char *buf) return sprintf(buf, "%ld\n", (long) vid_from_reg(data->vid, data->vrm)); } static DEVICE_ATTR(cpu0_vid, S_IRUGO, show_vid_reg, NULL); -#define device_create_file_vid(client) \ -device_create_file(&client->dev, &dev_attr_cpu0_vid) static ssize_t show_vrm_reg(struct device *dev, struct device_attribute *attr, char *buf) @@ -692,8 +670,6 @@ store_vrm_reg(struct device *dev, struct device_attribute *attr, const char *buf return count; } static DEVICE_ATTR(vrm, S_IRUGO | S_IWUSR, show_vrm_reg, store_vrm_reg); -#define device_create_file_vrm(client) \ -device_create_file(&client->dev, &dev_attr_vrm) static ssize_t show_alarms_reg(struct device *dev, struct device_attribute *attr, char *buf) @@ -702,8 +678,6 @@ show_alarms_reg(struct device *dev, struct device_attribute *attr, char *buf) return sprintf(buf, "%ld\n", (long) data->alarms); } static DEVICE_ATTR(alarms, S_IRUGO, show_alarms_reg, NULL); -#define device_create_file_alarms(client) \ -device_create_file(&client->dev, &dev_attr_alarms) #define show_beep_reg(REG, reg) \ static ssize_t show_beep_##reg (struct device *dev, struct device_attribute *attr, char *buf) \ @@ -766,12 +740,6 @@ static DEVICE_ATTR(beep_##reg, S_IRUGO | S_IWUSR, \ sysfs_beep(ENABLE, enable); sysfs_beep(MASK, mask); -#define device_create_file_beep(client) \ -do { \ -device_create_file(&client->dev, &dev_attr_beep_enable); \ -device_create_file(&client->dev, &dev_attr_beep_mask); \ -} while (0) - static ssize_t show_fan_div_reg(struct device *dev, char *buf, int nr) { @@ -837,11 +805,6 @@ sysfs_fan_div(1); sysfs_fan_div(2); sysfs_fan_div(3); -#define device_create_file_fan_div(client, offset) \ -do { \ -device_create_file(&client->dev, &dev_attr_fan##offset##_div); \ -} while (0) - static ssize_t show_pwm_reg(struct device *dev, char *buf, int nr) { @@ -896,11 +859,6 @@ sysfs_pwm(1); sysfs_pwm(2); sysfs_pwm(3); -#define device_create_file_pwm(client, offset) \ -do { \ -device_create_file(&client->dev, &dev_attr_pwm##offset); \ -} while (0) - static ssize_t show_sensor_reg(struct device *dev, char *buf, int nr) { @@ -972,12 +930,6 @@ sysfs_sensor(1); sysfs_sensor(2); sysfs_sensor(3); -#define device_create_file_sensor(client, offset) \ -do { \ -device_create_file(&client->dev, &dev_attr_temp##offset##_type); \ -} while (0) - - static int __init w83627hf_find(int sioaddr, unsigned short *addr) { u16 val; @@ -1009,6 +961,85 @@ static int __init w83627hf_find(int sioaddr, unsigned short *addr) return 0; } +static struct attribute *w83627hf_attributes[] = { + &dev_attr_in0_input.attr, + &dev_attr_in0_min.attr, + &dev_attr_in0_max.attr, + &dev_attr_in2_input.attr, + &dev_attr_in2_min.attr, + &dev_attr_in2_max.attr, + &dev_attr_in3_input.attr, + &dev_attr_in3_min.attr, + &dev_attr_in3_max.attr, + &dev_attr_in4_input.attr, + &dev_attr_in4_min.attr, + &dev_attr_in4_max.attr, + &dev_attr_in7_input.attr, + &dev_attr_in7_min.attr, + &dev_attr_in7_max.attr, + &dev_attr_in8_input.attr, + &dev_attr_in8_min.attr, + &dev_attr_in8_max.attr, + + &dev_attr_fan1_input.attr, + &dev_attr_fan1_min.attr, + &dev_attr_fan1_div.attr, + &dev_attr_fan2_input.attr, + &dev_attr_fan2_min.attr, + &dev_attr_fan2_div.attr, + + &dev_attr_temp1_input.attr, + &dev_attr_temp1_max.attr, + &dev_attr_temp1_max_hyst.attr, + &dev_attr_temp1_type.attr, + &dev_attr_temp2_input.attr, + &dev_attr_temp2_max.attr, + &dev_attr_temp2_max_hyst.attr, + &dev_attr_temp2_type.attr, + + &dev_attr_alarms.attr, + &dev_attr_beep_enable.attr, + &dev_attr_beep_mask.attr, + + &dev_attr_pwm1.attr, + &dev_attr_pwm2.attr, + + NULL +}; + +static const struct attribute_group w83627hf_group = { + .attrs = w83627hf_attributes, +}; + +static struct attribute *w83627hf_attributes_opt[] = { + &dev_attr_in1_input.attr, + &dev_attr_in1_min.attr, + &dev_attr_in1_max.attr, + &dev_attr_in5_input.attr, + &dev_attr_in5_min.attr, + &dev_attr_in5_max.attr, + &dev_attr_in6_input.attr, + &dev_attr_in6_min.attr, + &dev_attr_in6_max.attr, + + &dev_attr_fan3_input.attr, + &dev_attr_fan3_min.attr, + &dev_attr_fan3_div.attr, + + &dev_attr_temp3_input.attr, + &dev_attr_temp3_max.attr, + &dev_attr_temp3_max_hyst.attr, + &dev_attr_temp3_type.attr, + + &dev_attr_pwm3.attr, + + NULL +}; + +static const struct attribute_group w83627hf_group_opt = { + .attrs = w83627hf_attributes_opt, +}; + static int w83627hf_detect(struct i2c_adapter *adapter) { int val, kind; @@ -1108,62 +1139,72 @@ static int w83627hf_detect(struct i2c_adapter *adapter) data->fan_min[1] = w83627hf_read_value(new_client, W83781D_REG_FAN_MIN(2)); data->fan_min[2] = w83627hf_read_value(new_client, W83781D_REG_FAN_MIN(3)); - /* Register sysfs hooks */ + /* Register common device attributes */ + if ((err = sysfs_create_group(&new_client->dev.kobj, &w83627hf_group))) + goto ERROR3; + + /* Register chip-specific device attributes */ + if (kind == w83627hf || kind == w83697hf) + if ((err = device_create_file(&new_client->dev, + &dev_attr_in5_input)) + || (err = device_create_file(&new_client->dev, + &dev_attr_in5_min)) + || (err = device_create_file(&new_client->dev, + &dev_attr_in5_max)) + || (err = device_create_file(&new_client->dev, + &dev_attr_in6_input)) + || (err = device_create_file(&new_client->dev, + &dev_attr_in6_min)) + || (err = device_create_file(&new_client->dev, + &dev_attr_in6_max))) + goto ERROR4; + + if (kind != w83697hf) + if ((err = device_create_file(&new_client->dev, + &dev_attr_in1_input)) + || (err = device_create_file(&new_client->dev, + &dev_attr_in1_min)) + || (err = device_create_file(&new_client->dev, + &dev_attr_in1_max)) + || (err = device_create_file(&new_client->dev, + &dev_attr_fan3_input)) + || (err = device_create_file(&new_client->dev, + &dev_attr_fan3_min)) + || (err = device_create_file(&new_client->dev, + &dev_attr_fan3_div)) + || (err = device_create_file(&new_client->dev, + &dev_attr_temp3_input)) + || (err = device_create_file(&new_client->dev, + &dev_attr_temp3_max)) + || (err = device_create_file(&new_client->dev, + &dev_attr_temp3_max_hyst)) + || (err = device_create_file(&new_client->dev, + &dev_attr_temp3_type))) + goto ERROR4; + + if (kind != w83697hf && data->vid != 0xff) + if ((err = device_create_file(&new_client->dev, + &dev_attr_cpu0_vid)) + || (err = device_create_file(&new_client->dev, + &dev_attr_vrm))) + goto ERROR4; + + if (kind == w83627thf || kind == w83637hf || kind == w83687thf) + if ((err = device_create_file(&new_client->dev, + &dev_attr_pwm3))) + goto ERROR4; + data->class_dev = hwmon_device_register(&new_client->dev); if (IS_ERR(data->class_dev)) { err = PTR_ERR(data->class_dev); - goto ERROR3; + goto ERROR4; } - device_create_file_in(new_client, 0); - if (kind != w83697hf) - device_create_file_in(new_client, 1); - device_create_file_in(new_client, 2); - device_create_file_in(new_client, 3); - device_create_file_in(new_client, 4); - if (kind == w83627hf || kind == w83697hf) { - device_create_file_in(new_client, 5); - device_create_file_in(new_client, 6); - } - device_create_file_in(new_client, 7); - device_create_file_in(new_client, 8); - - device_create_file_fan(new_client, 1); - device_create_file_fan(new_client, 2); - if (kind != w83697hf) - device_create_file_fan(new_client, 3); - - device_create_file_temp(new_client, 1); - device_create_file_temp(new_client, 2); - if (kind != w83697hf) - device_create_file_temp(new_client, 3); - - if (kind != w83697hf && data->vid != 0xff) { - device_create_file_vid(new_client); - device_create_file_vrm(new_client); - } - - device_create_file_fan_div(new_client, 1); - device_create_file_fan_div(new_client, 2); - if (kind != w83697hf) - device_create_file_fan_div(new_client, 3); - - device_create_file_alarms(new_client); - - device_create_file_beep(new_client); - - device_create_file_pwm(new_client, 1); - device_create_file_pwm(new_client, 2); - if (kind == w83627thf || kind == w83637hf || kind == w83687thf) - device_create_file_pwm(new_client, 3); - - device_create_file_sensor(new_client, 1); - device_create_file_sensor(new_client, 2); - if (kind != w83697hf) - device_create_file_sensor(new_client, 3); - return 0; + ERROR4: + sysfs_remove_group(&new_client->dev.kobj, &w83627hf_group); + sysfs_remove_group(&new_client->dev.kobj, &w83627hf_group_opt); ERROR3: i2c_detach_client(new_client); ERROR2: @@ -1181,6 +1222,9 @@ static int w83627hf_detach_client(struct i2c_client *client) hwmon_device_unregister(data->class_dev); + sysfs_remove_group(&client->dev.kobj, &w83627hf_group); + sysfs_remove_group(&client->dev.kobj, &w83627hf_group_opt); + if ((err = i2c_detach_client(client))) return err; From 44646c19b41e40d81f5e4863466914e8ce060cc0 Mon Sep 17 00:00:00 2001 From: Jim Cromie Date: Sun, 24 Sep 2006 21:01:56 +0200 Subject: [PATCH 25/39] pc87360: Move some code around pc87360: Move some code around Moves code for get-set-decl tuples for 3 items: cpu0_vid, vrm, alarms_in up, to just after the get-set-decl tuple for voltages. These items are already 'activated' together with the rest of the voltage attributes, so the move tightens the grouping that's made explicit in next patch. Signed-off-by: Jim Cromie Signed-off-by: Jean Delvare Signed-off-by: Greg Kroah-Hartman --- drivers/hwmon/pc87360.c | 56 ++++++++++++++++++++--------------------- 1 file changed, 28 insertions(+), 28 deletions(-) diff --git a/drivers/hwmon/pc87360.c b/drivers/hwmon/pc87360.c index 236f9f29c624..db543a8d78b0 100644 --- a/drivers/hwmon/pc87360.c +++ b/drivers/hwmon/pc87360.c @@ -472,6 +472,34 @@ static struct sensor_device_attribute in_max[] = { SENSOR_ATTR(in10_max, S_IWUSR | S_IRUGO, show_in_max, set_in_max, 10), }; +static ssize_t show_vid(struct device *dev, struct device_attribute *attr, char *buf) +{ + struct pc87360_data *data = pc87360_update_device(dev); + return sprintf(buf, "%u\n", vid_from_reg(data->vid, data->vrm)); +} +static DEVICE_ATTR(cpu0_vid, S_IRUGO, show_vid, NULL); + +static ssize_t show_vrm(struct device *dev, struct device_attribute *attr, char *buf) +{ + struct pc87360_data *data = pc87360_update_device(dev); + return sprintf(buf, "%u\n", data->vrm); +} +static ssize_t set_vrm(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) +{ + struct i2c_client *client = to_i2c_client(dev); + struct pc87360_data *data = i2c_get_clientdata(client); + data->vrm = simple_strtoul(buf, NULL, 10); + return count; +} +static DEVICE_ATTR(vrm, S_IRUGO | S_IWUSR, show_vrm, set_vrm); + +static ssize_t show_in_alarms(struct device *dev, struct device_attribute *attr, char *buf) +{ + struct pc87360_data *data = pc87360_update_device(dev); + return sprintf(buf, "%u\n", data->in_alarms); +} +static DEVICE_ATTR(alarms_in, S_IRUGO, show_in_alarms, NULL); + static ssize_t show_therm_input(struct device *dev, struct device_attribute *devattr, char *buf) { struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); @@ -590,34 +618,6 @@ static struct sensor_device_attribute therm_crit[] = { show_therm_crit, set_therm_crit, 2+11), }; -static ssize_t show_vid(struct device *dev, struct device_attribute *attr, char *buf) -{ - struct pc87360_data *data = pc87360_update_device(dev); - return sprintf(buf, "%u\n", vid_from_reg(data->vid, data->vrm)); -} -static DEVICE_ATTR(cpu0_vid, S_IRUGO, show_vid, NULL); - -static ssize_t show_vrm(struct device *dev, struct device_attribute *attr, char *buf) -{ - struct pc87360_data *data = pc87360_update_device(dev); - return sprintf(buf, "%u\n", data->vrm); -} -static ssize_t set_vrm(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) -{ - struct i2c_client *client = to_i2c_client(dev); - struct pc87360_data *data = i2c_get_clientdata(client); - data->vrm = simple_strtoul(buf, NULL, 10); - return count; -} -static DEVICE_ATTR(vrm, S_IRUGO | S_IWUSR, show_vrm, set_vrm); - -static ssize_t show_in_alarms(struct device *dev, struct device_attribute *attr, char *buf) -{ - struct pc87360_data *data = pc87360_update_device(dev); - return sprintf(buf, "%u\n", data->in_alarms); -} -static DEVICE_ATTR(alarms_in, S_IRUGO, show_in_alarms, NULL); - static ssize_t show_temp_input(struct device *dev, struct device_attribute *devattr, char *buf) { struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); From 941c5c05cf38da5e12d70edc5d0fec5c24bce8b6 Mon Sep 17 00:00:00 2001 From: Jim Cromie Date: Sun, 24 Sep 2006 21:02:44 +0200 Subject: [PATCH 26/39] pc87360: Delete sysfs files on device deletion pc87360: Delete sysfs files on device deletion Add 4 explicit attribute groups for the 5 sensor types: voltage (in), therm, temp, and fan & pwm (together in one group). Use sysfs_remove_group() to drop them, but keeps the existing startup code, which calls device_create_file in loops. Signed-off-by: Jim Cromie Signed-off-by: Jean Delvare Signed-off-by: Greg Kroah-Hartman --- drivers/hwmon/pc87360.c | 87 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 87 insertions(+) diff --git a/drivers/hwmon/pc87360.c b/drivers/hwmon/pc87360.c index db543a8d78b0..ce3232c75ae1 100644 --- a/drivers/hwmon/pc87360.c +++ b/drivers/hwmon/pc87360.c @@ -328,6 +328,12 @@ static struct sensor_device_attribute fan_min[] = { SENSOR_ATTR(fan3_min, S_IWUSR | S_IRUGO, show_fan_min, set_fan_min, 2), }; +#define FAN_UNIT_ATTRS(X) \ + &fan_input[X].dev_attr.attr, \ + &fan_status[X].dev_attr.attr, \ + &fan_div[X].dev_attr.attr, \ + &fan_min[X].dev_attr.attr + static ssize_t show_pwm(struct device *dev, struct device_attribute *devattr, char *buf) { struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); @@ -360,6 +366,19 @@ static struct sensor_device_attribute pwm[] = { SENSOR_ATTR(pwm3, S_IWUSR | S_IRUGO, show_pwm, set_pwm, 2), }; +static struct attribute * pc8736x_fan_attr_array[] = { + FAN_UNIT_ATTRS(0), + FAN_UNIT_ATTRS(1), + FAN_UNIT_ATTRS(2), + &pwm[0].dev_attr.attr, + &pwm[1].dev_attr.attr, + &pwm[2].dev_attr.attr, + NULL +}; +static const struct attribute_group pc8736x_fan_group = { + .attrs = pc8736x_fan_attr_array, +}; + static ssize_t show_in_input(struct device *dev, struct device_attribute *devattr, char *buf) { struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); @@ -472,6 +491,12 @@ static struct sensor_device_attribute in_max[] = { SENSOR_ATTR(in10_max, S_IWUSR | S_IRUGO, show_in_max, set_in_max, 10), }; +#define VIN_UNIT_ATTRS(X) \ + &in_input[X].dev_attr.attr, \ + &in_status[X].dev_attr.attr, \ + &in_min[X].dev_attr.attr, \ + &in_max[X].dev_attr.attr + static ssize_t show_vid(struct device *dev, struct device_attribute *attr, char *buf) { struct pc87360_data *data = pc87360_update_device(dev); @@ -500,6 +525,27 @@ static ssize_t show_in_alarms(struct device *dev, struct device_attribute *attr, } static DEVICE_ATTR(alarms_in, S_IRUGO, show_in_alarms, NULL); +static struct attribute *pc8736x_vin_attr_array[] = { + VIN_UNIT_ATTRS(0), + VIN_UNIT_ATTRS(1), + VIN_UNIT_ATTRS(2), + VIN_UNIT_ATTRS(3), + VIN_UNIT_ATTRS(4), + VIN_UNIT_ATTRS(5), + VIN_UNIT_ATTRS(6), + VIN_UNIT_ATTRS(7), + VIN_UNIT_ATTRS(8), + VIN_UNIT_ATTRS(9), + VIN_UNIT_ATTRS(10), + &dev_attr_cpu0_vid.attr, + &dev_attr_vrm.attr, + &dev_attr_alarms_in.attr, + NULL +}; +static const struct attribute_group pc8736x_vin_group = { + .attrs = pc8736x_vin_attr_array, +}; + static ssize_t show_therm_input(struct device *dev, struct device_attribute *devattr, char *buf) { struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); @@ -618,6 +664,23 @@ static struct sensor_device_attribute therm_crit[] = { show_therm_crit, set_therm_crit, 2+11), }; +#define THERM_UNIT_ATTRS(X) \ + &therm_input[X].dev_attr.attr, \ + &therm_status[X].dev_attr.attr, \ + &therm_min[X].dev_attr.attr, \ + &therm_max[X].dev_attr.attr, \ + &therm_crit[X].dev_attr.attr + +static struct attribute * pc8736x_therm_attr_array[] = { + THERM_UNIT_ATTRS(0), + THERM_UNIT_ATTRS(1), + THERM_UNIT_ATTRS(2), + NULL +}; +static const struct attribute_group pc8736x_therm_group = { + .attrs = pc8736x_therm_attr_array, +}; + static ssize_t show_temp_input(struct device *dev, struct device_attribute *devattr, char *buf) { struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); @@ -736,6 +799,25 @@ static ssize_t show_temp_alarms(struct device *dev, struct device_attribute *att } static DEVICE_ATTR(alarms_temp, S_IRUGO, show_temp_alarms, NULL); +#define TEMP_UNIT_ATTRS(X) \ + &temp_input[X].dev_attr.attr, \ + &temp_status[X].dev_attr.attr, \ + &temp_min[X].dev_attr.attr, \ + &temp_max[X].dev_attr.attr, \ + &temp_crit[X].dev_attr.attr + +static struct attribute * pc8736x_temp_attr_array[] = { + TEMP_UNIT_ATTRS(0), + TEMP_UNIT_ATTRS(1), + TEMP_UNIT_ATTRS(2), + /* include the few miscellaneous atts here */ + &dev_attr_alarms_temp.attr, + NULL +}; +static const struct attribute_group pc8736x_temp_group = { + .attrs = pc8736x_temp_attr_array, +}; + /* * Device detection, registration and update */ @@ -1009,6 +1091,11 @@ static int pc87360_detach_client(struct i2c_client *client) hwmon_device_unregister(data->class_dev); + sysfs_remove_group(&client->dev.kobj, &pc8736x_temp_group); + sysfs_remove_group(&client->dev.kobj, &pc8736x_fan_group); + sysfs_remove_group(&client->dev.kobj, &pc8736x_therm_group); + sysfs_remove_group(&client->dev.kobj, &pc8736x_vin_group); + if ((i = i2c_detach_client(client))) return i; From f3722d5b6a474e31237d23980e9bd38facfda6f4 Mon Sep 17 00:00:00 2001 From: Jim Cromie Date: Sun, 24 Sep 2006 21:03:25 +0200 Subject: [PATCH 27/39] pc87360: Check for error on sysfs files creation pc87360: Check for error on sysfs files creation Use sysfs_create_group() for 2 sensor-types which are chip-model invariant, i.e. all-or-nothing attribute groups. Other 2 groups vary too much due to configuration, etc, so we keep the loops of device_create_file(), but now check their returns. Signed-off-by: Jim Cromie Signed-off-by: Jean Delvare Signed-off-by: Greg Kroah-Hartman --- drivers/hwmon/pc87360.c | 101 ++++++++++++++++++++++------------------ 1 file changed, 55 insertions(+), 46 deletions(-) diff --git a/drivers/hwmon/pc87360.c b/drivers/hwmon/pc87360.c index ce3232c75ae1..3b8b81984ad4 100644 --- a/drivers/hwmon/pc87360.c +++ b/drivers/hwmon/pc87360.c @@ -1018,60 +1018,69 @@ static int pc87360_detect(struct i2c_adapter *adapter) pc87360_init_client(client, use_thermistors); } - /* Register sysfs hooks */ + /* Register all-or-nothing sysfs groups */ + + if (data->innr && + (err = sysfs_create_group(&client->dev.kobj, + &pc8736x_vin_group))) + goto ERROR3; + + if (data->innr == 14 && + (err = sysfs_create_group(&client->dev.kobj, + &pc8736x_therm_group))) + goto ERROR3; + + /* create device attr-files for varying sysfs groups */ + + if (data->tempnr) { + for (i = 0; i < data->tempnr; i++) { + if ((err = device_create_file(dev, + &temp_input[i].dev_attr)) + || (err = device_create_file(dev, + &temp_min[i].dev_attr)) + || (err = device_create_file(dev, + &temp_max[i].dev_attr)) + || (err = device_create_file(dev, + &temp_crit[i].dev_attr)) + || (err = device_create_file(dev, + &temp_status[i].dev_attr))) + goto ERROR3; + } + if ((err = device_create_file(dev, &dev_attr_alarms_temp))) + goto ERROR3; + } + + for (i = 0; i < data->fannr; i++) { + if (FAN_CONFIG_MONITOR(data->fan_conf, i) + && ((err = device_create_file(dev, + &fan_input[i].dev_attr)) + || (err = device_create_file(dev, + &fan_min[i].dev_attr)) + || (err = device_create_file(dev, + &fan_div[i].dev_attr)) + || (err = device_create_file(dev, + &fan_status[i].dev_attr)))) + goto ERROR3; + + if (FAN_CONFIG_CONTROL(data->fan_conf, i) + && (err = device_create_file(dev, &pwm[i].dev_attr))) + goto ERROR3; + } + data->class_dev = hwmon_device_register(&client->dev); if (IS_ERR(data->class_dev)) { err = PTR_ERR(data->class_dev); goto ERROR3; } - - if (data->innr) { - for (i = 0; i < 11; i++) { - device_create_file(dev, &in_input[i].dev_attr); - device_create_file(dev, &in_min[i].dev_attr); - device_create_file(dev, &in_max[i].dev_attr); - device_create_file(dev, &in_status[i].dev_attr); - } - device_create_file(dev, &dev_attr_cpu0_vid); - device_create_file(dev, &dev_attr_vrm); - device_create_file(dev, &dev_attr_alarms_in); - } - - if (data->tempnr) { - for (i = 0; i < data->tempnr; i++) { - device_create_file(dev, &temp_input[i].dev_attr); - device_create_file(dev, &temp_min[i].dev_attr); - device_create_file(dev, &temp_max[i].dev_attr); - device_create_file(dev, &temp_crit[i].dev_attr); - device_create_file(dev, &temp_status[i].dev_attr); - } - device_create_file(dev, &dev_attr_alarms_temp); - } - - if (data->innr == 14) { - for (i = 0; i < 3; i++) { - device_create_file(dev, &therm_input[i].dev_attr); - device_create_file(dev, &therm_min[i].dev_attr); - device_create_file(dev, &therm_max[i].dev_attr); - device_create_file(dev, &therm_crit[i].dev_attr); - device_create_file(dev, &therm_status[i].dev_attr); - } - } - - for (i = 0; i < data->fannr; i++) { - if (FAN_CONFIG_MONITOR(data->fan_conf, i)) { - device_create_file(dev, &fan_input[i].dev_attr); - device_create_file(dev, &fan_min[i].dev_attr); - device_create_file(dev, &fan_div[i].dev_attr); - device_create_file(dev, &fan_status[i].dev_attr); - } - if (FAN_CONFIG_CONTROL(data->fan_conf, i)) - device_create_file(dev, &pwm[i].dev_attr); - } - return 0; ERROR3: + /* can still remove groups whose members were added individually */ + sysfs_remove_group(&client->dev.kobj, &pc8736x_temp_group); + sysfs_remove_group(&client->dev.kobj, &pc8736x_fan_group); + sysfs_remove_group(&client->dev.kobj, &pc8736x_therm_group); + sysfs_remove_group(&client->dev.kobj, &pc8736x_vin_group); + i2c_detach_client(client); ERROR2: for (i = 0; i < 3; i++) { From c18beb5b92b090cb424718a4f1771b1a9fad56de Mon Sep 17 00:00:00 2001 From: David Hubbard Date: Sun, 24 Sep 2006 21:04:38 +0200 Subject: [PATCH 28/39] w83627ehf: Fix unchecked return status w83627ehf: Fix unchecked return status Fix: check return value from device_create_file() Fix: call device_remove_file() on error and module unload Fix: call hwmon_device_register() after device_create_file() to eliminate race Signed-off-by: David Hubbard Signed-off-by: Jean Delvare Signed-off-by: Greg Kroah-Hartman --- drivers/hwmon/w83627ehf.c | 122 +++++++++++++++++++++++++------------- 1 file changed, 82 insertions(+), 40 deletions(-) diff --git a/drivers/hwmon/w83627ehf.c b/drivers/hwmon/w83627ehf.c index 23824183e02f..7a58b079d735 100644 --- a/drivers/hwmon/w83627ehf.c +++ b/drivers/hwmon/w83627ehf.c @@ -4,6 +4,7 @@ Copyright (C) 2005 Jean Delvare Copyright (C) 2006 Yuan Mu , Rudolf Marek + David Hubbard Shamelessly ripped from the w83627hf driver Copyright (C) 2003 Mark Studebaker @@ -621,14 +622,6 @@ static struct sensor_device_attribute sda_in_max[] = { SENSOR_ATTR(in9_max, S_IWUSR | S_IRUGO, show_in_max, store_in_max, 9), }; -static void device_create_file_in(struct device *dev, int i) -{ - device_create_file(dev, &sda_in_input[i].dev_attr); - device_create_file(dev, &sda_in_alarm[i].dev_attr); - device_create_file(dev, &sda_in_min[i].dev_attr); - device_create_file(dev, &sda_in_max[i].dev_attr); -} - #define show_fan_reg(reg) \ static ssize_t \ show_##reg(struct device *dev, struct device_attribute *attr, \ @@ -756,14 +749,6 @@ static struct sensor_device_attribute sda_fan_div[] = { SENSOR_ATTR(fan5_div, S_IRUGO, show_fan_div, NULL, 4), }; -static void device_create_file_fan(struct device *dev, int i) -{ - device_create_file(dev, &sda_fan_input[i].dev_attr); - device_create_file(dev, &sda_fan_alarm[i].dev_attr); - device_create_file(dev, &sda_fan_div[i].dev_attr); - device_create_file(dev, &sda_fan_min[i].dev_attr); -} - #define show_temp1_reg(reg) \ static ssize_t \ show_##reg(struct device *dev, struct device_attribute *attr, \ @@ -1036,15 +1021,6 @@ static struct sensor_device_attribute sda_tolerance[] = { store_tolerance, 3), }; -static void device_create_file_pwm(struct device *dev, int i) -{ - device_create_file(dev, &sda_pwm[i].dev_attr); - device_create_file(dev, &sda_pwm_mode[i].dev_attr); - device_create_file(dev, &sda_pwm_enable[i].dev_attr); - device_create_file(dev, &sda_target_temp[i].dev_attr); - device_create_file(dev, &sda_tolerance[i].dev_attr); -} - /* Smart Fan registers */ #define fan_functions(reg, REG) \ @@ -1131,6 +1107,39 @@ static struct sensor_device_attribute sda_sf3_arrays[] = { * Driver and client management */ +static void w83627ehf_device_remove_files(struct device *dev) +{ + /* some entries in the following arrays may not have been used in + * device_create_file(), but device_remove_file() will ignore them */ + int i; + + for (i = 0; i < ARRAY_SIZE(sda_sf3_arrays); i++) + device_remove_file(dev, &sda_sf3_arrays[i].dev_attr); + for (i = 0; i < ARRAY_SIZE(sda_sf3_arrays_fan4); i++) + device_remove_file(dev, &sda_sf3_arrays_fan4[i].dev_attr); + for (i = 0; i < 10; i++) { + device_remove_file(dev, &sda_in_input[i].dev_attr); + device_remove_file(dev, &sda_in_alarm[i].dev_attr); + device_remove_file(dev, &sda_in_min[i].dev_attr); + device_remove_file(dev, &sda_in_max[i].dev_attr); + } + for (i = 0; i < 5; i++) { + device_remove_file(dev, &sda_fan_input[i].dev_attr); + device_remove_file(dev, &sda_fan_alarm[i].dev_attr); + device_remove_file(dev, &sda_fan_div[i].dev_attr); + device_remove_file(dev, &sda_fan_min[i].dev_attr); + } + for (i = 0; i < 4; i++) { + device_remove_file(dev, &sda_pwm[i].dev_attr); + device_remove_file(dev, &sda_pwm_mode[i].dev_attr); + device_remove_file(dev, &sda_pwm_enable[i].dev_attr); + device_remove_file(dev, &sda_target_temp[i].dev_attr); + device_remove_file(dev, &sda_tolerance[i].dev_attr); + } + for (i = 0; i < ARRAY_SIZE(sda_temp); i++) + device_remove_file(dev, &sda_temp[i].dev_attr); +} + static struct i2c_driver w83627ehf_driver; static void w83627ehf_init_client(struct i2c_client *client) @@ -1217,37 +1226,69 @@ static int w83627ehf_detect(struct i2c_adapter *adapter) data->has_fan |= (1 << 4); /* Register sysfs hooks */ - data->class_dev = hwmon_device_register(dev); - if (IS_ERR(data->class_dev)) { - err = PTR_ERR(data->class_dev); - goto exit_detach; - } - for (i = 0; i < ARRAY_SIZE(sda_sf3_arrays); i++) - device_create_file(dev, &sda_sf3_arrays[i].dev_attr); + if ((err = device_create_file(dev, + &sda_sf3_arrays[i].dev_attr))) + goto exit_remove; /* if fan4 is enabled create the sf3 files for it */ if (data->has_fan & (1 << 3)) - for (i = 0; i < ARRAY_SIZE(sda_sf3_arrays_fan4); i++) - device_create_file(dev, &sda_sf3_arrays_fan4[i].dev_attr); + for (i = 0; i < ARRAY_SIZE(sda_sf3_arrays_fan4); i++) { + if ((err = device_create_file(dev, + &sda_sf3_arrays_fan4[i].dev_attr))) + goto exit_remove; + } for (i = 0; i < 10; i++) - device_create_file_in(dev, i); + if ((err = device_create_file(dev, &sda_in_input[i].dev_attr)) + || (err = device_create_file(dev, + &sda_in_alarm[i].dev_attr)) + || (err = device_create_file(dev, + &sda_in_min[i].dev_attr)) + || (err = device_create_file(dev, + &sda_in_max[i].dev_attr))) + goto exit_remove; for (i = 0; i < 5; i++) { if (data->has_fan & (1 << i)) { - device_create_file_fan(dev, i); - if (i != 4) /* we have only 4 pwm */ - device_create_file_pwm(dev, i); + if ((err = device_create_file(dev, + &sda_fan_input[i].dev_attr)) + || (err = device_create_file(dev, + &sda_fan_alarm[i].dev_attr)) + || (err = device_create_file(dev, + &sda_fan_div[i].dev_attr)) + || (err = device_create_file(dev, + &sda_fan_min[i].dev_attr))) + goto exit_remove; + if (i < 4 && /* w83627ehf only has 4 pwm */ + ((err = device_create_file(dev, + &sda_pwm[i].dev_attr)) + || (err = device_create_file(dev, + &sda_pwm_mode[i].dev_attr)) + || (err = device_create_file(dev, + &sda_pwm_enable[i].dev_attr)) + || (err = device_create_file(dev, + &sda_target_temp[i].dev_attr)) + || (err = device_create_file(dev, + &sda_tolerance[i].dev_attr)))) + goto exit_remove; } } for (i = 0; i < ARRAY_SIZE(sda_temp); i++) - device_create_file(dev, &sda_temp[i].dev_attr); + if ((err = device_create_file(dev, &sda_temp[i].dev_attr))) + goto exit_remove; + + data->class_dev = hwmon_device_register(dev); + if (IS_ERR(data->class_dev)) { + err = PTR_ERR(data->class_dev); + goto exit_remove; + } return 0; -exit_detach: +exit_remove: + w83627ehf_device_remove_files(dev); i2c_detach_client(client); exit_free: kfree(data); @@ -1263,6 +1304,7 @@ static int w83627ehf_detach_client(struct i2c_client *client) int err; hwmon_device_unregister(data->class_dev); + w83627ehf_device_remove_files(&client->dev); if ((err = i2c_detach_client(client))) return err; From 0501a3816e5b778830fc2157a6d6bb11a965fc2c Mon Sep 17 00:00:00 2001 From: "Mark M. Hoffman" Date: Sun, 24 Sep 2006 21:14:35 +0200 Subject: [PATCH 29/39] hwmon: Fix unchecked return status, batch 2 hwmon: Fix unchecked return status, batch 2 Fix up some hwmon drivers so that they no longer ignore return status from device_create_file(). Signed-off-by: Mark M. Hoffman Signed-off-by: Jean Delvare Signed-off-by: Greg Kroah-Hartman --- drivers/hwmon/lm77.c | 33 ++++++-- drivers/hwmon/lm80.c | 85 +++++++++++-------- drivers/hwmon/lm85.c | 173 ++++++++++++++++++++++---------------- drivers/hwmon/lm87.c | 195 +++++++++++++++++++++++++++++++------------ drivers/hwmon/lm92.c | 34 +++++--- 5 files changed, 340 insertions(+), 180 deletions(-) diff --git a/drivers/hwmon/lm77.c b/drivers/hwmon/lm77.c index 459cc977380a..dd969f1e8415 100644 --- a/drivers/hwmon/lm77.c +++ b/drivers/hwmon/lm77.c @@ -212,6 +212,23 @@ static int lm77_attach_adapter(struct i2c_adapter *adapter) return i2c_probe(adapter, &addr_data, lm77_detect); } +static struct attribute *lm77_attributes[] = { + &dev_attr_temp1_input.attr, + &dev_attr_temp1_crit.attr, + &dev_attr_temp1_min.attr, + &dev_attr_temp1_max.attr, + &dev_attr_temp1_crit_hyst.attr, + &dev_attr_temp1_min_hyst.attr, + &dev_attr_temp1_max_hyst.attr, + &dev_attr_alarms.attr, + + NULL +}; + +static const struct attribute_group lm77_group = { + .attrs = lm77_attributes, +}; + /* This function is called by i2c_probe */ static int lm77_detect(struct i2c_adapter *adapter, int address, int kind) { @@ -317,22 +334,19 @@ static int lm77_detect(struct i2c_adapter *adapter, int address, int kind) lm77_init_client(new_client); /* Register sysfs hooks */ + if ((err = sysfs_create_group(&new_client->dev.kobj, &lm77_group))) + goto exit_detach; + data->class_dev = hwmon_device_register(&new_client->dev); if (IS_ERR(data->class_dev)) { err = PTR_ERR(data->class_dev); - goto exit_detach; + goto exit_remove; } - device_create_file(&new_client->dev, &dev_attr_temp1_input); - device_create_file(&new_client->dev, &dev_attr_temp1_crit); - device_create_file(&new_client->dev, &dev_attr_temp1_min); - device_create_file(&new_client->dev, &dev_attr_temp1_max); - device_create_file(&new_client->dev, &dev_attr_temp1_crit_hyst); - device_create_file(&new_client->dev, &dev_attr_temp1_min_hyst); - device_create_file(&new_client->dev, &dev_attr_temp1_max_hyst); - device_create_file(&new_client->dev, &dev_attr_alarms); return 0; +exit_remove: + sysfs_remove_group(&new_client->dev.kobj, &lm77_group); exit_detach: i2c_detach_client(new_client); exit_free: @@ -345,6 +359,7 @@ static int lm77_detach_client(struct i2c_client *client) { struct lm77_data *data = i2c_get_clientdata(client); hwmon_device_unregister(data->class_dev); + sysfs_remove_group(&client->dev.kobj, &lm77_group); i2c_detach_client(client); kfree(data); return 0; diff --git a/drivers/hwmon/lm80.c b/drivers/hwmon/lm80.c index b4ccdfc01203..064516d824ad 100644 --- a/drivers/hwmon/lm80.c +++ b/drivers/hwmon/lm80.c @@ -394,6 +394,48 @@ static int lm80_attach_adapter(struct i2c_adapter *adapter) return i2c_probe(adapter, &addr_data, lm80_detect); } +static struct attribute *lm80_attributes[] = { + &dev_attr_in0_min.attr, + &dev_attr_in1_min.attr, + &dev_attr_in2_min.attr, + &dev_attr_in3_min.attr, + &dev_attr_in4_min.attr, + &dev_attr_in5_min.attr, + &dev_attr_in6_min.attr, + &dev_attr_in0_max.attr, + &dev_attr_in1_max.attr, + &dev_attr_in2_max.attr, + &dev_attr_in3_max.attr, + &dev_attr_in4_max.attr, + &dev_attr_in5_max.attr, + &dev_attr_in6_max.attr, + &dev_attr_in0_input.attr, + &dev_attr_in1_input.attr, + &dev_attr_in2_input.attr, + &dev_attr_in3_input.attr, + &dev_attr_in4_input.attr, + &dev_attr_in5_input.attr, + &dev_attr_in6_input.attr, + &dev_attr_fan1_min.attr, + &dev_attr_fan2_min.attr, + &dev_attr_fan1_input.attr, + &dev_attr_fan2_input.attr, + &dev_attr_fan1_div.attr, + &dev_attr_fan2_div.attr, + &dev_attr_temp1_input.attr, + &dev_attr_temp1_max.attr, + &dev_attr_temp1_max_hyst.attr, + &dev_attr_temp1_crit.attr, + &dev_attr_temp1_crit_hyst.attr, + &dev_attr_alarms.attr, + + NULL +}; + +static const struct attribute_group lm80_group = { + .attrs = lm80_attributes, +}; + static int lm80_detect(struct i2c_adapter *adapter, int address, int kind) { int i, cur; @@ -452,48 +494,19 @@ static int lm80_detect(struct i2c_adapter *adapter, int address, int kind) data->fan_min[1] = lm80_read_value(new_client, LM80_REG_FAN_MIN(2)); /* Register sysfs hooks */ + if ((err = sysfs_create_group(&new_client->dev.kobj, &lm80_group))) + goto error_detach; + data->class_dev = hwmon_device_register(&new_client->dev); if (IS_ERR(data->class_dev)) { err = PTR_ERR(data->class_dev); - goto error_detach; + goto error_remove; } - device_create_file(&new_client->dev, &dev_attr_in0_min); - device_create_file(&new_client->dev, &dev_attr_in1_min); - device_create_file(&new_client->dev, &dev_attr_in2_min); - device_create_file(&new_client->dev, &dev_attr_in3_min); - device_create_file(&new_client->dev, &dev_attr_in4_min); - device_create_file(&new_client->dev, &dev_attr_in5_min); - device_create_file(&new_client->dev, &dev_attr_in6_min); - device_create_file(&new_client->dev, &dev_attr_in0_max); - device_create_file(&new_client->dev, &dev_attr_in1_max); - device_create_file(&new_client->dev, &dev_attr_in2_max); - device_create_file(&new_client->dev, &dev_attr_in3_max); - device_create_file(&new_client->dev, &dev_attr_in4_max); - device_create_file(&new_client->dev, &dev_attr_in5_max); - device_create_file(&new_client->dev, &dev_attr_in6_max); - device_create_file(&new_client->dev, &dev_attr_in0_input); - device_create_file(&new_client->dev, &dev_attr_in1_input); - device_create_file(&new_client->dev, &dev_attr_in2_input); - device_create_file(&new_client->dev, &dev_attr_in3_input); - device_create_file(&new_client->dev, &dev_attr_in4_input); - device_create_file(&new_client->dev, &dev_attr_in5_input); - device_create_file(&new_client->dev, &dev_attr_in6_input); - device_create_file(&new_client->dev, &dev_attr_fan1_min); - device_create_file(&new_client->dev, &dev_attr_fan2_min); - device_create_file(&new_client->dev, &dev_attr_fan1_input); - device_create_file(&new_client->dev, &dev_attr_fan2_input); - device_create_file(&new_client->dev, &dev_attr_fan1_div); - device_create_file(&new_client->dev, &dev_attr_fan2_div); - device_create_file(&new_client->dev, &dev_attr_temp1_input); - device_create_file(&new_client->dev, &dev_attr_temp1_max); - device_create_file(&new_client->dev, &dev_attr_temp1_max_hyst); - device_create_file(&new_client->dev, &dev_attr_temp1_crit); - device_create_file(&new_client->dev, &dev_attr_temp1_crit_hyst); - device_create_file(&new_client->dev, &dev_attr_alarms); - return 0; +error_remove: + sysfs_remove_group(&new_client->dev.kobj, &lm80_group); error_detach: i2c_detach_client(new_client); error_free: @@ -508,7 +521,7 @@ static int lm80_detach_client(struct i2c_client *client) int err; hwmon_device_unregister(data->class_dev); - + sysfs_remove_group(&client->dev.kobj, &lm80_group); if ((err = i2c_detach_client(client))) return err; diff --git a/drivers/hwmon/lm85.c b/drivers/hwmon/lm85.c index 342e9663119d..2c3293cf69d1 100644 --- a/drivers/hwmon/lm85.c +++ b/drivers/hwmon/lm85.c @@ -1025,6 +1025,89 @@ static int lm85_attach_adapter(struct i2c_adapter *adapter) return i2c_probe(adapter, &addr_data, lm85_detect); } +static struct attribute *lm85_attributes[] = { + &dev_attr_fan1_input.attr, + &dev_attr_fan2_input.attr, + &dev_attr_fan3_input.attr, + &dev_attr_fan4_input.attr, + &dev_attr_fan1_min.attr, + &dev_attr_fan2_min.attr, + &dev_attr_fan3_min.attr, + &dev_attr_fan4_min.attr, + &dev_attr_pwm1.attr, + &dev_attr_pwm2.attr, + &dev_attr_pwm3.attr, + &dev_attr_pwm1_enable.attr, + &dev_attr_pwm2_enable.attr, + &dev_attr_pwm3_enable.attr, + &dev_attr_in0_input.attr, + &dev_attr_in1_input.attr, + &dev_attr_in2_input.attr, + &dev_attr_in3_input.attr, + &dev_attr_in0_min.attr, + &dev_attr_in1_min.attr, + &dev_attr_in2_min.attr, + &dev_attr_in3_min.attr, + &dev_attr_in0_max.attr, + &dev_attr_in1_max.attr, + &dev_attr_in2_max.attr, + &dev_attr_in3_max.attr, + &dev_attr_temp1_input.attr, + &dev_attr_temp2_input.attr, + &dev_attr_temp3_input.attr, + &dev_attr_temp1_min.attr, + &dev_attr_temp2_min.attr, + &dev_attr_temp3_min.attr, + &dev_attr_temp1_max.attr, + &dev_attr_temp2_max.attr, + &dev_attr_temp3_max.attr, + &dev_attr_vrm.attr, + &dev_attr_cpu0_vid.attr, + &dev_attr_alarms.attr, + &dev_attr_pwm1_auto_channels.attr, + &dev_attr_pwm2_auto_channels.attr, + &dev_attr_pwm3_auto_channels.attr, + &dev_attr_pwm1_auto_pwm_min.attr, + &dev_attr_pwm2_auto_pwm_min.attr, + &dev_attr_pwm3_auto_pwm_min.attr, + &dev_attr_pwm1_auto_pwm_minctl.attr, + &dev_attr_pwm2_auto_pwm_minctl.attr, + &dev_attr_pwm3_auto_pwm_minctl.attr, + &dev_attr_pwm1_auto_pwm_freq.attr, + &dev_attr_pwm2_auto_pwm_freq.attr, + &dev_attr_pwm3_auto_pwm_freq.attr, + &dev_attr_temp1_auto_temp_off.attr, + &dev_attr_temp2_auto_temp_off.attr, + &dev_attr_temp3_auto_temp_off.attr, + &dev_attr_temp1_auto_temp_min.attr, + &dev_attr_temp2_auto_temp_min.attr, + &dev_attr_temp3_auto_temp_min.attr, + &dev_attr_temp1_auto_temp_max.attr, + &dev_attr_temp2_auto_temp_max.attr, + &dev_attr_temp3_auto_temp_max.attr, + &dev_attr_temp1_auto_temp_crit.attr, + &dev_attr_temp2_auto_temp_crit.attr, + &dev_attr_temp3_auto_temp_crit.attr, + + NULL +}; + +static const struct attribute_group lm85_group = { + .attrs = lm85_attributes, +}; + +static struct attribute *lm85_attributes_opt[] = { + &dev_attr_in4_input.attr, + &dev_attr_in4_min.attr, + &dev_attr_in4_max.attr, + + NULL +}; + +static const struct attribute_group lm85_group_opt = { + .attrs = lm85_attributes_opt, +}; + static int lm85_detect(struct i2c_adapter *adapter, int address, int kind) { @@ -1163,87 +1246,33 @@ static int lm85_detect(struct i2c_adapter *adapter, int address, lm85_init_client(new_client); /* Register sysfs hooks */ - data->class_dev = hwmon_device_register(&new_client->dev); - if (IS_ERR(data->class_dev)) { - err = PTR_ERR(data->class_dev); + if ((err = sysfs_create_group(&new_client->dev.kobj, &lm85_group))) goto ERROR2; - } - - device_create_file(&new_client->dev, &dev_attr_fan1_input); - device_create_file(&new_client->dev, &dev_attr_fan2_input); - device_create_file(&new_client->dev, &dev_attr_fan3_input); - device_create_file(&new_client->dev, &dev_attr_fan4_input); - device_create_file(&new_client->dev, &dev_attr_fan1_min); - device_create_file(&new_client->dev, &dev_attr_fan2_min); - device_create_file(&new_client->dev, &dev_attr_fan3_min); - device_create_file(&new_client->dev, &dev_attr_fan4_min); - device_create_file(&new_client->dev, &dev_attr_pwm1); - device_create_file(&new_client->dev, &dev_attr_pwm2); - device_create_file(&new_client->dev, &dev_attr_pwm3); - device_create_file(&new_client->dev, &dev_attr_pwm1_enable); - device_create_file(&new_client->dev, &dev_attr_pwm2_enable); - device_create_file(&new_client->dev, &dev_attr_pwm3_enable); - device_create_file(&new_client->dev, &dev_attr_in0_input); - device_create_file(&new_client->dev, &dev_attr_in1_input); - device_create_file(&new_client->dev, &dev_attr_in2_input); - device_create_file(&new_client->dev, &dev_attr_in3_input); - device_create_file(&new_client->dev, &dev_attr_in0_min); - device_create_file(&new_client->dev, &dev_attr_in1_min); - device_create_file(&new_client->dev, &dev_attr_in2_min); - device_create_file(&new_client->dev, &dev_attr_in3_min); - device_create_file(&new_client->dev, &dev_attr_in0_max); - device_create_file(&new_client->dev, &dev_attr_in1_max); - device_create_file(&new_client->dev, &dev_attr_in2_max); - device_create_file(&new_client->dev, &dev_attr_in3_max); - device_create_file(&new_client->dev, &dev_attr_temp1_input); - device_create_file(&new_client->dev, &dev_attr_temp2_input); - device_create_file(&new_client->dev, &dev_attr_temp3_input); - device_create_file(&new_client->dev, &dev_attr_temp1_min); - device_create_file(&new_client->dev, &dev_attr_temp2_min); - device_create_file(&new_client->dev, &dev_attr_temp3_min); - device_create_file(&new_client->dev, &dev_attr_temp1_max); - device_create_file(&new_client->dev, &dev_attr_temp2_max); - device_create_file(&new_client->dev, &dev_attr_temp3_max); - device_create_file(&new_client->dev, &dev_attr_vrm); - device_create_file(&new_client->dev, &dev_attr_cpu0_vid); - device_create_file(&new_client->dev, &dev_attr_alarms); - device_create_file(&new_client->dev, &dev_attr_pwm1_auto_channels); - device_create_file(&new_client->dev, &dev_attr_pwm2_auto_channels); - device_create_file(&new_client->dev, &dev_attr_pwm3_auto_channels); - device_create_file(&new_client->dev, &dev_attr_pwm1_auto_pwm_min); - device_create_file(&new_client->dev, &dev_attr_pwm2_auto_pwm_min); - device_create_file(&new_client->dev, &dev_attr_pwm3_auto_pwm_min); - device_create_file(&new_client->dev, &dev_attr_pwm1_auto_pwm_minctl); - device_create_file(&new_client->dev, &dev_attr_pwm2_auto_pwm_minctl); - device_create_file(&new_client->dev, &dev_attr_pwm3_auto_pwm_minctl); - device_create_file(&new_client->dev, &dev_attr_pwm1_auto_pwm_freq); - device_create_file(&new_client->dev, &dev_attr_pwm2_auto_pwm_freq); - device_create_file(&new_client->dev, &dev_attr_pwm3_auto_pwm_freq); - device_create_file(&new_client->dev, &dev_attr_temp1_auto_temp_off); - device_create_file(&new_client->dev, &dev_attr_temp2_auto_temp_off); - device_create_file(&new_client->dev, &dev_attr_temp3_auto_temp_off); - device_create_file(&new_client->dev, &dev_attr_temp1_auto_temp_min); - device_create_file(&new_client->dev, &dev_attr_temp2_auto_temp_min); - device_create_file(&new_client->dev, &dev_attr_temp3_auto_temp_min); - device_create_file(&new_client->dev, &dev_attr_temp1_auto_temp_max); - device_create_file(&new_client->dev, &dev_attr_temp2_auto_temp_max); - device_create_file(&new_client->dev, &dev_attr_temp3_auto_temp_max); - device_create_file(&new_client->dev, &dev_attr_temp1_auto_temp_crit); - device_create_file(&new_client->dev, &dev_attr_temp2_auto_temp_crit); - device_create_file(&new_client->dev, &dev_attr_temp3_auto_temp_crit); /* The ADT7463 has an optional VRM 10 mode where pin 21 is used as a sixth digital VID input rather than an analog input. */ data->vid = lm85_read_value(new_client, LM85_REG_VID); - if (!(kind == adt7463 && (data->vid & 0x80))) { - device_create_file(&new_client->dev, &dev_attr_in4_input); - device_create_file(&new_client->dev, &dev_attr_in4_min); - device_create_file(&new_client->dev, &dev_attr_in4_max); + if (!(kind == adt7463 && (data->vid & 0x80))) + if ((err = device_create_file(&new_client->dev, + &dev_attr_in4_input)) + || (err = device_create_file(&new_client->dev, + &dev_attr_in4_min)) + || (err = device_create_file(&new_client->dev, + &dev_attr_in4_max))) + goto ERROR3; + + data->class_dev = hwmon_device_register(&new_client->dev); + if (IS_ERR(data->class_dev)) { + err = PTR_ERR(data->class_dev); + goto ERROR3; } return 0; /* Error out and cleanup code */ + ERROR3: + sysfs_remove_group(&new_client->dev.kobj, &lm85_group); + sysfs_remove_group(&new_client->dev.kobj, &lm85_group_opt); ERROR2: i2c_detach_client(new_client); ERROR1: @@ -1256,6 +1285,8 @@ static int lm85_detach_client(struct i2c_client *client) { struct lm85_data *data = i2c_get_clientdata(client); hwmon_device_unregister(data->class_dev); + sysfs_remove_group(&client->dev.kobj, &lm85_group); + sysfs_remove_group(&client->dev.kobj, &lm85_group_opt); i2c_detach_client(client); kfree(data); return 0; diff --git a/drivers/hwmon/lm87.c b/drivers/hwmon/lm87.c index e6c1b638c971..3ce825489e34 100644 --- a/drivers/hwmon/lm87.c +++ b/drivers/hwmon/lm87.c @@ -542,6 +542,78 @@ static int lm87_attach_adapter(struct i2c_adapter *adapter) return i2c_probe(adapter, &addr_data, lm87_detect); } +static struct attribute *lm87_attributes[] = { + &dev_attr_in1_input.attr, + &dev_attr_in1_min.attr, + &dev_attr_in1_max.attr, + &dev_attr_in2_input.attr, + &dev_attr_in2_min.attr, + &dev_attr_in2_max.attr, + &dev_attr_in3_input.attr, + &dev_attr_in3_min.attr, + &dev_attr_in3_max.attr, + &dev_attr_in4_input.attr, + &dev_attr_in4_min.attr, + &dev_attr_in4_max.attr, + + &dev_attr_temp1_input.attr, + &dev_attr_temp1_max.attr, + &dev_attr_temp1_min.attr, + &dev_attr_temp1_crit.attr, + &dev_attr_temp2_input.attr, + &dev_attr_temp2_max.attr, + &dev_attr_temp2_min.attr, + &dev_attr_temp2_crit.attr, + + &dev_attr_alarms.attr, + &dev_attr_aout_output.attr, + + NULL +}; + +static const struct attribute_group lm87_group = { + .attrs = lm87_attributes, +}; + +static struct attribute *lm87_attributes_opt[] = { + &dev_attr_in6_input.attr, + &dev_attr_in6_min.attr, + &dev_attr_in6_max.attr, + + &dev_attr_fan1_input.attr, + &dev_attr_fan1_min.attr, + &dev_attr_fan1_div.attr, + + &dev_attr_in7_input.attr, + &dev_attr_in7_min.attr, + &dev_attr_in7_max.attr, + + &dev_attr_fan2_input.attr, + &dev_attr_fan2_min.attr, + &dev_attr_fan2_div.attr, + + &dev_attr_temp3_input.attr, + &dev_attr_temp3_max.attr, + &dev_attr_temp3_min.attr, + &dev_attr_temp3_crit.attr, + + &dev_attr_in0_input.attr, + &dev_attr_in0_min.attr, + &dev_attr_in0_max.attr, + &dev_attr_in5_input.attr, + &dev_attr_in5_min.attr, + &dev_attr_in5_max.attr, + + &dev_attr_cpu0_vid.attr, + &dev_attr_vrm.attr, + + NULL +}; + +static const struct attribute_group lm87_group_opt = { + .attrs = lm87_attributes_opt, +}; + /* * The following function does more than just detection. If detection * succeeds, it also registers the new chip. @@ -609,77 +681,90 @@ static int lm87_detect(struct i2c_adapter *adapter, int address, int kind) data->in_scale[7] = 1875; /* Register sysfs hooks */ - data->class_dev = hwmon_device_register(&new_client->dev); - if (IS_ERR(data->class_dev)) { - err = PTR_ERR(data->class_dev); + if ((err = sysfs_create_group(&new_client->dev.kobj, &lm87_group))) goto exit_detach; - } - - device_create_file(&new_client->dev, &dev_attr_in1_input); - device_create_file(&new_client->dev, &dev_attr_in1_min); - device_create_file(&new_client->dev, &dev_attr_in1_max); - device_create_file(&new_client->dev, &dev_attr_in2_input); - device_create_file(&new_client->dev, &dev_attr_in2_min); - device_create_file(&new_client->dev, &dev_attr_in2_max); - device_create_file(&new_client->dev, &dev_attr_in3_input); - device_create_file(&new_client->dev, &dev_attr_in3_min); - device_create_file(&new_client->dev, &dev_attr_in3_max); - device_create_file(&new_client->dev, &dev_attr_in4_input); - device_create_file(&new_client->dev, &dev_attr_in4_min); - device_create_file(&new_client->dev, &dev_attr_in4_max); if (data->channel & CHAN_NO_FAN(0)) { - device_create_file(&new_client->dev, &dev_attr_in6_input); - device_create_file(&new_client->dev, &dev_attr_in6_min); - device_create_file(&new_client->dev, &dev_attr_in6_max); + if ((err = device_create_file(&new_client->dev, + &dev_attr_in6_input)) + || (err = device_create_file(&new_client->dev, + &dev_attr_in6_min)) + || (err = device_create_file(&new_client->dev, + &dev_attr_in6_max))) + goto exit_remove; } else { - device_create_file(&new_client->dev, &dev_attr_fan1_input); - device_create_file(&new_client->dev, &dev_attr_fan1_min); - device_create_file(&new_client->dev, &dev_attr_fan1_div); - } - if (data->channel & CHAN_NO_FAN(1)) { - device_create_file(&new_client->dev, &dev_attr_in7_input); - device_create_file(&new_client->dev, &dev_attr_in7_min); - device_create_file(&new_client->dev, &dev_attr_in7_max); - } else { - device_create_file(&new_client->dev, &dev_attr_fan2_input); - device_create_file(&new_client->dev, &dev_attr_fan2_min); - device_create_file(&new_client->dev, &dev_attr_fan2_div); + if ((err = device_create_file(&new_client->dev, + &dev_attr_fan1_input)) + || (err = device_create_file(&new_client->dev, + &dev_attr_fan1_min)) + || (err = device_create_file(&new_client->dev, + &dev_attr_fan1_div))) + goto exit_remove; } - device_create_file(&new_client->dev, &dev_attr_temp1_input); - device_create_file(&new_client->dev, &dev_attr_temp1_max); - device_create_file(&new_client->dev, &dev_attr_temp1_min); - device_create_file(&new_client->dev, &dev_attr_temp1_crit); - device_create_file(&new_client->dev, &dev_attr_temp2_input); - device_create_file(&new_client->dev, &dev_attr_temp2_max); - device_create_file(&new_client->dev, &dev_attr_temp2_min); - device_create_file(&new_client->dev, &dev_attr_temp2_crit); + if (data->channel & CHAN_NO_FAN(1)) { + if ((err = device_create_file(&new_client->dev, + &dev_attr_in7_input)) + || (err = device_create_file(&new_client->dev, + &dev_attr_in7_min)) + || (err = device_create_file(&new_client->dev, + &dev_attr_in7_max))) + goto exit_remove; + } else { + if ((err = device_create_file(&new_client->dev, + &dev_attr_fan2_input)) + || (err = device_create_file(&new_client->dev, + &dev_attr_fan2_min)) + || (err = device_create_file(&new_client->dev, + &dev_attr_fan2_div))) + goto exit_remove; + } if (data->channel & CHAN_TEMP3) { - device_create_file(&new_client->dev, &dev_attr_temp3_input); - device_create_file(&new_client->dev, &dev_attr_temp3_max); - device_create_file(&new_client->dev, &dev_attr_temp3_min); - device_create_file(&new_client->dev, &dev_attr_temp3_crit); + if ((err = device_create_file(&new_client->dev, + &dev_attr_temp3_input)) + || (err = device_create_file(&new_client->dev, + &dev_attr_temp3_max)) + || (err = device_create_file(&new_client->dev, + &dev_attr_temp3_min)) + || (err = device_create_file(&new_client->dev, + &dev_attr_temp3_crit))) + goto exit_remove; } else { - device_create_file(&new_client->dev, &dev_attr_in0_input); - device_create_file(&new_client->dev, &dev_attr_in0_min); - device_create_file(&new_client->dev, &dev_attr_in0_max); - device_create_file(&new_client->dev, &dev_attr_in5_input); - device_create_file(&new_client->dev, &dev_attr_in5_min); - device_create_file(&new_client->dev, &dev_attr_in5_max); + if ((err = device_create_file(&new_client->dev, + &dev_attr_in0_input)) + || (err = device_create_file(&new_client->dev, + &dev_attr_in0_min)) + || (err = device_create_file(&new_client->dev, + &dev_attr_in0_max)) + || (err = device_create_file(&new_client->dev, + &dev_attr_in5_input)) + || (err = device_create_file(&new_client->dev, + &dev_attr_in5_min)) + || (err = device_create_file(&new_client->dev, + &dev_attr_in5_max))) + goto exit_remove; } if (!(data->channel & CHAN_NO_VID)) { - device_create_file(&new_client->dev, &dev_attr_cpu0_vid); - device_create_file(&new_client->dev, &dev_attr_vrm); + if ((err = device_create_file(&new_client->dev, + &dev_attr_cpu0_vid)) + || (err = device_create_file(&new_client->dev, + &dev_attr_vrm))) + goto exit_remove; } - device_create_file(&new_client->dev, &dev_attr_alarms); - device_create_file(&new_client->dev, &dev_attr_aout_output); + data->class_dev = hwmon_device_register(&new_client->dev); + if (IS_ERR(data->class_dev)) { + err = PTR_ERR(data->class_dev); + goto exit_remove; + } return 0; +exit_remove: + sysfs_remove_group(&new_client->dev.kobj, &lm87_group); + sysfs_remove_group(&new_client->dev.kobj, &lm87_group_opt); exit_detach: i2c_detach_client(new_client); exit_free: @@ -732,6 +817,8 @@ static int lm87_detach_client(struct i2c_client *client) int err; hwmon_device_unregister(data->class_dev); + sysfs_remove_group(&client->dev.kobj, &lm87_group); + sysfs_remove_group(&client->dev.kobj, &lm87_group_opt); if ((err = i2c_detach_client(client))) return err; diff --git a/drivers/hwmon/lm92.c b/drivers/hwmon/lm92.c index 197f77226dc4..30b536333f14 100644 --- a/drivers/hwmon/lm92.c +++ b/drivers/hwmon/lm92.c @@ -288,6 +288,23 @@ static int max6635_check(struct i2c_client *client) return 1; } +static struct attribute *lm92_attributes[] = { + &dev_attr_temp1_input.attr, + &dev_attr_temp1_crit.attr, + &dev_attr_temp1_crit_hyst.attr, + &dev_attr_temp1_min.attr, + &dev_attr_temp1_min_hyst.attr, + &dev_attr_temp1_max.attr, + &dev_attr_temp1_max_hyst.attr, + &dev_attr_alarms.attr, + + NULL +}; + +static const struct attribute_group lm92_group = { + .attrs = lm92_attributes, +}; + /* The following function does more than just detection. If detection succeeds, it also registers the new chip. */ static int lm92_detect(struct i2c_adapter *adapter, int address, int kind) @@ -359,23 +376,19 @@ static int lm92_detect(struct i2c_adapter *adapter, int address, int kind) lm92_init_client(new_client); /* Register sysfs hooks */ + if ((err = sysfs_create_group(&new_client->dev.kobj, &lm92_group))) + goto exit_detach; + data->class_dev = hwmon_device_register(&new_client->dev); if (IS_ERR(data->class_dev)) { err = PTR_ERR(data->class_dev); - goto exit_detach; + goto exit_remove; } - device_create_file(&new_client->dev, &dev_attr_temp1_input); - device_create_file(&new_client->dev, &dev_attr_temp1_crit); - device_create_file(&new_client->dev, &dev_attr_temp1_crit_hyst); - device_create_file(&new_client->dev, &dev_attr_temp1_min); - device_create_file(&new_client->dev, &dev_attr_temp1_min_hyst); - device_create_file(&new_client->dev, &dev_attr_temp1_max); - device_create_file(&new_client->dev, &dev_attr_temp1_max_hyst); - device_create_file(&new_client->dev, &dev_attr_alarms); - return 0; +exit_remove: + sysfs_remove_group(&new_client->dev.kobj, &lm92_group); exit_detach: i2c_detach_client(new_client); exit_free: @@ -397,6 +410,7 @@ static int lm92_detach_client(struct i2c_client *client) int err; hwmon_device_unregister(data->class_dev); + sysfs_remove_group(&client->dev.kobj, &lm92_group); if ((err = i2c_detach_client(client))) return err; From 681c6f7a6702f208d48b501c8829dbc03a2ca238 Mon Sep 17 00:00:00 2001 From: "Mark M. Hoffman" Date: Sun, 24 Sep 2006 21:15:35 +0200 Subject: [PATCH 30/39] hwmon: Fix unchecked return status, batch 3 hwmon: Fix unchecked return status, batch 3 Fix up some hwmon drivers so that they no longer ignore return status from device_create_file(). Signed-off-by: Mark M. Hoffman Signed-off-by: Jean Delvare Signed-off-by: Greg Kroah-Hartman --- drivers/hwmon/adm1021.c | 31 +++-- drivers/hwmon/adm1025.c | 94 ++++++++----- drivers/hwmon/adm1026.c | 286 ++++++++++++++++++++-------------------- drivers/hwmon/adm1031.c | 114 +++++++++------- drivers/hwmon/adm9240.c | 105 +++++++-------- 5 files changed, 346 insertions(+), 284 deletions(-) diff --git a/drivers/hwmon/adm1021.c b/drivers/hwmon/adm1021.c index 2b6e74dd4a82..c466329b2ef4 100644 --- a/drivers/hwmon/adm1021.c +++ b/drivers/hwmon/adm1021.c @@ -190,6 +190,21 @@ static int adm1021_attach_adapter(struct i2c_adapter *adapter) return i2c_probe(adapter, &addr_data, adm1021_detect); } +static struct attribute *adm1021_attributes[] = { + &dev_attr_temp1_max.attr, + &dev_attr_temp1_min.attr, + &dev_attr_temp1_input.attr, + &dev_attr_temp2_max.attr, + &dev_attr_temp2_min.attr, + &dev_attr_temp2_input.attr, + &dev_attr_alarms.attr, + NULL +}; + +static const struct attribute_group adm1021_group = { + .attrs = adm1021_attributes, +}; + static int adm1021_detect(struct i2c_adapter *adapter, int address, int kind) { int i; @@ -287,22 +302,19 @@ static int adm1021_detect(struct i2c_adapter *adapter, int address, int kind) adm1021_init_client(new_client); /* Register sysfs hooks */ + if ((err = sysfs_create_group(&new_client->dev.kobj, &adm1021_group))) + goto error2; + data->class_dev = hwmon_device_register(&new_client->dev); if (IS_ERR(data->class_dev)) { err = PTR_ERR(data->class_dev); - goto error2; + goto error3; } - device_create_file(&new_client->dev, &dev_attr_temp1_max); - device_create_file(&new_client->dev, &dev_attr_temp1_min); - device_create_file(&new_client->dev, &dev_attr_temp1_input); - device_create_file(&new_client->dev, &dev_attr_temp2_max); - device_create_file(&new_client->dev, &dev_attr_temp2_min); - device_create_file(&new_client->dev, &dev_attr_temp2_input); - device_create_file(&new_client->dev, &dev_attr_alarms); - return 0; +error3: + sysfs_remove_group(&new_client->dev.kobj, &adm1021_group); error2: i2c_detach_client(new_client); error1: @@ -326,6 +338,7 @@ static int adm1021_detach_client(struct i2c_client *client) int err; hwmon_device_unregister(data->class_dev); + sysfs_remove_group(&client->dev.kobj, &adm1021_group); if ((err = i2c_detach_client(client))) return err; diff --git a/drivers/hwmon/adm1025.c b/drivers/hwmon/adm1025.c index a4c859c9fbf8..8c562885b54b 100644 --- a/drivers/hwmon/adm1025.c +++ b/drivers/hwmon/adm1025.c @@ -315,6 +315,49 @@ static int adm1025_attach_adapter(struct i2c_adapter *adapter) return i2c_probe(adapter, &addr_data, adm1025_detect); } +static struct attribute *adm1025_attributes[] = { + &dev_attr_in0_input.attr, + &dev_attr_in1_input.attr, + &dev_attr_in2_input.attr, + &dev_attr_in3_input.attr, + &dev_attr_in5_input.attr, + &dev_attr_in0_min.attr, + &dev_attr_in1_min.attr, + &dev_attr_in2_min.attr, + &dev_attr_in3_min.attr, + &dev_attr_in5_min.attr, + &dev_attr_in0_max.attr, + &dev_attr_in1_max.attr, + &dev_attr_in2_max.attr, + &dev_attr_in3_max.attr, + &dev_attr_in5_max.attr, + &dev_attr_temp1_input.attr, + &dev_attr_temp2_input.attr, + &dev_attr_temp1_min.attr, + &dev_attr_temp2_min.attr, + &dev_attr_temp1_max.attr, + &dev_attr_temp2_max.attr, + &dev_attr_alarms.attr, + &dev_attr_cpu0_vid.attr, + &dev_attr_vrm.attr, + NULL +}; + +static const struct attribute_group adm1025_group = { + .attrs = adm1025_attributes, +}; + +static struct attribute *adm1025_attributes_opt[] = { + &dev_attr_in4_input.attr, + &dev_attr_in4_min.attr, + &dev_attr_in4_max.attr, + NULL +}; + +static const struct attribute_group adm1025_group_opt = { + .attrs = adm1025_attributes_opt, +}; + /* * The following function does more than just detection. If detection * succeeds, it also registers the new chip. @@ -415,46 +458,31 @@ static int adm1025_detect(struct i2c_adapter *adapter, int address, int kind) adm1025_init_client(new_client); /* Register sysfs hooks */ - data->class_dev = hwmon_device_register(&new_client->dev); - if (IS_ERR(data->class_dev)) { - err = PTR_ERR(data->class_dev); + if ((err = sysfs_create_group(&new_client->dev.kobj, &adm1025_group))) goto exit_detach; - } - - device_create_file(&new_client->dev, &dev_attr_in0_input); - device_create_file(&new_client->dev, &dev_attr_in1_input); - device_create_file(&new_client->dev, &dev_attr_in2_input); - device_create_file(&new_client->dev, &dev_attr_in3_input); - device_create_file(&new_client->dev, &dev_attr_in5_input); - device_create_file(&new_client->dev, &dev_attr_in0_min); - device_create_file(&new_client->dev, &dev_attr_in1_min); - device_create_file(&new_client->dev, &dev_attr_in2_min); - device_create_file(&new_client->dev, &dev_attr_in3_min); - device_create_file(&new_client->dev, &dev_attr_in5_min); - device_create_file(&new_client->dev, &dev_attr_in0_max); - device_create_file(&new_client->dev, &dev_attr_in1_max); - device_create_file(&new_client->dev, &dev_attr_in2_max); - device_create_file(&new_client->dev, &dev_attr_in3_max); - device_create_file(&new_client->dev, &dev_attr_in5_max); - device_create_file(&new_client->dev, &dev_attr_temp1_input); - device_create_file(&new_client->dev, &dev_attr_temp2_input); - device_create_file(&new_client->dev, &dev_attr_temp1_min); - device_create_file(&new_client->dev, &dev_attr_temp2_min); - device_create_file(&new_client->dev, &dev_attr_temp1_max); - device_create_file(&new_client->dev, &dev_attr_temp2_max); - device_create_file(&new_client->dev, &dev_attr_alarms); - device_create_file(&new_client->dev, &dev_attr_cpu0_vid); - device_create_file(&new_client->dev, &dev_attr_vrm); /* Pin 11 is either in4 (+12V) or VID4 */ if (!(config & 0x20)) { - device_create_file(&new_client->dev, &dev_attr_in4_input); - device_create_file(&new_client->dev, &dev_attr_in4_min); - device_create_file(&new_client->dev, &dev_attr_in4_max); + if ((err = device_create_file(&new_client->dev, + &dev_attr_in4_input)) + || (err = device_create_file(&new_client->dev, + &dev_attr_in4_min)) + || (err = device_create_file(&new_client->dev, + &dev_attr_in4_max))) + goto exit_remove; + } + + data->class_dev = hwmon_device_register(&new_client->dev); + if (IS_ERR(data->class_dev)) { + err = PTR_ERR(data->class_dev); + goto exit_remove; } return 0; +exit_remove: + sysfs_remove_group(&new_client->dev.kobj, &adm1025_group); + sysfs_remove_group(&new_client->dev.kobj, &adm1025_group_opt); exit_detach: i2c_detach_client(new_client); exit_free: @@ -511,6 +539,8 @@ static int adm1025_detach_client(struct i2c_client *client) int err; hwmon_device_unregister(data->class_dev); + sysfs_remove_group(&client->dev.kobj, &adm1025_group); + sysfs_remove_group(&client->dev.kobj, &adm1025_group_opt); if ((err = i2c_detach_client(client))) return err; diff --git a/drivers/hwmon/adm1026.c b/drivers/hwmon/adm1026.c index 6d4f8b8d358e..b4618b2705f7 100644 --- a/drivers/hwmon/adm1026.c +++ b/drivers/hwmon/adm1026.c @@ -323,15 +323,6 @@ static int adm1026_attach_adapter(struct i2c_adapter *adapter) return i2c_probe(adapter, &addr_data, adm1026_detect); } -static int adm1026_detach_client(struct i2c_client *client) -{ - struct adm1026_data *data = i2c_get_clientdata(client); - hwmon_device_unregister(data->class_dev); - i2c_detach_client(client); - kfree(data); - return 0; -} - static int adm1026_read_value(struct i2c_client *client, u8 reg) { int res; @@ -1450,6 +1441,135 @@ static DEVICE_ATTR(temp1_auto_point2_pwm, S_IRUGO, show_auto_pwm_max, NULL); static DEVICE_ATTR(temp2_auto_point2_pwm, S_IRUGO, show_auto_pwm_max, NULL); static DEVICE_ATTR(temp3_auto_point2_pwm, S_IRUGO, show_auto_pwm_max, NULL); +static struct attribute *adm1026_attributes[] = { + &sensor_dev_attr_in0_input.dev_attr.attr, + &sensor_dev_attr_in0_max.dev_attr.attr, + &sensor_dev_attr_in0_min.dev_attr.attr, + &sensor_dev_attr_in1_input.dev_attr.attr, + &sensor_dev_attr_in1_max.dev_attr.attr, + &sensor_dev_attr_in1_min.dev_attr.attr, + &sensor_dev_attr_in2_input.dev_attr.attr, + &sensor_dev_attr_in2_max.dev_attr.attr, + &sensor_dev_attr_in2_min.dev_attr.attr, + &sensor_dev_attr_in3_input.dev_attr.attr, + &sensor_dev_attr_in3_max.dev_attr.attr, + &sensor_dev_attr_in3_min.dev_attr.attr, + &sensor_dev_attr_in4_input.dev_attr.attr, + &sensor_dev_attr_in4_max.dev_attr.attr, + &sensor_dev_attr_in4_min.dev_attr.attr, + &sensor_dev_attr_in5_input.dev_attr.attr, + &sensor_dev_attr_in5_max.dev_attr.attr, + &sensor_dev_attr_in5_min.dev_attr.attr, + &sensor_dev_attr_in6_input.dev_attr.attr, + &sensor_dev_attr_in6_max.dev_attr.attr, + &sensor_dev_attr_in6_min.dev_attr.attr, + &sensor_dev_attr_in7_input.dev_attr.attr, + &sensor_dev_attr_in7_max.dev_attr.attr, + &sensor_dev_attr_in7_min.dev_attr.attr, + &sensor_dev_attr_in8_input.dev_attr.attr, + &sensor_dev_attr_in8_max.dev_attr.attr, + &sensor_dev_attr_in8_min.dev_attr.attr, + &sensor_dev_attr_in9_input.dev_attr.attr, + &sensor_dev_attr_in9_max.dev_attr.attr, + &sensor_dev_attr_in9_min.dev_attr.attr, + &sensor_dev_attr_in10_input.dev_attr.attr, + &sensor_dev_attr_in10_max.dev_attr.attr, + &sensor_dev_attr_in10_min.dev_attr.attr, + &sensor_dev_attr_in11_input.dev_attr.attr, + &sensor_dev_attr_in11_max.dev_attr.attr, + &sensor_dev_attr_in11_min.dev_attr.attr, + &sensor_dev_attr_in12_input.dev_attr.attr, + &sensor_dev_attr_in12_max.dev_attr.attr, + &sensor_dev_attr_in12_min.dev_attr.attr, + &sensor_dev_attr_in13_input.dev_attr.attr, + &sensor_dev_attr_in13_max.dev_attr.attr, + &sensor_dev_attr_in13_min.dev_attr.attr, + &sensor_dev_attr_in14_input.dev_attr.attr, + &sensor_dev_attr_in14_max.dev_attr.attr, + &sensor_dev_attr_in14_min.dev_attr.attr, + &sensor_dev_attr_in15_input.dev_attr.attr, + &sensor_dev_attr_in15_max.dev_attr.attr, + &sensor_dev_attr_in15_min.dev_attr.attr, + &sensor_dev_attr_in16_input.dev_attr.attr, + &sensor_dev_attr_in16_max.dev_attr.attr, + &sensor_dev_attr_in16_min.dev_attr.attr, + &sensor_dev_attr_fan1_input.dev_attr.attr, + &sensor_dev_attr_fan1_div.dev_attr.attr, + &sensor_dev_attr_fan1_min.dev_attr.attr, + &sensor_dev_attr_fan2_input.dev_attr.attr, + &sensor_dev_attr_fan2_div.dev_attr.attr, + &sensor_dev_attr_fan2_min.dev_attr.attr, + &sensor_dev_attr_fan3_input.dev_attr.attr, + &sensor_dev_attr_fan3_div.dev_attr.attr, + &sensor_dev_attr_fan3_min.dev_attr.attr, + &sensor_dev_attr_fan4_input.dev_attr.attr, + &sensor_dev_attr_fan4_div.dev_attr.attr, + &sensor_dev_attr_fan4_min.dev_attr.attr, + &sensor_dev_attr_fan5_input.dev_attr.attr, + &sensor_dev_attr_fan5_div.dev_attr.attr, + &sensor_dev_attr_fan5_min.dev_attr.attr, + &sensor_dev_attr_fan6_input.dev_attr.attr, + &sensor_dev_attr_fan6_div.dev_attr.attr, + &sensor_dev_attr_fan6_min.dev_attr.attr, + &sensor_dev_attr_fan7_input.dev_attr.attr, + &sensor_dev_attr_fan7_div.dev_attr.attr, + &sensor_dev_attr_fan7_min.dev_attr.attr, + &sensor_dev_attr_fan8_input.dev_attr.attr, + &sensor_dev_attr_fan8_div.dev_attr.attr, + &sensor_dev_attr_fan8_min.dev_attr.attr, + &sensor_dev_attr_temp1_input.dev_attr.attr, + &sensor_dev_attr_temp1_max.dev_attr.attr, + &sensor_dev_attr_temp1_min.dev_attr.attr, + &sensor_dev_attr_temp2_input.dev_attr.attr, + &sensor_dev_attr_temp2_max.dev_attr.attr, + &sensor_dev_attr_temp2_min.dev_attr.attr, + &sensor_dev_attr_temp3_input.dev_attr.attr, + &sensor_dev_attr_temp3_max.dev_attr.attr, + &sensor_dev_attr_temp3_min.dev_attr.attr, + &sensor_dev_attr_temp1_offset.dev_attr.attr, + &sensor_dev_attr_temp2_offset.dev_attr.attr, + &sensor_dev_attr_temp3_offset.dev_attr.attr, + &sensor_dev_attr_temp1_auto_point1_temp.dev_attr.attr, + &sensor_dev_attr_temp2_auto_point1_temp.dev_attr.attr, + &sensor_dev_attr_temp3_auto_point1_temp.dev_attr.attr, + &sensor_dev_attr_temp1_auto_point1_temp_hyst.dev_attr.attr, + &sensor_dev_attr_temp2_auto_point1_temp_hyst.dev_attr.attr, + &sensor_dev_attr_temp3_auto_point1_temp_hyst.dev_attr.attr, + &sensor_dev_attr_temp1_auto_point2_temp.dev_attr.attr, + &sensor_dev_attr_temp2_auto_point2_temp.dev_attr.attr, + &sensor_dev_attr_temp3_auto_point2_temp.dev_attr.attr, + &sensor_dev_attr_temp1_crit.dev_attr.attr, + &sensor_dev_attr_temp2_crit.dev_attr.attr, + &sensor_dev_attr_temp3_crit.dev_attr.attr, + &dev_attr_temp1_crit_enable.attr, + &dev_attr_temp2_crit_enable.attr, + &dev_attr_temp3_crit_enable.attr, + &dev_attr_cpu0_vid.attr, + &dev_attr_vrm.attr, + &dev_attr_alarms.attr, + &dev_attr_alarm_mask.attr, + &dev_attr_gpio.attr, + &dev_attr_gpio_mask.attr, + &dev_attr_pwm1.attr, + &dev_attr_pwm2.attr, + &dev_attr_pwm3.attr, + &dev_attr_pwm1_enable.attr, + &dev_attr_pwm2_enable.attr, + &dev_attr_pwm3_enable.attr, + &dev_attr_temp1_auto_point1_pwm.attr, + &dev_attr_temp2_auto_point1_pwm.attr, + &dev_attr_temp3_auto_point1_pwm.attr, + &dev_attr_temp1_auto_point2_pwm.attr, + &dev_attr_temp2_auto_point2_pwm.attr, + &dev_attr_temp3_auto_point2_pwm.attr, + &dev_attr_analog_out.attr, + NULL +}; + +static const struct attribute_group adm1026_group = { + .attrs = adm1026_attributes, +}; + static int adm1026_detect(struct i2c_adapter *adapter, int address, int kind) { @@ -1554,145 +1674,20 @@ static int adm1026_detect(struct i2c_adapter *adapter, int address, adm1026_init_client(new_client); /* Register sysfs hooks */ + if ((err = sysfs_create_group(&new_client->dev.kobj, &adm1026_group))) + goto exitdetach; + data->class_dev = hwmon_device_register(&new_client->dev); if (IS_ERR(data->class_dev)) { err = PTR_ERR(data->class_dev); - goto exitdetach; + goto exitremove; } - device_create_file(&new_client->dev, &sensor_dev_attr_in0_input.dev_attr); - device_create_file(&new_client->dev, &sensor_dev_attr_in0_max.dev_attr); - device_create_file(&new_client->dev, &sensor_dev_attr_in0_min.dev_attr); - device_create_file(&new_client->dev, &sensor_dev_attr_in1_input.dev_attr); - device_create_file(&new_client->dev, &sensor_dev_attr_in1_max.dev_attr); - device_create_file(&new_client->dev, &sensor_dev_attr_in1_min.dev_attr); - device_create_file(&new_client->dev, &sensor_dev_attr_in2_input.dev_attr); - device_create_file(&new_client->dev, &sensor_dev_attr_in2_max.dev_attr); - device_create_file(&new_client->dev, &sensor_dev_attr_in2_min.dev_attr); - device_create_file(&new_client->dev, &sensor_dev_attr_in3_input.dev_attr); - device_create_file(&new_client->dev, &sensor_dev_attr_in3_max.dev_attr); - device_create_file(&new_client->dev, &sensor_dev_attr_in3_min.dev_attr); - device_create_file(&new_client->dev, &sensor_dev_attr_in4_input.dev_attr); - device_create_file(&new_client->dev, &sensor_dev_attr_in4_max.dev_attr); - device_create_file(&new_client->dev, &sensor_dev_attr_in4_min.dev_attr); - device_create_file(&new_client->dev, &sensor_dev_attr_in5_input.dev_attr); - device_create_file(&new_client->dev, &sensor_dev_attr_in5_max.dev_attr); - device_create_file(&new_client->dev, &sensor_dev_attr_in5_min.dev_attr); - device_create_file(&new_client->dev, &sensor_dev_attr_in6_input.dev_attr); - device_create_file(&new_client->dev, &sensor_dev_attr_in6_max.dev_attr); - device_create_file(&new_client->dev, &sensor_dev_attr_in6_min.dev_attr); - device_create_file(&new_client->dev, &sensor_dev_attr_in7_input.dev_attr); - device_create_file(&new_client->dev, &sensor_dev_attr_in7_max.dev_attr); - device_create_file(&new_client->dev, &sensor_dev_attr_in7_min.dev_attr); - device_create_file(&new_client->dev, &sensor_dev_attr_in8_input.dev_attr); - device_create_file(&new_client->dev, &sensor_dev_attr_in8_max.dev_attr); - device_create_file(&new_client->dev, &sensor_dev_attr_in8_min.dev_attr); - device_create_file(&new_client->dev, &sensor_dev_attr_in9_input.dev_attr); - device_create_file(&new_client->dev, &sensor_dev_attr_in9_max.dev_attr); - device_create_file(&new_client->dev, &sensor_dev_attr_in9_min.dev_attr); - device_create_file(&new_client->dev, &sensor_dev_attr_in10_input.dev_attr); - device_create_file(&new_client->dev, &sensor_dev_attr_in10_max.dev_attr); - device_create_file(&new_client->dev, &sensor_dev_attr_in10_min.dev_attr); - device_create_file(&new_client->dev, &sensor_dev_attr_in11_input.dev_attr); - device_create_file(&new_client->dev, &sensor_dev_attr_in11_max.dev_attr); - device_create_file(&new_client->dev, &sensor_dev_attr_in11_min.dev_attr); - device_create_file(&new_client->dev, &sensor_dev_attr_in12_input.dev_attr); - device_create_file(&new_client->dev, &sensor_dev_attr_in12_max.dev_attr); - device_create_file(&new_client->dev, &sensor_dev_attr_in12_min.dev_attr); - device_create_file(&new_client->dev, &sensor_dev_attr_in13_input.dev_attr); - device_create_file(&new_client->dev, &sensor_dev_attr_in13_max.dev_attr); - device_create_file(&new_client->dev, &sensor_dev_attr_in13_min.dev_attr); - device_create_file(&new_client->dev, &sensor_dev_attr_in14_input.dev_attr); - device_create_file(&new_client->dev, &sensor_dev_attr_in14_max.dev_attr); - device_create_file(&new_client->dev, &sensor_dev_attr_in14_min.dev_attr); - device_create_file(&new_client->dev, &sensor_dev_attr_in15_input.dev_attr); - device_create_file(&new_client->dev, &sensor_dev_attr_in15_max.dev_attr); - device_create_file(&new_client->dev, &sensor_dev_attr_in15_min.dev_attr); - device_create_file(&new_client->dev, &sensor_dev_attr_in16_input.dev_attr); - device_create_file(&new_client->dev, &sensor_dev_attr_in16_max.dev_attr); - device_create_file(&new_client->dev, &sensor_dev_attr_in16_min.dev_attr); - device_create_file(&new_client->dev, &sensor_dev_attr_fan1_input.dev_attr); - device_create_file(&new_client->dev, &sensor_dev_attr_fan1_div.dev_attr); - device_create_file(&new_client->dev, &sensor_dev_attr_fan1_min.dev_attr); - device_create_file(&new_client->dev, &sensor_dev_attr_fan2_input.dev_attr); - device_create_file(&new_client->dev, &sensor_dev_attr_fan2_div.dev_attr); - device_create_file(&new_client->dev, &sensor_dev_attr_fan2_min.dev_attr); - device_create_file(&new_client->dev, &sensor_dev_attr_fan3_input.dev_attr); - device_create_file(&new_client->dev, &sensor_dev_attr_fan3_div.dev_attr); - device_create_file(&new_client->dev, &sensor_dev_attr_fan3_min.dev_attr); - device_create_file(&new_client->dev, &sensor_dev_attr_fan4_input.dev_attr); - device_create_file(&new_client->dev, &sensor_dev_attr_fan4_div.dev_attr); - device_create_file(&new_client->dev, &sensor_dev_attr_fan4_min.dev_attr); - device_create_file(&new_client->dev, &sensor_dev_attr_fan5_input.dev_attr); - device_create_file(&new_client->dev, &sensor_dev_attr_fan5_div.dev_attr); - device_create_file(&new_client->dev, &sensor_dev_attr_fan5_min.dev_attr); - device_create_file(&new_client->dev, &sensor_dev_attr_fan6_input.dev_attr); - device_create_file(&new_client->dev, &sensor_dev_attr_fan6_div.dev_attr); - device_create_file(&new_client->dev, &sensor_dev_attr_fan6_min.dev_attr); - device_create_file(&new_client->dev, &sensor_dev_attr_fan7_input.dev_attr); - device_create_file(&new_client->dev, &sensor_dev_attr_fan7_div.dev_attr); - device_create_file(&new_client->dev, &sensor_dev_attr_fan7_min.dev_attr); - device_create_file(&new_client->dev, &sensor_dev_attr_fan8_input.dev_attr); - device_create_file(&new_client->dev, &sensor_dev_attr_fan8_div.dev_attr); - device_create_file(&new_client->dev, &sensor_dev_attr_fan8_min.dev_attr); - device_create_file(&new_client->dev, &sensor_dev_attr_temp1_input.dev_attr); - device_create_file(&new_client->dev, &sensor_dev_attr_temp1_max.dev_attr); - device_create_file(&new_client->dev, &sensor_dev_attr_temp1_min.dev_attr); - device_create_file(&new_client->dev, &sensor_dev_attr_temp2_input.dev_attr); - device_create_file(&new_client->dev, &sensor_dev_attr_temp2_max.dev_attr); - device_create_file(&new_client->dev, &sensor_dev_attr_temp2_min.dev_attr); - device_create_file(&new_client->dev, &sensor_dev_attr_temp3_input.dev_attr); - device_create_file(&new_client->dev, &sensor_dev_attr_temp3_max.dev_attr); - device_create_file(&new_client->dev, &sensor_dev_attr_temp3_min.dev_attr); - device_create_file(&new_client->dev, &sensor_dev_attr_temp1_offset.dev_attr); - device_create_file(&new_client->dev, &sensor_dev_attr_temp2_offset.dev_attr); - device_create_file(&new_client->dev, &sensor_dev_attr_temp3_offset.dev_attr); - device_create_file(&new_client->dev, - &sensor_dev_attr_temp1_auto_point1_temp.dev_attr); - device_create_file(&new_client->dev, - &sensor_dev_attr_temp2_auto_point1_temp.dev_attr); - device_create_file(&new_client->dev, - &sensor_dev_attr_temp3_auto_point1_temp.dev_attr); - device_create_file(&new_client->dev, - &sensor_dev_attr_temp1_auto_point1_temp_hyst.dev_attr); - device_create_file(&new_client->dev, - &sensor_dev_attr_temp2_auto_point1_temp_hyst.dev_attr); - device_create_file(&new_client->dev, - &sensor_dev_attr_temp3_auto_point1_temp_hyst.dev_attr); - device_create_file(&new_client->dev, - &sensor_dev_attr_temp1_auto_point2_temp.dev_attr); - device_create_file(&new_client->dev, - &sensor_dev_attr_temp2_auto_point2_temp.dev_attr); - device_create_file(&new_client->dev, - &sensor_dev_attr_temp3_auto_point2_temp.dev_attr); - device_create_file(&new_client->dev, &sensor_dev_attr_temp1_crit.dev_attr); - device_create_file(&new_client->dev, &sensor_dev_attr_temp2_crit.dev_attr); - device_create_file(&new_client->dev, &sensor_dev_attr_temp3_crit.dev_attr); - device_create_file(&new_client->dev, &dev_attr_temp1_crit_enable); - device_create_file(&new_client->dev, &dev_attr_temp2_crit_enable); - device_create_file(&new_client->dev, &dev_attr_temp3_crit_enable); - device_create_file(&new_client->dev, &dev_attr_cpu0_vid); - device_create_file(&new_client->dev, &dev_attr_vrm); - device_create_file(&new_client->dev, &dev_attr_alarms); - device_create_file(&new_client->dev, &dev_attr_alarm_mask); - device_create_file(&new_client->dev, &dev_attr_gpio); - device_create_file(&new_client->dev, &dev_attr_gpio_mask); - device_create_file(&new_client->dev, &dev_attr_pwm1); - device_create_file(&new_client->dev, &dev_attr_pwm2); - device_create_file(&new_client->dev, &dev_attr_pwm3); - device_create_file(&new_client->dev, &dev_attr_pwm1_enable); - device_create_file(&new_client->dev, &dev_attr_pwm2_enable); - device_create_file(&new_client->dev, &dev_attr_pwm3_enable); - device_create_file(&new_client->dev, &dev_attr_temp1_auto_point1_pwm); - device_create_file(&new_client->dev, &dev_attr_temp2_auto_point1_pwm); - device_create_file(&new_client->dev, &dev_attr_temp3_auto_point1_pwm); - device_create_file(&new_client->dev, &dev_attr_temp1_auto_point2_pwm); - device_create_file(&new_client->dev, &dev_attr_temp2_auto_point2_pwm); - device_create_file(&new_client->dev, &dev_attr_temp3_auto_point2_pwm); - device_create_file(&new_client->dev, &dev_attr_analog_out); return 0; /* Error out and cleanup code */ +exitremove: + sysfs_remove_group(&new_client->dev.kobj, &adm1026_group); exitdetach: i2c_detach_client(new_client); exitfree: @@ -1700,6 +1695,17 @@ static int adm1026_detect(struct i2c_adapter *adapter, int address, exit: return err; } + +static int adm1026_detach_client(struct i2c_client *client) +{ + struct adm1026_data *data = i2c_get_clientdata(client); + hwmon_device_unregister(data->class_dev); + sysfs_remove_group(&client->dev.kobj, &adm1026_group); + i2c_detach_client(client); + kfree(data); + return 0; +} + static int __init sm_adm1026_init(void) { return i2c_add_driver(&adm1026_driver); diff --git a/drivers/hwmon/adm1031.c b/drivers/hwmon/adm1031.c index 3bf2da621aed..122683fc91d0 100644 --- a/drivers/hwmon/adm1031.c +++ b/drivers/hwmon/adm1031.c @@ -730,6 +730,61 @@ static int adm1031_attach_adapter(struct i2c_adapter *adapter) return i2c_probe(adapter, &addr_data, adm1031_detect); } +static struct attribute *adm1031_attributes[] = { + &dev_attr_fan1_input.attr, + &dev_attr_fan1_div.attr, + &dev_attr_fan1_min.attr, + &dev_attr_pwm1.attr, + &dev_attr_auto_fan1_channel.attr, + &dev_attr_temp1_input.attr, + &dev_attr_temp1_min.attr, + &dev_attr_temp1_max.attr, + &dev_attr_temp1_crit.attr, + &dev_attr_temp2_input.attr, + &dev_attr_temp2_min.attr, + &dev_attr_temp2_max.attr, + &dev_attr_temp2_crit.attr, + + &dev_attr_auto_temp1_off.attr, + &dev_attr_auto_temp1_min.attr, + &dev_attr_auto_temp1_max.attr, + + &dev_attr_auto_temp2_off.attr, + &dev_attr_auto_temp2_min.attr, + &dev_attr_auto_temp2_max.attr, + + &dev_attr_auto_fan1_min_pwm.attr, + + &dev_attr_alarms.attr, + + NULL +}; + +static const struct attribute_group adm1031_group = { + .attrs = adm1031_attributes, +}; + +static struct attribute *adm1031_attributes_opt[] = { + &dev_attr_fan2_input.attr, + &dev_attr_fan2_div.attr, + &dev_attr_fan2_min.attr, + &dev_attr_pwm2.attr, + &dev_attr_auto_fan2_channel.attr, + &dev_attr_temp3_input.attr, + &dev_attr_temp3_min.attr, + &dev_attr_temp3_max.attr, + &dev_attr_temp3_crit.attr, + &dev_attr_auto_temp3_off.attr, + &dev_attr_auto_temp3_min.attr, + &dev_attr_auto_temp3_max.attr, + &dev_attr_auto_fan2_min_pwm.attr, + NULL +}; + +static const struct attribute_group adm1031_group_opt = { + .attrs = adm1031_attributes_opt, +}; + /* This function is called by i2c_probe */ static int adm1031_detect(struct i2c_adapter *adapter, int address, int kind) { @@ -789,57 +844,26 @@ static int adm1031_detect(struct i2c_adapter *adapter, int address, int kind) adm1031_init_client(new_client); /* Register sysfs hooks */ + if ((err = sysfs_create_group(&new_client->dev.kobj, &adm1031_group))) + goto exit_detach; + + if (kind == adm1031) { + if ((err = sysfs_create_group(&new_client->dev.kobj, + &adm1031_group_opt))) + goto exit_remove; + } + data->class_dev = hwmon_device_register(&new_client->dev); if (IS_ERR(data->class_dev)) { err = PTR_ERR(data->class_dev); - goto exit_detach; - } - - device_create_file(&new_client->dev, &dev_attr_fan1_input); - device_create_file(&new_client->dev, &dev_attr_fan1_div); - device_create_file(&new_client->dev, &dev_attr_fan1_min); - device_create_file(&new_client->dev, &dev_attr_pwm1); - device_create_file(&new_client->dev, &dev_attr_auto_fan1_channel); - device_create_file(&new_client->dev, &dev_attr_temp1_input); - device_create_file(&new_client->dev, &dev_attr_temp1_min); - device_create_file(&new_client->dev, &dev_attr_temp1_max); - device_create_file(&new_client->dev, &dev_attr_temp1_crit); - device_create_file(&new_client->dev, &dev_attr_temp2_input); - device_create_file(&new_client->dev, &dev_attr_temp2_min); - device_create_file(&new_client->dev, &dev_attr_temp2_max); - device_create_file(&new_client->dev, &dev_attr_temp2_crit); - - device_create_file(&new_client->dev, &dev_attr_auto_temp1_off); - device_create_file(&new_client->dev, &dev_attr_auto_temp1_min); - device_create_file(&new_client->dev, &dev_attr_auto_temp1_max); - - device_create_file(&new_client->dev, &dev_attr_auto_temp2_off); - device_create_file(&new_client->dev, &dev_attr_auto_temp2_min); - device_create_file(&new_client->dev, &dev_attr_auto_temp2_max); - - device_create_file(&new_client->dev, &dev_attr_auto_fan1_min_pwm); - - device_create_file(&new_client->dev, &dev_attr_alarms); - - if (kind == adm1031) { - device_create_file(&new_client->dev, &dev_attr_fan2_input); - device_create_file(&new_client->dev, &dev_attr_fan2_div); - device_create_file(&new_client->dev, &dev_attr_fan2_min); - device_create_file(&new_client->dev, &dev_attr_pwm2); - device_create_file(&new_client->dev, - &dev_attr_auto_fan2_channel); - device_create_file(&new_client->dev, &dev_attr_temp3_input); - device_create_file(&new_client->dev, &dev_attr_temp3_min); - device_create_file(&new_client->dev, &dev_attr_temp3_max); - device_create_file(&new_client->dev, &dev_attr_temp3_crit); - device_create_file(&new_client->dev, &dev_attr_auto_temp3_off); - device_create_file(&new_client->dev, &dev_attr_auto_temp3_min); - device_create_file(&new_client->dev, &dev_attr_auto_temp3_max); - device_create_file(&new_client->dev, &dev_attr_auto_fan2_min_pwm); + goto exit_remove; } return 0; +exit_remove: + sysfs_remove_group(&new_client->dev.kobj, &adm1031_group); + sysfs_remove_group(&new_client->dev.kobj, &adm1031_group_opt); exit_detach: i2c_detach_client(new_client); exit_free: @@ -854,6 +878,8 @@ static int adm1031_detach_client(struct i2c_client *client) int ret; hwmon_device_unregister(data->class_dev); + sysfs_remove_group(&client->dev.kobj, &adm1031_group); + sysfs_remove_group(&client->dev.kobj, &adm1031_group_opt); if ((ret = i2c_detach_client(client)) != 0) { return ret; } diff --git a/drivers/hwmon/adm9240.c b/drivers/hwmon/adm9240.c index 43f6991b588c..377961c4a41e 100644 --- a/drivers/hwmon/adm9240.c +++ b/drivers/hwmon/adm9240.c @@ -465,6 +465,45 @@ static ssize_t chassis_clear(struct device *dev, } static DEVICE_ATTR(chassis_clear, S_IWUSR, NULL, chassis_clear); +static struct attribute *adm9240_attributes[] = { + &sensor_dev_attr_in0_input.dev_attr.attr, + &sensor_dev_attr_in0_min.dev_attr.attr, + &sensor_dev_attr_in0_max.dev_attr.attr, + &sensor_dev_attr_in1_input.dev_attr.attr, + &sensor_dev_attr_in1_min.dev_attr.attr, + &sensor_dev_attr_in1_max.dev_attr.attr, + &sensor_dev_attr_in2_input.dev_attr.attr, + &sensor_dev_attr_in2_min.dev_attr.attr, + &sensor_dev_attr_in2_max.dev_attr.attr, + &sensor_dev_attr_in3_input.dev_attr.attr, + &sensor_dev_attr_in3_min.dev_attr.attr, + &sensor_dev_attr_in3_max.dev_attr.attr, + &sensor_dev_attr_in4_input.dev_attr.attr, + &sensor_dev_attr_in4_min.dev_attr.attr, + &sensor_dev_attr_in4_max.dev_attr.attr, + &sensor_dev_attr_in5_input.dev_attr.attr, + &sensor_dev_attr_in5_min.dev_attr.attr, + &sensor_dev_attr_in5_max.dev_attr.attr, + &dev_attr_temp1_input.attr, + &sensor_dev_attr_temp1_max.dev_attr.attr, + &sensor_dev_attr_temp1_max_hyst.dev_attr.attr, + &sensor_dev_attr_fan1_input.dev_attr.attr, + &sensor_dev_attr_fan1_div.dev_attr.attr, + &sensor_dev_attr_fan1_min.dev_attr.attr, + &sensor_dev_attr_fan2_input.dev_attr.attr, + &sensor_dev_attr_fan2_div.dev_attr.attr, + &sensor_dev_attr_fan2_min.dev_attr.attr, + &dev_attr_alarms.attr, + &dev_attr_aout_output.attr, + &dev_attr_chassis_clear.attr, + &dev_attr_cpu0_vid.attr, + NULL +}; + +static const struct attribute_group adm9240_group = { + .attrs = adm9240_attributes, +}; + /*** sensor chip detect and driver install ***/ @@ -548,72 +587,19 @@ static int adm9240_detect(struct i2c_adapter *adapter, int address, int kind) adm9240_init_client(new_client); /* populate sysfs filesystem */ + if ((err = sysfs_create_group(&new_client->dev.kobj, &adm9240_group))) + goto exit_detach; + data->class_dev = hwmon_device_register(&new_client->dev); if (IS_ERR(data->class_dev)) { err = PTR_ERR(data->class_dev); - goto exit_detach; + goto exit_remove; } - device_create_file(&new_client->dev, - &sensor_dev_attr_in0_input.dev_attr); - device_create_file(&new_client->dev, - &sensor_dev_attr_in0_min.dev_attr); - device_create_file(&new_client->dev, - &sensor_dev_attr_in0_max.dev_attr); - device_create_file(&new_client->dev, - &sensor_dev_attr_in1_input.dev_attr); - device_create_file(&new_client->dev, - &sensor_dev_attr_in1_min.dev_attr); - device_create_file(&new_client->dev, - &sensor_dev_attr_in1_max.dev_attr); - device_create_file(&new_client->dev, - &sensor_dev_attr_in2_input.dev_attr); - device_create_file(&new_client->dev, - &sensor_dev_attr_in2_min.dev_attr); - device_create_file(&new_client->dev, - &sensor_dev_attr_in2_max.dev_attr); - device_create_file(&new_client->dev, - &sensor_dev_attr_in3_input.dev_attr); - device_create_file(&new_client->dev, - &sensor_dev_attr_in3_min.dev_attr); - device_create_file(&new_client->dev, - &sensor_dev_attr_in3_max.dev_attr); - device_create_file(&new_client->dev, - &sensor_dev_attr_in4_input.dev_attr); - device_create_file(&new_client->dev, - &sensor_dev_attr_in4_min.dev_attr); - device_create_file(&new_client->dev, - &sensor_dev_attr_in4_max.dev_attr); - device_create_file(&new_client->dev, - &sensor_dev_attr_in5_input.dev_attr); - device_create_file(&new_client->dev, - &sensor_dev_attr_in5_min.dev_attr); - device_create_file(&new_client->dev, - &sensor_dev_attr_in5_max.dev_attr); - device_create_file(&new_client->dev, &dev_attr_temp1_input); - device_create_file(&new_client->dev, - &sensor_dev_attr_temp1_max.dev_attr); - device_create_file(&new_client->dev, - &sensor_dev_attr_temp1_max_hyst.dev_attr); - device_create_file(&new_client->dev, - &sensor_dev_attr_fan1_input.dev_attr); - device_create_file(&new_client->dev, - &sensor_dev_attr_fan1_div.dev_attr); - device_create_file(&new_client->dev, - &sensor_dev_attr_fan1_min.dev_attr); - device_create_file(&new_client->dev, - &sensor_dev_attr_fan2_input.dev_attr); - device_create_file(&new_client->dev, - &sensor_dev_attr_fan2_div.dev_attr); - device_create_file(&new_client->dev, - &sensor_dev_attr_fan2_min.dev_attr); - device_create_file(&new_client->dev, &dev_attr_alarms); - device_create_file(&new_client->dev, &dev_attr_aout_output); - device_create_file(&new_client->dev, &dev_attr_chassis_clear); - device_create_file(&new_client->dev, &dev_attr_cpu0_vid); - return 0; +exit_remove: + sysfs_remove_group(&new_client->dev.kobj, &adm9240_group); exit_detach: i2c_detach_client(new_client); exit_free: @@ -635,6 +621,7 @@ static int adm9240_detach_client(struct i2c_client *client) int err; hwmon_device_unregister(data->class_dev); + sysfs_remove_group(&client->dev.kobj, &adm9240_group); if ((err = i2c_detach_client(client))) return err; From 0e39e01c908fdc498fff0d788fd7b955ab75ebb6 Mon Sep 17 00:00:00 2001 From: Jean Delvare Date: Sun, 24 Sep 2006 21:16:40 +0200 Subject: [PATCH 31/39] hwmon: Fix unchecked return status, batch 4 hwmon: Fix unchecked return status, batch 4 Fix up some hwmon drivers so that they no longer ignore return status from device_create_file(). Note: f71805f actually checked the status from device_create_file already. However it did not remove the files on device destruction. It was also an opportunity to use sysfs_create/remove_group instead of hand-made loops. This makes the changes much more important but I think the result is worth it. Signed-off-by: Jean Delvare Signed-off-by: Greg Kroah-Hartman --- drivers/hwmon/f71805f.c | 324 +++++++++++++++++++++++++--------------- drivers/hwmon/lm63.c | 89 ++++++----- drivers/hwmon/lm83.c | 123 ++++++++------- drivers/hwmon/lm90.c | 83 +++++----- 4 files changed, 356 insertions(+), 263 deletions(-) diff --git a/drivers/hwmon/f71805f.c b/drivers/hwmon/f71805f.c index 678bae43716d..de17a72149d9 100644 --- a/drivers/hwmon/f71805f.c +++ b/drivers/hwmon/f71805f.c @@ -31,6 +31,7 @@ #include #include #include +#include #include static struct platform_device *pdev; @@ -593,104 +594,189 @@ static ssize_t show_name(struct device *dev, struct device_attribute return sprintf(buf, "%s\n", data->name); } -static struct device_attribute f71805f_dev_attr[] = { - __ATTR(in0_input, S_IRUGO, show_in0, NULL), - __ATTR(in0_max, S_IRUGO| S_IWUSR, show_in0_max, set_in0_max), - __ATTR(in0_min, S_IRUGO| S_IWUSR, show_in0_min, set_in0_min), - __ATTR(alarms_in, S_IRUGO, show_alarms_in, NULL), - __ATTR(alarms_fan, S_IRUGO, show_alarms_fan, NULL), - __ATTR(alarms_temp, S_IRUGO, show_alarms_temp, NULL), - __ATTR(name, S_IRUGO, show_name, NULL), +static DEVICE_ATTR(in0_input, S_IRUGO, show_in0, NULL); +static DEVICE_ATTR(in0_max, S_IRUGO| S_IWUSR, show_in0_max, set_in0_max); +static DEVICE_ATTR(in0_min, S_IRUGO| S_IWUSR, show_in0_min, set_in0_min); +static SENSOR_DEVICE_ATTR(in1_input, S_IRUGO, show_in, NULL, 1); +static SENSOR_DEVICE_ATTR(in1_max, S_IRUGO | S_IWUSR, + show_in_max, set_in_max, 1); +static SENSOR_DEVICE_ATTR(in1_min, S_IRUGO | S_IWUSR, + show_in_min, set_in_min, 1); +static SENSOR_DEVICE_ATTR(in2_input, S_IRUGO, show_in, NULL, 2); +static SENSOR_DEVICE_ATTR(in2_max, S_IRUGO | S_IWUSR, + show_in_max, set_in_max, 2); +static SENSOR_DEVICE_ATTR(in2_min, S_IRUGO | S_IWUSR, + show_in_min, set_in_min, 2); +static SENSOR_DEVICE_ATTR(in3_input, S_IRUGO, show_in, NULL, 3); +static SENSOR_DEVICE_ATTR(in3_max, S_IRUGO | S_IWUSR, + show_in_max, set_in_max, 3); +static SENSOR_DEVICE_ATTR(in3_min, S_IRUGO | S_IWUSR, + show_in_min, set_in_min, 3); +static SENSOR_DEVICE_ATTR(in4_input, S_IRUGO, show_in, NULL, 4); +static SENSOR_DEVICE_ATTR(in4_max, S_IRUGO | S_IWUSR, + show_in_max, set_in_max, 4); +static SENSOR_DEVICE_ATTR(in4_min, S_IRUGO | S_IWUSR, + show_in_min, set_in_min, 4); +static SENSOR_DEVICE_ATTR(in5_input, S_IRUGO, show_in, NULL, 5); +static SENSOR_DEVICE_ATTR(in5_max, S_IRUGO | S_IWUSR, + show_in_max, set_in_max, 5); +static SENSOR_DEVICE_ATTR(in5_min, S_IRUGO | S_IWUSR, + show_in_min, set_in_min, 5); +static SENSOR_DEVICE_ATTR(in6_input, S_IRUGO, show_in, NULL, 6); +static SENSOR_DEVICE_ATTR(in6_max, S_IRUGO | S_IWUSR, + show_in_max, set_in_max, 6); +static SENSOR_DEVICE_ATTR(in6_min, S_IRUGO | S_IWUSR, + show_in_min, set_in_min, 6); +static SENSOR_DEVICE_ATTR(in7_input, S_IRUGO, show_in, NULL, 7); +static SENSOR_DEVICE_ATTR(in7_max, S_IRUGO | S_IWUSR, + show_in_max, set_in_max, 7); +static SENSOR_DEVICE_ATTR(in7_min, S_IRUGO | S_IWUSR, + show_in_min, set_in_min, 7); +static SENSOR_DEVICE_ATTR(in8_input, S_IRUGO, show_in, NULL, 8); +static SENSOR_DEVICE_ATTR(in8_max, S_IRUGO | S_IWUSR, + show_in_max, set_in_max, 8); +static SENSOR_DEVICE_ATTR(in8_min, S_IRUGO | S_IWUSR, + show_in_min, set_in_min, 8); + +static SENSOR_DEVICE_ATTR(fan1_input, S_IRUGO, show_fan, NULL, 0); +static SENSOR_DEVICE_ATTR(fan1_min, S_IRUGO | S_IWUSR, + show_fan_min, set_fan_min, 0); +static SENSOR_DEVICE_ATTR(fan2_input, S_IRUGO, show_fan, NULL, 1); +static SENSOR_DEVICE_ATTR(fan2_min, S_IRUGO | S_IWUSR, + show_fan_min, set_fan_min, 1); +static SENSOR_DEVICE_ATTR(fan3_input, S_IRUGO, show_fan, NULL, 2); +static SENSOR_DEVICE_ATTR(fan3_min, S_IRUGO | S_IWUSR, + show_fan_min, set_fan_min, 2); + +static SENSOR_DEVICE_ATTR(temp1_input, S_IRUGO, show_temp, NULL, 0); +static SENSOR_DEVICE_ATTR(temp1_max, S_IRUGO | S_IWUSR, + show_temp_max, set_temp_max, 0); +static SENSOR_DEVICE_ATTR(temp1_max_hyst, S_IRUGO | S_IWUSR, + show_temp_hyst, set_temp_hyst, 0); +static SENSOR_DEVICE_ATTR(temp1_type, S_IRUGO, show_temp_type, NULL, 0); +static SENSOR_DEVICE_ATTR(temp2_input, S_IRUGO, show_temp, NULL, 1); +static SENSOR_DEVICE_ATTR(temp2_max, S_IRUGO | S_IWUSR, + show_temp_max, set_temp_max, 1); +static SENSOR_DEVICE_ATTR(temp2_max_hyst, S_IRUGO | S_IWUSR, + show_temp_hyst, set_temp_hyst, 1); +static SENSOR_DEVICE_ATTR(temp2_type, S_IRUGO, show_temp_type, NULL, 1); +static SENSOR_DEVICE_ATTR(temp3_input, S_IRUGO, show_temp, NULL, 2); +static SENSOR_DEVICE_ATTR(temp3_max, S_IRUGO | S_IWUSR, + show_temp_max, set_temp_max, 2); +static SENSOR_DEVICE_ATTR(temp3_max_hyst, S_IRUGO | S_IWUSR, + show_temp_hyst, set_temp_hyst, 2); +static SENSOR_DEVICE_ATTR(temp3_type, S_IRUGO, show_temp_type, NULL, 2); + +static SENSOR_DEVICE_ATTR(in0_alarm, S_IRUGO, show_alarm, NULL, 0); +static SENSOR_DEVICE_ATTR(in1_alarm, S_IRUGO, show_alarm, NULL, 1); +static SENSOR_DEVICE_ATTR(in2_alarm, S_IRUGO, show_alarm, NULL, 2); +static SENSOR_DEVICE_ATTR(in3_alarm, S_IRUGO, show_alarm, NULL, 3); +static SENSOR_DEVICE_ATTR(in4_alarm, S_IRUGO, show_alarm, NULL, 4); +static SENSOR_DEVICE_ATTR(in5_alarm, S_IRUGO, show_alarm, NULL, 5); +static SENSOR_DEVICE_ATTR(in6_alarm, S_IRUGO, show_alarm, NULL, 6); +static SENSOR_DEVICE_ATTR(in7_alarm, S_IRUGO, show_alarm, NULL, 7); +static SENSOR_DEVICE_ATTR(in8_alarm, S_IRUGO, show_alarm, NULL, 8); +static SENSOR_DEVICE_ATTR(temp1_alarm, S_IRUGO, show_alarm, NULL, 11); +static SENSOR_DEVICE_ATTR(temp2_alarm, S_IRUGO, show_alarm, NULL, 12); +static SENSOR_DEVICE_ATTR(temp3_alarm, S_IRUGO, show_alarm, NULL, 13); +static SENSOR_DEVICE_ATTR(fan1_alarm, S_IRUGO, show_alarm, NULL, 16); +static SENSOR_DEVICE_ATTR(fan2_alarm, S_IRUGO, show_alarm, NULL, 17); +static SENSOR_DEVICE_ATTR(fan3_alarm, S_IRUGO, show_alarm, NULL, 18); +static DEVICE_ATTR(alarms_in, S_IRUGO, show_alarms_in, NULL); +static DEVICE_ATTR(alarms_fan, S_IRUGO, show_alarms_fan, NULL); +static DEVICE_ATTR(alarms_temp, S_IRUGO, show_alarms_temp, NULL); + +static DEVICE_ATTR(name, S_IRUGO, show_name, NULL); + +static struct attribute *f71805f_attributes[] = { + &dev_attr_in0_input.attr, + &dev_attr_in0_max.attr, + &dev_attr_in0_min.attr, + &sensor_dev_attr_in1_input.dev_attr.attr, + &sensor_dev_attr_in1_max.dev_attr.attr, + &sensor_dev_attr_in1_min.dev_attr.attr, + &sensor_dev_attr_in2_input.dev_attr.attr, + &sensor_dev_attr_in2_max.dev_attr.attr, + &sensor_dev_attr_in2_min.dev_attr.attr, + &sensor_dev_attr_in3_input.dev_attr.attr, + &sensor_dev_attr_in3_max.dev_attr.attr, + &sensor_dev_attr_in3_min.dev_attr.attr, + &sensor_dev_attr_in4_input.dev_attr.attr, + &sensor_dev_attr_in4_max.dev_attr.attr, + &sensor_dev_attr_in4_min.dev_attr.attr, + &sensor_dev_attr_in5_input.dev_attr.attr, + &sensor_dev_attr_in5_max.dev_attr.attr, + &sensor_dev_attr_in5_min.dev_attr.attr, + &sensor_dev_attr_in6_input.dev_attr.attr, + &sensor_dev_attr_in6_max.dev_attr.attr, + &sensor_dev_attr_in6_min.dev_attr.attr, + &sensor_dev_attr_in7_input.dev_attr.attr, + &sensor_dev_attr_in7_max.dev_attr.attr, + &sensor_dev_attr_in7_min.dev_attr.attr, + &sensor_dev_attr_in8_input.dev_attr.attr, + &sensor_dev_attr_in8_max.dev_attr.attr, + &sensor_dev_attr_in8_min.dev_attr.attr, + + &sensor_dev_attr_temp1_input.dev_attr.attr, + &sensor_dev_attr_temp1_max.dev_attr.attr, + &sensor_dev_attr_temp1_max_hyst.dev_attr.attr, + &sensor_dev_attr_temp1_type.dev_attr.attr, + &sensor_dev_attr_temp2_input.dev_attr.attr, + &sensor_dev_attr_temp2_max.dev_attr.attr, + &sensor_dev_attr_temp2_max_hyst.dev_attr.attr, + &sensor_dev_attr_temp2_type.dev_attr.attr, + &sensor_dev_attr_temp3_input.dev_attr.attr, + &sensor_dev_attr_temp3_max.dev_attr.attr, + &sensor_dev_attr_temp3_max_hyst.dev_attr.attr, + &sensor_dev_attr_temp3_type.dev_attr.attr, + + &sensor_dev_attr_in0_alarm.dev_attr.attr, + &sensor_dev_attr_in1_alarm.dev_attr.attr, + &sensor_dev_attr_in2_alarm.dev_attr.attr, + &sensor_dev_attr_in3_alarm.dev_attr.attr, + &sensor_dev_attr_in4_alarm.dev_attr.attr, + &sensor_dev_attr_in5_alarm.dev_attr.attr, + &sensor_dev_attr_in6_alarm.dev_attr.attr, + &sensor_dev_attr_in7_alarm.dev_attr.attr, + &sensor_dev_attr_in8_alarm.dev_attr.attr, + &dev_attr_alarms_in.attr, + &sensor_dev_attr_temp1_alarm.dev_attr.attr, + &sensor_dev_attr_temp2_alarm.dev_attr.attr, + &sensor_dev_attr_temp3_alarm.dev_attr.attr, + &dev_attr_alarms_temp.attr, + &dev_attr_alarms_fan.attr, + + &dev_attr_name.attr, + NULL }; -static struct sensor_device_attribute f71805f_sensor_attr[] = { - SENSOR_ATTR(in1_input, S_IRUGO, show_in, NULL, 1), - SENSOR_ATTR(in1_max, S_IRUGO | S_IWUSR, - show_in_max, set_in_max, 1), - SENSOR_ATTR(in1_min, S_IRUGO | S_IWUSR, - show_in_min, set_in_min, 1), - SENSOR_ATTR(in2_input, S_IRUGO, show_in, NULL, 2), - SENSOR_ATTR(in2_max, S_IRUGO | S_IWUSR, - show_in_max, set_in_max, 2), - SENSOR_ATTR(in2_min, S_IRUGO | S_IWUSR, - show_in_min, set_in_min, 2), - SENSOR_ATTR(in3_input, S_IRUGO, show_in, NULL, 3), - SENSOR_ATTR(in3_max, S_IRUGO | S_IWUSR, - show_in_max, set_in_max, 3), - SENSOR_ATTR(in3_min, S_IRUGO | S_IWUSR, - show_in_min, set_in_min, 3), - SENSOR_ATTR(in4_input, S_IRUGO, show_in, NULL, 4), - SENSOR_ATTR(in4_max, S_IRUGO | S_IWUSR, - show_in_max, set_in_max, 4), - SENSOR_ATTR(in4_min, S_IRUGO | S_IWUSR, - show_in_min, set_in_min, 4), - SENSOR_ATTR(in5_input, S_IRUGO, show_in, NULL, 5), - SENSOR_ATTR(in5_max, S_IRUGO | S_IWUSR, - show_in_max, set_in_max, 5), - SENSOR_ATTR(in5_min, S_IRUGO | S_IWUSR, - show_in_min, set_in_min, 5), - SENSOR_ATTR(in6_input, S_IRUGO, show_in, NULL, 6), - SENSOR_ATTR(in6_max, S_IRUGO | S_IWUSR, - show_in_max, set_in_max, 6), - SENSOR_ATTR(in6_min, S_IRUGO | S_IWUSR, - show_in_min, set_in_min, 6), - SENSOR_ATTR(in7_input, S_IRUGO, show_in, NULL, 7), - SENSOR_ATTR(in7_max, S_IRUGO | S_IWUSR, - show_in_max, set_in_max, 7), - SENSOR_ATTR(in7_min, S_IRUGO | S_IWUSR, - show_in_min, set_in_min, 7), - SENSOR_ATTR(in8_input, S_IRUGO, show_in, NULL, 8), - SENSOR_ATTR(in8_max, S_IRUGO | S_IWUSR, - show_in_max, set_in_max, 8), - SENSOR_ATTR(in8_min, S_IRUGO | S_IWUSR, - show_in_min, set_in_min, 8), - - SENSOR_ATTR(temp1_input, S_IRUGO, show_temp, NULL, 0), - SENSOR_ATTR(temp1_max, S_IRUGO | S_IWUSR, - show_temp_max, set_temp_max, 0), - SENSOR_ATTR(temp1_max_hyst, S_IRUGO | S_IWUSR, - show_temp_hyst, set_temp_hyst, 0), - SENSOR_ATTR(temp1_type, S_IRUGO, show_temp_type, NULL, 0), - SENSOR_ATTR(temp2_input, S_IRUGO, show_temp, NULL, 1), - SENSOR_ATTR(temp2_max, S_IRUGO | S_IWUSR, - show_temp_max, set_temp_max, 1), - SENSOR_ATTR(temp2_max_hyst, S_IRUGO | S_IWUSR, - show_temp_hyst, set_temp_hyst, 1), - SENSOR_ATTR(temp2_type, S_IRUGO, show_temp_type, NULL, 1), - SENSOR_ATTR(temp3_input, S_IRUGO, show_temp, NULL, 2), - SENSOR_ATTR(temp3_max, S_IRUGO | S_IWUSR, - show_temp_max, set_temp_max, 2), - SENSOR_ATTR(temp3_max_hyst, S_IRUGO | S_IWUSR, - show_temp_hyst, set_temp_hyst, 2), - SENSOR_ATTR(temp3_type, S_IRUGO, show_temp_type, NULL, 2), - - SENSOR_ATTR(in0_alarm, S_IRUGO, show_alarm, NULL, 0), - SENSOR_ATTR(in1_alarm, S_IRUGO, show_alarm, NULL, 1), - SENSOR_ATTR(in2_alarm, S_IRUGO, show_alarm, NULL, 2), - SENSOR_ATTR(in3_alarm, S_IRUGO, show_alarm, NULL, 3), - SENSOR_ATTR(in4_alarm, S_IRUGO, show_alarm, NULL, 4), - SENSOR_ATTR(in5_alarm, S_IRUGO, show_alarm, NULL, 5), - SENSOR_ATTR(in6_alarm, S_IRUGO, show_alarm, NULL, 6), - SENSOR_ATTR(in7_alarm, S_IRUGO, show_alarm, NULL, 7), - SENSOR_ATTR(in8_alarm, S_IRUGO, show_alarm, NULL, 8), - SENSOR_ATTR(temp1_alarm, S_IRUGO, show_alarm, NULL, 11), - SENSOR_ATTR(temp2_alarm, S_IRUGO, show_alarm, NULL, 12), - SENSOR_ATTR(temp3_alarm, S_IRUGO, show_alarm, NULL, 13), +static const struct attribute_group f71805f_group = { + .attrs = f71805f_attributes, }; -static struct sensor_device_attribute f71805f_fan_attr[] = { - SENSOR_ATTR(fan1_input, S_IRUGO, show_fan, NULL, 0), - SENSOR_ATTR(fan1_min, S_IRUGO | S_IWUSR, - show_fan_min, set_fan_min, 0), - SENSOR_ATTR(fan1_alarm, S_IRUGO, show_alarm, NULL, 16), - SENSOR_ATTR(fan2_input, S_IRUGO, show_fan, NULL, 1), - SENSOR_ATTR(fan2_min, S_IRUGO | S_IWUSR, - show_fan_min, set_fan_min, 1), - SENSOR_ATTR(fan2_alarm, S_IRUGO, show_alarm, NULL, 17), - SENSOR_ATTR(fan3_input, S_IRUGO, show_fan, NULL, 2), - SENSOR_ATTR(fan3_min, S_IRUGO | S_IWUSR, - show_fan_min, set_fan_min, 2), - SENSOR_ATTR(fan3_alarm, S_IRUGO, show_alarm, NULL, 18), +static struct attribute *f71805f_attributes_fan[3][4] = { + { + &sensor_dev_attr_fan1_input.dev_attr.attr, + &sensor_dev_attr_fan1_min.dev_attr.attr, + &sensor_dev_attr_fan1_alarm.dev_attr.attr, + NULL + }, { + &sensor_dev_attr_fan2_input.dev_attr.attr, + &sensor_dev_attr_fan2_min.dev_attr.attr, + &sensor_dev_attr_fan2_alarm.dev_attr.attr, + NULL + }, { + &sensor_dev_attr_fan3_input.dev_attr.attr, + &sensor_dev_attr_fan3_min.dev_attr.attr, + &sensor_dev_attr_fan3_alarm.dev_attr.attr, + NULL + } +}; + +static const struct attribute_group f71805f_group_fan[3] = { + { .attrs = f71805f_attributes_fan[0] }, + { .attrs = f71805f_attributes_fan[1] }, + { .attrs = f71805f_attributes_fan[2] }, }; /* @@ -738,43 +824,35 @@ static int __devinit f71805f_probe(struct platform_device *pdev) platform_set_drvdata(pdev, data); - data->class_dev = hwmon_device_register(&pdev->dev); - if (IS_ERR(data->class_dev)) { - err = PTR_ERR(data->class_dev); - dev_err(&pdev->dev, "Class registration failed (%d)\n", err); - goto exit_free; - } - /* Initialize the F71805F chip */ f71805f_init_device(data); /* Register sysfs interface files */ - for (i = 0; i < ARRAY_SIZE(f71805f_dev_attr); i++) { - err = device_create_file(&pdev->dev, &f71805f_dev_attr[i]); - if (err) - goto exit_class; - } - for (i = 0; i < ARRAY_SIZE(f71805f_sensor_attr); i++) { - err = device_create_file(&pdev->dev, - &f71805f_sensor_attr[i].dev_attr); - if (err) - goto exit_class; - } - for (i = 0; i < ARRAY_SIZE(f71805f_fan_attr); i++) { - if (!(data->fan_enabled & (1 << (i / 3)))) + if ((err = sysfs_create_group(&pdev->dev.kobj, &f71805f_group))) + goto exit_free; + for (i = 0; i < 3; i++) { + if (!(data->fan_enabled & (1 << i))) continue; - err = device_create_file(&pdev->dev, - &f71805f_fan_attr[i].dev_attr); - if (err) - goto exit_class; + if ((err = sysfs_create_group(&pdev->dev.kobj, + &f71805f_group_fan[i]))) + goto exit_remove_files; + } + + data->class_dev = hwmon_device_register(&pdev->dev); + if (IS_ERR(data->class_dev)) { + err = PTR_ERR(data->class_dev); + dev_err(&pdev->dev, "Class registration failed (%d)\n", err); + goto exit_remove_files; } return 0; -exit_class: - dev_err(&pdev->dev, "Sysfs interface creation failed\n"); - hwmon_device_unregister(data->class_dev); +exit_remove_files: + sysfs_remove_group(&pdev->dev.kobj, &f71805f_group); + for (i = 0; i < 3; i++) + sysfs_remove_group(&pdev->dev.kobj, &f71805f_group_fan[i]); exit_free: + platform_set_drvdata(pdev, NULL); kfree(data); exit: return err; @@ -783,9 +861,13 @@ static int __devinit f71805f_probe(struct platform_device *pdev) static int __devexit f71805f_remove(struct platform_device *pdev) { struct f71805f_data *data = platform_get_drvdata(pdev); + int i; platform_set_drvdata(pdev, NULL); hwmon_device_unregister(data->class_dev); + sysfs_remove_group(&pdev->dev.kobj, &f71805f_group); + for (i = 0; i < 3; i++) + sysfs_remove_group(&pdev->dev.kobj, &f71805f_group_fan[i]); kfree(data); return 0; diff --git a/drivers/hwmon/lm63.c b/drivers/hwmon/lm63.c index 00a50bea7cbd..d69f3cf07122 100644 --- a/drivers/hwmon/lm63.c +++ b/drivers/hwmon/lm63.c @@ -46,6 +46,7 @@ #include #include #include +#include /* * Addresses to scan @@ -370,6 +371,42 @@ static SENSOR_DEVICE_ATTR(temp1_max_alarm, S_IRUGO, show_alarm, NULL, 6); /* Raw alarm file for compatibility */ static DEVICE_ATTR(alarms, S_IRUGO, show_alarms, NULL); +static struct attribute *lm63_attributes[] = { + &dev_attr_pwm1.attr, + &dev_attr_pwm1_enable.attr, + &sensor_dev_attr_temp1_input.dev_attr.attr, + &sensor_dev_attr_temp2_input.dev_attr.attr, + &sensor_dev_attr_temp2_min.dev_attr.attr, + &sensor_dev_attr_temp1_max.dev_attr.attr, + &sensor_dev_attr_temp2_max.dev_attr.attr, + &sensor_dev_attr_temp2_crit.dev_attr.attr, + &dev_attr_temp2_crit_hyst.attr, + + &sensor_dev_attr_temp2_crit_alarm.dev_attr.attr, + &sensor_dev_attr_temp2_input_fault.dev_attr.attr, + &sensor_dev_attr_temp2_min_alarm.dev_attr.attr, + &sensor_dev_attr_temp2_max_alarm.dev_attr.attr, + &sensor_dev_attr_temp1_max_alarm.dev_attr.attr, + &dev_attr_alarms.attr, + NULL +}; + +static const struct attribute_group lm63_group = { + .attrs = lm63_attributes, +}; + +static struct attribute *lm63_attributes_fan1[] = { + &sensor_dev_attr_fan1_input.dev_attr.attr, + &sensor_dev_attr_fan1_min.dev_attr.attr, + + &sensor_dev_attr_fan1_min_alarm.dev_attr.attr, + NULL +}; + +static const struct attribute_group lm63_group_fan1 = { + .attrs = lm63_attributes_fan1, +}; + /* * Real code */ @@ -456,50 +493,26 @@ static int lm63_detect(struct i2c_adapter *adapter, int address, int kind) lm63_init_client(new_client); /* Register sysfs hooks */ + if ((err = sysfs_create_group(&new_client->dev.kobj, + &lm63_group))) + goto exit_detach; + if (data->config & 0x04) { /* tachometer enabled */ + if ((err = sysfs_create_group(&new_client->dev.kobj, + &lm63_group_fan1))) + goto exit_remove_files; + } + data->class_dev = hwmon_device_register(&new_client->dev); if (IS_ERR(data->class_dev)) { err = PTR_ERR(data->class_dev); - goto exit_detach; + goto exit_remove_files; } - if (data->config & 0x04) { /* tachometer enabled */ - device_create_file(&new_client->dev, - &sensor_dev_attr_fan1_input.dev_attr); - device_create_file(&new_client->dev, - &sensor_dev_attr_fan1_min.dev_attr); - device_create_file(&new_client->dev, - &sensor_dev_attr_fan1_min_alarm.dev_attr); - } - device_create_file(&new_client->dev, &dev_attr_pwm1); - device_create_file(&new_client->dev, &dev_attr_pwm1_enable); - device_create_file(&new_client->dev, - &sensor_dev_attr_temp1_input.dev_attr); - device_create_file(&new_client->dev, - &sensor_dev_attr_temp2_input.dev_attr); - device_create_file(&new_client->dev, - &sensor_dev_attr_temp2_min.dev_attr); - device_create_file(&new_client->dev, - &sensor_dev_attr_temp1_max.dev_attr); - device_create_file(&new_client->dev, - &sensor_dev_attr_temp2_max.dev_attr); - device_create_file(&new_client->dev, - &sensor_dev_attr_temp2_crit.dev_attr); - device_create_file(&new_client->dev, &dev_attr_temp2_crit_hyst); - - device_create_file(&new_client->dev, - &sensor_dev_attr_temp2_input_fault.dev_attr); - device_create_file(&new_client->dev, - &sensor_dev_attr_temp2_min_alarm.dev_attr); - device_create_file(&new_client->dev, - &sensor_dev_attr_temp1_max_alarm.dev_attr); - device_create_file(&new_client->dev, - &sensor_dev_attr_temp2_max_alarm.dev_attr); - device_create_file(&new_client->dev, - &sensor_dev_attr_temp2_crit_alarm.dev_attr); - device_create_file(&new_client->dev, &dev_attr_alarms); - return 0; +exit_remove_files: + sysfs_remove_group(&new_client->dev.kobj, &lm63_group); + sysfs_remove_group(&new_client->dev.kobj, &lm63_group_fan1); exit_detach: i2c_detach_client(new_client); exit_free: @@ -549,6 +562,8 @@ static int lm63_detach_client(struct i2c_client *client) int err; hwmon_device_unregister(data->class_dev); + sysfs_remove_group(&client->dev.kobj, &lm63_group); + sysfs_remove_group(&client->dev.kobj, &lm63_group_fan1); if ((err = i2c_detach_client(client))) return err; diff --git a/drivers/hwmon/lm83.c b/drivers/hwmon/lm83.c index ea224891d311..feb87b41e986 100644 --- a/drivers/hwmon/lm83.c +++ b/drivers/hwmon/lm83.c @@ -40,6 +40,7 @@ #include #include #include +#include /* * Addresses to scan @@ -234,6 +235,48 @@ static SENSOR_DEVICE_ATTR(temp2_max_alarm, S_IRUGO, show_alarm, NULL, 15); /* Raw alarm file for compatibility */ static DEVICE_ATTR(alarms, S_IRUGO, show_alarms, NULL); +static struct attribute *lm83_attributes[] = { + &sensor_dev_attr_temp1_input.dev_attr.attr, + &sensor_dev_attr_temp3_input.dev_attr.attr, + &sensor_dev_attr_temp1_max.dev_attr.attr, + &sensor_dev_attr_temp3_max.dev_attr.attr, + &sensor_dev_attr_temp1_crit.dev_attr.attr, + &sensor_dev_attr_temp3_crit.dev_attr.attr, + + &sensor_dev_attr_temp1_crit_alarm.dev_attr.attr, + &sensor_dev_attr_temp3_crit_alarm.dev_attr.attr, + &sensor_dev_attr_temp3_input_fault.dev_attr.attr, + &sensor_dev_attr_temp3_max_alarm.dev_attr.attr, + &sensor_dev_attr_temp1_max_alarm.dev_attr.attr, + &dev_attr_alarms.attr, + NULL +}; + +static const struct attribute_group lm83_group = { + .attrs = lm83_attributes, +}; + +static struct attribute *lm83_attributes_opt[] = { + &sensor_dev_attr_temp2_input.dev_attr.attr, + &sensor_dev_attr_temp4_input.dev_attr.attr, + &sensor_dev_attr_temp2_max.dev_attr.attr, + &sensor_dev_attr_temp4_max.dev_attr.attr, + &sensor_dev_attr_temp2_crit.dev_attr.attr, + &sensor_dev_attr_temp4_crit.dev_attr.attr, + + &sensor_dev_attr_temp2_crit_alarm.dev_attr.attr, + &sensor_dev_attr_temp4_crit_alarm.dev_attr.attr, + &sensor_dev_attr_temp4_input_fault.dev_attr.attr, + &sensor_dev_attr_temp4_max_alarm.dev_attr.attr, + &sensor_dev_attr_temp2_input_fault.dev_attr.attr, + &sensor_dev_attr_temp2_max_alarm.dev_attr.attr, + NULL +}; + +static const struct attribute_group lm83_group_opt = { + .attrs = lm83_attributes_opt, +}; + /* * Real code */ @@ -342,82 +385,32 @@ static int lm83_detect(struct i2c_adapter *adapter, int address, int kind) goto exit_free; /* - * Initialize the LM83 chip - * (Nothing to do for this one.) - */ - - /* Register sysfs hooks */ - data->class_dev = hwmon_device_register(&new_client->dev); - if (IS_ERR(data->class_dev)) { - err = PTR_ERR(data->class_dev); - goto exit_detach; - } - - /* + * Register sysfs hooks * The LM82 can only monitor one external diode which is * at the same register as the LM83 temp3 entry - so we * declare 1 and 3 common, and then 2 and 4 only for the LM83. */ - device_create_file(&new_client->dev, - &sensor_dev_attr_temp1_input.dev_attr); - device_create_file(&new_client->dev, - &sensor_dev_attr_temp3_input.dev_attr); - - device_create_file(&new_client->dev, - &sensor_dev_attr_temp1_max.dev_attr); - device_create_file(&new_client->dev, - &sensor_dev_attr_temp3_max.dev_attr); - - device_create_file(&new_client->dev, - &sensor_dev_attr_temp1_crit.dev_attr); - device_create_file(&new_client->dev, - &sensor_dev_attr_temp3_crit.dev_attr); - - device_create_file(&new_client->dev, - &sensor_dev_attr_temp3_input_fault.dev_attr); - device_create_file(&new_client->dev, - &sensor_dev_attr_temp1_max_alarm.dev_attr); - device_create_file(&new_client->dev, - &sensor_dev_attr_temp3_max_alarm.dev_attr); - device_create_file(&new_client->dev, - &sensor_dev_attr_temp1_crit_alarm.dev_attr); - device_create_file(&new_client->dev, - &sensor_dev_attr_temp3_crit_alarm.dev_attr); - device_create_file(&new_client->dev, &dev_attr_alarms); + if ((err = sysfs_create_group(&new_client->dev.kobj, &lm83_group))) + goto exit_detach; if (kind == lm83) { - device_create_file(&new_client->dev, - &sensor_dev_attr_temp2_input.dev_attr); - device_create_file(&new_client->dev, - &sensor_dev_attr_temp4_input.dev_attr); + if ((err = sysfs_create_group(&new_client->dev.kobj, + &lm83_group_opt))) + goto exit_remove_files; + } - device_create_file(&new_client->dev, - &sensor_dev_attr_temp2_max.dev_attr); - device_create_file(&new_client->dev, - &sensor_dev_attr_temp4_max.dev_attr); - - device_create_file(&new_client->dev, - &sensor_dev_attr_temp2_crit.dev_attr); - device_create_file(&new_client->dev, - &sensor_dev_attr_temp4_crit.dev_attr); - - device_create_file(&new_client->dev, - &sensor_dev_attr_temp2_input_fault.dev_attr); - device_create_file(&new_client->dev, - &sensor_dev_attr_temp4_input_fault.dev_attr); - device_create_file(&new_client->dev, - &sensor_dev_attr_temp2_max_alarm.dev_attr); - device_create_file(&new_client->dev, - &sensor_dev_attr_temp4_max_alarm.dev_attr); - device_create_file(&new_client->dev, - &sensor_dev_attr_temp2_crit_alarm.dev_attr); - device_create_file(&new_client->dev, - &sensor_dev_attr_temp4_crit_alarm.dev_attr); + data->class_dev = hwmon_device_register(&new_client->dev); + if (IS_ERR(data->class_dev)) { + err = PTR_ERR(data->class_dev); + goto exit_remove_files; } return 0; +exit_remove_files: + sysfs_remove_group(&new_client->dev.kobj, &lm83_group); + sysfs_remove_group(&new_client->dev.kobj, &lm83_group_opt); exit_detach: i2c_detach_client(new_client); exit_free: @@ -432,6 +425,8 @@ static int lm83_detach_client(struct i2c_client *client) int err; hwmon_device_unregister(data->class_dev); + sysfs_remove_group(&client->dev.kobj, &lm83_group); + sysfs_remove_group(&client->dev.kobj, &lm83_group_opt); if ((err = i2c_detach_client(client))) return err; diff --git a/drivers/hwmon/lm90.c b/drivers/hwmon/lm90.c index 77f8e3f7fd49..6882ce75feee 100644 --- a/drivers/hwmon/lm90.c +++ b/drivers/hwmon/lm90.c @@ -79,6 +79,7 @@ #include #include #include +#include /* * Addresses to scan @@ -366,6 +367,33 @@ static SENSOR_DEVICE_ATTR(temp1_max_alarm, S_IRUGO, show_alarm, NULL, 6); /* Raw alarm file for compatibility */ static DEVICE_ATTR(alarms, S_IRUGO, show_alarms, NULL); +static struct attribute *lm90_attributes[] = { + &sensor_dev_attr_temp1_input.dev_attr.attr, + &sensor_dev_attr_temp2_input.dev_attr.attr, + &sensor_dev_attr_temp1_min.dev_attr.attr, + &sensor_dev_attr_temp2_min.dev_attr.attr, + &sensor_dev_attr_temp1_max.dev_attr.attr, + &sensor_dev_attr_temp2_max.dev_attr.attr, + &sensor_dev_attr_temp1_crit.dev_attr.attr, + &sensor_dev_attr_temp2_crit.dev_attr.attr, + &sensor_dev_attr_temp1_crit_hyst.dev_attr.attr, + &sensor_dev_attr_temp2_crit_hyst.dev_attr.attr, + + &sensor_dev_attr_temp1_crit_alarm.dev_attr.attr, + &sensor_dev_attr_temp2_crit_alarm.dev_attr.attr, + &sensor_dev_attr_temp2_input_fault.dev_attr.attr, + &sensor_dev_attr_temp2_min_alarm.dev_attr.attr, + &sensor_dev_attr_temp2_max_alarm.dev_attr.attr, + &sensor_dev_attr_temp1_min_alarm.dev_attr.attr, + &sensor_dev_attr_temp1_max_alarm.dev_attr.attr, + &dev_attr_alarms.attr, + NULL +}; + +static const struct attribute_group lm90_group = { + .attrs = lm90_attributes, +}; + /* pec used for ADM1032 only */ static ssize_t show_pec(struct device *dev, struct device_attribute *dummy, char *buf) @@ -589,54 +617,25 @@ static int lm90_detect(struct i2c_adapter *adapter, int address, int kind) lm90_init_client(new_client); /* Register sysfs hooks */ + if ((err = sysfs_create_group(&new_client->dev.kobj, &lm90_group))) + goto exit_detach; + if (new_client->flags & I2C_CLIENT_PEC) { + if ((err = device_create_file(&new_client->dev, + &dev_attr_pec))) + goto exit_remove_files; + } + data->class_dev = hwmon_device_register(&new_client->dev); if (IS_ERR(data->class_dev)) { err = PTR_ERR(data->class_dev); - goto exit_detach; + goto exit_remove_files; } - device_create_file(&new_client->dev, - &sensor_dev_attr_temp1_input.dev_attr); - device_create_file(&new_client->dev, - &sensor_dev_attr_temp2_input.dev_attr); - device_create_file(&new_client->dev, - &sensor_dev_attr_temp1_min.dev_attr); - device_create_file(&new_client->dev, - &sensor_dev_attr_temp2_min.dev_attr); - device_create_file(&new_client->dev, - &sensor_dev_attr_temp1_max.dev_attr); - device_create_file(&new_client->dev, - &sensor_dev_attr_temp2_max.dev_attr); - device_create_file(&new_client->dev, - &sensor_dev_attr_temp1_crit.dev_attr); - device_create_file(&new_client->dev, - &sensor_dev_attr_temp2_crit.dev_attr); - device_create_file(&new_client->dev, - &sensor_dev_attr_temp1_crit_hyst.dev_attr); - device_create_file(&new_client->dev, - &sensor_dev_attr_temp2_crit_hyst.dev_attr); - - device_create_file(&new_client->dev, - &sensor_dev_attr_temp2_input_fault.dev_attr); - device_create_file(&new_client->dev, - &sensor_dev_attr_temp1_min_alarm.dev_attr); - device_create_file(&new_client->dev, - &sensor_dev_attr_temp2_min_alarm.dev_attr); - device_create_file(&new_client->dev, - &sensor_dev_attr_temp1_max_alarm.dev_attr); - device_create_file(&new_client->dev, - &sensor_dev_attr_temp2_max_alarm.dev_attr); - device_create_file(&new_client->dev, - &sensor_dev_attr_temp1_crit_alarm.dev_attr); - device_create_file(&new_client->dev, - &sensor_dev_attr_temp2_crit_alarm.dev_attr); - device_create_file(&new_client->dev, &dev_attr_alarms); - - if (new_client->flags & I2C_CLIENT_PEC) - device_create_file(&new_client->dev, &dev_attr_pec); - return 0; +exit_remove_files: + sysfs_remove_group(&new_client->dev.kobj, &lm90_group); + device_remove_file(&new_client->dev, &dev_attr_pec); exit_detach: i2c_detach_client(new_client); exit_free: @@ -669,6 +668,8 @@ static int lm90_detach_client(struct i2c_client *client) int err; hwmon_device_unregister(data->class_dev); + sysfs_remove_group(&client->dev.kobj, &lm90_group); + device_remove_file(&client->dev, &dev_attr_pec); if ((err = i2c_detach_client(client))) return err; From 87808be4f97674e6a2982fa835080cc0320dcbdc Mon Sep 17 00:00:00 2001 From: Jean Delvare Date: Sun, 24 Sep 2006 21:17:13 +0200 Subject: [PATCH 32/39] Fix unchecked return status, batch 5 hwmon: Fix unchecked return status, batch 5 Fix up some hwmon drivers so that they no longer ignore return status from device_create_file(). Signed-off-by: Jean Delvare Signed-off-by: Greg Kroah-Hartman --- drivers/hwmon/fscher.c | 94 +++++++--------- drivers/hwmon/fscpos.c | 75 ++++++++----- drivers/hwmon/gl518sm.c | 74 +++++++------ drivers/hwmon/gl520sm.c | 128 ++++++++++++++-------- drivers/hwmon/it87.c | 234 +++++++++++++++++++++++++--------------- 5 files changed, 362 insertions(+), 243 deletions(-) diff --git a/drivers/hwmon/fscher.c b/drivers/hwmon/fscher.c index 6bc76b407636..19717752cfca 100644 --- a/drivers/hwmon/fscher.c +++ b/drivers/hwmon/fscher.c @@ -34,6 +34,7 @@ #include #include #include +#include /* * Addresses to scan @@ -240,47 +241,45 @@ sysfs_alarms(FSCHER_REG_EVENTS) sysfs_control(FSCHER_REG_CONTROL) sysfs_watchdog(FSCHER_REG_WDOG_CONTROL, FSCHER_REG_WDOG_STATE, FSCHER_REG_WDOG_PRESET) -#define device_create_file_fan(client, offset) \ -do { \ - device_create_file(&client->dev, &dev_attr_fan##offset##_status); \ - device_create_file(&client->dev, &dev_attr_pwm##offset); \ - device_create_file(&client->dev, &dev_attr_fan##offset##_div); \ - device_create_file(&client->dev, &dev_attr_fan##offset##_input); \ -} while (0) +static struct attribute *fscher_attributes[] = { + &dev_attr_revision.attr, + &dev_attr_alarms.attr, + &dev_attr_control.attr, -#define device_create_file_temp(client, offset) \ -do { \ - device_create_file(&client->dev, &dev_attr_temp##offset##_status); \ - device_create_file(&client->dev, &dev_attr_temp##offset##_input); \ -} while (0) + &dev_attr_watchdog_status.attr, + &dev_attr_watchdog_control.attr, + &dev_attr_watchdog_preset.attr, -#define device_create_file_in(client, offset) \ -do { \ - device_create_file(&client->dev, &dev_attr_in##offset##_input); \ -} while (0) + &dev_attr_in0_input.attr, + &dev_attr_in1_input.attr, + &dev_attr_in2_input.attr, -#define device_create_file_revision(client) \ -do { \ - device_create_file(&client->dev, &dev_attr_revision); \ -} while (0) + &dev_attr_fan1_status.attr, + &dev_attr_fan1_div.attr, + &dev_attr_fan1_input.attr, + &dev_attr_pwm1.attr, + &dev_attr_fan2_status.attr, + &dev_attr_fan2_div.attr, + &dev_attr_fan2_input.attr, + &dev_attr_pwm2.attr, + &dev_attr_fan3_status.attr, + &dev_attr_fan3_div.attr, + &dev_attr_fan3_input.attr, + &dev_attr_pwm3.attr, -#define device_create_file_alarms(client) \ -do { \ - device_create_file(&client->dev, &dev_attr_alarms); \ -} while (0) + &dev_attr_temp1_status.attr, + &dev_attr_temp1_input.attr, + &dev_attr_temp2_status.attr, + &dev_attr_temp2_input.attr, + &dev_attr_temp3_status.attr, + &dev_attr_temp3_input.attr, + NULL +}; -#define device_create_file_control(client) \ -do { \ - device_create_file(&client->dev, &dev_attr_control); \ -} while (0) +static const struct attribute_group fscher_group = { + .attrs = fscher_attributes, +}; -#define device_create_file_watchdog(client) \ -do { \ - device_create_file(&client->dev, &dev_attr_watchdog_status); \ - device_create_file(&client->dev, &dev_attr_watchdog_control); \ - device_create_file(&client->dev, &dev_attr_watchdog_preset); \ -} while (0) - /* * Real code */ @@ -342,31 +341,19 @@ static int fscher_detect(struct i2c_adapter *adapter, int address, int kind) fscher_init_client(new_client); /* Register sysfs hooks */ + if ((err = sysfs_create_group(&new_client->dev.kobj, &fscher_group))) + goto exit_detach; + data->class_dev = hwmon_device_register(&new_client->dev); if (IS_ERR(data->class_dev)) { err = PTR_ERR(data->class_dev); - goto exit_detach; + goto exit_remove_files; } - device_create_file_revision(new_client); - device_create_file_alarms(new_client); - device_create_file_control(new_client); - device_create_file_watchdog(new_client); - - device_create_file_in(new_client, 0); - device_create_file_in(new_client, 1); - device_create_file_in(new_client, 2); - - device_create_file_fan(new_client, 1); - device_create_file_fan(new_client, 2); - device_create_file_fan(new_client, 3); - - device_create_file_temp(new_client, 1); - device_create_file_temp(new_client, 2); - device_create_file_temp(new_client, 3); - return 0; +exit_remove_files: + sysfs_remove_group(&new_client->dev.kobj, &fscher_group); exit_detach: i2c_detach_client(new_client); exit_free: @@ -381,6 +368,7 @@ static int fscher_detach_client(struct i2c_client *client) int err; hwmon_device_unregister(data->class_dev); + sysfs_remove_group(&client->dev.kobj, &fscher_group); if ((err = i2c_detach_client(client))) return err; diff --git a/drivers/hwmon/fscpos.c b/drivers/hwmon/fscpos.c index 6dc4846b9eeb..ea506a77f9c9 100644 --- a/drivers/hwmon/fscpos.c +++ b/drivers/hwmon/fscpos.c @@ -38,6 +38,7 @@ #include #include #include +#include /* * Addresses to scan @@ -432,6 +433,44 @@ static DEVICE_ATTR(in0_input, S_IRUGO, show_volt_12, NULL); static DEVICE_ATTR(in1_input, S_IRUGO, show_volt_5, NULL); static DEVICE_ATTR(in2_input, S_IRUGO, show_volt_batt, NULL); +static struct attribute *fscpos_attributes[] = { + &dev_attr_event.attr, + &dev_attr_in0_input.attr, + &dev_attr_in1_input.attr, + &dev_attr_in2_input.attr, + + &dev_attr_wdog_control.attr, + &dev_attr_wdog_preset.attr, + &dev_attr_wdog_state.attr, + + &dev_attr_temp1_input.attr, + &dev_attr_temp1_status.attr, + &dev_attr_temp1_reset.attr, + &dev_attr_temp2_input.attr, + &dev_attr_temp2_status.attr, + &dev_attr_temp2_reset.attr, + &dev_attr_temp3_input.attr, + &dev_attr_temp3_status.attr, + &dev_attr_temp3_reset.attr, + + &dev_attr_fan1_input.attr, + &dev_attr_fan1_status.attr, + &dev_attr_fan1_ripple.attr, + &dev_attr_pwm1.attr, + &dev_attr_fan2_input.attr, + &dev_attr_fan2_status.attr, + &dev_attr_fan2_ripple.attr, + &dev_attr_pwm2.attr, + &dev_attr_fan3_input.attr, + &dev_attr_fan3_status.attr, + &dev_attr_fan3_ripple.attr, + NULL +}; + +static const struct attribute_group fscpos_group = { + .attrs = fscpos_attributes, +}; + static int fscpos_attach_adapter(struct i2c_adapter *adapter) { if (!(adapter->class & I2C_CLASS_HWMON)) @@ -497,42 +536,19 @@ static int fscpos_detect(struct i2c_adapter *adapter, int address, int kind) dev_info(&new_client->dev, "Found fscpos chip, rev %u\n", data->revision); /* Register sysfs hooks */ + if ((err = sysfs_create_group(&new_client->dev.kobj, &fscpos_group))) + goto exit_detach; + data->class_dev = hwmon_device_register(&new_client->dev); if (IS_ERR(data->class_dev)) { err = PTR_ERR(data->class_dev); - goto exit_detach; + goto exit_remove_files; } - device_create_file(&new_client->dev, &dev_attr_event); - device_create_file(&new_client->dev, &dev_attr_in0_input); - device_create_file(&new_client->dev, &dev_attr_in1_input); - device_create_file(&new_client->dev, &dev_attr_in2_input); - device_create_file(&new_client->dev, &dev_attr_wdog_control); - device_create_file(&new_client->dev, &dev_attr_wdog_preset); - device_create_file(&new_client->dev, &dev_attr_wdog_state); - device_create_file(&new_client->dev, &dev_attr_temp1_input); - device_create_file(&new_client->dev, &dev_attr_temp1_status); - device_create_file(&new_client->dev, &dev_attr_temp1_reset); - device_create_file(&new_client->dev, &dev_attr_temp2_input); - device_create_file(&new_client->dev, &dev_attr_temp2_status); - device_create_file(&new_client->dev, &dev_attr_temp2_reset); - device_create_file(&new_client->dev, &dev_attr_temp3_input); - device_create_file(&new_client->dev, &dev_attr_temp3_status); - device_create_file(&new_client->dev, &dev_attr_temp3_reset); - device_create_file(&new_client->dev, &dev_attr_fan1_input); - device_create_file(&new_client->dev, &dev_attr_fan1_status); - device_create_file(&new_client->dev, &dev_attr_fan1_ripple); - device_create_file(&new_client->dev, &dev_attr_pwm1); - device_create_file(&new_client->dev, &dev_attr_fan2_input); - device_create_file(&new_client->dev, &dev_attr_fan2_status); - device_create_file(&new_client->dev, &dev_attr_fan2_ripple); - device_create_file(&new_client->dev, &dev_attr_pwm2); - device_create_file(&new_client->dev, &dev_attr_fan3_input); - device_create_file(&new_client->dev, &dev_attr_fan3_status); - device_create_file(&new_client->dev, &dev_attr_fan3_ripple); - return 0; +exit_remove_files: + sysfs_remove_group(&new_client->dev.kobj, &fscpos_group); exit_detach: i2c_detach_client(new_client); exit_free: @@ -547,6 +563,7 @@ static int fscpos_detach_client(struct i2c_client *client) int err; hwmon_device_unregister(data->class_dev); + sysfs_remove_group(&client->dev.kobj, &fscpos_group); if ((err = i2c_detach_client(client))) return err; diff --git a/drivers/hwmon/gl518sm.c b/drivers/hwmon/gl518sm.c index 6606aabdb49d..c103640455a3 100644 --- a/drivers/hwmon/gl518sm.c +++ b/drivers/hwmon/gl518sm.c @@ -44,6 +44,7 @@ #include #include #include +#include /* Addresses to scan */ static unsigned short normal_i2c[] = { 0x2c, 0x2d, I2C_CLIENT_END }; @@ -340,6 +341,42 @@ static DEVICE_ATTR(beep_enable, S_IWUSR|S_IRUGO, static DEVICE_ATTR(beep_mask, S_IWUSR|S_IRUGO, show_beep_mask, set_beep_mask); +static struct attribute *gl518_attributes[] = { + &dev_attr_in0_input.attr, + &dev_attr_in1_input.attr, + &dev_attr_in2_input.attr, + &dev_attr_in3_input.attr, + &dev_attr_in0_min.attr, + &dev_attr_in1_min.attr, + &dev_attr_in2_min.attr, + &dev_attr_in3_min.attr, + &dev_attr_in0_max.attr, + &dev_attr_in1_max.attr, + &dev_attr_in2_max.attr, + &dev_attr_in3_max.attr, + + &dev_attr_fan1_auto.attr, + &dev_attr_fan1_input.attr, + &dev_attr_fan2_input.attr, + &dev_attr_fan1_min.attr, + &dev_attr_fan2_min.attr, + &dev_attr_fan1_div.attr, + &dev_attr_fan2_div.attr, + + &dev_attr_temp1_input.attr, + &dev_attr_temp1_max.attr, + &dev_attr_temp1_max_hyst.attr, + + &dev_attr_alarms.attr, + &dev_attr_beep_enable.attr, + &dev_attr_beep_mask.attr, + NULL +}; + +static const struct attribute_group gl518_group = { + .attrs = gl518_attributes, +}; + /* * Real code */ @@ -420,43 +457,19 @@ static int gl518_detect(struct i2c_adapter *adapter, int address, int kind) gl518_init_client((struct i2c_client *) new_client); /* Register sysfs hooks */ + if ((err = sysfs_create_group(&new_client->dev.kobj, &gl518_group))) + goto exit_detach; + data->class_dev = hwmon_device_register(&new_client->dev); if (IS_ERR(data->class_dev)) { err = PTR_ERR(data->class_dev); - goto exit_detach; + goto exit_remove_files; } - device_create_file(&new_client->dev, &dev_attr_in0_input); - device_create_file(&new_client->dev, &dev_attr_in1_input); - device_create_file(&new_client->dev, &dev_attr_in2_input); - device_create_file(&new_client->dev, &dev_attr_in3_input); - device_create_file(&new_client->dev, &dev_attr_in0_min); - device_create_file(&new_client->dev, &dev_attr_in1_min); - device_create_file(&new_client->dev, &dev_attr_in2_min); - device_create_file(&new_client->dev, &dev_attr_in3_min); - device_create_file(&new_client->dev, &dev_attr_in0_max); - device_create_file(&new_client->dev, &dev_attr_in1_max); - device_create_file(&new_client->dev, &dev_attr_in2_max); - device_create_file(&new_client->dev, &dev_attr_in3_max); - device_create_file(&new_client->dev, &dev_attr_fan1_auto); - device_create_file(&new_client->dev, &dev_attr_fan1_input); - device_create_file(&new_client->dev, &dev_attr_fan2_input); - device_create_file(&new_client->dev, &dev_attr_fan1_min); - device_create_file(&new_client->dev, &dev_attr_fan2_min); - device_create_file(&new_client->dev, &dev_attr_fan1_div); - device_create_file(&new_client->dev, &dev_attr_fan2_div); - device_create_file(&new_client->dev, &dev_attr_temp1_input); - device_create_file(&new_client->dev, &dev_attr_temp1_max); - device_create_file(&new_client->dev, &dev_attr_temp1_max_hyst); - device_create_file(&new_client->dev, &dev_attr_alarms); - device_create_file(&new_client->dev, &dev_attr_beep_enable); - device_create_file(&new_client->dev, &dev_attr_beep_mask); - return 0; -/* OK, this is not exactly good programming practice, usually. But it is - very code-efficient in this case. */ - +exit_remove_files: + sysfs_remove_group(&new_client->dev.kobj, &gl518_group); exit_detach: i2c_detach_client(new_client); exit_free: @@ -490,6 +503,7 @@ static int gl518_detach_client(struct i2c_client *client) int err; hwmon_device_unregister(data->class_dev); + sysfs_remove_group(&client->dev.kobj, &gl518_group); if ((err = i2c_detach_client(client))) return err; diff --git a/drivers/hwmon/gl520sm.c b/drivers/hwmon/gl520sm.c index 14e810f3c2c0..ebe7b9aaa916 100644 --- a/drivers/hwmon/gl520sm.c +++ b/drivers/hwmon/gl520sm.c @@ -30,6 +30,7 @@ #include #include #include +#include /* Type of the extra sensor */ static unsigned short extra_sensor_type; @@ -190,55 +191,29 @@ static DEVICE_ATTR(type##item, S_IRUGO, get_##type##0##item, NULL); #define sysfs_vid(n) \ sysfs_ro_n(cpu, n, _vid, GL520_REG_VID_INPUT) -#define device_create_file_vid(client, n) \ -device_create_file(&client->dev, &dev_attr_cpu##n##_vid) - #define sysfs_in(n) \ sysfs_ro_n(in, n, _input, GL520_REG_IN##n##INPUT) \ sysfs_rw_n(in, n, _min, GL520_REG_IN##n##_MIN) \ sysfs_rw_n(in, n, _max, GL520_REG_IN##n##_MAX) \ -#define device_create_file_in(client, n) \ -({device_create_file(&client->dev, &dev_attr_in##n##_input); \ -device_create_file(&client->dev, &dev_attr_in##n##_min); \ -device_create_file(&client->dev, &dev_attr_in##n##_max);}) - #define sysfs_fan(n) \ sysfs_ro_n(fan, n, _input, GL520_REG_FAN_INPUT) \ sysfs_rw_n(fan, n, _min, GL520_REG_FAN_MIN) \ sysfs_rw_n(fan, n, _div, GL520_REG_FAN_DIV) -#define device_create_file_fan(client, n) \ -({device_create_file(&client->dev, &dev_attr_fan##n##_input); \ -device_create_file(&client->dev, &dev_attr_fan##n##_min); \ -device_create_file(&client->dev, &dev_attr_fan##n##_div);}) - #define sysfs_fan_off(n) \ sysfs_rw_n(fan, n, _off, GL520_REG_FAN_OFF) \ -#define device_create_file_fan_off(client, n) \ -device_create_file(&client->dev, &dev_attr_fan##n##_off) - #define sysfs_temp(n) \ sysfs_ro_n(temp, n, _input, GL520_REG_TEMP##n##_INPUT) \ sysfs_rw_n(temp, n, _max, GL520_REG_TEMP##n##_MAX) \ sysfs_rw_n(temp, n, _max_hyst, GL520_REG_TEMP##n##_MAX_HYST) -#define device_create_file_temp(client, n) \ -({device_create_file(&client->dev, &dev_attr_temp##n##_input); \ -device_create_file(&client->dev, &dev_attr_temp##n##_max); \ -device_create_file(&client->dev, &dev_attr_temp##n##_max_hyst);}) - #define sysfs_alarms() \ sysfs_ro(alarms, , GL520_REG_ALARMS) \ sysfs_rw(beep_enable, , GL520_REG_BEEP_ENABLE) \ sysfs_rw(beep_mask, , GL520_REG_BEEP_MASK) -#define device_create_file_alarms(client) \ -({device_create_file(&client->dev, &dev_attr_alarms); \ -device_create_file(&client->dev, &dev_attr_beep_enable); \ -device_create_file(&client->dev, &dev_attr_beep_mask);}) - sysfs_vid(0) @@ -511,6 +486,59 @@ static ssize_t set_beep_mask(struct i2c_client *client, struct gl520_data *data, return count; } +static struct attribute *gl520_attributes[] = { + &dev_attr_cpu0_vid.attr, + + &dev_attr_in0_input.attr, + &dev_attr_in0_min.attr, + &dev_attr_in0_max.attr, + &dev_attr_in1_input.attr, + &dev_attr_in1_min.attr, + &dev_attr_in1_max.attr, + &dev_attr_in2_input.attr, + &dev_attr_in2_min.attr, + &dev_attr_in2_max.attr, + &dev_attr_in3_input.attr, + &dev_attr_in3_min.attr, + &dev_attr_in3_max.attr, + + &dev_attr_fan1_input.attr, + &dev_attr_fan1_min.attr, + &dev_attr_fan1_div.attr, + &dev_attr_fan1_off.attr, + &dev_attr_fan2_input.attr, + &dev_attr_fan2_min.attr, + &dev_attr_fan2_div.attr, + + &dev_attr_temp1_input.attr, + &dev_attr_temp1_max.attr, + &dev_attr_temp1_max_hyst.attr, + + &dev_attr_alarms.attr, + &dev_attr_beep_enable.attr, + &dev_attr_beep_mask.attr, + NULL +}; + +static const struct attribute_group gl520_group = { + .attrs = gl520_attributes, +}; + +static struct attribute *gl520_attributes_opt[] = { + &dev_attr_in4_input.attr, + &dev_attr_in4_min.attr, + &dev_attr_in4_max.attr, + + &dev_attr_temp2_input.attr, + &dev_attr_temp2_max.attr, + &dev_attr_temp2_max_hyst.attr, + NULL +}; + +static const struct attribute_group gl520_group_opt = { + .attrs = gl520_attributes_opt, +}; + /* * Real code @@ -572,33 +600,39 @@ static int gl520_detect(struct i2c_adapter *adapter, int address, int kind) gl520_init_client(new_client); /* Register sysfs hooks */ + if ((err = sysfs_create_group(&new_client->dev.kobj, &gl520_group))) + goto exit_detach; + + if (data->two_temps) { + if ((err = device_create_file(&new_client->dev, + &dev_attr_temp2_input)) + || (err = device_create_file(&new_client->dev, + &dev_attr_temp2_max)) + || (err = device_create_file(&new_client->dev, + &dev_attr_temp2_max_hyst))) + goto exit_remove_files; + } else { + if ((err = device_create_file(&new_client->dev, + &dev_attr_in4_input)) + || (err = device_create_file(&new_client->dev, + &dev_attr_in4_min)) + || (err = device_create_file(&new_client->dev, + &dev_attr_in4_max))) + goto exit_remove_files; + } + + data->class_dev = hwmon_device_register(&new_client->dev); if (IS_ERR(data->class_dev)) { err = PTR_ERR(data->class_dev); - goto exit_detach; + goto exit_remove_files; } - device_create_file_vid(new_client, 0); - - device_create_file_in(new_client, 0); - device_create_file_in(new_client, 1); - device_create_file_in(new_client, 2); - device_create_file_in(new_client, 3); - if (!data->two_temps) - device_create_file_in(new_client, 4); - - device_create_file_fan(new_client, 1); - device_create_file_fan(new_client, 2); - device_create_file_fan_off(new_client, 1); - - device_create_file_temp(new_client, 1); - if (data->two_temps) - device_create_file_temp(new_client, 2); - - device_create_file_alarms(new_client); - return 0; +exit_remove_files: + sysfs_remove_group(&new_client->dev.kobj, &gl520_group); + sysfs_remove_group(&new_client->dev.kobj, &gl520_group_opt); exit_detach: i2c_detach_client(new_client); exit_free: @@ -652,6 +686,8 @@ static int gl520_detach_client(struct i2c_client *client) int err; hwmon_device_unregister(data->class_dev); + sysfs_remove_group(&client->dev.kobj, &gl520_group); + sysfs_remove_group(&client->dev.kobj, &gl520_group_opt); if ((err = i2c_detach_client(client))) return err; diff --git a/drivers/hwmon/it87.c b/drivers/hwmon/it87.c index af5740d5d70f..323ef06719c1 100644 --- a/drivers/hwmon/it87.c +++ b/drivers/hwmon/it87.c @@ -37,6 +37,7 @@ #include #include #include +#include #include @@ -758,8 +759,6 @@ store_vrm_reg(struct device *dev, struct device_attribute *attr, const char *buf return count; } static DEVICE_ATTR(vrm, S_IRUGO | S_IWUSR, show_vrm_reg, store_vrm_reg); -#define device_create_file_vrm(client) \ -device_create_file(&client->dev, &dev_attr_vrm) static ssize_t show_vid_reg(struct device *dev, struct device_attribute *attr, char *buf) @@ -768,8 +767,88 @@ show_vid_reg(struct device *dev, struct device_attribute *attr, char *buf) return sprintf(buf, "%ld\n", (long) vid_from_reg(data->vid, data->vrm)); } static DEVICE_ATTR(cpu0_vid, S_IRUGO, show_vid_reg, NULL); -#define device_create_file_vid(client) \ -device_create_file(&client->dev, &dev_attr_cpu0_vid) + +static struct attribute *it87_attributes[] = { + &sensor_dev_attr_in0_input.dev_attr.attr, + &sensor_dev_attr_in1_input.dev_attr.attr, + &sensor_dev_attr_in2_input.dev_attr.attr, + &sensor_dev_attr_in3_input.dev_attr.attr, + &sensor_dev_attr_in4_input.dev_attr.attr, + &sensor_dev_attr_in5_input.dev_attr.attr, + &sensor_dev_attr_in6_input.dev_attr.attr, + &sensor_dev_attr_in7_input.dev_attr.attr, + &sensor_dev_attr_in8_input.dev_attr.attr, + &sensor_dev_attr_in0_min.dev_attr.attr, + &sensor_dev_attr_in1_min.dev_attr.attr, + &sensor_dev_attr_in2_min.dev_attr.attr, + &sensor_dev_attr_in3_min.dev_attr.attr, + &sensor_dev_attr_in4_min.dev_attr.attr, + &sensor_dev_attr_in5_min.dev_attr.attr, + &sensor_dev_attr_in6_min.dev_attr.attr, + &sensor_dev_attr_in7_min.dev_attr.attr, + &sensor_dev_attr_in0_max.dev_attr.attr, + &sensor_dev_attr_in1_max.dev_attr.attr, + &sensor_dev_attr_in2_max.dev_attr.attr, + &sensor_dev_attr_in3_max.dev_attr.attr, + &sensor_dev_attr_in4_max.dev_attr.attr, + &sensor_dev_attr_in5_max.dev_attr.attr, + &sensor_dev_attr_in6_max.dev_attr.attr, + &sensor_dev_attr_in7_max.dev_attr.attr, + + &sensor_dev_attr_temp1_input.dev_attr.attr, + &sensor_dev_attr_temp2_input.dev_attr.attr, + &sensor_dev_attr_temp3_input.dev_attr.attr, + &sensor_dev_attr_temp1_max.dev_attr.attr, + &sensor_dev_attr_temp2_max.dev_attr.attr, + &sensor_dev_attr_temp3_max.dev_attr.attr, + &sensor_dev_attr_temp1_min.dev_attr.attr, + &sensor_dev_attr_temp2_min.dev_attr.attr, + &sensor_dev_attr_temp3_min.dev_attr.attr, + &sensor_dev_attr_temp1_type.dev_attr.attr, + &sensor_dev_attr_temp2_type.dev_attr.attr, + &sensor_dev_attr_temp3_type.dev_attr.attr, + + &dev_attr_alarms.attr, + NULL +}; + +static const struct attribute_group it87_group = { + .attrs = it87_attributes, +}; + +static struct attribute *it87_attributes_opt[] = { + &sensor_dev_attr_fan1_input16.dev_attr.attr, + &sensor_dev_attr_fan1_min16.dev_attr.attr, + &sensor_dev_attr_fan2_input16.dev_attr.attr, + &sensor_dev_attr_fan2_min16.dev_attr.attr, + &sensor_dev_attr_fan3_input16.dev_attr.attr, + &sensor_dev_attr_fan3_min16.dev_attr.attr, + + &sensor_dev_attr_fan1_input.dev_attr.attr, + &sensor_dev_attr_fan1_min.dev_attr.attr, + &sensor_dev_attr_fan1_div.dev_attr.attr, + &sensor_dev_attr_fan2_input.dev_attr.attr, + &sensor_dev_attr_fan2_min.dev_attr.attr, + &sensor_dev_attr_fan2_div.dev_attr.attr, + &sensor_dev_attr_fan3_input.dev_attr.attr, + &sensor_dev_attr_fan3_min.dev_attr.attr, + &sensor_dev_attr_fan3_div.dev_attr.attr, + + &sensor_dev_attr_pwm1_enable.dev_attr.attr, + &sensor_dev_attr_pwm2_enable.dev_attr.attr, + &sensor_dev_attr_pwm3_enable.dev_attr.attr, + &sensor_dev_attr_pwm1.dev_attr.attr, + &sensor_dev_attr_pwm2.dev_attr.attr, + &sensor_dev_attr_pwm3.dev_attr.attr, + + &dev_attr_vrm.attr, + &dev_attr_cpu0_vid.attr, + NULL +}; + +static const struct attribute_group it87_group_opt = { + .attrs = it87_attributes_opt, +}; /* This function is called when: * it87_driver is inserted (when this module is loaded), for each @@ -948,107 +1027,78 @@ static int it87_detect(struct i2c_adapter *adapter, int address, int kind) it87_init_client(new_client, data); /* Register sysfs hooks */ - data->class_dev = hwmon_device_register(&new_client->dev); - if (IS_ERR(data->class_dev)) { - err = PTR_ERR(data->class_dev); + if ((err = sysfs_create_group(&new_client->dev.kobj, &it87_group))) goto ERROR3; - } - - device_create_file(&new_client->dev, &sensor_dev_attr_in0_input.dev_attr); - device_create_file(&new_client->dev, &sensor_dev_attr_in1_input.dev_attr); - device_create_file(&new_client->dev, &sensor_dev_attr_in2_input.dev_attr); - device_create_file(&new_client->dev, &sensor_dev_attr_in3_input.dev_attr); - device_create_file(&new_client->dev, &sensor_dev_attr_in4_input.dev_attr); - device_create_file(&new_client->dev, &sensor_dev_attr_in5_input.dev_attr); - device_create_file(&new_client->dev, &sensor_dev_attr_in6_input.dev_attr); - device_create_file(&new_client->dev, &sensor_dev_attr_in7_input.dev_attr); - device_create_file(&new_client->dev, &sensor_dev_attr_in8_input.dev_attr); - device_create_file(&new_client->dev, &sensor_dev_attr_in0_min.dev_attr); - device_create_file(&new_client->dev, &sensor_dev_attr_in1_min.dev_attr); - device_create_file(&new_client->dev, &sensor_dev_attr_in2_min.dev_attr); - device_create_file(&new_client->dev, &sensor_dev_attr_in3_min.dev_attr); - device_create_file(&new_client->dev, &sensor_dev_attr_in4_min.dev_attr); - device_create_file(&new_client->dev, &sensor_dev_attr_in5_min.dev_attr); - device_create_file(&new_client->dev, &sensor_dev_attr_in6_min.dev_attr); - device_create_file(&new_client->dev, &sensor_dev_attr_in7_min.dev_attr); - device_create_file(&new_client->dev, &sensor_dev_attr_in0_max.dev_attr); - device_create_file(&new_client->dev, &sensor_dev_attr_in1_max.dev_attr); - device_create_file(&new_client->dev, &sensor_dev_attr_in2_max.dev_attr); - device_create_file(&new_client->dev, &sensor_dev_attr_in3_max.dev_attr); - device_create_file(&new_client->dev, &sensor_dev_attr_in4_max.dev_attr); - device_create_file(&new_client->dev, &sensor_dev_attr_in5_max.dev_attr); - device_create_file(&new_client->dev, &sensor_dev_attr_in6_max.dev_attr); - device_create_file(&new_client->dev, &sensor_dev_attr_in7_max.dev_attr); - device_create_file(&new_client->dev, &sensor_dev_attr_temp1_input.dev_attr); - device_create_file(&new_client->dev, &sensor_dev_attr_temp2_input.dev_attr); - device_create_file(&new_client->dev, &sensor_dev_attr_temp3_input.dev_attr); - device_create_file(&new_client->dev, &sensor_dev_attr_temp1_max.dev_attr); - device_create_file(&new_client->dev, &sensor_dev_attr_temp2_max.dev_attr); - device_create_file(&new_client->dev, &sensor_dev_attr_temp3_max.dev_attr); - device_create_file(&new_client->dev, &sensor_dev_attr_temp1_min.dev_attr); - device_create_file(&new_client->dev, &sensor_dev_attr_temp2_min.dev_attr); - device_create_file(&new_client->dev, &sensor_dev_attr_temp3_min.dev_attr); - device_create_file(&new_client->dev, &sensor_dev_attr_temp1_type.dev_attr); - device_create_file(&new_client->dev, &sensor_dev_attr_temp2_type.dev_attr); - device_create_file(&new_client->dev, &sensor_dev_attr_temp3_type.dev_attr); /* Do not create fan files for disabled fans */ if (data->type == it8716 || data->type == it8718) { /* 16-bit tachometers */ if (data->has_fan & (1 << 0)) { - device_create_file(&new_client->dev, - &sensor_dev_attr_fan1_input16.dev_attr); - device_create_file(&new_client->dev, - &sensor_dev_attr_fan1_min16.dev_attr); + if ((err = device_create_file(&new_client->dev, + &sensor_dev_attr_fan1_input16.dev_attr)) + || (err = device_create_file(&new_client->dev, + &sensor_dev_attr_fan1_min16.dev_attr))) + goto ERROR4; } if (data->has_fan & (1 << 1)) { - device_create_file(&new_client->dev, - &sensor_dev_attr_fan2_input16.dev_attr); - device_create_file(&new_client->dev, - &sensor_dev_attr_fan2_min16.dev_attr); + if ((err = device_create_file(&new_client->dev, + &sensor_dev_attr_fan2_input16.dev_attr)) + || (err = device_create_file(&new_client->dev, + &sensor_dev_attr_fan2_min16.dev_attr))) + goto ERROR4; } if (data->has_fan & (1 << 2)) { - device_create_file(&new_client->dev, - &sensor_dev_attr_fan3_input16.dev_attr); - device_create_file(&new_client->dev, - &sensor_dev_attr_fan3_min16.dev_attr); + if ((err = device_create_file(&new_client->dev, + &sensor_dev_attr_fan3_input16.dev_attr)) + || (err = device_create_file(&new_client->dev, + &sensor_dev_attr_fan3_min16.dev_attr))) + goto ERROR4; } } else { /* 8-bit tachometers with clock divider */ if (data->has_fan & (1 << 0)) { - device_create_file(&new_client->dev, - &sensor_dev_attr_fan1_input.dev_attr); - device_create_file(&new_client->dev, - &sensor_dev_attr_fan1_min.dev_attr); - device_create_file(&new_client->dev, - &sensor_dev_attr_fan1_div.dev_attr); + if ((err = device_create_file(&new_client->dev, + &sensor_dev_attr_fan1_input.dev_attr)) + || (err = device_create_file(&new_client->dev, + &sensor_dev_attr_fan1_min.dev_attr)) + || (err = device_create_file(&new_client->dev, + &sensor_dev_attr_fan1_div.dev_attr))) + goto ERROR4; } if (data->has_fan & (1 << 1)) { - device_create_file(&new_client->dev, - &sensor_dev_attr_fan2_input.dev_attr); - device_create_file(&new_client->dev, - &sensor_dev_attr_fan2_min.dev_attr); - device_create_file(&new_client->dev, - &sensor_dev_attr_fan2_div.dev_attr); + if ((err = device_create_file(&new_client->dev, + &sensor_dev_attr_fan2_input.dev_attr)) + || (err = device_create_file(&new_client->dev, + &sensor_dev_attr_fan2_min.dev_attr)) + || (err = device_create_file(&new_client->dev, + &sensor_dev_attr_fan2_div.dev_attr))) + goto ERROR4; } if (data->has_fan & (1 << 2)) { - device_create_file(&new_client->dev, - &sensor_dev_attr_fan3_input.dev_attr); - device_create_file(&new_client->dev, - &sensor_dev_attr_fan3_min.dev_attr); - device_create_file(&new_client->dev, - &sensor_dev_attr_fan3_div.dev_attr); + if ((err = device_create_file(&new_client->dev, + &sensor_dev_attr_fan3_input.dev_attr)) + || (err = device_create_file(&new_client->dev, + &sensor_dev_attr_fan3_min.dev_attr)) + || (err = device_create_file(&new_client->dev, + &sensor_dev_attr_fan3_div.dev_attr))) + goto ERROR4; } } - device_create_file(&new_client->dev, &dev_attr_alarms); if (enable_pwm_interface) { - device_create_file(&new_client->dev, &sensor_dev_attr_pwm1_enable.dev_attr); - device_create_file(&new_client->dev, &sensor_dev_attr_pwm2_enable.dev_attr); - device_create_file(&new_client->dev, &sensor_dev_attr_pwm3_enable.dev_attr); - device_create_file(&new_client->dev, &sensor_dev_attr_pwm1.dev_attr); - device_create_file(&new_client->dev, &sensor_dev_attr_pwm2.dev_attr); - device_create_file(&new_client->dev, &sensor_dev_attr_pwm3.dev_attr); + if ((err = device_create_file(&new_client->dev, + &sensor_dev_attr_pwm1_enable.dev_attr)) + || (err = device_create_file(&new_client->dev, + &sensor_dev_attr_pwm2_enable.dev_attr)) + || (err = device_create_file(&new_client->dev, + &sensor_dev_attr_pwm3_enable.dev_attr)) + || (err = device_create_file(&new_client->dev, + &sensor_dev_attr_pwm1.dev_attr)) + || (err = device_create_file(&new_client->dev, + &sensor_dev_attr_pwm2.dev_attr)) + || (err = device_create_file(&new_client->dev, + &sensor_dev_attr_pwm3.dev_attr))) + goto ERROR4; } if (data->type == it8712 || data->type == it8716 @@ -1056,12 +1106,24 @@ static int it87_detect(struct i2c_adapter *adapter, int address, int kind) data->vrm = vid_which_vrm(); /* VID reading from Super-I/O config space if available */ data->vid = vid_value; - device_create_file_vrm(new_client); - device_create_file_vid(new_client); + if ((err = device_create_file(&new_client->dev, + &dev_attr_vrm)) + || (err = device_create_file(&new_client->dev, + &dev_attr_cpu0_vid))) + goto ERROR4; + } + + data->class_dev = hwmon_device_register(&new_client->dev); + if (IS_ERR(data->class_dev)) { + err = PTR_ERR(data->class_dev); + goto ERROR4; } return 0; +ERROR4: + sysfs_remove_group(&new_client->dev.kobj, &it87_group); + sysfs_remove_group(&new_client->dev.kobj, &it87_group_opt); ERROR3: i2c_detach_client(new_client); ERROR2: @@ -1079,6 +1141,8 @@ static int it87_detach_client(struct i2c_client *client) int err; hwmon_device_unregister(data->class_dev); + sysfs_remove_group(&client->dev.kobj, &it87_group); + sysfs_remove_group(&client->dev.kobj, &it87_group_opt); if ((err = i2c_detach_client(client))) return err; From cbeeb5b7c91b23967162185d7580048559db8d58 Mon Sep 17 00:00:00 2001 From: Roger Lucas Date: Sun, 24 Sep 2006 21:21:46 +0200 Subject: [PATCH 33/39] vt8231: Fix unchecked return status vt8231: Fix unchecked return status Check the return status from device_create_file() and also use the newer and cleaner sysfs creation functions. Signed-off-by: Roger Lucas Signed-off-by: Jean Delvare Signed-off-by: Greg Kroah-Hartman --- drivers/hwmon/vt8231.c | 186 +++++++++++++++++++++++++++++------------ 1 file changed, 132 insertions(+), 54 deletions(-) diff --git a/drivers/hwmon/vt8231.c b/drivers/hwmon/vt8231.c index 236ccf0e915d..93f93d4fb8ae 100644 --- a/drivers/hwmon/vt8231.c +++ b/drivers/hwmon/vt8231.c @@ -451,37 +451,6 @@ define_temperature_sysfs(4); define_temperature_sysfs(5); define_temperature_sysfs(6); -#define CFG_INFO_TEMP(id) { &sensor_dev_attr_temp##id##_input.dev_attr, \ - &sensor_dev_attr_temp##id##_max_hyst.dev_attr, \ - &sensor_dev_attr_temp##id##_max.dev_attr } -#define CFG_INFO_VOLT(id) { &sensor_dev_attr_in##id##_input.dev_attr, \ - &sensor_dev_attr_in##id##_min.dev_attr, \ - &sensor_dev_attr_in##id##_max.dev_attr } - -struct str_device_attr_table { - struct device_attribute *input; - struct device_attribute *min; - struct device_attribute *max; -}; - -static struct str_device_attr_table cfg_info_temp[] = { - { &dev_attr_temp1_input, &dev_attr_temp1_max_hyst, &dev_attr_temp1_max }, - CFG_INFO_TEMP(2), - CFG_INFO_TEMP(3), - CFG_INFO_TEMP(4), - CFG_INFO_TEMP(5), - CFG_INFO_TEMP(6) -}; - -static struct str_device_attr_table cfg_info_volt[] = { - CFG_INFO_VOLT(0), - CFG_INFO_VOLT(1), - CFG_INFO_VOLT(2), - CFG_INFO_VOLT(3), - CFG_INFO_VOLT(4), - { &dev_attr_in5_input, &dev_attr_in5_min, &dev_attr_in5_max } -}; - /* Fans */ static ssize_t show_fan(struct device *dev, struct device_attribute *attr, char *buf) @@ -585,6 +554,107 @@ static ssize_t show_alarms(struct device *dev, struct device_attribute *attr, static DEVICE_ATTR(alarms, S_IRUGO, show_alarms, NULL); +static struct attribute *vt8231_attributes_temps[6][4] = { + { + &dev_attr_temp1_input.attr, + &dev_attr_temp1_max_hyst.attr, + &dev_attr_temp1_max.attr, + NULL + }, { + &sensor_dev_attr_temp2_input.dev_attr.attr, + &sensor_dev_attr_temp2_max_hyst.dev_attr.attr, + &sensor_dev_attr_temp2_max.dev_attr.attr, + NULL + }, { + &sensor_dev_attr_temp3_input.dev_attr.attr, + &sensor_dev_attr_temp3_max_hyst.dev_attr.attr, + &sensor_dev_attr_temp3_max.dev_attr.attr, + NULL + }, { + &sensor_dev_attr_temp4_input.dev_attr.attr, + &sensor_dev_attr_temp4_max_hyst.dev_attr.attr, + &sensor_dev_attr_temp4_max.dev_attr.attr, + NULL + }, { + &sensor_dev_attr_temp5_input.dev_attr.attr, + &sensor_dev_attr_temp5_max_hyst.dev_attr.attr, + &sensor_dev_attr_temp5_max.dev_attr.attr, + NULL + }, { + &sensor_dev_attr_temp6_input.dev_attr.attr, + &sensor_dev_attr_temp6_max_hyst.dev_attr.attr, + &sensor_dev_attr_temp6_max.dev_attr.attr, + NULL + } +}; + +static const struct attribute_group vt8231_group_temps[6] = { + { .attrs = vt8231_attributes_temps[0] }, + { .attrs = vt8231_attributes_temps[1] }, + { .attrs = vt8231_attributes_temps[2] }, + { .attrs = vt8231_attributes_temps[3] }, + { .attrs = vt8231_attributes_temps[4] }, + { .attrs = vt8231_attributes_temps[5] }, +}; + +static struct attribute *vt8231_attributes_volts[6][4] = { + { + &sensor_dev_attr_in0_input.dev_attr.attr, + &sensor_dev_attr_in0_min.dev_attr.attr, + &sensor_dev_attr_in0_max.dev_attr.attr, + NULL + }, { + &sensor_dev_attr_in1_input.dev_attr.attr, + &sensor_dev_attr_in1_min.dev_attr.attr, + &sensor_dev_attr_in1_max.dev_attr.attr, + NULL + }, { + &sensor_dev_attr_in2_input.dev_attr.attr, + &sensor_dev_attr_in2_min.dev_attr.attr, + &sensor_dev_attr_in2_max.dev_attr.attr, + NULL + }, { + &sensor_dev_attr_in3_input.dev_attr.attr, + &sensor_dev_attr_in3_min.dev_attr.attr, + &sensor_dev_attr_in3_max.dev_attr.attr, + NULL + }, { + &sensor_dev_attr_in4_input.dev_attr.attr, + &sensor_dev_attr_in4_min.dev_attr.attr, + &sensor_dev_attr_in4_max.dev_attr.attr, + NULL + }, { + &dev_attr_in5_input.attr, + &dev_attr_in5_min.attr, + &dev_attr_in5_max.attr, + NULL + } +}; + +static const struct attribute_group vt8231_group_volts[6] = { + { .attrs = vt8231_attributes_volts[0] }, + { .attrs = vt8231_attributes_volts[1] }, + { .attrs = vt8231_attributes_volts[2] }, + { .attrs = vt8231_attributes_volts[3] }, + { .attrs = vt8231_attributes_volts[4] }, + { .attrs = vt8231_attributes_volts[5] }, +}; + +static struct attribute *vt8231_attributes[] = { + &sensor_dev_attr_fan1_input.dev_attr.attr, + &sensor_dev_attr_fan2_input.dev_attr.attr, + &sensor_dev_attr_fan1_min.dev_attr.attr, + &sensor_dev_attr_fan2_min.dev_attr.attr, + &sensor_dev_attr_fan1_div.dev_attr.attr, + &sensor_dev_attr_fan2_div.dev_attr.attr, + &dev_attr_alarms.attr, + NULL +}; + +static const struct attribute_group vt8231_group = { + .attrs = vt8231_attributes, +}; + static struct i2c_driver vt8231_driver = { .driver = { .owner = THIS_MODULE, @@ -671,43 +741,43 @@ int vt8231_detect(struct i2c_adapter *adapter) vt8231_init_client(client); /* Register sysfs hooks */ - data->class_dev = hwmon_device_register(&client->dev); - if (IS_ERR(data->class_dev)) { - err = PTR_ERR(data->class_dev); + if ((err = sysfs_create_group(&client->dev.kobj, &vt8231_group))) goto exit_detach; - } /* Must update device information to find out the config field */ data->uch_config = vt8231_read_value(client, VT8231_REG_UCH_CONFIG); - for (i = 0; i < ARRAY_SIZE(cfg_info_temp); i++) { + for (i = 0; i < ARRAY_SIZE(vt8231_group_temps); i++) { if (ISTEMP(i, data->uch_config)) { - device_create_file(&client->dev, - cfg_info_temp[i].input); - device_create_file(&client->dev, cfg_info_temp[i].max); - device_create_file(&client->dev, cfg_info_temp[i].min); + if ((err = sysfs_create_group(&client->dev.kobj, + &vt8231_group_temps[i]))) + goto exit_remove_files; } } - for (i = 0; i < ARRAY_SIZE(cfg_info_volt); i++) { + for (i = 0; i < ARRAY_SIZE(vt8231_group_volts); i++) { if (ISVOLT(i, data->uch_config)) { - device_create_file(&client->dev, - cfg_info_volt[i].input); - device_create_file(&client->dev, cfg_info_volt[i].max); - device_create_file(&client->dev, cfg_info_volt[i].min); + if ((err = sysfs_create_group(&client->dev.kobj, + &vt8231_group_volts[i]))) + goto exit_remove_files; } } - device_create_file(&client->dev, &sensor_dev_attr_fan1_input.dev_attr); - device_create_file(&client->dev, &sensor_dev_attr_fan2_input.dev_attr); - device_create_file(&client->dev, &sensor_dev_attr_fan1_min.dev_attr); - device_create_file(&client->dev, &sensor_dev_attr_fan2_min.dev_attr); - device_create_file(&client->dev, &sensor_dev_attr_fan1_div.dev_attr); - device_create_file(&client->dev, &sensor_dev_attr_fan2_div.dev_attr); - - device_create_file(&client->dev, &dev_attr_alarms); + data->class_dev = hwmon_device_register(&client->dev); + if (IS_ERR(data->class_dev)) { + err = PTR_ERR(data->class_dev); + goto exit_remove_files; + } return 0; +exit_remove_files: + for (i = 0; i < ARRAY_SIZE(vt8231_group_volts); i++) + sysfs_remove_group(&client->dev.kobj, &vt8231_group_volts[i]); + + for (i = 0; i < ARRAY_SIZE(vt8231_group_temps); i++) + sysfs_remove_group(&client->dev.kobj, &vt8231_group_temps[i]); + + sysfs_remove_group(&client->dev.kobj, &vt8231_group); exit_detach: i2c_detach_client(client); exit_free: @@ -720,10 +790,18 @@ int vt8231_detect(struct i2c_adapter *adapter) static int vt8231_detach_client(struct i2c_client *client) { struct vt8231_data *data = i2c_get_clientdata(client); - int err; + int err, i; hwmon_device_unregister(data->class_dev); + for (i = 0; i < ARRAY_SIZE(vt8231_group_volts); i++) + sysfs_remove_group(&client->dev.kobj, &vt8231_group_volts[i]); + + for (i = 0; i < ARRAY_SIZE(vt8231_group_temps); i++) + sysfs_remove_group(&client->dev.kobj, &vt8231_group_temps[i]); + + sysfs_remove_group(&client->dev.kobj, &vt8231_group); + if ((err = i2c_detach_client(client))) { return err; } From 311ce2efb1b640584676fc1b0b7f16c5baf85eb8 Mon Sep 17 00:00:00 2001 From: Jim Cromie Date: Sun, 24 Sep 2006 21:22:52 +0200 Subject: [PATCH 34/39] w83781d: Fix unchecked return status w83781d: Fix unchecked return status Add 2 attr-file groups (for base and model-specific attrs respectively), create the base group with single call to sysfs_create_group, check the return code on individual calls to device_create_file for each of the model-specific attr-files. Signed-off-by: Jim Cromie Signed-off-by: Jean Delvare Signed-off-by: Greg Kroah-Hartman --- drivers/hwmon/w83781d.c | 293 +++++++++++++++++++++------------------- 1 file changed, 151 insertions(+), 142 deletions(-) diff --git a/drivers/hwmon/w83781d.c b/drivers/hwmon/w83781d.c index 95221b14e13a..a4584ec69842 100644 --- a/drivers/hwmon/w83781d.c +++ b/drivers/hwmon/w83781d.c @@ -41,6 +41,7 @@ #include #include #include +#include #include #include #include @@ -360,13 +361,6 @@ sysfs_in_offsets(6); sysfs_in_offsets(7); sysfs_in_offsets(8); -#define device_create_file_in(client, offset) \ -do { \ -device_create_file(&client->dev, &dev_attr_in##offset##_input); \ -device_create_file(&client->dev, &dev_attr_in##offset##_min); \ -device_create_file(&client->dev, &dev_attr_in##offset##_max); \ -} while (0) - #define show_fan_reg(reg) \ static ssize_t show_##reg (struct device *dev, char *buf, int nr) \ { \ @@ -421,12 +415,6 @@ sysfs_fan_min_offset(2); sysfs_fan_offset(3); sysfs_fan_min_offset(3); -#define device_create_file_fan(client, offset) \ -do { \ -device_create_file(&client->dev, &dev_attr_fan##offset##_input); \ -device_create_file(&client->dev, &dev_attr_fan##offset##_min); \ -} while (0) - #define show_temp_reg(reg) \ static ssize_t show_##reg (struct device *dev, char *buf, int nr) \ { \ @@ -497,13 +485,6 @@ sysfs_temp_offsets(1); sysfs_temp_offsets(2); sysfs_temp_offsets(3); -#define device_create_file_temp(client, offset) \ -do { \ -device_create_file(&client->dev, &dev_attr_temp##offset##_input); \ -device_create_file(&client->dev, &dev_attr_temp##offset##_max); \ -device_create_file(&client->dev, &dev_attr_temp##offset##_max_hyst); \ -} while (0) - static ssize_t show_vid_reg(struct device *dev, struct device_attribute *attr, char *buf) { @@ -511,10 +492,8 @@ show_vid_reg(struct device *dev, struct device_attribute *attr, char *buf) return sprintf(buf, "%ld\n", (long) vid_from_reg(data->vid, data->vrm)); } -static -DEVICE_ATTR(cpu0_vid, S_IRUGO, show_vid_reg, NULL); -#define device_create_file_vid(client) \ -device_create_file(&client->dev, &dev_attr_cpu0_vid); +static DEVICE_ATTR(cpu0_vid, S_IRUGO, show_vid_reg, NULL); + static ssize_t show_vrm_reg(struct device *dev, struct device_attribute *attr, char *buf) { @@ -535,10 +514,8 @@ store_vrm_reg(struct device *dev, struct device_attribute *attr, const char *buf return count; } -static -DEVICE_ATTR(vrm, S_IRUGO | S_IWUSR, show_vrm_reg, store_vrm_reg); -#define device_create_file_vrm(client) \ -device_create_file(&client->dev, &dev_attr_vrm); +static DEVICE_ATTR(vrm, S_IRUGO | S_IWUSR, show_vrm_reg, store_vrm_reg); + static ssize_t show_alarms_reg(struct device *dev, struct device_attribute *attr, char *buf) { @@ -546,10 +523,8 @@ show_alarms_reg(struct device *dev, struct device_attribute *attr, char *buf) return sprintf(buf, "%u\n", data->alarms); } -static -DEVICE_ATTR(alarms, S_IRUGO, show_alarms_reg, NULL); -#define device_create_file_alarms(client) \ -device_create_file(&client->dev, &dev_attr_alarms); +static DEVICE_ATTR(alarms, S_IRUGO, show_alarms_reg, NULL); + static ssize_t show_beep_mask (struct device *dev, struct device_attribute *attr, char *buf) { struct w83781d_data *data = w83781d_update_device(dev); @@ -615,12 +590,6 @@ static DEVICE_ATTR(beep_##reg, S_IRUGO | S_IWUSR, show_regs_beep_##reg, store_re sysfs_beep(ENABLE, enable); sysfs_beep(MASK, mask); -#define device_create_file_beep(client) \ -do { \ -device_create_file(&client->dev, &dev_attr_beep_enable); \ -device_create_file(&client->dev, &dev_attr_beep_mask); \ -} while (0) - static ssize_t show_fan_div_reg(struct device *dev, char *buf, int nr) { @@ -686,11 +655,6 @@ sysfs_fan_div(1); sysfs_fan_div(2); sysfs_fan_div(3); -#define device_create_file_fan_div(client, offset) \ -do { \ -device_create_file(&client->dev, &dev_attr_fan##offset##_div); \ -} while (0) - static ssize_t show_pwm_reg(struct device *dev, char *buf, int nr) { @@ -787,16 +751,6 @@ sysfs_pwmenable(2); /* only PWM2 can be enabled/disabled */ sysfs_pwm(3); sysfs_pwm(4); -#define device_create_file_pwm(client, offset) \ -do { \ -device_create_file(&client->dev, &dev_attr_pwm##offset); \ -} while (0) - -#define device_create_file_pwmenable(client, offset) \ -do { \ -device_create_file(&client->dev, &dev_attr_pwm##offset##_enable); \ -} while (0) - static ssize_t show_sensor_reg(struct device *dev, char *buf, int nr) { @@ -865,11 +819,6 @@ sysfs_sensor(1); sysfs_sensor(2); sysfs_sensor(3); -#define device_create_file_sensor(client, offset) \ -do { \ -device_create_file(&client->dev, &dev_attr_temp##offset##_type); \ -} while (0) - /* This function is called when: * w83781d_driver is inserted (when this module is loaded), for each available adapter @@ -994,11 +943,69 @@ w83781d_detect_subclients(struct i2c_adapter *adapter, int address, int kind, return err; } +#define IN_UNIT_ATTRS(X) \ + &dev_attr_in##X##_input.attr, \ + &dev_attr_in##X##_min.attr, \ + &dev_attr_in##X##_max.attr + +#define FAN_UNIT_ATTRS(X) \ + &dev_attr_fan##X##_input.attr, \ + &dev_attr_fan##X##_min.attr, \ + &dev_attr_fan##X##_div.attr + +#define TEMP_UNIT_ATTRS(X) \ + &dev_attr_temp##X##_input.attr, \ + &dev_attr_temp##X##_max.attr, \ + &dev_attr_temp##X##_max_hyst.attr + +static struct attribute* w83781d_attributes[] = { + IN_UNIT_ATTRS(0), + IN_UNIT_ATTRS(2), + IN_UNIT_ATTRS(3), + IN_UNIT_ATTRS(4), + IN_UNIT_ATTRS(5), + IN_UNIT_ATTRS(6), + FAN_UNIT_ATTRS(1), + FAN_UNIT_ATTRS(2), + FAN_UNIT_ATTRS(3), + TEMP_UNIT_ATTRS(1), + TEMP_UNIT_ATTRS(2), + &dev_attr_cpu0_vid.attr, + &dev_attr_vrm.attr, + &dev_attr_alarms.attr, + &dev_attr_beep_mask.attr, + &dev_attr_beep_enable.attr, + NULL +}; +static const struct attribute_group w83781d_group = { + .attrs = w83781d_attributes, +}; + +static struct attribute *w83781d_attributes_opt[] = { + IN_UNIT_ATTRS(1), + IN_UNIT_ATTRS(7), + IN_UNIT_ATTRS(8), + TEMP_UNIT_ATTRS(3), + &dev_attr_pwm1.attr, + &dev_attr_pwm2.attr, + &dev_attr_pwm2_enable.attr, + &dev_attr_pwm3.attr, + &dev_attr_pwm4.attr, + &dev_attr_temp1_type.attr, + &dev_attr_temp2_type.attr, + &dev_attr_temp3_type.attr, + NULL +}; +static const struct attribute_group w83781d_group_opt = { + .attrs = w83781d_attributes_opt, +}; + static int w83781d_detect(struct i2c_adapter *adapter, int address, int kind) { int i = 0, val1 = 0, val2; - struct i2c_client *new_client; + struct i2c_client *client; + struct device *dev; struct w83781d_data *data; int err; const char *client_name = ""; @@ -1075,13 +1082,14 @@ w83781d_detect(struct i2c_adapter *adapter, int address, int kind) goto ERROR1; } - new_client = &data->client; - i2c_set_clientdata(new_client, data); - new_client->addr = address; + client = &data->client; + i2c_set_clientdata(client, data); + client->addr = address; mutex_init(&data->lock); - new_client->adapter = adapter; - new_client->driver = is_isa ? &w83781d_isa_driver : &w83781d_driver; - new_client->flags = 0; + client->adapter = adapter; + client->driver = is_isa ? &w83781d_isa_driver : &w83781d_driver; + client->flags = 0; + dev = &client->dev; /* Now, we do the remaining detection. */ @@ -1090,20 +1098,18 @@ w83781d_detect(struct i2c_adapter *adapter, int address, int kind) force_*=... parameter, and the Winbond will be reset to the right bank. */ if (kind < 0) { - if (w83781d_read_value(new_client, W83781D_REG_CONFIG) & 0x80) { - dev_dbg(&new_client->dev, "Detection failed at step " - "3\n"); + if (w83781d_read_value(client, W83781D_REG_CONFIG) & 0x80) { + dev_dbg(dev, "Detection failed at step 3\n"); err = -ENODEV; goto ERROR2; } - val1 = w83781d_read_value(new_client, W83781D_REG_BANK); - val2 = w83781d_read_value(new_client, W83781D_REG_CHIPMAN); + val1 = w83781d_read_value(client, W83781D_REG_BANK); + val2 = w83781d_read_value(client, W83781D_REG_CHIPMAN); /* Check for Winbond or Asus ID if in bank 0 */ if ((!(val1 & 0x07)) && (((!(val1 & 0x80)) && (val2 != 0xa3) && (val2 != 0xc3)) || ((val1 & 0x80) && (val2 != 0x5c) && (val2 != 0x12)))) { - dev_dbg(&new_client->dev, "Detection failed at step " - "4\n"); + dev_dbg(dev, "Detection failed at step 4\n"); err = -ENODEV; goto ERROR2; } @@ -1112,9 +1118,8 @@ w83781d_detect(struct i2c_adapter *adapter, int address, int kind) if ((!is_isa) && (((!(val1 & 0x80)) && (val2 == 0xa3)) || ((val1 & 0x80) && (val2 == 0x5c)))) { if (w83781d_read_value - (new_client, W83781D_REG_I2C_ADDR) != address) { - dev_dbg(&new_client->dev, "Detection failed " - "at step 5\n"); + (client, W83781D_REG_I2C_ADDR) != address) { + dev_dbg(dev, "Detection failed at step 5\n"); err = -ENODEV; goto ERROR2; } @@ -1123,27 +1128,26 @@ w83781d_detect(struct i2c_adapter *adapter, int address, int kind) /* We have either had a force parameter, or we have already detected the Winbond. Put it now into bank 0 and Vendor ID High Byte */ - w83781d_write_value(new_client, W83781D_REG_BANK, - (w83781d_read_value(new_client, - W83781D_REG_BANK) & 0x78) | - 0x80); + w83781d_write_value(client, W83781D_REG_BANK, + (w83781d_read_value(client, W83781D_REG_BANK) + & 0x78) | 0x80); /* Determine the chip type. */ if (kind <= 0) { /* get vendor ID */ - val2 = w83781d_read_value(new_client, W83781D_REG_CHIPMAN); + val2 = w83781d_read_value(client, W83781D_REG_CHIPMAN); if (val2 == 0x5c) vendid = winbond; else if (val2 == 0x12) vendid = asus; else { - dev_dbg(&new_client->dev, "Chip was made by neither " + dev_dbg(dev, "Chip was made by neither " "Winbond nor Asus?\n"); err = -ENODEV; goto ERROR2; } - val1 = w83781d_read_value(new_client, W83781D_REG_WCHIPID); + val1 = w83781d_read_value(client, W83781D_REG_WCHIPID); if ((val1 == 0x10 || val1 == 0x11) && vendid == winbond) kind = w83781d; else if (val1 == 0x30 && vendid == winbond) @@ -1157,7 +1161,7 @@ w83781d_detect(struct i2c_adapter *adapter, int address, int kind) kind = as99127f; else { if (kind == 0) - dev_warn(&new_client->dev, "Ignoring 'force' " + dev_warn(dev, "Ignoring 'force' " "parameter for unknown chip at " "adapter %d, address 0x%02x\n", i2c_adapter_id(adapter), address); @@ -1179,20 +1183,20 @@ w83781d_detect(struct i2c_adapter *adapter, int address, int kind) } /* Fill in the remaining client fields and put into the global list */ - strlcpy(new_client->name, client_name, I2C_NAME_SIZE); + strlcpy(client->name, client_name, I2C_NAME_SIZE); data->type = kind; data->valid = 0; mutex_init(&data->update_lock); /* Tell the I2C layer a new client has arrived */ - if ((err = i2c_attach_client(new_client))) + if ((err = i2c_attach_client(client))) goto ERROR2; /* attach secondary i2c lm75-like clients */ if (!is_isa) { if ((err = w83781d_detect_subclients(adapter, address, - kind, new_client))) + kind, client))) goto ERROR3; } else { data->lm75[0] = NULL; @@ -1200,11 +1204,11 @@ w83781d_detect(struct i2c_adapter *adapter, int address, int kind) } /* Initialize the chip */ - w83781d_init_client(new_client); + w83781d_init_client(client); /* A few vars need to be filled upon startup */ for (i = 1; i <= 3; i++) { - data->fan_min[i - 1] = w83781d_read_value(new_client, + data->fan_min[i - 1] = w83781d_read_value(client, W83781D_REG_FAN_MIN(i)); } if (kind != w83781d && kind != as99127f) @@ -1212,65 +1216,68 @@ w83781d_detect(struct i2c_adapter *adapter, int address, int kind) data->pwmenable[i] = 1; /* Register sysfs hooks */ - data->class_dev = hwmon_device_register(&new_client->dev); + if ((err = sysfs_create_group(&dev->kobj, &w83781d_group))) + goto ERROR4; + + if (kind != w83783s) { + if ((err = device_create_file(dev, &dev_attr_in1_input)) + || (err = device_create_file(dev, &dev_attr_in1_min)) + || (err = device_create_file(dev, &dev_attr_in1_max))) + goto ERROR4; + } + if (kind != as99127f && kind != w83781d && kind != w83783s) { + if ((err = device_create_file(dev, &dev_attr_in7_input)) + || (err = device_create_file(dev, &dev_attr_in7_min)) + || (err = device_create_file(dev, &dev_attr_in7_max)) + || (err = device_create_file(dev, &dev_attr_in8_input)) + || (err = device_create_file(dev, &dev_attr_in8_min)) + || (err = device_create_file(dev, &dev_attr_in8_max))) + goto ERROR4; + } + if (kind != w83783s) { + if ((err = device_create_file(dev, &dev_attr_temp3_input)) + || (err = device_create_file(dev, &dev_attr_temp3_max)) + || (err = device_create_file(dev, + &dev_attr_temp3_max_hyst))) + goto ERROR4; + } + + if (kind != w83781d && kind != as99127f) { + if ((err = device_create_file(dev, &dev_attr_pwm1)) + || (err = device_create_file(dev, &dev_attr_pwm2)) + || (err = device_create_file(dev, &dev_attr_pwm2_enable))) + goto ERROR4; + } + if (kind == w83782d && !is_isa) { + if ((err = device_create_file(dev, &dev_attr_pwm3)) + || (err = device_create_file(dev, &dev_attr_pwm4))) + goto ERROR4; + } + + if (kind != as99127f && kind != w83781d) { + if ((err = device_create_file(dev, &dev_attr_temp1_type)) + || (err = device_create_file(dev, + &dev_attr_temp2_type))) + goto ERROR4; + if (kind != w83783s) { + if ((err = device_create_file(dev, + &dev_attr_temp3_type))) + goto ERROR4; + } + } + + data->class_dev = hwmon_device_register(dev); if (IS_ERR(data->class_dev)) { err = PTR_ERR(data->class_dev); goto ERROR4; } - device_create_file_in(new_client, 0); - if (kind != w83783s) - device_create_file_in(new_client, 1); - device_create_file_in(new_client, 2); - device_create_file_in(new_client, 3); - device_create_file_in(new_client, 4); - device_create_file_in(new_client, 5); - device_create_file_in(new_client, 6); - if (kind != as99127f && kind != w83781d && kind != w83783s) { - device_create_file_in(new_client, 7); - device_create_file_in(new_client, 8); - } - - device_create_file_fan(new_client, 1); - device_create_file_fan(new_client, 2); - device_create_file_fan(new_client, 3); - - device_create_file_temp(new_client, 1); - device_create_file_temp(new_client, 2); - if (kind != w83783s) - device_create_file_temp(new_client, 3); - - device_create_file_vid(new_client); - device_create_file_vrm(new_client); - - device_create_file_fan_div(new_client, 1); - device_create_file_fan_div(new_client, 2); - device_create_file_fan_div(new_client, 3); - - device_create_file_alarms(new_client); - - device_create_file_beep(new_client); - - if (kind != w83781d && kind != as99127f) { - device_create_file_pwm(new_client, 1); - device_create_file_pwm(new_client, 2); - device_create_file_pwmenable(new_client, 2); - } - if (kind == w83782d && !is_isa) { - device_create_file_pwm(new_client, 3); - device_create_file_pwm(new_client, 4); - } - - if (kind != as99127f && kind != w83781d) { - device_create_file_sensor(new_client, 1); - device_create_file_sensor(new_client, 2); - if (kind != w83783s) - device_create_file_sensor(new_client, 3); - } - return 0; ERROR4: + sysfs_remove_group(&dev->kobj, &w83781d_group); + sysfs_remove_group(&dev->kobj, &w83781d_group_opt); + if (data->lm75[1]) { i2c_detach_client(data->lm75[1]); kfree(data->lm75[1]); @@ -1280,7 +1287,7 @@ w83781d_detect(struct i2c_adapter *adapter, int address, int kind) kfree(data->lm75[0]); } ERROR3: - i2c_detach_client(new_client); + i2c_detach_client(client); ERROR2: kfree(data); ERROR1: @@ -1297,9 +1304,11 @@ w83781d_detach_client(struct i2c_client *client) int err; /* main client */ - if (data) + if (data) { hwmon_device_unregister(data->class_dev); - + sysfs_remove_group(&client->dev.kobj, &w83781d_group); + sysfs_remove_group(&client->dev.kobj, &w83781d_group_opt); + } if (i2c_is_isa_client(client)) release_region(client->addr, W83781D_EXTENT); From ccc5c306957bb7fbaef61de249bac4b0f09f2336 Mon Sep 17 00:00:00 2001 From: Rudolf Marek Date: Sun, 24 Sep 2006 21:23:26 +0200 Subject: [PATCH 35/39] w83l785ts: Fix unchecked return status w83l785ts: Fix unchecked return status Fix the w83l785ts driver. Add error checking to device_create_file and also care to destroy the files upon exit. Signed-off-by: Rudolf Marek Signed-off-by: Jean Delvare Signed-off-by: Greg Kroah-Hartman --- drivers/hwmon/w83l785ts.c | 28 ++++++++++++++++++++-------- 1 file changed, 20 insertions(+), 8 deletions(-) diff --git a/drivers/hwmon/w83l785ts.c b/drivers/hwmon/w83l785ts.c index 3f2bac125fb1..a3fcace412f0 100644 --- a/drivers/hwmon/w83l785ts.c +++ b/drivers/hwmon/w83l785ts.c @@ -236,21 +236,30 @@ static int w83l785ts_detect(struct i2c_adapter *adapter, int address, int kind) * Nothing yet, assume it is already started. */ + err = device_create_file(&new_client->dev, + &sensor_dev_attr_temp1_input.dev_attr); + if (err) + goto exit_remove; + + err = device_create_file(&new_client->dev, + &sensor_dev_attr_temp1_max.dev_attr); + if (err) + goto exit_remove; + /* Register sysfs hooks */ data->class_dev = hwmon_device_register(&new_client->dev); if (IS_ERR(data->class_dev)) { err = PTR_ERR(data->class_dev); - goto exit_detach; + goto exit_remove; } - device_create_file(&new_client->dev, - &sensor_dev_attr_temp1_input.dev_attr); - device_create_file(&new_client->dev, - &sensor_dev_attr_temp1_max.dev_attr); - return 0; -exit_detach: +exit_remove: + device_remove_file(&new_client->dev, + &sensor_dev_attr_temp1_input.dev_attr); + device_remove_file(&new_client->dev, + &sensor_dev_attr_temp1_max.dev_attr); i2c_detach_client(new_client); exit_free: kfree(data); @@ -264,7 +273,10 @@ static int w83l785ts_detach_client(struct i2c_client *client) int err; hwmon_device_unregister(data->class_dev); - + device_remove_file(&client->dev, + &sensor_dev_attr_temp1_input.dev_attr); + device_remove_file(&client->dev, + &sensor_dev_attr_temp1_max.dev_attr); if ((err = i2c_detach_client(client))) return err; From f52f79da2908796a0fa1e7bbbe0d5ff20183d75f Mon Sep 17 00:00:00 2001 From: Rudolf Marek Date: Sun, 24 Sep 2006 21:24:12 +0200 Subject: [PATCH 36/39] w83792d: Fix unchecked return status w83792d: Fix unchecked return status Fix the w83792d driver. Add error checking to device_create_file and also care to destroy the files upon exit. Signed-off-by: Rudolf Marek Signed-off-by: Jean Delvare Signed-off-by: Greg Kroah-Hartman --- drivers/hwmon/w83792d.c | 554 +++++++++++++++++++++++----------------- 1 file changed, 323 insertions(+), 231 deletions(-) diff --git a/drivers/hwmon/w83792d.c b/drivers/hwmon/w83792d.c index 7576ec9426a3..4e108262576f 100644 --- a/drivers/hwmon/w83792d.c +++ b/drivers/hwmon/w83792d.c @@ -43,6 +43,7 @@ #include #include #include +#include /* Addresses to scan */ static unsigned short normal_i2c[] = { 0x2c, 0x2d, 0x2e, 0x2f, I2C_CLIENT_END }; @@ -381,41 +382,6 @@ static ssize_t store_in_##reg (struct device *dev, \ store_in_reg(MIN, min); store_in_reg(MAX, max); -static struct sensor_device_attribute sda_in_input[] = { - SENSOR_ATTR(in0_input, S_IRUGO, show_in, NULL, 0), - SENSOR_ATTR(in1_input, S_IRUGO, show_in, NULL, 1), - SENSOR_ATTR(in2_input, S_IRUGO, show_in, NULL, 2), - SENSOR_ATTR(in3_input, S_IRUGO, show_in, NULL, 3), - SENSOR_ATTR(in4_input, S_IRUGO, show_in, NULL, 4), - SENSOR_ATTR(in5_input, S_IRUGO, show_in, NULL, 5), - SENSOR_ATTR(in6_input, S_IRUGO, show_in, NULL, 6), - SENSOR_ATTR(in7_input, S_IRUGO, show_in, NULL, 7), - SENSOR_ATTR(in8_input, S_IRUGO, show_in, NULL, 8), -}; -static struct sensor_device_attribute sda_in_min[] = { - SENSOR_ATTR(in0_min, S_IWUSR | S_IRUGO, show_in_min, store_in_min, 0), - SENSOR_ATTR(in1_min, S_IWUSR | S_IRUGO, show_in_min, store_in_min, 1), - SENSOR_ATTR(in2_min, S_IWUSR | S_IRUGO, show_in_min, store_in_min, 2), - SENSOR_ATTR(in3_min, S_IWUSR | S_IRUGO, show_in_min, store_in_min, 3), - SENSOR_ATTR(in4_min, S_IWUSR | S_IRUGO, show_in_min, store_in_min, 4), - SENSOR_ATTR(in5_min, S_IWUSR | S_IRUGO, show_in_min, store_in_min, 5), - SENSOR_ATTR(in6_min, S_IWUSR | S_IRUGO, show_in_min, store_in_min, 6), - SENSOR_ATTR(in7_min, S_IWUSR | S_IRUGO, show_in_min, store_in_min, 7), - SENSOR_ATTR(in8_min, S_IWUSR | S_IRUGO, show_in_min, store_in_min, 8), -}; -static struct sensor_device_attribute sda_in_max[] = { - SENSOR_ATTR(in0_max, S_IWUSR | S_IRUGO, show_in_max, store_in_max, 0), - SENSOR_ATTR(in1_max, S_IWUSR | S_IRUGO, show_in_max, store_in_max, 1), - SENSOR_ATTR(in2_max, S_IWUSR | S_IRUGO, show_in_max, store_in_max, 2), - SENSOR_ATTR(in3_max, S_IWUSR | S_IRUGO, show_in_max, store_in_max, 3), - SENSOR_ATTR(in4_max, S_IWUSR | S_IRUGO, show_in_max, store_in_max, 4), - SENSOR_ATTR(in5_max, S_IWUSR | S_IRUGO, show_in_max, store_in_max, 5), - SENSOR_ATTR(in6_max, S_IWUSR | S_IRUGO, show_in_max, store_in_max, 6), - SENSOR_ATTR(in7_max, S_IWUSR | S_IRUGO, show_in_max, store_in_max, 7), - SENSOR_ATTR(in8_max, S_IWUSR | S_IRUGO, show_in_max, store_in_max, 8), -}; - - #define show_fan_reg(reg) \ static ssize_t show_##reg (struct device *dev, struct device_attribute *attr, \ char *buf) \ @@ -499,35 +465,6 @@ store_fan_div(struct device *dev, struct device_attribute *attr, return count; } -static struct sensor_device_attribute sda_fan_input[] = { - SENSOR_ATTR(fan1_input, S_IRUGO, show_fan, NULL, 1), - SENSOR_ATTR(fan2_input, S_IRUGO, show_fan, NULL, 2), - SENSOR_ATTR(fan3_input, S_IRUGO, show_fan, NULL, 3), - SENSOR_ATTR(fan4_input, S_IRUGO, show_fan, NULL, 4), - SENSOR_ATTR(fan5_input, S_IRUGO, show_fan, NULL, 5), - SENSOR_ATTR(fan6_input, S_IRUGO, show_fan, NULL, 6), - SENSOR_ATTR(fan7_input, S_IRUGO, show_fan, NULL, 7), -}; -static struct sensor_device_attribute sda_fan_min[] = { - SENSOR_ATTR(fan1_min, S_IWUSR | S_IRUGO, show_fan_min, store_fan_min, 1), - SENSOR_ATTR(fan2_min, S_IWUSR | S_IRUGO, show_fan_min, store_fan_min, 2), - SENSOR_ATTR(fan3_min, S_IWUSR | S_IRUGO, show_fan_min, store_fan_min, 3), - SENSOR_ATTR(fan4_min, S_IWUSR | S_IRUGO, show_fan_min, store_fan_min, 4), - SENSOR_ATTR(fan5_min, S_IWUSR | S_IRUGO, show_fan_min, store_fan_min, 5), - SENSOR_ATTR(fan6_min, S_IWUSR | S_IRUGO, show_fan_min, store_fan_min, 6), - SENSOR_ATTR(fan7_min, S_IWUSR | S_IRUGO, show_fan_min, store_fan_min, 7), -}; -static struct sensor_device_attribute sda_fan_div[] = { - SENSOR_ATTR(fan1_div, S_IWUSR | S_IRUGO, show_fan_div, store_fan_div, 1), - SENSOR_ATTR(fan2_div, S_IWUSR | S_IRUGO, show_fan_div, store_fan_div, 2), - SENSOR_ATTR(fan3_div, S_IWUSR | S_IRUGO, show_fan_div, store_fan_div, 3), - SENSOR_ATTR(fan4_div, S_IWUSR | S_IRUGO, show_fan_div, store_fan_div, 4), - SENSOR_ATTR(fan5_div, S_IWUSR | S_IRUGO, show_fan_div, store_fan_div, 5), - SENSOR_ATTR(fan6_div, S_IWUSR | S_IRUGO, show_fan_div, store_fan_div, 6), - SENSOR_ATTR(fan7_div, S_IWUSR | S_IRUGO, show_fan_div, store_fan_div, 7), -}; - - /* read/write the temperature1, includes measured value and limits */ static ssize_t show_temp1(struct device *dev, struct device_attribute *attr, @@ -595,24 +532,6 @@ static ssize_t store_temp23(struct device *dev, struct device_attribute *attr, return count; } -static struct sensor_device_attribute_2 sda_temp_input[] = { - SENSOR_ATTR_2(temp1_input, S_IRUGO, show_temp1, NULL, 0, 0), - SENSOR_ATTR_2(temp2_input, S_IRUGO, show_temp23, NULL, 0, 0), - SENSOR_ATTR_2(temp3_input, S_IRUGO, show_temp23, NULL, 1, 0), -}; - -static struct sensor_device_attribute_2 sda_temp_max[] = { - SENSOR_ATTR_2(temp1_max, S_IRUGO | S_IWUSR, show_temp1, store_temp1, 0, 1), - SENSOR_ATTR_2(temp2_max, S_IRUGO | S_IWUSR, show_temp23, store_temp23, 0, 2), - SENSOR_ATTR_2(temp3_max, S_IRUGO | S_IWUSR, show_temp23, store_temp23, 1, 2), -}; - -static struct sensor_device_attribute_2 sda_temp_max_hyst[] = { - SENSOR_ATTR_2(temp1_max_hyst, S_IRUGO | S_IWUSR, show_temp1, store_temp1, 0, 2), - SENSOR_ATTR_2(temp2_max_hyst, S_IRUGO | S_IWUSR, show_temp23, store_temp23, 0, 4), - SENSOR_ATTR_2(temp3_max_hyst, S_IRUGO | S_IWUSR, show_temp23, store_temp23, 1, 4), -}; - /* get reatime status of all sensors items: voltage, temp, fan */ static ssize_t show_alarms_reg(struct device *dev, struct device_attribute *attr, char *buf) @@ -621,9 +540,6 @@ show_alarms_reg(struct device *dev, struct device_attribute *attr, char *buf) return sprintf(buf, "%d\n", data->alarms); } -static -DEVICE_ATTR(alarms, S_IRUGO, show_alarms_reg, NULL); - static ssize_t show_pwm(struct device *dev, struct device_attribute *attr, char *buf) @@ -715,21 +631,6 @@ store_pwmenable(struct device *dev, struct device_attribute *attr, return count; } -static struct sensor_device_attribute sda_pwm[] = { - SENSOR_ATTR(pwm1, S_IWUSR | S_IRUGO, show_pwm, store_pwm, 0), - SENSOR_ATTR(pwm2, S_IWUSR | S_IRUGO, show_pwm, store_pwm, 1), - SENSOR_ATTR(pwm3, S_IWUSR | S_IRUGO, show_pwm, store_pwm, 2), -}; -static struct sensor_device_attribute sda_pwm_enable[] = { - SENSOR_ATTR(pwm1_enable, S_IWUSR | S_IRUGO, - show_pwmenable, store_pwmenable, 1), - SENSOR_ATTR(pwm2_enable, S_IWUSR | S_IRUGO, - show_pwmenable, store_pwmenable, 2), - SENSOR_ATTR(pwm3_enable, S_IWUSR | S_IRUGO, - show_pwmenable, store_pwmenable, 3), -}; - - static ssize_t show_pwm_mode(struct device *dev, struct device_attribute *attr, char *buf) @@ -767,16 +668,6 @@ store_pwm_mode(struct device *dev, struct device_attribute *attr, return count; } -static struct sensor_device_attribute sda_pwm_mode[] = { - SENSOR_ATTR(pwm1_mode, S_IWUSR | S_IRUGO, - show_pwm_mode, store_pwm_mode, 0), - SENSOR_ATTR(pwm2_mode, S_IWUSR | S_IRUGO, - show_pwm_mode, store_pwm_mode, 1), - SENSOR_ATTR(pwm3_mode, S_IWUSR | S_IRUGO, - show_pwm_mode, store_pwm_mode, 2), -}; - - static ssize_t show_regs_chassis(struct device *dev, struct device_attribute *attr, char *buf) @@ -785,8 +676,6 @@ show_regs_chassis(struct device *dev, struct device_attribute *attr, return sprintf(buf, "%d\n", data->chassis); } -static DEVICE_ATTR(chassis, S_IRUGO, show_regs_chassis, NULL); - static ssize_t show_chassis_clear(struct device *dev, struct device_attribute *attr, char *buf) { @@ -815,9 +704,6 @@ store_chassis_clear(struct device *dev, struct device_attribute *attr, return count; } -static DEVICE_ATTR(chassis_clear, S_IRUGO | S_IWUSR, - show_chassis_clear, store_chassis_clear); - /* For Smart Fan I / Thermal Cruise */ static ssize_t show_thermal_cruise(struct device *dev, struct device_attribute *attr, @@ -853,15 +739,6 @@ store_thermal_cruise(struct device *dev, struct device_attribute *attr, return count; } -static struct sensor_device_attribute sda_thermal_cruise[] = { - SENSOR_ATTR(thermal_cruise1, S_IWUSR | S_IRUGO, - show_thermal_cruise, store_thermal_cruise, 1), - SENSOR_ATTR(thermal_cruise2, S_IWUSR | S_IRUGO, - show_thermal_cruise, store_thermal_cruise, 2), - SENSOR_ATTR(thermal_cruise3, S_IWUSR | S_IRUGO, - show_thermal_cruise, store_thermal_cruise, 3), -}; - /* For Smart Fan I/Thermal Cruise and Smart Fan II */ static ssize_t show_tolerance(struct device *dev, struct device_attribute *attr, @@ -901,15 +778,6 @@ store_tolerance(struct device *dev, struct device_attribute *attr, return count; } -static struct sensor_device_attribute sda_tolerance[] = { - SENSOR_ATTR(tolerance1, S_IWUSR | S_IRUGO, - show_tolerance, store_tolerance, 1), - SENSOR_ATTR(tolerance2, S_IWUSR | S_IRUGO, - show_tolerance, store_tolerance, 2), - SENSOR_ATTR(tolerance3, S_IWUSR | S_IRUGO, - show_tolerance, store_tolerance, 3), -}; - /* For Smart Fan II */ static ssize_t show_sf2_point(struct device *dev, struct device_attribute *attr, @@ -946,36 +814,6 @@ store_sf2_point(struct device *dev, struct device_attribute *attr, return count; } -static struct sensor_device_attribute_2 sda_sf2_point[] = { - SENSOR_ATTR_2(sf2_point1_fan1, S_IRUGO | S_IWUSR, - show_sf2_point, store_sf2_point, 1, 1), - SENSOR_ATTR_2(sf2_point2_fan1, S_IRUGO | S_IWUSR, - show_sf2_point, store_sf2_point, 2, 1), - SENSOR_ATTR_2(sf2_point3_fan1, S_IRUGO | S_IWUSR, - show_sf2_point, store_sf2_point, 3, 1), - SENSOR_ATTR_2(sf2_point4_fan1, S_IRUGO | S_IWUSR, - show_sf2_point, store_sf2_point, 4, 1), - - SENSOR_ATTR_2(sf2_point1_fan2, S_IRUGO | S_IWUSR, - show_sf2_point, store_sf2_point, 1, 2), - SENSOR_ATTR_2(sf2_point2_fan2, S_IRUGO | S_IWUSR, - show_sf2_point, store_sf2_point, 2, 2), - SENSOR_ATTR_2(sf2_point3_fan2, S_IRUGO | S_IWUSR, - show_sf2_point, store_sf2_point, 3, 2), - SENSOR_ATTR_2(sf2_point4_fan2, S_IRUGO | S_IWUSR, - show_sf2_point, store_sf2_point, 4, 2), - - SENSOR_ATTR_2(sf2_point1_fan3, S_IRUGO | S_IWUSR, - show_sf2_point, store_sf2_point, 1, 3), - SENSOR_ATTR_2(sf2_point2_fan3, S_IRUGO | S_IWUSR, - show_sf2_point, store_sf2_point, 2, 3), - SENSOR_ATTR_2(sf2_point3_fan3, S_IRUGO | S_IWUSR, - show_sf2_point, store_sf2_point, 3, 3), - SENSOR_ATTR_2(sf2_point4_fan3, S_IRUGO | S_IWUSR, - show_sf2_point, store_sf2_point, 4, 3), -}; - - static ssize_t show_sf2_level(struct device *dev, struct device_attribute *attr, char *buf) @@ -1016,29 +854,6 @@ store_sf2_level(struct device *dev, struct device_attribute *attr, return count; } -static struct sensor_device_attribute_2 sda_sf2_level[] = { - SENSOR_ATTR_2(sf2_level1_fan1, S_IRUGO | S_IWUSR, - show_sf2_level, store_sf2_level, 1, 1), - SENSOR_ATTR_2(sf2_level2_fan1, S_IRUGO | S_IWUSR, - show_sf2_level, store_sf2_level, 2, 1), - SENSOR_ATTR_2(sf2_level3_fan1, S_IRUGO | S_IWUSR, - show_sf2_level, store_sf2_level, 3, 1), - - SENSOR_ATTR_2(sf2_level1_fan2, S_IRUGO | S_IWUSR, - show_sf2_level, store_sf2_level, 1, 2), - SENSOR_ATTR_2(sf2_level2_fan2, S_IRUGO | S_IWUSR, - show_sf2_level, store_sf2_level, 2, 2), - SENSOR_ATTR_2(sf2_level3_fan2, S_IRUGO | S_IWUSR, - show_sf2_level, store_sf2_level, 3, 2), - - SENSOR_ATTR_2(sf2_level1_fan3, S_IRUGO | S_IWUSR, - show_sf2_level, store_sf2_level, 1, 3), - SENSOR_ATTR_2(sf2_level2_fan3, S_IRUGO | S_IWUSR, - show_sf2_level, store_sf2_level, 2, 3), - SENSOR_ATTR_2(sf2_level3_fan3, S_IRUGO | S_IWUSR, - show_sf2_level, store_sf2_level, 3, 3), -}; - /* This function is called when: * w83792d_driver is inserted (when this module is loaded), for each available adapter @@ -1139,12 +954,297 @@ w83792d_detect_subclients(struct i2c_adapter *adapter, int address, int kind, return err; } -static void device_create_file_fan(struct device *dev, int i) -{ - device_create_file(dev, &sda_fan_input[i].dev_attr); - device_create_file(dev, &sda_fan_div[i].dev_attr); - device_create_file(dev, &sda_fan_min[i].dev_attr); -} +static SENSOR_DEVICE_ATTR(in0_input, S_IRUGO, show_in, NULL, 0); +static SENSOR_DEVICE_ATTR(in1_input, S_IRUGO, show_in, NULL, 1); +static SENSOR_DEVICE_ATTR(in2_input, S_IRUGO, show_in, NULL, 2); +static SENSOR_DEVICE_ATTR(in3_input, S_IRUGO, show_in, NULL, 3); +static SENSOR_DEVICE_ATTR(in4_input, S_IRUGO, show_in, NULL, 4); +static SENSOR_DEVICE_ATTR(in5_input, S_IRUGO, show_in, NULL, 5); +static SENSOR_DEVICE_ATTR(in6_input, S_IRUGO, show_in, NULL, 6); +static SENSOR_DEVICE_ATTR(in7_input, S_IRUGO, show_in, NULL, 7); +static SENSOR_DEVICE_ATTR(in8_input, S_IRUGO, show_in, NULL, 8); +static SENSOR_DEVICE_ATTR(in0_min, S_IWUSR | S_IRUGO, + show_in_min, store_in_min, 0); +static SENSOR_DEVICE_ATTR(in1_min, S_IWUSR | S_IRUGO, + show_in_min, store_in_min, 1); +static SENSOR_DEVICE_ATTR(in2_min, S_IWUSR | S_IRUGO, + show_in_min, store_in_min, 2); +static SENSOR_DEVICE_ATTR(in3_min, S_IWUSR | S_IRUGO, + show_in_min, store_in_min, 3); +static SENSOR_DEVICE_ATTR(in4_min, S_IWUSR | S_IRUGO, + show_in_min, store_in_min, 4); +static SENSOR_DEVICE_ATTR(in5_min, S_IWUSR | S_IRUGO, + show_in_min, store_in_min, 5); +static SENSOR_DEVICE_ATTR(in6_min, S_IWUSR | S_IRUGO, + show_in_min, store_in_min, 6); +static SENSOR_DEVICE_ATTR(in7_min, S_IWUSR | S_IRUGO, + show_in_min, store_in_min, 7); +static SENSOR_DEVICE_ATTR(in8_min, S_IWUSR | S_IRUGO, + show_in_min, store_in_min, 8); +static SENSOR_DEVICE_ATTR(in0_max, S_IWUSR | S_IRUGO, + show_in_max, store_in_max, 0); +static SENSOR_DEVICE_ATTR(in1_max, S_IWUSR | S_IRUGO, + show_in_max, store_in_max, 1); +static SENSOR_DEVICE_ATTR(in2_max, S_IWUSR | S_IRUGO, + show_in_max, store_in_max, 2); +static SENSOR_DEVICE_ATTR(in3_max, S_IWUSR | S_IRUGO, + show_in_max, store_in_max, 3); +static SENSOR_DEVICE_ATTR(in4_max, S_IWUSR | S_IRUGO, + show_in_max, store_in_max, 4); +static SENSOR_DEVICE_ATTR(in5_max, S_IWUSR | S_IRUGO, + show_in_max, store_in_max, 5); +static SENSOR_DEVICE_ATTR(in6_max, S_IWUSR | S_IRUGO, + show_in_max, store_in_max, 6); +static SENSOR_DEVICE_ATTR(in7_max, S_IWUSR | S_IRUGO, + show_in_max, store_in_max, 7); +static SENSOR_DEVICE_ATTR(in8_max, S_IWUSR | S_IRUGO, + show_in_max, store_in_max, 8); +static SENSOR_DEVICE_ATTR_2(temp1_input, S_IRUGO, show_temp1, NULL, 0, 0); +static SENSOR_DEVICE_ATTR_2(temp2_input, S_IRUGO, show_temp23, NULL, 0, 0); +static SENSOR_DEVICE_ATTR_2(temp3_input, S_IRUGO, show_temp23, NULL, 1, 0); +static SENSOR_DEVICE_ATTR_2(temp1_max, S_IRUGO | S_IWUSR, + show_temp1, store_temp1, 0, 1); +static SENSOR_DEVICE_ATTR_2(temp2_max, S_IRUGO | S_IWUSR, show_temp23, + store_temp23, 0, 2); +static SENSOR_DEVICE_ATTR_2(temp3_max, S_IRUGO | S_IWUSR, show_temp23, + store_temp23, 1, 2); +static SENSOR_DEVICE_ATTR_2(temp1_max_hyst, S_IRUGO | S_IWUSR, + show_temp1, store_temp1, 0, 2); +static SENSOR_DEVICE_ATTR_2(temp2_max_hyst, S_IRUGO | S_IWUSR, + show_temp23, store_temp23, 0, 4); +static SENSOR_DEVICE_ATTR_2(temp3_max_hyst, S_IRUGO | S_IWUSR, + show_temp23, store_temp23, 1, 4); +static DEVICE_ATTR(alarms, S_IRUGO, show_alarms_reg, NULL); +static DEVICE_ATTR(chassis, S_IRUGO, show_regs_chassis, NULL); +static DEVICE_ATTR(chassis_clear, S_IRUGO | S_IWUSR, + show_chassis_clear, store_chassis_clear); +static SENSOR_DEVICE_ATTR(pwm1, S_IWUSR | S_IRUGO, show_pwm, store_pwm, 0); +static SENSOR_DEVICE_ATTR(pwm2, S_IWUSR | S_IRUGO, show_pwm, store_pwm, 1); +static SENSOR_DEVICE_ATTR(pwm3, S_IWUSR | S_IRUGO, show_pwm, store_pwm, 2); +static SENSOR_DEVICE_ATTR(pwm1_enable, S_IWUSR | S_IRUGO, + show_pwmenable, store_pwmenable, 1); +static SENSOR_DEVICE_ATTR(pwm2_enable, S_IWUSR | S_IRUGO, + show_pwmenable, store_pwmenable, 2); +static SENSOR_DEVICE_ATTR(pwm3_enable, S_IWUSR | S_IRUGO, + show_pwmenable, store_pwmenable, 3); +static SENSOR_DEVICE_ATTR(pwm1_mode, S_IWUSR | S_IRUGO, + show_pwm_mode, store_pwm_mode, 0); +static SENSOR_DEVICE_ATTR(pwm2_mode, S_IWUSR | S_IRUGO, + show_pwm_mode, store_pwm_mode, 1); +static SENSOR_DEVICE_ATTR(pwm3_mode, S_IWUSR | S_IRUGO, + show_pwm_mode, store_pwm_mode, 2); +static SENSOR_DEVICE_ATTR(tolerance1, S_IWUSR | S_IRUGO, + show_tolerance, store_tolerance, 1); +static SENSOR_DEVICE_ATTR(tolerance2, S_IWUSR | S_IRUGO, + show_tolerance, store_tolerance, 2); +static SENSOR_DEVICE_ATTR(tolerance3, S_IWUSR | S_IRUGO, + show_tolerance, store_tolerance, 3); +static SENSOR_DEVICE_ATTR(thermal_cruise1, S_IWUSR | S_IRUGO, + show_thermal_cruise, store_thermal_cruise, 1); +static SENSOR_DEVICE_ATTR(thermal_cruise2, S_IWUSR | S_IRUGO, + show_thermal_cruise, store_thermal_cruise, 2); +static SENSOR_DEVICE_ATTR(thermal_cruise3, S_IWUSR | S_IRUGO, + show_thermal_cruise, store_thermal_cruise, 3); +static SENSOR_DEVICE_ATTR_2(sf2_point1_fan1, S_IRUGO | S_IWUSR, + show_sf2_point, store_sf2_point, 1, 1); +static SENSOR_DEVICE_ATTR_2(sf2_point2_fan1, S_IRUGO | S_IWUSR, + show_sf2_point, store_sf2_point, 2, 1); +static SENSOR_DEVICE_ATTR_2(sf2_point3_fan1, S_IRUGO | S_IWUSR, + show_sf2_point, store_sf2_point, 3, 1); +static SENSOR_DEVICE_ATTR_2(sf2_point4_fan1, S_IRUGO | S_IWUSR, + show_sf2_point, store_sf2_point, 4, 1); +static SENSOR_DEVICE_ATTR_2(sf2_point1_fan2, S_IRUGO | S_IWUSR, + show_sf2_point, store_sf2_point, 1, 2); +static SENSOR_DEVICE_ATTR_2(sf2_point2_fan2, S_IRUGO | S_IWUSR, + show_sf2_point, store_sf2_point, 2, 2); +static SENSOR_DEVICE_ATTR_2(sf2_point3_fan2, S_IRUGO | S_IWUSR, + show_sf2_point, store_sf2_point, 3, 2); +static SENSOR_DEVICE_ATTR_2(sf2_point4_fan2, S_IRUGO | S_IWUSR, + show_sf2_point, store_sf2_point, 4, 2); +static SENSOR_DEVICE_ATTR_2(sf2_point1_fan3, S_IRUGO | S_IWUSR, + show_sf2_point, store_sf2_point, 1, 3); +static SENSOR_DEVICE_ATTR_2(sf2_point2_fan3, S_IRUGO | S_IWUSR, + show_sf2_point, store_sf2_point, 2, 3); +static SENSOR_DEVICE_ATTR_2(sf2_point3_fan3, S_IRUGO | S_IWUSR, + show_sf2_point, store_sf2_point, 3, 3); +static SENSOR_DEVICE_ATTR_2(sf2_point4_fan3, S_IRUGO | S_IWUSR, + show_sf2_point, store_sf2_point, 4, 3); +static SENSOR_DEVICE_ATTR_2(sf2_level1_fan1, S_IRUGO | S_IWUSR, + show_sf2_level, store_sf2_level, 1, 1); +static SENSOR_DEVICE_ATTR_2(sf2_level2_fan1, S_IRUGO | S_IWUSR, + show_sf2_level, store_sf2_level, 2, 1); +static SENSOR_DEVICE_ATTR_2(sf2_level3_fan1, S_IRUGO | S_IWUSR, + show_sf2_level, store_sf2_level, 3, 1); +static SENSOR_DEVICE_ATTR_2(sf2_level1_fan2, S_IRUGO | S_IWUSR, + show_sf2_level, store_sf2_level, 1, 2); +static SENSOR_DEVICE_ATTR_2(sf2_level2_fan2, S_IRUGO | S_IWUSR, + show_sf2_level, store_sf2_level, 2, 2); +static SENSOR_DEVICE_ATTR_2(sf2_level3_fan2, S_IRUGO | S_IWUSR, + show_sf2_level, store_sf2_level, 3, 2); +static SENSOR_DEVICE_ATTR_2(sf2_level1_fan3, S_IRUGO | S_IWUSR, + show_sf2_level, store_sf2_level, 1, 3); +static SENSOR_DEVICE_ATTR_2(sf2_level2_fan3, S_IRUGO | S_IWUSR, + show_sf2_level, store_sf2_level, 2, 3); +static SENSOR_DEVICE_ATTR_2(sf2_level3_fan3, S_IRUGO | S_IWUSR, + show_sf2_level, store_sf2_level, 3, 3); +static SENSOR_DEVICE_ATTR(fan1_input, S_IRUGO, show_fan, NULL, 1); +static SENSOR_DEVICE_ATTR(fan2_input, S_IRUGO, show_fan, NULL, 2); +static SENSOR_DEVICE_ATTR(fan3_input, S_IRUGO, show_fan, NULL, 3); +static SENSOR_DEVICE_ATTR(fan4_input, S_IRUGO, show_fan, NULL, 4); +static SENSOR_DEVICE_ATTR(fan5_input, S_IRUGO, show_fan, NULL, 5); +static SENSOR_DEVICE_ATTR(fan6_input, S_IRUGO, show_fan, NULL, 6); +static SENSOR_DEVICE_ATTR(fan7_input, S_IRUGO, show_fan, NULL, 7); +static SENSOR_DEVICE_ATTR(fan1_min, S_IWUSR | S_IRUGO, + show_fan_min, store_fan_min, 1); +static SENSOR_DEVICE_ATTR(fan2_min, S_IWUSR | S_IRUGO, + show_fan_min, store_fan_min, 2); +static SENSOR_DEVICE_ATTR(fan3_min, S_IWUSR | S_IRUGO, + show_fan_min, store_fan_min, 3); +static SENSOR_DEVICE_ATTR(fan4_min, S_IWUSR | S_IRUGO, + show_fan_min, store_fan_min, 4); +static SENSOR_DEVICE_ATTR(fan5_min, S_IWUSR | S_IRUGO, + show_fan_min, store_fan_min, 5); +static SENSOR_DEVICE_ATTR(fan6_min, S_IWUSR | S_IRUGO, + show_fan_min, store_fan_min, 6); +static SENSOR_DEVICE_ATTR(fan7_min, S_IWUSR | S_IRUGO, + show_fan_min, store_fan_min, 7); +static SENSOR_DEVICE_ATTR(fan1_div, S_IWUSR | S_IRUGO, + show_fan_div, store_fan_div, 1); +static SENSOR_DEVICE_ATTR(fan2_div, S_IWUSR | S_IRUGO, + show_fan_div, store_fan_div, 2); +static SENSOR_DEVICE_ATTR(fan3_div, S_IWUSR | S_IRUGO, + show_fan_div, store_fan_div, 3); +static SENSOR_DEVICE_ATTR(fan4_div, S_IWUSR | S_IRUGO, + show_fan_div, store_fan_div, 4); +static SENSOR_DEVICE_ATTR(fan5_div, S_IWUSR | S_IRUGO, + show_fan_div, store_fan_div, 5); +static SENSOR_DEVICE_ATTR(fan6_div, S_IWUSR | S_IRUGO, + show_fan_div, store_fan_div, 6); +static SENSOR_DEVICE_ATTR(fan7_div, S_IWUSR | S_IRUGO, + show_fan_div, store_fan_div, 7); + +static struct attribute *w83792d_attributes_fan[4][4] = { + { + &sensor_dev_attr_fan4_input.dev_attr.attr, + &sensor_dev_attr_fan4_min.dev_attr.attr, + &sensor_dev_attr_fan4_div.dev_attr.attr, + NULL + }, { + &sensor_dev_attr_fan5_input.dev_attr.attr, + &sensor_dev_attr_fan5_min.dev_attr.attr, + &sensor_dev_attr_fan5_div.dev_attr.attr, + NULL + }, { + &sensor_dev_attr_fan6_input.dev_attr.attr, + &sensor_dev_attr_fan6_min.dev_attr.attr, + &sensor_dev_attr_fan6_div.dev_attr.attr, + NULL + }, { + &sensor_dev_attr_fan7_input.dev_attr.attr, + &sensor_dev_attr_fan7_min.dev_attr.attr, + &sensor_dev_attr_fan7_div.dev_attr.attr, + NULL + } +}; + +static const struct attribute_group w83792d_group_fan[4] = { + { .attrs = w83792d_attributes_fan[0] }, + { .attrs = w83792d_attributes_fan[1] }, + { .attrs = w83792d_attributes_fan[2] }, + { .attrs = w83792d_attributes_fan[3] }, +}; + +static struct attribute *w83792d_attributes[] = { + &sensor_dev_attr_in0_input.dev_attr.attr, + &sensor_dev_attr_in0_max.dev_attr.attr, + &sensor_dev_attr_in0_min.dev_attr.attr, + &sensor_dev_attr_in1_input.dev_attr.attr, + &sensor_dev_attr_in1_max.dev_attr.attr, + &sensor_dev_attr_in1_min.dev_attr.attr, + &sensor_dev_attr_in2_input.dev_attr.attr, + &sensor_dev_attr_in2_max.dev_attr.attr, + &sensor_dev_attr_in2_min.dev_attr.attr, + &sensor_dev_attr_in3_input.dev_attr.attr, + &sensor_dev_attr_in3_max.dev_attr.attr, + &sensor_dev_attr_in3_min.dev_attr.attr, + &sensor_dev_attr_in4_input.dev_attr.attr, + &sensor_dev_attr_in4_max.dev_attr.attr, + &sensor_dev_attr_in4_min.dev_attr.attr, + &sensor_dev_attr_in5_input.dev_attr.attr, + &sensor_dev_attr_in5_max.dev_attr.attr, + &sensor_dev_attr_in5_min.dev_attr.attr, + &sensor_dev_attr_in6_input.dev_attr.attr, + &sensor_dev_attr_in6_max.dev_attr.attr, + &sensor_dev_attr_in6_min.dev_attr.attr, + &sensor_dev_attr_in7_input.dev_attr.attr, + &sensor_dev_attr_in7_max.dev_attr.attr, + &sensor_dev_attr_in7_min.dev_attr.attr, + &sensor_dev_attr_in8_input.dev_attr.attr, + &sensor_dev_attr_in8_max.dev_attr.attr, + &sensor_dev_attr_in8_min.dev_attr.attr, + &sensor_dev_attr_temp1_input.dev_attr.attr, + &sensor_dev_attr_temp1_max.dev_attr.attr, + &sensor_dev_attr_temp1_max_hyst.dev_attr.attr, + &sensor_dev_attr_temp2_input.dev_attr.attr, + &sensor_dev_attr_temp2_max.dev_attr.attr, + &sensor_dev_attr_temp2_max_hyst.dev_attr.attr, + &sensor_dev_attr_temp3_input.dev_attr.attr, + &sensor_dev_attr_temp3_max.dev_attr.attr, + &sensor_dev_attr_temp3_max_hyst.dev_attr.attr, + &sensor_dev_attr_pwm1.dev_attr.attr, + &sensor_dev_attr_pwm1_mode.dev_attr.attr, + &sensor_dev_attr_pwm1_enable.dev_attr.attr, + &sensor_dev_attr_pwm2.dev_attr.attr, + &sensor_dev_attr_pwm2_mode.dev_attr.attr, + &sensor_dev_attr_pwm2_enable.dev_attr.attr, + &sensor_dev_attr_pwm3.dev_attr.attr, + &sensor_dev_attr_pwm3_mode.dev_attr.attr, + &sensor_dev_attr_pwm3_enable.dev_attr.attr, + &dev_attr_alarms.attr, + &dev_attr_chassis.attr, + &dev_attr_chassis_clear.attr, + &sensor_dev_attr_tolerance1.dev_attr.attr, + &sensor_dev_attr_thermal_cruise1.dev_attr.attr, + &sensor_dev_attr_tolerance2.dev_attr.attr, + &sensor_dev_attr_thermal_cruise2.dev_attr.attr, + &sensor_dev_attr_tolerance3.dev_attr.attr, + &sensor_dev_attr_thermal_cruise3.dev_attr.attr, + &sensor_dev_attr_sf2_point1_fan1.dev_attr.attr, + &sensor_dev_attr_sf2_point2_fan1.dev_attr.attr, + &sensor_dev_attr_sf2_point3_fan1.dev_attr.attr, + &sensor_dev_attr_sf2_point4_fan1.dev_attr.attr, + &sensor_dev_attr_sf2_point1_fan2.dev_attr.attr, + &sensor_dev_attr_sf2_point2_fan2.dev_attr.attr, + &sensor_dev_attr_sf2_point3_fan2.dev_attr.attr, + &sensor_dev_attr_sf2_point4_fan2.dev_attr.attr, + &sensor_dev_attr_sf2_point1_fan3.dev_attr.attr, + &sensor_dev_attr_sf2_point2_fan3.dev_attr.attr, + &sensor_dev_attr_sf2_point3_fan3.dev_attr.attr, + &sensor_dev_attr_sf2_point4_fan3.dev_attr.attr, + &sensor_dev_attr_sf2_level1_fan1.dev_attr.attr, + &sensor_dev_attr_sf2_level2_fan1.dev_attr.attr, + &sensor_dev_attr_sf2_level3_fan1.dev_attr.attr, + &sensor_dev_attr_sf2_level1_fan2.dev_attr.attr, + &sensor_dev_attr_sf2_level2_fan2.dev_attr.attr, + &sensor_dev_attr_sf2_level3_fan2.dev_attr.attr, + &sensor_dev_attr_sf2_level1_fan3.dev_attr.attr, + &sensor_dev_attr_sf2_level2_fan3.dev_attr.attr, + &sensor_dev_attr_sf2_level3_fan3.dev_attr.attr, + &sensor_dev_attr_fan1_input.dev_attr.attr, + &sensor_dev_attr_fan1_min.dev_attr.attr, + &sensor_dev_attr_fan1_div.dev_attr.attr, + &sensor_dev_attr_fan2_input.dev_attr.attr, + &sensor_dev_attr_fan2_min.dev_attr.attr, + &sensor_dev_attr_fan2_div.dev_attr.attr, + &sensor_dev_attr_fan3_input.dev_attr.attr, + &sensor_dev_attr_fan3_min.dev_attr.attr, + &sensor_dev_attr_fan3_div.dev_attr.attr, + NULL +}; + +static const struct attribute_group w83792d_group = { + .attrs = w83792d_attributes, +}; static int w83792d_detect(struct i2c_adapter *adapter, int address, int kind) @@ -1268,59 +1368,46 @@ w83792d_detect(struct i2c_adapter *adapter, int address, int kind) } /* Register sysfs hooks */ - data->class_dev = hwmon_device_register(dev); - if (IS_ERR(data->class_dev)) { - err = PTR_ERR(data->class_dev); + if ((err = sysfs_create_group(&dev->kobj, &w83792d_group))) goto ERROR3; - } - for (i = 0; i < 9; i++) { - device_create_file(dev, &sda_in_input[i].dev_attr); - device_create_file(dev, &sda_in_max[i].dev_attr); - device_create_file(dev, &sda_in_min[i].dev_attr); - } - for (i = 0; i < 3; i++) - device_create_file_fan(dev, i); /* Read GPIO enable register to check if pins for fan 4,5 are used as GPIO */ val1 = w83792d_read_value(client, W83792D_REG_GPIO_EN); + if (!(val1 & 0x40)) - device_create_file_fan(dev, 3); + if ((err = sysfs_create_group(&dev->kobj, + &w83792d_group_fan[0]))) + goto exit_remove_files; + if (!(val1 & 0x20)) - device_create_file_fan(dev, 4); + if ((err = sysfs_create_group(&dev->kobj, + &w83792d_group_fan[1]))) + goto exit_remove_files; val1 = w83792d_read_value(client, W83792D_REG_PIN); if (val1 & 0x40) - device_create_file_fan(dev, 5); + if ((err = sysfs_create_group(&dev->kobj, + &w83792d_group_fan[2]))) + goto exit_remove_files; + if (val1 & 0x04) - device_create_file_fan(dev, 6); + if ((err = sysfs_create_group(&dev->kobj, + &w83792d_group_fan[3]))) + goto exit_remove_files; - for (i = 0; i < 3; i++) { - device_create_file(dev, &sda_temp_input[i].dev_attr); - device_create_file(dev, &sda_temp_max[i].dev_attr); - device_create_file(dev, &sda_temp_max_hyst[i].dev_attr); - device_create_file(dev, &sda_thermal_cruise[i].dev_attr); - device_create_file(dev, &sda_tolerance[i].dev_attr); + data->class_dev = hwmon_device_register(dev); + if (IS_ERR(data->class_dev)) { + err = PTR_ERR(data->class_dev); + goto exit_remove_files; } - for (i = 0; i < ARRAY_SIZE(sda_pwm); i++) { - device_create_file(dev, &sda_pwm[i].dev_attr); - device_create_file(dev, &sda_pwm_enable[i].dev_attr); - device_create_file(dev, &sda_pwm_mode[i].dev_attr); - } - - device_create_file(dev, &dev_attr_alarms); - device_create_file(dev, &dev_attr_chassis); - device_create_file(dev, &dev_attr_chassis_clear); - - for (i = 0; i < ARRAY_SIZE(sda_sf2_point); i++) - device_create_file(dev, &sda_sf2_point[i].dev_attr); - - for (i = 0; i < ARRAY_SIZE(sda_sf2_level); i++) - device_create_file(dev, &sda_sf2_level[i].dev_attr); - return 0; +exit_remove_files: + sysfs_remove_group(&dev->kobj, &w83792d_group); + for (i = 0; i < ARRAY_SIZE(w83792d_group_fan); i++) + sysfs_remove_group(&dev->kobj, &w83792d_group_fan[i]); ERROR3: if (data->lm75[0] != NULL) { i2c_detach_client(data->lm75[0]); @@ -1342,11 +1429,16 @@ static int w83792d_detach_client(struct i2c_client *client) { struct w83792d_data *data = i2c_get_clientdata(client); - int err; + int err, i; /* main client */ - if (data) + if (data) { hwmon_device_unregister(data->class_dev); + sysfs_remove_group(&client->dev.kobj, &w83792d_group); + for (i = 0; i < ARRAY_SIZE(w83792d_group_fan); i++) + sysfs_remove_group(&client->dev.kobj, + &w83792d_group_fan[i]); + } if ((err = i2c_detach_client(client))) return err; From a5ebe668add5f76ed8f01f752b37cfa164a26a30 Mon Sep 17 00:00:00 2001 From: Jean Delvare Date: Sun, 24 Sep 2006 21:24:46 +0200 Subject: [PATCH 37/39] hwmon: Fix unchecked return status, batch 6 hwmon: Fix unchecked return status, batch 6 Fix up 5 more hwmon drivers so that they no longer ignore return status from device_create_file(). Signed-off-by: Jean Delvare Signed-off-by: Greg Kroah-Hartman --- drivers/hwmon/atxp1.c | 25 ++++++++-- drivers/hwmon/ds1621.c | 28 +++++++---- drivers/hwmon/max1619.c | 33 +++++++++---- drivers/hwmon/sis5595.c | 101 ++++++++++++++++++++++++++++------------ drivers/hwmon/via686a.c | 83 ++++++++++++++++++++------------- 5 files changed, 185 insertions(+), 85 deletions(-) diff --git a/drivers/hwmon/atxp1.c b/drivers/hwmon/atxp1.c index ba843f8c4cef..0ccdd0750c44 100644 --- a/drivers/hwmon/atxp1.c +++ b/drivers/hwmon/atxp1.c @@ -27,6 +27,7 @@ #include #include #include +#include MODULE_LICENSE("GPL"); MODULE_DESCRIPTION("System voltages control via Attansic ATXP1"); @@ -250,6 +251,17 @@ static ssize_t atxp1_storegpio2(struct device *dev, struct device_attribute *att */ static DEVICE_ATTR(gpio2, S_IRUGO | S_IWUSR, atxp1_showgpio2, atxp1_storegpio2); +static struct attribute *atxp1_attributes[] = { + &dev_attr_gpio1.attr, + &dev_attr_gpio2.attr, + &dev_attr_cpu0_vid.attr, + NULL +}; + +static const struct attribute_group atxp1_group = { + .attrs = atxp1_attributes, +}; + static int atxp1_attach_adapter(struct i2c_adapter *adapter) { @@ -319,21 +331,23 @@ static int atxp1_detect(struct i2c_adapter *adapter, int address, int kind) goto exit_free; } + /* Register sysfs hooks */ + if ((err = sysfs_create_group(&new_client->dev.kobj, &atxp1_group))) + goto exit_detach; + data->class_dev = hwmon_device_register(&new_client->dev); if (IS_ERR(data->class_dev)) { err = PTR_ERR(data->class_dev); - goto exit_detach; + goto exit_remove_files; } - device_create_file(&new_client->dev, &dev_attr_gpio1); - device_create_file(&new_client->dev, &dev_attr_gpio2); - device_create_file(&new_client->dev, &dev_attr_cpu0_vid); - dev_info(&new_client->dev, "Using VRM: %d.%d\n", data->vrm / 10, data->vrm % 10); return 0; +exit_remove_files: + sysfs_remove_group(&new_client->dev.kobj, &atxp1_group); exit_detach: i2c_detach_client(new_client); exit_free: @@ -348,6 +362,7 @@ static int atxp1_detach_client(struct i2c_client * client) int err; hwmon_device_unregister(data->class_dev); + sysfs_remove_group(&client->dev.kobj, &atxp1_group); err = i2c_detach_client(client); diff --git a/drivers/hwmon/ds1621.c b/drivers/hwmon/ds1621.c index 478eb4bb8570..c849c0c6ee9c 100644 --- a/drivers/hwmon/ds1621.c +++ b/drivers/hwmon/ds1621.c @@ -29,6 +29,7 @@ #include #include #include +#include #include "lm75.h" /* Addresses to scan */ @@ -178,6 +179,18 @@ static DEVICE_ATTR(temp1_input, S_IRUGO , show_temp, NULL); static DEVICE_ATTR(temp1_min, S_IWUSR | S_IRUGO , show_temp_min, set_temp_min); static DEVICE_ATTR(temp1_max, S_IWUSR | S_IRUGO, show_temp_max, set_temp_max); +static struct attribute *ds1621_attributes[] = { + &dev_attr_temp1_input.attr, + &dev_attr_temp1_min.attr, + &dev_attr_temp1_max.attr, + &dev_attr_alarms.attr, + NULL +}; + +static const struct attribute_group ds1621_group = { + .attrs = ds1621_attributes, +}; + static int ds1621_attach_adapter(struct i2c_adapter *adapter) { @@ -253,21 +266,19 @@ static int ds1621_detect(struct i2c_adapter *adapter, int address, ds1621_init_client(new_client); /* Register sysfs hooks */ + if ((err = sysfs_create_group(&new_client->dev.kobj, &ds1621_group))) + goto exit_detach; + data->class_dev = hwmon_device_register(&new_client->dev); if (IS_ERR(data->class_dev)) { err = PTR_ERR(data->class_dev); - goto exit_detach; + goto exit_remove_files; } - device_create_file(&new_client->dev, &dev_attr_alarms); - device_create_file(&new_client->dev, &dev_attr_temp1_input); - device_create_file(&new_client->dev, &dev_attr_temp1_min); - device_create_file(&new_client->dev, &dev_attr_temp1_max); - return 0; -/* OK, this is not exactly good programming practice, usually. But it is - very code-efficient in this case. */ + exit_remove_files: + sysfs_remove_group(&new_client->dev.kobj, &ds1621_group); exit_detach: i2c_detach_client(new_client); exit_free: @@ -282,6 +293,7 @@ static int ds1621_detach_client(struct i2c_client *client) int err; hwmon_device_unregister(data->class_dev); + sysfs_remove_group(&client->dev.kobj, &ds1621_group); if ((err = i2c_detach_client(client))) return err; diff --git a/drivers/hwmon/max1619.c b/drivers/hwmon/max1619.c index b4135b5971f4..2f58f651f03a 100644 --- a/drivers/hwmon/max1619.c +++ b/drivers/hwmon/max1619.c @@ -34,6 +34,7 @@ #include #include #include +#include static unsigned short normal_i2c[] = { 0x18, 0x19, 0x1a, 0x29, 0x2a, 0x2b, @@ -172,6 +173,22 @@ static DEVICE_ATTR(temp2_crit_hyst, S_IWUSR | S_IRUGO, show_temp_hyst2, set_temp_hyst2); static DEVICE_ATTR(alarms, S_IRUGO, show_alarms, NULL); +static struct attribute *max1619_attributes[] = { + &dev_attr_temp1_input.attr, + &dev_attr_temp2_input.attr, + &dev_attr_temp2_min.attr, + &dev_attr_temp2_max.attr, + &dev_attr_temp2_crit.attr, + &dev_attr_temp2_crit_hyst.attr, + + &dev_attr_alarms.attr, + NULL +}; + +static const struct attribute_group max1619_group = { + .attrs = max1619_attributes, +}; + /* * Real code */ @@ -273,22 +290,19 @@ static int max1619_detect(struct i2c_adapter *adapter, int address, int kind) max1619_init_client(new_client); /* Register sysfs hooks */ + if ((err = sysfs_create_group(&new_client->dev.kobj, &max1619_group))) + goto exit_detach; + data->class_dev = hwmon_device_register(&new_client->dev); if (IS_ERR(data->class_dev)) { err = PTR_ERR(data->class_dev); - goto exit_detach; + goto exit_remove_files; } - device_create_file(&new_client->dev, &dev_attr_temp1_input); - device_create_file(&new_client->dev, &dev_attr_temp2_input); - device_create_file(&new_client->dev, &dev_attr_temp2_min); - device_create_file(&new_client->dev, &dev_attr_temp2_max); - device_create_file(&new_client->dev, &dev_attr_temp2_crit); - device_create_file(&new_client->dev, &dev_attr_temp2_crit_hyst); - device_create_file(&new_client->dev, &dev_attr_alarms); - return 0; +exit_remove_files: + sysfs_remove_group(&new_client->dev.kobj, &max1619_group); exit_detach: i2c_detach_client(new_client); exit_free: @@ -318,6 +332,7 @@ static int max1619_detach_client(struct i2c_client *client) int err; hwmon_device_unregister(data->class_dev); + sysfs_remove_group(&client->dev.kobj, &max1619_group); if ((err = i2c_detach_client(client))) return err; diff --git a/drivers/hwmon/sis5595.c b/drivers/hwmon/sis5595.c index 3783af4195bd..95a4b5d9eaf2 100644 --- a/drivers/hwmon/sis5595.c +++ b/drivers/hwmon/sis5595.c @@ -61,6 +61,7 @@ #include #include #include +#include #include @@ -473,6 +474,50 @@ static ssize_t show_alarms(struct device *dev, struct device_attribute *attr, ch return sprintf(buf, "%d\n", data->alarms); } static DEVICE_ATTR(alarms, S_IRUGO, show_alarms, NULL); + +static struct attribute *sis5595_attributes[] = { + &dev_attr_in0_input.attr, + &dev_attr_in0_min.attr, + &dev_attr_in0_max.attr, + &dev_attr_in1_input.attr, + &dev_attr_in1_min.attr, + &dev_attr_in1_max.attr, + &dev_attr_in2_input.attr, + &dev_attr_in2_min.attr, + &dev_attr_in2_max.attr, + &dev_attr_in3_input.attr, + &dev_attr_in3_min.attr, + &dev_attr_in3_max.attr, + + &dev_attr_fan1_input.attr, + &dev_attr_fan1_min.attr, + &dev_attr_fan1_div.attr, + &dev_attr_fan2_input.attr, + &dev_attr_fan2_min.attr, + &dev_attr_fan2_div.attr, + + &dev_attr_alarms.attr, + NULL +}; + +static const struct attribute_group sis5595_group = { + .attrs = sis5595_attributes, +}; + +static struct attribute *sis5595_attributes_opt[] = { + &dev_attr_in4_input.attr, + &dev_attr_in4_min.attr, + &dev_attr_in4_max.attr, + + &dev_attr_temp1_input.attr, + &dev_attr_temp1_max.attr, + &dev_attr_temp1_max_hyst.attr, + NULL +}; + +static const struct attribute_group sis5595_group_opt = { + .attrs = sis5595_attributes_opt, +}; /* This is called when the module is loaded */ static int sis5595_detect(struct i2c_adapter *adapter) @@ -566,43 +611,37 @@ static int sis5595_detect(struct i2c_adapter *adapter) } /* Register sysfs hooks */ + if ((err = sysfs_create_group(&new_client->dev.kobj, &sis5595_group))) + goto exit_detach; + if (data->maxins == 4) { + if ((err = device_create_file(&new_client->dev, + &dev_attr_in4_input)) + || (err = device_create_file(&new_client->dev, + &dev_attr_in4_min)) + || (err = device_create_file(&new_client->dev, + &dev_attr_in4_max))) + goto exit_remove_files; + } else { + if ((err = device_create_file(&new_client->dev, + &dev_attr_temp1_input)) + || (err = device_create_file(&new_client->dev, + &dev_attr_temp1_max)) + || (err = device_create_file(&new_client->dev, + &dev_attr_temp1_max_hyst))) + goto exit_remove_files; + } + data->class_dev = hwmon_device_register(&new_client->dev); if (IS_ERR(data->class_dev)) { err = PTR_ERR(data->class_dev); - goto exit_detach; + goto exit_remove_files; } - device_create_file(&new_client->dev, &dev_attr_in0_input); - device_create_file(&new_client->dev, &dev_attr_in0_min); - device_create_file(&new_client->dev, &dev_attr_in0_max); - device_create_file(&new_client->dev, &dev_attr_in1_input); - device_create_file(&new_client->dev, &dev_attr_in1_min); - device_create_file(&new_client->dev, &dev_attr_in1_max); - device_create_file(&new_client->dev, &dev_attr_in2_input); - device_create_file(&new_client->dev, &dev_attr_in2_min); - device_create_file(&new_client->dev, &dev_attr_in2_max); - device_create_file(&new_client->dev, &dev_attr_in3_input); - device_create_file(&new_client->dev, &dev_attr_in3_min); - device_create_file(&new_client->dev, &dev_attr_in3_max); - if (data->maxins == 4) { - device_create_file(&new_client->dev, &dev_attr_in4_input); - device_create_file(&new_client->dev, &dev_attr_in4_min); - device_create_file(&new_client->dev, &dev_attr_in4_max); - } - device_create_file(&new_client->dev, &dev_attr_fan1_input); - device_create_file(&new_client->dev, &dev_attr_fan1_min); - device_create_file(&new_client->dev, &dev_attr_fan1_div); - device_create_file(&new_client->dev, &dev_attr_fan2_input); - device_create_file(&new_client->dev, &dev_attr_fan2_min); - device_create_file(&new_client->dev, &dev_attr_fan2_div); - device_create_file(&new_client->dev, &dev_attr_alarms); - if (data->maxins == 3) { - device_create_file(&new_client->dev, &dev_attr_temp1_input); - device_create_file(&new_client->dev, &dev_attr_temp1_max); - device_create_file(&new_client->dev, &dev_attr_temp1_max_hyst); - } return 0; +exit_remove_files: + sysfs_remove_group(&new_client->dev.kobj, &sis5595_group); + sysfs_remove_group(&new_client->dev.kobj, &sis5595_group_opt); exit_detach: i2c_detach_client(new_client); exit_free: @@ -619,6 +658,8 @@ static int sis5595_detach_client(struct i2c_client *client) int err; hwmon_device_unregister(data->class_dev); + sysfs_remove_group(&client->dev.kobj, &sis5595_group); + sysfs_remove_group(&client->dev.kobj, &sis5595_group_opt); if ((err = i2c_detach_client(client))) return err; diff --git a/drivers/hwmon/via686a.c b/drivers/hwmon/via686a.c index 95ae056e5a94..f8acada0537a 100644 --- a/drivers/hwmon/via686a.c +++ b/drivers/hwmon/via686a.c @@ -40,6 +40,7 @@ #include #include #include +#include #include @@ -570,6 +571,48 @@ static ssize_t show_alarms(struct device *dev, struct device_attribute *attr, ch } static DEVICE_ATTR(alarms, S_IRUGO, show_alarms, NULL); +static struct attribute *via686a_attributes[] = { + &dev_attr_in0_input.attr, + &dev_attr_in1_input.attr, + &dev_attr_in2_input.attr, + &dev_attr_in3_input.attr, + &dev_attr_in4_input.attr, + &dev_attr_in0_min.attr, + &dev_attr_in1_min.attr, + &dev_attr_in2_min.attr, + &dev_attr_in3_min.attr, + &dev_attr_in4_min.attr, + &dev_attr_in0_max.attr, + &dev_attr_in1_max.attr, + &dev_attr_in2_max.attr, + &dev_attr_in3_max.attr, + &dev_attr_in4_max.attr, + + &dev_attr_temp1_input.attr, + &dev_attr_temp2_input.attr, + &dev_attr_temp3_input.attr, + &dev_attr_temp1_max.attr, + &dev_attr_temp2_max.attr, + &dev_attr_temp3_max.attr, + &dev_attr_temp1_max_hyst.attr, + &dev_attr_temp2_max_hyst.attr, + &dev_attr_temp3_max_hyst.attr, + + &dev_attr_fan1_input.attr, + &dev_attr_fan2_input.attr, + &dev_attr_fan1_min.attr, + &dev_attr_fan2_min.attr, + &dev_attr_fan1_div.attr, + &dev_attr_fan2_div.attr, + + &dev_attr_alarms.attr, + NULL +}; + +static const struct attribute_group via686a_group = { + .attrs = via686a_attributes, +}; + /* 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 = { @@ -650,46 +693,19 @@ static int via686a_detect(struct i2c_adapter *adapter) via686a_init_client(new_client); /* Register sysfs hooks */ + if ((err = sysfs_create_group(&new_client->dev.kobj, &via686a_group))) + goto exit_detach; + data->class_dev = hwmon_device_register(&new_client->dev); if (IS_ERR(data->class_dev)) { err = PTR_ERR(data->class_dev); - goto exit_detach; + goto exit_remove_files; } - device_create_file(&new_client->dev, &dev_attr_in0_input); - device_create_file(&new_client->dev, &dev_attr_in1_input); - device_create_file(&new_client->dev, &dev_attr_in2_input); - device_create_file(&new_client->dev, &dev_attr_in3_input); - device_create_file(&new_client->dev, &dev_attr_in4_input); - device_create_file(&new_client->dev, &dev_attr_in0_min); - device_create_file(&new_client->dev, &dev_attr_in1_min); - device_create_file(&new_client->dev, &dev_attr_in2_min); - device_create_file(&new_client->dev, &dev_attr_in3_min); - device_create_file(&new_client->dev, &dev_attr_in4_min); - device_create_file(&new_client->dev, &dev_attr_in0_max); - device_create_file(&new_client->dev, &dev_attr_in1_max); - device_create_file(&new_client->dev, &dev_attr_in2_max); - device_create_file(&new_client->dev, &dev_attr_in3_max); - device_create_file(&new_client->dev, &dev_attr_in4_max); - device_create_file(&new_client->dev, &dev_attr_temp1_input); - device_create_file(&new_client->dev, &dev_attr_temp2_input); - device_create_file(&new_client->dev, &dev_attr_temp3_input); - device_create_file(&new_client->dev, &dev_attr_temp1_max); - device_create_file(&new_client->dev, &dev_attr_temp2_max); - device_create_file(&new_client->dev, &dev_attr_temp3_max); - device_create_file(&new_client->dev, &dev_attr_temp1_max_hyst); - device_create_file(&new_client->dev, &dev_attr_temp2_max_hyst); - device_create_file(&new_client->dev, &dev_attr_temp3_max_hyst); - device_create_file(&new_client->dev, &dev_attr_fan1_input); - device_create_file(&new_client->dev, &dev_attr_fan2_input); - device_create_file(&new_client->dev, &dev_attr_fan1_min); - device_create_file(&new_client->dev, &dev_attr_fan2_min); - device_create_file(&new_client->dev, &dev_attr_fan1_div); - device_create_file(&new_client->dev, &dev_attr_fan2_div); - device_create_file(&new_client->dev, &dev_attr_alarms); - return 0; +exit_remove_files: + sysfs_remove_group(&new_client->dev.kobj, &via686a_group); exit_detach: i2c_detach_client(new_client); exit_free: @@ -705,6 +721,7 @@ static int via686a_detach_client(struct i2c_client *client) int err; hwmon_device_unregister(data->class_dev); + sysfs_remove_group(&client->dev.kobj, &via686a_group); if ((err = i2c_detach_client(client))) return err; From ce8c6ce1eceecfe090f6c1aa4108087b2051497b Mon Sep 17 00:00:00 2001 From: Jean Delvare Date: Sun, 24 Sep 2006 21:25:12 +0200 Subject: [PATCH 38/39] hwmon: Fix unchecked return status, SMSC chips hwmon: Fix unchecked return status, SMSC chips Fix up 2 more hwmon drivers so that they no longer ignore return status from device_create_file(). Signed-off-by: Jean Delvare Signed-off-by: Greg Kroah-Hartman --- drivers/hwmon/smsc47m1.c | 78 ++++++++++++++----- drivers/hwmon/smsc47m192.c | 150 +++++++++++++++++++++---------------- 2 files changed, 145 insertions(+), 83 deletions(-) diff --git a/drivers/hwmon/smsc47m1.c b/drivers/hwmon/smsc47m1.c index 9cd28f2709fc..47132fd26b1b 100644 --- a/drivers/hwmon/smsc47m1.c +++ b/drivers/hwmon/smsc47m1.c @@ -35,6 +35,7 @@ #include #include #include +#include #include /* Address is autodetected, there is no default value */ @@ -347,6 +348,30 @@ fan_present(2); static DEVICE_ATTR(alarms, S_IRUGO, get_alarms, NULL); +/* Almost all sysfs files may or may not be created depending on the chip + setup so we create them individually. It is still convenient to define a + group to remove them all at once. */ +static struct attribute *smsc47m1_attributes[] = { + &dev_attr_fan1_input.attr, + &dev_attr_fan1_min.attr, + &dev_attr_fan1_div.attr, + &dev_attr_fan2_input.attr, + &dev_attr_fan2_min.attr, + &dev_attr_fan2_div.attr, + + &dev_attr_pwm1.attr, + &dev_attr_pwm1_enable.attr, + &dev_attr_pwm2.attr, + &dev_attr_pwm2_enable.attr, + + &dev_attr_alarms.attr, + NULL +}; + +static const struct attribute_group smsc47m1_group = { + .attrs = smsc47m1_attributes, +}; + static int __init smsc47m1_find(unsigned short *addr) { u8 val; @@ -447,46 +472,62 @@ static int smsc47m1_detect(struct i2c_adapter *adapter) smsc47m1_update_device(&new_client->dev, 1); /* Register sysfs hooks */ - data->class_dev = hwmon_device_register(&new_client->dev); - if (IS_ERR(data->class_dev)) { - err = PTR_ERR(data->class_dev); - goto error_detach; - } - if (fan1) { - device_create_file(&new_client->dev, &dev_attr_fan1_input); - device_create_file(&new_client->dev, &dev_attr_fan1_min); - device_create_file(&new_client->dev, &dev_attr_fan1_div); + if ((err = device_create_file(&new_client->dev, + &dev_attr_fan1_input)) + || (err = device_create_file(&new_client->dev, + &dev_attr_fan1_min)) + || (err = device_create_file(&new_client->dev, + &dev_attr_fan1_div))) + goto error_remove_files; } else dev_dbg(&new_client->dev, "Fan 1 not enabled by hardware, " "skipping\n"); if (fan2) { - device_create_file(&new_client->dev, &dev_attr_fan2_input); - device_create_file(&new_client->dev, &dev_attr_fan2_min); - device_create_file(&new_client->dev, &dev_attr_fan2_div); + if ((err = device_create_file(&new_client->dev, + &dev_attr_fan2_input)) + || (err = device_create_file(&new_client->dev, + &dev_attr_fan2_min)) + || (err = device_create_file(&new_client->dev, + &dev_attr_fan2_div))) + goto error_remove_files; } else dev_dbg(&new_client->dev, "Fan 2 not enabled by hardware, " "skipping\n"); if (pwm1) { - device_create_file(&new_client->dev, &dev_attr_pwm1); - device_create_file(&new_client->dev, &dev_attr_pwm1_enable); + if ((err = device_create_file(&new_client->dev, + &dev_attr_pwm1)) + || (err = device_create_file(&new_client->dev, + &dev_attr_pwm1_enable))) + goto error_remove_files; } else dev_dbg(&new_client->dev, "PWM 1 not enabled by hardware, " "skipping\n"); if (pwm2) { - device_create_file(&new_client->dev, &dev_attr_pwm2); - device_create_file(&new_client->dev, &dev_attr_pwm2_enable); + if ((err = device_create_file(&new_client->dev, + &dev_attr_pwm2)) + || (err = device_create_file(&new_client->dev, + &dev_attr_pwm2_enable))) + goto error_remove_files; } else dev_dbg(&new_client->dev, "PWM 2 not enabled by hardware, " "skipping\n"); - device_create_file(&new_client->dev, &dev_attr_alarms); + if ((err = device_create_file(&new_client->dev, &dev_attr_alarms))) + goto error_remove_files; + + data->class_dev = hwmon_device_register(&new_client->dev); + if (IS_ERR(data->class_dev)) { + err = PTR_ERR(data->class_dev); + goto error_remove_files; + } return 0; -error_detach: +error_remove_files: + sysfs_remove_group(&new_client->dev.kobj, &smsc47m1_group); i2c_detach_client(new_client); error_free: kfree(data); @@ -501,6 +542,7 @@ static int smsc47m1_detach_client(struct i2c_client *client) int err; hwmon_device_unregister(data->class_dev); + sysfs_remove_group(&client->dev.kobj, &smsc47m1_group); if ((err = i2c_detach_client(client))) return err; diff --git a/drivers/hwmon/smsc47m192.c b/drivers/hwmon/smsc47m192.c index bdc4570acf9a..a6833f437395 100644 --- a/drivers/hwmon/smsc47m192.c +++ b/drivers/hwmon/smsc47m192.c @@ -30,6 +30,7 @@ #include #include #include +#include /* Addresses to scan */ static unsigned short normal_i2c[] = { 0x2c, 0x2d, I2C_CLIENT_END }; @@ -370,6 +371,75 @@ static SENSOR_DEVICE_ATTR(in5_alarm, S_IRUGO, show_alarm, NULL, 0x0200); static SENSOR_DEVICE_ATTR(in6_alarm, S_IRUGO, show_alarm, NULL, 0x0400); static SENSOR_DEVICE_ATTR(in7_alarm, S_IRUGO, show_alarm, NULL, 0x0800); +static struct attribute *smsc47m192_attributes[] = { + &sensor_dev_attr_in0_input.dev_attr.attr, + &sensor_dev_attr_in0_min.dev_attr.attr, + &sensor_dev_attr_in0_max.dev_attr.attr, + &sensor_dev_attr_in0_alarm.dev_attr.attr, + &sensor_dev_attr_in1_input.dev_attr.attr, + &sensor_dev_attr_in1_min.dev_attr.attr, + &sensor_dev_attr_in1_max.dev_attr.attr, + &sensor_dev_attr_in1_alarm.dev_attr.attr, + &sensor_dev_attr_in2_input.dev_attr.attr, + &sensor_dev_attr_in2_min.dev_attr.attr, + &sensor_dev_attr_in2_max.dev_attr.attr, + &sensor_dev_attr_in2_alarm.dev_attr.attr, + &sensor_dev_attr_in3_input.dev_attr.attr, + &sensor_dev_attr_in3_min.dev_attr.attr, + &sensor_dev_attr_in3_max.dev_attr.attr, + &sensor_dev_attr_in3_alarm.dev_attr.attr, + &sensor_dev_attr_in5_input.dev_attr.attr, + &sensor_dev_attr_in5_min.dev_attr.attr, + &sensor_dev_attr_in5_max.dev_attr.attr, + &sensor_dev_attr_in5_alarm.dev_attr.attr, + &sensor_dev_attr_in6_input.dev_attr.attr, + &sensor_dev_attr_in6_min.dev_attr.attr, + &sensor_dev_attr_in6_max.dev_attr.attr, + &sensor_dev_attr_in6_alarm.dev_attr.attr, + &sensor_dev_attr_in7_input.dev_attr.attr, + &sensor_dev_attr_in7_min.dev_attr.attr, + &sensor_dev_attr_in7_max.dev_attr.attr, + &sensor_dev_attr_in7_alarm.dev_attr.attr, + + &sensor_dev_attr_temp1_input.dev_attr.attr, + &sensor_dev_attr_temp1_max.dev_attr.attr, + &sensor_dev_attr_temp1_min.dev_attr.attr, + &sensor_dev_attr_temp1_offset.dev_attr.attr, + &sensor_dev_attr_temp1_alarm.dev_attr.attr, + &sensor_dev_attr_temp2_input.dev_attr.attr, + &sensor_dev_attr_temp2_max.dev_attr.attr, + &sensor_dev_attr_temp2_min.dev_attr.attr, + &sensor_dev_attr_temp2_offset.dev_attr.attr, + &sensor_dev_attr_temp2_alarm.dev_attr.attr, + &sensor_dev_attr_temp2_input_fault.dev_attr.attr, + &sensor_dev_attr_temp3_input.dev_attr.attr, + &sensor_dev_attr_temp3_max.dev_attr.attr, + &sensor_dev_attr_temp3_min.dev_attr.attr, + &sensor_dev_attr_temp3_offset.dev_attr.attr, + &sensor_dev_attr_temp3_alarm.dev_attr.attr, + &sensor_dev_attr_temp3_input_fault.dev_attr.attr, + + &dev_attr_cpu0_vid.attr, + &dev_attr_vrm.attr, + NULL +}; + +static const struct attribute_group smsc47m192_group = { + .attrs = smsc47m192_attributes, +}; + +static struct attribute *smsc47m192_attributes_in4[] = { + &sensor_dev_attr_in4_input.dev_attr.attr, + &sensor_dev_attr_in4_min.dev_attr.attr, + &sensor_dev_attr_in4_max.dev_attr.attr, + &sensor_dev_attr_in4_alarm.dev_attr.attr, + NULL +}; + +static const struct attribute_group smsc47m192_group_in4 = { + .attrs = smsc47m192_attributes_in4, +}; + /* This function is called when: * smsc47m192_driver is inserted (when this module is loaded), for each available adapter @@ -471,80 +541,28 @@ static int smsc47m192_detect(struct i2c_adapter *adapter, int address, smsc47m192_init_client(client); /* Register sysfs hooks */ - data->class_dev = hwmon_device_register(&client->dev); - if (IS_ERR(data->class_dev)) { - err = PTR_ERR(data->class_dev); + if ((err = sysfs_create_group(&client->dev.kobj, &smsc47m192_group))) goto exit_detach; - } - - device_create_file(&client->dev, &sensor_dev_attr_in0_input.dev_attr); - device_create_file(&client->dev, &sensor_dev_attr_in0_min.dev_attr); - device_create_file(&client->dev, &sensor_dev_attr_in0_max.dev_attr); - device_create_file(&client->dev, &sensor_dev_attr_in0_alarm.dev_attr); - device_create_file(&client->dev, &sensor_dev_attr_in1_input.dev_attr); - device_create_file(&client->dev, &sensor_dev_attr_in1_min.dev_attr); - device_create_file(&client->dev, &sensor_dev_attr_in1_max.dev_attr); - device_create_file(&client->dev, &sensor_dev_attr_in1_alarm.dev_attr); - device_create_file(&client->dev, &sensor_dev_attr_in2_input.dev_attr); - device_create_file(&client->dev, &sensor_dev_attr_in2_min.dev_attr); - device_create_file(&client->dev, &sensor_dev_attr_in2_max.dev_attr); - device_create_file(&client->dev, &sensor_dev_attr_in2_alarm.dev_attr); - device_create_file(&client->dev, &sensor_dev_attr_in3_input.dev_attr); - device_create_file(&client->dev, &sensor_dev_attr_in3_min.dev_attr); - device_create_file(&client->dev, &sensor_dev_attr_in3_max.dev_attr); - device_create_file(&client->dev, &sensor_dev_attr_in3_alarm.dev_attr); /* Pin 110 is either in4 (+12V) or VID4 */ config = i2c_smbus_read_byte_data(client, SMSC47M192_REG_CONFIG); if (!(config & 0x20)) { - device_create_file(&client->dev, - &sensor_dev_attr_in4_input.dev_attr); - device_create_file(&client->dev, - &sensor_dev_attr_in4_min.dev_attr); - device_create_file(&client->dev, - &sensor_dev_attr_in4_max.dev_attr); - device_create_file(&client->dev, - &sensor_dev_attr_in4_alarm.dev_attr); + if ((err = sysfs_create_group(&client->dev.kobj, + &smsc47m192_group_in4))) + goto exit_remove_files; + } + + data->class_dev = hwmon_device_register(&client->dev); + if (IS_ERR(data->class_dev)) { + err = PTR_ERR(data->class_dev); + goto exit_remove_files; } - device_create_file(&client->dev, &sensor_dev_attr_in5_input.dev_attr); - device_create_file(&client->dev, &sensor_dev_attr_in5_min.dev_attr); - device_create_file(&client->dev, &sensor_dev_attr_in5_max.dev_attr); - device_create_file(&client->dev, &sensor_dev_attr_in5_alarm.dev_attr); - device_create_file(&client->dev, &sensor_dev_attr_in6_input.dev_attr); - device_create_file(&client->dev, &sensor_dev_attr_in6_min.dev_attr); - device_create_file(&client->dev, &sensor_dev_attr_in6_max.dev_attr); - device_create_file(&client->dev, &sensor_dev_attr_in6_alarm.dev_attr); - device_create_file(&client->dev, &sensor_dev_attr_in7_input.dev_attr); - device_create_file(&client->dev, &sensor_dev_attr_in7_min.dev_attr); - device_create_file(&client->dev, &sensor_dev_attr_in7_max.dev_attr); - device_create_file(&client->dev, &sensor_dev_attr_in7_alarm.dev_attr); - device_create_file(&client->dev, &sensor_dev_attr_temp1_input.dev_attr); - device_create_file(&client->dev, &sensor_dev_attr_temp1_max.dev_attr); - device_create_file(&client->dev, &sensor_dev_attr_temp1_min.dev_attr); - device_create_file(&client->dev, - &sensor_dev_attr_temp1_offset.dev_attr); - device_create_file(&client->dev, &sensor_dev_attr_temp1_alarm.dev_attr); - device_create_file(&client->dev, &sensor_dev_attr_temp2_input.dev_attr); - device_create_file(&client->dev, &sensor_dev_attr_temp2_max.dev_attr); - device_create_file(&client->dev, &sensor_dev_attr_temp2_min.dev_attr); - device_create_file(&client->dev, - &sensor_dev_attr_temp2_offset.dev_attr); - device_create_file(&client->dev, &sensor_dev_attr_temp2_alarm.dev_attr); - device_create_file(&client->dev, - &sensor_dev_attr_temp2_input_fault.dev_attr); - device_create_file(&client->dev, &sensor_dev_attr_temp3_input.dev_attr); - device_create_file(&client->dev, &sensor_dev_attr_temp3_max.dev_attr); - device_create_file(&client->dev, &sensor_dev_attr_temp3_min.dev_attr); - device_create_file(&client->dev, - &sensor_dev_attr_temp3_offset.dev_attr); - device_create_file(&client->dev, &sensor_dev_attr_temp3_alarm.dev_attr); - device_create_file(&client->dev, - &sensor_dev_attr_temp3_input_fault.dev_attr); - device_create_file(&client->dev, &dev_attr_cpu0_vid); - device_create_file(&client->dev, &dev_attr_vrm); return 0; +exit_remove_files: + sysfs_remove_group(&client->dev.kobj, &smsc47m192_group); + sysfs_remove_group(&client->dev.kobj, &smsc47m192_group_in4); exit_detach: i2c_detach_client(client); exit_free: @@ -559,6 +577,8 @@ static int smsc47m192_detach_client(struct i2c_client *client) int err; hwmon_device_unregister(data->class_dev); + sysfs_remove_group(&client->dev.kobj, &smsc47m192_group); + sysfs_remove_group(&client->dev.kobj, &smsc47m192_group_in4); if ((err = i2c_detach_client(client))) return err; From 3379ceeefde923a05c2c77ed2d84ba26c2fe9e81 Mon Sep 17 00:00:00 2001 From: Jean Delvare Date: Sun, 24 Sep 2006 21:25:52 +0200 Subject: [PATCH 39/39] hwmon: Remove Yuan Mu's address hwmon: Remove Yuan Mu's address Yuan Mu no longer works at Winbond. I wish to publicly thank Yuan for his help with Winbond hardware monitoring chips support during the past 10 months. Signed-off-by: Jean Delvare Signed-off-by: Greg Kroah-Hartman --- Documentation/hwmon/w83627ehf | 2 +- drivers/hwmon/w83627ehf.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Documentation/hwmon/w83627ehf b/Documentation/hwmon/w83627ehf index 1474e78d5d32..fae3b781d82d 100644 --- a/Documentation/hwmon/w83627ehf +++ b/Documentation/hwmon/w83627ehf @@ -9,7 +9,7 @@ Supported chips: Authors: Jean Delvare - Yuan Mu + Yuan Mu (Winbond) Rudolf Marek Description diff --git a/drivers/hwmon/w83627ehf.c b/drivers/hwmon/w83627ehf.c index 7a58b079d735..833faa275ffa 100644 --- a/drivers/hwmon/w83627ehf.c +++ b/drivers/hwmon/w83627ehf.c @@ -2,7 +2,7 @@ w83627ehf - Driver for the hardware monitoring functionality of the Winbond W83627EHF Super-I/O chip Copyright (C) 2005 Jean Delvare - Copyright (C) 2006 Yuan Mu , + Copyright (C) 2006 Yuan Mu (Winbond), Rudolf Marek David Hubbard