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