ac97.c revision 1.5 1 /* $NetBSD: ac97.c,v 1.5 1999/11/24 23:21:01 augustss Exp $ */
2 /* $OpenBSD: ac97.c,v 1.2 1999/09/21 16:06:27 csapuntz Exp $ */
3
4 /*
5 * Copyright (c) 1999 Constantine Sapuntzakis
6 *
7 * Author: Constantine Sapuntzakis <csapuntz (at) stanford.edu>
8 *
9 * Redistribution and use in source and binary forms, with or without
10 * modification, are permitted provided that the following conditions
11 * are met:
12 * 1. Redistributions of source code must retain the above copyright
13 * notice, this list of conditions and the following disclaimer.
14 * 2. Redistributions in binary form must reproduce the above copyright
15 * notice, this list of conditions and the following disclaimer in the
16 * documentation and/or other materials provided with the distribution.
17 *
18 * THIS SOFTWARE IS PROVIDED BY CONSTANTINE SAPUNTZAKIS AND CONTRIBUTORS
19 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
20 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
21 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS
22 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
23 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
24 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
25 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
26 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
27 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
28 * POSSIBILITY OF SUCH DAMAGE.
29 */
30
31 /* Partially inspired by FreeBSD's sys/dev/pcm/ac97.c. It came with
32 the following copyright */
33
34 /*
35 * Copyright (c) 1999 Cameron Grant <gandalf (at) vilnya.demon.co.uk>
36 * All rights reserved.
37 *
38 * Redistribution and use in source and binary forms, with or without
39 * modification, are permitted provided that the following conditions
40 * are met:
41 * 1. Redistributions of source code must retain the above copyright
42 * notice, this list of conditions and the following disclaimer.
43 * 2. Redistributions in binary form must reproduce the above copyright
44 * notice, this list of conditions and the following disclaimer in the
45 * documentation and/or other materials provided with the distribution.
46 *
47 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
48 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
49 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
50 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
51 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
52 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
53 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
54 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
55 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
56 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
57 * SUCH DAMAGE.
58 *
59 * $FreeBSD$
60 */
61
62 #include <sys/param.h>
63 #include <sys/systm.h>
64 #include <sys/kernel.h>
65 #include <sys/malloc.h>
66 #include <sys/device.h>
67
68 #include <sys/audioio.h>
69 #include <dev/audio_if.h>
70 #include <dev/ic/ac97.h>
71
72 #define AC97_REG_RESET 0x00
73 #define AC97_SOUND_ENHANCEMENT(reg) (((reg) >> 10) & 0x1f)
74 #define AC97_REG_MASTER_VOLUME 0x02
75 #define AC97_REG_HEADPHONE_VOLUME 0x04
76 #define AC97_REG_MASTER_VOLUME_MONO 0x06
77 #define AC97_REG_MASTER_TONE 0x08
78 #define AC97_REG_PCBEEP_VOLUME 0x0a
79 #define AC97_REG_PHONE_VOLUME 0x0c
80 #define AC97_REG_MIC_VOLUME 0x0e
81 #define AC97_REG_LINEIN_VOLUME 0x10
82 #define AC97_REG_CD_VOLUME 0x12
83 #define AC97_REG_VIDEO_VOLUME 0x14
84 #define AC97_REG_AUX_VOLUME 0x16
85 #define AC97_REG_PCMOUT_VOLUME 0x18
86 #define AC97_REG_RECORD_SELECT 0x1a
87 #define AC97_REG_RECORD_GAIN 0x1c
88 #define AC97_REG_RECORD_GAIN_MIC 0x1e
89 #define AC97_REG_GP 0x20
90 #define AC97_REG_3D_CONTROL 0x22
91 #define AC97_REG_POWER 0x26
92 #define AC97_REG_VENDOR_ID1 0x7c
93 #define AC97_REG_VENDOR_ID2 0x7e
94
95 static struct audio_mixer_enum ac97_on_off = { 2,
96 { { { AudioNoff } , 0 },
97 { { AudioNon } , 1 } }};
98
99
100 static struct audio_mixer_enum ac97_mic_select = { 2,
101 { { { AudioNmicrophone "0" },
102 0 },
103 { { AudioNmicrophone "1" },
104 1 } }};
105
106 static struct audio_mixer_enum ac97_mono_select = { 2,
107 { { { AudioNmixerout },
108 0 },
109 { { AudioNmicrophone },
110 1 } }};
111
112 static struct audio_mixer_enum ac97_source = { 8,
113 { { { AudioNmicrophone } , 0 },
114 { { AudioNcd }, 1 },
115 { { "video" }, 2 },
116 { { AudioNaux }, 3 },
117 { { AudioNline }, 4 },
118 { { AudioNmixerout }, 5 },
119 { { AudioNmixerout AudioNmono }, 6 },
120 { { "phone" }, 7 }}};
121
122 static struct audio_mixer_value ac97_volume_stereo = { { AudioNvolume },
123 2 };
124
125
126 static struct audio_mixer_value ac97_volume_mono = { { AudioNvolume },
127 1 };
128
129 #define WRAP(a) &a, sizeof(a)
130
131 struct ac97_source_info {
132 char *class;
133 char *device;
134 char *qualifier;
135 int type;
136
137 void *info;
138 int info_size;
139
140 u_int8_t reg;
141 u_int8_t bits:3;
142 u_int8_t ofs:4;
143 u_int8_t mute:1;
144 u_int8_t polarity:1; /* Does 0 == MAX or MIN */
145
146 int prev;
147 int next;
148 int mixer_class;
149 } source_info[] = {
150 { AudioCinputs , NULL, NULL, AUDIO_MIXER_CLASS,
151 },
152 { AudioCoutputs, NULL, NULL, AUDIO_MIXER_CLASS,
153 },
154 { AudioCrecord , NULL, NULL, AUDIO_MIXER_CLASS,
155 },
156 /* Stereo master volume*/
157 { AudioCoutputs, AudioNmaster, NULL, AUDIO_MIXER_VALUE,
158 WRAP(ac97_volume_stereo),
159 AC97_REG_MASTER_VOLUME, 5, 0, 1,
160 },
161 /* Mono volume */
162 { AudioCoutputs, AudioNmono, NULL, AUDIO_MIXER_VALUE,
163 WRAP(ac97_volume_mono),
164 AC97_REG_MASTER_VOLUME_MONO, 6, 0, 1,
165 },
166 { AudioCoutputs, AudioNmono,AudioNsource, AUDIO_MIXER_ENUM,
167 WRAP(ac97_mono_select),
168 AC97_REG_GP, 1, 9, 0,
169 },
170 /* Headphone volume */
171 { AudioCoutputs, AudioNheadphone, NULL, AUDIO_MIXER_VALUE,
172 WRAP(ac97_volume_stereo),
173 AC97_REG_HEADPHONE_VOLUME, 6, 0, 1,
174 },
175 /* Tone */
176 { AudioCoutputs, "tone", NULL, AUDIO_MIXER_VALUE,
177 WRAP(ac97_volume_stereo),
178 AC97_REG_MASTER_TONE, 4, 0, 0,
179 },
180 /* PC Beep Volume */
181 { AudioCinputs, AudioNspeaker, NULL, AUDIO_MIXER_VALUE,
182 WRAP(ac97_volume_mono),
183 AC97_REG_PCBEEP_VOLUME, 4, 1, 1,
184 },
185 /* Phone */
186 { AudioCinputs, "phone", NULL, AUDIO_MIXER_VALUE,
187 WRAP(ac97_volume_mono),
188 AC97_REG_PHONE_VOLUME, 5, 0, 1,
189 },
190 /* Mic Volume */
191 { AudioCinputs, AudioNmicrophone, NULL, AUDIO_MIXER_VALUE,
192 WRAP(ac97_volume_mono),
193 AC97_REG_MIC_VOLUME, 5, 0, 1,
194 },
195 { AudioCinputs, AudioNmicrophone, AudioNpreamp, AUDIO_MIXER_ENUM,
196 WRAP(ac97_on_off),
197 AC97_REG_MIC_VOLUME, 1, 6, 0,
198 },
199 { AudioCinputs, AudioNmicrophone, AudioNsource, AUDIO_MIXER_ENUM,
200 WRAP(ac97_mic_select),
201 AC97_REG_GP, 1, 8, 0,
202 },
203 /* Line in Volume */
204 { AudioCinputs, AudioNline, NULL, AUDIO_MIXER_VALUE,
205 WRAP(ac97_volume_stereo),
206 AC97_REG_LINEIN_VOLUME, 5, 0, 1,
207 },
208 /* CD Volume */
209 { AudioCinputs, AudioNcd, NULL, AUDIO_MIXER_VALUE,
210 WRAP(ac97_volume_stereo),
211 AC97_REG_CD_VOLUME, 5, 0, 1,
212 },
213 /* Video Volume */
214 { AudioCinputs, "video", NULL, AUDIO_MIXER_VALUE,
215 WRAP(ac97_volume_stereo),
216 AC97_REG_VIDEO_VOLUME, 5, 0, 1,
217 },
218 /* AUX volume */
219 { AudioCinputs, AudioNaux, NULL, AUDIO_MIXER_VALUE,
220 WRAP(ac97_volume_stereo),
221 AC97_REG_AUX_VOLUME, 5, 0, 1,
222 },
223 /* PCM out volume */
224 { AudioCinputs, AudioNdac, NULL, AUDIO_MIXER_VALUE,
225 WRAP(ac97_volume_stereo),
226 AC97_REG_PCMOUT_VOLUME, 5, 0, 1,
227 },
228 /* Record Source - some logic for this is hard coded - see below */
229 { AudioCrecord, AudioNsource, NULL, AUDIO_MIXER_ENUM,
230 WRAP(ac97_source),
231 AC97_REG_RECORD_SELECT, 3, 0, 0,
232 },
233 /* Record Gain */
234 { AudioCrecord, AudioNvolume, NULL, AUDIO_MIXER_VALUE,
235 WRAP(ac97_volume_stereo),
236 AC97_REG_RECORD_GAIN, 4, 0, 1,
237 },
238 /* Record Gain mic */
239 { AudioCrecord, AudioNmicrophone, NULL, AUDIO_MIXER_VALUE,
240 WRAP(ac97_volume_mono),
241 AC97_REG_RECORD_GAIN_MIC, 4, 0, 1, 1,
242 },
243 /* */
244 { AudioCoutputs, AudioNloudness, NULL, AUDIO_MIXER_ENUM,
245 WRAP(ac97_on_off),
246 AC97_REG_GP, 1, 12, 0,
247 },
248 { AudioCoutputs, AudioNspatial, NULL, AUDIO_MIXER_ENUM,
249 WRAP(ac97_on_off),
250 AC97_REG_GP, 1, 13, 0,
251 },
252 { AudioCoutputs, AudioNspatial, "center", AUDIO_MIXER_VALUE,
253 WRAP(ac97_volume_mono),
254 AC97_REG_3D_CONTROL, 4, 8, 0, 1,
255 },
256 { AudioCoutputs, AudioNspatial, "depth", AUDIO_MIXER_VALUE,
257 WRAP(ac97_volume_mono),
258 AC97_REG_3D_CONTROL, 4, 0, 0, 1,
259 },
260
261 /* Missing features: Simulated Stereo, POP, Loopback mode */
262 } ;
263
264 #define SOURCE_INFO_SIZE (sizeof(source_info)/sizeof(source_info[0]))
265
266 /*
267 * Check out http://developer.intel.com/pc-supp/platform/ac97/ for
268 * information on AC-97
269 */
270
271 struct ac97_softc {
272 struct ac97_codec_if codecIf;
273
274 struct ac97_host_if *hostIf;
275
276 struct ac97_source_info source_info[2 * SOURCE_INFO_SIZE];
277 int num_source_info;
278 };
279
280 int ac97_mixer_get_port __P((struct ac97_codec_if *self, mixer_ctrl_t *cp));
281 int ac97_mixer_set_port __P((struct ac97_codec_if *self, mixer_ctrl_t *));
282 int ac97_query_devinfo __P((struct ac97_codec_if *self, mixer_devinfo_t *));
283 int ac97_get_portnum_by_name __P((struct ac97_codec_if *, char *, char *,
284 char *));
285
286 struct ac97_codec_if_vtbl ac97civ = {
287 ac97_mixer_get_port,
288 ac97_mixer_set_port,
289 ac97_query_devinfo,
290 ac97_get_portnum_by_name
291 };
292
293 static struct ac97_codecid {
294 u_int32_t id;
295 char *name;
296 } ac97codecid[] = {
297 { 0x414B4D00, "Asahi Kasei AK4540" },
298 /*0x43525900, "Cirrus Logic CS4297" },*/
299 { 0x43525903, "Cirrus Logic CS4297" },
300 { 0x83847600, "SigmaTel STAC????" },
301 { 0x83847604, "SigmaTel STAC9701/3/4/5" },
302 { 0x83847605, "SigmaTel STAC9704" },
303 { 0x83847608, "SigmaTel STAC9708" },
304 { 0x83847609, "SigmaTel STAC9721" },
305 { 0, NULL }
306 };
307
308 static char *ac97enhancement[] = {
309 "no 3D stereo",
310 "Analog Devices Phat Stereo",
311 "Creative"
312 "National Semi 3D",
313 "Yamaha Ymersion",
314 "BBE 3D",
315 "Crystal Semi 3D"
316 "Qsound QXpander",
317 "Spatializer 3D",
318 "SRS 3D",
319 "Platform Tech 3D",
320 "AKM 3D",
321 "Aureal",
322 "AZTECH 3D",
323 "Binaura 3D",
324 "ESS Technology",
325 "Harman International VMAx",
326 "Nvidea 3D",
327 "Philips Incredible Sound",
328 "Texas Instruments' 3D",
329 "VLSI Technology 3D",
330 "TriTech 3D",
331 "Realtek 3D",
332 "Samsung 3D",
333 "Wolfson Microelectronics 3D",
334 "Delta Integration 3D",
335 "SigmaTel 3D",
336 "Unknown 3D",
337 "Rockwell 3D",
338 "Unknown 3D",
339 "Unknown 3D",
340 "Unknown 3D",
341 };
342
343 static char *ac97feature[] = {
344 "mic channel",
345 "reserved",
346 "tone",
347 "simulated stereo",
348 "headphone",
349 "bass boost",
350 "18 bit DAC",
351 "20 bit DAC",
352 "18 bit ADC",
353 "20 bit ADC"
354 };
355
356
357 int ac97_str_equal __P((char *, char *));
358 void ac97_setup_source_info __P((struct ac97_softc *));
359
360 /* #define AC97_DEBUG 10 */
361
362 #ifdef AUDIO_DEBUG
363 #define DPRINTF(x) if (ac97debug) printf x
364 #define DPRINTFN(n,x) if (ac97debug>(n)) printf x
365 #ifdef AC97_DEBUG
366 int ac97debug = AC97_DEBUG;
367 #else
368 int ac97debug = 0;
369 #endif
370 #else
371 #define DPRINTF(x)
372 #define DPRINTFN(n,x)
373 #endif
374
375
376 int
377 ac97_str_equal(a, b)
378 char *a, *b;
379 {
380 return ((a == b) || (a && b && (!strcmp(a, b))));
381 }
382
383 void
384 ac97_setup_source_info(as)
385 struct ac97_softc *as;
386 {
387 int idx, ouridx;
388 struct ac97_source_info *si, *si2;
389
390 for (idx = 0, ouridx = 0; idx < SOURCE_INFO_SIZE; idx++) {
391 si = &as->source_info[ouridx];
392
393 bcopy(&source_info[idx], si, sizeof(*si));
394
395 switch (si->type) {
396 case AUDIO_MIXER_CLASS:
397 si->mixer_class = ouridx;
398 ouridx++;
399 break;
400 case AUDIO_MIXER_VALUE:
401 /* Todo - Test to see if it works */
402 ouridx++;
403
404 /* Add an entry for mute, if necessary */
405 if (si->mute) {
406 si = &as->source_info[ouridx];
407 bcopy(&source_info[idx], si, sizeof(*si));
408 si->qualifier = AudioNmute;
409 si->type = AUDIO_MIXER_ENUM;
410 si->info = &ac97_on_off;
411 si->info_size = sizeof(ac97_on_off);
412 si->bits = 1;
413 si->ofs = 15;
414 si->mute = 0;
415 si->polarity = 0;
416 ouridx++;
417 }
418 break;
419 case AUDIO_MIXER_ENUM:
420 /* Todo - Test to see if it works */
421 ouridx++;
422 break;
423 default:
424 printf ("ac97: shouldn't get here\n");
425 break;
426 }
427 }
428
429 as->num_source_info = ouridx;
430
431 for (idx = 0; idx < as->num_source_info; idx++) {
432 int idx2, previdx;
433
434 si = &as->source_info[idx];
435
436 /* Find mixer class */
437 for (idx2 = 0; idx2 < as->num_source_info; idx2++) {
438 si2 = &as->source_info[idx2];
439
440 if (si2->type == AUDIO_MIXER_CLASS &&
441 ac97_str_equal(si->class,
442 si2->class)) {
443 si->mixer_class = idx2;
444 }
445 }
446
447
448 /* Setup prev and next pointers */
449 if (si->prev != 0)
450 continue;
451
452 if (si->qualifier)
453 continue;
454
455 si->prev = AUDIO_MIXER_LAST;
456 previdx = idx;
457
458 for (idx2 = 0; idx2 < as->num_source_info; idx2++) {
459 if (idx2 == idx)
460 continue;
461
462 si2 = &as->source_info[idx2];
463
464 if (!si2->prev &&
465 ac97_str_equal(si->class, si2->class) &&
466 ac97_str_equal(si->device, si2->device)) {
467 as->source_info[previdx].next = idx2;
468 as->source_info[idx2].prev = previdx;
469
470 previdx = idx2;
471 }
472 }
473
474 as->source_info[previdx].next = AUDIO_MIXER_LAST;
475 }
476 }
477
478 int
479 ac97_attach(hostIf)
480 struct ac97_host_if *hostIf;
481 {
482 struct ac97_softc *as;
483 struct device *sc_dev = (struct device *)hostIf->arg;
484 int error, i, j;
485 u_int16_t id1, id2, caps;
486 u_int32_t id;
487
488 as = malloc(sizeof(struct ac97_softc), M_DEVBUF, M_WAITOK);
489
490 if (as == NULL)
491 return (ENOMEM);
492
493 as->codecIf.vtbl = &ac97civ;
494 as->hostIf = hostIf;
495
496 if ((error = hostIf->attach(hostIf->arg, &as->codecIf))) {
497 free (as, M_DEVBUF);
498 return (error);
499 }
500
501 hostIf->reset(hostIf->arg);
502
503 hostIf->write(hostIf->arg, AC97_REG_POWER, 0);
504 hostIf->write(hostIf->arg, AC97_REG_RESET, 0);
505
506 if ((error = hostIf->read(hostIf->arg, AC97_REG_VENDOR_ID1, &id1)))
507 return (error);
508
509 if ((error = hostIf->read(hostIf->arg, AC97_REG_VENDOR_ID2, &id2)))
510 return (error);
511
512 if ((error = hostIf->read(hostIf->arg, AC97_REG_RESET, &caps)))
513 return (error);
514
515 id = (id1 << 16) | id2;
516
517 printf("%s: ", sc_dev->dv_xname);
518
519 for (i = 0; ; i++) {
520 if (ac97codecid[i].id == id) {
521 printf("%s", ac97codecid[i].name);
522 break;
523 }
524 if (ac97codecid[i].id == 0) {
525 char pnp[4];
526 pnp[0] = id >> 24;
527 pnp[1] = id >> 16;
528 pnp[2] = id >> 8;
529 pnp[3] = '\0';
530 #define ISASCII(c) ((c) >= ' ' && (c) < 0x7f)
531 if (ISASCII(pnp[0]) && ISASCII(pnp[1]) &&
532 ISASCII(pnp[2]))
533 printf("%s%d", pnp, id & 0xff);
534 else
535 printf("unknown (0x%8x)", id);
536 break;
537 }
538 }
539 printf(" codec; ");
540 for (i = j = 0; i < 10; i++) {
541 if (caps & (1 << i)) {
542 printf("%s%s", j? ", " : "", ac97feature[i]);
543 j++;
544 }
545 }
546
547 printf("%s%s\n", j? ", " : "", ac97enhancement[(caps >> 10) & 0x1f]);
548
549 ac97_setup_source_info(as);
550
551 return (0);
552 }
553
554
555 int
556 ac97_query_devinfo(codec_if, dip)
557 struct ac97_codec_if *codec_if;
558 mixer_devinfo_t *dip;
559 {
560 struct ac97_softc *as = (struct ac97_softc *)codec_if;
561
562 if (dip->index < as->num_source_info) {
563 struct ac97_source_info *si = &as->source_info[dip->index];
564 char *name;
565
566 dip->type = si->type;
567 dip->mixer_class = si->mixer_class;
568 dip->prev = si->prev;
569 dip->next = si->next;
570
571 if (si->qualifier)
572 name = si->qualifier;
573 else if (si->device)
574 name = si->device;
575 else if (si->class)
576 name = si->class;
577
578 if (name)
579 strcpy(dip->label.name, name);
580
581 bcopy(si->info, &dip->un, si->info_size);
582 return (0);
583 }
584
585 return (ENXIO);
586 }
587
588
589
590 int
591 ac97_mixer_set_port(codec_if, cp)
592 struct ac97_codec_if *codec_if;
593 mixer_ctrl_t *cp;
594 {
595 struct ac97_softc *as = (struct ac97_softc *)codec_if;
596 struct ac97_source_info *si = &as->source_info[cp->dev];
597 u_int16_t mask;
598 u_int16_t val, newval;
599 int error;
600
601 if (cp->dev < 0 || cp->dev >= as->num_source_info)
602 return (EINVAL);
603
604 if (cp->type != si->type)
605 return (EINVAL);
606
607 error = as->hostIf->read(as->hostIf->arg, si->reg, &val);
608 if (error)
609 return (error);
610
611 DPRINTFN(5, ("read(%x) = %x\n", si->reg, val));
612
613 mask = (1 << si->bits) - 1;
614
615 switch (cp->type) {
616 case AUDIO_MIXER_ENUM:
617 if (cp->un.ord > mask || cp->un.ord < 0)
618 return (EINVAL);
619
620 newval = (cp->un.ord << si->ofs);
621 if (si->reg == AC97_REG_RECORD_SELECT) {
622 newval |= (newval << (8 + si->ofs));
623 mask |= (mask << 8);
624 }
625 break;
626 case AUDIO_MIXER_VALUE:
627 {
628 struct audio_mixer_value *value = si->info;
629 u_int16_t l, r;
630
631 if ((cp->un.value.num_channels <= 0) ||
632 (cp->un.value.num_channels > value->num_channels))
633 return (EINVAL);
634
635 if (cp->un.value.num_channels == 1) {
636 l = r = cp->un.value.level[AUDIO_MIXER_LEVEL_MONO];
637 } else {
638 l = cp->un.value.level[AUDIO_MIXER_LEVEL_LEFT];
639 r = cp->un.value.level[AUDIO_MIXER_LEVEL_RIGHT];
640 }
641
642 if (!si->polarity) {
643 l = 255 - l;
644 r = 255 - r;
645 }
646
647 l = l >> (8 - si->bits);
648 r = r >> (8 - si->bits);
649
650 newval = ((l & mask) << si->ofs);
651 if (value->num_channels == 2) {
652 newval |= ((r & mask) << (si->ofs + 8));
653 mask |= (mask << 8);
654 }
655
656 break;
657 }
658 default:
659 return (EINVAL);
660 }
661
662 mask = mask << si->ofs;
663 error = as->hostIf->write(as->hostIf->arg, si->reg, (val & ~mask) | newval);
664 if (error)
665 return (error);
666
667 return (0);
668 }
669
670 int
671 ac97_get_portnum_by_name(codec_if, class, device, qualifier)
672 struct ac97_codec_if *codec_if;
673 char *class, *device, *qualifier;
674 {
675 struct ac97_softc *as = (struct ac97_softc *)codec_if;
676 int idx;
677
678 for (idx = 0; idx < as->num_source_info; idx++) {
679 struct ac97_source_info *si = &as->source_info[idx];
680 if (ac97_str_equal(class, si->class) &&
681 ac97_str_equal(device, si->device) &&
682 ac97_str_equal(qualifier, si->qualifier))
683 return (idx);
684 }
685
686 return (-1);
687 }
688
689 int
690 ac97_mixer_get_port(codec_if, cp)
691 struct ac97_codec_if *codec_if;
692 mixer_ctrl_t *cp;
693 {
694 struct ac97_softc *as = (struct ac97_softc *)codec_if;
695 struct ac97_source_info *si = &as->source_info[cp->dev];
696 u_int16_t mask;
697 u_int16_t val;
698 int error;
699
700 if (cp->dev < 0 || cp->dev >= as->num_source_info)
701 return (EINVAL);
702
703 if (cp->type != si->type)
704 return (EINVAL);
705
706 error = as->hostIf->read(as->hostIf->arg, si->reg, &val);
707 if (error)
708 return (error);
709
710 DPRINTFN(5, ("read(%x) = %x\n", si->reg, val));
711
712 mask = (1 << si->bits) - 1;
713
714 switch (cp->type) {
715 case AUDIO_MIXER_ENUM:
716 cp->un.ord = (val >> si->ofs) & mask;
717 DPRINTFN(4, ("AUDIO_MIXER_ENUM: %x %d %x %d\n", val, si->ofs, mask, cp->un.ord));
718 break;
719 case AUDIO_MIXER_VALUE:
720 {
721 struct audio_mixer_value *value = si->info;
722 u_int16_t l, r;
723
724 if ((cp->un.value.num_channels <= 0) ||
725 (cp->un.value.num_channels > value->num_channels))
726 return (EINVAL);
727
728 if (value->num_channels == 1) {
729 l = r = (val >> si->ofs) & mask;
730 } else {
731 l = (val >> si->ofs) & mask;
732 r = (val >> (si->ofs + 8)) & mask;
733 }
734
735 l = (l << (8 - si->bits));
736 r = (r << (8 - si->bits));
737 if (!si->polarity) {
738 l = 255 - l;
739 r = 255 - r;
740 }
741
742 /* The EAP driver averages l and r for stereo
743 channels that are requested in MONO mode. Does this
744 make sense? */
745 if (cp->un.value.num_channels == 1) {
746 cp->un.value.level[AUDIO_MIXER_LEVEL_MONO] = l;
747 } else if (cp->un.value.num_channels == 2) {
748 cp->un.value.level[AUDIO_MIXER_LEVEL_LEFT] = l;
749 cp->un.value.level[AUDIO_MIXER_LEVEL_RIGHT] = r;
750 }
751
752 break;
753 }
754 default:
755 return (EINVAL);
756 }
757
758 return (0);
759 }
760
761