Home | History | Annotate | Line # | Download | only in ic
ac97.c revision 1.25
      1 /*      $NetBSD: ac97.c,v 1.25 2002/07/05 13:50:47 joda 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.25 2002/07/05 13:50:47 joda 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', 64),	"Analog Devices AD1881" },
    294 	{ AC97_CODEC_ID('A', 'D', 'S', 72),	"Analog Devices AD1881A" },
    295 	{ AC97_CODEC_ID('A', 'D', 'S', 96),	"Analog Devices AD1885" },
    296 	{ AC97_CODEC_ID('A', 'K', 'M', 0),	"Asahi Kasei AK4540"	},
    297 	{ AC97_CODEC_ID('A', 'K', 'M', 2),	"Asahi Kasei AK4543"	},
    298 	{ AC97_CODEC_ID('C', 'R', 'Y', 0),	"Crystal CS4297"	},
    299 	{ AC97_CODEC_ID('C', 'R', 'Y', 3),	"Crystal CS4297"	},
    300 	{ AC97_CODEC_ID('C', 'R', 'Y', 19),	"Crystal CS4297A"	},
    301 	{ AC97_CODEC_ID('C', 'R', 'Y', 35),	"Crystal CS4298",	},
    302 	{ AC97_CODEC_ID('C', 'R', 'Y', 43),	"Crystal CS4294",	},
    303 	{ AC97_CODEC_ID('C', 'R', 'Y', 49),	"Crystal CS4299",	},
    304 	{ AC97_CODEC_ID('C', 'R', 'Y', 51),	"Crystal CS4298A",	},
    305 	{ AC97_CODEC_ID('C', 'R', 'Y', 52),	"Crystal CS4299",	},
    306 	{ AC97_CODEC_ID('N', 'S', 'C', 49), "National Semiconductor LM4549", },
    307 	{ AC97_CODEC_ID('S', 'I', 'L', 34),	"Silicon Laboratory Si3036", },
    308 	{ AC97_CODEC_ID('S', 'I', 'L', 35),	"Silicon Laboratory Si3038", },
    309 	{ AC97_CODEC_ID('T', 'R', 'A', 2),	"TriTech TR28022",	},
    310 	{ AC97_CODEC_ID('T', 'R', 'A', 3),	"TriTech TR28023",	},
    311 	{ AC97_CODEC_ID('T', 'R', 'A', 6),	"TriTech TR28026",	},
    312 	{ AC97_CODEC_ID('T', 'R', 'A', 8),	"TriTech TR28028",	},
    313 	{ AC97_CODEC_ID('T', 'R', 'A', 35),	"TriTech unknown",	},
    314 	{ AC97_CODEC_ID('W', 'M', 'L', 0),	"Wolfson WM9704",	},
    315 	{ AC97_CODEC_ID('W', 'M', 'L', 3),	"Wolfson WM9707",	},
    316 	{ 0x45838308,				"ESS Technology ES1921", },
    317 	{ 0x83847600,				"SigmaTel STAC9700",	},
    318 	{ 0x83847604,				"SigmaTel STAC9701/3/4/5", },
    319 	{ 0x83847605,				"SigmaTel STAC9704", 	},
    320 	{ 0x83847608,				"SigmaTel STAC9708", 	},
    321 	{ 0x83847609,				"SigmaTel STAC9721/23",	},
    322 	{ 0x83847644,				"SigmaTel STAC9744/45",	},
    323 	{ 0x83847684,				"SigmaTel STAC9783/84",	},
    324 	{ 0,					NULL,			}
    325 };
    326 
    327 static const char * const ac97enhancement[] = {
    328 	"no 3D stereo",
    329 	"Analog Devices Phat Stereo",
    330 	"Creative",
    331 	"National Semi 3D",
    332 	"Yamaha Ymersion",
    333 	"BBE 3D",
    334 	"Crystal Semi 3D",
    335 	"Qsound QXpander",
    336 	"Spatializer 3D",
    337 	"SRS 3D",
    338 	"Platform Tech 3D",
    339 	"AKM 3D",
    340 	"Aureal",
    341 	"AZTECH 3D",
    342 	"Binaura 3D",
    343 	"ESS Technology",
    344 	"Harman International VMAx",
    345 	"Nvidea 3D",
    346 	"Philips Incredible Sound",
    347 	"Texas Instruments' 3D",
    348 	"VLSI Technology 3D",
    349 	"TriTech 3D",
    350 	"Realtek 3D",
    351 	"Samsung 3D",
    352 	"Wolfson Microelectronics 3D",
    353 	"Delta Integration 3D",
    354 	"SigmaTel 3D",
    355 	"Unknown 3D",
    356 	"Rockwell 3D",
    357 	"Unknown 3D",
    358 	"Unknown 3D",
    359 	"Unknown 3D",
    360 };
    361 
    362 static const char * const ac97feature[] = {
    363 	"mic channel",
    364 	"reserved",
    365 	"tone",
    366 	"simulated stereo",
    367 	"headphone",
    368 	"bass boost",
    369 	"18 bit DAC",
    370 	"20 bit DAC",
    371 	"18 bit ADC",
    372 	"20 bit ADC"
    373 };
    374 
    375 
    376 int ac97_str_equal __P((const char *, const char *));
    377 void ac97_setup_source_info __P((struct ac97_softc *));
    378 void ac97_read __P((struct ac97_softc *, u_int8_t, u_int16_t *));
    379 void ac97_setup_defaults __P((struct ac97_softc *));
    380 int ac97_write __P((struct ac97_softc *, u_int8_t, u_int16_t));
    381 
    382 /* #define AC97_DEBUG 10 */
    383 
    384 #ifdef AUDIO_DEBUG
    385 #define DPRINTF(x)	if (ac97debug) printf x
    386 #define DPRINTFN(n,x)	if (ac97debug>(n)) printf x
    387 #ifdef AC97_DEBUG
    388 int	ac97debug = AC97_DEBUG;
    389 #else
    390 int	ac97debug = 0;
    391 #endif
    392 #else
    393 #define DPRINTF(x)
    394 #define DPRINTFN(n,x)
    395 #endif
    396 
    397 void
    398 ac97_read(as, reg, val)
    399 	struct ac97_softc *as;
    400 	u_int8_t reg;
    401 	u_int16_t *val;
    402 {
    403 	int error;
    404 
    405 	if (as->host_flags & AC97_HOST_DONT_READ &&
    406 	    (reg != AC97_REG_VENDOR_ID1 && reg != AC97_REG_VENDOR_ID2 &&
    407 	     reg != AC97_REG_RESET)) {
    408 		*val = as->shadow_reg[reg >> 1];
    409 		return;
    410 	}
    411 
    412 	if ((error = as->host_if->read(as->host_if->arg, reg, val))) {
    413 		*val = as->shadow_reg[reg >> 1];
    414 	}
    415 }
    416 
    417 int
    418 ac97_write(as, reg, val)
    419 	struct ac97_softc *as;
    420 	u_int8_t reg;
    421 	u_int16_t val;
    422 {
    423 
    424 	as->shadow_reg[reg >> 1] = val;
    425 
    426 	return (as->host_if->write(as->host_if->arg, reg, val));
    427 }
    428 
    429 void
    430 ac97_setup_defaults(as)
    431 	struct ac97_softc *as;
    432 {
    433 	int idx;
    434 	const struct ac97_source_info *si;
    435 
    436 	memset(as->shadow_reg, 0, sizeof(as->shadow_reg));
    437 
    438 	for (idx = 0; idx < SOURCE_INFO_SIZE; idx++) {
    439 		si = &source_info[idx];
    440 		ac97_write(as, si->reg, si->default_value);
    441 	}
    442 }
    443 
    444 void
    445 ac97_restore_shadow(self)
    446 	struct ac97_codec_if *self;
    447 {
    448 	struct ac97_softc *as = (struct ac97_softc *) self;
    449 	int idx;
    450 	const struct ac97_source_info *si;
    451 
    452 	for (idx = 0; idx < SOURCE_INFO_SIZE; idx++) {
    453 		si = &source_info[idx];
    454 		ac97_write(as, si->reg, as->shadow_reg[si->reg >> 1]);
    455 	}
    456 }
    457 
    458 int
    459 ac97_str_equal(a, b)
    460 	const char *a, *b;
    461 {
    462 	return ((a == b) || (a && b && (!strcmp(a, b))));
    463 }
    464 
    465 void
    466 ac97_setup_source_info(as)
    467 	struct ac97_softc *as;
    468 {
    469 	int idx, ouridx;
    470 	struct ac97_source_info *si, *si2;
    471 
    472 	for (idx = 0, ouridx = 0; idx < SOURCE_INFO_SIZE; idx++) {
    473 		si = &as->source_info[ouridx];
    474 
    475 		memcpy(si, &source_info[idx], sizeof(*si));
    476 
    477 		switch (si->type) {
    478 		case AUDIO_MIXER_CLASS:
    479 		        si->mixer_class = ouridx;
    480 			ouridx++;
    481 			break;
    482 		case AUDIO_MIXER_VALUE:
    483 			/* Todo - Test to see if it works */
    484 			ouridx++;
    485 
    486 			/* Add an entry for mute, if necessary */
    487 			if (si->mute) {
    488 				si = &as->source_info[ouridx];
    489 				memcpy(si, &source_info[idx], sizeof(*si));
    490 				si->qualifier = AudioNmute;
    491 				si->type = AUDIO_MIXER_ENUM;
    492 				si->info = &ac97_on_off;
    493 				si->info_size = sizeof(ac97_on_off);
    494 				si->bits = 1;
    495 				si->ofs = 15;
    496 				si->mute = 0;
    497 				si->polarity = 0;
    498 				ouridx++;
    499 			}
    500 			break;
    501 		case AUDIO_MIXER_ENUM:
    502 			/* Todo - Test to see if it works */
    503 			ouridx++;
    504 			break;
    505 		default:
    506 			printf ("ac97: shouldn't get here\n");
    507 			break;
    508 		}
    509 	}
    510 
    511 	as->num_source_info = ouridx;
    512 
    513 	for (idx = 0; idx < as->num_source_info; idx++) {
    514 		int idx2, previdx;
    515 
    516 		si = &as->source_info[idx];
    517 
    518 		/* Find mixer class */
    519 		for (idx2 = 0; idx2 < as->num_source_info; idx2++) {
    520 			si2 = &as->source_info[idx2];
    521 
    522 			if (si2->type == AUDIO_MIXER_CLASS &&
    523 			    ac97_str_equal(si->class,
    524 					   si2->class)) {
    525 				si->mixer_class = idx2;
    526 			}
    527 		}
    528 
    529 
    530 		/* Setup prev and next pointers */
    531 		if (si->prev != 0)
    532 			continue;
    533 
    534 		if (si->qualifier)
    535 			continue;
    536 
    537 		si->prev = AUDIO_MIXER_LAST;
    538 		previdx = idx;
    539 
    540 		for (idx2 = 0; idx2 < as->num_source_info; idx2++) {
    541 			if (idx2 == idx)
    542 				continue;
    543 
    544 			si2 = &as->source_info[idx2];
    545 
    546 			if (!si2->prev &&
    547 			    ac97_str_equal(si->class, si2->class) &&
    548 			    ac97_str_equal(si->device, si2->device)) {
    549 				as->source_info[previdx].next = idx2;
    550 				as->source_info[idx2].prev = previdx;
    551 
    552 				previdx = idx2;
    553 			}
    554 		}
    555 
    556 		as->source_info[previdx].next = AUDIO_MIXER_LAST;
    557 	}
    558 }
    559 
    560 int
    561 ac97_attach(host_if)
    562 	struct ac97_host_if *host_if;
    563 {
    564 	struct ac97_softc *as;
    565 	struct device *sc_dev = (struct device *)host_if->arg;
    566 	int error, i, j;
    567 	u_int16_t id1, id2, caps;
    568 	u_int32_t id;
    569 	mixer_ctrl_t ctl;
    570 
    571 	as = malloc(sizeof(struct ac97_softc), M_DEVBUF, M_WAITOK|M_ZERO);
    572 
    573 	if (as == NULL)
    574 		return (ENOMEM);
    575 
    576 	as->codec_if.vtbl = &ac97civ;
    577 	as->host_if = host_if;
    578 
    579 	if ((error = host_if->attach(host_if->arg, &as->codec_if))) {
    580 		free (as, M_DEVBUF);
    581 		return (error);
    582 	}
    583 
    584 	host_if->reset(host_if->arg);
    585 
    586 	host_if->write(host_if->arg, AC97_REG_POWER, 0);
    587 	host_if->write(host_if->arg, AC97_REG_RESET, 0);
    588 
    589 	if (host_if->flags)
    590 		as->host_flags = host_if->flags(host_if->arg);
    591 
    592 	ac97_setup_defaults(as);
    593 	ac97_read(as, AC97_REG_VENDOR_ID1, &id1);
    594 	ac97_read(as, AC97_REG_VENDOR_ID2, &id2);
    595 	ac97_read(as, AC97_REG_RESET, &caps);
    596 
    597 	id = (id1 << 16) | id2;
    598 
    599 	printf("%s: ", sc_dev->dv_xname);
    600 
    601 	for (i = 0; ; i++) {
    602 		if (ac97codecid[i].id == 0) {
    603 			char pnp[4];
    604 
    605 			AC97_GET_CODEC_ID(id, pnp);
    606 #define ISASCII(c) ((c) >= ' ' && (c) < 0x7f)
    607 			if (ISASCII(pnp[0]) && ISASCII(pnp[1]) &&
    608 			    ISASCII(pnp[2]))
    609 				printf("%c%c%c%d", pnp[0], pnp[1], pnp[2],
    610 				    pnp[3]);
    611 			else
    612 				printf("unknown (0x%08x)", id);
    613 			break;
    614 		}
    615 		if (ac97codecid[i].id == id) {
    616 			printf("%s", ac97codecid[i].name);
    617 			break;
    618 		}
    619 	}
    620 	printf(" codec; ");
    621 	for (i = j = 0; i < 10; i++) {
    622 		if (caps & (1 << i)) {
    623 			printf("%s%s", j? ", " : "", ac97feature[i]);
    624 			j++;
    625 		}
    626 	}
    627 
    628 	printf("%s%s\n", j? ", " : "", ac97enhancement[(caps >> 10) & 0x1f]);
    629 
    630 	ac97_setup_source_info(as);
    631 
    632 	/* Just enable the DAC and master volumes by default */
    633 	memset(&ctl, 0, sizeof(ctl));
    634 
    635 	ctl.type = AUDIO_MIXER_ENUM;
    636 	ctl.un.ord = 0;  /* off */
    637 	ctl.dev = ac97_get_portnum_by_name(&as->codec_if, AudioCoutputs,
    638 					   AudioNmaster, AudioNmute);
    639 	ac97_mixer_set_port(&as->codec_if, &ctl);
    640 	ctl.dev = ac97_get_portnum_by_name(&as->codec_if, AudioCinputs,
    641 					   AudioNdac, AudioNmute);
    642 
    643 	ac97_mixer_set_port(&as->codec_if, &ctl);
    644 	ctl.dev = ac97_get_portnum_by_name(&as->codec_if, AudioCrecord,
    645 					   AudioNvolume, AudioNmute);
    646 	ac97_mixer_set_port(&as->codec_if, &ctl);
    647 
    648 	ctl.dev = ac97_get_portnum_by_name(&as->codec_if, AudioCrecord,
    649 					   AudioNsource, NULL);
    650 	ctl.type = AUDIO_MIXER_ENUM;
    651 	ctl.un.ord = 0;
    652 	ac97_mixer_set_port(&as->codec_if, &ctl);
    653 
    654 	return (0);
    655 }
    656 
    657 
    658 int
    659 ac97_query_devinfo(codec_if, dip)
    660 	struct ac97_codec_if *codec_if;
    661 	mixer_devinfo_t *dip;
    662 {
    663 	struct ac97_softc *as = (struct ac97_softc *)codec_if;
    664 
    665 	if (dip->index < as->num_source_info) {
    666 		struct ac97_source_info *si = &as->source_info[dip->index];
    667 		const char *name;
    668 
    669 		dip->type = si->type;
    670 		dip->mixer_class = si->mixer_class;
    671 		dip->prev = si->prev;
    672 		dip->next = si->next;
    673 
    674 		if (si->qualifier)
    675 			name = si->qualifier;
    676 		else if (si->device)
    677 			name = si->device;
    678 		else if (si->class)
    679 			name = si->class;
    680 		else
    681 			name = 0;
    682 
    683 		if (name)
    684 			strcpy(dip->label.name, name);
    685 
    686 		memcpy(&dip->un, si->info, si->info_size);
    687 
    688 		/* Set the delta for volume sources */
    689 		if (dip->type == AUDIO_MIXER_VALUE)
    690 			dip->un.v.delta = 1 << (8 - si->bits);
    691 
    692 		return (0);
    693 	}
    694 
    695 	return (ENXIO);
    696 }
    697 
    698 
    699 
    700 int
    701 ac97_mixer_set_port(codec_if, cp)
    702 	struct ac97_codec_if *codec_if;
    703 	mixer_ctrl_t *cp;
    704 {
    705 	struct ac97_softc *as = (struct ac97_softc *)codec_if;
    706 	struct ac97_source_info *si = &as->source_info[cp->dev];
    707 	u_int16_t mask;
    708 	u_int16_t val, newval;
    709 	int error;
    710 
    711 	if (cp->dev < 0 || cp->dev >= as->num_source_info)
    712 		return (EINVAL);
    713 
    714 	if (cp->type != si->type)
    715 		return (EINVAL);
    716 
    717 	ac97_read(as, si->reg, &val);
    718 
    719 	DPRINTFN(5, ("read(%x) = %x\n", si->reg, val));
    720 
    721 	mask = (1 << si->bits) - 1;
    722 
    723 	switch (cp->type) {
    724 	case AUDIO_MIXER_ENUM:
    725 		if (cp->un.ord > mask || cp->un.ord < 0)
    726 			return (EINVAL);
    727 
    728 		newval = (cp->un.ord << si->ofs);
    729 		if (si->reg == AC97_REG_RECORD_SELECT) {
    730 			newval |= (newval << (8 + si->ofs));
    731 			mask |= (mask << 8);
    732 		}
    733 		break;
    734 	case AUDIO_MIXER_VALUE:
    735 	{
    736 		const struct audio_mixer_value *value = si->info;
    737 		u_int16_t  l, r;
    738 
    739 		if ((cp->un.value.num_channels <= 0) ||
    740 		    (cp->un.value.num_channels > value->num_channels))
    741 			return (EINVAL);
    742 
    743 		if (cp->un.value.num_channels == 1) {
    744 			l = r = cp->un.value.level[AUDIO_MIXER_LEVEL_MONO];
    745 		} else {
    746 			if (!(as->host_flags & AC97_HOST_SWAPPED_CHANNELS)) {
    747 				l = cp->un.value.level[AUDIO_MIXER_LEVEL_LEFT];
    748 				r = cp->un.value.level[AUDIO_MIXER_LEVEL_RIGHT];
    749 			} else {	/* left/right is reversed here */
    750 				r = cp->un.value.level[AUDIO_MIXER_LEVEL_LEFT];
    751 				l = cp->un.value.level[AUDIO_MIXER_LEVEL_RIGHT];
    752 			}
    753 
    754 		}
    755 
    756 		if (!si->polarity) {
    757 			l = 255 - l;
    758 			r = 255 - r;
    759 		}
    760 
    761 		l = l >> (8 - si->bits);
    762 		r = r >> (8 - si->bits);
    763 
    764 		newval = ((l & mask) << si->ofs);
    765 		if (value->num_channels == 2) {
    766 			newval |= ((r & mask) << (si->ofs + 8));
    767 			mask |= (mask << 8);
    768 		}
    769 
    770 		break;
    771 	}
    772 	default:
    773 		return (EINVAL);
    774 	}
    775 
    776 	mask = mask << si->ofs;
    777 	error = ac97_write(as, si->reg, (val & ~mask) | newval);
    778 	if (error)
    779 		return (error);
    780 
    781 	return (0);
    782 }
    783 
    784 int
    785 ac97_get_portnum_by_name(codec_if, class, device, qualifier)
    786 	struct ac97_codec_if *codec_if;
    787 	char *class, *device, *qualifier;
    788 {
    789 	struct ac97_softc *as = (struct ac97_softc *)codec_if;
    790 	int idx;
    791 
    792 	for (idx = 0; idx < as->num_source_info; idx++) {
    793 		struct ac97_source_info *si = &as->source_info[idx];
    794 		if (ac97_str_equal(class, si->class) &&
    795 		    ac97_str_equal(device, si->device) &&
    796 		    ac97_str_equal(qualifier, si->qualifier))
    797 			return (idx);
    798 	}
    799 
    800 	return (-1);
    801 }
    802 
    803 int
    804 ac97_mixer_get_port(codec_if, cp)
    805 	struct ac97_codec_if *codec_if;
    806 	mixer_ctrl_t *cp;
    807 {
    808 	struct ac97_softc *as = (struct ac97_softc *)codec_if;
    809 	struct ac97_source_info *si = &as->source_info[cp->dev];
    810 	u_int16_t mask;
    811 	u_int16_t val;
    812 
    813 	if (cp->dev < 0 || cp->dev >= as->num_source_info)
    814 		return (EINVAL);
    815 
    816 	if (cp->type != si->type)
    817 		return (EINVAL);
    818 
    819 	ac97_read(as, si->reg, &val);
    820 
    821 	DPRINTFN(5, ("read(%x) = %x\n", si->reg, val));
    822 
    823 	mask = (1 << si->bits) - 1;
    824 
    825 	switch (cp->type) {
    826 	case AUDIO_MIXER_ENUM:
    827 		cp->un.ord = (val >> si->ofs) & mask;
    828 		DPRINTFN(4, ("AUDIO_MIXER_ENUM: %x %d %x %d\n", val, si->ofs, mask, cp->un.ord));
    829 		break;
    830 	case AUDIO_MIXER_VALUE:
    831 	{
    832 		const struct audio_mixer_value *value = si->info;
    833 		u_int16_t  l, r;
    834 
    835 		if ((cp->un.value.num_channels <= 0) ||
    836 		    (cp->un.value.num_channels > value->num_channels))
    837 			return (EINVAL);
    838 
    839 		if (value->num_channels == 1) {
    840 			l = r = (val >> si->ofs) & mask;
    841 		} else {
    842 			if (!(as->host_flags & AC97_HOST_SWAPPED_CHANNELS)) {
    843 				l = (val >> si->ofs) & mask;
    844 				r = (val >> (si->ofs + 8)) & mask;
    845 			} else {	/* host has reversed channels */
    846 				r = (val >> si->ofs) & mask;
    847 				l = (val >> (si->ofs + 8)) & mask;
    848 			}
    849 		}
    850 
    851 		l = (l << (8 - si->bits));
    852 		r = (r << (8 - si->bits));
    853 		if (!si->polarity) {
    854 			l = 255 - l;
    855 			r = 255 - r;
    856 		}
    857 
    858 		/* The EAP driver averages l and r for stereo
    859 		   channels that are requested in MONO mode. Does this
    860 		   make sense? */
    861 		if (cp->un.value.num_channels == 1) {
    862 			cp->un.value.level[AUDIO_MIXER_LEVEL_MONO] = l;
    863 		} else if (cp->un.value.num_channels == 2) {
    864 			cp->un.value.level[AUDIO_MIXER_LEVEL_LEFT] = l;
    865 			cp->un.value.level[AUDIO_MIXER_LEVEL_RIGHT] = r;
    866 		}
    867 
    868 		break;
    869 	}
    870 	default:
    871 		return (EINVAL);
    872 	}
    873 
    874 	return (0);
    875 }
    876 
    877