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.5 2004/01/21 22:04:39 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.5 2004/01/21 22:04:39 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 Laboratory" },
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 { 0x414c4320, 0x0f, 0, "ALC100", 0 },
144 { 0x414c4730, 0x0f, 0, "ALC101", 0 },
145 { 0x414c4710, 0x0f, 0, "ALC200", 0 },
146 { 0x414c4740, 0x0f, 0, "ALC202", 0 },
147 { 0x414c4720, 0x0f, 0, "ALC650", 0 },
148 { 0x414c4760, 0x0f, 0, "ALC655", 0 },
149 { 0x414c4780, 0x0f, 0, "ALC658", 0 },
150 { 0x43525900, 0x07, 0, "CS4297", 0 },
151 { 0x43525910, 0x07, 0, "CS4297A", 0 },
152 { 0x43525920, 0x07, 0, "CS4294/98", 0 },
153 { 0x43525930, 0x07, 0, "CS4299", 0 },
154 { 0x43525940, 0x07, 0, "CS4201", 0 },
155 { 0x43525958, 0x07, 0, "CS4205", 0 },
156 { 0x43525960, 0x07, 0, "CS4291A", 0 },
157 { 0x434d4961, 0x00, 0, "CMI9739", 0 },
158 { 0x434d4941, 0x00, 0, "CMI9738", 0 },
159 { 0x43585429, 0x00, 0, "CX20468", 0 },
160 { 0x44543000, 0x00, 0, "DT0398", 0 },
161 { 0x454d4323, 0x00, 0, "EM28023", 0 },
162 { 0x454d4328, 0x00, 0, "EM28028", 0 },
163 { 0x45838308, 0x00, 0, "ES1988", 0 }, /* Formerly ES1921(?) */
164 { 0x48525300, 0x00, 0, "HMP9701", 0 },
165 { 0x49434501, 0x00, 0, "ICE1230", 0 },
166 { 0x49434511, 0x00, 0, "ICE1232", 0 },
167 { 0x49434514, 0x00, 0, "ICE1232A", 0 },
168 { 0x49434551, 0x03, 0, "VT1616", 0 }, /* Via badged ICE */
169 { 0x49544520, 0x00, 0, "ITE2226E", 0 },
170 { 0x49544560, 0x07, 0, "ITE2646E", 0 }, /* XXX: patch needed */
171 { 0x4e534340, 0x00, 0, "LM4540", 0 }, /* Spec blank on revid */
172 { 0x4e534343, 0x00, 0, "LM4543", 0 }, /* Ditto */
173 { 0x4e534346, 0x00, 0, "LM4546A", 0 },
174 { 0x4e534348, 0x00, 0, "LM4548A", 0 },
175 { 0x4e534331, 0x00, 0, "LM4549", 0 },
176 { 0x4e534349, 0x00, 0, "LM4549A", 0 },
177 { 0x4e534350, 0x00, 0, "LM4550", 0 },
178 { 0x50534301, 0x00, 0, "UCB1510", 0 },
179 { 0x50534304, 0x00, 0, "UCB1400", 0 },
180 { 0x83847600, 0x00, 0, "STAC9700/83/84", 0 },
181 { 0x83847604, 0x00, 0, "STAC9701/03/04/05", 0 },
182 { 0x83847605, 0x00, 0, "STAC9704", 0 },
183 { 0x83847608, 0x00, 0, "STAC9708/11", 0 },
184 { 0x83847609, 0x00, 0, "STAC9721/23", 0 },
185 { 0x83847644, 0x00, 0, "STAC9744/45", 0 },
186 { 0x83847650, 0x00, 0, "STAC9750/51", 0 },
187 { 0x83847652, 0x00, 0, "STAC9752/53", 0 },
188 { 0x83847656, 0x00, 0, "STAC9756/57", 0 },
189 { 0x83847658, 0x00, 0, "STAC9758/59", 0 },
190 { 0x83847660, 0x00, 0, "STAC9760/61", 0 }, /* Extrapolated */
191 { 0x83847662, 0x00, 0, "STAC9762/63", 0 }, /* Extrapolated */
192 { 0x53494c22, 0x00, 0, "Si3036", 0 },
193 { 0x53494c23, 0x00, 0, "Si3038", 0 },
194 { 0x54524103, 0x00, 0, "TR28023", 0 }, /* Extrapolated */
195 { 0x54524106, 0x00, 0, "TR28026", 0 },
196 { 0x54524108, 0x00, 0, "TR28028", 0 },
197 { 0x54524123, 0x00, 0, "TR28602", 0 },
198 { 0x54584320, 0x00, 0, "TLC320AD90", 0 },
199 { 0x56494161, 0x00, 0, "VIA1612A", 0 },
200 { 0x574d4c00, 0x00, 0, "WM9701A", 0 },
201 { 0x574d4c03, 0x00, 0, "WM9703/4/7/8", 0 },
202 { 0x574d4c04, 0x00, 0, "WM9704Q", 0 },
203 { 0x574d4c05, 0x00, 0, "WM9705/10", 0 },
204 { 0x57454301, 0x00, 0, "W83971D", 0 },
205 { 0x594d4800, 0x00, 0, "YMF743", 0 },
206 { 0x594d4802, 0x00, 0, "YMF752", 0 },
207 { 0x594d4803, 0x00, 0, "YMF753", 0 },
208 { 0x01408384, 0x00, 0, "EV1938", 0 },
212 static char *ac97enhancement[] = {
213 "no 3D Stereo Enhancement",
214 "Analog Devices Phat Stereo",
215 "Creative Stereo Enhancement",
216 "National Semi 3D Stereo Enhancement",
218 "BBE 3D Stereo Enhancement",
219 "Crystal Semi 3D Stereo Enhancement",
221 "Spatializer 3D Stereo Enhancement",
222 "SRS 3D Stereo Enhancement",
223 "Platform Tech 3D Stereo Enhancement",
225 "Aureal Stereo Enhancement",
226 "Aztech 3D Enhancement",
227 "Binaura 3D Audio Enhancement",
228 "ESS Technology Stereo Enhancement",
229 "Harman International VMAx",
230 "Nvidea 3D Stereo Enhancement",
231 "Philips Incredible Sound",
232 "Texas Instruments 3D Stereo Enhancement",
233 "VLSI Technology 3D Stereo Enhancement",
234 "TriTech 3D Stereo Enhancement",
235 "Realtek 3D Stereo Enhancement",
236 "Samsung 3D Stereo Enhancement",
237 "Wolfson Microelectronics 3D Enhancement",
238 "Delta Integration 3D Enhancement",
239 "SigmaTel 3D Enhancement",
241 "Rockwell 3D Stereo Enhancement",
247 static char *ac97feature[] = {
260 static char *ac97extfeature[] = {
278 ac97_rdcd(struct ac97_info *codec, int reg)
280 return AC97_READ(codec->methods, codec->devinfo, reg);
284 ac97_wrcd(struct ac97_info *codec, int reg, u_int16_t val)
286 AC97_WRITE(codec->methods, codec->devinfo, reg, val);
290 ac97_reset(struct ac97_info *codec)
293 ac97_wrcd(codec, AC97_REG_RESET, 0);
294 for (i = 0; i < 500; i++) {
295 ps = ac97_rdcd(codec, AC97_REG_POWER) & AC97_POWER_STATUS;
296 if (ps == AC97_POWER_STATUS)
300 device_printf(codec->dev, "AC97 reset timed out.\n");
304 ac97_setrate(struct ac97_info *codec, int which, int rate)
309 case AC97_REGEXT_FDACRATE:
310 case AC97_REGEXT_SDACRATE:
311 case AC97_REGEXT_LDACRATE:
312 case AC97_REGEXT_LADCRATE:
313 case AC97_REGEXT_MADCRATE:
320 snd_mtxlock(codec->lock);
323 if (codec->extstat & AC97_EXTCAP_DRA)
325 ac97_wrcd(codec, which, v);
327 v = ac97_rdcd(codec, which);
328 if (codec->extstat & AC97_EXTCAP_DRA)
330 snd_mtxunlock(codec->lock);
335 ac97_setextmode(struct ac97_info *codec, u_int16_t mode)
337 mode &= AC97_EXTCAPS;
338 if ((mode & ~codec->extcaps) != 0) {
339 device_printf(codec->dev, "ac97 invalid mode set 0x%04x\n",
343 snd_mtxlock(codec->lock);
344 ac97_wrcd(codec, AC97_REGEXT_STAT, mode);
345 codec->extstat = ac97_rdcd(codec, AC97_REGEXT_STAT) & AC97_EXTCAPS;
346 snd_mtxunlock(codec->lock);
347 return (mode == codec->extstat)? 0 : -1;
351 ac97_getextmode(struct ac97_info *codec)
353 return codec->extstat;
357 ac97_getextcaps(struct ac97_info *codec)
359 return codec->extcaps;
363 ac97_getcaps(struct ac97_info *codec)
369 ac97_setrecsrc(struct ac97_info *codec, int channel)
371 struct ac97mixtable_entry *e = &codec->mix[channel];
374 int val = e->recidx - 1;
376 snd_mtxlock(codec->lock);
377 ac97_wrcd(codec, AC97_REG_RECSEL, val);
378 snd_mtxunlock(codec->lock);
385 ac97_setmixer(struct ac97_info *codec, unsigned channel, unsigned left, unsigned right)
387 struct ac97mixtable_entry *e = &codec->mix[channel];
389 if (e->reg && e->enable && e->bits) {
390 int mask, max, val, reg;
392 reg = (e->reg >= 0) ? e->reg : -e->reg; /* AC97 register */
393 max = (1 << e->bits) - 1; /* actual range */
394 mask = (max << 8) | max; /* bits of interest */
400 * Invert the range if the polarity requires so,
401 * then scale to 0..max-1 to compute the value to
402 * write into the codec, and scale back to 0..100
403 * for the return value.
410 left = (left * max) / 100;
411 right = (right * max) / 100;
413 val = (left << 8) | right;
415 left = (left * 100) / max;
416 right = (right * 100) / max;
424 * For mono controls, trim val and mask, also taking
425 * care of e->ofs (offset of control field).
430 mask = (max << e->ofs);
434 * If we have a mute bit, add it to the mask and
435 * update val and set mute if both channels require a
440 if (left == 0 && right == 0)
445 * If the mask bit is set, do not alter the other bits.
447 snd_mtxlock(codec->lock);
449 int cur = ac97_rdcd(codec, e->reg);
450 val |= cur & ~(mask);
452 ac97_wrcd(codec, reg, val);
453 snd_mtxunlock(codec->lock);
454 return left | (right << 8);
456 /* printf("ac97_setmixer: reg=%d, bits=%d, enable=%d\n", e->reg, e->bits, e->enable); */
462 ac97_fix_auxout(struct ac97_info *codec)
467 * By default, The ac97 aux_out register (0x04) corresponds to OSS's
470 * We first check whether aux_out is a valid register. If not
471 * we may not want to keep ogain.
473 keep_ogain = ac97_rdcd(codec, AC97_MIX_AUXOUT) & 0x8000;
476 * Determine what AUX_OUT really means, it can be:
480 * 3. True line level out (effectively master volume).
482 * See Sections 5.2.1 and 5.27 for AUX_OUT Options in AC97r2.{2,3}.
484 if (codec->extcaps & AC97_EXTCAP_SDAC &&
485 ac97_rdcd(codec, AC97_MIXEXT_SURROUND) == 0x8080) {
486 codec->mix[SOUND_MIXER_OGAIN].reg = AC97_MIXEXT_SURROUND;
490 if (keep_ogain == 0) {
491 bzero(&codec->mix[SOUND_MIXER_OGAIN],
492 sizeof(codec->mix[SOUND_MIXER_OGAIN]));
497 ac97_fix_tone(struct ac97_info *codec)
499 /* Hide treble and bass if they don't exist */
500 if ((codec->caps & AC97_CAP_TONE) == 0) {
501 bzero(&codec->mix[SOUND_MIXER_BASS],
502 sizeof(codec->mix[SOUND_MIXER_BASS]));
503 bzero(&codec->mix[SOUND_MIXER_TREBLE],
504 sizeof(codec->mix[SOUND_MIXER_TREBLE]));
509 ac97_hw_desc(u_int32_t id, const char* vname, const char* cname, char* buf)
512 sprintf(buf, "Unknown AC97 Codec (id = 0x%08x)", id);
516 if (vname == NULL) vname = "Unknown";
519 sprintf(buf, "%s %s AC97 Codec (id = 0x%08x)", vname, cname, id);
521 sprintf(buf, "%s %s AC97 Codec", vname, cname);
527 ac97_initmixer(struct ac97_info *codec)
529 ac97_patch codec_patch;
530 const char *cname, *vname;
532 u_int8_t model, step;
533 unsigned i, j, k, old;
536 snd_mtxlock(codec->lock);
537 codec->count = AC97_INIT(codec->methods, codec->devinfo);
538 if (codec->count == 0) {
539 device_printf(codec->dev, "ac97 codec init failed\n");
540 snd_mtxunlock(codec->lock);
544 ac97_wrcd(codec, AC97_REG_POWER, (codec->flags & AC97_F_EAPD_INV)? 0x8000 : 0x0000);
546 ac97_wrcd(codec, AC97_REG_POWER, (codec->flags & AC97_F_EAPD_INV)? 0x8000 : 0x0000);
548 i = ac97_rdcd(codec, AC97_REG_RESET);
549 codec->caps = i & 0x03ff;
550 codec->se = (i & 0x7c00) >> 10;
552 id = (ac97_rdcd(codec, AC97_REG_ID1) << 16) | ac97_rdcd(codec, AC97_REG_ID2);
553 if (id == 0 || id == 0xffffffff) {
554 device_printf(codec->dev, "ac97 codec invalid or not present (id == %x)\n", id);
555 snd_mtxunlock(codec->lock);
565 for (i = 0; ac97codecid[i].id; i++) {
566 u_int32_t modelmask = 0xffffffff ^ ac97codecid[i].stepmask;
567 if ((ac97codecid[i].id & modelmask) == (id & modelmask)) {
568 codec->noext = ac97codecid[i].noext;
569 codec_patch = ac97codecid[i].patch;
570 cname = ac97codecid[i].name;
571 model = (id & modelmask) & 0xff;
572 step = (id & ~modelmask) & 0xff;
578 for (i = 0; ac97vendorid[i].id; i++) {
579 if (ac97vendorid[i].id == (id & 0xffffff00)) {
580 vname = ac97vendorid[i].name;
589 i = ac97_rdcd(codec, AC97_REGEXT_ID);
591 codec->extcaps = i & 0x3fff;
592 codec->extid = (i & 0xc000) >> 14;
593 codec->extstat = ac97_rdcd(codec, AC97_REGEXT_STAT) & AC97_EXTCAPS;
597 for (i = 0; i < 32; i++) {
598 codec->mix[i] = ac97mixtable_default[i];
600 ac97_fix_auxout(codec);
601 ac97_fix_tone(codec);
605 for (i = 0; i < 32; i++) {
606 k = codec->noext? codec->mix[i].enable : 1;
607 if (k && (codec->mix[i].reg > 0)) {
608 old = ac97_rdcd(codec, codec->mix[i].reg);
609 ac97_wrcd(codec, codec->mix[i].reg, 0x3f);
610 j = ac97_rdcd(codec, codec->mix[i].reg);
611 ac97_wrcd(codec, codec->mix[i].reg, old);
612 codec->mix[i].enable = (j != 0 && j != old)? 1 : 0;
613 for (k = 1; j & (1 << k); k++);
614 codec->mix[i].bits = j? k - codec->mix[i].ofs : 0;
616 /* printf("mixch %d, en=%d, b=%d\n", i, codec->mix[i].enable, codec->mix[i].bits); */
619 device_printf(codec->dev, "<%s>\n",
620 ac97_hw_desc(codec->id, vname, cname, desc));
623 device_printf(codec->dev, "Codec features ");
624 for (i = j = 0; i < 10; i++)
625 if (codec->caps & (1 << i))
626 printf("%s%s", j++? ", " : "", ac97feature[i]);
627 printf("%s%d bit master volume", j++? ", " : "", codec->mix[SOUND_MIXER_VOLUME].bits);
628 printf("%s%s\n", j? ", " : "", ac97enhancement[codec->se]);
630 if (codec->extcaps != 0 || codec->extid) {
631 device_printf(codec->dev, "%s codec",
632 codec->extid? "Secondary" : "Primary");
634 printf(" extended features ");
635 for (i = j = 0; i < 14; i++)
636 if (codec->extcaps & (1 << i))
637 printf("%s%s", j++? ", " : "", ac97extfeature[i]);
642 if ((ac97_rdcd(codec, AC97_REG_POWER) & 2) == 0)
643 device_printf(codec->dev, "ac97 codec reports dac not ready\n");
644 snd_mtxunlock(codec->lock);
649 ac97_reinitmixer(struct ac97_info *codec)
651 snd_mtxlock(codec->lock);
652 codec->count = AC97_INIT(codec->methods, codec->devinfo);
653 if (codec->count == 0) {
654 device_printf(codec->dev, "ac97 codec init failed\n");
655 snd_mtxunlock(codec->lock);
659 ac97_wrcd(codec, AC97_REG_POWER, (codec->flags & AC97_F_EAPD_INV)? 0x8000 : 0x0000);
661 ac97_wrcd(codec, AC97_REG_POWER, (codec->flags & AC97_F_EAPD_INV)? 0x8000 : 0x0000);
664 ac97_wrcd(codec, AC97_REGEXT_STAT, codec->extstat);
665 if ((ac97_rdcd(codec, AC97_REGEXT_STAT) & AC97_EXTCAPS)
667 device_printf(codec->dev, "ac97 codec failed to reset extended mode (%x, got %x)\n",
669 ac97_rdcd(codec, AC97_REGEXT_STAT) &
673 if ((ac97_rdcd(codec, AC97_REG_POWER) & 2) == 0)
674 device_printf(codec->dev, "ac97 codec reports dac not ready\n");
675 snd_mtxunlock(codec->lock);
680 ac97_create(device_t dev, void *devinfo, kobj_class_t cls)
682 struct ac97_info *codec;
684 codec = (struct ac97_info *)malloc(sizeof *codec, M_AC97, M_NOWAIT);
688 snprintf(codec->name, AC97_NAMELEN, "%s:ac97", device_get_nameunit(dev));
689 codec->lock = snd_mtxcreate(codec->name, "ac97 codec");
690 codec->methods = kobj_create(cls, M_AC97, 0);
691 if (codec->methods == NULL) {
692 snd_mtxlock(codec->lock);
693 snd_mtxfree(codec->lock);
699 codec->devinfo = devinfo;
705 ac97_destroy(struct ac97_info *codec)
707 snd_mtxlock(codec->lock);
708 if (codec->methods != NULL)
709 kobj_delete(codec->methods, M_AC97);
710 snd_mtxfree(codec->lock);
715 ac97_setflags(struct ac97_info *codec, u_int32_t val)
721 ac97_getflags(struct ac97_info *codec)
726 /* -------------------------------------------------------------------- */
729 ac97mix_init(struct snd_mixer *m)
731 struct ac97_info *codec = mix_getdevinfo(m);
737 if (ac97_initmixer(codec))
741 for (i = 0; i < 32; i++)
742 mask |= codec->mix[i].enable? 1 << i : 0;
743 mix_setdevs(m, mask);
746 for (i = 0; i < 32; i++)
747 mask |= codec->mix[i].recidx? 1 << i : 0;
748 mix_setrecdevs(m, mask);
753 ac97mix_uninit(struct snd_mixer *m)
755 struct ac97_info *codec = mix_getdevinfo(m);
760 if (ac97_uninitmixer(codec))
768 ac97mix_reinit(struct snd_mixer *m)
770 struct ac97_info *codec = mix_getdevinfo(m);
774 return ac97_reinitmixer(codec);
778 ac97mix_set(struct snd_mixer *m, unsigned dev, unsigned left, unsigned right)
780 struct ac97_info *codec = mix_getdevinfo(m);
784 return ac97_setmixer(codec, dev, left, right);
788 ac97mix_setrecsrc(struct snd_mixer *m, u_int32_t src)
791 struct ac97_info *codec = mix_getdevinfo(m);
795 for (i = 0; i < SOUND_MIXER_NRDEVICES; i++)
796 if ((src & (1 << i)) != 0)
798 return (ac97_setrecsrc(codec, i) == 0)? 1 << i : -1;
801 static kobj_method_t ac97mixer_methods[] = {
802 KOBJMETHOD(mixer_init, ac97mix_init),
803 KOBJMETHOD(mixer_uninit, ac97mix_uninit),
804 KOBJMETHOD(mixer_reinit, ac97mix_reinit),
805 KOBJMETHOD(mixer_set, ac97mix_set),
806 KOBJMETHOD(mixer_setrecsrc, ac97mix_setrecsrc),
809 MIXER_DECLARE(ac97mixer);
811 /* -------------------------------------------------------------------- */
814 ac97_getmixerclass(void)
816 return &ac97mixer_class;