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