1 /* 2 * Copyright (c) by Jaroslav Kysela <perex@suse.cz> 3 * Routines for Sound Blaster mixer control 4 * 5 * 6 * This program is free software; you can redistribute it and/or modify 7 * it under the terms of the GNU General Public License as published by 8 * the Free Software Foundation; either version 2 of the License, or 9 * (at your option) any later version. 10 * 11 * This program is distributed in the hope that it will be useful, 12 * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 * GNU General Public License for more details. 15 * 16 * You should have received a copy of the GNU General Public License 17 * along with this program; if not, write to the Free Software 18 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 19 * 20 */ 21 22 #include <sound/driver.h> 23 #include <asm/io.h> 24 #include <linux/delay.h> 25 #include <linux/time.h> 26 #include <sound/core.h> 27 #include <sound/sb.h> 28 #include <sound/control.h> 29 30 #undef IO_DEBUG 31 32 void snd_sbmixer_write(sb_t *chip, unsigned char reg, unsigned char data) 33 { 34 outb(reg, SBP(chip, MIXER_ADDR)); 35 udelay(10); 36 outb(data, SBP(chip, MIXER_DATA)); 37 udelay(10); 38 #ifdef IO_DEBUG 39 snd_printk(KERN_DEBUG "mixer_write 0x%x 0x%x\n", reg, data); 40 #endif 41 } 42 43 unsigned char snd_sbmixer_read(sb_t *chip, unsigned char reg) 44 { 45 unsigned char result; 46 47 outb(reg, SBP(chip, MIXER_ADDR)); 48 udelay(10); 49 result = inb(SBP(chip, MIXER_DATA)); 50 udelay(10); 51 #ifdef IO_DEBUG 52 snd_printk(KERN_DEBUG "mixer_read 0x%x 0x%x\n", reg, result); 53 #endif 54 return result; 55 } 56 57 /* 58 * Single channel mixer element 59 */ 60 61 static int snd_sbmixer_info_single(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t * uinfo) 62 { 63 int mask = (kcontrol->private_value >> 24) & 0xff; 64 65 uinfo->type = mask == 1 ? SNDRV_CTL_ELEM_TYPE_BOOLEAN : SNDRV_CTL_ELEM_TYPE_INTEGER; 66 uinfo->count = 1; 67 uinfo->value.integer.min = 0; 68 uinfo->value.integer.max = mask; 69 return 0; 70 } 71 72 static int snd_sbmixer_get_single(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * ucontrol) 73 { 74 sb_t *sb = snd_kcontrol_chip(kcontrol); 75 unsigned long flags; 76 int reg = kcontrol->private_value & 0xff; 77 int shift = (kcontrol->private_value >> 16) & 0xff; 78 int mask = (kcontrol->private_value >> 24) & 0xff; 79 unsigned char val; 80 81 spin_lock_irqsave(&sb->mixer_lock, flags); 82 val = (snd_sbmixer_read(sb, reg) >> shift) & mask; 83 spin_unlock_irqrestore(&sb->mixer_lock, flags); 84 ucontrol->value.integer.value[0] = val; 85 return 0; 86 } 87 88 static int snd_sbmixer_put_single(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * ucontrol) 89 { 90 sb_t *sb = snd_kcontrol_chip(kcontrol); 91 unsigned long flags; 92 int reg = kcontrol->private_value & 0xff; 93 int shift = (kcontrol->private_value >> 16) & 0x07; 94 int mask = (kcontrol->private_value >> 24) & 0xff; 95 int change; 96 unsigned char val, oval; 97 98 val = (ucontrol->value.integer.value[0] & mask) << shift; 99 spin_lock_irqsave(&sb->mixer_lock, flags); 100 oval = snd_sbmixer_read(sb, reg); 101 val = (oval & ~(mask << shift)) | val; 102 change = val != oval; 103 if (change) 104 snd_sbmixer_write(sb, reg, val); 105 spin_unlock_irqrestore(&sb->mixer_lock, flags); 106 return change; 107 } 108 109 /* 110 * Double channel mixer element 111 */ 112 113 static int snd_sbmixer_info_double(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t * uinfo) 114 { 115 int mask = (kcontrol->private_value >> 24) & 0xff; 116 117 uinfo->type = mask == 1 ? SNDRV_CTL_ELEM_TYPE_BOOLEAN : SNDRV_CTL_ELEM_TYPE_INTEGER; 118 uinfo->count = 2; 119 uinfo->value.integer.min = 0; 120 uinfo->value.integer.max = mask; 121 return 0; 122 } 123 124 static int snd_sbmixer_get_double(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * ucontrol) 125 { 126 sb_t *sb = snd_kcontrol_chip(kcontrol); 127 unsigned long flags; 128 int left_reg = kcontrol->private_value & 0xff; 129 int right_reg = (kcontrol->private_value >> 8) & 0xff; 130 int left_shift = (kcontrol->private_value >> 16) & 0x07; 131 int right_shift = (kcontrol->private_value >> 19) & 0x07; 132 int mask = (kcontrol->private_value >> 24) & 0xff; 133 unsigned char left, right; 134 135 spin_lock_irqsave(&sb->mixer_lock, flags); 136 left = (snd_sbmixer_read(sb, left_reg) >> left_shift) & mask; 137 right = (snd_sbmixer_read(sb, right_reg) >> right_shift) & mask; 138 spin_unlock_irqrestore(&sb->mixer_lock, flags); 139 ucontrol->value.integer.value[0] = left; 140 ucontrol->value.integer.value[1] = right; 141 return 0; 142 } 143 144 static int snd_sbmixer_put_double(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * ucontrol) 145 { 146 sb_t *sb = snd_kcontrol_chip(kcontrol); 147 unsigned long flags; 148 int left_reg = kcontrol->private_value & 0xff; 149 int right_reg = (kcontrol->private_value >> 8) & 0xff; 150 int left_shift = (kcontrol->private_value >> 16) & 0x07; 151 int right_shift = (kcontrol->private_value >> 19) & 0x07; 152 int mask = (kcontrol->private_value >> 24) & 0xff; 153 int change; 154 unsigned char left, right, oleft, oright; 155 156 left = (ucontrol->value.integer.value[0] & mask) << left_shift; 157 right = (ucontrol->value.integer.value[1] & mask) << right_shift; 158 spin_lock_irqsave(&sb->mixer_lock, flags); 159 if (left_reg == right_reg) { 160 oleft = snd_sbmixer_read(sb, left_reg); 161 left = (oleft & ~((mask << left_shift) | (mask << right_shift))) | left | right; 162 change = left != oleft; 163 if (change) 164 snd_sbmixer_write(sb, left_reg, left); 165 } else { 166 oleft = snd_sbmixer_read(sb, left_reg); 167 oright = snd_sbmixer_read(sb, right_reg); 168 left = (oleft & ~(mask << left_shift)) | left; 169 right = (oright & ~(mask << right_shift)) | right; 170 change = left != oleft || right != oright; 171 if (change) { 172 snd_sbmixer_write(sb, left_reg, left); 173 snd_sbmixer_write(sb, right_reg, right); 174 } 175 } 176 spin_unlock_irqrestore(&sb->mixer_lock, flags); 177 return change; 178 } 179 180 /* 181 * DT-019x / ALS-007 capture/input switch 182 */ 183 184 static int snd_dt019x_input_sw_info(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t * uinfo) 185 { 186 static char *texts[5] = { 187 "CD", "Mic", "Line", "Synth", "Master" 188 }; 189 190 uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; 191 uinfo->count = 1; 192 uinfo->value.enumerated.items = 5; 193 if (uinfo->value.enumerated.item > 4) 194 uinfo->value.enumerated.item = 4; 195 strcpy(uinfo->value.enumerated.name, texts[uinfo->value.enumerated.item]); 196 return 0; 197 } 198 199 static int snd_dt019x_input_sw_get(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * ucontrol) 200 { 201 sb_t *sb = snd_kcontrol_chip(kcontrol); 202 unsigned long flags; 203 unsigned char oval; 204 205 spin_lock_irqsave(&sb->mixer_lock, flags); 206 oval = snd_sbmixer_read(sb, SB_DT019X_CAPTURE_SW); 207 spin_unlock_irqrestore(&sb->mixer_lock, flags); 208 switch (oval & 0x07) { 209 case SB_DT019X_CAP_CD: 210 ucontrol->value.enumerated.item[0] = 0; 211 break; 212 case SB_DT019X_CAP_MIC: 213 ucontrol->value.enumerated.item[0] = 1; 214 break; 215 case SB_DT019X_CAP_LINE: 216 ucontrol->value.enumerated.item[0] = 2; 217 break; 218 case SB_DT019X_CAP_MAIN: 219 ucontrol->value.enumerated.item[0] = 4; 220 break; 221 /* To record the synth on these cards you must record the main. */ 222 /* Thus SB_DT019X_CAP_SYNTH == SB_DT019X_CAP_MAIN and would cause */ 223 /* duplicate case labels if left uncommented. */ 224 /* case SB_DT019X_CAP_SYNTH: 225 * ucontrol->value.enumerated.item[0] = 3; 226 * break; 227 */ 228 default: 229 ucontrol->value.enumerated.item[0] = 4; 230 break; 231 } 232 return 0; 233 } 234 235 static int snd_dt019x_input_sw_put(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * ucontrol) 236 { 237 sb_t *sb = snd_kcontrol_chip(kcontrol); 238 unsigned long flags; 239 int change; 240 unsigned char nval, oval; 241 242 if (ucontrol->value.enumerated.item[0] > 4) 243 return -EINVAL; 244 switch (ucontrol->value.enumerated.item[0]) { 245 case 0: 246 nval = SB_DT019X_CAP_CD; 247 break; 248 case 1: 249 nval = SB_DT019X_CAP_MIC; 250 break; 251 case 2: 252 nval = SB_DT019X_CAP_LINE; 253 break; 254 case 3: 255 nval = SB_DT019X_CAP_SYNTH; 256 break; 257 case 4: 258 nval = SB_DT019X_CAP_MAIN; 259 break; 260 default: 261 nval = SB_DT019X_CAP_MAIN; 262 } 263 spin_lock_irqsave(&sb->mixer_lock, flags); 264 oval = snd_sbmixer_read(sb, SB_DT019X_CAPTURE_SW); 265 change = nval != oval; 266 if (change) 267 snd_sbmixer_write(sb, SB_DT019X_CAPTURE_SW, nval); 268 spin_unlock_irqrestore(&sb->mixer_lock, flags); 269 return change; 270 } 271 272 /* 273 * SBPRO input multiplexer 274 */ 275 276 static int snd_sb8mixer_info_mux(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t * uinfo) 277 { 278 static char *texts[3] = { 279 "Mic", "CD", "Line" 280 }; 281 282 uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; 283 uinfo->count = 1; 284 uinfo->value.enumerated.items = 3; 285 if (uinfo->value.enumerated.item > 2) 286 uinfo->value.enumerated.item = 2; 287 strcpy(uinfo->value.enumerated.name, texts[uinfo->value.enumerated.item]); 288 return 0; 289 } 290 291 292 static int snd_sb8mixer_get_mux(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * ucontrol) 293 { 294 sb_t *sb = snd_kcontrol_chip(kcontrol); 295 unsigned long flags; 296 unsigned char oval; 297 298 spin_lock_irqsave(&sb->mixer_lock, flags); 299 oval = snd_sbmixer_read(sb, SB_DSP_CAPTURE_SOURCE); 300 spin_unlock_irqrestore(&sb->mixer_lock, flags); 301 switch ((oval >> 0x01) & 0x03) { 302 case SB_DSP_MIXS_CD: 303 ucontrol->value.enumerated.item[0] = 1; 304 break; 305 case SB_DSP_MIXS_LINE: 306 ucontrol->value.enumerated.item[0] = 2; 307 break; 308 default: 309 ucontrol->value.enumerated.item[0] = 0; 310 break; 311 } 312 return 0; 313 } 314 315 static int snd_sb8mixer_put_mux(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * ucontrol) 316 { 317 sb_t *sb = snd_kcontrol_chip(kcontrol); 318 unsigned long flags; 319 int change; 320 unsigned char nval, oval; 321 322 if (ucontrol->value.enumerated.item[0] > 2) 323 return -EINVAL; 324 switch (ucontrol->value.enumerated.item[0]) { 325 case 1: 326 nval = SB_DSP_MIXS_CD; 327 break; 328 case 2: 329 nval = SB_DSP_MIXS_LINE; 330 break; 331 default: 332 nval = SB_DSP_MIXS_MIC; 333 } 334 nval <<= 1; 335 spin_lock_irqsave(&sb->mixer_lock, flags); 336 oval = snd_sbmixer_read(sb, SB_DSP_CAPTURE_SOURCE); 337 nval |= oval & ~0x06; 338 change = nval != oval; 339 if (change) 340 snd_sbmixer_write(sb, SB_DSP_CAPTURE_SOURCE, nval); 341 spin_unlock_irqrestore(&sb->mixer_lock, flags); 342 return change; 343 } 344 345 /* 346 * SB16 input switch 347 */ 348 349 static int snd_sb16mixer_info_input_sw(snd_kcontrol_t * kcontrol, snd_ctl_elem_info_t * uinfo) 350 { 351 uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN; 352 uinfo->count = 4; 353 uinfo->value.integer.min = 0; 354 uinfo->value.integer.max = 1; 355 return 0; 356 } 357 358 static int snd_sb16mixer_get_input_sw(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * ucontrol) 359 { 360 sb_t *sb = snd_kcontrol_chip(kcontrol); 361 unsigned long flags; 362 int reg1 = kcontrol->private_value & 0xff; 363 int reg2 = (kcontrol->private_value >> 8) & 0xff; 364 int left_shift = (kcontrol->private_value >> 16) & 0x0f; 365 int right_shift = (kcontrol->private_value >> 24) & 0x0f; 366 unsigned char val1, val2; 367 368 spin_lock_irqsave(&sb->mixer_lock, flags); 369 val1 = snd_sbmixer_read(sb, reg1); 370 val2 = snd_sbmixer_read(sb, reg2); 371 spin_unlock_irqrestore(&sb->mixer_lock, flags); 372 ucontrol->value.integer.value[0] = (val1 >> left_shift) & 0x01; 373 ucontrol->value.integer.value[1] = (val2 >> left_shift) & 0x01; 374 ucontrol->value.integer.value[2] = (val1 >> right_shift) & 0x01; 375 ucontrol->value.integer.value[3] = (val2 >> right_shift) & 0x01; 376 return 0; 377 } 378 379 static int snd_sb16mixer_put_input_sw(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * ucontrol) 380 { 381 sb_t *sb = snd_kcontrol_chip(kcontrol); 382 unsigned long flags; 383 int reg1 = kcontrol->private_value & 0xff; 384 int reg2 = (kcontrol->private_value >> 8) & 0xff; 385 int left_shift = (kcontrol->private_value >> 16) & 0x0f; 386 int right_shift = (kcontrol->private_value >> 24) & 0x0f; 387 int change; 388 unsigned char val1, val2, oval1, oval2; 389 390 spin_lock_irqsave(&sb->mixer_lock, flags); 391 oval1 = snd_sbmixer_read(sb, reg1); 392 oval2 = snd_sbmixer_read(sb, reg2); 393 val1 = oval1 & ~((1 << left_shift) | (1 << right_shift)); 394 val2 = oval2 & ~((1 << left_shift) | (1 << right_shift)); 395 val1 |= (ucontrol->value.integer.value[0] & 1) << left_shift; 396 val2 |= (ucontrol->value.integer.value[1] & 1) << left_shift; 397 val1 |= (ucontrol->value.integer.value[2] & 1) << right_shift; 398 val2 |= (ucontrol->value.integer.value[3] & 1) << right_shift; 399 change = val1 != oval1 || val2 != oval2; 400 if (change) { 401 snd_sbmixer_write(sb, reg1, val1); 402 snd_sbmixer_write(sb, reg2, val2); 403 } 404 spin_unlock_irqrestore(&sb->mixer_lock, flags); 405 return change; 406 } 407 408 409 /* 410 */ 411 /* 412 */ 413 int snd_sbmixer_add_ctl(sb_t *chip, const char *name, int index, int type, unsigned long value) 414 { 415 static snd_kcontrol_new_t newctls[] = { 416 [SB_MIX_SINGLE] = { 417 .iface = SNDRV_CTL_ELEM_IFACE_MIXER, 418 .info = snd_sbmixer_info_single, 419 .get = snd_sbmixer_get_single, 420 .put = snd_sbmixer_put_single, 421 }, 422 [SB_MIX_DOUBLE] = { 423 .iface = SNDRV_CTL_ELEM_IFACE_MIXER, 424 .info = snd_sbmixer_info_double, 425 .get = snd_sbmixer_get_double, 426 .put = snd_sbmixer_put_double, 427 }, 428 [SB_MIX_INPUT_SW] = { 429 .iface = SNDRV_CTL_ELEM_IFACE_MIXER, 430 .info = snd_sb16mixer_info_input_sw, 431 .get = snd_sb16mixer_get_input_sw, 432 .put = snd_sb16mixer_put_input_sw, 433 }, 434 [SB_MIX_CAPTURE_PRO] = { 435 .iface = SNDRV_CTL_ELEM_IFACE_MIXER, 436 .info = snd_sb8mixer_info_mux, 437 .get = snd_sb8mixer_get_mux, 438 .put = snd_sb8mixer_put_mux, 439 }, 440 [SB_MIX_CAPTURE_DT019X] = { 441 .iface = SNDRV_CTL_ELEM_IFACE_MIXER, 442 .info = snd_dt019x_input_sw_info, 443 .get = snd_dt019x_input_sw_get, 444 .put = snd_dt019x_input_sw_put, 445 }, 446 }; 447 snd_kcontrol_t *ctl; 448 int err; 449 450 ctl = snd_ctl_new1(&newctls[type], chip); 451 if (! ctl) 452 return -ENOMEM; 453 strlcpy(ctl->id.name, name, sizeof(ctl->id.name)); 454 ctl->id.index = index; 455 ctl->private_value = value; 456 if ((err = snd_ctl_add(chip->card, ctl)) < 0) { 457 snd_ctl_free_one(ctl); 458 return err; 459 } 460 return 0; 461 } 462 463 /* 464 * SB 2.0 specific mixer elements 465 */ 466 467 static struct sbmix_elem snd_sb20_ctl_master_play_vol = 468 SB_SINGLE("Master Playback Volume", SB_DSP20_MASTER_DEV, 1, 7); 469 static struct sbmix_elem snd_sb20_ctl_pcm_play_vol = 470 SB_SINGLE("PCM Playback Volume", SB_DSP20_PCM_DEV, 1, 3); 471 static struct sbmix_elem snd_sb20_ctl_synth_play_vol = 472 SB_SINGLE("Synth Playback Volume", SB_DSP20_FM_DEV, 1, 7); 473 static struct sbmix_elem snd_sb20_ctl_cd_play_vol = 474 SB_SINGLE("CD Playback Volume", SB_DSP20_CD_DEV, 1, 7); 475 476 static struct sbmix_elem *snd_sb20_controls[] = { 477 &snd_sb20_ctl_master_play_vol, 478 &snd_sb20_ctl_pcm_play_vol, 479 &snd_sb20_ctl_synth_play_vol, 480 &snd_sb20_ctl_cd_play_vol 481 }; 482 483 static unsigned char snd_sb20_init_values[][2] = { 484 { SB_DSP20_MASTER_DEV, 0 }, 485 { SB_DSP20_FM_DEV, 0 }, 486 }; 487 488 /* 489 * SB Pro specific mixer elements 490 */ 491 static struct sbmix_elem snd_sbpro_ctl_master_play_vol = 492 SB_DOUBLE("Master Playback Volume", SB_DSP_MASTER_DEV, SB_DSP_MASTER_DEV, 5, 1, 7); 493 static struct sbmix_elem snd_sbpro_ctl_pcm_play_vol = 494 SB_DOUBLE("PCM Playback Volume", SB_DSP_PCM_DEV, SB_DSP_PCM_DEV, 5, 1, 7); 495 static struct sbmix_elem snd_sbpro_ctl_pcm_play_filter = 496 SB_SINGLE("PCM Playback Filter", SB_DSP_PLAYBACK_FILT, 5, 1); 497 static struct sbmix_elem snd_sbpro_ctl_synth_play_vol = 498 SB_DOUBLE("Synth Playback Volume", SB_DSP_FM_DEV, SB_DSP_FM_DEV, 5, 1, 7); 499 static struct sbmix_elem snd_sbpro_ctl_cd_play_vol = 500 SB_DOUBLE("CD Playback Volume", SB_DSP_CD_DEV, SB_DSP_CD_DEV, 5, 1, 7); 501 static struct sbmix_elem snd_sbpro_ctl_line_play_vol = 502 SB_DOUBLE("Line Playback Volume", SB_DSP_LINE_DEV, SB_DSP_LINE_DEV, 5, 1, 7); 503 static struct sbmix_elem snd_sbpro_ctl_mic_play_vol = 504 SB_SINGLE("Mic Playback Volume", SB_DSP_MIC_DEV, 1, 3); 505 static struct sbmix_elem snd_sbpro_ctl_capture_source = 506 { 507 .name = "Capture Source", 508 .type = SB_MIX_CAPTURE_PRO 509 }; 510 static struct sbmix_elem snd_sbpro_ctl_capture_filter = 511 SB_SINGLE("Capture Filter", SB_DSP_CAPTURE_FILT, 5, 1); 512 static struct sbmix_elem snd_sbpro_ctl_capture_low_filter = 513 SB_SINGLE("Capture Low-Pass Filter", SB_DSP_CAPTURE_FILT, 3, 1); 514 515 static struct sbmix_elem *snd_sbpro_controls[] = { 516 &snd_sbpro_ctl_master_play_vol, 517 &snd_sbpro_ctl_pcm_play_vol, 518 &snd_sbpro_ctl_pcm_play_filter, 519 &snd_sbpro_ctl_synth_play_vol, 520 &snd_sbpro_ctl_cd_play_vol, 521 &snd_sbpro_ctl_line_play_vol, 522 &snd_sbpro_ctl_mic_play_vol, 523 &snd_sbpro_ctl_capture_source, 524 &snd_sbpro_ctl_capture_filter, 525 &snd_sbpro_ctl_capture_low_filter 526 }; 527 528 static unsigned char snd_sbpro_init_values[][2] = { 529 { SB_DSP_MASTER_DEV, 0 }, 530 { SB_DSP_PCM_DEV, 0 }, 531 { SB_DSP_FM_DEV, 0 }, 532 }; 533 534 /* 535 * SB16 specific mixer elements 536 */ 537 static struct sbmix_elem snd_sb16_ctl_master_play_vol = 538 SB_DOUBLE("Master Playback Volume", SB_DSP4_MASTER_DEV, (SB_DSP4_MASTER_DEV + 1), 3, 3, 31); 539 static struct sbmix_elem snd_sb16_ctl_3d_enhance_switch = 540 SB_SINGLE("3D Enhancement Switch", SB_DSP4_3DSE, 0, 1); 541 static struct sbmix_elem snd_sb16_ctl_tone_bass = 542 SB_DOUBLE("Tone Control - Bass", SB_DSP4_BASS_DEV, (SB_DSP4_BASS_DEV + 1), 4, 4, 15); 543 static struct sbmix_elem snd_sb16_ctl_tone_treble = 544 SB_DOUBLE("Tone Control - Treble", SB_DSP4_TREBLE_DEV, (SB_DSP4_TREBLE_DEV + 1), 4, 4, 15); 545 static struct sbmix_elem snd_sb16_ctl_pcm_play_vol = 546 SB_DOUBLE("PCM Playback Volume", SB_DSP4_PCM_DEV, (SB_DSP4_PCM_DEV + 1), 3, 3, 31); 547 static struct sbmix_elem snd_sb16_ctl_synth_capture_route = 548 SB16_INPUT_SW("Synth Capture Route", SB_DSP4_INPUT_LEFT, SB_DSP4_INPUT_RIGHT, 6, 5); 549 static struct sbmix_elem snd_sb16_ctl_synth_play_vol = 550 SB_DOUBLE("Synth Playback Volume", SB_DSP4_SYNTH_DEV, (SB_DSP4_SYNTH_DEV + 1), 3, 3, 31); 551 static struct sbmix_elem snd_sb16_ctl_cd_capture_route = 552 SB16_INPUT_SW("CD Capture Route", SB_DSP4_INPUT_LEFT, SB_DSP4_INPUT_RIGHT, 2, 1); 553 static struct sbmix_elem snd_sb16_ctl_cd_play_switch = 554 SB_DOUBLE("CD Playback Switch", SB_DSP4_OUTPUT_SW, SB_DSP4_OUTPUT_SW, 2, 1, 1); 555 static struct sbmix_elem snd_sb16_ctl_cd_play_vol = 556 SB_DOUBLE("CD Playback Volume", SB_DSP4_CD_DEV, (SB_DSP4_CD_DEV + 1), 3, 3, 31); 557 static struct sbmix_elem snd_sb16_ctl_line_capture_route = 558 SB16_INPUT_SW("Line Capture Route", SB_DSP4_INPUT_LEFT, SB_DSP4_INPUT_RIGHT, 4, 3); 559 static struct sbmix_elem snd_sb16_ctl_line_play_switch = 560 SB_DOUBLE("Line Playback Switch", SB_DSP4_OUTPUT_SW, SB_DSP4_OUTPUT_SW, 4, 3, 1); 561 static struct sbmix_elem snd_sb16_ctl_line_play_vol = 562 SB_DOUBLE("Line Playback Volume", SB_DSP4_LINE_DEV, (SB_DSP4_LINE_DEV + 1), 3, 3, 31); 563 static struct sbmix_elem snd_sb16_ctl_mic_capture_route = 564 SB16_INPUT_SW("Mic Capture Route", SB_DSP4_INPUT_LEFT, SB_DSP4_INPUT_RIGHT, 0, 0); 565 static struct sbmix_elem snd_sb16_ctl_mic_play_switch = 566 SB_SINGLE("Mic Playback Switch", SB_DSP4_OUTPUT_SW, 0, 1); 567 static struct sbmix_elem snd_sb16_ctl_mic_play_vol = 568 SB_SINGLE("Mic Playback Volume", SB_DSP4_MIC_DEV, 3, 31); 569 static struct sbmix_elem snd_sb16_ctl_pc_speaker_vol = 570 SB_SINGLE("PC Speaker Volume", SB_DSP4_SPEAKER_DEV, 6, 3); 571 static struct sbmix_elem snd_sb16_ctl_capture_vol = 572 SB_DOUBLE("Capture Volume", SB_DSP4_IGAIN_DEV, (SB_DSP4_IGAIN_DEV + 1), 6, 6, 3); 573 static struct sbmix_elem snd_sb16_ctl_play_vol = 574 SB_DOUBLE("Playback Volume", SB_DSP4_OGAIN_DEV, (SB_DSP4_OGAIN_DEV + 1), 6, 6, 3); 575 static struct sbmix_elem snd_sb16_ctl_auto_mic_gain = 576 SB_SINGLE("Mic Auto Gain", SB_DSP4_MIC_AGC, 0, 1); 577 578 static struct sbmix_elem *snd_sb16_controls[] = { 579 &snd_sb16_ctl_master_play_vol, 580 &snd_sb16_ctl_3d_enhance_switch, 581 &snd_sb16_ctl_tone_bass, 582 &snd_sb16_ctl_tone_treble, 583 &snd_sb16_ctl_pcm_play_vol, 584 &snd_sb16_ctl_synth_capture_route, 585 &snd_sb16_ctl_synth_play_vol, 586 &snd_sb16_ctl_cd_capture_route, 587 &snd_sb16_ctl_cd_play_switch, 588 &snd_sb16_ctl_cd_play_vol, 589 &snd_sb16_ctl_line_capture_route, 590 &snd_sb16_ctl_line_play_switch, 591 &snd_sb16_ctl_line_play_vol, 592 &snd_sb16_ctl_mic_capture_route, 593 &snd_sb16_ctl_mic_play_switch, 594 &snd_sb16_ctl_mic_play_vol, 595 &snd_sb16_ctl_pc_speaker_vol, 596 &snd_sb16_ctl_capture_vol, 597 &snd_sb16_ctl_play_vol, 598 &snd_sb16_ctl_auto_mic_gain 599 }; 600 601 static unsigned char snd_sb16_init_values[][2] = { 602 { SB_DSP4_MASTER_DEV + 0, 0 }, 603 { SB_DSP4_MASTER_DEV + 1, 0 }, 604 { SB_DSP4_PCM_DEV + 0, 0 }, 605 { SB_DSP4_PCM_DEV + 1, 0 }, 606 { SB_DSP4_SYNTH_DEV + 0, 0 }, 607 { SB_DSP4_SYNTH_DEV + 1, 0 }, 608 { SB_DSP4_INPUT_LEFT, 0 }, 609 { SB_DSP4_INPUT_RIGHT, 0 }, 610 { SB_DSP4_OUTPUT_SW, 0 }, 611 { SB_DSP4_SPEAKER_DEV, 0 }, 612 }; 613 614 /* 615 * DT019x specific mixer elements 616 */ 617 static struct sbmix_elem snd_dt019x_ctl_master_play_vol = 618 SB_DOUBLE("Master Playback Volume", SB_DT019X_MASTER_DEV, SB_DT019X_MASTER_DEV, 4,0, 15); 619 static struct sbmix_elem snd_dt019x_ctl_pcm_play_vol = 620 SB_DOUBLE("PCM Playback Volume", SB_DT019X_PCM_DEV, SB_DT019X_PCM_DEV, 4,0, 15); 621 static struct sbmix_elem snd_dt019x_ctl_synth_play_vol = 622 SB_DOUBLE("Synth Playback Volume", SB_DT019X_SYNTH_DEV, SB_DT019X_SYNTH_DEV, 4,0, 15); 623 static struct sbmix_elem snd_dt019x_ctl_cd_play_vol = 624 SB_DOUBLE("CD Playback Volume", SB_DT019X_CD_DEV, SB_DT019X_CD_DEV, 4,0, 15); 625 static struct sbmix_elem snd_dt019x_ctl_mic_play_vol = 626 SB_SINGLE("Mic Playback Volume", SB_DT019X_MIC_DEV, 4, 7); 627 static struct sbmix_elem snd_dt019x_ctl_pc_speaker_vol = 628 SB_SINGLE("PC Speaker Volume", SB_DT019X_SPKR_DEV, 0, 7); 629 static struct sbmix_elem snd_dt019x_ctl_line_play_vol = 630 SB_DOUBLE("Line Playback Volume", SB_DT019X_LINE_DEV, SB_DT019X_LINE_DEV, 4,0, 15); 631 static struct sbmix_elem snd_dt019x_ctl_pcm_play_switch = 632 SB_DOUBLE("PCM Playback Switch", SB_DT019X_OUTPUT_SW2, SB_DT019X_OUTPUT_SW2, 2,1, 1); 633 static struct sbmix_elem snd_dt019x_ctl_synth_play_switch = 634 SB_DOUBLE("Synth Playback Switch", SB_DT019X_OUTPUT_SW2, SB_DT019X_OUTPUT_SW2, 4,3, 1); 635 static struct sbmix_elem snd_dt019x_ctl_capture_source = 636 { 637 .name = "Capture Source", 638 .type = SB_MIX_CAPTURE_DT019X 639 }; 640 641 static struct sbmix_elem *snd_dt019x_controls[] = { 642 &snd_dt019x_ctl_master_play_vol, 643 &snd_dt019x_ctl_pcm_play_vol, 644 &snd_dt019x_ctl_synth_play_vol, 645 &snd_dt019x_ctl_cd_play_vol, 646 &snd_dt019x_ctl_mic_play_vol, 647 &snd_dt019x_ctl_pc_speaker_vol, 648 &snd_dt019x_ctl_line_play_vol, 649 &snd_sb16_ctl_mic_play_switch, 650 &snd_sb16_ctl_cd_play_switch, 651 &snd_sb16_ctl_line_play_switch, 652 &snd_dt019x_ctl_pcm_play_switch, 653 &snd_dt019x_ctl_synth_play_switch, 654 &snd_dt019x_ctl_capture_source 655 }; 656 657 static unsigned char snd_dt019x_init_values[][2] = { 658 { SB_DT019X_MASTER_DEV, 0 }, 659 { SB_DT019X_PCM_DEV, 0 }, 660 { SB_DT019X_SYNTH_DEV, 0 }, 661 { SB_DT019X_CD_DEV, 0 }, 662 { SB_DT019X_MIC_DEV, 0 }, /* Includes PC-speaker in high nibble */ 663 { SB_DT019X_LINE_DEV, 0 }, 664 { SB_DSP4_OUTPUT_SW, 0 }, 665 { SB_DT019X_OUTPUT_SW2, 0 }, 666 { SB_DT019X_CAPTURE_SW, 0x06 }, 667 }; 668 669 /* 670 * ALS4000 specific mixer elements 671 */ 672 /* FIXME: SB_ALS4000_MONO_IO_CTRL needs output select ctrl ! */ 673 static struct sbmix_elem snd_als4000_ctl_mono_output_switch = 674 SB_SINGLE("Mono Output Switch", SB_ALS4000_MONO_IO_CTRL, 5, 1); 675 /* FIXME: mono input switch also available on DT019X ? */ 676 static struct sbmix_elem snd_als4000_ctl_mono_input_switch = 677 SB_SINGLE("Mono Input Switch", SB_DT019X_OUTPUT_SW2, 0, 1); 678 static struct sbmix_elem snd_als4000_ctl_mic_20db_boost = 679 SB_SINGLE("Mic Boost (+20dB)", SB_ALS4000_MIC_IN_GAIN, 0, 0x03); 680 static struct sbmix_elem snd_als4000_ctl_mixer_out_to_in = 681 SB_SINGLE("Mixer Out To In", SB_ALS4000_MIC_IN_GAIN, 7, 0x01); 682 /* FIXME: 3D needs much more sophisticated controls, many more features ! */ 683 static struct sbmix_elem snd_als4000_ctl_3d_output_switch = 684 SB_SINGLE("3D Output Switch", SB_ALS4000_3D_SND_FX, 6, 0x01); 685 static struct sbmix_elem snd_als4000_ctl_3d_output_ratio = 686 SB_SINGLE("3D Output Ratio", SB_ALS4000_3D_SND_FX, 0, 0x07); 687 static struct sbmix_elem snd_als4000_ctl_3d_poweroff_switch = 688 SB_SINGLE("3D PowerOff Switch", SB_ALS4000_3D_TIME_DELAY, 4, 0x01); 689 static struct sbmix_elem snd_als4000_ctl_3d_delay = 690 SB_SINGLE("3D Delay", SB_ALS4000_3D_TIME_DELAY, 0, 0x0f); 691 #ifdef NOT_AVAILABLE 692 static struct sbmix_elem snd_als4000_ctl_fmdac = 693 SB_SINGLE("FMDAC Switch (Option ?)", SB_ALS4000_FMDAC, 0, 0x01); 694 static struct sbmix_elem snd_als4000_ctl_qsound = 695 SB_SINGLE("QSound Mode", SB_ALS4000_QSOUND, 1, 0x1f); 696 #endif 697 698 static struct sbmix_elem *snd_als4000_controls[] = { 699 &snd_sb16_ctl_master_play_vol, 700 &snd_dt019x_ctl_pcm_play_switch, 701 &snd_sb16_ctl_pcm_play_vol, 702 &snd_sb16_ctl_synth_capture_route, 703 &snd_dt019x_ctl_synth_play_switch, 704 &snd_sb16_ctl_synth_play_vol, 705 &snd_sb16_ctl_cd_capture_route, 706 &snd_sb16_ctl_cd_play_switch, 707 &snd_sb16_ctl_cd_play_vol, 708 &snd_sb16_ctl_line_capture_route, 709 &snd_sb16_ctl_line_play_switch, 710 &snd_sb16_ctl_line_play_vol, 711 &snd_sb16_ctl_mic_capture_route, 712 &snd_als4000_ctl_mic_20db_boost, 713 &snd_sb16_ctl_auto_mic_gain, 714 &snd_sb16_ctl_mic_play_switch, 715 &snd_sb16_ctl_mic_play_vol, 716 &snd_sb16_ctl_pc_speaker_vol, 717 &snd_sb16_ctl_capture_vol, 718 &snd_sb16_ctl_play_vol, 719 &snd_als4000_ctl_mono_output_switch, 720 &snd_als4000_ctl_mono_input_switch, 721 &snd_als4000_ctl_mixer_out_to_in, 722 &snd_als4000_ctl_3d_output_switch, 723 &snd_als4000_ctl_3d_output_ratio, 724 &snd_als4000_ctl_3d_delay, 725 &snd_als4000_ctl_3d_poweroff_switch, 726 #ifdef NOT_AVAILABLE 727 &snd_als4000_ctl_fmdac, 728 &snd_als4000_ctl_qsound, 729 #endif 730 }; 731 732 static unsigned char snd_als4000_init_values[][2] = { 733 { SB_DSP4_MASTER_DEV + 0, 0 }, 734 { SB_DSP4_MASTER_DEV + 1, 0 }, 735 { SB_DSP4_PCM_DEV + 0, 0 }, 736 { SB_DSP4_PCM_DEV + 1, 0 }, 737 { SB_DSP4_SYNTH_DEV + 0, 0 }, 738 { SB_DSP4_SYNTH_DEV + 1, 0 }, 739 { SB_DSP4_SPEAKER_DEV, 0 }, 740 { SB_DSP4_OUTPUT_SW, 0 }, 741 { SB_DSP4_INPUT_LEFT, 0 }, 742 { SB_DSP4_INPUT_RIGHT, 0 }, 743 { SB_DT019X_OUTPUT_SW2, 0 }, 744 { SB_ALS4000_MIC_IN_GAIN, 0 }, 745 }; 746 747 748 /* 749 */ 750 static int snd_sbmixer_init(sb_t *chip, 751 struct sbmix_elem **controls, 752 int controls_count, 753 unsigned char map[][2], 754 int map_count, 755 char *name) 756 { 757 unsigned long flags; 758 snd_card_t *card = chip->card; 759 int idx, err; 760 761 /* mixer reset */ 762 spin_lock_irqsave(&chip->mixer_lock, flags); 763 snd_sbmixer_write(chip, 0x00, 0x00); 764 spin_unlock_irqrestore(&chip->mixer_lock, flags); 765 766 /* mute and zero volume channels */ 767 for (idx = 0; idx < map_count; idx++) { 768 spin_lock_irqsave(&chip->mixer_lock, flags); 769 snd_sbmixer_write(chip, map[idx][0], map[idx][1]); 770 spin_unlock_irqrestore(&chip->mixer_lock, flags); 771 } 772 773 for (idx = 0; idx < controls_count; idx++) { 774 if ((err = snd_sbmixer_add_ctl_elem(chip, controls[idx])) < 0) 775 return err; 776 } 777 snd_component_add(card, name); 778 strcpy(card->mixername, name); 779 return 0; 780 } 781 782 int snd_sbmixer_new(sb_t *chip) 783 { 784 snd_card_t * card; 785 int err; 786 787 snd_assert(chip != NULL && chip->card != NULL, return -EINVAL); 788 789 card = chip->card; 790 791 switch (chip->hardware) { 792 case SB_HW_10: 793 return 0; /* no mixer chip on SB1.x */ 794 case SB_HW_20: 795 case SB_HW_201: 796 if ((err = snd_sbmixer_init(chip, 797 snd_sb20_controls, 798 ARRAY_SIZE(snd_sb20_controls), 799 snd_sb20_init_values, 800 ARRAY_SIZE(snd_sb20_init_values), 801 "CTL1335")) < 0) 802 return err; 803 break; 804 case SB_HW_PRO: 805 if ((err = snd_sbmixer_init(chip, 806 snd_sbpro_controls, 807 ARRAY_SIZE(snd_sbpro_controls), 808 snd_sbpro_init_values, 809 ARRAY_SIZE(snd_sbpro_init_values), 810 "CTL1345")) < 0) 811 return err; 812 break; 813 case SB_HW_16: 814 case SB_HW_ALS100: 815 if ((err = snd_sbmixer_init(chip, 816 snd_sb16_controls, 817 ARRAY_SIZE(snd_sb16_controls), 818 snd_sb16_init_values, 819 ARRAY_SIZE(snd_sb16_init_values), 820 "CTL1745")) < 0) 821 return err; 822 break; 823 case SB_HW_ALS4000: 824 if ((err = snd_sbmixer_init(chip, 825 snd_als4000_controls, 826 ARRAY_SIZE(snd_als4000_controls), 827 snd_als4000_init_values, 828 ARRAY_SIZE(snd_als4000_init_values), 829 "ALS4000")) < 0) 830 return err; 831 break; 832 case SB_HW_DT019X: 833 if ((err = snd_sbmixer_init(chip, 834 snd_dt019x_controls, 835 ARRAY_SIZE(snd_dt019x_controls), 836 snd_dt019x_init_values, 837 ARRAY_SIZE(snd_dt019x_init_values), 838 "DT019X")) < 0) 839 break; 840 default: 841 strcpy(card->mixername, "???"); 842 } 843 return 0; 844 } 845