1 /* $OpenBSD: bba.c,v 1.2 2011/09/05 16:54:41 miod 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 void bba_output_conv(void *, u_char *, int); 129 void bba_input_conv(void *, u_char *, int); 130 131 struct am7930_glue bba_glue = { 132 bba_codec_iread, 133 bba_codec_iwrite, 134 bba_codec_iread16, 135 bba_codec_iwrite16, 136 bba_onopen, 137 bba_onclose, 138 4, 139 bba_input_conv, 140 bba_output_conv 141 }; 142 143 /* 144 * Define our interface to the higher level audio driver. 145 */ 146 147 int bba_round_blocksize(void *, int); 148 int bba_halt_output(void *); 149 int bba_halt_input(void *); 150 int bba_getdev(void *, struct audio_device *); 151 void *bba_allocm(void *, int, size_t, int, int); 152 void bba_freem(void *, void *, int); 153 size_t bba_round_buffersize(void *, int, size_t); 154 int bba_get_props(void *); 155 paddr_t bba_mappage(void *, void *, off_t, int); 156 int bba_trigger_output(void *, void *, void *, int, 157 void (*)(void *), void *, struct audio_params *); 158 int bba_trigger_input(void *, void *, void *, int, 159 void (*)(void *), void *, struct audio_params *); 160 161 struct audio_hw_if bba_hw_if = { 162 am7930_open, 163 am7930_close, 164 NULL, 165 am7930_query_encoding, 166 am7930_set_params, 167 bba_round_blocksize, /* md */ 168 am7930_commit_settings, 169 NULL, 170 NULL, 171 NULL, 172 NULL, 173 bba_halt_output, /* md */ 174 bba_halt_input, /* md */ 175 NULL, 176 bba_getdev, 177 NULL, 178 am7930_set_port, 179 am7930_get_port, 180 am7930_query_devinfo, 181 bba_allocm, /* md */ 182 bba_freem, /* md */ 183 bba_round_buffersize, /* md */ 184 bba_mappage, 185 bba_get_props, 186 bba_trigger_output, /* md */ 187 bba_trigger_input, /* md */ 188 NULL 189 }; 190 191 static struct audio_device bba_device = { 192 "am7930", 193 "x", 194 "bba" 195 }; 196 197 int bba_intr(void *); 198 void bba_reset(struct bba_softc *, int); 199 void bba_codec_dwrite(struct am7930_softc *, int, uint8_t); 200 uint8_t bba_codec_dread(struct am7930_softc *, int); 201 202 int 203 bba_match(struct device *parent, void *vcf, void *aux) 204 { 205 struct ioasicdev_attach_args *ia = aux; 206 207 if (strcmp(ia->iada_modname, "isdn") != 0 && 208 strcmp(ia->iada_modname, "AMD79c30") != 0) 209 return 0; 210 211 return 1; 212 } 213 214 void 215 bba_attach(struct device *parent, struct device *self, void *aux) 216 { 217 struct ioasicdev_attach_args *ia = aux; 218 struct bba_softc *sc = (struct bba_softc *)self; 219 struct ioasic_softc *iosc = (struct ioasic_softc *)parent; 220 221 sc->sc_bst = iosc->sc_bst; 222 sc->sc_bsh = iosc->sc_bsh; 223 sc->sc_dmat = iosc->sc_dmat; 224 225 /* get the bus space handle for codec */ 226 if (bus_space_subregion(sc->sc_bst, sc->sc_bsh, 227 ia->iada_offset, 0, &sc->sc_codec_bsh)) { 228 printf(": unable to map device\n"); 229 return; 230 } 231 232 printf("\n"); 233 234 bba_reset(sc,1); 235 236 /* 237 * Set up glue for MI code early; we use some of it here. 238 */ 239 sc->sc_am7930.sc_glue = &bba_glue; 240 241 /* 242 * MI initialisation. We will be doing DMA. 243 */ 244 am7930_init(&sc->sc_am7930, AUDIOAMD_DMA_MODE); 245 246 ioasic_intr_establish(parent, ia->iada_cookie, IPL_AUDIO, 247 bba_intr, sc, self->dv_xname); 248 249 audio_attach_mi(&bba_hw_if, sc, self); 250 } 251 252 void 253 bba_onopen(struct am7930_softc *sc) 254 { 255 } 256 257 void 258 bba_onclose(struct am7930_softc *sc) 259 { 260 } 261 262 void 263 bba_reset(struct bba_softc *sc, int reset) 264 { 265 uint32_t ssr; 266 267 /* disable any DMA and reset the codec */ 268 ssr = bus_space_read_4(sc->sc_bst, sc->sc_bsh, IOASIC_CSR); 269 ssr &= ~(IOASIC_CSR_DMAEN_ISDN_T | IOASIC_CSR_DMAEN_ISDN_R); 270 if (reset) 271 ssr &= ~IOASIC_CSR_ISDN_ENABLE; 272 bus_space_write_4(sc->sc_bst, sc->sc_bsh, IOASIC_CSR, ssr); 273 DELAY(10); /* 400ns required for codec to reset */ 274 275 /* initialise DMA pointers */ 276 bus_space_write_4(sc->sc_bst, sc->sc_bsh, IOASIC_ISDN_X_DMAPTR, 0); 277 bus_space_write_4(sc->sc_bst, sc->sc_bsh, IOASIC_ISDN_X_NEXTPTR, 0); 278 bus_space_write_4(sc->sc_bst, sc->sc_bsh, IOASIC_ISDN_R_DMAPTR, 0); 279 bus_space_write_4(sc->sc_bst, sc->sc_bsh, IOASIC_ISDN_R_NEXTPTR, 0); 280 281 /* take out of reset state */ 282 if (reset) { 283 ssr |= IOASIC_CSR_ISDN_ENABLE; 284 bus_space_write_4(sc->sc_bst, sc->sc_bsh, IOASIC_CSR, ssr); 285 } 286 287 } 288 289 void * 290 bba_allocm(void *v, int direction, size_t size, int mtype, int flags) 291 { 292 struct bba_softc *sc = v; 293 bus_dma_segment_t seg; 294 int rseg; 295 caddr_t kva; 296 struct bba_mem *m; 297 int w; 298 int state; 299 300 DPRINTF(("bba_allocm: size = %zu\n", size)); 301 state = 0; 302 w = (flags & M_NOWAIT) ? BUS_DMA_NOWAIT : BUS_DMA_WAITOK; 303 304 if (bus_dmamem_alloc(sc->sc_dmat, size, BBA_DMABUF_ALIGN, 305 BBA_DMABUF_BOUNDARY, &seg, 1, &rseg, w)) { 306 printf("%s: can't allocate DMA buffer\n", 307 sc->sc_am7930.sc_dev.dv_xname); 308 goto bad; 309 } 310 state |= 1; 311 312 if (bus_dmamem_map(sc->sc_dmat, &seg, rseg, size, 313 &kva, w | BUS_DMA_COHERENT)) { 314 printf("%s: can't map DMA buffer\n", 315 sc->sc_am7930.sc_dev.dv_xname); 316 goto bad; 317 } 318 state |= 2; 319 320 m = malloc(sizeof(struct bba_mem), mtype, flags | M_CANFAIL); 321 if (m == NULL) 322 goto bad; 323 m->addr = seg.ds_addr; 324 m->size = seg.ds_len; 325 m->kva = kva; 326 m->next = sc->sc_mem_head; 327 sc->sc_mem_head = m; 328 329 return (void *)kva; 330 331 bad: 332 if (state & 2) 333 bus_dmamem_unmap(sc->sc_dmat, kva, size); 334 if (state & 1) 335 bus_dmamem_free(sc->sc_dmat, &seg, 1); 336 return NULL; 337 } 338 339 void 340 bba_freem(void *v, void *ptr, int mtype) 341 { 342 struct bba_softc *sc = v; 343 struct bba_mem **mp, *m; 344 bus_dma_segment_t seg; 345 void *kva; 346 347 kva = (void *)ptr; 348 for (mp = &sc->sc_mem_head; *mp && (*mp)->kva != kva; mp = &(*mp)->next) 349 continue; 350 m = *mp; 351 if (m == NULL) { 352 printf("bba_freem: freeing unallocated memory\n"); 353 return; 354 } 355 *mp = m->next; 356 bus_dmamem_unmap(sc->sc_dmat, kva, m->size); 357 358 seg.ds_addr = m->addr; 359 seg.ds_len = m->size; 360 bus_dmamem_free(sc->sc_dmat, &seg, 1); 361 free(m, mtype); 362 } 363 364 size_t 365 bba_round_buffersize(void *v, int direction, size_t size) 366 { 367 368 DPRINTF(("bba_round_buffersize: size=%zu\n", size)); 369 return size > BBA_DMABUF_SIZE ? BBA_DMABUF_SIZE : 370 roundup(size, IOASIC_DMA_BLOCKSIZE); 371 } 372 373 int 374 bba_halt_output(void *v) 375 { 376 struct bba_softc *sc = v; 377 struct bba_dma_state *d; 378 uint32_t ssr; 379 380 d = &sc->sc_tx_dma_state; 381 /* disable any DMA */ 382 ssr = bus_space_read_4(sc->sc_bst, sc->sc_bsh, IOASIC_CSR); 383 ssr &= ~IOASIC_CSR_DMAEN_ISDN_T; 384 bus_space_write_4(sc->sc_bst, sc->sc_bsh, IOASIC_CSR, ssr); 385 bus_space_write_4(sc->sc_bst, sc->sc_bsh, IOASIC_ISDN_X_DMAPTR, 0); 386 bus_space_write_4(sc->sc_bst, sc->sc_bsh, IOASIC_ISDN_X_NEXTPTR, 0); 387 388 if (d->active) { 389 bus_dmamap_sync(sc->sc_dmat, d->dmam, 0, d->size, 390 BUS_DMASYNC_POSTWRITE); 391 bus_dmamap_unload(sc->sc_dmat, d->dmam); 392 bus_dmamap_destroy(sc->sc_dmat, d->dmam); 393 d->active = 0; 394 } 395 396 return 0; 397 } 398 399 int 400 bba_halt_input(void *v) 401 { 402 struct bba_softc *sc = v; 403 struct bba_dma_state *d; 404 uint32_t ssr; 405 406 d = &sc->sc_rx_dma_state; 407 /* disable any DMA */ 408 ssr = bus_space_read_4(sc->sc_bst, sc->sc_bsh, IOASIC_CSR); 409 ssr &= ~IOASIC_CSR_DMAEN_ISDN_R; 410 bus_space_write_4(sc->sc_bst, sc->sc_bsh, IOASIC_CSR, ssr); 411 bus_space_write_4(sc->sc_bst, sc->sc_bsh, IOASIC_ISDN_R_DMAPTR, 0); 412 bus_space_write_4(sc->sc_bst, sc->sc_bsh, IOASIC_ISDN_R_NEXTPTR, 0); 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 ssr |= IOASIC_CSR_DMAEN_ISDN_T; 485 bus_space_write_4(sc->sc_bst, sc->sc_bsh, IOASIC_CSR, ssr); 486 487 d->active = 1; 488 489 return 0; 490 491 bad: 492 if (state & 2) 493 bus_dmamap_unload(sc->sc_dmat, d->dmam); 494 if (state & 1) 495 bus_dmamap_destroy(sc->sc_dmat, d->dmam); 496 return 1; 497 } 498 499 int 500 bba_trigger_input(void *v, void *start, void *end, int blksize, 501 void (*intr)(void *), void *arg, struct audio_params *param) 502 { 503 struct bba_softc *sc = v; 504 struct bba_dma_state *d; 505 uint32_t ssr; 506 tc_addr_t phys, nphys; 507 int state; 508 509 DPRINTF(("bba_trigger_input: sc=%p start=%p end=%p blksize=%d intr=%p(%p)\n", 510 sc, start, end, blksize, intr, arg)); 511 d = &sc->sc_rx_dma_state; 512 state = 0; 513 514 /* disable any DMA */ 515 ssr = bus_space_read_4(sc->sc_bst, sc->sc_bsh, IOASIC_CSR); 516 ssr &= ~IOASIC_CSR_DMAEN_ISDN_R; 517 bus_space_write_4(sc->sc_bst, sc->sc_bsh, IOASIC_CSR, ssr); 518 519 d->size = (vaddr_t)end - (vaddr_t)start; 520 if (bus_dmamap_create(sc->sc_dmat, d->size, 521 BBA_MAX_DMA_SEGMENTS, IOASIC_DMA_BLOCKSIZE, 522 BBA_DMABUF_BOUNDARY, BUS_DMA_NOWAIT, &d->dmam)) { 523 printf("bba_trigger_input: can't create DMA map\n"); 524 goto bad; 525 } 526 state |= 1; 527 528 if (bus_dmamap_load(sc->sc_dmat, d->dmam, start, d->size, NULL, 529 BUS_DMA_READ | BUS_DMA_NOWAIT)) { 530 printf("bba_trigger_input: can't load DMA map\n"); 531 goto bad; 532 } 533 bus_dmamap_sync(sc->sc_dmat, d->dmam, 0, d->size, BUS_DMASYNC_PREREAD); 534 state |= 2; 535 536 d->intr = intr; 537 d->intr_arg = arg; 538 d->curseg = 1; 539 540 /* get physical address of buffer start */ 541 phys = (tc_addr_t)d->dmam->dm_segs[0].ds_addr; 542 nphys = (tc_addr_t)d->dmam->dm_segs[1 % d->dmam->dm_nsegs].ds_addr; 543 544 /* setup DMA pointer */ 545 bus_space_write_4(sc->sc_bst, sc->sc_bsh, IOASIC_ISDN_R_DMAPTR, 546 IOASIC_DMA_ADDR(phys)); 547 bus_space_write_4(sc->sc_bst, sc->sc_bsh, IOASIC_ISDN_R_NEXTPTR, 548 IOASIC_DMA_ADDR(nphys)); 549 550 /* kick off DMA */ 551 ssr |= IOASIC_CSR_DMAEN_ISDN_R; 552 bus_space_write_4(sc->sc_bst, sc->sc_bsh, IOASIC_CSR, ssr); 553 554 d->active = 1; 555 556 return 0; 557 558 bad: 559 if (state & 2) 560 bus_dmamap_unload(sc->sc_dmat, d->dmam); 561 if (state & 1) 562 bus_dmamap_destroy(sc->sc_dmat, d->dmam); 563 return 1; 564 } 565 566 int 567 bba_intr(void *v) 568 { 569 struct bba_softc *sc = v; 570 struct bba_dma_state *d; 571 tc_addr_t nphys; 572 int s, mask; 573 574 s = splaudio(); 575 576 mask = bus_space_read_4(sc->sc_bst, sc->sc_bsh, IOASIC_INTR); 577 578 if (mask & IOASIC_INTR_ISDN_TXLOAD) { 579 d = &sc->sc_tx_dma_state; 580 d->curseg = (d->curseg+1) % d->dmam->dm_nsegs; 581 nphys = (tc_addr_t)d->dmam->dm_segs[d->curseg].ds_addr; 582 bus_space_write_4(sc->sc_bst, sc->sc_bsh, 583 IOASIC_ISDN_X_NEXTPTR, IOASIC_DMA_ADDR(nphys)); 584 if (d->intr != NULL) 585 (*d->intr)(d->intr_arg); 586 } 587 if (mask & IOASIC_INTR_ISDN_RXLOAD) { 588 d = &sc->sc_rx_dma_state; 589 d->curseg = (d->curseg+1) % d->dmam->dm_nsegs; 590 nphys = (tc_addr_t)d->dmam->dm_segs[d->curseg].ds_addr; 591 bus_space_write_4(sc->sc_bst, sc->sc_bsh, 592 IOASIC_ISDN_R_NEXTPTR, IOASIC_DMA_ADDR(nphys)); 593 if (d->intr != NULL) 594 (*d->intr)(d->intr_arg); 595 } 596 597 splx(s); 598 599 return 0; 600 } 601 602 int 603 bba_get_props(void *v) 604 { 605 return AUDIO_PROP_MMAP | am7930_get_props(v); 606 } 607 608 paddr_t 609 bba_mappage(void *v, void *mem, off_t offset, int prot) 610 { 611 struct bba_softc *sc = v; 612 struct bba_mem **mp; 613 bus_dma_segment_t seg; 614 615 if (offset < 0) 616 return -1; 617 618 for (mp = &sc->sc_mem_head; *mp && (*mp)->kva != mem; 619 mp = &(*mp)->next) 620 continue; 621 if (*mp == NULL) 622 return -1; 623 624 seg.ds_addr = (*mp)->addr; 625 seg.ds_len = (*mp)->size; 626 627 return bus_dmamem_mmap(sc->sc_dmat, &seg, 1, offset, 628 prot, BUS_DMA_WAITOK); 629 } 630 631 void 632 bba_input_conv(void *v, u_char *p, int cc) 633 { 634 struct bba_softc *sc = v; 635 u_char *p0 = p; 636 int cc0 = cc; 637 uint32_t *q = (uint32_t *)p; 638 639 DPRINTF(("bba_input_conv(): v=%p p=%p cc=%d\n", v, p, cc)); 640 641 /* convert data from dma stream - one byte per longword<23:16> */ 642 #ifdef __alpha__ 643 /* try to avoid smaller than 32 bit accesses whenever possible */ 644 if (((vaddr_t)p & 3) == 0) { 645 while (cc >= 4) { 646 uint32_t fp; 647 648 /* alpha is little endian */ 649 fp = (*q++ >> 16) & 0xff; 650 fp |= ((*q++ >> 16) & 0xff) << 8; 651 fp |= ((*q++ >> 16) & 0xff) << 16; 652 fp |= ((*q++ >> 16) & 0xff) << 24; 653 *(uint32_t *)p = fp; 654 p += 4; 655 cc -= 4; 656 } 657 } 658 #endif 659 while (--cc >= 0) 660 *p++ = (*q++ >> 16) & 0xff; 661 662 /* convert mulaw data to expected encoding if necessary */ 663 if (sc->sc_am7930.rec_sw_code != NULL) 664 (*sc->sc_am7930.rec_sw_code)(v, p0, cc0); 665 } 666 667 void 668 bba_output_conv(void *v, u_char *p, int cc) 669 { 670 struct bba_softc *sc = v; 671 uint32_t *q = (uint32_t *)p; 672 673 DPRINTF(("bba_output_conv(): v=%p p=%p cc=%d\n", v, p, cc)); 674 675 /* convert data to mulaw first if necessary */ 676 if (sc->sc_am7930.play_sw_code != NULL) 677 (*sc->sc_am7930.play_sw_code)(v, p, cc); 678 679 /* convert data to dma stream - one byte per longword<23:16> */ 680 p += cc; 681 q += cc; 682 #ifdef __alpha__ 683 /* try to avoid smaller than 32 bit accesses whenever possible */ 684 if (((vaddr_t)p & 3) == 0) { 685 while (cc >= 4) { 686 uint32_t fp; 687 688 p -= 4; 689 fp = *(uint32_t *)p; 690 /* alpha is little endian */ 691 *--q = ((fp >> 24) & 0xff) << 16; 692 *--q = ((fp >> 16) & 0xff) << 16; 693 *--q = ((fp >> 8) & 0xff) << 16; 694 *--q = (fp & 0xff) << 16; 695 cc -= 4; 696 } 697 } 698 #endif 699 while (--cc >= 0) 700 *--q = *--p << 16; 701 } 702 703 int 704 bba_round_blocksize(void *v, int blk) 705 { 706 return IOASIC_DMA_BLOCKSIZE; 707 } 708 709 710 /* indirect write */ 711 void 712 bba_codec_iwrite(struct am7930_softc *sc, int reg, uint8_t val) 713 { 714 DPRINTF(("bba_codec_iwrite(): sc=%p, reg=%02x, val=%02x\n", sc, reg, val)); 715 bba_codec_dwrite(sc, AM7930_DREG_CR, reg); 716 bba_codec_dwrite(sc, AM7930_DREG_DR, val); 717 } 718 719 720 void 721 bba_codec_iwrite16(struct am7930_softc *sc, int reg, uint16_t val) 722 { 723 DPRINTF(("bba_codec_iwrite16(): sc=%p, reg=%02x, val=%04x\n", sc, reg, val)); 724 bba_codec_dwrite(sc, AM7930_DREG_CR, reg); 725 bba_codec_dwrite(sc, AM7930_DREG_DR, val); 726 bba_codec_dwrite(sc, AM7930_DREG_DR, val >> 8); 727 } 728 729 730 /* indirect read */ 731 uint8_t 732 bba_codec_iread(struct am7930_softc *sc, int reg) 733 { 734 uint8_t val; 735 736 DPRINTF(("bba_codec_iread(): sc=%p, reg=%02x\n", sc, reg)); 737 bba_codec_dwrite(sc, AM7930_DREG_CR, reg); 738 val = bba_codec_dread(sc, AM7930_DREG_DR); 739 740 DPRINTF(("read 0x%02x (%d)\n", val, val)); 741 742 return val; 743 } 744 745 uint16_t 746 bba_codec_iread16(struct am7930_softc *sc, int reg) 747 { 748 uint16_t val; 749 750 DPRINTF(("bba_codec_iread16(): sc=%p, reg=%02x\n", sc, reg)); 751 bba_codec_dwrite(sc, AM7930_DREG_CR, reg); 752 val = bba_codec_dread(sc, AM7930_DREG_DR); 753 val |= bba_codec_dread(sc, AM7930_DREG_DR) << 8; 754 755 return val; 756 } 757 758 759 /* direct write */ 760 void 761 bba_codec_dwrite(struct am7930_softc *asc, int reg, uint8_t val) 762 { 763 struct bba_softc *sc = (struct bba_softc *)asc; 764 765 #if defined(__alpha__) 766 bus_space_write_4(sc->sc_bst, sc->sc_codec_bsh, reg << 2, val << 8); 767 #else 768 bus_space_write_4(sc->sc_bst, sc->sc_codec_bsh, reg << 6, val); 769 #endif 770 } 771 772 /* direct read */ 773 uint8_t 774 bba_codec_dread(struct am7930_softc *asc, int reg) 775 { 776 struct bba_softc *sc = (struct bba_softc *)asc; 777 778 #if defined(__alpha__) 779 return (bus_space_read_4(sc->sc_bst, sc->sc_codec_bsh, reg << 2) >> 8) & 780 0xff; 781 #else 782 return bus_space_read_4(sc->sc_bst, sc->sc_codec_bsh, reg << 6) & 0xff; 783 #endif 784 } 785