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