"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.

    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 }