iwmc3200wifi: Test of wrong pointer after kzalloc in iwm_mlme_update_bss_table()
[safe/jmp/linux-2.6] / drivers / hwmon / w83791d.c
index a8ff4e1..97851c5 100644 (file)
@@ -53,7 +53,10 @@ static const unsigned short normal_i2c[] = { 0x2c, 0x2d, 0x2e, 0x2f,
 
 /* Insmod parameters */
 I2C_CLIENT_INSMOD_1(w83791d);
-I2C_CLIENT_MODULE_PARM(force_subclients, "List of subclient addresses: "
+
+static unsigned short force_subclients[4];
+module_param_array(force_subclients, short, NULL, 0);
+MODULE_PARM_DESC(force_subclients, "List of subclient addresses: "
                        "{bus, clientaddr, subclientaddr1, subclientaddr2}");
 
 static int reset;
@@ -125,6 +128,17 @@ static const u8 W83791D_REG_PWM[NUMBER_OF_PWM] = {
        0xA1,                   /* PWM 5 duty cycle register in DataSheet */
 };
 
+static const u8 W83791D_REG_TEMP_TARGET[3] = {
+       0x85,                   /* PWM 1 target temperature for temp 1 */
+       0x86,                   /* PWM 2 target temperature for temp 2 */
+       0x96,                   /* PWM 3 target temperature for temp 3 */
+};
+
+static const u8 W83791D_REG_TEMP_TOL[2] = {
+       0x87,                   /* PWM 1/2 temperature tolerance */
+       0x97,                   /* PWM 3 temperature tolerance */
+};
+
 static const u8 W83791D_REG_FAN_CFG[2] = {
        0x84,                   /* FAN 1/2 configuration */
        0x95,                   /* FAN 3 configuration */
@@ -234,6 +248,15 @@ static u8 fan_to_reg(long rpm, int div)
                                 (val) < 0 ? ((val) - 250) / 500 * 128 : \
                                 ((val) + 250) / 500 * 128)
 
+/* for thermal cruise target temp, 7-bits, LSB = 1 degree Celsius */
+#define TARGET_TEMP_TO_REG(val)                ((val) < 0 ? 0 : \
+                                       (val) >= 127000 ? 127 : \
+                                       ((val) + 500) / 1000)
+
+/* for thermal cruise temp tolerance, 4-bits, LSB = 1 degree Celsius */
+#define TOL_TEMP_TO_REG(val)           ((val) < 0 ? 0 : \
+                                       (val) >= 15000 ? 15 : \
+                                       ((val) + 500) / 1000)
 
 #define BEEP_MASK_TO_REG(val)          ((val) & 0xffffff)
 #define BEEP_MASK_FROM_REG(val)                ((val) & 0xffffff)
@@ -287,6 +310,11 @@ struct w83791d_data {
 
        /* PWMs */
        u8 pwm[5];              /* pwm duty cycle */
+       u8 pwm_enable[3];       /* pwm enable status for fan 1-3
+                                       (fan 4-5 only support manual mode) */
+
+       u8 temp_target[3];      /* pwm 1-3 target temperature */
+       u8 temp_tolerance[3];   /* pwm 1-3 temperature tolerance */
 
        /* Misc */
        u32 alarms;             /* realtime status register encoding,combined */
@@ -707,6 +735,175 @@ static struct sensor_device_attribute sda_pwm[] = {
                        show_pwm, store_pwm, 4),
 };
 
