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