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