git: e06874f3f6d1 - main - Centralize offset width handling, and make it possible to specify explicit endianess.
Poul-Henning Kamp
phk at FreeBSD.org
Wed May 12 20:02:07 UTC 2021
The branch main has been updated by phk:
URL: https://cgit.FreeBSD.org/src/commit/?id=e06874f3f6d1f9a737f4d6489a3de676a5cdc9ec
commit e06874f3f6d1f9a737f4d6489a3de676a5cdc9ec
Author: Poul-Henning Kamp <phk at FreeBSD.org>
AuthorDate: 2021-05-12 20:01:14 +0000
Commit: Poul-Henning Kamp <phk at FreeBSD.org>
CommitDate: 2021-05-12 20:01:14 +0000
Centralize offset width handling, and make it possible to specify explicit endianess.
---
usr.sbin/i2c/i2c.8 | 5 +-
usr.sbin/i2c/i2c.c | 214 ++++++++++++++++++++++++-----------------------------
2 files changed, 101 insertions(+), 118 deletions(-)
diff --git a/usr.sbin/i2c/i2c.8 b/usr.sbin/i2c/i2c.8
index 7e6fe0e7bd49..1c5174e63f32 100644
--- a/usr.sbin/i2c/i2c.8
+++ b/usr.sbin/i2c/i2c.8
@@ -36,7 +36,7 @@
.Cm -a Ar address
.Op Fl f Ar device
.Op Fl d Ar r|w
-.Op Fl w Ar 0|8|16
+.Op Fl w Ar 0|8|16|16LE|16BE
.Op Fl o Ar offset
.Op Fl c Ar count
.Op Fl m Ar tr|ss|rs|no
@@ -112,7 +112,7 @@ reset the controller.
scan the bus for devices.
.It Fl v
be verbose.
-.It Fl w Ar 0|8|16
+.It Fl w Ar 0|8|16|16LE|16BE
device addressing width (in bits).
This is used to determine how to pass
.Ar offset
@@ -120,6 +120,7 @@ specified with
.Fl o
to the slave.
Zero means that the offset is ignored and not passed to the slave at all.
+The endianess defaults to little-endian.
.El
.Sh WARNINGS
Great care must be taken when manipulating slave I2C devices with the
diff --git a/usr.sbin/i2c/i2c.c b/usr.sbin/i2c/i2c.c
index 604460625ecf..64233366a0a8 100644
--- a/usr.sbin/i2c/i2c.c
+++ b/usr.sbin/i2c/i2c.c
@@ -51,18 +51,20 @@ __FBSDID("$FreeBSD$");
#define I2C_MODE_TRANSFER 4
struct options {
- int width;
- int count;
- int verbose;
- int addr_set;
- int binary;
- int scan;
- int skip;
- int reset;
- int mode;
- char dir;
+ const char *width;
+ int count;
+ int verbose;
+ int addr_set;
+ int binary;
+ int scan;
+ int skip;
+ int reset;
+ int mode;
+ char dir;
uint32_t addr;
uint32_t off;
+ uint8_t off_buf[2];
+ size_t off_len;
};
struct skip_range {
@@ -267,30 +269,56 @@ reset_bus(const char *dev, int fd)
}
}
-static char *
-prepare_buf(int size, uint32_t off)
+static const char *
+encode_offset(const char *width, unsigned address, uint8_t *dst, size_t *len)
{
- char *buf;
-
- buf = malloc(size);
- if (buf == NULL)
- return (buf);
- if (size == 1)
- buf[0] = off & 0xff;
- else if (size == 2) {
- buf[0] = (off >> 8) & 0xff;
- buf[1] = off & 0xff;
+ if (!strcmp(width, "0")) {
+ *len = 0;
+ return (NULL);
+ }
+ if (!strcmp(width, "8")) {
+ if (address > 0xff)
+ return ("Invalid 8-bit address\n");
+ *dst = address;
+ *len = 1;
+ return (NULL);
}
+ if (address > 0xffff)
+ return ("Invalid 16-bit address\n");
+ if (!strcmp(width, "16LE") || !strcmp(width, "16")) {
+ le16enc(dst, address);
+ *len = 2;
+ return (NULL);
+ }
+ if (!strcmp(width, "16BE")) {
+ be16enc(dst, address);
+ *len = 2;
+ return (NULL);
+ }
+ return ("Invalid offset width, must be: 0|8|16|16LE|16BE\n");
+}
- return (buf);
+static const char *
+write_offset(int fd, struct options i2c_opt, struct iiccmd *cmd)
+{
+ int error;
+
+ if (i2c_opt.off_len > 0) {
+ cmd->count = i2c_opt.off_len;
+ cmd->buf = i2c_opt.off_buf;
+ error = ioctl(fd, I2CWRITE, cmd);
+ if (error == -1)
+ return ("ioctl: error writing offset\n");
+ }
+ return (NULL);
}
static int
i2c_write(int fd, struct options i2c_opt, char *i2c_buf)
{
struct iiccmd cmd;
- int error, bufsize;
+ int error;
char *buf;
const char *err_msg;
@@ -301,33 +329,11 @@ i2c_write(int fd, struct options i2c_opt, char *i2c_buf)
goto err1;
}
- if (i2c_opt.width) {
- bufsize = i2c_opt.width / 8;
- buf = prepare_buf(bufsize, i2c_opt.off);
- if (buf == NULL) {
- err_msg = "error: offset malloc";
- goto err1;
- }
- } else {
- bufsize = 0;
- buf = NULL;
- }
-
switch(i2c_opt.mode) {
case I2C_MODE_STOP_START:
- /*
- * Write offset where the data will go
- */
- if (i2c_opt.width) {
- cmd.count = bufsize;
- cmd.buf = buf;
- error = ioctl(fd, I2CWRITE, &cmd);
- free(buf);
- if (error == -1) {
- err_msg = "ioctl: error writing offset";
- goto err1;
- }
- }
+ err_msg = write_offset(fd, i2c_opt, &cmd);
+ if (err_msg != NULL)
+ goto err1;
error = ioctl(fd, I2CSTOP);
if (error == -1) {
@@ -355,19 +361,9 @@ i2c_write(int fd, struct options i2c_opt, char *i2c_buf)
break;
case I2C_MODE_REPEATED_START:
- /*
- * Write offset where the data will go
- */
- if (i2c_opt.width) {
- cmd.count = bufsize;
- cmd.buf = buf;
- error = ioctl(fd, I2CWRITE, &cmd);
- free(buf);
- if (error == -1) {
- err_msg = "ioctl: error writing offset";
- goto err1;
- }
- }
+ err_msg = write_offset(fd, i2c_opt, &cmd);
+ if (err_msg != NULL)
+ goto err1;
cmd.slave = i2c_opt.addr;
error = ioctl(fd, I2CRPTSTART, &cmd);
@@ -392,17 +388,18 @@ i2c_write(int fd, struct options i2c_opt, char *i2c_buf)
case I2C_MODE_NONE: /* fall through */
default:
- buf = realloc(buf, bufsize + i2c_opt.count);
+ buf = malloc(i2c_opt.off_len + i2c_opt.count);
if (buf == NULL) {
err_msg = "error: data malloc";
goto err1;
}
+ memcpy(buf, i2c_opt.off_buf, i2c_opt.off_len);
- memcpy(buf + bufsize, i2c_buf, i2c_opt.count);
+ memcpy(buf + i2c_opt.off_len, i2c_buf, i2c_opt.count);
/*
* Write offset and data
*/
- cmd.count = bufsize + i2c_opt.count;
+ cmd.count = i2c_opt.off_len + i2c_opt.count;
cmd.buf = buf;
cmd.last = 0;
error = ioctl(fd, I2CWRITE, &cmd);
@@ -436,13 +433,13 @@ static int
i2c_read(int fd, struct options i2c_opt, char *i2c_buf)
{
struct iiccmd cmd;
- int error, bufsize;
- char data = 0, *buf;
+ int error;
+ char data = 0;
const char *err_msg;
bzero(&cmd, sizeof(cmd));
- if (i2c_opt.width) {
+ if (i2c_opt.off_len) {
cmd.slave = i2c_opt.addr;
cmd.count = 1;
cmd.last = 0;
@@ -452,22 +449,10 @@ i2c_read(int fd, struct options i2c_opt, char *i2c_buf)
err_msg = "ioctl: error sending start condition";
goto err1;
}
- bufsize = i2c_opt.width / 8;
- buf = prepare_buf(bufsize, i2c_opt.off);
- if (buf == NULL) {
- err_msg = "error: offset malloc";
- goto err1;
- }
- cmd.count = bufsize;
- cmd.buf = buf;
- cmd.last = 0;
- error = ioctl(fd, I2CWRITE, &cmd);
- free(buf);
- if (error == -1) {
- err_msg = "ioctl: error writing offset";
+ err_msg = write_offset(fd, i2c_opt, &cmd);
+ if (err_msg != NULL)
goto err1;
- }
if (i2c_opt.mode == I2C_MODE_STOP_START) {
error = ioctl(fd, I2CSTOP);
@@ -481,7 +466,7 @@ i2c_read(int fd, struct options i2c_opt, char *i2c_buf)
cmd.count = 1;
cmd.last = 0;
cmd.buf = &data;
- if (i2c_opt.mode == I2C_MODE_STOP_START || i2c_opt.width == 0) {
+ if (i2c_opt.mode == I2C_MODE_STOP_START || i2c_opt.off_len == 0) {
error = ioctl(fd, I2CSTART, &cmd);
if (error == -1) {
err_msg = "ioctl: error sending start condition";
@@ -538,24 +523,17 @@ err2:
static int
i2c_rdwr_transfer(int fd, struct options i2c_opt, char *i2c_buf)
{
- struct iic_msg msgs[2];
+ struct iic_msg msgs[2], *msgp = msgs;
struct iic_rdwr_data xfer;
- int i;
- uint8_t off_buf[2];
-
- i = 0;
- if (i2c_opt.width > 0) {
- msgs[i].flags = IIC_M_WR | IIC_M_NOSTOP;
- msgs[i].slave = i2c_opt.addr;
- msgs[i].buf = off_buf;
- if (i2c_opt.width == 8) {
- off_buf[0] = i2c_opt.off;
- msgs[i].len = 1;
- } else {
- le16enc(off_buf, i2c_opt.off);
- msgs[i].len = 2;
- }
- ++i;
+ int flag = 0;
+
+ if (i2c_opt.off_len) {
+ msgp->flags = IIC_M_WR | IIC_M_NOSTOP;
+ msgp->slave = i2c_opt.addr;
+ msgp->buf = i2c_opt.off_buf;
+ msgp->len = i2c_opt.off_len;
+ msgp++;
+ flag = IIC_M_NOSTART;
}
/*
@@ -566,16 +544,16 @@ i2c_rdwr_transfer(int fd, struct options i2c_opt, char *i2c_buf)
* because of the NOSTOP flag used above.
*/
if (i2c_opt.dir == 'w')
- msgs[i].flags = IIC_M_WR | ((i > 0) ? IIC_M_NOSTART : 0);
+ msgp->flags = IIC_M_WR | flag;
else
- msgs[i].flags = IIC_M_RD;
- msgs[i].slave = i2c_opt.addr;
- msgs[i].len = i2c_opt.count;
- msgs[i].buf = i2c_buf;
- ++i;
+ msgp->flags = IIC_M_RD;
+ msgp->slave = i2c_opt.addr;
+ msgp->len = i2c_opt.count;
+ msgp->buf = i2c_buf;
+ msgp++;
xfer.msgs = msgs;
- xfer.nmsgs = i;
+ xfer.nmsgs = msgp - msgs;
if (ioctl(fd, I2CRDWR, &xfer) == -1 )
err(1, "ioctl(I2CRDWR) failed");
@@ -588,7 +566,7 @@ main(int argc, char** argv)
{
struct options i2c_opt;
char *skip_addr = NULL, *i2c_buf;
- const char *dev;
+ const char *dev, *err_msg;
int fd, error, chunk_size, i, j, ch;
errno = 0;
@@ -604,7 +582,7 @@ main(int argc, char** argv)
i2c_opt.off = 0;
i2c_opt.verbose = 0;
i2c_opt.dir = 'r'; /* direction = read */
- i2c_opt.width = 8;
+ i2c_opt.width = "8";
i2c_opt.count = 1;
i2c_opt.binary = 0; /* ASCII text output */
i2c_opt.scan = 0; /* no bus scan */
@@ -633,7 +611,7 @@ main(int argc, char** argv)
error = 1;
break;
case 'w':
- i2c_opt.width = atoi(optarg);
+ i2c_opt.width = optarg;
break;
case 'c':
i2c_opt.count = atoi(optarg);
@@ -686,6 +664,15 @@ main(int argc, char** argv)
i2c_opt.mode = I2C_MODE_NONE;
}
+ if (i2c_opt.addr_set) {
+ err_msg = encode_offset(i2c_opt.width, i2c_opt.off,
+ i2c_opt.off_buf, &i2c_opt.off_len);
+ if (err_msg != NULL) {
+ fprintf(stderr, "%s", err_msg);
+ exit(EX_USAGE);
+ }
+ }
+
/* Basic sanity check of command line arguments */
if (i2c_opt.scan) {
if (i2c_opt.addr_set)
@@ -695,16 +682,11 @@ main(int argc, char** argv)
usage();
} else if (error) {
usage();
- } else if ((i2c_opt.dir == 'r' || i2c_opt.dir == 'w')) {
- if ((i2c_opt.addr_set == 0) ||
- !(i2c_opt.width == 0 || i2c_opt.width == 8 ||
- i2c_opt.width == 16))
- usage();
}
if (i2c_opt.verbose)
fprintf(stderr, "dev: %s, addr: 0x%x, r/w: %c, "
- "offset: 0x%02x, width: %d, count: %d\n", dev,
+ "offset: 0x%02x, width: %s, count: %d\n", dev,
i2c_opt.addr >> 1, i2c_opt.dir, i2c_opt.off,
i2c_opt.width, i2c_opt.count);
More information about the dev-commits-src-main
mailing list