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

Revision 2211, 16.5 KB (checked in by khali, 9 years ago)

Get rid of the lm90 hyst exception.

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