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