Ejemplo n.º 1
0
/*
 * isa_dmastart(): program 8237 DMA controller channel, avoid page alignment
 * problems by using a bounce buffer.
 */
void
isa_dmastart(int flags, caddr_t addr, u_int nbytes, int chan)
{
	vm_paddr_t phys;
	int waport;
	caddr_t newaddr;
	int dma_range_checked;

	dma_range_checked = isa_dmarangecheck(addr, nbytes, chan);

#ifdef DIAGNOSTIC
	if (chan & ~VALID_DMA_MASK)
		panic("isa_dmastart: channel out of range");

	if ((chan < 4 && nbytes > (1<<16))
	    || (chan >= 4 && (nbytes > (1<<17) || (uintptr_t)addr & 1)))
		panic("isa_dmastart: impossible request");

	mtx_lock(&isa_dma_lock);
	if ((dma_inuse & (1 << chan)) == 0)
		printf("isa_dmastart: channel %d not acquired\n", chan);
#else
	mtx_lock(&isa_dma_lock);
#endif

#if 0
	/*
	 * XXX This should be checked, but drivers like ad1848 only call
	 * isa_dmastart() once because they use Auto DMA mode.  If we
	 * leave this in, drivers that do this will print this continuously.
	 */
	if (dma_busy & (1 << chan))
		printf("isa_dmastart: channel %d busy\n", chan);
#endif

	dma_busy |= (1 << chan);

	if (dma_range_checked) {
		if (dma_bouncebuf[chan] == NULL
		    || dma_bouncebufsize[chan] < nbytes)
			panic("isa_dmastart: bad bounce buffer"); 
		dma_bounced |= (1 << chan);
		newaddr = dma_bouncebuf[chan];

		/* copy bounce buffer on write */
		if (!(flags & ISADMA_READ))
			bcopy(addr, newaddr, nbytes);
		addr = newaddr;
	}

	/* translate to physical */
	phys = pmap_extract(kernel_pmap, (vm_offset_t)addr);

	if (flags & ISADMA_RAW) {
	    dma_auto_mode |= (1 << chan);
	} else { 
	    dma_auto_mode &= ~(1 << chan);
	}

	if ((chan & 4) == 0) {
		/*
		 * Program one of DMA channels 0..3.  These are
		 * byte mode channels.
		 */
		/* set dma channel mode, and reset address ff */

		/* If ISADMA_RAW flag is set, then use autoinitialise mode */
		if (flags & ISADMA_RAW) {
		  if (flags & ISADMA_READ)
			outb(DMA1_MODE, DMA37MD_AUTO|DMA37MD_WRITE|chan);
		  else
			outb(DMA1_MODE, DMA37MD_AUTO|DMA37MD_READ|chan);
		}
		else
		if (flags & ISADMA_READ)
			outb(DMA1_MODE, DMA37MD_SINGLE|DMA37MD_WRITE|chan);
		else
			outb(DMA1_MODE, DMA37MD_SINGLE|DMA37MD_READ|chan);
		outb(DMA1_FFC, 0);

		/* send start address */
		waport =  DMA1_CHN(chan);
		outb(waport, phys);
		outb(waport, phys>>8);
		outb(dmapageport[chan], phys>>16);

		/* send count */
		outb(waport + 1, --nbytes);
		outb(waport + 1, nbytes>>8);

		/* unmask channel */
		outb(DMA1_SMSK, chan);
	} else {
		/*
		 * Program one of DMA channels 4..7.  These are
		 * word mode channels.
		 */
		/* set dma channel mode, and reset address ff */

		/* If ISADMA_RAW flag is set, then use autoinitialise mode */
		if (flags & ISADMA_RAW) {
Ejemplo n.º 2
0
/*
 * _isa_dmastart(): program 8237 DMA controller channel and set it
 * in motion.
 */
int
_isa_dmastart(struct isa_dma_state *ids, int chan, void *addr, bus_size_t nbytes, struct proc *p, int flags, int busdmaflags)
{
	bus_dmamap_t dmam;
	bus_addr_t dmaaddr;
	int waport;
	int ochan = chan & 3;
	int error;

	if (chan < 0 || chan > 7) {
		printf("%s: bogus drq %d\n", device_xname(ids->ids_dev), chan);
		goto lose;
	}

#ifdef ISADMA_DEBUG
	printf("_isa_dmastart: drq %d, addr %p, nbytes 0x%lx, p %p, "
	    "flags 0x%x, dmaflags 0x%x\n",
	    chan, addr, (u_long)nbytes, p, flags, busdmaflags);
#endif

	if (ISA_DMA_DRQ_ISFREE(ids, chan)) {
		printf("%s: dma start on free channel %d\n",
		    device_xname(ids->ids_dev), chan);
		goto lose;
	}

	if (chan & 4) {
		if (nbytes > (1 << 17) || nbytes & 1 || (u_long)addr & 1) {
			printf("%s: drq %d, nbytes 0x%lx, addr %p\n",
			    device_xname(ids->ids_dev), chan,
			    (unsigned long) nbytes, addr);
			goto lose;
		}
	} else {
		if (nbytes > (1 << 16)) {
			printf("%s: drq %d, nbytes 0x%lx\n",
			    device_xname(ids->ids_dev), chan,
			    (unsigned long) nbytes);
			goto lose;
		}
	}

	dmam = ids->ids_dmamaps[chan];
	if (dmam == NULL)
		panic("_isa_dmastart: no DMA map for chan %d", chan);

	error = bus_dmamap_load(ids->ids_dmat, dmam, addr, nbytes,
	    p, busdmaflags |
	    ((flags & DMAMODE_READ) ? BUS_DMA_READ : BUS_DMA_WRITE));
	if (error)
		return (error);

#ifdef ISADMA_DEBUG
	__asm(".globl isa_dmastart_afterload ; isa_dmastart_afterload:");
#endif

	if (flags & DMAMODE_READ) {
		bus_dmamap_sync(ids->ids_dmat, dmam, 0, dmam->dm_mapsize,
		    BUS_DMASYNC_PREREAD);
		ids->ids_dmareads |= (1 << chan);
	} else {
		bus_dmamap_sync(ids->ids_dmat, dmam, 0, dmam->dm_mapsize,
		    BUS_DMASYNC_PREWRITE);
		ids->ids_dmareads &= ~(1 << chan);
	}

	dmaaddr = dmam->dm_segs[0].ds_addr;

#ifdef ISADMA_DEBUG
	printf("     dmaaddr %#" PRIxPADDR "\n", dmaaddr);

	__asm(".globl isa_dmastart_aftersync ; isa_dmastart_aftersync:");
#endif

	ids->ids_dmalength[chan] = nbytes;

	_isa_dmamask(ids, chan);
	ids->ids_dmafinished &= ~(1 << chan);

	if ((chan & 4) == 0) {
		/* set dma channel mode */
		bus_space_write_1(ids->ids_bst, ids->ids_dma1h, DMA1_MODE,
		    ochan | dmamode[flags]);

		/* send start address */
		waport = DMA1_CHN(ochan);
		bus_space_write_1(ids->ids_bst, ids->ids_dmapgh,
		    dmapageport[0][ochan], (dmaaddr >> 16) & 0xff);
		bus_space_write_1(ids->ids_bst, ids->ids_dma1h, waport,
		    dmaaddr & 0xff);
		bus_space_write_1(ids->ids_bst, ids->ids_dma1h, waport,
		    (dmaaddr >> 8) & 0xff);

		/* send count */
		bus_space_write_1(ids->ids_bst, ids->ids_dma1h, waport + 1,
		    (--nbytes) & 0xff);
		bus_space_write_1(ids->ids_bst, ids->ids_dma1h, waport + 1,
		    (nbytes >> 8) & 0xff);
	} else {