OpenCores
URL https://opencores.org/ocsvn/or1k_soc_on_altera_embedded_dev_kit/or1k_soc_on_altera_embedded_dev_kit/trunk

Subversion Repositories or1k_soc_on_altera_embedded_dev_kit

[/] [or1k_soc_on_altera_embedded_dev_kit/] [trunk/] [linux-2.6/] [linux-2.6.24/] [sound/] [core/] [oss/] [mixer_oss.c] - Blame information for rev 3

Details | Compare with Previous | View Log

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

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.