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.3 2006/01/09 02:06:42 ariff Exp $
27 * $DragonFly: src/sys/dev/sound/pcm/ac97.c,v 1.23 2007/01/04 21:47:03 corecode Exp $
30 #include <dev/sound/pcm/sound.h>
31 #include <dev/sound/pcm/ac97.h>
32 #include <dev/sound/pcm/ac97_patch.h>
36 SND_DECLARE_FILE("$DragonFly: src/sys/dev/sound/pcm/ac97.c,v 1.23 2007/01/04 21:47:03 corecode Exp $");
38 MALLOC_DEFINE(M_AC97, "ac97", "ac97 codec");
40 struct ac97mixtable_entry {
41 int reg:8; /* register index */
42 /* reg < 0 if inverted polarity */
43 unsigned bits:4; /* width of control field */
44 unsigned ofs:4; /* offset (only if stereo=0) */
45 unsigned stereo:1; /* set for stereo controls */
46 unsigned mute:1; /* bit15 is MUTE */
47 unsigned recidx:4; /* index in rec mux */
48 unsigned mask:1; /* use only masked bits */
49 unsigned enable:1; /* entry is enabled */
52 #define AC97_NAMELEN 16
58 unsigned count, caps, se, extcaps, extid, extstat, noext:1;
60 struct ac97mixtable_entry mix[32];
61 char name[AC97_NAMELEN];
62 struct spinlock *lock;
65 struct ac97_vendorid {
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 }
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" },
123 * XXX This is a fluke, really! The real vendor
124 * should be SigmaTel, not this! This should be
127 { 0x01408300, "Creative" },
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", 0 },
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", 0 },
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 },
230 * XXX This is a fluke, really! The real codec
231 * should be STAC9704, not this! This should be
234 { 0x01408384, 0x00, 0, "EV1938", 0 },
238 static char *ac97enhancement[] = {
239 "no 3D Stereo Enhancement",
240 "Analog Devices Phat Stereo",
241 "Creative Stereo Enhancement",
242 "National Semi 3D Stereo Enhancement",
244 "BBE 3D Stereo Enhancement",
245 "Crystal Semi 3D Stereo Enhancement",
247 "Spatializer 3D Stereo Enhancement",
248 "SRS 3D Stereo Enhancement",
249 "Platform Tech 3D Stereo Enhancement",
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",
267 "Rockwell 3D Stereo Enhancement",
273 static char *ac97feature[] = {
286 static char *ac97extfeature[] = {
304 ac97_rdcd(struct ac97_info *codec, int reg)
306 if (codec->flags & AC97_F_RDCD_BUG) {
307 u_int16_t i[2], j = 100;
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);
315 device_printf(codec->dev, "%s(): Inconsistent register value at"
316 " 0x%08x (retry: %d)\n", __func__, reg, 100 - j);
321 return AC97_READ(codec->methods, codec->devinfo, reg);
325 ac97_wrcd(struct ac97_info *codec, int reg, u_int16_t val)
327 AC97_WRITE(codec->methods, codec->devinfo, reg, val);
331 ac97_reset(struct ac97_info *codec)
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)
341 device_printf(codec->dev, "AC97 reset timed out.\n");
345 ac97_setrate(struct ac97_info *codec, int which, int rate)
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:
361 snd_mtxlock(codec->lock);
364 if (codec->extstat & AC97_EXTCAP_DRA)
366 ac97_wrcd(codec, which, v);
368 v = ac97_rdcd(codec, which);
369 if (codec->extstat & AC97_EXTCAP_DRA)
371 snd_mtxunlock(codec->lock);
376 ac97_setextmode(struct ac97_info *codec, u_int16_t mode)
378 mode &= AC97_EXTCAPS;
379 if ((mode & ~codec->extcaps) != 0) {
380 device_printf(codec->dev, "ac97 invalid mode set 0x%04x\n",
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;
392 ac97_getextmode(struct ac97_info *codec)
394 return codec->extstat;
398 ac97_getextcaps(struct ac97_info *codec)
400 return codec->extcaps;
404 ac97_getcaps(struct ac97_info *codec)
410 ac97_setrecsrc(struct ac97_info *codec, int channel)
412 struct ac97mixtable_entry *e = &codec->mix[channel];
415 int val = e->recidx - 1;
417 snd_mtxlock(codec->lock);
418 ac97_wrcd(codec, AC97_REG_RECSEL, val);
419 snd_mtxunlock(codec->lock);
426 ac97_setmixer(struct ac97_info *codec, unsigned channel, unsigned left, unsigned right)
428 struct ac97mixtable_entry *e = &codec->mix[channel];
430 if (e->reg && e->enable && e->bits) {
431 int mask, max, val, reg;
433 reg = (e->reg >= 0) ? e->reg : -e->reg; /* AC97 register */
434 max = (1 << e->bits) - 1; /* actual range */
435 mask = (max << 8) | max; /* bits of interest */
441 * Invert the range if the polarity requires so,
442 * then scale to 0..max-1 to compute the value to
443 * write into the codec, and scale back to 0..100
444 * for the return value.
451 left = (left * max) / 100;
452 right = (right * max) / 100;
454 val = (left << 8) | right;
456 left = (left * 100) / max;
457 right = (right * 100) / max;
465 * For mono controls, trim val and mask, also taking
466 * care of e->ofs (offset of control field).
471 mask = (max << e->ofs);
475 * If we have a mute bit, add it to the mask and
476 * update val and set mute if both channels require a
481 if (left == 0 && right == 0)
486 * If the mask bit is set, do not alter the other bits.
488 snd_mtxlock(codec->lock);
490 int cur = ac97_rdcd(codec, reg);
491 val |= cur & ~(mask);
493 ac97_wrcd(codec, reg, val);
494 snd_mtxunlock(codec->lock);
495 return left | (right << 8);
498 kprintf("ac97_setmixer: reg=%d, bits=%d, enable=%d\n", e->reg, e->bits, e->enable);
505 ac97_fix_auxout(struct ac97_info *codec)
510 * By default, The ac97 aux_out register (0x04) corresponds to OSS's
513 * We first check whether aux_out is a valid register. If not
514 * we may not want to keep ogain.
516 keep_ogain = ac97_rdcd(codec, AC97_MIX_AUXOUT) & 0x8000;
519 * Determine what AUX_OUT really means, it can be:
523 * 3. True line level out (effectively master volume).
525 * See Sections 5.2.1 and 5.27 for AUX_OUT Options in AC97r2.{2,3}.
527 if (codec->extcaps & AC97_EXTCAP_SDAC &&
528 ac97_rdcd(codec, AC97_MIXEXT_SURROUND) == 0x8080) {
529 codec->mix[SOUND_MIXER_OGAIN].reg = AC97_MIXEXT_SURROUND;
533 if (keep_ogain == 0) {
534 bzero(&codec->mix[SOUND_MIXER_OGAIN],
535 sizeof(codec->mix[SOUND_MIXER_OGAIN]));
540 ac97_fix_tone(struct ac97_info *codec)
542 /* Hide treble and bass if they don't exist */
543 if ((codec->caps & AC97_CAP_TONE) == 0) {
544 bzero(&codec->mix[SOUND_MIXER_BASS],
545 sizeof(codec->mix[SOUND_MIXER_BASS]));
546 bzero(&codec->mix[SOUND_MIXER_TREBLE],
547 sizeof(codec->mix[SOUND_MIXER_TREBLE]));
552 ac97_fix_volume(struct ac97_info *codec)
554 struct snddev_info *d = device_get_softc(codec->dev);
557 /* XXX For the sake of debugging purposes */
558 ac97_wrcd(codec, AC97_MIX_PCM, 0);
559 bzero(&codec->mix[SOUND_MIXER_PCM],
560 sizeof(codec->mix[SOUND_MIXER_PCM]));
561 codec->flags |= AC97_F_SOFTVOL;
563 d->flags |= SD_F_SOFTVOL;
567 case 0x434d4941: /* CMI9738 */
568 case 0x434d4961: /* CMI9739 */
569 case 0x434d4978: /* CMI9761 */
570 case 0x434d4982: /* CMI9761 */
571 case 0x434d4983: /* CMI9761 */
572 ac97_wrcd(codec, AC97_MIX_PCM, 0);
578 bzero(&codec->mix[SOUND_MIXER_PCM],
579 sizeof(codec->mix[SOUND_MIXER_PCM]));
580 codec->flags |= AC97_F_SOFTVOL;
582 d->flags |= SD_F_SOFTVOL;
586 ac97_hw_desc(u_int32_t id, const char* vname, const char* cname, char* buf)
589 ksprintf(buf, "Unknown AC97 Codec (id = 0x%08x)", id);
593 if (vname == NULL) vname = "Unknown";
596 ksprintf(buf, "%s %s AC97 Codec (id = 0x%08x)", vname, cname, id);
598 ksprintf(buf, "%s %s AC97 Codec", vname, cname);
604 ac97_initmixer(struct ac97_info *codec)
606 ac97_patch codec_patch;
607 const char *cname, *vname;
609 u_int8_t model, step;
610 unsigned i, j, k, bit, old;
614 snd_mtxlock(codec->lock);
615 codec->count = AC97_INIT(codec->methods, codec->devinfo);
616 if (codec->count == 0) {
617 device_printf(codec->dev, "ac97 codec init failed\n");
618 snd_mtxunlock(codec->lock);
622 ac97_wrcd(codec, AC97_REG_POWER, (codec->flags & AC97_F_EAPD_INV)? 0x8000 : 0x0000);
624 ac97_wrcd(codec, AC97_REG_POWER, (codec->flags & AC97_F_EAPD_INV)? 0x8000 : 0x0000);
626 i = ac97_rdcd(codec, AC97_REG_RESET);
627 j = ac97_rdcd(codec, AC97_REG_RESET);
629 * Let see if this codec can return consistent value.
630 * If not, turn on aggressive read workaround
631 * (STAC9704 comes in mind).
634 codec->flags |= AC97_F_RDCD_BUG;
635 i = ac97_rdcd(codec, AC97_REG_RESET);
637 codec->caps = i & 0x03ff;
638 codec->se = (i & 0x7c00) >> 10;
640 id = (ac97_rdcd(codec, AC97_REG_ID1) << 16) | ac97_rdcd(codec, AC97_REG_ID2);
641 if (id == 0 || id == 0xffffffff) {
642 device_printf(codec->dev, "ac97 codec invalid or not present (id == %x)\n", id);
643 snd_mtxunlock(codec->lock);
653 for (i = 0; ac97codecid[i].id; i++) {
654 u_int32_t modelmask = 0xffffffff ^ ac97codecid[i].stepmask;
655 if ((ac97codecid[i].id & modelmask) == (id & modelmask)) {
656 codec->noext = ac97codecid[i].noext;
657 codec_patch = ac97codecid[i].patch;
658 cname = ac97codecid[i].name;
659 model = (id & modelmask) & 0xff;
660 step = (id & ~modelmask) & 0xff;
666 for (i = 0; ac97vendorid[i].id; i++) {
667 if (ac97vendorid[i].id == (id & 0xffffff00)) {
668 vname = ac97vendorid[i].name;
677 i = ac97_rdcd(codec, AC97_REGEXT_ID);
679 codec->extcaps = i & 0x3fff;
680 codec->extid = (i & 0xc000) >> 14;
681 codec->extstat = ac97_rdcd(codec, AC97_REGEXT_STAT) & AC97_EXTCAPS;
685 for (i = 0; i < 32; i++) {
686 codec->mix[i] = ac97mixtable_default[i];
688 ac97_fix_auxout(codec);
689 ac97_fix_tone(codec);
690 ac97_fix_volume(codec);
694 for (i = 0; i < 32; i++) {
695 k = codec->noext? codec->mix[i].enable : 1;
696 reg = codec->mix[i].reg;
700 j = old = ac97_rdcd(codec, reg);
702 * Test for mute bit (except for AC97_MIX_TONE,
703 * where we simply assume it as available).
705 if (codec->mix[i].mute) {
706 ac97_wrcd(codec, reg, j | 0x8000);
707 j = ac97_rdcd(codec, reg);
712 * Test whether the control width should be
713 * 4, 5 or 6 bit. For 5bit register, we should
714 * test it whether it's really 5 or 6bit. Leave
715 * 4bit register alone, because sometimes an
716 * attempt to write past 4th bit may cause
717 * incorrect result especially for AC97_MIX_BEEP
720 bit = codec->mix[i].bits;
723 j = ((1 << bit) - 1) << codec->mix[i].ofs;
724 ac97_wrcd(codec, reg,
725 j | (codec->mix[i].mute ? 0x8000 : 0));
726 k = ac97_rdcd(codec, reg) & j;
727 k >>= codec->mix[i].ofs;
728 if (reg == AC97_MIX_TONE &&
729 ((k & 0x0001) == 0x0000))
731 for (j = 0; k >> j; j++)
735 device_printf(codec->dev, "%2d: [ac97_rdcd() = %d] [Testbit = %d] %d -> %d\n",
736 i, k, bit, codec->mix[i].bits, j);
738 codec->mix[i].enable = 1;
739 codec->mix[i].bits = j;
740 } else if (reg == AC97_MIX_BEEP) {
742 * Few codec such as CX20468-21 does
743 * have this control register, although
744 * the only usable part is the mute bit.
746 codec->mix[i].enable = 1;
748 codec->mix[i].enable = 0;
750 codec->mix[i].enable = 0;
751 ac97_wrcd(codec, reg, old);
754 kprintf("mixch %d, en=%d, b=%d\n", i, codec->mix[i].enable, codec->mix[i].bits);
758 device_printf(codec->dev, "<%s>\n",
759 ac97_hw_desc(codec->id, vname, cname, desc));
762 if (codec->flags & AC97_F_RDCD_BUG)
763 device_printf(codec->dev, "Buggy AC97 Codec: aggressive ac97_rdcd() workaround enabled\n");
764 if (codec->flags & AC97_F_SOFTVOL)
765 device_printf(codec->dev, "Soft PCM volume\n");
766 device_printf(codec->dev, "Codec features ");
767 for (i = j = 0; i < 10; i++)
768 if (codec->caps & (1 << i))
769 kprintf("%s%s", j++? ", " : "", ac97feature[i]);
770 kprintf("%s%d bit master volume", j++? ", " : "", codec->mix[SOUND_MIXER_VOLUME].bits);
771 kprintf("%s%s\n", j? ", " : "", ac97enhancement[codec->se]);
773 if (codec->extcaps != 0 || codec->extid) {
774 device_printf(codec->dev, "%s codec",
775 codec->extid? "Secondary" : "Primary");
777 kprintf(" extended features ");
778 for (i = j = 0; i < 14; i++)
779 if (codec->extcaps & (1 << i))
780 kprintf("%s%s", j++? ", " : "", ac97extfeature[i]);
786 while ((ac97_rdcd(codec, AC97_REG_POWER) & 2) == 0) {
788 device_printf(codec->dev, "ac97 codec reports dac not ready\n");
794 device_printf(codec->dev, "ac97 codec dac ready count: %d\n", i);
795 snd_mtxunlock(codec->lock);
800 ac97_reinitmixer(struct ac97_info *codec)
802 snd_mtxlock(codec->lock);
803 codec->count = AC97_INIT(codec->methods, codec->devinfo);
804 if (codec->count == 0) {
805 device_printf(codec->dev, "ac97 codec init failed\n");
806 snd_mtxunlock(codec->lock);
810 ac97_wrcd(codec, AC97_REG_POWER, (codec->flags & AC97_F_EAPD_INV)? 0x8000 : 0x0000);
812 ac97_wrcd(codec, AC97_REG_POWER, (codec->flags & AC97_F_EAPD_INV)? 0x8000 : 0x0000);
815 ac97_wrcd(codec, AC97_REGEXT_STAT, codec->extstat);
816 if ((ac97_rdcd(codec, AC97_REGEXT_STAT) & AC97_EXTCAPS)
818 device_printf(codec->dev, "ac97 codec failed to reset extended mode (%x, got %x)\n",
820 ac97_rdcd(codec, AC97_REGEXT_STAT) &
824 if ((ac97_rdcd(codec, AC97_REG_POWER) & 2) == 0)
825 device_printf(codec->dev, "ac97 codec reports dac not ready\n");
826 snd_mtxunlock(codec->lock);
831 ac97_create(device_t dev, void *devinfo, kobj_class_t cls)
833 struct ac97_info *codec;
835 codec = (struct ac97_info *)kmalloc(sizeof *codec, M_AC97, M_NOWAIT);
839 ksnprintf(codec->name, AC97_NAMELEN, "%s:ac97", device_get_nameunit(dev));
840 codec->lock = snd_mtxcreate(codec->name, "ac97 codec");
841 codec->methods = kobj_create(cls, M_AC97, M_WAITOK);
842 if (codec->methods == NULL) {
843 snd_mtxfree(codec->lock);
844 kfree(codec, M_AC97);
849 codec->devinfo = devinfo;
855 ac97_destroy(struct ac97_info *codec)
857 if (codec->methods != NULL)
858 kobj_delete(codec->methods, M_AC97);
859 snd_mtxfree(codec->lock);
860 kfree(codec, M_AC97);
864 ac97_setflags(struct ac97_info *codec, u_int32_t val)
870 ac97_getflags(struct ac97_info *codec)
875 /* -------------------------------------------------------------------- */
878 ac97mix_init(struct snd_mixer *m)
880 struct ac97_info *codec = mix_getdevinfo(m);
886 if (ac97_initmixer(codec))
890 for (i = 0; i < 32; i++)
891 mask |= codec->mix[i].enable? 1 << i : 0;
892 mix_setdevs(m, mask);
895 for (i = 0; i < 32; i++)
896 mask |= codec->mix[i].recidx? 1 << i : 0;
897 mix_setrecdevs(m, mask);
902 ac97mix_uninit(struct snd_mixer *m)
904 struct ac97_info *codec = mix_getdevinfo(m);
909 if (ac97_uninitmixer(codec))
917 ac97mix_reinit(struct snd_mixer *m)
919 struct ac97_info *codec = mix_getdevinfo(m);
923 return ac97_reinitmixer(codec);
927 ac97mix_set(struct snd_mixer *m, unsigned dev, unsigned left, unsigned right)
929 struct ac97_info *codec = mix_getdevinfo(m);
933 return ac97_setmixer(codec, dev, left, right);
937 ac97mix_setrecsrc(struct snd_mixer *m, u_int32_t src)
940 struct ac97_info *codec = mix_getdevinfo(m);
944 for (i = 0; i < SOUND_MIXER_NRDEVICES; i++)
945 if ((src & (1 << i)) != 0)
947 return (ac97_setrecsrc(codec, i) == 0)? 1 << i : -1;
950 static kobj_method_t ac97mixer_methods[] = {
951 KOBJMETHOD(mixer_init, ac97mix_init),
952 KOBJMETHOD(mixer_uninit, ac97mix_uninit),
953 KOBJMETHOD(mixer_reinit, ac97mix_reinit),
954 KOBJMETHOD(mixer_set, ac97mix_set),
955 KOBJMETHOD(mixer_setrecsrc, ac97mix_setrecsrc),
958 MIXER_DECLARE(ac97mixer);
960 /* -------------------------------------------------------------------- */
963 ac97_getmixerclass(void)
965 return &ac97mixer_class;