1223534Shselasky/* $NetBSD$ */ 2223534Shselasky 3223534Shselasky/* 4223534Shselasky * Copyright (c) 1995 Rolf Grossmann 5223534Shselasky * All rights reserved. 6223534Shselasky * 7223534Shselasky * Redistribution and use in source and binary forms, with or without 8223534Shselasky * modification, are permitted provided that the following conditions 9223534Shselasky * are met: 10223534Shselasky * 1. Redistributions of source code must retain the above copyright 11223534Shselasky * notice, this list of conditions and the following disclaimer. 12223534Shselasky * 2. Redistributions in binary form must reproduce the above copyright 13223534Shselasky * notice, this list of conditions and the following disclaimer in the 14223534Shselasky * documentation and/or other materials provided with the distribution. 15223534Shselasky * 3. All advertising materials mentioning features or use of this software 16223534Shselasky * must display the following acknowledgement: 17223534Shselasky * This product includes software developed by Rolf Grossmann. 18223534Shselasky * 4. The name of the author may not be used to endorse or promote products 19223534Shselasky * derived from this software without specific prior written permission 20223534Shselasky * 21223534Shselasky * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 22223534Shselasky * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 23223534Shselasky * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 24223534Shselasky * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 25223534Shselasky * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 26223534Shselasky * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 27223534Shselasky * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 28223534Shselasky * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 29223534Shselasky * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 30223534Shselasky * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 31223534Shselasky */ 32223534Shselasky 33223534Shselasky/* 34223534Shselasky * Front-end attachment independent layer for AMD 79c30 35223534Shselasky * audio driver. No ISDN support. 36223534Shselasky */ 37223534Shselasky 38223534Shselasky#include <sys/cdefs.h> 39223534Shselasky__KERNEL_RCSID(0, "$NetBSD$"); 40223534Shselasky 41223534Shselasky#include "audio.h" 42223534Shselasky#if NAUDIO > 0 43223534Shselasky 44223534Shselasky#include <sys/param.h> 45223534Shselasky#include <sys/systm.h> 46223534Shselasky#include <sys/errno.h> 47223534Shselasky#include <sys/ioctl.h> 48223534Shselasky#include <sys/device.h> 49223534Shselasky#include <sys/proc.h> 50223534Shselasky 51223534Shselasky#include <sys/bus.h> 52223534Shselasky#include <machine/autoconf.h> 53223534Shselasky#include <sys/cpu.h> 54223534Shselasky 55223534Shselasky#include <sys/audioio.h> 56223534Shselasky#include <dev/audio_if.h> 57223534Shselasky 58223534Shselasky#include <dev/ic/am7930reg.h> 59223534Shselasky#include <dev/ic/am7930var.h> 60223534Shselasky 61223534Shselasky#ifdef AUDIO_DEBUG 62223534Shselaskyint am7930debug = 0; 63223534Shselasky#define DPRINTF(x) if (am7930debug) printf x 64223534Shselasky#else 65223534Shselasky#define DPRINTF(x) 66223534Shselasky#endif 67223534Shselasky 68223534Shselasky 69223534Shselasky/* The following tables stolen from former (4.4Lite's) sys/sparc/bsd_audio.c */ 70223534Shselasky 71223534Shselasky/* 72223534Shselasky * gx, gr & stg gains. this table must contain 256 elements with 73223534Shselasky * the 0th being "infinity" (the magic value 9008). The remaining 74223534Shselasky * elements match sun's gain curve (but with higher resolution): 75223534Shselasky * -18 to 0dB in .16dB steps then 0 to 12dB in .08dB steps. 76223534Shselasky */ 77223534Shselaskystatic const uint16_t gx_coeff[256] = { 78223534Shselasky 0x9008, 0x8e7c, 0x8e51, 0x8e45, 0x8d42, 0x8d3b, 0x8c36, 0x8c33, 79223534Shselasky 0x8b32, 0x8b2a, 0x8b2b, 0x8b2c, 0x8b25, 0x8b23, 0x8b22, 0x8b22, 80223534Shselasky 0x9122, 0x8b1a, 0x8aa3, 0x8aa3, 0x8b1c, 0x8aa6, 0x912d, 0x912b, 81223534Shselasky 0x8aab, 0x8b12, 0x8aaa, 0x8ab2, 0x9132, 0x8ab4, 0x913c, 0x8abb, 82223534Shselasky 0x9142, 0x9144, 0x9151, 0x8ad5, 0x8aeb, 0x8a79, 0x8a5a, 0x8a4a, 83223534Shselasky 0x8b03, 0x91c2, 0x91bb, 0x8a3f, 0x8a33, 0x91b2, 0x9212, 0x9213, 84223534Shselasky 0x8a2c, 0x921d, 0x8a23, 0x921a, 0x9222, 0x9223, 0x922d, 0x9231, 85223534Shselasky 0x9234, 0x9242, 0x925b, 0x92dd, 0x92c1, 0x92b3, 0x92ab, 0x92a4, 86223534Shselasky 0x92a2, 0x932b, 0x9341, 0x93d3, 0x93b2, 0x93a2, 0x943c, 0x94b2, 87223534Shselasky 0x953a, 0x9653, 0x9782, 0x9e21, 0x9d23, 0x9cd2, 0x9c23, 0x9baa, 88223534Shselasky 0x9bde, 0x9b33, 0x9b22, 0x9b1d, 0x9ab2, 0xa142, 0xa1e5, 0x9a3b, 89223534Shselasky 0xa213, 0xa1a2, 0xa231, 0xa2eb, 0xa313, 0xa334, 0xa421, 0xa54b, 90223534Shselasky 0xada4, 0xac23, 0xab3b, 0xaaab, 0xaa5c, 0xb1a3, 0xb2ca, 0xb3bd, 91223534Shselasky 0xbe24, 0xbb2b, 0xba33, 0xc32b, 0xcb5a, 0xd2a2, 0xe31d, 0x0808, 92223534Shselasky 0x72ba, 0x62c2, 0x5c32, 0x52db, 0x513e, 0x4cce, 0x43b2, 0x4243, 93223534Shselasky 0x41b4, 0x3b12, 0x3bc3, 0x3df2, 0x34bd, 0x3334, 0x32c2, 0x3224, 94223534Shselasky 0x31aa, 0x2a7b, 0x2aaa, 0x2b23, 0x2bba, 0x2c42, 0x2e23, 0x25bb, 95223534Shselasky 0x242b, 0x240f, 0x231a, 0x22bb, 0x2241, 0x2223, 0x221f, 0x1a33, 96223534Shselasky 0x1a4a, 0x1acd, 0x2132, 0x1b1b, 0x1b2c, 0x1b62, 0x1c12, 0x1c32, 97223534Shselasky 0x1d1b, 0x1e71, 0x16b1, 0x1522, 0x1434, 0x1412, 0x1352, 0x1323, 98223534Shselasky 0x1315, 0x12bc, 0x127a, 0x1235, 0x1226, 0x11a2, 0x1216, 0x0a2a, 99223534Shselasky 0x11bc, 0x11d1, 0x1163, 0x0ac2, 0x0ab2, 0x0aab, 0x0b1b, 0x0b23, 100223534Shselasky 0x0b33, 0x0c0f, 0x0bb3, 0x0c1b, 0x0c3e, 0x0cb1, 0x0d4c, 0x0ec1, 101223534Shselasky 0x079a, 0x0614, 0x0521, 0x047c, 0x0422, 0x03b1, 0x03e3, 0x0333, 102223534Shselasky 0x0322, 0x031c, 0x02aa, 0x02ba, 0x02f2, 0x0242, 0x0232, 0x0227, 103223534Shselasky 0x0222, 0x021b, 0x01ad, 0x0212, 0x01b2, 0x01bb, 0x01cb, 0x01f6, 104223534Shselasky 0x0152, 0x013a, 0x0133, 0x0131, 0x012c, 0x0123, 0x0122, 0x00a2, 105223534Shselasky 0x011b, 0x011e, 0x0114, 0x00b1, 0x00aa, 0x00b3, 0x00bd, 0x00ba, 106223534Shselasky 0x00c5, 0x00d3, 0x00f3, 0x0062, 0x0051, 0x0042, 0x003b, 0x0033, 107223534Shselasky 0x0032, 0x002a, 0x002c, 0x0025, 0x0023, 0x0022, 0x001a, 0x0021, 108223534Shselasky 0x001b, 0x001b, 0x001d, 0x0015, 0x0013, 0x0013, 0x0012, 0x0012, 109223534Shselasky 0x000a, 0x000a, 0x0011, 0x0011, 0x000b, 0x000b, 0x000c, 0x000e, 110223534Shselasky}; 111223534Shselasky 112223534Shselasky/* 113223534Shselasky * second stage play gain. 114223534Shselasky */ 115223534Shselaskystatic const uint16_t ger_coeff[] = { 116223534Shselasky 0x431f, /* 5. dB */ 117223534Shselasky 0x331f, /* 5.5 dB */ 118223534Shselasky 0x40dd, /* 6. dB */ 119223534Shselasky 0x11dd, /* 6.5 dB */ 120223534Shselasky 0x440f, /* 7. dB */ 121223534Shselasky 0x411f, /* 7.5 dB */ 122223534Shselasky 0x311f, /* 8. dB */ 123223534Shselasky 0x5520, /* 8.5 dB */ 124223534Shselasky 0x10dd, /* 9. dB */ 125223534Shselasky 0x4211, /* 9.5 dB */ 126223534Shselasky 0x410f, /* 10. dB */ 127223534Shselasky 0x111f, /* 10.5 dB */ 128223534Shselasky 0x600b, /* 11. dB */ 129223534Shselasky 0x00dd, /* 11.5 dB */ 130223534Shselasky 0x4210, /* 12. dB */ 131223534Shselasky 0x110f, /* 13. dB */ 132223534Shselasky 0x7200, /* 14. dB */ 133223534Shselasky 0x2110, /* 15. dB */ 134223534Shselasky 0x2200, /* 15.9 dB */ 135223534Shselasky 0x000b, /* 16.9 dB */ 136223534Shselasky 0x000f /* 18. dB */ 137223534Shselasky#define NGER (sizeof(ger_coeff) / sizeof(ger_coeff[0])) 138223534Shselasky}; 139223534Shselasky 140223534Shselasky 141223534Shselasky/* 142223534Shselasky * Reset chip and set boot-time softc defaults. 143223534Shselasky */ 144223534Shselaskyvoid 145223534Shselaskyam7930_init(struct am7930_softc *sc, int flag) 146223534Shselasky{ 147223534Shselasky 148223534Shselasky DPRINTF(("am7930_init()\n")); 149223534Shselasky 150223534Shselasky /* set boot defaults */ 151223534Shselasky sc->sc_rlevel = 128; 152223534Shselasky sc->sc_plevel = 128; 153223534Shselasky sc->sc_mlevel = 0; 154223534Shselasky sc->sc_out_port = AUDIOAMD_SPEAKER_VOL; 155223534Shselasky sc->sc_mic_mute = 0; 156223534Shselasky 157223534Shselasky /* disable sample interrupts */ 158223534Shselasky AM7930_IWRITE(sc, AM7930_IREG_MUX_MCR4, 0); 159223534Shselasky 160223534Shselasky /* initialise voice and data, and disable interrupts */ 161223534Shselasky AM7930_IWRITE(sc, AM7930_IREG_INIT, 162223534Shselasky AM7930_INIT_PMS_ACTIVE | AM7930_INIT_INT_DISABLE); 163223534Shselasky 164223534Shselasky if (flag == AUDIOAMD_DMA_MODE) { 165223534Shselasky 166223534Shselasky /* configure PP for serial (SBP) mode */ 167223534Shselasky AM7930_IWRITE(sc, AM7930_IREG_PP_PPCR1, AM7930_PPCR1_SBP); 168223534Shselasky 169223534Shselasky /* 170223534Shselasky * Initialise the MUX unit - route the MAP to the PP 171223534Shselasky */ 172223534Shselasky AM7930_IWRITE(sc, AM7930_IREG_MUX_MCR1, 173223534Shselasky (AM7930_MCRCHAN_BA << 4) | AM7930_MCRCHAN_BD); 174223534Shselasky AM7930_IWRITE(sc, AM7930_IREG_MUX_MCR2, AM7930_MCRCHAN_NC); 175223534Shselasky AM7930_IWRITE(sc, AM7930_IREG_MUX_MCR3, AM7930_MCRCHAN_NC); 176223534Shselasky 177223534Shselasky } else { 178223534Shselasky 179223534Shselasky /* 180223534Shselasky * Initialize the MUX unit. We use MCR3 to route the MAP 181223534Shselasky * through channel Bb. MCR1 and MCR2 are unused. 182223534Shselasky * Setting the INT enable bit in MCR4 will generate an 183223534Shselasky * interrupt on each converted audio sample. 184223534Shselasky */ 185223534Shselasky AM7930_IWRITE(sc, AM7930_IREG_MUX_MCR1, 0); 186223534Shselasky AM7930_IWRITE(sc, AM7930_IREG_MUX_MCR2, 0); 187223534Shselasky AM7930_IWRITE(sc, AM7930_IREG_MUX_MCR3, 188223534Shselasky (AM7930_MCRCHAN_BB << 4) | AM7930_MCRCHAN_BA); 189223534Shselasky AM7930_IWRITE(sc, AM7930_IREG_MUX_MCR4, 190223534Shselasky AM7930_MCR4_INT_ENABLE); 191223534Shselasky } 192223534Shselasky 193223534Shselasky mutex_init(&sc->sc_lock, MUTEX_DEFAULT, IPL_NONE); 194223534Shselasky mutex_init(&sc->sc_intr_lock, MUTEX_DEFAULT, IPL_SCHED); 195223534Shselasky} 196223534Shselasky 197223534Shselaskyint 198223534Shselaskyam7930_open(void *addr, int flags) 199223534Shselasky{ 200223534Shselasky struct am7930_softc *sc; 201223534Shselasky 202223534Shselasky sc = addr; 203223534Shselasky DPRINTF(("sa_open: unit %p\n", sc)); 204223534Shselasky sc->sc_glue->onopen(sc); 205223534Shselasky DPRINTF(("saopen: ok -> sc=%p\n",sc)); 206223534Shselasky return 0; 207223534Shselasky} 208223534Shselasky 209223534Shselaskyvoid 210223534Shselaskyam7930_close(void *addr) 211223534Shselasky{ 212223534Shselasky struct am7930_softc *sc; 213223534Shselasky 214223534Shselasky sc = addr; 215223534Shselasky DPRINTF(("sa_close: sc=%p\n", sc)); 216223534Shselasky sc->sc_glue->onclose(sc); 217223534Shselasky DPRINTF(("sa_close: closed.\n")); 218223534Shselasky} 219223534Shselasky 220223534Shselasky/* 221223534Shselasky * XXX should be extended to handle a few of the more common formats. 222223534Shselasky */ 223223534Shselaskyint 224223534Shselaskyam7930_set_params(void *addr, int setmode, int usemode, audio_params_t *p, 225223534Shselasky audio_params_t *r, stream_filter_list_t *pfil, stream_filter_list_t *rfil) 226223534Shselasky{ 227223534Shselasky audio_params_t hw; 228223534Shselasky struct am7930_softc *sc; 229223534Shselasky 230223534Shselasky sc = addr; 231223534Shselasky if ((usemode & AUMODE_PLAY) == AUMODE_PLAY) { 232223534Shselasky if (p->sample_rate < 7500 || p->sample_rate > 8500 || 233223534Shselasky p->encoding != AUDIO_ENCODING_ULAW || 234223534Shselasky p->precision != 8 || 235223534Shselasky p->channels != 1) 236223534Shselasky return EINVAL; 237223534Shselasky p->sample_rate = 8000; 238223534Shselasky if (sc->sc_glue->output_conv != NULL) { 239223534Shselasky hw = *p; 240223534Shselasky hw.encoding = AUDIO_ENCODING_NONE; 241223534Shselasky hw.precision *= sc->sc_glue->factor; 242223534Shselasky pfil->append(pfil, sc->sc_glue->output_conv, &hw); 243223534Shselasky } 244223534Shselasky } 245223534Shselasky if ((usemode & AUMODE_RECORD) == AUMODE_RECORD) { 246223534Shselasky if (r->sample_rate < 7500 || r->sample_rate > 8500 || 247223534Shselasky r->encoding != AUDIO_ENCODING_ULAW || 248223534Shselasky r->precision != 8 || 249223534Shselasky r->channels != 1) 250223534Shselasky return EINVAL; 251223534Shselasky r->sample_rate = 8000; 252223534Shselasky if (sc->sc_glue->input_conv != NULL) { 253223534Shselasky hw = *r; 254223534Shselasky hw.encoding = AUDIO_ENCODING_NONE; 255223534Shselasky hw.precision *= sc->sc_glue->factor; 256223534Shselasky pfil->append(rfil, sc->sc_glue->input_conv, &hw); 257223534Shselasky } 258223534Shselasky } 259223534Shselasky 260223534Shselasky return 0; 261223534Shselasky} 262223534Shselasky 263223534Shselaskyint 264223534Shselaskyam7930_query_encoding(void *addr, struct audio_encoding *fp) 265223534Shselasky{ 266223534Shselasky switch (fp->index) { 267223534Shselasky case 0: 268223534Shselasky strcpy(fp->name, AudioEmulaw); 269223534Shselasky fp->encoding = AUDIO_ENCODING_ULAW; 270223534Shselasky fp->precision = 8; 271223534Shselasky fp->flags = 0; 272223534Shselasky break; 273223534Shselasky default: 274223534Shselasky return EINVAL; 275223534Shselasky /*NOTREACHED*/ 276223534Shselasky } 277223534Shselasky return 0; 278223534Shselasky} 279223535Shselasky 280223535Shselaskyint 281223535Shselaskyam7930_round_blocksize(void *addr, int blk, 282223535Shselasky int mode, const audio_params_t *param) 283223534Shselasky{ 284223534Shselasky return blk; 285223534Shselasky} 286223534Shselasky 287223534Shselaskyint 288223534Shselaskyam7930_commit_settings(void *addr) 289223534Shselasky{ 290223534Shselasky struct am7930_softc *sc; 291223534Shselasky uint16_t ger, gr, gx, stgr; 292223534Shselasky uint8_t mmr2, mmr3; 293223534Shselasky int level; 294223534Shselasky 295223534Shselasky DPRINTF(("sa_commit.\n")); 296223534Shselasky sc = addr; 297223534Shselasky gx = gx_coeff[sc->sc_rlevel]; 298223534Shselasky stgr = gx_coeff[sc->sc_mlevel]; 299223534Shselasky 300223534Shselasky level = (sc->sc_plevel * (256 + NGER)) >> 8; 301223534Shselasky if (level >= 256) { 302223534Shselasky ger = ger_coeff[level - 256]; 303223534Shselasky gr = gx_coeff[255]; 304223534Shselasky } else { 305223534Shselasky ger = ger_coeff[0]; 306223534Shselasky gr = gx_coeff[level]; 307223534Shselasky } 308223534Shselasky 309223534Shselasky mutex_enter(&sc->sc_intr_lock); 310223534Shselasky 311223534Shselasky mmr2 = AM7930_IREAD(sc, AM7930_IREG_MAP_MMR2); 312223534Shselasky if (sc->sc_out_port == AUDIOAMD_SPEAKER_VOL) 313223534Shselasky mmr2 |= AM7930_MMR2_LS; 314223534Shselasky else 315223534Shselasky mmr2 &= ~AM7930_MMR2_LS; 316223534Shselasky AM7930_IWRITE(sc, AM7930_IREG_MAP_MMR2, mmr2); 317223534Shselasky 318223534Shselasky mmr3 = AM7930_IREAD(sc, AM7930_IREG_MAP_MMR3); 319223534Shselasky if (sc->sc_mic_mute) 320233110Shselasky mmr3 |= AM7930_MMR3_MUTE; 321223534Shselasky else 322223534Shselasky mmr3 &= ~AM7930_MMR3_MUTE; 323223534Shselasky AM7930_IWRITE(sc, AM7930_IREG_MAP_MMR3, mmr3); 324223534Shselasky 325223534Shselasky AM7930_IWRITE(sc, AM7930_IREG_MAP_MMR1, 326223534Shselasky AM7930_MMR1_GX | AM7930_MMR1_GER | 327223534Shselasky AM7930_MMR1_GR | AM7930_MMR1_STG); 328223534Shselasky 329223534Shselasky AM7930_IWRITE16(sc, AM7930_IREG_MAP_GX, gx); 330223534Shselasky AM7930_IWRITE16(sc, AM7930_IREG_MAP_STG, stgr); 331223534Shselasky AM7930_IWRITE16(sc, AM7930_IREG_MAP_GR, gr); 332223534Shselasky AM7930_IWRITE16(sc, AM7930_IREG_MAP_GER, ger); 333223534Shselasky 334223534Shselasky mutex_exit(&sc->sc_intr_lock); 335223534Shselasky 336223534Shselasky return 0; 337223534Shselasky} 338223534Shselasky 339223534Shselaskyint 340223534Shselaskyam7930_halt_output(void *addr) 341223534Shselasky{ 342223534Shselasky struct am7930_softc *sc; 343223534Shselasky 344223534Shselasky sc = addr; 345223534Shselasky /* XXX only halt, if input is also halted ?? */ 346223534Shselasky AM7930_IWRITE(sc, AM7930_IREG_INIT, 347223534Shselasky AM7930_INIT_PMS_ACTIVE | AM7930_INIT_INT_DISABLE); 348223534Shselasky return 0; 349223534Shselasky} 350223534Shselasky 351223534Shselaskyint 352223534Shselaskyam7930_halt_input(void *addr) 353223534Shselasky{ 354223534Shselasky struct am7930_softc *sc; 355223534Shselasky 356223534Shselasky sc = addr; 357223534Shselasky /* XXX only halt, if output is also halted ?? */ 358223534Shselasky AM7930_IWRITE(sc, AM7930_IREG_INIT, 359223534Shselasky AM7930_INIT_PMS_ACTIVE | AM7930_INIT_INT_DISABLE); 360223534Shselasky return 0; 361223534Shselasky} 362223534Shselasky 363223534Shselasky/* 364223534Shselasky * XXX chip is full-duplex, but really attach-dependent. 365223534Shselasky * For now we know of no half-duplex attachments. 366223534Shselasky */ 367223534Shselaskyint 368223534Shselaskyam7930_get_props(void *addr) 369223534Shselasky{ 370223534Shselasky return AUDIO_PROP_FULLDUPLEX; 371223534Shselasky} 372223534Shselasky 373223534Shselasky/* 374223534Shselasky * Attach-dependent channel set/query 375223534Shselasky */ 376223534Shselaskyint 377223534Shselaskyam7930_set_port(void *addr, mixer_ctrl_t *cp) 378223534Shselasky{ 379223534Shselasky struct am7930_softc *sc; 380223534Shselasky 381223534Shselasky DPRINTF(("am7930_set_port: port=%d", cp->dev)); 382223534Shselasky sc = addr; 383223534Shselasky if (cp->dev == AUDIOAMD_RECORD_SOURCE || 384223534Shselasky cp->dev == AUDIOAMD_MONITOR_OUTPUT || 385223534Shselasky cp->dev == AUDIOAMD_MIC_MUTE) { 386223534Shselasky if (cp->type != AUDIO_MIXER_ENUM) 387 return EINVAL; 388 } else if (cp->type != AUDIO_MIXER_VALUE || 389 cp->un.value.num_channels != 1) { 390 return EINVAL; 391 } 392 393 switch(cp->dev) { 394 case AUDIOAMD_MIC_VOL: 395 sc->sc_rlevel = cp->un.value.level[AUDIO_MIXER_LEVEL_MONO]; 396 break; 397 case AUDIOAMD_SPEAKER_VOL: 398 case AUDIOAMD_HEADPHONES_VOL: 399 sc->sc_plevel = cp->un.value.level[AUDIO_MIXER_LEVEL_MONO]; 400 break; 401 case AUDIOAMD_MONITOR_VOL: 402 sc->sc_mlevel = cp->un.value.level[AUDIO_MIXER_LEVEL_MONO]; 403 break; 404 case AUDIOAMD_RECORD_SOURCE: 405 if (cp->un.ord != AUDIOAMD_MIC_VOL) 406 return EINVAL; 407 break; 408 case AUDIOAMD_MIC_MUTE: 409 sc->sc_mic_mute = cp->un.ord; 410 break; 411 case AUDIOAMD_MONITOR_OUTPUT: 412 if (cp->un.ord != AUDIOAMD_SPEAKER_VOL && 413 cp->un.ord != AUDIOAMD_HEADPHONES_VOL) 414 return EINVAL; 415 sc->sc_out_port = cp->un.ord; 416 break; 417 default: 418 return EINVAL; 419 /* NOTREACHED */ 420 } 421 return 0; 422} 423 424int 425am7930_get_port(void *addr, mixer_ctrl_t *cp) 426{ 427 struct am7930_softc *sc; 428 429 DPRINTF(("am7930_get_port: port=%d\n", cp->dev)); 430 sc = addr; 431 if (cp->dev == AUDIOAMD_RECORD_SOURCE || 432 cp->dev == AUDIOAMD_MONITOR_OUTPUT || 433 cp->dev == AUDIOAMD_MIC_MUTE) { 434 if (cp->type != AUDIO_MIXER_ENUM) 435 return EINVAL; 436 } else if (cp->type != AUDIO_MIXER_VALUE || 437 cp->un.value.num_channels != 1) { 438 return EINVAL; 439 } 440 441 switch(cp->dev) { 442 case AUDIOAMD_MIC_VOL: 443 cp->un.value.level[AUDIO_MIXER_LEVEL_MONO] = sc->sc_rlevel; 444 break; 445 case AUDIOAMD_SPEAKER_VOL: 446 case AUDIOAMD_HEADPHONES_VOL: 447 cp->un.value.level[AUDIO_MIXER_LEVEL_MONO] = sc->sc_plevel; 448 break; 449 case AUDIOAMD_MONITOR_VOL: 450 cp->un.value.level[AUDIO_MIXER_LEVEL_MONO] = sc->sc_mlevel; 451 break; 452 case AUDIOAMD_RECORD_SOURCE: 453 cp->un.ord = AUDIOAMD_MIC_VOL; 454 break; 455 case AUDIOAMD_MIC_MUTE: 456 cp->un.ord = sc->sc_mic_mute; 457 break; 458 case AUDIOAMD_MONITOR_OUTPUT: 459 cp->un.ord = sc->sc_out_port; 460 break; 461 default: 462 return EINVAL; 463 /* NOTREACHED */ 464 } 465 return 0; 466} 467 468 469/* 470 * Define mixer control facilities. 471 */ 472int 473am7930_query_devinfo(void *addr, mixer_devinfo_t *dip) 474{ 475 476 DPRINTF(("am7930_query_devinfo()\n")); 477 478 switch(dip->index) { 479 case AUDIOAMD_MIC_VOL: 480 dip->type = AUDIO_MIXER_VALUE; 481 dip->mixer_class = AUDIOAMD_INPUT_CLASS; 482 dip->prev = AUDIO_MIXER_LAST; 483 dip->next = AUDIOAMD_MIC_MUTE; 484 strcpy(dip->label.name, AudioNmicrophone); 485 dip->un.v.num_channels = 1; 486 strcpy(dip->un.v.units.name, AudioNvolume); 487 break; 488 case AUDIOAMD_SPEAKER_VOL: 489 dip->type = AUDIO_MIXER_VALUE; 490 dip->mixer_class = AUDIOAMD_OUTPUT_CLASS; 491 dip->prev = dip->next = AUDIO_MIXER_LAST; 492 strcpy(dip->label.name, AudioNspeaker); 493 dip->un.v.num_channels = 1; 494 strcpy(dip->un.v.units.name, AudioNvolume); 495 break; 496 case AUDIOAMD_HEADPHONES_VOL: 497 dip->type = AUDIO_MIXER_VALUE; 498 dip->mixer_class = AUDIOAMD_OUTPUT_CLASS; 499 dip->prev = dip->next = AUDIO_MIXER_LAST; 500 strcpy(dip->label.name, AudioNheadphone); 501 dip->un.v.num_channels = 1; 502 strcpy(dip->un.v.units.name, AudioNvolume); 503 break; 504 case AUDIOAMD_MONITOR_VOL: 505 dip->type = AUDIO_MIXER_VALUE; 506 dip->mixer_class = AUDIOAMD_MONITOR_CLASS; 507 dip->prev = dip->next = AUDIO_MIXER_LAST; 508 strcpy(dip->label.name, AudioNmonitor); 509 dip->un.v.num_channels = 1; 510 strcpy(dip->un.v.units.name, AudioNvolume); 511 break; 512 case AUDIOAMD_RECORD_SOURCE: 513 dip->type = AUDIO_MIXER_ENUM; 514 dip->mixer_class = AUDIOAMD_RECORD_CLASS; 515 dip->next = dip->prev = AUDIO_MIXER_LAST; 516 strcpy(dip->label.name, AudioNsource); 517 dip->un.e.num_mem = 1; 518 strcpy(dip->un.e.member[0].label.name, AudioNmicrophone); 519 dip->un.e.member[0].ord = AUDIOAMD_MIC_VOL; 520 break; 521 case AUDIOAMD_MONITOR_OUTPUT: 522 dip->type = AUDIO_MIXER_ENUM; 523 dip->mixer_class = AUDIOAMD_MONITOR_CLASS; 524 dip->next = dip->prev = AUDIO_MIXER_LAST; 525 strcpy(dip->label.name, AudioNoutput); 526 dip->un.e.num_mem = 2; 527 strcpy(dip->un.e.member[0].label.name, AudioNspeaker); 528 dip->un.e.member[0].ord = AUDIOAMD_SPEAKER_VOL; 529 strcpy(dip->un.e.member[1].label.name, AudioNheadphone); 530 dip->un.e.member[1].ord = AUDIOAMD_HEADPHONES_VOL; 531 break; 532 case AUDIOAMD_MIC_MUTE: 533 dip->type = AUDIO_MIXER_ENUM; 534 dip->mixer_class = AUDIOAMD_INPUT_CLASS; 535 dip->prev = AUDIOAMD_MIC_VOL; 536 dip->next = AUDIO_MIXER_LAST; 537 strcpy(dip->label.name, AudioNmute); 538 dip->un.e.num_mem = 2; 539 strcpy(dip->un.e.member[0].label.name, AudioNoff); 540 dip->un.e.member[0].ord = 0; 541 strcpy(dip->un.e.member[1].label.name, AudioNon); 542 dip->un.e.member[1].ord = 1; 543 break; 544 case AUDIOAMD_INPUT_CLASS: 545 dip->type = AUDIO_MIXER_CLASS; 546 dip->mixer_class = AUDIOAMD_INPUT_CLASS; 547 dip->next = dip->prev = AUDIO_MIXER_LAST; 548 strcpy(dip->label.name, AudioCinputs); 549 break; 550 case AUDIOAMD_OUTPUT_CLASS: 551 dip->type = AUDIO_MIXER_CLASS; 552 dip->mixer_class = AUDIOAMD_OUTPUT_CLASS; 553 dip->next = dip->prev = AUDIO_MIXER_LAST; 554 strcpy(dip->label.name, AudioCoutputs); 555 break; 556 case AUDIOAMD_RECORD_CLASS: 557 dip->type = AUDIO_MIXER_CLASS; 558 dip->mixer_class = AUDIOAMD_RECORD_CLASS; 559 dip->next = dip->prev = AUDIO_MIXER_LAST; 560 strcpy(dip->label.name, AudioCrecord); 561 break; 562 case AUDIOAMD_MONITOR_CLASS: 563 dip->type = AUDIO_MIXER_CLASS; 564 dip->mixer_class = AUDIOAMD_MONITOR_CLASS; 565 dip->next = dip->prev = AUDIO_MIXER_LAST; 566 strcpy(dip->label.name, AudioCmonitor); 567 break; 568 default: 569 return ENXIO; 570 /*NOTREACHED*/ 571 } 572 573 DPRINTF(("AUDIO_MIXER_DEVINFO: name=%s\n", dip->label.name)); 574 575 return 0; 576} 577 578#endif /* NAUDIO */ 579