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