Home | History | Annotate | Line # | Download | only in isa
ym.c revision 1.1
      1 /* $NetBSD: ym.c,v 1.1 1998/05/20 16:19:43 augustss 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/ioctl.h>
     39 #include <sys/syslog.h>
     40 #include <sys/device.h>
     41 #include <sys/proc.h>
     42 #include <sys/buf.h>
     43 
     44 #include <machine/cpu.h>
     45 #include <machine/intr.h>
     46 #include <machine/bus.h>
     47 #include <machine/pio.h>
     48 
     49 #include <sys/audioio.h>
     50 #include <dev/audio_if.h>
     51 
     52 #include <dev/isa/isavar.h>
     53 #include <dev/isa/isadmavar.h>
     54 
     55 #include <dev/ic/ad1848reg.h>
     56 #include <dev/isa/ad1848var.h>
     57 #include <dev/ic/opl3sa3.h>
     58 #include <dev/isa/ymvar.h>
     59 
     60 
     61 int	ym_getdev __P((void *, struct audio_device *));
     62 int	ym_mixer_set_port __P((void *, mixer_ctrl_t *));
     63 int	ym_mixer_get_port __P((void *, mixer_ctrl_t *));
     64 int	ym_query_devinfo __P((void *, mixer_devinfo_t *));
     65 
     66 static void ym_mute __P((struct ym_softc *, int, int));
     67 static void ym_set_master_gain __P((struct ym_softc *, struct ad1848_volume *));
     68 static void ym_set_mic_gain __P((struct ym_softc *, struct ad1848_volume *));
     69 
     70 
     71 
     72 struct audio_hw_if ym_hw_if = {
     73 	ad1848_open,
     74 	ad1848_close,
     75 	NULL,
     76 	ad1848_query_encoding,
     77 	ad1848_set_params,
     78 	ad1848_round_blocksize,
     79 	ad1848_commit_settings,
     80 	ad1848_dma_init_output,
     81 	ad1848_dma_init_input,
     82 	ad1848_dma_output,
     83 	ad1848_dma_input,
     84 	ad1848_halt_out_dma,
     85 	ad1848_halt_in_dma,
     86 	NULL,
     87 	ym_getdev,
     88 	NULL,
     89 	ym_mixer_set_port,
     90 	ym_mixer_get_port,
     91 	ym_query_devinfo,
     92 	ad1848_malloc,
     93 	ad1848_free,
     94 	ad1848_round,
     95 	ad1848_mappage,
     96 	ad1848_get_props,
     97 };
     98 
     99 
    100 struct audio_device ym_device = {
    101 	"ym,ad1848",
    102 	"",
    103 	"ym"
    104 };
    105 
    106 static __inline int ym_read __P((struct ym_softc *, int));
    107 static __inline void ym_write __P((struct ym_softc *, int, int));
    108 
    109 void
    110 ym_attach(sc)
    111     struct ym_softc *sc;
    112 
    113 {
    114   struct ad1848_volume vol_mid = {220, 220};
    115   struct ad1848_volume vol_0   = {0, 0};
    116 
    117   sc->sc_ih = isa_intr_establish(sc->sc_ic, sc->ym_irq, IST_EDGE, IPL_AUDIO,
    118 			    ad1848_intr, &sc->sc_ad1848);
    119 
    120   ad1848_attach(&sc->sc_ad1848);
    121   sc->sc_ad1848.parent = sc;
    122 
    123   /* Establish chip in well known mode */
    124   ym_set_master_gain(sc, &vol_mid);
    125   ym_set_mic_gain(sc, &vol_0);
    126   sc->master_mute = 0;
    127   ym_mute(sc, SA3_LCH, sc->master_mute);
    128   ym_mute(sc, SA3_RCH, sc->master_mute);
    129 
    130   sc->mic_mute = 1;
    131   ym_mute(sc, SA3_MIC, sc->mic_mute);
    132 
    133   audio_attach_mi(&ym_hw_if, 0, &sc->sc_ad1848, &sc->sc_dev);
    134 }
    135 
    136 static __inline int
    137 ym_read(sc, reg)
    138     struct ym_softc *sc;
    139     int reg;
    140 {
    141   bus_space_write_1(sc->sc_iot, sc->sc_controlioh, 0, 0x1d);
    142   bus_space_write_1(sc->sc_iot, sc->sc_controlioh, 0, (reg & 0xff));
    143   return (bus_space_read_1(sc->sc_iot, sc->sc_controlioh, 1));
    144 }
    145 
    146 static __inline void
    147 ym_write(sc, reg, data)
    148     struct ym_softc *sc;
    149     int reg;
    150     int data;
    151 {
    152   bus_space_write_1(sc->sc_iot, sc->sc_controlioh, 0, 0x1d);
    153   bus_space_write_1(sc->sc_iot, sc->sc_controlioh, 0, (reg & 0xff));
    154   bus_space_write_1(sc->sc_iot, sc->sc_controlioh, 1, (data & 0xff));
    155 }
    156 
    157 
    158 
    159 int
    160 ym_getdev(addr, retp)
    161     void *addr;
    162     struct audio_device *retp;
    163 {
    164     *retp = ym_device;
    165     return 0;
    166 }
    167 
    168 
    169 static ad1848_devmap_t mappings[] = {
    170 { YM_MIDI_LVL, AD1848_KIND_LVL, AD1848_AUX2_CHANNEL },
    171 { YM_CD_LVL, AD1848_KIND_LVL, AD1848_AUX1_CHANNEL },
    172 { YM_DAC_LVL, AD1848_KIND_LVL, AD1848_DAC_CHANNEL },
    173 { YM_LINE_LVL, AD1848_KIND_LVL, AD1848_LINE_CHANNEL },
    174 { YM_SPEAKER_LVL, AD1848_KIND_LVL, AD1848_MONO_CHANNEL },
    175 { YM_MONITOR_LVL, AD1848_KIND_LVL, AD1848_MONITOR_CHANNEL },
    176 { YM_MIDI_MUTE, AD1848_KIND_MUTE, AD1848_AUX2_CHANNEL },
    177 { YM_CD_MUTE, AD1848_KIND_MUTE, AD1848_AUX1_CHANNEL },
    178 { YM_DAC_MUTE, AD1848_KIND_MUTE, AD1848_DAC_CHANNEL },
    179 { YM_LINE_MUTE, AD1848_KIND_MUTE, AD1848_LINE_CHANNEL },
    180 { YM_SPEAKER_MUTE, AD1848_KIND_MUTE, AD1848_MONO_CHANNEL },
    181 { YM_MONITOR_MUTE, AD1848_KIND_MUTE, AD1848_MONITOR_CHANNEL },
    182 { YM_REC_LVL, AD1848_KIND_RECORDGAIN, -1 },
    183 { YM_RECORD_SOURCE, AD1848_KIND_RECORDSOURCE, -1}
    184 };
    185 
    186 static int nummap = sizeof(mappings) / sizeof(mappings[0]);
    187 
    188 
    189 static void
    190 ym_mute(sc, left_reg, mute)
    191   struct ym_softc *sc;
    192   int left_reg;
    193   int mute;
    194 
    195 {
    196   u_char reg;
    197 
    198   if (mute) {
    199     reg = ym_read(sc, left_reg);
    200     ym_write (sc, left_reg, reg | 0x80);
    201   } else {
    202     reg = ym_read(sc, left_reg);
    203     ym_write (sc, left_reg, reg & ~0x80);
    204   }
    205 }
    206 
    207 #define MIC_ATTEN_BITS 0x1f
    208 #define MASTER_ATTEN_BITS 0x0f
    209 
    210 
    211 static void
    212 ym_set_master_gain(sc, vol)
    213   struct ym_softc *sc;
    214   struct ad1848_volume *vol;
    215 {
    216   u_char reg;
    217   u_int  atten;
    218 
    219   sc->master_gain = *vol;
    220 
    221   atten = ((AUDIO_MAX_GAIN - vol->left) * MASTER_ATTEN_BITS)/AUDIO_MAX_GAIN;
    222 
    223   reg = ym_read(sc, SA3_LCH);
    224 
    225   reg &= ~(MASTER_ATTEN_BITS);
    226   reg |= atten;
    227 
    228   ym_write (sc, SA3_LCH, reg);
    229 
    230   atten = ((AUDIO_MAX_GAIN - vol->right) * MASTER_ATTEN_BITS)/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 
    332       ad1848_from_vol(cp, &sc->mic_gain);
    333       break;
    334 
    335     case YM_MIC_MUTE:
    336       cp->un.ord = sc->mic_mute;
    337       break;
    338 
    339     default:
    340 	error = ENXIO;
    341 	break;
    342     }
    343 
    344     return(error);
    345 }
    346 
    347 static char *mixer_classes[] = { AudioCinputs, AudioCrecord, AudioCoutputs,
    348 				 AudioCmonitor };
    349 
    350 int
    351 ym_query_devinfo(addr, dip)
    352     void *addr;
    353     mixer_devinfo_t *dip;
    354 {
    355   static char *mixer_port_names[] = { AudioNmidi, AudioNcd, AudioNdac,
    356 				       AudioNline, AudioNspeaker,
    357 				       AudioNmicrophone,
    358                                        AudioNmonitor};
    359 
    360     dip->next = dip->prev = AUDIO_MIXER_LAST;
    361 
    362     switch(dip->index) {
    363     case YM_INPUT_CLASS:			/* input class descriptor */
    364     case YM_OUTPUT_CLASS:
    365     case YM_MONITOR_CLASS:
    366     case YM_RECORD_CLASS:
    367 	dip->type = AUDIO_MIXER_CLASS;
    368 	dip->mixer_class = dip->index;
    369 	strcpy(dip->label.name,
    370 	       mixer_classes[dip->index - YM_INPUT_CLASS]);
    371 	break;
    372 
    373     case YM_MIDI_LVL:
    374     case YM_CD_LVL:
    375     case YM_DAC_LVL:
    376     case YM_LINE_LVL:
    377     case YM_SPEAKER_LVL:
    378     case YM_MIC_LVL:
    379     case YM_MONITOR_LVL:
    380 	dip->type = AUDIO_MIXER_VALUE;
    381 	if (dip->index == YM_MONITOR_LVL)
    382 	  dip->mixer_class = YM_MONITOR_CLASS;
    383 	else
    384 	  dip->mixer_class = YM_INPUT_CLASS;
    385 
    386 	dip->next = dip->index + 7;
    387 
    388 	strcpy(dip->label.name,mixer_port_names[dip->index - YM_MIDI_LVL]);
    389 
    390 	if (dip->index == YM_SPEAKER_LVL ||
    391 	    dip->index == YM_MIC_LVL)
    392 	  dip->un.v.num_channels = 1;
    393 	else
    394 	  dip->un.v.num_channels = 2;
    395 
    396 	strcpy(dip->un.v.units.name, AudioNvolume);
    397 	break;
    398 
    399     case YM_MIDI_MUTE:
    400     case YM_CD_MUTE:
    401     case YM_DAC_MUTE:
    402     case YM_LINE_MUTE:
    403     case YM_SPEAKER_MUTE:
    404     case YM_MIC_MUTE:
    405     case YM_MONITOR_MUTE:
    406 	if (dip->index == YM_MONITOR_MUTE)
    407 	  dip->mixer_class = YM_MONITOR_CLASS;
    408 	else
    409 	  dip->mixer_class = YM_INPUT_CLASS;
    410 	dip->type = AUDIO_MIXER_ENUM;
    411 	dip->prev = dip->index - 7;
    412 mute:
    413 	strcpy(dip->label.name, AudioNmute);
    414 	dip->un.e.num_mem = 2;
    415 	strcpy(dip->un.e.member[0].label.name, AudioNoff);
    416 	dip->un.e.member[0].ord = 0;
    417 	strcpy(dip->un.e.member[1].label.name, AudioNon);
    418 	dip->un.e.member[1].ord = 1;
    419 	break;
    420 
    421 
    422     case YM_OUTPUT_LVL:
    423 	dip->type = AUDIO_MIXER_VALUE;
    424 	dip->mixer_class = YM_OUTPUT_CLASS;
    425 	dip->next = YM_OUTPUT_MUTE;
    426 	strcpy(dip->label.name, AudioNmaster);
    427 	dip->un.v.num_channels = 2;
    428 	strcpy(dip->un.v.units.name, AudioNvolume);
    429 	break;
    430 
    431     case YM_OUTPUT_MUTE:
    432 	dip->mixer_class = YM_OUTPUT_CLASS;
    433 	dip->type = AUDIO_MIXER_ENUM;
    434 	dip->prev = YM_OUTPUT_LVL;
    435 	goto mute;
    436 
    437     case YM_REC_LVL:	/* record level */
    438 	dip->type = AUDIO_MIXER_VALUE;
    439 	dip->mixer_class = YM_RECORD_CLASS;
    440 	dip->next = YM_RECORD_SOURCE;
    441 	strcpy(dip->label.name, AudioNrecord);
    442 	dip->un.v.num_channels = 2;
    443 	strcpy(dip->un.v.units.name, AudioNvolume);
    444 	break;
    445 
    446 
    447     case YM_RECORD_SOURCE:
    448 	dip->mixer_class = YM_RECORD_CLASS;
    449 	dip->type = AUDIO_MIXER_ENUM;
    450 	dip->prev = YM_REC_LVL;
    451 	strcpy(dip->label.name, AudioNsource);
    452 	dip->un.e.num_mem = 4;
    453 	strcpy(dip->un.e.member[0].label.name, AudioNmicrophone);
    454 	dip->un.e.member[0].ord = MIC_IN_PORT;
    455 	strcpy(dip->un.e.member[1].label.name, AudioNline);
    456 	dip->un.e.member[1].ord = LINE_IN_PORT;
    457 	strcpy(dip->un.e.member[2].label.name, AudioNdac);
    458 	dip->un.e.member[2].ord = DAC_IN_PORT;
    459 	strcpy(dip->un.e.member[3].label.name, AudioNcd);
    460 	dip->un.e.member[3].ord = AUX1_IN_PORT;
    461 	break;
    462 
    463     default:
    464 	return ENXIO;
    465 	/*NOTREACHED*/
    466     }
    467 
    468     return 0;
    469 }
    470