Blame lib/sysfs.c

Packit Service 23242a
/*
Packit Service 23242a
    sysfs.c - Part of libsensors, a library for reading Linux sensor data
Packit Service 23242a
    Copyright (c) 2005 Mark M. Hoffman <mhoffman@lightlink.com>
Packit Service 23242a
    Copyright (C) 2007-2014 Jean Delvare <jdelvare@suse.de>
Packit Service 23242a
Packit Service 23242a
    This library is free software; you can redistribute it and/or
Packit Service 23242a
    modify it under the terms of the GNU Lesser General Public
Packit Service 23242a
    License as published by the Free Software Foundation; either
Packit Service 23242a
    version 2.1 of the License, or (at your option) any later version.
Packit Service 23242a
Packit Service 23242a
    This library is distributed in the hope that it will be useful,
Packit Service 23242a
    but WITHOUT ANY WARRANTY; without even the implied warranty of
Packit Service 23242a
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
Packit Service 23242a
    GNU Lesser General Public License for more details.
Packit Service 23242a
Packit Service 23242a
    You should have received a copy of the GNU General Public License
Packit Service 23242a
    along with this program; if not, write to the Free Software
Packit Service 23242a
    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
Packit Service 23242a
    MA 02110-1301 USA.
Packit Service 23242a
*/
Packit Service 23242a
Packit Service 23242a
/* this define needed for strndup() */
Packit Service 23242a
#define _GNU_SOURCE
Packit Service 23242a
Packit Service 23242a
#include <sys/types.h>
Packit Service 23242a
#include <sys/stat.h>
Packit Service 23242a
#include <sys/vfs.h>
Packit Service 23242a
#include <unistd.h>
Packit Service 23242a
#include <string.h>
Packit Service 23242a
#include <stdlib.h>
Packit Service 23242a
#include <limits.h>
Packit Service 23242a
#include <errno.h>
Packit Service 23242a
#include <dirent.h>
Packit Service 23242a
#include "data.h"
Packit Service 23242a
#include "error.h"
Packit Service 23242a
#include "access.h"
Packit Service 23242a
#include "general.h"
Packit Service 23242a
#include "sysfs.h"
Packit Service 23242a
Packit Service 23242a
Packit Service 23242a
/****************************************************************************/
Packit Service 23242a
Packit Service 23242a
#define ATTR_MAX	128
Packit Service 23242a
#define SYSFS_MAGIC	0x62656572
Packit Service 23242a
Packit Service 23242a
/*
Packit Service 23242a
 * Read an attribute from sysfs
Packit Service 23242a
 * Returns a pointer to a freshly allocated string; free it yourself.
Packit Service 23242a
 * If the file doesn't exist or can't be read, NULL is returned.
Packit Service 23242a
 */
Packit Service 23242a
static char *sysfs_read_attr(const char *device, const char *attr)
Packit Service 23242a
{
Packit Service 23242a
	char path[NAME_MAX];
Packit Service 23242a
	char buf[ATTR_MAX], *p;
Packit Service 23242a
	FILE *f;
Packit Service 23242a
Packit Service 23242a
	snprintf(path, NAME_MAX, "%s/%s", device, attr);
Packit Service 23242a
Packit Service 23242a
	if (!(f = fopen(path, "r")))
Packit Service 23242a
		return NULL;
Packit Service 23242a
	p = fgets(buf, ATTR_MAX, f);
Packit Service 23242a
	fclose(f);
Packit Service 23242a
	if (!p)
Packit Service 23242a
		return NULL;
Packit Service 23242a
Packit Service 23242a
	/* Last byte is a '\n'; chop that off */
Packit Service 23242a
	p = strndup(buf, strlen(buf) - 1);
Packit Service 23242a
	if (!p)
Packit Service 23242a
		sensors_fatal_error(__func__, "Out of memory");
Packit Service 23242a
	return p;
Packit Service 23242a
}
Packit Service 23242a
Packit Service 23242a
/*
Packit Service 23242a
 * Call an arbitrary function for each class device of the given class
Packit Service 23242a
 * Returns 0 on success (all calls returned 0), a positive errno for
Packit Service 23242a
 * local errors, or a negative error value if any call fails.
Packit Service 23242a
 */
Packit Service 23242a
static int sysfs_foreach_classdev(const char *class_name,
Packit Service 23242a
				   int (*func)(const char *, const char *))
Packit Service 23242a
{
Packit Service 23242a
	char path[NAME_MAX];
Packit Service 23242a
	int path_off, ret;
Packit Service 23242a
	DIR *dir;
Packit Service 23242a
	struct dirent *ent;
Packit Service 23242a
Packit Service 23242a
	path_off = snprintf(path, NAME_MAX, "%s/class/%s",
Packit Service 23242a
			    sensors_sysfs_mount, class_name);
Packit Service 23242a
	if (!(dir = opendir(path)))
Packit Service 23242a
		return errno;
Packit Service 23242a
Packit Service 23242a
	ret = 0;
Packit Service 23242a
	while (!ret && (ent = readdir(dir))) {
Packit Service 23242a
		if (ent->d_name[0] == '.')	/* skip hidden entries */
Packit Service 23242a
			continue;
Packit Service 23242a
Packit Service 23242a
		snprintf(path + path_off, NAME_MAX - path_off, "/%s",
Packit Service 23242a
			 ent->d_name);
Packit Service 23242a
		ret = func(path, ent->d_name);
Packit Service 23242a
	}
Packit Service 23242a
Packit Service 23242a
	closedir(dir);
Packit Service 23242a
	return ret;
Packit Service 23242a
}
Packit Service 23242a
Packit Service 23242a
/*
Packit Service 23242a
 * Call an arbitrary function for each device of the given bus type
Packit Service 23242a
 * Returns 0 on success (all calls returned 0), a positive errno for
Packit Service 23242a
 * local errors, or a negative error value if any call fails.
Packit Service 23242a
 */
Packit Service 23242a
static int sysfs_foreach_busdev(const char *bus_type,
Packit Service 23242a
				 int (*func)(const char *, const char *))
