Internally, all the mapping routines deal with a DMA map structure. The values stored in members of the structure are subject to change from release to release. Therefore, when your driver manipulates the DMA maps, it must use the following routines only. Your driver must not try to access the structure members directly.
Note: When using DMA maps, be sure that the source or destination address begins on a 32-bit word boundary.
Caution: Once you free a DMA map, it is gone and you can no longer use it. Free it only after the DMA operation has been successfully aborted.
#define MAXTRANSFER 4 /* maximum transfer size in pages */ /* pointer to device registers */ volatile struct vdk_device*vdk_device; dmamap_t vdk_map; /* pntr to DMA map */ struct buf *vdk_curbp; /* current buffer */ caddr_t vdk_curaddr; /* current address to transfer */ int vdk_curcount; static int vdk_vmeadap /* computed during edtinit */ vdkopen(dev, flag, otyp, crp) dev_t *dev; int flag, otyp; credit *crp; { ... vdk_map = dma_mapalloc(DMA_A24VME, vdk_vmeadap, MAXTRANSFER, 0); ... } vdkclose(dev, flag, otyp, crp) dev_t dev; int flag, otyp; { ... dma_mapfree(vdk_map); ... } vdkstrategy(bp) struct buf *bp { ... /* Save structure pointer for the interrupt routine, vdkintr */ vdk_curbp = bp; /* Set up the mapping registers */ bp->b_resid = bp->b_bcount; vdk_curaddr = bp->b_dmaaddr; vdk_curcount = dma_map (vdk_map, vdk_curaddr, bp->b_resid); /* Tell the device starting bus virtual address and count */ vdk_device->startaddr = dma_mapaddr(vdk_map, vdk_curaddr); vdk_device->count = count; if (bp->b_flags & B_READ) == 0) vdk_device->direction = VDK_WRITE; else vdk_device->direction = VDK_READ; vdk_device->command = VDK_GO; /* Set up for next transfer */ vdk_curaddr += count; ... } vdkintr(unit) int unit; { int count; register struct buf *bp = vdk_curbp; ... if(error) { bp->b_flags |= B_ERROR; iodone(bp); return( ); } /*On successful transfer of last chunk, continue if necessary.*/ bp->resid -= vdk_curcount; if (bp->b_resid > 0) { count = dma_map(vdk_map, vdk_curaddr, bp->b_resid); vdk_device->startaddr = dma_mapaddr(vdk_map,vdk_curaddr); vdk_device->count = count; if (bp->b_flags & B_READ) == 0) vdk_device->direction = VDK_WRITE; else vdk_device->direction = VDK_READ; vdk_device->command = VDK_GO; vdk_curaddr += count; } else { biodone(bp); } ... }
Note: As with other examples, error checking is omitted, but should not be omitted in real code.