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