Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-or-later
0002 /*
0003  *  Copyright (c) by Jaroslav Kysela <perex@perex.cz>
0004  *  Routines for Sound Blaster mixer control
0005  */
0006 
0007 #include <linux/io.h>
0008 #include <linux/delay.h>
0009 #include <linux/time.h>
0010 #include <sound/core.h>
0011 #include <sound/sb.h>
0012 #include <sound/control.h>
0013 
0014 #undef IO_DEBUG
0015 
0016 void snd_sbmixer_write(struct snd_sb *chip, unsigned char reg, unsigned char data)
0017 {
0018     outb(reg, SBP(chip, MIXER_ADDR));
0019     udelay(10);
0020     outb(data, SBP(chip, MIXER_DATA));
0021     udelay(10);
0022 #ifdef IO_DEBUG
0023     snd_printk(KERN_DEBUG "mixer_write 0x%x 0x%x\n", reg, data);
0024 #endif
0025 }
0026 
0027 unsigned char snd_sbmixer_read(struct snd_sb *chip, unsigned char reg)
0028 {
0029     unsigned char result;
0030 
0031     outb(reg, SBP(chip, MIXER_ADDR));
0032     udelay(10);
0033     result = inb(SBP(chip, MIXER_DATA));
0034     udelay(10);
0035 #ifdef IO_DEBUG
0036     snd_printk(KERN_DEBUG "mixer_read 0x%x 0x%x\n", reg, result);
0037 #endif
0038     return result;
0039 }
0040 
0041 /*
0042  * Single channel mixer element
0043  */
0044 
0045 static int snd_sbmixer_info_single(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo)
0046 {
0047     int mask = (kcontrol->private_value >> 24) & 0xff;
0048 
0049     uinfo->type = mask == 1 ? SNDRV_CTL_ELEM_TYPE_BOOLEAN : SNDRV_CTL_ELEM_TYPE_INTEGER;
0050     uinfo->count = 1;
0051     uinfo->value.integer.min = 0;
0052     uinfo->value.integer.max = mask;
0053     return 0;
0054 }
0055 
0056 static int snd_sbmixer_get_single(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
0057 {
0058     struct snd_sb *sb = snd_kcontrol_chip(kcontrol);
0059     unsigned long flags;
0060     int reg = kcontrol->private_value & 0xff;
0061     int shift = (kcontrol->private_value >> 16) & 0xff;
0062     int mask = (kcontrol->private_value >> 24) & 0xff;
0063     unsigned char val;
0064 
0065     spin_lock_irqsave(&sb->mixer_lock, flags);
0066     val = (snd_sbmixer_read(sb, reg) >> shift) & mask;
0067     spin_unlock_irqrestore(&sb->mixer_lock, flags);
0068     ucontrol->value.integer.value[0] = val;
0069     return 0;
0070 }
0071 
0072 static int snd_sbmixer_put_single(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
0073 {
0074     struct snd_sb *sb = snd_kcontrol_chip(kcontrol);
0075     unsigned long flags;
0076     int reg = kcontrol->private_value & 0xff;
0077     int shift = (kcontrol->private_value >> 16) & 0x07;
0078     int mask = (kcontrol->private_value >> 24) & 0xff;
0079     int change;
0080     unsigned char val, oval;
0081 
0082     val = (ucontrol->value.integer.value[0] & mask) << shift;
0083     spin_lock_irqsave(&sb->mixer_lock, flags);
0084     oval = snd_sbmixer_read(sb, reg);
0085     val = (oval & ~(mask << shift)) | val;
0086     change = val != oval;
0087     if (change)
0088         snd_sbmixer_write(sb, reg, val);
0089     spin_unlock_irqrestore(&sb->mixer_lock, flags);
0090     return change;
0091 }
0092 
0093 /*
0094  * Double channel mixer element
0095  */
0096 
0097 static int snd_sbmixer_info_double(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo)
0098 {
0099     int mask = (kcontrol->private_value >> 24) & 0xff;
0100 
0101     uinfo->type = mask == 1 ? SNDRV_CTL_ELEM_TYPE_BOOLEAN : SNDRV_CTL_ELEM_TYPE_INTEGER;
0102     uinfo->count = 2;
0103     uinfo->value.integer.min = 0;
0104     uinfo->value.integer.max = mask;
0105     return 0;
0106 }
0107 
0108 static int snd_sbmixer_get_double(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
0109 {
0110     struct snd_sb *sb = snd_kcontrol_chip(kcontrol);
0111     unsigned long flags;
0112     int left_reg = kcontrol->private_value & 0xff;
0113     int right_reg = (kcontrol->private_value >> 8) & 0xff;
0114     int left_shift = (kcontrol->private_value >> 16) & 0x07;
0115     int right_shift = (kcontrol->private_value >> 19) & 0x07;
0116     int mask = (kcontrol->private_value >> 24) & 0xff;
0117     unsigned char left, right;
0118 
0119     spin_lock_irqsave(&sb->mixer_lock, flags);
0120     left = (snd_sbmixer_read(sb, left_reg) >> left_shift) & mask;
0121     right = (snd_sbmixer_read(sb, right_reg) >> right_shift) & mask;
0122     spin_unlock_irqrestore(&sb->mixer_lock, flags);
0123     ucontrol->value.integer.value[0] = left;
0124     ucontrol->value.integer.value[1] = right;
0125     return 0;
0126 }
0127 
0128 static int snd_sbmixer_put_double(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
0129 {
0130     struct snd_sb *sb = snd_kcontrol_chip(kcontrol);
0131     unsigned long flags;
0132     int left_reg = kcontrol->private_value & 0xff;
0133     int right_reg = (kcontrol->private_value >> 8) & 0xff;
0134     int left_shift = (kcontrol->private_value >> 16) & 0x07;
0135     int right_shift = (kcontrol->private_value >> 19) & 0x07;
0136     int mask = (kcontrol->private_value >> 24) & 0xff;
0137     int change;
0138     unsigned char left, right, oleft, oright;
0139 
0140     left = (ucontrol->value.integer.value[0] & mask) << left_shift;
0141     right = (ucontrol->value.integer.value[1] & mask) << right_shift;
0142     spin_lock_irqsave(&sb->mixer_lock, flags);
0143     if (left_reg == right_reg) {
0144         oleft = snd_sbmixer_read(sb, left_reg);
0145         left = (oleft & ~((mask << left_shift) | (mask << right_shift))) | left | right;
0146         change = left != oleft;
0147         if (change)
0148             snd_sbmixer_write(sb, left_reg, left);
0149     } else {
0150         oleft = snd_sbmixer_read(sb, left_reg);
0151         oright = snd_sbmixer_read(sb, right_reg);
0152         left = (oleft & ~(mask << left_shift)) | left;
0153         right = (oright & ~(mask << right_shift)) | right;
0154         change = left != oleft || right != oright;
0155         if (change) {
0156             snd_sbmixer_write(sb, left_reg, left);
0157             snd_sbmixer_write(sb, right_reg, right);
0158         }
0159     }
0160     spin_unlock_irqrestore(&sb->mixer_lock, flags);
0161     return change;
0162 }
0163 
0164 /*
0165  * DT-019x / ALS-007 capture/input switch
0166  */
0167 
0168 static int snd_dt019x_input_sw_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo)
0169 {
0170     static const char * const texts[5] = {
0171         "CD", "Mic", "Line", "Synth", "Master"
0172     };
0173 
0174     return snd_ctl_enum_info(uinfo, 1, 5, texts);
0175 }
0176 
0177 static int snd_dt019x_input_sw_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
0178 {
0179     struct snd_sb *sb = snd_kcontrol_chip(kcontrol);
0180     unsigned long flags;
0181     unsigned char oval;
0182     
0183     spin_lock_irqsave(&sb->mixer_lock, flags);
0184     oval = snd_sbmixer_read(sb, SB_DT019X_CAPTURE_SW);
0185     spin_unlock_irqrestore(&sb->mixer_lock, flags);
0186     switch (oval & 0x07) {
0187     case SB_DT019X_CAP_CD:
0188         ucontrol->value.enumerated.item[0] = 0;
0189         break;
0190     case SB_DT019X_CAP_MIC:
0191         ucontrol->value.enumerated.item[0] = 1;
0192         break;
0193     case SB_DT019X_CAP_LINE:
0194         ucontrol->value.enumerated.item[0] = 2;
0195         break;
0196     case SB_DT019X_CAP_MAIN:
0197         ucontrol->value.enumerated.item[0] = 4;
0198         break;
0199     /* To record the synth on these cards you must record the main.   */
0200     /* Thus SB_DT019X_CAP_SYNTH == SB_DT019X_CAP_MAIN and would cause */
0201     /* duplicate case labels if left uncommented. */
0202     /* case SB_DT019X_CAP_SYNTH:
0203      *  ucontrol->value.enumerated.item[0] = 3;
0204      *  break;
0205      */
0206     default:
0207         ucontrol->value.enumerated.item[0] = 4;
0208         break;
0209     }
0210     return 0;
0211 }
0212 
0213 static int snd_dt019x_input_sw_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
0214 {
0215     struct snd_sb *sb = snd_kcontrol_chip(kcontrol);
0216     unsigned long flags;
0217     int change;
0218     unsigned char nval, oval;
0219     
0220     if (ucontrol->value.enumerated.item[0] > 4)
0221         return -EINVAL;
0222     switch (ucontrol->value.enumerated.item[0]) {
0223     case 0:
0224         nval = SB_DT019X_CAP_CD;
0225         break;
0226     case 1:
0227         nval = SB_DT019X_CAP_MIC;
0228         break;
0229     case 2:
0230         nval = SB_DT019X_CAP_LINE;
0231         break;
0232     case 3:
0233         nval = SB_DT019X_CAP_SYNTH;
0234         break;
0235     case 4:
0236         nval = SB_DT019X_CAP_MAIN;
0237         break;
0238     default:
0239         nval = SB_DT019X_CAP_MAIN;
0240     }
0241     spin_lock_irqsave(&sb->mixer_lock, flags);
0242     oval = snd_sbmixer_read(sb, SB_DT019X_CAPTURE_SW);
0243     change = nval != oval;
0244     if (change)
0245         snd_sbmixer_write(sb, SB_DT019X_CAPTURE_SW, nval);
0246     spin_unlock_irqrestore(&sb->mixer_lock, flags);
0247     return change;
0248 }
0249 
0250 /*
0251  * ALS4000 mono recording control switch
0252  */
0253 
0254 static int snd_als4k_mono_capture_route_info(struct snd_kcontrol *kcontrol,
0255                          struct snd_ctl_elem_info *uinfo)
0256 {
0257     static const char * const texts[3] = {
0258         "L chan only", "R chan only", "L ch/2 + R ch/2"
0259     };
0260 
0261     return snd_ctl_enum_info(uinfo, 1, 3, texts);
0262 }
0263 
0264 static int snd_als4k_mono_capture_route_get(struct snd_kcontrol *kcontrol,
0265                 struct snd_ctl_elem_value *ucontrol)
0266 {
0267     struct snd_sb *sb = snd_kcontrol_chip(kcontrol);
0268     unsigned long flags;
0269     unsigned char oval;
0270 
0271     spin_lock_irqsave(&sb->mixer_lock, flags);
0272     oval = snd_sbmixer_read(sb, SB_ALS4000_MONO_IO_CTRL);
0273     spin_unlock_irqrestore(&sb->mixer_lock, flags);
0274     oval >>= 6;
0275     if (oval > 2)
0276         oval = 2;
0277 
0278     ucontrol->value.enumerated.item[0] = oval;
0279     return 0;
0280 }
0281 
0282 static int snd_als4k_mono_capture_route_put(struct snd_kcontrol *kcontrol,
0283                 struct snd_ctl_elem_value *ucontrol)
0284 {
0285     struct snd_sb *sb = snd_kcontrol_chip(kcontrol);
0286     unsigned long flags;
0287     int change;
0288     unsigned char nval, oval;
0289 
0290     if (ucontrol->value.enumerated.item[0] > 2)
0291         return -EINVAL;
0292     spin_lock_irqsave(&sb->mixer_lock, flags);
0293     oval = snd_sbmixer_read(sb, SB_ALS4000_MONO_IO_CTRL);
0294 
0295     nval = (oval & ~(3 << 6))
0296          | (ucontrol->value.enumerated.item[0] << 6);
0297     change = nval != oval;
0298     if (change)
0299         snd_sbmixer_write(sb, SB_ALS4000_MONO_IO_CTRL, nval);
0300     spin_unlock_irqrestore(&sb->mixer_lock, flags);
0301     return change;
0302 }
0303 
0304 /*
0305  * SBPRO input multiplexer
0306  */
0307 
0308 static int snd_sb8mixer_info_mux(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo)
0309 {
0310     static const char * const texts[3] = {
0311         "Mic", "CD", "Line"
0312     };
0313 
0314     return snd_ctl_enum_info(uinfo, 1, 3, texts);
0315 }
0316 
0317 
0318 static int snd_sb8mixer_get_mux(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
0319 {
0320     struct snd_sb *sb = snd_kcontrol_chip(kcontrol);
0321     unsigned long flags;
0322     unsigned char oval;
0323     
0324     spin_lock_irqsave(&sb->mixer_lock, flags);
0325     oval = snd_sbmixer_read(sb, SB_DSP_CAPTURE_SOURCE);
0326     spin_unlock_irqrestore(&sb->mixer_lock, flags);
0327     switch ((oval >> 0x01) & 0x03) {
0328     case SB_DSP_MIXS_CD:
0329         ucontrol->value.enumerated.item[0] = 1;
0330         break;
0331     case SB_DSP_MIXS_LINE:
0332         ucontrol->value.enumerated.item[0] = 2;
0333         break;
0334     default:
0335         ucontrol->value.enumerated.item[0] = 0;
0336         break;
0337     }
0338     return 0;
0339 }
0340 
0341 static int snd_sb8mixer_put_mux(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
0342 {
0343     struct snd_sb *sb = snd_kcontrol_chip(kcontrol);
0344     unsigned long flags;
0345     int change;
0346     unsigned char nval, oval;
0347     
0348     if (ucontrol->value.enumerated.item[0] > 2)
0349         return -EINVAL;
0350     switch (ucontrol->value.enumerated.item[0]) {
0351     case 1:
0352         nval = SB_DSP_MIXS_CD;
0353         break;
0354     case 2:
0355         nval = SB_DSP_MIXS_LINE;
0356         break;
0357     default:
0358         nval = SB_DSP_MIXS_MIC;
0359     }
0360     nval <<= 1;
0361     spin_lock_irqsave(&sb->mixer_lock, flags);
0362     oval = snd_sbmixer_read(sb, SB_DSP_CAPTURE_SOURCE);
0363     nval |= oval & ~0x06;
0364     change = nval != oval;
0365     if (change)
0366         snd_sbmixer_write(sb, SB_DSP_CAPTURE_SOURCE, nval);
0367     spin_unlock_irqrestore(&sb->mixer_lock, flags);
0368     return change;
0369 }
0370 
0371 /*
0372  * SB16 input switch
0373  */
0374 
0375 static int snd_sb16mixer_info_input_sw(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo)
0376 {
0377     uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN;
0378     uinfo->count = 4;
0379     uinfo->value.integer.min = 0;
0380     uinfo->value.integer.max = 1;
0381     return 0;
0382 }
0383 
0384 static int snd_sb16mixer_get_input_sw(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
0385 {
0386     struct snd_sb *sb = snd_kcontrol_chip(kcontrol);
0387     unsigned long flags;
0388     int reg1 = kcontrol->private_value & 0xff;
0389     int reg2 = (kcontrol->private_value >> 8) & 0xff;
0390     int left_shift = (kcontrol->private_value >> 16) & 0x0f;
0391     int right_shift = (kcontrol->private_value >> 24) & 0x0f;
0392     unsigned char val1, val2;
0393 
0394     spin_lock_irqsave(&sb->mixer_lock, flags);
0395     val1 = snd_sbmixer_read(sb, reg1);
0396     val2 = snd_sbmixer_read(sb, reg2);
0397     spin_unlock_irqrestore(&sb->mixer_lock, flags);
0398     ucontrol->value.integer.value[0] = (val1 >> left_shift) & 0x01;
0399     ucontrol->value.integer.value[1] = (val2 >> left_shift) & 0x01;
0400     ucontrol->value.integer.value[2] = (val1 >> right_shift) & 0x01;
0401     ucontrol->value.integer.value[3] = (val2 >> right_shift) & 0x01;
0402     return 0;
0403 }                                                                                                                   
0404 
0405 static int snd_sb16mixer_put_input_sw(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
0406 {
0407     struct snd_sb *sb = snd_kcontrol_chip(kcontrol);
0408     unsigned long flags;
0409     int reg1 = kcontrol->private_value & 0xff;
0410     int reg2 = (kcontrol->private_value >> 8) & 0xff;
0411     int left_shift = (kcontrol->private_value >> 16) & 0x0f;
0412     int right_shift = (kcontrol->private_value >> 24) & 0x0f;
0413     int change;
0414     unsigned char val1, val2, oval1, oval2;
0415 
0416     spin_lock_irqsave(&sb->mixer_lock, flags);
0417     oval1 = snd_sbmixer_read(sb, reg1);
0418     oval2 = snd_sbmixer_read(sb, reg2);
0419     val1 = oval1 & ~((1 << left_shift) | (1 << right_shift));
0420     val2 = oval2 & ~((1 << left_shift) | (1 << right_shift));
0421     val1 |= (ucontrol->value.integer.value[0] & 1) << left_shift;
0422     val2 |= (ucontrol->value.integer.value[1] & 1) << left_shift;
0423     val1 |= (ucontrol->value.integer.value[2] & 1) << right_shift;
0424     val2 |= (ucontrol->value.integer.value[3] & 1) << right_shift;
0425     change = val1 != oval1 || val2 != oval2;
0426     if (change) {
0427         snd_sbmixer_write(sb, reg1, val1);
0428         snd_sbmixer_write(sb, reg2, val2);
0429     }
0430     spin_unlock_irqrestore(&sb->mixer_lock, flags);
0431     return change;
0432 }
0433 
0434 
0435 /*
0436  */
0437 /*
0438  */
0439 int snd_sbmixer_add_ctl(struct snd_sb *chip, const char *name, int index, int type, unsigned long value)
0440 {
0441     static const struct snd_kcontrol_new newctls[] = {
0442         [SB_MIX_SINGLE] = {
0443             .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
0444             .info = snd_sbmixer_info_single,
0445             .get = snd_sbmixer_get_single,
0446             .put = snd_sbmixer_put_single,
0447         },
0448         [SB_MIX_DOUBLE] = {
0449             .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
0450             .info = snd_sbmixer_info_double,
0451             .get = snd_sbmixer_get_double,
0452             .put = snd_sbmixer_put_double,
0453         },
0454         [SB_MIX_INPUT_SW] = {
0455             .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
0456             .info = snd_sb16mixer_info_input_sw,
0457             .get = snd_sb16mixer_get_input_sw,
0458             .put = snd_sb16mixer_put_input_sw,
0459         },
0460         [SB_MIX_CAPTURE_PRO] = {
0461             .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
0462             .info = snd_sb8mixer_info_mux,
0463             .get = snd_sb8mixer_get_mux,
0464             .put = snd_sb8mixer_put_mux,
0465         },
0466         [SB_MIX_CAPTURE_DT019X] = {
0467             .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
0468             .info = snd_dt019x_input_sw_info,
0469             .get = snd_dt019x_input_sw_get,
0470             .put = snd_dt019x_input_sw_put,
0471         },
0472         [SB_MIX_MONO_CAPTURE_ALS4K] = {
0473             .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
0474             .info = snd_als4k_mono_capture_route_info,
0475             .get = snd_als4k_mono_capture_route_get,
0476             .put = snd_als4k_mono_capture_route_put,
0477         },
0478     };
0479     struct snd_kcontrol *ctl;
0480     int err;
0481 
0482     ctl = snd_ctl_new1(&newctls[type], chip);
0483     if (! ctl)
0484         return -ENOMEM;
0485     strscpy(ctl->id.name, name, sizeof(ctl->id.name));
0486     ctl->id.index = index;
0487     ctl->private_value = value;
0488     err = snd_ctl_add(chip->card, ctl);
0489     if (err < 0)
0490         return err;
0491     return 0;
0492 }
0493 
0494 /*
0495  * SB 2.0 specific mixer elements
0496  */
0497 
0498 static const struct sbmix_elem snd_sb20_controls[] = {
0499     SB_SINGLE("Master Playback Volume", SB_DSP20_MASTER_DEV, 1, 7),
0500     SB_SINGLE("PCM Playback Volume", SB_DSP20_PCM_DEV, 1, 3),
0501     SB_SINGLE("Synth Playback Volume", SB_DSP20_FM_DEV, 1, 7),
0502     SB_SINGLE("CD Playback Volume", SB_DSP20_CD_DEV, 1, 7)
0503 };
0504 
0505 static const unsigned char snd_sb20_init_values[][2] = {
0506     { SB_DSP20_MASTER_DEV, 0 },
0507     { SB_DSP20_FM_DEV, 0 },
0508 };
0509 
0510 /*
0511  * SB Pro specific mixer elements
0512  */
0513 static const struct sbmix_elem snd_sbpro_controls[] = {
0514     SB_DOUBLE("Master Playback Volume",
0515           SB_DSP_MASTER_DEV, SB_DSP_MASTER_DEV, 5, 1, 7),
0516     SB_DOUBLE("PCM Playback Volume",
0517           SB_DSP_PCM_DEV, SB_DSP_PCM_DEV, 5, 1, 7),
0518     SB_SINGLE("PCM Playback Filter", SB_DSP_PLAYBACK_FILT, 5, 1),
0519     SB_DOUBLE("Synth Playback Volume",
0520           SB_DSP_FM_DEV, SB_DSP_FM_DEV, 5, 1, 7),
0521     SB_DOUBLE("CD Playback Volume", SB_DSP_CD_DEV, SB_DSP_CD_DEV, 5, 1, 7),
0522     SB_DOUBLE("Line Playback Volume",
0523           SB_DSP_LINE_DEV, SB_DSP_LINE_DEV, 5, 1, 7),
0524     SB_SINGLE("Mic Playback Volume", SB_DSP_MIC_DEV, 1, 3),
0525     {
0526         .name = "Capture Source",
0527         .type = SB_MIX_CAPTURE_PRO
0528     },
0529     SB_SINGLE("Capture Filter", SB_DSP_CAPTURE_FILT, 5, 1),
0530     SB_SINGLE("Capture Low-Pass Filter", SB_DSP_CAPTURE_FILT, 3, 1)
0531 };
0532 
0533 static const unsigned char snd_sbpro_init_values[][2] = {
0534     { SB_DSP_MASTER_DEV, 0 },
0535     { SB_DSP_PCM_DEV, 0 },
0536     { SB_DSP_FM_DEV, 0 },
0537 };
0538 
0539 /*
0540  * SB16 specific mixer elements
0541  */
0542 static const struct sbmix_elem snd_sb16_controls[] = {
0543     SB_DOUBLE("Master Playback Volume",
0544           SB_DSP4_MASTER_DEV, (SB_DSP4_MASTER_DEV + 1), 3, 3, 31),
0545     SB_DOUBLE("PCM Playback Volume",
0546           SB_DSP4_PCM_DEV, (SB_DSP4_PCM_DEV + 1), 3, 3, 31),
0547     SB16_INPUT_SW("Synth Capture Route",
0548               SB_DSP4_INPUT_LEFT, SB_DSP4_INPUT_RIGHT, 6, 5),
0549     SB_DOUBLE("Synth Playback Volume",
0550           SB_DSP4_SYNTH_DEV, (SB_DSP4_SYNTH_DEV + 1), 3, 3, 31),
0551     SB16_INPUT_SW("CD Capture Route",
0552               SB_DSP4_INPUT_LEFT, SB_DSP4_INPUT_RIGHT, 2, 1),
0553     SB_DOUBLE("CD Playback Switch",
0554           SB_DSP4_OUTPUT_SW, SB_DSP4_OUTPUT_SW, 2, 1, 1),
0555     SB_DOUBLE("CD Playback Volume",
0556           SB_DSP4_CD_DEV, (SB_DSP4_CD_DEV + 1), 3, 3, 31),
0557     SB16_INPUT_SW("Mic Capture Route",
0558               SB_DSP4_INPUT_LEFT, SB_DSP4_INPUT_RIGHT, 0, 0),
0559     SB_SINGLE("Mic Playback Switch", SB_DSP4_OUTPUT_SW, 0, 1),
0560     SB_SINGLE("Mic Playback Volume", SB_DSP4_MIC_DEV, 3, 31),
0561     SB_SINGLE("Beep Volume", SB_DSP4_SPEAKER_DEV, 6, 3),
0562     SB_DOUBLE("Capture Volume",
0563           SB_DSP4_IGAIN_DEV, (SB_DSP4_IGAIN_DEV + 1), 6, 6, 3),
0564     SB_DOUBLE("Playback Volume",
0565           SB_DSP4_OGAIN_DEV, (SB_DSP4_OGAIN_DEV + 1), 6, 6, 3),
0566     SB16_INPUT_SW("Line Capture Route",
0567               SB_DSP4_INPUT_LEFT, SB_DSP4_INPUT_RIGHT, 4, 3),
0568     SB_DOUBLE("Line Playback Switch",
0569           SB_DSP4_OUTPUT_SW, SB_DSP4_OUTPUT_SW, 4, 3, 1),
0570     SB_DOUBLE("Line Playback Volume",
0571           SB_DSP4_LINE_DEV, (SB_DSP4_LINE_DEV + 1), 3, 3, 31),
0572     SB_SINGLE("Mic Auto Gain", SB_DSP4_MIC_AGC, 0, 1),
0573     SB_SINGLE("3D Enhancement Switch", SB_DSP4_3DSE, 0, 1),
0574     SB_DOUBLE("Tone Control - Bass",
0575           SB_DSP4_BASS_DEV, (SB_DSP4_BASS_DEV + 1), 4, 4, 15),
0576     SB_DOUBLE("Tone Control - Treble",
0577           SB_DSP4_TREBLE_DEV, (SB_DSP4_TREBLE_DEV + 1), 4, 4, 15)
0578 };
0579 
0580 static const unsigned char snd_sb16_init_values[][2] = {
0581     { SB_DSP4_MASTER_DEV + 0, 0 },
0582     { SB_DSP4_MASTER_DEV + 1, 0 },
0583     { SB_DSP4_PCM_DEV + 0, 0 },
0584     { SB_DSP4_PCM_DEV + 1, 0 },
0585     { SB_DSP4_SYNTH_DEV + 0, 0 },
0586     { SB_DSP4_SYNTH_DEV + 1, 0 },
0587     { SB_DSP4_INPUT_LEFT, 0 },
0588     { SB_DSP4_INPUT_RIGHT, 0 },
0589     { SB_DSP4_OUTPUT_SW, 0 },
0590     { SB_DSP4_SPEAKER_DEV, 0 },
0591 };
0592 
0593 /*
0594  * DT019x specific mixer elements
0595  */
0596 static const struct sbmix_elem snd_dt019x_controls[] = {
0597     /* ALS4000 below has some parts which we might be lacking,
0598      * e.g. snd_als4000_ctl_mono_playback_switch - check it! */
0599     SB_DOUBLE("Master Playback Volume",
0600           SB_DT019X_MASTER_DEV, SB_DT019X_MASTER_DEV, 4, 0, 15),
0601     SB_DOUBLE("PCM Playback Switch",
0602           SB_DT019X_OUTPUT_SW2, SB_DT019X_OUTPUT_SW2, 2, 1, 1),
0603     SB_DOUBLE("PCM Playback Volume",
0604           SB_DT019X_PCM_DEV, SB_DT019X_PCM_DEV, 4, 0, 15),
0605     SB_DOUBLE("Synth Playback Switch",
0606           SB_DT019X_OUTPUT_SW2, SB_DT019X_OUTPUT_SW2, 4, 3, 1),
0607     SB_DOUBLE("Synth Playback Volume",
0608           SB_DT019X_SYNTH_DEV, SB_DT019X_SYNTH_DEV, 4, 0, 15),
0609     SB_DOUBLE("CD Playback Switch",
0610           SB_DSP4_OUTPUT_SW, SB_DSP4_OUTPUT_SW, 2, 1, 1),
0611     SB_DOUBLE("CD Playback Volume",
0612           SB_DT019X_CD_DEV, SB_DT019X_CD_DEV, 4, 0, 15),
0613     SB_SINGLE("Mic Playback Switch", SB_DSP4_OUTPUT_SW, 0, 1),
0614     SB_SINGLE("Mic Playback Volume", SB_DT019X_MIC_DEV, 4, 7),
0615     SB_SINGLE("Beep Volume", SB_DT019X_SPKR_DEV, 0,  7),
0616     SB_DOUBLE("Line Playback Switch",
0617           SB_DSP4_OUTPUT_SW, SB_DSP4_OUTPUT_SW, 4, 3, 1),
0618     SB_DOUBLE("Line Playback Volume",
0619           SB_DT019X_LINE_DEV, SB_DT019X_LINE_DEV, 4, 0, 15),
0620     {
0621         .name = "Capture Source",
0622         .type = SB_MIX_CAPTURE_DT019X
0623     }
0624 };
0625 
0626 static const unsigned char snd_dt019x_init_values[][2] = {
0627         { SB_DT019X_MASTER_DEV, 0 },
0628         { SB_DT019X_PCM_DEV, 0 },
0629         { SB_DT019X_SYNTH_DEV, 0 },
0630         { SB_DT019X_CD_DEV, 0 },
0631         { SB_DT019X_MIC_DEV, 0 },   /* Includes PC-speaker in high nibble */
0632         { SB_DT019X_LINE_DEV, 0 },
0633         { SB_DSP4_OUTPUT_SW, 0 },
0634         { SB_DT019X_OUTPUT_SW2, 0 },
0635         { SB_DT019X_CAPTURE_SW, 0x06 },
0636 };
0637 
0638 /*
0639  * ALS4000 specific mixer elements
0640  */
0641 static const struct sbmix_elem snd_als4000_controls[] = {
0642     SB_DOUBLE("PCM Playback Switch",
0643           SB_DT019X_OUTPUT_SW2, SB_DT019X_OUTPUT_SW2, 2, 1, 1),
0644     SB_DOUBLE("Synth Playback Switch",
0645           SB_DT019X_OUTPUT_SW2, SB_DT019X_OUTPUT_SW2, 4, 3, 1),
0646     SB_SINGLE("Mic Boost (+20dB)", SB_ALS4000_MIC_IN_GAIN, 0, 0x03),
0647     SB_SINGLE("Master Mono Playback Switch", SB_ALS4000_MONO_IO_CTRL, 5, 1),
0648     {
0649         .name = "Master Mono Capture Route",
0650         .type = SB_MIX_MONO_CAPTURE_ALS4K
0651     },
0652     SB_SINGLE("Mono Playback Switch", SB_DT019X_OUTPUT_SW2, 0, 1),
0653     SB_SINGLE("Analog Loopback Switch", SB_ALS4000_MIC_IN_GAIN, 7, 0x01),
0654     SB_SINGLE("3D Control - Switch", SB_ALS4000_3D_SND_FX, 6, 0x01),
0655     SB_SINGLE("Digital Loopback Switch",
0656           SB_ALS4000_CR3_CONFIGURATION, 7, 0x01),
0657     /* FIXME: functionality of 3D controls might be swapped, I didn't find
0658      * a description of how to identify what is supposed to be what */
0659     SB_SINGLE("3D Control - Level", SB_ALS4000_3D_SND_FX, 0, 0x07),
0660     /* FIXME: maybe there's actually some standard 3D ctrl name for it?? */
0661     SB_SINGLE("3D Control - Freq", SB_ALS4000_3D_SND_FX, 4, 0x03),
0662     /* FIXME: ALS4000a.pdf mentions BBD (Bucket Brigade Device) time delay,
0663      * but what ALSA 3D attribute is that actually? "Center", "Depth",
0664      * "Wide" or "Space" or even "Level"? Assuming "Wide" for now... */
0665     SB_SINGLE("3D Control - Wide", SB_ALS4000_3D_TIME_DELAY, 0, 0x0f),
0666     SB_SINGLE("3D PowerOff Switch", SB_ALS4000_3D_TIME_DELAY, 4, 0x01),
0667     SB_SINGLE("Master Playback 8kHz / 20kHz LPF Switch",
0668           SB_ALS4000_FMDAC, 5, 0x01),
0669 #ifdef NOT_AVAILABLE
0670     SB_SINGLE("FMDAC Switch (Option ?)", SB_ALS4000_FMDAC, 0, 0x01),
0671     SB_SINGLE("QSound Mode", SB_ALS4000_QSOUND, 1, 0x1f),
0672 #endif
0673 };
0674 
0675 static const unsigned char snd_als4000_init_values[][2] = {
0676     { SB_DSP4_MASTER_DEV + 0, 0 },
0677     { SB_DSP4_MASTER_DEV + 1, 0 },
0678     { SB_DSP4_PCM_DEV + 0, 0 },
0679     { SB_DSP4_PCM_DEV + 1, 0 },
0680     { SB_DSP4_SYNTH_DEV + 0, 0 },
0681     { SB_DSP4_SYNTH_DEV + 1, 0 },
0682     { SB_DSP4_SPEAKER_DEV, 0 },
0683     { SB_DSP4_OUTPUT_SW, 0 },
0684     { SB_DSP4_INPUT_LEFT, 0 },
0685     { SB_DSP4_INPUT_RIGHT, 0 },
0686     { SB_DT019X_OUTPUT_SW2, 0 },
0687     { SB_ALS4000_MIC_IN_GAIN, 0 },
0688 };
0689 
0690 /*
0691  */
0692 static int snd_sbmixer_init(struct snd_sb *chip,
0693                 const struct sbmix_elem *controls,
0694                 int controls_count,
0695                 const unsigned char map[][2],
0696                 int map_count,
0697                 char *name)
0698 {
0699     unsigned long flags;
0700     struct snd_card *card = chip->card;
0701     int idx, err;
0702 
0703     /* mixer reset */
0704     spin_lock_irqsave(&chip->mixer_lock, flags);
0705     snd_sbmixer_write(chip, 0x00, 0x00);
0706     spin_unlock_irqrestore(&chip->mixer_lock, flags);
0707 
0708     /* mute and zero volume channels */
0709     for (idx = 0; idx < map_count; idx++) {
0710         spin_lock_irqsave(&chip->mixer_lock, flags);
0711         snd_sbmixer_write(chip, map[idx][0], map[idx][1]);
0712         spin_unlock_irqrestore(&chip->mixer_lock, flags);
0713     }
0714 
0715     for (idx = 0; idx < controls_count; idx++) {
0716         err = snd_sbmixer_add_ctl_elem(chip, &controls[idx]);
0717         if (err < 0)
0718             return err;
0719     }
0720     snd_component_add(card, name);
0721     strcpy(card->mixername, name);
0722     return 0;
0723 }
0724 
0725 int snd_sbmixer_new(struct snd_sb *chip)
0726 {
0727     struct snd_card *card;
0728     int err;
0729 
0730     if (snd_BUG_ON(!chip || !chip->card))
0731         return -EINVAL;
0732 
0733     card = chip->card;
0734 
0735     switch (chip->hardware) {
0736     case SB_HW_10:
0737         return 0; /* no mixer chip on SB1.x */
0738     case SB_HW_20:
0739     case SB_HW_201:
0740         err = snd_sbmixer_init(chip,
0741                        snd_sb20_controls,
0742                        ARRAY_SIZE(snd_sb20_controls),
0743                        snd_sb20_init_values,
0744                        ARRAY_SIZE(snd_sb20_init_values),
0745                        "CTL1335");
0746         if (err < 0)
0747             return err;
0748         break;
0749     case SB_HW_PRO:
0750     case SB_HW_JAZZ16:
0751         err = snd_sbmixer_init(chip,
0752                        snd_sbpro_controls,
0753                        ARRAY_SIZE(snd_sbpro_controls),
0754                        snd_sbpro_init_values,
0755                        ARRAY_SIZE(snd_sbpro_init_values),
0756                        "CTL1345");
0757         if (err < 0)
0758             return err;
0759         break;
0760     case SB_HW_16:
0761     case SB_HW_ALS100:
0762     case SB_HW_CS5530:
0763         err = snd_sbmixer_init(chip,
0764                        snd_sb16_controls,
0765                        ARRAY_SIZE(snd_sb16_controls),
0766                        snd_sb16_init_values,
0767                        ARRAY_SIZE(snd_sb16_init_values),
0768                        "CTL1745");
0769         if (err < 0)
0770             return err;
0771         break;
0772     case SB_HW_ALS4000:
0773         /* use only the first 16 controls from SB16 */
0774         err = snd_sbmixer_init(chip,
0775                     snd_sb16_controls,
0776                     16,
0777                     snd_sb16_init_values,
0778                     ARRAY_SIZE(snd_sb16_init_values),
0779                     "ALS4000");
0780         if (err < 0)
0781             return err;
0782         err = snd_sbmixer_init(chip,
0783                        snd_als4000_controls,
0784                        ARRAY_SIZE(snd_als4000_controls),
0785                        snd_als4000_init_values,
0786                        ARRAY_SIZE(snd_als4000_init_values),
0787                        "ALS4000");
0788         if (err < 0)
0789             return err;
0790         break;
0791     case SB_HW_DT019X:
0792         err = snd_sbmixer_init(chip,
0793                        snd_dt019x_controls,
0794                        ARRAY_SIZE(snd_dt019x_controls),
0795                        snd_dt019x_init_values,
0796                        ARRAY_SIZE(snd_dt019x_init_values),
0797                        "DT019X");
0798         if (err < 0)
0799             return err;
0800         break;
0801     default:
0802         strcpy(card->mixername, "???");
0803     }
0804     return 0;
0805 }
0806 
0807 #ifdef CONFIG_PM
0808 static const unsigned char sb20_saved_regs[] = {
0809     SB_DSP20_MASTER_DEV,
0810     SB_DSP20_PCM_DEV,
0811     SB_DSP20_FM_DEV,
0812     SB_DSP20_CD_DEV,
0813 };
0814 
0815 static const unsigned char sbpro_saved_regs[] = {
0816     SB_DSP_MASTER_DEV,
0817     SB_DSP_PCM_DEV,
0818     SB_DSP_PLAYBACK_FILT,
0819     SB_DSP_FM_DEV,
0820     SB_DSP_CD_DEV,
0821     SB_DSP_LINE_DEV,
0822     SB_DSP_MIC_DEV,
0823     SB_DSP_CAPTURE_SOURCE,
0824     SB_DSP_CAPTURE_FILT,
0825 };
0826 
0827 static const unsigned char sb16_saved_regs[] = {
0828     SB_DSP4_MASTER_DEV, SB_DSP4_MASTER_DEV + 1,
0829     SB_DSP4_3DSE,
0830     SB_DSP4_BASS_DEV, SB_DSP4_BASS_DEV + 1,
0831     SB_DSP4_TREBLE_DEV, SB_DSP4_TREBLE_DEV + 1,
0832     SB_DSP4_PCM_DEV, SB_DSP4_PCM_DEV + 1,
0833     SB_DSP4_INPUT_LEFT, SB_DSP4_INPUT_RIGHT,
0834     SB_DSP4_SYNTH_DEV, SB_DSP4_SYNTH_DEV + 1,
0835     SB_DSP4_OUTPUT_SW,
0836     SB_DSP4_CD_DEV, SB_DSP4_CD_DEV + 1,
0837     SB_DSP4_LINE_DEV, SB_DSP4_LINE_DEV + 1,
0838     SB_DSP4_MIC_DEV,
0839     SB_DSP4_SPEAKER_DEV,
0840     SB_DSP4_IGAIN_DEV, SB_DSP4_IGAIN_DEV + 1,
0841     SB_DSP4_OGAIN_DEV, SB_DSP4_OGAIN_DEV + 1,
0842     SB_DSP4_MIC_AGC
0843 };
0844 
0845 static const unsigned char dt019x_saved_regs[] = {
0846     SB_DT019X_MASTER_DEV,
0847     SB_DT019X_PCM_DEV,
0848     SB_DT019X_SYNTH_DEV,
0849     SB_DT019X_CD_DEV,
0850     SB_DT019X_MIC_DEV,
0851     SB_DT019X_SPKR_DEV,
0852     SB_DT019X_LINE_DEV,
0853     SB_DSP4_OUTPUT_SW,
0854     SB_DT019X_OUTPUT_SW2,
0855     SB_DT019X_CAPTURE_SW,
0856 };
0857 
0858 static const unsigned char als4000_saved_regs[] = {
0859     /* please verify in dsheet whether regs to be added
0860        are actually real H/W or just dummy */
0861     SB_DSP4_MASTER_DEV, SB_DSP4_MASTER_DEV + 1,
0862     SB_DSP4_OUTPUT_SW,
0863     SB_DSP4_PCM_DEV, SB_DSP4_PCM_DEV + 1,
0864     SB_DSP4_INPUT_LEFT, SB_DSP4_INPUT_RIGHT,
0865     SB_DSP4_SYNTH_DEV, SB_DSP4_SYNTH_DEV + 1,
0866     SB_DSP4_CD_DEV, SB_DSP4_CD_DEV + 1,
0867     SB_DSP4_MIC_DEV,
0868     SB_DSP4_SPEAKER_DEV,
0869     SB_DSP4_IGAIN_DEV, SB_DSP4_IGAIN_DEV + 1,
0870     SB_DSP4_OGAIN_DEV, SB_DSP4_OGAIN_DEV + 1,
0871     SB_DT019X_OUTPUT_SW2,
0872     SB_ALS4000_MONO_IO_CTRL,
0873     SB_ALS4000_MIC_IN_GAIN,
0874     SB_ALS4000_FMDAC,
0875     SB_ALS4000_3D_SND_FX,
0876     SB_ALS4000_3D_TIME_DELAY,
0877     SB_ALS4000_CR3_CONFIGURATION,
0878 };
0879 
0880 static void save_mixer(struct snd_sb *chip, const unsigned char *regs, int num_regs)
0881 {
0882     unsigned char *val = chip->saved_regs;
0883     if (snd_BUG_ON(num_regs > ARRAY_SIZE(chip->saved_regs)))
0884         return;
0885     for (; num_regs; num_regs--)
0886         *val++ = snd_sbmixer_read(chip, *regs++);
0887 }
0888 
0889 static void restore_mixer(struct snd_sb *chip, const unsigned char *regs, int num_regs)
0890 {
0891     unsigned char *val = chip->saved_regs;
0892     if (snd_BUG_ON(num_regs > ARRAY_SIZE(chip->saved_regs)))
0893         return;
0894     for (; num_regs; num_regs--)
0895         snd_sbmixer_write(chip, *regs++, *val++);
0896 }
0897 
0898 void snd_sbmixer_suspend(struct snd_sb *chip)
0899 {
0900     switch (chip->hardware) {
0901     case SB_HW_20:
0902     case SB_HW_201:
0903         save_mixer(chip, sb20_saved_regs, ARRAY_SIZE(sb20_saved_regs));
0904         break;
0905     case SB_HW_PRO:
0906     case SB_HW_JAZZ16:
0907         save_mixer(chip, sbpro_saved_regs, ARRAY_SIZE(sbpro_saved_regs));
0908         break;
0909     case SB_HW_16:
0910     case SB_HW_ALS100:
0911     case SB_HW_CS5530:
0912         save_mixer(chip, sb16_saved_regs, ARRAY_SIZE(sb16_saved_regs));
0913         break;
0914     case SB_HW_ALS4000:
0915         save_mixer(chip, als4000_saved_regs, ARRAY_SIZE(als4000_saved_regs));
0916         break;
0917     case SB_HW_DT019X:
0918         save_mixer(chip, dt019x_saved_regs, ARRAY_SIZE(dt019x_saved_regs));
0919         break;
0920     default:
0921         break;
0922     }
0923 }
0924 
0925 void snd_sbmixer_resume(struct snd_sb *chip)
0926 {
0927     switch (chip->hardware) {
0928     case SB_HW_20:
0929     case SB_HW_201:
0930         restore_mixer(chip, sb20_saved_regs, ARRAY_SIZE(sb20_saved_regs));
0931         break;
0932     case SB_HW_PRO:
0933     case SB_HW_JAZZ16:
0934         restore_mixer(chip, sbpro_saved_regs, ARRAY_SIZE(sbpro_saved_regs));
0935         break;
0936     case SB_HW_16:
0937     case SB_HW_ALS100:
0938     case SB_HW_CS5530:
0939         restore_mixer(chip, sb16_saved_regs, ARRAY_SIZE(sb16_saved_regs));
0940         break;
0941     case SB_HW_ALS4000:
0942         restore_mixer(chip, als4000_saved_regs, ARRAY_SIZE(als4000_saved_regs));
0943         break;
0944     case SB_HW_DT019X:
0945         restore_mixer(chip, dt019x_saved_regs, ARRAY_SIZE(dt019x_saved_regs));
0946         break;
0947     default:
0948         break;
0949     }
0950 }
0951 #endif