ac97.c revision 70324
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 70324 2000-12-24 03:33:21Z 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	{ 0x414b4d00, 1, "Asahi Kasei AK4540 rev 0" },
60	{ 0x414b4d01, 1, "Asahi Kasei AK4540 rev 1" },
61	{ 0x43525900, 0, "Cirrus Logic CS4297" 	},
62	{ 0x83847600, 0, "SigmaTel STAC????" 	},
63	{ 0x83847604, 0, "SigmaTel STAC9701/3/4/5" },
64	{ 0x83847605, 0, "SigmaTel STAC9704" 	},
65	{ 0x83847608, 0, "SigmaTel STAC9708" 	},
66	{ 0x83847609, 0, "SigmaTel STAC9721" 	},
67	{ 0, 	      0, NULL			}
68};
69
70static char *ac97enhancement[] = {
71	"no 3D Stereo Enhancement",
72	"Analog Devices Phat Stereo",
73	"Creative Stereo Enhancement",
74	"National Semi 3D Stereo Enhancement",
75	"Yamaha Ymersion",
76	"BBE 3D Stereo Enhancement",
77	"Crystal Semi 3D Stereo Enhancement",
78	"Qsound QXpander",
79	"Spatializer 3D Stereo Enhancement",
80	"SRS 3D Stereo Enhancement",
81	"Platform Tech 3D Stereo Enhancement",
82	"AKM 3D Audio",
83	"Aureal Stereo Enhancement",
84	"Aztech 3D Enhancement",
85	"Binaura 3D Audio Enhancement",
86	"ESS Technology Stereo Enhancement",
87	"Harman International VMAx",
88	"Nvidea 3D Stereo Enhancement",
89	"Philips Incredible Sound",
90	"Texas Instruments 3D Stereo Enhancement",
91	"VLSI Technology 3D Stereo Enhancement",
92	"TriTech 3D Stereo Enhancement",
93	"Realtek 3D Stereo Enhancement",
94	"Samsung 3D Stereo Enhancement",
95	"Wolfson Microelectronics 3D Enhancement",
96	"Delta Integration 3D Enhancement",
97	"SigmaTel 3D Enhancement",
98	"Reserved 27",
99	"Rockwell 3D Stereo Enhancement",
100	"Reserved 29",
101	"Reserved 30",
102	"Reserved 31"
103};
104
105static char *ac97feature[] = {
106	"mic channel",
107	"reserved",
108	"tone",
109	"simulated stereo",
110	"headphone",
111	"bass boost",
112	"18 bit DAC",
113	"20 bit DAC",
114	"18 bit ADC",
115	"20 bit ADC"
116};
117
118static char *ac97extfeature[] = {
119	"variable rate PCM",
120	"double rate PCM",
121	"reserved 1",
122	"variable rate mic",
123	"reserved 2",
124	"reserved 3",
125	"center DAC",
126	"surround DAC",
127	"LFE DAC",
128	"AMAP",
129	"reserved 4",
130	"reserved 5",
131	"reserved 6",
132	"reserved 7",
133};
134
135static u_int16_t
136rdcd(struct ac97_info *codec, int reg)
137{
138	return AC97_READ(codec->methods, codec->devinfo, reg);
139}
140
141static void
142wrcd(struct ac97_info *codec, int reg, u_int16_t val)
143{
144	AC97_WRITE(codec->methods, codec->devinfo, reg, val);
145}
146
147int
148ac97_setrate(struct ac97_info *codec, int which, int rate)
149{
150	u_int16_t v;
151
152	switch(which) {
153	case AC97_REGEXT_FDACRATE:
154	case AC97_REGEXT_SDACRATE:
155	case AC97_REGEXT_LDACRATE:
156	case AC97_REGEXT_LADCRATE:
157	case AC97_REGEXT_MADCRATE:
158		break;
159
160	default:
161		return -1;
162	}
163
164	if (rate != 0) {
165		v = rate;
166		if (codec->extstat & AC97_EXTCAP_DRA)
167			v >>= 1;
168		wrcd(codec, which, v);
169	}
170	v = rdcd(codec, which);
171	if (codec->extstat & AC97_EXTCAP_DRA)
172		v <<= 1;
173	return v;
174}
175
176int
177ac97_setextmode(struct ac97_info *codec, u_int16_t mode)
178{
179	mode &= AC97_EXTCAPS;
180	if ((mode & ~codec->extcaps) != 0)
181		return -1;
182	wrcd(codec, AC97_REGEXT_STAT, mode);
183	codec->extstat = rdcd(codec, AC97_REGEXT_STAT) & AC97_EXTCAPS;
184	return (mode == codec->extstat)? 0 : -1;
185}
186
187u_int16_t
188ac97_getextmode(struct ac97_info *codec)
189{
190	return codec->extstat;
191}
192
193u_int16_t
194ac97_getextcaps(struct ac97_info *codec)
195{
196	return codec->extcaps;
197}
198
199static int
200ac97_setrecsrc(struct ac97_info *codec, int channel)
201{
202	struct ac97mixtable_entry *e = &codec->mix[channel];
203
204	if (e->recidx > 0) {
205		int val = e->recidx - 1;
206		val |= val << 8;
207		wrcd(codec, AC97_REG_RECSEL, val);
208		return 0;
209	} else
210		return -1;
211}
212
213static int
214ac97_setmixer(struct ac97_info *codec, unsigned channel, unsigned left, unsigned right)
215{
216	struct ac97mixtable_entry *e = &codec->mix[channel];
217
218	if (e->reg && e->enable && e->bits) {
219		int max, val, reg = (e->reg >= 0)? e->reg : -e->reg;
220
221		if (!e->stereo)
222			right = left;
223		if (e->reg > 0) {
224			left = 100 - left;
225			right = 100 - right;
226		}
227
228		max = (1 << e->bits) - 1;
229		left = (left * max) / 100;
230		right = (right * max) / 100;
231
232		val = (left << 8) | right;
233
234		left = (left * 100) / max;
235		right = (right * 100) / max;
236
237		if (e->reg > 0) {
238			left = 100 - left;
239			right = 100 - right;
240		}
241
242		if (!e->stereo) {
243			val &= max;
244			val <<= e->ofs;
245			if (e->mask) {
246				int cur = rdcd(codec, e->reg);
247				val |= cur & ~(max << e->ofs);
248			}
249		}
250		if (left == 0 && right == 0 && e->mute == 1)
251			val = AC97_MUTE;
252		wrcd(codec, reg, val);
253		return left | (right << 8);
254	} else {
255		/* printf("ac97_setmixer: reg=%d, bits=%d, enable=%d\n", e->reg, e->bits, e->enable); */
256		return -1;
257	}
258}
259
260#if 0
261static int
262ac97_getmixer(struct ac97_info *codec, int channel)
263{
264	struct ac97mixtable_entry *e = &codec->mix[channel];
265	if (channel < SOUND_MIXER_NRDEVICES && e->reg != 0) {
266		int max, val, volume;
267
268		max = (1 << e->bits) - 1;
269		val = rdcd(code, e->reg);
270		if (val == AC97_MUTE && e->mute == 1)
271			volume = 0;
272		else {
273			if (e->stereo == 0) val >>= e->ofs;
274			val &= max;
275			volume = (val * 100) / max;
276			if (e->reg > 0) volume = 100 - volume;
277		}
278		return volume;
279	} else
280		return -1;
281}
282#endif
283
284static unsigned
285ac97_initmixer(struct ac97_info *codec)
286{
287	unsigned i, j, k, old;
288	u_int32_t id;
289
290	for (i = 0; i < 32; i++)
291		codec->mix[i] = ac97mixtable_default[i];
292
293	codec->count = AC97_INIT(codec->methods, codec->devinfo);
294	if (codec->count == 0) {
295		device_printf(codec->dev, "ac97 codec init failed\n");
296		return ENODEV;
297	}
298
299	wrcd(codec, AC97_REG_POWER, 0);
300	wrcd(codec, AC97_REG_RESET, 0);
301	DELAY(100000);
302
303	i = rdcd(codec, AC97_REG_RESET);
304	codec->caps = i & 0x03ff;
305	codec->se =  (i & 0x7c00) >> 10;
306
307	id = (rdcd(codec, AC97_REG_ID1) << 16) | rdcd(codec, AC97_REG_ID2);
308	codec->rev = id & 0x000000ff;
309	if (id == 0 || id == 0xffffffff) {
310		device_printf(codec->dev, "ac97 codec invalid or not present (id == %x)\n", id);
311		return ENODEV;
312	}
313
314	codec->noext = 0;
315	codec->name = NULL;
316	for (i = 0; ac97codecid[i].id; i++) {
317		if (ac97codecid[i].id == id) {
318			codec->name = ac97codecid[i].name;
319			codec->noext = ac97codecid[i].noext;
320		}
321	}
322
323	codec->extcaps = 0;
324	codec->extid = 0;
325	codec->extstat = 0;
326	if (!codec->noext) {
327		i = rdcd(codec, AC97_REGEXT_ID);
328		if (i != 0xffff) {
329			codec->extcaps = i & 0x3fff;
330			codec->extid =  (i & 0xc000) >> 14;
331			codec->extstat = rdcd(codec, AC97_REGEXT_STAT) & AC97_EXTCAPS;
332		}
333	}
334
335	for (i = 0; i < 32; i++) {
336		k = codec->noext? codec->mix[i].enable : 1;
337		if (k && (codec->mix[i].reg > 0)) {
338			old = rdcd(codec, codec->mix[i].reg);
339			wrcd(codec, codec->mix[i].reg, 0x3f);
340			j = rdcd(codec, codec->mix[i].reg);
341			wrcd(codec, codec->mix[i].reg, old);
342			codec->mix[i].enable = (j != 0 && j != old)? 1 : 0;
343			for (k = 1; j & (1 << k); k++);
344			codec->mix[i].bits = j? k - codec->mix[i].ofs : 0;
345		}
346		/* printf("mixch %d, en=%d, b=%d\n", i, codec->mix[i].enable, codec->mix[i].bits); */
347	}
348
349	if (bootverbose) {
350		device_printf(codec->dev, "ac97 codec id 0x%08x", id);
351		if (codec->name)
352			printf(" (%s)", codec->name);
353		printf("\n");
354		device_printf(codec->dev, "ac97 codec features ");
355		for (i = j = 0; i < 10; i++)
356			if (codec->caps & (1 << i))
357				printf("%s%s", j++? ", " : "", ac97feature[i]);
358		printf("%s%d bit master volume", j++? ", " : "", codec->mix[SOUND_MIXER_VOLUME].bits);
359		printf("%s%s\n", j? ", " : "", ac97enhancement[codec->se]);
360
361		if (codec->extcaps != 0 || codec->extid) {
362			device_printf(codec->dev, "ac97 %s codec",
363				      codec->extid? "secondary" : "primary");
364			if (codec->extcaps)
365				printf(" extended features ");
366			for (i = j = 0; i < 14; i++)
367				if (codec->extcaps & (1 << i))
368					printf("%s%s", j++? ", " : "", ac97extfeature[i]);
369			printf("\n");
370		}
371	}
372
373	if ((rdcd(codec, AC97_REG_POWER) & 2) == 0)
374		device_printf(codec->dev, "ac97 codec reports dac not ready\n");
375	return 0;
376}
377
378static unsigned
379ac97_reinitmixer(struct ac97_info *codec)
380{
381	unsigned i;
382
383	codec->count = AC97_INIT(codec->methods, codec->devinfo);
384	if (codec->count == 0) {
385		device_printf(codec->dev, "ac97 codec init failed\n");
386		return ENODEV;
387	}
388
389	wrcd(codec, AC97_REG_POWER, 0);
390	wrcd(codec, AC97_REG_RESET, 0);
391	DELAY(100000);
392	i = rdcd(codec, AC97_REG_RESET);
393
394	if (!codec->noext) {
395		wrcd(codec, AC97_REGEXT_STAT, codec->extstat);
396		if (rdcd(codec, AC97_REGEXT_STAT) != codec->extstat)
397			device_printf(codec->dev, "ac97 codec failed to reset extended mode (%x, got %x)\n",
398				      codec->extstat, rdcd(codec, AC97_REGEXT_STAT));
399	}
400
401	if ((rdcd(codec, AC97_REG_POWER) & 2) == 0)
402		device_printf(codec->dev, "ac97 codec reports dac not ready\n");
403	return 0;
404}
405
406struct ac97_info *
407ac97_create(device_t dev, void *devinfo, kobj_class_t cls)
408{
409	struct ac97_info *codec;
410
411	codec = (struct ac97_info *)malloc(sizeof *codec, M_AC97, M_NOWAIT);
412	if (codec == NULL)
413		return NULL;
414
415	codec->methods = kobj_create(cls, M_AC97, M_WAITOK);
416	if (codec->methods == NULL) {
417		free(codec, M_AC97);
418		return NULL;
419	}
420
421	codec->dev = dev;
422	codec->devinfo = devinfo;
423	return codec;
424}
425
426void
427ac97_destroy(struct ac97_info *codec)
428{
429	if (codec->methods != NULL)
430		kobj_delete(codec->methods, M_AC97);
431	free(codec, M_AC97);
432}
433
434/* -------------------------------------------------------------------- */
435
436static int
437ac97mix_init(snd_mixer *m)
438{
439	struct ac97_info *codec = mix_getdevinfo(m);
440	u_int32_t i, mask;
441
442	if (codec == NULL)
443		return -1;
444
445	if (ac97_initmixer(codec))
446		return -1;
447
448	mask = 0;
449	for (i = 0; i < 32; i++)
450		mask |= codec->mix[i].enable? 1 << i : 0;
451	mix_setdevs(m, mask);
452
453	mask = 0;
454	for (i = 0; i < 32; i++)
455		mask |= codec->mix[i].recidx? 1 << i : 0;
456	mix_setrecdevs(m, mask);
457	return 0;
458}
459
460static int
461ac97mix_uninit(snd_mixer *m)
462{
463	struct ac97_info *codec = mix_getdevinfo(m);
464
465	if (codec == NULL)
466		return -1;
467	/*
468	if (ac97_uninitmixer(codec))
469		return -1;
470	*/
471	ac97_destroy(codec);
472	return 0;
473}
474
475static int
476ac97mix_reinit(snd_mixer *m)
477{
478	struct ac97_info *codec = mix_getdevinfo(m);
479
480	if (codec == NULL)
481		return -1;
482	return ac97_reinitmixer(codec);
483}
484
485static int
486ac97mix_set(snd_mixer *m, unsigned dev, unsigned left, unsigned right)
487{
488	struct ac97_info *codec = mix_getdevinfo(m);
489
490	if (codec == NULL)
491		return -1;
492	return ac97_setmixer(codec, dev, left, right);
493}
494
495static int
496ac97mix_setrecsrc(snd_mixer *m, u_int32_t src)
497{
498	int i;
499	struct ac97_info *codec = mix_getdevinfo(m);
500
501	if (codec == NULL)
502		return -1;
503	for (i = 0; i < SOUND_MIXER_NRDEVICES; i++)
504		if ((src & (1 << i)) != 0)
505			break;
506	return (ac97_setrecsrc(codec, i) == 0)? 1 << i : -1;
507}
508
509static kobj_method_t ac97mixer_methods[] = {
510    	KOBJMETHOD(mixer_init,		ac97mix_init),
511    	KOBJMETHOD(mixer_uninit,	ac97mix_uninit),
512    	KOBJMETHOD(mixer_reinit,	ac97mix_reinit),
513    	KOBJMETHOD(mixer_set,		ac97mix_set),
514    	KOBJMETHOD(mixer_setrecsrc,	ac97mix_setrecsrc),
515	{ 0, 0 }
516};
517MIXER_DECLARE(ac97mixer);
518
519/* -------------------------------------------------------------------- */
520
521kobj_class_t
522ac97_getmixerclass(void)
523{
524	return &ac97mixer_class;
525}
526
527
528