If an i2c transfer ends due to error, issue a stop on the bus even if the

nostop option is set, if a start was issued.

The nostop option doesn't mean "never issue a stop" it means "only issue
a stop after the last in a series of transfers".  If the transfer ends
due to error, then that was the last transfer in the series, and a stop
is required.

Before this change, any error during a transfer when nostop is set would
effectively hang the bus, because sc->started would never get cleared,
and that caused all future calls to iicbus_start() to return an error
because it looked like the bus was already active.  (Unrelated errors in
handling the nostop option, to be addressed separately, could lead to
this bus hang condition even on busses that don't set the nostop option.)
This commit is contained in:
Ian Lepore 2017-06-29 00:29:15 +00:00
parent ad6eb97601
commit f03b277259

View File

@ -419,7 +419,7 @@ iicbus_transfer_gen(device_t dev, struct iic_msg *msgs, uint32_t nmsgs)
{
int i, error, lenread, lenwrote, nkid, rpstart, addr;
device_t *children, bus;
bool nostop;
bool nostop, started;
if ((error = device_get_children(dev, &children, &nkid)) != 0)
return (IIC_ERESOURCE);
@ -431,6 +431,7 @@ iicbus_transfer_gen(device_t dev, struct iic_msg *msgs, uint32_t nmsgs)
rpstart = 0;
free(children, M_TEMP);
nostop = iicbus_get_nostop(dev);
started = false;
for (i = 0, error = 0; i < nmsgs && error == 0; i++) {
addr = msgs[i].slave;
if (msgs[i].flags & IIC_M_RD)
@ -443,9 +444,10 @@ iicbus_transfer_gen(device_t dev, struct iic_msg *msgs, uint32_t nmsgs)
error = iicbus_repeated_start(bus, addr, 0);
else
error = iicbus_start(bus, addr, 0);
if (error != 0)
break;
started = true;
}
if (error != 0)
break;
if (msgs[i].flags & IIC_M_RD)
error = iicbus_read(bus, msgs[i].buf, msgs[i].len,
@ -464,7 +466,7 @@ iicbus_transfer_gen(device_t dev, struct iic_msg *msgs, uint32_t nmsgs)
iicbus_stop(bus);
}
}
if (error != 0 && !nostop)
if (error != 0 && started)
iicbus_stop(bus);
return (error);
}