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