Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
torvalds
GitHub Repository: torvalds/linux
Path: blob/master/sound/pci/ctxfi/ctmixer.c
53084 views
1
// SPDX-License-Identifier: GPL-2.0-only
2
/*
3
* Copyright (C) 2008, Creative Technology Ltd. All Rights Reserved.
4
*
5
* @File ctmixer.c
6
*
7
* @Brief
8
* This file contains the implementation of alsa mixer device functions.
9
*
10
* @Author Liu Chun
11
* @Date May 28 2008
12
*/
13
14
15
#include "ctmixer.h"
16
#include "ctamixer.h"
17
#include <linux/slab.h>
18
#include <sound/core.h>
19
#include <sound/control.h>
20
#include <sound/asoundef.h>
21
#include <sound/pcm.h>
22
#include <sound/tlv.h>
23
24
enum CT_SUM_CTL {
25
SUM_IN_F,
26
SUM_IN_R,
27
SUM_IN_C,
28
SUM_IN_S,
29
SUM_IN_F_C,
30
31
NUM_CT_SUMS
32
};
33
34
enum CT_AMIXER_CTL {
35
/* volume control mixers */
36
AMIXER_MASTER_F,
37
AMIXER_MASTER_R,
38
AMIXER_MASTER_C,
39
AMIXER_MASTER_S,
40
AMIXER_PCM_F,
41
AMIXER_PCM_R,
42
AMIXER_PCM_C,
43
AMIXER_PCM_S,
44
AMIXER_SPDIFI,
45
AMIXER_LINEIN,
46
AMIXER_MIC,
47
AMIXER_SPDIFO,
48
AMIXER_WAVE_F,
49
AMIXER_WAVE_R,
50
AMIXER_WAVE_C,
51
AMIXER_WAVE_S,
52
AMIXER_MASTER_F_C,
53
AMIXER_PCM_F_C,
54
AMIXER_SPDIFI_C,
55
AMIXER_LINEIN_C,
56
AMIXER_MIC_C,
57
58
/* this should always be the last one */
59
NUM_CT_AMIXERS
60
};
61
62
enum CTALSA_MIXER_CTL {
63
/* volume control mixers */
64
MIXER_MASTER_P,
65
MIXER_PCM_P,
66
MIXER_LINEIN_P,
67
MIXER_MIC_P,
68
MIXER_SPDIFI_P,
69
MIXER_SPDIFO_P,
70
MIXER_WAVEF_P,
71
MIXER_WAVER_P,
72
MIXER_WAVEC_P,
73
MIXER_WAVES_P,
74
MIXER_MASTER_C,
75
MIXER_PCM_C,
76
MIXER_LINEIN_C,
77
MIXER_MIC_C,
78
MIXER_SPDIFI_C,
79
80
/* switch control mixers */
81
MIXER_PCM_C_S,
82
MIXER_LINEIN_C_S,
83
MIXER_MIC_C_S,
84
MIXER_SPDIFI_C_S,
85
MIXER_SPDIFO_P_S,
86
MIXER_WAVEF_P_S,
87
MIXER_WAVER_P_S,
88
MIXER_WAVEC_P_S,
89
MIXER_WAVES_P_S,
90
MIXER_DIGITAL_IO_S,
91
MIXER_IEC958_MASK,
92
MIXER_IEC958_DEFAULT,
93
MIXER_IEC958_STREAM,
94
95
/* this should always be the last one */
96
NUM_CTALSA_MIXERS
97
};
98
99
#define VOL_MIXER_START MIXER_MASTER_P
100
#define VOL_MIXER_END MIXER_SPDIFI_C
101
#define VOL_MIXER_NUM (VOL_MIXER_END - VOL_MIXER_START + 1)
102
#define SWH_MIXER_START MIXER_PCM_C_S
103
#define SWH_MIXER_END MIXER_DIGITAL_IO_S
104
#define SWH_CAPTURE_START MIXER_PCM_C_S
105
#define SWH_CAPTURE_END MIXER_SPDIFI_C_S
106
107
#define CHN_NUM 2
108
109
struct ct_kcontrol_init {
110
unsigned char ctl;
111
char *name;
112
};
113
114
static struct ct_kcontrol_init
115
ct_kcontrol_init_table[NUM_CTALSA_MIXERS] = {
116
[MIXER_MASTER_P] = {
117
.ctl = 1,
118
.name = "Master Playback Volume",
119
},
120
[MIXER_MASTER_C] = {
121
.ctl = 1,
122
.name = "Master Capture Volume",
123
},
124
[MIXER_PCM_P] = {
125
.ctl = 1,
126
.name = "PCM Playback Volume",
127
},
128
[MIXER_PCM_C] = {
129
.ctl = 1,
130
.name = "PCM Capture Volume",
131
},
132
[MIXER_LINEIN_P] = {
133
.ctl = 1,
134
.name = "Line Playback Volume",
135
},
136
[MIXER_LINEIN_C] = {
137
.ctl = 1,
138
.name = "Line Capture Volume",
139
},
140
[MIXER_MIC_P] = {
141
.ctl = 1,
142
.name = "Mic Playback Volume",
143
},
144
[MIXER_MIC_C] = {
145
.ctl = 1,
146
.name = "Mic Capture Volume",
147
},
148
[MIXER_SPDIFI_P] = {
149
.ctl = 1,
150
.name = "IEC958 Playback Volume",
151
},
152
[MIXER_SPDIFI_C] = {
153
.ctl = 1,
154
.name = "IEC958 Capture Volume",
155
},
156
[MIXER_SPDIFO_P] = {
157
.ctl = 1,
158
.name = "Digital Playback Volume",
159
},
160
[MIXER_WAVEF_P] = {
161
.ctl = 1,
162
.name = "Front Playback Volume",
163
},
164
[MIXER_WAVES_P] = {
165
.ctl = 1,
166
.name = "Side Playback Volume",
167
},
168
[MIXER_WAVEC_P] = {
169
.ctl = 1,
170
.name = "Center/LFE Playback Volume",
171
},
172
[MIXER_WAVER_P] = {
173
.ctl = 1,
174
.name = "Surround Playback Volume",
175
},
176
[MIXER_PCM_C_S] = {
177
.ctl = 1,
178
.name = "PCM Capture Switch",
179
},
180
[MIXER_LINEIN_C_S] = {
181
.ctl = 1,
182
.name = "Line Capture Switch",
183
},
184
[MIXER_MIC_C_S] = {
185
.ctl = 1,
186
.name = "Mic Capture Switch",
187
},
188
[MIXER_SPDIFI_C_S] = {
189
.ctl = 1,
190
.name = "IEC958 Capture Switch",
191
},
192
[MIXER_SPDIFO_P_S] = {
193
.ctl = 1,
194
.name = "Digital Playback Switch",
195
},
196
[MIXER_WAVEF_P_S] = {
197
.ctl = 1,
198
.name = "Front Playback Switch",
199
},
200
[MIXER_WAVES_P_S] = {
201
.ctl = 1,
202
.name = "Side Playback Switch",
203
},
204
[MIXER_WAVEC_P_S] = {
205
.ctl = 1,
206
.name = "Center/LFE Playback Switch",
207
},
208
[MIXER_WAVER_P_S] = {
209
.ctl = 1,
210
.name = "Surround Playback Switch",
211
},
212
[MIXER_DIGITAL_IO_S] = {
213
.ctl = 0,
214
.name = "Digit-IO Playback Switch",
215
},
216
};
217
218
static void
219
ct_mixer_recording_select(struct ct_mixer *mixer, enum CT_AMIXER_CTL type);
220
221
static void
222
ct_mixer_recording_unselect(struct ct_mixer *mixer, enum CT_AMIXER_CTL type);
223
224
/* FIXME: this static looks like it would fail if more than one card was */
225
/* installed. */
226
static struct snd_kcontrol *kctls[2] = {NULL};
227
228
static enum CT_AMIXER_CTL get_amixer_index(enum CTALSA_MIXER_CTL alsa_index)
229
{
230
switch (alsa_index) {
231
case MIXER_MASTER_P: return AMIXER_MASTER_F;
232
case MIXER_MASTER_C: return AMIXER_MASTER_F_C;
233
case MIXER_PCM_P: return AMIXER_PCM_F;
234
case MIXER_PCM_C:
235
case MIXER_PCM_C_S: return AMIXER_PCM_F_C;
236
case MIXER_LINEIN_P: return AMIXER_LINEIN;
237
case MIXER_LINEIN_C:
238
case MIXER_LINEIN_C_S: return AMIXER_LINEIN_C;
239
case MIXER_MIC_P: return AMIXER_MIC;
240
case MIXER_MIC_C:
241
case MIXER_MIC_C_S: return AMIXER_MIC_C;
242
case MIXER_SPDIFI_P: return AMIXER_SPDIFI;
243
case MIXER_SPDIFI_C:
244
case MIXER_SPDIFI_C_S: return AMIXER_SPDIFI_C;
245
case MIXER_SPDIFO_P: return AMIXER_SPDIFO;
246
case MIXER_WAVEF_P: return AMIXER_WAVE_F;
247
case MIXER_WAVES_P: return AMIXER_WAVE_S;
248
case MIXER_WAVEC_P: return AMIXER_WAVE_C;
249
case MIXER_WAVER_P: return AMIXER_WAVE_R;
250
default: return NUM_CT_AMIXERS;
251
}
252
}
253
254
static enum CT_AMIXER_CTL get_recording_amixer(enum CT_AMIXER_CTL index)
255
{
256
switch (index) {
257
case AMIXER_MASTER_F: return AMIXER_MASTER_F_C;
258
case AMIXER_PCM_F: return AMIXER_PCM_F_C;
259
case AMIXER_SPDIFI: return AMIXER_SPDIFI_C;
260
case AMIXER_LINEIN: return AMIXER_LINEIN_C;
261
case AMIXER_MIC: return AMIXER_MIC_C;
262
default: return NUM_CT_AMIXERS;
263
}
264
}
265
266
static unsigned char
267
get_switch_state(struct ct_mixer *mixer, enum CTALSA_MIXER_CTL type)
268
{
269
return (mixer->switch_state & (0x1 << (type - SWH_MIXER_START)))
270
? 1 : 0;
271
}
272
273
static void
274
set_switch_state(struct ct_mixer *mixer,
275
enum CTALSA_MIXER_CTL type, unsigned char state)
276
{
277
if (state)
278
mixer->switch_state |= (0x1 << (type - SWH_MIXER_START));
279
else
280
mixer->switch_state &= ~(0x1 << (type - SWH_MIXER_START));
281
}
282
283
#if 0 /* not used */
284
/* Map integer value ranging from 0 to 65535 to 14-bit float value ranging
285
* from 2^-6 to (1+1023/1024) */
286
static unsigned int uint16_to_float14(unsigned int x)
287
{
288
unsigned int i;
289
290
if (x < 17)
291
return 0;
292
293
x *= 2031;
294
x /= 65535;
295
x += 16;
296
297
/* i <= 6 */
298
for (i = 0; !(x & 0x400); i++)
299
x <<= 1;
300
301
x = (((7 - i) & 0x7) << 10) | (x & 0x3ff);
302
303
return x;
304
}
305
306
static unsigned int float14_to_uint16(unsigned int x)
307
{
308
unsigned int e;
309
310
if (!x)
311
return x;
312
313
e = (x >> 10) & 0x7;
314
x &= 0x3ff;
315
x += 1024;
316
x >>= (7 - e);
317
x -= 16;
318
x *= 65535;
319
x /= 2031;
320
321
return x;
322
}
323
#endif /* not used */
324
325
#define VOL_SCALE 0x1c
326
#define VOL_MAX 0x100
327
328
static const DECLARE_TLV_DB_SCALE(ct_vol_db_scale, -6400, 25, 1);
329
330
static int ct_alsa_mix_volume_info(struct snd_kcontrol *kcontrol,
331
struct snd_ctl_elem_info *uinfo)
332
{
333
uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
334
uinfo->count = 2;
335
uinfo->value.integer.min = 0;
336
uinfo->value.integer.max = VOL_MAX;
337
338
return 0;
339
}
340
341
static int ct_alsa_mix_volume_get(struct snd_kcontrol *kcontrol,
342
struct snd_ctl_elem_value *ucontrol)
343
{
344
struct ct_atc *atc = snd_kcontrol_chip(kcontrol);
345
enum CT_AMIXER_CTL type = get_amixer_index(kcontrol->private_value);
346
struct amixer *amixer;
347
int i, val;
348
349
for (i = 0; i < 2; i++) {
350
amixer = ((struct ct_mixer *)atc->mixer)->
351
amixers[type*CHN_NUM+i];
352
val = amixer->ops->get_scale(amixer) / VOL_SCALE;
353
if (val < 0)
354
val = 0;
355
else if (val > VOL_MAX)
356
val = VOL_MAX;
357
ucontrol->value.integer.value[i] = val;
358
}
359
360
return 0;
361
}
362
363
static int ct_alsa_mix_volume_put(struct snd_kcontrol *kcontrol,
364
struct snd_ctl_elem_value *ucontrol)
365
{
366
struct ct_atc *atc = snd_kcontrol_chip(kcontrol);
367
struct ct_mixer *mixer = atc->mixer;
368
enum CT_AMIXER_CTL type = get_amixer_index(kcontrol->private_value);
369
struct amixer *amixer;
370
int i, j, val, oval, change = 0;
371
372
for (i = 0; i < 2; i++) {
373
val = ucontrol->value.integer.value[i];
374
if (val < 0)
375
val = 0;
376
else if (val > VOL_MAX)
377
val = VOL_MAX;
378
val *= VOL_SCALE;
379
amixer = mixer->amixers[type*CHN_NUM+i];
380
oval = amixer->ops->get_scale(amixer);
381
if (val != oval) {
382
amixer->ops->set_scale(amixer, val);
383
amixer->ops->commit_write(amixer);
384
change = 1;
385
/* Synchronize Master/PCM playback AMIXERs. */
386
if (AMIXER_MASTER_F == type || AMIXER_PCM_F == type) {
387
for (j = 1; j < 4; j++) {
388
amixer = mixer->
389
amixers[(type+j)*CHN_NUM+i];
390
amixer->ops->set_scale(amixer, val);
391
amixer->ops->commit_write(amixer);
392
}
393
}
394
}
395
}
396
397
return change;
398
}
399
400
static struct snd_kcontrol_new vol_ctl = {
401
.access = SNDRV_CTL_ELEM_ACCESS_READWRITE |
402
SNDRV_CTL_ELEM_ACCESS_TLV_READ,
403
.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
404
.info = ct_alsa_mix_volume_info,
405
.get = ct_alsa_mix_volume_get,
406
.put = ct_alsa_mix_volume_put,
407
.tlv = { .p = ct_vol_db_scale },
408
};
409
410
static int output_switch_info(struct snd_kcontrol *kcontrol,
411
struct snd_ctl_elem_info *info)
412
{
413
static const char *const names[3] = {
414
"FP Headphones", "Headphones", "Speakers"
415
};
416
417
return snd_ctl_enum_info(info, 1, 3, names);
418
}
419
420
static int output_switch_get(struct snd_kcontrol *kcontrol,
421
struct snd_ctl_elem_value *ucontrol)
422
{
423
struct ct_atc *atc = snd_kcontrol_chip(kcontrol);
424
ucontrol->value.enumerated.item[0] = atc->output_switch_get(atc);
425
return 0;
426
}
427
428
static int output_switch_put(struct snd_kcontrol *kcontrol,
429
struct snd_ctl_elem_value *ucontrol)
430
{
431
struct ct_atc *atc = snd_kcontrol_chip(kcontrol);
432
if (ucontrol->value.enumerated.item[0] > 2)
433
return -EINVAL;
434
return atc->output_switch_put(atc, ucontrol->value.enumerated.item[0]);
435
}
436
437
static struct snd_kcontrol_new output_ctl = {
438
.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
439
.name = "Analog Output Playback Enum",
440
.info = output_switch_info,
441
.get = output_switch_get,
442
.put = output_switch_put,
443
};
444
445
static int mic_source_switch_info(struct snd_kcontrol *kcontrol,
446
struct snd_ctl_elem_info *info)
447
{
448
static const char *const names[3] = {
449
"Mic", "FP Mic", "Aux"
450
};
451
452
return snd_ctl_enum_info(info, 1, 3, names);
453
}
454
455
static int mic_source_switch_get(struct snd_kcontrol *kcontrol,
456
struct snd_ctl_elem_value *ucontrol)
457
{
458
struct ct_atc *atc = snd_kcontrol_chip(kcontrol);
459
ucontrol->value.enumerated.item[0] = atc->mic_source_switch_get(atc);
460
return 0;
461
}
462
463
static int mic_source_switch_put(struct snd_kcontrol *kcontrol,
464
struct snd_ctl_elem_value *ucontrol)
465
{
466
struct ct_atc *atc = snd_kcontrol_chip(kcontrol);
467
if (ucontrol->value.enumerated.item[0] > 2)
468
return -EINVAL;
469
return atc->mic_source_switch_put(atc,
470
ucontrol->value.enumerated.item[0]);
471
}
472
473
static struct snd_kcontrol_new mic_source_ctl = {
474
.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
475
.name = "Mic Source Capture Enum",
476
.info = mic_source_switch_info,
477
.get = mic_source_switch_get,
478
.put = mic_source_switch_put,
479
};
480
481
static void
482
do_line_mic_switch(struct ct_atc *atc, enum CTALSA_MIXER_CTL type)
483
{
484
485
if (MIXER_LINEIN_C_S == type) {
486
atc->select_line_in(atc);
487
set_switch_state(atc->mixer, MIXER_MIC_C_S, 0);
488
snd_ctl_notify(atc->card, SNDRV_CTL_EVENT_MASK_VALUE,
489
&kctls[1]->id);
490
} else if (MIXER_MIC_C_S == type) {
491
atc->select_mic_in(atc);
492
set_switch_state(atc->mixer, MIXER_LINEIN_C_S, 0);
493
snd_ctl_notify(atc->card, SNDRV_CTL_EVENT_MASK_VALUE,
494
&kctls[0]->id);
495
}
496
}
497
498
static void
499
do_digit_io_switch(struct ct_atc *atc, int state)
500
{
501
struct ct_mixer *mixer = atc->mixer;
502
503
if (state) {
504
atc->select_digit_io(atc);
505
atc->spdif_out_unmute(atc,
506
get_switch_state(mixer, MIXER_SPDIFO_P_S));
507
atc->spdif_in_unmute(atc, 1);
508
atc->line_in_unmute(atc, 0);
509
return;
510
}
511
512
if (get_switch_state(mixer, MIXER_LINEIN_C_S))
513
atc->select_line_in(atc);
514
else if (get_switch_state(mixer, MIXER_MIC_C_S))
515
atc->select_mic_in(atc);
516
517
atc->spdif_out_unmute(atc, 0);
518
atc->spdif_in_unmute(atc, 0);
519
atc->line_in_unmute(atc, 1);
520
return;
521
}
522
523
static void do_switch(struct ct_atc *atc, enum CTALSA_MIXER_CTL type, int state)
524
{
525
struct ct_mixer *mixer = atc->mixer;
526
struct capabilities cap = atc->capabilities(atc);
527
528
/* Do changes in mixer. */
529
if ((SWH_CAPTURE_START <= type) && (SWH_CAPTURE_END >= type)) {
530
if (state) {
531
ct_mixer_recording_select(mixer,
532
get_amixer_index(type));
533
} else {
534
ct_mixer_recording_unselect(mixer,
535
get_amixer_index(type));
536
}
537
}
538
/* Do changes out of mixer. */
539
if (!cap.dedicated_mic &&
540
(MIXER_LINEIN_C_S == type || MIXER_MIC_C_S == type)) {
541
if (state)
542
do_line_mic_switch(atc, type);
543
atc->line_in_unmute(atc, state);
544
} else if (cap.dedicated_mic && (MIXER_LINEIN_C_S == type))
545
atc->line_in_unmute(atc, state);
546
else if (cap.dedicated_mic && (MIXER_MIC_C_S == type))
547
atc->mic_unmute(atc, state);
548
else if (MIXER_SPDIFI_C_S == type)
549
atc->spdif_in_unmute(atc, state);
550
else if (MIXER_WAVEF_P_S == type) {
551
if (cap.dedicated_rca) {
552
atc->rca_unmute(atc, atc->rca_state ? 0 : state);
553
atc->line_front_unmute(atc, atc->rca_state ? state : 0);
554
} else {
555
atc->line_front_unmute(atc, state);
556
}
557
}
558
else if (MIXER_WAVES_P_S == type)
559
atc->line_surround_unmute(atc, state);
560
else if (MIXER_WAVEC_P_S == type)
561
atc->line_clfe_unmute(atc, state);
562
else if (MIXER_WAVER_P_S == type)
563
atc->line_rear_unmute(atc, state);
564
else if (MIXER_SPDIFO_P_S == type)
565
atc->spdif_out_unmute(atc, state);
566
else if (MIXER_DIGITAL_IO_S == type)
567
do_digit_io_switch(atc, state);
568
569
return;
570
}
571
572
static int ct_alsa_mix_switch_info(struct snd_kcontrol *kcontrol,
573
struct snd_ctl_elem_info *uinfo)
574
{
575
uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN;
576
uinfo->count = 1;
577
uinfo->value.integer.min = 0;
578
uinfo->value.integer.max = 1;
579
uinfo->value.integer.step = 1;
580
581
return 0;
582
}
583
584
static int ct_alsa_mix_switch_get(struct snd_kcontrol *kcontrol,
585
struct snd_ctl_elem_value *ucontrol)
586
{
587
struct ct_mixer *mixer =
588
((struct ct_atc *)snd_kcontrol_chip(kcontrol))->mixer;
589
enum CTALSA_MIXER_CTL type = kcontrol->private_value;
590
591
ucontrol->value.integer.value[0] = get_switch_state(mixer, type);
592
return 0;
593
}
594
595
static int ct_alsa_mix_switch_put(struct snd_kcontrol *kcontrol,
596
struct snd_ctl_elem_value *ucontrol)
597
{
598
struct ct_atc *atc = snd_kcontrol_chip(kcontrol);
599
struct ct_mixer *mixer = atc->mixer;
600
enum CTALSA_MIXER_CTL type = kcontrol->private_value;
601
int state;
602
603
state = ucontrol->value.integer.value[0];
604
if (get_switch_state(mixer, type) == state)
605
return 0;
606
607
set_switch_state(mixer, type, state);
608
do_switch(atc, type, state);
609
610
return 1;
611
}
612
613
static struct snd_kcontrol_new swh_ctl = {
614
.access = SNDRV_CTL_ELEM_ACCESS_READWRITE,
615
.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
616
.info = ct_alsa_mix_switch_info,
617
.get = ct_alsa_mix_switch_get,
618
.put = ct_alsa_mix_switch_put
619
};
620
621
static int dedicated_rca_info(struct snd_kcontrol *kcontrol,
622
struct snd_ctl_elem_info *info)
623
{
624
static const char *const names[2] = {
625
"RCA", "Front"
626
};
627
628
return snd_ctl_enum_info(info, 1, 2, names);
629
}
630
631
static int dedicated_rca_get(struct snd_kcontrol *kcontrol,
632
struct snd_ctl_elem_value *ucontrol)
633
{
634
struct ct_atc *atc = snd_kcontrol_chip(kcontrol);
635
636
ucontrol->value.enumerated.item[0] = atc->rca_state;
637
return 0;
638
}
639
640
static int dedicated_rca_put(struct snd_kcontrol *kcontrol,
641
struct snd_ctl_elem_value *ucontrol)
642
{
643
struct ct_atc *atc = snd_kcontrol_chip(kcontrol);
644
unsigned int rca_state = ucontrol->value.enumerated.item[0];
645
unsigned char state;
646
647
if (rca_state > 1)
648
return -EINVAL;
649
650
if (rca_state == atc->rca_state)
651
return 0;
652
653
state = get_switch_state(atc->mixer, MIXER_WAVEF_P_S);
654
do_switch(atc, MIXER_WAVEF_P_S, 0);
655
656
atc->rca_state = rca_state;
657
atc->dedicated_rca_select(atc);
658
659
do_switch(atc, MIXER_WAVEF_P_S, state);
660
661
return 1;
662
}
663
664
static struct snd_kcontrol_new rca_ctl = {
665
.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
666
.name = "Analog Playback Route",
667
.info = dedicated_rca_info,
668
.get = dedicated_rca_get,
669
.put = dedicated_rca_put,
670
};
671
672
static int ct_spdif_info(struct snd_kcontrol *kcontrol,
673
struct snd_ctl_elem_info *uinfo)
674
{
675
uinfo->type = SNDRV_CTL_ELEM_TYPE_IEC958;
676
uinfo->count = 1;
677
return 0;
678
}
679
680
static int ct_spdif_get_mask(struct snd_kcontrol *kcontrol,
681
struct snd_ctl_elem_value *ucontrol)
682
{
683
ucontrol->value.iec958.status[0] = 0xff;
684
ucontrol->value.iec958.status[1] = 0xff;
685
ucontrol->value.iec958.status[2] = 0xff;
686
ucontrol->value.iec958.status[3] = 0xff;
687
return 0;
688
}
689
690
static int ct_spdif_get(struct snd_kcontrol *kcontrol,
691
struct snd_ctl_elem_value *ucontrol)
692
{
693
struct ct_atc *atc = snd_kcontrol_chip(kcontrol);
694
unsigned int status;
695
696
atc->spdif_out_get_status(atc, &status);
697
698
if (status == 0)
699
status = SNDRV_PCM_DEFAULT_CON_SPDIF;
700
701
ucontrol->value.iec958.status[0] = (status >> 0) & 0xff;
702
ucontrol->value.iec958.status[1] = (status >> 8) & 0xff;
703
ucontrol->value.iec958.status[2] = (status >> 16) & 0xff;
704
ucontrol->value.iec958.status[3] = (status >> 24) & 0xff;
705
706
return 0;
707
}
708
709
static int ct_spdif_put(struct snd_kcontrol *kcontrol,
710
struct snd_ctl_elem_value *ucontrol)
711
{
712
struct ct_atc *atc = snd_kcontrol_chip(kcontrol);
713
int change;
714
unsigned int status, old_status;
715
716
status = (ucontrol->value.iec958.status[0] << 0) |
717
(ucontrol->value.iec958.status[1] << 8) |
718
(ucontrol->value.iec958.status[2] << 16) |
719
(ucontrol->value.iec958.status[3] << 24);
720
721
atc->spdif_out_get_status(atc, &old_status);
722
change = (old_status != status);
723
if (change)
724
atc->spdif_out_set_status(atc, status);
725
726
return change;
727
}
728
729
static struct snd_kcontrol_new iec958_mask_ctl = {
730
.access = SNDRV_CTL_ELEM_ACCESS_READ,
731
.iface = SNDRV_CTL_ELEM_IFACE_PCM,
732
.name = SNDRV_CTL_NAME_IEC958("", PLAYBACK, MASK),
733
.count = 1,
734
.info = ct_spdif_info,
735
.get = ct_spdif_get_mask,
736
.private_value = MIXER_IEC958_MASK
737
};
738
739
static struct snd_kcontrol_new iec958_default_ctl = {
740
.iface = SNDRV_CTL_ELEM_IFACE_PCM,
741
.name = SNDRV_CTL_NAME_IEC958("", PLAYBACK, DEFAULT),
742
.count = 1,
743
.info = ct_spdif_info,
744
.get = ct_spdif_get,
745
.put = ct_spdif_put,
746
.private_value = MIXER_IEC958_DEFAULT
747
};
748
749
static struct snd_kcontrol_new iec958_ctl = {
750
.access = SNDRV_CTL_ELEM_ACCESS_READWRITE,
751
.iface = SNDRV_CTL_ELEM_IFACE_PCM,
752
.name = SNDRV_CTL_NAME_IEC958("", PLAYBACK, PCM_STREAM),
753
.count = 1,
754
.info = ct_spdif_info,
755
.get = ct_spdif_get,
756
.put = ct_spdif_put,
757
.private_value = MIXER_IEC958_STREAM
758
};
759
760
#define NUM_IEC958_CTL 3
761
762
static int
763
ct_mixer_kcontrol_new(struct ct_mixer *mixer, struct snd_kcontrol_new *new)
764
{
765
struct snd_kcontrol *kctl;
766
int err;
767
768
kctl = snd_ctl_new1(new, mixer->atc);
769
if (!kctl)
770
return -ENOMEM;
771
772
if (SNDRV_CTL_ELEM_IFACE_PCM == kctl->id.iface)
773
kctl->id.device = IEC958;
774
775
err = snd_ctl_add(mixer->atc->card, kctl);
776
if (err)
777
return err;
778
779
switch (new->private_value) {
780
case MIXER_LINEIN_C_S:
781
kctls[0] = kctl; break;
782
case MIXER_MIC_C_S:
783
kctls[1] = kctl; break;
784
default:
785
break;
786
}
787
788
return 0;
789
}
790
791
static int ct_mixer_kcontrols_create(struct ct_mixer *mixer)
792
{
793
enum CTALSA_MIXER_CTL type;
794
struct ct_atc *atc = mixer->atc;
795
struct capabilities cap = atc->capabilities(atc);
796
int err;
797
798
/* Create snd kcontrol instances on demand */
799
for (type = VOL_MIXER_START; type <= VOL_MIXER_END; type++) {
800
if (ct_kcontrol_init_table[type].ctl) {
801
vol_ctl.name = ct_kcontrol_init_table[type].name;
802
vol_ctl.private_value = (unsigned long)type;
803
err = ct_mixer_kcontrol_new(mixer, &vol_ctl);
804
if (err)
805
return err;
806
}
807
}
808
809
ct_kcontrol_init_table[MIXER_DIGITAL_IO_S].ctl = cap.digit_io_switch;
810
811
for (type = SWH_MIXER_START; type <= SWH_MIXER_END; type++) {
812
if (ct_kcontrol_init_table[type].ctl) {
813
swh_ctl.name = ct_kcontrol_init_table[type].name;
814
swh_ctl.private_value = (unsigned long)type;
815
err = ct_mixer_kcontrol_new(mixer, &swh_ctl);
816
if (err)
817
return err;
818
}
819
}
820
821
err = ct_mixer_kcontrol_new(mixer, &iec958_mask_ctl);
822
if (err)
823
return err;
824
825
err = ct_mixer_kcontrol_new(mixer, &iec958_default_ctl);
826
if (err)
827
return err;
828
829
err = ct_mixer_kcontrol_new(mixer, &iec958_ctl);
830
if (err)
831
return err;
832
833
if (cap.output_switch) {
834
err = ct_mixer_kcontrol_new(mixer, &output_ctl);
835
if (err)
836
return err;
837
}
838
839
if (cap.mic_source_switch) {
840
err = ct_mixer_kcontrol_new(mixer, &mic_source_ctl);
841
if (err)
842
return err;
843
}
844
845
if (cap.dedicated_rca) {
846
err = ct_mixer_kcontrol_new(mixer, &rca_ctl);
847
if (err)
848
return err;
849
850
atc->line_front_unmute(atc, 0);
851
atc->rca_unmute(atc, 1);
852
} else {
853
atc->line_front_unmute(atc, 1);
854
}
855
set_switch_state(mixer, MIXER_WAVEF_P_S, 1);
856
atc->line_surround_unmute(atc, 0);
857
set_switch_state(mixer, MIXER_WAVES_P_S, 0);
858
atc->line_clfe_unmute(atc, 0);
859
set_switch_state(mixer, MIXER_WAVEC_P_S, 0);
860
atc->line_rear_unmute(atc, 0);
861
set_switch_state(mixer, MIXER_WAVER_P_S, 0);
862
atc->spdif_out_unmute(atc, 0);
863
set_switch_state(mixer, MIXER_SPDIFO_P_S, 0);
864
atc->line_in_unmute(atc, 0);
865
if (cap.dedicated_mic)
866
atc->mic_unmute(atc, 0);
867
atc->spdif_in_unmute(atc, 0);
868
set_switch_state(mixer, MIXER_PCM_C_S, 0);
869
set_switch_state(mixer, MIXER_LINEIN_C_S, 0);
870
set_switch_state(mixer, MIXER_SPDIFI_C_S, 0);
871
872
return 0;
873
}
874
875
static void
876
ct_mixer_recording_select(struct ct_mixer *mixer, enum CT_AMIXER_CTL type)
877
{
878
struct amixer *amix_d;
879
struct sum *sum_c;
880
int i;
881
882
for (i = 0; i < 2; i++) {
883
amix_d = mixer->amixers[type*CHN_NUM+i];
884
sum_c = mixer->sums[SUM_IN_F_C*CHN_NUM+i];
885
amix_d->ops->set_sum(amix_d, sum_c);
886
amix_d->ops->commit_write(amix_d);
887
}
888
}
889
890
static void
891
ct_mixer_recording_unselect(struct ct_mixer *mixer, enum CT_AMIXER_CTL type)
892
{
893
struct amixer *amix_d;
894
int i;
895
896
for (i = 0; i < 2; i++) {
897
amix_d = mixer->amixers[type*CHN_NUM+i];
898
amix_d->ops->set_sum(amix_d, NULL);
899
amix_d->ops->commit_write(amix_d);
900
}
901
}
902
903
static int ct_mixer_get_resources(struct ct_mixer *mixer)
904
{
905
struct sum_mgr *sum_mgr;
906
struct sum *sum;
907
struct sum_desc sum_desc = {0};
908
struct amixer_mgr *amixer_mgr;
909
struct amixer *amixer;
910
struct amixer_desc am_desc = {0};
911
int err;
912
int i;
913
914
/* Allocate sum resources for mixer obj */
915
sum_mgr = (struct sum_mgr *)mixer->atc->rsc_mgrs[SUM];
916
sum_desc.msr = mixer->atc->msr;
917
for (i = 0; i < (NUM_CT_SUMS * CHN_NUM); i++) {
918
err = sum_mgr->get_sum(sum_mgr, &sum_desc, &sum);
919
if (err) {
920
dev_err(mixer->atc->card->dev,
921
"Failed to get sum resources for front output!\n");
922
break;
923
}
924
mixer->sums[i] = sum;
925
}
926
if (err)
927
goto error1;
928
929
/* Allocate amixer resources for mixer obj */
930
amixer_mgr = (struct amixer_mgr *)mixer->atc->rsc_mgrs[AMIXER];
931
am_desc.msr = mixer->atc->msr;
932
for (i = 0; i < (NUM_CT_AMIXERS * CHN_NUM); i++) {
933
err = amixer_mgr->get_amixer(amixer_mgr, &am_desc, &amixer);
934
if (err) {
935
dev_err(mixer->atc->card->dev,
936
"Failed to get amixer resources for mixer obj!\n");
937
break;
938
}
939
mixer->amixers[i] = amixer;
940
}
941
if (err)
942
goto error2;
943
944
return 0;
945
946
error2:
947
for (i = 0; i < (NUM_CT_AMIXERS * CHN_NUM); i++) {
948
if (NULL != mixer->amixers[i]) {
949
amixer = mixer->amixers[i];
950
amixer_mgr->put_amixer(amixer_mgr, amixer);
951
mixer->amixers[i] = NULL;
952
}
953
}
954
error1:
955
for (i = 0; i < (NUM_CT_SUMS * CHN_NUM); i++) {
956
if (NULL != mixer->sums[i]) {
957
sum_mgr->put_sum(sum_mgr, (struct sum *)mixer->sums[i]);
958
mixer->sums[i] = NULL;
959
}
960
}
961
962
return err;
963
}
964
965
static int ct_mixer_get_mem(struct ct_mixer **rmixer)
966
{
967
struct ct_mixer *mixer;
968
int err;
969
970
*rmixer = NULL;
971
/* Allocate mem for mixer obj */
972
mixer = kzalloc(sizeof(*mixer), GFP_KERNEL);
973
if (!mixer)
974
return -ENOMEM;
975
976
mixer->amixers = kcalloc(NUM_CT_AMIXERS * CHN_NUM, sizeof(void *),
977
GFP_KERNEL);
978
if (!mixer->amixers) {
979
err = -ENOMEM;
980
goto error1;
981
}
982
mixer->sums = kcalloc(NUM_CT_SUMS * CHN_NUM, sizeof(void *),
983
GFP_KERNEL);
984
if (!mixer->sums) {
985
err = -ENOMEM;
986
goto error2;
987
}
988
989
*rmixer = mixer;
990
return 0;
991
992
error2:
993
kfree(mixer->amixers);
994
error1:
995
kfree(mixer);
996
return err;
997
}
998
999
static int ct_mixer_topology_build(struct ct_mixer *mixer)
1000
{
1001
struct sum *sum;
1002
struct amixer *amix_d, *amix_s;
1003
enum CT_AMIXER_CTL i, j;
1004
enum CT_SUM_CTL k;
1005
1006
/* Build topology from destination to source */
1007
1008
/* Set up Master mixer */
1009
for (i = AMIXER_MASTER_F, k = SUM_IN_F;
1010
i <= AMIXER_MASTER_S; i++, k++) {
1011
amix_d = mixer->amixers[i*CHN_NUM];
1012
sum = mixer->sums[k*CHN_NUM];
1013
amix_d->ops->setup(amix_d, &sum->rsc, INIT_VOL, NULL);
1014
amix_d = mixer->amixers[i*CHN_NUM+1];
1015
sum = mixer->sums[k*CHN_NUM+1];
1016
amix_d->ops->setup(amix_d, &sum->rsc, INIT_VOL, NULL);
1017
}
1018
1019
/* Set up Wave-out mixer */
1020
for (i = AMIXER_WAVE_F, j = AMIXER_MASTER_F;
1021
i <= AMIXER_WAVE_S; i++, j++) {
1022
amix_d = mixer->amixers[i*CHN_NUM];
1023
amix_s = mixer->amixers[j*CHN_NUM];
1024
amix_d->ops->setup(amix_d, &amix_s->rsc, INIT_VOL, NULL);
1025
amix_d = mixer->amixers[i*CHN_NUM+1];
1026
amix_s = mixer->amixers[j*CHN_NUM+1];
1027
amix_d->ops->setup(amix_d, &amix_s->rsc, INIT_VOL, NULL);
1028
}
1029
1030
/* Set up S/PDIF-out mixer */
1031
amix_d = mixer->amixers[AMIXER_SPDIFO*CHN_NUM];
1032
amix_s = mixer->amixers[AMIXER_MASTER_F*CHN_NUM];
1033
amix_d->ops->setup(amix_d, &amix_s->rsc, INIT_VOL, NULL);
1034
amix_d = mixer->amixers[AMIXER_SPDIFO*CHN_NUM+1];
1035
amix_s = mixer->amixers[AMIXER_MASTER_F*CHN_NUM+1];
1036
amix_d->ops->setup(amix_d, &amix_s->rsc, INIT_VOL, NULL);
1037
1038
/* Set up PCM-in mixer */
1039
for (i = AMIXER_PCM_F, k = SUM_IN_F; i <= AMIXER_PCM_S; i++, k++) {
1040
amix_d = mixer->amixers[i*CHN_NUM];
1041
sum = mixer->sums[k*CHN_NUM];
1042
amix_d->ops->setup(amix_d, NULL, INIT_VOL, sum);
1043
amix_d = mixer->amixers[i*CHN_NUM+1];
1044
sum = mixer->sums[k*CHN_NUM+1];
1045
amix_d->ops->setup(amix_d, NULL, INIT_VOL, sum);
1046
}
1047
1048
/* Set up Line-in mixer */
1049
amix_d = mixer->amixers[AMIXER_LINEIN*CHN_NUM];
1050
sum = mixer->sums[SUM_IN_F*CHN_NUM];
1051
amix_d->ops->setup(amix_d, NULL, INIT_VOL, sum);
1052
amix_d = mixer->amixers[AMIXER_LINEIN*CHN_NUM+1];
1053
sum = mixer->sums[SUM_IN_F*CHN_NUM+1];
1054
amix_d->ops->setup(amix_d, NULL, INIT_VOL, sum);
1055
1056
/* Set up Mic-in mixer */
1057
amix_d = mixer->amixers[AMIXER_MIC*CHN_NUM];
1058
sum = mixer->sums[SUM_IN_F*CHN_NUM];
1059
amix_d->ops->setup(amix_d, NULL, INIT_VOL, sum);
1060
amix_d = mixer->amixers[AMIXER_MIC*CHN_NUM+1];
1061
sum = mixer->sums[SUM_IN_F*CHN_NUM+1];
1062
amix_d->ops->setup(amix_d, NULL, INIT_VOL, sum);
1063
1064
/* Set up S/PDIF-in mixer */
1065
amix_d = mixer->amixers[AMIXER_SPDIFI*CHN_NUM];
1066
sum = mixer->sums[SUM_IN_F*CHN_NUM];
1067
amix_d->ops->setup(amix_d, NULL, INIT_VOL, sum);
1068
amix_d = mixer->amixers[AMIXER_SPDIFI*CHN_NUM+1];
1069
sum = mixer->sums[SUM_IN_F*CHN_NUM+1];
1070
amix_d->ops->setup(amix_d, NULL, INIT_VOL, sum);
1071
1072
/* Set up Master recording mixer */
1073
amix_d = mixer->amixers[AMIXER_MASTER_F_C*CHN_NUM];
1074
sum = mixer->sums[SUM_IN_F_C*CHN_NUM];
1075
amix_d->ops->setup(amix_d, &sum->rsc, INIT_VOL, NULL);
1076
amix_d = mixer->amixers[AMIXER_MASTER_F_C*CHN_NUM+1];
1077
sum = mixer->sums[SUM_IN_F_C*CHN_NUM+1];
1078
amix_d->ops->setup(amix_d, &sum->rsc, INIT_VOL, NULL);
1079
1080
/* Set up PCM-in recording mixer */
1081
amix_d = mixer->amixers[AMIXER_PCM_F_C*CHN_NUM];
1082
sum = mixer->sums[SUM_IN_F_C*CHN_NUM];
1083
amix_d->ops->setup(amix_d, NULL, INIT_VOL, sum);
1084
amix_d = mixer->amixers[AMIXER_PCM_F_C*CHN_NUM+1];
1085
sum = mixer->sums[SUM_IN_F_C*CHN_NUM+1];
1086
amix_d->ops->setup(amix_d, NULL, INIT_VOL, sum);
1087
1088
/* Set up Line-in recording mixer */
1089
amix_d = mixer->amixers[AMIXER_LINEIN_C*CHN_NUM];
1090
sum = mixer->sums[SUM_IN_F_C*CHN_NUM];
1091
amix_d->ops->setup(amix_d, NULL, INIT_VOL, sum);
1092
amix_d = mixer->amixers[AMIXER_LINEIN_C*CHN_NUM+1];
1093
sum = mixer->sums[SUM_IN_F_C*CHN_NUM+1];
1094
amix_d->ops->setup(amix_d, NULL, INIT_VOL, sum);
1095
1096
/* Set up Mic-in recording mixer */
1097
amix_d = mixer->amixers[AMIXER_MIC_C*CHN_NUM];
1098
sum = mixer->sums[SUM_IN_F_C*CHN_NUM];
1099
amix_d->ops->setup(amix_d, NULL, INIT_VOL, sum);
1100
amix_d = mixer->amixers[AMIXER_MIC_C*CHN_NUM+1];
1101
sum = mixer->sums[SUM_IN_F_C*CHN_NUM+1];
1102
amix_d->ops->setup(amix_d, NULL, INIT_VOL, sum);
1103
1104
/* Set up S/PDIF-in recording mixer */
1105
amix_d = mixer->amixers[AMIXER_SPDIFI_C*CHN_NUM];
1106
sum = mixer->sums[SUM_IN_F_C*CHN_NUM];
1107
amix_d->ops->setup(amix_d, NULL, INIT_VOL, sum);
1108
amix_d = mixer->amixers[AMIXER_SPDIFI_C*CHN_NUM+1];
1109
sum = mixer->sums[SUM_IN_F_C*CHN_NUM+1];
1110
amix_d->ops->setup(amix_d, NULL, INIT_VOL, sum);
1111
1112
return 0;
1113
}
1114
1115
static int mixer_set_input_port(struct amixer *amixer, struct rsc *rsc)
1116
{
1117
amixer->ops->set_input(amixer, rsc);
1118
amixer->ops->commit_write(amixer);
1119
1120
return 0;
1121
}
1122
1123
static enum CT_AMIXER_CTL port_to_amixer(enum MIXER_PORT_T type)
1124
{
1125
switch (type) {
1126
case MIX_WAVE_FRONT: return AMIXER_WAVE_F;
1127
case MIX_WAVE_SURROUND: return AMIXER_WAVE_S;
1128
case MIX_WAVE_CENTLFE: return AMIXER_WAVE_C;
1129
case MIX_WAVE_REAR: return AMIXER_WAVE_R;
1130
case MIX_PCMO_FRONT: return AMIXER_MASTER_F_C;
1131
case MIX_SPDIF_OUT: return AMIXER_SPDIFO;
1132
case MIX_LINE_IN: return AMIXER_LINEIN;
1133
case MIX_MIC_IN: return AMIXER_MIC;
1134
case MIX_SPDIF_IN: return AMIXER_SPDIFI;
1135
case MIX_PCMI_FRONT: return AMIXER_PCM_F;
1136
case MIX_PCMI_SURROUND: return AMIXER_PCM_S;
1137
case MIX_PCMI_CENTLFE: return AMIXER_PCM_C;
1138
case MIX_PCMI_REAR: return AMIXER_PCM_R;
1139
default: return 0;
1140
}
1141
}
1142
1143
static int mixer_get_output_ports(struct ct_mixer *mixer,
1144
enum MIXER_PORT_T type,
1145
struct rsc **rleft, struct rsc **rright)
1146
{
1147
enum CT_AMIXER_CTL amix = port_to_amixer(type);
1148
1149
if (NULL != rleft)
1150
*rleft = &((struct amixer *)mixer->amixers[amix*CHN_NUM])->rsc;
1151
1152
if (NULL != rright)
1153
*rright =
1154
&((struct amixer *)mixer->amixers[amix*CHN_NUM+1])->rsc;
1155
1156
return 0;
1157
}
1158
1159
static int mixer_set_input_left(struct ct_mixer *mixer,
1160
enum MIXER_PORT_T type, struct rsc *rsc)
1161
{
1162
enum CT_AMIXER_CTL amix = port_to_amixer(type);
1163
1164
mixer_set_input_port(mixer->amixers[amix*CHN_NUM], rsc);
1165
amix = get_recording_amixer(amix);
1166
if (amix < NUM_CT_AMIXERS)
1167
mixer_set_input_port(mixer->amixers[amix*CHN_NUM], rsc);
1168
1169
return 0;
1170
}
1171
1172
static int
1173
mixer_set_input_right(struct ct_mixer *mixer,
1174
enum MIXER_PORT_T type, struct rsc *rsc)
1175
{
1176
enum CT_AMIXER_CTL amix = port_to_amixer(type);
1177
1178
mixer_set_input_port(mixer->amixers[amix*CHN_NUM+1], rsc);
1179
amix = get_recording_amixer(amix);
1180
if (amix < NUM_CT_AMIXERS)
1181
mixer_set_input_port(mixer->amixers[amix*CHN_NUM+1], rsc);
1182
1183
return 0;
1184
}
1185
1186
#ifdef CONFIG_PM_SLEEP
1187
static int mixer_resume(struct ct_mixer *mixer)
1188
{
1189
int i, state;
1190
struct amixer *amixer;
1191
1192
/* resume topology and volume gain. */
1193
for (i = 0; i < NUM_CT_AMIXERS*CHN_NUM; i++) {
1194
amixer = mixer->amixers[i];
1195
amixer->ops->commit_write(amixer);
1196
}
1197
1198
/* resume switch state. */
1199
for (i = SWH_MIXER_START; i <= SWH_MIXER_END; i++) {
1200
state = get_switch_state(mixer, i);
1201
do_switch(mixer->atc, i, state);
1202
}
1203
1204
return 0;
1205
}
1206
#endif
1207
1208
int ct_mixer_destroy(struct ct_mixer *mixer)
1209
{
1210
struct sum_mgr *sum_mgr = (struct sum_mgr *)mixer->atc->rsc_mgrs[SUM];
1211
struct amixer_mgr *amixer_mgr =
1212
(struct amixer_mgr *)mixer->atc->rsc_mgrs[AMIXER];
1213
struct amixer *amixer;
1214
int i = 0;
1215
1216
/* Release amixer resources */
1217
for (i = 0; i < (NUM_CT_AMIXERS * CHN_NUM); i++) {
1218
if (NULL != mixer->amixers[i]) {
1219
amixer = mixer->amixers[i];
1220
amixer_mgr->put_amixer(amixer_mgr, amixer);
1221
}
1222
}
1223
1224
/* Release sum resources */
1225
for (i = 0; i < (NUM_CT_SUMS * CHN_NUM); i++) {
1226
if (NULL != mixer->sums[i])
1227
sum_mgr->put_sum(sum_mgr, (struct sum *)mixer->sums[i]);
1228
}
1229
1230
/* Release mem assigned to mixer object */
1231
kfree(mixer->sums);
1232
kfree(mixer->amixers);
1233
kfree(mixer);
1234
1235
return 0;
1236
}
1237
1238
int ct_mixer_create(struct ct_atc *atc, struct ct_mixer **rmixer)
1239
{
1240
struct ct_mixer *mixer;
1241
int err;
1242
1243
*rmixer = NULL;
1244
1245
/* Allocate mem for mixer obj */
1246
err = ct_mixer_get_mem(&mixer);
1247
if (err)
1248
return err;
1249
1250
mixer->switch_state = 0;
1251
mixer->atc = atc;
1252
/* Set operations */
1253
mixer->get_output_ports = mixer_get_output_ports;
1254
mixer->set_input_left = mixer_set_input_left;
1255
mixer->set_input_right = mixer_set_input_right;
1256
#ifdef CONFIG_PM_SLEEP
1257
mixer->resume = mixer_resume;
1258
#endif
1259
1260
/* Allocate chip resources for mixer obj */
1261
err = ct_mixer_get_resources(mixer);
1262
if (err)
1263
goto error;
1264
1265
/* Build internal mixer topology */
1266
ct_mixer_topology_build(mixer);
1267
1268
*rmixer = mixer;
1269
1270
return 0;
1271
1272
error:
1273
ct_mixer_destroy(mixer);
1274
return err;
1275
}
1276
1277
int ct_alsa_mix_create(struct ct_atc *atc,
1278
enum CTALSADEVS device,
1279
const char *device_name)
1280
{
1281
int err;
1282
1283
/* Create snd kcontrol instances on demand */
1284
/* vol_ctl.device = swh_ctl.device = device; */ /* better w/ device 0 */
1285
err = ct_mixer_kcontrols_create((struct ct_mixer *)atc->mixer);
1286
if (err)
1287
return err;
1288
1289
strscpy(atc->card->mixername, device_name);
1290
1291
return 0;
1292
}
1293
1294