kernel - Get rid of old KDSETRAD keyboard ioctl, and some __i386__ kbd code.
[dragonfly.git] / sys / dev / sound / pcm / ac97.c
blob0735a2950cc6c6c96036de5344539139f6b186b2
1 /*-
2 * Copyright (c) 1999 Cameron Grant <cg@freebsd.org>
3 * All rights reserved.
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.
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.
27 #ifdef HAVE_KERNEL_OPTION_HEADERS
28 #include "opt_snd.h"
29 #endif
31 #include <dev/sound/pcm/sound.h>
32 #include <dev/sound/pcm/ac97.h>
33 #include <dev/sound/pcm/ac97_patch.h>
35 #include <bus/pci/pcivar.h>
37 #include "mixer_if.h"
39 SND_DECLARE_FILE("$FreeBSD: head/sys/dev/sound/pcm/ac97.c 227293 2011-11-07 06:44:47Z ed $");
41 static MALLOC_DEFINE(M_AC97, "ac97", "ac97 codec");
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 */
55 #define AC97_MIXER_SIZE SOUND_MIXER_NRDEVICES
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 lock *lock;
70 struct ac97_vendorid {
71 u_int32_t id;
72 const char *name;
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;
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 }
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" },
128 * XXX This is a fluke, really! The real vendor
129 * should be SigmaTel, not this! This should be
130 * removed someday!
132 { 0x01408300, "Creative" },
133 { 0x00000000, NULL }
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 },
235 * XXX This is a fluke, really! The real codec
236 * should be STAC9704, not this! This should be
237 * removed someday!
239 { 0x01408384, 0x00, 0, "EV1938", 0 },
240 { 0, 0, 0, NULL, 0 }
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"
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"
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",
308 u_int16_t
309 ac97_rdcd(struct ac97_info *codec, int reg)
311 if (codec->flags & AC97_F_RDCD_BUG) {
312 u_int16_t i[2], j = 100;
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);
323 #endif
324 return i[!(j & 1)];
326 return AC97_READ(codec->methods, codec->devinfo, reg);
329 void
330 ac97_wrcd(struct ac97_info *codec, int reg, u_int16_t val)
332 AC97_WRITE(codec->methods, codec->devinfo, reg, val);
335 static void
336 ac97_reset(struct ac97_info *codec)
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);
346 device_printf(codec->dev, "AC97 reset timed out.\n");
350 ac97_setrate(struct ac97_info *codec, int which, int rate)
352 u_int16_t v;
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;
362 default:
363 return -1;
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);
373 v = ac97_rdcd(codec, which);
374 if (codec->extstat & AC97_EXTCAP_DRA)
375 v <<= 1;
376 snd_mtxunlock(codec->lock);
377 return v;
381 ac97_setextmode(struct ac97_info *codec, u_int16_t mode)
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;
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;
396 u_int16_t
397 ac97_getextmode(struct ac97_info *codec)
399 return codec->extstat;
402 u_int16_t
403 ac97_getextcaps(struct ac97_info *codec)
405 return codec->extcaps;
408 u_int16_t
409 ac97_getcaps(struct ac97_info *codec)
411 return codec->caps;
414 u_int32_t
415 ac97_getsubvendor(struct ac97_info *codec)
417 return codec->subvendor;
420 static int
421 ac97_setrecsrc(struct ac97_info *codec, int channel)
423 struct ac97mixtable_entry *e = &codec->mix[channel];
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;
436 static int
437 ac97_setmixer(struct ac97_info *codec, unsigned channel, unsigned left, unsigned right)
439 struct ac97mixtable_entry *e = &codec->mix[channel];
441 if (e->reg && e->enable && e->bits) {
442 int mask, max, val, reg;
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 */
448 if (!e->stereo)
449 right = left;
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.
457 if (e->reg > 0) {
458 left = 100 - left;
459 right = 100 - right;
462 left = (left * max) / 100;
463 right = (right * max) / 100;
465 val = (left << 8) | right;
467 left = (left * 100) / max;
468 right = (right * 100) / max;
470 if (e->reg > 0) {
471 left = 100 - left;
472 right = 100 - right;
476 * For mono controls, trim val and mask, also taking
477 * care of e->ofs (offset of control field).
479 if (e->ofs) {
480 val &= max;
481 val <<= e->ofs;
482 mask = (max << e->ofs);
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.
490 if (e->mute == 1) {
491 mask |= AC97_MUTE;
492 if (left == 0 && right == 0)
493 val = AC97_MUTE;
497 * If the mask bit is set, do not alter the other bits.
499 snd_mtxlock(codec->lock);
500 if (e->mask) {
501 int cur = ac97_rdcd(codec, reg);
502 val |= cur & ~(mask);
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;
515 static void
516 ac97_fix_auxout(struct ac97_info *codec)
518 int keep_ogain;
521 * By default, The ac97 aux_out register (0x04) corresponds to OSS's
522 * OGAIN setting.
524 * We first check whether aux_out is a valid register. If not
525 * we may not want to keep ogain.
527 keep_ogain = ac97_rdcd(codec, AC97_MIX_AUXOUT) & 0x8000;
530 * Determine what AUX_OUT really means, it can be:
532 * 1. Headphone out.
533 * 2. 4-Channel Out
534 * 3. True line level out (effectively master volume).
536 * See Sections 5.2.1 and 5.27 for AUX_OUT Options in AC97r2.{2,3}.
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;
544 if (keep_ogain == 0) {
545 bzero(&codec->mix[SOUND_MIXER_OGAIN],
546 sizeof(codec->mix[SOUND_MIXER_OGAIN]));
550 static void
551 ac97_fix_tone(struct ac97_info *codec)
554 * YMF chips does not indicate tone and 3D enhancement capability
555 * in the AC97_REG_RESET register.
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;
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]));
579 static const char*
580 ac97_hw_desc(u_int32_t id, const char* vname, const char* cname, char* buf)
582 if (cname == NULL) {
583 ksprintf(buf, "Unknown AC97 Codec (id = 0x%08x)", id);
584 return buf;
587 if (vname == NULL) vname = "Unknown";
589 if (bootverbose) {
590 ksprintf(buf, "%s %s AC97 Codec (id = 0x%08x)", vname, cname, id);
591 } else {
592 ksprintf(buf, "%s %s AC97 Codec", vname, cname);
594 return buf;
597 static unsigned
598 ac97_initmixer(struct ac97_info *codec)
600 ac97_patch codec_patch;
601 const char *cname, *vname;
602 char desc[80];
603 u_int8_t model, step;
604 unsigned i, j, k, bit, old;
605 u_int32_t id;
606 int reg;
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;
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);
620 i = ac97_rdcd(codec, AC97_REG_RESET);
621 j = ac97_rdcd(codec, AC97_REG_RESET);
622 k = ac97_rdcd(codec, AC97_REG_RESET);
624 * Let see if this codec can return consistent value.
625 * If not, turn on aggressive read workaround
626 * (STAC9704 comes in mind).
628 if (i != j || j != k) {
629 codec->flags |= AC97_F_RDCD_BUG;
630 i = ac97_rdcd(codec, AC97_REG_RESET);
632 codec->caps = i & 0x03ff;
633 codec->se = (i & 0x7c00) >> 10;
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;
642 codec->id = id;
643 codec->subvendor = (u_int32_t)pci_get_subdevice(codec->dev) << 16;
644 codec->subvendor |= (u_int32_t)pci_get_subvendor(codec->dev) &
645 0x0000ffff;
646 codec->noext = 0;
647 codec_patch = NULL;
649 cname = NULL;
650 model = step = 0;
651 for (i = 0; ac97codecid[i].id; i++) {
652 u_int32_t modelmask = 0xffffffff ^ ac97codecid[i].stepmask;
653 if ((ac97codecid[i].id & modelmask) == (id & modelmask)) {
654 codec->noext = ac97codecid[i].noext;
655 codec_patch = ac97codecid[i].patch;
656 cname = ac97codecid[i].name;
657 model = (id & modelmask) & 0xff;
658 step = (id & ~modelmask) & 0xff;
659 break;
663 vname = NULL;
664 for (i = 0; ac97vendorid[i].id; i++) {
665 if (ac97vendorid[i].id == (id & 0xffffff00)) {
666 vname = ac97vendorid[i].name;
667 break;
671 codec->extcaps = 0;
672 codec->extid = 0;
673 codec->extstat = 0;
674 if (!codec->noext) {
675 i = ac97_rdcd(codec, AC97_REGEXT_ID);
676 if (i != 0xffff) {
677 codec->extcaps = i & 0x3fff;
678 codec->extid = (i & 0xc000) >> 14;
679 codec->extstat = ac97_rdcd(codec, AC97_REGEXT_STAT) & AC97_EXTCAPS;
683 for (i = 0; i < AC97_MIXER_SIZE; i++) {
684 codec->mix[i] = ac97mixtable_default[i];
686 ac97_fix_auxout(codec);
687 ac97_fix_tone(codec);
688 if (codec_patch)
689 codec_patch(codec);
691 for (i = 0; i < AC97_MIXER_SIZE; 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);
699 * Test for mute bit (except for AC97_MIX_TONE,
700 * where we simply assume it as available).
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)) {
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).
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++)
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) {
739 * Few codec such as CX20468-21 does
740 * have this control register, although
741 * the only usable part is the mute bit.
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);
750 #if 0
751 printf("mixch %d, en=%d, b=%d\n", i, codec->mix[i].enable, codec->mix[i].bits);
752 #endif
755 device_printf(codec->dev, "<%s>\n",
756 ac97_hw_desc(codec->id, vname, cname, desc));
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 device_printf(codec->dev, "Codec features ");
762 for (i = j = 0; i < 10; i++)
763 if (codec->caps & (1 << i))
764 kprintf("%s%s", j++? ", " : "", ac97feature[i]);
765 kprintf("%s%d bit master volume", j++? ", " : "", codec->mix[SOUND_MIXER_VOLUME].bits);
766 kprintf("%s%s\n", j? ", " : "", ac97enhancement[codec->se]);
768 if (codec->extcaps != 0 || codec->extid) {
769 device_printf(codec->dev, "%s codec",
770 codec->extid? "Secondary" : "Primary");
771 if (codec->extcaps)
772 kprintf(" extended features ");
773 for (i = j = 0; i < 14; i++)
774 if (codec->extcaps & (1 << i))
775 kprintf("%s%s", j++? ", " : "", ac97extfeature[i]);
776 kprintf("\n");
780 i = 0;
781 while ((ac97_rdcd(codec, AC97_REG_POWER) & 2) == 0) {
782 if (++i == 100) {
783 device_printf(codec->dev, "ac97 codec reports dac not ready\n");
784 break;
786 DELAY(1000);
788 if (bootverbose)
789 device_printf(codec->dev, "ac97 codec dac ready count: %d\n", i);
790 snd_mtxunlock(codec->lock);
791 return 0;
794 static unsigned
795 ac97_reinitmixer(struct ac97_info *codec)
797 snd_mtxlock(codec->lock);
798 codec->count = AC97_INIT(codec->methods, codec->devinfo);
799 if (codec->count == 0) {
800 device_printf(codec->dev, "ac97 codec init failed\n");
801 snd_mtxunlock(codec->lock);
802 return ENODEV;
805 ac97_wrcd(codec, AC97_REG_POWER, (codec->flags & AC97_F_EAPD_INV)? 0x8000 : 0x0000);
806 ac97_reset(codec);
807 ac97_wrcd(codec, AC97_REG_POWER, (codec->flags & AC97_F_EAPD_INV)? 0x8000 : 0x0000);
809 if (!codec->noext) {
810 ac97_wrcd(codec, AC97_REGEXT_STAT, codec->extstat);
811 if ((ac97_rdcd(codec, AC97_REGEXT_STAT) & AC97_EXTCAPS)
812 != codec->extstat)
813 device_printf(codec->dev, "ac97 codec failed to reset extended mode (%x, got %x)\n",
814 codec->extstat,
815 ac97_rdcd(codec, AC97_REGEXT_STAT) &
816 AC97_EXTCAPS);
819 if ((ac97_rdcd(codec, AC97_REG_POWER) & 2) == 0)
820 device_printf(codec->dev, "ac97 codec reports dac not ready\n");
821 snd_mtxunlock(codec->lock);
822 return 0;
825 struct ac97_info *
826 ac97_create(device_t dev, void *devinfo, kobj_class_t cls)
828 struct ac97_info *codec;
829 int i;
831 codec = kmalloc(sizeof(*codec), M_AC97, M_WAITOK | M_ZERO);
832 ksnprintf(codec->name, sizeof(codec->name), "%s:ac97",
833 device_get_nameunit(dev));
834 codec->lock = snd_mtxcreate(codec->name, "ac97 codec");
835 codec->methods = kobj_create(cls, M_AC97, M_WAITOK | M_ZERO);
836 codec->dev = dev;
837 codec->devinfo = devinfo;
838 codec->flags = 0;
840 if (resource_int_value(device_get_name(dev), device_get_unit(dev),
841 "eapdinv", &i) == 0 && i != 0)
842 codec->flags |= AC97_F_EAPD_INV;
844 if (resource_int_value(device_get_name(dev), device_get_unit(dev),
845 "softpcmvol", &i) == 0 && i != 0)
846 pcm_setflags(dev, pcm_getflags(dev) | SD_F_SOFTPCMVOL);
848 return codec;
851 void
852 ac97_destroy(struct ac97_info *codec)
854 snd_mtxlock(codec->lock);
855 if (codec->methods != NULL)
856 kobj_delete(codec->methods, M_AC97);
857 snd_mtxfree(codec->lock);
858 kfree(codec, M_AC97);
861 void
862 ac97_setflags(struct ac97_info *codec, u_int32_t val)
864 codec->flags = val;
867 u_int32_t
868 ac97_getflags(struct ac97_info *codec)
870 return codec->flags;
873 /* -------------------------------------------------------------------- */
875 static int
876 sysctl_hw_snd_ac97_eapd(SYSCTL_HANDLER_ARGS)
878 struct ac97_info *codec;
879 int ea, inv, err = 0;
880 u_int16_t val;
882 codec = oidp->oid_arg1;
883 if (codec == NULL || codec->id == 0 || codec->lock == NULL)
884 return EINVAL;
885 snd_mtxlock(codec->lock);
886 val = ac97_rdcd(codec, AC97_REG_POWER);
887 inv = (codec->flags & AC97_F_EAPD_INV) ? 0 : 1;
888 ea = (val >> 15) ^ inv;
889 snd_mtxunlock(codec->lock);
890 err = sysctl_handle_int(oidp, &ea, 0, req);
891 if (err == 0 && req->newptr != NULL) {
892 if (ea != 0 && ea != 1)
893 return EINVAL;
894 if (ea != ((val >> 15) ^ inv)) {
895 snd_mtxlock(codec->lock);
896 ac97_wrcd(codec, AC97_REG_POWER, val ^ 0x8000);
897 snd_mtxunlock(codec->lock);
900 return err;
903 static void
904 ac97_init_sysctl(struct ac97_info *codec)
906 u_int16_t orig, val;
908 if (codec == NULL || codec->dev == NULL)
909 return;
910 snd_mtxlock(codec->lock);
911 orig = ac97_rdcd(codec, AC97_REG_POWER);
912 ac97_wrcd(codec, AC97_REG_POWER, orig ^ 0x8000);
913 val = ac97_rdcd(codec, AC97_REG_POWER);
914 ac97_wrcd(codec, AC97_REG_POWER, orig);
915 snd_mtxunlock(codec->lock);
916 if ((val & 0x8000) == (orig & 0x8000))
917 return;
918 SYSCTL_ADD_PROC(device_get_sysctl_ctx(codec->dev),
919 SYSCTL_CHILDREN(device_get_sysctl_tree(codec->dev)),
920 OID_AUTO, "eapd", CTLTYPE_INT | CTLFLAG_RW,
921 codec, sizeof(codec), sysctl_hw_snd_ac97_eapd,
922 "I", "AC97 External Amplifier");
925 static int
926 ac97mix_init(struct snd_mixer *m)
928 struct ac97_info *codec = mix_getdevinfo(m);
929 u_int32_t i, mask;
931 if (codec == NULL)
932 return -1;
934 if (ac97_initmixer(codec))
935 return -1;
937 switch (codec->id) {
938 case 0x41445374: /* AD1981B */
939 switch (codec->subvendor) {
940 case 0x02d91014:
942 * IBM Thinkcentre:
944 * Tie "ogain" and "phout" to "vol" since its
945 * master volume is basically useless and can't
946 * control anything.
948 mask = 0;
949 if (codec->mix[SOUND_MIXER_OGAIN].enable)
950 mask |= SOUND_MASK_OGAIN;
951 if (codec->mix[SOUND_MIXER_PHONEOUT].enable)
952 mask |= SOUND_MASK_PHONEOUT;
953 if (codec->mix[SOUND_MIXER_VOLUME].enable)
954 mix_setparentchild(m, SOUND_MIXER_VOLUME,
955 mask);
956 else {
957 mix_setparentchild(m, SOUND_MIXER_VOLUME,
958 mask);
959 mix_setrealdev(m, SOUND_MIXER_VOLUME,
960 SOUND_MIXER_NONE);
962 break;
963 case 0x099c103c:
965 * HP nx6110:
967 * By default, "vol" is controlling internal speakers
968 * (not a master volume!) and "ogain" is controlling
969 * headphone. Enable dummy "phout" so it can be
970 * remapped to internal speakers and virtualize
971 * "vol" to control both.
973 codec->mix[SOUND_MIXER_OGAIN].enable = 1;
974 codec->mix[SOUND_MIXER_PHONEOUT].enable = 1;
975 mix_setrealdev(m, SOUND_MIXER_PHONEOUT,
976 SOUND_MIXER_VOLUME);
977 mix_setrealdev(m, SOUND_MIXER_VOLUME,
978 SOUND_MIXER_NONE);
979 mix_setparentchild(m, SOUND_MIXER_VOLUME,
980 SOUND_MASK_OGAIN | SOUND_MASK_PHONEOUT);
981 break;
982 default:
983 break;
985 break;
986 case 0x434d4941: /* CMI9738 */
987 case 0x434d4961: /* CMI9739 */
988 case 0x434d4978: /* CMI9761 */
989 case 0x434d4982: /* CMI9761 */
990 case 0x434d4983: /* CMI9761 */
991 bzero(&codec->mix[SOUND_MIXER_PCM],
992 sizeof(codec->mix[SOUND_MIXER_PCM]));
993 pcm_setflags(codec->dev, pcm_getflags(codec->dev) |
994 SD_F_SOFTPCMVOL);
995 /* XXX How about master volume ? */
996 break;
997 default:
998 break;
1001 if (pcm_getflags(codec->dev) & SD_F_SOFTPCMVOL)
1002 ac97_wrcd(codec, AC97_MIX_PCM, 0);
1003 #if 0
1004 /* XXX For the sake of debugging purposes */
1005 mix_setparentchild(m, SOUND_MIXER_VOLUME,
1006 SOUND_MASK_PCM | SOUND_MASK_CD);
1007 mix_setrealdev(m, SOUND_MIXER_VOLUME, SOUND_MIXER_NONE);
1008 ac97_wrcd(codec, AC97_MIX_MASTER, 0);
1009 #endif
1011 mask = 0;
1012 for (i = 0; i < AC97_MIXER_SIZE; i++)
1013 mask |= codec->mix[i].enable? 1 << i : 0;
1014 mix_setdevs(m, mask);
1016 mask = 0;
1017 for (i = 0; i < AC97_MIXER_SIZE; i++)
1018 mask |= codec->mix[i].recidx? 1 << i : 0;
1019 mix_setrecdevs(m, mask);
1021 ac97_init_sysctl(codec);
1023 return 0;
1026 static int
1027 ac97mix_uninit(struct snd_mixer *m)
1029 struct ac97_info *codec = mix_getdevinfo(m);
1031 if (codec == NULL)
1032 return -1;
1034 if (ac97_uninitmixer(codec))
1035 return -1;
1037 ac97_destroy(codec);
1038 return 0;
1041 static int
1042 ac97mix_reinit(struct snd_mixer *m)
1044 struct ac97_info *codec = mix_getdevinfo(m);
1046 if (codec == NULL)
1047 return -1;
1048 return ac97_reinitmixer(codec);
1051 static int
1052 ac97mix_set(struct snd_mixer *m, unsigned dev, unsigned left, unsigned right)
1054 struct ac97_info *codec = mix_getdevinfo(m);
1056 if (codec == NULL || dev >= AC97_MIXER_SIZE)
1057 return -1;
1058 return ac97_setmixer(codec, dev, left, right);
1061 static u_int32_t
1062 ac97mix_setrecsrc(struct snd_mixer *m, u_int32_t src)
1064 int i;
1065 struct ac97_info *codec = mix_getdevinfo(m);
1067 if (codec == NULL)
1068 return -1;
1069 for (i = 0; i < AC97_MIXER_SIZE; i++)
1070 if ((src & (1 << i)) != 0)
1071 break;
1072 return (ac97_setrecsrc(codec, i) == 0)? 1U << i : 0xffffffffU;
1075 static kobj_method_t ac97mixer_methods[] = {
1076 KOBJMETHOD(mixer_init, ac97mix_init),
1077 KOBJMETHOD(mixer_uninit, ac97mix_uninit),
1078 KOBJMETHOD(mixer_reinit, ac97mix_reinit),
1079 KOBJMETHOD(mixer_set, ac97mix_set),
1080 KOBJMETHOD(mixer_setrecsrc, ac97mix_setrecsrc),
1081 KOBJMETHOD_END
1083 MIXER_DECLARE(ac97mixer);
1085 /* -------------------------------------------------------------------- */
1087 kobj_class_t
1088 ac97_getmixerclass(void)
1090 return &ac97mixer_class;