i2c(8): clean up and clarify read operation
The code went to a lot of trouble to issue either a start+stop condition or a repeated start condition only to follow it with a stop condition and a read(2) call that issues a new start condition. So, fix the read in I2C_MODE_REPEATED_START mode by using I2CREAD ioctl within the running transaction. This obviously requires that the slave address has the read bit set which was not required before. Another problem was with width parameter of zero and I2C_MODE_REPEATED_START mode. In that case we issued a repeated start without any preceding start. While here, remove the redundant (unused) argument to I2CSTOP throughout the program. Also, clarify the meaning of -w option, especially "-w 0", in the manual page. Reviewed by: no one Differential Revision: https://reviews.freebsd.org/D12331
This commit is contained in:
parent
79caf56e97
commit
668f9cbec0
@ -83,6 +83,10 @@ using selected addresses 'a:b:c'. This option is available only when "-s" is
|
||||
used.
|
||||
.It Fl o Ar offset
|
||||
offset within the device for data transfer (hex).
|
||||
The default is zero.
|
||||
Use
|
||||
.Dq -w 0
|
||||
to disable writing of the offset to the slave.
|
||||
.It Fl r
|
||||
reset the controller.
|
||||
.It Fl s
|
||||
@ -91,6 +95,12 @@ scan the bus for devices.
|
||||
be verbose.
|
||||
.It Fl w Ar 0|8|16
|
||||
device addressing width (in bits).
|
||||
This is used to determine how to pass
|
||||
.Ar offset
|
||||
specified with
|
||||
.Fl o
|
||||
to the slave.
|
||||
Zero means that the offset is ignored and not passed to the slave at all.
|
||||
.El
|
||||
.Sh WARNINGS
|
||||
Great care must be taken when manipulating slave I2C devices with the
|
||||
|
@ -212,15 +212,14 @@ start_over:
|
||||
use_read_xfer = 1;
|
||||
goto start_over;
|
||||
}
|
||||
cmd.slave = i << 1;
|
||||
cmd.last = 1;
|
||||
ioctl(fd, I2CSTOP, &cmd);
|
||||
ioctl(fd, I2CSTOP);
|
||||
}
|
||||
if (error == 0) {
|
||||
++num_found;
|
||||
printf("%02x ", i);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* If we found nothing, maybe START is not supported and returns a
|
||||
* generic error code such as EIO or ENXIO, so try again using reads.
|
||||
@ -355,7 +354,7 @@ i2c_write(char *dev, struct options i2c_opt, char *i2c_buf)
|
||||
}
|
||||
}
|
||||
|
||||
error = ioctl(fd, I2CSTOP, &cmd);
|
||||
error = ioctl(fd, I2CSTOP);
|
||||
if (error == -1) {
|
||||
err_msg = "ioctl: error sending stop condition";
|
||||
goto err2;
|
||||
@ -439,8 +438,7 @@ i2c_write(char *dev, struct options i2c_opt, char *i2c_buf)
|
||||
}
|
||||
break;
|
||||
}
|
||||
cmd.slave = i2c_opt.addr;
|
||||
error = ioctl(fd, I2CSTOP, &cmd);
|
||||
error = ioctl(fd, I2CSTOP);
|
||||
if (error == -1) {
|
||||
err_msg = "ioctl: error sending stop condition";
|
||||
goto err2;
|
||||
@ -450,8 +448,7 @@ i2c_write(char *dev, struct options i2c_opt, char *i2c_buf)
|
||||
return (0);
|
||||
|
||||
err1:
|
||||
cmd.slave = i2c_opt.addr;
|
||||
error = ioctl(fd, I2CSTOP, &cmd);
|
||||
error = ioctl(fd, I2CSTOP);
|
||||
if (error == -1)
|
||||
fprintf(stderr, "error sending stop condition\n");
|
||||
err2:
|
||||
@ -466,7 +463,7 @@ static int
|
||||
i2c_read(char *dev, struct options i2c_opt, char *i2c_buf)
|
||||
{
|
||||
struct iiccmd cmd;
|
||||
int i, fd, error, bufsize;
|
||||
int fd, error, bufsize;
|
||||
char *err_msg, data = 0, *buf;
|
||||
|
||||
fd = open(dev, O_RDWR);
|
||||
@ -503,23 +500,22 @@ i2c_read(char *dev, struct options i2c_opt, char *i2c_buf)
|
||||
}
|
||||
|
||||
if (i2c_opt.mode == I2C_MODE_STOP_START) {
|
||||
cmd.slave = i2c_opt.addr;
|
||||
error = ioctl(fd, I2CSTOP, &cmd);
|
||||
error = ioctl(fd, I2CSTOP);
|
||||
if (error == -1) {
|
||||
err_msg = "error sending stop condition";
|
||||
goto err2;
|
||||
}
|
||||
}
|
||||
}
|
||||
cmd.slave = i2c_opt.addr;
|
||||
cmd.slave = i2c_opt.addr | 1;
|
||||
cmd.count = 1;
|
||||
cmd.last = 0;
|
||||
cmd.buf = &data;
|
||||
if (i2c_opt.mode == I2C_MODE_STOP_START) {
|
||||
if (i2c_opt.mode == I2C_MODE_STOP_START || i2c_opt.width == 0) {
|
||||
error = ioctl(fd, I2CSTART, &cmd);
|
||||
if (error == -1) {
|
||||
err_msg = "ioctl: error sending start condition";
|
||||
goto err1;
|
||||
goto err2;
|
||||
}
|
||||
} else if (i2c_opt.mode == I2C_MODE_REPEATED_START) {
|
||||
error = ioctl(fd, I2CRPTSTART, &cmd);
|
||||
@ -529,26 +525,27 @@ i2c_read(char *dev, struct options i2c_opt, char *i2c_buf)
|
||||
goto err1;
|
||||
}
|
||||
}
|
||||
error = ioctl(fd, I2CSTOP, &cmd);
|
||||
|
||||
cmd.count = i2c_opt.count;
|
||||
cmd.buf = i2c_buf;
|
||||
cmd.last = 1;
|
||||
error = ioctl(fd, I2CREAD, &cmd);
|
||||
if (error == -1) {
|
||||
err_msg = "error sending stop condition";
|
||||
goto err2;
|
||||
err_msg = "ioctl: error while reading";
|
||||
goto err1;
|
||||
}
|
||||
|
||||
for (i = 0; i < i2c_opt.count; i++) {
|
||||
error = read(fd, &i2c_buf[i], 1);
|
||||
if (error == -1) {
|
||||
err_msg = "ioctl: error while reading";
|
||||
goto err1;
|
||||
}
|
||||
error = ioctl(fd, I2CSTOP);
|
||||
if (error == -1) {
|
||||
err_msg = "error sending stop condtion\n";
|
||||
goto err2;
|
||||
}
|
||||
|
||||
close(fd);
|
||||
return (0);
|
||||
|
||||
err1:
|
||||
cmd.slave = i2c_opt.addr;
|
||||
error = ioctl(fd, I2CSTOP, &cmd);
|
||||
error = ioctl(fd, I2CSTOP);
|
||||
if (error == -1)
|
||||
fprintf(stderr, "error sending stop condition\n");
|
||||
err2:
|
||||
|
Loading…
x
Reference in New Issue
Block a user