Home | History | Annotate | Line # | Download | only in ic
am7930.c revision 1.57.4.1
      1  1.57.4.1  christos /*	$NetBSD: am7930.c,v 1.57.4.1 2019/06/10 22:07:10 christos Exp $	*/
      2       1.3       cgd 
      3       1.1        pk /*
      4       1.1        pk  * Copyright (c) 1995 Rolf Grossmann
      5       1.1        pk  * All rights reserved.
      6       1.1        pk  *
      7       1.1        pk  * Redistribution and use in source and binary forms, with or without
      8       1.1        pk  * modification, are permitted provided that the following conditions
      9       1.1        pk  * are met:
     10       1.1        pk  * 1. Redistributions of source code must retain the above copyright
     11       1.1        pk  *    notice, this list of conditions and the following disclaimer.
     12       1.1        pk  * 2. Redistributions in binary form must reproduce the above copyright
     13       1.1        pk  *    notice, this list of conditions and the following disclaimer in the
     14       1.1        pk  *    documentation and/or other materials provided with the distribution.
     15       1.1        pk  * 3. All advertising materials mentioning features or use of this software
     16       1.1        pk  *    must display the following acknowledgement:
     17       1.1        pk  *      This product includes software developed by Rolf Grossmann.
     18       1.1        pk  * 4. The name of the author may not be used to endorse or promote products
     19       1.1        pk  *    derived from this software without specific prior written permission
     20       1.1        pk  *
     21       1.1        pk  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
     22       1.1        pk  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
     23       1.1        pk  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
     24       1.1        pk  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
     25       1.1        pk  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
     26       1.1        pk  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
     27       1.1        pk  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
     28       1.1        pk  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
     29       1.1        pk  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
     30       1.1        pk  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
     31       1.1        pk  */
     32       1.1        pk 
     33      1.39  jonathan /*
     34      1.39  jonathan  * Front-end attachment independent layer for AMD 79c30
     35      1.43  augustss  * audio driver.  No ISDN support.
     36      1.39  jonathan  */
     37      1.44     lukem 
     38      1.44     lukem #include <sys/cdefs.h>
     39  1.57.4.1  christos __KERNEL_RCSID(0, "$NetBSD: am7930.c,v 1.57.4.1 2019/06/10 22:07:10 christos Exp $");
     40      1.39  jonathan 
     41       1.1        pk #include "audio.h"
     42       1.1        pk #if NAUDIO > 0
     43       1.1        pk 
     44       1.1        pk #include <sys/param.h>
     45       1.1        pk #include <sys/systm.h>
     46       1.1        pk #include <sys/errno.h>
     47       1.1        pk #include <sys/ioctl.h>
     48       1.1        pk #include <sys/device.h>
     49       1.1        pk #include <sys/proc.h>
     50       1.1        pk 
     51      1.50        ad #include <sys/bus.h>
     52      1.50        ad #include <sys/cpu.h>
     53       1.1        pk 
     54       1.1        pk #include <sys/audioio.h>
     55  1.57.4.1  christos #include <dev/audio/audio_if.h>
     56  1.57.4.1  christos #include <dev/audio/mulaw.h>
     57       1.1        pk 
     58       1.3       cgd #include <dev/ic/am7930reg.h>
     59      1.39  jonathan #include <dev/ic/am7930var.h>
     60       1.1        pk 
     61       1.4    brezak #ifdef AUDIO_DEBUG
     62      1.39  jonathan int     am7930debug = 0;
     63      1.40        pk #define DPRINTF(x)      if (am7930debug) printf x
     64       1.1        pk #else
     65       1.1        pk #define DPRINTF(x)
     66       1.1        pk #endif
     67       1.1        pk 
     68       1.1        pk 
     69       1.1        pk /* The following tables stolen from former (4.4Lite's) sys/sparc/bsd_audio.c */
     70       1.1        pk 
     71       1.1        pk /*
     72       1.1        pk  * gx, gr & stg gains.  this table must contain 256 elements with
     73       1.1        pk  * the 0th being "infinity" (the magic value 9008).  The remaining
     74       1.1        pk  * elements match sun's gain curve (but with higher resolution):
     75       1.1        pk  * -18 to 0dB in .16dB steps then 0 to 12dB in .08dB steps.
     76       1.1        pk  */
     77      1.47      kent static const uint16_t gx_coeff[256] = {
     78      1.21        pk 	0x9008, 0x8e7c, 0x8e51, 0x8e45, 0x8d42, 0x8d3b, 0x8c36, 0x8c33,
     79       1.1        pk 	0x8b32, 0x8b2a, 0x8b2b, 0x8b2c, 0x8b25, 0x8b23, 0x8b22, 0x8b22,
     80       1.1        pk 	0x9122, 0x8b1a, 0x8aa3, 0x8aa3, 0x8b1c, 0x8aa6, 0x912d, 0x912b,
     81       1.1        pk 	0x8aab, 0x8b12, 0x8aaa, 0x8ab2, 0x9132, 0x8ab4, 0x913c, 0x8abb,
     82       1.1        pk 	0x9142, 0x9144, 0x9151, 0x8ad5, 0x8aeb, 0x8a79, 0x8a5a, 0x8a4a,
     83       1.1        pk 	0x8b03, 0x91c2, 0x91bb, 0x8a3f, 0x8a33, 0x91b2, 0x9212, 0x9213,
     84       1.1        pk 	0x8a2c, 0x921d, 0x8a23, 0x921a, 0x9222, 0x9223, 0x922d, 0x9231,
     85       1.1        pk 	0x9234, 0x9242, 0x925b, 0x92dd, 0x92c1, 0x92b3, 0x92ab, 0x92a4,
     86       1.1        pk 	0x92a2, 0x932b, 0x9341, 0x93d3, 0x93b2, 0x93a2, 0x943c, 0x94b2,
     87       1.1        pk 	0x953a, 0x9653, 0x9782, 0x9e21, 0x9d23, 0x9cd2, 0x9c23, 0x9baa,
     88       1.1        pk 	0x9bde, 0x9b33, 0x9b22, 0x9b1d, 0x9ab2, 0xa142, 0xa1e5, 0x9a3b,
     89       1.1        pk 	0xa213, 0xa1a2, 0xa231, 0xa2eb, 0xa313, 0xa334, 0xa421, 0xa54b,
     90       1.1        pk 	0xada4, 0xac23, 0xab3b, 0xaaab, 0xaa5c, 0xb1a3, 0xb2ca, 0xb3bd,
     91       1.1        pk 	0xbe24, 0xbb2b, 0xba33, 0xc32b, 0xcb5a, 0xd2a2, 0xe31d, 0x0808,
     92       1.1        pk 	0x72ba, 0x62c2, 0x5c32, 0x52db, 0x513e, 0x4cce, 0x43b2, 0x4243,
     93       1.1        pk 	0x41b4, 0x3b12, 0x3bc3, 0x3df2, 0x34bd, 0x3334, 0x32c2, 0x3224,
     94       1.1        pk 	0x31aa, 0x2a7b, 0x2aaa, 0x2b23, 0x2bba, 0x2c42, 0x2e23, 0x25bb,
     95       1.1        pk 	0x242b, 0x240f, 0x231a, 0x22bb, 0x2241, 0x2223, 0x221f, 0x1a33,
     96       1.1        pk 	0x1a4a, 0x1acd, 0x2132, 0x1b1b, 0x1b2c, 0x1b62, 0x1c12, 0x1c32,
     97       1.1        pk 	0x1d1b, 0x1e71, 0x16b1, 0x1522, 0x1434, 0x1412, 0x1352, 0x1323,
     98       1.1        pk 	0x1315, 0x12bc, 0x127a, 0x1235, 0x1226, 0x11a2, 0x1216, 0x0a2a,
     99       1.1        pk 	0x11bc, 0x11d1, 0x1163, 0x0ac2, 0x0ab2, 0x0aab, 0x0b1b, 0x0b23,
    100       1.1        pk 	0x0b33, 0x0c0f, 0x0bb3, 0x0c1b, 0x0c3e, 0x0cb1, 0x0d4c, 0x0ec1,
    101       1.1        pk 	0x079a, 0x0614, 0x0521, 0x047c, 0x0422, 0x03b1, 0x03e3, 0x0333,
    102       1.1        pk 	0x0322, 0x031c, 0x02aa, 0x02ba, 0x02f2, 0x0242, 0x0232, 0x0227,
    103       1.1        pk 	0x0222, 0x021b, 0x01ad, 0x0212, 0x01b2, 0x01bb, 0x01cb, 0x01f6,
    104       1.1        pk 	0x0152, 0x013a, 0x0133, 0x0131, 0x012c, 0x0123, 0x0122, 0x00a2,
    105       1.1        pk 	0x011b, 0x011e, 0x0114, 0x00b1, 0x00aa, 0x00b3, 0x00bd, 0x00ba,
    106       1.1        pk 	0x00c5, 0x00d3, 0x00f3, 0x0062, 0x0051, 0x0042, 0x003b, 0x0033,
    107       1.1        pk 	0x0032, 0x002a, 0x002c, 0x0025, 0x0023, 0x0022, 0x001a, 0x0021,
    108       1.1        pk 	0x001b, 0x001b, 0x001d, 0x0015, 0x0013, 0x0013, 0x0012, 0x0012,
    109       1.1        pk 	0x000a, 0x000a, 0x0011, 0x0011, 0x000b, 0x000b, 0x000c, 0x000e,
    110       1.1        pk };
    111       1.1        pk 
    112       1.1        pk /*
    113       1.1        pk  * second stage play gain.
    114       1.1        pk  */
    115      1.47      kent static const uint16_t ger_coeff[] = {
    116       1.1        pk 	0x431f, /* 5. dB */
    117       1.1        pk 	0x331f, /* 5.5 dB */
    118       1.1        pk 	0x40dd, /* 6. dB */
    119       1.1        pk 	0x11dd, /* 6.5 dB */
    120       1.1        pk 	0x440f, /* 7. dB */
    121       1.1        pk 	0x411f, /* 7.5 dB */
    122       1.1        pk 	0x311f, /* 8. dB */
    123       1.1        pk 	0x5520, /* 8.5 dB */
    124       1.1        pk 	0x10dd, /* 9. dB */
    125       1.1        pk 	0x4211, /* 9.5 dB */
    126       1.1        pk 	0x410f, /* 10. dB */
    127       1.1        pk 	0x111f, /* 10.5 dB */
    128       1.1        pk 	0x600b, /* 11. dB */
    129       1.1        pk 	0x00dd, /* 11.5 dB */
    130       1.1        pk 	0x4210, /* 12. dB */
    131       1.1        pk 	0x110f, /* 13. dB */
    132       1.1        pk 	0x7200, /* 14. dB */
    133       1.1        pk 	0x2110, /* 15. dB */
    134       1.1        pk 	0x2200, /* 15.9 dB */
    135       1.1        pk 	0x000b, /* 16.9 dB */
    136       1.1        pk 	0x000f  /* 18. dB */
    137       1.1        pk #define NGER (sizeof(ger_coeff) / sizeof(ger_coeff[0]))
    138       1.1        pk };
    139       1.1        pk 
    140  1.57.4.1  christos static const struct audio_format am7930_format = {
    141  1.57.4.1  christos 	.mode		= AUMODE_PLAY | AUMODE_RECORD,
    142  1.57.4.1  christos 	.encoding	= AUDIO_ENCODING_ULAW,
    143  1.57.4.1  christos 	.validbits	= 8,
    144  1.57.4.1  christos 	.precision	= 8,
    145  1.57.4.1  christos 	.channels	= 1,
    146  1.57.4.1  christos 	.channel_mask	= AUFMT_MONAURAL,
    147  1.57.4.1  christos 	.frequency_type	= 1,
    148  1.57.4.1  christos 	.frequency	= { 8000 },
    149  1.57.4.1  christos };
    150       1.1        pk 
    151       1.1        pk /*
    152      1.39  jonathan  * Reset chip and set boot-time softc defaults.
    153       1.1        pk  */
    154       1.1        pk void
    155      1.47      kent am7930_init(struct am7930_softc *sc, int flag)
    156      1.36        pk {
    157      1.41  jonathan 
    158      1.43  augustss 	DPRINTF(("am7930_init()\n"));
    159      1.39  jonathan 
    160       1.1        pk 	/* set boot defaults */
    161       1.1        pk 	sc->sc_rlevel = 128;
    162       1.1        pk 	sc->sc_plevel = 128;
    163       1.1        pk 	sc->sc_mlevel = 0;
    164      1.43  augustss 	sc->sc_out_port = AUDIOAMD_SPEAKER_VOL;
    165      1.43  augustss 	sc->sc_mic_mute = 0;
    166      1.43  augustss 
    167      1.43  augustss 	/* disable sample interrupts */
    168      1.43  augustss 	AM7930_IWRITE(sc, AM7930_IREG_MUX_MCR4, 0);
    169      1.43  augustss 
    170      1.43  augustss 	/* initialise voice and data, and disable interrupts */
    171      1.43  augustss 	AM7930_IWRITE(sc, AM7930_IREG_INIT,
    172      1.43  augustss 		AM7930_INIT_PMS_ACTIVE | AM7930_INIT_INT_DISABLE);
    173      1.43  augustss 
    174      1.43  augustss 	if (flag == AUDIOAMD_DMA_MODE) {
    175      1.43  augustss 
    176      1.43  augustss 		/* configure PP for serial (SBP) mode */
    177      1.43  augustss 		AM7930_IWRITE(sc, AM7930_IREG_PP_PPCR1, AM7930_PPCR1_SBP);
    178      1.43  augustss 
    179      1.43  augustss 		/*
    180      1.43  augustss 		 * Initialise the MUX unit - route the MAP to the PP
    181      1.43  augustss 		 */
    182      1.43  augustss 		AM7930_IWRITE(sc, AM7930_IREG_MUX_MCR1,
    183      1.43  augustss 			(AM7930_MCRCHAN_BA << 4) | AM7930_MCRCHAN_BD);
    184      1.43  augustss 		AM7930_IWRITE(sc, AM7930_IREG_MUX_MCR2, AM7930_MCRCHAN_NC);
    185      1.43  augustss 		AM7930_IWRITE(sc, AM7930_IREG_MUX_MCR3, AM7930_MCRCHAN_NC);
    186      1.43  augustss 
    187      1.43  augustss 	} else {
    188      1.43  augustss 
    189      1.43  augustss 		/*
    190      1.43  augustss 		 * Initialize the MUX unit.  We use MCR3 to route the MAP
    191      1.43  augustss 		 * through channel Bb.  MCR1 and MCR2 are unused.
    192      1.43  augustss 		 * Setting the INT enable bit in MCR4 will generate an
    193      1.43  augustss 		 * interrupt on each converted audio sample.
    194      1.43  augustss 		 */
    195      1.43  augustss 		AM7930_IWRITE(sc, AM7930_IREG_MUX_MCR1, 0);
    196      1.43  augustss 		AM7930_IWRITE(sc, AM7930_IREG_MUX_MCR2, 0);
    197      1.43  augustss 		AM7930_IWRITE(sc, AM7930_IREG_MUX_MCR3,
    198      1.43  augustss 			(AM7930_MCRCHAN_BB << 4) | AM7930_MCRCHAN_BA);
    199      1.43  augustss 		AM7930_IWRITE(sc, AM7930_IREG_MUX_MCR4,
    200      1.43  augustss 			AM7930_MCR4_INT_ENABLE);
    201      1.43  augustss 	}
    202      1.43  augustss 
    203      1.51  jmcneill 	mutex_init(&sc->sc_lock, MUTEX_DEFAULT, IPL_NONE);
    204      1.51  jmcneill 	mutex_init(&sc->sc_intr_lock, MUTEX_DEFAULT, IPL_SCHED);
    205       1.1        pk }
    206       1.1        pk 
    207       1.1        pk int
    208      1.47      kent am7930_open(void *addr, int flags)
    209       1.1        pk {
    210      1.47      kent 	struct am7930_softc *sc;
    211       1.1        pk 
    212      1.47      kent 	sc = addr;
    213      1.26  augustss 	DPRINTF(("sa_open: unit %p\n", sc));
    214      1.43  augustss 	sc->sc_glue->onopen(sc);
    215      1.48  christos 	DPRINTF(("saopen: ok -> sc=%p\n",sc));
    216      1.47      kent 	return 0;
    217       1.1        pk }
    218       1.1        pk 
    219       1.1        pk void
    220      1.47      kent am7930_close(void *addr)
    221       1.1        pk {
    222      1.47      kent 	struct am7930_softc *sc;
    223       1.1        pk 
    224      1.47      kent 	sc = addr;
    225      1.40        pk 	DPRINTF(("sa_close: sc=%p\n", sc));
    226      1.43  augustss 	sc->sc_glue->onclose(sc);
    227       1.1        pk 	DPRINTF(("sa_close: closed.\n"));
    228       1.1        pk }
    229       1.1        pk 
    230       1.1        pk int
    231  1.57.4.1  christos am7930_query_format(void *addr, audio_format_query_t *afp)
    232       1.1        pk {
    233      1.55       nat 
    234  1.57.4.1  christos 	return audio_query_format(&am7930_format, 1, afp);
    235       1.1        pk }
    236       1.1        pk 
    237       1.1        pk int
    238  1.57.4.1  christos am7930_set_format(void *addr, int setmode,
    239  1.57.4.1  christos 	const audio_params_t *play, const audio_params_t *rec,
    240  1.57.4.1  christos 	audio_filter_reg_t *pfil, audio_filter_reg_t *rfil)
    241      1.47      kent {
    242  1.57.4.1  christos 
    243  1.57.4.1  christos 	if ((setmode & AUMODE_PLAY) != 0) {
    244  1.57.4.1  christos 		pfil->codec = audio_internal_to_mulaw;
    245  1.57.4.1  christos 	}
    246  1.57.4.1  christos 	if ((setmode & AUMODE_RECORD) != 0) {
    247  1.57.4.1  christos 		rfil->codec = audio_mulaw_to_internal;
    248       1.1        pk 	}
    249       1.1        pk 
    250  1.57.4.1  christos 	return 0;
    251       1.1        pk }
    252       1.1        pk 
    253       1.1        pk int
    254      1.47      kent am7930_commit_settings(void *addr)
    255       1.1        pk {
    256      1.47      kent 	struct am7930_softc *sc;
    257      1.47      kent 	uint16_t ger, gr, gx, stgr;
    258      1.47      kent 	uint8_t mmr2, mmr3;
    259      1.51  jmcneill 	int level;
    260      1.10        pk 
    261       1.1        pk 	DPRINTF(("sa_commit.\n"));
    262      1.47      kent 	sc = addr;
    263      1.43  augustss 	gx = gx_coeff[sc->sc_rlevel];
    264      1.43  augustss 	stgr = gx_coeff[sc->sc_mlevel];
    265      1.10        pk 
    266       1.1        pk 	level = (sc->sc_plevel * (256 + NGER)) >> 8;
    267       1.1        pk 	if (level >= 256) {
    268      1.43  augustss 		ger = ger_coeff[level - 256];
    269      1.43  augustss 		gr = gx_coeff[255];
    270       1.1        pk 	} else {
    271      1.43  augustss 		ger = ger_coeff[0];
    272      1.43  augustss 		gr = gx_coeff[level];
    273       1.1        pk 	}
    274       1.1        pk 
    275      1.51  jmcneill 	mutex_enter(&sc->sc_intr_lock);
    276      1.10        pk 
    277      1.43  augustss 	mmr2 = AM7930_IREAD(sc, AM7930_IREG_MAP_MMR2);
    278      1.43  augustss 	if (sc->sc_out_port == AUDIOAMD_SPEAKER_VOL)
    279      1.43  augustss 		mmr2 |= AM7930_MMR2_LS;
    280      1.43  augustss 	else
    281      1.43  augustss 		mmr2 &= ~AM7930_MMR2_LS;
    282      1.43  augustss 	AM7930_IWRITE(sc, AM7930_IREG_MAP_MMR2, mmr2);
    283      1.41  jonathan 
    284      1.43  augustss 	mmr3 = AM7930_IREAD(sc, AM7930_IREG_MAP_MMR3);
    285      1.43  augustss 	if (sc->sc_mic_mute)
    286      1.43  augustss 		mmr3 |= AM7930_MMR3_MUTE;
    287      1.43  augustss 	else
    288      1.43  augustss 		mmr3 &= ~AM7930_MMR3_MUTE;
    289      1.43  augustss 	AM7930_IWRITE(sc, AM7930_IREG_MAP_MMR3, mmr3);
    290      1.41  jonathan 
    291      1.43  augustss 	AM7930_IWRITE(sc, AM7930_IREG_MAP_MMR1,
    292      1.43  augustss 		AM7930_MMR1_GX | AM7930_MMR1_GER |
    293      1.43  augustss 		AM7930_MMR1_GR | AM7930_MMR1_STG);
    294      1.43  augustss 
    295      1.43  augustss 	AM7930_IWRITE16(sc, AM7930_IREG_MAP_GX, gx);
    296      1.43  augustss 	AM7930_IWRITE16(sc, AM7930_IREG_MAP_STG, stgr);
    297      1.43  augustss 	AM7930_IWRITE16(sc, AM7930_IREG_MAP_GR, gr);
    298      1.43  augustss 	AM7930_IWRITE16(sc, AM7930_IREG_MAP_GER, ger);
    299      1.41  jonathan 
    300      1.51  jmcneill 	mutex_exit(&sc->sc_intr_lock);
    301       1.1        pk 
    302      1.47      kent 	return 0;
    303       1.1        pk }
    304       1.1        pk 
    305       1.1        pk int
    306      1.47      kent am7930_halt_output(void *addr)
    307       1.1        pk {
    308      1.47      kent 	struct am7930_softc *sc;
    309       1.1        pk 
    310      1.47      kent 	sc = addr;
    311       1.1        pk 	/* XXX only halt, if input is also halted ?? */
    312      1.43  augustss 	AM7930_IWRITE(sc, AM7930_IREG_INIT,
    313      1.47      kent 	    AM7930_INIT_PMS_ACTIVE | AM7930_INIT_INT_DISABLE);
    314      1.47      kent 	return 0;
    315       1.1        pk }
    316       1.1        pk 
    317       1.1        pk int
    318      1.47      kent am7930_halt_input(void *addr)
    319       1.1        pk {
    320      1.47      kent 	struct am7930_softc *sc;
    321       1.1        pk 
    322      1.47      kent 	sc = addr;
    323       1.1        pk 	/* XXX only halt, if output is also halted ?? */
    324      1.43  augustss 	AM7930_IWRITE(sc, AM7930_IREG_INIT,
    325      1.47      kent 	    AM7930_INIT_PMS_ACTIVE | AM7930_INIT_INT_DISABLE);
    326      1.47      kent 	return 0;
    327       1.1        pk }
    328       1.1        pk 
    329      1.43  augustss /*
    330      1.43  augustss  * XXX chip is full-duplex, but really attach-dependent.
    331      1.43  augustss  * For now we know of no half-duplex attachments.
    332      1.43  augustss  */
    333       1.1        pk int
    334      1.47      kent am7930_get_props(void *addr)
    335       1.1        pk {
    336  1.57.4.1  christos 
    337  1.57.4.1  christos 	return AUDIO_PROP_PLAYBACK | AUDIO_PROP_CAPTURE |
    338  1.57.4.1  christos 	    AUDIO_PROP_FULLDUPLEX;
    339      1.43  augustss }
    340      1.43  augustss 
    341      1.43  augustss /*
    342      1.43  augustss  * Attach-dependent channel set/query
    343      1.43  augustss  */
    344      1.43  augustss int
    345      1.47      kent am7930_set_port(void *addr, mixer_ctrl_t *cp)
    346      1.43  augustss {
    347      1.47      kent 	struct am7930_softc *sc;
    348      1.43  augustss 
    349      1.43  augustss 	DPRINTF(("am7930_set_port: port=%d", cp->dev));
    350      1.47      kent 	sc = addr;
    351      1.43  augustss 	if (cp->dev == AUDIOAMD_RECORD_SOURCE ||
    352      1.43  augustss 		cp->dev == AUDIOAMD_MONITOR_OUTPUT ||
    353      1.43  augustss 		cp->dev == AUDIOAMD_MIC_MUTE) {
    354      1.43  augustss 		if (cp->type != AUDIO_MIXER_ENUM)
    355      1.47      kent 			return EINVAL;
    356      1.43  augustss 	} else if (cp->type != AUDIO_MIXER_VALUE ||
    357      1.47      kent 	    cp->un.value.num_channels != 1) {
    358      1.47      kent 		return EINVAL;
    359      1.43  augustss 	}
    360      1.43  augustss 
    361      1.43  augustss 	switch(cp->dev) {
    362      1.43  augustss 	    case AUDIOAMD_MIC_VOL:
    363      1.43  augustss 		    sc->sc_rlevel = cp->un.value.level[AUDIO_MIXER_LEVEL_MONO];
    364      1.43  augustss 		    break;
    365      1.43  augustss 	    case AUDIOAMD_SPEAKER_VOL:
    366      1.43  augustss 	    case AUDIOAMD_HEADPHONES_VOL:
    367      1.43  augustss 		    sc->sc_plevel = cp->un.value.level[AUDIO_MIXER_LEVEL_MONO];
    368      1.43  augustss 		    break;
    369      1.43  augustss 	    case AUDIOAMD_MONITOR_VOL:
    370      1.43  augustss 		    sc->sc_mlevel = cp->un.value.level[AUDIO_MIXER_LEVEL_MONO];
    371      1.43  augustss 		    break;
    372      1.43  augustss 	    case AUDIOAMD_RECORD_SOURCE:
    373      1.43  augustss 		    if (cp->un.ord != AUDIOAMD_MIC_VOL)
    374      1.43  augustss 			    return EINVAL;
    375      1.43  augustss 		    break;
    376      1.43  augustss 	    case AUDIOAMD_MIC_MUTE:
    377      1.43  augustss 		    sc->sc_mic_mute = cp->un.ord;
    378      1.43  augustss 		    break;
    379      1.43  augustss 	    case AUDIOAMD_MONITOR_OUTPUT:
    380      1.43  augustss 		    if (cp->un.ord != AUDIOAMD_SPEAKER_VOL &&
    381      1.43  augustss 			cp->un.ord != AUDIOAMD_HEADPHONES_VOL)
    382      1.43  augustss 			    return EINVAL;
    383      1.43  augustss 			sc->sc_out_port = cp->un.ord;
    384      1.43  augustss 		    break;
    385      1.43  augustss 	    default:
    386      1.47      kent 		    return EINVAL;
    387      1.43  augustss 		    /* NOTREACHED */
    388      1.43  augustss 	}
    389      1.43  augustss 	return 0;
    390      1.43  augustss }
    391      1.43  augustss 
    392      1.43  augustss int
    393      1.47      kent am7930_get_port(void *addr, mixer_ctrl_t *cp)
    394      1.43  augustss {
    395      1.47      kent 	struct am7930_softc *sc;
    396      1.43  augustss 
    397      1.43  augustss 	DPRINTF(("am7930_get_port: port=%d\n", cp->dev));
    398      1.47      kent 	sc = addr;
    399      1.43  augustss 	if (cp->dev == AUDIOAMD_RECORD_SOURCE ||
    400      1.43  augustss 		cp->dev == AUDIOAMD_MONITOR_OUTPUT ||
    401      1.43  augustss 		cp->dev == AUDIOAMD_MIC_MUTE) {
    402      1.43  augustss 		if (cp->type != AUDIO_MIXER_ENUM)
    403      1.47      kent 			return EINVAL;
    404      1.43  augustss 	} else if (cp->type != AUDIO_MIXER_VALUE ||
    405      1.43  augustss 		cp->un.value.num_channels != 1) {
    406      1.47      kent 		return EINVAL;
    407      1.43  augustss 	}
    408      1.43  augustss 
    409      1.43  augustss 	switch(cp->dev) {
    410      1.43  augustss 	    case AUDIOAMD_MIC_VOL:
    411      1.43  augustss 		    cp->un.value.level[AUDIO_MIXER_LEVEL_MONO] = sc->sc_rlevel;
    412      1.43  augustss 		    break;
    413      1.43  augustss 	    case AUDIOAMD_SPEAKER_VOL:
    414      1.43  augustss 	    case AUDIOAMD_HEADPHONES_VOL:
    415      1.43  augustss 		    cp->un.value.level[AUDIO_MIXER_LEVEL_MONO] = sc->sc_plevel;
    416      1.43  augustss 		    break;
    417      1.43  augustss 	    case AUDIOAMD_MONITOR_VOL:
    418      1.43  augustss 		    cp->un.value.level[AUDIO_MIXER_LEVEL_MONO] = sc->sc_mlevel;
    419      1.43  augustss 		    break;
    420      1.43  augustss 	    case AUDIOAMD_RECORD_SOURCE:
    421      1.43  augustss 		    cp->un.ord = AUDIOAMD_MIC_VOL;
    422      1.43  augustss 		    break;
    423      1.43  augustss 	    case AUDIOAMD_MIC_MUTE:
    424      1.43  augustss 		    cp->un.ord = sc->sc_mic_mute;
    425      1.43  augustss 		    break;
    426      1.43  augustss 	    case AUDIOAMD_MONITOR_OUTPUT:
    427      1.43  augustss 		    cp->un.ord = sc->sc_out_port;
    428      1.43  augustss 		    break;
    429      1.43  augustss 	    default:
    430      1.47      kent 		    return EINVAL;
    431      1.43  augustss 		    /* NOTREACHED */
    432      1.43  augustss 	}
    433      1.43  augustss 	return 0;
    434       1.1        pk }
    435       1.1        pk 
    436      1.26  augustss 
    437      1.39  jonathan /*
    438      1.43  augustss  * Define mixer control facilities.
    439      1.39  jonathan  */
    440      1.26  augustss int
    441      1.47      kent am7930_query_devinfo(void *addr, mixer_devinfo_t *dip)
    442      1.26  augustss {
    443      1.43  augustss 
    444      1.43  augustss 	DPRINTF(("am7930_query_devinfo()\n"));
    445      1.43  augustss 
    446      1.43  augustss 	switch(dip->index) {
    447      1.47      kent 	case AUDIOAMD_MIC_VOL:
    448      1.47      kent 		dip->type = AUDIO_MIXER_VALUE;
    449      1.47      kent 		dip->mixer_class = AUDIOAMD_INPUT_CLASS;
    450      1.47      kent 		dip->prev =  AUDIO_MIXER_LAST;
    451      1.47      kent 		dip->next = AUDIOAMD_MIC_MUTE;
    452      1.47      kent 		strcpy(dip->label.name, AudioNmicrophone);
    453      1.47      kent 		dip->un.v.num_channels = 1;
    454      1.47      kent 		strcpy(dip->un.v.units.name, AudioNvolume);
    455      1.47      kent 		break;
    456      1.47      kent 	case AUDIOAMD_SPEAKER_VOL:
    457      1.47      kent 		dip->type = AUDIO_MIXER_VALUE;
    458      1.47      kent 		dip->mixer_class = AUDIOAMD_OUTPUT_CLASS;
    459      1.47      kent 		dip->prev = dip->next = AUDIO_MIXER_LAST;
    460      1.47      kent 		strcpy(dip->label.name, AudioNspeaker);
    461      1.47      kent 		dip->un.v.num_channels = 1;
    462      1.47      kent 		strcpy(dip->un.v.units.name, AudioNvolume);
    463      1.47      kent 		break;
    464      1.47      kent 	case AUDIOAMD_HEADPHONES_VOL:
    465      1.47      kent 		dip->type = AUDIO_MIXER_VALUE;
    466      1.47      kent 		dip->mixer_class = AUDIOAMD_OUTPUT_CLASS;
    467      1.47      kent 		dip->prev = dip->next = AUDIO_MIXER_LAST;
    468      1.47      kent 		strcpy(dip->label.name, AudioNheadphone);
    469      1.47      kent 		dip->un.v.num_channels = 1;
    470      1.47      kent 		strcpy(dip->un.v.units.name, AudioNvolume);
    471      1.47      kent 		break;
    472      1.47      kent 	case AUDIOAMD_MONITOR_VOL:
    473      1.47      kent 		dip->type = AUDIO_MIXER_VALUE;
    474      1.47      kent 		dip->mixer_class = AUDIOAMD_MONITOR_CLASS;
    475      1.47      kent 		dip->prev = dip->next = AUDIO_MIXER_LAST;
    476      1.47      kent 		strcpy(dip->label.name, AudioNmonitor);
    477      1.47      kent 		dip->un.v.num_channels = 1;
    478      1.47      kent 		strcpy(dip->un.v.units.name, AudioNvolume);
    479      1.47      kent 		break;
    480      1.47      kent 	case AUDIOAMD_RECORD_SOURCE:
    481      1.47      kent 		dip->type = AUDIO_MIXER_ENUM;
    482      1.47      kent 		dip->mixer_class = AUDIOAMD_RECORD_CLASS;
    483      1.47      kent 		dip->next = dip->prev = AUDIO_MIXER_LAST;
    484      1.47      kent 		strcpy(dip->label.name, AudioNsource);
    485      1.47      kent 		dip->un.e.num_mem = 1;
    486      1.47      kent 		strcpy(dip->un.e.member[0].label.name, AudioNmicrophone);
    487      1.47      kent 		dip->un.e.member[0].ord = AUDIOAMD_MIC_VOL;
    488      1.47      kent 		break;
    489      1.47      kent 	case AUDIOAMD_MONITOR_OUTPUT:
    490      1.47      kent 		dip->type = AUDIO_MIXER_ENUM;
    491      1.47      kent 		dip->mixer_class = AUDIOAMD_MONITOR_CLASS;
    492      1.47      kent 		dip->next = dip->prev = AUDIO_MIXER_LAST;
    493      1.47      kent 		strcpy(dip->label.name, AudioNoutput);
    494      1.47      kent 		dip->un.e.num_mem = 2;
    495      1.47      kent 		strcpy(dip->un.e.member[0].label.name, AudioNspeaker);
    496      1.47      kent 		dip->un.e.member[0].ord = AUDIOAMD_SPEAKER_VOL;
    497      1.47      kent 		strcpy(dip->un.e.member[1].label.name, AudioNheadphone);
    498      1.47      kent 		dip->un.e.member[1].ord = AUDIOAMD_HEADPHONES_VOL;
    499      1.47      kent 		break;
    500      1.47      kent 	case AUDIOAMD_MIC_MUTE:
    501      1.47      kent 		dip->type = AUDIO_MIXER_ENUM;
    502      1.47      kent 		dip->mixer_class = AUDIOAMD_INPUT_CLASS;
    503      1.47      kent 		dip->prev =  AUDIOAMD_MIC_VOL;
    504      1.47      kent 		dip->next = AUDIO_MIXER_LAST;
    505      1.47      kent 		strcpy(dip->label.name, AudioNmute);
    506      1.47      kent 		dip->un.e.num_mem = 2;
    507      1.47      kent 		strcpy(dip->un.e.member[0].label.name, AudioNoff);
    508      1.47      kent 		dip->un.e.member[0].ord = 0;
    509      1.47      kent 		strcpy(dip->un.e.member[1].label.name, AudioNon);
    510      1.47      kent 		dip->un.e.member[1].ord = 1;
    511      1.47      kent 		break;
    512      1.47      kent 	case AUDIOAMD_INPUT_CLASS:
    513      1.47      kent 		dip->type = AUDIO_MIXER_CLASS;
    514      1.47      kent 		dip->mixer_class = AUDIOAMD_INPUT_CLASS;
    515      1.47      kent 		dip->next = dip->prev = AUDIO_MIXER_LAST;
    516      1.47      kent 		strcpy(dip->label.name, AudioCinputs);
    517      1.47      kent 		break;
    518      1.47      kent 	case AUDIOAMD_OUTPUT_CLASS:
    519      1.47      kent 		dip->type = AUDIO_MIXER_CLASS;
    520      1.47      kent 		dip->mixer_class = AUDIOAMD_OUTPUT_CLASS;
    521      1.47      kent 		dip->next = dip->prev = AUDIO_MIXER_LAST;
    522      1.47      kent 		strcpy(dip->label.name, AudioCoutputs);
    523      1.47      kent 		break;
    524      1.47      kent 	case AUDIOAMD_RECORD_CLASS:
    525      1.47      kent 		dip->type = AUDIO_MIXER_CLASS;
    526      1.47      kent 		dip->mixer_class = AUDIOAMD_RECORD_CLASS;
    527      1.47      kent 		dip->next = dip->prev = AUDIO_MIXER_LAST;
    528      1.47      kent 		strcpy(dip->label.name, AudioCrecord);
    529      1.47      kent 		break;
    530      1.47      kent 	case AUDIOAMD_MONITOR_CLASS:
    531      1.47      kent 		dip->type = AUDIO_MIXER_CLASS;
    532      1.47      kent 		dip->mixer_class = AUDIOAMD_MONITOR_CLASS;
    533      1.47      kent 		dip->next = dip->prev = AUDIO_MIXER_LAST;
    534      1.47      kent 		strcpy(dip->label.name, AudioCmonitor);
    535      1.47      kent 		break;
    536      1.47      kent 	default:
    537      1.47      kent 		return ENXIO;
    538      1.47      kent 		/*NOTREACHED*/
    539      1.43  augustss 	}
    540      1.43  augustss 
    541      1.43  augustss 	DPRINTF(("AUDIO_MIXER_DEVINFO: name=%s\n", dip->label.name));
    542      1.43  augustss 
    543      1.47      kent 	return 0;
    544       1.1        pk }
    545      1.43  augustss 
    546      1.39  jonathan #endif	/* NAUDIO */
    547