[BACK]Return to ac97.c CVS log [TXT][DIR] Up to [local] / sys / dev / ic

Annotation of sys/dev/ic/ac97.c, Revision 1.1.1.1

1.1       nbrk        1: /*     $OpenBSD: ac97.c,v 1.63 2007/07/27 01:48:04 ian Exp $   */
                      2:
                      3: /*
                      4:  * Copyright (c) 1999, 2000 Constantine Sapuntzakis
                      5:  *
                      6:  * Author:     Constantine Sapuntzakis <csapuntz@stanford.edu>
                      7:  *
                      8:  * Redistribution and use in source and binary forms, with or without
                      9:  * modification, are permitted provided that the following conditions
                     10:  * are met:
                     11:  * 1. Redistributions of source code must retain the above copyright
                     12:  *    notice, this list of conditions and the following disclaimer.
                     13:  * 2. Redistributions in binary form must reproduce the above copyright
                     14:  *    notice, this list of conditions and the following disclaimer in the
                     15:  *    documentation and/or other materials provided with the distribution.
                     16:  * 3. The name of the author may not be used to endorse or promote
                     17:  *    products derived from this software without specific prior written
                     18:  *    permission.
                     19:  * THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS
                     20:  * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
                     21:  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
                     22:  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE
                     23:  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
                     24:  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
                     25:  * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
                     26:  * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
                     27:  * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
                     28:  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
                     29:  * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
                     30:  * DAMAGE.  */
                     31:
                     32: /* Partially inspired by FreeBSD's sys/dev/pcm/ac97.c. It came with
                     33:    the following copyright */
                     34:
                     35: /*
                     36:  * Copyright (c) 1999 Cameron Grant <gandalf@vilnya.demon.co.uk>
                     37:  * All rights reserved.
                     38:  *
                     39:  * Redistribution and use in source and binary forms, with or without
                     40:  * modification, are permitted provided that the following conditions
                     41:  * are met:
                     42:  * 1. Redistributions of source code must retain the above copyright
                     43:  *    notice, this list of conditions and the following disclaimer.
                     44:  * 2. Redistributions in binary form must reproduce the above copyright
                     45:  *    notice, this list of conditions and the following disclaimer in the
                     46:  *    documentation and/or other materials provided with the distribution.
                     47:  *
                     48:  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
                     49:  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
                     50:  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
                     51:  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
                     52:  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
                     53:  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
                     54:  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
                     55:  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
                     56:  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
                     57:  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
                     58:  * SUCH DAMAGE.
                     59:  *
                     60:  * $FreeBSD$
                     61:  */
                     62:
                     63: #include <sys/param.h>
                     64: #include <sys/systm.h>
                     65: #include <sys/kernel.h>
                     66: #include <sys/malloc.h>
                     67: #include <sys/device.h>
                     68:
                     69: #include <sys/audioio.h>
                     70: #include <dev/audio_if.h>
                     71: #include <dev/ic/ac97.h>
                     72:
                     73: const struct audio_mixer_enum ac97_on_off = {
                     74:        2,
                     75:        { { { AudioNoff } , 0 },
                     76:        { { AudioNon }  , 1 } }
                     77: };
                     78:
                     79: const struct audio_mixer_enum ac97_mic_select = {
                     80:        2,
                     81:        { { { AudioNmicrophone "0" }, 0 },
                     82:        { { AudioNmicrophone "1" }, 1 } }
                     83: };
                     84:
                     85: const struct audio_mixer_enum ac97_mono_select = {
                     86:        2,
                     87:        { { { AudioNmixerout }, 0 },
                     88:        { { AudioNmicrophone }, 1 } }
                     89: };
                     90:
                     91: const struct audio_mixer_enum ac97_source = {
                     92:        8,
                     93:        { { { AudioNmicrophone } , 0 },
                     94:        { { AudioNcd }, 1 },
                     95:        { { "video" }, 2 },
                     96:        { { AudioNaux }, 3 },
                     97:        { { AudioNline }, 4 },
                     98:        { { AudioNmixerout }, 5 },
                     99:        { { AudioNmixerout AudioNmono }, 6 },
                    100:        { { "phone" }, 7 }}
                    101: };
                    102:
                    103: /*
                    104:  * Due to different values for each source that uses these structures,
                    105:  * the ac97_query_devinfo function sets delta in mixer_devinfo_t using
                    106:  * ac97_source_info.bits.
                    107:  */
                    108: const struct audio_mixer_value ac97_volume_stereo = {
                    109:        { AudioNvolume },
                    110:        2
                    111: };
                    112:
                    113: const struct audio_mixer_value ac97_volume_mono = {
                    114:        { AudioNvolume },
                    115:        1
                    116: };
                    117:
                    118: #define WRAP(a)  &a, sizeof(a)
                    119:
                    120: const struct ac97_source_info {
                    121:        char *class;
                    122:        char *device;
                    123:        char *qualifier;
                    124:        int  type;
                    125:
                    126:        const void *info;
                    127:        int16_t info_size;
                    128:
                    129:        u_int8_t  reg;
                    130:        u_int8_t  bits:3;
                    131:        u_int8_t  ofs:4;
                    132:        u_int8_t  mute:1;
                    133:        u_int8_t  polarity:1;           /* Does 0 == MAX or MIN */
                    134:        u_int16_t default_value;
                    135:
                    136:        int16_t  prev;
                    137:        int16_t  next;
                    138:        int16_t  mixer_class;
                    139: } source_info[] = {
                    140:        {
                    141:                AudioCinputs,   NULL,           NULL,   AUDIO_MIXER_CLASS,
                    142:        }, {
                    143:                AudioCoutputs,  NULL,           NULL,   AUDIO_MIXER_CLASS,
                    144:        }, {
                    145:                AudioCrecord,   NULL,           NULL,   AUDIO_MIXER_CLASS,
                    146:        }, {
                    147:                /* Stereo master volume*/
                    148:                AudioCoutputs,  AudioNmaster,   NULL,   AUDIO_MIXER_VALUE,
                    149:                WRAP(ac97_volume_stereo),
                    150:                AC97_REG_MASTER_VOLUME, 5, 0, 1, 0, 0x8000
                    151:        }, {
                    152:                /* Mono volume */
                    153:                AudioCoutputs,  AudioNmono,     NULL,   AUDIO_MIXER_VALUE,
                    154:                WRAP(ac97_volume_mono),
                    155:                AC97_REG_MASTER_VOLUME_MONO, 6, 0, 1, 0, 0x8000
                    156:        }, {
                    157:                AudioCoutputs,  AudioNmono, AudioNsource, AUDIO_MIXER_ENUM,
                    158:                WRAP(ac97_mono_select),
                    159:                AC97_REG_GP, 1, 9, 0, 0, 0x0000
                    160:        }, {
                    161:                /* Headphone volume */
                    162:                AudioCoutputs,  AudioNheadphone, NULL,  AUDIO_MIXER_VALUE,
                    163:                WRAP(ac97_volume_stereo),
                    164:                AC97_REG_HEADPHONE_VOLUME, 6, 0, 1, 0, 0x8000
                    165:        }, {
                    166:                AudioCoutputs,  AudioNbass,     NULL,   AUDIO_MIXER_VALUE,
                    167:                WRAP(ac97_volume_mono),
                    168:                AC97_REG_MASTER_TONE, 4, 8, 0, 0, 0x0f0f
                    169:        }, {
                    170:                AudioCoutputs,  AudioNtreble,   NULL,   AUDIO_MIXER_VALUE,
                    171:                WRAP(ac97_volume_mono),
                    172:                AC97_REG_MASTER_TONE, 4, 0, 0, 0, 0x0f0f
                    173:        }, {
                    174:                /* PC Beep Volume */
                    175:                AudioCinputs,   AudioNspeaker,  NULL,   AUDIO_MIXER_VALUE,
                    176:                WRAP(ac97_volume_mono),
                    177:                AC97_REG_PCBEEP_VOLUME, 4, 1, 1, 0, 0x0000
                    178:        }, {
                    179:                /* Phone */
                    180:                AudioCinputs,   "phone",        NULL,   AUDIO_MIXER_VALUE,
                    181:                WRAP(ac97_volume_mono),
                    182:                AC97_REG_PHONE_VOLUME, 5, 0, 1, 0, 0x8008
                    183:        }, {
                    184:                /* Mic Volume */
                    185:                AudioCinputs,   AudioNmicrophone, NULL, AUDIO_MIXER_VALUE,
                    186:                WRAP(ac97_volume_mono),
                    187:                AC97_REG_MIC_VOLUME, 5, 0, 1, 0, 0x8008
                    188:        }, {
                    189:                AudioCinputs,   AudioNmicrophone, AudioNpreamp, AUDIO_MIXER_ENUM,
                    190:                WRAP(ac97_on_off),
                    191:                AC97_REG_MIC_VOLUME, 1, 6, 0, 0, 0x8008
                    192:        }, {
                    193:                AudioCinputs,   AudioNmicrophone, AudioNsource, AUDIO_MIXER_ENUM,
                    194:                WRAP(ac97_mic_select),
                    195:                AC97_REG_GP, 1, 8, 0, 0x0000
                    196:        }, {
                    197:                /* Line in Volume */
                    198:                AudioCinputs,   AudioNline,     NULL,   AUDIO_MIXER_VALUE,
                    199:                WRAP(ac97_volume_stereo),
                    200:                AC97_REG_LINEIN_VOLUME, 5, 0, 1, 0, 0x8808
                    201:        }, {
                    202:                /* CD Volume */
                    203:                AudioCinputs,   AudioNcd,       NULL,   AUDIO_MIXER_VALUE,
                    204:                WRAP(ac97_volume_stereo),
                    205:                AC97_REG_CD_VOLUME, 5, 0, 1, 0, 0x8808
                    206:        }, {
                    207:                /* Video Volume */
                    208:                AudioCinputs,   "video",        NULL,   AUDIO_MIXER_VALUE,
                    209:                WRAP(ac97_volume_stereo),
                    210:                AC97_REG_VIDEO_VOLUME, 5, 0, 1, 0, 0x8808
                    211:        }, {
                    212:                /* AUX volume */
                    213:                AudioCinputs,   AudioNaux,      NULL,   AUDIO_MIXER_VALUE,
                    214:                WRAP(ac97_volume_stereo),
                    215:                AC97_REG_AUX_VOLUME, 5, 0, 1, 0, 0x8808
                    216:        }, {
                    217:                /* PCM out volume */
                    218:                AudioCinputs,   AudioNdac,      NULL,   AUDIO_MIXER_VALUE,
                    219:                WRAP(ac97_volume_stereo),
                    220:                AC97_REG_PCMOUT_VOLUME, 5, 0, 1, 0, 0x8808
                    221:        }, {
                    222:                /* Record Source - some logic for this is hard coded - see below */
                    223:                AudioCrecord,   AudioNsource,   NULL,   AUDIO_MIXER_ENUM,
                    224:                WRAP(ac97_source),
                    225:                AC97_REG_RECORD_SELECT, 3, 0, 0, 0, 0x0000
                    226:        }, {
                    227:                /* Record Gain */
                    228:                AudioCrecord,   AudioNvolume,   NULL,   AUDIO_MIXER_VALUE,
                    229:                WRAP(ac97_volume_stereo),
                    230:                AC97_REG_RECORD_GAIN, 4, 0, 1, 0, 0x8000
                    231:        }, {
                    232:                /* Record Gain mic */
                    233:                AudioCrecord,   AudioNmicrophone, NULL, AUDIO_MIXER_VALUE,
                    234:                WRAP(ac97_volume_mono),
                    235:                AC97_REG_RECORD_GAIN_MIC, 4, 0, 1, 1, 0x8000
                    236:        }, {
                    237:                /* */
                    238:                AudioCoutputs,  AudioNloudness, NULL,   AUDIO_MIXER_ENUM,
                    239:                WRAP(ac97_on_off),
                    240:                AC97_REG_GP, 1, 12, 0, 0, 0x0000
                    241:        }, {
                    242:                AudioCoutputs,  AudioNspatial,  NULL,   AUDIO_MIXER_ENUM,
                    243:                WRAP(ac97_on_off),
                    244:                AC97_REG_GP, 1, 13, 0, 0, 0x0000
                    245:        }, {
                    246:                AudioCoutputs,  AudioNspatial,  AudioNcenter,AUDIO_MIXER_VALUE,
                    247:                WRAP(ac97_volume_mono),
                    248:                AC97_REG_3D_CONTROL, 4, 8, 0, 1, 0x0000
                    249:        }, {
                    250:                AudioCoutputs,  AudioNspatial,  AudioNdepth, AUDIO_MIXER_VALUE,
                    251:                WRAP(ac97_volume_mono),
                    252:                AC97_REG_3D_CONTROL, 4, 0, 0, 1, 0x0000
                    253:        }, {
                    254:                /* Surround volume */
                    255:                AudioCoutputs,  AudioNsurround, NULL,   AUDIO_MIXER_VALUE,
                    256:                WRAP(ac97_volume_stereo),
                    257:                AC97_REG_SURROUND_VOLUME, 6, 0, 1, 0, 0x8080
                    258:        }, {
                    259:                /* Center volume */
                    260:                AudioCoutputs,  AudioNcenter,   NULL,   AUDIO_MIXER_VALUE,
                    261:                WRAP(ac97_volume_mono),
                    262:                AC97_REG_CENTER_LFE_VOLUME, 6, 0, 1, 0, 0x8080
                    263:        }, {
                    264:                /* LFE volume */
                    265:                AudioCoutputs,  AudioNlfe,      NULL,   AUDIO_MIXER_VALUE,
                    266:                WRAP(ac97_volume_mono),
                    267:                AC97_REG_CENTER_LFE_VOLUME, 6, 8, 1, 0, 0x8080
                    268:        }, {
                    269:                /* External Amp */
                    270:                AudioCoutputs,  AudioNextamp,   NULL,   AUDIO_MIXER_ENUM,
                    271:                WRAP(ac97_on_off),
                    272:                AC97_REG_POWER, 1, 15, 0, 0, 0x0000
                    273:        }
                    274:
                    275:        /* Missing features: Simulated Stereo, POP, Loopback mode */
                    276: };
                    277:
                    278: #define SOURCE_INFO_SIZE (sizeof(source_info)/sizeof(source_info[0]))
                    279:
                    280: /*
                    281:  * Check out http://www.intel.com/technology/computing/audio/index.htm
                    282:  * for information on AC-97
                    283:  */
                    284:
                    285: struct ac97_softc {
                    286:        struct ac97_codec_if codec_if;
                    287:        struct ac97_host_if *host_if;
                    288:        struct ac97_source_info source_info[2 * SOURCE_INFO_SIZE];
                    289:        int num_source_info;
                    290:        enum ac97_host_flags host_flags;
                    291:        u_int16_t caps, ext_id;
                    292:        u_int16_t shadow_reg[128];
                    293: };
                    294:
                    295: int    ac97_mixer_get_port(struct ac97_codec_if *, mixer_ctrl_t *);
                    296: int    ac97_mixer_set_port(struct ac97_codec_if *, mixer_ctrl_t *);
                    297: int    ac97_query_devinfo(struct ac97_codec_if *, mixer_devinfo_t *);
                    298: int    ac97_get_portnum_by_name(struct ac97_codec_if *, char *, char *,
                    299:            char *);
                    300: void   ac97_restore_shadow(struct ac97_codec_if *);
                    301:
                    302: void   ac97_ad1886_init(struct ac97_softc *);
                    303: void   ac97_ad198x_init(struct ac97_softc *);
                    304: void   ac97_alc655_init(struct ac97_softc *);
                    305: void   ac97_cx20468_init(struct ac97_softc *);
                    306:
                    307: struct ac97_codec_if_vtbl ac97civ = {
                    308:        ac97_mixer_get_port,
                    309:        ac97_mixer_set_port,
                    310:        ac97_query_devinfo,
                    311:        ac97_get_portnum_by_name,
                    312:        ac97_restore_shadow
                    313: };
                    314:
                    315: const struct ac97_codecid {
                    316:        u_int8_t id;
                    317:        u_int8_t mask;
                    318:        u_int8_t rev;
                    319:        u_int8_t shift; /* no use yet */
                    320:        char * const name;
                    321:        void (*init)(struct ac97_softc *);
                    322: }  ac97_ad[] = {
                    323:        { 0x03, 0xff, 0, 0,     "AD1819" },
                    324:        { 0x40, 0xff, 0, 0,     "AD1881" },
                    325:        { 0x48, 0xff, 0, 0,     "AD1881A" },
                    326:        { 0x60, 0xff, 0, 0,     "AD1885" },
                    327:        { 0x61, 0xff, 0, 0,     "AD1886",       ac97_ad1886_init },
                    328:        { 0x63, 0xff, 0, 0,     "AD1886A" },
                    329:        { 0x68, 0xff, 0, 0,     "AD1888",       ac97_ad198x_init },
                    330:        { 0x70, 0xff, 0, 0,     "AD1980" },
                    331:        { 0x72, 0xff, 0, 0,     "AD1981A" },
                    332:        { 0x74, 0xff, 0, 0,     "AD1981B" },
                    333:        { 0x75, 0xff, 0, 0,     "AD1985",       ac97_ad198x_init },
                    334: }, ac97_ak[] = {
                    335:        { 0x00, 0xfe, 1, 0,     "AK4540" },
                    336:        { 0x01, 0xfe, 1, 0,     "AK4540" },
                    337:        { 0x02, 0xff, 0, 0,     "AK4543" },
                    338:        { 0x05, 0xff, 0, 0,     "AK4544" },
                    339:        { 0x06, 0xff, 0, 0,     "AK4544A" },
                    340:        { 0x07, 0xff, 0, 0,     "AK4545" },
                    341: }, ac97_av[] = {
                    342:        { 0x10, 0xff, 0, 0,     "ALC200" },
                    343:        { 0x20, 0xff, 0, 0,     "ALC650" },
                    344:        { 0x21, 0xff, 0, 0,     "ALC650D" },
                    345:        { 0x22, 0xff, 0, 0,     "ALC650E" },
                    346:        { 0x23, 0xff, 0, 0,     "ALC650F" },
                    347:        { 0x30, 0xff, 0, 0,     "ALC101" },
                    348:        { 0x40, 0xff, 0, 0,     "ALC202" },
                    349:        { 0x50, 0xff, 0, 0,     "ALC250" },
                    350:        { 0x52, 0xff, 0, 0,     "ALC250A?" },
                    351:        { 0x60, 0xf0, 0xf, 0,   "ALC655",       ac97_alc655_init },
                    352:        { 0x70, 0xf0, 0xf, 0,   "ALC203" },
                    353:        { 0x80, 0xf0, 0xf, 0,   "ALC658",       ac97_alc655_init },
                    354:        { 0x90, 0xf0, 0xf, 0,   "ALC850" },
                    355: }, ac97_rl[] = {
                    356:        { 0x00, 0xf0, 0xf, 0,   "RL5306" },
                    357:        { 0x10, 0xf0, 0xf, 0,   "RL5382" },
                    358:        { 0x20, 0xf0, 0xf, 0,   "RL5383" },
                    359: }, ac97_cm[] = {
                    360:        { 0x41, 0xff, 0, 0,     "CMI9738" },
                    361:        { 0x61, 0xff, 0, 0,     "CMI9739" },
                    362:        { 0x78, 0xff, 0, 0,     "CMI9761A" },
                    363:        { 0x82, 0xff, 0, 0,     "CMI9761B" },
                    364:        { 0x83, 0xff, 0, 0,     "CMI9761A+" },
                    365: }, ac97_cr[] = {
                    366:        { 0x84, 0xff, 0, 0,     "EV1938" },
                    367: }, ac97_cs[] = {
                    368:        { 0x00, 0xf8, 7, 0,     "CS4297" },
                    369:        { 0x10, 0xf8, 7, 0,     "CS4297A" },
                    370:        { 0x20, 0xf8, 7, 0,     "CS4298" },
                    371:        { 0x28, 0xf8, 7, 0,     "CS4294" },
                    372:        { 0x30, 0xf8, 7, 0,     "CS4299" },
                    373:        { 0x48, 0xf8, 7, 0,     "CS4201" },
                    374:        { 0x58, 0xf8, 7, 0,     "CS4205" },
                    375:        { 0x60, 0xf8, 7, 0,     "CS4291" },
                    376:        { 0x70, 0xf8, 7, 0,     "CS4202" },
                    377: }, ac97_cx[] = {
                    378:        { 0x21, 0xff, 0, 0,     "HSD11246" },
                    379:        { 0x28, 0xf8, 7, 0,     "CX20468",      ac97_cx20468_init },
                    380:        { 0x30, 0xff, 0, 0,     "CXT48", },
                    381:        { 0x42, 0xff, 0, 0,     "CXT66", },
                    382: }, ac97_dt[] = {
                    383:        { 0x00, 0xff, 0, 0,     "DT0398" },
                    384: }, ac97_em[] = {
                    385:        { 0x23, 0xff, 0, 0,     "EM28023" },
                    386:        { 0x28, 0xff, 0, 0,     "EM28028" },
                    387: }, ac97_es[] = {
                    388:        { 0x08, 0xff, 0, 0,     "ES1921" },
                    389: }, ac97_is[] = {
                    390:        { 0x00, 0xff, 0, 0,     "HMP9701" },
                    391: }, ac97_ic[] = {
                    392:        { 0x01, 0xff, 0, 0,     "ICE1230" },
                    393:        { 0x11, 0xff, 0, 0,     "ICE1232" },
                    394:        { 0x14, 0xff, 0, 0,     "ICE1232A" },
                    395:        { 0x51, 0xff, 0, 0,     "VIA VT1616" },
                    396:        { 0x52, 0xff, 0, 0,     "VIA VT1616i" },
                    397: }, ac97_it[] = {
                    398:        { 0x20, 0xff, 0, 0,     "ITE2226E" },
                    399:        { 0x60, 0xff, 0, 0,     "ITE2646E" },
                    400: }, ac97_ns[] = {
                    401:        { 0x00, 0xff, 0, 0,     "LM454[03568]" },
                    402:        { 0x31, 0xff, 0, 0,     "LM4549" },
                    403:        { 0x40, 0xff, 0, 0,     "LM4540" },
                    404:        { 0x43, 0xff, 0, 0,     "LM4543" },
                    405:        { 0x46, 0xff, 0, 0,     "LM4546A" },
                    406:        { 0x48, 0xff, 0, 0,     "LM4548A" },
                    407:        { 0x49, 0xff, 0, 0,     "LM4549A" },
                    408:        { 0x50, 0xff, 0, 0,     "LM4550" },
                    409: }, ac97_ps[] = {
                    410:        { 0x01, 0xff, 0, 0,     "UCB1510" },
                    411:        { 0x04, 0xff, 0, 0,     "UCB1400" },
                    412: }, ac97_sl[] = {
                    413:        { 0x20, 0xe0, 0, 0,     "Si3036/38" },
                    414: }, ac97_st[] = {
                    415:        { 0x00, 0xff, 0, 0,     "STAC9700" },
                    416:        { 0x04, 0xff, 0, 0,     "STAC970[135]" },
                    417:        { 0x05, 0xff, 0, 0,     "STAC9704" },
                    418:        { 0x08, 0xff, 0, 0,     "STAC9708/11" },
                    419:        { 0x09, 0xff, 0, 0,     "STAC9721/23" },
                    420:        { 0x44, 0xff, 0, 0,     "STAC9744/45" },
                    421:        { 0x50, 0xff, 0, 0,     "STAC9750/51" },
                    422:        { 0x52, 0xff, 0, 0,     "STAC9752/53" },
                    423:        { 0x56, 0xff, 0, 0,     "STAC9756/57" },
                    424:        { 0x58, 0xff, 0, 0,     "STAC9758/59" },
                    425:        { 0x60, 0xff, 0, 0,     "STAC9760/61" },
                    426:        { 0x62, 0xff, 0, 0,     "STAC9762/63" },
                    427:        { 0x66, 0xff, 0, 0,     "STAC9766/67" },
                    428:        { 0x84, 0xff, 0, 0,     "STAC9784/85" },
                    429: }, ac97_vi[] = {
                    430:        { 0x61, 0xff, 0, 0,     "VT1612A" },
                    431: }, ac97_tt[] = {
                    432:        { 0x02, 0xff, 0, 0,     "TR28022" },
                    433:        { 0x03, 0xff, 0, 0,     "TR28023" },
                    434:        { 0x06, 0xff, 0, 0,     "TR28026" },
                    435:        { 0x08, 0xff, 0, 0,     "TR28028" },
                    436:        { 0x23, 0xff, 0, 0,     "TR28602" },
                    437: }, ac97_ti[] = {
                    438:        { 0x20, 0xff, 0, 0,     "TLC320AD9xC" },
                    439: }, ac97_wb[] = {
                    440:        { 0x01, 0xff, 0, 0,     "W83971D" },
                    441: }, ac97_wo[] = {
                    442:        { 0x00, 0xff, 0, 0,     "WM9701A" },
                    443:        { 0x03, 0xff, 0, 0,     "WM9704M/Q-0" }, /* & WM9703 */
                    444:        { 0x04, 0xff, 0, 0,     "WM9704M/Q-1" },
                    445:        { 0x05, 0xff, 0, 0,     "WM9705/10" },
                    446:        { 0x09, 0xff, 0, 0,     "WM9709" },
                    447:        { 0x12, 0xff, 0, 0,     "WM9711/12" },
                    448: }, ac97_ym[] = {
                    449:        { 0x00, 0xff, 0, 0,     "YMF743-S" },
                    450:        { 0x02, 0xff, 0, 0,     "YMF752-S" },
                    451:        { 0x03, 0xff, 0, 0,     "YMF753-S" },
                    452: };
                    453:
                    454: #define        cl(n)   n, sizeof(n)/sizeof(n[0])
                    455: const struct ac97_vendorid {
                    456:        u_int32_t id;
                    457:        char * const name;
                    458:        const struct ac97_codecid * const codecs;
                    459:        u_int8_t num;
                    460: } ac97_vendors[] = {
                    461:        { 0x01408300, "Creative",               cl(ac97_cr) },
                    462:        { 0x41445300, "Analog Devices",         cl(ac97_ad) },
                    463:        { 0x414b4D00, "Asahi Kasei",            cl(ac97_ak) },
                    464:        { 0x414c4300, "Realtek",                cl(ac97_rl) },
                    465:        { 0x414c4700, "Avance Logic",           cl(ac97_av) },
                    466:        { 0x434d4900, "C-Media Electronics",    cl(ac97_cm) },
                    467:        { 0x43525900, "Cirrus Logic",           cl(ac97_cs) },
                    468:        { 0x43585400, "Conexant",               cl(ac97_cx) },
                    469:        { 0x44543000, "Diamond Technology",     cl(ac97_dt) },
                    470:        { 0x454d4300, "eMicro",                 cl(ac97_em) },
                    471:        { 0x45838300, "ESS Technology",         cl(ac97_es) },
                    472:        { 0x48525300, "Intersil",               cl(ac97_is) },
                    473:        { 0x49434500, "ICEnsemble",             cl(ac97_ic) },
                    474:        { 0x49544500, "ITE, Inc.",              cl(ac97_it) },
                    475:        { 0x4e534300, "National Semiconductor", cl(ac97_ns) },
                    476:        { 0x50534300, "Philips Semiconductor",  cl(ac97_ps) },
                    477:        { 0x53494c00, "Silicon Laboratory",     cl(ac97_sl) },
                    478:        { 0x54524100, "TriTech Microelectronics", cl(ac97_tt) },
                    479:        { 0x54584e00, "Texas Instruments",      cl(ac97_ti) },
                    480:        { 0x56494100, "VIA Technologies",       cl(ac97_vi) },
                    481:        { 0x57454300, "Winbond",                cl(ac97_wb) },
                    482:        { 0x574d4c00, "Wolfson",                cl(ac97_wo) },
                    483:        { 0x594d4800, "Yamaha",                 cl(ac97_ym) },
                    484:        { 0x83847600, "SigmaTel",               cl(ac97_st) },
                    485: };
                    486: #undef cl
                    487:
                    488: const char * const ac97enhancement[] = {
                    489:        "No 3D Stereo",
                    490:        "Analog Devices Phat Stereo",
                    491:        "Creative",
                    492:        "National Semi 3D",
                    493:        "Yamaha Ymersion",
                    494:        "BBE 3D",
                    495:        "Crystal Semi 3D",
                    496:        "Qsound QXpander",
                    497:        "Spatializer 3D",
                    498:        "SRS 3D",
                    499:        "Platform Tech 3D",
                    500:        "AKM 3D",
                    501:        "Aureal",
                    502:        "AZTECH 3D",
                    503:        "Binaura 3D",
                    504:        "ESS Technology",
                    505:        "Harman International VMAx",
                    506:        "Nvidea 3D",
                    507:        "Philips Incredible Sound",
                    508:        "Texas Instruments 3D",
                    509:        "VLSI Technology 3D",
                    510:        "TriTech 3D",
                    511:        "Realtek 3D",
                    512:        "Samsung 3D",
                    513:        "Wolfson Microelectronics 3D",
                    514:        "Delta Integration 3D",
                    515:        "SigmaTel 3D",
                    516:        "KS Waves 3D",
                    517:        "Rockwell 3D",
                    518:        "Unknown 3D",
                    519:        "Unknown 3D",
                    520:        "Unknown 3D"
                    521: };
                    522:
                    523: const char * const ac97feature[] = {
                    524:        "mic channel",
                    525:        "reserved",
                    526:        "tone",
                    527:        "simulated stereo",
                    528:        "headphone",
                    529:        "bass boost",
                    530:        "18 bit DAC",
                    531:        "20 bit DAC",
                    532:        "18 bit ADC",
                    533:        "20 bit ADC"
                    534: };
                    535:
                    536:
                    537: int    ac97_str_equal(const char *, const char *);
                    538: void   ac97_setup_source_info(struct ac97_softc *);
                    539: void   ac97_setup_defaults(struct ac97_softc *);
                    540: int    ac97_read(struct ac97_softc *, u_int8_t, u_int16_t *);
                    541: int    ac97_write(struct ac97_softc *, u_int8_t, u_int16_t);
                    542:
                    543:
                    544: #ifdef AUDIO_DEBUG
                    545: #define DPRINTF(x)     if (ac97debug) printf x
                    546: #define DPRINTFN(n,x)  if (ac97debug>(n)) printf x
                    547: #ifdef AC97_DEBUG
                    548: int    ac97debug = 1;
                    549: #else
                    550: int    ac97debug = 0;
                    551: #endif
                    552: #else
                    553: #define DPRINTF(x)
                    554: #define DPRINTFN(n,x)
                    555: #endif
                    556:
                    557: int
                    558: ac97_read(struct ac97_softc *as, u_int8_t reg, u_int16_t *val)
                    559: {
                    560:        int error;
                    561:
                    562:        if (((as->host_flags & AC97_HOST_DONT_READ) &&
                    563:            (reg != AC97_REG_VENDOR_ID1 && reg != AC97_REG_VENDOR_ID2 &&
                    564:            reg != AC97_REG_RESET)) ||
                    565:            (as->host_flags & AC97_HOST_DONT_READANY)) {
                    566:                *val = as->shadow_reg[reg >> 1];
                    567:                return (0);
                    568:        }
                    569:
                    570:        if ((error = as->host_if->read(as->host_if->arg, reg, val)))
                    571:                *val = as->shadow_reg[reg >> 1];
                    572:        return (error);
                    573: }
                    574:
                    575: int
                    576: ac97_write(struct ac97_softc *as, u_int8_t reg, u_int16_t val)
                    577: {
                    578:        as->shadow_reg[reg >> 1] = val;
                    579:        return (as->host_if->write(as->host_if->arg, reg, val));
                    580: }
                    581:
                    582: void
                    583: ac97_setup_defaults(struct ac97_softc *as)
                    584: {
                    585:        int idx;
                    586:
                    587:        bzero(as->shadow_reg, sizeof(as->shadow_reg));
                    588:
                    589:        for (idx = 0; idx < SOURCE_INFO_SIZE; idx++) {
                    590:                const struct ac97_source_info *si = &source_info[idx];
                    591:
                    592:                ac97_write(as, si->reg, si->default_value);
                    593:        }
                    594: }
                    595:
                    596: void
                    597: ac97_restore_shadow(struct ac97_codec_if *self)
                    598: {
                    599:        struct ac97_softc *as = (struct ac97_softc *)self;
                    600:        int idx;
                    601:
                    602:        for (idx = 0; idx < SOURCE_INFO_SIZE; idx++) {
                    603:                const struct ac97_source_info *si = &source_info[idx];
                    604:
                    605:                ac97_write(as, si->reg, as->shadow_reg[si->reg >> 1]);
                    606:        }
                    607: }
                    608:
                    609: int
                    610: ac97_str_equal(const char *a, const char *b)
                    611: {
                    612:        return ((a == b) || (a && b && (!strcmp(a, b))));
                    613: }
                    614:
                    615: void
                    616: ac97_setup_source_info(struct ac97_softc *as)
                    617: {
                    618:        struct ac97_source_info *si, *si2;
                    619:        int idx, ouridx;
                    620:
                    621:        for (idx = 0, ouridx = 0; idx < SOURCE_INFO_SIZE; idx++) {
                    622:                si = &as->source_info[ouridx];
                    623:
                    624:                bcopy(&source_info[idx], si, sizeof(*si));
                    625:
                    626:                switch (si->type) {
                    627:                case AUDIO_MIXER_CLASS:
                    628:                        si->mixer_class = ouridx;
                    629:                        ouridx++;
                    630:                        break;
                    631:                case AUDIO_MIXER_VALUE:
                    632:                        /* Todo - Test to see if it works */
                    633:                        ouridx++;
                    634:
                    635:                        /* Add an entry for mute, if necessary */
                    636:                        if (si->mute) {
                    637:                                si = &as->source_info[ouridx];
                    638:                                bcopy(&source_info[idx], si, sizeof(*si));
                    639:                                si->qualifier = AudioNmute;
                    640:                                si->type = AUDIO_MIXER_ENUM;
                    641:                                si->info = &ac97_on_off;
                    642:                                si->info_size = sizeof(ac97_on_off);
                    643:                                si->bits = 1;
                    644:                                si->ofs = 15;
                    645:                                si->mute = 0;
                    646:                                si->polarity = 0;
                    647:                                ouridx++;
                    648:                        }
                    649:                        break;
                    650:                case AUDIO_MIXER_ENUM:
                    651:                        /* Todo - Test to see if it works */
                    652:                        ouridx++;
                    653:                        break;
                    654:                default:
                    655:                        printf ("ac97: shouldn't get here\n");
                    656:                        break;
                    657:                }
                    658:        }
                    659:
                    660:        as->num_source_info = ouridx;
                    661:
                    662:        for (idx = 0; idx < as->num_source_info; idx++) {
                    663:                int idx2, previdx;
                    664:
                    665:                si = &as->source_info[idx];
                    666:
                    667:                /* Find mixer class */
                    668:                for (idx2 = 0; idx2 < as->num_source_info; idx2++) {
                    669:                        si2 = &as->source_info[idx2];
                    670:
                    671:                        if (si2->type == AUDIO_MIXER_CLASS &&
                    672:                            ac97_str_equal(si->class, si2->class)) {
                    673:                                si->mixer_class = idx2;
                    674:                        }
                    675:                }
                    676:
                    677:
                    678:                /* Setup prev and next pointers */
                    679:                if (si->prev != 0 || si->qualifier)
                    680:                        continue;
                    681:
                    682:                si->prev = AUDIO_MIXER_LAST;
                    683:                previdx = idx;
                    684:
                    685:                for (idx2 = 0; idx2 < as->num_source_info; idx2++) {
                    686:                        if (idx2 == idx)
                    687:                                continue;
                    688:
                    689:                        si2 = &as->source_info[idx2];
                    690:
                    691:                        if (!si2->prev &&
                    692:                            ac97_str_equal(si->class, si2->class) &&
                    693:                            ac97_str_equal(si->device, si2->device)) {
                    694:                                as->source_info[previdx].next = idx2;
                    695:                                as->source_info[idx2].prev = previdx;
                    696:
                    697:                                previdx = idx2;
                    698:                        }
                    699:                }
                    700:
                    701:                as->source_info[previdx].next = AUDIO_MIXER_LAST;
                    702:        }
                    703: }
                    704:
                    705: int
                    706: ac97_attach(struct ac97_host_if *host_if)
                    707: {
                    708:        struct ac97_softc *as;
                    709:        u_int16_t id1, id2;
                    710:        u_int32_t id;
                    711:        mixer_ctrl_t ctl;
                    712:        int error, i;
                    713:        void (*initfunc)(struct ac97_softc *);
                    714:
                    715:        initfunc = NULL;
                    716:
                    717:        if (!(as = malloc(sizeof(struct ac97_softc), M_DEVBUF, M_NOWAIT)))
                    718:                return (ENOMEM);
                    719:
                    720:        bzero(as, sizeof(*as));
                    721:
                    722:        as->codec_if.vtbl = &ac97civ;
                    723:        as->host_if = host_if;
                    724:
                    725:        if ((error = host_if->attach(host_if->arg, &as->codec_if))) {
                    726:                free(as, M_DEVBUF);
                    727:                return (error);
                    728:        }
                    729:
                    730:        host_if->reset(host_if->arg);
                    731:        DELAY(1000);
                    732:
                    733:        host_if->write(host_if->arg, AC97_REG_POWER, 0);
                    734:        host_if->write(host_if->arg, AC97_REG_RESET, 0);
                    735:        DELAY(10000);
                    736:
                    737:        if (host_if->flags)
                    738:                as->host_flags = host_if->flags(host_if->arg);
                    739:
                    740:        ac97_setup_defaults(as);
                    741:        ac97_read(as, AC97_REG_VENDOR_ID1, &id1);
                    742:        ac97_read(as, AC97_REG_VENDOR_ID2, &id2);
                    743:        ac97_read(as, AC97_REG_RESET, &as->caps);
                    744:
                    745:        id = (id1 << 16) | id2;
                    746:        if (id) {
                    747:                register const struct ac97_vendorid *vendor;
                    748:                register const struct ac97_codecid *codec;
                    749:
                    750:                printf("ac97: codec id 0x%08x", id);
                    751:                for (vendor = &ac97_vendors[sizeof(ac97_vendors) /
                    752:                     sizeof(ac97_vendors[0]) - 1];
                    753:                     vendor >= ac97_vendors; vendor--) {
                    754:                        if (vendor->id == (id & AC97_VENDOR_ID_MASK)) {
                    755:                                printf(" (%s", vendor->name);
                    756:                                for (codec = &vendor->codecs[vendor->num-1];
                    757:                                     codec >= vendor->codecs; codec--) {
                    758:                                        if (codec->id == (id & codec->mask))
                    759:                                                break;
                    760:                                }
                    761:                                if (codec >= vendor->codecs && codec->mask) {
                    762:                                        printf(" %s", codec->name);
                    763:                                        initfunc = codec->init;
                    764:                                } else
                    765:                                        printf(" <%02x>", id & 0xff);
                    766:                                if (codec >= vendor->codecs && codec->rev)
                    767:                                        printf(" rev %d", id & codec->rev);
                    768:                                printf(")");
                    769:                                break;
                    770:                        }
                    771:                }
                    772:                printf("\n");
                    773:        } else
                    774:                printf("ac97: codec id not read\n");
                    775:
                    776:        if (as->caps) {
                    777:                printf("ac97: codec features ");
                    778:                for (i = 0; i < 10; i++) {
                    779:                        if (as->caps & (1 << i))
                    780:                                printf("%s, ", ac97feature[i]);
                    781:                }
                    782:                printf("%s\n",
                    783:                    ac97enhancement[AC97_CAPS_ENHANCEMENT(as->caps)]);
                    784:        }
                    785:
                    786:        ac97_read(as, AC97_REG_EXT_AUDIO_ID, &as->ext_id);
                    787:        if (as->ext_id)
                    788:                DPRINTF(("ac97: ext id %b\n", as->ext_id,
                    789:                    AC97_EXT_AUDIO_BITS));
                    790:        if (as->ext_id & (AC97_EXT_AUDIO_VRA | AC97_EXT_AUDIO_VRM)) {
                    791:                ac97_read(as, AC97_REG_EXT_AUDIO_CTRL, &id1);
                    792:                if (as->ext_id & AC97_EXT_AUDIO_VRA)
                    793:                        id1 |= AC97_EXT_AUDIO_VRA;
                    794:                if (as->ext_id & AC97_EXT_AUDIO_VRM)
                    795:                        id1 |= AC97_EXT_AUDIO_VRM;
                    796:                ac97_write(as, AC97_REG_EXT_AUDIO_CTRL, id1);
                    797:        }
                    798:
                    799:        ac97_setup_source_info(as);
                    800:
                    801:        /* use initfunc for specific device */
                    802:        if (initfunc != NULL)
                    803:                initfunc(as);
                    804:
                    805:        /* Just enable the DAC and master volumes by default */
                    806:        bzero(&ctl, sizeof(ctl));
                    807:
                    808:        ctl.type = AUDIO_MIXER_ENUM;
                    809:        ctl.un.ord = 0;  /* off */
                    810:        ctl.dev = ac97_get_portnum_by_name(&as->codec_if, AudioCoutputs,
                    811:            AudioNmaster, AudioNmute);
                    812:        ac97_mixer_set_port(&as->codec_if, &ctl);
                    813:
                    814:        ctl.dev = ac97_get_portnum_by_name(&as->codec_if, AudioCinputs,
                    815:            AudioNdac, AudioNmute);
                    816:        ac97_mixer_set_port(&as->codec_if, &ctl);
                    817:
                    818:        ctl.dev = ac97_get_portnum_by_name(&as->codec_if, AudioCrecord,
                    819:            AudioNvolume, AudioNmute);
                    820:        ac97_mixer_set_port(&as->codec_if, &ctl);
                    821:
                    822:        ctl.type = AUDIO_MIXER_ENUM;
                    823:        ctl.un.ord = 0;
                    824:        ctl.dev = ac97_get_portnum_by_name(&as->codec_if, AudioCrecord,
                    825:            AudioNsource, NULL);
                    826:        ac97_mixer_set_port(&as->codec_if, &ctl);
                    827:
                    828:        return (0);
                    829: }
                    830:
                    831: int
                    832: ac97_query_devinfo(struct ac97_codec_if *codec_if, mixer_devinfo_t *dip)
                    833: {
                    834:        struct ac97_softc *as = (struct ac97_softc *)codec_if;
                    835:
                    836:        if (dip->index < as->num_source_info) {
                    837:                struct ac97_source_info *si = &as->source_info[dip->index];
                    838:                const char *name;
                    839:
                    840:                dip->type = si->type;
                    841:                dip->mixer_class = si->mixer_class;
                    842:                dip->prev = si->prev;
                    843:                dip->next = si->next;
                    844:
                    845:                if (si->qualifier)
                    846:                        name = si->qualifier;
                    847:                else if (si->device)
                    848:                        name = si->device;
                    849:                else if (si->class)
                    850:                        name = si->class;
                    851:
                    852:                if (name)
                    853:                        strlcpy(dip->label.name, name, sizeof dip->label.name);
                    854:
                    855:                bcopy(si->info, &dip->un, si->info_size);
                    856:
                    857:                /* Set the delta for volume sources */
                    858:                if (dip->type == AUDIO_MIXER_VALUE)
                    859:                        dip->un.v.delta = 1 << (8 - si->bits);
                    860:
                    861:                return (0);
                    862:        }
                    863:
                    864:        return (ENXIO);
                    865: }
                    866:
                    867: int
                    868: ac97_mixer_set_port(struct ac97_codec_if *codec_if, mixer_ctrl_t *cp)
                    869: {
                    870:        struct ac97_softc *as = (struct ac97_softc *)codec_if;
                    871:        struct ac97_source_info *si = &as->source_info[cp->dev];
                    872:        u_int16_t mask;
                    873:        u_int16_t val, newval;
                    874:        int error;
                    875:
                    876:        if (cp->dev < 0 || cp->dev >= as->num_source_info ||
                    877:            cp->type != si->type)
                    878:                return (EINVAL);
                    879:
                    880:        ac97_read(as, si->reg, &val);
                    881:
                    882:        DPRINTFN(5, ("read(%x) = %x\n", si->reg, val));
                    883:
                    884:        mask = (1 << si->bits) - 1;
                    885:
                    886:        switch (cp->type) {
                    887:        case AUDIO_MIXER_ENUM:
                    888:                if (cp->un.ord > mask || cp->un.ord < 0)
                    889:                        return (EINVAL);
                    890:
                    891:                newval = (cp->un.ord << si->ofs);
                    892:                if (si->reg == AC97_REG_RECORD_SELECT) {
                    893:                        newval |= (newval << (8 + si->ofs));
                    894:                        mask |= (mask << 8);
                    895:                }
                    896:
                    897:                if (si->mute) {
                    898:                        newval |= newval << 8;
                    899:                        mask |= mask << 8;
                    900:                }
                    901:
                    902:                break;
                    903:        case AUDIO_MIXER_VALUE:
                    904:        {
                    905:                const struct audio_mixer_value *value = si->info;
                    906:                u_int16_t  l, r;
                    907:
                    908:                if (cp->un.value.num_channels <= 0 ||
                    909:                    cp->un.value.num_channels > value->num_channels)
                    910:                        return (EINVAL);
                    911:
                    912:                if (cp->un.value.num_channels == 1) {
                    913:                        l = r = cp->un.value.level[AUDIO_MIXER_LEVEL_MONO];
                    914:                } else {
                    915:                        if (!(as->host_flags & AC97_HOST_SWAPPED_CHANNELS)) {
                    916:                                l = cp->un.value.level[AUDIO_MIXER_LEVEL_LEFT];
                    917:                                r = cp->un.value.level[AUDIO_MIXER_LEVEL_RIGHT];
                    918:                        } else {
                    919:                                r = cp->un.value.level[AUDIO_MIXER_LEVEL_LEFT];
                    920:                                l = cp->un.value.level[AUDIO_MIXER_LEVEL_RIGHT];
                    921:                        }
                    922:                }
                    923:
                    924:                if (!si->polarity) {
                    925:                        l = 255 - l;
                    926:                        r = 255 - r;
                    927:                }
                    928:
                    929:                l >>= 8 - si->bits;
                    930:                r >>= 8 - si->bits;
                    931:
                    932:                newval = ((l & mask) << si->ofs);
                    933:                if (value->num_channels == 2) {
                    934:                        newval |= ((r & mask) << (si->ofs + 8));
                    935:                        mask |= (mask << 8);
                    936:                }
                    937:
                    938:                break;
                    939:        }
                    940:        default:
                    941:                return (EINVAL);
                    942:        }
                    943:
                    944:        mask = mask << si->ofs;
                    945:        error = ac97_write(as, si->reg, (val & ~mask) | newval);
                    946:        if (error)
                    947:                return (error);
                    948:
                    949:        return (0);
                    950: }
                    951:
                    952: int
                    953: ac97_get_portnum_by_name(struct ac97_codec_if *codec_if, char *class,
                    954:     char *device, char *qualifier)
                    955: {
                    956:        struct ac97_softc *as = (struct ac97_softc *)codec_if;
                    957:        int idx;
                    958:
                    959:        for (idx = 0; idx < as->num_source_info; idx++) {
                    960:                struct ac97_source_info *si = &as->source_info[idx];
                    961:                if (ac97_str_equal(class, si->class) &&
                    962:                    ac97_str_equal(device, si->device) &&
                    963:                    ac97_str_equal(qualifier, si->qualifier))
                    964:                        return (idx);
                    965:        }
                    966:
                    967:        return (-1);
                    968: }
                    969:
                    970: int
                    971: ac97_mixer_get_port(struct ac97_codec_if *codec_if, mixer_ctrl_t *cp)
                    972: {
                    973:        struct ac97_softc *as = (struct ac97_softc *)codec_if;
                    974:        struct ac97_source_info *si = &as->source_info[cp->dev];
                    975:        u_int16_t mask;
                    976:        u_int16_t val;
                    977:
                    978:        if (cp->dev < 0 || cp->dev >= as->num_source_info ||
                    979:            cp->type != si->type)
                    980:                return (EINVAL);
                    981:
                    982:        ac97_read(as, si->reg, &val);
                    983:
                    984:        DPRINTFN(5, ("read(%x) = %x\n", si->reg, val));
                    985:
                    986:        mask = (1 << si->bits) - 1;
                    987:
                    988:        switch (cp->type) {
                    989:        case AUDIO_MIXER_ENUM:
                    990:                cp->un.ord = (val >> si->ofs) & mask;
                    991:                DPRINTFN(4, ("AUDIO_MIXER_ENUM: %x %d %x %d\n", val, si->ofs,
                    992:                    mask, cp->un.ord));
                    993:                break;
                    994:        case AUDIO_MIXER_VALUE:
                    995:        {
                    996:                const struct audio_mixer_value *value = si->info;
                    997:                u_int16_t  l, r;
                    998:
                    999:                if ((cp->un.value.num_channels <= 0) ||
                   1000:                    (cp->un.value.num_channels > value->num_channels))
                   1001:                        return (EINVAL);
                   1002:
                   1003:                if (value->num_channels == 1)
                   1004:                        l = r = (val >> si->ofs) & mask;
                   1005:                else {
                   1006:                        if (!(as->host_flags & AC97_HOST_SWAPPED_CHANNELS)) {
                   1007:                                l = (val >> si->ofs) & mask;
                   1008:                                r = (val >> (si->ofs + 8)) & mask;
                   1009:                        } else {
                   1010:                                r = (val >> si->ofs) & mask;
                   1011:                                l = (val >> (si->ofs + 8)) & mask;
                   1012:                        }
                   1013:                }
                   1014:
                   1015:                l <<= 8 - si->bits;
                   1016:                r <<= 8 - si->bits;
                   1017:                if (!si->polarity) {
                   1018:                        l = 255 - l;
                   1019:                        r = 255 - r;
                   1020:                }
                   1021:
                   1022:                /*
                   1023:                 * The EAP driver averages l and r for stereo
                   1024:                 * channels that are requested in MONO mode. Does this
                   1025:                 * make sense?
                   1026:                 */
                   1027:                if (cp->un.value.num_channels == 1) {
                   1028:                        cp->un.value.level[AUDIO_MIXER_LEVEL_MONO] = l;
                   1029:                } else if (cp->un.value.num_channels == 2) {
                   1030:                        cp->un.value.level[AUDIO_MIXER_LEVEL_LEFT] = l;
                   1031:                        cp->un.value.level[AUDIO_MIXER_LEVEL_RIGHT] = r;
                   1032:                }
                   1033:
                   1034:                break;
                   1035:        }
                   1036:        default:
                   1037:                return (EINVAL);
                   1038:        }
                   1039:
                   1040:        return (0);
                   1041: }
                   1042:
                   1043: int
                   1044: ac97_set_rate(struct ac97_codec_if *codec_if, struct audio_params *p,
                   1045:     int mode)
                   1046: {
                   1047:        struct ac97_softc *as = (struct ac97_softc *)codec_if;
                   1048:        u_int16_t reg, val, regval, id = 0;
                   1049:
                   1050:        DPRINTFN(5, ("set_rate(%lu) ", p->sample_rate));
                   1051:
                   1052:        if (!(as->ext_id & AC97_EXT_AUDIO_VRA)) {
                   1053:                p->sample_rate = AC97_SINGLERATE;
                   1054:                return (0);
                   1055:        }
                   1056:
                   1057:        if (p->sample_rate > 0xffff) {
                   1058:                if (mode != AUMODE_PLAY)
                   1059:                        return (EINVAL);
                   1060:                if (!(as->ext_id & AC97_EXT_AUDIO_DRA))
                   1061:                        return (EINVAL);
                   1062:                if (ac97_read(as, AC97_REG_EXT_AUDIO_CTRL, &id))
                   1063:                        return (EIO);
                   1064:                id |= AC97_EXT_AUDIO_DRA;
                   1065:                if (ac97_write(as, AC97_REG_EXT_AUDIO_CTRL, id))
                   1066:                        return (EIO);
                   1067:                p->sample_rate /= 2;
                   1068:        }
                   1069:
                   1070:        /* i guess it's better w/o clicks and squeecks when changing the rate */
                   1071:        if (ac97_read(as, AC97_REG_POWER, &val) ||
                   1072:            ac97_write(as, AC97_REG_POWER, val |
                   1073:              (mode == AUMODE_PLAY? AC97_POWER_OUT : AC97_POWER_IN)))
                   1074:                return (EIO);
                   1075:
                   1076:        reg = mode == AUMODE_PLAY ?
                   1077:            AC97_REG_FRONT_DAC_RATE : AC97_REG_PCM_ADC_RATE;
                   1078:
                   1079:        if (ac97_write(as, reg, (u_int16_t) p->sample_rate) ||
                   1080:            ac97_read(as, reg, &regval))
                   1081:                return (EIO);
                   1082:        p->sample_rate = regval;
                   1083:        if (id & AC97_EXT_AUDIO_DRA)
                   1084:                p->sample_rate *= 2;
                   1085:
                   1086:        DPRINTFN(5, (" %lu\n", regval));
                   1087:
                   1088:        if (ac97_write(as, AC97_REG_POWER, val))
                   1089:                return (EIO);
                   1090:
                   1091:        return (0);
                   1092: }
                   1093:
                   1094: /*
                   1095:  * Codec-dependent initialization
                   1096:  */
                   1097:
                   1098: #define AC97_AD1886_JACK_SENSE 0x72
                   1099:
                   1100: void
                   1101: ac97_ad1886_init(struct ac97_softc *as)
                   1102: {
                   1103:        ac97_write(as, AC97_AD1886_JACK_SENSE, 0x0010);
                   1104: }
                   1105:
                   1106: void
                   1107: ac97_ad198x_init(struct ac97_softc *as)
                   1108: {
                   1109:        int i;
                   1110:        u_int16_t misc;
                   1111:
                   1112:        ac97_read(as, AC97_AD_REG_MISC, &misc);
                   1113:        ac97_write(as, AC97_AD_REG_MISC,
                   1114:            misc|AC97_AD_MISC_HPSEL|AC97_AD_MISC_LOSEL);
                   1115:
                   1116:        for (i = 0; i < as->num_source_info; i++) {
                   1117:                if (as->source_info[i].reg == AC97_REG_SURROUND_VOLUME)
                   1118:                        as->source_info[i].reg = AC97_REG_MASTER_VOLUME;
                   1119:                else if (as->source_info[i].reg == AC97_REG_MASTER_VOLUME) {
                   1120:                        as->source_info[i].reg = AC97_REG_SURROUND_VOLUME;
                   1121:                        if (as->source_info[i].type == AUDIO_MIXER_ENUM) {
                   1122:                                as->source_info[i].mute = 1;
                   1123:                                as->source_info[i].ofs = 7;
                   1124:                        }
                   1125:                }
                   1126:        }
                   1127: }
                   1128:
                   1129: void
                   1130: ac97_alc655_init(struct ac97_softc *as)
                   1131: {
                   1132:        u_int16_t misc;
                   1133:
                   1134:        ac97_read(as, AC97_AV_REG_MISC, &misc);
                   1135:        if (as->host_flags & AC97_HOST_DONT_ENABLE_SPDIF) {
                   1136:                misc &= ~AC97_AV_MISC_SPDIFEN;
                   1137:        } else  {
                   1138:                misc |= AC97_AV_MISC_SPDIFEN;
                   1139:        }
                   1140:        misc &= ~AC97_AV_MISC_VREFDIS;
                   1141:        ac97_write(as, AC97_AV_REG_MISC, misc);
                   1142:
                   1143:        ac97_write(as, AC97_AV_REG_MULTICH, AC97_AV_MULTICH_MAGIC);
                   1144: }
                   1145:
                   1146: void
                   1147: ac97_cx20468_init(struct ac97_softc *as)
                   1148: {
                   1149:        u_int16_t misc;
                   1150:
                   1151:        ac97_read(as, AC97_CX_REG_MISC, &misc);
                   1152:        ac97_write(as, AC97_CX_REG_MISC, misc &
                   1153:            ~(AC97_CX_SPDIFEN | AC97_CX_COPYRIGHT | AC97_CX_MASK));
                   1154: }

CVSweb