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