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