Update all sound code to use the snd_*() locking abstraction and sndlock_t.
[dragonfly/vkernel-mp.git] / sys / dev / sound / pcm / ac97.c
blobc92585b947ba38d71476acc324f2e688df31b086
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.5 2007/05/13 20:53:39 ariff Exp $
27 * $DragonFly: src/sys/dev/sound/pcm/ac97.c,v 1.25 2007/06/16 20:07:22 dillon 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.25 2007/06/16 20:07:22 dillon 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 void
578 ac97_fix_volume(struct ac97_info *codec)
580 struct snddev_info *d = device_get_softc(codec->dev);
582 #if 0
583 /* XXX For the sake of debugging purposes */
584 ac97_wrcd(codec, AC97_MIX_PCM, 0);
585 bzero(&codec->mix[SOUND_MIXER_PCM],
586 sizeof(codec->mix[SOUND_MIXER_PCM]));
587 if (d)
588 d->flags |= SD_F_SOFTPCMVOL;
589 return;
590 #endif
591 switch (codec->id) {
592 case 0x434d4941: /* CMI9738 */
593 case 0x434d4961: /* CMI9739 */
594 case 0x434d4978: /* CMI9761 */
595 case 0x434d4982: /* CMI9761 */
596 case 0x434d4983: /* CMI9761 */
597 ac97_wrcd(codec, AC97_MIX_PCM, 0);
598 break;
599 default:
600 return;
601 break;
603 bzero(&codec->mix[SOUND_MIXER_PCM],
604 sizeof(codec->mix[SOUND_MIXER_PCM]));
605 if (d)
606 d->flags |= SD_F_SOFTPCMVOL;
609 static const char*
610 ac97_hw_desc(u_int32_t id, const char* vname, const char* cname, char* buf)
612 if (cname == NULL) {
613 ksprintf(buf, "Unknown AC97 Codec (id = 0x%08x)", id);
614 return buf;
617 if (vname == NULL) vname = "Unknown";
619 if (bootverbose) {
620 ksprintf(buf, "%s %s AC97 Codec (id = 0x%08x)", vname, cname, id);
621 } else {
622 ksprintf(buf, "%s %s AC97 Codec", vname, cname);
624 return buf;
627 static unsigned
628 ac97_initmixer(struct ac97_info *codec)
630 ac97_patch codec_patch;
631 const char *cname, *vname;
632 char desc[80];
633 u_int8_t model, step;
634 unsigned i, j, k, bit, old;
635 u_int32_t id;
636 int reg;
638 snd_mtxlock(codec->lock);
639 codec->count = AC97_INIT(codec->methods, codec->devinfo);
640 if (codec->count == 0) {
641 device_printf(codec->dev, "ac97 codec init failed\n");
642 snd_mtxunlock(codec->lock);
643 return ENODEV;
646 ac97_wrcd(codec, AC97_REG_POWER, (codec->flags & AC97_F_EAPD_INV)? 0x8000 : 0x0000);
647 ac97_reset(codec);
648 ac97_wrcd(codec, AC97_REG_POWER, (codec->flags & AC97_F_EAPD_INV)? 0x8000 : 0x0000);
650 i = ac97_rdcd(codec, AC97_REG_RESET);
651 j = ac97_rdcd(codec, AC97_REG_RESET);
653 * Let see if this codec can return consistent value.
654 * If not, turn on aggressive read workaround
655 * (STAC9704 comes in mind).
657 if (i != j) {
658 codec->flags |= AC97_F_RDCD_BUG;
659 i = ac97_rdcd(codec, AC97_REG_RESET);
661 codec->caps = i & 0x03ff;
662 codec->se = (i & 0x7c00) >> 10;
664 id = (ac97_rdcd(codec, AC97_REG_ID1) << 16) | ac97_rdcd(codec, AC97_REG_ID2);
665 if (id == 0 || id == 0xffffffff) {
666 device_printf(codec->dev, "ac97 codec invalid or not present (id == %x)\n", id);
667 snd_mtxunlock(codec->lock);
668 return ENODEV;
671 codec->id = id;
672 codec->subvendor = (u_int32_t)pci_get_subdevice(codec->dev) << 16;
673 codec->subvendor |= (u_int32_t)pci_get_subvendor(codec->dev) &
674 0x0000ffff;
675 codec->noext = 0;
676 codec_patch = NULL;
678 cname = NULL;
679 model = step = 0;
680 for (i = 0; ac97codecid[i].id; i++) {
681 u_int32_t modelmask = 0xffffffff ^ ac97codecid[i].stepmask;
682 if ((ac97codecid[i].id & modelmask) == (id & modelmask)) {
683 codec->noext = ac97codecid[i].noext;
684 codec_patch = ac97codecid[i].patch;
685 cname = ac97codecid[i].name;
686 model = (id & modelmask) & 0xff;
687 step = (id & ~modelmask) & 0xff;
688 break;
692 vname = NULL;
693 for (i = 0; ac97vendorid[i].id; i++) {
694 if (ac97vendorid[i].id == (id & 0xffffff00)) {
695 vname = ac97vendorid[i].name;
696 break;
700 codec->extcaps = 0;
701 codec->extid = 0;
702 codec->extstat = 0;
703 if (!codec->noext) {
704 i = ac97_rdcd(codec, AC97_REGEXT_ID);
705 if (i != 0xffff) {
706 codec->extcaps = i & 0x3fff;
707 codec->extid = (i & 0xc000) >> 14;
708 codec->extstat = ac97_rdcd(codec, AC97_REGEXT_STAT) & AC97_EXTCAPS;
712 for (i = 0; i < 32; i++) {
713 codec->mix[i] = ac97mixtable_default[i];
715 ac97_fix_auxout(codec);
716 ac97_fix_tone(codec);
717 ac97_fix_volume(codec);
718 if (codec_patch)
719 codec_patch(codec);
721 for (i = 0; i < 32; i++) {
722 k = codec->noext? codec->mix[i].enable : 1;
723 reg = codec->mix[i].reg;
724 if (reg < 0)
725 reg = -reg;
726 if (k && reg) {
727 j = old = ac97_rdcd(codec, reg);
729 * Test for mute bit (except for AC97_MIX_TONE,
730 * where we simply assume it as available).
732 if (codec->mix[i].mute) {
733 ac97_wrcd(codec, reg, j | 0x8000);
734 j = ac97_rdcd(codec, reg);
735 } else
736 j |= 0x8000;
737 if ((j & 0x8000)) {
739 * Test whether the control width should be
740 * 4, 5 or 6 bit. For 5bit register, we should
741 * test it whether it's really 5 or 6bit. Leave
742 * 4bit register alone, because sometimes an
743 * attempt to write past 4th bit may cause
744 * incorrect result especially for AC97_MIX_BEEP
745 * (ac97 2.3).
747 bit = codec->mix[i].bits;
748 if (bit == 5)
749 bit++;
750 j = ((1 << bit) - 1) << codec->mix[i].ofs;
751 ac97_wrcd(codec, reg,
752 j | (codec->mix[i].mute ? 0x8000 : 0));
753 k = ac97_rdcd(codec, reg) & j;
754 k >>= codec->mix[i].ofs;
755 if (reg == AC97_MIX_TONE &&
756 ((k & 0x0001) == 0x0000))
757 k >>= 1;
758 for (j = 0; k >> j; j++)
760 if (j != 0) {
761 #if 0
762 device_printf(codec->dev, "%2d: [ac97_rdcd() = %d] [Testbit = %d] %d -> %d\n",
763 i, k, bit, codec->mix[i].bits, j);
764 #endif
765 codec->mix[i].enable = 1;
766 codec->mix[i].bits = j;
767 } else if (reg == AC97_MIX_BEEP) {
769 * Few codec such as CX20468-21 does
770 * have this control register, although
771 * the only usable part is the mute bit.
773 codec->mix[i].enable = 1;
774 } else
775 codec->mix[i].enable = 0;
776 } else
777 codec->mix[i].enable = 0;
778 ac97_wrcd(codec, reg, old);
780 #if 0
781 kprintf("mixch %d, en=%d, b=%d\n", i, codec->mix[i].enable, codec->mix[i].bits);
782 #endif
785 device_printf(codec->dev, "<%s>\n",
786 ac97_hw_desc(codec->id, vname, cname, desc));
788 if (bootverbose) {
789 if (codec->flags & AC97_F_RDCD_BUG)
790 device_printf(codec->dev, "Buggy AC97 Codec: aggressive ac97_rdcd() workaround enabled\n");
791 device_printf(codec->dev, "Codec features ");
792 for (i = j = 0; i < 10; i++)
793 if (codec->caps & (1 << i))
794 kprintf("%s%s", j++? ", " : "", ac97feature[i]);
795 kprintf("%s%d bit master volume", j++? ", " : "", codec->mix[SOUND_MIXER_VOLUME].bits);
796 kprintf("%s%s\n", j? ", " : "", ac97enhancement[codec->se]);
798 if (codec->extcaps != 0 || codec->extid) {
799 device_printf(codec->dev, "%s codec",
800 codec->extid? "Secondary" : "Primary");
801 if (codec->extcaps)
802 kprintf(" extended features ");
803 for (i = j = 0; i < 14; i++)
804 if (codec->extcaps & (1 << i))
805 kprintf("%s%s", j++? ", " : "", ac97extfeature[i]);
806 kprintf("\n");
810 i = 0;
811 while ((ac97_rdcd(codec, AC97_REG_POWER) & 2) == 0) {
812 if (++i == 100) {
813 device_printf(codec->dev, "ac97 codec reports dac not ready\n");
814 break;
816 DELAY(1000);
818 if (bootverbose)
819 device_printf(codec->dev, "ac97 codec dac ready count: %d\n", i);
820 snd_mtxunlock(codec->lock);
821 return 0;
824 static unsigned
825 ac97_reinitmixer(struct ac97_info *codec)
827 snd_mtxlock(codec->lock);
828 codec->count = AC97_INIT(codec->methods, codec->devinfo);
829 if (codec->count == 0) {
830 device_printf(codec->dev, "ac97 codec init failed\n");
831 snd_mtxunlock(codec->lock);
832 return ENODEV;
835 ac97_wrcd(codec, AC97_REG_POWER, (codec->flags & AC97_F_EAPD_INV)? 0x8000 : 0x0000);
836 ac97_reset(codec);
837 ac97_wrcd(codec, AC97_REG_POWER, (codec->flags & AC97_F_EAPD_INV)? 0x8000 : 0x0000);
839 if (!codec->noext) {
840 ac97_wrcd(codec, AC97_REGEXT_STAT, codec->extstat);
841 if ((ac97_rdcd(codec, AC97_REGEXT_STAT) & AC97_EXTCAPS)
842 != codec->extstat)
843 device_printf(codec->dev, "ac97 codec failed to reset extended mode (%x, got %x)\n",
844 codec->extstat,
845 ac97_rdcd(codec, AC97_REGEXT_STAT) &
846 AC97_EXTCAPS);
849 if ((ac97_rdcd(codec, AC97_REG_POWER) & 2) == 0)
850 device_printf(codec->dev, "ac97 codec reports dac not ready\n");
851 snd_mtxunlock(codec->lock);
852 return 0;
855 struct ac97_info *
856 ac97_create(device_t dev, void *devinfo, kobj_class_t cls)
858 struct ac97_info *codec;
860 codec = (struct ac97_info *)kmalloc(sizeof *codec, M_AC97, M_NOWAIT);
861 if (codec == NULL)
862 return NULL;
864 ksnprintf(codec->name, AC97_NAMELEN, "%s:ac97", device_get_nameunit(dev));
865 codec->lock = snd_mtxcreate(codec->name, "ac97 codec");
866 codec->methods = kobj_create(cls, M_AC97, M_WAITOK);
867 if (codec->methods == NULL) {
868 snd_mtxfree(codec->lock);
869 kfree(codec, M_AC97);
870 return NULL;
873 codec->dev = dev;
874 codec->devinfo = devinfo;
875 codec->flags = 0;
876 return codec;
879 void
880 ac97_destroy(struct ac97_info *codec)
882 if (codec->methods != NULL)
883 kobj_delete(codec->methods, M_AC97);
884 snd_mtxfree(codec->lock);
885 kfree(codec, M_AC97);
888 void
889 ac97_setflags(struct ac97_info *codec, u_int32_t val)
891 codec->flags = val;
894 u_int32_t
895 ac97_getflags(struct ac97_info *codec)
897 return codec->flags;
900 /* -------------------------------------------------------------------- */
902 static int
903 ac97mix_init(struct snd_mixer *m)
905 struct ac97_info *codec = mix_getdevinfo(m);
906 u_int32_t i, mask;
908 if (codec == NULL)
909 return -1;
911 if (ac97_initmixer(codec))
912 return -1;
914 mask = 0;
915 for (i = 0; i < 32; i++)
916 mask |= codec->mix[i].enable? 1 << i : 0;
917 mix_setdevs(m, mask);
919 mask = 0;
920 for (i = 0; i < 32; i++)
921 mask |= codec->mix[i].recidx? 1 << i : 0;
922 mix_setrecdevs(m, mask);
923 return 0;
926 static int
927 ac97mix_uninit(struct snd_mixer *m)
929 struct ac97_info *codec = mix_getdevinfo(m);
931 if (codec == NULL)
932 return -1;
934 if (ac97_uninitmixer(codec))
935 return -1;
937 ac97_destroy(codec);
938 return 0;
941 static int
942 ac97mix_reinit(struct snd_mixer *m)
944 struct ac97_info *codec = mix_getdevinfo(m);
946 if (codec == NULL)
947 return -1;
948 return ac97_reinitmixer(codec);
951 static int
952 ac97mix_set(struct snd_mixer *m, unsigned dev, unsigned left, unsigned right)
954 struct ac97_info *codec = mix_getdevinfo(m);
956 if (codec == NULL)
957 return -1;
958 return ac97_setmixer(codec, dev, left, right);
961 static int
962 ac97mix_setrecsrc(struct snd_mixer *m, u_int32_t src)
964 int i;
965 struct ac97_info *codec = mix_getdevinfo(m);
967 if (codec == NULL)
968 return -1;
969 for (i = 0; i < SOUND_MIXER_NRDEVICES; i++)
970 if ((src & (1 << i)) != 0)
971 break;
972 return (ac97_setrecsrc(codec, i) == 0)? 1 << i : -1;
975 static kobj_method_t ac97mixer_methods[] = {
976 KOBJMETHOD(mixer_init, ac97mix_init),
977 KOBJMETHOD(mixer_uninit, ac97mix_uninit),
978 KOBJMETHOD(mixer_reinit, ac97mix_reinit),
979 KOBJMETHOD(mixer_set, ac97mix_set),
980 KOBJMETHOD(mixer_setrecsrc, ac97mix_setrecsrc),
981 { 0, 0 }
983 MIXER_DECLARE(ac97mixer);
985 /* -------------------------------------------------------------------- */
987 kobj_class_t
988 ac97_getmixerclass(void)
990 return &ac97mixer_class;