1 /*-
2 * SPDX-License-Identifier: BSD-2-Clause
3 *
4 * Copyright (c) 1999 Cameron Grant <cg@freebsd.org>
5 * All rights reserved.
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
17 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
20 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
22 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
23 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
24 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
25 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26 * SUCH DAMAGE.
27 */
28
29 #ifdef HAVE_KERNEL_OPTION_HEADERS
30 #include "opt_snd.h"
31 #endif
32
33 #include <dev/sound/pcm/sound.h>
34 #include <dev/sound/pcm/ac97.h>
35 #include <dev/sound/pcm/ac97_patch.h>
36
37 #include <dev/pci/pcivar.h>
38
39 #include "mixer_if.h"
40
41 static MALLOC_DEFINE(M_AC97, "ac97", "ac97 codec");
42
43 struct ac97mixtable_entry {
44 int reg; /* register index */
45 /* reg < 0 if inverted polarity */
46 unsigned bits:4; /* width of control field */
47 unsigned ofs:4; /* offset (only if stereo=0) */
48 unsigned stereo:1; /* set for stereo controls */
49 unsigned mute:1; /* bit15 is MUTE */
50 unsigned recidx:4; /* index in rec mux */
51 unsigned mask:1; /* use only masked bits */
52 unsigned enable:1; /* entry is enabled */
53 };
54
55 #define AC97_MIXER_SIZE SOUND_MIXER_NRDEVICES
56
57 struct ac97_info {
58 kobj_t methods;
59 device_t dev;
60 void *devinfo;
61 u_int32_t id;
62 u_int32_t subvendor;
63 unsigned count, caps, se, extcaps, extid, extstat, noext:1;
64 u_int32_t flags;
65 struct ac97mixtable_entry mix[AC97_MIXER_SIZE];
66 char name[16];
67 struct mtx *lock;
68 };
69
70 struct ac97_vendorid {
71 u_int32_t id;
72 const char *name;
73 };
74
75 struct ac97_codecid {
76 u_int32_t id;
77 u_int8_t stepmask;
78 u_int8_t noext:1;
79 char *name;
80 ac97_patch patch;
81 };
82
83 static const struct ac97mixtable_entry ac97mixtable_default[AC97_MIXER_SIZE] = {
84 /* [offset] reg bits of st mu re mk en */
85 [SOUND_MIXER_VOLUME] = { AC97_MIX_MASTER, 5, 0, 1, 1, 6, 0, 1 },
86 [SOUND_MIXER_OGAIN] = { AC97_MIX_AUXOUT, 5, 0, 1, 1, 0, 0, 0 },
87 [SOUND_MIXER_PHONEOUT] = { AC97_MIX_MONO, 5, 0, 0, 1, 7, 0, 0 },
88 [SOUND_MIXER_BASS] = { AC97_MIX_TONE, 4, 8, 0, 0, 0, 1, 0 },
89 [SOUND_MIXER_TREBLE] = { AC97_MIX_TONE, 4, 0, 0, 0, 0, 1, 0 },
90 [SOUND_MIXER_PCM] = { AC97_MIX_PCM, 5, 0, 1, 1, 0, 0, 1 },
91 [SOUND_MIXER_SPEAKER] = { AC97_MIX_BEEP, 4, 1, 0, 1, 0, 0, 0 },
92 [SOUND_MIXER_LINE] = { AC97_MIX_LINE, 5, 0, 1, 1, 5, 0, 1 },
93 [SOUND_MIXER_PHONEIN] = { AC97_MIX_PHONE, 5, 0, 0, 1, 8, 0, 0 },
94 [SOUND_MIXER_MIC] = { AC97_MIX_MIC, 5, 0, 0, 1, 1, 1, 1 },
95 /* use igain for the mic 20dB boost */
96 [SOUND_MIXER_IGAIN] = { -AC97_MIX_MIC, 1, 6, 0, 0, 0, 1, 1 },
97 [SOUND_MIXER_CD] = { AC97_MIX_CD, 5, 0, 1, 1, 2, 0, 1 },
98 [SOUND_MIXER_LINE1] = { AC97_MIX_AUX, 5, 0, 1, 1, 4, 0, 0 },
99 [SOUND_MIXER_VIDEO] = { AC97_MIX_VIDEO, 5, 0, 1, 1, 3, 0, 0 },
100 [SOUND_MIXER_RECLEV] = { -AC97_MIX_RGAIN, 4, 0, 1, 1, 0, 0, 1 }
101 };
102
103 static const struct ac97_vendorid ac97vendorid[] = {
104 { 0x41445300, "Analog Devices" },
105 { 0x414b4d00, "Asahi Kasei" },
106 { 0x414c4300, "Realtek" },
107 { 0x414c4700, "Avance Logic" },
108 { 0x43525900, "Cirrus Logic" },
109 { 0x434d4900, "C-Media Electronics" },
110 { 0x43585400, "Conexant" },
111 { 0x44543000, "Diamond Technology" },
112 { 0x454d4300, "eMicro" },
113 { 0x45838300, "ESS Technology" },
114 { 0x48525300, "Intersil" },
115 { 0x49434500, "ICEnsemble" },
116 { 0x49544500, "ITE, Inc." },
117 { 0x4e534300, "National Semiconductor" },
118 { 0x50534300, "Philips Semiconductor" },
119 { 0x83847600, "SigmaTel" },
120 { 0x53494c00, "Silicon Laboratories" },
121 { 0x54524100, "TriTech" },
122 { 0x54584e00, "Texas Instruments" },
123 { 0x56494100, "VIA Technologies" },
124 { 0x57454300, "Winbond" },
125 { 0x574d4c00, "Wolfson" },
126 { 0x594d4800, "Yamaha" },
127 /*
128 * XXX This is a fluke, really! The real vendor
129 * should be SigmaTel, not this! This should be
130 * removed someday!
131 */
132 { 0x01408300, "Creative" },
133 { 0x00000000, NULL }
134 };
135
136 static struct ac97_codecid ac97codecid[] = {
137 { 0x41445303, 0x00, 0, "AD1819", 0 },
138 { 0x41445340, 0x00, 0, "AD1881", 0 },
139 { 0x41445348, 0x00, 0, "AD1881A", 0 },
140 { 0x41445360, 0x00, 0, "AD1885", 0 },
141 { 0x41445361, 0x00, 0, "AD1886", ad1886_patch },
142 { 0x41445362, 0x00, 0, "AD1887", 0 },
143 { 0x41445363, 0x00, 0, "AD1886A", 0 },
144 { 0x41445368, 0x00, 0, "AD1888", ad198x_patch },
145 { 0x41445370, 0x00, 0, "AD1980", ad198x_patch },
146 { 0x41445372, 0x00, 0, "AD1981A", 0 },
147 { 0x41445374, 0x00, 0, "AD1981B", ad1981b_patch },
148 { 0x41445375, 0x00, 0, "AD1985", ad198x_patch },
149 { 0x41445378, 0x00, 0, "AD1986", ad198x_patch },
150 { 0x414b4d00, 0x00, 1, "AK4540", 0 },
151 { 0x414b4d01, 0x00, 1, "AK4542", 0 },
152 { 0x414b4d02, 0x00, 1, "AK4543", 0 },
153 { 0x414b4d06, 0x00, 0, "AK4544A", 0 },
154 { 0x454b4d07, 0x00, 0, "AK4545", 0 },
155 { 0x414c4320, 0x0f, 0, "ALC100", 0 },
156 { 0x414c4730, 0x0f, 0, "ALC101", 0 },
157 { 0x414c4710, 0x0f, 0, "ALC200", 0 },
158 { 0x414c4740, 0x0f, 0, "ALC202", 0 },
159 { 0x414c4720, 0x0f, 0, "ALC650", 0 },
160 { 0x414c4752, 0x0f, 0, "ALC250", 0 },
161 { 0x414c4760, 0x0f, 0, "ALC655", alc655_patch },
162 { 0x414c4770, 0x0f, 0, "ALC203", 0 },
163 { 0x414c4780, 0x0f, 0, "ALC658", 0 },
164 { 0x414c4790, 0x0f, 0, "ALC850", 0 },
165 { 0x43525900, 0x07, 0, "CS4297", 0 },
166 { 0x43525910, 0x07, 0, "CS4297A", 0 },
167 { 0x43525920, 0x07, 0, "CS4294/98", 0 },
168 { 0x4352592d, 0x07, 0, "CS4294", 0 },
169 { 0x43525930, 0x07, 0, "CS4299", 0 },
170 { 0x43525940, 0x07, 0, "CS4201", 0 },
171 { 0x43525958, 0x07, 0, "CS4205", 0 },
172 { 0x43525960, 0x07, 0, "CS4291A", 0 },
173 { 0x434d4961, 0x00, 0, "CMI9739", cmi9739_patch },
174 { 0x434d4941, 0x00, 0, "CMI9738", 0 },
175 { 0x434d4978, 0x00, 0, "CMI9761", 0 },
176 { 0x434d4982, 0x00, 0, "CMI9761", 0 },
177 { 0x434d4983, 0x00, 0, "CMI9761", 0 },
178 { 0x43585421, 0x00, 0, "HSD11246", 0 },
179 { 0x43585428, 0x07, 0, "CX20468", 0 },
180 { 0x43585430, 0x00, 0, "CX20468-21", 0 },
181 { 0x44543000, 0x00, 0, "DT0398", 0 },
182 { 0x454d4323, 0x00, 0, "EM28023", 0 },
183 { 0x454d4328, 0x00, 0, "EM28028", 0 },
184 { 0x45838308, 0x00, 0, "ES1988", 0 }, /* Formerly ES1921(?) */
185 { 0x48525300, 0x00, 0, "HMP9701", 0 },
186 { 0x49434501, 0x00, 0, "ICE1230", 0 },
187 { 0x49434511, 0x00, 0, "ICE1232", 0 },
188 { 0x49434514, 0x00, 0, "ICE1232A", 0 },
189 { 0x49434551, 0x03, 0, "VT1616", 0 }, /* Via badged ICE */
190 { 0x49544520, 0x00, 0, "ITE2226E", 0 },
191 { 0x49544560, 0x07, 0, "ITE2646E", 0 }, /* XXX: patch needed */
192 { 0x4e534340, 0x00, 0, "LM4540", 0 }, /* Spec blank on revid */
193 { 0x4e534343, 0x00, 0, "LM4543", 0 }, /* Ditto */
194 { 0x4e534346, 0x00, 0, "LM4546A", 0 },
195 { 0x4e534348, 0x00, 0, "LM4548A", 0 },
196 { 0x4e534331, 0x00, 0, "LM4549", 0 },
197 { 0x4e534349, 0x00, 0, "LM4549A", 0 },
198 { 0x4e534350, 0x00, 0, "LM4550", 0 },
199 { 0x50534301, 0x00, 0, "UCB1510", 0 },
200 { 0x50534304, 0x00, 0, "UCB1400", 0 },
201 { 0x83847600, 0x00, 0, "STAC9700/83/84", 0 },
202 { 0x83847604, 0x00, 0, "STAC9701/03/04/05", 0 },
203 { 0x83847605, 0x00, 0, "STAC9704", 0 },
204 { 0x83847608, 0x00, 0, "STAC9708/11", 0 },
205 { 0x83847609, 0x00, 0, "STAC9721/23", 0 },
206 { 0x83847644, 0x00, 0, "STAC9744/45", 0 },
207 { 0x83847650, 0x00, 0, "STAC9750/51", 0 },
208 { 0x83847652, 0x00, 0, "STAC9752/53", 0 },
209 { 0x83847656, 0x00, 0, "STAC9756/57", 0 },
210 { 0x83847658, 0x00, 0, "STAC9758/59", 0 },
211 { 0x83847660, 0x00, 0, "STAC9760/61", 0 }, /* Extrapolated */
212 { 0x83847662, 0x00, 0, "STAC9762/63", 0 }, /* Extrapolated */
213 { 0x83847666, 0x00, 0, "STAC9766/67", 0 },
214 { 0x53494c22, 0x00, 0, "Si3036", 0 },
215 { 0x53494c23, 0x00, 0, "Si3038", 0 },
216 { 0x54524103, 0x00, 0, "TR28023", 0 }, /* Extrapolated */
217 { 0x54524106, 0x00, 0, "TR28026", 0 },
218 { 0x54524108, 0x00, 0, "TR28028", 0 },
219 { 0x54524123, 0x00, 0, "TR28602", 0 },
220 { 0x54524e03, 0x07, 0, "TLV320AIC27", 0 },
221 { 0x54584e20, 0x00, 0, "TLC320AD90", 0 },
222 { 0x56494161, 0x00, 0, "VIA1612A", 0 },
223 { 0x56494170, 0x00, 0, "VIA1617A", 0 },
224 { 0x574d4c00, 0x00, 0, "WM9701A", 0 },
225 { 0x574d4c03, 0x00, 0, "WM9703/4/7/8", 0 },
226 { 0x574d4c04, 0x00, 0, "WM9704Q", 0 },
227 { 0x574d4c05, 0x00, 0, "WM9705/10", 0 },
228 { 0x574d4d09, 0x00, 0, "WM9709", 0 },
229 { 0x574d4c12, 0x00, 0, "WM9711/12", 0 }, /* XXX: patch needed */
230 { 0x57454301, 0x00, 0, "W83971D", 0 },
231 { 0x594d4800, 0x00, 0, "YMF743", 0 },
232 { 0x594d4802, 0x00, 0, "YMF752", 0 },
233 { 0x594d4803, 0x00, 0, "YMF753", 0 },
234 /*
235 * XXX This is a fluke, really! The real codec
236 * should be STAC9704, not this! This should be
237 * removed someday!
238 */
239 { 0x01408384, 0x00, 0, "EV1938", 0 },
240 { 0, 0, 0, NULL, 0 }
241 };
242
243 static char *ac97enhancement[] = {
244 "no 3D Stereo Enhancement",
245 "Analog Devices Phat Stereo",
246 "Creative Stereo Enhancement",
247 "National Semi 3D Stereo Enhancement",
248 "Yamaha Ymersion",
249 "BBE 3D Stereo Enhancement",
250 "Crystal Semi 3D Stereo Enhancement",
251 "Qsound QXpander",
252 "Spatializer 3D Stereo Enhancement",
253 "SRS 3D Stereo Enhancement",
254 "Platform Tech 3D Stereo Enhancement",
255 "AKM 3D Audio",
256 "Aureal Stereo Enhancement",
257 "Aztech 3D Enhancement",
258 "Binaura 3D Audio Enhancement",
259 "ESS Technology Stereo Enhancement",
260 "Harman International VMAx",
261 "Nvidea 3D Stereo Enhancement",
262 "Philips Incredible Sound",
263 "Texas Instruments 3D Stereo Enhancement",
264 "VLSI Technology 3D Stereo Enhancement",
265 "TriTech 3D Stereo Enhancement",
266 "Realtek 3D Stereo Enhancement",
267 "Samsung 3D Stereo Enhancement",
268 "Wolfson Microelectronics 3D Enhancement",
269 "Delta Integration 3D Enhancement",
270 "SigmaTel 3D Enhancement",
271 "Reserved 27",
272 "Rockwell 3D Stereo Enhancement",
273 "Reserved 29",
274 "Reserved 30",
275 "Reserved 31"
276 };
277
278 static char *ac97feature[] = {
279 "mic channel",
280 "reserved",
281 "tone",
282 "simulated stereo",
283 "headphone",
284 "bass boost",
285 "18 bit DAC",
286 "20 bit DAC",
287 "18 bit ADC",
288 "20 bit ADC"
289 };
290
291 static char *ac97extfeature[] = {
292 "variable rate PCM",
293 "double rate PCM",
294 "reserved 1",
295 "variable rate mic",
296 "reserved 2",
297 "reserved 3",
298 "center DAC",
299 "surround DAC",
300 "LFE DAC",
301 "AMAP",
302 "reserved 4",
303 "reserved 5",
304 "reserved 6",
305 "reserved 7",
306 };
307
308 u_int16_t
ac97_rdcd(struct ac97_info * codec,int reg)309 ac97_rdcd(struct ac97_info *codec, int reg)
310 {
311 if (codec->flags & AC97_F_RDCD_BUG) {
312 u_int16_t i[2], j = 100;
313
314 i[0] = AC97_READ(codec->methods, codec->devinfo, reg);
315 i[1] = AC97_READ(codec->methods, codec->devinfo, reg);
316 while (i[0] != i[1] && j)
317 i[j-- & 1] = AC97_READ(codec->methods, codec->devinfo, reg);
318 #if 0
319 if (j < 100) {
320 device_printf(codec->dev, "%s(): Inconsistent register value at"
321 " 0x%08x (retry: %d)\n", __func__, reg, 100 - j);
322 }
323 #endif
324 return i[!(j & 1)];
325 }
326 return AC97_READ(codec->methods, codec->devinfo, reg);
327 }
328
329 void
ac97_wrcd(struct ac97_info * codec,int reg,u_int16_t val)330 ac97_wrcd(struct ac97_info *codec, int reg, u_int16_t val)
331 {
332 AC97_WRITE(codec->methods, codec->devinfo, reg, val);
333 }
334
335 static void
ac97_reset(struct ac97_info * codec)336 ac97_reset(struct ac97_info *codec)
337 {
338 u_int32_t i, ps;
339 ac97_wrcd(codec, AC97_REG_RESET, 0);
340 for (i = 0; i < 500; i++) {
341 ps = ac97_rdcd(codec, AC97_REG_POWER) & AC97_POWER_STATUS;
342 if (ps == AC97_POWER_STATUS)
343 return;
344 DELAY(1000);
345 }
346 device_printf(codec->dev, "AC97 reset timed out.\n");
347 }
348
349 int
ac97_setrate(struct ac97_info * codec,int which,int rate)350 ac97_setrate(struct ac97_info *codec, int which, int rate)
351 {
352 u_int16_t v;
353
354 switch(which) {
355 case AC97_REGEXT_FDACRATE:
356 case AC97_REGEXT_SDACRATE:
357 case AC97_REGEXT_LDACRATE:
358 case AC97_REGEXT_LADCRATE:
359 case AC97_REGEXT_MADCRATE:
360 break;
361
362 default:
363 return -1;
364 }
365
366 snd_mtxlock(codec->lock);
367 if (rate != 0) {
368 v = rate;
369 if (codec->extstat & AC97_EXTCAP_DRA)
370 v >>= 1;
371 ac97_wrcd(codec, which, v);
372 }
373 v = ac97_rdcd(codec, which);
374 if (codec->extstat & AC97_EXTCAP_DRA)
375 v <<= 1;
376 snd_mtxunlock(codec->lock);
377 return v;
378 }
379
380 int
ac97_setextmode(struct ac97_info * codec,u_int16_t mode)381 ac97_setextmode(struct ac97_info *codec, u_int16_t mode)
382 {
383 mode &= AC97_EXTCAPS;
384 if ((mode & ~codec->extcaps) != 0) {
385 device_printf(codec->dev, "ac97 invalid mode set 0x%04x\n",
386 mode);
387 return -1;
388 }
389 snd_mtxlock(codec->lock);
390 ac97_wrcd(codec, AC97_REGEXT_STAT, mode);
391 codec->extstat = ac97_rdcd(codec, AC97_REGEXT_STAT) & AC97_EXTCAPS;
392 snd_mtxunlock(codec->lock);
393 return (mode == codec->extstat)? 0 : -1;
394 }
395
396 u_int16_t
ac97_getextmode(struct ac97_info * codec)397 ac97_getextmode(struct ac97_info *codec)
398 {
399 return codec->extstat;
400 }
401
402 u_int16_t
ac97_getextcaps(struct ac97_info * codec)403 ac97_getextcaps(struct ac97_info *codec)
404 {
405 return codec->extcaps;
406 }
407
408 u_int16_t
ac97_getcaps(struct ac97_info * codec)409 ac97_getcaps(struct ac97_info *codec)
410 {
411 return codec->caps;
412 }
413
414 u_int32_t
ac97_getsubvendor(struct ac97_info * codec)415 ac97_getsubvendor(struct ac97_info *codec)
416 {
417 return codec->subvendor;
418 }
419
420 static int
ac97_setrecsrc(struct ac97_info * codec,int channel)421 ac97_setrecsrc(struct ac97_info *codec, int channel)
422 {
423 struct ac97mixtable_entry *e = &codec->mix[channel];
424
425 if (e->recidx > 0) {
426 int val = e->recidx - 1;
427 val |= val << 8;
428 snd_mtxlock(codec->lock);
429 ac97_wrcd(codec, AC97_REG_RECSEL, val);
430 snd_mtxunlock(codec->lock);
431 return 0;
432 } else
433 return -1;
434 }
435
436 static int
ac97_setmixer(struct ac97_info * codec,unsigned channel,unsigned left,unsigned right)437 ac97_setmixer(struct ac97_info *codec, unsigned channel, unsigned left, unsigned right)
438 {
439 struct ac97mixtable_entry *e = &codec->mix[channel];
440
441 if (e->reg && e->enable && e->bits) {
442 int mask, max, val, reg;
443
444 reg = (e->reg >= 0) ? e->reg : -e->reg; /* AC97 register */
445 max = (1 << e->bits) - 1; /* actual range */
446 mask = (max << 8) | max; /* bits of interest */
447
448 if (!e->stereo)
449 right = left;
450
451 /*
452 * Invert the range if the polarity requires so,
453 * then scale to 0..max-1 to compute the value to
454 * write into the codec, and scale back to 0..100
455 * for the return value.
456 */
457 if (e->reg > 0) {
458 left = 100 - left;
459 right = 100 - right;
460 }
461
462 left = (left * max) / 100;
463 right = (right * max) / 100;
464
465 val = (left << 8) | right;
466
467 left = (left * 100) / max;
468 right = (right * 100) / max;
469
470 if (e->reg > 0) {
471 left = 100 - left;
472 right = 100 - right;
473 }
474
475 /*
476 * For mono controls, trim val and mask, also taking
477 * care of e->ofs (offset of control field).
478 */
479 if (e->ofs) {
480 val &= max;
481 val <<= e->ofs;
482 mask = (max << e->ofs);
483 }
484
485 /*
486 * If we have a mute bit, add it to the mask and
487 * update val and set mute if both channels require a
488 * zero volume.
489 */
490 if (e->mute == 1) {
491 mask |= AC97_MUTE;
492 if (left == 0 && right == 0)
493 val = AC97_MUTE;
494 }
495
496 /*
497 * If the mask bit is set, do not alter the other bits.
498 */
499 snd_mtxlock(codec->lock);
500 if (e->mask) {
501 int cur = ac97_rdcd(codec, reg);
502 val |= cur & ~(mask);
503 }
504 ac97_wrcd(codec, reg, val);
505 snd_mtxunlock(codec->lock);
506 return left | (right << 8);
507 } else {
508 #if 0
509 printf("ac97_setmixer: reg=%d, bits=%d, enable=%d\n", e->reg, e->bits, e->enable);
510 #endif
511 return -1;
512 }
513 }
514
515 static void
ac97_fix_auxout(struct ac97_info * codec)516 ac97_fix_auxout(struct ac97_info *codec)
517 {
518 int keep_ogain;
519
520 /*
521 * By default, The ac97 aux_out register (0x04) corresponds to OSS's
522 * OGAIN setting.
523 *
524 * We first check whether aux_out is a valid register. If not
525 * we may not want to keep ogain.
526 */
527 keep_ogain = ac97_rdcd(codec, AC97_MIX_AUXOUT) & 0x8000;
528
529 /*
530 * Determine what AUX_OUT really means, it can be:
531 *
532 * 1. Headphone out.
533 * 2. 4-Channel Out
534 * 3. True line level out (effectively master volume).
535 *
536 * See Sections 5.2.1 and 5.27 for AUX_OUT Options in AC97r2.{2,3}.
537 */
538 if (codec->extcaps & AC97_EXTCAP_SDAC &&
539 ac97_rdcd(codec, AC97_MIXEXT_SURROUND) == 0x8080) {
540 codec->mix[SOUND_MIXER_OGAIN].reg = AC97_MIXEXT_SURROUND;
541 keep_ogain = 1;
542 }
543
544 if (keep_ogain == 0) {
545 bzero(&codec->mix[SOUND_MIXER_OGAIN],
546 sizeof(codec->mix[SOUND_MIXER_OGAIN]));
547 }
548 }
549
550 static void
ac97_fix_tone(struct ac97_info * codec)551 ac97_fix_tone(struct ac97_info *codec)
552 {
553 /*
554 * YMF chips does not indicate tone and 3D enhancement capability
555 * in the AC97_REG_RESET register.
556 */
557 switch (codec->id) {
558 case 0x594d4800: /* YMF743 */
559 case 0x594d4803: /* YMF753 */
560 codec->caps |= AC97_CAP_TONE;
561 codec->se |= 0x04;
562 break;
563 case 0x594d4802: /* YMF752 */
564 codec->se |= 0x04;
565 break;
566 default:
567 break;
568 }
569
570 /* Hide treble and bass if they don't exist */
571 if ((codec->caps & AC97_CAP_TONE) == 0) {
572 bzero(&codec->mix[SOUND_MIXER_BASS],
573 sizeof(codec->mix[SOUND_MIXER_BASS]));
574 bzero(&codec->mix[SOUND_MIXER_TREBLE],
575 sizeof(codec->mix[SOUND_MIXER_TREBLE]));
576 }
577 }
578
579 static const char*
ac97_hw_desc(u_int32_t id,const char * vname,const char * cname,char * buf)580 ac97_hw_desc(u_int32_t id, const char* vname, const char* cname, char* buf)
581 {
582 if (cname == NULL) {
583 sprintf(buf, "Unknown AC97 Codec (id = 0x%08x)", id);
584 return buf;
585 }
586
587 if (vname == NULL) vname = "Unknown";
588
589 if (bootverbose) {
590 sprintf(buf, "%s %s AC97 Codec (id = 0x%08x)", vname, cname, id);
591 } else {
592 sprintf(buf, "%s %s AC97 Codec", vname, cname);
593 }
594 return buf;
595 }
596
597 static unsigned
ac97_initmixer(struct ac97_info * codec)598 ac97_initmixer(struct ac97_info *codec)
599 {
600 ac97_patch codec_patch;
601 const char *cname, *vname;
602 char desc[80];
603 device_t pdev;
604 unsigned i, j, k, bit, old;
605 u_int32_t id;
606 int reg;
607
608 snd_mtxlock(codec->lock);
609 codec->count = AC97_INIT(codec->methods, codec->devinfo);
610 if (codec->count == 0) {
611 device_printf(codec->dev, "ac97 codec init failed\n");
612 snd_mtxunlock(codec->lock);
613 return ENODEV;
614 }
615
616 ac97_wrcd(codec, AC97_REG_POWER, (codec->flags & AC97_F_EAPD_INV)? 0x8000 : 0x0000);
617 ac97_reset(codec);
618 ac97_wrcd(codec, AC97_REG_POWER, (codec->flags & AC97_F_EAPD_INV)? 0x8000 : 0x0000);
619
620 i = ac97_rdcd(codec, AC97_REG_RESET);
621 j = ac97_rdcd(codec, AC97_REG_RESET);
622 k = ac97_rdcd(codec, AC97_REG_RESET);
623 /*
624 * Let see if this codec can return consistent value.
625 * If not, turn on aggressive read workaround
626 * (STAC9704 comes in mind).
627 */
628 if (i != j || j != k) {
629 codec->flags |= AC97_F_RDCD_BUG;
630 i = ac97_rdcd(codec, AC97_REG_RESET);
631 }
632 codec->caps = i & 0x03ff;
633 codec->se = (i & 0x7c00) >> 10;
634
635 id = (ac97_rdcd(codec, AC97_REG_ID1) << 16) | ac97_rdcd(codec, AC97_REG_ID2);
636 if (id == 0 || id == 0xffffffff) {
637 device_printf(codec->dev, "ac97 codec invalid or not present (id == %x)\n", id);
638 snd_mtxunlock(codec->lock);
639 return ENODEV;
640 }
641
642 pdev = codec->dev;
643 while (strcmp(device_get_name(device_get_parent(pdev)), "pci") != 0) {
644 /* find the top-level PCI device handler */
645 pdev = device_get_parent(pdev);
646 }
647 codec->id = id;
648 codec->subvendor = (u_int32_t)pci_get_subdevice(pdev) << 16;
649 codec->subvendor |= (u_int32_t)pci_get_subvendor(pdev) &
650 0x0000ffff;
651 codec->noext = 0;
652 codec_patch = NULL;
653
654 cname = NULL;
655 for (i = 0; ac97codecid[i].id; i++) {
656 u_int32_t modelmask = 0xffffffff ^ ac97codecid[i].stepmask;
657 if ((ac97codecid[i].id & modelmask) == (id & modelmask)) {
658 codec->noext = ac97codecid[i].noext;
659 codec_patch = ac97codecid[i].patch;
660 cname = ac97codecid[i].name;
661 break;
662 }
663 }
664
665 vname = NULL;
666 for (i = 0; ac97vendorid[i].id; i++) {
667 if (ac97vendorid[i].id == (id & 0xffffff00)) {
668 vname = ac97vendorid[i].name;
669 break;
670 }
671 }
672
673 codec->extcaps = 0;
674 codec->extid = 0;
675 codec->extstat = 0;
676 if (!codec->noext) {
677 i = ac97_rdcd(codec, AC97_REGEXT_ID);
678 if (i != 0xffff) {
679 codec->extcaps = i & 0x3fff;
680 codec->extid = (i & 0xc000) >> 14;
681 codec->extstat = ac97_rdcd(codec, AC97_REGEXT_STAT) & AC97_EXTCAPS;
682 }
683 }
684
685 for (i = 0; i < AC97_MIXER_SIZE; i++) {
686 codec->mix[i] = ac97mixtable_default[i];
687 }
688 ac97_fix_auxout(codec);
689 ac97_fix_tone(codec);
690 if (codec_patch)
691 codec_patch(codec);
692
693 for (i = 0; i < AC97_MIXER_SIZE; i++) {
694 k = codec->noext? codec->mix[i].enable : 1;
695 reg = codec->mix[i].reg;
696 if (reg < 0)
697 reg = -reg;
698 if (k && reg) {
699 j = old = ac97_rdcd(codec, reg);
700 /*
701 * Test for mute bit (except for AC97_MIX_TONE,
702 * where we simply assume it as available).
703 */
704 if (codec->mix[i].mute) {
705 ac97_wrcd(codec, reg, j | 0x8000);
706 j = ac97_rdcd(codec, reg);
707 } else
708 j |= 0x8000;
709 if ((j & 0x8000)) {
710 /*
711 * Test whether the control width should be
712 * 4, 5 or 6 bit. For 5bit register, we should
713 * test it whether it's really 5 or 6bit. Leave
714 * 4bit register alone, because sometimes an
715 * attempt to write past 4th bit may cause
716 * incorrect result especially for AC97_MIX_BEEP
717 * (ac97 2.3).
718 */
719 bit = codec->mix[i].bits;
720 if (bit == 5)
721 bit++;
722 j = ((1 << bit) - 1) << codec->mix[i].ofs;
723 ac97_wrcd(codec, reg,
724 j | (codec->mix[i].mute ? 0x8000 : 0));
725 k = ac97_rdcd(codec, reg) & j;
726 k >>= codec->mix[i].ofs;
727 if (reg == AC97_MIX_TONE &&
728 ((k & 0x0001) == 0x0000))
729 k >>= 1;
730 for (j = 0; k >> j; j++)
731 ;
732 if (j != 0) {
733 #if 0
734 device_printf(codec->dev, "%2d: [ac97_rdcd() = %d] [Testbit = %d] %d -> %d\n",
735 i, k, bit, codec->mix[i].bits, j);
736 #endif
737 codec->mix[i].enable = 1;
738 codec->mix[i].bits = j;
739 } else if (reg == AC97_MIX_BEEP) {
740 /*
741 * Few codec such as CX20468-21 does
742 * have this control register, although
743 * the only usable part is the mute bit.
744 */
745 codec->mix[i].enable = 1;
746 } else
747 codec->mix[i].enable = 0;
748 } else
749 codec->mix[i].enable = 0;
750 ac97_wrcd(codec, reg, old);
751 }
752 #if 0
753 printf("mixch %d, en=%d, b=%d\n", i, codec->mix[i].enable, codec->mix[i].bits);
754 #endif
755 }
756
757 device_printf(codec->dev, "<%s>\n",
758 ac97_hw_desc(codec->id, vname, cname, desc));
759
760 if (bootverbose) {
761 if (codec->flags & AC97_F_RDCD_BUG)
762 device_printf(codec->dev, "Buggy AC97 Codec: aggressive ac97_rdcd() workaround enabled\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
796 static unsigned
ac97_reinitmixer(struct ac97_info * codec)797 ac97_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
827 struct ac97_info *
ac97_create(device_t dev,void * devinfo,kobj_class_t cls)828 ac97_create(device_t dev, void *devinfo, kobj_class_t cls)
829 {
830 struct ac97_info *codec;
831 int i;
832
833 codec = malloc(sizeof(*codec), M_AC97, M_WAITOK | M_ZERO);
834 snprintf(codec->name, sizeof(codec->name), "%s:ac97",
835 device_get_nameunit(dev));
836 codec->lock = snd_mtxcreate(codec->name, "ac97 codec");
837 codec->methods = kobj_create(cls, M_AC97, M_WAITOK | M_ZERO);
838 codec->dev = dev;
839 codec->devinfo = devinfo;
840 codec->flags = 0;
841
842 if (resource_int_value(device_get_name(dev), device_get_unit(dev),
843 "eapdinv", &i) == 0 && i != 0)
844 codec->flags |= AC97_F_EAPD_INV;
845
846 if (resource_int_value(device_get_name(dev), device_get_unit(dev),
847 "softpcmvol", &i) == 0 && i != 0)
848 pcm_setflags(dev, pcm_getflags(dev) | SD_F_SOFTPCMVOL);
849
850 return codec;
851 }
852
853 void
ac97_destroy(struct ac97_info * codec)854 ac97_destroy(struct ac97_info *codec)
855 {
856 snd_mtxlock(codec->lock);
857 if (codec->methods != NULL)
858 kobj_delete(codec->methods, M_AC97);
859 snd_mtxfree(codec->lock);
860 free(codec, M_AC97);
861 }
862
863 void
ac97_setflags(struct ac97_info * codec,u_int32_t val)864 ac97_setflags(struct ac97_info *codec, u_int32_t val)
865 {
866 codec->flags = val;
867 }
868
869 u_int32_t
ac97_getflags(struct ac97_info * codec)870 ac97_getflags(struct ac97_info *codec)
871 {
872 return codec->flags;
873 }
874
875 /* -------------------------------------------------------------------- */
876
877 static int
sysctl_hw_snd_ac97_eapd(SYSCTL_HANDLER_ARGS)878 sysctl_hw_snd_ac97_eapd(SYSCTL_HANDLER_ARGS)
879 {
880 struct ac97_info *codec;
881 int ea, inv, err = 0;
882 u_int16_t val;
883
884 codec = oidp->oid_arg1;
885 if (codec == NULL || codec->id == 0 || codec->lock == NULL)
886 return EINVAL;
887 snd_mtxlock(codec->lock);
888 val = ac97_rdcd(codec, AC97_REG_POWER);
889 inv = (codec->flags & AC97_F_EAPD_INV) ? 0 : 1;
890 ea = (val >> 15) ^ inv;
891 snd_mtxunlock(codec->lock);
892 err = sysctl_handle_int(oidp, &ea, 0, req);
893 if (err == 0 && req->newptr != NULL) {
894 if (ea != 0 && ea != 1)
895 return EINVAL;
896 if (ea != ((val >> 15) ^ inv)) {
897 snd_mtxlock(codec->lock);
898 ac97_wrcd(codec, AC97_REG_POWER, val ^ 0x8000);
899 snd_mtxunlock(codec->lock);
900 }
901 }
902 return err;
903 }
904
905 static void
ac97_init_sysctl(struct ac97_info * codec)906 ac97_init_sysctl(struct ac97_info *codec)
907 {
908 u_int16_t orig, val;
909
910 if (codec == NULL || codec->dev == NULL)
911 return;
912 snd_mtxlock(codec->lock);
913 orig = ac97_rdcd(codec, AC97_REG_POWER);
914 ac97_wrcd(codec, AC97_REG_POWER, orig ^ 0x8000);
915 val = ac97_rdcd(codec, AC97_REG_POWER);
916 ac97_wrcd(codec, AC97_REG_POWER, orig);
917 snd_mtxunlock(codec->lock);
918 if ((val & 0x8000) == (orig & 0x8000))
919 return;
920 SYSCTL_ADD_PROC(device_get_sysctl_ctx(codec->dev),
921 SYSCTL_CHILDREN(device_get_sysctl_tree(codec->dev)),
922 OID_AUTO, "eapd",
923 CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_MPSAFE,
924 codec, sizeof(codec), sysctl_hw_snd_ac97_eapd,
925 "I", "AC97 External Amplifier");
926 }
927
928 static int
ac97mix_init(struct snd_mixer * m)929 ac97mix_init(struct snd_mixer *m)
930 {
931 struct ac97_info *codec = mix_getdevinfo(m);
932 u_int32_t i, mask;
933
934 if (codec == NULL)
935 return -1;
936
937 if (ac97_initmixer(codec))
938 return -1;
939
940 switch (codec->id) {
941 case 0x41445374: /* AD1981B */
942 switch (codec->subvendor) {
943 case 0x02d91014:
944 /*
945 * IBM Thinkcentre:
946 *
947 * Tie "ogain" and "phout" to "vol" since its
948 * master volume is basically useless and can't
949 * control anything.
950 */
951 mask = 0;
952 if (codec->mix[SOUND_MIXER_OGAIN].enable)
953 mask |= SOUND_MASK_OGAIN;
954 if (codec->mix[SOUND_MIXER_PHONEOUT].enable)
955 mask |= SOUND_MASK_PHONEOUT;
956 if (codec->mix[SOUND_MIXER_VOLUME].enable)
957 mix_setparentchild(m, SOUND_MIXER_VOLUME,
958 mask);
959 else {
960 mix_setparentchild(m, SOUND_MIXER_VOLUME,
961 mask);
962 mix_setrealdev(m, SOUND_MIXER_VOLUME,
963 SOUND_MIXER_NONE);
964 }
965 break;
966 case 0x099c103c:
967 /*
968 * HP nx6110:
969 *
970 * By default, "vol" is controlling internal speakers
971 * (not a master volume!) and "ogain" is controlling
972 * headphone. Enable dummy "phout" so it can be
973 * remapped to internal speakers and virtualize
974 * "vol" to control both.
975 */
976 codec->mix[SOUND_MIXER_OGAIN].enable = 1;
977 codec->mix[SOUND_MIXER_PHONEOUT].enable = 1;
978 mix_setrealdev(m, SOUND_MIXER_PHONEOUT,
979 SOUND_MIXER_VOLUME);
980 mix_setrealdev(m, SOUND_MIXER_VOLUME,
981 SOUND_MIXER_NONE);
982 mix_setparentchild(m, SOUND_MIXER_VOLUME,
983 SOUND_MASK_OGAIN | SOUND_MASK_PHONEOUT);
984 break;
985 default:
986 break;
987 }
988 break;
989 case 0x434d4941: /* CMI9738 */
990 case 0x434d4961: /* CMI9739 */
991 case 0x434d4978: /* CMI9761 */
992 case 0x434d4982: /* CMI9761 */
993 case 0x434d4983: /* CMI9761 */
994 bzero(&codec->mix[SOUND_MIXER_PCM],
995 sizeof(codec->mix[SOUND_MIXER_PCM]));
996 pcm_setflags(codec->dev, pcm_getflags(codec->dev) |
997 SD_F_SOFTPCMVOL);
998 /* XXX How about master volume ? */
999 break;
1000 default:
1001 break;
1002 }
1003
1004 if (pcm_getflags(codec->dev) & SD_F_SOFTPCMVOL)
1005 ac97_wrcd(codec, AC97_MIX_PCM, 0);
1006 #if 0
1007 /* XXX For the sake of debugging purposes */
1008 mix_setparentchild(m, SOUND_MIXER_VOLUME,
1009 SOUND_MASK_PCM | SOUND_MASK_CD);
1010 mix_setrealdev(m, SOUND_MIXER_VOLUME, SOUND_MIXER_NONE);
1011 ac97_wrcd(codec, AC97_MIX_MASTER, 0);
1012 #endif
1013
1014 mask = 0;
1015 for (i = 0; i < AC97_MIXER_SIZE; i++)
1016 mask |= codec->mix[i].enable? 1 << i : 0;
1017 mix_setdevs(m, mask);
1018
1019 mask = 0;
1020 for (i = 0; i < AC97_MIXER_SIZE; i++)
1021 mask |= codec->mix[i].recidx? 1 << i : 0;
1022 mix_setrecdevs(m, mask);
1023
1024 ac97_init_sysctl(codec);
1025
1026 return 0;
1027 }
1028
1029 static int
ac97mix_uninit(struct snd_mixer * m)1030 ac97mix_uninit(struct snd_mixer *m)
1031 {
1032 struct ac97_info *codec = mix_getdevinfo(m);
1033
1034 if (codec == NULL)
1035 return -1;
1036 /*
1037 if (ac97_uninitmixer(codec))
1038 return -1;
1039 */
1040 ac97_destroy(codec);
1041 return 0;
1042 }
1043
1044 static int
ac97mix_reinit(struct snd_mixer * m)1045 ac97mix_reinit(struct snd_mixer *m)
1046 {
1047 struct ac97_info *codec = mix_getdevinfo(m);
1048
1049 if (codec == NULL)
1050 return -1;
1051 return ac97_reinitmixer(codec);
1052 }
1053
1054 static int
ac97mix_set(struct snd_mixer * m,unsigned dev,unsigned left,unsigned right)1055 ac97mix_set(struct snd_mixer *m, unsigned dev, unsigned left, unsigned right)
1056 {
1057 struct ac97_info *codec = mix_getdevinfo(m);
1058
1059 if (codec == NULL || dev >= AC97_MIXER_SIZE)
1060 return -1;
1061 return ac97_setmixer(codec, dev, left, right);
1062 }
1063
1064 static u_int32_t
ac97mix_setrecsrc(struct snd_mixer * m,u_int32_t src)1065 ac97mix_setrecsrc(struct snd_mixer *m, u_int32_t src)
1066 {
1067 int i;
1068 struct ac97_info *codec = mix_getdevinfo(m);
1069
1070 if (codec == NULL)
1071 return -1;
1072 for (i = 0; i < AC97_MIXER_SIZE; i++)
1073 if ((src & (1 << i)) != 0)
1074 break;
1075 return (ac97_setrecsrc(codec, i) == 0)? 1U << i : 0xffffffffU;
1076 }
1077
1078 static kobj_method_t ac97mixer_methods[] = {
1079 KOBJMETHOD(mixer_init, ac97mix_init),
1080 KOBJMETHOD(mixer_uninit, ac97mix_uninit),
1081 KOBJMETHOD(mixer_reinit, ac97mix_reinit),
1082 KOBJMETHOD(mixer_set, ac97mix_set),
1083 KOBJMETHOD(mixer_setrecsrc, ac97mix_setrecsrc),
1084 KOBJMETHOD_END
1085 };
1086 MIXER_DECLARE(ac97mixer);
1087
1088 /* -------------------------------------------------------------------- */
1089
1090 kobj_class_t
ac97_getmixerclass(void)1091 ac97_getmixerclass(void)
1092 {
1093 return &ac97mixer_class;
1094 }
1095