ac97.c revision 1.62 1 /* $NetBSD: ac97.c,v 1.62 2004/09/22 12:20:24 kent 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.62 2004/09/22 12:20:24 kent 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 /* #define AC97_IO_DEBUG */
676
677 #ifdef AUDIO_DEBUG
678 #define DPRINTF(x) if (ac97debug) printf x
679 #define DPRINTFN(n,x) if (ac97debug>(n)) printf x
680 #ifdef AC97_DEBUG
681 int ac97debug = AC97_DEBUG;
682 #else
683 int ac97debug = 0;
684 #endif
685 #else
686 #define DPRINTF(x)
687 #define DPRINTFN(n,x)
688 #endif
689
690 #ifdef AC97_IO_DEBUG
691 static const char *ac97_register_names[0x80 / 2] = {
692 "RESET", "MASTER_VOLUME", "HEADPHONE_VOLUME", "MASTER_VOLUME_MONO",
693 "MASTER_TONE", "PCBEEP_VOLUME", "PHONE_VOLUME", "MIC_VOLUME",
694 "LINEIN_VOLUME", "CD_VOLUME", "VIDEO_VOLUME", "AUX_VOLUME",
695 "PCMOUT_VOLUME", "RECORD_SELECT", "RECORD_GATIN", "RECORD_GAIN_MIC",
696 "GP", "3D_CONTROL", "AUDIO_INT", "POWER",
697 "EXT_AUDIO_ID", "EXT_AUDIO_CTRL", "PCM_FRONT_DAC_RATE", "PCM_SURR_DAC_RATE",
698 "PCM_LFE_DAC_RATE", "PCM_LR_ADC_RATE", "PCM_MIC_ADC_RATE", "CENTER_LFE_MASTER",
699 "SURR_MASTER", "SPDIF_CTRL", "EXT_MODEM_ID", "EXT_MODEM_CTRL",
700 "LINE1_RATE", "LINE2_RATE", "HANDSET_RATE", "LINE1_LEVEL",
701 "LINE2_LEVEL", "HANDSET_LEVEL", "GPIO_PIN_CONFIG", "GPIO_PIN_POLARITY",
702 "GPIO_PIN_STICKY", "GPIO_PIN_WAKEUP", "GPIO_PIN_STATUS", "MISC_MODEM_CTRL",
703 "0x58", "VENDOR-5A", "VENDOR-5C", "VENDOR-5E",
704 "0x60", "0x62", "0x64", "0x66",
705 "0x68", "0x6a", "0x6c", "0x6e",
706 "VENDOR-70", "VENDOR-72", "VENDOR-74", "VENDOR-76",
707 "VENDOR-78", "VENDOR-7A", "VENDOR_ID1", "VENDOR_ID2"
708 };
709 #endif
710
711 static void
712 ac97_read(struct ac97_softc *as, u_int8_t reg, u_int16_t *val)
713 {
714 if (as->host_flags & AC97_HOST_DONT_READ &&
715 (reg != AC97_REG_VENDOR_ID1 && reg != AC97_REG_VENDOR_ID2 &&
716 reg != AC97_REG_RESET)) {
717 *val = as->shadow_reg[reg >> 1];
718 return;
719 }
720
721 if (as->host_if->read(as->host_if->arg, reg, val)) {
722 *val = as->shadow_reg[reg >> 1];
723 }
724 }
725
726 static int
727 ac97_write(struct ac97_softc *as, u_int8_t reg, u_int16_t val)
728 {
729 #ifndef AC97_IO_DEBUG
730 as->shadow_reg[reg >> 1] = val;
731 return as->host_if->write(as->host_if->arg, reg, val);
732 #else
733 int ret;
734 uint16_t actual;
735
736 as->shadow_reg[reg >> 1] = val;
737 ret = as->host_if->write(as->host_if->arg, reg, val);
738 as->host_if->read(as->host_if->arg, reg, &actual);
739 if (val != actual && reg < 0x80) {
740 printf("ac97_write: reg=%s, written=0x%04x, read=0x%04x\n",
741 ac97_register_names[reg / 2], val, actual);
742 }
743 return ret;
744 #endif
745 }
746
747 static void
748 ac97_setup_defaults(struct ac97_softc *as)
749 {
750 int idx;
751 const struct ac97_source_info *si;
752
753 memset(as->shadow_reg, 0, sizeof(as->shadow_reg));
754
755 for (idx = 0; idx < SOURCE_INFO_SIZE; idx++) {
756 si = &source_info[idx];
757 ac97_write(as, si->reg, si->default_value);
758 }
759 }
760
761 static void
762 ac97_restore_shadow(struct ac97_codec_if *self)
763 {
764 struct ac97_softc *as;
765 const struct ac97_source_info *si;
766 int idx;
767 uint16_t val;
768
769 as = (struct ac97_softc *) self;
770
771 /* make sure chip is fully operational */
772 #define AC97_POWER_ALL (AC97_POWER_REF | AC97_POWER_ANL | AC97_POWER_DAC \
773 | AC97_POWER_ADC)
774 for (idx = 500000; idx >= 0; idx--) {
775 ac97_read(as, AC97_REG_POWER, &val);
776 if ((val & AC97_POWER_ALL) == AC97_POWER_ALL)
777 break;
778 DELAY(1);
779 }
780 #undef AC97_POWER_ALL
781
782 for (idx = 0; idx < SOURCE_INFO_SIZE; idx++) {
783 si = &source_info[idx];
784 /* don't "restore" to the reset reg! */
785 if (si->reg != AC97_REG_RESET)
786 ac97_write(as, si->reg, as->shadow_reg[si->reg >> 1]);
787 }
788
789 if (as->ext_id & (AC97_EXT_AUDIO_VRA | AC97_EXT_AUDIO_DRA
790 | AC97_EXT_AUDIO_SPDIF | AC97_EXT_AUDIO_VRM
791 | AC97_EXT_AUDIO_CDAC | AC97_EXT_AUDIO_SDAC
792 | AC97_EXT_AUDIO_LDAC)) {
793 ac97_write(as, AC97_REG_EXT_AUDIO_CTRL,
794 as->shadow_reg[AC97_REG_EXT_AUDIO_CTRL >> 1]);
795 }
796 }
797
798 static int
799 ac97_str_equal(const char *a, const char *b)
800 {
801 return (a == b) || (a && b && (!strcmp(a, b)));
802 }
803
804 static int
805 ac97_check_capability(struct ac97_softc *as, int check)
806 {
807 switch (check) {
808 case CHECK_NONE:
809 return 1;
810 case CHECK_SURROUND:
811 return as->ext_id & AC97_EXT_AUDIO_SDAC;
812 case CHECK_CENTER:
813 return as->ext_id & AC97_EXT_AUDIO_CDAC;
814 case CHECK_LFE:
815 return as->ext_id & AC97_EXT_AUDIO_LDAC;
816 case CHECK_HEADPHONES:
817 return as->caps & AC97_CAPS_HEADPHONES;
818 case CHECK_TONE:
819 return as->caps & AC97_CAPS_TONECTRL;
820 case CHECK_MIC:
821 return as->caps & AC97_CAPS_MICIN;
822 case CHECK_LOUDNESS:
823 return as->caps & AC97_CAPS_LOUDNESS;
824 case CHECK_3D:
825 return AC97_CAPS_ENHANCEMENT(as->caps) != 0;
826 default:
827 printf("%s: internal error: feature=%d\n", __func__, check);
828 return 0;
829 }
830 }
831
832 static void
833 ac97_setup_source_info(struct ac97_softc *as)
834 {
835 int idx, ouridx;
836 struct ac97_source_info *si, *si2;
837
838 for (idx = 0, ouridx = 0; idx < SOURCE_INFO_SIZE; idx++) {
839 si = &as->source_info[ouridx];
840
841 if (!ac97_check_capability(as, source_info[idx].req_feature))
842 continue;
843
844 memcpy(si, &source_info[idx], sizeof(*si));
845
846 switch (si->type) {
847 case AUDIO_MIXER_CLASS:
848 si->mixer_class = ouridx;
849 ouridx++;
850 break;
851 case AUDIO_MIXER_VALUE:
852 /* Todo - Test to see if it works */
853 ouridx++;
854
855 /* Add an entry for mute, if necessary */
856 if (si->mute) {
857 si = &as->source_info[ouridx];
858 memcpy(si, &source_info[idx], sizeof(*si));
859 si->qualifier = AudioNmute;
860 si->type = AUDIO_MIXER_ENUM;
861 si->info = &ac97_on_off;
862 si->info_size = sizeof(ac97_on_off);
863 si->bits = 1;
864 si->ofs = 15;
865 si->mute = 0;
866 si->polarity = 0;
867 ouridx++;
868 }
869 break;
870 case AUDIO_MIXER_ENUM:
871 /* Todo - Test to see if it works */
872 ouridx++;
873 break;
874 default:
875 aprint_error ("ac97: shouldn't get here\n");
876 break;
877 }
878 }
879
880 as->num_source_info = ouridx;
881
882 for (idx = 0; idx < as->num_source_info; idx++) {
883 int idx2, previdx;
884
885 si = &as->source_info[idx];
886
887 /* Find mixer class */
888 for (idx2 = 0; idx2 < as->num_source_info; idx2++) {
889 si2 = &as->source_info[idx2];
890
891 if (si2->type == AUDIO_MIXER_CLASS &&
892 ac97_str_equal(si->class,
893 si2->class)) {
894 si->mixer_class = idx2;
895 }
896 }
897
898
899 /* Setup prev and next pointers */
900 if (si->prev != 0)
901 continue;
902
903 if (si->qualifier)
904 continue;
905
906 si->prev = AUDIO_MIXER_LAST;
907 previdx = idx;
908
909 for (idx2 = 0; idx2 < as->num_source_info; idx2++) {
910 if (idx2 == idx)
911 continue;
912
913 si2 = &as->source_info[idx2];
914
915 if (!si2->prev &&
916 ac97_str_equal(si->class, si2->class) &&
917 ac97_str_equal(si->device, si2->device)) {
918 as->source_info[previdx].next = idx2;
919 as->source_info[idx2].prev = previdx;
920
921 previdx = idx2;
922 }
923 }
924
925 as->source_info[previdx].next = AUDIO_MIXER_LAST;
926 }
927 }
928
929 int
930 ac97_attach(struct ac97_host_if *host_if)
931 {
932 struct ac97_softc *as;
933 struct device *sc_dev;
934 int error, i, j;
935 uint32_t id;
936 uint16_t id1, id2;
937 uint16_t extstat, rate;
938 uint16_t val;
939 mixer_ctrl_t ctl;
940 void (*initfunc)(struct ac97_softc *);
941 #define FLAGBUFLEN 140
942 char flagbuf[FLAGBUFLEN];
943
944 sc_dev = (struct device *)host_if->arg;
945 initfunc = NULL;
946 as = malloc(sizeof(struct ac97_softc), M_DEVBUF, M_WAITOK|M_ZERO);
947
948 if (as == NULL)
949 return ENOMEM;
950
951 as->codec_if.vtbl = &ac97civ;
952 as->host_if = host_if;
953
954 if ((error = host_if->attach(host_if->arg, &as->codec_if))) {
955 free(as, M_DEVBUF);
956 return error;
957 }
958
959 if ((error = host_if->reset(host_if->arg))) {
960 free(as, M_DEVBUF);
961 return error;
962 }
963
964 host_if->write(host_if->arg, AC97_REG_POWER, 0);
965 host_if->write(host_if->arg, AC97_REG_RESET, 0);
966
967 if (host_if->flags)
968 as->host_flags = host_if->flags(host_if->arg);
969
970 #define AC97_POWER_ALL (AC97_POWER_REF | AC97_POWER_ANL | AC97_POWER_DAC \
971 | AC97_POWER_ADC)
972 for (i = 500000; i >= 0; i--) {
973 ac97_read(as, AC97_REG_POWER, &val);
974 if ((val & AC97_POWER_ALL) == AC97_POWER_ALL)
975 break;
976 DELAY(1);
977 }
978 #undef AC97_POWER_ALL
979
980 ac97_setup_defaults(as);
981 ac97_read(as, AC97_REG_RESET, &as->caps);
982 ac97_read(as, AC97_REG_VENDOR_ID1, &id1);
983 ac97_read(as, AC97_REG_VENDOR_ID2, &id2);
984
985 id = (id1 << 16) | id2;
986
987 aprint_normal("%s: ac97: ", sc_dev->dv_xname);
988
989 for (i = 0; ; i++) {
990 if (ac97codecid[i].id == 0) {
991 char pnp[4];
992
993 AC97_GET_CODEC_ID(id, pnp);
994 #define ISASCII(c) ((c) >= ' ' && (c) < 0x7f)
995 if (ISASCII(pnp[0]) && ISASCII(pnp[1]) &&
996 ISASCII(pnp[2]))
997 aprint_normal("%c%c%c%d",
998 pnp[0], pnp[1], pnp[2], pnp[3]);
999 else
1000 aprint_normal("unknown (0x%08x)", id);
1001 break;
1002 }
1003 if (ac97codecid[i].id == (id & ac97codecid[i].mask)) {
1004 aprint_normal("%s", ac97codecid[i].name);
1005 if (ac97codecid[i].mask == AC97_VENDOR_ID_MASK) {
1006 aprint_normal(" (0x%08x)", id);
1007 }
1008 initfunc = ac97codecid[i].init;
1009 break;
1010 }
1011 }
1012 aprint_normal(" codec; ");
1013 for (i = j = 0; i < 10; i++) {
1014 if (as->caps & (1 << i)) {
1015 aprint_normal("%s%s", j ? ", " : "", ac97feature[i]);
1016 j++;
1017 }
1018 }
1019 aprint_normal("%s%s\n", j ? ", " : "",
1020 ac97enhancement[AC97_CAPS_ENHANCEMENT(as->caps)]);
1021
1022 as->ac97_clock = AC97_STANDARD_CLOCK;
1023 ac97_read(as, AC97_REG_EXT_AUDIO_ID, &as->ext_id);
1024 if (as->ext_id != 0) {
1025 /* Print capabilities */
1026 bitmask_snprintf(as->ext_id, "\20\20SECONDARY10\17SECONDARY01"
1027 "\14AC97_23\13AC97_22\12AMAP\11LDAC\10SDAC"
1028 "\7CDAC\4VRM\3SPDIF\2DRA\1VRA",
1029 flagbuf, FLAGBUFLEN);
1030 aprint_normal("%s: ac97: ext id %s\n", sc_dev->dv_xname, flagbuf);
1031
1032 /* Print unusual settings */
1033 if (as->ext_id & AC97_EXT_AUDIO_DSA_MASK) {
1034 aprint_normal("%s: ac97: Slot assignment: ",
1035 sc_dev->dv_xname);
1036 switch (as->ext_id & AC97_EXT_AUDIO_DSA_MASK) {
1037 case AC97_EXT_AUDIO_DSA01:
1038 aprint_normal("7&8, 6&9, 10&11.\n");
1039 break;
1040 case AC97_EXT_AUDIO_DSA10:
1041 aprint_normal("6&9, 10&11, 3&4.\n");
1042 break;
1043 case AC97_EXT_AUDIO_DSA11:
1044 aprint_normal("10&11, 3&4, 7&8.\n");
1045 break;
1046 }
1047 }
1048
1049 /* Enable and disable features */
1050 ac97_read(as, AC97_REG_EXT_AUDIO_CTRL, &extstat);
1051 extstat &= ~AC97_EXT_AUDIO_DRA;
1052 if (as->ext_id & AC97_EXT_AUDIO_LDAC)
1053 extstat |= AC97_EXT_AUDIO_LDAC;
1054 if (as->ext_id & AC97_EXT_AUDIO_SDAC)
1055 extstat |= AC97_EXT_AUDIO_SDAC;
1056 if (as->ext_id & AC97_EXT_AUDIO_CDAC)
1057 extstat |= AC97_EXT_AUDIO_CDAC;
1058 if (as->ext_id & AC97_EXT_AUDIO_VRM)
1059 extstat |= AC97_EXT_AUDIO_VRM;
1060 if (as->ext_id & AC97_EXT_AUDIO_SPDIF) {
1061 /* Output the same data as DAC to SPDIF output */
1062 extstat &= ~AC97_EXT_AUDIO_SPSA_MASK;
1063 extstat |= AC97_EXT_AUDIO_SPSA34;
1064 }
1065 if (as->ext_id & AC97_EXT_AUDIO_VRA)
1066 extstat |= AC97_EXT_AUDIO_VRA;
1067 ac97_write(as, AC97_REG_EXT_AUDIO_CTRL, extstat);
1068 if (as->ext_id & AC97_EXT_AUDIO_VRA) {
1069 /* VRA should be enabled. */
1070 /* so it claims to do variable rate, let's make sure */
1071 ac97_write(as, AC97_REG_PCM_FRONT_DAC_RATE, 44100);
1072 ac97_read(as, AC97_REG_PCM_FRONT_DAC_RATE, &rate);
1073 if (rate != 44100) {
1074 /* We can't believe ext_id */
1075 as->ext_id = 0;
1076 aprint_normal(
1077 "%s: Ignore these capabilities.\n",
1078 sc_dev->dv_xname);
1079 }
1080 /* restore the default value */
1081 ac97_write(as, AC97_REG_PCM_FRONT_DAC_RATE,
1082 AC97_SINGLE_RATE);
1083 }
1084 }
1085
1086 ac97_setup_source_info(as);
1087
1088 memset(&ctl, 0, sizeof(ctl));
1089 /* disable mutes */
1090 for (i = 0; i < 11; i++) {
1091 static struct {
1092 char *class, *device;
1093 } d[11] = {
1094 { AudioCoutputs, AudioNmaster},
1095 { AudioCoutputs, AudioNheadphone},
1096 { AudioCoutputs, AudioNsurround},
1097 { AudioCoutputs, AudioNcenter},
1098 { AudioCoutputs, AudioNlfe},
1099 { AudioCinputs, AudioNdac},
1100 { AudioCinputs, AudioNcd},
1101 { AudioCinputs, AudioNline},
1102 { AudioCinputs, AudioNaux},
1103 { AudioCinputs, AudioNvideo},
1104 { AudioCrecord, AudioNvolume},
1105 };
1106
1107 ctl.type = AUDIO_MIXER_ENUM;
1108 ctl.un.ord = 0;
1109
1110 ctl.dev = ac97_get_portnum_by_name(&as->codec_if,
1111 d[i].class, d[i].device, AudioNmute);
1112 ac97_mixer_set_port(&as->codec_if, &ctl);
1113 }
1114 ctl.type = AUDIO_MIXER_ENUM;
1115 ctl.un.ord = 0;
1116 ctl.dev = ac97_get_portnum_by_name(&as->codec_if, AudioCrecord,
1117 AudioNsource, NULL);
1118 ac97_mixer_set_port(&as->codec_if, &ctl);
1119
1120 /* set a reasonable default volume */
1121 ctl.type = AUDIO_MIXER_VALUE;
1122 ctl.un.value.num_channels = 2;
1123 ctl.un.value.level[AUDIO_MIXER_LEVEL_LEFT] = \
1124 ctl.un.value.level[AUDIO_MIXER_LEVEL_RIGHT] = 127;
1125 ctl.dev = ac97_get_portnum_by_name(&as->codec_if, AudioCoutputs,
1126 AudioNmaster, NULL);
1127 ac97_mixer_set_port(&as->codec_if, &ctl);
1128 ctl.dev = ac97_get_portnum_by_name(&as->codec_if, AudioCoutputs,
1129 AudioNsurround, NULL);
1130 ac97_mixer_set_port(&as->codec_if, &ctl);
1131 ctl.un.value.num_channels = 1;
1132 ctl.dev = ac97_get_portnum_by_name(&as->codec_if, AudioCoutputs,
1133 AudioNcenter, NULL);
1134 ac97_mixer_set_port(&as->codec_if, &ctl);
1135 ctl.dev = ac97_get_portnum_by_name(&as->codec_if, AudioCoutputs,
1136 AudioNlfe, NULL);
1137 ac97_mixer_set_port(&as->codec_if, &ctl);
1138
1139 if (initfunc != NULL)
1140 initfunc(as);
1141 return 0;
1142 }
1143
1144
1145 static int
1146 ac97_query_devinfo(struct ac97_codec_if *codec_if, mixer_devinfo_t *dip)
1147 {
1148 struct ac97_softc *as;
1149 struct ac97_source_info *si;
1150 const char *name;
1151
1152 as = (struct ac97_softc *)codec_if;
1153 if (dip->index < as->num_source_info) {
1154 si = &as->source_info[dip->index];
1155 dip->type = si->type;
1156 dip->mixer_class = si->mixer_class;
1157 dip->prev = si->prev;
1158 dip->next = si->next;
1159
1160 if (si->qualifier)
1161 name = si->qualifier;
1162 else if (si->device)
1163 name = si->device;
1164 else if (si->class)
1165 name = si->class;
1166 else
1167 name = 0;
1168
1169 if (name)
1170 strcpy(dip->label.name, name);
1171
1172 memcpy(&dip->un, si->info, si->info_size);
1173
1174 /* Set the delta for volume sources */
1175 if (dip->type == AUDIO_MIXER_VALUE)
1176 dip->un.v.delta = 1 << (8 - si->bits);
1177
1178 return 0;
1179 }
1180
1181 return ENXIO;
1182 }
1183
1184
1185
1186 static int
1187 ac97_mixer_set_port(struct ac97_codec_if *codec_if, mixer_ctrl_t *cp)
1188 {
1189 struct ac97_softc *as;
1190 struct ac97_source_info *si;
1191 u_int16_t mask;
1192 u_int16_t val, newval;
1193 int error;
1194
1195 as = (struct ac97_softc *)codec_if;
1196 si = &as->source_info[cp->dev];
1197 if (cp->dev < 0 || cp->dev >= as->num_source_info)
1198 return EINVAL;
1199
1200 if (cp->type != si->type)
1201 return EINVAL;
1202
1203 ac97_read(as, si->reg, &val);
1204
1205 DPRINTFN(5, ("read(%x) = %x\n", si->reg, val));
1206
1207 mask = (1 << si->bits) - 1;
1208
1209 switch (cp->type) {
1210 case AUDIO_MIXER_ENUM:
1211 if (cp->un.ord > mask || cp->un.ord < 0)
1212 return EINVAL;
1213
1214 newval = (cp->un.ord << si->ofs);
1215 if (si->reg == AC97_REG_RECORD_SELECT) {
1216 newval |= (newval << (8 + si->ofs));
1217 mask |= (mask << 8);
1218 mask = mask << si->ofs;
1219 } else if (si->reg == AC97_REG_SURR_MASTER) {
1220 newval = cp->un.ord ? 0x8080 : 0x0000;
1221 mask = 0x8080;
1222 } else
1223 mask = mask << si->ofs;
1224 break;
1225 case AUDIO_MIXER_VALUE:
1226 {
1227 const struct audio_mixer_value *value = si->info;
1228 u_int16_t l, r, ol, or;
1229 int deltal, deltar;
1230
1231 if ((cp->un.value.num_channels <= 0) ||
1232 (cp->un.value.num_channels > value->num_channels))
1233 return EINVAL;
1234
1235 if (cp->un.value.num_channels == 1) {
1236 l = r = cp->un.value.level[AUDIO_MIXER_LEVEL_MONO];
1237 } else {
1238 if (!(as->host_flags & AC97_HOST_SWAPPED_CHANNELS)) {
1239 l = cp->un.value.level[AUDIO_MIXER_LEVEL_LEFT];
1240 r = cp->un.value.level[AUDIO_MIXER_LEVEL_RIGHT];
1241 } else { /* left/right is reversed here */
1242 r = cp->un.value.level[AUDIO_MIXER_LEVEL_LEFT];
1243 l = cp->un.value.level[AUDIO_MIXER_LEVEL_RIGHT];
1244 }
1245
1246 }
1247
1248 if (!si->polarity) {
1249 l = 255 - l;
1250 r = 255 - r;
1251 }
1252
1253 ol = (val >> (8+si->ofs)) & mask;
1254 or = (val >> si->ofs) & mask;
1255
1256 deltal = (ol << (8 - si->bits)) - l;
1257 deltar = (or << (8 - si->bits)) - r;
1258
1259 l = l >> (8 - si->bits);
1260 r = r >> (8 - si->bits);
1261
1262 if (deltal && ol == l)
1263 l += (deltal > 0) ? (l ? -1 : 0) : (l < mask ? 1 : 0);
1264 if (deltar && or == r)
1265 r += (deltar > 0) ? (r ? -1 : 0) : (r < mask ? 1 : 0);
1266
1267 newval = ((r & mask) << si->ofs);
1268 if (value->num_channels == 2) {
1269 newval = newval | ((l & mask) << (si->ofs+8));
1270 mask |= (mask << 8);
1271 }
1272 mask = mask << si->ofs;
1273 break;
1274 }
1275 default:
1276 return EINVAL;
1277 }
1278
1279 error = ac97_write(as, si->reg, (val & ~mask) | newval);
1280 if (error)
1281 return error;
1282
1283 return 0;
1284 }
1285
1286 static int
1287 ac97_get_portnum_by_name(struct ac97_codec_if *codec_if, const char *class,
1288 const char *device, const char *qualifier)
1289 {
1290 struct ac97_softc *as;
1291 int idx;
1292
1293 as = (struct ac97_softc *)codec_if;
1294 for (idx = 0; idx < as->num_source_info; idx++) {
1295 struct ac97_source_info *si = &as->source_info[idx];
1296 if (ac97_str_equal(class, si->class) &&
1297 ac97_str_equal(device, si->device) &&
1298 ac97_str_equal(qualifier, si->qualifier))
1299 return idx;
1300 }
1301
1302 return -1;
1303 }
1304
1305 static int
1306 ac97_mixer_get_port(struct ac97_codec_if *codec_if, mixer_ctrl_t *cp)
1307 {
1308 struct ac97_softc *as;
1309 struct ac97_source_info *si;
1310 u_int16_t mask;
1311 u_int16_t val;
1312
1313 as = (struct ac97_softc *)codec_if;
1314 si = &as->source_info[cp->dev];
1315 if (cp->dev < 0 || cp->dev >= as->num_source_info)
1316 return EINVAL;
1317
1318 if (cp->type != si->type)
1319 return EINVAL;
1320
1321 ac97_read(as, si->reg, &val);
1322
1323 DPRINTFN(5, ("read(%x) = %x\n", si->reg, val));
1324
1325 mask = (1 << si->bits) - 1;
1326
1327 switch (cp->type) {
1328 case AUDIO_MIXER_ENUM:
1329 cp->un.ord = (val >> si->ofs) & mask;
1330 DPRINTFN(4, ("AUDIO_MIXER_ENUM: %x %d %x %d\n",
1331 val, si->ofs, mask, cp->un.ord));
1332 break;
1333 case AUDIO_MIXER_VALUE:
1334 {
1335 const struct audio_mixer_value *value = si->info;
1336 u_int16_t l, r;
1337
1338 if ((cp->un.value.num_channels <= 0) ||
1339 (cp->un.value.num_channels > value->num_channels))
1340 return EINVAL;
1341
1342 if (value->num_channels == 1) {
1343 l = r = (val >> si->ofs) & mask;
1344 } else {
1345 if (!(as->host_flags & AC97_HOST_SWAPPED_CHANNELS)) {
1346 l = (val >> (si->ofs + 8)) & mask;
1347 r = (val >> si->ofs) & mask;
1348 } else { /* host has reversed channels */
1349 r = (val >> (si->ofs + 8)) & mask;
1350 l = (val >> si->ofs) & mask;
1351 }
1352 }
1353
1354 l = (l << (8 - si->bits));
1355 r = (r << (8 - si->bits));
1356 if (!si->polarity) {
1357 l = 255 - l;
1358 r = 255 - r;
1359 }
1360
1361 /* The EAP driver averages l and r for stereo
1362 channels that are requested in MONO mode. Does this
1363 make sense? */
1364 if (cp->un.value.num_channels == 1) {
1365 cp->un.value.level[AUDIO_MIXER_LEVEL_MONO] = l;
1366 } else if (cp->un.value.num_channels == 2) {
1367 cp->un.value.level[AUDIO_MIXER_LEVEL_LEFT] = l;
1368 cp->un.value.level[AUDIO_MIXER_LEVEL_RIGHT] = r;
1369 }
1370
1371 break;
1372 }
1373 default:
1374 return EINVAL;
1375 }
1376
1377 return 0;
1378 }
1379
1380
1381 static int
1382 ac97_set_rate(struct ac97_codec_if *codec_if, int target, u_long *rate)
1383 {
1384 struct ac97_softc *as;
1385 u_long value;
1386 u_int16_t ext_stat;
1387 u_int16_t actual;
1388 u_int16_t power;
1389 u_int16_t power_bit;
1390
1391 as = (struct ac97_softc *)codec_if;
1392 if (target == AC97_REG_PCM_MIC_ADC_RATE) {
1393 if (!(as->ext_id & AC97_EXT_AUDIO_VRM)) {
1394 *rate = AC97_SINGLE_RATE;
1395 return 0;
1396 }
1397 } else {
1398 if (!(as->ext_id & AC97_EXT_AUDIO_VRA)) {
1399 *rate = AC97_SINGLE_RATE;
1400 return 0;
1401 }
1402 }
1403 value = *rate * AC97_STANDARD_CLOCK / as->ac97_clock;
1404 ext_stat = 0;
1405 /*
1406 * PCM_FRONT_DAC_RATE/PCM_SURR_DAC_RATE/PCM_LFE_DAC_RATE
1407 * Check VRA, DRA
1408 * PCM_LR_ADC_RATE
1409 * Check VRA
1410 * PCM_MIC_ADC_RATE
1411 * Check VRM
1412 */
1413 switch (target) {
1414 case AC97_REG_PCM_FRONT_DAC_RATE:
1415 case AC97_REG_PCM_SURR_DAC_RATE:
1416 case AC97_REG_PCM_LFE_DAC_RATE:
1417 power_bit = AC97_POWER_OUT;
1418 if (!(as->ext_id & AC97_EXT_AUDIO_VRA)) {
1419 *rate = AC97_SINGLE_RATE;
1420 return 0;
1421 }
1422 if (as->ext_id & AC97_EXT_AUDIO_DRA) {
1423 ac97_read(as, AC97_REG_EXT_AUDIO_CTRL, &ext_stat);
1424 if (value > 0x1ffff) {
1425 return EINVAL;
1426 } else if (value > 0xffff) {
1427 /* Enable DRA */
1428 ext_stat |= AC97_EXT_AUDIO_DRA;
1429 ac97_write(as, AC97_REG_EXT_AUDIO_CTRL, ext_stat);
1430 value /= 2;
1431 } else {
1432 /* Disable DRA */
1433 ext_stat &= ~AC97_EXT_AUDIO_DRA;
1434 ac97_write(as, AC97_REG_EXT_AUDIO_CTRL, ext_stat);
1435 }
1436 } else {
1437 if (value > 0xffff)
1438 return EINVAL;
1439 }
1440 break;
1441 case AC97_REG_PCM_LR_ADC_RATE:
1442 power_bit = AC97_POWER_IN;
1443 if (!(as->ext_id & AC97_EXT_AUDIO_VRA)) {
1444 *rate = AC97_SINGLE_RATE;
1445 return 0;
1446 }
1447 if (value > 0xffff)
1448 return EINVAL;
1449 break;
1450 case AC97_REG_PCM_MIC_ADC_RATE:
1451 power_bit = AC97_POWER_IN;
1452 if (!(as->ext_id & AC97_EXT_AUDIO_VRM)) {
1453 *rate = AC97_SINGLE_RATE;
1454 return 0;
1455 }
1456 if (value > 0xffff)
1457 return EINVAL;
1458 break;
1459 default:
1460 printf("%s: Unknown register: 0x%x\n", __func__, target);
1461 return EINVAL;
1462 }
1463
1464 ac97_read(as, AC97_REG_POWER, &power);
1465 ac97_write(as, AC97_REG_POWER, power | power_bit);
1466
1467 ac97_write(as, target, (u_int16_t)value);
1468 ac97_read(as, target, &actual);
1469 actual = (u_int32_t)actual * as->ac97_clock / AC97_STANDARD_CLOCK;
1470
1471 ac97_write(as, AC97_REG_POWER, power);
1472 if (ext_stat & AC97_EXT_AUDIO_DRA) {
1473 *rate = actual * 2;
1474 } else {
1475 *rate = actual;
1476 }
1477 return 0;
1478 }
1479
1480 static void
1481 ac97_set_clock(struct ac97_codec_if *codec_if, unsigned int clock)
1482 {
1483 struct ac97_softc *as;
1484
1485 as = (struct ac97_softc *)codec_if;
1486 as->ac97_clock = clock;
1487 }
1488
1489 static u_int16_t
1490 ac97_get_extcaps(struct ac97_codec_if *codec_if)
1491 {
1492 struct ac97_softc *as;
1493
1494 as = (struct ac97_softc *)codec_if;
1495 return as->ext_id;
1496 }
1497
1498 static int
1499 ac97_add_port(struct ac97_softc *as, const struct ac97_source_info *src)
1500 {
1501 struct ac97_source_info *si;
1502 int ouridx, idx;
1503
1504 if (as->num_source_info >= MAX_SOURCES) {
1505 printf("%s: internal error: increase MAX_SOURCES in %s\n",
1506 __func__, __FILE__);
1507 return -1;
1508 }
1509 if (!ac97_check_capability(as, src->req_feature))
1510 return -1;
1511 ouridx = as->num_source_info;
1512 si = &as->source_info[ouridx];
1513 memcpy(si, src, sizeof(*si));
1514
1515 switch (si->type) {
1516 case AUDIO_MIXER_CLASS:
1517 case AUDIO_MIXER_VALUE:
1518 printf("%s: adding class/value is not supported yet.\n",
1519 __func__);
1520 return -1;
1521 case AUDIO_MIXER_ENUM:
1522 break;
1523 default:
1524 printf("%s: unknown type: %d\n", __func__, si->type);
1525 return -1;
1526 }
1527 as->num_source_info++;
1528
1529 si->mixer_class = ac97_get_portnum_by_name(&as->codec_if, si->class,
1530 NULL, NULL);
1531 /* Find the root of the device */
1532 idx = ac97_get_portnum_by_name(&as->codec_if, si->class,
1533 si->device, NULL);
1534 /* Find the last item */
1535 while (as->source_info[idx].next != AUDIO_MIXER_LAST)
1536 idx = as->source_info[idx].next;
1537 /* Append */
1538 as->source_info[idx].next = ouridx;
1539 si->prev = idx;
1540 si->next = AUDIO_MIXER_LAST;
1541
1542 return 0;
1543 }
1544
1545 /**
1546 * Codec-dependent initialization
1547 */
1548
1549 #define AD1980_REG_MISC 0x76
1550 #define AD1980_MISC_MBG0 0x0001 /* 0 1888/1980/1981 /1985 */
1551 #define AD1980_MISC_MBG1 0x0002 /* 1 1888/1980/1981 /1985 */
1552 #define AD1980_MISC_VREFD 0x0004 /* 2 1888/1980/1981 /1985 */
1553 #define AD1980_MISC_VREFH 0x0008 /* 3 1888/1980/1981 /1985 */
1554 #define AD1980_MISC_SRU 0x0010 /* 4 1888/1980 /1985 */
1555 #define AD1980_MISC_LOSEL 0x0020 /* 5 1888/1980/1981 /1985 */
1556 #define AD1980_MISC_2CMIC 0x0040 /* 6 1980/1981B/1985 */
1557 #define AD1980_MISC_SPRD 0x0080 /* 7 1888/1980 /1985 */
1558 #define AD1980_MISC_DMIX0 0x0100 /* 8 1888/1980 /1985 */
1559 #define AD1980_MISC_DMIX1 0x0200 /* 9 1888/1980 /1985 */
1560 #define AD1980_MISC_HPSEL 0x0400 /*10 1888/1980 /1985 */
1561 #define AD1980_MISC_CLDIS 0x0800 /*11 1888/1980 /1985 */
1562 #define AD1980_MISC_LODIS 0x1000 /*12 1888/1980/1981 /1985 */
1563 #define AD1980_MISC_MSPLT 0x2000 /*13 1888/1980/1981 /1985 */
1564 #define AD1980_MISC_AC97NC 0x4000 /*14 1888/1980 /1985 */
1565 #define AD1980_MISC_DACZ 0x8000 /*15 1888/1980/1981 /1985 */
1566 #define AD1981_REG_MISC 0x76
1567 #define AD1981_MISC_MADST 0x0010 /* 4 */
1568 #define AD1981A_MISC_MADPD 0x0040 /* 6 */
1569 #define AD1981B_MISC_MADPD 0x0080 /* 7 */
1570 #define AD1981_MISC_FMXE 0x0200 /* 9 */
1571 #define AD1981_MISC_DAM 0x0800 /*11 */
1572 static void
1573 ac97_ad198x_init(struct ac97_softc *as)
1574 {
1575 int i;
1576 uint16_t misc;
1577
1578 ac97_read(as, AD1980_REG_MISC, &misc);
1579 ac97_write(as, AD1980_REG_MISC,
1580 misc | AD1980_MISC_LOSEL | AD1980_MISC_HPSEL);
1581
1582 for (i = 0; i < as->num_source_info; i++) {
1583 if (as->source_info[i].type != AUDIO_MIXER_VALUE)
1584 continue;
1585
1586 if (as->source_info[i].reg == AC97_REG_MASTER_VOLUME)
1587 as->source_info[i].reg = AC97_REG_SURR_MASTER;
1588 else if (as->source_info[i].reg == AC97_REG_SURR_MASTER)
1589 as->source_info[i].reg = AC97_REG_MASTER_VOLUME;
1590 }
1591 }
1592
1593 #define ALC650_REG_MULTI_CHANNEL_CONTROL 0x6a
1594 #define ALC650_MCC_SLOT_MODIFY_MASK 0xc000
1595 #define ALC650_MCC_FRONTDAC_FROM_SPDIFIN 0x2000 /* 13 */
1596 #define ALC650_MCC_SPDIFOUT_FROM_ADC 0x1000 /* 12 */
1597 #define ALC650_MCC_PCM_FROM_SPDIFIN 0x0800 /* 11 */
1598 #define ALC650_MCC_MIC_OR_CENTERLFE 0x0400 /* 10 */
1599 #define ALC650_MCC_LINEIN_OR_SURROUND 0x0200 /* 9 */
1600 #define ALC650_MCC_INDEPENDENT_MASTER_L 0x0080 /* 7 */
1601 #define ALC650_MCC_INDEPENDENT_MASTER_R 0x0040 /* 6 */
1602 #define ALC650_MCC_ANALOG_TO_CENTERLFE 0x0020 /* 5 */
1603 #define ALC650_MCC_ANALOG_TO_SURROUND 0x0010 /* 4 */
1604 #define ALC650_MCC_EXCHANGE_CENTERLFE 0x0008 /* 3 */
1605 #define ALC650_MCC_CENTERLFE_DOWNMIX 0x0004 /* 2 */
1606 #define ALC650_MCC_SURROUND_DOWNMIX 0x0002 /* 1 */
1607 #define ALC650_MCC_LINEOUT_TO_SURROUND 0x0001 /* 0 */
1608 static void
1609 ac97_alc650_init(struct ac97_softc *as)
1610 {
1611 static const struct ac97_source_info sources[6] = {
1612 { AudioCoutputs, AudioNsurround, "lineinjack",
1613 AUDIO_MIXER_ENUM, WRAP(ac97_on_off),
1614 ALC650_REG_MULTI_CHANNEL_CONTROL,
1615 0x0000, 1, 9, 0, 0, CHECK_SURROUND },
1616 { AudioCoutputs, AudioNsurround, "mixtofront",
1617 AUDIO_MIXER_ENUM, WRAP(ac97_on_off),
1618 ALC650_REG_MULTI_CHANNEL_CONTROL,
1619 0x0000, 1, 1, 0, 0, CHECK_SURROUND },
1620 { AudioCoutputs, AudioNcenter, "micjack",
1621 AUDIO_MIXER_ENUM, WRAP(ac97_on_off),
1622 ALC650_REG_MULTI_CHANNEL_CONTROL,
1623 0x0000, 1, 10, 0, 0, CHECK_CENTER },
1624 { AudioCoutputs, AudioNlfe, "micjack",
1625 AUDIO_MIXER_ENUM, WRAP(ac97_on_off),
1626 ALC650_REG_MULTI_CHANNEL_CONTROL,
1627 0x0000, 1, 10, 0, 0, CHECK_LFE },
1628 { AudioCoutputs, AudioNcenter, "mixtofront",
1629 AUDIO_MIXER_ENUM, WRAP(ac97_on_off),
1630 ALC650_REG_MULTI_CHANNEL_CONTROL,
1631 0x0000, 1, 2, 0, 0, CHECK_CENTER },
1632 { AudioCoutputs, AudioNlfe, "mixtofront",
1633 AUDIO_MIXER_ENUM, WRAP(ac97_on_off),
1634 ALC650_REG_MULTI_CHANNEL_CONTROL,
1635 0x0000, 1, 2, 0, 0, CHECK_LFE },
1636 };
1637
1638 ac97_add_port(as, &sources[0]);
1639 ac97_add_port(as, &sources[1]);
1640 ac97_add_port(as, &sources[2]);
1641 ac97_add_port(as, &sources[3]);
1642 ac97_add_port(as, &sources[4]);
1643 ac97_add_port(as, &sources[5]);
1644 }
1645
1646 #define VT1616_REG_IO_CONTROL 0x5a
1647 #define VT1616_IC_LVL (1 << 15)
1648 #define VT1616_IC_LFECENTER_TO_FRONT (1 << 12)
1649 #define VT1616_IC_SURROUND_TO_FRONT (1 << 11)
1650 #define VT1616_IC_BPDC (1 << 10)
1651 #define VT1616_IC_DC (1 << 9)
1652 #define VT1616_IC_IB_MASK 0x000c
1653 static void
1654 ac97_vt1616_init(struct ac97_softc *as)
1655 {
1656 static const struct ac97_source_info sources[3] = {
1657 { AudioCoutputs, AudioNsurround, "mixtofront",
1658 AUDIO_MIXER_ENUM, WRAP(ac97_on_off),
1659 VT1616_REG_IO_CONTROL,
1660 0x0000, 1, 11, 0, 0, CHECK_SURROUND },
1661 { AudioCoutputs, AudioNcenter, "mixtofront",
1662 AUDIO_MIXER_ENUM, WRAP(ac97_on_off),
1663 VT1616_REG_IO_CONTROL,
1664 0x0000, 1, 12, 0, 0, CHECK_CENTER },
1665 { AudioCoutputs, AudioNlfe, "mixtofront",
1666 AUDIO_MIXER_ENUM, WRAP(ac97_on_off),
1667 VT1616_REG_IO_CONTROL,
1668 0x0000, 1, 12, 0, 0, CHECK_LFE },
1669 };
1670
1671 ac97_add_port(as, &sources[0]);
1672 ac97_add_port(as, &sources[1]);
1673 ac97_add_port(as, &sources[2]);
1674 }
1675