root/lm-sensors/trunk/lib/proc.c @ 2654

Revision 2654, 17.4 KB (checked in by khali, 9 years ago)

Allow an alternate sysfs file name for chip features. This is

needed to provide backward compatibility when changes are made
to the sysfs interface (policy change or driver fix).
The first item for which this is needed is VID files. The name
we chose, in0_ref, is bad (because motherboard manufacturers can
use any input for VCore, regardless of the recommendations.
Thus, the new name cpu0_vid is better. Drivers will be updated
later.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
Line 
1/*
2    proc.c - Part of libsensors, a Linux library for reading sensor data.
3    Copyright (c) 1998, 1999  Frodo Looijaard <frodol@dds.nl>
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/* for open() */
21#include <sys/types.h>
22#include <sys/stat.h>
23#include <fcntl.h>
24
25#include <stddef.h>
26#include <unistd.h>
27#include <stdio.h>
28#include <string.h>
29#include <sys/sysctl.h>
30#include "kernel/include/sensors.h"
31#include "data.h"
32#include "error.h"
33#include "access.h"
34#include "general.h"
35#include <limits.h>
36#include <dirent.h>
37
38/* OK, this proves one thing: if there are too many chips detected, we get in
39   trouble. The limit is around 4096/sizeof(struct sensors_chip_data), which
40   works out to about 100 entries right now. That seems sensible enough,
41   but if we ever get at the point where more chips can be detected, we must
42   enlarge buf, and check that sysctl can handle larger buffers. */
43
44#define BUF_LEN 4096
45
46static char buf[BUF_LEN];
47
48sensors_proc_chips_entry *sensors_proc_chips;
49int sensors_proc_chips_count, sensors_proc_chips_max;
50int sensors_sys_chips_count, sensors_sys_chips_max;
51
52sensors_bus *sensors_sys_bus;
53int sensors_sys_bus_count, sensors_sys_bus_max;
54sensors_bus *sensors_proc_bus;
55int sensors_proc_bus_count, sensors_proc_bus_max;
56
57static int sensors_get_chip_id(sensors_chip_name name);
58
59int foundsysfs=0;
60char sysfsmount[NAME_MAX];
61
62#define add_proc_chips(el) sensors_add_array_el(el,\
63                                       &sensors_proc_chips,\
64                                       &sensors_proc_chips_count,\
65                                       &sensors_proc_chips_max,\
66                                       sizeof(struct sensors_proc_chips_entry))
67
68#define add_proc_bus(el) sensors_add_array_el(el,\
69                                       &sensors_proc_bus,\
70                                       &sensors_proc_bus_count,\
71                                       &sensors_proc_bus_max,\
72                                       sizeof(struct sensors_bus))
73
74int getsysname(const sensors_chip_feature *feature, char *sysname,
75        int *sysmag, char *altsysname);
76
77/* This reads /proc/sys/dev/sensors/chips into memory */
78int sensors_read_proc_chips(void)
79{
80        struct dirent *de;
81        DIR *dir;
82        FILE *f;
83        char dev[NAME_MAX], fstype[NAME_MAX], sysfs[NAME_MAX], n[NAME_MAX];
84        char dirname[NAME_MAX];
85        int res;
86
87        int name[3] = { CTL_DEV, DEV_SENSORS, SENSORS_CHIPS };
88        int buflen = BUF_LEN;
89        char *bufptr = buf;
90        sensors_proc_chips_entry entry;
91        int lineno;
92
93        /* First figure out where sysfs was mounted */
94        if ((f = fopen("/proc/mounts", "r")) == NULL)
95                goto proc;
96        while (fgets(n, NAME_MAX, f)) {
97                sscanf(n, "%[^ ] %[^ ] %[^ ] %*s\n", dev, sysfs, fstype);
98                if (strcasecmp(fstype, "sysfs") == 0) {
99                        foundsysfs++;
100                        break;
101                }
102        }
103        fclose(f);
104        if (! foundsysfs)
105                goto proc;
106        strcpy(sysfsmount, sysfs);
107        strcat(sysfs, "/bus/i2c/devices");
108
109        /* Then read from it */
110        dir = opendir(sysfs);
111        if (! dir)
112                goto proc;
113
114        while ((de = readdir(dir)) != NULL) {
115                if (!strcmp(de->d_name, "."))
116                        continue;
117                if (!strcmp(de->d_name, ".."))
118                        continue;
119/*
120                if (de->d_type != DT_DIR && de->d_type != DT_LNK)
121                        continue;
122*/
123
124                sprintf(n, "%s/%s", sysfs, de->d_name);
125                strcpy(dirname, n);
126                strcat(n, "/name");
127
128                if ((f = fopen(n, "r")) != NULL) {
129                        char x[81];
130                        int len = 0;
131                        if (!fscanf(f, "%80[a-zA-z0-9_ ]%n", x, &len)) {
132                                fclose(f);
133                                continue;
134                        }
135                        fclose(f);
136                        if (len >= 10 && !strcmp(x+len-10, " subclient"))
137                                continue;
138                       
139                        /* HACK */ strcat(x, "-*");
140                        if ((res = sensors_parse_chip_name(x, &entry.name))) {
141                                char    em[NAME_MAX + 20];
142                                strcpy(em, "Parsing ");
143                                strcat(em, n);
144                                sensors_parse_error(em, 0);
145                                return res;
146                        }
147                        entry.name.busname = strdup(dirname);
148                        sscanf(de->d_name, "%d-%x", &entry.name.bus, &entry.name.addr);
149                        /* find out if ISA or not */
150                        sprintf(n, "%s/class/i2c-adapter/i2c-%d/device/name",
151                                sysfsmount, entry.name.bus);
152                        if ((f = fopen(n, "r")) != NULL) {
153                                fgets(x, 5, f);
154                                fclose(f);
155                                if(!strncmp(x, "ISA ", 4))
156                                        entry.name.bus = SENSORS_CHIP_NAME_BUS_ISA;
157                        }
158                        add_proc_chips(&entry);
159                }
160        }
161        closedir(dir);
162        return 0;
163
164proc:
165
166  if (sysctl(name, 3, bufptr, &buflen, NULL, 0))
167    return -SENSORS_ERR_PROC;
168
169  lineno = 1;
170  while (buflen >= sizeof(struct i2c_chips_data)) {
171    if ((res = 
172          sensors_parse_chip_name(((struct i2c_chips_data *) bufptr)->name, 
173                                   &entry.name))) {
174      sensors_parse_error("Parsing /proc/sys/dev/sensors/chips",lineno);
175      return res;
176    }
177    entry.sysctl = ((struct i2c_chips_data *) bufptr)->sysctl_id;
178    add_proc_chips(&entry);
179    bufptr += sizeof(struct i2c_chips_data);
180    buflen -= sizeof(struct i2c_chips_data);
181    lineno++;
182  }
183  return 0;
184}
185
186int sensors_read_proc_bus(void)
187{
188        struct dirent *de;
189        DIR *dir;
190        FILE *f;
191        char line[255];
192        char *border;
193        sensors_bus entry;
194        int lineno;
195        char sysfs[NAME_MAX], n[NAME_MAX];
196        char dirname[NAME_MAX];
197
198        if(foundsysfs) {
199                strcpy(sysfs, sysfsmount);
200                strcat(sysfs, "/class/i2c-adapter");
201                /* Then read from it */
202                dir = opendir(sysfs);
203                if (! dir)
204                        goto proc;
205
206                while ((de = readdir(dir)) != NULL) {
207                        if (!strcmp(de->d_name, "."))
208                                continue;
209                        if (!strcmp(de->d_name, ".."))
210                                continue;
211
212                        strcpy(n, sysfs);
213                        strcat(n, "/");
214                        strcat(n, de->d_name);
215                        strcpy(dirname, n);
216                        strcat(n, "/device/name");
217
218                        if ((f = fopen(n, "r")) != NULL) {
219                                char    x[120];
220                                fgets(x, 120, f);
221                                fclose(f);
222                                if((border = index(x, '\n')) != NULL)
223                                        *border = 0;
224                                entry.adapter=strdup(x);
225                                if(!strncmp(x, "ISA ", 4)) {
226                                        entry.number = SENSORS_CHIP_NAME_BUS_ISA;
227                                        entry.algorithm = strdup("ISA bus algorithm");
228                                } else if(!sscanf(de->d_name, "i2c-%d", &entry.number)) {
229                                        entry.number = SENSORS_CHIP_NAME_BUS_DUMMY;
230                                        entry.algorithm = strdup("Dummy bus algorithm");
231                                } else
232                                        entry.algorithm = strdup("Unavailable from sysfs");
233                                if (entry.algorithm == NULL)
234                                        goto FAT_ERROR_SYS;
235                                add_proc_bus(&entry);
236                        }
237                }
238                closedir(dir);
239                return 0;
240FAT_ERROR_SYS:
241                sensors_fatal_error("sensors_read_proc_bus", "Allocating entry");
242                closedir(dir);
243                return -SENSORS_ERR_PROC;
244        }
245
246proc:
247
248  f = fopen("/proc/bus/i2c","r");
249  if (!f)
250    return -SENSORS_ERR_PROC;
251  lineno=1;
252  while (fgets(line,255,f)) {
253    if (strlen(line) > 0)
254      line[strlen(line)-1] = '\0';
255    if (! (border = rindex(line,'\t')))
256      goto ERROR;
257    if (! (entry.algorithm = strdup(border+1)))
258      goto FAT_ERROR;
259    *border='\0';
260    if (! (border = rindex(line,'\t')))
261      goto ERROR;
262    if (! (entry.adapter = strdup(border + 1)))
263      goto FAT_ERROR;
264    *border='\0';
265    if (! (border = rindex(line,'\t')))
266      goto ERROR;
267    *border='\0';
268    if (strncmp(line,"i2c-",4))
269      goto ERROR;
270    if (sensors_parse_i2cbus_name(line,&entry.number))
271      goto ERROR;
272    sensors_strip_of_spaces(entry.algorithm);
273    sensors_strip_of_spaces(entry.adapter);
274    add_proc_bus(&entry);
275    lineno++;
276  }
277  fclose(f);
278  return 0;
279FAT_ERROR:
280  sensors_fatal_error("sensors_read_proc_bus","Allocating entry");
281ERROR:
282  sensors_parse_error("Parsing /proc/bus/i2c",lineno);
283  fclose(f);
284  return -SENSORS_ERR_PROC;
285}
286   
287
288/* This returns the first detected chip which matches the name */
289int sensors_get_chip_id(sensors_chip_name name)
290{
291  int i;
292  for (i = 0; i < sensors_proc_chips_count; i++)
293    if (sensors_match_chip(name, sensors_proc_chips[i].name))
294      return sensors_proc_chips[i].sysctl;
295  return -SENSORS_ERR_NO_ENTRY;
296}
297 
298/* This reads a feature /proc or /sys file.
299   Sysfs uses a one-value-per file system...
300   except for eeprom, which puts the entire eeprom into one file.
301*/
302int sensors_read_proc(sensors_chip_name name, int feature, double *value)
303{
304        int sysctl_name[4] = { CTL_DEV, DEV_SENSORS };
305        const sensors_chip_feature *the_feature;
306        int buflen = BUF_LEN;
307        int mag, eepromoffset, fd, ret=0;
308
309        if(!foundsysfs)
310                if ((sysctl_name[2] = sensors_get_chip_id(name)) < 0)
311                        return sysctl_name[2];
312        if (! (the_feature = sensors_lookup_feature_nr(name.prefix,feature)))
313                return -SENSORS_ERR_NO_ENTRY;
314        if(foundsysfs) {
315                char n[NAME_MAX], altn[NAME_MAX];
316                FILE *f;
317                strcpy(n, name.busname);
318                strcat(n, "/");
319                /* total hack for eeprom */
320                if (! strcmp(name.prefix, "eeprom")){
321                        strcat(n, "eeprom");
322                        /* we use unbuffered I/O to benefit from eeprom driver
323                           optimization */
324                        if ((fd = open(n, O_RDONLY)) >= 0) {
325                                eepromoffset =
326                                  (the_feature->offset / sizeof(long))  +
327                                  (16 * (the_feature->sysctl - EEPROM_SYSCTL1));
328                                if (lseek(fd, eepromoffset, SEEK_SET) < 0
329                                 || read(fd, &ret, 1) != 1) {
330                                        close(fd);
331                                        return -SENSORS_ERR_PROC;
332                                }
333                                close(fd);
334                                *value = ret;
335                                return 0;
336                        } else
337                                return -SENSORS_ERR_PROC;
338                } else {
339                        strcpy(altn, n);
340                        /* use rindex to append sysname to n */
341                        getsysname(the_feature, rindex(n, '\0'), &mag, rindex(altn, '\0'));
342                        if ((f = fopen(n, "r")) != NULL
343                         || (f = fopen(altn, "r")) != NULL) {
344                                fscanf(f, "%lf", value);
345                                fclose(f);
346                                for (; mag > 0; mag --)
347                                        *value /= 10.0;
348                //              fprintf(stderr, "Feature %s value %lf scale %d offset %d\n",
349                //                      the_feature->name, *value,
350                //                      the_feature->scaling, the_feature->offset);
351                                return 0;
352                        } else
353                                return -SENSORS_ERR_PROC;
354                }
355        } else {
356                sysctl_name[3] = the_feature->sysctl;
357                if (sysctl(sysctl_name, 4, buf, &buflen, NULL, 0))
358                        return -SENSORS_ERR_PROC;
359                *value = *((long *) (buf + the_feature->offset));
360                for (mag = the_feature->scaling; mag > 0; mag --)
361                        *value /= 10.0;
362                for (; mag < 0; mag ++)
363                        *value *= 10.0;
364        }
365        return 0;
366}
367 
368int sensors_write_proc(sensors_chip_name name, int feature, double value)
369{
370        int sysctl_name[4] = { CTL_DEV, DEV_SENSORS };
371        const sensors_chip_feature *the_feature;
372        int buflen = BUF_LEN;
373        int mag;
374 
375        if(!foundsysfs)
376                if ((sysctl_name[2] = sensors_get_chip_id(name)) < 0)
377                        return sysctl_name[2];
378        if (! (the_feature = sensors_lookup_feature_nr(name.prefix,feature)))
379                return -SENSORS_ERR_NO_ENTRY;
380        if(foundsysfs) {
381                char n[NAME_MAX], altn[NAME_MAX];
382                FILE *f;
383                strcpy(n, name.busname);
384                strcat(n, "/");
385                strcpy(altn, n);
386                /* use rindex to append sysname to n */
387                getsysname(the_feature, rindex(n, '\0'), &mag, rindex(altn, '\0'));
388                if ((f = fopen(n, "w")) != NULL
389                 || (f = fopen(altn, "w")) != NULL) {
390                        for (; mag > 0; mag --)
391                                value *= 10.0;
392                        fprintf(f, "%d", (int) value);
393                        fclose(f);
394                } else
395                        return -SENSORS_ERR_PROC;
396        } else {
397                sysctl_name[3] = the_feature->sysctl;
398                if (sysctl(sysctl_name, 4, buf, &buflen, NULL, 0))
399                        return -SENSORS_ERR_PROC;
400                /* The following line is known to solve random problems, still it
401                   can't be considered a definitive solution...
402                if (sysctl_name[0] != CTL_DEV) { sysctl_name[0] = CTL_DEV ; } */
403                for (mag = the_feature->scaling; mag > 0; mag --)
404                        value *= 10.0;
405                for (; mag < 0; mag ++)
406                        value /= 10.0;
407                * ((long *) (buf + the_feature->offset)) = (long) value;
408                buflen = the_feature->offset + sizeof(long);
409#ifdef DEBUG
410                /* The following get* calls don't do anything, they are here
411                   for debugging purposes only. Strace will show the
412                   returned values. */
413                getuid(); geteuid();
414                getgid(); getegid();
415#endif
416                if (sysctl(sysctl_name, 4, NULL, 0, buf, buflen))
417                        return -SENSORS_ERR_PROC;
418        }
419        return 0;
420}
421
422#define CURRMAG 3
423#define FANMAG 0
424#define INMAG 3
425#define TEMPMAG 3
426
427/*
428        Returns the sysfs name and magnitude for a given feature.
429        First looks for a sysfs name and magnitude in the feature structure.
430        These should be added in chips.c for all non-standard feature names.
431        If that fails, converts common /proc feature names
432        to their sysfs equivalent, and uses common sysfs magnitude.
433        Common magnitudes are #defined above.
434        Common conversions are as follows:
435                fan%d_min -> fan%d_min (for magnitude)
436                fan%d_state -> fan%d_status
437                fan%d -> fan_input%d
438                pwm%d -> fan%d_pwm
439                pwm%d_enable -> fan%d_pwm_enable
440                in%d_max -> in%d_max (for magnitude)
441                in%d_min -> in%d_min (for magnitude)
442                in%d -> in%d_input
443                vin%d_max -> in%d_max
444                vin%d_min -> in%d_min
445                vin%d -> in_input%d
446                temp%d_over -> temp%d_max
447                temp%d_hyst -> temp%d_max_hyst
448                temp%d_max -> temp%d_max (for magnitude)
449                temp%d_high -> temp%d_max
450                temp%d_min -> temp%d_min (for magnitude)
451                temp%d_low -> temp%d_min
452                temp%d_state -> temp%d_status
453                temp%d -> temp%d_input
454                sensor%d -> temp%d_type
455        AND all conversions listed in the matches[] structure below.
456
457        If that fails, returns old /proc feature name and magnitude.
458
459        References: doc/developers/proc in the lm_sensors package;
460                    Documentation/i2c/sysfs_interface in the kernel
461*/
462int getsysname(const sensors_chip_feature *feature, char *sysname,
463        int *sysmag, char *altsysname)
464{
465        const char * name = feature->name;
466        char last;
467        char check; /* used to verify end of string */
468        int num;
469       
470        struct match {
471                const char * name, * sysname;
472                const int sysmag;
473                const char * altsysname;
474        };
475
476        struct match *m;
477
478        struct match matches[] = {
479                { "beeps", "beep_mask", 0 },
480                { "pwm", "fan1_pwm", 0 },
481                { "vid", "cpu0_vid", INMAG, "in0_ref" },
482                { "remote_temp", "temp2_input", TEMPMAG },
483                { "remote_temp_hyst", "temp2_max_hyst", TEMPMAG },
484                { "remote_temp_low", "temp2_min", TEMPMAG },
485                { "remote_temp_over", "temp2_max", TEMPMAG },
486                { "temp", "temp1_input", TEMPMAG },
487                { "temp_hyst", "temp1_max_hyst", TEMPMAG },
488                { "temp_low", "temp1_min", TEMPMAG },
489                { "temp_over", "temp1_max", TEMPMAG },
490                { NULL, NULL }
491        };
492
493
494/* default to a non-existent alternate name (should rarely be tried) */
495        strcpy(altsysname, "_");
496
497/* use override in feature structure if present */
498        if(feature->sysname != NULL) {
499                strcpy(sysname, feature->sysname);
500                if(feature->sysscaling)
501                        *sysmag = feature->sysscaling;
502                else
503                        *sysmag = feature->scaling;
504                return 0;
505        }
506
507/* check for constant mappings */
508        for(m = matches; m->name != NULL; m++) {
509                if(!strcmp(m->name, name)) {
510                        strcpy(sysname, m->sysname);
511                        if (m->altsysname != NULL)
512                                strcpy(altsysname, m->altsysname);
513                        *sysmag = m->sysmag;
514                        return 0;
515                }
516        }
517
518/* convert common /proc names to common sysfs names */
519        if(sscanf(name, "fan%d_mi%c%c", &num, &last, &check) == 2 && last == 'n') {
520                strcpy(sysname, name);
521                *sysmag = FANMAG;
522                return 0;
523        }
524        if(sscanf(name, "fan%d_stat%c%c", &num, &last, &check) == 2 && last == 'e') {
525                sprintf(sysname, "fan%d_status", num);
526                *sysmag = 0;
527                return 0;
528        }
529        if(sscanf(name, "fan%d%c", &num, &check) == 1) {
530                sprintf(sysname, "fan%d_input", num);
531                *sysmag = FANMAG;
532                return 0;
533        }
534        if(sscanf(name, "pwm%d%c", &num, &check) == 1) {
535                sprintf(sysname, "fan%d_pwm", num);
536                *sysmag = 0;
537                return 0;
538        }
539        if(sscanf(name, "pwm%d_enabl%c%c", &num, &last, &check) == 2 && last == 'e') {
540                sprintf(sysname, "fan%d_pwm_enable", num);
541                *sysmag = 0;
542                return 0;
543        }
544
545        if((sscanf(name, "in%d_mi%c%c", &num, &last, &check) == 2 && last == 'n')
546        || (sscanf(name, "in%d_ma%c%c", &num, &last, &check) == 2 && last == 'x')) {
547                strcpy(sysname, name);
548                *sysmag = INMAG;
549                return 0;
550        }
551        if((sscanf(name, "in%d%c", &num, &check) == 1)
552        || (sscanf(name, "vin%d%c", &num, &check) == 1)) {
553                sprintf(sysname, "in%d_input", num);
554                *sysmag = INMAG;
555                return 0;
556        }
557        if(sscanf(name, "vin%d_mi%c%c", &num, &last, &check) == 2 && last == 'n') {
558                sprintf(sysname, "in%d_min", num);
559                *sysmag = INMAG;
560                return 0;
561        }
562        if(sscanf(name, "vin%d_ma%c%c", &num, &last, &check) == 2 && last == 'x') {
563                sprintf(sysname, "in%d_max", num);
564                *sysmag = INMAG;
565                return 0;
566        }
567
568        if(sscanf(name, "temp%d_hys%c%c", &num, &last, &check) == 2 && last == 't') {
569                sprintf(sysname, "temp%d_max_hyst", num);
570                *sysmag = TEMPMAG;
571                return 0;
572        }
573        if((sscanf(name, "temp%d_ove%c%c", &num, &last, &check) == 2 && last == 'r')
574        || (sscanf(name, "temp%d_ma%c%c", &num, &last, &check) == 2 && last == 'x')
575        || (sscanf(name, "temp%d_hig%c%c", &num, &last, &check) == 2 && last == 'h')) {
576                sprintf(sysname, "temp%d_max", num);
577                *sysmag = TEMPMAG;
578                return 0;
579        }
580        if((sscanf(name, "temp%d_mi%c%c", &num, &last, &check) == 2 && last == 'n')
581        || (sscanf(name, "temp%d_lo%c%c", &num, &last, &check) == 2 && last == 'w')) {
582                sprintf(sysname, "temp%d_min", num);
583                *sysmag = TEMPMAG;
584                return 0;
585        }
586        if(sscanf(name, "temp%d_stat%c%c", &num, &last, &check) == 2 && last == 'e') {
587                sprintf(sysname, "temp%d_status", num);
588                *sysmag = 0;
589                return 0;
590        }
591        if(sscanf(name, "temp%d%c", &num, &check) == 1) {
592                sprintf(sysname, "temp%d_input", num);
593                *sysmag = TEMPMAG;
594                return 0;
595        }
596        if(sscanf(name, "sensor%d%c", &num, &check) == 1) {
597                sprintf(sysname, "temp%d_type", num);
598                *sysmag = 0;
599                return 0;
600        }
601
602/* bmcsensors only, not yet in kernel */
603/*
604        if((sscanf(name, "curr%d_mi%c%c", &num, &last, &check) == 2 && last == 'n')
605        || (sscanf(name, "curr%d_ma%c%c", &num, &last, &check) == 2 && last == 'x')) {
606                strcpy(sysname, name);
607                *sysmag = CURRMAG;
608                return 0;
609        }
610        if(sscanf(name, "curr%d%c", &num, &check) == 1) {
611                sprintf(sysname, "curr%d_input", num);
612                *sysmag = CURRMAG;
613                return 0;
614        }
615*/
616
617/* give up, use old name (probably won't work though...) */
618/* known to be the same:
619        "alarms", "beep_enable", "vrm", "fan%d_div"
620*/
621        strcpy(sysname, name);
622        *sysmag = feature->scaling;
623        return 0;
624}
Note: See TracBrowser for help on using the browser.