~ubuntu-branches/ubuntu/precise/linux-lowlatency/precise

« back to all changes in this revision

Viewing changes to sound/usb/6fire/control.c

  • Committer: Package Import Robot
  • Author(s): Alessio Igor Bogani
  • Date: 2011-10-26 11:13:05 UTC
  • Revision ID: package-import@ubuntu.com-20111026111305-tz023xykf0i6eosh
Tags: upstream-3.2.0
ImportĀ upstreamĀ versionĀ 3.2.0

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
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
 * Version:     0.3.0
 
9
 * Copyright:   (C) Torsten Schenk
 
10
 *
 
11
 * This program is free software; you can redistribute it and/or modify
 
12
 * it under the terms of the GNU General Public License as published by
 
13
 * the Free Software Foundation; either version 2 of the License, or
 
14
 * (at your option) any later version.
 
15
 */
 
16
 
 
17
#include <linux/interrupt.h>
 
18
#include <sound/control.h>
 
19
 
 
20
#include "control.h"
 
21
#include "comm.h"
 
22
#include "chip.h"
 
23
 
 
24
static char *opt_coax_texts[2] = { "Optical", "Coax" };
 
25
static char *line_phono_texts[2] = { "Line", "Phono" };
 
26
 
 
27
/*
 
28
 * calculated with $value\[i\] = 128 \cdot sqrt[3]{\frac{i}{128}}$
 
29
 * this is done because the linear values cause rapid degredation
 
30
 * of volume in the uppermost region.
 
31
 */
 
32
static const u8 log_volume_table[128] = {
 
33
        0x00, 0x19, 0x20, 0x24, 0x28, 0x2b, 0x2e, 0x30, 0x32, 0x34,
 
34
        0x36, 0x38, 0x3a, 0x3b, 0x3d, 0x3e, 0x40, 0x41, 0x42, 0x43,
 
35
        0x44, 0x46, 0x47, 0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e,
 
36
        0x4e, 0x4f, 0x50, 0x51, 0x52, 0x53, 0x53, 0x54, 0x55, 0x56,
 
37
        0x56, 0x57, 0x58, 0x58, 0x59, 0x5a, 0x5b, 0x5b, 0x5c, 0x5c,
 
38
        0x5d, 0x5e, 0x5e, 0x5f, 0x60, 0x60, 0x61, 0x61, 0x62, 0x62,
 
39
        0x63, 0x63, 0x64, 0x65, 0x65, 0x66, 0x66, 0x67, 0x67, 0x68,
 
40
        0x68, 0x69, 0x69, 0x6a, 0x6a, 0x6b, 0x6b, 0x6c, 0x6c, 0x6c,
 
41
        0x6d, 0x6d, 0x6e, 0x6e, 0x6f, 0x6f, 0x70, 0x70, 0x70, 0x71,
 
42
        0x71, 0x72, 0x72, 0x73, 0x73, 0x73, 0x74, 0x74, 0x75, 0x75,
 
43
        0x75, 0x76, 0x76, 0x77, 0x77, 0x77, 0x78, 0x78, 0x78, 0x79,
 
44
        0x79, 0x7a, 0x7a, 0x7a, 0x7b, 0x7b, 0x7b, 0x7c, 0x7c, 0x7c,
 
45
        0x7d, 0x7d, 0x7d, 0x7e, 0x7e, 0x7e, 0x7f, 0x7f };
 
46
 
 
47
/*
 
48
 * data that needs to be sent to device. sets up card internal stuff.
 
49
 * values dumped from windows driver and filtered by trial'n'error.
 
50
 */
 
51
static const struct {
 
52
        u8 type;
 
53
        u8 reg;
 
54
        u8 value;
 
55
}
 
