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