Esempio n. 1
0
/*
 * Close the character device.
 */
static int
cmx_close(struct cdev *cdev, int flags, int fmt, struct thread *td)
{
	struct cmx_softc *sc = cdev->si_drv1;

	if (sc == NULL || sc->dying)
		return ENXIO;

	CMX_LOCK(sc);
	if (!sc->open) {
		CMX_UNLOCK(sc);
		return EINVAL;
	}
	if (sc->polling) {
		DEBUG_printf(sc->dev, "disabling polling\n");
		callout_stop(&sc->ch);
		sc->polling = 0;
		CMX_UNLOCK(sc);
		callout_drain(&sc->ch);
		selwakeuppri(&sc->sel, PZERO);
		CMX_LOCK(sc);
	}
	sc->open = 0;
	CMX_UNLOCK(sc);

	DEBUG_printf(sc->dev, "close (flags=%b thread=%p)\n",
			flags, MODEBITS, td);
	return 0;
}
Esempio n. 2
0
/*
 * Bus independant device detachment routine.  Makes sure all
 * allocated resources are freed, callouts disabled and waiting
 * processes unblocked.
 */
int
cmx_detach(device_t dev)
{
	struct cmx_softc *sc = device_get_softc(dev);

	DEBUG_printf(dev, "called\n");

	sc->dying = 1;

	CMX_LOCK(sc);
	if (sc->polling) {
		DEBUG_printf(sc->dev, "disabling polling\n");
		callout_stop(&sc->ch);
		sc->polling = 0;
		CMX_UNLOCK(sc);
		callout_drain(&sc->ch);
		selwakeuppri(&sc->sel, PZERO);
	} else {
		CMX_UNLOCK(sc);
	}

	wakeup(sc);
	destroy_dev(sc->cdev);

	DEBUG_printf(dev, "releasing resources\n");
	cmx_release_resources(dev);
	return 0;
}
Esempio n. 3
0
/*
 * Close the character device.
 */
static int
cmx_close(struct dev_close_args *ap)
{
	cdev_t dev = ap->a_head.a_dev;
	struct cmx_softc *sc;

	sc = devclass_get_softc(cmx_devclass, minor(dev));
	if (sc == NULL || sc->dying)
		return ENXIO;

	CMX_LOCK(sc);
	if (!sc->open) {
		CMX_UNLOCK(sc);
		return EINVAL;
	}
	if (sc->polling) {
		DEBUG_printf(sc->dev, "disabling polling\n");
		callout_stop(&sc->ch);
		sc->polling = 0;
		CMX_UNLOCK(sc);
		KNOTE(&sc->kq.ki_note, 0);
		CMX_LOCK(sc);
	}
	sc->open = 0;
	CMX_UNLOCK(sc);

	DEBUG_printf(sc->dev, "close (flags=%b thread=%p)\n",
			ap->a_fflag, MODEBITS, curthread);
	return 0;
}
Esempio n. 4
0
/*
 * Bus independant device detachment routine.  Makes sure all
 * allocated resources are freed, callouts disabled and waiting
 * processes unblocked.
 */
int
cmx_detach(device_t dev)
{
	struct cmx_softc *sc = device_get_softc(dev);

	DEBUG_printf(dev, "called\n");

	sc->dying = 1;

	CMX_LOCK(sc);
	if (sc->polling) {
		DEBUG_printf(sc->dev, "disabling polling\n");
		callout_stop(&sc->ch);
		sc->polling = 0;
		CMX_UNLOCK(sc);
		KNOTE(&sc->kq.ki_note, 0);
	} else {
		CMX_UNLOCK(sc);
	}

	wakeup(sc);
	DEBUG_printf(dev, "releasing resources\n");
	cmx_release_resources(dev);
	dev_ops_remove_minor(&cmx_ops, device_get_unit(dev));

	return 0;
}
Esempio n. 5
0
static int
cmx_filter_read(struct knote *kn, long hint)
{
	struct cmx_softc *sc = (struct cmx_softc *)kn->kn_hook;
	int ready = 0;
        uint8_t bsr = 0;

        if (sc == NULL || sc->dying) {
		kn->kn_flags |= EV_EOF;
                return (1);
	}

        bsr = cmx_read_BSR(sc);
	if (cmx_test(bsr, BSR_BULK_IN_FULL, 1)) {
		ready = 1;
	} else {
		CMX_LOCK(sc);
		if (!sc->polling) {
			sc->polling = 1;
			callout_reset(&sc->ch, POLL_TICKS,
				      cmx_tick, sc);
		}
		CMX_UNLOCK(sc);
	}

	return (ready);
}
Esempio n. 6
0
/*
 * Open the character device.  Only a single process may open the
 * device at a time.
 */
