1 /* $OpenBSD: bba.c,v 1.5 2015/05/11 06:46:22 ratchov Exp $ */ 2 /* $NetBSD: bba.c,v 1.38 2011/06/04 01:27:57 tsutsui Exp $ */ 3 /* 4 * Copyright (c) 2011 Miodrag Vallat. 5 * 6 * Permission to use, copy, modify, and distribute this software for any 7 * purpose with or without fee is hereby granted, provided that the above 8 * copyright notice and this permission notice appear in all copies. 9 * 10 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 11 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 12 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 13 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 14 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 15 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 16 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 17 */ 18 /* 19 * Copyright (c) 2000 The NetBSD Foundation, Inc. 20 * All rights reserved. 21 * 22 * Redistribution and use in source and binary forms, with or without 23 * modification, are permitted provided that the following conditions 24 * are met: 25 * 1. Redistributions of source code must retain the above copyright 26 * notice, this list of conditions and the following disclaimer. 27 * 2. Redistributions in binary form must reproduce the above copyright 28 * notice, this list of conditions and the following disclaimer in the 29 * documentation and/or other materials provided with the distribution. 30 * 31 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 32 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 33 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 34 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 35 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 36 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 37 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 38 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 39 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 40 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 41 * POSSIBILITY OF SUCH DAMAGE. 42 */ 43 44 /* maxine/alpha baseboard audio (bba) */ 45 46 #include <sys/param.h> 47 #include <sys/systm.h> 48 #include <sys/kernel.h> 49 #include <sys/device.h> 50 #include <sys/malloc.h> 51 52 #include <machine/autoconf.h> 53 #include <machine/bus.h> 54 #include <machine/cpu.h> 55 56 #include <sys/audioio.h> 57 #include <dev/audio_if.h> 58 59 #include <dev/ic/am7930reg.h> 60 #include <dev/ic/am7930var.h> 61 62 #include <dev/tc/tcvar.h> 63 #include <dev/tc/ioasicreg.h> 64 #include <dev/tc/ioasicvar.h> 65 66 #ifdef AUDIO_DEBUG 67 #define DPRINTF(x) if (am7930debug) printf x 68 #else 69 #define DPRINTF(x) 70 #endif /* AUDIO_DEBUG */ 71 72 #define BBA_MAX_DMA_SEGMENTS 16 73 #define BBA_DMABUF_SIZE (BBA_MAX_DMA_SEGMENTS*IOASIC_DMA_BLOCKSIZE) 74 #define BBA_DMABUF_ALIGN IOASIC_DMA_BLOCKSIZE 75 #define BBA_DMABUF_BOUNDARY 0 76 77 struct bba_mem { 78 struct bba_mem *next; 79 bus_addr_t addr; 80 bus_size_t size; 81 void *kva; 82 }; 83 84 struct bba_dma_state { 85 bus_dmamap_t dmam; /* DMA map */ 86 size_t size; 87 int active; 88 int curseg; /* current segment in DMA buffer */ 89 void (*intr)(void *); /* higher-level audio handler */ 90 void *intr_arg; 91 }; 92 93 struct bba_softc { 94 struct am7930_softc sc_am7930; /* glue to MI code */ 95 96 bus_space_tag_t sc_bst; /* IOASIC bus tag/handle */ 97 bus_space_handle_t sc_bsh; 98 bus_dma_tag_t sc_dmat; 99 bus_space_handle_t sc_codec_bsh; /* codec bus space handle */ 100 101 struct bba_mem *sc_mem_head; /* list of buffers */ 102 103 struct bba_dma_state sc_tx_dma_state; 104 struct bba_dma_state sc_rx_dma_state; 105 }; 106 107 int bba_match(struct device *, void *, void *); 108 void bba_attach(struct device *, struct device *, void *); 109 110 struct cfdriver bba_cd = { 111 NULL, "bba", DV_DULL 112 }; 113 114 const struct cfattach bba_ca = { 115 sizeof(struct bba_softc), bba_match, bba_attach 116 }; 117 118 /* 119 * Define our interface into the am7930 MI driver. 120 */ 121 122 uint8_t bba_codec_iread(struct am7930_softc *, int); 123 uint16_t bba_codec_iread16(struct am7930_softc *, int); 124 void bba_codec_iwrite(struct am7930_softc *, int, uint8_t); 125 void bba_codec_iwrite16(struct am7930_softc *, int, uint16_t); 126 void bba_onopen(struct am7930_softc *); 127 void bba_onclose(struct am7930_softc *); 128 129 struct am7930_glue bba_glue = { 130 bba_codec_iread, 131 bba_codec_iwrite, 132 bba_codec_iread16, 133 bba_codec_iwrite16, 134 bba_onopen, 135 bba_onclose, 136 24 137 }; 138 139 /* 140 * Define our interface to the higher level audio driver. 141 */ 142 143 int bba_round_blocksize(void *, int); 144 int bba_halt_output(void *); 145 int bba_halt_input(void *); 146 int bba_getdev(void *, struct audio_device *); 147 void *bba_allocm(void *, int, size_t, int, int); 148 void bba_freem(void *, void *, int); 149 size_t bba_round_buffersize(void *, int, size_t); 150 int bba_get_props(void *); 151 paddr_t bba_mappage(void *, void *, off_t, int); 152 int bba_trigger_output(void *, void *, void *, int, 153 void (*)(void *), void *, struct audio_params *); 154 int bba_trigger_input(void *, void *, void *, int, 155 void (*)(void *), void *, struct audio_params *); 156 157 struct audio_hw_if bba_hw_if = { 158 am7930_open, 159 am7930_close, 160 NULL, 161 am7930_query_encoding, 162 am7930_set_params, 163 bba_round_blocksize, /* md */ 164 am7930_commit_settings, 165 NULL, 166 NULL, 167 NULL, 168 NULL, 169 bba_halt_output, /* md */ 170 bba_halt_input, /* md */ 171 NULL, 172 bba_getdev, 173 NULL, 174 am7930_set_port, 175 am7930_get_port, 176 am7930_query_devinfo, 177 bba_allocm, /* md */ 178 bba_freem, /* md */ 179 bba_round_buffersize, /* md */ 180 bba_mappage, 181 bba_get_props, 182 bba_trigger_output, /* md */ 183 bba_trigger_input, /* md */ 184 NULL 185 }; 186 187 static struct audio_device bba_device = { 188 "am7930", 189 "x", 190 "bba" 191 }; 192 193 int bba_intr(void *); 194 void bba_reset(struct bba_softc *, int); 195 void bba_codec_dwrite(struct am7930_softc *, int, uint8_t); 196 uint8_t bba_codec_dread(struct am7930_softc *, int); 197 198 int 199 bba_match(struct device *parent, void *vcf, void *aux) 200 { 201 struct ioasicdev_attach_args *ia = aux; 202 203 if (strcmp(ia->iada_modname, "isdn") != 0 && 204 strcmp(ia->iada_modname, "AMD79c30") != 0) 205 return 0; 206 207 return 1; 208 } 209 210 void 211 bba_attach(struct device *parent, struct device *self, void *aux) 212 { 213 struct ioasicdev_attach_args *ia = aux; 214 struct bba_softc *sc = (struct bba_softc *)self; 215 struct ioasic_softc *iosc = (struct ioasic_softc *)parent; 216 217 sc->sc_bst = iosc->sc_bst; 218 sc->sc_bsh = iosc->sc_bsh; 219 sc->sc_dmat = iosc->sc_dmat; 220 221 /* get the bus space handle for codec */ 222 if (bus_space_subregion(sc->sc_bst, sc->sc_bsh, 223 ia->iada_offset, 0, &sc->sc_codec_bsh)) { 224 printf(": unable to map device\n"); 225 return; 226 } 227 228 printf("\n"); 229 230 bba_reset(sc,1); 231 232 /* 233 * Set up glue for MI code early; we use some of it here. 234 */ 235 sc->sc_am7930.sc_glue = &bba_glue; 236 237 /* 238 * MI initialisation. We will be doing DMA. 239 */ 240 am7930_init(&sc->sc_am7930, AUDIOAMD_DMA_MODE); 241 242 ioasic_intr_establish(parent, ia->iada_cookie, IPL_AUDIO, 243 bba_intr, sc, self->dv_xname); 244 245 audio_attach_mi(&bba_hw_if, sc, self); 246 } 247 248 void 249 bba_onopen(struct am7930_softc *sc) 250 { 251 } 252 253 void 254 bba_onclose(struct am7930_softc *sc) 255 { 256 } 257 258 void 259 bba_reset(struct bba_softc *sc, int reset) 260 { 261 uint32_t ssr; 262 263 /* disable any DMA and reset the codec */ 264 ssr = bus_space_read_4(sc->sc_bst, sc->sc_bsh, IOASIC_CSR); 265 ssr &= ~(IOASIC_CSR_DMAEN_ISDN_T | IOASIC_CSR_DMAEN_ISDN_R); 266 if (reset) 267 ssr &= ~IOASIC_CSR_ISDN_ENABLE; 268 bus_space_write_4(sc->sc_bst, sc->sc_bsh, IOASIC_CSR, ssr); 269 DELAY(10); /* 400ns required for codec to reset */ 270 271 /* initialise DMA pointers */ 272 bus_space_write_4(sc->sc_bst, sc->sc_bsh, IOASIC_ISDN_X_DMAPTR, 0); 273 bus_space_write_4(sc->sc_bst, sc->sc_bsh, IOASIC_ISDN_X_NEXTPTR, 0); 274 bus_space_write_4(sc->sc_bst, sc->sc_bsh, IOASIC_ISDN_R_DMAPTR, 0); 275 bus_space_write_4(sc->sc_bst, sc->sc_bsh, IOASIC_ISDN_R_NEXTPTR, 0); 276 277 /* take out of reset state */ 278 if (reset) { 279 ssr |= IOASIC_CSR_ISDN_ENABLE; 280 bus_space_write_4(sc->sc_bst, sc->sc_bsh, IOASIC_CSR, ssr); 281 } 282 283 } 284 285 void * 286 bba_allocm(void *v, int direction, size_t size, int mtype, int flags) 287 { 288 struct bba_softc *sc = v; 289 bus_dma_segment_t seg; 290 int rseg; 291 caddr_t kva; 292 struct bba_mem *m; 293 int w; 294 int state; 295 296 DPRINTF(("bba_allocm: size = %zu\n", size)); 297 state = 0; 298 w = (flags & M_NOWAIT) ? BUS_DMA_NOWAIT : BUS_DMA_WAITOK; 299 300 if (bus_dmamem_alloc(sc->sc_dmat, size, BBA_DMABUF_ALIGN, 301 BBA_DMABUF_BOUNDARY, &seg, 1, &rseg, w)) { 302 printf("%s: can't allocate DMA buffer\n", 303 sc->sc_am7930.sc_dev.dv_xname); 304 goto bad; 305 } 306 state |= 1; 307 308 if (bus_dmamem_map(sc->sc_dmat, &seg, rseg, size, 309 &kva, w | BUS_DMA_COHERENT)) { 310 printf("%s: can't map DMA buffer\n", 311 sc->sc_am7930.sc_dev.dv_xname); 312 goto bad; 313 } 314 state |= 2; 315 316 m = malloc(sizeof(struct bba_mem), mtype, flags | M_CANFAIL); 317 if (m == NULL) 318 goto bad; 319 m->addr = seg.ds_addr; 320 m->size = seg.ds_len; 321 m->kva = kva; 322 m->next = sc->sc_mem_head; 323 sc->sc_mem_head = m; 324 325 return (void *)kva; 326 327 bad: 328 if (state & 2) 329 bus_dmamem_unmap(sc->sc_dmat, kva, size); 330 if (state & 1) 331 bus_dmamem_free(sc->sc_dmat, &seg, 1); 332 return NULL; 333 } 334 335 void 336 bba_freem(void *v, void *ptr, int mtype) 337 { 338 struct bba_softc *sc = v; 339 struct bba_mem **mp, *m; 340 bus_dma_segment_t seg; 341 void *kva; 342 343 kva = (void *)ptr; 344 for (mp = &sc->sc_mem_head; *mp && (*mp)->kva != kva; mp = &(*mp)->next) 345 continue; 346 m = *mp; 347 if (m == NULL) { 348 printf("bba_freem: freeing unallocated memory\n"); 349 return; 350 } 351 *mp = m->next; 352 bus_dmamem_unmap(sc->sc_dmat, kva, m->size); 353 354 seg.ds_addr = m->addr; 355 seg.ds_len = m->size; 356 bus_dmamem_free(sc->sc_dmat, &seg, 1); 357 free(m, mtype, 0); 358 } 359 360 size_t 361 bba_round_buffersize(void *v, int direction, size_t size) 362 { 363 364 DPRINTF(("bba_round_buffersize: size=%zu\n", size)); 365 return size > BBA_DMABUF_SIZE ? BBA_DMABUF_SIZE : 366 roundup(size, IOASIC_DMA_BLOCKSIZE); 367 } 368 369 int 370 bba_halt_output(void *v) 371 { 372 struct bba_softc *sc = v; 373 struct bba_dma_state *d; 374 uint32_t ssr; 375 376 mtx_enter(&audio_lock); 377 d = &sc->sc_tx_dma_state; 378 /* disable any DMA */ 379 ssr = bus_space_read_4(sc->sc_bst, sc->sc_bsh, IOASIC_CSR); 380 ssr &= ~IOASIC_CSR_DMAEN_ISDN_T; 381 bus_space_write_4(sc->sc_bst, sc->sc_bsh, IOASIC_CSR, ssr); 382 bus_space_write_4(sc->sc_bst, sc->sc_bsh, IOASIC_ISDN_X_DMAPTR, 0); 383 bus_space_write_4(sc->sc_bst, sc->sc_bsh, IOASIC_ISDN_X_NEXTPTR, 0); 384 mtx_leave(&audio_lock); 385 386 if (d->active) { 387 bus_dmamap_sync(sc->sc_dmat, d->dmam, 0, d->size, 388 BUS_DMASYNC_POSTWRITE); 389 bus_dmamap_unload(sc->sc_dmat, d->dmam); 390 bus_dmamap_destroy(sc->sc_dmat, d->dmam); 391 d->active = 0; 392 } 393 394 return 0; 395 } 396 397 int 398 bba_halt_input(void *v) 399 { 400 struct bba_softc *sc = v; 401 struct bba_dma_state *d; 402 uint32_t ssr; 403 404 mtx_enter(&audio_lock); 405 d = &sc->sc_rx_dma_state; 406 /* disable any DMA */ 407 ssr = bus_space_read_4(sc->sc_bst, sc->sc_bsh, IOASIC_CSR); 408 ssr &= ~IOASIC_CSR_DMAEN_ISDN_R; 409 bus_space_write_4(sc->sc_bst, sc->sc_bsh, IOASIC_CSR, ssr); 410 bus_space_write_4(sc->sc_bst, sc->sc_bsh, IOASIC_ISDN_R_DMAPTR, 0); 411 bus_space_write_4(sc->sc_bst, sc->sc_bsh, IOASIC_ISDN_R_NEXTPTR, 0); 412 mtx_leave(&audio_lock); 413 414 if (d->active) { 415 bus_dmamap_sync(sc->sc_dmat, d->dmam, 0, d->size, 416 BUS_DMASYNC_POSTREAD); 417 bus_dmamap_unload(sc->sc_dmat, d->dmam); 418 bus_dmamap_destroy(sc->sc_dmat, d->dmam); 419 d->active = 0; 420 } 421 422 return 0; 423 } 424 425 int 426 bba_getdev(void *v, struct audio_device *retp) 427 { 428 *retp = bba_device; 429 return 0; 430 } 431 432 int 433 bba_trigger_output(void *v, void *start, void *end, int blksize, 434 void (*intr)(void *), void *arg, struct audio_params *param) 435 { 436 struct bba_softc *sc = v; 437 struct bba_dma_state *d; 438 uint32_t ssr; 439 tc_addr_t phys, nphys; 440 int state; 441 442 DPRINTF(("bba_trigger_output: sc=%p start=%p end=%p blksize=%d intr=%p(%p)\n", 443 sc, start, end, blksize, intr, arg)); 444 d = &sc->sc_tx_dma_state; 445 state = 0; 446 447 /* disable any DMA */ 448 ssr = bus_space_read_4(sc->sc_bst, sc->sc_bsh, IOASIC_CSR); 449 ssr &= ~IOASIC_CSR_DMAEN_ISDN_T; 450 bus_space_write_4(sc->sc_bst, sc->sc_bsh, IOASIC_CSR, ssr); 451 452 d->size = (vaddr_t)end - (vaddr_t)start; 453 if (bus_dmamap_create(sc->sc_dmat, d->size, 454 BBA_MAX_DMA_SEGMENTS, IOASIC_DMA_BLOCKSIZE, 455 BBA_DMABUF_BOUNDARY, BUS_DMA_NOWAIT, &d->dmam)) { 456 printf("bba_trigger_output: can't create DMA map\n"); 457 goto bad; 458 } 459 state |= 1; 460 461 if (bus_dmamap_load(sc->sc_dmat, d->dmam, start, d->size, NULL, 462 BUS_DMA_WRITE | BUS_DMA_NOWAIT)) { 463 printf("bba_trigger_output: can't load DMA map\n"); 464 goto bad; 465 } 466 bus_dmamap_sync(sc->sc_dmat, d->dmam, 0, d->size, BUS_DMASYNC_PREWRITE); 467 state |= 2; 468 469 d->intr = intr; 470 d->intr_arg = arg; 471 d->curseg = 1; 472 473 /* get physical address of buffer start */ 474 phys = (tc_addr_t)d->dmam->dm_segs[0].ds_addr; 475 nphys = (tc_addr_t)d->dmam->dm_segs[1 % d->dmam->dm_nsegs].ds_addr; 476 477 /* setup DMA pointer */ 478 bus_space_write_4(sc->sc_bst, sc->sc_bsh, IOASIC_ISDN_X_DMAPTR, 479 IOASIC_DMA_ADDR(phys)); 480 bus_space_write_4(sc->sc_bst, sc->sc_bsh, IOASIC_ISDN_X_NEXTPTR, 481 IOASIC_DMA_ADDR(nphys)); 482 483 /* kick off DMA */ 484 mtx_enter(&audio_lock); 485 ssr |= IOASIC_CSR_DMAEN_ISDN_T; 486 bus_space_write_4(sc->sc_bst, sc->sc_bsh, IOASIC_CSR, ssr); 487 488 d->active = 1; 489 mtx_leave(&audio_lock); 490 return 0; 491 492 bad: 493 if (state & 2) 494 bus_dmamap_unload(sc->sc_dmat, d->dmam); 495 if (state & 1) 496 bus_dmamap_destroy(sc->sc_dmat, d->dmam); 497 return 1; 498 } 499 500 int 501 bba_trigger_input(void *v, void *start, void *end, int blksize, 502 void (*intr)(void *), void *arg, struct audio_params *param) 503 { 504 struct bba_softc *sc = v; 505 struct bba_dma_state *d; 506 uint32_t ssr; 507 tc_addr_t phys, nphys; 508 int state; 509 510 DPRINTF(("bba_trigger_input: sc=%p start=%p end=%p blksize=%d intr=%p(%p)\n", 511 sc, start, end, blksize, intr, arg)); 512 d = &sc->sc_rx_dma_state; 513 state = 0; 514 515 /* disable any DMA */ 516 ssr = bus_space_read_4(sc->sc_bst, sc->sc_bsh, IOASIC_CSR); 517 ssr &= ~IOASIC_CSR_DMAEN_ISDN_R; 518 bus_space_write_4(sc->sc_bst, sc->sc_bsh, IOASIC_CSR, ssr); 519 520 d->size = (vaddr_t)end - (vaddr_t)start; 521 if (bus_dmamap_create(sc->sc_dmat, d->size, 522 BBA_MAX_DMA_SEGMENTS, IOASIC_DMA_BLOCKSIZE, 523 BBA_DMABUF_BOUNDARY, BUS_DMA_NOWAIT, &d->dmam)) { 524 printf("bba_trigger_input: can't create DMA map\n"); 525 goto bad; 526 } 527 state |= 1; 528 529 if (bus_dmamap_load(sc->sc_dmat, d->dmam, start, d->size, NULL, 530 BUS_DMA_READ | BUS_DMA_NOWAIT)) { 531 printf("bba_trigger_input: can't load DMA map\n"); 532 goto bad; 533 } 534 bus_dmamap_sync(sc->sc_dmat, d->dmam, 0, d->size, BUS_DMASYNC_PREREAD); 535 state |= 2; 536 537 d->intr = intr; 538 d->intr_arg = arg; 539 d->curseg = 1; 540 541 /* get physical address of buffer start */ 542 phys = (tc_addr_t)d->dmam->dm_segs[0].ds_addr; 543 nphys = (tc_addr_t)d->dmam->dm_segs[1 % d->dmam->dm_nsegs].ds_addr; 544 545 /* setup DMA pointer */ 546 bus_space_write_4(sc->sc_bst, sc->sc_bsh, IOASIC_ISDN_R_DMAPTR, 547 IOASIC_DMA_ADDR(phys)); 548 bus_space_write_4(sc->sc_bst, sc->sc_bsh, IOASIC_ISDN_R_NEXTPTR, 549 IOASIC_DMA_ADDR(nphys)); 550 551 /* kick off DMA */ 552 mtx_enter(&audio_lock); 553 ssr |= IOASIC_CSR_DMAEN_ISDN_R; 554 bus_space_write_4(sc->sc_bst, sc->sc_bsh, IOASIC_CSR, ssr); 555 556 d->active = 1; 557 mtx_leave(&audio_lock); 558 return 0; 559 560 bad: 561 if (state & 2) 562 bus_dmamap_unload(sc->sc_dmat, d->dmam); 563 if (state & 1) 564 bus_dmamap_destroy(sc->sc_dmat, d->dmam); 565 return 1; 566 } 567 568 int 569 bba_intr(void *v) 570 { 571 struct bba_softc *sc = v; 572 struct bba_dma_state *d; 573 tc_addr_t nphys; 574 int mask; 575 576 mtx_enter(&audio_lock); 577 578 mask = bus_space_read_4(sc->sc_bst, sc->sc_bsh, IOASIC_INTR); 579 580 if (mask & IOASIC_INTR_ISDN_TXLOAD) { 581 d = &sc->sc_tx_dma_state; 582 d->curseg = (d->curseg+1) % d->dmam->dm_nsegs; 583 nphys = (tc_addr_t)d->dmam->dm_segs[d->curseg].ds_addr; 584 bus_space_write_4(sc->sc_bst, sc->sc_bsh, 585 IOASIC_ISDN_X_NEXTPTR, IOASIC_DMA_ADDR(nphys)); 586 if (d->intr != NULL) 587 (*d->intr)(d->intr_arg); 588 } 589 if (mask & IOASIC_INTR_ISDN_RXLOAD) { 590 d = &sc->sc_rx_dma_state; 591 d->curseg = (d->curseg+1) % d->dmam->dm_nsegs; 592 nphys = (tc_addr_t)d->dmam->dm_segs[d->curseg].ds_addr; 593 bus_space_write_4(sc->sc_bst, sc->sc_bsh, 594 IOASIC_ISDN_R_NEXTPTR, IOASIC_DMA_ADDR(nphys)); 595 if (d->intr != NULL) 596 (*d->intr)(d->intr_arg); 597 } 598 599 mtx_leave(&audio_lock); 600 601 return 0; 602 } 603 604 int 605 bba_get_props(void *v) 606 { 607 return AUDIO_PROP_MMAP | am7930_get_props(v); 608 } 609 610 paddr_t 611 bba_mappage(void *v, void *mem, off_t offset, int prot) 612 { 613 struct bba_softc *sc = v; 614 struct bba_mem **mp; 615 bus_dma_segment_t seg; 616 617 if (offset < 0) 618 return -1; 619 620 for (mp = &sc->sc_mem_head; *mp && (*mp)->kva != mem; 621 mp = &(*mp)->next) 622 continue; 623 if (*mp == NULL) 624 return -1; 625 626 seg.ds_addr = (*mp)->addr; 627 seg.ds_len = (*mp)->size; 628 629 return bus_dmamem_mmap(sc->sc_dmat, &seg, 1, offset, 630 prot, BUS_DMA_WAITOK); 631 } 632 633 int 634 bba_round_blocksize(void *v, int blk) 635 { 636 return IOASIC_DMA_BLOCKSIZE; 637 } 638 639 640 /* indirect write */ 641 void 642 bba_codec_iwrite(struct am7930_softc *sc, int reg, uint8_t val) 643 { 644 DPRINTF(("bba_codec_iwrite(): sc=%p, reg=%02x, val=%02x\n", sc, reg, val)); 645 bba_codec_dwrite(sc, AM7930_DREG_CR, reg); 646 bba_codec_dwrite(sc, AM7930_DREG_DR, val); 647 } 648 649 650 void 651 bba_codec_iwrite16(struct am7930_softc *sc, int reg, uint16_t val) 652 { 653 DPRINTF(("bba_codec_iwrite16(): sc=%p, reg=%02x, val=%04x\n", sc, reg, val)); 654 bba_codec_dwrite(sc, AM7930_DREG_CR, reg); 655 bba_codec_dwrite(sc, AM7930_DREG_DR, val); 656 bba_codec_dwrite(sc, AM7930_DREG_DR, val >> 8); 657 } 658 659 660 /* indirect read */ 661 uint8_t 662 bba_codec_iread(struct am7930_softc *sc, int reg) 663 { 664 uint8_t val; 665 666 DPRINTF(("bba_codec_iread(): sc=%p, reg=%02x\n", sc, reg)); 667 bba_codec_dwrite(sc, AM7930_DREG_CR, reg); 668 val = bba_codec_dread(sc, AM7930_DREG_DR); 669 670 DPRINTF(("read 0x%02x (%d)\n", val, val)); 671 672 return val; 673 } 674 675 uint16_t 676 bba_codec_iread16(struct am7930_softc *sc, int reg) 677 { 678 uint16_t val; 679 680 DPRINTF(("bba_codec_iread16(): sc=%p, reg=%02x\n", sc, reg)); 681 bba_codec_dwrite(sc, AM7930_DREG_CR, reg); 682 val = bba_codec_dread(sc, AM7930_DREG_DR); 683 val |= bba_codec_dread(sc, AM7930_DREG_DR) << 8; 684 685 return val; 686 } 687 688 689 /* direct write */ 690 void 691 bba_codec_dwrite(struct am7930_softc *asc, int reg, uint8_t val) 692 { 693 struct bba_softc *sc = (struct bba_softc *)asc; 694 695 #if defined(__alpha__) 696 bus_space_write_4(sc->sc_bst, sc->sc_codec_bsh, reg << 2, val << 8); 697 #else 698 bus_space_write_4(sc->sc_bst, sc->sc_codec_bsh, reg << 6, val); 699 #endif 700 } 701 702 /* direct read */ 703 uint8_t 704 bba_codec_dread(struct am7930_softc *asc, int reg) 705 { 706 struct bba_softc *sc = (struct bba_softc *)asc; 707 708 #if defined(__alpha__) 709 return (bus_space_read_4(sc->sc_bst, sc->sc_codec_bsh, reg << 2) >> 8) & 710 0xff; 711 #else 712 return bus_space_read_4(sc->sc_bst, sc->sc_codec_bsh, reg << 6) & 0xff; 713 #endif 714 } 715