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

Revision 6048, 8.4 KB (checked in by khali, 3 years ago)

i2c-dev: Move SMBus helper functions to include/i2c/smbus.h

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