Packit Service 23242a
{
Packit Service 23242a
	char path[NAME_MAX];
Packit Service 23242a
	int path_off, ret;
Packit Service 23242a
	DIR *dir;
Packit Service 23242a
	struct dirent *ent;
Packit Service 23242a
Packit Service 23242a
	path_off = snprintf(path, NAME_MAX, "%s/bus/%s/devices",
Packit Service 23242a
			    sensors_sysfs_mount, bus_type);
Packit Service 23242a
	if (!(dir = opendir(path)))
Packit Service 23242a
		return errno;
Packit Service 23242a
Packit Service 23242a
	ret = 0;
Packit Service 23242a
	while (!ret && (ent = readdir(dir))) {
Packit Service 23242a
		if (ent->d_name[0] == '.')	/* skip hidden entries */
Packit Service 23242a
			continue;
Packit Service 23242a
Packit Service 23242a
		snprintf(path + path_off, NAME_MAX - path_off, "/%s",
Packit Service 23242a
			 ent->d_name);
Packit Service 23242a
		ret = func(path, ent->d_name);
Packit Service 23242a
	}
Packit Service 23242a
Packit Service 23242a
	closedir(dir);
Packit Service 23242a
	return ret;
Packit Service 23242a
}
Packit Service 23242a
Packit Service 23242a
/****************************************************************************/
Packit Service 23242a
Packit Service 23242a
char sensors_sysfs_mount[NAME_MAX];
Packit Service 23242a
Packit Service 23242a
static
Packit Service 23242a
int get_type_scaling(sensors_subfeature_type type)
Packit Service 23242a
{
Packit Service 23242a
	/* Multipliers for subfeatures */
Packit Service 23242a
	switch (type & 0xFF80) {
Packit Service 23242a
	case SENSORS_SUBFEATURE_IN_INPUT:
Packit Service 23242a
	case SENSORS_SUBFEATURE_TEMP_INPUT:
Packit Service 23242a
	case SENSORS_SUBFEATURE_CURR_INPUT:
Packit Service 23242a
	case SENSORS_SUBFEATURE_HUMIDITY_INPUT:
Packit Service 23242a
		return 1000;
Packit Service 23242a
	case SENSORS_SUBFEATURE_FAN_INPUT:
Packit Service 23242a
		return 1;
Packit Service 23242a
	case SENSORS_SUBFEATURE_POWER_AVERAGE:
Packit Service 23242a
	case SENSORS_SUBFEATURE_ENERGY_INPUT:
Packit Service 23242a
		return 1000000;
Packit Service 23242a
	}
Packit Service 23242a
Packit Service 23242a
	/* Multipliers for second class subfeatures
Packit Service 23242a
	   that need their own multiplier */
Packit Service 23242a
	switch (type) {
Packit Service 23242a
	case SENSORS_SUBFEATURE_POWER_AVERAGE_INTERVAL:
Packit Service 23242a
	case SENSORS_SUBFEATURE_VID:
Packit Service 23242a
	case SENSORS_SUBFEATURE_TEMP_OFFSET:
Packit Service 23242a
		return 1000;
Packit Service 23242a
	default:
Packit Service 23242a
		return 1;
Packit Service 23242a
	}
Packit Service 23242a
}
Packit Service 23242a
Packit Service 23242a
static
Packit Service 23242a
char *get_feature_name(sensors_feature_type ftype, char *sfname)
Packit Service 23242a
{
Packit Service 23242a
	char *name, *underscore;
Packit Service 23242a
Packit Service 23242a
	switch (ftype) {
Packit Service 23242a
	case SENSORS_FEATURE_IN:
Packit Service 23242a
	case SENSORS_FEATURE_FAN:
Packit Service 23242a
	case SENSORS_FEATURE_TEMP:
Packit Service 23242a
	case SENSORS_FEATURE_POWER:
Packit Service 23242a
	case SENSORS_FEATURE_ENERGY:
Packit Service 23242a
	case SENSORS_FEATURE_CURR:
Packit Service 23242a
	case SENSORS_FEATURE_HUMIDITY:
Packit Service 23242a
	case SENSORS_FEATURE_INTRUSION:
Packit Service 23242a
		underscore = strchr(sfname, '_');
Packit Service 23242a
		name = strndup(sfname, underscore - sfname);
Packit Service 23242a
		if (!name)
Packit Service 23242a
			sensors_fatal_error(__func__, "Out of memory");
Packit Service 23242a
Packit Service 23242a
		break;
Packit Service 23242a
	default:
Packit Service 23242a
		name = strdup(sfname);
Packit Service 23242a
		if (!name)
Packit Service 23242a
			sensors_fatal_error(__func__, "Out of memory");
Packit Service 23242a
	}
Packit Service 23242a
Packit Service 23242a
	return name;
Packit Service 23242a
}
Packit Service 23242a
Packit Service 23242a
/* Static mappings for use by sensors_subfeature_get_type() */
Packit Service 23242a
struct subfeature_type_match
Packit Service 23242a
{
Packit Service 23242a
	const char *name;
Packit Service 23242a
	sensors_subfeature_type type;
Packit Service 23242a
};
Packit Service 23242a
Packit Service 23242a
struct feature_type_match
Packit Service 23242a
{
Packit Service 23242a
	const char *name;
Packit Service 23242a
	const struct subfeature_type_match *submatches;
Packit Service 23242a
};
Packit Service 23242a
Packit Service 23242a
static const struct subfeature_type_match temp_matches[] = {
Packit Service 23242a
	{ "input", SENSORS_SUBFEATURE_TEMP_INPUT },
Packit Service 23242a
	{ "max", SENSORS_SUBFEATURE_TEMP_MAX },
Packit Service 23242a
	{ "max_hyst", SENSORS_SUBFEATURE_TEMP_MAX_HYST },
Packit Service 23242a
	{ "min", SENSORS_SUBFEATURE_TEMP_MIN },
Packit Service 23242a
	{ "min_hyst", SENSORS_SUBFEATURE_TEMP_MIN_HYST },
Packit Service 23242a
	{ "crit", SENSORS_SUBFEATURE_TEMP_CRIT },
Packit Service 23242a
	{ "crit_hyst", SENSORS_SUBFEATURE_TEMP_CRIT_HYST },
Packit Service 23242a
	{ "lcrit", SENSORS_SUBFEATURE_TEMP_LCRIT },
Packit Service 23242a
	{ "lcrit_hyst", SENSORS_SUBFEATURE_TEMP_LCRIT_HYST },
Packit Service 23242a
	{ "emergency", SENSORS_SUBFEATURE_TEMP_EMERGENCY },
Packit Service 23242a
	{ "emergency_hyst", SENSORS_SUBFEATURE_TEMP_EMERGENCY_HYST },
Packit Service 23242a
	{ "lowest", SENSORS_SUBFEATURE_TEMP_LOWEST },
Packit Service 23242a
	{ "highest", SENSORS_SUBFEATURE_TEMP_HIGHEST },
Packit Service 23242a
	{ "alarm", SENSORS_SUBFEATURE_TEMP_ALARM },
Packit Service 23242a
	{ "min_alarm", SENSORS_SUBFEATURE_TEMP_MIN_ALARM },
Packit Service 23242a
	{ "max_alarm", SENSORS_SUBFEATURE_TEMP_MAX_ALARM },
Packit Service 23242a
	{ "crit_alarm", SENSORS_SUBFEATURE_TEMP_CRIT_ALARM },
Packit Service 23242a
	{ "emergency_alarm", SENSORS_SUBFEATURE_TEMP_EMERGENCY_ALARM },
Packit Service 23242a
	{ "lcrit_alarm", SENSORS_SUBFEATURE_TEMP_LCRIT_ALARM },
Packit Service 23242a
	{ "fault", SENSORS_SUBFEATURE_TEMP_FAULT },
Packit Service 23242a
	{ "type", SENSORS_SUBFEATURE_TEMP_TYPE },
Packit Service 23242a
	{ "offset", SENSORS_SUBFEATURE_TEMP_OFFSET },
Packit Service 23242a
	{ "beep", SENSORS_SUBFEATURE_TEMP_BEEP },
Packit Service 23242a
	{ NULL, 0 }
Packit Service 23242a
};
Packit Service 23242a
Packit Service 23242a
static const struct subfeature_type_match in_matches[] = {
Packit Service 23242a
	{ "input", SENSORS_SUBFEATURE_IN_INPUT },
Packit Service 23242a
	{ "min", SENSORS_SUBFEATURE_IN_MIN },
Packit Service 23242a
	{ "max", SENSORS_SUBFEATURE_IN_MAX },
Packit Service 23242a
	{ "lcrit", SENSORS_SUBFEATURE_IN_LCRIT },
Packit Service 23242a
	{ "crit", SENSORS_SUBFEATURE_IN_CRIT },
Packit Service 23242a
	{ "average", SENSORS_SUBFEATURE_IN_AVERAGE },
Packit Service 23242a
	{ "lowest", SENSORS_SUBFEATURE_IN_LOWEST },
Packit Service 23242a
	{ "highest", SENSORS_SUBFEATURE_IN_HIGHEST },
Packit Service 23242a
	{ "alarm", SENSORS_SUBFEATURE_IN_ALARM },
Packit Service 23242a
	{ "min_alarm", SENSORS_SUBFEATURE_IN_MIN_ALARM },
Packit Service 23242a
	{ "max_alarm", SENSORS_SUBFEATURE_IN_MAX_ALARM },
Packit Service 23242a
	{ "lcrit_alarm", SENSORS_SUBFEATURE_IN_LCRIT_ALARM },
Packit Service 23242a
	{ "crit_alarm", SENSORS_SUBFEATURE_IN_CRIT_ALARM },
Packit Service 23242a
	{ "beep", SENSORS_SUBFEATURE_IN_BEEP },
Packit Service 23242a
	{ NULL, 0 }
Packit Service 23242a
};
Packit Service 23242a
Packit Service 23242a
static const struct subfeature_type_match fan_matches[] = {
Packit Service 23242a
	{ "input", SENSORS_SUBFEATURE_FAN_INPUT },
Packit Service 23242a
	{ "min", SENSORS_SUBFEATURE_FAN_MIN },
Packit Service 23242a
	{ "max", SENSORS_SUBFEATURE_FAN_MAX },
Packit Service 23242a
	{ "div", SENSORS_SUBFEATURE_FAN_DIV },
Packit Service 23242a
	{ "pulses", SENSORS_SUBFEATURE_FAN_PULSES },
Packit Service 23242a
	{ "alarm", SENSORS_SUBFEATURE_FAN_ALARM },
Packit Service 23242a
	{ "min_alarm", SENSORS_SUBFEATURE_FAN_MIN_ALARM },
Packit Service 23242a
	{ "max_alarm", SENSORS_SUBFEATURE_FAN_MAX_ALARM },
Packit Service 23242a
	{ "fault", SENSORS_SUBFEATURE_FAN_FAULT },
Packit Service 23242a
	{ "beep", SENSORS_SUBFEATURE_FAN_BEEP },
Packit Service 23242a
	{ NULL, 0 }
Packit Service 23242a
};
Packit Service 23242a
Packit Service 23242a
static const struct subfeature_type_match power_matches[] = {
Packit Service 23242a
	{ "average", SENSORS_SUBFEATURE_POWER_AVERAGE },
Packit Service 23242a
	{ "average_highest", SENSORS_SUBFEATURE_POWER_AVERAGE_HIGHEST },
Packit Service 23242a
	{ "average_lowest", SENSORS_SUBFEATURE_POWER_AVERAGE_LOWEST },
Packit Service 23242a
	{ "input", SENSORS_SUBFEATURE_POWER_INPUT },
Packit Service 23242a
	{ "input_highest", SENSORS_SUBFEATURE_POWER_INPUT_HIGHEST },
Packit Service 23242a
	{ "input_lowest", SENSORS_SUBFEATURE_POWER_INPUT_LOWEST },
Packit Service 23242a
	{ "cap", SENSORS_SUBFEATURE_POWER_CAP },
Packit Service 23242a
	{ "cap_hyst", SENSORS_SUBFEATURE_POWER_CAP_HYST },
Packit Service 23242a
	{ "cap_alarm", SENSORS_SUBFEATURE_POWER_CAP_ALARM },
Packit Service 23242a
	{ "alarm", SENSORS_SUBFEATURE_POWER_ALARM },
Packit Service 23242a
	{ "max", SENSORS_SUBFEATURE_POWER_MAX },
Packit Service 23242a
	{ "max_alarm", SENSORS_SUBFEATURE_POWER_MAX_ALARM },
Packit Service 23242a
	{ "crit", SENSORS_SUBFEATURE_POWER_CRIT },
Packit Service 23242a
	{ "crit_alarm", SENSORS_SUBFEATURE_POWER_CRIT_ALARM },
Packit Service 23242a
	{ "average_interval", SENSORS_SUBFEATURE_POWER_AVERAGE_INTERVAL },
Packit Service 23242a
	{ NULL, 0 }
Packit Service 23242a
};
Packit Service 23242a
Packit Service 23242a
static const struct subfeature_type_match energy_matches[] = {
Packit Service 23242a
	{ "input", SENSORS_SUBFEATURE_ENERGY_INPUT },
Packit Service 23242a
	{ NULL, 0 }
Packit Service 23242a
};
Packit Service 23242a
Packit Service 23242a
static const struct subfeature_type_match curr_matches[] = {
Packit Service 23242a
	{ "input", SENSORS_SUBFEATURE_CURR_INPUT },
Packit Service 23242a
	{ "min", SENSORS_SUBFEATURE_CURR_MIN },
Packit Service 23242a
	{ "max", SENSORS_SUBFEATURE_CURR_MAX },
Packit Service 23242a
	{ "lcrit", SENSORS_SUBFEATURE_CURR_LCRIT },
Packit Service 23242a
	{ "crit", SENSORS_SUBFEATURE_CURR_CRIT },
Packit Service 23242a
	{ "average", SENSORS_SUBFEATURE_CURR_AVERAGE },
Packit Service 23242a
	{ "lowest", SENSORS_SUBFEATURE_CURR_LOWEST },
Packit Service 23242a
	{ "highest", SENSORS_SUBFEATURE_CURR_HIGHEST },
Packit Service 23242a
	{ "alarm", SENSORS_SUBFEATURE_CURR_ALARM },
Packit Service 23242a
	{ "min_alarm", SENSORS_SUBFEATURE_CURR_MIN_ALARM },
Packit Service 23242a
	{ "max_alarm", SENSORS_SUBFEATURE_CURR_MAX_ALARM },
Packit Service 23242a
	{ "lcrit_alarm", SENSORS_SUBFEATURE_CURR_LCRIT_ALARM },
Packit Service 23242a
	{ "crit_alarm", SENSORS_SUBFEATURE_CURR_CRIT_ALARM },
Packit Service 23242a
	{ "beep", SENSORS_SUBFEATURE_CURR_BEEP },
Packit Service 23242a
	{ NULL, 0 }
Packit Service 23242a
};
Packit Service 23242a
Packit Service 23242a
static const struct subfeature_type_match humidity_matches[] = {
Packit Service 23242a
	{ "input", SENSORS_SUBFEATURE_HUMIDITY_INPUT },
Packit Service 23242a
	{ NULL, 0 }
Packit Service 23242a
};
Packit Service 23242a
Packit Service 23242a
static const struct subfeature_type_match cpu_matches[] = {
Packit Service 23242a
	{ "vid", SENSORS_SUBFEATURE_VID },
Packit Service 23242a
	{ NULL, 0 }
Packit Service 23242a
};
Packit Service 23242a
Packit Service 23242a
static const struct subfeature_type_match intrusion_matches[] = {
Packit Service 23242a
	{ "alarm", SENSORS_SUBFEATURE_INTRUSION_ALARM },
Packit Service 23242a
	{ "beep", SENSORS_SUBFEATURE_INTRUSION_BEEP },
Packit Service 23242a
	{ NULL, 0 }
Packit Service 23242a
};
Packit Service 23242a
static struct feature_type_match matches[] = {
Packit Service 23242a
	{ "temp%d%c", temp_matches },
Packit Service 23242a
	{ "in%d%c", in_matches },
Packit Service 23242a
	{ "fan%d%c", fan_matches },
Packit Service 23242a
	{ "cpu%d%c", cpu_matches },
Packit Service 23242a
	{ "power%d%c", power_matches },
Packit Service 23242a
	{ "curr%d%c", curr_matches },
Packit Service 23242a
	{ "energy%d%c", energy_matches },
Packit Service 23242a
	{ "intrusion%d%c", intrusion_matches },
Packit Service 23242a
	{ "humidity%d%c", humidity_matches },
Packit Service 23242a
};
Packit Service 23242a
Packit Service 23242a
/* Return the subfeature type and channel number based on the subfeature
Packit Service 23242a
   name */
