Skip to content

Commit

Permalink
hwmon: (applesmc) Dynamic creation of fan files
Browse files Browse the repository at this point in the history
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>
  • Loading branch information
Henrik Rydberg authored and Guenter Roeck committed Jan 8, 2011
1 parent 40ef06f commit 3eba2bf
Showing 1 changed file with 43 additions and 145 deletions.
188 changes: 43 additions & 145 deletions drivers/hwmon/applesmc.c
Original file line number Diff line number Diff line change
Expand Up @@ -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 ... */
Expand All @@ -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 {
Expand All @@ -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 */
};

Expand All @@ -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 */
Expand All @@ -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.
Expand Down Expand Up @@ -483,29 +478,14 @@ 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.
*/
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)
Expand All @@ -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;
Expand All @@ -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);
Expand Down Expand Up @@ -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);
Expand All @@ -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;
Expand All @@ -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;
Expand All @@ -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);

Expand All @@ -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;
Expand All @@ -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;
Expand Down Expand Up @@ -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[] = {
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -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");
Expand Down Expand Up @@ -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)
Expand Down Expand Up @@ -1402,9 +1303,8 @@ static int __init applesmc_init(void)
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);
Expand Down Expand Up @@ -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();
Expand Down

0 comments on commit 3eba2bf

Please sign in to comment.