1 /* 2 * Copyright (c) 1999 Cameron Grant <gandalf@vilnya.demon.co.uk> 3 * All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 8 * 1. Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer. 10 * 2. Redistributions in binary form must reproduce the above copyright 11 * notice, this list of conditions and the following disclaimer in the 12 * documentation and/or other materials provided with the distribution. 13 * 14 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 15 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 18 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 22 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 23 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 24 * SUCH DAMAGE. 25 * 26 * $FreeBSD$ 27 */ 28 29 #include <dev/sound/pcm/sound.h> 30 #include <dev/sound/pcm/ac97.h> 31 32 #define AC97_MUTE 0x8000 33 34 #define AC97_REG_RESET 0x00 35 #define AC97_MIX_MASTER 0x02 36 #define AC97_MIX_PHONES 0x04 37 #define AC97_MIX_MONO 0x06 38 #define AC97_MIX_TONE 0x08 39 #define AC97_MIX_BEEP 0x0a 40 #define AC97_MIX_PHONE 0x0c 41 #define AC97_MIX_MIC 0x0e 42 #define AC97_MIX_LINE 0x10 43 #define AC97_MIX_CD 0x12 44 #define AC97_MIX_VIDEO 0x14 45 #define AC97_MIX_AUX 0x16 46 #define AC97_MIX_PCM 0x18 47 #define AC97_REG_RECSEL 0x1a 48 #define AC97_MIX_RGAIN 0x1c 49 #define AC97_MIX_MGAIN 0x1e 50 #define AC97_REG_GEN 0x20 51 #define AC97_REG_3D 0x22 52 #define AC97_REG_POWER 0x26 53 #define AC97_REG_ID1 0x7c 54 #define AC97_REG_ID2 0x7e 55 56 struct ac97mixtable_entry { 57 int reg:8; 58 unsigned bits:4; 59 unsigned ofs:4; 60 unsigned stereo:1; 61 unsigned mute:1; 62 unsigned recidx:4; 63 unsigned mask:1; 64 }; 65 66 struct ac97_info { 67 ac97_read *read; 68 ac97_write *write; 69 void *devinfo; 70 char id[4]; 71 char rev; 72 unsigned caps, se; 73 struct ac97mixtable_entry mix[32]; 74 }; 75 76 struct ac97_codecid { 77 u_int32_t id; 78 char *name; 79 }; 80 81 static const struct ac97mixtable_entry ac97mixtable_default[32] = { 82 [SOUND_MIXER_VOLUME] = { AC97_MIX_MASTER, 5, 0, 1, 1, 6, 0 }, 83 [SOUND_MIXER_BASS] = { AC97_MIX_TONE, 4, 8, 0, 0, 0, 1 }, 84 [SOUND_MIXER_TREBLE] = { AC97_MIX_TONE, 4, 0, 0, 0, 0, 1 }, 85 [SOUND_MIXER_PCM] = { AC97_MIX_PCM, 5, 0, 1, 1, 0, 0 }, 86 [SOUND_MIXER_SPEAKER] = { AC97_MIX_BEEP, 4, 1, 0, 1, 0, 0 }, 87 [SOUND_MIXER_LINE] = { AC97_MIX_LINE, 5, 0, 1, 1, 5, 0 }, 88 [SOUND_MIXER_MIC] = { AC97_MIX_MIC, 5, 0, 0, 1, 1, 0 }, 89 [SOUND_MIXER_CD] = { AC97_MIX_CD, 5, 0, 1, 1, 2, 0 }, 90 [SOUND_MIXER_LINE1] = { AC97_MIX_AUX, 5, 0, 1, 1, 4, 0 }, 91 [SOUND_MIXER_VIDEO] = { AC97_MIX_VIDEO, 5, 0, 1, 1, 3, 0 }, 92 [SOUND_MIXER_RECLEV] = { -AC97_MIX_RGAIN, 4, 0, 1, 1, 0, 0 } 93 }; 94 95 static const unsigned ac97mixdevs = 96 SOUND_MASK_VOLUME | 97 SOUND_MASK_PCM | SOUND_MASK_SPEAKER | SOUND_MASK_LINE | 98 SOUND_MASK_MIC | SOUND_MASK_CD | SOUND_MASK_LINE1 | 99 SOUND_MASK_VIDEO | SOUND_MASK_RECLEV; 100 101 static const unsigned ac97recdevs = 102 SOUND_MASK_VOLUME | SOUND_MASK_LINE | SOUND_MASK_MIC | 103 SOUND_MASK_CD | SOUND_MASK_LINE1 | SOUND_MASK_VIDEO; 104 105 static struct ac97_codecid ac97codecid[] = { 106 { 0x414B4D00, "Asahi Kasei AK4540" }, 107 { 0x43525900, "Cirrus Logic CS4297" }, 108 { 0x83847600, "SigmaTel STAC????" }, 109 { 0x83847604, "SigmaTel STAC9701/3/4/5" }, 110 { 0x83847605, "SigmaTel STAC9704" }, 111 { 0x83847608, "SigmaTel STAC9708" }, 112 { 0x83847609, "SigmaTel STAC9721" }, 113 { 0, NULL } 114 }; 115 116 static char *ac97enhancement[] = { 117 "", 118 "Analog Devices Phat Stereo", 119 "Creative Stereo Enhancement", 120 "National Semi 3D Stereo Enhancement", 121 "Yamaha Ymersion", 122 "BBE 3D Stereo Enhancement", 123 "Crystal Semi 3D Stereo Enhancement", 124 "Qsound QXpander", 125 "Spatializer 3D Stereo Enhancement", 126 "SRS 3D Stereo Enhancement", 127 "Platform Tech 3D Stereo Enhancement", 128 "AKM 3D Audio", 129 "Aureal Stereo Enhancement", 130 "Aztech 3D Enhancement", 131 "Binaura 3D Audio Enhancement", 132 "ESS Technology Stereo Enhancement", 133 "Harman International VMAx", 134 "Nvidea 3D Stereo Enhancement", 135 "Philips Incredible Sound", 136 "Texas Instruments 3D Stereo Enhancement", 137 "VLSI Technology 3D Stereo Enhancement", 138 "TriTech 3D Stereo Enhancement", 139 "Realtek 3D Stereo Enhancement", 140 "Samsung 3D Stereo Enhancement", 141 "Wolfson Microelectronics 3D Enhancement", 142 "Delta Integration 3D Enhancement", 143 "SigmaTel 3D Enhancement", 144 "Reserved 27", 145 "Rockwell 3D Stereo Enhancement", 146 "Reserved 29", 147 "Reserved 30", 148 "Reserved 31" 149 }; 150 151 static char *ac97feature[] = { 152 "mic channel", 153 "reserved", 154 "tone", 155 "simulated stereo", 156 "headphone", 157 "bass boost", 158 "18 bit DAC", 159 "20 bit DAC", 160 "18 bit ADC", 161 "20 bit ADC" 162 }; 163 164 static int 165 ac97_setrecsrc(struct ac97_info *codec, int channel) 166 { 167 struct ac97mixtable_entry *e = &codec->mix[channel]; 168 if (e->recidx > 0) { 169 int val = e->recidx - 1; 170 val |= val << 8; 171 codec->write(codec->devinfo, AC97_REG_RECSEL, val); 172 return 0; 173 } else return -1; 174 } 175 176 static int 177 ac97_setmixer(struct ac97_info *codec, unsigned channel, unsigned left, unsigned right) 178 { 179 struct ac97mixtable_entry *e = &codec->mix[channel]; 180 if (e->reg != 0) { 181 int max, val, reg = (e->reg >= 0)? e->reg : -e->reg; 182 183 if (!e->stereo) right = left; 184 if (e->reg > 0) { 185 left = 100 - left; 186 right = 100 - right; 187 } 188 189 max = (1 << e->bits) - 1; 190 left = (left * max) / 100; 191 right = (right * max) / 100; 192 193 val = (left << 8) | right; 194 195 left = (left * 100) / max; 196 right = (right * 100) / max; 197 198 if (e->reg > 0) { 199 left = 100 - left; 200 right = 100 - right; 201 } 202 203 if (!e->stereo) { 204 val &= max; 205 val <<= e->ofs; 206 if (e->mask) { 207 int cur = codec->read(codec->devinfo, e->reg); 208 val |= cur & ~(max << e->ofs); 209 } 210 } 211 if (left == 0 && right == 0 && e->mute == 1) val = AC97_MUTE; 212 codec->write(codec->devinfo, reg, val); 213 return left | (right << 8); 214 } else return -1; 215 } 216 217 #if 0 218 static int 219 ac97_getmixer(struct ac97_info *codec, int channel) 220 { 221 struct ac97mixtable_entry *e = &codec->mix[channel]; 222 if (channel < SOUND_MIXER_NRDEVICES && e->reg != 0) { 223 int max, val, volume; 224 225 max = (1 << e->bits) - 1; 226 val = codec->read(codec->devinfo, e->reg); 227 if (val == AC97_MUTE && e->mute == 1) volume = 0; 228 else { 229 if (e->stereo == 0) val >>= e->ofs; 230 val &= max; 231 volume = (val * 100) / max; 232 if (e->reg > 0) volume = 100 - volume; 233 } 234 return volume; 235 } else return -1; 236 } 237 #endif 238 239 static unsigned 240 ac97_init(struct ac97_info *codec) 241 { 242 unsigned i, j; 243 u_int32_t id; 244 245 for (i = 0; i < 32; i++) codec->mix[i] = ac97mixtable_default[i]; 246 247 codec->write(codec->devinfo, AC97_REG_POWER, 0); 248 codec->write(codec->devinfo, AC97_REG_RESET, 0); 249 DELAY(10000); 250 251 i = codec->read(codec->devinfo, AC97_REG_RESET); 252 codec->caps = i & 0x03ff; 253 codec->se = (i & 0x7c00) >> 10; 254 255 id = (codec->read(codec->devinfo, AC97_REG_ID1) << 16) | 256 codec->read(codec->devinfo, AC97_REG_ID2); 257 codec->rev = id & 0x000000ff; 258 259 codec->write(codec->devinfo, AC97_MIX_MASTER, 0x20); 260 if ((codec->read(codec->devinfo, AC97_MIX_MASTER) & 0x20) == 0x20) 261 codec->mix[SOUND_MIXER_VOLUME].bits++; 262 codec->write(codec->devinfo, AC97_MIX_MASTER, 0x00); 263 264 if (bootverbose) { 265 printf("ac97: codec id 0x%8x", id); 266 for (i = 0; ac97codecid[i].id; i++) { 267 if (ac97codecid[i].id == id) printf(" (%s)", ac97codecid[i].name); 268 } 269 printf("\nac97: codec features "); 270 for (i = j = 0; i < 10; i++) { 271 if (codec->caps & (1 << i)) { 272 printf("%s%s", j? ", " : "", ac97feature[i]); 273 j++; 274 } 275 } 276 printf("%s%d bit master volume", j? ", " : "", codec->mix[SOUND_MIXER_VOLUME].bits); 277 printf("%s%s\n", j? ", " : "", ac97enhancement[codec->se]); 278 } 279 280 if ((codec->read(codec->devinfo, AC97_REG_POWER) & 2) == 0) 281 printf("ac97: dac not ready\n"); 282 return 0; 283 } 284 285 struct ac97_info * 286 ac97_create(void *devinfo, ac97_read *rd, ac97_write *wr) 287 { 288 struct ac97_info *codec; 289 290 codec = (struct ac97_info *)malloc(sizeof *codec, M_DEVBUF, M_NOWAIT); 291 if (codec != NULL) { 292 codec->read = rd; 293 codec->write = wr; 294 codec->devinfo = devinfo; 295 } 296 return codec; 297 } 298 299 static int 300 ac97mix_init(snd_mixer *m) 301 { 302 struct ac97_info *codec = mix_getdevinfo(m); 303 if (codec == NULL) return -1; 304 ac97_init(codec); 305 mix_setdevs(m, ac97mixdevs | ((codec->caps & 4)? SOUND_MASK_BASS | SOUND_MASK_TREBLE : 0)); 306 mix_setrecdevs(m, ac97recdevs); 307 return 0; 308 } 309 310 static int 311 ac97mix_set(snd_mixer *m, unsigned dev, unsigned left, unsigned right) 312 { 313 struct ac97_info *codec = mix_getdevinfo(m); 314 if (codec == NULL) return -1; 315 return ac97_setmixer(codec, dev, left, right); 316 } 317 318 static int 319 ac97mix_setrecsrc(snd_mixer *m, u_int32_t src) 320 { 321 int i; 322 struct ac97_info *codec = mix_getdevinfo(m); 323 if (codec == NULL) return -1; 324 for (i = 0; i < SOUND_MIXER_NRDEVICES; i++) 325 if ((src & (1 << i)) != 0) break; 326 return (ac97_setrecsrc(codec, i) == 0)? 1 << i : -1; 327 } 328 329 snd_mixer ac97_mixer = { 330 "AC97 mixer", 331 ac97mix_init, 332 ac97mix_set, 333 ac97mix_setrecsrc, 334 }; 335 336