Packit Service 23242a
static
Packit Service 23242a
sensors_subfeature_type sensors_subfeature_get_type(const char *name, int *nr)
Packit Service 23242a
{
Packit Service 23242a
	char c;
Packit Service 23242a
	int i, count;
Packit Service 23242a
	const struct subfeature_type_match *submatches;
Packit Service 23242a
Packit Service 23242a
	/* Special case */
Packit Service 23242a
	if (!strcmp(name, "beep_enable")) {
Packit Service 23242a
		*nr = 0;
Packit Service 23242a
		return SENSORS_SUBFEATURE_BEEP_ENABLE;
Packit Service 23242a
	}
Packit Service 23242a
Packit Service 23242a
	for (i = 0; i < ARRAY_SIZE(matches); i++)
Packit Service 23242a
		if ((count = sscanf(name, matches[i].name, nr, &c)))
Packit Service 23242a
			break;
Packit Service 23242a
Packit Service 23242a
	if (i == ARRAY_SIZE(matches) || count != 2 || c != '_')
Packit Service 23242a
		return SENSORS_SUBFEATURE_UNKNOWN;  /* no match */
Packit Service 23242a
Packit Service 23242a
	submatches = matches[i].submatches;
Packit Service 23242a
	name = strchr(name + 3, '_') + 1;
Packit Service 23242a
	for (i = 0; submatches[i].name != NULL; i++)
Packit Service 23242a
		if (!strcmp(name, submatches[i].name))
Packit Service 23242a
			return submatches[i].type;
Packit Service 23242a
Packit Service 23242a
	return SENSORS_SUBFEATURE_UNKNOWN;
Packit Service 23242a
}
Packit Service 23242a
Packit Service 23242a
static int sensors_compute_max_sf(void)
Packit Service 23242a
{
Packit Service 23242a
	int i, j, max, offset;
Packit Service 23242a
	const struct subfeature_type_match *submatches;
Packit Service 23242a
	sensors_feature_type ftype;
Packit Service 23242a
Packit Service 23242a
	max = 0;
Packit Service 23242a
	for (i = 0; i < ARRAY_SIZE(matches); i++) {
Packit Service 23242a
		submatches = matches[i].submatches;
Packit Service 23242a
		for (j = 0; submatches[j].name != NULL; j++) {
Packit Service 23242a
			ftype = submatches[j].type >> 8;
Packit Service 23242a
Packit Service 23242a
			if (ftype < SENSORS_FEATURE_VID) {
Packit Service 23242a
				offset = submatches[j].type & 0x7F;
Packit Service 23242a
				if (offset >= max)
Packit Service 23242a
					max = offset + 1;
Packit Service 23242a
			} else {
Packit Service 23242a
				offset = submatches[j].type & 0xFF;
Packit Service 23242a
				if (offset >= max * 2)
Packit Service 23242a
					max = ((offset + 1) + 1) / 2;
Packit Service 23242a
			}
Packit Service 23242a
		}
Packit Service 23242a
	}
Packit Service 23242a
Packit Service 23242a
	return max;
Packit Service 23242a
}
Packit Service 23242a
Packit Service 23242a
static int sensors_get_attr_mode(const char *device, const char *attr)
Packit Service 23242a
{
Packit Service 23242a
	char path[NAME_MAX];
Packit Service 23242a
	struct stat st;
Packit Service 23242a
	int mode = 0;
Packit Service 23242a
Packit Service 23242a
	snprintf(path, NAME_MAX, "%s/%s", device, attr);
Packit Service 23242a
	if (!stat(path, &st)) {
Packit Service 23242a
		if (st.st_mode & S_IRUSR)
Packit Service 23242a
			mode |= SENSORS_MODE_R;
Packit Service 23242a
		if (st.st_mode & S_IWUSR)
Packit Service 23242a
			mode |= SENSORS_MODE_W;
Packit Service 23242a
	}
Packit Service 23242a
	return mode;
Packit Service 23242a
}
Packit Service 23242a
Packit Service 23242a
static int sensors_read_dynamic_chip(sensors_chip_features *chip,
Packit Service 23242a
				     const char *dev_path)
