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