static int iicread(dev_t dev, struct uio * uio, int ioflag) { device_t iicdev = IIC_DEVICE(minor(dev)); struct iic_softc *sc = IIC_SOFTC(minor(dev)); int len, error = 0; int bufsize; if (!sc || !iicdev || !sc->sc_addr) return (EINVAL); if (sc->sc_count == 0) return (EINVAL); if ((error = iicbus_request_bus(device_get_parent(iicdev), iicdev, IIC_DONTWAIT))) return (error); /* max amount of data to read */ len = min(uio->uio_resid, BUFSIZE); if ((error = iicbus_block_read(device_get_parent(iicdev), sc->sc_addr, sc->sc_inbuf, len, &bufsize))) return (error); if (bufsize > uio->uio_resid) panic("%s: too much data read!", __func__); iicbus_release_bus(device_get_parent(iicdev), iicdev); return (uiomove(sc->sc_inbuf, bufsize, uio)); }
static int iicwrite(dev_t dev, struct uio * uio, int ioflag) { device_t iicdev = IIC_DEVICE(minor(dev)); struct iic_softc *sc = IIC_SOFTC(minor(dev)); int sent, error, count; if (!sc || !iicdev || !sc->sc_addr) return (EINVAL); if (sc->sc_count == 0) return (EINVAL); if ((error = iicbus_request_bus(device_get_parent(iicdev), iicdev, IIC_DONTWAIT))) return (error); count = min(uio->uio_resid, BUFSIZE); uiomove(sc->sc_buffer, count, uio); error = iicbus_block_write(device_get_parent(iicdev), sc->sc_addr, sc->sc_buffer, count, &sent); iicbus_release_bus(device_get_parent(iicdev), iicdev); return(error); }
static int iicrdwr(struct iic_cdevpriv *priv, struct iic_rdwr_data *d, int flags) { struct iic_msg *buf, *m; void **usrbufs; device_t iicdev, parent; int error, i; iicdev = priv->sc->sc_dev; parent = device_get_parent(iicdev); error = 0; buf = malloc(sizeof(*d->msgs) * d->nmsgs, M_IIC, M_WAITOK); error = copyin(d->msgs, buf, sizeof(*d->msgs) * d->nmsgs); /* Alloc kernel buffers for userland data, copyin write data */ usrbufs = malloc(sizeof(void *) * d->nmsgs, M_IIC, M_WAITOK | M_ZERO); for (i = 0; i < d->nmsgs; i++) { m = &(buf[i]); usrbufs[i] = m->buf; /* * At least init the buffer to NULL so we can safely free() it later. * If the copyin() to buf failed, don't try to malloc bogus m->len. */ m->buf = NULL; if (error != 0) continue; m->buf = malloc(m->len, M_IIC, M_WAITOK); if (!(m->flags & IIC_M_RD)) error = copyin(usrbufs[i], m->buf, m->len); } if (error == 0) error = iicbus_request_bus(parent, iicdev, (flags & O_NONBLOCK) ? IIC_DONTWAIT : (IIC_WAIT | IIC_INTR)); if (error == 0) { error = iicbus_transfer(iicdev, buf, d->nmsgs); iicbus_release_bus(parent, iicdev); } /* Copyout all read segments, free up kernel buffers */ for (i = 0; i < d->nmsgs; i++) { m = &(buf[i]); if ((error == 0) && (m->flags & IIC_M_RD)) error = copyout(m->buf, usrbufs[i], m->len); free(m->buf, M_IIC); } free(usrbufs, M_IIC); free(buf, M_IIC); return (error); }
static int iicioctl(dev_t dev, u_long cmd, caddr_t data, int flags, struct thread *td) { device_t iicdev = IIC_DEVICE(minor(dev)); struct iic_softc *sc = IIC_SOFTC(minor(dev)); device_t parent = device_get_parent(iicdev); struct iiccmd *s = (struct iiccmd *)data; int error, count; if (!sc) return (EINVAL); if ((error = iicbus_request_bus(device_get_parent(iicdev), iicdev, (flags & O_NONBLOCK) ? IIC_DONTWAIT : (IIC_WAIT | IIC_INTR)))) return (error); switch (cmd) { case I2CSTART: error = iicbus_start(parent, s->slave, 0); /* * Implicitly set the chip addr to the slave addr passed as * parameter. Consequently, start/stop shall be called before * the read or the write of a block. */ if (!error) sc->sc_addr = s->slave; break; case I2CSTOP: error = iicbus_stop(parent); break; case I2CRSTCARD: error = iicbus_reset(parent, 0, 0, NULL); break; case I2CWRITE: error = iicbus_write(parent, s->buf, s->count, &count, 10); break; case I2CREAD: error = iicbus_read(parent, s->buf, s->count, &count, s->last, 10); break; default: error = ENODEV; } iicbus_release_bus(device_get_parent(iicdev), iicdev); return (error); }
int iicbus_transfer_excl(device_t dev, struct iic_msg *msgs, uint32_t nmsgs, int how) { device_t bus; int error; bus = device_get_parent(dev); error = iicbus_request_bus(bus, dev, how); if (error == 0) error = IICBUS_TRANSFER(bus, msgs, nmsgs); iicbus_release_bus(bus, dev); return (error); }
static int iicuio(struct cdev *dev, struct uio *uio, int ioflag) { device_t parent; struct iic_cdevpriv *priv; int error; uint8_t addr; priv = NULL; error = devfs_get_cdevpriv((void**)&priv); if (error != 0) return (error); KASSERT(priv != NULL, ("iic cdevpriv should not be NULL!")); IIC_LOCK(priv); if (priv->started || (priv->addr == 0)) { IIC_UNLOCK(priv); return (ENXIO); } parent = device_get_parent(priv->sc->sc_dev); error = iicbus_request_bus(parent, priv->sc->sc_dev, (ioflag & O_NONBLOCK) ? IIC_DONTWAIT : (IIC_WAIT | IIC_INTR)); if (error != 0) { IIC_UNLOCK(priv); return (error); } if (uio->uio_rw == UIO_READ) addr = priv->addr | LSB; else addr = priv->addr & ~LSB; error = iicbus_start(parent, addr, 0); if (error != 0) { iicbus_release_bus(parent, priv->sc->sc_dev); IIC_UNLOCK(priv); return (error); } error = iicuio_move(priv, uio, IIC_LAST_READ); iicbus_stop(parent); iicbus_release_bus(parent, priv->sc->sc_dev); IIC_UNLOCK(priv); return (error); }
static int cambria_gpio_write(struct cambria_gpio_softc *sc) { device_t dev = sc->sc_dev; int error; error = iicbus_request_bus(device_get_parent(dev), dev, IIC_DONTWAIT); if (error) return (error); i2c_sendstart(sc); i2c_sendbyte(sc, PLD_ADDR & ~LSB); i2c_sendbyte(sc, sc->sc_latch); i2c_sendstop(sc); iicbus_release_bus(device_get_parent(dev), dev); return (0); }
static int cambria_gpio_read(struct cambria_gpio_softc *sc, uint32_t pin, unsigned int *val) { device_t dev = sc->sc_dev; int error; error = iicbus_request_bus(device_get_parent(dev), dev, IIC_DONTWAIT); if (error) return (error); i2c_sendstart(sc); i2c_sendbyte(sc, PLD_ADDR | LSB); *val = (i2c_readbyte(sc) & (1 << pin)) != 0; i2c_sendstop(sc); iicbus_release_bus(device_get_parent(dev), dev); return (0); }
/* * iciotcl() */ static int icioctl(struct ifnet *ifp, u_long cmd, caddr_t data, struct ucred *cr) { device_t icdev = devclass_get_device(ic_devclass, ifp->if_dunit); device_t parent = device_get_parent(icdev); struct ic_softc *sc = (struct ic_softc *)device_get_softc(icdev); struct ifaddr *ifa = (struct ifaddr *)data; struct ifreq *ifr = (struct ifreq *)data; u_char *iptr, *optr; int error; switch (cmd) { case SIOCSIFDSTADDR: case SIOCAIFADDR: case SIOCSIFADDR: if (ifa->ifa_addr->sa_family != AF_INET) return EAFNOSUPPORT; ifp->if_flags |= IFF_UP; /* FALLTHROUGH */ case SIOCSIFFLAGS: if ((!(ifp->if_flags & IFF_UP)) && (ifp->if_flags & IFF_RUNNING)) { /* XXX disable PCF */ ifp->if_flags &= ~IFF_RUNNING; /* IFF_UP is not set, try to release the bus anyway */ iicbus_release_bus(parent, icdev); break; } if (((ifp->if_flags & IFF_UP)) && (!(ifp->if_flags & IFF_RUNNING))) { if ((error = iicbus_request_bus(parent, icdev, IIC_WAIT|IIC_INTR))) return (error); sc->ic_obuf = kmalloc(sc->ic_if.if_mtu + ICHDRLEN, M_DEVBUF, M_WAITOK); sc->ic_ifbuf = kmalloc(sc->ic_if.if_mtu + ICHDRLEN, M_DEVBUF, M_WAITOK); iicbus_reset(parent, IIC_FASTEST, 0, NULL); ifp->if_flags |= IFF_RUNNING; } break; case SIOCSIFMTU: /* save previous buffers */ iptr = sc->ic_ifbuf; optr = sc->ic_obuf; /* allocate input buffer */ sc->ic_ifbuf = kmalloc(ifr->ifr_mtu+ICHDRLEN, M_DEVBUF, M_WAITOK); /* allocate output buffer */ sc->ic_ifbuf = kmalloc(ifr->ifr_mtu+ICHDRLEN, M_DEVBUF, M_WAITOK); if (iptr) kfree(iptr,M_DEVBUF); if (optr) kfree(optr,M_DEVBUF); sc->ic_if.if_mtu = ifr->ifr_mtu; break; case SIOCGIFMTU: ifr->ifr_mtu = sc->ic_if.if_mtu; break; case SIOCADDMULTI: case SIOCDELMULTI: if (ifr == NULL) { return EAFNOSUPPORT; /* XXX */ } switch (ifr->ifr_addr.sa_family) { case AF_INET: break; default: return EAFNOSUPPORT; } break; default: return EINVAL; } return 0; }
static int iicioctl(struct cdev *dev, u_long cmd, caddr_t data, int flags, struct thread *td) { device_t parent, iicdev; struct iiccmd *s; struct uio ubuf; struct iovec uvec; struct iic_cdevpriv *priv; int error; s = (struct iiccmd *)data; error = devfs_get_cdevpriv((void**)&priv); if (error != 0) return (error); KASSERT(priv != NULL, ("iic cdevpriv should not be NULL!")); iicdev = priv->sc->sc_dev; parent = device_get_parent(iicdev); IIC_LOCK(priv); switch (cmd) { case I2CSTART: if (priv->started) { error = EINVAL; break; } error = iicbus_request_bus(parent, iicdev, (flags & O_NONBLOCK) ? IIC_DONTWAIT : (IIC_WAIT | IIC_INTR)); if (error == 0) error = iicbus_start(parent, s->slave, 0); if (error == 0) { priv->addr = s->slave; priv->started = true; } else iicbus_release_bus(parent, iicdev); break; case I2CSTOP: if (priv->started) { error = iicbus_stop(parent); iicbus_release_bus(parent, iicdev); priv->started = false; } break; case I2CRSTCARD: /* * Bus should be owned before we reset it. * We allow the bus to be already owned as the result of an in-progress * sequence; however, bus reset will always be followed by release * (a new start is presumably needed for I/O anyway). */ if (!priv->started) error = iicbus_request_bus(parent, iicdev, (flags & O_NONBLOCK) ? IIC_DONTWAIT : (IIC_WAIT | IIC_INTR)); if (error == 0) { error = iicbus_reset(parent, IIC_UNKNOWN, 0, NULL); /* * Ignore IIC_ENOADDR as it only means we have a master-only * controller. */ if (error == IIC_ENOADDR) error = 0; iicbus_release_bus(parent, iicdev); priv->started = false; } break; case I2CWRITE: if (!priv->started) { error = EINVAL; break; } uvec.iov_base = s->buf; uvec.iov_len = s->count; ubuf.uio_iov = &uvec; ubuf.uio_iovcnt = 1; ubuf.uio_segflg = UIO_USERSPACE; ubuf.uio_td = td; ubuf.uio_resid = s->count; ubuf.uio_offset = 0; ubuf.uio_rw = UIO_WRITE; error = iicuio_move(priv, &ubuf, 0); break; case I2CREAD: if (!priv->started) { error = EINVAL; break; } uvec.iov_base = s->buf; uvec.iov_len = s->count; ubuf.uio_iov = &uvec; ubuf.uio_iovcnt = 1; ubuf.uio_segflg = UIO_USERSPACE; ubuf.uio_td = td; ubuf.uio_resid = s->count; ubuf.uio_offset = 0; ubuf.uio_rw = UIO_READ; error = iicuio_move(priv, &ubuf, s->last); break; case I2CRDWR: /* * The rdwr list should be a self-contained set of * transactions. Fail if another transaction is in progress. */ if (priv->started) { error = EINVAL; break; } error = iicrdwr(priv, (struct iic_rdwr_data *)data, flags); break; case I2CRPTSTART: if (!priv->started) { error = EINVAL; break; } error = iicbus_repeated_start(parent, s->slave, 0); break; case I2CSADDR: priv->addr = *((uint8_t*)data); break; default: error = ENOTTY; } IIC_UNLOCK(priv); return (error); }
/* * iciotcl() */ static int icioctl(struct ifnet *ifp, u_long cmd, caddr_t data) { struct ic_softc *sc = ifp->if_softc; device_t icdev = sc->ic_dev; device_t parent = device_get_parent(icdev); struct ifaddr *ifa = (struct ifaddr *)data; struct ifreq *ifr = (struct ifreq *)data; int error; switch (cmd) { case SIOCSIFDSTADDR: case SIOCAIFADDR: case SIOCSIFADDR: if (ifa->ifa_addr->sa_family != AF_INET) return (EAFNOSUPPORT); mtx_lock(&sc->ic_lock); ifp->if_flags |= IFF_UP; goto locked; case SIOCSIFFLAGS: mtx_lock(&sc->ic_lock); locked: if ((!(ifp->if_flags & IFF_UP)) && (ifp->if_drv_flags & IFF_DRV_RUNNING)) { /* XXX disable PCF */ ifp->if_drv_flags &= ~IFF_DRV_RUNNING; mtx_unlock(&sc->ic_lock); /* IFF_UP is not set, try to release the bus anyway */ iicbus_release_bus(parent, icdev); break; } if (((ifp->if_flags & IFF_UP)) && (!(ifp->if_drv_flags & IFF_DRV_RUNNING))) { mtx_unlock(&sc->ic_lock); if ((error = iicbus_request_bus(parent, icdev, IIC_WAIT | IIC_INTR))) return (error); mtx_lock(&sc->ic_lock); iicbus_reset(parent, IIC_FASTEST, 0, NULL); ifp->if_drv_flags |= IFF_DRV_RUNNING; } mtx_unlock(&sc->ic_lock); break; case SIOCSIFMTU: ic_alloc_buffers(sc, ifr->ifr_mtu); break; case SIOCGIFMTU: mtx_lock(&sc->ic_lock); ifr->ifr_mtu = sc->ic_ifp->if_mtu; mtx_unlock(&sc->ic_lock); break; case SIOCADDMULTI: case SIOCDELMULTI: if (ifr == 0) return (EAFNOSUPPORT); /* XXX */ switch (ifr->ifr_addr.sa_family) { case AF_INET: break; default: return (EAFNOSUPPORT); } break; default: return (EINVAL); } return (0); }