linux/sound/core/vmaster.c
<<
>>
Prefs
   1/*
   2 * Virtual master and slave controls
   3 *
   4 *  Copyright (c) 2008 by Takashi Iwai <tiwai@suse.de>
   5 *
   6 *  This program is free software; you can redistribute it and/or
   7 *  modify it under the terms of the GNU General Public License as
   8 *  published by the Free Software Foundation, version 2.
   9 *
  10 */
  11
  12#include <linux/slab.h>
  13#include <sound/core.h>
  14#include <sound/control.h>
  15#include <sound/tlv.h>
  16
  17/*
  18 * a subset of information returned via ctl info callback
  19 */
  20struct link_ctl_info {
  21        int type;               /* value type */
  22        int count;              /* item count */
  23        int min_val, max_val;   /* min, max values */
  24};
  25
  26/*
  27 * link master - this contains a list of slave controls that are
  28 * identical types, i.e. info returns the same value type and value
  29 * ranges, but may have different number of counts.
  30 *
  31 * The master control is so far only mono volume/switch for simplicity.
  32 * The same value will be applied to all slaves.
  33 */
  34struct link_master {
  35        struct list_head slaves;
  36        struct link_ctl_info info;
  37        int val;                /* the master value */
  38        unsigned int tlv[4];
  39};
  40
  41/*
  42 * link slave - this contains a slave control element
  43 *
  44 * It fakes the control callbacsk with additional attenuation by the
  45 * master control.  A slave may have either one or two channels.
  46 */
  47
  48struct link_slave {
  49        struct list_head list;
  50        struct link_master *master;
  51        struct link_ctl_info info;
  52        int vals[2];            /* current values */
  53        struct snd_kcontrol slave; /* the copy of original control entry */
  54};
  55
  56/* get the slave ctl info and save the initial values */
  57static int slave_init(struct link_slave *slave)
  58{
  59        struct snd_ctl_elem_info *uinfo;
  60        struct snd_ctl_elem_value *uctl;
  61        int err, ch;
  62
  63        if (slave->info.count)
  64                return 0; /* already initialized */
  65
  66        uinfo = kmalloc(sizeof(*uinfo), GFP_KERNEL);
  67        if (!uinfo)
  68                return -ENOMEM;
  69        uinfo->id = slave->slave.id;
  70        err = slave->slave.info(&slave->slave, uinfo);
  71        if (err < 0) {
  72                kfree(uinfo);
  73                return err;
  74        }
  75        slave->info.type = uinfo->type;
  76        slave->info.count = uinfo->count;
  77        if (slave->info.count > 2  ||
  78            (slave->info.type != SNDRV_CTL_ELEM_TYPE_INTEGER &&
  79             slave->info.type != SNDRV_CTL_ELEM_TYPE_BOOLEAN)) {
  80                snd_printk(KERN_ERR "invalid slave element\n");
  81                kfree(uinfo);
  82                return -EINVAL;
  83        }
  84        slave->info.min_val = uinfo->value.integer.min;
  85        slave->info.max_val = uinfo->value.integer.max;
  86        kfree(uinfo);
  87
  88        uctl = kmalloc(sizeof(*uctl), GFP_KERNEL);
  89        if (!uctl)
  90                return -ENOMEM;
  91        uctl->id = slave->slave.id;
  92        err = slave->slave.get(&slave->slave, uctl);
  93        for (ch = 0; ch < slave->info.count; ch++)
  94                slave->vals[ch] = uctl->value.integer.value[ch];
  95        kfree(uctl);
  96        return 0;
  97}
  98
  99/* initialize master volume */
 100static int master_init(struct link_master *master)
 101{
 102        struct link_slave *slave;
 103
 104        if (master->info.count)
 105                return 0; /* already initialized */
 106
 107        list_for_each_entry(slave, &master->slaves, list) {
 108                int err = slave_init(slave);
 109                if (err < 0)
 110                        return err;
 111                master->info = slave->info;
 112                master->info.count = 1; /* always mono */
 113                /* set full volume as default (= no attenuation) */
 114                master->val = master->info.max_val;
 115                return 0;
 116        }
 117        return -ENOENT;
 118}
 119
 120static int slave_get_val(struct link_slave *slave,
 121                         struct snd_ctl_elem_value *ucontrol)
 122{
 123        int err, ch;
 124
 125        err = slave_init(slave);
 126        if (err < 0)
 127                return err;
 128        for (ch = 0; ch < slave->info.count; ch++)
 129                ucontrol->value.integer.value[ch] = slave->vals[ch];
 130        return 0;
 131}
 132
 133static int slave_put_val(struct link_slave *slave,
 134                         struct snd_ctl_elem_value *ucontrol)
 135{
 136        int err, ch, vol;
 137
 138        err = master_init(slave->master);
 139        if (err < 0)
 140                return err;
 141
 142        switch (slave->info.type) {
 143        case SNDRV_CTL_ELEM_TYPE_BOOLEAN:
 144                for (ch = 0; ch < slave->info.count; ch++)
 145                        ucontrol->value.integer.value[ch] &=
 146                                !!slave->master->val;
 147                break;
 148        case SNDRV_CTL_ELEM_TYPE_INTEGER:
 149                for (ch = 0; ch < slave->info.count; ch++) {
 150                        /* max master volume is supposed to be 0 dB */
 151                        vol = ucontrol->value.integer.value[ch];
 152                        vol += slave->master->val - slave->master->info.max_val;
 153                        if (vol < slave->info.min_val)
 154                                vol = slave->info.min_val;
 155                        else if (vol > slave->info.max_val)
 156                                vol = slave->info.max_val;
 157                        ucontrol->value.integer.value[ch] = vol;
 158                }
 159                break;
 160        }
 161        return slave->slave.put(&slave->slave, ucontrol);
 162}
 163
 164/*
 165 * ctl callbacks for slaves
 166 */
 167static int slave_info(struct snd_kcontrol *kcontrol,
 168                      struct snd_ctl_elem_info *uinfo)
 169{
 170        struct link_slave *slave = snd_kcontrol_chip(kcontrol);
 171        return slave->slave.info(&slave->slave, uinfo);
 172}
 173
 174static int slave_get(struct snd_kcontrol *kcontrol,
 175                     struct snd_ctl_elem_value *ucontrol)
 176{
 177        struct link_slave *slave = snd_kcontrol_chip(kcontrol);
 178        return slave_get_val(slave, ucontrol);
 179}
 180
 181static int slave_put(struct snd_kcontrol *kcontrol,
 182                     struct snd_ctl_elem_value *ucontrol)
 183{
 184        struct link_slave *slave = snd_kcontrol_chip(kcontrol);
 185        int err, ch, changed = 0;
 186
 187        err = slave_init(slave);
 188        if (err < 0)
 189                return err;
 190        for (ch = 0; ch < slave->info.count; ch++) {
 191                if (slave->vals[ch] != ucontrol->value.integer.value[ch]) {
 192                        changed = 1;
 193                        slave->vals[ch] = ucontrol->value.integer.value[ch];
 194                }
 195        }
 196        if (!changed)
 197                return 0;
 198        return slave_put_val(slave, ucontrol);
 199}
 200
 201static int slave_tlv_cmd(struct snd_kcontrol *kcontrol,
 202                         int op_flag, unsigned int size,
 203                         unsigned int __user *tlv)
 204{
 205        struct link_slave *slave = snd_kcontrol_chip(kcontrol);
 206        /* FIXME: this assumes that the max volume is 0 dB */
 207        return slave->slave.tlv.c(&slave->slave, op_flag, size, tlv);
 208}
 209
 210static void slave_free(struct snd_kcontrol *kcontrol)
 211{
 212        struct link_slave *slave = snd_kcontrol_chip(kcontrol);
 213        if (slave->slave.private_free)
 214                slave->slave.private_free(&slave->slave);
 215        if (slave->master)
 216                list_del(&slave->list);
 217        kfree(slave);
 218}
 219
 220/*
 221 * Add a slave control to the group with the given master control
 222 *
 223 * All slaves must be the same type (returning the same information
 224 * via info callback).  The fucntion doesn't check it, so it's your
 225 * responsibility.
 226 *
 227 * Also, some additional limitations:
 228 * - at most two channels
 229 * - logarithmic volume control (dB level), no linear volume
 230 * - master can only attenuate the volume, no gain
 231 */
 232int snd_ctl_add_slave(struct snd_kcontrol *master, struct snd_kcontrol *slave)
 233{
 234        struct link_master *master_link = snd_kcontrol_chip(master);
 235        struct link_slave *srec;
 236
 237        srec = kzalloc(sizeof(*srec) +
 238                       slave->count * sizeof(*slave->vd), GFP_KERNEL);
 239        if (!srec)
 240                return -ENOMEM;
 241        srec->slave = *slave;
 242        memcpy(srec->slave.vd, slave->vd, slave->count * sizeof(*slave->vd));
 243        srec->master = master_link;
 244
 245        /* override callbacks */
 246        slave->info = slave_info;
 247        slave->get = slave_get;
 248        slave->put = slave_put;
 249        if (slave->vd[0].access & SNDRV_CTL_ELEM_ACCESS_TLV_CALLBACK)
 250                slave->tlv.c = slave_tlv_cmd;
 251        slave->private_data = srec;
 252        slave->private_free = slave_free;
 253
 254        list_add_tail(&srec->list, &master_link->slaves);
 255        return 0;
 256}
 257
 258EXPORT_SYMBOL(snd_ctl_add_slave);
 259
 260/*
 261 * ctl callbacks for master controls
 262 */
 263static int master_info(struct snd_kcontrol *kcontrol,
 264                      struct snd_ctl_elem_info *uinfo)
 265{
 266        struct link_master *master = snd_kcontrol_chip(kcontrol);
 267        int ret;
 268
 269        ret = master_init(master);
 270        if (ret < 0)
 271                return ret;
 272        uinfo->type = master->info.type;
 273        uinfo->count = master->info.count;
 274        uinfo->value.integer.min = master->info.min_val;
 275        uinfo->value.integer.max = master->info.max_val;
 276        return 0;
 277}
 278
 279static int master_get(struct snd_kcontrol *kcontrol,
 280                      struct snd_ctl_elem_value *ucontrol)
 281{
 282        struct link_master *master = snd_kcontrol_chip(kcontrol);
 283        int err = master_init(master);
 284        if (err < 0)
 285                return err;
 286        ucontrol->value.integer.value[0] = master->val;
 287        return 0;
 288}
 289
 290static int master_put(struct snd_kcontrol *kcontrol,
 291                      struct snd_ctl_elem_value *ucontrol)
 292{
 293        struct link_master *master = snd_kcontrol_chip(kcontrol);
 294        struct link_slave *slave;
 295        struct snd_ctl_elem_value *uval;
 296        int err, old_val;
 297
 298        err = master_init(master);
 299        if (err < 0)
 300                return err;
 301        old_val = master->val;
 302        if (ucontrol->value.integer.value[0] == old_val)
 303                return 0;
 304
 305        uval = kmalloc(sizeof(*uval), GFP_KERNEL);
 306        if (!uval)
 307                return -ENOMEM;
 308        list_for_each_entry(slave, &master->slaves, list) {
 309                master->val = old_val;
 310                uval->id = slave->slave.id;
 311                slave_get_val(slave, uval);
 312                master->val = ucontrol->value.integer.value[0];
 313                slave_put_val(slave, uval);
 314        }
 315        kfree(uval);
 316        return 1;
 317}
 318
 319static void master_free(struct snd_kcontrol *kcontrol)
 320{
 321        struct link_master *master = snd_kcontrol_chip(kcontrol);
 322        struct link_slave *slave;
 323
 324        list_for_each_entry(slave, &master->slaves, list)
 325                slave->master = NULL;
 326        kfree(master);
 327}
 328
 329
 330/*
 331 * Create a virtual master control with the given name
 332 */
 333struct snd_kcontrol *snd_ctl_make_virtual_master(char *name,
 334                                                 const unsigned int *tlv)
 335{
 336        struct link_master *master;
 337        struct snd_kcontrol *kctl;
 338        struct snd_kcontrol_new knew;
 339
 340        memset(&knew, 0, sizeof(knew));
 341        knew.iface = SNDRV_CTL_ELEM_IFACE_MIXER;
 342        knew.name = name;
 343        knew.info = master_info;
 344
 345        master = kzalloc(sizeof(*master), GFP_KERNEL);
 346        if (!master)
 347                return NULL;
 348        INIT_LIST_HEAD(&master->slaves);
 349
 350        kctl = snd_ctl_new1(&knew, master);
 351        if (!kctl) {
 352                kfree(master);
 353                return NULL;
 354        }
 355        /* override some callbacks */
 356        kctl->info = master_info;
 357        kctl->get = master_get;
 358        kctl->put = master_put;
 359        kctl->private_free = master_free;
 360
 361        /* additional (constant) TLV read */
 362        if (tlv && tlv[0] == SNDRV_CTL_TLVT_DB_SCALE) {
 363                kctl->vd[0].access |= SNDRV_CTL_ELEM_ACCESS_TLV_READ;
 364                memcpy(master->tlv, tlv, sizeof(master->tlv));
 365                kctl->tlv.p = master->tlv;
 366        }
 367
 368        return kctl;
 369}
 370
 371EXPORT_SYMBOL(snd_ctl_make_virtual_master);
 372