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

Revision 4744, 11.9 KB (checked in by khali, 7 years ago)

Start numbering the features at 0, not 1. There's nothing wrong with
having a feature number 0, and this makes the code slightly simpler.

  • 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                        feature.data.compute_mapping = SENSORS_NO_MAPPING;
146                } else if (type & 0x10) {
147                        /* sub feature without compute mapping */
148                        feature.data.mapping = i - i % MAX_SUB_FEATURES;
149                        feature.data.compute_mapping = SENSORS_NO_MAPPING;
150                } else {
151                        feature.data.mapping = i - i % MAX_SUB_FEATURES;
152                        feature.data.compute_mapping = feature.data.mapping;
153                }
154
155                if (attr->method & SYSFS_METHOD_SHOW)
156                        feature.data.mode |= SENSORS_MODE_R;
157                if (attr->method & SYSFS_METHOD_STORE)
158                        feature.data.mode |= SENSORS_MODE_W;
159
160                feature.scaling = get_type_scaling(type);
161
162                features[i] = feature;
163                fnum++;
164        }
165
166        if (fnum == 1) { /* No feature */
167                chip->feature = NULL;
168                goto exit_free;
169        }
170
171        dyn_features = calloc(fnum, sizeof(sensors_chip_feature));
172        if (dyn_features == NULL) {
173                sensors_fatal_error(__FUNCTION__, "Out of memory");
174        }
175
176        fnum = 0;
177        for (i = 0; i < ALL_POSSIBLE_FEATURES; i++) {
178                if (features[i].data.name) {
179                        dyn_features[fnum] = features[i];
180                        fnum++;
181                }
182        }
183
184        chip->feature = dyn_features;
185
186exit_free:
187        free(features);
188        return 0;
189}
190
191/* returns !0 if sysfs filesystem was found, 0 otherwise */
192int sensors_init_sysfs(void)
193{
194        struct stat statbuf;
195
196        /* libsysfs will return success even if sysfs is not mounted,
197           so we have to double-check */
198        if (sysfs_get_mnt_path(sensors_sysfs_mount, NAME_MAX)
199         || stat(sensors_sysfs_mount, &statbuf) < 0
200         || statbuf.st_nlink <= 2)      /* Empty directory */
201                return 0;
202
203        return 1;
204}
205
206/* returns: 0 if successful, !0 otherwise */
207static int sensors_read_one_sysfs_chip(struct sysfs_device *dev)
208{
209        int domain, bus, slot, fn;
210        int err = -SENSORS_ERR_PARSE;
211        struct sysfs_attribute *attr, *bus_attr;
212        char bus_path[SYSFS_PATH_MAX];
213        sensors_chip_features entry;
214
215        /* ignore any device without name attribute */
216        if (!(attr = sysfs_get_device_attr(dev, "name")))
217                return 0;
218
219        /* NB: attr->value[attr->len-1] == '\n'; chop that off */
220        entry.chip.prefix = strndup(attr->value, attr->len - 1);
221        if (!entry.chip.prefix)
222                sensors_fatal_error(__FUNCTION__, "out of memory");
223
224        entry.chip.path = strdup(dev->path);
225        if (!entry.chip.path)
226                sensors_fatal_error(__FUNCTION__, "out of memory");
227
228        if (sscanf(dev->name, "%hd-%x", &entry.chip.bus.nr, &entry.chip.addr) == 2) {
229                /* find out if legacy ISA or not */
230                if (entry.chip.bus.nr == 9191) {
231                        entry.chip.bus.type = SENSORS_BUS_TYPE_ISA;
232                        entry.chip.bus.nr = 0;
233                } else {
234                        entry.chip.bus.type = SENSORS_BUS_TYPE_I2C;
235                        snprintf(bus_path, sizeof(bus_path),
236                                "%s/class/i2c-adapter/i2c-%d/device/name",
237                                sensors_sysfs_mount, entry.chip.bus.nr);
238
239                        if ((bus_attr = sysfs_open_attribute(bus_path))) {
240                                if (sysfs_read_attribute(bus_attr)) {
241                                        sysfs_close_attribute(bus_attr);
242                                        goto exit_free;
243                                }
244
245                                if (bus_attr->value
246                                 && !strncmp(bus_attr->value, "ISA ", 4)) {
247                                        entry.chip.bus.type = SENSORS_BUS_TYPE_ISA;
248                                        entry.chip.bus.nr = 0;
249                                }
250
251                                sysfs_close_attribute(bus_attr);
252                        }
253                }
254        } else if (sscanf(dev->name, "spi%hd.%d", &entry.chip.bus.nr,
255                          &entry.chip.addr) == 2) {
256                /* SPI */
257                entry.chip.bus.type = SENSORS_BUS_TYPE_SPI;
258        } else if (sscanf(dev->name, "%*[a-z0-9_].%d", &entry.chip.addr) == 1) {
259                /* must be new ISA (platform driver) */
260                entry.chip.bus.type = SENSORS_BUS_TYPE_ISA;
261                entry.chip.bus.nr = 0;
262        } else if (sscanf(dev->name, "%x:%x:%x.%x", &domain, &bus, &slot, &fn) == 4) {
263                /* PCI */
264                entry.chip.addr = (domain << 16) + (bus << 8) + (slot << 3) + fn;
265                entry.chip.bus.type = SENSORS_BUS_TYPE_PCI;
266                entry.chip.bus.nr = 0;
267        } else
268                goto exit_free;
269
270        if (sensors_read_dynamic_chip(&entry, dev) < 0)
271                goto exit_free;
272        if (!entry.feature) { /* No feature, discard chip */
273                err = 0;
274                goto exit_free;
275        }
276        sensors_add_proc_chips(&entry);
277
278        return 0;
279
280exit_free:
281        free(entry.chip.prefix);
282        free(entry.chip.path);
283        return err;
284}
285
286/* returns 0 if successful, !0 otherwise */
287static int sensors_read_sysfs_chips_compat(void)
288{
289        struct sysfs_bus *bus;
290        struct dlist *devs;
291        struct sysfs_device *dev;
292        int ret = 0;
293
294        if (!(bus = sysfs_open_bus("i2c"))) {
295                if (errno && errno != ENOENT)
296                        ret = -SENSORS_ERR_PROC;
297                goto exit0;
298        }
299
300        if (!(devs = sysfs_get_bus_devices(bus))) {
301                if (errno && errno != ENOENT)
302                        ret = -SENSORS_ERR_PROC;
303                goto exit1;
304        }
305
306        dlist_for_each_data(devs, dev, struct sysfs_device)
307                if ((ret = sensors_read_one_sysfs_chip(dev)))
308                        goto exit1;
309
310exit1:
311        /* this frees bus and devs */
312        sysfs_close_bus(bus);
313
314exit0:
315        return ret;
316}
317
318/* returns 0 if successful, !0 otherwise */
319int sensors_read_sysfs_chips(void)
320{
321        struct sysfs_class *cls;
322        struct dlist *clsdevs;
323        struct sysfs_class_device *clsdev;
324        int ret = 0;
325
326        if (!(cls = sysfs_open_class("hwmon"))) {
327                /* compatibility function for kernel 2.6.n where n <= 13 */
328                return sensors_read_sysfs_chips_compat();
329        }
330
331        if (!(clsdevs = sysfs_get_class_devices(cls))) {
332                if (errno && errno != ENOENT)
333                        ret = -SENSORS_ERR_PROC;
334                goto exit;
335        }
336
337        dlist_for_each_data(clsdevs, clsdev, struct sysfs_class_device) {
338                struct sysfs_device *dev;
339                if (!(dev = sysfs_get_classdev_device(clsdev))) {
340                        ret = -SENSORS_ERR_PROC;
341                        goto exit;
342                }
343                if ((ret = sensors_read_one_sysfs_chip(dev)))
344                        goto exit;
345        }
346
347exit:
348        /* this frees cls and clsdevs */
349        sysfs_close_class(cls);
350        return ret;
351}
352
353/* returns 0 if successful, !0 otherwise */
354int sensors_read_sysfs_bus(void)
355{
356        struct sysfs_class *cls;
357        struct dlist *clsdevs;
358        struct sysfs_class_device *clsdev;
359        sensors_bus entry;
360        int ret = 0;
361
362        if (!(cls = sysfs_open_class("i2c-adapter"))) {
363                if (errno && errno != ENOENT)
364                        ret = -SENSORS_ERR_PROC;
365                goto exit0;
366        }
367
368        if (!(clsdevs = sysfs_get_class_devices(cls))) {
369                if (errno && errno != ENOENT)
370                        ret = -SENSORS_ERR_PROC;
371                goto exit1;
372        }
373
374        dlist_for_each_data(clsdevs, clsdev, struct sysfs_class_device) {
375                struct sysfs_device *dev;
376                struct sysfs_attribute *attr;
377
378                /* Get the adapter name from the classdev "name" attribute
379                 * (Linux 2.6.20 and later). If it fails, fall back to
380                 * the device "name" attribute (for older kernels). */
381                if (!(attr = sysfs_get_classdev_attr(clsdev, "name"))
382                 && !((dev = sysfs_get_classdev_device(clsdev)) &&
383                      (attr = sysfs_get_device_attr(dev, "name"))))
384                        continue;
385
386                if (sscanf(clsdev->name, "i2c-%hd", &entry.bus.nr) != 1 ||
387                    entry.bus.nr == 9191) /* legacy ISA */
388                        continue;
389                entry.bus.type = SENSORS_BUS_TYPE_I2C;
390
391                /* NB: attr->value[attr->len-1] == '\n'; chop that off */
392                entry.adapter = strndup(attr->value, attr->len - 1);
393                if (!entry.adapter)
394                        sensors_fatal_error(__FUNCTION__, "out of memory");
395
396                sensors_add_proc_bus(&entry);
397        }
398
399exit1:
400        /* this frees *cls _and_ *clsdevs */
401        sysfs_close_class(cls);
402
403exit0:
404        return ret;
405}
406
407int sensors_read_sysfs_attr(const sensors_chip_name *name, int feature,
408                            double *value)
409{
410        const sensors_chip_feature *the_feature;
411        int mag;
412        char n[NAME_MAX];
413        FILE *f;
414        const char *suffix = "";
415
416        if (!(the_feature = sensors_lookup_feature_nr(name, feature)))
417                return -SENSORS_ERR_NO_ENTRY;
418
419        /* REVISIT: this is a ugly hack */
420        if (the_feature->data.type == SENSORS_FEATURE_IN
421         || the_feature->data.type == SENSORS_FEATURE_FAN
422         || the_feature->data.type == SENSORS_FEATURE_TEMP)
423                suffix = "_input";
424
425        snprintf(n, NAME_MAX, "%s/%s%s", name->path, the_feature->data.name,
426                 suffix);
427        if ((f = fopen(n, "r"))) {
428                int res = fscanf(f, "%lf", value);
429                fclose(f);
430                if (res != 1)
431                        return -SENSORS_ERR_PROC;
432                for (mag = the_feature->scaling; mag > 0; mag --)
433                        *value /= 10.0;
434        } else
435                return -SENSORS_ERR_PROC;
436
437        return 0;
438}
439
440int sensors_write_sysfs_attr(const sensors_chip_name *name, int feature,
441                             double value)
442{
443        const sensors_chip_feature *the_feature;
444        int mag;
445        char n[NAME_MAX];
446        FILE *f;
447        const char *suffix = "";
448
449        if (!(the_feature = sensors_lookup_feature_nr(name, feature)))
450                return -SENSORS_ERR_NO_ENTRY;
451
452        /* REVISIT: this is a ugly hack */
453        if (the_feature->data.type == SENSORS_FEATURE_IN
454         || the_feature->data.type == SENSORS_FEATURE_FAN
455         || the_feature->data.type == SENSORS_FEATURE_TEMP)
456                suffix = "_input";
457
458        snprintf(n, NAME_MAX, "%s/%s%s", name->path, the_feature->data.name,
459                 suffix);
460        if ((f = fopen(n, "w"))) {
461                for (mag = the_feature->scaling; mag > 0; mag --)
462                        value *= 10.0;
463                fprintf(f, "%d", (int) value);
464                fclose(f);
465        } else
466                return -SENSORS_ERR_PROC;
467
468        return 0;
469}
Note: See TracBrowser for help on using the browser.