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