Home | History | Annotate | Line # | Download | only in ic
am7930.c revision 1.43
      1  1.43  augustss /*	$NetBSD: am7930.c,v 1.43 2000/05/02 06:30:51 augustss 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.39  jonathan 
     38   1.1        pk #include "audio.h"
     39   1.1        pk #if NAUDIO > 0
     40   1.1        pk 
     41   1.1        pk #include <sys/param.h>
     42   1.1        pk #include <sys/systm.h>
     43   1.1        pk #include <sys/errno.h>
     44   1.1        pk #include <sys/ioctl.h>
     45   1.1        pk #include <sys/device.h>
     46   1.1        pk #include <sys/proc.h>
     47   1.1        pk 
     48  1.36        pk #include <machine/bus.h>
     49   1.1        pk #include <machine/autoconf.h>
     50   1.1        pk #include <machine/cpu.h>
     51   1.1        pk 
     52   1.1        pk #include <sys/audioio.h>
     53   1.1        pk #include <dev/audio_if.h>
     54   1.1        pk 
     55   1.3       cgd #include <dev/ic/am7930reg.h>
     56  1.39  jonathan #include <dev/ic/am7930var.h>
     57   1.1        pk 
     58   1.4    brezak #ifdef AUDIO_DEBUG
     59  1.39  jonathan int     am7930debug = 0;
     60  1.40        pk #define DPRINTF(x)      if (am7930debug) printf x
     61   1.1        pk #else
     62   1.1        pk #define DPRINTF(x)
     63   1.1        pk #endif
     64   1.1        pk 
     65   1.1        pk 
     66   1.1        pk /* The following tables stolen from former (4.4Lite's) sys/sparc/bsd_audio.c */
     67   1.1        pk 
     68   1.1        pk /*
     69   1.1        pk  * gx, gr & stg gains.  this table must contain 256 elements with
     70   1.1        pk  * the 0th being "infinity" (the magic value 9008).  The remaining
     71   1.1        pk  * elements match sun's gain curve (but with higher resolution):
     72   1.1        pk  * -18 to 0dB in .16dB steps then 0 to 12dB in .08dB steps.
     73   1.1        pk  */
     74   1.1        pk static const u_short gx_coeff[256] = {
     75  1.21        pk 	0x9008, 0x8e7c, 0x8e51, 0x8e45, 0x8d42, 0x8d3b, 0x8c36, 0x8c33,
     76   1.1        pk 	0x8b32, 0x8b2a, 0x8b2b, 0x8b2c, 0x8b25, 0x8b23, 0x8b22, 0x8b22,
     77   1.1        pk 	0x9122, 0x8b1a, 0x8aa3, 0x8aa3, 0x8b1c, 0x8aa6, 0x912d, 0x912b,
     78   1.1        pk 	0x8aab, 0x8b12, 0x8aaa, 0x8ab2, 0x9132, 0x8ab4, 0x913c, 0x8abb,
     79   1.1        pk 	0x9142, 0x9144, 0x9151, 0x8ad5, 0x8aeb, 0x8a79, 0x8a5a, 0x8a4a,
     80   1.1        pk 	0x8b03, 0x91c2, 0x91bb, 0x8a3f, 0x8a33, 0x91b2, 0x9212, 0x9213,
     81   1.1        pk 	0x8a2c, 0x921d, 0x8a23, 0x921a, 0x9222, 0x9223, 0x922d, 0x9231,
     82   1.1        pk 	0x9234, 0x9242, 0x925b, 0x92dd, 0x92c1, 0x92b3, 0x92ab, 0x92a4,
     83   1.1        pk 	0x92a2, 0x932b, 0x9341, 0x93d3, 0x93b2, 0x93a2, 0x943c, 0x94b2,
     84   1.1        pk 	0x953a, 0x9653, 0x9782, 0x9e21, 0x9d23, 0x9cd2, 0x9c23, 0x9baa,
     85   1.1        pk 	0x9bde, 0x9b33, 0x9b22, 0x9b1d, 0x9ab2, 0xa142, 0xa1e5, 0x9a3b,
     86   1.1        pk 	0xa213, 0xa1a2, 0xa231, 0xa2eb, 0xa313, 0xa334, 0xa421, 0xa54b,
     87   1.1        pk 	0xada4, 0xac23, 0xab3b, 0xaaab, 0xaa5c, 0xb1a3, 0xb2ca, 0xb3bd,
     88   1.1        pk 	0xbe24, 0xbb2b, 0xba33, 0xc32b, 0xcb5a, 0xd2a2, 0xe31d, 0x0808,
     89   1.1        pk 	0x72ba, 0x62c2, 0x5c32, 0x52db, 0x513e, 0x4cce, 0x43b2, 0x4243,
     90   1.1        pk 	0x41b4, 0x3b12, 0x3bc3, 0x3df2, 0x34bd, 0x3334, 0x32c2, 0x3224,
     91   1.1        pk 	0x31aa, 0x2a7b, 0x2aaa, 0x2b23, 0x2bba, 0x2c42, 0x2e23, 0x25bb,
     92   1.1        pk 	0x242b, 0x240f, 0x231a, 0x22bb, 0x2241, 0x2223, 0x221f, 0x1a33,
     93   1.1        pk 	0x1a4a, 0x1acd, 0x2132, 0x1b1b, 0x1b2c, 0x1b62, 0x1c12, 0x1c32,
     94   1.1        pk 	0x1d1b, 0x1e71, 0x16b1, 0x1522, 0x1434, 0x1412, 0x1352, 0x1323,
     95   1.1        pk 	0x1315, 0x12bc, 0x127a, 0x1235, 0x1226, 0x11a2, 0x1216, 0x0a2a,
     96   1.1        pk 	0x11bc, 0x11d1, 0x1163, 0x0ac2, 0x0ab2, 0x0aab, 0x0b1b, 0x0b23,
     97   1.1        pk 	0x0b33, 0x0c0f, 0x0bb3, 0x0c1b, 0x0c3e, 0x0cb1, 0x0d4c, 0x0ec1,
     98   1.1        pk 	0x079a, 0x0614, 0x0521, 0x047c, 0x0422, 0x03b1, 0x03e3, 0x0333,
     99   1.1        pk 	0x0322, 0x031c, 0x02aa, 0x02ba, 0x02f2, 0x0242, 0x0232, 0x0227,
    100   1.1        pk 	0x0222, 0x021b, 0x01ad, 0x0212, 0x01b2, 0x01bb, 0x01cb, 0x01f6,
    101   1.1        pk 	0x0152, 0x013a, 0x0133, 0x0131, 0x012c, 0x0123, 0x0122, 0x00a2,
    102   1.1        pk 	0x011b, 0x011e, 0x0114, 0x00b1, 0x00aa, 0x00b3, 0x00bd, 0x00ba,
    103   1.1        pk 	0x00c5, 0x00d3, 0x00f3, 0x0062, 0x0051, 0x0042, 0x003b, 0x0033,
    104   1.1        pk 	0x0032, 0x002a, 0x002c, 0x0025, 0x0023, 0x0022, 0x001a, 0x0021,
    105   1.1        pk 	0x001b, 0x001b, 0x001d, 0x0015, 0x0013, 0x0013, 0x0012, 0x0012,
    106   1.1        pk 	0x000a, 0x000a, 0x0011, 0x0011, 0x000b, 0x000b, 0x000c, 0x000e,
    107   1.1        pk };
    108   1.1        pk 
    109   1.1        pk /*
    110   1.1        pk  * second stage play gain.
    111   1.1        pk  */
    112   1.1        pk static const u_short ger_coeff[] = {
    113   1.1        pk 	0x431f, /* 5. dB */
    114   1.1        pk 	0x331f, /* 5.5 dB */
    115   1.1        pk 	0x40dd, /* 6. dB */
    116   1.1        pk 	0x11dd, /* 6.5 dB */
    117   1.1        pk 	0x440f, /* 7. dB */
    118   1.1        pk 	0x411f, /* 7.5 dB */
    119   1.1        pk 	0x311f, /* 8. dB */
    120   1.1        pk 	0x5520, /* 8.5 dB */
    121   1.1        pk 	0x10dd, /* 9. dB */
    122   1.1        pk 	0x4211, /* 9.5 dB */
    123   1.1        pk 	0x410f, /* 10. dB */
    124   1.1        pk 	0x111f, /* 10.5 dB */
    125   1.1        pk 	0x600b, /* 11. dB */
    126   1.1        pk 	0x00dd, /* 11.5 dB */
    127   1.1        pk 	0x4210, /* 12. dB */
    128   1.1        pk 	0x110f, /* 13. dB */
    129   1.1        pk 	0x7200, /* 14. dB */
    130   1.1        pk 	0x2110, /* 15. dB */
    131   1.1        pk 	0x2200, /* 15.9 dB */
    132   1.1        pk 	0x000b, /* 16.9 dB */
    133   1.1        pk 	0x000f  /* 18. dB */
    134   1.1        pk #define NGER (sizeof(ger_coeff) / sizeof(ger_coeff[0]))
    135   1.1        pk };
    136   1.1        pk 
    137   1.1        pk 
    138   1.1        pk /*
    139  1.39  jonathan  * Reset chip and set boot-time softc defaults.
    140   1.1        pk  */
    141   1.1        pk void
    142  1.43  augustss am7930_init(sc, flag)
    143  1.39  jonathan 	struct am7930_softc *sc;
    144  1.43  augustss 	int flag;
    145  1.36        pk {
    146  1.41  jonathan 
    147  1.43  augustss 	DPRINTF(("am7930_init()\n"));
    148  1.39  jonathan 
    149   1.1        pk 	/* set boot defaults */
    150   1.1        pk 	sc->sc_rlevel = 128;
    151   1.1        pk 	sc->sc_plevel = 128;
    152   1.1        pk 	sc->sc_mlevel = 0;
    153  1.43  augustss 	sc->sc_out_port = AUDIOAMD_SPEAKER_VOL;
    154  1.43  augustss 	sc->sc_mic_mute = 0;
    155  1.43  augustss 
    156  1.43  augustss 	/* disable sample interrupts */
    157  1.43  augustss 	AM7930_IWRITE(sc, AM7930_IREG_MUX_MCR4, 0);
    158  1.43  augustss 
    159  1.43  augustss 	/* initialise voice and data, and disable interrupts */
    160  1.43  augustss 	AM7930_IWRITE(sc, AM7930_IREG_INIT,
    161  1.43  augustss 		AM7930_INIT_PMS_ACTIVE | AM7930_INIT_INT_DISABLE);
    162  1.43  augustss 
    163  1.43  augustss 	if (flag == AUDIOAMD_DMA_MODE) {
    164  1.43  augustss 
    165  1.43  augustss 		/* configure PP for serial (SBP) mode */
    166  1.43  augustss 		AM7930_IWRITE(sc, AM7930_IREG_PP_PPCR1, AM7930_PPCR1_SBP);
    167  1.43  augustss 
    168  1.43  augustss 		/*
    169  1.43  augustss 		 * Initialise the MUX unit - route the MAP to the PP
    170  1.43  augustss 		 */
    171  1.43  augustss 		AM7930_IWRITE(sc, AM7930_IREG_MUX_MCR1,
    172  1.43  augustss 			(AM7930_MCRCHAN_BA << 4) | AM7930_MCRCHAN_BD);
    173  1.43  augustss 		AM7930_IWRITE(sc, AM7930_IREG_MUX_MCR2, AM7930_MCRCHAN_NC);
    174  1.43  augustss 		AM7930_IWRITE(sc, AM7930_IREG_MUX_MCR3, AM7930_MCRCHAN_NC);
    175  1.43  augustss 
    176  1.43  augustss 	} else {
    177  1.43  augustss 
    178  1.43  augustss 		/*
    179  1.43  augustss 		 * Initialize the MUX unit.  We use MCR3 to route the MAP
    180  1.43  augustss 		 * through channel Bb.  MCR1 and MCR2 are unused.
    181  1.43  augustss 		 * Setting the INT enable bit in MCR4 will generate an
    182  1.43  augustss 		 * interrupt on each converted audio sample.
    183  1.43  augustss 		 */
    184  1.43  augustss 		AM7930_IWRITE(sc, AM7930_IREG_MUX_MCR1, 0);
    185  1.43  augustss 		AM7930_IWRITE(sc, AM7930_IREG_MUX_MCR2, 0);
    186  1.43  augustss 		AM7930_IWRITE(sc, AM7930_IREG_MUX_MCR3,
    187  1.43  augustss 			(AM7930_MCRCHAN_BB << 4) | AM7930_MCRCHAN_BA);
    188  1.43  augustss 		AM7930_IWRITE(sc, AM7930_IREG_MUX_MCR4,
    189  1.43  augustss 			AM7930_MCR4_INT_ENABLE);
    190  1.43  augustss 	}
    191  1.43  augustss 
    192   1.1        pk }
    193   1.1        pk 
    194   1.1        pk 
    195   1.1        pk int
    196  1.39  jonathan am7930_open(addr, flags)
    197  1.26  augustss 	void *addr;
    198   1.1        pk 	int flags;
    199   1.1        pk {
    200  1.39  jonathan 	struct am7930_softc *sc = addr;
    201   1.1        pk 
    202  1.26  augustss 	DPRINTF(("sa_open: unit %p\n", sc));
    203   1.1        pk 
    204   1.1        pk 	if (sc->sc_open)
    205   1.1        pk 		return (EBUSY);
    206   1.1        pk 	sc->sc_open = 1;
    207   1.1        pk 	sc->sc_locked = 0;
    208   1.1        pk 
    209  1.43  augustss 	sc->sc_glue->onopen(sc);
    210   1.1        pk 
    211  1.41  jonathan 	DPRINTF(("saopen: ok -> sc=0x%p\n",sc));
    212   1.1        pk 
    213   1.1        pk 	return (0);
    214   1.1        pk }
    215   1.1        pk 
    216   1.1        pk void
    217  1.39  jonathan am7930_close(addr)
    218   1.1        pk 	void *addr;
    219   1.1        pk {
    220  1.42  augustss 	struct am7930_softc *sc = addr;
    221   1.1        pk 
    222  1.40        pk 	DPRINTF(("sa_close: sc=%p\n", sc));
    223  1.43  augustss 
    224  1.43  augustss 	sc->sc_glue->onclose(sc);
    225   1.1        pk 	sc->sc_open = 0;
    226   1.1        pk 
    227   1.1        pk 	DPRINTF(("sa_close: closed.\n"));
    228   1.1        pk }
    229   1.1        pk 
    230  1.43  augustss 
    231  1.43  augustss /*
    232  1.43  augustss  * XXX should be extended to handle a few of the more common formats.
    233  1.43  augustss  */
    234   1.1        pk int
    235  1.39  jonathan am7930_set_params(addr, setmode, usemode, p, r)
    236   1.1        pk 	void *addr;
    237  1.28  augustss 	int setmode, usemode;
    238  1.28  augustss 	struct audio_params *p, *r;
    239   1.1        pk {
    240  1.43  augustss 	struct am7930_softc *sc = addr;
    241  1.43  augustss 
    242  1.43  augustss 	if ((usemode & AUMODE_PLAY) == AUMODE_PLAY) {
    243  1.43  augustss 		if (p->sample_rate < 7500 || p->sample_rate > 8500 ||
    244  1.43  augustss 			p->encoding != AUDIO_ENCODING_ULAW ||
    245  1.43  augustss 			p->precision != 8 ||
    246  1.43  augustss 			p->channels != 1)
    247  1.43  augustss 				return EINVAL;
    248  1.43  augustss 		p->sample_rate = 8000;
    249  1.43  augustss 		if (sc->sc_glue->factor > 1) {
    250  1.43  augustss 			p->factor = sc->sc_glue->factor;
    251  1.43  augustss 			p->sw_code = sc->sc_glue->output_conv;
    252  1.43  augustss 		}
    253  1.43  augustss 	}
    254  1.43  augustss 	if ((usemode & AUMODE_RECORD) == AUMODE_RECORD) {
    255  1.43  augustss 		if (r->sample_rate < 7500 || r->sample_rate > 8500 ||
    256  1.43  augustss 			r->encoding != AUDIO_ENCODING_ULAW ||
    257  1.43  augustss 			r->precision != 8 ||
    258  1.43  augustss 			r->channels != 1)
    259  1.43  augustss 				return EINVAL;
    260  1.43  augustss 		r->sample_rate = 8000;
    261  1.43  augustss 		if (sc->sc_glue->factor > 1) {
    262  1.43  augustss 			r->factor = sc->sc_glue->factor;
    263  1.43  augustss 			r->sw_code = sc->sc_glue->input_conv;
    264  1.43  augustss 		}
    265  1.43  augustss 	}
    266  1.20  augustss 
    267  1.20  augustss 	return 0;
    268   1.1        pk }
    269   1.1        pk 
    270   1.1        pk int
    271  1.39  jonathan am7930_query_encoding(addr, fp)
    272   1.1        pk 	void *addr;
    273   1.1        pk 	struct audio_encoding *fp;
    274   1.1        pk {
    275   1.1        pk 	switch (fp->index) {	/* ??? */
    276   1.1        pk 	    case 0:
    277  1.19  augustss 		    strcpy(fp->name, AudioEmulaw);
    278  1.19  augustss 		    fp->encoding = AUDIO_ENCODING_ULAW;
    279  1.19  augustss 		    fp->precision = 8;
    280  1.19  augustss 		    fp->flags = 0;
    281   1.1        pk 		    break;
    282   1.1        pk 	    default:
    283   1.1        pk 		    return(EINVAL);
    284   1.1        pk 		    /*NOTREACHED*/
    285   1.1        pk 	}
    286   1.1        pk 	return(0);
    287   1.1        pk }
    288   1.1        pk 
    289  1.39  jonathan 
    290   1.1        pk int
    291  1.39  jonathan am7930_round_blocksize(addr, blk)
    292   1.1        pk 	void *addr;
    293   1.1        pk 	int blk;
    294   1.1        pk {
    295   1.1        pk 	return(blk);
    296   1.1        pk }
    297   1.1        pk 
    298  1.43  augustss 
    299   1.1        pk int
    300  1.39  jonathan am7930_commit_settings(addr)
    301   1.1        pk 	void *addr;
    302   1.1        pk {
    303  1.42  augustss 	struct am7930_softc *sc = addr;
    304  1.43  augustss 	u_int16_t ger, gr, gx, stgr;
    305  1.43  augustss 	u_int8_t mmr2, mmr3;
    306  1.42  augustss 	int s, level;
    307  1.10        pk 
    308   1.1        pk 	DPRINTF(("sa_commit.\n"));
    309   1.1        pk 
    310  1.43  augustss 	gx = gx_coeff[sc->sc_rlevel];
    311  1.43  augustss 	stgr = gx_coeff[sc->sc_mlevel];
    312  1.10        pk 
    313   1.1        pk 	level = (sc->sc_plevel * (256 + NGER)) >> 8;
    314   1.1        pk 	if (level >= 256) {
    315  1.43  augustss 		ger = ger_coeff[level - 256];
    316  1.43  augustss 		gr = gx_coeff[255];
    317   1.1        pk 	} else {
    318  1.43  augustss 		ger = ger_coeff[0];
    319  1.43  augustss 		gr = gx_coeff[level];
    320   1.1        pk 	}
    321   1.1        pk 
    322   1.1        pk 	s = splaudio();
    323  1.10        pk 
    324  1.43  augustss 	mmr2 = AM7930_IREAD(sc, AM7930_IREG_MAP_MMR2);
    325  1.43  augustss 	if (sc->sc_out_port == AUDIOAMD_SPEAKER_VOL)
    326  1.43  augustss 		mmr2 |= AM7930_MMR2_LS;
    327  1.43  augustss 	else
    328  1.43  augustss 		mmr2 &= ~AM7930_MMR2_LS;
    329  1.43  augustss 	AM7930_IWRITE(sc, AM7930_IREG_MAP_MMR2, mmr2);
    330  1.41  jonathan 
    331  1.43  augustss 	mmr3 = AM7930_IREAD(sc, AM7930_IREG_MAP_MMR3);
    332  1.43  augustss 	if (sc->sc_mic_mute)
    333  1.43  augustss 		mmr3 |= AM7930_MMR3_MUTE;
    334  1.43  augustss 	else
    335  1.43  augustss 		mmr3 &= ~AM7930_MMR3_MUTE;
    336  1.43  augustss 	AM7930_IWRITE(sc, AM7930_IREG_MAP_MMR3, mmr3);
    337  1.41  jonathan 
    338  1.43  augustss 	AM7930_IWRITE(sc, AM7930_IREG_MAP_MMR1,
    339  1.43  augustss 		AM7930_MMR1_GX | AM7930_MMR1_GER |
    340  1.43  augustss 		AM7930_MMR1_GR | AM7930_MMR1_STG);
    341  1.43  augustss 
    342  1.43  augustss 	AM7930_IWRITE16(sc, AM7930_IREG_MAP_GX, gx);
    343  1.43  augustss 	AM7930_IWRITE16(sc, AM7930_IREG_MAP_STG, stgr);
    344  1.43  augustss 	AM7930_IWRITE16(sc, AM7930_IREG_MAP_GR, gr);
    345  1.43  augustss 	AM7930_IWRITE16(sc, AM7930_IREG_MAP_GER, ger);
    346  1.41  jonathan 
    347  1.43  augustss 	splx(s);
    348   1.1        pk 
    349   1.1        pk 	return(0);
    350   1.1        pk }
    351   1.1        pk 
    352  1.43  augustss 
    353   1.1        pk int
    354  1.39  jonathan am7930_halt_output(addr)
    355   1.1        pk 	void *addr;
    356   1.1        pk {
    357  1.42  augustss 	struct am7930_softc *sc = addr;
    358   1.1        pk 
    359   1.1        pk 	/* XXX only halt, if input is also halted ?? */
    360  1.43  augustss 	AM7930_IWRITE(sc, AM7930_IREG_INIT,
    361  1.43  augustss 		AM7930_INIT_PMS_ACTIVE | AM7930_INIT_INT_DISABLE);
    362   1.1        pk 	sc->sc_locked = 0;
    363   1.1        pk 
    364   1.1        pk 	return(0);
    365   1.1        pk }
    366   1.1        pk 
    367  1.43  augustss 
    368   1.1        pk int
    369  1.39  jonathan am7930_halt_input(addr)
    370   1.1        pk 	void *addr;
    371   1.1        pk {
    372  1.42  augustss 	struct am7930_softc *sc = addr;
    373   1.1        pk 
    374   1.1        pk 	/* XXX only halt, if output is also halted ?? */
    375  1.43  augustss 	AM7930_IWRITE(sc, AM7930_IREG_INIT,
    376  1.43  augustss 		AM7930_INIT_PMS_ACTIVE | AM7930_INIT_INT_DISABLE);
    377   1.1        pk 	sc->sc_locked = 0;
    378   1.1        pk 
    379   1.1        pk 	return(0);
    380   1.1        pk }
    381   1.1        pk 
    382  1.43  augustss 
    383  1.43  augustss /*
    384  1.43  augustss  * XXX chip is full-duplex, but really attach-dependent.
    385  1.43  augustss  * For now we know of no half-duplex attachments.
    386  1.43  augustss  */
    387   1.1        pk int
    388  1.43  augustss am7930_get_props(addr)
    389  1.43  augustss 	void *addr;
    390   1.1        pk {
    391  1.43  augustss 	return AUDIO_PROP_FULLDUPLEX;
    392  1.43  augustss }
    393  1.43  augustss 
    394  1.43  augustss /*
    395  1.43  augustss  * Attach-dependent channel set/query
    396  1.43  augustss  */
    397  1.43  augustss int
    398  1.43  augustss am7930_set_port(addr, cp)
    399  1.43  augustss 	void *addr;
    400  1.43  augustss 	mixer_ctrl_t *cp;
    401  1.43  augustss {
    402  1.43  augustss 	struct am7930_softc *sc = addr;
    403  1.43  augustss 
    404  1.43  augustss 	DPRINTF(("am7930_set_port: port=%d", cp->dev));
    405  1.43  augustss 
    406  1.43  augustss 	if (cp->dev == AUDIOAMD_RECORD_SOURCE ||
    407  1.43  augustss 		cp->dev == AUDIOAMD_MONITOR_OUTPUT ||
    408  1.43  augustss 		cp->dev == AUDIOAMD_MIC_MUTE) {
    409  1.43  augustss 		if (cp->type != AUDIO_MIXER_ENUM)
    410  1.43  augustss 			return(EINVAL);
    411  1.43  augustss 	} else if (cp->type != AUDIO_MIXER_VALUE ||
    412  1.43  augustss 					cp->un.value.num_channels != 1) {
    413  1.43  augustss 		return(EINVAL);
    414  1.43  augustss 	}
    415  1.43  augustss 
    416  1.43  augustss 	switch(cp->dev) {
    417  1.43  augustss 	    case AUDIOAMD_MIC_VOL:
    418  1.43  augustss 		    sc->sc_rlevel = cp->un.value.level[AUDIO_MIXER_LEVEL_MONO];
    419  1.43  augustss 		    break;
    420  1.43  augustss 	    case AUDIOAMD_SPEAKER_VOL:
    421  1.43  augustss 	    case AUDIOAMD_HEADPHONES_VOL:
    422  1.43  augustss 		    sc->sc_plevel = cp->un.value.level[AUDIO_MIXER_LEVEL_MONO];
    423  1.43  augustss 		    break;
    424  1.43  augustss 	    case AUDIOAMD_MONITOR_VOL:
    425  1.43  augustss 		    sc->sc_mlevel = cp->un.value.level[AUDIO_MIXER_LEVEL_MONO];
    426  1.43  augustss 		    break;
    427  1.43  augustss 	    case AUDIOAMD_RECORD_SOURCE:
    428  1.43  augustss 		    if (cp->un.ord != AUDIOAMD_MIC_VOL)
    429  1.43  augustss 			    return EINVAL;
    430  1.43  augustss 		    break;
    431  1.43  augustss 	    case AUDIOAMD_MIC_MUTE:
    432  1.43  augustss 		    sc->sc_mic_mute = cp->un.ord;
    433  1.43  augustss 		    break;
    434  1.43  augustss 	    case AUDIOAMD_MONITOR_OUTPUT:
    435  1.43  augustss 		    if (cp->un.ord != AUDIOAMD_SPEAKER_VOL &&
    436  1.43  augustss 			cp->un.ord != AUDIOAMD_HEADPHONES_VOL)
    437  1.43  augustss 			    return EINVAL;
    438  1.43  augustss 			sc->sc_out_port = cp->un.ord;
    439  1.43  augustss 		    break;
    440  1.43  augustss 	    default:
    441  1.43  augustss 		    return(EINVAL);
    442  1.43  augustss 		    /* NOTREACHED */
    443  1.43  augustss 	}
    444  1.43  augustss 	return 0;
    445  1.43  augustss }
    446  1.43  augustss 
    447  1.43  augustss int
    448  1.43  augustss am7930_get_port(addr, cp)
    449  1.43  augustss 	void *addr;
    450  1.43  augustss 	mixer_ctrl_t *cp;
    451  1.43  augustss {
    452  1.43  augustss 	struct am7930_softc *sc = addr;
    453  1.43  augustss 
    454  1.43  augustss 	DPRINTF(("am7930_get_port: port=%d\n", cp->dev));
    455  1.43  augustss 
    456  1.43  augustss 	if (cp->dev == AUDIOAMD_RECORD_SOURCE ||
    457  1.43  augustss 		cp->dev == AUDIOAMD_MONITOR_OUTPUT ||
    458  1.43  augustss 		cp->dev == AUDIOAMD_MIC_MUTE) {
    459  1.43  augustss 		if (cp->type != AUDIO_MIXER_ENUM)
    460  1.43  augustss 			return(EINVAL);
    461  1.43  augustss 	} else if (cp->type != AUDIO_MIXER_VALUE ||
    462  1.43  augustss 		cp->un.value.num_channels != 1) {
    463  1.43  augustss 		return(EINVAL);
    464  1.43  augustss 	}
    465  1.43  augustss 
    466  1.43  augustss 	switch(cp->dev) {
    467  1.43  augustss 	    case AUDIOAMD_MIC_VOL:
    468  1.43  augustss 		    cp->un.value.level[AUDIO_MIXER_LEVEL_MONO] = sc->sc_rlevel;
    469  1.43  augustss 		    break;
    470  1.43  augustss 	    case AUDIOAMD_SPEAKER_VOL:
    471  1.43  augustss 	    case AUDIOAMD_HEADPHONES_VOL:
    472  1.43  augustss 		    cp->un.value.level[AUDIO_MIXER_LEVEL_MONO] = sc->sc_plevel;
    473  1.43  augustss 		    break;
    474  1.43  augustss 	    case AUDIOAMD_MONITOR_VOL:
    475  1.43  augustss 		    cp->un.value.level[AUDIO_MIXER_LEVEL_MONO] = sc->sc_mlevel;
    476  1.43  augustss 		    break;
    477  1.43  augustss 	    case AUDIOAMD_RECORD_SOURCE:
    478  1.43  augustss 		    cp->un.ord = AUDIOAMD_MIC_VOL;
    479  1.43  augustss 		    break;
    480  1.43  augustss 	    case AUDIOAMD_MIC_MUTE:
    481  1.43  augustss 		    cp->un.ord = sc->sc_mic_mute;
    482  1.43  augustss 		    break;
    483  1.43  augustss 	    case AUDIOAMD_MONITOR_OUTPUT:
    484  1.43  augustss 		    cp->un.ord = sc->sc_out_port;
    485  1.43  augustss 		    break;
    486  1.43  augustss 	    default:
    487  1.43  augustss 		    return(EINVAL);
    488  1.43  augustss 		    /* NOTREACHED */
    489  1.43  augustss 	}
    490  1.43  augustss 	return 0;
    491   1.1        pk }
    492   1.1        pk 
    493  1.26  augustss 
    494  1.39  jonathan /*
    495  1.43  augustss  * Define mixer control facilities.
    496  1.39  jonathan  */
    497  1.26  augustss int
    498  1.43  augustss am7930_query_devinfo(addr, dip)
    499  1.26  augustss 	void *addr;
    500  1.43  augustss 	mixer_devinfo_t *dip;
    501  1.26  augustss {
    502  1.43  augustss 
    503  1.43  augustss 	DPRINTF(("am7930_query_devinfo()\n"));
    504  1.43  augustss 
    505  1.43  augustss 	switch(dip->index) {
    506  1.43  augustss 	    case AUDIOAMD_MIC_VOL:
    507  1.43  augustss 		    dip->type = AUDIO_MIXER_VALUE;
    508  1.43  augustss 		    dip->mixer_class = AUDIOAMD_INPUT_CLASS;
    509  1.43  augustss 		    dip->prev =  AUDIO_MIXER_LAST;
    510  1.43  augustss 		    dip->next = AUDIOAMD_MIC_MUTE;
    511  1.43  augustss 		    strcpy(dip->label.name, AudioNmicrophone);
    512  1.43  augustss 		    dip->un.v.num_channels = 1;
    513  1.43  augustss 		    strcpy(dip->un.v.units.name, AudioNvolume);
    514  1.43  augustss 		    break;
    515  1.43  augustss 	    case AUDIOAMD_SPEAKER_VOL:
    516  1.43  augustss 		    dip->type = AUDIO_MIXER_VALUE;
    517  1.43  augustss 		    dip->mixer_class = AUDIOAMD_OUTPUT_CLASS;
    518  1.43  augustss 		    dip->prev = dip->next = AUDIO_MIXER_LAST;
    519  1.43  augustss 		    strcpy(dip->label.name, AudioNspeaker);
    520  1.43  augustss 		    dip->un.v.num_channels = 1;
    521  1.43  augustss 		    strcpy(dip->un.v.units.name, AudioNvolume);
    522  1.43  augustss 		    break;
    523  1.43  augustss 	    case AUDIOAMD_HEADPHONES_VOL:
    524  1.43  augustss 		    dip->type = AUDIO_MIXER_VALUE;
    525  1.43  augustss 		    dip->mixer_class = AUDIOAMD_OUTPUT_CLASS;
    526  1.43  augustss 		    dip->prev = dip->next = AUDIO_MIXER_LAST;
    527  1.43  augustss 		    strcpy(dip->label.name, AudioNheadphone);
    528  1.43  augustss 		    dip->un.v.num_channels = 1;
    529  1.43  augustss 		    strcpy(dip->un.v.units.name, AudioNvolume);
    530  1.43  augustss 		    break;
    531  1.43  augustss 	    case AUDIOAMD_MONITOR_VOL:
    532  1.43  augustss 		    dip->type = AUDIO_MIXER_VALUE;
    533  1.43  augustss 		    dip->mixer_class = AUDIOAMD_MONITOR_CLASS;
    534  1.43  augustss 		    dip->prev = dip->next = AUDIO_MIXER_LAST;
    535  1.43  augustss 		    strcpy(dip->label.name, AudioNmonitor);
    536  1.43  augustss 		    dip->un.v.num_channels = 1;
    537  1.43  augustss 		    strcpy(dip->un.v.units.name, AudioNvolume);
    538  1.43  augustss 		    break;
    539  1.43  augustss 	    case AUDIOAMD_RECORD_SOURCE:
    540  1.43  augustss 		    dip->type = AUDIO_MIXER_ENUM;
    541  1.43  augustss 		    dip->mixer_class = AUDIOAMD_RECORD_CLASS;
    542  1.43  augustss 		    dip->next = dip->prev = AUDIO_MIXER_LAST;
    543  1.43  augustss 		    strcpy(dip->label.name, AudioNsource);
    544  1.43  augustss 		    dip->un.e.num_mem = 1;
    545  1.43  augustss 		    strcpy(dip->un.e.member[0].label.name, AudioNmicrophone);
    546  1.43  augustss 		    dip->un.e.member[0].ord = AUDIOAMD_MIC_VOL;
    547  1.43  augustss 		    break;
    548  1.43  augustss 	    case AUDIOAMD_MONITOR_OUTPUT:
    549  1.43  augustss 		    dip->type = AUDIO_MIXER_ENUM;
    550  1.43  augustss 		    dip->mixer_class = AUDIOAMD_MONITOR_CLASS;
    551  1.43  augustss 		    dip->next = dip->prev = AUDIO_MIXER_LAST;
    552  1.43  augustss 		    strcpy(dip->label.name, AudioNoutput);
    553  1.43  augustss 		    dip->un.e.num_mem = 2;
    554  1.43  augustss 		    strcpy(dip->un.e.member[0].label.name, AudioNspeaker);
    555  1.43  augustss 		    dip->un.e.member[0].ord = AUDIOAMD_SPEAKER_VOL;
    556  1.43  augustss 		    strcpy(dip->un.e.member[1].label.name, AudioNheadphone);
    557  1.43  augustss 		    dip->un.e.member[1].ord = AUDIOAMD_HEADPHONES_VOL;
    558  1.43  augustss 		    break;
    559  1.43  augustss 	    case AUDIOAMD_MIC_MUTE:
    560  1.43  augustss 		    dip->type = AUDIO_MIXER_ENUM;
    561  1.43  augustss 		    dip->mixer_class = AUDIOAMD_INPUT_CLASS;
    562  1.43  augustss 		    dip->prev =  AUDIOAMD_MIC_VOL;
    563  1.43  augustss 		    dip->next = AUDIO_MIXER_LAST;
    564  1.43  augustss 		    strcpy(dip->label.name, AudioNmute);
    565  1.43  augustss 		    dip->un.e.num_mem = 2;
    566  1.43  augustss 		    strcpy(dip->un.e.member[0].label.name, AudioNoff);
    567  1.43  augustss 		    dip->un.e.member[0].ord = 0;
    568  1.43  augustss 		    strcpy(dip->un.e.member[1].label.name, AudioNon);
    569  1.43  augustss 		    dip->un.e.member[1].ord = 1;
    570  1.43  augustss 		    break;
    571  1.43  augustss 	    case AUDIOAMD_INPUT_CLASS:
    572  1.43  augustss 		    dip->type = AUDIO_MIXER_CLASS;
    573  1.43  augustss 		    dip->mixer_class = AUDIOAMD_INPUT_CLASS;
    574  1.43  augustss 		    dip->next = dip->prev = AUDIO_MIXER_LAST;
    575  1.43  augustss 		    strcpy(dip->label.name, AudioCinputs);
    576  1.43  augustss 		    break;
    577  1.43  augustss 	    case AUDIOAMD_OUTPUT_CLASS:
    578  1.43  augustss 		    dip->type = AUDIO_MIXER_CLASS;
    579  1.43  augustss 		    dip->mixer_class = AUDIOAMD_OUTPUT_CLASS;
    580  1.43  augustss 		    dip->next = dip->prev = AUDIO_MIXER_LAST;
    581  1.43  augustss 		    strcpy(dip->label.name, AudioCoutputs);
    582  1.43  augustss 		    break;
    583  1.43  augustss 	    case AUDIOAMD_RECORD_CLASS:
    584  1.43  augustss 		    dip->type = AUDIO_MIXER_CLASS;
    585  1.43  augustss 		    dip->mixer_class = AUDIOAMD_RECORD_CLASS;
    586  1.43  augustss 		    dip->next = dip->prev = AUDIO_MIXER_LAST;
    587  1.43  augustss 		    strcpy(dip->label.name, AudioCrecord);
    588  1.43  augustss 		    break;
    589  1.43  augustss 	    case AUDIOAMD_MONITOR_CLASS:
    590  1.43  augustss 		    dip->type = AUDIO_MIXER_CLASS;
    591  1.43  augustss 		    dip->mixer_class = AUDIOAMD_MONITOR_CLASS;
    592  1.43  augustss 		    dip->next = dip->prev = AUDIO_MIXER_LAST;
    593  1.43  augustss 		    strcpy(dip->label.name, AudioCmonitor);
    594  1.43  augustss 		    break;
    595  1.43  augustss 	    default:
    596  1.43  augustss 		    return ENXIO;
    597  1.43  augustss 		    /*NOTREACHED*/
    598  1.43  augustss 	}
    599  1.43  augustss 
    600  1.43  augustss 	DPRINTF(("AUDIO_MIXER_DEVINFO: name=%s\n", dip->label.name));
    601  1.43  augustss 
    602  1.43  augustss 	return(0);
    603   1.1        pk }
    604  1.43  augustss 
    605  1.39  jonathan #endif	/* NAUDIO */
    606