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