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.12 2004/01/22 07:38:42 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.12 2004/01/22 07:38:42 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 { 0x43525930, 0x07, 0, "CS4299", 0 },
157 { 0x43525940, 0x07, 0, "CS4201", 0 },
158 { 0x43525958, 0x07, 0, "CS4205", 0 },
159 { 0x43525960, 0x07, 0, "CS4291A", 0 },
160 { 0x434d4961, 0x00, 0, "CMI9739", 0 },
161 { 0x434d4941, 0x00, 0, "CMI9738", 0 },
162 { 0x43585429, 0x00, 0, "CX20468", 0 },
163 { 0x44543000, 0x00, 0, "DT0398", 0 },
164 { 0x454d4323, 0x00, 0, "EM28023", 0 },
165 { 0x454d4328, 0x00, 0, "EM28028", 0 },
166 { 0x45838308, 0x00, 0, "ES1988", 0 }, /* Formerly ES1921(?) */
167 { 0x48525300, 0x00, 0, "HMP9701", 0 },
168 { 0x49434501, 0x00, 0, "ICE1230", 0 },
169 { 0x49434511, 0x00, 0, "ICE1232", 0 },
170 { 0x49434514, 0x00, 0, "ICE1232A", 0 },
171 { 0x49434551, 0x03, 0, "VT1616", 0 }, /* Via badged ICE */
172 { 0x49544520, 0x00, 0, "ITE2226E", 0 },
173 { 0x49544560, 0x07, 0, "ITE2646E", 0 }, /* XXX: patch needed */
174 { 0x4e534340, 0x00, 0, "LM4540", 0 }, /* Spec blank on revid */
175 { 0x4e534343, 0x00, 0, "LM4543", 0 }, /* Ditto */
176 { 0x4e534346, 0x00, 0, "LM4546A", 0 },
177 { 0x4e534348, 0x00, 0, "LM4548A", 0 },
178 { 0x4e534331, 0x00, 0, "LM4549", 0 },
179 { 0x4e534349, 0x00, 0, "LM4549A", 0 },
180 { 0x4e534350, 0x00, 0, "LM4550", 0 },
181 { 0x50534301, 0x00, 0, "UCB1510", 0 },
182 { 0x50534304, 0x00, 0, "UCB1400", 0 },
183 { 0x83847600, 0x00, 0, "STAC9700/83/84", 0 },
184 { 0x83847604, 0x00, 0, "STAC9701/03/04/05", 0 },
185 { 0x83847605, 0x00, 0, "STAC9704", 0 },
186 { 0x83847608, 0x00, 0, "STAC9708/11", 0 },
187 { 0x83847609, 0x00, 0, "STAC9721/23", 0 },
188 { 0x83847644, 0x00, 0, "STAC9744/45", 0 },
189 { 0x83847650, 0x00, 0, "STAC9750/51", 0 },
190 { 0x83847652, 0x00, 0, "STAC9752/53", 0 },
191 { 0x83847656, 0x00, 0, "STAC9756/57", 0 },
192 { 0x83847658, 0x00, 0, "STAC9758/59", 0 },
193 { 0x83847660, 0x00, 0, "STAC9760/61", 0 }, /* Extrapolated */
194 { 0x83847662, 0x00, 0, "STAC9762/63", 0 }, /* Extrapolated */
195 { 0x53494c22, 0x00, 0, "Si3036", 0 },
196 { 0x53494c23, 0x00, 0, "Si3038", 0 },
197 { 0x54524103, 0x00, 0, "TR28023", 0 }, /* Extrapolated */
198 { 0x54524106, 0x00, 0, "TR28026", 0 },
199 { 0x54524108, 0x00, 0, "TR28028", 0 },
200 { 0x54524123, 0x00, 0, "TR28602", 0 },
201 { 0x54524e03, 0x07, 0, "TLV320AIC27" 0 },
202 { 0x54584e20, 0x00, 0, "TLC320AD90", 0 },
203 { 0x56494161, 0x00, 0, "VIA1612A", 0 },
204 { 0x574d4c00, 0x00, 0, "WM9701A", 0 },
205 { 0x574d4c03, 0x00, 0, "WM9703/4/7/8", 0 },
206 { 0x574d4c04, 0x00, 0, "WM9704Q", 0 },
207 { 0x574d4c05, 0x00, 0, "WM9705/10", 0 },
208 { 0x574d4d09, 0x00, 0, "WM9709", 0 },
209 { 0x574d4c12, 0x00, 0, "WM9711/12", 0 }, /* XXX: patch needed */
210 { 0x57454301, 0x00, 0, "W83971D", 0 },
211 { 0x594d4800, 0x00, 0, "YMF743", 0 },
212 { 0x594d4802, 0x00, 0, "YMF752", 0 },
213 { 0x594d4803, 0x00, 0, "YMF753", 0 },
214 { 0x01408384, 0x00, 0, "EV1938", 0 },
218 static char *ac97enhancement[] = {
219 "no 3D Stereo Enhancement",
220 "Analog Devices Phat Stereo",
221 "Creative Stereo Enhancement",
222 "National Semi 3D Stereo Enhancement",
224 "BBE 3D Stereo Enhancement",
225 "Crystal Semi 3D Stereo Enhancement",
227 "Spatializer 3D Stereo Enhancement",
228 "SRS 3D Stereo Enhancement",
229 "Platform Tech 3D Stereo Enhancement",
231 "Aureal Stereo Enhancement",
232 "Aztech 3D Enhancement",
233 "Binaura 3D Audio Enhancement",
234 "ESS Technology Stereo Enhancement",
235 "Harman International VMAx",
236 "Nvidea 3D Stereo Enhancement",
237 "Philips Incredible Sound",
238 "Texas Instruments 3D Stereo Enhancement",
239 "VLSI Technology 3D Stereo Enhancement",
240 "TriTech 3D Stereo Enhancement",
241 "Realtek 3D Stereo Enhancement",
242 "Samsung 3D Stereo Enhancement",
243 "Wolfson Microelectronics 3D Enhancement",
244 "Delta Integration 3D Enhancement",
245 "SigmaTel 3D Enhancement",
247 "Rockwell 3D Stereo Enhancement",
253 static char *ac97feature[] = {
266 static char *ac97extfeature[] = {
284 ac97_rdcd(struct ac97_info *codec, int reg)
286 return AC97_READ(codec->methods, codec->devinfo, reg);
290 ac97_wrcd(struct ac97_info *codec, int reg, u_int16_t val)
292 AC97_WRITE(codec->methods, codec->devinfo, reg, val);
296 ac97_reset(struct ac97_info *codec)
299 ac97_wrcd(codec, AC97_REG_RESET, 0);
300 for (i = 0; i < 500; i++) {
301 ps = ac97_rdcd(codec, AC97_REG_POWER) & AC97_POWER_STATUS;
302 if (ps == AC97_POWER_STATUS)
306 device_printf(codec->dev, "AC97 reset timed out.\n");
310 ac97_setrate(struct ac97_info *codec, int which, int rate)
315 case AC97_REGEXT_FDACRATE:
316 case AC97_REGEXT_SDACRATE:
317 case AC97_REGEXT_LDACRATE:
318 case AC97_REGEXT_LADCRATE:
319 case AC97_REGEXT_MADCRATE:
326 snd_mtxlock(codec->lock);
329 if (codec->extstat & AC97_EXTCAP_DRA)
331 ac97_wrcd(codec, which, v);
333 v = ac97_rdcd(codec, which);
334 if (codec->extstat & AC97_EXTCAP_DRA)
336 snd_mtxunlock(codec->lock);
341 ac97_setextmode(struct ac97_info *codec, u_int16_t mode)
343 mode &= AC97_EXTCAPS;
344 if ((mode & ~codec->extcaps) != 0) {
345 device_printf(codec->dev, "ac97 invalid mode set 0x%04x\n",
349 snd_mtxlock(codec->lock);
350 ac97_wrcd(codec, AC97_REGEXT_STAT, mode);
351 codec->extstat = ac97_rdcd(codec, AC97_REGEXT_STAT) & AC97_EXTCAPS;
352 snd_mtxunlock(codec->lock);
353 return (mode == codec->extstat)? 0 : -1;
357 ac97_getextmode(struct ac97_info *codec)
359 return codec->extstat;
363 ac97_getextcaps(struct ac97_info *codec)
365 return codec->extcaps;
369 ac97_getcaps(struct ac97_info *codec)
375 ac97_setrecsrc(struct ac97_info *codec, int channel)
377 struct ac97mixtable_entry *e = &codec->mix[channel];
380 int val = e->recidx - 1;
382 snd_mtxlock(codec->lock);
383 ac97_wrcd(codec, AC97_REG_RECSEL, val);
384 snd_mtxunlock(codec->lock);
391 ac97_setmixer(struct ac97_info *codec, unsigned channel, unsigned left, unsigned right)
393 struct ac97mixtable_entry *e = &codec->mix[channel];
395 if (e->reg && e->enable && e->bits) {
396 int mask, max, val, reg;
398 reg = (e->reg >= 0) ? e->reg : -e->reg; /* AC97 register */
399 max = (1 << e->bits) - 1; /* actual range */
400 mask = (max << 8) | max; /* bits of interest */
406 * Invert the range if the polarity requires so,
407 * then scale to 0..max-1 to compute the value to
408 * write into the codec, and scale back to 0..100
409 * for the return value.
416 left = (left * max) / 100;
417 right = (right * max) / 100;
419 val = (left << 8) | right;
421 left = (left * 100) / max;
422 right = (right * 100) / max;
430 * For mono controls, trim val and mask, also taking
431 * care of e->ofs (offset of control field).
436 mask = (max << e->ofs);
440 * If we have a mute bit, add it to the mask and
441 * update val and set mute if both channels require a
446 if (left == 0 && right == 0)
451 * If the mask bit is set, do not alter the other bits.
453 snd_mtxlock(codec->lock);
455 int cur = ac97_rdcd(codec, e->reg);
456 val |= cur & ~(mask);
458 ac97_wrcd(codec, reg, val);
459 snd_mtxunlock(codec->lock);
460 return left | (right << 8);
462 /* printf("ac97_setmixer: reg=%d, bits=%d, enable=%d\n", e->reg, e->bits, e->enable); */
468 ac97_fix_auxout(struct ac97_info *codec)
473 * By default, The ac97 aux_out register (0x04) corresponds to OSS's
476 * We first check whether aux_out is a valid register. If not
477 * we may not want to keep ogain.
479 keep_ogain = ac97_rdcd(codec, AC97_MIX_AUXOUT) & 0x8000;
482 * Determine what AUX_OUT really means, it can be:
486 * 3. True line level out (effectively master volume).
488 * See Sections 5.2.1 and 5.27 for AUX_OUT Options in AC97r2.{2,3}.
490 if (codec->extcaps & AC97_EXTCAP_SDAC &&
491 ac97_rdcd(codec, AC97_MIXEXT_SURROUND) == 0x8080) {
492 codec->mix[SOUND_MIXER_OGAIN].reg = AC97_MIXEXT_SURROUND;
496 if (keep_ogain == 0) {
497 bzero(&codec->mix[SOUND_MIXER_OGAIN],
498 sizeof(codec->mix[SOUND_MIXER_OGAIN]));
503 ac97_fix_tone(struct ac97_info *codec)
505 /* Hide treble and bass if they don't exist */
506 if ((codec->caps & AC97_CAP_TONE) == 0) {
507 bzero(&codec->mix[SOUND_MIXER_BASS],
508 sizeof(codec->mix[SOUND_MIXER_BASS]));
509 bzero(&codec->mix[SOUND_MIXER_TREBLE],
510 sizeof(codec->mix[SOUND_MIXER_TREBLE]));
515 ac97_hw_desc(u_int32_t id, const char* vname, const char* cname, char* buf)
518 sprintf(buf, "Unknown AC97 Codec (id = 0x%08x)", id);
522 if (vname == NULL) vname = "Unknown";
525 sprintf(buf, "%s %s AC97 Codec (id = 0x%08x)", vname, cname, id);
527 sprintf(buf, "%s %s AC97 Codec", vname, cname);
533 ac97_initmixer(struct ac97_info *codec)
535 ac97_patch codec_patch;
536 const char *cname, *vname;
538 u_int8_t model, step;
539 unsigned i, j, k, old;
542 snd_mtxlock(codec->lock);
543 codec->count = AC97_INIT(codec->methods, codec->devinfo);
544 if (codec->count == 0) {
545 device_printf(codec->dev, "ac97 codec init failed\n");
546 snd_mtxunlock(codec->lock);
550 ac97_wrcd(codec, AC97_REG_POWER, (codec->flags & AC97_F_EAPD_INV)? 0x8000 : 0x0000);
552 ac97_wrcd(codec, AC97_REG_POWER, (codec->flags & AC97_F_EAPD_INV)? 0x8000 : 0x0000);
554 i = ac97_rdcd(codec, AC97_REG_RESET);
555 codec->caps = i & 0x03ff;
556 codec->se = (i & 0x7c00) >> 10;
558 id = (ac97_rdcd(codec, AC97_REG_ID1) << 16) | ac97_rdcd(codec, AC97_REG_ID2);
559 if (id == 0 || id == 0xffffffff) {
560 device_printf(codec->dev, "ac97 codec invalid or not present (id == %x)\n", id);
561 snd_mtxunlock(codec->lock);
571 for (i = 0; ac97codecid[i].id; i++) {
572 u_int32_t modelmask = 0xffffffff ^ ac97codecid[i].stepmask;
573 if ((ac97codecid[i].id & modelmask) == (id & modelmask)) {
574 codec->noext = ac97codecid[i].noext;
575 codec_patch = ac97codecid[i].patch;
576 cname = ac97codecid[i].name;
577 model = (id & modelmask) & 0xff;
578 step = (id & ~modelmask) & 0xff;
584 for (i = 0; ac97vendorid[i].id; i++) {
585 if (ac97vendorid[i].id == (id & 0xffffff00)) {
586 vname = ac97vendorid[i].name;
595 i = ac97_rdcd(codec, AC97_REGEXT_ID);
597 codec->extcaps = i & 0x3fff;
598 codec->extid = (i & 0xc000) >> 14;
599 codec->extstat = ac97_rdcd(codec, AC97_REGEXT_STAT) & AC97_EXTCAPS;
603 for (i = 0; i < 32; i++) {
604 codec->mix[i] = ac97mixtable_default[i];
606 ac97_fix_auxout(codec);
607 ac97_fix_tone(codec);
611 for (i = 0; i < 32; i++) {
612 k = codec->noext? codec->mix[i].enable : 1;
613 if (k && (codec->mix[i].reg > 0)) {
614 old = ac97_rdcd(codec, codec->mix[i].reg);
615 ac97_wrcd(codec, codec->mix[i].reg, 0x3f);
616 j = ac97_rdcd(codec, codec->mix[i].reg);
617 ac97_wrcd(codec, codec->mix[i].reg, old);
618 codec->mix[i].enable = (j != 0 && j != old)? 1 : 0;
619 for (k = 1; j & (1 << k); k++);
620 codec->mix[i].bits = j? k - codec->mix[i].ofs : 0;
622 /* printf("mixch %d, en=%d, b=%d\n", i, codec->mix[i].enable, codec->mix[i].bits); */
625 device_printf(codec->dev, "<%s>\n",
626 ac97_hw_desc(codec->id, vname, cname, desc));
629 device_printf(codec->dev, "Codec features ");
630 for (i = j = 0; i < 10; i++)
631 if (codec->caps & (1 << i))
632 printf("%s%s", j++? ", " : "", ac97feature[i]);
633 printf("%s%d bit master volume", j++? ", " : "", codec->mix[SOUND_MIXER_VOLUME].bits);
634 printf("%s%s\n", j? ", " : "", ac97enhancement[codec->se]);
636 if (codec->extcaps != 0 || codec->extid) {
637 device_printf(codec->dev, "%s codec",
638 codec->extid? "Secondary" : "Primary");
640 printf(" extended features ");
641 for (i = j = 0; i < 14; i++)
642 if (codec->extcaps & (1 << i))
643 printf("%s%s", j++? ", " : "", ac97extfeature[i]);
648 if ((ac97_rdcd(codec, AC97_REG_POWER) & 2) == 0)
649 device_printf(codec->dev, "ac97 codec reports dac not ready\n");
650 snd_mtxunlock(codec->lock);
655 ac97_reinitmixer(struct ac97_info *codec)
657 snd_mtxlock(codec->lock);
658 codec->count = AC97_INIT(codec->methods, codec->devinfo);
659 if (codec->count == 0) {
660 device_printf(codec->dev, "ac97 codec init failed\n");
661 snd_mtxunlock(codec->lock);
665 ac97_wrcd(codec, AC97_REG_POWER, (codec->flags & AC97_F_EAPD_INV)? 0x8000 : 0x0000);
667 ac97_wrcd(codec, AC97_REG_POWER, (codec->flags & AC97_F_EAPD_INV)? 0x8000 : 0x0000);
670 ac97_wrcd(codec, AC97_REGEXT_STAT, codec->extstat);
671 if ((ac97_rdcd(codec, AC97_REGEXT_STAT) & AC97_EXTCAPS)
673 device_printf(codec->dev, "ac97 codec failed to reset extended mode (%x, got %x)\n",
675 ac97_rdcd(codec, AC97_REGEXT_STAT) &
679 if ((ac97_rdcd(codec, AC97_REG_POWER) & 2) == 0)
680 device_printf(codec->dev, "ac97 codec reports dac not ready\n");
681 snd_mtxunlock(codec->lock);
686 ac97_create(device_t dev, void *devinfo, kobj_class_t cls)
688 struct ac97_info *codec;
690 codec = (struct ac97_info *)malloc(sizeof *codec, M_AC97, M_NOWAIT);
694 snprintf(codec->name, AC97_NAMELEN, "%s:ac97", device_get_nameunit(dev));
695 codec->lock = snd_mtxcreate(codec->name, "ac97 codec");
696 codec->methods = kobj_create(cls, M_AC97, 0);
697 if (codec->methods == NULL) {
698 snd_mtxlock(codec->lock);
699 snd_mtxfree(codec->lock);
705 codec->devinfo = devinfo;
711 ac97_destroy(struct ac97_info *codec)
713 snd_mtxlock(codec->lock);
714 if (codec->methods != NULL)
715 kobj_delete(codec->methods, M_AC97);
716 snd_mtxfree(codec->lock);
721 ac97_setflags(struct ac97_info *codec, u_int32_t val)
727 ac97_getflags(struct ac97_info *codec)
732 /* -------------------------------------------------------------------- */
735 ac97mix_init(struct snd_mixer *m)
737 struct ac97_info *codec = mix_getdevinfo(m);
743 if (ac97_initmixer(codec))
747 for (i = 0; i < 32; i++)
748 mask |= codec->mix[i].enable? 1 << i : 0;
749 mix_setdevs(m, mask);
752 for (i = 0; i < 32; i++)
753 mask |= codec->mix[i].recidx? 1 << i : 0;
754 mix_setrecdevs(m, mask);
759 ac97mix_uninit(struct snd_mixer *m)
761 struct ac97_info *codec = mix_getdevinfo(m);
766 if (ac97_uninitmixer(codec))
774 ac97mix_reinit(struct snd_mixer *m)
776 struct ac97_info *codec = mix_getdevinfo(m);
780 return ac97_reinitmixer(codec);
784 ac97mix_set(struct snd_mixer *m, unsigned dev, unsigned left, unsigned right)
786 struct ac97_info *codec = mix_getdevinfo(m);
790 return ac97_setmixer(codec, dev, left, right);
794 ac97mix_setrecsrc(struct snd_mixer *m, u_int32_t src)
797 struct ac97_info *codec = mix_getdevinfo(m);
801 for (i = 0; i < SOUND_MIXER_NRDEVICES; i++)
802 if ((src & (1 << i)) != 0)
804 return (ac97_setrecsrc(codec, i) == 0)? 1 << i : -1;
807 static kobj_method_t ac97mixer_methods[] = {
808 KOBJMETHOD(mixer_init, ac97mix_init),
809 KOBJMETHOD(mixer_uninit, ac97mix_uninit),
810 KOBJMETHOD(mixer_reinit, ac97mix_reinit),
811 KOBJMETHOD(mixer_set, ac97mix_set),
812 KOBJMETHOD(mixer_setrecsrc, ac97mix_setrecsrc),
815 MIXER_DECLARE(ac97mixer);
817 /* -------------------------------------------------------------------- */
820 ac97_getmixerclass(void)
822 return &ac97mixer_class;