"Fossies" - the Fresh Open Source Software Archive

Member "i2c-tools-4.3/tools/i2cdetect.c" (22 Jul 2021, 9374 Bytes) of package /linux/misc/i2c-tools-4.3.tar.gz:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style: standard) with prefixed line numbers and code folding option. Alternatively you can here view or download the uninterpreted source code file. For more information about "i2cdetect.c" see the Fossies "Dox" file reference documentation and the last Fossies "Diffs" side-by-side code changes report: 4.1_vs_4.2.

    1 /*
    2     i2cdetect.c - a user-space program to scan for I2C devices
    3     Copyright (C) 1999-2004  Frodo Looijaard <frodol@dds.nl>, and
    4                              Mark D. Studebaker <mdsxyz123@yahoo.com>
    5     Copyright (C) 2004-2012  Jean Delvare <jdelvare@suse.de>
    6 
    7     This program is free software; you can redistribute it and/or modify
    8     it under the terms of the GNU General Public License as published by
    9     the Free Software Foundation; either version 2 of the License, or
   10     (at your option) any later version.
   11 
   12     This program is distributed in the hope that it will be useful,
   13     but WITHOUT ANY WARRANTY; without even the implied warranty of
   14     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   15     GNU General Public License for more details.
   16 
   17     You should have received a copy of the GNU General Public License
   18     along with this program; if not, write to the Free Software
   19     Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
   20     MA 02110-1301 USA.
   21 */
   22 
   23 #include <sys/ioctl.h>
   24 #include <errno.h>
   25 #include <string.h>
   26 #include <stdio.h>
   27 #include <stdlib.h>
   28 #include <unistd.h>
   29 #include <linux/i2c.h>
   30 #include <linux/i2c-dev.h>
   31 #include <i2c/smbus.h>
   32 #include "i2cbusses.h"
   33 #include "../version.h"
   34 
   35 #define MODE_AUTO   0
   36 #define MODE_QUICK  1
   37 #define MODE_READ   2
   38 #define MODE_FUNC   3
   39 
   40 static void help(void)
   41 {
   42     fprintf(stderr,
   43         "Usage: i2cdetect [-y] [-a] [-q|-r] I2CBUS [FIRST LAST]\n"
   44         "       i2cdetect -F I2CBUS\n"
   45         "       i2cdetect -l\n"
   46         "  I2CBUS is an integer or an I2C bus name\n"
   47         "  If provided, FIRST and LAST limit the probing range.\n");
   48 }
   49 
   50 static int scan_i2c_bus(int file, int mode, unsigned long funcs,
   51             int first, int last)
   52 {
   53     int i, j;
   54     int cmd, res;
   55 
   56     printf("     0  1  2  3  4  5  6  7  8  9  a  b  c  d  e  f\n");
   57 
   58     for (i = 0; i < 128; i += 16) {
   59         printf("%02x: ", i);
   60         for(j = 0; j < 16; j++) {
   61             fflush(stdout);
   62 
   63             /* Select detection command for this address */
   64             switch (mode) {
   65             default:
   66                 cmd = mode;
   67                 break;
   68             case MODE_AUTO:
   69                 if ((i+j >= 0x30 && i+j <= 0x37)
   70                  || (i+j >= 0x50 && i+j <= 0x5F))
   71                     cmd = MODE_READ;
   72                 else
   73                     cmd = MODE_QUICK;
   74                 break;
   75             }
   76 
   77             /* Skip unwanted addresses */
   78             if (i+j < first || i+j > last
   79              || (cmd == MODE_READ &&
   80                  !(funcs & I2C_FUNC_SMBUS_READ_BYTE))
   81              || (cmd == MODE_QUICK &&
   82                  !(funcs & I2C_FUNC_SMBUS_QUICK))) {
   83                 printf("   ");
   84                 continue;
   85             }
   86 
   87             /* Set slave address */
   88             if (ioctl(file, I2C_SLAVE, i+j) < 0) {
   89                 if (errno == EBUSY) {
   90                     printf("UU ");
   91                     continue;
   92                 } else {
   93                     fprintf(stderr, "Error: Could not set "
   94                         "address to 0x%02x: %s\n", i+j,
   95                         strerror(errno));
   96                     return -1;
   97                 }
   98             }
   99 
  100             /* Probe this address */
  101             switch (cmd) {
  102             default: /* MODE_QUICK */
  103                 /* This is known to corrupt the Atmel AT24RF08
  104                    EEPROM */
  105                 res = i2c_smbus_write_quick(file,
  106                       I2C_SMBUS_WRITE);
  107                 break;
  108             case MODE_READ:
  109                 /* This is known to lock SMBus on various
  110                    write-only chips (mainly clock chips) */
  111                 res = i2c_smbus_read_byte(file);
  112                 break;
  113             }
  114 
  115             if (res < 0)
  116                 printf("-- ");
  117             else
  118                 printf("%02x ", i+j);
  119         }
  120         printf("\n");
  121     }
  122 
  123     return 0;
  124 }
  125 
  126 struct func
  127 {
  128     long value;
  129     const char* name;
  130 };
  131 
  132 static const struct func all_func[] = {
  133     { .value = I2C_FUNC_I2C,
  134       .name = "I2C" },
  135     { .value = I2C_FUNC_SMBUS_QUICK,
  136       .name = "SMBus Quick Command" },
  137     { .value = I2C_FUNC_SMBUS_WRITE_BYTE,
  138       .name = "SMBus Send Byte" },
  139     { .value = I2C_FUNC_SMBUS_READ_BYTE,
  140       .name = "SMBus Receive Byte" },
  141     { .value = I2C_FUNC_SMBUS_WRITE_BYTE_DATA,
  142       .name = "SMBus Write Byte" },
  143     { .value = I2C_FUNC_SMBUS_READ_BYTE_DATA,
  144       .name = "SMBus Read Byte" },
  145     { .value = I2C_FUNC_SMBUS_WRITE_WORD_DATA,
  146       .name = "SMBus Write Word" },
  147     { .value = I2C_FUNC_SMBUS_READ_WORD_DATA,
  148       .name = "SMBus Read Word" },
  149     { .value = I2C_FUNC_SMBUS_PROC_CALL,
  150       .name = "SMBus Process Call" },
  151     { .value = I2C_FUNC_SMBUS_WRITE_BLOCK_DATA,
  152       .name = "SMBus Block Write" },
  153     { .value = I2C_FUNC_SMBUS_READ_BLOCK_DATA,
  154       .name = "SMBus Block Read" },
  155     { .value = I2C_FUNC_SMBUS_BLOCK_PROC_CALL,
  156       .name = "SMBus Block Process Call" },
  157     { .value = I2C_FUNC_SMBUS_PEC,
  158       .name = "SMBus PEC" },
  159     { .value = I2C_FUNC_SMBUS_WRITE_I2C_BLOCK,
  160       .name = "I2C Block Write" },
  161     { .value = I2C_FUNC_SMBUS_READ_I2C_BLOCK,
  162       .name = "I2C Block Read" },
  163     { .value = 0, .name = "" }
  164 };
  165 
  166 static void print_functionality(unsigned long funcs)
  167 {
  168     int i;
  169 
  170     for (i = 0; all_func[i].value; i++) {
  171         printf("%-32s %s\n", all_func[i].name,
  172                (funcs & all_func[i].value) ? "yes" : "no");
  173     }
  174 }
  175 
  176 /*
  177  * Print the installed i2c busses. The format is those of Linux 2.4's
  178  * /proc/bus/i2c for historical compatibility reasons.
  179  */
  180 static void print_i2c_busses(void)
  181 {
  182     struct i2c_adap *adapters;
  183     int count;
  184 
  185     adapters = gather_i2c_busses();
  186     if (adapters == NULL) {
  187         fprintf(stderr, "Error: Out of memory!\n");
  188         return;
  189     }
  190 
  191     for (count = 0; adapters[count].name; count++) {
  192         printf("i2c-%d\t%-10s\t%-32s\t%s\n",
  193             adapters[count].nr, adapters[count].funcs,
  194             adapters[count].name, adapters[count].algo);
  195     }
  196 
  197     free_adapters(adapters);
  198 }
  199 
  200 int main(int argc, char *argv[])
  201 {
  202     char *end;
  203     int i2cbus, file, res;
  204     char filename[20];
  205     unsigned long funcs;
  206     int mode = MODE_AUTO;
  207     int first = 0x08, last = 0x77;
  208     int flags = 0;
  209     int yes = 0, version = 0, list = 0;
  210 
  211     /* handle (optional) flags first */
  212     while (1+flags < argc && argv[1+flags][0] == '-') {
  213         switch (argv[1+flags][1]) {
  214         case 'V': version = 1; break;
  215         case 'y': yes = 1; break;
  216         case 'l': list = 1; break;
  217         case 'F':
  218             if (mode != MODE_AUTO && mode != MODE_FUNC) {
  219                 fprintf(stderr, "Error: Different modes "
  220                     "specified!\n");
  221                 exit(1);
  222             }
  223             mode = MODE_FUNC;
  224             break;
  225         case 'r':
  226             if (mode == MODE_QUICK) {
  227                 fprintf(stderr, "Error: Different modes "
  228                     "specified!\n");
  229                 exit(1);
  230             }
  231             mode = MODE_READ;
  232             break;
  233         case 'q':
  234             if (mode == MODE_READ) {
  235                 fprintf(stderr, "Error: Different modes "
  236                     "specified!\n");
  237                 exit(1);
  238             }
  239             mode = MODE_QUICK;
  240             break;
  241         case 'a':
  242             first = 0x00;
  243             last = 0x7F;
  244             break;
  245         default:
  246             fprintf(stderr, "Error: Unsupported option "
  247                 "\"%s\"!\n", argv[1+flags]);
  248             help();
  249             exit(1);
  250         }
  251         flags++;
  252     }
  253 
  254     if (version) {
  255         fprintf(stderr, "i2cdetect version %s\n", VERSION);
  256         exit(0);
  257     }
  258 
  259     if (list) {
  260         print_i2c_busses();
  261         exit(0);
  262     }
  263 
  264     if (argc < flags + 2) {
  265         fprintf(stderr, "Error: No i2c-bus specified!\n");
  266         help();
  267         exit(1);
  268     }
  269     i2cbus = lookup_i2c_bus(argv[flags+1]);
  270     if (i2cbus < 0) {
  271         help();
  272         exit(1);
  273     }
  274 
  275     /* read address range if present */
  276     if (argc == flags + 4 && mode != MODE_FUNC) {
  277         int tmp;
  278 
  279         tmp = strtol(argv[flags+2], &end, 0);
  280         if (*end) {
  281             fprintf(stderr, "Error: FIRST argment not a "
  282                 "number!\n");
  283             help();
  284             exit(1);
  285         }
  286         if (tmp < first || tmp > last) {
  287             fprintf(stderr, "Error: FIRST argument out of range "
  288                 "(0x%02x-0x%02x)!\n", first, last);
  289             help();
  290             exit(1);
  291         }
  292         first = tmp;
  293 
  294         tmp = strtol(argv[flags+3], &end, 0);
  295         if (*end) {
  296             fprintf(stderr, "Error: LAST argment not a "
  297                 "number!\n");
  298             help();
  299             exit(1);
  300         }
  301         if (tmp < first || tmp > last) {
  302             fprintf(stderr, "Error: LAST argument out of range "
  303                 "(0x%02x-0x%02x)!\n", first, last);
  304             help();
  305             exit(1);
  306         }
  307         last = tmp;
  308     } else if (argc != flags + 2) {
  309         help();
  310         exit(1);
  311     }
  312 
  313     file = open_i2c_dev(i2cbus, filename, sizeof(filename), 0);
  314     if (file < 0) {
  315         exit(1);
  316     }
  317 
  318     if (ioctl(file, I2C_FUNCS, &funcs) < 0) {
  319         fprintf(stderr, "Error: Could not get the adapter "
  320             "functionality matrix: %s\n", strerror(errno));
  321         close(file);
  322         exit(1);
  323     }
  324 
  325     /* Special case, we only list the implemented functionalities */
  326     if (mode == MODE_FUNC) {
  327         close(file);
  328         printf("Functionalities implemented by %s:\n", filename);
  329         print_functionality(funcs);
  330         exit(0);
  331     }
  332 
  333     if (!(funcs & (I2C_FUNC_SMBUS_QUICK | I2C_FUNC_SMBUS_READ_BYTE))) {
  334         fprintf(stderr,
  335             "Error: Bus doesn't support detection commands\n");
  336         close(file);
  337         exit(1);
  338     }
  339     if (mode == MODE_QUICK && !(funcs & I2C_FUNC_SMBUS_QUICK)) {
  340         fprintf(stderr, "Error: Can't use SMBus Quick Write command "
  341             "on this bus\n");
  342         close(file);
  343         exit(1);
  344     }
  345     if (mode == MODE_READ && !(funcs & I2C_FUNC_SMBUS_READ_BYTE)) {
  346         fprintf(stderr, "Error: Can't use SMBus Receive Byte command "
  347             "on this bus\n");
  348         close(file);
  349         exit(1);
  350     }
  351     if (mode == MODE_AUTO) {
  352         if (!(funcs & I2C_FUNC_SMBUS_QUICK))
  353             fprintf(stderr, "Warning: Can't use SMBus Quick Write "
  354                 "command, will skip some addresses\n");
  355         if (!(funcs & I2C_FUNC_SMBUS_READ_BYTE))
  356             fprintf(stderr, "Warning: Can't use SMBus Receive Byte "
  357                 "command, will skip some addresses\n");
  358     }
  359 
  360     if (!yes) {
  361         char s[2];
  362 
  363         fprintf(stderr, "WARNING! This program can confuse your I2C "
  364             "bus, cause data loss and worse!\n");
  365 
  366         fprintf(stderr, "I will probe file %s%s.\n", filename,
  367             mode==MODE_QUICK?" using quick write commands":
  368             mode==MODE_READ?" using receive byte commands":"");
  369         fprintf(stderr, "I will probe address range 0x%02x-0x%02x.\n",
  370             first, last);
  371 
  372         fprintf(stderr, "Continue? [Y/n] ");
  373         fflush(stderr);
  374         if (!fgets(s, 2, stdin)
  375          || (s[0] != '\n' && s[0] != 'y' && s[0] != 'Y')) {
  376             fprintf(stderr, "Aborting on user request.\n");
  377             exit(0);
  378         }
  379     }
  380 
  381     res = scan_i2c_bus(file, mode, funcs, first, last);
  382 
  383     close(file);
  384 
  385     exit(res?1:0);
  386 }