2 * Copyright (c) 1999 Cameron Grant <cg@freebsd.org>
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
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.
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
27 #include <dev/sound/pcm/sound.h>
28 #include <dev/sound/pcm/ac97.h>
29 #include <dev/sound/pcm/ac97_patch.h>
31 #include <dev/pci/pcivar.h>
35 SND_DECLARE_FILE("$FreeBSD$");
37 MALLOC_DEFINE(M_AC97, "ac97", "ac97 codec");
39 struct ac97mixtable_entry {
40 int reg; /* 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 */
51 #define AC97_MIXER_SIZE SOUND_MIXER_NRDEVICES
59 unsigned count, caps, se, extcaps, extid, extstat, noext:1;
61 struct ac97mixtable_entry mix[AC97_MIXER_SIZE];
66 struct ac97_vendorid {
79 static const struct ac97mixtable_entry ac97mixtable_default[AC97_MIXER_SIZE] = {
80 /* [offset] reg bits of st mu re mk en */
81 [SOUND_MIXER_VOLUME] = { AC97_MIX_MASTER, 5, 0, 1, 1, 6, 0, 1 },
82 [SOUND_MIXER_OGAIN] = { AC97_MIX_AUXOUT, 5, 0, 1, 1, 0, 0, 0 },
83 [SOUND_MIXER_PHONEOUT] = { AC97_MIX_MONO, 5, 0, 0, 1, 7, 0, 0 },
84 [SOUND_MIXER_BASS] = { AC97_MIX_TONE, 4, 8, 0, 0, 0, 1, 0 },
85 [SOUND_MIXER_TREBLE] = { AC97_MIX_TONE, 4, 0, 0, 0, 0, 1, 0 },
86 [SOUND_MIXER_PCM] = { AC97_MIX_PCM, 5, 0, 1, 1, 0, 0, 1 },
87 [SOUND_MIXER_SPEAKER] = { AC97_MIX_BEEP, 4, 1, 0, 1, 0, 0, 0 },
88 [SOUND_MIXER_LINE] = { AC97_MIX_LINE, 5, 0, 1, 1, 5, 0, 1 },
89 [SOUND_MIXER_PHONEIN] = { AC97_MIX_PHONE, 5, 0, 0, 1, 8, 0, 0 },
90 [SOUND_MIXER_MIC] = { AC97_MIX_MIC, 5, 0, 0, 1, 1, 1, 1 },
91 /* use igain for the mic 20dB boost */
92 [SOUND_MIXER_IGAIN] = { -AC97_MIX_MIC, 1, 6, 0, 0, 0, 1, 1 },
93 [SOUND_MIXER_CD] = { AC97_MIX_CD, 5, 0, 1, 1, 2, 0, 1 },
94 [SOUND_MIXER_LINE1] = { AC97_MIX_AUX, 5, 0, 1, 1, 4, 0, 0 },
95 [SOUND_MIXER_VIDEO] = { AC97_MIX_VIDEO, 5, 0, 1, 1, 3, 0, 0 },
96 [SOUND_MIXER_RECLEV] = { -AC97_MIX_RGAIN, 4, 0, 1, 1, 0, 0, 1 }
99 static const struct ac97_vendorid ac97vendorid[] = {
100 { 0x41445300, "Analog Devices" },
101 { 0x414b4d00, "Asahi Kasei" },
102 { 0x414c4300, "Realtek" },
103 { 0x414c4700, "Avance Logic" },
104 { 0x43525900, "Cirrus Logic" },
105 { 0x434d4900, "C-Media Electronics" },
106 { 0x43585400, "Conexant" },
107 { 0x44543000, "Diamond Technology" },
108 { 0x454d4300, "eMicro" },
109 { 0x45838300, "ESS Technology" },
110 { 0x48525300, "Intersil" },
111 { 0x49434500, "ICEnsemble" },
112 { 0x49544500, "ITE, Inc." },
113 { 0x4e534300, "National Semiconductor" },
114 { 0x50534300, "Philips Semiconductor" },
115 { 0x83847600, "SigmaTel" },
116 { 0x53494c00, "Silicon Laboratories" },
117 { 0x54524100, "TriTech" },
118 { 0x54584e00, "Texas Instruments" },
119 { 0x56494100, "VIA Technologies" },
120 { 0x57454300, "Winbond" },
121 { 0x574d4c00, "Wolfson" },
122 { 0x594d4800, "Yamaha" },
124 * XXX This is a fluke, really! The real vendor
125 * should be SigmaTel, not this! This should be
128 { 0x01408300, "Creative" },
132 static struct ac97_codecid ac97codecid[] = {
133 { 0x41445303, 0x00, 0, "AD1819", 0 },
134 { 0x41445340, 0x00, 0, "AD1881", 0 },
135 { 0x41445348, 0x00, 0, "AD1881A", 0 },
136 { 0x41445360, 0x00, 0, "AD1885", 0 },
137 { 0x41445361, 0x00, 0, "AD1886", ad1886_patch },
138 { 0x41445362, 0x00, 0, "AD1887", 0 },
139 { 0x41445363, 0x00, 0, "AD1886A", 0 },
140 { 0x41445368, 0x00, 0, "AD1888", ad198x_patch },
141 { 0x41445370, 0x00, 0, "AD1980", ad198x_patch },
142 { 0x41445372, 0x00, 0, "AD1981A", 0 },
143 { 0x41445374, 0x00, 0, "AD1981B", ad1981b_patch },
144 { 0x41445375, 0x00, 0, "AD1985", ad198x_patch },
145 { 0x41445378, 0x00, 0, "AD1986", ad198x_patch },
146 { 0x414b4d00, 0x00, 1, "AK4540", 0 },
147 { 0x414b4d01, 0x00, 1, "AK4542", 0 },
148 { 0x414b4d02, 0x00, 1, "AK4543", 0 },
149 { 0x414b4d06, 0x00, 0, "AK4544A", 0 },
150 { 0x454b4d07, 0x00, 0, "AK4545", 0 },
151 { 0x414c4320, 0x0f, 0, "ALC100", 0 },
152 { 0x414c4730, 0x0f, 0, "ALC101", 0 },
153 { 0x414c4710, 0x0f, 0, "ALC200", 0 },
154 { 0x414c4740, 0x0f, 0, "ALC202", 0 },
155 { 0x414c4720, 0x0f, 0, "ALC650", 0 },
156 { 0x414c4752, 0x0f, 0, "ALC250", 0 },
157 { 0x414c4760, 0x0f, 0, "ALC655", alc655_patch },
158 { 0x414c4770, 0x0f, 0, "ALC203", 0 },
159 { 0x414c4780, 0x0f, 0, "ALC658", 0 },
160 { 0x414c4790, 0x0f, 0, "ALC850", 0 },
161 { 0x43525900, 0x07, 0, "CS4297", 0 },
162 { 0x43525910, 0x07, 0, "CS4297A", 0 },
163 { 0x43525920, 0x07, 0, "CS4294/98", 0 },
164 { 0x4352592d, 0x07, 0, "CS4294", 0 },
165 { 0x43525930, 0x07, 0, "CS4299", 0 },
166 { 0x43525940, 0x07, 0, "CS4201", 0 },
167 { 0x43525958, 0x07, 0, "CS4205", 0 },
168 { 0x43525960, 0x07, 0, "CS4291A", 0 },
169 { 0x434d4961, 0x00, 0, "CMI9739", cmi9739_patch },
170 { 0x434d4941, 0x00, 0, "CMI9738", 0 },
171 { 0x434d4978, 0x00, 0, "CMI9761", 0 },
172 { 0x434d4982, 0x00, 0, "CMI9761", 0 },
173 { 0x434d4983, 0x00, 0, "CMI9761", 0 },
174 { 0x43585421, 0x00, 0, "HSD11246", 0 },
175 { 0x43585428, 0x07, 0, "CX20468", 0 },
176 { 0x43585430, 0x00, 0, "CX20468-21", 0 },
177 { 0x44543000, 0x00, 0, "DT0398", 0 },
178 { 0x454d4323, 0x00, 0, "EM28023", 0 },
179 { 0x454d4328, 0x00, 0, "EM28028", 0 },
180 { 0x45838308, 0x00, 0, "ES1988", 0 }, /* Formerly ES1921(?) */
181 { 0x48525300, 0x00, 0, "HMP9701", 0 },
182 { 0x49434501, 0x00, 0, "ICE1230", 0 },
183 { 0x49434511, 0x00, 0, "ICE1232", 0 },
184 { 0x49434514, 0x00, 0, "ICE1232A", 0 },
185 { 0x49434551, 0x03, 0, "VT1616", 0 }, /* Via badged ICE */
186 { 0x49544520, 0x00, 0, "ITE2226E", 0 },
187 { 0x49544560, 0x07, 0, "ITE2646E", 0 }, /* XXX: patch needed */
188 { 0x4e534340, 0x00, 0, "LM4540", 0 }, /* Spec blank on revid */
189 { 0x4e534343, 0x00, 0, "LM4543", 0 }, /* Ditto */
190 { 0x4e534346, 0x00, 0, "LM4546A", 0 },
191 { 0x4e534348, 0x00, 0, "LM4548A", 0 },
192 { 0x4e534331, 0x00, 0, "LM4549", 0 },
193 { 0x4e534349, 0x00, 0, "LM4549A", 0 },
194 { 0x4e534350, 0x00, 0, "LM4550", 0 },
195 { 0x50534301, 0x00, 0, "UCB1510", 0 },
196 { 0x50534304, 0x00, 0, "UCB1400", 0 },
197 { 0x83847600, 0x00, 0, "STAC9700/83/84", 0 },
198 { 0x83847604, 0x00, 0, "STAC9701/03/04/05", 0 },
199 { 0x83847605, 0x00, 0, "STAC9704", 0 },
200 { 0x83847608, 0x00, 0, "STAC9708/11", 0 },
201 { 0x83847609, 0x00, 0, "STAC9721/23", 0 },
202 { 0x83847644, 0x00, 0, "STAC9744/45", 0 },
203 { 0x83847650, 0x00, 0, "STAC9750/51", 0 },
204 { 0x83847652, 0x00, 0, "STAC9752/53", 0 },
205 { 0x83847656, 0x00, 0, "STAC9756/57", 0 },
206 { 0x83847658, 0x00, 0, "STAC9758/59", 0 },
207 { 0x83847660, 0x00, 0, "STAC9760/61", 0 }, /* Extrapolated */
208 { 0x83847662, 0x00, 0, "STAC9762/63", 0 }, /* Extrapolated */
209 { 0x83847666, 0x00, 0, "STAC9766/67", 0 },
210 { 0x53494c22, 0x00, 0, "Si3036", 0 },
211 { 0x53494c23, 0x00, 0, "Si3038", 0 },
212 { 0x54524103, 0x00, 0, "TR28023", 0 }, /* Extrapolated */
213 { 0x54524106, 0x00, 0, "TR28026", 0 },
214 { 0x54524108, 0x00, 0, "TR28028", 0 },
215 { 0x54524123, 0x00, 0, "TR28602", 0 },
216 { 0x54524e03, 0x07, 0, "TLV320AIC27", 0 },
217 { 0x54584e20, 0x00, 0, "TLC320AD90", 0 },
218 { 0x56494161, 0x00, 0, "VIA1612A", 0 },
219 { 0x56494170, 0x00, 0, "VIA1617A", 0 },
220 { 0x574d4c00, 0x00, 0, "WM9701A", 0 },
221 { 0x574d4c03, 0x00, 0, "WM9703/4/7/8", 0 },
222 { 0x574d4c04, 0x00, 0, "WM9704Q", 0 },
223 { 0x574d4c05, 0x00, 0, "WM9705/10", 0 },
224 { 0x574d4d09, 0x00, 0, "WM9709", 0 },
225 { 0x574d4c12, 0x00, 0, "WM9711/12", 0 }, /* XXX: patch needed */
226 { 0x57454301, 0x00, 0, "W83971D", 0 },
227 { 0x594d4800, 0x00, 0, "YMF743", 0 },
228 { 0x594d4802, 0x00, 0, "YMF752", 0 },
229 { 0x594d4803, 0x00, 0, "YMF753", 0 },
231 * XXX This is a fluke, really! The real codec
232 * should be STAC9704, not this! This should be
235 { 0x01408384, 0x00, 0, "EV1938", 0 },
239 static char *ac97enhancement[] = {
240 "no 3D Stereo Enhancement",
241 "Analog Devices Phat Stereo",
242 "Creative Stereo Enhancement",
243 "National Semi 3D Stereo Enhancement",
245 "BBE 3D Stereo Enhancement",
246 "Crystal Semi 3D Stereo Enhancement",
248 "Spatializer 3D Stereo Enhancement",
249 "SRS 3D Stereo Enhancement",
250 "Platform Tech 3D Stereo Enhancement",
252 "Aureal Stereo Enhancement",
253 "Aztech 3D Enhancement",
254 "Binaura 3D Audio Enhancement",
255 "ESS Technology Stereo Enhancement",
256 "Harman International VMAx",
257 "Nvidea 3D Stereo Enhancement",
258 "Philips Incredible Sound",
259 "Texas Instruments 3D Stereo Enhancement",
260 "VLSI Technology 3D Stereo Enhancement",
261 "TriTech 3D Stereo Enhancement",
262 "Realtek 3D Stereo Enhancement",
263 "Samsung 3D Stereo Enhancement",
264 "Wolfson Microelectronics 3D Enhancement",
265 "Delta Integration 3D Enhancement",
266 "SigmaTel 3D Enhancement",
268 "Rockwell 3D Stereo Enhancement",
274 static char *ac97feature[] = {
287 static char *ac97extfeature[] = {
305 ac97_rdcd(struct ac97_info *codec, int reg)
307 if (codec->flags & AC97_F_RDCD_BUG) {
308 u_int16_t i[2], j = 100;
310 i[0] = AC97_READ(codec->methods, codec->devinfo, reg);
311 i[1] = AC97_READ(codec->methods, codec->devinfo, reg);
312 while (i[0] != i[1] && j)
313 i[j-- & 1] = AC97_READ(codec->methods, codec->devinfo, reg);
316 device_printf(codec->dev, "%s(): Inconsistent register value at"
317 " 0x%08x (retry: %d)\n", __func__, reg, 100 - j);
322 return AC97_READ(codec->methods, codec->devinfo, reg);
326 ac97_wrcd(struct ac97_info *codec, int reg, u_int16_t val)
328 AC97_WRITE(codec->methods, codec->devinfo, reg, val);
332 ac97_reset(struct ac97_info *codec)
335 ac97_wrcd(codec, AC97_REG_RESET, 0);
336 for (i = 0; i < 500; i++) {
337 ps = ac97_rdcd(codec, AC97_REG_POWER) & AC97_POWER_STATUS;
338 if (ps == AC97_POWER_STATUS)
342 device_printf(codec->dev, "AC97 reset timed out.\n");
346 ac97_setrate(struct ac97_info *codec, int which, int rate)
351 case AC97_REGEXT_FDACRATE:
352 case AC97_REGEXT_SDACRATE:
353 case AC97_REGEXT_LDACRATE:
354 case AC97_REGEXT_LADCRATE:
355 case AC97_REGEXT_MADCRATE:
362 snd_mtxlock(codec->lock);
365 if (codec->extstat & AC97_EXTCAP_DRA)
367 ac97_wrcd(codec, which, v);
369 v = ac97_rdcd(codec, which);
370 if (codec->extstat & AC97_EXTCAP_DRA)
372 snd_mtxunlock(codec->lock);
377 ac97_setextmode(struct ac97_info *codec, u_int16_t mode)
379 mode &= AC97_EXTCAPS;
380 if ((mode & ~codec->extcaps) != 0) {
381 device_printf(codec->dev, "ac97 invalid mode set 0x%04x\n",
385 snd_mtxlock(codec->lock);
386 ac97_wrcd(codec, AC97_REGEXT_STAT, mode);
387 codec->extstat = ac97_rdcd(codec, AC97_REGEXT_STAT) & AC97_EXTCAPS;
388 snd_mtxunlock(codec->lock);
389 return (mode == codec->extstat)? 0 : -1;
393 ac97_getextmode(struct ac97_info *codec)
395 return codec->extstat;
399 ac97_getextcaps(struct ac97_info *codec)
401 return codec->extcaps;
405 ac97_getcaps(struct ac97_info *codec)
411 ac97_getsubvendor(struct ac97_info *codec)
413 return codec->subvendor;
417 ac97_setrecsrc(struct ac97_info *codec, int channel)
419 struct ac97mixtable_entry *e = &codec->mix[channel];
422 int val = e->recidx - 1;
424 snd_mtxlock(codec->lock);
425 ac97_wrcd(codec, AC97_REG_RECSEL, val);
426 snd_mtxunlock(codec->lock);
433 ac97_setmixer(struct ac97_info *codec, unsigned channel, unsigned left, unsigned right)
435 struct ac97mixtable_entry *e = &codec->mix[channel];
437 if (e->reg && e->enable && e->bits) {
438 int mask, max, val, reg;
440 reg = (e->reg >= 0) ? e->reg : -e->reg; /* AC97 register */
441 max = (1 << e->bits) - 1; /* actual range */
442 mask = (max << 8) | max; /* bits of interest */
448 * Invert the range if the polarity requires so,
449 * then scale to 0..max-1 to compute the value to
450 * write into the codec, and scale back to 0..100
451 * for the return value.
458 left = (left * max) / 100;
459 right = (right * max) / 100;
461 val = (left << 8) | right;
463 left = (left * 100) / max;
464 right = (right * 100) / max;
472 * For mono controls, trim val and mask, also taking
473 * care of e->ofs (offset of control field).
478 mask = (max << e->ofs);
482 * If we have a mute bit, add it to the mask and
483 * update val and set mute if both channels require a
488 if (left == 0 && right == 0)
493 * If the mask bit is set, do not alter the other bits.
495 snd_mtxlock(codec->lock);
497 int cur = ac97_rdcd(codec, reg);
498 val |= cur & ~(mask);
500 ac97_wrcd(codec, reg, val);
501 snd_mtxunlock(codec->lock);
502 return left | (right << 8);
505 printf("ac97_setmixer: reg=%d, bits=%d, enable=%d\n", e->reg, e->bits, e->enable);
512 ac97_fix_auxout(struct ac97_info *codec)
517 * By default, The ac97 aux_out register (0x04) corresponds to OSS's
520 * We first check whether aux_out is a valid register. If not
521 * we may not want to keep ogain.
523 keep_ogain = ac97_rdcd(codec, AC97_MIX_AUXOUT) & 0x8000;
526 * Determine what AUX_OUT really means, it can be:
530 * 3. True line level out (effectively master volume).
532 * See Sections 5.2.1 and 5.27 for AUX_OUT Options in AC97r2.{2,3}.
534 if (codec->extcaps & AC97_EXTCAP_SDAC &&
535 ac97_rdcd(codec, AC97_MIXEXT_SURROUND) == 0x8080) {
536 codec->mix[SOUND_MIXER_OGAIN].reg = AC97_MIXEXT_SURROUND;
540 if (keep_ogain == 0) {
541 bzero(&codec->mix[SOUND_MIXER_OGAIN],
542 sizeof(codec->mix[SOUND_MIXER_OGAIN]));
547 ac97_fix_tone(struct ac97_info *codec)
550 * YMF chips does not indicate tone and 3D enhancement capability
551 * in the AC97_REG_RESET register.
554 case 0x594d4800: /* YMF743 */
555 case 0x594d4803: /* YMF753 */
556 codec->caps |= AC97_CAP_TONE;
559 case 0x594d4802: /* YMF752 */
566 /* Hide treble and bass if they don't exist */
567 if ((codec->caps & AC97_CAP_TONE) == 0) {
568 bzero(&codec->mix[SOUND_MIXER_BASS],
569 sizeof(codec->mix[SOUND_MIXER_BASS]));
570 bzero(&codec->mix[SOUND_MIXER_TREBLE],
571 sizeof(codec->mix[SOUND_MIXER_TREBLE]));
576 ac97_hw_desc(u_int32_t id, const char* vname, const char* cname, char* buf)
579 sprintf(buf, "Unknown AC97 Codec (id = 0x%08x)", id);
583 if (vname == NULL) vname = "Unknown";
586 sprintf(buf, "%s %s AC97 Codec (id = 0x%08x)", vname, cname, id);
588 sprintf(buf, "%s %s AC97 Codec", vname, cname);
594 ac97_initmixer(struct ac97_info *codec)
596 ac97_patch codec_patch;
597 const char *cname, *vname;
599 u_int8_t model, step;
600 unsigned i, j, k, bit, old;
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);
612 ac97_wrcd(codec, AC97_REG_POWER, (codec->flags & AC97_F_EAPD_INV)? 0x8000 : 0x0000);
614 ac97_wrcd(codec, AC97_REG_POWER, (codec->flags & AC97_F_EAPD_INV)? 0x8000 : 0x0000);
616 i = ac97_rdcd(codec, AC97_REG_RESET);
617 j = ac97_rdcd(codec, AC97_REG_RESET);
618 k = ac97_rdcd(codec, AC97_REG_RESET);
620 * Let see if this codec can return consistent value.
621 * If not, turn on aggressive read workaround
622 * (STAC9704 comes in mind).
624 if (i != j || j != k) {
625 codec->flags |= AC97_F_RDCD_BUG;
626 i = ac97_rdcd(codec, AC97_REG_RESET);
628 codec->caps = i & 0x03ff;
629 codec->se = (i & 0x7c00) >> 10;
631 id = (ac97_rdcd(codec, AC97_REG_ID1) << 16) | ac97_rdcd(codec, AC97_REG_ID2);
632 if (id == 0 || id == 0xffffffff) {
633 device_printf(codec->dev, "ac97 codec invalid or not present (id == %x)\n", id);
634 snd_mtxunlock(codec->lock);
639 codec->subvendor = (u_int32_t)pci_get_subdevice(codec->dev) << 16;
640 codec->subvendor |= (u_int32_t)pci_get_subvendor(codec->dev) &
647 for (i = 0; ac97codecid[i].id; i++) {
648 u_int32_t modelmask = 0xffffffff ^ ac97codecid[i].stepmask;
649 if ((ac97codecid[i].id & modelmask) == (id & modelmask)) {
650 codec->noext = ac97codecid[i].noext;
651 codec_patch = ac97codecid[i].patch;
652 cname = ac97codecid[i].name;
653 model = (id & modelmask) & 0xff;
654 step = (id & ~modelmask) & 0xff;
660 for (i = 0; ac97vendorid[i].id; i++) {
661 if (ac97vendorid[i].id == (id & 0xffffff00)) {
662 vname = ac97vendorid[i].name;
671 i = ac97_rdcd(codec, AC97_REGEXT_ID);
673 codec->extcaps = i & 0x3fff;
674 codec->extid = (i & 0xc000) >> 14;
675 codec->extstat = ac97_rdcd(codec, AC97_REGEXT_STAT) & AC97_EXTCAPS;
679 for (i = 0; i < AC97_MIXER_SIZE; i++) {
680 codec->mix[i] = ac97mixtable_default[i];
682 ac97_fix_auxout(codec);
683 ac97_fix_tone(codec);
687 for (i = 0; i < AC97_MIXER_SIZE; i++) {
688 k = codec->noext? codec->mix[i].enable : 1;
689 reg = codec->mix[i].reg;
693 j = old = ac97_rdcd(codec, reg);
695 * Test for mute bit (except for AC97_MIX_TONE,
696 * where we simply assume it as available).
698 if (codec->mix[i].mute) {
699 ac97_wrcd(codec, reg, j | 0x8000);
700 j = ac97_rdcd(codec, reg);
705 * Test whether the control width should be
706 * 4, 5 or 6 bit. For 5bit register, we should
707 * test it whether it's really 5 or 6bit. Leave
708 * 4bit register alone, because sometimes an
709 * attempt to write past 4th bit may cause
710 * incorrect result especially for AC97_MIX_BEEP
713 bit = codec->mix[i].bits;
716 j = ((1 << bit) - 1) << codec->mix[i].ofs;
717 ac97_wrcd(codec, reg,
718 j | (codec->mix[i].mute ? 0x8000 : 0));
719 k = ac97_rdcd(codec, reg) & j;
720 k >>= codec->mix[i].ofs;
721 if (reg == AC97_MIX_TONE &&
722 ((k & 0x0001) == 0x0000))
724 for (j = 0; k >> j; j++)
728 device_printf(codec->dev, "%2d: [ac97_rdcd() = %d] [Testbit = %d] %d -> %d\n",
729 i, k, bit, codec->mix[i].bits, j);
731 codec->mix[i].enable = 1;
732 codec->mix[i].bits = j;
733 } else if (reg == AC97_MIX_BEEP) {
735 * Few codec such as CX20468-21 does
736 * have this control register, although
737 * the only usable part is the mute bit.
739 codec->mix[i].enable = 1;
741 codec->mix[i].enable = 0;
743 codec->mix[i].enable = 0;
744 ac97_wrcd(codec, reg, old);
747 printf("mixch %d, en=%d, b=%d\n", i, codec->mix[i].enable, codec->mix[i].bits);
751 device_printf(codec->dev, "<%s>\n",
752 ac97_hw_desc(codec->id, vname, cname, desc));
755 if (codec->flags & AC97_F_RDCD_BUG)
756 device_printf(codec->dev, "Buggy AC97 Codec: aggressive ac97_rdcd() workaround enabled\n");
757 device_printf(codec->dev, "Codec features ");
758 for (i = j = 0; i < 10; i++)
759 if (codec->caps & (1 << i))
760 printf("%s%s", j++? ", " : "", ac97feature[i]);
761 printf("%s%d bit master volume", j++? ", " : "", codec->mix[SOUND_MIXER_VOLUME].bits);
762 printf("%s%s\n", j? ", " : "", ac97enhancement[codec->se]);
764 if (codec->extcaps != 0 || codec->extid) {
765 device_printf(codec->dev, "%s codec",
766 codec->extid? "Secondary" : "Primary");
768 printf(" extended features ");
769 for (i = j = 0; i < 14; i++)
770 if (codec->extcaps & (1 << i))
771 printf("%s%s", j++? ", " : "", ac97extfeature[i]);
777 while ((ac97_rdcd(codec, AC97_REG_POWER) & 2) == 0) {
779 device_printf(codec->dev, "ac97 codec reports dac not ready\n");
785 device_printf(codec->dev, "ac97 codec dac ready count: %d\n", i);
786 snd_mtxunlock(codec->lock);
791 ac97_reinitmixer(struct ac97_info *codec)
793 snd_mtxlock(codec->lock);
794 codec->count = AC97_INIT(codec->methods, codec->devinfo);
795 if (codec->count == 0) {
796 device_printf(codec->dev, "ac97 codec init failed\n");
797 snd_mtxunlock(codec->lock);
801 ac97_wrcd(codec, AC97_REG_POWER, (codec->flags & AC97_F_EAPD_INV)? 0x8000 : 0x0000);
803 ac97_wrcd(codec, AC97_REG_POWER, (codec->flags & AC97_F_EAPD_INV)? 0x8000 : 0x0000);
806 ac97_wrcd(codec, AC97_REGEXT_STAT, codec->extstat);
807 if ((ac97_rdcd(codec, AC97_REGEXT_STAT) & AC97_EXTCAPS)
809 device_printf(codec->dev, "ac97 codec failed to reset extended mode (%x, got %x)\n",
811 ac97_rdcd(codec, AC97_REGEXT_STAT) &
815 if ((ac97_rdcd(codec, AC97_REG_POWER) & 2) == 0)
816 device_printf(codec->dev, "ac97 codec reports dac not ready\n");
817 snd_mtxunlock(codec->lock);
822 ac97_create(device_t dev, void *devinfo, kobj_class_t cls)
824 struct ac97_info *codec;
827 codec = malloc(sizeof(*codec), M_AC97, M_WAITOK | M_ZERO);
828 snprintf(codec->name, sizeof(codec->name), "%s:ac97",
829 device_get_nameunit(dev));
830 codec->lock = snd_mtxcreate(codec->name, "ac97 codec");
831 codec->methods = kobj_create(cls, M_AC97, M_WAITOK | M_ZERO);
833 codec->devinfo = devinfo;
835 if (resource_int_value(device_get_name(dev), device_get_unit(dev),
836 "eapdinv", &eapdinv) == 0) {
838 codec->flags |= AC97_F_EAPD_INV;
844 ac97_destroy(struct ac97_info *codec)
846 snd_mtxlock(codec->lock);
847 if (codec->methods != NULL)
848 kobj_delete(codec->methods, M_AC97);
849 snd_mtxfree(codec->lock);
854 ac97_setflags(struct ac97_info *codec, u_int32_t val)
860 ac97_getflags(struct ac97_info *codec)
865 /* -------------------------------------------------------------------- */
869 sysctl_hw_snd_ac97_eapd(SYSCTL_HANDLER_ARGS)
871 struct ac97_info *codec;
872 int ea, inv, err = 0;
875 codec = oidp->oid_arg1;
876 if (codec == NULL || codec->id == 0 || codec->lock == NULL)
878 snd_mtxlock(codec->lock);
879 val = ac97_rdcd(codec, AC97_REG_POWER);
880 inv = (codec->flags & AC97_F_EAPD_INV) ? 0 : 1;
881 ea = (val >> 15) ^ inv;
882 snd_mtxunlock(codec->lock);
883 err = sysctl_handle_int(oidp, &ea, 0, req);
884 if (err == 0 && req->newptr != NULL) {
885 if (ea != 0 && ea != 1)
887 if (ea != ((val >> 15) ^ inv)) {
888 snd_mtxlock(codec->lock);
889 ac97_wrcd(codec, AC97_REG_POWER, val ^ 0x8000);
890 snd_mtxunlock(codec->lock);
898 ac97_init_sysctl(struct ac97_info *codec)
903 if (codec == NULL || codec->dev == NULL)
905 snd_mtxlock(codec->lock);
906 orig = ac97_rdcd(codec, AC97_REG_POWER);
907 ac97_wrcd(codec, AC97_REG_POWER, orig ^ 0x8000);
908 val = ac97_rdcd(codec, AC97_REG_POWER);
909 ac97_wrcd(codec, AC97_REG_POWER, orig);
910 snd_mtxunlock(codec->lock);
911 if ((val & 0x8000) == (orig & 0x8000))
913 SYSCTL_ADD_PROC(device_get_sysctl_ctx(codec->dev),
914 SYSCTL_CHILDREN(device_get_sysctl_tree(codec->dev)),
915 OID_AUTO, "eapd", CTLTYPE_INT | CTLFLAG_RW,
916 codec, sizeof(codec), sysctl_hw_snd_ac97_eapd,
917 "I", "AC97 External Amplifier");
922 ac97mix_init(struct snd_mixer *m)
924 struct ac97_info *codec = mix_getdevinfo(m);
930 if (ac97_initmixer(codec))
934 case 0x41445374: /* AD1981B */
935 switch (codec->subvendor) {
940 * Tie "ogain" and "phout" to "vol" since its
941 * master volume is basically useless and can't
945 if (codec->mix[SOUND_MIXER_OGAIN].enable)
946 mask |= SOUND_MASK_OGAIN;
947 if (codec->mix[SOUND_MIXER_PHONEOUT].enable)
948 mask |= SOUND_MASK_PHONEOUT;
949 if (codec->mix[SOUND_MIXER_VOLUME].enable)
950 mix_setparentchild(m, SOUND_MIXER_VOLUME,
953 mix_setparentchild(m, SOUND_MIXER_VOLUME,
955 mix_setrealdev(m, SOUND_MIXER_VOLUME,
963 * By default, "vol" is controlling internal speakers
964 * (not a master volume!) and "ogain" is controlling
965 * headphone. Enable dummy "phout" so it can be
966 * remapped to internal speakers and virtualize
967 * "vol" to control both.
969 codec->mix[SOUND_MIXER_OGAIN].enable = 1;
970 codec->mix[SOUND_MIXER_PHONEOUT].enable = 1;
971 mix_setrealdev(m, SOUND_MIXER_PHONEOUT,
973 mix_setrealdev(m, SOUND_MIXER_VOLUME,
975 mix_setparentchild(m, SOUND_MIXER_VOLUME,
976 SOUND_MASK_OGAIN | SOUND_MASK_PHONEOUT);
982 case 0x434d4941: /* CMI9738 */
983 case 0x434d4961: /* CMI9739 */
984 case 0x434d4978: /* CMI9761 */
985 case 0x434d4982: /* CMI9761 */
986 case 0x434d4983: /* CMI9761 */
987 ac97_wrcd(codec, AC97_MIX_PCM, 0);
988 bzero(&codec->mix[SOUND_MIXER_PCM],
989 sizeof(codec->mix[SOUND_MIXER_PCM]));
990 pcm_setflags(codec->dev, pcm_getflags(codec->dev) |
992 /* XXX How about master volume ? */
999 /* XXX For the sake of debugging purposes */
1000 mix_setparentchild(m, SOUND_MIXER_VOLUME,
1001 SOUND_MASK_PCM | SOUND_MASK_CD);
1002 mix_setrealdev(m, SOUND_MIXER_VOLUME, SOUND_MIXER_NONE);
1003 ac97_wrcd(codec, AC97_MIX_MASTER, 0);
1007 for (i = 0; i < AC97_MIXER_SIZE; i++)
1008 mask |= codec->mix[i].enable? 1 << i : 0;
1009 mix_setdevs(m, mask);
1012 for (i = 0; i < AC97_MIXER_SIZE; i++)
1013 mask |= codec->mix[i].recidx? 1 << i : 0;
1014 mix_setrecdevs(m, mask);
1016 ac97_init_sysctl(codec);
1022 ac97mix_uninit(struct snd_mixer *m)
1024 struct ac97_info *codec = mix_getdevinfo(m);
1029 if (ac97_uninitmixer(codec))
1032 ac97_destroy(codec);
1037 ac97mix_reinit(struct snd_mixer *m)
1039 struct ac97_info *codec = mix_getdevinfo(m);
1043 return ac97_reinitmixer(codec);
1047 ac97mix_set(struct snd_mixer *m, unsigned dev, unsigned left, unsigned right)
1049 struct ac97_info *codec = mix_getdevinfo(m);
1051 if (codec == NULL || dev >= AC97_MIXER_SIZE)
1053 return ac97_setmixer(codec, dev, left, right);
1057 ac97mix_setrecsrc(struct snd_mixer *m, u_int32_t src)
1060 struct ac97_info *codec = mix_getdevinfo(m);
1064 for (i = 0; i < AC97_MIXER_SIZE; i++)
1065 if ((src & (1 << i)) != 0)
1067 return (ac97_setrecsrc(codec, i) == 0)? 1 << i : -1;
1070 static kobj_method_t ac97mixer_methods[] = {
1071 KOBJMETHOD(mixer_init, ac97mix_init),
1072 KOBJMETHOD(mixer_uninit, ac97mix_uninit),
1073 KOBJMETHOD(mixer_reinit, ac97mix_reinit),
1074 KOBJMETHOD(mixer_set, ac97mix_set),
1075 KOBJMETHOD(mixer_setrecsrc, ac97mix_setrecsrc),
1078 MIXER_DECLARE(ac97mixer);
1080 /* -------------------------------------------------------------------- */
1083 ac97_getmixerclass(void)
1085 return &ac97mixer_class;