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