Packit Service 23242a
{
Packit Service 23242a
	int i, fnum = 0, sfnum = 0, prev_slot;
Packit Service 23242a
	static int max_subfeatures, feature_size;
Packit Service 23242a
	DIR *dir;
Packit Service 23242a
	struct dirent *ent;
Packit Service 23242a
	struct {
Packit Service 23242a
		int count;
Packit Service 23242a
		sensors_subfeature *sf;
Packit Service 23242a
	} all_types[SENSORS_FEATURE_MAX];
Packit Service 23242a
	sensors_subfeature *dyn_subfeatures;
Packit Service 23242a
	sensors_feature *dyn_features;
Packit Service 23242a
	sensors_feature_type ftype;
Packit Service 23242a
	sensors_subfeature_type sftype;
Packit Service 23242a
Packit Service 23242a
	if (!(dir = opendir(dev_path)))
Packit Service 23242a
		return -errno;
Packit Service 23242a
Packit Service 23242a
	/* Dynamically figure out the max number of subfeatures */
Packit Service 23242a
	if (!max_subfeatures) {
Packit Service 23242a
		max_subfeatures = sensors_compute_max_sf();
Packit Service 23242a
		feature_size = max_subfeatures * 2;
Packit Service 23242a
	}
Packit Service 23242a
Packit Service 23242a
	/* We use a set of large sparse tables at first (one per main
Packit Service 23242a
	   feature type present) to store all found subfeatures, so that we
Packit Service 23242a
	   can store them sorted and then later create a dense sorted table. */
Packit Service 23242a
	memset(&all_types, 0, sizeof(all_types));
Packit Service 23242a
Packit Service 23242a
	while ((ent = readdir(dir))) {
Packit Service 23242a
		char *name;
Packit Service 23242a
		int nr;
Packit Service 23242a
Packit Service 23242a
		/* Skip directories and symlinks */
Packit Service 23242a
		if (ent->d_type != DT_REG)
Packit Service 23242a
			continue;
Packit Service 23242a
Packit Service 23242a
		name = ent->d_name;
Packit Service 23242a
Packit Service 23242a
		sftype = sensors_subfeature_get_type(name, &nr);
Packit Service 23242a
		if (sftype == SENSORS_SUBFEATURE_UNKNOWN)
Packit Service 23242a
			continue;
Packit Service 23242a
		ftype = sftype >> 8;
Packit Service 23242a
Packit Service 23242a
		/* Adjust the channel number */
Packit Service 23242a
		switch (ftype) {
Packit Service 23242a
		case SENSORS_FEATURE_FAN:
Packit Service 23242a
		case SENSORS_FEATURE_TEMP:
Packit Service 23242a
		case SENSORS_FEATURE_POWER:
Packit Service 23242a
		case SENSORS_FEATURE_ENERGY:
Packit Service 23242a
		case SENSORS_FEATURE_CURR:
Packit Service 23242a
		case SENSORS_FEATURE_HUMIDITY:
Packit Service 23242a
			nr--;
Packit Service 23242a
			break;
Packit Service 23242a
		default:
Packit Service 23242a
			break;
Packit Service 23242a
		}
Packit Service 23242a
Packit Service 23242a
		/* Skip invalid entries. The high limit is arbitrary, we just
Packit Service 23242a
		   don't want to allocate an insane amount of memory. */
Packit Service 23242a
		if (nr < 0 || nr >= 1024) {
Packit Service 23242a
#ifdef DEBUG
Packit Service 23242a
			sensors_fatal_error(__func__,
Packit Service 23242a
					    "Invalid channel number!");
Packit Service 23242a
#endif
Packit Service 23242a
			continue;
Packit Service 23242a
		}
Packit Service 23242a
Packit Service 23242a
		/* (Re-)allocate memory if needed */
Packit Service 23242a
		if (all_types[ftype].count < nr + 1) {
Packit Service 23242a
			int old_count = all_types[ftype].count;
Packit Service 23242a
			int step = ftype < SENSORS_FEATURE_VID ? 8 :
Packit Service 23242a
				   ftype < SENSORS_FEATURE_BEEP_ENABLE ? 2 : 1;
Packit Service 23242a
Packit Service 23242a
			while (all_types[ftype].count < nr + 1)
Packit Service 23242a
				all_types[ftype].count += step;
Packit Service 23242a
Packit Service 23242a
			all_types[ftype].sf = realloc(all_types[ftype].sf,
Packit Service 23242a
						all_types[ftype].count *
Packit Service 23242a
						feature_size *
Packit Service 23242a
						sizeof(sensors_subfeature));
Packit Service 23242a
			if (!all_types[ftype].sf)
Packit Service 23242a
				sensors_fatal_error(__func__, "Out of memory");
Packit Service 23242a
			memset(all_types[ftype].sf + old_count * feature_size,
Packit Service 23242a
			       0, (all_types[ftype].count - old_count) *
Packit Service 23242a
				  feature_size * sizeof(sensors_subfeature));
Packit Service 23242a
		}
Packit Service 23242a
Packit Service 23242a
		/* "calculate" a place to store the subfeature in our sparse,
Packit Service 23242a
		   sorted table */
Packit Service 23242a
		if (ftype < SENSORS_FEATURE_VID)
Packit Service 23242a
			i = nr * feature_size +
Packit Service 23242a
			    ((sftype & 0x80) >> 7) * max_subfeatures +
Packit Service 23242a
			    (sftype & 0x7F);
Packit Service 23242a
		else
Packit Service 23242a
			i = nr * feature_size + (sftype & 0xFF);
Packit Service 23242a
Packit Service 23242a
		if (all_types[ftype].sf[i].name) {
Packit Service 23242a
#ifdef DEBUG
Packit Service 23242a
			sensors_fatal_error(__func__, "Duplicate subfeature");
Packit Service 23242a
#endif
Packit Service 23242a
			continue;
Packit Service 23242a
		}
Packit Service 23242a
Packit Service 23242a
		/* fill in the subfeature members */
Packit Service 23242a
		all_types[ftype].sf[i].type = sftype;
Packit Service 23242a
		all_types[ftype].sf[i].name = strdup(name);
Packit Service 23242a
		if (!all_types[ftype].sf[i].name)
Packit Service 23242a
			sensors_fatal_error(__func__, "Out of memory");
Packit Service 23242a
Packit Service 23242a
		/* Other and misc subfeatures are never scaled */
Packit Service 23242a
		if (sftype < SENSORS_SUBFEATURE_VID && !(sftype & 0x80))
Packit Service 23242a
			all_types[ftype].sf[i].flags |= SENSORS_COMPUTE_MAPPING;
Packit Service 23242a
		all_types[ftype].sf[i].flags |=
Packit Service 23242a
					sensors_get_attr_mode(dev_path, name);
Packit Service 23242a
Packit Service 23242a
		sfnum++;
Packit Service 23242a
	}
Packit Service 23242a
	closedir(dir);
Packit Service 23242a
Packit Service 23242a
	if (!sfnum) { /* No subfeature */
Packit Service 23242a
		chip->subfeature = NULL;
Packit Service 23242a
		goto exit_free;
Packit Service 23242a
	}
Packit Service 23242a
Packit Service 23242a
	/* How many main features? */
Packit Service 23242a
	for (ftype = 0; ftype < SENSORS_FEATURE_MAX; ftype++) {
Packit Service 23242a
		prev_slot = -1;
Packit Service 23242a
		for (i = 0; i < all_types[ftype].count * feature_size; i++) {
Packit Service 23242a
			if (!all_types[ftype].sf[i].name)
Packit Service 23242a
				continue;
Packit Service 23242a
Packit Service 23242a
			if (i / feature_size != prev_slot) {
Packit Service 23242a
				fnum++;
Packit Service 23242a
				prev_slot = i / feature_size;
Packit Service 23242a
			}
Packit Service 23242a
		}
Packit Service 23242a
	}
Packit Service 23242a
Packit Service 23242a
	dyn_subfeatures = calloc(sfnum, sizeof(sensors_subfeature));
Packit Service 23242a
	dyn_features = calloc(fnum, sizeof(sensors_feature));
Packit Service 23242a
	if (!dyn_subfeatures || !dyn_features)
Packit Service 23242a
		sensors_fatal_error(__func__, "Out of memory");
Packit Service 23242a
Packit Service 23242a
	/* Copy from the sparse array to the compact array */
Packit Service 23242a
	sfnum = 0;
Packit Service 23242a
	fnum = -1;
Packit Service 23242a
	for (ftype = 0; ftype < SENSORS_FEATURE_MAX; ftype++) {
Packit Service 23242a
		prev_slot = -1;
Packit Service 23242a
		for (i = 0; i < all_types[ftype].count * feature_size; i++) {
Packit Service 23242a
			if (!all_types[ftype].sf[i].name)
Packit Service 23242a
				continue;
Packit Service 23242a
Packit Service 23242a
			/* New main feature? */
Packit Service 23242a
			if (i / feature_size != prev_slot) {
Packit Service 23242a
				fnum++;
Packit Service 23242a
				prev_slot = i / feature_size;
Packit Service 23242a
Packit Service 23242a
				dyn_features[fnum].name =
Packit Service 23242a
					get_feature_name(ftype,
Packit Service 23242a
						all_types[ftype].sf[i].name);
Packit Service 23242a
				dyn_features[fnum].number = fnum;
Packit Service 23242a
				dyn_features[fnum].first_subfeature = sfnum;
Packit Service 23242a
				dyn_features[fnum].type = ftype;
Packit Service 23242a
			}
Packit Service 23242a
Packit Service 23242a
			dyn_subfeatures[sfnum] = all_types[ftype].sf[i];
Packit Service 23242a
			dyn_subfeatures[sfnum].number = sfnum;
Packit Service 23242a
			/* Back to the feature */
Packit Service 23242a
			dyn_subfeatures[sfnum].mapping = fnum;
Packit Service 23242a
Packit Service 23242a
			sfnum++;
Packit Service 23242a
		}
Packit Service 23242a
	}
Packit Service 23242a
Packit Service 23242a
	chip->subfeature = dyn_subfeatures;
Packit Service 23242a
	chip->subfeature_count = sfnum;
Packit Service 23242a
	chip->feature = dyn_features;
Packit Service 23242a
	chip->feature_count = ++fnum;
Packit Service 23242a
Packit Service 23242a
exit_free:
Packit Service 23242a
	for (ftype = 0; ftype < SENSORS_FEATURE_MAX; ftype++)
Packit Service 23242a
		free(all_types[ftype].sf);
Packit Service 23242a
	return 0;
Packit Service 23242a
}
Packit Service 23242a
Packit Service 23242a
/* returns !0 if sysfs filesystem was found, 0 otherwise */
Packit Service 23242a
int sensors_init_sysfs(void)
Packit Service 23242a
{
Packit Service 23242a
	struct statfs statfsbuf;
Packit Service 23242a
Packit Service 23242a
	snprintf(sensors_sysfs_mount, NAME_MAX, "%s", "/sys");
Packit Service 23242a
	if (statfs(sensors_sysfs_mount, &statfsbuf) < 0
Packit Service 23242a
	 || statfsbuf.f_type != SYSFS_MAGIC)
Packit Service 23242a
		return 0;
Packit Service 23242a
Packit Service 23242a
	return 1;
Packit Service 23242a
}
Packit Service 23242a
Packit Service 23242a
/* returns: number of devices added (0 or 1) if successful, <0 otherwise */
Packit Service 23242a
static int sensors_read_one_sysfs_chip(const char *dev_path,
Packit Service 23242a
				       const char *dev_name,
Packit Service 23242a
				       const char *hwmon_path)
