Deleted Added
full compact
ac97.c (153865) ac97.c (154094)
1/*-
2 * Copyright (c) 1999 Cameron Grant <cg@freebsd.org>
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
27#include <dev/sound/pcm/sound.h>
28#include <dev/sound/pcm/ac97.h>
29#include <dev/sound/pcm/ac97_patch.h>
30
31#include "mixer_if.h"
32
1/*-
2 * Copyright (c) 1999 Cameron Grant <cg@freebsd.org>
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
27#include <dev/sound/pcm/sound.h>
28#include <dev/sound/pcm/ac97.h>
29#include <dev/sound/pcm/ac97_patch.h>
30
31#include "mixer_if.h"
32
33SND_DECLARE_FILE("$FreeBSD: head/sys/dev/sound/pcm/ac97.c 153865 2005-12-30 01:06:29Z ariff $");
33SND_DECLARE_FILE("$FreeBSD: head/sys/dev/sound/pcm/ac97.c 154094 2006-01-07 05:20:46Z ariff $");
34
35MALLOC_DEFINE(M_AC97, "ac97", "ac97 codec");
36
37struct ac97mixtable_entry {
38 int reg:8; /* register index */
39 /* reg < 0 if inverted polarity */
40 unsigned bits:4; /* width of control field */
41 unsigned ofs:4; /* offset (only if stereo=0) */
42 unsigned stereo:1; /* set for stereo controls */
43 unsigned mute:1; /* bit15 is MUTE */
44 unsigned recidx:4; /* index in rec mux */
45 unsigned mask:1; /* use only masked bits */
46 unsigned enable:1; /* entry is enabled */
47};
48
49#define AC97_NAMELEN 16
50struct ac97_info {
51 kobj_t methods;
52 device_t dev;
53 void *devinfo;
54 u_int32_t id;
55 unsigned count, caps, se, extcaps, extid, extstat, noext:1;
56 u_int32_t flags;
57 struct ac97mixtable_entry mix[32];
58 char name[AC97_NAMELEN];
59 struct mtx *lock;
60};
61
62struct ac97_vendorid {
63 u_int32_t id;
64 const char *name;
65};
66
67struct ac97_codecid {
68 u_int32_t id;
69 u_int8_t stepmask;
70 u_int8_t noext:1;
71 char *name;
72 ac97_patch patch;
73};
74
75static const struct ac97mixtable_entry ac97mixtable_default[32] = {
76 /* [offset] reg bits of st mu re mk en */
77 [SOUND_MIXER_VOLUME] = { AC97_MIX_MASTER, 5, 0, 1, 1, 6, 0, 1 },
78 [SOUND_MIXER_OGAIN] = { AC97_MIX_AUXOUT, 5, 0, 1, 1, 0, 0, 0 },
79 [SOUND_MIXER_PHONEOUT] = { AC97_MIX_MONO, 5, 0, 0, 1, 7, 0, 0 },
80 [SOUND_MIXER_BASS] = { AC97_MIX_TONE, 4, 8, 0, 0, 0, 1, 0 },
81 [SOUND_MIXER_TREBLE] = { AC97_MIX_TONE, 4, 0, 0, 0, 0, 1, 0 },
82 [SOUND_MIXER_PCM] = { AC97_MIX_PCM, 5, 0, 1, 1, 0, 0, 1 },
83 [SOUND_MIXER_SPEAKER] = { AC97_MIX_BEEP, 4, 1, 0, 1, 0, 0, 0 },
84 [SOUND_MIXER_LINE] = { AC97_MIX_LINE, 5, 0, 1, 1, 5, 0, 1 },
85 [SOUND_MIXER_PHONEIN] = { AC97_MIX_PHONE, 5, 0, 0, 1, 8, 0, 0 },
86 [SOUND_MIXER_MIC] = { AC97_MIX_MIC, 5, 0, 0, 1, 1, 1, 1 },
87 /* use igain for the mic 20dB boost */
88 [SOUND_MIXER_IGAIN] = { -AC97_MIX_MIC, 1, 6, 0, 0, 0, 1, 1 },
89 [SOUND_MIXER_CD] = { AC97_MIX_CD, 5, 0, 1, 1, 2, 0, 1 },
90 [SOUND_MIXER_LINE1] = { AC97_MIX_AUX, 5, 0, 1, 1, 4, 0, 0 },
91 [SOUND_MIXER_VIDEO] = { AC97_MIX_VIDEO, 5, 0, 1, 1, 3, 0, 0 },
92 [SOUND_MIXER_RECLEV] = { -AC97_MIX_RGAIN, 4, 0, 1, 1, 0, 0, 1 }
93};
94
95static const struct ac97_vendorid ac97vendorid[] = {
96 { 0x41445300, "Analog Devices" },
97 { 0x414b4d00, "Asahi Kasei" },
98 { 0x414c4300, "Realtek" },
99 { 0x414c4700, "Avance Logic" },
100 { 0x43525900, "Cirrus Logic" },
101 { 0x434d4900, "C-Media Electronics" },
102 { 0x43585400, "Conexant" },
103 { 0x44543000, "Diamond Technology" },
104 { 0x454d4300, "eMicro" },
105 { 0x45838300, "ESS Technology" },
106 { 0x48525300, "Intersil" },
107 { 0x49434500, "ICEnsemble" },
108 { 0x49544500, "ITE, Inc." },
109 { 0x4e534300, "National Semiconductor" },
110 { 0x50534300, "Philips Semiconductor" },
111 { 0x83847600, "SigmaTel" },
112 { 0x53494c00, "Silicon Laboratories" },
113 { 0x54524100, "TriTech" },
114 { 0x54584e00, "Texas Instruments" },
115 { 0x56494100, "VIA Technologies" },
116 { 0x57454300, "Winbond" },
117 { 0x574d4c00, "Wolfson" },
118 { 0x594d4800, "Yamaha" },
119 /*
120 * XXX This is a fluke, really! The real vendor
121 * should be SigmaTel, not this! This should be
122 * removed someday!
123 */
124 { 0x01408300, "Creative" },
125 { 0x00000000, NULL }
126};
127
128static struct ac97_codecid ac97codecid[] = {
129 { 0x41445303, 0x00, 0, "AD1819", 0 },
130 { 0x41445340, 0x00, 0, "AD1881", 0 },
131 { 0x41445348, 0x00, 0, "AD1881A", 0 },
132 { 0x41445360, 0x00, 0, "AD1885", 0 },
133 { 0x41445361, 0x00, 0, "AD1886", ad1886_patch },
134 { 0x41445362, 0x00, 0, "AD1887", 0 },
135 { 0x41445363, 0x00, 0, "AD1886A", 0 },
136 { 0x41445368, 0x00, 0, "AD1888", ad198x_patch },
137 { 0x41445370, 0x00, 0, "AD1980", ad198x_patch },
138 { 0x41445372, 0x00, 0, "AD1981A", 0 },
139 { 0x41445374, 0x00, 0, "AD1981B", 0 },
140 { 0x41445375, 0x00, 0, "AD1985", ad198x_patch },
34
35MALLOC_DEFINE(M_AC97, "ac97", "ac97 codec");
36
37struct ac97mixtable_entry {
38 int reg:8; /* register index */
39 /* reg < 0 if inverted polarity */
40 unsigned bits:4; /* width of control field */
41 unsigned ofs:4; /* offset (only if stereo=0) */
42 unsigned stereo:1; /* set for stereo controls */
43 unsigned mute:1; /* bit15 is MUTE */
44 unsigned recidx:4; /* index in rec mux */
45 unsigned mask:1; /* use only masked bits */
46 unsigned enable:1; /* entry is enabled */
47};
48
49#define AC97_NAMELEN 16
50struct ac97_info {
51 kobj_t methods;
52 device_t dev;
53 void *devinfo;
54 u_int32_t id;
55 unsigned count, caps, se, extcaps, extid, extstat, noext:1;
56 u_int32_t flags;
57 struct ac97mixtable_entry mix[32];
58 char name[AC97_NAMELEN];
59 struct mtx *lock;
60};
61
62struct ac97_vendorid {
63 u_int32_t id;
64 const char *name;
65};
66
67struct ac97_codecid {
68 u_int32_t id;
69 u_int8_t stepmask;
70 u_int8_t noext:1;
71 char *name;
72 ac97_patch patch;
73};
74
75static const struct ac97mixtable_entry ac97mixtable_default[32] = {
76 /* [offset] reg bits of st mu re mk en */
77 [SOUND_MIXER_VOLUME] = { AC97_MIX_MASTER, 5, 0, 1, 1, 6, 0, 1 },
78 [SOUND_MIXER_OGAIN] = { AC97_MIX_AUXOUT, 5, 0, 1, 1, 0, 0, 0 },
79 [SOUND_MIXER_PHONEOUT] = { AC97_MIX_MONO, 5, 0, 0, 1, 7, 0, 0 },
80 [SOUND_MIXER_BASS] = { AC97_MIX_TONE, 4, 8, 0, 0, 0, 1, 0 },
81 [SOUND_MIXER_TREBLE] = { AC97_MIX_TONE, 4, 0, 0, 0, 0, 1, 0 },
82 [SOUND_MIXER_PCM] = { AC97_MIX_PCM, 5, 0, 1, 1, 0, 0, 1 },
83 [SOUND_MIXER_SPEAKER] = { AC97_MIX_BEEP, 4, 1, 0, 1, 0, 0, 0 },
84 [SOUND_MIXER_LINE] = { AC97_MIX_LINE, 5, 0, 1, 1, 5, 0, 1 },
85 [SOUND_MIXER_PHONEIN] = { AC97_MIX_PHONE, 5, 0, 0, 1, 8, 0, 0 },
86 [SOUND_MIXER_MIC] = { AC97_MIX_MIC, 5, 0, 0, 1, 1, 1, 1 },
87 /* use igain for the mic 20dB boost */
88 [SOUND_MIXER_IGAIN] = { -AC97_MIX_MIC, 1, 6, 0, 0, 0, 1, 1 },
89 [SOUND_MIXER_CD] = { AC97_MIX_CD, 5, 0, 1, 1, 2, 0, 1 },
90 [SOUND_MIXER_LINE1] = { AC97_MIX_AUX, 5, 0, 1, 1, 4, 0, 0 },
91 [SOUND_MIXER_VIDEO] = { AC97_MIX_VIDEO, 5, 0, 1, 1, 3, 0, 0 },
92 [SOUND_MIXER_RECLEV] = { -AC97_MIX_RGAIN, 4, 0, 1, 1, 0, 0, 1 }
93};
94
95static const struct ac97_vendorid ac97vendorid[] = {
96 { 0x41445300, "Analog Devices" },
97 { 0x414b4d00, "Asahi Kasei" },
98 { 0x414c4300, "Realtek" },
99 { 0x414c4700, "Avance Logic" },
100 { 0x43525900, "Cirrus Logic" },
101 { 0x434d4900, "C-Media Electronics" },
102 { 0x43585400, "Conexant" },
103 { 0x44543000, "Diamond Technology" },
104 { 0x454d4300, "eMicro" },
105 { 0x45838300, "ESS Technology" },
106 { 0x48525300, "Intersil" },
107 { 0x49434500, "ICEnsemble" },
108 { 0x49544500, "ITE, Inc." },
109 { 0x4e534300, "National Semiconductor" },
110 { 0x50534300, "Philips Semiconductor" },
111 { 0x83847600, "SigmaTel" },
112 { 0x53494c00, "Silicon Laboratories" },
113 { 0x54524100, "TriTech" },
114 { 0x54584e00, "Texas Instruments" },
115 { 0x56494100, "VIA Technologies" },
116 { 0x57454300, "Winbond" },
117 { 0x574d4c00, "Wolfson" },
118 { 0x594d4800, "Yamaha" },
119 /*
120 * XXX This is a fluke, really! The real vendor
121 * should be SigmaTel, not this! This should be
122 * removed someday!
123 */
124 { 0x01408300, "Creative" },
125 { 0x00000000, NULL }
126};
127
128static struct ac97_codecid ac97codecid[] = {
129 { 0x41445303, 0x00, 0, "AD1819", 0 },
130 { 0x41445340, 0x00, 0, "AD1881", 0 },
131 { 0x41445348, 0x00, 0, "AD1881A", 0 },
132 { 0x41445360, 0x00, 0, "AD1885", 0 },
133 { 0x41445361, 0x00, 0, "AD1886", ad1886_patch },
134 { 0x41445362, 0x00, 0, "AD1887", 0 },
135 { 0x41445363, 0x00, 0, "AD1886A", 0 },
136 { 0x41445368, 0x00, 0, "AD1888", ad198x_patch },
137 { 0x41445370, 0x00, 0, "AD1980", ad198x_patch },
138 { 0x41445372, 0x00, 0, "AD1981A", 0 },
139 { 0x41445374, 0x00, 0, "AD1981B", 0 },
140 { 0x41445375, 0x00, 0, "AD1985", ad198x_patch },
141 { 0x41445378, 0x00, 0, "AD1986", ad198x_patch },
141 { 0x414b4d00, 0x00, 1, "AK4540", 0 },
142 { 0x414b4d01, 0x00, 1, "AK4542", 0 },
143 { 0x414b4d02, 0x00, 1, "AK4543", 0 },
144 { 0x414b4d06, 0x00, 0, "AK4544A", 0 },
145 { 0x454b4d07, 0x00, 0, "AK4545", 0 },
146 { 0x414c4320, 0x0f, 0, "ALC100", 0 },
147 { 0x414c4730, 0x0f, 0, "ALC101", 0 },
148 { 0x414c4710, 0x0f, 0, "ALC200", 0 },
149 { 0x414c4740, 0x0f, 0, "ALC202", 0 },
150 { 0x414c4720, 0x0f, 0, "ALC650", 0 },
151 { 0x414c4752, 0x0f, 0, "ALC250", 0 },
152 { 0x414c4760, 0x0f, 0, "ALC655", 0 },
153 { 0x414c4770, 0x0f, 0, "ALC203", 0 },
154 { 0x414c4780, 0x0f, 0, "ALC658", 0 },
155 { 0x414c4790, 0x0f, 0, "ALC850", 0 },
156 { 0x43525900, 0x07, 0, "CS4297", 0 },
157 { 0x43525910, 0x07, 0, "CS4297A", 0 },
158 { 0x43525920, 0x07, 0, "CS4294/98", 0 },
159 { 0x4352592d, 0x07, 0, "CS4294", 0 },
160 { 0x43525930, 0x07, 0, "CS4299", 0 },
161 { 0x43525940, 0x07, 0, "CS4201", 0 },
162 { 0x43525958, 0x07, 0, "CS4205", 0 },
163 { 0x43525960, 0x07, 0, "CS4291A", 0 },
164 { 0x434d4961, 0x00, 0, "CMI9739", cmi9739_patch },
165 { 0x434d4941, 0x00, 0, "CMI9738", 0 },
166 { 0x434d4978, 0x00, 0, "CMI9761", 0 },
167 { 0x434d4982, 0x00, 0, "CMI9761", 0 },
168 { 0x434d4983, 0x00, 0, "CMI9761", 0 },
169 { 0x43585421, 0x00, 0, "HSD11246", 0 },
170 { 0x43585428, 0x07, 0, "CX20468", 0 },
171 { 0x43585430, 0x00, 0, "CX20468-21", 0 },
172 { 0x44543000, 0x00, 0, "DT0398", 0 },
173 { 0x454d4323, 0x00, 0, "EM28023", 0 },
174 { 0x454d4328, 0x00, 0, "EM28028", 0 },
175 { 0x45838308, 0x00, 0, "ES1988", 0 }, /* Formerly ES1921(?) */
176 { 0x48525300, 0x00, 0, "HMP9701", 0 },
177 { 0x49434501, 0x00, 0, "ICE1230", 0 },
178 { 0x49434511, 0x00, 0, "ICE1232", 0 },
179 { 0x49434514, 0x00, 0, "ICE1232A", 0 },
180 { 0x49434551, 0x03, 0, "VT1616", 0 }, /* Via badged ICE */
181 { 0x49544520, 0x00, 0, "ITE2226E", 0 },
182 { 0x49544560, 0x07, 0, "ITE2646E", 0 }, /* XXX: patch needed */
183 { 0x4e534340, 0x00, 0, "LM4540", 0 }, /* Spec blank on revid */
184 { 0x4e534343, 0x00, 0, "LM4543", 0 }, /* Ditto */
185 { 0x4e534346, 0x00, 0, "LM4546A", 0 },
186 { 0x4e534348, 0x00, 0, "LM4548A", 0 },
187 { 0x4e534331, 0x00, 0, "LM4549", 0 },
188 { 0x4e534349, 0x00, 0, "LM4549A", 0 },
189 { 0x4e534350, 0x00, 0, "LM4550", 0 },
190 { 0x50534301, 0x00, 0, "UCB1510", 0 },
191 { 0x50534304, 0x00, 0, "UCB1400", 0 },
192 { 0x83847600, 0x00, 0, "STAC9700/83/84", 0 },
193 { 0x83847604, 0x00, 0, "STAC9701/03/04/05", 0 },
194 { 0x83847605, 0x00, 0, "STAC9704", 0 },
195 { 0x83847608, 0x00, 0, "STAC9708/11", 0 },
196 { 0x83847609, 0x00, 0, "STAC9721/23", 0 },
197 { 0x83847644, 0x00, 0, "STAC9744/45", 0 },
198 { 0x83847650, 0x00, 0, "STAC9750/51", 0 },
199 { 0x83847652, 0x00, 0, "STAC9752/53", 0 },
200 { 0x83847656, 0x00, 0, "STAC9756/57", 0 },
201 { 0x83847658, 0x00, 0, "STAC9758/59", 0 },
202 { 0x83847660, 0x00, 0, "STAC9760/61", 0 }, /* Extrapolated */
203 { 0x83847662, 0x00, 0, "STAC9762/63", 0 }, /* Extrapolated */
204 { 0x83847666, 0x00, 0, "STAC9766/67", 0 },
205 { 0x53494c22, 0x00, 0, "Si3036", 0 },
206 { 0x53494c23, 0x00, 0, "Si3038", 0 },
207 { 0x54524103, 0x00, 0, "TR28023", 0 }, /* Extrapolated */
208 { 0x54524106, 0x00, 0, "TR28026", 0 },
209 { 0x54524108, 0x00, 0, "TR28028", 0 },
210 { 0x54524123, 0x00, 0, "TR28602", 0 },
211 { 0x54524e03, 0x07, 0, "TLV320AIC27", 0 },
212 { 0x54584e20, 0x00, 0, "TLC320AD90", 0 },
213 { 0x56494161, 0x00, 0, "VIA1612A", 0 },
214 { 0x56494170, 0x00, 0, "VIA1617A", 0 },
215 { 0x574d4c00, 0x00, 0, "WM9701A", 0 },
216 { 0x574d4c03, 0x00, 0, "WM9703/4/7/8", 0 },
217 { 0x574d4c04, 0x00, 0, "WM9704Q", 0 },
218 { 0x574d4c05, 0x00, 0, "WM9705/10", 0 },
219 { 0x574d4d09, 0x00, 0, "WM9709", 0 },
220 { 0x574d4c12, 0x00, 0, "WM9711/12", 0 }, /* XXX: patch needed */
221 { 0x57454301, 0x00, 0, "W83971D", 0 },
222 { 0x594d4800, 0x00, 0, "YMF743", 0 },
223 { 0x594d4802, 0x00, 0, "YMF752", 0 },
224 { 0x594d4803, 0x00, 0, "YMF753", 0 },
225 /*
226 * XXX This is a fluke, really! The real codec
227 * should be STAC9704, not this! This should be
228 * removed someday!
229 */
230 { 0x01408384, 0x00, 0, "EV1938", 0 },
231 { 0, 0, 0, NULL, 0 }
232};
233
234static char *ac97enhancement[] = {
235 "no 3D Stereo Enhancement",
236 "Analog Devices Phat Stereo",
237 "Creative Stereo Enhancement",
238 "National Semi 3D Stereo Enhancement",
239 "Yamaha Ymersion",
240 "BBE 3D Stereo Enhancement",
241 "Crystal Semi 3D Stereo Enhancement",
242 "Qsound QXpander",
243 "Spatializer 3D Stereo Enhancement",
244 "SRS 3D Stereo Enhancement",
245 "Platform Tech 3D Stereo Enhancement",
246 "AKM 3D Audio",
247 "Aureal Stereo Enhancement",
248 "Aztech 3D Enhancement",
249 "Binaura 3D Audio Enhancement",
250 "ESS Technology Stereo Enhancement",
251 "Harman International VMAx",
252 "Nvidea 3D Stereo Enhancement",
253 "Philips Incredible Sound",
254 "Texas Instruments 3D Stereo Enhancement",
255 "VLSI Technology 3D Stereo Enhancement",
256 "TriTech 3D Stereo Enhancement",
257 "Realtek 3D Stereo Enhancement",
258 "Samsung 3D Stereo Enhancement",
259 "Wolfson Microelectronics 3D Enhancement",
260 "Delta Integration 3D Enhancement",
261 "SigmaTel 3D Enhancement",
262 "Reserved 27",
263 "Rockwell 3D Stereo Enhancement",
264 "Reserved 29",
265 "Reserved 30",
266 "Reserved 31"
267};
268
269static char *ac97feature[] = {
270 "mic channel",
271 "reserved",
272 "tone",
273 "simulated stereo",
274 "headphone",
275 "bass boost",
276 "18 bit DAC",
277 "20 bit DAC",
278 "18 bit ADC",
279 "20 bit ADC"
280};
281
282static char *ac97extfeature[] = {
283 "variable rate PCM",
284 "double rate PCM",
285 "reserved 1",
286 "variable rate mic",
287 "reserved 2",
288 "reserved 3",
289 "center DAC",
290 "surround DAC",
291 "LFE DAC",
292 "AMAP",
293 "reserved 4",
294 "reserved 5",
295 "reserved 6",
296 "reserved 7",
297};
298
299u_int16_t
300ac97_rdcd(struct ac97_info *codec, int reg)
301{
302 if (codec->flags & AC97_F_RDCD_BUG) {
303 u_int16_t i[2], j = 100;
304
305 i[0] = AC97_READ(codec->methods, codec->devinfo, reg);
306 i[1] = AC97_READ(codec->methods, codec->devinfo, reg);
307 while (i[0] != i[1] && j)
308 i[j-- & 1] = AC97_READ(codec->methods, codec->devinfo, reg);
309#if 0
310 if (j < 100) {
311 device_printf(codec->dev, "%s(): Inconsistent register value at"
312 " 0x%08x (retry: %d)\n", __func__, reg, 100 - j);
313 }
314#endif
315 return i[!(j & 1)];
316 }
317 return AC97_READ(codec->methods, codec->devinfo, reg);
318}
319
320void
321ac97_wrcd(struct ac97_info *codec, int reg, u_int16_t val)
322{
323 AC97_WRITE(codec->methods, codec->devinfo, reg, val);
324}
325
326static void
327ac97_reset(struct ac97_info *codec)
328{
329 u_int32_t i, ps;
330 ac97_wrcd(codec, AC97_REG_RESET, 0);
331 for (i = 0; i < 500; i++) {
332 ps = ac97_rdcd(codec, AC97_REG_POWER) & AC97_POWER_STATUS;
333 if (ps == AC97_POWER_STATUS)
334 return;
335 DELAY(1000);
336 }
337 device_printf(codec->dev, "AC97 reset timed out.\n");
338}
339
340int
341ac97_setrate(struct ac97_info *codec, int which, int rate)
342{
343 u_int16_t v;
344
345 switch(which) {
346 case AC97_REGEXT_FDACRATE:
347 case AC97_REGEXT_SDACRATE:
348 case AC97_REGEXT_LDACRATE:
349 case AC97_REGEXT_LADCRATE:
350 case AC97_REGEXT_MADCRATE:
351 break;
352
353 default:
354 return -1;
355 }
356
357 snd_mtxlock(codec->lock);
358 if (rate != 0) {
359 v = rate;
360 if (codec->extstat & AC97_EXTCAP_DRA)
361 v >>= 1;
362 ac97_wrcd(codec, which, v);
363 }
364 v = ac97_rdcd(codec, which);
365 if (codec->extstat & AC97_EXTCAP_DRA)
366 v <<= 1;
367 snd_mtxunlock(codec->lock);
368 return v;
369}
370
371int
372ac97_setextmode(struct ac97_info *codec, u_int16_t mode)
373{
374 mode &= AC97_EXTCAPS;
375 if ((mode & ~codec->extcaps) != 0) {
376 device_printf(codec->dev, "ac97 invalid mode set 0x%04x\n",
377 mode);
378 return -1;
379 }
380 snd_mtxlock(codec->lock);
381 ac97_wrcd(codec, AC97_REGEXT_STAT, mode);
382 codec->extstat = ac97_rdcd(codec, AC97_REGEXT_STAT) & AC97_EXTCAPS;
383 snd_mtxunlock(codec->lock);
384 return (mode == codec->extstat)? 0 : -1;
385}
386
387u_int16_t
388ac97_getextmode(struct ac97_info *codec)
389{
390 return codec->extstat;
391}
392
393u_int16_t
394ac97_getextcaps(struct ac97_info *codec)
395{
396 return codec->extcaps;
397}
398
399u_int16_t
400ac97_getcaps(struct ac97_info *codec)
401{
402 return codec->caps;
403}
404
405static int
406ac97_setrecsrc(struct ac97_info *codec, int channel)
407{
408 struct ac97mixtable_entry *e = &codec->mix[channel];
409
410 if (e->recidx > 0) {
411 int val = e->recidx - 1;
412 val |= val << 8;
413 snd_mtxlock(codec->lock);
414 ac97_wrcd(codec, AC97_REG_RECSEL, val);
415 snd_mtxunlock(codec->lock);
416 return 0;
417 } else
418 return -1;
419}
420
421static int
422ac97_setmixer(struct ac97_info *codec, unsigned channel, unsigned left, unsigned right)
423{
424 struct ac97mixtable_entry *e = &codec->mix[channel];
425
426 if (e->reg && e->enable && e->bits) {
427 int mask, max, val, reg;
428
429 reg = (e->reg >= 0) ? e->reg : -e->reg; /* AC97 register */
430 max = (1 << e->bits) - 1; /* actual range */
431 mask = (max << 8) | max; /* bits of interest */
432
433 if (!e->stereo)
434 right = left;
435
436 /*
437 * Invert the range if the polarity requires so,
438 * then scale to 0..max-1 to compute the value to
439 * write into the codec, and scale back to 0..100
440 * for the return value.
441 */
442 if (e->reg > 0) {
443 left = 100 - left;
444 right = 100 - right;
445 }
446
447 left = (left * max) / 100;
448 right = (right * max) / 100;
449
450 val = (left << 8) | right;
451
452 left = (left * 100) / max;
453 right = (right * 100) / max;
454
455 if (e->reg > 0) {
456 left = 100 - left;
457 right = 100 - right;
458 }
459
460 /*
461 * For mono controls, trim val and mask, also taking
462 * care of e->ofs (offset of control field).
463 */
464 if (e->ofs) {
465 val &= max;
466 val <<= e->ofs;
467 mask = (max << e->ofs);
468 }
469
470 /*
471 * If we have a mute bit, add it to the mask and
472 * update val and set mute if both channels require a
473 * zero volume.
474 */
475 if (e->mute == 1) {
476 mask |= AC97_MUTE;
477 if (left == 0 && right == 0)
478 val = AC97_MUTE;
479 }
480
481 /*
482 * If the mask bit is set, do not alter the other bits.
483 */
484 snd_mtxlock(codec->lock);
485 if (e->mask) {
486 int cur = ac97_rdcd(codec, reg);
487 val |= cur & ~(mask);
488 }
489 ac97_wrcd(codec, reg, val);
490 snd_mtxunlock(codec->lock);
491 return left | (right << 8);
492 } else {
493#if 0
494 printf("ac97_setmixer: reg=%d, bits=%d, enable=%d\n", e->reg, e->bits, e->enable);
495#endif
496 return -1;
497 }
498}
499
500static void
501ac97_fix_auxout(struct ac97_info *codec)
502{
503 int keep_ogain;
504
505 /*
506 * By default, The ac97 aux_out register (0x04) corresponds to OSS's
507 * OGAIN setting.
508 *
509 * We first check whether aux_out is a valid register. If not
510 * we may not want to keep ogain.
511 */
512 keep_ogain = ac97_rdcd(codec, AC97_MIX_AUXOUT) & 0x8000;
513
514 /*
515 * Determine what AUX_OUT really means, it can be:
516 *
517 * 1. Headphone out.
518 * 2. 4-Channel Out
519 * 3. True line level out (effectively master volume).
520 *
521 * See Sections 5.2.1 and 5.27 for AUX_OUT Options in AC97r2.{2,3}.
522 */
523 if (codec->extcaps & AC97_EXTCAP_SDAC &&
524 ac97_rdcd(codec, AC97_MIXEXT_SURROUND) == 0x8080) {
525 codec->mix[SOUND_MIXER_OGAIN].reg = AC97_MIXEXT_SURROUND;
526 keep_ogain = 1;
527 }
528
529 if (keep_ogain == 0) {
530 bzero(&codec->mix[SOUND_MIXER_OGAIN],
531 sizeof(codec->mix[SOUND_MIXER_OGAIN]));
532 }
533}
534
535static void
536ac97_fix_tone(struct ac97_info *codec)
537{
538 /* Hide treble and bass if they don't exist */
539 if ((codec->caps & AC97_CAP_TONE) == 0) {
540 bzero(&codec->mix[SOUND_MIXER_BASS],
541 sizeof(codec->mix[SOUND_MIXER_BASS]));
542 bzero(&codec->mix[SOUND_MIXER_TREBLE],
543 sizeof(codec->mix[SOUND_MIXER_TREBLE]));
544 }
545}
546
547static void
548ac97_fix_volume(struct ac97_info *codec)
549{
550 struct snddev_info *d = device_get_softc(codec->dev);
551
552#if 0
553 /* XXX For the sake of debugging purposes */
554 ac97_wrcd(codec, AC97_MIX_PCM, 0);
555 bzero(&codec->mix[SOUND_MIXER_PCM],
556 sizeof(codec->mix[SOUND_MIXER_PCM]));
557 codec->flags |= AC97_F_SOFTVOL;
558 if (d)
559 d->flags |= SD_F_SOFTVOL;
560 return;
561#endif
562 switch (codec->id) {
563 case 0x434d4941: /* CMI9738 */
564 case 0x434d4961: /* CMI9739 */
565 case 0x434d4978: /* CMI9761 */
566 case 0x434d4982: /* CMI9761 */
567 case 0x434d4983: /* CMI9761 */
568 ac97_wrcd(codec, AC97_MIX_PCM, 0);
569 break;
570 default:
571 return;
572 break;
573 }
574 bzero(&codec->mix[SOUND_MIXER_PCM],
575 sizeof(codec->mix[SOUND_MIXER_PCM]));
576 codec->flags |= AC97_F_SOFTVOL;
577 if (d)
578 d->flags |= SD_F_SOFTVOL;
579}
580
581static const char*
582ac97_hw_desc(u_int32_t id, const char* vname, const char* cname, char* buf)
583{
584 if (cname == NULL) {
585 sprintf(buf, "Unknown AC97 Codec (id = 0x%08x)", id);
586 return buf;
587 }
588
589 if (vname == NULL) vname = "Unknown";
590
591 if (bootverbose) {
592 sprintf(buf, "%s %s AC97 Codec (id = 0x%08x)", vname, cname, id);
593 } else {
594 sprintf(buf, "%s %s AC97 Codec", vname, cname);
595 }
596 return buf;
597}
598
599static unsigned
600ac97_initmixer(struct ac97_info *codec)
601{
602 ac97_patch codec_patch;
603 const char *cname, *vname;
604 char desc[80];
605 u_int8_t model, step;
606 unsigned i, j, k, bit, old;
607 u_int32_t id;
608 int reg;
609
610 snd_mtxlock(codec->lock);
611 codec->count = AC97_INIT(codec->methods, codec->devinfo);
612 if (codec->count == 0) {
613 device_printf(codec->dev, "ac97 codec init failed\n");
614 snd_mtxunlock(codec->lock);
615 return ENODEV;
616 }
617
618 ac97_wrcd(codec, AC97_REG_POWER, (codec->flags & AC97_F_EAPD_INV)? 0x8000 : 0x0000);
619 ac97_reset(codec);
620 ac97_wrcd(codec, AC97_REG_POWER, (codec->flags & AC97_F_EAPD_INV)? 0x8000 : 0x0000);
621
622 i = ac97_rdcd(codec, AC97_REG_RESET);
623 j = ac97_rdcd(codec, AC97_REG_RESET);
624 /*
625 * Let see if this codec can return consistent value.
626 * If not, turn on aggressive read workaround
627 * (STAC9704 comes in mind).
628 */
629 if (i != j) {
630 codec->flags |= AC97_F_RDCD_BUG;
631 i = ac97_rdcd(codec, AC97_REG_RESET);
632 }
633 codec->caps = i & 0x03ff;
634 codec->se = (i & 0x7c00) >> 10;
635
636 id = (ac97_rdcd(codec, AC97_REG_ID1) << 16) | ac97_rdcd(codec, AC97_REG_ID2);
637 if (id == 0 || id == 0xffffffff) {
638 device_printf(codec->dev, "ac97 codec invalid or not present (id == %x)\n", id);
639 snd_mtxunlock(codec->lock);
640 return ENODEV;
641 }
642
643 codec->id = id;
644 codec->noext = 0;
645 codec_patch = NULL;
646
647 cname = NULL;
648 model = step = 0;
649 for (i = 0; ac97codecid[i].id; i++) {
650 u_int32_t modelmask = 0xffffffff ^ ac97codecid[i].stepmask;
651 if ((ac97codecid[i].id & modelmask) == (id & modelmask)) {
652 codec->noext = ac97codecid[i].noext;
653 codec_patch = ac97codecid[i].patch;
654 cname = ac97codecid[i].name;
655 model = (id & modelmask) & 0xff;
656 step = (id & ~modelmask) & 0xff;
657 break;
658 }
659 }
660
661 vname = NULL;
662 for (i = 0; ac97vendorid[i].id; i++) {
663 if (ac97vendorid[i].id == (id & 0xffffff00)) {
664 vname = ac97vendorid[i].name;
665 break;
666 }
667 }
668
669 codec->extcaps = 0;
670 codec->extid = 0;
671 codec->extstat = 0;
672 if (!codec->noext) {
673 i = ac97_rdcd(codec, AC97_REGEXT_ID);
674 if (i != 0xffff) {
675 codec->extcaps = i & 0x3fff;
676 codec->extid = (i & 0xc000) >> 14;
677 codec->extstat = ac97_rdcd(codec, AC97_REGEXT_STAT) & AC97_EXTCAPS;
678 }
679 }
680
681 for (i = 0; i < 32; i++) {
682 codec->mix[i] = ac97mixtable_default[i];
683 }
684 ac97_fix_auxout(codec);
685 ac97_fix_tone(codec);
686 ac97_fix_volume(codec);
687 if (codec_patch)
688 codec_patch(codec);
689
690 for (i = 0; i < 32; i++) {
691 k = codec->noext? codec->mix[i].enable : 1;
692 reg = codec->mix[i].reg;
693 if (reg < 0)
694 reg = -reg;
695 if (k && reg) {
696 j = old = ac97_rdcd(codec, reg);
697 /*
698 * Test for mute bit (except for AC97_MIX_TONE,
699 * where we simply assume it as available).
700 */
701 if (codec->mix[i].mute) {
702 ac97_wrcd(codec, reg, j | 0x8000);
703 j = ac97_rdcd(codec, reg);
704 } else
705 j |= 0x8000;
706 if ((j & 0x8000)) {
707 /*
708 * Test whether the control width should be
709 * 4, 5 or 6 bit. For 5bit register, we should
710 * test it whether it's really 5 or 6bit. Leave
711 * 4bit register alone, because sometimes an
712 * attempt to write past 4th bit may cause
713 * incorrect result especially for AC97_MIX_BEEP
714 * (ac97 2.3).
715 */
716 bit = codec->mix[i].bits;
717 if (bit == 5)
718 bit++;
719 j = ((1 << bit) - 1) << codec->mix[i].ofs;
720 ac97_wrcd(codec, reg,
721 j | (codec->mix[i].mute ? 0x8000 : 0));
722 k = ac97_rdcd(codec, reg) & j;
723 k >>= codec->mix[i].ofs;
724 if (reg == AC97_MIX_TONE &&
725 ((k & 0x0001) == 0x0000))
726 k >>= 1;
727 for (j = 0; k >> j; j++)
728 ;
729 if (j != 0) {
730#if 0
731 device_printf(codec->dev, "%2d: [ac97_rdcd() = %d] [Testbit = %d] %d -> %d\n",
732 i, k, bit, codec->mix[i].bits, j);
733#endif
734 codec->mix[i].enable = 1;
735 codec->mix[i].bits = j;
736 } else if (reg == AC97_MIX_BEEP) {
737 /*
738 * Few codec such as CX20468-21 does
739 * have this control register, although
740 * the only usable part is the mute bit.
741 */
742 codec->mix[i].enable = 1;
743 } else
744 codec->mix[i].enable = 0;
745 } else
746 codec->mix[i].enable = 0;
747 ac97_wrcd(codec, reg, old);
748 }
749#if 0
750 printf("mixch %d, en=%d, b=%d\n", i, codec->mix[i].enable, codec->mix[i].bits);
751#endif
752 }
753
754 device_printf(codec->dev, "<%s>\n",
755 ac97_hw_desc(codec->id, vname, cname, desc));
756
757 if (bootverbose) {
758 if (codec->flags & AC97_F_RDCD_BUG)
759 device_printf(codec->dev, "Buggy AC97 Codec: aggressive ac97_rdcd() workaround enabled\n");
760 if (codec->flags & AC97_F_SOFTVOL)
761 device_printf(codec->dev, "Soft PCM volume\n");
762 device_printf(codec->dev, "Codec features ");
763 for (i = j = 0; i < 10; i++)
764 if (codec->caps & (1 << i))
765 printf("%s%s", j++? ", " : "", ac97feature[i]);
766 printf("%s%d bit master volume", j++? ", " : "", codec->mix[SOUND_MIXER_VOLUME].bits);
767 printf("%s%s\n", j? ", " : "", ac97enhancement[codec->se]);
768
769 if (codec->extcaps != 0 || codec->extid) {
770 device_printf(codec->dev, "%s codec",
771 codec->extid? "Secondary" : "Primary");
772 if (codec->extcaps)
773 printf(" extended features ");
774 for (i = j = 0; i < 14; i++)
775 if (codec->extcaps & (1 << i))
776 printf("%s%s", j++? ", " : "", ac97extfeature[i]);
777 printf("\n");
778 }
779 }
780
781 i = 0;
782 while ((ac97_rdcd(codec, AC97_REG_POWER) & 2) == 0) {
783 if (++i == 100) {
784 device_printf(codec->dev, "ac97 codec reports dac not ready\n");
785 break;
786 }
787 DELAY(1000);
788 }
789 if (bootverbose)
790 device_printf(codec->dev, "ac97 codec dac ready count: %d\n", i);
791 snd_mtxunlock(codec->lock);
792 return 0;
793}
794
795static unsigned
796ac97_reinitmixer(struct ac97_info *codec)
797{
798 snd_mtxlock(codec->lock);
799 codec->count = AC97_INIT(codec->methods, codec->devinfo);
800 if (codec->count == 0) {
801 device_printf(codec->dev, "ac97 codec init failed\n");
802 snd_mtxunlock(codec->lock);
803 return ENODEV;
804 }
805
806 ac97_wrcd(codec, AC97_REG_POWER, (codec->flags & AC97_F_EAPD_INV)? 0x8000 : 0x0000);
807 ac97_reset(codec);
808 ac97_wrcd(codec, AC97_REG_POWER, (codec->flags & AC97_F_EAPD_INV)? 0x8000 : 0x0000);
809
810 if (!codec->noext) {
811 ac97_wrcd(codec, AC97_REGEXT_STAT, codec->extstat);
812 if ((ac97_rdcd(codec, AC97_REGEXT_STAT) & AC97_EXTCAPS)
813 != codec->extstat)
814 device_printf(codec->dev, "ac97 codec failed to reset extended mode (%x, got %x)\n",
815 codec->extstat,
816 ac97_rdcd(codec, AC97_REGEXT_STAT) &
817 AC97_EXTCAPS);
818 }
819
820 if ((ac97_rdcd(codec, AC97_REG_POWER) & 2) == 0)
821 device_printf(codec->dev, "ac97 codec reports dac not ready\n");
822 snd_mtxunlock(codec->lock);
823 return 0;
824}
825
826struct ac97_info *
827ac97_create(device_t dev, void *devinfo, kobj_class_t cls)
828{
829 struct ac97_info *codec;
830
831 codec = (struct ac97_info *)malloc(sizeof *codec, M_AC97, M_NOWAIT);
832 if (codec == NULL)
833 return NULL;
834
835 snprintf(codec->name, AC97_NAMELEN, "%s:ac97", device_get_nameunit(dev));
836 codec->lock = snd_mtxcreate(codec->name, "ac97 codec");
837 codec->methods = kobj_create(cls, M_AC97, M_WAITOK);
838 if (codec->methods == NULL) {
839 snd_mtxlock(codec->lock);
840 snd_mtxfree(codec->lock);
841 free(codec, M_AC97);
842 return NULL;
843 }
844
845 codec->dev = dev;
846 codec->devinfo = devinfo;
847 codec->flags = 0;
848 return codec;
849}
850
851void
852ac97_destroy(struct ac97_info *codec)
853{
854 snd_mtxlock(codec->lock);
855 if (codec->methods != NULL)
856 kobj_delete(codec->methods, M_AC97);
857 snd_mtxfree(codec->lock);
858 free(codec, M_AC97);
859}
860
861void
862ac97_setflags(struct ac97_info *codec, u_int32_t val)
863{
864 codec->flags = val;
865}
866
867u_int32_t
868ac97_getflags(struct ac97_info *codec)
869{
870 return codec->flags;
871}
872
873/* -------------------------------------------------------------------- */
874
875static int
876ac97mix_init(struct snd_mixer *m)
877{
878 struct ac97_info *codec = mix_getdevinfo(m);
879 u_int32_t i, mask;
880
881 if (codec == NULL)
882 return -1;
883
884 if (ac97_initmixer(codec))
885 return -1;
886
887 mask = 0;
888 for (i = 0; i < 32; i++)
889 mask |= codec->mix[i].enable? 1 << i : 0;
890 mix_setdevs(m, mask);
891
892 mask = 0;
893 for (i = 0; i < 32; i++)
894 mask |= codec->mix[i].recidx? 1 << i : 0;
895 mix_setrecdevs(m, mask);
896 return 0;
897}
898
899static int
900ac97mix_uninit(struct snd_mixer *m)
901{
902 struct ac97_info *codec = mix_getdevinfo(m);
903
904 if (codec == NULL)
905 return -1;
906 /*
907 if (ac97_uninitmixer(codec))
908 return -1;
909 */
910 ac97_destroy(codec);
911 return 0;
912}
913
914static int
915ac97mix_reinit(struct snd_mixer *m)
916{
917 struct ac97_info *codec = mix_getdevinfo(m);
918
919 if (codec == NULL)
920 return -1;
921 return ac97_reinitmixer(codec);
922}
923
924static int
925ac97mix_set(struct snd_mixer *m, unsigned dev, unsigned left, unsigned right)
926{
927 struct ac97_info *codec = mix_getdevinfo(m);
928
929 if (codec == NULL)
930 return -1;
931 return ac97_setmixer(codec, dev, left, right);
932}
933
934static int
935ac97mix_setrecsrc(struct snd_mixer *m, u_int32_t src)
936{
937 int i;
938 struct ac97_info *codec = mix_getdevinfo(m);
939
940 if (codec == NULL)
941 return -1;
942 for (i = 0; i < SOUND_MIXER_NRDEVICES; i++)
943 if ((src & (1 << i)) != 0)
944 break;
945 return (ac97_setrecsrc(codec, i) == 0)? 1 << i : -1;
946}
947
948static kobj_method_t ac97mixer_methods[] = {
949 KOBJMETHOD(mixer_init, ac97mix_init),
950 KOBJMETHOD(mixer_uninit, ac97mix_uninit),
951 KOBJMETHOD(mixer_reinit, ac97mix_reinit),
952 KOBJMETHOD(mixer_set, ac97mix_set),
953 KOBJMETHOD(mixer_setrecsrc, ac97mix_setrecsrc),
954 { 0, 0 }
955};
956MIXER_DECLARE(ac97mixer);
957
958/* -------------------------------------------------------------------- */
959
960kobj_class_t
961ac97_getmixerclass(void)
962{
963 return &ac97mixer_class;
964}
965
966
142 { 0x414b4d00, 0x00, 1, "AK4540", 0 },
143 { 0x414b4d01, 0x00, 1, "AK4542", 0 },
144 { 0x414b4d02, 0x00, 1, "AK4543", 0 },
145 { 0x414b4d06, 0x00, 0, "AK4544A", 0 },
146 { 0x454b4d07, 0x00, 0, "AK4545", 0 },
147 { 0x414c4320, 0x0f, 0, "ALC100", 0 },
148 { 0x414c4730, 0x0f, 0, "ALC101", 0 },
149 { 0x414c4710, 0x0f, 0, "ALC200", 0 },
150 { 0x414c4740, 0x0f, 0, "ALC202", 0 },
151 { 0x414c4720, 0x0f, 0, "ALC650", 0 },
152 { 0x414c4752, 0x0f, 0, "ALC250", 0 },
153 { 0x414c4760, 0x0f, 0, "ALC655", 0 },
154 { 0x414c4770, 0x0f, 0, "ALC203", 0 },
155 { 0x414c4780, 0x0f, 0, "ALC658", 0 },
156 { 0x414c4790, 0x0f, 0, "ALC850", 0 },
157 { 0x43525900, 0x07, 0, "CS4297", 0 },
158 { 0x43525910, 0x07, 0, "CS4297A", 0 },
159 { 0x43525920, 0x07, 0, "CS4294/98", 0 },
160 { 0x4352592d, 0x07, 0, "CS4294", 0 },
161 { 0x43525930, 0x07, 0, "CS4299", 0 },
162 { 0x43525940, 0x07, 0, "CS4201", 0 },
163 { 0x43525958, 0x07, 0, "CS4205", 0 },
164 { 0x43525960, 0x07, 0, "CS4291A", 0 },
165 { 0x434d4961, 0x00, 0, "CMI9739", cmi9739_patch },
166 { 0x434d4941, 0x00, 0, "CMI9738", 0 },
167 { 0x434d4978, 0x00, 0, "CMI9761", 0 },
168 { 0x434d4982, 0x00, 0, "CMI9761", 0 },
169 { 0x434d4983, 0x00, 0, "CMI9761", 0 },
170 { 0x43585421, 0x00, 0, "HSD11246", 0 },
171 { 0x43585428, 0x07, 0, "CX20468", 0 },
172 { 0x43585430, 0x00, 0, "CX20468-21", 0 },
173 { 0x44543000, 0x00, 0, "DT0398", 0 },
174 { 0x454d4323, 0x00, 0, "EM28023", 0 },
175 { 0x454d4328, 0x00, 0, "EM28028", 0 },
176 { 0x45838308, 0x00, 0, "ES1988", 0 }, /* Formerly ES1921(?) */
177 { 0x48525300, 0x00, 0, "HMP9701", 0 },
178 { 0x49434501, 0x00, 0, "ICE1230", 0 },
179 { 0x49434511, 0x00, 0, "ICE1232", 0 },
180 { 0x49434514, 0x00, 0, "ICE1232A", 0 },
181 { 0x49434551, 0x03, 0, "VT1616", 0 }, /* Via badged ICE */
182 { 0x49544520, 0x00, 0, "ITE2226E", 0 },
183 { 0x49544560, 0x07, 0, "ITE2646E", 0 }, /* XXX: patch needed */
184 { 0x4e534340, 0x00, 0, "LM4540", 0 }, /* Spec blank on revid */
185 { 0x4e534343, 0x00, 0, "LM4543", 0 }, /* Ditto */
186 { 0x4e534346, 0x00, 0, "LM4546A", 0 },
187 { 0x4e534348, 0x00, 0, "LM4548A", 0 },
188 { 0x4e534331, 0x00, 0, "LM4549", 0 },
189 { 0x4e534349, 0x00, 0, "LM4549A", 0 },
190 { 0x4e534350, 0x00, 0, "LM4550", 0 },
191 { 0x50534301, 0x00, 0, "UCB1510", 0 },
192 { 0x50534304, 0x00, 0, "UCB1400", 0 },
193 { 0x83847600, 0x00, 0, "STAC9700/83/84", 0 },
194 { 0x83847604, 0x00, 0, "STAC9701/03/04/05", 0 },
195 { 0x83847605, 0x00, 0, "STAC9704", 0 },
196 { 0x83847608, 0x00, 0, "STAC9708/11", 0 },
197 { 0x83847609, 0x00, 0, "STAC9721/23", 0 },
198 { 0x83847644, 0x00, 0, "STAC9744/45", 0 },
199 { 0x83847650, 0x00, 0, "STAC9750/51", 0 },
200 { 0x83847652, 0x00, 0, "STAC9752/53", 0 },
201 { 0x83847656, 0x00, 0, "STAC9756/57", 0 },
202 { 0x83847658, 0x00, 0, "STAC9758/59", 0 },
203 { 0x83847660, 0x00, 0, "STAC9760/61", 0 }, /* Extrapolated */
204 { 0x83847662, 0x00, 0, "STAC9762/63", 0 }, /* Extrapolated */
205 { 0x83847666, 0x00, 0, "STAC9766/67", 0 },
206 { 0x53494c22, 0x00, 0, "Si3036", 0 },
207 { 0x53494c23, 0x00, 0, "Si3038", 0 },
208 { 0x54524103, 0x00, 0, "TR28023", 0 }, /* Extrapolated */
209 { 0x54524106, 0x00, 0, "TR28026", 0 },
210 { 0x54524108, 0x00, 0, "TR28028", 0 },
211 { 0x54524123, 0x00, 0, "TR28602", 0 },
212 { 0x54524e03, 0x07, 0, "TLV320AIC27", 0 },
213 { 0x54584e20, 0x00, 0, "TLC320AD90", 0 },
214 { 0x56494161, 0x00, 0, "VIA1612A", 0 },
215 { 0x56494170, 0x00, 0, "VIA1617A", 0 },
216 { 0x574d4c00, 0x00, 0, "WM9701A", 0 },
217 { 0x574d4c03, 0x00, 0, "WM9703/4/7/8", 0 },
218 { 0x574d4c04, 0x00, 0, "WM9704Q", 0 },
219 { 0x574d4c05, 0x00, 0, "WM9705/10", 0 },
220 { 0x574d4d09, 0x00, 0, "WM9709", 0 },
221 { 0x574d4c12, 0x00, 0, "WM9711/12", 0 }, /* XXX: patch needed */
222 { 0x57454301, 0x00, 0, "W83971D", 0 },
223 { 0x594d4800, 0x00, 0, "YMF743", 0 },
224 { 0x594d4802, 0x00, 0, "YMF752", 0 },
225 { 0x594d4803, 0x00, 0, "YMF753", 0 },
226 /*
227 * XXX This is a fluke, really! The real codec
228 * should be STAC9704, not this! This should be
229 * removed someday!
230 */
231 { 0x01408384, 0x00, 0, "EV1938", 0 },
232 { 0, 0, 0, NULL, 0 }
233};
234
235static char *ac97enhancement[] = {
236 "no 3D Stereo Enhancement",
237 "Analog Devices Phat Stereo",
238 "Creative Stereo Enhancement",
239 "National Semi 3D Stereo Enhancement",
240 "Yamaha Ymersion",
241 "BBE 3D Stereo Enhancement",
242 "Crystal Semi 3D Stereo Enhancement",
243 "Qsound QXpander",
244 "Spatializer 3D Stereo Enhancement",
245 "SRS 3D Stereo Enhancement",
246 "Platform Tech 3D Stereo Enhancement",
247 "AKM 3D Audio",
248 "Aureal Stereo Enhancement",
249 "Aztech 3D Enhancement",
250 "Binaura 3D Audio Enhancement",
251 "ESS Technology Stereo Enhancement",
252 "Harman International VMAx",
253 "Nvidea 3D Stereo Enhancement",
254 "Philips Incredible Sound",
255 "Texas Instruments 3D Stereo Enhancement",
256 "VLSI Technology 3D Stereo Enhancement",
257 "TriTech 3D Stereo Enhancement",
258 "Realtek 3D Stereo Enhancement",
259 "Samsung 3D Stereo Enhancement",
260 "Wolfson Microelectronics 3D Enhancement",
261 "Delta Integration 3D Enhancement",
262 "SigmaTel 3D Enhancement",
263 "Reserved 27",
264 "Rockwell 3D Stereo Enhancement",
265 "Reserved 29",
266 "Reserved 30",
267 "Reserved 31"
268};
269
270static char *ac97feature[] = {
271 "mic channel",
272 "reserved",
273 "tone",
274 "simulated stereo",
275 "headphone",
276 "bass boost",
277 "18 bit DAC",
278 "20 bit DAC",
279 "18 bit ADC",
280 "20 bit ADC"
281};
282
283static char *ac97extfeature[] = {
284 "variable rate PCM",
285 "double rate PCM",
286 "reserved 1",
287 "variable rate mic",
288 "reserved 2",
289 "reserved 3",
290 "center DAC",
291 "surround DAC",
292 "LFE DAC",
293 "AMAP",
294 "reserved 4",
295 "reserved 5",
296 "reserved 6",
297 "reserved 7",
298};
299
300u_int16_t
301ac97_rdcd(struct ac97_info *codec, int reg)
302{
303 if (codec->flags & AC97_F_RDCD_BUG) {
304 u_int16_t i[2], j = 100;
305
306 i[0] = AC97_READ(codec->methods, codec->devinfo, reg);
307 i[1] = AC97_READ(codec->methods, codec->devinfo, reg);
308 while (i[0] != i[1] && j)
309 i[j-- & 1] = AC97_READ(codec->methods, codec->devinfo, reg);
310#if 0
311 if (j < 100) {
312 device_printf(codec->dev, "%s(): Inconsistent register value at"
313 " 0x%08x (retry: %d)\n", __func__, reg, 100 - j);
314 }
315#endif
316 return i[!(j & 1)];
317 }
318 return AC97_READ(codec->methods, codec->devinfo, reg);
319}
320
321void
322ac97_wrcd(struct ac97_info *codec, int reg, u_int16_t val)
323{
324 AC97_WRITE(codec->methods, codec->devinfo, reg, val);
325}
326
327static void
328ac97_reset(struct ac97_info *codec)
329{
330 u_int32_t i, ps;
331 ac97_wrcd(codec, AC97_REG_RESET, 0);
332 for (i = 0; i < 500; i++) {
333 ps = ac97_rdcd(codec, AC97_REG_POWER) & AC97_POWER_STATUS;
334 if (ps == AC97_POWER_STATUS)
335 return;
336 DELAY(1000);
337 }
338 device_printf(codec->dev, "AC97 reset timed out.\n");
339}
340
341int
342ac97_setrate(struct ac97_info *codec, int which, int rate)
343{
344 u_int16_t v;
345
346 switch(which) {
347 case AC97_REGEXT_FDACRATE:
348 case AC97_REGEXT_SDACRATE:
349 case AC97_REGEXT_LDACRATE:
350 case AC97_REGEXT_LADCRATE:
351 case AC97_REGEXT_MADCRATE:
352 break;
353
354 default:
355 return -1;
356 }
357
358 snd_mtxlock(codec->lock);
359 if (rate != 0) {
360 v = rate;
361 if (codec->extstat & AC97_EXTCAP_DRA)
362 v >>= 1;
363 ac97_wrcd(codec, which, v);
364 }
365 v = ac97_rdcd(codec, which);
366 if (codec->extstat & AC97_EXTCAP_DRA)
367 v <<= 1;
368 snd_mtxunlock(codec->lock);
369 return v;
370}
371
372int
373ac97_setextmode(struct ac97_info *codec, u_int16_t mode)
374{
375 mode &= AC97_EXTCAPS;
376 if ((mode & ~codec->extcaps) != 0) {
377 device_printf(codec->dev, "ac97 invalid mode set 0x%04x\n",
378 mode);
379 return -1;
380 }
381 snd_mtxlock(codec->lock);
382 ac97_wrcd(codec, AC97_REGEXT_STAT, mode);
383 codec->extstat = ac97_rdcd(codec, AC97_REGEXT_STAT) & AC97_EXTCAPS;
384 snd_mtxunlock(codec->lock);
385 return (mode == codec->extstat)? 0 : -1;
386}
387
388u_int16_t
389ac97_getextmode(struct ac97_info *codec)
390{
391 return codec->extstat;
392}
393
394u_int16_t
395ac97_getextcaps(struct ac97_info *codec)
396{
397 return codec->extcaps;
398}
399
400u_int16_t
401ac97_getcaps(struct ac97_info *codec)
402{
403 return codec->caps;
404}
405
406static int
407ac97_setrecsrc(struct ac97_info *codec, int channel)
408{
409 struct ac97mixtable_entry *e = &codec->mix[channel];
410
411 if (e->recidx > 0) {
412 int val = e->recidx - 1;
413 val |= val << 8;
414 snd_mtxlock(codec->lock);
415 ac97_wrcd(codec, AC97_REG_RECSEL, val);
416 snd_mtxunlock(codec->lock);
417 return 0;
418 } else
419 return -1;
420}
421
422static int
423ac97_setmixer(struct ac97_info *codec, unsigned channel, unsigned left, unsigned right)
424{
425 struct ac97mixtable_entry *e = &codec->mix[channel];
426
427 if (e->reg && e->enable && e->bits) {
428 int mask, max, val, reg;
429
430 reg = (e->reg >= 0) ? e->reg : -e->reg; /* AC97 register */
431 max = (1 << e->bits) - 1; /* actual range */
432 mask = (max << 8) | max; /* bits of interest */
433
434 if (!e->stereo)
435 right = left;
436
437 /*
438 * Invert the range if the polarity requires so,
439 * then scale to 0..max-1 to compute the value to
440 * write into the codec, and scale back to 0..100
441 * for the return value.
442 */
443 if (e->reg > 0) {
444 left = 100 - left;
445 right = 100 - right;
446 }
447
448 left = (left * max) / 100;
449 right = (right * max) / 100;
450
451 val = (left << 8) | right;
452
453 left = (left * 100) / max;
454 right = (right * 100) / max;
455
456 if (e->reg > 0) {
457 left = 100 - left;
458 right = 100 - right;
459 }
460
461 /*
462 * For mono controls, trim val and mask, also taking
463 * care of e->ofs (offset of control field).
464 */
465 if (e->ofs) {
466 val &= max;
467 val <<= e->ofs;
468 mask = (max << e->ofs);
469 }
470
471 /*
472 * If we have a mute bit, add it to the mask and
473 * update val and set mute if both channels require a
474 * zero volume.
475 */
476 if (e->mute == 1) {
477 mask |= AC97_MUTE;
478 if (left == 0 && right == 0)
479 val = AC97_MUTE;
480 }
481
482 /*
483 * If the mask bit is set, do not alter the other bits.
484 */
485 snd_mtxlock(codec->lock);
486 if (e->mask) {
487 int cur = ac97_rdcd(codec, reg);
488 val |= cur & ~(mask);
489 }
490 ac97_wrcd(codec, reg, val);
491 snd_mtxunlock(codec->lock);
492 return left | (right << 8);
493 } else {
494#if 0
495 printf("ac97_setmixer: reg=%d, bits=%d, enable=%d\n", e->reg, e->bits, e->enable);
496#endif
497 return -1;
498 }
499}
500
501static void
502ac97_fix_auxout(struct ac97_info *codec)
503{
504 int keep_ogain;
505
506 /*
507 * By default, The ac97 aux_out register (0x04) corresponds to OSS's
508 * OGAIN setting.
509 *
510 * We first check whether aux_out is a valid register. If not
511 * we may not want to keep ogain.
512 */
513 keep_ogain = ac97_rdcd(codec, AC97_MIX_AUXOUT) & 0x8000;
514
515 /*
516 * Determine what AUX_OUT really means, it can be:
517 *
518 * 1. Headphone out.
519 * 2. 4-Channel Out
520 * 3. True line level out (effectively master volume).
521 *
522 * See Sections 5.2.1 and 5.27 for AUX_OUT Options in AC97r2.{2,3}.
523 */
524 if (codec->extcaps & AC97_EXTCAP_SDAC &&
525 ac97_rdcd(codec, AC97_MIXEXT_SURROUND) == 0x8080) {
526 codec->mix[SOUND_MIXER_OGAIN].reg = AC97_MIXEXT_SURROUND;
527 keep_ogain = 1;
528 }
529
530 if (keep_ogain == 0) {
531 bzero(&codec->mix[SOUND_MIXER_OGAIN],
532 sizeof(codec->mix[SOUND_MIXER_OGAIN]));
533 }
534}
535
536static void
537ac97_fix_tone(struct ac97_info *codec)
538{
539 /* Hide treble and bass if they don't exist */
540 if ((codec->caps & AC97_CAP_TONE) == 0) {
541 bzero(&codec->mix[SOUND_MIXER_BASS],
542 sizeof(codec->mix[SOUND_MIXER_BASS]));
543 bzero(&codec->mix[SOUND_MIXER_TREBLE],
544 sizeof(codec->mix[SOUND_MIXER_TREBLE]));
545 }
546}
547
548static void
549ac97_fix_volume(struct ac97_info *codec)
550{
551 struct snddev_info *d = device_get_softc(codec->dev);
552
553#if 0
554 /* XXX For the sake of debugging purposes */
555 ac97_wrcd(codec, AC97_MIX_PCM, 0);
556 bzero(&codec->mix[SOUND_MIXER_PCM],
557 sizeof(codec->mix[SOUND_MIXER_PCM]));
558 codec->flags |= AC97_F_SOFTVOL;
559 if (d)
560 d->flags |= SD_F_SOFTVOL;
561 return;
562#endif
563 switch (codec->id) {
564 case 0x434d4941: /* CMI9738 */
565 case 0x434d4961: /* CMI9739 */
566 case 0x434d4978: /* CMI9761 */
567 case 0x434d4982: /* CMI9761 */
568 case 0x434d4983: /* CMI9761 */
569 ac97_wrcd(codec, AC97_MIX_PCM, 0);
570 break;
571 default:
572 return;
573 break;
574 }
575 bzero(&codec->mix[SOUND_MIXER_PCM],
576 sizeof(codec->mix[SOUND_MIXER_PCM]));
577 codec->flags |= AC97_F_SOFTVOL;
578 if (d)
579 d->flags |= SD_F_SOFTVOL;
580}
581
582static const char*
583ac97_hw_desc(u_int32_t id, const char* vname, const char* cname, char* buf)
584{
585 if (cname == NULL) {
586 sprintf(buf, "Unknown AC97 Codec (id = 0x%08x)", id);
587 return buf;
588 }
589
590 if (vname == NULL) vname = "Unknown";
591
592 if (bootverbose) {
593 sprintf(buf, "%s %s AC97 Codec (id = 0x%08x)", vname, cname, id);
594 } else {
595 sprintf(buf, "%s %s AC97 Codec", vname, cname);
596 }
597 return buf;
598}
599
600static unsigned
601ac97_initmixer(struct ac97_info *codec)
602{
603 ac97_patch codec_patch;
604 const char *cname, *vname;
605 char desc[80];
606 u_int8_t model, step;
607 unsigned i, j, k, bit, old;
608 u_int32_t id;
609 int reg;
610
611 snd_mtxlock(codec->lock);
612 codec->count = AC97_INIT(codec->methods, codec->devinfo);
613 if (codec->count == 0) {
614 device_printf(codec->dev, "ac97 codec init failed\n");
615 snd_mtxunlock(codec->lock);
616 return ENODEV;
617 }
618
619 ac97_wrcd(codec, AC97_REG_POWER, (codec->flags & AC97_F_EAPD_INV)? 0x8000 : 0x0000);
620 ac97_reset(codec);
621 ac97_wrcd(codec, AC97_REG_POWER, (codec->flags & AC97_F_EAPD_INV)? 0x8000 : 0x0000);
622
623 i = ac97_rdcd(codec, AC97_REG_RESET);
624 j = ac97_rdcd(codec, AC97_REG_RESET);
625 /*
626 * Let see if this codec can return consistent value.
627 * If not, turn on aggressive read workaround
628 * (STAC9704 comes in mind).
629 */
630 if (i != j) {
631 codec->flags |= AC97_F_RDCD_BUG;
632 i = ac97_rdcd(codec, AC97_REG_RESET);
633 }
634 codec->caps = i & 0x03ff;
635 codec->se = (i & 0x7c00) >> 10;
636
637 id = (ac97_rdcd(codec, AC97_REG_ID1) << 16) | ac97_rdcd(codec, AC97_REG_ID2);
638 if (id == 0 || id == 0xffffffff) {
639 device_printf(codec->dev, "ac97 codec invalid or not present (id == %x)\n", id);
640 snd_mtxunlock(codec->lock);
641 return ENODEV;
642 }
643
644 codec->id = id;
645 codec->noext = 0;
646 codec_patch = NULL;
647
648 cname = NULL;
649 model = step = 0;
650 for (i = 0; ac97codecid[i].id; i++) {
651 u_int32_t modelmask = 0xffffffff ^ ac97codecid[i].stepmask;
652 if ((ac97codecid[i].id & modelmask) == (id & modelmask)) {
653 codec->noext = ac97codecid[i].noext;
654 codec_patch = ac97codecid[i].patch;
655 cname = ac97codecid[i].name;
656 model = (id & modelmask) & 0xff;
657 step = (id & ~modelmask) & 0xff;
658 break;
659 }
660 }
661
662 vname = NULL;
663 for (i = 0; ac97vendorid[i].id; i++) {
664 if (ac97vendorid[i].id == (id & 0xffffff00)) {
665 vname = ac97vendorid[i].name;
666 break;
667 }
668 }
669
670 codec->extcaps = 0;
671 codec->extid = 0;
672 codec->extstat = 0;
673 if (!codec->noext) {
674 i = ac97_rdcd(codec, AC97_REGEXT_ID);
675 if (i != 0xffff) {
676 codec->extcaps = i & 0x3fff;
677 codec->extid = (i & 0xc000) >> 14;
678 codec->extstat = ac97_rdcd(codec, AC97_REGEXT_STAT) & AC97_EXTCAPS;
679 }
680 }
681
682 for (i = 0; i < 32; i++) {
683 codec->mix[i] = ac97mixtable_default[i];
684 }
685 ac97_fix_auxout(codec);
686 ac97_fix_tone(codec);
687 ac97_fix_volume(codec);
688 if (codec_patch)
689 codec_patch(codec);
690
691 for (i = 0; i < 32; i++) {
692 k = codec->noext? codec->mix[i].enable : 1;
693 reg = codec->mix[i].reg;
694 if (reg < 0)
695 reg = -reg;
696 if (k && reg) {
697 j = old = ac97_rdcd(codec, reg);
698 /*
699 * Test for mute bit (except for AC97_MIX_TONE,
700 * where we simply assume it as available).
701 */
702 if (codec->mix[i].mute) {
703 ac97_wrcd(codec, reg, j | 0x8000);
704 j = ac97_rdcd(codec, reg);
705 } else
706 j |= 0x8000;
707 if ((j & 0x8000)) {
708 /*
709 * Test whether the control width should be
710 * 4, 5 or 6 bit. For 5bit register, we should
711 * test it whether it's really 5 or 6bit. Leave
712 * 4bit register alone, because sometimes an
713 * attempt to write past 4th bit may cause
714 * incorrect result especially for AC97_MIX_BEEP
715 * (ac97 2.3).
716 */
717 bit = codec->mix[i].bits;
718 if (bit == 5)
719 bit++;
720 j = ((1 << bit) - 1) << codec->mix[i].ofs;
721 ac97_wrcd(codec, reg,
722 j | (codec->mix[i].mute ? 0x8000 : 0));
723 k = ac97_rdcd(codec, reg) & j;
724 k >>= codec->mix[i].ofs;
725 if (reg == AC97_MIX_TONE &&
726 ((k & 0x0001) == 0x0000))
727 k >>= 1;
728 for (j = 0; k >> j; j++)
729 ;
730 if (j != 0) {
731#if 0
732 device_printf(codec->dev, "%2d: [ac97_rdcd() = %d] [Testbit = %d] %d -> %d\n",
733 i, k, bit, codec->mix[i].bits, j);
734#endif
735 codec->mix[i].enable = 1;
736 codec->mix[i].bits = j;
737 } else if (reg == AC97_MIX_BEEP) {
738 /*
739 * Few codec such as CX20468-21 does
740 * have this control register, although
741 * the only usable part is the mute bit.
742 */
743 codec->mix[i].enable = 1;
744 } else
745 codec->mix[i].enable = 0;
746 } else
747 codec->mix[i].enable = 0;
748 ac97_wrcd(codec, reg, old);
749 }
750#if 0
751 printf("mixch %d, en=%d, b=%d\n", i, codec->mix[i].enable, codec->mix[i].bits);
752#endif
753 }
754
755 device_printf(codec->dev, "<%s>\n",
756 ac97_hw_desc(codec->id, vname, cname, desc));
757
758 if (bootverbose) {
759 if (codec->flags & AC97_F_RDCD_BUG)
760 device_printf(codec->dev, "Buggy AC97 Codec: aggressive ac97_rdcd() workaround enabled\n");
761 if (codec->flags & AC97_F_SOFTVOL)
762 device_printf(codec->dev, "Soft PCM volume\n");
763 device_printf(codec->dev, "Codec features ");
764 for (i = j = 0; i < 10; i++)
765 if (codec->caps & (1 << i))
766 printf("%s%s", j++? ", " : "", ac97feature[i]);
767 printf("%s%d bit master volume", j++? ", " : "", codec->mix[SOUND_MIXER_VOLUME].bits);
768 printf("%s%s\n", j? ", " : "", ac97enhancement[codec->se]);
769
770 if (codec->extcaps != 0 || codec->extid) {
771 device_printf(codec->dev, "%s codec",
772 codec->extid? "Secondary" : "Primary");
773 if (codec->extcaps)
774 printf(" extended features ");
775 for (i = j = 0; i < 14; i++)
776 if (codec->extcaps & (1 << i))
777 printf("%s%s", j++? ", " : "", ac97extfeature[i]);
778 printf("\n");
779 }
780 }
781
782 i = 0;
783 while ((ac97_rdcd(codec, AC97_REG_POWER) & 2) == 0) {
784 if (++i == 100) {
785 device_printf(codec->dev, "ac97 codec reports dac not ready\n");
786 break;
787 }
788 DELAY(1000);
789 }
790 if (bootverbose)
791 device_printf(codec->dev, "ac97 codec dac ready count: %d\n", i);
792 snd_mtxunlock(codec->lock);
793 return 0;
794}
795
796static unsigned
797ac97_reinitmixer(struct ac97_info *codec)
798{
799 snd_mtxlock(codec->lock);
800 codec->count = AC97_INIT(codec->methods, codec->devinfo);
801 if (codec->count == 0) {
802 device_printf(codec->dev, "ac97 codec init failed\n");
803 snd_mtxunlock(codec->lock);
804 return ENODEV;
805 }
806
807 ac97_wrcd(codec, AC97_REG_POWER, (codec->flags & AC97_F_EAPD_INV)? 0x8000 : 0x0000);
808 ac97_reset(codec);
809 ac97_wrcd(codec, AC97_REG_POWER, (codec->flags & AC97_F_EAPD_INV)? 0x8000 : 0x0000);
810
811 if (!codec->noext) {
812 ac97_wrcd(codec, AC97_REGEXT_STAT, codec->extstat);
813 if ((ac97_rdcd(codec, AC97_REGEXT_STAT) & AC97_EXTCAPS)
814 != codec->extstat)
815 device_printf(codec->dev, "ac97 codec failed to reset extended mode (%x, got %x)\n",
816 codec->extstat,
817 ac97_rdcd(codec, AC97_REGEXT_STAT) &
818 AC97_EXTCAPS);
819 }
820
821 if ((ac97_rdcd(codec, AC97_REG_POWER) & 2) == 0)
822 device_printf(codec->dev, "ac97 codec reports dac not ready\n");
823 snd_mtxunlock(codec->lock);
824 return 0;
825}
826
827struct ac97_info *
828ac97_create(device_t dev, void *devinfo, kobj_class_t cls)
829{
830 struct ac97_info *codec;
831
832 codec = (struct ac97_info *)malloc(sizeof *codec, M_AC97, M_NOWAIT);
833 if (codec == NULL)
834 return NULL;
835
836 snprintf(codec->name, AC97_NAMELEN, "%s:ac97", device_get_nameunit(dev));
837 codec->lock = snd_mtxcreate(codec->name, "ac97 codec");
838 codec->methods = kobj_create(cls, M_AC97, M_WAITOK);
839 if (codec->methods == NULL) {
840 snd_mtxlock(codec->lock);
841 snd_mtxfree(codec->lock);
842 free(codec, M_AC97);
843 return NULL;
844 }
845
846 codec->dev = dev;
847 codec->devinfo = devinfo;
848 codec->flags = 0;
849 return codec;
850}
851
852void
853ac97_destroy(struct ac97_info *codec)
854{
855 snd_mtxlock(codec->lock);
856 if (codec->methods != NULL)
857 kobj_delete(codec->methods, M_AC97);
858 snd_mtxfree(codec->lock);
859 free(codec, M_AC97);
860}
861
862void
863ac97_setflags(struct ac97_info *codec, u_int32_t val)
864{
865 codec->flags = val;
866}
867
868u_int32_t
869ac97_getflags(struct ac97_info *codec)
870{
871 return codec->flags;
872}
873
874/* -------------------------------------------------------------------- */
875
876static int
877ac97mix_init(struct snd_mixer *m)
878{
879 struct ac97_info *codec = mix_getdevinfo(m);
880 u_int32_t i, mask;
881
882 if (codec == NULL)
883 return -1;
884
885 if (ac97_initmixer(codec))
886 return -1;
887
888 mask = 0;
889 for (i = 0; i < 32; i++)
890 mask |= codec->mix[i].enable? 1 << i : 0;
891 mix_setdevs(m, mask);
892
893 mask = 0;
894 for (i = 0; i < 32; i++)
895 mask |= codec->mix[i].recidx? 1 << i : 0;
896 mix_setrecdevs(m, mask);
897 return 0;
898}
899
900static int
901ac97mix_uninit(struct snd_mixer *m)
902{
903 struct ac97_info *codec = mix_getdevinfo(m);
904
905 if (codec == NULL)
906 return -1;
907 /*
908 if (ac97_uninitmixer(codec))
909 return -1;
910 */
911 ac97_destroy(codec);
912 return 0;
913}
914
915static int
916ac97mix_reinit(struct snd_mixer *m)
917{
918 struct ac97_info *codec = mix_getdevinfo(m);
919
920 if (codec == NULL)
921 return -1;
922 return ac97_reinitmixer(codec);
923}
924
925static int
926ac97mix_set(struct snd_mixer *m, unsigned dev, unsigned left, unsigned right)
927{
928 struct ac97_info *codec = mix_getdevinfo(m);
929
930 if (codec == NULL)
931 return -1;
932 return ac97_setmixer(codec, dev, left, right);
933}
934
935static int
936ac97mix_setrecsrc(struct snd_mixer *m, u_int32_t src)
937{
938 int i;
939 struct ac97_info *codec = mix_getdevinfo(m);
940
941 if (codec == NULL)
942 return -1;
943 for (i = 0; i < SOUND_MIXER_NRDEVICES; i++)
944 if ((src & (1 << i)) != 0)
945 break;
946 return (ac97_setrecsrc(codec, i) == 0)? 1 << i : -1;
947}
948
949static kobj_method_t ac97mixer_methods[] = {
950 KOBJMETHOD(mixer_init, ac97mix_init),
951 KOBJMETHOD(mixer_uninit, ac97mix_uninit),
952 KOBJMETHOD(mixer_reinit, ac97mix_reinit),
953 KOBJMETHOD(mixer_set, ac97mix_set),
954 KOBJMETHOD(mixer_setrecsrc, ac97mix_setrecsrc),
955 { 0, 0 }
956};
957MIXER_DECLARE(ac97mixer);
958
959/* -------------------------------------------------------------------- */
960
961kobj_class_t
962ac97_getmixerclass(void)
963{
964 return &ac97mixer_class;
965}
966
967