+static ssize_t show_pwmenable(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 w83791d_data *data = w83791d_update_device(dev);
+       return sprintf(buf, "%u\n", data->pwm_enable[nr] + 1);
+}
+
+static ssize_t store_pwmenable(struct device *dev,
+               struct device_attribute *attr, const char *buf, size_t count)
+{
+       struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr);
+       struct i2c_client *client = to_i2c_client(dev);
+       struct w83791d_data *data = i2c_get_clientdata(client);
+       int nr = sensor_attr->index;
+       unsigned long val;
+       u8 reg_cfg_tmp;
+       u8 reg_idx = 0;
+       u8 val_shift = 0;
+       u8 keep_mask = 0;
+
+       int ret = strict_strtoul(buf, 10, &val);
+
+       if (ret || val < 1 || val > 3)
+               return -EINVAL;
+
+       mutex_lock(&data->update_lock);
+       data->pwm_enable[nr] = val - 1;
+       switch (nr) {
+       case 0:
+               reg_idx = 0;
+               val_shift = 2;
+               keep_mask = 0xf3;
+               break;
+       case 1:
+               reg_idx = 0;
+               val_shift = 4;
+               keep_mask = 0xcf;
+               break;
+       case 2:
+               reg_idx = 1;
+               val_shift = 2;
+               keep_mask = 0xf3;
+               break;
+       }
+
+       reg_cfg_tmp = w83791d_read(client, W83791D_REG_FAN_CFG[reg_idx]);
+       reg_cfg_tmp = (reg_cfg_tmp & keep_mask) |
+                                       data->pwm_enable[nr] << val_shift;
+
+       w83791d_write(client, W83791D_REG_FAN_CFG[reg_idx], reg_cfg_tmp);
+       mutex_unlock(&data->update_lock);
+
+       return count;
+}
+static struct sensor_device_attribute sda_pwmenable[] = {
+       SENSOR_ATTR(pwm1_enable, S_IWUSR | S_IRUGO,
+                       show_pwmenable, store_pwmenable, 0),
+       SENSOR_ATTR(pwm2_enable, S_IWUSR | S_IRUGO,
+                       show_pwmenable, store_pwmenable, 1),
+       SENSOR_ATTR(pwm3_enable, S_IWUSR | S_IRUGO,
+                       show_pwmenable, store_pwmenable, 2),
+};
+
+/* For Smart Fan I / Thermal Cruise */
+static ssize_t show_temp_target(struct device *dev,
+                       struct device_attribute *attr, char *buf)
+{
+       struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr);
+       struct w83791d_data *data = w83791d_update_device(dev);
+       int nr = sensor_attr->index;
+       return sprintf(buf, "%d\n", TEMP1_FROM_REG(data->temp_target[nr]));
+}
+
+static ssize_t store_temp_target(struct device *dev,
+               struct device_attribute *attr, const char *buf, size_t count)
+{
+       struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr);
+       struct i2c_client *client = to_i2c_client(dev);
+       struct w83791d_data *data = i2c_get_clientdata(client);
+       int nr = sensor_attr->index;
+       unsigned long val;
+       u8 target_mask;
+
+       if (strict_strtoul(buf, 10, &val))
+               return -EINVAL;
+
+       mutex_lock(&data->update_lock);
+       data->temp_target[nr] = TARGET_TEMP_TO_REG(val);
+       target_mask = w83791d_read(client,
+                               W83791D_REG_TEMP_TARGET[nr]) & 0x80;
+       w83791d_write(client, W83791D_REG_TEMP_TARGET[nr],
+                               data->temp_target[nr] | target_mask);
+       mutex_unlock(&data->update_lock);
+       return count;
+}
+
+static struct sensor_device_attribute sda_temp_target[] = {
+       SENSOR_ATTR(temp1_target, S_IWUSR | S_IRUGO,
+                       show_temp_target, store_temp_target, 0),
+       SENSOR_ATTR(temp2_target, S_IWUSR | S_IRUGO,
+                       show_temp_target, store_temp_target, 1),
+       SENSOR_ATTR(temp3_target, S_IWUSR | S_IRUGO,
+                       show_temp_target, store_temp_target, 2),
+};
+
+static ssize_t show_temp_tolerance(struct device *dev,
+                       struct device_attribute *attr, char *buf)
+{
+       struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr);
+       struct w83791d_data *data = w83791d_update_device(dev);
+       int nr = sensor_attr->index;
+       return sprintf(buf, "%d\n", TEMP1_FROM_REG(data->temp_tolerance[nr]));
+}
+
+static ssize_t store_temp_tolerance(struct device *dev,
+               struct device_attribute *attr, const char *buf, size_t count)
+{
+       struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr);
+       struct i2c_client *client = to_i2c_client(dev);
+       struct w83791d_data *data = i2c_get_clientdata(client);
+       int nr = sensor_attr->index;
+       unsigned long val;
+       u8 target_mask;
+       u8 reg_idx = 0;
+       u8 val_shift = 0;
+       u8 keep_mask = 0;
+
+       if (strict_strtoul(buf, 10, &val))
+               return -EINVAL;
+
+       switch (nr) {
+       case 0:
+               reg_idx = 0;
+               val_shift = 0;
+               keep_mask = 0xf0;
+               break;
+       case 1:
+               reg_idx = 0;
+               val_shift = 4;
+               keep_mask = 0x0f;
+               break;
+       case 2:
+               reg_idx = 1;
+               val_shift = 0;
+               keep_mask = 0xf0;
+               break;
+       }
+
+       mutex_lock(&data->update_lock);
+       data->temp_tolerance[nr] = TOL_TEMP_TO_REG(val);
+       target_mask = w83791d_read(client,
+                       W83791D_REG_TEMP_TOL[reg_idx]) & keep_mask;
+       w83791d_write(client, W83791D_REG_TEMP_TOL[reg_idx],
+                       (data->temp_tolerance[nr] << val_shift) | target_mask);
+       mutex_unlock(&data->update_lock);
+       return count;
+}
+
+static struct sensor_device_attribute sda_temp_tolerance[] = {
+       SENSOR_ATTR(temp1_tolerance, S_IWUSR | S_IRUGO,
+                       show_temp_tolerance, store_temp_tolerance, 0),
+       SENSOR_ATTR(temp2_tolerance, S_IWUSR | S_IRUGO,
+                       show_temp_tolerance, store_temp_tolerance, 1),
+       SENSOR_ATTR(temp3_tolerance, S_IWUSR | S_IRUGO,
+                       show_temp_tolerance, store_temp_tolerance, 2),
+};
+
 /* read/write the temperature1, includes measured value and limits */
 static ssize_t show_temp1(struct device *dev, struct device_attribute *devattr,
                                char *buf)