Packit Service 23242a
{
Packit Service 23242a
	int domain, bus, slot, fn, vendor, product, id;
Packit Service 23242a
	int err = -SENSORS_ERR_KERNEL;
Packit Service 23242a
	char *bus_attr;
Packit Service 23242a
	char bus_path[NAME_MAX];
Packit Service 23242a
	char linkpath[NAME_MAX];
Packit Service 23242a
	char subsys_path[NAME_MAX], *subsys;
Packit Service 23242a
	int sub_len;
Packit Service 23242a
	sensors_chip_features entry;
Packit Service 23242a
Packit Service 23242a
	/* ignore any device without name attribute */
Packit Service 23242a
	if (!(entry.chip.prefix = sysfs_read_attr(hwmon_path, "name")))
Packit Service 23242a
		return 0;
Packit Service 23242a
Packit Service 23242a
	entry.chip.path = strdup(hwmon_path);
Packit Service 23242a
	if (!entry.chip.path)
Packit Service 23242a
		sensors_fatal_error(__func__, "Out of memory");
Packit Service 23242a
Packit Service 23242a
	if (dev_path == NULL) {
Packit Service 23242a
		/* Virtual device */
Packit Service 23242a
		entry.chip.bus.type = SENSORS_BUS_TYPE_VIRTUAL;
Packit Service 23242a
		entry.chip.bus.nr = 0;
Packit Service 23242a
		/* For now we assume that virtual devices are unique */
Packit Service 23242a
		entry.chip.addr = 0;
Packit Service 23242a
		goto done;
Packit Service 23242a
	}
Packit Service 23242a
Packit Service 23242a
	/* Find bus type */
Packit Service 23242a
	snprintf(linkpath, NAME_MAX, "%s/subsystem", dev_path);
Packit Service 23242a
	sub_len = readlink(linkpath, subsys_path, NAME_MAX - 1);
Packit Service 23242a
	if (sub_len < 0 && errno == ENOENT) {
Packit Service 23242a
		/* Fallback to "bus" link for kernels <= 2.6.17 */
Packit Service 23242a
		snprintf(linkpath, NAME_MAX, "%s/bus", dev_path);
Packit Service 23242a
		sub_len = readlink(linkpath, subsys_path, NAME_MAX - 1);
Packit Service 23242a
	}
Packit Service 23242a
	if (sub_len < 0) {
Packit Service 23242a
		/* Older kernels (<= 2.6.11) have neither the subsystem
Packit Service 23242a
		   symlink nor the bus symlink */
Packit Service 23242a
		if (errno == ENOENT)
Packit Service 23242a
			subsys = NULL;
Packit Service 23242a
		else
Packit Service 23242a
			goto exit_free;
Packit Service 23242a
	} else {
Packit Service 23242a
		subsys_path[sub_len] = '\0';
Packit Service 23242a
		subsys = strrchr(subsys_path, '/') + 1;
Packit Service 23242a
	}
Packit Service 23242a
Packit Service 23242a
	if ((!subsys || !strcmp(subsys, "i2c")) &&
Packit Service 23242a
	    sscanf(dev_name, "%hd-%x", &entry.chip.bus.nr,
Packit Service 23242a
		   &entry.chip.addr) == 2) {
Packit Service 23242a
		/* find out if legacy ISA or not */
Packit Service 23242a
		if (entry.chip.bus.nr == 9191) {
Packit Service 23242a
			entry.chip.bus.type = SENSORS_BUS_TYPE_ISA;
Packit Service 23242a
			entry.chip.bus.nr = 0;
Packit Service 23242a
		} else {
Packit Service 23242a
			entry.chip.bus.type = SENSORS_BUS_TYPE_I2C;
Packit Service 23242a
			snprintf(bus_path, sizeof(bus_path),
Packit Service 23242a
				"%s/class/i2c-adapter/i2c-%d/device",
Packit Service 23242a
				sensors_sysfs_mount, entry.chip.bus.nr);
Packit Service 23242a
Packit Service 23242a
			if ((bus_attr = sysfs_read_attr(bus_path, "name"))) {
Packit Service 23242a
				if (!strncmp(bus_attr, "ISA ", 4)) {
Packit Service 23242a
					entry.chip.bus.type = SENSORS_BUS_TYPE_ISA;
Packit Service 23242a
					entry.chip.bus.nr = 0;
Packit Service 23242a
				}
Packit Service 23242a
Packit Service 23242a
				free(bus_attr);
Packit Service 23242a
			}
Packit Service 23242a
		}
Packit Service 23242a
	} else
Packit Service 23242a
	if ((!subsys || !strcmp(subsys, "spi")) &&
Packit Service 23242a
	    sscanf(dev_name, "spi%hd.%d", &entry.chip.bus.nr,
Packit Service 23242a
		   &entry.chip.addr) == 2) {
Packit Service 23242a
		/* SPI */
Packit Service 23242a
		entry.chip.bus.type = SENSORS_BUS_TYPE_SPI;
Packit Service 23242a
	} else
Packit Service 23242a
	if ((!subsys || !strcmp(subsys, "pci")) &&
Packit Service 23242a
	    sscanf(dev_name, "%x:%x:%x.%x", &domain, &bus, &slot, &fn) == 4) {
Packit Service 23242a
		/* PCI */
Packit Service 23242a
		entry.chip.addr = (domain << 16) + (bus << 8) + (slot << 3) + fn;
Packit Service 23242a
		entry.chip.bus.type = SENSORS_BUS_TYPE_PCI;
Packit Service 23242a
		entry.chip.bus.nr = 0;
Packit Service 23242a
	} else
Packit Service 23242a
	if ((!subsys || !strcmp(subsys, "platform") ||
Packit Service 23242a
			!strcmp(subsys, "of_platform"))) {
Packit Service 23242a
		/* must be new ISA (platform driver) */
Packit Service 23242a
		if (sscanf(dev_name, "%*[a-z0-9_].%d", &entry.chip.addr) != 1)
Packit Service 23242a
			entry.chip.addr = 0;
Packit Service 23242a
		entry.chip.bus.type = SENSORS_BUS_TYPE_ISA;
Packit Service 23242a
		entry.chip.bus.nr = 0;
Packit Service 23242a
	} else if (subsys && !strcmp(subsys, "acpi")) {
Packit Service 23242a
		entry.chip.bus.type = SENSORS_BUS_TYPE_ACPI;
Packit Service 23242a
		/* For now we assume that acpi devices are unique */
Packit Service 23242a
		entry.chip.bus.nr = 0;
Packit Service 23242a
		entry.chip.addr = 0;
Packit Service 23242a
	} else
Packit Service 23242a
	if (subsys && !strcmp(subsys, "hid") &&
Packit Service 23242a
	    sscanf(dev_name, "%x:%x:%x.%x", &bus, &vendor, &product, &id) == 4) {
Packit Service 23242a
		entry.chip.bus.type = SENSORS_BUS_TYPE_HID;
Packit Service 23242a
		/* As of kernel 2.6.32, the hid device names don't look good */
Packit Service 23242a
		entry.chip.bus.nr = bus;
Packit Service 23242a
		entry.chip.addr = id;
Packit Service 23242a
	} else
Packit Service 23242a
	if (subsys && !strcmp(subsys, "mdio_bus")) {
Packit Service 23242a
		if (sscanf(dev_name, "%*[^:]:%d", &entry.chip.addr) != 1)
Packit Service 23242a
			entry.chip.addr = 0;
Packit Service 23242a
		entry.chip.bus.type = SENSORS_BUS_TYPE_MDIO;
Packit Service 23242a
		entry.chip.bus.nr = 0;
Packit Service 23242a
	} else {
Packit Service 23242a
		/* Ignore unknown device */
Packit Service 23242a
		err = 0;
Packit Service 23242a
		goto exit_free;
Packit Service 23242a
	}
Packit Service 23242a
Packit Service 23242a
done:
Packit Service 23242a
	if (sensors_read_dynamic_chip(&entry, hwmon_path) < 0)
Packit Service 23242a
		goto exit_free;
Packit Service 23242a
	if (!entry.subfeature) { /* No subfeature, discard chip */
Packit Service 23242a
		err = 0;
Packit Service 23242a
		goto exit_free;
Packit Service 23242a
	}
Packit Service 23242a
	sensors_add_proc_chips(&entry);
Packit Service 23242a
Packit Service 23242a
	return 1;
Packit Service 23242a
Packit Service 23242a
exit_free:
Packit Service 23242a
	free(entry.chip.prefix);
Packit Service 23242a
	free(entry.chip.path);
Packit Service 23242a
	return err;
Packit Service 23242a
}
Packit Service 23242a
Packit Service 23242a
static int sensors_add_hwmon_device_compat(const char *path,
Packit Service 23242a
					   const char *dev_name)
