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