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-all mailing list