Exemple #1
0
static int
iicbus_detach(device_t dev)
{
	struct iicbus_softc *sc = IICBUS_SOFTC(dev);

	iicbus_reset(dev, IIC_FASTEST, 0, NULL);
	bus_generic_detach(dev);
	mtx_destroy(&sc->lock);
	return (0);
}
Exemple #2
0
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);
}
Exemple #3
0
static int
ofw_iicbus_attach(device_t dev)
{
	struct iicbus_softc *sc = IICBUS_SOFTC(dev);
	struct ofw_iicbus_devinfo *dinfo;
	phandle_t child;
	pcell_t paddr;
	device_t childdev;
	uint32_t addr;

	sc->dev = dev;
	mtx_init(&sc->lock, "iicbus", NULL, MTX_DEF);
	iicbus_reset(dev, IIC_FASTEST, 0, NULL);

	bus_generic_probe(dev);
	bus_enumerate_hinted_children(dev);

	/*
	 * Attach those children represented in the device tree.
	 */
	for (child = OF_child(ofw_bus_get_node(dev)); child != 0;
	    child = OF_peer(child)) {
		/*
		 * Try to get the I2C address first from the i2c-address
		 * property, then try the reg property.  It moves around
		 * on different systems.
		 */
		if (OF_getprop(child, "i2c-address", &paddr, sizeof(paddr)) == -1)
			if (OF_getprop(child, "reg", &paddr, sizeof(paddr)) == -1)
				continue;

		addr = fdt32_to_cpu(paddr);
		/*
		 * Now set up the I2C and OFW bus layer devinfo and add it
		 * to the bus.
		 */
		dinfo = malloc(sizeof(struct ofw_iicbus_devinfo), M_DEVBUF,
		    M_NOWAIT | M_ZERO);
		if (dinfo == NULL)
			continue;
		dinfo->opd_dinfo.addr = addr;
		if (ofw_bus_gen_setup_devinfo(&dinfo->opd_obdinfo, child) !=
		    0) {
			free(dinfo, M_DEVBUF);
			continue;
		}
		childdev = device_add_child(dev, NULL, -1);
		device_set_ivars(childdev, dinfo);
	}

	return (bus_generic_attach(dev));
}
Exemple #4
0
static void
iicdtor(void *data)
{
	device_t iicdev, parent;
	struct iic_cdevpriv *priv;

	priv = data;
	KASSERT(priv != NULL, ("iic cdevpriv should not be NULL!"));

	iicdev = priv->sc->sc_dev;
	parent = device_get_parent(iicdev);

	if (priv->started) {
		iicbus_stop(parent);
		iicbus_reset(parent, IIC_UNKNOWN, 0, NULL);
		iicbus_release_bus(parent, iicdev);
	}

	sx_destroy(&priv->lock);
	free(priv, M_IIC);
}
Exemple #5
0
/*
 * We add all the devices which we know about.
 * The generic attach routine will attach them if they are alive.
 */
