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