Nife version Beta
Nie możesz wybrać więcej, niż 25 tematów Tematy muszą się zaczynać od litery lub cyfry, mogą zawierać myślniki ('-') i mogą mieć do 35 znaków.

10 lat temu
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416
  1. /*
  2. i2cbusses: Print the installed i2c busses for both 2.4 and 2.6 kernels.
  3. Part of user-space programs to access for I2C
  4. devices.
  5. Copyright (c) 1999-2003 Frodo Looijaard <frodol@dds.nl> and
  6. Mark D. Studebaker <mdsxyz123@yahoo.com>
  7. Copyright (C) 2008-2012 Jean Delvare <jdelvare@suse.de>
  8. This program is free software; you can redistribute it and/or modify
  9. it under the terms of the GNU General Public License as published by
  10. the Free Software Foundation; either version 2 of the License, or
  11. (at your option) any later version.
  12. This program is distributed in the hope that it will be useful,
  13. but WITHOUT ANY WARRANTY; without even the implied warranty of
  14. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  15. GNU General Public License for more details.
  16. You should have received a copy of the GNU General Public License
  17. along with this program; if not, write to the Free Software
  18. Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
  19. MA 02110-1301 USA.
  20. */
  21. /* For strdup and snprintf */
  22. #define _BSD_SOURCE 1
  23. #include <sys/types.h>
  24. #include <sys/stat.h>
  25. #include <sys/param.h> /* for NAME_MAX */
  26. #include <sys/ioctl.h>
  27. #include <string.h>
  28. #include <strings.h> /* for strcasecmp() */
  29. #include <stdio.h>
  30. #include <stdlib.h>
  31. #include <unistd.h>
  32. #include <limits.h>
  33. #include <dirent.h>
  34. #include <fcntl.h>
  35. #include <errno.h>
  36. #include "i2cbusses.h"
  37. #include <linux/i2c-dev.h>
  38. enum adt { adt_dummy, adt_isa, adt_i2c, adt_smbus, adt_unknown };
  39. struct adap_type {
  40. const char *funcs;
  41. const char* algo;
  42. };
  43. static struct adap_type adap_types[5] = {
  44. { .funcs = "dummy",
  45. .algo = "Dummy bus", },
  46. { .funcs = "isa",
  47. .algo = "ISA bus", },
  48. { .funcs = "i2c",
  49. .algo = "I2C adapter", },
  50. { .funcs = "smbus",
  51. .algo = "SMBus adapter", },
  52. { .funcs = "unknown",
  53. .algo = "N/A", },
  54. };
  55. static enum adt i2c_get_funcs(int i2cbus)
  56. {
  57. unsigned long funcs;
  58. int file;
  59. char filename[20];
  60. enum adt ret;
  61. file = open_i2c_dev(i2cbus, filename, sizeof(filename), 1);
  62. if (file < 0)
  63. return adt_unknown;
  64. if (ioctl(file, I2C_FUNCS, &funcs) < 0)
  65. ret = adt_unknown;
  66. else if (funcs & I2C_FUNC_I2C)
  67. ret = adt_i2c;
  68. else if (funcs & (I2C_FUNC_SMBUS_BYTE |
  69. I2C_FUNC_SMBUS_BYTE_DATA |
  70. I2C_FUNC_SMBUS_WORD_DATA))
  71. ret = adt_smbus;
  72. else
  73. ret = adt_dummy;
  74. close(file);
  75. return ret;
  76. }
  77. /* Remove trailing spaces from a string
  78. Return the new string length including the trailing NUL */
  79. static int rtrim(char *s)
  80. {
  81. int i;
  82. for (i = strlen(s) - 1; i >= 0 && (s[i] == ' ' || s[i] == '\n'); i--)
  83. s[i] = '\0';
  84. return i + 2;
  85. }
  86. void free_adapters(struct i2c_adap *adapters)
  87. {
  88. int i;
  89. for (i = 0; adapters[i].name; i++)
  90. free(adapters[i].name);
  91. free(adapters);
  92. }
  93. /* We allocate space for the adapters in bunches. The last item is a
  94. terminator, so here we start with room for 7 adapters, which should
  95. be enough in most cases. If not, we allocate more later as needed. */
  96. #define BUNCH 8
  97. /* n must match the size of adapters at calling time */
  98. static struct i2c_adap *more_adapters(struct i2c_adap *adapters, int n)
  99. {
  100. struct i2c_adap *new_adapters;
  101. new_adapters = realloc(adapters, (n + BUNCH) * sizeof(struct i2c_adap));
  102. if (!new_adapters) {
  103. free_adapters(adapters);
  104. return NULL;
  105. }
  106. memset(new_adapters + n, 0, BUNCH * sizeof(struct i2c_adap));
  107. return new_adapters;
  108. }
  109. struct i2c_adap *gather_i2c_busses(void)
  110. {
  111. char s[120];
  112. struct dirent *de, *dde;
  113. DIR *dir, *ddir;
  114. FILE *f;
  115. char fstype[NAME_MAX], sysfs[NAME_MAX], n[NAME_MAX];
  116. int foundsysfs = 0;
  117. int count=0;
  118. struct i2c_adap *adapters;
  119. adapters = calloc(BUNCH, sizeof(struct i2c_adap));
  120. if (!adapters)
  121. return NULL;
  122. /* look in /proc/bus/i2c */
  123. if ((f = fopen("/proc/bus/i2c", "r"))) {
  124. while (fgets(s, 120, f)) {
  125. char *algo, *name, *type, *all;
  126. int len_algo, len_name, len_type;
  127. int i2cbus;
  128. algo = strrchr(s, '\t');
  129. *(algo++) = '\0';
  130. len_algo = rtrim(algo);
  131. name = strrchr(s, '\t');
  132. *(name++) = '\0';
  133. len_name = rtrim(name);
  134. type = strrchr(s, '\t');
  135. *(type++) = '\0';
  136. len_type = rtrim(type);
  137. sscanf(s, "i2c-%d", &i2cbus);
  138. if ((count + 1) % BUNCH == 0) {
  139. /* We need more space */
  140. adapters = more_adapters(adapters, count + 1);
  141. if (!adapters)
  142. return NULL;
  143. }
  144. all = malloc(len_name + len_type + len_algo);
  145. if (all == NULL) {
  146. free_adapters(adapters);
  147. return NULL;
  148. }
  149. adapters[count].nr = i2cbus;
  150. adapters[count].name = strcpy(all, name);
  151. adapters[count].funcs = strcpy(all + len_name, type);
  152. adapters[count].algo = strcpy(all + len_name + len_type,
  153. algo);
  154. count++;
  155. }
  156. fclose(f);
  157. goto done;
  158. }
  159. /* look in sysfs */
  160. /* First figure out where sysfs was mounted */
  161. if ((f = fopen("/proc/mounts", "r")) == NULL) {
  162. goto done;
  163. }
  164. while (fgets(n, NAME_MAX, f)) {
  165. sscanf(n, "%*[^ ] %[^ ] %[^ ] %*s\n", sysfs, fstype);
  166. if (strcasecmp(fstype, "sysfs") == 0) {
  167. foundsysfs++;
  168. break;
  169. }
  170. }
  171. fclose(f);
  172. if (! foundsysfs) {
  173. goto done;
  174. }
  175. /* Bus numbers in i2c-adapter don't necessarily match those in
  176. i2c-dev and what we really care about are the i2c-dev numbers.
  177. Unfortunately the names are harder to get in i2c-dev */
  178. strcat(sysfs, "/class/i2c-dev");
  179. if(!(dir = opendir(sysfs)))
  180. goto done;
  181. /* go through the busses */
  182. while ((de = readdir(dir)) != NULL) {
  183. if (!strcmp(de->d_name, "."))
  184. continue;
  185. if (!strcmp(de->d_name, ".."))
  186. continue;
  187. /* this should work for kernels 2.6.5 or higher and */
  188. /* is preferred because is unambiguous */
  189. sprintf(n, "%s/%s/name", sysfs, de->d_name);
  190. f = fopen(n, "r");
  191. /* this seems to work for ISA */
  192. if(f == NULL) {
  193. sprintf(n, "%s/%s/device/name", sysfs, de->d_name);
  194. f = fopen(n, "r");
  195. }
  196. /* non-ISA is much harder */
  197. /* and this won't find the correct bus name if a driver
  198. has more than one bus */
  199. if(f == NULL) {
  200. sprintf(n, "%s/%s/device", sysfs, de->d_name);
  201. if(!(ddir = opendir(n)))
  202. continue;
  203. while ((dde = readdir(ddir)) != NULL) {
  204. if (!strcmp(dde->d_name, "."))
  205. continue;
  206. if (!strcmp(dde->d_name, ".."))
  207. continue;
  208. if ((!strncmp(dde->d_name, "i2c-", 4))) {
  209. sprintf(n, "%s/%s/device/%s/name",
  210. sysfs, de->d_name, dde->d_name);
  211. if((f = fopen(n, "r")))
  212. goto found;
  213. }
  214. }
  215. }
  216. found:
  217. if (f != NULL) {
  218. int i2cbus;
  219. enum adt type;
  220. char *px;
  221. px = fgets(s, 120, f);
  222. fclose(f);
  223. if (!px) {
  224. fprintf(stderr, "%s: read error\n", n);
  225. continue;
  226. }
  227. if ((px = strchr(s, '\n')) != NULL)
  228. *px = 0;
  229. if (!sscanf(de->d_name, "i2c-%d", &i2cbus))
  230. continue;
  231. if (!strncmp(s, "ISA ", 4)) {
  232. type = adt_isa;
  233. } else {
  234. /* Attempt to probe for adapter capabilities */
  235. type = i2c_get_funcs(i2cbus);
  236. }
  237. if ((count + 1) % BUNCH == 0) {
  238. /* We need more space */
  239. adapters = more_adapters(adapters, count + 1);
  240. if (!adapters)
  241. return NULL;
  242. }
  243. adapters[count].nr = i2cbus;
  244. adapters[count].name = strdup(s);
  245. if (adapters[count].name == NULL) {
  246. free_adapters(adapters);
  247. return NULL;
  248. }
  249. adapters[count].funcs = adap_types[type].funcs;
  250. adapters[count].algo = adap_types[type].algo;
  251. count++;
  252. }
  253. }
  254. closedir(dir);
  255. done:
  256. return adapters;
  257. }
  258. static int lookup_i2c_bus_by_name(const char *bus_name)
  259. {
  260. struct i2c_adap *adapters;
  261. int i, i2cbus = -1;
  262. adapters = gather_i2c_busses();
  263. if (adapters == NULL) {
  264. fprintf(stderr, "Error: Out of memory!\n");
  265. return -3;
  266. }
  267. /* Walk the list of i2c busses, looking for the one with the
  268. right name */
  269. for (i = 0; adapters[i].name; i++) {
  270. if (strcmp(adapters[i].name, bus_name) == 0) {
  271. if (i2cbus >= 0) {
  272. fprintf(stderr,
  273. "Error: I2C bus name is not unique!\n");
  274. i2cbus = -4;
  275. goto done;
  276. }
  277. i2cbus = adapters[i].nr;
  278. }
  279. }
  280. if (i2cbus == -1)
  281. fprintf(stderr, "Error: I2C bus name doesn't match any "
  282. "bus present!\n");
  283. done:
  284. free_adapters(adapters);
  285. return i2cbus;
  286. }
  287. /*
  288. * Parse an I2CBUS command line argument and return the corresponding
  289. * bus number, or a negative value if the bus is invalid.
  290. */
  291. int lookup_i2c_bus(const char *i2cbus_arg)
  292. {
  293. unsigned long i2cbus;
  294. char *end;
  295. i2cbus = strtoul(i2cbus_arg, &end, 0);
  296. if (*end || !*i2cbus_arg) {
  297. /* Not a number, maybe a name? */
  298. return lookup_i2c_bus_by_name(i2cbus_arg);
  299. }
  300. if (i2cbus > 0xFFFFF) {
  301. fprintf(stderr, "Error: I2C bus out of range!\n");
  302. return -2;
  303. }
  304. return i2cbus;
  305. }
  306. /*
  307. * Parse a CHIP-ADDRESS command line argument and return the corresponding
  308. * chip address, or a negative value if the address is invalid.
  309. */
  310. int parse_i2c_address(const char *address_arg)
  311. {
  312. long address;
  313. char *end;
  314. address = strtol(address_arg, &end, 0);
  315. if (*end || !*address_arg) {
  316. fprintf(stderr, "Error: Chip address is not a number!\n");
  317. return -1;
  318. }
  319. if (address < 0x03 || address > 0x77) {
  320. fprintf(stderr, "Error: Chip address out of range "
  321. "(0x03-0x77)!\n");
  322. return -2;
  323. }
  324. return address;
  325. }
  326. int open_i2c_dev(int i2cbus, char *filename, size_t size, int quiet)
  327. {
  328. int file;
  329. snprintf(filename, size, "/dev/i2c/%d", i2cbus);
  330. filename[size - 1] = '\0';
  331. file = open(filename, O_RDWR);
  332. if (file < 0 && (errno == ENOENT || errno == ENOTDIR)) {
  333. sprintf(filename, "/dev/i2c-%d", i2cbus);
  334. file = open(filename, O_RDWR);
  335. }
  336. if (file < 0 && !quiet) {
  337. if (errno == ENOENT) {
  338. fprintf(stderr, "Error: Could not open file "
  339. "`/dev/i2c-%d' or `/dev/i2c/%d': %s\n",
  340. i2cbus, i2cbus, strerror(ENOENT));
  341. } else {
  342. fprintf(stderr, "Error: Could not open file "
  343. "`%s': %s\n", filename, strerror(errno));
  344. if (errno == EACCES)
  345. fprintf(stderr, "Run as root?\n");
  346. }
  347. }
  348. return file;
  349. }
  350. int set_slave_addr(int file, int address, int force)
  351. {
  352. /* With force, let the user read from/write to the registers
  353. even when a driver is also running */
  354. if (ioctl(file, force ? I2C_SLAVE_FORCE : I2C_SLAVE, address) < 0) {
  355. fprintf(stderr,
  356. "Error: Could not set address to 0x%02x: %s\n",
  357. address, strerror(errno));
  358. return -errno;
  359. }
  360. return 0;
  361. }