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