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