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
30 #include "mixer_if.h"
31
32 SND_DECLARE_FILE("$FreeBSD: releng/5.0/sys/dev/sound/pcm/ac97.c 107285 2002-11-26 18:16:27Z cg $");
33
34 MALLOC_DEFINE(M_AC97, "ac97", "ac97 codec");
35
36 struct ac97mixtable_entry {
37 int reg:8;
38 unsigned bits:4;
39 unsigned ofs:4;
40 unsigned stereo:1;
41 unsigned mute:1;
42 unsigned recidx:4;
43 unsigned mask:1;
44 unsigned enable:1;
45 };
46
47 #define AC97_NAMELEN 16
48 struct ac97_info {
49 kobj_t methods;
50 device_t dev;
51 void *devinfo;
52 char *id;
53 char rev;
54 unsigned count, caps, se, extcaps, extid, extstat, noext:1;
55 u_int32_t flags;
56 struct ac97mixtable_entry mix[32];
57 char name[AC97_NAMELEN];
58 struct mtx *lock;
59 };
60
61 struct ac97_codecid {
62 u_int32_t id, noext:1;
63 char *name;
64 };
65
66 static const struct ac97mixtable_entry ac97mixtable_default[32] = {
67 [SOUND_MIXER_VOLUME] = { AC97_MIX_MASTER, 5, 0, 1, 1, 6, 0, 1 },
68 [SOUND_MIXER_MONITOR] = { AC97_MIX_AUXOUT, 5, 0, 1, 1, 0, 0, 0 },
69 [SOUND_MIXER_PHONEOUT] = { AC97_MIX_MONO, 5, 0, 0, 1, 7, 0, 0 },
70 [SOUND_MIXER_BASS] = { AC97_MIX_TONE, 4, 8, 0, 0, 0, 1, 0 },
71 [SOUND_MIXER_TREBLE] = { AC97_MIX_TONE, 4, 0, 0, 0, 0, 1, 0 },
72 [SOUND_MIXER_PCM] = { AC97_MIX_PCM, 5, 0, 1, 1, 0, 0, 1 },
73 [SOUND_MIXER_SPEAKER] = { AC97_MIX_BEEP, 4, 1, 0, 1, 0, 0, 0 },
74 [SOUND_MIXER_LINE] = { AC97_MIX_LINE, 5, 0, 1, 1, 5, 0, 1 },
75 [SOUND_MIXER_PHONEIN] = { AC97_MIX_PHONE, 5, 0, 0, 1, 8, 0, 0 },
76 [SOUND_MIXER_MIC] = { AC97_MIX_MIC, 5, 0, 0, 1, 1, 0, 1 },
77 [SOUND_MIXER_CD] = { AC97_MIX_CD, 5, 0, 1, 1, 2, 0, 1 },
78 [SOUND_MIXER_LINE1] = { AC97_MIX_AUX, 5, 0, 1, 1, 4, 0, 0 },
79 [SOUND_MIXER_VIDEO] = { AC97_MIX_VIDEO, 5, 0, 1, 1, 3, 0, 0 },
80 [SOUND_MIXER_RECLEV] = { -AC97_MIX_RGAIN, 4, 0, 1, 1, 0, 0, 1 }
81 };
82
83 static struct ac97_codecid ac97codecid[] = {
84 { 0x41445303, 0, "Analog Devices AD1819" },
85 { 0x41445340, 0, "Analog Devices AD1881" },
86 { 0x41445348, 0, "Analog Devices AD1881A" },
87 { 0x41445360, 0, "Analog Devices AD1885" },
88 { 0x414b4d00, 1, "Asahi Kasei AK4540" },
89 { 0x414b4d01, 1, "Asahi Kasei AK4542" },
90 { 0x414b4d02, 1, "Asahi Kasei AK4543" },
91 { 0x414c4710, 0, "Avance Logic ALC200/200P" },
92 { 0x43525900, 0, "Cirrus Logic CS4297" },
93 { 0x43525903, 0, "Cirrus Logic CS4297" },
94 { 0x43525913, 0, "Cirrus Logic CS4297A" },
95 { 0x43525914, 0, "Cirrus Logic CS4297B" },
96 { 0x43525923, 0, "Cirrus Logic CS4294C" },
97 { 0x4352592b, 0, "Cirrus Logic CS4298C" },
98 { 0x43525931, 0, "Cirrus Logic CS4299A" },
99 { 0x43525933, 0, "Cirrus Logic CS4299C" },
100 { 0x43525934, 0, "Cirrus Logic CS4299D" },
101 { 0x43525941, 0, "Cirrus Logic CS4201A" },
102 { 0x43525951, 0, "Cirrus Logic CS4205A" },
103 { 0x43525961, 0, "Cirrus Logic CS4291A" },
104 { 0x45838308, 0, "ESS Technology ES1921" },
105 { 0x49434511, 0, "ICEnsemble ICE1232" },
106 { 0x4e534331, 0, "National Semiconductor LM4549" },
107 { 0x83847600, 0, "SigmaTel STAC9700/9783/9784" },
108 { 0x83847604, 0, "SigmaTel STAC9701/9703/9704/9705" },
109 { 0x83847605, 0, "SigmaTel STAC9704" },
110 { 0x83847608, 0, "SigmaTel STAC9708/9711" },
111 { 0x83847609, 0, "SigmaTel STAC9721/9723" },
112 { 0x83847644, 0, "SigmaTel STAC9744" },
113 { 0x83847656, 0, "SigmaTel STAC9756/9757" },
114 { 0x53494c22, 0, "Silicon Laboratory Si3036" },
115 { 0x53494c23, 0, "Silicon Laboratory Si3038" },
116 { 0x54524103, 0, "TriTech TR?????" },
117 { 0x54524106, 0, "TriTech TR28026" },
118 { 0x54524108, 0, "TriTech TR28028" },
119 { 0x54524123, 0, "TriTech TR28602" },
120 { 0x574d4c00, 0, "Wolfson WM9701A" },
121 { 0x574d4c03, 0, "Wolfson WM9703/9704" },
122 { 0x574d4c04, 0, "Wolfson WM9704 (quad)" },
123 { 0, 0, NULL }
124 };
125
126 static char *ac97enhancement[] = {
127 "no 3D Stereo Enhancement",
128 "Analog Devices Phat Stereo",
129 "Creative Stereo Enhancement",
130 "National Semi 3D Stereo Enhancement",
131 "Yamaha Ymersion",
132 "BBE 3D Stereo Enhancement",
133 "Crystal Semi 3D Stereo Enhancement",
134 "Qsound QXpander",
135 "Spatializer 3D Stereo Enhancement",
136 "SRS 3D Stereo Enhancement",
137 "Platform Tech 3D Stereo Enhancement",
138 "AKM 3D Audio",
139 "Aureal Stereo Enhancement",
140 "Aztech 3D Enhancement",
141 "Binaura 3D Audio Enhancement",
142 "ESS Technology Stereo Enhancement",
143 "Harman International VMAx",
144 "Nvidea 3D Stereo Enhancement",
145 "Philips Incredible Sound",
146 "Texas Instruments 3D Stereo Enhancement",
147 "VLSI Technology 3D Stereo Enhancement",
148 "TriTech 3D Stereo Enhancement",
149 "Realtek 3D Stereo Enhancement",
150 "Samsung 3D Stereo Enhancement",
151 "Wolfson Microelectronics 3D Enhancement",
152 "Delta Integration 3D Enhancement",
153 "SigmaTel 3D Enhancement",
154 "Reserved 27",
155 "Rockwell 3D Stereo Enhancement",
156 "Reserved 29",
157 "Reserved 30",
158 "Reserved 31"
159 };
160
161 static char *ac97feature[] = {
162 "mic channel",
163 "reserved",
164 "tone",
165 "simulated stereo",
166 "headphone",
167 "bass boost",
168 "18 bit DAC",
169 "20 bit DAC",
170 "18 bit ADC",
171 "20 bit ADC"
172 };
173
174 static char *ac97extfeature[] = {
175 "variable rate PCM",
176 "double rate PCM",
177 "reserved 1",
178 "variable rate mic",
179 "reserved 2",
180 "reserved 3",
181 "center DAC",
182 "surround DAC",
183 "LFE DAC",
184 "AMAP",
185 "reserved 4",
186 "reserved 5",
187 "reserved 6",
188 "reserved 7",
189 };
190
191 static u_int16_t
192 rdcd(struct ac97_info *codec, int reg)
193 {
194 return AC97_READ(codec->methods, codec->devinfo, reg);
195 }
196
197 static void
198 wrcd(struct ac97_info *codec, int reg, u_int16_t val)
199 {
200 AC97_WRITE(codec->methods, codec->devinfo, reg, val);
201 }
202
203 static void
204 ac97_reset(struct ac97_info *codec)
205 {
206 u_int32_t i, ps;
207 wrcd(codec, AC97_REG_RESET, 0);
208 for (i = 0; i < 500; i++) {
209 ps = rdcd(codec, AC97_REG_POWER) & AC97_POWER_STATUS;
210 if (ps == AC97_POWER_STATUS)
211 return;
212 DELAY(1000);
213 }
214 device_printf(codec->dev, "AC97 reset timed out.");
215 }
216
217 int
218 ac97_setrate(struct ac97_info *codec, int which, int rate)
219 {
220 u_int16_t v;
221
222 switch(which) {
223 case AC97_REGEXT_FDACRATE:
224 case AC97_REGEXT_SDACRATE:
225 case AC97_REGEXT_LDACRATE:
226 case AC97_REGEXT_LADCRATE:
227 case AC97_REGEXT_MADCRATE:
228 break;
229
230 default:
231 return -1;
232 }
233
234 snd_mtxlock(codec->lock);
235 if (rate != 0) {
236 v = rate;
237 if (codec->extstat & AC97_EXTCAP_DRA)
238 v >>= 1;
239 wrcd(codec, which, v);
240 }
241 v = rdcd(codec, which);
242 if (codec->extstat & AC97_EXTCAP_DRA)
243 v <<= 1;
244 snd_mtxunlock(codec->lock);
245 return v;
246 }
247
248 int
249 ac97_setextmode(struct ac97_info *codec, u_int16_t mode)
250 {
251 mode &= AC97_EXTCAPS;
252 if ((mode & ~codec->extcaps) != 0) {
253 device_printf(codec->dev, "ac97 invalid mode set 0x%04x\n",
254 mode);
255 return -1;
256 }
257 snd_mtxlock(codec->lock);
258 wrcd(codec, AC97_REGEXT_STAT, mode);
259 codec->extstat = rdcd(codec, AC97_REGEXT_STAT) & AC97_EXTCAPS;
260 snd_mtxunlock(codec->lock);
261 return (mode == codec->extstat)? 0 : -1;
262 }
263
264 u_int16_t
265 ac97_getextmode(struct ac97_info *codec)
266 {
267 return codec->extstat;
268 }
269
270 u_int16_t
271 ac97_getextcaps(struct ac97_info *codec)
272 {
273 return codec->extcaps;
274 }
275
276 u_int16_t
277 ac97_getcaps(struct ac97_info *codec)
278 {
279 return codec->caps;
280 }
281
282 static int
283 ac97_setrecsrc(struct ac97_info *codec, int channel)
284 {
285 struct ac97mixtable_entry *e = &codec->mix[channel];
286
287 if (e->recidx > 0) {
288 int val = e->recidx - 1;
289 val |= val << 8;
290 snd_mtxlock(codec->lock);
291 wrcd(codec, AC97_REG_RECSEL, val);
292 snd_mtxunlock(codec->lock);
293 return 0;
294 } else
295 return -1;
296 }
297
298 static int
299 ac97_setmixer(struct ac97_info *codec, unsigned channel, unsigned left, unsigned right)
300 {
301 struct ac97mixtable_entry *e = &codec->mix[channel];
302
303 if (e->reg && e->enable && e->bits) {
304 int max, val, reg = (e->reg >= 0)? e->reg : -e->reg;
305
306 if (!e->stereo)
307 right = left;
308 if (e->reg > 0) {
309 left = 100 - left;
310 right = 100 - right;
311 }
312
313 max = (1 << e->bits) - 1;
314 left = (left * max) / 100;
315 right = (right * max) / 100;
316
317 val = (left << 8) | right;
318
319 left = (left * 100) / max;
320 right = (right * 100) / max;
321
322 if (e->reg > 0) {
323 left = 100 - left;
324 right = 100 - right;
325 }
326
327 if (!e->stereo) {
328 val &= max;
329 val <<= e->ofs;
330 if (e->mask) {
331 int cur = rdcd(codec, e->reg);
332 val |= cur & ~(max << e->ofs);
333 }
334 }
335 if (left == 0 && right == 0 && e->mute == 1)
336 val = AC97_MUTE;
337 snd_mtxlock(codec->lock);
338 wrcd(codec, reg, val);
339 snd_mtxunlock(codec->lock);
340 return left | (right << 8);
341 } else {
342 /* printf("ac97_setmixer: reg=%d, bits=%d, enable=%d\n", e->reg, e->bits, e->enable); */
343 return -1;
344 }
345 }
346
347 #if 0
348 static int
349 ac97_getmixer(struct ac97_info *codec, int channel)
350 {
351 struct ac97mixtable_entry *e = &codec->mix[channel];
352 if (channel < SOUND_MIXER_NRDEVICES && e->reg != 0) {
353 int max, val, volume;
354
355 max = (1 << e->bits) - 1;
356 val = rdcd(code, e->reg);
357 if (val == AC97_MUTE && e->mute == 1)
358 volume = 0;
359 else {
360 if (e->stereo == 0) val >>= e->ofs;
361 val &= max;
362 volume = (val * 100) / max;
363 if (e->reg > 0) volume = 100 - volume;
364 }
365 return volume;
366 } else
367 return -1;
368 }
369 #endif
370
371 static void
372 ac97_fix_auxout(struct ac97_info *codec)
373 {
374 /* Determine what AUXOUT really means, it can be:
375 *
376 * 1. Headphone out.
377 * 2. 4-Channel Out
378 * 3. True line level out (effectively master volume).
379 *
380 * See Sections 5.2.1 and 5.27 for AUX_OUT Options in AC97r2.{2,3}.
381 */
382 if (codec->caps & AC97_CAP_HEADPHONE) {
383 /* XXX We should probably check the AUX_OUT initial value.
384 * Leave AC97_MIX_AUXOUT - SOUND_MIXER_MONITOR relationship */
385 return;
386 } else if (codec->extcaps & AC97_EXTCAP_SDAC &&
387 rdcd(codec, AC97_MIXEXT_SURROUND) == 0x8080) {
388 /* 4-Channel Out, add an additional gain setting. */
389 codec->mix[SOUND_MIXER_OGAIN] = codec->mix[SOUND_MIXER_MONITOR];
390 } else {
391 /* Master volume is/maybe fixed in h/w, not sufficiently
392 * clear in spec to blat SOUND_MIXER_MASTER. */
393 codec->mix[SOUND_MIXER_OGAIN] = codec->mix[SOUND_MIXER_MONITOR];
394 }
395 /* Blat monitor, inappropriate label if we get here */
396 bzero(&codec->mix[SOUND_MIXER_MONITOR],
397 sizeof(codec->mix[SOUND_MIXER_MONITOR]));
398 }
399
400 static unsigned
401 ac97_initmixer(struct ac97_info *codec)
402 {
403 unsigned i, j, k, old;
404 u_int32_t id;
405
406 snd_mtxlock(codec->lock);
407 codec->count = AC97_INIT(codec->methods, codec->devinfo);
408 if (codec->count == 0) {
409 device_printf(codec->dev, "ac97 codec init failed\n");
410 snd_mtxunlock(codec->lock);
411 return ENODEV;
412 }
413
414 wrcd(codec, AC97_REG_POWER, (codec->flags & AC97_F_EAPD_INV)? 0x8000 : 0x0000);
415 ac97_reset(codec);
416 wrcd(codec, AC97_REG_POWER, (codec->flags & AC97_F_EAPD_INV)? 0x8000 : 0x0000);
417
418 i = rdcd(codec, AC97_REG_RESET);
419 codec->caps = i & 0x03ff;
420 codec->se = (i & 0x7c00) >> 10;
421
422 id = (rdcd(codec, AC97_REG_ID1) << 16) | rdcd(codec, AC97_REG_ID2);
423 codec->rev = id & 0x000000ff;
424 if (id == 0 || id == 0xffffffff) {
425 device_printf(codec->dev, "ac97 codec invalid or not present (id == %x)\n", id);
426 snd_mtxunlock(codec->lock);
427 return ENODEV;
428 }
429
430 codec->noext = 0;
431 codec->id = NULL;
432 for (i = 0; ac97codecid[i].id; i++) {
433 if (ac97codecid[i].id == id) {
434 codec->id = ac97codecid[i].name;
435 codec->noext = ac97codecid[i].noext;
436 }
437 }
438
439 codec->extcaps = 0;
440 codec->extid = 0;
441 codec->extstat = 0;
442 if (!codec->noext) {
443 i = rdcd(codec, AC97_REGEXT_ID);
444 if (i != 0xffff) {
445 codec->extcaps = i & 0x3fff;
446 codec->extid = (i & 0xc000) >> 14;
447 codec->extstat = rdcd(codec, AC97_REGEXT_STAT) & AC97_EXTCAPS;
448 }
449 }
450
451 for (i = 0; i < 32; i++) {
452 codec->mix[i] = ac97mixtable_default[i];
453 }
454 ac97_fix_auxout(codec);
455
456 for (i = 0; i < 32; i++) {
457 k = codec->noext? codec->mix[i].enable : 1;
458 if (k && (codec->mix[i].reg > 0)) {
459 old = rdcd(codec, codec->mix[i].reg);
460 wrcd(codec, codec->mix[i].reg, 0x3f);
461 j = rdcd(codec, codec->mix[i].reg);
462 wrcd(codec, codec->mix[i].reg, old);
463 codec->mix[i].enable = (j != 0 && j != old)? 1 : 0;
464 for (k = 1; j & (1 << k); k++);
465 codec->mix[i].bits = j? k - codec->mix[i].ofs : 0;
466 }
467 /* printf("mixch %d, en=%d, b=%d\n", i, codec->mix[i].enable, codec->mix[i].bits); */
468 }
469
470 if (bootverbose) {
471 device_printf(codec->dev, "ac97 codec id 0x%08x", id);
472 if (codec->id)
473 printf(" (%s)", codec->id);
474 printf("\n");
475 device_printf(codec->dev, "ac97 codec features ");
476 for (i = j = 0; i < 10; i++)
477 if (codec->caps & (1 << i))
478 printf("%s%s", j++? ", " : "", ac97feature[i]);
479 printf("%s%d bit master volume", j++? ", " : "", codec->mix[SOUND_MIXER_VOLUME].bits);
480 printf("%s%s\n", j? ", " : "", ac97enhancement[codec->se]);
481
482 if (codec->extcaps != 0 || codec->extid) {
483 device_printf(codec->dev, "ac97 %s codec",
484 codec->extid? "secondary" : "primary");
485 if (codec->extcaps)
486 printf(" extended features ");
487 for (i = j = 0; i < 14; i++)
488 if (codec->extcaps & (1 << i))
489 printf("%s%s", j++? ", " : "", ac97extfeature[i]);
490 printf("\n");
491 }
492 }
493
494 if ((rdcd(codec, AC97_REG_POWER) & 2) == 0)
495 device_printf(codec->dev, "ac97 codec reports dac not ready\n");
496 snd_mtxunlock(codec->lock);
497 return 0;
498 }
499
500 static unsigned
501 ac97_reinitmixer(struct ac97_info *codec)
502 {
503 snd_mtxlock(codec->lock);
504 codec->count = AC97_INIT(codec->methods, codec->devinfo);
505 if (codec->count == 0) {
506 device_printf(codec->dev, "ac97 codec init failed\n");
507 snd_mtxunlock(codec->lock);
508 return ENODEV;
509 }
510
511 wrcd(codec, AC97_REG_POWER, (codec->flags & AC97_F_EAPD_INV)? 0x8000 : 0x0000);
512 ac97_reset(codec);
513 wrcd(codec, AC97_REG_POWER, (codec->flags & AC97_F_EAPD_INV)? 0x8000 : 0x0000);
514
515 if (!codec->noext) {
516 wrcd(codec, AC97_REGEXT_STAT, codec->extstat);
517 if ((rdcd(codec, AC97_REGEXT_STAT) & AC97_EXTCAPS)
518 != codec->extstat)
519 device_printf(codec->dev, "ac97 codec failed to reset extended mode (%x, got %x)\n",
520 codec->extstat,
521 rdcd(codec, AC97_REGEXT_STAT) &
522 AC97_EXTCAPS);
523 }
524
525 if ((rdcd(codec, AC97_REG_POWER) & 2) == 0)
526 device_printf(codec->dev, "ac97 codec reports dac not ready\n");
527 snd_mtxunlock(codec->lock);
528 return 0;
529 }
530
531 struct ac97_info *
532 ac97_create(device_t dev, void *devinfo, kobj_class_t cls)
533 {
534 struct ac97_info *codec;
535
536 codec = (struct ac97_info *)malloc(sizeof *codec, M_AC97, M_NOWAIT);
537 if (codec == NULL)
538 return NULL;
539
540 snprintf(codec->name, AC97_NAMELEN, "%s:ac97", device_get_nameunit(dev));
541 codec->lock = snd_mtxcreate(codec->name, "ac97 codec");
542 codec->methods = kobj_create(cls, M_AC97, M_WAITOK);
543 if (codec->methods == NULL) {
544 snd_mtxlock(codec->lock);
545 snd_mtxfree(codec->lock);
546 free(codec, M_AC97);
547 return NULL;
548 }
549
550 codec->dev = dev;
551 codec->devinfo = devinfo;
552 codec->flags = 0;
553 return codec;
554 }
555
556 void
557 ac97_destroy(struct ac97_info *codec)
558 {
559 snd_mtxlock(codec->lock);
560 if (codec->methods != NULL)
561 kobj_delete(codec->methods, M_AC97);
562 snd_mtxfree(codec->lock);
563 free(codec, M_AC97);
564 }
565
566 void
567 ac97_setflags(struct ac97_info *codec, u_int32_t val)
568 {
569 codec->flags = val;
570 }
571
572 u_int32_t
573 ac97_getflags(struct ac97_info *codec)
574 {
575 return codec->flags;
576 }
577
578 /* -------------------------------------------------------------------- */
579
580 static int
581 ac97mix_init(struct snd_mixer *m)
582 {
583 struct ac97_info *codec = mix_getdevinfo(m);
584 u_int32_t i, mask;
585
586 if (codec == NULL)
587 return -1;
588
589 if (ac97_initmixer(codec))
590 return -1;
591
592 mask = 0;
593 for (i = 0; i < 32; i++)
594 mask |= codec->mix[i].enable? 1 << i : 0;
595 mix_setdevs(m, mask);
596
597 mask = 0;
598 for (i = 0; i < 32; i++)
599 mask |= codec->mix[i].recidx? 1 << i : 0;
600 mix_setrecdevs(m, mask);
601 return 0;
602 }
603
604 static int
605 ac97mix_uninit(struct snd_mixer *m)
606 {
607 struct ac97_info *codec = mix_getdevinfo(m);
608
609 if (codec == NULL)
610 return -1;
611 /*
612 if (ac97_uninitmixer(codec))
613 return -1;
614 */
615 ac97_destroy(codec);
616 return 0;
617 }
618
619 static int
620 ac97mix_reinit(struct snd_mixer *m)
621 {
622 struct ac97_info *codec = mix_getdevinfo(m);
623
624 if (codec == NULL)
625 return -1;
626 return ac97_reinitmixer(codec);
627 }
628
629 static int
630 ac97mix_set(struct snd_mixer *m, unsigned dev, unsigned left, unsigned right)
631 {
632 struct ac97_info *codec = mix_getdevinfo(m);
633
634 if (codec == NULL)
635 return -1;
636 return ac97_setmixer(codec, dev, left, right);
637 }
638
639 static int
640 ac97mix_setrecsrc(struct snd_mixer *m, u_int32_t src)
641 {
642 int i;
643 struct ac97_info *codec = mix_getdevinfo(m);
644
645 if (codec == NULL)
646 return -1;
647 for (i = 0; i < SOUND_MIXER_NRDEVICES; i++)
648 if ((src & (1 << i)) != 0)
649 break;
650 return (ac97_setrecsrc(codec, i) == 0)? 1 << i : -1;
651 }
652
653 static kobj_method_t ac97mixer_methods[] = {
654 KOBJMETHOD(mixer_init, ac97mix_init),
655 KOBJMETHOD(mixer_uninit, ac97mix_uninit),
656 KOBJMETHOD(mixer_reinit, ac97mix_reinit),
657 KOBJMETHOD(mixer_set, ac97mix_set),
658 KOBJMETHOD(mixer_setrecsrc, ac97mix_setrecsrc),
659 { 0, 0 }
660 };
661 MIXER_DECLARE(ac97mixer);
662
663 /* -------------------------------------------------------------------- */
664
665 kobj_class_t
666 ac97_getmixerclass(void)
667 {
668 return &ac97mixer_class;
669 }
670
671
Cache object: 67c73497fc2712258332a05939f27923
|