Misc cleanups to take care of GCC3.x warnings. Missing 'U' and 'LL'
[dragonfly.git] / sys / dev / sound / pcm / ac97.c
1 /*
2  * Copyright (c) 1999 Cameron Grant <gandalf@vilnya.demon.co.uk>
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.5.2.14 2003/03/11 15:08:30 orion Exp $
27  * $DragonFly: src/sys/dev/sound/pcm/ac97.c,v 1.2 2003/06/17 04:28:31 dillon 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
37 SND_DECLARE_FILE("$DragonFly: src/sys/dev/sound/pcm/ac97.c,v 1.2 2003/06/17 04:28:31 dillon Exp $");
38
39 MALLOC_DEFINE(M_AC97, "ac97", "ac97 codec");
40
41 struct ac97mixtable_entry {
42         int             reg:8;
43         unsigned        bits:4;
44         unsigned        ofs:4;
45         unsigned        stereo:1;
46         unsigned        mute:1;
47         unsigned        recidx:4;
48         unsigned        mask:1;
49         unsigned        enable:1;
50 };
51
52 #define AC97_NAMELEN    16
53 struct ac97_info {
54         kobj_t methods;
55         device_t dev;
56         void *devinfo;
57         char *id;
58         char rev;
59         unsigned count, caps, se, extcaps, extid, extstat, noext:1;
60         u_int32_t flags;
61         struct ac97mixtable_entry mix[32];
62         char name[AC97_NAMELEN];
63         void *lock;
64 };
65
66 struct ac97_codecid {
67         u_int32_t id, noext:1;
68         char *name;
69         ac97_patch patch;
70 };
71
72 static const struct ac97mixtable_entry ac97mixtable_default[32] = {
73         [SOUND_MIXER_VOLUME]    = { AC97_MIX_MASTER,    5, 0, 1, 1, 6, 0, 1 },
74         [SOUND_MIXER_MONITOR]   = { AC97_MIX_AUXOUT,    5, 0, 1, 1, 0, 0, 0 },
75         [SOUND_MIXER_PHONEOUT]  = { AC97_MIX_MONO,      5, 0, 0, 1, 7, 0, 0 },
76         [SOUND_MIXER_BASS]      = { AC97_MIX_TONE,      4, 8, 0, 0, 0, 1, 0 },
77         [SOUND_MIXER_TREBLE]    = { AC97_MIX_TONE,      4, 0, 0, 0, 0, 1, 0 },
78         [SOUND_MIXER_PCM]       = { AC97_MIX_PCM,       5, 0, 1, 1, 0, 0, 1 },
79         [SOUND_MIXER_SPEAKER]   = { AC97_MIX_BEEP,      4, 1, 0, 1, 0, 0, 0 },
80         [SOUND_MIXER_LINE]      = { AC97_MIX_LINE,      5, 0, 1, 1, 5, 0, 1 },
81         [SOUND_MIXER_PHONEIN]   = { AC97_MIX_PHONE,     5, 0, 0, 1, 8, 0, 0 },
82         [SOUND_MIXER_MIC]       = { AC97_MIX_MIC,       5, 0, 0, 1, 1, 0, 1 },
83         [SOUND_MIXER_CD]        = { AC97_MIX_CD,        5, 0, 1, 1, 2, 0, 1 },
84         [SOUND_MIXER_LINE1]     = { AC97_MIX_AUX,       5, 0, 1, 1, 4, 0, 0 },
85         [SOUND_MIXER_VIDEO]     = { AC97_MIX_VIDEO,     5, 0, 1, 1, 3, 0, 0 },
86         [SOUND_MIXER_RECLEV]    = { -AC97_MIX_RGAIN,    4, 0, 1, 1, 0, 0, 1 }
87 };
88
89 static struct ac97_codecid ac97codecid[] = {
90         { 0x41445303, 0, "Analog Devices AD1819",       0 },
91         { 0x41445340, 0, "Analog Devices AD1881",       0 },
92         { 0x41445348, 0, "Analog Devices AD1881A",      0 },
93         { 0x41445360, 0, "Analog Devices AD1885",       0 },
94         { 0x41445361, 0, "Analog Devices AD1886",       ad1886_patch },
95         { 0x414b4d00, 1, "Asahi Kasei AK4540",          0 },
96         { 0x414b4d01, 1, "Asahi Kasei AK4542",          0 },
97         { 0x414b4d02, 1, "Asahi Kasei AK4543",          0 },
98         { 0x414c4710, 0, "Avance Logic ALC200/200P",    0 },
99         { 0x414c4720, 0, "Realtek ALC650",              0 },
100         { 0x43525900, 0, "Cirrus Logic CS4297",         0 },
101         { 0x43525903, 0, "Cirrus Logic CS4297",         0 },
102         { 0x43525913, 0, "Cirrus Logic CS4297A",        0 },
103         { 0x43525914, 0, "Cirrus Logic CS4297B",        0 },
104         { 0x43525923, 0, "Cirrus Logic CS4294C",        0 },
105         { 0x4352592b, 0, "Cirrus Logic CS4298C",        0 },
106         { 0x43525931, 0, "Cirrus Logic CS4299A",        0 },
107         { 0x43525933, 0, "Cirrus Logic CS4299C",        0 },
108         { 0x43525934, 0, "Cirrus Logic CS4299D/E/F/G/H", 0 },
109         { 0x43525935, 0, "Cirrus Logic CS4299K",        0 },
110         { 0x43525936, 0, "Cirrus Logic CS4299L",        0 },
111         { 0x43525941, 0, "Cirrus Logic CS4201A",        0 },
112         { 0x43525951, 0, "Cirrus Logic CS4205A",        0 },
113         { 0x43525961, 0, "Cirrus Logic CS4291A",        0 },
114         { 0x43585429, 0, "Conexant CX20468",            0 },
115         { 0x45838308, 0, "ESS Technology ES1921",       0 },
116         { 0x49434511, 0, "ICEnsemble ICE1232",          0 },
117         { 0x4e534331, 0, "National Semiconductor LM4549", 0 },
118         { 0x83847600, 0, "SigmaTel STAC9700/9783/9784", 0 },
119         { 0x83847604, 0, "SigmaTel STAC9701/9703/9704/9705", 0 },
120         { 0x83847605, 0, "SigmaTel STAC9704",           0 },
121         { 0x83847608, 0, "SigmaTel STAC9708/9711",      0 },
122         { 0x83847609, 0, "SigmaTel STAC9721/9723",      0 },
123         { 0x83847644, 0, "SigmaTel STAC9744",           0 },
124         { 0x83847656, 0, "SigmaTel STAC9756/9757",      0 },
125         { 0x53494c22, 0, "Silicon Laboratory Si3036",   0 },
126         { 0x53494c23, 0, "Silicon Laboratory Si3038",   0 },
127         { 0x54524103, 0, "TriTech TR28023",             0 },
128         { 0x54524106, 0, "TriTech TR28026",             0 },
129         { 0x54524108, 0, "TriTech TR28028",             0 },
130         { 0x54524123, 0, "TriTech TR28602",             0 },
131         { 0x574d4c00, 0, "Wolfson WM9701A",             0 },
132         { 0x574d4c03, 0, "Wolfson WM9703/9704",         0 },
133         { 0x574d4c04, 0, "Wolfson WM9704 (quad)",       0 },
134         { 0, 0, NULL, 0 }
135 };
136
137 static char *ac97enhancement[] = {
138         "no 3D Stereo Enhancement",
139         "Analog Devices Phat Stereo",
140         "Creative Stereo Enhancement",
141         "National Semi 3D Stereo Enhancement",
142         "Yamaha Ymersion",
143         "BBE 3D Stereo Enhancement",
144         "Crystal Semi 3D Stereo Enhancement",
145         "Qsound QXpander",
146         "Spatializer 3D Stereo Enhancement",
147         "SRS 3D Stereo Enhancement",
148         "Platform Tech 3D Stereo Enhancement",
149         "AKM 3D Audio",
150         "Aureal Stereo Enhancement",
151         "Aztech 3D Enhancement",
152         "Binaura 3D Audio Enhancement",
153         "ESS Technology Stereo Enhancement",
154         "Harman International VMAx",
155         "Nvidea 3D Stereo Enhancement",
156         "Philips Incredible Sound",
157         "Texas Instruments 3D Stereo Enhancement",
158         "VLSI Technology 3D Stereo Enhancement",
159         "TriTech 3D Stereo Enhancement",
160         "Realtek 3D Stereo Enhancement",
161         "Samsung 3D Stereo Enhancement",
162         "Wolfson Microelectronics 3D Enhancement",
163         "Delta Integration 3D Enhancement",
164         "SigmaTel 3D Enhancement",
165         "Reserved 27",
166         "Rockwell 3D Stereo Enhancement",
167         "Reserved 29",
168         "Reserved 30",
169         "Reserved 31"
170 };
171
172 static char *ac97feature[] = {
173         "mic channel",
174         "reserved",
175         "tone",
176         "simulated stereo",
177         "headphone",
178         "bass boost",
179         "18 bit DAC",
180         "20 bit DAC",
181         "18 bit ADC",
182         "20 bit ADC"
183 };
184
185 static char *ac97extfeature[] = {
186         "variable rate PCM",
187         "double rate PCM",
188         "reserved 1",
189         "variable rate mic",
190         "reserved 2",
191         "reserved 3",
192         "center DAC",
193         "surround DAC",
194         "LFE DAC",
195         "AMAP",
196         "reserved 4",
197         "reserved 5",
198         "reserved 6",
199         "reserved 7",
200 };
201
202 u_int16_t
203 ac97_rdcd(struct ac97_info *codec, int reg)
204 {
205         return AC97_READ(codec->methods, codec->devinfo, reg);
206 }
207
208 void
209 ac97_wrcd(struct ac97_info *codec, int reg, u_int16_t val)
210 {
211         AC97_WRITE(codec->methods, codec->devinfo, reg, val);
212 }
213
214 static void
215 ac97_reset(struct ac97_info *codec)
216 {
217         u_int32_t i, ps;
218         ac97_wrcd(codec, AC97_REG_RESET, 0);
219         for (i = 0; i < 500; i++) {
220                 ps = ac97_rdcd(codec, AC97_REG_POWER) & AC97_POWER_STATUS;
221                 if (ps == AC97_POWER_STATUS)
222                         return;
223                 DELAY(1000);
224         }
225         device_printf(codec->dev, "AC97 reset timed out.\n");
226 }
227
228 int
229 ac97_setrate(struct ac97_info *codec, int which, int rate)
230 {
231         u_int16_t v;
232
233         switch(which) {
234         case AC97_REGEXT_FDACRATE: 
235         case AC97_REGEXT_SDACRATE:
236         case AC97_REGEXT_LDACRATE:
237         case AC97_REGEXT_LADCRATE: 
238         case AC97_REGEXT_MADCRATE:
239                 break;
240
241         default:
242                 return -1;
243         }
244
245         snd_mtxlock(codec->lock);
246         if (rate != 0) {
247                 v = rate;
248                 if (codec->extstat & AC97_EXTCAP_DRA)
249                         v >>= 1;
250                 ac97_wrcd(codec, which, v);
251         }
252         v = ac97_rdcd(codec, which);
253         if (codec->extstat & AC97_EXTCAP_DRA)
254                 v <<= 1;
255         snd_mtxunlock(codec->lock);
256         return v;
257 }
258
259 int
260 ac97_setextmode(struct ac97_info *codec, u_int16_t mode)
261 {
262         mode &= AC97_EXTCAPS;
263         if ((mode & ~codec->extcaps) != 0) {
264                 device_printf(codec->dev, "ac97 invalid mode set 0x%04x\n", 
265                               mode);
266                 return -1;
267         }
268         snd_mtxlock(codec->lock);
269         ac97_wrcd(codec, AC97_REGEXT_STAT, mode);
270         codec->extstat = ac97_rdcd(codec, AC97_REGEXT_STAT) & AC97_EXTCAPS;
271         snd_mtxunlock(codec->lock);
272         return (mode == codec->extstat)? 0 : -1;
273 }
274
275 u_int16_t
276 ac97_getextmode(struct ac97_info *codec)
277 {
278         return codec->extstat;
279 }
280
281 u_int16_t
282 ac97_getextcaps(struct ac97_info *codec)
283 {
284         return codec->extcaps;
285 }
286
287 u_int16_t
288 ac97_getcaps(struct ac97_info *codec)
289 {
290         return codec->caps;
291 }
292
293 static int
294 ac97_setrecsrc(struct ac97_info *codec, int channel)
295 {
296         struct ac97mixtable_entry *e = &codec->mix[channel];
297
298         if (e->recidx > 0) {
299                 int val = e->recidx - 1;
300                 val |= val << 8;
301                 snd_mtxlock(codec->lock);
302                 ac97_wrcd(codec, AC97_REG_RECSEL, val);
303                 snd_mtxunlock(codec->lock);
304                 return 0;
305         } else
306                 return -1;
307 }
308
309 static int
310 ac97_setmixer(struct ac97_info *codec, unsigned channel, unsigned left, unsigned right)
311 {
312         struct ac97mixtable_entry *e = &codec->mix[channel];
313
314         if (e->reg && e->enable && e->bits) {
315                 int max, val, reg = (e->reg >= 0)? e->reg : -e->reg;
316
317                 if (!e->stereo)
318                         right = left;
319                 if (e->reg > 0) {
320                         left = 100 - left;
321                         right = 100 - right;
322                 }
323
324                 max = (1 << e->bits) - 1;
325                 left = (left * max) / 100;
326                 right = (right * max) / 100;
327
328                 val = (left << 8) | right;
329
330                 left = (left * 100) / max;
331                 right = (right * 100) / max;
332
333                 if (e->reg > 0) {
334                         left = 100 - left;
335                         right = 100 - right;
336                 }
337
338                 if (!e->stereo) {
339                         val &= max;
340                         val <<= e->ofs;
341                         if (e->mask) {
342                                 int cur = ac97_rdcd(codec, e->reg);
343                                 val |= cur & ~(max << e->ofs);
344                         }
345                 }
346                 if (left == 0 && right == 0 && e->mute == 1)
347                         val = AC97_MUTE;
348                 snd_mtxlock(codec->lock);
349                 ac97_wrcd(codec, reg, val);
350                 snd_mtxunlock(codec->lock);
351                 return left | (right << 8);
352         } else {
353                 /* printf("ac97_setmixer: reg=%d, bits=%d, enable=%d\n", e->reg, e->bits, e->enable); */
354                 return -1;
355         }
356 }
357
358 #if 0
359 static int
360 ac97_getmixer(struct ac97_info *codec, int channel)
361 {
362         struct ac97mixtable_entry *e = &codec->mix[channel];
363         if (channel < SOUND_MIXER_NRDEVICES && e->reg != 0) {
364                 int max, val, volume;
365
366                 max = (1 << e->bits) - 1;
367                 val = ac97_rdcd(code, e->reg);
368                 if (val == AC97_MUTE && e->mute == 1)
369                         volume = 0;
370                 else {
371                         if (e->stereo == 0) val >>= e->ofs;
372                         val &= max;
373                         volume = (val * 100) / max;
374                         if (e->reg > 0) volume = 100 - volume;
375                 }
376                 return volume;
377         } else
378                 return -1;
379 }
380 #endif
381
382 static void
383 ac97_fix_auxout(struct ac97_info *codec)
384 {
385         /* Determine what AUXOUT really means, it can be: 
386          *
387          * 1. Headphone out.
388          * 2. 4-Channel Out
389          * 3. True line level out (effectively master volume).
390          *
391          * See Sections 5.2.1 and 5.27 for AUX_OUT Options in AC97r2.{2,3}.
392          */
393         if (codec->caps & AC97_CAP_HEADPHONE) {
394                 /* XXX We should probably check the AUX_OUT initial value. 
395                  * Leave AC97_MIX_AUXOUT - SOUND_MIXER_MONITOR relationship */
396                 return;
397         } else if (codec->extcaps & AC97_EXTCAP_SDAC &&
398                    ac97_rdcd(codec, AC97_MIXEXT_SURROUND) == 0x8080) {
399                 /* 4-Channel Out, add an additional gain setting. */
400                 codec->mix[SOUND_MIXER_OGAIN] = codec->mix[SOUND_MIXER_MONITOR];
401         } else {
402                 /* Master volume is/maybe fixed in h/w, not sufficiently 
403                  * clear in spec to blat SOUND_MIXER_MASTER. */
404                 codec->mix[SOUND_MIXER_OGAIN] = codec->mix[SOUND_MIXER_MONITOR];
405         }
406         /* Blat monitor, inappropriate label if we get here */
407         bzero(&codec->mix[SOUND_MIXER_MONITOR], 
408               sizeof(codec->mix[SOUND_MIXER_MONITOR]));
409 }
410
411 static unsigned
412 ac97_initmixer(struct ac97_info *codec)
413 {
414         ac97_patch codec_patch;
415         unsigned i, j, k, old;
416         u_int32_t id;
417
418         snd_mtxlock(codec->lock);
419         codec->count = AC97_INIT(codec->methods, codec->devinfo);
420         if (codec->count == 0) {
421                 device_printf(codec->dev, "ac97 codec init failed\n");
422                 snd_mtxunlock(codec->lock);
423                 return ENODEV;
424         }
425
426         ac97_wrcd(codec, AC97_REG_POWER, (codec->flags & AC97_F_EAPD_INV)? 0x8000 : 0x0000);
427         ac97_reset(codec);
428         ac97_wrcd(codec, AC97_REG_POWER, (codec->flags & AC97_F_EAPD_INV)? 0x8000 : 0x0000);
429
430         i = ac97_rdcd(codec, AC97_REG_RESET);
431         codec->caps = i & 0x03ff;
432         codec->se =  (i & 0x7c00) >> 10;
433
434         id = (ac97_rdcd(codec, AC97_REG_ID1) << 16) | ac97_rdcd(codec, AC97_REG_ID2);
435         codec->rev = id & 0x000000ff;
436         if (id == 0 || id == 0xffffffff) {
437                 device_printf(codec->dev, "ac97 codec invalid or not present (id == %x)\n", id);
438                 snd_mtxunlock(codec->lock);
439                 return ENODEV;
440         }
441
442         codec->noext = 0;
443         codec->id = NULL;
444         codec_patch = NULL;
445         for (i = 0; ac97codecid[i].id; i++) {
446                 if (ac97codecid[i].id == id) {
447                         codec->id = ac97codecid[i].name;
448                         codec->noext = ac97codecid[i].noext;
449                         codec_patch = ac97codecid[i].patch;
450                 }
451         }
452
453         codec->extcaps = 0;
454         codec->extid = 0;
455         codec->extstat = 0;
456         if (!codec->noext) {
457                 i = ac97_rdcd(codec, AC97_REGEXT_ID);
458                 if (i != 0xffff) {
459                         codec->extcaps = i & 0x3fff;
460                         codec->extid =  (i & 0xc000) >> 14;
461                         codec->extstat = ac97_rdcd(codec, AC97_REGEXT_STAT) & AC97_EXTCAPS;
462                 }
463         }
464
465         for (i = 0; i < 32; i++) {
466                 codec->mix[i] = ac97mixtable_default[i];
467         }
468         ac97_fix_auxout(codec);
469         if (codec_patch)
470                 codec_patch(codec);
471
472         for (i = 0; i < 32; i++) {
473                 k = codec->noext? codec->mix[i].enable : 1;
474                 if (k && (codec->mix[i].reg > 0)) {
475                         old = ac97_rdcd(codec, codec->mix[i].reg);
476                         ac97_wrcd(codec, codec->mix[i].reg, 0x3f);
477                         j = ac97_rdcd(codec, codec->mix[i].reg);
478                         ac97_wrcd(codec, codec->mix[i].reg, old);
479                         codec->mix[i].enable = (j != 0 && j != old)? 1 : 0;
480                         for (k = 1; j & (1 << k); k++);
481                         codec->mix[i].bits = j? k - codec->mix[i].ofs : 0;
482                 }
483                 /* printf("mixch %d, en=%d, b=%d\n", i, codec->mix[i].enable, codec->mix[i].bits); */
484         }
485
486         if (codec->id) {
487                 device_printf(codec->dev, "<%s ac97 codec>\n", codec->id);
488         } else {
489                 device_printf(codec->dev, 
490                               "<unknown ac97 codec> (id=0x%08x)\n", id);
491         }
492
493         if (bootverbose) {
494                 device_printf(codec->dev, "ac97 codec features ");
495                 for (i = j = 0; i < 10; i++)
496                         if (codec->caps & (1 << i))
497                                 printf("%s%s", j++? ", " : "", ac97feature[i]);
498                 printf("%s%d bit master volume", j++? ", " : "", codec->mix[SOUND_MIXER_VOLUME].bits);
499                 printf("%s%s\n", j? ", " : "", ac97enhancement[codec->se]);
500
501                 if (codec->extcaps != 0 || codec->extid) {
502                         device_printf(codec->dev, "ac97 %s codec",
503                                       codec->extid? "secondary" : "primary");
504                         if (codec->extcaps)
505                                 printf(" extended features ");
506                         for (i = j = 0; i < 14; i++)
507                                 if (codec->extcaps & (1 << i))
508                                         printf("%s%s", j++? ", " : "", ac97extfeature[i]);
509                         printf("\n");
510                 }
511         }
512
513         if ((ac97_rdcd(codec, AC97_REG_POWER) & 2) == 0)
514                 device_printf(codec->dev, "ac97 codec reports dac not ready\n");
515         snd_mtxunlock(codec->lock);
516         return 0;
517 }
518
519 static unsigned
520 ac97_reinitmixer(struct ac97_info *codec)
521 {
522         snd_mtxlock(codec->lock);
523         codec->count = AC97_INIT(codec->methods, codec->devinfo);
524         if (codec->count == 0) {
525                 device_printf(codec->dev, "ac97 codec init failed\n");
526                 snd_mtxunlock(codec->lock);
527                 return ENODEV;
528         }
529
530         ac97_wrcd(codec, AC97_REG_POWER, (codec->flags & AC97_F_EAPD_INV)? 0x8000 : 0x0000);
531         ac97_reset(codec);
532         ac97_wrcd(codec, AC97_REG_POWER, (codec->flags & AC97_F_EAPD_INV)? 0x8000 : 0x0000);
533
534         if (!codec->noext) {
535                 ac97_wrcd(codec, AC97_REGEXT_STAT, codec->extstat);
536                 if ((ac97_rdcd(codec, AC97_REGEXT_STAT) & AC97_EXTCAPS)
537                     != codec->extstat)
538                         device_printf(codec->dev, "ac97 codec failed to reset extended mode (%x, got %x)\n",
539                                       codec->extstat,
540                                       ac97_rdcd(codec, AC97_REGEXT_STAT) &
541                                       AC97_EXTCAPS);
542         }
543
544         if ((ac97_rdcd(codec, AC97_REG_POWER) & 2) == 0)
545                 device_printf(codec->dev, "ac97 codec reports dac not ready\n");
546         snd_mtxunlock(codec->lock);
547         return 0;
548 }
549
550 struct ac97_info *
551 ac97_create(device_t dev, void *devinfo, kobj_class_t cls)
552 {
553         struct ac97_info *codec;
554
555         codec = (struct ac97_info *)malloc(sizeof *codec, M_AC97, M_NOWAIT);
556         if (codec == NULL)
557                 return NULL;
558
559         snprintf(codec->name, AC97_NAMELEN, "%s:ac97", device_get_nameunit(dev));
560         codec->lock = snd_mtxcreate(codec->name, "ac97 codec");
561         codec->methods = kobj_create(cls, M_AC97, 0);
562         if (codec->methods == NULL) {
563                 snd_mtxlock(codec->lock);
564                 snd_mtxfree(codec->lock);
565                 free(codec, M_AC97);
566                 return NULL;
567         }
568
569         codec->dev = dev;
570         codec->devinfo = devinfo;
571         codec->flags = 0;
572         return codec;
573 }
574
575 void
576 ac97_destroy(struct ac97_info *codec)
577 {
578         snd_mtxlock(codec->lock);
579         if (codec->methods != NULL)
580                 kobj_delete(codec->methods, M_AC97);
581         snd_mtxfree(codec->lock);
582         free(codec, M_AC97);
583 }
584
585 void
586 ac97_setflags(struct ac97_info *codec, u_int32_t val)
587 {
588         codec->flags = val;
589 }
590
591 u_int32_t
592 ac97_getflags(struct ac97_info *codec)
593 {
594         return codec->flags;
595 }
596
597 /* -------------------------------------------------------------------- */
598
599 static int
600 ac97mix_init(struct snd_mixer *m)
601 {
602         struct ac97_info *codec = mix_getdevinfo(m);
603         u_int32_t i, mask;
604
605         if (codec == NULL)
606                 return -1;
607
608         if (ac97_initmixer(codec))
609                 return -1;
610
611         mask = 0;
612         for (i = 0; i < 32; i++)
613                 mask |= codec->mix[i].enable? 1 << i : 0;
614         mix_setdevs(m, mask);
615
616         mask = 0;
617         for (i = 0; i < 32; i++)
618                 mask |= codec->mix[i].recidx? 1 << i : 0;
619         mix_setrecdevs(m, mask);
620         return 0;
621 }
622
623 static int
624 ac97mix_uninit(struct snd_mixer *m)
625 {
626         struct ac97_info *codec = mix_getdevinfo(m);
627
628         if (codec == NULL)
629                 return -1;
630         /*
631         if (ac97_uninitmixer(codec))
632                 return -1;
633         */
634         ac97_destroy(codec);
635         return 0;
636 }
637
638 static int
639 ac97mix_reinit(struct snd_mixer *m)
640 {
641         struct ac97_info *codec = mix_getdevinfo(m);
642
643         if (codec == NULL)
644                 return -1;
645         return ac97_reinitmixer(codec);
646 }
647
648 static int
649 ac97mix_set(struct snd_mixer *m, unsigned dev, unsigned left, unsigned right)
650 {
651         struct ac97_info *codec = mix_getdevinfo(m);
652
653         if (codec == NULL)
654                 return -1;
655         return ac97_setmixer(codec, dev, left, right);
656 }
657
658 static int
659 ac97mix_setrecsrc(struct snd_mixer *m, u_int32_t src)
660 {
661         int i;
662         struct ac97_info *codec = mix_getdevinfo(m);
663
664         if (codec == NULL)
665                 return -1;
666         for (i = 0; i < SOUND_MIXER_NRDEVICES; i++)
667                 if ((src & (1 << i)) != 0)
668                         break;
669         return (ac97_setrecsrc(codec, i) == 0)? 1 << i : -1;
670 }
671
672 static kobj_method_t ac97mixer_methods[] = {
673         KOBJMETHOD(mixer_init,          ac97mix_init),
674         KOBJMETHOD(mixer_uninit,        ac97mix_uninit),
675         KOBJMETHOD(mixer_reinit,        ac97mix_reinit),
676         KOBJMETHOD(mixer_set,           ac97mix_set),
677         KOBJMETHOD(mixer_setrecsrc,     ac97mix_setrecsrc),
678         { 0, 0 }
679 };
680 MIXER_DECLARE(ac97mixer);
681
682 /* -------------------------------------------------------------------- */
683
684 kobj_class_t
685 ac97_getmixerclass(void)
686 {
687         return &ac97mixer_class;
688 }
689
690