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