1 /* $NetBSD: ac97.c,v 1.61 2004/08/28 07:02:11 kent Exp $ */ 2 /* $OpenBSD: ac97.c,v 1.8 2000/07/19 09:01:35 csapuntz Exp $ */ 3 4 /* 5 * Copyright (c) 1999, 2000 Constantine Sapuntzakis 6 * 7 * Author: Constantine Sapuntzakis <csapuntz@stanford.edu> 8 * 9 * Redistribution and use in source and binary forms, with or without 10 * modification, are permitted provided that the following conditions 11 * are met: 12 * 1. Redistributions of source code must retain the above copyright 13 * notice, this list of conditions and the following disclaimer. 14 * 2. Redistributions in binary form must reproduce the above copyright 15 * notice, this list of conditions and the following disclaimer in the 16 * documentation and/or other materials provided with the distribution. 17 * 3. The name of the author may not be used to endorse or promote 18 * products derived from this software without specific prior written 19 * permission. 20 * THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS 21 * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 22 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 23 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE 24 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 25 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT 26 * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR 27 * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF 28 * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 29 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE 30 * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH 31 * DAMAGE 32 */ 33 34 /* Partially inspired by FreeBSD's sys/dev/pcm/ac97.c. It came with 35 the following copyright */ 36 37 /* 38 * Copyright (c) 1999 Cameron Grant <gandalf@vilnya.demon.co.uk> 39 * All rights reserved. 40 * 41 * Redistribution and use in source and binary forms, with or without 42 * modification, are permitted provided that the following conditions 43 * are met: 44 * 1. Redistributions of source code must retain the above copyright 45 * notice, this list of conditions and the following disclaimer. 46 * 2. Redistributions in binary form must reproduce the above copyright 47 * notice, this list of conditions and the following disclaimer in the 48 * documentation and/or other materials provided with the distribution. 49 * 50 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 51 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 52 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 53 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 54 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 55 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 56 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 57 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 58 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 59 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 60 * SUCH DAMAGE. 61 * 62 * $FreeBSD$ 63 */ 64 65 #include <sys/cdefs.h> 66 __KERNEL_RCSID(0, "$NetBSD: ac97.c,v 1.61 2004/08/28 07:02:11 kent Exp $"); 67 68 #include <sys/param.h> 69 #include <sys/systm.h> 70 #include <sys/kernel.h> 71 #include <sys/malloc.h> 72 #include <sys/device.h> 73 74 #include <sys/audioio.h> 75 #include <dev/audio_if.h> 76 77 #include <dev/ic/ac97reg.h> 78 #include <dev/ic/ac97var.h> 79 80 struct ac97_softc; 81 struct ac97_source_info; 82 static int ac97_mixer_get_port(struct ac97_codec_if *, mixer_ctrl_t *); 83 static int ac97_mixer_set_port(struct ac97_codec_if *, mixer_ctrl_t *); 84 static int ac97_query_devinfo(struct ac97_codec_if *, mixer_devinfo_t *); 85 static int ac97_get_portnum_by_name(struct ac97_codec_if *, const char *, 86 const char *, const char *); 87 static void ac97_restore_shadow(struct ac97_codec_if *); 88 static int ac97_set_rate(struct ac97_codec_if *, int, u_long *); 89 static void ac97_set_clock(struct ac97_codec_if *, unsigned int); 90 static u_int16_t ac97_get_extcaps(struct ac97_codec_if *); 91 static int ac97_add_port(struct ac97_softc *, 92 const struct ac97_source_info *); 93 static int ac97_str_equal(const char *, const char *); 94 static int ac97_check_capability(struct ac97_softc *, int); 95 static void ac97_setup_source_info(struct ac97_softc *); 96 static void ac97_read(struct ac97_softc *, u_int8_t, u_int16_t *); 97 static void ac97_setup_defaults(struct ac97_softc *); 98 static int ac97_write(struct ac97_softc *, u_int8_t, u_int16_t); 99 100 static void ac97_ad198x_init(struct ac97_softc *); 101 static void ac97_alc650_init(struct ac97_softc *); 102 static void ac97_vt1616_init(struct ac97_softc *); 103 104 #define Ac97Ntone "tone" 105 #define Ac97Nphone "phone" 106 107 static const struct audio_mixer_enum 108 ac97_on_off = { 2, { { { AudioNoff } , 0 }, 109 { { AudioNon } , 1 } } }; 110 111 static const struct audio_mixer_enum 112 ac97_mic_select = { 2, { { { AudioNmicrophone "0" }, 0 }, 113 { { AudioNmicrophone "1" }, 1 } } }; 114 115 static const struct audio_mixer_enum 116 ac97_mono_select = { 2, { { { AudioNmixerout }, 0 }, 117 { { AudioNmicrophone }, 1 } } }; 118 119 static const struct audio_mixer_enum 120 ac97_source = { 8, { { { AudioNmicrophone } , 0 }, 121 { { AudioNcd }, 1 }, 122 { { AudioNvideo }, 2 }, 123 { { AudioNaux }, 3 }, 124 { { AudioNline }, 4 }, 125 { { AudioNmixerout }, 5 }, 126 { { AudioNmixerout AudioNmono }, 6 }, 127 { { Ac97Nphone }, 7 } } }; 128 129 /* 130 * Due to different values for each source that uses these structures, 131 * the ac97_query_devinfo function sets delta in mixer_devinfo_t using 132 * ac97_source_info.bits. 133 */ 134 static const struct audio_mixer_value 135 ac97_volume_stereo = { { AudioNvolume }, 2 }; 136 137 static const struct audio_mixer_value 138 ac97_volume_mono = { { AudioNvolume }, 1 }; 139 140 #define WRAP(a) &a, sizeof(a) 141 142 static const struct ac97_source_info { 143 const char *class; 144 const char *device; 145 const char *qualifier; 146 147 int type; 148 const void *info; 149 int info_size; 150 151 u_int8_t reg; 152 u_int16_t default_value; 153 u_int8_t bits:3; 154 u_int8_t ofs:4; 155 u_int8_t mute:1; 156 u_int8_t polarity:1; /* Does 0 == MAX or MIN */ 157 enum { 158 CHECK_NONE = 0, 159 CHECK_SURROUND, 160 CHECK_CENTER, 161 CHECK_LFE, 162 CHECK_HEADPHONES, 163 CHECK_TONE, 164 CHECK_MIC, 165 CHECK_LOUDNESS, 166 CHECK_3D 167 } req_feature; 168 169 int prev; 170 int next; 171 int mixer_class; 172 } source_info[] = { 173 { AudioCinputs, NULL, NULL, 174 AUDIO_MIXER_CLASS, }, 175 { AudioCoutputs, NULL, NULL, 176 AUDIO_MIXER_CLASS, }, 177 { AudioCrecord, NULL, NULL, 178 AUDIO_MIXER_CLASS, }, 179 /* Stereo master volume*/ 180 { AudioCoutputs, AudioNmaster, NULL, 181 AUDIO_MIXER_VALUE, WRAP(ac97_volume_stereo), 182 AC97_REG_MASTER_VOLUME, 0x8000, 5, 0, 1, 183 }, 184 /* Mono volume */ 185 { AudioCoutputs, AudioNmono, NULL, 186 AUDIO_MIXER_VALUE, WRAP(ac97_volume_mono), 187 AC97_REG_MASTER_VOLUME_MONO, 0x8000, 6, 0, 1, 188 }, 189 { AudioCoutputs, AudioNmono, AudioNsource, 190 AUDIO_MIXER_ENUM, WRAP(ac97_mono_select), 191 AC97_REG_GP, 0x0000, 1, 9, 0, 192 }, 193 /* Headphone volume */ 194 { AudioCoutputs, AudioNheadphone, NULL, 195 AUDIO_MIXER_VALUE, WRAP(ac97_volume_stereo), 196 AC97_REG_HEADPHONE_VOLUME, 0x8000, 6, 0, 1, 0, CHECK_HEADPHONES 197 }, 198 /* Surround volume - logic hard coded for mute */ 199 { AudioCoutputs, AudioNsurround, NULL, 200 AUDIO_MIXER_VALUE, WRAP(ac97_volume_stereo), 201 AC97_REG_SURR_MASTER, 0x8080, 5, 0, 1, 0, CHECK_SURROUND 202 }, 203 /* Center volume*/ 204 { AudioCoutputs, AudioNcenter, NULL, 205 AUDIO_MIXER_VALUE, WRAP(ac97_volume_mono), 206 AC97_REG_CENTER_LFE_MASTER, 0x8080, 5, 0, 0, 0, CHECK_CENTER 207 }, 208 { AudioCoutputs, AudioNcenter, AudioNmute, 209 AUDIO_MIXER_ENUM, WRAP(ac97_on_off), 210 AC97_REG_CENTER_LFE_MASTER, 0x8080, 1, 7, 0, 0, CHECK_CENTER 211 }, 212 /* LFE volume*/ 213 { AudioCoutputs, AudioNlfe, NULL, 214 AUDIO_MIXER_VALUE, WRAP(ac97_volume_mono), 215 AC97_REG_CENTER_LFE_MASTER, 0x8080, 5, 8, 0, 0, CHECK_LFE 216 }, 217 { AudioCoutputs, AudioNlfe, AudioNmute, 218 AUDIO_MIXER_ENUM, WRAP(ac97_on_off), 219 AC97_REG_CENTER_LFE_MASTER, 0x8080, 1, 15, 0, 0, CHECK_LFE 220 }, 221 /* Tone */ 222 { AudioCoutputs, Ac97Ntone, NULL, 223 AUDIO_MIXER_VALUE, WRAP(ac97_volume_stereo), 224 AC97_REG_MASTER_TONE, 0x0f0f, 4, 0, 0, 0, CHECK_TONE 225 }, 226 /* PC Beep Volume */ 227 { AudioCinputs, AudioNspeaker, NULL, 228 AUDIO_MIXER_VALUE, WRAP(ac97_volume_mono), 229 AC97_REG_PCBEEP_VOLUME, 0x0000, 4, 1, 1, 230 }, 231 232 /* Phone */ 233 { AudioCinputs, Ac97Nphone, NULL, 234 AUDIO_MIXER_VALUE, WRAP(ac97_volume_mono), 235 AC97_REG_PHONE_VOLUME, 0x8008, 5, 0, 1, 236 }, 237 /* Mic Volume */ 238 { AudioCinputs, AudioNmicrophone, NULL, 239 AUDIO_MIXER_VALUE, WRAP(ac97_volume_mono), 240 AC97_REG_MIC_VOLUME, 0x8008, 5, 0, 1, 241 }, 242 { AudioCinputs, AudioNmicrophone, AudioNpreamp, 243 AUDIO_MIXER_ENUM, WRAP(ac97_on_off), 244 AC97_REG_MIC_VOLUME, 0x8008, 1, 6, 0, 245 }, 246 { AudioCinputs, AudioNmicrophone, AudioNsource, 247 AUDIO_MIXER_ENUM, WRAP(ac97_mic_select), 248 AC97_REG_GP, 0x0000, 1, 8, 0, 249 }, 250 /* Line in Volume */ 251 { AudioCinputs, AudioNline, NULL, 252 AUDIO_MIXER_VALUE, WRAP(ac97_volume_stereo), 253 AC97_REG_LINEIN_VOLUME, 0x8808, 5, 0, 1, 254 }, 255 /* CD Volume */ 256 { AudioCinputs, AudioNcd, NULL, 257 AUDIO_MIXER_VALUE, WRAP(ac97_volume_stereo), 258 AC97_REG_CD_VOLUME, 0x8808, 5, 0, 1, 259 }, 260 /* Video Volume */ 261 { AudioCinputs, AudioNvideo, NULL, 262 AUDIO_MIXER_VALUE, WRAP(ac97_volume_stereo), 263 AC97_REG_VIDEO_VOLUME, 0x8808, 5, 0, 1, 264 }, 265 /* AUX volume */ 266 { AudioCinputs, AudioNaux, NULL, 267 AUDIO_MIXER_VALUE, WRAP(ac97_volume_stereo), 268 AC97_REG_AUX_VOLUME, 0x8808, 5, 0, 1, 269 }, 270 /* PCM out volume */ 271 { AudioCinputs, AudioNdac, NULL, 272 AUDIO_MIXER_VALUE, WRAP(ac97_volume_stereo), 273 AC97_REG_PCMOUT_VOLUME, 0x8808, 5, 0, 1, 274 }, 275 /* Record Source - some logic for this is hard coded - see below */ 276 { AudioCrecord, AudioNsource, NULL, 277 AUDIO_MIXER_ENUM, WRAP(ac97_source), 278 AC97_REG_RECORD_SELECT, 0x0000, 3, 0, 0, 279 }, 280 /* Record Gain */ 281 { AudioCrecord, AudioNvolume, NULL, 282 AUDIO_MIXER_VALUE, WRAP(ac97_volume_stereo), 283 AC97_REG_RECORD_GAIN, 0x8000, 4, 0, 1, 1, 284 }, 285 /* Record Gain mic */ 286 { AudioCrecord, AudioNmicrophone, NULL, 287 AUDIO_MIXER_VALUE, WRAP(ac97_volume_mono), 288 AC97_REG_RECORD_GAIN_MIC, 0x8000, 4, 0, 1, 1, CHECK_MIC 289 }, 290 /* */ 291 { AudioCoutputs, AudioNloudness, NULL, 292 AUDIO_MIXER_ENUM, WRAP(ac97_on_off), 293 AC97_REG_GP, 0x0000, 1, 12, 0, 0, CHECK_LOUDNESS 294 }, 295 { AudioCoutputs, AudioNspatial, NULL, 296 AUDIO_MIXER_ENUM, WRAP(ac97_on_off), 297 AC97_REG_GP, 0x0000, 1, 13, 0, 1, CHECK_3D 298 }, 299 { AudioCoutputs, AudioNspatial, "center", 300 AUDIO_MIXER_VALUE, WRAP(ac97_volume_mono), 301 AC97_REG_3D_CONTROL, 0x0000, 4, 8, 0, 1, CHECK_3D 302 }, 303 { AudioCoutputs, AudioNspatial, "depth", 304 AUDIO_MIXER_VALUE, WRAP(ac97_volume_mono), 305 AC97_REG_3D_CONTROL, 0x0000, 4, 0, 0, 1, CHECK_3D 306 }, 307 308 /* Missing features: Simulated Stereo, POP, Loopback mode */ 309 }; 310 311 #define SOURCE_INFO_SIZE (sizeof(source_info)/sizeof(source_info[0])) 312 313 /* 314 * Check out http://developer.intel.com/pc-supp/platform/ac97/ for 315 * information on AC-97 316 */ 317 318 struct ac97_softc { 319 /* ac97_codec_if must be at the first of ac97_softc. */ 320 struct ac97_codec_if codec_if; 321 322 struct ac97_host_if *host_if; 323 324 #define MAX_SOURCES (2 * SOURCE_INFO_SIZE) 325 struct ac97_source_info source_info[MAX_SOURCES]; 326 int num_source_info; 327 328 enum ac97_host_flags host_flags; 329 unsigned int ac97_clock; /* usually 48000 */ 330 #define AC97_STANDARD_CLOCK 48000U 331 u_int16_t caps; /* -> AC97_REG_RESET */ 332 u_int16_t ext_id; /* -> AC97_REG_EXT_AUDIO_ID */ 333 u_int16_t shadow_reg[128]; 334 }; 335 336 static struct ac97_codec_if_vtbl ac97civ = { 337 ac97_mixer_get_port, 338 ac97_mixer_set_port, 339 ac97_query_devinfo, 340 ac97_get_portnum_by_name, 341 ac97_restore_shadow, 342 ac97_get_extcaps, 343 ac97_set_rate, 344 ac97_set_clock, 345 }; 346 347 static const struct ac97_codecid { 348 u_int32_t id; 349 u_int32_t mask; 350 const char *name; 351 void (*init)(struct ac97_softc *); 352 } ac97codecid[] = { 353 /* 354 * Analog Devices SoundMAX 355 * http://www.soundmax.com/products/information/codecs.html 356 * http://www.analog.com/productSelection/pdf/AD1881A_0.pdf 357 * http://www.analog.com/productSelection/pdf/AD1885_0.pdf 358 * http://www.analog.com/UploadedFiles/Data_Sheets/206585810AD1980_0.pdf 359 * http://www.analog.com/productSelection/pdf/AD1981A_0.pdf 360 * http://www.analog.com/productSelection/pdf/AD1981B_0.pdf 361 * http://www.analog.com/UploadedFiles/Data_Sheets/180644528AD1985_0.pdf 362 */ 363 { AC97_CODEC_ID('A', 'D', 'S', 3), 364 0xffffffff, "Analog Devices AD1819B" }, 365 { AC97_CODEC_ID('A', 'D', 'S', 0x40), 366 0xffffffff, "Analog Devices AD1881" }, 367 { AC97_CODEC_ID('A', 'D', 'S', 0x48), 368 0xffffffff, "Analog Devices AD1881A" }, 369 { AC97_CODEC_ID('A', 'D', 'S', 0x60), 370 0xffffffff, "Analog Devices AD1885" }, 371 { AC97_CODEC_ID('A', 'D', 'S', 0x61), 372 0xffffffff, "Analog Devices AD1886" }, 373 { AC97_CODEC_ID('A', 'D', 'S', 0x63), 374 0xffffffff, "Analog Devices AD1886A" }, 375 { AC97_CODEC_ID('A', 'D', 'S', 0x68), 376 0xffffffff, "Analog Devices AD1888", ac97_ad198x_init }, 377 { AC97_CODEC_ID('A', 'D', 'S', 0x70), 378 0xffffffff, "Analog Devices AD1980", ac97_ad198x_init }, 379 { AC97_CODEC_ID('A', 'D', 'S', 0x72), 380 0xffffffff, "Analog Devices AD1981A" }, 381 { AC97_CODEC_ID('A', 'D', 'S', 0x74), 382 0xffffffff, "Analog Devices AD1981B" }, 383 { AC97_CODEC_ID('A', 'D', 'S', 0x75), 384 0xffffffff, "Analog Devices AD1985", ac97_ad198x_init }, 385 { AC97_CODEC_ID('A', 'D', 'S', 0), 386 AC97_VENDOR_ID_MASK, "Analog Devices unknown" }, 387 388 /* 389 * Datasheets: 390 * http://www.asahi-kasei.co.jp/akm/usa/product/ak4541/ek4541.pdf 391 * http://www.asahi-kasei.co.jp/akm/usa/product/ak4543/ek4543.pdf 392 * http://www.asahi-kasei.co.jp/akm/usa/product/ak4544a/ek4544a.pdf 393 * http://www.asahi-kasei.co.jp/akm/usa/product/ak4545/ek4545.pdf 394 */ 395 { AC97_CODEC_ID('A', 'K', 'M', 0), 396 0xffffffff, "Asahi Kasei AK4540" }, 397 { AC97_CODEC_ID('A', 'K', 'M', 1), 398 0xffffffff, "Asahi Kasei AK4542" }, 399 { AC97_CODEC_ID('A', 'K', 'M', 2), 400 0xffffffff, "Asahi Kasei AK4541/AK4543" }, 401 { AC97_CODEC_ID('A', 'K', 'M', 5), 402 0xffffffff, "Asahi Kasei AK4544" }, 403 { AC97_CODEC_ID('A', 'K', 'M', 6), 404 0xffffffff, "Asahi Kasei AK4544A" }, 405 { AC97_CODEC_ID('A', 'K', 'M', 7), 406 0xffffffff, "Asahi Kasei AK4545" }, 407 { AC97_CODEC_ID('A', 'K', 'M', 0), 408 AC97_VENDOR_ID_MASK, "Asahi Kasei unknown" }, 409 410 /* 411 * Realtek & Avance Logic 412 * http://www.realtek.com.tw/downloads/downloads1-3.aspx?lineid=5&famid=All&series=All&Spec=True 413 * 414 * ALC650 and ALC658 support VRA, but it supports only 8000, 11025, 415 * 12000, 16000, 22050, 24000, 32000, 44100, and 48000 Hz. 416 */ 417 { AC97_CODEC_ID('A', 'L', 'C', 0x00), 418 0xfffffff0, "Realtek RL5306" }, 419 { AC97_CODEC_ID('A', 'L', 'C', 0x10), 420 0xfffffff0, "Realtek RL5382" }, 421 { AC97_CODEC_ID('A', 'L', 'C', 0x20), 422 0xfffffff0, "Realtek RL5383/RL5522/ALC100" }, 423 { AC97_CODEC_ID('A', 'L', 'G', 0x10), 424 0xffffffff, "Avance Logic ALC200/ALC201" }, 425 { AC97_CODEC_ID('A', 'L', 'G', 0x20), 426 0xfffffff0, "Avance Logic ALC650", ac97_alc650_init }, 427 { AC97_CODEC_ID('A', 'L', 'G', 0x30), 428 0xffffffff, "Avance Logic ALC101" }, 429 { AC97_CODEC_ID('A', 'L', 'G', 0x40), 430 0xffffffff, "Avance Logic ALC202" }, 431 { AC97_CODEC_ID('A', 'L', 'G', 0x50), 432 0xffffffff, "Avance Logic ALC250" }, 433 { AC97_CODEC_ID('A', 'L', 'G', 0x60), 434 0xfffffff0, "Avance Logic ALC655" }, 435 { AC97_CODEC_ID('A', 'L', 'G', 0x80), 436 0xfffffff0, "Avance Logic ALC658" }, 437 { AC97_CODEC_ID('A', 'L', 'G', 0x90), 438 0xfffffff0, "Avance Logic ALC850" }, 439 { AC97_CODEC_ID('A', 'L', 'C', 0), 440 AC97_VENDOR_ID_MASK, "Realtek unknown" }, 441 { AC97_CODEC_ID('A', 'L', 'G', 0), 442 AC97_VENDOR_ID_MASK, "Avance Logic unknown" }, 443 444 /** 445 * C-Media Electronics Inc. 446 * http://www.cmedia.com.tw/doc/CMI9739%206CH%20Audio%20Codec%20SPEC_Ver12.pdf 447 */ 448 { AC97_CODEC_ID('C', 'M', 'I', 0x61), 449 0xffffffff, "C-Media CMI9739" }, 450 { AC97_CODEC_ID('C', 'M', 'I', 0), 451 AC97_VENDOR_ID_MASK, "C-Media unknown" }, 452 453 /* Cirrus Logic, Crystal series: 454 * 'C' 'R' 'Y' 0x0[0-7] - CS4297 455 * 0x1[0-7] - CS4297A 456 * 0x2[0-7] - CS4298 457 * 0x2[8-f] - CS4294 458 * 0x3[0-7] - CS4299 459 * 0x4[8-f] - CS4201 460 * 0x5[8-f] - CS4205 461 * 0x6[0-7] - CS4291 462 * 0x7[0-7] - CS4202 463 * Datasheets: 464 * http://www.cirrus.com/pubs/cs4297A-5.pdf?DocumentID=593 465 * http://www.cirrus.com/pubs/cs4294.pdf?DocumentID=32 466 * http://www.cirrus.com/pubs/cs4299-5.pdf?DocumentID=594 467 * http://www.cirrus.com/pubs/cs4201-2.pdf?DocumentID=492 468 * http://www.cirrus.com/pubs/cs4205-2.pdf?DocumentID=492 469 * http://www.cirrus.com/pubs/cs4202-1.pdf?DocumentID=852 470 */ 471 { AC97_CODEC_ID('C', 'R', 'Y', 0x00), 472 0xfffffff8, "Crystal CS4297", }, 473 { AC97_CODEC_ID('C', 'R', 'Y', 0x10), 474 0xfffffff8, "Crystal CS4297A", }, 475 { AC97_CODEC_ID('C', 'R', 'Y', 0x20), 476 0xfffffff8, "Crystal CS4298", }, 477 { AC97_CODEC_ID('C', 'R', 'Y', 0x28), 478 0xfffffff8, "Crystal CS4294", }, 479 { AC97_CODEC_ID('C', 'R', 'Y', 0x30), 480 0xfffffff8, "Crystal CS4299", }, 481 { AC97_CODEC_ID('C', 'R', 'Y', 0x48), 482 0xfffffff8, "Crystal CS4201", }, 483 { AC97_CODEC_ID('C', 'R', 'Y', 0x58), 484 0xfffffff8, "Crystal CS4205", }, 485 { AC97_CODEC_ID('C', 'R', 'Y', 0x60), 486 0xfffffff8, "Crystal CS4291", }, 487 { AC97_CODEC_ID('C', 'R', 'Y', 0x70), 488 0xfffffff8, "Crystal CS4202", }, 489 { AC97_CODEC_ID('C', 'R', 'Y', 0), 490 AC97_VENDOR_ID_MASK, "Cirrus Logic unknown", }, 491 492 { 0x45838308, 0xffffffff, "ESS Technology ES1921", }, 493 { 0x45838300, AC97_VENDOR_ID_MASK, "ESS Technology unknown", }, 494 495 { AC97_CODEC_ID('H', 'R', 'S', 0), 496 0xffffffff, "Intersil HMP9701", }, 497 { AC97_CODEC_ID('H', 'R', 'S', 0), 498 AC97_VENDOR_ID_MASK, "Intersil unknown", }, 499 500 /* 501 * IC Ensemble (VIA) 502 * http://www.viatech.com/en/datasheet/DS1616.pdf 503 */ 504 { AC97_CODEC_ID('I', 'C', 'E', 0x01), 505 0xffffffff, "ICEnsemble ICE1230/VT1611", }, 506 { AC97_CODEC_ID('I', 'C', 'E', 0x11), 507 0xffffffff, "ICEnsemble ICE1232/VT1611A", }, 508 { AC97_CODEC_ID('I', 'C', 'E', 0x14), 509 0xffffffff, "ICEnsemble ICE1232A", }, 510 { AC97_CODEC_ID('I', 'C', 'E', 0x51), 511 0xffffffff, "VIA Technologies VT1616", ac97_vt1616_init }, 512 { AC97_CODEC_ID('I', 'C', 'E', 0x52), 513 0xffffffff, "VIA Technologies VT1616i", ac97_vt1616_init }, 514 { AC97_CODEC_ID('I', 'C', 'E', 0), 515 AC97_VENDOR_ID_MASK, "ICEnsemble/VIA unknown", }, 516 517 { AC97_CODEC_ID('N', 'S', 'C', 0), 518 0xffffffff, "National Semiconductor LM454[03568]", }, 519 { AC97_CODEC_ID('N', 'S', 'C', 49), 520 0xffffffff, "National Semiconductor LM4549", }, 521 { AC97_CODEC_ID('N', 'S', 'C', 0), 522 AC97_VENDOR_ID_MASK, "National Semiconductor unknown", }, 523 524 { AC97_CODEC_ID('P', 'S', 'C', 4), 525 0xffffffff, "Philips Semiconductor UCB1400", }, 526 { AC97_CODEC_ID('P', 'S', 'C', 0), 527 AC97_VENDOR_ID_MASK, "Philips Semiconductor unknown", }, 528 529 { AC97_CODEC_ID('S', 'I', 'L', 34), 530 0xffffffff, "Silicon Laboratory Si3036", }, 531 { AC97_CODEC_ID('S', 'I', 'L', 35), 532 0xffffffff, "Silicon Laboratory Si3038", }, 533 { AC97_CODEC_ID('S', 'I', 'L', 0), 534 AC97_VENDOR_ID_MASK, "Silicon Laboratory unknown", }, 535 536 { AC97_CODEC_ID('T', 'R', 'A', 2), 537 0xffffffff, "TriTech TR28022", }, 538 { AC97_CODEC_ID('T', 'R', 'A', 3), 539 0xffffffff, "TriTech TR28023", }, 540 { AC97_CODEC_ID('T', 'R', 'A', 6), 541 0xffffffff, "TriTech TR28026", }, 542 { AC97_CODEC_ID('T', 'R', 'A', 8), 543 0xffffffff, "TriTech TR28028", }, 544 { AC97_CODEC_ID('T', 'R', 'A', 35), 545 0xffffffff, "TriTech TR28602", }, 546 { AC97_CODEC_ID('T', 'R', 'A', 0), 547 AC97_VENDOR_ID_MASK, "TriTech unknown", }, 548 549 { AC97_CODEC_ID('T', 'X', 'N', 0x20), 550 0xffffffff, "Texas Instruments TLC320AD9xC", }, 551 { AC97_CODEC_ID('T', 'X', 'N', 0), 552 AC97_VENDOR_ID_MASK, "Texas Instruments unknown", }, 553 554 /* 555 * VIA 556 * http://www.viatech.com/en/multimedia/audio.jsp 557 */ 558 { AC97_CODEC_ID('V', 'I', 'A', 0x61), 559 0xffffffff, "VIA Technologies VT1612A", }, 560 { AC97_CODEC_ID('V', 'I', 'A', 0), 561 AC97_VENDOR_ID_MASK, "VIA Technologies unknown", }, 562 563 { AC97_CODEC_ID('W', 'E', 'C', 1), 564 0xffffffff, "Winbond W83971D", }, 565 { AC97_CODEC_ID('W', 'E', 'C', 0), 566 AC97_VENDOR_ID_MASK, "Winbond unknown", }, 567 568 /* 569 * http://www.wolfsonmicro.com/product_list.asp?cid=64 570 * http://www.wolfsonmicro.com/download.asp/did.56/WM9701A.pdf - 00 571 * http://www.wolfsonmicro.com/download.asp/did.57/WM9703.pdf - 03 572 * http://www.wolfsonmicro.com/download.asp/did.58/WM9704M.pdf - 04 573 * http://www.wolfsonmicro.com/download.asp/did.59/WM9704Q.pdf - 04 574 * http://www.wolfsonmicro.com/download.asp/did.184/WM9705_Rev34.pdf - 05 575 * http://www.wolfsonmicro.com/download.asp/did.60/WM9707.pdf - 03 576 * http://www.wolfsonmicro.com/download.asp/did.136/WM9708.pdf - 03 577 * http://www.wolfsonmicro.com/download.asp/did.243/WM9710.pdf - 05 578 */ 579 { AC97_CODEC_ID('W', 'M', 'L', 0), 580 0xffffffff, "Wolfson WM9701A", }, 581 { AC97_CODEC_ID('W', 'M', 'L', 3), 582 0xffffffff, "Wolfson WM9703/WM9707/WM9708", }, 583 { AC97_CODEC_ID('W', 'M', 'L', 4), 584 0xffffffff, "Wolfson WM9704", }, 585 { AC97_CODEC_ID('W', 'M', 'L', 5), 586 0xffffffff, "Wolfson WM9705/WM9710", }, 587 { AC97_CODEC_ID('W', 'M', 'L', 0), 588 AC97_VENDOR_ID_MASK, "Wolfson unknown", }, 589 590 /* 591 * http://www.yamaha.co.jp/english/product/lsi/us/products/pcaudio.html 592 * Datasheets: 593 * http://www.yamaha.co.jp/english/product/lsi/us/products/pdf/4MF743A20.pdf 594 * http://www.yamaha.co.jp/english/product/lsi/us/products/pdf/4MF753A20.pdf 595 */ 596 { AC97_CODEC_ID('Y', 'M', 'H', 0), 597 0xffffffff, "Yamaha YMF743-S", }, 598 { AC97_CODEC_ID('Y', 'M', 'H', 3), 599 0xffffffff, "Yamaha YMF753-S", }, 600 { AC97_CODEC_ID('Y', 'M', 'H', 0), 601 AC97_VENDOR_ID_MASK, "Yamaha unknown", }, 602 603 /* 604 * http://www.sigmatel.com/products/technical_docs.htm 605 * and 606 * http://www.sigmatel.com/documents/c-major-brochure-9-0.pdf 607 */ 608 { 0x83847600, 0xffffffff, "SigmaTel STAC9700", }, 609 { 0x83847604, 0xffffffff, "SigmaTel STAC9701/3/4/5", }, 610 { 0x83847605, 0xffffffff, "SigmaTel STAC9704", }, 611 { 0x83847608, 0xffffffff, "SigmaTel STAC9708", }, 612 { 0x83847609, 0xffffffff, "SigmaTel STAC9721/23", }, 613 { 0x83847644, 0xffffffff, "SigmaTel STAC9744/45", }, 614 { 0x83847650, 0xffffffff, "SigmaTel STAC9750/51", }, 615 { 0x83847656, 0xffffffff, "SigmaTel STAC9756/57", }, 616 { 0x83847658, 0xffffffff, "SigmaTel STAC9758/59", }, 617 { 0x83847666, 0xffffffff, "SigmaTel STAC9766/67", }, 618 { 0x83847684, 0xffffffff, "SigmaTel STAC9783/84", }, 619 { 0x83847600, AC97_VENDOR_ID_MASK, "SigmaTel unknown", }, 620 621 { 0, 622 0, NULL, } 623 }; 624 625 static const char * const ac97enhancement[] = { 626 "no 3D stereo", 627 "Analog Devices Phat Stereo", 628 "Creative", 629 "National Semi 3D", 630 "Yamaha Ymersion", 631 "BBE 3D", 632 "Crystal Semi 3D", 633 "Qsound QXpander", 634 "Spatializer 3D", 635 "SRS 3D", 636 "Platform Tech 3D", 637 "AKM 3D", 638 "Aureal", 639 "AZTECH 3D", 640 "Binaura 3D", 641 "ESS Technology", 642 "Harman International VMAx", 643 "Nvidea 3D", 644 "Philips Incredible Sound", 645 "Texas Instruments' 3D", 646 "VLSI Technology 3D", 647 "TriTech 3D", 648 "Realtek 3D", 649 "Samsung 3D", 650 "Wolfson Microelectronics 3D", 651 "Delta Integration 3D", 652 "SigmaTel 3D", 653 "KS Waves 3D", 654 "Rockwell 3D", 655 "Unknown 3D", 656 "Unknown 3D", 657 "Unknown 3D", 658 }; 659 660 static const char * const ac97feature[] = { 661 "dedicated mic channel", 662 "reserved", 663 "tone", 664 "simulated stereo", 665 "headphone", 666 "bass boost", 667 "18 bit DAC", 668 "20 bit DAC", 669 "18 bit ADC", 670 "20 bit ADC" 671 }; 672 673 674 /* #define AC97_DEBUG 10 */ 675 /* #define AC97_IO_DEBUG */ 676 677 #ifdef AUDIO_DEBUG 678 #define DPRINTF(x) if (ac97debug) printf x 679 #define DPRINTFN(n,x) if (ac97debug>(n)) printf x 680 #ifdef AC97_DEBUG 681 int ac97debug = AC97_DEBUG; 682 #else 683 int ac97debug = 0; 684 #endif 685 #else 686 #define DPRINTF(x) 687 #define DPRINTFN(n,x) 688 #endif 689 690 #ifdef AC97_IO_DEBUG 691 static const char *ac97_register_names[0x80 / 2] = { 692 "RESET", "MASTER_VOLUME", "HEADPHONE_VOLUME", "MASTER_VOLUME_MONO", 693 "MASTER_TONE", "PCBEEP_VOLUME", "PHONE_VOLUME", "MIC_VOLUME", 694 "LINEIN_VOLUME", "CD_VOLUME", "VIDEO_VOLUME", "AUX_VOLUME", 695 "PCMOUT_VOLUME", "RECORD_SELECT", "RECORD_GATIN", "RECORD_GAIN_MIC", 696 "GP", "3D_CONTROL", "AUDIO_INT", "POWER", 697 "EXT_AUDIO_ID", "EXT_AUDIO_CTRL", "PCM_FRONT_DAC_RATE", "PCM_SURR_DAC_RATE", 698 "PCM_LFE_DAC_RATE", "PCM_LR_ADC_RATE", "PCM_MIC_ADC_RATE", "CENTER_LFE_MASTER", 699 "SURR_MASTER", "SPDIF_CTRL", "EXT_MODEM_ID", "EXT_MODEM_CTRL", 700 "LINE1_RATE", "LINE2_RATE", "HANDSET_RATE", "LINE1_LEVEL", 701 "LINE2_LEVEL", "HANDSET_LEVEL", "GPIO_PIN_CONFIG", "GPIO_PIN_POLARITY", 702 "GPIO_PIN_STICKY", "GPIO_PIN_WAKEUP", "GPIO_PIN_STATUS", "MISC_MODEM_CTRL", 703 "0x58", "VENDOR-5A", "VENDOR-5C", "VENDOR-5E", 704 "0x60", "0x62", "0x64", "0x66", 705 "0x68", "0x6a", "0x6c", "0x6e", 706 "VENDOR-70", "VENDOR-72", "VENDOR-74", "VENDOR-76", 707 "VENDOR-78", "VENDOR-7A", "VENDOR_ID1", "VENDOR_ID2" 708 }; 709 #endif 710 711 static void 712 ac97_read(struct ac97_softc *as, u_int8_t reg, u_int16_t *val) 713 { 714 if (as->host_flags & AC97_HOST_DONT_READ && 715 (reg != AC97_REG_VENDOR_ID1 && reg != AC97_REG_VENDOR_ID2 && 716 reg != AC97_REG_RESET)) { 717 *val = as->shadow_reg[reg >> 1]; 718 return; 719 } 720 721 if (as->host_if->read(as->host_if->arg, reg, val)) { 722 *val = as->shadow_reg[reg >> 1]; 723 } 724 } 725 726 static int 727 ac97_write(struct ac97_softc *as, u_int8_t reg, u_int16_t val) 728 { 729 #ifndef AC97_IO_DEBUG 730 as->shadow_reg[reg >> 1] = val; 731 return as->host_if->write(as->host_if->arg, reg, val); 732 #else 733 int ret; 734 uint16_t actual; 735 736 as->shadow_reg[reg >> 1] = val; 737 ret = as->host_if->write(as->host_if->arg, reg, val); 738 as->host_if->read(as->host_if->arg, reg, &actual); 739 if (val != actual && reg < 0x80) { 740 printf("ac97_write: reg=%s, written=0x%04x, read=0x%04x\n", 741 ac97_register_names[reg / 2], val, actual); 742 } 743 return ret; 744 #endif 745 } 746 747 static void 748 ac97_setup_defaults(struct ac97_softc *as) 749 { 750 int idx; 751 const struct ac97_source_info *si; 752 753 memset(as->shadow_reg, 0, sizeof(as->shadow_reg)); 754 755 for (idx = 0; idx < SOURCE_INFO_SIZE; idx++) { 756 si = &source_info[idx]; 757 ac97_write(as, si->reg, si->default_value); 758 } 759 } 760 761 static void 762 ac97_restore_shadow(struct ac97_codec_if *self) 763 { 764 struct ac97_softc *as; 765 const struct ac97_source_info *si; 766 int idx; 767 uint16_t val; 768 769 as = (struct ac97_softc *) self; 770 771 /* make sure chip is fully operational */ 772 #define AC97_POWER_ALL (AC97_POWER_REF | AC97_POWER_ANL | AC97_POWER_DAC \ 773 | AC97_POWER_ADC) 774 for (idx = 500000; idx >= 0; idx--) { 775 ac97_read(as, AC97_REG_POWER, &val); 776 if ((val & AC97_POWER_ALL) == AC97_POWER_ALL) 777 break; 778 DELAY(1); 779 } 780 #undef AC97_POWER_ALL 781 782 for (idx = 0; idx < SOURCE_INFO_SIZE; idx++) { 783 si = &source_info[idx]; 784 /* don't "restore" to the reset reg! */ 785 if (si->reg != AC97_REG_RESET) 786 ac97_write(as, si->reg, as->shadow_reg[si->reg >> 1]); 787 } 788 789 if (as->ext_id & (AC97_EXT_AUDIO_VRA | AC97_EXT_AUDIO_DRA 790 | AC97_EXT_AUDIO_SPDIF | AC97_EXT_AUDIO_VRM 791 | AC97_EXT_AUDIO_CDAC | AC97_EXT_AUDIO_SDAC 792 | AC97_EXT_AUDIO_LDAC)) { 793 ac97_write(as, AC97_REG_EXT_AUDIO_CTRL, 794 as->shadow_reg[AC97_REG_EXT_AUDIO_CTRL >> 1]); 795 } 796 } 797 798 static int 799 ac97_str_equal(const char *a, const char *b) 800 { 801 return (a == b) || (a && b && (!strcmp(a, b))); 802 } 803 804 static int 805 ac97_check_capability(struct ac97_softc *as, int check) 806 { 807 switch (check) { 808 case CHECK_NONE: 809 return 1; 810 case CHECK_SURROUND: 811 return as->ext_id & AC97_EXT_AUDIO_SDAC; 812 case CHECK_CENTER: 813 return as->ext_id & AC97_EXT_AUDIO_CDAC; 814 case CHECK_LFE: 815 return as->ext_id & AC97_EXT_AUDIO_LDAC; 816 case CHECK_HEADPHONES: 817 return as->caps & AC97_CAPS_HEADPHONES; 818 case CHECK_TONE: 819 return as->caps & AC97_CAPS_TONECTRL; 820 case CHECK_MIC: 821 return as->caps & AC97_CAPS_MICIN; 822 case CHECK_LOUDNESS: 823 return as->caps & AC97_CAPS_LOUDNESS; 824 case CHECK_3D: 825 return AC97_CAPS_ENHANCEMENT(as->caps) != 0; 826 default: 827 printf("%s: internal error: feature=%d\n", __func__, check); 828 return 0; 829 } 830 } 831 832 static void 833 ac97_setup_source_info(struct ac97_softc *as) 834 { 835 int idx, ouridx; 836 struct ac97_source_info *si, *si2; 837 838 for (idx = 0, ouridx = 0; idx < SOURCE_INFO_SIZE; idx++) { 839 si = &as->source_info[ouridx]; 840 841 if (!ac97_check_capability(as, source_info[idx].req_feature)) 842 continue; 843 844 memcpy(si, &source_info[idx], sizeof(*si)); 845 846 switch (si->type) { 847 case AUDIO_MIXER_CLASS: 848 si->mixer_class = ouridx; 849 ouridx++; 850 break; 851 case AUDIO_MIXER_VALUE: 852 /* Todo - Test to see if it works */ 853 ouridx++; 854 855 /* Add an entry for mute, if necessary */ 856 if (si->mute) { 857 si = &as->source_info[ouridx]; 858 memcpy(si, &source_info[idx], sizeof(*si)); 859 si->qualifier = AudioNmute; 860 si->type = AUDIO_MIXER_ENUM; 861 si->info = &ac97_on_off; 862 si->info_size = sizeof(ac97_on_off); 863 si->bits = 1; 864 si->ofs = 15; 865 si->mute = 0; 866 si->polarity = 0; 867 ouridx++; 868 } 869 break; 870 case AUDIO_MIXER_ENUM: 871 /* Todo - Test to see if it works */ 872 ouridx++; 873 break; 874 default: 875 aprint_error ("ac97: shouldn't get here\n"); 876 break; 877 } 878 } 879 880 as->num_source_info = ouridx; 881 882 for (idx = 0; idx < as->num_source_info; idx++) { 883 int idx2, previdx; 884 885 si = &as->source_info[idx]; 886 887 /* Find mixer class */ 888 for (idx2 = 0; idx2 < as->num_source_info; idx2++) { 889 si2 = &as->source_info[idx2]; 890 891 if (si2->type == AUDIO_MIXER_CLASS && 892 ac97_str_equal(si->class, 893 si2->class)) { 894 si->mixer_class = idx2; 895 } 896 } 897 898 899 /* Setup prev and next pointers */ 900 if (si->prev != 0) 901 continue; 902 903 if (si->qualifier) 904 continue; 905 906 si->prev = AUDIO_MIXER_LAST; 907 previdx = idx; 908 909 for (idx2 = 0; idx2 < as->num_source_info; idx2++) { 910 if (idx2 == idx) 911 continue; 912 913 si2 = &as->source_info[idx2]; 914 915 if (!si2->prev && 916 ac97_str_equal(si->class, si2->class) && 917 ac97_str_equal(si->device, si2->device)) { 918 as->source_info[previdx].next = idx2; 919 as->source_info[idx2].prev = previdx; 920 921 previdx = idx2; 922 } 923 } 924 925 as->source_info[previdx].next = AUDIO_MIXER_LAST; 926 } 927 } 928 929 int 930 ac97_attach(struct ac97_host_if *host_if) 931 { 932 struct ac97_softc *as; 933 struct device *sc_dev; 934 int error, i, j; 935 uint32_t id; 936 uint16_t id1, id2; 937 uint16_t extstat, rate; 938 uint16_t val; 939 mixer_ctrl_t ctl; 940 void (*initfunc)(struct ac97_softc *); 941 #define FLAGBUFLEN 140 942 char flagbuf[FLAGBUFLEN]; 943 944 sc_dev = (struct device *)host_if->arg; 945 initfunc = NULL; 946 as = malloc(sizeof(struct ac97_softc), M_DEVBUF, M_WAITOK|M_ZERO); 947 948 if (as == NULL) 949 return ENOMEM; 950 951 as->codec_if.vtbl = &ac97civ; 952 as->host_if = host_if; 953 954 if ((error = host_if->attach(host_if->arg, &as->codec_if))) { 955 free(as, M_DEVBUF); 956 return error; 957 } 958 959 host_if->reset(host_if->arg); 960 961 host_if->write(host_if->arg, AC97_REG_POWER, 0); 962 host_if->write(host_if->arg, AC97_REG_RESET, 0); 963 964 if (host_if->flags) 965 as->host_flags = host_if->flags(host_if->arg); 966 967 #define AC97_POWER_ALL (AC97_POWER_REF | AC97_POWER_ANL | AC97_POWER_DAC \ 968 | AC97_POWER_ADC) 969 for (i = 500000; i >= 0; i--) { 970 ac97_read(as, AC97_REG_POWER, &val); 971 if ((val & AC97_POWER_ALL) == AC97_POWER_ALL) 972 break; 973 DELAY(1); 974 } 975 #undef AC97_POWER_ALL 976 977 ac97_setup_defaults(as); 978 ac97_read(as, AC97_REG_RESET, &as->caps); 979 ac97_read(as, AC97_REG_VENDOR_ID1, &id1); 980 ac97_read(as, AC97_REG_VENDOR_ID2, &id2); 981 982 id = (id1 << 16) | id2; 983 984 aprint_normal("%s: ac97: ", sc_dev->dv_xname); 985 986 for (i = 0; ; i++) { 987 if (ac97codecid[i].id == 0) { 988 char pnp[4]; 989 990 AC97_GET_CODEC_ID(id, pnp); 991 #define ISASCII(c) ((c) >= ' ' && (c) < 0x7f) 992 if (ISASCII(pnp[0]) && ISASCII(pnp[1]) && 993 ISASCII(pnp[2])) 994 aprint_normal("%c%c%c%d", 995 pnp[0], pnp[1], pnp[2], pnp[3]); 996 else 997 aprint_normal("unknown (0x%08x)", id); 998 break; 999 } 1000 if (ac97codecid[i].id == (id & ac97codecid[i].mask)) { 1001 aprint_normal("%s", ac97codecid[i].name); 1002 if (ac97codecid[i].mask == AC97_VENDOR_ID_MASK) { 1003 aprint_normal(" (0x%08x)", id); 1004 } 1005 initfunc = ac97codecid[i].init; 1006 break; 1007 } 1008 } 1009 aprint_normal(" codec; "); 1010 for (i = j = 0; i < 10; i++) { 1011 if (as->caps & (1 << i)) { 1012 aprint_normal("%s%s", j ? ", " : "", ac97feature[i]); 1013 j++; 1014 } 1015 } 1016 aprint_normal("%s%s\n", j ? ", " : "", 1017 ac97enhancement[AC97_CAPS_ENHANCEMENT(as->caps)]); 1018 1019 as->ac97_clock = AC97_STANDARD_CLOCK; 1020 ac97_read(as, AC97_REG_EXT_AUDIO_ID, &as->ext_id); 1021 if (as->ext_id != 0) { 1022 /* Print capabilities */ 1023 bitmask_snprintf(as->ext_id, "\20\20SECONDARY10\17SECONDARY01" 1024 "\14AC97_23\13AC97_22\12AMAP\11LDAC\10SDAC" 1025 "\7CDAC\4VRM\3SPDIF\2DRA\1VRA", 1026 flagbuf, FLAGBUFLEN); 1027 aprint_normal("%s: ac97: ext id %s\n", sc_dev->dv_xname, flagbuf); 1028 1029 /* Print unusual settings */ 1030 if (as->ext_id & AC97_EXT_AUDIO_DSA_MASK) { 1031 aprint_normal("%s: ac97: Slot assignment: ", 1032 sc_dev->dv_xname); 1033 switch (as->ext_id & AC97_EXT_AUDIO_DSA_MASK) { 1034 case AC97_EXT_AUDIO_DSA01: 1035 aprint_normal("7&8, 6&9, 10&11.\n"); 1036 break; 1037 case AC97_EXT_AUDIO_DSA10: 1038 aprint_normal("6&9, 10&11, 3&4.\n"); 1039 break; 1040 case AC97_EXT_AUDIO_DSA11: 1041 aprint_normal("10&11, 3&4, 7&8.\n"); 1042 break; 1043 } 1044 } 1045 1046 /* Enable and disable features */ 1047 ac97_read(as, AC97_REG_EXT_AUDIO_CTRL, &extstat); 1048 extstat &= ~AC97_EXT_AUDIO_DRA; 1049 if (as->ext_id & AC97_EXT_AUDIO_LDAC) 1050 extstat |= AC97_EXT_AUDIO_LDAC; 1051 if (as->ext_id & AC97_EXT_AUDIO_SDAC) 1052 extstat |= AC97_EXT_AUDIO_SDAC; 1053 if (as->ext_id & AC97_EXT_AUDIO_CDAC) 1054 extstat |= AC97_EXT_AUDIO_CDAC; 1055 if (as->ext_id & AC97_EXT_AUDIO_VRM) 1056 extstat |= AC97_EXT_AUDIO_VRM; 1057 if (as->ext_id & AC97_EXT_AUDIO_SPDIF) { 1058 /* Output the same data as DAC to SPDIF output */ 1059 extstat &= ~AC97_EXT_AUDIO_SPSA_MASK; 1060 extstat |= AC97_EXT_AUDIO_SPSA34; 1061 } 1062 if (as->ext_id & AC97_EXT_AUDIO_VRA) 1063 extstat |= AC97_EXT_AUDIO_VRA; 1064 ac97_write(as, AC97_REG_EXT_AUDIO_CTRL, extstat); 1065 if (as->ext_id & AC97_EXT_AUDIO_VRA) { 1066 /* VRA should be enabled. */ 1067 /* so it claims to do variable rate, let's make sure */ 1068 ac97_write(as, AC97_REG_PCM_FRONT_DAC_RATE, 44100); 1069 ac97_read(as, AC97_REG_PCM_FRONT_DAC_RATE, &rate); 1070 if (rate != 44100) { 1071 /* We can't believe ext_id */ 1072 as->ext_id = 0; 1073 aprint_normal( 1074 "%s: Ignore these capabilities.\n", 1075 sc_dev->dv_xname); 1076 } 1077 /* restore the default value */ 1078 ac97_write(as, AC97_REG_PCM_FRONT_DAC_RATE, 1079 AC97_SINGLE_RATE); 1080 } 1081 } 1082 1083 ac97_setup_source_info(as); 1084 1085 memset(&ctl, 0, sizeof(ctl)); 1086 /* disable mutes */ 1087 for (i = 0; i < 11; i++) { 1088 static struct { 1089 char *class, *device; 1090 } d[11] = { 1091 { AudioCoutputs, AudioNmaster}, 1092 { AudioCoutputs, AudioNheadphone}, 1093 { AudioCoutputs, AudioNsurround}, 1094 { AudioCoutputs, AudioNcenter}, 1095 { AudioCoutputs, AudioNlfe}, 1096 { AudioCinputs, AudioNdac}, 1097 { AudioCinputs, AudioNcd}, 1098 { AudioCinputs, AudioNline}, 1099 { AudioCinputs, AudioNaux}, 1100 { AudioCinputs, AudioNvideo}, 1101 { AudioCrecord, AudioNvolume}, 1102 }; 1103 1104 ctl.type = AUDIO_MIXER_ENUM; 1105 ctl.un.ord = 0; 1106 1107 ctl.dev = ac97_get_portnum_by_name(&as->codec_if, 1108 d[i].class, d[i].device, AudioNmute); 1109 ac97_mixer_set_port(&as->codec_if, &ctl); 1110 } 1111 ctl.type = AUDIO_MIXER_ENUM; 1112 ctl.un.ord = 0; 1113 ctl.dev = ac97_get_portnum_by_name(&as->codec_if, AudioCrecord, 1114 AudioNsource, NULL); 1115 ac97_mixer_set_port(&as->codec_if, &ctl); 1116 1117 /* set a reasonable default volume */ 1118 ctl.type = AUDIO_MIXER_VALUE; 1119 ctl.un.value.num_channels = 2; 1120 ctl.un.value.level[AUDIO_MIXER_LEVEL_LEFT] = \ 1121 ctl.un.value.level[AUDIO_MIXER_LEVEL_RIGHT] = 127; 1122 ctl.dev = ac97_get_portnum_by_name(&as->codec_if, AudioCoutputs, 1123 AudioNmaster, NULL); 1124 ac97_mixer_set_port(&as->codec_if, &ctl); 1125 ctl.dev = ac97_get_portnum_by_name(&as->codec_if, AudioCoutputs, 1126 AudioNsurround, NULL); 1127 ac97_mixer_set_port(&as->codec_if, &ctl); 1128 ctl.un.value.num_channels = 1; 1129 ctl.dev = ac97_get_portnum_by_name(&as->codec_if, AudioCoutputs, 1130 AudioNcenter, NULL); 1131 ac97_mixer_set_port(&as->codec_if, &ctl); 1132 ctl.dev = ac97_get_portnum_by_name(&as->codec_if, AudioCoutputs, 1133 AudioNlfe, NULL); 1134 ac97_mixer_set_port(&as->codec_if, &ctl); 1135 1136 if (initfunc != NULL) 1137 initfunc(as); 1138 return 0; 1139 } 1140 1141 1142 static int 1143 ac97_query_devinfo(struct ac97_codec_if *codec_if, mixer_devinfo_t *dip) 1144 { 1145 struct ac97_softc *as; 1146 struct ac97_source_info *si; 1147 const char *name; 1148 1149 as = (struct ac97_softc *)codec_if; 1150 if (dip->index < as->num_source_info) { 1151 si = &as->source_info[dip->index]; 1152 dip->type = si->type; 1153 dip->mixer_class = si->mixer_class; 1154 dip->prev = si->prev; 1155 dip->next = si->next; 1156 1157 if (si->qualifier) 1158 name = si->qualifier; 1159 else if (si->device) 1160 name = si->device; 1161 else if (si->class) 1162 name = si->class; 1163 else 1164 name = 0; 1165 1166 if (name) 1167 strcpy(dip->label.name, name); 1168 1169 memcpy(&dip->un, si->info, si->info_size); 1170 1171 /* Set the delta for volume sources */ 1172 if (dip->type == AUDIO_MIXER_VALUE) 1173 dip->un.v.delta = 1 << (8 - si->bits); 1174 1175 return 0; 1176 } 1177 1178 return ENXIO; 1179 } 1180 1181 1182 1183 static int 1184 ac97_mixer_set_port(struct ac97_codec_if *codec_if, mixer_ctrl_t *cp) 1185 { 1186 struct ac97_softc *as; 1187 struct ac97_source_info *si; 1188 u_int16_t mask; 1189 u_int16_t val, newval; 1190 int error; 1191 1192 as = (struct ac97_softc *)codec_if; 1193 si = &as->source_info[cp->dev]; 1194 if (cp->dev < 0 || cp->dev >= as->num_source_info) 1195 return EINVAL; 1196 1197 if (cp->type != si->type) 1198 return EINVAL; 1199 1200 ac97_read(as, si->reg, &val); 1201 1202 DPRINTFN(5, ("read(%x) = %x\n", si->reg, val)); 1203 1204 mask = (1 << si->bits) - 1; 1205 1206 switch (cp->type) { 1207 case AUDIO_MIXER_ENUM: 1208 if (cp->un.ord > mask || cp->un.ord < 0) 1209 return EINVAL; 1210 1211 newval = (cp->un.ord << si->ofs); 1212 if (si->reg == AC97_REG_RECORD_SELECT) { 1213 newval |= (newval << (8 + si->ofs)); 1214 mask |= (mask << 8); 1215 mask = mask << si->ofs; 1216 } else if (si->reg == AC97_REG_SURR_MASTER) { 1217 newval = cp->un.ord ? 0x8080 : 0x0000; 1218 mask = 0x8080; 1219 } else 1220 mask = mask << si->ofs; 1221 break; 1222 case AUDIO_MIXER_VALUE: 1223 { 1224 const struct audio_mixer_value *value = si->info; 1225 u_int16_t l, r, ol, or; 1226 int deltal, deltar; 1227 1228 if ((cp->un.value.num_channels <= 0) || 1229 (cp->un.value.num_channels > value->num_channels)) 1230 return EINVAL; 1231 1232 if (cp->un.value.num_channels == 1) { 1233 l = r = cp->un.value.level[AUDIO_MIXER_LEVEL_MONO]; 1234 } else { 1235 if (!(as->host_flags & AC97_HOST_SWAPPED_CHANNELS)) { 1236 l = cp->un.value.level[AUDIO_MIXER_LEVEL_LEFT]; 1237 r = cp->un.value.level[AUDIO_MIXER_LEVEL_RIGHT]; 1238 } else { /* left/right is reversed here */ 1239 r = cp->un.value.level[AUDIO_MIXER_LEVEL_LEFT]; 1240 l = cp->un.value.level[AUDIO_MIXER_LEVEL_RIGHT]; 1241 } 1242 1243 } 1244 1245 if (!si->polarity) { 1246 l = 255 - l; 1247 r = 255 - r; 1248 } 1249 1250 ol = (val >> (8+si->ofs)) & mask; 1251 or = (val >> si->ofs) & mask; 1252 1253 deltal = (ol << (8 - si->bits)) - l; 1254 deltar = (or << (8 - si->bits)) - r; 1255 1256 l = l >> (8 - si->bits); 1257 r = r >> (8 - si->bits); 1258 1259 if (deltal && ol == l) 1260 l += (deltal > 0) ? (l ? -1 : 0) : (l < mask ? 1 : 0); 1261 if (deltar && or == r) 1262 r += (deltar > 0) ? (r ? -1 : 0) : (r < mask ? 1 : 0); 1263 1264 newval = ((r & mask) << si->ofs); 1265 if (value->num_channels == 2) { 1266 newval = newval | ((l & mask) << (si->ofs+8)); 1267 mask |= (mask << 8); 1268 } 1269 mask = mask << si->ofs; 1270 break; 1271 } 1272 default: 1273 return EINVAL; 1274 } 1275 1276 error = ac97_write(as, si->reg, (val & ~mask) | newval); 1277 if (error) 1278 return error; 1279 1280 return 0; 1281 } 1282 1283 static int 1284 ac97_get_portnum_by_name(struct ac97_codec_if *codec_if, const char *class, 1285 const char *device, const char *qualifier) 1286 { 1287 struct ac97_softc *as; 1288 int idx; 1289 1290 as = (struct ac97_softc *)codec_if; 1291 for (idx = 0; idx < as->num_source_info; idx++) { 1292 struct ac97_source_info *si = &as->source_info[idx]; 1293 if (ac97_str_equal(class, si->class) && 1294 ac97_str_equal(device, si->device) && 1295 ac97_str_equal(qualifier, si->qualifier)) 1296 return idx; 1297 } 1298 1299 return -1; 1300 } 1301 1302 static int 1303 ac97_mixer_get_port(struct ac97_codec_if *codec_if, mixer_ctrl_t *cp) 1304 { 1305 struct ac97_softc *as; 1306 struct ac97_source_info *si; 1307 u_int16_t mask; 1308 u_int16_t val; 1309 1310 as = (struct ac97_softc *)codec_if; 1311 si = &as->source_info[cp->dev]; 1312 if (cp->dev < 0 || cp->dev >= as->num_source_info) 1313 return EINVAL; 1314 1315 if (cp->type != si->type) 1316 return EINVAL; 1317 1318 ac97_read(as, si->reg, &val); 1319 1320 DPRINTFN(5, ("read(%x) = %x\n", si->reg, val)); 1321 1322 mask = (1 << si->bits) - 1; 1323 1324 switch (cp->type) { 1325 case AUDIO_MIXER_ENUM: 1326 cp->un.ord = (val >> si->ofs) & mask; 1327 DPRINTFN(4, ("AUDIO_MIXER_ENUM: %x %d %x %d\n", 1328 val, si->ofs, mask, cp->un.ord)); 1329 break; 1330 case AUDIO_MIXER_VALUE: 1331 { 1332 const struct audio_mixer_value *value = si->info; 1333 u_int16_t l, r; 1334 1335 if ((cp->un.value.num_channels <= 0) || 1336 (cp->un.value.num_channels > value->num_channels)) 1337 return EINVAL; 1338 1339 if (value->num_channels == 1) { 1340 l = r = (val >> si->ofs) & mask; 1341 } else { 1342 if (!(as->host_flags & AC97_HOST_SWAPPED_CHANNELS)) { 1343 l = (val >> (si->ofs + 8)) & mask; 1344 r = (val >> si->ofs) & mask; 1345 } else { /* host has reversed channels */ 1346 r = (val >> (si->ofs + 8)) & mask; 1347 l = (val >> si->ofs) & mask; 1348 } 1349 } 1350 1351 l = (l << (8 - si->bits)); 1352 r = (r << (8 - si->bits)); 1353 if (!si->polarity) { 1354 l = 255 - l; 1355 r = 255 - r; 1356 } 1357 1358 /* The EAP driver averages l and r for stereo 1359 channels that are requested in MONO mode. Does this 1360 make sense? */ 1361 if (cp->un.value.num_channels == 1) { 1362 cp->un.value.level[AUDIO_MIXER_LEVEL_MONO] = l; 1363 } else if (cp->un.value.num_channels == 2) { 1364 cp->un.value.level[AUDIO_MIXER_LEVEL_LEFT] = l; 1365 cp->un.value.level[AUDIO_MIXER_LEVEL_RIGHT] = r; 1366 } 1367 1368 break; 1369 } 1370 default: 1371 return EINVAL; 1372 } 1373 1374 return 0; 1375 } 1376 1377 1378 static int 1379 ac97_set_rate(struct ac97_codec_if *codec_if, int target, u_long *rate) 1380 { 1381 struct ac97_softc *as; 1382 u_long value; 1383 u_int16_t ext_stat; 1384 u_int16_t actual; 1385 u_int16_t power; 1386 u_int16_t power_bit; 1387 1388 as = (struct ac97_softc *)codec_if; 1389 if (target == AC97_REG_PCM_MIC_ADC_RATE) { 1390 if (!(as->ext_id & AC97_EXT_AUDIO_VRM)) { 1391 *rate = AC97_SINGLE_RATE; 1392 return 0; 1393 } 1394 } else { 1395 if (!(as->ext_id & AC97_EXT_AUDIO_VRA)) { 1396 *rate = AC97_SINGLE_RATE; 1397 return 0; 1398 } 1399 } 1400 value = *rate * AC97_STANDARD_CLOCK / as->ac97_clock; 1401 ext_stat = 0; 1402 /* 1403 * PCM_FRONT_DAC_RATE/PCM_SURR_DAC_RATE/PCM_LFE_DAC_RATE 1404 * Check VRA, DRA 1405 * PCM_LR_ADC_RATE 1406 * Check VRA 1407 * PCM_MIC_ADC_RATE 1408 * Check VRM 1409 */ 1410 switch (target) { 1411 case AC97_REG_PCM_FRONT_DAC_RATE: 1412 case AC97_REG_PCM_SURR_DAC_RATE: 1413 case AC97_REG_PCM_LFE_DAC_RATE: 1414 power_bit = AC97_POWER_OUT; 1415 if (!(as->ext_id & AC97_EXT_AUDIO_VRA)) { 1416 *rate = AC97_SINGLE_RATE; 1417 return 0; 1418 } 1419 if (as->ext_id & AC97_EXT_AUDIO_DRA) { 1420 ac97_read(as, AC97_REG_EXT_AUDIO_CTRL, &ext_stat); 1421 if (value > 0x1ffff) { 1422 return EINVAL; 1423 } else if (value > 0xffff) { 1424 /* Enable DRA */ 1425 ext_stat |= AC97_EXT_AUDIO_DRA; 1426 ac97_write(as, AC97_REG_EXT_AUDIO_CTRL, ext_stat); 1427 value /= 2; 1428 } else { 1429 /* Disable DRA */ 1430 ext_stat &= ~AC97_EXT_AUDIO_DRA; 1431 ac97_write(as, AC97_REG_EXT_AUDIO_CTRL, ext_stat); 1432 } 1433 } else { 1434 if (value > 0xffff) 1435 return EINVAL; 1436 } 1437 break; 1438 case AC97_REG_PCM_LR_ADC_RATE: 1439 power_bit = AC97_POWER_IN; 1440 if (!(as->ext_id & AC97_EXT_AUDIO_VRA)) { 1441 *rate = AC97_SINGLE_RATE; 1442 return 0; 1443 } 1444 if (value > 0xffff) 1445 return EINVAL; 1446 break; 1447 case AC97_REG_PCM_MIC_ADC_RATE: 1448 power_bit = AC97_POWER_IN; 1449 if (!(as->ext_id & AC97_EXT_AUDIO_VRM)) { 1450 *rate = AC97_SINGLE_RATE; 1451 return 0; 1452 } 1453 if (value > 0xffff) 1454 return EINVAL; 1455 break; 1456 default: 1457 printf("%s: Unknown register: 0x%x\n", __func__, target); 1458 return EINVAL; 1459 } 1460 1461 ac97_read(as, AC97_REG_POWER, &power); 1462 ac97_write(as, AC97_REG_POWER, power | power_bit); 1463 1464 ac97_write(as, target, (u_int16_t)value); 1465 ac97_read(as, target, &actual); 1466 actual = (u_int32_t)actual * as->ac97_clock / AC97_STANDARD_CLOCK; 1467 1468 ac97_write(as, AC97_REG_POWER, power); 1469 if (ext_stat & AC97_EXT_AUDIO_DRA) { 1470 *rate = actual * 2; 1471 } else { 1472 *rate = actual; 1473 } 1474 return 0; 1475 } 1476 1477 static void 1478 ac97_set_clock(struct ac97_codec_if *codec_if, unsigned int clock) 1479 { 1480 struct ac97_softc *as; 1481 1482 as = (struct ac97_softc *)codec_if; 1483 as->ac97_clock = clock; 1484 } 1485 1486 static u_int16_t 1487 ac97_get_extcaps(struct ac97_codec_if *codec_if) 1488 { 1489 struct ac97_softc *as; 1490 1491 as = (struct ac97_softc *)codec_if; 1492 return as->ext_id; 1493 } 1494 1495 static int 1496 ac97_add_port(struct ac97_softc *as, const struct ac97_source_info *src) 1497 { 1498 struct ac97_source_info *si; 1499 int ouridx, idx; 1500 1501 if (as->num_source_info >= MAX_SOURCES) { 1502 printf("%s: internal error: increase MAX_SOURCES in %s\n", 1503 __func__, __FILE__); 1504 return -1; 1505 } 1506 if (!ac97_check_capability(as, src->req_feature)) 1507 return -1; 1508 ouridx = as->num_source_info; 1509 si = &as->source_info[ouridx]; 1510 memcpy(si, src, sizeof(*si)); 1511 1512 switch (si->type) { 1513 case AUDIO_MIXER_CLASS: 1514 case AUDIO_MIXER_VALUE: 1515 printf("%s: adding class/value is not supported yet.\n", 1516 __func__); 1517 return -1; 1518 case AUDIO_MIXER_ENUM: 1519 break; 1520 default: 1521 printf("%s: unknown type: %d\n", __func__, si->type); 1522 return -1; 1523 } 1524 as->num_source_info++; 1525 1526 si->mixer_class = ac97_get_portnum_by_name(&as->codec_if, si->class, 1527 NULL, NULL); 1528 /* Find the root of the device */ 1529 idx = ac97_get_portnum_by_name(&as->codec_if, si->class, 1530 si->device, NULL); 1531 /* Find the last item */ 1532 while (as->source_info[idx].next != AUDIO_MIXER_LAST) 1533 idx = as->source_info[idx].next; 1534 /* Append */ 1535 as->source_info[idx].next = ouridx; 1536 si->prev = idx; 1537 si->next = AUDIO_MIXER_LAST; 1538 1539 return 0; 1540 } 1541 1542 /** 1543 * Codec-dependent initialization 1544 */ 1545 1546 #define AD1980_REG_MISC 0x76 1547 #define AD1980_MISC_MBG0 0x0001 /* 0 1888/1980/1981 /1985 */ 1548 #define AD1980_MISC_MBG1 0x0002 /* 1 1888/1980/1981 /1985 */ 1549 #define AD1980_MISC_VREFD 0x0004 /* 2 1888/1980/1981 /1985 */ 1550 #define AD1980_MISC_VREFH 0x0008 /* 3 1888/1980/1981 /1985 */ 1551 #define AD1980_MISC_SRU 0x0010 /* 4 1888/1980 /1985 */ 1552 #define AD1980_MISC_LOSEL 0x0020 /* 5 1888/1980/1981 /1985 */ 1553 #define AD1980_MISC_2CMIC 0x0040 /* 6 1980/1981B/1985 */ 1554 #define AD1980_MISC_SPRD 0x0080 /* 7 1888/1980 /1985 */ 1555 #define AD1980_MISC_DMIX0 0x0100 /* 8 1888/1980 /1985 */ 1556 #define AD1980_MISC_DMIX1 0x0200 /* 9 1888/1980 /1985 */ 1557 #define AD1980_MISC_HPSEL 0x0400 /*10 1888/1980 /1985 */ 1558 #define AD1980_MISC_CLDIS 0x0800 /*11 1888/1980 /1985 */ 1559 #define AD1980_MISC_LODIS 0x1000 /*12 1888/1980/1981 /1985 */ 1560 #define AD1980_MISC_MSPLT 0x2000 /*13 1888/1980/1981 /1985 */ 1561 #define AD1980_MISC_AC97NC 0x4000 /*14 1888/1980 /1985 */ 1562 #define AD1980_MISC_DACZ 0x8000 /*15 1888/1980/1981 /1985 */ 1563 #define AD1981_REG_MISC 0x76 1564 #define AD1981_MISC_MADST 0x0010 /* 4 */ 1565 #define AD1981A_MISC_MADPD 0x0040 /* 6 */ 1566 #define AD1981B_MISC_MADPD 0x0080 /* 7 */ 1567 #define AD1981_MISC_FMXE 0x0200 /* 9 */ 1568 #define AD1981_MISC_DAM 0x0800 /*11 */ 1569 static void 1570 ac97_ad198x_init(struct ac97_softc *as) 1571 { 1572 int i; 1573 uint16_t misc; 1574 1575 ac97_read(as, AD1980_REG_MISC, &misc); 1576 ac97_write(as, AD1980_REG_MISC, 1577 misc | AD1980_MISC_LOSEL | AD1980_MISC_HPSEL); 1578 1579 for (i = 0; i < as->num_source_info; i++) { 1580 if (as->source_info[i].type != AUDIO_MIXER_VALUE) 1581 continue; 1582 1583 if (as->source_info[i].reg == AC97_REG_MASTER_VOLUME) 1584 as->source_info[i].reg = AC97_REG_SURR_MASTER; 1585 else if (as->source_info[i].reg == AC97_REG_SURR_MASTER) 1586 as->source_info[i].reg = AC97_REG_MASTER_VOLUME; 1587 } 1588 } 1589 1590 #define ALC650_REG_MULTI_CHANNEL_CONTROL 0x6a 1591 #define ALC650_MCC_SLOT_MODIFY_MASK 0xc000 1592 #define ALC650_MCC_FRONTDAC_FROM_SPDIFIN 0x2000 /* 13 */ 1593 #define ALC650_MCC_SPDIFOUT_FROM_ADC 0x1000 /* 12 */ 1594 #define ALC650_MCC_PCM_FROM_SPDIFIN 0x0800 /* 11 */ 1595 #define ALC650_MCC_MIC_OR_CENTERLFE 0x0400 /* 10 */ 1596 #define ALC650_MCC_LINEIN_OR_SURROUND 0x0200 /* 9 */ 1597 #define ALC650_MCC_INDEPENDENT_MASTER_L 0x0080 /* 7 */ 1598 #define ALC650_MCC_INDEPENDENT_MASTER_R 0x0040 /* 6 */ 1599 #define ALC650_MCC_ANALOG_TO_CENTERLFE 0x0020 /* 5 */ 1600 #define ALC650_MCC_ANALOG_TO_SURROUND 0x0010 /* 4 */ 1601 #define ALC650_MCC_EXCHANGE_CENTERLFE 0x0008 /* 3 */ 1602 #define ALC650_MCC_CENTERLFE_DOWNMIX 0x0004 /* 2 */ 1603 #define ALC650_MCC_SURROUND_DOWNMIX 0x0002 /* 1 */ 1604 #define ALC650_MCC_LINEOUT_TO_SURROUND 0x0001 /* 0 */ 1605 static void 1606 ac97_alc650_init(struct ac97_softc *as) 1607 { 1608 static const struct ac97_source_info sources[6] = { 1609 { AudioCoutputs, AudioNsurround, "lineinjack", 1610 AUDIO_MIXER_ENUM, WRAP(ac97_on_off), 1611 ALC650_REG_MULTI_CHANNEL_CONTROL, 1612 0x0000, 1, 9, 0, 0, CHECK_SURROUND }, 1613 { AudioCoutputs, AudioNsurround, "mixtofront", 1614 AUDIO_MIXER_ENUM, WRAP(ac97_on_off), 1615 ALC650_REG_MULTI_CHANNEL_CONTROL, 1616 0x0000, 1, 1, 0, 0, CHECK_SURROUND }, 1617 { AudioCoutputs, AudioNcenter, "micjack", 1618 AUDIO_MIXER_ENUM, WRAP(ac97_on_off), 1619 ALC650_REG_MULTI_CHANNEL_CONTROL, 1620 0x0000, 1, 10, 0, 0, CHECK_CENTER }, 1621 { AudioCoutputs, AudioNlfe, "micjack", 1622 AUDIO_MIXER_ENUM, WRAP(ac97_on_off), 1623 ALC650_REG_MULTI_CHANNEL_CONTROL, 1624 0x0000, 1, 10, 0, 0, CHECK_LFE }, 1625 { AudioCoutputs, AudioNcenter, "mixtofront", 1626 AUDIO_MIXER_ENUM, WRAP(ac97_on_off), 1627 ALC650_REG_MULTI_CHANNEL_CONTROL, 1628 0x0000, 1, 2, 0, 0, CHECK_CENTER }, 1629 { AudioCoutputs, AudioNlfe, "mixtofront", 1630 AUDIO_MIXER_ENUM, WRAP(ac97_on_off), 1631 ALC650_REG_MULTI_CHANNEL_CONTROL, 1632 0x0000, 1, 2, 0, 0, CHECK_LFE }, 1633 }; 1634 1635 ac97_add_port(as, &sources[0]); 1636 ac97_add_port(as, &sources[1]); 1637 ac97_add_port(as, &sources[2]); 1638 ac97_add_port(as, &sources[3]); 1639 ac97_add_port(as, &sources[4]); 1640 ac97_add_port(as, &sources[5]); 1641 } 1642 1643 #define VT1616_REG_IO_CONTROL 0x5a 1644 #define VT1616_IC_LVL (1 << 15) 1645 #define VT1616_IC_LFECENTER_TO_FRONT (1 << 12) 1646 #define VT1616_IC_SURROUND_TO_FRONT (1 << 11) 1647 #define VT1616_IC_BPDC (1 << 10) 1648 #define VT1616_IC_DC (1 << 9) 1649 #define VT1616_IC_IB_MASK 0x000c 1650 static void 1651 ac97_vt1616_init(struct ac97_softc *as) 1652 { 1653 static const struct ac97_source_info sources[3] = { 1654 { AudioCoutputs, AudioNsurround, "mixtofront", 1655 AUDIO_MIXER_ENUM, WRAP(ac97_on_off), 1656 VT1616_REG_IO_CONTROL, 1657 0x0000, 1, 11, 0, 0, CHECK_SURROUND }, 1658 { AudioCoutputs, AudioNcenter, "mixtofront", 1659 AUDIO_MIXER_ENUM, WRAP(ac97_on_off), 1660 VT1616_REG_IO_CONTROL, 1661 0x0000, 1, 12, 0, 0, CHECK_CENTER }, 1662 { AudioCoutputs, AudioNlfe, "mixtofront", 1663 AUDIO_MIXER_ENUM, WRAP(ac97_on_off), 1664 VT1616_REG_IO_CONTROL, 1665 0x0000, 1, 12, 0, 0, CHECK_LFE }, 1666 }; 1667 1668 ac97_add_port(as, &sources[0]); 1669 ac97_add_port(as, &sources[1]); 1670 ac97_add_port(as, &sources[2]); 1671 } 1672