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