Packit Service 23242a
{
Packit Service 23242a
	int err;
Packit Service 23242a
Packit Service 23242a
	err = sensors_read_one_sysfs_chip(path, dev_name, path);
Packit Service 23242a
	if (err < 0)
Packit Service 23242a
		return err;
Packit Service 23242a
	return 0;
Packit Service 23242a
}
Packit Service 23242a
Packit Service 23242a
/* returns 0 if successful, !0 otherwise */
Packit Service 23242a
static int sensors_read_sysfs_chips_compat(void)
Packit Service 23242a
{
Packit Service 23242a
	int ret;
Packit Service 23242a
Packit Service 23242a
	ret = sysfs_foreach_busdev("i2c", sensors_add_hwmon_device_compat);
Packit Service 23242a
	if (ret && ret != ENOENT)
Packit Service 23242a
		return -SENSORS_ERR_KERNEL;
Packit Service 23242a
Packit Service 23242a
	return 0;
Packit Service 23242a
}
Packit Service 23242a
Packit Service 23242a
static int sensors_add_hwmon_device(const char *path, const char *classdev)
Packit Service 23242a
{
Packit Service 23242a
	char linkpath[NAME_MAX];
Packit Service 23242a
	char device[NAME_MAX], *device_p;
Packit Service 23242a
	int dev_len, err;
Packit Service 23242a
	(void)classdev; /* hide warning */
Packit Service 23242a
Packit Service 23242a
	snprintf(linkpath, NAME_MAX, "%s/device", path);
Packit Service 23242a
	dev_len = readlink(linkpath, device, NAME_MAX - 1);
Packit Service 23242a
	if (dev_len < 0) {
Packit Service 23242a
		/* No device link? Treat as virtual */
Packit Service 23242a
		err = sensors_read_one_sysfs_chip(NULL, NULL, path);
Packit Service 23242a
	} else {
Packit Service 23242a
		device[dev_len] = '\0';
Packit Service 23242a
		device_p = strrchr(device, '/') + 1;
Packit Service 23242a
Packit Service 23242a
		/* The attributes we want might be those of the hwmon class
Packit Service 23242a
		   device, or those of the device itself. */
Packit Service 23242a
		err = sensors_read_one_sysfs_chip(linkpath, device_p, path);
Packit Service 23242a
		if (err == 0)
Packit Service 23242a
			err = sensors_read_one_sysfs_chip(linkpath, device_p,
Packit Service 23242a
							  linkpath);
Packit Service 23242a
	}
Packit Service 23242a
	if (err < 0)
Packit Service 23242a
		return err;
Packit Service 23242a
	return 0;
Packit Service 23242a
}
Packit Service 23242a
Packit Service 23242a
/* returns 0 if successful, !0 otherwise */
Packit Service 23242a
int sensors_read_sysfs_chips(void)
Packit Service 23242a
{
Packit Service 23242a
	int ret;
Packit Service 23242a
Packit Service 23242a
	ret = sysfs_foreach_classdev("hwmon", sensors_add_hwmon_device);
Packit Service 23242a
	if (ret == ENOENT) {
Packit Service 23242a
		/* compatibility function for kernel 2.6.n where n <= 13 */
Packit Service 23242a
		return sensors_read_sysfs_chips_compat();
Packit Service 23242a
	}
Packit Service 23242a
Packit Service 23242a
	if (ret > 0)
Packit Service 23242a
		ret = -SENSORS_ERR_KERNEL;
Packit Service 23242a
	return ret;
Packit Service 23242a
}
Packit Service 23242a
Packit Service 23242a
/* returns 0 if successful, !0 otherwise */
Packit Service 23242a
static int sensors_add_i2c_bus(const char *path, const char *classdev)
Packit Service 23242a
{
Packit Service 23242a
	sensors_bus entry;
Packit Service 23242a
Packit Service 23242a
	if (sscanf(classdev, "i2c-%hd", &entry.bus.nr) != 1 ||
Packit Service 23242a
	    entry.bus.nr == 9191) /* legacy ISA */
Packit Service 23242a
		return 0;
Packit Service 23242a
	entry.bus.type = SENSORS_BUS_TYPE_I2C;
Packit Service 23242a
Packit Service 23242a
	/* Get the adapter name from the classdev "name" attribute
Packit Service 23242a
	 * (Linux 2.6.20 and later). If it fails, fall back to
Packit Service 23242a
	 * the device "name" attribute (for older kernels). */
Packit Service 23242a
	entry.adapter = sysfs_read_attr(path, "name");
Packit Service 23242a
	if (!entry.adapter)
Packit Service 23242a
		entry.adapter = sysfs_read_attr(path, "device/name");
Packit Service 23242a
	if (entry.adapter)
Packit Service 23242a
		sensors_add_proc_bus(&entry);
Packit Service 23242a
Packit Service 23242a
	return 0;
Packit Service 23242a
}
Packit Service 23242a
Packit Service 23242a
/* returns 0 if successful, !0 otherwise */
Packit Service 23242a
int sensors_read_sysfs_bus(void)
Packit Service 23242a
{
Packit Service 23242a
	int ret;
Packit Service 23242a
Packit Service 23242a
	ret = sysfs_foreach_classdev("i2c-adapter", sensors_add_i2c_bus);
Packit Service 23242a
	if (ret == ENOENT)
Packit Service 23242a
		ret = sysfs_foreach_busdev("i2c", sensors_add_i2c_bus);
Packit Service 23242a
	if (ret && ret != ENOENT)
Packit Service 23242a
		return -SENSORS_ERR_KERNEL;
Packit Service 23242a
Packit Service 23242a
	return 0;
Packit Service 23242a
}
Packit Service 23242a
Packit Service 23242a
int sensors_read_sysfs_attr(const sensors_chip_name *name,
Packit Service 23242a
			    const sensors_subfeature *subfeature,
Packit Service 23242a
			    double *value)
