PageRenderTime 53ms CodeModel.GetById 24ms RepoModel.GetById 1ms app.codeStats 0ms

/user/lm_sensors/lib/proc.c

https://bitbucket.org/thelearninglabs/uclinux-distro-tll-public
C | 455 lines | 331 code | 30 blank | 94 comment | 124 complexity | 91cc97196a6566d12c39da025231ae6d MD5 | raw file
Possible License(s): LGPL-2.1, BSD-3-Clause, MPL-2.0-no-copyleft-exception, LGPL-3.0, Unlicense, GPL-2.0, GPL-3.0, CC-BY-SA-3.0, AGPL-1.0, ISC, MIT, 0BSD, LGPL-2.0
  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. This program is free software; you can redistribute it and/or modify
  5. it under the terms of the GNU General Public License as published by
  6. the Free Software Foundation; either version 2 of the License, or
  7. (at your option) any later version.
  8. This program is distributed in the hope that it will be useful,
  9. but WITHOUT ANY WARRANTY; without even the implied warranty of
  10. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  11. GNU General Public License for more details.
  12. You should have received a copy of the GNU General Public License
  13. along with this program; if not, write to the Free Software
  14. Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  15. */
  16. #include <sys/types.h>
  17. #include <sys/sysctl.h>
  18. #include <stddef.h>
  19. #include <unistd.h>
  20. #include <stdio.h>
  21. #include <string.h>
  22. #include <limits.h>
  23. #include <dirent.h>
  24. #include "kernel/include/sensors.h"
  25. #include "data.h"
  26. #include "error.h"
  27. #include "access.h"
  28. #include "general.h"
  29. #include "sysfs.h"
  30. /* OK, this proves one thing: if there are too many chips detected, we get in
  31. trouble. The limit is around 4096/sizeof(struct sensors_chip_data), which
  32. works out to about 100 entries right now. That seems sensible enough,
  33. but if we ever get at the point where more chips can be detected, we must
  34. enlarge buf, and check that sysctl can handle larger buffers. */
  35. #define BUF_LEN 4096
  36. static char buf[BUF_LEN];
  37. static int getsysname(const sensors_chip_feature *feature, char *sysname,
  38. int *sysmag, char *altsysname);
  39. /* This reads /proc/sys/dev/sensors/chips into memory */
  40. int sensors_read_proc_chips(void)
  41. {
  42. int res;
  43. int name[3] = { CTL_DEV, DEV_SENSORS, SENSORS_CHIPS };
  44. size_t buflen = BUF_LEN;
  45. char *bufptr = buf;
  46. sensors_proc_chips_entry entry;
  47. int lineno;
  48. if (sysctl(name, 3, bufptr, &buflen, NULL, 0))
  49. return -SENSORS_ERR_PROC;
  50. lineno = 1;
  51. while (buflen >= sizeof(struct i2c_chips_data)) {
  52. if ((res =
  53. sensors_parse_chip_name(((struct i2c_chips_data *) bufptr)->name,
  54. &entry.name))) {
  55. sensors_parse_error("Parsing /proc/sys/dev/sensors/chips",lineno);
  56. return res;
  57. }
  58. entry.sysctl = ((struct i2c_chips_data *) bufptr)->sysctl_id;
  59. sensors_add_proc_chips(&entry);
  60. bufptr += sizeof(struct i2c_chips_data);
  61. buflen -= sizeof(struct i2c_chips_data);
  62. lineno++;
  63. }
  64. return 0;
  65. }
  66. int sensors_read_proc_bus(void)
  67. {
  68. FILE *f;
  69. char line[255];
  70. char *border;
  71. sensors_bus entry;
  72. int lineno;
  73. f = fopen("/proc/bus/i2c","r");
  74. if (!f)
  75. return -SENSORS_ERR_PROC;
  76. lineno=1;
  77. while (fgets(line,255,f)) {
  78. if (strlen(line) > 0)
  79. line[strlen(line)-1] = '\0';
  80. if (! (border = rindex(line,'\t')))
  81. goto ERROR;
  82. if (! (entry.algorithm = strdup(border+1)))
  83. goto FAT_ERROR;
  84. *border='\0';
  85. if (! (border = rindex(line,'\t')))
  86. goto ERROR;
  87. if (! (entry.adapter = strdup(border + 1)))
  88. goto FAT_ERROR;
  89. *border='\0';
  90. if (! (border = rindex(line,'\t')))
  91. goto ERROR;
  92. *border='\0';
  93. if (strncmp(line,"i2c-",4))
  94. goto ERROR;
  95. if (sensors_parse_i2cbus_name(line,&entry.number))
  96. goto ERROR;
  97. sensors_strip_of_spaces(entry.algorithm);
  98. sensors_strip_of_spaces(entry.adapter);
  99. sensors_add_proc_bus(&entry);
  100. lineno++;
  101. }
  102. fclose(f);
  103. return 0;
  104. FAT_ERROR:
  105. sensors_fatal_error("sensors_read_proc_bus","Allocating entry");
  106. ERROR:
  107. sensors_parse_error("Parsing /proc/bus/i2c",lineno);
  108. fclose(f);
  109. return -SENSORS_ERR_PROC;
  110. }
  111. /* This returns the first detected chip which matches the name */
  112. static int sensors_get_chip_id(sensors_chip_name name)
  113. {
  114. int i;
  115. for (i = 0; i < sensors_proc_chips_count; i++)
  116. if (sensors_match_chip(name, sensors_proc_chips[i].name))
  117. return sensors_proc_chips[i].sysctl;
  118. return -SENSORS_ERR_NO_ENTRY;
  119. }
  120. /* This reads a feature /proc or /sys file.
  121. Sysfs uses a one-value-per file system...
  122. */
  123. int sensors_read_proc(sensors_chip_name name, int feature, double *value)
  124. {
  125. int sysctl_name[4] = { CTL_DEV, DEV_SENSORS };
  126. const sensors_chip_feature *the_feature;
  127. size_t buflen = BUF_LEN;
  128. int mag;
  129. if (!sensors_found_sysfs)
  130. if ((sysctl_name[2] = sensors_get_chip_id(name)) < 0)
  131. return sysctl_name[2];
  132. if (! (the_feature = sensors_lookup_feature_nr(name.prefix,feature)))
  133. return -SENSORS_ERR_NO_ENTRY;
  134. if (sensors_found_sysfs) {
  135. char n[NAME_MAX], altn[NAME_MAX];
  136. FILE *f;
  137. strcpy(n, name.busname);
  138. strcat(n, "/");
  139. strcpy(altn, n);
  140. /* use rindex to append sysname to n */
  141. getsysname(the_feature, rindex(n, '\0'), &mag, rindex(altn, '\0'));
  142. if ((f = fopen(n, "r")) != NULL
  143. || (f = fopen(altn, "r")) != NULL) {
  144. fscanf(f, "%lf", value);
  145. fclose(f);
  146. for (; mag > 0; mag --)
  147. *value /= 10.0;
  148. return 0;
  149. } else
  150. return -SENSORS_ERR_PROC;
  151. } else {
  152. sysctl_name[3] = the_feature->sysctl;
  153. if (sysctl(sysctl_name, 4, buf, &buflen, NULL, 0))
  154. return -SENSORS_ERR_PROC;
  155. *value = *((long *) (buf + the_feature->offset));
  156. for (mag = the_feature->scaling; mag > 0; mag --)
  157. *value /= 10.0;
  158. for (; mag < 0; mag ++)
  159. *value *= 10.0;
  160. }
  161. return 0;
  162. }
  163. int sensors_write_proc(sensors_chip_name name, int feature, double value)
  164. {
  165. int sysctl_name[4] = { CTL_DEV, DEV_SENSORS };
  166. const sensors_chip_feature *the_feature;
  167. size_t buflen = BUF_LEN;
  168. int mag;
  169. if (!sensors_found_sysfs)
  170. if ((sysctl_name[2] = sensors_get_chip_id(name)) < 0)
  171. return sysctl_name[2];
  172. if (! (the_feature = sensors_lookup_feature_nr(name.prefix,feature)))
  173. return -SENSORS_ERR_NO_ENTRY;
  174. if (sensors_found_sysfs) {
  175. char n[NAME_MAX], altn[NAME_MAX];
  176. FILE *f;
  177. strcpy(n, name.busname);
  178. strcat(n, "/");
  179. strcpy(altn, n);
  180. /* use rindex to append sysname to n */
  181. getsysname(the_feature, rindex(n, '\0'), &mag, rindex(altn, '\0'));
  182. if ((f = fopen(n, "w")) != NULL
  183. || (f = fopen(altn, "w")) != NULL) {
  184. for (; mag > 0; mag --)
  185. value *= 10.0;
  186. fprintf(f, "%d", (int) value);
  187. fclose(f);
  188. } else
  189. return -SENSORS_ERR_PROC;
  190. } else {
  191. sysctl_name[3] = the_feature->sysctl;
  192. if (sysctl(sysctl_name, 4, buf, &buflen, NULL, 0))
  193. return -SENSORS_ERR_PROC;
  194. /* The following line is known to solve random problems, still it
  195. can't be considered a definitive solution...
  196. if (sysctl_name[0] != CTL_DEV) { sysctl_name[0] = CTL_DEV ; } */
  197. for (mag = the_feature->scaling; mag > 0; mag --)
  198. value *= 10.0;
  199. for (; mag < 0; mag ++)
  200. value /= 10.0;
  201. * ((long *) (buf + the_feature->offset)) = (long) value;
  202. buflen = the_feature->offset + sizeof(long);
  203. #ifdef DEBUG
  204. /* The following get* calls don't do anything, they are here
  205. for debugging purposes only. Strace will show the
  206. returned values. */
  207. getuid(); geteuid();
  208. getgid(); getegid();
  209. #endif
  210. if (sysctl(sysctl_name, 4, NULL, 0, buf, buflen))
  211. return -SENSORS_ERR_PROC;
  212. }
  213. return 0;
  214. }
  215. #define CURRMAG 3
  216. #define FANMAG 0
  217. #define INMAG 3
  218. #define TEMPMAG 3
  219. /* The following are used in getsysname() below */
  220. struct match {
  221. const char * name, * sysname;
  222. const int sysmag;
  223. const char * altsysname;
  224. };
  225. static const struct match matches[] = {
  226. { "beeps", "beep_mask", 0 },
  227. { "pwm", "fan1_pwm", 0 },
  228. { "vid", "cpu0_vid", INMAG, "in0_ref" },
  229. { "remote_temp", "temp2_input", TEMPMAG },
  230. { "remote_temp_hyst", "temp2_max_hyst", TEMPMAG },
  231. { "remote_temp_low", "temp2_min", TEMPMAG },
  232. { "remote_temp_over", "temp2_max", TEMPMAG },
  233. { "temp", "temp1_input", TEMPMAG },
  234. { "temp_hyst", "temp1_max_hyst", TEMPMAG },
  235. { "temp_low", "temp1_min", TEMPMAG },
  236. { "temp_over", "temp1_max", TEMPMAG },
  237. { "temp_high", "temp1_max", TEMPMAG },
  238. { "temp_crit", "temp1_crit", TEMPMAG },
  239. { "pwm1", "pwm1", 0, "fan1_pwm" },
  240. { "pwm2", "pwm2", 0, "fan2_pwm" },
  241. { "pwm3", "pwm3", 0, "fan3_pwm" },
  242. { "pwm4", "pwm4", 0, "fan4_pwm" },
  243. { "pwm1_enable", "pwm1_enable", 0, "fan1_pwm_enable" },
  244. { "pwm2_enable", "pwm2_enable", 0, "fan2_pwm_enable" },
  245. { "pwm3_enable", "pwm3_enable", 0, "fan3_pwm_enable" },
  246. { "pwm4_enable", "pwm4_enable", 0, "fan4_pwm_enable" },
  247. { NULL, NULL }
  248. };
  249. /*
  250. Returns the sysfs name and magnitude for a given feature.
  251. First looks for a sysfs name and magnitude in the feature structure.
  252. These should be added in chips.c for all non-standard feature names.
  253. If that fails, converts common /proc feature names
  254. to their sysfs equivalent, and uses common sysfs magnitude.
  255. Common magnitudes are #defined above.
  256. Common conversions are as follows:
  257. fan%d_min -> fan%d_min (for magnitude)
  258. fan%d_state -> fan%d_status
  259. fan%d -> fan_input%d
  260. pwm%d -> fan%d_pwm
  261. pwm%d_enable -> fan%d_pwm_enable
  262. in%d_max -> in%d_max (for magnitude)
  263. in%d_min -> in%d_min (for magnitude)
  264. in%d -> in%d_input
  265. vin%d_max -> in%d_max
  266. vin%d_min -> in%d_min
  267. vin%d -> in_input%d
  268. temp%d_over -> temp%d_max
  269. temp%d_hyst -> temp%d_max_hyst
  270. temp%d_max -> temp%d_max (for magnitude)
  271. temp%d_high -> temp%d_max
  272. temp%d_min -> temp%d_min (for magnitude)
  273. temp%d_low -> temp%d_min
  274. temp%d_state -> temp%d_status
  275. temp%d -> temp%d_input
  276. sensor%d -> temp%d_type
  277. AND all conversions listed in the matches[] structure above.
  278. If that fails, returns old /proc feature name and magnitude.
  279. References: doc/developers/proc in the lm_sensors package;
  280. Documentation/i2c/sysfs_interface in the kernel
  281. */
  282. static int getsysname(const sensors_chip_feature *feature, char *sysname,
  283. int *sysmag, char *altsysname)
  284. {
  285. const char * name = feature->name;
  286. char last;
  287. char check; /* used to verify end of string */
  288. int num;
  289. const struct match *m;
  290. /* default to a non-existent alternate name (should rarely be tried) */
  291. strcpy(altsysname, "_");
  292. /* use override in feature structure if present */
  293. if(feature->sysname != NULL) {
  294. strcpy(sysname, feature->sysname);
  295. if(feature->sysscaling)
  296. *sysmag = feature->sysscaling;
  297. else
  298. *sysmag = feature->scaling;
  299. if(feature->altsysname != NULL)
  300. strcpy(altsysname, feature->altsysname);
  301. return 0;
  302. }
  303. /* check for constant mappings */
  304. for(m = matches; m->name != NULL; m++) {
  305. if(!strcmp(m->name, name)) {
  306. strcpy(sysname, m->sysname);
  307. if (m->altsysname != NULL)
  308. strcpy(altsysname, m->altsysname);
  309. *sysmag = m->sysmag;
  310. return 0;
  311. }
  312. }
  313. /* convert common /proc names to common sysfs names */
  314. if(sscanf(name, "fan%d_mi%c%c", &num, &last, &check) == 2 && last == 'n') {
  315. strcpy(sysname, name);
  316. *sysmag = FANMAG;
  317. return 0;
  318. }
  319. if(sscanf(name, "fan%d_stat%c%c", &num, &last, &check) == 2 && last == 'e') {
  320. sprintf(sysname, "fan%d_status", num);
  321. *sysmag = 0;
  322. return 0;
  323. }
  324. if(sscanf(name, "fan%d%c", &num, &check) == 1) {
  325. sprintf(sysname, "fan%d_input", num);
  326. *sysmag = FANMAG;
  327. return 0;
  328. }
  329. if(sscanf(name, "pwm%d%c", &num, &check) == 1) {
  330. sprintf(sysname, "fan%d_pwm", num);
  331. *sysmag = 0;
  332. return 0;
  333. }
  334. if(sscanf(name, "pwm%d_enabl%c%c", &num, &last, &check) == 2 && last == 'e') {
  335. sprintf(sysname, "fan%d_pwm_enable", num);
  336. *sysmag = 0;
  337. return 0;
  338. }
  339. if((sscanf(name, "in%d_mi%c%c", &num, &last, &check) == 2 && last == 'n')
  340. || (sscanf(name, "in%d_ma%c%c", &num, &last, &check) == 2 && last == 'x')) {
  341. strcpy(sysname, name);
  342. *sysmag = INMAG;
  343. return 0;
  344. }
  345. if((sscanf(name, "in%d%c", &num, &check) == 1)
  346. || (sscanf(name, "vin%d%c", &num, &check) == 1)) {
  347. sprintf(sysname, "in%d_input", num);
  348. *sysmag = INMAG;
  349. return 0;
  350. }
  351. if(sscanf(name, "vin%d_mi%c%c", &num, &last, &check) == 2 && last == 'n') {
  352. sprintf(sysname, "in%d_min", num);
  353. *sysmag = INMAG;
  354. return 0;
  355. }
  356. if(sscanf(name, "vin%d_ma%c%c", &num, &last, &check) == 2 && last == 'x') {
  357. sprintf(sysname, "in%d_max", num);
  358. *sysmag = INMAG;
  359. return 0;
  360. }
  361. if(sscanf(name, "temp%d_hys%c%c", &num, &last, &check) == 2 && last == 't') {
  362. sprintf(sysname, "temp%d_max_hyst", num);
  363. *sysmag = TEMPMAG;
  364. return 0;
  365. }
  366. if((sscanf(name, "temp%d_ove%c%c", &num, &last, &check) == 2 && last == 'r')
  367. || (sscanf(name, "temp%d_ma%c%c", &num, &last, &check) == 2 && last == 'x')
  368. || (sscanf(name, "temp%d_hig%c%c", &num, &last, &check) == 2 && last == 'h')) {
  369. sprintf(sysname, "temp%d_max", num);
  370. *sysmag = TEMPMAG;
  371. return 0;
  372. }
  373. if((sscanf(name, "temp%d_mi%c%c", &num, &last, &check) == 2 && last == 'n')
  374. || (sscanf(name, "temp%d_lo%c%c", &num, &last, &check) == 2 && last == 'w')) {
  375. sprintf(sysname, "temp%d_min", num);
  376. *sysmag = TEMPMAG;
  377. return 0;
  378. }
  379. if(sscanf(name, "temp%d_cri%c%c", &num, &last, &check) == 2 && last == 't') {
  380. sprintf(sysname, "temp%d_crit", num);
  381. *sysmag = TEMPMAG;
  382. return 0;
  383. }
  384. if(sscanf(name, "temp%d_stat%c%c", &num, &last, &check) == 2 && last == 'e') {
  385. sprintf(sysname, "temp%d_status", num);
  386. *sysmag = 0;
  387. return 0;
  388. }
  389. if(sscanf(name, "temp%d%c", &num, &check) == 1) {
  390. sprintf(sysname, "temp%d_input", num);
  391. *sysmag = TEMPMAG;
  392. return 0;
  393. }
  394. if(sscanf(name, "sensor%d%c", &num, &check) == 1) {
  395. sprintf(sysname, "temp%d_type", num);
  396. *sysmag = 0;
  397. return 0;
  398. }
  399. /* bmcsensors only, not yet in kernel */
  400. /*
  401. if((sscanf(name, "curr%d_mi%c%c", &num, &last, &check) == 2 && last == 'n')
  402. || (sscanf(name, "curr%d_ma%c%c", &num, &last, &check) == 2 && last == 'x')) {
  403. strcpy(sysname, name);
  404. *sysmag = CURRMAG;
  405. return 0;
  406. }
  407. if(sscanf(name, "curr%d%c", &num, &check) == 1) {
  408. sprintf(sysname, "curr%d_input", num);
  409. *sysmag = CURRMAG;
  410. return 0;
  411. }
  412. */
  413. /* give up, use old name (probably won't work though...) */
  414. /* known to be the same:
  415. "alarms", "beep_enable", "vrm", "fan%d_div"
  416. */
  417. strcpy(sysname, name);
  418. *sysmag = feature->scaling;
  419. return 0;
  420. }