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

Revision 4674, 11.7 KB (checked in by khali, 7 years ago)

Don't handle the isa bus in sensors_parse_i2cbus_name(). We really
don't need to, as there is a single ISA bus, there's no need for
substituting anything.

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