1 /* 2 * Copyright 2020, Jérôme Duval, jerome.duval@gmail.com. 3 * Distributed under the terms of the MIT license. 4 */ 5 6 7 #include <errno.h> 8 #include <fcntl.h> 9 #include <getopt.h> 10 #include <stdint.h> 11 #include <stdio.h> 12 #include <stdlib.h> 13 #include <string.h> 14 15 #include <Drivers.h> 16 17 #include <AutoDeleter.h> 18 19 #include "i2c.h" 20 21 22 static struct option const kLongOptions[] = { 23 {"help", no_argument, 0, 'h'}, 24 {NULL} 25 }; 26 27 28 extern const char *__progname; 29 static const char *kProgramName = __progname; 30 31 32 void 33 usage(int returnValue) 34 { 35 fprintf(stderr, "Usage: %s <path-to-i2c-bus-device>\n", kProgramName); 36 exit(returnValue); 37 } 38 39 40 static int 41 scan_bus(const char *path) 42 { 43 int err = EXIT_SUCCESS; 44 int fd = open(path, O_RDONLY); 45 if (fd < 0) { 46 fprintf(stderr, "%s: Could not access path: %s\n", kProgramName, 47 strerror(errno)); 48 return EXIT_FAILURE; 49 } 50 51 setbuf(stdout, NULL); 52 printf("Scanning I2C bus: %s\n", path); 53 FileDescriptorCloser closer(fd); 54 55 printf(" 0 1 2 3 4 5 6 7 8 9 a b c d e f\n"); 56 for (int i = 0; i < 128; i+=16) { 57 printf("%02x: ", i); 58 for (int j = 0; j < 16; j++) { 59 uint16 addr = i + j; 60 uint8 cmd = 0; 61 uint8 data = 0; 62 i2c_ioctl_exec exec; 63 exec.addr = addr; 64 exec.op = I2C_OP_READ_STOP; 65 exec.cmdBuffer = &cmd; 66 exec.cmdLength = sizeof(cmd); 67 exec.buffer = &data; 68 exec.bufferLength = sizeof(data); 69 if (ioctl(fd, I2CEXEC, &exec, sizeof(exec)) == 0) 70 printf("%02x ", addr); 71 else 72 printf("-- "); 73 } 74 printf("\n"); 75 } 76 77 close(fd); 78 79 return err; 80 } 81 82 83 int 84 main(int argc, char** argv) 85 { 86 int c; 87 while ((c = getopt_long(argc, argv, "h", kLongOptions, NULL)) != -1) { 88 switch (c) { 89 case 0: 90 break; 91 case 'h': 92 usage(0); 93 break; 94 default: 95 usage(1); 96 break; 97 } 98 } 99 100 if (argc - optind < 1) 101 usage(1); 102 const char* path = argv[optind++]; 103 104 exit(scan_bus(path)); 105 } 106