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