Root/sound/core/sound_oss.c

1/*
2 * Advanced Linux Sound Architecture
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#ifdef CONFIG_SND_OSSEMUL
23
24#if !defined(CONFIG_SOUND) && !(defined(MODULE) && defined(CONFIG_SOUND_MODULE))
25#error "Enable the OSS soundcore multiplexer (CONFIG_SOUND) in the kernel."
26#endif
27
28#include <linux/init.h>
29#include <linux/slab.h>
30#include <linux/time.h>
31#include <sound/core.h>
32#include <sound/minors.h>
33#include <sound/info.h>
34#include <linux/sound.h>
35#include <linux/mutex.h>
36
37#define SNDRV_OSS_MINORS 128
38
39static struct snd_minor *snd_oss_minors[SNDRV_OSS_MINORS];
40static DEFINE_MUTEX(sound_oss_mutex);
41
42void *snd_lookup_oss_minor_data(unsigned int minor, int type)
43{
44    struct snd_minor *mreg;
45    void *private_data;
46
47    if (minor >= ARRAY_SIZE(snd_oss_minors))
48        return NULL;
49    mutex_lock(&sound_oss_mutex);
50    mreg = snd_oss_minors[minor];
51    if (mreg && mreg->type == type)
52        private_data = mreg->private_data;
53    else
54        private_data = NULL;
55    mutex_unlock(&sound_oss_mutex);
56    return private_data;
57}
58
59EXPORT_SYMBOL(snd_lookup_oss_minor_data);
60
61static int snd_oss_kernel_minor(int type, struct snd_card *card, int dev)
62{
63    int minor;
64
65    switch (type) {
66    case SNDRV_OSS_DEVICE_TYPE_MIXER:
67        if (snd_BUG_ON(!card || dev < 0 || dev > 1))
68            return -EINVAL;
69        minor = SNDRV_MINOR_OSS(card->number, (dev ? SNDRV_MINOR_OSS_MIXER1 : SNDRV_MINOR_OSS_MIXER));
70        break;
71    case SNDRV_OSS_DEVICE_TYPE_SEQUENCER:
72        minor = SNDRV_MINOR_OSS_SEQUENCER;
73        break;
74    case SNDRV_OSS_DEVICE_TYPE_MUSIC:
75        minor = SNDRV_MINOR_OSS_MUSIC;
76        break;
77    case SNDRV_OSS_DEVICE_TYPE_PCM:
78        if (snd_BUG_ON(!card || dev < 0 || dev > 1))
79            return -EINVAL;
80        minor = SNDRV_MINOR_OSS(card->number, (dev ? SNDRV_MINOR_OSS_PCM1 : SNDRV_MINOR_OSS_PCM));
81        break;
82    case SNDRV_OSS_DEVICE_TYPE_MIDI:
83        if (snd_BUG_ON(!card || dev < 0 || dev > 1))
84            return -EINVAL;
85        minor = SNDRV_MINOR_OSS(card->number, (dev ? SNDRV_MINOR_OSS_MIDI1 : SNDRV_MINOR_OSS_MIDI));
86        break;
87    case SNDRV_OSS_DEVICE_TYPE_DMFM:
88        minor = SNDRV_MINOR_OSS(card->number, SNDRV_MINOR_OSS_DMFM);
89        break;
90    case SNDRV_OSS_DEVICE_TYPE_SNDSTAT:
91        minor = SNDRV_MINOR_OSS_SNDSTAT;
92        break;
93    default:
94        return -EINVAL;
95    }
96    if (minor < 0 || minor >= SNDRV_OSS_MINORS)
97        return -EINVAL;
98    return minor;
99}
100
101int snd_register_oss_device(int type, struct snd_card *card, int dev,
102                const struct file_operations *f_ops, void *private_data,
103                const char *name)
104{
105    int minor = snd_oss_kernel_minor(type, card, dev);
106    int minor_unit;
107    struct snd_minor *preg;
108    int cidx = SNDRV_MINOR_OSS_CARD(minor);
109    int track2 = -1;
110    int register1 = -1, register2 = -1;
111    struct device *carddev = snd_card_get_device_link(card);
112
113    if (card && card->number >= 8)
114        return 0; /* ignore silently */
115    if (minor < 0)
116        return minor;
117    preg = kmalloc(sizeof(struct snd_minor), GFP_KERNEL);
118    if (preg == NULL)
119        return -ENOMEM;
120    preg->type = type;
121    preg->card = card ? card->number : -1;
122    preg->device = dev;
123    preg->f_ops = f_ops;
124    preg->private_data = private_data;
125    mutex_lock(&sound_oss_mutex);
126    snd_oss_minors[minor] = preg;
127    minor_unit = SNDRV_MINOR_OSS_DEVICE(minor);
128    switch (minor_unit) {
129    case SNDRV_MINOR_OSS_PCM:
130        track2 = SNDRV_MINOR_OSS(cidx, SNDRV_MINOR_OSS_AUDIO);
131        break;
132    case SNDRV_MINOR_OSS_MIDI:
133        track2 = SNDRV_MINOR_OSS(cidx, SNDRV_MINOR_OSS_DMMIDI);
134        break;
135    case SNDRV_MINOR_OSS_MIDI1:
136        track2 = SNDRV_MINOR_OSS(cidx, SNDRV_MINOR_OSS_DMMIDI1);
137        break;
138    }
139    register1 = register_sound_special_device(f_ops, minor, carddev);
140    if (register1 != minor)
141        goto __end;
142    if (track2 >= 0) {
143        register2 = register_sound_special_device(f_ops, track2,
144                              carddev);
145        if (register2 != track2)
146            goto __end;
147        snd_oss_minors[track2] = preg;
148    }
149    mutex_unlock(&sound_oss_mutex);
150    return 0;
151
152      __end:
153          if (register2 >= 0)
154              unregister_sound_special(register2);
155          if (register1 >= 0)
156              unregister_sound_special(register1);
157    snd_oss_minors[minor] = NULL;
158    mutex_unlock(&sound_oss_mutex);
159    kfree(preg);
160          return -EBUSY;
161}
162
163EXPORT_SYMBOL(snd_register_oss_device);
164
165int snd_unregister_oss_device(int type, struct snd_card *card, int dev)
166{
167    int minor = snd_oss_kernel_minor(type, card, dev);
168    int cidx = SNDRV_MINOR_OSS_CARD(minor);
169    int track2 = -1;
170    struct snd_minor *mptr;
171
172    if (card && card->number >= 8)
173        return 0;
174    if (minor < 0)
175        return minor;
176    mutex_lock(&sound_oss_mutex);
177    mptr = snd_oss_minors[minor];
178    if (mptr == NULL) {
179        mutex_unlock(&sound_oss_mutex);
180        return -ENOENT;
181    }
182    unregister_sound_special(minor);
183    switch (SNDRV_MINOR_OSS_DEVICE(minor)) {
184    case SNDRV_MINOR_OSS_PCM:
185        track2 = SNDRV_MINOR_OSS(cidx, SNDRV_MINOR_OSS_AUDIO);
186        break;
187    case SNDRV_MINOR_OSS_MIDI:
188        track2 = SNDRV_MINOR_OSS(cidx, SNDRV_MINOR_OSS_DMMIDI);
189        break;
190    case SNDRV_MINOR_OSS_MIDI1:
191        track2 = SNDRV_MINOR_OSS(cidx, SNDRV_MINOR_OSS_DMMIDI1);
192        break;
193    }
194    if (track2 >= 0) {
195        unregister_sound_special(track2);
196        snd_oss_minors[track2] = NULL;
197    }
198    snd_oss_minors[minor] = NULL;
199    mutex_unlock(&sound_oss_mutex);
200    kfree(mptr);
201    return 0;
202}
203
204EXPORT_SYMBOL(snd_unregister_oss_device);
205
206/*
207 * INFO PART
208 */
209
210#ifdef CONFIG_PROC_FS
211
212static struct snd_info_entry *snd_minor_info_oss_entry;
213
214static const char *snd_oss_device_type_name(int type)
215{
216    switch (type) {
217    case SNDRV_OSS_DEVICE_TYPE_MIXER:
218        return "mixer";
219    case SNDRV_OSS_DEVICE_TYPE_SEQUENCER:
220    case SNDRV_OSS_DEVICE_TYPE_MUSIC:
221        return "sequencer";
222    case SNDRV_OSS_DEVICE_TYPE_PCM:
223        return "digital audio";
224    case SNDRV_OSS_DEVICE_TYPE_MIDI:
225        return "raw midi";
226    case SNDRV_OSS_DEVICE_TYPE_DMFM:
227        return "hardware dependent";
228    default:
229        return "?";
230    }
231}
232
233static void snd_minor_info_oss_read(struct snd_info_entry *entry,
234                    struct snd_info_buffer *buffer)
235{
236    int minor;
237    struct snd_minor *mptr;
238
239    mutex_lock(&sound_oss_mutex);
240    for (minor = 0; minor < SNDRV_OSS_MINORS; ++minor) {
241        if (!(mptr = snd_oss_minors[minor]))
242            continue;
243        if (mptr->card >= 0)
244            snd_iprintf(buffer, "%3i: [%i-%2i]: %s\n", minor,
245                    mptr->card, mptr->device,
246                    snd_oss_device_type_name(mptr->type));
247        else
248            snd_iprintf(buffer, "%3i: : %s\n", minor,
249                    snd_oss_device_type_name(mptr->type));
250    }
251    mutex_unlock(&sound_oss_mutex);
252}
253
254
255int __init snd_minor_info_oss_init(void)
256{
257    struct snd_info_entry *entry;
258
259    entry = snd_info_create_module_entry(THIS_MODULE, "devices", snd_oss_root);
260    if (entry) {
261        entry->c.text.read = snd_minor_info_oss_read;
262        if (snd_info_register(entry) < 0) {
263            snd_info_free_entry(entry);
264            entry = NULL;
265        }
266    }
267    snd_minor_info_oss_entry = entry;
268    return 0;
269}
270
271int __exit snd_minor_info_oss_done(void)
272{
273    snd_info_free_entry(snd_minor_info_oss_entry);
274    return 0;
275}
276#endif /* CONFIG_PROC_FS */
277
278#endif /* CONFIG_SND_OSSEMUL */
279

Archive Download this file



interactive