Skip to content

Commit

Permalink
twsi: clearing of TWSI_CONTROL_ACK is moved to the state machine
Browse files Browse the repository at this point in the history
Clearing of TWSI_CONTROL_ACK is moved from twsi_transfer to the state
machine in twsi_intr. Specifically, the bit is cleared in the
TWSI_STATUS_ADDR_R_ACK state when we want to read just one byte. We need to
do that because if we send ACK after a received byte a device can send us
another byte and the code may write beyond the read buffer. The old code
did not work in a scenario where a single byte was read from an EEPROM
device with two byte addressing.
For example:
    i2c -m tr -a 0x50 -d r -w 16 -o 0 -c 1 -v
The reason is that the first message (a write) has two bytes, so
TWSI_CONTROL_ACK was never cleared at all.
  • Loading branch information
avg-I committed Sep 23, 2021
1 parent 239e9b5 commit 1c6777d
Showing 1 changed file with 2 additions and 2 deletions.
4 changes: 2 additions & 2 deletions sys/dev/iicbus/twsi/twsi.c
Original file line number Diff line number Diff line change
Expand Up @@ -511,8 +511,6 @@ twsi_transfer(device_t dev, struct iic_msg *msgs, uint32_t nmsgs)
/* Send start and re-enable interrupts */
sc->control_val = TWSI_CONTROL_TWSIEN |
TWSI_CONTROL_INTEN | TWSI_CONTROL_ACK;
if (sc->msgs[0].len == 1)
sc->control_val &= ~TWSI_CONTROL_ACK;
TWSI_WRITE(sc, sc->reg_control, sc->control_val | TWSI_CONTROL_START);
for (i = 0; i < 100 && sc->error == 0 && sc->transfer != 0; i++) {
pause_sbt("twsi", SBT_1MS * 30, SBT_1MS, 0);
Expand Down Expand Up @@ -585,6 +583,8 @@ twsi_intr(void *arg)
debugf(sc->dev, "Ack received after transmitting the address (read)\n");
sc->recv_bytes = 0;

if (sc->msgs[sc->msg_idx].len == 1)
sc->control_val &= ~TWSI_CONTROL_ACK;
TWSI_WRITE(sc, sc->reg_control, sc->control_val);
break;

Expand Down

0 comments on commit 1c6777d

Please sign in to comment.