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 cmd.slave = i2c_opt.addr; 284 error = ioctl(fd, I2CSTART, &cmd); 285 if (error == -1) { 286 err_msg = "ioctl: error sending start condition"; 287 goto err1; 288 } 289 290 if (i2c_opt.width) { 291 bufsize = i2c_opt.width / 8; 292 buf = prepare_buf(bufsize, i2c_opt.off); 293 if (buf == NULL) { 294 err_msg = "error: offset malloc"; 295 goto err1; 296 } 297 } else { 298 bufsize = 0; 299 buf = NULL; 300 } 301 302 switch(i2c_opt.mode) { 303 case I2C_MODE_STOP_START: 304 /* 305 * Write offset where the data will go 306 */ 307 if (i2c_opt.width) { 308 cmd.count = bufsize; 309 cmd.buf = buf; 310 error = ioctl(fd, I2CWRITE, &cmd); 311 free(buf); 312 if (error == -1) { 313 err_msg = "ioctl: error when write offset"; 314 goto err1; 315 } 316 } 317 318 error = ioctl(fd, I2CSTOP, &cmd); 319 if (error == -1) { 320 err_msg = "ioctl: error sending stop condition"; 321 goto err2; 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 /* 331 * Write the data 332 */ 333 cmd.count = i2c_opt.count; 334 cmd.buf = i2c_buf; 335 cmd.last = 0; 336 error = ioctl(fd, I2CWRITE, &cmd); 337 if (error == -1) { 338 err_msg = "ioctl: error when write"; 339 goto err1; 340 } 341 break; 342 343 case I2C_MODE_REPEATED_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 when write offset"; 354 goto err1; 355 } 356 } 357 358 cmd.slave = i2c_opt.addr; 359 error = ioctl(fd, I2CRPTSTART, &cmd); 360 if (error == -1) { 361 err_msg = "ioctl: error sending repeated start " 362 "condition"; 363 goto err1; 364 } 365 366 /* 367 * Write the data 368 */ 369 cmd.count = i2c_opt.count; 370 cmd.buf = i2c_buf; 371 cmd.last = 0; 372 error = ioctl(fd, I2CWRITE, &cmd); 373 if (error == -1) { 374 err_msg = "ioctl: error when write"; 375 goto err1; 376 } 377 break; 378 379 case I2C_MODE_NONE: /* fall through */ 380 default: 381 buf = realloc(buf, bufsize + i2c_opt.count); 382 if (buf == NULL) { 383 err_msg = "error: data malloc"; 384 goto err1; 385 } 386 387 memcpy(buf + bufsize, i2c_buf, i2c_opt.count); 388 /* 389 * Write offset and data 390 */ 391 cmd.count = bufsize + i2c_opt.count; 392 cmd.buf = buf; 393 cmd.last = 0; 394 error = ioctl(fd, I2CWRITE, &cmd); 395 free(buf); 396 if (error == -1) { 397 err_msg = "ioctl: error when write"; 398 goto err1; 399 } 400 break; 401 } 402 cmd.slave = i2c_opt.addr; 403 error = ioctl(fd, I2CSTOP, &cmd); 404 if (error == -1) { 405 err_msg = "ioctl: error sending stop condition"; 406 goto err2; 407 } 408 409 close(fd); 410 return (0); 411 412 err1: 413 cmd.slave = i2c_opt.addr; 414 error = ioctl(fd, I2CSTOP, &cmd); 415 if (error == -1) 416 fprintf(stderr, "error sending stop condtion\n"); 417 err2: 418 if (err_msg) 419 fprintf(stderr, "%s", err_msg); 420 421 close(fd); 422 return (1); 423 } 424 425 static int 426 i2c_read(char *dev, struct options i2c_opt, char *i2c_buf) 427 { 428 struct iiccmd cmd; 429 int i, fd, error, bufsize; 430 char *err_msg, data = 0, *buf; 431 432 fd = open(dev, O_RDWR); 433 if (fd == -1) 434 err(1, "open failed"); 435 436 bzero(&cmd, sizeof(cmd)); 437 438 if (i2c_opt.width) { 439 cmd.slave = i2c_opt.addr; 440 cmd.count = 1; 441 cmd.last = 0; 442 cmd.buf = &data; 443 error = ioctl(fd, I2CSTART, &cmd); 444 if (error == -1) { 445 err_msg = "ioctl: error sending start condition"; 446 goto err1; 447 } 448 bufsize = i2c_opt.width / 8; 449 buf = prepare_buf(bufsize, i2c_opt.off); 450 if (buf == NULL) { 451 err_msg = "error: offset malloc"; 452 goto err1; 453 } 454 455 cmd.count = bufsize; 456 cmd.buf = buf; 457 cmd.last = 0; 458 error = ioctl(fd, I2CWRITE, &cmd); 459 free(buf); 460 if (error == -1) { 461 err_msg = "ioctl: error when write offset"; 462 goto err1; 463 } 464 465 if (i2c_opt.mode == I2C_MODE_STOP_START) { 466 cmd.slave = i2c_opt.addr; 467 error = ioctl(fd, I2CSTOP, &cmd); 468 if (error == -1) { 469 err_msg = "error sending stop condtion\n"; 470 goto err2; 471 } 472 } 473 } 474 cmd.slave = i2c_opt.addr; 475 cmd.count = 1; 476 cmd.last = 0; 477 cmd.buf = &data; 478 if (i2c_opt.mode == I2C_MODE_STOP_START) { 479 error = ioctl(fd, I2CSTART, &cmd); 480 if (error == -1) { 481 err_msg = "ioctl: error sending start condition"; 482 goto err1; 483 } 484 } else if (i2c_opt.mode == I2C_MODE_REPEATED_START) { 485 error = ioctl(fd, I2CRPTSTART, &cmd); 486 if (error == -1) { 487 err_msg = "ioctl: error sending repeated start " 488 "condition"; 489 goto err1; 490 } 491 } 492 error = ioctl(fd, I2CSTOP, &cmd); 493 if (error == -1) { 494 err_msg = "error sending stop condtion\n"; 495 goto err2; 496 } 497 498 for (i = 0; i < i2c_opt.count; i++) { 499 error = read(fd, &i2c_buf[i], 1); 500 if (error == -1) { 501 err_msg = "ioctl: error while reading"; 502 goto err1; 503 } 504 } 505 506 close(fd); 507 return (0); 508 509 err1: 510 cmd.slave = i2c_opt.addr; 511 error = ioctl(fd, I2CSTOP, &cmd); 512 if (error == -1) 513 fprintf(stderr, "error sending stop condtion\n"); 514 err2: 515 if (err_msg) 516 fprintf(stderr, "%s", err_msg); 517 518 close(fd); 519 return (1); 520 } 521 522 int 523 main(int argc, char** argv) 524 { 525 struct iiccmd cmd; 526 struct options i2c_opt; 527 char *dev, *skip_addr, *i2c_buf; 528 int error, chunk_size, i, j, ch; 529 530 errno = 0; 531 error = 0; 532 533 /* Line-break the output every chunk_size bytes */ 534 chunk_size = 16; 535 536 dev = I2C_DEV; 537 538 /* Default values */ 539 i2c_opt.addr_set = 0; 540 i2c_opt.off = 0; 541 i2c_opt.verbose = 0; 542 i2c_opt.dir = 'r'; /* direction = read */ 543 i2c_opt.width = 8; 544 i2c_opt.count = 1; 545 i2c_opt.binary = 0; /* ASCII text output */ 546 i2c_opt.scan = 0; /* no bus scan */ 547 i2c_opt.skip = 0; /* scan all addresses */ 548 i2c_opt.reset = 0; /* no bus reset */ 549 i2c_opt.mode = I2C_MODE_NOTSET; 550 551 while ((ch = getopt(argc, argv, "a:f:d:o:w:c:m:n:sbvrh")) != -1) { 552 switch(ch) { 553 case 'a': 554 i2c_opt.addr = (strtoul(optarg, 0, 16) << 1); 555 if (i2c_opt.addr == 0 && errno == EINVAL) 556 i2c_opt.addr_set = 0; 557 else 558 i2c_opt.addr_set = 1; 559 break; 560 case 'f': 561 dev = optarg; 562 break; 563 case 'd': 564 i2c_opt.dir = optarg[0]; 565 break; 566 case 'o': 567 i2c_opt.off = strtoul(optarg, 0, 16); 568 if (i2c_opt.off == 0 && errno == EINVAL) 569 error = 1; 570 break; 571 case 'w': 572 i2c_opt.width = atoi(optarg); 573 break; 574 case 'c': 575 i2c_opt.count = atoi(optarg); 576 break; 577 case 'm': 578 if (!strcmp(optarg, "no")) 579 i2c_opt.mode = I2C_MODE_NONE; 580 else if (!strcmp(optarg, "ss")) 581 i2c_opt.mode = I2C_MODE_STOP_START; 582 else if (!strcmp(optarg, "rs")) 583 i2c_opt.mode = I2C_MODE_REPEATED_START; 584 else 585 usage(); 586 break; 587 case 'n': 588 i2c_opt.skip = 1; 589 skip_addr = optarg; 590 break; 591 case 's': 592 i2c_opt.scan = 1; 593 break; 594 case 'b': 595 i2c_opt.binary = 1; 596 break; 597 case 'v': 598 i2c_opt.verbose = 1; 599 break; 600 case 'r': 601 i2c_opt.reset = 1; 602 break; 603 case 'h': 604 default: 605 usage(); 606 } 607 } 608 argc -= optind; 609 argv += optind; 610 611 /* Set default mode if option -m is not specified */ 612 if (i2c_opt.mode == I2C_MODE_NOTSET) { 613 if (i2c_opt.dir == 'r') 614 i2c_opt.mode = I2C_MODE_STOP_START; 615 else if (i2c_opt.dir == 'w') 616 i2c_opt.mode = I2C_MODE_NONE; 617 } 618 619 /* Basic sanity check of command line arguments */ 620 if (i2c_opt.scan) { 621 if (i2c_opt.addr_set) 622 usage(); 623 } else if (i2c_opt.reset) { 624 if (i2c_opt.addr_set) 625 usage(); 626 } else if (error) { 627 usage(); 628 } else if ((i2c_opt.dir == 'r' || i2c_opt.dir == 'w')) { 629 if ((i2c_opt.addr_set == 0) || 630 !(i2c_opt.width == 0 || i2c_opt.width == 8 || 631 i2c_opt.width == 16)) 632 usage(); 633 } 634 635 if (i2c_opt.verbose) 636 fprintf(stderr, "dev: %s, addr: 0x%x, r/w: %c, " 637 "offset: 0x%02x, width: %u, count: %u\n", dev, 638 i2c_opt.addr >> 1, i2c_opt.dir, i2c_opt.off, 639 i2c_opt.width, i2c_opt.count); 640 641 if (i2c_opt.scan) 642 exit(scan_bus(cmd, dev, i2c_opt.skip, skip_addr)); 643 644 if (i2c_opt.reset) 645 exit(reset_bus(cmd, dev)); 646 647 i2c_buf = malloc(i2c_opt.count); 648 if (i2c_buf == NULL) 649 err(1, "data malloc"); 650 651 if (i2c_opt.dir == 'w') { 652 error = i2c_write(dev, i2c_opt, i2c_buf); 653 if (error) { 654 free(i2c_buf); 655 return (1); 656 } 657 } 658 if (i2c_opt.dir == 'r') { 659 error = i2c_read(dev, i2c_opt, i2c_buf); 660 if (error) { 661 free(i2c_buf); 662 return (1); 663 } 664 } 665 666 if (i2c_opt.verbose) 667 fprintf(stderr, "\nData %s (hex):\n", i2c_opt.dir == 'r' ? 668 "read" : "written"); 669 670 i = 0; 671 j = 0; 672 while (i < i2c_opt.count) { 673 if (i2c_opt.verbose || (i2c_opt.dir == 'r' && 674 !i2c_opt.binary)) 675 fprintf (stderr, "%02hhx ", i2c_buf[i++]); 676 677 if (i2c_opt.dir == 'r' && i2c_opt.binary) { 678 fprintf(stdout, "%c", i2c_buf[j++]); 679 if(!i2c_opt.verbose) 680 i++; 681 } 682 if (!i2c_opt.verbose && (i2c_opt.dir == 'w')) 683 break; 684 if ((i % chunk_size) == 0) 685 fprintf(stderr, "\n"); 686 } 687 if ((i % chunk_size) != 0) 688 fprintf(stderr, "\n"); 689 690 free(i2c_buf); 691 return (0); 692 } 693