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