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