ac97.c revision 74622
1/*
2 * Copyright (c) 1999 Cameron Grant <gandalf@vilnya.demon.co.uk>
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 *    notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 *    notice, this list of conditions and the following disclaimer in the
12 *    documentation and/or other materials provided with the distribution.
13 *
14 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17 * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24 * SUCH DAMAGE.
25 *
26 * $FreeBSD: head/sys/dev/sound/pcm/ac97.c 74622 2001-03-22 02:41:24Z cg $
27 */
28
29#include <dev/sound/pcm/sound.h>
30#include <dev/sound/pcm/ac97.h>
31
32#include "mixer_if.h"
33
34MALLOC_DEFINE(M_AC97, "ac97", "ac97 codec");
35
36struct ac97_codecid {
37	u_int32_t id, noext:1;
38	char *name;
39};
40
41static const struct ac97mixtable_entry ac97mixtable_default[32] = {
42	[SOUND_MIXER_VOLUME]	= { AC97_MIX_MASTER, 	5, 0, 1, 1, 6, 0, 1 },
43	[SOUND_MIXER_MONITOR]	= { AC97_MIX_PHONES, 	5, 0, 1, 1, 0, 0, 0 },
44	[SOUND_MIXER_PHONEOUT]	= { AC97_MIX_MONO, 	5, 0, 0, 1, 7, 0, 0 },
45	[SOUND_MIXER_BASS]	= { AC97_MIX_TONE, 	4, 8, 0, 0, 0, 1, 0 },
46	[SOUND_MIXER_TREBLE]	= { AC97_MIX_TONE, 	4, 0, 0, 0, 0, 1, 0 },
47	[SOUND_MIXER_PCM]	= { AC97_MIX_PCM, 	5, 0, 1, 1, 0, 0, 1 },
48	[SOUND_MIXER_SPEAKER]	= { AC97_MIX_BEEP, 	4, 1, 0, 1, 0, 0, 0 },
49	[SOUND_MIXER_LINE]	= { AC97_MIX_LINE, 	5, 0, 1, 1, 5, 0, 1 },
50	[SOUND_MIXER_PHONEIN]	= { AC97_MIX_PHONE, 	5, 0, 0, 1, 8, 0, 0 },
51	[SOUND_MIXER_MIC] 	= { AC97_MIX_MIC, 	5, 0, 0, 1, 1, 0, 1 },
52	[SOUND_MIXER_CD]	= { AC97_MIX_CD, 	5, 0, 1, 1, 2, 0, 1 },
53	[SOUND_MIXER_LINE1]	= { AC97_MIX_AUX, 	5, 0, 1, 1, 4, 0, 0 },
54	[SOUND_MIXER_VIDEO]	= { AC97_MIX_VIDEO, 	5, 0, 1, 1, 3, 0, 0 },
55	[SOUND_MIXER_RECLEV]	= { -AC97_MIX_RGAIN, 	4, 0, 1, 1, 0, 0, 1 }
56};
57
58static struct ac97_codecid ac97codecid[] = {
59	{ 0x41445303, 0, "Analog Devices AD1819" },
60	{ 0x41445340, 0, "Analog Devices AD1881" },
61	{ 0x41445348, 0, "Analog Devices AD1881A" },
62	{ 0x41445360, 0, "Analog Devices AD1885" },
63	{ 0x414b4d00, 1, "Asahi Kasei AK4540" },
64	{ 0x414b4d01, 1, "Asahi Kasei AK4542" },
65	{ 0x414b4d02, 1, "Asahi Kasei AK4543" },
66	{ 0x414c4710, 0, "Avance Logic ALC200/200P" },
67	{ 0x43525900, 0, "Cirrus Logic CS4297" },
68	{ 0x43525903, 0, "Cirrus Logic CS4297" },
69	{ 0x43525913, 0, "Cirrus Logic CS4297A" },
70	{ 0x43525914, 0, "Cirrus Logic CS4297B" },
71	{ 0x43525923, 0, "Cirrus Logic CS4294C" },
72	{ 0x4352592b, 0, "Cirrus Logic CS4298C" },
73	{ 0x43525931, 0, "Cirrus Logic CS4299A" },
74	{ 0x43525933, 0, "Cirrus Logic CS4299C" },
75	{ 0x43525934, 0, "Cirrus Logic CS4299D" },
76	{ 0x43525941, 0, "Cirrus Logic CS4201A" },
77	{ 0x43525951, 0, "Cirrus Logic CS4205A" },
78	{ 0x43525961, 0, "Cirrus Logic CS4291A" },
79	{ 0x45838308, 0, "ESS Technology ES1921" },
80	{ 0x49434511, 0, "ICEnsemble ICE1232" },
81	{ 0x4e534331, 0, "National Semiconductor LM4549" },
82	{ 0x83847600, 0, "SigmaTel STAC9700/9783/9784" },
83	{ 0x83847604, 0, "SigmaTel STAC9701/9703/9704/9705" },
84	{ 0x83847605, 0, "SigmaTel STAC9704" },
85	{ 0x83847608, 0, "SigmaTel STAC9708/9711" },
86	{ 0x83847609, 0, "SigmaTel STAC9721/9723" },
87	{ 0x83847644, 0, "SigmaTel STAC9744" },
88	{ 0x83847656, 0, "SigmaTel STAC9756/9757" },
89	{ 0x53494c22, 0, "Silicon Laboratory Si3036" },
90	{ 0x53494c23, 0, "Silicon Laboratory Si3038" },
91	{ 0x54524103, 0, "TriTech TR?????" },
92	{ 0x54524106, 0, "TriTech TR28026" },
93	{ 0x54524108, 0, "TriTech TR28028" },
94	{ 0x54524123, 0, "TriTech TR28602" },
95	{ 0x574d4c00, 0, "Wolfson WM9701A" },
96	{ 0x574d4c03, 0, "Wolfson WM9703/9704" },
97	{ 0x574d4c04, 0, "Wolfson WM9704 (quad)" },
98	{ 0, 0, NULL }
99};
100
101static char *ac97enhancement[] = {
102	"no 3D Stereo Enhancement",
103	"Analog Devices Phat Stereo",
104	"Creative Stereo Enhancement",
105	"National Semi 3D Stereo Enhancement",
106	"Yamaha Ymersion",
107	"BBE 3D Stereo Enhancement",
108	"Crystal Semi 3D Stereo Enhancement",
109	"Qsound QXpander",
110	"Spatializer 3D Stereo Enhancement",
111	"SRS 3D Stereo Enhancement",
112	"Platform Tech 3D Stereo Enhancement",
113	"AKM 3D Audio",
114	"Aureal Stereo Enhancement",
115	"Aztech 3D Enhancement",
116	"Binaura 3D Audio Enhancement",
117	"ESS Technology Stereo Enhancement",
118	"Harman International VMAx",
119	"Nvidea 3D Stereo Enhancement",
120	"Philips Incredible Sound",
121	"Texas Instruments 3D Stereo Enhancement",
122	"VLSI Technology 3D Stereo Enhancement",
123	"TriTech 3D Stereo Enhancement",
124	"Realtek 3D Stereo Enhancement",
125	"Samsung 3D Stereo Enhancement",
126	"Wolfson Microelectronics 3D Enhancement",
127	"Delta Integration 3D Enhancement",
128	"SigmaTel 3D Enhancement",
129	"Reserved 27",
130	"Rockwell 3D Stereo Enhancement",
131	"Reserved 29",
132	"Reserved 30",
133	"Reserved 31"
134};
135
136static char *ac97feature[] = {
137	"mic channel",
138	"reserved",
139	"tone",
140	"simulated stereo",
141	"headphone",
142	"bass boost",
143	"18 bit DAC",
144	"20 bit DAC",
145	"18 bit ADC",
146	"20 bit ADC"
147};
148
149static char *ac97extfeature[] = {
150	"variable rate PCM",
151	"double rate PCM",
152	"reserved 1",
153	"variable rate mic",
154	"reserved 2",
155	"reserved 3",
156	"center DAC",
157	"surround DAC",
158	"LFE DAC",
159	"AMAP",
160	"reserved 4",
161	"reserved 5",
162	"reserved 6",
163	"reserved 7",
164};
165
166static u_int16_t
167rdcd(struct ac97_info *codec, int reg)
168{
169	return AC97_READ(codec->methods, codec->devinfo, reg);
170}
171
172static void
173wrcd(struct ac97_info *codec, int reg, u_int16_t val)
174{
175	AC97_WRITE(codec->methods, codec->devinfo, reg, val);
176}
177
178int
179ac97_setrate(struct ac97_info *codec, int which, int rate)
180{
181	u_int16_t v;
182
183	switch(which) {
184	case AC97_REGEXT_FDACRATE:
185	case AC97_REGEXT_SDACRATE:
186	case AC97_REGEXT_LDACRATE:
187	case AC97_REGEXT_LADCRATE:
188	case AC97_REGEXT_MADCRATE:
189		break;
190
191	default:
192		return -1;
193	}
194
195	if (rate != 0) {
196		v = rate;
197		if (codec->extstat & AC97_EXTCAP_DRA)
198			v >>= 1;
199		wrcd(codec, which, v);
200	}
201	v = rdcd(codec, which);
202	if (codec->extstat & AC97_EXTCAP_DRA)
203		v <<= 1;
204	return v;
205}
206
207int
208ac97_setextmode(struct ac97_info *codec, u_int16_t mode)
209{
210	mode &= AC97_EXTCAPS;
211	if ((mode & ~codec->extcaps) != 0)
212		return -1;
213	wrcd(codec, AC97_REGEXT_STAT, mode);
214	codec->extstat = rdcd(codec, AC97_REGEXT_STAT) & AC97_EXTCAPS;
215	return (mode == codec->extstat)? 0 : -1;
216}
217
218u_int16_t
219ac97_getextmode(struct ac97_info *codec)
220{
221	return codec->extstat;
222}
223
224u_int16_t
225ac97_getextcaps(struct ac97_info *codec)
226{
227	return codec->extcaps;
228}
229
230static int
231ac97_setrecsrc(struct ac97_info *codec, int channel)
232{
233	struct ac97mixtable_entry *e = &codec->mix[channel];
234
235	if (e->recidx > 0) {
236		int val = e->recidx - 1;
237		val |= val << 8;
238		wrcd(codec, AC97_REG_RECSEL, val);
239		return 0;
240	} else
241		return -1;
242}
243
244static int
245ac97_setmixer(struct ac97_info *codec, unsigned channel, unsigned left, unsigned right)
246{
247	struct ac97mixtable_entry *e = &codec->mix[channel];
248
249	if (e->reg && e->enable && e->bits) {
250		int max, val, reg = (e->reg >= 0)? e->reg : -e->reg;
251
252		if (!e->stereo)
253			right = left;
254		if (e->reg > 0) {
255			left = 100 - left;
256			right = 100 - right;
257		}
258
259		max = (1 << e->bits) - 1;
260		left = (left * max) / 100;
261		right = (right * max) / 100;
262
263		val = (left << 8) | right;
264
265		left = (left * 100) / max;
266		right = (right * 100) / max;
267
268		if (e->reg > 0) {
269			left = 100 - left;
270			right = 100 - right;
271		}
272
273		if (!e->stereo) {
274			val &= max;
275			val <<= e->ofs;
276			if (e->mask) {
277				int cur = rdcd(codec, e->reg);
278				val |= cur & ~(max << e->ofs);
279			}
280		}
281		if (left == 0 && right == 0 && e->mute == 1)
282			val = AC97_MUTE;
283		wrcd(codec, reg, val);
284		return left | (right << 8);
285	} else {
286		/* printf("ac97_setmixer: reg=%d, bits=%d, enable=%d\n", e->reg, e->bits, e->enable); */
287		return -1;
288	}
289}
290
291#if 0
292static int
293ac97_getmixer(struct ac97_info *codec, int channel)
294{
295	struct ac97mixtable_entry *e = &codec->mix[channel];
296	if (channel < SOUND_MIXER_NRDEVICES && e->reg != 0) {
297		int max, val, volume;
298
299		max = (1 << e->bits) - 1;
300		val = rdcd(code, e->reg);
301		if (val == AC97_MUTE && e->mute == 1)
302			volume = 0;
303		else {
304			if (e->stereo == 0) val >>= e->ofs;
305			val &= max;
306			volume = (val * 100) / max;
307			if (e->reg > 0) volume = 100 - volume;
308		}
309		return volume;
310	} else
311		return -1;
312}
313#endif
314
315static unsigned
316ac97_initmixer(struct ac97_info *codec)
317{
318	unsigned i, j, k, old;
319	u_int32_t id;
320
321	for (i = 0; i < 32; i++)
322		codec->mix[i] = ac97mixtable_default[i];
323
324	codec->count = AC97_INIT(codec->methods, codec->devinfo);
325	if (codec->count == 0) {
326		device_printf(codec->dev, "ac97 codec init failed\n");
327		return ENODEV;
328	}
329
330	wrcd(codec, AC97_REG_POWER, 0);
331	wrcd(codec, AC97_REG_RESET, 0);
332	DELAY(100000);
333
334	i = rdcd(codec, AC97_REG_RESET);
335	codec->caps = i & 0x03ff;
336	codec->se =  (i & 0x7c00) >> 10;
337
338	id = (rdcd(codec, AC97_REG_ID1) << 16) | rdcd(codec, AC97_REG_ID2);
339	codec->rev = id & 0x000000ff;
340	if (id == 0 || id == 0xffffffff) {
341		device_printf(codec->dev, "ac97 codec invalid or not present (id == %x)\n", id);
342		return ENODEV;
343	}
344
345	codec->noext = 0;
346	codec->name = NULL;
347	for (i = 0; ac97codecid[i].id; i++) {
348		if (ac97codecid[i].id == id) {
349			codec->name = ac97codecid[i].name;
350			codec->noext = ac97codecid[i].noext;
351		}
352	}
353
354	codec->extcaps = 0;
355	codec->extid = 0;
356	codec->extstat = 0;
357	if (!codec->noext) {
358		i = rdcd(codec, AC97_REGEXT_ID);
359		if (i != 0xffff) {
360			codec->extcaps = i & 0x3fff;
361			codec->extid =  (i & 0xc000) >> 14;
362			codec->extstat = rdcd(codec, AC97_REGEXT_STAT) & AC97_EXTCAPS;
363		}
364	}
365
366	for (i = 0; i < 32; i++) {
367		k = codec->noext? codec->mix[i].enable : 1;
368		if (k && (codec->mix[i].reg > 0)) {
369			old = rdcd(codec, codec->mix[i].reg);
370			wrcd(codec, codec->mix[i].reg, 0x3f);
371			j = rdcd(codec, codec->mix[i].reg);
372			wrcd(codec, codec->mix[i].reg, old);
373			codec->mix[i].enable = (j != 0 && j != old)? 1 : 0;
374			for (k = 1; j & (1 << k); k++);
375			codec->mix[i].bits = j? k - codec->mix[i].ofs : 0;
376		}
377		/* printf("mixch %d, en=%d, b=%d\n", i, codec->mix[i].enable, codec->mix[i].bits); */
378	}
379
380	if (bootverbose) {
381		device_printf(codec->dev, "ac97 codec id 0x%08x", id);
382		if (codec->name)
383			printf(" (%s)", codec->name);
384		printf("\n");
385		device_printf(codec->dev, "ac97 codec features ");
386		for (i = j = 0; i < 10; i++)
387			if (codec->caps & (1 << i))
388				printf("%s%s", j++? ", " : "", ac97feature[i]);
389		printf("%s%d bit master volume", j++? ", " : "", codec->mix[SOUND_MIXER_VOLUME].bits);
390		printf("%s%s\n", j? ", " : "", ac97enhancement[codec->se]);
391
392		if (codec->extcaps != 0 || codec->extid) {
393			device_printf(codec->dev, "ac97 %s codec",
394				      codec->extid? "secondary" : "primary");
395			if (codec->extcaps)
396				printf(" extended features ");
397			for (i = j = 0; i < 14; i++)
398				if (codec->extcaps & (1 << i))
399					printf("%s%s", j++? ", " : "", ac97extfeature[i]);
400			printf("\n");
401		}
402	}
403
404	if ((rdcd(codec, AC97_REG_POWER) & 2) == 0)
405		device_printf(codec->dev, "ac97 codec reports dac not ready\n");
406	return 0;
407}
408
409static unsigned
410ac97_reinitmixer(struct ac97_info *codec)
411{
412	unsigned i;
413
414	codec->count = AC97_INIT(codec->methods, codec->devinfo);
415	if (codec->count == 0) {
416		device_printf(codec->dev, "ac97 codec init failed\n");
417		return ENODEV;
418	}
419
420	wrcd(codec, AC97_REG_POWER, 0);
421	wrcd(codec, AC97_REG_RESET, 0);
422	DELAY(100000);
423	i = rdcd(codec, AC97_REG_RESET);
424
425	if (!codec->noext) {
426		wrcd(codec, AC97_REGEXT_STAT, codec->extstat);
427		if (rdcd(codec, AC97_REGEXT_STAT) != codec->extstat)
428			device_printf(codec->dev, "ac97 codec failed to reset extended mode (%x, got %x)\n",
429				      codec->extstat, rdcd(codec, AC97_REGEXT_STAT));
430	}
431
432	if ((rdcd(codec, AC97_REG_POWER) & 2) == 0)
433		device_printf(codec->dev, "ac97 codec reports dac not ready\n");
434	return 0;
435}
436
437struct ac97_info *
438ac97_create(device_t dev, void *devinfo, kobj_class_t cls)
439{
440	struct ac97_info *codec;
441
442	codec = (struct ac97_info *)malloc(sizeof *codec, M_AC97, M_NOWAIT);
443	if (codec == NULL)
444		return NULL;
445
446	codec->methods = kobj_create(cls, M_AC97, M_WAITOK);
447	if (codec->methods == NULL) {
448		free(codec, M_AC97);
449		return NULL;
450	}
451
452	codec->dev = dev;
453	codec->devinfo = devinfo;
454	return codec;
455}
456
457void
458ac97_destroy(struct ac97_info *codec)
459{
460	if (codec->methods != NULL)
461		kobj_delete(codec->methods, M_AC97);
462	free(codec, M_AC97);
463}
464
465/* -------------------------------------------------------------------- */
466
467static int
468ac97mix_init(snd_mixer *m)
469{
470	struct ac97_info *codec = mix_getdevinfo(m);
471	u_int32_t i, mask;
472
473	if (codec == NULL)
474		return -1;
475
476	if (ac97_initmixer(codec))
477		return -1;
478
479	mask = 0;
480	for (i = 0; i < 32; i++)
481		mask |= codec->mix[i].enable? 1 << i : 0;
482	mix_setdevs(m, mask);
483
484	mask = 0;
485	for (i = 0; i < 32; i++)
486		mask |= codec->mix[i].recidx? 1 << i : 0;
487	mix_setrecdevs(m, mask);
488	return 0;
489}
490
491static int
492ac97mix_uninit(snd_mixer *m)
493{
494	struct ac97_info *codec = mix_getdevinfo(m);
495
496	if (codec == NULL)
497		return -1;
498	/*
499	if (ac97_uninitmixer(codec))
500		return -1;
501	*/
502	ac97_destroy(codec);
503	return 0;
504}
505
506static int
507ac97mix_reinit(snd_mixer *m)
508{
509	struct ac97_info *codec = mix_getdevinfo(m);
510
511	if (codec == NULL)
512		return -1;
513	return ac97_reinitmixer(codec);
514}
515
516static int
517ac97mix_set(snd_mixer *m, unsigned dev, unsigned left, unsigned right)
518{
519	struct ac97_info *codec = mix_getdevinfo(m);
520
521	if (codec == NULL)
522		return -1;
523	return ac97_setmixer(codec, dev, left, right);
524}
525
526static int
527ac97mix_setrecsrc(snd_mixer *m, u_int32_t src)
528{
529	int i;
530	struct ac97_info *codec = mix_getdevinfo(m);
531
532	if (codec == NULL)
533		return -1;
534	for (i = 0; i < SOUND_MIXER_NRDEVICES; i++)
535		if ((src & (1 << i)) != 0)
536			break;
537	return (ac97_setrecsrc(codec, i) == 0)? 1 << i : -1;
538}
539
540static kobj_method_t ac97mixer_methods[] = {
541    	KOBJMETHOD(mixer_init,		ac97mix_init),
542    	KOBJMETHOD(mixer_uninit,	ac97mix_uninit),
543    	KOBJMETHOD(mixer_reinit,	ac97mix_reinit),
544    	KOBJMETHOD(mixer_set,		ac97mix_set),
545    	KOBJMETHOD(mixer_setrecsrc,	ac97mix_setrecsrc),
546	{ 0, 0 }
547};
548MIXER_DECLARE(ac97mixer);
549
550/* -------------------------------------------------------------------- */
551
552kobj_class_t
553ac97_getmixerclass(void)
554{
555	return &ac97mixer_class;
556}
557
558
559