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