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