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

Revision 2426, 17.0 KB (checked in by khali, 9 years ago)

Fix hyst temp for 2.6 lm75, lm78 and gl518sm. Shame on me.

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