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