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.7 2004/01/22 07:16: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.7 2004/01/22 07:16: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 { 0x43525900, 0x07, 0, "CS4297", 0 },
153 { 0x43525910, 0x07, 0, "CS4297A", 0 },
154 { 0x43525920, 0x07, 0, "CS4294/98", 0 },
155 { 0x43525930, 0x07, 0, "CS4299", 0 },
156 { 0x43525940, 0x07, 0, "CS4201", 0 },
157 { 0x43525958, 0x07, 0, "CS4205", 0 },
158 { 0x43525960, 0x07, 0, "CS4291A", 0 },
159 { 0x434d4961, 0x00, 0, "CMI9739", 0 },
160 { 0x434d4941, 0x00, 0, "CMI9738", 0 },
161 { 0x43585429, 0x00, 0, "CX20468", 0 },
162 { 0x44543000, 0x00, 0, "DT0398", 0 },
163 { 0x454d4323, 0x00, 0, "EM28023", 0 },
164 { 0x454d4328, 0x00, 0, "EM28028", 0 },
165 { 0x45838308, 0x00, 0, "ES1988", 0 }, /* Formerly ES1921(?) */
166 { 0x48525300, 0x00, 0, "HMP9701", 0 },
167 { 0x49434501, 0x00, 0, "ICE1230", 0 },
168 { 0x49434511, 0x00, 0, "ICE1232", 0 },
169 { 0x49434514, 0x00, 0, "ICE1232A", 0 },
170 { 0x49434551, 0x03, 0, "VT1616", 0 }, /* Via badged ICE */
171 { 0x49544520, 0x00, 0, "ITE2226E", 0 },
172 { 0x49544560, 0x07, 0, "ITE2646E", 0 }, /* XXX: patch needed */
173 { 0x4e534340, 0x00, 0, "LM4540", 0 }, /* Spec blank on revid */
174 { 0x4e534343, 0x00, 0, "LM4543", 0 }, /* Ditto */
175 { 0x4e534346, 0x00, 0, "LM4546A", 0 },
176 { 0x4e534348, 0x00, 0, "LM4548A", 0 },
177 { 0x4e534331, 0x00, 0, "LM4549", 0 },
178 { 0x4e534349, 0x00, 0, "LM4549A", 0 },
179 { 0x4e534350, 0x00, 0, "LM4550", 0 },
180 { 0x50534301, 0x00, 0, "UCB1510", 0 },
181 { 0x50534304, 0x00, 0, "UCB1400", 0 },
182 { 0x83847600, 0x00, 0, "STAC9700/83/84", 0 },
183 { 0x83847604, 0x00, 0, "STAC9701/03/04/05", 0 },
184 { 0x83847605, 0x00, 0, "STAC9704", 0 },
185 { 0x83847608, 0x00, 0, "STAC9708/11", 0 },
186 { 0x83847609, 0x00, 0, "STAC9721/23", 0 },
187 { 0x83847644, 0x00, 0, "STAC9744/45", 0 },
188 { 0x83847650, 0x00, 0, "STAC9750/51", 0 },
189 { 0x83847652, 0x00, 0, "STAC9752/53", 0 },
190 { 0x83847656, 0x00, 0, "STAC9756/57", 0 },
191 { 0x83847658, 0x00, 0, "STAC9758/59", 0 },
192 { 0x83847660, 0x00, 0, "STAC9760/61", 0 }, /* Extrapolated */
193 { 0x83847662, 0x00, 0, "STAC9762/63", 0 }, /* Extrapolated */
194 { 0x53494c22, 0x00, 0, "Si3036", 0 },
195 { 0x53494c23, 0x00, 0, "Si3038", 0 },
196 { 0x54524103, 0x00, 0, "TR28023", 0 }, /* Extrapolated */
197 { 0x54524106, 0x00, 0, "TR28026", 0 },
198 { 0x54524108, 0x00, 0, "TR28028", 0 },
199 { 0x54524123, 0x00, 0, "TR28602", 0 },
200 { 0x54584320, 0x00, 0, "TLC320AD90", 0 },
201 { 0x56494161, 0x00, 0, "VIA1612A", 0 },
202 { 0x574d4c00, 0x00, 0, "WM9701A", 0 },
203 { 0x574d4c03, 0x00, 0, "WM9703/4/7/8", 0 },
204 { 0x574d4c04, 0x00, 0, "WM9704Q", 0 },
205 { 0x574d4c05, 0x00, 0, "WM9705/10", 0 },
206 { 0x57454301, 0x00, 0, "W83971D", 0 },
207 { 0x594d4800, 0x00, 0, "YMF743", 0 },
208 { 0x594d4802, 0x00, 0, "YMF752", 0 },
209 { 0x594d4803, 0x00, 0, "YMF753", 0 },
210 { 0x01408384, 0x00, 0, "EV1938", 0 },
214 static char *ac97enhancement[] = {
215 "no 3D Stereo Enhancement",
216 "Analog Devices Phat Stereo",
217 "Creative Stereo Enhancement",
218 "National Semi 3D Stereo Enhancement",
220 "BBE 3D Stereo Enhancement",
221 "Crystal Semi 3D Stereo Enhancement",
223 "Spatializer 3D Stereo Enhancement",
224 "SRS 3D Stereo Enhancement",
225 "Platform Tech 3D Stereo Enhancement",
227 "Aureal Stereo Enhancement",
228 "Aztech 3D Enhancement",
229 "Binaura 3D Audio Enhancement",
230 "ESS Technology Stereo Enhancement",
231 "Harman International VMAx",
232 "Nvidea 3D Stereo Enhancement",
233 "Philips Incredible Sound",
234 "Texas Instruments 3D Stereo Enhancement",
235 "VLSI Technology 3D Stereo Enhancement",
236 "TriTech 3D Stereo Enhancement",
237 "Realtek 3D Stereo Enhancement",
238 "Samsung 3D Stereo Enhancement",
239 "Wolfson Microelectronics 3D Enhancement",
240 "Delta Integration 3D Enhancement",
241 "SigmaTel 3D Enhancement",
243 "Rockwell 3D Stereo Enhancement",
249 static char *ac97feature[] = {
262 static char *ac97extfeature[] = {
280 ac97_rdcd(struct ac97_info *codec, int reg)
282 return AC97_READ(codec->methods, codec->devinfo, reg);
286 ac97_wrcd(struct ac97_info *codec, int reg, u_int16_t val)
288 AC97_WRITE(codec->methods, codec->devinfo, reg, val);
292 ac97_reset(struct ac97_info *codec)
295 ac97_wrcd(codec, AC97_REG_RESET, 0);
296 for (i = 0; i < 500; i++) {
297 ps = ac97_rdcd(codec, AC97_REG_POWER) & AC97_POWER_STATUS;
298 if (ps == AC97_POWER_STATUS)
302 device_printf(codec->dev, "AC97 reset timed out.\n");
306 ac97_setrate(struct ac97_info *codec, int which, int rate)
311 case AC97_REGEXT_FDACRATE:
312 case AC97_REGEXT_SDACRATE:
313 case AC97_REGEXT_LDACRATE:
314 case AC97_REGEXT_LADCRATE:
315 case AC97_REGEXT_MADCRATE:
322 snd_mtxlock(codec->lock);
325 if (codec->extstat & AC97_EXTCAP_DRA)
327 ac97_wrcd(codec, which, v);
329 v = ac97_rdcd(codec, which);
330 if (codec->extstat & AC97_EXTCAP_DRA)
332 snd_mtxunlock(codec->lock);
337 ac97_setextmode(struct ac97_info *codec, u_int16_t mode)
339 mode &= AC97_EXTCAPS;
340 if ((mode & ~codec->extcaps) != 0) {
341 device_printf(codec->dev, "ac97 invalid mode set 0x%04x\n",
345 snd_mtxlock(codec->lock);
346 ac97_wrcd(codec, AC97_REGEXT_STAT, mode);
347 codec->extstat = ac97_rdcd(codec, AC97_REGEXT_STAT) & AC97_EXTCAPS;
348 snd_mtxunlock(codec->lock);
349 return (mode == codec->extstat)? 0 : -1;
353 ac97_getextmode(struct ac97_info *codec)
355 return codec->extstat;
359 ac97_getextcaps(struct ac97_info *codec)
361 return codec->extcaps;
365 ac97_getcaps(struct ac97_info *codec)
371 ac97_setrecsrc(struct ac97_info *codec, int channel)
373 struct ac97mixtable_entry *e = &codec->mix[channel];
376 int val = e->recidx - 1;
378 snd_mtxlock(codec->lock);
379 ac97_wrcd(codec, AC97_REG_RECSEL, val);
380 snd_mtxunlock(codec->lock);
387 ac97_setmixer(struct ac97_info *codec, unsigned channel, unsigned left, unsigned right)
389 struct ac97mixtable_entry *e = &codec->mix[channel];
391 if (e->reg && e->enable && e->bits) {
392 int mask, max, val, reg;
394 reg = (e->reg >= 0) ? e->reg : -e->reg; /* AC97 register */
395 max = (1 << e->bits) - 1; /* actual range */
396 mask = (max << 8) | max; /* bits of interest */
402 * Invert the range if the polarity requires so,
403 * then scale to 0..max-1 to compute the value to
404 * write into the codec, and scale back to 0..100
405 * for the return value.
412 left = (left * max) / 100;
413 right = (right * max) / 100;
415 val = (left << 8) | right;
417 left = (left * 100) / max;
418 right = (right * 100) / max;
426 * For mono controls, trim val and mask, also taking
427 * care of e->ofs (offset of control field).
432 mask = (max << e->ofs);
436 * If we have a mute bit, add it to the mask and
437 * update val and set mute if both channels require a
442 if (left == 0 && right == 0)
447 * If the mask bit is set, do not alter the other bits.
449 snd_mtxlock(codec->lock);
451 int cur = ac97_rdcd(codec, e->reg);
452 val |= cur & ~(mask);
454 ac97_wrcd(codec, reg, val);
455 snd_mtxunlock(codec->lock);
456 return left | (right << 8);
458 /* printf("ac97_setmixer: reg=%d, bits=%d, enable=%d\n", e->reg, e->bits, e->enable); */
464 ac97_fix_auxout(struct ac97_info *codec)
469 * By default, The ac97 aux_out register (0x04) corresponds to OSS's
472 * We first check whether aux_out is a valid register. If not
473 * we may not want to keep ogain.
475 keep_ogain = ac97_rdcd(codec, AC97_MIX_AUXOUT) & 0x8000;
478 * Determine what AUX_OUT really means, it can be:
482 * 3. True line level out (effectively master volume).
484 * See Sections 5.2.1 and 5.27 for AUX_OUT Options in AC97r2.{2,3}.
486 if (codec->extcaps & AC97_EXTCAP_SDAC &&
487 ac97_rdcd(codec, AC97_MIXEXT_SURROUND) == 0x8080) {
488 codec->mix[SOUND_MIXER_OGAIN].reg = AC97_MIXEXT_SURROUND;
492 if (keep_ogain == 0) {
493 bzero(&codec->mix[SOUND_MIXER_OGAIN],
494 sizeof(codec->mix[SOUND_MIXER_OGAIN]));
499 ac97_fix_tone(struct ac97_info *codec)
501 /* Hide treble and bass if they don't exist */
502 if ((codec->caps & AC97_CAP_TONE) == 0) {
503 bzero(&codec->mix[SOUND_MIXER_BASS],
504 sizeof(codec->mix[SOUND_MIXER_BASS]));
505 bzero(&codec->mix[SOUND_MIXER_TREBLE],
506 sizeof(codec->mix[SOUND_MIXER_TREBLE]));
511 ac97_hw_desc(u_int32_t id, const char* vname, const char* cname, char* buf)
514 sprintf(buf, "Unknown AC97 Codec (id = 0x%08x)", id);
518 if (vname == NULL) vname = "Unknown";
521 sprintf(buf, "%s %s AC97 Codec (id = 0x%08x)", vname, cname, id);
523 sprintf(buf, "%s %s AC97 Codec", vname, cname);
529 ac97_initmixer(struct ac97_info *codec)
531 ac97_patch codec_patch;
532 const char *cname, *vname;
534 u_int8_t model, step;
535 unsigned i, j, k, old;
538 snd_mtxlock(codec->lock);
539 codec->count = AC97_INIT(codec->methods, codec->devinfo);
540 if (codec->count == 0) {
541 device_printf(codec->dev, "ac97 codec init failed\n");
542 snd_mtxunlock(codec->lock);
546 ac97_wrcd(codec, AC97_REG_POWER, (codec->flags & AC97_F_EAPD_INV)? 0x8000 : 0x0000);
548 ac97_wrcd(codec, AC97_REG_POWER, (codec->flags & AC97_F_EAPD_INV)? 0x8000 : 0x0000);
550 i = ac97_rdcd(codec, AC97_REG_RESET);
551 codec->caps = i & 0x03ff;
552 codec->se = (i & 0x7c00) >> 10;
554 id = (ac97_rdcd(codec, AC97_REG_ID1) << 16) | ac97_rdcd(codec, AC97_REG_ID2);
555 if (id == 0 || id == 0xffffffff) {
556 device_printf(codec->dev, "ac97 codec invalid or not present (id == %x)\n", id);
557 snd_mtxunlock(codec->lock);
567 for (i = 0; ac97codecid[i].id; i++) {
568 u_int32_t modelmask = 0xffffffff ^ ac97codecid[i].stepmask;
569 if ((ac97codecid[i].id & modelmask) == (id & modelmask)) {
570 codec->noext = ac97codecid[i].noext;
571 codec_patch = ac97codecid[i].patch;
572 cname = ac97codecid[i].name;
573 model = (id & modelmask) & 0xff;
574 step = (id & ~modelmask) & 0xff;
580 for (i = 0; ac97vendorid[i].id; i++) {
581 if (ac97vendorid[i].id == (id & 0xffffff00)) {
582 vname = ac97vendorid[i].name;
591 i = ac97_rdcd(codec, AC97_REGEXT_ID);
593 codec->extcaps = i & 0x3fff;
594 codec->extid = (i & 0xc000) >> 14;
595 codec->extstat = ac97_rdcd(codec, AC97_REGEXT_STAT) & AC97_EXTCAPS;
599 for (i = 0; i < 32; i++) {
600 codec->mix[i] = ac97mixtable_default[i];
602 ac97_fix_auxout(codec);
603 ac97_fix_tone(codec);
607 for (i = 0; i < 32; i++) {
608 k = codec->noext? codec->mix[i].enable : 1;
609 if (k && (codec->mix[i].reg > 0)) {
610 old = ac97_rdcd(codec, codec->mix[i].reg);
611 ac97_wrcd(codec, codec->mix[i].reg, 0x3f);
612 j = ac97_rdcd(codec, codec->mix[i].reg);
613 ac97_wrcd(codec, codec->mix[i].reg, old);
614 codec->mix[i].enable = (j != 0 && j != old)? 1 : 0;
615 for (k = 1; j & (1 << k); k++);
616 codec->mix[i].bits = j? k - codec->mix[i].ofs : 0;
618 /* printf("mixch %d, en=%d, b=%d\n", i, codec->mix[i].enable, codec->mix[i].bits); */
621 device_printf(codec->dev, "<%s>\n",
622 ac97_hw_desc(codec->id, vname, cname, desc));
625 device_printf(codec->dev, "Codec features ");
626 for (i = j = 0; i < 10; i++)
627 if (codec->caps & (1 << i))
628 printf("%s%s", j++? ", " : "", ac97feature[i]);
629 printf("%s%d bit master volume", j++? ", " : "", codec->mix[SOUND_MIXER_VOLUME].bits);
630 printf("%s%s\n", j? ", " : "", ac97enhancement[codec->se]);
632 if (codec->extcaps != 0 || codec->extid) {
633 device_printf(codec->dev, "%s codec",
634 codec->extid? "Secondary" : "Primary");
636 printf(" extended features ");
637 for (i = j = 0; i < 14; i++)
638 if (codec->extcaps & (1 << i))
639 printf("%s%s", j++? ", " : "", ac97extfeature[i]);
644 if ((ac97_rdcd(codec, AC97_REG_POWER) & 2) == 0)
645 device_printf(codec->dev, "ac97 codec reports dac not ready\n");
646 snd_mtxunlock(codec->lock);
651 ac97_reinitmixer(struct ac97_info *codec)
653 snd_mtxlock(codec->lock);
654 codec->count = AC97_INIT(codec->methods, codec->devinfo);
655 if (codec->count == 0) {
656 device_printf(codec->dev, "ac97 codec init failed\n");
657 snd_mtxunlock(codec->lock);
661 ac97_wrcd(codec, AC97_REG_POWER, (codec->flags & AC97_F_EAPD_INV)? 0x8000 : 0x0000);
663 ac97_wrcd(codec, AC97_REG_POWER, (codec->flags & AC97_F_EAPD_INV)? 0x8000 : 0x0000);
666 ac97_wrcd(codec, AC97_REGEXT_STAT, codec->extstat);
667 if ((ac97_rdcd(codec, AC97_REGEXT_STAT) & AC97_EXTCAPS)
669 device_printf(codec->dev, "ac97 codec failed to reset extended mode (%x, got %x)\n",
671 ac97_rdcd(codec, AC97_REGEXT_STAT) &
675 if ((ac97_rdcd(codec, AC97_REG_POWER) & 2) == 0)
676 device_printf(codec->dev, "ac97 codec reports dac not ready\n");
677 snd_mtxunlock(codec->lock);
682 ac97_create(device_t dev, void *devinfo, kobj_class_t cls)
684 struct ac97_info *codec;
686 codec = (struct ac97_info *)malloc(sizeof *codec, M_AC97, M_NOWAIT);
690 snprintf(codec->name, AC97_NAMELEN, "%s:ac97", device_get_nameunit(dev));
691 codec->lock = snd_mtxcreate(codec->name, "ac97 codec");
692 codec->methods = kobj_create(cls, M_AC97, 0);
693 if (codec->methods == NULL) {
694 snd_mtxlock(codec->lock);
695 snd_mtxfree(codec->lock);
701 codec->devinfo = devinfo;
707 ac97_destroy(struct ac97_info *codec)
709 snd_mtxlock(codec->lock);
710 if (codec->methods != NULL)
711 kobj_delete(codec->methods, M_AC97);
712 snd_mtxfree(codec->lock);
717 ac97_setflags(struct ac97_info *codec, u_int32_t val)
723 ac97_getflags(struct ac97_info *codec)
728 /* -------------------------------------------------------------------- */
731 ac97mix_init(struct snd_mixer *m)
733 struct ac97_info *codec = mix_getdevinfo(m);
739 if (ac97_initmixer(codec))
743 for (i = 0; i < 32; i++)
744 mask |= codec->mix[i].enable? 1 << i : 0;
745 mix_setdevs(m, mask);
748 for (i = 0; i < 32; i++)
749 mask |= codec->mix[i].recidx? 1 << i : 0;
750 mix_setrecdevs(m, mask);
755 ac97mix_uninit(struct snd_mixer *m)
757 struct ac97_info *codec = mix_getdevinfo(m);
762 if (ac97_uninitmixer(codec))
770 ac97mix_reinit(struct snd_mixer *m)
772 struct ac97_info *codec = mix_getdevinfo(m);
776 return ac97_reinitmixer(codec);
780 ac97mix_set(struct snd_mixer *m, unsigned dev, unsigned left, unsigned right)
782 struct ac97_info *codec = mix_getdevinfo(m);
786 return ac97_setmixer(codec, dev, left, right);
790 ac97mix_setrecsrc(struct snd_mixer *m, u_int32_t src)
793 struct ac97_info *codec = mix_getdevinfo(m);
797 for (i = 0; i < SOUND_MIXER_NRDEVICES; i++)
798 if ((src & (1 << i)) != 0)
800 return (ac97_setrecsrc(codec, i) == 0)? 1 << i : -1;
803 static kobj_method_t ac97mixer_methods[] = {
804 KOBJMETHOD(mixer_init, ac97mix_init),
805 KOBJMETHOD(mixer_uninit, ac97mix_uninit),
806 KOBJMETHOD(mixer_reinit, ac97mix_reinit),
807 KOBJMETHOD(mixer_set, ac97mix_set),
808 KOBJMETHOD(mixer_setrecsrc, ac97mix_setrecsrc),
811 MIXER_DECLARE(ac97mixer);
813 /* -------------------------------------------------------------------- */
816 ac97_getmixerclass(void)
818 return &ac97mixer_class;