"Fossies" - the Fresh Open Source Software Archive

Member "i2c-tools-4.3/tools/i2cget.c" (22 Jul 2021, 8603 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 "i2cget.c" see the Fossies "Dox" file reference documentation and the latest Fossies "Diffs" side-by-side code changes report: 4.2_vs_4.3.

    1 /*
    2     i2cget.c - A user-space program to read an I2C register.
    3     Copyright (C) 2005-2021  Jean Delvare <jdelvare@suse.de>
    4 
    5     Based on i2cset.c:
    6     Copyright (C) 2001-2003  Frodo Looijaard <frodol@dds.nl>, and
    7                              Mark D. Studebaker <mdsxyz123@yahoo.com>
    8     Copyright (C) 2004-2005  Jean Delvare
    9 
   10     This program is free software; you can redistribute it and/or modify
   11     it under the terms of the GNU General Public License as published by
   12     the Free Software Foundation; either version 2 of the License, or
   13     (at your option) any later version.
   14 
   15     This program is distributed in the hope that it will be useful,
   16     but WITHOUT ANY WARRANTY; without even the implied warranty of
   17     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   18     GNU General Public License for more details.
   19 
   20     You should have received a copy of the GNU General Public License
   21     along with this program; if not, write to the Free Software
   22     Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
   23     MA 02110-1301 USA.
   24 */
   25 
   26 #include <sys/ioctl.h>
   27 #include <errno.h>
   28 #include <string.h>
   29 #include <stdio.h>
   30 #include <stdlib.h>
   31 #include <unistd.h>
   32 #include <linux/i2c.h>
   33 #include <linux/i2c-dev.h>
   34 #include <i2c/smbus.h>
   35 #include "i2cbusses.h"
   36 #include "util.h"
   37 #include "../version.h"
   38 
   39 static void help(void) __attribute__ ((noreturn));
   40 
   41 static void help(void)
   42 {
   43     fprintf(stderr,
   44         "Usage: i2cget [-f] [-y] [-a] I2CBUS CHIP-ADDRESS [DATA-ADDRESS [MODE [LENGTH]]]\n"
   45         "  I2CBUS is an integer or an I2C bus name\n"
   46         "  ADDRESS is an integer (0x08 - 0x77, or 0x00 - 0x7f if -a is given)\n"
   47         "  MODE is one of:\n"
   48         "    b (read byte data, default)\n"
   49         "    w (read word data)\n"
   50         "    c (write byte/read byte)\n"
   51         "    s (read SMBus block data)\n"
   52         "    i (read I2C block data)\n"
   53         "    Append p for SMBus PEC\n"
   54         "  LENGTH is the I2C block data length (between 1 and %d, default %d)\n",
   55         I2C_SMBUS_BLOCK_MAX, I2C_SMBUS_BLOCK_MAX);
   56     exit(1);
   57 }
   58 
   59 static int check_funcs(int file, int size, int daddress, int pec)
   60 {
   61     unsigned long funcs;
   62 
   63     /* check adapter functionality */
   64     if (ioctl(file, I2C_FUNCS, &funcs) < 0) {
   65         fprintf(stderr, "Error: Could not get the adapter "
   66             "functionality matrix: %s\n", strerror(errno));
   67         return -1;
   68     }
   69 
   70     switch (size) {
   71     case I2C_SMBUS_BYTE:
   72         if (!(funcs & I2C_FUNC_SMBUS_READ_BYTE)) {
   73             fprintf(stderr, MISSING_FUNC_FMT, "SMBus receive byte");
   74             return -1;
   75         }
   76         if (daddress >= 0
   77          && !(funcs & I2C_FUNC_SMBUS_WRITE_BYTE)) {
   78             fprintf(stderr, MISSING_FUNC_FMT, "SMBus send byte");
   79             return -1;
   80         }
   81         break;
   82 
   83     case I2C_SMBUS_BYTE_DATA:
   84         if (!(funcs & I2C_FUNC_SMBUS_READ_BYTE_DATA)) {
   85             fprintf(stderr, MISSING_FUNC_FMT, "SMBus read byte");
   86             return -1;
   87         }
   88         break;
   89 
   90     case I2C_SMBUS_WORD_DATA:
   91         if (!(funcs & I2C_FUNC_SMBUS_READ_WORD_DATA)) {
   92             fprintf(stderr, MISSING_FUNC_FMT, "SMBus read word");
   93             return -1;
   94         }
   95         break;
   96 
   97     case I2C_SMBUS_BLOCK_DATA:
   98         if (!(funcs & I2C_FUNC_SMBUS_READ_BLOCK_DATA)) {
   99             fprintf(stderr, MISSING_FUNC_FMT, "SMBus block read");
  100             return -1;
  101         }
  102         break;
  103 
  104     case I2C_SMBUS_I2C_BLOCK_DATA:
  105         if (!(funcs & I2C_FUNC_SMBUS_READ_I2C_BLOCK)) {
  106             fprintf(stderr, MISSING_FUNC_FMT, "I2C block read");
  107             return -1;
  108         }
  109         break;
  110     }
  111 
  112     if (pec
  113      && !(funcs & (I2C_FUNC_SMBUS_PEC | I2C_FUNC_I2C))) {
  114         fprintf(stderr, "Warning: Adapter does "
  115             "not seem to support PEC\n");
  116     }
  117 
  118     return 0;
  119 }
  120 
  121 static int confirm(const char *filename, int address, int size, int daddress,
  122            int length, int pec)
  123 {
  124     int dont = 0;
  125 
  126     fprintf(stderr, "WARNING! This program can confuse your I2C "
  127         "bus, cause data loss and worse!\n");
  128 
  129     /* Don't let the user break his/her EEPROMs */
  130     if (address >= 0x50 && address <= 0x57 && pec) {
  131         fprintf(stderr, "STOP! EEPROMs are I2C devices, not "
  132             "SMBus devices. Using PEC\non I2C devices may "
  133             "result in unexpected results, such as\n"
  134             "trashing the contents of EEPROMs. We can't "
  135             "let you do that, sorry.\n");
  136         return 0;
  137     }
  138 
  139     if (size == I2C_SMBUS_BYTE && daddress >= 0 && pec) {
  140         fprintf(stderr, "WARNING! All I2C chips and some SMBus chips "
  141             "will interpret a write\nbyte command with PEC as a"
  142             "write byte data command, effectively writing a\n"
  143             "value into a register!\n");
  144         dont++;
  145     }
  146 
  147     fprintf(stderr, "I will read from device file %s, chip "
  148         "address 0x%02x, ", filename, address);
  149     if (daddress < 0)
  150         fprintf(stderr, "current data\naddress");
  151     else
  152         fprintf(stderr, "data address\n0x%02x", daddress);
  153     if (size == I2C_SMBUS_I2C_BLOCK_DATA)
  154         fprintf(stderr, ", %d %s using read I2C block data.\n",
  155             length, length > 1 ? "bytes" : "byte");
  156     else
  157         fprintf(stderr, ", using %s.\n",
  158             size == I2C_SMBUS_BYTE ? (daddress < 0 ?
  159             "read byte" : "write byte/read byte") :
  160             size == I2C_SMBUS_BYTE_DATA ? "read byte data" :
  161             size == I2C_SMBUS_BLOCK_DATA ? "read SMBus block data" :
  162             "read word data");
  163     if (pec)
  164         fprintf(stderr, "PEC checking enabled.\n");
  165 
  166     fprintf(stderr, "Continue? [%s] ", dont ? "y/N" : "Y/n");
  167     fflush(stderr);
  168     if (!user_ack(!dont)) {
  169         fprintf(stderr, "Aborting on user request.\n");
  170         return 0;
  171     }
  172 
  173     return 1;
  174 }
  175 
  176 int main(int argc, char *argv[])
  177 {
  178     char *end;
  179     int res, i2cbus, address, size, file;
  180     int daddress;
  181     char filename[20];
  182     int pec = 0;
  183     int flags = 0;
  184     int force = 0, yes = 0, version = 0, all_addrs = 0;
  185     int length;
  186     unsigned char block_data[I2C_SMBUS_BLOCK_MAX];
  187 
  188     /* handle (optional) flags first */
  189     while (1+flags < argc && argv[1+flags][0] == '-') {
  190         switch (argv[1+flags][1]) {
  191         case 'V': version = 1; break;
  192         case 'f': force = 1; break;
  193         case 'y': yes = 1; break;
  194         case 'a': all_addrs = 1; break;
  195         default:
  196             fprintf(stderr, "Error: Unsupported option "
  197                 "\"%s\"!\n", argv[1+flags]);
  198             help();
  199             exit(1);
  200         }
  201         flags++;
  202     }
  203 
  204     if (version) {
  205         fprintf(stderr, "i2cget version %s\n", VERSION);
  206         exit(0);
  207     }
  208 
  209     if (argc < flags + 3)
  210         help();
  211 
  212     i2cbus = lookup_i2c_bus(argv[flags+1]);
  213     if (i2cbus < 0)
  214         help();
  215 
  216     address = parse_i2c_address(argv[flags+2], all_addrs);
  217     if (address < 0)
  218         help();
  219 
  220     if (argc > flags + 3) {
  221         size = I2C_SMBUS_BYTE_DATA;
  222         daddress = strtol(argv[flags+3], &end, 0);
  223         if (*end || daddress < 0 || daddress > 0xff) {
  224             fprintf(stderr, "Error: Data address invalid!\n");
  225             help();
  226         }
  227     } else {
  228         size = I2C_SMBUS_BYTE;
  229         daddress = -1;
  230     }
  231 
  232     if (argc > flags + 4) {
  233         switch (argv[flags+4][0]) {
  234         case 'b': size = I2C_SMBUS_BYTE_DATA; break;
  235         case 'w': size = I2C_SMBUS_WORD_DATA; break;
  236         case 'c': size = I2C_SMBUS_BYTE; break;
  237         case 's': size = I2C_SMBUS_BLOCK_DATA; break;
  238         case 'i': size = I2C_SMBUS_I2C_BLOCK_DATA; break;
  239         default:
  240             fprintf(stderr, "Error: Invalid mode!\n");
  241             help();
  242         }
  243         pec = argv[flags+4][1] == 'p';
  244         if (size == I2C_SMBUS_I2C_BLOCK_DATA && pec) {
  245             fprintf(stderr, "Error: PEC not supported for I2C block data!\n");
  246             help();
  247         }
  248     }
  249 
  250     if (argc > flags + 5) {
  251         if (size != I2C_SMBUS_I2C_BLOCK_DATA) {
  252             fprintf(stderr, "Error: Length only valid for I2C block data!\n");
  253             help();
  254         }
  255         length = strtol(argv[flags+5], &end, 0);
  256         if (*end || length < 1 || length > I2C_SMBUS_BLOCK_MAX) {
  257             fprintf(stderr, "Error: Length invalid!\n");
  258             help();
  259         }
  260     } else {
  261         length = I2C_SMBUS_BLOCK_MAX;
  262     }
  263 
  264     file = open_i2c_dev(i2cbus, filename, sizeof(filename), 0);
  265     if (file < 0
  266      || check_funcs(file, size, daddress, pec)
  267      || set_slave_addr(file, address, force))
  268         exit(1);
  269 
  270     if (!yes && !confirm(filename, address, size, daddress, length, pec))
  271         exit(0);
  272 
  273     if (pec && ioctl(file, I2C_PEC, 1) < 0) {
  274         fprintf(stderr, "Error: Could not set PEC: %s\n",
  275             strerror(errno));
  276         close(file);
  277         exit(1);
  278     }
  279 
  280     switch (size) {
  281     case I2C_SMBUS_BYTE:
  282         if (daddress >= 0) {
  283             res = i2c_smbus_write_byte(file, daddress);
  284             if (res < 0)
  285                 fprintf(stderr, "Warning - write failed\n");
  286         }
  287         res = i2c_smbus_read_byte(file);
  288         break;
  289     case I2C_SMBUS_WORD_DATA:
  290         res = i2c_smbus_read_word_data(file, daddress);
  291         break;
  292     case I2C_SMBUS_BLOCK_DATA:
  293         res = i2c_smbus_read_block_data(file, daddress, block_data);
  294         break;
  295     case I2C_SMBUS_I2C_BLOCK_DATA:
  296         res = i2c_smbus_read_i2c_block_data(file, daddress, length, block_data);
  297         break;
  298     default: /* I2C_SMBUS_BYTE_DATA */
  299         res = i2c_smbus_read_byte_data(file, daddress);
  300     }
  301     close(file);
  302 
  303     if (res < 0) {
  304         fprintf(stderr, "Error: Read failed\n");
  305         exit(2);
  306     }
  307 
  308     if (size == I2C_SMBUS_BLOCK_DATA ||
  309         size == I2C_SMBUS_I2C_BLOCK_DATA) {
  310         int i;
  311 
  312         for (i = 0; i < res - 1; ++i)
  313             printf("0x%02hhx ", block_data[i]);
  314         printf("0x%02hhx\n", block_data[res - 1]);
  315     } else {
  316         printf("0x%0*x\n", size == I2C_SMBUS_WORD_DATA ? 4 : 2, res);
  317     }
  318 
  319     exit(0);
  320 }