Date: Thu, 6 Jul 2006 10:17:14 GMT From: Warner Losh <imp@FreeBSD.org> To: Perforce Change Reviews <perforce@freebsd.org> Subject: PERFORCE change 100710 for review Message-ID: <200607061017.k66AHEc4061481@repoman.freebsd.org>
next in thread | raw e-mail | index | archive | help
http://perforce.freebsd.org/chv.cgi?CH=100710 Change 100710 by imp@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
Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?200607061017.k66AHEc4061481>