FreeBSD/Linux Kernel Cross Reference
sys/dev/sound/pcm/ac97.c
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 "mixer_if.h"
32
33 SND_DECLARE_FILE("$FreeBSD: releng/6.0/sys/dev/sound/pcm/ac97.c 144865 2005-04-10 14:45:27Z scottl $");
34
35 MALLOC_DEFINE(M_AC97, "ac97", "ac97 codec");
36
37 struct ac97mixtable_entry {
38 int reg:8; /* register index */
39 /* reg < 0 if inverted polarity */
40 unsigned bits:4; /* width of control field */
41 unsigned ofs:4; /* offset (only if stereo=0) */
42 unsigned stereo:1; /* set for stereo controls */
43 unsigned mute:1; /* bit15 is MUTE */
44 unsigned recidx:4; /* index in rec mux */
45 unsigned mask:1; /* use only masked bits */
46 unsigned enable:1; /* entry is enabled */
47 };
48
49 #define AC97_NAMELEN 16
50 struct ac97_info {
51 kobj_t methods;
52 device_t dev;
53 void *devinfo;
54 u_int32_t id;
55 unsigned count, caps, se, extcaps, extid, extstat, noext:1;
56 u_int32_t flags;
57 struct ac97mixtable_entry mix[32];
58 char name[AC97_NAMELEN];
59 struct mtx *lock;
60 };
61
62 struct ac97_vendorid {
63 u_int32_t id;
64 const char *name;
65 };
66
67 struct ac97_codecid {
68 u_int32_t id;
69 u_int8_t stepmask;
70 u_int8_t noext:1;
71 char *name;
72 ac97_patch patch;
73 };
74
75 static const struct ac97mixtable_entry ac97mixtable_default[32] = {
76 /* [offset] reg bits of st mu re mk en */
77 [SOUND_MIXER_VOLUME] = { AC97_MIX_MASTER, 5, 0, 1, 1, 6, 0, 1 },
78 [SOUND_MIXER_OGAIN] = { AC97_MIX_AUXOUT, 5, 0, 1, 1, 0, 0, 0 },
79 [SOUND_MIXER_PHONEOUT] = { AC97_MIX_MONO, 5, 0, 0, 1, 7, 0, 0 },
80 [SOUND_MIXER_BASS] = { AC97_MIX_TONE, 4, 8, 0, 0, 0, 1, 0 },
81 [SOUND_MIXER_TREBLE] = { AC97_MIX_TONE, 4, 0, 0, 0, 0, 1, 0 },
82 [SOUND_MIXER_PCM] = { AC97_MIX_PCM, 5, 0, 1, 1, 0, 0, 1 },
83 [SOUND_MIXER_SPEAKER] = { AC97_MIX_BEEP, 4, 1, 0, 1, 0, 0, 0 },
84 [SOUND_MIXER_LINE] = { AC97_MIX_LINE, 5, 0, 1, 1, 5, 0, 1 },
85 [SOUND_MIXER_PHONEIN] = { AC97_MIX_PHONE, 5, 0, 0, 1, 8, 0, 0 },
86 [SOUND_MIXER_MIC] = { AC97_MIX_MIC, 5, 0, 0, 1, 1, 1, 1 },
87 #if 0
88 /* use igain for the mic 20dB boost */
89 [SOUND_MIXER_IGAIN] = { -AC97_MIX_MIC, 1, 6, 0, 0, 0, 1, 1 },
90 #endif
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
97 static 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 { 0x01408300, "Creative" },
122 { 0x00000000, NULL }
123 };
124
125 static struct ac97_codecid ac97codecid[] = {
126 { 0x41445303, 0x00, 0, "AD1819", 0 },
127 { 0x41445340, 0x00, 0, "AD1881", 0 },
128 { 0x41445348, 0x00, 0, "AD1881A", 0 },
129 { 0x41445360, 0x00, 0, "AD1885", 0 },
130 { 0x41445361, 0x00, 0, "AD1886", ad1886_patch },
131 { 0x41445362, 0x00, 0, "AD1887", 0 },
132 { 0x41445363, 0x00, 0, "AD1886A", 0 },
133 { 0x41445368, 0x00, 0, "AD1888", ad198x_patch },
134 { 0x41445370, 0x00, 0, "AD1980", ad198x_patch },
135 { 0x41445372, 0x00, 0, "AD1981A", 0 },
136 { 0x41445374, 0x00, 0, "AD1981B", 0 },
137 { 0x41445375, 0x00, 0, "AD1985", ad198x_patch },
138 { 0x414b4d00, 0x00, 1, "AK4540", 0 },
139 { 0x414b4d01, 0x00, 1, "AK4542", 0 },
140 { 0x414b4d02, 0x00, 1, "AK4543", 0 },
141 { 0x414b4d06, 0x00, 0, "AK4544A", 0 },
142 { 0x454b4d07, 0x00, 0, "AK4545", 0 },
143 { 0x414c4320, 0x0f, 0, "ALC100", 0 },
144 { 0x414c4730, 0x0f, 0, "ALC101", 0 },
145 { 0x414c4710, 0x0f, 0, "ALC200", 0 },
146 { 0x414c4740, 0x0f, 0, "ALC202", 0 },
147 { 0x414c4720, 0x0f, 0, "ALC650", 0 },
148 { 0x414c4760, 0x0f, 0, "ALC655", 0 },
149 { 0x414c4780, 0x0f, 0, "ALC658", 0 },
150 { 0x414c4790, 0x0f, 0, "ALC850", 0 },
151 { 0x43525900, 0x07, 0, "CS4297", 0 },
152 { 0x43525910, 0x07, 0, "CS4297A", 0 },
153 { 0x43525920, 0x07, 0, "CS4294/98", 0 },
154 { 0x4352592d, 0x07, 0, "CS4294", 0 },
155 { 0x43525930, 0x07, 0, "CS4299", 0 },
156 { 0x43525940, 0x07, 0, "CS4201", 0 },
157 { 0x43525958, 0x07, 0, "CS4205", 0 },
158 { 0x43525960, 0x07, 0, "CS4291A", 0 },
159 { 0x434d4961, 0x00, 0, "CMI9739", 0 },
160 { 0x434d4941, 0x00, 0, "CMI9738", 0 },
161 { 0x43585421, 0x00, 0, "HSD11246", 0 },
162 { 0x43585428, 0x07, 0, "CX20468", 0 },
163 { 0x44543000, 0x00, 0, "DT0398", 0 },
164 { 0x454d4323, 0x00, 0, "EM28023", 0 },
165 { 0x454d4328, 0x00, 0, "EM28028", 0 },
166 { 0x45838308, 0x00, 0, "ES1988", 0 }, /* Formerly ES1921(?) */
167 { 0x48525300, 0x00, 0, "HMP9701", 0 },
168 { 0x49434501, 0x00, 0, "ICE1230", 0 },
169 { 0x49434511, 0x00, 0, "ICE1232", 0 },
170 { 0x49434514, 0x00, 0, "ICE1232A", 0 },
171 { 0x49434551, 0x03, 0, "VT1616", 0 }, /* Via badged ICE */
172 { 0x49544520, 0x00, 0, "ITE2226E", 0 },
173 { 0x49544560, 0x07, 0, "ITE2646E", 0 }, /* XXX: patch needed */
174 { 0x4e534340, 0x00, 0, "LM4540", 0 }, /* Spec blank on revid */
175 { 0x4e534343, 0x00, 0, "LM4543", 0 }, /* Ditto */
176 { 0x4e534346, 0x00, 0, "LM4546A", 0 },
177 { 0x4e534348, 0x00, 0, "LM4548A", 0 },
178 { 0x4e534331, 0x00, 0, "LM4549", 0 },
179 { 0x4e534349, 0x00, 0, "LM4549A", 0 },
180 { 0x4e534350, 0x00, 0, "LM4550", 0 },
181 { 0x50534301, 0x00, 0, "UCB1510", 0 },
182 { 0x50534304, 0x00, 0, "UCB1400", 0 },
183 { 0x83847600, 0x00, 0, "STAC9700/83/84", 0 },
184 { 0x83847604, 0x00, 0, "STAC9701/03/04/05", 0 },
185 { 0x83847605, 0x00, 0, "STAC9704", 0 },
186 { 0x83847608, 0x00, 0, "STAC9708/11", 0 },
187 { 0x83847609, 0x00, 0, "STAC9721/23", 0 },
188 { 0x83847644, 0x00, 0, "STAC9744/45", 0 },
189 { 0x83847650, 0x00, 0, "STAC9750/51", 0 },
190 { 0x83847652, 0x00, 0, "STAC9752/53", 0 },
191 { 0x83847656, 0x00, 0, "STAC9756/57", 0 },
192 { 0x83847658, 0x00, 0, "STAC9758/59", 0 },
193 { 0x83847660, 0x00, 0, "STAC9760/61", 0 }, /* Extrapolated */
194 { 0x83847662, 0x00, 0, "STAC9762/63", 0 }, /* Extrapolated */
195 { 0x53494c22, 0x00, 0, "Si3036", 0 },
196 { 0x53494c23, 0x00, 0, "Si3038", 0 },
197 { 0x54524103, 0x00, 0, "TR28023", 0 }, /* Extrapolated */
198 { 0x54524106, 0x00, 0, "TR28026", 0 },
199 { 0x54524108, 0x00, 0, "TR28028", 0 },
200 { 0x54524123, 0x00, 0, "TR28602", 0 },
201 { 0x54524e03, 0x07, 0, "TLV320AIC27", 0 },
202 { 0x54584e20, 0x00, 0, "TLC320AD90", 0 },
203 { 0x56494161, 0x00, 0, "VIA1612A", 0 },
204 { 0x574d4c00, 0x00, 0, "WM9701A", 0 },
205 { 0x574d4c03, 0x00, 0, "WM9703/4/7/8", 0 },
206 { 0x574d4c04, 0x00, 0, "WM9704Q", 0 },
207 { 0x574d4c05, 0x00, 0, "WM9705/10", 0 },
208 { 0x574d4d09, 0x00, 0, "WM9709", 0 },
209 { 0x574d4c12, 0x00, 0, "WM9711/12", 0 }, /* XXX: patch needed */
210 { 0x57454301, 0x00, 0, "W83971D", 0 },
211 { 0x594d4800, 0x00, 0, "YMF743", 0 },
212 { 0x594d4802, 0x00, 0, "YMF752", 0 },
213 { 0x594d4803, 0x00, 0, "YMF753", 0 },
214 { 0x01408384, 0x00, 0, "EV1938", 0 },
215 { 0, 0, 0, NULL, 0 }
216 };
217
218 static char *ac97enhancement[] = {
219 "no 3D Stereo Enhancement",
220 "Analog Devices Phat Stereo",
221 "Creative Stereo Enhancement",
222 "National Semi 3D Stereo Enhancement",
223 "Yamaha Ymersion",
224 "BBE 3D Stereo Enhancement",
225 "Crystal Semi 3D Stereo Enhancement",
226 "Qsound QXpander",
227 "Spatializer 3D Stereo Enhancement",
228 "SRS 3D Stereo Enhancement",
229 "Platform Tech 3D Stereo Enhancement",
230 "AKM 3D Audio",
231 "Aureal Stereo Enhancement",
232 "Aztech 3D Enhancement",
233 "Binaura 3D Audio Enhancement",
234 "ESS Technology Stereo Enhancement",
235 "Harman International VMAx",
236 "Nvidea 3D Stereo Enhancement",
237 "Philips Incredible Sound",
238 "Texas Instruments 3D Stereo Enhancement",
239 "VLSI Technology 3D Stereo Enhancement",
240 "TriTech 3D Stereo Enhancement",
241 "Realtek 3D Stereo Enhancement",
242 "Samsung 3D Stereo Enhancement",
243 "Wolfson Microelectronics 3D Enhancement",
244 "Delta Integration 3D Enhancement",
245 "SigmaTel 3D Enhancement",
246 "Reserved 27",
247 "Rockwell 3D Stereo Enhancement",
248 "Reserved 29",
249 "Reserved 30",
250 "Reserved 31"
251 };
252
253 static char *ac97feature[] = {
254 "mic channel",
255 "reserved",
256 "tone",
257 "simulated stereo",
258 "headphone",
259 "bass boost",
260 "18 bit DAC",
261 "20 bit DAC",
262 "18 bit ADC",
263 "20 bit ADC"
264 };
265
266 static char *ac97extfeature[] = {
267 "variable rate PCM",
268 "double rate PCM",
269 "reserved 1",
270 "variable rate mic",
271 "reserved 2",
272 "reserved 3",
273 "center DAC",
274 "surround DAC",
275 "LFE DAC",
276 "AMAP",
277 "reserved 4",
278 "reserved 5",
279 "reserved 6",
280 "reserved 7",
281 };
282
283 u_int16_t
284 ac97_rdcd(struct ac97_info *codec, int reg)
285 {
286 return AC97_READ(codec->methods, codec->devinfo, reg);
287 }
288
289 void
290 ac97_wrcd(struct ac97_info *codec, int reg, u_int16_t val)
291 {
292 AC97_WRITE(codec->methods, codec->devinfo, reg, val);
293 }
294
295 static void
296 ac97_reset(struct ac97_info *codec)
297 {
298 u_int32_t i, ps;
299 ac97_wrcd(codec, AC97_REG_RESET, 0);
300 for (i = 0; i < 500; i++) {
301 ps = ac97_rdcd(codec, AC97_REG_POWER) & AC97_POWER_STATUS;
302 if (ps == AC97_POWER_STATUS)
303 return;
304 DELAY(1000);
305 }
306 device_printf(codec->dev, "AC97 reset timed out.\n");
307 }
308
309 int
310 ac97_setrate(struct ac97_info *codec, int which, int rate)
311 {
312 u_int16_t v;
313
314 switch(which) {
315 case AC97_REGEXT_FDACRATE:
316 case AC97_REGEXT_SDACRATE:
317 case AC97_REGEXT_LDACRATE:
318 case AC97_REGEXT_LADCRATE:
319 case AC97_REGEXT_MADCRATE:
320 break;
321
322 default:
323 return -1;
324 }
325
326 snd_mtxlock(codec->lock);
327 if (rate != 0) {
328 v = rate;
329 if (codec->extstat & AC97_EXTCAP_DRA)
330 v >>= 1;
331 ac97_wrcd(codec, which, v);
332 }
333 v = ac97_rdcd(codec, which);
334 if (codec->extstat & AC97_EXTCAP_DRA)
335 v <<= 1;
336 snd_mtxunlock(codec->lock);
337 return v;
338 }
339
340 int
341 ac97_setextmode(struct ac97_info *codec, u_int16_t mode)
342 {
343 mode &= AC97_EXTCAPS;
344 if ((mode & ~codec->extcaps) != 0) {
345 device_printf(codec->dev, "ac97 invalid mode set 0x%04x\n",
346 mode);
347 return -1;
348 }
349 snd_mtxlock(codec->lock);
350 ac97_wrcd(codec, AC97_REGEXT_STAT, mode);
351 codec->extstat = ac97_rdcd(codec, AC97_REGEXT_STAT) & AC97_EXTCAPS;
352 snd_mtxunlock(codec->lock);
353 return (mode == codec->extstat)? 0 : -1;
354 }
355
356 u_int16_t
357 ac97_getextmode(struct ac97_info *codec)
358 {
359 return codec->extstat;
360 }
361
362 u_int16_t
363 ac97_getextcaps(struct ac97_info *codec)
364 {
365 return codec->extcaps;
366 }
367
368 u_int16_t
369 ac97_getcaps(struct ac97_info *codec)
370 {
371 return codec->caps;
372 }
373
374 static int
375 ac97_setrecsrc(struct ac97_info *codec, int channel)
376 {
377 struct ac97mixtable_entry *e = &codec->mix[channel];
378
379 if (e->recidx > 0) {
380 int val = e->recidx - 1;
381 val |= val << 8;
382 snd_mtxlock(codec->lock);
383 ac97_wrcd(codec, AC97_REG_RECSEL, val);
384 snd_mtxunlock(codec->lock);
385 return 0;
386 } else
387 return -1;
388 }
389
390 static int
391 ac97_setmixer(struct ac97_info *codec, unsigned channel, unsigned left, unsigned right)
392 {
393 struct ac97mixtable_entry *e = &codec->mix[channel];
394
395 if (e->reg && e->enable && e->bits) {
396 int mask, max, val, reg;
397
398 reg = (e->reg >= 0) ? e->reg : -e->reg; /* AC97 register */
399 max = (1 << e->bits) - 1; /* actual range */
400 mask = (max << 8) | max; /* bits of interest */
401
402 if (!e->stereo)
403 right = left;
404
405 /*
406 * Invert the range if the polarity requires so,
407 * then scale to 0..max-1 to compute the value to
408 * write into the codec, and scale back to 0..100
409 * for the return value.
410 */
411 if (e->reg > 0) {
412 left = 100 - left;
413 right = 100 - right;
414 }
415
416 left = (left * max) / 100;
417 right = (right * max) / 100;
418
419 val = (left << 8) | right;
420
421 left = (left * 100) / max;
422 right = (right * 100) / max;
423
424 if (e->reg > 0) {
425 left = 100 - left;
426 right = 100 - right;
427 }
428
429 /*
430 * For mono controls, trim val and mask, also taking
431 * care of e->ofs (offset of control field).
432 */
433 if (e->ofs) {
434 val &= max;
435 val <<= e->ofs;
436 mask = (max << e->ofs);
437 }
438
439 /*
440 * If we have a mute bit, add it to the mask and
441 * update val and set mute if both channels require a
442 * zero volume.
443 */
444 if (e->mute == 1) {
445 mask |= AC97_MUTE;
446 if (left == 0 && right == 0)
447 val = AC97_MUTE;
448 }
449
450 /*
451 * If the mask bit is set, do not alter the other bits.
452 */
453 snd_mtxlock(codec->lock);
454 if (e->mask) {
455 int cur = ac97_rdcd(codec, e->reg);
456 val |= cur & ~(mask);
457 }
458 ac97_wrcd(codec, reg, val);
459 snd_mtxunlock(codec->lock);
460 return left | (right << 8);
461 } else {
462 /* printf("ac97_setmixer: reg=%d, bits=%d, enable=%d\n", e->reg, e->bits, e->enable); */
463 return -1;
464 }
465 }
466
467 static void
468 ac97_fix_auxout(struct ac97_info *codec)
469 {
470 int keep_ogain;
471
472 /*
473 * By default, The ac97 aux_out register (0x04) corresponds to OSS's
474 * OGAIN setting.
475 *
476 * We first check whether aux_out is a valid register. If not
477 * we may not want to keep ogain.
478 */
479 keep_ogain = ac97_rdcd(codec, AC97_MIX_AUXOUT) & 0x8000;
480
481 /*
482 * Determine what AUX_OUT really means, it can be:
483 *
484 * 1. Headphone out.
485 * 2. 4-Channel Out
486 * 3. True line level out (effectively master volume).
487 *
488 * See Sections 5.2.1 and 5.27 for AUX_OUT Options in AC97r2.{2,3}.
489 */
490 if (codec->extcaps & AC97_EXTCAP_SDAC &&
491 ac97_rdcd(codec, AC97_MIXEXT_SURROUND) == 0x8080) {
492 codec->mix[SOUND_MIXER_OGAIN].reg = AC97_MIXEXT_SURROUND;
493 keep_ogain = 1;
494 }
495
496 if (keep_ogain == 0) {
497 bzero(&codec->mix[SOUND_MIXER_OGAIN],
498 sizeof(codec->mix[SOUND_MIXER_OGAIN]));
499 }
500 }
501
502 static void
503 ac97_fix_tone(struct ac97_info *codec)
504 {
505 /* Hide treble and bass if they don't exist */
506 if ((codec->caps & AC97_CAP_TONE) == 0) {
507 bzero(&codec->mix[SOUND_MIXER_BASS],
508 sizeof(codec->mix[SOUND_MIXER_BASS]));
509 bzero(&codec->mix[SOUND_MIXER_TREBLE],
510 sizeof(codec->mix[SOUND_MIXER_TREBLE]));
511 }
512 }
513
514 static const char*
515 ac97_hw_desc(u_int32_t id, const char* vname, const char* cname, char* buf)
516 {
517 if (cname == NULL) {
518 sprintf(buf, "Unknown AC97 Codec (id = 0x%08x)", id);
519 return buf;
520 }
521
522 if (vname == NULL) vname = "Unknown";
523
524 if (bootverbose) {
525 sprintf(buf, "%s %s AC97 Codec (id = 0x%08x)", vname, cname, id);
526 } else {
527 sprintf(buf, "%s %s AC97 Codec", vname, cname);
528 }
529 return buf;
530 }
531
532 static unsigned
533 ac97_initmixer(struct ac97_info *codec)
534 {
535 ac97_patch codec_patch;
536 const char *cname, *vname;
537 char desc[80];
538 u_int8_t model, step;
539 unsigned i, j, k, old;
540 u_int32_t id;
541
542 snd_mtxlock(codec->lock);
543 codec->count = AC97_INIT(codec->methods, codec->devinfo);
544 if (codec->count == 0) {
545 device_printf(codec->dev, "ac97 codec init failed\n");
546 snd_mtxunlock(codec->lock);
547 return ENODEV;
548 }
549
550 ac97_wrcd(codec, AC97_REG_POWER, (codec->flags & AC97_F_EAPD_INV)? 0x8000 : 0x0000);
551 ac97_reset(codec);
552 ac97_wrcd(codec, AC97_REG_POWER, (codec->flags & AC97_F_EAPD_INV)? 0x8000 : 0x0000);
553
554 i = ac97_rdcd(codec, AC97_REG_RESET);
555 codec->caps = i & 0x03ff;
556 codec->se = (i & 0x7c00) >> 10;
557
558 id = (ac97_rdcd(codec, AC97_REG_ID1) << 16) | ac97_rdcd(codec, AC97_REG_ID2);
559 if (id == 0 || id == 0xffffffff) {
560 device_printf(codec->dev, "ac97 codec invalid or not present (id == %x)\n", id);
561 snd_mtxunlock(codec->lock);
562 return ENODEV;
563 }
564
565 codec->id = id;
566 codec->noext = 0;
567 codec_patch = NULL;
568
569 cname = NULL;
570 model = step = 0;
571 for (i = 0; ac97codecid[i].id; i++) {
572 u_int32_t modelmask = 0xffffffff ^ ac97codecid[i].stepmask;
573 if ((ac97codecid[i].id & modelmask) == (id & modelmask)) {
574 codec->noext = ac97codecid[i].noext;
575 codec_patch = ac97codecid[i].patch;
576 cname = ac97codecid[i].name;
577 model = (id & modelmask) & 0xff;
578 step = (id & ~modelmask) & 0xff;
579 break;
580 }
581 }
582
583 vname = NULL;
584 for (i = 0; ac97vendorid[i].id; i++) {
585 if (ac97vendorid[i].id == (id & 0xffffff00)) {
586 vname = ac97vendorid[i].name;
587 break;
588 }
589 }
590
591 codec->extcaps = 0;
592 codec->extid = 0;
593 codec->extstat = 0;
594 if (!codec->noext) {
595 i = ac97_rdcd(codec, AC97_REGEXT_ID);
596 if (i != 0xffff) {
597 codec->extcaps = i & 0x3fff;
598 codec->extid = (i & 0xc000) >> 14;
599 codec->extstat = ac97_rdcd(codec, AC97_REGEXT_STAT) & AC97_EXTCAPS;
600 }
601 }
602
603 for (i = 0; i < 32; i++) {
604 codec->mix[i] = ac97mixtable_default[i];
605 }
606 ac97_fix_auxout(codec);
607 ac97_fix_tone(codec);
608 if (codec_patch)
609 codec_patch(codec);
610
611 for (i = 0; i < 32; i++) {
612 k = codec->noext? codec->mix[i].enable : 1;
613 if (k && (codec->mix[i].reg > 0)) {
614 old = ac97_rdcd(codec, codec->mix[i].reg);
615 ac97_wrcd(codec, codec->mix[i].reg, 0x3f);
616 j = ac97_rdcd(codec, codec->mix[i].reg);
617 ac97_wrcd(codec, codec->mix[i].reg, old);
618 codec->mix[i].enable = (j != 0 && j != old)? 1 : 0;
619 for (k = 1; j & (1 << k); k++);
620 codec->mix[i].bits = j? k - codec->mix[i].ofs : 0;
621 }
622 /* printf("mixch %d, en=%d, b=%d\n", i, codec->mix[i].enable, codec->mix[i].bits); */
623 }
624
625 device_printf(codec->dev, "<%s>\n",
626 ac97_hw_desc(codec->id, vname, cname, desc));
627
628 if (bootverbose) {
629 device_printf(codec->dev, "Codec features ");
630 for (i = j = 0; i < 10; i++)
631 if (codec->caps & (1 << i))
632 printf("%s%s", j++? ", " : "", ac97feature[i]);
633 printf("%s%d bit master volume", j++? ", " : "", codec->mix[SOUND_MIXER_VOLUME].bits);
634 printf("%s%s\n", j? ", " : "", ac97enhancement[codec->se]);
635
636 if (codec->extcaps != 0 || codec->extid) {
637 device_printf(codec->dev, "%s codec",
638 codec->extid? "Secondary" : "Primary");
639 if (codec->extcaps)
640 printf(" extended features ");
641 for (i = j = 0; i < 14; i++)
642 if (codec->extcaps & (1 << i))
643 printf("%s%s", j++? ", " : "", ac97extfeature[i]);
644 printf("\n");
645 }
646 }
647
648 if ((ac97_rdcd(codec, AC97_REG_POWER) & 2) == 0)
649 device_printf(codec->dev, "ac97 codec reports dac not ready\n");
650 snd_mtxunlock(codec->lock);
651 return 0;
652 }
653
654 static unsigned
655 ac97_reinitmixer(struct ac97_info *codec)
656 {
657 snd_mtxlock(codec->lock);
658 codec->count = AC97_INIT(codec->methods, codec->devinfo);
659 if (codec->count == 0) {
660 device_printf(codec->dev, "ac97 codec init failed\n");
661 snd_mtxunlock(codec->lock);
662 return ENODEV;
663 }
664
665 ac97_wrcd(codec, AC97_REG_POWER, (codec->flags & AC97_F_EAPD_INV)? 0x8000 : 0x0000);
666 ac97_reset(codec);
667 ac97_wrcd(codec, AC97_REG_POWER, (codec->flags & AC97_F_EAPD_INV)? 0x8000 : 0x0000);
668
669 if (!codec->noext) {
670 ac97_wrcd(codec, AC97_REGEXT_STAT, codec->extstat);
671 if ((ac97_rdcd(codec, AC97_REGEXT_STAT) & AC97_EXTCAPS)
672 != codec->extstat)
673 device_printf(codec->dev, "ac97 codec failed to reset extended mode (%x, got %x)\n",
674 codec->extstat,
675 ac97_rdcd(codec, AC97_REGEXT_STAT) &
676 AC97_EXTCAPS);
677 }
678
679 if ((ac97_rdcd(codec, AC97_REG_POWER) & 2) == 0)
680 device_printf(codec->dev, "ac97 codec reports dac not ready\n");
681 snd_mtxunlock(codec->lock);
682 return 0;
683 }
684
685 struct ac97_info *
686 ac97_create(device_t dev, void *devinfo, kobj_class_t cls)
687 {
688 struct ac97_info *codec;
689
690 codec = (struct ac97_info *)malloc(sizeof *codec, M_AC97, M_NOWAIT);
691 if (codec == NULL)
692 return NULL;
693
694 snprintf(codec->name, AC97_NAMELEN, "%s:ac97", device_get_nameunit(dev));
695 codec->lock = snd_mtxcreate(codec->name, "ac97 codec");
696 codec->methods = kobj_create(cls, M_AC97, M_WAITOK);
697 if (codec->methods == NULL) {
698 snd_mtxlock(codec->lock);
699 snd_mtxfree(codec->lock);
700 free(codec, M_AC97);
701 return NULL;
702 }
703
704 codec->dev = dev;
705 codec->devinfo = devinfo;
706 codec->flags = 0;
707 return codec;
708 }
709
710 void
711 ac97_destroy(struct ac97_info *codec)
712 {
713 snd_mtxlock(codec->lock);
714 if (codec->methods != NULL)
715 kobj_delete(codec->methods, M_AC97);
716 snd_mtxfree(codec->lock);
717 free(codec, M_AC97);
718 }
719
720 void
721 ac97_setflags(struct ac97_info *codec, u_int32_t val)
722 {
723 codec->flags = val;
724 }
725
726 u_int32_t
727 ac97_getflags(struct ac97_info *codec)
728 {
729 return codec->flags;
730 }
731
732 /* -------------------------------------------------------------------- */
733
734 static int
735 ac97mix_init(struct snd_mixer *m)
736 {
737 struct ac97_info *codec = mix_getdevinfo(m);
738 u_int32_t i, mask;
739
740 if (codec == NULL)
741 return -1;
742
743 if (ac97_initmixer(codec))
744 return -1;
745
746 mask = 0;
747 for (i = 0; i < 32; i++)
748 mask |= codec->mix[i].enable? 1 << i : 0;
749 mix_setdevs(m, mask);
750
751 mask = 0;
752 for (i = 0; i < 32; i++)
753 mask |= codec->mix[i].recidx? 1 << i : 0;
754 mix_setrecdevs(m, mask);
755 return 0;
756 }
757
758 static int
759 ac97mix_uninit(struct snd_mixer *m)
760 {
761 struct ac97_info *codec = mix_getdevinfo(m);
762
763 if (codec == NULL)
764 return -1;
765 /*
766 if (ac97_uninitmixer(codec))
767 return -1;
768 */
769 ac97_destroy(codec);
770 return 0;
771 }
772
773 static int
774 ac97mix_reinit(struct snd_mixer *m)
775 {
776 struct ac97_info *codec = mix_getdevinfo(m);
777
778 if (codec == NULL)
779 return -1;
780 return ac97_reinitmixer(codec);
781 }
782
783 static int
784 ac97mix_set(struct snd_mixer *m, unsigned dev, unsigned left, unsigned right)
785 {
786 struct ac97_info *codec = mix_getdevinfo(m);
787
788 if (codec == NULL)
789 return -1;
790 return ac97_setmixer(codec, dev, left, right);
791 }
792
793 static int
794 ac97mix_setrecsrc(struct snd_mixer *m, u_int32_t src)
795 {
796 int i;
797 struct ac97_info *codec = mix_getdevinfo(m);
798
799 if (codec == NULL)
800 return -1;
801 for (i = 0; i < SOUND_MIXER_NRDEVICES; i++)
802 if ((src & (1 << i)) != 0)
803 break;
804 return (ac97_setrecsrc(codec, i) == 0)? 1 << i : -1;
805 }
806
807 static kobj_method_t ac97mixer_methods[] = {
808 KOBJMETHOD(mixer_init, ac97mix_init),
809 KOBJMETHOD(mixer_uninit, ac97mix_uninit),
810 KOBJMETHOD(mixer_reinit, ac97mix_reinit),
811 KOBJMETHOD(mixer_set, ac97mix_set),
812 KOBJMETHOD(mixer_setrecsrc, ac97mix_setrecsrc),
813 { 0, 0 }
814 };
815 MIXER_DECLARE(ac97mixer);
816
817 /* -------------------------------------------------------------------- */
818
819 kobj_class_t
820 ac97_getmixerclass(void)
821 {
822 return &ac97mixer_class;
823 }
824
825
Cache object: a0ad660ad02e320911b4a28339efe6d6
|