xref: /freebsd/usr.sbin/i2c/i2c.c (revision f540a43052c12c76d3453ead881248d5467a1ab0)
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 #define N_FDCACHE 128
69 static int fd_cache[N_FDCACHE];
70 
71 __dead2 static void
72 usage(const char *msg)
73 {
74 
75 	if (msg != NULL)
76 		fprintf(stderr, "%s\n", msg);
77 	fprintf(stderr, "usage: %s -a addr [-f device] [-d [r|w]] [-o offset] "
78 	    "[-w [0|8|16|16LE|16BE]] [-c count] [-m [tr|ss|rs|no]] [-b] [-v]\n",
79 	    getprogname());
80 	fprintf(stderr, "       %s -s [-f device] [-n skip_addr] -v\n",
81 	    getprogname());
82 	fprintf(stderr, "       %s -r [-f device] -v\n", getprogname());
83 	exit(EX_USAGE);
84 }
85 
86 static int
87 i2c_do_stop(int fd)
88 {
89 	int i;
90 
91 	i = ioctl(fd, I2CSTOP);
92 	if (i < 0)
93 		fprintf(stderr, "ioctl: error sending stop condition: %s\n",
94 		    strerror(errno));
95 	return (i);
96 }
97 
98 static int
99 i2c_do_start(int fd, struct iiccmd *cmd)
100 {
101 	int i;
102 
103 	i = ioctl(fd, I2CSTART, cmd);
104 	if (i < 0)
105 		fprintf(stderr, "ioctl: error sending start condition: %s\n",
106 		    strerror(errno));
107 	return (i);
108 }
109 
110 static int
111 i2c_do_repeatstart(int fd, struct iiccmd *cmd)
112 {
113 	int i;
114 
115 	i = ioctl(fd, I2CRPTSTART, cmd);
116 	if (i < 0)
117 		fprintf(stderr, "ioctl: error sending repeated start: %s\n",
118 		    strerror(errno));
119 	return (i);
120 }
121 
122 static int
123 i2c_do_write(int fd, struct iiccmd *cmd)
124 {
125 	int i;
126 
127 	i = ioctl(fd, I2CWRITE, cmd);
128 	if (i < 0)
129 		fprintf(stderr, "ioctl: error writing: %s\n",
130 		    strerror(errno));
131 	return (i);
132 }
133 
134 static int
135 i2c_do_read(int fd, struct iiccmd *cmd)
136 {
137 	int i;
138 
139 	i = ioctl(fd, I2CREAD, cmd);
140 	if (i < 0)
141 		fprintf(stderr, "ioctl: error reading: %s\n",
142 		    strerror(errno));
143 	return (i);
144 }
145 
146 static int
147 i2c_do_reset(int fd)
148 {
149 	struct iiccmd cmd;
150 	int i;
151 
152 	memset(&cmd, 0, sizeof cmd);
153 	i = ioctl(fd, I2CRSTCARD, &cmd);
154 	if (i < 0)
155 		fprintf(stderr, "ioctl: error resetting controller: %s\n",
156 		    strerror(errno));
157 	return (i);
158 }
159 
160 static void
161 parse_skip(const char *skip, char blacklist[128])
162 {
163 	const char *p;
164 	unsigned x, y;
165 
166 	for (p = skip; *p != '\0';) {
167 		if (*p == '0' && p[1] == 'x')
168 			p += 2;
169 		if (!isxdigit(*p))
170 			usage("Bad -n argument, expected (first) hex-digit");
171 		x = digittoint(*p++) << 4;
172 		if (!isxdigit(*p))
173 			usage("Bad -n argument, expected (second) hex-digit");
174 		x |= digittoint(*p++);
175 		if (x == 0 || x > 0x7f)
176 			usage("Bad -n argument, (01..7f)");
177 		if (*p == ':' || *p == ',' || *p == '\0') {
178 			blacklist[x] = 1;
179 			if (*p != '\0')
180 				p++;
181 			continue;
182 		}
183 		if (*p == '-') {
184 			p++;
185 		} else if (*p == '.' && p[1] == '.') {
186 			p += 2;
187 		} else {
188 			usage("Bad -n argument, ([:|,|..|-])");
189 		}
190 		if (*p == '0' && p[1] == 'x')
191 			p += 2;
192 		if (!isxdigit(*p))
193 			usage("Bad -n argument, expected (first) hex-digit");
194 		y = digittoint(*p++) << 4;
195 		if (!isxdigit(*p))
196 			usage("Bad -n argument, expected (second) hex-digit");
197 		y |= digittoint(*p++);
198 		if (y == 0 || y > 0x7f)
199 			usage("Bad -n argument, (01..7f)");
200 		if (y < x)
201 			usage("Bad -n argument, (end < start)");
202 		for (;x <= y; x++)
203 			blacklist[x] = 1;
204 		if (*p == ':' || *p == ',')
205 			p++;
206 	}
207 }
208 
209 static int
210 scan_bus(const char *dev, int fd, const char *skip, int verbose)
211 {
212 	struct iiccmd cmd;
213 	struct iic_msg rdmsg;
214 	struct iic_rdwr_data rdwrdata;
215 	int error;
216 	unsigned u;
217 	int num_found = 0, use_read_xfer;
218 	uint8_t rdbyte;
219 	char blacklist[128];
220 	const char *sep = "";
221 
222 	memset(blacklist, 0, sizeof blacklist);
223 
224 	if (skip != NULL)
225 		parse_skip(skip, blacklist);
226 
227 	for (use_read_xfer = 0; use_read_xfer < 2; use_read_xfer++) {
228 		for (u = 1; u < 127; u++) {
229 			if (blacklist[u])
230 				continue;
231 
232 			cmd.slave = u << 1;
233 			cmd.last = 1;
234 			cmd.count = 0;
235 			if (i2c_do_reset(fd))
236 				return (EX_NOINPUT);
237 
238 			if (use_read_xfer) {
239 				rdmsg.buf = &rdbyte;
240 				rdmsg.len = 1;
241 				rdmsg.flags = IIC_M_RD;
242 				rdmsg.slave = u << 1;
243 				rdwrdata.msgs = &rdmsg;
244 				rdwrdata.nmsgs = 1;
245 				error = ioctl(fd, I2CRDWR, &rdwrdata);
246 			} else {
247 				error = ioctl(fd, I2CSTART, &cmd);
248 				if (errno == ENODEV || errno == EOPNOTSUPP)
249 					break; /* Try reads instead */
250 				(void)ioctl(fd, I2CSTOP);
251 			}
252 			if (error == 0) {
253 				if (!num_found++ && verbose) {
254 					fprintf(stderr,
255 					    "Scanning I2C devices on %s:\n",
256 					    dev);
257 				}
258 				printf("%s%02x", sep, u);
259 				sep = " ";
260 			}
261 		}
262 		if (num_found > 0)
263 			break;
264 		if (verbose && !use_read_xfer)
265 			fprintf(stderr,
266 			    "Hardware may not support START/STOP scanning; "
267 			    "trying less-reliable read method.\n");
268 	}
269 	if (num_found == 0 && verbose)
270 		printf("<Nothing Found>");
271 
272 	printf("\n");
273 
274 	return (i2c_do_reset(fd));
275 }
276 
277 static int
278 reset_bus(const char *dev, int fd, int verbose)
279 {
280 
281 	if (verbose)
282 		fprintf(stderr, "Resetting I2C controller on %s\n", dev);
283 	return (i2c_do_reset(fd));
284 }
285 
286 static const char *
287 encode_offset(const char *width, unsigned offset, uint8_t *dst, size_t *len)
288 {
289 
290 	if (!strcmp(width, "0")) {
291 		*len = 0;
292 		return (NULL);
293 	}
294 	if (!strcmp(width, "8")) {
295 		if (offset > 0xff)
296 			return ("Invalid 8-bit offset\n");
297 		*dst = offset;
298 		*len = 1;
299 		return (NULL);
300 	}
301 	if (offset > 0xffff)
302 		return ("Invalid 16-bit offset\n");
303 	if (!strcmp(width, "16LE") || !strcmp(width, "16")) {
304 		le16enc(dst, offset);
305 		*len = 2;
306 		return (NULL);
307 	}
308 	if (!strcmp(width, "16BE")) {
309 		be16enc(dst, offset);
310 		*len = 2;
311 		return (NULL);
312 	}
313 	return ("Invalid offset width, must be: 0|8|16|16LE|16BE\n");
314 }
315 
316 static int
317 write_offset(int fd, struct options i2c_opt, struct iiccmd *cmd)
318 {
319 
320 	if (i2c_opt.off_len > 0) {
321 		cmd->count = i2c_opt.off_len;
322 		cmd->buf = (void*)i2c_opt.off_buf;
323 		return (i2c_do_write(fd, cmd));
324 	}
325 	return (0);
326 }
327 
328 static int
329 i2c_write(int fd, struct options i2c_opt, uint8_t *i2c_buf)
330 {
331 	struct iiccmd cmd;
332 	char buf[i2c_opt.off_len + i2c_opt.count];
333 
334 	memset(&cmd, 0, sizeof(cmd));
335 	cmd.slave = i2c_opt.addr;
336 
337 	if (i2c_do_start(fd, &cmd))
338 		return (i2c_do_stop(fd) | 1);
339 
340 	switch(i2c_opt.mode) {
341 	case I2C_MODE_STOP_START:
342 		if (write_offset(fd, i2c_opt, &cmd))
343 			return (i2c_do_stop(fd) | 1);
344 
345 		if (i2c_do_stop(fd))
346 			return (1);
347 
348 		if (i2c_do_start(fd, &cmd))
349 			return (i2c_do_stop(fd) | 1);
350 
351 		/*
352 		 * Write the data
353 		 */
354 		cmd.count = i2c_opt.count;
355 		cmd.buf = (void*)i2c_buf;
356 		cmd.last = 0;
357 		if (i2c_do_write(fd, &cmd))
358 			return (i2c_do_stop(fd) | 1);
359 		break;
360 
361 	case I2C_MODE_REPEATED_START:
362 		if (write_offset(fd, i2c_opt, &cmd))
363 			return (i2c_do_stop(fd) | 1);
364 
365 		if (i2c_do_repeatstart(fd, &cmd))
366 			return (i2c_do_stop(fd) | 1);
367 
368 		/*
369 		 * Write the data
370 		 */
371 		cmd.count = i2c_opt.count;
372 		cmd.buf = (void*)i2c_buf;
373 		cmd.last = 0;
374 		if (i2c_do_write(fd, &cmd))
375 			return (i2c_do_stop(fd) | 1);
376 		break;
377 
378 	case I2C_MODE_NONE: /* fall through */
379 	default:
380 		memcpy(buf, i2c_opt.off_buf, i2c_opt.off_len);
381 		memcpy(buf + i2c_opt.off_len, i2c_buf, i2c_opt.count);
382 		/*
383 		 * Write offset and data
384 		 */
385 		cmd.count = i2c_opt.off_len + i2c_opt.count;
386 		cmd.buf = (void*)buf;
387 		cmd.last = 0;
388 		if (i2c_do_write(fd, &cmd))
389 			return (i2c_do_stop(fd) | 1);
390 		break;
391 	}
392 
393 	return (i2c_do_stop(fd));
394 }
395 
396 static int
397 i2c_read(int fd, struct options i2c_opt, uint8_t *i2c_buf)
398 {
399 	struct iiccmd cmd;
400 	char data = 0;
401 
402 	memset(&cmd, 0, sizeof(cmd));
403 	cmd.slave = i2c_opt.addr;
404 
405 	if (i2c_opt.off_len) {
406 		cmd.count = 1;
407 		cmd.last = 0;
408 		cmd.buf = &data;
409 		if (i2c_do_start(fd, &cmd))
410 			return (i2c_do_stop(fd) | 1);
411 
412 		if (write_offset(fd, i2c_opt, &cmd))
413 			return (i2c_do_stop(fd) | 1);
414 
415 		if (i2c_opt.mode == I2C_MODE_STOP_START && i2c_do_stop(fd))
416 			return (1);
417 	}
418 	cmd.slave = i2c_opt.addr | 1;
419 	cmd.count = 1;
420 	cmd.last = 0;
421 	cmd.buf = &data;
422 	if (i2c_opt.mode == I2C_MODE_STOP_START || i2c_opt.off_len == 0) {
423 		if (i2c_do_start(fd, &cmd))
424 			return (i2c_do_stop(fd) | 1);
425 	} else if (i2c_opt.mode == I2C_MODE_REPEATED_START) {
426 		if (i2c_do_repeatstart(fd, &cmd))
427 			return (i2c_do_stop(fd) | 1);
428 	}
429 
430 	cmd.count = i2c_opt.count;
431 	cmd.buf = (void*)i2c_buf;
432 	cmd.last = 1;
433 	if (i2c_do_read(fd, &cmd))
434 		return (i2c_do_stop(fd) | 1);
435 
436 	return (i2c_do_stop(fd));
437 }
438 
439 /*
440  * i2c_rdwr_transfer() - use I2CRDWR to conduct a complete i2c transfer.
441  *
442  * Some i2c hardware is unable to provide direct control over START, REPEAT-
443  * START, and STOP operations.  Such hardware can only perform a complete
444  * START-<data>-STOP or START-<data>-REPEAT-START-<data>-STOP sequence as a
445  * single operation.  The driver framework refers to this sequence as a
446  * "transfer" so we call it "transfer mode".  We assemble either one or two
447  * iic_msg structures to describe the IO operations, and hand them off to the
448  * driver to be handled as a single transfer.
449  */
450 static int
451 i2c_rdwr_transfer(int fd, struct options i2c_opt, uint8_t *i2c_buf)
452 {
453 	struct iic_msg msgs[2], *msgp = msgs;
454 	struct iic_rdwr_data xfer;
455 	int flag = 0;
456 
457 	if (i2c_opt.off_len) {
458 		msgp->flags = IIC_M_WR | IIC_M_NOSTOP;
459 		msgp->slave = i2c_opt.addr;
460 		msgp->buf   = i2c_opt.off_buf;
461 		msgp->len   = i2c_opt.off_len;
462 		msgp++;
463 		flag = IIC_M_NOSTART;
464 	}
465 
466 	/*
467 	 * If the transfer direction is write and we did a write of the offset
468 	 * above, then we need to elide the start; this transfer is just more
469 	 * writing that follows the one started above.  For a read, we always do
470 	 * a start; if we did an offset write above it'll be a repeat-start
471 	 * because of the NOSTOP flag used above.
472 	 */
473 	if (i2c_opt.dir == 'w')
474 		msgp->flags = IIC_M_WR | flag;
475 	else
476 		msgp->flags = IIC_M_RD;
477 	msgp->slave = i2c_opt.addr;
478 	msgp->len   = i2c_opt.count;
479 	msgp->buf   = i2c_buf;
480 	msgp++;
481 
482 	xfer.msgs = msgs;
483 	xfer.nmsgs = msgp - msgs;
484 
485 	if (ioctl(fd, I2CRDWR, &xfer) == -1 )
486 		err(1, "ioctl(I2CRDWR) failed");
487 
488 	return (0);
489 }
490 
491 static int
492 access_bus(int fd, struct options i2c_opt)
493 {
494 	uint8_t i2c_buf[i2c_opt.count];
495 	int error;
496 	unsigned u, chunk_size = 16;
497 
498 	/*
499 	 * For a write, read the data to be written to the chip from stdin.
500 	 */
501 	if (i2c_opt.dir == 'w') {
502 		if (i2c_opt.verbose && !i2c_opt.binary)
503 			fprintf(stderr, "Enter %u bytes of data: ",
504 			    i2c_opt.count);
505 		if (fread(i2c_buf, 1, i2c_opt.count, stdin) != i2c_opt.count)
506 			err(1, "not enough data, exiting\n");
507 	}
508 
509 	if (i2c_opt.mode == I2C_MODE_TRANSFER)
510 		error = i2c_rdwr_transfer(fd, i2c_opt, i2c_buf);
511 	else if (i2c_opt.dir == 'w')
512 		error = i2c_write(fd, i2c_opt, i2c_buf);
513 	else
514 		error = i2c_read(fd, i2c_opt, i2c_buf);
515 
516 	if (error == 0) {
517 		if (i2c_opt.dir == 'r' && i2c_opt.binary) {
518 			(void)fwrite(i2c_buf, 1, i2c_opt.count, stdout);
519 		} else if (i2c_opt.verbose || i2c_opt.dir == 'r') {
520 			if (i2c_opt.verbose)
521 				fprintf(stderr, "\nData %s (hex):\n",
522 				    i2c_opt.dir == 'r' ?  "read" : "written");
523 
524 			for (u = 0; u < i2c_opt.count; u++) {
525 				printf("%02hhx ", i2c_buf[u]);
526 				if ((u % chunk_size) == chunk_size - 1)
527 					printf("\n");
528 			}
529 			if ((u % chunk_size) != 0)
530 				printf("\n");
531 		}
532 	}
533 
534 	return (error);
535 }
536 
537 static const char *widths[] = {
538 	"0",
539 	"8",
540 	"16LE",
541 	"16BE",
542 	"16",
543 	NULL,
544 };
545 
546 static int
547 command_bus(struct options i2c_opt, char *cmd)
548 {
549 	int error, fd;
550 	char devbuf[64];
551 	uint8_t dbuf[BUFSIZ];
552 	unsigned bus;
553 	const char *width = NULL;
554 	const char *err_msg;
555 	unsigned offset;
556 	unsigned u;
557 	size_t length;
558 
559 	while (isspace(*cmd))
560 		cmd++;
561 
562 	switch(*cmd) {
563 	case 0:
564 	case '#':
565 		return (0);
566 	case 'p':
567 	case 'P':
568 		printf("%s", cmd);
569 		return (0);
570 	case 'r':
571 	case 'R':
572 		i2c_opt.dir = 'r';
573 		break;
574 	case 'w':
575 	case 'W':
576 		i2c_opt.dir = 'w';
577 		break;
578 	default:
579 		fprintf(stderr,
580 		    "Did not understand command: 0x%02x ", *cmd);
581 		if (isgraph(*cmd))
582 			fprintf(stderr, "'%c'", *cmd);
583 		fprintf(stderr, "\n");
584 		return(-1);
585 	}
586 	cmd++;
587 
588 	bus = strtoul(cmd, &cmd, 0);
589 	if (bus == 0 && errno == EINVAL) {
590 		fprintf(stderr, "Could not translate bus number\n");
591 		return(-1);
592 	}
593 
594 	i2c_opt.addr = strtoul(cmd, &cmd, 0);
595 	if (i2c_opt.addr == 0 && errno == EINVAL) {
596 		fprintf(stderr, "Could not translate device\n");
597 		return(-1);
598 	}
599 	if (i2c_opt.addr < 1 || i2c_opt.addr > 0x7f) {
600 		fprintf(stderr, "Invalid device (0x%x)\n", i2c_opt.addr);
601 		return(-1);
602 	}
603 	i2c_opt.addr <<= 1;
604 
605 	while(isspace(*cmd))
606 		cmd++;
607 
608 	for(u = 0; widths[u]; u++) {
609 		length = strlen(widths[u]);
610 		if (memcmp(cmd, widths[u], length))
611 			continue;
612 		if (!isspace(cmd[length]))
613 			continue;
614 		width = widths[u];
615 		cmd += length;
616 		break;
617 	}
618 	if (width == NULL) {
619 		fprintf(stderr, "Invalid width\n");
620 		return(-1);
621 	}
622 
623 	offset = strtoul(cmd, &cmd, 0);
624 	if (offset == 0 && errno == EINVAL) {
625 		fprintf(stderr, "Could not translate offset\n");
626 		return(-1);
627 	}
628 
629 	err_msg = encode_offset(width, offset,
630 	    i2c_opt.off_buf, &i2c_opt.off_len);
631 	if (err_msg) {
632 		fprintf(stderr, "%s", err_msg);
633 		return(-1);
634 	}
635 
636 	if (i2c_opt.dir == 'r') {
637 		i2c_opt.count = strtoul(cmd, &cmd, 0);
638 		if (i2c_opt.count == 0 && errno == EINVAL) {
639 			fprintf(stderr, "Could not translate length\n");
640 			return(-1);
641 		}
642 	} else {
643 		i2c_opt.count = 0;
644 		while (1) {
645 			while(isspace(*cmd))
646 				cmd++;
647 			if (!*cmd)
648 				break;
649 			if (!isxdigit(*cmd)) {
650 				fprintf(stderr, "Not a hex digit.\n");
651 				return(-1);
652 			}
653 			dbuf[i2c_opt.count] = digittoint(*cmd++) << 4;
654 			while(isspace(*cmd))
655 				cmd++;
656 			if (!*cmd) {
657 				fprintf(stderr,
658 				    "Uneven number of hex digits.\n");
659 				return(-1);
660 			}
661 			if (!isxdigit(*cmd)) {
662 				fprintf(stderr, "Not a hex digit.\n");
663 				return(-1);
664 			}
665 			dbuf[i2c_opt.count++] |= digittoint(*cmd++);
666 		}
667 	}
668 	assert(bus < N_FDCACHE);
669 	fd = fd_cache[bus];
670 	if (fd < 0) {
671 		(void)sprintf(devbuf, "/dev/iic%u", bus);
672 		fd = open(devbuf, O_RDWR);
673 		if (fd == -1) {
674 			fprintf(stderr, "Error opening I2C controller (%s): %s\n",
675 			    devbuf, strerror(errno));
676 			return (EX_NOINPUT);
677 		}
678 		fd_cache[bus] = fd;
679 	}
680 
681 	error = i2c_rdwr_transfer(fd, i2c_opt, dbuf);
682 	if (error)
683 		return(-1);
684 
685 	if (i2c_opt.dir == 'r') {
686 		for (u = 0; u < i2c_opt.count; u++)
687 			printf("%02x", dbuf[u]);
688 		printf("\n");
689 	}
690 	return (0);
691 }
692 
693 static int
694 exec_bus(struct options i2c_opt, char *cmd)
695 {
696 	int error;
697 
698 	while (isspace(*cmd))
699 		cmd++;
700 	if (*cmd == '#' || *cmd == '\0')
701 		return (0);
702 	error = command_bus(i2c_opt, cmd);
703 	if (i2c_opt.verbose) {
704 		(void)fflush(stderr);
705 		printf(error ? "ERROR\n" : "OK\n");
706 		error = 0;
707 	} else if (error) {
708 		fprintf(stderr, "  in: %s", cmd);
709 	}
710 	(void)fflush(stdout);
711 	return (error);
712 }
713 
714 static int
715 instruct_bus(struct options i2c_opt, int argc, char **argv)
716 {
717 	char buf[BUFSIZ];
718 	int rd_cmds = (argc == 0);
719 	int error;
720 
721 	while (argc-- > 0) {
722 		if (argc == 0 && !strcmp(*argv, "-")) {
723 			rd_cmds = 1;
724 		} else {
725 			error = exec_bus(i2c_opt, *argv);
726 			if (error)
727 				return (error);
728 		}
729 		argv++;
730 	}
731 	if (!rd_cmds)
732 		return (0);
733 	while (fgets(buf, sizeof buf, stdin) != NULL) {
734 		error = exec_bus(i2c_opt, buf);
735 		if (error)
736 			return (error);
737 	}
738 	return (0);
739 }
740 
741 int
742 main(int argc, char** argv)
743 {
744 	struct options i2c_opt;
745 	const char *dev, *err_msg;
746 	int fd, error = 0, ch;
747 	const char *optflags = "a:f:d:o:iw:c:m:n:sbvrh";
748 	char do_what = 0;
749 
750 	dev = I2C_DEV;
751 	for (ch = 0; ch < N_FDCACHE; ch++)
752 		fd_cache[ch] = -1;
753 
754 	/* Default values */
755 	i2c_opt.off = 0;
756 	i2c_opt.verbose = 0;
757 	i2c_opt.dir = 'r';	/* direction = read */
758 	i2c_opt.width = "8";
759 	i2c_opt.count = 1;
760 	i2c_opt.binary = 0;	/* ASCII text output */
761 	i2c_opt.skip = NULL;	/* scan all addresses */
762 	i2c_opt.mode = I2C_MODE_TRANSFER;
763 
764 	/* Find out what we are going to do */
765 
766 	while ((ch = getopt(argc, argv, optflags)) != -1) {
767 		switch(ch) {
768 		case 'a':
769 		case 'i':
770 		case 'r':
771 		case 's':
772 			if (do_what)
773 				usage("Only one of [-a|-h|-r|-s]");
774 			do_what = ch;
775 			break;
776 		case 'h':
777 			usage("Help:");
778 			break;
779 		default:
780 			break;
781 		}
782 	}
783 
784 	/* Then handle the legal subset of arguments */
785 
786 	switch (do_what) {
787 	case 0: usage("Pick one of [-a|-h|-i|-r|-s]"); break;
788 	case 'a': optflags = "a:f:d:w:o:c:m:bv"; break;
789 	case 'i': optflags = "iv"; break;
790 	case 'r': optflags = "rf:v"; break;
791 	case 's': optflags = "sf:n:v"; break;
792 	default: assert("Bad do_what");
793 	}
794 
795 	optreset = 1;
796 	optind = 1;
797 
798 	while ((ch = getopt(argc, argv, optflags)) != -1) {
799 		switch(ch) {
800 		case 'a':
801 			i2c_opt.addr = strtoul(optarg, 0, 16);
802 			if (i2c_opt.addr == 0 && errno == EINVAL)
803 				usage("Bad -a argument (hex)");
804 			if (i2c_opt.addr == 0 || i2c_opt.addr > 0x7f)
805 				usage("Bad -a argument (01..7f)");
806 			i2c_opt.addr <<= 1;
807 			break;
808 		case 'b':
809 			i2c_opt.binary = 1;
810 			break;
811 		case 'c':
812 			i2c_opt.count = (strtoul(optarg, 0, 10));
813 			if (i2c_opt.count == 0 && errno == EINVAL)
814 				usage("Bad -c argument (decimal)");
815 			break;
816 		case 'd':
817 			if (strcmp(optarg, "r") && strcmp(optarg, "w"))
818 				usage("Bad -d argument ([r|w])");
819 			i2c_opt.dir = optarg[0];
820 			break;
821 		case 'f':
822 			dev = optarg;
823 			break;
824 		case 'i': break;
825 		case 'm':
826 			if (!strcmp(optarg, "no"))
827 				i2c_opt.mode = I2C_MODE_NONE;
828 			else if (!strcmp(optarg, "ss"))
829 				i2c_opt.mode = I2C_MODE_STOP_START;
830 			else if (!strcmp(optarg, "rs"))
831 				i2c_opt.mode = I2C_MODE_REPEATED_START;
832 			else if (!strcmp(optarg, "tr"))
833 				i2c_opt.mode = I2C_MODE_TRANSFER;
834 			else
835 				usage("Bad -m argument ([no|ss|rs|tr])");
836 			break;
837 		case 'n':
838 			i2c_opt.skip = optarg;
839 			break;
840 		case 'o':
841 			i2c_opt.off = strtoul(optarg, 0, 16);
842 			if (i2c_opt.off == 0 && errno == EINVAL)
843 				usage("Bad -o argument (hex)");
844 			break;
845 		case 'r': break;
846 		case 's': break;
847 		case 'v':
848 			i2c_opt.verbose = 1;
849 			break;
850 		case 'w':
851 			i2c_opt.width = optarg;		// checked later.
852 			break;
853 		default:
854 			fprintf(stderr, "Illegal -%c option", ch);
855 			usage(NULL);
856 		}
857 	}
858 	argc -= optind;
859 	argv += optind;
860 	if (do_what == 'i')
861 		return(instruct_bus(i2c_opt, argc, argv));
862 	if (argc > 0)
863 		usage("Too many arguments");
864 
865 	/* Set default mode if option -m is not specified */
866 	if (i2c_opt.mode == I2C_MODE_NOTSET) {
867 		if (i2c_opt.dir == 'r')
868 			i2c_opt.mode = I2C_MODE_STOP_START;
869 		else if (i2c_opt.dir == 'w')
870 			i2c_opt.mode = I2C_MODE_NONE;
871 	}
872 
873 	err_msg = encode_offset(i2c_opt.width, i2c_opt.off,
874 	    i2c_opt.off_buf, &i2c_opt.off_len);
875 	if (err_msg != NULL) {
876 		fprintf(stderr, "%s", err_msg);
877 		return(EX_USAGE);
878 	}
879 
880 	if (i2c_opt.verbose)
881 		fprintf(stderr, "dev: %s, addr: 0x%x, r/w: %c, "
882 		    "offset: 0x%02x, width: %s, count: %u\n", dev,
883 		    i2c_opt.addr >> 1, i2c_opt.dir, i2c_opt.off,
884 		    i2c_opt.width, i2c_opt.count);
885 
886 	fd = open(dev, O_RDWR);
887 	if (fd == -1) {
888 		fprintf(stderr, "Error opening I2C controller (%s): %s\n",
889 		    dev, strerror(errno));
890 		return (EX_NOINPUT);
891 	}
892 
893 	switch (do_what) {
894 	case 'a':
895 		error = access_bus(fd, i2c_opt);
896 		break;
897 	case 's':
898 		error = scan_bus(dev, fd, i2c_opt.skip, i2c_opt.verbose);
899 		break;
900 	case 'r':
901 		error = reset_bus(dev, fd, i2c_opt.verbose);
902 		break;
903 	default:
904 		assert("Bad do_what");
905 	}
906 
907 	ch = close(fd);
908 	assert(ch == 0);
909 	return (error);
910 }
911