static int
iicbus_attach(device_t dev)
{
#if SCAN_IICBUS
	unsigned char addr;
#endif
	struct iicbus_softc *sc = IICBUS_SOFTC(dev);
	int strict;

	sc->dev = dev;
	mtx_init(&sc->lock, "iicbus", NULL, MTX_DEF);
	iicbus_init_frequency(dev, 0);
	iicbus_reset(dev, IIC_FASTEST, 0, NULL);
	if (resource_int_value(device_get_name(dev),
		device_get_unit(dev), "strict", &strict) == 0)
		sc->strict = strict;
	else
		sc->strict = 1;

	/* device probing is meaningless since the bus is supposed to be
	 * hot-plug. Moreover, some I2C chips do not appreciate random
	 * accesses like stop after start to fast, reads for less than
	 * x bytes...
	 */
#if SCAN_IICBUS
	printf("Probing for devices on iicbus%d:", device_get_unit(dev));

	/* probe any devices */
	for (addr = 16; addr < 240; addr++) {
		if (iic_probe_device(dev, (u_char)addr)) {
			printf(" <%x>", addr);
		}
	}
	printf("\n");
#endif
	bus_generic_probe(dev);
	bus_enumerate_hinted_children(dev);
	bus_generic_attach(dev);
        return (0);
}
Exemple #6
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;
}
Exemple #7
0
static int
ofw_iicbus_attach(device_t dev)
{
	struct iicbus_softc *sc = IICBUS_SOFTC(dev);
	struct ofw_iicbus_devinfo *dinfo;
	phandle_t child, node, root;
	pcell_t freq, paddr;
	device_t childdev;
	ssize_t compatlen;
	char compat[255];
	char *curstr;
	u_int iic_addr_8bit = 0;

	sc->dev = dev;
	mtx_init(&sc->lock, "iicbus", NULL, MTX_DEF);

	/*
	 * If there is a clock-frequency property for the device node, use it as
	 * the starting value for the bus frequency.  Then call the common
	 * routine that handles the tunable/sysctl which allows the FDT value to
	 * be overridden by the user.
	 */
	node = ofw_bus_get_node(dev);
	freq = 0;
	OF_getencprop(node, "clock-frequency", &freq, sizeof(freq));
	iicbus_init_frequency(dev, freq);
	
	iicbus_reset(dev, IIC_FASTEST, 0, NULL);

	bus_generic_probe(dev);
	bus_enumerate_hinted_children(dev);

	/*
	 * Check if we're running on a PowerMac, needed for the I2C
	 * address below.
	 */
	root = OF_peer(0);
	compatlen = OF_getprop(root, "compatible", compat,
				sizeof(compat));
	if (compatlen != -1) {
	    for (curstr = compat; curstr < compat + compatlen;
		curstr += strlen(curstr) + 1) {
		if (strncmp(curstr, "MacRISC", 7) == 0)
		    iic_addr_8bit = 1;
	    }
	}

	/*
	 * Attach those children represented in the device tree.
	 */
	for (child = OF_child(node); child != 0; child = OF_peer(child)) {
		/*
		 * Try to get the I2C address first from the i2c-address
		 * property, then try the reg property.  It moves around
		 * on different systems.
		 */
		if (OF_getencprop(child, "i2c-address", &paddr,
		    sizeof(paddr)) == -1)
			if (OF_getencprop(child, "reg", &paddr,
			    sizeof(paddr)) == -1)
				continue;

		/*
		 * Now set up the I2C and OFW bus layer devinfo and add it
		 * to the bus.
		 */
		dinfo = malloc(sizeof(struct ofw_iicbus_devinfo), M_DEVBUF,
		    M_NOWAIT | M_ZERO);
		if (dinfo == NULL)
			continue;
		/*
		 * FreeBSD drivers expect I2C addresses to be expressed as
		 * 8-bit values.  Apple OFW data contains 8-bit values, but
		 * Linux FDT data contains 7-bit values, so shift them up to
		 * 8-bit format.
		 */
		if (iic_addr_8bit)
		    dinfo->opd_dinfo.addr = paddr;
		else
		    dinfo->opd_dinfo.addr = paddr << 1;

		if (ofw_bus_gen_setup_devinfo(&dinfo->opd_obdinfo, child) !=
		    0) {
			free(dinfo, M_DEVBUF);
			continue;
		}

		childdev = device_add_child(dev, NULL, -1);
		resource_list_init(&dinfo->opd_dinfo.rl);
		ofw_bus_intr_to_rl(childdev, child,
					&dinfo->opd_dinfo.rl, NULL);
		device_set_ivars(childdev, dinfo);
	}

	/* Register bus */
	OF_device_register_xref(OF_xref_from_node(node), dev);
	return (bus_generic_attach(dev));
}
Exemple #8
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);
}
Exemple #9
0
static int
ofw_iicbus_attach(device_t dev)
{
	struct iicbus_softc *sc = IICBUS_SOFTC(dev);
	struct ofw_iicbus_devinfo *dinfo;
	phandle_t child, node;
	pcell_t freq, paddr;
	device_t childdev;

	sc->dev = dev;
	mtx_init(&sc->lock, "iicbus", NULL, MTX_DEF);

	/*
	 * If there is a clock-frequency property for the device node, use it as
	 * the starting value for the bus frequency.  Then call the common
	 * routine that handles the tunable/sysctl which allows the FDT value to
	 * be overridden by the user.
	 */
	node = ofw_bus_get_node(dev);
	freq = 0;
	OF_getencprop(node, "clock-frequency", &freq, sizeof(freq));
	iicbus_init_frequency(dev, freq);
	
	iicbus_reset(dev, IIC_FASTEST, 0, NULL);

	bus_generic_probe(dev);
	bus_enumerate_hinted_children(dev);

	/*
	 * Attach those children represented in the device tree.
	 */
	for (child = OF_child(node); child != 0; child = OF_peer(child)) {
		/*
		 * Try to get the I2C address first from the i2c-address
		 * property, then try the reg property.  It moves around
		 * on different systems.
		 */
		if (OF_getencprop(child, "i2c-address", &paddr,
		    sizeof(paddr)) == -1)
			if (OF_getencprop(child, "reg", &paddr,
			    sizeof(paddr)) == -1)
				continue;

		/*
		 * Now set up the I2C and OFW bus layer devinfo and add it
		 * to the bus.
		 */
		dinfo = malloc(sizeof(struct ofw_iicbus_devinfo), M_DEVBUF,
		    M_NOWAIT | M_ZERO);
		if (dinfo == NULL)
			continue;
		/*
		 * FreeBSD drivers expect I2C addresses to be expressed as
		 * 8-bit values.  Apple OFW data contains 8-bit values, but
		 * Linux FDT data contains 7-bit values, so shift them up to
		 * 8-bit format.
		 */
#ifdef AIM
		dinfo->opd_dinfo.addr = paddr;
#else
		dinfo->opd_dinfo.addr = paddr << 1;
#endif
		if (ofw_bus_gen_setup_devinfo(&dinfo->opd_obdinfo, child) !=
		    0) {
			free(dinfo, M_DEVBUF);
			continue;
		}

		childdev = device_add_child(dev, NULL, -1);
		resource_list_init(&dinfo->opd_dinfo.rl);
		ofw_bus_intr_to_rl(childdev, child,
					&dinfo->opd_dinfo.rl, NULL);
		device_set_ivars(childdev, dinfo);
	}

	return (bus_generic_attach(dev));
}
Exemple #10
0
/*
 * 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);
}