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