ac97.c revision 1.60 1 /* $NetBSD: ac97.c,v 1.60 2004/08/24 00:53:28 thorpej Exp $ */
2 /* $OpenBSD: ac97.c,v 1.8 2000/07/19 09:01:35 csapuntz Exp $ */
3
4 /*
5 * Copyright (c) 1999, 2000 Constantine Sapuntzakis
6 *
7 * Author: Constantine Sapuntzakis <csapuntz (at) stanford.edu>
8 *
9 * Redistribution and use in source and binary forms, with or without
10 * modification, are permitted provided that the following conditions
11 * are met:
12 * 1. Redistributions of source code must retain the above copyright
13 * notice, this list of conditions and the following disclaimer.
14 * 2. Redistributions in binary form must reproduce the above copyright
15 * notice, this list of conditions and the following disclaimer in the
16 * documentation and/or other materials provided with the distribution.
17 * 3. The name of the author may not be used to endorse or promote
18 * products derived from this software without specific prior written
19 * permission.
20 * THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS
21 * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
22 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE
24 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
25 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
26 * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
27 * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
28 * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
29 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
30 * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
31 * DAMAGE
32 */
33
34 /* Partially inspired by FreeBSD's sys/dev/pcm/ac97.c. It came with
35 the following copyright */
36
37 /*
38 * Copyright (c) 1999 Cameron Grant <gandalf (at) vilnya.demon.co.uk>
39 * All rights reserved.
40 *
41 * Redistribution and use in source and binary forms, with or without
42 * modification, are permitted provided that the following conditions
43 * are met:
44 * 1. Redistributions of source code must retain the above copyright
45 * notice, this list of conditions and the following disclaimer.
46 * 2. Redistributions in binary form must reproduce the above copyright
47 * notice, this list of conditions and the following disclaimer in the
48 * documentation and/or other materials provided with the distribution.
49 *
50 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
51 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
52 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
53 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
54 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
55 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
56 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
57 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
58 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
59 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
60 * SUCH DAMAGE.
61 *
62 * $FreeBSD$
63 */
64
65 #include <sys/cdefs.h>
66 __KERNEL_RCSID(0, "$NetBSD: ac97.c,v 1.60 2004/08/24 00:53:28 thorpej 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 struct ac97_softc;
81 struct ac97_source_info;
82 static int ac97_mixer_get_port(struct ac97_codec_if *, mixer_ctrl_t *);
83 static int ac97_mixer_set_port(struct ac97_codec_if *, mixer_ctrl_t *);
84 static int ac97_query_devinfo(struct ac97_codec_if *, mixer_devinfo_t *);
85 static int ac97_get_portnum_by_name(struct ac97_codec_if *, const char *,
86 const char *, const char *);
87 static void ac97_restore_shadow(struct ac97_codec_if *);
88 static int ac97_set_rate(struct ac97_codec_if *, int, u_long *);
89 static void ac97_set_clock(struct ac97_codec_if *, unsigned int);
90 static u_int16_t ac97_get_extcaps(struct ac97_codec_if *);
91 static int ac97_add_port(struct ac97_softc *,
92 const struct ac97_source_info *);
93 static int ac97_str_equal(const char *, const char *);
94 static int ac97_check_capability(struct ac97_softc *, int);
95 static void ac97_setup_source_info(struct ac97_softc *);
96 static void ac97_read(struct ac97_softc *, u_int8_t, u_int16_t *);
97 static void ac97_setup_defaults(struct ac97_softc *);
98 static int ac97_write(struct ac97_softc *, u_int8_t, u_int16_t);
99
100 static void ac97_ad198x_init(struct ac97_softc *);
101 static void ac97_alc650_init(struct ac97_softc *);
102 static void ac97_vt1616_init(struct ac97_softc *);
103
104 #define Ac97Ntone "tone"
105 #define Ac97Nphone "phone"
106
107 static const struct audio_mixer_enum
108 ac97_on_off = { 2, { { { AudioNoff } , 0 },
109 { { AudioNon } , 1 } } };
110
111 static const struct audio_mixer_enum
112 ac97_mic_select = { 2, { { { AudioNmicrophone "0" }, 0 },
113 { { AudioNmicrophone "1" }, 1 } } };
114
115 static const struct audio_mixer_enum
116 ac97_mono_select = { 2, { { { AudioNmixerout }, 0 },
117 { { AudioNmicrophone }, 1 } } };
118
119 static const struct audio_mixer_enum
120 ac97_source = { 8, { { { AudioNmicrophone } , 0 },
121 { { AudioNcd }, 1 },
122 { { AudioNvideo }, 2 },
123 { { AudioNaux }, 3 },
124 { { AudioNline }, 4 },
125 { { AudioNmixerout }, 5 },
126 { { AudioNmixerout AudioNmono }, 6 },
127 { { Ac97Nphone }, 7 } } };
128
129 /*
130 * Due to different values for each source that uses these structures,
131 * the ac97_query_devinfo function sets delta in mixer_devinfo_t using
132 * ac97_source_info.bits.
133 */
134 static const struct audio_mixer_value
135 ac97_volume_stereo = { { AudioNvolume }, 2 };
136
137 static const struct audio_mixer_value
138 ac97_volume_mono = { { AudioNvolume }, 1 };
139
140 #define WRAP(a) &a, sizeof(a)
141
142 static const struct ac97_source_info {
143 const char *class;
144 const char *device;
145 const char *qualifier;
146
147 int type;
148 const void *info;
149 int info_size;
150
151 u_int8_t reg;
152 u_int16_t default_value;
153 u_int8_t bits:3;
154 u_int8_t ofs:4;
155 u_int8_t mute:1;
156 u_int8_t polarity:1; /* Does 0 == MAX or MIN */
157 enum {
158 CHECK_NONE = 0,
159 CHECK_SURROUND,
160 CHECK_CENTER,
161 CHECK_LFE,
162 CHECK_HEADPHONES,
163 CHECK_TONE,
164 CHECK_MIC,
165 CHECK_LOUDNESS,
166 CHECK_3D
167 } req_feature;
168
169 int prev;
170 int next;
171 int mixer_class;
172 } source_info[] = {
173 { AudioCinputs, NULL, NULL,
174 AUDIO_MIXER_CLASS, },
175 { AudioCoutputs, NULL, NULL,
176 AUDIO_MIXER_CLASS, },
177 { AudioCrecord, NULL, NULL,
178 AUDIO_MIXER_CLASS, },
179 /* Stereo master volume*/
180 { AudioCoutputs, AudioNmaster, NULL,
181 AUDIO_MIXER_VALUE, WRAP(ac97_volume_stereo),
182 AC97_REG_MASTER_VOLUME, 0x8000, 5, 0, 1,
183 },
184 /* Mono volume */
185 { AudioCoutputs, AudioNmono, NULL,
186 AUDIO_MIXER_VALUE, WRAP(ac97_volume_mono),
187 AC97_REG_MASTER_VOLUME_MONO, 0x8000, 6, 0, 1,
188 },
189 { AudioCoutputs, AudioNmono, AudioNsource,
190 AUDIO_MIXER_ENUM, WRAP(ac97_mono_select),
191 AC97_REG_GP, 0x0000, 1, 9, 0,
192 },
193 /* Headphone volume */
194 { AudioCoutputs, AudioNheadphone, NULL,
195 AUDIO_MIXER_VALUE, WRAP(ac97_volume_stereo),
196 AC97_REG_HEADPHONE_VOLUME, 0x8000, 6, 0, 1, 0, CHECK_HEADPHONES
197 },
198 /* Surround volume - logic hard coded for mute */
199 { AudioCoutputs, AudioNsurround, NULL,
200 AUDIO_MIXER_VALUE, WRAP(ac97_volume_stereo),
201 AC97_REG_SURR_MASTER, 0x8080, 5, 0, 1, 0, CHECK_SURROUND
202 },
203 /* Center volume*/
204 { AudioCoutputs, AudioNcenter, NULL,
205 AUDIO_MIXER_VALUE, WRAP(ac97_volume_mono),
206 AC97_REG_CENTER_LFE_MASTER, 0x8080, 5, 0, 0, 0, CHECK_CENTER
207 },
208 { AudioCoutputs, AudioNcenter, AudioNmute,
209 AUDIO_MIXER_ENUM, WRAP(ac97_on_off),
210 AC97_REG_CENTER_LFE_MASTER, 0x8080, 1, 7, 0, 0, CHECK_CENTER
211 },
212 /* LFE volume*/
213 { AudioCoutputs, AudioNlfe, NULL,
214 AUDIO_MIXER_VALUE, WRAP(ac97_volume_mono),
215 AC97_REG_CENTER_LFE_MASTER, 0x8080, 5, 8, 0, 0, CHECK_LFE
216 },
217 { AudioCoutputs, AudioNlfe, AudioNmute,
218 AUDIO_MIXER_ENUM, WRAP(ac97_on_off),
219 AC97_REG_CENTER_LFE_MASTER, 0x8080, 1, 15, 0, 0, CHECK_LFE
220 },
221 /* Tone */
222 { AudioCoutputs, Ac97Ntone, NULL,
223 AUDIO_MIXER_VALUE, WRAP(ac97_volume_stereo),
224 AC97_REG_MASTER_TONE, 0x0f0f, 4, 0, 0, 0, CHECK_TONE
225 },
226 /* PC Beep Volume */
227 { AudioCinputs, AudioNspeaker, NULL,
228 AUDIO_MIXER_VALUE, WRAP(ac97_volume_mono),
229 AC97_REG_PCBEEP_VOLUME, 0x0000, 4, 1, 1,
230 },
231
232 /* Phone */
233 { AudioCinputs, Ac97Nphone, NULL,
234 AUDIO_MIXER_VALUE, WRAP(ac97_volume_mono),
235 AC97_REG_PHONE_VOLUME, 0x8008, 5, 0, 1,
236 },
237 /* Mic Volume */
238 { AudioCinputs, AudioNmicrophone, NULL,
239 AUDIO_MIXER_VALUE, WRAP(ac97_volume_mono),
240 AC97_REG_MIC_VOLUME, 0x8008, 5, 0, 1,
241 },
242 { AudioCinputs, AudioNmicrophone, AudioNpreamp,
243 AUDIO_MIXER_ENUM, WRAP(ac97_on_off),
244 AC97_REG_MIC_VOLUME, 0x8008, 1, 6, 0,
245 },
246 { AudioCinputs, AudioNmicrophone, AudioNsource,
247 AUDIO_MIXER_ENUM, WRAP(ac97_mic_select),
248 AC97_REG_GP, 0x0000, 1, 8, 0,
249 },
250 /* Line in Volume */
251 { AudioCinputs, AudioNline, NULL,
252 AUDIO_MIXER_VALUE, WRAP(ac97_volume_stereo),
253 AC97_REG_LINEIN_VOLUME, 0x8808, 5, 0, 1,
254 },
255 /* CD Volume */
256 { AudioCinputs, AudioNcd, NULL,
257 AUDIO_MIXER_VALUE, WRAP(ac97_volume_stereo),
258 AC97_REG_CD_VOLUME, 0x8808, 5, 0, 1,
259 },
260 /* Video Volume */
261 { AudioCinputs, AudioNvideo, NULL,
262 AUDIO_MIXER_VALUE, WRAP(ac97_volume_stereo),
263 AC97_REG_VIDEO_VOLUME, 0x8808, 5, 0, 1,
264 },
265 /* AUX volume */
266 { AudioCinputs, AudioNaux, NULL,
267 AUDIO_MIXER_VALUE, WRAP(ac97_volume_stereo),
268 AC97_REG_AUX_VOLUME, 0x8808, 5, 0, 1,
269 },
270 /* PCM out volume */
271 { AudioCinputs, AudioNdac, NULL,
272 AUDIO_MIXER_VALUE, WRAP(ac97_volume_stereo),
273 AC97_REG_PCMOUT_VOLUME, 0x8808, 5, 0, 1,
274 },
275 /* Record Source - some logic for this is hard coded - see below */
276 { AudioCrecord, AudioNsource, NULL,
277 AUDIO_MIXER_ENUM, WRAP(ac97_source),
278 AC97_REG_RECORD_SELECT, 0x0000, 3, 0, 0,
279 },
280 /* Record Gain */
281 { AudioCrecord, AudioNvolume, NULL,
282 AUDIO_MIXER_VALUE, WRAP(ac97_volume_stereo),
283 AC97_REG_RECORD_GAIN, 0x8000, 4, 0, 1, 1,
284 },
285 /* Record Gain mic */
286 { AudioCrecord, AudioNmicrophone, NULL,
287 AUDIO_MIXER_VALUE, WRAP(ac97_volume_mono),
288 AC97_REG_RECORD_GAIN_MIC, 0x8000, 4, 0, 1, 1, CHECK_MIC
289 },
290 /* */
291 { AudioCoutputs, AudioNloudness, NULL,
292 AUDIO_MIXER_ENUM, WRAP(ac97_on_off),
293 AC97_REG_GP, 0x0000, 1, 12, 0, 0, CHECK_LOUDNESS
294 },
295 { AudioCoutputs, AudioNspatial, NULL,
296 AUDIO_MIXER_ENUM, WRAP(ac97_on_off),
297 AC97_REG_GP, 0x0000, 1, 13, 0, 1, CHECK_3D
298 },
299 { AudioCoutputs, AudioNspatial, "center",
300 AUDIO_MIXER_VALUE, WRAP(ac97_volume_mono),
301 AC97_REG_3D_CONTROL, 0x0000, 4, 8, 0, 1, CHECK_3D
302 },
303 { AudioCoutputs, AudioNspatial, "depth",
304 AUDIO_MIXER_VALUE, WRAP(ac97_volume_mono),
305 AC97_REG_3D_CONTROL, 0x0000, 4, 0, 0, 1, CHECK_3D
306 },
307
308 /* Missing features: Simulated Stereo, POP, Loopback mode */
309 };
310
311 #define SOURCE_INFO_SIZE (sizeof(source_info)/sizeof(source_info[0]))
312
313 /*
314 * Check out http://developer.intel.com/pc-supp/platform/ac97/ for
315 * information on AC-97
316 */
317
318 struct ac97_softc {
319 /* ac97_codec_if must be at the first of ac97_softc. */
320 struct ac97_codec_if codec_if;
321
322 struct ac97_host_if *host_if;
323
324 #define MAX_SOURCES (2 * SOURCE_INFO_SIZE)
325 struct ac97_source_info source_info[MAX_SOURCES];
326 int num_source_info;
327
328 enum ac97_host_flags host_flags;
329 unsigned int ac97_clock; /* usually 48000 */
330 #define AC97_STANDARD_CLOCK 48000U
331 u_int16_t caps; /* -> AC97_REG_RESET */
332 u_int16_t ext_id; /* -> AC97_REG_EXT_AUDIO_ID */
333 u_int16_t shadow_reg[128];
334 };
335
336 static struct ac97_codec_if_vtbl ac97civ = {
337 ac97_mixer_get_port,
338 ac97_mixer_set_port,
339 ac97_query_devinfo,
340 ac97_get_portnum_by_name,
341 ac97_restore_shadow,
342 ac97_get_extcaps,
343 ac97_set_rate,
344 ac97_set_clock,
345 };
346
347 static const struct ac97_codecid {
348 u_int32_t id;
349 u_int32_t mask;
350 const char *name;
351 void (*init)(struct ac97_softc *);
352 } ac97codecid[] = {
353 /*
354 * Analog Devices SoundMAX
355 * http://www.soundmax.com/products/information/codecs.html
356 * http://www.analog.com/productSelection/pdf/AD1881A_0.pdf
357 * http://www.analog.com/productSelection/pdf/AD1885_0.pdf
358 * http://www.analog.com/UploadedFiles/Data_Sheets/206585810AD1980_0.pdf
359 * http://www.analog.com/productSelection/pdf/AD1981A_0.pdf
360 * http://www.analog.com/productSelection/pdf/AD1981B_0.pdf
361 * http://www.analog.com/UploadedFiles/Data_Sheets/180644528AD1985_0.pdf
362 */
363 { AC97_CODEC_ID('A', 'D', 'S', 3),
364 0xffffffff, "Analog Devices AD1819B" },
365 { AC97_CODEC_ID('A', 'D', 'S', 0x40),
366 0xffffffff, "Analog Devices AD1881" },
367 { AC97_CODEC_ID('A', 'D', 'S', 0x48),
368 0xffffffff, "Analog Devices AD1881A" },
369 { AC97_CODEC_ID('A', 'D', 'S', 0x60),
370 0xffffffff, "Analog Devices AD1885" },
371 { AC97_CODEC_ID('A', 'D', 'S', 0x61),
372 0xffffffff, "Analog Devices AD1886" },
373 { AC97_CODEC_ID('A', 'D', 'S', 0x63),
374 0xffffffff, "Analog Devices AD1886A" },
375 { AC97_CODEC_ID('A', 'D', 'S', 0x68),
376 0xffffffff, "Analog Devices AD1888", ac97_ad198x_init },
377 { AC97_CODEC_ID('A', 'D', 'S', 0x70),
378 0xffffffff, "Analog Devices AD1980", ac97_ad198x_init },
379 { AC97_CODEC_ID('A', 'D', 'S', 0x72),
380 0xffffffff, "Analog Devices AD1981A" },
381 { AC97_CODEC_ID('A', 'D', 'S', 0x74),
382 0xffffffff, "Analog Devices AD1981B" },
383 { AC97_CODEC_ID('A', 'D', 'S', 0x75),
384 0xffffffff, "Analog Devices AD1985", ac97_ad198x_init },
385 { AC97_CODEC_ID('A', 'D', 'S', 0),
386 AC97_VENDOR_ID_MASK, "Analog Devices unknown" },
387
388 /*
389 * Datasheets:
390 * http://www.asahi-kasei.co.jp/akm/usa/product/ak4541/ek4541.pdf
391 * http://www.asahi-kasei.co.jp/akm/usa/product/ak4543/ek4543.pdf
392 * http://www.asahi-kasei.co.jp/akm/usa/product/ak4544a/ek4544a.pdf
393 * http://www.asahi-kasei.co.jp/akm/usa/product/ak4545/ek4545.pdf
394 */
395 { AC97_CODEC_ID('A', 'K', 'M', 0),
396 0xffffffff, "Asahi Kasei AK4540" },
397 { AC97_CODEC_ID('A', 'K', 'M', 1),
398 0xffffffff, "Asahi Kasei AK4542" },
399 { AC97_CODEC_ID('A', 'K', 'M', 2),
400 0xffffffff, "Asahi Kasei AK4541/AK4543" },
401 { AC97_CODEC_ID('A', 'K', 'M', 5),
402 0xffffffff, "Asahi Kasei AK4544" },
403 { AC97_CODEC_ID('A', 'K', 'M', 6),
404 0xffffffff, "Asahi Kasei AK4544A" },
405 { AC97_CODEC_ID('A', 'K', 'M', 7),
406 0xffffffff, "Asahi Kasei AK4545" },
407 { AC97_CODEC_ID('A', 'K', 'M', 0),
408 AC97_VENDOR_ID_MASK, "Asahi Kasei unknown" },
409
410 /*
411 * Realtek & Avance Logic
412 * http://www.realtek.com.tw/downloads/downloads1-3.aspx?lineid=5&famid=All&series=All&Spec=True
413 *
414 * ALC650 and ALC658 support VRA, but it supports only 8000, 11025,
415 * 12000, 16000, 22050, 24000, 32000, 44100, and 48000 Hz.
416 */
417 { AC97_CODEC_ID('A', 'L', 'C', 0x00),
418 0xfffffff0, "Realtek RL5306" },
419 { AC97_CODEC_ID('A', 'L', 'C', 0x10),
420 0xfffffff0, "Realtek RL5382" },
421 { AC97_CODEC_ID('A', 'L', 'C', 0x20),
422 0xfffffff0, "Realtek RL5383/RL5522/ALC100" },
423 { AC97_CODEC_ID('A', 'L', 'G', 0x10),
424 0xffffffff, "Avance Logic ALC200/ALC201" },
425 { AC97_CODEC_ID('A', 'L', 'G', 0x20),
426 0xfffffff0, "Avance Logic ALC650", ac97_alc650_init },
427 { AC97_CODEC_ID('A', 'L', 'G', 0x30),
428 0xffffffff, "Avance Logic ALC101" },
429 { AC97_CODEC_ID('A', 'L', 'G', 0x40),
430 0xffffffff, "Avance Logic ALC202" },
431 { AC97_CODEC_ID('A', 'L', 'G', 0x50),
432 0xffffffff, "Avance Logic ALC250" },
433 { AC97_CODEC_ID('A', 'L', 'G', 0x60),
434 0xfffffff0, "Avance Logic ALC655" },
435 { AC97_CODEC_ID('A', 'L', 'G', 0x80),
436 0xfffffff0, "Avance Logic ALC658" },
437 { AC97_CODEC_ID('A', 'L', 'G', 0x90),
438 0xfffffff0, "Avance Logic ALC850" },
439 { AC97_CODEC_ID('A', 'L', 'C', 0),
440 AC97_VENDOR_ID_MASK, "Realtek unknown" },
441 { AC97_CODEC_ID('A', 'L', 'G', 0),
442 AC97_VENDOR_ID_MASK, "Avance Logic unknown" },
443
444 /**
445 * C-Media Electronics Inc.
446 * http://www.cmedia.com.tw/doc/CMI9739%206CH%20Audio%20Codec%20SPEC_Ver12.pdf
447 */
448 { AC97_CODEC_ID('C', 'M', 'I', 0x61),
449 0xffffffff, "C-Media CMI9739" },
450 { AC97_CODEC_ID('C', 'M', 'I', 0),
451 AC97_VENDOR_ID_MASK, "C-Media unknown" },
452
453 /* Cirrus Logic, Crystal series:
454 * 'C' 'R' 'Y' 0x0[0-7] - CS4297
455 * 0x1[0-7] - CS4297A
456 * 0x2[0-7] - CS4298
457 * 0x2[8-f] - CS4294
458 * 0x3[0-7] - CS4299
459 * 0x4[8-f] - CS4201
460 * 0x5[8-f] - CS4205
461 * 0x6[0-7] - CS4291
462 * 0x7[0-7] - CS4202
463 * Datasheets:
464 * http://www.cirrus.com/pubs/cs4297A-5.pdf?DocumentID=593
465 * http://www.cirrus.com/pubs/cs4294.pdf?DocumentID=32
466 * http://www.cirrus.com/pubs/cs4299-5.pdf?DocumentID=594
467 * http://www.cirrus.com/pubs/cs4201-2.pdf?DocumentID=492
468 * http://www.cirrus.com/pubs/cs4205-2.pdf?DocumentID=492
469 * http://www.cirrus.com/pubs/cs4202-1.pdf?DocumentID=852
470 */
471 { AC97_CODEC_ID('C', 'R', 'Y', 0x00),
472 0xfffffff8, "Crystal CS4297", },
473 { AC97_CODEC_ID('C', 'R', 'Y', 0x10),
474 0xfffffff8, "Crystal CS4297A", },
475 { AC97_CODEC_ID('C', 'R', 'Y', 0x20),
476 0xfffffff8, "Crystal CS4298", },
477 { AC97_CODEC_ID('C', 'R', 'Y', 0x28),
478 0xfffffff8, "Crystal CS4294", },
479 { AC97_CODEC_ID('C', 'R', 'Y', 0x30),
480 0xfffffff8, "Crystal CS4299", },
481 { AC97_CODEC_ID('C', 'R', 'Y', 0x48),
482 0xfffffff8, "Crystal CS4201", },
483 { AC97_CODEC_ID('C', 'R', 'Y', 0x58),
484 0xfffffff8, "Crystal CS4205", },
485 { AC97_CODEC_ID('C', 'R', 'Y', 0x60),
486 0xfffffff8, "Crystal CS4291", },
487 { AC97_CODEC_ID('C', 'R', 'Y', 0x70),
488 0xfffffff8, "Crystal CS4202", },
489 { AC97_CODEC_ID('C', 'R', 'Y', 0),
490 AC97_VENDOR_ID_MASK, "Cirrus Logic unknown", },
491
492 { 0x45838308, 0xffffffff, "ESS Technology ES1921", },
493 { 0x45838300, AC97_VENDOR_ID_MASK, "ESS Technology unknown", },
494
495 { AC97_CODEC_ID('H', 'R', 'S', 0),
496 0xffffffff, "Intersil HMP9701", },
497 { AC97_CODEC_ID('H', 'R', 'S', 0),
498 AC97_VENDOR_ID_MASK, "Intersil unknown", },
499
500 /*
501 * IC Ensemble (VIA)
502 * http://www.viatech.com/en/datasheet/DS1616.pdf
503 */
504 { AC97_CODEC_ID('I', 'C', 'E', 0x01),
505 0xffffffff, "ICEnsemble ICE1230/VT1611", },
506 { AC97_CODEC_ID('I', 'C', 'E', 0x11),
507 0xffffffff, "ICEnsemble ICE1232/VT1611A", },
508 { AC97_CODEC_ID('I', 'C', 'E', 0x14),
509 0xffffffff, "ICEnsemble ICE1232A", },
510 { AC97_CODEC_ID('I', 'C', 'E', 0x51),
511 0xffffffff, "VIA Technologies VT1616", ac97_vt1616_init },
512 { AC97_CODEC_ID('I', 'C', 'E', 0x52),
513 0xffffffff, "VIA Technologies VT1616i", ac97_vt1616_init },
514 { AC97_CODEC_ID('I', 'C', 'E', 0),
515 AC97_VENDOR_ID_MASK, "ICEnsemble/VIA unknown", },
516
517 { AC97_CODEC_ID('N', 'S', 'C', 0),
518 0xffffffff, "National Semiconductor LM454[03568]", },
519 { AC97_CODEC_ID('N', 'S', 'C', 49),
520 0xffffffff, "National Semiconductor LM4549", },
521 { AC97_CODEC_ID('N', 'S', 'C', 0),
522 AC97_VENDOR_ID_MASK, "National Semiconductor unknown", },
523
524 { AC97_CODEC_ID('P', 'S', 'C', 4),
525 0xffffffff, "Philips Semiconductor UCB1400", },
526 { AC97_CODEC_ID('P', 'S', 'C', 0),
527 AC97_VENDOR_ID_MASK, "Philips Semiconductor unknown", },
528
529 { AC97_CODEC_ID('S', 'I', 'L', 34),
530 0xffffffff, "Silicon Laboratory Si3036", },
531 { AC97_CODEC_ID('S', 'I', 'L', 35),
532 0xffffffff, "Silicon Laboratory Si3038", },
533 { AC97_CODEC_ID('S', 'I', 'L', 0),
534 AC97_VENDOR_ID_MASK, "Silicon Laboratory unknown", },
535
536 { AC97_CODEC_ID('T', 'R', 'A', 2),
537 0xffffffff, "TriTech TR28022", },
538 { AC97_CODEC_ID('T', 'R', 'A', 3),
539 0xffffffff, "TriTech TR28023", },
540 { AC97_CODEC_ID('T', 'R', 'A', 6),
541 0xffffffff, "TriTech TR28026", },
542 { AC97_CODEC_ID('T', 'R', 'A', 8),
543 0xffffffff, "TriTech TR28028", },
544 { AC97_CODEC_ID('T', 'R', 'A', 35),
545 0xffffffff, "TriTech TR28602", },
546 { AC97_CODEC_ID('T', 'R', 'A', 0),
547 AC97_VENDOR_ID_MASK, "TriTech unknown", },
548
549 { AC97_CODEC_ID('T', 'X', 'N', 0x20),
550 0xffffffff, "Texas Instruments TLC320AD9xC", },
551 { AC97_CODEC_ID('T', 'X', 'N', 0),
552 AC97_VENDOR_ID_MASK, "Texas Instruments unknown", },
553
554 /*
555 * VIA
556 * http://www.viatech.com/en/multimedia/audio.jsp
557 */
558 { AC97_CODEC_ID('V', 'I', 'A', 0x61),
559 0xffffffff, "VIA Technologies VT1612A", },
560 { AC97_CODEC_ID('V', 'I', 'A', 0),
561 AC97_VENDOR_ID_MASK, "VIA Technologies unknown", },
562
563 { AC97_CODEC_ID('W', 'E', 'C', 1),
564 0xffffffff, "Winbond W83971D", },
565 { AC97_CODEC_ID('W', 'E', 'C', 0),
566 AC97_VENDOR_ID_MASK, "Winbond unknown", },
567
568 /*
569 * http://www.wolfsonmicro.com/product_list.asp?cid=64
570 * http://www.wolfsonmicro.com/download.asp/did.56/WM9701A.pdf - 00
571 * http://www.wolfsonmicro.com/download.asp/did.57/WM9703.pdf - 03
572 * http://www.wolfsonmicro.com/download.asp/did.58/WM9704M.pdf - 04
573 * http://www.wolfsonmicro.com/download.asp/did.59/WM9704Q.pdf - 04
574 * http://www.wolfsonmicro.com/download.asp/did.184/WM9705_Rev34.pdf - 05
575 * http://www.wolfsonmicro.com/download.asp/did.60/WM9707.pdf - 03
576 * http://www.wolfsonmicro.com/download.asp/did.136/WM9708.pdf - 03
577 * http://www.wolfsonmicro.com/download.asp/did.243/WM9710.pdf - 05
578 */
579 { AC97_CODEC_ID('W', 'M', 'L', 0),
580 0xffffffff, "Wolfson WM9701A", },
581 { AC97_CODEC_ID('W', 'M', 'L', 3),
582 0xffffffff, "Wolfson WM9703/WM9707/WM9708", },
583 { AC97_CODEC_ID('W', 'M', 'L', 4),
584 0xffffffff, "Wolfson WM9704", },
585 { AC97_CODEC_ID('W', 'M', 'L', 5),
586 0xffffffff, "Wolfson WM9705/WM9710", },
587 { AC97_CODEC_ID('W', 'M', 'L', 0),
588 AC97_VENDOR_ID_MASK, "Wolfson unknown", },
589
590 /*
591 * http://www.yamaha.co.jp/english/product/lsi/us/products/pcaudio.html
592 * Datasheets:
593 * http://www.yamaha.co.jp/english/product/lsi/us/products/pdf/4MF743A20.pdf
594 * http://www.yamaha.co.jp/english/product/lsi/us/products/pdf/4MF753A20.pdf
595 */
596 { AC97_CODEC_ID('Y', 'M', 'H', 0),
597 0xffffffff, "Yamaha YMF743-S", },
598 { AC97_CODEC_ID('Y', 'M', 'H', 3),
599 0xffffffff, "Yamaha YMF753-S", },
600 { AC97_CODEC_ID('Y', 'M', 'H', 0),
601 AC97_VENDOR_ID_MASK, "Yamaha unknown", },
602
603 /*
604 * http://www.sigmatel.com/products/technical_docs.htm
605 * and
606 * http://www.sigmatel.com/documents/c-major-brochure-9-0.pdf
607 */
608 { 0x83847600, 0xffffffff, "SigmaTel STAC9700", },
609 { 0x83847604, 0xffffffff, "SigmaTel STAC9701/3/4/5", },
610 { 0x83847605, 0xffffffff, "SigmaTel STAC9704", },
611 { 0x83847608, 0xffffffff, "SigmaTel STAC9708", },
612 { 0x83847609, 0xffffffff, "SigmaTel STAC9721/23", },
613 { 0x83847644, 0xffffffff, "SigmaTel STAC9744/45", },
614 { 0x83847650, 0xffffffff, "SigmaTel STAC9750/51", },
615 { 0x83847656, 0xffffffff, "SigmaTel STAC9756/57", },
616 { 0x83847658, 0xffffffff, "SigmaTel STAC9758/59", },
617 { 0x83847666, 0xffffffff, "SigmaTel STAC9766/67", },
618 { 0x83847684, 0xffffffff, "SigmaTel STAC9783/84", },
619 { 0x83847600, AC97_VENDOR_ID_MASK, "SigmaTel unknown", },
620
621 { 0,
622 0, NULL, }
623 };
624
625 static const char * const ac97enhancement[] = {
626 "no 3D stereo",
627 "Analog Devices Phat Stereo",
628 "Creative",
629 "National Semi 3D",
630 "Yamaha Ymersion",
631 "BBE 3D",
632 "Crystal Semi 3D",
633 "Qsound QXpander",
634 "Spatializer 3D",
635 "SRS 3D",
636 "Platform Tech 3D",
637 "AKM 3D",
638 "Aureal",
639 "AZTECH 3D",
640 "Binaura 3D",
641 "ESS Technology",
642 "Harman International VMAx",
643 "Nvidea 3D",
644 "Philips Incredible Sound",
645 "Texas Instruments' 3D",
646 "VLSI Technology 3D",
647 "TriTech 3D",
648 "Realtek 3D",
649 "Samsung 3D",
650 "Wolfson Microelectronics 3D",
651 "Delta Integration 3D",
652 "SigmaTel 3D",
653 "KS Waves 3D",
654 "Rockwell 3D",
655 "Unknown 3D",
656 "Unknown 3D",
657 "Unknown 3D",
658 };
659
660 static const char * const ac97feature[] = {
661 "dedicated mic channel",
662 "reserved",
663 "tone",
664 "simulated stereo",
665 "headphone",
666 "bass boost",
667 "18 bit DAC",
668 "20 bit DAC",
669 "18 bit ADC",
670 "20 bit ADC"
671 };
672
673
674 /* #define AC97_DEBUG 10 */
675
676 #ifdef AUDIO_DEBUG
677 #define DPRINTF(x) if (ac97debug) printf x
678 #define DPRINTFN(n,x) if (ac97debug>(n)) printf x
679 #ifdef AC97_DEBUG
680 int ac97debug = AC97_DEBUG;
681 #else
682 int ac97debug = 0;
683 #endif
684 #else
685 #define DPRINTF(x)
686 #define DPRINTFN(n,x)
687 #endif
688
689 static void
690 ac97_read(struct ac97_softc *as, u_int8_t reg, u_int16_t *val)
691 {
692 if (as->host_flags & AC97_HOST_DONT_READ &&
693 (reg != AC97_REG_VENDOR_ID1 && reg != AC97_REG_VENDOR_ID2 &&
694 reg != AC97_REG_RESET)) {
695 *val = as->shadow_reg[reg >> 1];
696 return;
697 }
698
699 if (as->host_if->read(as->host_if->arg, reg, val)) {
700 *val = as->shadow_reg[reg >> 1];
701 }
702 }
703
704 static int
705 ac97_write(struct ac97_softc *as, u_int8_t reg, u_int16_t val)
706 {
707 as->shadow_reg[reg >> 1] = val;
708 return as->host_if->write(as->host_if->arg, reg, val);
709 }
710
711 static void
712 ac97_setup_defaults(struct ac97_softc *as)
713 {
714 int idx;
715 const struct ac97_source_info *si;
716
717 memset(as->shadow_reg, 0, sizeof(as->shadow_reg));
718
719 for (idx = 0; idx < SOURCE_INFO_SIZE; idx++) {
720 si = &source_info[idx];
721 ac97_write(as, si->reg, si->default_value);
722 }
723 }
724
725 static void
726 ac97_restore_shadow(struct ac97_codec_if *self)
727 {
728 struct ac97_softc *as;
729 const struct ac97_source_info *si;
730 int idx;
731 uint16_t val;
732
733 as = (struct ac97_softc *) self;
734
735 /* make sure chip is fully operational */
736 #define AC97_POWER_ALL (AC97_POWER_REF | AC97_POWER_ANL | AC97_POWER_DAC \
737 | AC97_POWER_ADC)
738 for (idx = 500000; idx >= 0; idx--) {
739 ac97_read(as, AC97_REG_POWER, &val);
740 if ((val & AC97_POWER_ALL) == AC97_POWER_ALL)
741 break;
742 DELAY(1);
743 }
744 #undef AC97_POWER_ALL
745
746 for (idx = 0; idx < SOURCE_INFO_SIZE; idx++) {
747 si = &source_info[idx];
748 /* don't "restore" to the reset reg! */
749 if (si->reg != AC97_REG_RESET)
750 ac97_write(as, si->reg, as->shadow_reg[si->reg >> 1]);
751 }
752
753 if (as->ext_id & (AC97_EXT_AUDIO_VRA | AC97_EXT_AUDIO_DRA
754 | AC97_EXT_AUDIO_SPDIF | AC97_EXT_AUDIO_VRM
755 | AC97_EXT_AUDIO_CDAC | AC97_EXT_AUDIO_SDAC
756 | AC97_EXT_AUDIO_LDAC)) {
757 ac97_write(as, AC97_REG_EXT_AUDIO_CTRL,
758 as->shadow_reg[AC97_REG_EXT_AUDIO_CTRL >> 1]);
759 }
760 }
761
762 static int
763 ac97_str_equal(const char *a, const char *b)
764 {
765 return (a == b) || (a && b && (!strcmp(a, b)));
766 }
767
768 static int
769 ac97_check_capability(struct ac97_softc *as, int check)
770 {
771 switch (check) {
772 case CHECK_NONE:
773 return 1;
774 case CHECK_SURROUND:
775 return as->ext_id & AC97_EXT_AUDIO_SDAC;
776 case CHECK_CENTER:
777 return as->ext_id & AC97_EXT_AUDIO_CDAC;
778 case CHECK_LFE:
779 return as->ext_id & AC97_EXT_AUDIO_LDAC;
780 case CHECK_HEADPHONES:
781 return as->caps & AC97_CAPS_HEADPHONES;
782 case CHECK_TONE:
783 return as->caps & AC97_CAPS_TONECTRL;
784 case CHECK_MIC:
785 return as->caps & AC97_CAPS_MICIN;
786 case CHECK_LOUDNESS:
787 return as->caps & AC97_CAPS_LOUDNESS;
788 case CHECK_3D:
789 return AC97_CAPS_ENHANCEMENT(as->caps) != 0;
790 default:
791 printf("%s: internal error: feature=%d\n", __func__, check);
792 return 0;
793 }
794 }
795
796 static void
797 ac97_setup_source_info(struct ac97_softc *as)
798 {
799 int idx, ouridx;
800 struct ac97_source_info *si, *si2;
801
802 for (idx = 0, ouridx = 0; idx < SOURCE_INFO_SIZE; idx++) {
803 si = &as->source_info[ouridx];
804
805 if (!ac97_check_capability(as, source_info[idx].req_feature))
806 continue;
807
808 memcpy(si, &source_info[idx], sizeof(*si));
809
810 switch (si->type) {
811 case AUDIO_MIXER_CLASS:
812 si->mixer_class = ouridx;
813 ouridx++;
814 break;
815 case AUDIO_MIXER_VALUE:
816 /* Todo - Test to see if it works */
817 ouridx++;
818
819 /* Add an entry for mute, if necessary */
820 if (si->mute) {
821 si = &as->source_info[ouridx];
822 memcpy(si, &source_info[idx], sizeof(*si));
823 si->qualifier = AudioNmute;
824 si->type = AUDIO_MIXER_ENUM;
825 si->info = &ac97_on_off;
826 si->info_size = sizeof(ac97_on_off);
827 si->bits = 1;
828 si->ofs = 15;
829 si->mute = 0;
830 si->polarity = 0;
831 ouridx++;
832 }
833 break;
834 case AUDIO_MIXER_ENUM:
835 /* Todo - Test to see if it works */
836 ouridx++;
837 break;
838 default:
839 aprint_error ("ac97: shouldn't get here\n");
840 break;
841 }
842 }
843
844 as->num_source_info = ouridx;
845
846 for (idx = 0; idx < as->num_source_info; idx++) {
847 int idx2, previdx;
848
849 si = &as->source_info[idx];
850
851 /* Find mixer class */
852 for (idx2 = 0; idx2 < as->num_source_info; idx2++) {
853 si2 = &as->source_info[idx2];
854
855 if (si2->type == AUDIO_MIXER_CLASS &&
856 ac97_str_equal(si->class,
857 si2->class)) {
858 si->mixer_class = idx2;
859 }
860 }
861
862
863 /* Setup prev and next pointers */
864 if (si->prev != 0)
865 continue;
866
867 if (si->qualifier)
868 continue;
869
870 si->prev = AUDIO_MIXER_LAST;
871 previdx = idx;
872
873 for (idx2 = 0; idx2 < as->num_source_info; idx2++) {
874 if (idx2 == idx)
875 continue;
876
877 si2 = &as->source_info[idx2];
878
879 if (!si2->prev &&
880 ac97_str_equal(si->class, si2->class) &&
881 ac97_str_equal(si->device, si2->device)) {
882 as->source_info[previdx].next = idx2;
883 as->source_info[idx2].prev = previdx;
884
885 previdx = idx2;
886 }
887 }
888
889 as->source_info[previdx].next = AUDIO_MIXER_LAST;
890 }
891 }
892
893 int
894 ac97_attach(struct ac97_host_if *host_if)
895 {
896 struct ac97_softc *as;
897 struct device *sc_dev;
898 int error, i, j;
899 uint32_t id;
900 uint16_t id1, id2;
901 uint16_t extstat, rate;
902 uint16_t val;
903 mixer_ctrl_t ctl;
904 void (*initfunc)(struct ac97_softc *);
905 #define FLAGBUFLEN 140
906 char flagbuf[FLAGBUFLEN];
907
908 sc_dev = (struct device *)host_if->arg;
909 initfunc = NULL;
910 as = malloc(sizeof(struct ac97_softc), M_DEVBUF, M_WAITOK|M_ZERO);
911
912 if (as == NULL)
913 return ENOMEM;
914
915 as->codec_if.vtbl = &ac97civ;
916 as->host_if = host_if;
917
918 if ((error = host_if->attach(host_if->arg, &as->codec_if))) {
919 free(as, M_DEVBUF);
920 return error;
921 }
922
923 host_if->reset(host_if->arg);
924
925 host_if->write(host_if->arg, AC97_REG_POWER, 0);
926 host_if->write(host_if->arg, AC97_REG_RESET, 0);
927
928 if (host_if->flags)
929 as->host_flags = host_if->flags(host_if->arg);
930
931 #define AC97_POWER_ALL (AC97_POWER_REF | AC97_POWER_ANL | AC97_POWER_DAC \
932 | AC97_POWER_ADC)
933 for (i = 500000; i >= 0; i--) {
934 ac97_read(as, AC97_REG_POWER, &val);
935 if ((val & AC97_POWER_ALL) == AC97_POWER_ALL)
936 break;
937 DELAY(1);
938 }
939 #undef AC97_POWER_ALL
940
941 ac97_setup_defaults(as);
942 ac97_read(as, AC97_REG_RESET, &as->caps);
943 ac97_read(as, AC97_REG_VENDOR_ID1, &id1);
944 ac97_read(as, AC97_REG_VENDOR_ID2, &id2);
945
946 id = (id1 << 16) | id2;
947
948 aprint_normal("%s: ac97: ", sc_dev->dv_xname);
949
950 for (i = 0; ; i++) {
951 if (ac97codecid[i].id == 0) {
952 char pnp[4];
953
954 AC97_GET_CODEC_ID(id, pnp);
955 #define ISASCII(c) ((c) >= ' ' && (c) < 0x7f)
956 if (ISASCII(pnp[0]) && ISASCII(pnp[1]) &&
957 ISASCII(pnp[2]))
958 aprint_normal("%c%c%c%d",
959 pnp[0], pnp[1], pnp[2], pnp[3]);
960 else
961 aprint_normal("unknown (0x%08x)", id);
962 break;
963 }
964 if (ac97codecid[i].id == (id & ac97codecid[i].mask)) {
965 aprint_normal("%s", ac97codecid[i].name);
966 if (ac97codecid[i].mask == AC97_VENDOR_ID_MASK) {
967 aprint_normal(" (0x%08x)", id);
968 }
969 initfunc = ac97codecid[i].init;
970 break;
971 }
972 }
973 aprint_normal(" codec; ");
974 for (i = j = 0; i < 10; i++) {
975 if (as->caps & (1 << i)) {
976 aprint_normal("%s%s", j ? ", " : "", ac97feature[i]);
977 j++;
978 }
979 }
980 aprint_normal("%s%s\n", j ? ", " : "",
981 ac97enhancement[AC97_CAPS_ENHANCEMENT(as->caps)]);
982
983 as->ac97_clock = AC97_STANDARD_CLOCK;
984 ac97_read(as, AC97_REG_EXT_AUDIO_ID, &as->ext_id);
985 if (as->ext_id != 0) {
986 /* Print capabilities */
987 bitmask_snprintf(as->ext_id, "\20\20SECONDARY10\17SECONDARY01"
988 "\14AC97_23\13AC97_22\12AMAP\11LDAC\10SDAC"
989 "\7CDAC\4VRM\3SPDIF\2DRA\1VRA",
990 flagbuf, FLAGBUFLEN);
991 aprint_normal("%s: ac97: ext id %s\n", sc_dev->dv_xname, flagbuf);
992
993 /* Print unusual settings */
994 if (as->ext_id & AC97_EXT_AUDIO_DSA_MASK) {
995 aprint_normal("%s: ac97: Slot assignment: ",
996 sc_dev->dv_xname);
997 switch (as->ext_id & AC97_EXT_AUDIO_DSA_MASK) {
998 case AC97_EXT_AUDIO_DSA01:
999 aprint_normal("7&8, 6&9, 10&11.\n");
1000 break;
1001 case AC97_EXT_AUDIO_DSA10:
1002 aprint_normal("6&9, 10&11, 3&4.\n");
1003 break;
1004 case AC97_EXT_AUDIO_DSA11:
1005 aprint_normal("10&11, 3&4, 7&8.\n");
1006 break;
1007 }
1008 }
1009
1010 /* Enable and disable features */
1011 ac97_read(as, AC97_REG_EXT_AUDIO_CTRL, &extstat);
1012 extstat &= ~AC97_EXT_AUDIO_DRA;
1013 if (as->ext_id & AC97_EXT_AUDIO_LDAC)
1014 extstat |= AC97_EXT_AUDIO_LDAC;
1015 if (as->ext_id & AC97_EXT_AUDIO_SDAC)
1016 extstat |= AC97_EXT_AUDIO_SDAC;
1017 if (as->ext_id & AC97_EXT_AUDIO_CDAC)
1018 extstat |= AC97_EXT_AUDIO_CDAC;
1019 if (as->ext_id & AC97_EXT_AUDIO_VRM)
1020 extstat |= AC97_EXT_AUDIO_VRM;
1021 if (as->ext_id & AC97_EXT_AUDIO_SPDIF) {
1022 /* Output the same data as DAC to SPDIF output */
1023 extstat &= ~AC97_EXT_AUDIO_SPSA_MASK;
1024 extstat |= AC97_EXT_AUDIO_SPSA34;
1025 }
1026 if (as->ext_id & AC97_EXT_AUDIO_VRA)
1027 extstat |= AC97_EXT_AUDIO_VRA;
1028 ac97_write(as, AC97_REG_EXT_AUDIO_CTRL, extstat);
1029 if (as->ext_id & AC97_EXT_AUDIO_VRA) {
1030 /* VRA should be enabled. */
1031 /* so it claims to do variable rate, let's make sure */
1032 ac97_write(as, AC97_REG_PCM_FRONT_DAC_RATE, 44100);
1033 ac97_read(as, AC97_REG_PCM_FRONT_DAC_RATE, &rate);
1034 if (rate != 44100) {
1035 /* We can't believe ext_id */
1036 as->ext_id = 0;
1037 aprint_normal(
1038 "%s: Ignore these capabilities.\n",
1039 sc_dev->dv_xname);
1040 }
1041 /* restore the default value */
1042 ac97_write(as, AC97_REG_PCM_FRONT_DAC_RATE,
1043 AC97_SINGLE_RATE);
1044 }
1045 }
1046
1047 ac97_setup_source_info(as);
1048
1049 memset(&ctl, 0, sizeof(ctl));
1050 /* disable mutes */
1051 for (i = 0; i < 11; i++) {
1052 static struct {
1053 char *class, *device;
1054 } d[11] = {
1055 { AudioCoutputs, AudioNmaster},
1056 { AudioCoutputs, AudioNheadphone},
1057 { AudioCoutputs, AudioNsurround},
1058 { AudioCoutputs, AudioNcenter},
1059 { AudioCoutputs, AudioNlfe},
1060 { AudioCinputs, AudioNdac},
1061 { AudioCinputs, AudioNcd},
1062 { AudioCinputs, AudioNline},
1063 { AudioCinputs, AudioNaux},
1064 { AudioCinputs, AudioNvideo},
1065 { AudioCrecord, AudioNvolume},
1066 };
1067
1068 ctl.type = AUDIO_MIXER_ENUM;
1069 ctl.un.ord = 0;
1070
1071 ctl.dev = ac97_get_portnum_by_name(&as->codec_if,
1072 d[i].class, d[i].device, AudioNmute);
1073 ac97_mixer_set_port(&as->codec_if, &ctl);
1074 }
1075 ctl.type = AUDIO_MIXER_ENUM;
1076 ctl.un.ord = 0;
1077 ctl.dev = ac97_get_portnum_by_name(&as->codec_if, AudioCrecord,
1078 AudioNsource, NULL);
1079 ac97_mixer_set_port(&as->codec_if, &ctl);
1080
1081 /* set a reasonable default volume */
1082 ctl.type = AUDIO_MIXER_VALUE;
1083 ctl.un.value.num_channels = 2;
1084 ctl.un.value.level[AUDIO_MIXER_LEVEL_LEFT] = \
1085 ctl.un.value.level[AUDIO_MIXER_LEVEL_RIGHT] = 127;
1086 ctl.dev = ac97_get_portnum_by_name(&as->codec_if, AudioCoutputs,
1087 AudioNmaster, NULL);
1088 ac97_mixer_set_port(&as->codec_if, &ctl);
1089 ctl.dev = ac97_get_portnum_by_name(&as->codec_if, AudioCoutputs,
1090 AudioNsurround, NULL);
1091 ac97_mixer_set_port(&as->codec_if, &ctl);
1092 ctl.un.value.num_channels = 1;
1093 ctl.dev = ac97_get_portnum_by_name(&as->codec_if, AudioCoutputs,
1094 AudioNcenter, NULL);
1095 ac97_mixer_set_port(&as->codec_if, &ctl);
1096 ctl.dev = ac97_get_portnum_by_name(&as->codec_if, AudioCoutputs,
1097 AudioNlfe, NULL);
1098 ac97_mixer_set_port(&as->codec_if, &ctl);
1099
1100 if (initfunc != NULL)
1101 initfunc(as);
1102 return 0;
1103 }
1104
1105
1106 static int
1107 ac97_query_devinfo(struct ac97_codec_if *codec_if, mixer_devinfo_t *dip)
1108 {
1109 struct ac97_softc *as;
1110 struct ac97_source_info *si;
1111 const char *name;
1112
1113 as = (struct ac97_softc *)codec_if;
1114 if (dip->index < as->num_source_info) {
1115 si = &as->source_info[dip->index];
1116 dip->type = si->type;
1117 dip->mixer_class = si->mixer_class;
1118 dip->prev = si->prev;
1119 dip->next = si->next;
1120
1121 if (si->qualifier)
1122 name = si->qualifier;
1123 else if (si->device)
1124 name = si->device;
1125 else if (si->class)
1126 name = si->class;
1127 else
1128 name = 0;
1129
1130 if (name)
1131 strcpy(dip->label.name, name);
1132
1133 memcpy(&dip->un, si->info, si->info_size);
1134
1135 /* Set the delta for volume sources */
1136 if (dip->type == AUDIO_MIXER_VALUE)
1137 dip->un.v.delta = 1 << (8 - si->bits);
1138
1139 return 0;
1140 }
1141
1142 return ENXIO;
1143 }
1144
1145
1146
1147 static int
1148 ac97_mixer_set_port(struct ac97_codec_if *codec_if, mixer_ctrl_t *cp)
1149 {
1150 struct ac97_softc *as;
1151 struct ac97_source_info *si;
1152 u_int16_t mask;
1153 u_int16_t val, newval;
1154 int error;
1155
1156 as = (struct ac97_softc *)codec_if;
1157 si = &as->source_info[cp->dev];
1158 if (cp->dev < 0 || cp->dev >= as->num_source_info)
1159 return EINVAL;
1160
1161 if (cp->type != si->type)
1162 return EINVAL;
1163
1164 ac97_read(as, si->reg, &val);
1165
1166 DPRINTFN(5, ("read(%x) = %x\n", si->reg, val));
1167
1168 mask = (1 << si->bits) - 1;
1169
1170 switch (cp->type) {
1171 case AUDIO_MIXER_ENUM:
1172 if (cp->un.ord > mask || cp->un.ord < 0)
1173 return EINVAL;
1174
1175 newval = (cp->un.ord << si->ofs);
1176 if (si->reg == AC97_REG_RECORD_SELECT) {
1177 newval |= (newval << (8 + si->ofs));
1178 mask |= (mask << 8);
1179 mask = mask << si->ofs;
1180 } else if (si->reg == AC97_REG_SURR_MASTER) {
1181 newval = cp->un.ord ? 0x8080 : 0x0000;
1182 mask = 0x8080;
1183 } else
1184 mask = mask << si->ofs;
1185 break;
1186 case AUDIO_MIXER_VALUE:
1187 {
1188 const struct audio_mixer_value *value = si->info;
1189 u_int16_t l, r, ol, or;
1190 int deltal, deltar;
1191
1192 if ((cp->un.value.num_channels <= 0) ||
1193 (cp->un.value.num_channels > value->num_channels))
1194 return EINVAL;
1195
1196 if (cp->un.value.num_channels == 1) {
1197 l = r = cp->un.value.level[AUDIO_MIXER_LEVEL_MONO];
1198 } else {
1199 if (!(as->host_flags & AC97_HOST_SWAPPED_CHANNELS)) {
1200 l = cp->un.value.level[AUDIO_MIXER_LEVEL_LEFT];
1201 r = cp->un.value.level[AUDIO_MIXER_LEVEL_RIGHT];
1202 } else { /* left/right is reversed here */
1203 r = cp->un.value.level[AUDIO_MIXER_LEVEL_LEFT];
1204 l = cp->un.value.level[AUDIO_MIXER_LEVEL_RIGHT];
1205 }
1206
1207 }
1208
1209 if (!si->polarity) {
1210 l = 255 - l;
1211 r = 255 - r;
1212 }
1213
1214 ol = (val >> (8+si->ofs)) & mask;
1215 or = (val >> si->ofs) & mask;
1216
1217 deltal = (ol << (8 - si->bits)) - l;
1218 deltar = (or << (8 - si->bits)) - r;
1219
1220 l = l >> (8 - si->bits);
1221 r = r >> (8 - si->bits);
1222
1223 if (deltal && ol == l)
1224 l += (deltal > 0) ? (l ? -1 : 0) : (l < mask ? 1 : 0);
1225 if (deltar && or == r)
1226 r += (deltar > 0) ? (r ? -1 : 0) : (r < mask ? 1 : 0);
1227
1228 newval = ((r & mask) << si->ofs);
1229 if (value->num_channels == 2) {
1230 newval = newval | ((l & mask) << (si->ofs+8));
1231 mask |= (mask << 8);
1232 }
1233 mask = mask << si->ofs;
1234 break;
1235 }
1236 default:
1237 return EINVAL;
1238 }
1239
1240 error = ac97_write(as, si->reg, (val & ~mask) | newval);
1241 if (error)
1242 return error;
1243
1244 return 0;
1245 }
1246
1247 static int
1248 ac97_get_portnum_by_name(struct ac97_codec_if *codec_if, const char *class,
1249 const char *device, const char *qualifier)
1250 {
1251 struct ac97_softc *as;
1252 int idx;
1253
1254 as = (struct ac97_softc *)codec_if;
1255 for (idx = 0; idx < as->num_source_info; idx++) {
1256 struct ac97_source_info *si = &as->source_info[idx];
1257 if (ac97_str_equal(class, si->class) &&
1258 ac97_str_equal(device, si->device) &&
1259 ac97_str_equal(qualifier, si->qualifier))
1260 return idx;
1261 }
1262
1263 return -1;
1264 }
1265
1266 static int
1267 ac97_mixer_get_port(struct ac97_codec_if *codec_if, mixer_ctrl_t *cp)
1268 {
1269 struct ac97_softc *as;
1270 struct ac97_source_info *si;
1271 u_int16_t mask;
1272 u_int16_t val;
1273
1274 as = (struct ac97_softc *)codec_if;
1275 si = &as->source_info[cp->dev];
1276 if (cp->dev < 0 || cp->dev >= as->num_source_info)
1277 return EINVAL;
1278
1279 if (cp->type != si->type)
1280 return EINVAL;
1281
1282 ac97_read(as, si->reg, &val);
1283
1284 DPRINTFN(5, ("read(%x) = %x\n", si->reg, val));
1285
1286 mask = (1 << si->bits) - 1;
1287
1288 switch (cp->type) {
1289 case AUDIO_MIXER_ENUM:
1290 cp->un.ord = (val >> si->ofs) & mask;
1291 DPRINTFN(4, ("AUDIO_MIXER_ENUM: %x %d %x %d\n",
1292 val, si->ofs, mask, cp->un.ord));
1293 break;
1294 case AUDIO_MIXER_VALUE:
1295 {
1296 const struct audio_mixer_value *value = si->info;
1297 u_int16_t l, r;
1298
1299 if ((cp->un.value.num_channels <= 0) ||
1300 (cp->un.value.num_channels > value->num_channels))
1301 return EINVAL;
1302
1303 if (value->num_channels == 1) {
1304 l = r = (val >> si->ofs) & mask;
1305 } else {
1306 if (!(as->host_flags & AC97_HOST_SWAPPED_CHANNELS)) {
1307 l = (val >> (si->ofs + 8)) & mask;
1308 r = (val >> si->ofs) & mask;
1309 } else { /* host has reversed channels */
1310 r = (val >> (si->ofs + 8)) & mask;
1311 l = (val >> si->ofs) & mask;
1312 }
1313 }
1314
1315 l = (l << (8 - si->bits));
1316 r = (r << (8 - si->bits));
1317 if (!si->polarity) {
1318 l = 255 - l;
1319 r = 255 - r;
1320 }
1321
1322 /* The EAP driver averages l and r for stereo
1323 channels that are requested in MONO mode. Does this
1324 make sense? */
1325 if (cp->un.value.num_channels == 1) {
1326 cp->un.value.level[AUDIO_MIXER_LEVEL_MONO] = l;
1327 } else if (cp->un.value.num_channels == 2) {
1328 cp->un.value.level[AUDIO_MIXER_LEVEL_LEFT] = l;
1329 cp->un.value.level[AUDIO_MIXER_LEVEL_RIGHT] = r;
1330 }
1331
1332 break;
1333 }
1334 default:
1335 return EINVAL;
1336 }
1337
1338 return 0;
1339 }
1340
1341
1342 static int
1343 ac97_set_rate(struct ac97_codec_if *codec_if, int target, u_long *rate)
1344 {
1345 struct ac97_softc *as;
1346 u_long value;
1347 u_int16_t ext_stat;
1348 u_int16_t actual;
1349 u_int16_t power;
1350 u_int16_t power_bit;
1351
1352 as = (struct ac97_softc *)codec_if;
1353 if (target == AC97_REG_PCM_MIC_ADC_RATE) {
1354 if (!(as->ext_id & AC97_EXT_AUDIO_VRM)) {
1355 *rate = AC97_SINGLE_RATE;
1356 return 0;
1357 }
1358 } else {
1359 if (!(as->ext_id & AC97_EXT_AUDIO_VRA)) {
1360 *rate = AC97_SINGLE_RATE;
1361 return 0;
1362 }
1363 }
1364 value = *rate * AC97_STANDARD_CLOCK / as->ac97_clock;
1365 ext_stat = 0;
1366 /*
1367 * PCM_FRONT_DAC_RATE/PCM_SURR_DAC_RATE/PCM_LFE_DAC_RATE
1368 * Check VRA, DRA
1369 * PCM_LR_ADC_RATE
1370 * Check VRA
1371 * PCM_MIC_ADC_RATE
1372 * Check VRM
1373 */
1374 switch (target) {
1375 case AC97_REG_PCM_FRONT_DAC_RATE:
1376 case AC97_REG_PCM_SURR_DAC_RATE:
1377 case AC97_REG_PCM_LFE_DAC_RATE:
1378 power_bit = AC97_POWER_OUT;
1379 if (!(as->ext_id & AC97_EXT_AUDIO_VRA)) {
1380 *rate = AC97_SINGLE_RATE;
1381 return 0;
1382 }
1383 if (as->ext_id & AC97_EXT_AUDIO_DRA) {
1384 ac97_read(as, AC97_REG_EXT_AUDIO_CTRL, &ext_stat);
1385 if (value > 0x1ffff) {
1386 return EINVAL;
1387 } else if (value > 0xffff) {
1388 /* Enable DRA */
1389 ext_stat |= AC97_EXT_AUDIO_DRA;
1390 ac97_write(as, AC97_REG_EXT_AUDIO_CTRL, ext_stat);
1391 value /= 2;
1392 } else {
1393 /* Disable DRA */
1394 ext_stat &= ~AC97_EXT_AUDIO_DRA;
1395 ac97_write(as, AC97_REG_EXT_AUDIO_CTRL, ext_stat);
1396 }
1397 } else {
1398 if (value > 0xffff)
1399 return EINVAL;
1400 }
1401 break;
1402 case AC97_REG_PCM_LR_ADC_RATE:
1403 power_bit = AC97_POWER_IN;
1404 if (!(as->ext_id & AC97_EXT_AUDIO_VRA)) {
1405 *rate = AC97_SINGLE_RATE;
1406 return 0;
1407 }
1408 if (value > 0xffff)
1409 return EINVAL;
1410 break;
1411 case AC97_REG_PCM_MIC_ADC_RATE:
1412 power_bit = AC97_POWER_IN;
1413 if (!(as->ext_id & AC97_EXT_AUDIO_VRM)) {
1414 *rate = AC97_SINGLE_RATE;
1415 return 0;
1416 }
1417 if (value > 0xffff)
1418 return EINVAL;
1419 break;
1420 default:
1421 printf("%s: Unknown register: 0x%x\n", __func__, target);
1422 return EINVAL;
1423 }
1424
1425 ac97_read(as, AC97_REG_POWER, &power);
1426 ac97_write(as, AC97_REG_POWER, power | power_bit);
1427
1428 ac97_write(as, target, (u_int16_t)value);
1429 ac97_read(as, target, &actual);
1430 actual = (u_int32_t)actual * as->ac97_clock / AC97_STANDARD_CLOCK;
1431
1432 ac97_write(as, AC97_REG_POWER, power);
1433 if (ext_stat & AC97_EXT_AUDIO_DRA) {
1434 *rate = actual * 2;
1435 } else {
1436 *rate = actual;
1437 }
1438 return 0;
1439 }
1440
1441 static void
1442 ac97_set_clock(struct ac97_codec_if *codec_if, unsigned int clock)
1443 {
1444 struct ac97_softc *as;
1445
1446 as = (struct ac97_softc *)codec_if;
1447 as->ac97_clock = clock;
1448 }
1449
1450 static u_int16_t
1451 ac97_get_extcaps(struct ac97_codec_if *codec_if)
1452 {
1453 struct ac97_softc *as;
1454
1455 as = (struct ac97_softc *)codec_if;
1456 return as->ext_id;
1457 }
1458
1459 static int
1460 ac97_add_port(struct ac97_softc *as, const struct ac97_source_info *src)
1461 {
1462 struct ac97_source_info *si;
1463 int ouridx, idx;
1464
1465 if (as->num_source_info >= MAX_SOURCES) {
1466 printf("%s: internal error: increase MAX_SOURCES in %s\n",
1467 __func__, __FILE__);
1468 return -1;
1469 }
1470 if (!ac97_check_capability(as, src->req_feature))
1471 return -1;
1472 ouridx = as->num_source_info;
1473 si = &as->source_info[ouridx];
1474 memcpy(si, src, sizeof(*si));
1475
1476 switch (si->type) {
1477 case AUDIO_MIXER_CLASS:
1478 case AUDIO_MIXER_VALUE:
1479 printf("%s: adding class/value is not supported yet.\n",
1480 __func__);
1481 return -1;
1482 case AUDIO_MIXER_ENUM:
1483 break;
1484 default:
1485 printf("%s: unknown type: %d\n", __func__, si->type);
1486 return -1;
1487 }
1488 as->num_source_info++;
1489
1490 si->mixer_class = ac97_get_portnum_by_name(&as->codec_if, si->class,
1491 NULL, NULL);
1492 /* Find the root of the device */
1493 idx = ac97_get_portnum_by_name(&as->codec_if, si->class,
1494 si->device, NULL);
1495 /* Find the last item */
1496 while (as->source_info[idx].next != AUDIO_MIXER_LAST)
1497 idx = as->source_info[idx].next;
1498 /* Append */
1499 as->source_info[idx].next = ouridx;
1500 si->prev = idx;
1501 si->next = AUDIO_MIXER_LAST;
1502
1503 return 0;
1504 }
1505
1506 /**
1507 * Codec-dependent initialization
1508 */
1509
1510 #define AD1980_REG_MISC 0x76
1511 #define AD1980_MISC_MBG0 0x0001 /* 0 1888/1980/1981 /1985 */
1512 #define AD1980_MISC_MBG1 0x0002 /* 1 1888/1980/1981 /1985 */
1513 #define AD1980_MISC_VREFD 0x0004 /* 2 1888/1980/1981 /1985 */
1514 #define AD1980_MISC_VREFH 0x0008 /* 3 1888/1980/1981 /1985 */
1515 #define AD1980_MISC_SRU 0x0010 /* 4 1888/1980 /1985 */
1516 #define AD1980_MISC_LOSEL 0x0020 /* 5 1888/1980/1981 /1985 */
1517 #define AD1980_MISC_2CMIC 0x0040 /* 6 1980/1981B/1985 */
1518 #define AD1980_MISC_SPRD 0x0080 /* 7 1888/1980 /1985 */
1519 #define AD1980_MISC_DMIX0 0x0100 /* 8 1888/1980 /1985 */
1520 #define AD1980_MISC_DMIX1 0x0200 /* 9 1888/1980 /1985 */
1521 #define AD1980_MISC_HPSEL 0x0400 /*10 1888/1980 /1985 */
1522 #define AD1980_MISC_CLDIS 0x0800 /*11 1888/1980 /1985 */
1523 #define AD1980_MISC_LODIS 0x1000 /*12 1888/1980/1981 /1985 */
1524 #define AD1980_MISC_MSPLT 0x2000 /*13 1888/1980/1981 /1985 */
1525 #define AD1980_MISC_AC97NC 0x4000 /*14 1888/1980 /1985 */
1526 #define AD1980_MISC_DACZ 0x8000 /*15 1888/1980/1981 /1985 */
1527 #define AD1981_REG_MISC 0x76
1528 #define AD1981_MISC_MADST 0x0010 /* 4 */
1529 #define AD1981A_MISC_MADPD 0x0040 /* 6 */
1530 #define AD1981B_MISC_MADPD 0x0080 /* 7 */
1531 #define AD1981_MISC_FMXE 0x0200 /* 9 */
1532 #define AD1981_MISC_DAM 0x0800 /*11 */
1533 static void
1534 ac97_ad198x_init(struct ac97_softc *as)
1535 {
1536 int i;
1537 uint16_t misc;
1538
1539 ac97_read(as, AD1980_REG_MISC, &misc);
1540 ac97_write(as, AD1980_REG_MISC,
1541 misc | AD1980_MISC_LOSEL | AD1980_MISC_HPSEL);
1542
1543 for (i = 0; i < as->num_source_info; i++) {
1544 if (as->source_info[i].type != AUDIO_MIXER_VALUE)
1545 continue;
1546
1547 if (as->source_info[i].reg == AC97_REG_MASTER_VOLUME)
1548 as->source_info[i].reg = AC97_REG_SURR_MASTER;
1549 else if (as->source_info[i].reg == AC97_REG_SURR_MASTER)
1550 as->source_info[i].reg = AC97_REG_MASTER_VOLUME;
1551 }
1552 }
1553
1554 #define ALC650_REG_MULTI_CHANNEL_CONTROL 0x6a
1555 #define ALC650_MCC_SLOT_MODIFY_MASK 0xc000
1556 #define ALC650_MCC_FRONTDAC_FROM_SPDIFIN 0x2000 /* 13 */
1557 #define ALC650_MCC_SPDIFOUT_FROM_ADC 0x1000 /* 12 */
1558 #define ALC650_MCC_PCM_FROM_SPDIFIN 0x0800 /* 11 */
1559 #define ALC650_MCC_MIC_OR_CENTERLFE 0x0400 /* 10 */
1560 #define ALC650_MCC_LINEIN_OR_SURROUND 0x0200 /* 9 */
1561 #define ALC650_MCC_INDEPENDENT_MASTER_L 0x0080 /* 7 */
1562 #define ALC650_MCC_INDEPENDENT_MASTER_R 0x0040 /* 6 */
1563 #define ALC650_MCC_ANALOG_TO_CENTERLFE 0x0020 /* 5 */
1564 #define ALC650_MCC_ANALOG_TO_SURROUND 0x0010 /* 4 */
1565 #define ALC650_MCC_EXCHANGE_CENTERLFE 0x0008 /* 3 */
1566 #define ALC650_MCC_CENTERLFE_DOWNMIX 0x0004 /* 2 */
1567 #define ALC650_MCC_SURROUND_DOWNMIX 0x0002 /* 1 */
1568 #define ALC650_MCC_LINEOUT_TO_SURROUND 0x0001 /* 0 */
1569 static void
1570 ac97_alc650_init(struct ac97_softc *as)
1571 {
1572 static const struct ac97_source_info sources[6] = {
1573 { AudioCoutputs, AudioNsurround, "lineinjack",
1574 AUDIO_MIXER_ENUM, WRAP(ac97_on_off),
1575 ALC650_REG_MULTI_CHANNEL_CONTROL,
1576 0x0000, 1, 9, 0, 0, CHECK_SURROUND },
1577 { AudioCoutputs, AudioNsurround, "mixtofront",
1578 AUDIO_MIXER_ENUM, WRAP(ac97_on_off),
1579 ALC650_REG_MULTI_CHANNEL_CONTROL,
1580 0x0000, 1, 1, 0, 0, CHECK_SURROUND },
1581 { AudioCoutputs, AudioNcenter, "micjack",
1582 AUDIO_MIXER_ENUM, WRAP(ac97_on_off),
1583 ALC650_REG_MULTI_CHANNEL_CONTROL,
1584 0x0000, 1, 10, 0, 0, CHECK_CENTER },
1585 { AudioCoutputs, AudioNlfe, "micjack",
1586 AUDIO_MIXER_ENUM, WRAP(ac97_on_off),
1587 ALC650_REG_MULTI_CHANNEL_CONTROL,
1588 0x0000, 1, 10, 0, 0, CHECK_LFE },
1589 { AudioCoutputs, AudioNcenter, "mixtofront",
1590 AUDIO_MIXER_ENUM, WRAP(ac97_on_off),
1591 ALC650_REG_MULTI_CHANNEL_CONTROL,
1592 0x0000, 1, 2, 0, 0, CHECK_CENTER },
1593 { AudioCoutputs, AudioNlfe, "mixtofront",
1594 AUDIO_MIXER_ENUM, WRAP(ac97_on_off),
1595 ALC650_REG_MULTI_CHANNEL_CONTROL,
1596 0x0000, 1, 2, 0, 0, CHECK_LFE },
1597 };
1598
1599 ac97_add_port(as, &sources[0]);
1600 ac97_add_port(as, &sources[1]);
1601 ac97_add_port(as, &sources[2]);
1602 ac97_add_port(as, &sources[3]);
1603 ac97_add_port(as, &sources[4]);
1604 ac97_add_port(as, &sources[5]);
1605 }
1606
1607 #define VT1616_REG_IO_CONTROL 0x5a
1608 #define VT1616_IC_LVL (1 << 15)
1609 #define VT1616_IC_LFECENTER_TO_FRONT (1 << 12)
1610 #define VT1616_IC_SURROUND_TO_FRONT (1 << 11)
1611 #define VT1616_IC_BPDC (1 << 10)
1612 #define VT1616_IC_DC (1 << 9)
1613 #define VT1616_IC_IB_MASK 0x000c
1614 static void
1615 ac97_vt1616_init(struct ac97_softc *as)
1616 {
1617 static const struct ac97_source_info sources[3] = {
1618 { AudioCoutputs, AudioNsurround, "mixtofront",
1619 AUDIO_MIXER_ENUM, WRAP(ac97_on_off),
1620 VT1616_REG_IO_CONTROL,
1621 0x0000, 1, 11, 0, 0, CHECK_SURROUND },
1622 { AudioCoutputs, AudioNcenter, "mixtofront",
1623 AUDIO_MIXER_ENUM, WRAP(ac97_on_off),
1624 VT1616_REG_IO_CONTROL,
1625 0x0000, 1, 12, 0, 0, CHECK_CENTER },
1626 { AudioCoutputs, AudioNlfe, "mixtofront",
1627 AUDIO_MIXER_ENUM, WRAP(ac97_on_off),
1628 VT1616_REG_IO_CONTROL,
1629 0x0000, 1, 12, 0, 0, CHECK_LFE },
1630 };
1631
1632 ac97_add_port(as, &sources[0]);
1633 ac97_add_port(as, &sources[1]);
1634 ac97_add_port(as, &sources[2]);
1635 }
1636