Home | History | Annotate | Line # | Download | only in ic
ac97.c revision 1.27
      1 /*      $NetBSD: ac97.c,v 1.27 2002/10/06 16:33:35 kent Exp $ */
      2 /*	$OpenBSD: ac97.c,v 1.8 2000/07/19 09:01:35 csapuntz Exp $	*/
      3 
      4 /*
      5  * Copyright (c) 1999, 2000 Constantine Sapuntzakis
      6  *
      7  * Author:        Constantine Sapuntzakis <csapuntz (at) stanford.edu>
      8  *
      9  * Redistribution and use in source and binary forms, with or without
     10  * modification, are permitted provided that the following conditions
     11  * are met:
     12  * 1. Redistributions of source code must retain the above copyright
     13  *    notice, this list of conditions and the following disclaimer.
     14  * 2. Redistributions in binary form must reproduce the above copyright
     15  *    notice, this list of conditions and the following disclaimer in the
     16  *    documentation and/or other materials provided with the distribution.
     17  * 3. The name of the author may not be used to endorse or promote
     18  *    products derived from this software without specific prior written
     19  *    permission.
     20  * THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS
     21  * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
     22  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
     23  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE
     24  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
     25  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
     26  * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
     27  * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
     28  * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
     29  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
     30  * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
     31  * DAMAGE
     32  */
     33 
     34 /* Partially inspired by FreeBSD's sys/dev/pcm/ac97.c. It came with
     35    the following copyright */
     36 
     37 /*
     38  * Copyright (c) 1999 Cameron Grant <gandalf (at) vilnya.demon.co.uk>
     39  * All rights reserved.
     40  *
     41  * Redistribution and use in source and binary forms, with or without
     42  * modification, are permitted provided that the following conditions
     43  * are met:
     44  * 1. Redistributions of source code must retain the above copyright
     45  *    notice, this list of conditions and the following disclaimer.
     46  * 2. Redistributions in binary form must reproduce the above copyright
     47  *    notice, this list of conditions and the following disclaimer in the
     48  *    documentation and/or other materials provided with the distribution.
     49  *
     50  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
     51  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
     52  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
     53  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
     54  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
     55  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
     56  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
     57  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
     58  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
     59  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
     60  * SUCH DAMAGE.
     61  *
     62  * $FreeBSD$
     63  */
     64 
     65 #include <sys/cdefs.h>
     66 __KERNEL_RCSID(0, "$NetBSD: ac97.c,v 1.27 2002/10/06 16:33:35 kent Exp $");
     67 
     68 #include <sys/param.h>
     69 #include <sys/systm.h>
     70 #include <sys/kernel.h>
     71 #include <sys/malloc.h>
     72 #include <sys/device.h>
     73 
     74 #include <sys/audioio.h>
     75 #include <dev/audio_if.h>
     76 
     77 #include <dev/ic/ac97reg.h>
     78 #include <dev/ic/ac97var.h>
     79 
     80 static const struct audio_mixer_enum ac97_on_off = { 2,
     81 					       { { { AudioNoff } , 0 },
     82 					         { { AudioNon }  , 1 } }};
     83 
     84 
     85 static const struct audio_mixer_enum ac97_mic_select = { 2,
     86 					       { { { AudioNmicrophone "0" },
     87 						   0 },
     88 					         { { AudioNmicrophone "1" },
     89 						   1 } }};
     90 
     91 static const struct audio_mixer_enum ac97_mono_select = { 2,
     92 					       { { { AudioNmixerout },
     93 						   0 },
     94 					         { { AudioNmicrophone },
     95 						   1 } }};
     96 
     97 static const struct audio_mixer_enum ac97_source = { 8,
     98 					       { { { AudioNmicrophone } , 0 },
     99 						 { { AudioNcd }, 1 },
    100 						 { { "video" }, 2 },
    101 						 { { AudioNaux }, 3 },
    102 						 { { AudioNline }, 4 },
    103 						 { { AudioNmixerout }, 5 },
    104 						 { { AudioNmixerout AudioNmono }, 6 },
    105 						 { { "phone" }, 7 }}};
    106 
    107 /*
    108  * Due to different values for each source that uses these structures,
    109  * the ac97_query_devinfo function sets delta in mixer_devinfo_t using
    110  * ac97_source_info.bits.
    111  */
    112 static const struct audio_mixer_value ac97_volume_stereo = { { AudioNvolume },
    113 						       2 };
    114 
    115 static const struct audio_mixer_value ac97_volume_mono = { { AudioNvolume },
    116 						     1 };
    117 
    118 #define WRAP(a)  &a, sizeof(a)
    119 
    120 const struct ac97_source_info {
    121 	const char *class;
    122 	const char *device;
    123 	const char *qualifier;
    124 	int  type;
    125 
    126 	const void *info;
    127 	int  info_size;
    128 
    129 	u_int8_t  reg;
    130 	u_int16_t default_value;
    131 	u_int8_t  bits:3;
    132 	u_int8_t  ofs:4;
    133 	u_int8_t  mute:1;
    134 	u_int8_t  polarity:1;   /* Does 0 == MAX or MIN */
    135 
    136 	int  prev;
    137 	int  next;
    138 	int  mixer_class;
    139 } source_info[] = {
    140 	{ AudioCinputs ,            NULL,           NULL,    AUDIO_MIXER_CLASS,
    141 	},
    142 	{ AudioCoutputs,            NULL,           NULL,    AUDIO_MIXER_CLASS,
    143 	},
    144 	{ AudioCrecord ,            NULL,           NULL,    AUDIO_MIXER_CLASS,
    145 	},
    146 	/* Stereo master volume*/
    147 	{ AudioCoutputs,     AudioNmaster,        NULL,    AUDIO_MIXER_VALUE,
    148 	  WRAP(ac97_volume_stereo),
    149 	  AC97_REG_MASTER_VOLUME, 0x8000, 5, 0, 1,
    150 	},
    151 	/* Mono volume */
    152 	{ AudioCoutputs,       AudioNmono,        NULL,    AUDIO_MIXER_VALUE,
    153 	  WRAP(ac97_volume_mono),
    154 	  AC97_REG_MASTER_VOLUME_MONO, 0x8000, 6, 0, 1,
    155 	},
    156 	{ AudioCoutputs,       AudioNmono,AudioNsource,   AUDIO_MIXER_ENUM,
    157 	  WRAP(ac97_mono_select),
    158 	  AC97_REG_GP, 0x0000, 1, 9, 0,
    159 	},
    160 	/* Headphone volume */
    161 	{ AudioCoutputs,  AudioNheadphone,        NULL,    AUDIO_MIXER_VALUE,
    162 	  WRAP(ac97_volume_stereo),
    163 	  AC97_REG_HEADPHONE_VOLUME, 0x8000, 6, 0, 1,
    164 	},
    165 	/* Tone */
    166 	{ AudioCoutputs,           "tone",        NULL,    AUDIO_MIXER_VALUE,
    167 	  WRAP(ac97_volume_stereo),
    168 	  AC97_REG_MASTER_TONE, 0x0f0f, 4, 0, 0,
    169 	},
    170 	/* PC Beep Volume */
    171 	{ AudioCinputs,     AudioNspeaker,        NULL,    AUDIO_MIXER_VALUE,
    172 	  WRAP(ac97_volume_mono),
    173 	  AC97_REG_PCBEEP_VOLUME, 0x0000, 4, 1, 1,
    174 	},
    175 	/* Phone */
    176 	{ AudioCinputs,           "phone",        NULL,    AUDIO_MIXER_VALUE,
    177 	  WRAP(ac97_volume_mono),
    178 	  AC97_REG_PHONE_VOLUME, 0x8008, 5, 0, 1,
    179 	},
    180 	/* Mic Volume */
    181 	{ AudioCinputs,  AudioNmicrophone,        NULL,    AUDIO_MIXER_VALUE,
    182 	  WRAP(ac97_volume_mono),
    183 	  AC97_REG_MIC_VOLUME, 0x8008, 5, 0, 1,
    184 	},
    185 	{ AudioCinputs,  AudioNmicrophone, AudioNpreamp,   AUDIO_MIXER_ENUM,
    186 	  WRAP(ac97_on_off),
    187 	  AC97_REG_MIC_VOLUME, 0x8008, 1, 6, 0,
    188 	},
    189 	{ AudioCinputs,  AudioNmicrophone, AudioNsource,   AUDIO_MIXER_ENUM,
    190 	  WRAP(ac97_mic_select),
    191 	  AC97_REG_GP, 0x0000, 1, 8, 0,
    192 	},
    193 	/* Line in Volume */
    194 	{ AudioCinputs,        AudioNline,        NULL,    AUDIO_MIXER_VALUE,
    195 	  WRAP(ac97_volume_stereo),
    196 	  AC97_REG_LINEIN_VOLUME, 0x8808, 5, 0, 1,
    197 	},
    198 	/* CD Volume */
    199 	{ AudioCinputs,          AudioNcd,        NULL,    AUDIO_MIXER_VALUE,
    200 	  WRAP(ac97_volume_stereo),
    201 	  AC97_REG_CD_VOLUME, 0x8808, 5, 0, 1,
    202 	},
    203 	/* Video Volume */
    204 	{ AudioCinputs,           "video",        NULL,    AUDIO_MIXER_VALUE,
    205 	  WRAP(ac97_volume_stereo),
    206 	  AC97_REG_VIDEO_VOLUME, 0x8808, 5, 0, 1,
    207 	},
    208 	/* AUX volume */
    209 	{ AudioCinputs,         AudioNaux,        NULL,    AUDIO_MIXER_VALUE,
    210 	  WRAP(ac97_volume_stereo),
    211 	  AC97_REG_AUX_VOLUME, 0x8808, 5, 0, 1,
    212 	},
    213 	/* PCM out volume */
    214 	{ AudioCinputs,         AudioNdac,        NULL,    AUDIO_MIXER_VALUE,
    215 	  WRAP(ac97_volume_stereo),
    216 	  AC97_REG_PCMOUT_VOLUME, 0x8808, 5, 0, 1,
    217 	},
    218 	/* Record Source - some logic for this is hard coded - see below */
    219 	{ AudioCrecord,      AudioNsource,        NULL,    AUDIO_MIXER_ENUM,
    220 	  WRAP(ac97_source),
    221 	  AC97_REG_RECORD_SELECT, 0x0000, 3, 0, 0,
    222 	},
    223 	/* Record Gain */
    224 	{ AudioCrecord,      AudioNvolume,        NULL,    AUDIO_MIXER_VALUE,
    225 	  WRAP(ac97_volume_stereo),
    226 	  AC97_REG_RECORD_GAIN, 0x8000, 4, 0, 1,
    227 	},
    228 	/* Record Gain mic */
    229 	{ AudioCrecord,  AudioNmicrophone,        NULL,    AUDIO_MIXER_VALUE,
    230 	  WRAP(ac97_volume_mono),
    231 	  AC97_REG_RECORD_GAIN_MIC, 0x8000, 4, 0, 1, 1,
    232 	},
    233 	/* */
    234 	{ AudioCoutputs,   AudioNloudness,        NULL,    AUDIO_MIXER_ENUM,
    235 	  WRAP(ac97_on_off),
    236 	  AC97_REG_GP, 0x0000, 1, 12, 0,
    237 	},
    238 	{ AudioCoutputs,    AudioNspatial,        NULL,    AUDIO_MIXER_ENUM,
    239 	  WRAP(ac97_on_off),
    240 	  AC97_REG_GP, 0x0000, 1, 13, 0,
    241 	},
    242 	{ AudioCoutputs,    AudioNspatial,    "center",    AUDIO_MIXER_VALUE,
    243 	  WRAP(ac97_volume_mono),
    244 	  AC97_REG_3D_CONTROL, 0x0000, 4, 8, 0, 1,
    245 	},
    246 	{ AudioCoutputs,    AudioNspatial,     "depth",    AUDIO_MIXER_VALUE,
    247 	  WRAP(ac97_volume_mono),
    248 	  AC97_REG_3D_CONTROL, 0x0000, 4, 0, 0, 1,
    249 	},
    250 
    251 	/* Missing features: Simulated Stereo, POP, Loopback mode */
    252 } ;
    253 
    254 #define SOURCE_INFO_SIZE (sizeof(source_info)/sizeof(source_info[0]))
    255 
    256 /*
    257  * Check out http://developer.intel.com/pc-supp/platform/ac97/ for
    258  * information on AC-97
    259  */
    260 
    261 struct ac97_softc {
    262 	struct ac97_codec_if codec_if;
    263 
    264 	struct ac97_host_if *host_if;
    265 
    266 	struct ac97_source_info source_info[2 * SOURCE_INFO_SIZE];
    267 	int num_source_info;
    268 
    269 	enum ac97_host_flags host_flags;
    270 
    271 	u_int16_t shadow_reg[128];
    272 };
    273 
    274 int ac97_mixer_get_port __P((struct ac97_codec_if *self, mixer_ctrl_t *cp));
    275 int ac97_mixer_set_port __P((struct ac97_codec_if *self, mixer_ctrl_t *));
    276 int ac97_query_devinfo __P((struct ac97_codec_if *self, mixer_devinfo_t *));
    277 int ac97_get_portnum_by_name __P((struct ac97_codec_if *, char *, char *,
    278 				  char *));
    279 void ac97_restore_shadow __P((struct ac97_codec_if *self));
    280 
    281 struct ac97_codec_if_vtbl ac97civ = {
    282 	ac97_mixer_get_port,
    283 	ac97_mixer_set_port,
    284 	ac97_query_devinfo,
    285 	ac97_get_portnum_by_name,
    286 	ac97_restore_shadow,
    287 };
    288 
    289 static const struct ac97_codecid {
    290 	u_int32_t id;
    291 	const char *name;
    292 } ac97codecid[] = {
    293 	{ AC97_CODEC_ID('A', 'D', 'S', 3),	"Analog Devices AD1819B" },
    294 	{ AC97_CODEC_ID('A', 'D', 'S', 64),	"Analog Devices AD1881" },
    295 	{ AC97_CODEC_ID('A', 'D', 'S', 72),	"Analog Devices AD1881A" },
    296 	{ AC97_CODEC_ID('A', 'D', 'S', 96),	"Analog Devices AD1885" },
    297 	{ AC97_CODEC_ID('A', 'D', 'S', 99),	"Analog Devices AD1886A" },
    298 	{ AC97_CODEC_ID('A', 'K', 'M', 0),	"Asahi Kasei AK4540"	},
    299 	{ AC97_CODEC_ID('A', 'K', 'M', 2),	"Asahi Kasei AK4543"	},
    300 	{ AC97_CODEC_ID('A', 'L', 'G', 16),	"Advance Logic ALC200"	},
    301 	{ AC97_CODEC_ID('A', 'L', 'G', 32),	"Advance Logic ALC650"	},
    302 	{ AC97_CODEC_ID('A', 'L', 'G', 48),	"Advance Logic ALC101"	},
    303 	{ AC97_CODEC_ID('A', 'L', 'G', 64),	"Advance Logic ALC202"	},
    304 	{ AC97_CODEC_ID('A', 'L', 'G', 80),	"Advance Logic ALC250"	},
    305 	{ AC97_CODEC_ID('C', 'R', 'Y', 0),	"Crystal CS4297"	},
    306 	{ AC97_CODEC_ID('C', 'R', 'Y', 3),	"Crystal CS4297"	},
    307 	{ AC97_CODEC_ID('C', 'R', 'Y', 19),	"Crystal CS4297A"	},
    308 	{ AC97_CODEC_ID('C', 'R', 'Y', 35),	"Crystal CS4298",	},
    309 	{ AC97_CODEC_ID('C', 'R', 'Y', 43),	"Crystal CS4294",	},
    310 	{ AC97_CODEC_ID('C', 'R', 'Y', 49),	"Crystal CS4299",	},
    311 	{ AC97_CODEC_ID('C', 'R', 'Y', 51),	"Crystal CS4298A",	},
    312 	{ AC97_CODEC_ID('C', 'R', 'Y', 52),	"Crystal CS4299",	},
    313 	{ AC97_CODEC_ID('N', 'S', 'C', 49), "National Semiconductor LM4549", },
    314 	{ AC97_CODEC_ID('S', 'I', 'L', 34),	"Silicon Laboratory Si3036", },
    315 	{ AC97_CODEC_ID('S', 'I', 'L', 35),	"Silicon Laboratory Si3038", },
    316 	{ AC97_CODEC_ID('T', 'R', 'A', 2),	"TriTech TR28022",	},
    317 	{ AC97_CODEC_ID('T', 'R', 'A', 3),	"TriTech TR28023",	},
    318 	{ AC97_CODEC_ID('T', 'R', 'A', 6),	"TriTech TR28026",	},
    319 	{ AC97_CODEC_ID('T', 'R', 'A', 8),	"TriTech TR28028",	},
    320 	{ AC97_CODEC_ID('T', 'R', 'A', 35),	"TriTech unknown",	},
    321 	{ AC97_CODEC_ID('W', 'M', 'L', 0),	"Wolfson WM9704",	},
    322 	{ AC97_CODEC_ID('W', 'M', 'L', 3),	"Wolfson WM9707",	},
    323 	{ 0x45838308,				"ESS Technology ES1921", },
    324 	{ 0x83847600,				"SigmaTel STAC9700",	},
    325 	{ 0x83847604,				"SigmaTel STAC9701/3/4/5", },
    326 	{ 0x83847605,				"SigmaTel STAC9704", 	},
    327 	{ 0x83847608,				"SigmaTel STAC9708", 	},
    328 	{ 0x83847609,				"SigmaTel STAC9721/23",	},
    329 	{ 0x83847644,				"SigmaTel STAC9744/45",	},
    330 	{ 0x83847684,				"SigmaTel STAC9783/84",	},
    331 	{ 0,					NULL,			}
    332 };
    333 
    334 static const char * const ac97enhancement[] = {
    335 	"no 3D stereo",
    336 	"Analog Devices Phat Stereo",
    337 	"Creative",
    338 	"National Semi 3D",
    339 	"Yamaha Ymersion",
    340 	"BBE 3D",
    341 	"Crystal Semi 3D",
    342 	"Qsound QXpander",
    343 	"Spatializer 3D",
    344 	"SRS 3D",
    345 	"Platform Tech 3D",
    346 	"AKM 3D",
    347 	"Aureal",
    348 	"AZTECH 3D",
    349 	"Binaura 3D",
    350 	"ESS Technology",
    351 	"Harman International VMAx",
    352 	"Nvidea 3D",
    353 	"Philips Incredible Sound",
    354 	"Texas Instruments' 3D",
    355 	"VLSI Technology 3D",
    356 	"TriTech 3D",
    357 	"Realtek 3D",
    358 	"Samsung 3D",
    359 	"Wolfson Microelectronics 3D",
    360 	"Delta Integration 3D",
    361 	"SigmaTel 3D",
    362 	"Unknown 3D",
    363 	"Rockwell 3D",
    364 	"Unknown 3D",
    365 	"Unknown 3D",
    366 	"Unknown 3D",
    367 };
    368 
    369 static const char * const ac97feature[] = {
    370 	"dedicated mic channel",
    371 	"reserved",
    372 	"tone",
    373 	"simulated stereo",
    374 	"headphone",
    375 	"bass boost",
    376 	"18 bit DAC",
    377 	"20 bit DAC",
    378 	"18 bit ADC",
    379 	"20 bit ADC"
    380 };
    381 
    382 
    383 int ac97_str_equal __P((const char *, const char *));
    384 void ac97_setup_source_info __P((struct ac97_softc *));
    385 void ac97_read __P((struct ac97_softc *, u_int8_t, u_int16_t *));
    386 void ac97_setup_defaults __P((struct ac97_softc *));
    387 int ac97_write __P((struct ac97_softc *, u_int8_t, u_int16_t));
    388 
    389 /* #define AC97_DEBUG 10 */
    390 
    391 #ifdef AUDIO_DEBUG
    392 #define DPRINTF(x)	if (ac97debug) printf x
    393 #define DPRINTFN(n,x)	if (ac97debug>(n)) printf x
    394 #ifdef AC97_DEBUG
    395 int	ac97debug = AC97_DEBUG;
    396 #else
    397 int	ac97debug = 0;
    398 #endif
    399 #else
    400 #define DPRINTF(x)
    401 #define DPRINTFN(n,x)
    402 #endif
    403 
    404 void
    405 ac97_read(as, reg, val)
    406 	struct ac97_softc *as;
    407 	u_int8_t reg;
    408 	u_int16_t *val;
    409 {
    410 	int error;
    411 
    412 	if (as->host_flags & AC97_HOST_DONT_READ &&
    413 	    (reg != AC97_REG_VENDOR_ID1 && reg != AC97_REG_VENDOR_ID2 &&
    414 	     reg != AC97_REG_RESET)) {
    415 		*val = as->shadow_reg[reg >> 1];
    416 		return;
    417 	}
    418 
    419 	if ((error = as->host_if->read(as->host_if->arg, reg, val))) {
    420 		*val = as->shadow_reg[reg >> 1];
    421 	}
    422 }
    423 
    424 int
    425 ac97_write(as, reg, val)
    426 	struct ac97_softc *as;
    427 	u_int8_t reg;
    428 	u_int16_t val;
    429 {
    430 
    431 	as->shadow_reg[reg >> 1] = val;
    432 
    433 	return (as->host_if->write(as->host_if->arg, reg, val));
    434 }
    435 
    436 void
    437 ac97_setup_defaults(as)
    438 	struct ac97_softc *as;
    439 {
    440 	int idx;
    441 	const struct ac97_source_info *si;
    442 
    443 	memset(as->shadow_reg, 0, sizeof(as->shadow_reg));
    444 
    445 	for (idx = 0; idx < SOURCE_INFO_SIZE; idx++) {
    446 		si = &source_info[idx];
    447 		ac97_write(as, si->reg, si->default_value);
    448 	}
    449 }
    450 
    451 void
    452 ac97_restore_shadow(self)
    453 	struct ac97_codec_if *self;
    454 {
    455 	struct ac97_softc *as = (struct ac97_softc *) self;
    456 	int idx;
    457 	const struct ac97_source_info *si;
    458 
    459 	for (idx = 0; idx < SOURCE_INFO_SIZE; idx++) {
    460 		si = &source_info[idx];
    461 		ac97_write(as, si->reg, as->shadow_reg[si->reg >> 1]);
    462 	}
    463 }
    464 
    465 int
    466 ac97_str_equal(a, b)
    467 	const char *a, *b;
    468 {
    469 	return ((a == b) || (a && b && (!strcmp(a, b))));
    470 }
    471 
    472 void
    473 ac97_setup_source_info(as)
    474 	struct ac97_softc *as;
    475 {
    476 	int idx, ouridx;
    477 	struct ac97_source_info *si, *si2;
    478 
    479 	for (idx = 0, ouridx = 0; idx < SOURCE_INFO_SIZE; idx++) {
    480 		si = &as->source_info[ouridx];
    481 
    482 		memcpy(si, &source_info[idx], sizeof(*si));
    483 
    484 		switch (si->type) {
    485 		case AUDIO_MIXER_CLASS:
    486 		        si->mixer_class = ouridx;
    487 			ouridx++;
    488 			break;
    489 		case AUDIO_MIXER_VALUE:
    490 			/* Todo - Test to see if it works */
    491 			ouridx++;
    492 
    493 			/* Add an entry for mute, if necessary */
    494 			if (si->mute) {
    495 				si = &as->source_info[ouridx];
    496 				memcpy(si, &source_info[idx], sizeof(*si));
    497 				si->qualifier = AudioNmute;
    498 				si->type = AUDIO_MIXER_ENUM;
    499 				si->info = &ac97_on_off;
    500 				si->info_size = sizeof(ac97_on_off);
    501 				si->bits = 1;
    502 				si->ofs = 15;
    503 				si->mute = 0;
    504 				si->polarity = 0;
    505 				ouridx++;
    506 			}
    507 			break;
    508 		case AUDIO_MIXER_ENUM:
    509 			/* Todo - Test to see if it works */
    510 			ouridx++;
    511 			break;
    512 		default:
    513 			printf ("ac97: shouldn't get here\n");
    514 			break;
    515 		}
    516 	}
    517 
    518 	as->num_source_info = ouridx;
    519 
    520 	for (idx = 0; idx < as->num_source_info; idx++) {
    521 		int idx2, previdx;
    522 
    523 		si = &as->source_info[idx];
    524 
    525 		/* Find mixer class */
    526 		for (idx2 = 0; idx2 < as->num_source_info; idx2++) {
    527 			si2 = &as->source_info[idx2];
    528 
    529 			if (si2->type == AUDIO_MIXER_CLASS &&
    530 			    ac97_str_equal(si->class,
    531 					   si2->class)) {
    532 				si->mixer_class = idx2;
    533 			}
    534 		}
    535 
    536 
    537 		/* Setup prev and next pointers */
    538 		if (si->prev != 0)
    539 			continue;
    540 
    541 		if (si->qualifier)
    542 			continue;
    543 
    544 		si->prev = AUDIO_MIXER_LAST;
    545 		previdx = idx;
    546 
    547 		for (idx2 = 0; idx2 < as->num_source_info; idx2++) {
    548 			if (idx2 == idx)
    549 				continue;
    550 
    551 			si2 = &as->source_info[idx2];
    552 
    553 			if (!si2->prev &&
    554 			    ac97_str_equal(si->class, si2->class) &&
    555 			    ac97_str_equal(si->device, si2->device)) {
    556 				as->source_info[previdx].next = idx2;
    557 				as->source_info[idx2].prev = previdx;
    558 
    559 				previdx = idx2;
    560 			}
    561 		}
    562 
    563 		as->source_info[previdx].next = AUDIO_MIXER_LAST;
    564 	}
    565 }
    566 
    567 int
    568 ac97_attach(host_if)
    569 	struct ac97_host_if *host_if;
    570 {
    571 	struct ac97_softc *as;
    572 	struct device *sc_dev = (struct device *)host_if->arg;
    573 	int error, i, j;
    574 	u_int16_t id1, id2, caps;
    575 	u_int32_t id;
    576 	mixer_ctrl_t ctl;
    577 	const char *delim;
    578 
    579 	as = malloc(sizeof(struct ac97_softc), M_DEVBUF, M_WAITOK|M_ZERO);
    580 
    581 	if (as == NULL)
    582 		return (ENOMEM);
    583 
    584 	as->codec_if.vtbl = &ac97civ;
    585 	as->host_if = host_if;
    586 
    587 	if ((error = host_if->attach(host_if->arg, &as->codec_if))) {
    588 		free (as, M_DEVBUF);
    589 		return (error);
    590 	}
    591 
    592 	host_if->reset(host_if->arg);
    593 
    594 	host_if->write(host_if->arg, AC97_REG_POWER, 0);
    595 	host_if->write(host_if->arg, AC97_REG_RESET, 0);
    596 
    597 	if (host_if->flags)
    598 		as->host_flags = host_if->flags(host_if->arg);
    599 
    600 	ac97_setup_defaults(as);
    601 	ac97_read(as, AC97_REG_VENDOR_ID1, &id1);
    602 	ac97_read(as, AC97_REG_VENDOR_ID2, &id2);
    603 	ac97_read(as, AC97_REG_RESET, &caps);
    604 
    605 	id = (id1 << 16) | id2;
    606 
    607 	printf("%s: ", sc_dev->dv_xname);
    608 
    609 	for (i = 0; ; i++) {
    610 		if (ac97codecid[i].id == 0) {
    611 			char pnp[4];
    612 
    613 			AC97_GET_CODEC_ID(id, pnp);
    614 #define ISASCII(c) ((c) >= ' ' && (c) < 0x7f)
    615 			if (ISASCII(pnp[0]) && ISASCII(pnp[1]) &&
    616 			    ISASCII(pnp[2]))
    617 				printf("%c%c%c%d", pnp[0], pnp[1], pnp[2],
    618 				    pnp[3]);
    619 			else
    620 				printf("unknown (0x%08x)", id);
    621 			break;
    622 		}
    623 		if (ac97codecid[i].id == id) {
    624 			printf("%s", ac97codecid[i].name);
    625 			break;
    626 		}
    627 	}
    628 	printf(" codec; ");
    629 	for (i = j = 0; i < 10; i++) {
    630 		if (caps & (1 << i)) {
    631 			printf("%s%s", j? ", " : "", ac97feature[i]);
    632 			j++;
    633 		}
    634 	}
    635 	printf("%s%s\n", j? ", " : "", ac97enhancement[(caps >> 10) & 0x1f]);
    636 
    637 	ac97_read(as, AC97_REG_EXT_AUDIO_ID, &caps);
    638 	if (caps & (AC97_EXT_AUDIO_VRA | AC97_EXT_AUDIO_DRA
    639 		    | AC97_EXT_AUDIO_SPDIF | AC97_EXT_AUDIO_VRM
    640 		    | AC97_EXT_AUDIO_CDAC | AC97_EXT_AUDIO_SDAC
    641 		    | AC97_EXT_AUDIO_LDAC)) {
    642 		printf("%s:", sc_dev->dv_xname);
    643 		delim = "";
    644 
    645 		if (caps & AC97_EXT_AUDIO_VRA) {
    646 			printf("%s variable rate audio", delim);
    647 			delim = ",";
    648 		}
    649 		if (caps & AC97_EXT_AUDIO_DRA) {
    650 			printf("%s double rate output", delim);
    651 			delim = ",";
    652 		}
    653 		if (caps & AC97_EXT_AUDIO_SPDIF) {
    654 			printf("%s S/PDIF", delim);
    655 			delim = ",";
    656 		}
    657 		if (caps & AC97_EXT_AUDIO_VRM) {
    658 			printf("%s variable rate dedicated mic", delim);
    659 			delim = ",";
    660 		}
    661 		if (caps & AC97_EXT_AUDIO_CDAC) {
    662 			printf("%s center DAC", delim);
    663 			delim = ",";
    664 		}
    665 		if (caps & AC97_EXT_AUDIO_SDAC) {
    666 			printf("%s surround DAC", delim);
    667 			delim = ",";
    668 		}
    669 		if (caps & AC97_EXT_AUDIO_LDAC) {
    670 			printf("%s LFE DAC", delim);
    671 		}
    672 		printf("\n");
    673 	}
    674 
    675 	ac97_setup_source_info(as);
    676 
    677 	/* Just enable the DAC and master volumes by default */
    678 	memset(&ctl, 0, sizeof(ctl));
    679 
    680 	ctl.type = AUDIO_MIXER_ENUM;
    681 	ctl.un.ord = 0;  /* off */
    682 	ctl.dev = ac97_get_portnum_by_name(&as->codec_if, AudioCoutputs,
    683 					   AudioNmaster, AudioNmute);
    684 	ac97_mixer_set_port(&as->codec_if, &ctl);
    685 	ctl.dev = ac97_get_portnum_by_name(&as->codec_if, AudioCinputs,
    686 					   AudioNdac, AudioNmute);
    687 
    688 	ac97_mixer_set_port(&as->codec_if, &ctl);
    689 	ctl.dev = ac97_get_portnum_by_name(&as->codec_if, AudioCrecord,
    690 					   AudioNvolume, AudioNmute);
    691 	ac97_mixer_set_port(&as->codec_if, &ctl);
    692 
    693 	ctl.dev = ac97_get_portnum_by_name(&as->codec_if, AudioCrecord,
    694 					   AudioNsource, NULL);
    695 	ctl.type = AUDIO_MIXER_ENUM;
    696 	ctl.un.ord = 0;
    697 	ac97_mixer_set_port(&as->codec_if, &ctl);
    698 
    699 	return (0);
    700 }
    701 
    702 
    703 int
    704 ac97_query_devinfo(codec_if, dip)
    705 	struct ac97_codec_if *codec_if;
    706 	mixer_devinfo_t *dip;
    707 {
    708 	struct ac97_softc *as = (struct ac97_softc *)codec_if;
    709 
    710 	if (dip->index < as->num_source_info) {
    711 		struct ac97_source_info *si = &as->source_info[dip->index];
    712 		const char *name;
    713 
    714 		dip->type = si->type;
    715 		dip->mixer_class = si->mixer_class;
    716 		dip->prev = si->prev;
    717 		dip->next = si->next;
    718 
    719 		if (si->qualifier)
    720 			name = si->qualifier;
    721 		else if (si->device)
    722 			name = si->device;
    723 		else if (si->class)
    724 			name = si->class;
    725 		else
    726 			name = 0;
    727 
    728 		if (name)
    729 			strcpy(dip->label.name, name);
    730 
    731 		memcpy(&dip->un, si->info, si->info_size);
    732 
    733 		/* Set the delta for volume sources */
    734 		if (dip->type == AUDIO_MIXER_VALUE)
    735 			dip->un.v.delta = 1 << (8 - si->bits);
    736 
    737 		return (0);
    738 	}
    739 
    740 	return (ENXIO);
    741 }
    742 
    743 
    744 
    745 int
    746 ac97_mixer_set_port(codec_if, cp)
    747 	struct ac97_codec_if *codec_if;
    748 	mixer_ctrl_t *cp;
    749 {
    750 	struct ac97_softc *as = (struct ac97_softc *)codec_if;
    751 	struct ac97_source_info *si = &as->source_info[cp->dev];
    752 	u_int16_t mask;
    753 	u_int16_t val, newval;
    754 	int error;
    755 
    756 	if (cp->dev < 0 || cp->dev >= as->num_source_info)
    757 		return (EINVAL);
    758 
    759 	if (cp->type != si->type)
    760 		return (EINVAL);
    761 
    762 	ac97_read(as, si->reg, &val);
    763 
    764 	DPRINTFN(5, ("read(%x) = %x\n", si->reg, val));
    765 
    766 	mask = (1 << si->bits) - 1;
    767 
    768 	switch (cp->type) {
    769 	case AUDIO_MIXER_ENUM:
    770 		if (cp->un.ord > mask || cp->un.ord < 0)
    771 			return (EINVAL);
    772 
    773 		newval = (cp->un.ord << si->ofs);
    774 		if (si->reg == AC97_REG_RECORD_SELECT) {
    775 			newval |= (newval << (8 + si->ofs));
    776 			mask |= (mask << 8);
    777 		}
    778 		break;
    779 	case AUDIO_MIXER_VALUE:
    780 	{
    781 		const struct audio_mixer_value *value = si->info;
    782 		u_int16_t  l, r;
    783 
    784 		if ((cp->un.value.num_channels <= 0) ||
    785 		    (cp->un.value.num_channels > value->num_channels))
    786 			return (EINVAL);
    787 
    788 		if (cp->un.value.num_channels == 1) {
    789 			l = r = cp->un.value.level[AUDIO_MIXER_LEVEL_MONO];
    790 		} else {
    791 			if (!(as->host_flags & AC97_HOST_SWAPPED_CHANNELS)) {
    792 				l = cp->un.value.level[AUDIO_MIXER_LEVEL_LEFT];
    793 				r = cp->un.value.level[AUDIO_MIXER_LEVEL_RIGHT];
    794 			} else {	/* left/right is reversed here */
    795 				r = cp->un.value.level[AUDIO_MIXER_LEVEL_LEFT];
    796 				l = cp->un.value.level[AUDIO_MIXER_LEVEL_RIGHT];
    797 			}
    798 
    799 		}
    800 
    801 		if (!si->polarity) {
    802 			l = 255 - l;
    803 			r = 255 - r;
    804 		}
    805 
    806 		l = l >> (8 - si->bits);
    807 		r = r >> (8 - si->bits);
    808 
    809 		newval = ((l & mask) << si->ofs);
    810 		if (value->num_channels == 2) {
    811 			newval |= ((r & mask) << (si->ofs + 8));
    812 			mask |= (mask << 8);
    813 		}
    814 
    815 		break;
    816 	}
    817 	default:
    818 		return (EINVAL);
    819 	}
    820 
    821 	mask = mask << si->ofs;
    822 	error = ac97_write(as, si->reg, (val & ~mask) | newval);
    823 	if (error)
    824 		return (error);
    825 
    826 	return (0);
    827 }
    828 
    829 int
    830 ac97_get_portnum_by_name(codec_if, class, device, qualifier)
    831 	struct ac97_codec_if *codec_if;
    832 	char *class, *device, *qualifier;
    833 {
    834 	struct ac97_softc *as = (struct ac97_softc *)codec_if;
    835 	int idx;
    836 
    837 	for (idx = 0; idx < as->num_source_info; idx++) {
    838 		struct ac97_source_info *si = &as->source_info[idx];
    839 		if (ac97_str_equal(class, si->class) &&
    840 		    ac97_str_equal(device, si->device) &&
    841 		    ac97_str_equal(qualifier, si->qualifier))
    842 			return (idx);
    843 	}
    844 
    845 	return (-1);
    846 }
    847 
    848 int
    849 ac97_mixer_get_port(codec_if, cp)
    850 	struct ac97_codec_if *codec_if;
    851 	mixer_ctrl_t *cp;
    852 {
    853 	struct ac97_softc *as = (struct ac97_softc *)codec_if;
    854 	struct ac97_source_info *si = &as->source_info[cp->dev];
    855 	u_int16_t mask;
    856 	u_int16_t val;
    857 
    858 	if (cp->dev < 0 || cp->dev >= as->num_source_info)
    859 		return (EINVAL);
    860 
    861 	if (cp->type != si->type)
    862 		return (EINVAL);
    863 
    864 	ac97_read(as, si->reg, &val);
    865 
    866 	DPRINTFN(5, ("read(%x) = %x\n", si->reg, val));
    867 
    868 	mask = (1 << si->bits) - 1;
    869 
    870 	switch (cp->type) {
    871 	case AUDIO_MIXER_ENUM:
    872 		cp->un.ord = (val >> si->ofs) & mask;
    873 		DPRINTFN(4, ("AUDIO_MIXER_ENUM: %x %d %x %d\n", val, si->ofs, mask, cp->un.ord));
    874 		break;
    875 	case AUDIO_MIXER_VALUE:
    876 	{
    877 		const struct audio_mixer_value *value = si->info;
    878 		u_int16_t  l, r;
    879 
    880 		if ((cp->un.value.num_channels <= 0) ||
    881 		    (cp->un.value.num_channels > value->num_channels))
    882 			return (EINVAL);
    883 
    884 		if (value->num_channels == 1) {
    885 			l = r = (val >> si->ofs) & mask;
    886 		} else {
    887 			if (!(as->host_flags & AC97_HOST_SWAPPED_CHANNELS)) {
    888 				l = (val >> si->ofs) & mask;
    889 				r = (val >> (si->ofs + 8)) & mask;
    890 			} else {	/* host has reversed channels */
    891 				r = (val >> si->ofs) & mask;
    892 				l = (val >> (si->ofs + 8)) & mask;
    893 			}
    894 		}
    895 
    896 		l = (l << (8 - si->bits));
    897 		r = (r << (8 - si->bits));
    898 		if (!si->polarity) {
    899 			l = 255 - l;
    900 			r = 255 - r;
    901 		}
    902 
    903 		/* The EAP driver averages l and r for stereo
    904 		   channels that are requested in MONO mode. Does this
    905 		   make sense? */
    906 		if (cp->un.value.num_channels == 1) {
    907 			cp->un.value.level[AUDIO_MIXER_LEVEL_MONO] = l;
    908 		} else if (cp->un.value.num_channels == 2) {
    909 			cp->un.value.level[AUDIO_MIXER_LEVEL_LEFT] = l;
    910 			cp->un.value.level[AUDIO_MIXER_LEVEL_RIGHT] = r;
    911 		}
    912 
    913 		break;
    914 	}
    915 	default:
    916 		return (EINVAL);
    917 	}
    918 
    919 	return (0);
    920 }
    921 
    922