1/*
2 * sound/oss/dev_table.c
3 *
4 * Device call tables.
5 *
6 *
7 * Copyright (C) by Hannu Savolainen 1993-1997
8 *
9 * OSS/Free for Linux is distributed under the GNU GENERAL PUBLIC LICENSE (GPL)
10 * Version 2 (June 1991). See the "COPYING" file distributed with this software
11 * for more info.
12 */
13
14#include <linux/init.h>
15
16#include "sound_config.h"
17
18struct audio_operations *audio_devs[MAX_AUDIO_DEV];
19EXPORT_SYMBOL(audio_devs);
20
21int num_audiodevs;
22EXPORT_SYMBOL(num_audiodevs);
23
24struct mixer_operations *mixer_devs[MAX_MIXER_DEV];
25EXPORT_SYMBOL(mixer_devs);
26
27int num_mixers;
28EXPORT_SYMBOL(num_mixers);
29
30struct synth_operations *synth_devs[MAX_SYNTH_DEV+MAX_MIDI_DEV];
31EXPORT_SYMBOL(synth_devs);
32
33int num_synths;
34
35struct midi_operations *midi_devs[MAX_MIDI_DEV];
36EXPORT_SYMBOL(midi_devs);
37
38int num_midis;
39EXPORT_SYMBOL(num_midis);
40
41struct sound_timer_operations *sound_timer_devs[MAX_TIMER_DEV] = {
42	&default_sound_timer, NULL
43};
44EXPORT_SYMBOL(sound_timer_devs);
45
46int num_sound_timers = 1;
47
48
49static int sound_alloc_audiodev(void);
50
51int sound_install_audiodrv(int vers, char *name, struct audio_driver *driver,
52			int driver_size, int flags, unsigned int format_mask,
53			void *devc, int dma1, int dma2)
54{
55	struct audio_driver *d;
56	struct audio_operations *op;
57	int num;
58
59	if (vers != AUDIO_DRIVER_VERSION || driver_size > sizeof(struct audio_driver)) {
60		printk(KERN_ERR "Sound: Incompatible audio driver for %s\n", name);
61		return -(EINVAL);
62	}
63	num = sound_alloc_audiodev();
64
65	if (num == -1) {
66		printk(KERN_ERR "sound: Too many audio drivers\n");
67		return -(EBUSY);
68	}
69	d = (struct audio_driver *) (sound_mem_blocks[sound_nblocks] = vmalloc(sizeof(struct audio_driver)));
70
71	if (sound_nblocks < 1024)
72		sound_nblocks++;
73
74	op = (struct audio_operations *) (sound_mem_blocks[sound_nblocks] = vmalloc(sizeof(struct audio_operations)));
75
76	if (sound_nblocks < 1024)
77		sound_nblocks++;
78	if (d == NULL || op == NULL) {
79		printk(KERN_ERR "Sound: Can't allocate driver for (%s)\n", name);
80		sound_unload_audiodev(num);
81		return -(ENOMEM);
82	}
83	memset((char *) op, 0, sizeof(struct audio_operations));
84	init_waitqueue_head(&op->in_sleeper);
85	init_waitqueue_head(&op->out_sleeper);
86	init_waitqueue_head(&op->poll_sleeper);
87	if (driver_size < sizeof(struct audio_driver))
88		memset((char *) d, 0, sizeof(struct audio_driver));
89
90	memcpy((char *) d, (char *) driver, driver_size);
91
92	op->d = d;
93	strlcpy(op->name, name, sizeof(op->name));
94	op->flags = flags;
95	op->format_mask = format_mask;
96	op->devc = devc;
97
98	/*
99	 *    Hardcoded defaults
100	 */
101	audio_devs[num] = op;
102
103	DMAbuf_init(num, dma1, dma2);
104
105	audio_init_devices();
106	return num;
107}
108EXPORT_SYMBOL(sound_install_audiodrv);
109
110int sound_install_mixer(int vers, char *name, struct mixer_operations *driver,
111	int driver_size, void *devc)
112{
113	struct mixer_operations *op;
114
115	int n = sound_alloc_mixerdev();
116
117	if (n == -1) {
118		printk(KERN_ERR "Sound: Too many mixer drivers\n");
119		return -EBUSY;
120	}
121	if (vers != MIXER_DRIVER_VERSION ||
122		driver_size > sizeof(struct mixer_operations)) {
123		printk(KERN_ERR "Sound: Incompatible mixer driver for %s\n", name);
124		return -EINVAL;
125	}
126
127
128	op = (struct mixer_operations *) (sound_mem_blocks[sound_nblocks] = vmalloc(sizeof(struct mixer_operations)));
129
130	if (sound_nblocks < 1024)
131		sound_nblocks++;
132	if (op == NULL) {
133		printk(KERN_ERR "Sound: Can't allocate mixer driver for (%s)\n", name);
134		return -ENOMEM;
135	}
136	memset((char *) op, 0, sizeof(struct mixer_operations));
137	memcpy((char *) op, (char *) driver, driver_size);
138
139	strlcpy(op->name, name, sizeof(op->name));
140	op->devc = devc;
141
142	mixer_devs[n] = op;
143	return n;
144}
145EXPORT_SYMBOL(sound_install_mixer);
146
147void sound_unload_audiodev(int dev)
148{
149	if (dev != -1) {
150		DMAbuf_deinit(dev);
151		audio_devs[dev] = NULL;
152		unregister_sound_dsp((dev<<4)+3);
153	}
154}
155EXPORT_SYMBOL(sound_unload_audiodev);
156
157static int sound_alloc_audiodev(void)
158{
159	int i = register_sound_dsp(&oss_sound_fops, -1);
160	if(i==-1)
161		return i;
162	i>>=4;
163	if(i>=num_audiodevs)
164		num_audiodevs = i + 1;
165	return i;
166}
167
168int sound_alloc_mididev(void)
169{
170	int i = register_sound_midi(&oss_sound_fops, -1);
171	if(i==-1)
172		return i;
173	i>>=4;
174	if(i>=num_midis)
175		num_midis = i + 1;
176	return i;
177}
178EXPORT_SYMBOL(sound_alloc_mididev);
179
180int sound_alloc_synthdev(void)
181{
182	int i;
183
184	for (i = 0; i < MAX_SYNTH_DEV; i++) {
185		if (synth_devs[i] == NULL) {
186			if (i >= num_synths)
187				num_synths++;
188			return i;
189		}
190	}
191	return -1;
192}
193EXPORT_SYMBOL(sound_alloc_synthdev);
194
195int sound_alloc_mixerdev(void)
196{
197	int i = register_sound_mixer(&oss_sound_fops, -1);
198	if(i==-1)
199		return -1;
200	i>>=4;
201	if(i>=num_mixers)
202		num_mixers = i + 1;
203	return i;
204}
205EXPORT_SYMBOL(sound_alloc_mixerdev);
206
207int sound_alloc_timerdev(void)
208{
209	int i;
210
211	for (i = 0; i < MAX_TIMER_DEV; i++) {
212		if (sound_timer_devs[i] == NULL) {
213			if (i >= num_sound_timers)
214				num_sound_timers++;
215			return i;
216		}
217	}
218	return -1;
219}
220EXPORT_SYMBOL(sound_alloc_timerdev);
221
222void sound_unload_mixerdev(int dev)
223{
224	if (dev != -1) {
225		mixer_devs[dev] = NULL;
226		unregister_sound_mixer(dev<<4);
227		num_mixers--;
228	}
229}
230EXPORT_SYMBOL(sound_unload_mixerdev);
231
232void sound_unload_mididev(int dev)
233{
234	if (dev != -1) {
235		midi_devs[dev] = NULL;
236		unregister_sound_midi((dev<<4)+2);
237	}
238}
239EXPORT_SYMBOL(sound_unload_mididev);
240
241void sound_unload_synthdev(int dev)
242{
243	if (dev != -1)
244		synth_devs[dev] = NULL;
245}
246EXPORT_SYMBOL(sound_unload_synthdev);
247
248void sound_unload_timerdev(int dev)
249{
250	if (dev != -1)
251		sound_timer_devs[dev] = NULL;
252}
253EXPORT_SYMBOL(sound_unload_timerdev);
254