Packit Service 23242a
{
Packit Service 23242a
	char n[NAME_MAX];
Packit Service 23242a
	FILE *f;
Packit Service 23242a
Packit Service 23242a
	snprintf(n, NAME_MAX, "%s/%s", name->path, subfeature->name);
Packit Service 23242a
	if ((f = fopen(n, "r"))) {
Packit Service 23242a
		int res, err = 0;
Packit Service 23242a
Packit Service 23242a
		errno = 0;
Packit Service 23242a
		res = fscanf(f, "%lf", value);
Packit Service 23242a
		if (res == EOF && errno == EIO)
Packit Service 23242a
			err = -SENSORS_ERR_IO;
Packit Service 23242a
		else if (res != 1)
Packit Service 23242a
			err = -SENSORS_ERR_ACCESS_R;
Packit Service 23242a
		res = fclose(f);
Packit Service 23242a
		if (err)
Packit Service 23242a
			return err;
Packit Service 23242a
Packit Service 23242a
		if (res == EOF) {
Packit Service 23242a
			if (errno == EIO)
Packit Service 23242a
				return -SENSORS_ERR_IO;
Packit Service 23242a
			else 
Packit Service 23242a
				return -SENSORS_ERR_ACCESS_R;
Packit Service 23242a
		}
Packit Service 23242a
		*value /= get_type_scaling(subfeature->type);
Packit Service 23242a
	} else
Packit Service 23242a
		return -SENSORS_ERR_KERNEL;
Packit Service 23242a
Packit Service 23242a
	return 0;
Packit Service 23242a
}
Packit Service 23242a
Packit Service 23242a
int sensors_write_sysfs_attr(const sensors_chip_name *name,
Packit Service 23242a
			     const sensors_subfeature *subfeature,
Packit Service 23242a
			     double value)
