1 /* $OpenBSD: ac97.c,v 1.85 2024/04/29 00:29:48 jsg Exp $ */
2
3 /*
4 * Copyright (c) 1999, 2000 Constantine Sapuntzakis
5 *
6 * Author: Constantine Sapuntzakis <csapuntz@stanford.edu>
7 *
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
10 * are met:
11 * 1. Redistributions of source code must retain the above copyright
12 * notice, this list of conditions and the following disclaimer.
13 * 2. Redistributions in binary form must reproduce the above copyright
14 * notice, this list of conditions and the following disclaimer in the
15 * documentation and/or other materials provided with the distribution.
16 * 3. The name of the author may not be used to endorse or promote
17 * products derived from this software without specific prior written
18 * permission.
19 * THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS
20 * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
21 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE
23 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
24 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
25 * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
26 * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
27 * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
28 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
29 * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
30 * DAMAGE. */
31
32 /* Partially inspired by FreeBSD's sys/dev/pcm/ac97.c. It came with
33 the following copyright */
34
35 /*
36 * Copyright (c) 1999 Cameron Grant <gandalf@vilnya.demon.co.uk>
37 * All rights reserved.
38 *
39 * Redistribution and use in source and binary forms, with or without
40 * modification, are permitted provided that the following conditions
41 * are met:
42 * 1. Redistributions of source code must retain the above copyright
43 * notice, this list of conditions and the following disclaimer.
44 * 2. Redistributions in binary form must reproduce the above copyright
45 * notice, this list of conditions and the following disclaimer in the
46 * documentation and/or other materials provided with the distribution.
47 *
48 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
49 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
50 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
51 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
52 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
53 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
54 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
55 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
56 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
57 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
58 * SUCH DAMAGE.
59 *
60 * $FreeBSD$
61 */
62
63 #include <sys/param.h>
64 #include <sys/systm.h>
65 #include <sys/kernel.h>
66 #include <sys/malloc.h>
67
68 #include <sys/audioio.h>
69 #include <dev/audio_if.h>
70 #include <dev/ic/ac97.h>
71
72 const struct audio_mixer_enum ac97_on_off = {
73 2,
74 { { { AudioNoff } , 0 },
75 { { AudioNon } , 1 } }
76 };
77
78 const struct audio_mixer_enum ac97_mic_select = {
79 2,
80 { { { AudioNmicrophone "0" }, 0 },
81 { { AudioNmicrophone "1" }, 1 } }
82 };
83
84 const struct audio_mixer_enum ac97_mono_select = {
85 2,
86 { { { AudioNmixerout }, 0 },
87 { { AudioNmicrophone }, 1 } }
88 };
89
90 const struct audio_mixer_enum ac97_source = {
91 8,
92 { { { AudioNmicrophone } , 0 },
93 { { AudioNcd }, 1 },
94 { { "video" }, 2 },
95 { { AudioNaux }, 3 },
96 { { AudioNline }, 4 },
97 { { AudioNmixerout }, 5 },
98 { { AudioNmixerout AudioNmono }, 6 },
99 { { "phone" }, 7 }}
100 };
101
102 /*
103 * Due to different values for each source that uses these structures,
104 * the ac97_query_devinfo function sets delta in mixer_devinfo_t using
105 * ac97_source_info.bits.
106 */
107 const struct audio_mixer_value ac97_volume_stereo = {
108 { AudioNvolume },
109 2
110 };
111
112 const struct audio_mixer_value ac97_volume_mono = {
113 { AudioNvolume },
114 1
115 };
116
117 #define AudioNspdif "spdif"
118
119 #define WRAP(a) &a, sizeof(a)
120
121 const struct ac97_source_info {
122 char *class;
123 char *device;
124 char *qualifier;
125 int type;
126
127 const void *info;
128 int16_t info_size;
129
130 u_int8_t reg;
131 u_int16_t default_value;
132 u_int8_t bits:3;
133 u_int8_t ofs:4;
134 u_int8_t mute:1;
135 u_int8_t polarity:1; /* Does 0 == MAX or MIN */
136 enum {
137 CHECK_NONE = 0,
138 CHECK_SURROUND,
139 CHECK_CENTER,
140 CHECK_LFE,
141 CHECK_HEADPHONES,
142 CHECK_TONE,
143 CHECK_MIC,
144 CHECK_LOUDNESS,
145 CHECK_3D,
146 CHECK_SPDIF
147 } req_feature;
148
149 int16_t prev;
150 int16_t next;
151 int16_t mixer_class;
152 } source_info[] = {
153 { AudioCinputs, NULL, NULL,
154 AUDIO_MIXER_CLASS, },
155 { AudioCoutputs, NULL, NULL,
156 AUDIO_MIXER_CLASS, },
157 { AudioCrecord, NULL, NULL,
158 AUDIO_MIXER_CLASS, },
159 /* Stereo master volume*/
160 { AudioCoutputs, AudioNmaster, NULL,
161 AUDIO_MIXER_VALUE, WRAP(ac97_volume_stereo),
162 AC97_REG_MASTER_VOLUME, 0x8000, 5, 0, 1,
163 },
164 /* Mono volume */
165 { AudioCoutputs, AudioNmono, NULL,
166 AUDIO_MIXER_VALUE, WRAP(ac97_volume_mono),
167 AC97_REG_MASTER_VOLUME_MONO, 0x8000, 6, 0, 1,
168 },
169 { AudioCoutputs, AudioNmono, AudioNsource,
170 AUDIO_MIXER_ENUM, WRAP(ac97_mono_select),
171 AC97_REG_GP, 0x0000, 1, 9, 0,
172 },
173 /* Headphone volume */
174 { AudioCoutputs, AudioNheadphone, NULL,
175 AUDIO_MIXER_VALUE, WRAP(ac97_volume_stereo),
176 AC97_REG_HEADPHONE_VOLUME, 0x8000, 6, 0, 1, 0, CHECK_HEADPHONES
177 },
178 /* Surround volume - logic hard coded for mute */
179 { AudioCoutputs, AudioNsurround, NULL,
180 AUDIO_MIXER_VALUE, WRAP(ac97_volume_stereo),
181 AC97_REG_SURR_MASTER, 0x8080, 5, 0, 1, 0, CHECK_SURROUND
182 },
183 /* Center volume*/
184 { AudioCoutputs, AudioNcenter, NULL,
185 AUDIO_MIXER_VALUE, WRAP(ac97_volume_mono),
186 AC97_REG_CENTER_LFE_MASTER, 0x8080, 5, 0, 0, 0, CHECK_CENTER
187 },
188 { AudioCoutputs, AudioNcenter, AudioNmute,
189 AUDIO_MIXER_ENUM, WRAP(ac97_on_off),
190 AC97_REG_CENTER_LFE_MASTER, 0x8080, 1, 7, 0, 0, CHECK_CENTER
191 },
192 /* LFE volume*/
193 { AudioCoutputs, AudioNlfe, NULL,
194 AUDIO_MIXER_VALUE, WRAP(ac97_volume_mono),
195 AC97_REG_CENTER_LFE_MASTER, 0x8080, 5, 8, 0, 0, CHECK_LFE
196 },
197 { AudioCoutputs, AudioNlfe, AudioNmute,
198 AUDIO_MIXER_ENUM, WRAP(ac97_on_off),
199 AC97_REG_CENTER_LFE_MASTER, 0x8080, 1, 15, 0, 0, CHECK_LFE
200 },
201 /* Tone */
202 { AudioCoutputs, "tone", NULL,
203 AUDIO_MIXER_VALUE, WRAP(ac97_volume_stereo),
204 AC97_REG_MASTER_TONE, 0x0f0f, 4, 0, 0, 0, CHECK_TONE
205 },
206 /* PC Beep Volume */
207 { AudioCinputs, AudioNspeaker, NULL,
208 AUDIO_MIXER_VALUE, WRAP(ac97_volume_mono),
209 AC97_REG_PCBEEP_VOLUME, 0x0000, 4, 1, 1,
210 },
211
212 /* Phone */
213 { AudioCinputs, "phone", NULL,
214 AUDIO_MIXER_VALUE, WRAP(ac97_volume_mono),
215 AC97_REG_PHONE_VOLUME, 0x8008, 5, 0, 1,
216 },
217 /* Mic Volume */
218 { AudioCinputs, AudioNmicrophone, NULL,
219 AUDIO_MIXER_VALUE, WRAP(ac97_volume_mono),
220 AC97_REG_MIC_VOLUME, 0x8008, 5, 0, 1,
221 },
222 { AudioCinputs, AudioNmicrophone, AudioNpreamp,
223 AUDIO_MIXER_ENUM, WRAP(ac97_on_off),
224 AC97_REG_MIC_VOLUME, 0x8008, 1, 6, 0,
225 },
226 { AudioCinputs, AudioNmicrophone, AudioNsource,
227 AUDIO_MIXER_ENUM, WRAP(ac97_mic_select),
228 AC97_REG_GP, 0x0000, 1, 8, 0,
229 },
230 /* Line in Volume */
231 { AudioCinputs, AudioNline, NULL,
232 AUDIO_MIXER_VALUE, WRAP(ac97_volume_stereo),
233 AC97_REG_LINEIN_VOLUME, 0x8808, 5, 0, 1,
234 },
235 /* CD Volume */
236 { AudioCinputs, AudioNcd, NULL,
237 AUDIO_MIXER_VALUE, WRAP(ac97_volume_stereo),
238 AC97_REG_CD_VOLUME, 0x8808, 5, 0, 1,
239 },
240 /* Video Volume */
241 { AudioCinputs, AudioNvideo, NULL,
242 AUDIO_MIXER_VALUE, WRAP(ac97_volume_stereo),
243 AC97_REG_VIDEO_VOLUME, 0x8808, 5, 0, 1,
244 },
245 /* AUX volume */
246 { AudioCinputs, AudioNaux, NULL,
247 AUDIO_MIXER_VALUE, WRAP(ac97_volume_stereo),
248 AC97_REG_AUX_VOLUME, 0x8808, 5, 0, 1,
249 },
250 /* PCM out volume */
251 { AudioCinputs, AudioNdac, NULL,
252 AUDIO_MIXER_VALUE, WRAP(ac97_volume_stereo),
253 AC97_REG_PCMOUT_VOLUME, 0x8808, 5, 0, 1,
254 },
255 /* Record Source - some logic for this is hard coded - see below */
256 { AudioCrecord, AudioNsource, NULL,
257 AUDIO_MIXER_ENUM, WRAP(ac97_source),
258 AC97_REG_RECORD_SELECT, 0x0000, 3, 0, 0,
259 },
260 /* Record Gain */
261 { AudioCrecord, AudioNvolume, NULL,
262 AUDIO_MIXER_VALUE, WRAP(ac97_volume_stereo),
263 AC97_REG_RECORD_GAIN, 0x8000, 4, 0, 1,
264 },
265 /* Record Gain mic */
266 { AudioCrecord, AudioNmicrophone, NULL,
267 AUDIO_MIXER_VALUE, WRAP(ac97_volume_mono),
268 AC97_REG_RECORD_GAIN_MIC, 0x8000, 4, 0, 1, 1, CHECK_MIC
269 },
270 /* */
271 { AudioCoutputs, AudioNloudness, NULL,
272 AUDIO_MIXER_ENUM, WRAP(ac97_on_off),
273 AC97_REG_GP, 0x0000, 1, 12, 0, 0, CHECK_LOUDNESS
274 },
275 { AudioCoutputs, AudioNspatial, NULL,
276 AUDIO_MIXER_ENUM, WRAP(ac97_on_off),
277 AC97_REG_GP, 0x0000, 1, 13, 0, 1, CHECK_3D
278 },
279 { AudioCoutputs, AudioNspatial, "center",
280 AUDIO_MIXER_VALUE, WRAP(ac97_volume_mono),
281 AC97_REG_3D_CONTROL, 0x0000, 4, 8, 0, 1, CHECK_3D
282 },
283 { AudioCoutputs, AudioNspatial, "depth",
284 AUDIO_MIXER_VALUE, WRAP(ac97_volume_mono),
285 AC97_REG_3D_CONTROL, 0x0000, 4, 0, 0, 1, CHECK_3D
286 },
287 /* External Amp */
288 { AudioCoutputs, AudioNextamp, NULL,
289 AUDIO_MIXER_ENUM, WRAP(ac97_on_off),
290 AC97_REG_POWER, 0x0000, 1, 15, 0, 0
291 },
292 /* S/PDIF output enable */
293 { AudioCoutputs, AudioNspdif, NULL,
294 AUDIO_MIXER_ENUM, WRAP(ac97_on_off),
295 AC97_REG_EXT_AUDIO_CTRL, 0x0000, 1, 2, 0, 0, CHECK_SPDIF
296 }
297
298 /* Missing features: Simulated Stereo, POP, Loopback mode */
299 };
300
301 /*
302 * Check out http://www.intel.com/technology/computing/audio/index.htm
303 * for information on AC-97
304 */
305
306 struct ac97_softc {
307 /* ac97_codec_if must be at the first of ac97_softc. */
308 struct ac97_codec_if codec_if;
309 struct ac97_host_if *host_if;
310 #define MAX_SOURCES (2 * nitems(source_info))
311 struct ac97_source_info source_info[MAX_SOURCES];
312 int num_source_info;
313 enum ac97_host_flags host_flags;
314 unsigned int ac97_clock; /* usually 48000 */
315 #define AC97_STANDARD_CLOCK 48000U
316 u_int16_t caps; /* -> AC97_REG_RESET */
317 u_int16_t ext_id; /* -> AC97_REG_EXT_AUDIO_ID */
318 u_int16_t shadow_reg[128];
319 int lock_counter;
320 };
321
322 int ac97_mixer_get_port(struct ac97_codec_if *, mixer_ctrl_t *);
323 int ac97_mixer_set_port(struct ac97_codec_if *, mixer_ctrl_t *);
324 void ac97_lock(struct ac97_codec_if *);
325 void ac97_unlock(struct ac97_codec_if *);
326 int ac97_query_devinfo(struct ac97_codec_if *, mixer_devinfo_t *);
327 int ac97_get_portnum_by_name(struct ac97_codec_if *, char *, char *,
328 char *);
329 int ac97_set_rate(struct ac97_codec_if *codec_if, int target, u_long *rate);
330 void ac97_set_clock(struct ac97_codec_if *codec_if, unsigned int clock);
331 u_int16_t ac97_get_extcaps(struct ac97_codec_if *codec_if);
332 int ac97_add_port(struct ac97_softc *as, struct ac97_source_info *src);
333
334 void ac97_ad1885_init(struct ac97_softc *, int);
335 void ac97_ad1886_init(struct ac97_softc *, int);
336 void ac97_ad198x_init(struct ac97_softc *, int);
337 void ac97_alc650_init(struct ac97_softc *, int);
338 void ac97_cx20468_init(struct ac97_softc *, int);
339 void ac97_vt1616_init(struct ac97_softc *, int);
340
341 struct ac97_codec_if_vtbl ac97civ = {
342 ac97_mixer_get_port,
343 ac97_mixer_set_port,
344 ac97_query_devinfo,
345 ac97_get_portnum_by_name,
346 ac97_get_extcaps,
347 ac97_set_rate,
348 ac97_set_clock,
349 ac97_lock,
350 ac97_unlock
351 };
352
353 const struct ac97_codecid {
354 u_int8_t id;
355 u_int8_t mask;
356 u_int8_t rev;
357 u_int8_t shift; /* no use yet */
358 char * const name;
359 void (*init)(struct ac97_softc *, int);
360 } ac97_ad[] = {
361 { 0x03, 0xff, 0, 0, "AD1819" },
362 { 0x40, 0xff, 0, 0, "AD1881" },
363 { 0x48, 0xff, 0, 0, "AD1881A" },
364 { 0x60, 0xff, 0, 0, "AD1885", ac97_ad1885_init },
365 { 0x61, 0xff, 0, 0, "AD1886", ac97_ad1886_init },
366 { 0x63, 0xff, 0, 0, "AD1886A" },
367 { 0x68, 0xff, 0, 0, "AD1888", ac97_ad198x_init },
368 { 0x70, 0xff, 0, 0, "AD1980", ac97_ad198x_init },
369 { 0x72, 0xff, 0, 0, "AD1981A" },
370 { 0x74, 0xff, 0, 0, "AD1981B" },
371 { 0x75, 0xff, 0, 0, "AD1985", ac97_ad198x_init },
372 }, ac97_ak[] = {
373 { 0x00, 0xfe, 1, 0, "AK4540" },
374 { 0x01, 0xfe, 1, 0, "AK4540" },
375 { 0x02, 0xff, 0, 0, "AK4543" },
376 { 0x05, 0xff, 0, 0, "AK4544" },
377 { 0x06, 0xff, 0, 0, "AK4544A" },
378 { 0x07, 0xff, 0, 0, "AK4545" },
379 }, ac97_av[] = {
380 { 0x10, 0xff, 0, 0, "ALC200" },
381 { 0x20, 0xff, 0, 0, "ALC650" },
382 { 0x21, 0xff, 0, 0, "ALC650D" },
383 { 0x22, 0xff, 0, 0, "ALC650E" },
384 { 0x23, 0xff, 0, 0, "ALC650F" },
385 { 0x30, 0xff, 0, 0, "ALC101" },
386 { 0x40, 0xff, 0, 0, "ALC202" },
387 { 0x50, 0xff, 0, 0, "ALC250" },
388 { 0x52, 0xff, 0, 0, "ALC250A?" },
389 { 0x60, 0xf0, 0xf, 0, "ALC655", ac97_alc650_init },
390 { 0x70, 0xf0, 0xf, 0, "ALC203" },
391 { 0x80, 0xf0, 0xf, 0, "ALC658", ac97_alc650_init },
392 { 0x90, 0xf0, 0xf, 0, "ALC850" },
393 }, ac97_rl[] = {
394 { 0x00, 0xf0, 0xf, 0, "RL5306" },
395 { 0x10, 0xf0, 0xf, 0, "RL5382" },
396 { 0x20, 0xf0, 0xf, 0, "RL5383" },
397 }, ac97_cm[] = {
398 { 0x41, 0xff, 0, 0, "CMI9738" },
399 { 0x61, 0xff, 0, 0, "CMI9739" },
400 { 0x78, 0xff, 0, 0, "CMI9761A" },
401 { 0x82, 0xff, 0, 0, "CMI9761B" },
402 { 0x83, 0xff, 0, 0, "CMI9761A+" },
403 }, ac97_cr[] = {
404 { 0x84, 0xff, 0, 0, "EV1938" },
405 }, ac97_cs[] = {
406 { 0x00, 0xf8, 7, 0, "CS4297" },
407 { 0x10, 0xf8, 7, 0, "CS4297A" },
408 { 0x20, 0xf8, 7, 0, "CS4298" },
409 { 0x28, 0xf8, 7, 0, "CS4294" },
410 { 0x30, 0xf8, 7, 0, "CS4299" },
411 { 0x48, 0xf8, 7, 0, "CS4201" },
412 { 0x58, 0xf8, 7, 0, "CS4205" },
413 { 0x60, 0xf8, 7, 0, "CS4291" },
414 { 0x70, 0xf8, 7, 0, "CS4202" },
415 }, ac97_cx[] = {
416 { 0x21, 0xff, 0, 0, "HSD11246" },
417 { 0x28, 0xf8, 7, 0, "CX20468", ac97_cx20468_init },
418 { 0x30, 0xff, 0, 0, "CXT48", },
419 { 0x42, 0xff, 0, 0, "CXT66", },
420 }, ac97_dt[] = {
421 { 0x00, 0xff, 0, 0, "DT0398" },
422 }, ac97_em[] = {
423 { 0x23, 0xff, 0, 0, "EM28023" },
424 { 0x28, 0xff, 0, 0, "EM28028" },
425 }, ac97_es[] = {
426 { 0x08, 0xff, 0, 0, "ES1921" },
427 }, ac97_is[] = {
428 { 0x00, 0xff, 0, 0, "HMP9701" },
429 }, ac97_ic[] = {
430 { 0x01, 0xff, 0, 0, "ICE1230" },
431 { 0x11, 0xff, 0, 0, "ICE1232" },
432 { 0x14, 0xff, 0, 0, "ICE1232A" },
433 { 0x51, 0xff, 0, 0, "VIA VT1616" },
434 { 0x52, 0xff, 0, 0, "VIA VT1616i", ac97_vt1616_init },
435 }, ac97_it[] = {
436 { 0x20, 0xff, 0, 0, "ITE2226E" },
437 { 0x60, 0xff, 0, 0, "ITE2646E" },
438 }, ac97_ns[] = {
439 { 0x00, 0xff, 0, 0, "LM454[03568]" },
440 { 0x31, 0xff, 0, 0, "LM4549" },
441 { 0x40, 0xff, 0, 0, "LM4540" },
442 { 0x43, 0xff, 0, 0, "LM4543" },
443 { 0x46, 0xff, 0, 0, "LM4546A" },
444 { 0x48, 0xff, 0, 0, "LM4548A" },
445 { 0x49, 0xff, 0, 0, "LM4549A" },
446 { 0x50, 0xff, 0, 0, "LM4550" },
447 }, ac97_ps[] = {
448 { 0x01, 0xff, 0, 0, "UCB1510" },
449 { 0x04, 0xff, 0, 0, "UCB1400" },
450 }, ac97_sl[] = {
451 { 0x20, 0xe0, 0, 0, "Si3036/38" },
452 }, ac97_st[] = {
453 { 0x00, 0xff, 0, 0, "STAC9700" },
454 { 0x04, 0xff, 0, 0, "STAC970[135]" },
455 { 0x05, 0xff, 0, 0, "STAC9704" },
456 { 0x08, 0xff, 0, 0, "STAC9708/11" },
457 { 0x09, 0xff, 0, 0, "STAC9721/23" },
458 { 0x44, 0xff, 0, 0, "STAC9744/45" },
459 { 0x50, 0xff, 0, 0, "STAC9750/51" },
460 { 0x52, 0xff, 0, 0, "STAC9752/53" },
461 { 0x56, 0xff, 0, 0, "STAC9756/57" },
462 { 0x58, 0xff, 0, 0, "STAC9758/59" },
463 { 0x60, 0xff, 0, 0, "STAC9760/61" },
464 { 0x62, 0xff, 0, 0, "STAC9762/63" },
465 { 0x66, 0xff, 0, 0, "STAC9766/67" },
466 { 0x84, 0xff, 0, 0, "STAC9784/85" },
467 }, ac97_vi[] = {
468 { 0x61, 0xff, 0, 0, "VT1612A" },
469 { 0x70, 0xff, 0, 0, "VT1617" },
470 }, ac97_tt[] = {
471 { 0x02, 0xff, 0, 0, "TR28022" },
472 { 0x03, 0xff, 0, 0, "TR28023" },
473 { 0x06, 0xff, 0, 0, "TR28026" },
474 { 0x08, 0xff, 0, 0, "TR28028" },
475 { 0x23, 0xff, 0, 0, "TR28602" },
476 }, ac97_ti[] = {
477 { 0x20, 0xff, 0, 0, "TLC320AD9xC" },
478 }, ac97_wb[] = {
479 { 0x01, 0xff, 0, 0, "W83971D" },
480 }, ac97_wo[] = {
481 { 0x00, 0xff, 0, 0, "WM9701A" },
482 { 0x03, 0xff, 0, 0, "WM9704M/Q-0" }, /* & WM9703 */
483 { 0x04, 0xff, 0, 0, "WM9704M/Q-1" },
484 { 0x05, 0xff, 0, 0, "WM9705/10" },
485 { 0x09, 0xff, 0, 0, "WM9709" },
486 { 0x12, 0xff, 0, 0, "WM9711/12" },
487 }, ac97_ym[] = {
488 { 0x00, 0xff, 0, 0, "YMF743-S" },
489 { 0x02, 0xff, 0, 0, "YMF752-S" },
490 { 0x03, 0xff, 0, 0, "YMF753-S" },
491 };
492
493 #define cl(n) n, nitems(n)
494 const struct ac97_vendorid {
495 u_int32_t id;
496 char * const name;
497 const struct ac97_codecid * const codecs;
498 u_int8_t num;
499 } ac97_vendors[] = {
500 { 0x01408300, "Creative", cl(ac97_cr) },
501 { 0x41445300, "Analog Devices", cl(ac97_ad) },
502 { 0x414b4D00, "Asahi Kasei", cl(ac97_ak) },
503 { 0x414c4300, "Realtek", cl(ac97_rl) },
504 { 0x414c4700, "Avance Logic", cl(ac97_av) },
505 { 0x434d4900, "C-Media Electronics", cl(ac97_cm) },
506 { 0x43525900, "Cirrus Logic", cl(ac97_cs) },
507 { 0x43585400, "Conexant", cl(ac97_cx) },
508 { 0x44543000, "Diamond Technology", cl(ac97_dt) },
509 { 0x454d4300, "eMicro", cl(ac97_em) },
510 { 0x45838300, "ESS Technology", cl(ac97_es) },
511 { 0x48525300, "Intersil", cl(ac97_is) },
512 { 0x49434500, "ICEnsemble", cl(ac97_ic) },
513 { 0x49544500, "ITE, Inc.", cl(ac97_it) },
514 { 0x4e534300, "National Semiconductor", cl(ac97_ns) },
515 { 0x50534300, "Philips Semiconductor", cl(ac97_ps) },
516 { 0x53494c00, "Silicon Laboratory", cl(ac97_sl) },
517 { 0x54524100, "TriTech Microelectronics", cl(ac97_tt) },
518 { 0x54584e00, "Texas Instruments", cl(ac97_ti) },
519 { 0x56494100, "VIA Technologies", cl(ac97_vi) },
520 { 0x57454300, "Winbond", cl(ac97_wb) },
521 { 0x574d4c00, "Wolfson", cl(ac97_wo) },
522 { 0x594d4800, "Yamaha", cl(ac97_ym) },
523 { 0x83847600, "SigmaTel", cl(ac97_st) },
524 };
525 #undef cl
526
527 const char * const ac97enhancement[] = {
528 "No 3D Stereo",
529 "Analog Devices Phat Stereo",
530 "Creative",
531 "National Semi 3D",
532 "Yamaha Ymersion",
533 "BBE 3D",
534 "Crystal Semi 3D",
535 "Qsound QXpander",
536 "Spatializer 3D",
537 "SRS 3D",
538 "Platform Tech 3D",
539 "AKM 3D",
540 "Aureal",
541 "AZTECH 3D",
542 "Binaura 3D",
543 "ESS Technology",
544 "Harman International VMAx",
545 "Nvidea 3D",
546 "Philips Incredible Sound",
547 "Texas Instruments 3D",
548 "VLSI Technology 3D",
549 "TriTech 3D",
550 "Realtek 3D",
551 "Samsung 3D",
552 "Wolfson Microelectronics 3D",
553 "Delta Integration 3D",
554 "SigmaTel 3D",
555 "KS Waves 3D",
556 "Rockwell 3D",
557 "Unknown 3D",
558 "Unknown 3D",
559 "Unknown 3D"
560 };
561
562 const char * const ac97feature[] = {
563 "mic channel",
564 "reserved",
565 "tone",
566 "simulated stereo",
567 "headphone",
568 "bass boost",
569 "18 bit DAC",
570 "20 bit DAC",
571 "18 bit ADC",
572 "20 bit ADC"
573 };
574
575
576 int ac97_str_equal(const char *, const char *);
577 int ac97_check_capability(struct ac97_softc *, int);
578 void ac97_setup_source_info(struct ac97_softc *);
579 void ac97_setup_defaults(struct ac97_softc *);
580 int ac97_read(struct ac97_softc *, u_int8_t, u_int16_t *);
581 int ac97_write(struct ac97_softc *, u_int8_t, u_int16_t);
582
583
584 #ifdef AUDIO_DEBUG
585 #define DPRINTF(x) if (ac97debug) printf x
586 #define DPRINTFN(n,x) if (ac97debug>(n)) printf x
587 #ifdef AC97_DEBUG
588 int ac97debug = 1;
589 #else
590 int ac97debug = 0;
591 #endif
592 #else
593 #define DPRINTF(x)
594 #define DPRINTFN(n,x)
595 #endif
596
597 int
ac97_read(struct ac97_softc * as,u_int8_t reg,u_int16_t * val)598 ac97_read(struct ac97_softc *as, u_int8_t reg, u_int16_t *val)
599 {
600 int error;
601
602 if (((as->host_flags & AC97_HOST_DONT_READ) &&
603 (reg != AC97_REG_VENDOR_ID1 && reg != AC97_REG_VENDOR_ID2 &&
604 reg != AC97_REG_RESET)) ||
605 (as->host_flags & AC97_HOST_DONT_READANY)) {
606 *val = as->shadow_reg[reg >> 1];
607 return (0);
608 }
609
610 if ((error = as->host_if->read(as->host_if->arg, reg, val)))
611 *val = as->shadow_reg[reg >> 1];
612 return (error);
613 }
614
615 int
ac97_write(struct ac97_softc * as,u_int8_t reg,u_int16_t val)616 ac97_write(struct ac97_softc *as, u_int8_t reg, u_int16_t val)
617 {
618 as->shadow_reg[reg >> 1] = val;
619 return (as->host_if->write(as->host_if->arg, reg, val));
620 }
621
622 void
ac97_setup_defaults(struct ac97_softc * as)623 ac97_setup_defaults(struct ac97_softc *as)
624 {
625 int idx;
626
627 bzero(as->shadow_reg, sizeof(as->shadow_reg));
628
629 for (idx = 0; idx < nitems(source_info); idx++) {
630 const struct ac97_source_info *si = &source_info[idx];
631
632 ac97_write(as, si->reg, si->default_value);
633 }
634 }
635
636 int
ac97_str_equal(const char * a,const char * b)637 ac97_str_equal(const char *a, const char *b)
638 {
639 return ((a == b) || (a && b && (!strcmp(a, b))));
640 }
641
642 int
ac97_check_capability(struct ac97_softc * as,int check)643 ac97_check_capability(struct ac97_softc *as, int check)
644 {
645 switch (check) {
646 case CHECK_NONE:
647 return 1;
648 case CHECK_SURROUND:
649 return as->ext_id & AC97_EXT_AUDIO_SDAC;
650 case CHECK_CENTER:
651 return as->ext_id & AC97_EXT_AUDIO_CDAC;
652 case CHECK_LFE:
653 return as->ext_id & AC97_EXT_AUDIO_LDAC;
654 case CHECK_SPDIF:
655 return as->ext_id & AC97_EXT_AUDIO_SPDIF;
656 case CHECK_HEADPHONES:
657 return as->caps & AC97_CAPS_HEADPHONES;
658 case CHECK_TONE:
659 return as->caps & AC97_CAPS_TONECTRL;
660 case CHECK_MIC:
661 return as->caps & AC97_CAPS_MICIN;
662 case CHECK_LOUDNESS:
663 return as->caps & AC97_CAPS_LOUDNESS;
664 case CHECK_3D:
665 return AC97_CAPS_ENHANCEMENT(as->caps) != 0;
666 default:
667 printf("%s: internal error: feature=%d\n", __func__, check);
668 return 0;
669 }
670 }
671
672 void
ac97_setup_source_info(struct ac97_softc * as)673 ac97_setup_source_info(struct ac97_softc *as)
674 {
675 struct ac97_source_info *si, *si2;
676 int idx, ouridx;
677
678 for (idx = 0, ouridx = 0; idx < nitems(source_info); idx++) {
679 si = &as->source_info[ouridx];
680
681 if (!ac97_check_capability(as, source_info[idx].req_feature))
682 continue;
683
684 bcopy(&source_info[idx], si, sizeof(*si));
685
686 switch (si->type) {
687 case AUDIO_MIXER_CLASS:
688 si->mixer_class = ouridx;
689 ouridx++;
690 break;
691 case AUDIO_MIXER_VALUE:
692 /* Todo - Test to see if it works */
693 ouridx++;
694
695 /* Add an entry for mute, if necessary */
696 if (si->mute) {
697 si = &as->source_info[ouridx];
698 bcopy(&source_info[idx], si, sizeof(*si));
699 si->qualifier = AudioNmute;
700 si->type = AUDIO_MIXER_ENUM;
701 si->info = &ac97_on_off;
702 si->info_size = sizeof(ac97_on_off);
703 si->bits = 1;
704 si->ofs = 15;
705 si->mute = 0;
706 si->polarity = 0;
707 ouridx++;
708 }
709 break;
710 case AUDIO_MIXER_ENUM:
711 /* Todo - Test to see if it works */
712 ouridx++;
713 break;
714 default:
715 printf ("ac97: shouldn't get here\n");
716 break;
717 }
718 }
719
720 as->num_source_info = ouridx;
721
722 for (idx = 0; idx < as->num_source_info; idx++) {
723 int idx2, previdx;
724
725 si = &as->source_info[idx];
726
727 /* Find mixer class */
728 for (idx2 = 0; idx2 < as->num_source_info; idx2++) {
729 si2 = &as->source_info[idx2];
730
731 if (si2->type == AUDIO_MIXER_CLASS &&
732 ac97_str_equal(si->class, si2->class)) {
733 si->mixer_class = idx2;
734 }
735 }
736
737
738 /* Setup prev and next pointers */
739 if (si->prev != 0 || si->qualifier)
740 continue;
741
742 si->prev = AUDIO_MIXER_LAST;
743 previdx = idx;
744
745 for (idx2 = 0; idx2 < as->num_source_info; idx2++) {
746 if (idx2 == idx)
747 continue;
748
749 si2 = &as->source_info[idx2];
750
751 if (!si2->prev &&
752 ac97_str_equal(si->class, si2->class) &&
753 ac97_str_equal(si->device, si2->device)) {
754 as->source_info[previdx].next = idx2;
755 as->source_info[idx2].prev = previdx;
756
757 previdx = idx2;
758 }
759 }
760
761 as->source_info[previdx].next = AUDIO_MIXER_LAST;
762 }
763 }
764
765 int
ac97_attach(struct ac97_host_if * host_if)766 ac97_attach(struct ac97_host_if *host_if)
767 {
768 struct ac97_softc *as;
769 u_int16_t id1, id2, val;
770 u_int32_t id;
771 u_int16_t extstat, rate;
772 mixer_ctrl_t ctl;
773 int error, i;
774 void (*initfunc)(struct ac97_softc *, int);
775
776 initfunc = NULL;
777
778 if (!(as = malloc(sizeof(*as), M_DEVBUF, M_NOWAIT | M_ZERO)))
779 return (ENOMEM);
780
781 as->codec_if.as = as;
782 as->codec_if.vtbl = &ac97civ;
783 as->host_if = host_if;
784
785 if ((error = host_if->attach(host_if->arg, &as->codec_if))) {
786 free(as, M_DEVBUF, sizeof(*as));
787 return (error);
788 }
789
790 host_if->reset(host_if->arg);
791 DELAY(1000);
792
793 host_if->write(host_if->arg, AC97_REG_POWER, 0);
794 host_if->write(host_if->arg, AC97_REG_RESET, 0);
795 DELAY(10000);
796
797 if (host_if->flags)
798 as->host_flags = host_if->flags(host_if->arg);
799
800 ac97_setup_defaults(as);
801 ac97_read(as, AC97_REG_VENDOR_ID1, &id1);
802 ac97_read(as, AC97_REG_VENDOR_ID2, &id2);
803 ac97_read(as, AC97_REG_RESET, &as->caps);
804
805 id = (id1 << 16) | id2;
806 if (id) {
807 register const struct ac97_vendorid *vendor;
808 register const struct ac97_codecid *codec;
809
810 printf("ac97: codec id 0x%08x", id);
811 for (vendor = &ac97_vendors[sizeof(ac97_vendors) /
812 sizeof(ac97_vendors[0]) - 1];
813 vendor >= ac97_vendors; vendor--) {
814 if (vendor->id == (id & AC97_VENDOR_ID_MASK)) {
815 printf(" (%s", vendor->name);
816 for (codec = &vendor->codecs[vendor->num-1];
817 codec >= vendor->codecs; codec--) {
818 if (codec->id == (id & codec->mask))
819 break;
820 }
821 if (codec >= vendor->codecs && codec->mask) {
822 printf(" %s", codec->name);
823 initfunc = codec->init;
824 } else
825 printf(" <%02x>", id & 0xff);
826 if (codec >= vendor->codecs && codec->rev)
827 printf(" rev %d", id & codec->rev);
828 printf(")");
829 break;
830 }
831 }
832 printf("\n");
833 } else
834 printf("ac97: codec id not read\n");
835
836 if (as->caps) {
837 printf("ac97: codec features ");
838 for (i = 0; i < 10; i++) {
839 if (as->caps & (1 << i))
840 printf("%s, ", ac97feature[i]);
841 }
842 printf("%s\n",
843 ac97enhancement[AC97_CAPS_ENHANCEMENT(as->caps)]);
844 }
845
846
847 as->ac97_clock = AC97_STANDARD_CLOCK;
848 ac97_read(as, AC97_REG_EXT_AUDIO_ID, &as->ext_id);
849 if (as->ext_id & (AC97_EXT_AUDIO_VRA | AC97_EXT_AUDIO_DRA
850 | AC97_EXT_AUDIO_SPDIF | AC97_EXT_AUDIO_VRM
851 | AC97_EXT_AUDIO_CDAC | AC97_EXT_AUDIO_SDAC
852 | AC97_EXT_AUDIO_LDAC)) {
853
854 ac97_read(as, AC97_REG_EXT_AUDIO_CTRL, &extstat);
855 extstat &= ~AC97_EXT_AUDIO_DRA;
856
857 if (as->ext_id & AC97_EXT_AUDIO_VRM)
858 extstat |= AC97_EXT_AUDIO_VRM;
859
860 if (as->ext_id & AC97_EXT_AUDIO_LDAC)
861 extstat |= AC97_EXT_AUDIO_LDAC;
862 if (as->ext_id & AC97_EXT_AUDIO_SDAC)
863 extstat |= AC97_EXT_AUDIO_SDAC;
864 if (as->ext_id & AC97_EXT_AUDIO_CDAC)
865 extstat |= AC97_EXT_AUDIO_CDAC;
866 if (as->ext_id & AC97_EXT_AUDIO_SPDIF) {
867 /* XXX S/PDIF gets same data as DAC?
868 * maybe this should be settable?
869 * default is SPSAAB (10/11) on AD1980 and ALC codecs.
870 */
871 extstat &= ~AC97_EXT_AUDIO_SPSA_MASK;
872 extstat |= AC97_EXT_AUDIO_SPSA34;
873 ac97_read(as, AC97_REG_SPDIF_CTRL, &val);
874 val = (val & ~AC97_SPDIF_SPSR_MASK) |
875 AC97_SPDIF_SPSR_48K;
876 ac97_write(as, AC97_REG_SPDIF_CTRL, val);
877 }
878 if (as->ext_id & AC97_EXT_AUDIO_VRA)
879 extstat |= AC97_EXT_AUDIO_VRA;
880 ac97_write(as, AC97_REG_EXT_AUDIO_CTRL, extstat);
881 if (as->ext_id & AC97_EXT_AUDIO_VRA) {
882 /* VRA should be enabled. */
883 /* so it claims to do variable rate, let's make sure */
884 ac97_write(as, AC97_REG_PCM_FRONT_DAC_RATE, 44100);
885 ac97_read(as, AC97_REG_PCM_FRONT_DAC_RATE, &rate);
886 if (rate != 44100) {
887 /* We can't believe ext_id */
888 as->ext_id = 0;
889 }
890 /* restore the default value */
891 ac97_write(as, AC97_REG_PCM_FRONT_DAC_RATE,
892 AC97_SINGLE_RATE);
893 }
894 }
895
896 ac97_setup_source_info(as);
897
898 DELAY(900 * 1000);
899
900 /* use initfunc for specific device */
901 as->codec_if.initfunc = initfunc;
902 if (initfunc != NULL)
903 initfunc(as, 0);
904
905 /* Just enable the DAC and master volumes by default */
906 bzero(&ctl, sizeof(ctl));
907
908 ctl.type = AUDIO_MIXER_ENUM;
909 ctl.un.ord = 0; /* off */
910 ctl.dev = ac97_get_portnum_by_name(&as->codec_if, AudioCoutputs,
911 AudioNmaster, AudioNmute);
912 ac97_mixer_set_port(&as->codec_if, &ctl);
913
914 ctl.dev = ac97_get_portnum_by_name(&as->codec_if, AudioCinputs,
915 AudioNdac, AudioNmute);
916 ac97_mixer_set_port(&as->codec_if, &ctl);
917
918 ctl.dev = ac97_get_portnum_by_name(&as->codec_if, AudioCrecord,
919 AudioNvolume, AudioNmute);
920 ac97_mixer_set_port(&as->codec_if, &ctl);
921
922 ctl.type = AUDIO_MIXER_ENUM;
923 ctl.un.ord = 0;
924 ctl.dev = ac97_get_portnum_by_name(&as->codec_if, AudioCrecord,
925 AudioNsource, NULL);
926 ac97_mixer_set_port(&as->codec_if, &ctl);
927
928 return (0);
929 }
930
931 int
ac97_resume(struct ac97_host_if * host_if,struct ac97_codec_if * codec_if)932 ac97_resume(struct ac97_host_if *host_if, struct ac97_codec_if *codec_if)
933 {
934 struct ac97_softc *as = codec_if->as;
935 u_int16_t val, extstat;
936
937 host_if->reset(host_if->arg);
938 DELAY(1000);
939
940 host_if->write(host_if->arg, AC97_REG_POWER, 0);
941 host_if->write(host_if->arg, AC97_REG_RESET, 0);
942 DELAY(10000);
943
944 if (as->ext_id & (AC97_EXT_AUDIO_VRA | AC97_EXT_AUDIO_DRA
945 | AC97_EXT_AUDIO_SPDIF | AC97_EXT_AUDIO_VRM
946 | AC97_EXT_AUDIO_CDAC | AC97_EXT_AUDIO_SDAC
947 | AC97_EXT_AUDIO_LDAC)) {
948
949 ac97_read(as, AC97_REG_EXT_AUDIO_CTRL, &extstat);
950 extstat &= ~AC97_EXT_AUDIO_DRA;
951
952 if (as->ext_id & AC97_EXT_AUDIO_VRM)
953 extstat |= AC97_EXT_AUDIO_VRM;
954
955 if (as->ext_id & AC97_EXT_AUDIO_LDAC)
956 extstat |= AC97_EXT_AUDIO_LDAC;
957 if (as->ext_id & AC97_EXT_AUDIO_SDAC)
958 extstat |= AC97_EXT_AUDIO_SDAC;
959 if (as->ext_id & AC97_EXT_AUDIO_CDAC)
960 extstat |= AC97_EXT_AUDIO_CDAC;
961
962 if (as->ext_id & AC97_EXT_AUDIO_SPDIF) {
963 extstat &= ~AC97_EXT_AUDIO_SPSA_MASK;
964 extstat |= AC97_EXT_AUDIO_SPSA34;
965 ac97_read(as, AC97_REG_SPDIF_CTRL, &val);
966 val = (val & ~AC97_SPDIF_SPSR_MASK) |
967 AC97_SPDIF_SPSR_48K;
968 ac97_write(as, AC97_REG_SPDIF_CTRL, val);
969 }
970 if (as->ext_id & AC97_EXT_AUDIO_VRA)
971 extstat |= AC97_EXT_AUDIO_VRA;
972 ac97_write(as, AC97_REG_EXT_AUDIO_CTRL, extstat);
973 }
974
975 /* use initfunc for specific device */
976 if (as->codec_if.initfunc != NULL)
977 as->codec_if.initfunc(as, 1);
978
979 return (0);
980 }
981
982 void
ac97_lock(struct ac97_codec_if * codec_if)983 ac97_lock(struct ac97_codec_if *codec_if)
984 {
985 struct ac97_softc *as = (struct ac97_softc *)codec_if;
986 as->lock_counter++;
987 }
988
989 void
ac97_unlock(struct ac97_codec_if * codec_if)990 ac97_unlock(struct ac97_codec_if *codec_if)
991 {
992 struct ac97_softc *as = (struct ac97_softc *)codec_if;
993 as->lock_counter--;
994 }
995
996 int
ac97_query_devinfo(struct ac97_codec_if * codec_if,mixer_devinfo_t * dip)997 ac97_query_devinfo(struct ac97_codec_if *codec_if, mixer_devinfo_t *dip)
998 {
999 struct ac97_softc *as = (struct ac97_softc *)codec_if;
1000
1001 if (dip->index < as->num_source_info && dip->index >= 0) {
1002 struct ac97_source_info *si = &as->source_info[dip->index];
1003 const char *name;
1004
1005 dip->type = si->type;
1006 dip->mixer_class = si->mixer_class;
1007 dip->prev = si->prev;
1008 dip->next = si->next;
1009
1010 if (si->qualifier)
1011 name = si->qualifier;
1012 else if (si->device)
1013 name = si->device;
1014 else if (si->class)
1015 name = si->class;
1016 else
1017 name = NULL;
1018
1019 if (name)
1020 strlcpy(dip->label.name, name, sizeof dip->label.name);
1021
1022 bcopy(si->info, &dip->un, si->info_size);
1023
1024 /* Set the delta for volume sources */
1025 if (dip->type == AUDIO_MIXER_VALUE)
1026 dip->un.v.delta = 1 << (8 - si->bits);
1027
1028 return (0);
1029 }
1030
1031 return (ENXIO);
1032 }
1033
1034 int
ac97_mixer_set_port(struct ac97_codec_if * codec_if,mixer_ctrl_t * cp)1035 ac97_mixer_set_port(struct ac97_codec_if *codec_if, mixer_ctrl_t *cp)
1036 {
1037 struct ac97_softc *as = (struct ac97_softc *)codec_if;
1038 struct ac97_source_info *si;
1039 u_int16_t mask;
1040 u_int16_t val, newval;
1041 int error, spdif;
1042
1043 if (cp->dev < 0 || cp->dev >= as->num_source_info)
1044 return (EINVAL);
1045
1046 si = &as->source_info[cp->dev];
1047
1048 if (cp->type == AUDIO_MIXER_CLASS || cp->type != si->type)
1049 return (EINVAL);
1050
1051 spdif = si->req_feature == CHECK_SPDIF &&
1052 si->reg == AC97_REG_EXT_AUDIO_CTRL;
1053 if (spdif && as->lock_counter >= 0)
1054 return EBUSY;
1055
1056 ac97_read(as, si->reg, &val);
1057
1058 DPRINTFN(5, ("read(%x) = %x\n", si->reg, val));
1059
1060 mask = (1 << si->bits) - 1;
1061
1062 switch (cp->type) {
1063 case AUDIO_MIXER_ENUM:
1064 if (cp->un.ord > mask || cp->un.ord < 0)
1065 return (EINVAL);
1066
1067 newval = (cp->un.ord << si->ofs);
1068 if (si->reg == AC97_REG_RECORD_SELECT) {
1069 newval |= (newval << (8 + si->ofs));
1070 mask |= (mask << 8);
1071 mask = mask << si->ofs;
1072 } else if (si->reg == AC97_REG_SURR_MASTER) {
1073 newval = cp->un.ord ? 0x8080 : 0x0000;
1074 mask = 0x8080;
1075 } else
1076 mask = mask << si->ofs;
1077
1078 if (si->mute) {
1079 newval |= newval << 8;
1080 mask |= mask << 8;
1081 }
1082
1083 break;
1084 case AUDIO_MIXER_VALUE:
1085 {
1086 const struct audio_mixer_value *value = si->info;
1087 u_int16_t l, r;
1088
1089 if (cp->un.value.num_channels <= 0 ||
1090 cp->un.value.num_channels > value->num_channels)
1091 return (EINVAL);
1092
1093 if (cp->un.value.num_channels == 1) {
1094 l = r = cp->un.value.level[AUDIO_MIXER_LEVEL_MONO];
1095 } else {
1096 if (!(as->host_flags & AC97_HOST_SWAPPED_CHANNELS)) {
1097 l = cp->un.value.level[AUDIO_MIXER_LEVEL_LEFT];
1098 r = cp->un.value.level[AUDIO_MIXER_LEVEL_RIGHT];
1099 } else {
1100 r = cp->un.value.level[AUDIO_MIXER_LEVEL_LEFT];
1101 l = cp->un.value.level[AUDIO_MIXER_LEVEL_RIGHT];
1102 }
1103 }
1104
1105 if (!si->polarity) {
1106 l = 255 - l;
1107 r = 255 - r;
1108 }
1109
1110 l >>= 8 - si->bits;
1111 r >>= 8 - si->bits;
1112
1113 newval = ((l & mask) << si->ofs);
1114 if (value->num_channels == 2) {
1115 newval |= ((r & mask) << (si->ofs + 8));
1116 mask |= (mask << 8);
1117 }
1118 mask = mask << si->ofs;
1119 break;
1120 }
1121 default:
1122 return (EINVAL);
1123 }
1124
1125 error = ac97_write(as, si->reg, (val & ~mask) | newval);
1126 if (error)
1127 return (error);
1128
1129 if (spdif && as->host_if->spdif_event != NULL)
1130 as->host_if->spdif_event(as->host_if->arg, cp->un.ord);
1131
1132 return (0);
1133 }
1134
1135
1136 int
ac97_set_rate(struct ac97_codec_if * codec_if,int target,u_long * rate)1137 ac97_set_rate(struct ac97_codec_if *codec_if, int target, u_long *rate)
1138 {
1139 struct ac97_softc *as;
1140 u_long value;
1141 u_int16_t ext_stat;
1142 u_int16_t actual;
1143 u_int16_t power;
1144 u_int16_t power_bit;
1145
1146 as = (struct ac97_softc *)codec_if;
1147
1148 if ((target == AC97_REG_PCM_SURR_DAC_RATE) &&
1149 !(as->ext_id & AC97_EXT_AUDIO_SDAC))
1150 return 0;
1151 if ((target == AC97_REG_PCM_LFE_DAC_RATE) &&
1152 !(as->ext_id & AC97_EXT_AUDIO_LDAC))
1153 return 0;
1154 if (target == AC97_REG_PCM_MIC_ADC_RATE) {
1155 if (!(as->ext_id & AC97_EXT_AUDIO_VRM)) {
1156 *rate = AC97_SINGLE_RATE;
1157 return 0;
1158 }
1159 } else {
1160 if (!(as->ext_id & AC97_EXT_AUDIO_VRA)) {
1161 *rate = AC97_SINGLE_RATE;
1162 return 0;
1163 }
1164 }
1165 if (as->ac97_clock == 0)
1166 as->ac97_clock = AC97_STANDARD_CLOCK;
1167 value = *rate * AC97_STANDARD_CLOCK / as->ac97_clock;
1168 ext_stat = 0;
1169 /*
1170 * PCM_FRONT_DAC_RATE/PCM_SURR_DAC_RATE/PCM_LFE_DAC_RATE
1171 * Check VRA, DRA
1172 * PCM_LR_ADC_RATE
1173 * Check VRA
1174 * PCM_MIC_ADC_RATE
1175 * Check VRM
1176 */
1177 switch (target) {
1178 case AC97_REG_PCM_FRONT_DAC_RATE:
1179 case AC97_REG_PCM_SURR_DAC_RATE:
1180 case AC97_REG_PCM_LFE_DAC_RATE:
1181 power_bit = AC97_POWER_OUT;
1182 if (as->ext_id & AC97_EXT_AUDIO_DRA) {
1183 ac97_read(as, AC97_REG_EXT_AUDIO_CTRL, &ext_stat);
1184 if (value > 0x1ffff) {
1185 return EINVAL;
1186 } else if (value > 0xffff) {
1187 /* Enable DRA */
1188 ext_stat |= AC97_EXT_AUDIO_DRA;
1189 ac97_write(as, AC97_REG_EXT_AUDIO_CTRL, ext_stat);
1190 value /= 2;
1191 } else {
1192 /* Disable DRA */
1193 ext_stat &= ~AC97_EXT_AUDIO_DRA;
1194 ac97_write(as, AC97_REG_EXT_AUDIO_CTRL, ext_stat);
1195 }
1196 } else {
1197 if (value > 0xffff)
1198 return EINVAL;
1199 }
1200 break;
1201 case AC97_REG_PCM_LR_ADC_RATE:
1202 power_bit = AC97_POWER_IN;
1203 if (value > 0xffff)
1204 return EINVAL;
1205 break;
1206 case AC97_REG_PCM_MIC_ADC_RATE:
1207 power_bit = AC97_POWER_IN;
1208 if (value > 0xffff)
1209 return EINVAL;
1210 break;
1211 default:
1212 printf("%s: Unknown register: 0x%x\n", __func__, target);
1213 return EINVAL;
1214 }
1215
1216 ac97_read(as, AC97_REG_POWER, &power);
1217 ac97_write(as, AC97_REG_POWER, power | power_bit);
1218
1219 ac97_write(as, target, (u_int16_t)value);
1220 ac97_read(as, target, &actual);
1221 actual = (u_int32_t)actual * as->ac97_clock / AC97_STANDARD_CLOCK;
1222
1223 ac97_write(as, AC97_REG_POWER, power);
1224 if (ext_stat & AC97_EXT_AUDIO_DRA) {
1225 *rate = actual * 2;
1226 } else {
1227 *rate = actual;
1228 }
1229 return 0;
1230 }
1231
1232 void
ac97_set_clock(struct ac97_codec_if * codec_if,unsigned int clock)1233 ac97_set_clock(struct ac97_codec_if *codec_if, unsigned int clock)
1234 {
1235 struct ac97_softc *as;
1236
1237 as = (struct ac97_softc *)codec_if;
1238 as->ac97_clock = clock;
1239 }
1240
1241 u_int16_t
ac97_get_extcaps(struct ac97_codec_if * codec_if)1242 ac97_get_extcaps(struct ac97_codec_if *codec_if)
1243 {
1244 struct ac97_softc *as;
1245
1246 as = (struct ac97_softc *)codec_if;
1247 return as->ext_id;
1248 }
1249
1250 int
ac97_add_port(struct ac97_softc * as,struct ac97_source_info * src)1251 ac97_add_port(struct ac97_softc *as, struct ac97_source_info *src)
1252 {
1253 struct ac97_source_info *si;
1254 int ouridx, idx;
1255
1256 if (as->num_source_info >= MAX_SOURCES) {
1257 printf("%s: internal error: increase MAX_SOURCES in %s\n",
1258 __func__, __FILE__);
1259 return -1;
1260 }
1261 if (!ac97_check_capability(as, src->req_feature))
1262 return -1;
1263 ouridx = as->num_source_info;
1264 si = &as->source_info[ouridx];
1265 memcpy(si, src, sizeof(*si));
1266
1267 switch (si->type) {
1268 case AUDIO_MIXER_CLASS:
1269 case AUDIO_MIXER_VALUE:
1270 printf("%s: adding class/value is not supported yet.\n",
1271 __func__);
1272 return -1;
1273 case AUDIO_MIXER_ENUM:
1274 break;
1275 default:
1276 printf("%s: unknown type: %d\n", __func__, si->type);
1277 return -1;
1278 }
1279 as->num_source_info++;
1280
1281 si->mixer_class = ac97_get_portnum_by_name(&as->codec_if, si->class,
1282 NULL, NULL);
1283 /* Find the root of the device */
1284 idx = ac97_get_portnum_by_name(&as->codec_if, si->class,
1285 si->device, NULL);
1286 /* Find the last item */
1287 while (as->source_info[idx].next != AUDIO_MIXER_LAST)
1288 idx = as->source_info[idx].next;
1289 /* Append */
1290 as->source_info[idx].next = ouridx;
1291 si->prev = idx;
1292 si->next = AUDIO_MIXER_LAST;
1293
1294 return 0;
1295 }
1296
1297 int
ac97_get_portnum_by_name(struct ac97_codec_if * codec_if,char * class,char * device,char * qualifier)1298 ac97_get_portnum_by_name(struct ac97_codec_if *codec_if, char *class,
1299 char *device, char *qualifier)
1300 {
1301 struct ac97_softc *as = (struct ac97_softc *)codec_if;
1302 int idx;
1303
1304 for (idx = 0; idx < as->num_source_info; idx++) {
1305 struct ac97_source_info *si = &as->source_info[idx];
1306 if (ac97_str_equal(class, si->class) &&
1307 ac97_str_equal(device, si->device) &&
1308 ac97_str_equal(qualifier, si->qualifier))
1309 return (idx);
1310 }
1311
1312 return (-1);
1313 }
1314
1315 int
ac97_mixer_get_port(struct ac97_codec_if * codec_if,mixer_ctrl_t * cp)1316 ac97_mixer_get_port(struct ac97_codec_if *codec_if, mixer_ctrl_t *cp)
1317 {
1318 struct ac97_softc *as = (struct ac97_softc *)codec_if;
1319 struct ac97_source_info *si;
1320 u_int16_t mask;
1321 u_int16_t val;
1322
1323 if (cp->dev < 0 || cp->dev >= as->num_source_info)
1324 return (EINVAL);
1325
1326 si = &as->source_info[cp->dev];
1327
1328 if (cp->type != si->type)
1329 return (EINVAL);
1330
1331 ac97_read(as, si->reg, &val);
1332
1333 DPRINTFN(5, ("read(%x) = %x\n", si->reg, val));
1334
1335 mask = (1 << si->bits) - 1;
1336
1337 switch (cp->type) {
1338 case AUDIO_MIXER_ENUM:
1339 cp->un.ord = (val >> si->ofs) & mask;
1340 DPRINTFN(4, ("AUDIO_MIXER_ENUM: %x %d %x %d\n", val, si->ofs,
1341 mask, cp->un.ord));
1342 break;
1343 case AUDIO_MIXER_VALUE:
1344 {
1345 const struct audio_mixer_value *value = si->info;
1346 u_int16_t l, r;
1347
1348 if ((cp->un.value.num_channels <= 0) ||
1349 (cp->un.value.num_channels > value->num_channels))
1350 return (EINVAL);
1351
1352 if (value->num_channels == 1)
1353 l = r = (val >> si->ofs) & mask;
1354 else {
1355 if (!(as->host_flags & AC97_HOST_SWAPPED_CHANNELS)) {
1356 l = (val >> si->ofs) & mask;
1357 r = (val >> (si->ofs + 8)) & mask;
1358 } else {
1359 r = (val >> si->ofs) & mask;
1360 l = (val >> (si->ofs + 8)) & mask;
1361 }
1362 }
1363
1364 l <<= 8 - si->bits;
1365 r <<= 8 - si->bits;
1366 if (!si->polarity) {
1367 l = 255 - l;
1368 r = 255 - r;
1369 }
1370
1371 /*
1372 * The EAP driver averages l and r for stereo
1373 * channels that are requested in MONO mode. Does this
1374 * make sense?
1375 */
1376 if (cp->un.value.num_channels == 1) {
1377 cp->un.value.level[AUDIO_MIXER_LEVEL_MONO] = l;
1378 } else if (cp->un.value.num_channels == 2) {
1379 cp->un.value.level[AUDIO_MIXER_LEVEL_LEFT] = l;
1380 cp->un.value.level[AUDIO_MIXER_LEVEL_RIGHT] = r;
1381 }
1382
1383 break;
1384 }
1385 default:
1386 return (EINVAL);
1387 }
1388
1389 return (0);
1390 }
1391
1392
1393 /*
1394 * Codec-dependent initialization
1395 */
1396
1397 void
ac97_ad1885_init(struct ac97_softc * as,int resuming)1398 ac97_ad1885_init(struct ac97_softc *as, int resuming)
1399 {
1400 int i;
1401
1402 if (resuming)
1403 return;
1404
1405 for (i = 0; i < as->num_source_info; i++) {
1406 if (as->source_info[i].reg == AC97_REG_HEADPHONE_VOLUME)
1407 as->source_info[i].reg = AC97_REG_MASTER_VOLUME;
1408 else if (as->source_info[i].reg == AC97_REG_MASTER_VOLUME)
1409 as->source_info[i].reg = AC97_REG_HEADPHONE_VOLUME;
1410 }
1411 }
1412
1413 #define AC97_AD1886_JACK_SENSE 0x72
1414
1415 void
ac97_ad1886_init(struct ac97_softc * as,int resuming)1416 ac97_ad1886_init(struct ac97_softc *as, int resuming)
1417 {
1418 ac97_write(as, AC97_AD1886_JACK_SENSE, 0x0010);
1419 }
1420
1421 void
ac97_ad198x_init(struct ac97_softc * as,int resuming)1422 ac97_ad198x_init(struct ac97_softc *as, int resuming)
1423 {
1424 int i;
1425 u_int16_t misc;
1426
1427 ac97_read(as, AC97_AD_REG_MISC, &misc);
1428 ac97_write(as, AC97_AD_REG_MISC,
1429 misc|AC97_AD_MISC_HPSEL|AC97_AD_MISC_LOSEL);
1430
1431 if (resuming)
1432 return;
1433
1434 for (i = 0; i < as->num_source_info; i++) {
1435 if (as->source_info[i].reg == AC97_REG_SURR_MASTER)
1436 as->source_info[i].reg = AC97_REG_MASTER_VOLUME;
1437 else if (as->source_info[i].reg == AC97_REG_MASTER_VOLUME)
1438 as->source_info[i].reg = AC97_REG_SURR_MASTER;
1439 }
1440 }
1441
1442 void
ac97_alc650_init(struct ac97_softc * as,int resuming)1443 ac97_alc650_init(struct ac97_softc *as, int resuming)
1444 {
1445 u_int16_t misc;
1446
1447 ac97_read(as, AC97_ALC650_REG_MISC, &misc);
1448 if (as->host_flags & AC97_HOST_ALC650_PIN47_IS_EAPD)
1449 misc &= ~AC97_ALC650_MISC_PIN47;
1450 misc &= ~AC97_ALC650_MISC_VREFDIS;
1451 ac97_write(as, AC97_ALC650_REG_MISC, misc);
1452
1453 if (resuming)
1454 return;
1455
1456 struct ac97_source_info sources[3] = {
1457 { AudioCoutputs, AudioNsurround, "lineinjack",
1458 AUDIO_MIXER_ENUM, WRAP(ac97_on_off),
1459 AC97_ALC650_REG_MULTI_CHANNEL_CONTROL,
1460 0x0000, 1, 9, 0, 0, CHECK_SURROUND },
1461 { AudioCoutputs, AudioNcenter, "micjack",
1462 AUDIO_MIXER_ENUM, WRAP(ac97_on_off),
1463 AC97_ALC650_REG_MULTI_CHANNEL_CONTROL,
1464 0x0000, 1, 10, 0, 0, CHECK_CENTER },
1465 { AudioCoutputs, AudioNlfe, "micjack",
1466 AUDIO_MIXER_ENUM, WRAP(ac97_on_off),
1467 AC97_ALC650_REG_MULTI_CHANNEL_CONTROL,
1468 0x0000, 1, 10, 0, 0, CHECK_LFE }};
1469
1470 ac97_add_port(as, &sources[0]);
1471 ac97_add_port(as, &sources[1]);
1472 ac97_add_port(as, &sources[2]);
1473 }
1474
1475 void
ac97_cx20468_init(struct ac97_softc * as,int resuming)1476 ac97_cx20468_init(struct ac97_softc *as, int resuming)
1477 {
1478 u_int16_t misc;
1479
1480 ac97_read(as, AC97_CX_REG_MISC, &misc);
1481 ac97_write(as, AC97_CX_REG_MISC, misc &
1482 ~(AC97_CX_SPDIFEN | AC97_CX_COPYRIGHT | AC97_CX_MASK));
1483 }
1484
1485 void
ac97_vt1616_init(struct ac97_softc * as,int resuming)1486 ac97_vt1616_init(struct ac97_softc *as, int resuming)
1487 {
1488 u_int16_t reg;
1489
1490 if (as->host_flags & AC97_HOST_VT1616_DYNEX) {
1491 ac97_read(as, AC97_VT_REG_TEST, ®);
1492
1493 /* disable 'hp' mixer controls controlling the surround pins */
1494 reg &= ~(AC97_VT_LVL);
1495
1496 /* disable downmixing */
1497 reg &= ~(AC97_VT_LCTF | AC97_VT_STF);
1498
1499 /* enable DC offset removal */
1500 reg |= AC97_VT_BPDC;
1501
1502 ac97_write(as, AC97_VT_REG_TEST, reg);
1503 }
1504 }
1505