Sync usage with man page.
[netbsd-mini2440.git] / sys / dev / ic / ac97.c
blob039abbc1a8d1d5712e53676fc29494c4631dd623
1 /* $NetBSD: ac97.c,v 1.90 2009/05/12 14:25:17 cegger Exp $ */
2 /* $OpenBSD: ac97.c,v 1.8 2000/07/19 09:01:35 csapuntz Exp $ */
4 /*
5 * Copyright (c) 1999, 2000 Constantine Sapuntzakis
7 * Author: Constantine Sapuntzakis <csapuntz@stanford.edu>
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
34 /* Partially inspired by FreeBSD's sys/dev/pcm/ac97.c. It came with
35 the following copyright */
38 * Copyright (c) 1999 Cameron Grant <gandalf@vilnya.demon.co.uk>
39 * All rights reserved.
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.
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.
62 * $FreeBSD$
65 #include <sys/cdefs.h>
66 __KERNEL_RCSID(0, "$NetBSD: ac97.c,v 1.90 2009/05/12 14:25:17 cegger Exp $");
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 #include <sys/sysctl.h>
75 #include <sys/audioio.h>
76 #include <dev/audio_if.h>
78 #include <dev/ic/ac97reg.h>
79 #include <dev/ic/ac97var.h>
81 struct ac97_softc;
82 struct ac97_source_info;
83 static int ac97_mixer_get_port(struct ac97_codec_if *, mixer_ctrl_t *);
84 static int ac97_mixer_set_port(struct ac97_codec_if *, mixer_ctrl_t *);
85 static void ac97_detach(struct ac97_codec_if *);
86 static void ac97_lock(struct ac97_codec_if *);
87 static void ac97_unlock(struct ac97_codec_if *);
88 static int ac97_query_devinfo(struct ac97_codec_if *, mixer_devinfo_t *);
89 static int ac97_get_portnum_by_name(struct ac97_codec_if *, const char *,
90 const char *, const char *);
91 static void ac97_restore_shadow(struct ac97_codec_if *);
92 static int ac97_set_rate(struct ac97_codec_if *, int, u_int *);
93 static void ac97_set_clock(struct ac97_codec_if *, unsigned int);
94 static uint16_t ac97_get_extcaps(struct ac97_codec_if *);
95 static int ac97_add_port(struct ac97_softc *,
96 const struct ac97_source_info *);
97 static int ac97_str_equal(const char *, const char *);
98 static int ac97_check_capability(struct ac97_softc *, int);
99 static void ac97_setup_source_info(struct ac97_softc *);
100 static void ac97_read(struct ac97_softc *, uint8_t, uint16_t *);
101 static void ac97_setup_defaults(struct ac97_softc *);
102 static int ac97_write(struct ac97_softc *, uint8_t, uint16_t);
104 static void ac97_ad198x_init(struct ac97_softc *);
105 static void ac97_alc650_init(struct ac97_softc *);
106 static void ac97_ucb1400_init(struct ac97_softc *);
107 static void ac97_vt1616_init(struct ac97_softc *);
109 static int ac97_modem_offhook_set(struct ac97_softc *, int, int);
110 static int ac97_sysctl_verify(SYSCTLFN_ARGS);
112 #define Ac97Nphone "phone"
113 #define Ac97Nline1 "line1"
114 #define Ac97Nline2 "line2"
115 #define Ac97Nhandset "handset"
117 static const struct audio_mixer_enum
118 ac97_on_off = { 2, { { { AudioNoff, 0 } , 0 },
119 { { AudioNon, 0 } , 1 },
120 { { "", 0 } , 0 },
121 { { "", 0 } , 0 },
122 { { "", 0 } , 0 },
123 { { "", 0 } , 0 },
124 { { "", 0 } , 0 },
125 { { "", 0 } , 0 },
126 { { "", 0 } , 0 },
127 { { "", 0 } , 0 },
128 { { "", 0 } , 0 },
129 { { "", 0 } , 0 },
130 { { "", 0 } , 0 },
131 { { "", 0 } , 0 },
132 { { "", 0 } , 0 },
133 { { "", 0 } , 0 },
134 { { "", 0 } , 0 },
135 { { "", 0 } , 0 },
136 { { "", 0 } , 0 },
137 { { "", 0 } , 0 },
138 { { "", 0 } , 0 },
139 { { "", 0 } , 0 },
140 { { "", 0 } , 0 },
141 { { "", 0 } , 0 },
142 { { "", 0 } , 0 },
143 { { "", 0 } , 0 },
144 { { "", 0 } , 0 },
145 { { "", 0 } , 0 },
146 { { "", 0 } , 0 },
147 { { "", 0 } , 0 },
148 { { "", 0 } , 0 },
149 { { "", 0 } , 0 }, } };
151 static const struct audio_mixer_enum
152 ac97_mic_select = { 2, { { { AudioNmicrophone "0", 0 }, 0 },
153 { { AudioNmicrophone "1", 0 }, 1 },
154 { { "", 0 } , 0 },
155 { { "", 0 } , 0 },
156 { { "", 0 } , 0 },
157 { { "", 0 } , 0 },
158 { { "", 0 } , 0 },
159 { { "", 0 } , 0 },
160 { { "", 0 } , 0 },
161 { { "", 0 } , 0 },
162 { { "", 0 } , 0 },
163 { { "", 0 } , 0 },
164 { { "", 0 } , 0 },
165 { { "", 0 } , 0 },
166 { { "", 0 } , 0 },
167 { { "", 0 } , 0 },
168 { { "", 0 } , 0 },
169 { { "", 0 } , 0 },
170 { { "", 0 } , 0 },
171 { { "", 0 } , 0 },
172 { { "", 0 } , 0 },
173 { { "", 0 } , 0 },
174 { { "", 0 } , 0 },
175 { { "", 0 } , 0 },
176 { { "", 0 } , 0 },
177 { { "", 0 } , 0 },
178 { { "", 0 } , 0 },
179 { { "", 0 } , 0 },
180 { { "", 0 } , 0 },
181 { { "", 0 } , 0 },
182 { { "", 0 } , 0 },
183 { { "", 0 } , 0 }, } };
185 static const struct audio_mixer_enum
186 ac97_mono_select = { 2, { { { AudioNmixerout, 0 }, 0 },
187 { { AudioNmicrophone, 0 }, 1 },
188 { { "", 0 } , 0 },
189 { { "", 0 } , 0 },
190 { { "", 0 } , 0 },
191 { { "", 0 } , 0 },
192 { { "", 0 } , 0 },
193 { { "", 0 } , 0 },
194 { { "", 0 } , 0 },
195 { { "", 0 } , 0 },
196 { { "", 0 } , 0 },
197 { { "", 0 } , 0 },
198 { { "", 0 } , 0 },
199 { { "", 0 } , 0 },
200 { { "", 0 } , 0 },
201 { { "", 0 } , 0 },
202 { { "", 0 } , 0 },
203 { { "", 0 } , 0 },
204 { { "", 0 } , 0 },
205 { { "", 0 } , 0 },
206 { { "", 0 } , 0 },
207 { { "", 0 } , 0 },
208 { { "", 0 } , 0 },
209 { { "", 0 } , 0 },
210 { { "", 0 } , 0 },
211 { { "", 0 } , 0 },
212 { { "", 0 } , 0 },
213 { { "", 0 } , 0 },
214 { { "", 0 } , 0 },
215 { { "", 0 } , 0 },
216 { { "", 0 } , 0 },
217 { { "", 0 } , 0 }, } };
219 static const struct audio_mixer_enum
220 ac97_source = { 8, { { { AudioNmicrophone, 0 } , 0 },
221 { { AudioNcd, 0 }, 1 },
222 { { AudioNvideo, 0 }, 2 },
223 { { AudioNaux, 0 }, 3 },
224 { { AudioNline, 0 }, 4 },
225 { { AudioNmixerout, 0 }, 5 },
226 { { AudioNmixerout AudioNmono, 0 }, 6 },
227 { { Ac97Nphone, 0 }, 7 },
228 { { "", 0 } , 0 },
229 { { "", 0 } , 0 },
230 { { "", 0 } , 0 },
231 { { "", 0 } , 0 },
232 { { "", 0 } , 0 },
233 { { "", 0 } , 0 },
234 { { "", 0 } , 0 },
235 { { "", 0 } , 0 },
236 { { "", 0 } , 0 },
237 { { "", 0 } , 0 },
238 { { "", 0 } , 0 },
239 { { "", 0 } , 0 },
240 { { "", 0 } , 0 },
241 { { "", 0 } , 0 },
242 { { "", 0 } , 0 },
243 { { "", 0 } , 0 },
244 { { "", 0 } , 0 },
245 { { "", 0 } , 0 },
246 { { "", 0 } , 0 },
247 { { "", 0 } , 0 },
248 { { "", 0 } , 0 },
249 { { "", 0 } , 0 },
250 { { "", 0 } , 0 },
251 { { "", 0 } , 0 }, } };
254 * Due to different values for each source that uses these structures,
255 * the ac97_query_devinfo function sets delta in mixer_devinfo_t using
256 * ac97_source_info.bits.
258 static const struct audio_mixer_value
259 ac97_volume_stereo = { { AudioNvolume, 0 }, 2, 0 };
261 static const struct audio_mixer_value
262 ac97_volume_mono = { { AudioNvolume, 0 }, 1, 0 };
264 #define WRAP(a) &a, sizeof(a)
266 struct ac97_source_info {
267 const char *class;
268 const char *device;
269 const char *qualifier;
271 int type;
272 const void *info;
273 int info_size;
275 uint8_t reg;
276 int32_t default_value;
277 unsigned bits:3;
278 unsigned ofs:4;
279 unsigned mute:1;
280 unsigned polarity:1; /* Does 0 == MAX or MIN */
281 unsigned checkbits:1;
282 enum {
283 CHECK_NONE = 0,
284 CHECK_SURROUND,
285 CHECK_CENTER,
286 CHECK_LFE,
287 CHECK_HEADPHONES,
288 CHECK_TONE,
289 CHECK_MIC,
290 CHECK_LOUDNESS,
291 CHECK_3D,
292 CHECK_LINE1,
293 CHECK_LINE2,
294 CHECK_HANDSET,
295 CHECK_SPDIF
296 } req_feature;
298 int prev;
299 int next;
300 int mixer_class;
303 static const struct ac97_source_info audio_source_info[] = {
304 { AudioCinputs, NULL, NULL,
305 AUDIO_MIXER_CLASS, NULL, 0,
306 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, },
307 { AudioCoutputs, NULL, 0,
308 AUDIO_MIXER_CLASS, NULL, 0,
309 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, },
310 { AudioCrecord, NULL, 0,
311 AUDIO_MIXER_CLASS, NULL, 0,
312 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, },
313 /* Stereo master volume*/
314 { AudioCoutputs, AudioNmaster, 0,
315 AUDIO_MIXER_VALUE, WRAP(ac97_volume_stereo),
316 AC97_REG_MASTER_VOLUME, 0x8000, 5, 0, 1, 0, 1, 0, 0, 0, 0,
318 /* Mono volume */
319 { AudioCoutputs, AudioNmono, NULL,
320 AUDIO_MIXER_VALUE, WRAP(ac97_volume_mono),
321 AC97_REG_MASTER_VOLUME_MONO, 0x8000, 6, 0, 1, 0, 1, 0, 0, 0, 0,
323 { AudioCoutputs, AudioNmono, AudioNsource,
324 AUDIO_MIXER_ENUM, WRAP(ac97_mono_select),
325 AC97_REG_GP, 0x0000, 1, 9, 0, 0, 0, 0, 0, 0, 0,
327 /* Headphone volume */
328 { AudioCoutputs, AudioNheadphone, NULL,
329 AUDIO_MIXER_VALUE, WRAP(ac97_volume_stereo),
330 AC97_REG_HEADPHONE_VOLUME, 0x8000, 5, 0, 1, 0, 1, CHECK_HEADPHONES, 0, 0, 0,
332 /* Surround volume - logic hard coded for mute */
333 { AudioCoutputs, AudioNsurround, NULL,
334 AUDIO_MIXER_VALUE, WRAP(ac97_volume_stereo),
335 AC97_REG_SURR_MASTER, 0x8080, 5, 0, 1, 0, 1, CHECK_SURROUND, 0, 0, 0
337 /* Center volume*/
338 { AudioCoutputs, AudioNcenter, NULL,
339 AUDIO_MIXER_VALUE, WRAP(ac97_volume_mono),
340 AC97_REG_CENTER_LFE_MASTER, 0x8080, 5, 0, 0, 0, 1, CHECK_CENTER, 0, 0, 0
342 { AudioCoutputs, AudioNcenter, AudioNmute,
343 AUDIO_MIXER_ENUM, WRAP(ac97_on_off),
344 AC97_REG_CENTER_LFE_MASTER, 0x8080, 1, 7, 0, 0, 0, CHECK_CENTER, 0, 0, 0
346 /* LFE volume*/
347 { AudioCoutputs, AudioNlfe, NULL,
348 AUDIO_MIXER_VALUE, WRAP(ac97_volume_mono),
349 AC97_REG_CENTER_LFE_MASTER, 0x8080, 5, 8, 0, 0, 1, CHECK_LFE, 0, 0, 0
351 { AudioCoutputs, AudioNlfe, AudioNmute,
352 AUDIO_MIXER_ENUM, WRAP(ac97_on_off),
353 AC97_REG_CENTER_LFE_MASTER, 0x8080, 1, 15, 0, 0, 0, CHECK_LFE, 0, 0, 0
355 /* Tone - bass */
356 { AudioCoutputs, AudioNbass, NULL,
357 AUDIO_MIXER_VALUE, WRAP(ac97_volume_mono),
358 AC97_REG_MASTER_TONE, 0x0f0f, 4, 8, 0, 0, 0, CHECK_TONE, 0, 0, 0
360 /* Tone - treble */
361 { AudioCoutputs, AudioNtreble, NULL,
362 AUDIO_MIXER_VALUE, WRAP(ac97_volume_mono),
363 AC97_REG_MASTER_TONE, 0x0f0f, 4, 0, 0, 0, 0, CHECK_TONE, 0, 0, 0
365 /* PC Beep Volume */
366 { AudioCinputs, AudioNspeaker, NULL,
367 AUDIO_MIXER_VALUE, WRAP(ac97_volume_mono),
368 AC97_REG_PCBEEP_VOLUME, 0x0000, 4, 1, 1, 0, 0, 0, 0, 0, 0,
371 /* Phone */
372 { AudioCinputs, Ac97Nphone, NULL,
373 AUDIO_MIXER_VALUE, WRAP(ac97_volume_mono),
374 AC97_REG_PHONE_VOLUME, 0x8008, 5, 0, 1, 0, 0, 0, 0, 0, 0,
376 /* Mic Volume */
377 { AudioCinputs, AudioNmicrophone, NULL,
378 AUDIO_MIXER_VALUE, WRAP(ac97_volume_mono),
379 AC97_REG_MIC_VOLUME, 0x8008, 5, 0, 1, 0, 0, 0, 0, 0, 0,
381 { AudioCinputs, AudioNmicrophone, AudioNpreamp,
382 AUDIO_MIXER_ENUM, WRAP(ac97_on_off),
383 AC97_REG_MIC_VOLUME, 0x8008, 1, 6, 0, 0, 0, 0, 0, 0, 0,
385 { AudioCinputs, AudioNmicrophone, AudioNsource,
386 AUDIO_MIXER_ENUM, WRAP(ac97_mic_select),
387 AC97_REG_GP, 0x0000, 1, 8, 0, 0, 0, 0, 0, 0, 0,
389 /* Line in Volume */
390 { AudioCinputs, AudioNline, NULL,
391 AUDIO_MIXER_VALUE, WRAP(ac97_volume_stereo),
392 AC97_REG_LINEIN_VOLUME, 0x8808, 5, 0, 1, 0, 0, 0, 0, 0, 0,
394 /* CD Volume */
395 { AudioCinputs, AudioNcd, NULL,
396 AUDIO_MIXER_VALUE, WRAP(ac97_volume_stereo),
397 AC97_REG_CD_VOLUME, 0x8808, 5, 0, 1, 0, 0, 0, 0, 0, 0,
399 /* Video Volume */
400 { AudioCinputs, AudioNvideo, NULL,
401 AUDIO_MIXER_VALUE, WRAP(ac97_volume_stereo),
402 AC97_REG_VIDEO_VOLUME, 0x8808, 5, 0, 1, 0, 0, 0, 0, 0, 0,
404 /* AUX volume */
405 { AudioCinputs, AudioNaux, NULL,
406 AUDIO_MIXER_VALUE, WRAP(ac97_volume_stereo),
407 AC97_REG_AUX_VOLUME, 0x8808, 5, 0, 1, 0, 0, 0, 0, 0, 0,
409 /* PCM out volume */
410 { AudioCinputs, AudioNdac, NULL,
411 AUDIO_MIXER_VALUE, WRAP(ac97_volume_stereo),
412 AC97_REG_PCMOUT_VOLUME, 0x8808, 5, 0, 1, 0, 0, 0, 0, 0, 0,
414 /* Record Source - some logic for this is hard coded - see below */
415 { AudioCrecord, AudioNsource, NULL,
416 AUDIO_MIXER_ENUM, WRAP(ac97_source),
417 AC97_REG_RECORD_SELECT, 0x0000, 3, 0, 0, 0, 0, 0, 0, 0, 0,
419 /* Record Gain */
420 { AudioCrecord, AudioNvolume, NULL,
421 AUDIO_MIXER_VALUE, WRAP(ac97_volume_stereo),
422 AC97_REG_RECORD_GAIN, 0x8000, 4, 0, 1, 1, 0, 0, 0, 0, 0,
424 /* Record Gain mic */
425 { AudioCrecord, AudioNmicrophone, NULL,
426 AUDIO_MIXER_VALUE, WRAP(ac97_volume_mono),
427 AC97_REG_RECORD_GAIN_MIC, 0x8000, 4, 0, 1, 1, 0, CHECK_MIC, 0, 0, 0
429 /* */
430 { AudioCoutputs, AudioNloudness, NULL,
431 AUDIO_MIXER_ENUM, WRAP(ac97_on_off),
432 AC97_REG_GP, 0x0000, 1, 12, 0, 0, 0, CHECK_LOUDNESS, 0, 0, 0
434 { AudioCoutputs, AudioNspatial, NULL,
435 AUDIO_MIXER_ENUM, WRAP(ac97_on_off),
436 AC97_REG_GP, 0x0000, 1, 13, 0, 1, 0, CHECK_3D, 0, 0, 0
438 { AudioCoutputs, AudioNspatial, "center",
439 AUDIO_MIXER_VALUE, WRAP(ac97_volume_mono),
440 AC97_REG_3D_CONTROL, 0x0000, 4, 8, 0, 1, 0, CHECK_3D, 0, 0, 0
442 { AudioCoutputs, AudioNspatial, "depth",
443 AUDIO_MIXER_VALUE, WRAP(ac97_volume_mono),
444 AC97_REG_3D_CONTROL, 0x0000, 4, 0, 0, 1, 0, CHECK_3D, 0, 0, 0
447 /* SPDIF */
448 { "spdif", NULL, NULL,
449 AUDIO_MIXER_CLASS, NULL, 0,
450 0, 0, 0, 0, 0, 0, 0, CHECK_SPDIF, 0, 0, 0
452 { "spdif", "enable", NULL,
453 AUDIO_MIXER_ENUM, WRAP(ac97_on_off),
454 AC97_REG_EXT_AUDIO_CTRL, -1, 1, 2, 0, 0, 0, CHECK_SPDIF, 0, 0, 0
457 /* Missing features: Simulated Stereo, POP, Loopback mode */
460 static const struct ac97_source_info modem_source_info[] = {
461 /* Classes */
462 { AudioCinputs, NULL, NULL,
463 AUDIO_MIXER_CLASS, NULL, 0,
464 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, },
465 { AudioCoutputs, NULL, NULL,
466 AUDIO_MIXER_CLASS, NULL, 0,
467 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, },
468 { AudioCinputs, Ac97Nline1, NULL,
469 AUDIO_MIXER_VALUE, WRAP(ac97_volume_mono),
470 AC97_REG_LINE1_LEVEL, 0x8080, 4, 0, 0, 1, 0, CHECK_LINE1, 0, 0, 0
472 { AudioCoutputs, Ac97Nline1, NULL,
473 AUDIO_MIXER_VALUE, WRAP(ac97_volume_mono),
474 AC97_REG_LINE1_LEVEL, 0x8080, 4, 8, 0, 1, 0, CHECK_LINE1, 0, 0, 0
476 { AudioCinputs, Ac97Nline1, AudioNmute,
477 AUDIO_MIXER_ENUM, WRAP(ac97_on_off),
478 AC97_REG_LINE1_LEVEL, 0x8080, 1, 7, 0, 0, 0, CHECK_LINE1, 0, 0, 0
480 { AudioCoutputs, Ac97Nline1, AudioNmute,
481 AUDIO_MIXER_ENUM, WRAP(ac97_on_off),
482 AC97_REG_LINE1_LEVEL, 0x8080, 1, 15, 0, 0, 0, CHECK_LINE1, 0, 0, 0
486 #define AUDIO_SOURCE_INFO_SIZE \
487 (sizeof(audio_source_info)/sizeof(audio_source_info[0]))
488 #define MODEM_SOURCE_INFO_SIZE \
489 (sizeof(modem_source_info)/sizeof(modem_source_info[0]))
490 #define SOURCE_INFO_SIZE(as) ((as)->type == AC97_CODEC_TYPE_MODEM ? \
491 MODEM_SOURCE_INFO_SIZE : AUDIO_SOURCE_INFO_SIZE)
494 * Check out http://www.intel.com/support/motherboards/desktop/sb/cs-025406.htm for
495 * AC'97 Component Specification
498 struct ac97_softc {
499 /* ac97_codec_if must be at the first of ac97_softc. */
500 struct ac97_codec_if codec_if;
502 struct ac97_host_if *host_if;
504 #define AUDIO_MAX_SOURCES (2 * AUDIO_SOURCE_INFO_SIZE)
505 #define MODEM_MAX_SOURCES (2 * MODEM_SOURCE_INFO_SIZE)
506 struct ac97_source_info audio_source_info[AUDIO_MAX_SOURCES];
507 struct ac97_source_info modem_source_info[MODEM_MAX_SOURCES];
508 struct ac97_source_info *source_info;
509 int num_source_info;
511 enum ac97_host_flags host_flags;
512 unsigned int ac97_clock; /* usually 48000 */
513 #define AC97_STANDARD_CLOCK 48000U
514 uint16_t power_all;
515 uint16_t power_reg; /* -> AC97_REG_POWER */
516 uint16_t caps; /* -> AC97_REG_RESET */
517 uint16_t ext_id; /* -> AC97_REG_EXT_AUDIO_ID */
518 uint16_t ext_mid; /* -> AC97_REG_EXT_MODEM_ID */
519 uint16_t shadow_reg[128];
521 int lock_counter;
522 int type;
524 /* sysctl */
525 struct sysctllog *log;
526 int offhook_line1_mib;
527 int offhook_line2_mib;
528 int offhook_line1;
529 int offhook_line2;
532 static struct ac97_codec_if_vtbl ac97civ = {
533 ac97_mixer_get_port,
534 ac97_mixer_set_port,
535 ac97_query_devinfo,
536 ac97_get_portnum_by_name,
537 ac97_restore_shadow,
538 ac97_get_extcaps,
539 ac97_set_rate,
540 ac97_set_clock,
541 ac97_detach,
542 ac97_lock,
543 ac97_unlock,
546 static const struct ac97_codecid {
547 uint32_t id;
548 uint32_t mask;
549 const char *name;
550 void (*init)(struct ac97_softc *);
551 } ac97codecid[] = {
553 * Analog Devices SoundMAX
554 * http://www.soundmax.com/products/information/codecs.html
555 * http://www.analog.com/productSelection/pdf/AD1881A_0.pdf
556 * http://www.analog.com/productSelection/pdf/AD1885_0.pdf
557 * http://www.analog.com/UploadedFiles/Data_Sheets/206585810AD1980_0.pdf
558 * http://www.analog.com/productSelection/pdf/AD1981A_0.pdf
559 * http://www.analog.com/productSelection/pdf/AD1981B_0.pdf
560 * http://www.analog.com/UploadedFiles/Data_Sheets/180644528AD1985_0.pdf
562 { AC97_CODEC_ID('A', 'D', 'S', 3),
563 0xffffffff, "Analog Devices AD1819B", NULL, },
564 { AC97_CODEC_ID('A', 'D', 'S', 0x40),
565 0xffffffff, "Analog Devices AD1881", NULL, },
566 { AC97_CODEC_ID('A', 'D', 'S', 0x48),
567 0xffffffff, "Analog Devices AD1881A", NULL, },
568 { AC97_CODEC_ID('A', 'D', 'S', 0x60),
569 0xffffffff, "Analog Devices AD1885", NULL, },
570 { AC97_CODEC_ID('A', 'D', 'S', 0x61),
571 0xffffffff, "Analog Devices AD1886", NULL, },
572 { AC97_CODEC_ID('A', 'D', 'S', 0x63),
573 0xffffffff, "Analog Devices AD1886A", NULL, },
574 { AC97_CODEC_ID('A', 'D', 'S', 0x68),
575 0xffffffff, "Analog Devices AD1888", ac97_ad198x_init },
576 { AC97_CODEC_ID('A', 'D', 'S', 0x70),
577 0xffffffff, "Analog Devices AD1980", ac97_ad198x_init },
578 { AC97_CODEC_ID('A', 'D', 'S', 0x72),
579 0xffffffff, "Analog Devices AD1981A", NULL, },
580 { AC97_CODEC_ID('A', 'D', 'S', 0x74),
581 0xffffffff, "Analog Devices AD1981B", NULL, },
582 { AC97_CODEC_ID('A', 'D', 'S', 0x75),
583 0xffffffff, "Analog Devices AD1985", ac97_ad198x_init },
584 { AC97_CODEC_ID('A', 'D', 'S', 0),
585 AC97_VENDOR_ID_MASK, "Analog Devices unknown", NULL, },
588 * Datasheets:
589 * http://www.asahi-kasei.co.jp/akm/japanese/product/ak4543/ek4543.pdf
590 * http://www.asahi-kasei.co.jp/akm/japanese/product/ak4544a/ek4544a.pdf
591 * http://www.asahi-kasei.co.jp/akm/japanese/product/ak4545/ak4545_f00e.pdf
593 { AC97_CODEC_ID('A', 'K', 'M', 0),
594 0xffffffff, "Asahi Kasei AK4540", NULL, },
595 { AC97_CODEC_ID('A', 'K', 'M', 1),
596 0xffffffff, "Asahi Kasei AK4542", NULL, },
597 { AC97_CODEC_ID('A', 'K', 'M', 2),
598 0xffffffff, "Asahi Kasei AK4541/AK4543", NULL, },
599 { AC97_CODEC_ID('A', 'K', 'M', 5),
600 0xffffffff, "Asahi Kasei AK4544", NULL, },
601 { AC97_CODEC_ID('A', 'K', 'M', 6),
602 0xffffffff, "Asahi Kasei AK4544A", NULL, },
603 { AC97_CODEC_ID('A', 'K', 'M', 7),
604 0xffffffff, "Asahi Kasei AK4545", NULL, },
605 { AC97_CODEC_ID('A', 'K', 'M', 0),
606 AC97_VENDOR_ID_MASK, "Asahi Kasei unknown", NULL, },
609 * Realtek & Avance Logic
610 * http://www.realtek.com.tw/downloads/downloads1-3.aspx?lineid=5&famid=All&series=All&Spec=True
612 * ALC650 and ALC658 support VRA, but it supports only 8000, 11025,
613 * 12000, 16000, 22050, 24000, 32000, 44100, and 48000 Hz.
615 { AC97_CODEC_ID('A', 'L', 'C', 0x00),
616 0xfffffff0, "Realtek RL5306", NULL, },
617 { AC97_CODEC_ID('A', 'L', 'C', 0x10),
618 0xfffffff0, "Realtek RL5382", NULL, },
619 { AC97_CODEC_ID('A', 'L', 'C', 0x20),
620 0xfffffff0, "Realtek RL5383/RL5522/ALC100", NULL, },
621 { AC97_CODEC_ID('A', 'L', 'G', 0x10),
622 0xffffffff, "Avance Logic ALC200/ALC201", NULL, },
623 { AC97_CODEC_ID('A', 'L', 'G', 0x20),
624 0xfffffff0, "Avance Logic ALC650", ac97_alc650_init },
625 { AC97_CODEC_ID('A', 'L', 'G', 0x30),
626 0xffffffff, "Avance Logic ALC101", NULL, },
627 { AC97_CODEC_ID('A', 'L', 'G', 0x40),
628 0xffffffff, "Avance Logic ALC202", NULL, },
629 { AC97_CODEC_ID('A', 'L', 'G', 0x50),
630 0xffffffff, "Avance Logic ALC250", NULL, },
631 { AC97_CODEC_ID('A', 'L', 'G', 0x60),
632 0xfffffff0, "Avance Logic ALC655", NULL, },
633 { AC97_CODEC_ID('A', 'L', 'G', 0x80),
634 0xfffffff0, "Avance Logic ALC658", NULL, },
635 { AC97_CODEC_ID('A', 'L', 'G', 0x90),
636 0xfffffff0, "Avance Logic ALC850", NULL, },
637 { AC97_CODEC_ID('A', 'L', 'C', 0),
638 AC97_VENDOR_ID_MASK, "Realtek unknown", NULL, },
639 { AC97_CODEC_ID('A', 'L', 'G', 0),
640 AC97_VENDOR_ID_MASK, "Avance Logic unknown", NULL, },
643 * C-Media Electronics Inc.
644 * http://www.cmedia.com.tw/doc/CMI9739%206CH%20Audio%20Codec%20SPEC_Ver12.pdf
646 { AC97_CODEC_ID('C', 'M', 'I', 0x61),
647 0xffffffff, "C-Media CMI9739", NULL, },
648 { AC97_CODEC_ID('C', 'M', 'I', 0),
649 AC97_VENDOR_ID_MASK, "C-Media unknown", NULL, },
651 /* Cirrus Logic, Crystal series:
652 * 'C' 'R' 'Y' 0x0[0-7] - CS4297
653 * 0x1[0-7] - CS4297A
654 * 0x2[0-7] - CS4298
655 * 0x2[8-f] - CS4294
656 * 0x3[0-7] - CS4299
657 * 0x4[8-f] - CS4201
658 * 0x5[8-f] - CS4205
659 * 0x6[0-7] - CS4291
660 * 0x7[0-7] - CS4202
661 * Datasheets:
662 * http://www.cirrus.com/pubs/cs4297A-5.pdf?DocumentID=593
663 * http://www.cirrus.com/pubs/cs4294.pdf?DocumentID=32
664 * http://www.cirrus.com/pubs/cs4299-5.pdf?DocumentID=594
665 * http://www.cirrus.com/pubs/cs4201-2.pdf?DocumentID=492
666 * http://www.cirrus.com/pubs/cs4205-2.pdf?DocumentID=492
667 * http://www.cirrus.com/pubs/cs4202-1.pdf?DocumentID=852
669 { AC97_CODEC_ID('C', 'R', 'Y', 0x00),
670 0xfffffff8, "Crystal CS4297", NULL, },
671 { AC97_CODEC_ID('C', 'R', 'Y', 0x10),
672 0xfffffff8, "Crystal CS4297A", NULL, },
673 { AC97_CODEC_ID('C', 'R', 'Y', 0x20),
674 0xfffffff8, "Crystal CS4298", NULL, },
675 { AC97_CODEC_ID('C', 'R', 'Y', 0x28),
676 0xfffffff8, "Crystal CS4294", NULL, },
677 { AC97_CODEC_ID('C', 'R', 'Y', 0x30),
678 0xfffffff8, "Crystal CS4299", NULL, },
679 { AC97_CODEC_ID('C', 'R', 'Y', 0x48),
680 0xfffffff8, "Crystal CS4201", NULL, },
681 { AC97_CODEC_ID('C', 'R', 'Y', 0x58),
682 0xfffffff8, "Crystal CS4205", NULL, },
683 { AC97_CODEC_ID('C', 'R', 'Y', 0x60),
684 0xfffffff8, "Crystal CS4291", NULL, },
685 { AC97_CODEC_ID('C', 'R', 'Y', 0x70),
686 0xfffffff8, "Crystal CS4202", NULL, },
687 { AC97_CODEC_ID('C', 'R', 'Y', 0),
688 AC97_VENDOR_ID_MASK, "Cirrus Logic unknown", NULL, },
690 { 0x45838308, 0xffffffff, "ESS Technology ES1921", NULL, },
691 { 0x45838300, AC97_VENDOR_ID_MASK, "ESS Technology unknown", NULL, },
693 { AC97_CODEC_ID('H', 'R', 'S', 0),
694 0xffffffff, "Intersil HMP9701", NULL, },
695 { AC97_CODEC_ID('H', 'R', 'S', 0),
696 AC97_VENDOR_ID_MASK, "Intersil unknown", NULL, },
699 * IC Ensemble (VIA)
700 * http://www.viatech.com/en/datasheet/DS1616.pdf
702 { AC97_CODEC_ID('I', 'C', 'E', 0x01),
703 0xffffffff, "ICEnsemble ICE1230/VT1611", NULL, },
704 { AC97_CODEC_ID('I', 'C', 'E', 0x11),
705 0xffffffff, "ICEnsemble ICE1232/VT1611A", NULL, },
706 { AC97_CODEC_ID('I', 'C', 'E', 0x14),
707 0xffffffff, "ICEnsemble ICE1232A", NULL, },
708 { AC97_CODEC_ID('I', 'C', 'E', 0x51),
709 0xffffffff, "VIA Technologies VT1616", ac97_vt1616_init },
710 { AC97_CODEC_ID('I', 'C', 'E', 0x52),
711 0xffffffff, "VIA Technologies VT1616i", ac97_vt1616_init },
712 { AC97_CODEC_ID('I', 'C', 'E', 0),
713 AC97_VENDOR_ID_MASK, "ICEnsemble/VIA unknown", NULL, },
715 { AC97_CODEC_ID('N', 'S', 'C', 0),
716 0xffffffff, "National Semiconductor LM454[03568]", NULL, },
717 { AC97_CODEC_ID('N', 'S', 'C', 49),
718 0xffffffff, "National Semiconductor LM4549", NULL, },
719 { AC97_CODEC_ID('N', 'S', 'C', 0),
720 AC97_VENDOR_ID_MASK, "National Semiconductor unknown", NULL, },
722 { AC97_CODEC_ID('P', 'S', 'C', 4),
723 0xffffffff, "Philips Semiconductor UCB1400", ac97_ucb1400_init, },
724 { AC97_CODEC_ID('P', 'S', 'C', 0),
725 AC97_VENDOR_ID_MASK, "Philips Semiconductor unknown", NULL, },
727 { AC97_CODEC_ID('S', 'I', 'L', 34),
728 0xffffffff, "Silicon Laboratory Si3036", NULL, },
729 { AC97_CODEC_ID('S', 'I', 'L', 35),
730 0xffffffff, "Silicon Laboratory Si3038", NULL, },
731 { AC97_CODEC_ID('S', 'I', 'L', 0),
732 AC97_VENDOR_ID_MASK, "Silicon Laboratory unknown", NULL, },
734 { AC97_CODEC_ID('T', 'R', 'A', 2),
735 0xffffffff, "TriTech TR28022", NULL, },
736 { AC97_CODEC_ID('T', 'R', 'A', 3),
737 0xffffffff, "TriTech TR28023", NULL, },
738 { AC97_CODEC_ID('T', 'R', 'A', 6),
739 0xffffffff, "TriTech TR28026", NULL, },
740 { AC97_CODEC_ID('T', 'R', 'A', 8),
741 0xffffffff, "TriTech TR28028", NULL, },
742 { AC97_CODEC_ID('T', 'R', 'A', 35),
743 0xffffffff, "TriTech TR28602", NULL, },
744 { AC97_CODEC_ID('T', 'R', 'A', 0),
745 AC97_VENDOR_ID_MASK, "TriTech unknown", NULL, },
747 { AC97_CODEC_ID('T', 'X', 'N', 0x20),
748 0xffffffff, "Texas Instruments TLC320AD9xC", NULL, },
749 { AC97_CODEC_ID('T', 'X', 'N', 0),
750 AC97_VENDOR_ID_MASK, "Texas Instruments unknown", NULL, },
753 * VIA
754 * http://www.viatech.com/en/multimedia/audio.jsp
756 { AC97_CODEC_ID('V', 'I', 'A', 0x61),
757 0xffffffff, "VIA Technologies VT1612A", NULL, },
758 { AC97_CODEC_ID('V', 'I', 'A', 0),
759 AC97_VENDOR_ID_MASK, "VIA Technologies unknown", NULL, },
761 { AC97_CODEC_ID('W', 'E', 'C', 1),
762 0xffffffff, "Winbond W83971D", NULL, },
763 { AC97_CODEC_ID('W', 'E', 'C', 0),
764 AC97_VENDOR_ID_MASK, "Winbond unknown", NULL, },
767 * http://www.wolfsonmicro.com/product_list.asp?cid=64
768 * http://www.wolfsonmicro.com/download.asp/did.56/WM9701A.pdf - 00
769 * http://www.wolfsonmicro.com/download.asp/did.57/WM9703.pdf - 03
770 * http://www.wolfsonmicro.com/download.asp/did.58/WM9704M.pdf - 04
771 * http://www.wolfsonmicro.com/download.asp/did.59/WM9704Q.pdf - 04
772 * http://www.wolfsonmicro.com/download.asp/did.184/WM9705_Rev34.pdf - 05
773 * http://www.wolfsonmicro.com/download.asp/did.60/WM9707.pdf - 03
774 * http://www.wolfsonmicro.com/download.asp/did.136/WM9708.pdf - 03
775 * http://www.wolfsonmicro.com/download.asp/did.243/WM9710.pdf - 05
777 { AC97_CODEC_ID('W', 'M', 'L', 0),
778 0xffffffff, "Wolfson WM9701A", NULL, },
779 { AC97_CODEC_ID('W', 'M', 'L', 3),
780 0xffffffff, "Wolfson WM9703/WM9707/WM9708", NULL, },
781 { AC97_CODEC_ID('W', 'M', 'L', 4),
782 0xffffffff, "Wolfson WM9704", NULL, },
783 { AC97_CODEC_ID('W', 'M', 'L', 5),
784 0xffffffff, "Wolfson WM9705/WM9710", NULL, },
785 { AC97_CODEC_ID('W', 'M', 'L', 0),
786 AC97_VENDOR_ID_MASK, "Wolfson unknown", NULL, },
789 * http://www.yamaha.co.jp/english/product/lsi/us/products/pcaudio.html
790 * Datasheets:
791 * http://www.yamaha.co.jp/english/product/lsi/us/products/pdf/4MF743A20.pdf
792 * http://www.yamaha.co.jp/english/product/lsi/us/products/pdf/4MF753A20.pdf
794 { AC97_CODEC_ID('Y', 'M', 'H', 0),
795 0xffffffff, "Yamaha YMF743-S", NULL, },
796 { AC97_CODEC_ID('Y', 'M', 'H', 3),
797 0xffffffff, "Yamaha YMF753-S", NULL, },
798 { AC97_CODEC_ID('Y', 'M', 'H', 0),
799 AC97_VENDOR_ID_MASK, "Yamaha unknown", NULL, },
802 * http://www.sigmatel.com/products/technical_docs.htm
803 * and
804 * http://www.sigmatel.com/documents/c-major-brochure-9-0.pdf
806 { 0x83847600, 0xffffffff, "SigmaTel STAC9700", NULL, },
807 { 0x83847604, 0xffffffff, "SigmaTel STAC9701/3/4/5", NULL, },
808 { 0x83847605, 0xffffffff, "SigmaTel STAC9704", NULL, },
809 { 0x83847608, 0xffffffff, "SigmaTel STAC9708", NULL, },
810 { 0x83847609, 0xffffffff, "SigmaTel STAC9721/23", NULL, },
811 { 0x83847644, 0xffffffff, "SigmaTel STAC9744/45", NULL, },
812 { 0x83847650, 0xffffffff, "SigmaTel STAC9750/51", NULL, },
813 { 0x83847652, 0xffffffff, "SigmaTel STAC9752/53", NULL, },
814 { 0x83847656, 0xffffffff, "SigmaTel STAC9756/57", NULL, },
815 { 0x83847658, 0xffffffff, "SigmaTel STAC9758/59", NULL, },
816 { 0x83847666, 0xffffffff, "SigmaTel STAC9766/67", NULL, },
817 { 0x83847684, 0xffffffff, "SigmaTel STAC9783/84", NULL, },
818 { 0x83847600, AC97_VENDOR_ID_MASK, "SigmaTel unknown", NULL, },
820 /* Conexant AC'97 modems -- good luck finding datasheets! */
821 { AC97_CODEC_ID('C', 'X', 'T', 33),
822 0xffffffff, "Conexant HSD11246", NULL, },
823 { AC97_CODEC_ID('C', 'X', 'T', 34),
824 0xffffffff, "Conexant D480 MDC V.92 Modem", NULL, },
825 { AC97_CODEC_ID('C', 'X', 'T', 48),
826 0xffffffff, "Conexant CXT48", NULL, },
827 { AC97_CODEC_ID('C', 'X', 'T', 0),
828 AC97_VENDOR_ID_MASK, "Conexant unknown", NULL, },
830 { 0,
831 0, NULL, NULL, },
834 static const char * const ac97enhancement[] = {
835 "no 3D stereo",
836 "Analog Devices Phat Stereo",
837 "Creative",
838 "National Semi 3D",
839 "Yamaha Ymersion",
840 "BBE 3D",
841 "Crystal Semi 3D",
842 "Qsound QXpander",
843 "Spatializer 3D",
844 "SRS 3D",
845 "Platform Tech 3D",
846 "AKM 3D",
847 "Aureal",
848 "AZTECH 3D",
849 "Binaura 3D",
850 "ESS Technology",
851 "Harman International VMAx",
852 "Nvidea 3D",
853 "Philips Incredible Sound",
854 "Texas Instruments' 3D",
855 "VLSI Technology 3D",
856 "TriTech 3D",
857 "Realtek 3D",
858 "Samsung 3D",
859 "Wolfson Microelectronics 3D",
860 "Delta Integration 3D",
861 "SigmaTel 3D",
862 "KS Waves 3D",
863 "Rockwell 3D",
864 "Unknown 3D",
865 "Unknown 3D",
866 "Unknown 3D",
869 static const char * const ac97feature[] = {
870 "dedicated mic channel",
871 "reserved",
872 "tone",
873 "simulated stereo",
874 "headphone",
875 "bass boost",
876 "18 bit DAC",
877 "20 bit DAC",
878 "18 bit ADC",
879 "20 bit ADC"
883 /* #define AC97_DEBUG 10 */
884 /* #define AC97_IO_DEBUG */
886 #ifdef AUDIO_DEBUG
887 #define DPRINTF(x) if (ac97debug) printf x
888 #define DPRINTFN(n,x) if (ac97debug>(n)) printf x
889 #ifdef AC97_DEBUG
890 int ac97debug = AC97_DEBUG;
891 #else
892 int ac97debug = 0;
893 #endif
894 #else
895 #define DPRINTF(x)
896 #define DPRINTFN(n,x)
897 #endif
899 #ifdef AC97_IO_DEBUG
900 static const char *ac97_register_names[0x80 / 2] = {
901 "RESET", "MASTER_VOLUME", "HEADPHONE_VOLUME", "MASTER_VOLUME_MONO",
902 "MASTER_TONE", "PCBEEP_VOLUME", "PHONE_VOLUME", "MIC_VOLUME",
903 "LINEIN_VOLUME", "CD_VOLUME", "VIDEO_VOLUME", "AUX_VOLUME",
904 "PCMOUT_VOLUME", "RECORD_SELECT", "RECORD_GATIN", "RECORD_GAIN_MIC",
905 "GP", "3D_CONTROL", "AUDIO_INT", "POWER",
906 "EXT_AUDIO_ID", "EXT_AUDIO_CTRL", "PCM_FRONT_DAC_RATE", "PCM_SURR_DAC_RATE",
907 "PCM_LFE_DAC_RATE", "PCM_LR_ADC_RATE", "PCM_MIC_ADC_RATE", "CENTER_LFE_MASTER",
908 "SURR_MASTER", "SPDIF_CTRL", "EXT_MODEM_ID", "EXT_MODEM_CTRL",
909 "LINE1_RATE", "LINE2_RATE", "HANDSET_RATE", "LINE1_LEVEL",
910 "LINE2_LEVEL", "HANDSET_LEVEL", "GPIO_PIN_CONFIG", "GPIO_PIN_POLARITY",
911 "GPIO_PIN_STICKY", "GPIO_PIN_WAKEUP", "GPIO_PIN_STATUS", "MISC_MODEM_CTRL",
912 "0x58", "VENDOR-5A", "VENDOR-5C", "VENDOR-5E",
913 "0x60", "0x62", "0x64", "0x66",
914 "0x68", "0x6a", "0x6c", "0x6e",
915 "VENDOR-70", "VENDOR-72", "VENDOR-74", "VENDOR-76",
916 "VENDOR-78", "VENDOR-7A", "VENDOR_ID1", "VENDOR_ID2"
918 #endif
921 * XXX Some cards have an inverted AC97_POWER_EAMP bit.
922 * These cards will produce no sound unless AC97_HOST_INVERTED_EAMP is set.
925 #define POWER_EAMP_ON(as) ((as->host_flags & AC97_HOST_INVERTED_EAMP) \
926 ? AC97_POWER_EAMP : 0)
927 #define POWER_EAMP_OFF(as) ((as->host_flags & AC97_HOST_INVERTED_EAMP) \
928 ? 0 : AC97_POWER_EAMP)
930 static void
931 ac97_read(struct ac97_softc *as, uint8_t reg, uint16_t *val)
933 if (as->host_flags & AC97_HOST_DONT_READ &&
934 (reg != AC97_REG_VENDOR_ID1 && reg != AC97_REG_VENDOR_ID2 &&
935 reg != AC97_REG_RESET)) {
936 *val = as->shadow_reg[reg >> 1];
937 return;
940 if (as->host_if->read(as->host_if->arg, reg, val)) {
941 *val = as->shadow_reg[reg >> 1];
945 static int
946 ac97_write(struct ac97_softc *as, uint8_t reg, uint16_t val)
948 #ifndef AC97_IO_DEBUG
949 as->shadow_reg[reg >> 1] = val;
950 return as->host_if->write(as->host_if->arg, reg, val);
951 #else
952 int ret;
953 uint16_t actual;
955 as->shadow_reg[reg >> 1] = val;
956 ret = as->host_if->write(as->host_if->arg, reg, val);
957 as->host_if->read(as->host_if->arg, reg, &actual);
958 if (val != actual && reg < 0x80) {
959 printf("ac97_write: reg=%s, written=0x%04x, read=0x%04x\n",
960 ac97_register_names[reg / 2], val, actual);
962 return ret;
963 #endif
966 static void
967 ac97_setup_defaults(struct ac97_softc *as)
969 int idx;
970 const struct ac97_source_info *si;
972 memset(as->shadow_reg, 0, sizeof(as->shadow_reg));
974 for (idx = 0; idx < AUDIO_SOURCE_INFO_SIZE; idx++) {
975 si = &audio_source_info[idx];
976 if (si->default_value >= 0)
977 ac97_write(as, si->reg, si->default_value);
979 for (idx = 0; idx < MODEM_SOURCE_INFO_SIZE; idx++) {
980 si = &modem_source_info[idx];
981 if (si->default_value >= 0)
982 ac97_write(as, si->reg, si->default_value);
986 static void
987 ac97_restore_shadow(struct ac97_codec_if *self)
989 struct ac97_softc *as;
990 const struct ac97_source_info *si;
991 int idx;
992 uint16_t val;
994 as = (struct ac97_softc *) self;
996 if (as->type == AC97_CODEC_TYPE_AUDIO) {
997 /* restore AC97_REG_POWER */
998 ac97_write(as, AC97_REG_POWER, as->power_reg);
999 /* make sure chip is fully operational */
1000 for (idx = 50000; idx >= 0; idx--) {
1001 ac97_read(as, AC97_REG_POWER, &val);
1002 if ((val & as->power_all) == as->power_all)
1003 break;
1004 DELAY(10);
1008 * actually try changing a value!
1009 * The default value of AC97_REG_MASTER_VOLUME is 0x8000.
1011 for (idx = 50000; idx >= 0; idx--) {
1012 ac97_write(as, AC97_REG_MASTER_VOLUME, 0x1010);
1013 ac97_read(as, AC97_REG_MASTER_VOLUME, &val);
1014 if (val == 0x1010)
1015 break;
1016 DELAY(10);
1020 for (idx = 0; idx < SOURCE_INFO_SIZE(as); idx++) {
1021 if (as->type == AC97_CODEC_TYPE_MODEM)
1022 si = &modem_source_info[idx];
1023 else
1024 si = &audio_source_info[idx];
1025 /* don't "restore" to the reset reg! */
1026 if (si->reg != AC97_REG_RESET)
1027 ac97_write(as, si->reg, as->shadow_reg[si->reg >> 1]);
1030 if (as->ext_id & (AC97_EXT_AUDIO_VRA | AC97_EXT_AUDIO_DRA
1031 | AC97_EXT_AUDIO_SPDIF | AC97_EXT_AUDIO_VRM
1032 | AC97_EXT_AUDIO_CDAC | AC97_EXT_AUDIO_SDAC
1033 | AC97_EXT_AUDIO_LDAC)) {
1034 ac97_write(as, AC97_REG_EXT_AUDIO_CTRL,
1035 as->shadow_reg[AC97_REG_EXT_AUDIO_CTRL >> 1]);
1037 if (as->ext_mid & (AC97_EXT_MODEM_LINE1 | AC97_EXT_MODEM_LINE2
1038 | AC97_EXT_MODEM_HANDSET | AC97_EXT_MODEM_CID1
1039 | AC97_EXT_MODEM_CID2 | AC97_EXT_MODEM_ID0
1040 | AC97_EXT_MODEM_ID1)) {
1041 ac97_write(as, AC97_REG_EXT_MODEM_CTRL,
1042 as->shadow_reg[AC97_REG_EXT_MODEM_CTRL >> 1]);
1046 static int
1047 ac97_str_equal(const char *a, const char *b)
1049 return (a == b) || (a && b && (!strcmp(a, b)));
1052 static int
1053 ac97_check_capability(struct ac97_softc *as, int check)
1055 switch (check) {
1056 case CHECK_NONE:
1057 return 1;
1058 case CHECK_SURROUND:
1059 return as->ext_id & AC97_EXT_AUDIO_SDAC;
1060 case CHECK_CENTER:
1061 return as->ext_id & AC97_EXT_AUDIO_CDAC;
1062 case CHECK_LFE:
1063 return as->ext_id & AC97_EXT_AUDIO_LDAC;
1064 case CHECK_SPDIF:
1065 return as->ext_id & AC97_EXT_AUDIO_SPDIF;
1066 case CHECK_HEADPHONES:
1067 return as->caps & AC97_CAPS_HEADPHONES;
1068 case CHECK_TONE:
1069 return as->caps & AC97_CAPS_TONECTRL;
1070 case CHECK_MIC:
1071 return as->caps & AC97_CAPS_MICIN;
1072 case CHECK_LOUDNESS:
1073 return as->caps & AC97_CAPS_LOUDNESS;
1074 case CHECK_3D:
1075 return AC97_CAPS_ENHANCEMENT(as->caps) != 0;
1076 case CHECK_LINE1:
1077 return as->ext_mid & AC97_EXT_MODEM_LINE1;
1078 case CHECK_LINE2:
1079 return as->ext_mid & AC97_EXT_MODEM_LINE2;
1080 case CHECK_HANDSET:
1081 return as->ext_mid & AC97_EXT_MODEM_HANDSET;
1082 default:
1083 printf("%s: internal error: feature=%d\n", __func__, check);
1084 return 0;
1088 static void
1089 ac97_setup_source_info(struct ac97_softc *as)
1091 int idx, ouridx;
1092 struct ac97_source_info *si, *si2;
1093 uint16_t value1, value2, value3;
1095 for (idx = 0, ouridx = 0; idx < SOURCE_INFO_SIZE(as); idx++) {
1096 si = &as->source_info[ouridx];
1097 if (as->type == AC97_CODEC_TYPE_MODEM) {
1098 memcpy(si, &modem_source_info[idx], sizeof(*si));
1099 } else {
1100 memcpy(si, &audio_source_info[idx], sizeof(*si));
1102 if (!ac97_check_capability(as, si->req_feature))
1103 continue;
1104 if (si->checkbits) {
1105 /* read the register value */
1106 ac97_read(as, si->reg, &value1);
1107 /* write 0b100000 */
1108 value2 = value1 & 0xffc0;
1109 value2 |= 0x20;
1110 ac97_write(as, si->reg, value2);
1111 /* verify */
1112 ac97_read(as, si->reg, &value3);
1113 if (value2 == value3) {
1114 si->bits = 6;
1115 } else {
1116 si->bits = 5;
1118 DPRINTF(("%s: register=%02x bits=%d\n",
1119 __func__, si->reg, si->bits));
1120 ac97_write(as, si->reg, value1);
1123 switch (si->type) {
1124 case AUDIO_MIXER_CLASS:
1125 si->mixer_class = ouridx;
1126 ouridx++;
1127 break;
1128 case AUDIO_MIXER_VALUE:
1129 /* Todo - Test to see if it works */
1130 ouridx++;
1132 /* Add an entry for mute, if necessary */
1133 if (si->mute) {
1134 si = &as->source_info[ouridx];
1135 if (as->type == AC97_CODEC_TYPE_MODEM)
1136 memcpy(si, &modem_source_info[idx],
1137 sizeof(*si));
1138 else
1139 memcpy(si, &audio_source_info[idx],
1140 sizeof(*si));
1141 si->qualifier = AudioNmute;
1142 si->type = AUDIO_MIXER_ENUM;
1143 si->info = &ac97_on_off;
1144 si->info_size = sizeof(ac97_on_off);
1145 si->bits = 1;
1146 si->ofs = 15;
1147 si->mute = 0;
1148 si->polarity = 0;
1149 ouridx++;
1151 break;
1152 case AUDIO_MIXER_ENUM:
1153 /* Todo - Test to see if it works */
1154 ouridx++;
1155 break;
1156 default:
1157 aprint_error ("ac97: shouldn't get here\n");
1158 break;
1162 as->num_source_info = ouridx;
1164 for (idx = 0; idx < as->num_source_info; idx++) {
1165 int idx2, previdx;
1167 si = &as->source_info[idx];
1169 /* Find mixer class */
1170 for (idx2 = 0; idx2 < as->num_source_info; idx2++) {
1171 si2 = &as->source_info[idx2];
1173 if (si2->type == AUDIO_MIXER_CLASS &&
1174 ac97_str_equal(si->class,
1175 si2->class)) {
1176 si->mixer_class = idx2;
1181 /* Setup prev and next pointers */
1182 if (si->prev != 0)
1183 continue;
1185 if (si->qualifier)
1186 continue;
1188 si->prev = AUDIO_MIXER_LAST;
1189 previdx = idx;
1191 for (idx2 = 0; idx2 < as->num_source_info; idx2++) {
1192 if (idx2 == idx)
1193 continue;
1195 si2 = &as->source_info[idx2];
1197 if (!si2->prev &&
1198 ac97_str_equal(si->class, si2->class) &&
1199 ac97_str_equal(si->device, si2->device)) {
1200 as->source_info[previdx].next = idx2;
1201 as->source_info[idx2].prev = previdx;
1203 previdx = idx2;
1207 as->source_info[previdx].next = AUDIO_MIXER_LAST;
1211 /* backward compatibility */
1213 ac97_attach(struct ac97_host_if *host_if, device_t sc_dev)
1215 return ac97_attach_type(host_if, sc_dev, AC97_CODEC_TYPE_AUDIO);
1219 ac97_attach_type(struct ac97_host_if *host_if, device_t sc_dev, int type)
1221 struct ac97_softc *as;
1222 int error, i, j;
1223 uint32_t id;
1224 uint16_t id1, id2;
1225 uint16_t extstat, rate;
1226 uint16_t val;
1227 mixer_ctrl_t ctl;
1228 void (*initfunc)(struct ac97_softc *);
1229 #define FLAGBUFLEN 140
1230 char flagbuf[FLAGBUFLEN];
1232 initfunc = NULL;
1233 as = malloc(sizeof(struct ac97_softc), M_DEVBUF, M_WAITOK|M_ZERO);
1235 if (as == NULL)
1236 return ENOMEM;
1238 as->codec_if.vtbl = &ac97civ;
1239 as->host_if = host_if;
1240 as->type = type;
1242 if ((error = host_if->attach(host_if->arg, &as->codec_if))) {
1243 free(as, M_DEVBUF);
1244 return error;
1247 if (host_if->reset != NULL) {
1248 if ((error = host_if->reset(host_if->arg))) {
1249 free(as, M_DEVBUF);
1250 return error;
1254 if (host_if->flags)
1255 as->host_flags = host_if->flags(host_if->arg);
1258 * Assume codec has all four power bits.
1259 * XXXSCW: what to do for modems?
1261 as->power_all = AC97_POWER_REF | AC97_POWER_ANL | AC97_POWER_DAC |
1262 AC97_POWER_ADC;
1263 if (as->type == AC97_CODEC_TYPE_AUDIO) {
1264 host_if->write(host_if->arg, AC97_REG_RESET, 0);
1267 * Power-up everything except the analogue mixer.
1268 * If this codec doesn't support analogue mixer power-down,
1269 * AC97_POWER_MIXER will read back as zero.
1271 host_if->write(host_if->arg, AC97_REG_POWER, AC97_POWER_MIXER);
1272 ac97_read(as, AC97_REG_POWER, &val);
1273 if ((val & AC97_POWER_MIXER) == 0) {
1274 /* Codec doesn't support analogue mixer power-down */
1275 as->power_all &= ~AC97_POWER_ANL;
1277 host_if->write(host_if->arg, AC97_REG_POWER, POWER_EAMP_ON(as));
1279 for (i = 500000; i >= 0; i--) {
1280 ac97_read(as, AC97_REG_POWER, &val);
1281 if ((val & as->power_all) == as->power_all)
1282 break;
1283 DELAY(1);
1286 /* save AC97_REG_POWER so that we can restore it later */
1287 ac97_read(as, AC97_REG_POWER, &as->power_reg);
1288 } else if (as->type == AC97_CODEC_TYPE_MODEM) {
1289 host_if->write(host_if->arg, AC97_REG_EXT_MODEM_ID, 0);
1292 ac97_setup_defaults(as);
1293 if (as->type == AC97_CODEC_TYPE_AUDIO)
1294 ac97_read(as, AC97_REG_RESET, &as->caps);
1295 ac97_read(as, AC97_REG_VENDOR_ID1, &id1);
1296 ac97_read(as, AC97_REG_VENDOR_ID2, &id2);
1298 id = (id1 << 16) | id2;
1299 aprint_normal_dev(sc_dev, "ac97: ");
1301 for (i = 0; ; i++) {
1302 if (ac97codecid[i].id == 0) {
1303 char pnp[4];
1305 AC97_GET_CODEC_ID(id, pnp);
1306 #define ISASCII(c) ((c) >= ' ' && (c) < 0x7f)
1307 if (ISASCII(pnp[0]) && ISASCII(pnp[1]) &&
1308 ISASCII(pnp[2]))
1309 aprint_normal("%c%c%c%d",
1310 pnp[0], pnp[1], pnp[2], pnp[3]);
1311 else
1312 aprint_normal("unknown (0x%08x)", id);
1313 break;
1315 if (ac97codecid[i].id == (id & ac97codecid[i].mask)) {
1316 aprint_normal("%s", ac97codecid[i].name);
1317 if (ac97codecid[i].mask == AC97_VENDOR_ID_MASK) {
1318 aprint_normal(" (0x%08x)", id);
1320 initfunc = ac97codecid[i].init;
1321 break;
1324 aprint_normal(" codec; ");
1325 for (i = j = 0; i < 10; i++) {
1326 if (as->caps & (1 << i)) {
1327 aprint_normal("%s%s", j ? ", " : "", ac97feature[i]);
1328 j++;
1331 aprint_normal("%s%s\n", j ? ", " : "",
1332 ac97enhancement[AC97_CAPS_ENHANCEMENT(as->caps)]);
1334 as->ac97_clock = AC97_STANDARD_CLOCK;
1336 if (as->type == AC97_CODEC_TYPE_AUDIO) {
1337 ac97_read(as, AC97_REG_EXT_AUDIO_ID, &as->ext_id);
1338 if (as->ext_id != 0) {
1339 /* Print capabilities */
1340 snprintb(flagbuf, sizeof(flagbuf),
1341 "\20\20SECONDARY10\17SECONDARY01"
1342 "\14AC97_23\13AC97_22\12AMAP\11LDAC\10SDAC"
1343 "\7CDAC\4VRM\3SPDIF\2DRA\1VRA", as->ext_id);
1344 aprint_normal_dev(sc_dev, "ac97: ext id %s\n",
1345 flagbuf);
1347 /* Print unusual settings */
1348 if (as->ext_id & AC97_EXT_AUDIO_DSA_MASK) {
1349 aprint_normal_dev(sc_dev, "ac97: Slot assignment: ");
1350 switch (as->ext_id & AC97_EXT_AUDIO_DSA_MASK) {
1351 case AC97_EXT_AUDIO_DSA01:
1352 aprint_normal("7&8, 6&9, 10&11.\n");
1353 break;
1354 case AC97_EXT_AUDIO_DSA10:
1355 aprint_normal("6&9, 10&11, 3&4.\n");
1356 break;
1357 case AC97_EXT_AUDIO_DSA11:
1358 aprint_normal("10&11, 3&4, 7&8.\n");
1359 break;
1362 if (as->host_flags & AC97_HOST_INVERTED_EAMP) {
1363 aprint_normal_dev(sc_dev, "ac97: using inverted "
1364 "AC97_POWER_EAMP bit\n");
1367 /* Enable and disable features */
1368 ac97_read(as, AC97_REG_EXT_AUDIO_CTRL, &extstat);
1369 extstat &= ~AC97_EXT_AUDIO_DRA;
1370 if (as->ext_id & AC97_EXT_AUDIO_LDAC)
1371 extstat |= AC97_EXT_AUDIO_LDAC;
1372 if (as->ext_id & AC97_EXT_AUDIO_SDAC)
1373 extstat |= AC97_EXT_AUDIO_SDAC;
1374 if (as->ext_id & AC97_EXT_AUDIO_CDAC)
1375 extstat |= AC97_EXT_AUDIO_CDAC;
1376 if (as->ext_id & AC97_EXT_AUDIO_VRM)
1377 extstat |= AC97_EXT_AUDIO_VRM;
1378 if (as->ext_id & AC97_EXT_AUDIO_SPDIF) {
1379 /* Output the same data as DAC to SPDIF output */
1380 extstat &= ~AC97_EXT_AUDIO_SPSA_MASK;
1381 extstat |= AC97_EXT_AUDIO_SPSA34;
1382 ac97_read(as, AC97_REG_SPDIF_CTRL, &val);
1383 val = (val & ~AC97_SPDIF_SPSR_MASK)
1384 | AC97_SPDIF_SPSR_48K;
1385 ac97_write(as, AC97_REG_SPDIF_CTRL, val);
1387 if (as->ext_id & AC97_EXT_AUDIO_VRA)
1388 extstat |= AC97_EXT_AUDIO_VRA;
1389 ac97_write(as, AC97_REG_EXT_AUDIO_CTRL, extstat);
1390 if (as->ext_id & AC97_EXT_AUDIO_VRA) {
1391 /* VRA should be enabled. */
1392 /* so it claims to do variable rate, let's make sure */
1393 ac97_write(as, AC97_REG_PCM_FRONT_DAC_RATE,
1394 44100);
1395 ac97_read(as, AC97_REG_PCM_FRONT_DAC_RATE,
1396 &rate);
1397 if (rate != 44100) {
1398 /* We can't believe ext_id */
1399 as->ext_id = 0;
1400 aprint_normal_dev(sc_dev,
1401 "Ignore these capabilities.\n");
1403 /* restore the default value */
1404 ac97_write(as, AC97_REG_PCM_FRONT_DAC_RATE,
1405 AC97_SINGLE_RATE);
1408 } else if (as->type == AC97_CODEC_TYPE_MODEM) {
1409 const struct sysctlnode *node;
1410 const struct sysctlnode *node_line1;
1411 const struct sysctlnode *node_line2;
1412 uint16_t xrate = 8000;
1413 uint16_t xval, reg;
1414 int err;
1416 ac97_read(as, AC97_REG_EXT_MODEM_ID, &as->ext_mid);
1417 if (as->ext_mid == 0 || as->ext_mid == 0xffff) {
1418 aprint_normal_dev(sc_dev, "no modem codec found\n");
1419 return ENXIO;
1421 as->type = AC97_CODEC_TYPE_MODEM;
1423 /* Print capabilities */
1424 snprintb(flagbuf, sizeof(flagbuf),
1425 "\20\5CID2\4CID1\3HANDSET\2LINE2\1LINE1", as->ext_mid);
1426 aprint_normal_dev(sc_dev, "ac97: ext mid %s",
1427 flagbuf);
1428 aprint_normal(", %s codec\n",
1429 (as->ext_mid & 0xc000) == 0 ?
1430 "primary" : "secondary");
1432 /* Setup modem and sysctls */
1433 err = sysctl_createv(&as->log, 0, NULL, NULL, 0, CTLTYPE_NODE,
1434 "hw", NULL, NULL, 0, NULL, 0, CTL_HW,
1435 CTL_EOL);
1436 if (err != 0)
1437 goto setup_modem;
1438 err = sysctl_createv(&as->log, 0, NULL, &node, 0,
1439 CTLTYPE_NODE, device_xname(sc_dev), NULL,
1440 NULL, 0, NULL, 0, CTL_HW, CTL_CREATE,
1441 CTL_EOL);
1442 if (err != 0)
1443 goto setup_modem;
1444 setup_modem:
1445 /* reset */
1446 ac97_write(as, AC97_REG_EXT_MODEM_ID, 1);
1448 /* program rates */
1449 xval = 0xff00 & ~AC97_EXT_MODEM_CTRL_PRA;
1450 if (as->ext_mid & AC97_EXT_MODEM_LINE1) {
1451 ac97_write(as, AC97_REG_LINE1_RATE, xrate);
1452 xval &= ~(AC97_EXT_MODEM_CTRL_PRC |
1453 AC97_EXT_MODEM_CTRL_PRD);
1455 if (as->ext_mid & AC97_EXT_MODEM_LINE2) {
1456 ac97_write(as, AC97_REG_LINE2_RATE, xrate);
1457 xval &= ~(AC97_EXT_MODEM_CTRL_PRE |
1458 AC97_EXT_MODEM_CTRL_PRF);
1460 if (as->ext_mid & AC97_EXT_MODEM_HANDSET) {
1461 ac97_write(as, AC97_REG_HANDSET_RATE, xrate);
1462 xval &= ~(AC97_EXT_MODEM_CTRL_PRG |
1463 AC97_EXT_MODEM_CTRL_PRH);
1466 /* power-up everything */
1467 ac97_write(as, AC97_REG_EXT_MODEM_CTRL, 0);
1468 for (i = 5000; i >= 0; i--) {
1469 ac97_read(as, AC97_REG_EXT_MODEM_CTRL, &reg);
1470 if ((reg & /*XXXval*/0xf) == /*XXXval*/0xf)
1471 break;
1472 DELAY(1);
1474 if (i <= 0) {
1475 printf("%s: codec not responding, status=0x%x\n",
1476 device_xname(sc_dev), reg);
1477 return ENXIO;
1480 /* setup sysctls */
1481 if (as->ext_mid & AC97_EXT_MODEM_LINE1) {
1482 ac97_read(as, AC97_REG_GPIO_CFG, &reg);
1483 reg &= ~AC97_GPIO_LINE1_OH;
1484 ac97_write(as, AC97_REG_GPIO_CFG, reg);
1485 ac97_read(as, AC97_REG_GPIO_POLARITY, &reg);
1486 reg &= ~AC97_GPIO_LINE1_OH;
1487 ac97_write(as, AC97_REG_GPIO_POLARITY, reg);
1489 err = sysctl_createv(&as->log, 0, NULL, &node_line1,
1490 CTLFLAG_READWRITE, CTLTYPE_INT,
1491 "line1",
1492 SYSCTL_DESCR("off-hook line1"),
1493 ac97_sysctl_verify, 0, as, 0,
1494 CTL_HW, node->sysctl_num,
1495 CTL_CREATE, CTL_EOL);
1496 if (err != 0)
1497 goto sysctl_err;
1498 as->offhook_line1_mib = node_line1->sysctl_num;
1500 if (as->ext_mid & AC97_EXT_MODEM_LINE2) {
1501 ac97_read(as, AC97_REG_GPIO_CFG, &reg);
1502 reg &= ~AC97_GPIO_LINE2_OH;
1503 ac97_write(as, AC97_REG_GPIO_CFG, reg);
1504 ac97_read(as, AC97_REG_GPIO_POLARITY, &reg);
1505 reg &= ~AC97_GPIO_LINE2_OH;
1506 ac97_write(as, AC97_REG_GPIO_POLARITY, reg);
1508 err = sysctl_createv(&as->log, 0, NULL, &node_line2,
1509 CTLFLAG_READWRITE, CTLTYPE_INT,
1510 "line2",
1511 SYSCTL_DESCR("off-hook line2"),
1512 ac97_sysctl_verify, 0, as, 0,
1513 CTL_HW, node->sysctl_num,
1514 CTL_CREATE, CTL_EOL);
1515 if (err != 0)
1516 goto sysctl_err;
1517 as->offhook_line2_mib = node_line2->sysctl_num;
1519 sysctl_err:
1521 ac97_write(as, AC97_REG_GPIO_STICKY, 0xffff);
1522 ac97_write(as, AC97_REG_GPIO_WAKEUP, 0x0);
1523 ac97_write(as, AC97_REG_MISC_AFE, 0x0);
1526 as->source_info = (as->type == AC97_CODEC_TYPE_MODEM ?
1527 as->modem_source_info : as->audio_source_info);
1528 ac97_setup_source_info(as);
1530 memset(&ctl, 0, sizeof(ctl));
1531 /* disable mutes */
1532 for (i = 0; i < 11; i++) {
1533 static struct {
1534 const char *class, *device;
1535 } d[11] = {
1536 { AudioCoutputs, AudioNmaster},
1537 { AudioCoutputs, AudioNheadphone},
1538 { AudioCoutputs, AudioNsurround},
1539 { AudioCoutputs, AudioNcenter},
1540 { AudioCoutputs, AudioNlfe},
1541 { AudioCinputs, AudioNdac},
1542 { AudioCinputs, AudioNcd},
1543 { AudioCinputs, AudioNline},
1544 { AudioCinputs, AudioNaux},
1545 { AudioCinputs, AudioNvideo},
1546 { AudioCrecord, AudioNvolume},
1549 ctl.type = AUDIO_MIXER_ENUM;
1550 ctl.un.ord = 0;
1552 ctl.dev = ac97_get_portnum_by_name(&as->codec_if,
1553 d[i].class, d[i].device, AudioNmute);
1554 ac97_mixer_set_port(&as->codec_if, &ctl);
1556 ctl.type = AUDIO_MIXER_ENUM;
1557 ctl.un.ord = 0;
1558 ctl.dev = ac97_get_portnum_by_name(&as->codec_if, AudioCrecord,
1559 AudioNsource, NULL);
1560 ac97_mixer_set_port(&as->codec_if, &ctl);
1562 /* set a reasonable default volume */
1563 ctl.type = AUDIO_MIXER_VALUE;
1564 ctl.un.value.num_channels = 2;
1565 ctl.un.value.level[AUDIO_MIXER_LEVEL_LEFT] = \
1566 ctl.un.value.level[AUDIO_MIXER_LEVEL_RIGHT] = 127;
1567 ctl.dev = ac97_get_portnum_by_name(&as->codec_if, AudioCoutputs,
1568 AudioNmaster, NULL);
1569 ac97_mixer_set_port(&as->codec_if, &ctl);
1570 ctl.dev = ac97_get_portnum_by_name(&as->codec_if, AudioCoutputs,
1571 AudioNsurround, NULL);
1572 ac97_mixer_set_port(&as->codec_if, &ctl);
1573 ctl.un.value.num_channels = 1;
1574 ctl.dev = ac97_get_portnum_by_name(&as->codec_if, AudioCoutputs,
1575 AudioNcenter, NULL);
1576 ac97_mixer_set_port(&as->codec_if, &ctl);
1577 ctl.dev = ac97_get_portnum_by_name(&as->codec_if, AudioCoutputs,
1578 AudioNlfe, NULL);
1579 ac97_mixer_set_port(&as->codec_if, &ctl);
1581 if (initfunc != NULL)
1582 initfunc(as);
1584 /* restore AC97_REG_POWER */
1585 if (as->type == AC97_CODEC_TYPE_AUDIO)
1586 ac97_write(as, AC97_REG_POWER, as->power_reg);
1588 return 0;
1591 static void
1592 ac97_detach(struct ac97_codec_if *codec_if)
1594 struct ac97_softc *as;
1596 as = (struct ac97_softc *)codec_if;
1597 ac97_write(as, AC97_REG_POWER, AC97_POWER_IN | AC97_POWER_OUT
1598 | AC97_POWER_MIXER | AC97_POWER_MIXER_VREF
1599 | AC97_POWER_ACLINK | AC97_POWER_CLK | AC97_POWER_AUX
1600 | POWER_EAMP_OFF(as));
1601 free(as, M_DEVBUF);
1604 static void
1605 ac97_lock(struct ac97_codec_if *codec_if)
1607 struct ac97_softc *as;
1609 as = (struct ac97_softc *)codec_if;
1610 as->lock_counter++;
1613 static void
1614 ac97_unlock(struct ac97_codec_if *codec_if)
1616 struct ac97_softc *as;
1618 as = (struct ac97_softc *)codec_if;
1619 as->lock_counter--;
1622 static int
1623 ac97_query_devinfo(struct ac97_codec_if *codec_if, mixer_devinfo_t *dip)
1625 struct ac97_softc *as;
1626 struct ac97_source_info *si;
1627 const char *name;
1629 as = (struct ac97_softc *)codec_if;
1630 if (dip->index < as->num_source_info) {
1631 si = &as->source_info[dip->index];
1632 dip->type = si->type;
1633 dip->mixer_class = si->mixer_class;
1634 dip->prev = si->prev;
1635 dip->next = si->next;
1637 if (si->qualifier)
1638 name = si->qualifier;
1639 else if (si->device)
1640 name = si->device;
1641 else if (si->class)
1642 name = si->class;
1643 else
1644 name = 0;
1646 if (name)
1647 strcpy(dip->label.name, name);
1649 memcpy(&dip->un, si->info, si->info_size);
1651 /* Set the delta for volume sources */
1652 if (dip->type == AUDIO_MIXER_VALUE)
1653 dip->un.v.delta = 1 << (8 - si->bits);
1655 return 0;
1658 return ENXIO;
1661 static int
1662 ac97_mixer_set_port(struct ac97_codec_if *codec_if, mixer_ctrl_t *cp)
1664 struct ac97_softc *as;
1665 struct ac97_source_info *si;
1666 uint16_t mask;
1667 uint16_t val, newval;
1668 int error;
1669 bool spdif;
1671 as = (struct ac97_softc *)codec_if;
1672 if (cp->dev < 0 || cp->dev >= as->num_source_info)
1673 return EINVAL;
1674 si = &as->source_info[cp->dev];
1676 if (cp->type == AUDIO_MIXER_CLASS || cp->type != si->type)
1677 return EINVAL;
1678 spdif = si->req_feature == CHECK_SPDIF && si->reg == AC97_REG_EXT_AUDIO_CTRL;
1679 if (spdif && as->lock_counter >= 0) {
1680 /* When the value of lock_counter is the default 0,
1681 * it is not allowed to change the SPDIF mode. */
1682 return EBUSY;
1685 ac97_read(as, si->reg, &val);
1687 DPRINTFN(5, ("read(%x) = %x\n", si->reg, val));
1689 mask = (1 << si->bits) - 1;
1691 switch (cp->type) {
1692 case AUDIO_MIXER_ENUM:
1693 if (cp->un.ord > mask || cp->un.ord < 0)
1694 return EINVAL;
1696 newval = (cp->un.ord << si->ofs);
1697 if (si->reg == AC97_REG_RECORD_SELECT) {
1698 newval |= (newval << (8 + si->ofs));
1699 mask |= (mask << 8);
1700 mask = mask << si->ofs;
1701 } else if (si->reg == AC97_REG_SURR_MASTER) {
1702 newval = cp->un.ord ? 0x8080 : 0x0000;
1703 mask = 0x8080;
1704 } else
1705 mask = mask << si->ofs;
1706 break;
1707 case AUDIO_MIXER_VALUE:
1709 const struct audio_mixer_value *value = si->info;
1710 uint16_t l, r, ol, or;
1711 int deltal, deltar;
1713 if ((cp->un.value.num_channels <= 0) ||
1714 (cp->un.value.num_channels > value->num_channels))
1715 return EINVAL;
1717 if (cp->un.value.num_channels == 1) {
1718 l = r = cp->un.value.level[AUDIO_MIXER_LEVEL_MONO];
1719 } else {
1720 if (!(as->host_flags & AC97_HOST_SWAPPED_CHANNELS)) {
1721 l = cp->un.value.level[AUDIO_MIXER_LEVEL_LEFT];
1722 r = cp->un.value.level[AUDIO_MIXER_LEVEL_RIGHT];
1723 } else { /* left/right is reversed here */
1724 r = cp->un.value.level[AUDIO_MIXER_LEVEL_LEFT];
1725 l = cp->un.value.level[AUDIO_MIXER_LEVEL_RIGHT];
1730 if (!si->polarity) {
1731 l = 255 - l;
1732 r = 255 - r;
1735 ol = (val >> (8+si->ofs)) & mask;
1736 or = (val >> si->ofs) & mask;
1738 deltal = (ol << (8 - si->bits)) - l;
1739 deltar = (or << (8 - si->bits)) - r;
1741 l = l >> (8 - si->bits);
1742 r = r >> (8 - si->bits);
1744 if (deltal && ol == l)
1745 l += (deltal > 0) ? (l ? -1 : 0) : (l < mask ? 1 : 0);
1746 if (deltar && or == r)
1747 r += (deltar > 0) ? (r ? -1 : 0) : (r < mask ? 1 : 0);
1749 newval = ((r & mask) << si->ofs);
1750 if (value->num_channels == 2) {
1751 newval = newval | ((l & mask) << (si->ofs+8));
1752 mask |= (mask << 8);
1754 mask = mask << si->ofs;
1755 break;
1757 default:
1758 return EINVAL;
1761 error = ac97_write(as, si->reg, (val & ~mask) | newval);
1762 if (error)
1763 return error;
1765 if (spdif && as->host_if->spdif_event != NULL) {
1766 DPRINTF(("%s: call spdif_event(%d)\n", __func__, cp->un.ord));
1767 as->host_if->spdif_event(as->host_if->arg, cp->un.ord);
1769 return 0;
1772 static int
1773 ac97_get_portnum_by_name(struct ac97_codec_if *codec_if, const char *class,
1774 const char *device, const char *qualifier)
1776 struct ac97_softc *as;
1777 int idx;
1779 as = (struct ac97_softc *)codec_if;
1780 for (idx = 0; idx < as->num_source_info; idx++) {
1781 struct ac97_source_info *si = &as->source_info[idx];
1782 if (ac97_str_equal(class, si->class) &&
1783 ac97_str_equal(device, si->device) &&
1784 ac97_str_equal(qualifier, si->qualifier))
1785 return idx;
1788 return -1;
1791 static int
1792 ac97_mixer_get_port(struct ac97_codec_if *codec_if, mixer_ctrl_t *cp)
1794 struct ac97_softc *as;
1795 struct ac97_source_info *si;
1796 uint16_t mask;
1797 uint16_t val;
1799 as = (struct ac97_softc *)codec_if;
1800 si = &as->source_info[cp->dev];
1801 if (cp->dev < 0 || cp->dev >= as->num_source_info)
1802 return EINVAL;
1804 if (cp->type != si->type)
1805 return EINVAL;
1807 ac97_read(as, si->reg, &val);
1809 DPRINTFN(5, ("read(%x) = %x\n", si->reg, val));
1811 mask = (1 << si->bits) - 1;
1813 switch (cp->type) {
1814 case AUDIO_MIXER_ENUM:
1815 cp->un.ord = (val >> si->ofs) & mask;
1816 DPRINTFN(4, ("AUDIO_MIXER_ENUM: %x %d %x %d\n",
1817 val, si->ofs, mask, cp->un.ord));
1818 break;
1819 case AUDIO_MIXER_VALUE:
1821 const struct audio_mixer_value *value = si->info;
1822 uint16_t l, r;
1824 if ((cp->un.value.num_channels <= 0) ||
1825 (cp->un.value.num_channels > value->num_channels))
1826 return EINVAL;
1828 if (value->num_channels == 1) {
1829 l = r = (val >> si->ofs) & mask;
1830 } else {
1831 if (!(as->host_flags & AC97_HOST_SWAPPED_CHANNELS)) {
1832 l = (val >> (si->ofs + 8)) & mask;
1833 r = (val >> si->ofs) & mask;
1834 } else { /* host has reversed channels */
1835 r = (val >> (si->ofs + 8)) & mask;
1836 l = (val >> si->ofs) & mask;
1840 l = (l << (8 - si->bits));
1841 r = (r << (8 - si->bits));
1842 if (!si->polarity) {
1843 l = 255 - l;
1844 r = 255 - r;
1847 /* The EAP driver averages l and r for stereo
1848 channels that are requested in MONO mode. Does this
1849 make sense? */
1850 if (cp->un.value.num_channels == 1) {
1851 cp->un.value.level[AUDIO_MIXER_LEVEL_MONO] = l;
1852 } else if (cp->un.value.num_channels == 2) {
1853 cp->un.value.level[AUDIO_MIXER_LEVEL_LEFT] = l;
1854 cp->un.value.level[AUDIO_MIXER_LEVEL_RIGHT] = r;
1857 break;
1859 default:
1860 return EINVAL;
1863 return 0;
1867 static int
1868 ac97_set_rate(struct ac97_codec_if *codec_if, int target, u_int *rate)
1870 struct ac97_softc *as;
1871 u_int value;
1872 uint16_t ext_stat;
1873 uint16_t actual;
1874 uint16_t power;
1875 uint16_t power_bit;
1877 as = (struct ac97_softc *)codec_if;
1878 if (target == AC97_REG_PCM_MIC_ADC_RATE) {
1879 if (!(as->ext_id & AC97_EXT_AUDIO_VRM)) {
1880 *rate = AC97_SINGLE_RATE;
1881 return 0;
1883 } else {
1884 if (!(as->ext_id & AC97_EXT_AUDIO_VRA)) {
1885 *rate = AC97_SINGLE_RATE;
1886 return 0;
1889 value = *rate * AC97_STANDARD_CLOCK / as->ac97_clock;
1890 ext_stat = 0;
1892 * PCM_FRONT_DAC_RATE/PCM_SURR_DAC_RATE/PCM_LFE_DAC_RATE
1893 * Check VRA, DRA
1894 * PCM_LR_ADC_RATE
1895 * Check VRA
1896 * PCM_MIC_ADC_RATE
1897 * Check VRM
1899 switch (target) {
1900 case AC97_REG_PCM_FRONT_DAC_RATE:
1901 case AC97_REG_PCM_SURR_DAC_RATE:
1902 case AC97_REG_PCM_LFE_DAC_RATE:
1903 power_bit = AC97_POWER_OUT;
1904 if (!(as->ext_id & AC97_EXT_AUDIO_VRA)) {
1905 *rate = AC97_SINGLE_RATE;
1906 return 0;
1908 if (as->ext_id & AC97_EXT_AUDIO_DRA) {
1909 ac97_read(as, AC97_REG_EXT_AUDIO_CTRL, &ext_stat);
1910 if (value > 0x1ffff) {
1911 return EINVAL;
1912 } else if (value > 0xffff) {
1913 /* Enable DRA */
1914 ext_stat |= AC97_EXT_AUDIO_DRA;
1915 ac97_write(as, AC97_REG_EXT_AUDIO_CTRL, ext_stat);
1916 value /= 2;
1917 } else {
1918 /* Disable DRA */
1919 ext_stat &= ~AC97_EXT_AUDIO_DRA;
1920 ac97_write(as, AC97_REG_EXT_AUDIO_CTRL, ext_stat);
1922 } else {
1923 if (value > 0xffff)
1924 return EINVAL;
1926 break;
1927 case AC97_REG_PCM_LR_ADC_RATE:
1928 power_bit = AC97_POWER_IN;
1929 if (!(as->ext_id & AC97_EXT_AUDIO_VRA)) {
1930 *rate = AC97_SINGLE_RATE;
1931 return 0;
1933 if (value > 0xffff)
1934 return EINVAL;
1935 break;
1936 case AC97_REG_PCM_MIC_ADC_RATE:
1937 power_bit = AC97_POWER_IN;
1938 if (!(as->ext_id & AC97_EXT_AUDIO_VRM)) {
1939 *rate = AC97_SINGLE_RATE;
1940 return 0;
1942 if (value > 0xffff)
1943 return EINVAL;
1944 break;
1945 default:
1946 printf("%s: Unknown register: 0x%x\n", __func__, target);
1947 return EINVAL;
1950 ac97_read(as, AC97_REG_POWER, &power);
1951 ac97_write(as, AC97_REG_POWER, power | power_bit);
1953 ac97_write(as, target, (uint16_t)value);
1954 ac97_read(as, target, &actual);
1955 actual = (uint32_t)actual * as->ac97_clock / AC97_STANDARD_CLOCK;
1957 ac97_write(as, AC97_REG_POWER, power);
1958 if (ext_stat & AC97_EXT_AUDIO_DRA) {
1959 *rate = actual * 2;
1960 } else {
1961 *rate = actual;
1963 return 0;
1966 static void
1967 ac97_set_clock(struct ac97_codec_if *codec_if, unsigned int clock)
1969 struct ac97_softc *as;
1971 as = (struct ac97_softc *)codec_if;
1972 as->ac97_clock = clock;
1975 static uint16_t
1976 ac97_get_extcaps(struct ac97_codec_if *codec_if)
1978 struct ac97_softc *as;
1980 as = (struct ac97_softc *)codec_if;
1981 return as->ext_id;
1984 static int
1985 ac97_add_port(struct ac97_softc *as, const struct ac97_source_info *src)
1987 struct ac97_source_info *si;
1988 int ouridx, idx;
1990 if ((as->type == AC97_CODEC_TYPE_AUDIO &&
1991 as->num_source_info >= AUDIO_MAX_SOURCES) ||
1992 (as->type == AC97_CODEC_TYPE_MODEM &&
1993 as->num_source_info >= MODEM_MAX_SOURCES)) {
1994 printf("%s: internal error: increase MAX_SOURCES in %s\n",
1995 __func__, __FILE__);
1996 return -1;
1998 if (!ac97_check_capability(as, src->req_feature))
1999 return -1;
2000 ouridx = as->num_source_info;
2001 si = &as->source_info[ouridx];
2002 memcpy(si, src, sizeof(*si));
2004 switch (si->type) {
2005 case AUDIO_MIXER_CLASS:
2006 case AUDIO_MIXER_VALUE:
2007 printf("%s: adding class/value is not supported yet.\n",
2008 __func__);
2009 return -1;
2010 case AUDIO_MIXER_ENUM:
2011 break;
2012 default:
2013 printf("%s: unknown type: %d\n", __func__, si->type);
2014 return -1;
2016 as->num_source_info++;
2018 si->mixer_class = ac97_get_portnum_by_name(&as->codec_if, si->class,
2019 NULL, NULL);
2020 /* Find the root of the device */
2021 idx = ac97_get_portnum_by_name(&as->codec_if, si->class,
2022 si->device, NULL);
2023 /* Find the last item */
2024 while (as->source_info[idx].next != AUDIO_MIXER_LAST)
2025 idx = as->source_info[idx].next;
2026 /* Append */
2027 as->source_info[idx].next = ouridx;
2028 si->prev = idx;
2029 si->next = AUDIO_MIXER_LAST;
2031 return 0;
2035 * Codec-dependent initialization
2038 #define AD1980_REG_MISC 0x76
2039 #define AD1980_MISC_MBG0 0x0001 /* 0 1888/1980/1981 /1985 */
2040 #define AD1980_MISC_MBG1 0x0002 /* 1 1888/1980/1981 /1985 */
2041 #define AD1980_MISC_VREFD 0x0004 /* 2 1888/1980/1981 /1985 */
2042 #define AD1980_MISC_VREFH 0x0008 /* 3 1888/1980/1981 /1985 */
2043 #define AD1980_MISC_SRU 0x0010 /* 4 1888/1980 /1985 */
2044 #define AD1980_MISC_LOSEL 0x0020 /* 5 1888/1980/1981 /1985 */
2045 #define AD1980_MISC_2CMIC 0x0040 /* 6 1980/1981B/1985 */
2046 #define AD1980_MISC_SPRD 0x0080 /* 7 1888/1980 /1985 */
2047 #define AD1980_MISC_DMIX0 0x0100 /* 8 1888/1980 /1985 */
2048 #define AD1980_MISC_DMIX1 0x0200 /* 9 1888/1980 /1985 */
2049 #define AD1980_MISC_HPSEL 0x0400 /*10 1888/1980 /1985 */
2050 #define AD1980_MISC_CLDIS 0x0800 /*11 1888/1980 /1985 */
2051 #define AD1980_MISC_LODIS 0x1000 /*12 1888/1980/1981 /1985 */
2052 #define AD1980_MISC_MSPLT 0x2000 /*13 1888/1980/1981 /1985 */
2053 #define AD1980_MISC_AC97NC 0x4000 /*14 1888/1980 /1985 */
2054 #define AD1980_MISC_DACZ 0x8000 /*15 1888/1980/1981 /1985 */
2055 #define AD1981_REG_MISC 0x76
2056 #define AD1981_MISC_MADST 0x0010 /* 4 */
2057 #define AD1981A_MISC_MADPD 0x0040 /* 6 */
2058 #define AD1981B_MISC_MADPD 0x0080 /* 7 */
2059 #define AD1981_MISC_FMXE 0x0200 /* 9 */
2060 #define AD1981_MISC_DAM 0x0800 /*11 */
2061 static void
2062 ac97_ad198x_init(struct ac97_softc *as)
2064 int i;
2065 uint16_t misc;
2067 ac97_read(as, AD1980_REG_MISC, &misc);
2068 ac97_write(as, AD1980_REG_MISC,
2069 misc | AD1980_MISC_LOSEL | AD1980_MISC_HPSEL);
2071 for (i = 0; i < as->num_source_info; i++) {
2072 if (as->source_info[i].type != AUDIO_MIXER_VALUE)
2073 continue;
2075 if (as->source_info[i].reg == AC97_REG_MASTER_VOLUME)
2076 as->source_info[i].reg = AC97_REG_SURR_MASTER;
2077 else if (as->source_info[i].reg == AC97_REG_SURR_MASTER)
2078 as->source_info[i].reg = AC97_REG_MASTER_VOLUME;
2082 #define ALC650_REG_MULTI_CHANNEL_CONTROL 0x6a
2083 #define ALC650_MCC_SLOT_MODIFY_MASK 0xc000
2084 #define ALC650_MCC_FRONTDAC_FROM_SPDIFIN 0x2000 /* 13 */
2085 #define ALC650_MCC_SPDIFOUT_FROM_ADC 0x1000 /* 12 */
2086 #define ALC650_MCC_PCM_FROM_SPDIFIN 0x0800 /* 11 */
2087 #define ALC650_MCC_MIC_OR_CENTERLFE 0x0400 /* 10 */
2088 #define ALC650_MCC_LINEIN_OR_SURROUND 0x0200 /* 9 */
2089 #define ALC650_MCC_INDEPENDENT_MASTER_L 0x0080 /* 7 */
2090 #define ALC650_MCC_INDEPENDENT_MASTER_R 0x0040 /* 6 */
2091 #define ALC650_MCC_ANALOG_TO_CENTERLFE 0x0020 /* 5 */
2092 #define ALC650_MCC_ANALOG_TO_SURROUND 0x0010 /* 4 */
2093 #define ALC650_MCC_EXCHANGE_CENTERLFE 0x0008 /* 3 */
2094 #define ALC650_MCC_CENTERLFE_DOWNMIX 0x0004 /* 2 */
2095 #define ALC650_MCC_SURROUND_DOWNMIX 0x0002 /* 1 */
2096 #define ALC650_MCC_LINEOUT_TO_SURROUND 0x0001 /* 0 */
2097 static void
2098 ac97_alc650_init(struct ac97_softc *as)
2100 static const struct ac97_source_info sources[6] = {
2101 { AudioCoutputs, AudioNsurround, "lineinjack",
2102 AUDIO_MIXER_ENUM, WRAP(ac97_on_off),
2103 ALC650_REG_MULTI_CHANNEL_CONTROL,
2104 0x0000, 1, 9, 0, 0, 0, CHECK_SURROUND, 0, 0, 0, },
2105 { AudioCoutputs, AudioNsurround, "mixtofront",
2106 AUDIO_MIXER_ENUM, WRAP(ac97_on_off),
2107 ALC650_REG_MULTI_CHANNEL_CONTROL,
2108 0x0000, 1, 1, 0, 0, 0, CHECK_SURROUND, 0, 0, 0, },
2109 { AudioCoutputs, AudioNcenter, "micjack",
2110 AUDIO_MIXER_ENUM, WRAP(ac97_on_off),
2111 ALC650_REG_MULTI_CHANNEL_CONTROL,
2112 0x0000, 1, 10, 0, 0, 0, CHECK_CENTER, 0, 0, 0, },
2113 { AudioCoutputs, AudioNlfe, "micjack",
2114 AUDIO_MIXER_ENUM, WRAP(ac97_on_off),
2115 ALC650_REG_MULTI_CHANNEL_CONTROL,
2116 0x0000, 1, 10, 0, 0, 0, CHECK_LFE, 0, 0, 0, },
2117 { AudioCoutputs, AudioNcenter, "mixtofront",
2118 AUDIO_MIXER_ENUM, WRAP(ac97_on_off),
2119 ALC650_REG_MULTI_CHANNEL_CONTROL,
2120 0x0000, 1, 2, 0, 0, 0, CHECK_CENTER, 0, 0, 0, },
2121 { AudioCoutputs, AudioNlfe, "mixtofront",
2122 AUDIO_MIXER_ENUM, WRAP(ac97_on_off),
2123 ALC650_REG_MULTI_CHANNEL_CONTROL,
2124 0x0000, 1, 2, 0, 0, 0, CHECK_LFE, 0, 0, 0, },
2127 ac97_add_port(as, &sources[0]);
2128 ac97_add_port(as, &sources[1]);
2129 ac97_add_port(as, &sources[2]);
2130 ac97_add_port(as, &sources[3]);
2131 ac97_add_port(as, &sources[4]);
2132 ac97_add_port(as, &sources[5]);
2135 #define UCB1400_REG_FEATURE_CSR1 0x6a
2136 #define UCB1400_BB(bb) (((bb) & 0xf) << 11)
2137 #define UCB1400_TR(tr) (((tr) & 0x3) << 9)
2138 #define UCB1400_M_MAXIMUM (3 << 7)
2139 #define UCB1400_M_MINIMUM (1 << 7)
2140 #define UCB1400_M_FLAT (0 << 7)
2141 #define UCB1400_HPEN (1 << 6)
2142 #define UCB1400_DE (1 << 5)
2143 #define UCB1400_DC (1 << 4)
2144 #define UCB1400_HIPS (1 << 3)
2145 #define UCB1400_GIEN (1 << 2)
2146 #define UCB1400_OVFL (1 << 0)
2147 #define UCB1400_REG_FEATURE_CSR2 0x6c
2148 #define UCB1400_SMT (1 << 15) /* Must be 0 */
2149 #define UCB1400_SUEV1 (1 << 14) /* Must be 0 */
2150 #define UCB1400_SUEV0 (1 << 13) /* Must be 0 */
2151 #define UCB1400_AVE (1 << 12)
2152 #define UCB1400_AVEN1 (1 << 11) /* Must be 0 */
2153 #define UCB1400_AVEN0 (1 << 10) /* Must be 0 */
2154 #define UCB1400_SLP_ON \
2155 (UCB1400_SLP_PLL | UCB1400_SLP_CODEC)
2156 #define UCB1400_SLP_PLL (2 << 4)
2157 #define UCB1400_SLP_CODEC (1 << 4)
2158 #define UCB1400_SLP_NO (0 << 4)
2159 #define UCB1400_EV2 (1 << 2) /* Must be 0 */
2160 #define UCB1400_EV1 (1 << 1) /* Must be 0 */
2161 #define UCB1400_EV0 (1 << 0) /* Must be 0 */
2162 static void
2163 ac97_ucb1400_init(struct ac97_softc *as)
2166 ac97_write(as, UCB1400_REG_FEATURE_CSR1,
2167 UCB1400_HPEN | UCB1400_DC | UCB1400_HIPS | UCB1400_OVFL);
2168 ac97_write(as, UCB1400_REG_FEATURE_CSR2, UCB1400_AVE | UCB1400_SLP_ON);
2171 #define VT1616_REG_IO_CONTROL 0x5a
2172 #define VT1616_IC_LVL (1 << 15)
2173 #define VT1616_IC_LFECENTER_TO_FRONT (1 << 12)
2174 #define VT1616_IC_SURROUND_TO_FRONT (1 << 11)
2175 #define VT1616_IC_BPDC (1 << 10)
2176 #define VT1616_IC_DC (1 << 9)
2177 #define VT1616_IC_IB_MASK 0x000c
2178 static void
2179 ac97_vt1616_init(struct ac97_softc *as)
2181 static const struct ac97_source_info sources[3] = {
2182 { AudioCoutputs, AudioNsurround, "mixtofront",
2183 AUDIO_MIXER_ENUM, WRAP(ac97_on_off),
2184 VT1616_REG_IO_CONTROL,
2185 0x0000, 1, 11, 0, 0, 0, CHECK_SURROUND, 0, 0, 0, },
2186 { AudioCoutputs, AudioNcenter, "mixtofront",
2187 AUDIO_MIXER_ENUM, WRAP(ac97_on_off),
2188 VT1616_REG_IO_CONTROL,
2189 0x0000, 1, 12, 0, 0, 0, CHECK_CENTER, 0, 0, 0, },
2190 { AudioCoutputs, AudioNlfe, "mixtofront",
2191 AUDIO_MIXER_ENUM, WRAP(ac97_on_off),
2192 VT1616_REG_IO_CONTROL,
2193 0x0000, 1, 12, 0, 0, 0, CHECK_LFE, 0, 0, 0, },
2196 ac97_add_port(as, &sources[0]);
2197 ac97_add_port(as, &sources[1]);
2198 ac97_add_port(as, &sources[2]);
2201 static int
2202 ac97_modem_offhook_set(struct ac97_softc *as, int line, int newval)
2204 uint16_t val;
2206 val = as->shadow_reg[AC97_REG_GPIO_STATUS >> 1];
2207 switch (newval) {
2208 case 0:
2209 val &= ~line;
2210 break;
2211 case 1:
2212 val |= line;
2213 break;
2215 ac97_write(as, AC97_REG_GPIO_STATUS, val);
2217 return 0;
2220 static int
2221 ac97_sysctl_verify(SYSCTLFN_ARGS)
2223 int error, tmp;
2224 struct sysctlnode node;
2225 struct ac97_softc *as;
2227 node = *rnode;
2228 as = rnode->sysctl_data;
2229 if (node.sysctl_num == as->offhook_line1_mib) {
2230 tmp = as->offhook_line1;
2231 node.sysctl_data = &tmp;
2232 error = sysctl_lookup(SYSCTLFN_CALL(&node));
2233 if (error || newp == NULL)
2234 return error;
2236 if (tmp < 0 || tmp > 1)
2237 return EINVAL;
2239 as->offhook_line1 = tmp;
2240 ac97_modem_offhook_set(as, AC97_GPIO_LINE1_OH, tmp);
2241 } else if (node.sysctl_num == as->offhook_line2_mib) {
2242 tmp = as->offhook_line2;
2243 node.sysctl_data = &tmp;
2244 error = sysctl_lookup(SYSCTLFN_CALL(&node));
2245 if (error || newp == NULL)
2246 return error;
2248 if (tmp < 0 || tmp > 1)
2249 return EINVAL;
2251 as->offhook_line2 = tmp;
2252 ac97_modem_offhook_set(as, AC97_GPIO_LINE2_OH, tmp);
2255 return 0;