xref: /openbsd/sys/dev/ic/ac97.c (revision d485f761)
1 /*	$OpenBSD: ac97.c,v 1.25 2001/10/28 18:58:12 mickey 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 		AudioCoutputs,	AudioNbass,	NULL,	AUDIO_MIXER_VALUE,
167 		WRAP(ac97_volume_mono),
168 		AC97_REG_MASTER_TONE, 4, 8, 0, 0, 0x0f0f
169 	}, {
170 		AudioCoutputs,	AudioNtreble,	NULL,	AUDIO_MIXER_VALUE,
171 		WRAP(ac97_volume_mono),
172 		AC97_REG_MASTER_TONE, 4, 0, 0, 0, 0x0f0f
173 	}, {
174 		/* PC Beep Volume */
175 		AudioCinputs,	AudioNspeaker,	NULL,	AUDIO_MIXER_VALUE,
176 		WRAP(ac97_volume_mono),
177 		AC97_REG_PCBEEP_VOLUME, 4, 1, 1, 0, 0x0000
178 	}, {
179 		/* Phone */
180 		AudioCinputs,	"phone",	NULL,	AUDIO_MIXER_VALUE,
181 		WRAP(ac97_volume_mono),
182 		AC97_REG_PHONE_VOLUME, 5, 0, 1, 0, 0x8008
183 	}, {
184 		/* Mic Volume */
185 		AudioCinputs,	AudioNmicrophone, NULL,	AUDIO_MIXER_VALUE,
186 		WRAP(ac97_volume_mono),
187 		AC97_REG_MIC_VOLUME, 5, 0, 1, 0, 0x8008
188 	}, {
189 		AudioCinputs,	AudioNmicrophone, AudioNpreamp, AUDIO_MIXER_ENUM,
190 		WRAP(ac97_on_off),
191 		AC97_REG_MIC_VOLUME, 1, 6, 0, 0, 0x8008
192 	}, {
193 		AudioCinputs,	AudioNmicrophone, AudioNsource, AUDIO_MIXER_ENUM,
194 		WRAP(ac97_mic_select),
195 		AC97_REG_GP, 1, 8, 0, 0x0000
196 	}, {
197 		/* Line in Volume */
198 		AudioCinputs,	AudioNline,	NULL,	AUDIO_MIXER_VALUE,
199 		WRAP(ac97_volume_stereo),
200 		AC97_REG_LINEIN_VOLUME, 5, 0, 1, 0, 0x8808
201 	}, {
202 		/* CD Volume */
203 		AudioCinputs,	AudioNcd,	NULL,	AUDIO_MIXER_VALUE,
204 		WRAP(ac97_volume_stereo),
205 		AC97_REG_CD_VOLUME, 5, 0, 1, 0, 0x8808
206 	}, {
207 		/* Video Volume */
208 		AudioCinputs,	"video",	NULL,	AUDIO_MIXER_VALUE,
209 		WRAP(ac97_volume_stereo),
210 		AC97_REG_VIDEO_VOLUME, 5, 0, 1, 0, 0x8808
211 	}, {
212 		/* AUX volume */
213 		AudioCinputs,	AudioNaux,	NULL,	AUDIO_MIXER_VALUE,
214 		WRAP(ac97_volume_stereo),
215 		AC97_REG_AUX_VOLUME, 5, 0, 1, 0, 0x8808
216 	}, {
217 		/* PCM out volume */
218 		AudioCinputs,	AudioNdac,	NULL,	AUDIO_MIXER_VALUE,
219 		WRAP(ac97_volume_stereo),
220 		AC97_REG_PCMOUT_VOLUME, 5, 0, 1, 0, 0x8808
221 	}, {
222 		/* Record Source - some logic for this is hard coded - see below */
223 		AudioCrecord,	AudioNsource,	NULL,	AUDIO_MIXER_ENUM,
224 		WRAP(ac97_source),
225 		AC97_REG_RECORD_SELECT, 3, 0, 0, 0, 0x0000
226 	}, {
227 		/* Record Gain */
228 		AudioCrecord,	AudioNvolume,	NULL,	AUDIO_MIXER_VALUE,
229 		WRAP(ac97_volume_stereo),
230 		AC97_REG_RECORD_GAIN, 4, 0, 1, 0, 0x8000
231 	}, {
232 		/* Record Gain mic */
233 		AudioCrecord,	AudioNmicrophone, NULL,	AUDIO_MIXER_VALUE,
234 		WRAP(ac97_volume_mono),
235 		AC97_REG_RECORD_GAIN_MIC, 4, 0, 1, 1, 0x8000
236 	}, {
237 		/* */
238 		AudioCoutputs,	AudioNloudness,	NULL,	AUDIO_MIXER_ENUM,
239 		WRAP(ac97_on_off),
240 		AC97_REG_GP, 1, 12, 0, 0, 0x0000
241 	}, {
242 		AudioCoutputs,	AudioNspatial,	NULL,	AUDIO_MIXER_ENUM,
243 		WRAP(ac97_on_off),
244 		AC97_REG_GP, 1, 13, 0, 0, 0x0000
245 	}, {
246 		AudioCoutputs,	AudioNspatial,	AudioNcenter,AUDIO_MIXER_VALUE,
247 		WRAP(ac97_volume_mono),
248 		AC97_REG_3D_CONTROL, 4, 8, 0, 1, 0x0000
249 	}, {
250 		AudioCoutputs,	AudioNspatial,	AudioNdepth, AUDIO_MIXER_VALUE,
251 		WRAP(ac97_volume_mono),
252 		AC97_REG_3D_CONTROL, 4, 0, 0, 1, 0x0000
253 	}, {
254 		/* Surround volume */
255 		AudioCoutputs,	AudioNsurround,	NULL,	AUDIO_MIXER_VALUE,
256 		WRAP(ac97_volume_stereo),
257 		AC97_REG_SURROUND_VOLUME, 6, 0, 1, 0, 0x8080
258 	}, {
259 		/* Center volume */
260 		AudioCoutputs,	AudioNcenter,	NULL,	AUDIO_MIXER_VALUE,
261 		WRAP(ac97_volume_mono),
262 		AC97_REG_CENTER_LFE_VOLUME, 6, 0, 1, 0, 0x8080
263 	}, {
264 		/* LFE volume */
265 		AudioCoutputs,	AudioNlfe,	NULL,	AUDIO_MIXER_VALUE,
266 		WRAP(ac97_volume_mono),
267 		AC97_REG_CENTER_LFE_VOLUME, 6, 8, 1, 0, 0x8080
268 	}
269 
270 	/* Missing features: Simulated Stereo, POP, Loopback mode */
271 } ;
272 
273 #define SOURCE_INFO_SIZE (sizeof(source_info)/sizeof(source_info[0]))
274 
275 /*
276  * Check out http://developer.intel.com/pc-supp/platform/ac97/ for
277  * information on AC-97
278  */
279 
280 struct ac97_softc {
281 	struct ac97_codec_if codec_if;
282 	struct ac97_host_if *host_if;
283 	struct ac97_source_info source_info[2 * SOURCE_INFO_SIZE];
284 	int num_source_info;
285 	enum ac97_host_flags host_flags;
286 	u_int16_t caps, ext_id;
287 	u_int16_t shadow_reg[128];
288 };
289 
290 int ac97_mixer_get_port __P((struct ac97_codec_if *self, mixer_ctrl_t *cp));
291 int ac97_mixer_set_port __P((struct ac97_codec_if *self, mixer_ctrl_t *));
292 int ac97_query_devinfo __P((struct ac97_codec_if *self, mixer_devinfo_t *));
293 int ac97_get_portnum_by_name __P((struct ac97_codec_if *, char *, char *,
294 				  char *));
295 void ac97_restore_shadow __P((struct ac97_codec_if *self));
296 
297 struct ac97_codec_if_vtbl ac97civ = {
298 	ac97_mixer_get_port,
299 	ac97_mixer_set_port,
300 	ac97_query_devinfo,
301 	ac97_get_portnum_by_name,
302 	ac97_restore_shadow
303 };
304 
305 const struct ac97_codecid {
306 	u_int8_t id;
307 	u_int8_t mask;
308 	u_int8_t rev;
309 	u_int8_t shift;	/* no use yet */
310 	char * const name;
311 }  ac97_ad[] = {
312 	{ 0x03, 0xff, 0, 0,	"AD1819" },
313 	{ 0x40, 0xff, 0, 0,	"AD1881" },
314 	{ 0x48, 0xff, 0, 0,	"AD1881A" },
315 	{ 0x60, 0xff, 0, 0,	"AD1885" },
316 	{ 0x61, 0xff, 0, 0,	"AD1886" },
317 }, ac97_ak[] = {
318 	{ 0x00,	0xfe, 1, 0,	"AK4540" },
319 	{ 0x01,	0xfe, 1, 0,	"AK4540" },
320 	{ 0x02,	0xff, 0, 0,	"AK4543" },
321 	{ 0x06,	0xff, 0, 0,	"AK4544A" },
322 	{ 0x07,	0xff, 0, 0,	"AK4545" },
323 }, ac97_av[] = {
324 	{ 0x10, 0xff, 0, 0,	"ALC200" },
325 }, ac97_rl[] = {
326 	{ 0x00, 0xff, 0, 0,	"RL5306" },
327 	{ 0x10, 0xff, 0, 0,	"RL5382" },
328 	{ 0x20, 0xff, 0, 0,	"RL5383" },
329 }, ac97_cs[] = {
330 	{ 0x00,	0xf8, 7, 0,	"CS4297" },
331 	{ 0x10,	0xf8, 7, 0,	"CS4297A" },
332 	{ 0x20,	0xf8, 7, 0,	"CS4298" },
333 	{ 0x28,	0xf8, 7, 0,	"CS4294" },
334 	{ 0x30,	0xf8, 7, 0,	"CS4299" },
335 	{ 0x40,	0xf8, 7, 0,	"CS4201" },
336 	{ 0x50,	0xf8, 7, 0,	"CS4205" },
337 	{ 0x60,	0xf8, 7, 0,	"CS4291" },
338 }, ac97_is[] = {
339 	{ 0x00, 0xff, 0, 0,	"HMP9701" },
340 }, ac97_ic[] = {
341 	{ 0x01, 0xff, 0, 0,	"ICE1230" },
342 	{ 0x11, 0xff, 0, 0,	"ICE1232" },
343 }, ac97_ns[] = {
344 	{ 0x00,	0xff, 0, 0,	"LM454[03568]" },
345 	{ 0x31,	0xff, 0, 0,	"LM4549" },
346 }, ac97_sl[] = {
347 	{ 0x22,	0xff, 0, 0,	"Si3036" },
348 	{ 0x23,	0xff, 0, 0,	"Si3038" },
349 }, ac97_st[] = {
350 	{ 0x00,	0xff, 0, 0,	"STAC9700" },
351 	{ 0x04,	0xff, 0, 0,	"STAC970[135]" },
352 	{ 0x05,	0xff, 0, 0,	"STAC9704" },
353 	{ 0x08,	0xff, 0, 0,	"STAC9708/11" },
354 	{ 0x09,	0xff, 0, 0,	"STAC9721/23" },
355 	{ 0x44,	0xff, 0, 0,	"STAC9744/45" },
356 	{ 0x56,	0xff, 0, 0,	"STAC9756/57" },
357 	{ 0x84,	0xff, 0, 0,	"STAC9784/85" },
358 }, ac97_tt[] = {
359 	{ 0x02,	0xff, 0, 0,	"TR28022" },
360 	{ 0x03,	0xff, 0, 0,	"TR28023" },
361 	{ 0x06,	0xff, 0, 0,	"TR28026" },
362 	{ 0x08,	0xff, 0, 0,	"TR28028" },
363 	{ 0x23,	0xff, 0, 0,	"TR28602" },
364 }, ac97_ti[] = {
365 	{ 0x20, 0xff, 0, 0,	"TLC320AD9xC" },
366 }, ac97_wb[] = {
367 	{ 0x01, 0xff, 0, 0,	"W83971D" },
368 }, ac97_wo[] = {
369 	{ 0x00,	0xff, 0, 0,	"WM9701A" },
370 	{ 0x03,	0xff, 0, 0,	"WM9704M/Q-0" }, /* & WM9703 */
371 	{ 0x04,	0xff, 0, 0,	"WM9704M/Q-1" },
372 }, ac97_ym[] = {
373 	{ 0x00, 0xff, 0, 0,	"YMF743" },
374 };
375 
376 #define	cl(n)	n, sizeof(n)/sizeof(n[0])
377 const struct ac97_vendorid {
378 	u_int32_t id;
379 	char * const name;
380 	const struct ac97_codecid * const codecs;
381 	u_int8_t num;
382 } ac97_vendors[] = {
383 	{ 0x41445300, "Analog Devices",		cl(ac97_ad) },
384 	{ 0x414B4D00, "Asahi Kasei",		cl(ac97_ak) },
385 	{ 0x414c4700, "Avance Logic",		cl(ac97_av) },
386 	{ 0x414c4300, "Realtek",		cl(ac97_rl) },
387 	{ 0x43525900, "Cirrus Logic",		cl(ac97_cs) },
388 	{ 0x48525300, "Intersil",		cl(ac97_is) },
389 	{ 0x49434500, "ICEnsemble",		cl(ac97_ic) },
390 	{ 0x4e534300, "National Semiconductor", cl(ac97_ns) },
391 	{ 0x53494c00, "Silicon Laboratory",	cl(ac97_sl) },
392 	{ 0x54524100, "TriTech Microelectronics", cl(ac97_tt) },
393 	{ 0x54584e00, "Texas Instruments",	cl(ac97_ti) },
394 	{ 0x57454300, "Winbond",		cl(ac97_wb) },
395 	{ 0x574d4c00, "Wolfson",		cl(ac97_wo) },
396 	{ 0x594d4800, "Yamaha",			cl(ac97_ym) },
397 	{ 0x83847600, "SigmaTel",		cl(ac97_st) },
398 };
399 #undef cl
400 
401 const char * const ac97enhancement[] = {
402 	"No 3D Stereo",
403 	"Analog Devices Phat Stereo",
404 	"Creative",
405 	"National Semi 3D",
406 	"Yamaha Ymersion",
407 	"BBE 3D",
408 	"Crystal Semi 3D",
409 	"Qsound QXpander",
410 	"Spatializer 3D",
411 	"SRS 3D",
412 	"Platform Tech 3D",
413 	"AKM 3D",
414 	"Aureal",
415 	"AZTECH 3D",
416 	"Binaura 3D",
417 	"ESS Technology",
418 	"Harman International VMAx",
419 	"Nvidea 3D",
420 	"Philips Incredible Sound",
421 	"Texas Instruments 3D",
422 	"VLSI Technology 3D",
423 	"TriTech 3D",
424 	"Realtek 3D",
425 	"Samsung 3D",
426 	"Wolfson Microelectronics 3D",
427 	"Delta Integration 3D",
428 	"SigmaTel 3D",
429 	"Unknown 3D",
430 	"Rockwell 3D",
431 	"Unknown 3D",
432 	"Unknown 3D",
433 	"Unknown 3D"
434 };
435 
436 const char * const ac97feature[] = {
437 	"mic channel",
438 	"reserved",
439 	"tone",
440 	"simulated stereo",
441 	"headphone",
442 	"bass boost",
443 	"18 bit DAC",
444 	"20 bit DAC",
445 	"18 bit ADC",
446 	"20 bit ADC"
447 };
448 
449 
450 int ac97_str_equal __P((const char *, const char *));
451 void ac97_setup_source_info __P((struct ac97_softc *));
452 void ac97_setup_defaults __P((struct ac97_softc *));
453 int ac97_read __P((struct ac97_softc *, u_int8_t, u_int16_t *));
454 int ac97_write __P((struct ac97_softc *, u_int8_t, u_int16_t));
455 
456 #define AC97_DEBUG 10
457 
458 #ifdef AUDIO_DEBUG
459 #define DPRINTF(x)	if (ac97debug) printf x
460 #define DPRINTFN(n,x)	if (ac97debug>(n)) printf x
461 #ifdef AC97_DEBUG
462 int	ac97debug = AC97_DEBUG;
463 #else
464 int	ac97debug = 0;
465 #endif
466 #else
467 #define DPRINTF(x)
468 #define DPRINTFN(n,x)
469 #endif
470 
471 int
472 ac97_read(as, reg, val)
473 	struct ac97_softc *as;
474 	u_int8_t	reg;
475 	u_int16_t	*val;
476 {
477 	int error;
478 
479 	if (((as->host_flags & AC97_HOST_DONT_READ) &&
480 	    (reg != AC97_REG_VENDOR_ID1 && reg != AC97_REG_VENDOR_ID2 &&
481 	    reg != AC97_REG_RESET)) ||
482 	    (as->host_flags & AC97_HOST_DONT_READANY)) {
483 		*val = as->shadow_reg[reg >> 1];
484 		return (0);
485 	}
486 
487 	if ((error = as->host_if->read(as->host_if->arg, reg, val)))
488 		*val = as->shadow_reg[reg >> 1];
489 	return (error);
490 }
491 
492 int
493 ac97_write(as, reg, val)
494 	struct ac97_softc *as;
495 	u_int8_t	reg;
496 	u_int16_t	val;
497 {
498 	as->shadow_reg[reg >> 1] = val;
499 	return (as->host_if->write(as->host_if->arg, reg, val));
500 }
501 
502 void
503 ac97_setup_defaults(as)
504 	struct ac97_softc *as;
505 {
506 	int idx;
507 
508 	bzero(as->shadow_reg, sizeof(as->shadow_reg));
509 
510 	for (idx = 0; idx < SOURCE_INFO_SIZE; idx++) {
511 		const struct ac97_source_info *si = &source_info[idx];
512 
513 		ac97_write(as, si->reg, si->default_value);
514 	}
515 }
516 
517 void
518 ac97_restore_shadow(self)
519 	struct ac97_codec_if *self;
520 {
521 	struct ac97_softc *as = (struct ac97_softc *)self;
522 	int idx;
523 
524 	for (idx = 0; idx < SOURCE_INFO_SIZE; idx++) {
525 		const struct ac97_source_info *si = &source_info[idx];
526 
527 		ac97_write(as, si->reg, as->shadow_reg[si->reg >> 1]);
528 	}
529 }
530 
531 int
532 ac97_str_equal(a, b)
533 	const char *a, *b;
534 {
535 	return ((a == b) || (a && b && (!strcmp(a, b))));
536 }
537 
538 void
539 ac97_setup_source_info(as)
540 	struct ac97_softc *as;
541 {
542 	struct ac97_source_info *si, *si2;
543 	int idx, ouridx;
544 
545 	for (idx = 0, ouridx = 0; idx < SOURCE_INFO_SIZE; idx++) {
546 		si = &as->source_info[ouridx];
547 
548 		bcopy(&source_info[idx], si, sizeof(*si));
549 
550 		switch (si->type) {
551 		case AUDIO_MIXER_CLASS:
552 			si->mixer_class = ouridx;
553 			ouridx++;
554 			break;
555 		case AUDIO_MIXER_VALUE:
556 			/* Todo - Test to see if it works */
557 			ouridx++;
558 
559 			/* Add an entry for mute, if necessary */
560 			if (si->mute) {
561 				si = &as->source_info[ouridx];
562 				bcopy(&source_info[idx], si, sizeof(*si));
563 				si->qualifier = AudioNmute;
564 				si->type = AUDIO_MIXER_ENUM;
565 				si->info = &ac97_on_off;
566 				si->info_size = sizeof(ac97_on_off);
567 				si->bits = 1;
568 				si->ofs = 15;
569 				si->mute = 0;
570 				si->polarity = 0;
571 				ouridx++;
572 			}
573 			break;
574 		case AUDIO_MIXER_ENUM:
575 			/* Todo - Test to see if it works */
576 			ouridx++;
577 			break;
578 		default:
579 			printf ("ac97: shouldn't get here\n");
580 			break;
581 		}
582 	}
583 
584 	as->num_source_info = ouridx;
585 
586 	for (idx = 0; idx < as->num_source_info; idx++) {
587 		int idx2, previdx;
588 
589 		si = &as->source_info[idx];
590 
591 		/* Find mixer class */
592 		for (idx2 = 0; idx2 < as->num_source_info; idx2++) {
593 			si2 = &as->source_info[idx2];
594 
595 			if (si2->type == AUDIO_MIXER_CLASS &&
596 			    ac97_str_equal(si->class, si2->class)) {
597 				si->mixer_class = idx2;
598 			}
599 		}
600 
601 
602 		/* Setup prev and next pointers */
603 		if (si->prev != 0 || si->qualifier)
604 			continue;
605 
606 		si->prev = AUDIO_MIXER_LAST;
607 		previdx = idx;
608 
609 		for (idx2 = 0; idx2 < as->num_source_info; idx2++) {
610 			if (idx2 == idx)
611 				continue;
612 
613 			si2 = &as->source_info[idx2];
614 
615 			if (!si2->prev &&
616 			    ac97_str_equal(si->class, si2->class) &&
617 			    ac97_str_equal(si->device, si2->device)) {
618 				as->source_info[previdx].next = idx2;
619 				as->source_info[idx2].prev = previdx;
620 
621 				previdx = idx2;
622 			}
623 		}
624 
625 		as->source_info[previdx].next = AUDIO_MIXER_LAST;
626 	}
627 }
628 
629 int
630 ac97_attach(host_if)
631 	struct ac97_host_if *host_if;
632 {
633 	struct ac97_softc *as;
634 	u_int16_t id1, id2;
635 	u_int32_t id;
636 	mixer_ctrl_t ctl;
637 	int error, i;
638 
639 	if (!(as = malloc(sizeof(struct ac97_softc), M_DEVBUF, M_NOWAIT)))
640 		return (ENOMEM);
641 
642 	bzero(as, sizeof(*as));
643 
644 	as->codec_if.vtbl = &ac97civ;
645 	as->host_if = host_if;
646 
647 	if ((error = host_if->attach(host_if->arg, &as->codec_if))) {
648 		free(as, M_DEVBUF);
649 		return (error);
650 	}
651 
652 	host_if->reset(host_if->arg);
653 	DELAY(1000);
654 
655 	host_if->write(host_if->arg, AC97_REG_POWER, 0);
656 	host_if->write(host_if->arg, AC97_REG_RESET, 0);
657 	DELAY(10000);
658 
659 	if (host_if->flags)
660 		as->host_flags = host_if->flags(host_if->arg);
661 
662 	ac97_setup_defaults(as);
663 	ac97_read(as, AC97_REG_VENDOR_ID1, &id1);
664 	ac97_read(as, AC97_REG_VENDOR_ID2, &id2);
665 	ac97_read(as, AC97_REG_RESET, &as->caps);
666 
667 	id = (id1 << 16) | id2;
668 	if (id) {
669 		register const struct ac97_vendorid *vendor;
670 		register const struct ac97_codecid *codec;
671 
672 		printf("ac97: codec id 0x%08x", id);
673 		for (vendor = &ac97_vendors[sizeof(ac97_vendors) /
674 		     sizeof(ac97_vendors[0]) - 1];
675 		     vendor >= ac97_vendors; vendor--) {
676 			if (vendor->id == (id & AC97_VENDOR_ID_MASK)) {
677 				printf(" (%s", vendor->name);
678 				for (codec = &vendor->codecs[vendor->num-1];
679 				     codec >= vendor->codecs; codec--) {
680 					if (codec->id == (id & codec->mask))
681 						break;
682 				}
683 				if (codec->mask)
684 					printf(" %s", codec->name);
685 				else
686 					printf(" <%02x>", id & 0xff);
687 				if (codec->rev)
688 					printf(" rev %d", id & codec->rev);
689 				printf(")");
690 				break;
691 			}
692 		}
693 		printf("\n");
694 	} else
695 		printf("ac97: codec id not read\n");
696 
697 	if (as->caps) {
698 		printf("ac97: codec features ");
699 		for (i = 0; i < 10; i++) {
700 			if (as->caps & (1 << i))
701 				printf("%s, ", ac97feature[i]);
702 		}
703 		printf("%s\n",
704 		    ac97enhancement[AC97_CAPS_ENHANCEMENT(as->caps)]);
705 	}
706 
707 	ac97_read(as, AC97_REG_EXT_AUDIO_ID, &as->ext_id);
708 	if (as->ext_id)
709 		DPRINTF(("ac97: ext id %b\n", as->ext_id,
710 		    AC97_EXT_AUDIO_BITS));
711 	if (as->ext_id & AC97_EXT_AUDIO_VRA)
712 		ac97_write(as, AC97_REG_EXT_AUDIO_CTRL,
713 		    AC97_EXT_AUDIO_VRA | AC97_EXT_AUDIO_VRM);
714 
715 	ac97_setup_source_info(as);
716 
717 	/* Just enable the DAC and master volumes by default */
718 	bzero(&ctl, sizeof(ctl));
719 
720 	ctl.type = AUDIO_MIXER_ENUM;
721 	ctl.un.ord = 0;  /* off */
722 	ctl.dev = ac97_get_portnum_by_name(&as->codec_if, AudioCoutputs,
723 	    AudioNmaster, AudioNmute);
724 	ac97_mixer_set_port(&as->codec_if, &ctl);
725 
726 	ctl.dev = ac97_get_portnum_by_name(&as->codec_if, AudioCinputs,
727 	    AudioNdac, AudioNmute);
728 	ac97_mixer_set_port(&as->codec_if, &ctl);
729 
730 	ctl.dev = ac97_get_portnum_by_name(&as->codec_if, AudioCrecord,
731 	    AudioNvolume, AudioNmute);
732 	ac97_mixer_set_port(&as->codec_if, &ctl);
733 
734 	ctl.type = AUDIO_MIXER_ENUM;
735 	ctl.un.ord = 0;
736 	ctl.dev = ac97_get_portnum_by_name(&as->codec_if, AudioCrecord,
737 	    AudioNsource, NULL);
738 	ac97_mixer_set_port(&as->codec_if, &ctl);
739 
740 	return (0);
741 }
742 
743 int
744 ac97_query_devinfo(codec_if, dip)
745 	struct ac97_codec_if *codec_if;
746 	mixer_devinfo_t *dip;
747 {
748 	struct ac97_softc *as = (struct ac97_softc *)codec_if;
749 
750 	if (dip->index < as->num_source_info) {
751 		struct ac97_source_info *si = &as->source_info[dip->index];
752 		const char *name;
753 
754 		dip->type = si->type;
755 		dip->mixer_class = si->mixer_class;
756 		dip->prev = si->prev;
757 		dip->next = si->next;
758 
759 		if (si->qualifier)
760 			name = si->qualifier;
761 		else if (si->device)
762 			name = si->device;
763 		else if (si->class)
764 			name = si->class;
765 
766 		if (name)
767 			strcpy(dip->label.name, name);
768 
769 		bcopy(si->info, &dip->un, si->info_size);
770 
771 		/* Set the delta for volume sources */
772 		if (dip->type == AUDIO_MIXER_VALUE)
773 			dip->un.v.delta = 1 << (8 - si->bits);
774 
775 		return (0);
776 	}
777 
778 	return (ENXIO);
779 }
780 
781 int
782 ac97_mixer_set_port(codec_if, cp)
783 	struct ac97_codec_if *codec_if;
784 	mixer_ctrl_t *cp;
785 {
786 	struct ac97_softc *as = (struct ac97_softc *)codec_if;
787 	struct ac97_source_info *si = &as->source_info[cp->dev];
788 	u_int16_t mask;
789 	u_int16_t val, newval;
790 	int error;
791 
792 	if (cp->dev < 0 || cp->dev >= as->num_source_info ||
793 	    cp->type != si->type)
794 		return (EINVAL);
795 
796 	ac97_read(as, si->reg, &val);
797 
798 	DPRINTFN(5, ("read(%x) = %x\n", si->reg, val));
799 
800 	mask = (1 << si->bits) - 1;
801 
802 	switch (cp->type) {
803 	case AUDIO_MIXER_ENUM:
804 		if (cp->un.ord > mask || cp->un.ord < 0)
805 			return (EINVAL);
806 
807 		newval = (cp->un.ord << si->ofs);
808 		if (si->reg == AC97_REG_RECORD_SELECT) {
809 			newval |= (newval << (8 + si->ofs));
810 			mask |= (mask << 8);
811 		}
812 		break;
813 	case AUDIO_MIXER_VALUE:
814 	{
815 		const struct audio_mixer_value *value = si->info;
816 		u_int16_t  l, r;
817 
818 		if (cp->un.value.num_channels <= 0 ||
819 		    cp->un.value.num_channels > value->num_channels)
820 			return (EINVAL);
821 
822 		if (cp->un.value.num_channels == 1) {
823 			l = r = cp->un.value.level[AUDIO_MIXER_LEVEL_MONO];
824 		} else {
825 			l = cp->un.value.level[AUDIO_MIXER_LEVEL_LEFT];
826 			r = cp->un.value.level[AUDIO_MIXER_LEVEL_RIGHT];
827 		}
828 
829 		if (!si->polarity) {
830 			l = 255 - l;
831 			r = 255 - r;
832 		}
833 
834 		l >>= 8 - si->bits;
835 		r >>= 8 - si->bits;
836 
837 		newval = ((l & mask) << si->ofs);
838 		if (value->num_channels == 2) {
839 			newval |= ((r & mask) << (si->ofs + 8));
840 			mask |= (mask << 8);
841 		}
842 
843 		break;
844 	}
845 	default:
846 		return (EINVAL);
847 	}
848 
849 	mask = mask << si->ofs;
850 	error = ac97_write(as, si->reg, (val & ~mask) | newval);
851 	if (error)
852 		return (error);
853 
854 	return (0);
855 }
856 
857 int
858 ac97_get_portnum_by_name(codec_if, class, device, qualifier)
859 	struct ac97_codec_if *codec_if;
860 	char *class, *device, *qualifier;
861 {
862 	struct ac97_softc *as = (struct ac97_softc *)codec_if;
863 	int idx;
864 
865 	for (idx = 0; idx < as->num_source_info; idx++) {
866 		struct ac97_source_info *si = &as->source_info[idx];
867 		if (ac97_str_equal(class, si->class) &&
868 		    ac97_str_equal(device, si->device) &&
869 		    ac97_str_equal(qualifier, si->qualifier))
870 			return (idx);
871 	}
872 
873 	return (-1);
874 }
875 
876 int
877 ac97_mixer_get_port(codec_if, cp)
878 	struct ac97_codec_if *codec_if;
879 	mixer_ctrl_t *cp;
880 {
881 	struct ac97_softc *as = (struct ac97_softc *)codec_if;
882 	struct ac97_source_info *si = &as->source_info[cp->dev];
883 	u_int16_t mask;
884 	u_int16_t val;
885 
886 	if (cp->dev < 0 || cp->dev >= as->num_source_info ||
887 	    cp->type != si->type)
888 		return (EINVAL);
889 
890 	ac97_read(as, si->reg, &val);
891 
892 	DPRINTFN(5, ("read(%x) = %x\n", si->reg, val));
893 
894 	mask = (1 << si->bits) - 1;
895 
896 	switch (cp->type) {
897 	case AUDIO_MIXER_ENUM:
898 		cp->un.ord = (val >> si->ofs) & mask;
899 		DPRINTFN(4, ("AUDIO_MIXER_ENUM: %x %d %x %d\n", val, si->ofs,
900 		    mask, cp->un.ord));
901 		break;
902 	case AUDIO_MIXER_VALUE:
903 	{
904 		const struct audio_mixer_value *value = si->info;
905 		u_int16_t  l, r;
906 
907 		if ((cp->un.value.num_channels <= 0) ||
908 		    (cp->un.value.num_channels > value->num_channels))
909 			return (EINVAL);
910 
911 		l = r = (val >> si->ofs) & mask;
912 		if (value->num_channels > 1)
913 			r = (val >> (si->ofs + 8)) & mask;
914 
915 		l <<= 8 - si->bits;
916 		r <<= 8 - si->bits;
917 		if (!si->polarity) {
918 			l = 255 - l;
919 			r = 255 - r;
920 		}
921 
922 		/*
923 		 * The EAP driver averages l and r for stereo
924 		 * channels that are requested in MONO mode. Does this
925 		 * make sense?
926 		 */
927 		if (cp->un.value.num_channels == 1) {
928 			cp->un.value.level[AUDIO_MIXER_LEVEL_MONO] = l;
929 		} else if (cp->un.value.num_channels == 2) {
930 			cp->un.value.level[AUDIO_MIXER_LEVEL_LEFT] = l;
931 			cp->un.value.level[AUDIO_MIXER_LEVEL_RIGHT] = r;
932 		}
933 
934 		break;
935 	}
936 	default:
937 		return (EINVAL);
938 	}
939 
940 	return (0);
941 }
942 
943 int
944 ac97_set_rate(codec_if, p, mode)
945 	struct ac97_codec_if *codec_if;
946 	struct audio_params *p;
947 	int mode;
948 {
949 	struct ac97_softc *as = (struct ac97_softc *)codec_if;
950 	u_int16_t reg, val, regval, id = 0;
951 
952 	DPRINTFN(5, ("set_rate(%lu) ", p->sample_rate));
953 
954 	if (!(as->ext_id & AC97_EXT_AUDIO_VRA)) {
955 		p->sample_rate = AC97_SINGLERATE;
956 		return (0);
957 	}
958 
959 	if (p->sample_rate > 0xffff) {
960 		if (mode != AUMODE_PLAY)
961 			return (EINVAL);
962 		if (!(as->ext_id & AC97_EXT_AUDIO_DRA))
963 			return (EINVAL);
964 		if (ac97_read(as, AC97_REG_EXT_AUDIO_CTRL, &id))
965 			return (EIO);
966 		id |= AC97_EXT_AUDIO_DRA;
967 		if (ac97_write(as, AC97_REG_EXT_AUDIO_CTRL, id))
968 			return (EIO);
969 		p->sample_rate /= 2;
970 	}
971 
972 	/* i guess it's better w/o clicks and squeecks when changing the rate */
973 	if (ac97_read(as, AC97_REG_POWER, &val) ||
974 	    ac97_write(as, AC97_REG_POWER, val |
975 	      (mode == AUMODE_PLAY? AC97_POWER_OUT : AC97_POWER_IN)))
976 		return (EIO);
977 
978 	reg = mode == AUMODE_PLAY ?
979 	    AC97_REG_FRONT_DAC_RATE : AC97_REG_PCM_ADC_RATE;
980 
981 	if (ac97_write(as, reg, (u_int16_t) p->sample_rate) ||
982 	    ac97_read(as, reg, &regval))
983 		return (EIO);
984 	p->sample_rate = regval;
985 	if (id & AC97_EXT_AUDIO_DRA)
986 		p->sample_rate *= 2;
987 
988 	DPRINTFN(5, (" %lu\n", regval));
989 
990 	if (ac97_write(as, AC97_REG_POWER, val))
991 		return (EIO);
992 
993 	return (0);
994 }
995