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