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 32void snd_sbmixer_write(struct snd_sb *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 43unsigned char snd_sbmixer_read(struct snd_sb *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 61static int snd_sbmixer_info_single(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *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 72static int snd_sbmixer_get_single(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) 73{ 74 struct snd_sb *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 88static int snd_sbmixer_put_single(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) 89{ 90 struct snd_sb *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 113static int snd_sbmixer_info_double(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *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 124static int snd_sbmixer_get_double(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) 125{ 126 struct snd_sb *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 144static int snd_sbmixer_put_double(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) 145{ 146 struct snd_sb *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 184static int snd_dt019x_input_sw_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *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 199static int snd_dt019x_input_sw_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) 200{ 201 struct snd_sb *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 235static int snd_dt019x_input_sw_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) 236{ 237 struct snd_sb *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 276static int snd_sb8mixer_info_mux(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *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 292static int snd_sb8mixer_get_mux(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) 293{ 294 struct snd_sb *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 315static int snd_sb8mixer_put_mux(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) 316{ 317 struct snd_sb *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 349static int snd_sb16mixer_info_input_sw(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *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 358static int snd_sb16mixer_get_input_sw(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) 359{ 360 struct snd_sb *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 379static int snd_sb16mixer_put_input_sw(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) 380{ 381 struct snd_sb *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 */ 413int snd_sbmixer_add_ctl(struct snd_sb *chip, const char *name, int index, int type, unsigned long value) 414{ 415 static struct snd_kcontrol_new 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 struct snd_kcontrol *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 return err; 458 return 0; 459} 460 461/* 462 * SB 2.0 specific mixer elements 463 */ 464 465static struct sbmix_elem snd_sb20_ctl_master_play_vol = 466 SB_SINGLE("Master Playback Volume", SB_DSP20_MASTER_DEV, 1, 7); 467static struct sbmix_elem snd_sb20_ctl_pcm_play_vol = 468 SB_SINGLE("PCM Playback Volume", SB_DSP20_PCM_DEV, 1, 3); 469static struct sbmix_elem snd_sb20_ctl_synth_play_vol = 470 SB_SINGLE("Synth Playback Volume", SB_DSP20_FM_DEV, 1, 7); 471static struct sbmix_elem snd_sb20_ctl_cd_play_vol = 472 SB_SINGLE("CD Playback Volume", SB_DSP20_CD_DEV, 1, 7); 473 474static struct sbmix_elem *snd_sb20_controls[] = { 475 &snd_sb20_ctl_master_play_vol, 476 &snd_sb20_ctl_pcm_play_vol, 477 &snd_sb20_ctl_synth_play_vol, 478 &snd_sb20_ctl_cd_play_vol 479}; 480 481static unsigned char snd_sb20_init_values[][2] = { 482 { SB_DSP20_MASTER_DEV, 0 }, 483 { SB_DSP20_FM_DEV, 0 }, 484}; 485 486/* 487 * SB Pro specific mixer elements 488 */ 489static struct sbmix_elem snd_sbpro_ctl_master_play_vol = 490 SB_DOUBLE("Master Playback Volume", SB_DSP_MASTER_DEV, SB_DSP_MASTER_DEV, 5, 1, 7); 491static struct sbmix_elem snd_sbpro_ctl_pcm_play_vol = 492 SB_DOUBLE("PCM Playback Volume", SB_DSP_PCM_DEV, SB_DSP_PCM_DEV, 5, 1, 7); 493static struct sbmix_elem snd_sbpro_ctl_pcm_play_filter = 494 SB_SINGLE("PCM Playback Filter", SB_DSP_PLAYBACK_FILT, 5, 1); 495static struct sbmix_elem snd_sbpro_ctl_synth_play_vol = 496 SB_DOUBLE("Synth Playback Volume", SB_DSP_FM_DEV, SB_DSP_FM_DEV, 5, 1, 7); 497static struct sbmix_elem snd_sbpro_ctl_cd_play_vol = 498 SB_DOUBLE("CD Playback Volume", SB_DSP_CD_DEV, SB_DSP_CD_DEV, 5, 1, 7); 499static struct sbmix_elem snd_sbpro_ctl_line_play_vol = 500 SB_DOUBLE("Line Playback Volume", SB_DSP_LINE_DEV, SB_DSP_LINE_DEV, 5, 1, 7); 501static struct sbmix_elem snd_sbpro_ctl_mic_play_vol = 502 SB_SINGLE("Mic Playback Volume", SB_DSP_MIC_DEV, 1, 3); 503static struct sbmix_elem snd_sbpro_ctl_capture_source = 504 { 505 .name = "Capture Source", 506 .type = SB_MIX_CAPTURE_PRO 507 }; 508static struct sbmix_elem snd_sbpro_ctl_capture_filter = 509 SB_SINGLE("Capture Filter", SB_DSP_CAPTURE_FILT, 5, 1); 510static struct sbmix_elem snd_sbpro_ctl_capture_low_filter = 511 SB_SINGLE("Capture Low-Pass Filter", SB_DSP_CAPTURE_FILT, 3, 1); 512 513static struct sbmix_elem *snd_sbpro_controls[] = { 514 &snd_sbpro_ctl_master_play_vol, 515 &snd_sbpro_ctl_pcm_play_vol, 516 &snd_sbpro_ctl_pcm_play_filter, 517 &snd_sbpro_ctl_synth_play_vol, 518 &snd_sbpro_ctl_cd_play_vol, 519 &snd_sbpro_ctl_line_play_vol, 520 &snd_sbpro_ctl_mic_play_vol, 521 &snd_sbpro_ctl_capture_source, 522 &snd_sbpro_ctl_capture_filter, 523 &snd_sbpro_ctl_capture_low_filter 524}; 525 526static unsigned char snd_sbpro_init_values[][2] = { 527 { SB_DSP_MASTER_DEV, 0 }, 528 { SB_DSP_PCM_DEV, 0 }, 529 { SB_DSP_FM_DEV, 0 }, 530}; 531 532/* 533 * SB16 specific mixer elements 534 */ 535static struct sbmix_elem snd_sb16_ctl_master_play_vol = 536 SB_DOUBLE("Master Playback Volume", SB_DSP4_MASTER_DEV, (SB_DSP4_MASTER_DEV + 1), 3, 3, 31); 537static struct sbmix_elem snd_sb16_ctl_3d_enhance_switch = 538 SB_SINGLE("3D Enhancement Switch", SB_DSP4_3DSE, 0, 1); 539static struct sbmix_elem snd_sb16_ctl_tone_bass = 540 SB_DOUBLE("Tone Control - Bass", SB_DSP4_BASS_DEV, (SB_DSP4_BASS_DEV + 1), 4, 4, 15); 541static struct sbmix_elem snd_sb16_ctl_tone_treble = 542 SB_DOUBLE("Tone Control - Treble", SB_DSP4_TREBLE_DEV, (SB_DSP4_TREBLE_DEV + 1), 4, 4, 15); 543static struct sbmix_elem snd_sb16_ctl_pcm_play_vol = 544 SB_DOUBLE("PCM Playback Volume", SB_DSP4_PCM_DEV, (SB_DSP4_PCM_DEV + 1), 3, 3, 31); 545static struct sbmix_elem snd_sb16_ctl_synth_capture_route = 546 SB16_INPUT_SW("Synth Capture Route", SB_DSP4_INPUT_LEFT, SB_DSP4_INPUT_RIGHT, 6, 5); 547static struct sbmix_elem snd_sb16_ctl_synth_play_vol = 548 SB_DOUBLE("Synth Playback Volume", SB_DSP4_SYNTH_DEV, (SB_DSP4_SYNTH_DEV + 1), 3, 3, 31); 549static struct sbmix_elem snd_sb16_ctl_cd_capture_route = 550 SB16_INPUT_SW("CD Capture Route", SB_DSP4_INPUT_LEFT, SB_DSP4_INPUT_RIGHT, 2, 1); 551static struct sbmix_elem snd_sb16_ctl_cd_play_switch = 552 SB_DOUBLE("CD Playback Switch", SB_DSP4_OUTPUT_SW, SB_DSP4_OUTPUT_SW, 2, 1, 1); 553static struct sbmix_elem snd_sb16_ctl_cd_play_vol = 554 SB_DOUBLE("CD Playback Volume", SB_DSP4_CD_DEV, (SB_DSP4_CD_DEV + 1), 3, 3, 31); 555static struct sbmix_elem snd_sb16_ctl_line_capture_route = 556 SB16_INPUT_SW("Line Capture Route", SB_DSP4_INPUT_LEFT, SB_DSP4_INPUT_RIGHT, 4, 3); 557static struct sbmix_elem snd_sb16_ctl_line_play_switch = 558 SB_DOUBLE("Line Playback Switch", SB_DSP4_OUTPUT_SW, SB_DSP4_OUTPUT_SW, 4, 3, 1); 559static struct sbmix_elem snd_sb16_ctl_line_play_vol = 560 SB_DOUBLE("Line Playback Volume", SB_DSP4_LINE_DEV, (SB_DSP4_LINE_DEV + 1), 3, 3, 31); 561static struct sbmix_elem snd_sb16_ctl_mic_capture_route = 562 SB16_INPUT_SW("Mic Capture Route", SB_DSP4_INPUT_LEFT, SB_DSP4_INPUT_RIGHT, 0, 0); 563static struct sbmix_elem snd_sb16_ctl_mic_play_switch = 564 SB_SINGLE("Mic Playback Switch", SB_DSP4_OUTPUT_SW, 0, 1); 565static struct sbmix_elem snd_sb16_ctl_mic_play_vol = 566 SB_SINGLE("Mic Playback Volume", SB_DSP4_MIC_DEV, 3, 31); 567static struct sbmix_elem snd_sb16_ctl_pc_speaker_vol = 568 SB_SINGLE("PC Speaker Volume", SB_DSP4_SPEAKER_DEV, 6, 3); 569static struct sbmix_elem snd_sb16_ctl_capture_vol = 570 SB_DOUBLE("Capture Volume", SB_DSP4_IGAIN_DEV, (SB_DSP4_IGAIN_DEV + 1), 6, 6, 3); 571static struct sbmix_elem snd_sb16_ctl_play_vol = 572 SB_DOUBLE("Playback Volume", SB_DSP4_OGAIN_DEV, (SB_DSP4_OGAIN_DEV + 1), 6, 6, 3); 573static struct sbmix_elem snd_sb16_ctl_auto_mic_gain = 574 SB_SINGLE("Mic Auto Gain", SB_DSP4_MIC_AGC, 0, 1); 575 576static struct sbmix_elem *snd_sb16_controls[] = { 577 &snd_sb16_ctl_master_play_vol, 578 &snd_sb16_ctl_3d_enhance_switch, 579 &snd_sb16_ctl_tone_bass, 580 &snd_sb16_ctl_tone_treble, 581 &snd_sb16_ctl_pcm_play_vol, 582 &snd_sb16_ctl_synth_capture_route, 583 &snd_sb16_ctl_synth_play_vol, 584 &snd_sb16_ctl_cd_capture_route, 585 &snd_sb16_ctl_cd_play_switch, 586 &snd_sb16_ctl_cd_play_vol, 587 &snd_sb16_ctl_line_capture_route, 588 &snd_sb16_ctl_line_play_switch, 589 &snd_sb16_ctl_line_play_vol, 590 &snd_sb16_ctl_mic_capture_route, 591 &snd_sb16_ctl_mic_play_switch, 592 &snd_sb16_ctl_mic_play_vol, 593 &snd_sb16_ctl_pc_speaker_vol, 594 &snd_sb16_ctl_capture_vol, 595 &snd_sb16_ctl_play_vol, 596 &snd_sb16_ctl_auto_mic_gain 597}; 598 599static unsigned char snd_sb16_init_values[][2] = { 600 { SB_DSP4_MASTER_DEV + 0, 0 }, 601 { SB_DSP4_MASTER_DEV + 1, 0 }, 602 { SB_DSP4_PCM_DEV + 0, 0 }, 603 { SB_DSP4_PCM_DEV + 1, 0 }, 604 { SB_DSP4_SYNTH_DEV + 0, 0 }, 605 { SB_DSP4_SYNTH_DEV + 1, 0 }, 606 { SB_DSP4_INPUT_LEFT, 0 }, 607 { SB_DSP4_INPUT_RIGHT, 0 }, 608 { SB_DSP4_OUTPUT_SW, 0 }, 609 { SB_DSP4_SPEAKER_DEV, 0 }, 610}; 611 612/* 613 * DT019x specific mixer elements 614 */ 615static struct sbmix_elem snd_dt019x_ctl_master_play_vol = 616 SB_DOUBLE("Master Playback Volume", SB_DT019X_MASTER_DEV, SB_DT019X_MASTER_DEV, 4,0, 15); 617static struct sbmix_elem snd_dt019x_ctl_pcm_play_vol = 618 SB_DOUBLE("PCM Playback Volume", SB_DT019X_PCM_DEV, SB_DT019X_PCM_DEV, 4,0, 15); 619static struct sbmix_elem snd_dt019x_ctl_synth_play_vol = 620 SB_DOUBLE("Synth Playback Volume", SB_DT019X_SYNTH_DEV, SB_DT019X_SYNTH_DEV, 4,0, 15); 621static struct sbmix_elem snd_dt019x_ctl_cd_play_vol = 622 SB_DOUBLE("CD Playback Volume", SB_DT019X_CD_DEV, SB_DT019X_CD_DEV, 4,0, 15); 623static struct sbmix_elem snd_dt019x_ctl_mic_play_vol = 624 SB_SINGLE("Mic Playback Volume", SB_DT019X_MIC_DEV, 4, 7); 625static struct sbmix_elem snd_dt019x_ctl_pc_speaker_vol = 626 SB_SINGLE("PC Speaker Volume", SB_DT019X_SPKR_DEV, 0, 7); 627static struct sbmix_elem snd_dt019x_ctl_line_play_vol = 628 SB_DOUBLE("Line Playback Volume", SB_DT019X_LINE_DEV, SB_DT019X_LINE_DEV, 4,0, 15); 629static struct sbmix_elem snd_dt019x_ctl_pcm_play_switch = 630 SB_DOUBLE("PCM Playback Switch", SB_DT019X_OUTPUT_SW2, SB_DT019X_OUTPUT_SW2, 2,1, 1); 631static struct sbmix_elem snd_dt019x_ctl_synth_play_switch = 632 SB_DOUBLE("Synth Playback Switch", SB_DT019X_OUTPUT_SW2, SB_DT019X_OUTPUT_SW2, 4,3, 1); 633static struct sbmix_elem snd_dt019x_ctl_capture_source = 634 { 635 .name = "Capture Source", 636 .type = SB_MIX_CAPTURE_DT019X 637 }; 638 639static struct sbmix_elem *snd_dt019x_controls[] = { 640 &snd_dt019x_ctl_master_play_vol, 641 &snd_dt019x_ctl_pcm_play_vol, 642 &snd_dt019x_ctl_synth_play_vol, 643 &snd_dt019x_ctl_cd_play_vol, 644 &snd_dt019x_ctl_mic_play_vol, 645 &snd_dt019x_ctl_pc_speaker_vol, 646 &snd_dt019x_ctl_line_play_vol, 647 &snd_sb16_ctl_mic_play_switch, 648 &snd_sb16_ctl_cd_play_switch, 649 &snd_sb16_ctl_line_play_switch, 650 &snd_dt019x_ctl_pcm_play_switch, 651 &snd_dt019x_ctl_synth_play_switch, 652 &snd_dt019x_ctl_capture_source 653}; 654 655static unsigned char snd_dt019x_init_values[][2] = { 656 { SB_DT019X_MASTER_DEV, 0 }, 657 { SB_DT019X_PCM_DEV, 0 }, 658 { SB_DT019X_SYNTH_DEV, 0 }, 659 { SB_DT019X_CD_DEV, 0 }, 660 { SB_DT019X_MIC_DEV, 0 }, /* Includes PC-speaker in high nibble */ 661 { SB_DT019X_LINE_DEV, 0 }, 662 { SB_DSP4_OUTPUT_SW, 0 }, 663 { SB_DT019X_OUTPUT_SW2, 0 }, 664 { SB_DT019X_CAPTURE_SW, 0x06 }, 665}; 666 667/* 668 * ALS4000 specific mixer elements 669 */ 670static struct sbmix_elem snd_als4000_ctl_master_mono_playback_switch = 671 SB_SINGLE("Master Mono Playback Switch", SB_ALS4000_MONO_IO_CTRL, 5, 1); 672static struct sbmix_elem snd_als4000_ctl_master_mono_capture_route = 673 SB_SINGLE("Master Mono Capture Route", SB_ALS4000_MONO_IO_CTRL, 6, 0x03); 674static struct sbmix_elem snd_als4000_ctl_mono_playback_switch = 675 SB_SINGLE("Mono Playback Switch", SB_DT019X_OUTPUT_SW2, 0, 1); 676static struct sbmix_elem snd_als4000_ctl_mic_20db_boost = 677 SB_SINGLE("Mic Boost (+20dB)", SB_ALS4000_MIC_IN_GAIN, 0, 0x03); 678static struct sbmix_elem snd_als4000_ctl_mixer_loopback = 679 SB_SINGLE("Analog Loopback", SB_ALS4000_MIC_IN_GAIN, 7, 0x01); 680static struct sbmix_elem snd_als4000_3d_control_switch = 681 SB_SINGLE("3D Control - Switch", SB_ALS4000_3D_SND_FX, 6, 0x01); 682static struct sbmix_elem snd_als4000_3d_control_ratio = 683 SB_SINGLE("3D Control - Level", SB_ALS4000_3D_SND_FX, 0, 0x07); 684static struct sbmix_elem snd_als4000_3d_control_freq = 685 SB_SINGLE("3D Control - Freq", SB_ALS4000_3D_SND_FX, 4, 0x03); 686static struct sbmix_elem snd_als4000_3d_control_delay = 687 SB_SINGLE("3D Control - Wide", SB_ALS4000_3D_TIME_DELAY, 0, 0x0f); 688static struct sbmix_elem snd_als4000_3d_control_poweroff_switch = 689 SB_SINGLE("3D PowerOff Switch", SB_ALS4000_3D_TIME_DELAY, 4, 0x01); 690#ifdef NOT_AVAILABLE 691static struct sbmix_elem snd_als4000_ctl_fmdac = 692 SB_SINGLE("FMDAC Switch (Option ?)", SB_ALS4000_FMDAC, 0, 0x01); 693static struct sbmix_elem snd_als4000_ctl_qsound = 694 SB_SINGLE("QSound Mode", SB_ALS4000_QSOUND, 1, 0x1f); 695#endif 696 697static struct sbmix_elem *snd_als4000_controls[] = { 698 &snd_sb16_ctl_master_play_vol, 699 &snd_dt019x_ctl_pcm_play_switch, 700 &snd_sb16_ctl_pcm_play_vol, 701 &snd_sb16_ctl_synth_capture_route, 702 &snd_dt019x_ctl_synth_play_switch, 703 &snd_sb16_ctl_synth_play_vol, 704 &snd_sb16_ctl_cd_capture_route, 705 &snd_sb16_ctl_cd_play_switch, 706 &snd_sb16_ctl_cd_play_vol, 707 &snd_sb16_ctl_line_capture_route, 708 &snd_sb16_ctl_line_play_switch, 709 &snd_sb16_ctl_line_play_vol, 710 &snd_sb16_ctl_mic_capture_route, 711 &snd_als4000_ctl_mic_20db_boost, 712 &snd_sb16_ctl_auto_mic_gain, 713 &snd_sb16_ctl_mic_play_switch, 714 &snd_sb16_ctl_mic_play_vol, 715 &snd_sb16_ctl_pc_speaker_vol, 716 &snd_sb16_ctl_capture_vol, 717 &snd_sb16_ctl_play_vol, 718 &snd_als4000_ctl_master_mono_playback_switch, 719 &snd_als4000_ctl_master_mono_capture_route, 720 &snd_als4000_ctl_mono_playback_switch, 721 &snd_als4000_ctl_mixer_loopback, 722 &snd_als4000_3d_control_switch, 723 &snd_als4000_3d_control_ratio, 724 &snd_als4000_3d_control_freq, 725 &snd_als4000_3d_control_delay, 726 &snd_als4000_3d_control_poweroff_switch, 727#ifdef NOT_AVAILABLE 728 &snd_als4000_ctl_fmdac, 729 &snd_als4000_ctl_qsound, 730#endif 731}; 732 733static unsigned char snd_als4000_init_values[][2] = { 734 { SB_DSP4_MASTER_DEV + 0, 0 }, 735 { SB_DSP4_MASTER_DEV + 1, 0 }, 736 { SB_DSP4_PCM_DEV + 0, 0 }, 737 { SB_DSP4_PCM_DEV + 1, 0 }, 738 { SB_DSP4_SYNTH_DEV + 0, 0 }, 739 { SB_DSP4_SYNTH_DEV + 1, 0 }, 740 { SB_DSP4_SPEAKER_DEV, 0 }, 741 { SB_DSP4_OUTPUT_SW, 0 }, 742 { SB_DSP4_INPUT_LEFT, 0 }, 743 { SB_DSP4_INPUT_RIGHT, 0 }, 744 { SB_DT019X_OUTPUT_SW2, 0 }, 745 { SB_ALS4000_MIC_IN_GAIN, 0 }, 746}; 747 748 749/* 750 */ 751static int snd_sbmixer_init(struct snd_sb *chip, 752 struct sbmix_elem **controls, 753 int controls_count, 754 unsigned char map[][2], 755 int map_count, 756 char *name) 757{ 758 unsigned long flags; 759 struct snd_card *card = chip->card; 760 int idx, err; 761 762 /* mixer reset */ 763 spin_lock_irqsave(&chip->mixer_lock, flags); 764 snd_sbmixer_write(chip, 0x00, 0x00); 765 spin_unlock_irqrestore(&chip->mixer_lock, flags); 766 767 /* mute and zero volume channels */ 768 for (idx = 0; idx < map_count; idx++) { 769 spin_lock_irqsave(&chip->mixer_lock, flags); 770 snd_sbmixer_write(chip, map[idx][0], map[idx][1]); 771 spin_unlock_irqrestore(&chip->mixer_lock, flags); 772 } 773 774 for (idx = 0; idx < controls_count; idx++) { 775 if ((err = snd_sbmixer_add_ctl_elem(chip, controls[idx])) < 0) 776 return err; 777 } 778 snd_component_add(card, name); 779 strcpy(card->mixername, name); 780 return 0; 781} 782 783int snd_sbmixer_new(struct snd_sb *chip) 784{ 785 struct snd_card *card; 786 int err; 787 788 snd_assert(chip != NULL && chip->card != NULL, return -EINVAL); 789 790 card = chip->card; 791 792 switch (chip->hardware) { 793 case SB_HW_10: 794 return 0; /* no mixer chip on SB1.x */ 795 case SB_HW_20: 796 case SB_HW_201: 797 if ((err = snd_sbmixer_init(chip, 798 snd_sb20_controls, 799 ARRAY_SIZE(snd_sb20_controls), 800 snd_sb20_init_values, 801 ARRAY_SIZE(snd_sb20_init_values), 802 "CTL1335")) < 0) 803 return err; 804 break; 805 case SB_HW_PRO: 806 if ((err = snd_sbmixer_init(chip, 807 snd_sbpro_controls, 808 ARRAY_SIZE(snd_sbpro_controls), 809 snd_sbpro_init_values, 810 ARRAY_SIZE(snd_sbpro_init_values), 811 "CTL1345")) < 0) 812 return err; 813 break; 814 case SB_HW_16: 815 case SB_HW_ALS100: 816 if ((err = snd_sbmixer_init(chip, 817 snd_sb16_controls, 818 ARRAY_SIZE(snd_sb16_controls), 819 snd_sb16_init_values, 820 ARRAY_SIZE(snd_sb16_init_values), 821 "CTL1745")) < 0) 822 return err; 823 break; 824 case SB_HW_ALS4000: 825 if ((err = snd_sbmixer_init(chip, 826 snd_als4000_controls, 827 ARRAY_SIZE(snd_als4000_controls), 828 snd_als4000_init_values, 829 ARRAY_SIZE(snd_als4000_init_values), 830 "ALS4000")) < 0) 831 return err; 832 break; 833 case SB_HW_DT019X: 834 if ((err = snd_sbmixer_init(chip, 835 snd_dt019x_controls, 836 ARRAY_SIZE(snd_dt019x_controls), 837 snd_dt019x_init_values, 838 ARRAY_SIZE(snd_dt019x_init_values), 839 "DT019X")) < 0) 840 break; 841 default: 842 strcpy(card->mixername, "???"); 843 } 844 return 0; 845} 846 847#ifdef CONFIG_PM 848static unsigned char sb20_saved_regs[] = { 849 SB_DSP20_MASTER_DEV, 850 SB_DSP20_PCM_DEV, 851 SB_DSP20_FM_DEV, 852 SB_DSP20_CD_DEV, 853}; 854 855static unsigned char sbpro_saved_regs[] = { 856 SB_DSP_MASTER_DEV, 857 SB_DSP_PCM_DEV, 858 SB_DSP_PLAYBACK_FILT, 859 SB_DSP_FM_DEV, 860 SB_DSP_CD_DEV, 861 SB_DSP_LINE_DEV, 862 SB_DSP_MIC_DEV, 863 SB_DSP_CAPTURE_SOURCE, 864 SB_DSP_CAPTURE_FILT, 865}; 866 867static unsigned char sb16_saved_regs[] = { 868 SB_DSP4_MASTER_DEV, SB_DSP4_MASTER_DEV + 1, 869 SB_DSP4_3DSE, 870 SB_DSP4_BASS_DEV, SB_DSP4_BASS_DEV + 1, 871 SB_DSP4_TREBLE_DEV, SB_DSP4_TREBLE_DEV + 1, 872 SB_DSP4_PCM_DEV, SB_DSP4_PCM_DEV + 1, 873 SB_DSP4_INPUT_LEFT, SB_DSP4_INPUT_RIGHT, 874 SB_DSP4_SYNTH_DEV, SB_DSP4_SYNTH_DEV + 1, 875 SB_DSP4_OUTPUT_SW, 876 SB_DSP4_CD_DEV, SB_DSP4_CD_DEV + 1, 877 SB_DSP4_LINE_DEV, SB_DSP4_LINE_DEV + 1, 878 SB_DSP4_MIC_DEV, 879 SB_DSP4_SPEAKER_DEV, 880 SB_DSP4_IGAIN_DEV, SB_DSP4_IGAIN_DEV + 1, 881 SB_DSP4_OGAIN_DEV, SB_DSP4_OGAIN_DEV + 1, 882 SB_DSP4_MIC_AGC 883}; 884 885static unsigned char dt019x_saved_regs[] = { 886 SB_DT019X_MASTER_DEV, 887 SB_DT019X_PCM_DEV, 888 SB_DT019X_SYNTH_DEV, 889 SB_DT019X_CD_DEV, 890 SB_DT019X_MIC_DEV, 891 SB_DT019X_SPKR_DEV, 892 SB_DT019X_LINE_DEV, 893 SB_DSP4_OUTPUT_SW, 894 SB_DT019X_OUTPUT_SW2, 895 SB_DT019X_CAPTURE_SW, 896}; 897 898static unsigned char als4000_saved_regs[] = { 899 SB_DSP4_MASTER_DEV, SB_DSP4_MASTER_DEV + 1, 900 SB_DSP4_OUTPUT_SW, 901 SB_DSP4_PCM_DEV, SB_DSP4_PCM_DEV + 1, 902 SB_DSP4_INPUT_LEFT, SB_DSP4_INPUT_RIGHT, 903 SB_DSP4_SYNTH_DEV, SB_DSP4_SYNTH_DEV + 1, 904 SB_DSP4_CD_DEV, SB_DSP4_CD_DEV + 1, 905 SB_DSP4_MIC_AGC, 906 SB_DSP4_MIC_DEV, 907 SB_DSP4_SPEAKER_DEV, 908 SB_DSP4_IGAIN_DEV, SB_DSP4_IGAIN_DEV + 1, 909 SB_DSP4_OGAIN_DEV, SB_DSP4_OGAIN_DEV + 1, 910 SB_DT019X_OUTPUT_SW2, 911 SB_ALS4000_MONO_IO_CTRL, 912 SB_ALS4000_MIC_IN_GAIN, 913 SB_ALS4000_3D_SND_FX, 914 SB_ALS4000_3D_TIME_DELAY, 915}; 916 917static void save_mixer(struct snd_sb *chip, unsigned char *regs, int num_regs) 918{ 919 unsigned char *val = chip->saved_regs; 920 snd_assert(num_regs > ARRAY_SIZE(chip->saved_regs), return); 921 for (; num_regs; num_regs--) 922 *val++ = snd_sbmixer_read(chip, *regs++); 923} 924 925static void restore_mixer(struct snd_sb *chip, unsigned char *regs, int num_regs) 926{ 927 unsigned char *val = chip->saved_regs; 928 snd_assert(num_regs > ARRAY_SIZE(chip->saved_regs), return); 929 for (; num_regs; num_regs--) 930 snd_sbmixer_write(chip, *regs++, *val++); 931} 932 933void snd_sbmixer_suspend(struct snd_sb *chip) 934{ 935 switch (chip->hardware) { 936 case SB_HW_20: 937 case SB_HW_201: 938 save_mixer(chip, sb20_saved_regs, ARRAY_SIZE(sb20_saved_regs)); 939 break; 940 case SB_HW_PRO: 941 save_mixer(chip, sbpro_saved_regs, ARRAY_SIZE(sbpro_saved_regs)); 942 break; 943 case SB_HW_16: 944 case SB_HW_ALS100: 945 save_mixer(chip, sb16_saved_regs, ARRAY_SIZE(sb16_saved_regs)); 946 break; 947 case SB_HW_ALS4000: 948 save_mixer(chip, als4000_saved_regs, ARRAY_SIZE(als4000_saved_regs)); 949 break; 950 case SB_HW_DT019X: 951 save_mixer(chip, dt019x_saved_regs, ARRAY_SIZE(dt019x_saved_regs)); 952 break; 953 default: 954 break; 955 } 956} 957 958void snd_sbmixer_resume(struct snd_sb *chip) 959{ 960 switch (chip->hardware) { 961 case SB_HW_20: 962 case SB_HW_201: 963 restore_mixer(chip, sb20_saved_regs, ARRAY_SIZE(sb20_saved_regs)); 964 break; 965 case SB_HW_PRO: 966 restore_mixer(chip, sbpro_saved_regs, ARRAY_SIZE(sbpro_saved_regs)); 967 break; 968 case SB_HW_16: 969 case SB_HW_ALS100: 970 restore_mixer(chip, sb16_saved_regs, ARRAY_SIZE(sb16_saved_regs)); 971 break; 972 case SB_HW_ALS4000: 973 restore_mixer(chip, als4000_saved_regs, ARRAY_SIZE(als4000_saved_regs)); 974 break; 975 case SB_HW_DT019X: 976 restore_mixer(chip, dt019x_saved_regs, ARRAY_SIZE(dt019x_saved_regs)); 977 break; 978 default: 979 break; 980 } 981} 982#endif 983