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

Revision 5204, 9.7 KB (checked in by khali, 7 years ago)

Move the chip address parsing to a common function for consistency.

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