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