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.49 2003/11/11 22:15:17 kuriyama Exp $
27 * $DragonFly: src/sys/dev/sound/pcm/ac97.c,v 1.17 2004/07/09 10:01:02 asmodai 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.17 2004/07/09 10:01:02 asmodai 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];
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 },
91 /* use igain for the mic 20dB boost */
92 [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 }
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 { 0x01408300, "Creative" },
128 static struct ac97_codecid ac97codecid[] = {
129 { 0x41445303, 0x00, 0, "AD1819", 0 },
130 { 0x41445340, 0x00, 0, "AD1881", 0 },
131 { 0x41445348, 0x00, 0, "AD1881A", 0 },
132 { 0x41445360, 0x00, 0, "AD1885", 0 },
133 { 0x41445361, 0x00, 0, "AD1886", ad1886_patch },
134 { 0x41445362, 0x00, 0, "AD1887", 0 },
135 { 0x41445363, 0x00, 0, "AD1886A", 0 },
136 { 0x41445370, 0x00, 0, "AD1980", ad198x_patch },
137 { 0x41445372, 0x00, 0, "AD1981A", 0 },
138 { 0x41445374, 0x00, 0, "AD1981B", 0 },
139 { 0x41445375, 0x00, 0, "AD1985", ad198x_patch },
140 { 0x414b4d00, 0x00, 1, "AK4540", 0 },
141 { 0x414b4d01, 0x00, 1, "AK4542", 0 },
142 { 0x414b4d02, 0x00, 1, "AK4543", 0 },
143 { 0x414b4d06, 0x00, 0, "AK4544A", 0 },
144 { 0x454b4d07, 0x00, 0, "AK4545", 0 },
145 { 0x414c4320, 0x0f, 0, "ALC100", 0 },
146 { 0x414c4730, 0x0f, 0, "ALC101", 0 },
147 { 0x414c4710, 0x0f, 0, "ALC200", 0 },
148 { 0x414c4740, 0x0f, 0, "ALC202", 0 },
149 { 0x414c4720, 0x0f, 0, "ALC650", 0 },
150 { 0x414c4760, 0x0f, 0, "ALC655", 0 },
151 { 0x414c4780, 0x0f, 0, "ALC658", 0 },
152 { 0x414c4790, 0x0f, 0, "ALC850", 0 },
153 { 0x43525900, 0x07, 0, "CS4297", 0 },
154 { 0x43525910, 0x07, 0, "CS4297A", 0 },
155 { 0x43525920, 0x07, 0, "CS4294/98", 0 },
156 { 0x4352592d, 0x07, 0, "CS4294", 0 },
157 { 0x43525930, 0x07, 0, "CS4299", 0 },
158 { 0x43525940, 0x07, 0, "CS4201", 0 },
159 { 0x43525958, 0x07, 0, "CS4205", 0 },
160 { 0x43525960, 0x07, 0, "CS4291A", 0 },
161 { 0x434d4961, 0x00, 0, "CMI9739", 0 },
162 { 0x434d4941, 0x00, 0, "CMI9738", 0 },
163 { 0x43585421, 0x00, 0, "HSD11246", 0 },
164 { 0x43585428, 0x07, 0, "CX20468", 0 },
165 { 0x44543000, 0x00, 0, "DT0398", 0 },
166 { 0x454d4323, 0x00, 0, "EM28023", 0 },
167 { 0x454d4328, 0x00, 0, "EM28028", 0 },
168 { 0x45838308, 0x00, 0, "ES1988", 0 }, /* Formerly ES1921(?) */
169 { 0x48525300, 0x00, 0, "HMP9701", 0 },
170 { 0x49434501, 0x00, 0, "ICE1230", 0 },
171 { 0x49434511, 0x00, 0, "ICE1232", 0 },
172 { 0x49434514, 0x00, 0, "ICE1232A", 0 },
173 { 0x49434551, 0x03, 0, "VT1616", 0 }, /* Via badged ICE */
174 { 0x49544520, 0x00, 0, "ITE2226E", 0 },
175 { 0x49544560, 0x07, 0, "ITE2646E", 0 }, /* XXX: patch needed */
176 { 0x4e534340, 0x00, 0, "LM4540", 0 }, /* Spec blank on revid */
177 { 0x4e534343, 0x00, 0, "LM4543", 0 }, /* Ditto */
178 { 0x4e534346, 0x00, 0, "LM4546A", 0 },
179 { 0x4e534348, 0x00, 0, "LM4548A", 0 },
180 { 0x4e534331, 0x00, 0, "LM4549", 0 },
181 { 0x4e534349, 0x00, 0, "LM4549A", 0 },
182 { 0x4e534350, 0x00, 0, "LM4550", 0 },
183 { 0x50534301, 0x00, 0, "UCB1510", 0 },
184 { 0x50534304, 0x00, 0, "UCB1400", 0 },
185 { 0x83847600, 0x00, 0, "STAC9700/83/84", 0 },
186 { 0x83847604, 0x00, 0, "STAC9701/03/04/05", 0 },
187 { 0x83847605, 0x00, 0, "STAC9704", 0 },
188 { 0x83847608, 0x00, 0, "STAC9708/11", 0 },
189 { 0x83847609, 0x00, 0, "STAC9721/23", 0 },
190 { 0x83847644, 0x00, 0, "STAC9744/45", 0 },
191 { 0x83847650, 0x00, 0, "STAC9750/51", 0 },
192 { 0x83847652, 0x00, 0, "STAC9752/53", 0 },
193 { 0x83847656, 0x00, 0, "STAC9756/57", 0 },
194 { 0x83847658, 0x00, 0, "STAC9758/59", 0 },
195 { 0x83847660, 0x00, 0, "STAC9760/61", 0 }, /* Extrapolated */
196 { 0x83847662, 0x00, 0, "STAC9762/63", 0 }, /* Extrapolated */
197 { 0x53494c22, 0x00, 0, "Si3036", 0 },
198 { 0x53494c23, 0x00, 0, "Si3038", 0 },
199 { 0x54524103, 0x00, 0, "TR28023", 0 }, /* Extrapolated */
200 { 0x54524106, 0x00, 0, "TR28026", 0 },
201 { 0x54524108, 0x00, 0, "TR28028", 0 },
202 { 0x54524123, 0x00, 0, "TR28602", 0 },
203 { 0x54524e03, 0x07, 0, "TLV320AIC27", 0 },
204 { 0x54584e20, 0x00, 0, "TLC320AD90", 0 },
205 { 0x56494161, 0x00, 0, "VIA1612A", 0 },
206 { 0x574d4c00, 0x00, 0, "WM9701A", 0 },
207 { 0x574d4c03, 0x00, 0, "WM9703/4/7/8", 0 },
208 { 0x574d4c04, 0x00, 0, "WM9704Q", 0 },
209 { 0x574d4c05, 0x00, 0, "WM9705/10", 0 },
210 { 0x574d4d09, 0x00, 0, "WM9709", 0 },
211 { 0x574d4c12, 0x00, 0, "WM9711/12", 0 }, /* XXX: patch needed */
212 { 0x57454301, 0x00, 0, "W83971D", 0 },
213 { 0x594d4800, 0x00, 0, "YMF743", 0 },
214 { 0x594d4802, 0x00, 0, "YMF752", 0 },
215 { 0x594d4803, 0x00, 0, "YMF753", 0 },
216 { 0x01408384, 0x00, 0, "EV1938", 0 },
220 static char *ac97enhancement[] = {
221 "no 3D Stereo Enhancement",
222 "Analog Devices Phat Stereo",
223 "Creative Stereo Enhancement",
224 "National Semi 3D Stereo Enhancement",
226 "BBE 3D Stereo Enhancement",
227 "Crystal Semi 3D Stereo Enhancement",
229 "Spatializer 3D Stereo Enhancement",
230 "SRS 3D Stereo Enhancement",
231 "Platform Tech 3D Stereo Enhancement",
233 "Aureal Stereo Enhancement",
234 "Aztech 3D Enhancement",
235 "Binaura 3D Audio Enhancement",
236 "ESS Technology Stereo Enhancement",
237 "Harman International VMAx",
238 "Nvidea 3D Stereo Enhancement",
239 "Philips Incredible Sound",
240 "Texas Instruments 3D Stereo Enhancement",
241 "VLSI Technology 3D Stereo Enhancement",
242 "TriTech 3D Stereo Enhancement",
243 "Realtek 3D Stereo Enhancement",
244 "Samsung 3D Stereo Enhancement",
245 "Wolfson Microelectronics 3D Enhancement",
246 "Delta Integration 3D Enhancement",
247 "SigmaTel 3D Enhancement",
249 "Rockwell 3D Stereo Enhancement",
255 static char *ac97feature[] = {
268 static char *ac97extfeature[] = {
286 ac97_rdcd(struct ac97_info *codec, int reg)
288 return AC97_READ(codec->methods, codec->devinfo, reg);
292 ac97_wrcd(struct ac97_info *codec, int reg, u_int16_t val)
294 AC97_WRITE(codec->methods, codec->devinfo, reg, val);
298 ac97_reset(struct ac97_info *codec)
301 ac97_wrcd(codec, AC97_REG_RESET, 0);
302 for (i = 0; i < 500; i++) {
303 ps = ac97_rdcd(codec, AC97_REG_POWER) & AC97_POWER_STATUS;
304 if (ps == AC97_POWER_STATUS)
308 device_printf(codec->dev, "AC97 reset timed out.\n");
312 ac97_setrate(struct ac97_info *codec, int which, int rate)
317 case AC97_REGEXT_FDACRATE:
318 case AC97_REGEXT_SDACRATE:
319 case AC97_REGEXT_LDACRATE:
320 case AC97_REGEXT_LADCRATE:
321 case AC97_REGEXT_MADCRATE:
328 snd_mtxlock(codec->lock);
331 if (codec->extstat & AC97_EXTCAP_DRA)
333 ac97_wrcd(codec, which, v);
335 v = ac97_rdcd(codec, which);
336 if (codec->extstat & AC97_EXTCAP_DRA)
338 snd_mtxunlock(codec->lock);
343 ac97_setextmode(struct ac97_info *codec, u_int16_t mode)
345 mode &= AC97_EXTCAPS;
346 if ((mode & ~codec->extcaps) != 0) {
347 device_printf(codec->dev, "ac97 invalid mode set 0x%04x\n",
351 snd_mtxlock(codec->lock);
352 ac97_wrcd(codec, AC97_REGEXT_STAT, mode);
353 codec->extstat = ac97_rdcd(codec, AC97_REGEXT_STAT) & AC97_EXTCAPS;
354 snd_mtxunlock(codec->lock);
355 return (mode == codec->extstat)? 0 : -1;
359 ac97_getextmode(struct ac97_info *codec)
361 return codec->extstat;
365 ac97_getextcaps(struct ac97_info *codec)
367 return codec->extcaps;
371 ac97_getcaps(struct ac97_info *codec)
377 ac97_setrecsrc(struct ac97_info *codec, int channel)
379 struct ac97mixtable_entry *e = &codec->mix[channel];
382 int val = e->recidx - 1;
384 snd_mtxlock(codec->lock);
385 ac97_wrcd(codec, AC97_REG_RECSEL, val);
386 snd_mtxunlock(codec->lock);
393 ac97_setmixer(struct ac97_info *codec, unsigned channel, unsigned left, unsigned right)
395 struct ac97mixtable_entry *e = &codec->mix[channel];
397 if (e->reg && e->enable && e->bits) {
398 int mask, max, val, reg;
400 reg = (e->reg >= 0) ? e->reg : -e->reg; /* AC97 register */
401 max = (1 << e->bits) - 1; /* actual range */
402 mask = (max << 8) | max; /* bits of interest */
408 * Invert the range if the polarity requires so,
409 * then scale to 0..max-1 to compute the value to
410 * write into the codec, and scale back to 0..100
411 * for the return value.
418 left = (left * max) / 100;
419 right = (right * max) / 100;
421 val = (left << 8) | right;
423 left = (left * 100) / max;
424 right = (right * 100) / max;
432 * For mono controls, trim val and mask, also taking
433 * care of e->ofs (offset of control field).
438 mask = (max << e->ofs);
442 * If we have a mute bit, add it to the mask and
443 * update val and set mute if both channels require a
448 if (left == 0 && right == 0)
453 * If the mask bit is set, do not alter the other bits.
455 snd_mtxlock(codec->lock);
457 int cur = ac97_rdcd(codec, e->reg);
458 val |= cur & ~(mask);
460 ac97_wrcd(codec, reg, val);
461 snd_mtxunlock(codec->lock);
462 return left | (right << 8);
464 /* printf("ac97_setmixer: reg=%d, bits=%d, enable=%d\n", e->reg, e->bits, e->enable); */
470 ac97_fix_auxout(struct ac97_info *codec)
475 * By default, The ac97 aux_out register (0x04) corresponds to OSS's
478 * We first check whether aux_out is a valid register. If not
479 * we may not want to keep ogain.
481 keep_ogain = ac97_rdcd(codec, AC97_MIX_AUXOUT) & 0x8000;
484 * Determine what AUX_OUT really means, it can be:
488 * 3. True line level out (effectively master volume).
490 * See Sections 5.2.1 and 5.27 for AUX_OUT Options in AC97r2.{2,3}.
492 if (codec->extcaps & AC97_EXTCAP_SDAC &&
493 ac97_rdcd(codec, AC97_MIXEXT_SURROUND) == 0x8080) {
494 codec->mix[SOUND_MIXER_OGAIN].reg = AC97_MIXEXT_SURROUND;
498 if (keep_ogain == 0) {
499 bzero(&codec->mix[SOUND_MIXER_OGAIN],
500 sizeof(codec->mix[SOUND_MIXER_OGAIN]));
505 ac97_fix_tone(struct ac97_info *codec)
507 /* Hide treble and bass if they don't exist */
508 if ((codec->caps & AC97_CAP_TONE) == 0) {
509 bzero(&codec->mix[SOUND_MIXER_BASS],
510 sizeof(codec->mix[SOUND_MIXER_BASS]));
511 bzero(&codec->mix[SOUND_MIXER_TREBLE],
512 sizeof(codec->mix[SOUND_MIXER_TREBLE]));
517 ac97_hw_desc(u_int32_t id, const char* vname, const char* cname, char* buf)
520 sprintf(buf, "Unknown AC97 Codec (id = 0x%08x)", id);
524 if (vname == NULL) vname = "Unknown";
527 sprintf(buf, "%s %s AC97 Codec (id = 0x%08x)", vname, cname, id);
529 sprintf(buf, "%s %s AC97 Codec", vname, cname);
535 ac97_initmixer(struct ac97_info *codec)
537 ac97_patch codec_patch;
538 const char *cname, *vname;
540 u_int8_t model, step;
541 unsigned i, j, k, old;
544 snd_mtxlock(codec->lock);
545 codec->count = AC97_INIT(codec->methods, codec->devinfo);
546 if (codec->count == 0) {
547 device_printf(codec->dev, "ac97 codec init failed\n");
548 snd_mtxunlock(codec->lock);
552 ac97_wrcd(codec, AC97_REG_POWER, (codec->flags & AC97_F_EAPD_INV)? 0x8000 : 0x0000);
554 ac97_wrcd(codec, AC97_REG_POWER, (codec->flags & AC97_F_EAPD_INV)? 0x8000 : 0x0000);
556 i = ac97_rdcd(codec, AC97_REG_RESET);
557 codec->caps = i & 0x03ff;
558 codec->se = (i & 0x7c00) >> 10;
560 id = (ac97_rdcd(codec, AC97_REG_ID1) << 16) | ac97_rdcd(codec, AC97_REG_ID2);
561 if (id == 0 || id == 0xffffffff) {
562 device_printf(codec->dev, "ac97 codec invalid or not present (id == %x)\n", id);
563 snd_mtxunlock(codec->lock);
573 for (i = 0; ac97codecid[i].id; i++) {
574 u_int32_t modelmask = 0xffffffff ^ ac97codecid[i].stepmask;
575 if ((ac97codecid[i].id & modelmask) == (id & modelmask)) {
576 codec->noext = ac97codecid[i].noext;
577 codec_patch = ac97codecid[i].patch;
578 cname = ac97codecid[i].name;
579 model = (id & modelmask) & 0xff;
580 step = (id & ~modelmask) & 0xff;
586 for (i = 0; ac97vendorid[i].id; i++) {
587 if (ac97vendorid[i].id == (id & 0xffffff00)) {
588 vname = ac97vendorid[i].name;
597 i = ac97_rdcd(codec, AC97_REGEXT_ID);
599 codec->extcaps = i & 0x3fff;
600 codec->extid = (i & 0xc000) >> 14;
601 codec->extstat = ac97_rdcd(codec, AC97_REGEXT_STAT) & AC97_EXTCAPS;
605 for (i = 0; i < 32; i++) {
606 codec->mix[i] = ac97mixtable_default[i];
608 ac97_fix_auxout(codec);
609 ac97_fix_tone(codec);
613 for (i = 0; i < 32; i++) {
614 k = codec->noext? codec->mix[i].enable : 1;
615 if (k && (codec->mix[i].reg > 0)) {
616 old = ac97_rdcd(codec, codec->mix[i].reg);
617 ac97_wrcd(codec, codec->mix[i].reg, 0x3f);
618 j = ac97_rdcd(codec, codec->mix[i].reg);
619 ac97_wrcd(codec, codec->mix[i].reg, old);
620 codec->mix[i].enable = (j != 0 && j != old)? 1 : 0;
621 for (k = 1; j & (1 << k); k++);
622 codec->mix[i].bits = j? k - codec->mix[i].ofs : 0;
624 /* printf("mixch %d, en=%d, b=%d\n", i, codec->mix[i].enable, codec->mix[i].bits); */
627 device_printf(codec->dev, "<%s>\n",
628 ac97_hw_desc(codec->id, vname, cname, desc));
631 device_printf(codec->dev, "Codec features ");
632 for (i = j = 0; i < 10; i++)
633 if (codec->caps & (1 << i))
634 printf("%s%s", j++? ", " : "", ac97feature[i]);
635 printf("%s%d bit master volume", j++? ", " : "", codec->mix[SOUND_MIXER_VOLUME].bits);
636 printf("%s%s\n", j? ", " : "", ac97enhancement[codec->se]);
638 if (codec->extcaps != 0 || codec->extid) {
639 device_printf(codec->dev, "%s codec",
640 codec->extid? "Secondary" : "Primary");
642 printf(" extended features ");
643 for (i = j = 0; i < 14; i++)
644 if (codec->extcaps & (1 << i))
645 printf("%s%s", j++? ", " : "", ac97extfeature[i]);
650 if ((ac97_rdcd(codec, AC97_REG_POWER) & 2) == 0)
651 device_printf(codec->dev, "ac97 codec reports dac not ready\n");
652 snd_mtxunlock(codec->lock);
657 ac97_reinitmixer(struct ac97_info *codec)
659 snd_mtxlock(codec->lock);
660 codec->count = AC97_INIT(codec->methods, codec->devinfo);
661 if (codec->count == 0) {
662 device_printf(codec->dev, "ac97 codec init failed\n");
663 snd_mtxunlock(codec->lock);
667 ac97_wrcd(codec, AC97_REG_POWER, (codec->flags & AC97_F_EAPD_INV)? 0x8000 : 0x0000);
669 ac97_wrcd(codec, AC97_REG_POWER, (codec->flags & AC97_F_EAPD_INV)? 0x8000 : 0x0000);
672 ac97_wrcd(codec, AC97_REGEXT_STAT, codec->extstat);
673 if ((ac97_rdcd(codec, AC97_REGEXT_STAT) & AC97_EXTCAPS)
675 device_printf(codec->dev, "ac97 codec failed to reset extended mode (%x, got %x)\n",
677 ac97_rdcd(codec, AC97_REGEXT_STAT) &
681 if ((ac97_rdcd(codec, AC97_REG_POWER) & 2) == 0)
682 device_printf(codec->dev, "ac97 codec reports dac not ready\n");
683 snd_mtxunlock(codec->lock);
688 ac97_create(device_t dev, void *devinfo, kobj_class_t cls)
690 struct ac97_info *codec;
692 codec = (struct ac97_info *)malloc(sizeof *codec, M_AC97, M_NOWAIT);
696 snprintf(codec->name, AC97_NAMELEN, "%s:ac97", device_get_nameunit(dev));
697 codec->lock = snd_mtxcreate(codec->name, "ac97 codec");
698 codec->methods = kobj_create(cls, M_AC97, 0);
699 if (codec->methods == NULL) {
700 snd_mtxlock(codec->lock);
701 snd_mtxfree(codec->lock);
707 codec->devinfo = devinfo;
713 ac97_destroy(struct ac97_info *codec)
715 snd_mtxlock(codec->lock);
716 if (codec->methods != NULL)
717 kobj_delete(codec->methods, M_AC97);
718 snd_mtxfree(codec->lock);
723 ac97_setflags(struct ac97_info *codec, u_int32_t val)
729 ac97_getflags(struct ac97_info *codec)
734 /* -------------------------------------------------------------------- */
737 ac97mix_init(struct snd_mixer *m)
739 struct ac97_info *codec = mix_getdevinfo(m);
745 if (ac97_initmixer(codec))
749 for (i = 0; i < 32; i++)
750 mask |= codec->mix[i].enable? 1 << i : 0;
751 mix_setdevs(m, mask);
754 for (i = 0; i < 32; i++)
755 mask |= codec->mix[i].recidx? 1 << i : 0;
756 mix_setrecdevs(m, mask);
761 ac97mix_uninit(struct snd_mixer *m)
763 struct ac97_info *codec = mix_getdevinfo(m);
768 if (ac97_uninitmixer(codec))
776 ac97mix_reinit(struct snd_mixer *m)
778 struct ac97_info *codec = mix_getdevinfo(m);
782 return ac97_reinitmixer(codec);
786 ac97mix_set(struct snd_mixer *m, unsigned dev, unsigned left, unsigned right)
788 struct ac97_info *codec = mix_getdevinfo(m);
792 return ac97_setmixer(codec, dev, left, right);
796 ac97mix_setrecsrc(struct snd_mixer *m, u_int32_t src)
799 struct ac97_info *codec = mix_getdevinfo(m);
803 for (i = 0; i < SOUND_MIXER_NRDEVICES; i++)
804 if ((src & (1 << i)) != 0)
806 return (ac97_setrecsrc(codec, i) == 0)? 1 << i : -1;
809 static kobj_method_t ac97mixer_methods[] = {
810 KOBJMETHOD(mixer_init, ac97mix_init),
811 KOBJMETHOD(mixer_uninit, ac97mix_uninit),
812 KOBJMETHOD(mixer_reinit, ac97mix_reinit),
813 KOBJMETHOD(mixer_set, ac97mix_set),
814 KOBJMETHOD(mixer_setrecsrc, ac97mix_setrecsrc),
817 MIXER_DECLARE(ac97mixer);
819 /* -------------------------------------------------------------------- */
822 ac97_getmixerclass(void)
824 return &ac97mixer_class;