Home | History | Annotate | Line # | Download | only in ic
am7930.c revision 1.50.56.1
      1  1.50.56.1       mrg /*	$NetBSD: am7930.c,v 1.50.56.1 2011/11/20 10:56:18 mrg 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.50.56.1       mrg __KERNEL_RCSID(0, "$NetBSD: am7930.c,v 1.50.56.1 2011/11/20 10:56:18 mrg 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.1        pk #include <machine/autoconf.h>
     53       1.50        ad #include <sys/cpu.h>
     54        1.1        pk 
     55        1.1        pk #include <sys/audioio.h>
     56        1.1        pk #include <dev/audio_if.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.1        pk 
    141        1.1        pk /*
    142       1.39  jonathan  * Reset chip and set boot-time softc defaults.
    143        1.1        pk  */
    144        1.1        pk void
    145       1.47      kent am7930_init(struct am7930_softc *sc, int flag)
    146       1.36        pk {
    147       1.41  jonathan 
    148       1.43  augustss 	DPRINTF(("am7930_init()\n"));
    149       1.39  jonathan 
    150        1.1        pk 	/* set boot defaults */
    151        1.1        pk 	sc->sc_rlevel = 128;
    152        1.1        pk 	sc->sc_plevel = 128;
    153        1.1        pk 	sc->sc_mlevel = 0;
    154       1.43  augustss 	sc->sc_out_port = AUDIOAMD_SPEAKER_VOL;
    155       1.43  augustss 	sc->sc_mic_mute = 0;
    156       1.43  augustss 
    157       1.43  augustss 	/* disable sample interrupts */
    158       1.43  augustss 	AM7930_IWRITE(sc, AM7930_IREG_MUX_MCR4, 0);
    159       1.43  augustss 
    160       1.43  augustss 	/* initialise voice and data, and disable interrupts */
    161       1.43  augustss 	AM7930_IWRITE(sc, AM7930_IREG_INIT,
    162       1.43  augustss 		AM7930_INIT_PMS_ACTIVE | AM7930_INIT_INT_DISABLE);
    163       1.43  augustss 
    164       1.43  augustss 	if (flag == AUDIOAMD_DMA_MODE) {
    165       1.43  augustss 
    166       1.43  augustss 		/* configure PP for serial (SBP) mode */
    167       1.43  augustss 		AM7930_IWRITE(sc, AM7930_IREG_PP_PPCR1, AM7930_PPCR1_SBP);
    168       1.43  augustss 
    169       1.43  augustss 		/*
    170       1.43  augustss 		 * Initialise the MUX unit - route the MAP to the PP
    171       1.43  augustss 		 */
    172       1.43  augustss 		AM7930_IWRITE(sc, AM7930_IREG_MUX_MCR1,
    173       1.43  augustss 			(AM7930_MCRCHAN_BA << 4) | AM7930_MCRCHAN_BD);
    174       1.43  augustss 		AM7930_IWRITE(sc, AM7930_IREG_MUX_MCR2, AM7930_MCRCHAN_NC);
    175       1.43  augustss 		AM7930_IWRITE(sc, AM7930_IREG_MUX_MCR3, AM7930_MCRCHAN_NC);
    176       1.43  augustss 
    177       1.43  augustss 	} else {
    178       1.43  augustss 
    179       1.43  augustss 		/*
    180       1.43  augustss 		 * Initialize the MUX unit.  We use MCR3 to route the MAP
    181       1.43  augustss 		 * through channel Bb.  MCR1 and MCR2 are unused.
    182       1.43  augustss 		 * Setting the INT enable bit in MCR4 will generate an
    183       1.43  augustss 		 * interrupt on each converted audio sample.
    184       1.43  augustss 		 */
    185       1.43  augustss 		AM7930_IWRITE(sc, AM7930_IREG_MUX_MCR1, 0);
    186       1.43  augustss 		AM7930_IWRITE(sc, AM7930_IREG_MUX_MCR2, 0);
    187       1.43  augustss 		AM7930_IWRITE(sc, AM7930_IREG_MUX_MCR3,
    188       1.43  augustss 			(AM7930_MCRCHAN_BB << 4) | AM7930_MCRCHAN_BA);
    189       1.43  augustss 		AM7930_IWRITE(sc, AM7930_IREG_MUX_MCR4,
    190       1.43  augustss 			AM7930_MCR4_INT_ENABLE);
    191       1.43  augustss 	}
    192       1.43  augustss 
    193  1.50.56.1       mrg 	mutex_init(&sc->sc_lock, MUTEX_DEFAULT, IPL_NONE);
    194  1.50.56.1       mrg 	/* We used to take splaudio() in commit_settings */
    195  1.50.56.1       mrg 	mutex_init(&sc->sc_intr_lock, MUTEX_DEFAULT, IPL_VM);
    196        1.1        pk }
    197        1.1        pk 
    198        1.1        pk int
    199       1.47      kent am7930_open(void *addr, int flags)
    200        1.1        pk {
    201       1.47      kent 	struct am7930_softc *sc;
    202        1.1        pk 
    203       1.47      kent 	sc = addr;
    204       1.26  augustss 	DPRINTF(("sa_open: unit %p\n", sc));
    205       1.43  augustss 	sc->sc_glue->onopen(sc);
    206       1.48  christos 	DPRINTF(("saopen: ok -> sc=%p\n",sc));
    207       1.47      kent 	return 0;
    208        1.1        pk }
    209        1.1        pk 
    210        1.1        pk void
    211       1.47      kent am7930_close(void *addr)
    212        1.1        pk {
    213       1.47      kent 	struct am7930_softc *sc;
    214        1.1        pk 
    215       1.47      kent 	sc = addr;
    216       1.40        pk 	DPRINTF(("sa_close: sc=%p\n", sc));
    217       1.43  augustss 	sc->sc_glue->onclose(sc);
    218        1.1        pk 	DPRINTF(("sa_close: closed.\n"));
    219        1.1        pk }
    220        1.1        pk 
    221       1.43  augustss /*
    222       1.43  augustss  * XXX should be extended to handle a few of the more common formats.
    223       1.43  augustss  */
    224        1.1        pk int
    225       1.47      kent am7930_set_params(void *addr, int setmode, int usemode, audio_params_t *p,
    226       1.47      kent     audio_params_t *r, stream_filter_list_t *pfil, stream_filter_list_t *rfil)
    227        1.1        pk {
    228       1.46      kent 	audio_params_t hw;
    229       1.47      kent 	struct am7930_softc *sc;
    230       1.43  augustss 
    231       1.47      kent 	sc = addr;
    232       1.43  augustss 	if ((usemode & AUMODE_PLAY) == AUMODE_PLAY) {
    233       1.43  augustss 		if (p->sample_rate < 7500 || p->sample_rate > 8500 ||
    234       1.43  augustss 			p->encoding != AUDIO_ENCODING_ULAW ||
    235       1.43  augustss 			p->precision != 8 ||
    236       1.43  augustss 			p->channels != 1)
    237       1.43  augustss 				return EINVAL;
    238       1.43  augustss 		p->sample_rate = 8000;
    239       1.46      kent 		if (sc->sc_glue->output_conv != NULL) {
    240       1.46      kent 			hw = *p;
    241       1.46      kent 			hw.encoding = AUDIO_ENCODING_NONE;
    242       1.46      kent 			hw.precision *= sc->sc_glue->factor;
    243       1.46      kent 			pfil->append(pfil, sc->sc_glue->output_conv, &hw);
    244       1.43  augustss 		}
    245       1.43  augustss 	}
    246       1.43  augustss 	if ((usemode & AUMODE_RECORD) == AUMODE_RECORD) {
    247       1.43  augustss 		if (r->sample_rate < 7500 || r->sample_rate > 8500 ||
    248       1.43  augustss 			r->encoding != AUDIO_ENCODING_ULAW ||
    249       1.43  augustss 			r->precision != 8 ||
    250       1.43  augustss 			r->channels != 1)
    251       1.43  augustss 				return EINVAL;
    252       1.43  augustss 		r->sample_rate = 8000;
    253       1.46      kent 		if (sc->sc_glue->input_conv != NULL) {
    254       1.46      kent 			hw = *r;
    255       1.46      kent 			hw.encoding = AUDIO_ENCODING_NONE;
    256       1.46      kent 			hw.precision *= sc->sc_glue->factor;
    257       1.46      kent 			pfil->append(rfil, sc->sc_glue->input_conv, &hw);
    258       1.43  augustss 		}
    259       1.43  augustss 	}
    260       1.20  augustss 
    261       1.20  augustss 	return 0;
    262        1.1        pk }
    263        1.1        pk 
    264        1.1        pk int
    265       1.47      kent am7930_query_encoding(void *addr, struct audio_encoding *fp)
    266       1.47      kent {
    267       1.47      kent 	switch (fp->index) {
    268       1.47      kent 	case 0:
    269       1.47      kent 		strcpy(fp->name, AudioEmulaw);
    270       1.47      kent 		fp->encoding = AUDIO_ENCODING_ULAW;
    271       1.47      kent 		fp->precision = 8;
    272       1.47      kent 		fp->flags = 0;
    273       1.47      kent 		break;
    274       1.47      kent 	default:
    275       1.47      kent 		return EINVAL;
    276        1.1        pk 		    /*NOTREACHED*/
    277        1.1        pk 	}
    278       1.47      kent 	return 0;
    279        1.1        pk }
    280        1.1        pk 
    281        1.1        pk int
    282       1.47      kent am7930_round_blocksize(void *addr, int blk,
    283       1.47      kent     int mode, const audio_params_t *param)
    284        1.1        pk {
    285       1.47      kent 	return blk;
    286        1.1        pk }
    287        1.1        pk 
    288        1.1        pk int
    289       1.47      kent am7930_commit_settings(void *addr)
    290        1.1        pk {
    291       1.47      kent 	struct am7930_softc *sc;
    292       1.47      kent 	uint16_t ger, gr, gx, stgr;
    293       1.47      kent 	uint8_t mmr2, mmr3;
    294  1.50.56.1       mrg 	int level;
    295       1.10        pk 
    296        1.1        pk 	DPRINTF(("sa_commit.\n"));
    297       1.47      kent 	sc = addr;
    298       1.43  augustss 	gx = gx_coeff[sc->sc_rlevel];
    299       1.43  augustss 	stgr = gx_coeff[sc->sc_mlevel];
    300       1.10        pk 
    301        1.1        pk 	level = (sc->sc_plevel * (256 + NGER)) >> 8;
    302        1.1        pk 	if (level >= 256) {
    303       1.43  augustss 		ger = ger_coeff[level - 256];
    304       1.43  augustss 		gr = gx_coeff[255];
    305        1.1        pk 	} else {
    306       1.43  augustss 		ger = ger_coeff[0];
    307       1.43  augustss 		gr = gx_coeff[level];
    308        1.1        pk 	}
    309        1.1        pk 
    310  1.50.56.1       mrg 	mutex_enter(&sc->sc_intr_lock);
    311       1.10        pk 
    312       1.43  augustss 	mmr2 = AM7930_IREAD(sc, AM7930_IREG_MAP_MMR2);
    313       1.43  augustss 	if (sc->sc_out_port == AUDIOAMD_SPEAKER_VOL)
    314       1.43  augustss 		mmr2 |= AM7930_MMR2_LS;
    315       1.43  augustss 	else
    316       1.43  augustss 		mmr2 &= ~AM7930_MMR2_LS;
    317       1.43  augustss 	AM7930_IWRITE(sc, AM7930_IREG_MAP_MMR2, mmr2);
    318       1.41  jonathan 
    319       1.43  augustss 	mmr3 = AM7930_IREAD(sc, AM7930_IREG_MAP_MMR3);
    320       1.43  augustss 	if (sc->sc_mic_mute)
    321       1.43  augustss 		mmr3 |= AM7930_MMR3_MUTE;
    322       1.43  augustss 	else
    323       1.43  augustss 		mmr3 &= ~AM7930_MMR3_MUTE;
    324       1.43  augustss 	AM7930_IWRITE(sc, AM7930_IREG_MAP_MMR3, mmr3);
    325       1.41  jonathan 
    326       1.43  augustss 	AM7930_IWRITE(sc, AM7930_IREG_MAP_MMR1,
    327       1.43  augustss 		AM7930_MMR1_GX | AM7930_MMR1_GER |
    328       1.43  augustss 		AM7930_MMR1_GR | AM7930_MMR1_STG);
    329       1.43  augustss 
    330       1.43  augustss 	AM7930_IWRITE16(sc, AM7930_IREG_MAP_GX, gx);
    331       1.43  augustss 	AM7930_IWRITE16(sc, AM7930_IREG_MAP_STG, stgr);
    332       1.43  augustss 	AM7930_IWRITE16(sc, AM7930_IREG_MAP_GR, gr);
    333       1.43  augustss 	AM7930_IWRITE16(sc, AM7930_IREG_MAP_GER, ger);
    334       1.41  jonathan 
    335  1.50.56.1       mrg 	mutex_exit(&sc->sc_intr_lock);
    336        1.1        pk 
    337       1.47      kent 	return 0;
    338        1.1        pk }
    339        1.1        pk 
    340        1.1        pk int
    341       1.47      kent am7930_halt_output(void *addr)
    342        1.1        pk {
    343       1.47      kent 	struct am7930_softc *sc;
    344        1.1        pk 
    345       1.47      kent 	sc = addr;
    346        1.1        pk 	/* XXX only halt, if input is also halted ?? */
    347       1.43  augustss 	AM7930_IWRITE(sc, AM7930_IREG_INIT,
    348       1.47      kent 	    AM7930_INIT_PMS_ACTIVE | AM7930_INIT_INT_DISABLE);
    349       1.47      kent 	return 0;
    350        1.1        pk }
    351        1.1        pk 
    352        1.1        pk int
    353       1.47      kent am7930_halt_input(void *addr)
    354        1.1        pk {
    355       1.47      kent 	struct am7930_softc *sc;
    356        1.1        pk 
    357       1.47      kent 	sc = addr;
    358        1.1        pk 	/* XXX only halt, if output is also halted ?? */
    359       1.43  augustss 	AM7930_IWRITE(sc, AM7930_IREG_INIT,
    360       1.47      kent 	    AM7930_INIT_PMS_ACTIVE | AM7930_INIT_INT_DISABLE);
    361       1.47      kent 	return 0;
    362        1.1        pk }
    363        1.1        pk 
    364       1.43  augustss /*
    365       1.43  augustss  * XXX chip is full-duplex, but really attach-dependent.
    366       1.43  augustss  * For now we know of no half-duplex attachments.
    367       1.43  augustss  */
    368        1.1        pk int
    369       1.47      kent am7930_get_props(void *addr)
    370        1.1        pk {
    371       1.43  augustss 	return AUDIO_PROP_FULLDUPLEX;
    372       1.43  augustss }
    373       1.43  augustss 
    374       1.43  augustss /*
    375       1.43  augustss  * Attach-dependent channel set/query
    376       1.43  augustss  */
    377       1.43  augustss int
    378       1.47      kent am7930_set_port(void *addr, mixer_ctrl_t *cp)
    379       1.43  augustss {
    380       1.47      kent 	struct am7930_softc *sc;
    381       1.43  augustss 
    382       1.43  augustss 	DPRINTF(("am7930_set_port: port=%d", cp->dev));
    383       1.47      kent 	sc = addr;
    384       1.43  augustss 	if (cp->dev == AUDIOAMD_RECORD_SOURCE ||
    385       1.43  augustss 		cp->dev == AUDIOAMD_MONITOR_OUTPUT ||
    386       1.43  augustss 		cp->dev == AUDIOAMD_MIC_MUTE) {
    387       1.43  augustss 		if (cp->type != AUDIO_MIXER_ENUM)
    388       1.47      kent 			return EINVAL;
    389       1.43  augustss 	} else if (cp->type != AUDIO_MIXER_VALUE ||
    390       1.47      kent 	    cp->un.value.num_channels != 1) {
    391       1.47      kent 		return EINVAL;
    392       1.43  augustss 	}
    393       1.43  augustss 
    394       1.43  augustss 	switch(cp->dev) {
    395       1.43  augustss 	    case AUDIOAMD_MIC_VOL:
    396       1.43  augustss 		    sc->sc_rlevel = cp->un.value.level[AUDIO_MIXER_LEVEL_MONO];
    397       1.43  augustss 		    break;
    398       1.43  augustss 	    case AUDIOAMD_SPEAKER_VOL:
    399       1.43  augustss 	    case AUDIOAMD_HEADPHONES_VOL:
    400       1.43  augustss 		    sc->sc_plevel = cp->un.value.level[AUDIO_MIXER_LEVEL_MONO];
    401       1.43  augustss 		    break;
    402       1.43  augustss 	    case AUDIOAMD_MONITOR_VOL:
    403       1.43  augustss 		    sc->sc_mlevel = cp->un.value.level[AUDIO_MIXER_LEVEL_MONO];
    404       1.43  augustss 		    break;
    405       1.43  augustss 	    case AUDIOAMD_RECORD_SOURCE:
    406       1.43  augustss 		    if (cp->un.ord != AUDIOAMD_MIC_VOL)
    407       1.43  augustss 			    return EINVAL;
    408       1.43  augustss 		    break;
    409       1.43  augustss 	    case AUDIOAMD_MIC_MUTE:
    410       1.43  augustss 		    sc->sc_mic_mute = cp->un.ord;
    411       1.43  augustss 		    break;
    412       1.43  augustss 	    case AUDIOAMD_MONITOR_OUTPUT:
    413       1.43  augustss 		    if (cp->un.ord != AUDIOAMD_SPEAKER_VOL &&
    414       1.43  augustss 			cp->un.ord != AUDIOAMD_HEADPHONES_VOL)
    415       1.43  augustss 			    return EINVAL;
    416       1.43  augustss 			sc->sc_out_port = cp->un.ord;
    417       1.43  augustss 		    break;
    418       1.43  augustss 	    default:
    419       1.47      kent 		    return EINVAL;
    420       1.43  augustss 		    /* NOTREACHED */
    421       1.43  augustss 	}
    422       1.43  augustss 	return 0;
    423       1.43  augustss }
    424       1.43  augustss 
    425       1.43  augustss int
    426       1.47      kent am7930_get_port(void *addr, mixer_ctrl_t *cp)
    427       1.43  augustss {
    428       1.47      kent 	struct am7930_softc *sc;
    429       1.43  augustss 
    430       1.43  augustss 	DPRINTF(("am7930_get_port: port=%d\n", cp->dev));
    431       1.47      kent 	sc = addr;
    432       1.43  augustss 	if (cp->dev == AUDIOAMD_RECORD_SOURCE ||
    433       1.43  augustss 		cp->dev == AUDIOAMD_MONITOR_OUTPUT ||
    434       1.43  augustss 		cp->dev == AUDIOAMD_MIC_MUTE) {
    435       1.43  augustss 		if (cp->type != AUDIO_MIXER_ENUM)
    436       1.47      kent 			return EINVAL;
    437       1.43  augustss 	} else if (cp->type != AUDIO_MIXER_VALUE ||
    438       1.43  augustss 		cp->un.value.num_channels != 1) {
    439       1.47      kent 		return EINVAL;
    440       1.43  augustss 	}
    441       1.43  augustss 
    442       1.43  augustss 	switch(cp->dev) {
    443       1.43  augustss 	    case AUDIOAMD_MIC_VOL:
    444       1.43  augustss 		    cp->un.value.level[AUDIO_MIXER_LEVEL_MONO] = sc->sc_rlevel;
    445       1.43  augustss 		    break;
    446       1.43  augustss 	    case AUDIOAMD_SPEAKER_VOL:
    447       1.43  augustss 	    case AUDIOAMD_HEADPHONES_VOL:
    448       1.43  augustss 		    cp->un.value.level[AUDIO_MIXER_LEVEL_MONO] = sc->sc_plevel;
    449       1.43  augustss 		    break;
    450       1.43  augustss 	    case AUDIOAMD_MONITOR_VOL:
    451       1.43  augustss 		    cp->un.value.level[AUDIO_MIXER_LEVEL_MONO] = sc->sc_mlevel;
    452       1.43  augustss 		    break;
    453       1.43  augustss 	    case AUDIOAMD_RECORD_SOURCE:
    454       1.43  augustss 		    cp->un.ord = AUDIOAMD_MIC_VOL;
    455       1.43  augustss 		    break;
    456       1.43  augustss 	    case AUDIOAMD_MIC_MUTE:
    457       1.43  augustss 		    cp->un.ord = sc->sc_mic_mute;
    458       1.43  augustss 		    break;
    459       1.43  augustss 	    case AUDIOAMD_MONITOR_OUTPUT:
    460       1.43  augustss 		    cp->un.ord = sc->sc_out_port;
    461       1.43  augustss 		    break;
    462       1.43  augustss 	    default:
    463       1.47      kent 		    return EINVAL;
    464       1.43  augustss 		    /* NOTREACHED */
    465       1.43  augustss 	}
    466       1.43  augustss 	return 0;
    467        1.1        pk }
    468        1.1        pk 
    469       1.26  augustss 
    470       1.39  jonathan /*
    471       1.43  augustss  * Define mixer control facilities.
    472       1.39  jonathan  */
    473       1.26  augustss int
    474       1.47      kent am7930_query_devinfo(void *addr, mixer_devinfo_t *dip)
    475       1.26  augustss {
    476       1.43  augustss 
    477       1.43  augustss 	DPRINTF(("am7930_query_devinfo()\n"));
    478       1.43  augustss 
    479       1.43  augustss 	switch(dip->index) {
    480       1.47      kent 	case AUDIOAMD_MIC_VOL:
    481       1.47      kent 		dip->type = AUDIO_MIXER_VALUE;
    482       1.47      kent 		dip->mixer_class = AUDIOAMD_INPUT_CLASS;
    483       1.47      kent 		dip->prev =  AUDIO_MIXER_LAST;
    484       1.47      kent 		dip->next = AUDIOAMD_MIC_MUTE;
    485       1.47      kent 		strcpy(dip->label.name, AudioNmicrophone);
    486       1.47      kent 		dip->un.v.num_channels = 1;
    487       1.47      kent 		strcpy(dip->un.v.units.name, AudioNvolume);
    488       1.47      kent 		break;
    489       1.47      kent 	case AUDIOAMD_SPEAKER_VOL:
    490       1.47      kent 		dip->type = AUDIO_MIXER_VALUE;
    491       1.47      kent 		dip->mixer_class = AUDIOAMD_OUTPUT_CLASS;
    492       1.47      kent 		dip->prev = dip->next = AUDIO_MIXER_LAST;
    493       1.47      kent 		strcpy(dip->label.name, AudioNspeaker);
    494       1.47      kent 		dip->un.v.num_channels = 1;
    495       1.47      kent 		strcpy(dip->un.v.units.name, AudioNvolume);
    496       1.47      kent 		break;
    497       1.47      kent 	case AUDIOAMD_HEADPHONES_VOL:
    498       1.47      kent 		dip->type = AUDIO_MIXER_VALUE;
    499       1.47      kent 		dip->mixer_class = AUDIOAMD_OUTPUT_CLASS;
    500       1.47      kent 		dip->prev = dip->next = AUDIO_MIXER_LAST;
    501       1.47      kent 		strcpy(dip->label.name, AudioNheadphone);
    502       1.47      kent 		dip->un.v.num_channels = 1;
    503       1.47      kent 		strcpy(dip->un.v.units.name, AudioNvolume);
    504       1.47      kent 		break;
    505       1.47      kent 	case AUDIOAMD_MONITOR_VOL:
    506       1.47      kent 		dip->type = AUDIO_MIXER_VALUE;
    507       1.47      kent 		dip->mixer_class = AUDIOAMD_MONITOR_CLASS;
    508       1.47      kent 		dip->prev = dip->next = AUDIO_MIXER_LAST;
    509       1.47      kent 		strcpy(dip->label.name, AudioNmonitor);
    510       1.47      kent 		dip->un.v.num_channels = 1;
    511       1.47      kent 		strcpy(dip->un.v.units.name, AudioNvolume);
    512       1.47      kent 		break;
    513       1.47      kent 	case AUDIOAMD_RECORD_SOURCE:
    514       1.47      kent 		dip->type = AUDIO_MIXER_ENUM;
    515       1.47      kent 		dip->mixer_class = AUDIOAMD_RECORD_CLASS;
    516       1.47      kent 		dip->next = dip->prev = AUDIO_MIXER_LAST;
    517       1.47      kent 		strcpy(dip->label.name, AudioNsource);
    518       1.47      kent 		dip->un.e.num_mem = 1;
    519       1.47      kent 		strcpy(dip->un.e.member[0].label.name, AudioNmicrophone);
    520       1.47      kent 		dip->un.e.member[0].ord = AUDIOAMD_MIC_VOL;
    521       1.47      kent 		break;
    522       1.47      kent 	case AUDIOAMD_MONITOR_OUTPUT:
    523       1.47      kent 		dip->type = AUDIO_MIXER_ENUM;
    524       1.47      kent 		dip->mixer_class = AUDIOAMD_MONITOR_CLASS;
    525       1.47      kent 		dip->next = dip->prev = AUDIO_MIXER_LAST;
    526       1.47      kent 		strcpy(dip->label.name, AudioNoutput);
    527       1.47      kent 		dip->un.e.num_mem = 2;
    528       1.47      kent 		strcpy(dip->un.e.member[0].label.name, AudioNspeaker);
    529       1.47      kent 		dip->un.e.member[0].ord = AUDIOAMD_SPEAKER_VOL;
    530       1.47      kent 		strcpy(dip->un.e.member[1].label.name, AudioNheadphone);
    531       1.47      kent 		dip->un.e.member[1].ord = AUDIOAMD_HEADPHONES_VOL;
    532       1.47      kent 		break;
    533       1.47      kent 	case AUDIOAMD_MIC_MUTE:
    534       1.47      kent 		dip->type = AUDIO_MIXER_ENUM;
    535       1.47      kent 		dip->mixer_class = AUDIOAMD_INPUT_CLASS;
    536       1.47      kent 		dip->prev =  AUDIOAMD_MIC_VOL;
    537       1.47      kent 		dip->next = AUDIO_MIXER_LAST;
    538       1.47      kent 		strcpy(dip->label.name, AudioNmute);
    539       1.47      kent 		dip->un.e.num_mem = 2;
    540       1.47      kent 		strcpy(dip->un.e.member[0].label.name, AudioNoff);
    541       1.47      kent 		dip->un.e.member[0].ord = 0;
    542       1.47      kent 		strcpy(dip->un.e.member[1].label.name, AudioNon);
    543       1.47      kent 		dip->un.e.member[1].ord = 1;
    544       1.47      kent 		break;
    545       1.47      kent 	case AUDIOAMD_INPUT_CLASS:
    546       1.47      kent 		dip->type = AUDIO_MIXER_CLASS;
    547       1.47      kent 		dip->mixer_class = AUDIOAMD_INPUT_CLASS;
    548       1.47      kent 		dip->next = dip->prev = AUDIO_MIXER_LAST;
    549       1.47      kent 		strcpy(dip->label.name, AudioCinputs);
    550       1.47      kent 		break;
    551       1.47      kent 	case AUDIOAMD_OUTPUT_CLASS:
    552       1.47      kent 		dip->type = AUDIO_MIXER_CLASS;
    553       1.47      kent 		dip->mixer_class = AUDIOAMD_OUTPUT_CLASS;
    554       1.47      kent 		dip->next = dip->prev = AUDIO_MIXER_LAST;
    555       1.47      kent 		strcpy(dip->label.name, AudioCoutputs);
    556       1.47      kent 		break;
    557       1.47      kent 	case AUDIOAMD_RECORD_CLASS:
    558       1.47      kent 		dip->type = AUDIO_MIXER_CLASS;
    559       1.47      kent 		dip->mixer_class = AUDIOAMD_RECORD_CLASS;
    560       1.47      kent 		dip->next = dip->prev = AUDIO_MIXER_LAST;
    561       1.47      kent 		strcpy(dip->label.name, AudioCrecord);
    562       1.47      kent 		break;
    563       1.47      kent 	case AUDIOAMD_MONITOR_CLASS:
    564       1.47      kent 		dip->type = AUDIO_MIXER_CLASS;
    565       1.47      kent 		dip->mixer_class = AUDIOAMD_MONITOR_CLASS;
    566       1.47      kent 		dip->next = dip->prev = AUDIO_MIXER_LAST;
    567       1.47      kent 		strcpy(dip->label.name, AudioCmonitor);
    568       1.47      kent 		break;
    569       1.47      kent 	default:
    570       1.47      kent 		return ENXIO;
    571       1.47      kent 		/*NOTREACHED*/
    572       1.43  augustss 	}
    573       1.43  augustss 
    574       1.43  augustss 	DPRINTF(("AUDIO_MIXER_DEVINFO: name=%s\n", dip->label.name));
    575       1.43  augustss 
    576       1.47      kent 	return 0;
    577        1.1        pk }
    578       1.43  augustss 
    579       1.39  jonathan #endif	/* NAUDIO */
    580