root/i2c-tools/trunk/tools/i2cdetect.c @ 5885

Revision 5885, 8.4 KB (checked in by khali, 2 years ago)

Use a 20-bit limit for the i2c bus number.
Use snprintf for the i2c dev node name.
Update copyright years.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
Line 
1/*
2    i2cdetect.c - a user-space program to scan for I2C devices
3    Copyright (C) 1999-2004  Frodo Looijaard <frodol@dds.nl>, and
4                             Mark D. Studebaker <mdsxyz123@yahoo.com>
5    Copyright (C) 2004-2010  Jean Delvare <khali@linux-fr.org>
6
7    This program is free software; you can redistribute it and/or modify
8    it under the terms of the GNU General Public License as published by
9    the Free Software Foundation; either version 2 of the License, or
10    (at your option) any later version.
11
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
17    You should have received a copy of the GNU General Public License
18    along with this program; if not, write to the Free Software
19    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
20    MA 02110-1301 USA.
21*/
22
23#include <errno.h>
24#include <string.h>
25#include <stdio.h>
26#include <stdlib.h>
27#include <unistd.h>
28#include <linux/i2c-dev.h>
29#include "i2cbusses.h"
30#include "../version.h"
31
32#define MODE_AUTO       0
33#define MODE_QUICK      1
34#define MODE_READ       2
35#define MODE_FUNC       3
36
37static void help(void)
38{
39        fprintf(stderr,
40                "Usage: i2cdetect [-y] [-a] [-q|-r] I2CBUS [FIRST LAST]\n"
41                "       i2cdetect -F I2CBUS\n"
42                "       i2cdetect -l\n"
43                "  I2CBUS is an integer or an I2C bus name\n"
44                "  If provided, FIRST and LAST limit the probing range.\n");
45}
46
47static int scan_i2c_bus(int file, int mode, int first, int last)
48{
49        int i, j;
50        int res;
51
52        printf("     0  1  2  3  4  5  6  7  8  9  a  b  c  d  e  f\n");
53
54        for (i = 0; i < 128; i += 16) {
55                printf("%02x: ", i);
56                for(j = 0; j < 16; j++) {
57                        fflush(stdout);
58
59                        /* Skip unwanted addresses */
60                        if (i+j < first || i+j > last) {
61                                printf("   ");
62                                continue;
63                        }
64
65                        /* Set slave address */
66                        if (ioctl(file, I2C_SLAVE, i+j) < 0) {
67                                if (errno == EBUSY) {
68                                        printf("UU ");
69                                        continue;
70                                } else {
71                                        fprintf(stderr, "Error: Could not set "
72                                                "address to 0x%02x: %s\n", i+j,
73                                                strerror(errno));
74                                        return -1;
75                                }
76                        }
77
78                        /* Probe this address */
79                        switch (mode) {
80                        case MODE_QUICK:
81                                /* This is known to corrupt the Atmel AT24RF08
82                                   EEPROM */
83                                res = i2c_smbus_write_quick(file,
84                                      I2C_SMBUS_WRITE);
85                                break;
86                        case MODE_READ:
87                                /* This is known to lock SMBus on various
88                                   write-only chips (mainly clock chips) */
89                                res = i2c_smbus_read_byte(file);
90                                break;
91                        default:
92                                if ((i+j >= 0x30 && i+j <= 0x37)
93                                 || (i+j >= 0x50 && i+j <= 0x5F))
94                                        res = i2c_smbus_read_byte(file);
95                                else
96                                        res = i2c_smbus_write_quick(file,
97                                              I2C_SMBUS_WRITE);
98                        }
99
100                        if (res < 0)
101                                printf("-- ");
102                        else
103                                printf("%02x ", i+j);
104                }
105                printf("\n");
106        }
107
108        return 0;
109}
110
111struct func
112{
113        long value;
114        const char* name;
115};
116
117static const struct func all_func[] = {
118        { .value = I2C_FUNC_I2C,
119          .name = "I2C" },
120        { .value = I2C_FUNC_SMBUS_QUICK,
121          .name = "SMBus Quick Command" },
122        { .value = I2C_FUNC_SMBUS_WRITE_BYTE,
123          .name = "SMBus Send Byte" },
124        { .value = I2C_FUNC_SMBUS_READ_BYTE,
125          .name = "SMBus Receive Byte" },
126        { .value = I2C_FUNC_SMBUS_WRITE_BYTE_DATA,
127          .name = "SMBus Write Byte" },
128        { .value = I2C_FUNC_SMBUS_READ_BYTE_DATA,
129          .name = "SMBus Read Byte" },
130        { .value = I2C_FUNC_SMBUS_WRITE_WORD_DATA,
131          .name = "SMBus Write Word" },
132        { .value = I2C_FUNC_SMBUS_READ_WORD_DATA,
133          .name = "SMBus Read Word" },
134        { .value = I2C_FUNC_SMBUS_PROC_CALL,
135          .name = "SMBus Process Call" },
136        { .value = I2C_FUNC_SMBUS_WRITE_BLOCK_DATA,
137          .name = "SMBus Block Write" },
138        { .value = I2C_FUNC_SMBUS_READ_BLOCK_DATA,
139          .name = "SMBus Block Read" },
140        { .value = I2C_FUNC_SMBUS_BLOCK_PROC_CALL,
141          .name = "SMBus Block Process Call" },
142        { .value = I2C_FUNC_SMBUS_PEC,
143          .name = "SMBus PEC" },
144        { .value = I2C_FUNC_SMBUS_WRITE_I2C_BLOCK,
145          .name = "I2C Block Write" },
146        { .value = I2C_FUNC_SMBUS_READ_I2C_BLOCK,
147          .name = "I2C Block Read" },
148        { .value = 0, .name = "" }
149};
150
151static void print_functionality(unsigned long funcs)
152{
153        int i;
154
155        for (i = 0; all_func[i].value; i++) {
156                printf("%-32s %s\n", all_func[i].name,
157                       (funcs & all_func[i].value) ? "yes" : "no");
158        }
159}
160
161/*
162 * Print the installed i2c busses. The format is those of Linux 2.4's
163 * /proc/bus/i2c for historical compatibility reasons.
164 */
165static void print_i2c_busses(void)
166{
167        struct i2c_adap *adapters;
168        int count;
169
170        adapters = gather_i2c_busses();
171        if (adapters == NULL) {
172                fprintf(stderr, "Error: Out of memory!\n");
173                return;
174        }
175
176        for (count = 0; adapters[count].name; count++) {
177                printf("i2c-%d\t%-10s\t%-32s\t%s\n",
178                        adapters[count].nr, adapters[count].funcs,
179                        adapters[count].name, adapters[count].algo);
180        }
181
182        free_adapters(adapters);
183}
184
185int main(int argc, char *argv[])
186{
187        char *end;
188        int i2cbus, file, res;
189        char filename[20];
190        unsigned long funcs;
191        int mode = MODE_AUTO;
192        int first = 0x03, last = 0x77;
193        int flags = 0;
194        int yes = 0, version = 0, list = 0;
195
196        /* handle (optional) flags first */
197        while (1+flags < argc && argv[1+flags][0] == '-') {
198                switch (argv[1+flags][1]) {
199                case 'V': version = 1; break;
200                case 'y': yes = 1; break;
201                case 'l': list = 1; break;
202                case 'F':
203                        if (mode != MODE_AUTO && mode != MODE_FUNC) {
204                                fprintf(stderr, "Error: Different modes "
205                                        "specified!\n");
206                                exit(1);
207                        }
208                        mode = MODE_FUNC;
209                        break;
210                case 'r':
211                        if (mode == MODE_QUICK) {
212                                fprintf(stderr, "Error: Different modes "
213                                        "specified!\n");
214                                exit(1);
215                        }
216                        mode = MODE_READ;
217                        break;
218                case 'q':
219                        if (mode == MODE_READ) {
220                                fprintf(stderr, "Error: Different modes "
221                                        "specified!\n");
222                                exit(1);
223                        }
224                        mode = MODE_QUICK;
225                        break;
226                case 'a':
227                        first = 0x00;
228                        last = 0x7F;
229                        break;
230                default:
231                        fprintf(stderr, "Error: Unsupported option "
232                                "\"%s\"!\n", argv[1+flags]);
233                        help();
234                        exit(1);
235                }
236                flags++;
237        }
238
239        if (version) {
240                fprintf(stderr, "i2cdetect version %s\n", VERSION);
241                exit(0);
242        }
243
244        if (list) {
245                print_i2c_busses();
246                exit(0);
247        }
248
249        if (argc < flags + 2) {
250                fprintf(stderr, "Error: No i2c-bus specified!\n");
251                help();
252                exit(1);
253        }
254        i2cbus = lookup_i2c_bus(argv[flags+1]);
255        if (i2cbus < 0) {
256                help();
257                exit(1);
258        }
259
260        /* read address range if present */
261        if (argc == flags + 4 && mode != MODE_FUNC) {
262                int tmp;
263
264                tmp = strtol(argv[flags+2], &end, 0);
265                if (*end) {
266                        fprintf(stderr, "Error: FIRST argment not a "
267                                "number!\n");
268                        help();
269                        exit(1);
270                }
271                if (tmp < first || tmp > last) {
272                        fprintf(stderr, "Error: FIRST argument out of range "
273                                "(0x%02x-0x%02x)!\n", first, last);
274                        help();
275                        exit(1);
276                }
277                first = tmp;
278
279                tmp = strtol(argv[flags+3], &end, 0);
280                if (*end) {
281                        fprintf(stderr, "Error: LAST argment not a "
282                                "number!\n");
283                        help();
284                        exit(1);
285                }
286                if (tmp < first || tmp > last) {
287                        fprintf(stderr, "Error: LAST argument out of range "
288                                "(0x%02x-0x%02x)!\n", first, last);
289                        help();
290                        exit(1);
291                }
292                last = tmp;
293        } else if (argc != flags + 2) {
294                help();
295                exit(1);
296        }
297
298        file = open_i2c_dev(i2cbus, filename, sizeof(filename), 0);
299        if (file < 0) {
300                exit(1);
301        }
302
303        if (ioctl(file, I2C_FUNCS, &funcs) < 0) {
304                fprintf(stderr, "Error: Could not get the adapter "
305                        "functionality matrix: %s\n", strerror(errno));
306                close(file);
307                exit(1);
308        }
309
310        /* Special case, we only list the implemented functionalities */
311        if (mode == MODE_FUNC) {
312                close(file);
313                printf("Functionalities implemented by %s:\n", filename);
314                print_functionality(funcs);
315                exit(0);
316        }
317
318        if (mode != MODE_READ && !(funcs & I2C_FUNC_SMBUS_QUICK)) {
319                fprintf(stderr, "Error: Can't use SMBus Quick Write command "
320                        "on this bus\n");
321                close(file);
322                exit(1);
323        }
324        if (mode != MODE_QUICK && !(funcs & I2C_FUNC_SMBUS_READ_BYTE)) {
325                fprintf(stderr, "Error: Can't use SMBus Read Byte command "
326                        "on this bus\n");
327                close(file);
328                exit(1);
329        }
330
331        if (!yes) {
332                char s[2];
333
334                fprintf(stderr, "WARNING! This program can confuse your I2C "
335                        "bus, cause data loss and worse!\n");
336
337                fprintf(stderr, "I will probe file %s%s.\n", filename,
338                        mode==MODE_QUICK?" using quick write commands":
339                        mode==MODE_READ?" using read byte commands":"");
340                fprintf(stderr, "I will probe address range 0x%02x-0x%02x.\n",
341                        first, last);
342
343                fprintf(stderr, "Continue? [Y/n] ");
344                fflush(stderr);
345                if (!fgets(s, 2, stdin)
346                 || (s[0] != '\n' && s[0] != 'y' && s[0] != 'Y')) {
347                        fprintf(stderr, "Aborting on user request.\n");
348                        exit(0);
349                }
350        }
351
352        res = scan_i2c_bus(file, mode, first, last);
353
354        close(file);
355
356        exit(res?1:0);
357}
Note: See TracBrowser for help on using the browser.