xref: /openbsd/sys/dev/isa/isadma.c (revision 898184e3)
1 /*	$OpenBSD: isadma.c,v 1.31 2008/06/26 05:42:16 ray Exp $	*/
2 /*	$NetBSD: isadma.c,v 1.32 1997/09/05 01:48:33 thorpej Exp $	*/
3 
4 /*-
5  * Copyright (c) 1997 The NetBSD Foundation, Inc.
6  * All rights reserved.
7  *
8  * This code is derived from software contributed to The NetBSD Foundation
9  * by Jason R. Thorpe of the Numerical Aerospace Simulation Facility,
10  * NASA Ames Research Center.
11  *
12  * Redistribution and use in source and binary forms, with or without
13  * modification, are permitted provided that the following conditions
14  * are met:
15  * 1. Redistributions of source code must retain the above copyright
16  *    notice, this list of conditions and the following disclaimer.
17  * 2. Redistributions in binary form must reproduce the above copyright
18  *    notice, this list of conditions and the following disclaimer in the
19  *    documentation and/or other materials provided with the distribution.
20  *
21  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
22  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
23  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
24  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
25  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
26  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
27  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
28  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
29  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
30  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
31  * POSSIBILITY OF SUCH DAMAGE.
32  */
33 
34 /*
35  * Device driver for the ISA on-board DMA controller.
36  */
37 
38 #include <sys/param.h>
39 #include <sys/systm.h>
40 #include <sys/proc.h>
41 #include <sys/device.h>
42 
43 #include <uvm/uvm_extern.h>
44 
45 #include <machine/bus.h>
46 
47 #include <dev/isa/isareg.h>
48 #include <dev/isa/isavar.h>
49 #include <dev/isa/isadmavar.h>
50 #include <dev/isa/isadmareg.h>
51 
52 #ifdef __ISADMA_COMPAT
53 /* XXX ugly, but will go away soon... */
54 struct device *isa_dev;
55 
56 bus_dmamap_t isadma_dmam[8];
57 #endif
58 
59 /* Used by isa_malloc() */
60 #include <sys/malloc.h>
61 struct isa_mem {
62 	struct device *isadev;
63 	int chan;
64 	bus_size_t size;
65 	bus_addr_t addr;
66 	caddr_t kva;
67 	struct isa_mem *next;
68 } *isa_mem_head = 0;
69 
70 /*
71  * High byte of DMA address is stored in this DMAPG register for
72  * the Nth DMA channel.
73  */
74 static int dmapageport[2][4] = {
75 	{0x7, 0x3, 0x1, 0x2},
76 	{0xf, 0xb, 0x9, 0xa}
77 };
78 
79 static u_int8_t dmamode[4] = {
80 	DMA37MD_READ | DMA37MD_SINGLE,
81 	DMA37MD_WRITE | DMA37MD_SINGLE,
82 	DMA37MD_READ | DMA37MD_SINGLE | DMA37MD_LOOP,
83 	DMA37MD_WRITE | DMA37MD_SINGLE | DMA37MD_LOOP
84 };
85 
86 int isadmamatch(struct device *, void *, void *);
87 void isadmaattach(struct device *, struct device *, void *);
88 
89 struct cfattach isadma_ca = {
90 	sizeof(struct device), isadmamatch, isadmaattach
91 };
92 
93 struct cfdriver isadma_cd = {
94 	NULL, "isadma", DV_DULL, 1
95 };
96 
97 int
98 isadmamatch(parent, match, aux)
99 	struct device *parent;
100 	void *match, *aux;
101 {
102 	struct isa_attach_args *ia = aux;
103 
104 	/* Sure we exist */
105 	ia->ia_iosize = 0;
106 	return (1);
107 }
108 
109 void
110 isadmaattach(parent, self, aux)
111 	struct device *parent, *self;
112 	void *aux;
113 {
114 #ifdef __ISADMA_COMPAT
115 	int i, sz;
116 	struct isa_softc *sc = (struct isa_softc *)parent;
117 
118 	/* XXX ugly, but will go away soon... */
119 	isa_dev = parent;
120 
121 	for (i = 0; i < 8; i++) {
122 		sz = (i & 4) ? 1 << 17 : 1 << 16;
123 		if ((bus_dmamap_create(sc->sc_dmat, sz, 1, sz, sz,
124 		    BUS_DMA_24BIT|BUS_DMA_NOWAIT|BUS_DMA_ALLOCNOW,
125 		    &isadma_dmam[i])) != 0)
126 			panic("isadmaattach: can not create DMA map");
127 	}
128 #endif
129 
130 	/* XXX I'd like to map the DMA ports here, see isa.c why not... */
131 
132 	printf("\n");
133 }
134 
135 static inline void isa_dmaunmask(struct isa_softc *, int);
136 static inline void isa_dmamask(struct isa_softc *, int);
137 
138 static inline void
139 isa_dmaunmask(sc, chan)
140 	struct isa_softc *sc;
141 	int chan;
142 {
143 	int ochan = chan & 3;
144 
145 	/* set dma channel mode, and set dma channel mode */
146 	if ((chan & 4) == 0)
147 		bus_space_write_1(sc->sc_iot, sc->sc_dma1h,
148 		    DMA1_SMSK, ochan | DMA37SM_CLEAR);
149 	else
150 		bus_space_write_1(sc->sc_iot, sc->sc_dma2h,
151 		    DMA2_SMSK, ochan | DMA37SM_CLEAR);
152 }
153 
154 static inline void
155 isa_dmamask(sc, chan)
156 	struct isa_softc *sc;
157 	int chan;
158 {
159 	int ochan = chan & 3;
160 
161 	/* set dma channel mode, and set dma channel mode */
162 	if ((chan & 4) == 0) {
163 		bus_space_write_1(sc->sc_iot, sc->sc_dma1h,
164 		    DMA1_SMSK, ochan | DMA37SM_SET);
165 		bus_space_write_1(sc->sc_iot, sc->sc_dma1h,
166 		    DMA1_FFC, 0);
167 	} else {
168 		bus_space_write_1(sc->sc_iot, sc->sc_dma2h,
169 		    DMA2_SMSK, ochan | DMA37SM_SET);
170 		bus_space_write_1(sc->sc_iot, sc->sc_dma2h,
171 		    DMA2_FFC, 0);
172 	}
173 }
174 
175 /*
176  * isa_dmacascade(): program 8237 DMA controller channel to accept
177  * external dma control by a board.
178  */
179 void
180 isa_dmacascade(isadev, chan)
181 	struct device *isadev;
182 	int chan;
183 {
184 	struct isa_softc *sc = (struct isa_softc *)isadev;
185 	int ochan = chan & 3;
186 
187 	if (chan < 0 || chan > 7) {
188 		printf("%s: bogus drq %d\n", sc->sc_dev.dv_xname, chan);
189 		goto lose;
190 	}
191 
192 	if (ISA_DRQ_ISFREE(sc, chan) == 0) {
193 		printf("%s: DRQ %d is not free\n", sc->sc_dev.dv_xname, chan);
194 		goto lose;
195 	}
196 
197 	ISA_DRQ_ALLOC(sc, chan);
198 
199 	/* set dma channel mode, and set dma channel mode */
200 	if ((chan & 4) == 0)
201 		bus_space_write_1(sc->sc_iot, sc->sc_dma1h,
202 		    DMA1_MODE, ochan | DMA37MD_CASCADE);
203 	else
204 		bus_space_write_1(sc->sc_iot, sc->sc_dma2h,
205 		    DMA2_MODE, ochan | DMA37MD_CASCADE);
206 
207 	isa_dmaunmask(sc, chan);
208 	return;
209 
210  lose:
211 	panic("isa_dmacascade");
212 }
213 
214 int
215 isa_dmamap_create(isadev, chan, size, flags)
216 	struct device *isadev;
217 	int chan;
218 	bus_size_t size;
219 	int flags;
220 {
221 	struct isa_softc *sc = (struct isa_softc *)isadev;
222 	bus_size_t maxsize;
223 
224 	if (chan < 0 || chan > 7) {
225 		printf("%s: bogus drq %d\n", sc->sc_dev.dv_xname, chan);
226 		goto lose;
227 	}
228 
229 	if (chan & 4)
230 		maxsize = (1 << 17);
231 	else
232 		maxsize = (1 << 16);
233 
234 	if (size > maxsize)
235 		return (EINVAL);
236 
237 	if (ISA_DRQ_ISFREE(sc, chan) == 0) {
238 		printf("%s: drq %d is not free\n", sc->sc_dev.dv_xname, chan);
239 		goto lose;
240 	}
241 
242 	ISA_DRQ_ALLOC(sc, chan);
243 
244 	return (bus_dmamap_create(sc->sc_dmat, size, 1, size, maxsize,
245 	    flags, &sc->sc_dmamaps[chan]));
246 
247  lose:
248 	panic("isa_dmamap_create");
249 }
250 
251 void
252 isa_dmamap_destroy(isadev, chan)
253 	struct device *isadev;
254 	int chan;
255 {
256 	struct isa_softc *sc = (struct isa_softc *)isadev;
257 
258 	if (chan < 0 || chan > 7) {
259 		printf("%s: bogus drq %d\n", sc->sc_dev.dv_xname, chan);
260 		goto lose;
261 	}
262 
263 	if (ISA_DRQ_ISFREE(sc, chan)) {
264 		printf("%s: drq %d is already free\n",
265 		    sc->sc_dev.dv_xname, chan);
266 		goto lose;
267 	}
268 
269 	ISA_DRQ_FREE(sc, chan);
270 
271 	bus_dmamap_destroy(sc->sc_dmat, sc->sc_dmamaps[chan]);
272 	return;
273 
274  lose:
275 	panic("isa_dmamap_destroy");
276 }
277 
278 /*
279  * isa_dmastart(): program 8237 DMA controller channel and set it
280  * in motion.
281  */
282 int
283 isa_dmastart(isadev, chan, addr, nbytes, p, flags, busdmaflags)
284 	struct device *isadev;
285 	int chan;
286 	void *addr;
287 	bus_size_t nbytes;
288 	struct proc *p;
289 	int flags;
290 	int busdmaflags;
291 {
292 	struct isa_softc *sc = (struct isa_softc *)isadev;
293 	bus_dmamap_t dmam;
294 	bus_addr_t dmaaddr;
295 	int waport;
296 	int ochan = chan & 3;
297 	int error;
298 #ifdef __ISADMA_COMPAT
299 	int compat = busdmaflags & BUS_DMA_BUS1;
300 
301 	busdmaflags &= ~BUS_DMA_BUS1;
302 #endif /* __ISADMA_COMPAT */
303 
304 	if (chan < 0 || chan > 7) {
305 		printf("%s: bogus drq %d\n", sc->sc_dev.dv_xname, chan);
306 		goto lose;
307 	}
308 
309 #ifdef ISADMA_DEBUG
310 	printf("isa_dmastart: drq %d, addr %p, nbytes 0x%lx, p %p, "
311 	    "flags 0x%x, dmaflags 0x%x\n",
312 	    chan, addr, nbytes, p, flags, busdmaflags);
313 #endif
314 
315 	if (chan & 4) {
316 		if (nbytes > (1 << 17) || nbytes & 1 || (u_long)addr & 1) {
317 			printf("%s: drq %d, nbytes 0x%lx, addr %p\n",
318 			    sc->sc_dev.dv_xname, chan, nbytes, addr);
319 			goto lose;
320 		}
321 	} else {
322 		if (nbytes > (1 << 16)) {
323 			printf("%s: drq %d, nbytes 0x%lx\n",
324 			    sc->sc_dev.dv_xname, chan, nbytes);
325 			goto lose;
326 		}
327 	}
328 
329 	dmam = sc->sc_dmamaps[chan];
330 	if (dmam == NULL) {
331 #ifdef __ISADMA_COMPAT
332 		if (compat)
333 			dmam = sc->sc_dmamaps[chan] = isadma_dmam[chan];
334 		else
335 #endif /* __ISADMA_COMPAT */
336 		panic("isa_dmastart: no DMA map for chan %d", chan);
337 	}
338 
339 	error = bus_dmamap_load(sc->sc_dmat, dmam, addr, nbytes, p,
340 	    busdmaflags);
341 	if (error)
342 		return (error);
343 
344 #ifdef ISADMA_DEBUG
345 	__asm(".globl isa_dmastart_afterload ; isa_dmastart_afterload:");
346 #endif
347 
348 	if (flags & DMAMODE_READ) {
349 		bus_dmamap_sync(sc->sc_dmat, dmam, 0, dmam->dm_mapsize,
350 		    BUS_DMASYNC_PREREAD);
351 		sc->sc_dmareads |= (1 << chan);
352 	} else {
353 		bus_dmamap_sync(sc->sc_dmat, dmam, 0, dmam->dm_mapsize,
354 		    BUS_DMASYNC_PREWRITE);
355 		sc->sc_dmareads &= ~(1 << chan);
356 	}
357 
358 	dmaaddr = dmam->dm_segs[0].ds_addr;
359 
360 #ifdef ISADMA_DEBUG
361 	printf("     dmaaddr 0x%lx\n", dmaaddr);
362 
363 	__asm(".globl isa_dmastart_aftersync ; isa_dmastart_aftersync:");
364 #endif
365 
366 	sc->sc_dmalength[chan] = nbytes;
367 
368 	isa_dmamask(sc, chan);
369 	sc->sc_dmafinished &= ~(1 << chan);
370 
371 	if ((chan & 4) == 0) {
372 		/* set dma channel mode */
373 		bus_space_write_1(sc->sc_iot, sc->sc_dma1h, DMA1_MODE,
374 		    ochan | dmamode[flags]);
375 
376 		/* send start address */
377 		waport = DMA1_CHN(ochan);
378 		bus_space_write_1(sc->sc_iot, sc->sc_dmapgh,
379 		    dmapageport[0][ochan], (dmaaddr >> 16) & 0xff);
380 		bus_space_write_1(sc->sc_iot, sc->sc_dma1h, waport,
381 		    dmaaddr & 0xff);
382 		bus_space_write_1(sc->sc_iot, sc->sc_dma1h, waport,
383 		    (dmaaddr >> 8) & 0xff);
384 
385 		/* send count */
386 		bus_space_write_1(sc->sc_iot, sc->sc_dma1h, waport + 1,
387 		    (--nbytes) & 0xff);
388 		bus_space_write_1(sc->sc_iot, sc->sc_dma1h, waport + 1,
389 		    (nbytes >> 8) & 0xff);
390 	} else {
391 		/* set dma channel mode */
392 		bus_space_write_1(sc->sc_iot, sc->sc_dma2h, DMA2_MODE,
393 		    ochan | dmamode[flags]);
394 
395 		/* send start address */
396 		waport = DMA2_CHN(ochan);
397 		bus_space_write_1(sc->sc_iot, sc->sc_dmapgh,
398 		    dmapageport[1][ochan], (dmaaddr >> 16) & 0xff);
399 		dmaaddr >>= 1;
400 		bus_space_write_1(sc->sc_iot, sc->sc_dma2h, waport,
401 		    dmaaddr & 0xff);
402 		bus_space_write_1(sc->sc_iot, sc->sc_dma2h, waport,
403 		    (dmaaddr >> 8) & 0xff);
404 
405 		/* send count */
406 		nbytes >>= 1;
407 		bus_space_write_1(sc->sc_iot, sc->sc_dma2h, waport + 2,
408 		    (--nbytes) & 0xff);
409 		bus_space_write_1(sc->sc_iot, sc->sc_dma2h, waport + 2,
410 		    (nbytes >> 8) & 0xff);
411 	}
412 
413 	isa_dmaunmask(sc, chan);
414 	return (0);
415 
416  lose:
417 	panic("isa_dmastart");
418 }
419 
420 void
421 isa_dmaabort(isadev, chan)
422 	struct device *isadev;
423 	int chan;
424 {
425 	struct isa_softc *sc = (struct isa_softc *)isadev;
426 
427 	if (chan < 0 || chan > 7) {
428 		panic("isa_dmaabort: %s: bogus drq %d", sc->sc_dev.dv_xname,
429 		    chan);
430 	}
431 
432 	isa_dmamask(sc, chan);
433 	bus_dmamap_unload(sc->sc_dmat, sc->sc_dmamaps[chan]);
434 	sc->sc_dmareads &= ~(1 << chan);
435 }
436 
437 bus_size_t
438 isa_dmacount(isadev, chan)
439 	struct device *isadev;
440 	int chan;
441 {
442 	struct isa_softc *sc = (struct isa_softc *)isadev;
443 	int waport;
444 	bus_size_t nbytes;
445 	int ochan = chan & 3;
446 
447 	if (chan < 0 || chan > 7) {
448 		panic("isa_dmacount: %s: bogus drq %d", sc->sc_dev.dv_xname,
449 		    chan);
450 	}
451 
452 	isa_dmamask(sc, chan);
453 
454 	/*
455 	 * We have to shift the byte count by 1.  If we're in auto-initialize
456 	 * mode, the count may have wrapped around to the initial value.  We
457 	 * can't use the TC bit to check for this case, so instead we compare
458 	 * against the original byte count.
459 	 * If we're not in auto-initialize mode, then the count will wrap to
460 	 * -1, so we also handle that case.
461 	 */
462 	if ((chan & 4) == 0) {
463 		waport = DMA1_CHN(ochan);
464 		nbytes = bus_space_read_1(sc->sc_iot, sc->sc_dma1h,
465 		    waport + 1) + 1;
466 		nbytes += bus_space_read_1(sc->sc_iot, sc->sc_dma1h,
467 		    waport + 1) << 8;
468 		nbytes &= 0xffff;
469 	} else {
470 		waport = DMA2_CHN(ochan);
471 		nbytes = bus_space_read_1(sc->sc_iot, sc->sc_dma2h,
472 		    waport + 2) + 1;
473 		nbytes += bus_space_read_1(sc->sc_iot, sc->sc_dma2h,
474 		    waport + 2) << 8;
475 		nbytes <<= 1;
476 		nbytes &= 0x1ffff;
477 	}
478 
479 	if (nbytes == sc->sc_dmalength[chan])
480 		nbytes = 0;
481 
482 	isa_dmaunmask(sc, chan);
483 	return (nbytes);
484 }
485 
486 int
487 isa_dmafinished(isadev, chan)
488 	struct device *isadev;
489 	int chan;
490 {
491 	struct isa_softc *sc = (struct isa_softc *)isadev;
492 
493 	if (chan < 0 || chan > 7) {
494 		panic("isa_dmafinished: %s: bogus drq %d", sc->sc_dev.dv_xname,
495 		    chan);
496 	}
497 
498 	/* check that the terminal count was reached */
499 	if ((chan & 4) == 0)
500 		sc->sc_dmafinished |= bus_space_read_1(sc->sc_iot,
501 		    sc->sc_dma1h, DMA1_SR) & 0x0f;
502 	else
503 		sc->sc_dmafinished |= (bus_space_read_1(sc->sc_iot,
504 		    sc->sc_dma2h, DMA2_SR) & 0x0f) << 4;
505 
506 	return ((sc->sc_dmafinished & (1 << chan)) != 0);
507 }
508 
509 void
510 isa_dmadone(isadev, chan)
511 	struct device *isadev;
512 	int chan;
513 {
514 	struct isa_softc *sc = (struct isa_softc *)isadev;
515 	bus_dmamap_t dmam;
516 
517 	if (chan < 0 || chan > 7) {
518 		panic("isa_dmadone: %s: bogus drq %d", sc->sc_dev.dv_xname,
519 		    chan);
520 	}
521 
522 	dmam = sc->sc_dmamaps[chan];
523 
524 	isa_dmamask(sc, chan);
525 
526 	if (isa_dmafinished(isadev, chan) == 0)
527 		printf("%s: isa_dmadone: channel %d not finished\n",
528 		    sc->sc_dev.dv_xname, chan);
529 
530 	bus_dmamap_sync(sc->sc_dmat, dmam, 0, dmam->dm_mapsize,
531 	    (sc->sc_dmareads & (1 << chan)) ? BUS_DMASYNC_POSTREAD :
532 	    BUS_DMASYNC_POSTWRITE);
533 
534 	bus_dmamap_unload(sc->sc_dmat, dmam);
535 	sc->sc_dmareads &= ~(1 << chan);
536 }
537 
538 int
539 isa_dmamem_alloc(isadev, chan, size, addrp, flags)
540 	struct device *isadev;
541 	int chan;
542 	bus_size_t size;
543 	bus_addr_t *addrp;
544 	int flags;
545 {
546 	struct isa_softc *sc = (struct isa_softc *)isadev;
547 	bus_dma_segment_t seg;
548 	int error, boundary, rsegs;
549 
550 	if (chan < 0 || chan > 7) {
551 		panic("isa_dmamem_alloc: %s: bogus drq %d",
552 		    sc->sc_dev.dv_xname, chan);
553 	}
554 
555 	boundary = (chan & 4) ? (1 << 17) : (1 << 16);
556 
557 	size = round_page(size);
558 
559 	error = bus_dmamem_alloc(sc->sc_dmat, size, NBPG, boundary,
560 	    &seg, 1, &rsegs, flags);
561 	if (error)
562 		return (error);
563 
564 	*addrp = seg.ds_addr;
565 	return (0);
566 }
567 
568 void
569 isa_dmamem_free(isadev, chan, addr, size)
570 	struct device *isadev;
571 	int chan;
572 	bus_addr_t addr;
573 	bus_size_t size;
574 {
575 	struct isa_softc *sc = (struct isa_softc *)isadev;
576 	bus_dma_segment_t seg;
577 
578 	if (chan < 0 || chan > 7) {
579 		panic("isa_dmamem_free: %s: bogus drq %d",
580 		    sc->sc_dev.dv_xname, chan);
581 	}
582 
583 	seg.ds_addr = addr;
584 	seg.ds_len = size;
585 
586 	bus_dmamem_free(sc->sc_dmat, &seg, 1);
587 }
588 
589 int
590 isa_dmamem_map(isadev, chan, addr, size, kvap, flags)
591 	struct device *isadev;
592 	int chan;
593 	bus_addr_t addr;
594 	bus_size_t size;
595 	caddr_t *kvap;
596 	int flags;
597 {
598 	struct isa_softc *sc = (struct isa_softc *)isadev;
599 	bus_dma_segment_t seg;
600 
601 	if (chan < 0 || chan > 7) {
602 		panic("isa_dmamem_map: %s: bogus drq %d", sc->sc_dev.dv_xname,
603 		    chan);
604 	}
605 
606 	seg.ds_addr = addr;
607 	seg.ds_len = size;
608 
609 	return (bus_dmamem_map(sc->sc_dmat, &seg, 1, size, kvap, flags));
610 }
611 
612 void
613 isa_dmamem_unmap(isadev, chan, kva, size)
614 	struct device *isadev;
615 	int chan;
616 	caddr_t kva;
617 	size_t size;
618 {
619 	struct isa_softc *sc = (struct isa_softc *)isadev;
620 
621 	if (chan < 0 || chan > 7) {
622 		panic("isa_dmamem_unmap: %s: bogus drq %d",
623 		    sc->sc_dev.dv_xname, chan);
624 	}
625 
626 	bus_dmamem_unmap(sc->sc_dmat, kva, size);
627 }
628 
629 int
630 isa_dmamem_mmap(isadev, chan, addr, size, off, prot, flags)
631 	struct device *isadev;
632 	int chan;
633 	bus_addr_t addr;
634 	bus_size_t size;
635 	int off, prot, flags;
636 {
637 	struct isa_softc *sc = (struct isa_softc *)isadev;
638 	bus_dma_segment_t seg;
639 
640 	if (chan < 0 || chan > 7) {
641 		panic("isa_dmamem_mmap: %s: bogus drq %d", sc->sc_dev.dv_xname,
642 		    chan);
643 	}
644 
645 	if (off < 0)
646 		return (-1);
647 
648 	seg.ds_addr = addr;
649 	seg.ds_len = size;
650 
651 	return (bus_dmamem_mmap(sc->sc_dmat, &seg, 1, off, prot, flags));
652 }
653 
654 int
655 isa_drq_isfree(isadev, chan)
656 	struct device *isadev;
657 	int chan;
658 {
659 	struct isa_softc *sc = (struct isa_softc *)isadev;
660 	if (chan < 0 || chan > 7) {
661 		panic("isa_drq_isfree: %s: bogus drq %d", sc->sc_dev.dv_xname,
662 		    chan);
663 	}
664 	return ISA_DRQ_ISFREE(sc, chan);
665 }
666 
667 void *
668 isa_malloc(isadev, chan, size, pool, flags)
669 	struct device *isadev;
670 	int chan;
671 	size_t size;
672 	int pool;
673 	int flags;
674 {
675 	bus_addr_t addr;
676 	caddr_t kva;
677 	int bflags;
678 	struct isa_mem *m;
679 
680 	bflags = flags & M_NOWAIT ? BUS_DMA_NOWAIT : BUS_DMA_WAITOK;
681 
682 	if (isa_dmamem_alloc(isadev, chan, size, &addr, bflags))
683 		return 0;
684 	if (isa_dmamem_map(isadev, chan, addr, size, &kva, bflags)) {
685 		isa_dmamem_free(isadev, chan, addr, size);
686 		return 0;
687 	}
688 	m = malloc(sizeof(*m), pool, flags);
689 	if (m == 0) {
690 		isa_dmamem_unmap(isadev, chan, kva, size);
691 		isa_dmamem_free(isadev, chan, addr, size);
692 		return 0;
693 	}
694 	m->isadev = isadev;
695 	m->chan = chan;
696 	m->size = size;
697 	m->addr = addr;
698 	m->kva = kva;
699 	m->next = isa_mem_head;
700 	isa_mem_head = m;
701 	return (void *)kva;
702 }
703 
704 void
705 isa_free(addr, pool)
706 	void *addr;
707 	int pool;
708 {
709 	struct isa_mem **mp, *m;
710 	caddr_t kva = (caddr_t)addr;
711 
712 	for(mp = &isa_mem_head; *mp && (*mp)->kva != kva; mp = &(*mp)->next)
713 		;
714 	m = *mp;
715 	if (!m) {
716 		printf("isa_free: freeing unallocated memory\n");
717 		return;
718 	}
719 	*mp = m->next;
720 	isa_dmamem_unmap(m->isadev, m->chan, kva, m->size);
721 	isa_dmamem_free(m->isadev, m->chan, m->addr, m->size);
722 	free(m, pool);
723 }
724 
725 paddr_t
726 isa_mappage(mem, off, prot)
727 	void *mem;
728 	off_t off;
729 	int prot;
730 {
731 	struct isa_mem *m;
732 
733 	for(m = isa_mem_head; m && m->kva != (caddr_t)mem; m = m->next)
734 		;
735 	if (!m) {
736 		printf("isa_mappage: mapping unallocated memory\n");
737 		return -1;
738 	}
739 	return (isa_dmamem_mmap(m->isadev, m->chan, m->addr, m->size, off,
740 	    prot, BUS_DMA_WAITOK));
741 }
742