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