56
init_data[] = {
 
57
        { 0x22, 0x00, 0x00 }, { 0x20, 0x00, 0x08 }, { 0x22, 0x01, 0x01 },
 
58
        { 0x20, 0x01, 0x08 }, { 0x22, 0x02, 0x00 }, { 0x20, 0x02, 0x08 },
 
59
        { 0x22, 0x03, 0x00 }, { 0x20, 0x03, 0x08 }, { 0x22, 0x04, 0x00 },
 
60
        { 0x20, 0x04, 0x08 }, { 0x22, 0x05, 0x01 }, { 0x20, 0x05, 0x08 },
 
61
        { 0x22, 0x04, 0x01 }, { 0x12, 0x04, 0x00 }, { 0x12, 0x05, 0x00 },
 
62
        { 0x12, 0x0d, 0x78 }, { 0x12, 0x21, 0x82 }, { 0x12, 0x22, 0x80 },
 
63
        { 0x12, 0x23, 0x00 }, { 0x12, 0x06, 0x02 }, { 0x12, 0x03, 0x00 },
 
64
        { 0x12, 0x02, 0x00 }, { 0x22, 0x03, 0x01 },
 
65
        { 0 } /* TERMINATING ENTRY */
 
66
};
 
67
 
 
68
static const int rates_altsetting[] = { 1, 1, 2, 2, 3, 3 };
 
69
/* values to write to soundcard register for all samplerates */
 
70
static const u16 rates_6fire_vl[] = {0x00, 0x01, 0x00, 0x01, 0x00, 0x01};
 
71
static const u16 rates_6fire_vh[] = {0x11, 0x11, 0x10, 0x10, 0x00, 0x00};
 
72
 
 
73
enum {
 
74
        DIGITAL_THRU_ONLY_SAMPLERATE = 3
 
75
};
 
76
 
 
77
static void usb6fire_control_master_vol_update(struct control_runtime *rt)
 
78
{
 
79
        struct comm_runtime *comm_rt = rt->chip->comm;
 
80
        if (comm_rt) {
 
81
                /* set volume */
 
82
                comm_rt->write8(comm_rt, 0x12, 0x0f, 0x7f -
 
83
                                log_volume_table[rt->master_vol]);
 
84
                 /* unmute */
 
85
                comm_rt->write8(comm_rt, 0x12, 0x0e, 0x00);
 
86
        }
 
87
}
 
88
 
 
89
static void usb6fire_control_line_phono_update(struct control_runtime *rt)
 
90
{
 
91
        struct comm_runtime *comm_rt = rt->chip->comm;
 
92
        if (comm_rt) {
 
93
                comm_rt->write8(comm_rt, 0x22, 0x02, rt->line_phono_switch);
 
94
                comm_rt->write8(comm_rt, 0x21, 0x02, rt->line_phono_switch);
 
95
        }
 
96
}
 
97
 
 
98
static void usb6fire_control_opt_coax_update(struct control_runtime *rt)
 
99
{
 
100
        struct comm_runtime *comm_rt = rt->chip->comm;
 
101
        if (comm_rt) {
 
102
                comm_rt->write8(comm_rt, 0x22, 0x00, rt->opt_coax_switch);
 
103
                comm_rt->write8(comm_rt, 0x21, 0x00, rt->opt_coax_switch);
 
104
        }
 
105
}
 
106
 
 
107
static int usb6fire_control_set_rate(struct control_runtime *rt, int rate)
 
108
{
 
109
        int ret;
 
110
        struct usb_device *device = rt->chip->dev;
 
111
        struct comm_runtime *comm_rt = rt->chip->comm;
 
112
 
 
113
        if (rate < 0 || rate >= CONTROL_N_RATES)
 
114
                return -EINVAL;
 
115
 
 
116
        ret = usb_set_interface(device, 1, rates_altsetting[rate]);
 
117
        if (ret < 0)
 
118
                return ret;
 
119
 
 
120
        /* set soundcard clock */
 
121
        ret = comm_rt->write16(comm_rt, 0x02, 0x01, rates_6fire_vl[rate],
 
122
                        rates_6fire_vh[rate]);
 
123
        if (ret < 0)
 
124
                return ret;
 
125
 
 
126
        return 0;
 
127
}
 
