Remap and virtualize mixer controls for HP nx6110 with AD1981B AC97 codec,
[dragonfly/netmp.git] / sys / dev / sound / pcm / ac97.c
blob3edbe41b55ac677948f9c6b973b249b91ba97463
1 /*-
2 * Copyright (c) 1999 Cameron Grant <cg@freebsd.org>
3 * All rights reserved.
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
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
24 * SUCH DAMAGE.
26 * $FreeBSD: src/sys/dev/sound/pcm/ac97.c,v 1.53.2.6 2007/10/31 04:00:07 ariff Exp $
27 * $DragonFly: src/sys/dev/sound/pcm/ac97.c,v 1.26 2007/11/30 07:59:56 hasso Exp $
30 #include <dev/sound/pcm/sound.h>
31 #include <dev/sound/pcm/ac97.h>
32 #include <dev/sound/pcm/ac97_patch.h>
34 #include <bus/pci/pcivar.h>
36 #include "mixer_if.h"
38 SND_DECLARE_FILE("$DragonFly: src/sys/dev/sound/pcm/ac97.c,v 1.26 2007/11/30 07:59:56 hasso Exp $");
40 MALLOC_DEFINE(M_AC97, "ac97", "ac97 codec");
42 struct ac97mixtable_entry {
43 int reg:8; /* register index */
44 /* reg < 0 if inverted polarity */
45 unsigned bits:4; /* width of control field */
46 unsigned ofs:4; /* offset (only if stereo=0) */
47 unsigned stereo:1; /* set for stereo controls */
48 unsigned mute:1; /* bit15 is MUTE */
49 unsigned recidx:4; /* index in rec mux */
50 unsigned mask:1; /* use only masked bits */
51 unsigned enable:1; /* entry is enabled */
54 #define AC97_NAMELEN 16
55 struct ac97_info {
56 kobj_t methods;
57 device_t dev;
58 void *devinfo;
59 u_int32_t id;
60 u_int32_t subvendor;
61 unsigned count, caps, se, extcaps, extid, extstat, noext:1;
62 u_int32_t flags;
63 struct ac97mixtable_entry mix[32];
64 char name[AC97_NAMELEN];
65 sndlock_t lock;
68 struct ac97_vendorid {
69 u_int32_t id;
70 const char *name;
73 struct ac97_codecid {
74 u_int32_t id;
75 u_int8_t stepmask;
76 u_int8_t noext:1;
77 char *name;
78 ac97_patch patch;
81 static const struct ac97mixtable_entry ac97mixtable_default[32] = {
82 /* [offset] reg bits of st mu re mk en */
83 [SOUND_MIXER_VOLUME] = { AC97_MIX_MASTER, 5, 0, 1, 1, 6, 0, 1 },
84 [SOUND_MIXER_OGAIN] = { AC97_MIX_AUXOUT, 5, 0, 1, 1, 0, 0, 0 },
85 [SOUND_MIXER_PHONEOUT] = { AC97_MIX_MONO, 5, 0, 0, 1, 7, 0, 0 },
86 [SOUND_MIXER_BASS] = { AC97_MIX_TONE, 4, 8, 0, 0, 0, 1, 0 },
87 [SOUND_MIXER_TREBLE] = { AC97_MIX_TONE, 4, 0, 0, 0, 0, 1, 0 },
88 [SOUND_MIXER_PCM] = { AC97_MIX_PCM, 5, 0, 1, 1, 0, 0, 1 },
89 [SOUND_MIXER_SPEAKER] = { AC97_MIX_BEEP, 4, 1, 0, 1, 0, 0, 0 },
90 [SOUND_MIXER_LINE] = { AC97_MIX_LINE, 5, 0, 1, 1, 5, 0, 1 },
91 [SOUND_MIXER_PHONEIN] = { AC97_MIX_PHONE, 5, 0, 0, 1, 8, 0, 0 },
92 [SOUND_MIXER_MIC] = { AC97_MIX_MIC, 5, 0, 0, 1, 1, 1, 1 },
93 /* use igain for the mic 20dB boost */
94 [SOUND_MIXER_IGAIN] = { -AC97_MIX_MIC, 1, 6, 0, 0, 0, 1, 1 },
95 [SOUND_MIXER_CD] = { AC97_MIX_CD, 5, 0, 1, 1, 2, 0, 1 },
96 [SOUND_MIXER_LINE1] = { AC97_MIX_AUX, 5, 0, 1, 1, 4, 0, 0 },
97 [SOUND_MIXER_VIDEO] = { AC97_MIX_VIDEO, 5, 0, 1, 1, 3, 0, 0 },
98 [SOUND_MIXER_RECLEV] = { -AC97_MIX_RGAIN, 4, 0, 1, 1, 0, 0, 1 }
101 static const struct ac97_vendorid ac97vendorid[] = {
102 { 0x41445300, "Analog Devices" },
103 { 0x414b4d00, "Asahi Kasei" },
104 { 0x414c4300, "Realtek" },
105 { 0x414c4700, "Avance Logic" },
106 { 0x43525900, "Cirrus Logic" },
107 { 0x434d4900, "C-Media Electronics" },
108 { 0x43585400, "Conexant" },
109 { 0x44543000, "Diamond Technology" },
110 { 0x454d4300, "eMicro" },
111 { 0x45838300, "ESS Technology" },
112 { 0x48525300, "Intersil" },
113 { 0x49434500, "ICEnsemble" },
114 { 0x49544500, "ITE, Inc." },
115 { 0x4e534300, "National Semiconductor" },
116 { 0x50534300, "Philips Semiconductor" },
117 { 0x83847600, "SigmaTel" },
118 { 0x53494c00, "Silicon Laboratories" },
119 { 0x54524100, "TriTech" },
120 { 0x54584e00, "Texas Instruments" },
121 { 0x56494100, "VIA Technologies" },
122 { 0x57454300, "Winbond" },
123 { 0x574d4c00, "Wolfson" },
124 { 0x594d4800, "Yamaha" },
126 * XXX This is a fluke, really! The real vendor
127 * should be SigmaTel, not this! This should be
128 * removed someday!
130 { 0x01408300, "Creative" },
131 { 0x00000000, NULL }
134 static struct ac97_codecid ac97codecid[] = {
135 { 0x41445303, 0x00, 0, "AD1819", 0 },
136 { 0x41445340, 0x00, 0, "AD1881", 0 },
137 { 0x41445348, 0x00, 0, "AD1881A", 0 },
138 { 0x41445360, 0x00, 0, "AD1885", 0 },
139 { 0x41445361, 0x00, 0, "AD1886", ad1886_patch },
140 { 0x41445362, 0x00, 0, "AD1887", 0 },
141 { 0x41445363, 0x00, 0, "AD1886A", 0 },
142 { 0x41445368, 0x00, 0, "AD1888", ad198x_patch },
143 { 0x41445370, 0x00, 0, "AD1980", ad198x_patch },
144 { 0x41445372, 0x00, 0, "AD1981A", 0 },
145 { 0x41445374, 0x00, 0, "AD1981B", ad1981b_patch },
146 { 0x41445375, 0x00, 0, "AD1985", ad198x_patch },
147 { 0x41445378, 0x00, 0, "AD1986", ad198x_patch },
148 { 0x414b4d00, 0x00, 1, "AK4540", 0 },
149 { 0x414b4d01, 0x00, 1, "AK4542", 0 },
150 { 0x414b4d02, 0x00, 1, "AK4543", 0 },
151 { 0x414b4d06, 0x00, 0, "AK4544A", 0 },
152 { 0x454b4d07, 0x00, 0, "AK4545", 0 },
153 { 0x414c4320, 0x0f, 0, "ALC100", 0 },
154 { 0x414c4730, 0x0f, 0, "ALC101", 0 },
155 { 0x414c4710, 0x0f, 0, "ALC200", 0 },
156 { 0x414c4740, 0x0f, 0, "ALC202", 0 },
157 { 0x414c4720, 0x0f, 0, "ALC650", 0 },
158 { 0x414c4752, 0x0f, 0, "ALC250", 0 },
159 { 0x414c4760, 0x0f, 0, "ALC655", alc655_patch },
160 { 0x414c4770, 0x0f, 0, "ALC203", 0 },
161 { 0x414c4780, 0x0f, 0, "ALC658", 0 },
162 { 0x414c4790, 0x0f, 0, "ALC850", 0 },
163 { 0x43525900, 0x07, 0, "CS4297", 0 },
164 { 0x43525910, 0x07, 0, "CS4297A", 0 },
165 { 0x43525920, 0x07, 0, "CS4294/98", 0 },
166 { 0x4352592d, 0x07, 0, "CS4294", 0 },
167 { 0x43525930, 0x07, 0, "CS4299", 0 },
168 { 0x43525940, 0x07, 0, "CS4201", 0 },
169 { 0x43525958, 0x07, 0, "CS4205", 0 },
170 { 0x43525960, 0x07, 0, "CS4291A", 0 },
171 { 0x434d4961, 0x00, 0, "CMI9739", cmi9739_patch },
172 { 0x434d4941, 0x00, 0, "CMI9738", 0 },
173 { 0x434d4978, 0x00, 0, "CMI9761", 0 },
174 { 0x434d4982, 0x00, 0, "CMI9761", 0 },
175 { 0x434d4983, 0x00, 0, "CMI9761", 0 },
176 { 0x43585421, 0x00, 0, "HSD11246", 0 },
177 { 0x43585428, 0x07, 0, "CX20468", 0 },
178 { 0x43585430, 0x00, 0, "CX20468-21", 0 },
179 { 0x44543000, 0x00, 0, "DT0398", 0 },
180 { 0x454d4323, 0x00, 0, "EM28023", 0 },
181 { 0x454d4328, 0x00, 0, "EM28028", 0 },
182 { 0x45838308, 0x00, 0, "ES1988", 0 }, /* Formerly ES1921(?) */
183 { 0x48525300, 0x00, 0, "HMP9701", 0 },
184 { 0x49434501, 0x00, 0, "ICE1230", 0 },
185 { 0x49434511, 0x00, 0, "ICE1232", 0 },
186 { 0x49434514, 0x00, 0, "ICE1232A", 0 },
187 { 0x49434551, 0x03, 0, "VT1616", 0 }, /* Via badged ICE */
188 { 0x49544520, 0x00, 0, "ITE2226E", 0 },
189 { 0x49544560, 0x07, 0, "ITE2646E", 0 }, /* XXX: patch needed */
190 { 0x4e534340, 0x00, 0, "LM4540", 0 }, /* Spec blank on revid */
191 { 0x4e534343, 0x00, 0, "LM4543", 0 }, /* Ditto */
192 { 0x4e534346, 0x00, 0, "LM4546A", 0 },
193 { 0x4e534348, 0x00, 0, "LM4548A", 0 },
194 { 0x4e534331, 0x00, 0, "LM4549", 0 },
195 { 0x4e534349, 0x00, 0, "LM4549A", 0 },
196 { 0x4e534350, 0x00, 0, "LM4550", 0 },
197 { 0x50534301, 0x00, 0, "UCB1510", 0 },
198 { 0x50534304, 0x00, 0, "UCB1400", 0 },
199 { 0x83847600, 0x00, 0, "STAC9700/83/84", 0 },
200 { 0x83847604, 0x00, 0, "STAC9701/03/04/05", 0 },
201 { 0x83847605, 0x00, 0, "STAC9704", 0 },
202 { 0x83847608, 0x00, 0, "STAC9708/11", 0 },
203 { 0x83847609, 0x00, 0, "STAC9721/23", 0 },
204 { 0x83847644, 0x00, 0, "STAC9744/45", 0 },
205 { 0x83847650, 0x00, 0, "STAC9750/51", 0 },
206 { 0x83847652, 0x00, 0, "STAC9752/53", 0 },
207 { 0x83847656, 0x00, 0, "STAC9756/57", 0 },
208 { 0x83847658, 0x00, 0, "STAC9758/59", 0 },
209 { 0x83847660, 0x00, 0, "STAC9760/61", 0 }, /* Extrapolated */
210 { 0x83847662, 0x00, 0, "STAC9762/63", 0 }, /* Extrapolated */
211 { 0x83847666, 0x00, 0, "STAC9766/67", 0 },
212 { 0x53494c22, 0x00, 0, "Si3036", 0 },
213 { 0x53494c23, 0x00, 0, "Si3038", 0 },
214 { 0x54524103, 0x00, 0, "TR28023", 0 }, /* Extrapolated */
215 { 0x54524106, 0x00, 0, "TR28026", 0 },
216 { 0x54524108, 0x00, 0, "TR28028", 0 },
217 { 0x54524123, 0x00, 0, "TR28602", 0 },
218 { 0x54524e03, 0x07, 0, "TLV320AIC27", 0 },
219 { 0x54584e20, 0x00, 0, "TLC320AD90", 0 },
220 { 0x56494161, 0x00, 0, "VIA1612A", 0 },
221 { 0x56494170, 0x00, 0, "VIA1617A", 0 },
222 { 0x574d4c00, 0x00, 0, "WM9701A", 0 },
223 { 0x574d4c03, 0x00, 0, "WM9703/4/7/8", 0 },
224 { 0x574d4c04, 0x00, 0, "WM9704Q", 0 },
225 { 0x574d4c05, 0x00, 0, "WM9705/10", 0 },
226 { 0x574d4d09, 0x00, 0, "WM9709", 0 },
227 { 0x574d4c12, 0x00, 0, "WM9711/12", 0 }, /* XXX: patch needed */
228 { 0x57454301, 0x00, 0, "W83971D", 0 },
229 { 0x594d4800, 0x00, 0, "YMF743", 0 },
230 { 0x594d4802, 0x00, 0, "YMF752", 0 },
231 { 0x594d4803, 0x00, 0, "YMF753", 0 },
233 * XXX This is a fluke, really! The real codec
234 * should be STAC9704, not this! This should be
235 * removed someday!
237 { 0x01408384, 0x00, 0, "EV1938", 0 },
238 { 0, 0, 0, NULL, 0 }
241 static char *ac97enhancement[] = {
242 "no 3D Stereo Enhancement",
243 "Analog Devices Phat Stereo",
244 "Creative Stereo Enhancement",
245 "National Semi 3D Stereo Enhancement",
246 "Yamaha Ymersion",
247 "BBE 3D Stereo Enhancement",
248 "Crystal Semi 3D Stereo Enhancement",
249 "Qsound QXpander",
250 "Spatializer 3D Stereo Enhancement",
251 "SRS 3D Stereo Enhancement",
252 "Platform Tech 3D Stereo Enhancement",
253 "AKM 3D Audio",
254 "Aureal Stereo Enhancement",
255 "Aztech 3D Enhancement",
256 "Binaura 3D Audio Enhancement",
257 "ESS Technology Stereo Enhancement",
258 "Harman International VMAx",
259 "Nvidea 3D Stereo Enhancement",
260 "Philips Incredible Sound",
261 "Texas Instruments 3D Stereo Enhancement",
262 "VLSI Technology 3D Stereo Enhancement",
263 "TriTech 3D Stereo Enhancement",
264 "Realtek 3D Stereo Enhancement",
265 "Samsung 3D Stereo Enhancement",
266 "Wolfson Microelectronics 3D Enhancement",
267 "Delta Integration 3D Enhancement",
268 "SigmaTel 3D Enhancement",
269 "Reserved 27",
270 "Rockwell 3D Stereo Enhancement",
271 "Reserved 29",
272 "Reserved 30",
273 "Reserved 31"
276 static char *ac97feature[] = {
277 "mic channel",
278 "reserved",
279 "tone",
280 "simulated stereo",
281 "headphone",
282 "bass boost",
283 "18 bit DAC",
284 "20 bit DAC",
285 "18 bit ADC",
286 "20 bit ADC"
289 static char *ac97extfeature[] = {
290 "variable rate PCM",
291 "double rate PCM",
292 "reserved 1",
293 "variable rate mic",
294 "reserved 2",
295 "reserved 3",
296 "center DAC",
297 "surround DAC",
298 "LFE DAC",
299 "AMAP",
300 "reserved 4",
301 "reserved 5",
302 "reserved 6",
303 "reserved 7",
306 u_int16_t
307 ac97_rdcd(struct ac97_info *codec, int reg)
309 if (codec->flags & AC97_F_RDCD_BUG) {
310 u_int16_t i[2], j = 100;
312 i[0] = AC97_READ(codec->methods, codec->devinfo, reg);
313 i[1] = AC97_READ(codec->methods, codec->devinfo, reg);
314 while (i[0] != i[1] && j)
315 i[j-- & 1] = AC97_READ(codec->methods, codec->devinfo, reg);
316 #if 0
317 if (j < 100) {
318 device_printf(codec->dev, "%s(): Inconsistent register value at"
319 " 0x%08x (retry: %d)\n", __func__, reg, 100 - j);
321 #endif
322 return i[!(j & 1)];
324 return AC97_READ(codec->methods, codec->devinfo, reg);
327 void
328 ac97_wrcd(struct ac97_info *codec, int reg, u_int16_t val)
330 AC97_WRITE(codec->methods, codec->devinfo, reg, val);
333 static void
334 ac97_reset(struct ac97_info *codec)
336 u_int32_t i, ps;
337 ac97_wrcd(codec, AC97_REG_RESET, 0);
338 for (i = 0; i < 500; i++) {
339 ps = ac97_rdcd(codec, AC97_REG_POWER) & AC97_POWER_STATUS;
340 if (ps == AC97_POWER_STATUS)
341 return;
342 DELAY(1000);
344 device_printf(codec->dev, "AC97 reset timed out.\n");
348 ac97_setrate(struct ac97_info *codec, int which, int rate)
350 u_int16_t v;
352 switch(which) {
353 case AC97_REGEXT_FDACRATE:
354 case AC97_REGEXT_SDACRATE:
355 case AC97_REGEXT_LDACRATE:
356 case AC97_REGEXT_LADCRATE:
357 case AC97_REGEXT_MADCRATE:
358 break;
360 default:
361 return -1;
364 snd_mtxlock(codec->lock);
365 if (rate != 0) {
366 v = rate;
367 if (codec->extstat & AC97_EXTCAP_DRA)
368 v >>= 1;
369 ac97_wrcd(codec, which, v);
371 v = ac97_rdcd(codec, which);
372 if (codec->extstat & AC97_EXTCAP_DRA)
373 v <<= 1;
374 snd_mtxunlock(codec->lock);
375 return v;
379 ac97_setextmode(struct ac97_info *codec, u_int16_t mode)
381 mode &= AC97_EXTCAPS;
382 if ((mode & ~codec->extcaps) != 0) {
383 device_printf(codec->dev, "ac97 invalid mode set 0x%04x\n",
384 mode);
385 return -1;
387 snd_mtxlock(codec->lock);
388 ac97_wrcd(codec, AC97_REGEXT_STAT, mode);
389 codec->extstat = ac97_rdcd(codec, AC97_REGEXT_STAT) & AC97_EXTCAPS;
390 snd_mtxunlock(codec->lock);
391 return (mode == codec->extstat)? 0 : -1;
394 u_int16_t
395 ac97_getextmode(struct ac97_info *codec)
397 return codec->extstat;
400 u_int16_t
401 ac97_getextcaps(struct ac97_info *codec)
403 return codec->extcaps;
406 u_int16_t
407 ac97_getcaps(struct ac97_info *codec)
409 return codec->caps;
412 u_int32_t
413 ac97_getsubvendor(struct ac97_info *codec)
415 return codec->subvendor;
418 static int
419 ac97_setrecsrc(struct ac97_info *codec, int channel)
421 struct ac97mixtable_entry *e = &codec->mix[channel];
423 if (e->recidx > 0) {
424 int val = e->recidx - 1;
425 val |= val << 8;
426 snd_mtxlock(codec->lock);
427 ac97_wrcd(codec, AC97_REG_RECSEL, val);
428 snd_mtxunlock(codec->lock);
429 return 0;
430 } else
431 return -1;
434 static int
435 ac97_setmixer(struct ac97_info *codec, unsigned channel, unsigned left, unsigned right)
437 struct ac97mixtable_entry *e = &codec->mix[channel];
439 if (e->reg && e->enable && e->bits) {
440 int mask, max, val, reg;
442 reg = (e->reg >= 0) ? e->reg : -e->reg; /* AC97 register */
443 max = (1 << e->bits) - 1; /* actual range */
444 mask = (max << 8) | max; /* bits of interest */
446 if (!e->stereo)
447 right = left;
450 * Invert the range if the polarity requires so,
451 * then scale to 0..max-1 to compute the value to
452 * write into the codec, and scale back to 0..100
453 * for the return value.
455 if (e->reg > 0) {
456 left = 100 - left;
457 right = 100 - right;
460 left = (left * max) / 100;
461 right = (right * max) / 100;
463 val = (left << 8) | right;
465 left = (left * 100) / max;
466 right = (right * 100) / max;
468 if (e->reg > 0) {
469 left = 100 - left;
470 right = 100 - right;
474 * For mono controls, trim val and mask, also taking
475 * care of e->ofs (offset of control field).
477 if (e->ofs) {
478 val &= max;
479 val <<= e->ofs;
480 mask = (max << e->ofs);
484 * If we have a mute bit, add it to the mask and
485 * update val and set mute if both channels require a
486 * zero volume.
488 if (e->mute == 1) {
489 mask |= AC97_MUTE;
490 if (left == 0 && right == 0)
491 val = AC97_MUTE;
495 * If the mask bit is set, do not alter the other bits.
497 snd_mtxlock(codec->lock);
498 if (e->mask) {
499 int cur = ac97_rdcd(codec, reg);
500 val |= cur & ~(mask);
502 ac97_wrcd(codec, reg, val);
503 snd_mtxunlock(codec->lock);
504 return left | (right << 8);
505 } else {
506 #if 0
507 kprintf("ac97_setmixer: reg=%d, bits=%d, enable=%d\n", e->reg, e->bits, e->enable);
508 #endif
509 return -1;
513 static void
514 ac97_fix_auxout(struct ac97_info *codec)
516 int keep_ogain;
519 * By default, The ac97 aux_out register (0x04) corresponds to OSS's
520 * OGAIN setting.
522 * We first check whether aux_out is a valid register. If not
523 * we may not want to keep ogain.
525 keep_ogain = ac97_rdcd(codec, AC97_MIX_AUXOUT) & 0x8000;
528 * Determine what AUX_OUT really means, it can be:
530 * 1. Headphone out.
531 * 2. 4-Channel Out
532 * 3. True line level out (effectively master volume).
534 * See Sections 5.2.1 and 5.27 for AUX_OUT Options in AC97r2.{2,3}.
536 if (codec->extcaps & AC97_EXTCAP_SDAC &&
537 ac97_rdcd(codec, AC97_MIXEXT_SURROUND) == 0x8080) {
538 codec->mix[SOUND_MIXER_OGAIN].reg = AC97_MIXEXT_SURROUND;
539 keep_ogain = 1;
542 if (keep_ogain == 0) {
543 bzero(&codec->mix[SOUND_MIXER_OGAIN],
544 sizeof(codec->mix[SOUND_MIXER_OGAIN]));
548 static void
549 ac97_fix_tone(struct ac97_info *codec)
552 * YMF chips does not indicate tone and 3D enhancement capability
553 * in the AC97_REG_RESET register.
555 switch (codec->id) {
556 case 0x594d4800: /* YMF743 */
557 case 0x594d4803: /* YMF753 */
558 codec->caps |= AC97_CAP_TONE;
559 codec->se |= 0x04;
560 break;
561 case 0x594d4802: /* YMF752 */
562 codec->se |= 0x04;
563 break;
564 default:
565 break;
568 /* Hide treble and bass if they don't exist */
569 if ((codec->caps & AC97_CAP_TONE) == 0) {
570 bzero(&codec->mix[SOUND_MIXER_BASS],
571 sizeof(codec->mix[SOUND_MIXER_BASS]));
572 bzero(&codec->mix[SOUND_MIXER_TREBLE],
573 sizeof(codec->mix[SOUND_MIXER_TREBLE]));
577 static const char*
578 ac97_hw_desc(u_int32_t id, const char* vname, const char* cname, char* buf)
580 if (cname == NULL) {
581 ksprintf(buf, "Unknown AC97 Codec (id = 0x%08x)", id);
582 return buf;
585 if (vname == NULL) vname = "Unknown";
587 if (bootverbose) {
588 ksprintf(buf, "%s %s AC97 Codec (id = 0x%08x)", vname, cname, id);
589 } else {
590 ksprintf(buf, "%s %s AC97 Codec", vname, cname);
592 return buf;
595 static unsigned
596 ac97_initmixer(struct ac97_info *codec)
598 ac97_patch codec_patch;
599 const char *cname, *vname;
600 char desc[80];
601 u_int8_t model, step;
602 unsigned i, j, k, bit, old;
603 u_int32_t id;
604 int reg;
606 snd_mtxlock(codec->lock);
607 codec->count = AC97_INIT(codec->methods, codec->devinfo);
608 if (codec->count == 0) {
609 device_printf(codec->dev, "ac97 codec init failed\n");
610 snd_mtxunlock(codec->lock);
611 return ENODEV;
614 ac97_wrcd(codec, AC97_REG_POWER, (codec->flags & AC97_F_EAPD_INV)? 0x8000 : 0x0000);
615 ac97_reset(codec);
616 ac97_wrcd(codec, AC97_REG_POWER, (codec->flags & AC97_F_EAPD_INV)? 0x8000 : 0x0000);
618 i = ac97_rdcd(codec, AC97_REG_RESET);
619 j = ac97_rdcd(codec, AC97_REG_RESET);
621 * Let see if this codec can return consistent value.
622 * If not, turn on aggressive read workaround
623 * (STAC9704 comes in mind).
625 if (i != j) {
626 codec->flags |= AC97_F_RDCD_BUG;
627 i = ac97_rdcd(codec, AC97_REG_RESET);
629 codec->caps = i & 0x03ff;
630 codec->se = (i & 0x7c00) >> 10;
632 id = (ac97_rdcd(codec, AC97_REG_ID1) << 16) | ac97_rdcd(codec, AC97_REG_ID2);
633 if (id == 0 || id == 0xffffffff) {
634 device_printf(codec->dev, "ac97 codec invalid or not present (id == %x)\n", id);
635 snd_mtxunlock(codec->lock);
636 return ENODEV;
639 codec->id = id;
640 codec->subvendor = (u_int32_t)pci_get_subdevice(codec->dev) << 16;
641 codec->subvendor |= (u_int32_t)pci_get_subvendor(codec->dev) &
642 0x0000ffff;
643 codec->noext = 0;
644 codec_patch = NULL;
646 cname = NULL;
647 model = step = 0;
648 for (i = 0; ac97codecid[i].id; i++) {
649 u_int32_t modelmask = 0xffffffff ^ ac97codecid[i].stepmask;
650 if ((ac97codecid[i].id & modelmask) == (id & modelmask)) {
651 codec->noext = ac97codecid[i].noext;
652 codec_patch = ac97codecid[i].patch;
653 cname = ac97codecid[i].name;
654 model = (id & modelmask) & 0xff;
655 step = (id & ~modelmask) & 0xff;
656 break;
660 vname = NULL;
661 for (i = 0; ac97vendorid[i].id; i++) {
662 if (ac97vendorid[i].id == (id & 0xffffff00)) {
663 vname = ac97vendorid[i].name;
664 break;
668 codec->extcaps = 0;
669 codec->extid = 0;
670 codec->extstat = 0;
671 if (!codec->noext) {
672 i = ac97_rdcd(codec, AC97_REGEXT_ID);
673 if (i != 0xffff) {
674 codec->extcaps = i & 0x3fff;
675 codec->extid = (i & 0xc000) >> 14;
676 codec->extstat = ac97_rdcd(codec, AC97_REGEXT_STAT) & AC97_EXTCAPS;
680 for (i = 0; i < 32; i++) {
681 codec->mix[i] = ac97mixtable_default[i];
683 ac97_fix_auxout(codec);
684 ac97_fix_tone(codec);
685 if (codec_patch)
686 codec_patch(codec);
688 for (i = 0; i < 32; i++) {
689 k = codec->noext? codec->mix[i].enable : 1;
690 reg = codec->mix[i].reg;
691 if (reg < 0)
692 reg = -reg;
693 if (k && reg) {
694 j = old = ac97_rdcd(codec, reg);
696 * Test for mute bit (except for AC97_MIX_TONE,
697 * where we simply assume it as available).
699 if (codec->mix[i].mute) {
700 ac97_wrcd(codec, reg, j | 0x8000);
701 j = ac97_rdcd(codec, reg);
702 } else
703 j |= 0x8000;
704 if ((j & 0x8000)) {
706 * Test whether the control width should be
707 * 4, 5 or 6 bit. For 5bit register, we should
708 * test it whether it's really 5 or 6bit. Leave
709 * 4bit register alone, because sometimes an
710 * attempt to write past 4th bit may cause
711 * incorrect result especially for AC97_MIX_BEEP
712 * (ac97 2.3).
714 bit = codec->mix[i].bits;
715 if (bit == 5)
716 bit++;
717 j = ((1 << bit) - 1) << codec->mix[i].ofs;
718 ac97_wrcd(codec, reg,
719 j | (codec->mix[i].mute ? 0x8000 : 0));
720 k = ac97_rdcd(codec, reg) & j;
721 k >>= codec->mix[i].ofs;
722 if (reg == AC97_MIX_TONE &&
723 ((k & 0x0001) == 0x0000))
724 k >>= 1;
725 for (j = 0; k >> j; j++)
727 if (j != 0) {
728 #if 0
729 device_printf(codec->dev, "%2d: [ac97_rdcd() = %d] [Testbit = %d] %d -> %d\n",
730 i, k, bit, codec->mix[i].bits, j);
731 #endif
732 codec->mix[i].enable = 1;
733 codec->mix[i].bits = j;
734 } else if (reg == AC97_MIX_BEEP) {
736 * Few codec such as CX20468-21 does
737 * have this control register, although
738 * the only usable part is the mute bit.
740 codec->mix[i].enable = 1;
741 } else
742 codec->mix[i].enable = 0;
743 } else
744 codec->mix[i].enable = 0;
745 ac97_wrcd(codec, reg, old);
747 #if 0
748 kprintf("mixch %d, en=%d, b=%d\n", i, codec->mix[i].enable, codec->mix[i].bits);
749 #endif
752 device_printf(codec->dev, "<%s>\n",
753 ac97_hw_desc(codec->id, vname, cname, desc));
755 if (bootverbose) {
756 if (codec->flags & AC97_F_RDCD_BUG)
757 device_printf(codec->dev, "Buggy AC97 Codec: aggressive ac97_rdcd() workaround enabled\n");
758 device_printf(codec->dev, "Codec features ");
759 for (i = j = 0; i < 10; i++)
760 if (codec->caps & (1 << i))
761 kprintf("%s%s", j++? ", " : "", ac97feature[i]);
762 kprintf("%s%d bit master volume", j++? ", " : "", codec->mix[SOUND_MIXER_VOLUME].bits);
763 kprintf("%s%s\n", j? ", " : "", ac97enhancement[codec->se]);
765 if (codec->extcaps != 0 || codec->extid) {
766 device_printf(codec->dev, "%s codec",
767 codec->extid? "Secondary" : "Primary");
768 if (codec->extcaps)
769 kprintf(" extended features ");
770 for (i = j = 0; i < 14; i++)
771 if (codec->extcaps & (1 << i))
772 kprintf("%s%s", j++? ", " : "", ac97extfeature[i]);
773 kprintf("\n");
777 i = 0;
778 while ((ac97_rdcd(codec, AC97_REG_POWER) & 2) == 0) {
779 if (++i == 100) {
780 device_printf(codec->dev, "ac97 codec reports dac not ready\n");
781 break;
783 DELAY(1000);
785 if (bootverbose)
786 device_printf(codec->dev, "ac97 codec dac ready count: %d\n", i);
787 snd_mtxunlock(codec->lock);
788 return 0;
791 static unsigned
792 ac97_reinitmixer(struct ac97_info *codec)
794 snd_mtxlock(codec->lock);
795 codec->count = AC97_INIT(codec->methods, codec->devinfo);
796 if (codec->count == 0) {
797 device_printf(codec->dev, "ac97 codec init failed\n");
798 snd_mtxunlock(codec->lock);
799 return ENODEV;
802 ac97_wrcd(codec, AC97_REG_POWER, (codec->flags & AC97_F_EAPD_INV)? 0x8000 : 0x0000);
803 ac97_reset(codec);
804 ac97_wrcd(codec, AC97_REG_POWER, (codec->flags & AC97_F_EAPD_INV)? 0x8000 : 0x0000);
806 if (!codec->noext) {
807 ac97_wrcd(codec, AC97_REGEXT_STAT, codec->extstat);
808 if ((ac97_rdcd(codec, AC97_REGEXT_STAT) & AC97_EXTCAPS)
809 != codec->extstat)
810 device_printf(codec->dev, "ac97 codec failed to reset extended mode (%x, got %x)\n",
811 codec->extstat,
812 ac97_rdcd(codec, AC97_REGEXT_STAT) &
813 AC97_EXTCAPS);
816 if ((ac97_rdcd(codec, AC97_REG_POWER) & 2) == 0)
817 device_printf(codec->dev, "ac97 codec reports dac not ready\n");
818 snd_mtxunlock(codec->lock);
819 return 0;
822 struct ac97_info *
823 ac97_create(device_t dev, void *devinfo, kobj_class_t cls)
825 struct ac97_info *codec;
827 codec = (struct ac97_info *)kmalloc(sizeof *codec, M_AC97, M_NOWAIT);
828 if (codec == NULL)
829 return NULL;
831 ksnprintf(codec->name, AC97_NAMELEN, "%s:ac97", device_get_nameunit(dev));
832 codec->lock = snd_mtxcreate(codec->name, "ac97 codec");
833 codec->methods = kobj_create(cls, M_AC97, M_WAITOK);
834 if (codec->methods == NULL) {
835 snd_mtxfree(codec->lock);
836 kfree(codec, M_AC97);
837 return NULL;
840 codec->dev = dev;
841 codec->devinfo = devinfo;
842 codec->flags = 0;
843 return codec;
846 void
847 ac97_destroy(struct ac97_info *codec)
849 if (codec->methods != NULL)
850 kobj_delete(codec->methods, M_AC97);
851 snd_mtxfree(codec->lock);
852 kfree(codec, M_AC97);
855 void
856 ac97_setflags(struct ac97_info *codec, u_int32_t val)
858 codec->flags = val;
861 u_int32_t
862 ac97_getflags(struct ac97_info *codec)
864 return codec->flags;
867 /* -------------------------------------------------------------------- */
869 static int
870 ac97mix_init(struct snd_mixer *m)
872 struct ac97_info *codec = mix_getdevinfo(m);
873 u_int32_t i, mask;
875 if (codec == NULL)
876 return -1;
878 if (ac97_initmixer(codec))
879 return -1;
881 switch (codec->id) {
882 case 0x41445374: /* AD1981B */
883 switch (codec->subvendor) {
884 case 0x02d91014:
886 * IBM Thinkcentre:
888 * Tie "ogain" and "phout" to "vol" since its
889 * master volume is basically useless and can't
890 * control anything.
892 mask = 0;
893 if (codec->mix[SOUND_MIXER_OGAIN].enable)
894 mask |= SOUND_MASK_OGAIN;
895 if (codec->mix[SOUND_MIXER_PHONEOUT].enable)
896 mask |= SOUND_MASK_PHONEOUT;
897 if (codec->mix[SOUND_MIXER_VOLUME].enable)
898 mix_setparentchild(m, SOUND_MIXER_VOLUME,
899 mask);
900 else {
901 mix_setparentchild(m, SOUND_MIXER_VOLUME,
902 mask);
903 mix_setrealdev(m, SOUND_MIXER_VOLUME,
904 SOUND_MIXER_NONE);
906 break;
907 case 0x099c103c:
909 * HP nx6110:
911 * By default, "vol" is controlling internal speakers
912 * (not a master volume!) and "ogain" is controlling
913 * headphone. Enable dummy "phout" so it can be
914 * remapped to internal speakers and virtualize
915 * "vol" to control both.
917 codec->mix[SOUND_MIXER_OGAIN].enable = 1;
918 codec->mix[SOUND_MIXER_PHONEOUT].enable = 1;
919 mix_setrealdev(m, SOUND_MIXER_PHONEOUT,
920 SOUND_MIXER_VOLUME);
921 mix_setrealdev(m, SOUND_MIXER_VOLUME,
922 SOUND_MIXER_NONE);
923 mix_setparentchild(m, SOUND_MIXER_VOLUME,
924 SOUND_MASK_OGAIN | SOUND_MASK_PHONEOUT);
925 break;
926 default:
927 break;
929 break;
930 case 0x434d4941: /* CMI9738 */
931 case 0x434d4961: /* CMI9739 */
932 case 0x434d4978: /* CMI9761 */
933 case 0x434d4982: /* CMI9761 */
934 case 0x434d4983: /* CMI9761 */
935 ac97_wrcd(codec, AC97_MIX_PCM, 0);
936 bzero(&codec->mix[SOUND_MIXER_PCM],
937 sizeof(codec->mix[SOUND_MIXER_PCM]));
938 pcm_setflags(codec->dev, pcm_getflags(codec->dev) |
939 SD_F_SOFTPCMVOL);
940 /* XXX How about master volume ? */
941 break;
942 default:
943 break;
946 #if 0
947 /* XXX For the sake of debugging purposes */
948 mix_setparentchild(m, SOUND_MIXER_VOLUME,
949 SOUND_MASK_PCM | SOUND_MASK_CD);
950 mix_setrealdev(m, SOUND_MIXER_VOLUME, SOUND_MIXER_NONE);
951 ac97_wrcd(codec, AC97_MIX_MASTER, 0);
952 #endif
954 mask = 0;
955 for (i = 0; i < 32; i++)
956 mask |= codec->mix[i].enable? 1 << i : 0;
957 mix_setdevs(m, mask);
959 mask = 0;
960 for (i = 0; i < 32; i++)
961 mask |= codec->mix[i].recidx? 1 << i : 0;
962 mix_setrecdevs(m, mask);
963 return 0;
966 static int
967 ac97mix_uninit(struct snd_mixer *m)
969 struct ac97_info *codec = mix_getdevinfo(m);
971 if (codec == NULL)
972 return -1;
974 if (ac97_uninitmixer(codec))
975 return -1;
977 ac97_destroy(codec);
978 return 0;
981 static int
982 ac97mix_reinit(struct snd_mixer *m)
984 struct ac97_info *codec = mix_getdevinfo(m);
986 if (codec == NULL)
987 return -1;
988 return ac97_reinitmixer(codec);
991 static int
992 ac97mix_set(struct snd_mixer *m, unsigned dev, unsigned left, unsigned right)
994 struct ac97_info *codec = mix_getdevinfo(m);
996 if (codec == NULL)
997 return -1;
998 return ac97_setmixer(codec, dev, left, right);
1001 static int
1002 ac97mix_setrecsrc(struct snd_mixer *m, u_int32_t src)
1004 int i;
1005 struct ac97_info *codec = mix_getdevinfo(m);
1007 if (codec == NULL)
1008 return -1;
1009 for (i = 0; i < SOUND_MIXER_NRDEVICES; i++)
1010 if ((src & (1 << i)) != 0)
1011 break;
1012 return (ac97_setrecsrc(codec, i) == 0)? 1 << i : -1;
1015 static kobj_method_t ac97mixer_methods[] = {
1016 KOBJMETHOD(mixer_init, ac97mix_init),
1017 KOBJMETHOD(mixer_uninit, ac97mix_uninit),
1018 KOBJMETHOD(mixer_reinit, ac97mix_reinit),
1019 KOBJMETHOD(mixer_set, ac97mix_set),
1020 KOBJMETHOD(mixer_setrecsrc, ac97mix_setrecsrc),
1021 { 0, 0 }
1023 MIXER_DECLARE(ac97mixer);
1025 /* -------------------------------------------------------------------- */
1027 kobj_class_t
1028 ac97_getmixerclass(void)
1030 return &ac97mixer_class;