]> CyberLeo.Net >> Repos - FreeBSD/releng/10.2.git/blob - usr.sbin/i2c/i2c.c
- Copy stable/10@285827 to releng/10.2 in preparation for 10.2-RC1
[FreeBSD/releng/10.2.git] / usr.sbin / i2c / i2c.c
1 /*-
2  * Copyright (C) 2008-2009 Semihalf, Michal Hajduk and Bartlomiej Sieka
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  * 1. Redistributions of source code must retain the above copyright
9  *    notice, this list of conditions and the following disclaimer.
10  * 2. Redistributions in binary form must reproduce the above copyright
11  *    notice, this list of conditions and the following disclaimer in the
12  *    documentation and/or other materials provided with the distribution.
13  *
14  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17  * ARE DISCLAIMED.  IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE
18  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24  * SUCH DAMAGE.
25  */
26
27 #include <sys/cdefs.h>
28 __FBSDID("$FreeBSD$");
29
30 #include <err.h>
31 #include <errno.h>
32 #include <sysexits.h>
33 #include <fcntl.h>
34 #include <stdio.h>
35 #include <stdlib.h>
36 #include <string.h>
37 #include <stdarg.h>
38 #include <unistd.h>
39 #include <sys/ioctl.h>
40
41 #include <dev/iicbus/iic.h>
42
43 #define I2C_DEV                 "/dev/iic0"
44 #define I2C_MODE_NOTSET         0
45 #define I2C_MODE_NONE           1
46 #define I2C_MODE_STOP_START     2
47 #define I2C_MODE_REPEATED_START 3
48
49 struct options {
50         int     width;
51         int     count;
52         int     verbose;
53         int     addr_set;
54         int     binary;
55         int     scan;
56         int     skip;
57         int     reset;
58         int     mode;
59         char    dir;
60         uint32_t        addr;
61         uint32_t        off;
62 };
63
64 struct skip_range {
65         int     start;
66         int     end;
67 };
68
69 __dead2 static void
70 usage(void)
71 {
72
73         fprintf(stderr, "usage: %s -a addr [-f device] [-d [r|w]] [-o offset] "
74             "[-w [0|8|16]] [-c count] [-m [ss|rs|no]] [-b] [-v]\n",
75             getprogname());
76         fprintf(stderr, "       %s -s [-f device] [-n skip_addr] -v\n",
77             getprogname());
78         fprintf(stderr, "       %s -r [-f device] -v\n", getprogname());
79         exit(EX_USAGE);
80 }
81
82 static struct skip_range
83 skip_get_range(char *skip_addr)
84 {
85         struct skip_range addr_range;
86         char *token;
87
88         addr_range.start = 0;
89         addr_range.end = 0;
90
91         token = strsep(&skip_addr, "..");
92         if (token) {
93                 addr_range.start = strtoul(token, 0, 16);
94                 token = strsep(&skip_addr, "..");
95                 if ((token != NULL) && !atoi(token)) {
96                         token = strsep(&skip_addr, "..");
97                         if (token)
98                                 addr_range.end = strtoul(token, 0, 16);
99                 }
100         }
101
102         return (addr_range);
103 }
104
105 /* Parse the string to get hex 7 bits addresses */
106 static int
107 skip_get_tokens(char *skip_addr, int *sk_addr, int max_index)
108 {
109         char *token;
110         int i;
111
112         for (i = 0; i < max_index; i++) {
113                 token = strsep(&skip_addr, ":");
114                 if (token == NULL)
115                         break;
116                 sk_addr[i] = strtoul(token, 0, 16);
117         }
118         return (i);
119 }
120
121 static int
122 scan_bus(struct iiccmd cmd, char *dev, int skip, char *skip_addr)
123 {
124         struct skip_range addr_range = { 0, 0 };
125         int *tokens, fd, error, i, index, j;
126         int len = 0, do_skip = 0, no_range = 1;
127
128         fd = open(dev, O_RDWR);
129         if (fd == -1) {
130                 fprintf(stderr, "Error opening I2C controller (%s) for "
131                     "scanning: %s\n", dev, strerror(errno));
132                 return (EX_NOINPUT);
133         }
134
135         if (skip) {
136                 len = strlen(skip_addr);
137                 if (strstr(skip_addr, "..") != NULL) {
138                         addr_range = skip_get_range(skip_addr);
139                         no_range = 0;
140                 } else {
141                         tokens = (int *)malloc((len / 2 + 1) * sizeof(int));
142                         if (tokens == NULL) {
143                                 fprintf(stderr, "Error allocating tokens "
144                                     "buffer\n");
145                                 error = -1;
146                                 goto out;
147                         }
148                         index = skip_get_tokens(skip_addr, tokens,
149                             len / 2 + 1);
150                 }
151
152                 if (!no_range && (addr_range.start > addr_range.end)) {
153                         fprintf(stderr, "Skip address out of range\n");
154                         error = -1;
155                         goto out;
156                 }
157         }
158
159         printf("Scanning I2C devices on %s: ", dev);
160         for (i = 1; i < 127; i++) {
161
162                 if (skip && ( addr_range.start < addr_range.end)) {
163                         if (i >= addr_range.start && i <= addr_range.end)
164                                 continue;
165
166                 } else if (skip && no_range)
167                         for (j = 0; j < index; j++) {
168                                 if (tokens[j] == i) {
169                                         do_skip = 1;
170                                         break;
171                                 }
172                         }
173
174                 if (do_skip) {
175                         do_skip = 0;
176                         continue;
177                 }
178
179                 cmd.slave = i << 1;
180                 cmd.last = 1;
181                 cmd.count = 0;
182                 error = ioctl(fd, I2CRSTCARD, &cmd);
183                 if (error)
184                         goto out;
185
186                 cmd.slave = i << 1;
187                 cmd.last = 1;
188                 error = ioctl(fd, I2CSTART, &cmd);
189                 if (!error)
190                         printf("%x ", i);
191                 cmd.slave = i << 1;
192                 cmd.last = 1;
193                 error = ioctl(fd, I2CSTOP, &cmd);
194         }
195         printf("\n");
196
197         error = ioctl(fd, I2CRSTCARD, &cmd);
198 out:
199         close(fd);
200         if (skip && no_range)
201                 free(tokens);
202
203         if (error) {
204                 fprintf(stderr, "Error scanning I2C controller (%s): %s\n",
205                     dev, strerror(errno));
206                 return (EX_NOINPUT);
207         } else
208                 return (EX_OK);
209 }
210
211 static int
212 reset_bus(struct iiccmd cmd, char *dev)
213 {
214         int fd, error;
215
216         fd = open(dev, O_RDWR);
217         if (fd == -1) {
218                 fprintf(stderr, "Error opening I2C controller (%s) for "
219                     "resetting: %s\n", dev, strerror(errno));
220                 return (EX_NOINPUT);
221         }
222
223         printf("Resetting I2C controller on %s: ", dev);
224         error = ioctl(fd, I2CRSTCARD, &cmd);
225         close (fd);
226
227         if (error) {
228                 printf("error: %s\n", strerror(errno));
229                 return (EX_IOERR);
230         } else {
231                 printf("OK\n");
232                 return (EX_OK);
233         }
234 }
235
236 static char *
237 prepare_buf(int size, uint32_t off)
238 {
239         char *buf;
240
241         buf = malloc(size);
242         if (buf == NULL)
243                 return (buf);
244
245         if (size == 1)
246                 buf[0] = off & 0xff;
247         else if (size == 2) {
248                 buf[0] = (off >> 8) & 0xff;
249                 buf[1] = off & 0xff;
250         }
251
252         return (buf);
253 }
254
255 static int
256 i2c_write(char *dev, struct options i2c_opt, char *i2c_buf)
257 {
258         struct iiccmd cmd;
259         int ch, i, error, fd, bufsize;
260         char *err_msg, *buf;
261
262         /*
263          * Read data to be written to the chip from stdin
264          */
265         if (i2c_opt.verbose && !i2c_opt.binary)
266                 fprintf(stderr, "Enter %u bytes of data: ", i2c_opt.count);
267
268         for (i = 0; i < i2c_opt.count; i++) {
269                 ch = getchar();
270                 if (ch == EOF) {
271                         free(i2c_buf);
272                         err(1, "not enough data, exiting\n");
273                 }
274                 i2c_buf[i] = ch;
275         }
276
277         fd = open(dev, O_RDWR);
278         if (fd == -1) {
279                 free(i2c_buf);
280                 err(1, "open failed");
281         }
282
283         /*
284          * Write offset where the data will go
285          */
286         cmd.slave = i2c_opt.addr;
287         error = ioctl(fd, I2CSTART, &cmd);
288         if (error == -1) {
289                 err_msg = "ioctl: error sending start condition";
290                 goto err1;
291         }
292
293         if (i2c_opt.width) {
294                 bufsize = i2c_opt.width / 8;
295                 buf = prepare_buf(bufsize, i2c_opt.off);
296                 if (buf == NULL) {
297                         err_msg = "error: offset malloc";
298                         goto err1;
299                 }
300
301                 cmd.count = bufsize;
302                 cmd.buf = buf;
303                 error = ioctl(fd, I2CWRITE, &cmd);
304                 free(buf);
305                 if (error == -1) {
306                         err_msg = "ioctl: error when write offset";
307                         goto err1;
308                 }
309         }
310
311         /* Mode - stop start */
312         if (i2c_opt.mode == I2C_MODE_STOP_START) {
313                 cmd.slave = i2c_opt.addr;
314                 error = ioctl(fd, I2CSTOP, &cmd);
315                 if (error == -1) {
316                         err_msg = "ioctl: error sending stop condition";
317                         goto err2;
318                 }
319                 cmd.slave = i2c_opt.addr;
320                 error = ioctl(fd, I2CSTART, &cmd);
321                 if (error == -1) {
322                         err_msg = "ioctl: error sending start condition";
323                         goto err1;
324                 }
325         }
326         /* Mode - repeated start */
327         if (i2c_opt.mode == I2C_MODE_REPEATED_START) {
328                 cmd.slave = i2c_opt.addr;
329                 error = ioctl(fd, I2CRPTSTART, &cmd);
330                 if (error == -1) {
331                         err_msg = "ioctl: error sending repeated start "
332                             "condition";
333                         goto err1;
334                 }
335         }
336
337         /*
338          * Write the data
339          */
340         cmd.count = i2c_opt.count;
341         cmd.buf = i2c_buf;
342         cmd.last = 0;
343         error = ioctl(fd, I2CWRITE, &cmd);
344         if (error == -1) {
345                 err_msg = "ioctl: error when write";
346                 goto err1;
347         }
348         cmd.slave = i2c_opt.addr;
349         error = ioctl(fd, I2CSTOP, &cmd);
350         if (error == -1) {
351                 err_msg = "ioctl: error sending stop condition";
352                 goto err2;
353         }
354
355         close(fd);
356         return (0);
357
358 err1:
359         cmd.slave = i2c_opt.addr;
360         error = ioctl(fd, I2CSTOP, &cmd);
361         if (error == -1)
362                 fprintf(stderr, "error sending stop condtion\n");
363 err2:
364         if (err_msg)
365                 fprintf(stderr, "%s", err_msg);
366
367         close(fd);
368         return (1);
369 }
370
371 static int
372 i2c_read(char *dev, struct options i2c_opt, char *i2c_buf)
373 {
374         struct iiccmd cmd;
375         int i, fd, error, bufsize;
376         char *err_msg, data = 0, *buf;
377
378         fd = open(dev, O_RDWR);
379         if (fd == -1)
380                 err(1, "open failed");
381
382         bzero(&cmd, sizeof(cmd));
383
384         if (i2c_opt.width) {
385                 cmd.slave = i2c_opt.addr;
386                 cmd.count = 1;
387                 cmd.last = 0;
388                 cmd.buf = &data;
389                 error = ioctl(fd, I2CSTART, &cmd);
390                 if (error == -1) {
391                         err_msg = "ioctl: error sending start condition";
392                         goto err1;
393                 }
394                 bufsize = i2c_opt.width / 8;
395                 buf = prepare_buf(bufsize, i2c_opt.off);
396                 if (buf == NULL) {
397                         err_msg = "error: offset malloc";
398                         goto err1;
399                 }
400
401                 cmd.count = bufsize;
402                 cmd.buf = buf;
403                 cmd.last = 0;
404                 error = ioctl(fd, I2CWRITE, &cmd);
405                 free(buf);
406                 if (error == -1) {
407                         err_msg = "ioctl: error when write offset";
408                         goto err1;
409                 }
410
411                 if (i2c_opt.mode == I2C_MODE_STOP_START) {
412                         cmd.slave = i2c_opt.addr;
413                         error = ioctl(fd, I2CSTOP, &cmd);
414                         if (error == -1) {
415                                 err_msg = "error sending stop condtion\n";
416                                 goto err2;
417                         }
418                 }
419         }
420         cmd.slave = i2c_opt.addr;
421         cmd.count = 1;
422         cmd.last = 0;
423         cmd.buf = &data;
424         if (i2c_opt.mode == I2C_MODE_STOP_START) {
425                 error = ioctl(fd, I2CSTART, &cmd);
426                 if (error == -1) {
427                         err_msg = "ioctl: error sending start condition";
428                         goto err1;
429                 }
430         } else if (i2c_opt.mode == I2C_MODE_REPEATED_START) {
431                 error = ioctl(fd, I2CRPTSTART, &cmd);
432                 if (error == -1) {
433                         err_msg = "ioctl: error sending repeated start "
434                             "condition";
435                         goto err1;
436                 }
437         }
438         error = ioctl(fd, I2CSTOP, &cmd);
439         if (error == -1) {
440                 err_msg = "error sending stop condtion\n";
441                 goto err2;
442         }
443
444         for (i = 0; i < i2c_opt.count; i++) {
445                 error = read(fd, &i2c_buf[i], 1);
446                 if (error == -1) {
447                         err_msg = "ioctl: error while reading";
448                         goto err1;
449                 }
450         }
451
452         close(fd);
453         return (0);
454
455 err1:
456         cmd.slave = i2c_opt.addr;
457         error = ioctl(fd, I2CSTOP, &cmd);
458         if (error == -1)
459                 fprintf(stderr, "error sending stop condtion\n");
460 err2:
461         if (err_msg)
462                 fprintf(stderr, "%s", err_msg);
463
464         close(fd);
465         return (1);
466 }
467
468 int
469 main(int argc, char** argv)
470 {
471         struct iiccmd cmd;
472         struct options i2c_opt;
473         char *dev, *skip_addr, *i2c_buf;
474         int error, chunk_size, i, j, ch;
475
476         errno = 0;
477         error = 0;
478
479         /* Line-break the output every chunk_size bytes */
480         chunk_size = 16;
481
482         dev = I2C_DEV;
483
484         /* Default values */
485         i2c_opt.addr_set = 0;
486         i2c_opt.off = 0;
487         i2c_opt.verbose = 0;
488         i2c_opt.dir = 'r';      /* direction = read */
489         i2c_opt.width = 8;
490         i2c_opt.count = 1;
491         i2c_opt.binary = 0;     /* ASCII text output */
492         i2c_opt.scan = 0;       /* no bus scan */
493         i2c_opt.skip = 0;       /* scan all addresses */
494         i2c_opt.reset = 0;      /* no bus reset */
495         i2c_opt.mode = I2C_MODE_NOTSET;
496
497         while ((ch = getopt(argc, argv, "a:f:d:o:w:c:m:n:sbvrh")) != -1) {
498                 switch(ch) {
499                 case 'a':
500                         i2c_opt.addr = (strtoul(optarg, 0, 16) << 1);
501                         if (i2c_opt.addr == 0 && errno == EINVAL)
502                                 i2c_opt.addr_set = 0;
503                         else
504                                 i2c_opt.addr_set = 1;
505                         break;
506                 case 'f':
507                         dev = optarg;
508                         break;
509                 case 'd':
510                         i2c_opt.dir = optarg[0];
511                         break;
512                 case 'o':
513                         i2c_opt.off = strtoul(optarg, 0, 16);
514                         if (i2c_opt.off == 0 && errno == EINVAL)
515                                 error = 1;
516                         break;
517                 case 'w':
518                         i2c_opt.width = atoi(optarg);
519                         break;
520                 case 'c':
521                         i2c_opt.count = atoi(optarg);
522                         break;
523                 case 'm':
524                         if (!strcmp(optarg, "no"))
525                                 i2c_opt.mode = I2C_MODE_NONE;
526                         else if (!strcmp(optarg, "ss"))
527                                 i2c_opt.mode = I2C_MODE_STOP_START;
528                         else if (!strcmp(optarg, "rs"))
529                                 i2c_opt.mode = I2C_MODE_REPEATED_START;
530                         else
531                                 usage();
532                         break;
533                 case 'n':
534                         i2c_opt.skip = 1;
535                         skip_addr = optarg;
536                         break;
537                 case 's':
538                         i2c_opt.scan = 1;
539                         break;
540                 case 'b':
541                         i2c_opt.binary = 1;
542                         break;
543                 case 'v':
544                         i2c_opt.verbose = 1;
545                         break;
546                 case 'r':
547                         i2c_opt.reset = 1;
548                         break;
549                 case 'h':
550                 default:
551                         usage();
552                 }
553         }
554         argc -= optind;
555         argv += optind;
556
557         /* Set default mode if option -m is not specified */
558         if (i2c_opt.mode == I2C_MODE_NOTSET) {
559                 if (i2c_opt.dir == 'r')
560                         i2c_opt.mode = I2C_MODE_STOP_START;
561                 else if (i2c_opt.dir == 'w')
562                         i2c_opt.mode = I2C_MODE_NONE;
563         }
564
565         /* Basic sanity check of command line arguments */
566         if (i2c_opt.scan) {
567                 if (i2c_opt.addr_set)
568                         usage();
569         } else if (i2c_opt.reset) {
570                 if (i2c_opt.addr_set)
571                         usage();
572         } else if (error) {
573                 usage();
574         } else if ((i2c_opt.dir == 'r' || i2c_opt.dir == 'w')) {
575                 if ((i2c_opt.addr_set == 0) ||
576                     !(i2c_opt.width == 0 || i2c_opt.width == 8 ||
577                     i2c_opt.width == 16))
578                 usage();
579         }
580
581         if (i2c_opt.verbose)
582                 fprintf(stderr, "dev: %s, addr: 0x%x, r/w: %c, "
583                     "offset: 0x%02x, width: %u, count: %u\n", dev,
584                     i2c_opt.addr >> 1, i2c_opt.dir, i2c_opt.off,
585                     i2c_opt.width, i2c_opt.count);
586
587         if (i2c_opt.scan)
588                 exit(scan_bus(cmd, dev, i2c_opt.skip, skip_addr));
589
590         if (i2c_opt.reset)
591                 exit(reset_bus(cmd, dev));
592
593         i2c_buf = malloc(i2c_opt.count);
594         if (i2c_buf == NULL)
595                 err(1, "data malloc");
596
597         if (i2c_opt.dir == 'w') {
598                 error = i2c_write(dev, i2c_opt, i2c_buf);
599                 if (error) {
600                         free(i2c_buf);
601                         return (1);
602                 }
603         }
604         if (i2c_opt.dir == 'r') {
605                 error = i2c_read(dev, i2c_opt, i2c_buf);
606                 if (error) {
607                         free(i2c_buf);
608                         return (1);
609                 }
610         }
611
612         if (i2c_opt.verbose)
613                 fprintf(stderr, "\nData %s (hex):\n", i2c_opt.dir == 'r' ?
614                     "read" : "written");
615
616         i = 0;
617         j = 0;
618         while (i < i2c_opt.count) {
619                 if (i2c_opt.verbose || (i2c_opt.dir == 'r' &&
620                     !i2c_opt.binary))
621                         fprintf (stderr, "%02hhx ", i2c_buf[i++]);
622
623                 if (i2c_opt.dir == 'r' && i2c_opt.binary) {
624                         fprintf(stdout, "%c", i2c_buf[j++]);
625                         if(!i2c_opt.verbose)
626                                 i++;
627                 }
628                 if (!i2c_opt.verbose && (i2c_opt.dir == 'w'))
629                         break;
630                 if ((i % chunk_size) == 0)
631                         fprintf(stderr, "\n");
632         }
633         if ((i % chunk_size) != 0)
634                 fprintf(stderr, "\n");
635
636         free(i2c_buf);
637         return (0);
638 }