128
 
 
129
static int usb6fire_control_set_channels(
 
130
        struct control_runtime *rt, int n_analog_out,
 
131
        int n_analog_in, bool spdif_out, bool spdif_in)
 
132
{
 
133
        int ret;
 
134
        struct comm_runtime *comm_rt = rt->chip->comm;
 
135
 
 
136
        /* enable analog inputs and outputs
 
137
         * (one bit per stereo-channel) */
 
138
        ret = comm_rt->write16(comm_rt, 0x02, 0x02,
 
139
                        (1 << (n_analog_out / 2)) - 1,
 
140
                        (1 << (n_analog_in / 2)) - 1);
 
141
        if (ret < 0)
 
142
                return ret;
 
143
 
 
144
        /* disable digital inputs and outputs */
 
145
        /* TODO: use spdif_x to enable/disable digital channels */
 
146
        ret = comm_rt->write16(comm_rt, 0x02, 0x03, 0x00, 0x00);
 
147
        if (ret < 0)
 
148
                return ret;
 
149
 
 
150
        return 0;
 
151
}
 
152
 
 
153
static int usb6fire_control_streaming_update(struct control_runtime *rt)
 
154
{
 
155
        struct comm_runtime *comm_rt = rt->chip->comm;
 
156
 
 
157
        if (comm_rt) {
 
158
                if (!rt->usb_streaming && rt->digital_thru_switch)
 
159
                        usb6fire_control_set_rate(rt,
 
160
                                DIGITAL_THRU_ONLY_SAMPLERATE);
 
161
                return comm_rt->write16(comm_rt, 0x02, 0x00, 0x00,
 
162
                        (rt->usb_streaming ? 0x01 : 0x00) |
 
163
                        (rt->digital_thru_switch ? 0x08 : 0x00));
 
164
        }
 
165
        return -EINVAL;
 
166
}
 
167
 
 
168
static int usb6fire_control_master_vol_info(struct snd_kcontrol *kcontrol,
 
169
                struct snd_ctl_elem_info *uinfo)
 
170
{
 
171
        uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
 
172
        uinfo->count = 1;
 
173
        uinfo->value.integer.min = 0;
 
174
        uinfo->value.integer.max = 127;
 
175
        return 0;
 
176
}
 
177
 
 
178
static int usb6fire_control_master_vol_put(struct snd_kcontrol *kcontrol,
 
179
                struct snd_ctl_elem_value *ucontrol)
 
180
{
 
181
        struct control_runtime *rt = snd_kcontrol_chip(kcontrol);
 
182
        int changed = 0;
 
183
        if (rt->master_vol != ucontrol->value.integer.value[0]) {
 
184
                rt->master_vol = ucontrol->value.integer.value[0];
 
185
                usb6fire_control_master_vol_update(rt);
 
186
                changed = 1;
 
187
        }
 
188
        return changed;
 
189
}
 
190
 
 
191
static int usb6fire_control_master_vol_get(struct snd_kcontrol *kcontrol,
 
192
                struct snd_ctl_elem_value *ucontrol)
 
193
{
 
194
        struct control_runtime *rt = snd_kcontrol_chip(kcontrol);
 
195
        ucontrol->value.integer.value[0] = rt->master_vol;
 
196
        return 0;
 
197
}
 
198
 
 
199
static int usb6fire_control_line_phono_info(struct snd_kcontrol *kcontrol,
 
200
                struct snd_ctl_elem_info *uinfo)
 
201
{
 
202
        uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
 
203
        uinfo->count = 1;
 
204
        uinfo->value.enumerated.items = 2;
 
205
        if (uinfo->value.enumerated.item > 1)
 
206
                uinfo->value.enumerated.item = 1;
 
207
        strcpy(uinfo->value.enumerated.name,
 
208
                        line_phono_texts[uinfo->value.enumerated.item]);
 
209
        return 0;
 
210
}
 
