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

Revision 5210, 8.4 kB (checked in by khali, 7 months ago)

Whitespace cleanups.

  • 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>,
4                              Mark D. Studebaker <mdsxyz123@yahoo.com> and
5                              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
37 static 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
47 static 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
111 struct func
112 {
113         long value;
114         const char* name;
115 };
116
117 static 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
151 static 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  */
165 static 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
185 int 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, 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 (ISA 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 (ISA 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.