Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
awilliam
GitHub Repository: awilliam/linux-vfio
Path: blob/master/sound/core/oss/mixer_oss.c
10817 views
1
/*
2
* OSS emulation layer for the mixer interface
3
* Copyright (c) by Jaroslav Kysela <[email protected]>
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 <linux/init.h>
23
#include <linux/slab.h>
24
#include <linux/time.h>
25
#include <linux/string.h>
26
#include <sound/core.h>
27
#include <sound/minors.h>
28
#include <sound/control.h>
29
#include <sound/info.h>
30
#include <sound/mixer_oss.h>
31
#include <linux/soundcard.h>
32
33
#define OSS_ALSAEMULVER _SIOR ('M', 249, int)
34
35
MODULE_AUTHOR("Jaroslav Kysela <[email protected]>");
36
MODULE_DESCRIPTION("Mixer OSS emulation for ALSA.");
37
MODULE_LICENSE("GPL");
38
MODULE_ALIAS_SNDRV_MINOR(SNDRV_MINOR_OSS_MIXER);
39
40
static int snd_mixer_oss_open(struct inode *inode, struct file *file)
41
{
42
struct snd_card *card;
43
struct snd_mixer_oss_file *fmixer;
44
int err;
45
46
err = nonseekable_open(inode, file);
47
if (err < 0)
48
return err;
49
50
card = snd_lookup_oss_minor_data(iminor(inode),
51
SNDRV_OSS_DEVICE_TYPE_MIXER);
52
if (card == NULL)
53
return -ENODEV;
54
if (card->mixer_oss == NULL)
55
return -ENODEV;
56
err = snd_card_file_add(card, file);
57
if (err < 0)
58
return err;
59
fmixer = kzalloc(sizeof(*fmixer), GFP_KERNEL);
60
if (fmixer == NULL) {
61
snd_card_file_remove(card, file);
62
return -ENOMEM;
63
}
64
fmixer->card = card;
65
fmixer->mixer = card->mixer_oss;
66
file->private_data = fmixer;
67
if (!try_module_get(card->module)) {
68
kfree(fmixer);
69
snd_card_file_remove(card, file);
70
return -EFAULT;
71
}
72
return 0;
73
}
74
75
static int snd_mixer_oss_release(struct inode *inode, struct file *file)
76
{
77
struct snd_mixer_oss_file *fmixer;
78
79
if (file->private_data) {
80
fmixer = file->private_data;
81
module_put(fmixer->card->module);
82
snd_card_file_remove(fmixer->card, file);
83
kfree(fmixer);
84
}
85
return 0;
86
}
87
88
static int snd_mixer_oss_info(struct snd_mixer_oss_file *fmixer,
89
mixer_info __user *_info)
90
{
91
struct snd_card *card = fmixer->card;
92
struct snd_mixer_oss *mixer = fmixer->mixer;
93
struct mixer_info info;
94
95
memset(&info, 0, sizeof(info));
96
strlcpy(info.id, mixer && mixer->id[0] ? mixer->id : card->driver, sizeof(info.id));
97
strlcpy(info.name, mixer && mixer->name[0] ? mixer->name : card->mixername, sizeof(info.name));
98
info.modify_counter = card->mixer_oss_change_count;
99
if (copy_to_user(_info, &info, sizeof(info)))
100
return -EFAULT;
101
return 0;
102
}
103
104
static int snd_mixer_oss_info_obsolete(struct snd_mixer_oss_file *fmixer,
105
_old_mixer_info __user *_info)
106
{
107
struct snd_card *card = fmixer->card;
108
struct snd_mixer_oss *mixer = fmixer->mixer;
109
_old_mixer_info info;
110
111
memset(&info, 0, sizeof(info));
112
strlcpy(info.id, mixer && mixer->id[0] ? mixer->id : card->driver, sizeof(info.id));
113
strlcpy(info.name, mixer && mixer->name[0] ? mixer->name : card->mixername, sizeof(info.name));
114
if (copy_to_user(_info, &info, sizeof(info)))
115
return -EFAULT;
116
return 0;
117
}
118
119
static int snd_mixer_oss_caps(struct snd_mixer_oss_file *fmixer)
120
{
121
struct snd_mixer_oss *mixer = fmixer->mixer;
122
int result = 0;
123
124
if (mixer == NULL)
125
return -EIO;
126
if (mixer->get_recsrc && mixer->put_recsrc)
127
result |= SOUND_CAP_EXCL_INPUT;
128
return result;
129
}
130
131
static int snd_mixer_oss_devmask(struct snd_mixer_oss_file *fmixer)
132
{
133
struct snd_mixer_oss *mixer = fmixer->mixer;
134
struct snd_mixer_oss_slot *pslot;
135
int result = 0, chn;
136
137
if (mixer == NULL)
138
return -EIO;
139
for (chn = 0; chn < 31; chn++) {
140
pslot = &mixer->slots[chn];
141
if (pslot->put_volume || pslot->put_recsrc)
142
result |= 1 << chn;
143
}
144
return result;
145
}
146
147
static int snd_mixer_oss_stereodevs(struct snd_mixer_oss_file *fmixer)
148
{
149
struct snd_mixer_oss *mixer = fmixer->mixer;
150
struct snd_mixer_oss_slot *pslot;
151
int result = 0, chn;
152
153
if (mixer == NULL)
154
return -EIO;
155
for (chn = 0; chn < 31; chn++) {
156
pslot = &mixer->slots[chn];
157
if (pslot->put_volume && pslot->stereo)
158
result |= 1 << chn;
159
}
160
return result;
161
}
162
163
static int snd_mixer_oss_recmask(struct snd_mixer_oss_file *fmixer)
164
{
165
struct snd_mixer_oss *mixer = fmixer->mixer;
166
int result = 0;
167
168
if (mixer == NULL)
169
return -EIO;
170
if (mixer->put_recsrc && mixer->get_recsrc) { /* exclusive */
171
result = mixer->mask_recsrc;
172
} else {
173
struct snd_mixer_oss_slot *pslot;
174
int chn;
175
for (chn = 0; chn < 31; chn++) {
176
pslot = &mixer->slots[chn];
177
if (pslot->put_recsrc)
178
result |= 1 << chn;
179
}
180
}
181
return result;
182
}
183
184
static int snd_mixer_oss_get_recsrc(struct snd_mixer_oss_file *fmixer)
185
{
186
struct snd_mixer_oss *mixer = fmixer->mixer;
187
int result = 0;
188
189
if (mixer == NULL)
190
return -EIO;
191
if (mixer->put_recsrc && mixer->get_recsrc) { /* exclusive */
192
int err;
193
unsigned int index;
194
if ((err = mixer->get_recsrc(fmixer, &index)) < 0)
195
return err;
196
result = 1 << index;
197
} else {
198
struct snd_mixer_oss_slot *pslot;
199
int chn;
200
for (chn = 0; chn < 31; chn++) {
201
pslot = &mixer->slots[chn];
202
if (pslot->get_recsrc) {
203
int active = 0;
204
pslot->get_recsrc(fmixer, pslot, &active);
205
if (active)
206
result |= 1 << chn;
207
}
208
}
209
}
210
return mixer->oss_recsrc = result;
211
}
212
213
static int snd_mixer_oss_set_recsrc(struct snd_mixer_oss_file *fmixer, int recsrc)
214
{
215
struct snd_mixer_oss *mixer = fmixer->mixer;
216
struct snd_mixer_oss_slot *pslot;
217
int chn, active;
218
unsigned int index;
219
int result = 0;
220
221
if (mixer == NULL)
222
return -EIO;
223
if (mixer->get_recsrc && mixer->put_recsrc) { /* exclusive input */
224
if (recsrc & ~mixer->oss_recsrc)
225
recsrc &= ~mixer->oss_recsrc;
226
mixer->put_recsrc(fmixer, ffz(~recsrc));
227
mixer->get_recsrc(fmixer, &index);
228
result = 1 << index;
229
}
230
for (chn = 0; chn < 31; chn++) {
231
pslot = &mixer->slots[chn];
232
if (pslot->put_recsrc) {
233
active = (recsrc & (1 << chn)) ? 1 : 0;
234
pslot->put_recsrc(fmixer, pslot, active);
235
}
236
}
237
if (! result) {
238
for (chn = 0; chn < 31; chn++) {
239
pslot = &mixer->slots[chn];
240
if (pslot->get_recsrc) {
241
active = 0;
242
pslot->get_recsrc(fmixer, pslot, &active);
243
if (active)
244
result |= 1 << chn;
245
}
246
}
247
}
248
return result;
249
}
250
251
static int snd_mixer_oss_get_volume(struct snd_mixer_oss_file *fmixer, int slot)
252
{
253
struct snd_mixer_oss *mixer = fmixer->mixer;
254
struct snd_mixer_oss_slot *pslot;
255
int result = 0, left, right;
256
257
if (mixer == NULL || slot > 30)
258
return -EIO;
259
pslot = &mixer->slots[slot];
260
left = pslot->volume[0];
261
right = pslot->volume[1];
262
if (pslot->get_volume)
263
result = pslot->get_volume(fmixer, pslot, &left, &right);
264
if (!pslot->stereo)
265
right = left;
266
if (snd_BUG_ON(left < 0 || left > 100))
267
return -EIO;
268
if (snd_BUG_ON(right < 0 || right > 100))
269
return -EIO;
270
if (result >= 0) {
271
pslot->volume[0] = left;
272
pslot->volume[1] = right;
273
result = (left & 0xff) | ((right & 0xff) << 8);
274
}
275
return result;
276
}
277
278
static int snd_mixer_oss_set_volume(struct snd_mixer_oss_file *fmixer,
279
int slot, int volume)
280
{
281
struct snd_mixer_oss *mixer = fmixer->mixer;
282
struct snd_mixer_oss_slot *pslot;
283
int result = 0, left = volume & 0xff, right = (volume >> 8) & 0xff;
284
285
if (mixer == NULL || slot > 30)
286
return -EIO;
287
pslot = &mixer->slots[slot];
288
if (left > 100)
289
left = 100;
290
if (right > 100)
291
right = 100;
292
if (!pslot->stereo)
293
right = left;
294
if (pslot->put_volume)
295
result = pslot->put_volume(fmixer, pslot, left, right);
296
if (result < 0)
297
return result;
298
pslot->volume[0] = left;
299
pslot->volume[1] = right;
300
return (left & 0xff) | ((right & 0xff) << 8);
301
}
302
303
static int snd_mixer_oss_ioctl1(struct snd_mixer_oss_file *fmixer, unsigned int cmd, unsigned long arg)
304
{
305
void __user *argp = (void __user *)arg;
306
int __user *p = argp;
307
int tmp;
308
309
if (snd_BUG_ON(!fmixer))
310
return -ENXIO;
311
if (((cmd >> 8) & 0xff) == 'M') {
312
switch (cmd) {
313
case SOUND_MIXER_INFO:
314
return snd_mixer_oss_info(fmixer, argp);
315
case SOUND_OLD_MIXER_INFO:
316
return snd_mixer_oss_info_obsolete(fmixer, argp);
317
case SOUND_MIXER_WRITE_RECSRC:
318
if (get_user(tmp, p))
319
return -EFAULT;
320
tmp = snd_mixer_oss_set_recsrc(fmixer, tmp);
321
if (tmp < 0)
322
return tmp;
323
return put_user(tmp, p);
324
case OSS_GETVERSION:
325
return put_user(SNDRV_OSS_VERSION, p);
326
case OSS_ALSAEMULVER:
327
return put_user(1, p);
328
case SOUND_MIXER_READ_DEVMASK:
329
tmp = snd_mixer_oss_devmask(fmixer);
330
if (tmp < 0)
331
return tmp;
332
return put_user(tmp, p);
333
case SOUND_MIXER_READ_STEREODEVS:
334
tmp = snd_mixer_oss_stereodevs(fmixer);
335
if (tmp < 0)
336
return tmp;
337
return put_user(tmp, p);
338
case SOUND_MIXER_READ_RECMASK:
339
tmp = snd_mixer_oss_recmask(fmixer);
340
if (tmp < 0)
341
return tmp;
342
return put_user(tmp, p);
343
case SOUND_MIXER_READ_CAPS:
344
tmp = snd_mixer_oss_caps(fmixer);
345
if (tmp < 0)
346
return tmp;
347
return put_user(tmp, p);
348
case SOUND_MIXER_READ_RECSRC:
349
tmp = snd_mixer_oss_get_recsrc(fmixer);
350
if (tmp < 0)
351
return tmp;
352
return put_user(tmp, p);
353
}
354
}
355
if (cmd & SIOC_IN) {
356
if (get_user(tmp, p))
357
return -EFAULT;
358
tmp = snd_mixer_oss_set_volume(fmixer, cmd & 0xff, tmp);
359
if (tmp < 0)
360
return tmp;
361
return put_user(tmp, p);
362
} else if (cmd & SIOC_OUT) {
363
tmp = snd_mixer_oss_get_volume(fmixer, cmd & 0xff);
364
if (tmp < 0)
365
return tmp;
366
return put_user(tmp, p);
367
}
368
return -ENXIO;
369
}
370
371
static long snd_mixer_oss_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
372
{
373
return snd_mixer_oss_ioctl1(file->private_data, cmd, arg);
374
}
375
376
int snd_mixer_oss_ioctl_card(struct snd_card *card, unsigned int cmd, unsigned long arg)
377
{
378
struct snd_mixer_oss_file fmixer;
379
380
if (snd_BUG_ON(!card))
381
return -ENXIO;
382
if (card->mixer_oss == NULL)
383
return -ENXIO;
384
memset(&fmixer, 0, sizeof(fmixer));
385
fmixer.card = card;
386
fmixer.mixer = card->mixer_oss;
387
return snd_mixer_oss_ioctl1(&fmixer, cmd, arg);
388
}
389
390
#ifdef CONFIG_COMPAT
391
/* all compatible */
392
#define snd_mixer_oss_ioctl_compat snd_mixer_oss_ioctl
393
#else
394
#define snd_mixer_oss_ioctl_compat NULL
395
#endif
396
397
/*
398
* REGISTRATION PART
399
*/
400
401
static const struct file_operations snd_mixer_oss_f_ops =
402
{
403
.owner = THIS_MODULE,
404
.open = snd_mixer_oss_open,
405
.release = snd_mixer_oss_release,
406
.llseek = no_llseek,
407
.unlocked_ioctl = snd_mixer_oss_ioctl,
408
.compat_ioctl = snd_mixer_oss_ioctl_compat,
409
};
410
411
/*
412
* utilities
413
*/
414
415
static long snd_mixer_oss_conv(long val, long omin, long omax, long nmin, long nmax)
416
{
417
long orange = omax - omin, nrange = nmax - nmin;
418
419
if (orange == 0)
420
return 0;
421
return ((nrange * (val - omin)) + (orange / 2)) / orange + nmin;
422
}
423
424
/* convert from alsa native to oss values (0-100) */
425
static long snd_mixer_oss_conv1(long val, long min, long max, int *old)
426
{
427
if (val == snd_mixer_oss_conv(*old, 0, 100, min, max))
428
return *old;
429
return snd_mixer_oss_conv(val, min, max, 0, 100);
430
}
431
432
/* convert from oss to alsa native values */
433
static long snd_mixer_oss_conv2(long val, long min, long max)
434
{
435
return snd_mixer_oss_conv(val, 0, 100, min, max);
436
}
437
438
#if 0
439
static void snd_mixer_oss_recsrce_set(struct snd_card *card, int slot)
440
{
441
struct snd_mixer_oss *mixer = card->mixer_oss;
442
if (mixer)
443
mixer->mask_recsrc |= 1 << slot;
444
}
445
446
static int snd_mixer_oss_recsrce_get(struct snd_card *card, int slot)
447
{
448
struct snd_mixer_oss *mixer = card->mixer_oss;
449
if (mixer && (mixer->mask_recsrc & (1 << slot)))
450
return 1;
451
return 0;
452
}
453
#endif
454
455
#define SNDRV_MIXER_OSS_SIGNATURE 0x65999250
456
457
#define SNDRV_MIXER_OSS_ITEM_GLOBAL 0
458
#define SNDRV_MIXER_OSS_ITEM_GSWITCH 1
459
#define SNDRV_MIXER_OSS_ITEM_GROUTE 2
460
#define SNDRV_MIXER_OSS_ITEM_GVOLUME 3
461
#define SNDRV_MIXER_OSS_ITEM_PSWITCH 4
462
#define SNDRV_MIXER_OSS_ITEM_PROUTE 5
463
#define SNDRV_MIXER_OSS_ITEM_PVOLUME 6
464
#define SNDRV_MIXER_OSS_ITEM_CSWITCH 7
465
#define SNDRV_MIXER_OSS_ITEM_CROUTE 8
466
#define SNDRV_MIXER_OSS_ITEM_CVOLUME 9
467
#define SNDRV_MIXER_OSS_ITEM_CAPTURE 10
468
469
#define SNDRV_MIXER_OSS_ITEM_COUNT 11
470
471
#define SNDRV_MIXER_OSS_PRESENT_GLOBAL (1<<0)
472
#define SNDRV_MIXER_OSS_PRESENT_GSWITCH (1<<1)
473
#define SNDRV_MIXER_OSS_PRESENT_GROUTE (1<<2)
474
#define SNDRV_MIXER_OSS_PRESENT_GVOLUME (1<<3)
475
#define SNDRV_MIXER_OSS_PRESENT_PSWITCH (1<<4)
476
#define SNDRV_MIXER_OSS_PRESENT_PROUTE (1<<5)
477
#define SNDRV_MIXER_OSS_PRESENT_PVOLUME (1<<6)
478
#define SNDRV_MIXER_OSS_PRESENT_CSWITCH (1<<7)
479
#define SNDRV_MIXER_OSS_PRESENT_CROUTE (1<<8)
480
#define SNDRV_MIXER_OSS_PRESENT_CVOLUME (1<<9)
481
#define SNDRV_MIXER_OSS_PRESENT_CAPTURE (1<<10)
482
483
struct slot {
484
unsigned int signature;
485
unsigned int present;
486
unsigned int channels;
487
unsigned int numid[SNDRV_MIXER_OSS_ITEM_COUNT];
488
unsigned int capture_item;
489
struct snd_mixer_oss_assign_table *assigned;
490
unsigned int allocated: 1;
491
};
492
493
#define ID_UNKNOWN ((unsigned int)-1)
494
495
static struct snd_kcontrol *snd_mixer_oss_test_id(struct snd_mixer_oss *mixer, const char *name, int index)
496
{
497
struct snd_card *card = mixer->card;
498
struct snd_ctl_elem_id id;
499
500
memset(&id, 0, sizeof(id));
501
id.iface = SNDRV_CTL_ELEM_IFACE_MIXER;
502
strcpy(id.name, name);
503
id.index = index;
504
return snd_ctl_find_id(card, &id);
505
}
506
507
static void snd_mixer_oss_get_volume1_vol(struct snd_mixer_oss_file *fmixer,
508
struct snd_mixer_oss_slot *pslot,
509
unsigned int numid,
510
int *left, int *right)
511
{
512
struct snd_ctl_elem_info *uinfo;
513
struct snd_ctl_elem_value *uctl;
514
struct snd_kcontrol *kctl;
515
struct snd_card *card = fmixer->card;
516
517
if (numid == ID_UNKNOWN)
518
return;
519
down_read(&card->controls_rwsem);
520
if ((kctl = snd_ctl_find_numid(card, numid)) == NULL) {
521
up_read(&card->controls_rwsem);
522
return;
523
}
524
uinfo = kzalloc(sizeof(*uinfo), GFP_KERNEL);
525
uctl = kzalloc(sizeof(*uctl), GFP_KERNEL);
526
if (uinfo == NULL || uctl == NULL)
527
goto __unalloc;
528
if (kctl->info(kctl, uinfo))
529
goto __unalloc;
530
if (kctl->get(kctl, uctl))
531
goto __unalloc;
532
if (uinfo->type == SNDRV_CTL_ELEM_TYPE_BOOLEAN &&
533
uinfo->value.integer.min == 0 && uinfo->value.integer.max == 1)
534
goto __unalloc;
535
*left = snd_mixer_oss_conv1(uctl->value.integer.value[0], uinfo->value.integer.min, uinfo->value.integer.max, &pslot->volume[0]);
536
if (uinfo->count > 1)
537
*right = snd_mixer_oss_conv1(uctl->value.integer.value[1], uinfo->value.integer.min, uinfo->value.integer.max, &pslot->volume[1]);
538
__unalloc:
539
up_read(&card->controls_rwsem);
540
kfree(uctl);
541
kfree(uinfo);
542
}
543
544
static void snd_mixer_oss_get_volume1_sw(struct snd_mixer_oss_file *fmixer,
545
struct snd_mixer_oss_slot *pslot,
546
unsigned int numid,
547
int *left, int *right,
548
int route)
549
{
550
struct snd_ctl_elem_info *uinfo;
551
struct snd_ctl_elem_value *uctl;
552
struct snd_kcontrol *kctl;
553
struct snd_card *card = fmixer->card;
554
555
if (numid == ID_UNKNOWN)
556
return;
557
down_read(&card->controls_rwsem);
558
if ((kctl = snd_ctl_find_numid(card, numid)) == NULL) {
559
up_read(&card->controls_rwsem);
560
return;
561
}
562
uinfo = kzalloc(sizeof(*uinfo), GFP_KERNEL);
563
uctl = kzalloc(sizeof(*uctl), GFP_KERNEL);
564
if (uinfo == NULL || uctl == NULL)
565
goto __unalloc;
566
if (kctl->info(kctl, uinfo))
567
goto __unalloc;
568
if (kctl->get(kctl, uctl))
569
goto __unalloc;
570
if (!uctl->value.integer.value[0]) {
571
*left = 0;
572
if (uinfo->count == 1)
573
*right = 0;
574
}
575
if (uinfo->count > 1 && !uctl->value.integer.value[route ? 3 : 1])
576
*right = 0;
577
__unalloc:
578
up_read(&card->controls_rwsem);
579
kfree(uctl);
580
kfree(uinfo);
581
}
582
583
static int snd_mixer_oss_get_volume1(struct snd_mixer_oss_file *fmixer,
584
struct snd_mixer_oss_slot *pslot,
585
int *left, int *right)
586
{
587
struct slot *slot = pslot->private_data;
588
589
*left = *right = 100;
590
if (slot->present & SNDRV_MIXER_OSS_PRESENT_PVOLUME) {
591
snd_mixer_oss_get_volume1_vol(fmixer, pslot, slot->numid[SNDRV_MIXER_OSS_ITEM_PVOLUME], left, right);
592
} else if (slot->present & SNDRV_MIXER_OSS_PRESENT_GVOLUME) {
593
snd_mixer_oss_get_volume1_vol(fmixer, pslot, slot->numid[SNDRV_MIXER_OSS_ITEM_GVOLUME], left, right);
594
} else if (slot->present & SNDRV_MIXER_OSS_PRESENT_GLOBAL) {
595
snd_mixer_oss_get_volume1_vol(fmixer, pslot, slot->numid[SNDRV_MIXER_OSS_ITEM_GLOBAL], left, right);
596
}
597
if (slot->present & SNDRV_MIXER_OSS_PRESENT_PSWITCH) {
598
snd_mixer_oss_get_volume1_sw(fmixer, pslot, slot->numid[SNDRV_MIXER_OSS_ITEM_PSWITCH], left, right, 0);
599
} else if (slot->present & SNDRV_MIXER_OSS_PRESENT_GSWITCH) {
600
snd_mixer_oss_get_volume1_sw(fmixer, pslot, slot->numid[SNDRV_MIXER_OSS_ITEM_GSWITCH], left, right, 0);
601
} else if (slot->present & SNDRV_MIXER_OSS_PRESENT_PROUTE) {
602
snd_mixer_oss_get_volume1_sw(fmixer, pslot, slot->numid[SNDRV_MIXER_OSS_ITEM_PROUTE], left, right, 1);
603
} else if (slot->present & SNDRV_MIXER_OSS_PRESENT_GROUTE) {
604
snd_mixer_oss_get_volume1_sw(fmixer, pslot, slot->numid[SNDRV_MIXER_OSS_ITEM_GROUTE], left, right, 1);
605
}
606
return 0;
607
}
608
609
static void snd_mixer_oss_put_volume1_vol(struct snd_mixer_oss_file *fmixer,
610
struct snd_mixer_oss_slot *pslot,
611
unsigned int numid,
612
int left, int right)
613
{
614
struct snd_ctl_elem_info *uinfo;
615
struct snd_ctl_elem_value *uctl;
616
struct snd_kcontrol *kctl;
617
struct snd_card *card = fmixer->card;
618
int res;
619
620
if (numid == ID_UNKNOWN)
621
return;
622
down_read(&card->controls_rwsem);
623
if ((kctl = snd_ctl_find_numid(card, numid)) == NULL) {
624
up_read(&card->controls_rwsem);
625
return;
626
}
627
uinfo = kzalloc(sizeof(*uinfo), GFP_KERNEL);
628
uctl = kzalloc(sizeof(*uctl), GFP_KERNEL);
629
if (uinfo == NULL || uctl == NULL)
630
goto __unalloc;
631
if (kctl->info(kctl, uinfo))
632
goto __unalloc;
633
if (uinfo->type == SNDRV_CTL_ELEM_TYPE_BOOLEAN &&
634
uinfo->value.integer.min == 0 && uinfo->value.integer.max == 1)
635
goto __unalloc;
636
uctl->value.integer.value[0] = snd_mixer_oss_conv2(left, uinfo->value.integer.min, uinfo->value.integer.max);
637
if (uinfo->count > 1)
638
uctl->value.integer.value[1] = snd_mixer_oss_conv2(right, uinfo->value.integer.min, uinfo->value.integer.max);
639
if ((res = kctl->put(kctl, uctl)) < 0)
640
goto __unalloc;
641
if (res > 0)
642
snd_ctl_notify(card, SNDRV_CTL_EVENT_MASK_VALUE, &kctl->id);
643
__unalloc:
644
up_read(&card->controls_rwsem);
645
kfree(uctl);
646
kfree(uinfo);
647
}
648
649
static void snd_mixer_oss_put_volume1_sw(struct snd_mixer_oss_file *fmixer,
650
struct snd_mixer_oss_slot *pslot,
651
unsigned int numid,
652
int left, int right,
653
int route)
654
{
655
struct snd_ctl_elem_info *uinfo;
656
struct snd_ctl_elem_value *uctl;
657
struct snd_kcontrol *kctl;
658
struct snd_card *card = fmixer->card;
659
int res;
660
661
if (numid == ID_UNKNOWN)
662
return;
663
down_read(&card->controls_rwsem);
664
if ((kctl = snd_ctl_find_numid(card, numid)) == NULL) {
665
up_read(&card->controls_rwsem);
666
return;
667
}
668
uinfo = kzalloc(sizeof(*uinfo), GFP_KERNEL);
669
uctl = kzalloc(sizeof(*uctl), GFP_KERNEL);
670
if (uinfo == NULL || uctl == NULL)
671
goto __unalloc;
672
if (kctl->info(kctl, uinfo))
673
goto __unalloc;
674
if (uinfo->count > 1) {
675
uctl->value.integer.value[0] = left > 0 ? 1 : 0;
676
uctl->value.integer.value[route ? 3 : 1] = right > 0 ? 1 : 0;
677
if (route) {
678
uctl->value.integer.value[1] =
679
uctl->value.integer.value[2] = 0;
680
}
681
} else {
682
uctl->value.integer.value[0] = (left > 0 || right > 0) ? 1 : 0;
683
}
684
if ((res = kctl->put(kctl, uctl)) < 0)
685
goto __unalloc;
686
if (res > 0)
687
snd_ctl_notify(card, SNDRV_CTL_EVENT_MASK_VALUE, &kctl->id);
688
__unalloc:
689
up_read(&card->controls_rwsem);
690
kfree(uctl);
691
kfree(uinfo);
692
}
693
694
static int snd_mixer_oss_put_volume1(struct snd_mixer_oss_file *fmixer,
695
struct snd_mixer_oss_slot *pslot,
696
int left, int right)
697
{
698
struct slot *slot = pslot->private_data;
699
700
if (slot->present & SNDRV_MIXER_OSS_PRESENT_PVOLUME) {
701
snd_mixer_oss_put_volume1_vol(fmixer, pslot, slot->numid[SNDRV_MIXER_OSS_ITEM_PVOLUME], left, right);
702
if (slot->present & SNDRV_MIXER_OSS_PRESENT_CVOLUME)
703
snd_mixer_oss_put_volume1_vol(fmixer, pslot, slot->numid[SNDRV_MIXER_OSS_ITEM_CVOLUME], left, right);
704
} else if (slot->present & SNDRV_MIXER_OSS_PRESENT_CVOLUME) {
705
snd_mixer_oss_put_volume1_vol(fmixer, pslot,
706
slot->numid[SNDRV_MIXER_OSS_ITEM_CVOLUME], left, right);
707
} else if (slot->present & SNDRV_MIXER_OSS_PRESENT_GVOLUME) {
708
snd_mixer_oss_put_volume1_vol(fmixer, pslot, slot->numid[SNDRV_MIXER_OSS_ITEM_GVOLUME], left, right);
709
} else if (slot->present & SNDRV_MIXER_OSS_PRESENT_GLOBAL) {
710
snd_mixer_oss_put_volume1_vol(fmixer, pslot, slot->numid[SNDRV_MIXER_OSS_ITEM_GLOBAL], left, right);
711
}
712
if (left || right) {
713
if (slot->present & SNDRV_MIXER_OSS_PRESENT_PSWITCH)
714
snd_mixer_oss_put_volume1_sw(fmixer, pslot, slot->numid[SNDRV_MIXER_OSS_ITEM_PSWITCH], left, right, 0);
715
if (slot->present & SNDRV_MIXER_OSS_PRESENT_CSWITCH)
716
snd_mixer_oss_put_volume1_sw(fmixer, pslot, slot->numid[SNDRV_MIXER_OSS_ITEM_CSWITCH], left, right, 0);
717
if (slot->present & SNDRV_MIXER_OSS_PRESENT_GSWITCH)
718
snd_mixer_oss_put_volume1_sw(fmixer, pslot, slot->numid[SNDRV_MIXER_OSS_ITEM_GSWITCH], left, right, 0);
719
if (slot->present & SNDRV_MIXER_OSS_PRESENT_PROUTE)
720
snd_mixer_oss_put_volume1_sw(fmixer, pslot, slot->numid[SNDRV_MIXER_OSS_ITEM_PROUTE], left, right, 1);
721
if (slot->present & SNDRV_MIXER_OSS_PRESENT_CROUTE)
722
snd_mixer_oss_put_volume1_sw(fmixer, pslot, slot->numid[SNDRV_MIXER_OSS_ITEM_CROUTE], left, right, 1);
723
if (slot->present & SNDRV_MIXER_OSS_PRESENT_GROUTE)
724
snd_mixer_oss_put_volume1_sw(fmixer, pslot, slot->numid[SNDRV_MIXER_OSS_ITEM_GROUTE], left, right, 1);
725
} else {
726
if (slot->present & SNDRV_MIXER_OSS_PRESENT_PSWITCH) {
727
snd_mixer_oss_put_volume1_sw(fmixer, pslot, slot->numid[SNDRV_MIXER_OSS_ITEM_PSWITCH], left, right, 0);
728
} else if (slot->present & SNDRV_MIXER_OSS_PRESENT_CSWITCH) {
729
snd_mixer_oss_put_volume1_sw(fmixer, pslot, slot->numid[SNDRV_MIXER_OSS_ITEM_CSWITCH], left, right, 0);
730
} else if (slot->present & SNDRV_MIXER_OSS_PRESENT_GSWITCH) {
731
snd_mixer_oss_put_volume1_sw(fmixer, pslot, slot->numid[SNDRV_MIXER_OSS_ITEM_GSWITCH], left, right, 0);
732
} else if (slot->present & SNDRV_MIXER_OSS_PRESENT_PROUTE) {
733
snd_mixer_oss_put_volume1_sw(fmixer, pslot, slot->numid[SNDRV_MIXER_OSS_ITEM_PROUTE], left, right, 1);
734
} else if (slot->present & SNDRV_MIXER_OSS_PRESENT_CROUTE) {
735
snd_mixer_oss_put_volume1_sw(fmixer, pslot, slot->numid[SNDRV_MIXER_OSS_ITEM_CROUTE], left, right, 1);
736
} else if (slot->present & SNDRV_MIXER_OSS_PRESENT_GROUTE) {
737
snd_mixer_oss_put_volume1_sw(fmixer, pslot, slot->numid[SNDRV_MIXER_OSS_ITEM_GROUTE], left, right, 1);
738
}
739
}
740
return 0;
741
}
742
743
static int snd_mixer_oss_get_recsrc1_sw(struct snd_mixer_oss_file *fmixer,
744
struct snd_mixer_oss_slot *pslot,
745
int *active)
746
{
747
struct slot *slot = pslot->private_data;
748
int left, right;
749
750
left = right = 1;
751
snd_mixer_oss_get_volume1_sw(fmixer, pslot, slot->numid[SNDRV_MIXER_OSS_ITEM_CSWITCH], &left, &right, 0);
752
*active = (left || right) ? 1 : 0;
753
return 0;
754
}
755
756
static int snd_mixer_oss_get_recsrc1_route(struct snd_mixer_oss_file *fmixer,
757
struct snd_mixer_oss_slot *pslot,
758
int *active)
759
{
760
struct slot *slot = pslot->private_data;
761
int left, right;
762
763
left = right = 1;
764
snd_mixer_oss_get_volume1_sw(fmixer, pslot, slot->numid[SNDRV_MIXER_OSS_ITEM_CROUTE], &left, &right, 1);
765
*active = (left || right) ? 1 : 0;
766
return 0;
767
}
768
769
static int snd_mixer_oss_put_recsrc1_sw(struct snd_mixer_oss_file *fmixer,
770
struct snd_mixer_oss_slot *pslot,
771
int active)
772
{
773
struct slot *slot = pslot->private_data;
774
775
snd_mixer_oss_put_volume1_sw(fmixer, pslot, slot->numid[SNDRV_MIXER_OSS_ITEM_CSWITCH], active, active, 0);
776
return 0;
777
}
778
779
static int snd_mixer_oss_put_recsrc1_route(struct snd_mixer_oss_file *fmixer,
780
struct snd_mixer_oss_slot *pslot,
781
int active)
782
{
783
struct slot *slot = pslot->private_data;
784
785
snd_mixer_oss_put_volume1_sw(fmixer, pslot, slot->numid[SNDRV_MIXER_OSS_ITEM_CROUTE], active, active, 1);
786
return 0;
787
}
788
789
static int snd_mixer_oss_get_recsrc2(struct snd_mixer_oss_file *fmixer, unsigned int *active_index)
790
{
791
struct snd_card *card = fmixer->card;
792
struct snd_mixer_oss *mixer = fmixer->mixer;
793
struct snd_kcontrol *kctl;
794
struct snd_mixer_oss_slot *pslot;
795
struct slot *slot;
796
struct snd_ctl_elem_info *uinfo;
797
struct snd_ctl_elem_value *uctl;
798
int err, idx;
799
800
uinfo = kzalloc(sizeof(*uinfo), GFP_KERNEL);
801
uctl = kzalloc(sizeof(*uctl), GFP_KERNEL);
802
if (uinfo == NULL || uctl == NULL) {
803
err = -ENOMEM;
804
goto __free_only;
805
}
806
down_read(&card->controls_rwsem);
807
kctl = snd_mixer_oss_test_id(mixer, "Capture Source", 0);
808
if (! kctl) {
809
err = -ENOENT;
810
goto __unlock;
811
}
812
if ((err = kctl->info(kctl, uinfo)) < 0)
813
goto __unlock;
814
if ((err = kctl->get(kctl, uctl)) < 0)
815
goto __unlock;
816
for (idx = 0; idx < 32; idx++) {
817
if (!(mixer->mask_recsrc & (1 << idx)))
818
continue;
819
pslot = &mixer->slots[idx];
820
slot = pslot->private_data;
821
if (slot->signature != SNDRV_MIXER_OSS_SIGNATURE)
822
continue;
823
if (!(slot->present & SNDRV_MIXER_OSS_PRESENT_CAPTURE))
824
continue;
825
if (slot->capture_item == uctl->value.enumerated.item[0]) {
826
*active_index = idx;
827
break;
828
}
829
}
830
err = 0;
831
__unlock:
832
up_read(&card->controls_rwsem);
833
__free_only:
834
kfree(uctl);
835
kfree(uinfo);
836
return err;
837
}
838
839
static int snd_mixer_oss_put_recsrc2(struct snd_mixer_oss_file *fmixer, unsigned int active_index)
840
{
841
struct snd_card *card = fmixer->card;
842
struct snd_mixer_oss *mixer = fmixer->mixer;
843
struct snd_kcontrol *kctl;
844
struct snd_mixer_oss_slot *pslot;
845
struct slot *slot = NULL;
846
struct snd_ctl_elem_info *uinfo;
847
struct snd_ctl_elem_value *uctl;
848
int err;
849
unsigned int idx;
850
851
uinfo = kzalloc(sizeof(*uinfo), GFP_KERNEL);
852
uctl = kzalloc(sizeof(*uctl), GFP_KERNEL);
853
if (uinfo == NULL || uctl == NULL) {
854
err = -ENOMEM;
855
goto __free_only;
856
}
857
down_read(&card->controls_rwsem);
858
kctl = snd_mixer_oss_test_id(mixer, "Capture Source", 0);
859
if (! kctl) {
860
err = -ENOENT;
861
goto __unlock;
862
}
863
if ((err = kctl->info(kctl, uinfo)) < 0)
864
goto __unlock;
865
for (idx = 0; idx < 32; idx++) {
866
if (!(mixer->mask_recsrc & (1 << idx)))
867
continue;
868
pslot = &mixer->slots[idx];
869
slot = pslot->private_data;
870
if (slot->signature != SNDRV_MIXER_OSS_SIGNATURE)
871
continue;
872
if (!(slot->present & SNDRV_MIXER_OSS_PRESENT_CAPTURE))
873
continue;
874
if (idx == active_index)
875
break;
876
slot = NULL;
877
}
878
if (! slot)
879
goto __unlock;
880
for (idx = 0; idx < uinfo->count; idx++)
881
uctl->value.enumerated.item[idx] = slot->capture_item;
882
err = kctl->put(kctl, uctl);
883
if (err > 0)
884
snd_ctl_notify(fmixer->card, SNDRV_CTL_EVENT_MASK_VALUE, &kctl->id);
885
err = 0;
886
__unlock:
887
up_read(&card->controls_rwsem);
888
__free_only:
889
kfree(uctl);
890
kfree(uinfo);
891
return err;
892
}
893
894
struct snd_mixer_oss_assign_table {
895
int oss_id;
896
const char *name;
897
int index;
898
};
899
900
static int snd_mixer_oss_build_test(struct snd_mixer_oss *mixer, struct slot *slot, const char *name, int index, int item)
901
{
902
struct snd_ctl_elem_info *info;
903
struct snd_kcontrol *kcontrol;
904
struct snd_card *card = mixer->card;
905
int err;
906
907
down_read(&card->controls_rwsem);
908
kcontrol = snd_mixer_oss_test_id(mixer, name, index);
909
if (kcontrol == NULL) {
910
up_read(&card->controls_rwsem);
911
return 0;
912
}
913
info = kmalloc(sizeof(*info), GFP_KERNEL);
914
if (! info) {
915
up_read(&card->controls_rwsem);
916
return -ENOMEM;
917
}
918
if ((err = kcontrol->info(kcontrol, info)) < 0) {
919
up_read(&card->controls_rwsem);
920
kfree(info);
921
return err;
922
}
923
slot->numid[item] = kcontrol->id.numid;
924
up_read(&card->controls_rwsem);
925
if (info->count > slot->channels)
926
slot->channels = info->count;
927
slot->present |= 1 << item;
928
kfree(info);
929
return 0;
930
}
931
932
static void snd_mixer_oss_slot_free(struct snd_mixer_oss_slot *chn)
933
{
934
struct slot *p = chn->private_data;
935
if (p) {
936
if (p->allocated && p->assigned) {
937
kfree(p->assigned->name);
938
kfree(p->assigned);
939
}
940
kfree(p);
941
}
942
}
943
944
static void mixer_slot_clear(struct snd_mixer_oss_slot *rslot)
945
{
946
int idx = rslot->number; /* remember this */
947
if (rslot->private_free)
948
rslot->private_free(rslot);
949
memset(rslot, 0, sizeof(*rslot));
950
rslot->number = idx;
951
}
952
953
/* In a separate function to keep gcc 3.2 happy - do NOT merge this in
954
snd_mixer_oss_build_input! */
955
static int snd_mixer_oss_build_test_all(struct snd_mixer_oss *mixer,
956
struct snd_mixer_oss_assign_table *ptr,
957
struct slot *slot)
958
{
959
char str[64];
960
int err;
961
962
err = snd_mixer_oss_build_test(mixer, slot, ptr->name, ptr->index,
963
SNDRV_MIXER_OSS_ITEM_GLOBAL);
964
if (err)
965
return err;
966
sprintf(str, "%s Switch", ptr->name);
967
err = snd_mixer_oss_build_test(mixer, slot, str, ptr->index,
968
SNDRV_MIXER_OSS_ITEM_GSWITCH);
969
if (err)
970
return err;
971
sprintf(str, "%s Route", ptr->name);
972
err = snd_mixer_oss_build_test(mixer, slot, str, ptr->index,
973
SNDRV_MIXER_OSS_ITEM_GROUTE);
974
if (err)
975
return err;
976
sprintf(str, "%s Volume", ptr->name);
977
err = snd_mixer_oss_build_test(mixer, slot, str, ptr->index,
978
SNDRV_MIXER_OSS_ITEM_GVOLUME);
979
if (err)
980
return err;
981
sprintf(str, "%s Playback Switch", ptr->name);
982
err = snd_mixer_oss_build_test(mixer, slot, str, ptr->index,
983
SNDRV_MIXER_OSS_ITEM_PSWITCH);
984
if (err)
985
return err;
986
sprintf(str, "%s Playback Route", ptr->name);
987
err = snd_mixer_oss_build_test(mixer, slot, str, ptr->index,
988
SNDRV_MIXER_OSS_ITEM_PROUTE);
989
if (err)
990
return err;
991
sprintf(str, "%s Playback Volume", ptr->name);
992
err = snd_mixer_oss_build_test(mixer, slot, str, ptr->index,
993
SNDRV_MIXER_OSS_ITEM_PVOLUME);
994
if (err)
995
return err;
996
sprintf(str, "%s Capture Switch", ptr->name);
997
err = snd_mixer_oss_build_test(mixer, slot, str, ptr->index,
998
SNDRV_MIXER_OSS_ITEM_CSWITCH);
999
if (err)
1000
return err;
1001
sprintf(str, "%s Capture Route", ptr->name);
1002
err = snd_mixer_oss_build_test(mixer, slot, str, ptr->index,
1003
SNDRV_MIXER_OSS_ITEM_CROUTE);
1004
if (err)
1005
return err;
1006
sprintf(str, "%s Capture Volume", ptr->name);
1007
err = snd_mixer_oss_build_test(mixer, slot, str, ptr->index,
1008
SNDRV_MIXER_OSS_ITEM_CVOLUME);
1009
if (err)
1010
return err;
1011
1012
return 0;
1013
}
1014
1015
/*
1016
* build an OSS mixer element.
1017
* ptr_allocated means the entry is dynamically allocated (change via proc file).
1018
* when replace_old = 1, the old entry is replaced with the new one.
1019
*/
1020
static int snd_mixer_oss_build_input(struct snd_mixer_oss *mixer, struct snd_mixer_oss_assign_table *ptr, int ptr_allocated, int replace_old)
1021
{
1022
struct slot slot;
1023
struct slot *pslot;
1024
struct snd_kcontrol *kctl;
1025
struct snd_mixer_oss_slot *rslot;
1026
char str[64];
1027
1028
/* check if already assigned */
1029
if (mixer->slots[ptr->oss_id].get_volume && ! replace_old)
1030
return 0;
1031
1032
memset(&slot, 0, sizeof(slot));
1033
memset(slot.numid, 0xff, sizeof(slot.numid)); /* ID_UNKNOWN */
1034
if (snd_mixer_oss_build_test_all(mixer, ptr, &slot))
1035
return 0;
1036
down_read(&mixer->card->controls_rwsem);
1037
if (ptr->index == 0 && (kctl = snd_mixer_oss_test_id(mixer, "Capture Source", 0)) != NULL) {
1038
struct snd_ctl_elem_info *uinfo;
1039
1040
uinfo = kzalloc(sizeof(*uinfo), GFP_KERNEL);
1041
if (! uinfo) {
1042
up_read(&mixer->card->controls_rwsem);
1043
return -ENOMEM;
1044
}
1045
1046
if (kctl->info(kctl, uinfo)) {
1047
up_read(&mixer->card->controls_rwsem);
1048
return 0;
1049
}
1050
strcpy(str, ptr->name);
1051
if (!strcmp(str, "Master"))
1052
strcpy(str, "Mix");
1053
if (!strcmp(str, "Master Mono"))
1054
strcpy(str, "Mix Mono");
1055
slot.capture_item = 0;
1056
if (!strcmp(uinfo->value.enumerated.name, str)) {
1057
slot.present |= SNDRV_MIXER_OSS_PRESENT_CAPTURE;
1058
} else {
1059
for (slot.capture_item = 1; slot.capture_item < uinfo->value.enumerated.items; slot.capture_item++) {
1060
uinfo->value.enumerated.item = slot.capture_item;
1061
if (kctl->info(kctl, uinfo)) {
1062
up_read(&mixer->card->controls_rwsem);
1063
return 0;
1064
}
1065
if (!strcmp(uinfo->value.enumerated.name, str)) {
1066
slot.present |= SNDRV_MIXER_OSS_PRESENT_CAPTURE;
1067
break;
1068
}
1069
}
1070
}
1071
kfree(uinfo);
1072
}
1073
up_read(&mixer->card->controls_rwsem);
1074
if (slot.present != 0) {
1075
pslot = kmalloc(sizeof(slot), GFP_KERNEL);
1076
if (! pslot)
1077
return -ENOMEM;
1078
*pslot = slot;
1079
pslot->signature = SNDRV_MIXER_OSS_SIGNATURE;
1080
pslot->assigned = ptr;
1081
pslot->allocated = ptr_allocated;
1082
rslot = &mixer->slots[ptr->oss_id];
1083
mixer_slot_clear(rslot);
1084
rslot->stereo = slot.channels > 1 ? 1 : 0;
1085
rslot->get_volume = snd_mixer_oss_get_volume1;
1086
rslot->put_volume = snd_mixer_oss_put_volume1;
1087
/* note: ES18xx have both Capture Source and XX Capture Volume !!! */
1088
if (slot.present & SNDRV_MIXER_OSS_PRESENT_CSWITCH) {
1089
rslot->get_recsrc = snd_mixer_oss_get_recsrc1_sw;
1090
rslot->put_recsrc = snd_mixer_oss_put_recsrc1_sw;
1091
} else if (slot.present & SNDRV_MIXER_OSS_PRESENT_CROUTE) {
1092
rslot->get_recsrc = snd_mixer_oss_get_recsrc1_route;
1093
rslot->put_recsrc = snd_mixer_oss_put_recsrc1_route;
1094
} else if (slot.present & SNDRV_MIXER_OSS_PRESENT_CAPTURE) {
1095
mixer->mask_recsrc |= 1 << ptr->oss_id;
1096
}
1097
rslot->private_data = pslot;
1098
rslot->private_free = snd_mixer_oss_slot_free;
1099
return 1;
1100
}
1101
return 0;
1102
}
1103
1104
#ifdef CONFIG_PROC_FS
1105
/*
1106
*/
1107
#define MIXER_VOL(name) [SOUND_MIXER_##name] = #name
1108
static char *oss_mixer_names[SNDRV_OSS_MAX_MIXERS] = {
1109
MIXER_VOL(VOLUME),
1110
MIXER_VOL(BASS),
1111
MIXER_VOL(TREBLE),
1112
MIXER_VOL(SYNTH),
1113
MIXER_VOL(PCM),
1114
MIXER_VOL(SPEAKER),
1115
MIXER_VOL(LINE),
1116
MIXER_VOL(MIC),
1117
MIXER_VOL(CD),
1118
MIXER_VOL(IMIX),
1119
MIXER_VOL(ALTPCM),
1120
MIXER_VOL(RECLEV),
1121
MIXER_VOL(IGAIN),
1122
MIXER_VOL(OGAIN),
1123
MIXER_VOL(LINE1),
1124
MIXER_VOL(LINE2),
1125
MIXER_VOL(LINE3),
1126
MIXER_VOL(DIGITAL1),
1127
MIXER_VOL(DIGITAL2),
1128
MIXER_VOL(DIGITAL3),
1129
MIXER_VOL(PHONEIN),
1130
MIXER_VOL(PHONEOUT),
1131
MIXER_VOL(VIDEO),
1132
MIXER_VOL(RADIO),
1133
MIXER_VOL(MONITOR),
1134
};
1135
1136
/*
1137
* /proc interface
1138
*/
1139
1140
static void snd_mixer_oss_proc_read(struct snd_info_entry *entry,
1141
struct snd_info_buffer *buffer)
1142
{
1143
struct snd_mixer_oss *mixer = entry->private_data;
1144
int i;
1145
1146
mutex_lock(&mixer->reg_mutex);
1147
for (i = 0; i < SNDRV_OSS_MAX_MIXERS; i++) {
1148
struct slot *p;
1149
1150
if (! oss_mixer_names[i])
1151
continue;
1152
p = (struct slot *)mixer->slots[i].private_data;
1153
snd_iprintf(buffer, "%s ", oss_mixer_names[i]);
1154
if (p && p->assigned)
1155
snd_iprintf(buffer, "\"%s\" %d\n",
1156
p->assigned->name,
1157
p->assigned->index);
1158
else
1159
snd_iprintf(buffer, "\"\" 0\n");
1160
}
1161
mutex_unlock(&mixer->reg_mutex);
1162
}
1163
1164
static void snd_mixer_oss_proc_write(struct snd_info_entry *entry,
1165
struct snd_info_buffer *buffer)
1166
{
1167
struct snd_mixer_oss *mixer = entry->private_data;
1168
char line[128], str[32], idxstr[16];
1169
const char *cptr;
1170
int ch, idx;
1171
struct snd_mixer_oss_assign_table *tbl;
1172
struct slot *slot;
1173
1174
while (!snd_info_get_line(buffer, line, sizeof(line))) {
1175
cptr = snd_info_get_str(str, line, sizeof(str));
1176
for (ch = 0; ch < SNDRV_OSS_MAX_MIXERS; ch++)
1177
if (oss_mixer_names[ch] && strcmp(oss_mixer_names[ch], str) == 0)
1178
break;
1179
if (ch >= SNDRV_OSS_MAX_MIXERS) {
1180
snd_printk(KERN_ERR "mixer_oss: invalid OSS volume '%s'\n", str);
1181
continue;
1182
}
1183
cptr = snd_info_get_str(str, cptr, sizeof(str));
1184
if (! *str) {
1185
/* remove the entry */
1186
mutex_lock(&mixer->reg_mutex);
1187
mixer_slot_clear(&mixer->slots[ch]);
1188
mutex_unlock(&mixer->reg_mutex);
1189
continue;
1190
}
1191
snd_info_get_str(idxstr, cptr, sizeof(idxstr));
1192
idx = simple_strtoul(idxstr, NULL, 10);
1193
if (idx >= 0x4000) { /* too big */
1194
snd_printk(KERN_ERR "mixer_oss: invalid index %d\n", idx);
1195
continue;
1196
}
1197
mutex_lock(&mixer->reg_mutex);
1198
slot = (struct slot *)mixer->slots[ch].private_data;
1199
if (slot && slot->assigned &&
1200
slot->assigned->index == idx && ! strcmp(slot->assigned->name, str))
1201
/* not changed */
1202
goto __unlock;
1203
tbl = kmalloc(sizeof(*tbl), GFP_KERNEL);
1204
if (! tbl) {
1205
snd_printk(KERN_ERR "mixer_oss: no memory\n");
1206
goto __unlock;
1207
}
1208
tbl->oss_id = ch;
1209
tbl->name = kstrdup(str, GFP_KERNEL);
1210
if (! tbl->name) {
1211
kfree(tbl);
1212
goto __unlock;
1213
}
1214
tbl->index = idx;
1215
if (snd_mixer_oss_build_input(mixer, tbl, 1, 1) <= 0) {
1216
kfree(tbl->name);
1217
kfree(tbl);
1218
}
1219
__unlock:
1220
mutex_unlock(&mixer->reg_mutex);
1221
}
1222
}
1223
1224
static void snd_mixer_oss_proc_init(struct snd_mixer_oss *mixer)
1225
{
1226
struct snd_info_entry *entry;
1227
1228
entry = snd_info_create_card_entry(mixer->card, "oss_mixer",
1229
mixer->card->proc_root);
1230
if (! entry)
1231
return;
1232
entry->content = SNDRV_INFO_CONTENT_TEXT;
1233
entry->mode = S_IFREG | S_IRUGO | S_IWUSR;
1234
entry->c.text.read = snd_mixer_oss_proc_read;
1235
entry->c.text.write = snd_mixer_oss_proc_write;
1236
entry->private_data = mixer;
1237
if (snd_info_register(entry) < 0) {
1238
snd_info_free_entry(entry);
1239
entry = NULL;
1240
}
1241
mixer->proc_entry = entry;
1242
}
1243
1244
static void snd_mixer_oss_proc_done(struct snd_mixer_oss *mixer)
1245
{
1246
snd_info_free_entry(mixer->proc_entry);
1247
mixer->proc_entry = NULL;
1248
}
1249
#else /* !CONFIG_PROC_FS */
1250
#define snd_mixer_oss_proc_init(mix)
1251
#define snd_mixer_oss_proc_done(mix)
1252
#endif /* CONFIG_PROC_FS */
1253
1254
static void snd_mixer_oss_build(struct snd_mixer_oss *mixer)
1255
{
1256
static struct snd_mixer_oss_assign_table table[] = {
1257
{ SOUND_MIXER_VOLUME, "Master", 0 },
1258
{ SOUND_MIXER_VOLUME, "Front", 0 }, /* fallback */
1259
{ SOUND_MIXER_BASS, "Tone Control - Bass", 0 },
1260
{ SOUND_MIXER_TREBLE, "Tone Control - Treble", 0 },
1261
{ SOUND_MIXER_SYNTH, "Synth", 0 },
1262
{ SOUND_MIXER_SYNTH, "FM", 0 }, /* fallback */
1263
{ SOUND_MIXER_SYNTH, "Music", 0 }, /* fallback */
1264
{ SOUND_MIXER_PCM, "PCM", 0 },
1265
{ SOUND_MIXER_SPEAKER, "Beep", 0 },
1266
{ SOUND_MIXER_SPEAKER, "PC Speaker", 0 }, /* fallback */
1267
{ SOUND_MIXER_SPEAKER, "Speaker", 0 }, /* fallback */
1268
{ SOUND_MIXER_LINE, "Line", 0 },
1269
{ SOUND_MIXER_MIC, "Mic", 0 },
1270
{ SOUND_MIXER_CD, "CD", 0 },
1271
{ SOUND_MIXER_IMIX, "Monitor Mix", 0 },
1272
{ SOUND_MIXER_ALTPCM, "PCM", 1 },
1273
{ SOUND_MIXER_ALTPCM, "Headphone", 0 }, /* fallback */
1274
{ SOUND_MIXER_ALTPCM, "Wave", 0 }, /* fallback */
1275
{ SOUND_MIXER_RECLEV, "-- nothing --", 0 },
1276
{ SOUND_MIXER_IGAIN, "Capture", 0 },
1277
{ SOUND_MIXER_OGAIN, "Playback", 0 },
1278
{ SOUND_MIXER_LINE1, "Aux", 0 },
1279
{ SOUND_MIXER_LINE2, "Aux", 1 },
1280
{ SOUND_MIXER_LINE3, "Aux", 2 },
1281
{ SOUND_MIXER_DIGITAL1, "Digital", 0 },
1282
{ SOUND_MIXER_DIGITAL1, "IEC958", 0 }, /* fallback */
1283
{ SOUND_MIXER_DIGITAL1, "IEC958 Optical", 0 }, /* fallback */
1284
{ SOUND_MIXER_DIGITAL1, "IEC958 Coaxial", 0 }, /* fallback */
1285
{ SOUND_MIXER_DIGITAL2, "Digital", 1 },
1286
{ SOUND_MIXER_DIGITAL3, "Digital", 2 },
1287
{ SOUND_MIXER_PHONEIN, "Phone", 0 },
1288
{ SOUND_MIXER_PHONEOUT, "Master Mono", 0 },
1289
{ SOUND_MIXER_PHONEOUT, "Speaker", 0 }, /*fallback*/
1290
{ SOUND_MIXER_PHONEOUT, "Mono", 0 }, /*fallback*/
1291
{ SOUND_MIXER_PHONEOUT, "Phone", 0 }, /* fallback */
1292
{ SOUND_MIXER_VIDEO, "Video", 0 },
1293
{ SOUND_MIXER_RADIO, "Radio", 0 },
1294
{ SOUND_MIXER_MONITOR, "Monitor", 0 }
1295
};
1296
unsigned int idx;
1297
1298
for (idx = 0; idx < ARRAY_SIZE(table); idx++)
1299
snd_mixer_oss_build_input(mixer, &table[idx], 0, 0);
1300
if (mixer->mask_recsrc) {
1301
mixer->get_recsrc = snd_mixer_oss_get_recsrc2;
1302
mixer->put_recsrc = snd_mixer_oss_put_recsrc2;
1303
}
1304
}
1305
1306
/*
1307
*
1308
*/
1309
1310
static int snd_mixer_oss_free1(void *private)
1311
{
1312
struct snd_mixer_oss *mixer = private;
1313
struct snd_card *card;
1314
int idx;
1315
1316
if (!mixer)
1317
return 0;
1318
card = mixer->card;
1319
if (snd_BUG_ON(mixer != card->mixer_oss))
1320
return -ENXIO;
1321
card->mixer_oss = NULL;
1322
for (idx = 0; idx < SNDRV_OSS_MAX_MIXERS; idx++) {
1323
struct snd_mixer_oss_slot *chn = &mixer->slots[idx];
1324
if (chn->private_free)
1325
chn->private_free(chn);
1326
}
1327
kfree(mixer);
1328
return 0;
1329
}
1330
1331
static int snd_mixer_oss_notify_handler(struct snd_card *card, int cmd)
1332
{
1333
struct snd_mixer_oss *mixer;
1334
1335
if (cmd == SND_MIXER_OSS_NOTIFY_REGISTER) {
1336
char name[128];
1337
int idx, err;
1338
1339
mixer = kcalloc(2, sizeof(*mixer), GFP_KERNEL);
1340
if (mixer == NULL)
1341
return -ENOMEM;
1342
mutex_init(&mixer->reg_mutex);
1343
sprintf(name, "mixer%i%i", card->number, 0);
1344
if ((err = snd_register_oss_device(SNDRV_OSS_DEVICE_TYPE_MIXER,
1345
card, 0,
1346
&snd_mixer_oss_f_ops, card,
1347
name)) < 0) {
1348
snd_printk(KERN_ERR "unable to register OSS mixer device %i:%i\n",
1349
card->number, 0);
1350
kfree(mixer);
1351
return err;
1352
}
1353
mixer->oss_dev_alloc = 1;
1354
mixer->card = card;
1355
if (*card->mixername)
1356
strlcpy(mixer->name, card->mixername, sizeof(mixer->name));
1357
else
1358
strlcpy(mixer->name, name, sizeof(mixer->name));
1359
#ifdef SNDRV_OSS_INFO_DEV_MIXERS
1360
snd_oss_info_register(SNDRV_OSS_INFO_DEV_MIXERS,
1361
card->number,
1362
mixer->name);
1363
#endif
1364
for (idx = 0; idx < SNDRV_OSS_MAX_MIXERS; idx++)
1365
mixer->slots[idx].number = idx;
1366
card->mixer_oss = mixer;
1367
snd_mixer_oss_build(mixer);
1368
snd_mixer_oss_proc_init(mixer);
1369
} else {
1370
mixer = card->mixer_oss;
1371
if (mixer == NULL)
1372
return 0;
1373
if (mixer->oss_dev_alloc) {
1374
#ifdef SNDRV_OSS_INFO_DEV_MIXERS
1375
snd_oss_info_unregister(SNDRV_OSS_INFO_DEV_MIXERS, mixer->card->number);
1376
#endif
1377
snd_unregister_oss_device(SNDRV_OSS_DEVICE_TYPE_MIXER, mixer->card, 0);
1378
mixer->oss_dev_alloc = 0;
1379
}
1380
if (cmd == SND_MIXER_OSS_NOTIFY_DISCONNECT)
1381
return 0;
1382
snd_mixer_oss_proc_done(mixer);
1383
return snd_mixer_oss_free1(mixer);
1384
}
1385
return 0;
1386
}
1387
1388
static int __init alsa_mixer_oss_init(void)
1389
{
1390
int idx;
1391
1392
snd_mixer_oss_notify_callback = snd_mixer_oss_notify_handler;
1393
for (idx = 0; idx < SNDRV_CARDS; idx++) {
1394
if (snd_cards[idx])
1395
snd_mixer_oss_notify_handler(snd_cards[idx], SND_MIXER_OSS_NOTIFY_REGISTER);
1396
}
1397
return 0;
1398
}
1399
1400
static void __exit alsa_mixer_oss_exit(void)
1401
{
1402
int idx;
1403
1404
snd_mixer_oss_notify_callback = NULL;
1405
for (idx = 0; idx < SNDRV_CARDS; idx++) {
1406
if (snd_cards[idx])
1407
snd_mixer_oss_notify_handler(snd_cards[idx], SND_MIXER_OSS_NOTIFY_FREE);
1408
}
1409
}
1410
1411
module_init(alsa_mixer_oss_init)
1412
module_exit(alsa_mixer_oss_exit)
1413
1414
EXPORT_SYMBOL(snd_mixer_oss_ioctl_card);
1415
1416