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
26 * $FreeBSD: src/sys/dev/sound/pcm/ac97.c,v 1.53.2.6 2007/10/31 04:00:07 ariff Exp $
27 * $DragonFly: src/sys/dev/sound/pcm/ac97.c,v 1.26 2007/11/30 07:59:56 hasso Exp $
30 #include <dev/sound/pcm/sound.h>
31 #include <dev/sound/pcm/ac97.h>
32 #include <dev/sound/pcm/ac97_patch.h>
34 #include <bus/pci/pcivar.h>
38 SND_DECLARE_FILE("$DragonFly: src/sys/dev/sound/pcm/ac97.c,v 1.26 2007/11/30 07:59:56 hasso Exp $");
40 MALLOC_DEFINE(M_AC97, "ac97", "ac97 codec");
42 struct ac97mixtable_entry {
43 int reg:8; /* register index */
44 /* reg < 0 if inverted polarity */
45 unsigned bits:4; /* width of control field */
46 unsigned ofs:4; /* offset (only if stereo=0) */
47 unsigned stereo:1; /* set for stereo controls */
48 unsigned mute:1; /* bit15 is MUTE */
49 unsigned recidx:4; /* index in rec mux */
50 unsigned mask:1; /* use only masked bits */
51 unsigned enable:1; /* entry is enabled */
54 #define AC97_NAMELEN 16
61 unsigned count, caps, se, extcaps, extid, extstat, noext:1;
63 struct ac97mixtable_entry mix[32];
64 char name[AC97_NAMELEN];
68 struct ac97_vendorid {
81 static const struct ac97mixtable_entry ac97mixtable_default[32] = {
82 /* [offset] reg bits of st mu re mk en */
83 [SOUND_MIXER_VOLUME] = { AC97_MIX_MASTER, 5, 0, 1, 1, 6, 0, 1 },
84 [SOUND_MIXER_OGAIN] = { AC97_MIX_AUXOUT, 5, 0, 1, 1, 0, 0, 0 },
85 [SOUND_MIXER_PHONEOUT] = { AC97_MIX_MONO, 5, 0, 0, 1, 7, 0, 0 },
86 [SOUND_MIXER_BASS] = { AC97_MIX_TONE, 4, 8, 0, 0, 0, 1, 0 },
87 [SOUND_MIXER_TREBLE] = { AC97_MIX_TONE, 4, 0, 0, 0, 0, 1, 0 },
88 [SOUND_MIXER_PCM] = { AC97_MIX_PCM, 5, 0, 1, 1, 0, 0, 1 },
89 [SOUND_MIXER_SPEAKER] = { AC97_MIX_BEEP, 4, 1, 0, 1, 0, 0, 0 },
90 [SOUND_MIXER_LINE] = { AC97_MIX_LINE, 5, 0, 1, 1, 5, 0, 1 },
91 [SOUND_MIXER_PHONEIN] = { AC97_MIX_PHONE, 5, 0, 0, 1, 8, 0, 0 },
92 [SOUND_MIXER_MIC] = { AC97_MIX_MIC, 5, 0, 0, 1, 1, 1, 1 },
93 /* use igain for the mic 20dB boost */
94 [SOUND_MIXER_IGAIN] = { -AC97_MIX_MIC, 1, 6, 0, 0, 0, 1, 1 },
95 [SOUND_MIXER_CD] = { AC97_MIX_CD, 5, 0, 1, 1, 2, 0, 1 },
96 [SOUND_MIXER_LINE1] = { AC97_MIX_AUX, 5, 0, 1, 1, 4, 0, 0 },
97 [SOUND_MIXER_VIDEO] = { AC97_MIX_VIDEO, 5, 0, 1, 1, 3, 0, 0 },
98 [SOUND_MIXER_RECLEV] = { -AC97_MIX_RGAIN, 4, 0, 1, 1, 0, 0, 1 }
101 static const struct ac97_vendorid ac97vendorid[] = {
102 { 0x41445300, "Analog Devices" },
103 { 0x414b4d00, "Asahi Kasei" },
104 { 0x414c4300, "Realtek" },
105 { 0x414c4700, "Avance Logic" },
106 { 0x43525900, "Cirrus Logic" },
107 { 0x434d4900, "C-Media Electronics" },
108 { 0x43585400, "Conexant" },
109 { 0x44543000, "Diamond Technology" },
110 { 0x454d4300, "eMicro" },
111 { 0x45838300, "ESS Technology" },
112 { 0x48525300, "Intersil" },
113 { 0x49434500, "ICEnsemble" },
114 { 0x49544500, "ITE, Inc." },
115 { 0x4e534300, "National Semiconductor" },
116 { 0x50534300, "Philips Semiconductor" },
117 { 0x83847600, "SigmaTel" },
118 { 0x53494c00, "Silicon Laboratories" },
119 { 0x54524100, "TriTech" },
120 { 0x54584e00, "Texas Instruments" },
121 { 0x56494100, "VIA Technologies" },
122 { 0x57454300, "Winbond" },
123 { 0x574d4c00, "Wolfson" },
124 { 0x594d4800, "Yamaha" },
126 * XXX This is a fluke, really! The real vendor
127 * should be SigmaTel, not this! This should be
130 { 0x01408300, "Creative" },
134 static struct ac97_codecid ac97codecid[] = {
135 { 0x41445303, 0x00, 0, "AD1819", 0 },
136 { 0x41445340, 0x00, 0, "AD1881", 0 },
137 { 0x41445348, 0x00, 0, "AD1881A", 0 },
138 { 0x41445360, 0x00, 0, "AD1885", 0 },
139 { 0x41445361, 0x00, 0, "AD1886", ad1886_patch },
140 { 0x41445362, 0x00, 0, "AD1887", 0 },
141 { 0x41445363, 0x00, 0, "AD1886A", 0 },
142 { 0x41445368, 0x00, 0, "AD1888", ad198x_patch },
143 { 0x41445370, 0x00, 0, "AD1980", ad198x_patch },
144 { 0x41445372, 0x00, 0, "AD1981A", 0 },
145 { 0x41445374, 0x00, 0, "AD1981B", ad1981b_patch },
146 { 0x41445375, 0x00, 0, "AD1985", ad198x_patch },
147 { 0x41445378, 0x00, 0, "AD1986", ad198x_patch },
148 { 0x414b4d00, 0x00, 1, "AK4540", 0 },
149 { 0x414b4d01, 0x00, 1, "AK4542", 0 },
150 { 0x414b4d02, 0x00, 1, "AK4543", 0 },
151 { 0x414b4d06, 0x00, 0, "AK4544A", 0 },
152 { 0x454b4d07, 0x00, 0, "AK4545", 0 },
153 { 0x414c4320, 0x0f, 0, "ALC100", 0 },
154 { 0x414c4730, 0x0f, 0, "ALC101", 0 },
155 { 0x414c4710, 0x0f, 0, "ALC200", 0 },
156 { 0x414c4740, 0x0f, 0, "ALC202", 0 },
157 { 0x414c4720, 0x0f, 0, "ALC650", 0 },
158 { 0x414c4752, 0x0f, 0, "ALC250", 0 },
159 { 0x414c4760, 0x0f, 0, "ALC655", alc655_patch },
160 { 0x414c4770, 0x0f, 0, "ALC203", 0 },
161 { 0x414c4780, 0x0f, 0, "ALC658", 0 },
162 { 0x414c4790, 0x0f, 0, "ALC850", 0 },
163 { 0x43525900, 0x07, 0, "CS4297", 0 },
164 { 0x43525910, 0x07, 0, "CS4297A", 0 },
165 { 0x43525920, 0x07, 0, "CS4294/98", 0 },
166 { 0x4352592d, 0x07, 0, "CS4294", 0 },
167 { 0x43525930, 0x07, 0, "CS4299", 0 },
168 { 0x43525940, 0x07, 0, "CS4201", 0 },
169 { 0x43525958, 0x07, 0, "CS4205", 0 },
170 { 0x43525960, 0x07, 0, "CS4291A", 0 },
171 { 0x434d4961, 0x00, 0, "CMI9739", cmi9739_patch },
172 { 0x434d4941, 0x00, 0, "CMI9738", 0 },
173 { 0x434d4978, 0x00, 0, "CMI9761", 0 },
174 { 0x434d4982, 0x00, 0, "CMI9761", 0 },
175 { 0x434d4983, 0x00, 0, "CMI9761", 0 },
176 { 0x43585421, 0x00, 0, "HSD11246", 0 },
177 { 0x43585428, 0x07, 0, "CX20468", 0 },
178 { 0x43585430, 0x00, 0, "CX20468-21", 0 },
179 { 0x44543000, 0x00, 0, "DT0398", 0 },
180 { 0x454d4323, 0x00, 0, "EM28023", 0 },
181 { 0x454d4328, 0x00, 0, "EM28028", 0 },
182 { 0x45838308, 0x00, 0, "ES1988", 0 }, /* Formerly ES1921(?) */
183 { 0x48525300, 0x00, 0, "HMP9701", 0 },
184 { 0x49434501, 0x00, 0, "ICE1230", 0 },
185 { 0x49434511, 0x00, 0, "ICE1232", 0 },
186 { 0x49434514, 0x00, 0, "ICE1232A", 0 },
187 { 0x49434551, 0x03, 0, "VT1616", 0 }, /* Via badged ICE */
188 { 0x49544520, 0x00, 0, "ITE2226E", 0 },
189 { 0x49544560, 0x07, 0, "ITE2646E", 0 }, /* XXX: patch needed */
190 { 0x4e534340, 0x00, 0, "LM4540", 0 }, /* Spec blank on revid */
191 { 0x4e534343, 0x00, 0, "LM4543", 0 }, /* Ditto */
192 { 0x4e534346, 0x00, 0, "LM4546A", 0 },
193 { 0x4e534348, 0x00, 0, "LM4548A", 0 },
194 { 0x4e534331, 0x00, 0, "LM4549", 0 },
195 { 0x4e534349, 0x00, 0, "LM4549A", 0 },
196 { 0x4e534350, 0x00, 0, "LM4550", 0 },
197 { 0x50534301, 0x00, 0, "UCB1510", 0 },
198 { 0x50534304, 0x00, 0, "UCB1400", 0 },
199 { 0x83847600, 0x00, 0, "STAC9700/83/84", 0 },
200 { 0x83847604, 0x00, 0, "STAC9701/03/04/05", 0 },
201 { 0x83847605, 0x00, 0, "STAC9704", 0 },
202 { 0x83847608, 0x00, 0, "STAC9708/11", 0 },
203 { 0x83847609, 0x00, 0, "STAC9721/23", 0 },
204 { 0x83847644, 0x00, 0, "STAC9744/45", 0 },
205 { 0x83847650, 0x00, 0, "STAC9750/51", 0 },
206 { 0x83847652, 0x00, 0, "STAC9752/53", 0 },
207 { 0x83847656, 0x00, 0, "STAC9756/57", 0 },
208 { 0x83847658, 0x00, 0, "STAC9758/59", 0 },
209 { 0x83847660, 0x00, 0, "STAC9760/61", 0 }, /* Extrapolated */
210 { 0x83847662, 0x00, 0, "STAC9762/63", 0 }, /* Extrapolated */
211 { 0x83847666, 0x00, 0, "STAC9766/67", 0 },
212 { 0x53494c22, 0x00, 0, "Si3036", 0 },
213 { 0x53494c23, 0x00, 0, "Si3038", 0 },
214 { 0x54524103, 0x00, 0, "TR28023", 0 }, /* Extrapolated */
215 { 0x54524106, 0x00, 0, "TR28026", 0 },
216 { 0x54524108, 0x00, 0, "TR28028", 0 },
217 { 0x54524123, 0x00, 0, "TR28602", 0 },
218 { 0x54524e03, 0x07, 0, "TLV320AIC27", 0 },
219 { 0x54584e20, 0x00, 0, "TLC320AD90", 0 },
220 { 0x56494161, 0x00, 0, "VIA1612A", 0 },
221 { 0x56494170, 0x00, 0, "VIA1617A", 0 },
222 { 0x574d4c00, 0x00, 0, "WM9701A", 0 },
223 { 0x574d4c03, 0x00, 0, "WM9703/4/7/8", 0 },
224 { 0x574d4c04, 0x00, 0, "WM9704Q", 0 },
225 { 0x574d4c05, 0x00, 0, "WM9705/10", 0 },
226 { 0x574d4d09, 0x00, 0, "WM9709", 0 },
227 { 0x574d4c12, 0x00, 0, "WM9711/12", 0 }, /* XXX: patch needed */
228 { 0x57454301, 0x00, 0, "W83971D", 0 },
229 { 0x594d4800, 0x00, 0, "YMF743", 0 },
230 { 0x594d4802, 0x00, 0, "YMF752", 0 },
231 { 0x594d4803, 0x00, 0, "YMF753", 0 },
233 * XXX This is a fluke, really! The real codec
234 * should be STAC9704, not this! This should be
237 { 0x01408384, 0x00, 0, "EV1938", 0 },
241 static char *ac97enhancement[] = {
242 "no 3D Stereo Enhancement",
243 "Analog Devices Phat Stereo",
244 "Creative Stereo Enhancement",
245 "National Semi 3D Stereo Enhancement",
247 "BBE 3D Stereo Enhancement",
248 "Crystal Semi 3D Stereo Enhancement",
250 "Spatializer 3D Stereo Enhancement",
251 "SRS 3D Stereo Enhancement",
252 "Platform Tech 3D Stereo Enhancement",
254 "Aureal Stereo Enhancement",
255 "Aztech 3D Enhancement",
256 "Binaura 3D Audio Enhancement",
257 "ESS Technology Stereo Enhancement",
258 "Harman International VMAx",
259 "Nvidea 3D Stereo Enhancement",
260 "Philips Incredible Sound",
261 "Texas Instruments 3D Stereo Enhancement",
262 "VLSI Technology 3D Stereo Enhancement",
263 "TriTech 3D Stereo Enhancement",
264 "Realtek 3D Stereo Enhancement",
265 "Samsung 3D Stereo Enhancement",
266 "Wolfson Microelectronics 3D Enhancement",
267 "Delta Integration 3D Enhancement",
268 "SigmaTel 3D Enhancement",
270 "Rockwell 3D Stereo Enhancement",
276 static char *ac97feature[] = {
289 static char *ac97extfeature[] = {
307 ac97_rdcd(struct ac97_info *codec, int reg)
309 if (codec->flags & AC97_F_RDCD_BUG) {
310 u_int16_t i[2], j = 100;
312 i[0] = AC97_READ(codec->methods, codec->devinfo, reg);
313 i[1] = AC97_READ(codec->methods, codec->devinfo, reg);
314 while (i[0] != i[1] && j)
315 i[j-- & 1] = AC97_READ(codec->methods, codec->devinfo, reg);
318 device_printf(codec->dev, "%s(): Inconsistent register value at"
319 " 0x%08x (retry: %d)\n", __func__, reg, 100 - j);
324 return AC97_READ(codec->methods, codec->devinfo, reg);
328 ac97_wrcd(struct ac97_info *codec, int reg, u_int16_t val)
330 AC97_WRITE(codec->methods, codec->devinfo, reg, val);
334 ac97_reset(struct ac97_info *codec)
337 ac97_wrcd(codec, AC97_REG_RESET, 0);
338 for (i = 0; i < 500; i++) {
339 ps = ac97_rdcd(codec, AC97_REG_POWER) & AC97_POWER_STATUS;
340 if (ps == AC97_POWER_STATUS)
344 device_printf(codec->dev, "AC97 reset timed out.\n");
348 ac97_setrate(struct ac97_info *codec, int which, int rate)
353 case AC97_REGEXT_FDACRATE:
354 case AC97_REGEXT_SDACRATE:
355 case AC97_REGEXT_LDACRATE:
356 case AC97_REGEXT_LADCRATE:
357 case AC97_REGEXT_MADCRATE:
364 snd_mtxlock(codec->lock);
367 if (codec->extstat & AC97_EXTCAP_DRA)
369 ac97_wrcd(codec, which, v);
371 v = ac97_rdcd(codec, which);
372 if (codec->extstat & AC97_EXTCAP_DRA)
374 snd_mtxunlock(codec->lock);
379 ac97_setextmode(struct ac97_info *codec, u_int16_t mode)
381 mode &= AC97_EXTCAPS;
382 if ((mode & ~codec->extcaps) != 0) {
383 device_printf(codec->dev, "ac97 invalid mode set 0x%04x\n",
387 snd_mtxlock(codec->lock);
388 ac97_wrcd(codec, AC97_REGEXT_STAT, mode);
389 codec->extstat = ac97_rdcd(codec, AC97_REGEXT_STAT) & AC97_EXTCAPS;
390 snd_mtxunlock(codec->lock);
391 return (mode == codec->extstat)? 0 : -1;
395 ac97_getextmode(struct ac97_info *codec)
397 return codec->extstat;
401 ac97_getextcaps(struct ac97_info *codec)
403 return codec->extcaps;
407 ac97_getcaps(struct ac97_info *codec)
413 ac97_getsubvendor(struct ac97_info *codec)
415 return codec->subvendor;
419 ac97_setrecsrc(struct ac97_info *codec, int channel)
421 struct ac97mixtable_entry *e = &codec->mix[channel];
424 int val = e->recidx - 1;
426 snd_mtxlock(codec->lock);
427 ac97_wrcd(codec, AC97_REG_RECSEL, val);
428 snd_mtxunlock(codec->lock);
435 ac97_setmixer(struct ac97_info *codec, unsigned channel, unsigned left, unsigned right)
437 struct ac97mixtable_entry *e = &codec->mix[channel];
439 if (e->reg && e->enable && e->bits) {
440 int mask, max, val, reg;
442 reg = (e->reg >= 0) ? e->reg : -e->reg; /* AC97 register */
443 max = (1 << e->bits) - 1; /* actual range */
444 mask = (max << 8) | max; /* bits of interest */
450 * Invert the range if the polarity requires so,
451 * then scale to 0..max-1 to compute the value to
452 * write into the codec, and scale back to 0..100
453 * for the return value.
460 left = (left * max) / 100;
461 right = (right * max) / 100;
463 val = (left << 8) | right;
465 left = (left * 100) / max;
466 right = (right * 100) / max;
474 * For mono controls, trim val and mask, also taking
475 * care of e->ofs (offset of control field).
480 mask = (max << e->ofs);
484 * If we have a mute bit, add it to the mask and
485 * update val and set mute if both channels require a
490 if (left == 0 && right == 0)
495 * If the mask bit is set, do not alter the other bits.
497 snd_mtxlock(codec->lock);
499 int cur = ac97_rdcd(codec, reg);
500 val |= cur & ~(mask);
502 ac97_wrcd(codec, reg, val);
503 snd_mtxunlock(codec->lock);
504 return left | (right << 8);
507 kprintf("ac97_setmixer: reg=%d, bits=%d, enable=%d\n", e->reg, e->bits, e->enable);
514 ac97_fix_auxout(struct ac97_info *codec)
519 * By default, The ac97 aux_out register (0x04) corresponds to OSS's
522 * We first check whether aux_out is a valid register. If not
523 * we may not want to keep ogain.
525 keep_ogain = ac97_rdcd(codec, AC97_MIX_AUXOUT) & 0x8000;
528 * Determine what AUX_OUT really means, it can be:
532 * 3. True line level out (effectively master volume).
534 * See Sections 5.2.1 and 5.27 for AUX_OUT Options in AC97r2.{2,3}.
536 if (codec->extcaps & AC97_EXTCAP_SDAC &&
537 ac97_rdcd(codec, AC97_MIXEXT_SURROUND) == 0x8080) {
538 codec->mix[SOUND_MIXER_OGAIN].reg = AC97_MIXEXT_SURROUND;
542 if (keep_ogain == 0) {
543 bzero(&codec->mix[SOUND_MIXER_OGAIN],
544 sizeof(codec->mix[SOUND_MIXER_OGAIN]));
549 ac97_fix_tone(struct ac97_info *codec)
552 * YMF chips does not indicate tone and 3D enhancement capability
553 * in the AC97_REG_RESET register.
556 case 0x594d4800: /* YMF743 */
557 case 0x594d4803: /* YMF753 */
558 codec->caps |= AC97_CAP_TONE;
561 case 0x594d4802: /* YMF752 */
568 /* Hide treble and bass if they don't exist */
569 if ((codec->caps & AC97_CAP_TONE) == 0) {
570 bzero(&codec->mix[SOUND_MIXER_BASS],
571 sizeof(codec->mix[SOUND_MIXER_BASS]));
572 bzero(&codec->mix[SOUND_MIXER_TREBLE],
573 sizeof(codec->mix[SOUND_MIXER_TREBLE]));
578 ac97_hw_desc(u_int32_t id, const char* vname, const char* cname, char* buf)
581 ksprintf(buf, "Unknown AC97 Codec (id = 0x%08x)", id);
585 if (vname == NULL) vname = "Unknown";
588 ksprintf(buf, "%s %s AC97 Codec (id = 0x%08x)", vname, cname, id);
590 ksprintf(buf, "%s %s AC97 Codec", vname, cname);
596 ac97_initmixer(struct ac97_info *codec)
598 ac97_patch codec_patch;
599 const char *cname, *vname;
601 u_int8_t model, step;
602 unsigned i, j, k, bit, old;
606 snd_mtxlock(codec->lock);
607 codec->count = AC97_INIT(codec->methods, codec->devinfo);
608 if (codec->count == 0) {
609 device_printf(codec->dev, "ac97 codec init failed\n");
610 snd_mtxunlock(codec->lock);
614 ac97_wrcd(codec, AC97_REG_POWER, (codec->flags & AC97_F_EAPD_INV)? 0x8000 : 0x0000);
616 ac97_wrcd(codec, AC97_REG_POWER, (codec->flags & AC97_F_EAPD_INV)? 0x8000 : 0x0000);
618 i = ac97_rdcd(codec, AC97_REG_RESET);
619 j = ac97_rdcd(codec, AC97_REG_RESET);
621 * Let see if this codec can return consistent value.
622 * If not, turn on aggressive read workaround
623 * (STAC9704 comes in mind).
626 codec->flags |= AC97_F_RDCD_BUG;
627 i = ac97_rdcd(codec, AC97_REG_RESET);
629 codec->caps = i & 0x03ff;
630 codec->se = (i & 0x7c00) >> 10;
632 id = (ac97_rdcd(codec, AC97_REG_ID1) << 16) | ac97_rdcd(codec, AC97_REG_ID2);
633 if (id == 0 || id == 0xffffffff) {
634 device_printf(codec->dev, "ac97 codec invalid or not present (id == %x)\n", id);
635 snd_mtxunlock(codec->lock);
640 codec->subvendor = (u_int32_t)pci_get_subdevice(codec->dev) << 16;
641 codec->subvendor |= (u_int32_t)pci_get_subvendor(codec->dev) &
648 for (i = 0; ac97codecid[i].id; i++) {
649 u_int32_t modelmask = 0xffffffff ^ ac97codecid[i].stepmask;
650 if ((ac97codecid[i].id & modelmask) == (id & modelmask)) {
651 codec->noext = ac97codecid[i].noext;
652 codec_patch = ac97codecid[i].patch;
653 cname = ac97codecid[i].name;
654 model = (id & modelmask) & 0xff;
655 step = (id & ~modelmask) & 0xff;
661 for (i = 0; ac97vendorid[i].id; i++) {
662 if (ac97vendorid[i].id == (id & 0xffffff00)) {
663 vname = ac97vendorid[i].name;
672 i = ac97_rdcd(codec, AC97_REGEXT_ID);
674 codec->extcaps = i & 0x3fff;
675 codec->extid = (i & 0xc000) >> 14;
676 codec->extstat = ac97_rdcd(codec, AC97_REGEXT_STAT) & AC97_EXTCAPS;
680 for (i = 0; i < 32; i++) {
681 codec->mix[i] = ac97mixtable_default[i];
683 ac97_fix_auxout(codec);
684 ac97_fix_tone(codec);
688 for (i = 0; i < 32; i++) {
689 k = codec->noext? codec->mix[i].enable : 1;
690 reg = codec->mix[i].reg;
694 j = old = ac97_rdcd(codec, reg);
696 * Test for mute bit (except for AC97_MIX_TONE,
697 * where we simply assume it as available).
699 if (codec->mix[i].mute) {
700 ac97_wrcd(codec, reg, j | 0x8000);
701 j = ac97_rdcd(codec, reg);
706 * Test whether the control width should be
707 * 4, 5 or 6 bit. For 5bit register, we should
708 * test it whether it's really 5 or 6bit. Leave
709 * 4bit register alone, because sometimes an
710 * attempt to write past 4th bit may cause
711 * incorrect result especially for AC97_MIX_BEEP
714 bit = codec->mix[i].bits;
717 j = ((1 << bit) - 1) << codec->mix[i].ofs;
718 ac97_wrcd(codec, reg,
719 j | (codec->mix[i].mute ? 0x8000 : 0));
720 k = ac97_rdcd(codec, reg) & j;
721 k >>= codec->mix[i].ofs;
722 if (reg == AC97_MIX_TONE &&
723 ((k & 0x0001) == 0x0000))
725 for (j = 0; k >> j; j++)
729 device_printf(codec->dev, "%2d: [ac97_rdcd() = %d] [Testbit = %d] %d -> %d\n",
730 i, k, bit, codec->mix[i].bits, j);
732 codec->mix[i].enable = 1;
733 codec->mix[i].bits = j;
734 } else if (reg == AC97_MIX_BEEP) {
736 * Few codec such as CX20468-21 does
737 * have this control register, although
738 * the only usable part is the mute bit.
740 codec->mix[i].enable = 1;
742 codec->mix[i].enable = 0;
744 codec->mix[i].enable = 0;
745 ac97_wrcd(codec, reg, old);
748 kprintf("mixch %d, en=%d, b=%d\n", i, codec->mix[i].enable, codec->mix[i].bits);
752 device_printf(codec->dev, "<%s>\n",
753 ac97_hw_desc(codec->id, vname, cname, desc));
756 if (codec->flags & AC97_F_RDCD_BUG)
757 device_printf(codec->dev, "Buggy AC97 Codec: aggressive ac97_rdcd() workaround enabled\n");
758 device_printf(codec->dev, "Codec features ");
759 for (i = j = 0; i < 10; i++)
760 if (codec->caps & (1 << i))
761 kprintf("%s%s", j++? ", " : "", ac97feature[i]);
762 kprintf("%s%d bit master volume", j++? ", " : "", codec->mix[SOUND_MIXER_VOLUME].bits);
763 kprintf("%s%s\n", j? ", " : "", ac97enhancement[codec->se]);
765 if (codec->extcaps != 0 || codec->extid) {
766 device_printf(codec->dev, "%s codec",
767 codec->extid? "Secondary" : "Primary");
769 kprintf(" extended features ");
770 for (i = j = 0; i < 14; i++)
771 if (codec->extcaps & (1 << i))
772 kprintf("%s%s", j++? ", " : "", ac97extfeature[i]);
778 while ((ac97_rdcd(codec, AC97_REG_POWER) & 2) == 0) {
780 device_printf(codec->dev, "ac97 codec reports dac not ready\n");
786 device_printf(codec->dev, "ac97 codec dac ready count: %d\n", i);
787 snd_mtxunlock(codec->lock);
792 ac97_reinitmixer(struct ac97_info *codec)
794 snd_mtxlock(codec->lock);
795 codec->count = AC97_INIT(codec->methods, codec->devinfo);
796 if (codec->count == 0) {
797 device_printf(codec->dev, "ac97 codec init failed\n");
798 snd_mtxunlock(codec->lock);
802 ac97_wrcd(codec, AC97_REG_POWER, (codec->flags & AC97_F_EAPD_INV)? 0x8000 : 0x0000);
804 ac97_wrcd(codec, AC97_REG_POWER, (codec->flags & AC97_F_EAPD_INV)? 0x8000 : 0x0000);
807 ac97_wrcd(codec, AC97_REGEXT_STAT, codec->extstat);
808 if ((ac97_rdcd(codec, AC97_REGEXT_STAT) & AC97_EXTCAPS)
810 device_printf(codec->dev, "ac97 codec failed to reset extended mode (%x, got %x)\n",
812 ac97_rdcd(codec, AC97_REGEXT_STAT) &
816 if ((ac97_rdcd(codec, AC97_REG_POWER) & 2) == 0)
817 device_printf(codec->dev, "ac97 codec reports dac not ready\n");
818 snd_mtxunlock(codec->lock);
823 ac97_create(device_t dev, void *devinfo, kobj_class_t cls)
825 struct ac97_info *codec;
827 codec = (struct ac97_info *)kmalloc(sizeof *codec, M_AC97, M_NOWAIT);
831 ksnprintf(codec->name, AC97_NAMELEN, "%s:ac97", device_get_nameunit(dev));
832 codec->lock = snd_mtxcreate(codec->name, "ac97 codec");
833 codec->methods = kobj_create(cls, M_AC97, M_WAITOK);
834 if (codec->methods == NULL) {
835 snd_mtxfree(codec->lock);
836 kfree(codec, M_AC97);
841 codec->devinfo = devinfo;
847 ac97_destroy(struct ac97_info *codec)
849 if (codec->methods != NULL)
850 kobj_delete(codec->methods, M_AC97);
851 snd_mtxfree(codec->lock);
852 kfree(codec, M_AC97);
856 ac97_setflags(struct ac97_info *codec, u_int32_t val)
862 ac97_getflags(struct ac97_info *codec)
867 /* -------------------------------------------------------------------- */
870 ac97mix_init(struct snd_mixer *m)
872 struct ac97_info *codec = mix_getdevinfo(m);
878 if (ac97_initmixer(codec))
882 case 0x41445374: /* AD1981B */
883 switch (codec->subvendor) {
888 * Tie "ogain" and "phout" to "vol" since its
889 * master volume is basically useless and can't
893 if (codec->mix[SOUND_MIXER_OGAIN].enable)
894 mask |= SOUND_MASK_OGAIN;
895 if (codec->mix[SOUND_MIXER_PHONEOUT].enable)
896 mask |= SOUND_MASK_PHONEOUT;
897 if (codec->mix[SOUND_MIXER_VOLUME].enable)
898 mix_setparentchild(m, SOUND_MIXER_VOLUME,
901 mix_setparentchild(m, SOUND_MIXER_VOLUME,
903 mix_setrealdev(m, SOUND_MIXER_VOLUME,
911 * By default, "vol" is controlling internal speakers
912 * (not a master volume!) and "ogain" is controlling
913 * headphone. Enable dummy "phout" so it can be
914 * remapped to internal speakers and virtualize
915 * "vol" to control both.
917 codec->mix[SOUND_MIXER_OGAIN].enable = 1;
918 codec->mix[SOUND_MIXER_PHONEOUT].enable = 1;
919 mix_setrealdev(m, SOUND_MIXER_PHONEOUT,
921 mix_setrealdev(m, SOUND_MIXER_VOLUME,
923 mix_setparentchild(m, SOUND_MIXER_VOLUME,
924 SOUND_MASK_OGAIN | SOUND_MASK_PHONEOUT);
930 case 0x434d4941: /* CMI9738 */
931 case 0x434d4961: /* CMI9739 */
932 case 0x434d4978: /* CMI9761 */
933 case 0x434d4982: /* CMI9761 */
934 case 0x434d4983: /* CMI9761 */
935 ac97_wrcd(codec, AC97_MIX_PCM, 0);
936 bzero(&codec->mix[SOUND_MIXER_PCM],
937 sizeof(codec->mix[SOUND_MIXER_PCM]));
938 pcm_setflags(codec->dev, pcm_getflags(codec->dev) |
940 /* XXX How about master volume ? */
947 /* XXX For the sake of debugging purposes */
948 mix_setparentchild(m, SOUND_MIXER_VOLUME,
949 SOUND_MASK_PCM | SOUND_MASK_CD);
950 mix_setrealdev(m, SOUND_MIXER_VOLUME, SOUND_MIXER_NONE);
951 ac97_wrcd(codec, AC97_MIX_MASTER, 0);
955 for (i = 0; i < 32; i++)
956 mask |= codec->mix[i].enable? 1 << i : 0;
957 mix_setdevs(m, mask);
960 for (i = 0; i < 32; i++)
961 mask |= codec->mix[i].recidx? 1 << i : 0;
962 mix_setrecdevs(m, mask);
967 ac97mix_uninit(struct snd_mixer *m)
969 struct ac97_info *codec = mix_getdevinfo(m);
974 if (ac97_uninitmixer(codec))
982 ac97mix_reinit(struct snd_mixer *m)
984 struct ac97_info *codec = mix_getdevinfo(m);
988 return ac97_reinitmixer(codec);
992 ac97mix_set(struct snd_mixer *m, unsigned dev, unsigned left, unsigned right)
994 struct ac97_info *codec = mix_getdevinfo(m);
998 return ac97_setmixer(codec, dev, left, right);
1002 ac97mix_setrecsrc(struct snd_mixer *m, u_int32_t src)
1005 struct ac97_info *codec = mix_getdevinfo(m);
1009 for (i = 0; i < SOUND_MIXER_NRDEVICES; i++)
1010 if ((src & (1 << i)) != 0)
1012 return (ac97_setrecsrc(codec, i) == 0)? 1 << i : -1;
1015 static kobj_method_t ac97mixer_methods[] = {
1016 KOBJMETHOD(mixer_init, ac97mix_init),
1017 KOBJMETHOD(mixer_uninit, ac97mix_uninit),
1018 KOBJMETHOD(mixer_reinit, ac97mix_reinit),
1019 KOBJMETHOD(mixer_set, ac97mix_set),
1020 KOBJMETHOD(mixer_setrecsrc, ac97mix_setrecsrc),
1023 MIXER_DECLARE(ac97mixer);
1025 /* -------------------------------------------------------------------- */
1028 ac97_getmixerclass(void)
1030 return &ac97mixer_class;