Ejemplo n.º 1
0
int
ad1848_trigger_input(void *addr, void *start, void *end, int blksize,
    void (*intr)(void *), void *arg, struct audio_params *param)
{
	struct ad1848_softc *sc = addr;
	u_char reg;

	if (sc->sc_recdrq == -1) {
		DPRINTF(("ad1848_trigger_input: invalid recording drq\n"));
		return ENXIO;
	}

	isa_dmastart(sc->sc_isa, sc->sc_recdrq, start,
	    (char *)end - (char *)start, NULL, DMAMODE_READ | DMAMODE_LOOP,
	    BUS_DMA_NOWAIT);

	sc->sc_recrun = 1;
	sc->sc_rintr = intr;
	sc->sc_rarg = arg;

	blksize = (blksize * NBBY) / (param->precision * param->channels) - 1;

	if (sc->mode == 2) {
		ad_write(sc, CS_LOWER_REC_CNT, (blksize & 0xff));
		ad_write(sc, CS_UPPER_REC_CNT, ((blksize >> 8) & 0xff));
	} else {
Ejemplo n.º 2
0
int
satlinkopen(dev_t dev, int flags, int fmt,
    struct lwp *l)
{
	struct satlink_softc *sc;
	int error;

	sc = device_lookup_private(&satlink_cd, minor(dev));

	if (sc == NULL)
		return (ENXIO);

	if (sc->sc_flags & SATF_ISOPEN)
		return (EBUSY);

	bus_space_write_1(sc->sc_iot, sc->sc_ioh, SATLINK_COMMAND,
		    SATLINK_CMD_RESET);

	/* Reset the ring buffer, and start the DMA loop. */
	sc->sc_uptr = 0;
	sc->sc_sptr = 0;
	sc->sc_lastresid = sc->sc_bufsize;
	memset(sc->sc_buf, 0, sc->sc_bufsize);
	error = isa_dmastart(sc->sc_ic, sc->sc_drq, sc->sc_buf,
	    sc->sc_bufsize, NULL, DMAMODE_READ|DMAMODE_LOOP, BUS_DMA_WAITOK);
	if (error)
		return (error);

	sc->sc_flags |= SATF_ISOPEN;

	callout_reset(&sc->sc_ch, SATLINK_TIMEOUT, satlinktimeout, sc);

	return (0);
}
Ejemplo n.º 3
0
/* Start DMA operation over ISA bus */
int
atppc_isadma_start(isa_chipset_tag_t ic, int drq, void *buf, u_int nbytes,
	u_int8_t mode)
{
	return (isa_dmastart(ic, drq, buf, nbytes, NULL,
		((mode == ATPPC_DMA_MODE_WRITE) ? DMAMODE_WRITE :
		DMAMODE_READ) | DMAMODE_DEMAND, ((mode == ATPPC_DMA_MODE_WRITE)
		? BUS_DMA_WRITE : BUS_DMA_READ) | BUS_DMA_NOWAIT));
}
Ejemplo n.º 4
0
static void
wdc_isapnp_dma_start(void *scv, void *buf, size_t size, int read)
{
	struct wdc_isapnp_softc *sc = scv;

	isa_dmastart(sc->sc_ic, sc->sc_drq, buf, size, NULL,
	    (read ? DMAMODE_READ : DMAMODE_WRITE) | DMAMODE_DEMAND,
	    BUS_DMA_NOWAIT);
}
Ejemplo n.º 5
0
static int
wdc_isa_dma_init(void *v, int channel, int drive, void *databuf, size_t datalen,
    int read)
{
	struct wdc_isa_softc *sc = v;

	isa_dmastart(sc->sc_isa, sc->sc_drq, databuf, datalen, NULL,
	    (read ? DMAMODE_READ : DMAMODE_WRITE),
	    BUS_DMA_NOWAIT);

	return 0;
}
Ejemplo n.º 6
0
int
ad1848_isa_trigger_input(
	void *addr,
	void *start, void *end,
	int blksize,
	void (*intr)(void *),
	void *arg,
	const audio_params_t *param)
{
	struct ad1848_isa_softc *isc;
	struct ad1848_softc *sc;
	uint8_t reg;

	isc = addr;
	sc = &isc->sc_ad1848;
	isa_dmastart(isc->sc_ic, isc->sc_recdrq, start,
	    (char *)end - (char *)start, NULL,
	    DMAMODE_READ | DMAMODE_LOOPDEMAND, BUS_DMA_NOWAIT);

	isc->sc_recrun = 1;
	if (sc->mode == 2 && isc->sc_playdrq != isc->sc_recdrq) {
		isc->sc_rintr = intr;
		isc->sc_rarg = arg;
	} else {
		isc->sc_pintr = intr;
		isc->sc_parg = arg;
	}

	/*
	 * Calculate number of transfers.
	 * Note that ADPCM is always transferred 4 bytes at at a time.
	 */
	blksize = (param->encoding == AUDIO_ENCODING_ADPCM) ? blksize / 4 - 1 :
	    (blksize * 8) / (param->precision * param->channels) - 1;

	if (sc->mode >= 2) {
		ad_write(sc, CS_LOWER_REC_CNT, blksize & 0xff);
		ad_write(sc, CS_UPPER_REC_CNT, blksize >> 8);
	} else {
Ejemplo n.º 7
0
void
sndbuf_dma(struct snd_dbuf *b, int go)
{
	KASSERT(b, ("sndbuf_dma called with b == NULL"));
	KASSERT(sndbuf_getflags(b) & SNDBUF_F_DMA, ("sndbuf_dma called on non-ISA buffer"));

	switch (go) {
	case PCMTRIG_START:
		/* isa_dmainit(b->chan, size); */
		isa_dmastart(b->dir | ISADMA_RAW, b->buf, b->bufsize, b->dmachan);
		break;

	case PCMTRIG_STOP:
	case PCMTRIG_ABORT:
		isa_dmastop(b->dmachan);
		isa_dmadone(b->dir | ISADMA_RAW, b->buf, b->bufsize, b->dmachan);
		break;
	}

	DEB(printf("buf 0x%p ISA DMA %s, channel %d\n",
		b,
		(go == PCMTRIG_START)? "started" : "stopped",
		b->dmachan));
}
Ejemplo n.º 8
0
Archivo: ppc.c Proyecto: MarginC/kame
/*
 * Call this function if you want to send data in any advanced mode
 * of your parallel port: FIFO, DMA
 *
 * If what you want is not possible (no ECP, no DMA...),
 * EINVAL is returned
 */
int
ppc_write(device_t dev, char *buf, int len, int how)
{
	struct ppc_data *ppc = DEVTOSOFTC(dev);
	char ecr, ecr_sav, ctr, ctr_sav;
	int s, error = 0;
	int spin;

#ifdef PPC_DEBUG
	printf("w");
#endif

	ecr_sav = r_ecr(ppc);
	ctr_sav = r_ctr(ppc);

	/*
	 * Send buffer with DMA, FIFO and interrupts
	 */
	if ((ppc->ppc_avm & PPB_ECP) && (ppc->ppc_registered)) {

	    if (ppc->ppc_dmachan > 0) {

		/* byte mode, no intr, no DMA, dir=0, flush fifo
		 */
		ecr = PPC_ECR_STD | PPC_DISABLE_INTR;
		w_ecr(ppc, ecr);

		/* disable nAck interrupts */
		ctr = r_ctr(ppc);
		ctr &= ~IRQENABLE;
		w_ctr(ppc, ctr);

		ppc->ppc_dmaflags = 0;
		ppc->ppc_dmaddr = (caddr_t)buf;
		ppc->ppc_dmacnt = (u_int)len;

		switch (ppc->ppc_mode) {
		case PPB_COMPATIBLE:
			/* compatible mode with FIFO, no intr, DMA, dir=0 */
			ecr = PPC_ECR_FIFO | PPC_DISABLE_INTR | PPC_ENABLE_DMA;
			break;
		case PPB_ECP:
			ecr = PPC_ECR_ECP | PPC_DISABLE_INTR | PPC_ENABLE_DMA;
			break;
		default:
			error = EINVAL;
			goto error;
		}

		w_ecr(ppc, ecr);
		ecr = r_ecr(ppc);

		/* enter splhigh() not to be preempted
		 * by the dma interrupt, we may miss
		 * the wakeup otherwise
		 */
		s = splhigh();

		ppc->ppc_dmastat = PPC_DMA_INIT;

		/* enable interrupts */
		ecr &= ~PPC_SERVICE_INTR;
		ppc->ppc_irqstat = PPC_IRQ_DMA;
		w_ecr(ppc, ecr);

		isa_dmastart(
			ppc->ppc_dmaflags,
			ppc->ppc_dmaddr,
			ppc->ppc_dmacnt,
			ppc->ppc_dmachan);
#ifdef PPC_DEBUG
		printf("s%d", ppc->ppc_dmacnt);
#endif
		ppc->ppc_dmastat = PPC_DMA_STARTED;

		/* Wait for the DMA completed interrupt. We hope we won't
		 * miss it, otherwise a signal will be necessary to unlock the
		 * process.
		 */
		do {
			/* release CPU */
			error = tsleep(ppc,
				PPBPRI | PCATCH, "ppcdma", 0);

		} while (error == EWOULDBLOCK);

		splx(s);

		if (error) {
#ifdef PPC_DEBUG
			printf("i");
#endif
			/* stop DMA */
			isa_dmadone(
				ppc->ppc_dmaflags, ppc->ppc_dmaddr,
				ppc->ppc_dmacnt, ppc->ppc_dmachan);

			/* no dma, no interrupt, flush the fifo */
			w_ecr(ppc, PPC_ECR_RESET);

			ppc->ppc_dmastat = PPC_DMA_INTERRUPTED;
			goto error;
		}

		/* wait for an empty fifo */
		while (!(r_ecr(ppc) & PPC_FIFO_EMPTY)) {

			for (spin=100; spin; spin--)
				if (r_ecr(ppc) & PPC_FIFO_EMPTY)
					goto fifo_empty;
#ifdef PPC_DEBUG
			printf("Z");
#endif
			error = tsleep(ppc, PPBPRI | PCATCH, "ppcfifo", hz/100);
			if (error != EWOULDBLOCK) {
#ifdef PPC_DEBUG
				printf("I");
#endif
				/* no dma, no interrupt, flush the fifo */
				w_ecr(ppc, PPC_ECR_RESET);

				ppc->ppc_dmastat = PPC_DMA_INTERRUPTED;
				error = EINTR;
				goto error;
			}
		}

fifo_empty:
		/* no dma, no interrupt, flush the fifo */
		w_ecr(ppc, PPC_ECR_RESET);

	    } else
		error = EINVAL;			/* XXX we should FIFO and
						 * interrupts */
	} else
		error = EINVAL;

error:

	/* PDRQ must be kept unasserted until nPDACK is
	 * deasserted for a minimum of 350ns (SMC datasheet)
	 *
	 * Consequence may be a FIFO that never empty
	 */
	DELAY(1);

	w_ecr(ppc, ecr_sav);
	w_ctr(ppc, ctr_sav);

	return (error);
}
Ejemplo n.º 9
0
Archivo: gsc.c Proyecto: npe9/spin
static int
buffer_read(struct gsc_unit *scu)
{
    int stb;
    int res = SUCCESS;
    int chan_bit;
    char *p;
    int sps;
    int delay;

    lprintf("gsc.buffer_read: begin\n");

    if (scu->ctrl_byte == INVALID)
    {
        lprintf("gsc.buffer_read: invalid ctrl_byte\n");
        return EIO;
    }

    sps=splbio();

    outb( scu->ctrl, scu->ctrl_byte | GSC_POWER_ON );
    outb( scu->clrp, 0 );
    stb = inb( scu->stat );

    isa_dmastart(B_READ, scu->sbuf.base, scu->sbuf.size, scu->channel);

    chan_bit = 0x01 << scu->channel;

    for(delay=0; !(inb(DMA1_READY) & 0x01 << scu->channel); delay += LONG)
    {
        if(delay >= scu->btime)
        {
            splx(sps);
            lprintf("gsc.buffer_read: timeout\n");
            res = EWOULDBLOCK;
            break;
        }
        res = tsleep((caddr_t)scu, GSCPRI | PCATCH, "gscread", LONG);
        if ( ( res == 0 ) || ( res == EWOULDBLOCK ) )
            res = SUCCESS;
        else
            break;
    }
    splx(sps);
    isa_dmadone(B_READ, scu->sbuf.base, scu->sbuf.size, scu->channel);
    outb( scu->clrp, 0 );

    if(res != SUCCESS)
    {
        lprintf("gsc.buffer_read: aborted with %d\n", res);
        return res;
    }

    lprintf("gsc.buffer_read: invert buffer\n");
    for(p = scu->sbuf.base + scu->sbuf.size - 1; p >= scu->sbuf.base; p--)
        *p = ~*p;

    scu->sbuf.poi = 0;
    lprintf("gsc.buffer_read: ok\n");
    return SUCCESS;
}
Ejemplo n.º 10
0
static int
fdcintr1(struct fdc_softc *fdc)
{
#define	st0	fdc->sc_status[0]
#define	cyl	fdc->sc_status[1]
	struct fd_softc *fd;
	struct buf *bp;
	bus_space_tag_t iot = fdc->sc_iot;
	bus_space_handle_t ioh = fdc->sc_ioh;
	int read, head, sec, i, nblks;
	struct fd_type *type;
	struct ne7_fd_formb *finfo = NULL;

	KASSERT(mutex_owned(&fdc->sc_mtx));
	if (fdc->sc_state == PROBING) {
#ifdef DEBUG
		printf("fdcintr: got probe interrupt\n");
#endif
		fdc->sc_probe++;
		goto out;
	}

loop:
	/* Is there a drive for the controller to do a transfer with? */
	fd = TAILQ_FIRST(&fdc->sc_drives);
	if (fd == NULL) {
		fdc->sc_state = DEVIDLE;
 		goto out;
	}

	/* Is there a transfer to this drive?  If not, deactivate drive. */
	bp = BUFQ_PEEK(fd->sc_q);
	if (bp == NULL) {
		fd->sc_ops = 0;
		TAILQ_REMOVE(&fdc->sc_drives, fd, sc_drivechain);
		fd->sc_active = 0;
		goto loop;
	}

	if (bp->b_flags & B_FORMAT)
		finfo = (struct ne7_fd_formb *)bp->b_data;

	switch (fdc->sc_state) {
	case DEVIDLE:
		fdc->sc_errors = 0;
		fd->sc_skip = 0;
		fd->sc_bcount = bp->b_bcount;
		fd->sc_blkno = bp->b_blkno / (FDC_BSIZE / DEV_BSIZE);
		callout_stop(&fd->sc_motoroff_ch);
		if ((fd->sc_flags & FD_MOTOR_WAIT) != 0) {
			fdc->sc_state = MOTORWAIT;
			return 1;
		}
		if ((fd->sc_flags & FD_MOTOR) == 0) {
			/* Turn on the motor, being careful about pairing. */
			struct fd_softc *ofd = fdc->sc_fd[fd->sc_drive ^ 1];
			if (ofd && ofd->sc_flags & FD_MOTOR) {
				callout_stop(&ofd->sc_motoroff_ch);
				ofd->sc_flags &= ~(FD_MOTOR | FD_MOTOR_WAIT);
			}
			fd->sc_flags |= FD_MOTOR | FD_MOTOR_WAIT;
			fd_set_motor(fdc, 0);
			fdc->sc_state = MOTORWAIT;
			/* Allow .25s for motor to stabilize. */
			callout_reset(&fd->sc_motoron_ch, hz / 4,
			    fd_motor_on, fd);
			return 1;
		}
		/* Make sure the right drive is selected. */
		fd_set_motor(fdc, 0);

		/* fall through */
	case DOSEEK:
	doseek:
		if (fd->sc_cylin == bp->b_cylinder)
			goto doio;

		out_fdc(iot, ioh, NE7CMD_SPECIFY);/* specify command */
		out_fdc(iot, ioh, fd->sc_type->steprate);
		out_fdc(iot, ioh, 6);		/* XXX head load time == 6ms */

		out_fdc(iot, ioh, NE7CMD_SEEK);	/* seek function */
		out_fdc(iot, ioh, fd->sc_drive); /* drive number */
		out_fdc(iot, ioh, bp->b_cylinder * fd->sc_type->step);

		fd->sc_cylin = -1;
		fdc->sc_state = SEEKWAIT;

		iostat_seek(fd->sc_dk.dk_stats);
		disk_busy(&fd->sc_dk);

		callout_reset(&fdc->sc_timo_ch, 4 * hz, fdctimeout, fdc);
		return 1;

	case DOIO:
	doio:
		type = fd->sc_type;
		if (finfo)
			fd->sc_skip = (char *)&(finfo->fd_formb_cylno(0)) -
				      (char *)finfo;
		sec = fd->sc_blkno % type->seccyl;
		nblks = type->seccyl - sec;
		nblks = min(nblks, fd->sc_bcount / FDC_BSIZE);
		nblks = min(nblks, fdc->sc_maxiosize / FDC_BSIZE);
		fd->sc_nblks = nblks;
		fd->sc_nbytes = finfo ? bp->b_bcount : nblks * FDC_BSIZE;
		head = sec / type->sectrac;
		sec -= head * type->sectrac;
#ifdef DIAGNOSTIC
		{
			int block;
			block = (fd->sc_cylin * type->heads + head)
			    * type->sectrac + sec;
			if (block != fd->sc_blkno) {
				printf("fdcintr: block %d != blkno "
				    "%" PRId64 "\n", block, fd->sc_blkno);
#ifdef DDB
				 Debugger();
#endif
			}
		}
#endif
		read = bp->b_flags & B_READ ? DMAMODE_READ : DMAMODE_WRITE;
		isa_dmastart(fdc->sc_ic, fdc->sc_drq,
		    (char *)bp->b_data + fd->sc_skip, fd->sc_nbytes,
		    NULL, read | DMAMODE_DEMAND, BUS_DMA_NOWAIT);
		bus_space_write_1(iot, fdc->sc_fdctlioh, 0, type->rate);
#ifdef FD_DEBUG
		printf("fdcintr: %s drive %d track %d head %d sec %d nblks %d\n",
			read ? "read" : "write", fd->sc_drive, fd->sc_cylin,
			head, sec, nblks);
#endif
		if (finfo) {
			/* formatting */
			if (out_fdc(iot, ioh, NE7CMD_FORMAT) < 0) {
				fdc->sc_errors = 4;
				fdcretry(fdc);
				goto loop;
			}
			out_fdc(iot, ioh, (head << 2) | fd->sc_drive);
			out_fdc(iot, ioh, finfo->fd_formb_secshift);
			out_fdc(iot, ioh, finfo->fd_formb_nsecs);
			out_fdc(iot, ioh, finfo->fd_formb_gaplen);
			out_fdc(iot, ioh, finfo->fd_formb_fillbyte);
		} else {
			if (read)
				out_fdc(iot, ioh, NE7CMD_READ);	/* READ */
			else
				out_fdc(iot, ioh, NE7CMD_WRITE); /* WRITE */
			out_fdc(iot, ioh, (head << 2) | fd->sc_drive);
			out_fdc(iot, ioh, fd->sc_cylin); /* track */
			out_fdc(iot, ioh, head);
			out_fdc(iot, ioh, sec + 1);	 /* sector +1 */
			out_fdc(iot, ioh, type->secsize);/* sector size */
			out_fdc(iot, ioh, type->sectrac);/* sectors/track */
			out_fdc(iot, ioh, type->gap1);	 /* gap1 size */
			out_fdc(iot, ioh, type->datalen);/* data length */
		}
		fdc->sc_state = IOCOMPLETE;

		disk_busy(&fd->sc_dk);

		/* allow 2 seconds for operation */
		callout_reset(&fdc->sc_timo_ch, 2 * hz, fdctimeout, fdc);
		return 1;				/* will return later */

	case SEEKWAIT:
		callout_stop(&fdc->sc_timo_ch);
		fdc->sc_state = SEEKCOMPLETE;
		/* allow 1/50 second for heads to settle */
		callout_reset(&fdc->sc_intr_ch, hz / 50, fdcintrcb, fdc);
		return 1;

	case SEEKCOMPLETE:
		/* no data on seek */
		disk_unbusy(&fd->sc_dk, 0, 0);

		/* Make sure seek really happened. */
		out_fdc(iot, ioh, NE7CMD_SENSEI);
		if (fdcresult(fdc) != 2 || (st0 & 0xf8) != 0x20 ||
		    cyl != bp->b_cylinder * fd->sc_type->step) {
#ifdef FD_DEBUG
			fdcstatus(fd->sc_dev, 2, "seek failed");
#endif
			fdcretry(fdc);
			goto loop;
		}
		fd->sc_cylin = bp->b_cylinder;
		goto doio;

	case IOTIMEDOUT:
		isa_dmaabort(fdc->sc_ic, fdc->sc_drq);
	case SEEKTIMEDOUT:
	case RECALTIMEDOUT:
	case RESETTIMEDOUT:
		fdcretry(fdc);
		goto loop;

	case IOCOMPLETE: /* IO DONE, post-analyze */
		callout_stop(&fdc->sc_timo_ch);

		disk_unbusy(&fd->sc_dk, (bp->b_bcount - bp->b_resid),
		    (bp->b_flags & B_READ));

		if (fdcresult(fdc) != 7 || (st0 & 0xf8) != 0) {
			isa_dmaabort(fdc->sc_ic, fdc->sc_drq);
#ifdef FD_DEBUG
			fdcstatus(fd->sc_dev, 7, bp->b_flags & B_READ ?
			    "read failed" : "write failed");
			printf("blkno %llu nblks %d\n",
			    (unsigned long long)fd->sc_blkno, fd->sc_nblks);
#endif
			fdcretry(fdc);
			goto loop;
		}
		isa_dmadone(fdc->sc_ic, fdc->sc_drq);
		if (fdc->sc_errors) {
			diskerr(bp, "fd", "soft error (corrected)", LOG_PRINTF,
			    fd->sc_skip / FDC_BSIZE, NULL);
			printf("\n");
			fdc->sc_errors = 0;
		}
		fd->sc_blkno += fd->sc_nblks;
		fd->sc_skip += fd->sc_nbytes;
		fd->sc_bcount -= fd->sc_nbytes;
		if (!finfo && fd->sc_bcount > 0) {
			bp->b_cylinder = fd->sc_blkno / fd->sc_type->seccyl;
			goto doseek;
		}
		fdfinish(fd, bp);
		goto loop;

	case DORESET:
		/* try a reset, keep motor on */
		fd_set_motor(fdc, 1);
		delay(100);
		fd_set_motor(fdc, 0);
		fdc->sc_state = RESETCOMPLETE;
		callout_reset(&fdc->sc_timo_ch, hz / 2, fdctimeout, fdc);
		return 1;			/* will return later */

	case RESETCOMPLETE:
		callout_stop(&fdc->sc_timo_ch);
		/* clear the controller output buffer */
		for (i = 0; i < 4; i++) {
			out_fdc(iot, ioh, NE7CMD_SENSEI);
			(void) fdcresult(fdc);
		}

		/* fall through */
	case DORECAL:
		out_fdc(iot, ioh, NE7CMD_RECAL); /* recalibrate function */
		out_fdc(iot, ioh, fd->sc_drive);
		fdc->sc_state = RECALWAIT;
		callout_reset(&fdc->sc_timo_ch, 5 * hz, fdctimeout, fdc);
		return 1;			/* will return later */

	case RECALWAIT:
		callout_stop(&fdc->sc_timo_ch);
		fdc->sc_state = RECALCOMPLETE;
		/* allow 1/30 second for heads to settle */
		callout_reset(&fdc->sc_intr_ch, hz / 30, fdcintrcb, fdc);
		return 1;			/* will return later */

	case RECALCOMPLETE:
		out_fdc(iot, ioh, NE7CMD_SENSEI);
		if (fdcresult(fdc) != 2 || (st0 & 0xf8) != 0x20 || cyl != 0) {
#ifdef FD_DEBUG
			fdcstatus(fd->sc_dev, 2, "recalibrate failed");
#endif
			fdcretry(fdc);
			goto loop;
		}
		fd->sc_cylin = 0;
		goto doseek;

	case MOTORWAIT:
		if (fd->sc_flags & FD_MOTOR_WAIT)
			return 1;		/* time's not up yet */
		goto doseek;

	default:
		fdcstatus(fd->sc_dev, 0, "stray interrupt");
		return 1;
	}
#undef	st0
#undef	cyl

out:
	cv_signal(&fdc->sc_cv);
	return 1;
}
Ejemplo n.º 11
0
Archivo: cec.c Proyecto: MarginC/kame
void
cecxfer(void *v, int slave, int sec, void *buf, int count, int dir, int timo)
{
	struct cec_softc *sc = v;
	bus_space_tag_t iot = sc->sc_iot;
	bus_space_handle_t ioh = sc->sc_ioh;

	DPRINTF(DBG_FOLLOW,
	    ("cecxfer: slave=%d sec=%d buf=%p count=%d dir=%x timo=%d\n",
	    slave, sec, buf, count, dir, timo));

	sc->sc_flags |= CECF_IO;
	if (dir == GPIB_READ)
		sc->sc_flags |= CECF_READ;
	if (timo) {
		sc->sc_flags |= CECF_TIMO;
		callout_reset(&sc->sc_timeout_ch, 5*hz, cectimeout, sc);
	}

	if (sc->sc_flags & CECF_READ) {
		DPRINTF(DBG_FOLLOW, ("cecxfer: DMA read request\n"));
		if ((sc->sc_flags & CECF_USEDMA) != 0) {
			isa_dmastart(sc->sc_ic, sc->sc_drq, buf, count, NULL,
			    DMAMODE_READ | DMAMODE_DEMAND, BUS_DMA_NOWAIT);
			bus_space_write_1(iot, ioh, NEC7210_IMR2, IMR2_DMAI);
			bus_space_write_1(iot, ioh, NEC7210_IMR1, IMR1_END);
			// XXX (void) cecrecv(sc, slave, sec, NULL, 0);
			(void) gpibrecv(&cec_ic, slave, sec, NULL, 0);
		} else {
			/* XXX this doesn't work */
			DPRINTF(DBG_FOLLOW, ("cecxfer: polling instead\n"));
			bus_space_write_1(iot, ioh, NEC7210_IMR1, IMR1_END);
			// XXX (void) cecrecv(sc, slave, sec, buf, count);
			(void) gpibrecv(&cec_ic, slave, sec, buf, count);
			bus_space_write_1(iot, ioh, NEC7210_IMR2, IMR2_CO);
		}
	} else {
		DPRINTF(DBG_FOLLOW, ("cecxfer: DMA write request\n"));
		bus_space_write_1(iot, ioh, NEC7210_IMR2, 0);
		if (count < cecdmathresh ||
		    (sc->sc_flags & CECF_USEDMA) == 0) {
			DPRINTF(DBG_FOLLOW, ("cecxfer: polling instead\n"));
			// XXX (void) cecsend(sc, slave, sec, buf, count);
			(void) gpibsend(&cec_ic, slave, sec, buf, count);
			bus_space_write_1(iot, ioh, NEC7210_IMR2, IMR2_CO);
			return;
		}
		/* we send the last byte with EOI set */
		isa_dmastart(sc->sc_ic, sc->sc_drq, buf, count-1, NULL,
		    DMAMODE_WRITE | DMAMODE_DEMAND, BUS_DMA_NOWAIT);
		bus_space_write_1(iot, ioh, NEC7210_IMR2, IMR2_DMAO);
		// XXX (void) cecsend(sc, slave, sec, NULL, 0);
		(void) gpibsend(&cec_ic, slave, sec, NULL, 0);
		while (!isa_dmafinished(sc->sc_ic, sc->sc_drq))
			DELAY(1);
		(void) cecwait(sc, ISR1_DO, 0);
		bus_space_write_1(iot, ioh, NEC7210_AUXMR, AUXCMD_SEOI);
		bus_space_write_1(iot, ioh, NEC7210_CDOR, *(char *)buf+count);
		/* generate interrupt */
		bus_space_write_1(iot, ioh, NEC7210_IMR1, IMR1_DO);
	}
}