1/* $NetBSD: cs4231.c,v 1.32 2019/11/10 21:16:35 chs 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 * 19 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 20 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 21 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 22 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 23 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 24 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 25 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 26 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 27 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 28 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 29 * POSSIBILITY OF SUCH DAMAGE. 30 */ 31 32#include <sys/cdefs.h> 33__KERNEL_RCSID(0, "$NetBSD: cs4231.c,v 1.32 2019/11/10 21:16:35 chs Exp $"); 34 35#include "audio.h" 36#if NAUDIO > 0 37 38#include <sys/param.h> 39#include <sys/systm.h> 40#include <sys/errno.h> 41#include <sys/device.h> 42#include <sys/bus.h> 43#include <sys/kmem.h> 44#include <sys/malloc.h> 45 46#include <machine/autoconf.h> 47#include <sys/cpu.h> 48 49#include <sys/audioio.h> 50#include <dev/audio/audio_if.h> 51 52#include <dev/ic/ad1848reg.h> 53#include <dev/ic/cs4231reg.h> 54#include <dev/ic/ad1848var.h> 55#include <dev/ic/cs4231var.h> 56 57/*---*/ 58#define CSAUDIO_DAC_LVL 0 59#define CSAUDIO_LINE_IN_LVL 1 60#define CSAUDIO_MONO_LVL 2 61#define CSAUDIO_CD_LVL 3 62#define CSAUDIO_OUTPUT_LVL 4 63#define CSAUDIO_OUT_LVL 5 64#define CSAUDIO_LINE_IN_MUTE 6 65#define CSAUDIO_DAC_MUTE 7 66#define CSAUDIO_CD_MUTE 8 67#define CSAUDIO_MONO_MUTE 9 68#define CSAUDIO_OUTPUT_MUTE 10 69#define CSAUDIO_OUT_MUTE 11 70#define CSAUDIO_REC_LVL 12 71#define CSAUDIO_RECORD_SOURCE 13 72 73#define CSAUDIO_INPUT_CLASS 14 74#define CSAUDIO_MONITOR_CLASS 15 75#define CSAUDIO_RECORD_CLASS 16 76 77#ifdef AUDIO_DEBUG 78int cs4231_debug = 0; 79#define DPRINTF(x) if (cs4231_debug) printf x 80#else 81#define DPRINTF(x) 82#endif 83 84struct audio_device cs4231_device = { 85 "cs4231", 86 "x", 87 "audio" 88}; 89 90 91/* ad1848 sc_{read,write}reg */ 92static int cs4231_read(struct ad1848_softc *, int); 93static void cs4231_write(struct ad1848_softc *, int, int); 94 95int 96cs4231_read(struct ad1848_softc *sc, int index) 97{ 98 99 return bus_space_read_1(sc->sc_iot, sc->sc_ioh, (index << 2)); 100} 101 102void 103cs4231_write(struct ad1848_softc *sc, int index, int value) 104{ 105 106 bus_space_write_1(sc->sc_iot, sc->sc_ioh, (index << 2), value); 107} 108 109 110void 111cs4231_common_attach(struct cs4231_softc *sc, device_t self, 112 bus_space_handle_t ioh) 113{ 114 char *buf; 115 int reg; 116 117 sc->sc_ad1848.parent = sc; 118 sc->sc_ad1848.sc_dev = self; 119 sc->sc_ad1848.sc_iot = sc->sc_bustag; 120 sc->sc_ad1848.sc_ioh = ioh; 121 sc->sc_ad1848.sc_readreg = cs4231_read; 122 sc->sc_ad1848.sc_writereg = cs4231_write; 123 124 sc->sc_playback.t_name = "playback"; 125 sc->sc_capture.t_name = "capture"; 126 127 evcnt_attach_dynamic(&sc->sc_intrcnt, EVCNT_TYPE_INTR, 128 NULL, 129 device_xname(sc->sc_ad1848.sc_dev), "total"); 130 131 evcnt_attach_dynamic(&sc->sc_playback.t_intrcnt, EVCNT_TYPE_INTR, 132 &sc->sc_intrcnt, 133 device_xname(sc->sc_ad1848.sc_dev), "playback"); 134 135 evcnt_attach_dynamic(&sc->sc_playback.t_ierrcnt, EVCNT_TYPE_INTR, 136 &sc->sc_intrcnt, 137 device_xname(sc->sc_ad1848.sc_dev), "perrors"); 138 139 evcnt_attach_dynamic(&sc->sc_capture.t_intrcnt, EVCNT_TYPE_INTR, 140 &sc->sc_intrcnt, 141 device_xname(sc->sc_ad1848.sc_dev), "capture"); 142 143 evcnt_attach_dynamic(&sc->sc_capture.t_ierrcnt, EVCNT_TYPE_INTR, 144 &sc->sc_intrcnt, 145 device_xname(sc->sc_ad1848.sc_dev), "cerrors"); 146 147 /* put chip in native mode to access (extended) ID register */ 148 reg = ad_read(&sc->sc_ad1848, SP_MISC_INFO); 149 ad_write(&sc->sc_ad1848, SP_MISC_INFO, reg | MODE2); 150 151 /* read version numbers from I25 */ 152 reg = ad_read(&sc->sc_ad1848, CS_VERSION_ID); 153 switch (reg & (CS_VERSION_NUMBER | CS_VERSION_CHIPID)) { 154 case 0xa0: 155 sc->sc_ad1848.chip_name = "CS4231A"; 156 break; 157 case 0x80: 158 sc->sc_ad1848.chip_name = "CS4231"; 159 break; 160 case 0x82: 161 sc->sc_ad1848.chip_name = "CS4232"; 162 break; 163 case 0xa2: 164 sc->sc_ad1848.chip_name = "CS4232C"; 165 break; 166 default: 167 buf = malloc(32, M_TEMP, M_WAITOK); 168 snprintf(buf, 32, "unknown rev: %x/%x", 169 reg&0xe0, reg&7); 170 sc->sc_ad1848.chip_name = buf; 171 } 172 173 sc->sc_ad1848.mode = 2; /* put ad1848 driver in `MODE 2' mode */ 174 ad1848_attach(&sc->sc_ad1848); 175} 176 177void * 178cs4231_malloc(void *addr, int direction, size_t size) 179{ 180 struct cs4231_softc *sc; 181 bus_dma_tag_t dmatag; 182 struct cs_dma *p; 183 184 sc = addr; 185 dmatag = sc->sc_dmatag; 186 p = kmem_alloc(sizeof(*p), KM_SLEEP); 187 188 /* Allocate a DMA map */ 189 if (bus_dmamap_create(dmatag, size, 1, size, 0, 190 BUS_DMA_NOWAIT, &p->dmamap) != 0) 191 goto fail1; 192 193 /* Allocate DMA memory */ 194 p->size = size; 195 if (bus_dmamem_alloc(dmatag, size, 64*1024, 0, 196 p->segs, sizeof(p->segs)/sizeof(p->segs[0]), 197 &p->nsegs, BUS_DMA_NOWAIT) != 0) 198 goto fail2; 199 200 /* Map DMA memory into kernel space */ 201 if (bus_dmamem_map(dmatag, p->segs, p->nsegs, p->size, 202 &p->addr, BUS_DMA_NOWAIT|BUS_DMA_COHERENT) != 0) 203 goto fail3; 204 205 /* Load the buffer */ 206 if (bus_dmamap_load(dmatag, p->dmamap, 207 p->addr, size, NULL, BUS_DMA_NOWAIT) != 0) 208 goto fail4; 209 210 p->next = sc->sc_dmas; 211 sc->sc_dmas = p; 212 return p->addr; 213 214fail4: 215 bus_dmamem_unmap(dmatag, p->addr, p->size); 216fail3: 217 bus_dmamem_free(dmatag, p->segs, p->nsegs); 218fail2: 219 bus_dmamap_destroy(dmatag, p->dmamap); 220fail1: 221 kmem_free(p, sizeof(*p)); 222 return NULL; 223} 224 225void 226cs4231_free(void *addr, void *ptr, size_t size) 227{ 228 struct cs4231_softc *sc; 229 bus_dma_tag_t dmatag; 230 struct cs_dma *p, **pp; 231 232 sc = addr; 233 dmatag = sc->sc_dmatag; 234 for (pp = &sc->sc_dmas; (p = *pp) != NULL; pp = &(*pp)->next) { 235 if (p->addr != ptr) 236 continue; 237 bus_dmamap_unload(dmatag, p->dmamap); 238 bus_dmamem_unmap(dmatag, p->addr, p->size); 239 bus_dmamem_free(dmatag, p->segs, p->nsegs); 240 bus_dmamap_destroy(dmatag, p->dmamap); 241 *pp = p->next; 242 kmem_free(p, sizeof(*p)); 243 return; 244 } 245 printf("cs4231_free: rogue pointer\n"); 246} 247 248 249/* 250 * Set up transfer and return DMA address and byte count in paddr and psize 251 * for bus dependent trigger_{in,out}put to load into the DMA controller. 252 */ 253int 254cs4231_transfer_init( 255 struct cs4231_softc *sc, 256 struct cs_transfer *t, 257 bus_addr_t *paddr, 258 bus_size_t *psize, 259 void *start, void *end, 260 int blksize, 261 void (*intr)(void *), 262 void *arg) 263{ 264 struct cs_dma *p; 265 vsize_t n; 266 267 if (t->t_active) { 268 printf("%s: %s already running\n", 269 device_xname(sc->sc_ad1848.sc_dev), t->t_name); 270 return EINVAL; 271 } 272 273 t->t_intr = intr; 274 t->t_arg = arg; 275 276 for (p = sc->sc_dmas; p != NULL && p->addr != start; p = p->next) 277 continue; 278 if (p == NULL) { 279 printf("%s: bad %s addr %p\n", 280 device_xname(sc->sc_ad1848.sc_dev), t->t_name, start); 281 return EINVAL; 282 } 283 284 n = (char *)end - (char *)start; 285 286 t->t_dma = p; /* the DMA memory segment */ 287 t->t_segsz = n; /* size of DMA segment */ 288 t->t_blksz = blksize; /* do transfers in blksize chunks */ 289 290 if (n > t->t_blksz) 291 n = t->t_blksz; 292 293 t->t_cnt = n; 294 295 /* for caller to load into DMA controller */ 296 *paddr = t->t_dma->dmamap->dm_segs[0].ds_addr; 297 *psize = n; 298 299 DPRINTF(("%s: init %s: [%p..%p] %lu bytes %lu blocks;" 300 " DMA at 0x%lx count %lu\n", 301 device_xname(sc->sc_ad1848.sc_dev), t->t_name, 302 start, end, (u_long)t->t_segsz, (u_long)t->t_blksz, 303 (u_long)*paddr, (u_long)*psize)); 304 305 t->t_active = 1; 306 return 0; 307} 308 309/* 310 * Compute next DMA address/counter, update transfer status. 311 */ 312void 313cs4231_transfer_advance(struct cs_transfer *t, bus_addr_t *paddr, 314 bus_size_t *psize) 315{ 316 bus_addr_t dmabase, nextaddr; 317 bus_size_t togo; 318 319 dmabase = t->t_dma->dmamap->dm_segs[0].ds_addr; 320 321 togo = t->t_segsz - t->t_cnt; 322 if (togo == 0) { /* roll over */ 323 nextaddr = dmabase; 324 t->t_cnt = togo = t->t_blksz; 325 } else { 326 nextaddr = dmabase + t->t_cnt; 327 if (togo > t->t_blksz) 328 togo = t->t_blksz; 329 t->t_cnt += togo; 330 } 331 332 /* for caller to load into DMA controller */ 333 *paddr = nextaddr; 334 *psize = togo; 335} 336 337 338int 339cs4231_open(void *addr, int flags) 340{ 341 struct cs4231_softc *sc; 342 343 sc = addr; 344 DPRINTF(("sa_open: unit %p\n", sc)); 345 346 sc->sc_playback.t_active = 0; 347 sc->sc_playback.t_intr = NULL; 348 sc->sc_playback.t_arg = NULL; 349 350 sc->sc_capture.t_active = 0; 351 sc->sc_capture.t_intr = NULL; 352 sc->sc_capture.t_arg = NULL; 353 354 /* no interrupts from ad1848 */ 355 ad_write(&sc->sc_ad1848, SP_PIN_CONTROL, 0); 356 ad1848_reset(&sc->sc_ad1848); 357 358 DPRINTF(("sa_open: ok -> sc=%p\n", sc)); 359 return 0; 360} 361 362void 363cs4231_close(void *addr) 364{ 365 366 DPRINTF(("sa_close: sc=%p\n", addr)); 367 368 /* audio(9) already called halt methods */ 369 370 DPRINTF(("sa_close: closed.\n")); 371} 372 373int 374cs4231_getdev(void *addr, struct audio_device *retp) 375{ 376 377 *retp = cs4231_device; 378 return 0; 379} 380 381static const ad1848_devmap_t csmapping[] = { 382 { CSAUDIO_DAC_LVL, AD1848_KIND_LVL, AD1848_AUX1_CHANNEL }, 383 { CSAUDIO_LINE_IN_LVL, AD1848_KIND_LVL, AD1848_LINE_CHANNEL }, 384 { CSAUDIO_MONO_LVL, AD1848_KIND_LVL, AD1848_MONO_CHANNEL }, 385 { CSAUDIO_CD_LVL, AD1848_KIND_LVL, AD1848_AUX2_CHANNEL }, 386 { CSAUDIO_OUTPUT_LVL, AD1848_KIND_LVL, AD1848_MONITOR_CHANNEL }, 387 { CSAUDIO_OUT_LVL, AD1848_KIND_LVL, AD1848_DAC_CHANNEL }, 388 { CSAUDIO_DAC_MUTE, AD1848_KIND_MUTE, AD1848_AUX1_CHANNEL }, 389 { CSAUDIO_LINE_IN_MUTE, AD1848_KIND_MUTE, AD1848_LINE_CHANNEL }, 390 { CSAUDIO_MONO_MUTE, AD1848_KIND_MUTE, AD1848_MONO_CHANNEL }, 391 { CSAUDIO_CD_MUTE, AD1848_KIND_MUTE, AD1848_AUX2_CHANNEL }, 392 { CSAUDIO_OUTPUT_MUTE, AD1848_KIND_MUTE, AD1848_MONITOR_CHANNEL }, 393 { CSAUDIO_OUT_MUTE, AD1848_KIND_MUTE, AD1848_OUT_CHANNEL }, 394 { CSAUDIO_REC_LVL, AD1848_KIND_RECORDGAIN, -1 }, 395 { CSAUDIO_RECORD_SOURCE, AD1848_KIND_RECORDSOURCE, -1 } 396}; 397 398static int nummap = sizeof(csmapping) / sizeof(csmapping[0]); 399 400 401int 402cs4231_set_port(void *addr, mixer_ctrl_t *cp) 403{ 404 struct ad1848_softc *ac; 405 406 DPRINTF(("cs4231_set_port: port=%d", cp->dev)); 407 ac = addr; 408 return ad1848_mixer_set_port(ac, csmapping, nummap, cp); 409} 410 411int 412cs4231_get_port(void *addr, mixer_ctrl_t *cp) 413{ 414 struct ad1848_softc *ac; 415 416 DPRINTF(("cs4231_get_port: port=%d", cp->dev)); 417 ac = addr; 418 return ad1848_mixer_get_port(ac, csmapping, nummap, cp); 419} 420 421int 422cs4231_get_props(void *addr) 423{ 424 425 return AUDIO_PROP_PLAYBACK | AUDIO_PROP_CAPTURE | 426 AUDIO_PROP_FULLDUPLEX; 427} 428 429int 430cs4231_query_devinfo(void *addr, mixer_devinfo_t *dip) 431{ 432 433 switch(dip->index) { 434 435 case CSAUDIO_DAC_LVL: /* dacout */ 436 dip->type = AUDIO_MIXER_VALUE; 437 dip->mixer_class = CSAUDIO_INPUT_CLASS; 438 dip->prev = AUDIO_MIXER_LAST; 439 dip->next = CSAUDIO_DAC_MUTE; 440 strcpy(dip->label.name, AudioNdac); 441 dip->un.v.num_channels = 2; 442 strcpy(dip->un.v.units.name, AudioNvolume); 443 break; 444 445 case CSAUDIO_LINE_IN_LVL: /* line */ 446 dip->type = AUDIO_MIXER_VALUE; 447 dip->mixer_class = CSAUDIO_INPUT_CLASS; 448 dip->prev = AUDIO_MIXER_LAST; 449 dip->next = CSAUDIO_LINE_IN_MUTE; 450 strcpy(dip->label.name, AudioNline); 451 dip->un.v.num_channels = 2; 452 strcpy(dip->un.v.units.name, AudioNvolume); 453 break; 454 455 case CSAUDIO_MONO_LVL: /* mono/microphone mixer */ 456 dip->type = AUDIO_MIXER_VALUE; 457 dip->mixer_class = CSAUDIO_INPUT_CLASS; 458 dip->prev = AUDIO_MIXER_LAST; 459 dip->next = CSAUDIO_MONO_MUTE; 460 strcpy(dip->label.name, AudioNmicrophone); 461 dip->un.v.num_channels = 1; 462 strcpy(dip->un.v.units.name, AudioNvolume); 463 break; 464 465 case CSAUDIO_CD_LVL: /* cd */ 466 dip->type = AUDIO_MIXER_VALUE; 467 dip->mixer_class = CSAUDIO_INPUT_CLASS; 468 dip->prev = AUDIO_MIXER_LAST; 469 dip->next = CSAUDIO_CD_MUTE; 470 strcpy(dip->label.name, AudioNcd); 471 dip->un.v.num_channels = 2; 472 strcpy(dip->un.v.units.name, AudioNvolume); 473 break; 474 475 476 case CSAUDIO_OUTPUT_LVL: /* monitor level */ 477 dip->type = AUDIO_MIXER_VALUE; 478 dip->mixer_class = CSAUDIO_MONITOR_CLASS; 479 dip->next = CSAUDIO_OUTPUT_MUTE; 480 dip->prev = AUDIO_MIXER_LAST; 481 strcpy(dip->label.name, AudioNmonitor); 482 dip->un.v.num_channels = 1; 483 strcpy(dip->un.v.units.name, AudioNvolume); 484 break; 485 486 case CSAUDIO_OUT_LVL: /* cs4231 output volume */ 487 dip->type = AUDIO_MIXER_VALUE; 488 dip->mixer_class = CSAUDIO_MONITOR_CLASS; 489 dip->next = dip->prev = AUDIO_MIXER_LAST; 490 strcpy(dip->label.name, AudioNmaster); 491 dip->un.v.num_channels = 2; 492 dip->un.v.delta = 16; 493 strcpy(dip->un.v.units.name, AudioNvolume); 494 break; 495 496 case CSAUDIO_OUT_MUTE: /* mute built-in speaker */ 497 dip->mixer_class = CSAUDIO_MONITOR_CLASS; 498 dip->type = AUDIO_MIXER_ENUM; 499 dip->prev = CSAUDIO_MONITOR_CLASS; 500 dip->next = AUDIO_MIXER_LAST; 501 strcpy(dip->label.name, AudioNmono); 502 /* names reversed, this is a "mute" value used as "mono enabled" */ 503 dip->un.e.num_mem = 2; 504 strcpy(dip->un.e.member[0].label.name, AudioNon); 505 dip->un.e.member[0].ord = 0; 506 strcpy(dip->un.e.member[1].label.name, AudioNoff); 507 dip->un.e.member[1].ord = 1; 508 break; 509 510 case CSAUDIO_LINE_IN_MUTE: 511 dip->mixer_class = CSAUDIO_INPUT_CLASS; 512 dip->type = AUDIO_MIXER_ENUM; 513 dip->prev = CSAUDIO_LINE_IN_LVL; 514 dip->next = AUDIO_MIXER_LAST; 515 goto mute; 516 517 case CSAUDIO_DAC_MUTE: 518 dip->mixer_class = CSAUDIO_INPUT_CLASS; 519 dip->type = AUDIO_MIXER_ENUM; 520 dip->prev = CSAUDIO_DAC_LVL; 521 dip->next = AUDIO_MIXER_LAST; 522 goto mute; 523 524 case CSAUDIO_CD_MUTE: 525 dip->mixer_class = CSAUDIO_INPUT_CLASS; 526 dip->type = AUDIO_MIXER_ENUM; 527 dip->prev = CSAUDIO_CD_LVL; 528 dip->next = AUDIO_MIXER_LAST; 529 goto mute; 530 531 case CSAUDIO_MONO_MUTE: 532 dip->mixer_class = CSAUDIO_INPUT_CLASS; 533 dip->type = AUDIO_MIXER_ENUM; 534 dip->prev = CSAUDIO_MONO_LVL; 535 dip->next = AUDIO_MIXER_LAST; 536 goto mute; 537 538 case CSAUDIO_OUTPUT_MUTE: 539 dip->mixer_class = CSAUDIO_MONITOR_CLASS; 540 dip->type = AUDIO_MIXER_ENUM; 541 dip->prev = CSAUDIO_OUTPUT_LVL; 542 dip->next = AUDIO_MIXER_LAST; 543 mute: 544 strcpy(dip->label.name, AudioNmute); 545 dip->un.e.num_mem = 2; 546 strcpy(dip->un.e.member[0].label.name, AudioNoff); 547 dip->un.e.member[0].ord = 0; 548 strcpy(dip->un.e.member[1].label.name, AudioNon); 549 dip->un.e.member[1].ord = 1; 550 break; 551 552 case CSAUDIO_REC_LVL: /* record level */ 553 dip->type = AUDIO_MIXER_VALUE; 554 dip->mixer_class = CSAUDIO_RECORD_CLASS; 555 dip->prev = AUDIO_MIXER_LAST; 556 dip->next = CSAUDIO_RECORD_SOURCE; 557 strcpy(dip->label.name, AudioNrecord); 558 dip->un.v.num_channels = 2; 559 strcpy(dip->un.v.units.name, AudioNvolume); 560 break; 561 562 case CSAUDIO_RECORD_SOURCE: 563 dip->mixer_class = CSAUDIO_RECORD_CLASS; 564 dip->type = AUDIO_MIXER_ENUM; 565 dip->prev = CSAUDIO_REC_LVL; 566 dip->next = AUDIO_MIXER_LAST; 567 strcpy(dip->label.name, AudioNsource); 568 dip->un.e.num_mem = 4; 569 strcpy(dip->un.e.member[0].label.name, AudioNoutput); 570 dip->un.e.member[0].ord = DAC_IN_PORT; 571 strcpy(dip->un.e.member[1].label.name, AudioNmicrophone); 572 dip->un.e.member[1].ord = MIC_IN_PORT; 573 strcpy(dip->un.e.member[2].label.name, AudioNdac); 574 dip->un.e.member[2].ord = AUX1_IN_PORT; 575 strcpy(dip->un.e.member[3].label.name, AudioNline); 576 dip->un.e.member[3].ord = LINE_IN_PORT; 577 break; 578 579 case CSAUDIO_INPUT_CLASS: /* input class descriptor */ 580 dip->type = AUDIO_MIXER_CLASS; 581 dip->mixer_class = CSAUDIO_INPUT_CLASS; 582 dip->next = dip->prev = AUDIO_MIXER_LAST; 583 strcpy(dip->label.name, AudioCinputs); 584 break; 585 586 case CSAUDIO_MONITOR_CLASS: /* output class descriptor */ 587 dip->type = AUDIO_MIXER_CLASS; 588 dip->mixer_class = CSAUDIO_MONITOR_CLASS; 589 dip->next = dip->prev = AUDIO_MIXER_LAST; 590 strcpy(dip->label.name, AudioCoutputs); 591 break; 592 593 case CSAUDIO_RECORD_CLASS: /* record source class */ 594 dip->type = AUDIO_MIXER_CLASS; 595 dip->mixer_class = CSAUDIO_RECORD_CLASS; 596 dip->next = dip->prev = AUDIO_MIXER_LAST; 597 strcpy(dip->label.name, AudioCrecord); 598 break; 599 600 default: 601 return ENXIO; 602 /*NOTREACHED*/ 603 } 604 DPRINTF(("AUDIO_MIXER_DEVINFO: name=%s\n", dip->label.name)); 605 606 return 0; 607} 608 609#endif /* NAUDIO > 0 */ 610