]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - usr.sbin/i2c/i2c.c
Centralize offset width handling, and make it possible to specify explicit endianess.
[FreeBSD/FreeBSD.git] / usr.sbin / i2c / i2c.c
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 <err.h>
34 #include <errno.h>
35 #include <sysexits.h>
36 #include <fcntl.h>
37 #include <stdio.h>
38 #include <stdlib.h>
39 #include <string.h>
40 #include <unistd.h>
41 #include <sys/endian.h>
42 #include <sys/ioctl.h>
43
44 #include <dev/iicbus/iic.h>
45
46 #define I2C_DEV                 "/dev/iic0"
47 #define I2C_MODE_NOTSET         0
48 #define I2C_MODE_NONE           1
49 #define I2C_MODE_STOP_START     2
50 #define I2C_MODE_REPEATED_START 3
51 #define I2C_MODE_TRANSFER       4
52
53 struct options {
54         const char      *width;
55         int             count;
56         int             verbose;
57         int             addr_set;
58         int             binary;
59         int             scan;
60         int             skip;
61         int             reset;
62         int             mode;
63         char            dir;
64         uint32_t        addr;
65         uint32_t        off;
66         uint8_t         off_buf[2];
67         size_t          off_len;
68 };
69
70 struct skip_range {
71         int     start;
72         int     end;
73 };
74
75 __dead2 static void
76 usage(void)
77 {
78
79         fprintf(stderr, "usage: %s -a addr [-f device] [-d [r|w]] [-o offset] "
80             "[-w [0|8|16]] [-c count] [-m [tr|ss|rs|no]] [-b] [-v]\n",
81             getprogname());
82         fprintf(stderr, "       %s -s [-f device] [-n skip_addr] -v\n",
83             getprogname());
84         fprintf(stderr, "       %s -r [-f device] -v\n", getprogname());
85         exit(EX_USAGE);
86 }
87
88 static struct skip_range
89 skip_get_range(char *skip_addr)
90 {
91         struct skip_range addr_range;
92         char *token;
93
94         addr_range.start = 0;
95         addr_range.end = 0;
96
97         token = strsep(&skip_addr, "..");
98         if (token) {
99                 addr_range.start = strtoul(token, 0, 16);
100                 token = strsep(&skip_addr, "..");
101                 if ((token != NULL) && !atoi(token)) {
102                         token = strsep(&skip_addr, "..");
103                         if (token)
104                                 addr_range.end = strtoul(token, 0, 16);
105                 }
106         }
107
108         return (addr_range);
109 }
110
111 /* Parse the string to get hex 7 bits addresses */
112 static int
113 skip_get_tokens(char *skip_addr, int *sk_addr, int max_index)
114 {
115         char *token;
116         int i;
117
118         for (i = 0; i < max_index; i++) {
119                 token = strsep(&skip_addr, ":");
120                 if (token == NULL)
121                         break;
122                 sk_addr[i] = strtoul(token, 0, 16);
123         }
124         return (i);
125 }
126
127 static int
128 scan_bus(const char *dev, int fd, int skip, char *skip_addr)
129 {
130         struct iiccmd cmd;
131         struct iic_msg rdmsg;
132         struct iic_rdwr_data rdwrdata;
133         struct skip_range addr_range = { 0, 0 };
134         int *tokens = NULL, error, i, idx = 0, j;
135         int len = 0, do_skip = 0, no_range = 1, num_found = 0, use_read_xfer = 0;
136         uint8_t rdbyte;
137
138         if (skip) {
139                 assert(skip_addr != NULL);
140                 len = strlen(skip_addr);
141                 if (strstr(skip_addr, "..") != NULL) {
142                         addr_range = skip_get_range(skip_addr);
143                         no_range = 0;
144                 } else {
145                         tokens = (int *)malloc((len / 2 + 1) * sizeof(int));
146                         if (tokens == NULL) {
147                                 fprintf(stderr, "Error allocating tokens "
148                                     "buffer\n");
149                                 error = -1;
150                                 goto out;
151                         }
152                         idx = skip_get_tokens(skip_addr, tokens,
153                             len / 2 + 1);
154                 }
155
156                 if (!no_range && (addr_range.start > addr_range.end)) {
157                         fprintf(stderr, "Skip address out of range\n");
158                         error = -1;
159                         goto out;
160                 }
161         }
162
163         printf("Scanning I2C devices on %s: ", dev);
164
165 start_over:
166         if (use_read_xfer) {
167                 fprintf(stderr,
168                     "Hardware may not support START/STOP scanning; "
169                     "trying less-reliable read method.\n");
170         }
171
172         for (i = 1; i < 127; i++) {
173
174                 if (skip && ( addr_range.start < addr_range.end)) {
175                         if (i >= addr_range.start && i <= addr_range.end)
176                                 continue;
177
178                 } else if (skip && no_range) {
179                         assert (tokens != NULL);
180                         for (j = 0; j < idx; j++) {
181                                 if (tokens[j] == i) {
182                                         do_skip = 1;
183                                         break;
184                                 }
185                         }
186                 }
187
188                 if (do_skip) {
189                         do_skip = 0;
190                         continue;
191                 }
192
193                 cmd.slave = i << 1;
194                 cmd.last = 1;
195                 cmd.count = 0;
196                 error = ioctl(fd, I2CRSTCARD, &cmd);
197                 if (error) {
198                         fprintf(stderr, "Controller reset failed\n");
199                         goto out;
200                 }
201                 if (use_read_xfer) {
202                         rdmsg.buf = &rdbyte;
203                         rdmsg.len = 1;
204                         rdmsg.flags = IIC_M_RD;
205                         rdmsg.slave = i << 1;
206                         rdwrdata.msgs = &rdmsg;
207                         rdwrdata.nmsgs = 1;
208                         error = ioctl(fd, I2CRDWR, &rdwrdata);
209                 } else {
210                         cmd.slave = i << 1;
211                         cmd.last = 1;
212                         error = ioctl(fd, I2CSTART, &cmd);
213                         if (errno == ENODEV || errno == EOPNOTSUPP) {
214                                 /* If START not supported try reading. */
215                                 use_read_xfer = 1;
216                                 goto start_over;
217                         }
218                         (void)ioctl(fd, I2CSTOP);
219                 }
220                 if (error == 0) {
221                         ++num_found;
222                         printf("%02x ", i);
223                 }
224         }
225
226         /*
227          * If we found nothing, maybe START is not supported and returns a
228          * generic error code such as EIO or ENXIO, so try again using reads.
229          */
230         if (num_found == 0) {
231                 if (!use_read_xfer) {
232                         use_read_xfer = 1;
233                         goto start_over;
234                 }
235                 printf("<none found>");
236         }
237         printf("\n");
238
239         error = ioctl(fd, I2CRSTCARD, &cmd);
240 out:
241         if (skip && no_range)
242                 free(tokens);
243         else
244                 assert(tokens == NULL);
245
246         if (error) {
247                 fprintf(stderr, "Error scanning I2C controller (%s): %s\n",
248                     dev, strerror(errno));
249                 return (EX_NOINPUT);
250         } else
251                 return (EX_OK);
252 }
253
254 static int
255 reset_bus(const char *dev, int fd)
256 {
257         struct iiccmd cmd;
258         int error;
259
260         printf("Resetting I2C controller on %s: ", dev);
261         error = ioctl(fd, I2CRSTCARD, &cmd);
262
263         if (error) {
264                 printf("error: %s\n", strerror(errno));
265                 return (EX_IOERR);
266         } else {
267                 printf("OK\n");
268                 return (EX_OK);
269         }
270 }
271
272 static const char *
273 encode_offset(const char *width, unsigned address, uint8_t *dst, size_t *len)
274 {
275
276         if (!strcmp(width, "0")) {
277                 *len = 0;
278                 return (NULL);
279         }
280         if (!strcmp(width, "8")) {
281                 if (address > 0xff)
282                         return ("Invalid 8-bit address\n");
283                 *dst = address;
284                 *len = 1;
285                 return (NULL);
286         }
287         if (address > 0xffff)
288                 return ("Invalid 16-bit address\n");
289         if (!strcmp(width, "16LE") || !strcmp(width, "16")) {
290                 le16enc(dst, address);
291                 *len = 2;
292                 return (NULL);
293         }
294         if (!strcmp(width, "16BE")) {
295                 be16enc(dst, address);
296                 *len = 2;
297                 return (NULL);
298         }
299         return ("Invalid offset width, must be: 0|8|16|16LE|16BE\n");
300 }
301
302 static const char *
303 write_offset(int fd, struct options i2c_opt, struct iiccmd *cmd)
304 {
305         int error;
306
307         if (i2c_opt.off_len > 0) {
308                 cmd->count = i2c_opt.off_len;
309                 cmd->buf = i2c_opt.off_buf;
310                 error = ioctl(fd, I2CWRITE, cmd);
311                 if (error == -1)
312                         return ("ioctl: error writing offset\n");
313         }
314         return (NULL);
315 }
316
317 static int
318 i2c_write(int fd, struct options i2c_opt, char *i2c_buf)
319 {
320         struct iiccmd cmd;
321         int error;
322         char *buf;
323         const char *err_msg;
324
325         cmd.slave = i2c_opt.addr;
326         error = ioctl(fd, I2CSTART, &cmd);
327         if (error == -1) {
328                 err_msg = "ioctl: error sending start condition";
329                 goto err1;
330         }
331
332         switch(i2c_opt.mode) {
333         case I2C_MODE_STOP_START:
334                 err_msg = write_offset(fd, i2c_opt, &cmd);
335                 if (err_msg != NULL)
336                         goto err1;
337
338                 error = ioctl(fd, I2CSTOP);
339                 if (error == -1) {
340                         err_msg = "ioctl: error sending stop condition";
341                         goto err2;
342                 }
343                 cmd.slave = i2c_opt.addr;
344                 error = ioctl(fd, I2CSTART, &cmd);
345                 if (error == -1) {
346                         err_msg = "ioctl: error sending start condition";
347                         goto err1;
348                 }
349
350                 /*
351                  * Write the data
352                  */
353                 cmd.count = i2c_opt.count;
354                 cmd.buf = i2c_buf;
355                 cmd.last = 0;
356                 error = ioctl(fd, I2CWRITE, &cmd);
357                 if (error == -1) {
358                         err_msg = "ioctl: error writing";
359                         goto err1;
360                 }
361                 break;
362
363         case I2C_MODE_REPEATED_START:
364                 err_msg = write_offset(fd, i2c_opt, &cmd);
365                 if (err_msg != NULL)
366                         goto err1;
367
368                 cmd.slave = i2c_opt.addr;
369                 error = ioctl(fd, I2CRPTSTART, &cmd);
370                 if (error == -1) {
371                         err_msg = "ioctl: error sending repeated start "
372                             "condition";
373                         goto err1;
374                 }
375
376                 /*
377                  * Write the data
378                  */
379                 cmd.count = i2c_opt.count;
380                 cmd.buf = i2c_buf;
381                 cmd.last = 0;
382                 error = ioctl(fd, I2CWRITE, &cmd);
383                 if (error == -1) {
384                         err_msg = "ioctl: error writing";
385                         goto err1;
386                 }
387                 break;
388
389         case I2C_MODE_NONE: /* fall through */
390         default:
391                 buf = malloc(i2c_opt.off_len + i2c_opt.count);
392                 if (buf == NULL) {
393                         err_msg = "error: data malloc";
394                         goto err1;
395                 }
396                 memcpy(buf, i2c_opt.off_buf, i2c_opt.off_len);
397
398                 memcpy(buf + i2c_opt.off_len, i2c_buf, i2c_opt.count);
399                 /*
400                  * Write offset and data
401                  */
402                 cmd.count = i2c_opt.off_len + i2c_opt.count;
403                 cmd.buf = buf;
404                 cmd.last = 0;
405                 error = ioctl(fd, I2CWRITE, &cmd);
406                 free(buf);
407                 if (error == -1) {
408                         err_msg = "ioctl: error writing";
409                         goto err1;
410                 }
411                 break;
412         }
413         error = ioctl(fd, I2CSTOP);
414         if (error == -1) {
415                 err_msg = "ioctl: error sending stop condition";
416                 goto err2;
417         }
418
419         return (0);
420
421 err1:
422         error = ioctl(fd, I2CSTOP);
423         if (error == -1)
424                 fprintf(stderr, "error sending stop condition\n");
425 err2:
426         if (err_msg)
427                 fprintf(stderr, "%s\n", err_msg);
428
429         return (1);
430 }
431
432 static int
433 i2c_read(int fd, struct options i2c_opt, char *i2c_buf)
434 {
435         struct iiccmd cmd;
436         int error;
437         char data = 0;
438         const char *err_msg;
439
440         bzero(&cmd, sizeof(cmd));
441
442         if (i2c_opt.off_len) {
443                 cmd.slave = i2c_opt.addr;
444                 cmd.count = 1;
445                 cmd.last = 0;
446                 cmd.buf = &data;
447                 error = ioctl(fd, I2CSTART, &cmd);
448                 if (error == -1) {
449                         err_msg = "ioctl: error sending start condition";
450                         goto err1;
451                 }
452
453                 err_msg = write_offset(fd, i2c_opt, &cmd);
454                 if (err_msg != NULL)
455                         goto err1;
456
457                 if (i2c_opt.mode == I2C_MODE_STOP_START) {
458                         error = ioctl(fd, I2CSTOP);
459                         if (error == -1) {
460                                 err_msg = "error sending stop condition";
461                                 goto err2;
462                         }
463                 }
464         }
465         cmd.slave = i2c_opt.addr | 1;
466         cmd.count = 1;
467         cmd.last = 0;
468         cmd.buf = &data;
469         if (i2c_opt.mode == I2C_MODE_STOP_START || i2c_opt.off_len == 0) {
470                 error = ioctl(fd, I2CSTART, &cmd);
471                 if (error == -1) {
472                         err_msg = "ioctl: error sending start condition";
473                         goto err2;
474                 }
475         } else if (i2c_opt.mode == I2C_MODE_REPEATED_START) {
476                 error = ioctl(fd, I2CRPTSTART, &cmd);
477                 if (error == -1) {
478                         err_msg = "ioctl: error sending repeated start "
479                             "condition";
480                         goto err1;
481                 }
482         }
483
484         cmd.count = i2c_opt.count;
485         cmd.buf = i2c_buf;
486         cmd.last = 1;
487         error = ioctl(fd, I2CREAD, &cmd);
488         if (error == -1) {
489                 err_msg = "ioctl: error while reading";
490                 goto err1;
491         }
492
493         error = ioctl(fd, I2CSTOP);
494         if (error == -1) {
495                 err_msg = "error sending stop condtion\n";
496                 goto err2;
497         }
498
499         return (0);
500
501 err1:
502         error = ioctl(fd, I2CSTOP);
503         if (error == -1)
504                 fprintf(stderr, "error sending stop condition\n");
505 err2:
506         if (err_msg)
507                 fprintf(stderr, "%s\n", err_msg);
508
509         return (1);
510 }
511
512 /*
513  * i2c_rdwr_transfer() - use I2CRDWR to conduct a complete i2c transfer.
514  *
515  * Some i2c hardware is unable to provide direct control over START, REPEAT-
516  * START, and STOP operations.  Such hardware can only perform a complete
517  * START-<data>-STOP or START-<data>-REPEAT-START-<data>-STOP sequence as a
518  * single operation.  The driver framework refers to this sequence as a
519  * "transfer" so we call it "transfer mode".  We assemble either one or two
520  * iic_msg structures to describe the IO operations, and hand them off to the
521  * driver to be handled as a single transfer.
522  */
523 static int
524 i2c_rdwr_transfer(int fd, struct options i2c_opt, char *i2c_buf)
525 {
526         struct iic_msg msgs[2], *msgp = msgs;
527         struct iic_rdwr_data xfer;
528         int flag = 0;
529
530         if (i2c_opt.off_len) {
531                 msgp->flags = IIC_M_WR | IIC_M_NOSTOP;
532                 msgp->slave = i2c_opt.addr;
533                 msgp->buf   = i2c_opt.off_buf;
534                 msgp->len   = i2c_opt.off_len;
535                 msgp++;
536                 flag = IIC_M_NOSTART;
537         }
538
539         /*
540          * If the transfer direction is write and we did a write of the offset
541          * above, then we need to elide the start; this transfer is just more
542          * writing that follows the one started above.  For a read, we always do
543          * a start; if we did an offset write above it'll be a repeat-start
544          * because of the NOSTOP flag used above.
545          */
546         if (i2c_opt.dir == 'w')
547                 msgp->flags = IIC_M_WR | flag;
548         else
549                 msgp->flags = IIC_M_RD;
550         msgp->slave = i2c_opt.addr;
551         msgp->len   = i2c_opt.count;
552         msgp->buf   = i2c_buf;
553         msgp++;
554
555         xfer.msgs = msgs;
556         xfer.nmsgs = msgp - msgs;
557
558         if (ioctl(fd, I2CRDWR, &xfer) == -1 )
559                 err(1, "ioctl(I2CRDWR) failed");
560
561         return (0);
562 }
563
564 int
565 main(int argc, char** argv)
566 {
567         struct options i2c_opt;
568         char *skip_addr = NULL, *i2c_buf;
569         const char *dev, *err_msg;
570         int fd, error, chunk_size, i, j, ch;
571
572         errno = 0;
573         error = 0;
574
575         /* Line-break the output every chunk_size bytes */
576         chunk_size = 16;
577
578         dev = I2C_DEV;
579
580         /* Default values */
581         i2c_opt.addr_set = 0;
582         i2c_opt.off = 0;
583         i2c_opt.verbose = 0;
584         i2c_opt.dir = 'r';      /* direction = read */
585         i2c_opt.width = "8";
586         i2c_opt.count = 1;
587         i2c_opt.binary = 0;     /* ASCII text output */
588         i2c_opt.scan = 0;       /* no bus scan */
589         i2c_opt.skip = 0;       /* scan all addresses */
590         i2c_opt.reset = 0;      /* no bus reset */
591         i2c_opt.mode = I2C_MODE_NOTSET;
592
593         while ((ch = getopt(argc, argv, "a:f:d:o:w:c:m:n:sbvrh")) != -1) {
594                 switch(ch) {
595                 case 'a':
596                         i2c_opt.addr = (strtoul(optarg, 0, 16) << 1);
597                         if (i2c_opt.addr == 0 && errno == EINVAL)
598                                 i2c_opt.addr_set = 0;
599                         else
600                                 i2c_opt.addr_set = 1;
601                         break;
602                 case 'f':
603                         dev = optarg;
604                         break;
605                 case 'd':
606                         i2c_opt.dir = optarg[0];
607                         break;
608                 case 'o':
609                         i2c_opt.off = strtoul(optarg, 0, 16);
610                         if (i2c_opt.off == 0 && errno == EINVAL)
611                                 error = 1;
612                         break;
613                 case 'w':
614                         i2c_opt.width = optarg;
615                         break;
616                 case 'c':
617                         i2c_opt.count = atoi(optarg);
618                         break;
619                 case 'm':
620                         if (!strcmp(optarg, "no"))
621                                 i2c_opt.mode = I2C_MODE_NONE;
622                         else if (!strcmp(optarg, "ss"))
623                                 i2c_opt.mode = I2C_MODE_STOP_START;
624                         else if (!strcmp(optarg, "rs"))
625                                 i2c_opt.mode = I2C_MODE_REPEATED_START;
626                         else if (!strcmp(optarg, "tr"))
627                                 i2c_opt.mode = I2C_MODE_TRANSFER;
628                         else
629                                 usage();
630                         break;
631                 case 'n':
632                         i2c_opt.skip = 1;
633                         skip_addr = optarg;
634                         break;
635                 case 's':
636                         i2c_opt.scan = 1;
637                         break;
638                 case 'b':
639                         i2c_opt.binary = 1;
640                         break;
641                 case 'v':
642                         i2c_opt.verbose = 1;
643                         break;
644                 case 'r':
645                         i2c_opt.reset = 1;
646                         break;
647                 case 'h':
648                 default:
649                         usage();
650                 }
651         }
652         argc -= optind;
653         argv += optind;
654         if (argc > 0) {
655                 fprintf(stderr, "Too many arguments\n");
656                 usage();
657         }
658
659         /* Set default mode if option -m is not specified */
660         if (i2c_opt.mode == I2C_MODE_NOTSET) {
661                 if (i2c_opt.dir == 'r')
662                         i2c_opt.mode = I2C_MODE_STOP_START;
663                 else if (i2c_opt.dir == 'w')
664                         i2c_opt.mode = I2C_MODE_NONE;
665         }
666
667         if (i2c_opt.addr_set) {
668                 err_msg = encode_offset(i2c_opt.width, i2c_opt.off,
669                     i2c_opt.off_buf, &i2c_opt.off_len);
670                 if (err_msg != NULL) {
671                         fprintf(stderr, "%s", err_msg);
672                         exit(EX_USAGE);
673                 }
674         }
675
676         /* Basic sanity check of command line arguments */
677         if (i2c_opt.scan) {
678                 if (i2c_opt.addr_set)
679                         usage();
680         } else if (i2c_opt.reset) {
681                 if (i2c_opt.addr_set)
682                         usage();
683         } else if (error) {
684                 usage();
685         }
686
687         if (i2c_opt.verbose)
688                 fprintf(stderr, "dev: %s, addr: 0x%x, r/w: %c, "
689                     "offset: 0x%02x, width: %s, count: %d\n", dev,
690                     i2c_opt.addr >> 1, i2c_opt.dir, i2c_opt.off,
691                     i2c_opt.width, i2c_opt.count);
692
693         fd = open(dev, O_RDWR);
694         if (fd == -1) {
695                 fprintf(stderr, "Error opening I2C controller (%s): %s\n",
696                     dev, strerror(errno));
697                 return (EX_NOINPUT);
698         }
699
700         if (i2c_opt.scan)
701                 exit(scan_bus(dev, fd, i2c_opt.skip, skip_addr));
702
703         if (i2c_opt.reset)
704                 exit(reset_bus(dev, fd));
705
706         i2c_buf = malloc(i2c_opt.count);
707         if (i2c_buf == NULL)
708                 err(1, "data malloc");
709
710         /*
711          * For a write, read the data to be written to the chip from stdin.
712          */
713         if (i2c_opt.dir == 'w') {
714                 if (i2c_opt.verbose && !i2c_opt.binary)
715                         fprintf(stderr, "Enter %d bytes of data: ",
716                             i2c_opt.count);
717                 for (i = 0; i < i2c_opt.count; i++) {
718                         ch = getchar();
719                         if (ch == EOF) {
720                                 free(i2c_buf);
721                                 err(1, "not enough data, exiting\n");
722                         }
723                         i2c_buf[i] = ch;
724                 }
725         }
726
727         if (i2c_opt.mode == I2C_MODE_TRANSFER)
728                 error = i2c_rdwr_transfer(fd, i2c_opt, i2c_buf);
729         else if (i2c_opt.dir == 'w')
730                 error = i2c_write(fd, i2c_opt, i2c_buf);
731         else
732                 error = i2c_read(fd, i2c_opt, i2c_buf);
733
734         if (error != 0) {
735                 free(i2c_buf);
736                 return (1);
737         }
738
739         error = close(fd);
740         assert(error == 0);
741
742         if (i2c_opt.verbose)
743                 fprintf(stderr, "\nData %s (hex):\n", i2c_opt.dir == 'r' ?
744                     "read" : "written");
745
746         i = 0;
747         j = 0;
748         while (i < i2c_opt.count) {
749                 if (i2c_opt.verbose || (i2c_opt.dir == 'r' &&
750                     !i2c_opt.binary))
751                         fprintf (stderr, "%02hhx ", i2c_buf[i++]);
752
753                 if (i2c_opt.dir == 'r' && i2c_opt.binary) {
754                         fprintf(stdout, "%c", i2c_buf[j++]);
755                         if(!i2c_opt.verbose)
756                                 i++;
757                 }
758                 if (!i2c_opt.verbose && (i2c_opt.dir == 'w'))
759                         break;
760                 if ((i % chunk_size) == 0)
761                         fprintf(stderr, "\n");
762         }
763         if ((i % chunk_size) != 0)
764                 fprintf(stderr, "\n");
765
766         free(i2c_buf);
767         return (0);
768 }