root/i2c-tools/trunk/tools/i2cbusses.c

Revision 5452, 9.8 kB (checked in by khali, 4 days ago)

Add missing includes.

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