Home | History | Annotate | Line # | Download | only in ic
ac97.c revision 1.23
      1 /*      $NetBSD: ac97.c,v 1.23 2002/01/12 16:03:11 tsutsui 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.23 2002/01/12 16:03:11 tsutsui 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|M_ZERO);
    570 
    571 	if (as == NULL)
    572 		return (ENOMEM);
    573 
    574 	as->codec_if.vtbl = &ac97civ;
    575 	as->host_if = host_if;
    576 
    577 	if ((error = host_if->attach(host_if->arg, &as->codec_if))) {
    578 		free (as, M_DEVBUF);
    579 		return (error);
    580 	}
    581 
    582 	host_if->reset(host_if->arg);
    583 
    584 	host_if->write(host_if->arg, AC97_REG_POWER, 0);
    585 	host_if->write(host_if->arg, AC97_REG_RESET, 0);
    586 
    587 	if (host_if->flags)
    588 		as->host_flags = host_if->flags(host_if->arg);
    589 
    590 	ac97_setup_defaults(as);
    591 	ac97_read(as, AC97_REG_VENDOR_ID1, &id1);
    592 	ac97_read(as, AC97_REG_VENDOR_ID2, &id2);
    593 	ac97_read(as, AC97_REG_RESET, &caps);
    594 
    595 	id = (id1 << 16) | id2;
    596 
    597 	printf("%s: ", sc_dev->dv_xname);
    598 
    599 	for (i = 0; ; i++) {
    600 		if (ac97codecid[i].id == 0) {
    601 			char pnp[4];
    602 
    603 			AC97_GET_CODEC_ID(id, pnp);
    604 #define ISASCII(c) ((c) >= ' ' && (c) < 0x7f)
    605 			if (ISASCII(pnp[0]) && ISASCII(pnp[1]) &&
    606 			    ISASCII(pnp[2]))
    607 				printf("%c%c%c%d", pnp[0], pnp[1], pnp[2],
    608 				    pnp[3]);
    609 			else
    610 				printf("unknown (0x%08x)", id);
    611 			break;
    612 		}
    613 		if (ac97codecid[i].id == id) {
    614 			printf("%s", ac97codecid[i].name);
    615 			break;
    616 		}
    617 	}
    618 	printf(" codec; ");
    619 	for (i = j = 0; i < 10; i++) {
    620 		if (caps & (1 << i)) {
    621 			printf("%s%s", j? ", " : "", ac97feature[i]);
    622 			j++;
    623 		}
    624 	}
    625 
    626 	printf("%s%s\n", j? ", " : "", ac97enhancement[(caps >> 10) & 0x1f]);
    627 
    628 	ac97_setup_source_info(as);
    629 
    630 	/* Just enable the DAC and master volumes by default */
    631 	memset(&ctl, 0, sizeof(ctl));
    632 
    633 	ctl.type = AUDIO_MIXER_ENUM;
    634 	ctl.un.ord = 0;  /* off */
    635 	ctl.dev = ac97_get_portnum_by_name(&as->codec_if, AudioCoutputs,
    636 					   AudioNmaster, AudioNmute);
    637 	ac97_mixer_set_port(&as->codec_if, &ctl);
    638 	ctl.dev = ac97_get_portnum_by_name(&as->codec_if, AudioCinputs,
    639 					   AudioNdac, AudioNmute);
    640 
    641 	ac97_mixer_set_port(&as->codec_if, &ctl);
    642 	ctl.dev = ac97_get_portnum_by_name(&as->codec_if, AudioCrecord,
    643 					   AudioNvolume, AudioNmute);
    644 	ac97_mixer_set_port(&as->codec_if, &ctl);
    645 
    646 	ctl.dev = ac97_get_portnum_by_name(&as->codec_if, AudioCrecord,
    647 					   AudioNsource, NULL);
    648 	ctl.type = AUDIO_MIXER_ENUM;
    649 	ctl.un.ord = 0;
    650 	ac97_mixer_set_port(&as->codec_if, &ctl);
    651 
    652 	return (0);
    653 }
    654 
    655 
    656 int
    657 ac97_query_devinfo(codec_if, dip)
    658 	struct ac97_codec_if *codec_if;
    659 	mixer_devinfo_t *dip;
    660 {
    661 	struct ac97_softc *as = (struct ac97_softc *)codec_if;
    662 
    663 	if (dip->index < as->num_source_info) {
    664 		struct ac97_source_info *si = &as->source_info[dip->index];
    665 		const char *name;
    666 
    667 		dip->type = si->type;
    668 		dip->mixer_class = si->mixer_class;
    669 		dip->prev = si->prev;
    670 		dip->next = si->next;
    671 
    672 		if (si->qualifier)
    673 			name = si->qualifier;
    674 		else if (si->device)
    675 			name = si->device;
    676 		else if (si->class)
    677 			name = si->class;
    678 		else
    679 			name = 0;
    680 
    681 		if (name)
    682 			strcpy(dip->label.name, name);
    683 
    684 		memcpy(&dip->un, si->info, si->info_size);
    685 
    686 		/* Set the delta for volume sources */
    687 		if (dip->type == AUDIO_MIXER_VALUE)
    688 			dip->un.v.delta = 1 << (8 - si->bits);
    689 
    690 		return (0);
    691 	}
    692 
    693 	return (ENXIO);
    694 }
    695 
    696 
    697 
    698 int
    699 ac97_mixer_set_port(codec_if, cp)
    700 	struct ac97_codec_if *codec_if;
    701 	mixer_ctrl_t *cp;
    702 {
    703 	struct ac97_softc *as = (struct ac97_softc *)codec_if;
    704 	struct ac97_source_info *si = &as->source_info[cp->dev];
    705 	u_int16_t mask;
    706 	u_int16_t val, newval;
    707 	int error;
    708 
    709 	if (cp->dev < 0 || cp->dev >= as->num_source_info)
    710 		return (EINVAL);
    711 
    712 	if (cp->type != si->type)
    713 		return (EINVAL);
    714 
    715 	ac97_read(as, si->reg, &val);
    716 
    717 	DPRINTFN(5, ("read(%x) = %x\n", si->reg, val));
    718 
    719 	mask = (1 << si->bits) - 1;
    720 
    721 	switch (cp->type) {
    722 	case AUDIO_MIXER_ENUM:
    723 		if (cp->un.ord > mask || cp->un.ord < 0)
    724 			return (EINVAL);
    725 
    726 		newval = (cp->un.ord << si->ofs);
    727 		if (si->reg == AC97_REG_RECORD_SELECT) {
    728 			newval |= (newval << (8 + si->ofs));
    729 			mask |= (mask << 8);
    730 		}
    731 		break;
    732 	case AUDIO_MIXER_VALUE:
    733 	{
    734 		const struct audio_mixer_value *value = si->info;
    735 		u_int16_t  l, r;
    736 
    737 		if ((cp->un.value.num_channels <= 0) ||
    738 		    (cp->un.value.num_channels > value->num_channels))
    739 			return (EINVAL);
    740 
    741 		if (cp->un.value.num_channels == 1) {
    742 			l = r = cp->un.value.level[AUDIO_MIXER_LEVEL_MONO];
    743 		} else {
    744 			if (!(as->host_flags & AC97_HOST_SWAPPED_CHANNELS)) {
    745 				l = cp->un.value.level[AUDIO_MIXER_LEVEL_LEFT];
    746 				r = cp->un.value.level[AUDIO_MIXER_LEVEL_RIGHT];
    747 			} else {	/* left/right is reversed here */
    748 				r = cp->un.value.level[AUDIO_MIXER_LEVEL_LEFT];
    749 				l = cp->un.value.level[AUDIO_MIXER_LEVEL_RIGHT];
    750 			}
    751 
    752 		}
    753 
    754 		if (!si->polarity) {
    755 			l = 255 - l;
    756 			r = 255 - r;
    757 		}
    758 
    759 		l = l >> (8 - si->bits);
    760 		r = r >> (8 - si->bits);
    761 
    762 		newval = ((l & mask) << si->ofs);
    763 		if (value->num_channels == 2) {
    764 			newval |= ((r & mask) << (si->ofs + 8));
    765 			mask |= (mask << 8);
    766 		}
    767 
    768 		break;
    769 	}
    770 	default:
    771 		return (EINVAL);
    772 	}
    773 
    774 	mask = mask << si->ofs;
    775 	error = ac97_write(as, si->reg, (val & ~mask) | newval);
    776 	if (error)
    777 		return (error);
    778 
    779 	return (0);
    780 }
    781 
    782 int
    783 ac97_get_portnum_by_name(codec_if, class, device, qualifier)
    784 	struct ac97_codec_if *codec_if;
    785 	char *class, *device, *qualifier;
    786 {
    787 	struct ac97_softc *as = (struct ac97_softc *)codec_if;
    788 	int idx;
    789 
    790 	for (idx = 0; idx < as->num_source_info; idx++) {
    791 		struct ac97_source_info *si = &as->source_info[idx];
    792 		if (ac97_str_equal(class, si->class) &&
    793 		    ac97_str_equal(device, si->device) &&
    794 		    ac97_str_equal(qualifier, si->qualifier))
    795 			return (idx);
    796 	}
    797 
    798 	return (-1);
    799 }
    800 
    801 int
    802 ac97_mixer_get_port(codec_if, cp)
    803 	struct ac97_codec_if *codec_if;
    804 	mixer_ctrl_t *cp;
    805 {
    806 	struct ac97_softc *as = (struct ac97_softc *)codec_if;
    807 	struct ac97_source_info *si = &as->source_info[cp->dev];
    808 	u_int16_t mask;
    809 	u_int16_t val;
    810 
    811 	if (cp->dev < 0 || cp->dev >= as->num_source_info)
    812 		return (EINVAL);
    813 
    814 	if (cp->type != si->type)
    815 		return (EINVAL);
    816 
    817 	ac97_read(as, si->reg, &val);
    818 
    819 	DPRINTFN(5, ("read(%x) = %x\n", si->reg, val));
    820 
    821 	mask = (1 << si->bits) - 1;
    822 
    823 	switch (cp->type) {
    824 	case AUDIO_MIXER_ENUM:
    825 		cp->un.ord = (val >> si->ofs) & mask;
    826 		DPRINTFN(4, ("AUDIO_MIXER_ENUM: %x %d %x %d\n", val, si->ofs, mask, cp->un.ord));
    827 		break;
    828 	case AUDIO_MIXER_VALUE:
    829 	{
    830 		const struct audio_mixer_value *value = si->info;
    831 		u_int16_t  l, r;
    832 
    833 		if ((cp->un.value.num_channels <= 0) ||
    834 		    (cp->un.value.num_channels > value->num_channels))
    835 			return (EINVAL);
    836 
    837 		if (value->num_channels == 1) {
    838 			l = r = (val >> si->ofs) & mask;
    839 		} else {
    840 			if (!(as->host_flags & AC97_HOST_SWAPPED_CHANNELS)) {
    841 				l = (val >> si->ofs) & mask;
    842 				r = (val >> (si->ofs + 8)) & mask;
    843 			} else {	/* host has reversed channels */
    844 				r = (val >> si->ofs) & mask;
    845 				l = (val >> (si->ofs + 8)) & mask;
    846 			}
    847 		}
    848 
    849 		l = (l << (8 - si->bits));
    850 		r = (r << (8 - si->bits));
    851 		if (!si->polarity) {
    852 			l = 255 - l;
    853 			r = 255 - r;
    854 		}
    855 
    856 		/* The EAP driver averages l and r for stereo
    857 		   channels that are requested in MONO mode. Does this
    858 		   make sense? */
    859 		if (cp->un.value.num_channels == 1) {
    860 			cp->un.value.level[AUDIO_MIXER_LEVEL_MONO] = l;
    861 		} else if (cp->un.value.num_channels == 2) {
    862 			cp->un.value.level[AUDIO_MIXER_LEVEL_LEFT] = l;
    863 			cp->un.value.level[AUDIO_MIXER_LEVEL_RIGHT] = r;
    864 		}
    865 
    866 		break;
    867 	}
    868 	default:
    869 		return (EINVAL);
    870 	}
    871 
    872 	return (0);
    873 }
    874 
    875