Home | History | Annotate | Line # | Download | only in isa
ym.c revision 1.5
      1 /* $NetBSD: ym.c,v 1.5 1998/08/25 22:34:31 pk Exp $ */
      2 
      3 
      4 /*
      5  * Copyright (c) 1998 Constantine Sapuntzakis. All rights reserved.
      6  *
      7  * Redistribution and use in source and binary forms, with or without
      8  * modification, are permitted provided that the following conditions
      9  * are met:
     10  * 1. Redistributions of source code must retain the above copyright
     11  *    notice, this list of conditions and the following disclaimer.
     12  * 2. Redistributions in binary form must reproduce the above copyright
     13  *    notice, this list of conditions and the following disclaimer in the
     14  *    documentation and/or other materials provided with the distribution.
     15  * 3. The name of the author may not be used to endorse or promote products
     16  *    derived from this software without specific prior written permission.
     17  *
     18  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
     19  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
     20  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
     21  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
     22  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
     23  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
     24  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
     25  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
     26  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
     27  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
     28  */
     29 
     30 /*
     31  *  Original code from OpenBSD.
     32  */
     33 
     34 
     35 #include <sys/param.h>
     36 #include <sys/systm.h>
     37 #include <sys/errno.h>
     38 #include <sys/device.h>
     39 
     40 #include <machine/cpu.h>
     41 #include <machine/intr.h>
     42 #include <machine/bus.h>
     43 
     44 #include <sys/audioio.h>
     45 #include <dev/audio_if.h>
     46 
     47 #include <dev/isa/isavar.h>
     48 #include <dev/isa/isadmavar.h>
     49 
     50 #include <dev/ic/ad1848reg.h>
     51 #include <dev/isa/ad1848var.h>
     52 #include <dev/ic/opl3sa3.h>
     53 #include <dev/isa/ymvar.h>
     54 
     55 
     56 int	ym_getdev __P((void *, struct audio_device *));
     57 int	ym_mixer_set_port __P((void *, mixer_ctrl_t *));
     58 int	ym_mixer_get_port __P((void *, mixer_ctrl_t *));
     59 int	ym_query_devinfo __P((void *, mixer_devinfo_t *));
     60 
     61 static void ym_mute __P((struct ym_softc *, int, int));
     62 static void ym_set_master_gain __P((struct ym_softc *, struct ad1848_volume*));
     63 static void ym_set_mic_gain __P((struct ym_softc *, struct ad1848_volume *));
     64 
     65 
     66 
     67 struct audio_hw_if ym_hw_if = {
     68 	ad1848_isa_open,
     69 	ad1848_isa_close,
     70 	NULL,
     71 	ad1848_query_encoding,
     72 	ad1848_set_params,
     73 	ad1848_round_blocksize,
     74 	ad1848_commit_settings,
     75 	ad1848_isa_dma_init_output,
     76 	ad1848_isa_dma_init_input,
     77 	ad1848_isa_dma_output,
     78 	ad1848_isa_dma_input,
     79 	ad1848_halt_out,
     80 	ad1848_halt_in,
     81 	NULL,
     82 	ym_getdev,
     83 	NULL,
     84 	ym_mixer_set_port,
     85 	ym_mixer_get_port,
     86 	ym_query_devinfo,
     87 	ad1848_isa_malloc,
     88 	ad1848_isa_free,
     89 	ad1848_isa_round,
     90 	ad1848_isa_mappage,
     91 	ad1848_isa_get_props,
     92 };
     93 
     94 
     95 struct audio_device ym_device = {
     96 	"ym,ad1848",
     97 	"",
     98 	"ym"
     99 };
    100 
    101 static __inline int ym_read __P((struct ym_softc *, int));
    102 static __inline void ym_write __P((struct ym_softc *, int, int));
    103 
    104 void
    105 ym_attach(sc)
    106 	struct ym_softc *sc;
    107 {
    108 	struct ad1848_softc *ac = &sc->sc_ad1848.sc_ad1848;
    109 	struct ad1848_volume vol_mid = {220, 220};
    110 	struct ad1848_volume vol_0   = {0, 0};
    111 
    112 	sc->sc_ad1848.sc_ih = isa_intr_establish(sc->sc_ic, sc->ym_irq,
    113 						 IST_EDGE,
    114 					         IPL_AUDIO, ad1848_isa_intr,
    115 					         &sc->sc_ad1848);
    116 
    117 	ad1848_attach(ac);
    118 	printf("\n");
    119 	ac->parent = sc;
    120 
    121 	/* Establish chip in well known mode */
    122 	ym_set_master_gain(sc, &vol_mid);
    123 	ym_set_mic_gain(sc, &vol_0);
    124 	sc->master_mute = 0;
    125 	ym_mute(sc, SA3_LCH, sc->master_mute);
    126 	ym_mute(sc, SA3_RCH, sc->master_mute);
    127 
    128 	sc->mic_mute = 1;
    129 	ym_mute(sc, SA3_MIC, sc->mic_mute);
    130 
    131 	audio_attach_mi(&ym_hw_if, ac, &ac->sc_dev);
    132 }
    133 
    134 static __inline int
    135 ym_read(sc, reg)
    136 	struct ym_softc *sc;
    137 	int reg;
    138 {
    139 	bus_space_write_1(sc->sc_iot, sc->sc_controlioh, 0, 0x1d);
    140 	bus_space_write_1(sc->sc_iot, sc->sc_controlioh, 0, (reg & 0xff));
    141 	return (bus_space_read_1(sc->sc_iot, sc->sc_controlioh, 1));
    142 }
    143 
    144 static __inline void
    145 ym_write(sc, reg, data)
    146 	struct ym_softc *sc;
    147 	int reg;
    148 	int data;
    149 {
    150 	bus_space_write_1(sc->sc_iot, sc->sc_controlioh, 0, 0x1d);
    151 	bus_space_write_1(sc->sc_iot, sc->sc_controlioh, 0, (reg & 0xff));
    152 	bus_space_write_1(sc->sc_iot, sc->sc_controlioh, 1, (data & 0xff));
    153 }
    154 
    155 
    156 
    157 int
    158 ym_getdev(addr, retp)
    159 	void *addr;
    160 	struct audio_device *retp;
    161 {
    162 	*retp = ym_device;
    163 	return 0;
    164 }
    165 
    166 
    167 static ad1848_devmap_t mappings[] = {
    168 	{ YM_MIDI_LVL, AD1848_KIND_LVL, AD1848_AUX2_CHANNEL },
    169 	{ YM_CD_LVL, AD1848_KIND_LVL, AD1848_AUX1_CHANNEL },
    170 	{ YM_DAC_LVL, AD1848_KIND_LVL, AD1848_DAC_CHANNEL },
    171 	{ YM_LINE_LVL, AD1848_KIND_LVL, AD1848_LINE_CHANNEL },
    172 	{ YM_SPEAKER_LVL, AD1848_KIND_LVL, AD1848_MONO_CHANNEL },
    173 	{ YM_MONITOR_LVL, AD1848_KIND_LVL, AD1848_MONITOR_CHANNEL },
    174 	{ YM_MIDI_MUTE, AD1848_KIND_MUTE, AD1848_AUX2_CHANNEL },
    175 	{ YM_CD_MUTE, AD1848_KIND_MUTE, AD1848_AUX1_CHANNEL },
    176 	{ YM_DAC_MUTE, AD1848_KIND_MUTE, AD1848_DAC_CHANNEL },
    177 	{ YM_LINE_MUTE, AD1848_KIND_MUTE, AD1848_LINE_CHANNEL },
    178 	{ YM_SPEAKER_MUTE, AD1848_KIND_MUTE, AD1848_MONO_CHANNEL },
    179 	{ YM_MONITOR_MUTE, AD1848_KIND_MUTE, AD1848_MONITOR_CHANNEL },
    180 	{ YM_REC_LVL, AD1848_KIND_RECORDGAIN, -1 },
    181 	{ YM_RECORD_SOURCE, AD1848_KIND_RECORDSOURCE, -1}
    182 };
    183 
    184 static int nummap = sizeof(mappings) / sizeof(mappings[0]);
    185 
    186 
    187 static void
    188 ym_mute(sc, left_reg, mute)
    189 	struct ym_softc *sc;
    190 	int left_reg;
    191 	int mute;
    192 
    193 {
    194 	u_char reg;
    195 
    196 	if (mute) {
    197 		reg = ym_read(sc, left_reg);
    198 		ym_write (sc, left_reg, reg | 0x80);
    199 	} else {
    200 		reg = ym_read(sc, left_reg);
    201 		ym_write (sc, left_reg, reg & ~0x80);
    202 	}
    203 }
    204 
    205 #define MIC_ATTEN_BITS 0x1f
    206 #define MASTER_ATTEN_BITS 0x0f
    207 
    208 
    209 static void
    210 ym_set_master_gain(sc, vol)
    211 	struct ym_softc *sc;
    212 	struct ad1848_volume *vol;
    213 {
    214 	u_char reg;
    215 	u_int  atten;
    216 
    217 	sc->master_gain = *vol;
    218 
    219 	atten = ((AUDIO_MAX_GAIN - vol->left) * MASTER_ATTEN_BITS) /
    220 		AUDIO_MAX_GAIN;
    221 
    222 	reg = ym_read(sc, SA3_LCH);
    223 
    224 	reg &= ~(MASTER_ATTEN_BITS);
    225 	reg |= atten;
    226 
    227 	ym_write (sc, SA3_LCH, reg);
    228 
    229 	atten = ((AUDIO_MAX_GAIN - vol->right) * MASTER_ATTEN_BITS) /
    230 		AUDIO_MAX_GAIN;
    231 
    232 	reg = ym_read(sc, SA3_RCH) & ~(MASTER_ATTEN_BITS);
    233 	reg |= atten;
    234 
    235 	ym_write (sc, SA3_RCH, reg);
    236 }
    237 
    238 static void
    239 ym_set_mic_gain(sc, vol)
    240 	struct ym_softc *sc;
    241 	struct ad1848_volume *vol;
    242 {
    243 	u_char reg;
    244 	u_int  atten;
    245 
    246 	sc->mic_gain = *vol;
    247 
    248 	atten = ((AUDIO_MAX_GAIN - vol->left) * MIC_ATTEN_BITS)/AUDIO_MAX_GAIN;
    249 
    250 	reg = ym_read(sc, SA3_MIC) & ~(MIC_ATTEN_BITS);
    251 	reg |= atten;
    252 
    253 	ym_write (sc, SA3_MIC, reg);
    254 }
    255 
    256 int
    257 ym_mixer_set_port(addr, cp)
    258 	void *addr;
    259 	mixer_ctrl_t *cp;
    260 {
    261 	struct ad1848_softc *ac = addr;
    262 	struct ym_softc *sc = ac->parent;
    263 	struct ad1848_volume vol;
    264 	int error = ad1848_mixer_set_port(ac, mappings, nummap, cp);
    265 
    266 	if (error != ENXIO)
    267 		return (error);
    268 
    269 	error = 0;
    270 
    271 	switch (cp->dev) {
    272 	case YM_OUTPUT_LVL:
    273 		ad1848_to_vol(cp, &vol);
    274 		ym_set_master_gain(sc, &vol);
    275 		break;
    276 
    277 	case YM_OUTPUT_MUTE:
    278 		sc->master_mute = (cp->un.ord != 0);
    279 		ym_mute(sc, SA3_LCH, sc->master_mute);
    280 		ym_mute(sc, SA3_RCH, sc->master_mute);
    281 		break;
    282 
    283 	case YM_MIC_LVL:
    284 		if (cp->un.value.num_channels != 1)
    285 			error = EINVAL;
    286 
    287 		ad1848_to_vol(cp, &vol);
    288 		ym_set_mic_gain(sc, &vol);
    289 		break;
    290 
    291 	case YM_MIC_MUTE:
    292 		sc->mic_mute = (cp->un.ord != 0);
    293 		ym_mute(sc, SA3_MIC, sc->mic_mute);
    294 		break;
    295 
    296 	default:
    297 		return ENXIO;
    298 		/*NOTREACHED*/
    299 	}
    300 
    301 	return (error);
    302 }
    303 
    304 int
    305 ym_mixer_get_port(addr, cp)
    306 	void *addr;
    307 	mixer_ctrl_t *cp;
    308 {
    309 	struct ad1848_softc *ac = addr;
    310 	struct ym_softc *sc = ac->parent;
    311 
    312 	int error = ad1848_mixer_get_port(ac, mappings, nummap, cp);
    313 
    314 	if (error != ENXIO)
    315 		return (error);
    316 
    317 	error = 0;
    318 
    319 	switch (cp->dev) {
    320 	case YM_OUTPUT_LVL:
    321 		ad1848_from_vol(cp, &sc->master_gain);
    322 		break;
    323 
    324 	case YM_OUTPUT_MUTE:
    325 		cp->un.ord = sc->master_mute;
    326 		break;
    327 
    328 	case YM_MIC_LVL:
    329 		if (cp->un.value.num_channels != 1)
    330 			error = EINVAL;
    331 		ad1848_from_vol(cp, &sc->mic_gain);
    332 		break;
    333 
    334 	case YM_MIC_MUTE:
    335 		cp->un.ord = sc->mic_mute;
    336 		break;
    337 
    338 	default:
    339 		error = ENXIO;
    340 		break;
    341 	}
    342 
    343 	return(error);
    344 }
    345 
    346 static char *mixer_classes[] =
    347 	{ AudioCinputs, AudioCrecord, AudioCoutputs, AudioCmonitor };
    348 
    349 int
    350 ym_query_devinfo(addr, dip)
    351 	void *addr;
    352 	mixer_devinfo_t *dip;
    353 {
    354 	static char *mixer_port_names[] =
    355 	     { AudioNmidi, AudioNcd, AudioNdac, AudioNline, AudioNspeaker,
    356 	       AudioNmicrophone, AudioNmonitor};
    357 
    358 	dip->next = dip->prev = AUDIO_MIXER_LAST;
    359 
    360 	switch(dip->index) {
    361 	case YM_INPUT_CLASS:			/* input class descriptor */
    362 	case YM_OUTPUT_CLASS:
    363 	case YM_MONITOR_CLASS:
    364 	case YM_RECORD_CLASS:
    365 		dip->type = AUDIO_MIXER_CLASS;
    366 		dip->mixer_class = dip->index;
    367 		strcpy(dip->label.name,
    368 		       mixer_classes[dip->index - YM_INPUT_CLASS]);
    369 		break;
    370 
    371 	case YM_MIDI_LVL:
    372 	case YM_CD_LVL:
    373 	case YM_DAC_LVL:
    374 	case YM_LINE_LVL:
    375 	case YM_SPEAKER_LVL:
    376 	case YM_MIC_LVL:
    377 	case YM_MONITOR_LVL:
    378 		dip->type = AUDIO_MIXER_VALUE;
    379 		if (dip->index == YM_MONITOR_LVL)
    380 			dip->mixer_class = YM_MONITOR_CLASS;
    381 		else
    382 			dip->mixer_class = YM_INPUT_CLASS;
    383 
    384 		dip->next = dip->index + 7;
    385 
    386 		strcpy(dip->label.name,
    387 		       mixer_port_names[dip->index - YM_MIDI_LVL]);
    388 
    389 		if (dip->index == YM_SPEAKER_LVL ||
    390 		    dip->index == YM_MIC_LVL)
    391 			dip->un.v.num_channels = 1;
    392 		else
    393 			dip->un.v.num_channels = 2;
    394 
    395 		strcpy(dip->un.v.units.name, AudioNvolume);
    396 		break;
    397 
    398 	case YM_MIDI_MUTE:
    399 	case YM_CD_MUTE:
    400 	case YM_DAC_MUTE:
    401 	case YM_LINE_MUTE:
    402 	case YM_SPEAKER_MUTE:
    403 	case YM_MIC_MUTE:
    404 	case YM_MONITOR_MUTE:
    405 		if (dip->index == YM_MONITOR_MUTE)
    406 			dip->mixer_class = YM_MONITOR_CLASS;
    407 		else
    408 			dip->mixer_class = YM_INPUT_CLASS;
    409 		dip->type = AUDIO_MIXER_ENUM;
    410 		dip->prev = dip->index - 7;
    411 	mute:
    412 		strcpy(dip->label.name, AudioNmute);
    413 		dip->un.e.num_mem = 2;
    414 		strcpy(dip->un.e.member[0].label.name, AudioNoff);
    415 		dip->un.e.member[0].ord = 0;
    416 		strcpy(dip->un.e.member[1].label.name, AudioNon);
    417 		dip->un.e.member[1].ord = 1;
    418 		break;
    419 
    420 
    421 	case YM_OUTPUT_LVL:
    422 		dip->type = AUDIO_MIXER_VALUE;
    423 		dip->mixer_class = YM_OUTPUT_CLASS;
    424 		dip->next = YM_OUTPUT_MUTE;
    425 		strcpy(dip->label.name, AudioNmaster);
    426 		dip->un.v.num_channels = 2;
    427 		strcpy(dip->un.v.units.name, AudioNvolume);
    428 		break;
    429 
    430 	case YM_OUTPUT_MUTE:
    431 		dip->mixer_class = YM_OUTPUT_CLASS;
    432 		dip->type = AUDIO_MIXER_ENUM;
    433 		dip->prev = YM_OUTPUT_LVL;
    434 		goto mute;
    435 
    436 	case YM_REC_LVL:	/* record level */
    437 		dip->type = AUDIO_MIXER_VALUE;
    438 		dip->mixer_class = YM_RECORD_CLASS;
    439 		dip->next = YM_RECORD_SOURCE;
    440 		strcpy(dip->label.name, AudioNrecord);
    441 		dip->un.v.num_channels = 2;
    442 		strcpy(dip->un.v.units.name, AudioNvolume);
    443 		break;
    444 
    445 
    446 	case YM_RECORD_SOURCE:
    447 		dip->mixer_class = YM_RECORD_CLASS;
    448 		dip->type = AUDIO_MIXER_ENUM;
    449 		dip->prev = YM_REC_LVL;
    450 		strcpy(dip->label.name, AudioNsource);
    451 		dip->un.e.num_mem = 4;
    452 		strcpy(dip->un.e.member[0].label.name, AudioNmicrophone);
    453 		dip->un.e.member[0].ord = MIC_IN_PORT;
    454 		strcpy(dip->un.e.member[1].label.name, AudioNline);
    455 		dip->un.e.member[1].ord = LINE_IN_PORT;
    456 		strcpy(dip->un.e.member[2].label.name, AudioNdac);
    457 		dip->un.e.member[2].ord = DAC_IN_PORT;
    458 		strcpy(dip->un.e.member[3].label.name, AudioNcd);
    459 		dip->un.e.member[3].ord = AUX1_IN_PORT;
    460 		break;
    461 
    462 	default:
    463 		return ENXIO;
    464 		/*NOTREACHED*/
    465 	}
    466 
    467 	return 0;
    468 }
    469