@@ -974,6 +1171,15 @@ static struct attribute *w83791d_attributes[] = {
        &sda_pwm[0].dev_attr.attr,
        &sda_pwm[1].dev_attr.attr,
        &sda_pwm[2].dev_attr.attr,
+       &sda_pwmenable[0].dev_attr.attr,
+       &sda_pwmenable[1].dev_attr.attr,
+       &sda_pwmenable[2].dev_attr.attr,
+       &sda_temp_target[0].dev_attr.attr,
+       &sda_temp_target[1].dev_attr.attr,
+       &sda_temp_target[2].dev_attr.attr,
+       &sda_temp_tolerance[0].dev_attr.attr,
+       &sda_temp_tolerance[1].dev_attr.attr,
+       &sda_temp_tolerance[2].dev_attr.attr,
        NULL
 };
 
@@ -1325,6 +1531,30 @@ static struct w83791d_data *w83791d_update_device(struct device *dev)
                                                W83791D_REG_PWM[i]);
                }
 
+               /* Update PWM enable status */
+               for (i = 0; i < 2; i++) {
+                       reg_array_tmp[i] = w83791d_read(client,
+                                               W83791D_REG_FAN_CFG[i]);
+               }
+               data->pwm_enable[0] = (reg_array_tmp[0] >> 2) & 0x03;
+               data->pwm_enable[1] = (reg_array_tmp[0] >> 4) & 0x03;
+               data->pwm_enable[2] = (reg_array_tmp[1] >> 2) & 0x03;
+
+               /* Update PWM target temperature */
+               for (i = 0; i < 3; i++) {
+                       data->temp_target[i] = w83791d_read(client,
+                               W83791D_REG_TEMP_TARGET[i]) & 0x7f;
+               }
+
+               /* Update PWM temperature tolerance */
+               for (i = 0; i < 2; i++) {
+                       reg_array_tmp[i] = w83791d_read(client,
+                                       W83791D_REG_TEMP_TOL[i]);
+               }
+               data->temp_tolerance[0] = reg_array_tmp[0] & 0x0f;
+               data->temp_tolerance[1] = (reg_array_tmp[0] >> 4) & 0x0f;
+               data->temp_tolerance[2] = reg_array_tmp[1] & 0x0f;
+
                /* Update the first temperature sensor */
                for (i = 0; i < 3; i++) {
                        data->temp1[i] = w83791d_read(client,