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