mirror of
https://github.com/torvalds/linux.git
synced 2024-12-28 13:51:44 +00:00
hwmon: (applesmc) Dynamic creation of fan files
With the dynamic temperature group in place, the setup of fans can be simplified. This patch sets up the fans dynamically, removing a hundred lines of code. Signed-off-by: Henrik Rydberg <rydberg@euromail.se> Signed-off-by: Guenter Roeck <guenter.roeck@ericsson.com>
This commit is contained in:
parent
40ef06f112
commit
3eba2bf7c5
@ -77,20 +77,15 @@
|
||||
|
||||
#define FANS_COUNT "FNum" /* r-o ui8 */
|
||||
#define FANS_MANUAL "FS! " /* r-w ui16 */
|
||||
#define FAN_ACTUAL_SPEED "F0Ac" /* r-o fpe2 (2 bytes) */
|
||||
#define FAN_MIN_SPEED "F0Mn" /* r-o fpe2 (2 bytes) */
|
||||
#define FAN_MAX_SPEED "F0Mx" /* r-o fpe2 (2 bytes) */
|
||||
#define FAN_SAFE_SPEED "F0Sf" /* r-o fpe2 (2 bytes) */
|
||||
#define FAN_TARGET_SPEED "F0Tg" /* r-w fpe2 (2 bytes) */
|
||||
#define FAN_POSITION "F0ID" /* r-o char[16] */
|
||||
#define FAN_ID_FMT "F%dID" /* r-o char[16] */
|
||||
|
||||
/* List of keys used to read/write fan speeds */
|
||||
static const char* fan_speed_keys[] = {
|
||||
FAN_ACTUAL_SPEED,
|
||||
FAN_MIN_SPEED,
|
||||
FAN_MAX_SPEED,
|
||||
FAN_SAFE_SPEED,
|
||||
FAN_TARGET_SPEED
|
||||
static const char *const fan_speed_fmt[] = {
|
||||
"F%dAc", /* actual speed */
|
||||
"F%dMn", /* minimum speed (rw) */
|
||||
"F%dMx", /* maximum speed */
|
||||
"F%dSf", /* safe speed - not all models */
|
||||
"F%dTg", /* target speed (manual: rw) */
|
||||
};
|
||||
|
||||
#define INIT_TIMEOUT_MSECS 5000 /* wait up to 5s for device init ... */
|
||||
@ -104,7 +99,8 @@ static const char* fan_speed_keys[] = {
|
||||
#define SENSOR_Y 1
|
||||
#define SENSOR_Z 2
|
||||
|
||||
#define to_index(attr) (to_sensor_dev_attr(attr)->index)
|
||||
#define to_index(attr) (to_sensor_dev_attr(attr)->index & 0xffff)
|
||||
#define to_option(attr) (to_sensor_dev_attr(attr)->index >> 16)
|
||||
|
||||
/* Dynamic device node attributes */
|
||||
struct applesmc_dev_attr {
|
||||
@ -117,6 +113,7 @@ struct applesmc_node_group {
|
||||
char *format; /* format string */
|
||||
void *show; /* show function */
|
||||
void *store; /* store function */
|
||||
int option; /* function argument */
|
||||
struct applesmc_dev_attr *nodes; /* dynamic node array */
|
||||
};
|
||||
|
||||
@ -133,6 +130,7 @@ struct applesmc_entry {
|
||||
static struct applesmc_registers {
|
||||
struct mutex mutex; /* register read/write mutex */
|
||||
unsigned int key_count; /* number of SMC registers */
|
||||
unsigned int fan_count; /* number of fans */
|
||||
unsigned int temp_count; /* number of temperature registers */
|
||||
unsigned int temp_begin; /* temperature lower index bound */
|
||||
unsigned int temp_end; /* temperature upper index bound */
|
||||
@ -154,9 +152,6 @@ static u8 backlight_state[2];
|
||||
static struct device *hwmon_dev;
|
||||
static struct input_polled_dev *applesmc_idev;
|
||||
|
||||
/* The number of fans handled by the driver */
|
||||
static unsigned int fans_handled;
|
||||
|
||||
/*
|
||||
* Last index written to key_at_index sysfs file, and value to use for all other
|
||||
* key_at_index_* sysfs files.
|
||||
@ -483,22 +478,6 @@ static void applesmc_device_init(void)
|
||||
pr_warn("failed to init the device\n");
|
||||
}
|
||||
|
||||
/*
|
||||
* applesmc_get_fan_count - get the number of fans.
|
||||
*/
|
||||
static int applesmc_get_fan_count(void)
|
||||
{
|
||||
int ret;
|
||||
u8 buffer[1];
|
||||
|
||||
ret = applesmc_read_key(FANS_COUNT, buffer, 1);
|
||||
|
||||
if (ret)
|
||||
return ret;
|
||||
else
|
||||
return buffer[0];
|
||||
}
|
||||
|
||||
/*
|
||||
* applesmc_init_smcreg_try - Try to initialize register cache. Idempotent.
|
||||
*/
|
||||
@ -506,6 +485,7 @@ static int applesmc_init_smcreg_try(void)
|
||||
{
|
||||
struct applesmc_registers *s = &smcreg;
|
||||
bool left_light_sensor, right_light_sensor;
|
||||
u8 tmp[1];
|
||||
int ret;
|
||||
|
||||
if (s->init_complete)
|
||||
@ -520,6 +500,11 @@ static int applesmc_init_smcreg_try(void)
|
||||
if (!s->cache)
|
||||
return -ENOMEM;
|
||||
|
||||
ret = applesmc_read_key(FANS_COUNT, tmp, 1);
|
||||
if (ret)
|
||||
return ret;
|
||||
s->fan_count = tmp[0];
|
||||
|
||||
ret = applesmc_get_lower_bound(&s->temp_begin, "T");
|
||||
if (ret)
|
||||
return ret;
|
||||
@ -544,8 +529,8 @@ static int applesmc_init_smcreg_try(void)
|
||||
s->num_light_sensors = left_light_sensor + right_light_sensor;
|
||||
s->init_complete = true;
|
||||
|
||||
pr_info("key=%d temp=%d acc=%d lux=%d kbd=%d\n",
|
||||
s->key_count, s->temp_count,
|
||||
pr_info("key=%d fan=%d temp=%d acc=%d lux=%d kbd=%d\n",
|
||||
s->key_count, s->fan_count, s->temp_count,
|
||||
s->has_accelerometer,
|
||||
s->num_light_sensors,
|
||||
s->has_key_backlight);
|
||||
@ -776,14 +761,8 @@ static ssize_t applesmc_show_fan_speed(struct device *dev,
|
||||
unsigned int speed = 0;
|
||||
char newkey[5];
|
||||
u8 buffer[2];
|
||||
struct sensor_device_attribute_2 *sensor_attr =
|
||||
to_sensor_dev_attr_2(attr);
|
||||
|
||||
newkey[0] = fan_speed_keys[sensor_attr->nr][0];
|
||||
newkey[1] = '0' + sensor_attr->index;
|
||||
newkey[2] = fan_speed_keys[sensor_attr->nr][2];
|
||||
newkey[3] = fan_speed_keys[sensor_attr->nr][3];
|
||||
newkey[4] = 0;
|
||||
sprintf(newkey, fan_speed_fmt[to_option(attr)], to_index(attr));
|
||||
|
||||
ret = applesmc_read_key(newkey, buffer, 2);
|
||||
speed = ((buffer[0] << 8 | buffer[1]) >> 2);
|
||||
@ -802,19 +781,13 @@ static ssize_t applesmc_store_fan_speed(struct device *dev,
|
||||
u32 speed;
|
||||
char newkey[5];
|
||||
u8 buffer[2];
|
||||
struct sensor_device_attribute_2 *sensor_attr =
|
||||
to_sensor_dev_attr_2(attr);
|
||||
|
||||
speed = simple_strtoul(sysfsbuf, NULL, 10);
|
||||
|
||||
if (speed > 0x4000) /* Bigger than a 14-bit value */
|
||||
return -EINVAL;
|
||||
|
||||
newkey[0] = fan_speed_keys[sensor_attr->nr][0];
|
||||
newkey[1] = '0' + sensor_attr->index;
|
||||
newkey[2] = fan_speed_keys[sensor_attr->nr][2];
|
||||
newkey[3] = fan_speed_keys[sensor_attr->nr][3];
|
||||
newkey[4] = 0;
|
||||
sprintf(newkey, fan_speed_fmt[to_option(attr)], to_index(attr));
|
||||
|
||||
buffer[0] = (speed >> 6) & 0xff;
|
||||
buffer[1] = (speed << 2) & 0xff;
|
||||
@ -827,15 +800,14 @@ static ssize_t applesmc_store_fan_speed(struct device *dev,
|
||||
}
|
||||
|
||||
static ssize_t applesmc_show_fan_manual(struct device *dev,
|
||||
struct device_attribute *devattr, char *sysfsbuf)
|
||||
struct device_attribute *attr, char *sysfsbuf)
|
||||
{
|
||||
int ret;
|
||||
u16 manual = 0;
|
||||
u8 buffer[2];
|
||||
struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
|
||||
|
||||
ret = applesmc_read_key(FANS_MANUAL, buffer, 2);
|
||||
manual = ((buffer[0] << 8 | buffer[1]) >> attr->index) & 0x01;
|
||||
manual = ((buffer[0] << 8 | buffer[1]) >> to_index(attr)) & 0x01;
|
||||
|
||||
if (ret)
|
||||
return ret;
|
||||
@ -844,14 +816,13 @@ static ssize_t applesmc_show_fan_manual(struct device *dev,
|
||||
}
|
||||
|
||||
static ssize_t applesmc_store_fan_manual(struct device *dev,
|
||||
struct device_attribute *devattr,
|
||||
struct device_attribute *attr,
|
||||
const char *sysfsbuf, size_t count)
|
||||
{
|
||||
int ret;
|
||||
u8 buffer[2];
|
||||
u32 input;
|
||||
u16 val;
|
||||
struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
|
||||
|
||||
input = simple_strtoul(sysfsbuf, NULL, 10);
|
||||
|
||||
@ -861,9 +832,9 @@ static ssize_t applesmc_store_fan_manual(struct device *dev,
|
||||
goto out;
|
||||
|
||||
if (input)
|
||||
val = val | (0x01 << attr->index);
|
||||
val = val | (0x01 << to_index(attr));
|
||||
else
|
||||
val = val & ~(0x01 << attr->index);
|
||||
val = val & ~(0x01 << to_index(attr));
|
||||
|
||||
buffer[0] = (val >> 8) & 0xFF;
|
||||
buffer[1] = val & 0xFF;
|
||||
@ -883,14 +854,8 @@ static ssize_t applesmc_show_fan_position(struct device *dev,
|
||||
int ret;
|
||||
char newkey[5];
|
||||
u8 buffer[17];
|
||||
struct sensor_device_attribute_2 *sensor_attr =
|
||||
to_sensor_dev_attr_2(attr);
|
||||
|
||||
newkey[0] = FAN_POSITION[0];
|
||||
newkey[1] = '0' + sensor_attr->index;
|
||||
newkey[2] = FAN_POSITION[2];
|
||||
newkey[3] = FAN_POSITION[3];
|
||||
newkey[4] = 0;
|
||||
sprintf(newkey, FAN_ID_FMT, to_index(attr));
|
||||
|
||||
ret = applesmc_read_key(newkey, buffer, 16);
|
||||
buffer[16] = 0;
|
||||
@ -1069,62 +1034,15 @@ static struct attribute *key_enumeration_attributes[] = {
|
||||
static const struct attribute_group key_enumeration_group =
|
||||
{ .attrs = key_enumeration_attributes };
|
||||
|
||||
/*
|
||||
* Macro defining SENSOR_DEVICE_ATTR for a fan sysfs entries.
|
||||
* - show actual speed
|
||||
* - show/store minimum speed
|
||||
* - show maximum speed
|
||||
* - show safe speed
|
||||
* - show/store target speed
|
||||
* - show/store manual mode
|
||||
*/
|
||||
#define sysfs_fan_speeds_offset(offset) \
|
||||
static SENSOR_DEVICE_ATTR_2(fan##offset##_input, S_IRUGO, \
|
||||
applesmc_show_fan_speed, NULL, 0, offset-1); \
|
||||
\
|
||||
static SENSOR_DEVICE_ATTR_2(fan##offset##_min, S_IRUGO | S_IWUSR, \
|
||||
applesmc_show_fan_speed, applesmc_store_fan_speed, 1, offset-1); \
|
||||
\
|
||||
static SENSOR_DEVICE_ATTR_2(fan##offset##_max, S_IRUGO, \
|
||||
applesmc_show_fan_speed, NULL, 2, offset-1); \
|
||||
\
|
||||
static SENSOR_DEVICE_ATTR_2(fan##offset##_safe, S_IRUGO, \
|
||||
applesmc_show_fan_speed, NULL, 3, offset-1); \
|
||||
\
|
||||
static SENSOR_DEVICE_ATTR_2(fan##offset##_output, S_IRUGO | S_IWUSR, \
|
||||
applesmc_show_fan_speed, applesmc_store_fan_speed, 4, offset-1); \
|
||||
\
|
||||
static SENSOR_DEVICE_ATTR(fan##offset##_manual, S_IRUGO | S_IWUSR, \
|
||||
applesmc_show_fan_manual, applesmc_store_fan_manual, offset-1); \
|
||||
\
|
||||
static SENSOR_DEVICE_ATTR(fan##offset##_label, S_IRUGO, \
|
||||
applesmc_show_fan_position, NULL, offset-1); \
|
||||
\
|
||||
static struct attribute *fan##offset##_attributes[] = { \
|
||||
&sensor_dev_attr_fan##offset##_input.dev_attr.attr, \
|
||||
&sensor_dev_attr_fan##offset##_min.dev_attr.attr, \
|
||||
&sensor_dev_attr_fan##offset##_max.dev_attr.attr, \
|
||||
&sensor_dev_attr_fan##offset##_safe.dev_attr.attr, \
|
||||
&sensor_dev_attr_fan##offset##_output.dev_attr.attr, \
|
||||
&sensor_dev_attr_fan##offset##_manual.dev_attr.attr, \
|
||||
&sensor_dev_attr_fan##offset##_label.dev_attr.attr, \
|
||||
NULL \
|
||||
};
|
||||
|
||||
/*
|
||||
* Create the needed functions for each fan using the macro defined above
|
||||
* (4 fans are supported)
|
||||
*/
|
||||
sysfs_fan_speeds_offset(1);
|
||||
sysfs_fan_speeds_offset(2);
|
||||
sysfs_fan_speeds_offset(3);
|
||||
sysfs_fan_speeds_offset(4);
|
||||
|
||||
static const struct attribute_group fan_attribute_groups[] = {
|
||||
{ .attrs = fan1_attributes },
|
||||
{ .attrs = fan2_attributes },
|
||||
{ .attrs = fan3_attributes },
|
||||
{ .attrs = fan4_attributes },
|
||||
static struct applesmc_node_group fan_group[] = {
|
||||
{ "fan%d_label", applesmc_show_fan_position },
|
||||
{ "fan%d_input", applesmc_show_fan_speed, NULL, 0 },
|
||||
{ "fan%d_min", applesmc_show_fan_speed, applesmc_store_fan_speed, 1 },
|
||||
{ "fan%d_max", applesmc_show_fan_speed, NULL, 2 },
|
||||
{ "fan%d_safe", applesmc_show_fan_speed, NULL, 3 },
|
||||
{ "fan%d_output", applesmc_show_fan_speed, applesmc_store_fan_speed, 4 },
|
||||
{ "fan%d_manual", applesmc_show_fan_manual, applesmc_store_fan_manual },
|
||||
{ }
|
||||
};
|
||||
|
||||
static struct applesmc_node_group temp_group[] = {
|
||||
@ -1171,7 +1089,7 @@ static int applesmc_create_nodes(struct applesmc_node_group *groups, int num)
|
||||
for (i = 0; i < num; i++) {
|
||||
node = &grp->nodes[i];
|
||||
sprintf(node->name, grp->format, i + 1);
|
||||
node->sda.index = i;
|
||||
node->sda.index = (grp->option << 16) | (i & 0xffff);
|
||||
node->sda.dev_attr.show = grp->show;
|
||||
node->sda.dev_attr.store = grp->store;
|
||||
attr = &node->sda.dev_attr.attr;
|
||||
@ -1287,7 +1205,6 @@ static __initdata struct dmi_system_id applesmc_whitelist[] = {
|
||||
static int __init applesmc_init(void)
|
||||
{
|
||||
int ret;
|
||||
int count;
|
||||
|
||||
if (!dmi_check_system(applesmc_whitelist)) {
|
||||
pr_warn("supported laptop not found!\n");
|
||||
@ -1326,25 +1243,9 @@ static int __init applesmc_init(void)
|
||||
if (ret)
|
||||
goto out_name;
|
||||
|
||||
/* create fan files */
|
||||
count = applesmc_get_fan_count();
|
||||
if (count < 0)
|
||||
pr_err("Cannot get the number of fans\n");
|
||||
else
|
||||
pr_info("%d fans found\n", count);
|
||||
|
||||
if (count > 4) {
|
||||
count = 4;
|
||||
pr_warn("A maximum of 4 fans are supported by this driver\n");
|
||||
}
|
||||
|
||||
while (fans_handled < count) {
|
||||
ret = sysfs_create_group(&pdev->dev.kobj,
|
||||
&fan_attribute_groups[fans_handled]);
|
||||
if (ret)
|
||||
goto out_fans;
|
||||
fans_handled++;
|
||||
}
|
||||
ret = applesmc_create_nodes(fan_group, smcreg.fan_count);
|
||||
if (ret)
|
||||
goto out_info;
|
||||
|
||||
ret = applesmc_create_nodes(temp_group, smcreg.temp_count);
|
||||
if (ret)
|
||||
@ -1402,9 +1303,8 @@ out_accelerometer:
|
||||
out_temperature:
|
||||
applesmc_destroy_nodes(temp_group);
|
||||
out_fans:
|
||||
while (fans_handled)
|
||||
sysfs_remove_group(&pdev->dev.kobj,
|
||||
&fan_attribute_groups[--fans_handled]);
|
||||
applesmc_destroy_nodes(fan_group);
|
||||
out_info:
|
||||
sysfs_remove_group(&pdev->dev.kobj, &key_enumeration_group);
|
||||
out_name:
|
||||
sysfs_remove_file(&pdev->dev.kobj, &dev_attr_name.attr);
|
||||
@ -1433,9 +1333,7 @@ static void __exit applesmc_exit(void)
|
||||
if (smcreg.has_accelerometer)
|
||||
applesmc_release_accelerometer();
|
||||
applesmc_destroy_nodes(temp_group);
|
||||
while (fans_handled)
|
||||
sysfs_remove_group(&pdev->dev.kobj,
|
||||
&fan_attribute_groups[--fans_handled]);
|
||||
applesmc_destroy_nodes(fan_group);
|
||||
sysfs_remove_group(&pdev->dev.kobj, &key_enumeration_group);
|
||||
sysfs_remove_file(&pdev->dev.kobj, &dev_attr_name.attr);
|
||||
applesmc_destroy_smcreg();
|
||||
|
Loading…
Reference in New Issue
Block a user