FreeBSD/Linux Kernel Cross Reference
sys/dev/sound/pcm/ac97.c
1 /*-
2 * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
3 *
4 * Copyright (c) 1999 Cameron Grant <cg@freebsd.org>
5 * All rights reserved.
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
17 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
20 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
22 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
23 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
24 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
25 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26 * SUCH DAMAGE.
27 */
28
29 #ifdef HAVE_KERNEL_OPTION_HEADERS
30 #include "opt_snd.h"
31 #endif
32
33 #include <dev/sound/pcm/sound.h>
34 #include <dev/sound/pcm/ac97.h>
35 #include <dev/sound/pcm/ac97_patch.h>
36
37 #include <dev/pci/pcivar.h>
38
39 #include "mixer_if.h"
40
41 SND_DECLARE_FILE("$FreeBSD: releng/12.0/sys/dev/sound/pcm/ac97.c 326255 2017-11-27 14:52:40Z pfg $");
42
43 static MALLOC_DEFINE(M_AC97, "ac97", "ac97 codec");
44
45 struct ac97mixtable_entry {
46 int reg; /* register index */
47 /* reg < 0 if inverted polarity */
48 unsigned bits:4; /* width of control field */
49 unsigned ofs:4; /* offset (only if stereo=0) */
50 unsigned stereo:1; /* set for stereo controls */
51 unsigned mute:1; /* bit15 is MUTE */
52 unsigned recidx:4; /* index in rec mux */
53 unsigned mask:1; /* use only masked bits */
54 unsigned enable:1; /* entry is enabled */
55 };
56
57 #define AC97_MIXER_SIZE SOUND_MIXER_NRDEVICES
58
59 struct ac97_info {
60 kobj_t methods;
61 device_t dev;
62 void *devinfo;
63 u_int32_t id;
64 u_int32_t subvendor;
65 unsigned count, caps, se, extcaps, extid, extstat, noext:1;
66 u_int32_t flags;
67 struct ac97mixtable_entry mix[AC97_MIXER_SIZE];
68 char name[16];
69 struct mtx *lock;
70 };
71
72 struct ac97_vendorid {
73 u_int32_t id;
74 const char *name;
75 };
76
77 struct ac97_codecid {
78 u_int32_t id;
79 u_int8_t stepmask;
80 u_int8_t noext:1;
81 char *name;
82 ac97_patch patch;
83 };
84
85 static const struct ac97mixtable_entry ac97mixtable_default[AC97_MIXER_SIZE] = {
86 /* [offset] reg bits of st mu re mk en */
87 [SOUND_MIXER_VOLUME] = { AC97_MIX_MASTER, 5, 0, 1, 1, 6, 0, 1 },
88 [SOUND_MIXER_OGAIN] = { AC97_MIX_AUXOUT, 5, 0, 1, 1, 0, 0, 0 },
89 [SOUND_MIXER_PHONEOUT] = { AC97_MIX_MONO, 5, 0, 0, 1, 7, 0, 0 },
90 [SOUND_MIXER_BASS] = { AC97_MIX_TONE, 4, 8, 0, 0, 0, 1, 0 },
91 [SOUND_MIXER_TREBLE] = { AC97_MIX_TONE, 4, 0, 0, 0, 0, 1, 0 },
92 [SOUND_MIXER_PCM] = { AC97_MIX_PCM, 5, 0, 1, 1, 0, 0, 1 },
93 [SOUND_MIXER_SPEAKER] = { AC97_MIX_BEEP, 4, 1, 0, 1, 0, 0, 0 },
94 [SOUND_MIXER_LINE] = { AC97_MIX_LINE, 5, 0, 1, 1, 5, 0, 1 },
95 [SOUND_MIXER_PHONEIN] = { AC97_MIX_PHONE, 5, 0, 0, 1, 8, 0, 0 },
96 [SOUND_MIXER_MIC] = { AC97_MIX_MIC, 5, 0, 0, 1, 1, 1, 1 },
97 /* use igain for the mic 20dB boost */
98 [SOUND_MIXER_IGAIN] = { -AC97_MIX_MIC, 1, 6, 0, 0, 0, 1, 1 },
99 [SOUND_MIXER_CD] = { AC97_MIX_CD, 5, 0, 1, 1, 2, 0, 1 },
100 [SOUND_MIXER_LINE1] = { AC97_MIX_AUX, 5, 0, 1, 1, 4, 0, 0 },
101 [SOUND_MIXER_VIDEO] = { AC97_MIX_VIDEO, 5, 0, 1, 1, 3, 0, 0 },
102 [SOUND_MIXER_RECLEV] = { -AC97_MIX_RGAIN, 4, 0, 1, 1, 0, 0, 1 }
103 };
104
105 static const struct ac97_vendorid ac97vendorid[] = {
106 { 0x41445300, "Analog Devices" },
107 { 0x414b4d00, "Asahi Kasei" },
108 { 0x414c4300, "Realtek" },
109 { 0x414c4700, "Avance Logic" },
110 { 0x43525900, "Cirrus Logic" },
111 { 0x434d4900, "C-Media Electronics" },
112 { 0x43585400, "Conexant" },
113 { 0x44543000, "Diamond Technology" },
114 { 0x454d4300, "eMicro" },
115 { 0x45838300, "ESS Technology" },
116 { 0x48525300, "Intersil" },
117 { 0x49434500, "ICEnsemble" },
118 { 0x49544500, "ITE, Inc." },
119 { 0x4e534300, "National Semiconductor" },
120 { 0x50534300, "Philips Semiconductor" },
121 { 0x83847600, "SigmaTel" },
122 { 0x53494c00, "Silicon Laboratories" },
123 { 0x54524100, "TriTech" },
124 { 0x54584e00, "Texas Instruments" },
125 { 0x56494100, "VIA Technologies" },
126 { 0x57454300, "Winbond" },
127 { 0x574d4c00, "Wolfson" },
128 { 0x594d4800, "Yamaha" },
129 /*
130 * XXX This is a fluke, really! The real vendor
131 * should be SigmaTel, not this! This should be
132 * removed someday!
133 */
134 { 0x01408300, "Creative" },
135 { 0x00000000, NULL }
136 };
137
138 static struct ac97_codecid ac97codecid[] = {
139 { 0x41445303, 0x00, 0, "AD1819", 0 },
140 { 0x41445340, 0x00, 0, "AD1881", 0 },
141 { 0x41445348, 0x00, 0, "AD1881A", 0 },
142 { 0x41445360, 0x00, 0, "AD1885", 0 },
143 { 0x41445361, 0x00, 0, "AD1886", ad1886_patch },
144 { 0x41445362, 0x00, 0, "AD1887", 0 },
145 { 0x41445363, 0x00, 0, "AD1886A", 0 },
146 { 0x41445368, 0x00, 0, "AD1888", ad198x_patch },
147 { 0x41445370, 0x00, 0, "AD1980", ad198x_patch },
148 { 0x41445372, 0x00, 0, "AD1981A", 0 },
149 { 0x41445374, 0x00, 0, "AD1981B", ad1981b_patch },
150 { 0x41445375, 0x00, 0, "AD1985", ad198x_patch },
151 { 0x41445378, 0x00, 0, "AD1986", ad198x_patch },
152 { 0x414b4d00, 0x00, 1, "AK4540", 0 },
153 { 0x414b4d01, 0x00, 1, "AK4542", 0 },
154 { 0x414b4d02, 0x00, 1, "AK4543", 0 },
155 { 0x414b4d06, 0x00, 0, "AK4544A", 0 },
156 { 0x454b4d07, 0x00, 0, "AK4545", 0 },
157 { 0x414c4320, 0x0f, 0, "ALC100", 0 },
158 { 0x414c4730, 0x0f, 0, "ALC101", 0 },
159 { 0x414c4710, 0x0f, 0, "ALC200", 0 },
160 { 0x414c4740, 0x0f, 0, "ALC202", 0 },
161 { 0x414c4720, 0x0f, 0, "ALC650", 0 },
162 { 0x414c4752, 0x0f, 0, "ALC250", 0 },
163 { 0x414c4760, 0x0f, 0, "ALC655", alc655_patch },
164 { 0x414c4770, 0x0f, 0, "ALC203", 0 },
165 { 0x414c4780, 0x0f, 0, "ALC658", 0 },
166 { 0x414c4790, 0x0f, 0, "ALC850", 0 },
167 { 0x43525900, 0x07, 0, "CS4297", 0 },
168 { 0x43525910, 0x07, 0, "CS4297A", 0 },
169 { 0x43525920, 0x07, 0, "CS4294/98", 0 },
170 { 0x4352592d, 0x07, 0, "CS4294", 0 },
171 { 0x43525930, 0x07, 0, "CS4299", 0 },
172 { 0x43525940, 0x07, 0, "CS4201", 0 },
173 { 0x43525958, 0x07, 0, "CS4205", 0 },
174 { 0x43525960, 0x07, 0, "CS4291A", 0 },
175 { 0x434d4961, 0x00, 0, "CMI9739", cmi9739_patch },
176 { 0x434d4941, 0x00, 0, "CMI9738", 0 },
177 { 0x434d4978, 0x00, 0, "CMI9761", 0 },
178 { 0x434d4982, 0x00, 0, "CMI9761", 0 },
179 { 0x434d4983, 0x00, 0, "CMI9761", 0 },
180 { 0x43585421, 0x00, 0, "HSD11246", 0 },
181 { 0x43585428, 0x07, 0, "CX20468", 0 },
182 { 0x43585430, 0x00, 0, "CX20468-21", 0 },
183 { 0x44543000, 0x00, 0, "DT0398", 0 },
184 { 0x454d4323, 0x00, 0, "EM28023", 0 },
185 { 0x454d4328, 0x00, 0, "EM28028", 0 },
186 { 0x45838308, 0x00, 0, "ES1988", 0 }, /* Formerly ES1921(?) */
187 { 0x48525300, 0x00, 0, "HMP9701", 0 },
188 { 0x49434501, 0x00, 0, "ICE1230", 0 },
189 { 0x49434511, 0x00, 0, "ICE1232", 0 },
190 { 0x49434514, 0x00, 0, "ICE1232A", 0 },
191 { 0x49434551, 0x03, 0, "VT1616", 0 }, /* Via badged ICE */
192 { 0x49544520, 0x00, 0, "ITE2226E", 0 },
193 { 0x49544560, 0x07, 0, "ITE2646E", 0 }, /* XXX: patch needed */
194 { 0x4e534340, 0x00, 0, "LM4540", 0 }, /* Spec blank on revid */
195 { 0x4e534343, 0x00, 0, "LM4543", 0 }, /* Ditto */
196 { 0x4e534346, 0x00, 0, "LM4546A", 0 },
197 { 0x4e534348, 0x00, 0, "LM4548A", 0 },
198 { 0x4e534331, 0x00, 0, "LM4549", 0 },
199 { 0x4e534349, 0x00, 0, "LM4549A", 0 },
200 { 0x4e534350, 0x00, 0, "LM4550", 0 },
201 { 0x50534301, 0x00, 0, "UCB1510", 0 },
202 { 0x50534304, 0x00, 0, "UCB1400", 0 },
203 { 0x83847600, 0x00, 0, "STAC9700/83/84", 0 },
204 { 0x83847604, 0x00, 0, "STAC9701/03/04/05", 0 },
205 { 0x83847605, 0x00, 0, "STAC9704", 0 },
206 { 0x83847608, 0x00, 0, "STAC9708/11", 0 },
207 { 0x83847609, 0x00, 0, "STAC9721/23", 0 },
208 { 0x83847644, 0x00, 0, "STAC9744/45", 0 },
209 { 0x83847650, 0x00, 0, "STAC9750/51", 0 },
210 { 0x83847652, 0x00, 0, "STAC9752/53", 0 },
211 { 0x83847656, 0x00, 0, "STAC9756/57", 0 },
212 { 0x83847658, 0x00, 0, "STAC9758/59", 0 },
213 { 0x83847660, 0x00, 0, "STAC9760/61", 0 }, /* Extrapolated */
214 { 0x83847662, 0x00, 0, "STAC9762/63", 0 }, /* Extrapolated */
215 { 0x83847666, 0x00, 0, "STAC9766/67", 0 },
216 { 0x53494c22, 0x00, 0, "Si3036", 0 },
217 { 0x53494c23, 0x00, 0, "Si3038", 0 },
218 { 0x54524103, 0x00, 0, "TR28023", 0 }, /* Extrapolated */
219 { 0x54524106, 0x00, 0, "TR28026", 0 },
220 { 0x54524108, 0x00, 0, "TR28028", 0 },
221 { 0x54524123, 0x00, 0, "TR28602", 0 },
222 { 0x54524e03, 0x07, 0, "TLV320AIC27", 0 },
223 { 0x54584e20, 0x00, 0, "TLC320AD90", 0 },
224 { 0x56494161, 0x00, 0, "VIA1612A", 0 },
225 { 0x56494170, 0x00, 0, "VIA1617A", 0 },
226 { 0x574d4c00, 0x00, 0, "WM9701A", 0 },
227 { 0x574d4c03, 0x00, 0, "WM9703/4/7/8", 0 },
228 { 0x574d4c04, 0x00, 0, "WM9704Q", 0 },
229 { 0x574d4c05, 0x00, 0, "WM9705/10", 0 },
230 { 0x574d4d09, 0x00, 0, "WM9709", 0 },
231 { 0x574d4c12, 0x00, 0, "WM9711/12", 0 }, /* XXX: patch needed */
232 { 0x57454301, 0x00, 0, "W83971D", 0 },
233 { 0x594d4800, 0x00, 0, "YMF743", 0 },
234 { 0x594d4802, 0x00, 0, "YMF752", 0 },
235 { 0x594d4803, 0x00, 0, "YMF753", 0 },
236 /*
237 * XXX This is a fluke, really! The real codec
238 * should be STAC9704, not this! This should be
239 * removed someday!
240 */
241 { 0x01408384, 0x00, 0, "EV1938", 0 },
242 { 0, 0, 0, NULL, 0 }
243 };
244
245 static char *ac97enhancement[] = {
246 "no 3D Stereo Enhancement",
247 "Analog Devices Phat Stereo",
248 "Creative Stereo Enhancement",
249 "National Semi 3D Stereo Enhancement",
250 "Yamaha Ymersion",
251 "BBE 3D Stereo Enhancement",
252 "Crystal Semi 3D Stereo Enhancement",
253 "Qsound QXpander",
254 "Spatializer 3D Stereo Enhancement",
255 "SRS 3D Stereo Enhancement",
256 "Platform Tech 3D Stereo Enhancement",
257 "AKM 3D Audio",
258 "Aureal Stereo Enhancement",
259 "Aztech 3D Enhancement",
260 "Binaura 3D Audio Enhancement",
261 "ESS Technology Stereo Enhancement",
262 "Harman International VMAx",
263 "Nvidea 3D Stereo Enhancement",
264 "Philips Incredible Sound",
265 "Texas Instruments 3D Stereo Enhancement",
266 "VLSI Technology 3D Stereo Enhancement",
267 "TriTech 3D Stereo Enhancement",
268 "Realtek 3D Stereo Enhancement",
269 "Samsung 3D Stereo Enhancement",
270 "Wolfson Microelectronics 3D Enhancement",
271 "Delta Integration 3D Enhancement",
272 "SigmaTel 3D Enhancement",
273 "Reserved 27",
274 "Rockwell 3D Stereo Enhancement",
275 "Reserved 29",
276 "Reserved 30",
277 "Reserved 31"
278 };
279
280 static char *ac97feature[] = {
281 "mic channel",
282 "reserved",
283 "tone",
284 "simulated stereo",
285 "headphone",
286 "bass boost",
287 "18 bit DAC",
288 "20 bit DAC",
289 "18 bit ADC",
290 "20 bit ADC"
291 };
292
293 static char *ac97extfeature[] = {
294 "variable rate PCM",
295 "double rate PCM",
296 "reserved 1",
297 "variable rate mic",
298 "reserved 2",
299 "reserved 3",
300 "center DAC",
301 "surround DAC",
302 "LFE DAC",
303 "AMAP",
304 "reserved 4",
305 "reserved 5",
306 "reserved 6",
307 "reserved 7",
308 };
309
310 u_int16_t
311 ac97_rdcd(struct ac97_info *codec, int reg)
312 {
313 if (codec->flags & AC97_F_RDCD_BUG) {
314 u_int16_t i[2], j = 100;
315
316 i[0] = AC97_READ(codec->methods, codec->devinfo, reg);
317 i[1] = AC97_READ(codec->methods, codec->devinfo, reg);
318 while (i[0] != i[1] && j)
319 i[j-- & 1] = AC97_READ(codec->methods, codec->devinfo, reg);
320 #if 0
321 if (j < 100) {
322 device_printf(codec->dev, "%s(): Inconsistent register value at"
323 " 0x%08x (retry: %d)\n", __func__, reg, 100 - j);
324 }
325 #endif
326 return i[!(j & 1)];
327 }
328 return AC97_READ(codec->methods, codec->devinfo, reg);
329 }
330
331 void
332 ac97_wrcd(struct ac97_info *codec, int reg, u_int16_t val)
333 {
334 AC97_WRITE(codec->methods, codec->devinfo, reg, val);
335 }
336
337 static void
338 ac97_reset(struct ac97_info *codec)
339 {
340 u_int32_t i, ps;
341 ac97_wrcd(codec, AC97_REG_RESET, 0);
342 for (i = 0; i < 500; i++) {
343 ps = ac97_rdcd(codec, AC97_REG_POWER) & AC97_POWER_STATUS;
344 if (ps == AC97_POWER_STATUS)
345 return;
346 DELAY(1000);
347 }
348 device_printf(codec->dev, "AC97 reset timed out.\n");
349 }
350
351 int
352 ac97_setrate(struct ac97_info *codec, int which, int rate)
353 {
354 u_int16_t v;
355
356 switch(which) {
357 case AC97_REGEXT_FDACRATE:
358 case AC97_REGEXT_SDACRATE:
359 case AC97_REGEXT_LDACRATE:
360 case AC97_REGEXT_LADCRATE:
361 case AC97_REGEXT_MADCRATE:
362 break;
363
364 default:
365 return -1;
366 }
367
368 snd_mtxlock(codec->lock);
369 if (rate != 0) {
370 v = rate;
371 if (codec->extstat & AC97_EXTCAP_DRA)
372 v >>= 1;
373 ac97_wrcd(codec, which, v);
374 }
375 v = ac97_rdcd(codec, which);
376 if (codec->extstat & AC97_EXTCAP_DRA)
377 v <<= 1;
378 snd_mtxunlock(codec->lock);
379 return v;
380 }
381
382 int
383 ac97_setextmode(struct ac97_info *codec, u_int16_t mode)
384 {
385 mode &= AC97_EXTCAPS;
386 if ((mode & ~codec->extcaps) != 0) {
387 device_printf(codec->dev, "ac97 invalid mode set 0x%04x\n",
388 mode);
389 return -1;
390 }
391 snd_mtxlock(codec->lock);
392 ac97_wrcd(codec, AC97_REGEXT_STAT, mode);
393 codec->extstat = ac97_rdcd(codec, AC97_REGEXT_STAT) & AC97_EXTCAPS;
394 snd_mtxunlock(codec->lock);
395 return (mode == codec->extstat)? 0 : -1;
396 }
397
398 u_int16_t
399 ac97_getextmode(struct ac97_info *codec)
400 {
401 return codec->extstat;
402 }
403
404 u_int16_t
405 ac97_getextcaps(struct ac97_info *codec)
406 {
407 return codec->extcaps;
408 }
409
410 u_int16_t
411 ac97_getcaps(struct ac97_info *codec)
412 {
413 return codec->caps;
414 }
415
416 u_int32_t
417 ac97_getsubvendor(struct ac97_info *codec)
418 {
419 return codec->subvendor;
420 }
421
422 static int
423 ac97_setrecsrc(struct ac97_info *codec, int channel)
424 {
425 struct ac97mixtable_entry *e = &codec->mix[channel];
426
427 if (e->recidx > 0) {
428 int val = e->recidx - 1;
429 val |= val << 8;
430 snd_mtxlock(codec->lock);
431 ac97_wrcd(codec, AC97_REG_RECSEL, val);
432 snd_mtxunlock(codec->lock);
433 return 0;
434 } else
435 return -1;
436 }
437
438 static int
439 ac97_setmixer(struct ac97_info *codec, unsigned channel, unsigned left, unsigned right)
440 {
441 struct ac97mixtable_entry *e = &codec->mix[channel];
442
443 if (e->reg && e->enable && e->bits) {
444 int mask, max, val, reg;
445
446 reg = (e->reg >= 0) ? e->reg : -e->reg; /* AC97 register */
447 max = (1 << e->bits) - 1; /* actual range */
448 mask = (max << 8) | max; /* bits of interest */
449
450 if (!e->stereo)
451 right = left;
452
453 /*
454 * Invert the range if the polarity requires so,
455 * then scale to 0..max-1 to compute the value to
456 * write into the codec, and scale back to 0..100
457 * for the return value.
458 */
459 if (e->reg > 0) {
460 left = 100 - left;
461 right = 100 - right;
462 }
463
464 left = (left * max) / 100;
465 right = (right * max) / 100;
466
467 val = (left << 8) | right;
468
469 left = (left * 100) / max;
470 right = (right * 100) / max;
471
472 if (e->reg > 0) {
473 left = 100 - left;
474 right = 100 - right;
475 }
476
477 /*
478 * For mono controls, trim val and mask, also taking
479 * care of e->ofs (offset of control field).
480 */
481 if (e->ofs) {
482 val &= max;
483 val <<= e->ofs;
484 mask = (max << e->ofs);
485 }
486
487 /*
488 * If we have a mute bit, add it to the mask and
489 * update val and set mute if both channels require a
490 * zero volume.
491 */
492 if (e->mute == 1) {
493 mask |= AC97_MUTE;
494 if (left == 0 && right == 0)
495 val = AC97_MUTE;
496 }
497
498 /*
499 * If the mask bit is set, do not alter the other bits.
500 */
501 snd_mtxlock(codec->lock);
502 if (e->mask) {
503 int cur = ac97_rdcd(codec, reg);
504 val |= cur & ~(mask);
505 }
506 ac97_wrcd(codec, reg, val);
507 snd_mtxunlock(codec->lock);
508 return left | (right << 8);
509 } else {
510 #if 0
511 printf("ac97_setmixer: reg=%d, bits=%d, enable=%d\n", e->reg, e->bits, e->enable);
512 #endif
513 return -1;
514 }
515 }
516
517 static void
518 ac97_fix_auxout(struct ac97_info *codec)
519 {
520 int keep_ogain;
521
522 /*
523 * By default, The ac97 aux_out register (0x04) corresponds to OSS's
524 * OGAIN setting.
525 *
526 * We first check whether aux_out is a valid register. If not
527 * we may not want to keep ogain.
528 */
529 keep_ogain = ac97_rdcd(codec, AC97_MIX_AUXOUT) & 0x8000;
530
531 /*
532 * Determine what AUX_OUT really means, it can be:
533 *
534 * 1. Headphone out.
535 * 2. 4-Channel Out
536 * 3. True line level out (effectively master volume).
537 *
538 * See Sections 5.2.1 and 5.27 for AUX_OUT Options in AC97r2.{2,3}.
539 */
540 if (codec->extcaps & AC97_EXTCAP_SDAC &&
541 ac97_rdcd(codec, AC97_MIXEXT_SURROUND) == 0x8080) {
542 codec->mix[SOUND_MIXER_OGAIN].reg = AC97_MIXEXT_SURROUND;
543 keep_ogain = 1;
544 }
545
546 if (keep_ogain == 0) {
547 bzero(&codec->mix[SOUND_MIXER_OGAIN],
548 sizeof(codec->mix[SOUND_MIXER_OGAIN]));
549 }
550 }
551
552 static void
553 ac97_fix_tone(struct ac97_info *codec)
554 {
555 /*
556 * YMF chips does not indicate tone and 3D enhancement capability
557 * in the AC97_REG_RESET register.
558 */
559 switch (codec->id) {
560 case 0x594d4800: /* YMF743 */
561 case 0x594d4803: /* YMF753 */
562 codec->caps |= AC97_CAP_TONE;
563 codec->se |= 0x04;
564 break;
565 case 0x594d4802: /* YMF752 */
566 codec->se |= 0x04;
567 break;
568 default:
569 break;
570 }
571
572 /* Hide treble and bass if they don't exist */
573 if ((codec->caps & AC97_CAP_TONE) == 0) {
574 bzero(&codec->mix[SOUND_MIXER_BASS],
575 sizeof(codec->mix[SOUND_MIXER_BASS]));
576 bzero(&codec->mix[SOUND_MIXER_TREBLE],
577 sizeof(codec->mix[SOUND_MIXER_TREBLE]));
578 }
579 }
580
581 static const char*
582 ac97_hw_desc(u_int32_t id, const char* vname, const char* cname, char* buf)
583 {
584 if (cname == NULL) {
585 sprintf(buf, "Unknown AC97 Codec (id = 0x%08x)", id);
586 return buf;
587 }
588
589 if (vname == NULL) vname = "Unknown";
590
591 if (bootverbose) {
592 sprintf(buf, "%s %s AC97 Codec (id = 0x%08x)", vname, cname, id);
593 } else {
594 sprintf(buf, "%s %s AC97 Codec", vname, cname);
595 }
596 return buf;
597 }
598
599 static unsigned
600 ac97_initmixer(struct ac97_info *codec)
601 {
602 ac97_patch codec_patch;
603 const char *cname, *vname;
604 char desc[80];
605 u_int8_t model, step;
606 unsigned i, j, k, bit, old;
607 u_int32_t id;
608 int reg;
609
610 snd_mtxlock(codec->lock);
611 codec->count = AC97_INIT(codec->methods, codec->devinfo);
612 if (codec->count == 0) {
613 device_printf(codec->dev, "ac97 codec init failed\n");
614 snd_mtxunlock(codec->lock);
615 return ENODEV;
616 }
617
618 ac97_wrcd(codec, AC97_REG_POWER, (codec->flags & AC97_F_EAPD_INV)? 0x8000 : 0x0000);
619 ac97_reset(codec);
620 ac97_wrcd(codec, AC97_REG_POWER, (codec->flags & AC97_F_EAPD_INV)? 0x8000 : 0x0000);
621
622 i = ac97_rdcd(codec, AC97_REG_RESET);
623 j = ac97_rdcd(codec, AC97_REG_RESET);
624 k = ac97_rdcd(codec, AC97_REG_RESET);
625 /*
626 * Let see if this codec can return consistent value.
627 * If not, turn on aggressive read workaround
628 * (STAC9704 comes in mind).
629 */
630 if (i != j || j != k) {
631 codec->flags |= AC97_F_RDCD_BUG;
632 i = ac97_rdcd(codec, AC97_REG_RESET);
633 }
634 codec->caps = i & 0x03ff;
635 codec->se = (i & 0x7c00) >> 10;
636
637 id = (ac97_rdcd(codec, AC97_REG_ID1) << 16) | ac97_rdcd(codec, AC97_REG_ID2);
638 if (id == 0 || id == 0xffffffff) {
639 device_printf(codec->dev, "ac97 codec invalid or not present (id == %x)\n", id);
640 snd_mtxunlock(codec->lock);
641 return ENODEV;
642 }
643
644 codec->id = id;
645 codec->subvendor = (u_int32_t)pci_get_subdevice(codec->dev) << 16;
646 codec->subvendor |= (u_int32_t)pci_get_subvendor(codec->dev) &
647 0x0000ffff;
648 codec->noext = 0;
649 codec_patch = NULL;
650
651 cname = NULL;
652 model = step = 0;
653 for (i = 0; ac97codecid[i].id; i++) {
654 u_int32_t modelmask = 0xffffffff ^ ac97codecid[i].stepmask;
655 if ((ac97codecid[i].id & modelmask) == (id & modelmask)) {
656 codec->noext = ac97codecid[i].noext;
657 codec_patch = ac97codecid[i].patch;
658 cname = ac97codecid[i].name;
659 model = (id & modelmask) & 0xff;
660 step = (id & ~modelmask) & 0xff;
661 break;
662 }
663 }
664
665 vname = NULL;
666 for (i = 0; ac97vendorid[i].id; i++) {
667 if (ac97vendorid[i].id == (id & 0xffffff00)) {
668 vname = ac97vendorid[i].name;
669 break;
670 }
671 }
672
673 codec->extcaps = 0;
674 codec->extid = 0;
675 codec->extstat = 0;
676 if (!codec->noext) {
677 i = ac97_rdcd(codec, AC97_REGEXT_ID);
678 if (i != 0xffff) {
679 codec->extcaps = i & 0x3fff;
680 codec->extid = (i & 0xc000) >> 14;
681 codec->extstat = ac97_rdcd(codec, AC97_REGEXT_STAT) & AC97_EXTCAPS;
682 }
683 }
684
685 for (i = 0; i < AC97_MIXER_SIZE; i++) {
686 codec->mix[i] = ac97mixtable_default[i];
687 }
688 ac97_fix_auxout(codec);
689 ac97_fix_tone(codec);
690 if (codec_patch)
691 codec_patch(codec);
692
693 for (i = 0; i < AC97_MIXER_SIZE; i++) {
694 k = codec->noext? codec->mix[i].enable : 1;
695 reg = codec->mix[i].reg;
696 if (reg < 0)
697 reg = -reg;
698 if (k && reg) {
699 j = old = ac97_rdcd(codec, reg);
700 /*
701 * Test for mute bit (except for AC97_MIX_TONE,
702 * where we simply assume it as available).
703 */
704 if (codec->mix[i].mute) {
705 ac97_wrcd(codec, reg, j | 0x8000);
706 j = ac97_rdcd(codec, reg);
707 } else
708 j |= 0x8000;
709 if ((j & 0x8000)) {
710 /*
711 * Test whether the control width should be
712 * 4, 5 or 6 bit. For 5bit register, we should
713 * test it whether it's really 5 or 6bit. Leave
714 * 4bit register alone, because sometimes an
715 * attempt to write past 4th bit may cause
716 * incorrect result especially for AC97_MIX_BEEP
717 * (ac97 2.3).
718 */
719 bit = codec->mix[i].bits;
720 if (bit == 5)
721 bit++;
722 j = ((1 << bit) - 1) << codec->mix[i].ofs;
723 ac97_wrcd(codec, reg,
724 j | (codec->mix[i].mute ? 0x8000 : 0));
725 k = ac97_rdcd(codec, reg) & j;
726 k >>= codec->mix[i].ofs;
727 if (reg == AC97_MIX_TONE &&
728 ((k & 0x0001) == 0x0000))
729 k >>= 1;
730 for (j = 0; k >> j; j++)
731 ;
732 if (j != 0) {
733 #if 0
734 device_printf(codec->dev, "%2d: [ac97_rdcd() = %d] [Testbit = %d] %d -> %d\n",
735 i, k, bit, codec->mix[i].bits, j);
736 #endif
737 codec->mix[i].enable = 1;
738 codec->mix[i].bits = j;
739 } else if (reg == AC97_MIX_BEEP) {
740 /*
741 * Few codec such as CX20468-21 does
742 * have this control register, although
743 * the only usable part is the mute bit.
744 */
745 codec->mix[i].enable = 1;
746 } else
747 codec->mix[i].enable = 0;
748 } else
749 codec->mix[i].enable = 0;
750 ac97_wrcd(codec, reg, old);
751 }
752 #if 0
753 printf("mixch %d, en=%d, b=%d\n", i, codec->mix[i].enable, codec->mix[i].bits);
754 #endif
755 }
756
757 device_printf(codec->dev, "<%s>\n",
758 ac97_hw_desc(codec->id, vname, cname, desc));
759
760 if (bootverbose) {
761 if (codec->flags & AC97_F_RDCD_BUG)
762 device_printf(codec->dev, "Buggy AC97 Codec: aggressive ac97_rdcd() workaround enabled\n");
763 device_printf(codec->dev, "Codec features ");
764 for (i = j = 0; i < 10; i++)
765 if (codec->caps & (1 << i))
766 printf("%s%s", j++? ", " : "", ac97feature[i]);
767 printf("%s%d bit master volume", j++? ", " : "", codec->mix[SOUND_MIXER_VOLUME].bits);
768 printf("%s%s\n", j? ", " : "", ac97enhancement[codec->se]);
769
770 if (codec->extcaps != 0 || codec->extid) {
771 device_printf(codec->dev, "%s codec",
772 codec->extid? "Secondary" : "Primary");
773 if (codec->extcaps)
774 printf(" extended features ");
775 for (i = j = 0; i < 14; i++)
776 if (codec->extcaps & (1 << i))
777 printf("%s%s", j++? ", " : "", ac97extfeature[i]);
778 printf("\n");
779 }
780 }
781
782 i = 0;
783 while ((ac97_rdcd(codec, AC97_REG_POWER) & 2) == 0) {
784 if (++i == 100) {
785 device_printf(codec->dev, "ac97 codec reports dac not ready\n");
786 break;
787 }
788 DELAY(1000);
789 }
790 if (bootverbose)
791 device_printf(codec->dev, "ac97 codec dac ready count: %d\n", i);
792 snd_mtxunlock(codec->lock);
793 return 0;
794 }
795
796 static unsigned
797 ac97_reinitmixer(struct ac97_info *codec)
798 {
799 snd_mtxlock(codec->lock);
800 codec->count = AC97_INIT(codec->methods, codec->devinfo);
801 if (codec->count == 0) {
802 device_printf(codec->dev, "ac97 codec init failed\n");
803 snd_mtxunlock(codec->lock);
804 return ENODEV;
805 }
806
807 ac97_wrcd(codec, AC97_REG_POWER, (codec->flags & AC97_F_EAPD_INV)? 0x8000 : 0x0000);
808 ac97_reset(codec);
809 ac97_wrcd(codec, AC97_REG_POWER, (codec->flags & AC97_F_EAPD_INV)? 0x8000 : 0x0000);
810
811 if (!codec->noext) {
812 ac97_wrcd(codec, AC97_REGEXT_STAT, codec->extstat);
813 if ((ac97_rdcd(codec, AC97_REGEXT_STAT) & AC97_EXTCAPS)
814 != codec->extstat)
815 device_printf(codec->dev, "ac97 codec failed to reset extended mode (%x, got %x)\n",
816 codec->extstat,
817 ac97_rdcd(codec, AC97_REGEXT_STAT) &
818 AC97_EXTCAPS);
819 }
820
821 if ((ac97_rdcd(codec, AC97_REG_POWER) & 2) == 0)
822 device_printf(codec->dev, "ac97 codec reports dac not ready\n");
823 snd_mtxunlock(codec->lock);
824 return 0;
825 }
826
827 struct ac97_info *
828 ac97_create(device_t dev, void *devinfo, kobj_class_t cls)
829 {
830 struct ac97_info *codec;
831 int i;
832
833 codec = malloc(sizeof(*codec), M_AC97, M_WAITOK | M_ZERO);
834 snprintf(codec->name, sizeof(codec->name), "%s:ac97",
835 device_get_nameunit(dev));
836 codec->lock = snd_mtxcreate(codec->name, "ac97 codec");
837 codec->methods = kobj_create(cls, M_AC97, M_WAITOK | M_ZERO);
838 codec->dev = dev;
839 codec->devinfo = devinfo;
840 codec->flags = 0;
841
842 if (resource_int_value(device_get_name(dev), device_get_unit(dev),
843 "eapdinv", &i) == 0 && i != 0)
844 codec->flags |= AC97_F_EAPD_INV;
845
846 if (resource_int_value(device_get_name(dev), device_get_unit(dev),
847 "softpcmvol", &i) == 0 && i != 0)
848 pcm_setflags(dev, pcm_getflags(dev) | SD_F_SOFTPCMVOL);
849
850 return codec;
851 }
852
853 void
854 ac97_destroy(struct ac97_info *codec)
855 {
856 snd_mtxlock(codec->lock);
857 if (codec->methods != NULL)
858 kobj_delete(codec->methods, M_AC97);
859 snd_mtxfree(codec->lock);
860 free(codec, M_AC97);
861 }
862
863 void
864 ac97_setflags(struct ac97_info *codec, u_int32_t val)
865 {
866 codec->flags = val;
867 }
868
869 u_int32_t
870 ac97_getflags(struct ac97_info *codec)
871 {
872 return codec->flags;
873 }
874
875 /* -------------------------------------------------------------------- */
876
877 static int
878 sysctl_hw_snd_ac97_eapd(SYSCTL_HANDLER_ARGS)
879 {
880 struct ac97_info *codec;
881 int ea, inv, err = 0;
882 u_int16_t val;
883
884 codec = oidp->oid_arg1;
885 if (codec == NULL || codec->id == 0 || codec->lock == NULL)
886 return EINVAL;
887 snd_mtxlock(codec->lock);
888 val = ac97_rdcd(codec, AC97_REG_POWER);
889 inv = (codec->flags & AC97_F_EAPD_INV) ? 0 : 1;
890 ea = (val >> 15) ^ inv;
891 snd_mtxunlock(codec->lock);
892 err = sysctl_handle_int(oidp, &ea, 0, req);
893 if (err == 0 && req->newptr != NULL) {
894 if (ea != 0 && ea != 1)
895 return EINVAL;
896 if (ea != ((val >> 15) ^ inv)) {
897 snd_mtxlock(codec->lock);
898 ac97_wrcd(codec, AC97_REG_POWER, val ^ 0x8000);
899 snd_mtxunlock(codec->lock);
900 }
901 }
902 return err;
903 }
904
905 static void
906 ac97_init_sysctl(struct ac97_info *codec)
907 {
908 u_int16_t orig, val;
909
910 if (codec == NULL || codec->dev == NULL)
911 return;
912 snd_mtxlock(codec->lock);
913 orig = ac97_rdcd(codec, AC97_REG_POWER);
914 ac97_wrcd(codec, AC97_REG_POWER, orig ^ 0x8000);
915 val = ac97_rdcd(codec, AC97_REG_POWER);
916 ac97_wrcd(codec, AC97_REG_POWER, orig);
917 snd_mtxunlock(codec->lock);
918 if ((val & 0x8000) == (orig & 0x8000))
919 return;
920 SYSCTL_ADD_PROC(device_get_sysctl_ctx(codec->dev),
921 SYSCTL_CHILDREN(device_get_sysctl_tree(codec->dev)),
922 OID_AUTO, "eapd", CTLTYPE_INT | CTLFLAG_RW,
923 codec, sizeof(codec), sysctl_hw_snd_ac97_eapd,
924 "I", "AC97 External Amplifier");
925 }
926
927 static int
928 ac97mix_init(struct snd_mixer *m)
929 {
930 struct ac97_info *codec = mix_getdevinfo(m);
931 u_int32_t i, mask;
932
933 if (codec == NULL)
934 return -1;
935
936 if (ac97_initmixer(codec))
937 return -1;
938
939 switch (codec->id) {
940 case 0x41445374: /* AD1981B */
941 switch (codec->subvendor) {
942 case 0x02d91014:
943 /*
944 * IBM Thinkcentre:
945 *
946 * Tie "ogain" and "phout" to "vol" since its
947 * master volume is basically useless and can't
948 * control anything.
949 */
950 mask = 0;
951 if (codec->mix[SOUND_MIXER_OGAIN].enable)
952 mask |= SOUND_MASK_OGAIN;
953 if (codec->mix[SOUND_MIXER_PHONEOUT].enable)
954 mask |= SOUND_MASK_PHONEOUT;
955 if (codec->mix[SOUND_MIXER_VOLUME].enable)
956 mix_setparentchild(m, SOUND_MIXER_VOLUME,
957 mask);
958 else {
959 mix_setparentchild(m, SOUND_MIXER_VOLUME,
960 mask);
961 mix_setrealdev(m, SOUND_MIXER_VOLUME,
962 SOUND_MIXER_NONE);
963 }
964 break;
965 case 0x099c103c:
966 /*
967 * HP nx6110:
968 *
969 * By default, "vol" is controlling internal speakers
970 * (not a master volume!) and "ogain" is controlling
971 * headphone. Enable dummy "phout" so it can be
972 * remapped to internal speakers and virtualize
973 * "vol" to control both.
974 */
975 codec->mix[SOUND_MIXER_OGAIN].enable = 1;
976 codec->mix[SOUND_MIXER_PHONEOUT].enable = 1;
977 mix_setrealdev(m, SOUND_MIXER_PHONEOUT,
978 SOUND_MIXER_VOLUME);
979 mix_setrealdev(m, SOUND_MIXER_VOLUME,
980 SOUND_MIXER_NONE);
981 mix_setparentchild(m, SOUND_MIXER_VOLUME,
982 SOUND_MASK_OGAIN | SOUND_MASK_PHONEOUT);
983 break;
984 default:
985 break;
986 }
987 break;
988 case 0x434d4941: /* CMI9738 */
989 case 0x434d4961: /* CMI9739 */
990 case 0x434d4978: /* CMI9761 */
991 case 0x434d4982: /* CMI9761 */
992 case 0x434d4983: /* CMI9761 */
993 bzero(&codec->mix[SOUND_MIXER_PCM],
994 sizeof(codec->mix[SOUND_MIXER_PCM]));
995 pcm_setflags(codec->dev, pcm_getflags(codec->dev) |
996 SD_F_SOFTPCMVOL);
997 /* XXX How about master volume ? */
998 break;
999 default:
1000 break;
1001 }
1002
1003 if (pcm_getflags(codec->dev) & SD_F_SOFTPCMVOL)
1004 ac97_wrcd(codec, AC97_MIX_PCM, 0);
1005 #if 0
1006 /* XXX For the sake of debugging purposes */
1007 mix_setparentchild(m, SOUND_MIXER_VOLUME,
1008 SOUND_MASK_PCM | SOUND_MASK_CD);
1009 mix_setrealdev(m, SOUND_MIXER_VOLUME, SOUND_MIXER_NONE);
1010 ac97_wrcd(codec, AC97_MIX_MASTER, 0);
1011 #endif
1012
1013 mask = 0;
1014 for (i = 0; i < AC97_MIXER_SIZE; i++)
1015 mask |= codec->mix[i].enable? 1 << i : 0;
1016 mix_setdevs(m, mask);
1017
1018 mask = 0;
1019 for (i = 0; i < AC97_MIXER_SIZE; i++)
1020 mask |= codec->mix[i].recidx? 1 << i : 0;
1021 mix_setrecdevs(m, mask);
1022
1023 ac97_init_sysctl(codec);
1024
1025 return 0;
1026 }
1027
1028 static int
1029 ac97mix_uninit(struct snd_mixer *m)
1030 {
1031 struct ac97_info *codec = mix_getdevinfo(m);
1032
1033 if (codec == NULL)
1034 return -1;
1035 /*
1036 if (ac97_uninitmixer(codec))
1037 return -1;
1038 */
1039 ac97_destroy(codec);
1040 return 0;
1041 }
1042
1043 static int
1044 ac97mix_reinit(struct snd_mixer *m)
1045 {
1046 struct ac97_info *codec = mix_getdevinfo(m);
1047
1048 if (codec == NULL)
1049 return -1;
1050 return ac97_reinitmixer(codec);
1051 }
1052
1053 static int
1054 ac97mix_set(struct snd_mixer *m, unsigned dev, unsigned left, unsigned right)
1055 {
1056 struct ac97_info *codec = mix_getdevinfo(m);
1057
1058 if (codec == NULL || dev >= AC97_MIXER_SIZE)
1059 return -1;
1060 return ac97_setmixer(codec, dev, left, right);
1061 }
1062
1063 static u_int32_t
1064 ac97mix_setrecsrc(struct snd_mixer *m, u_int32_t src)
1065 {
1066 int i;
1067 struct ac97_info *codec = mix_getdevinfo(m);
1068
1069 if (codec == NULL)
1070 return -1;
1071 for (i = 0; i < AC97_MIXER_SIZE; i++)
1072 if ((src & (1 << i)) != 0)
1073 break;
1074 return (ac97_setrecsrc(codec, i) == 0)? 1U << i : 0xffffffffU;
1075 }
1076
1077 static kobj_method_t ac97mixer_methods[] = {
1078 KOBJMETHOD(mixer_init, ac97mix_init),
1079 KOBJMETHOD(mixer_uninit, ac97mix_uninit),
1080 KOBJMETHOD(mixer_reinit, ac97mix_reinit),
1081 KOBJMETHOD(mixer_set, ac97mix_set),
1082 KOBJMETHOD(mixer_setrecsrc, ac97mix_setrecsrc),
1083 KOBJMETHOD_END
1084 };
1085 MIXER_DECLARE(ac97mixer);
1086
1087 /* -------------------------------------------------------------------- */
1088
1089 kobj_class_t
1090 ac97_getmixerclass(void)
1091 {
1092 return &ac97mixer_class;
1093 }
Cache object: c1d7592ea93daa457e6c1adfe0273315
|