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