linux/sound/usb/6fire/control.c
<<
>>
Prefs
   1/*
   2 * Linux driver for TerraTec DMX 6Fire USB
   3 *
   4 * Mixer control
   5 *
   6 * Author:      Torsten Schenk <torsten.schenk@zoho.com>
   7 * Created:     Jan 01, 2011
   8 * Copyright:   (C) Torsten Schenk
   9 *
  10 * Thanks to:
  11 * - Holger Ruckdeschel: he found out how to control individual channel
  12 *   volumes and introduced mute switch
  13 *
  14 * This program is free software; you can redistribute it and/or modify
  15 * it under the terms of the GNU General Public License as published by
  16 * the Free Software Foundation; either version 2 of the License, or
  17 * (at your option) any later version.
  18 */
  19
  20#include <linux/interrupt.h>
  21#include <sound/control.h>
  22#include <sound/tlv.h>
  23
  24#include "control.h"
  25#include "comm.h"
  26#include "chip.h"
  27
  28static char *opt_coax_texts[2] = { "Optical", "Coax" };
  29static char *line_phono_texts[2] = { "Line", "Phono" };
  30
  31/*
  32 * data that needs to be sent to device. sets up card internal stuff.
  33 * values dumped from windows driver and filtered by trial'n'error.
  34 */
  35static const struct {
  36        u8 type;
  37        u8 reg;
  38        u8 value;
  39}
  40init_data[] = {
  41        { 0x22, 0x00, 0x00 }, { 0x20, 0x00, 0x08 }, { 0x22, 0x01, 0x01 },
  42        { 0x20, 0x01, 0x08 }, { 0x22, 0x02, 0x00 }, { 0x20, 0x02, 0x08 },
  43        { 0x22, 0x03, 0x00 }, { 0x20, 0x03, 0x08 }, { 0x22, 0x04, 0x00 },
  44        { 0x20, 0x04, 0x08 }, { 0x22, 0x05, 0x01 }, { 0x20, 0x05, 0x08 },
  45        { 0x22, 0x04, 0x01 }, { 0x12, 0x04, 0x00 }, { 0x12, 0x05, 0x00 },
  46        { 0x12, 0x0d, 0x38 }, { 0x12, 0x21, 0x82 }, { 0x12, 0x22, 0x80 },
  47        { 0x12, 0x23, 0x00 }, { 0x12, 0x06, 0x02 }, { 0x12, 0x03, 0x00 },
  48        { 0x12, 0x02, 0x00 }, { 0x22, 0x03, 0x01 },
  49        { 0 } /* TERMINATING ENTRY */
  50};
  51
  52static const int rates_altsetting[] = { 1, 1, 2, 2, 3, 3 };
  53/* values to write to soundcard register for all samplerates */
  54static const u16 rates_6fire_vl[] = {0x00, 0x01, 0x00, 0x01, 0x00, 0x01};
  55static const u16 rates_6fire_vh[] = {0x11, 0x11, 0x10, 0x10, 0x00, 0x00};
  56
  57static DECLARE_TLV_DB_MINMAX(tlv_output, -9000, 0);
  58static DECLARE_TLV_DB_MINMAX(tlv_input, -1500, 1500);
  59
  60enum {
  61        DIGITAL_THRU_ONLY_SAMPLERATE = 3
  62};
  63
  64static void usb6fire_control_output_vol_update(struct control_runtime *rt)
  65{
  66        struct comm_runtime *comm_rt = rt->chip->comm;
  67        int i;
  68
  69        if (comm_rt)
  70                for (i = 0; i < 6; i++)
  71                        if (!(rt->ovol_updated & (1 << i))) {
  72                                comm_rt->write8(comm_rt, 0x12, 0x0f + i,
  73                                        180 - rt->output_vol[i]);
  74                                rt->ovol_updated |= 1 << i;
  75                        }
  76}
  77
  78static void usb6fire_control_output_mute_update(struct control_runtime *rt)
  79{
  80        struct comm_runtime *comm_rt = rt->chip->comm;
  81
  82        if (comm_rt)
  83                comm_rt->write8(comm_rt, 0x12, 0x0e, ~rt->output_mute);
  84}
  85
  86static void usb6fire_control_input_vol_update(struct control_runtime *rt)
  87{
  88        struct comm_runtime *comm_rt = rt->chip->comm;
  89        int i;
  90
  91        if (comm_rt)
  92                for (i = 0; i < 2; i++)
  93                        if (!(rt->ivol_updated & (1 << i))) {
  94                                comm_rt->write8(comm_rt, 0x12, 0x1c + i,
  95                                        rt->input_vol[i] & 0x3f);
  96                                rt->ivol_updated |= 1 << i;
  97                        }
  98}
  99
 100static void usb6fire_control_line_phono_update(struct control_runtime *rt)
 101{
 102        struct comm_runtime *comm_rt = rt->chip->comm;
 103        if (comm_rt) {
 104                comm_rt->write8(comm_rt, 0x22, 0x02, rt->line_phono_switch);
 105                comm_rt->write8(comm_rt, 0x21, 0x02, rt->line_phono_switch);
 106        }
 107}
 108
 109static void usb6fire_control_opt_coax_update(struct control_runtime *rt)
 110{
 111        struct comm_runtime *comm_rt = rt->chip->comm;
 112        if (comm_rt) {
 113                comm_rt->write8(comm_rt, 0x22, 0x00, rt->opt_coax_switch);
 114                comm_rt->write8(comm_rt, 0x21, 0x00, rt->opt_coax_switch);
 115        }
 116}
 117
 118static int usb6fire_control_set_rate(struct control_runtime *rt, int rate)
 119{
 120        int ret;
 121        struct usb_device *device = rt->chip->dev;
 122        struct comm_runtime *comm_rt = rt->chip->comm;
 123
 124        if (rate < 0 || rate >= CONTROL_N_RATES)
 125                return -EINVAL;
 126
 127        ret = usb_set_interface(device, 1, rates_altsetting[rate]);
 128        if (ret < 0)
 129                return ret;
 130
 131        /* set soundcard clock */
 132        ret = comm_rt->write16(comm_rt, 0x02, 0x01, rates_6fire_vl[rate],
 133                        rates_6fire_vh[rate]);
 134        if (ret < 0)
 135                return ret;
 136
 137        return 0;
 138}
 139
 140static int usb6fire_control_set_channels(
 141        struct control_runtime *rt, int n_analog_out,
 142        int n_analog_in, bool spdif_out, bool spdif_in)
 143{
 144        int ret;
 145        struct comm_runtime *comm_rt = rt->chip->comm;
 146
 147        /* enable analog inputs and outputs
 148         * (one bit per stereo-channel) */
 149        ret = comm_rt->write16(comm_rt, 0x02, 0x02,
 150                        (1 << (n_analog_out / 2)) - 1,
 151                        (1 << (n_analog_in / 2)) - 1);
 152        if (ret < 0)
 153                return ret;
 154
 155        /* disable digital inputs and outputs */
 156        /* TODO: use spdif_x to enable/disable digital channels */
 157        ret = comm_rt->write16(comm_rt, 0x02, 0x03, 0x00, 0x00);
 158        if (ret < 0)
 159                return ret;
 160
 161        return 0;
 162}
 163
 164static int usb6fire_control_streaming_update(struct control_runtime *rt)
 165{
 166        struct comm_runtime *comm_rt = rt->chip->comm;
 167
 168        if (comm_rt) {
 169                if (!rt->usb_streaming && rt->digital_thru_switch)
 170                        usb6fire_control_set_rate(rt,
 171                                DIGITAL_THRU_ONLY_SAMPLERATE);
 172                return comm_rt->write16(comm_rt, 0x02, 0x00, 0x00,
 173                        (rt->usb_streaming ? 0x01 : 0x00) |
 174                        (rt->digital_thru_switch ? 0x08 : 0x00));
 175        }
 176        return -EINVAL;
 177}
 178
 179static int usb6fire_control_output_vol_info(struct snd_kcontrol *kcontrol,
 180                struct snd_ctl_elem_info *uinfo)
 181{
 182        uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
 183        uinfo->count = 2;
 184        uinfo->value.integer.min = 0;
 185        uinfo->value.integer.max = 180;
 186        return 0;
 187}
 188
 189static int usb6fire_control_output_vol_put(struct snd_kcontrol *kcontrol,
 190                struct snd_ctl_elem_value *ucontrol)
 191{
 192        struct control_runtime *rt = snd_kcontrol_chip(kcontrol);
 193        unsigned int ch = kcontrol->private_value;
 194        int changed = 0;
 195
 196        if (ch > 4) {
 197                snd_printk(KERN_ERR PREFIX "Invalid channel in volume control.");
 198                return -EINVAL;
 199        }
 200
 201        if (rt->output_vol[ch] != ucontrol->value.integer.value[0]) {
 202                rt->output_vol[ch] = ucontrol->value.integer.value[0];
 203                rt->ovol_updated &= ~(1 << ch);
 204                changed = 1;
 205        }
 206        if (rt->output_vol[ch + 1] != ucontrol->value.integer.value[1]) {
 207                rt->output_vol[ch + 1] = ucontrol->value.integer.value[1];
 208                rt->ovol_updated &= ~(2 << ch);
 209                changed = 1;
 210        }
 211
 212        if (changed)
 213                usb6fire_control_output_vol_update(rt);
 214
 215        return changed;
 216}
 217
 218static int usb6fire_control_output_vol_get(struct snd_kcontrol *kcontrol,
 219                struct snd_ctl_elem_value *ucontrol)
 220{
 221        struct control_runtime *rt = snd_kcontrol_chip(kcontrol);
 222        unsigned int ch = kcontrol->private_value;
 223
 224        if (ch > 4) {
 225                snd_printk(KERN_ERR PREFIX "Invalid channel in volume control.");
 226                return -EINVAL;
 227        }
 228
 229        ucontrol->value.integer.value[0] = rt->output_vol[ch];
 230        ucontrol->value.integer.value[1] = rt->output_vol[ch + 1];
 231        return 0;
 232}
 233
 234static int usb6fire_control_output_mute_put(struct snd_kcontrol *kcontrol,
 235        struct snd_ctl_elem_value *ucontrol)
 236{
 237        struct control_runtime *rt = snd_kcontrol_chip(kcontrol);
 238        unsigned int ch = kcontrol->private_value;
 239        u8 old = rt->output_mute;
 240        u8 value = 0;
 241
 242        if (ch > 4) {
 243                snd_printk(KERN_ERR PREFIX "Invalid channel in volume control.");
 244                return -EINVAL;
 245        }
 246
 247        rt->output_mute &= ~(3 << ch);
 248        if (ucontrol->value.integer.value[0])
 249                value |= 1;
 250        if (ucontrol->value.integer.value[1])
 251                value |= 2;
 252        rt->output_mute |= value << ch;
 253
 254        if (rt->output_mute != old)
 255                usb6fire_control_output_mute_update(rt);
 256
 257        return rt->output_mute != old;
 258}
 259
 260static int usb6fire_control_output_mute_get(struct snd_kcontrol *kcontrol,
 261        struct snd_ctl_elem_value *ucontrol)
 262{
 263        struct control_runtime *rt = snd_kcontrol_chip(kcontrol);
 264        unsigned int ch = kcontrol->private_value;
 265        u8 value = rt->output_mute >> ch;
 266
 267        if (ch > 4) {
 268                snd_printk(KERN_ERR PREFIX "Invalid channel in volume control.");
 269                return -EINVAL;
 270        }
 271
 272        ucontrol->value.integer.value[0] = 1 & value;
 273        value >>= 1;
 274        ucontrol->value.integer.value[1] = 1 & value;
 275
 276        return 0;
 277}
 278
 279static int usb6fire_control_input_vol_info(struct snd_kcontrol *kcontrol,
 280                struct snd_ctl_elem_info *uinfo)
 281{
 282        uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
 283        uinfo->count = 2;
 284        uinfo->value.integer.min = 0;
 285        uinfo->value.integer.max = 30;
 286        return 0;
 287}
 288
 289static int usb6fire_control_input_vol_put(struct snd_kcontrol *kcontrol,
 290                struct snd_ctl_elem_value *ucontrol)
 291{
 292        struct control_runtime *rt = snd_kcontrol_chip(kcontrol);
 293        int changed = 0;
 294
 295        if (rt->input_vol[0] != ucontrol->value.integer.value[0]) {
 296                rt->input_vol[0] = ucontrol->value.integer.value[0] - 15;
 297                rt->ivol_updated &= ~(1 << 0);
 298                changed = 1;
 299        }
 300        if (rt->input_vol[1] != ucontrol->value.integer.value[1]) {
 301                rt->input_vol[1] = ucontrol->value.integer.value[1] - 15;
 302                rt->ivol_updated &= ~(1 << 1);
 303                changed = 1;
 304        }
 305
 306        if (changed)
 307                usb6fire_control_input_vol_update(rt);
 308
 309        return changed;
 310}
 311
 312static int usb6fire_control_input_vol_get(struct snd_kcontrol *kcontrol,
 313                struct snd_ctl_elem_value *ucontrol)
 314{
 315        struct control_runtime *rt = snd_kcontrol_chip(kcontrol);
 316
 317        ucontrol->value.integer.value[0] = rt->input_vol[0] + 15;
 318        ucontrol->value.integer.value[1] = rt->input_vol[1] + 15;
 319
 320        return 0;
 321}
 322
 323static int usb6fire_control_line_phono_info(struct snd_kcontrol *kcontrol,
 324                struct snd_ctl_elem_info *uinfo)
 325{
 326        uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
 327        uinfo->count = 1;
 328        uinfo->value.enumerated.items = 2;
 329        if (uinfo->value.enumerated.item > 1)
 330                uinfo->value.enumerated.item = 1;
 331        strcpy(uinfo->value.enumerated.name,
 332                        line_phono_texts[uinfo->value.enumerated.item]);
 333        return 0;
 334}
 335
 336static int usb6fire_control_line_phono_put(struct snd_kcontrol *kcontrol,
 337                struct snd_ctl_elem_value *ucontrol)
 338{
 339        struct control_runtime *rt = snd_kcontrol_chip(kcontrol);
 340        int changed = 0;
 341        if (rt->line_phono_switch != ucontrol->value.integer.value[0]) {
 342                rt->line_phono_switch = ucontrol->value.integer.value[0];
 343                usb6fire_control_line_phono_update(rt);
 344                changed = 1;
 345        }
 346        return changed;
 347}
 348
 349static int usb6fire_control_line_phono_get(struct snd_kcontrol *kcontrol,
 350                struct snd_ctl_elem_value *ucontrol)
 351{
 352        struct control_runtime *rt = snd_kcontrol_chip(kcontrol);
 353        ucontrol->value.integer.value[0] = rt->line_phono_switch;
 354        return 0;
 355}
 356
 357static int usb6fire_control_opt_coax_info(struct snd_kcontrol *kcontrol,
 358                struct snd_ctl_elem_info *uinfo)
 359{
 360        uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
 361        uinfo->count = 1;
 362        uinfo->value.enumerated.items = 2;
 363        if (uinfo->value.enumerated.item > 1)
 364                uinfo->value.enumerated.item = 1;
 365        strcpy(uinfo->value.enumerated.name,
 366                        opt_coax_texts[uinfo->value.enumerated.item]);
 367        return 0;
 368}
 369
 370static int usb6fire_control_opt_coax_put(struct snd_kcontrol *kcontrol,
 371                struct snd_ctl_elem_value *ucontrol)
 372{
 373        struct control_runtime *rt = snd_kcontrol_chip(kcontrol);
 374        int changed = 0;
 375
 376        if (rt->opt_coax_switch != ucontrol->value.enumerated.item[0]) {
 377                rt->opt_coax_switch = ucontrol->value.enumerated.item[0];
 378                usb6fire_control_opt_coax_update(rt);
 379                changed = 1;
 380        }
 381        return changed;
 382}
 383
 384static int usb6fire_control_opt_coax_get(struct snd_kcontrol *kcontrol,
 385                struct snd_ctl_elem_value *ucontrol)
 386{
 387        struct control_runtime *rt = snd_kcontrol_chip(kcontrol);
 388        ucontrol->value.enumerated.item[0] = rt->opt_coax_switch;
 389        return 0;
 390}
 391
 392static int usb6fire_control_digital_thru_put(struct snd_kcontrol *kcontrol,
 393                struct snd_ctl_elem_value *ucontrol)
 394{
 395        struct control_runtime *rt = snd_kcontrol_chip(kcontrol);
 396        int changed = 0;
 397
 398        if (rt->digital_thru_switch != ucontrol->value.integer.value[0]) {
 399                rt->digital_thru_switch = ucontrol->value.integer.value[0];
 400                usb6fire_control_streaming_update(rt);
 401                changed = 1;
 402        }
 403        return changed;
 404}
 405
 406static int usb6fire_control_digital_thru_get(struct snd_kcontrol *kcontrol,
 407                struct snd_ctl_elem_value *ucontrol)
 408{
 409        struct control_runtime *rt = snd_kcontrol_chip(kcontrol);
 410        ucontrol->value.integer.value[0] = rt->digital_thru_switch;
 411        return 0;
 412}
 413
 414static struct snd_kcontrol_new vol_elements[] = {
 415        {
 416                .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
 417                .name = "Analog Playback Volume",
 418                .index = 0,
 419                .private_value = 0,
 420                .access = SNDRV_CTL_ELEM_ACCESS_READWRITE |
 421                        SNDRV_CTL_ELEM_ACCESS_TLV_READ,
 422                .info = usb6fire_control_output_vol_info,
 423                .get = usb6fire_control_output_vol_get,
 424                .put = usb6fire_control_output_vol_put,
 425                .tlv = { .p = tlv_output }
 426        },
 427        {
 428                .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
 429                .name = "Analog Playback Volume",
 430                .index = 1,
 431                .private_value = 2,
 432                .access = SNDRV_CTL_ELEM_ACCESS_READWRITE |
 433                        SNDRV_CTL_ELEM_ACCESS_TLV_READ,
 434                .info = usb6fire_control_output_vol_info,
 435                .get = usb6fire_control_output_vol_get,
 436                .put = usb6fire_control_output_vol_put,
 437                .tlv = { .p = tlv_output }
 438        },
 439        {
 440                .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
 441                .name = "Analog Playback Volume",
 442                .index = 2,
 443                .private_value = 4,
 444                .access = SNDRV_CTL_ELEM_ACCESS_READWRITE |
 445                        SNDRV_CTL_ELEM_ACCESS_TLV_READ,
 446                .info = usb6fire_control_output_vol_info,
 447                .get = usb6fire_control_output_vol_get,
 448                .put = usb6fire_control_output_vol_put,
 449                .tlv = { .p = tlv_output }
 450        },
 451        {}
 452};
 453
 454static struct snd_kcontrol_new mute_elements[] = {
 455        {
 456                .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
 457                .name = "Analog Playback Switch",
 458                .index = 0,
 459                .private_value = 0,
 460                .access = SNDRV_CTL_ELEM_ACCESS_READWRITE,
 461                .info = snd_ctl_boolean_stereo_info,
 462                .get = usb6fire_control_output_mute_get,
 463                .put = usb6fire_control_output_mute_put,
 464        },
 465        {
 466                .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
 467                .name = "Analog Playback Switch",
 468                .index = 1,
 469                .private_value = 2,
 470                .access = SNDRV_CTL_ELEM_ACCESS_READWRITE,
 471                .info = snd_ctl_boolean_stereo_info,
 472                .get = usb6fire_control_output_mute_get,
 473                .put = usb6fire_control_output_mute_put,
 474        },
 475        {
 476                .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
 477                .name = "Analog Playback Switch",
 478                .index = 2,
 479                .private_value = 4,
 480                .access = SNDRV_CTL_ELEM_ACCESS_READWRITE,
 481                .info = snd_ctl_boolean_stereo_info,
 482                .get = usb6fire_control_output_mute_get,
 483                .put = usb6fire_control_output_mute_put,
 484        },
 485        {}
 486};
 487
 488static struct snd_kcontrol_new elements[] = {
 489        {
 490                .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
 491                .name = "Line/Phono Capture Route",
 492                .index = 0,
 493                .access = SNDRV_CTL_ELEM_ACCESS_READWRITE,
 494                .info = usb6fire_control_line_phono_info,
 495                .get = usb6fire_control_line_phono_get,
 496                .put = usb6fire_control_line_phono_put
 497        },
 498        {
 499                .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
 500                .name = "Opt/Coax Capture Route",
 501                .index = 0,
 502                .access = SNDRV_CTL_ELEM_ACCESS_READWRITE,
 503                .info = usb6fire_control_opt_coax_info,
 504                .get = usb6fire_control_opt_coax_get,
 505                .put = usb6fire_control_opt_coax_put
 506        },
 507        {
 508                .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
 509                .name = "Digital Thru Playback Route",
 510                .index = 0,
 511                .access = SNDRV_CTL_ELEM_ACCESS_READWRITE,
 512                .info = snd_ctl_boolean_mono_info,
 513                .get = usb6fire_control_digital_thru_get,
 514                .put = usb6fire_control_digital_thru_put
 515        },
 516        {
 517                .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
 518                .name = "Analog Capture Volume",
 519                .index = 0,
 520                .access = SNDRV_CTL_ELEM_ACCESS_READWRITE |
 521                        SNDRV_CTL_ELEM_ACCESS_TLV_READ,
 522                .info = usb6fire_control_input_vol_info,
 523                .get = usb6fire_control_input_vol_get,
 524                .put = usb6fire_control_input_vol_put,
 525                .tlv = { .p = tlv_input }
 526        },
 527        {}
 528};
 529
 530static int usb6fire_control_add_virtual(
 531        struct control_runtime *rt,
 532        struct snd_card *card,
 533        char *name,
 534        struct snd_kcontrol_new *elems)
 535{
 536        int ret;
 537        int i;
 538        struct snd_kcontrol *vmaster =
 539                snd_ctl_make_virtual_master(name, tlv_output);
 540        struct snd_kcontrol *control;
 541
 542        if (!vmaster)
 543                return -ENOMEM;
 544        ret = snd_ctl_add(card, vmaster);
 545        if (ret < 0)
 546                return ret;
 547
 548        i = 0;
 549        while (elems[i].name) {
 550                control = snd_ctl_new1(&elems[i], rt);
 551                if (!control)
 552                        return -ENOMEM;
 553                ret = snd_ctl_add(card, control);
 554                if (ret < 0)
 555                        return ret;
 556                ret = snd_ctl_add_slave(vmaster, control);
 557                if (ret < 0)
 558                        return ret;
 559                i++;
 560        }
 561        return 0;
 562}
 563
 564int usb6fire_control_init(struct sfire_chip *chip)
 565{
 566        int i;
 567        int ret;
 568        struct control_runtime *rt = kzalloc(sizeof(struct control_runtime),
 569                        GFP_KERNEL);
 570        struct comm_runtime *comm_rt = chip->comm;
 571
 572        if (!rt)
 573                return -ENOMEM;
 574
 575        rt->chip = chip;
 576        rt->update_streaming = usb6fire_control_streaming_update;
 577        rt->set_rate = usb6fire_control_set_rate;
 578        rt->set_channels = usb6fire_control_set_channels;
 579
 580        i = 0;
 581        while (init_data[i].type) {
 582                comm_rt->write8(comm_rt, init_data[i].type, init_data[i].reg,
 583                                init_data[i].value);
 584                i++;
 585        }
 586
 587        usb6fire_control_opt_coax_update(rt);
 588        usb6fire_control_line_phono_update(rt);
 589        usb6fire_control_output_vol_update(rt);
 590        usb6fire_control_output_mute_update(rt);
 591        usb6fire_control_input_vol_update(rt);
 592        usb6fire_control_streaming_update(rt);
 593
 594        ret = usb6fire_control_add_virtual(rt, chip->card,
 595                "Master Playback Volume", vol_elements);
 596        if (ret) {
 597                snd_printk(KERN_ERR PREFIX "cannot add control.\n");
 598                kfree(rt);
 599                return ret;
 600        }
 601        ret = usb6fire_control_add_virtual(rt, chip->card,
 602                "Master Playback Switch", mute_elements);
 603        if (ret) {
 604                snd_printk(KERN_ERR PREFIX "cannot add control.\n");
 605                kfree(rt);
 606                return ret;
 607        }
 608
 609        i = 0;
 610        while (elements[i].name) {
 611                ret = snd_ctl_add(chip->card, snd_ctl_new1(&elements[i], rt));
 612                if (ret < 0) {
 613                        kfree(rt);
 614                        snd_printk(KERN_ERR PREFIX "cannot add control.\n");
 615                        return ret;
 616                }
 617                i++;
 618        }
 619
 620        chip->control = rt;
 621        return 0;
 622}
 623
 624void usb6fire_control_abort(struct sfire_chip *chip)
 625{}
 626
 627void usb6fire_control_destroy(struct sfire_chip *chip)
 628{
 629        kfree(chip->control);
 630        chip->control = NULL;
 631}
 632