PERFORCE change 100710 for review

Warner Losh imp at FreeBSD.org
Thu Jul 6 10:17:15 UTC 2006


http://perforce.freebsd.org/chv.cgi?CH=100710

Change 100710 by imp at imp_lighthouse on 2006/07/06 10:16:21

	First, crude, cut at having iic_transfer, which will do
	multiple transfers in one shot it.  This can be used to
	optimize transfers, as well as exposed to iic bridges, if they
	so desire.

Affected files ...

.. //depot/projects/arm/src/sys/arm/at91/at91_twi.c#18 edit
.. //depot/projects/arm/src/sys/arm/conf/KB920X#34 edit
.. //depot/projects/arm/src/sys/dev/iicbus/iic.c#3 edit
.. //depot/projects/arm/src/sys/dev/iicbus/iic.h#2 edit
.. //depot/projects/arm/src/sys/dev/iicbus/iicbus.c#4 edit
.. //depot/projects/arm/src/sys/dev/iicbus/iicbus.h#3 edit
.. //depot/projects/arm/src/sys/dev/iicbus/iicbus_if.m#2 edit
.. //depot/projects/arm/src/sys/dev/iicbus/iiconf.c#2 edit
.. //depot/projects/arm/src/sys/dev/iicbus/iiconf.h#2 edit

Differences ...

==== //depot/projects/arm/src/sys/arm/at91/at91_twi.c#18 (text+ko) ====


==== //depot/projects/arm/src/sys/arm/conf/KB920X#34 (text+ko) ====

@@ -94,9 +94,9 @@
 
 device		mem			# Memory and kernel memory devices
 device		md
-# device	at91_twi		# TWI: Two Wire Interface
+device	at91_twi		# TWI: Two Wire Interface
 device		at91_spi		# SPI:
 device		at91_ssc
 # iic
-# device		iic
-# device		iicbus
+device		iic
+device		iicbus

==== //depot/projects/arm/src/sys/dev/iicbus/iic.c#3 (text+ko) ====

@@ -240,8 +240,11 @@
 	struct iic_softc *sc = IIC_SOFTC(minor(dev));
 	device_t parent = device_get_parent(iicdev);
 	struct iiccmd *s = (struct iiccmd *)data;
-	int error, count;
+	struct iic_rdwr_data *d = (struct iic_rdwr_data *)data;
+	struct iic_msg *m;
+	int error, count, i;
 	char *buf = NULL;
+	void **usrbufs = NULL;
 
 	if (!sc)
 		return (EINVAL);
@@ -297,6 +300,30 @@
 		error = copyout(buf, s->buf, s->count);
 		break;
 
+	case I2CRDWR:
+		buf = malloc(sizeof(*d->msgs) * d->nmsgs, M_TEMP, M_WAITOK);
+		usrbufs = malloc(sizeof(void *) * d->nmsgs, M_TEMP, M_ZERO | M_WAITOK);
+		error = copyin(d->msgs, buf, sizeof(*d->msgs) * d->nmsgs);
+		if (error)
+			break;
+		/* Allocate kernel buffers for userland data, copyin write data */
+		for (i = 0; i < d->nmsgs; i++) {
+			m = &((struct iic_msg *)buf)[i];
+			usrbufs[i] = m->buf;
+			m->buf = malloc(m->len, M_TEMP, M_WAITOK);
+			if (!(m->flags & IIC_M_RD))
+				copyin(usrbufs[i], m->buf, m->len);
+		}
+		error = iicbus_transfer(parent, (struct iic_msg *)buf, d->nmsgs);
+		/* Copyout all read segments, free up kernel buffers */
+		for (i = 0; i < d->nmsgs; i++) {
+			m = &((struct iic_msg *)buf)[i];
+			if (!(m->flags & IIC_M_RD))
+				copyout(m->buf, usrbufs[i], m->len);
+			free(m->buf, M_TEMP);
+		}
+		free(usrbufs, M_TEMP);
+		break;
 	default:
 		error = ENOTTY;
 	}

==== //depot/projects/arm/src/sys/dev/iicbus/iic.h#2 (text+ko) ====

@@ -31,6 +31,16 @@
 
 #include <sys/ioccom.h>
 
+/* Designed to be compatible with linux's struct i2c_msg */
+struct iic_msg
+{
+	uint16_t	slave;
+	uint16_t	flags;
+#define IIC_M_RD	0x0001	/* read vs write */
+	uint16_t	len;	/* msg legnth */
+	uint8_t *	buf;
+};
+
 struct iiccmd {
 	u_char slave;
 	int count;
@@ -38,10 +48,16 @@
 	char *buf;
 };
 
+struct iic_rdwr_data {
+	struct iic_msg *msgs;
+	uint32_t nmsgs;
+};
+
 #define I2CSTART	_IOW('i', 1, struct iiccmd)	/* start condition */
 #define I2CSTOP		_IO('i', 2)			/* stop condition */
 #define I2CRSTCARD	_IOW('i', 3, struct iiccmd)	/* reset the card */
 #define I2CWRITE	_IOW('i', 4, struct iiccmd)	/* send data */
 #define I2CREAD		_IOW('i', 5, struct iiccmd)	/* receive data */
