xref: /freebsd/usr.sbin/i2c/i2c.c (revision f55bd0e5798dd17251302f73904da76bdfd257b9)
1 /*-
2  * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
3  *
4  * Copyright (C) 2008-2009 Semihalf, Michal Hajduk and Bartlomiej Sieka
5  * All rights reserved.
6  *
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions
9  * are met:
10  * 1. Redistributions of source code must retain the above copyright
11  *    notice, this list of conditions and the following disclaimer.
12  * 2. Redistributions in binary form must reproduce the above copyright
13  *    notice, this list of conditions and the following disclaimer in the
14  *    documentation and/or other materials provided with the distribution.
15  *
16  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
17  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19  * ARE DISCLAIMED.  IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE
20  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
22  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
23  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
24  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
25  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26  * SUCH DAMAGE.
27  */
28 
29 #include <sys/cdefs.h>
30 __FBSDID("$FreeBSD$");
31 
32 #include <assert.h>
33 #include <ctype.h>
34 #include <err.h>
35 #include <errno.h>
36 #include <sysexits.h>
37 #include <fcntl.h>
38 #include <stdio.h>
39 #include <stdlib.h>
40 #include <string.h>
41 #include <unistd.h>
42 #include <sys/endian.h>
43 #include <sys/ioctl.h>
44 
45 #include <dev/iicbus/iic.h>
46 
47 #define	I2C_DEV			"/dev/iic0"
48 #define	I2C_MODE_NOTSET		0
49 #define	I2C_MODE_NONE		1
50 #define	I2C_MODE_STOP_START	2
51 #define	I2C_MODE_REPEATED_START	3
52 #define	I2C_MODE_TRANSFER	4
53 
54 struct options {
55 	const char	*width;
56 	unsigned	count;
57 	int		verbose;
58 	int		binary;
59 	const char	*skip;
60 	int		mode;
61 	char		dir;
62 	uint32_t	addr;
63 	uint32_t	off;
64 	uint8_t		off_buf[2];
65 	size_t		off_len;
66 };
67 
68 __dead2 static void
69 usage(const char *msg)
70 {
71 
72 	if (msg != NULL)
73 		fprintf(stderr, "%s\n", msg);
74 	fprintf(stderr, "usage: %s -a addr [-f device] [-d [r|w]] [-o offset] "
75 	    "[-w [0|8|16|16LE|16BE]] [-c count] [-m [tr|ss|rs|no]] [-b] [-v]\n",
76 	    getprogname());
77 	fprintf(stderr, "       %s -s [-f device] [-n skip_addr] -v\n",
78 	    getprogname());
79 	fprintf(stderr, "       %s -r [-f device] -v\n", getprogname());
80 	exit(EX_USAGE);
81 }
82 
83 static int
84 i2c_do_stop(int fd)
85 {
86 	int i;
87 
88 	i = ioctl(fd, I2CSTOP);
89 	if (i < 0)
90 		fprintf(stderr, "ioctl: error sending stop condition: %s\n",
91 		    strerror(errno));
92 	return (i);
93 }
94 
95 static int
96 i2c_do_start(int fd, struct iiccmd *cmd)
97 {
98 	int i;
99 
100 	i = ioctl(fd, I2CSTART, cmd);
101 	if (i < 0)
102 		fprintf(stderr, "ioctl: error sending start condition: %s\n",
103 		    strerror(errno));
104 	return (i);
105 }
106 
107 static int
108 i2c_do_repeatstart(int fd, struct iiccmd *cmd)
109 {
110 	int i;
111 
112 	i = ioctl(fd, I2CRPTSTART, cmd);
113 	if (i < 0)
114 		fprintf(stderr, "ioctl: error sending repeated start: %s\n",
115 		    strerror(errno));
116 	return (i);
117 }
118 
119 static int
120 i2c_do_write(int fd, struct iiccmd *cmd)
121 {
122 	int i;
123 
124 	i = ioctl(fd, I2CWRITE, cmd);
125 	if (i < 0)
126 		fprintf(stderr, "ioctl: error writing: %s\n",
127 		    strerror(errno));
128 	return (i);
129 }
130 
131 static int
132 i2c_do_read(int fd, struct iiccmd *cmd)
133 {
134 	int i;
135 
136 	i = ioctl(fd, I2CREAD, cmd);
137 	if (i < 0)
138 		fprintf(stderr, "ioctl: error reading: %s\n",
139 		    strerror(errno));
140 	return (i);
141 }
142 
143 static int
144 i2c_do_reset(int fd)
145 {
146 	struct iiccmd cmd;
147 	int i;
148 
149 	memset(&cmd, 0, sizeof cmd);
150 	i = ioctl(fd, I2CRSTCARD, &cmd);
151 	if (i < 0)
152 		fprintf(stderr, "ioctl: error resetting controller: %s\n",
153 		    strerror(errno));
154 	return (i);
155 }
156 
157 static void
158 parse_skip(const char *skip, char blacklist[128])
159 {
160 	const char *p;
161 	unsigned x, y;
162 
163 	for (p = skip; *p != '\0';) {
164 		if (*p == '0' && p[1] == 'x')
165 			p += 2;
166 		if (!isxdigit(*p))
167 			usage("Bad -n argument, expected (first) hex-digit");
168 		x = digittoint(*p++) << 4;
169 		if (!isxdigit(*p))
170 			usage("Bad -n argument, expected (second) hex-digit");
171 		x |= digittoint(*p++);
172 		if (x == 0 || x > 0x7f)
173 			usage("Bad -n argument, (01..7f)");
174 		if (*p == ':' || *p == ',' || *p == '\0') {
175 			blacklist[x] = 1;
176 			if (*p != '\0')
177 				p++;
178 			continue;
179 		}
180 		if (*p == '-') {
181 			p++;
182 		} else if (*p == '.' && p[1] == '.') {
183 			p += 2;
184 		} else {
185 			usage("Bad -n argument, ([:|,|..|-])");
186 		}
187 		if (*p == '0' && p[1] == 'x')
188 			p += 2;
189 		if (!isxdigit(*p))
190 			usage("Bad -n argument, expected (first) hex-digit");
191 		y = digittoint(*p++) << 4;
192 		if (!isxdigit(*p))
193 			usage("Bad -n argument, expected (second) hex-digit");
194 		y |= digittoint(*p++);
195 		if (y == 0 || y > 0x7f)
196 			usage("Bad -n argument, (01..7f)");
197 		if (y < x)
198 			usage("Bad -n argument, (end < start)");
199 		for (;x <= y; x++)
200 			blacklist[x] = 1;
201 		if (*p == ':' || *p == ',')
202 			p++;
203 	}
204 }
205 
206 static int
207 scan_bus(const char *dev, int fd, const char *skip, int verbose)
208 {
209 	struct iiccmd cmd;
210 	struct iic_msg rdmsg;
211 	struct iic_rdwr_data rdwrdata;
212 	int error;
213 	unsigned u;
214 	int num_found = 0, use_read_xfer;
215 	uint8_t rdbyte;
216 	char blacklist[128];
217 	const char *sep = "";
218 
219 	memset(blacklist, 0, sizeof blacklist);
220 
221 	if (skip != NULL)
222 		parse_skip(skip, blacklist);
223 
224 	for (use_read_xfer = 0; use_read_xfer < 2; use_read_xfer++) {
225 		for (u = 1; u < 127; u++) {
226 			if (blacklist[u])
227 				continue;
228 
229 			cmd.slave = u << 1;
230 			cmd.last = 1;
231 			cmd.count = 0;
232 			if (i2c_do_reset(fd))
233 				return (EX_NOINPUT);
234 
235 			if (use_read_xfer) {
236 				rdmsg.buf = &rdbyte;
237 				rdmsg.len = 1;
238 				rdmsg.flags = IIC_M_RD;
239 				rdmsg.slave = u << 1;
240 				rdwrdata.msgs = &rdmsg;
241 				rdwrdata.nmsgs = 1;
242 				error = ioctl(fd, I2CRDWR, &rdwrdata);
243 			} else {
244 				error = ioctl(fd, I2CSTART, &cmd);
245 				if (errno == ENODEV || errno == EOPNOTSUPP)
246 					break; /* Try reads instead */
247 				(void)ioctl(fd, I2CSTOP);
248 			}
249 			if (error == 0) {
250 				if (!num_found++ && verbose) {
251 					fprintf(stderr,
252 					    "Scanning I2C devices on %s:\n",
253 					    dev);
254 				}
255 				printf("%s%02x", sep, u);
256 				sep = " ";
257 			}
258 		}
259 		if (num_found > 0)
260 			break;
261 		if (verbose && !use_read_xfer)
262 			fprintf(stderr,
263 			    "Hardware may not support START/STOP scanning; "
264 			    "trying less-reliable read method.\n");
265 	}
266 	if (num_found == 0 && verbose)
267 		printf("<Nothing Found>");
268 
269 	printf("\n");
270 
271 	return (i2c_do_reset(fd));
272 }
273 
274 static int
275 reset_bus(const char *dev, int fd, int verbose)
276 {
277 
278 	if (verbose)
279 		fprintf(stderr, "Resetting I2C controller on %s\n", dev);
280 	return (i2c_do_reset(fd));
281 }
282 
283 static const char *
284 encode_offset(const char *width, unsigned address, uint8_t *dst, size_t *len)
285 {
286 
287 	if (!strcmp(width, "0")) {
288 		*len = 0;
289 		return (NULL);
290 	}
291 	if (!strcmp(width, "8")) {
292 		if (address > 0xff)
293 			return ("Invalid 8-bit address\n");
294 		*dst = address;
295 		*len = 1;
296 		return (NULL);
297 	}
298 	if (address > 0xffff)
299 		return ("Invalid 16-bit address\n");
300 	if (!strcmp(width, "16LE") || !strcmp(width, "16")) {
301 		le16enc(dst, address);
302 		*len = 2;
303 		return (NULL);
304 	}
305 	if (!strcmp(width, "16BE")) {
306 		be16enc(dst, address);
307 		*len = 2;
308 		return (NULL);
309 	}
310 	return ("Invalid offset width, must be: 0|8|16|16LE|16BE\n");
311 }
312 
313 static int
314 write_offset(int fd, struct options i2c_opt, struct iiccmd *cmd)
315 {
316 
317 	if (i2c_opt.off_len > 0) {
318 		cmd->count = i2c_opt.off_len;
319 		cmd->buf = (void*)i2c_opt.off_buf;
320 		return (i2c_do_write(fd, cmd));
321 	}
322 	return (0);
323 }
324 
325 static int
326 i2c_write(int fd, struct options i2c_opt, uint8_t *i2c_buf)
327 {
328 	struct iiccmd cmd;
329 	char buf[i2c_opt.off_len + i2c_opt.count];
330 
331 	memset(&cmd, 0, sizeof(cmd));
332 	cmd.slave = i2c_opt.addr;
333 
334 	if (i2c_do_start(fd, &cmd))
335 		return (i2c_do_stop(fd) | 1);
336 
337 	switch(i2c_opt.mode) {
338 	case I2C_MODE_STOP_START:
339 		if (write_offset(fd, i2c_opt, &cmd))
340 			return (i2c_do_stop(fd) | 1);
341 
342 		if (i2c_do_stop(fd))
343 			return (1);
344 
345 		if (i2c_do_start(fd, &cmd))
346 			return (i2c_do_stop(fd) | 1);
347 
348 		/*
349 		 * Write the data
350 		 */
351 		cmd.count = i2c_opt.count;
352 		cmd.buf = (void*)i2c_buf;
353 		cmd.last = 0;
354 		if (i2c_do_write(fd, &cmd))
355 			return (i2c_do_stop(fd) | 1);
356 		break;
357 
358 	case I2C_MODE_REPEATED_START:
359 		if (write_offset(fd, i2c_opt, &cmd))
360 			return (i2c_do_stop(fd) | 1);
361 
362 		if (i2c_do_repeatstart(fd, &cmd))
363 			return (i2c_do_stop(fd) | 1);
364 
365 		/*
366 		 * Write the data
367 		 */
368 		cmd.count = i2c_opt.count;
369 		cmd.buf = (void*)i2c_buf;
370 		cmd.last = 0;
371 		if (i2c_do_write(fd, &cmd))
372 			return (i2c_do_stop(fd) | 1);
373 		break;
374 
375 	case I2C_MODE_NONE: /* fall through */
376 	default:
377 		memcpy(buf, i2c_opt.off_buf, i2c_opt.off_len);
378 		memcpy(buf + i2c_opt.off_len, i2c_buf, i2c_opt.count);
379 		/*
380 		 * Write offset and data
381 		 */
382 		cmd.count = i2c_opt.off_len + i2c_opt.count;
383 		cmd.buf = (void*)buf;
384 		cmd.last = 0;
385 		if (i2c_do_write(fd, &cmd))
386 			return (i2c_do_stop(fd) | 1);
387 		break;
388 	}
389 
390 	return (i2c_do_stop(fd));
391 }
392 
393 static int
394 i2c_read(int fd, struct options i2c_opt, uint8_t *i2c_buf)
395 {
396 	struct iiccmd cmd;
397 	char data = 0;
398 
399 	memset(&cmd, 0, sizeof(cmd));
400 	cmd.slave = i2c_opt.addr;
401 
402 	if (i2c_opt.off_len) {
403 		cmd.count = 1;
404 		cmd.last = 0;
405 		cmd.buf = &data;
406 		if (i2c_do_start(fd, &cmd))
407 			return (i2c_do_stop(fd) | 1);
408 
409 		if (write_offset(fd, i2c_opt, &cmd))
410 			return (i2c_do_stop(fd) | 1);
411 
412 		if (i2c_opt.mode == I2C_MODE_STOP_START && i2c_do_stop(fd))
413 			return (1);
414 	}
415 	cmd.slave = i2c_opt.addr | 1;
416 	cmd.count = 1;
417 	cmd.last = 0;
418 	cmd.buf = &data;
419 	if (i2c_opt.mode == I2C_MODE_STOP_START || i2c_opt.off_len == 0) {
420 		if (i2c_do_start(fd, &cmd))
421 			return (i2c_do_stop(fd) | 1);
422 	} else if (i2c_opt.mode == I2C_MODE_REPEATED_START) {
423 		if (i2c_do_repeatstart(fd, &cmd))
424 			return (i2c_do_stop(fd) | 1);
425 	}
426 
427 	cmd.count = i2c_opt.count;
428 	cmd.buf = (void*)i2c_buf;
429 	cmd.last = 1;
430 	if (i2c_do_read(fd, &cmd))
431 		return (i2c_do_stop(fd) | 1);
432 
433 	return (i2c_do_stop(fd));
434 }
435 
436 /*
437  * i2c_rdwr_transfer() - use I2CRDWR to conduct a complete i2c transfer.
438  *
439  * Some i2c hardware is unable to provide direct control over START, REPEAT-
440  * START, and STOP operations.  Such hardware can only perform a complete
441  * START-<data>-STOP or START-<data>-REPEAT-START-<data>-STOP sequence as a
442  * single operation.  The driver framework refers to this sequence as a
443  * "transfer" so we call it "transfer mode".  We assemble either one or two
444  * iic_msg structures to describe the IO operations, and hand them off to the
445  * driver to be handled as a single transfer.
446  */
447 static int
448 i2c_rdwr_transfer(int fd, struct options i2c_opt, uint8_t *i2c_buf)
449 {
450 	struct iic_msg msgs[2], *msgp = msgs;
451 	struct iic_rdwr_data xfer;
452 	int flag = 0;
453 
454 	if (i2c_opt.off_len) {
455 		msgp->flags = IIC_M_WR | IIC_M_NOSTOP;
456 		msgp->slave = i2c_opt.addr;
457 		msgp->buf   = i2c_opt.off_buf;
458 		msgp->len   = i2c_opt.off_len;
459 		msgp++;
460 		flag = IIC_M_NOSTART;
461 	}
462 
463 	/*
464 	 * If the transfer direction is write and we did a write of the offset
465 	 * above, then we need to elide the start; this transfer is just more
466 	 * writing that follows the one started above.  For a read, we always do
467 	 * a start; if we did an offset write above it'll be a repeat-start
468 	 * because of the NOSTOP flag used above.
469 	 */
470 	if (i2c_opt.dir == 'w')
471 		msgp->flags = IIC_M_WR | flag;
472 	else
473 		msgp->flags = IIC_M_RD;
474 	msgp->slave = i2c_opt.addr;
475 	msgp->len   = i2c_opt.count;
476 	msgp->buf   = i2c_buf;
477 	msgp++;
478 
479 	xfer.msgs = msgs;
480 	xfer.nmsgs = msgp - msgs;
481 
482 	if (ioctl(fd, I2CRDWR, &xfer) == -1 )
483 		err(1, "ioctl(I2CRDWR) failed");
484 
485 	return (0);
486 }
487 
488 static int
489 access_bus(int fd, struct options i2c_opt)
490 {
491 	uint8_t i2c_buf[i2c_opt.count];
492 	int error;
493 	unsigned u, chunk_size = 16;
494 
495 	/*
496 	 * For a write, read the data to be written to the chip from stdin.
497 	 */
498 	if (i2c_opt.dir == 'w') {
499 		if (i2c_opt.verbose && !i2c_opt.binary)
500 			fprintf(stderr, "Enter %u bytes of data: ",
501 			    i2c_opt.count);
502 		if (fread(i2c_buf, 1, i2c_opt.count, stdin) != i2c_opt.count)
503 			err(1, "not enough data, exiting\n");
504 	}
505 
506 	if (i2c_opt.mode == I2C_MODE_TRANSFER)
507 		error = i2c_rdwr_transfer(fd, i2c_opt, i2c_buf);
508 	else if (i2c_opt.dir == 'w')
509 		error = i2c_write(fd, i2c_opt, i2c_buf);
510 	else
511 		error = i2c_read(fd, i2c_opt, i2c_buf);
512 
513 	if (error == 0) {
514 		if (i2c_opt.dir == 'r' && i2c_opt.binary) {
515 			(void)fwrite(i2c_buf, 1, i2c_opt.count, stdout);
516 		} else if (i2c_opt.verbose || i2c_opt.dir == 'r') {
517 			if (i2c_opt.verbose)
518 				fprintf(stderr, "\nData %s (hex):\n",
519 				    i2c_opt.dir == 'r' ?  "read" : "written");
520 
521 			for (u = 0; u < i2c_opt.count; u++) {
522 				printf("%02hhx ", i2c_buf[u]);
523 				if ((u % chunk_size) == chunk_size - 1)
524 					printf("\n");
525 			}
526 			if ((u % chunk_size) != 0)
527 				printf("\n");
528 		}
529 	}
530 
531 	return (error);
532 }
533 
534 int
535 main(int argc, char** argv)
536 {
537 	struct options i2c_opt;
538 	const char *dev, *err_msg;
539 	int fd, error = 0, ch;
540 	const char *optflags = "a:f:d:o:w:c:m:n:sbvrh";
541 	char do_what = 0;
542 
543 	dev = I2C_DEV;
544 
545 	/* Default values */
546 	i2c_opt.off = 0;
547 	i2c_opt.verbose = 0;
548 	i2c_opt.dir = 'r';	/* direction = read */
549 	i2c_opt.width = "8";
550 	i2c_opt.count = 1;
551 	i2c_opt.binary = 0;	/* ASCII text output */
552 	i2c_opt.skip = NULL;	/* scan all addresses */
553 	i2c_opt.mode = I2C_MODE_NOTSET;
554 
555 	/* Find out what we are going to do */
556 
557 	while ((ch = getopt(argc, argv, "a:f:d:o:w:c:m:n:sbvrh")) != -1) {
558 		switch(ch) {
559 		case 'a':
560 		case 'r':
561 		case 's':
562 			if (do_what)
563 				usage("Only one of [-a|-h|-r|-s]");
564 			do_what = ch;
565 			break;
566 		case 'h':
567 			usage("Help:");
568 			break;
569 		default:
570 			break;
571 		}
572 	}
573 
574 	/* Then handle the legal subset of arguments */
575 
576 	switch (do_what) {
577 	case 0: usage("Pick one of [-a|-h|-r|-s]"); break;
578 	case 'a': optflags = "a:f:d:w:o:c:m:bv"; break;
579 	case 'r': optflags = "rf:v"; break;
580 	case 's': optflags = "sf:n:v"; break;
581 	default: assert("Bad do_what");
582 	}
583 
584 	optreset = 1;
585 	optind = 1;
586 
587 	while ((ch = getopt(argc, argv, optflags)) != -1) {
588 		switch(ch) {
589 		case 'a':
590 			i2c_opt.addr = strtoul(optarg, 0, 16);
591 			if (i2c_opt.addr == 0 && errno == EINVAL)
592 				usage("Bad -a argument (hex)");
593 			if (i2c_opt.addr == 0 || i2c_opt.addr > 0x7f)
594 				usage("Bad -a argument (01..7f)");
595 			i2c_opt.addr <<= 1;
596 			break;
597 		case 'f':
598 			dev = optarg;
599 			break;
600 		case 'd':
601 			if (strcmp(optarg, "r") && strcmp(optarg, "w"))
602 				usage("Bad -d argument ([r|w])");
603 			i2c_opt.dir = optarg[0];
604 			break;
605 		case 'o':
606 			i2c_opt.off = strtoul(optarg, 0, 16);
607 			if (i2c_opt.off == 0 && errno == EINVAL)
608 				usage("Bad -o argument (hex)");
609 			break;
610 		case 'w':
611 			i2c_opt.width = optarg;		// checked later.
612 			break;
613 		case 'c':
614 			i2c_opt.count = (strtoul(optarg, 0, 10));
615 			if (i2c_opt.count == 0 && errno == EINVAL)
616 				usage("Bad -c argument (decimal)");
617 			break;
618 		case 'm':
619 			if (!strcmp(optarg, "no"))
620 				i2c_opt.mode = I2C_MODE_NONE;
621 			else if (!strcmp(optarg, "ss"))
622 				i2c_opt.mode = I2C_MODE_STOP_START;
623 			else if (!strcmp(optarg, "rs"))
624 				i2c_opt.mode = I2C_MODE_REPEATED_START;
625 			else if (!strcmp(optarg, "tr"))
626 				i2c_opt.mode = I2C_MODE_TRANSFER;
627 			else
628 				usage("Bad -m argument ([no|ss|rs|tr])");
629 			break;
630 		case 'n':
631 			i2c_opt.skip = optarg;
632 			break;
633 		case 's': break;
634 		case 'b':
635 			i2c_opt.binary = 1;
636 			break;
637 		case 'v':
638 			i2c_opt.verbose = 1;
639 			break;
640 		case 'r': break;
641 		default:
642 			fprintf(stderr, "Illegal -%c option", ch);
643 			usage(NULL);
644 		}
645 	}
646 	argc -= optind;
647 	argv += optind;
648 	if (argc > 0)
649 		usage("Too many arguments");
650 
651 	/* Set default mode if option -m is not specified */
652 	if (i2c_opt.mode == I2C_MODE_NOTSET) {
653 		if (i2c_opt.dir == 'r')
654 			i2c_opt.mode = I2C_MODE_STOP_START;
655 		else if (i2c_opt.dir == 'w')
656 			i2c_opt.mode = I2C_MODE_NONE;
657 	}
658 
659 	err_msg = encode_offset(i2c_opt.width, i2c_opt.off,
660 	    i2c_opt.off_buf, &i2c_opt.off_len);
661 	if (err_msg != NULL) {
662 		fprintf(stderr, "%s", err_msg);
663 		exit(EX_USAGE);
664 	}
665 
666 	if (i2c_opt.verbose)
667 		fprintf(stderr, "dev: %s, addr: 0x%x, r/w: %c, "
668 		    "offset: 0x%02x, width: %s, count: %u\n", dev,
669 		    i2c_opt.addr >> 1, i2c_opt.dir, i2c_opt.off,
670 		    i2c_opt.width, i2c_opt.count);
671 
672 	fd = open(dev, O_RDWR);
673 	if (fd == -1) {
674 		fprintf(stderr, "Error opening I2C controller (%s): %s\n",
675 		    dev, strerror(errno));
676 		return (EX_NOINPUT);
677 	}
678 
679 	switch (do_what) {
680 	case 's':
681 		error = scan_bus(dev, fd, i2c_opt.skip, i2c_opt.verbose);
682 		break;
683 	case 'r':
684 		error = reset_bus(dev, fd, i2c_opt.verbose);
685 		break;
686 	case 'a':
687 		error = access_bus(fd, i2c_opt);
688 		break;
689 	default:
690 		assert("Bad do_what");
691 	}
692 
693 	ch = close(fd);
694 	assert(ch == 0);
695 	return (error);
696 }
697