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