211
 
 
212
static int usb6fire_control_line_phono_put(struct snd_kcontrol *kcontrol,
 
213
                struct snd_ctl_elem_value *ucontrol)
 
214
{
 
215
        struct control_runtime *rt = snd_kcontrol_chip(kcontrol);
 
216
        int changed = 0;
 
217
        if (rt->line_phono_switch != ucontrol->value.integer.value[0]) {
 
218
                rt->line_phono_switch = ucontrol->value.integer.value[0];
 
219
                usb6fire_control_line_phono_update(rt);
 
220
                changed = 1;
 
221
        }
 
222
        return changed;
 
223
}
 
224
 
 
225
static int usb6fire_control_line_phono_get(struct snd_kcontrol *kcontrol,
 
226
                struct snd_ctl_elem_value *ucontrol)
 
227
{
 
228
        struct control_runtime *rt = snd_kcontrol_chip(kcontrol);
 
229
        ucontrol->value.integer.value[0] = rt->line_phono_switch;
 
230
        return 0;
 
231
}
 
232
 
 
233
static int usb6fire_control_opt_coax_info(struct snd_kcontrol *kcontrol,
 
234
                struct snd_ctl_elem_info *uinfo)
 
235
{
 
236
        uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
 
237
        uinfo->count = 1;
 
238
        uinfo->value.enumerated.items = 2;
 
239
        if (uinfo->value.enumerated.item > 1)
 
240
                uinfo->value.enumerated.item = 1;
 
241
        strcpy(uinfo->value.enumerated.name,
 
242
                        opt_coax_texts[uinfo->value.enumerated.item]);
 
243
        return 0;
 
244
}
 
245
 
 
246
static int usb6fire_control_opt_coax_put(struct snd_kcontrol *kcontrol,
 
247
                struct snd_ctl_elem_value *ucontrol)
 
248
{
 
249
        struct control_runtime *rt = snd_kcontrol_chip(kcontrol);
 
250
        int changed = 0;
 
251
 
 
252
        if (rt->opt_coax_switch != ucontrol->value.enumerated.item[0]) {
 
253
                rt->opt_coax_switch = ucontrol->value.enumerated.item[0];
 
254
                usb6fire_control_opt_coax_update(rt);
 
255
                changed = 1;
 
256
        }
 
257
        return changed;
 
258
}
 
259
 
 
260
static int usb6fire_control_opt_coax_get(struct snd_kcontrol *kcontrol,
 
261
                struct snd_ctl_elem_value *ucontrol)
 
262
{
 
263
        struct control_runtime *rt = snd_kcontrol_chip(kcontrol);
 
264
        ucontrol->value.enumerated.item[0] = rt->opt_coax_switch;
 
265
        return 0;
 
266
}
 
267
 
 
268
static int usb6fire_control_digital_thru_put(struct snd_kcontrol *kcontrol,
 
269
                struct snd_ctl_elem_value *ucontrol)
 
270
{
 
271
        struct control_runtime *rt = snd_kcontrol_chip(kcontrol);
 
272
        int changed = 0;
 
273
 
 
274
        if (rt->digital_thru_switch != ucontrol->value.integer.value[0]) {
 
275
                rt->digital_thru_switch = ucontrol->value.integer.value[0];
 
276
                usb6fire_control_streaming_update(rt);
 
277
                changed = 1;
 
278
        }
 
279
        return changed;
 
280
}
 
281
 
 
282
static int usb6fire_control_digital_thru_get(struct snd_kcontrol *kcontrol,
 
283
                struct snd_ctl_elem_value *ucontrol)
 
284
{
 
285
        struct control_runtime *rt = snd_kcontrol_chip(kcontrol);
 
286
        ucontrol->value.integer.value[0] = rt->digital_thru_switch;
 
287
        return 0;
 
288
}
 
