1 /* $NetBSD: cs4231.c,v 1.3 2000/03/30 12:45:30 augustss Exp $ */ 2 3 /*- 4 * Copyright (c) 1998, 1999 The NetBSD Foundation, Inc. 5 * All rights reserved. 6 * 7 * This code is derived from software contributed to The NetBSD Foundation 8 * by Paul Kranenburg. 9 * 10 * Redistribution and use in source and binary forms, with or without 11 * modification, are permitted provided that the following conditions 12 * are met: 13 * 1. Redistributions of source code must retain the above copyright 14 * notice, this list of conditions and the following disclaimer. 15 * 2. Redistributions in binary form must reproduce the above copyright 16 * notice, this list of conditions and the following disclaimer in the 17 * documentation and/or other materials provided with the distribution. 18 * 3. All advertising materials mentioning features or use of this software 19 * must display the following acknowledgement: 20 * This product includes software developed by the NetBSD 21 * Foundation, Inc. and its contributors. 22 * 4. Neither the name of The NetBSD Foundation nor the names of its 23 * contributors may be used to endorse or promote products derived 24 * from this software without specific prior written permission. 25 * 26 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 27 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 28 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 29 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 30 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 31 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 32 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 33 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 34 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 35 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 36 * POSSIBILITY OF SUCH DAMAGE. 37 */ 38 39 #include "audio.h" 40 #if NAUDIO > 0 41 42 #include <sys/param.h> 43 #include <sys/systm.h> 44 #include <sys/errno.h> 45 #include <sys/device.h> 46 #include <sys/malloc.h> 47 48 #include <machine/autoconf.h> 49 #include <machine/cpu.h> 50 51 #include <sys/audioio.h> 52 #include <dev/audio_if.h> 53 54 #include <dev/ic/ad1848reg.h> 55 #include <dev/ic/cs4231reg.h> 56 #include <dev/ic/ad1848var.h> 57 #include <dev/ic/cs4231var.h> 58 #include <dev/ic/apcdmareg.h> 59 60 /*---*/ 61 #define CSAUDIO_DAC_LVL 0 62 #define CSAUDIO_LINE_IN_LVL 1 63 #define CSAUDIO_MONO_LVL 2 64 #define CSAUDIO_CD_LVL 3 65 #define CSAUDIO_MONITOR_LVL 4 66 #define CSAUDIO_OUT_LVL 5 67 #define CSAUDIO_LINE_IN_MUTE 6 68 #define CSAUDIO_DAC_MUTE 7 69 #define CSAUDIO_CD_MUTE 8 70 #define CSAUDIO_MONO_MUTE 9 71 #define CSAUDIO_MONITOR_MUTE 10 72 #define CSAUDIO_REC_LVL 11 73 #define CSAUDIO_RECORD_SOURCE 12 74 75 #define CSAUDIO_INPUT_CLASS 13 76 #define CSAUDIO_OUTPUT_CLASS 14 77 #define CSAUDIO_RECORD_CLASS 15 78 #define CSAUDIO_MONITOR_CLASS 16 79 80 #ifdef AUDIO_DEBUG 81 int cs4231debug = 0; 82 #define DPRINTF(x) if (cs4231debug) printf x 83 #else 84 #define DPRINTF(x) 85 #endif 86 87 struct audio_device cs4231_device = { 88 "cs4231", 89 "x", 90 "audio" 91 }; 92 93 94 /* 95 * Define our interface to the higher level audio driver. 96 */ 97 int cs4231_open __P((void *, int)); 98 void cs4231_close __P((void *)); 99 size_t cs4231_round_buffersize __P((void *, int, size_t)); 100 int cs4231_round_blocksize __P((void *, int)); 101 int cs4231_halt_output __P((void *)); 102 int cs4231_halt_input __P((void *)); 103 int cs4231_getdev __P((void *, struct audio_device *)); 104 int cs4231_set_port __P((void *, mixer_ctrl_t *)); 105 int cs4231_get_port __P((void *, mixer_ctrl_t *)); 106 int cs4231_query_devinfo __P((void *, mixer_devinfo_t *)); 107 int cs4231_get_props __P((void *)); 108 109 void *cs4231_malloc __P((void *, int, size_t, int, int)); 110 void cs4231_free __P((void *, void *, int)); 111 int cs4231_trigger_output __P((void *, void *, void *, int, 112 void (*)(void *), void *, 113 struct audio_params *)); 114 int cs4231_trigger_input __P((void *, void *, void *, int, 115 void (*)(void *), void *, 116 struct audio_params *)); 117 118 #ifdef AUDIO_DEBUG 119 static void cs4231_regdump __P((char *, struct cs4231_softc *)); 120 #endif 121 122 int 123 cs4231_read(sc, index) 124 struct ad1848_softc *sc; 125 int index; 126 { 127 return bus_space_read_1(sc->sc_iot, sc->sc_ioh, (index << 2)); 128 } 129 130 void 131 cs4231_write(sc, index, value) 132 struct ad1848_softc *sc; 133 int index, value; 134 { 135 bus_space_write_1(sc->sc_iot, sc->sc_ioh, (index << 2), value); 136 } 137 138 struct audio_hw_if audiocs_hw_if = { 139 cs4231_open, 140 cs4231_close, 141 0, 142 ad1848_query_encoding, 143 ad1848_set_params, 144 cs4231_round_blocksize, 145 ad1848_commit_settings, 146 0, 147 0, 148 NULL, 149 NULL, 150 cs4231_halt_output, 151 cs4231_halt_input, 152 0, 153 cs4231_getdev, 154 0, 155 cs4231_set_port, 156 cs4231_get_port, 157 cs4231_query_devinfo, 158 cs4231_malloc, 159 cs4231_free, 160 cs4231_round_buffersize, 161 0, 162 cs4231_get_props, 163 cs4231_trigger_output, 164 cs4231_trigger_input 165 }; 166 167 168 #ifdef AUDIO_DEBUG 169 static void 170 cs4231_regdump(label, sc) 171 char *label; 172 struct cs4231_softc *sc; 173 { 174 char bits[128]; 175 volatile struct apc_dma *dma = sc->sc_dmareg; 176 177 printf("cs4231regdump(%s): regs:", label); 178 printf("dmapva: 0x%x; ", dma->dmapva); 179 printf("dmapc: 0x%x; ", dma->dmapc); 180 printf("dmapnva: 0x%x; ", dma->dmapnva); 181 printf("dmapnc: 0x%x\n", dma->dmapnc); 182 printf("dmacva: 0x%x; ", dma->dmacva); 183 printf("dmacc: 0x%x; ", dma->dmacc); 184 printf("dmacnva: 0x%x; ", dma->dmacnva); 185 printf("dmacnc: 0x%x\n", dma->dmacnc); 186 187 printf("apc_dmacsr=%s\n", 188 bitmask_snprintf(dma->dmacsr, APC_BITS, bits, sizeof(bits)) ); 189 190 ad1848_dump_regs(&sc->sc_ad1848); 191 } 192 #endif 193 194 void 195 cs4231_init(sc) 196 struct cs4231_softc *sc; 197 { 198 char *buf; 199 #if 0 200 volatile struct apc_dma *dma = sc->sc_dmareg; 201 #endif 202 int reg; 203 204 #if 0 205 dma->dmacsr = APC_CODEC_PDN; 206 delay(20); 207 dma->dmacsr &= ~APC_CODEC_PDN; 208 #endif 209 /* First, put chip in native mode */ 210 reg = ad_read(&sc->sc_ad1848, SP_MISC_INFO); 211 ad_write(&sc->sc_ad1848, SP_MISC_INFO, reg | MODE2); 212 213 /* Read version numbers from I25 */ 214 reg = ad_read(&sc->sc_ad1848, CS_VERSION_ID); 215 switch (reg & (CS_VERSION_NUMBER | CS_VERSION_CHIPID)) { 216 case 0xa0: 217 sc->sc_ad1848.chip_name = "CS4231A"; 218 break; 219 case 0x80: 220 sc->sc_ad1848.chip_name = "CS4231"; 221 break; 222 case 0x82: 223 sc->sc_ad1848.chip_name = "CS4232"; 224 break; 225 default: 226 if ((buf = malloc(32, M_TEMP, M_NOWAIT)) != NULL) { 227 sprintf(buf, "unknown rev: %x/%x", reg&0xe, reg&7); 228 sc->sc_ad1848.chip_name = buf; 229 } 230 } 231 } 232 233 void * 234 cs4231_malloc(addr, direction, size, pool, flags) 235 void *addr; 236 int direction; 237 size_t size; 238 int pool, flags; 239 { 240 struct cs4231_softc *sc = addr; 241 struct cs_dma *p; 242 int error; 243 244 p = malloc(sizeof(*p), pool, flags); 245 if (p == NULL) 246 return (NULL); 247 248 p->size = size; 249 error = bus_dmamem_alloc(sc->sc_dmatag, size, 64*1024, 0, 250 p->segs, sizeof(p->segs)/sizeof(p->segs[0]), 251 &p->nsegs, BUS_DMA_NOWAIT); 252 if (error) { 253 free(p, pool); 254 return (NULL); 255 } 256 257 error = bus_dmamem_map(sc->sc_dmatag, p->segs, p->nsegs, p->size, 258 &p->addr, BUS_DMA_NOWAIT|BUS_DMA_COHERENT); 259 if (error) { 260 bus_dmamem_free(sc->sc_dmatag, p->segs, p->nsegs); 261 free(p, pool); 262 return (NULL); 263 } 264 265 p->next = sc->sc_dmas; 266 sc->sc_dmas = p; 267 return (p->addr); 268 } 269 270 void 271 cs4231_free(addr, ptr, pool) 272 void *addr; 273 void *ptr; 274 int pool; 275 { 276 struct cs4231_softc *sc = addr; 277 struct cs_dma *p, **pp; 278 279 for (pp = &sc->sc_dmas; (p = *pp) != NULL; pp = &(*pp)->next) { 280 if (p->addr != ptr) 281 continue; 282 bus_dmamem_unmap(sc->sc_dmatag, p->addr, p->size); 283 bus_dmamem_free(sc->sc_dmatag, p->segs, p->nsegs); 284 *pp = p->next; 285 free(p, pool); 286 return; 287 } 288 printf("cs4231_free: rogue pointer\n"); 289 } 290 291 int 292 cs4231_open(addr, flags) 293 void *addr; 294 int flags; 295 { 296 struct cs4231_softc *sc = addr; 297 #if 0 298 struct apc_dma *dma = sc->sc_dmareg; 299 #endif 300 301 DPRINTF(("sa_open: unit %p\n", sc)); 302 303 if (sc->sc_open) 304 return (EBUSY); 305 sc->sc_open = 1; 306 sc->sc_locked = 0; 307 sc->sc_rintr = 0; 308 sc->sc_rarg = 0; 309 sc->sc_pintr = 0; 310 sc->sc_parg = 0; 311 #if 1 312 /*No interrupts from ad1848 */ 313 ad_write(&sc->sc_ad1848, SP_PIN_CONTROL, 0); 314 #endif 315 #if 0 316 dma->dmacsr = APC_RESET; 317 delay(10); 318 dma->dmacsr = 0; 319 delay(10); 320 #endif 321 ad1848_reset(&sc->sc_ad1848); 322 323 DPRINTF(("saopen: ok -> sc=%p\n", sc)); 324 return (0); 325 } 326 327 void 328 cs4231_close(addr) 329 void *addr; 330 { 331 struct cs4231_softc *sc = addr; 332 333 DPRINTF(("sa_close: sc=%p\n", sc)); 334 /* 335 * halt i/o, clear open flag, and done. 336 */ 337 cs4231_halt_input(sc); 338 cs4231_halt_output(sc); 339 sc->sc_open = 0; 340 341 DPRINTF(("sa_close: closed.\n")); 342 } 343 344 size_t 345 cs4231_round_buffersize(addr, direction, size) 346 void *addr; 347 int direction; 348 size_t size; 349 { 350 #if 0 351 if (size > APC_MAX) 352 size = APC_MAX; 353 #endif 354 return (size); 355 } 356 357 int 358 cs4231_round_blocksize(addr, blk) 359 void *addr; 360 int blk; 361 { 362 return (blk & -4); 363 } 364 365 int 366 cs4231_getdev(addr, retp) 367 void *addr; 368 struct audio_device *retp; 369 { 370 *retp = cs4231_device; 371 return (0); 372 } 373 374 static ad1848_devmap_t csmapping[] = { 375 { CSAUDIO_DAC_LVL, AD1848_KIND_LVL, AD1848_AUX1_CHANNEL }, 376 { CSAUDIO_LINE_IN_LVL, AD1848_KIND_LVL, AD1848_LINE_CHANNEL }, 377 { CSAUDIO_MONO_LVL, AD1848_KIND_LVL, AD1848_MONO_CHANNEL }, 378 { CSAUDIO_CD_LVL, AD1848_KIND_LVL, AD1848_AUX2_CHANNEL }, 379 { CSAUDIO_MONITOR_LVL, AD1848_KIND_LVL, AD1848_MONITOR_CHANNEL }, 380 { CSAUDIO_OUT_LVL, AD1848_KIND_LVL, AD1848_DAC_CHANNEL }, 381 { CSAUDIO_DAC_MUTE, AD1848_KIND_MUTE, AD1848_AUX1_CHANNEL }, 382 { CSAUDIO_LINE_IN_MUTE, AD1848_KIND_MUTE, AD1848_LINE_CHANNEL }, 383 { CSAUDIO_MONO_MUTE, AD1848_KIND_MUTE, AD1848_MONO_CHANNEL }, 384 { CSAUDIO_CD_MUTE, AD1848_KIND_MUTE, AD1848_AUX2_CHANNEL }, 385 { CSAUDIO_MONITOR_MUTE, AD1848_KIND_MUTE, AD1848_MONITOR_CHANNEL }, 386 { CSAUDIO_REC_LVL, AD1848_KIND_RECORDGAIN, -1 }, 387 { CSAUDIO_RECORD_SOURCE, AD1848_KIND_RECORDSOURCE, -1 } 388 }; 389 390 static int nummap = sizeof(csmapping) / sizeof(csmapping[0]); 391 392 393 int 394 cs4231_set_port(addr, cp) 395 void *addr; 396 mixer_ctrl_t *cp; 397 { 398 struct ad1848_softc *ac = addr; 399 400 DPRINTF(("cs4231_set_port: port=%d", cp->dev)); 401 return (ad1848_mixer_set_port(ac, csmapping, nummap, cp)); 402 } 403 404 int 405 cs4231_get_port(addr, cp) 406 void *addr; 407 mixer_ctrl_t *cp; 408 { 409 struct ad1848_softc *ac = addr; 410 411 DPRINTF(("cs4231_get_port: port=%d", cp->dev)); 412 return (ad1848_mixer_get_port(ac, csmapping, nummap, cp)); 413 } 414 415 int 416 cs4231_get_props(addr) 417 void *addr; 418 { 419 return (AUDIO_PROP_FULLDUPLEX); 420 } 421 422 int 423 cs4231_query_devinfo(addr, dip) 424 void *addr; 425 mixer_devinfo_t *dip; 426 { 427 428 switch(dip->index) { 429 #if 0 430 case CSAUDIO_MIC_IN_LVL: /* Microphone */ 431 dip->type = AUDIO_MIXER_VALUE; 432 dip->mixer_class = CSAUDIO_INPUT_CLASS; 433 dip->prev = AUDIO_MIXER_LAST; 434 dip->next = CSAUDIO_MIC_IN_MUTE; 435 strcpy(dip->label.name, AudioNmicrophone); 436 dip->un.v.num_channels = 2; 437 strcpy(dip->un.v.units.name, AudioNvolume); 438 break; 439 #endif 440 441 case CSAUDIO_MONO_LVL: /* mono/microphone mixer */ 442 dip->type = AUDIO_MIXER_VALUE; 443 dip->mixer_class = CSAUDIO_INPUT_CLASS; 444 dip->prev = AUDIO_MIXER_LAST; 445 dip->next = CSAUDIO_MONO_MUTE; 446 strcpy(dip->label.name, AudioNmicrophone); 447 dip->un.v.num_channels = 1; 448 strcpy(dip->un.v.units.name, AudioNvolume); 449 break; 450 451 case CSAUDIO_DAC_LVL: /* dacout */ 452 dip->type = AUDIO_MIXER_VALUE; 453 dip->mixer_class = CSAUDIO_INPUT_CLASS; 454 dip->prev = AUDIO_MIXER_LAST; 455 dip->next = CSAUDIO_DAC_MUTE; 456 strcpy(dip->label.name, AudioNdac); 457 dip->un.v.num_channels = 2; 458 strcpy(dip->un.v.units.name, AudioNvolume); 459 break; 460 461 case CSAUDIO_LINE_IN_LVL: /* line */ 462 dip->type = AUDIO_MIXER_VALUE; 463 dip->mixer_class = CSAUDIO_INPUT_CLASS; 464 dip->prev = AUDIO_MIXER_LAST; 465 dip->next = CSAUDIO_LINE_IN_MUTE; 466 strcpy(dip->label.name, AudioNline); 467 dip->un.v.num_channels = 2; 468 strcpy(dip->un.v.units.name, AudioNvolume); 469 break; 470 471 case CSAUDIO_CD_LVL: /* cd */ 472 dip->type = AUDIO_MIXER_VALUE; 473 dip->mixer_class = CSAUDIO_INPUT_CLASS; 474 dip->prev = AUDIO_MIXER_LAST; 475 dip->next = CSAUDIO_CD_MUTE; 476 strcpy(dip->label.name, AudioNcd); 477 dip->un.v.num_channels = 2; 478 strcpy(dip->un.v.units.name, AudioNvolume); 479 break; 480 481 482 case CSAUDIO_MONITOR_LVL: /* monitor level */ 483 dip->type = AUDIO_MIXER_VALUE; 484 dip->mixer_class = CSAUDIO_MONITOR_CLASS; 485 dip->next = CSAUDIO_MONITOR_MUTE; 486 dip->prev = AUDIO_MIXER_LAST; 487 strcpy(dip->label.name, AudioNmonitor); 488 dip->un.v.num_channels = 1; 489 strcpy(dip->un.v.units.name, AudioNvolume); 490 break; 491 492 case CSAUDIO_OUT_LVL: /* cs4231 output volume: not useful? */ 493 dip->type = AUDIO_MIXER_VALUE; 494 dip->mixer_class = CSAUDIO_MONITOR_CLASS; 495 dip->prev = dip->next = AUDIO_MIXER_LAST; 496 strcpy(dip->label.name, AudioNoutput); 497 dip->un.v.num_channels = 2; 498 strcpy(dip->un.v.units.name, AudioNvolume); 499 break; 500 501 case CSAUDIO_LINE_IN_MUTE: 502 dip->mixer_class = CSAUDIO_INPUT_CLASS; 503 dip->type = AUDIO_MIXER_ENUM; 504 dip->prev = CSAUDIO_LINE_IN_LVL; 505 dip->next = AUDIO_MIXER_LAST; 506 goto mute; 507 508 case CSAUDIO_DAC_MUTE: 509 dip->mixer_class = CSAUDIO_INPUT_CLASS; 510 dip->type = AUDIO_MIXER_ENUM; 511 dip->prev = CSAUDIO_DAC_LVL; 512 dip->next = AUDIO_MIXER_LAST; 513 goto mute; 514 515 case CSAUDIO_CD_MUTE: 516 dip->mixer_class = CSAUDIO_INPUT_CLASS; 517 dip->type = AUDIO_MIXER_ENUM; 518 dip->prev = CSAUDIO_CD_LVL; 519 dip->next = AUDIO_MIXER_LAST; 520 goto mute; 521 522 case CSAUDIO_MONO_MUTE: 523 dip->mixer_class = CSAUDIO_INPUT_CLASS; 524 dip->type = AUDIO_MIXER_ENUM; 525 dip->prev = CSAUDIO_MONO_LVL; 526 dip->next = AUDIO_MIXER_LAST; 527 goto mute; 528 529 case CSAUDIO_MONITOR_MUTE: 530 dip->mixer_class = CSAUDIO_OUTPUT_CLASS; 531 dip->type = AUDIO_MIXER_ENUM; 532 dip->prev = CSAUDIO_MONITOR_LVL; 533 dip->next = AUDIO_MIXER_LAST; 534 mute: 535 strcpy(dip->label.name, AudioNmute); 536 dip->un.e.num_mem = 2; 537 strcpy(dip->un.e.member[0].label.name, AudioNoff); 538 dip->un.e.member[0].ord = 0; 539 strcpy(dip->un.e.member[1].label.name, AudioNon); 540 dip->un.e.member[1].ord = 1; 541 break; 542 543 case CSAUDIO_REC_LVL: /* record level */ 544 dip->type = AUDIO_MIXER_VALUE; 545 dip->mixer_class = CSAUDIO_RECORD_CLASS; 546 dip->prev = AUDIO_MIXER_LAST; 547 dip->next = CSAUDIO_RECORD_SOURCE; 548 strcpy(dip->label.name, AudioNrecord); 549 dip->un.v.num_channels = 2; 550 strcpy(dip->un.v.units.name, AudioNvolume); 551 break; 552 553 case CSAUDIO_RECORD_SOURCE: 554 dip->mixer_class = CSAUDIO_RECORD_CLASS; 555 dip->type = AUDIO_MIXER_ENUM; 556 dip->prev = CSAUDIO_REC_LVL; 557 dip->next = AUDIO_MIXER_LAST; 558 strcpy(dip->label.name, AudioNsource); 559 dip->un.e.num_mem = 4; 560 strcpy(dip->un.e.member[0].label.name, AudioNoutput); 561 dip->un.e.member[0].ord = DAC_IN_PORT; 562 strcpy(dip->un.e.member[1].label.name, AudioNmicrophone); 563 dip->un.e.member[1].ord = MIC_IN_PORT; 564 strcpy(dip->un.e.member[2].label.name, AudioNdac); 565 dip->un.e.member[2].ord = AUX1_IN_PORT; 566 strcpy(dip->un.e.member[3].label.name, AudioNline); 567 dip->un.e.member[3].ord = LINE_IN_PORT; 568 break; 569 570 case CSAUDIO_INPUT_CLASS: /* input class descriptor */ 571 dip->type = AUDIO_MIXER_CLASS; 572 dip->mixer_class = CSAUDIO_INPUT_CLASS; 573 dip->next = dip->prev = AUDIO_MIXER_LAST; 574 strcpy(dip->label.name, AudioCinputs); 575 break; 576 577 case CSAUDIO_OUTPUT_CLASS: /* output class descriptor */ 578 dip->type = AUDIO_MIXER_CLASS; 579 dip->mixer_class = CSAUDIO_OUTPUT_CLASS; 580 dip->next = dip->prev = AUDIO_MIXER_LAST; 581 strcpy(dip->label.name, AudioCoutputs); 582 break; 583 584 case CSAUDIO_MONITOR_CLASS: /* monitor class descriptor */ 585 dip->type = AUDIO_MIXER_CLASS; 586 dip->mixer_class = CSAUDIO_MONITOR_CLASS; 587 dip->next = dip->prev = AUDIO_MIXER_LAST; 588 strcpy(dip->label.name, AudioCmonitor); 589 break; 590 591 case CSAUDIO_RECORD_CLASS: /* record source class */ 592 dip->type = AUDIO_MIXER_CLASS; 593 dip->mixer_class = CSAUDIO_RECORD_CLASS; 594 dip->next = dip->prev = AUDIO_MIXER_LAST; 595 strcpy(dip->label.name, AudioCrecord); 596 break; 597 598 default: 599 return ENXIO; 600 /*NOTREACHED*/ 601 } 602 DPRINTF(("AUDIO_MIXER_DEVINFO: name=%s\n", dip->label.name)); 603 604 return (0); 605 } 606 607 int 608 cs4231_trigger_output(addr, start, end, blksize, intr, arg, param) 609 void *addr; 610 void *start, *end; 611 int blksize; 612 void (*intr) __P((void *)); 613 void *arg; 614 struct audio_params *param; 615 { 616 struct cs4231_softc *sc = addr; 617 struct cs_dma *p; 618 volatile struct apc_dma *dma = sc->sc_dmareg; 619 int csr; 620 vsize_t n; 621 622 if (sc->sc_locked != 0) { 623 printf("cs4231_trigger_output: already running\n"); 624 return (EINVAL); 625 } 626 627 sc->sc_locked = 1; 628 sc->sc_pintr = intr; 629 sc->sc_parg = arg; 630 631 for (p = sc->sc_dmas; p != NULL && p->addr != start; p = p->next) 632 /*void*/; 633 if (p == NULL) { 634 printf("cs4231_trigger_output: bad addr %p\n", start); 635 return (EINVAL); 636 } 637 638 n = (char *)end - (char *)start; 639 640 /* XXX 641 * Do only `blksize' at a time, so audio_pint() is kept 642 * synchronous with us... 643 */ 644 /*XXX*/sc->sc_blksz = blksize; 645 /*XXX*/sc->sc_nowplaying = p; 646 /*XXX*/sc->sc_playsegsz = n; 647 648 if (n > APC_MAX) 649 n = APC_MAX; 650 651 sc->sc_playcnt = n; 652 653 DPRINTF(("trigger_out: start %p, end %p, size %lu; " 654 "dmaaddr 0x%lx, dmacnt %lu, segsize %lu\n", 655 start, end, (u_long)sc->sc_playsegsz, 656 (u_long)p->segs[0].ds_addr, 657 (u_long)n, (u_long)p->size)); 658 659 csr = dma->dmacsr; 660 dma->dmapnva = (u_long)p->segs[0].ds_addr; 661 dma->dmapnc = (u_long)n; 662 if ((csr & PDMA_GO) == 0 || (csr & APC_PPAUSE) != 0) { 663 int reg; 664 665 dma->dmacsr &= ~(APC_PIE|APC_PPAUSE); 666 dma->dmacsr |= APC_EI|APC_IE|APC_PIE|APC_EIE|APC_PMIE|PDMA_GO; 667 668 /* Start chip */ 669 670 /* Probably should just ignore this.. */ 671 ad_write(&sc->sc_ad1848, SP_LOWER_BASE_COUNT, 0xff); 672 ad_write(&sc->sc_ad1848, SP_UPPER_BASE_COUNT, 0xff); 673 674 reg = ad_read(&sc->sc_ad1848, SP_INTERFACE_CONFIG); 675 ad_write(&sc->sc_ad1848, SP_INTERFACE_CONFIG, 676 (PLAYBACK_ENABLE|reg)); 677 } 678 679 return (0); 680 } 681 682 int 683 cs4231_trigger_input(addr, start, end, blksize, intr, arg, param) 684 void *addr; 685 void *start, *end; 686 int blksize; 687 void (*intr) __P((void *)); 688 void *arg; 689 struct audio_params *param; 690 { 691 return (ENXIO); 692 } 693 694 int 695 cs4231_halt_output(addr) 696 void *addr; 697 { 698 struct cs4231_softc *sc = addr; 699 volatile struct apc_dma *dma = sc->sc_dmareg; 700 int reg; 701 702 dma->dmacsr &= ~(APC_EI | APC_IE | APC_PIE | APC_EIE | PDMA_GO | APC_PMIE); 703 reg = ad_read(&sc->sc_ad1848, SP_INTERFACE_CONFIG); 704 ad_write(&sc->sc_ad1848, SP_INTERFACE_CONFIG, (reg & ~PLAYBACK_ENABLE)); 705 sc->sc_locked = 0; 706 707 return (0); 708 } 709 710 int 711 cs4231_halt_input(addr) 712 void *addr; 713 { 714 struct cs4231_softc *sc = addr; 715 int reg; 716 717 reg = ad_read(&sc->sc_ad1848, SP_INTERFACE_CONFIG); 718 ad_write(&sc->sc_ad1848, SP_INTERFACE_CONFIG, (reg & ~CAPTURE_ENABLE)); 719 sc->sc_locked = 0; 720 721 return (0); 722 } 723 724 725 int 726 cs4231_intr(arg) 727 void *arg; 728 { 729 struct cs4231_softc *sc = arg; 730 volatile struct apc_dma *dma = sc->sc_dmareg; 731 struct cs_dma *p; 732 int ret = 0; 733 int csr; 734 int reg, status; 735 #if defined(DEBUG) || defined(AUDIO_DEBUG) 736 char bits[128]; 737 #endif 738 739 #ifdef AUDIO_DEBUG 740 if (cs4231debug > 1) 741 cs4231_regdump("audiointr", sc); 742 #endif 743 744 /* Read DMA status */ 745 csr = dma->dmacsr; 746 DPRINTF(( 747 "intr: csr=%s; dmapva=0x%lx,dmapc=%lu;dmapnva=0x%lx,dmapnc=%lu\n", 748 bitmask_snprintf(csr, APC_BITS, bits, sizeof(bits)), 749 (u_long)dma->dmapva, (u_long)dma->dmapc, 750 (u_long)dma->dmapnva, (u_long)dma->dmapnc)); 751 752 status = ADREAD(&sc->sc_ad1848, AD1848_STATUS); 753 DPRINTF(("%s: status: %s\n", sc->sc_ad1848.sc_dev.dv_xname, 754 bitmask_snprintf(status, AD_R2_BITS, bits, sizeof(bits)))); 755 if (status & (INTERRUPT_STATUS | SAMPLE_ERROR)) { 756 reg = ad_read(&sc->sc_ad1848, CS_IRQ_STATUS); 757 DPRINTF(("%s: i24: %s\n", sc->sc_ad1848.sc_dev.dv_xname, 758 bitmask_snprintf(reg, CS_I24_BITS, bits, sizeof(bits)))); 759 760 if (reg & CS_IRQ_PI) { 761 ad_write(&sc->sc_ad1848, SP_LOWER_BASE_COUNT, 0xff); 762 ad_write(&sc->sc_ad1848, SP_UPPER_BASE_COUNT, 0xff); 763 } 764 /* Clear interrupt bit */ 765 ADWRITE(&sc->sc_ad1848, AD1848_STATUS, 0); 766 } 767 768 /* Write back DMA status (clears interrupt) */ 769 dma->dmacsr = csr; 770 771 /* 772 * Simplistic.. if "play emtpy" is set advance to next chunk. 773 */ 774 #if 1 775 /* Ack all play interrupts*/ 776 if ((csr & (APC_PI|APC_PD|APC_PIE|APC_PMI)) != 0) 777 ret = 1; 778 #endif 779 if (csr & APC_PM) { 780 u_long nextaddr, togo; 781 782 p = sc->sc_nowplaying; 783 784 togo = sc->sc_playsegsz - sc->sc_playcnt; 785 if (togo == 0) { 786 /* Roll over */ 787 nextaddr = (u_long)p->segs[0].ds_addr; 788 sc->sc_playcnt = togo = APC_MAX; 789 } else { 790 nextaddr = dma->dmapnva + APC_MAX; 791 if (togo > APC_MAX) 792 togo = APC_MAX; 793 sc->sc_playcnt += togo; 794 } 795 796 dma->dmapnva = nextaddr; 797 dma->dmapnc = togo; 798 799 if (sc->sc_pintr != NULL) 800 (*sc->sc_pintr)(sc->sc_parg); 801 802 ret = 1; 803 } 804 805 if (csr & APC_CI) { 806 if (sc->sc_rintr != NULL) { 807 ret = 1; 808 (*sc->sc_rintr)(sc->sc_rarg); 809 } 810 } 811 812 #ifdef DEBUG 813 if (ret == 0) { 814 printf( 815 "oops: csr=%s; dmapva=0x%lx,dmapc=%lu;dmapnva=0x%lx,dmapnc=%lu\n", 816 bitmask_snprintf(csr, APC_BITS, bits, sizeof(bits)), 817 (u_long)dma->dmapva, (u_long)dma->dmapc, 818 (u_long)dma->dmapnva, (u_long)dma->dmapnc); 819 ret = 1; 820 } 821 #endif 822 823 return (ret); 824 } 825 #endif /* NAUDIO > 0 */ 826