Submitted by: nsouch
Philips I2C bus generic support other new bus architecture.
This commit is contained in:
commit
165178e426
468
sys/dev/iicbus/if_ic.c
Normal file
468
sys/dev/iicbus/if_ic.c
Normal file
@ -0,0 +1,468 @@
|
||||
/*-
|
||||
* Copyright (c) 1998 Nicolas Souchu
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*
|
||||
* $Id: if_ic.c,v 1.1.1.11 1998/08/13 17:10:42 son Exp $
|
||||
*/
|
||||
|
||||
/*
|
||||
* I2C bus IP driver
|
||||
*/
|
||||
|
||||
#ifdef KERNEL
|
||||
#include <sys/param.h>
|
||||
#include <sys/systm.h>
|
||||
#include <sys/proc.h>
|
||||
#include <sys/mbuf.h>
|
||||
#include <sys/socket.h>
|
||||
#include <sys/filio.h>
|
||||
#include <sys/sockio.h>
|
||||
#include <sys/kernel.h>
|
||||
#include <sys/module.h>
|
||||
#include <sys/bus.h>
|
||||
#include <sys/time.h>
|
||||
#include <sys/malloc.h>
|
||||
|
||||
#include <net/if.h>
|
||||
#include <net/if_types.h>
|
||||
#include <net/netisr.h>
|
||||
|
||||
#endif /* KERNEL */
|
||||
#include <sys/mbuf.h>
|
||||
#include <sys/socket.h>
|
||||
#include <net/netisr.h>
|
||||
#include <net/route.h>
|
||||
#include <netinet/in.h>
|
||||
#include <netinet/in_systm.h>
|
||||
#include <netinet/in_var.h>
|
||||
#include <netinet/ip.h>
|
||||
#include <netinet/if_ether.h>
|
||||
|
||||
#include "bpfilter.h"
|
||||
|
||||
#if NBPFILTER > 0
|
||||
#include <net/bpf.h>
|
||||
#endif
|
||||
|
||||
#include <dev/iicbus/iiconf.h>
|
||||
#include <dev/iicbus/iicbus.h>
|
||||
|
||||
#include "iicbus_if.h"
|
||||
|
||||
#define ICHDRLEN sizeof(u_int)
|
||||
#define ICMTU 1500 /* default mtu */
|
||||
|
||||
struct ic_softc {
|
||||
struct ifnet ic_if;
|
||||
|
||||
u_char ic_addr; /* peer I2C address */
|
||||
|
||||
int ic_sending;
|
||||
|
||||
char *ic_obuf;
|
||||
char *ic_ifbuf;
|
||||
char *ic_cp;
|
||||
|
||||
int ic_xfercnt;
|
||||
|
||||
int ic_iferrs;
|
||||
};
|
||||
|
||||
static devclass_t ic_devclass;
|
||||
|
||||
static int icprobe(device_t);
|
||||
static int icattach(device_t);
|
||||
|
||||
static int icioctl(struct ifnet *, u_long, caddr_t);
|
||||
static int icoutput(struct ifnet *, struct mbuf *, struct sockaddr *,
|
||||
struct rtentry *);
|
||||
|
||||
static void icintr(device_t, int, char *);
|
||||
|
||||
static device_method_t ic_methods[] = {
|
||||
/* device interface */
|
||||
DEVMETHOD(device_probe, icprobe),
|
||||
DEVMETHOD(device_attach, icattach),
|
||||
|
||||
/* iicbus interface */
|
||||
DEVMETHOD(iicbus_intr, icintr),
|
||||
|
||||
{ 0, 0 }
|
||||
};
|
||||
|
||||
static driver_t ic_driver = {
|
||||
"ic",
|
||||
ic_methods,
|
||||
DRIVER_TYPE_MISC,
|
||||
sizeof(struct ic_softc),
|
||||
};
|
||||
|
||||
/*
|
||||
* icprobe()
|
||||
*/
|
||||
static int
|
||||
icprobe(device_t dev)
|
||||
{
|
||||
return (0);
|
||||
}
|
||||
|
||||
/*
|
||||
* icattach()
|
||||
*/
|
||||
static int
|
||||
icattach(device_t dev)
|
||||
{
|
||||
struct ic_softc *sc = (struct ic_softc *)device_get_softc(dev);
|
||||
struct ifnet *ifp = &sc->ic_if;
|
||||
|
||||
sc->ic_addr = iicbus_get_addr(dev);
|
||||
|
||||
ifp->if_softc = sc;
|
||||
ifp->if_name = "ic";
|
||||
ifp->if_unit = device_get_unit(dev);
|
||||
ifp->if_mtu = ICMTU;
|
||||
ifp->if_flags = IFF_SIMPLEX | IFF_POINTOPOINT | IFF_MULTICAST;
|
||||
ifp->if_ioctl = icioctl;
|
||||
ifp->if_output = icoutput;
|
||||
ifp->if_type = IFT_PARA;
|
||||
ifp->if_hdrlen = 0;
|
||||
ifp->if_addrlen = 0;
|
||||
ifp->if_snd.ifq_maxlen = IFQ_MAXLEN;
|
||||
|
||||
if_attach(ifp);
|
||||
|
||||
#if NBPFILTER > 0
|
||||
bpfattach(ifp, DLT_NULL, ICHDRLEN);
|
||||
#endif
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
/*
|
||||
* iciotcl()
|
||||
*/
|
||||
static int
|
||||
icioctl(struct ifnet *ifp, u_long cmd, caddr_t data)
|
||||
{
|
||||
device_t icdev = devclass_get_device(ic_devclass, ifp->if_unit);
|
||||
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 = malloc(sc->ic_if.if_mtu + ICHDRLEN,
|
||||
M_DEVBUF, M_WAITOK);
|
||||
if (!sc->ic_obuf) {
|
||||
iicbus_release_bus(parent, icdev);
|
||||
return ENOBUFS;
|
||||
}
|
||||
|
||||
sc->ic_ifbuf = malloc(sc->ic_if.if_mtu + ICHDRLEN,
|
||||
M_DEVBUF, M_WAITOK);
|
||||
if (!sc->ic_ifbuf) {
|
||||
iicbus_release_bus(parent, icdev);
|
||||
return ENOBUFS;
|
||||
}
|
||||
|
||||
iicbus_reset(parent, IIC_FASTEST);
|
||||
|
||||
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 = malloc(ifr->ifr_mtu+ICHDRLEN, M_DEVBUF, M_NOWAIT);
|
||||
if (!sc->ic_ifbuf) {
|
||||
|
||||
sc->ic_ifbuf = iptr;
|
||||
sc->ic_obuf = optr;
|
||||
|
||||
return ENOBUFS;
|
||||
}
|
||||
|
||||
/* allocate output buffer */
|
||||
sc->ic_ifbuf = malloc(ifr->ifr_mtu+ICHDRLEN, M_DEVBUF, M_NOWAIT);
|
||||
if (!sc->ic_obuf) {
|
||||
|
||||
free(sc->ic_ifbuf,M_DEVBUF);
|
||||
|
||||
sc->ic_ifbuf = iptr;
|
||||
sc->ic_obuf = optr;
|
||||
|
||||
return ENOBUFS;
|
||||
}
|
||||
|
||||
if (iptr)
|
||||
free(iptr,M_DEVBUF);
|
||||
|
||||
if (optr)
|
||||
free(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 == 0) {
|
||||
return EAFNOSUPPORT; /* XXX */
|
||||
}
|
||||
switch (ifr->ifr_addr.sa_family) {
|
||||
|
||||
case AF_INET:
|
||||
break;
|
||||
|
||||
default:
|
||||
return EAFNOSUPPORT;
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
return EINVAL;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* icintr()
|
||||
*/
|
||||
static void
|
||||
icintr (device_t dev, int event, char *ptr)
|
||||
{
|
||||
struct ic_softc *sc = (struct ic_softc *)device_get_softc(dev);
|
||||
int unit = device_get_unit(dev);
|
||||
int s, len;
|
||||
struct mbuf *top;
|
||||
int i;
|
||||
|
||||
s = splhigh();
|
||||
|
||||
switch (event) {
|
||||
|
||||
case INTR_GENERAL:
|
||||
case INTR_START:
|
||||
sc->ic_cp = sc->ic_ifbuf;
|
||||
sc->ic_xfercnt = 0;
|
||||
break;
|
||||
|
||||
case INTR_STOP:
|
||||
|
||||
/* if any error occured during transfert,
|
||||
* drop the packet */
|
||||
if (sc->ic_iferrs)
|
||||
goto err;
|
||||
|
||||
if ((len = sc->ic_xfercnt) == 0)
|
||||
break; /* ignore */
|
||||
|
||||
if (len <= ICHDRLEN)
|
||||
goto err;
|
||||
|
||||
if (IF_QFULL(&ipintrq)) {
|
||||
IF_DROP(&ipintrq);
|
||||
break;
|
||||
}
|
||||
|
||||
len -= ICHDRLEN;
|
||||
sc->ic_if.if_ipackets ++;
|
||||
sc->ic_if.if_ibytes += len;
|
||||
|
||||
#if NBPFILTER > 0
|
||||
if (sc->ic_if.if_bpf)
|
||||
bpf_tap(&sc->ic_if, sc->ic_ifbuf, len + ICHDRLEN);
|
||||
#endif
|
||||
|
||||
top = m_devget(sc->ic_ifbuf + ICHDRLEN, len, 0, &sc->ic_if, 0);
|
||||
|
||||
if (top) {
|
||||
IF_ENQUEUE(&ipintrq, top);
|
||||
schednetisr(NETISR_IP);
|
||||
}
|
||||
break;
|
||||
|
||||
err:
|
||||
printf("ic%d: errors (%d)!\n", unit, sc->ic_iferrs);
|
||||
|
||||
sc->ic_iferrs = 0; /* reset error count */
|
||||
sc->ic_if.if_ierrors ++;
|
||||
|
||||
break;
|
||||
|
||||
case INTR_RECEIVE:
|
||||
if (sc->ic_xfercnt >= sc->ic_if.if_mtu+ICHDRLEN) {
|
||||
sc->ic_iferrs ++;
|
||||
|
||||
} else {
|
||||
*sc->ic_cp++ = *ptr;
|
||||
sc->ic_xfercnt ++;
|
||||
}
|
||||
break;
|
||||
|
||||
case INTR_NOACK: /* xfer terminated by master */
|
||||
break;
|
||||
|
||||
case INTR_TRANSMIT:
|
||||
*ptr = 0xff; /* XXX */
|
||||
break;
|
||||
|
||||
case INTR_ERROR:
|
||||
sc->ic_iferrs ++;
|
||||
break;
|
||||
|
||||
default:
|
||||
panic("%s: unknown event (%d)!", __FUNCTION__, event);
|
||||
}
|
||||
|
||||
splx(s);
|
||||
return;
|
||||
}
|
||||
|
||||
/*
|
||||
* icoutput()
|
||||
*/
|
||||
static int
|
||||
icoutput(struct ifnet *ifp, struct mbuf *m,
|
||||
struct sockaddr *dst, struct rtentry *rt)
|
||||
{
|
||||
device_t icdev = devclass_get_device(ic_devclass, ifp->if_unit);
|
||||
device_t parent = device_get_parent(icdev);
|
||||
struct ic_softc *sc = (struct ic_softc *)device_get_softc(icdev);
|
||||
|
||||
int s, len, sent;
|
||||
struct mbuf *mm;
|
||||
u_char *cp;
|
||||
u_int hdr = dst->sa_family;
|
||||
|
||||
ifp->if_flags |= IFF_RUNNING;
|
||||
|
||||
s = splhigh();
|
||||
|
||||
/* already sending? */
|
||||
if (sc->ic_sending) {
|
||||
ifp->if_oerrors ++;
|
||||
goto error;
|
||||
}
|
||||
|
||||
/* insert header */
|
||||
bcopy ((char *)&hdr, sc->ic_obuf, ICHDRLEN);
|
||||
|
||||
cp = sc->ic_obuf + ICHDRLEN;
|
||||
len = 0;
|
||||
mm = m;
|
||||
do {
|
||||
if (len + mm->m_len > sc->ic_if.if_mtu) {
|
||||
/* packet to large */
|
||||
ifp->if_oerrors ++;
|
||||
goto error;
|
||||
}
|
||||
|
||||
bcopy(mtod(mm,char *), cp, mm->m_len);
|
||||
cp += mm->m_len;
|
||||
len += mm->m_len;
|
||||
|
||||
} while ((mm = mm->m_next));
|
||||
|
||||
#if NBPFILTER > 0
|
||||
if (ifp->if_bpf) {
|
||||
struct mbuf m0, *n = m;
|
||||
|
||||
/*
|
||||
* We need to prepend the address family as
|
||||
* a four byte field. Cons up a dummy header
|
||||
* to pacify bpf. This is safe because bpf
|
||||
* will only read from the mbuf (i.e., it won't
|
||||
* try to free it or keep a pointer a to it).
|
||||
*/
|
||||
m0.m_next = m;
|
||||
m0.m_len = sizeof(u_int);
|
||||
m0.m_data = (char *)&hdr;
|
||||
n = &m0;
|
||||
|
||||
bpf_mtap(ifp, n);
|
||||
}
|
||||
#endif
|
||||
|
||||
sc->ic_sending = 1;
|
||||
|
||||
m_freem(m);
|
||||
splx(s);
|
||||
|
||||
/* send the packet */
|
||||
if (iicbus_block_write(parent, sc->ic_addr, sc->ic_obuf,
|
||||
len + ICHDRLEN, &sent))
|
||||
|
||||
ifp->if_oerrors ++;
|
||||
else {
|
||||
ifp->if_opackets ++;
|
||||
ifp->if_obytes += len;
|
||||
}
|
||||
|
||||
sc->ic_sending = 0;
|
||||
|
||||
return (0);
|
||||
|
||||
error:
|
||||
m_freem(m);
|
||||
splx(s);
|
||||
|
||||
return(0);
|
||||
}
|
||||
|
||||
DRIVER_MODULE(ic, iicbus, ic_driver, ic_devclass, 0, 0);
|
257
sys/dev/iicbus/iic.c
Normal file
257
sys/dev/iicbus/iic.c
Normal file
@ -0,0 +1,257 @@
|
||||
/*-
|
||||
* Copyright (c) 1998 Nicolas Souchu
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*
|
||||
* $Id: iic.c,v 1.1.2.9 1998/08/13 17:10:42 son Exp $
|
||||
*
|
||||
*/
|
||||
#include <sys/param.h>
|
||||
#include <sys/kernel.h>
|
||||
#include <sys/systm.h>
|
||||
#include <sys/module.h>
|
||||
#include <sys/bus.h>
|
||||
#include <sys/conf.h>
|
||||
#include <sys/buf.h>
|
||||
#include <sys/uio.h>
|
||||
#include <sys/malloc.h>
|
||||
|
||||
#include <machine/clock.h>
|
||||
|
||||
#include <dev/iicbus/iiconf.h>
|
||||
#include <dev/iicbus/iicbus.h>
|
||||
#include <machine/iic.h>
|
||||
|
||||
#include "iicbus_if.h"
|
||||
|
||||
#define BUFSIZE 1024
|
||||
|
||||
struct iic_softc {
|
||||
|
||||
u_char sc_addr; /* address on iicbus */
|
||||
int sc_count; /* >0 if device opened */
|
||||
|
||||
char sc_buffer[BUFSIZE]; /* output buffer */
|
||||
char sc_inbuf[BUFSIZE]; /* input buffer */
|
||||
};
|
||||
|
||||
#define IIC_SOFTC(unit) \
|
||||
((struct iic_softc *)devclass_get_softc(iic_devclass, (unit)))
|
||||
|
||||
#define IIC_DEVICE(unit) \
|
||||
(devclass_get_device(iic_devclass, (unit)))
|
||||
|
||||
static int iic_probe(device_t);
|
||||
static int iic_attach(device_t);
|
||||
|
||||
static devclass_t iic_devclass;
|
||||
|
||||
static device_method_t iic_methods[] = {
|
||||
/* device interface */
|
||||
DEVMETHOD(device_probe, iic_probe),
|
||||
DEVMETHOD(device_attach, iic_attach),
|
||||
|
||||
/* iicbus interface */
|
||||
DEVMETHOD(iicbus_intr, iicbus_generic_intr),
|
||||
|
||||
{ 0, 0 }
|
||||
};
|
||||
|
||||
static driver_t iic_driver = {
|
||||
"iic",
|
||||
iic_methods,
|
||||
DRIVER_TYPE_MISC,
|
||||
sizeof(struct iic_softc),
|
||||
};
|
||||
|
||||
static d_open_t iicopen;
|
||||
static d_close_t iicclose;
|
||||
static d_write_t iicwrite;
|
||||
static d_read_t iicread;
|
||||
static d_ioctl_t iicioctl;
|
||||
|
||||
#define CDEV_MAJOR 15
|
||||
static struct cdevsw iic_cdevsw =
|
||||
{ iicopen, iicclose, iicread, iicwrite, /*15*/
|
||||
iicioctl, nullstop, nullreset, nodevtotty, /*iic*/
|
||||
seltrue, nommap, nostrat, "iic", NULL, -1 };
|
||||
|
||||
/*
|
||||
* iicprobe()
|
||||
*/
|
||||
static int
|
||||
iic_probe(device_t dev)
|
||||
{
|
||||
struct iic_softc *sc = (struct iic_softc *)device_get_softc(dev);
|
||||
|
||||
sc->sc_addr = iicbus_get_addr(dev);
|
||||
|
||||
/* XXX detect chip with start/stop conditions */
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
/*
|
||||
* iicattach()
|
||||
*/
|
||||
static int
|
||||
iic_attach(device_t dev)
|
||||
{
|
||||
struct iic_softc *sc = (struct iic_softc *)device_get_softc(dev);
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
static int
|
||||
iicopen (dev_t dev, int flags, int fmt, struct proc *p)
|
||||
{
|
||||
struct iic_softc *sc = IIC_SOFTC(minor(dev));
|
||||
|
||||
if (!sc)
|
||||
return (EINVAL);
|
||||
|
||||
if (sc->sc_count > 0)
|
||||
return (EBUSY);
|
||||
|
||||
sc->sc_count++;
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
static int
|
||||
iicclose(dev_t dev, int flags, int fmt, struct proc *p)
|
||||
{
|
||||
struct iic_softc *sc = IIC_SOFTC(minor(dev));
|
||||
|
||||
if (!sc)
|
||||
return (EINVAL);
|
||||
|
||||
if (!sc->sc_count)
|
||||
return (EINVAL);
|
||||
|
||||
sc->sc_count--;
|
||||
|
||||
if (sc->sc_count < 0)
|
||||
panic("%s: iic_count < 0!", __FUNCTION__);
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
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)
|
||||
return (EINVAL);
|
||||
|
||||
if (sc->sc_count == 0)
|
||||
return (EINVAL);
|
||||
|
||||
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);
|
||||
|
||||
return(error);
|
||||
}
|
||||
|
||||
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)
|
||||
return (EINVAL);
|
||||
|
||||
if (sc->sc_count == 0)
|
||||
return (EINVAL);
|
||||
|
||||
/* 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!", __FUNCTION__);
|
||||
|
||||
return (uiomove(sc->sc_inbuf, bufsize, uio));
|
||||
}
|
||||
|
||||
static int
|
||||
iicioctl(dev_t dev, u_long cmd, caddr_t data, int flags, struct proc *p)
|
||||
{
|
||||
device_t iicdev = IIC_DEVICE(minor(dev));
|
||||
struct iic_softc *sc = IIC_SOFTC(minor(dev));
|
||||
int error;
|
||||
device_t parent = device_get_parent(iicdev);
|
||||
|
||||
if (!sc)
|
||||
return (EINVAL);
|
||||
|
||||
switch (cmd) {
|
||||
case I2CSTART:
|
||||
error = iicbus_start(parent, sc->sc_addr);
|
||||
break;
|
||||
|
||||
case I2CSTOP:
|
||||
error = iicbus_stop(parent);
|
||||
break;
|
||||
|
||||
case I2CRSTCARD:
|
||||
error = iicbus_reset(parent, 0);
|
||||
break;
|
||||
|
||||
default:
|
||||
error = ENODEV;
|
||||
}
|
||||
|
||||
return (error);
|
||||
}
|
||||
|
||||
static int iic_devsw_installed = 0;
|
||||
|
||||
static void
|
||||
iic_drvinit(void *unused)
|
||||
{
|
||||
dev_t dev;
|
||||
|
||||
if( ! iic_devsw_installed ) {
|
||||
dev = makedev(CDEV_MAJOR,0);
|
||||
cdevsw_add(&dev,&iic_cdevsw,NULL);
|
||||
iic_devsw_installed = 1;
|
||||
}
|
||||
}
|
||||
|
||||
CDEV_DRIVER_MODULE(iic, iicbus, iic_driver, iic_devclass, CDEV_MAJOR,
|
||||
iic_cdevsw, 0, 0);
|
||||
|
||||
SYSINIT(iicdev,SI_SUB_DRIVERS,SI_ORDER_MIDDLE+CDEV_MAJOR,iic_drvinit,NULL)
|
215
sys/dev/iicbus/iicbus.c
Normal file
215
sys/dev/iicbus/iicbus.c
Normal file
@ -0,0 +1,215 @@
|
||||
/*-
|
||||
* Copyright (c) 1998 Nicolas Souchu
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*
|
||||
* $Id: iicbus.c,v 1.1.2.7 1998/08/29 16:54:16 son Exp $
|
||||
*
|
||||
*/
|
||||
|
||||
/*
|
||||
* Autoconfiguration and support routines for the Philips serial I2C bus
|
||||
*/
|
||||
|
||||
#include <sys/param.h>
|
||||
#include <sys/systm.h>
|
||||
#include <sys/kernel.h>
|
||||
#include <sys/module.h>
|
||||
#include <sys/bus.h>
|
||||
|
||||
#include <machine/clock.h>
|
||||
|
||||
#include <dev/iicbus/iiconf.h>
|
||||
#include <dev/iicbus/iicbus.h>
|
||||
|
||||
#include "iicbus_if.h"
|
||||
|
||||
#define DEVTOIICBUS(dev) ((struct iicbus_device*)device_get_ivars(dev))
|
||||
|
||||
/*
|
||||
* structure used to attach devices to the I2C bus
|
||||
*/
|
||||
struct iicbus_device {
|
||||
const char *iicd_name; /* device name */
|
||||
int iicd_class; /* driver or slave device class */
|
||||
const char *iicd_desc; /* device descriptor */
|
||||
u_char iicd_addr; /* address of the device */
|
||||
int iicd_alive; /* 1 if device found */
|
||||
};
|
||||
|
||||
/*
|
||||
* Common I2C addresses
|
||||
*/
|
||||
#define I2C_GENERAL_CALL 0x0
|
||||
#define I2C_MASTER_ADDRESS 0xaa
|
||||
#define I2C_INET_ADDRESS 0xaa
|
||||
|
||||
#define MAXSLAVE 256
|
||||
|
||||
#define IICBUS_UNKNOWN_CLASS 0
|
||||
#define IICBUS_DEVICE_CLASS 1
|
||||
#define IICBUS_DRIVER_CLASS 2
|
||||
|
||||
/*
|
||||
* list of known devices
|
||||
*/
|
||||
struct iicbus_device iicbus_children[] = {
|
||||
{ "iic", IICBUS_DRIVER_CLASS, "General Call", I2C_GENERAL_CALL },
|
||||
{ "iicsmb", IICBUS_DRIVER_CLASS, "I2C to SMB bridge" },
|
||||
{ "iic", IICBUS_DEVICE_CLASS, "PCF8574 I2C to 8 bits parallel i/o", 64},
|
||||
{ "iic", IICBUS_DEVICE_CLASS, "PCF8584 as slave", I2C_MASTER_ADDRESS },
|
||||
{ "ic", IICBUS_DEVICE_CLASS, "network interface", I2C_INET_ADDRESS },
|
||||
{ NULL, 0 }
|
||||
};
|
||||
|
||||
static devclass_t iicbus_devclass;
|
||||
|
||||
/*
|
||||
* Device methods
|
||||
*/
|
||||
static int iicbus_probe(device_t);
|
||||
static int iicbus_attach(device_t);
|
||||
static void iicbus_print_child(device_t, device_t);
|
||||
static int iicbus_read_ivar(device_t , device_t, int, u_long *);
|
||||
|
||||
static device_method_t iicbus_methods[] = {
|
||||
/* device interface */
|
||||
DEVMETHOD(device_probe, iicbus_probe),
|
||||
DEVMETHOD(device_attach, iicbus_attach),
|
||||
DEVMETHOD(device_detach, bus_generic_detach),
|
||||
DEVMETHOD(device_shutdown, bus_generic_shutdown),
|
||||
|
||||
/* bus interface */
|
||||
DEVMETHOD(bus_print_child, iicbus_print_child),
|
||||
DEVMETHOD(bus_read_ivar, iicbus_read_ivar),
|
||||
DEVMETHOD(bus_write_ivar, bus_generic_write_ivar),
|
||||
DEVMETHOD(bus_create_intr, bus_generic_create_intr),
|
||||
DEVMETHOD(bus_connect_intr, bus_generic_connect_intr),
|
||||
|
||||
{ 0, 0 }
|
||||
};
|
||||
|
||||
static driver_t iicbus_driver = {
|
||||
"iicbus",
|
||||
iicbus_methods,
|
||||
DRIVER_TYPE_MISC,
|
||||
sizeof(struct iicbus_softc),
|
||||
};
|
||||
|
||||
/*
|
||||
* At 'probe' time, we add all the devices which we know about to the
|
||||
* bus. The generic attach routine will probe and attach them if they
|
||||
* are alive.
|
||||
*/
|
||||
static int
|
||||
iicbus_probe(device_t dev)
|
||||
{
|
||||
struct iicbus_softc *sc = device_get_softc(dev);
|
||||
struct iicbus_device *iicdev;
|
||||
device_t child;
|
||||
|
||||
/* XXX should query parent */
|
||||
sc->ownaddr = I2C_MASTER_ADDRESS;
|
||||
|
||||
iicbus_reset(dev, IIC_FASTEST);
|
||||
|
||||
for (iicdev = iicbus_children; iicdev->iicd_name; iicdev++) {
|
||||
|
||||
/* probe devices, not drivers */
|
||||
switch (iicdev->iicd_class) {
|
||||
case IICBUS_DEVICE_CLASS:
|
||||
if (!iicbus_start(dev, iicdev->iicd_addr)) {
|
||||
iicbus_stop(dev);
|
||||
iicdev->iicd_alive = 1;
|
||||
}
|
||||
break;
|
||||
case IICBUS_DRIVER_CLASS:
|
||||
iicdev->iicd_addr = sc->ownaddr;
|
||||
break;
|
||||
default:
|
||||
panic("%s: unknown class!", __FUNCTION__);
|
||||
}
|
||||
|
||||
child = device_add_child(dev, iicdev->iicd_name, -1, iicdev);
|
||||
device_set_desc(child, iicdev->iicd_desc);
|
||||
}
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
static int
|
||||
iicbus_attach(device_t dev)
|
||||
{
|
||||
bus_generic_attach(dev);
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
int
|
||||
iicbus_generic_intr(device_t dev, int event, char *buf)
|
||||
{
|
||||
return (0);
|
||||
}
|
||||
|
||||
static void
|
||||
iicbus_print_child(device_t bus, device_t dev)
|
||||
{
|
||||
struct iicbus_device* iicdev = DEVTOIICBUS(dev);
|
||||
|
||||
switch (iicdev->iicd_class) {
|
||||
case IICBUS_DEVICE_CLASS:
|
||||
printf(" on %s%d addr %d %s", device_get_name(bus),
|
||||
device_get_unit(bus), iicdev->iicd_addr,
|
||||
(iicdev->iicd_alive) ? "found" : "not found");
|
||||
break;
|
||||
|
||||
case IICBUS_DRIVER_CLASS:
|
||||
printf(" on %s%d", device_get_name(bus),
|
||||
device_get_unit(bus));
|
||||
break;
|
||||
|
||||
default:
|
||||
panic("%s: unknown class!", __FUNCTION__);
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
static int
|
||||
iicbus_read_ivar(device_t bus, device_t dev, int index, u_long* result)
|
||||
{
|
||||
struct iicbus_device* iicdev = DEVTOIICBUS(dev);
|
||||
|
||||
switch (index) {
|
||||
case IICBUS_IVAR_ADDR:
|
||||
*result = (u_long)iicdev->iicd_addr;
|
||||
break;
|
||||
|
||||
default:
|
||||
return (ENOENT);
|
||||
}
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
DRIVER_MODULE(iicbus, pcf, iicbus_driver, iicbus_devclass, 0, 0);
|
42
sys/dev/iicbus/iicbus.h
Normal file
42
sys/dev/iicbus/iicbus.h
Normal file
@ -0,0 +1,42 @@
|
||||
/*-
|
||||
* Copyright (c) 1998 Nicolas Souchu
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*
|
||||
* $Id: iicbus.h,v 1.1.2.3 1998/08/13 17:10:43 son Exp $
|
||||
*
|
||||
*/
|
||||
#ifndef __IICBUS_H
|
||||
#define __IICBUS_H
|
||||
|
||||
struct iicbus_softc {
|
||||
|
||||
u_char ownaddr; /* address of the adapter */
|
||||
device_t owner; /* iicbus owner device structure */
|
||||
};
|
||||
|
||||
extern devclass_t iicbus_devclass;
|
||||
|
||||
extern int iicbus_generic_intr(device_t dev, int event, char *buf);
|
||||
|
||||
#endif
|
89
sys/dev/iicbus/iicbus_if.m
Normal file
89
sys/dev/iicbus/iicbus_if.m
Normal file
@ -0,0 +1,89 @@
|
||||
#
|
||||
# Copyright (c) 1998 Nicolas Souchu
|
||||
# All rights reserved.
|
||||
#
|
||||
# Redistribution and use in source and binary forms, with or without
|
||||
# modification, are permitted provided that the following conditions
|
||||
# are met:
|
||||
# 1. Redistributions of source code must retain the above copyright
|
||||
# notice, this list of conditions and the following disclaimer.
|
||||
# 2. Redistributions in binary form must reproduce the above copyright
|
||||
# notice, this list of conditions and the following disclaimer in the
|
||||
# documentation and/or other materials provided with the distribution.
|
||||
#
|
||||
# THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
|
||||
# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
# ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
|
||||
# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
# OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
# OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
# SUCH DAMAGE.
|
||||
#
|
||||
# $Id: iicbus_if.m,v 1.1.2.4 1998/08/13 17:10:43 son Exp $
|
||||
#
|
||||
|
||||
INTERFACE iicbus
|
||||
|
||||
#
|
||||
# Interprete interrupt
|
||||
#
|
||||
METHOD int intr {
|
||||
device_t dev;
|
||||
int event;
|
||||
char *buf;
|
||||
};
|
||||
|
||||
#
|
||||
# Send REPEATED_START condition
|
||||
#
|
||||
METHOD int repeated_start {
|
||||
device_t dev;
|
||||
u_char slave;
|
||||
};
|
||||
|
||||
#
|
||||
# Send START condition
|
||||
#
|
||||
METHOD int start {
|
||||
device_t dev;
|
||||
u_char slave;
|
||||
};
|
||||
|
||||
#
|
||||
# Send STOP condition
|
||||
#
|
||||
METHOD int stop {
|
||||
device_t dev;
|
||||
};
|
||||
|
||||
#
|
||||
# Read from I2C bus
|
||||
#
|
||||
METHOD int read {
|
||||
device_t dev;
|
||||
char *buf;
|
||||
int len;
|
||||
int *bytes;
|
||||
};
|
||||
|
||||
#
|
||||
# Write to the I2C bus
|
||||
#
|
||||
METHOD int write {
|
||||
device_t dev;
|
||||
char *buf;
|
||||
int len;
|
||||
int *bytes;
|
||||
};
|
||||
|
||||
#
|
||||
# Reset I2C bus
|
||||
#
|
||||
METHOD int reset {
|
||||
device_t dev;
|
||||
u_char speed;
|
||||
};
|
207
sys/dev/iicbus/iiconf.c
Normal file
207
sys/dev/iicbus/iiconf.c
Normal file
@ -0,0 +1,207 @@
|
||||
/*-
|
||||
* Copyright (c) 1998 Nicolas Souchu
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*
|
||||
* $Id: iiconf.c,v 1.1.1.11 1998/08/29 17:02:05 son Exp $
|
||||
*
|
||||
*/
|
||||
#include <sys/param.h>
|
||||
#include <sys/systm.h>
|
||||
#include <sys/kernel.h>
|
||||
#include <sys/malloc.h>
|
||||
#include <sys/module.h>
|
||||
#include <sys/bus.h>
|
||||
|
||||
#include <dev/iicbus/iiconf.h>
|
||||
#include <dev/iicbus/iicbus.h>
|
||||
#include "iicbus_if.h"
|
||||
|
||||
/*
|
||||
* iicbus_intr()
|
||||
*/
|
||||
void
|
||||
iicbus_intr(device_t bus, int event, char *buf)
|
||||
{
|
||||
struct iicbus_softc *sc = (struct iicbus_softc *)device_get_softc(bus);
|
||||
|
||||
/* call owner's intr routine */
|
||||
if (sc->owner)
|
||||
IICBUS_INTR(sc->owner, event, buf);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
/*
|
||||
* iicbus_alloc_bus()
|
||||
*
|
||||
* Allocate a new bus connected to the given parent device
|
||||
*/
|
||||
device_t
|
||||
iicbus_alloc_bus(device_t parent)
|
||||
{
|
||||
device_t child;
|
||||
|
||||
/* add the bus to the parent */
|
||||
child = device_add_child(parent, "iicbus", -1, NULL);
|
||||
|
||||
if (child)
|
||||
device_set_desc(child, "Philips I2C bus");
|
||||
|
||||
return (child);
|
||||
}
|
||||
|
||||
/*
|
||||
* iicbus_request_bus()
|
||||
*
|
||||
* Allocate the device to perform transfers.
|
||||
*
|
||||
* how : IIC_WAIT or IIC_DONTWAIT
|
||||
*/
|
||||
int
|
||||
iicbus_request_bus(device_t bus, device_t dev, int how)
|
||||
{
|
||||
struct iicbus_softc *sc = (struct iicbus_softc *)device_get_softc(bus);
|
||||
int s, error = 0;
|
||||
|
||||
while (!error) {
|
||||
s = splhigh();
|
||||
if (sc->owner) {
|
||||
splx(s);
|
||||
|
||||
switch (how) {
|
||||
case (IIC_WAIT | IIC_INTR):
|
||||
error = tsleep(sc, IICPRI|PCATCH, "iicreq", 0);
|
||||
break;
|
||||
|
||||
case (IIC_WAIT | IIC_NOINTR):
|
||||
error = tsleep(sc, IICPRI, "iicreq", 0);
|
||||
break;
|
||||
|
||||
default:
|
||||
return (EWOULDBLOCK);
|
||||
break;
|
||||
}
|
||||
|
||||
} else {
|
||||
sc->owner = dev;
|
||||
|
||||
splx(s);
|
||||
return (0);
|
||||
}
|
||||
}
|
||||
|
||||
return (error);
|
||||
}
|
||||
|
||||
/*
|
||||
* iicbus_release_bus()
|
||||
*
|
||||
* Release the device allocated with iicbus_request_dev()
|
||||
*/
|
||||
int
|
||||
iicbus_release_bus(device_t bus, device_t dev)
|
||||
{
|
||||
struct iicbus_softc *sc = (struct iicbus_softc *)device_get_softc(bus);
|
||||
int s;
|
||||
|
||||
s = splhigh();
|
||||
if (sc->owner != dev) {
|
||||
splx(s);
|
||||
return (EACCES);
|
||||
}
|
||||
|
||||
sc->owner = 0;
|
||||
splx(s);
|
||||
|
||||
/* wakeup waiting processes */
|
||||
wakeup(sc);
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
/*
|
||||
* iicbus_block_write()
|
||||
*
|
||||
* Write a block of data to slave ; start/stop protocol managed
|
||||
*/
|
||||
int
|
||||
iicbus_block_write(device_t bus, u_char slave, char *buf, int len, int *sent)
|
||||
{
|
||||
u_char addr = slave & ~LSB;
|
||||
int error;
|
||||
|
||||
if ((error = iicbus_start(bus, addr)))
|
||||
return (error);
|
||||
|
||||
error = iicbus_write(bus, buf, len, sent);
|
||||
|
||||
iicbus_stop(bus);
|
||||
|
||||
return (error);
|
||||
}
|
||||
|
||||
/*
|
||||
* iicbus_block_read()
|
||||
*
|
||||
* Read a block of data from slave ; start/stop protocol managed
|
||||
*/
|
||||
int
|
||||
iicbus_block_read(device_t bus, u_char slave, char *buf, int len, int *read)
|
||||
{
|
||||
u_char addr = slave | LSB;
|
||||
int error;
|
||||
|
||||
if ((error = iicbus_start(bus, addr)))
|
||||
return (error);
|
||||
|
||||
error = iicbus_read(bus, buf, len, read);
|
||||
|
||||
/* STOP condition sent at adapter level */
|
||||
|
||||
return (error);
|
||||
}
|
||||
|
||||
/*
|
||||
* iicbus_get_addr()
|
||||
*
|
||||
* Get the I2C 7 bits address of the device
|
||||
*/
|
||||
u_char
|
||||
iicbus_get_addr(device_t dev)
|
||||
{
|
||||
u_long addr;
|
||||
device_t parent = device_get_parent(dev);
|
||||
|
||||
BUS_READ_IVAR(parent, dev, IICBUS_IVAR_ADDR, &addr);
|
||||
|
||||
return ((u_char)addr);
|
||||
}
|
||||
|
||||
u_char
|
||||
iicbus_get_own_address(device_t bus)
|
||||
{
|
||||
struct iicbus_softc *sc = (struct iicbus_softc *)device_get_softc(bus);
|
||||
|
||||
return (sc->ownaddr);
|
||||
}
|
115
sys/dev/iicbus/iiconf.h
Normal file
115
sys/dev/iicbus/iiconf.h
Normal file
@ -0,0 +1,115 @@
|
||||
/*-
|
||||
* Copyright (c) 1998 Nicolas Souchu
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*
|
||||
* $Id: iiconf.h,v 1.1.1.10 1998/08/13 17:10:43 son Exp $
|
||||
*/
|
||||
#ifndef __IICONF_H
|
||||
#define __IICONF_H
|
||||
|
||||
#include <sys/queue.h>
|
||||
|
||||
#define IICPRI PZERO+8 /* XXX sleep/wakeup queue priority */
|
||||
|
||||
#define n(flags) (~(flags) & (flags))
|
||||
|
||||
#define LSB 0x1
|
||||
|
||||
/*
|
||||
* How tsleep() is called in iic_request_bus().
|
||||
*/
|
||||
#define IIC_DONTWAIT 0
|
||||
#define IIC_NOINTR 0
|
||||
#define IIC_WAIT 0x1
|
||||
#define IIC_INTR 0x2
|
||||
|
||||
/*
|
||||
* i2c modes
|
||||
*/
|
||||
#define IIC_MASTER 0x1
|
||||
#define IIC_SLAVE 0x2
|
||||
#define IIC_POLLED 0x4
|
||||
|
||||
/*
|
||||
* i2c speed
|
||||
*/
|
||||
#define IIC_UNKNOWN 0x0
|
||||
#define IIC_SLOW 0x1
|
||||
#define IIC_FAST 0x2
|
||||
#define IIC_FASTEST 0x3
|
||||
|
||||
/*
|
||||
* interrupt events
|
||||
*/
|
||||
#define INTR_GENERAL 0x1 /* general call received */
|
||||
#define INTR_START 0x2 /* the I2C interface is addressed */
|
||||
#define INTR_STOP 0x3 /* stop condition received */
|
||||
#define INTR_RECEIVE 0x4 /* character received */
|
||||
#define INTR_TRANSMIT 0x5 /* character to transmit */
|
||||
#define INTR_ERROR 0x6 /* error */
|
||||
#define INTR_NOACK 0x7 /* no ack from master receiver */
|
||||
|
||||
/*
|
||||
* adapter layer errors
|
||||
*/
|
||||
#define IIC_NOERR 0x0 /* no error occured */
|
||||
#define IIC_EBUSERR 0x1 /* bus error */
|
||||
#define IIC_ENOACK 0x2 /* ack not received until timeout */
|
||||
#define IIC_ETIMEOUT 0x3 /* timeout */
|
||||
#define IIC_EBUSBSY 0x4 /* bus busy */
|
||||
#define IIC_ESTATUS 0x5 /* status error */
|
||||
#define IIC_EUNDERFLOW 0x6 /* slave ready for more data */
|
||||
#define IIC_EOVERFLOW 0x7 /* too much data */
|
||||
|
||||
/*
|
||||
* ivars codes
|
||||
*/
|
||||
#define IICBUS_IVAR_ADDR 0x1 /* I2C address of the device */
|
||||
|
||||
extern int iicbus_request_bus(device_t, device_t, int);
|
||||
extern int iicbus_release_bus(device_t, device_t);
|
||||
extern device_t iicbus_alloc_bus(device_t);
|
||||
|
||||
extern void iicbus_intr(device_t, int, char *);
|
||||
|
||||
#define iicbus_repeated_start(bus,slave) \
|
||||
(IICBUS_REPEATED_START(device_get_parent(bus), slave))
|
||||
#define iicbus_start(bus,slave) \
|
||||
(IICBUS_START(device_get_parent(bus), slave))
|
||||
#define iicbus_stop(bus) \
|
||||
(IICBUS_STOP(device_get_parent(bus)))
|
||||
#define iicbus_reset(bus,speed) \
|
||||
(IICBUS_RESET(device_get_parent(bus), speed))
|
||||
#define iicbus_write(bus,buf,len,sent) \
|
||||
(IICBUS_WRITE(device_get_parent(bus), buf, len, sent))
|
||||
#define iicbus_read(bus,buf,len,sent) \
|
||||
(IICBUS_READ(device_get_parent(bus), buf, len, sent))
|
||||
|
||||
extern int iicbus_block_write(device_t, u_char, char *, int, int *);
|
||||
extern int iicbus_block_read(device_t, u_char, char *, int, int *);
|
||||
|
||||
extern u_char iicbus_get_addr(device_t);
|
||||
extern u_char iicbus_get_own_address(device_t);
|
||||
|
||||
#endif
|
450
sys/dev/iicbus/iicsmb.c
Normal file
450
sys/dev/iicbus/iicsmb.c
Normal file
@ -0,0 +1,450 @@
|
||||
/*-
|
||||
* Copyright (c) 1998 Nicolas Souchu
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*
|
||||
* $Id: iicsmb.c,v 1.1.2.2 1998/08/13 17:10:44 son Exp $
|
||||
*
|
||||
*/
|
||||
|
||||
/*
|
||||
* I2C to SMB bridge
|
||||
*/
|
||||
|
||||
#include <sys/param.h>
|
||||
#include <sys/kernel.h>
|
||||
#include <sys/systm.h>
|
||||
#include <sys/module.h>
|
||||
#include <sys/bus.h>
|
||||
#include <sys/conf.h>
|
||||
#include <sys/buf.h>
|
||||
#include <sys/uio.h>
|
||||
#include <sys/malloc.h>
|
||||
|
||||
#include <machine/clock.h>
|
||||
|
||||
#include <dev/iicbus/iiconf.h>
|
||||
#include <dev/iicbus/iicbus.h>
|
||||
|
||||
#include <dev/smbus/smbconf.h>
|
||||
|
||||
#include "iicbus_if.h"
|
||||
#include "smbus_if.h"
|
||||
|
||||
struct iicsmb_softc {
|
||||
|
||||
#define SMB_WAITING_ADDR 0x0
|
||||
#define SMB_WAITING_LOW 0x1
|
||||
#define SMB_WAITING_HIGH 0x2
|
||||
#define SMB_DONE 0x3
|
||||
int state;
|
||||
|
||||
u_char devaddr; /* slave device address */
|
||||
|
||||
char low; /* low byte received first */
|
||||
char high; /* high byte */
|
||||
|
||||
device_t smbus;
|
||||
};
|
||||
|
||||
static int iicsmb_probe(device_t);
|
||||
static int iicsmb_attach(device_t);
|
||||
static void iicsmb_print_child(device_t, device_t);
|
||||
|
||||
static void iicsmb_intr(device_t dev, int event, char *buf);
|
||||
static int iicsmb_quick(device_t dev, u_char slave, int how);
|
||||
static int iicsmb_sendb(device_t dev, u_char slave, char byte);
|
||||
static int iicsmb_recvb(device_t dev, u_char slave, char *byte);
|
||||
static int iicsmb_writeb(device_t dev, u_char slave, char cmd, char byte);
|
||||
static int iicsmb_writew(device_t dev, u_char slave, char cmd, short word);
|
||||
static int iicsmb_readb(device_t dev, u_char slave, char cmd, char *byte);
|
||||
static int iicsmb_readw(device_t dev, u_char slave, char cmd, short *word);
|
||||
static int iicsmb_pcall(device_t dev, u_char slave, char cmd, short sdata, short *rdata);
|
||||
static int iicsmb_bwrite(device_t dev, u_char slave, char cmd, u_char count, char *buf);
|
||||
static int iicsmb_bread(device_t dev, u_char slave, char cmd, u_char count, char *buf);
|
||||
|
||||
static devclass_t iicsmb_devclass;
|
||||
|
||||
static device_method_t iicsmb_methods[] = {
|
||||
/* device interface */
|
||||
DEVMETHOD(device_probe, iicsmb_probe),
|
||||
DEVMETHOD(device_attach, iicsmb_attach),
|
||||
|
||||
/* bus interface */
|
||||
DEVMETHOD(bus_print_child, iicsmb_print_child),
|
||||
|
||||
/* iicbus interface */
|
||||
DEVMETHOD(iicbus_intr, iicsmb_intr),
|
||||
|
||||
/* smbus interface */
|
||||
DEVMETHOD(smbus_quick, iicsmb_quick),
|
||||
DEVMETHOD(smbus_sendb, iicsmb_sendb),
|
||||
DEVMETHOD(smbus_recvb, iicsmb_recvb),
|
||||
DEVMETHOD(smbus_writeb, iicsmb_writeb),
|
||||
DEVMETHOD(smbus_writew, iicsmb_writew),
|
||||
DEVMETHOD(smbus_readb, iicsmb_readb),
|
||||
DEVMETHOD(smbus_readw, iicsmb_readw),
|
||||
DEVMETHOD(smbus_pcall, iicsmb_pcall),
|
||||
DEVMETHOD(smbus_bwrite, iicsmb_bwrite),
|
||||
DEVMETHOD(smbus_bread, iicsmb_bread),
|
||||
|
||||
{ 0, 0 }
|
||||
};
|
||||
|
||||
static driver_t iicsmb_driver = {
|
||||
"iicsmb",
|
||||
iicsmb_methods,
|
||||
DRIVER_TYPE_MISC,
|
||||
sizeof(struct iicsmb_softc),
|
||||
};
|
||||
|
||||
static int
|
||||
iicsmb_probe(device_t dev)
|
||||
{
|
||||
struct iicsmb_softc *sc = (struct iicsmb_softc *)device_get_softc(dev);
|
||||
|
||||
sc->smbus = smbus_alloc_bus(dev);
|
||||
|
||||
if (!sc->smbus)
|
||||
return (EINVAL); /* XXX don't know what to return else */
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
static int
|
||||
iicsmb_attach(device_t dev)
|
||||
{
|
||||
struct iicsmb_softc *sc = (struct iicsmb_softc *)device_get_softc(dev);
|
||||
|
||||
/* probe and attach the smbus */
|
||||
device_probe_and_attach(sc->smbus);
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
static void
|
||||
iicsmb_print_child(device_t bus, device_t dev)
|
||||
{
|
||||
printf(" on %s%d", device_get_name(bus), device_get_unit(bus));
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
/*
|
||||
* iicsmb_intr()
|
||||
*
|
||||
* iicbus interrupt handler
|
||||
*/
|
||||
static void
|
||||
iicsmb_intr(device_t dev, int event, char *buf)
|
||||
{
|
||||
struct iicsmb_softc *sc = (struct iicsmb_softc *)device_get_softc(dev);
|
||||
|
||||
switch (event) {
|
||||
case INTR_GENERAL:
|
||||
case INTR_START:
|
||||
sc->state = SMB_WAITING_ADDR;
|
||||
break;
|
||||
|
||||
case INTR_STOP:
|
||||
/* call smbus intr handler */
|
||||
smbus_intr(sc->smbus, sc->devaddr,
|
||||
sc->low, sc->high, SMB_ENOERR);
|
||||
break;
|
||||
|
||||
case INTR_RECEIVE:
|
||||
switch (sc->state) {
|
||||
case SMB_DONE:
|
||||
/* XXX too much data, discard */
|
||||
printf("%s: too much data from 0x%x\n", __FUNCTION__,
|
||||
sc->devaddr & 0xff);
|
||||
goto end;
|
||||
|
||||
case SMB_WAITING_ADDR:
|
||||
sc->devaddr = (u_char)*buf;
|
||||
sc->state = SMB_WAITING_LOW;
|
||||
break;
|
||||
|
||||
case SMB_WAITING_LOW:
|
||||
sc->low = *buf;
|
||||
sc->state = SMB_WAITING_HIGH;
|
||||
break;
|
||||
|
||||
case SMB_WAITING_HIGH:
|
||||
sc->high = *buf;
|
||||
sc->state = SMB_DONE;
|
||||
break;
|
||||
}
|
||||
end:
|
||||
break;
|
||||
|
||||
case INTR_TRANSMIT:
|
||||
case INTR_NOACK:
|
||||
break;
|
||||
|
||||
case INTR_ERROR:
|
||||
switch (*buf) {
|
||||
case IIC_EBUSERR:
|
||||
smbus_intr(sc->smbus, sc->devaddr, 0, 0, SMB_EBUSERR);
|
||||
break;
|
||||
|
||||
default:
|
||||
printf("%s unknown error 0x%x!\n", __FUNCTION__,
|
||||
(int)*buf);
|
||||
break;
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
panic("%s: unknown event (%d)!", __FUNCTION__, event);
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
static int
|
||||
iicsmb_quick(device_t dev, u_char slave, int how)
|
||||
{
|
||||
device_t parent = device_get_parent(dev);
|
||||
int error;
|
||||
|
||||
switch (how) {
|
||||
case SMB_QWRITE:
|
||||
error = iicbus_start(parent, slave & ~LSB);
|
||||
break;
|
||||
|
||||
case SMB_QREAD:
|
||||
error = iicbus_start(parent, slave | LSB);
|
||||
break;
|
||||
|
||||
default:
|
||||
error = EINVAL;
|
||||
break;
|
||||
}
|
||||
|
||||
if (!error)
|
||||
error = iicbus_stop(parent);
|
||||
|
||||
return (error);
|
||||
}
|
||||
|
||||
static int
|
||||
iicsmb_sendb(device_t dev, u_char slave, char byte)
|
||||
{
|
||||
device_t parent = device_get_parent(dev);
|
||||
int error, sent;
|
||||
|
||||
error = iicbus_start(parent, slave & ~LSB);
|
||||
|
||||
if (!error) {
|
||||
error = iicbus_write(parent, &byte, 1, &sent);
|
||||
|
||||
iicbus_stop(parent);
|
||||
}
|
||||
|
||||
return (error);
|
||||
}
|
||||
|
||||
static int
|
||||
iicsmb_recvb(device_t dev, u_char slave, char *byte)
|
||||
{
|
||||
device_t parent = device_get_parent(dev);
|
||||
int error, read;
|
||||
|
||||
error = iicbus_start(parent, slave | LSB);
|
||||
|
||||
if (!error)
|
||||
error = iicbus_read(parent, byte, 1, &read);
|
||||
|
||||
return (error);
|
||||
}
|
||||
|
||||
static int
|
||||
iicsmb_writeb(device_t dev, u_char slave, char cmd, char byte)
|
||||
{
|
||||
device_t parent = device_get_parent(dev);
|
||||
int error, sent;
|
||||
|
||||
error = iicbus_start(parent, slave & ~LSB);
|
||||
|
||||
if (!error) {
|
||||
if (!(error = iicbus_write(parent, &cmd, 1, &sent)))
|
||||
error = iicbus_write(parent, &byte, 1, &sent);
|
||||
|
||||
iicbus_stop(parent);
|
||||
}
|
||||
|
||||
return (error);
|
||||
}
|
||||
|
||||
static int
|
||||
iicsmb_writew(device_t dev, u_char slave, char cmd, short word)
|
||||
{
|
||||
device_t parent = device_get_parent(dev);
|
||||
int error, sent;
|
||||
|
||||
char low = (char)(word & 0xff);
|
||||
char high = (char)((word & 0xff00) >> 8);
|
||||
|
||||
error = iicbus_start(parent, slave & ~LSB);
|
||||
|
||||
if (!error) {
|
||||
if (!(error = iicbus_write(parent, &cmd, 1, &sent)))
|
||||
if (!(error = iicbus_write(parent, &low, 1, &sent)))
|
||||
error = iicbus_write(parent, &high, 1, &sent);
|
||||
|
||||
iicbus_stop(parent);
|
||||
}
|
||||
|
||||
return (error);
|
||||
}
|
||||
|
||||
static int
|
||||
iicsmb_readb(device_t dev, u_char slave, char cmd, char *byte)
|
||||
{
|
||||
device_t parent = device_get_parent(dev);
|
||||
int error, sent, read;
|
||||
|
||||
if ((error = iicbus_start(parent, slave & ~LSB)))
|
||||
goto error;
|
||||
|
||||
if ((error = iicbus_write(parent, &cmd, 1, &sent)))
|
||||
goto error;
|
||||
|
||||
if ((error = iicbus_repeated_start(parent, slave | LSB)))
|
||||
goto error;
|
||||
|
||||
if ((error = iicbus_read(parent, byte, 1, &read)))
|
||||
goto error;
|
||||
|
||||
error:
|
||||
return (error);
|
||||
}
|
||||
|
||||
#define BUF2SHORT(low,high) \
|
||||
((short)(((high) & 0xff) << 8) | (short)((low) & 0xff))
|
||||
|
||||
static int
|
||||
iicsmb_readw(device_t dev, u_char slave, char cmd, short *word)
|
||||
{
|
||||
device_t parent = device_get_parent(dev);
|
||||
int error, sent, read;
|
||||
char buf[2];
|
||||
|
||||
if ((error = iicbus_start(parent, slave & ~LSB)))
|
||||
goto error;
|
||||
|
||||
if ((error = iicbus_write(parent, &cmd, 1, &sent)))
|
||||
goto error;
|
||||
|
||||
if ((error = iicbus_repeated_start(parent, slave | LSB)))
|
||||
goto error;
|
||||
|
||||
if ((error = iicbus_read(parent, buf, 2, &read)))
|
||||
goto error;
|
||||
|
||||
/* first, receive low, then high byte */
|
||||
*word = BUF2SHORT(buf[0], buf[1]);
|
||||
|
||||
error:
|
||||
return (error);
|
||||
}
|
||||
|
||||
static int
|
||||
iicsmb_pcall(device_t dev, u_char slave, char cmd, short sdata, short *rdata)
|
||||
{
|
||||
device_t parent = device_get_parent(dev);
|
||||
int error, sent, read;
|
||||
char buf[2];
|
||||
|
||||
if ((error = iicbus_start(parent, slave & ~LSB)))
|
||||
goto error;
|
||||
|
||||
if ((error = iicbus_write(parent, &cmd, 1, &sent)))
|
||||
goto error;
|
||||
|
||||
/* first, send low, then high byte */
|
||||
buf[0] = (char)(sdata & 0xff);
|
||||
buf[1] = (char)((sdata & 0xff00) >> 8);
|
||||
|
||||
if ((error = iicbus_write(parent, buf, 2, &sent)))
|
||||
goto error;
|
||||
|
||||
if ((error = iicbus_repeated_start(parent, slave | LSB)))
|
||||
goto error;
|
||||
|
||||
if ((error = iicbus_read(parent, buf, 2, &read)))
|
||||
goto error;
|
||||
|
||||
/* first, receive low, then high byte */
|
||||
*rdata = BUF2SHORT(buf[0], buf[1]);
|
||||
|
||||
error:
|
||||
return (error);
|
||||
}
|
||||
|
||||
static int
|
||||
iicsmb_bwrite(device_t dev, u_char slave, char cmd, u_char count, char *buf)
|
||||
{
|
||||
device_t parent = device_get_parent(dev);
|
||||
int error, sent;
|
||||
|
||||
if ((error = iicbus_start(parent, slave & ~LSB)))
|
||||
goto error;
|
||||
|
||||
if ((error = iicbus_write(parent, &cmd, 1, &sent)))
|
||||
goto error;
|
||||
|
||||
if ((error = iicbus_write(parent, buf, (int)count, &sent)))
|
||||
goto error;
|
||||
|
||||
if ((error = iicbus_stop(parent)))
|
||||
goto error;
|
||||
|
||||
error:
|
||||
return (error);
|
||||
}
|
||||
|
||||
static int
|
||||
iicsmb_bread(device_t dev, u_char slave, char cmd, u_char count, char *buf)
|
||||
{
|
||||
device_t parent = device_get_parent(dev);
|
||||
int error, sent, read;
|
||||
|
||||
if ((error = iicbus_start(parent, slave & ~LSB)))
|
||||
goto error;
|
||||
|
||||
if ((error = iicbus_write(parent, &cmd, 1, &sent)))
|
||||
goto error;
|
||||
|
||||
if ((error = iicbus_repeated_start(parent, slave | LSB)))
|
||||
goto error;
|
||||
|
||||
if ((error = iicbus_read(parent, buf, (int)count, &read)))
|
||||
goto error;
|
||||
|
||||
error:
|
||||
return (error);
|
||||
}
|
||||
|
||||
DRIVER_MODULE(iicsmb, iicbus, iicsmb_driver, iicsmb_devclass, 0, 0);
|
Loading…
Reference in New Issue
Block a user