289
 
 
290
static struct __devinitdata snd_kcontrol_new elements[] = {
 
291
        {
 
292
                .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
 
293
                .name = "Master Playback Volume",
 
294
                .index = 0,
 
295
                .access = SNDRV_CTL_ELEM_ACCESS_READWRITE,
 
296
                .info = usb6fire_control_master_vol_info,
 
297
                .get = usb6fire_control_master_vol_get,
 
298
                .put = usb6fire_control_master_vol_put
 
299
        },
 
300
        {
 
301
                .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
 
302
                .name = "Line/Phono Capture Route",
 
303
                .index = 0,
 
304
                .access = SNDRV_CTL_ELEM_ACCESS_READWRITE,
 
305
                .info = usb6fire_control_line_phono_info,
 
306
                .get = usb6fire_control_line_phono_get,
 
307
                .put = usb6fire_control_line_phono_put
 
308
        },
 
309
        {
 
310
                .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
 
311
                .name = "Opt/Coax Capture Route",
 
312
                .index = 0,
 
313
                .access = SNDRV_CTL_ELEM_ACCESS_READWRITE,
 
314
                .info = usb6fire_control_opt_coax_info,
 
315
                .get = usb6fire_control_opt_coax_get,
 
316
                .put = usb6fire_control_opt_coax_put
 
317
        },
 
318
        {
 
319
                .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
 
320
                .name = "Digital Thru Playback Route",
 
321
                .index = 0,
 
322
                .access = SNDRV_CTL_ELEM_ACCESS_READWRITE,
 
323
                .info = snd_ctl_boolean_mono_info,
 
324
                .get = usb6fire_control_digital_thru_get,
 
325
                .put = usb6fire_control_digital_thru_put
 
326
        },
 
327
        {}
 
328
};
 
329
 
 
330
int __devinit usb6fire_control_init(struct sfire_chip *chip)
 
331
{
 
332
        int i;
 
333
        int ret;
 
334
        struct control_runtime *rt = kzalloc(sizeof(struct control_runtime),
 
335
                        GFP_KERNEL);
 
336
        struct comm_runtime *comm_rt = chip->comm;
 
337
 
 
338
        if (!rt)
 
339
                return -ENOMEM;
 
340
 
 
341
        rt->chip = chip;
 
342
        rt->update_streaming = usb6fire_control_streaming_update;
 
343
        rt->set_rate = usb6fire_control_set_rate;
 
344
        rt->set_channels = usb6fire_control_set_channels;
 
345
 
 
346
        i = 0;
 
347
        while (init_data[i].type) {
 
348
                comm_rt->write8(comm_rt, init_data[i].type, init_data[i].reg,
 
349
                                init_data[i].value);
 
350
                i++;
 
351
        }
 
352
 
 
353
        usb6fire_control_opt_coax_update(rt);
 
354
        usb6fire_control_line_phono_update(rt);
 
355
        usb6fire_control_master_vol_update(rt);
 
356
        usb6fire_control_streaming_update(rt);
 
357
 
 
358
        i = 0;
 
359
        while (elements[i].name) {
 
360
                ret = snd_ctl_add(chip->card, snd_ctl_new1(&elements[i], rt));
 
361
                if (ret < 0) {
 
362
                        kfree(rt);
 
363
                        snd_printk(KERN_ERR PREFIX "cannot add control.\n");
 
364
                        return ret;
 
365
                }
 
366
                i++;
 
367
        }
 
368
 
 
369
        chip->control = rt;
 
370
        return 0;
 
371
}
 
372
 
 
373
void usb6fire_control_abort(struct sfire_chip *chip)
 
374
{}
 
375
 
 
376
void usb6fire_control_destroy(struct sfire_chip *chip)
 
377
{
 
378
        kfree(chip->control);
 
379
        chip->control = NULL;
 
380
}