Home | History | Annotate | Line # | Download | only in ic
ac97.c revision 1.22
      1 /*      $NetBSD: ac97.c,v 1.22 2002/01/06 17:03:17 jmcneill 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.22 2002/01/06 17:03:17 jmcneill 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', 'K', 'M', 0),	"Asahi Kasei AK4540"	},
    295 	{ AC97_CODEC_ID('A', 'K', 'M', 2),	"Asahi Kasei AK4543"	},
    296 	{ AC97_CODEC_ID('C', 'R', 'Y', 0),	"Crystal CS4297"	},
    297 	{ AC97_CODEC_ID('C', 'R', 'Y', 3),	"Crystal CS4297"	},
    298 	{ AC97_CODEC_ID('C', 'R', 'Y', 19),	"Crystal CS4297A"	},
    299 	{ AC97_CODEC_ID('C', 'R', 'Y', 35),	"Crystal CS4298",	},
    300 	{ AC97_CODEC_ID('C', 'R', 'Y', 43),	"Crystal CS4294",	},
    301 	{ AC97_CODEC_ID('C', 'R', 'Y', 49),	"Crystal CS4299",	},
    302 	{ AC97_CODEC_ID('C', 'R', 'Y', 51),	"Crystal CS4298A",	},
    303 	{ AC97_CODEC_ID('C', 'R', 'Y', 52),	"Crystal CS4299",	},
    304 	{ AC97_CODEC_ID('N', 'S', 'C', 49), "National Semiconductor LM4549", },
    305 	{ AC97_CODEC_ID('S', 'I', 'L', 34),	"Silicon Laboratory Si3036", },
    306 	{ AC97_CODEC_ID('S', 'I', 'L', 35),	"Silicon Laboratory Si3038", },
    307 	{ AC97_CODEC_ID('T', 'R', 'A', 2),	"TriTech TR28022",	},
    308 	{ AC97_CODEC_ID('T', 'R', 'A', 3),	"TriTech TR28023",	},
    309 	{ AC97_CODEC_ID('T', 'R', 'A', 6),	"TriTech TR28026",	},
    310 	{ AC97_CODEC_ID('T', 'R', 'A', 8),	"TriTech TR28028",	},
    311 	{ AC97_CODEC_ID('T', 'R', 'A', 35),	"TriTech unknown",	},
    312 	{ AC97_CODEC_ID('W', 'M', 'L', 0),	"Wolfson WM9704",	},
    313 	{ AC97_CODEC_ID('W', 'M', 'L', 3),	"Wolfson WM9707",	},
    314 	{ 0x45838308,				"ESS Technology ES1921", },
    315 	{ 0x83847600,				"SigmaTel STAC9700",	},
    316 	{ 0x83847604,				"SigmaTel STAC9701/3/4/5", },
    317 	{ 0x83847605,				"SigmaTel STAC9704", 	},
    318 	{ 0x83847608,				"SigmaTel STAC9708", 	},
    319 	{ 0x83847609,				"SigmaTel STAC9721/23",	},
    320 	{ 0x83847644,				"SigmaTel STAC9744/45",	},
    321 	{ 0x83847684,				"SigmaTel STAC9783/84",	},
    322 	{ 0,					NULL,			}
    323 };
    324 
    325 static const char * const ac97enhancement[] = {
    326 	"no 3D stereo",
    327 	"Analog Devices Phat Stereo",
    328 	"Creative"
    329 	"National Semi 3D",
    330 	"Yamaha Ymersion",
    331 	"BBE 3D",
    332 	"Crystal Semi 3D"
    333 	"Qsound QXpander",
    334 	"Spatializer 3D",
    335 	"SRS 3D",
    336 	"Platform Tech 3D",
    337 	"AKM 3D",
    338 	"Aureal",
    339 	"AZTECH 3D",
    340 	"Binaura 3D",
    341 	"ESS Technology",
    342 	"Harman International VMAx",
    343 	"Nvidea 3D",
    344 	"Philips Incredible Sound",
    345 	"Texas Instruments' 3D",
    346 	"VLSI Technology 3D",
    347 	"TriTech 3D",
    348 	"Realtek 3D",
    349 	"Samsung 3D",
    350 	"Wolfson Microelectronics 3D",
    351 	"Delta Integration 3D",
    352 	"SigmaTel 3D",
    353 	"Unknown 3D",
    354 	"Rockwell 3D",
    355 	"Unknown 3D",
    356 	"Unknown 3D",
    357 	"Unknown 3D",
    358 };
    359 
    360 static const char * const ac97feature[] = {
    361 	"mic channel",
    362 	"reserved",
    363 	"tone",
    364 	"simulated stereo",
    365 	"headphone",
    366 	"bass boost",
    367 	"18 bit DAC",
    368 	"20 bit DAC",
    369 	"18 bit ADC",
    370 	"20 bit ADC"
    371 };
    372 
    373 
    374 int ac97_str_equal __P((const char *, const char *));
    375 void ac97_setup_source_info __P((struct ac97_softc *));
    376 void ac97_read __P((struct ac97_softc *, u_int8_t, u_int16_t *));
    377 void ac97_setup_defaults __P((struct ac97_softc *));
    378 int ac97_write __P((struct ac97_softc *, u_int8_t, u_int16_t));
    379 
    380 /* #define AC97_DEBUG 10 */
    381 
    382 #ifdef AUDIO_DEBUG
    383 #define DPRINTF(x)	if (ac97debug) printf x
    384 #define DPRINTFN(n,x)	if (ac97debug>(n)) printf x
    385 #ifdef AC97_DEBUG
    386 int	ac97debug = AC97_DEBUG;
    387 #else
    388 int	ac97debug = 0;
    389 #endif
    390 #else
    391 #define DPRINTF(x)
    392 #define DPRINTFN(n,x)
    393 #endif
    394 
    395 void
    396 ac97_read(as, reg, val)
    397 	struct ac97_softc *as;
    398 	u_int8_t reg;
    399 	u_int16_t *val;
    400 {
    401 	int error;
    402 
    403 	if (as->host_flags & AC97_HOST_DONT_READ &&
    404 	    (reg != AC97_REG_VENDOR_ID1 && reg != AC97_REG_VENDOR_ID2 &&
    405 	     reg != AC97_REG_RESET)) {
    406 		*val = as->shadow_reg[reg >> 1];
    407 		return;
    408 	}
    409 
    410 	if ((error = as->host_if->read(as->host_if->arg, reg, val))) {
    411 		*val = as->shadow_reg[reg >> 1];
    412 	}
    413 }
    414 
    415 int
    416 ac97_write(as, reg, val)
    417 	struct ac97_softc *as;
    418 	u_int8_t reg;
    419 	u_int16_t val;
    420 {
    421 
    422 	as->shadow_reg[reg >> 1] = val;
    423 
    424 	return (as->host_if->write(as->host_if->arg, reg, val));
    425 }
    426 
    427 void
    428 ac97_setup_defaults(as)
    429 	struct ac97_softc *as;
    430 {
    431 	int idx;
    432 	const struct ac97_source_info *si;
    433 
    434 	memset(as->shadow_reg, 0, sizeof(as->shadow_reg));
    435 
    436 	for (idx = 0; idx < SOURCE_INFO_SIZE; idx++) {
    437 		si = &source_info[idx];
    438 		ac97_write(as, si->reg, si->default_value);
    439 	}
    440 }
    441 
    442 void
    443 ac97_restore_shadow(self)
    444 	struct ac97_codec_if *self;
    445 {
    446 	struct ac97_softc *as = (struct ac97_softc *) self;
    447 	int idx;
    448 	const struct ac97_source_info *si;
    449 
    450 	for (idx = 0; idx < SOURCE_INFO_SIZE; idx++) {
    451 		si = &source_info[idx];
    452 		ac97_write(as, si->reg, as->shadow_reg[si->reg >> 1]);
    453 	}
    454 }
    455 
    456 int
    457 ac97_str_equal(a, b)
    458 	const char *a, *b;
    459 {
    460 	return ((a == b) || (a && b && (!strcmp(a, b))));
    461 }
    462 
    463 void
    464 ac97_setup_source_info(as)
    465 	struct ac97_softc *as;
    466 {
    467 	int idx, ouridx;
    468 	struct ac97_source_info *si, *si2;
    469 
    470 	for (idx = 0, ouridx = 0; idx < SOURCE_INFO_SIZE; idx++) {
    471 		si = &as->source_info[ouridx];
    472 
    473 		memcpy(si, &source_info[idx], sizeof(*si));
    474 
    475 		switch (si->type) {
    476 		case AUDIO_MIXER_CLASS:
    477 		        si->mixer_class = ouridx;
    478 			ouridx++;
    479 			break;
    480 		case AUDIO_MIXER_VALUE:
    481 			/* Todo - Test to see if it works */
    482 			ouridx++;
    483 
    484 			/* Add an entry for mute, if necessary */
    485 			if (si->mute) {
    486 				si = &as->source_info[ouridx];
    487 				memcpy(si, &source_info[idx], sizeof(*si));
    488 				si->qualifier = AudioNmute;
    489 				si->type = AUDIO_MIXER_ENUM;
    490 				si->info = &ac97_on_off;
    491 				si->info_size = sizeof(ac97_on_off);
    492 				si->bits = 1;
    493 				si->ofs = 15;
    494 				si->mute = 0;
    495 				si->polarity = 0;
    496 				ouridx++;
    497 			}
    498 			break;
    499 		case AUDIO_MIXER_ENUM:
    500 			/* Todo - Test to see if it works */
    501 			ouridx++;
    502 			break;
    503 		default:
    504 			printf ("ac97: shouldn't get here\n");
    505 			break;
    506 		}
    507 	}
    508 
    509 	as->num_source_info = ouridx;
    510 
    511 	for (idx = 0; idx < as->num_source_info; idx++) {
    512 		int idx2, previdx;
    513 
    514 		si = &as->source_info[idx];
    515 
    516 		/* Find mixer class */
    517 		for (idx2 = 0; idx2 < as->num_source_info; idx2++) {
    518 			si2 = &as->source_info[idx2];
    519 
    520 			if (si2->type == AUDIO_MIXER_CLASS &&
    521 			    ac97_str_equal(si->class,
    522 					   si2->class)) {
    523 				si->mixer_class = idx2;
    524 			}
    525 		}
    526 
    527 
    528 		/* Setup prev and next pointers */
    529 		if (si->prev != 0)
    530 			continue;
    531 
    532 		if (si->qualifier)
    533 			continue;
    534 
    535 		si->prev = AUDIO_MIXER_LAST;
    536 		previdx = idx;
    537 
    538 		for (idx2 = 0; idx2 < as->num_source_info; idx2++) {
    539 			if (idx2 == idx)
    540 				continue;
    541 
    542 			si2 = &as->source_info[idx2];
    543 
    544 			if (!si2->prev &&
    545 			    ac97_str_equal(si->class, si2->class) &&
    546 			    ac97_str_equal(si->device, si2->device)) {
    547 				as->source_info[previdx].next = idx2;
    548 				as->source_info[idx2].prev = previdx;
    549 
    550 				previdx = idx2;
    551 			}
    552 		}
    553 
    554 		as->source_info[previdx].next = AUDIO_MIXER_LAST;
    555 	}
    556 }
    557 
    558 int
    559 ac97_attach(host_if)
    560 	struct ac97_host_if *host_if;
    561 {
    562 	struct ac97_softc *as;
    563 	struct device *sc_dev = (struct device *)host_if->arg;
    564 	int error, i, j;
    565 	u_int16_t id1, id2, caps;
    566 	u_int32_t id;
    567 	mixer_ctrl_t ctl;
    568 
    569 	as = malloc(sizeof(struct ac97_softc), M_DEVBUF, M_WAITOK);
    570 
    571 	if (as == NULL)
    572 		return (ENOMEM);
    573 
    574 	memset(as, 0, sizeof(*as));
    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