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