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