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