xref: /openbsd-src/sys/dev/ic/ac97.c (revision b2ea75c1b17e1a9a339660e7ed45cd24946b230e)
1 /*	$OpenBSD: ac97.c,v 1.21 2001/06/20 18:08:53 deraadt Exp $	*/
2 
3 /*
4  * Copyright (c) 1999, 2000 Constantine Sapuntzakis
5  *
6  * Author:	Constantine Sapuntzakis <csapuntz@stanford.edu>
7  *
8  * Redistribution and use in source and binary forms, with or without
9  * modification, are permitted provided that the following conditions
10  * are met:
11  * 1. Redistributions of source code must retain the above copyright
12  *    notice, this list of conditions and the following disclaimer.
13  * 2. Redistributions in binary form must reproduce the above copyright
14  *    notice, this list of conditions and the following disclaimer in the
15  *    documentation and/or other materials provided with the distribution.
16  * 3. The name of the author may not be used to endorse or promote
17  *    products derived from this software without specific prior written
18  *    permission.
19  * THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS
20  * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
21  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE
23  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
24  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
25  * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
26  * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
27  * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
28  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
29  * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
30  * DAMAGE.  */
31 
32 /* Partially inspired by FreeBSD's sys/dev/pcm/ac97.c. It came with
33    the following copyright */
34 
35 /*
36  * Copyright (c) 1999 Cameron Grant <gandalf@vilnya.demon.co.uk>
37  * All rights reserved.
38  *
39  * Redistribution and use in source and binary forms, with or without
40  * modification, are permitted provided that the following conditions
41  * are met:
42  * 1. Redistributions of source code must retain the above copyright
43  *    notice, this list of conditions and the following disclaimer.
44  * 2. Redistributions in binary form must reproduce the above copyright
45  *    notice, this list of conditions and the following disclaimer in the
46  *    documentation and/or other materials provided with the distribution.
47  *
48  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
49  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
50  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
51  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
52  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
53  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
54  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
55  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
56  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
57  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
58  * SUCH DAMAGE.
59  *
60  * $FreeBSD$
61  */
62 
63 #include <sys/param.h>
64 #include <sys/systm.h>
65 #include <sys/kernel.h>
66 #include <sys/malloc.h>
67 #include <sys/device.h>
68 
69 #include <sys/audioio.h>
70 #include <dev/audio_if.h>
71 #include <dev/ic/ac97.h>
72 
73 const struct audio_mixer_enum ac97_on_off = {
74 	2,
75 	{ { { AudioNoff } , 0 },
76 	{ { AudioNon }  , 1 } }
77 };
78 
79 const struct audio_mixer_enum ac97_mic_select = {
80 	2,
81 	{ { { AudioNmicrophone "0" }, 0 },
82 	{ { AudioNmicrophone "1" }, 1 } }
83 };
84 
85 const struct audio_mixer_enum ac97_mono_select = {
86 	2,
87 	{ { { AudioNmixerout }, 0 },
88 	{ { AudioNmicrophone }, 1 } }
89 };
90 
91 const struct audio_mixer_enum ac97_source = {
92 	8,
93 	{ { { AudioNmicrophone } , 0 },
94 	{ { AudioNcd }, 1 },
95 	{ { "video" }, 2 },
96 	{ { AudioNaux }, 3 },
97 	{ { AudioNline }, 4 },
98 	{ { AudioNmixerout }, 5 },
99 	{ { AudioNmixerout AudioNmono }, 6 },
100 	{ { "phone" }, 7 }}
101 };
102 
103 /*
104  * Due to different values for each source that uses these structures,
105  * the ac97_query_devinfo function sets delta in mixer_devinfo_t using
106  * ac97_source_info.bits.
107  */
108 const struct audio_mixer_value ac97_volume_stereo = {
109 	{ AudioNvolume },
110 	2
111 };
112 
113 const struct audio_mixer_value ac97_volume_mono = {
114 	{ AudioNvolume },
115 	1
116 };
117 
118 #define WRAP(a)  &a, sizeof(a)
119 
120 const struct ac97_source_info {
121 	char *class;
122 	char *device;
123 	char *qualifier;
124 	int  type;
125 
126 	const void *info;
127 	int16_t info_size;
128 
129 	u_int8_t  reg;
130 	u_int8_t  bits:3;
131 	u_int8_t  ofs:4;
132 	u_int8_t  mute:1;
133 	u_int8_t  polarity:1;		/* Does 0 == MAX or MIN */
134 	u_int16_t default_value;
135 
136 	int16_t  prev;
137 	int16_t  next;
138 	int16_t  mixer_class;
139 } source_info[] = {
140 	{
141 		AudioCinputs,	NULL,		NULL,	AUDIO_MIXER_CLASS,
142 	}, {
143 		AudioCoutputs,	NULL,		NULL,	AUDIO_MIXER_CLASS,
144 	}, {
145 		AudioCrecord,	NULL,		NULL,	AUDIO_MIXER_CLASS,
146 	}, {
147 		/* Stereo master volume*/
148 		AudioCoutputs,	AudioNmaster,	NULL,	AUDIO_MIXER_VALUE,
149 		WRAP(ac97_volume_stereo),
150 		AC97_REG_MASTER_VOLUME, 5, 0, 1, 0, 0x8000
151 	}, {
152 		/* Mono volume */
153 		AudioCoutputs,	AudioNmono,	NULL,	AUDIO_MIXER_VALUE,
154 		WRAP(ac97_volume_mono),
155 		AC97_REG_MASTER_VOLUME_MONO, 6, 0, 1, 0, 0x8000
156 	}, {
157 		AudioCoutputs,	AudioNmono, AudioNsource, AUDIO_MIXER_ENUM,
158 		WRAP(ac97_mono_select),
159 		AC97_REG_GP, 1, 9, 0, 0, 0x0000
160 	}, {
161 		/* Headphone volume */
162 		AudioCoutputs,	AudioNheadphone, NULL,	AUDIO_MIXER_VALUE,
163 		WRAP(ac97_volume_stereo),
164 		AC97_REG_HEADPHONE_VOLUME, 6, 0, 1, 0, 0x8000
165 	}, {
166 		/* Tone */
167 		AudioCoutputs,	"tone",		NULL,	AUDIO_MIXER_VALUE,
168 		WRAP(ac97_volume_stereo),
169 		AC97_REG_MASTER_TONE, 4, 0, 0, 0, 0x0f0f
170 	}, {
171 		/* PC Beep Volume */
172 		AudioCinputs,	AudioNspeaker,	NULL,	AUDIO_MIXER_VALUE,
173 		WRAP(ac97_volume_mono),
174 		AC97_REG_PCBEEP_VOLUME, 4, 1, 1, 0x0000
175 	}, {
176 		/* Phone */
177 		AudioCinputs,	"phone",	NULL,	AUDIO_MIXER_VALUE,
178 		WRAP(ac97_volume_mono),
179 		AC97_REG_PHONE_VOLUME, 5, 0, 1, 0, 0x8008
180 	}, {
181 		/* Mic Volume */
182 		AudioCinputs,	AudioNmicrophone, NULL,	AUDIO_MIXER_VALUE,
183 		WRAP(ac97_volume_mono),
184 		AC97_REG_MIC_VOLUME, 5, 0, 1, 0, 0x8008
185 	}, {
186 		AudioCinputs,	AudioNmicrophone, AudioNpreamp, AUDIO_MIXER_ENUM,
187 		WRAP(ac97_on_off),
188 		AC97_REG_MIC_VOLUME, 1, 6, 0, 0, 0x8008
189 	}, {
190 		AudioCinputs,	AudioNmicrophone, AudioNsource, AUDIO_MIXER_ENUM,
191 		WRAP(ac97_mic_select),
192 		AC97_REG_GP, 1, 8, 0, 0x0000
193 	}, {
194 		/* Line in Volume */
195 		AudioCinputs,	AudioNline,	NULL,	AUDIO_MIXER_VALUE,
196 		WRAP(ac97_volume_stereo),
197 		AC97_REG_LINEIN_VOLUME, 5, 0, 1, 0, 0x8808
198 	}, {
199 		/* CD Volume */
200 		AudioCinputs,	AudioNcd,	NULL,	AUDIO_MIXER_VALUE,
201 		WRAP(ac97_volume_stereo),
202 		AC97_REG_CD_VOLUME, 5, 0, 1, 0, 0x8808
203 	}, {
204 		/* Video Volume */
205 		AudioCinputs,	"video",	NULL,	AUDIO_MIXER_VALUE,
206 		WRAP(ac97_volume_stereo),
207 		AC97_REG_VIDEO_VOLUME, 5, 0, 1, 0, 0x8808
208 	}, {
209 		/* AUX volume */
210 		AudioCinputs,	AudioNaux,	NULL,	AUDIO_MIXER_VALUE,
211 		WRAP(ac97_volume_stereo),
212 		AC97_REG_AUX_VOLUME, 5, 0, 1, 0, 0x8808
213 	}, {
214 		/* PCM out volume */
215 		AudioCinputs,	AudioNdac,	NULL,	AUDIO_MIXER_VALUE,
216 		WRAP(ac97_volume_stereo),
217 		AC97_REG_PCMOUT_VOLUME, 5, 0, 1, 0, 0x8808
218 	}, {
219 		/* Record Source - some logic for this is hard coded - see below */
220 		AudioCrecord,	AudioNsource,	NULL,	AUDIO_MIXER_ENUM,
221 		WRAP(ac97_source),
222 		AC97_REG_RECORD_SELECT, 3, 0, 0, 0, 0x0000
223 	}, {
224 		/* Record Gain */
225 		AudioCrecord,	AudioNvolume,	NULL,	AUDIO_MIXER_VALUE,
226 		WRAP(ac97_volume_stereo),
227 		AC97_REG_RECORD_GAIN, 4, 0, 1, 0, 0x8000
228 	}, {
229 		/* Record Gain mic */
230 		AudioCrecord,	AudioNmicrophone, NULL,	AUDIO_MIXER_VALUE,
231 		WRAP(ac97_volume_mono),
232 		AC97_REG_RECORD_GAIN_MIC, 4, 0, 1, 1, 0x8000
233 	}, {
234 		/* */
235 		AudioCoutputs,	AudioNloudness,	NULL,	AUDIO_MIXER_ENUM,
236 		WRAP(ac97_on_off),
237 		AC97_REG_GP, 1, 12, 0, 0, 0x0000
238 	}, {
239 		AudioCoutputs,	AudioNspatial,	NULL,	AUDIO_MIXER_ENUM,
240 		WRAP(ac97_on_off),
241 		AC97_REG_GP, 1, 13, 0, 0, 0x0000
242 	}, {
243 		AudioCoutputs,	AudioNspatial,	"center", AUDIO_MIXER_VALUE,
244 		WRAP(ac97_volume_mono),
245 		AC97_REG_3D_CONTROL, 4, 8, 0, 1, 0x0000
246 	}, {
247 		AudioCoutputs,	AudioNspatial,	"depth", AUDIO_MIXER_VALUE,
248 		WRAP(ac97_volume_mono),
249 		AC97_REG_3D_CONTROL, 4, 0, 0, 1, 0x0000
250 	}, {
251 		/* Surround volume */
252 		AudioCoutputs,	"surround",	NULL,	AUDIO_MIXER_VALUE,
253 		WRAP(ac97_volume_stereo),
254 		AC97_REG_SURROUND_VOLUME, 6, 0, 1, 0, 0x8080
255 	}, {
256 		/* Center volume */
257 		AudioCoutputs,	"center",	NULL,	AUDIO_MIXER_VALUE,
258 		WRAP(ac97_volume_mono),
259 		AC97_REG_CENTER_LFE_VOLUME, 6, 0, 1, 0, 0x8080
260 	}, {
261 		/* LFE volume */
262 		AudioCoutputs,	"lfe",		NULL,	AUDIO_MIXER_VALUE,
263 		WRAP(ac97_volume_mono),
264 		AC97_REG_CENTER_LFE_VOLUME, 6, 8, 1, 0, 0x8080
265 	}
266 
267 	/* Missing features: Simulated Stereo, POP, Loopback mode */
268 } ;
269 
270 #define SOURCE_INFO_SIZE (sizeof(source_info)/sizeof(source_info[0]))
271 
272 /*
273  * Check out http://developer.intel.com/pc-supp/platform/ac97/ for
274  * information on AC-97
275  */
276 
277 struct ac97_softc {
278 	struct ac97_codec_if codec_if;
279 	struct ac97_host_if *host_if;
280 	struct ac97_source_info source_info[2 * SOURCE_INFO_SIZE];
281 	int num_source_info;
282 	enum ac97_host_flags host_flags;
283 	u_int16_t shadow_reg[128];
284 };
285 
286 int ac97_mixer_get_port __P((struct ac97_codec_if *self, mixer_ctrl_t *cp));
287 int ac97_mixer_set_port __P((struct ac97_codec_if *self, mixer_ctrl_t *));
288 int ac97_query_devinfo __P((struct ac97_codec_if *self, mixer_devinfo_t *));
289 int ac97_get_portnum_by_name __P((struct ac97_codec_if *, char *, char *,
290 				  char *));
291 void ac97_restore_shadow __P((struct ac97_codec_if *self));
292 
293 struct ac97_codec_if_vtbl ac97civ = {
294 	ac97_mixer_get_port,
295 	ac97_mixer_set_port,
296 	ac97_query_devinfo,
297 	ac97_get_portnum_by_name,
298 	ac97_restore_shadow
299 };
300 
301 const struct ac97_codecid {
302 	u_int8_t id;
303 	u_int8_t mask;
304 	u_int8_t rev;
305 	u_int8_t shift;	/* no use yet */
306 	char * const name;
307 }  ac97_ad[] = {
308 	{ 0x40, 0xff, 0, 0,	"AD1881" },
309 	{ 0x60, 0xff, 0, 0,	"AD1885" },
310 }, ac97_ak[] = {
311 	{ 0x00,	0xfe, 1, 0,	"AK4540" },
312 	{ 0x01,	0xfe, 1, 0,	"AK4540" },
313 	{ 0x02,	0xff, 0, 0,	"AK4543" },
314 }, ac97_av[] = {
315 	{ 0x10, 0xff, 0, 0,	"ALC200" },
316 }, ac97_cs[] = {
317 	{ 0x00,	0xf8, 7, 0,	"CS4297" },
318 	{ 0x10,	0xf8, 7, 0,	"CS4297A" },
319 	{ 0x20,	0xf8, 7, 0,	"CS4298" },
320 	{ 0x28,	0xf8, 7, 0,	"CS4294" },
321 	{ 0x30,	0xf8, 7, 0,	"CS4299" },
322 }, ac97_ns[] = {
323 	{ 0x31,	0xff, 0, 0,	"LM4549" },
324 	{ 0x00, 0x00 }
325 }, ac97_sl[] = {
326 	{ 0x22,	0xff, 0, 0,	"Si3036" },
327 	{ 0x23,	0xff, 0, 0,	"Si3038" },
328 }, ac97_st[] = {
329 	{ 0x00,	0xff, 0, 0,	"STAC9700" },
330 	{ 0x04,	0xff, 0, 0,	"STAC970[135]" },
331 	{ 0x05,	0xff, 0, 0,	"STAC9704" },
332 	{ 0x08,	0xff, 0, 0,	"STAC9708" },
333 	{ 0x09,	0xff, 0, 0,	"STAC9721/23" },
334 	{ 0x44,	0xff, 0, 0,	"STAC9744/45" },
335 	{ 0x56,	0xff, 0, 0,	"STAC9756/57" },
336 	{ 0x84,	0xff, 0, 0,	"STAC9784/85" },
337 }, ac97_tt[] = {
338 	{ 0x02,	0xff, 0, 0,	"TR28022" },
339 	{ 0x03,	0xff, 0, 0,	"TR28023" },
340 	{ 0x08,	0xff, 0, 0,	"TR28028" },
341 	{ 0x23,	0xff, 0, 0,	"unknown" },
342 }, ac97_wo[] = {
343 	{ 0x00,	0xff, 0, 0,	"WM9701A" },
344 	{ 0x03,	0xff, 0, 0,	"WM9704M/Q-0" },	/* also WM9703 */
345 	{ 0x04,	0xff, 0, 0,	"WM9704M/Q-1" },
346 };
347 
348 #define	cl(n)	n, sizeof(n)/sizeof(n[0])
349 const struct ac97_vendorid {
350 	u_int32_t id;
351 	char * const name;
352 	const struct ac97_codecid * const codecs;
353 	u_int8_t num;
354 } ac97_vendors[] = {
355 	{ 0x41445300, "Analog Devices",		cl(ac97_ad) },
356 	{ 0x414B4D00, "Asahi Kasei",		cl(ac97_ak) },
357 	{ 0x414c4700, "Avance",			cl(ac97_av) },
358 	{ 0x43525900, "Cirrus Logic",		cl(ac97_cs) },
359 	{ 0x4e534300, "National Semiconductor", cl(ac97_ns) },
360 	{ 0x53494c00, "Silicon Laboratory",	cl(ac97_sl) },
361 	{ 0x54524100, "TriTech Microelectronics", cl(ac97_tt) },
362 	{ 0x574d4c00, "Wolfson",		cl(ac97_wo) },
363 	{ 0x83847600, "SigmaTel",		cl(ac97_st) },
364 };
365 
366 const char * const ac97enhancement[] = {
367 	"No 3D Stereo",
368 	"Analog Devices Phat Stereo",
369 	"Creative",
370 	"National Semi 3D",
371 	"Yamaha Ymersion",
372 	"BBE 3D",
373 	"Crystal Semi 3D",
374 	"Qsound QXpander",
375 	"Spatializer 3D",
376 	"SRS 3D",
377 	"Platform Tech 3D",
378 	"AKM 3D",
379 	"Aureal",
380 	"AZTECH 3D",
381 	"Binaura 3D",
382 	"ESS Technology",
383 	"Harman International VMAx",
384 	"Nvidea 3D",
385 	"Philips Incredible Sound",
386 	"Texas Instruments 3D",
387 	"VLSI Technology 3D",
388 	"TriTech 3D",
389 	"Realtek 3D",
390 	"Samsung 3D",
391 	"Wolfson Microelectronics 3D",
392 	"Delta Integration 3D",
393 	"SigmaTel 3D",
394 	"Unknown 3D",
395 	"Rockwell 3D",
396 	"Unknown 3D",
397 	"Unknown 3D",
398 	"Unknown 3D"
399 };
400 
401 const char * const ac97feature[] = {
402 	"mic channel",
403 	"reserved",
404 	"tone",
405 	"simulated stereo",
406 	"headphone",
407 	"bass boost",
408 	"18 bit DAC",
409 	"20 bit DAC",
410 	"18 bit ADC",
411 	"20 bit ADC"
412 };
413 
414 
415 int ac97_str_equal __P((const char *, const char *));
416 void ac97_setup_source_info __P((struct ac97_softc *));
417 void ac97_setup_defaults __P((struct ac97_softc *));
418 int ac97_read __P((struct ac97_softc *, u_int8_t, u_int16_t *));
419 int ac97_write __P((struct ac97_softc *, u_int8_t, u_int16_t));
420 
421 #define AC97_DEBUG 10
422 
423 #ifdef AUDIO_DEBUG
424 #define DPRINTF(x)	if (ac97debug) printf x
425 #define DPRINTFN(n,x)	if (ac97debug>(n)) printf x
426 #ifdef AC97_DEBUG
427 int	ac97debug = AC97_DEBUG;
428 #else
429 int	ac97debug = 0;
430 #endif
431 #else
432 #define DPRINTF(x)
433 #define DPRINTFN(n,x)
434 #endif
435 
436 int
437 ac97_read(as, reg, val)
438 	struct ac97_softc *as;
439 	u_int8_t	reg;
440 	u_int16_t	*val;
441 {
442 	int error;
443 
444 	if (((as->host_flags & AC97_HOST_DONT_READ) &&
445 	    (reg != AC97_REG_VENDOR_ID1 && reg != AC97_REG_VENDOR_ID2 &&
446 	    reg != AC97_REG_RESET)) ||
447 	    (as->host_flags & AC97_HOST_DONT_READANY)) {
448 		*val = as->shadow_reg[reg >> 1];
449 		return (0);
450 	}
451 
452 	if ((error = as->host_if->read(as->host_if->arg, reg, val)))
453 		*val = as->shadow_reg[reg >> 1];
454 	return (error);
455 }
456 
457 int
458 ac97_write(as, reg, val)
459 	struct ac97_softc *as;
460 	u_int8_t	reg;
461 	u_int16_t	val;
462 {
463 	as->shadow_reg[reg >> 1] = val;
464 	return (as->host_if->write(as->host_if->arg, reg, val));
465 }
466 
467 void
468 ac97_setup_defaults(as)
469 	struct ac97_softc *as;
470 {
471 	int idx;
472 
473 	bzero(as->shadow_reg, sizeof(as->shadow_reg));
474 
475 	for (idx = 0; idx < SOURCE_INFO_SIZE; idx++) {
476 		const struct ac97_source_info *si = &source_info[idx];
477 
478 		ac97_write(as, si->reg, si->default_value);
479 	}
480 }
481 
482 void
483 ac97_restore_shadow(self)
484 	struct ac97_codec_if *self;
485 {
486 	struct ac97_softc *as = (struct ac97_softc *)self;
487 	int idx;
488 
489 	for (idx = 0; idx < SOURCE_INFO_SIZE; idx++) {
490 		const struct ac97_source_info *si = &source_info[idx];
491 
492 		ac97_write(as, si->reg, as->shadow_reg[si->reg >> 1]);
493 	}
494 }
495 
496 int
497 ac97_str_equal(a, b)
498 	const char *a, *b;
499 {
500 	return ((a == b) || (a && b && (!strcmp(a, b))));
501 }
502 
503 void
504 ac97_setup_source_info(as)
505 	struct ac97_softc *as;
506 {
507 	struct ac97_source_info *si, *si2;
508 	int idx, ouridx;
509 
510 	for (idx = 0, ouridx = 0; idx < SOURCE_INFO_SIZE; idx++) {
511 		si = &as->source_info[ouridx];
512 
513 		bcopy(&source_info[idx], si, sizeof(*si));
514 
515 		switch (si->type) {
516 		case AUDIO_MIXER_CLASS:
517 			si->mixer_class = ouridx;
518 			ouridx++;
519 			break;
520 		case AUDIO_MIXER_VALUE:
521 			/* Todo - Test to see if it works */
522 			ouridx++;
523 
524 			/* Add an entry for mute, if necessary */
525 			if (si->mute) {
526 				si = &as->source_info[ouridx];
527 				bcopy(&source_info[idx], si, sizeof(*si));
528 				si->qualifier = AudioNmute;
529 				si->type = AUDIO_MIXER_ENUM;
530 				si->info = &ac97_on_off;
531 				si->info_size = sizeof(ac97_on_off);
532 				si->bits = 1;
533 				si->ofs = 15;
534 				si->mute = 0;
535 				si->polarity = 0;
536 				ouridx++;
537 			}
538 			break;
539 		case AUDIO_MIXER_ENUM:
540 			/* Todo - Test to see if it works */
541 			ouridx++;
542 			break;
543 		default:
544 			printf ("ac97: shouldn't get here\n");
545 			break;
546 		}
547 	}
548 
549 	as->num_source_info = ouridx;
550 
551 	for (idx = 0; idx < as->num_source_info; idx++) {
552 		int idx2, previdx;
553 
554 		si = &as->source_info[idx];
555 
556 		/* Find mixer class */
557 		for (idx2 = 0; idx2 < as->num_source_info; idx2++) {
558 			si2 = &as->source_info[idx2];
559 
560 			if (si2->type == AUDIO_MIXER_CLASS &&
561 			    ac97_str_equal(si->class, si2->class)) {
562 				si->mixer_class = idx2;
563 			}
564 		}
565 
566 
567 		/* Setup prev and next pointers */
568 		if (si->prev != 0 || si->qualifier)
569 			continue;
570 
571 		si->prev = AUDIO_MIXER_LAST;
572 		previdx = idx;
573 
574 		for (idx2 = 0; idx2 < as->num_source_info; idx2++) {
575 			if (idx2 == idx)
576 				continue;
577 
578 			si2 = &as->source_info[idx2];
579 
580 			if (!si2->prev &&
581 			    ac97_str_equal(si->class, si2->class) &&
582 			    ac97_str_equal(si->device, si2->device)) {
583 				as->source_info[previdx].next = idx2;
584 				as->source_info[idx2].prev = previdx;
585 
586 				previdx = idx2;
587 			}
588 		}
589 
590 		as->source_info[previdx].next = AUDIO_MIXER_LAST;
591 	}
592 }
593 
594 int
595 ac97_attach(host_if)
596 	struct ac97_host_if *host_if;
597 {
598 	struct ac97_softc *as;
599 	u_int16_t id1, id2, caps;
600 	u_int32_t id;
601 	mixer_ctrl_t ctl;
602 	int error, i;
603 
604 	if (!(as = malloc(sizeof(struct ac97_softc), M_DEVBUF, M_NOWAIT)))
605 		return (ENOMEM);
606 
607 	bzero(as, sizeof(*as));
608 
609 	as->codec_if.vtbl = &ac97civ;
610 	as->host_if = host_if;
611 
612 	if ((error = host_if->attach(host_if->arg, &as->codec_if))) {
613 		free(as, M_DEVBUF);
614 		return (error);
615 	}
616 
617 	host_if->reset(host_if->arg);
618 	DELAY(1000);
619 
620 	host_if->write(host_if->arg, AC97_REG_POWER, 0);
621 	host_if->write(host_if->arg, AC97_REG_RESET, 0);
622 	DELAY(10000);
623 
624 	if (host_if->flags)
625 		as->host_flags = host_if->flags(host_if->arg);
626 
627 	ac97_setup_defaults(as);
628 	ac97_read(as, AC97_REG_VENDOR_ID1, &id1);
629 	ac97_read(as, AC97_REG_VENDOR_ID2, &id2);
630 	ac97_read(as, AC97_REG_RESET, &caps);
631 
632 	id = (id1 << 16) | id2;
633 	if (id) {
634 		register const struct ac97_vendorid *vendor;
635 		register const struct ac97_codecid *codec;
636 
637 		printf("ac97: codec id 0x%08x", id);
638 		for (vendor = &ac97_vendors[sizeof(ac97_vendors) /
639 		     sizeof(ac97_vendors[0]) - 1];
640 		     vendor >= ac97_vendors; vendor--) {
641 			if (vendor->id == (id & AC97_VENDOR_ID_MASK)) {
642 				printf(" (%s", vendor->name);
643 				for (codec = &vendor->codecs[vendor->num-1];
644 				     codec >= vendor->codecs; codec--) {
645 					if (codec->id == (id & codec->mask))
646 						break;
647 				}
648 				if (codec->mask)
649 					printf(" %s", codec->name);
650 				else
651 					printf(" <%2x>", id & codec->mask);
652 				if (codec->rev)
653 					printf(" rev %d", id & codec->rev);
654 				printf(")");
655 				break;
656 			}
657 		}
658 		printf("\n");
659 	} else
660 		printf("ac97: codec id not read\n");
661 
662 	if (caps) {
663 		printf("ac97: codec features ");
664 		for (i = 0; i < 10; i++) {
665 			if (caps & (1 << i))
666 				printf("%s, ", ac97feature[i]);
667 		}
668 		printf("%s\n", ac97enhancement[AC97_SOUND_ENHANCEMENT(caps)]);
669 	}
670 
671 	ac97_read(as, AC97_REG_EXT_AUDIO_ID, &caps);
672 	if (caps)
673 		DPRINTF(("ac97: ext id %b\n", caps, AC97_EXT_AUDIO_BITS));
674 	if (caps & AC97_EXT_AUDIO_VRA)
675 		ac97_write(as, AC97_REG_EXT_AUDIO_CTRL,
676 		    AC97_EXT_AUDIO_VRA | AC97_EXT_AUDIO_VRM);
677 
678 	ac97_setup_source_info(as);
679 
680 	/* Just enable the DAC and master volumes by default */
681 	bzero(&ctl, sizeof(ctl));
682 
683 	ctl.type = AUDIO_MIXER_ENUM;
684 	ctl.un.ord = 0;  /* off */
685 	ctl.dev = ac97_get_portnum_by_name(&as->codec_if, AudioCoutputs,
686 	    AudioNmaster, AudioNmute);
687 	ac97_mixer_set_port(&as->codec_if, &ctl);
688 
689 	ctl.dev = ac97_get_portnum_by_name(&as->codec_if, AudioCinputs,
690 	    AudioNdac, AudioNmute);
691 	ac97_mixer_set_port(&as->codec_if, &ctl);
692 
693 	ctl.dev = ac97_get_portnum_by_name(&as->codec_if, AudioCrecord,
694 	    AudioNvolume, AudioNmute);
695 	ac97_mixer_set_port(&as->codec_if, &ctl);
696 
697 	ctl.type = AUDIO_MIXER_ENUM;
698 	ctl.un.ord = 0;
699 	ctl.dev = ac97_get_portnum_by_name(&as->codec_if, AudioCrecord,
700 	    AudioNsource, NULL);
701 	ac97_mixer_set_port(&as->codec_if, &ctl);
702 
703 	return (0);
704 }
705 
706 int
707 ac97_query_devinfo(codec_if, dip)
708 	struct ac97_codec_if *codec_if;
709 	mixer_devinfo_t *dip;
710 {
711 	struct ac97_softc *as = (struct ac97_softc *)codec_if;
712 
713 	if (dip->index < as->num_source_info) {
714 		struct ac97_source_info *si = &as->source_info[dip->index];
715 		const char *name;
716 
717 		dip->type = si->type;
718 		dip->mixer_class = si->mixer_class;
719 		dip->prev = si->prev;
720 		dip->next = si->next;
721 
722 		if (si->qualifier)
723 			name = si->qualifier;
724 		else if (si->device)
725 			name = si->device;
726 		else if (si->class)
727 			name = si->class;
728 
729 		if (name)
730 			strcpy(dip->label.name, name);
731 
732 		bcopy(si->info, &dip->un, si->info_size);
733 
734 		/* Set the delta for volume sources */
735 		if (dip->type == AUDIO_MIXER_VALUE)
736 			dip->un.v.delta = 1 << (8 - si->bits);
737 
738 		return (0);
739 	}
740 
741 	return (ENXIO);
742 }
743 
744 int
745 ac97_mixer_set_port(codec_if, cp)
746 	struct ac97_codec_if *codec_if;
747 	mixer_ctrl_t *cp;
748 {
749 	struct ac97_softc *as = (struct ac97_softc *)codec_if;
750 	struct ac97_source_info *si = &as->source_info[cp->dev];
751 	u_int16_t mask;
752 	u_int16_t val, newval;
753 	int error;
754 
755 	if (cp->dev < 0 || cp->dev >= as->num_source_info ||
756 	    cp->type != si->type)
757 		return (EINVAL);
758 
759 	ac97_read(as, si->reg, &val);
760 
761 	DPRINTFN(5, ("read(%x) = %x\n", si->reg, val));
762 
763 	mask = (1 << si->bits) - 1;
764 
765 	switch (cp->type) {
766 	case AUDIO_MIXER_ENUM:
767 		if (cp->un.ord > mask || cp->un.ord < 0)
768 			return (EINVAL);
769 
770 		newval = (cp->un.ord << si->ofs);
771 		if (si->reg == AC97_REG_RECORD_SELECT) {
772 			newval |= (newval << (8 + si->ofs));
773 			mask |= (mask << 8);
774 		}
775 		break;
776 	case AUDIO_MIXER_VALUE:
777 	{
778 		const struct audio_mixer_value *value = si->info;
779 		u_int16_t  l, r;
780 
781 		if (cp->un.value.num_channels <= 0 ||
782 		    cp->un.value.num_channels > value->num_channels)
783 			return (EINVAL);
784 
785 		if (cp->un.value.num_channels == 1) {
786 			l = r = cp->un.value.level[AUDIO_MIXER_LEVEL_MONO];
787 		} else {
788 			l = cp->un.value.level[AUDIO_MIXER_LEVEL_LEFT];
789 			r = cp->un.value.level[AUDIO_MIXER_LEVEL_RIGHT];
790 		}
791 
792 		if (!si->polarity) {
793 			l = 255 - l;
794 			r = 255 - r;
795 		}
796 
797 		l >>= 8 - si->bits;
798 		r >>= 8 - si->bits;
799 
800 		newval = ((l & mask) << si->ofs);
801 		if (value->num_channels == 2) {
802 			newval |= ((r & mask) << (si->ofs + 8));
803 			mask |= (mask << 8);
804 		}
805 
806 		break;
807 	}
808 	default:
809 		return (EINVAL);
810 	}
811 
812 	mask = mask << si->ofs;
813 	error = ac97_write(as, si->reg, (val & ~mask) | newval);
814 	if (error)
815 		return (error);
816 
817 	return (0);
818 }
819 
820 int
821 ac97_get_portnum_by_name(codec_if, class, device, qualifier)
822 	struct ac97_codec_if *codec_if;
823 	char *class, *device, *qualifier;
824 {
825 	struct ac97_softc *as = (struct ac97_softc *)codec_if;
826 	int idx;
827 
828 	for (idx = 0; idx < as->num_source_info; idx++) {
829 		struct ac97_source_info *si = &as->source_info[idx];
830 		if (ac97_str_equal(class, si->class) &&
831 		    ac97_str_equal(device, si->device) &&
832 		    ac97_str_equal(qualifier, si->qualifier))
833 			return (idx);
834 	}
835 
836 	return (-1);
837 }
838 
839 int
840 ac97_mixer_get_port(codec_if, cp)
841 	struct ac97_codec_if *codec_if;
842 	mixer_ctrl_t *cp;
843 {
844 	struct ac97_softc *as = (struct ac97_softc *)codec_if;
845 	struct ac97_source_info *si = &as->source_info[cp->dev];
846 	u_int16_t mask;
847 	u_int16_t val;
848 
849 	if (cp->dev < 0 || cp->dev >= as->num_source_info ||
850 	    cp->type != si->type)
851 		return (EINVAL);
852 
853 	ac97_read(as, si->reg, &val);
854 
855 	DPRINTFN(5, ("read(%x) = %x\n", si->reg, val));
856 
857 	mask = (1 << si->bits) - 1;
858 
859 	switch (cp->type) {
860 	case AUDIO_MIXER_ENUM:
861 		cp->un.ord = (val >> si->ofs) & mask;
862 		DPRINTFN(4, ("AUDIO_MIXER_ENUM: %x %d %x %d\n", val, si->ofs,
863 		    mask, cp->un.ord));
864 		break;
865 	case AUDIO_MIXER_VALUE:
866 	{
867 		const struct audio_mixer_value *value = si->info;
868 		u_int16_t  l, r;
869 
870 		if ((cp->un.value.num_channels <= 0) ||
871 		    (cp->un.value.num_channels > value->num_channels))
872 			return (EINVAL);
873 
874 		l = r = (val >> si->ofs) & mask;
875 		if (value->num_channels > 1)
876 			r = (val >> (si->ofs + 8)) & mask;
877 
878 		l <<= 8 - si->bits;
879 		r <<= 8 - si->bits;
880 		if (!si->polarity) {
881 			l = 255 - l;
882 			r = 255 - r;
883 		}
884 
885 		/*
886 		 * The EAP driver averages l and r for stereo
887 		 * channels that are requested in MONO mode. Does this
888 		 * make sense?
889 		 */
890 		if (cp->un.value.num_channels == 1) {
891 			cp->un.value.level[AUDIO_MIXER_LEVEL_MONO] = l;
892 		} else if (cp->un.value.num_channels == 2) {
893 			cp->un.value.level[AUDIO_MIXER_LEVEL_LEFT] = l;
894 			cp->un.value.level[AUDIO_MIXER_LEVEL_RIGHT] = r;
895 		}
896 
897 		break;
898 	}
899 	default:
900 		return (EINVAL);
901 	}
902 
903 	return (0);
904 }
905 
906 int
907 ac97_set_rate(codec_if, p, mode)
908 	struct ac97_codec_if *codec_if;
909 	struct audio_params *p;
910 	int mode;
911 {
912 	struct ac97_softc *as = (struct ac97_softc *)codec_if;
913 	u_int16_t reg, val, regval, id = 0;
914 
915 	DPRINTFN(5, ("set_rate(%lu) ", p->sample_rate));
916 
917 	if (p->sample_rate > 0xffff) {
918 		if (mode != AUMODE_PLAY)
919 			return (EINVAL);
920 		if (ac97_read(as, AC97_REG_EXT_AUDIO_ID, &id))
921 			return (EIO);
922 		if (!(id & AC97_EXT_AUDIO_DRA))
923 			return (EINVAL);
924 		if (ac97_read(as, AC97_REG_EXT_AUDIO_CTRL, &id))
925 			return (EIO);
926 		id |= AC97_EXT_AUDIO_DRA;
927 		if (ac97_write(as, AC97_REG_EXT_AUDIO_CTRL, id))
928 			return (EIO);
929 		p->sample_rate /= 2;
930 	}
931 
932 	/* i guess it's better w/o clicks and squeecks when changing the rate */
933 	if (ac97_read(as, AC97_REG_POWER, &val) ||
934 	    ac97_write(as, AC97_REG_POWER, val |
935 	      (mode == AUMODE_PLAY? AC97_POWER_OUT : AC97_POWER_IN)))
936 		return (EIO);
937 
938 	reg = mode == AUMODE_PLAY ?
939 	    AC97_REG_FRONT_DAC_RATE : AC97_REG_PCM_ADC_RATE;
940 
941 	if (ac97_write(as, reg, (u_int16_t) p->sample_rate) ||
942 	    ac97_read(as, reg, &regval))
943 		return (EIO);
944 	p->sample_rate = regval;
945 	if (id & AC97_EXT_AUDIO_DRA)
946 		p->sample_rate *= 2;
947 
948 	DPRINTFN(5, (" %lu\n", regval));
949 
950 	if (ac97_write(as, AC97_REG_POWER, val))
951 		return (EIO);
952 
953 	return (0);
954 }
955