Ignore:
Timestamp:
Dec 11, 2005, 5:57:39 PM (20 years ago)
Author:
vladest
Message:

Latest update from ALSA. some intial > 15 interrupts support

Location:
GPL/trunk/alsa-kernel/isa/sb
Files:
2 edited

Legend:

Unmodified
Added
Removed
  • GPL/trunk/alsa-kernel/isa/sb/sb_common.c

    r33 r34  
    3434#undef IO_DEBUG
    3535
    36 int snd_sbdsp_command(sb_t *chip, unsigned char val)
     36int snd_sbdsp_command(struct snd_sb *chip, unsigned char val)
    3737{
    3838    int i;
     
    4949}
    5050
    51 int snd_sbdsp_get_byte(sb_t *chip)
     51int snd_sbdsp_get_byte(struct snd_sb *chip)
    5252{
    5353    int val;
     
    6666}
    6767
    68 int snd_sbdsp_reset(sb_t *chip)
     68int snd_sbdsp_reset(struct snd_sb *chip)
    6969{
    7070    int i;
     
    8585}
    8686
    87 int snd_sbdsp_version(sb_t * chip)
     87int snd_sbdsp_version(struct snd_sb * chip)
    8888{
    8989    unsigned int result = -ENODEV;
     
    9595}
    9696
    97 static int snd_sbdsp_probe(sb_t * chip)
     97static int snd_sbdsp_probe(struct snd_sb * chip)
    9898{
    9999    int version;
     
    166166}
    167167
    168 static int snd_sbdsp_free(sb_t *chip)
     168static int snd_sbdsp_free(struct snd_sb *chip)
    169169{
    170170    if (chip->res_port)
    171171        release_resource(chip->res_port);
    172     if (chip->res_alt_port)
    173         release_resource(chip->res_alt_port);
    174172    if (chip->irq >= 0)
    175173        free_irq(chip->irq, (void *) chip);
     
    188186static int snd_sbdsp_dev_free(snd_device_t *device)
    189187{
    190     sb_t *chip = device->device_data;
     188    struct snd_sb *chip = device->device_data;
    191189    return snd_sbdsp_free(chip);
    192190}
     
    195193                     unsigned long port,
    196194                     int irq,
    197                      void (*irq_handler)(int, void *, struct pt_regs *),
     195                     irqreturn_t (*irq_handler)(int, void *, struct pt_regs *),
    198196                     int dma8,
    199197                     int dma16,
    200198                     unsigned short hardware,
    201                      sb_t **r_chip)
    202 {
    203     sb_t *chip;
     199                     struct snd_sb **r_chip)
     200{
     201    struct snd_sb *chip;
    204202    int err;
    205203#ifdef TARGET_OS2
  • GPL/trunk/alsa-kernel/isa/sb/sb_mixer.c

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