1 // SPDX-License-Identifier: GPL-2.0-or-later 2 /* 3 * Copyright (c) by Jaroslav Kysela <perex@perex.cz> 4 * Routines for Sound Blaster mixer control 5 */ 6 7 #include <linux/io.h> 8 #include <linux/delay.h> 9 #include <linux/time.h> 10 #include <sound/core.h> 11 #include <sound/sb.h> 12 #include <sound/control.h> 13 14 #undef IO_DEBUG 15 16 void snd_sbmixer_write(struct snd_sb *chip, unsigned char reg, unsigned char data) 17 { 18 outb(reg, SBP(chip, MIXER_ADDR)); 19 udelay(10); 20 outb(data, SBP(chip, MIXER_DATA)); 21 udelay(10); 22 #ifdef IO_DEBUG 23 snd_printk(KERN_DEBUG "mixer_write 0x%x 0x%x\n", reg, data); 24 #endif 25 } 26 27 unsigned char snd_sbmixer_read(struct snd_sb *chip, unsigned char reg) 28 { 29 unsigned char result; 30 31 outb(reg, SBP(chip, MIXER_ADDR)); 32 udelay(10); 33 result = inb(SBP(chip, MIXER_DATA)); 34 udelay(10); 35 #ifdef IO_DEBUG 36 snd_printk(KERN_DEBUG "mixer_read 0x%x 0x%x\n", reg, result); 37 #endif 38 return result; 39 } 40 41 /* 42 * Single channel mixer element 43 */ 44 45 static int snd_sbmixer_info_single(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo) 46 { 47 int mask = (kcontrol->private_value >> 24) & 0xff; 48 49 uinfo->type = mask == 1 ? SNDRV_CTL_ELEM_TYPE_BOOLEAN : SNDRV_CTL_ELEM_TYPE_INTEGER; 50 uinfo->count = 1; 51 uinfo->value.integer.min = 0; 52 uinfo->value.integer.max = mask; 53 return 0; 54 } 55 56 static int snd_sbmixer_get_single(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) 57 { 58 struct snd_sb *sb = snd_kcontrol_chip(kcontrol); 59 unsigned long flags; 60 int reg = kcontrol->private_value & 0xff; 61 int shift = (kcontrol->private_value >> 16) & 0xff; 62 int mask = (kcontrol->private_value >> 24) & 0xff; 63 unsigned char val; 64 65 spin_lock_irqsave(&sb->mixer_lock, flags); 66 val = (snd_sbmixer_read(sb, reg) >> shift) & mask; 67 spin_unlock_irqrestore(&sb->mixer_lock, flags); 68 ucontrol->value.integer.value[0] = val; 69 return 0; 70 } 71 72 static int snd_sbmixer_put_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) & 0x07; 78 int mask = (kcontrol->private_value >> 24) & 0xff; 79 int change; 80 unsigned char val, oval; 81 82 val = (ucontrol->value.integer.value[0] & mask) << shift; 83 spin_lock_irqsave(&sb->mixer_lock, flags); 84 oval = snd_sbmixer_read(sb, reg); 85 val = (oval & ~(mask << shift)) | val; 86 change = val != oval; 87 if (change) 88 snd_sbmixer_write(sb, reg, val); 89 spin_unlock_irqrestore(&sb->mixer_lock, flags); 90 return change; 91 } 92 93 /* 94 * Double channel mixer element 95 */ 96 97 static int snd_sbmixer_info_double(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo) 98 { 99 int mask = (kcontrol->private_value >> 24) & 0xff; 100 101 uinfo->type = mask == 1 ? SNDRV_CTL_ELEM_TYPE_BOOLEAN : SNDRV_CTL_ELEM_TYPE_INTEGER; 102 uinfo->count = 2; 103 uinfo->value.integer.min = 0; 104 uinfo->value.integer.max = mask; 105 return 0; 106 } 107 108 static int snd_sbmixer_get_double(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) 109 { 110 struct snd_sb *sb = snd_kcontrol_chip(kcontrol); 111 unsigned long flags; 112 int left_reg = kcontrol->private_value & 0xff; 113 int right_reg = (kcontrol->private_value >> 8) & 0xff; 114 int left_shift = (kcontrol->private_value >> 16) & 0x07; 115 int right_shift = (kcontrol->private_value >> 19) & 0x07; 116 int mask = (kcontrol->private_value >> 24) & 0xff; 117 unsigned char left, right; 118 119 spin_lock_irqsave(&sb->mixer_lock, flags); 120 left = (snd_sbmixer_read(sb, left_reg) >> left_shift) & mask; 121 right = (snd_sbmixer_read(sb, right_reg) >> right_shift) & mask; 122 spin_unlock_irqrestore(&sb->mixer_lock, flags); 123 ucontrol->value.integer.value[0] = left; 124 ucontrol->value.integer.value[1] = right; 125 return 0; 126 } 127 128 static int snd_sbmixer_put_double(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) 129 { 130 struct snd_sb *sb = snd_kcontrol_chip(kcontrol); 131 unsigned long flags; 132 int left_reg = kcontrol->private_value & 0xff; 133 int right_reg = (kcontrol->private_value >> 8) & 0xff; 134 int left_shift = (kcontrol->private_value >> 16) & 0x07; 135 int right_shift = (kcontrol->private_value >> 19) & 0x07; 136 int mask = (kcontrol->private_value >> 24) & 0xff; 137 int change; 138 unsigned char left, right, oleft, oright; 139 140 left = (ucontrol->value.integer.value[0] & mask) << left_shift; 141 right = (ucontrol->value.integer.value[1] & mask) << right_shift; 142 spin_lock_irqsave(&sb->mixer_lock, flags); 143 if (left_reg == right_reg) { 144 oleft = snd_sbmixer_read(sb, left_reg); 145 left = (oleft & ~((mask << left_shift) | (mask << right_shift))) | left | right; 146 change = left != oleft; 147 if (change) 148 snd_sbmixer_write(sb, left_reg, left); 149 } else { 150 oleft = snd_sbmixer_read(sb, left_reg); 151 oright = snd_sbmixer_read(sb, right_reg); 152 left = (oleft & ~(mask << left_shift)) | left; 153 right = (oright & ~(mask << right_shift)) | right; 154 change = left != oleft || right != oright; 155 if (change) { 156 snd_sbmixer_write(sb, left_reg, left); 157 snd_sbmixer_write(sb, right_reg, right); 158 } 159 } 160 spin_unlock_irqrestore(&sb->mixer_lock, flags); 161 return change; 162 } 163 164 /* 165 * DT-019x / ALS-007 capture/input switch 166 */ 167 168 static int snd_dt019x_input_sw_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo) 169 { 170 static const char * const texts[5] = { 171 "CD", "Mic", "Line", "Synth", "Master" 172 }; 173 174 return snd_ctl_enum_info(uinfo, 1, 5, texts); 175 } 176 177 static int snd_dt019x_input_sw_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) 178 { 179 struct snd_sb *sb = snd_kcontrol_chip(kcontrol); 180 unsigned long flags; 181 unsigned char oval; 182 183 spin_lock_irqsave(&sb->mixer_lock, flags); 184 oval = snd_sbmixer_read(sb, SB_DT019X_CAPTURE_SW); 185 spin_unlock_irqrestore(&sb->mixer_lock, flags); 186 switch (oval & 0x07) { 187 case SB_DT019X_CAP_CD: 188 ucontrol->value.enumerated.item[0] = 0; 189 break; 190 case SB_DT019X_CAP_MIC: 191 ucontrol->value.enumerated.item[0] = 1; 192 break; 193 case SB_DT019X_CAP_LINE: 194 ucontrol->value.enumerated.item[0] = 2; 195 break; 196 case SB_DT019X_CAP_MAIN: 197 ucontrol->value.enumerated.item[0] = 4; 198 break; 199 /* To record the synth on these cards you must record the main. */ 200 /* Thus SB_DT019X_CAP_SYNTH == SB_DT019X_CAP_MAIN and would cause */ 201 /* duplicate case labels if left uncommented. */ 202 /* case SB_DT019X_CAP_SYNTH: 203 * ucontrol->value.enumerated.item[0] = 3; 204 * break; 205 */ 206 default: 207 ucontrol->value.enumerated.item[0] = 4; 208 break; 209 } 210 return 0; 211 } 212 213 static int snd_dt019x_input_sw_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) 214 { 215 struct snd_sb *sb = snd_kcontrol_chip(kcontrol); 216 unsigned long flags; 217 int change; 218 unsigned char nval, oval; 219 220 if (ucontrol->value.enumerated.item[0] > 4) 221 return -EINVAL; 222 switch (ucontrol->value.enumerated.item[0]) { 223 case 0: 224 nval = SB_DT019X_CAP_CD; 225 break; 226 case 1: 227 nval = SB_DT019X_CAP_MIC; 228 break; 229 case 2: 230 nval = SB_DT019X_CAP_LINE; 231 break; 232 case 3: 233 nval = SB_DT019X_CAP_SYNTH; 234 break; 235 case 4: 236 nval = SB_DT019X_CAP_MAIN; 237 break; 238 default: 239 nval = SB_DT019X_CAP_MAIN; 240 } 241 spin_lock_irqsave(&sb->mixer_lock, flags); 242 oval = snd_sbmixer_read(sb, SB_DT019X_CAPTURE_SW); 243 change = nval != oval; 244 if (change) 245 snd_sbmixer_write(sb, SB_DT019X_CAPTURE_SW, nval); 246 spin_unlock_irqrestore(&sb->mixer_lock, flags); 247 return change; 248 } 249 250 /* 251 * ALS4000 mono recording control switch 252 */ 253 254 static int snd_als4k_mono_capture_route_info(struct snd_kcontrol *kcontrol, 255 struct snd_ctl_elem_info *uinfo) 256 { 257 static const char * const texts[3] = { 258 "L chan only", "R chan only", "L ch/2 + R ch/2" 259 }; 260 261 return snd_ctl_enum_info(uinfo, 1, 3, texts); 262 } 263 264 static int snd_als4k_mono_capture_route_get(struct snd_kcontrol *kcontrol, 265 struct snd_ctl_elem_value *ucontrol) 266 { 267 struct snd_sb *sb = snd_kcontrol_chip(kcontrol); 268 unsigned long flags; 269 unsigned char oval; 270 271 spin_lock_irqsave(&sb->mixer_lock, flags); 272 oval = snd_sbmixer_read(sb, SB_ALS4000_MONO_IO_CTRL); 273 spin_unlock_irqrestore(&sb->mixer_lock, flags); 274 oval >>= 6; 275 if (oval > 2) 276 oval = 2; 277 278 ucontrol->value.enumerated.item[0] = oval; 279 return 0; 280 } 281 282 static int snd_als4k_mono_capture_route_put(struct snd_kcontrol *kcontrol, 283 struct snd_ctl_elem_value *ucontrol) 284 { 285 struct snd_sb *sb = snd_kcontrol_chip(kcontrol); 286 unsigned long flags; 287 int change; 288 unsigned char nval, oval; 289 290 if (ucontrol->value.enumerated.item[0] > 2) 291 return -EINVAL; 292 spin_lock_irqsave(&sb->mixer_lock, flags); 293 oval = snd_sbmixer_read(sb, SB_ALS4000_MONO_IO_CTRL); 294 295 nval = (oval & ~(3 << 6)) 296 | (ucontrol->value.enumerated.item[0] << 6); 297 change = nval != oval; 298 if (change) 299 snd_sbmixer_write(sb, SB_ALS4000_MONO_IO_CTRL, nval); 300 spin_unlock_irqrestore(&sb->mixer_lock, flags); 301 return change; 302 } 303 304 /* 305 * SBPRO input multiplexer 306 */ 307 308 static int snd_sb8mixer_info_mux(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo) 309 { 310 static const char * const texts[3] = { 311 "Mic", "CD", "Line" 312 }; 313 314 return snd_ctl_enum_info(uinfo, 1, 3, texts); 315 } 316 317 318 static int snd_sb8mixer_get_mux(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) 319 { 320 struct snd_sb *sb = snd_kcontrol_chip(kcontrol); 321 unsigned long flags; 322 unsigned char oval; 323 324 spin_lock_irqsave(&sb->mixer_lock, flags); 325 oval = snd_sbmixer_read(sb, SB_DSP_CAPTURE_SOURCE); 326 spin_unlock_irqrestore(&sb->mixer_lock, flags); 327 switch ((oval >> 0x01) & 0x03) { 328 case SB_DSP_MIXS_CD: 329 ucontrol->value.enumerated.item[0] = 1; 330 break; 331 case SB_DSP_MIXS_LINE: 332 ucontrol->value.enumerated.item[0] = 2; 333 break; 334 default: 335 ucontrol->value.enumerated.item[0] = 0; 336 break; 337 } 338 return 0; 339 } 340 341 static int snd_sb8mixer_put_mux(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) 342 { 343 struct snd_sb *sb = snd_kcontrol_chip(kcontrol); 344 unsigned long flags; 345 int change; 346 unsigned char nval, oval; 347 348 if (ucontrol->value.enumerated.item[0] > 2) 349 return -EINVAL; 350 switch (ucontrol->value.enumerated.item[0]) { 351 case 1: 352 nval = SB_DSP_MIXS_CD; 353 break; 354 case 2: 355 nval = SB_DSP_MIXS_LINE; 356 break; 357 default: 358 nval = SB_DSP_MIXS_MIC; 359 } 360 nval <<= 1; 361 spin_lock_irqsave(&sb->mixer_lock, flags); 362 oval = snd_sbmixer_read(sb, SB_DSP_CAPTURE_SOURCE); 363 nval |= oval & ~0x06; 364 change = nval != oval; 365 if (change) 366 snd_sbmixer_write(sb, SB_DSP_CAPTURE_SOURCE, nval); 367 spin_unlock_irqrestore(&sb->mixer_lock, flags); 368 return change; 369 } 370 371 /* 372 * SB16 input switch 373 */ 374 375 static int snd_sb16mixer_info_input_sw(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo) 376 { 377 uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN; 378 uinfo->count = 4; 379 uinfo->value.integer.min = 0; 380 uinfo->value.integer.max = 1; 381 return 0; 382 } 383 384 static int snd_sb16mixer_get_input_sw(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) 385 { 386 struct snd_sb *sb = snd_kcontrol_chip(kcontrol); 387 unsigned long flags; 388 int reg1 = kcontrol->private_value & 0xff; 389 int reg2 = (kcontrol->private_value >> 8) & 0xff; 390 int left_shift = (kcontrol->private_value >> 16) & 0x0f; 391 int right_shift = (kcontrol->private_value >> 24) & 0x0f; 392 unsigned char val1, val2; 393 394 spin_lock_irqsave(&sb->mixer_lock, flags); 395 val1 = snd_sbmixer_read(sb, reg1); 396 val2 = snd_sbmixer_read(sb, reg2); 397 spin_unlock_irqrestore(&sb->mixer_lock, flags); 398 ucontrol->value.integer.value[0] = (val1 >> left_shift) & 0x01; 399 ucontrol->value.integer.value[1] = (val2 >> left_shift) & 0x01; 400 ucontrol->value.integer.value[2] = (val1 >> right_shift) & 0x01; 401 ucontrol->value.integer.value[3] = (val2 >> right_shift) & 0x01; 402 return 0; 403 } 404 405 static int snd_sb16mixer_put_input_sw(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) 406 { 407 struct snd_sb *sb = snd_kcontrol_chip(kcontrol); 408 unsigned long flags; 409 int reg1 = kcontrol->private_value & 0xff; 410 int reg2 = (kcontrol->private_value >> 8) & 0xff; 411 int left_shift = (kcontrol->private_value >> 16) & 0x0f; 412 int right_shift = (kcontrol->private_value >> 24) & 0x0f; 413 int change; 414 unsigned char val1, val2, oval1, oval2; 415 416 spin_lock_irqsave(&sb->mixer_lock, flags); 417 oval1 = snd_sbmixer_read(sb, reg1); 418 oval2 = snd_sbmixer_read(sb, reg2); 419 val1 = oval1 & ~((1 << left_shift) | (1 << right_shift)); 420 val2 = oval2 & ~((1 << left_shift) | (1 << right_shift)); 421 val1 |= (ucontrol->value.integer.value[0] & 1) << left_shift; 422 val2 |= (ucontrol->value.integer.value[1] & 1) << left_shift; 423 val1 |= (ucontrol->value.integer.value[2] & 1) << right_shift; 424 val2 |= (ucontrol->value.integer.value[3] & 1) << right_shift; 425 change = val1 != oval1 || val2 != oval2; 426 if (change) { 427 snd_sbmixer_write(sb, reg1, val1); 428 snd_sbmixer_write(sb, reg2, val2); 429 } 430 spin_unlock_irqrestore(&sb->mixer_lock, flags); 431 return change; 432 } 433 434 435 /* 436 */ 437 /* 438 */ 439 int snd_sbmixer_add_ctl(struct snd_sb *chip, const char *name, int index, int type, unsigned long value) 440 { 441 static const struct snd_kcontrol_new newctls[] = { 442 [SB_MIX_SINGLE] = { 443 .iface = SNDRV_CTL_ELEM_IFACE_MIXER, 444 .info = snd_sbmixer_info_single, 445 .get = snd_sbmixer_get_single, 446 .put = snd_sbmixer_put_single, 447 }, 448 [SB_MIX_DOUBLE] = { 449 .iface = SNDRV_CTL_ELEM_IFACE_MIXER, 450 .info = snd_sbmixer_info_double, 451 .get = snd_sbmixer_get_double, 452 .put = snd_sbmixer_put_double, 453 }, 454 [SB_MIX_INPUT_SW] = { 455 .iface = SNDRV_CTL_ELEM_IFACE_MIXER, 456 .info = snd_sb16mixer_info_input_sw, 457 .get = snd_sb16mixer_get_input_sw, 458 .put = snd_sb16mixer_put_input_sw, 459 }, 460 [SB_MIX_CAPTURE_PRO] = { 461 .iface = SNDRV_CTL_ELEM_IFACE_MIXER, 462 .info = snd_sb8mixer_info_mux, 463 .get = snd_sb8mixer_get_mux, 464 .put = snd_sb8mixer_put_mux, 465 }, 466 [SB_MIX_CAPTURE_DT019X] = { 467 .iface = SNDRV_CTL_ELEM_IFACE_MIXER, 468 .info = snd_dt019x_input_sw_info, 469 .get = snd_dt019x_input_sw_get, 470 .put = snd_dt019x_input_sw_put, 471 }, 472 [SB_MIX_MONO_CAPTURE_ALS4K] = { 473 .iface = SNDRV_CTL_ELEM_IFACE_MIXER, 474 .info = snd_als4k_mono_capture_route_info, 475 .get = snd_als4k_mono_capture_route_get, 476 .put = snd_als4k_mono_capture_route_put, 477 }, 478 }; 479 struct snd_kcontrol *ctl; 480 int err; 481 482 ctl = snd_ctl_new1(&newctls[type], chip); 483 if (! ctl) 484 return -ENOMEM; 485 strlcpy(ctl->id.name, name, sizeof(ctl->id.name)); 486 ctl->id.index = index; 487 ctl->private_value = value; 488 if ((err = snd_ctl_add(chip->card, ctl)) < 0) 489 return err; 490 return 0; 491 } 492 493 /* 494 * SB 2.0 specific mixer elements 495 */ 496 497 static const struct sbmix_elem snd_sb20_controls[] = { 498 SB_SINGLE("Master Playback Volume", SB_DSP20_MASTER_DEV, 1, 7), 499 SB_SINGLE("PCM Playback Volume", SB_DSP20_PCM_DEV, 1, 3), 500 SB_SINGLE("Synth Playback Volume", SB_DSP20_FM_DEV, 1, 7), 501 SB_SINGLE("CD Playback Volume", SB_DSP20_CD_DEV, 1, 7) 502 }; 503 504 static const unsigned char snd_sb20_init_values[][2] = { 505 { SB_DSP20_MASTER_DEV, 0 }, 506 { SB_DSP20_FM_DEV, 0 }, 507 }; 508 509 /* 510 * SB Pro specific mixer elements 511 */ 512 static const struct sbmix_elem snd_sbpro_controls[] = { 513 SB_DOUBLE("Master Playback Volume", 514 SB_DSP_MASTER_DEV, SB_DSP_MASTER_DEV, 5, 1, 7), 515 SB_DOUBLE("PCM Playback Volume", 516 SB_DSP_PCM_DEV, SB_DSP_PCM_DEV, 5, 1, 7), 517 SB_SINGLE("PCM Playback Filter", SB_DSP_PLAYBACK_FILT, 5, 1), 518 SB_DOUBLE("Synth Playback Volume", 519 SB_DSP_FM_DEV, SB_DSP_FM_DEV, 5, 1, 7), 520 SB_DOUBLE("CD Playback Volume", SB_DSP_CD_DEV, SB_DSP_CD_DEV, 5, 1, 7), 521 SB_DOUBLE("Line Playback Volume", 522 SB_DSP_LINE_DEV, SB_DSP_LINE_DEV, 5, 1, 7), 523 SB_SINGLE("Mic Playback Volume", SB_DSP_MIC_DEV, 1, 3), 524 { 525 .name = "Capture Source", 526 .type = SB_MIX_CAPTURE_PRO 527 }, 528 SB_SINGLE("Capture Filter", SB_DSP_CAPTURE_FILT, 5, 1), 529 SB_SINGLE("Capture Low-Pass Filter", SB_DSP_CAPTURE_FILT, 3, 1) 530 }; 531 532 static const unsigned char snd_sbpro_init_values[][2] = { 533 { SB_DSP_MASTER_DEV, 0 }, 534 { SB_DSP_PCM_DEV, 0 }, 535 { SB_DSP_FM_DEV, 0 }, 536 }; 537 538 /* 539 * SB16 specific mixer elements 540 */ 541 static const struct sbmix_elem snd_sb16_controls[] = { 542 SB_DOUBLE("Master Playback Volume", 543 SB_DSP4_MASTER_DEV, (SB_DSP4_MASTER_DEV + 1), 3, 3, 31), 544 SB_DOUBLE("PCM Playback Volume", 545 SB_DSP4_PCM_DEV, (SB_DSP4_PCM_DEV + 1), 3, 3, 31), 546 SB16_INPUT_SW("Synth Capture Route", 547 SB_DSP4_INPUT_LEFT, SB_DSP4_INPUT_RIGHT, 6, 5), 548 SB_DOUBLE("Synth Playback Volume", 549 SB_DSP4_SYNTH_DEV, (SB_DSP4_SYNTH_DEV + 1), 3, 3, 31), 550 SB16_INPUT_SW("CD Capture Route", 551 SB_DSP4_INPUT_LEFT, SB_DSP4_INPUT_RIGHT, 2, 1), 552 SB_DOUBLE("CD Playback Switch", 553 SB_DSP4_OUTPUT_SW, SB_DSP4_OUTPUT_SW, 2, 1, 1), 554 SB_DOUBLE("CD Playback Volume", 555 SB_DSP4_CD_DEV, (SB_DSP4_CD_DEV + 1), 3, 3, 31), 556 SB16_INPUT_SW("Mic Capture Route", 557 SB_DSP4_INPUT_LEFT, SB_DSP4_INPUT_RIGHT, 0, 0), 558 SB_SINGLE("Mic Playback Switch", SB_DSP4_OUTPUT_SW, 0, 1), 559 SB_SINGLE("Mic Playback Volume", SB_DSP4_MIC_DEV, 3, 31), 560 SB_SINGLE("Beep Volume", SB_DSP4_SPEAKER_DEV, 6, 3), 561 SB_DOUBLE("Capture Volume", 562 SB_DSP4_IGAIN_DEV, (SB_DSP4_IGAIN_DEV + 1), 6, 6, 3), 563 SB_DOUBLE("Playback Volume", 564 SB_DSP4_OGAIN_DEV, (SB_DSP4_OGAIN_DEV + 1), 6, 6, 3), 565 SB16_INPUT_SW("Line Capture Route", 566 SB_DSP4_INPUT_LEFT, SB_DSP4_INPUT_RIGHT, 4, 3), 567 SB_DOUBLE("Line Playback Switch", 568 SB_DSP4_OUTPUT_SW, SB_DSP4_OUTPUT_SW, 4, 3, 1), 569 SB_DOUBLE("Line Playback Volume", 570 SB_DSP4_LINE_DEV, (SB_DSP4_LINE_DEV + 1), 3, 3, 31), 571 SB_SINGLE("Mic Auto Gain", SB_DSP4_MIC_AGC, 0, 1), 572 SB_SINGLE("3D Enhancement Switch", SB_DSP4_3DSE, 0, 1), 573 SB_DOUBLE("Tone Control - Bass", 574 SB_DSP4_BASS_DEV, (SB_DSP4_BASS_DEV + 1), 4, 4, 15), 575 SB_DOUBLE("Tone Control - Treble", 576 SB_DSP4_TREBLE_DEV, (SB_DSP4_TREBLE_DEV + 1), 4, 4, 15) 577 }; 578 579 static const unsigned char snd_sb16_init_values[][2] = { 580 { SB_DSP4_MASTER_DEV + 0, 0 }, 581 { SB_DSP4_MASTER_DEV + 1, 0 }, 582 { SB_DSP4_PCM_DEV + 0, 0 }, 583 { SB_DSP4_PCM_DEV + 1, 0 }, 584 { SB_DSP4_SYNTH_DEV + 0, 0 }, 585 { SB_DSP4_SYNTH_DEV + 1, 0 }, 586 { SB_DSP4_INPUT_LEFT, 0 }, 587 { SB_DSP4_INPUT_RIGHT, 0 }, 588 { SB_DSP4_OUTPUT_SW, 0 }, 589 { SB_DSP4_SPEAKER_DEV, 0 }, 590 }; 591 592 /* 593 * DT019x specific mixer elements 594 */ 595 static const struct sbmix_elem snd_dt019x_controls[] = { 596 /* ALS4000 below has some parts which we might be lacking, 597 * e.g. snd_als4000_ctl_mono_playback_switch - check it! */ 598 SB_DOUBLE("Master Playback Volume", 599 SB_DT019X_MASTER_DEV, SB_DT019X_MASTER_DEV, 4, 0, 15), 600 SB_DOUBLE("PCM Playback Switch", 601 SB_DT019X_OUTPUT_SW2, SB_DT019X_OUTPUT_SW2, 2, 1, 1), 602 SB_DOUBLE("PCM Playback Volume", 603 SB_DT019X_PCM_DEV, SB_DT019X_PCM_DEV, 4, 0, 15), 604 SB_DOUBLE("Synth Playback Switch", 605 SB_DT019X_OUTPUT_SW2, SB_DT019X_OUTPUT_SW2, 4, 3, 1), 606 SB_DOUBLE("Synth Playback Volume", 607 SB_DT019X_SYNTH_DEV, SB_DT019X_SYNTH_DEV, 4, 0, 15), 608 SB_DOUBLE("CD Playback Switch", 609 SB_DSP4_OUTPUT_SW, SB_DSP4_OUTPUT_SW, 2, 1, 1), 610 SB_DOUBLE("CD Playback Volume", 611 SB_DT019X_CD_DEV, SB_DT019X_CD_DEV, 4, 0, 15), 612 SB_SINGLE("Mic Playback Switch", SB_DSP4_OUTPUT_SW, 0, 1), 613 SB_SINGLE("Mic Playback Volume", SB_DT019X_MIC_DEV, 4, 7), 614 SB_SINGLE("Beep Volume", SB_DT019X_SPKR_DEV, 0, 7), 615 SB_DOUBLE("Line Playback Switch", 616 SB_DSP4_OUTPUT_SW, SB_DSP4_OUTPUT_SW, 4, 3, 1), 617 SB_DOUBLE("Line Playback Volume", 618 SB_DT019X_LINE_DEV, SB_DT019X_LINE_DEV, 4, 0, 15), 619 { 620 .name = "Capture Source", 621 .type = SB_MIX_CAPTURE_DT019X 622 } 623 }; 624 625 static const unsigned char snd_dt019x_init_values[][2] = { 626 { SB_DT019X_MASTER_DEV, 0 }, 627 { SB_DT019X_PCM_DEV, 0 }, 628 { SB_DT019X_SYNTH_DEV, 0 }, 629 { SB_DT019X_CD_DEV, 0 }, 630 { SB_DT019X_MIC_DEV, 0 }, /* Includes PC-speaker in high nibble */ 631 { SB_DT019X_LINE_DEV, 0 }, 632 { SB_DSP4_OUTPUT_SW, 0 }, 633 { SB_DT019X_OUTPUT_SW2, 0 }, 634 { SB_DT019X_CAPTURE_SW, 0x06 }, 635 }; 636 637 /* 638 * ALS4000 specific mixer elements 639 */ 640 static const struct sbmix_elem snd_als4000_controls[] = { 641 SB_DOUBLE("PCM Playback Switch", 642 SB_DT019X_OUTPUT_SW2, SB_DT019X_OUTPUT_SW2, 2, 1, 1), 643 SB_DOUBLE("Synth Playback Switch", 644 SB_DT019X_OUTPUT_SW2, SB_DT019X_OUTPUT_SW2, 4, 3, 1), 645 SB_SINGLE("Mic Boost (+20dB)", SB_ALS4000_MIC_IN_GAIN, 0, 0x03), 646 SB_SINGLE("Master Mono Playback Switch", SB_ALS4000_MONO_IO_CTRL, 5, 1), 647 { 648 .name = "Master Mono Capture Route", 649 .type = SB_MIX_MONO_CAPTURE_ALS4K 650 }, 651 SB_SINGLE("Mono Playback Switch", SB_DT019X_OUTPUT_SW2, 0, 1), 652 SB_SINGLE("Analog Loopback Switch", SB_ALS4000_MIC_IN_GAIN, 7, 0x01), 653 SB_SINGLE("3D Control - Switch", SB_ALS4000_3D_SND_FX, 6, 0x01), 654 SB_SINGLE("Digital Loopback Switch", 655 SB_ALS4000_CR3_CONFIGURATION, 7, 0x01), 656 /* FIXME: functionality of 3D controls might be swapped, I didn't find 657 * a description of how to identify what is supposed to be what */ 658 SB_SINGLE("3D Control - Level", SB_ALS4000_3D_SND_FX, 0, 0x07), 659 /* FIXME: maybe there's actually some standard 3D ctrl name for it?? */ 660 SB_SINGLE("3D Control - Freq", SB_ALS4000_3D_SND_FX, 4, 0x03), 661 /* FIXME: ALS4000a.pdf mentions BBD (Bucket Brigade Device) time delay, 662 * but what ALSA 3D attribute is that actually? "Center", "Depth", 663 * "Wide" or "Space" or even "Level"? Assuming "Wide" for now... */ 664 SB_SINGLE("3D Control - Wide", SB_ALS4000_3D_TIME_DELAY, 0, 0x0f), 665 SB_SINGLE("3D PowerOff Switch", SB_ALS4000_3D_TIME_DELAY, 4, 0x01), 666 SB_SINGLE("Master Playback 8kHz / 20kHz LPF Switch", 667 SB_ALS4000_FMDAC, 5, 0x01), 668 #ifdef NOT_AVAILABLE 669 SB_SINGLE("FMDAC Switch (Option ?)", SB_ALS4000_FMDAC, 0, 0x01), 670 SB_SINGLE("QSound Mode", SB_ALS4000_QSOUND, 1, 0x1f), 671 #endif 672 }; 673 674 static const unsigned char snd_als4000_init_values[][2] = { 675 { SB_DSP4_MASTER_DEV + 0, 0 }, 676 { SB_DSP4_MASTER_DEV + 1, 0 }, 677 { SB_DSP4_PCM_DEV + 0, 0 }, 678 { SB_DSP4_PCM_DEV + 1, 0 }, 679 { SB_DSP4_SYNTH_DEV + 0, 0 }, 680 { SB_DSP4_SYNTH_DEV + 1, 0 }, 681 { SB_DSP4_SPEAKER_DEV, 0 }, 682 { SB_DSP4_OUTPUT_SW, 0 }, 683 { SB_DSP4_INPUT_LEFT, 0 }, 684 { SB_DSP4_INPUT_RIGHT, 0 }, 685 { SB_DT019X_OUTPUT_SW2, 0 }, 686 { SB_ALS4000_MIC_IN_GAIN, 0 }, 687 }; 688 689 /* 690 */ 691 static int snd_sbmixer_init(struct snd_sb *chip, 692 const struct sbmix_elem *controls, 693 int controls_count, 694 const unsigned char map[][2], 695 int map_count, 696 char *name) 697 { 698 unsigned long flags; 699 struct snd_card *card = chip->card; 700 int idx, err; 701 702 /* mixer reset */ 703 spin_lock_irqsave(&chip->mixer_lock, flags); 704 snd_sbmixer_write(chip, 0x00, 0x00); 705 spin_unlock_irqrestore(&chip->mixer_lock, flags); 706 707 /* mute and zero volume channels */ 708 for (idx = 0; idx < map_count; idx++) { 709 spin_lock_irqsave(&chip->mixer_lock, flags); 710 snd_sbmixer_write(chip, map[idx][0], map[idx][1]); 711 spin_unlock_irqrestore(&chip->mixer_lock, flags); 712 } 713 714 for (idx = 0; idx < controls_count; idx++) { 715 err = snd_sbmixer_add_ctl_elem(chip, &controls[idx]); 716 if (err < 0) 717 return err; 718 } 719 snd_component_add(card, name); 720 strcpy(card->mixername, name); 721 return 0; 722 } 723 724 int snd_sbmixer_new(struct snd_sb *chip) 725 { 726 struct snd_card *card; 727 int err; 728 729 if (snd_BUG_ON(!chip || !chip->card)) 730 return -EINVAL; 731 732 card = chip->card; 733 734 switch (chip->hardware) { 735 case SB_HW_10: 736 return 0; /* no mixer chip on SB1.x */ 737 case SB_HW_20: 738 case SB_HW_201: 739 if ((err = snd_sbmixer_init(chip, 740 snd_sb20_controls, 741 ARRAY_SIZE(snd_sb20_controls), 742 snd_sb20_init_values, 743 ARRAY_SIZE(snd_sb20_init_values), 744 "CTL1335")) < 0) 745 return err; 746 break; 747 case SB_HW_PRO: 748 case SB_HW_JAZZ16: 749 if ((err = snd_sbmixer_init(chip, 750 snd_sbpro_controls, 751 ARRAY_SIZE(snd_sbpro_controls), 752 snd_sbpro_init_values, 753 ARRAY_SIZE(snd_sbpro_init_values), 754 "CTL1345")) < 0) 755 return err; 756 break; 757 case SB_HW_16: 758 case SB_HW_ALS100: 759 case SB_HW_CS5530: 760 if ((err = snd_sbmixer_init(chip, 761 snd_sb16_controls, 762 ARRAY_SIZE(snd_sb16_controls), 763 snd_sb16_init_values, 764 ARRAY_SIZE(snd_sb16_init_values), 765 "CTL1745")) < 0) 766 return err; 767 break; 768 case SB_HW_ALS4000: 769 /* use only the first 16 controls from SB16 */ 770 err = snd_sbmixer_init(chip, 771 snd_sb16_controls, 772 16, 773 snd_sb16_init_values, 774 ARRAY_SIZE(snd_sb16_init_values), 775 "ALS4000"); 776 if (err < 0) 777 return err; 778 if ((err = snd_sbmixer_init(chip, 779 snd_als4000_controls, 780 ARRAY_SIZE(snd_als4000_controls), 781 snd_als4000_init_values, 782 ARRAY_SIZE(snd_als4000_init_values), 783 "ALS4000")) < 0) 784 return err; 785 break; 786 case SB_HW_DT019X: 787 err = snd_sbmixer_init(chip, 788 snd_dt019x_controls, 789 ARRAY_SIZE(snd_dt019x_controls), 790 snd_dt019x_init_values, 791 ARRAY_SIZE(snd_dt019x_init_values), 792 "DT019X"); 793 if (err < 0) 794 return err; 795 break; 796 default: 797 strcpy(card->mixername, "???"); 798 } 799 return 0; 800 } 801 802 #ifdef CONFIG_PM 803 static const unsigned char sb20_saved_regs[] = { 804 SB_DSP20_MASTER_DEV, 805 SB_DSP20_PCM_DEV, 806 SB_DSP20_FM_DEV, 807 SB_DSP20_CD_DEV, 808 }; 809 810 static const unsigned char sbpro_saved_regs[] = { 811 SB_DSP_MASTER_DEV, 812 SB_DSP_PCM_DEV, 813 SB_DSP_PLAYBACK_FILT, 814 SB_DSP_FM_DEV, 815 SB_DSP_CD_DEV, 816 SB_DSP_LINE_DEV, 817 SB_DSP_MIC_DEV, 818 SB_DSP_CAPTURE_SOURCE, 819 SB_DSP_CAPTURE_FILT, 820 }; 821 822 static const unsigned char sb16_saved_regs[] = { 823 SB_DSP4_MASTER_DEV, SB_DSP4_MASTER_DEV + 1, 824 SB_DSP4_3DSE, 825 SB_DSP4_BASS_DEV, SB_DSP4_BASS_DEV + 1, 826 SB_DSP4_TREBLE_DEV, SB_DSP4_TREBLE_DEV + 1, 827 SB_DSP4_PCM_DEV, SB_DSP4_PCM_DEV + 1, 828 SB_DSP4_INPUT_LEFT, SB_DSP4_INPUT_RIGHT, 829 SB_DSP4_SYNTH_DEV, SB_DSP4_SYNTH_DEV + 1, 830 SB_DSP4_OUTPUT_SW, 831 SB_DSP4_CD_DEV, SB_DSP4_CD_DEV + 1, 832 SB_DSP4_LINE_DEV, SB_DSP4_LINE_DEV + 1, 833 SB_DSP4_MIC_DEV, 834 SB_DSP4_SPEAKER_DEV, 835 SB_DSP4_IGAIN_DEV, SB_DSP4_IGAIN_DEV + 1, 836 SB_DSP4_OGAIN_DEV, SB_DSP4_OGAIN_DEV + 1, 837 SB_DSP4_MIC_AGC 838 }; 839 840 static const unsigned char dt019x_saved_regs[] = { 841 SB_DT019X_MASTER_DEV, 842 SB_DT019X_PCM_DEV, 843 SB_DT019X_SYNTH_DEV, 844 SB_DT019X_CD_DEV, 845 SB_DT019X_MIC_DEV, 846 SB_DT019X_SPKR_DEV, 847 SB_DT019X_LINE_DEV, 848 SB_DSP4_OUTPUT_SW, 849 SB_DT019X_OUTPUT_SW2, 850 SB_DT019X_CAPTURE_SW, 851 }; 852 853 static const unsigned char als4000_saved_regs[] = { 854 /* please verify in dsheet whether regs to be added 855 are actually real H/W or just dummy */ 856 SB_DSP4_MASTER_DEV, SB_DSP4_MASTER_DEV + 1, 857 SB_DSP4_OUTPUT_SW, 858 SB_DSP4_PCM_DEV, SB_DSP4_PCM_DEV + 1, 859 SB_DSP4_INPUT_LEFT, SB_DSP4_INPUT_RIGHT, 860 SB_DSP4_SYNTH_DEV, SB_DSP4_SYNTH_DEV + 1, 861 SB_DSP4_CD_DEV, SB_DSP4_CD_DEV + 1, 862 SB_DSP4_MIC_DEV, 863 SB_DSP4_SPEAKER_DEV, 864 SB_DSP4_IGAIN_DEV, SB_DSP4_IGAIN_DEV + 1, 865 SB_DSP4_OGAIN_DEV, SB_DSP4_OGAIN_DEV + 1, 866 SB_DT019X_OUTPUT_SW2, 867 SB_ALS4000_MONO_IO_CTRL, 868 SB_ALS4000_MIC_IN_GAIN, 869 SB_ALS4000_FMDAC, 870 SB_ALS4000_3D_SND_FX, 871 SB_ALS4000_3D_TIME_DELAY, 872 SB_ALS4000_CR3_CONFIGURATION, 873 }; 874 875 static void save_mixer(struct snd_sb *chip, const unsigned char *regs, int num_regs) 876 { 877 unsigned char *val = chip->saved_regs; 878 if (snd_BUG_ON(num_regs > ARRAY_SIZE(chip->saved_regs))) 879 return; 880 for (; num_regs; num_regs--) 881 *val++ = snd_sbmixer_read(chip, *regs++); 882 } 883 884 static void restore_mixer(struct snd_sb *chip, const unsigned char *regs, int num_regs) 885 { 886 unsigned char *val = chip->saved_regs; 887 if (snd_BUG_ON(num_regs > ARRAY_SIZE(chip->saved_regs))) 888 return; 889 for (; num_regs; num_regs--) 890 snd_sbmixer_write(chip, *regs++, *val++); 891 } 892 893 void snd_sbmixer_suspend(struct snd_sb *chip) 894 { 895 switch (chip->hardware) { 896 case SB_HW_20: 897 case SB_HW_201: 898 save_mixer(chip, sb20_saved_regs, ARRAY_SIZE(sb20_saved_regs)); 899 break; 900 case SB_HW_PRO: 901 case SB_HW_JAZZ16: 902 save_mixer(chip, sbpro_saved_regs, ARRAY_SIZE(sbpro_saved_regs)); 903 break; 904 case SB_HW_16: 905 case SB_HW_ALS100: 906 case SB_HW_CS5530: 907 save_mixer(chip, sb16_saved_regs, ARRAY_SIZE(sb16_saved_regs)); 908 break; 909 case SB_HW_ALS4000: 910 save_mixer(chip, als4000_saved_regs, ARRAY_SIZE(als4000_saved_regs)); 911 break; 912 case SB_HW_DT019X: 913 save_mixer(chip, dt019x_saved_regs, ARRAY_SIZE(dt019x_saved_regs)); 914 break; 915 default: 916 break; 917 } 918 } 919 920 void snd_sbmixer_resume(struct snd_sb *chip) 921 { 922 switch (chip->hardware) { 923 case SB_HW_20: 924 case SB_HW_201: 925 restore_mixer(chip, sb20_saved_regs, ARRAY_SIZE(sb20_saved_regs)); 926 break; 927 case SB_HW_PRO: 928 case SB_HW_JAZZ16: 929 restore_mixer(chip, sbpro_saved_regs, ARRAY_SIZE(sbpro_saved_regs)); 930 break; 931 case SB_HW_16: 932 case SB_HW_ALS100: 933 case SB_HW_CS5530: 934 restore_mixer(chip, sb16_saved_regs, ARRAY_SIZE(sb16_saved_regs)); 935 break; 936 case SB_HW_ALS4000: 937 restore_mixer(chip, als4000_saved_regs, ARRAY_SIZE(als4000_saved_regs)); 938 break; 939 case SB_HW_DT019X: 940 restore_mixer(chip, dt019x_saved_regs, ARRAY_SIZE(dt019x_saved_regs)); 941 break; 942 default: 943 break; 944 } 945 } 946 #endif 947