Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
awilliam
GitHub Repository: awilliam/linux-vfio
Path: blob/master/sound/isa/sb/sb_mixer.c
10817 views
1
/*
2
* Copyright (c) by Jaroslav Kysela <[email protected]>
3
* Routines for Sound Blaster mixer control
4
*
5
*
6
* This program is free software; you can redistribute it and/or modify
7
* it under the terms of the GNU General Public License as published by
8
* the Free Software Foundation; either version 2 of the License, or
9
* (at your option) any later version.
10
*
11
* This program is distributed in the hope that it will be useful,
12
* but WITHOUT ANY WARRANTY; without even the implied warranty of
13
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14
* GNU General Public License for more details.
15
*
16
* You should have received a copy of the GNU General Public License
17
* along with this program; if not, write to the Free Software
18
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
19
*
20
*/
21
22
#include <asm/io.h>
23
#include <linux/delay.h>
24
#include <linux/time.h>
25
#include <sound/core.h>
26
#include <sound/sb.h>
27
#include <sound/control.h>
28
29
#undef IO_DEBUG
30
31
void snd_sbmixer_write(struct snd_sb *chip, unsigned char reg, unsigned char data)
32
{
33
outb(reg, SBP(chip, MIXER_ADDR));
34
udelay(10);
35
outb(data, SBP(chip, MIXER_DATA));
36
udelay(10);
37
#ifdef IO_DEBUG
38
snd_printk(KERN_DEBUG "mixer_write 0x%x 0x%x\n", reg, data);
39
#endif
40
}
41
42
unsigned char snd_sbmixer_read(struct snd_sb *chip, unsigned char reg)
43
{
44
unsigned char result;
45
46
outb(reg, SBP(chip, MIXER_ADDR));
47
udelay(10);
48
result = inb(SBP(chip, MIXER_DATA));
49
udelay(10);
50
#ifdef IO_DEBUG
51
snd_printk(KERN_DEBUG "mixer_read 0x%x 0x%x\n", reg, result);
52
#endif
53
return result;
54
}
55
56
/*
57
* Single channel mixer element
58
*/
59
60
static int snd_sbmixer_info_single(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo)
61
{
62
int mask = (kcontrol->private_value >> 24) & 0xff;
63
64
uinfo->type = mask == 1 ? SNDRV_CTL_ELEM_TYPE_BOOLEAN : SNDRV_CTL_ELEM_TYPE_INTEGER;
65
uinfo->count = 1;
66
uinfo->value.integer.min = 0;
67
uinfo->value.integer.max = mask;
68
return 0;
69
}
70
71
static int snd_sbmixer_get_single(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
72
{
73
struct snd_sb *sb = snd_kcontrol_chip(kcontrol);
74
unsigned long flags;
75
int reg = kcontrol->private_value & 0xff;
76
int shift = (kcontrol->private_value >> 16) & 0xff;
77
int mask = (kcontrol->private_value >> 24) & 0xff;
78
unsigned char val;
79
80
spin_lock_irqsave(&sb->mixer_lock, flags);
81
val = (snd_sbmixer_read(sb, reg) >> shift) & mask;
82
spin_unlock_irqrestore(&sb->mixer_lock, flags);
83
ucontrol->value.integer.value[0] = val;
84
return 0;
85
}
86
87
static int snd_sbmixer_put_single(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
88
{
89
struct snd_sb *sb = snd_kcontrol_chip(kcontrol);
90
unsigned long flags;
91
int reg = kcontrol->private_value & 0xff;
92
int shift = (kcontrol->private_value >> 16) & 0x07;
93
int mask = (kcontrol->private_value >> 24) & 0xff;
94
int change;
95
unsigned char val, oval;
96
97
val = (ucontrol->value.integer.value[0] & mask) << shift;
98
spin_lock_irqsave(&sb->mixer_lock, flags);
99
oval = snd_sbmixer_read(sb, reg);
100
val = (oval & ~(mask << shift)) | val;
101
change = val != oval;
102
if (change)
103
snd_sbmixer_write(sb, reg, val);
104
spin_unlock_irqrestore(&sb->mixer_lock, flags);
105
return change;
106
}
107
108
/*
109
* Double channel mixer element
110
*/
111
112
static int snd_sbmixer_info_double(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo)
113
{
114
int mask = (kcontrol->private_value >> 24) & 0xff;
115
116
uinfo->type = mask == 1 ? SNDRV_CTL_ELEM_TYPE_BOOLEAN : SNDRV_CTL_ELEM_TYPE_INTEGER;
117
uinfo->count = 2;
118
uinfo->value.integer.min = 0;
119
uinfo->value.integer.max = mask;
120
return 0;
121
}
122
123
static int snd_sbmixer_get_double(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
124
{
125
struct snd_sb *sb = snd_kcontrol_chip(kcontrol);
126
unsigned long flags;
127
int left_reg = kcontrol->private_value & 0xff;
128
int right_reg = (kcontrol->private_value >> 8) & 0xff;
129
int left_shift = (kcontrol->private_value >> 16) & 0x07;
130
int right_shift = (kcontrol->private_value >> 19) & 0x07;
131
int mask = (kcontrol->private_value >> 24) & 0xff;
132
unsigned char left, right;
133
134
spin_lock_irqsave(&sb->mixer_lock, flags);
135
left = (snd_sbmixer_read(sb, left_reg) >> left_shift) & mask;
136
right = (snd_sbmixer_read(sb, right_reg) >> right_shift) & mask;
137
spin_unlock_irqrestore(&sb->mixer_lock, flags);
138
ucontrol->value.integer.value[0] = left;
139
ucontrol->value.integer.value[1] = right;
140
return 0;
141
}
142
143
static int snd_sbmixer_put_double(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
144
{
145
struct snd_sb *sb = snd_kcontrol_chip(kcontrol);
146
unsigned long flags;
147
int left_reg = kcontrol->private_value & 0xff;
148
int right_reg = (kcontrol->private_value >> 8) & 0xff;
149
int left_shift = (kcontrol->private_value >> 16) & 0x07;
150
int right_shift = (kcontrol->private_value >> 19) & 0x07;
151
int mask = (kcontrol->private_value >> 24) & 0xff;
152
int change;
153
unsigned char left, right, oleft, oright;
154
155
left = (ucontrol->value.integer.value[0] & mask) << left_shift;
156
right = (ucontrol->value.integer.value[1] & mask) << right_shift;
157
spin_lock_irqsave(&sb->mixer_lock, flags);
158
if (left_reg == right_reg) {
159
oleft = snd_sbmixer_read(sb, left_reg);
160
left = (oleft & ~((mask << left_shift) | (mask << right_shift))) | left | right;
161
change = left != oleft;
162
if (change)
163
snd_sbmixer_write(sb, left_reg, left);
164
} else {
165
oleft = snd_sbmixer_read(sb, left_reg);
166
oright = snd_sbmixer_read(sb, right_reg);
167
left = (oleft & ~(mask << left_shift)) | left;
168
right = (oright & ~(mask << right_shift)) | right;
169
change = left != oleft || right != oright;
170
if (change) {
171
snd_sbmixer_write(sb, left_reg, left);
172
snd_sbmixer_write(sb, right_reg, right);
173
}
174
}
175
spin_unlock_irqrestore(&sb->mixer_lock, flags);
176
return change;
177
}
178
179
/*
180
* DT-019x / ALS-007 capture/input switch
181
*/
182
183
static int snd_dt019x_input_sw_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo)
184
{
185
static const char *texts[5] = {
186
"CD", "Mic", "Line", "Synth", "Master"
187
};
188
189
uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
190
uinfo->count = 1;
191
uinfo->value.enumerated.items = 5;
192
if (uinfo->value.enumerated.item > 4)
193
uinfo->value.enumerated.item = 4;
194
strcpy(uinfo->value.enumerated.name, texts[uinfo->value.enumerated.item]);
195
return 0;
196
}
197
198
static int snd_dt019x_input_sw_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
199
{
200
struct snd_sb *sb = snd_kcontrol_chip(kcontrol);
201
unsigned long flags;
202
unsigned char oval;
203
204
spin_lock_irqsave(&sb->mixer_lock, flags);
205
oval = snd_sbmixer_read(sb, SB_DT019X_CAPTURE_SW);
206
spin_unlock_irqrestore(&sb->mixer_lock, flags);
207
switch (oval & 0x07) {
208
case SB_DT019X_CAP_CD:
209
ucontrol->value.enumerated.item[0] = 0;
210
break;
211
case SB_DT019X_CAP_MIC:
212
ucontrol->value.enumerated.item[0] = 1;
213
break;
214
case SB_DT019X_CAP_LINE:
215
ucontrol->value.enumerated.item[0] = 2;
216
break;
217
case SB_DT019X_CAP_MAIN:
218
ucontrol->value.enumerated.item[0] = 4;
219
break;
220
/* To record the synth on these cards you must record the main. */
221
/* Thus SB_DT019X_CAP_SYNTH == SB_DT019X_CAP_MAIN and would cause */
222
/* duplicate case labels if left uncommented. */
223
/* case SB_DT019X_CAP_SYNTH:
224
* ucontrol->value.enumerated.item[0] = 3;
225
* break;
226
*/
227
default:
228
ucontrol->value.enumerated.item[0] = 4;
229
break;
230
}
231
return 0;
232
}
233
234
static int snd_dt019x_input_sw_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
235
{
236
struct snd_sb *sb = snd_kcontrol_chip(kcontrol);
237
unsigned long flags;
238
int change;
239
unsigned char nval, oval;
240
241
if (ucontrol->value.enumerated.item[0] > 4)
242
return -EINVAL;
243
switch (ucontrol->value.enumerated.item[0]) {
244
case 0:
245
nval = SB_DT019X_CAP_CD;
246
break;
247
case 1:
248
nval = SB_DT019X_CAP_MIC;
249
break;
250
case 2:
251
nval = SB_DT019X_CAP_LINE;
252
break;
253
case 3:
254
nval = SB_DT019X_CAP_SYNTH;
255
break;
256
case 4:
257
nval = SB_DT019X_CAP_MAIN;
258
break;
259
default:
260
nval = SB_DT019X_CAP_MAIN;
261
}
262
spin_lock_irqsave(&sb->mixer_lock, flags);
263
oval = snd_sbmixer_read(sb, SB_DT019X_CAPTURE_SW);
264
change = nval != oval;
265
if (change)
266
snd_sbmixer_write(sb, SB_DT019X_CAPTURE_SW, nval);
267
spin_unlock_irqrestore(&sb->mixer_lock, flags);
268
return change;
269
}
270
271
/*
272
* ALS4000 mono recording control switch
273
*/
274
275
static int snd_als4k_mono_capture_route_info(struct snd_kcontrol *kcontrol,
276
struct snd_ctl_elem_info *uinfo)
277
{
278
static const char *texts[3] = {
279
"L chan only", "R chan only", "L ch/2 + R ch/2"
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,
288
texts[uinfo->value.enumerated.item]);
289
return 0;
290
}
291
292
static int snd_als4k_mono_capture_route_get(struct snd_kcontrol *kcontrol,
293
struct snd_ctl_elem_value *ucontrol)
294
{
295
struct snd_sb *sb = snd_kcontrol_chip(kcontrol);
296
unsigned long flags;
297
unsigned char oval;
298
299
spin_lock_irqsave(&sb->mixer_lock, flags);
300
oval = snd_sbmixer_read(sb, SB_ALS4000_MONO_IO_CTRL);
301
spin_unlock_irqrestore(&sb->mixer_lock, flags);
302
oval >>= 6;
303
if (oval > 2)
304
oval = 2;
305
306
ucontrol->value.enumerated.item[0] = oval;
307
return 0;
308
}
309
310
static int snd_als4k_mono_capture_route_put(struct snd_kcontrol *kcontrol,
311
struct snd_ctl_elem_value *ucontrol)
312
{
313
struct snd_sb *sb = snd_kcontrol_chip(kcontrol);
314
unsigned long flags;
315
int change;
316
unsigned char nval, oval;
317
318
if (ucontrol->value.enumerated.item[0] > 2)
319
return -EINVAL;
320
spin_lock_irqsave(&sb->mixer_lock, flags);
321
oval = snd_sbmixer_read(sb, SB_ALS4000_MONO_IO_CTRL);
322
323
nval = (oval & ~(3 << 6))
324
| (ucontrol->value.enumerated.item[0] << 6);
325
change = nval != oval;
326
if (change)
327
snd_sbmixer_write(sb, SB_ALS4000_MONO_IO_CTRL, nval);
328
spin_unlock_irqrestore(&sb->mixer_lock, flags);
329
return change;
330
}
331
332
/*
333
* SBPRO input multiplexer
334
*/
335
336
static int snd_sb8mixer_info_mux(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo)
337
{
338
static const char *texts[3] = {
339
"Mic", "CD", "Line"
340
};
341
342
uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
343
uinfo->count = 1;
344
uinfo->value.enumerated.items = 3;
345
if (uinfo->value.enumerated.item > 2)
346
uinfo->value.enumerated.item = 2;
347
strcpy(uinfo->value.enumerated.name, texts[uinfo->value.enumerated.item]);
348
return 0;
349
}
350
351
352
static int snd_sb8mixer_get_mux(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
353
{
354
struct snd_sb *sb = snd_kcontrol_chip(kcontrol);
355
unsigned long flags;
356
unsigned char oval;
357
358
spin_lock_irqsave(&sb->mixer_lock, flags);
359
oval = snd_sbmixer_read(sb, SB_DSP_CAPTURE_SOURCE);
360
spin_unlock_irqrestore(&sb->mixer_lock, flags);
361
switch ((oval >> 0x01) & 0x03) {
362
case SB_DSP_MIXS_CD:
363
ucontrol->value.enumerated.item[0] = 1;
364
break;
365
case SB_DSP_MIXS_LINE:
366
ucontrol->value.enumerated.item[0] = 2;
367
break;
368
default:
369
ucontrol->value.enumerated.item[0] = 0;
370
break;
371
}
372
return 0;
373
}
374
375
static int snd_sb8mixer_put_mux(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
376
{
377
struct snd_sb *sb = snd_kcontrol_chip(kcontrol);
378
unsigned long flags;
379
int change;
380
unsigned char nval, oval;
381
382
if (ucontrol->value.enumerated.item[0] > 2)
383
return -EINVAL;
384
switch (ucontrol->value.enumerated.item[0]) {
385
case 1:
386
nval = SB_DSP_MIXS_CD;
387
break;
388
case 2:
389
nval = SB_DSP_MIXS_LINE;
390
break;
391
default:
392
nval = SB_DSP_MIXS_MIC;
393
}
394
nval <<= 1;
395
spin_lock_irqsave(&sb->mixer_lock, flags);
396
oval = snd_sbmixer_read(sb, SB_DSP_CAPTURE_SOURCE);
397
nval |= oval & ~0x06;
398
change = nval != oval;
399
if (change)
400
snd_sbmixer_write(sb, SB_DSP_CAPTURE_SOURCE, nval);
401
spin_unlock_irqrestore(&sb->mixer_lock, flags);
402
return change;
403
}
404
405
/*
406
* SB16 input switch
407
*/
408
409
static int snd_sb16mixer_info_input_sw(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo)
410
{
411
uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN;
412
uinfo->count = 4;
413
uinfo->value.integer.min = 0;
414
uinfo->value.integer.max = 1;
415
return 0;
416
}
417
418
static int snd_sb16mixer_get_input_sw(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
419
{
420
struct snd_sb *sb = snd_kcontrol_chip(kcontrol);
421
unsigned long flags;
422
int reg1 = kcontrol->private_value & 0xff;
423
int reg2 = (kcontrol->private_value >> 8) & 0xff;
424
int left_shift = (kcontrol->private_value >> 16) & 0x0f;
425
int right_shift = (kcontrol->private_value >> 24) & 0x0f;
426
unsigned char val1, val2;
427
428
spin_lock_irqsave(&sb->mixer_lock, flags);
429
val1 = snd_sbmixer_read(sb, reg1);
430
val2 = snd_sbmixer_read(sb, reg2);
431
spin_unlock_irqrestore(&sb->mixer_lock, flags);
432
ucontrol->value.integer.value[0] = (val1 >> left_shift) & 0x01;
433
ucontrol->value.integer.value[1] = (val2 >> left_shift) & 0x01;
434
ucontrol->value.integer.value[2] = (val1 >> right_shift) & 0x01;
435
ucontrol->value.integer.value[3] = (val2 >> right_shift) & 0x01;
436
return 0;
437
}
438
439
static int snd_sb16mixer_put_input_sw(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
440
{
441
struct snd_sb *sb = snd_kcontrol_chip(kcontrol);
442
unsigned long flags;
443
int reg1 = kcontrol->private_value & 0xff;
444
int reg2 = (kcontrol->private_value >> 8) & 0xff;
445
int left_shift = (kcontrol->private_value >> 16) & 0x0f;
446
int right_shift = (kcontrol->private_value >> 24) & 0x0f;
447
int change;
448
unsigned char val1, val2, oval1, oval2;
449
450
spin_lock_irqsave(&sb->mixer_lock, flags);
451
oval1 = snd_sbmixer_read(sb, reg1);
452
oval2 = snd_sbmixer_read(sb, reg2);
453
val1 = oval1 & ~((1 << left_shift) | (1 << right_shift));
454
val2 = oval2 & ~((1 << left_shift) | (1 << right_shift));
455
val1 |= (ucontrol->value.integer.value[0] & 1) << left_shift;
456
val2 |= (ucontrol->value.integer.value[1] & 1) << left_shift;
457
val1 |= (ucontrol->value.integer.value[2] & 1) << right_shift;
458
val2 |= (ucontrol->value.integer.value[3] & 1) << right_shift;
459
change = val1 != oval1 || val2 != oval2;
460
if (change) {
461
snd_sbmixer_write(sb, reg1, val1);
462
snd_sbmixer_write(sb, reg2, val2);
463
}
464
spin_unlock_irqrestore(&sb->mixer_lock, flags);
465
return change;
466
}
467
468
469
/*
470
*/
471
/*
472
*/
473
int snd_sbmixer_add_ctl(struct snd_sb *chip, const char *name, int index, int type, unsigned long value)
474
{
475
static struct snd_kcontrol_new newctls[] = {
476
[SB_MIX_SINGLE] = {
477
.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
478
.info = snd_sbmixer_info_single,
479
.get = snd_sbmixer_get_single,
480
.put = snd_sbmixer_put_single,
481
},
482
[SB_MIX_DOUBLE] = {
483
.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
484
.info = snd_sbmixer_info_double,
485
.get = snd_sbmixer_get_double,
486
.put = snd_sbmixer_put_double,
487
},
488
[SB_MIX_INPUT_SW] = {
489
.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
490
.info = snd_sb16mixer_info_input_sw,
491
.get = snd_sb16mixer_get_input_sw,
492
.put = snd_sb16mixer_put_input_sw,
493
},
494
[SB_MIX_CAPTURE_PRO] = {
495
.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
496
.info = snd_sb8mixer_info_mux,
497
.get = snd_sb8mixer_get_mux,
498
.put = snd_sb8mixer_put_mux,
499
},
500
[SB_MIX_CAPTURE_DT019X] = {
501
.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
502
.info = snd_dt019x_input_sw_info,
503
.get = snd_dt019x_input_sw_get,
504
.put = snd_dt019x_input_sw_put,
505
},
506
[SB_MIX_MONO_CAPTURE_ALS4K] = {
507
.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
508
.info = snd_als4k_mono_capture_route_info,
509
.get = snd_als4k_mono_capture_route_get,
510
.put = snd_als4k_mono_capture_route_put,
511
},
512
};
513
struct snd_kcontrol *ctl;
514
int err;
515
516
ctl = snd_ctl_new1(&newctls[type], chip);
517
if (! ctl)
518
return -ENOMEM;
519
strlcpy(ctl->id.name, name, sizeof(ctl->id.name));
520
ctl->id.index = index;
521
ctl->private_value = value;
522
if ((err = snd_ctl_add(chip->card, ctl)) < 0)
523
return err;
524
return 0;
525
}
526
527
/*
528
* SB 2.0 specific mixer elements
529
*/
530
531
static struct sbmix_elem snd_sb20_controls[] = {
532
SB_SINGLE("Master Playback Volume", SB_DSP20_MASTER_DEV, 1, 7),
533
SB_SINGLE("PCM Playback Volume", SB_DSP20_PCM_DEV, 1, 3),
534
SB_SINGLE("Synth Playback Volume", SB_DSP20_FM_DEV, 1, 7),
535
SB_SINGLE("CD Playback Volume", SB_DSP20_CD_DEV, 1, 7)
536
};
537
538
static unsigned char snd_sb20_init_values[][2] = {
539
{ SB_DSP20_MASTER_DEV, 0 },
540
{ SB_DSP20_FM_DEV, 0 },
541
};
542
543
/*
544
* SB Pro specific mixer elements
545
*/
546
static struct sbmix_elem snd_sbpro_controls[] = {
547
SB_DOUBLE("Master Playback Volume",
548
SB_DSP_MASTER_DEV, SB_DSP_MASTER_DEV, 5, 1, 7),
549
SB_DOUBLE("PCM Playback Volume",
550
SB_DSP_PCM_DEV, SB_DSP_PCM_DEV, 5, 1, 7),
551
SB_SINGLE("PCM Playback Filter", SB_DSP_PLAYBACK_FILT, 5, 1),
552
SB_DOUBLE("Synth Playback Volume",
553
SB_DSP_FM_DEV, SB_DSP_FM_DEV, 5, 1, 7),
554
SB_DOUBLE("CD Playback Volume", SB_DSP_CD_DEV, SB_DSP_CD_DEV, 5, 1, 7),
555
SB_DOUBLE("Line Playback Volume",
556
SB_DSP_LINE_DEV, SB_DSP_LINE_DEV, 5, 1, 7),
557
SB_SINGLE("Mic Playback Volume", SB_DSP_MIC_DEV, 1, 3),
558
{
559
.name = "Capture Source",
560
.type = SB_MIX_CAPTURE_PRO
561
},
562
SB_SINGLE("Capture Filter", SB_DSP_CAPTURE_FILT, 5, 1),
563
SB_SINGLE("Capture Low-Pass Filter", SB_DSP_CAPTURE_FILT, 3, 1)
564
};
565
566
static unsigned char snd_sbpro_init_values[][2] = {
567
{ SB_DSP_MASTER_DEV, 0 },
568
{ SB_DSP_PCM_DEV, 0 },
569
{ SB_DSP_FM_DEV, 0 },
570
};
571
572
/*
573
* SB16 specific mixer elements
574
*/
575
static struct sbmix_elem snd_sb16_controls[] = {
576
SB_DOUBLE("Master Playback Volume",
577
SB_DSP4_MASTER_DEV, (SB_DSP4_MASTER_DEV + 1), 3, 3, 31),
578
SB_DOUBLE("PCM Playback Volume",
579
SB_DSP4_PCM_DEV, (SB_DSP4_PCM_DEV + 1), 3, 3, 31),
580
SB16_INPUT_SW("Synth Capture Route",
581
SB_DSP4_INPUT_LEFT, SB_DSP4_INPUT_RIGHT, 6, 5),
582
SB_DOUBLE("Synth Playback Volume",
583
SB_DSP4_SYNTH_DEV, (SB_DSP4_SYNTH_DEV + 1), 3, 3, 31),
584
SB16_INPUT_SW("CD Capture Route",
585
SB_DSP4_INPUT_LEFT, SB_DSP4_INPUT_RIGHT, 2, 1),
586
SB_DOUBLE("CD Playback Switch",
587
SB_DSP4_OUTPUT_SW, SB_DSP4_OUTPUT_SW, 2, 1, 1),
588
SB_DOUBLE("CD Playback Volume",
589
SB_DSP4_CD_DEV, (SB_DSP4_CD_DEV + 1), 3, 3, 31),
590
SB16_INPUT_SW("Mic Capture Route",
591
SB_DSP4_INPUT_LEFT, SB_DSP4_INPUT_RIGHT, 0, 0),
592
SB_SINGLE("Mic Playback Switch", SB_DSP4_OUTPUT_SW, 0, 1),
593
SB_SINGLE("Mic Playback Volume", SB_DSP4_MIC_DEV, 3, 31),
594
SB_SINGLE("Beep Volume", SB_DSP4_SPEAKER_DEV, 6, 3),
595
SB_DOUBLE("Capture Volume",
596
SB_DSP4_IGAIN_DEV, (SB_DSP4_IGAIN_DEV + 1), 6, 6, 3),
597
SB_DOUBLE("Playback Volume",
598
SB_DSP4_OGAIN_DEV, (SB_DSP4_OGAIN_DEV + 1), 6, 6, 3),
599
SB16_INPUT_SW("Line Capture Route",
600
SB_DSP4_INPUT_LEFT, SB_DSP4_INPUT_RIGHT, 4, 3),
601
SB_DOUBLE("Line Playback Switch",
602
SB_DSP4_OUTPUT_SW, SB_DSP4_OUTPUT_SW, 4, 3, 1),
603
SB_DOUBLE("Line Playback Volume",
604
SB_DSP4_LINE_DEV, (SB_DSP4_LINE_DEV + 1), 3, 3, 31),
605
SB_SINGLE("Mic Auto Gain", SB_DSP4_MIC_AGC, 0, 1),
606
SB_SINGLE("3D Enhancement Switch", SB_DSP4_3DSE, 0, 1),
607
SB_DOUBLE("Tone Control - Bass",
608
SB_DSP4_BASS_DEV, (SB_DSP4_BASS_DEV + 1), 4, 4, 15),
609
SB_DOUBLE("Tone Control - Treble",
610
SB_DSP4_TREBLE_DEV, (SB_DSP4_TREBLE_DEV + 1), 4, 4, 15)
611
};
612
613
static unsigned char snd_sb16_init_values[][2] = {
614
{ SB_DSP4_MASTER_DEV + 0, 0 },
615
{ SB_DSP4_MASTER_DEV + 1, 0 },
616
{ SB_DSP4_PCM_DEV + 0, 0 },
617
{ SB_DSP4_PCM_DEV + 1, 0 },
618
{ SB_DSP4_SYNTH_DEV + 0, 0 },
619
{ SB_DSP4_SYNTH_DEV + 1, 0 },
620
{ SB_DSP4_INPUT_LEFT, 0 },
621
{ SB_DSP4_INPUT_RIGHT, 0 },
622
{ SB_DSP4_OUTPUT_SW, 0 },
623
{ SB_DSP4_SPEAKER_DEV, 0 },
624
};
625
626
/*
627
* DT019x specific mixer elements
628
*/
629
static struct sbmix_elem snd_dt019x_controls[] = {
630
/* ALS4000 below has some parts which we might be lacking,
631
* e.g. snd_als4000_ctl_mono_playback_switch - check it! */
632
SB_DOUBLE("Master Playback Volume",
633
SB_DT019X_MASTER_DEV, SB_DT019X_MASTER_DEV, 4, 0, 15),
634
SB_DOUBLE("PCM Playback Switch",
635
SB_DT019X_OUTPUT_SW2, SB_DT019X_OUTPUT_SW2, 2, 1, 1),
636
SB_DOUBLE("PCM Playback Volume",
637
SB_DT019X_PCM_DEV, SB_DT019X_PCM_DEV, 4, 0, 15),
638
SB_DOUBLE("Synth Playback Switch",
639
SB_DT019X_OUTPUT_SW2, SB_DT019X_OUTPUT_SW2, 4, 3, 1),
640
SB_DOUBLE("Synth Playback Volume",
641
SB_DT019X_SYNTH_DEV, SB_DT019X_SYNTH_DEV, 4, 0, 15),
642
SB_DOUBLE("CD Playback Switch",
643
SB_DSP4_OUTPUT_SW, SB_DSP4_OUTPUT_SW, 2, 1, 1),
644
SB_DOUBLE("CD Playback Volume",
645
SB_DT019X_CD_DEV, SB_DT019X_CD_DEV, 4, 0, 15),
646
SB_SINGLE("Mic Playback Switch", SB_DSP4_OUTPUT_SW, 0, 1),
647
SB_SINGLE("Mic Playback Volume", SB_DT019X_MIC_DEV, 4, 7),
648
SB_SINGLE("Beep Volume", SB_DT019X_SPKR_DEV, 0, 7),
649
SB_DOUBLE("Line Playback Switch",
650
SB_DSP4_OUTPUT_SW, SB_DSP4_OUTPUT_SW, 4, 3, 1),
651
SB_DOUBLE("Line Playback Volume",
652
SB_DT019X_LINE_DEV, SB_DT019X_LINE_DEV, 4, 0, 15),
653
{
654
.name = "Capture Source",
655
.type = SB_MIX_CAPTURE_DT019X
656
}
657
};
658
659
static unsigned char snd_dt019x_init_values[][2] = {
660
{ SB_DT019X_MASTER_DEV, 0 },
661
{ SB_DT019X_PCM_DEV, 0 },
662
{ SB_DT019X_SYNTH_DEV, 0 },
663
{ SB_DT019X_CD_DEV, 0 },
664
{ SB_DT019X_MIC_DEV, 0 }, /* Includes PC-speaker in high nibble */
665
{ SB_DT019X_LINE_DEV, 0 },
666
{ SB_DSP4_OUTPUT_SW, 0 },
667
{ SB_DT019X_OUTPUT_SW2, 0 },
668
{ SB_DT019X_CAPTURE_SW, 0x06 },
669
};
670
671
/*
672
* ALS4000 specific mixer elements
673
*/
674
static struct sbmix_elem snd_als4000_controls[] = {
675
SB_DOUBLE("PCM Playback Switch",
676
SB_DT019X_OUTPUT_SW2, SB_DT019X_OUTPUT_SW2, 2, 1, 1),
677
SB_DOUBLE("Synth Playback Switch",
678
SB_DT019X_OUTPUT_SW2, SB_DT019X_OUTPUT_SW2, 4, 3, 1),
679
SB_SINGLE("Mic Boost (+20dB)", SB_ALS4000_MIC_IN_GAIN, 0, 0x03),
680
SB_SINGLE("Master Mono Playback Switch", SB_ALS4000_MONO_IO_CTRL, 5, 1),
681
{
682
.name = "Master Mono Capture Route",
683
.type = SB_MIX_MONO_CAPTURE_ALS4K
684
},
685
SB_SINGLE("Mono Playback Switch", SB_DT019X_OUTPUT_SW2, 0, 1),
686
SB_SINGLE("Analog Loopback Switch", SB_ALS4000_MIC_IN_GAIN, 7, 0x01),
687
SB_SINGLE("3D Control - Switch", SB_ALS4000_3D_SND_FX, 6, 0x01),
688
SB_SINGLE("Digital Loopback Switch",
689
SB_ALS4000_CR3_CONFIGURATION, 7, 0x01),
690
/* FIXME: functionality of 3D controls might be swapped, I didn't find
691
* a description of how to identify what is supposed to be what */
692
SB_SINGLE("3D Control - Level", SB_ALS4000_3D_SND_FX, 0, 0x07),
693
/* FIXME: maybe there's actually some standard 3D ctrl name for it?? */
694
SB_SINGLE("3D Control - Freq", SB_ALS4000_3D_SND_FX, 4, 0x03),
695
/* FIXME: ALS4000a.pdf mentions BBD (Bucket Brigade Device) time delay,
696
* but what ALSA 3D attribute is that actually? "Center", "Depth",
697
* "Wide" or "Space" or even "Level"? Assuming "Wide" for now... */
698
SB_SINGLE("3D Control - Wide", SB_ALS4000_3D_TIME_DELAY, 0, 0x0f),
699
SB_SINGLE("3D PowerOff Switch", SB_ALS4000_3D_TIME_DELAY, 4, 0x01),
700
SB_SINGLE("Master Playback 8kHz / 20kHz LPF Switch",
701
SB_ALS4000_FMDAC, 5, 0x01),
702
#ifdef NOT_AVAILABLE
703
SB_SINGLE("FMDAC Switch (Option ?)", SB_ALS4000_FMDAC, 0, 0x01),
704
SB_SINGLE("QSound Mode", SB_ALS4000_QSOUND, 1, 0x1f),
705
#endif
706
};
707
708
static unsigned char snd_als4000_init_values[][2] = {
709
{ SB_DSP4_MASTER_DEV + 0, 0 },
710
{ SB_DSP4_MASTER_DEV + 1, 0 },
711
{ SB_DSP4_PCM_DEV + 0, 0 },
712
{ SB_DSP4_PCM_DEV + 1, 0 },
713
{ SB_DSP4_SYNTH_DEV + 0, 0 },
714
{ SB_DSP4_SYNTH_DEV + 1, 0 },
715
{ SB_DSP4_SPEAKER_DEV, 0 },
716
{ SB_DSP4_OUTPUT_SW, 0 },
717
{ SB_DSP4_INPUT_LEFT, 0 },
718
{ SB_DSP4_INPUT_RIGHT, 0 },
719
{ SB_DT019X_OUTPUT_SW2, 0 },
720
{ SB_ALS4000_MIC_IN_GAIN, 0 },
721
};
722
723
/*
724
*/
725
static int snd_sbmixer_init(struct snd_sb *chip,
726
struct sbmix_elem *controls,
727
int controls_count,
728
unsigned char map[][2],
729
int map_count,
730
char *name)
731
{
732
unsigned long flags;
733
struct snd_card *card = chip->card;
734
int idx, err;
735
736
/* mixer reset */
737
spin_lock_irqsave(&chip->mixer_lock, flags);
738
snd_sbmixer_write(chip, 0x00, 0x00);
739
spin_unlock_irqrestore(&chip->mixer_lock, flags);
740
741
/* mute and zero volume channels */
742
for (idx = 0; idx < map_count; idx++) {
743
spin_lock_irqsave(&chip->mixer_lock, flags);
744
snd_sbmixer_write(chip, map[idx][0], map[idx][1]);
745
spin_unlock_irqrestore(&chip->mixer_lock, flags);
746
}
747
748
for (idx = 0; idx < controls_count; idx++) {
749
err = snd_sbmixer_add_ctl_elem(chip, &controls[idx]);
750
if (err < 0)
751
return err;
752
}
753
snd_component_add(card, name);
754
strcpy(card->mixername, name);
755
return 0;
756
}
757
758
int snd_sbmixer_new(struct snd_sb *chip)
759
{
760
struct snd_card *card;
761
int err;
762
763
if (snd_BUG_ON(!chip || !chip->card))
764
return -EINVAL;
765
766
card = chip->card;
767
768
switch (chip->hardware) {
769
case SB_HW_10:
770
return 0; /* no mixer chip on SB1.x */
771
case SB_HW_20:
772
case SB_HW_201:
773
if ((err = snd_sbmixer_init(chip,
774
snd_sb20_controls,
775
ARRAY_SIZE(snd_sb20_controls),
776
snd_sb20_init_values,
777
ARRAY_SIZE(snd_sb20_init_values),
778
"CTL1335")) < 0)
779
return err;
780
break;
781
case SB_HW_PRO:
782
case SB_HW_JAZZ16:
783
if ((err = snd_sbmixer_init(chip,
784
snd_sbpro_controls,
785
ARRAY_SIZE(snd_sbpro_controls),
786
snd_sbpro_init_values,
787
ARRAY_SIZE(snd_sbpro_init_values),
788
"CTL1345")) < 0)
789
return err;
790
break;
791
case SB_HW_16:
792
case SB_HW_ALS100:
793
case SB_HW_CS5530:
794
if ((err = snd_sbmixer_init(chip,
795
snd_sb16_controls,
796
ARRAY_SIZE(snd_sb16_controls),
797
snd_sb16_init_values,
798
ARRAY_SIZE(snd_sb16_init_values),
799
"CTL1745")) < 0)
800
return err;
801
break;
802
case SB_HW_ALS4000:
803
/* use only the first 16 controls from SB16 */
804
err = snd_sbmixer_init(chip,
805
snd_sb16_controls,
806
16,
807
snd_sb16_init_values,
808
ARRAY_SIZE(snd_sb16_init_values),
809
"ALS4000");
810
if (err < 0)
811
return err;
812
if ((err = snd_sbmixer_init(chip,
813
snd_als4000_controls,
814
ARRAY_SIZE(snd_als4000_controls),
815
snd_als4000_init_values,
816
ARRAY_SIZE(snd_als4000_init_values),
817
"ALS4000")) < 0)
818
return err;
819
break;
820
case SB_HW_DT019X:
821
if ((err = snd_sbmixer_init(chip,
822
snd_dt019x_controls,
823
ARRAY_SIZE(snd_dt019x_controls),
824
snd_dt019x_init_values,
825
ARRAY_SIZE(snd_dt019x_init_values),
826
"DT019X")) < 0)
827
break;
828
default:
829
strcpy(card->mixername, "???");
830
}
831
return 0;
832
}
833
834
#ifdef CONFIG_PM
835
static unsigned char sb20_saved_regs[] = {
836
SB_DSP20_MASTER_DEV,
837
SB_DSP20_PCM_DEV,
838
SB_DSP20_FM_DEV,
839
SB_DSP20_CD_DEV,
840
};
841
842
static unsigned char sbpro_saved_regs[] = {
843
SB_DSP_MASTER_DEV,
844
SB_DSP_PCM_DEV,
845
SB_DSP_PLAYBACK_FILT,
846
SB_DSP_FM_DEV,
847
SB_DSP_CD_DEV,
848
SB_DSP_LINE_DEV,
849
SB_DSP_MIC_DEV,
850
SB_DSP_CAPTURE_SOURCE,
851
SB_DSP_CAPTURE_FILT,
852
};
853
854
static unsigned char sb16_saved_regs[] = {
855
SB_DSP4_MASTER_DEV, SB_DSP4_MASTER_DEV + 1,
856
SB_DSP4_3DSE,
857
SB_DSP4_BASS_DEV, SB_DSP4_BASS_DEV + 1,
858
SB_DSP4_TREBLE_DEV, SB_DSP4_TREBLE_DEV + 1,
859
SB_DSP4_PCM_DEV, SB_DSP4_PCM_DEV + 1,
860
SB_DSP4_INPUT_LEFT, SB_DSP4_INPUT_RIGHT,
861
SB_DSP4_SYNTH_DEV, SB_DSP4_SYNTH_DEV + 1,
862
SB_DSP4_OUTPUT_SW,
863
SB_DSP4_CD_DEV, SB_DSP4_CD_DEV + 1,
864
SB_DSP4_LINE_DEV, SB_DSP4_LINE_DEV + 1,
865
SB_DSP4_MIC_DEV,
866
SB_DSP4_SPEAKER_DEV,
867
SB_DSP4_IGAIN_DEV, SB_DSP4_IGAIN_DEV + 1,
868
SB_DSP4_OGAIN_DEV, SB_DSP4_OGAIN_DEV + 1,
869
SB_DSP4_MIC_AGC
870
};
871
872
static unsigned char dt019x_saved_regs[] = {
873
SB_DT019X_MASTER_DEV,
874
SB_DT019X_PCM_DEV,
875
SB_DT019X_SYNTH_DEV,
876
SB_DT019X_CD_DEV,
877
SB_DT019X_MIC_DEV,
878
SB_DT019X_SPKR_DEV,
879
SB_DT019X_LINE_DEV,
880
SB_DSP4_OUTPUT_SW,
881
SB_DT019X_OUTPUT_SW2,
882
SB_DT019X_CAPTURE_SW,
883
};
884
885
static unsigned char als4000_saved_regs[] = {
886
/* please verify in dsheet whether regs to be added
887
are actually real H/W or just dummy */
888
SB_DSP4_MASTER_DEV, SB_DSP4_MASTER_DEV + 1,
889
SB_DSP4_OUTPUT_SW,
890
SB_DSP4_PCM_DEV, SB_DSP4_PCM_DEV + 1,
891
SB_DSP4_INPUT_LEFT, SB_DSP4_INPUT_RIGHT,
892
SB_DSP4_SYNTH_DEV, SB_DSP4_SYNTH_DEV + 1,
893
SB_DSP4_CD_DEV, SB_DSP4_CD_DEV + 1,
894
SB_DSP4_MIC_DEV,
895
SB_DSP4_SPEAKER_DEV,
896
SB_DSP4_IGAIN_DEV, SB_DSP4_IGAIN_DEV + 1,
897
SB_DSP4_OGAIN_DEV, SB_DSP4_OGAIN_DEV + 1,
898
SB_DT019X_OUTPUT_SW2,
899
SB_ALS4000_MONO_IO_CTRL,
900
SB_ALS4000_MIC_IN_GAIN,
901
SB_ALS4000_FMDAC,
902
SB_ALS4000_3D_SND_FX,
903
SB_ALS4000_3D_TIME_DELAY,
904
SB_ALS4000_CR3_CONFIGURATION,
905
};
906
907
static void save_mixer(struct snd_sb *chip, unsigned char *regs, int num_regs)
908
{
909
unsigned char *val = chip->saved_regs;
910
if (snd_BUG_ON(num_regs > ARRAY_SIZE(chip->saved_regs)))
911
return;
912
for (; num_regs; num_regs--)
913
*val++ = snd_sbmixer_read(chip, *regs++);
914
}
915
916
static void restore_mixer(struct snd_sb *chip, unsigned char *regs, int num_regs)
917
{
918
unsigned char *val = chip->saved_regs;
919
if (snd_BUG_ON(num_regs > ARRAY_SIZE(chip->saved_regs)))
920
return;
921
for (; num_regs; num_regs--)
922
snd_sbmixer_write(chip, *regs++, *val++);
923
}
924
925
void snd_sbmixer_suspend(struct snd_sb *chip)
926
{
927
switch (chip->hardware) {
928
case SB_HW_20:
929
case SB_HW_201:
930
save_mixer(chip, sb20_saved_regs, ARRAY_SIZE(sb20_saved_regs));
931
break;
932
case SB_HW_PRO:
933
case SB_HW_JAZZ16:
934
save_mixer(chip, sbpro_saved_regs, ARRAY_SIZE(sbpro_saved_regs));
935
break;
936
case SB_HW_16:
937
case SB_HW_ALS100:
938
case SB_HW_CS5530:
939
save_mixer(chip, sb16_saved_regs, ARRAY_SIZE(sb16_saved_regs));
940
break;
941
case SB_HW_ALS4000:
942
save_mixer(chip, als4000_saved_regs, ARRAY_SIZE(als4000_saved_regs));
943
break;
944
case SB_HW_DT019X:
945
save_mixer(chip, dt019x_saved_regs, ARRAY_SIZE(dt019x_saved_regs));
946
break;
947
default:
948
break;
949
}
950
}
951
952
void snd_sbmixer_resume(struct snd_sb *chip)
953
{
954
switch (chip->hardware) {
955
case SB_HW_20:
956
case SB_HW_201:
957
restore_mixer(chip, sb20_saved_regs, ARRAY_SIZE(sb20_saved_regs));
958
break;
959
case SB_HW_PRO:
960
case SB_HW_JAZZ16:
961
restore_mixer(chip, sbpro_saved_regs, ARRAY_SIZE(sbpro_saved_regs));
962
break;
963
case SB_HW_16:
964
case SB_HW_ALS100:
965
case SB_HW_CS5530:
966
restore_mixer(chip, sb16_saved_regs, ARRAY_SIZE(sb16_saved_regs));
967
break;
968
case SB_HW_ALS4000:
969
restore_mixer(chip, als4000_saved_regs, ARRAY_SIZE(als4000_saved_regs));
970
break;
971
case SB_HW_DT019X:
972
restore_mixer(chip, dt019x_saved_regs, ARRAY_SIZE(dt019x_saved_regs));
973
break;
974
default:
975
break;
976
}
977
}
978
#endif
979
980