1987e5972SCameron Grant /* 2987e5972SCameron Grant * Copyright (c) 1999 Cameron Grant <gandalf@vilnya.demon.co.uk> 3987e5972SCameron Grant * All rights reserved. 4987e5972SCameron Grant * 5987e5972SCameron Grant * Redistribution and use in source and binary forms, with or without 6987e5972SCameron Grant * modification, are permitted provided that the following conditions 7987e5972SCameron Grant * are met: 8987e5972SCameron Grant * 1. Redistributions of source code must retain the above copyright 9987e5972SCameron Grant * notice, this list of conditions and the following disclaimer. 10987e5972SCameron Grant * 2. Redistributions in binary form must reproduce the above copyright 11987e5972SCameron Grant * notice, this list of conditions and the following disclaimer in the 12987e5972SCameron Grant * documentation and/or other materials provided with the distribution. 13987e5972SCameron Grant * 14987e5972SCameron Grant * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 15987e5972SCameron Grant * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16987e5972SCameron Grant * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17987e5972SCameron Grant * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 18987e5972SCameron Grant * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19987e5972SCameron Grant * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20987e5972SCameron Grant * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21987e5972SCameron Grant * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 22987e5972SCameron Grant * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 23987e5972SCameron Grant * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 24987e5972SCameron Grant * SUCH DAMAGE. 25987e5972SCameron Grant * 2653c5a968SPeter Wemm * $FreeBSD$ 27987e5972SCameron Grant */ 28987e5972SCameron Grant 29ef9308b1SCameron Grant #include <dev/sound/pcm/sound.h> 30ef9308b1SCameron Grant #include <dev/sound/pcm/ac97.h> 31987e5972SCameron Grant 32987e5972SCameron Grant struct ac97mixtable_entry { 33987e5972SCameron Grant int reg:8; 34987e5972SCameron Grant unsigned bits:4; 35987e5972SCameron Grant unsigned ofs:4; 36987e5972SCameron Grant unsigned stereo:1; 37987e5972SCameron Grant unsigned mute:1; 38987e5972SCameron Grant unsigned recidx:4; 39987e5972SCameron Grant unsigned mask:1; 40341f16ccSCameron Grant unsigned enable:1; 41987e5972SCameron Grant }; 42987e5972SCameron Grant 43987e5972SCameron Grant struct ac97_info { 4403a00905SCameron Grant device_t dev; 4539004e69SCameron Grant ac97_init *init; 46987e5972SCameron Grant ac97_read *read; 47987e5972SCameron Grant ac97_write *write; 48987e5972SCameron Grant void *devinfo; 49cd2c103aSCameron Grant char *name; 50987e5972SCameron Grant char rev; 51cd2c103aSCameron Grant unsigned count, caps, se, extcaps, extid, extstat, noext:1; 52987e5972SCameron Grant struct ac97mixtable_entry mix[32]; 53987e5972SCameron Grant }; 54987e5972SCameron Grant 55987e5972SCameron Grant struct ac97_codecid { 566b4b88f7SCameron Grant u_int32_t id, noext:1; 57987e5972SCameron Grant char *name; 58987e5972SCameron Grant }; 59987e5972SCameron Grant 60987e5972SCameron Grant static const struct ac97mixtable_entry ac97mixtable_default[32] = { 61341f16ccSCameron Grant [SOUND_MIXER_VOLUME] = { AC97_MIX_MASTER, 5, 0, 1, 1, 6, 0, 1 }, 62341f16ccSCameron Grant [SOUND_MIXER_MONITOR] = { AC97_MIX_PHONES, 5, 0, 1, 1, 0, 0, 0 }, 63341f16ccSCameron Grant [SOUND_MIXER_PHONEOUT] = { AC97_MIX_MONO, 5, 0, 0, 1, 7, 0, 0 }, 64341f16ccSCameron Grant [SOUND_MIXER_BASS] = { AC97_MIX_TONE, 4, 8, 0, 0, 0, 1, 0 }, 65341f16ccSCameron Grant [SOUND_MIXER_TREBLE] = { AC97_MIX_TONE, 4, 0, 0, 0, 0, 1, 0 }, 66341f16ccSCameron Grant [SOUND_MIXER_PCM] = { AC97_MIX_PCM, 5, 0, 1, 1, 0, 0, 1 }, 67341f16ccSCameron Grant [SOUND_MIXER_SPEAKER] = { AC97_MIX_BEEP, 4, 1, 0, 1, 0, 0, 0 }, 68341f16ccSCameron Grant [SOUND_MIXER_LINE] = { AC97_MIX_LINE, 5, 0, 1, 1, 5, 0, 1 }, 69341f16ccSCameron Grant [SOUND_MIXER_PHONEIN] = { AC97_MIX_PHONE, 5, 0, 0, 1, 8, 0, 0 }, 70341f16ccSCameron Grant [SOUND_MIXER_MIC] = { AC97_MIX_MIC, 5, 0, 0, 1, 1, 0, 1 }, 71341f16ccSCameron Grant [SOUND_MIXER_CD] = { AC97_MIX_CD, 5, 0, 1, 1, 2, 0, 1 }, 72341f16ccSCameron Grant [SOUND_MIXER_LINE1] = { AC97_MIX_AUX, 5, 0, 1, 1, 4, 0, 0 }, 73341f16ccSCameron Grant [SOUND_MIXER_VIDEO] = { AC97_MIX_VIDEO, 5, 0, 1, 1, 3, 0, 0 }, 74341f16ccSCameron Grant [SOUND_MIXER_RECLEV] = { -AC97_MIX_RGAIN, 4, 0, 1, 1, 0, 0, 1 } 75987e5972SCameron Grant }; 76987e5972SCameron Grant 77987e5972SCameron Grant static struct ac97_codecid ac97codecid[] = { 786b4b88f7SCameron Grant { 0x414b4d00, 1, "Asahi Kasei AK4540 rev 0" }, 79cd2c103aSCameron Grant { 0x414b4d01, 1, "Asahi Kasei AK4540 rev 1" }, 806b4b88f7SCameron Grant { 0x43525900, 0, "Cirrus Logic CS4297" }, 816b4b88f7SCameron Grant { 0x83847600, 0, "SigmaTel STAC????" }, 826b4b88f7SCameron Grant { 0x83847604, 0, "SigmaTel STAC9701/3/4/5" }, 836b4b88f7SCameron Grant { 0x83847605, 0, "SigmaTel STAC9704" }, 846b4b88f7SCameron Grant { 0x83847608, 0, "SigmaTel STAC9708" }, 856b4b88f7SCameron Grant { 0x83847609, 0, "SigmaTel STAC9721" }, 866b4b88f7SCameron Grant { 0, 0, NULL } 87987e5972SCameron Grant }; 88987e5972SCameron Grant 89987e5972SCameron Grant static char *ac97enhancement[] = { 9004553e63SCameron Grant "no 3D Stereo Enhancement", 91987e5972SCameron Grant "Analog Devices Phat Stereo", 92987e5972SCameron Grant "Creative Stereo Enhancement", 93987e5972SCameron Grant "National Semi 3D Stereo Enhancement", 94987e5972SCameron Grant "Yamaha Ymersion", 95987e5972SCameron Grant "BBE 3D Stereo Enhancement", 96987e5972SCameron Grant "Crystal Semi 3D Stereo Enhancement", 97987e5972SCameron Grant "Qsound QXpander", 98987e5972SCameron Grant "Spatializer 3D Stereo Enhancement", 99987e5972SCameron Grant "SRS 3D Stereo Enhancement", 100987e5972SCameron Grant "Platform Tech 3D Stereo Enhancement", 101987e5972SCameron Grant "AKM 3D Audio", 102987e5972SCameron Grant "Aureal Stereo Enhancement", 103987e5972SCameron Grant "Aztech 3D Enhancement", 104987e5972SCameron Grant "Binaura 3D Audio Enhancement", 105987e5972SCameron Grant "ESS Technology Stereo Enhancement", 106987e5972SCameron Grant "Harman International VMAx", 107987e5972SCameron Grant "Nvidea 3D Stereo Enhancement", 108987e5972SCameron Grant "Philips Incredible Sound", 109987e5972SCameron Grant "Texas Instruments 3D Stereo Enhancement", 110987e5972SCameron Grant "VLSI Technology 3D Stereo Enhancement", 111987e5972SCameron Grant "TriTech 3D Stereo Enhancement", 112987e5972SCameron Grant "Realtek 3D Stereo Enhancement", 113987e5972SCameron Grant "Samsung 3D Stereo Enhancement", 114987e5972SCameron Grant "Wolfson Microelectronics 3D Enhancement", 115987e5972SCameron Grant "Delta Integration 3D Enhancement", 116987e5972SCameron Grant "SigmaTel 3D Enhancement", 117987e5972SCameron Grant "Reserved 27", 118987e5972SCameron Grant "Rockwell 3D Stereo Enhancement", 119987e5972SCameron Grant "Reserved 29", 120987e5972SCameron Grant "Reserved 30", 121987e5972SCameron Grant "Reserved 31" 122987e5972SCameron Grant }; 123987e5972SCameron Grant 124987e5972SCameron Grant static char *ac97feature[] = { 125987e5972SCameron Grant "mic channel", 126987e5972SCameron Grant "reserved", 127987e5972SCameron Grant "tone", 128987e5972SCameron Grant "simulated stereo", 129987e5972SCameron Grant "headphone", 130987e5972SCameron Grant "bass boost", 131987e5972SCameron Grant "18 bit DAC", 132987e5972SCameron Grant "20 bit DAC", 133987e5972SCameron Grant "18 bit ADC", 134987e5972SCameron Grant "20 bit ADC" 135987e5972SCameron Grant }; 136987e5972SCameron Grant 13739004e69SCameron Grant static char *ac97extfeature[] = { 13839004e69SCameron Grant "variable rate PCM", 13939004e69SCameron Grant "double rate PCM", 14039004e69SCameron Grant "reserved 1", 14139004e69SCameron Grant "variable rate mic", 14239004e69SCameron Grant "reserved 2", 14339004e69SCameron Grant "reserved 3", 14439004e69SCameron Grant "center DAC", 14539004e69SCameron Grant "surround DAC", 14639004e69SCameron Grant "LFE DAC", 14739004e69SCameron Grant "AMAP", 14839004e69SCameron Grant "reserved 4", 14939004e69SCameron Grant "reserved 5", 15039004e69SCameron Grant "reserved 6", 15139004e69SCameron Grant "reserved 7", 15239004e69SCameron Grant }; 15339004e69SCameron Grant 15439004e69SCameron Grant static u_int16_t 15539004e69SCameron Grant rdcd(struct ac97_info *codec, int reg) 15639004e69SCameron Grant { 15739004e69SCameron Grant return codec->read(codec->devinfo, reg); 15839004e69SCameron Grant } 15939004e69SCameron Grant 16039004e69SCameron Grant static void 16139004e69SCameron Grant wrcd(struct ac97_info *codec, int reg, u_int16_t val) 16239004e69SCameron Grant { 16339004e69SCameron Grant codec->write(codec->devinfo, reg, val); 16439004e69SCameron Grant } 16539004e69SCameron Grant 16639004e69SCameron Grant int 16739004e69SCameron Grant ac97_setrate(struct ac97_info *codec, int which, int rate) 16839004e69SCameron Grant { 16939004e69SCameron Grant u_int16_t v; 17039004e69SCameron Grant 17139004e69SCameron Grant switch(which) { 17239004e69SCameron Grant case AC97_REGEXT_FDACRATE: 17339004e69SCameron Grant case AC97_REGEXT_SDACRATE: 17439004e69SCameron Grant case AC97_REGEXT_LDACRATE: 17539004e69SCameron Grant case AC97_REGEXT_LADCRATE: 17639004e69SCameron Grant case AC97_REGEXT_MADCRATE: 17739004e69SCameron Grant break; 17839004e69SCameron Grant 17939004e69SCameron Grant default: 18039004e69SCameron Grant return -1; 18139004e69SCameron Grant } 18239004e69SCameron Grant 18339004e69SCameron Grant if (rate != 0) { 18439004e69SCameron Grant v = rate; 18539004e69SCameron Grant if (codec->extstat & AC97_EXTCAP_DRA) 18639004e69SCameron Grant v >>= 1; 18739004e69SCameron Grant wrcd(codec, which, v); 18839004e69SCameron Grant } 18939004e69SCameron Grant v = rdcd(codec, which); 19039004e69SCameron Grant if (codec->extstat & AC97_EXTCAP_DRA) 19139004e69SCameron Grant v <<= 1; 19239004e69SCameron Grant return v; 19339004e69SCameron Grant } 19439004e69SCameron Grant 19539004e69SCameron Grant int 19639004e69SCameron Grant ac97_setextmode(struct ac97_info *codec, u_int16_t mode) 19739004e69SCameron Grant { 19839004e69SCameron Grant mode &= AC97_EXTCAPS; 19939004e69SCameron Grant if ((mode & ~codec->extcaps) != 0) 20039004e69SCameron Grant return -1; 20139004e69SCameron Grant wrcd(codec, AC97_REGEXT_STAT, mode); 20239004e69SCameron Grant codec->extstat = rdcd(codec, AC97_REGEXT_STAT) & AC97_EXTCAPS; 20339004e69SCameron Grant return (mode == codec->extstat)? 0 : -1; 20439004e69SCameron Grant } 20539004e69SCameron Grant 206987e5972SCameron Grant static int 207987e5972SCameron Grant ac97_setrecsrc(struct ac97_info *codec, int channel) 208987e5972SCameron Grant { 209987e5972SCameron Grant struct ac97mixtable_entry *e = &codec->mix[channel]; 210341f16ccSCameron Grant 211987e5972SCameron Grant if (e->recidx > 0) { 212987e5972SCameron Grant int val = e->recidx - 1; 213987e5972SCameron Grant val |= val << 8; 21439004e69SCameron Grant wrcd(codec, AC97_REG_RECSEL, val); 215987e5972SCameron Grant return 0; 21639004e69SCameron Grant } else 21739004e69SCameron Grant return -1; 218987e5972SCameron Grant } 219987e5972SCameron Grant 220987e5972SCameron Grant static int 221987e5972SCameron Grant ac97_setmixer(struct ac97_info *codec, unsigned channel, unsigned left, unsigned right) 222987e5972SCameron Grant { 223987e5972SCameron Grant struct ac97mixtable_entry *e = &codec->mix[channel]; 224341f16ccSCameron Grant 225341f16ccSCameron Grant if (e->reg && e->enable && e->bits) { 226e479a8afSCameron Grant int max, val, reg = (e->reg >= 0)? e->reg : -e->reg; 227987e5972SCameron Grant 22839004e69SCameron Grant if (!e->stereo) 22939004e69SCameron Grant right = left; 230987e5972SCameron Grant if (e->reg > 0) { 231987e5972SCameron Grant left = 100 - left; 232987e5972SCameron Grant right = 100 - right; 233987e5972SCameron Grant } 234987e5972SCameron Grant 235987e5972SCameron Grant max = (1 << e->bits) - 1; 236987e5972SCameron Grant left = (left * max) / 100; 237987e5972SCameron Grant right = (right * max) / 100; 238987e5972SCameron Grant 239987e5972SCameron Grant val = (left << 8) | right; 240987e5972SCameron Grant 241987e5972SCameron Grant left = (left * 100) / max; 242987e5972SCameron Grant right = (right * 100) / max; 243987e5972SCameron Grant 244987e5972SCameron Grant if (e->reg > 0) { 245987e5972SCameron Grant left = 100 - left; 246987e5972SCameron Grant right = 100 - right; 247987e5972SCameron Grant } 248987e5972SCameron Grant 249987e5972SCameron Grant if (!e->stereo) { 250987e5972SCameron Grant val &= max; 251987e5972SCameron Grant val <<= e->ofs; 252987e5972SCameron Grant if (e->mask) { 25339004e69SCameron Grant int cur = rdcd(codec, e->reg); 254987e5972SCameron Grant val |= cur & ~(max << e->ofs); 255987e5972SCameron Grant } 256987e5972SCameron Grant } 25739004e69SCameron Grant if (left == 0 && right == 0 && e->mute == 1) 25839004e69SCameron Grant val = AC97_MUTE; 25939004e69SCameron Grant wrcd(codec, reg, val); 260987e5972SCameron Grant return left | (right << 8); 261341f16ccSCameron Grant } else { 262341f16ccSCameron Grant /* printf("ac97_setmixer: reg=%d, bits=%d, enable=%d\n", e->reg, e->bits, e->enable); */ 26339004e69SCameron Grant return -1; 264987e5972SCameron Grant } 265341f16ccSCameron Grant } 266987e5972SCameron Grant 267987e5972SCameron Grant #if 0 268987e5972SCameron Grant static int 269987e5972SCameron Grant ac97_getmixer(struct ac97_info *codec, int channel) 270987e5972SCameron Grant { 271987e5972SCameron Grant struct ac97mixtable_entry *e = &codec->mix[channel]; 272987e5972SCameron Grant if (channel < SOUND_MIXER_NRDEVICES && e->reg != 0) { 273987e5972SCameron Grant int max, val, volume; 274987e5972SCameron Grant 275987e5972SCameron Grant max = (1 << e->bits) - 1; 27639004e69SCameron Grant val = rdcd(code, e->reg); 27739004e69SCameron Grant if (val == AC97_MUTE && e->mute == 1) 27839004e69SCameron Grant volume = 0; 279987e5972SCameron Grant else { 280987e5972SCameron Grant if (e->stereo == 0) val >>= e->ofs; 281987e5972SCameron Grant val &= max; 282987e5972SCameron Grant volume = (val * 100) / max; 283987e5972SCameron Grant if (e->reg > 0) volume = 100 - volume; 284987e5972SCameron Grant } 285987e5972SCameron Grant return volume; 28639004e69SCameron Grant } else 28739004e69SCameron Grant return -1; 288987e5972SCameron Grant } 289987e5972SCameron Grant #endif 290987e5972SCameron Grant 291987e5972SCameron Grant static unsigned 29239004e69SCameron Grant ac97_initmixer(struct ac97_info *codec) 293987e5972SCameron Grant { 294341f16ccSCameron Grant unsigned i, j, k, old; 295987e5972SCameron Grant u_int32_t id; 296987e5972SCameron Grant 29739004e69SCameron Grant for (i = 0; i < 32; i++) 29839004e69SCameron Grant codec->mix[i] = ac97mixtable_default[i]; 299987e5972SCameron Grant 30004553e63SCameron Grant if (codec->init) { 301cd2c103aSCameron Grant codec->count = codec->init(codec->devinfo); 302cd2c103aSCameron Grant if (codec->count == 0) { 30304553e63SCameron Grant device_printf(codec->dev, "ac97 codec init failed\n"); 30404553e63SCameron Grant return ENODEV; 30504553e63SCameron Grant } 306cd2c103aSCameron Grant } else 307cd2c103aSCameron Grant codec->count = 1; 30839004e69SCameron Grant wrcd(codec, AC97_REG_POWER, 0); 30939004e69SCameron Grant wrcd(codec, AC97_REG_RESET, 0); 310e620d959SCameron Grant DELAY(100000); 311987e5972SCameron Grant 31239004e69SCameron Grant i = rdcd(codec, AC97_REG_RESET); 313987e5972SCameron Grant codec->caps = i & 0x03ff; 314987e5972SCameron Grant codec->se = (i & 0x7c00) >> 10; 315987e5972SCameron Grant 3166b4b88f7SCameron Grant id = (rdcd(codec, AC97_REG_ID1) << 16) | rdcd(codec, AC97_REG_ID2); 3176b4b88f7SCameron Grant codec->rev = id & 0x000000ff; 318e620d959SCameron Grant if (id == 0 || id == 0xffffffff) { 319e620d959SCameron Grant device_printf(codec->dev, "ac97 codec invalid or not present (id == %x)\n", id); 320e620d959SCameron Grant return ENODEV; 321e620d959SCameron Grant } 3226b4b88f7SCameron Grant 323cd2c103aSCameron Grant codec->noext = 0; 324cd2c103aSCameron Grant codec->name = NULL; 325cd2c103aSCameron Grant for (i = 0; ac97codecid[i].id; i++) { 326cd2c103aSCameron Grant if (ac97codecid[i].id == id) { 327cd2c103aSCameron Grant codec->name = ac97codecid[i].name; 328cd2c103aSCameron Grant codec->noext = ac97codecid[i].noext; 329cd2c103aSCameron Grant } 330cd2c103aSCameron Grant } 3316b4b88f7SCameron Grant 332cd2c103aSCameron Grant if (codec->noext) { 333cd2c103aSCameron Grant codec->extcaps = 0; 334cd2c103aSCameron Grant codec->extid = 0; 335cd2c103aSCameron Grant codec->extstat = 0; 336cd2c103aSCameron Grant } else { 33739004e69SCameron Grant i = rdcd(codec, AC97_REGEXT_ID); 33839004e69SCameron Grant codec->extcaps = i & 0x3fff; 33939004e69SCameron Grant codec->extid = (i & 0xc000) >> 14; 34039004e69SCameron Grant codec->extstat = rdcd(codec, AC97_REGEXT_STAT) & AC97_EXTCAPS; 3416b4b88f7SCameron Grant } 342987e5972SCameron Grant 343341f16ccSCameron Grant for (i = 0; i < 32; i++) { 344341f16ccSCameron Grant if (codec->mix[i].reg > 0) { 345341f16ccSCameron Grant old = rdcd(codec, codec->mix[i].reg); 346341f16ccSCameron Grant wrcd(codec, codec->mix[i].reg, 0x3f); 347341f16ccSCameron Grant j = rdcd(codec, codec->mix[i].reg); 348341f16ccSCameron Grant wrcd(codec, codec->mix[i].reg, old); 349341f16ccSCameron Grant codec->mix[i].enable = j? 1 : 0; 350341f16ccSCameron Grant for (k = 1; j & (1 << k); k++); 351341f16ccSCameron Grant codec->mix[i].bits = j? k - codec->mix[i].ofs : 0; 352341f16ccSCameron Grant } 353341f16ccSCameron Grant /* printf("mixch %d, en=%d, b=%d\n", i, codec->mix[i].enable, codec->mix[i].bits); */ 354341f16ccSCameron Grant } 355987e5972SCameron Grant 356987e5972SCameron Grant if (bootverbose) { 357e620d959SCameron Grant device_printf(codec->dev, "ac97 codec id 0x%08x", id); 358cd2c103aSCameron Grant if (codec->name) 359cd2c103aSCameron Grant printf(" (%s)", codec->name); 36003a00905SCameron Grant printf("\n"); 36103a00905SCameron Grant device_printf(codec->dev, "ac97 codec features "); 36239004e69SCameron Grant for (i = j = 0; i < 10; i++) 36339004e69SCameron Grant if (codec->caps & (1 << i)) 36439004e69SCameron Grant printf("%s%s", j++? ", " : "", ac97feature[i]); 36539004e69SCameron Grant printf("%s%d bit master volume", j++? ", " : "", codec->mix[SOUND_MIXER_VOLUME].bits); 366987e5972SCameron Grant printf("%s%s\n", j? ", " : "", ac97enhancement[codec->se]); 36739004e69SCameron Grant 36839004e69SCameron Grant if (codec->extcaps != 0 || codec->extid) { 36939004e69SCameron Grant device_printf(codec->dev, "ac97 %s codec", 37039004e69SCameron Grant codec->extid? "secondary" : "primary"); 37139004e69SCameron Grant if (codec->extcaps) 37239004e69SCameron Grant printf(" extended features "); 37339004e69SCameron Grant for (i = j = 0; i < 14; i++) 37439004e69SCameron Grant if (codec->extcaps & (1 << i)) 37539004e69SCameron Grant printf("%s%s", j++? ", " : "", ac97extfeature[i]); 37639004e69SCameron Grant printf("\n"); 37739004e69SCameron Grant } 378987e5972SCameron Grant } 379987e5972SCameron Grant 38039004e69SCameron Grant if ((rdcd(codec, AC97_REG_POWER) & 2) == 0) 38103a00905SCameron Grant device_printf(codec->dev, "ac97 codec reports dac not ready\n"); 382987e5972SCameron Grant return 0; 383987e5972SCameron Grant } 384987e5972SCameron Grant 385987e5972SCameron Grant struct ac97_info * 38639004e69SCameron Grant ac97_create(device_t dev, void *devinfo, ac97_init *init, ac97_read *rd, ac97_write *wr) 387987e5972SCameron Grant { 388987e5972SCameron Grant struct ac97_info *codec; 389987e5972SCameron Grant 390987e5972SCameron Grant codec = (struct ac97_info *)malloc(sizeof *codec, M_DEVBUF, M_NOWAIT); 391987e5972SCameron Grant if (codec != NULL) { 39203a00905SCameron Grant codec->dev = dev; 39339004e69SCameron Grant codec->init = init; 394987e5972SCameron Grant codec->read = rd; 395987e5972SCameron Grant codec->write = wr; 396987e5972SCameron Grant codec->devinfo = devinfo; 397987e5972SCameron Grant } 398987e5972SCameron Grant return codec; 399987e5972SCameron Grant } 400987e5972SCameron Grant 40133dbf14aSCameron Grant void 40233dbf14aSCameron Grant ac97_destroy(struct ac97_info *codec) 40333dbf14aSCameron Grant { 40433dbf14aSCameron Grant free(codec, M_DEVBUF); 40533dbf14aSCameron Grant } 40633dbf14aSCameron Grant 407987e5972SCameron Grant static int 408987e5972SCameron Grant ac97mix_init(snd_mixer *m) 409987e5972SCameron Grant { 410987e5972SCameron Grant struct ac97_info *codec = mix_getdevinfo(m); 411341f16ccSCameron Grant u_int32_t i, mask; 412341f16ccSCameron Grant 41339004e69SCameron Grant if (codec == NULL) 41439004e69SCameron Grant return -1; 415341f16ccSCameron Grant 416e620d959SCameron Grant if (ac97_initmixer(codec)) 417e620d959SCameron Grant return -1; 418341f16ccSCameron Grant 419341f16ccSCameron Grant mask = 0; 420341f16ccSCameron Grant for (i = 0; i < 32; i++) 421341f16ccSCameron Grant mask |= codec->mix[i].enable? 1 << i : 0; 422341f16ccSCameron Grant mix_setdevs(m, mask); 423341f16ccSCameron Grant 424341f16ccSCameron Grant mask = 0; 425341f16ccSCameron Grant for (i = 0; i < 32; i++) 426341f16ccSCameron Grant mask |= codec->mix[i].recidx? 1 << i : 0; 427341f16ccSCameron Grant mix_setrecdevs(m, mask); 428987e5972SCameron Grant return 0; 429987e5972SCameron Grant } 430987e5972SCameron Grant 431987e5972SCameron Grant static int 43233dbf14aSCameron Grant ac97mix_uninit(snd_mixer *m) 43333dbf14aSCameron Grant { 43433dbf14aSCameron Grant struct ac97_info *codec = mix_getdevinfo(m); 435341f16ccSCameron Grant 43633dbf14aSCameron Grant if (codec == NULL) 43733dbf14aSCameron Grant return -1; 43833dbf14aSCameron Grant /* 43933dbf14aSCameron Grant if (ac97_uninitmixer(codec)) 44033dbf14aSCameron Grant return -1; 44133dbf14aSCameron Grant */ 44233dbf14aSCameron Grant ac97_destroy(codec); 44333dbf14aSCameron Grant return 0; 44433dbf14aSCameron Grant } 44533dbf14aSCameron Grant 44633dbf14aSCameron Grant static int 447987e5972SCameron Grant ac97mix_set(snd_mixer *m, unsigned dev, unsigned left, unsigned right) 448987e5972SCameron Grant { 449987e5972SCameron Grant struct ac97_info *codec = mix_getdevinfo(m); 450341f16ccSCameron Grant 45139004e69SCameron Grant if (codec == NULL) 45239004e69SCameron Grant return -1; 453987e5972SCameron Grant return ac97_setmixer(codec, dev, left, right); 454987e5972SCameron Grant } 455987e5972SCameron Grant 456987e5972SCameron Grant static int 457987e5972SCameron Grant ac97mix_setrecsrc(snd_mixer *m, u_int32_t src) 458987e5972SCameron Grant { 459987e5972SCameron Grant int i; 460987e5972SCameron Grant struct ac97_info *codec = mix_getdevinfo(m); 461341f16ccSCameron Grant 46239004e69SCameron Grant if (codec == NULL) 46339004e69SCameron Grant return -1; 464987e5972SCameron Grant for (i = 0; i < SOUND_MIXER_NRDEVICES; i++) 46539004e69SCameron Grant if ((src & (1 << i)) != 0) 46639004e69SCameron Grant break; 467987e5972SCameron Grant return (ac97_setrecsrc(codec, i) == 0)? 1 << i : -1; 468987e5972SCameron Grant } 469987e5972SCameron Grant 470987e5972SCameron Grant snd_mixer ac97_mixer = { 471987e5972SCameron Grant "AC97 mixer", 472987e5972SCameron Grant ac97mix_init, 47333dbf14aSCameron Grant ac97mix_uninit, 474987e5972SCameron Grant ac97mix_set, 475987e5972SCameron Grant ac97mix_setrecsrc, 476987e5972SCameron Grant }; 477987e5972SCameron Grant 478