ac97.c revision 1.8 1 /* $NetBSD: ac97.c,v 1.8 2000/04/28 12:39:59 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 #define AC97_CODEC_ID(a0, a1, a2, x) \
294 (((a0) << 24) | ((a1) << 16) | ((a2) << 8) | (x))
295
296 #define AC97_GET_CODEC_ID(id, cp) \
297 do { \
298 (cp)[0] = ((id) >> 24) & 0xff; \
299 (cp)[1] = ((id) >> 16) & 0xff; \
300 (cp)[2] = ((id) >> 8) & 0xff; \
301 (cp)[3] = (id) & 0xff; \
302 } while (0)
303
304 static const struct ac97_codecid {
305 u_int32_t id;
306 const char *name;
307 } ac97codecid[] = {
308 { AC97_CODEC_ID('A', 'K', 'M', 0), "Asahi Kasei AK4540" },
309 #if 0
310 { AC97_CODEC_ID('C', 'R', 'Y', 0), "Crystal CS4297" },
311 #endif
312 { AC97_CODEC_ID('C', 'R', 'Y', 3), "Crystal CS4297" },
313 { AC97_CODEC_ID('C', 'R', 'Y', 19), "Crystal CS4297A" },
314 { 0x83847600, "SigmaTel STAC????" },
315 { 0x83847604, "SigmaTel STAC9701/3/4/5" },
316 { 0x83847605, "SigmaTel STAC9704" },
317 { 0x83847608, "SigmaTel STAC9708" },
318 { 0x83847609, "SigmaTel STAC9721" },
319 { 0, NULL }
320 };
321
322 static char *ac97enhancement[] = {
323 "no 3D stereo",
324 "Analog Devices Phat Stereo",
325 "Creative"
326 "National Semi 3D",
327 "Yamaha Ymersion",
328 "BBE 3D",
329 "Crystal Semi 3D"
330 "Qsound QXpander",
331 "Spatializer 3D",
332 "SRS 3D",
333 "Platform Tech 3D",
334 "AKM 3D",
335 "Aureal",
336 "AZTECH 3D",
337 "Binaura 3D",
338 "ESS Technology",
339 "Harman International VMAx",
340 "Nvidea 3D",
341 "Philips Incredible Sound",
342 "Texas Instruments' 3D",
343 "VLSI Technology 3D",
344 "TriTech 3D",
345 "Realtek 3D",
346 "Samsung 3D",
347 "Wolfson Microelectronics 3D",
348 "Delta Integration 3D",
349 "SigmaTel 3D",
350 "Unknown 3D",
351 "Rockwell 3D",
352 "Unknown 3D",
353 "Unknown 3D",
354 "Unknown 3D",
355 };
356
357 static char *ac97feature[] = {
358 "mic channel",
359 "reserved",
360 "tone",
361 "simulated stereo",
362 "headphone",
363 "bass boost",
364 "18 bit DAC",
365 "20 bit DAC",
366 "18 bit ADC",
367 "20 bit ADC"
368 };
369
370
371 int ac97_str_equal __P((char *, char *));
372 void ac97_setup_source_info __P((struct ac97_softc *));
373
374 /* #define AC97_DEBUG 10 */
375
376 #ifdef AUDIO_DEBUG
377 #define DPRINTF(x) if (ac97debug) printf x
378 #define DPRINTFN(n,x) if (ac97debug>(n)) printf x
379 #ifdef AC97_DEBUG
380 int ac97debug = AC97_DEBUG;
381 #else
382 int ac97debug = 0;
383 #endif
384 #else
385 #define DPRINTF(x)
386 #define DPRINTFN(n,x)
387 #endif
388
389
390 int
391 ac97_str_equal(a, b)
392 char *a, *b;
393 {
394 return ((a == b) || (a && b && (!strcmp(a, b))));
395 }
396
397 void
398 ac97_setup_source_info(as)
399 struct ac97_softc *as;
400 {
401 int idx, ouridx;
402 struct ac97_source_info *si, *si2;
403
404 for (idx = 0, ouridx = 0; idx < SOURCE_INFO_SIZE; idx++) {
405 si = &as->source_info[ouridx];
406
407 bcopy(&source_info[idx], si, sizeof(*si));
408
409 switch (si->type) {
410 case AUDIO_MIXER_CLASS:
411 si->mixer_class = ouridx;
412 ouridx++;
413 break;
414 case AUDIO_MIXER_VALUE:
415 /* Todo - Test to see if it works */
416 ouridx++;
417
418 /* Add an entry for mute, if necessary */
419 if (si->mute) {
420 si = &as->source_info[ouridx];
421 bcopy(&source_info[idx], si, sizeof(*si));
422 si->qualifier = AudioNmute;
423 si->type = AUDIO_MIXER_ENUM;
424 si->info = &ac97_on_off;
425 si->info_size = sizeof(ac97_on_off);
426 si->bits = 1;
427 si->ofs = 15;
428 si->mute = 0;
429 si->polarity = 0;
430 ouridx++;
431 }
432 break;
433 case AUDIO_MIXER_ENUM:
434 /* Todo - Test to see if it works */
435 ouridx++;
436 break;
437 default:
438 printf ("ac97: shouldn't get here\n");
439 break;
440 }
441 }
442
443 as->num_source_info = ouridx;
444
445 for (idx = 0; idx < as->num_source_info; idx++) {
446 int idx2, previdx;
447
448 si = &as->source_info[idx];
449
450 /* Find mixer class */
451 for (idx2 = 0; idx2 < as->num_source_info; idx2++) {
452 si2 = &as->source_info[idx2];
453
454 if (si2->type == AUDIO_MIXER_CLASS &&
455 ac97_str_equal(si->class,
456 si2->class)) {
457 si->mixer_class = idx2;
458 }
459 }
460
461
462 /* Setup prev and next pointers */
463 if (si->prev != 0)
464 continue;
465
466 if (si->qualifier)
467 continue;
468
469 si->prev = AUDIO_MIXER_LAST;
470 previdx = idx;
471
472 for (idx2 = 0; idx2 < as->num_source_info; idx2++) {
473 if (idx2 == idx)
474 continue;
475
476 si2 = &as->source_info[idx2];
477
478 if (!si2->prev &&
479 ac97_str_equal(si->class, si2->class) &&
480 ac97_str_equal(si->device, si2->device)) {
481 as->source_info[previdx].next = idx2;
482 as->source_info[idx2].prev = previdx;
483
484 previdx = idx2;
485 }
486 }
487
488 as->source_info[previdx].next = AUDIO_MIXER_LAST;
489 }
490 }
491
492 int
493 ac97_attach(hostIf)
494 struct ac97_host_if *hostIf;
495 {
496 struct ac97_softc *as;
497 struct device *sc_dev = (struct device *)hostIf->arg;
498 int error, i, j;
499 u_int16_t id1, id2, caps;
500 u_int32_t id;
501 mixer_ctrl_t ctl;
502
503 as = malloc(sizeof(struct ac97_softc), M_DEVBUF, M_WAITOK);
504
505 if (as == NULL)
506 return (ENOMEM);
507
508 as->codecIf.vtbl = &ac97civ;
509 as->hostIf = hostIf;
510
511 if ((error = hostIf->attach(hostIf->arg, &as->codecIf))) {
512 free (as, M_DEVBUF);
513 return (error);
514 }
515
516 hostIf->reset(hostIf->arg);
517
518 hostIf->write(hostIf->arg, AC97_REG_POWER, 0);
519 hostIf->write(hostIf->arg, AC97_REG_RESET, 0);
520
521 if ((error = hostIf->read(hostIf->arg, AC97_REG_VENDOR_ID1, &id1)))
522 return (error);
523
524 if ((error = hostIf->read(hostIf->arg, AC97_REG_VENDOR_ID2, &id2)))
525 return (error);
526
527 if ((error = hostIf->read(hostIf->arg, AC97_REG_RESET, &caps)))
528 return (error);
529
530 id = (id1 << 16) | id2;
531
532 printf("%s: ", sc_dev->dv_xname);
533
534 for (i = 0; ; i++) {
535 if (ac97codecid[i].id == id) {
536 printf("%s", ac97codecid[i].name);
537 break;
538 }
539 if (ac97codecid[i].id == 0) {
540 char pnp[4];
541
542 AC97_GET_CODEC_ID(id, pnp);
543 #define ISASCII(c) ((c) >= ' ' && (c) < 0x7f)
544 if (ISASCII(pnp[0]) && ISASCII(pnp[1]) &&
545 ISASCII(pnp[2]))
546 printf("%c%c%c%d", pnp[0], pnp[1], pnp[2],
547 pnp[3]);
548 else
549 printf("unknown (0x%08x)", id);
550 break;
551 }
552 }
553 printf(" codec; ");
554 for (i = j = 0; i < 10; i++) {
555 if (caps & (1 << i)) {
556 printf("%s%s", j? ", " : "", ac97feature[i]);
557 j++;
558 }
559 }
560
561 printf("%s%s\n", j? ", " : "", ac97enhancement[(caps >> 10) & 0x1f]);
562
563 ac97_setup_source_info(as);
564
565 /* Just enable the DAC and master volumes by default */
566 memset(&ctl, 0, sizeof(ctl));
567
568 ctl.type = AUDIO_MIXER_ENUM;
569 ctl.un.ord = 0; /* off */
570 ctl.dev = ac97_get_portnum_by_name(&as->codecIf, AudioCoutputs,
571 AudioNmaster, AudioNmute);
572 ac97_mixer_set_port(&as->codecIf, &ctl);
573 ctl.dev = ac97_get_portnum_by_name(&as->codecIf, AudioCinputs,
574 AudioNdac, AudioNmute);
575
576 ac97_mixer_set_port(&as->codecIf, &ctl);
577 ctl.dev = ac97_get_portnum_by_name(&as->codecIf, AudioCrecord,
578 AudioNvolume, AudioNmute);
579 ac97_mixer_set_port(&as->codecIf, &ctl);
580
581 ctl.dev = ac97_get_portnum_by_name(&as->codecIf, AudioCrecord,
582 AudioNsource, NULL);
583 ctl.type = AUDIO_MIXER_ENUM;
584 ctl.un.ord = 0;
585 ac97_mixer_set_port(&as->codecIf, &ctl);
586
587 return (0);
588 }
589
590
591 int
592 ac97_query_devinfo(codec_if, dip)
593 struct ac97_codec_if *codec_if;
594 mixer_devinfo_t *dip;
595 {
596 struct ac97_softc *as = (struct ac97_softc *)codec_if;
597
598 if (dip->index < as->num_source_info) {
599 struct ac97_source_info *si = &as->source_info[dip->index];
600 char *name;
601
602 dip->type = si->type;
603 dip->mixer_class = si->mixer_class;
604 dip->prev = si->prev;
605 dip->next = si->next;
606
607 if (si->qualifier)
608 name = si->qualifier;
609 else if (si->device)
610 name = si->device;
611 else if (si->class)
612 name = si->class;
613 else
614 name = 0;
615
616 if (name)
617 strcpy(dip->label.name, name);
618
619 bcopy(si->info, &dip->un, si->info_size);
620 return (0);
621 }
622
623 return (ENXIO);
624 }
625
626
627
628 int
629 ac97_mixer_set_port(codec_if, cp)
630 struct ac97_codec_if *codec_if;
631 mixer_ctrl_t *cp;
632 {
633 struct ac97_softc *as = (struct ac97_softc *)codec_if;
634 struct ac97_source_info *si = &as->source_info[cp->dev];
635 u_int16_t mask;
636 u_int16_t val, newval;
637 int error;
638
639 if (cp->dev < 0 || cp->dev >= as->num_source_info)
640 return (EINVAL);
641
642 if (cp->type != si->type)
643 return (EINVAL);
644
645 error = as->hostIf->read(as->hostIf->arg, si->reg, &val);
646 if (error)
647 return (error);
648
649 DPRINTFN(5, ("read(%x) = %x\n", si->reg, val));
650
651 mask = (1 << si->bits) - 1;
652
653 switch (cp->type) {
654 case AUDIO_MIXER_ENUM:
655 if (cp->un.ord > mask || cp->un.ord < 0)
656 return (EINVAL);
657
658 newval = (cp->un.ord << si->ofs);
659 if (si->reg == AC97_REG_RECORD_SELECT) {
660 newval |= (newval << (8 + si->ofs));
661 mask |= (mask << 8);
662 }
663 break;
664 case AUDIO_MIXER_VALUE:
665 {
666 struct audio_mixer_value *value = si->info;
667 u_int16_t l, r;
668
669 if ((cp->un.value.num_channels <= 0) ||
670 (cp->un.value.num_channels > value->num_channels))
671 return (EINVAL);
672
673 if (cp->un.value.num_channels == 1) {
674 l = r = cp->un.value.level[AUDIO_MIXER_LEVEL_MONO];
675 } else {
676 l = cp->un.value.level[AUDIO_MIXER_LEVEL_LEFT];
677 r = cp->un.value.level[AUDIO_MIXER_LEVEL_RIGHT];
678 }
679
680 if (!si->polarity) {
681 l = 255 - l;
682 r = 255 - r;
683 }
684
685 l = l >> (8 - si->bits);
686 r = r >> (8 - si->bits);
687
688 newval = ((l & mask) << si->ofs);
689 if (value->num_channels == 2) {
690 newval |= ((r & mask) << (si->ofs + 8));
691 mask |= (mask << 8);
692 }
693
694 break;
695 }
696 default:
697 return (EINVAL);
698 }
699
700 mask = mask << si->ofs;
701 error = as->hostIf->write(as->hostIf->arg, si->reg, (val & ~mask) | newval);
702 if (error)
703 return (error);
704
705 return (0);
706 }
707
708 int
709 ac97_get_portnum_by_name(codec_if, class, device, qualifier)
710 struct ac97_codec_if *codec_if;
711 char *class, *device, *qualifier;
712 {
713 struct ac97_softc *as = (struct ac97_softc *)codec_if;
714 int idx;
715
716 for (idx = 0; idx < as->num_source_info; idx++) {
717 struct ac97_source_info *si = &as->source_info[idx];
718 if (ac97_str_equal(class, si->class) &&
719 ac97_str_equal(device, si->device) &&
720 ac97_str_equal(qualifier, si->qualifier))
721 return (idx);
722 }
723
724 return (-1);
725 }
726
727 int
728 ac97_mixer_get_port(codec_if, cp)
729 struct ac97_codec_if *codec_if;
730 mixer_ctrl_t *cp;
731 {
732 struct ac97_softc *as = (struct ac97_softc *)codec_if;
733 struct ac97_source_info *si = &as->source_info[cp->dev];
734 u_int16_t mask;
735 u_int16_t val;
736 int error;
737
738 if (cp->dev < 0 || cp->dev >= as->num_source_info)
739 return (EINVAL);
740
741 if (cp->type != si->type)
742 return (EINVAL);
743
744 error = as->hostIf->read(as->hostIf->arg, si->reg, &val);
745 if (error)
746 return (error);
747
748 DPRINTFN(5, ("read(%x) = %x\n", si->reg, val));
749
750 mask = (1 << si->bits) - 1;
751
752 switch (cp->type) {
753 case AUDIO_MIXER_ENUM:
754 cp->un.ord = (val >> si->ofs) & mask;
755 DPRINTFN(4, ("AUDIO_MIXER_ENUM: %x %d %x %d\n", val, si->ofs, mask, cp->un.ord));
756 break;
757 case AUDIO_MIXER_VALUE:
758 {
759 struct audio_mixer_value *value = si->info;
760 u_int16_t l, r;
761
762 if ((cp->un.value.num_channels <= 0) ||
763 (cp->un.value.num_channels > value->num_channels))
764 return (EINVAL);
765
766 if (value->num_channels == 1) {
767 l = r = (val >> si->ofs) & mask;
768 } else {
769 l = (val >> si->ofs) & mask;
770 r = (val >> (si->ofs + 8)) & mask;
771 }
772
773 l = (l << (8 - si->bits));
774 r = (r << (8 - si->bits));
775 if (!si->polarity) {
776 l = 255 - l;
777 r = 255 - r;
778 }
779
780 /* The EAP driver averages l and r for stereo
781 channels that are requested in MONO mode. Does this
782 make sense? */
783 if (cp->un.value.num_channels == 1) {
784 cp->un.value.level[AUDIO_MIXER_LEVEL_MONO] = l;
785 } else if (cp->un.value.num_channels == 2) {
786 cp->un.value.level[AUDIO_MIXER_LEVEL_LEFT] = l;
787 cp->un.value.level[AUDIO_MIXER_LEVEL_RIGHT] = r;
788 }
789
790 break;
791 }
792 default:
793 return (EINVAL);
794 }
795
796 return (0);
797 }
798
799