bba.c revision 1.4
1/* $OpenBSD: bba.c,v 1.4 2014/07/12 18:48:52 tedu 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 77struct bba_mem { 78 struct bba_mem *next; 79 bus_addr_t addr; 80 bus_size_t size; 81 void *kva; 82}; 83 84struct 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 93struct 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 107int bba_match(struct device *, void *, void *); 108void bba_attach(struct device *, struct device *, void *); 109 110struct cfdriver bba_cd = { 111 NULL, "bba", DV_DULL 112}; 113 114const 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 122uint8_t bba_codec_iread(struct am7930_softc *, int); 123uint16_t bba_codec_iread16(struct am7930_softc *, int); 124void bba_codec_iwrite(struct am7930_softc *, int, uint8_t); 125void bba_codec_iwrite16(struct am7930_softc *, int, uint16_t); 126void bba_onopen(struct am7930_softc *); 127void bba_onclose(struct am7930_softc *); 128void bba_output_conv(void *, u_char *, int); 129void bba_input_conv(void *, u_char *, int); 130 131struct 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 147int bba_round_blocksize(void *, int); 148int bba_halt_output(void *); 149int bba_halt_input(void *); 150int bba_getdev(void *, struct audio_device *); 151void *bba_allocm(void *, int, size_t, int, int); 152void bba_freem(void *, void *, int); 153size_t bba_round_buffersize(void *, int, size_t); 154int bba_get_props(void *); 155paddr_t bba_mappage(void *, void *, off_t, int); 156int bba_trigger_output(void *, void *, void *, int, 157 void (*)(void *), void *, struct audio_params *); 158int bba_trigger_input(void *, void *, void *, int, 159 void (*)(void *), void *, struct audio_params *); 160 161struct 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 191static struct audio_device bba_device = { 192 "am7930", 193 "x", 194 "bba" 195}; 196 197int bba_intr(void *); 198void bba_reset(struct bba_softc *, int); 199void bba_codec_dwrite(struct am7930_softc *, int, uint8_t); 200uint8_t bba_codec_dread(struct am7930_softc *, int); 201 202int 203bba_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 214void 215bba_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 252void 253bba_onopen(struct am7930_softc *sc) 254{ 255} 256 257void 258bba_onclose(struct am7930_softc *sc) 259{ 260} 261 262void 263bba_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 289void * 290bba_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 331bad: 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 339void 340bba_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, 0); 362} 363 364size_t 365bba_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 373int 374bba_halt_output(void *v) 375{ 376 struct bba_softc *sc = v; 377 struct bba_dma_state *d; 378 uint32_t ssr; 379 380 mtx_enter(&audio_lock); 381 d = &sc->sc_tx_dma_state; 382 /* disable any DMA */ 383 ssr = bus_space_read_4(sc->sc_bst, sc->sc_bsh, IOASIC_CSR); 384 ssr &= ~IOASIC_CSR_DMAEN_ISDN_T; 385 bus_space_write_4(sc->sc_bst, sc->sc_bsh, IOASIC_CSR, ssr); 386 bus_space_write_4(sc->sc_bst, sc->sc_bsh, IOASIC_ISDN_X_DMAPTR, 0); 387 bus_space_write_4(sc->sc_bst, sc->sc_bsh, IOASIC_ISDN_X_NEXTPTR, 0); 388 mtx_leave(&audio_lock); 389 390 if (d->active) { 391 bus_dmamap_sync(sc->sc_dmat, d->dmam, 0, d->size, 392 BUS_DMASYNC_POSTWRITE); 393 bus_dmamap_unload(sc->sc_dmat, d->dmam); 394 bus_dmamap_destroy(sc->sc_dmat, d->dmam); 395 d->active = 0; 396 } 397 398 return 0; 399} 400 401int 402bba_halt_input(void *v) 403{ 404 struct bba_softc *sc = v; 405 struct bba_dma_state *d; 406 uint32_t ssr; 407 408 mtx_enter(&audio_lock); 409 d = &sc->sc_rx_dma_state; 410 /* disable any DMA */ 411 ssr = bus_space_read_4(sc->sc_bst, sc->sc_bsh, IOASIC_CSR); 412 ssr &= ~IOASIC_CSR_DMAEN_ISDN_R; 413 bus_space_write_4(sc->sc_bst, sc->sc_bsh, IOASIC_CSR, ssr); 414 bus_space_write_4(sc->sc_bst, sc->sc_bsh, IOASIC_ISDN_R_DMAPTR, 0); 415 bus_space_write_4(sc->sc_bst, sc->sc_bsh, IOASIC_ISDN_R_NEXTPTR, 0); 416 mtx_leave(&audio_lock); 417 418 if (d->active) { 419 bus_dmamap_sync(sc->sc_dmat, d->dmam, 0, d->size, 420 BUS_DMASYNC_POSTREAD); 421 bus_dmamap_unload(sc->sc_dmat, d->dmam); 422 bus_dmamap_destroy(sc->sc_dmat, d->dmam); 423 d->active = 0; 424 } 425 426 return 0; 427} 428 429int 430bba_getdev(void *v, struct audio_device *retp) 431{ 432 *retp = bba_device; 433 return 0; 434} 435 436int 437bba_trigger_output(void *v, void *start, void *end, int blksize, 438 void (*intr)(void *), void *arg, struct audio_params *param) 439{ 440 struct bba_softc *sc = v; 441 struct bba_dma_state *d; 442 uint32_t ssr; 443 tc_addr_t phys, nphys; 444 int state; 445 446 DPRINTF(("bba_trigger_output: sc=%p start=%p end=%p blksize=%d intr=%p(%p)\n", 447 sc, start, end, blksize, intr, arg)); 448 d = &sc->sc_tx_dma_state; 449 state = 0; 450 451 /* disable any DMA */ 452 ssr = bus_space_read_4(sc->sc_bst, sc->sc_bsh, IOASIC_CSR); 453 ssr &= ~IOASIC_CSR_DMAEN_ISDN_T; 454 bus_space_write_4(sc->sc_bst, sc->sc_bsh, IOASIC_CSR, ssr); 455 456 d->size = (vaddr_t)end - (vaddr_t)start; 457 if (bus_dmamap_create(sc->sc_dmat, d->size, 458 BBA_MAX_DMA_SEGMENTS, IOASIC_DMA_BLOCKSIZE, 459 BBA_DMABUF_BOUNDARY, BUS_DMA_NOWAIT, &d->dmam)) { 460 printf("bba_trigger_output: can't create DMA map\n"); 461 goto bad; 462 } 463 state |= 1; 464 465 if (bus_dmamap_load(sc->sc_dmat, d->dmam, start, d->size, NULL, 466 BUS_DMA_WRITE | BUS_DMA_NOWAIT)) { 467 printf("bba_trigger_output: can't load DMA map\n"); 468 goto bad; 469 } 470 bus_dmamap_sync(sc->sc_dmat, d->dmam, 0, d->size, BUS_DMASYNC_PREWRITE); 471 state |= 2; 472 473 d->intr = intr; 474 d->intr_arg = arg; 475 d->curseg = 1; 476 477 /* get physical address of buffer start */ 478 phys = (tc_addr_t)d->dmam->dm_segs[0].ds_addr; 479 nphys = (tc_addr_t)d->dmam->dm_segs[1 % d->dmam->dm_nsegs].ds_addr; 480 481 /* setup DMA pointer */ 482 bus_space_write_4(sc->sc_bst, sc->sc_bsh, IOASIC_ISDN_X_DMAPTR, 483 IOASIC_DMA_ADDR(phys)); 484 bus_space_write_4(sc->sc_bst, sc->sc_bsh, IOASIC_ISDN_X_NEXTPTR, 485 IOASIC_DMA_ADDR(nphys)); 486 487 /* kick off DMA */ 488 mtx_enter(&audio_lock); 489 ssr |= IOASIC_CSR_DMAEN_ISDN_T; 490 bus_space_write_4(sc->sc_bst, sc->sc_bsh, IOASIC_CSR, ssr); 491 492 d->active = 1; 493 mtx_leave(&audio_lock); 494 return 0; 495 496bad: 497 if (state & 2) 498 bus_dmamap_unload(sc->sc_dmat, d->dmam); 499 if (state & 1) 500 bus_dmamap_destroy(sc->sc_dmat, d->dmam); 501 return 1; 502} 503 504int 505bba_trigger_input(void *v, void *start, void *end, int blksize, 506 void (*intr)(void *), void *arg, struct audio_params *param) 507{ 508 struct bba_softc *sc = v; 509 struct bba_dma_state *d; 510 uint32_t ssr; 511 tc_addr_t phys, nphys; 512 int state; 513 514 DPRINTF(("bba_trigger_input: sc=%p start=%p end=%p blksize=%d intr=%p(%p)\n", 515 sc, start, end, blksize, intr, arg)); 516 d = &sc->sc_rx_dma_state; 517 state = 0; 518 519 /* disable any DMA */ 520 ssr = bus_space_read_4(sc->sc_bst, sc->sc_bsh, IOASIC_CSR); 521 ssr &= ~IOASIC_CSR_DMAEN_ISDN_R; 522 bus_space_write_4(sc->sc_bst, sc->sc_bsh, IOASIC_CSR, ssr); 523 524 d->size = (vaddr_t)end - (vaddr_t)start; 525 if (bus_dmamap_create(sc->sc_dmat, d->size, 526 BBA_MAX_DMA_SEGMENTS, IOASIC_DMA_BLOCKSIZE, 527 BBA_DMABUF_BOUNDARY, BUS_DMA_NOWAIT, &d->dmam)) { 528 printf("bba_trigger_input: can't create DMA map\n"); 529 goto bad; 530 } 531 state |= 1; 532 533 if (bus_dmamap_load(sc->sc_dmat, d->dmam, start, d->size, NULL, 534 BUS_DMA_READ | BUS_DMA_NOWAIT)) { 535 printf("bba_trigger_input: can't load DMA map\n"); 536 goto bad; 537 } 538 bus_dmamap_sync(sc->sc_dmat, d->dmam, 0, d->size, BUS_DMASYNC_PREREAD); 539 state |= 2; 540 541 d->intr = intr; 542 d->intr_arg = arg; 543 d->curseg = 1; 544 545 /* get physical address of buffer start */ 546 phys = (tc_addr_t)d->dmam->dm_segs[0].ds_addr; 547 nphys = (tc_addr_t)d->dmam->dm_segs[1 % d->dmam->dm_nsegs].ds_addr; 548 549 /* setup DMA pointer */ 550 bus_space_write_4(sc->sc_bst, sc->sc_bsh, IOASIC_ISDN_R_DMAPTR, 551 IOASIC_DMA_ADDR(phys)); 552 bus_space_write_4(sc->sc_bst, sc->sc_bsh, IOASIC_ISDN_R_NEXTPTR, 553 IOASIC_DMA_ADDR(nphys)); 554 555 /* kick off DMA */ 556 mtx_enter(&audio_lock); 557 ssr |= IOASIC_CSR_DMAEN_ISDN_R; 558 bus_space_write_4(sc->sc_bst, sc->sc_bsh, IOASIC_CSR, ssr); 559 560 d->active = 1; 561 mtx_leave(&audio_lock); 562 return 0; 563 564bad: 565 if (state & 2) 566 bus_dmamap_unload(sc->sc_dmat, d->dmam); 567 if (state & 1) 568 bus_dmamap_destroy(sc->sc_dmat, d->dmam); 569 return 1; 570} 571 572int 573bba_intr(void *v) 574{ 575 struct bba_softc *sc = v; 576 struct bba_dma_state *d; 577 tc_addr_t nphys; 578 int mask; 579 580 mtx_enter(&audio_lock); 581 582 mask = bus_space_read_4(sc->sc_bst, sc->sc_bsh, IOASIC_INTR); 583 584 if (mask & IOASIC_INTR_ISDN_TXLOAD) { 585 d = &sc->sc_tx_dma_state; 586 d->curseg = (d->curseg+1) % d->dmam->dm_nsegs; 587 nphys = (tc_addr_t)d->dmam->dm_segs[d->curseg].ds_addr; 588 bus_space_write_4(sc->sc_bst, sc->sc_bsh, 589 IOASIC_ISDN_X_NEXTPTR, IOASIC_DMA_ADDR(nphys)); 590 if (d->intr != NULL) 591 (*d->intr)(d->intr_arg); 592 } 593 if (mask & IOASIC_INTR_ISDN_RXLOAD) { 594 d = &sc->sc_rx_dma_state; 595 d->curseg = (d->curseg+1) % d->dmam->dm_nsegs; 596 nphys = (tc_addr_t)d->dmam->dm_segs[d->curseg].ds_addr; 597 bus_space_write_4(sc->sc_bst, sc->sc_bsh, 598 IOASIC_ISDN_R_NEXTPTR, IOASIC_DMA_ADDR(nphys)); 599 if (d->intr != NULL) 600 (*d->intr)(d->intr_arg); 601 } 602 603 mtx_leave(&audio_lock); 604 605 return 0; 606} 607 608int 609bba_get_props(void *v) 610{ 611 return AUDIO_PROP_MMAP | am7930_get_props(v); 612} 613 614paddr_t 615bba_mappage(void *v, void *mem, off_t offset, int prot) 616{ 617 struct bba_softc *sc = v; 618 struct bba_mem **mp; 619 bus_dma_segment_t seg; 620 621 if (offset < 0) 622 return -1; 623 624 for (mp = &sc->sc_mem_head; *mp && (*mp)->kva != mem; 625 mp = &(*mp)->next) 626 continue; 627 if (*mp == NULL) 628 return -1; 629 630 seg.ds_addr = (*mp)->addr; 631 seg.ds_len = (*mp)->size; 632 633 return bus_dmamem_mmap(sc->sc_dmat, &seg, 1, offset, 634 prot, BUS_DMA_WAITOK); 635} 636 637void 638bba_input_conv(void *v, u_char *p, int cc) 639{ 640 struct bba_softc *sc = v; 641 u_char *p0 = p; 642 int cc0 = cc; 643 uint32_t *q = (uint32_t *)p; 644 645 DPRINTF(("bba_input_conv(): v=%p p=%p cc=%d\n", v, p, cc)); 646 647 /* convert data from dma stream - one byte per longword<23:16> */ 648#ifdef __alpha__ 649 /* try to avoid smaller than 32 bit accesses whenever possible */ 650 if (((vaddr_t)p & 3) == 0) { 651 while (cc >= 4) { 652 uint32_t fp; 653 654 /* alpha is little endian */ 655 fp = (*q++ >> 16) & 0xff; 656 fp |= ((*q++ >> 16) & 0xff) << 8; 657 fp |= ((*q++ >> 16) & 0xff) << 16; 658 fp |= ((*q++ >> 16) & 0xff) << 24; 659 *(uint32_t *)p = fp; 660 p += 4; 661 cc -= 4; 662 } 663 } 664#endif 665 while (--cc >= 0) 666 *p++ = (*q++ >> 16) & 0xff; 667 668 /* convert mulaw data to expected encoding if necessary */ 669 if (sc->sc_am7930.rec_sw_code != NULL) 670 (*sc->sc_am7930.rec_sw_code)(v, p0, cc0); 671} 672 673void 674bba_output_conv(void *v, u_char *p, int cc) 675{ 676 struct bba_softc *sc = v; 677 uint32_t *q = (uint32_t *)p; 678 679 DPRINTF(("bba_output_conv(): v=%p p=%p cc=%d\n", v, p, cc)); 680 681 /* convert data to mulaw first if necessary */ 682 if (sc->sc_am7930.play_sw_code != NULL) 683 (*sc->sc_am7930.play_sw_code)(v, p, cc); 684 685 /* convert data to dma stream - one byte per longword<23:16> */ 686 p += cc; 687 q += cc; 688#ifdef __alpha__ 689 /* try to avoid smaller than 32 bit accesses whenever possible */ 690 if (((vaddr_t)p & 3) == 0) { 691 while (cc >= 4) { 692 uint32_t fp; 693 694 p -= 4; 695 fp = *(uint32_t *)p; 696 /* alpha is little endian */ 697 *--q = ((fp >> 24) & 0xff) << 16; 698 *--q = ((fp >> 16) & 0xff) << 16; 699 *--q = ((fp >> 8) & 0xff) << 16; 700 *--q = (fp & 0xff) << 16; 701 cc -= 4; 702 } 703 } 704#endif 705 while (--cc >= 0) 706 *--q = *--p << 16; 707} 708 709int 710bba_round_blocksize(void *v, int blk) 711{ 712 return IOASIC_DMA_BLOCKSIZE; 713} 714 715 716/* indirect write */ 717void 718bba_codec_iwrite(struct am7930_softc *sc, int reg, uint8_t val) 719{ 720 DPRINTF(("bba_codec_iwrite(): sc=%p, reg=%02x, val=%02x\n", sc, reg, val)); 721 bba_codec_dwrite(sc, AM7930_DREG_CR, reg); 722 bba_codec_dwrite(sc, AM7930_DREG_DR, val); 723} 724 725 726void 727bba_codec_iwrite16(struct am7930_softc *sc, int reg, uint16_t val) 728{ 729 DPRINTF(("bba_codec_iwrite16(): sc=%p, reg=%02x, val=%04x\n", sc, reg, val)); 730 bba_codec_dwrite(sc, AM7930_DREG_CR, reg); 731 bba_codec_dwrite(sc, AM7930_DREG_DR, val); 732 bba_codec_dwrite(sc, AM7930_DREG_DR, val >> 8); 733} 734 735 736/* indirect read */ 737uint8_t 738bba_codec_iread(struct am7930_softc *sc, int reg) 739{ 740 uint8_t val; 741 742 DPRINTF(("bba_codec_iread(): sc=%p, reg=%02x\n", sc, reg)); 743 bba_codec_dwrite(sc, AM7930_DREG_CR, reg); 744 val = bba_codec_dread(sc, AM7930_DREG_DR); 745 746 DPRINTF(("read 0x%02x (%d)\n", val, val)); 747 748 return val; 749} 750 751uint16_t 752bba_codec_iread16(struct am7930_softc *sc, int reg) 753{ 754 uint16_t val; 755 756 DPRINTF(("bba_codec_iread16(): sc=%p, reg=%02x\n", sc, reg)); 757 bba_codec_dwrite(sc, AM7930_DREG_CR, reg); 758 val = bba_codec_dread(sc, AM7930_DREG_DR); 759 val |= bba_codec_dread(sc, AM7930_DREG_DR) << 8; 760 761 return val; 762} 763 764 765/* direct write */ 766void 767bba_codec_dwrite(struct am7930_softc *asc, int reg, uint8_t val) 768{ 769 struct bba_softc *sc = (struct bba_softc *)asc; 770 771#if defined(__alpha__) 772 bus_space_write_4(sc->sc_bst, sc->sc_codec_bsh, reg << 2, val << 8); 773#else 774 bus_space_write_4(sc->sc_bst, sc->sc_codec_bsh, reg << 6, val); 775#endif 776} 777 778/* direct read */ 779uint8_t 780bba_codec_dread(struct am7930_softc *asc, int reg) 781{ 782 struct bba_softc *sc = (struct bba_softc *)asc; 783 784#if defined(__alpha__) 785 return (bus_space_read_4(sc->sc_bst, sc->sc_codec_bsh, reg << 2) >> 8) & 786 0xff; 787#else 788 return bus_space_read_4(sc->sc_bst, sc->sc_codec_bsh, reg << 6) & 0xff; 789#endif 790} 791