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