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