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