+#define I2CRDWR		_IOW('i', 6, struct iic_rdwr_data)	/* General read/write interface */
 
 #endif

==== //depot/projects/arm/src/sys/dev/iicbus/iicbus.c#4 (text+ko) ====

@@ -45,7 +45,7 @@
 
 #define DEVTOIICBUS(dev) ((struct iicbus_device*)device_get_ivars(dev))
 
-static devclass_t iicbus_devclass;
+devclass_t iicbus_devclass;
 
 /* See comments below for why auto-scanning is a bad idea. */
 #define SCAN_IICBUS 0
@@ -72,7 +72,7 @@
         { 0, 0 }
 };
 
-static driver_t iicbus_driver = {
+driver_t iicbus_driver = {
         "iicbus",
         iicbus_methods,
         sizeof(struct iicbus_softc),
@@ -188,7 +188,6 @@
 	return (IIC_ENOTSUPP);
 }
 
-DRIVER_MODULE(iicbus, at91_twi, iicbus_driver, iicbus_devclass, 0, 0);
 DRIVER_MODULE(iicbus, envctrl, iicbus_driver, iicbus_devclass, 0, 0);
 DRIVER_MODULE(iicbus, iicbb, iicbus_driver, iicbus_devclass, 0, 0);
 MODULE_VERSION(iicbus, IICBUS_MODVER);

==== //depot/projects/arm/src/sys/dev/iicbus/iicbus.h#3 (text+ko) ====

@@ -38,4 +38,7 @@
 
 extern int iicbus_generic_intr(device_t dev, int event, char *buf);
 
+extern driver_t iicbus_driver;
+extern devclass_t iicbus_devclass;
+
 #endif

==== //depot/projects/arm/src/sys/dev/iicbus/iicbus_if.m#2 (text+ko) ====

@@ -27,6 +27,7 @@
 #
 
 #include <sys/bus.h>
+#include <dev/iicbus/iic.h>
 
 INTERFACE iicbus;
 
@@ -105,3 +106,12 @@
 	u_char addr;
 	u_char *oldaddr;
 };
+
+#
+# Generalized Read/Write interface
+#
+METHOD int transfer {
+	device_t dev;
+	struct iic_msg *msgs;
+	uint32_t nmsgs;
+};

==== //depot/projects/arm/src/sys/dev/iicbus/iiconf.c#2 (text+ko) ====

@@ -331,3 +331,45 @@
 
 	return (error);
 }
+
+/*
+ * iicbus_trasnfer()
+ *
+ * Do an aribtrary number of transfers on the iicbus.  We pass these
+ * raw requests to the bridge driver.  If the bridge driver supports
+ * them directly, then it manages all the details.  If not, it can use
+ * the helper function iicbus_transfer_gen() which will do the
+ * transfers at a low level.
+ *
+ * Pointers passed in as part of iic_msg must be kernel pointers.
+ * Callers that have user addresses to manage must do so on their own.
+ */
+int
+iicbus_transfer(device_t bus, struct iic_msg *msgs, uint32_t nmsgs)
+{
+	return (IICBUS_TRANSFER(device_get_parent(bus), msgs, nmsgs));
+}
+
+/*
+ * Generic version of iicbus_transfer that calls the appropriate
+ * routines to accomplish this.  See note above about acceptable
+ * buffer addresses.
+ */
+int
+iicbus_transfer_gen(device_t bus, struct iic_msg *msgs, uint32_t nmsgs)
+{
+	int i, error, max, lenread, lenwrote;
+
+	for (i = 0, max = 0; i < nmsgs; i++)
+		if (max < msgs[i].len)
+			max = msgs[i].len;
+	for (i = 0, error = 0; i < nmsgs && error == 0; i++) {
+		if (msgs[i].flags & IIC_M_RD)
+			error = iicbus_block_read(bus, msgs[i].slave,
+			    msgs[i].buf, msgs[i].len, &lenread);
+		else
+			error = iicbus_block_write(bus, msgs[i].slave,
+			    msgs[i].buf, msgs[i].len, &lenwrote);
+	}
+	return (error);
+}

==== //depot/projects/arm/src/sys/dev/iicbus/iiconf.h#2 (text+ko) ====

@@ -29,6 +29,8 @@
 #define __IICONF_H
 
 #include <sys/queue.h>
+#include <dev/iicbus/iic.h>
+
 
 #define IICPRI (PZERO+8)		/* XXX sleep/wakeup queue priority */
 
@@ -127,6 +129,10 @@
 
 extern u_char iicbus_get_addr(device_t);
 
+/* vectors of iic operations to pass to bridge */
+int iicbus_transfer(device_t bus, struct iic_msg *msgs, uint32_t nmsgs);
+int iicbus_transfer_gen(device_t bus, struct iic_msg *msgs, uint32_t nmsgs);
+
 #define IICBUS_MODVER	1
 #define IICBUS_MINVER	1
 #define IICBUS_MAXVER	1


More information about the p4-projects mailing list