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