<div dir="auto"><div><br><br><div class="gmail_quote"><div dir="ltr" class="gmail_attr">On Mon, Jun 10, 2019, 6:06 PM Christian Mauderer <<a href="mailto:list@c-mauderer.de" target="_blank" rel="noreferrer">list@c-mauderer.de</a>> wrote:<br></div><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">Hello Vijay,<br>
<br>
the patch set works fine on the Beagle (except for the i2c tool - but as<br>
discussed that will work after the next libbsd update). The patches look<br>
OK for me.<br>
<br>
Best regards<br>
<br>
Christian<br></blockquote></div></div><div dir="auto">Hi!</div><div dir="auto">Thanks for reviewing the patches. </div><div dir="auto">Currently the i2c tool can't do the read/write operation, but I checked that `i2c -s` function can scan the bus.</div><div dir="auto"><br></div><div dir="auto">Thanks,</div><div dir="auto">Vijay</div><div dir="auto"><div class="gmail_quote"><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex"><br>
On 08/06/2019 14:49, Vijay Kumar Banerjee wrote:<br>
> ---<br>
>  freebsd/sys/dev/iicbus/iic.c        | 506 ++++++++++++++++++++++++++<br>
>  freebsd/sys/dev/iicbus/iic.h        |  72 ++++<br>
>  freebsd/sys/dev/iicbus/iicbus.c     | 378 ++++++++++++++++++++<br>
>  freebsd/sys/dev/iicbus/iicbus.h     |  83 +++++<br>
>  freebsd/sys/dev/iicbus/iiconf.c     | 527 ++++++++++++++++++++++++++++<br>
>  freebsd/sys/dev/iicbus/iiconf.h     | 162 +++++++++<br>
>  freebsd/sys/dev/iicbus/ofw_iicbus.c | 242 +++++++++++++<br>
>  7 files changed, 1970 insertions(+)<br>
>  create mode 100644 freebsd/sys/dev/iicbus/iic.c<br>
>  create mode 100644 freebsd/sys/dev/iicbus/iic.h<br>
>  create mode 100644 freebsd/sys/dev/iicbus/iicbus.c<br>
>  create mode 100644 freebsd/sys/dev/iicbus/iicbus.h<br>
>  create mode 100644 freebsd/sys/dev/iicbus/iiconf.c<br>
>  create mode 100644 freebsd/sys/dev/iicbus/iiconf.h<br>
>  create mode 100644 freebsd/sys/dev/iicbus/ofw_iicbus.c<br>
> <br>
> diff --git a/freebsd/sys/dev/iicbus/iic.c b/freebsd/sys/dev/iicbus/iic.c<br>
> new file mode 100644<br>
> index 00000000..dc9c06f9<br>
> --- /dev/null<br>
> +++ b/freebsd/sys/dev/iicbus/iic.c<br>
> @@ -0,0 +1,506 @@<br>
> +#include <machine/rtems-bsd-kernel-space.h><br>
> +<br>
> +/*-<br>
> + * SPDX-License-Identifier: BSD-2-Clause-FreeBSD<br>
> + *<br>
> + * Copyright (c) 1998, 2001 Nicolas Souchu<br>
> + * All rights reserved.<br>
> + *<br>
> + * Redistribution and use in source and binary forms, with or without<br>
> + * modification, are permitted provided that the following conditions<br>
> + * are met:<br>
> + * 1. Redistributions of source code must retain the above copyright<br>
> + *    notice, this list of conditions and the following disclaimer.<br>
> + * 2. Redistributions in binary form must reproduce the above copyright<br>
> + *    notice, this list of conditions and the following disclaimer in the<br>
> + *    documentation and/or other materials provided with the distribution.<br>
> + *<br>
> + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND<br>
> + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE<br>
> + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE<br>
> + * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE<br>
> + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL<br>
> + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS<br>
> + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)<br>
> + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT<br>
> + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY<br>
> + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF<br>
> + * SUCH DAMAGE.<br>
> + *<br>
> + * $FreeBSD$<br>
> + *<br>
> + */<br>
> +#include <sys/param.h><br>
> +#include <sys/bus.h><br>
> +#include <sys/conf.h><br>
> +#include <sys/fcntl.h><br>
> +#include <sys/lock.h><br>
> +#include <sys/kernel.h><br>
> +#include <sys/malloc.h><br>
> +#include <sys/module.h><br>
> +#include <sys/sx.h><br>
> +#include <sys/systm.h><br>
> +#include <sys/uio.h><br>
> +#include <sys/errno.h><br>
> +<br>
> +#include <dev/iicbus/iiconf.h><br>
> +#include <dev/iicbus/iicbus.h><br>
> +#include <dev/iicbus/iic.h><br>
> +<br>
> +#include <rtems/bsd/local/iicbus_if.h><br>
> +<br>
> +struct iic_softc {<br>
> +     device_t sc_dev;<br>
> +     struct cdev *sc_devnode;<br>
> +};<br>
> +<br>
> +struct iic_cdevpriv {<br>
> +     struct sx lock;<br>
> +     struct iic_softc *sc;<br>
> +     bool started;<br>
> +     uint8_t addr;<br>
> +};<br>
> +<br>
> +<br>
> +#define      IIC_LOCK(cdp)                   sx_xlock(&(cdp)->lock)<br>
> +#define      IIC_UNLOCK(cdp)                 sx_xunlock(&(cdp)->lock)<br>
> +<br>
> +static MALLOC_DEFINE(M_IIC, "iic", "I2C device data");<br>
> +<br>
> +static int iic_probe(device_t);<br>
> +static int iic_attach(device_t);<br>
> +static int iic_detach(device_t);<br>
> +static void iic_identify(driver_t *driver, device_t parent);<br>
> +static void iicdtor(void *data);<br>
> +static int iicuio_move(struct iic_cdevpriv *priv, struct uio *uio, int last);<br>
> +static int iicuio(struct cdev *dev, struct uio *uio, int ioflag);<br>
> +static int iicrdwr(struct iic_cdevpriv *priv, struct iic_rdwr_data *d, int flags);<br>
> +<br>
> +static devclass_t iic_devclass;<br>
> +<br>
> +static device_method_t iic_methods[] = {<br>
> +     /* device interface */<br>
> +     DEVMETHOD(device_identify,      iic_identify),<br>
> +     DEVMETHOD(device_probe,         iic_probe),<br>
> +     DEVMETHOD(device_attach,        iic_attach),<br>
> +     DEVMETHOD(device_detach,        iic_detach),<br>
> +<br>
> +     /* iicbus interface */<br>
> +     DEVMETHOD(iicbus_intr,          iicbus_generic_intr),<br>
> +<br>
> +     { 0, 0 }<br>
> +};<br>
> +<br>
> +static driver_t iic_driver = {<br>
> +     "iic",<br>
> +     iic_methods,<br>
> +     sizeof(struct iic_softc),<br>
> +};<br>
> +<br>
> +static       d_open_t        iicopen;<br>
> +static       d_ioctl_t       iicioctl;<br>
> +<br>
> +static struct cdevsw iic_cdevsw = {<br>
> +     .d_version =    D_VERSION,<br>
> +     .d_open =       iicopen,<br>
> +     .d_read =       iicuio,<br>
> +     .d_write =      iicuio,<br>
> +     .d_ioctl =      iicioctl,<br>
> +     .d_name =       "iic",<br>
> +};<br>
> +<br>
> +static void<br>
> +iic_identify(driver_t *driver, device_t parent)<br>
> +{<br>
> +<br>
> +     if (device_find_child(parent, "iic", -1) == NULL)<br>
> +             BUS_ADD_CHILD(parent, 0, "iic", -1);<br>
> +}<br>
> +<br>
> +static int<br>
> +iic_probe(device_t dev)<br>
> +{<br>
> +     if (iicbus_get_addr(dev) > 0)<br>
> +             return (ENXIO);<br>
> +<br>
> +     device_set_desc(dev, "I2C generic I/O");<br>
> +<br>
> +     return (0);<br>
> +}<br>
> +     <br>
> +static int<br>
> +iic_attach(device_t dev)<br>
> +{<br>
> +     struct iic_softc *sc;<br>
> +<br>
> +     sc = device_get_softc(dev);<br>
> +     sc->sc_dev = dev;<br>
> +     sc->sc_devnode = make_dev(&iic_cdevsw, device_get_unit(dev),<br>
> +                     UID_ROOT, GID_WHEEL,<br>
> +                     0600, "iic%d", device_get_unit(dev));<br>
> +     if (sc->sc_devnode == NULL) {<br>
> +             device_printf(dev, "failed to create character device\n");<br>
> +             return (ENXIO);<br>
> +     }<br>
> +     sc->sc_devnode->si_drv1 = sc;<br>
> +<br>
> +     return (0);<br>
> +}<br>
> +<br>
> +static int<br>
> +iic_detach(device_t dev)<br>
> +{<br>
> +     struct iic_softc *sc;<br>
> +<br>
> +     sc = device_get_softc(dev);<br>
> +<br>
> +     if (sc->sc_devnode)<br>
> +             destroy_dev(sc->sc_devnode);<br>
> +<br>
> +     return (0);<br>
> +}<br>
> +<br>
> +static int<br>
> +iicopen(struct cdev *dev, int flags, int fmt, struct thread *td)<br>
> +{<br>
> +     struct iic_cdevpriv *priv;<br>
> +     int error;<br>
> +<br>
> +     priv = malloc(sizeof(*priv), M_IIC, M_WAITOK | M_ZERO);<br>
> +<br>
> +     sx_init(&priv->lock, "iic");<br>
> +     priv->sc = dev->si_drv1;<br>
> +<br>
> +     error = devfs_set_cdevpriv(priv, iicdtor); <br>
> +     if (error != 0)<br>
> +             free(priv, M_IIC);<br>
> +<br>
> +     return (error);<br>
> +}<br>
> +<br>
> +static void<br>
> +iicdtor(void *data)<br>
> +{<br>
> +     device_t iicdev, parent;<br>
> +     struct iic_cdevpriv *priv;<br>
> +<br>
> +     priv = data;<br>
> +     KASSERT(priv != NULL, ("iic cdevpriv should not be NULL!"));<br>
> +<br>
> +     iicdev = priv->sc->sc_dev;<br>
> +     parent = device_get_parent(iicdev);<br>
> +<br>
> +     if (priv->started) {<br>
> +             iicbus_stop(parent);<br>
> +             iicbus_reset(parent, IIC_UNKNOWN, 0, NULL);<br>
> +             iicbus_release_bus(parent, iicdev);<br>
> +     }<br>
> +<br>
> +     sx_destroy(&priv->lock);<br>
> +     free(priv, M_IIC);<br>
> +}<br>
> +<br>
> +static int<br>
> +iicuio_move(struct iic_cdevpriv *priv, struct uio *uio, int last)<br>
> +{<br>
> +     device_t parent;<br>
> +     int error, num_bytes, transferred_bytes, written_bytes;<br>
> +     char buffer[128];<br>
> +<br>
> +     parent = device_get_parent(priv->sc->sc_dev);<br>
> +     error = 0;<br>
> +<br>
> +     /*<br>
> +      * We can only transfer up to sizeof(buffer) bytes in 1 shot, so loop until<br>
> +      * everything has been transferred.<br>
> +     */<br>
> +     while ((error == 0) && (uio->uio_resid > 0)) {<br>
> +<br>
> +             num_bytes = MIN(uio->uio_resid, sizeof(buffer));<br>
> +             transferred_bytes = 0;<br>
> +<br>
> +             if (uio->uio_rw == UIO_WRITE) {<br>
> +                     error = uiomove(buffer, num_bytes, uio);<br>
> +<br>
> +                     while ((error == 0) && (transferred_bytes < num_bytes)) {<br>
> +                             written_bytes = 0;<br>
> +                             error = iicbus_write(parent, &buffer[transferred_bytes],<br>
> +                                 num_bytes - transferred_bytes, &written_bytes, 0);<br>
> +                             transferred_bytes += written_bytes;<br>
> +                     }<br>
> +                             <br>
> +             } else if (uio->uio_rw == UIO_READ) {<br>
> +                     error = iicbus_read(parent, buffer,<br>
> +                         num_bytes, &transferred_bytes,<br>
> +                         ((uio->uio_resid <= sizeof(buffer)) ? last : 0), 0);<br>
> +                     if (error == 0)<br>
> +                             error = uiomove(buffer, transferred_bytes, uio);<br>
> +             }<br>
> +     }<br>
> +<br>
> +     return (error);<br>
> +}<br>
> +<br>
> +static int<br>
> +iicuio(struct cdev *dev, struct uio *uio, int ioflag)<br>
> +{<br>
> +     device_t parent;<br>
> +     struct iic_cdevpriv *priv;<br>
> +     int error;<br>
> +     uint8_t addr;<br>
> +<br>
> +     priv = NULL;<br>
> +     error = devfs_get_cdevpriv((void**)&priv);<br>
> +<br>
> +     if (error != 0)<br>
> +             return (error);<br>
> +     KASSERT(priv != NULL, ("iic cdevpriv should not be NULL!"));<br>
> +<br>
> +     IIC_LOCK(priv);<br>
> +     if (priv->started || (priv->addr == 0)) {<br>
> +             IIC_UNLOCK(priv);<br>
> +             return (ENXIO);<br>
> +     }<br>
> +     parent = device_get_parent(priv->sc->sc_dev);<br>
> +<br>
> +     error = iicbus_request_bus(parent, priv->sc->sc_dev,<br>
> +         (ioflag & O_NONBLOCK) ? IIC_DONTWAIT : (IIC_WAIT | IIC_INTR));<br>
> +     if (error != 0) {<br>
> +             IIC_UNLOCK(priv);<br>
> +             return (error);<br>
> +     }<br>
> +<br>
> +     if (uio->uio_rw == UIO_READ)<br>
> +             addr = priv->addr | LSB;<br>
> +     else<br>
> +             addr = priv->addr & ~LSB;<br>
> +<br>
> +     error = iicbus_start(parent, addr, 0);<br>
> +     if (error != 0)<br>
> +     {<br>
> +             iicbus_release_bus(parent, priv->sc->sc_dev);<br>
> +             IIC_UNLOCK(priv);<br>
> +             return (error);<br>
> +     }<br>
> +<br>
> +     error = iicuio_move(priv, uio, IIC_LAST_READ);<br>
> +<br>
> +     iicbus_stop(parent);<br>
> +     iicbus_release_bus(parent, priv->sc->sc_dev);<br>
> +     IIC_UNLOCK(priv);<br>
> +     return (error);<br>
> +}<br>
> +<br>
> +static int<br>
> +iicrdwr(struct iic_cdevpriv *priv, struct iic_rdwr_data *d, int flags)<br>
> +{<br>
> +     struct iic_msg *buf, *m;<br>
> +     void **usrbufs;<br>
> +     device_t iicdev, parent;<br>
> +     int error;<br>
> +     uint32_t i;<br>
> +<br>
> +     iicdev = priv->sc->sc_dev;<br>
> +     parent = device_get_parent(iicdev);<br>
> +     error = 0;<br>
> +<br>
> +     if (d->nmsgs > IIC_RDRW_MAX_MSGS)<br>
> +             return (EINVAL);<br>
> +<br>
> +     buf = malloc(sizeof(*d->msgs) * d->nmsgs, M_IIC, M_WAITOK);<br>
> +<br>
> +     error = copyin(d->msgs, buf, sizeof(*d->msgs) * d->nmsgs);<br>
> +     if (error != 0) {<br>
> +             free(buf, M_IIC);<br>
> +             return (error);<br>
> +     }<br>
> +<br>
> +     /* Alloc kernel buffers for userland data, copyin write data */<br>
> +     usrbufs = malloc(sizeof(void *) * d->nmsgs, M_IIC, M_WAITOK | M_ZERO);<br>
> +<br>
> +     for (i = 0; i < d->nmsgs; i++) {<br>
> +             m = &(buf[i]);<br>
> +             usrbufs[i] = m->buf;<br>
> +<br>
> +             /*<br>
> +              * At least init the buffer to NULL so we can safely free() it later.<br>
> +              * If the copyin() to buf failed, don't try to malloc bogus m->len.<br>
> +              */<br>
> +             m->buf = NULL;<br>
> +             if (error != 0)<br>
> +                     continue;<br>
> +<br>
> +             /* m->len is uint16_t, so allocation size is capped at 64K. */<br>
> +             m->buf = malloc(m->len, M_IIC, M_WAITOK);<br>
> +             if (!(m->flags & IIC_M_RD))<br>
> +                     error = copyin(usrbufs[i], m->buf, m->len);<br>
> +     }<br>
> +<br>
> +     if (error == 0)<br>
> +             error = iicbus_request_bus(parent, iicdev,<br>
> +                 (flags & O_NONBLOCK) ? IIC_DONTWAIT : (IIC_WAIT | IIC_INTR));<br>
> +<br>
> +     if (error == 0) {<br>
> +             error = iicbus_transfer(iicdev, buf, d->nmsgs);<br>
> +             iicbus_release_bus(parent, iicdev);<br>
> +     }<br>
> +<br>
> +     /* Copyout all read segments, free up kernel buffers */<br>
> +     for (i = 0; i < d->nmsgs; i++) {<br>
> +             m = &(buf[i]);<br>
> +             if ((error == 0) && (m->flags & IIC_M_RD))<br>
> +                     error = copyout(m->buf, usrbufs[i], m->len);<br>
> +             free(m->buf, M_IIC);<br>
> +     }<br>
> +<br>
> +     free(usrbufs, M_IIC);<br>
> +     free(buf, M_IIC);<br>
> +     return (error);<br>
> +}<br>
> +<br>
> +static int<br>
> +iicioctl(struct cdev *dev, u_long cmd, caddr_t data, int flags, struct thread *td)<br>
> +{<br>
> +     device_t parent, iicdev;<br>
> +     struct iiccmd *s;<br>
> +     struct uio ubuf;<br>
> +     struct iovec uvec;<br>
> +     struct iic_cdevpriv *priv;<br>
> +     int error;<br>
> +<br>
> +     s = (struct iiccmd *)data;<br>
> +     error = devfs_get_cdevpriv((void**)&priv);<br>
> +     if (error != 0)<br>
> +             return (error);<br>
> +<br>
> +     KASSERT(priv != NULL, ("iic cdevpriv should not be NULL!"));<br>
> +<br>
> +     iicdev = priv->sc->sc_dev;<br>
> +     parent = device_get_parent(iicdev);<br>
> +     IIC_LOCK(priv);<br>
> +<br>
> +<br>
> +     switch (cmd) {<br>
> +     case I2CSTART:<br>
> +             if (priv->started) {<br>
> +                     error = EINVAL;<br>
> +                     break;<br>
> +             }<br>
> +             error = iicbus_request_bus(parent, iicdev,<br>
> +                 (flags & O_NONBLOCK) ? IIC_DONTWAIT : (IIC_WAIT | IIC_INTR));<br>
> +<br>
> +             if (error == 0)<br>
> +                     error = iicbus_start(parent, s->slave, 0);<br>
> +<br>
> +             if (error == 0) {<br>
> +                     priv->addr = s->slave;<br>
> +                     priv->started = true;<br>
> +             } else<br>
> +                     iicbus_release_bus(parent, iicdev);<br>
> +<br>
> +             break;<br>
> +<br>
> +     case I2CSTOP:<br>
> +             if (priv->started) {<br>
> +                     error = iicbus_stop(parent);<br>
> +                     iicbus_release_bus(parent, iicdev);<br>
> +                     priv->started = false;<br>
> +             }<br>
> +<br>
> +             break;<br>
> +<br>
> +     case I2CRSTCARD:<br>
> +             /*<br>
> +              * Bus should be owned before we reset it.<br>
> +              * We allow the bus to be already owned as the result of an in-progress<br>
> +              * sequence; however, bus reset will always be followed by release<br>
> +              * (a new start is presumably needed for I/O anyway). */ <br>
> +             if (!priv->started)     <br>
> +                     error = iicbus_request_bus(parent, iicdev,<br>
> +                         (flags & O_NONBLOCK) ? IIC_DONTWAIT : (IIC_WAIT | IIC_INTR));<br>
> +<br>
> +             if (error == 0) {<br>
> +                     error = iicbus_reset(parent, IIC_UNKNOWN, 0, NULL);<br>
> +                     /*<br>
> +                      * Ignore IIC_ENOADDR as it only means we have a master-only<br>
> +                      * controller.<br>
> +                      */<br>
> +                     if (error == IIC_ENOADDR)<br>
> +                             error = 0;<br>
> +<br>
> +                     iicbus_release_bus(parent, iicdev);<br>
> +                     priv->started = false;<br>
> +             }<br>
> +             break;<br>
> +<br>
> +     case I2CWRITE:<br>
> +             if (!priv->started) {<br>
> +                     error = EINVAL;<br>
> +                     break;<br>
> +             }<br>
> +             uvec.iov_base = s->buf;<br>
> +             uvec.iov_len = s->count;<br>
> +             ubuf.uio_iov = &uvec;<br>
> +             ubuf.uio_iovcnt = 1;<br>
> +             ubuf.uio_segflg = UIO_USERSPACE;<br>
> +             ubuf.uio_td = td;<br>
> +             ubuf.uio_resid = s->count;<br>
> +             ubuf.uio_offset = 0;<br>
> +             ubuf.uio_rw = UIO_WRITE;<br>
> +             error = iicuio_move(priv, &ubuf, 0);<br>
> +             break;<br>
> +<br>
> +     case I2CREAD:<br>
> +             if (!priv->started) {<br>
> +                     error = EINVAL;<br>
> +                     break;<br>
> +             }<br>
> +             uvec.iov_base = s->buf;<br>
> +             uvec.iov_len = s->count;<br>
> +             ubuf.uio_iov = &uvec;<br>
> +             ubuf.uio_iovcnt = 1;<br>
> +             ubuf.uio_segflg = UIO_USERSPACE;<br>
> +             ubuf.uio_td = td;<br>
> +             ubuf.uio_resid = s->count;<br>
> +             ubuf.uio_offset = 0;<br>
> +             ubuf.uio_rw = UIO_READ;<br>
> +             error = iicuio_move(priv, &ubuf, s->last);<br>
> +             break;<br>
> +<br>
> +     case I2CRDWR:<br>
> +             /*<br>
> +              * The rdwr list should be a self-contained set of<br>
> +              * transactions.  Fail if another transaction is in progress.<br>
> +                 */<br>
> +             if (priv->started) {<br>
> +                     error = EINVAL;<br>
> +                     break;<br>
> +             }<br>
> +<br>
> +             error = iicrdwr(priv, (struct iic_rdwr_data *)data, flags);<br>
> +<br>
> +             break;<br>
> +<br>
> +     case I2CRPTSTART:<br>
> +             if (!priv->started) {<br>
> +                     error = EINVAL;<br>
> +                     break;<br>
> +             }<br>
> +             error = iicbus_repeated_start(parent, s->slave, 0);<br>
> +             break;<br>
> +<br>
> +     case I2CSADDR:<br>
> +             priv->addr = *((uint8_t*)data);<br>
> +             break;<br>
> +<br>
> +     default:<br>
> +             error = ENOTTY;<br>
> +     }<br>
> +<br>
> +     IIC_UNLOCK(priv);<br>
> +     return (error);<br>
> +}<br>
> +<br>
> +DRIVER_MODULE(iic, iicbus, iic_driver, iic_devclass, 0, 0);<br>
> +MODULE_DEPEND(iic, iicbus, IICBUS_MINVER, IICBUS_PREFVER, IICBUS_MAXVER);<br>
> +MODULE_VERSION(iic, 1);<br>
> diff --git a/freebsd/sys/dev/iicbus/iic.h b/freebsd/sys/dev/iicbus/iic.h<br>
> new file mode 100644<br>
> index 00000000..5ebf56a9<br>
> --- /dev/null<br>
> +++ b/freebsd/sys/dev/iicbus/iic.h<br>
> @@ -0,0 +1,72 @@<br>
> +/*-<br>
> + * SPDX-License-Identifier: BSD-2-Clause-FreeBSD<br>
> + *<br>
> + * Copyright (c) 1998 Nicolas Souchu<br>
> + * All rights reserved.<br>
> + *<br>
> + * Redistribution and use in source and binary forms, with or without<br>
> + * modification, are permitted provided that the following conditions<br>
> + * are met:<br>
> + * 1. Redistributions of source code must retain the above copyright<br>
> + *    notice, this list of conditions and the following disclaimer.<br>
> + * 2. Redistributions in binary form must reproduce the above copyright<br>
> + *    notice, this list of conditions and the following disclaimer in the<br>
> + *    documentation and/or other materials provided with the distribution.<br>
> + *<br>
> + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND<br>
> + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE<br>
> + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE<br>
> + * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE<br>
> + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL<br>
> + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS<br>
> + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)<br>
> + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT<br>
> + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY<br>
> + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF<br>
> + * SUCH DAMAGE.<br>
> + *<br>
> + * $FreeBSD$<br>
> + *<br>
> + */<br>
> +#ifndef __IIC_H<br>
> +#define __IIC_H<br>
> +<br>
> +#include <sys/ioccom.h><br>
> +<br>
> +/* Designed to be compatible with linux's struct i2c_msg */<br>
> +struct iic_msg<br>
> +{<br>
> +     uint16_t        slave;<br>
> +     uint16_t        flags;<br>
> +#define      IIC_M_WR        0       /* Fake flag for write */<br>
> +#define      IIC_M_RD        0x0001  /* read vs write */<br>
> +#define      IIC_M_NOSTOP    0x0002  /* do not send a I2C stop after message */<br>
> +#define      IIC_M_NOSTART   0x0004  /* do not send a I2C start before message */<br>
> +     uint16_t        len;    /* msg length */<br>
> +     uint8_t *       buf;<br>
> +};<br>
> +<br>
> +struct iiccmd {<br>
> +     u_char slave;<br>
> +     int count;<br>
> +     int last;<br>
> +     char *buf;<br>
> +};<br>
> +<br>
> +struct iic_rdwr_data {<br>
> +     struct iic_msg *msgs;<br>
> +     uint32_t nmsgs;<br>
> +};<br>
> +<br>
> +#define IIC_RDRW_MAX_MSGS    42<br>
> +<br>
> +#define I2CSTART     _IOW('i', 1, struct iiccmd)     /* start condition */<br>
> +#define I2CSTOP              _IO('i', 2)                     /* stop condition */<br>
> +#define I2CRSTCARD   _IOW('i', 3, struct iiccmd)     /* reset the card */<br>
> +#define I2CWRITE     _IOW('i', 4, struct iiccmd)     /* send data */<br>
> +#define I2CREAD              _IOW('i', 5, struct iiccmd)     /* receive data */<br>
> +#define I2CRDWR              _IOW('i', 6, struct iic_rdwr_data)      /* General read/write interface */<br>
> +#define I2CRPTSTART  _IOW('i', 7, struct iiccmd)     /* repeated start */<br>
> +#define I2CSADDR     _IOW('i', 8, uint8_t)           /* set slave address for future I/O */<br>
> +<br>
> +#endif<br>
> diff --git a/freebsd/sys/dev/iicbus/iicbus.c b/freebsd/sys/dev/iicbus/iicbus.c<br>
> new file mode 100644<br>
> index 00000000..d1e55483<br>
> --- /dev/null<br>
> +++ b/freebsd/sys/dev/iicbus/iicbus.c<br>
> @@ -0,0 +1,378 @@<br>
> +#include <machine/rtems-bsd-kernel-space.h><br>
> +<br>
> +/*-<br>
> + * SPDX-License-Identifier: BSD-2-Clause-FreeBSD<br>
> + *<br>
> + * Copyright (c) 1998, 2001 Nicolas Souchu<br>
> + * All rights reserved.<br>
> + *<br>
> + * Redistribution and use in source and binary forms, with or without<br>
> + * modification, are permitted provided that the following conditions<br>
> + * are met:<br>
> + * 1. Redistributions of source code must retain the above copyright<br>
> + *    notice, this list of conditions and the following disclaimer.<br>
> + * 2. Redistributions in binary form must reproduce the above copyright<br>
> + *    notice, this list of conditions and the following disclaimer in the<br>
> + *    documentation and/or other materials provided with the distribution.<br>
> + *<br>
> + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND<br>
> + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE<br>
> + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE<br>
> + * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE<br>
> + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL<br>
> + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS<br>
> + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)<br>
> + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT<br>
> + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY<br>
> + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF<br>
> + * SUCH DAMAGE.<br>
> + */<br>
> +<br>
> +#include <sys/cdefs.h><br>
> +__FBSDID("$FreeBSD$");<br>
> +<br>
> +/*<br>
> + * Autoconfiguration and support routines for the Philips serial I2C bus<br>
> + */<br>
> +<br>
> +#include <sys/param.h><br>
> +#include <sys/systm.h><br>
> +#include <sys/kernel.h><br>
> +#include <sys/lock.h><br>
> +#include <sys/malloc.h><br>
> +#include <sys/module.h><br>
> +#include <sys/mutex.h><br>
> +#include <sys/rman.h><br>
> +#include <sys/sysctl.h><br>
> +#include <sys/bus.h><br>
> +<br>
> +#include <dev/iicbus/iiconf.h><br>
> +#include <dev/iicbus/iicbus.h><br>
> +<br>
> +#include <rtems/bsd/local/iicbus_if.h><br>
> +<br>
> +/* See comments below for why auto-scanning is a bad idea. */<br>
> +#define SCAN_IICBUS 0<br>
> +<br>
> +static int<br>
> +iicbus_probe(device_t dev)<br>
> +{<br>
> +<br>
> +     device_set_desc(dev, "Philips I2C bus");<br>
> +<br>
> +     /* Allow other subclasses to override this driver. */<br>
> +     return (BUS_PROBE_GENERIC);<br>
> +}<br>
> +<br>
> +#if SCAN_IICBUS<br>
> +static int<br>
> +iic_probe_device(device_t dev, u_char addr)<br>
> +{<br>
> +     int count;<br>
> +     char byte;<br>
> +<br>
> +     if ((addr & 1) == 0) {<br>
> +             /* is device writable? */<br>
> +             if (!iicbus_start(dev, (u_char)addr, 0)) {<br>
> +                     iicbus_stop(dev);<br>
> +                     return (1);<br>
> +             }<br>
> +     } else {<br>
> +             /* is device readable? */<br>
> +             if (!iicbus_block_read(dev, (u_char)addr, &byte, 1, &count))<br>
> +                     return (1);<br>
> +     }<br>
> +<br>
> +     return (0);<br>
> +}<br>
> +#endif<br>
> +<br>
> +/*<br>
> + * We add all the devices which we know about.<br>
> + * The generic attach routine will attach them if they are alive.<br>
> + */<br>
> +static int<br>
> +iicbus_attach(device_t dev)<br>
> +{<br>
> +#if SCAN_IICBUS<br>
> +     unsigned char addr;<br>
> +#endif<br>
> +     struct iicbus_softc *sc = IICBUS_SOFTC(dev);<br>
> +     int strict;<br>
> +<br>
> +     sc->dev = dev;<br>
> +     mtx_init(&sc->lock, "iicbus", NULL, MTX_DEF);<br>
> +     iicbus_init_frequency(dev, 0);<br>
> +     iicbus_reset(dev, IIC_FASTEST, 0, NULL);<br>
> +     if (resource_int_value(device_get_name(dev),<br>
> +             device_get_unit(dev), "strict", &strict) == 0)<br>
> +             sc->strict = strict;<br>
> +     else<br>
> +             sc->strict = 1;<br>
> +<br>
> +     /* device probing is meaningless since the bus is supposed to be<br>
> +      * hot-plug. Moreover, some I2C chips do not appreciate random<br>
> +      * accesses like stop after start to fast, reads for less than<br>
> +      * x bytes...<br>
> +      */<br>
> +#if SCAN_IICBUS<br>
> +     printf("Probing for devices on iicbus%d:", device_get_unit(dev));<br>
> +<br>
> +     /* probe any devices */<br>
> +     for (addr = 16; addr < 240; addr++) {<br>
> +             if (iic_probe_device(dev, (u_char)addr)) {<br>
> +                     printf(" <%x>", addr);<br>
> +             }<br>
> +     }<br>
> +     printf("\n");<br>
> +#endif<br>
> +     bus_generic_probe(dev);<br>
> +     bus_enumerate_hinted_children(dev);<br>
> +     bus_generic_attach(dev);<br>
> +        return (0);<br>
> +}<br>
> +<br>
> +static int<br>
> +iicbus_detach(device_t dev)<br>
> +{<br>
> +     struct iicbus_softc *sc = IICBUS_SOFTC(dev);<br>
> +<br>
> +     iicbus_reset(dev, IIC_FASTEST, 0, NULL);<br>
> +     bus_generic_detach(dev);<br>
> +     device_delete_children(dev);<br>
> +     mtx_destroy(&sc->lock);<br>
> +     return (0);<br>
> +}<br>
> +<br>
> +static int<br>
> +iicbus_print_child(device_t dev, device_t child)<br>
> +{<br>
> +     struct iicbus_ivar *devi = IICBUS_IVAR(child);<br>
> +     int retval = 0;<br>
> +<br>
> +     retval += bus_print_child_header(dev, child);<br>
> +     if (devi->addr != 0)<br>
> +             retval += printf(" at addr %#x", devi->addr);<br>
> +     resource_list_print_type(&devi->rl, "irq", SYS_RES_IRQ, "%jd");<br>
> +     retval += bus_print_child_footer(dev, child);<br>
> +<br>
> +     return (retval);<br>
> +}<br>
> +<br>
> +static void<br>
> +iicbus_probe_nomatch(device_t bus, device_t child)<br>
> +{<br>
> +     struct iicbus_ivar *devi = IICBUS_IVAR(child);<br>
> +<br>
> +     device_printf(bus, "<unknown card> at addr %#x\n", devi->addr);<br>
> +}<br>
> +<br>
> +static int<br>
> +iicbus_child_location_str(device_t bus, device_t child, char *buf,<br>
> +    size_t buflen)<br>
> +{<br>
> +     struct iicbus_ivar *devi = IICBUS_IVAR(child);<br>
> +<br>
> +     snprintf(buf, buflen, "addr=%#x", devi->addr);<br>
> +     return (0);<br>
> +}<br>
> +<br>
> +static int<br>
> +iicbus_child_pnpinfo_str(device_t bus, device_t child, char *buf,<br>
> +    size_t buflen)<br>
> +{<br>
> +     *buf = '\0';<br>
> +     return (0);<br>
> +}<br>
> +<br>
> +static int<br>
> +iicbus_read_ivar(device_t bus, device_t child, int which, uintptr_t *result)<br>
> +{<br>
> +     struct iicbus_ivar *devi = IICBUS_IVAR(child);<br>
> +<br>
> +     switch (which) {<br>
> +     default:<br>
> +             return (EINVAL);<br>
> +     case IICBUS_IVAR_ADDR:<br>
> +             *result = devi->addr;<br>
> +             break;<br>
> +     case IICBUS_IVAR_NOSTOP:<br>
> +             *result = devi->nostop;<br>
> +             break;<br>
> +     }<br>
> +     return (0);<br>
> +}<br>
> +<br>
> +static int<br>
> +iicbus_write_ivar(device_t bus, device_t child, int which, uintptr_t value)<br>
> +{<br>
> +     struct iicbus_ivar *devi = IICBUS_IVAR(child);<br>
> +<br>
> +     switch (which) {<br>
> +     default:<br>
> +             return (EINVAL);<br>
> +     case IICBUS_IVAR_ADDR:<br>
> +             if (devi->addr != 0)<br>
> +                     return (EINVAL);<br>
> +             devi->addr = value;<br>
> +     case IICBUS_IVAR_NOSTOP:<br>
> +             devi->nostop = value;<br>
> +             break;<br>
> +     }<br>
> +     return (0);<br>
> +}<br>
> +<br>
> +static device_t<br>
> +iicbus_add_child(device_t dev, u_int order, const char *name, int unit)<br>
> +{<br>
> +     device_t child;<br>
> +     struct iicbus_ivar *devi;<br>
> +<br>
> +     child = device_add_child_ordered(dev, order, name, unit);<br>
> +     if (child == NULL)<br>
> +             return (child);<br>
> +     devi = malloc(sizeof(struct iicbus_ivar), M_DEVBUF, M_NOWAIT | M_ZERO);<br>
> +     if (devi == NULL) {<br>
> +             device_delete_child(dev, child);<br>
> +             return (0);<br>
> +     }<br>
> +     resource_list_init(&devi->rl);<br>
> +     device_set_ivars(child, devi);<br>
> +     return (child);<br>
> +}<br>
> +<br>
> +static void<br>
> +iicbus_hinted_child(device_t bus, const char *dname, int dunit)<br>
> +{<br>
> +     device_t child;<br>
> +     int irq;<br>
> +     struct iicbus_ivar *devi;<br>
> +<br>
> +     child = BUS_ADD_CHILD(bus, 0, dname, dunit);<br>
> +     devi = IICBUS_IVAR(child);<br>
> +     resource_int_value(dname, dunit, "addr", &devi->addr);<br>
> +     if (resource_int_value(dname, dunit, "irq", &irq) == 0) {<br>
> +             if (bus_set_resource(child, SYS_RES_IRQ, 0, irq, 1) != 0)<br>
> +                     device_printf(bus,<br>
> +                         "warning: bus_set_resource() failed\n");<br>
> +     }<br>
> +}<br>
> +<br>
> +static struct resource_list *<br>
> +iicbus_get_resource_list(device_t bus __unused, device_t child)<br>
> +{<br>
> +     struct iicbus_ivar *devi;<br>
> +<br>
> +     devi = IICBUS_IVAR(child);<br>
> +     return (&devi->rl);<br>
> +}<br>
> +<br>
> +int<br>
> +iicbus_generic_intr(device_t dev, int event, char *buf)<br>
> +{<br>
> +<br>
> +     return (0);<br>
> +}<br>
> +<br>
> +int<br>
> +iicbus_null_callback(device_t dev, int index, caddr_t data)<br>
> +{<br>
> +<br>
> +     return (0);<br>
> +}<br>
> +<br>
> +int<br>
> +iicbus_null_repeated_start(device_t dev, u_char addr)<br>
> +{<br>
> +<br>
> +     return (IIC_ENOTSUPP);<br>
> +}<br>
> +<br>
> +void<br>
> +iicbus_init_frequency(device_t dev, u_int bus_freq)<br>
> +{<br>
> +     struct iicbus_softc *sc = IICBUS_SOFTC(dev);<br>
> +<br>
> +     /*<br>
> +      * If a bus frequency value was passed in, use it.  Otherwise initialize<br>
> +      * it first to the standard i2c 100KHz frequency, then override that<br>
> +      * from a hint if one exists.<br>
> +      */<br>
> +     if (bus_freq > 0)<br>
> +             sc->bus_freq = bus_freq;<br>
> +     else {<br>
> +             sc->bus_freq = 100000;<br>
> +             resource_int_value(device_get_name(dev), device_get_unit(dev),<br>
> +                 "frequency", (int *)&sc->bus_freq);<br>
> +     }<br>
> +     /*<br>
> +      * Set up the sysctl that allows the bus frequency to be changed.<br>
> +      * It is flagged as a tunable so that the user can set the value in<br>
> +      * loader(8), and that will override any other setting from any source.<br>
> +      * The sysctl tunable/value is the one most directly controlled by the<br>
> +      * user and thus the one that always takes precedence.<br>
> +      */<br>
> +     SYSCTL_ADD_UINT(device_get_sysctl_ctx(dev),<br>
> +         SYSCTL_CHILDREN(device_get_sysctl_tree(dev)),<br>
> +         OID_AUTO, "frequency", CTLFLAG_RW | CTLFLAG_TUN, &sc->bus_freq,<br>
> +         sc->bus_freq, "Bus frequency in Hz");<br>
> +}<br>
> +<br>
> +static u_int<br>
> +iicbus_get_frequency(device_t dev, u_char speed)<br>
> +{<br>
> +     struct iicbus_softc *sc = IICBUS_SOFTC(dev);<br>
> +<br>
> +     /*<br>
> +      * If the frequency has not been configured for the bus, or the request<br>
> +      * is specifically for SLOW speed, use the standard 100KHz rate, else<br>
> +      * use the configured bus speed.<br>
> +      */<br>
> +     if (sc->bus_freq == 0 || speed == IIC_SLOW)<br>
> +             return (100000);<br>
> +     return (sc->bus_freq);<br>
> +}<br>
> +<br>
> +static device_method_t iicbus_methods[] = {<br>
> +     /* device interface */<br>
> +     DEVMETHOD(device_probe,         iicbus_probe),<br>
> +     DEVMETHOD(device_attach,        iicbus_attach),<br>
> +     DEVMETHOD(device_detach,        iicbus_detach),<br>
> +<br>
> +     /* bus interface */<br>
> +     DEVMETHOD(bus_setup_intr,       bus_generic_setup_intr),<br>
> +     DEVMETHOD(bus_teardown_intr,    bus_generic_teardown_intr),<br>
> +     DEVMETHOD(bus_activate_resource, bus_generic_activate_resource),<br>
> +     DEVMETHOD(bus_deactivate_resource, bus_generic_deactivate_resource),<br>
> +     DEVMETHOD(bus_adjust_resource,  bus_generic_adjust_resource),<br>
> +     DEVMETHOD(bus_alloc_resource,   bus_generic_rl_alloc_resource),<br>
> +     DEVMETHOD(bus_get_resource,     bus_generic_rl_get_resource),<br>
> +     DEVMETHOD(bus_release_resource, bus_generic_rl_release_resource),<br>
> +     DEVMETHOD(bus_set_resource,     bus_generic_rl_set_resource),<br>
> +     DEVMETHOD(bus_get_resource_list, iicbus_get_resource_list),<br>
> +     DEVMETHOD(bus_add_child,        iicbus_add_child),<br>
> +     DEVMETHOD(bus_print_child,      iicbus_print_child),<br>
> +     DEVMETHOD(bus_probe_nomatch,    iicbus_probe_nomatch),<br>
> +     DEVMETHOD(bus_read_ivar,        iicbus_read_ivar),<br>
> +     DEVMETHOD(bus_write_ivar,       iicbus_write_ivar),<br>
> +     DEVMETHOD(bus_child_pnpinfo_str, iicbus_child_pnpinfo_str),<br>
> +     DEVMETHOD(bus_child_location_str, iicbus_child_location_str),<br>
> +     DEVMETHOD(bus_hinted_child,     iicbus_hinted_child),<br>
> +<br>
> +     /* iicbus interface */<br>
> +     DEVMETHOD(iicbus_transfer,      iicbus_transfer),<br>
> +     DEVMETHOD(iicbus_get_frequency, iicbus_get_frequency),<br>
> +<br>
> +     DEVMETHOD_END<br>
> +};<br>
> +<br>
> +driver_t iicbus_driver = {<br>
> +        "iicbus",<br>
> +        iicbus_methods,<br>
> +        sizeof(struct iicbus_softc),<br>
> +};<br>
> +<br>
> +devclass_t iicbus_devclass;<br>
> +<br>
> +MODULE_VERSION(iicbus, IICBUS_MODVER);<br>
> +DRIVER_MODULE(iicbus, iichb, iicbus_driver, iicbus_devclass, 0, 0);<br>
> diff --git a/freebsd/sys/dev/iicbus/iicbus.h b/freebsd/sys/dev/iicbus/iicbus.h<br>
> new file mode 100644<br>
> index 00000000..503305c7<br>
> --- /dev/null<br>
> +++ b/freebsd/sys/dev/iicbus/iicbus.h<br>
> @@ -0,0 +1,83 @@<br>
> +/*-<br>
> + * SPDX-License-Identifier: BSD-2-Clause-FreeBSD<br>
> + *<br>
> + * Copyright (c) 1998 Nicolas Souchu<br>
> + * All rights reserved.<br>
> + *<br>
> + * Redistribution and use in source and binary forms, with or without<br>
> + * modification, are permitted provided that the following conditions<br>
> + * are met:<br>
> + * 1. Redistributions of source code must retain the above copyright<br>
> + *    notice, this list of conditions and the following disclaimer.<br>
> + * 2. Redistributions in binary form must reproduce the above copyright<br>
> + *    notice, this list of conditions and the following disclaimer in the<br>
> + *    documentation and/or other materials provided with the distribution.<br>
> + *<br>
> + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND<br>
> + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE<br>
> + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE<br>
> + * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE<br>
> + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL<br>
> + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS<br>
> + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)<br>
> + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT<br>
> + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY<br>
> + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF<br>
> + * SUCH DAMAGE.<br>
> + *<br>
> + * $FreeBSD$<br>
> + *<br>
> + */<br>
> +#ifndef __IICBUS_H<br>
> +#define __IICBUS_H<br>
> +<br>
> +#include <sys/_lock.h><br>
> +#include <sys/_mutex.h><br>
> +<br>
> +#define IICBUS_IVAR(d) (struct iicbus_ivar *) device_get_ivars(d)<br>
> +#define IICBUS_SOFTC(d) (struct iicbus_softc *) device_get_softc(d)<br>
> +<br>
> +struct iicbus_softc<br>
> +{<br>
> +     device_t dev;           /* Myself */<br>
> +     device_t owner;         /* iicbus owner device structure */<br>
> +     u_int owncount;         /* iicbus ownership nesting count */<br>
> +     u_char started;         /* address of the 'started' slave<br>
> +                              * 0 if no start condition succeeded */<br>
> +     u_char strict;          /* deny operations that violate the<br>
> +                              * I2C protocol */<br>
> +     struct mtx lock;<br>
> +     u_int bus_freq;         /* Configured bus Hz. */<br>
> +};<br>
> +<br>
> +struct iicbus_ivar<br>
> +{<br>
> +     uint32_t        addr;<br>
> +     struct resource_list    rl;<br>
> +     bool            nostop;<br>
> +};<br>
> +<br>
> +enum {<br>
> +     IICBUS_IVAR_ADDR,               /* Address or base address */<br>
> +     IICBUS_IVAR_NOSTOP,             /* nostop defaults */<br>
> +};<br>
> +<br>
> +#define IICBUS_ACCESSOR(A, B, T)                                     \<br>
> +     __BUS_ACCESSOR(iicbus, A, IICBUS, B, T)<br>
> +     <br>
> +IICBUS_ACCESSOR(addr,                ADDR,           uint32_t)<br>
> +IICBUS_ACCESSOR(nostop,              NOSTOP,         bool)<br>
> +<br>
> +#define      IICBUS_LOCK(sc)                 mtx_lock(&(sc)->lock)<br>
> +#define      IICBUS_UNLOCK(sc)               mtx_unlock(&(sc)->lock)<br>
> +#define      IICBUS_ASSERT_LOCKED(sc)        mtx_assert(&(sc)->lock, MA_OWNED)<br>
> +<br>
> +int  iicbus_generic_intr(device_t dev, int event, char *buf);<br>
> +void iicbus_init_frequency(device_t dev, u_int bus_freq);<br>
> +<br>
> +extern driver_t iicbus_driver;<br>
> +extern devclass_t iicbus_devclass;<br>
> +extern driver_t ofw_iicbus_driver;<br>
> +extern devclass_t ofw_iicbus_devclass;<br>
> +<br>
> +#endif<br>
> diff --git a/freebsd/sys/dev/iicbus/iiconf.c b/freebsd/sys/dev/iicbus/iiconf.c<br>
> new file mode 100644<br>
> index 00000000..afdce118<br>
> --- /dev/null<br>
> +++ b/freebsd/sys/dev/iicbus/iiconf.c<br>
> @@ -0,0 +1,527 @@<br>
> +#include <machine/rtems-bsd-kernel-space.h><br>
> +<br>
> +/*-<br>
> + * SPDX-License-Identifier: BSD-2-Clause-FreeBSD<br>
> + *<br>
> + * Copyright (c) 1998 Nicolas Souchu<br>
> + * All rights reserved.<br>
> + *<br>
> + * Redistribution and use in source and binary forms, with or without<br>
> + * modification, are permitted provided that the following conditions<br>
> + * are met:<br>
> + * 1. Redistributions of source code must retain the above copyright<br>
> + *    notice, this list of conditions and the following disclaimer.<br>
> + * 2. Redistributions in binary form must reproduce the above copyright<br>
> + *    notice, this list of conditions and the following disclaimer in the<br>
> + *    documentation and/or other materials provided with the distribution.<br>
> + *<br>
> + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND<br>
> + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE<br>
> + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE<br>
> + * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE<br>
> + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL<br>
> + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS<br>
> + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)<br>
> + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT<br>
> + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY<br>
> + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF<br>
> + * SUCH DAMAGE.<br>
> + */<br>
> +<br>
> +#include <sys/cdefs.h><br>
> +__FBSDID("$FreeBSD$");<br>
> +<br>
> +#include <sys/param.h><br>
> +#include <sys/systm.h><br>
> +#include <sys/lock.h><br>
> +#include <sys/malloc.h><br>
> +#include <sys/module.h><br>
> +#include <sys/mutex.h><br>
> +#include <sys/bus.h><br>
> +<br>
> +#include <dev/iicbus/iiconf.h><br>
> +#include <dev/iicbus/iicbus.h><br>
> +#include <rtems/bsd/local/iicbus_if.h><br>
> +<br>
> +/*<br>
> + * Translate IIC_Exxxxx status values to vaguely-equivelent errno values.<br>
> + */<br>
> +int<br>
> +iic2errno(int iic_status)<br>
> +{<br>
> +     switch (iic_status) {<br>
> +     case IIC_NOERR:         return (0);<br>
> +     case IIC_EBUSERR:       return (EALREADY);<br>
> +     case IIC_ENOACK:        return (EIO);<br>
> +     case IIC_ETIMEOUT:      return (ETIMEDOUT);<br>
> +     case IIC_EBUSBSY:       return (EWOULDBLOCK);<br>
> +     case IIC_ESTATUS:       return (EPROTO);<br>
> +     case IIC_EUNDERFLOW:    return (EIO);<br>
> +     case IIC_EOVERFLOW:     return (EOVERFLOW);<br>
> +     case IIC_ENOTSUPP:      return (EOPNOTSUPP);<br>
> +     case IIC_ENOADDR:       return (EADDRNOTAVAIL);<br>
> +     case IIC_ERESOURCE:     return (ENOMEM);<br>
> +     default:                return (EIO);<br>
> +     }<br>
> +}<br>
> +<br>
> +/*<br>
> + * iicbus_intr()<br>
> + */<br>
> +void<br>
> +iicbus_intr(device_t bus, int event, char *buf)<br>
> +{<br>
> +     struct iicbus_softc *sc = (struct iicbus_softc *)device_get_softc(bus);<br>
> +<br>
> +     /* call owner's intr routine */<br>
> +     if (sc->owner)<br>
> +             IICBUS_INTR(sc->owner, event, buf);<br>
> +<br>
> +     return;<br>
> +}<br>
> +<br>
> +static int<br>
> +iicbus_poll(struct iicbus_softc *sc, int how)<br>
> +{<br>
> +     int error;<br>
> +<br>
> +     IICBUS_ASSERT_LOCKED(sc);<br>
> +     switch (how & IIC_INTRWAIT) {<br>
> +     case IIC_WAIT | IIC_INTR:<br>
> +             error = mtx_sleep(sc, &sc->lock, IICPRI|PCATCH, "iicreq", 0);<br>
> +             break;<br>
> +<br>
> +     case IIC_WAIT | IIC_NOINTR:<br>
> +             error = mtx_sleep(sc, &sc->lock, IICPRI, "iicreq", 0);<br>
> +             break;<br>
> +<br>
> +     default:<br>
> +             return (IIC_EBUSBSY);<br>
> +     }<br>
> +<br>
> +     return (error);<br>
> +}<br>
> +<br>
> +/*<br>
> + * iicbus_request_bus()<br>
> + *<br>
> + * Allocate the device to perform transfers.<br>
> + *<br>
> + * how       : IIC_WAIT or IIC_DONTWAIT<br>
> + */<br>
> +int<br>
> +iicbus_request_bus(device_t bus, device_t dev, int how)<br>
> +{<br>
> +     struct iicbus_softc *sc = (struct iicbus_softc *)device_get_softc(bus);<br>
> +     int error = 0;<br>
> +<br>
> +     IICBUS_LOCK(sc);<br>
> +<br>
> +     for (;;) {<br>
> +             if (sc->owner == NULL)<br>
> +                     break;<br>
> +             if ((how & IIC_RECURSIVE) && sc->owner == dev)<br>
> +                     break;<br>
> +             if ((error = iicbus_poll(sc, how)) != 0)<br>
> +                     break;<br>
> +     }<br>
> +<br>
> +     if (error == 0) {<br>
> +             ++sc->owncount;<br>
> +             if (sc->owner == NULL) {<br>
> +                     sc->owner = dev;<br>
> +                     /* <br>
> +                      * Drop the lock around the call to the bus driver, it<br>
> +                      * should be allowed to sleep in the IIC_WAIT case.<br>
> +                      * Drivers might also need to grab locks that would<br>
> +                      * cause a LOR if our lock is held.<br>
> +                      */<br>
> +                     IICBUS_UNLOCK(sc);<br>
> +                     /* Ask the underlying layers if the request is ok */<br>
> +                     error = IICBUS_CALLBACK(device_get_parent(bus),<br>
> +                         IIC_REQUEST_BUS, (caddr_t)&how);<br>
> +                     IICBUS_LOCK(sc);<br>
> +     <br>
> +                     if (error != 0) {<br>
> +                             sc->owner = NULL;<br>
> +                             sc->owncount = 0;<br>
> +                             wakeup_one(sc);<br>
> +                     }<br>
> +             }<br>
> +     }<br>
> +<br>
> +     IICBUS_UNLOCK(sc);<br>
> +<br>
> +     return (error);<br>
> +}<br>
> +<br>
> +/*<br>
> + * iicbus_release_bus()<br>
> + *<br>
> + * Release the device allocated with iicbus_request_dev()<br>
> + */<br>
> +int<br>
> +iicbus_release_bus(device_t bus, device_t dev)<br>
> +{<br>
> +     struct iicbus_softc *sc = (struct iicbus_softc *)device_get_softc(bus);<br>
> +<br>
> +     IICBUS_LOCK(sc);<br>
> +<br>
> +     if (sc->owner != dev) {<br>
> +             IICBUS_UNLOCK(sc);<br>
> +             return (IIC_EBUSBSY);<br>
> +     }<br>
> +<br>
> +     if (--sc->owncount == 0) {<br>
> +             /* Drop the lock while informing the low-level driver. */<br>
> +             IICBUS_UNLOCK(sc);<br>
> +             IICBUS_CALLBACK(device_get_parent(bus), IIC_RELEASE_BUS, NULL);<br>
> +             IICBUS_LOCK(sc);<br>
> +             sc->owner = NULL;<br>
> +             wakeup_one(sc);<br>
> +     }<br>
> +     IICBUS_UNLOCK(sc);<br>
> +     return (0);<br>
> +}<br>
> +<br>
> +/*<br>
> + * iicbus_started()<br>
> + *<br>
> + * Test if the iicbus is started by the controller<br>
> + */<br>
> +int<br>
> +iicbus_started(device_t bus)<br>
> +{<br>
> +     struct iicbus_softc *sc = (struct iicbus_softc *)device_get_softc(bus);<br>
> +<br>
> +     return (sc->started);<br>
> +}<br>
> +<br>
> +/*<br>
> + * iicbus_start()<br>
> + *<br>
> + * Send start condition to the slave addressed by 'slave'<br>
> + */<br>
> +int<br>
> +iicbus_start(device_t bus, u_char slave, int timeout)<br>
> +{<br>
> +     struct iicbus_softc *sc = (struct iicbus_softc *)device_get_softc(bus);<br>
> +     int error = 0;<br>
> +<br>
> +     if (sc->started)<br>
> +             return (IIC_ESTATUS); /* protocol error, bus already started */<br>
> +<br>
> +     if (!(error = IICBUS_START(device_get_parent(bus), slave, timeout)))<br>
> +             sc->started = slave;<br>
> +     else<br>
> +             sc->started = 0;<br>
> +<br>
> +     return (error);<br>
> +}<br>
> +<br>
> +/*<br>
> + * iicbus_repeated_start()<br>
> + *<br>
> + * Send start condition to the slave addressed by 'slave'<br>
> + */<br>
> +int<br>
> +iicbus_repeated_start(device_t bus, u_char slave, int timeout)<br>
> +{<br>
> +     struct iicbus_softc *sc = (struct iicbus_softc *)device_get_softc(bus);<br>
> +     int error = 0;<br>
> +<br>
> +     if (!sc->started)<br>
> +             return (IIC_ESTATUS); /* protocol error, bus not started */<br>
> +<br>
> +     if (!(error = IICBUS_REPEATED_START(device_get_parent(bus), slave, timeout)))<br>
> +             sc->started = slave;<br>
> +     else<br>
> +             sc->started = 0;<br>
> +<br>
> +     return (error);<br>
> +}<br>
> +<br>
> +/*<br>
> + * iicbus_stop()<br>
> + *<br>
> + * Send stop condition to the bus<br>
> + */<br>
> +int<br>
> +iicbus_stop(device_t bus)<br>
> +{<br>
> +     struct iicbus_softc *sc = (struct iicbus_softc *)device_get_softc(bus);<br>
> +     int error = 0;<br>
> +<br>
> +     if (!sc->started)<br>
> +             return (IIC_ESTATUS); /* protocol error, bus not started */<br>
> +<br>
> +     error = IICBUS_STOP(device_get_parent(bus));<br>
> +<br>
> +     /* refuse any further access */<br>
> +     sc->started = 0;<br>
> +<br>
> +     return (error);<br>
> +}<br>
> +<br>
> +/*<br>
> + * iicbus_write()<br>
> + *<br>
> + * Write a block of data to the slave previously started by<br>
> + * iicbus_start() call<br>
> + */<br>
> +int<br>
> +iicbus_write(device_t bus, const char *buf, int len, int *sent, int timeout)<br>
> +{<br>
> +     struct iicbus_softc *sc = (struct iicbus_softc *)device_get_softc(bus);<br>
> +     <br>
> +     /* a slave must have been started for writing */<br>
> +     if (sc->started == 0 || (sc->strict != 0 && (sc->started & LSB) != 0))<br>
> +             return (IIC_ESTATUS);<br>
> +<br>
> +     return (IICBUS_WRITE(device_get_parent(bus), buf, len, sent, timeout));<br>
> +}<br>
> +<br>
> +/*<br>
> + * iicbus_read()<br>
> + *<br>
> + * Read a block of data from the slave previously started by<br>
> + * iicbus_read() call<br>
> + */<br>
> +int <br>
> +iicbus_read(device_t bus, char *buf, int len, int *read, int last, int delay)<br>
> +{<br>
> +     struct iicbus_softc *sc = (struct iicbus_softc *)device_get_softc(bus);<br>
> +     <br>
> +     /* a slave must have been started for reading */<br>
> +     if (sc->started == 0 || (sc->strict != 0 && (sc->started & LSB) == 0))<br>
> +             return (IIC_ESTATUS);<br>
> +<br>
> +     return (IICBUS_READ(device_get_parent(bus), buf, len, read, last, delay));<br>
> +}<br>
> +<br>
> +/*<br>
> + * iicbus_write_byte()<br>
> + *<br>
> + * Write a byte to the slave previously started by iicbus_start() call<br>
> + */<br>
> +int<br>
> +iicbus_write_byte(device_t bus, char byte, int timeout)<br>
> +{<br>
> +     struct iicbus_softc *sc = device_get_softc(bus);<br>
> +     char data = byte;<br>
> +     int sent;<br>
> +<br>
> +     /* a slave must have been started for writing */<br>
> +     if (sc->started == 0 || (sc->strict != 0 && (sc->started & LSB) != 0))<br>
> +             return (IIC_ESTATUS);<br>
> +<br>
> +     return (iicbus_write(bus, &data, 1, &sent, timeout));<br>
> +}<br>
> +<br>
> +/*<br>
> + * iicbus_read_byte()<br>
> + *<br>
> + * Read a byte from the slave previously started by iicbus_start() call<br>
> + */<br>
> +int<br>
> +iicbus_read_byte(device_t bus, char *byte, int timeout)<br>
> +{<br>
> +     struct iicbus_softc *sc = device_get_softc(bus);<br>
> +     int read;<br>
> +<br>
> +     /* a slave must have been started for reading */<br>
> +     if (sc->started == 0 || (sc->strict != 0 && (sc->started & LSB) == 0))<br>
> +             return (IIC_ESTATUS);<br>
> +<br>
> +     return (iicbus_read(bus, byte, 1, &read, IIC_LAST_READ, timeout));<br>
> +}<br>
> +<br>
> +/*<br>
> + * iicbus_block_write()<br>
> + *<br>
> + * Write a block of data to slave ; start/stop protocol managed<br>
> + */<br>
> +int<br>
> +iicbus_block_write(device_t bus, u_char slave, char *buf, int len, int *sent)<br>
> +{<br>
> +     u_char addr = slave & ~LSB;<br>
> +     int error;<br>
> +<br>
> +     if ((error = iicbus_start(bus, addr, 0)))<br>
> +             return (error);<br>
> +<br>
> +     error = iicbus_write(bus, buf, len, sent, 0);<br>
> +<br>
> +     iicbus_stop(bus);<br>
> +<br>
> +     return (error);<br>
> +}<br>
> +<br>
> +/*<br>
> + * iicbus_block_read()<br>
> + *<br>
> + * Read a block of data from slave ; start/stop protocol managed<br>
> + */<br>
> +int<br>
> +iicbus_block_read(device_t bus, u_char slave, char *buf, int len, int *read)<br>
> +{<br>
> +     u_char addr = slave | LSB;<br>
> +     int error;<br>
> +<br>
> +     if ((error = iicbus_start(bus, addr, 0)))<br>
> +             return (error);<br>
> +<br>
> +     error = iicbus_read(bus, buf, len, read, IIC_LAST_READ, 0);<br>
> +<br>
> +     iicbus_stop(bus);<br>
> +<br>
> +     return (error);<br>
> +}<br>
> +<br>
> +/*<br>
> + * iicbus_transfer()<br>
> + *<br>
> + * Do an aribtrary number of transfers on the iicbus.  We pass these<br>
> + * raw requests to the bridge driver.  If the bridge driver supports<br>
> + * them directly, then it manages all the details.  If not, it can use<br>
> + * the helper function iicbus_transfer_gen() which will do the<br>
> + * transfers at a low level.<br>
> + *<br>
> + * Pointers passed in as part of iic_msg must be kernel pointers.<br>
> + * Callers that have user addresses to manage must do so on their own.<br>
> + */<br>
> +int<br>
> +iicbus_transfer(device_t bus, struct iic_msg *msgs, uint32_t nmsgs)<br>
> +{<br>
> +<br>
> +     return (IICBUS_TRANSFER(device_get_parent(bus), msgs, nmsgs));<br>
> +}<br>
> +<br>
> +int<br>
> +iicbus_transfer_excl(device_t dev, struct iic_msg *msgs, uint32_t nmsgs,<br>
> +    int how)<br>
> +{<br>
> +     device_t bus;<br>
> +     int error;<br>
> +<br>
> +     bus = device_get_parent(dev);<br>
> +     error = iicbus_request_bus(bus, dev, how);<br>
> +     if (error == 0)<br>
> +             error = IICBUS_TRANSFER(bus, msgs, nmsgs);<br>
> +     iicbus_release_bus(bus, dev);<br>
> +     return (error);<br>
> +}<br>
> +<br>
> +/*<br>
> + * Generic version of iicbus_transfer that calls the appropriate<br>
> + * routines to accomplish this.  See note above about acceptable<br>
> + * buffer addresses.<br>
> + */<br>
> +int<br>
> +iicbus_transfer_gen(device_t dev, struct iic_msg *msgs, uint32_t nmsgs)<br>
> +{<br>
> +     int i, error, lenread, lenwrote, nkid, rpstart, addr;<br>
> +     device_t *children, bus;<br>
> +     bool nostop, started;<br>
> +<br>
> +     if ((error = device_get_children(dev, &children, &nkid)) != 0)<br>
> +             return (IIC_ERESOURCE);<br>
> +     if (nkid != 1) {<br>
> +             free(children, M_TEMP);<br>
> +             return (IIC_ENOTSUPP);<br>
> +     }<br>
> +     bus = children[0];<br>
> +     rpstart = 0;<br>
> +     free(children, M_TEMP);<br>
> +     nostop = iicbus_get_nostop(dev);<br>
> +     started = false;<br>
> +     for (i = 0, error = 0; i < nmsgs && error == 0; i++) {<br>
> +             addr = msgs[i].slave;<br>
> +             if (msgs[i].flags & IIC_M_RD)<br>
> +                     addr |= LSB;<br>
> +             else<br>
> +                     addr &= ~LSB;<br>
> +<br>
> +             if (!(msgs[i].flags & IIC_M_NOSTART)) {<br>
> +                     if (rpstart)<br>
> +                             error = iicbus_repeated_start(bus, addr, 0);<br>
> +                     else<br>
> +                             error = iicbus_start(bus, addr, 0);<br>
> +                     if (error != 0)<br>
> +                             break;<br>
> +                     started = true;<br>
> +             }<br>
> +<br>
> +             if (msgs[i].flags & IIC_M_RD)<br>
> +                     error = iicbus_read(bus, msgs[i].buf, msgs[i].len,<br>
> +                         &lenread, IIC_LAST_READ, 0);<br>
> +             else<br>
> +                     error = iicbus_write(bus, msgs[i].buf, msgs[i].len,<br>
> +                         &lenwrote, 0);<br>
> +             if (error != 0)<br>
> +                     break;<br>
> +<br>
> +             if ((msgs[i].flags & IIC_M_NOSTOP) != 0 ||<br>
> +                 (nostop && i + 1 < nmsgs)) {<br>
> +                     rpstart = 1;    /* Next message gets repeated start */<br>
> +             } else {<br>
> +                     rpstart = 0;<br>
> +                     iicbus_stop(bus);<br>
> +             }<br>
> +     }<br>
> +     if (error != 0 && started)<br>
> +             iicbus_stop(bus);<br>
> +     return (error);<br>
> +}<br>
> +<br>
> +int<br>
> +iicdev_readfrom(device_t slavedev, uint8_t regaddr, void *buffer,<br>
> +    uint16_t buflen, int waithow)<br>
> +{<br>
> +     struct iic_msg msgs[2];<br>
> +     uint8_t slaveaddr;<br>
> +<br>
> +     /*<br>
> +      * Two transfers back to back with a repeat-start between them; first we<br>
> +      * write the address-within-device, then we read from the device.<br>
> +      */<br>
> +     slaveaddr = iicbus_get_addr(slavedev);<br>
> +<br>
> +     msgs[0].slave = slaveaddr;<br>
> +     msgs[0].flags = IIC_M_WR | IIC_M_NOSTOP;<br>
> +     msgs[0].len   = 1;<br>
> +     msgs[0].buf   = &regaddr;<br>
> +<br>
> +     msgs[1].slave = slaveaddr;<br>
> +     msgs[1].flags = IIC_M_RD;<br>
> +     msgs[1].len   = buflen;<br>
> +     msgs[1].buf   = buffer;<br>
> +<br>
> +     return (iicbus_transfer_excl(slavedev, msgs, nitems(msgs), waithow));<br>
> +}<br>
> +<br>
> +int iicdev_writeto(device_t slavedev, uint8_t regaddr, void *buffer,<br>
> +    uint16_t buflen, int waithow)<br>
> +{<br>
> +     struct iic_msg msgs[2];<br>
> +     uint8_t slaveaddr;<br>
> +<br>
> +     /*<br>
> +      * Two transfers back to back with no stop or start between them; first<br>
> +      * we write the address then we write the data to that address, all in a<br>
> +      * single transfer from two scattered buffers.<br>
> +      */<br>
> +     slaveaddr = iicbus_get_addr(slavedev);<br>
> +<br>
> +     msgs[0].slave = slaveaddr;<br>
> +     msgs[0].flags = IIC_M_WR | IIC_M_NOSTOP;<br>
> +     msgs[0].len   = 1;<br>
> +     msgs[0].buf   = &regaddr;<br>
> +<br>
> +     msgs[1].slave = slaveaddr;<br>
> +     msgs[1].flags = IIC_M_WR | IIC_M_NOSTART;<br>
> +     msgs[1].len   = buflen;<br>
> +     msgs[1].buf   = buffer;<br>
> +<br>
> +     return (iicbus_transfer_excl(slavedev, msgs, nitems(msgs), waithow));<br>
> +}<br>
> diff --git a/freebsd/sys/dev/iicbus/iiconf.h b/freebsd/sys/dev/iicbus/iiconf.h<br>
> new file mode 100644<br>
> index 00000000..c264183e<br>
> --- /dev/null<br>
> +++ b/freebsd/sys/dev/iicbus/iiconf.h<br>
> @@ -0,0 +1,162 @@<br>
> +/*-<br>
> + * SPDX-License-Identifier: BSD-2-Clause-FreeBSD<br>
> + *<br>
> + * Copyright (c) 1998, 2001 Nicolas Souchu<br>
> + * All rights reserved.<br>
> + *<br>
> + * Redistribution and use in source and binary forms, with or without<br>
> + * modification, are permitted provided that the following conditions<br>
> + * are met:<br>
> + * 1. Redistributions of source code must retain the above copyright<br>
> + *    notice, this list of conditions and the following disclaimer.<br>
> + * 2. Redistributions in binary form must reproduce the above copyright<br>
> + *    notice, this list of conditions and the following disclaimer in the<br>
> + *    documentation and/or other materials provided with the distribution.<br>
> + *<br>
> + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND<br>
> + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE<br>
> + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE<br>
> + * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE<br>
> + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL<br>
> + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS<br>
> + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)<br>
> + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT<br>
> + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY<br>
> + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF<br>
> + * SUCH DAMAGE.<br>
> + *<br>
> + * $FreeBSD$<br>
> + */<br>
> +#ifndef __IICONF_H<br>
> +#define __IICONF_H<br>
> +<br>
> +#include <sys/queue.h><br>
> +#include <dev/iicbus/iic.h><br>
> +<br>
> +<br>
> +#define IICPRI (PZERO+8)             /* XXX sleep/wakeup queue priority */<br>
> +<br>
> +#define LSB 0x1<br>
> +<br>
> +/*<br>
> + * Options affecting iicbus_request_bus()<br>
> + */<br>
> +#define IIC_DONTWAIT 0<br>
> +#define IIC_NOINTR   0<br>
> +#define IIC_WAIT     0x1<br>
> +#define IIC_INTR     0x2<br>
> +#define IIC_INTRWAIT (IIC_INTR | IIC_WAIT)<br>
> +#define IIC_RECURSIVE        0x4<br>
> +<br>
> +/*<br>
> + * i2c modes<br>
> + */<br>
> +#define IIC_MASTER   0x1<br>
> +#define IIC_SLAVE    0x2<br>
> +#define IIC_POLLED   0x4<br>
> +<br>
> +/*<br>
> + * i2c speed<br>
> + */<br>
> +#define IIC_UNKNOWN  0x0<br>
> +#define IIC_SLOW     0x1<br>
> +#define IIC_FAST     0x2<br>
> +#define IIC_FASTEST  0x3<br>
> +<br>
> +#define IIC_LAST_READ        0x1<br>
> +<br>
> +/*<br>
> + * callback index<br>
> + */<br>
> +#define IIC_REQUEST_BUS      0x1<br>
> +#define IIC_RELEASE_BUS      0x2<br>
> +<br>
> +/*<br>
> + * interrupt events<br>
> + */<br>
> +#define INTR_GENERAL 0x1     /* general call received */<br>
> +#define INTR_START   0x2     /* the I2C interface is addressed */<br>
> +#define INTR_STOP    0x3     /* stop condition received */<br>
> +#define INTR_RECEIVE 0x4     /* character received */<br>
> +#define INTR_TRANSMIT        0x5     /* character to transmit */<br>
> +#define INTR_ERROR   0x6     /* error */<br>
> +#define INTR_NOACK   0x7     /* no ack from master receiver */<br>
> +<br>
> +/*<br>
> + * adapter layer errors<br>
> + */<br>
> +#define      IIC_NOERR       0x0     /* no error occurred */<br>
> +#define IIC_EBUSERR  0x1     /* bus error (hardware not in expected state) */<br>
> +#define IIC_ENOACK   0x2     /* ack not received until timeout */<br>
> +#define IIC_ETIMEOUT 0x3     /* timeout */<br>
> +#define IIC_EBUSBSY  0x4     /* bus busy (reserved by another client) */<br>
> +#define IIC_ESTATUS  0x5     /* status error */<br>
> +#define IIC_EUNDERFLOW       0x6     /* slave ready for more data */<br>
> +#define IIC_EOVERFLOW        0x7     /* too much data */<br>
> +#define IIC_ENOTSUPP 0x8     /* request not supported */<br>
> +#define IIC_ENOADDR  0x9     /* no address assigned to the interface */<br>
> +#define IIC_ERESOURCE        0xa     /* resources (memory, whatever) unavailable */<br>
> +<br>
> +/*<br>
> + * Note that all iicbus functions return IIC_Exxxxx status values,<br>
> + * except iic2errno() (obviously) and iicbus_started() (returns bool).<br>
> + */<br>
> +extern int iic2errno(int);<br>
> +extern int iicbus_request_bus(device_t, device_t, int);<br>
> +extern int iicbus_release_bus(device_t, device_t);<br>
> +extern device_t iicbus_alloc_bus(device_t);<br>
> +<br>
> +extern void iicbus_intr(device_t, int, char *);<br>
> +<br>
> +extern int iicbus_null_repeated_start(device_t, u_char);<br>
> +extern int iicbus_null_callback(device_t, int, caddr_t);<br>
> +<br>
> +#define iicbus_reset(bus,speed,addr,oldaddr) \<br>
> +     (IICBUS_RESET(device_get_parent(bus), speed, addr, oldaddr))<br>
> +<br>
> +/* basic I2C operations */<br>
> +extern int iicbus_started(device_t);<br>
> +extern int iicbus_start(device_t, u_char, int);<br>
> +extern int iicbus_stop(device_t);<br>
> +extern int iicbus_repeated_start(device_t, u_char, int);<br>
> +extern int iicbus_write(device_t, const char *, int, int *, int);<br>
> +extern int iicbus_read(device_t, char *, int, int *, int, int);<br>
> +<br>
> +/* single byte read/write functions, start/stop not managed */<br>
> +extern int iicbus_write_byte(device_t, char, int);<br>
> +extern int iicbus_read_byte(device_t, char *, int);<br>
> +<br>
> +/* Read/write operations with start/stop conditions managed */<br>
> +extern int iicbus_block_write(device_t, u_char, char *, int, int *);<br>
> +extern int iicbus_block_read(device_t, u_char, char *, int, int *);<br>
> +<br>
> +/* vectors of iic operations to pass to bridge */<br>
> +int iicbus_transfer(device_t bus, struct iic_msg *msgs, uint32_t nmsgs);<br>
> +int iicbus_transfer_excl(device_t bus, struct iic_msg *msgs, uint32_t nmsgs,<br>
> +    int how);<br>
> +int iicbus_transfer_gen(device_t bus, struct iic_msg *msgs, uint32_t nmsgs);<br>
> +<br>
> +/*<br>
> + * Simple register read/write routines, but the "register" can be any size.<br>
> + * The transfers are done with iicbus_transfer_excl().  Reads use a repeat-start<br>
> + * between sending the address and reading; writes use a single start/stop.<br>
> + */<br>
> +int iicdev_readfrom(device_t _slavedev, uint8_t _regaddr, void *_buffer,<br>
> +    uint16_t _buflen, int _waithow);<br>
> +int iicdev_writeto(device_t _slavedev, uint8_t _regaddr, void *_buffer,<br>
> +    uint16_t _buflen, int _waithow);<br>
> +<br>
> +#define IICBUS_MODVER        1<br>
> +#define IICBUS_MINVER        1<br>
> +#define IICBUS_MAXVER        1<br>
> +#define IICBUS_PREFVER       IICBUS_MODVER<br>
> +<br>
> +extern driver_t iicbb_driver;<br>
> +extern devclass_t iicbb_devclass;<br>
> +<br>
> +#define IICBB_MODVER 1<br>
> +#define IICBB_MINVER 1<br>
> +#define IICBB_MAXVER 1<br>
> +#define IICBB_PREFVER        IICBB_MODVER<br>
> +<br>
> +#endif<br>
> diff --git a/freebsd/sys/dev/iicbus/ofw_iicbus.c b/freebsd/sys/dev/iicbus/ofw_iicbus.c<br>
> new file mode 100644<br>
> index 00000000..cb31459e<br>
> --- /dev/null<br>
> +++ b/freebsd/sys/dev/iicbus/ofw_iicbus.c<br>
> @@ -0,0 +1,242 @@<br>
> +#include <machine/rtems-bsd-kernel-space.h><br>
> +<br>
> +/*-<br>
> + * Copyright (c) 2009, Nathan Whitehorn <nwhitehorn@FreeBSD.org><br>
> + * All rights reserved.<br>
> + *<br>
> + * Redistribution and use in source and binary forms, with or without<br>
> + * modification, are permitted provided that the following conditions<br>
> + * are met:<br>
> + * 1. Redistributions of source code must retain the above copyright<br>
> + *    notice unmodified, this list of conditions, and the following<br>
> + *    disclaimer.<br>
> + * 2. Redistributions in binary form must reproduce the above copyright<br>
> + *    notice, this list of conditions and the following disclaimer in the<br>
> + *    documentation and/or other materials provided with the distribution.<br>
> + *<br>
> + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR<br>
> + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES<br>
> + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.<br>
> + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,<br>
> + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT<br>
> + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,<br>
> + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY<br>
> + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT<br>
> + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF<br>
> + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.<br>
> + */<br>
> +<br>
> +#include <sys/cdefs.h><br>
> +__FBSDID("$FreeBSD$");<br>
> +<br>
> +#include <sys/param.h><br>
> +#include <sys/bus.h><br>
> +#include <sys/kernel.h><br>
> +#include <sys/libkern.h><br>
> +#include <sys/lock.h><br>
> +#include <sys/module.h><br>
> +#include <sys/mutex.h><br>
> +<br>
> +#include <dev/iicbus/iicbus.h><br>
> +#include <dev/iicbus/iiconf.h><br>
> +#include <dev/ofw/ofw_bus.h><br>
> +#include <dev/ofw/ofw_bus_subr.h><br>
> +#include <dev/ofw/openfirm.h><br>
> +<br>
> +#include <rtems/bsd/local/iicbus_if.h><br>
> +<br>
> +/* Methods */<br>
> +static device_probe_t ofw_iicbus_probe;<br>
> +static device_attach_t ofw_iicbus_attach;<br>
> +static device_t ofw_iicbus_add_child(device_t dev, u_int order,<br>
> +    const char *name, int unit);<br>
> +static c</blockquote></div></div></div>