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