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 iic_msg rdmsg; 125 struct iic_rdwr_data rdwrdata; 126 struct skip_range addr_range = { 0, 0 }; 127 int *tokens, fd, error, i, index, j; 128 int len = 0, do_skip = 0, no_range = 1, num_found = 0, use_read_xfer = 0; 129 uint8_t rdbyte; 130 131 fd = open(dev, O_RDWR); 132 if (fd == -1) { 133 fprintf(stderr, "Error opening I2C controller (%s) for " 134 "scanning: %s\n", dev, strerror(errno)); 135 return (EX_NOINPUT); 136 } 137 138 if (skip) { 139 len = strlen(skip_addr); 140 if (strstr(skip_addr, "..") != NULL) { 141 addr_range = skip_get_range(skip_addr); 142 no_range = 0; 143 } else { 144 tokens = (int *)malloc((len / 2 + 1) * sizeof(int)); 145 if (tokens == NULL) { 146 fprintf(stderr, "Error allocating tokens " 147 "buffer\n"); 148 error = -1; 149 goto out; 150 } 151 index = skip_get_tokens(skip_addr, tokens, 152 len / 2 + 1); 153 } 154 155 if (!no_range && (addr_range.start > addr_range.end)) { 156 fprintf(stderr, "Skip address out of range\n"); 157 error = -1; 158 goto out; 159 } 160 } 161 162 printf("Scanning I2C devices on %s: ", dev); 163 164 start_over: 165 if (use_read_xfer) { 166 fprintf(stderr, 167 "Hardware may not support START/STOP scanning; " 168 "trying less-reliable read method.\n"); 169 } 170 171 for (i = 1; i < 127; i++) { 172 173 if (skip && ( addr_range.start < addr_range.end)) { 174 if (i >= addr_range.start && i <= addr_range.end) 175 continue; 176 177 } else if (skip && no_range) 178 for (j = 0; j < index; j++) { 179 if (tokens[j] == i) { 180 do_skip = 1; 181 break; 182 } 183 } 184 185 if (do_skip) { 186 do_skip = 0; 187 continue; 188 } 189 190 cmd.slave = i << 1; 191 cmd.last = 1; 192 cmd.count = 0; 193 error = ioctl(fd, I2CRSTCARD, &cmd); 194 if (error) { 195 fprintf(stderr, "Controller reset failed\n"); 196 goto out; 197 } 198 if (use_read_xfer) { 199 rdmsg.buf = &rdbyte; 200 rdmsg.len = 1; 201 rdmsg.flags = IIC_M_RD; 202 rdmsg.slave = i << 1; 203 rdwrdata.msgs = &rdmsg; 204 rdwrdata.nmsgs = 1; 205 error = ioctl(fd, I2CRDWR, &rdwrdata); 206 } else { 207 cmd.slave = i << 1; 208 cmd.last = 1; 209 error = ioctl(fd, I2CSTART, &cmd); 210 if (errno == ENODEV || errno == EOPNOTSUPP) { 211 /* If START not supported try reading. */ 212 use_read_xfer = 1; 213 goto start_over; 214 } 215 cmd.slave = i << 1; 216 cmd.last = 1; 217 ioctl(fd, I2CSTOP, &cmd); 218 } 219 if (error == 0) { 220 ++num_found; 221 printf("%02x ", i); 222 } 223 } 224 /* 225 * If we found nothing, maybe START is not supported and returns a 226 * generic error code such as EIO or ENXIO, so try again using reads. 227 */ 228 if (num_found == 0) { 229 if (!use_read_xfer) { 230 use_read_xfer = 1; 231 goto start_over; 232 } 233 printf("<none found>"); 234 } 235 printf("\n"); 236 237 error = ioctl(fd, I2CRSTCARD, &cmd); 238 out: 239 close(fd); 240 if (skip && no_range) 241 free(tokens); 242 243 if (error) { 244 fprintf(stderr, "Error scanning I2C controller (%s): %s\n", 245 dev, strerror(errno)); 246 return (EX_NOINPUT); 247 } else 248 return (EX_OK); 249 } 250 251 static int 252 reset_bus(struct iiccmd cmd, char *dev) 253 { 254 int fd, error; 255 256 fd = open(dev, O_RDWR); 257 if (fd == -1) { 258 fprintf(stderr, "Error opening I2C controller (%s) for " 259 "resetting: %s\n", dev, strerror(errno)); 260 return (EX_NOINPUT); 261 } 262 263 printf("Resetting I2C controller on %s: ", dev); 264 error = ioctl(fd, I2CRSTCARD, &cmd); 265 close (fd); 266 267 if (error) { 268 printf("error: %s\n", strerror(errno)); 269 return (EX_IOERR); 270 } else { 271 printf("OK\n"); 272 return (EX_OK); 273 } 274 } 275 276 static char * 277 prepare_buf(int size, uint32_t off) 278 { 279 char *buf; 280 281 buf = malloc(size); 282 if (buf == NULL) 283 return (buf); 284 285 if (size == 1) 286 buf[0] = off & 0xff; 287 else if (size == 2) { 288 buf[0] = (off >> 8) & 0xff; 289 buf[1] = off & 0xff; 290 } 291 292 return (buf); 293 } 294 295 static int 296 i2c_write(char *dev, struct options i2c_opt, char *i2c_buf) 297 { 298 struct iiccmd cmd; 299 int ch, i, error, fd, bufsize; 300 char *err_msg, *buf; 301 302 /* 303 * Read data to be written to the chip from stdin 304 */ 305 if (i2c_opt.verbose && !i2c_opt.binary) 306 fprintf(stderr, "Enter %u bytes of data: ", i2c_opt.count); 307 308 for (i = 0; i < i2c_opt.count; i++) { 309 ch = getchar(); 310 if (ch == EOF) { 311 free(i2c_buf); 312 err(1, "not enough data, exiting\n"); 313 } 314 i2c_buf[i] = ch; 315 } 316 317 fd = open(dev, O_RDWR); 318 if (fd == -1) { 319 free(i2c_buf); 320 err(1, "open failed"); 321 } 322 323 cmd.slave = i2c_opt.addr; 324 error = ioctl(fd, I2CSTART, &cmd); 325 if (error == -1) { 326 err_msg = "ioctl: error sending start condition"; 327 goto err1; 328 } 329 330 if (i2c_opt.width) { 331 bufsize = i2c_opt.width / 8; 332 buf = prepare_buf(bufsize, i2c_opt.off); 333 if (buf == NULL) { 334 err_msg = "error: offset malloc"; 335 goto err1; 336 } 337 } else { 338 bufsize = 0; 339 buf = NULL; 340 } 341 342 switch(i2c_opt.mode) { 343 case I2C_MODE_STOP_START: 344 /* 345 * Write offset where the data will go 346 */ 347 if (i2c_opt.width) { 348 cmd.count = bufsize; 349 cmd.buf = buf; 350 error = ioctl(fd, I2CWRITE, &cmd); 351 free(buf); 352 if (error == -1) { 353 err_msg = "ioctl: error writing offset"; 354 goto err1; 355 } 356 } 357 358 error = ioctl(fd, I2CSTOP, &cmd); 359 if (error == -1) { 360 err_msg = "ioctl: error sending stop condition"; 361 goto err2; 362 } 363 cmd.slave = i2c_opt.addr; 364 error = ioctl(fd, I2CSTART, &cmd); 365 if (error == -1) { 366 err_msg = "ioctl: error sending start condition"; 367 goto err1; 368 } 369 370 /* 371 * Write the data 372 */ 373 cmd.count = i2c_opt.count; 374 cmd.buf = i2c_buf; 375 cmd.last = 0; 376 error = ioctl(fd, I2CWRITE, &cmd); 377 if (error == -1) { 378 err_msg = "ioctl: error writing"; 379 goto err1; 380 } 381 break; 382 383 case I2C_MODE_REPEATED_START: 384 /* 385 * Write offset where the data will go 386 */ 387 if (i2c_opt.width) { 388 cmd.count = bufsize; 389 cmd.buf = buf; 390 error = ioctl(fd, I2CWRITE, &cmd); 391 free(buf); 392 if (error == -1) { 393 err_msg = "ioctl: error writing offset"; 394 goto err1; 395 } 396 } 397 398 cmd.slave = i2c_opt.addr; 399 error = ioctl(fd, I2CRPTSTART, &cmd); 400 if (error == -1) { 401 err_msg = "ioctl: error sending repeated start " 402 "condition"; 403 goto err1; 404 } 405 406 /* 407 * Write the data 408 */ 409 cmd.count = i2c_opt.count; 410 cmd.buf = i2c_buf; 411 cmd.last = 0; 412 error = ioctl(fd, I2CWRITE, &cmd); 413 if (error == -1) { 414 err_msg = "ioctl: error writing"; 415 goto err1; 416 } 417 break; 418 419 case I2C_MODE_NONE: /* fall through */ 420 default: 421 buf = realloc(buf, bufsize + i2c_opt.count); 422 if (buf == NULL) { 423 err_msg = "error: data malloc"; 424 goto err1; 425 } 426 427 memcpy(buf + bufsize, i2c_buf, i2c_opt.count); 428 /* 429 * Write offset and data 430 */ 431 cmd.count = bufsize + i2c_opt.count; 432 cmd.buf = buf; 433 cmd.last = 0; 434 error = ioctl(fd, I2CWRITE, &cmd); 435 free(buf); 436 if (error == -1) { 437 err_msg = "ioctl: error writing"; 438 goto err1; 439 } 440 break; 441 } 442 cmd.slave = i2c_opt.addr; 443 error = ioctl(fd, I2CSTOP, &cmd); 444 if (error == -1) { 445 err_msg = "ioctl: error sending stop condition"; 446 goto err2; 447 } 448 449 close(fd); 450 return (0); 451 452 err1: 453 cmd.slave = i2c_opt.addr; 454 error = ioctl(fd, I2CSTOP, &cmd); 455 if (error == -1) 456 fprintf(stderr, "error sending stop condition\n"); 457 err2: 458 if (err_msg) 459 fprintf(stderr, "%s\n", err_msg); 460 461 close(fd); 462 return (1); 463 } 464 465 static int 466 i2c_read(char *dev, struct options i2c_opt, char *i2c_buf) 467 { 468 struct iiccmd cmd; 469 int i, fd, error, bufsize; 470 char *err_msg, data = 0, *buf; 471 472 fd = open(dev, O_RDWR); 473 if (fd == -1) 474 err(1, "open failed"); 475 476 bzero(&cmd, sizeof(cmd)); 477 478 if (i2c_opt.width) { 479 cmd.slave = i2c_opt.addr; 480 cmd.count = 1; 481 cmd.last = 0; 482 cmd.buf = &data; 483 error = ioctl(fd, I2CSTART, &cmd); 484 if (error == -1) { 485 err_msg = "ioctl: error sending start condition"; 486 goto err1; 487 } 488 bufsize = i2c_opt.width / 8; 489 buf = prepare_buf(bufsize, i2c_opt.off); 490 if (buf == NULL) { 491 err_msg = "error: offset malloc"; 492 goto err1; 493 } 494 495 cmd.count = bufsize; 496 cmd.buf = buf; 497 cmd.last = 0; 498 error = ioctl(fd, I2CWRITE, &cmd); 499 free(buf); 500 if (error == -1) { 501 err_msg = "ioctl: error writing offset"; 502 goto err1; 503 } 504 505 if (i2c_opt.mode == I2C_MODE_STOP_START) { 506 cmd.slave = i2c_opt.addr; 507 error = ioctl(fd, I2CSTOP, &cmd); 508 if (error == -1) { 509 err_msg = "error sending stop condition"; 510 goto err2; 511 } 512 } 513 } 514 cmd.slave = i2c_opt.addr; 515 cmd.count = 1; 516 cmd.last = 0; 517 cmd.buf = &data; 518 if (i2c_opt.mode == I2C_MODE_STOP_START) { 519 error = ioctl(fd, I2CSTART, &cmd); 520 if (error == -1) { 521 err_msg = "ioctl: error sending start condition"; 522 goto err1; 523 } 524 } else if (i2c_opt.mode == I2C_MODE_REPEATED_START) { 525 error = ioctl(fd, I2CRPTSTART, &cmd); 526 if (error == -1) { 527 err_msg = "ioctl: error sending repeated start " 528 "condition"; 529 goto err1; 530 } 531 } 532 error = ioctl(fd, I2CSTOP, &cmd); 533 if (error == -1) { 534 err_msg = "error sending stop condition"; 535 goto err2; 536 } 537 538 for (i = 0; i < i2c_opt.count; i++) { 539 error = read(fd, &i2c_buf[i], 1); 540 if (error == -1) { 541 err_msg = "ioctl: error while reading"; 542 goto err1; 543 } 544 } 545 546 close(fd); 547 return (0); 548 549 err1: 550 cmd.slave = i2c_opt.addr; 551 error = ioctl(fd, I2CSTOP, &cmd); 552 if (error == -1) 553 fprintf(stderr, "error sending stop condition\n"); 554 err2: 555 if (err_msg) 556 fprintf(stderr, "%s\n", err_msg); 557 558 close(fd); 559 return (1); 560 } 561 562 int 563 main(int argc, char** argv) 564 { 565 struct iiccmd cmd; 566 struct options i2c_opt; 567 char *dev, *skip_addr, *i2c_buf; 568 int error, chunk_size, i, j, ch; 569 570 errno = 0; 571 error = 0; 572 573 /* Line-break the output every chunk_size bytes */ 574 chunk_size = 16; 575 576 dev = I2C_DEV; 577 578 /* Default values */ 579 i2c_opt.addr_set = 0; 580 i2c_opt.off = 0; 581 i2c_opt.verbose = 0; 582 i2c_opt.dir = 'r'; /* direction = read */ 583 i2c_opt.width = 8; 584 i2c_opt.count = 1; 585 i2c_opt.binary = 0; /* ASCII text output */ 586 i2c_opt.scan = 0; /* no bus scan */ 587 i2c_opt.skip = 0; /* scan all addresses */ 588 i2c_opt.reset = 0; /* no bus reset */ 589 i2c_opt.mode = I2C_MODE_NOTSET; 590 591 while ((ch = getopt(argc, argv, "a:f:d:o:w:c:m:n:sbvrh")) != -1) { 592 switch(ch) { 593 case 'a': 594 i2c_opt.addr = (strtoul(optarg, 0, 16) << 1); 595 if (i2c_opt.addr == 0 && errno == EINVAL) 596 i2c_opt.addr_set = 0; 597 else 598 i2c_opt.addr_set = 1; 599 break; 600 case 'f': 601 dev = optarg; 602 break; 603 case 'd': 604 i2c_opt.dir = optarg[0]; 605 break; 606 case 'o': 607 i2c_opt.off = strtoul(optarg, 0, 16); 608 if (i2c_opt.off == 0 && errno == EINVAL) 609 error = 1; 610 break; 611 case 'w': 612 i2c_opt.width = atoi(optarg); 613 break; 614 case 'c': 615 i2c_opt.count = atoi(optarg); 616 break; 617 case 'm': 618 if (!strcmp(optarg, "no")) 619 i2c_opt.mode = I2C_MODE_NONE; 620 else if (!strcmp(optarg, "ss")) 621 i2c_opt.mode = I2C_MODE_STOP_START; 622 else if (!strcmp(optarg, "rs")) 623 i2c_opt.mode = I2C_MODE_REPEATED_START; 624 else 625 usage(); 626 break; 627 case 'n': 628 i2c_opt.skip = 1; 629 skip_addr = optarg; 630 break; 631 case 's': 632 i2c_opt.scan = 1; 633 break; 634 case 'b': 635 i2c_opt.binary = 1; 636 break; 637 case 'v': 638 i2c_opt.verbose = 1; 639 break; 640 case 'r': 641 i2c_opt.reset = 1; 642 break; 643 case 'h': 644 default: 645 usage(); 646 } 647 } 648 argc -= optind; 649 argv += optind; 650 651 /* Set default mode if option -m is not specified */ 652 if (i2c_opt.mode == I2C_MODE_NOTSET) { 653 if (i2c_opt.dir == 'r') 654 i2c_opt.mode = I2C_MODE_STOP_START; 655 else if (i2c_opt.dir == 'w') 656 i2c_opt.mode = I2C_MODE_NONE; 657 } 658 659 /* Basic sanity check of command line arguments */ 660 if (i2c_opt.scan) { 661 if (i2c_opt.addr_set) 662 usage(); 663 } else if (i2c_opt.reset) { 664 if (i2c_opt.addr_set) 665 usage(); 666 } else if (error) { 667 usage(); 668 } else if ((i2c_opt.dir == 'r' || i2c_opt.dir == 'w')) { 669 if ((i2c_opt.addr_set == 0) || 670 !(i2c_opt.width == 0 || i2c_opt.width == 8 || 671 i2c_opt.width == 16)) 672 usage(); 673 } 674 675 if (i2c_opt.verbose) 676 fprintf(stderr, "dev: %s, addr: 0x%x, r/w: %c, " 677 "offset: 0x%02x, width: %u, count: %u\n", dev, 678 i2c_opt.addr >> 1, i2c_opt.dir, i2c_opt.off, 679 i2c_opt.width, i2c_opt.count); 680 681 if (i2c_opt.scan) 682 exit(scan_bus(cmd, dev, i2c_opt.skip, skip_addr)); 683 684 if (i2c_opt.reset) 685 exit(reset_bus(cmd, dev)); 686 687 i2c_buf = malloc(i2c_opt.count); 688 if (i2c_buf == NULL) 689 err(1, "data malloc"); 690 691 if (i2c_opt.dir == 'w') { 692 error = i2c_write(dev, i2c_opt, i2c_buf); 693 if (error) { 694 free(i2c_buf); 695 return (1); 696 } 697 } 698 if (i2c_opt.dir == 'r') { 699 error = i2c_read(dev, i2c_opt, i2c_buf); 700 if (error) { 701 free(i2c_buf); 702 return (1); 703 } 704 } 705 706 if (i2c_opt.verbose) 707 fprintf(stderr, "\nData %s (hex):\n", i2c_opt.dir == 'r' ? 708 "read" : "written"); 709 710 i = 0; 711 j = 0; 712 while (i < i2c_opt.count) { 713 if (i2c_opt.verbose || (i2c_opt.dir == 'r' && 714 !i2c_opt.binary)) 715 fprintf (stderr, "%02hhx ", i2c_buf[i++]); 716 717 if (i2c_opt.dir == 'r' && i2c_opt.binary) { 718 fprintf(stdout, "%c", i2c_buf[j++]); 719 if(!i2c_opt.verbose) 720 i++; 721 } 722 if (!i2c_opt.verbose && (i2c_opt.dir == 'w')) 723 break; 724 if ((i % chunk_size) == 0) 725 fprintf(stderr, "\n"); 726 } 727 if ((i % chunk_size) != 0) 728 fprintf(stderr, "\n"); 729 730 free(i2c_buf); 731 return (0); 732 } 733