svn commit: r320460 - head/sys/dev/iicbus

Ian Lepore ian at FreeBSD.org
Thu Jun 29 00:29:17 UTC 2017


Author: ian
Date: Thu Jun 29 00:29:15 2017
New Revision: 320460
URL: https://svnweb.freebsd.org/changeset/base/320460

Log:
  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.)

Modified:
  head/sys/dev/iicbus/iiconf.c

Modified: head/sys/dev/iicbus/iiconf.c
==============================================================================
--- head/sys/dev/iicbus/iiconf.c	Wed Jun 28 21:45:13 2017	(r320459)
+++ head/sys/dev/iicbus/iiconf.c	Thu Jun 29 00:29:15 2017	(r320460)
@@ -419,7 +419,7 @@ iicbus_transfer_gen(device_t dev, struct iic_msg *msgs
 {
 	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
 	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
 				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
 			iicbus_stop(bus);
 		}
 	}
-	if (error != 0 && !nostop)
+	if (error != 0 && started)
 		iicbus_stop(bus);
 	return (error);
 }


More information about the svn-src-head mailing list