summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorWolfram Sang <wsa+renesas@sang-engineering.com>2020-06-27 23:44:29 +0200
committerWolfram Sang <wsa@kernel.org>2020-08-10 12:06:29 +0200
commit264b9c5356a82ff2bb19957963c2680e71729557 (patch)
treecff5e34874e789c1b0d5e3968f040d9f6cf8a289
parent14281056546e45230384e1f0ecf8ec59703a5b26 (diff)
downloadi2c-tools-git-264b9c5356a82ff2bb19957963c2680e71729557.tar.gz
i2ctransfer: add support for I2C_M_RECV_LEN
Signed-off-by: Wolfram Sang <wsa+renesas@sang-engineering.com> Signed-off-by: Wolfram Sang <wsa@kernel.org>
-rw-r--r--CHANGES1
-rw-r--r--tools/i2ctransfer.81
-rw-r--r--tools/i2ctransfer.c44
3 files changed, 34 insertions, 12 deletions
diff --git a/CHANGES b/CHANGES
index db534fc..4b165b6 100644
--- a/CHANGES
+++ b/CHANGES
@@ -9,6 +9,7 @@ master
decode-dimms: Print SPD revision for DDR3 too
Move SDR-specific code
i2ctransfer: Mention '-a' everywhere in the manpage
+ support messages using I2C_M_RECV_LEN
4.1 (2018-11-30)
Makefile: Make STRIP, DESTDIR and PREFIX overridable
diff --git a/tools/i2ctransfer.8 b/tools/i2ctransfer.8
index cf2d14c..3b14375 100644
--- a/tools/i2ctransfer.8
+++ b/tools/i2ctransfer.8
@@ -91,6 +91,7 @@ specifies if the message is read or write
.B <length_of_message>
specifies the number of bytes read or written in this message.
It is parsed as an unsigned 16 bit integer, but note that the Linux Kernel applies an additional upper limit (8192 as of v4.10).
+For read messages to targets which support SMBus Block transactions, it can also be '?', then the target will determine the length.
.TP
.B [@address]
specifies the 7-bit address of the chip to be accessed for this message, and is an integer.
diff --git a/tools/i2ctransfer.c b/tools/i2ctransfer.c
index 7b95d48..b0e8d43 100644
--- a/tools/i2ctransfer.c
+++ b/tools/i2ctransfer.c
@@ -45,7 +45,8 @@ static void help(void)
"Usage: i2ctransfer [-f] [-y] [-v] [-V] [-a] I2CBUS DESC [DATA] [DESC [DATA]]...\n"
" I2CBUS is an integer or an I2C bus name\n"
" DESC describes the transfer in the form: {r|w}LENGTH[@address]\n"
- " 1) read/write-flag 2) LENGTH (range 0-65535) 3) I2C address (use last one if omitted)\n"
+ " 1) read/write-flag 2) LENGTH (range 0-65535, or '?')\n"
+ " 3) I2C address (use last one if omitted)\n"
" DATA are LENGTH bytes for a write message. They can be shortened by a suffix:\n"
" = (keep value constant until LENGTH)\n"
" + (increase value by 1 until LENGTH)\n"
@@ -84,17 +85,24 @@ static void print_msgs(struct i2c_msg *msgs, __u32 nmsgs, unsigned flags)
for (i = 0; i < nmsgs; i++) {
int read = msgs[i].flags & I2C_M_RD;
+ int recv_len = msgs[i].flags & I2C_M_RECV_LEN;
int print_buf = (read && (flags & PRINT_READ_BUF)) ||
(!read && (flags & PRINT_WRITE_BUF));
+ __u16 len = recv_len ? msgs[i].buf[0] + 1 : msgs[i].len;
+
+ if (flags & PRINT_HEADER) {
+ fprintf(output, "msg %u: addr 0x%02x, %s, len ",
+ i, msgs[i].addr, read ? "read" : "write");
+ if (!recv_len || flags & PRINT_READ_BUF)
+ fprintf(output, "%u", len);
+ else
+ fprintf(output, "TBD");
+ }
- if (flags & PRINT_HEADER)
- fprintf(output, "msg %u: addr 0x%02x, %s, len %u",
- i, msgs[i].addr, read ? "read" : "write", msgs[i].len);
-
- if (msgs[i].len && print_buf) {
+ if (len && print_buf) {
if (flags & PRINT_HEADER)
fprintf(output, ", buf ");
- for (j = 0; j < msgs[i].len - 1; j++)
+ for (j = 0; j < len - 1; j++)
fprintf(output, "0x%02x ", msgs[i].buf[j]);
/* Print final byte with newline */
fprintf(output, "0x%02x\n", msgs[i].buf[j]);
@@ -192,13 +200,23 @@ int main(int argc, char *argv[])
goto err_out_with_arg;
}
- len = strtoul(arg_ptr, &end, 0);
- if (len > 0xffff || arg_ptr == end) {
- fprintf(stderr, "Error: Length invalid\n");
- goto err_out_with_arg;
+ if (*arg_ptr == '?') {
+ if (!(flags & I2C_M_RD)) {
+ fprintf(stderr, "Error: variable length not allowed with write\n");
+ goto err_out_with_arg;
+ }
+ len = 256; /* SMBUS3_MAX_BLOCK_LEN + 1 */
+ flags |= I2C_M_RECV_LEN;
+ arg_ptr++;
+ } else {
+ len = strtoul(arg_ptr, &end, 0);
+ if (len > 0xffff || arg_ptr == end) {
+ fprintf(stderr, "Error: Length invalid\n");
+ goto err_out_with_arg;
+ }
+ arg_ptr = end;
}
- arg_ptr = end;
if (*arg_ptr) {
if (*arg_ptr++ != '@') {
fprintf(stderr, "Error: Unknown separator after length\n");
@@ -237,6 +255,8 @@ int main(int argc, char *argv[])
}
memset(buf, 0, len);
msgs[nmsgs].buf = buf;
+ if (flags & I2C_M_RECV_LEN)
+ buf[0] = 1; /* number of extra bytes */
}
if (flags & I2C_M_RD || len == 0) {