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