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