Packit Service 23242a
{
Packit Service 23242a
	char n[NAME_MAX];
Packit Service 23242a
	FILE *f;
Packit Service 23242a
Packit Service 23242a
	snprintf(n, NAME_MAX, "%s/%s", name->path, subfeature->name);
Packit Service 23242a
	if ((f = fopen(n, "w"))) {
Packit Service 23242a
		int res, err = 0;
Packit Service 23242a
Packit Service 23242a
		value *= get_type_scaling(subfeature->type);
Packit Service 23242a
		res = fprintf(f, "%d", (int) value);
Packit Service 23242a
		if (res == -EIO)
Packit Service 23242a
			err = -SENSORS_ERR_IO;
Packit Service 23242a
		else if (res < 0)
Packit Service 23242a
			err = -SENSORS_ERR_ACCESS_W;
Packit Service 23242a
		res = fclose(f);
Packit Service 23242a
		if (err)
Packit Service 23242a
			return err;
Packit Service 23242a
Packit Service 23242a
		if (res == EOF) {
Packit Service 23242a
			if (errno == EIO)
Packit Service 23242a
				return -SENSORS_ERR_IO;
Packit Service 23242a
			else 
Packit Service 23242a
				return -SENSORS_ERR_ACCESS_W;
Packit Service 23242a
		}
Packit Service 23242a
	} else
Packit Service 23242a
		return -SENSORS_ERR_KERNEL;
Packit Service 23242a
Packit Service 23242a
	return 0;
Packit Service 23242a
}