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