root/lm-sensors/branches/lm-sensors-3.0.0/lib/sysfs.c @ 4766

Revision 4766, 12.2 KB (checked in by khali, 7 years ago)

Add support for the standard beep_enable attribute (#2248).

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
Line 
1/*
2    sysfs.c - Part of libsensors, a library for reading Linux sensor data
3    Copyright (c) 2005 Mark M. Hoffman <mhoffman@lightlink.com>
4
5    This program is free software; you can redistribute it and/or modify
6    it under the terms of the GNU General Public License as published by
7    the Free Software Foundation; either version 2 of the License, or
8    (at your option) any later version.
9
10    This program is distributed in the hope that it will be useful,
11    but WITHOUT ANY WARRANTY; without even the implied warranty of
12    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13    GNU General Public License for more details.
14
15    You should have received a copy of the GNU General Public License
16    along with this program; if not, write to the Free Software
17    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
18*/
19
20/* this define needed for strndup() */
21#define _GNU_SOURCE
22
23#include <sys/types.h>
24#include <sys/stat.h>
25#include <unistd.h>
26#include <string.h>
27#include <stdlib.h>
28#include <limits.h>
29#include <errno.h>
30#include <sysfs/libsysfs.h>
31#include "data.h"
32#include "error.h"
33#include "access.h"
34#include "general.h"
35#include "sysfs.h"
36
37char sensors_sysfs_mount[NAME_MAX];
38
39#define MAX_SENSORS_PER_TYPE    20
40#define MAX_SUB_FEATURES        6
41/* Room for all 3 types (in, fan, temp) with all their subfeatures + VID
42   + misc features */
43#define ALL_POSSIBLE_FEATURES   (MAX_SENSORS_PER_TYPE * MAX_SUB_FEATURES * 6 \
44                                 + MAX_SENSORS_PER_TYPE + 1)
45
46static
47int get_type_scaling(int type)
48{
49        switch (type & 0xFF10) {
50        case SENSORS_FEATURE_IN:
51        case SENSORS_FEATURE_TEMP:
52                return 1000;
53        case SENSORS_FEATURE_FAN:
54                return 1;
55        }
56
57        switch (type) {
58        case SENSORS_FEATURE_VID:
59                return 1000;
60        default:
61                return 1;
62        }
63}
64
65static int sensors_read_dynamic_chip(sensors_chip_features *chip,
66                                     struct sysfs_device *sysdir)
67{
68        int i, type, fnum = 0;
69        struct sysfs_attribute *attr;
70        struct dlist *attrs;
71        sensors_chip_feature *features;
72        sensors_chip_feature *dyn_features;
73        char *name;
74
75        attrs = sysfs_get_device_attributes(sysdir);
76
77        if (attrs == NULL)
78                return -ENOENT;
79
80        /* We use a large sparse table at first to store all found features,
81           so that we can store them sorted at type and index and then later
82           create a dense sorted table. */
83        features = calloc(ALL_POSSIBLE_FEATURES, sizeof(sensors_chip_feature));
84        if (!features)
85                sensors_fatal_error(__FUNCTION__, "Out of memory");
86
87        dlist_for_each_data(attrs, attr, struct sysfs_attribute) {
88                name = attr->name;
89                int nr;
90
91                type = sensors_feature_get_type(name, &nr);
92                if (type == SENSORS_FEATURE_UNKNOWN)
93                        continue;
94
95                /* Adjust the channel number */
96                switch (type & 0xFF00) {
97                        case SENSORS_FEATURE_FAN:
98                        case SENSORS_FEATURE_TEMP:
99                                if (nr)
100                                        nr--;
101                                break;
102                }
103
104                if (nr >= MAX_SENSORS_PER_TYPE) {
105                        fprintf(stderr, "libsensors error, more sensors of one"
106                                " type then MAX_SENSORS_PER_TYPE, ignoring "
107                                "feature: %s\n", name);
108                        continue;
109                }
110
111                /* "calculate" a place to store the feature in our sparse,
112                   sorted table */
113                switch (type) {
114                case SENSORS_FEATURE_VID:
115                        i = nr + MAX_SENSORS_PER_TYPE * MAX_SUB_FEATURES * 6;
116                        break;
117                case SENSORS_FEATURE_BEEP_ENABLE:
118                        i = MAX_SENSORS_PER_TYPE * MAX_SUB_FEATURES * 6 +
119                            MAX_SENSORS_PER_TYPE;
120                        break;
121                default:
122                        i = (type >> 8) * MAX_SENSORS_PER_TYPE *
123                            MAX_SUB_FEATURES * 2 + nr * MAX_SUB_FEATURES * 2 +
124                            ((type & 0x10) >> 4) * MAX_SUB_FEATURES +
125                            (type & 0x0F);
126                }
127
128                if (features[i].data.name) {
129                        fprintf(stderr, "libsensors error, trying to add dupli"
130                                "cate feature: %s to dynamic feature table\n",
131                                name);
132                        continue;
133                }
134
135                /* fill in the feature members */
136                features[i].data.type = type;
137
138                /* check for _input extension and remove */
139                nr = strlen(name);
140                if (nr > 6 && !strcmp(name + nr - 6, "_input"))
141                        features[i].data.name = strndup(name, nr - 6);
142                else
143                        features[i].data.name = strdup(name);
144
145                if ((type & 0x00FF) == 0) {
146                        /* main feature */
147                        features[i].data.mapping = SENSORS_NO_MAPPING;
148                } else {
149                        /* sub feature */
150                        /* The mapping is set below after numbering */
151                        if (!(type & 0x10))
152                                features[i].data.flags |= SENSORS_COMPUTE_MAPPING;
153                }
154
155                if (attr->method & SYSFS_METHOD_SHOW)
156                        features[i].data.flags |= SENSORS_MODE_R;
157                if (attr->method & SYSFS_METHOD_STORE)
158                        features[i].data.flags |= SENSORS_MODE_W;
159
160                fnum++;
161        }
162
163        if (!fnum) { /* No feature */
164                chip->feature = NULL;
165                goto exit_free;
166        }
167
168        dyn_features = calloc(fnum, sizeof(sensors_chip_feature));
169        if (dyn_features == NULL) {
170                sensors_fatal_error(__FUNCTION__, "Out of memory");
171        }
172
173        fnum = 0;
174        for (i = 0; i < ALL_POSSIBLE_FEATURES; i++) {
175                if (features[i].data.name) {
176                        dyn_features[fnum] = features[i];
177                        fnum++;
178                }
179        }
180
181        /* Number the features linearly, so that feature number N is at
182           position N in the array. This allows for O(1) look-ups. */
183        for (i = 0; i < fnum; i++) {
184                int j;
185
186                dyn_features[i].data.number = i;
187                if (dyn_features[i].data.mapping == SENSORS_NO_MAPPING) {
188                        /* Main feature, set the mapping field of all its
189                           subfeatures */
190                        for (j = i + 1; j < fnum &&
191                             dyn_features[j].data.mapping != SENSORS_NO_MAPPING;
192                             j++)
193                                dyn_features[j].data.mapping = i;
194                }
195        }
196
197        chip->feature = dyn_features;
198        chip->feature_count = fnum;
199
200exit_free:
201        free(features);
202        return 0;
203}
204
205/* returns !0 if sysfs filesystem was found, 0 otherwise */
206int sensors_init_sysfs(void)
207{
208        struct stat statbuf;
209
210        /* libsysfs will return success even if sysfs is not mounted,
211           so we have to double-check */
212        if (sysfs_get_mnt_path(sensors_sysfs_mount, NAME_MAX)
213         || stat(sensors_sysfs_mount, &statbuf) < 0
214         || statbuf.st_nlink <= 2)      /* Empty directory */
215                return 0;
216
217        return 1;
218}
219
220/* returns: 0 if successful, !0 otherwise */
221static int sensors_read_one_sysfs_chip(struct sysfs_device *dev)
222{
223        int domain, bus, slot, fn;
224        int err = -SENSORS_ERR_PARSE;
225        struct sysfs_attribute *attr, *bus_attr;
226        char bus_path[SYSFS_PATH_MAX];
227        sensors_chip_features entry;
228
229        /* ignore any device without name attribute */
230        if (!(attr = sysfs_get_device_attr(dev, "name")))
231                return 0;
232
233        /* NB: attr->value[attr->len-1] == '\n'; chop that off */
234        entry.chip.prefix = strndup(attr->value, attr->len - 1);
235        if (!entry.chip.prefix)
236                sensors_fatal_error(__FUNCTION__, "out of memory");
237
238        entry.chip.path = strdup(dev->path);
239        if (!entry.chip.path)
240                sensors_fatal_error(__FUNCTION__, "out of memory");
241
242        if (sscanf(dev->name, "%hd-%x", &entry.chip.bus.nr, &entry.chip.addr) == 2) {
243                /* find out if legacy ISA or not */
244                if (entry.chip.bus.nr == 9191) {
245                        entry.chip.bus.type = SENSORS_BUS_TYPE_ISA;
246                        entry.chip.bus.nr = 0;
247                } else {
248                        entry.chip.bus.type = SENSORS_BUS_TYPE_I2C;
249                        snprintf(bus_path, sizeof(bus_path),
250                                "%s/class/i2c-adapter/i2c-%d/device/name",
251                                sensors_sysfs_mount, entry.chip.bus.nr);
252
253                        if ((bus_attr = sysfs_open_attribute(bus_path))) {
254                                if (sysfs_read_attribute(bus_attr)) {
255                                        sysfs_close_attribute(bus_attr);
256                                        goto exit_free;
257                                }
258
259                                if (bus_attr->value
260                                 && !strncmp(bus_attr->value, "ISA ", 4)) {
261                                        entry.chip.bus.type = SENSORS_BUS_TYPE_ISA;
262                                        entry.chip.bus.nr = 0;
263                                }
264
265                                sysfs_close_attribute(bus_attr);
266                        }
267                }
268        } else if (sscanf(dev->name, "spi%hd.%d", &entry.chip.bus.nr,
269                          &entry.chip.addr) == 2) {
270                /* SPI */
271                entry.chip.bus.type = SENSORS_BUS_TYPE_SPI;
272        } else if (sscanf(dev->name, "%*[a-z0-9_].%d", &entry.chip.addr) == 1) {
273                /* must be new ISA (platform driver) */
274                entry.chip.bus.type = SENSORS_BUS_TYPE_ISA;
275                entry.chip.bus.nr = 0;
276        } else if (sscanf(dev->name, "%x:%x:%x.%x", &domain, &bus, &slot, &fn) == 4) {
277                /* PCI */
278                entry.chip.addr = (domain << 16) + (bus << 8) + (slot << 3) + fn;
279                entry.chip.bus.type = SENSORS_BUS_TYPE_PCI;
280                entry.chip.bus.nr = 0;
281        } else
282                goto exit_free;
283
284        if (sensors_read_dynamic_chip(&entry, dev) < 0)
285                goto exit_free;
286        if (!entry.feature) { /* No feature, discard chip */
287                err = 0;
288                goto exit_free;
289        }
290        sensors_add_proc_chips(&entry);
291
292        return 0;
293
294exit_free:
295        free(entry.chip.prefix);
296        free(entry.chip.path);
297        return err;
298}
299
300/* returns 0 if successful, !0 otherwise */
301static int sensors_read_sysfs_chips_compat(void)
302{
303        struct sysfs_bus *bus;
304        struct dlist *devs;
305        struct sysfs_device *dev;
306        int ret = 0;
307
308        if (!(bus = sysfs_open_bus("i2c"))) {
309                if (errno && errno != ENOENT)
310                        ret = -SENSORS_ERR_PROC;
311                goto exit0;
312        }
313
314        if (!(devs = sysfs_get_bus_devices(bus))) {
315                if (errno && errno != ENOENT)
316                        ret = -SENSORS_ERR_PROC;
317                goto exit1;
318        }
319
320        dlist_for_each_data(devs, dev, struct sysfs_device)
321                if ((ret = sensors_read_one_sysfs_chip(dev)))
322                        goto exit1;
323
324exit1:
325        /* this frees bus and devs */
326        sysfs_close_bus(bus);
327
328exit0:
329        return ret;
330}
331
332/* returns 0 if successful, !0 otherwise */
333int sensors_read_sysfs_chips(void)
334{
335        struct sysfs_class *cls;
336        struct dlist *clsdevs;
337        struct sysfs_class_device *clsdev;
338        int ret = 0;
339
340        if (!(cls = sysfs_open_class("hwmon"))) {
341                /* compatibility function for kernel 2.6.n where n <= 13 */
342                return sensors_read_sysfs_chips_compat();
343        }
344
345        if (!(clsdevs = sysfs_get_class_devices(cls))) {
346                if (errno && errno != ENOENT)
347                        ret = -SENSORS_ERR_PROC;
348                goto exit;
349        }
350
351        dlist_for_each_data(clsdevs, clsdev, struct sysfs_class_device) {
352                struct sysfs_device *dev;
353                if (!(dev = sysfs_get_classdev_device(clsdev))) {
354                        ret = -SENSORS_ERR_PROC;
355                        goto exit;
356                }
357                if ((ret = sensors_read_one_sysfs_chip(dev)))
358                        goto exit;
359        }
360
361exit:
362        /* this frees cls and clsdevs */
363        sysfs_close_class(cls);
364        return ret;
365}
366
367/* returns 0 if successful, !0 otherwise */
368int sensors_read_sysfs_bus(void)
369{
370        struct sysfs_class *cls;
371        struct dlist *clsdevs;
372        struct sysfs_class_device *clsdev;
373        sensors_bus entry;
374        int ret = 0;
375
376        if (!(cls = sysfs_open_class("i2c-adapter"))) {
377                if (errno && errno != ENOENT)
378                        ret = -SENSORS_ERR_PROC;
379                goto exit0;
380        }
381
382        if (!(clsdevs = sysfs_get_class_devices(cls))) {
383                if (errno && errno != ENOENT)
384                        ret = -SENSORS_ERR_PROC;
385                goto exit1;
386        }
387
388        dlist_for_each_data(clsdevs, clsdev, struct sysfs_class_device) {
389                struct sysfs_device *dev;
390                struct sysfs_attribute *attr;
391
392                /* Get the adapter name from the classdev "name" attribute
393                 * (Linux 2.6.20 and later). If it fails, fall back to
394                 * the device "name" attribute (for older kernels). */
395                if (!(attr = sysfs_get_classdev_attr(clsdev, "name"))
396                 && !((dev = sysfs_get_classdev_device(clsdev)) &&
397                      (attr = sysfs_get_device_attr(dev, "name"))))
398                        continue;
399
400                if (sscanf(clsdev->name, "i2c-%hd", &entry.bus.nr) != 1 ||
401                    entry.bus.nr == 9191) /* legacy ISA */
402                        continue;
403                entry.bus.type = SENSORS_BUS_TYPE_I2C;
404
405                /* NB: attr->value[attr->len-1] == '\n'; chop that off */
406                entry.adapter = strndup(attr->value, attr->len - 1);
407                if (!entry.adapter)
408                        sensors_fatal_error(__FUNCTION__, "out of memory");
409
410                sensors_add_proc_bus(&entry);
411        }
412
413exit1:
414        /* this frees *cls _and_ *clsdevs */
415        sysfs_close_class(cls);
416
417exit0:
418        return ret;
419}
420
421int sensors_read_sysfs_attr(const sensors_chip_name *name, int feature,
422                            double *value)
423{
424        const sensors_chip_feature *the_feature;
425        char n[NAME_MAX];
426        FILE *f;
427        const char *suffix = "";
428
429        if (!(the_feature = sensors_lookup_feature_nr(name, feature)))
430                return -SENSORS_ERR_NO_ENTRY;
431
432        /* REVISIT: this is a ugly hack */
433        if (the_feature->data.type == SENSORS_FEATURE_IN
434         || the_feature->data.type == SENSORS_FEATURE_FAN
435         || the_feature->data.type == SENSORS_FEATURE_TEMP)
436                suffix = "_input";
437
438        snprintf(n, NAME_MAX, "%s/%s%s", name->path, the_feature->data.name,
439                 suffix);
440        if ((f = fopen(n, "r"))) {
441                int res = fscanf(f, "%lf", value);
442                fclose(f);
443                if (res != 1)
444                        return -SENSORS_ERR_PROC;
445                *value /= get_type_scaling(the_feature->data.type);
446        } else
447                return -SENSORS_ERR_PROC;
448
449        return 0;
450}
451
452int sensors_write_sysfs_attr(const sensors_chip_name *name, int feature,
453                             double value)
454{
455        const sensors_chip_feature *the_feature;
456        char n[NAME_MAX];
457        FILE *f;
458        const char *suffix = "";
459
460        if (!(the_feature = sensors_lookup_feature_nr(name, feature)))
461                return -SENSORS_ERR_NO_ENTRY;
462
463        /* REVISIT: this is a ugly hack */
464        if (the_feature->data.type == SENSORS_FEATURE_IN
465         || the_feature->data.type == SENSORS_FEATURE_FAN
466         || the_feature->data.type == SENSORS_FEATURE_TEMP)
467                suffix = "_input";
468
469        snprintf(n, NAME_MAX, "%s/%s%s", name->path, the_feature->data.name,
470                 suffix);
471        if ((f = fopen(n, "w"))) {
472                value *= get_type_scaling(the_feature->data.type);
473                fprintf(f, "%d", (int) value);
474                fclose(f);
475        } else
476                return -SENSORS_ERR_PROC;
477
478        return 0;
479}
Note: See TracBrowser for help on using the browser.