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