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