sb_mixer.c (28059B)
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 16void 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 27unsigned 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 45static 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 56static 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 72static 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 97static 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 108static 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 128static 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 168static 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 177static 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 213static 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 254static 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 264static 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 282static 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 308static 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 318static 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 341static 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 375static 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 384static 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 405static 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 */ 439int 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 strscpy(ctl->id.name, name, sizeof(ctl->id.name)); 486 ctl->id.index = index; 487 ctl->private_value = value; 488 err = snd_ctl_add(chip->card, ctl); 489 if (err < 0) 490 return err; 491 return 0; 492} 493 494/* 495 * SB 2.0 specific mixer elements 496 */ 497 498static const struct sbmix_elem snd_sb20_controls[] = { 499 SB_SINGLE("Master Playback Volume", SB_DSP20_MASTER_DEV, 1, 7), 500 SB_SINGLE("PCM Playback Volume", SB_DSP20_PCM_DEV, 1, 3), 501 SB_SINGLE("Synth Playback Volume", SB_DSP20_FM_DEV, 1, 7), 502 SB_SINGLE("CD Playback Volume", SB_DSP20_CD_DEV, 1, 7) 503}; 504 505static const unsigned char snd_sb20_init_values[][2] = { 506 { SB_DSP20_MASTER_DEV, 0 }, 507 { SB_DSP20_FM_DEV, 0 }, 508}; 509 510/* 511 * SB Pro specific mixer elements 512 */ 513static const struct sbmix_elem snd_sbpro_controls[] = { 514 SB_DOUBLE("Master Playback Volume", 515 SB_DSP_MASTER_DEV, SB_DSP_MASTER_DEV, 5, 1, 7), 516 SB_DOUBLE("PCM Playback Volume", 517 SB_DSP_PCM_DEV, SB_DSP_PCM_DEV, 5, 1, 7), 518 SB_SINGLE("PCM Playback Filter", SB_DSP_PLAYBACK_FILT, 5, 1), 519 SB_DOUBLE("Synth Playback Volume", 520 SB_DSP_FM_DEV, SB_DSP_FM_DEV, 5, 1, 7), 521 SB_DOUBLE("CD Playback Volume", SB_DSP_CD_DEV, SB_DSP_CD_DEV, 5, 1, 7), 522 SB_DOUBLE("Line Playback Volume", 523 SB_DSP_LINE_DEV, SB_DSP_LINE_DEV, 5, 1, 7), 524 SB_SINGLE("Mic Playback Volume", SB_DSP_MIC_DEV, 1, 3), 525 { 526 .name = "Capture Source", 527 .type = SB_MIX_CAPTURE_PRO 528 }, 529 SB_SINGLE("Capture Filter", SB_DSP_CAPTURE_FILT, 5, 1), 530 SB_SINGLE("Capture Low-Pass Filter", SB_DSP_CAPTURE_FILT, 3, 1) 531}; 532 533static const unsigned char snd_sbpro_init_values[][2] = { 534 { SB_DSP_MASTER_DEV, 0 }, 535 { SB_DSP_PCM_DEV, 0 }, 536 { SB_DSP_FM_DEV, 0 }, 537}; 538 539/* 540 * SB16 specific mixer elements 541 */ 542static const struct sbmix_elem snd_sb16_controls[] = { 543 SB_DOUBLE("Master Playback Volume", 544 SB_DSP4_MASTER_DEV, (SB_DSP4_MASTER_DEV + 1), 3, 3, 31), 545 SB_DOUBLE("PCM Playback Volume", 546 SB_DSP4_PCM_DEV, (SB_DSP4_PCM_DEV + 1), 3, 3, 31), 547 SB16_INPUT_SW("Synth Capture Route", 548 SB_DSP4_INPUT_LEFT, SB_DSP4_INPUT_RIGHT, 6, 5), 549 SB_DOUBLE("Synth Playback Volume", 550 SB_DSP4_SYNTH_DEV, (SB_DSP4_SYNTH_DEV + 1), 3, 3, 31), 551 SB16_INPUT_SW("CD Capture Route", 552 SB_DSP4_INPUT_LEFT, SB_DSP4_INPUT_RIGHT, 2, 1), 553 SB_DOUBLE("CD Playback Switch", 554 SB_DSP4_OUTPUT_SW, SB_DSP4_OUTPUT_SW, 2, 1, 1), 555 SB_DOUBLE("CD Playback Volume", 556 SB_DSP4_CD_DEV, (SB_DSP4_CD_DEV + 1), 3, 3, 31), 557 SB16_INPUT_SW("Mic Capture Route", 558 SB_DSP4_INPUT_LEFT, SB_DSP4_INPUT_RIGHT, 0, 0), 559 SB_SINGLE("Mic Playback Switch", SB_DSP4_OUTPUT_SW, 0, 1), 560 SB_SINGLE("Mic Playback Volume", SB_DSP4_MIC_DEV, 3, 31), 561 SB_SINGLE("Beep Volume", SB_DSP4_SPEAKER_DEV, 6, 3), 562 SB_DOUBLE("Capture Volume", 563 SB_DSP4_IGAIN_DEV, (SB_DSP4_IGAIN_DEV + 1), 6, 6, 3), 564 SB_DOUBLE("Playback Volume", 565 SB_DSP4_OGAIN_DEV, (SB_DSP4_OGAIN_DEV + 1), 6, 6, 3), 566 SB16_INPUT_SW("Line Capture Route", 567 SB_DSP4_INPUT_LEFT, SB_DSP4_INPUT_RIGHT, 4, 3), 568 SB_DOUBLE("Line Playback Switch", 569 SB_DSP4_OUTPUT_SW, SB_DSP4_OUTPUT_SW, 4, 3, 1), 570 SB_DOUBLE("Line Playback Volume", 571 SB_DSP4_LINE_DEV, (SB_DSP4_LINE_DEV + 1), 3, 3, 31), 572 SB_SINGLE("Mic Auto Gain", SB_DSP4_MIC_AGC, 0, 1), 573 SB_SINGLE("3D Enhancement Switch", SB_DSP4_3DSE, 0, 1), 574 SB_DOUBLE("Tone Control - Bass", 575 SB_DSP4_BASS_DEV, (SB_DSP4_BASS_DEV + 1), 4, 4, 15), 576 SB_DOUBLE("Tone Control - Treble", 577 SB_DSP4_TREBLE_DEV, (SB_DSP4_TREBLE_DEV + 1), 4, 4, 15) 578}; 579 580static const unsigned char snd_sb16_init_values[][2] = { 581 { SB_DSP4_MASTER_DEV + 0, 0 }, 582 { SB_DSP4_MASTER_DEV + 1, 0 }, 583 { SB_DSP4_PCM_DEV + 0, 0 }, 584 { SB_DSP4_PCM_DEV + 1, 0 }, 585 { SB_DSP4_SYNTH_DEV + 0, 0 }, 586 { SB_DSP4_SYNTH_DEV + 1, 0 }, 587 { SB_DSP4_INPUT_LEFT, 0 }, 588 { SB_DSP4_INPUT_RIGHT, 0 }, 589 { SB_DSP4_OUTPUT_SW, 0 }, 590 { SB_DSP4_SPEAKER_DEV, 0 }, 591}; 592 593/* 594 * DT019x specific mixer elements 595 */ 596static const struct sbmix_elem snd_dt019x_controls[] = { 597 /* ALS4000 below has some parts which we might be lacking, 598 * e.g. snd_als4000_ctl_mono_playback_switch - check it! */ 599 SB_DOUBLE("Master Playback Volume", 600 SB_DT019X_MASTER_DEV, SB_DT019X_MASTER_DEV, 4, 0, 15), 601 SB_DOUBLE("PCM Playback Switch", 602 SB_DT019X_OUTPUT_SW2, SB_DT019X_OUTPUT_SW2, 2, 1, 1), 603 SB_DOUBLE("PCM Playback Volume", 604 SB_DT019X_PCM_DEV, SB_DT019X_PCM_DEV, 4, 0, 15), 605 SB_DOUBLE("Synth Playback Switch", 606 SB_DT019X_OUTPUT_SW2, SB_DT019X_OUTPUT_SW2, 4, 3, 1), 607 SB_DOUBLE("Synth Playback Volume", 608 SB_DT019X_SYNTH_DEV, SB_DT019X_SYNTH_DEV, 4, 0, 15), 609 SB_DOUBLE("CD Playback Switch", 610 SB_DSP4_OUTPUT_SW, SB_DSP4_OUTPUT_SW, 2, 1, 1), 611 SB_DOUBLE("CD Playback Volume", 612 SB_DT019X_CD_DEV, SB_DT019X_CD_DEV, 4, 0, 15), 613 SB_SINGLE("Mic Playback Switch", SB_DSP4_OUTPUT_SW, 0, 1), 614 SB_SINGLE("Mic Playback Volume", SB_DT019X_MIC_DEV, 4, 7), 615 SB_SINGLE("Beep Volume", SB_DT019X_SPKR_DEV, 0, 7), 616 SB_DOUBLE("Line Playback Switch", 617 SB_DSP4_OUTPUT_SW, SB_DSP4_OUTPUT_SW, 4, 3, 1), 618 SB_DOUBLE("Line Playback Volume", 619 SB_DT019X_LINE_DEV, SB_DT019X_LINE_DEV, 4, 0, 15), 620 { 621 .name = "Capture Source", 622 .type = SB_MIX_CAPTURE_DT019X 623 } 624}; 625 626static const unsigned char snd_dt019x_init_values[][2] = { 627 { SB_DT019X_MASTER_DEV, 0 }, 628 { SB_DT019X_PCM_DEV, 0 }, 629 { SB_DT019X_SYNTH_DEV, 0 }, 630 { SB_DT019X_CD_DEV, 0 }, 631 { SB_DT019X_MIC_DEV, 0 }, /* Includes PC-speaker in high nibble */ 632 { SB_DT019X_LINE_DEV, 0 }, 633 { SB_DSP4_OUTPUT_SW, 0 }, 634 { SB_DT019X_OUTPUT_SW2, 0 }, 635 { SB_DT019X_CAPTURE_SW, 0x06 }, 636}; 637 638/* 639 * ALS4000 specific mixer elements 640 */ 641static const struct sbmix_elem snd_als4000_controls[] = { 642 SB_DOUBLE("PCM Playback Switch", 643 SB_DT019X_OUTPUT_SW2, SB_DT019X_OUTPUT_SW2, 2, 1, 1), 644 SB_DOUBLE("Synth Playback Switch", 645 SB_DT019X_OUTPUT_SW2, SB_DT019X_OUTPUT_SW2, 4, 3, 1), 646 SB_SINGLE("Mic Boost (+20dB)", SB_ALS4000_MIC_IN_GAIN, 0, 0x03), 647 SB_SINGLE("Master Mono Playback Switch", SB_ALS4000_MONO_IO_CTRL, 5, 1), 648 { 649 .name = "Master Mono Capture Route", 650 .type = SB_MIX_MONO_CAPTURE_ALS4K 651 }, 652 SB_SINGLE("Mono Playback Switch", SB_DT019X_OUTPUT_SW2, 0, 1), 653 SB_SINGLE("Analog Loopback Switch", SB_ALS4000_MIC_IN_GAIN, 7, 0x01), 654 SB_SINGLE("3D Control - Switch", SB_ALS4000_3D_SND_FX, 6, 0x01), 655 SB_SINGLE("Digital Loopback Switch", 656 SB_ALS4000_CR3_CONFIGURATION, 7, 0x01), 657 /* FIXME: functionality of 3D controls might be swapped, I didn't find 658 * a description of how to identify what is supposed to be what */ 659 SB_SINGLE("3D Control - Level", SB_ALS4000_3D_SND_FX, 0, 0x07), 660 /* FIXME: maybe there's actually some standard 3D ctrl name for it?? */ 661 SB_SINGLE("3D Control - Freq", SB_ALS4000_3D_SND_FX, 4, 0x03), 662 /* FIXME: ALS4000a.pdf mentions BBD (Bucket Brigade Device) time delay, 663 * but what ALSA 3D attribute is that actually? "Center", "Depth", 664 * "Wide" or "Space" or even "Level"? Assuming "Wide" for now... */ 665 SB_SINGLE("3D Control - Wide", SB_ALS4000_3D_TIME_DELAY, 0, 0x0f), 666 SB_SINGLE("3D PowerOff Switch", SB_ALS4000_3D_TIME_DELAY, 4, 0x01), 667 SB_SINGLE("Master Playback 8kHz / 20kHz LPF Switch", 668 SB_ALS4000_FMDAC, 5, 0x01), 669#ifdef NOT_AVAILABLE 670 SB_SINGLE("FMDAC Switch (Option ?)", SB_ALS4000_FMDAC, 0, 0x01), 671 SB_SINGLE("QSound Mode", SB_ALS4000_QSOUND, 1, 0x1f), 672#endif 673}; 674 675static const unsigned char snd_als4000_init_values[][2] = { 676 { SB_DSP4_MASTER_DEV + 0, 0 }, 677 { SB_DSP4_MASTER_DEV + 1, 0 }, 678 { SB_DSP4_PCM_DEV + 0, 0 }, 679 { SB_DSP4_PCM_DEV + 1, 0 }, 680 { SB_DSP4_SYNTH_DEV + 0, 0 }, 681 { SB_DSP4_SYNTH_DEV + 1, 0 }, 682 { SB_DSP4_SPEAKER_DEV, 0 }, 683 { SB_DSP4_OUTPUT_SW, 0 }, 684 { SB_DSP4_INPUT_LEFT, 0 }, 685 { SB_DSP4_INPUT_RIGHT, 0 }, 686 { SB_DT019X_OUTPUT_SW2, 0 }, 687 { SB_ALS4000_MIC_IN_GAIN, 0 }, 688}; 689 690/* 691 */ 692static int snd_sbmixer_init(struct snd_sb *chip, 693 const struct sbmix_elem *controls, 694 int controls_count, 695 const unsigned char map[][2], 696 int map_count, 697 char *name) 698{ 699 unsigned long flags; 700 struct snd_card *card = chip->card; 701 int idx, err; 702 703 /* mixer reset */ 704 spin_lock_irqsave(&chip->mixer_lock, flags); 705 snd_sbmixer_write(chip, 0x00, 0x00); 706 spin_unlock_irqrestore(&chip->mixer_lock, flags); 707 708 /* mute and zero volume channels */ 709 for (idx = 0; idx < map_count; idx++) { 710 spin_lock_irqsave(&chip->mixer_lock, flags); 711 snd_sbmixer_write(chip, map[idx][0], map[idx][1]); 712 spin_unlock_irqrestore(&chip->mixer_lock, flags); 713 } 714 715 for (idx = 0; idx < controls_count; idx++) { 716 err = snd_sbmixer_add_ctl_elem(chip, &controls[idx]); 717 if (err < 0) 718 return err; 719 } 720 snd_component_add(card, name); 721 strcpy(card->mixername, name); 722 return 0; 723} 724 725int snd_sbmixer_new(struct snd_sb *chip) 726{ 727 struct snd_card *card; 728 int err; 729 730 if (snd_BUG_ON(!chip || !chip->card)) 731 return -EINVAL; 732 733 card = chip->card; 734 735 switch (chip->hardware) { 736 case SB_HW_10: 737 return 0; /* no mixer chip on SB1.x */ 738 case SB_HW_20: 739 case SB_HW_201: 740 err = snd_sbmixer_init(chip, 741 snd_sb20_controls, 742 ARRAY_SIZE(snd_sb20_controls), 743 snd_sb20_init_values, 744 ARRAY_SIZE(snd_sb20_init_values), 745 "CTL1335"); 746 if (err < 0) 747 return err; 748 break; 749 case SB_HW_PRO: 750 case SB_HW_JAZZ16: 751 err = snd_sbmixer_init(chip, 752 snd_sbpro_controls, 753 ARRAY_SIZE(snd_sbpro_controls), 754 snd_sbpro_init_values, 755 ARRAY_SIZE(snd_sbpro_init_values), 756 "CTL1345"); 757 if (err < 0) 758 return err; 759 break; 760 case SB_HW_16: 761 case SB_HW_ALS100: 762 case SB_HW_CS5530: 763 err = snd_sbmixer_init(chip, 764 snd_sb16_controls, 765 ARRAY_SIZE(snd_sb16_controls), 766 snd_sb16_init_values, 767 ARRAY_SIZE(snd_sb16_init_values), 768 "CTL1745"); 769 if (err < 0) 770 return err; 771 break; 772 case SB_HW_ALS4000: 773 /* use only the first 16 controls from SB16 */ 774 err = snd_sbmixer_init(chip, 775 snd_sb16_controls, 776 16, 777 snd_sb16_init_values, 778 ARRAY_SIZE(snd_sb16_init_values), 779 "ALS4000"); 780 if (err < 0) 781 return err; 782 err = snd_sbmixer_init(chip, 783 snd_als4000_controls, 784 ARRAY_SIZE(snd_als4000_controls), 785 snd_als4000_init_values, 786 ARRAY_SIZE(snd_als4000_init_values), 787 "ALS4000"); 788 if (err < 0) 789 return err; 790 break; 791 case SB_HW_DT019X: 792 err = snd_sbmixer_init(chip, 793 snd_dt019x_controls, 794 ARRAY_SIZE(snd_dt019x_controls), 795 snd_dt019x_init_values, 796 ARRAY_SIZE(snd_dt019x_init_values), 797 "DT019X"); 798 if (err < 0) 799 return err; 800 break; 801 default: 802 strcpy(card->mixername, "???"); 803 } 804 return 0; 805} 806 807#ifdef CONFIG_PM 808static const unsigned char sb20_saved_regs[] = { 809 SB_DSP20_MASTER_DEV, 810 SB_DSP20_PCM_DEV, 811 SB_DSP20_FM_DEV, 812 SB_DSP20_CD_DEV, 813}; 814 815static const unsigned char sbpro_saved_regs[] = { 816 SB_DSP_MASTER_DEV, 817 SB_DSP_PCM_DEV, 818 SB_DSP_PLAYBACK_FILT, 819 SB_DSP_FM_DEV, 820 SB_DSP_CD_DEV, 821 SB_DSP_LINE_DEV, 822 SB_DSP_MIC_DEV, 823 SB_DSP_CAPTURE_SOURCE, 824 SB_DSP_CAPTURE_FILT, 825}; 826 827static const unsigned char sb16_saved_regs[] = { 828 SB_DSP4_MASTER_DEV, SB_DSP4_MASTER_DEV + 1, 829 SB_DSP4_3DSE, 830 SB_DSP4_BASS_DEV, SB_DSP4_BASS_DEV + 1, 831 SB_DSP4_TREBLE_DEV, SB_DSP4_TREBLE_DEV + 1, 832 SB_DSP4_PCM_DEV, SB_DSP4_PCM_DEV + 1, 833 SB_DSP4_INPUT_LEFT, SB_DSP4_INPUT_RIGHT, 834 SB_DSP4_SYNTH_DEV, SB_DSP4_SYNTH_DEV + 1, 835 SB_DSP4_OUTPUT_SW, 836 SB_DSP4_CD_DEV, SB_DSP4_CD_DEV + 1, 837 SB_DSP4_LINE_DEV, SB_DSP4_LINE_DEV + 1, 838 SB_DSP4_MIC_DEV, 839 SB_DSP4_SPEAKER_DEV, 840 SB_DSP4_IGAIN_DEV, SB_DSP4_IGAIN_DEV + 1, 841 SB_DSP4_OGAIN_DEV, SB_DSP4_OGAIN_DEV + 1, 842 SB_DSP4_MIC_AGC 843}; 844 845static const unsigned char dt019x_saved_regs[] = { 846 SB_DT019X_MASTER_DEV, 847 SB_DT019X_PCM_DEV, 848 SB_DT019X_SYNTH_DEV, 849 SB_DT019X_CD_DEV, 850 SB_DT019X_MIC_DEV, 851 SB_DT019X_SPKR_DEV, 852 SB_DT019X_LINE_DEV, 853 SB_DSP4_OUTPUT_SW, 854 SB_DT019X_OUTPUT_SW2, 855 SB_DT019X_CAPTURE_SW, 856}; 857 858static const unsigned char als4000_saved_regs[] = { 859 /* please verify in dsheet whether regs to be added 860 are actually real H/W or just dummy */ 861 SB_DSP4_MASTER_DEV, SB_DSP4_MASTER_DEV + 1, 862 SB_DSP4_OUTPUT_SW, 863 SB_DSP4_PCM_DEV, SB_DSP4_PCM_DEV + 1, 864 SB_DSP4_INPUT_LEFT, SB_DSP4_INPUT_RIGHT, 865 SB_DSP4_SYNTH_DEV, SB_DSP4_SYNTH_DEV + 1, 866 SB_DSP4_CD_DEV, SB_DSP4_CD_DEV + 1, 867 SB_DSP4_MIC_DEV, 868 SB_DSP4_SPEAKER_DEV, 869 SB_DSP4_IGAIN_DEV, SB_DSP4_IGAIN_DEV + 1, 870 SB_DSP4_OGAIN_DEV, SB_DSP4_OGAIN_DEV + 1, 871 SB_DT019X_OUTPUT_SW2, 872 SB_ALS4000_MONO_IO_CTRL, 873 SB_ALS4000_MIC_IN_GAIN, 874 SB_ALS4000_FMDAC, 875 SB_ALS4000_3D_SND_FX, 876 SB_ALS4000_3D_TIME_DELAY, 877 SB_ALS4000_CR3_CONFIGURATION, 878}; 879 880static void save_mixer(struct snd_sb *chip, const unsigned char *regs, int num_regs) 881{ 882 unsigned char *val = chip->saved_regs; 883 if (snd_BUG_ON(num_regs > ARRAY_SIZE(chip->saved_regs))) 884 return; 885 for (; num_regs; num_regs--) 886 *val++ = snd_sbmixer_read(chip, *regs++); 887} 888 889static void restore_mixer(struct snd_sb *chip, const unsigned char *regs, int num_regs) 890{ 891 unsigned char *val = chip->saved_regs; 892 if (snd_BUG_ON(num_regs > ARRAY_SIZE(chip->saved_regs))) 893 return; 894 for (; num_regs; num_regs--) 895 snd_sbmixer_write(chip, *regs++, *val++); 896} 897 898void snd_sbmixer_suspend(struct snd_sb *chip) 899{ 900 switch (chip->hardware) { 901 case SB_HW_20: 902 case SB_HW_201: 903 save_mixer(chip, sb20_saved_regs, ARRAY_SIZE(sb20_saved_regs)); 904 break; 905 case SB_HW_PRO: 906 case SB_HW_JAZZ16: 907 save_mixer(chip, sbpro_saved_regs, ARRAY_SIZE(sbpro_saved_regs)); 908 break; 909 case SB_HW_16: 910 case SB_HW_ALS100: 911 case SB_HW_CS5530: 912 save_mixer(chip, sb16_saved_regs, ARRAY_SIZE(sb16_saved_regs)); 913 break; 914 case SB_HW_ALS4000: 915 save_mixer(chip, als4000_saved_regs, ARRAY_SIZE(als4000_saved_regs)); 916 break; 917 case SB_HW_DT019X: 918 save_mixer(chip, dt019x_saved_regs, ARRAY_SIZE(dt019x_saved_regs)); 919 break; 920 default: 921 break; 922 } 923} 924 925void snd_sbmixer_resume(struct snd_sb *chip) 926{ 927 switch (chip->hardware) { 928 case SB_HW_20: 929 case SB_HW_201: 930 restore_mixer(chip, sb20_saved_regs, ARRAY_SIZE(sb20_saved_regs)); 931 break; 932 case SB_HW_PRO: 933 case SB_HW_JAZZ16: 934 restore_mixer(chip, sbpro_saved_regs, ARRAY_SIZE(sbpro_saved_regs)); 935 break; 936 case SB_HW_16: 937 case SB_HW_ALS100: 938 case SB_HW_CS5530: 939 restore_mixer(chip, sb16_saved_regs, ARRAY_SIZE(sb16_saved_regs)); 940 break; 941 case SB_HW_ALS4000: 942 restore_mixer(chip, als4000_saved_regs, ARRAY_SIZE(als4000_saved_regs)); 943 break; 944 case SB_HW_DT019X: 945 restore_mixer(chip, dt019x_saved_regs, ARRAY_SIZE(dt019x_saved_regs)); 946 break; 947 default: 948 break; 949 } 950} 951#endif