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