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$");
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 device_t pdev;
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 pdev = codec->dev;
645 while (strcmp(device_get_name(device_get_parent(pdev)), "pci") != 0) {
646 /* find the top-level PCI device handler */
647 pdev = device_get_parent(pdev);
648 }
649 codec->id = id;
650 codec->subvendor = (u_int32_t)pci_get_subdevice(pdev) << 16;
651 codec->subvendor |= (u_int32_t)pci_get_subvendor(pdev) &
652 0x0000ffff;
653 codec->noext = 0;
654 codec_patch = NULL;
655
656 cname = NULL;
657 for (i = 0; ac97codecid[i].id; i++) {
658 u_int32_t modelmask = 0xffffffff ^ ac97codecid[i].stepmask;
659 if ((ac97codecid[i].id & modelmask) == (id & modelmask)) {
660 codec->noext = ac97codecid[i].noext;
661 codec_patch = ac97codecid[i].patch;
662 cname = ac97codecid[i].name;
663 break;
664 }
665 }
666
667 vname = NULL;
668 for (i = 0; ac97vendorid[i].id; i++) {
669 if (ac97vendorid[i].id == (id & 0xffffff00)) {
670 vname = ac97vendorid[i].name;
671 break;
672 }
673 }
674
675 codec->extcaps = 0;
676 codec->extid = 0;
677 codec->extstat = 0;
678 if (!codec->noext) {
679 i = ac97_rdcd(codec, AC97_REGEXT_ID);
680 if (i != 0xffff) {
681 codec->extcaps = i & 0x3fff;
682 codec->extid = (i & 0xc000) >> 14;
683 codec->extstat = ac97_rdcd(codec, AC97_REGEXT_STAT) & AC97_EXTCAPS;
684 }
685 }
686
687 for (i = 0; i < AC97_MIXER_SIZE; i++) {
688 codec->mix[i] = ac97mixtable_default[i];
689 }
690 ac97_fix_auxout(codec);
691 ac97_fix_tone(codec);
692 if (codec_patch)
693 codec_patch(codec);
694
695 for (i = 0; i < AC97_MIXER_SIZE; i++) {
696 k = codec->noext? codec->mix[i].enable : 1;
697 reg = codec->mix[i].reg;
698 if (reg < 0)
699 reg = -reg;
700 if (k && reg) {
701 j = old = ac97_rdcd(codec, reg);
702 /*
703 * Test for mute bit (except for AC97_MIX_TONE,
704 * where we simply assume it as available).
705 */
706 if (codec->mix[i].mute) {
707 ac97_wrcd(codec, reg, j | 0x8000);
708 j = ac97_rdcd(codec, reg);
709 } else
710 j |= 0x8000;
711 if ((j & 0x8000)) {
712 /*
713 * Test whether the control width should be
714 * 4, 5 or 6 bit. For 5bit register, we should
715 * test it whether it's really 5 or 6bit. Leave
716 * 4bit register alone, because sometimes an
717 * attempt to write past 4th bit may cause
718 * incorrect result especially for AC97_MIX_BEEP
719 * (ac97 2.3).
720 */
721 bit = codec->mix[i].bits;
722 if (bit == 5)
723 bit++;
724 j = ((1 << bit) - 1) << codec->mix[i].ofs;
725 ac97_wrcd(codec, reg,
726 j | (codec->mix[i].mute ? 0x8000 : 0));
727 k = ac97_rdcd(codec, reg) & j;
728 k >>= codec->mix[i].ofs;
729 if (reg == AC97_MIX_TONE &&
730 ((k & 0x0001) == 0x0000))
731 k >>= 1;
732 for (j = 0; k >> j; j++)
733 ;
734 if (j != 0) {
735 #if 0
736 device_printf(codec->dev, "%2d: [ac97_rdcd() = %d] [Testbit = %d] %d -> %d\n",
737 i, k, bit, codec->mix[i].bits, j);
738 #endif
739 codec->mix[i].enable = 1;
740 codec->mix[i].bits = j;
741 } else if (reg == AC97_MIX_BEEP) {
742 /*
743 * Few codec such as CX20468-21 does
744 * have this control register, although
745 * the only usable part is the mute bit.
746 */
747 codec->mix[i].enable = 1;
748 } else
749 codec->mix[i].enable = 0;
750 } else
751 codec->mix[i].enable = 0;
752 ac97_wrcd(codec, reg, old);
753 }
754 #if 0
755 printf("mixch %d, en=%d, b=%d\n", i, codec->mix[i].enable, codec->mix[i].bits);
756 #endif
757 }
758
759 device_printf(codec->dev, "<%s>\n",
760 ac97_hw_desc(codec->id, vname, cname, desc));
761
762 if (bootverbose) {
763 if (codec->flags & AC97_F_RDCD_BUG)
764 device_printf(codec->dev, "Buggy AC97 Codec: aggressive ac97_rdcd() workaround enabled\n");
765 device_printf(codec->dev, "Codec features ");
766 for (i = j = 0; i < 10; i++)
767 if (codec->caps & (1 << i))
768 printf("%s%s", j++? ", " : "", ac97feature[i]);
769 printf("%s%d bit master volume", j++? ", " : "", codec->mix[SOUND_MIXER_VOLUME].bits);
770 printf("%s%s\n", j? ", " : "", ac97enhancement[codec->se]);
771
772 if (codec->extcaps != 0 || codec->extid) {
773 device_printf(codec->dev, "%s codec",
774 codec->extid? "Secondary" : "Primary");
775 if (codec->extcaps)
776 printf(" extended features ");
777 for (i = j = 0; i < 14; i++)
778 if (codec->extcaps & (1 << i))
779 printf("%s%s", j++? ", " : "", ac97extfeature[i]);
780 printf("\n");
781 }
782 }
783
784 i = 0;
785 while ((ac97_rdcd(codec, AC97_REG_POWER) & 2) == 0) {
786 if (++i == 100) {
787 device_printf(codec->dev, "ac97 codec reports dac not ready\n");
788 break;
789 }
790 DELAY(1000);
791 }
792 if (bootverbose)
793 device_printf(codec->dev, "ac97 codec dac ready count: %d\n", i);
794 snd_mtxunlock(codec->lock);
795 return 0;
796 }
797
798 static unsigned
799 ac97_reinitmixer(struct ac97_info *codec)
800 {
801 snd_mtxlock(codec->lock);
802 codec->count = AC97_INIT(codec->methods, codec->devinfo);
803 if (codec->count == 0) {
804 device_printf(codec->dev, "ac97 codec init failed\n");
805 snd_mtxunlock(codec->lock);
806 return ENODEV;
807 }
808
809 ac97_wrcd(codec, AC97_REG_POWER, (codec->flags & AC97_F_EAPD_INV)? 0x8000 : 0x0000);
810 ac97_reset(codec);
811 ac97_wrcd(codec, AC97_REG_POWER, (codec->flags & AC97_F_EAPD_INV)? 0x8000 : 0x0000);
812
813 if (!codec->noext) {
814 ac97_wrcd(codec, AC97_REGEXT_STAT, codec->extstat);
815 if ((ac97_rdcd(codec, AC97_REGEXT_STAT) & AC97_EXTCAPS)
816 != codec->extstat)
817 device_printf(codec->dev, "ac97 codec failed to reset extended mode (%x, got %x)\n",
818 codec->extstat,
819 ac97_rdcd(codec, AC97_REGEXT_STAT) &
820 AC97_EXTCAPS);
821 }
822
823 if ((ac97_rdcd(codec, AC97_REG_POWER) & 2) == 0)
824 device_printf(codec->dev, "ac97 codec reports dac not ready\n");
825 snd_mtxunlock(codec->lock);
826 return 0;
827 }
828
829 struct ac97_info *
830 ac97_create(device_t dev, void *devinfo, kobj_class_t cls)
831 {
832 struct ac97_info *codec;
833 int i;
834
835 codec = malloc(sizeof(*codec), M_AC97, M_WAITOK | M_ZERO);
836 snprintf(codec->name, sizeof(codec->name), "%s:ac97",
837 device_get_nameunit(dev));
838 codec->lock = snd_mtxcreate(codec->name, "ac97 codec");
839 codec->methods = kobj_create(cls, M_AC97, M_WAITOK | M_ZERO);
840 codec->dev = dev;
841 codec->devinfo = devinfo;
842 codec->flags = 0;
843
844 if (resource_int_value(device_get_name(dev), device_get_unit(dev),
845 "eapdinv", &i) == 0 && i != 0)
846 codec->flags |= AC97_F_EAPD_INV;
847
848 if (resource_int_value(device_get_name(dev), device_get_unit(dev),
849 "softpcmvol", &i) == 0 && i != 0)
850 pcm_setflags(dev, pcm_getflags(dev) | SD_F_SOFTPCMVOL);
851
852 return codec;
853 }
854
855 void
856 ac97_destroy(struct ac97_info *codec)
857 {
858 snd_mtxlock(codec->lock);
859 if (codec->methods != NULL)
860 kobj_delete(codec->methods, M_AC97);
861 snd_mtxfree(codec->lock);
862 free(codec, M_AC97);
863 }
864
865 void
866 ac97_setflags(struct ac97_info *codec, u_int32_t val)
867 {
868 codec->flags = val;
869 }
870
871 u_int32_t
872 ac97_getflags(struct ac97_info *codec)
873 {
874 return codec->flags;
875 }
876
877 /* -------------------------------------------------------------------- */
878
879 static int
880 sysctl_hw_snd_ac97_eapd(SYSCTL_HANDLER_ARGS)
881 {
882 struct ac97_info *codec;
883 int ea, inv, err = 0;
884 u_int16_t val;
885
886 codec = oidp->oid_arg1;
887 if (codec == NULL || codec->id == 0 || codec->lock == NULL)
888 return EINVAL;
889 snd_mtxlock(codec->lock);
890 val = ac97_rdcd(codec, AC97_REG_POWER);
891 inv = (codec->flags & AC97_F_EAPD_INV) ? 0 : 1;
892 ea = (val >> 15) ^ inv;
893 snd_mtxunlock(codec->lock);
894 err = sysctl_handle_int(oidp, &ea, 0, req);
895 if (err == 0 && req->newptr != NULL) {
896 if (ea != 0 && ea != 1)
897 return EINVAL;
898 if (ea != ((val >> 15) ^ inv)) {
899 snd_mtxlock(codec->lock);
900 ac97_wrcd(codec, AC97_REG_POWER, val ^ 0x8000);
901 snd_mtxunlock(codec->lock);
902 }
903 }
904 return err;
905 }
906
907 static void
908 ac97_init_sysctl(struct ac97_info *codec)
909 {
910 u_int16_t orig, val;
911
912 if (codec == NULL || codec->dev == NULL)
913 return;
914 snd_mtxlock(codec->lock);
915 orig = ac97_rdcd(codec, AC97_REG_POWER);
916 ac97_wrcd(codec, AC97_REG_POWER, orig ^ 0x8000);
917 val = ac97_rdcd(codec, AC97_REG_POWER);
918 ac97_wrcd(codec, AC97_REG_POWER, orig);
919 snd_mtxunlock(codec->lock);
920 if ((val & 0x8000) == (orig & 0x8000))
921 return;
922 SYSCTL_ADD_PROC(device_get_sysctl_ctx(codec->dev),
923 SYSCTL_CHILDREN(device_get_sysctl_tree(codec->dev)),
924 OID_AUTO, "eapd",
925 CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_MPSAFE,
926 codec, sizeof(codec), sysctl_hw_snd_ac97_eapd,
927 "I", "AC97 External Amplifier");
928 }
929
930 static int
931 ac97mix_init(struct snd_mixer *m)
932 {
933 struct ac97_info *codec = mix_getdevinfo(m);
934 u_int32_t i, mask;
935
936 if (codec == NULL)
937 return -1;
938
939 if (ac97_initmixer(codec))
940 return -1;
941
942 switch (codec->id) {
943 case 0x41445374: /* AD1981B */
944 switch (codec->subvendor) {
945 case 0x02d91014:
946 /*
947 * IBM Thinkcentre:
948 *
949 * Tie "ogain" and "phout" to "vol" since its
950 * master volume is basically useless and can't
951 * control anything.
952 */
953 mask = 0;
954 if (codec->mix[SOUND_MIXER_OGAIN].enable)
955 mask |= SOUND_MASK_OGAIN;
956 if (codec->mix[SOUND_MIXER_PHONEOUT].enable)
957 mask |= SOUND_MASK_PHONEOUT;
958 if (codec->mix[SOUND_MIXER_VOLUME].enable)
959 mix_setparentchild(m, SOUND_MIXER_VOLUME,
960 mask);
961 else {
962 mix_setparentchild(m, SOUND_MIXER_VOLUME,
963 mask);
964 mix_setrealdev(m, SOUND_MIXER_VOLUME,
965 SOUND_MIXER_NONE);
966 }
967 break;
968 case 0x099c103c:
969 /*
970 * HP nx6110:
971 *
972 * By default, "vol" is controlling internal speakers
973 * (not a master volume!) and "ogain" is controlling
974 * headphone. Enable dummy "phout" so it can be
975 * remapped to internal speakers and virtualize
976 * "vol" to control both.
977 */
978 codec->mix[SOUND_MIXER_OGAIN].enable = 1;
979 codec->mix[SOUND_MIXER_PHONEOUT].enable = 1;
980 mix_setrealdev(m, SOUND_MIXER_PHONEOUT,
981 SOUND_MIXER_VOLUME);
982 mix_setrealdev(m, SOUND_MIXER_VOLUME,
983 SOUND_MIXER_NONE);
984 mix_setparentchild(m, SOUND_MIXER_VOLUME,
985 SOUND_MASK_OGAIN | SOUND_MASK_PHONEOUT);
986 break;
987 default:
988 break;
989 }
990 break;
991 case 0x434d4941: /* CMI9738 */
992 case 0x434d4961: /* CMI9739 */
993 case 0x434d4978: /* CMI9761 */
994 case 0x434d4982: /* CMI9761 */
995 case 0x434d4983: /* CMI9761 */
996 bzero(&codec->mix[SOUND_MIXER_PCM],
997 sizeof(codec->mix[SOUND_MIXER_PCM]));
998 pcm_setflags(codec->dev, pcm_getflags(codec->dev) |
999 SD_F_SOFTPCMVOL);
1000 /* XXX How about master volume ? */
1001 break;
1002 default:
1003 break;
1004 }
1005
1006 if (pcm_getflags(codec->dev) & SD_F_SOFTPCMVOL)
1007 ac97_wrcd(codec, AC97_MIX_PCM, 0);
1008 #if 0
1009 /* XXX For the sake of debugging purposes */
1010 mix_setparentchild(m, SOUND_MIXER_VOLUME,
1011 SOUND_MASK_PCM | SOUND_MASK_CD);
1012 mix_setrealdev(m, SOUND_MIXER_VOLUME, SOUND_MIXER_NONE);
1013 ac97_wrcd(codec, AC97_MIX_MASTER, 0);
1014 #endif
1015
1016 mask = 0;
1017 for (i = 0; i < AC97_MIXER_SIZE; i++)
1018 mask |= codec->mix[i].enable? 1 << i : 0;
1019 mix_setdevs(m, mask);
1020
1021 mask = 0;
1022 for (i = 0; i < AC97_MIXER_SIZE; i++)
1023 mask |= codec->mix[i].recidx? 1 << i : 0;
1024 mix_setrecdevs(m, mask);
1025
1026 ac97_init_sysctl(codec);
1027
1028 return 0;
1029 }
1030
1031 static int
1032 ac97mix_uninit(struct snd_mixer *m)
1033 {
1034 struct ac97_info *codec = mix_getdevinfo(m);
1035
1036 if (codec == NULL)
1037 return -1;
1038 /*
1039 if (ac97_uninitmixer(codec))
1040 return -1;
1041 */
1042 ac97_destroy(codec);
1043 return 0;
1044 }
1045
1046 static int
1047 ac97mix_reinit(struct snd_mixer *m)
1048 {
1049 struct ac97_info *codec = mix_getdevinfo(m);
1050
1051 if (codec == NULL)
1052 return -1;
1053 return ac97_reinitmixer(codec);
1054 }
1055
1056 static int
1057 ac97mix_set(struct snd_mixer *m, unsigned dev, unsigned left, unsigned right)
1058 {
1059 struct ac97_info *codec = mix_getdevinfo(m);
1060
1061 if (codec == NULL || dev >= AC97_MIXER_SIZE)
1062 return -1;
1063 return ac97_setmixer(codec, dev, left, right);
1064 }
1065
1066 static u_int32_t
1067 ac97mix_setrecsrc(struct snd_mixer *m, u_int32_t src)
1068 {
1069 int i;
1070 struct ac97_info *codec = mix_getdevinfo(m);
1071
1072 if (codec == NULL)
1073 return -1;
1074 for (i = 0; i < AC97_MIXER_SIZE; i++)
1075 if ((src & (1 << i)) != 0)
1076 break;
1077 return (ac97_setrecsrc(codec, i) == 0)? 1U << i : 0xffffffffU;
1078 }
1079
1080 static kobj_method_t ac97mixer_methods[] = {
1081 KOBJMETHOD(mixer_init, ac97mix_init),
1082 KOBJMETHOD(mixer_uninit, ac97mix_uninit),
1083 KOBJMETHOD(mixer_reinit, ac97mix_reinit),
1084 KOBJMETHOD(mixer_set, ac97mix_set),
1085 KOBJMETHOD(mixer_setrecsrc, ac97mix_setrecsrc),
1086 KOBJMETHOD_END
1087 };
1088 MIXER_DECLARE(ac97mixer);
1089
1090 /* -------------------------------------------------------------------- */
1091
1092 kobj_class_t
1093 ac97_getmixerclass(void)
1094 {
1095 return &ac97mixer_class;
1096 }
Cache object: 3ad1e5b0c5737db0f8642ba87efc82fa
|