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