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