"Fossies" - the Fresh Open Source Software Archive

Member "i2c-tools-4.3/tools/i2ctransfer.c" (22 Jul 2021, 9049 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 "i2ctransfer.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     i2ctransfer.c - A user-space program to send concatenated i2c messages
    3     Copyright (C) 2015-17 Wolfram Sang <wsa@sang-engineering.com>
    4     Copyright (C) 2015-17 Renesas Electronics Corporation
    5 
    6     Based on i2cget.c:
    7     Copyright (C) 2005-2012  Jean Delvare <jdelvare@suse.de>
    8 
    9     This program is free software; you can redistribute it and/or modify
   10     it under the terms of the GNU General Public License as published by
   11     the Free Software Foundation; either version 2 of the License, or
   12     (at your option) any later version.
   13 
   14     This program is distributed in the hope that it will be useful,
   15     but WITHOUT ANY WARRANTY; without even the implied warranty of
   16     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   17     GNU General Public License for more details.
   18 */
   19 
   20 #include <sys/ioctl.h>
   21 #include <errno.h>
   22 #include <string.h>
   23 #include <stdio.h>
   24 #include <stdlib.h>
   25 #include <unistd.h>
   26 #include <linux/i2c.h>
   27 #include <linux/i2c-dev.h>
   28 #include "i2cbusses.h"
   29 #include "util.h"
   30 #include "../version.h"
   31 
   32 enum parse_state {
   33     PARSE_GET_DESC,
   34     PARSE_GET_DATA,
   35 };
   36 
   37 #define PRINT_STDERR    (1 << 0)
   38 #define PRINT_READ_BUF  (1 << 1)
   39 #define PRINT_WRITE_BUF (1 << 2)
   40 #define PRINT_HEADER    (1 << 3)
   41 
   42 static void help(void)
   43 {
   44     fprintf(stderr,
   45         "Usage: i2ctransfer [-f] [-y] [-v] [-V] [-a] I2CBUS DESC [DATA] [DESC [DATA]]...\n"
   46         "  I2CBUS is an integer or an I2C bus name\n"
   47         "  DESC describes the transfer in the form: {r|w}LENGTH[@address]\n"
   48         "    1) read/write-flag 2) LENGTH (range 0-65535, or '?')\n"
   49         "    3) I2C address (use last one if omitted)\n"
   50         "  DATA are LENGTH bytes for a write message. They can be shortened by a suffix:\n"
   51         "    = (keep value constant until LENGTH)\n"
   52         "    + (increase value by 1 until LENGTH)\n"
   53         "    - (decrease value by 1 until LENGTH)\n"
   54         "    p (use pseudo random generator until LENGTH with value as seed)\n\n"
   55         "Example (bus 0, read 8 byte at offset 0x64 from EEPROM at 0x50):\n"
   56         "  # i2ctransfer 0 w1@0x50 0x64 r8\n"
   57         "Example (same EEPROM, at offset 0x42 write 0xff 0xfe ... 0xf0):\n"
   58         "  # i2ctransfer 0 w17@0x50 0x42 0xff-\n");
   59 }
   60 
   61 static int check_funcs(int file)
   62 {
   63     unsigned long funcs;
   64 
   65     /* check adapter functionality */
   66     if (ioctl(file, I2C_FUNCS, &funcs) < 0) {
   67         fprintf(stderr, "Error: Could not get the adapter "
   68             "functionality matrix: %s\n", strerror(errno));
   69         return -1;
   70     }
   71 
   72     if (!(funcs & I2C_FUNC_I2C)) {
   73         fprintf(stderr, MISSING_FUNC_FMT, "I2C transfers");
   74         return -1;
   75     }
   76 
   77     return 0;
   78 }
   79 
   80 static void print_msgs(struct i2c_msg *msgs, __u32 nmsgs, unsigned flags)
   81 {
   82     FILE *output = flags & PRINT_STDERR ? stderr : stdout;
   83     unsigned i;
   84     __u16 j;
   85 
   86     for (i = 0; i < nmsgs; i++) {
   87         int read = msgs[i].flags & I2C_M_RD;
   88         int recv_len = msgs[i].flags & I2C_M_RECV_LEN;
   89         int print_buf = (read && (flags & PRINT_READ_BUF)) ||
   90                 (!read && (flags & PRINT_WRITE_BUF));
   91         __u16 len = recv_len ? msgs[i].buf[0] + 1 : msgs[i].len;
   92 
   93         if (flags & PRINT_HEADER) {
   94             fprintf(output, "msg %u: addr 0x%02x, %s, len ",
   95                 i, msgs[i].addr, read ? "read" : "write");
   96             if (!recv_len || flags & PRINT_READ_BUF)
   97                 fprintf(output, "%u", len);
   98             else
   99                 fprintf(output, "TBD");
  100         }
  101 
  102         if (len && print_buf) {
  103             if (flags & PRINT_HEADER)
  104                 fprintf(output, ", buf ");
  105             for (j = 0; j < len - 1; j++)
  106                 fprintf(output, "0x%02x ", msgs[i].buf[j]);
  107             /* Print final byte with newline */
  108             fprintf(output, "0x%02x\n", msgs[i].buf[j]);
  109         } else if (flags & PRINT_HEADER) {
  110             fprintf(output, "\n");
  111         }
  112     }
  113 }
  114 
  115 static int confirm(const char *filename, struct i2c_msg *msgs, __u32 nmsgs)
  116 {
  117     fprintf(stderr, "WARNING! This program can confuse your I2C bus, cause data loss and worse!\n");
  118     fprintf(stderr, "I will send the following messages to device file %s:\n", filename);
  119     print_msgs(msgs, nmsgs, PRINT_STDERR | PRINT_HEADER | PRINT_WRITE_BUF);
  120 
  121     fprintf(stderr, "Continue? [y/N] ");
  122     fflush(stderr);
  123     if (!user_ack(0)) {
  124         fprintf(stderr, "Aborting on user request.\n");
  125         return 0;
  126     }
  127 
  128     return 1;
  129 }
  130 
  131 int main(int argc, char *argv[])
  132 {
  133     char filename[20];
  134     int i2cbus, address = -1, file, arg_idx = 1, nmsgs = 0, nmsgs_sent, i;
  135     int force = 0, yes = 0, version = 0, verbose = 0, all_addrs = 0;
  136     struct i2c_msg msgs[I2C_RDRW_IOCTL_MAX_MSGS];
  137     enum parse_state state = PARSE_GET_DESC;
  138     unsigned buf_idx = 0;
  139 
  140     for (i = 0; i < I2C_RDRW_IOCTL_MAX_MSGS; i++)
  141         msgs[i].buf = NULL;
  142 
  143     /* handle (optional) arg_idx first */
  144     while (arg_idx < argc && argv[arg_idx][0] == '-') {
  145         switch (argv[arg_idx][1]) {
  146         case 'V': version = 1; break;
  147         case 'v': verbose = 1; break;
  148         case 'f': force = 1; break;
  149         case 'y': yes = 1; break;
  150         case 'a': all_addrs = 1; break;
  151         default:
  152             fprintf(stderr, "Error: Unsupported option \"%s\"!\n",
  153                 argv[arg_idx]);
  154             help();
  155             exit(1);
  156         }
  157         arg_idx++;
  158     }
  159 
  160     if (version) {
  161         fprintf(stderr, "i2ctransfer version %s\n", VERSION);
  162         exit(0);
  163     }
  164 
  165     if (arg_idx == argc) {
  166         help();
  167         exit(1);
  168     }
  169 
  170     i2cbus = lookup_i2c_bus(argv[arg_idx++]);
  171     if (i2cbus < 0)
  172         exit(1);
  173 
  174     file = open_i2c_dev(i2cbus, filename, sizeof(filename), 0);
  175     if (file < 0 || check_funcs(file))
  176         exit(1);
  177 
  178     while (arg_idx < argc) {
  179         char *arg_ptr = argv[arg_idx];
  180         unsigned long len, raw_data;
  181         __u16 flags;
  182         __u8 data, *buf;
  183         char *end;
  184 
  185         if (nmsgs > I2C_RDRW_IOCTL_MAX_MSGS) {
  186             fprintf(stderr, "Error: Too many messages (max: %d)\n",
  187                 I2C_RDRW_IOCTL_MAX_MSGS);
  188             goto err_out;
  189         }
  190 
  191         switch (state) {
  192         case PARSE_GET_DESC:
  193             flags = 0;
  194 
  195             switch (*arg_ptr++) {
  196             case 'r': flags |= I2C_M_RD; break;
  197             case 'w': break;
  198             default:
  199                 fprintf(stderr, "Error: Invalid direction\n");
  200                 goto err_out_with_arg;
  201             }
  202 
  203             if (*arg_ptr == '?') {
  204                 if (!(flags & I2C_M_RD)) {
  205                     fprintf(stderr, "Error: variable length not allowed with write\n");
  206                     goto err_out_with_arg;
  207                 }
  208                 len = 256; /* SMBUS3_MAX_BLOCK_LEN + 1 */
  209                 flags |= I2C_M_RECV_LEN;
  210                 arg_ptr++;
  211             } else {
  212                 len = strtoul(arg_ptr, &end, 0);
  213                 if (len > 0xffff || arg_ptr == end) {
  214                     fprintf(stderr, "Error: Length invalid\n");
  215                     goto err_out_with_arg;
  216                 }
  217                 arg_ptr = end;
  218             }
  219 
  220             if (*arg_ptr) {
  221                 if (*arg_ptr++ != '@') {
  222                     fprintf(stderr, "Error: Unknown separator after length\n");
  223                     goto err_out_with_arg;
  224                 }
  225 
  226                 /* We skip 10-bit support for now. If we want it,
  227                  * it should be marked with a 't' flag before
  228                  * the address here.
  229                  */
  230 
  231                 address = parse_i2c_address(arg_ptr, all_addrs);
  232                 if (address < 0)
  233                     goto err_out_with_arg;
  234 
  235                 /* Ensure address is not busy */
  236                 if (!force && set_slave_addr(file, address, 0))
  237                     goto err_out_with_arg;
  238             } else {
  239                 /* Reuse last address if possible */
  240                 if (address < 0) {
  241                     fprintf(stderr, "Error: No address given\n");
  242                     goto err_out_with_arg;
  243                 }
  244             }
  245 
  246             msgs[nmsgs].addr = address;
  247             msgs[nmsgs].flags = flags;
  248             msgs[nmsgs].len = len;
  249 
  250             if (len) {
  251                 buf = malloc(len);
  252                 if (!buf) {
  253                     fprintf(stderr, "Error: No memory for buffer\n");
  254                     goto err_out_with_arg;
  255                 }
  256                 memset(buf, 0, len);
  257                 msgs[nmsgs].buf = buf;
  258                 if (flags & I2C_M_RECV_LEN)
  259                     buf[0] = 1; /* number of extra bytes */
  260             }
  261 
  262             if (flags & I2C_M_RD || len == 0) {
  263                 nmsgs++;
  264             } else {
  265                 buf_idx = 0;
  266                 state = PARSE_GET_DATA;
  267             }
  268 
  269             break;
  270 
  271         case PARSE_GET_DATA:
  272             raw_data = strtoul(arg_ptr, &end, 0);
  273             if (raw_data > 0xff || arg_ptr == end) {
  274                 fprintf(stderr, "Error: Invalid data byte\n");
  275                 goto err_out_with_arg;
  276             }
  277             data = raw_data;
  278             len = msgs[nmsgs].len;
  279 
  280             while (buf_idx < len) {
  281                 msgs[nmsgs].buf[buf_idx++] = data;
  282 
  283                 if (!*end)
  284                     break;
  285 
  286                 switch (*end) {
  287                 /* Pseudo randomness (8 bit AXR with a=13 and b=27) */
  288                 case 'p':
  289                     data = (data ^ 27) + 13;
  290                     data = (data << 1) | (data >> 7);
  291                     break;
  292                 case '+': data++; break;
  293                 case '-': data--; break;
  294                 case '=': break;
  295                 default:
  296                     fprintf(stderr, "Error: Invalid data byte suffix\n");
  297                     goto err_out_with_arg;
  298                 }
  299             }
  300 
  301             if (buf_idx == len) {
  302                 nmsgs++;
  303                 state = PARSE_GET_DESC;
  304             }
  305 
  306             break;
  307 
  308         default:
  309             /* Should never happen */
  310             fprintf(stderr, "Internal Error: Unknown state in state machine!\n");
  311             goto err_out;
  312         }
  313 
  314         arg_idx++;
  315     }
  316 
  317     if (state != PARSE_GET_DESC || nmsgs == 0) {
  318         fprintf(stderr, "Error: Incomplete message\n");
  319         goto err_out;
  320     }
  321 
  322     if (yes || confirm(filename, msgs, nmsgs)) {
  323         struct i2c_rdwr_ioctl_data rdwr;
  324 
  325         rdwr.msgs = msgs;
  326         rdwr.nmsgs = nmsgs;
  327         nmsgs_sent = ioctl(file, I2C_RDWR, &rdwr);
  328         if (nmsgs_sent < 0) {
  329             fprintf(stderr, "Error: Sending messages failed: %s\n", strerror(errno));
  330             goto err_out;
  331         } else if (nmsgs_sent < nmsgs) {
  332             fprintf(stderr, "Warning: only %d/%d messages were sent\n", nmsgs_sent, nmsgs);
  333         }
  334 
  335         print_msgs(msgs, nmsgs_sent, PRINT_READ_BUF | (verbose ? PRINT_HEADER | PRINT_WRITE_BUF : 0));
  336     }
  337 
  338     close(file);
  339 
  340     for (i = 0; i < nmsgs; i++)
  341         free(msgs[i].buf);
  342 
  343     exit(0);
  344 
  345  err_out_with_arg:
  346     fprintf(stderr, "Error: faulty argument is '%s'\n", argv[arg_idx]);
  347  err_out:
  348     close(file);
  349 
  350     for (i = 0; i <= nmsgs; i++)
  351         free(msgs[i].buf);
  352 
  353     exit(1);
  354 }