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.20 2006/09/05 00:55:43 dillon 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.20 2006/09/05 00:55:43 dillon 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" }, /* Nowadays Realtek */
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 { 0x414c4750, 0x0f, 0, "ALC250", 0 },
151 { 0x414c4760, 0x0f, 0, "ALC655", 0 },
152 { 0x414c4770, 0x0f, 0, "ALC203", 0 },
153 { 0x414c4780, 0x0f, 0, "ALC658", 0 },
154 { 0x414c4790, 0x0f, 0, "ALC850", 0 },
155 { 0x43525900, 0x07, 0, "CS4297", 0 },
156 { 0x43525910, 0x07, 0, "CS4297A", 0 },
157 { 0x43525920, 0x07, 0, "CS4294/98", 0 },
158 { 0x4352592d, 0x07, 0, "CS4294", 0 },
159 { 0x43525930, 0x07, 0, "CS4299", 0 },
160 { 0x43525940, 0x07, 0, "CS4201", 0 },
161 { 0x43525958, 0x07, 0, "CS4205", 0 },
162 { 0x43525960, 0x07, 0, "CS4291A", 0 },
163 { 0x434d4961, 0x00, 0, "CMI9739", 0 },
164 { 0x434d4941, 0x00, 0, "CMI9738", 0 },
165 { 0x43585421, 0x00, 0, "HSD11246", 0 },
166 { 0x43585428, 0x07, 0, "CX20468", 0 },
167 { 0x44543000, 0x00, 0, "DT0398", 0 },
168 { 0x454d4323, 0x00, 0, "EM28023", 0 },
169 { 0x454d4328, 0x00, 0, "EM28028", 0 },
170 { 0x45838308, 0x00, 0, "ES1988", 0 }, /* Formerly ES1921(?) */
171 { 0x48525300, 0x00, 0, "HMP9701", 0 },
172 { 0x49434501, 0x00, 0, "ICE1230", 0 },
173 { 0x49434511, 0x00, 0, "ICE1232", 0 },
174 { 0x49434514, 0x00, 0, "ICE1232A", 0 },
175 { 0x49434551, 0x03, 0, "VT1616", 0 }, /* Via badged ICE */
176 { 0x49544520, 0x00, 0, "ITE2226E", 0 },
177 { 0x49544560, 0x07, 0, "ITE2646E", 0 }, /* XXX: patch needed */
178 { 0x4e534340, 0x00, 0, "LM4540", 0 }, /* Spec blank on revid */
179 { 0x4e534343, 0x00, 0, "LM4543", 0 }, /* Ditto */
180 { 0x4e534346, 0x00, 0, "LM4546A", 0 },
181 { 0x4e534348, 0x00, 0, "LM4548A", 0 },
182 { 0x4e534331, 0x00, 0, "LM4549", 0 },
183 { 0x4e534349, 0x00, 0, "LM4549A", 0 },
184 { 0x4e534350, 0x00, 0, "LM4550", 0 },
185 { 0x50534301, 0x00, 0, "UCB1510", 0 },
186 { 0x50534304, 0x00, 0, "UCB1400", 0 },
187 { 0x83847600, 0x00, 0, "STAC9700/83/84", 0 },
188 { 0x83847604, 0x00, 0, "STAC9701/03/04/05", 0 },
189 { 0x83847605, 0x00, 0, "STAC9704", 0 },
190 { 0x83847608, 0x00, 0, "STAC9708/11", 0 },
191 { 0x83847609, 0x00, 0, "STAC9721/23", 0 },
192 { 0x83847644, 0x00, 0, "STAC9744/45", 0 },
193 { 0x83847650, 0x00, 0, "STAC9750/51", 0 },
194 { 0x83847652, 0x00, 0, "STAC9752/53", 0 },
195 { 0x83847656, 0x00, 0, "STAC9756/57", 0 },
196 { 0x83847658, 0x00, 0, "STAC9758/59", 0 },
197 { 0x83847660, 0x00, 0, "STAC9760/61", 0 }, /* Extrapolated */
198 { 0x83847662, 0x00, 0, "STAC9762/63", 0 }, /* Extrapolated */
199 { 0x53494c22, 0x00, 0, "Si3036", 0 },
200 { 0x53494c23, 0x00, 0, "Si3038", 0 },
201 { 0x54524103, 0x00, 0, "TR28023", 0 }, /* Extrapolated */
202 { 0x54524106, 0x00, 0, "TR28026", 0 },
203 { 0x54524108, 0x00, 0, "TR28028", 0 },
204 { 0x54524123, 0x00, 0, "TR28602", 0 },
205 { 0x54524e03, 0x07, 0, "TLV320AIC27", 0 },
206 { 0x54584e20, 0x00, 0, "TLC320AD90", 0 },
207 { 0x56494161, 0x00, 0, "VIA1612A", 0 },
208 { 0x574d4c00, 0x00, 0, "WM9701A", 0 },
209 { 0x574d4c03, 0x00, 0, "WM9703/4/7/8", 0 },
210 { 0x574d4c04, 0x00, 0, "WM9704Q", 0 },
211 { 0x574d4c05, 0x00, 0, "WM9705/10", 0 },
212 { 0x574d4d09, 0x00, 0, "WM9709", 0 },
213 { 0x574d4c12, 0x00, 0, "WM9711/12", 0 }, /* XXX: patch needed */
214 { 0x57454301, 0x00, 0, "W83971D", 0 },
215 { 0x594d4800, 0x00, 0, "YMF743", 0 },
216 { 0x594d4802, 0x00, 0, "YMF752", 0 },
217 { 0x594d4803, 0x00, 0, "YMF753", 0 },
218 { 0x01408384, 0x00, 0, "EV1938", 0 },
222 static char *ac97enhancement[] = {
223 "no 3D Stereo Enhancement",
224 "Analog Devices Phat Stereo",
225 "Creative Stereo Enhancement",
226 "National Semi 3D Stereo Enhancement",
228 "BBE 3D Stereo Enhancement",
229 "Crystal Semi 3D Stereo Enhancement",
231 "Spatializer 3D Stereo Enhancement",
232 "SRS 3D Stereo Enhancement",
233 "Platform Tech 3D Stereo Enhancement",
235 "Aureal Stereo Enhancement",
236 "Aztech 3D Enhancement",
237 "Binaura 3D Audio Enhancement",
238 "ESS Technology Stereo Enhancement",
239 "Harman International VMAx",
240 "Nvidea 3D Stereo Enhancement",
241 "Philips Incredible Sound",
242 "Texas Instruments 3D Stereo Enhancement",
243 "VLSI Technology 3D Stereo Enhancement",
244 "TriTech 3D Stereo Enhancement",
245 "Realtek 3D Stereo Enhancement",
246 "Samsung 3D Stereo Enhancement",
247 "Wolfson Microelectronics 3D Enhancement",
248 "Delta Integration 3D Enhancement",
249 "SigmaTel 3D Enhancement",
251 "Rockwell 3D Stereo Enhancement",
257 static char *ac97feature[] = {
270 static char *ac97extfeature[] = {
288 ac97_rdcd(struct ac97_info *codec, int reg)
290 return AC97_READ(codec->methods, codec->devinfo, reg);
294 ac97_wrcd(struct ac97_info *codec, int reg, u_int16_t val)
296 AC97_WRITE(codec->methods, codec->devinfo, reg, val);
300 ac97_reset(struct ac97_info *codec)
303 ac97_wrcd(codec, AC97_REG_RESET, 0);
304 for (i = 0; i < 500; i++) {
305 ps = ac97_rdcd(codec, AC97_REG_POWER) & AC97_POWER_STATUS;
306 if (ps == AC97_POWER_STATUS)
310 device_printf(codec->dev, "AC97 reset timed out.\n");
314 ac97_setrate(struct ac97_info *codec, int which, int rate)
319 case AC97_REGEXT_FDACRATE:
320 case AC97_REGEXT_SDACRATE:
321 case AC97_REGEXT_LDACRATE:
322 case AC97_REGEXT_LADCRATE:
323 case AC97_REGEXT_MADCRATE:
330 snd_mtxlock(codec->lock);
333 if (codec->extstat & AC97_EXTCAP_DRA)
335 ac97_wrcd(codec, which, v);
337 v = ac97_rdcd(codec, which);
338 if (codec->extstat & AC97_EXTCAP_DRA)
340 snd_mtxunlock(codec->lock);
345 ac97_setextmode(struct ac97_info *codec, u_int16_t mode)
347 mode &= AC97_EXTCAPS;
348 if ((mode & ~codec->extcaps) != 0) {
349 device_printf(codec->dev, "ac97 invalid mode set 0x%04x\n",
353 snd_mtxlock(codec->lock);
354 ac97_wrcd(codec, AC97_REGEXT_STAT, mode);
355 codec->extstat = ac97_rdcd(codec, AC97_REGEXT_STAT) & AC97_EXTCAPS;
356 snd_mtxunlock(codec->lock);
357 return (mode == codec->extstat)? 0 : -1;
361 ac97_getextmode(struct ac97_info *codec)
363 return codec->extstat;
367 ac97_getextcaps(struct ac97_info *codec)
369 return codec->extcaps;
373 ac97_getcaps(struct ac97_info *codec)
379 ac97_setrecsrc(struct ac97_info *codec, int channel)
381 struct ac97mixtable_entry *e = &codec->mix[channel];
384 int val = e->recidx - 1;
386 snd_mtxlock(codec->lock);
387 ac97_wrcd(codec, AC97_REG_RECSEL, val);
388 snd_mtxunlock(codec->lock);
395 ac97_setmixer(struct ac97_info *codec, unsigned channel, unsigned left, unsigned right)
397 struct ac97mixtable_entry *e = &codec->mix[channel];
399 if (e->reg && e->enable && e->bits) {
400 int mask, max, val, reg;
402 reg = (e->reg >= 0) ? e->reg : -e->reg; /* AC97 register */
403 max = (1 << e->bits) - 1; /* actual range */
404 mask = (max << 8) | max; /* bits of interest */
410 * Invert the range if the polarity requires so,
411 * then scale to 0..max-1 to compute the value to
412 * write into the codec, and scale back to 0..100
413 * for the return value.
420 left = (left * max) / 100;
421 right = (right * max) / 100;
423 val = (left << 8) | right;
425 left = (left * 100) / max;
426 right = (right * 100) / max;
434 * For mono controls, trim val and mask, also taking
435 * care of e->ofs (offset of control field).
440 mask = (max << e->ofs);
444 * If we have a mute bit, add it to the mask and
445 * update val and set mute if both channels require a
450 if (left == 0 && right == 0)
455 * If the mask bit is set, do not alter the other bits.
457 snd_mtxlock(codec->lock);
459 int cur = ac97_rdcd(codec, e->reg);
460 val |= cur & ~(mask);
462 ac97_wrcd(codec, reg, val);
463 snd_mtxunlock(codec->lock);
464 return left | (right << 8);
466 /* printf("ac97_setmixer: reg=%d, bits=%d, enable=%d\n", e->reg, e->bits, e->enable); */
472 ac97_fix_auxout(struct ac97_info *codec)
477 * By default, The ac97 aux_out register (0x04) corresponds to OSS's
480 * We first check whether aux_out is a valid register. If not
481 * we may not want to keep ogain.
483 keep_ogain = ac97_rdcd(codec, AC97_MIX_AUXOUT) & 0x8000;
486 * Determine what AUX_OUT really means, it can be:
490 * 3. True line level out (effectively master volume).
492 * See Sections 5.2.1 and 5.27 for AUX_OUT Options in AC97r2.{2,3}.
494 if (codec->extcaps & AC97_EXTCAP_SDAC &&
495 ac97_rdcd(codec, AC97_MIXEXT_SURROUND) == 0x8080) {
496 codec->mix[SOUND_MIXER_OGAIN].reg = AC97_MIXEXT_SURROUND;
500 if (keep_ogain == 0) {
501 bzero(&codec->mix[SOUND_MIXER_OGAIN],
502 sizeof(codec->mix[SOUND_MIXER_OGAIN]));
507 ac97_fix_tone(struct ac97_info *codec)
509 /* Hide treble and bass if they don't exist */
510 if ((codec->caps & AC97_CAP_TONE) == 0) {
511 bzero(&codec->mix[SOUND_MIXER_BASS],
512 sizeof(codec->mix[SOUND_MIXER_BASS]));
513 bzero(&codec->mix[SOUND_MIXER_TREBLE],
514 sizeof(codec->mix[SOUND_MIXER_TREBLE]));
519 ac97_hw_desc(u_int32_t id, const char* vname, const char* cname, char* buf)
522 sprintf(buf, "Unknown AC97 Codec (id = 0x%08x)", id);
526 if (vname == NULL) vname = "Unknown";
529 sprintf(buf, "%s %s AC97 Codec (id = 0x%08x)", vname, cname, id);
531 sprintf(buf, "%s %s AC97 Codec", vname, cname);
537 ac97_initmixer(struct ac97_info *codec)
539 ac97_patch codec_patch;
540 const char *cname, *vname;
542 u_int8_t model, step;
543 unsigned i, j, k, old;
546 snd_mtxlock(codec->lock);
547 codec->count = AC97_INIT(codec->methods, codec->devinfo);
548 if (codec->count == 0) {
549 device_printf(codec->dev, "ac97 codec init failed\n");
550 snd_mtxunlock(codec->lock);
554 ac97_wrcd(codec, AC97_REG_POWER, (codec->flags & AC97_F_EAPD_INV)? 0x8000 : 0x0000);
556 ac97_wrcd(codec, AC97_REG_POWER, (codec->flags & AC97_F_EAPD_INV)? 0x8000 : 0x0000);
558 i = ac97_rdcd(codec, AC97_REG_RESET);
559 codec->caps = i & 0x03ff;
560 codec->se = (i & 0x7c00) >> 10;
562 id = (ac97_rdcd(codec, AC97_REG_ID1) << 16) | ac97_rdcd(codec, AC97_REG_ID2);
563 if (id == 0 || id == 0xffffffff) {
564 device_printf(codec->dev, "ac97 codec invalid or not present (id == %x)\n", id);
565 snd_mtxunlock(codec->lock);
575 for (i = 0; ac97codecid[i].id; i++) {
576 u_int32_t modelmask = 0xffffffff ^ ac97codecid[i].stepmask;
577 if ((ac97codecid[i].id & modelmask) == (id & modelmask)) {
578 codec->noext = ac97codecid[i].noext;
579 codec_patch = ac97codecid[i].patch;
580 cname = ac97codecid[i].name;
581 model = (id & modelmask) & 0xff;
582 step = (id & ~modelmask) & 0xff;
588 for (i = 0; ac97vendorid[i].id; i++) {
589 if (ac97vendorid[i].id == (id & 0xffffff00)) {
590 vname = ac97vendorid[i].name;
599 i = ac97_rdcd(codec, AC97_REGEXT_ID);
601 codec->extcaps = i & 0x3fff;
602 codec->extid = (i & 0xc000) >> 14;
603 codec->extstat = ac97_rdcd(codec, AC97_REGEXT_STAT) & AC97_EXTCAPS;
607 for (i = 0; i < 32; i++) {
608 codec->mix[i] = ac97mixtable_default[i];
610 ac97_fix_auxout(codec);
611 ac97_fix_tone(codec);
615 for (i = 0; i < 32; i++) {
616 k = codec->noext? codec->mix[i].enable : 1;
617 if (k && (codec->mix[i].reg > 0)) {
618 old = ac97_rdcd(codec, codec->mix[i].reg);
619 ac97_wrcd(codec, codec->mix[i].reg, 0x3f);
620 j = ac97_rdcd(codec, codec->mix[i].reg);
621 ac97_wrcd(codec, codec->mix[i].reg, old);
622 codec->mix[i].enable = (j != 0 && j != old)? 1 : 0;
623 for (k = 1; j & (1 << k); k++);
624 codec->mix[i].bits = j? k - codec->mix[i].ofs : 0;
626 /* printf("mixch %d, en=%d, b=%d\n", i, codec->mix[i].enable, codec->mix[i].bits); */
629 device_printf(codec->dev, "<%s>\n",
630 ac97_hw_desc(codec->id, vname, cname, desc));
633 device_printf(codec->dev, "Codec features ");
634 for (i = j = 0; i < 10; i++)
635 if (codec->caps & (1 << i))
636 printf("%s%s", j++? ", " : "", ac97feature[i]);
637 printf("%s%d bit master volume", j++? ", " : "", codec->mix[SOUND_MIXER_VOLUME].bits);
638 printf("%s%s\n", j? ", " : "", ac97enhancement[codec->se]);
640 if (codec->extcaps != 0 || codec->extid) {
641 device_printf(codec->dev, "%s codec",
642 codec->extid? "Secondary" : "Primary");
644 printf(" extended features ");
645 for (i = j = 0; i < 14; i++)
646 if (codec->extcaps & (1 << i))
647 printf("%s%s", j++? ", " : "", ac97extfeature[i]);
652 if ((ac97_rdcd(codec, AC97_REG_POWER) & 2) == 0)
653 device_printf(codec->dev, "ac97 codec reports dac not ready\n");
654 snd_mtxunlock(codec->lock);
659 ac97_reinitmixer(struct ac97_info *codec)
661 snd_mtxlock(codec->lock);
662 codec->count = AC97_INIT(codec->methods, codec->devinfo);
663 if (codec->count == 0) {
664 device_printf(codec->dev, "ac97 codec init failed\n");
665 snd_mtxunlock(codec->lock);
669 ac97_wrcd(codec, AC97_REG_POWER, (codec->flags & AC97_F_EAPD_INV)? 0x8000 : 0x0000);
671 ac97_wrcd(codec, AC97_REG_POWER, (codec->flags & AC97_F_EAPD_INV)? 0x8000 : 0x0000);
674 ac97_wrcd(codec, AC97_REGEXT_STAT, codec->extstat);
675 if ((ac97_rdcd(codec, AC97_REGEXT_STAT) & AC97_EXTCAPS)
677 device_printf(codec->dev, "ac97 codec failed to reset extended mode (%x, got %x)\n",
679 ac97_rdcd(codec, AC97_REGEXT_STAT) &
683 if ((ac97_rdcd(codec, AC97_REG_POWER) & 2) == 0)
684 device_printf(codec->dev, "ac97 codec reports dac not ready\n");
685 snd_mtxunlock(codec->lock);
690 ac97_create(device_t dev, void *devinfo, kobj_class_t cls)
692 struct ac97_info *codec;
694 codec = (struct ac97_info *)kmalloc(sizeof *codec, M_AC97, M_NOWAIT);
698 snprintf(codec->name, AC97_NAMELEN, "%s:ac97", device_get_nameunit(dev));
699 codec->lock = snd_mtxcreate(codec->name, "ac97 codec");
700 codec->methods = kobj_create(cls, M_AC97, 0);
701 if (codec->methods == NULL) {
702 snd_mtxlock(codec->lock);
703 snd_mtxfree(codec->lock);
704 kfree(codec, M_AC97);
709 codec->devinfo = devinfo;
715 ac97_destroy(struct ac97_info *codec)
717 snd_mtxlock(codec->lock);
718 if (codec->methods != NULL)
719 kobj_delete(codec->methods, M_AC97);
720 snd_mtxfree(codec->lock);
721 kfree(codec, M_AC97);
725 ac97_setflags(struct ac97_info *codec, u_int32_t val)
731 ac97_getflags(struct ac97_info *codec)
736 /* -------------------------------------------------------------------- */
739 ac97mix_init(struct snd_mixer *m)
741 struct ac97_info *codec = mix_getdevinfo(m);
747 if (ac97_initmixer(codec))
751 for (i = 0; i < 32; i++)
752 mask |= codec->mix[i].enable? 1 << i : 0;
753 mix_setdevs(m, mask);
756 for (i = 0; i < 32; i++)
757 mask |= codec->mix[i].recidx? 1 << i : 0;
758 mix_setrecdevs(m, mask);
763 ac97mix_uninit(struct snd_mixer *m)
765 struct ac97_info *codec = mix_getdevinfo(m);
770 if (ac97_uninitmixer(codec))
778 ac97mix_reinit(struct snd_mixer *m)
780 struct ac97_info *codec = mix_getdevinfo(m);
784 return ac97_reinitmixer(codec);
788 ac97mix_set(struct snd_mixer *m, unsigned dev, unsigned left, unsigned right)
790 struct ac97_info *codec = mix_getdevinfo(m);
794 return ac97_setmixer(codec, dev, left, right);
798 ac97mix_setrecsrc(struct snd_mixer *m, u_int32_t src)
801 struct ac97_info *codec = mix_getdevinfo(m);
805 for (i = 0; i < SOUND_MIXER_NRDEVICES; i++)
806 if ((src & (1 << i)) != 0)
808 return (ac97_setrecsrc(codec, i) == 0)? 1 << i : -1;
811 static kobj_method_t ac97mixer_methods[] = {
812 KOBJMETHOD(mixer_init, ac97mix_init),
813 KOBJMETHOD(mixer_uninit, ac97mix_uninit),
814 KOBJMETHOD(mixer_reinit, ac97mix_reinit),
815 KOBJMETHOD(mixer_set, ac97mix_set),
816 KOBJMETHOD(mixer_setrecsrc, ac97mix_setrecsrc),
819 MIXER_DECLARE(ac97mixer);
821 /* -------------------------------------------------------------------- */
824 ac97_getmixerclass(void)
826 return &ac97mixer_class;