static int
cmx_open(struct cdev *cdev, int flags, int fmt, struct thread *td)
{
	struct cmx_softc *sc = cdev->si_drv1;

	if (sc == NULL || sc->dying)
		return ENXIO;

	CMX_LOCK(sc);
	if (sc->open) {
		CMX_UNLOCK(sc);
		return EBUSY;
	}
	sc->open = 1;
	CMX_UNLOCK(sc);

	DEBUG_printf(sc->dev, "open (flags=%b thread=%p)\n",
			flags, MODEBITS, td);
	return 0;
}
Esempio n. 7
0
/*
 * Open the character device.  Only a single process may open the
 * device at a time.
 */
static int
cmx_open(struct dev_open_args *ap)
{
	cdev_t dev = ap->a_head.a_dev;
	struct cmx_softc *sc;
	
	sc = devclass_get_softc(cmx_devclass, minor(dev));
	if (sc == NULL || sc->dying)
		return ENXIO;

	CMX_LOCK(sc);
	if (sc->open) {
		CMX_UNLOCK(sc);
		return EBUSY;
	}
	sc->open = 1;
	CMX_UNLOCK(sc);

	DEBUG_printf(sc->dev, "open (flags=%b thread=%p)\n",
			ap->a_oflags, MODEBITS, curthread);
	return 0;
}
Esempio n. 8
0
/*
 * Periodical callout routine, polling the reader for data
 * availability.  If the reader signals data ready for reading,
 * wakes up the processes which are waiting in select()/poll().
 * Otherwise, reschedules itself with a delay of POLL_TICKS.
 */
static void
cmx_tick(void *xsc)
{
	struct cmx_softc *sc = xsc;
	uint8_t bsr;

	CMX_LOCK(sc);
	if (sc->polling && !sc->dying) {
		bsr = cmx_read_BSR(sc);
		DEBUG_printf(sc->dev, "BSR=%b\n", bsr, BSRBITS);
		if (cmx_test(bsr, BSR_BULK_IN_FULL, 1)) {
			sc->polling = 0;
			selwakeuppri(&sc->sel, PZERO);
		} else {
			callout_reset(&sc->ch, POLL_TICKS, cmx_tick, sc);
		}
	}
	CMX_UNLOCK(sc);
}
Esempio n. 9
0
/*
 * Poll handler.  Writing is always possible, reading is only possible
 * if BSR_BULK_IN_FULL is set.  Will start the cmx_tick callout and
 * set sc->polling.
 */
static int
cmx_poll(struct cdev *cdev, int events, struct thread *td)
{
	struct cmx_softc *sc = cdev->si_drv1;
	int revents = 0;
	uint8_t bsr = 0;

	if (sc == NULL || sc->dying)
		return ENXIO;

	bsr = cmx_read_BSR(sc);
	DEBUG_printf(sc->dev, "called (events=%b BSR=%b)\n",
			events, POLLBITS, bsr, BSRBITS);

	revents = events & (POLLOUT | POLLWRNORM);
	if (events & (POLLIN | POLLRDNORM)) {
		if (cmx_test(bsr, BSR_BULK_IN_FULL, 1)) {
			revents |= events & (POLLIN | POLLRDNORM);
		} else {
			selrecord(td, &sc->sel);
			CMX_LOCK(sc);
			if (!sc->polling) {
				DEBUG_printf(sc->dev, "enabling polling\n");
				sc->polling = 1;
				callout_reset(&sc->ch, POLL_TICKS,
						cmx_tick, sc);
			} else {
				DEBUG_printf(sc->dev, "already polling\n");
			}
			CMX_UNLOCK(sc);
		}
	}

	DEBUG_printf(sc->dev, "success (revents=%b)\n", revents, POLLBITS);

	return revents;
}
Esempio n. 10
0
/*
 * Read from the character device.
 * Returns zero if successful, ENXIO if dying, EINVAL if an attempt
 * was made to read less than CMX_MIN_RDLEN bytes or less than the
 * device has available, or any of the errors that cmx_sync_write_SCR
 * can return.  Partial reads are not supported.
 */
