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