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