static int
cmx_read(struct cdev *cdev, struct uio *uio, int flag)
{
	struct cmx_softc *sc = cdev->si_drv1;
	unsigned long bytes_left;
	uint8_t uc;
	int rv, amnt, offset;

	if (sc == NULL || sc->dying)
		return ENXIO;

	DEBUG_printf(sc->dev, "called (len=%d flag=%b)\n",
		uio->uio_resid, flag, MODEBITS);

	CMX_LOCK(sc);
	if (sc->polling) {
		DEBUG_printf(sc->dev, "disabling polling\n");
		callout_stop(&sc->ch);
		sc->polling = 0;
		CMX_UNLOCK(sc);
		callout_drain(&sc->ch);
		selwakeuppri(&sc->sel, PZERO);
	} else {
		CMX_UNLOCK(sc);
	}

	if (uio->uio_resid == 0) {
		return 0;
	}

	if (uio->uio_resid < CMX_MIN_RDLEN) {
		return EINVAL;
	}

	if (flag & O_NONBLOCK) {
		if (cmx_test_BSR(sc, BSR_BULK_IN_FULL, 0)) {
			return EAGAIN;
		}
	}

	for (int i = 0; i < 5; i++) {
		if ((rv = cmx_wait_BSR(sc, BSR_BULK_IN_FULL, 1)) != 0) {
			return rv;
		}
		sc->buf[i] = cmx_read_DTR(sc);
		DEBUG_printf(sc->dev, "buf[%02x]=%02x\n", i, sc->buf[i]);
	}

	bytes_left = CMX_MIN_RDLEN +
	                (0x000000FF&((char)sc->buf[1])) +
	                (0x0000FF00&((char)sc->buf[2] << 8)) +
	                (0x00FF0000&((char)sc->buf[3] << 16)) +
	                (0xFF000000&((char)sc->buf[4] << 24));
	DEBUG_printf(sc->dev, "msgsz=%lu\n", bytes_left);

	if (uio->uio_resid < bytes_left) {
		return EINVAL;
	}

	offset = 5; /* prefetched header */
	while (bytes_left > 0) {
		amnt = MIN(bytes_left, sizeof(sc->buf));

		for (int i = offset; i < amnt; i++) {
			if ((rv = cmx_wait_BSR(sc, BSR_BULK_IN_FULL, 1))!=0) {
				return rv;
			}
			sc->buf[i] = cmx_read_DTR(sc);
			DEBUG_printf(sc->dev, "buf[%02x]=%02x\n",
					i, sc->buf[i]);
		}

		if ((rv = uiomove(sc->buf, amnt, uio)) != 0) {
			DEBUG_printf(sc->dev, "uiomove failed (%d)\n", rv);
			return rv;
		}

		if (offset)
			offset = 0;
		bytes_left -= amnt;
	}

	if ((rv = cmx_wait_BSR(sc, BSR_BULK_IN_FULL, 1)) != 0) {
		return rv;
	}

	if ((rv = cmx_sync_write_SCR(sc, SCR_READER_TO_HOST_DONE)) != 0) {
		return rv;
	}

	uc = cmx_read_DTR(sc);
	DEBUG_printf(sc->dev, "success (DTR=%02x)\n", uc);
	return 0;
}