]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - usr.sbin/i2c/i2c.c
ntp: import ntp-4.2.8p16
[FreeBSD/FreeBSD.git] / usr.sbin / i2c / i2c.c
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 __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 }