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