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

Revision 4759, 12.2 KB (checked in by khali, 6 years ago)

Renumber the features linearly, so that feature number N is at
position N in the array. This allows for O(1) look-ups, as opposed
to O(N) before. This makes sensors_lookup_feature_nr() 2.4 times
faster in my real-world tests, resulting in a 6% performance boost
on average in the runtime part of "sensors".

  • 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    16
40#define MAX_SUB_FEATURES        22
41/* Room for all 3 types (in, fan, temp) with all their subfeatures + VID */
42#define ALL_POSSIBLE_FEATURES   (MAX_SENSORS_PER_TYPE * MAX_SUB_FEATURES * 3 \
43                                 + MAX_SENSORS_PER_TYPE)
44
45static
46int get_type_scaling(int type)
47{
48        switch (type & 0xFF10) {
49        case SENSORS_FEATURE_IN:
50        case SENSORS_FEATURE_TEMP:
51                return 3;
52        case SENSORS_FEATURE_FAN:
53                return 0;
54        }
55
56        switch (type) {
57        case SENSORS_FEATURE_VID:
58                return 3;
59        default:
60                return 0;
61        }
62}
63
64static int sensors_read_dynamic_chip(sensors_chip_features *chip,
65                                     struct sysfs_device *sysdir)
66{
67        int i, type, fnum = 1;
68        struct sysfs_attribute *attr;
69        struct dlist *attrs;
70        sensors_chip_feature *features;
71        sensors_chip_feature *dyn_features;
72        char *name;
73
74        attrs = sysfs_get_device_attributes(sysdir);
75
76        if (attrs == NULL)
77                return -ENOENT;
78
79        /* We use a large sparse table at first to store all found features,
80           so that we can store them sorted at type and index and then later
81           create a dense sorted table. */
82        features = calloc(ALL_POSSIBLE_FEATURES, sizeof(sensors_chip_feature));
83        if (!features)
84                sensors_fatal_error(__FUNCTION__, "Out of memory");
85
86        dlist_for_each_data(attrs, attr, struct sysfs_attribute) {
87                sensors_chip_feature feature;
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                memset(&feature, 0, sizeof(sensors_chip_feature));
96                /* check for _input extension and remove */
97                i = strlen(name);
98                if (i > 6 && !strcmp(name + i - 6, "_input"))
99                        feature.data.name = strndup(name, i-6);
100                else
101                        feature.data.name = strdup(name);
102
103                /* Adjust the channel number */
104                switch (type & 0xFF00) {
105                        case SENSORS_FEATURE_FAN:
106                        case SENSORS_FEATURE_TEMP:
107                                if (nr)
108                                        nr--;
109                                break;
110                }
111
112                if (nr >= MAX_SENSORS_PER_TYPE) {
113                        fprintf(stderr, "libsensors error, more sensors of one"
114                                " type then MAX_SENSORS_PER_TYPE, ignoring "
115                                "feature: %s\n", name);
116                        free(feature.data.name);
117                        continue;
118                }
119
120                /* "calculate" a place to store the feature in our sparse,
121                   sorted table */
122                if (type == SENSORS_FEATURE_VID) {
123                        i = nr + MAX_SENSORS_PER_TYPE * MAX_SUB_FEATURES * 3;
124                } else {
125                        i = (type >> 8) * MAX_SENSORS_PER_TYPE *
126                                MAX_SUB_FEATURES + nr * MAX_SUB_FEATURES +
127                                (type & 0xFF);
128                }
129
130                if (features[i].data.name) {
131                        fprintf(stderr, "libsensors error, trying to add dupli"
132                                "cate feature: %s to dynamic feature table\n",
133                                name);
134                        free(feature.data.name);
135                        continue;
136                }
137
138                /* fill in the other feature members */
139                feature.data.number = i;
140                feature.data.type = type;
141
142                if ((type & 0x00FF) == 0) {
143                        /* main feature */
144                        feature.data.mapping = SENSORS_NO_MAPPING;
145                } else {
146                        /* sub feature */
147                        feature.data.mapping = i - i % MAX_SUB_FEATURES;
148                        if (!(type & 0x10))
149                                feature.data.flags |= SENSORS_COMPUTE_MAPPING;
150                }
151
152                if (attr->method & SYSFS_METHOD_SHOW)
153                        feature.data.flags |= SENSORS_MODE_R;
154                if (attr->method & SYSFS_METHOD_STORE)
155                        feature.data.flags |= SENSORS_MODE_W;
156
157                feature.scaling = get_type_scaling(type);
158
159                features[i] = feature;
160                fnum++;
161        }
162
163        if (fnum == 1) { /* 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        /* Renumber 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, old;
185
186                old = dyn_features[i].data.number;
187                dyn_features[i].data.number = i;
188                for (j = i + 1;
189                     j < fnum && dyn_features[j].data.mapping != SENSORS_NO_MAPPING;
190                     j++) {
191                        if (dyn_features[j].data.mapping == old)
192                                dyn_features[j].data.mapping = i;
193                }
194        }
195
196        chip->feature = dyn_features;
197
198exit_free:
199        free(features);
200        return 0;
201}
202
203/* returns !0 if sysfs filesystem was found, 0 otherwise */
204int sensors_init_sysfs(void)
205{
206        struct stat statbuf;
207
208        /* libsysfs will return success even if sysfs is not mounted,
209           so we have to double-check */
210        if (sysfs_get_mnt_path(sensors_sysfs_mount, NAME_MAX)
211         || stat(sensors_sysfs_mount, &statbuf) < 0
212         || statbuf.st_nlink <= 2)      /* Empty directory */
213                return 0;
214
215        return 1;
216}
217
218/* returns: 0 if successful, !0 otherwise */
219static int sensors_read_one_sysfs_chip(struct sysfs_device *dev)
220{
221        int domain, bus, slot, fn;
222        int err = -SENSORS_ERR_PARSE;
223        struct sysfs_attribute *attr, *bus_attr;
224        char bus_path[SYSFS_PATH_MAX];
225        sensors_chip_features entry;
226
227        /* ignore any device without name attribute */
228        if (!(attr = sysfs_get_device_attr(dev, "name")))
229                return 0;
230
231        /* NB: attr->value[attr->len-1] == '\n'; chop that off */
232        entry.chip.prefix = strndup(attr->value, attr->len - 1);
233        if (!entry.chip.prefix)
234                sensors_fatal_error(__FUNCTION__, "out of memory");
235
236        entry.chip.path = strdup(dev->path);
237        if (!entry.chip.path)
238                sensors_fatal_error(__FUNCTION__, "out of memory");
239
240        if (sscanf(dev->name, "%hd-%x", &entry.chip.bus.nr, &entry.chip.addr) == 2) {
241                /* find out if legacy ISA or not */
242                if (entry.chip.bus.nr == 9191) {
243                        entry.chip.bus.type = SENSORS_BUS_TYPE_ISA;
244                        entry.chip.bus.nr = 0;
245                } else {
246                        entry.chip.bus.type = SENSORS_BUS_TYPE_I2C;
247                        snprintf(bus_path, sizeof(bus_path),
248                                "%s/class/i2c-adapter/i2c-%d/device/name",
249                                sensors_sysfs_mount, entry.chip.bus.nr);
250
251                        if ((bus_attr = sysfs_open_attribute(bus_path))) {
252                                if (sysfs_read_attribute(bus_attr)) {
253                                        sysfs_close_attribute(bus_attr);
254                                        goto exit_free;
255                                }
256
257                                if (bus_attr->value
258                                 && !strncmp(bus_attr->value, "ISA ", 4)) {
259                                        entry.chip.bus.type = SENSORS_BUS_TYPE_ISA;
260                                        entry.chip.bus.nr = 0;
261                                }
262
263                                sysfs_close_attribute(bus_attr);
264                        }
265                }
266        } else if (sscanf(dev->name, "spi%hd.%d", &entry.chip.bus.nr,
267                          &entry.chip.addr) == 2) {
268                /* SPI */
269                entry.chip.bus.type = SENSORS_BUS_TYPE_SPI;
270        } else if (sscanf(dev->name, "%*[a-z0-9_].%d", &entry.chip.addr) == 1) {
271                /* must be new ISA (platform driver) */
272                entry.chip.bus.type = SENSORS_BUS_TYPE_ISA;
273                entry.chip.bus.nr = 0;
274        } else if (sscanf(dev->name, "%x:%x:%x.%x", &domain, &bus, &slot, &fn) == 4) {
275                /* PCI */
276                entry.chip.addr = (domain << 16) + (bus << 8) + (slot << 3) + fn;
277                entry.chip.bus.type = SENSORS_BUS_TYPE_PCI;
278                entry.chip.bus.nr = 0;
279        } else
280                goto exit_free;
281
282        if (sensors_read_dynamic_chip(&entry, dev) < 0)
283                goto exit_free;
284        if (!entry.feature) { /* No feature, discard chip */
285                err = 0;
286                goto exit_free;
287        }
288        sensors_add_proc_chips(&entry);
289
290        return 0;
291
292exit_free:
293        free(entry.chip.prefix);
294        free(entry.chip.path);
295        return err;
296}
297
298/* returns 0 if successful, !0 otherwise */
299static int sensors_read_sysfs_chips_compat(void)
300{
301        struct sysfs_bus *bus;
302        struct dlist *devs;
303        struct sysfs_device *dev;
304        int ret = 0;
305
306        if (!(bus = sysfs_open_bus("i2c"))) {
307                if (errno && errno != ENOENT)
308                        ret = -SENSORS_ERR_PROC;
309                goto exit0;
310        }
311
312        if (!(devs = sysfs_get_bus_devices(bus))) {
313                if (errno && errno != ENOENT)
314                        ret = -SENSORS_ERR_PROC;
315                goto exit1;
316        }
317
318        dlist_for_each_data(devs, dev, struct sysfs_device)
319                if ((ret = sensors_read_one_sysfs_chip(dev)))
320                        goto exit1;
321
322exit1:
323        /* this frees bus and devs */
324        sysfs_close_bus(bus);
325
326exit0:
327        return ret;
328}
329
330/* returns 0 if successful, !0 otherwise */
331int sensors_read_sysfs_chips(void)
332{
333        struct sysfs_class *cls;
334        struct dlist *clsdevs;
335        struct sysfs_class_device *clsdev;
336        int ret = 0;
337
338        if (!(cls = sysfs_open_class("hwmon"))) {
339                /* compatibility function for kernel 2.6.n where n <= 13 */
340                return sensors_read_sysfs_chips_compat();
341        }
342
343        if (!(clsdevs = sysfs_get_class_devices(cls))) {
344                if (errno && errno != ENOENT)
345                        ret = -SENSORS_ERR_PROC;
346                goto exit;
347        }
348
349        dlist_for_each_data(clsdevs, clsdev, struct sysfs_class_device) {
350                struct sysfs_device *dev;
351                if (!(dev = sysfs_get_classdev_device(clsdev))) {
352                        ret = -SENSORS_ERR_PROC;
353                        goto exit;
354                }
355                if ((ret = sensors_read_one_sysfs_chip(dev)))
356                        goto exit;
357        }
358
359exit:
360        /* this frees cls and clsdevs */
361        sysfs_close_class(cls);
362        return ret;
363}
364
365/* returns 0 if successful, !0 otherwise */
366int sensors_read_sysfs_bus(void)
367{
368        struct sysfs_class *cls;
369        struct dlist *clsdevs;
370        struct sysfs_class_device *clsdev;
371        sensors_bus entry;
372        int ret = 0;
373
374        if (!(cls = sysfs_open_class("i2c-adapter"))) {
375                if (errno && errno != ENOENT)
376                        ret = -SENSORS_ERR_PROC;
377                goto exit0;
378        }
379
380        if (!(clsdevs = sysfs_get_class_devices(cls))) {
381                if (errno && errno != ENOENT)
382                        ret = -SENSORS_ERR_PROC;
383                goto exit1;
384        }
385
386        dlist_for_each_data(clsdevs, clsdev, struct sysfs_class_device) {
387                struct sysfs_device *dev;
388                struct sysfs_attribute *attr;
389
390                /* Get the adapter name from the classdev "name" attribute
391                 * (Linux 2.6.20 and later). If it fails, fall back to
392                 * the device "name" attribute (for older kernels). */
393                if (!(attr = sysfs_get_classdev_attr(clsdev, "name"))
394                 && !((dev = sysfs_get_classdev_device(clsdev)) &&
395                      (attr = sysfs_get_device_attr(dev, "name"))))
396                        continue;
397
398                if (sscanf(clsdev->name, "i2c-%hd", &entry.bus.nr) != 1 ||
399                    entry.bus.nr == 9191) /* legacy ISA */
400                        continue;
401                entry.bus.type = SENSORS_BUS_TYPE_I2C;
402
403                /* NB: attr->value[attr->len-1] == '\n'; chop that off */
404                entry.adapter = strndup(attr->value, attr->len - 1);
405                if (!entry.adapter)
406                        sensors_fatal_error(__FUNCTION__, "out of memory");
407
408                sensors_add_proc_bus(&entry);
409        }
410
411exit1:
412        /* this frees *cls _and_ *clsdevs */
413        sysfs_close_class(cls);
414
415exit0:
416        return ret;
417}
418
419int sensors_read_sysfs_attr(const sensors_chip_name *name, int feature,
420                            double *value)
421{
422        const sensors_chip_feature *the_feature;
423        int mag;
424        char n[NAME_MAX];
425        FILE *f;
426        const char *suffix = "";
427
428        if (!(the_feature = sensors_lookup_feature_nr(name, feature)))
429                return -SENSORS_ERR_NO_ENTRY;
430
431        /* REVISIT: this is a ugly hack */
432        if (the_feature->data.type == SENSORS_FEATURE_IN
433         || the_feature->data.type == SENSORS_FEATURE_FAN
434         || the_feature->data.type == SENSORS_FEATURE_TEMP)
435                suffix = "_input";
436
437        snprintf(n, NAME_MAX, "%s/%s%s", name->path, the_feature->data.name,
438                 suffix);
439        if ((f = fopen(n, "r"))) {
440                int res = fscanf(f, "%lf", value);
441                fclose(f);
442                if (res != 1)
443                        return -SENSORS_ERR_PROC;
444                for (mag = the_feature->scaling; mag > 0; mag --)
445                        *value /= 10.0;
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        int mag;
457        char n[NAME_MAX];
458        FILE *f;
459        const char *suffix = "";
460
461        if (!(the_feature = sensors_lookup_feature_nr(name, feature)))
462                return -SENSORS_ERR_NO_ENTRY;
463
464        /* REVISIT: this is a ugly hack */
465        if (the_feature->data.type == SENSORS_FEATURE_IN
466         || the_feature->data.type == SENSORS_FEATURE_FAN
467         || the_feature->data.type == SENSORS_FEATURE_TEMP)
468                suffix = "_input";
469
470        snprintf(n, NAME_MAX, "%s/%s%s", name->path, the_feature->data.name,
471                 suffix);
472        if ((f = fopen(n, "w"))) {
473                for (mag = the_feature->scaling; mag > 0; mag --)
474                        value *= 10.0;
475                fprintf(f, "%d", (int) value);
476                fclose(f);
477        } else
478                return -SENSORS_ERR_PROC;
479
480        return 0;
481}
Note: See TracBrowser for help on using the browser.