Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 2c6315da authored by Clemens Ladisch's avatar Clemens Ladisch Committed by Guenter Roeck
Browse files

hwmon: (jc42) do not allow writing to locked registers



On systems where the temperature sensor is actually used, the BIOS is
likely to have locked the alarm registers.  In that case, all writes
through the corresponding sysfs files would be silently ignored.

To prevent this, detect the locks and make the affected sysfs files
read-only.

Signed-off-by: default avatarClemens Ladisch <clemens@ladisch.de>
Cc: stable@kernel.org
Signed-off-by: default avatarGuenter Roeck <guenter.roeck@ericsson.com>
parent d5622f5b
Loading
Loading
Loading
Loading
+8 −4
Original line number Diff line number Diff line
@@ -86,15 +86,19 @@ limits. The chip supports only a single register to configure the hysteresis,
which applies to all limits. This register can be written by writing into
temp1_crit_hyst. Other hysteresis attributes are read-only.

If the BIOS has configured the sensor for automatic temperature management, it
is likely that it has locked the registers, i.e., that the temperature limits
cannot be changed.

Sysfs entries
-------------

temp1_input		Temperature (RO)
temp1_min		Minimum temperature (RW)
temp1_max		Maximum temperature (RW)
temp1_crit		Critical high temperature (RW)
temp1_min		Minimum temperature (RO or RW)
temp1_max		Maximum temperature (RO or RW)
temp1_crit		Critical high temperature (RO or RW)

temp1_crit_hyst		Critical hysteresis temperature (RW)
temp1_crit_hyst		Critical hysteresis temperature (RO or RW)
temp1_max_hyst		Maximum hysteresis temperature (RO)

temp1_min_alarm		Temperature low alarm
+29 −4
Original line number Diff line number Diff line
@@ -53,6 +53,8 @@ static const unsigned short normal_i2c[] = {

/* Configuration register defines */
#define JC42_CFG_CRIT_ONLY	(1 << 2)
#define JC42_CFG_TCRIT_LOCK	(1 << 6)
#define JC42_CFG_EVENT_LOCK	(1 << 7)
#define JC42_CFG_SHUTDOWN	(1 << 8)
#define JC42_CFG_HYST_SHIFT	9
#define JC42_CFG_HYST_MASK	0x03
@@ -380,14 +382,14 @@ static ssize_t show_alarm(struct device *dev,

static DEVICE_ATTR(temp1_input, S_IRUGO,
		   show_temp_input, NULL);
static DEVICE_ATTR(temp1_crit, S_IWUSR | S_IRUGO,
static DEVICE_ATTR(temp1_crit, S_IRUGO,
		   show_temp_crit, set_temp_crit);
static DEVICE_ATTR(temp1_min, S_IWUSR | S_IRUGO,
static DEVICE_ATTR(temp1_min, S_IRUGO,
		   show_temp_min, set_temp_min);
static DEVICE_ATTR(temp1_max, S_IWUSR | S_IRUGO,
static DEVICE_ATTR(temp1_max, S_IRUGO,
		   show_temp_max, set_temp_max);

static DEVICE_ATTR(temp1_crit_hyst, S_IWUSR | S_IRUGO,
static DEVICE_ATTR(temp1_crit_hyst, S_IRUGO,
		   show_temp_crit_hyst, set_temp_crit_hyst);
static DEVICE_ATTR(temp1_max_hyst, S_IRUGO,
		   show_temp_max_hyst, NULL);
@@ -412,8 +414,31 @@ static struct attribute *jc42_attributes[] = {
	NULL
};

static mode_t jc42_attribute_mode(struct kobject *kobj,
				  struct attribute *attr, int index)
{
	struct device *dev = container_of(kobj, struct device, kobj);
	struct i2c_client *client = to_i2c_client(dev);
	struct jc42_data *data = i2c_get_clientdata(client);
	unsigned int config = data->config;
	bool readonly;

	if (attr == &dev_attr_temp1_crit.attr)
		readonly = config & JC42_CFG_TCRIT_LOCK;
	else if (attr == &dev_attr_temp1_min.attr ||
		 attr == &dev_attr_temp1_max.attr)
		readonly = config & JC42_CFG_EVENT_LOCK;
	else if (attr == &dev_attr_temp1_crit_hyst.attr)
		readonly = config & (JC42_CFG_EVENT_LOCK | JC42_CFG_TCRIT_LOCK);
	else
		readonly = true;

	return S_IRUGO | (readonly ? 0 : S_IWUSR);
}

static const struct attribute_group jc42_group = {
	.attrs = jc42_attributes,
	.is_visible = jc42_attribute_mode,
};

/* Return 0 if detection is successful, -ENODEV otherwise */